Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 18 Oct 2013 17:56:17 +0000 (13:56 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 18 Oct 2013 17:56:17 +0000 (13:56 -0400)
2483 files changed:
Documentation/ABI/testing/sysfs-class-mtd
Documentation/DocBook/mtdnand.tmpl
Documentation/aoe/udev.txt
Documentation/block/cmdline-partition.txt [new file with mode: 0644]
Documentation/cgroups/memory.txt
Documentation/clk.txt
Documentation/device-mapper/cache.txt
Documentation/device-mapper/statistics.txt [new file with mode: 0644]
Documentation/device-mapper/thin-provisioning.txt
Documentation/devicetree/bindings/clock/exynos4-clock.txt
Documentation/devicetree/bindings/clock/exynos5250-clock.txt
Documentation/devicetree/bindings/clock/exynos5420-clock.txt
Documentation/devicetree/bindings/clock/samsung,s3c64xx-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi.txt
Documentation/devicetree/bindings/clock/sunxi/sun5i-a10s-gates.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi/sun6i-a31-gates.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/sunxi/sun7i-a20-gates.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
Documentation/devicetree/bindings/dma/k3dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/shdma.txt
Documentation/devicetree/bindings/gpu/samsung-g2d.txt
Documentation/devicetree/bindings/leds/leds-lp55xx.txt
Documentation/devicetree/bindings/leds/pca963x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/memory.txt [new file with mode: 0644]
Documentation/devicetree/bindings/metag/pdc-intc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/palmas.txt
Documentation/devicetree/bindings/mfd/s2mps11.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/fsl-esdhc.txt
Documentation/devicetree/bindings/mtd/atmel-nand.txt
Documentation/devicetree/bindings/mtd/fsmc-nand.txt
Documentation/devicetree/bindings/mtd/partition.txt
Documentation/devicetree/bindings/net/can/sja1000.txt
Documentation/devicetree/bindings/pci/ralink,rt3883-pci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/power_supply/msm-poweroff.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pwm-samsung.txt
Documentation/devicetree/bindings/regulator/palmas-pmic.txt
Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/rtc-omap.txt
Documentation/devicetree/bindings/rtc/rtc-palmas.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/mvebu-audio.txt
Documentation/devicetree/bindings/thermal/exynos-thermal.txt [new file with mode: 0644]
Documentation/devicetree/bindings/thermal/imx-thermal.txt [new file with mode: 0644]
Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
Documentation/dma-buf-sharing.txt
Documentation/dmatest.txt
Documentation/driver-model/devres.txt
Documentation/filesystems/caching/backend-api.txt
Documentation/filesystems/caching/netfs-api.txt
Documentation/filesystems/cifs.txt [deleted file]
Documentation/filesystems/cifs/AUTHORS [new file with mode: 0644]
Documentation/filesystems/cifs/CHANGES [new file with mode: 0644]
Documentation/filesystems/cifs/README [new file with mode: 0644]
Documentation/filesystems/cifs/TODO [new file with mode: 0644]
Documentation/filesystems/cifs/cifs.txt [new file with mode: 0644]
Documentation/filesystems/cifs/winucase_convert.pl [new file with mode: 0755]
Documentation/filesystems/porting
Documentation/filesystems/proc.txt
Documentation/filesystems/ramfs-rootfs-initramfs.txt
Documentation/filesystems/vfs.txt
Documentation/kbuild/kconfig-language.txt
Documentation/kbuild/kconfig.txt
Documentation/kernel-parameters.txt
Documentation/leds/leds-lp5521.txt
Documentation/leds/leds-lp5523.txt
Documentation/leds/leds-lp55xx.txt
Documentation/networking/00-INDEX
Documentation/networking/bonding.txt
Documentation/networking/i40e.txt [new file with mode: 0644]
Documentation/scheduler/sched-design-CFS.txt
Documentation/scsi/ChangeLog.megaraid_sas
Documentation/sysctl/kernel.txt
Documentation/sysctl/vm.txt
Documentation/thermal/exynos_thermal
Documentation/thermal/sysfs-api.txt
Documentation/vfio.txt
Documentation/vm/hugetlbpage.txt
Documentation/vm/soft-dirty.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/lib/csum_partial_copy.c
arch/alpha/mm/fault.c
arch/arc/Kconfig
arch/arc/boot/.gitignore [new file with mode: 0644]
arch/arc/include/asm/cache.h
arch/arc/include/asm/delay.h
arch/arc/include/asm/entry.h
arch/arc/include/asm/io.h
arch/arc/include/asm/irqflags.h
arch/arc/include/asm/mmu.h
arch/arc/include/asm/mmu_context.h
arch/arc/include/asm/pgtable.h
arch/arc/include/asm/ptrace.h
arch/arc/include/asm/sections.h
arch/arc/include/asm/spinlock_types.h
arch/arc/kernel/.gitignore [new file with mode: 0644]
arch/arc/kernel/devtree.c
arch/arc/kernel/entry.S
arch/arc/kernel/head.S
arch/arc/kernel/irq.c
arch/arc/kernel/setup.c
arch/arc/kernel/unaligned.c
arch/arc/mm/cache_arc700.c
arch/arc/mm/fault.c
arch/arc/mm/init.c
arch/arc/mm/tlb.c
arch/arc/mm/tlbex.S
arch/arm/Kconfig
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/emev2-kzm9d-reference.dts
arch/arm/boot/dts/emev2-kzm9d.dts
arch/arm/boot/dts/emev2.dtsi
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos5.dtsi
arch/arm/boot/dts/exynos5250-arndale.dts
arch/arm/boot/dts/exynos5250-snow.dts
arch/arm/boot/dts/exynos5250.dtsi
arch/arm/boot/dts/exynos5420.dtsi
arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts [new file with mode: 0644]
arch/arm/boot/dts/r8a73a4-ape6evm.dts
arch/arm/boot/dts/r8a7740-armadillo800eva-reference.dts
arch/arm/boot/dts/r8a7740-armadillo800eva.dts
arch/arm/boot/dts/r8a7740.dtsi
arch/arm/boot/dts/r8a7778-bockw-reference.dts [new file with mode: 0644]
arch/arm/boot/dts/r8a7778-bockw.dts
arch/arm/boot/dts/r8a7779-marzen-reference.dts
arch/arm/boot/dts/r8a7779-marzen.dts [new file with mode: 0644]
arch/arm/boot/dts/r8a7779.dtsi
arch/arm/boot/dts/r8a7790-lager-reference.dts [new file with mode: 0644]
arch/arm/boot/dts/r8a7790-lager.dts
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/boot/dts/sama5d3xcm.dtsi
arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
arch/arm/boot/dts/sh73a0-kzm9g.dts
arch/arm/boot/dts/sh73a0.dtsi
arch/arm/boot/dts/sun5i-a10s.dtsi
arch/arm/boot/dts/sun6i-a31-colombus.dts
arch/arm/boot/dts/sun6i-a31.dtsi
arch/arm/boot/dts/sun7i-a20-cubieboard2.dts [new file with mode: 0644]
arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
arch/arm/boot/dts/sun7i-a20.dtsi
arch/arm/boot/dts/vexpress-v2p-ca15_a7.dts
arch/arm/common/edma.c
arch/arm/common/timer-sp.c
arch/arm/configs/ag5evm_defconfig [deleted file]
arch/arm/configs/at91_dt_defconfig
arch/arm/configs/kota2_defconfig [deleted file]
arch/arm/include/asm/dma-contiguous.h
arch/arm/include/asm/mach/arch.h
arch/arm/include/asm/outercache.h
arch/arm/lib/Makefile
arch/arm/lib/xor-neon.c
arch/arm/mach-at91/include/mach/hardware.h
arch/arm/mach-at91/include/mach/sama5d3.h
arch/arm/mach-at91/include/mach/uncompress.h
arch/arm/mach-ep93xx/core.c
arch/arm/mach-ep93xx/vision_ep9307.c
arch/arm/mach-exynos/Kconfig
arch/arm/mach-exynos/cpuidle.c
arch/arm/mach-highbank/Kconfig
arch/arm/mach-highbank/highbank.c
arch/arm/mach-imx/clk.h
arch/arm/mach-imx/mm-imx25.c
arch/arm/mach-imx/mm-imx5.c
arch/arm/mach-mmp/Makefile
arch/arm/mach-mmp/common.h
arch/arm/mach-mmp/include/mach/entry-macro.S [deleted file]
arch/arm/mach-mmp/include/mach/pxa168.h
arch/arm/mach-mmp/include/mach/pxa910.h
arch/arm/mach-mmp/irq.c [deleted file]
arch/arm/mach-mmp/mmp-dt.c
arch/arm/mach-mmp/mmp2-dt.c
arch/arm/mach-mmp/mmp2.c
arch/arm/mach-mmp/pxa910.c
arch/arm/mach-mvebu/armada-370-xp.c
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/cclock33xx_data.c
arch/arm/mach-omap2/cclock44xx_data.c
arch/arm/mach-omap2/clockdomain.h
arch/arm/mach-omap2/clockdomains7xx_data.c [new file with mode: 0644]
arch/arm/mach-omap2/cm-regbits-7xx.h [new file with mode: 0644]
arch/arm/mach-omap2/cm1_7xx.h [new file with mode: 0644]
arch/arm/mach-omap2/cm2_7xx.h [new file with mode: 0644]
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/omap_hwmod.h
arch/arm/mach-omap2/omap_hwmod_33xx_data.c
arch/arm/mach-omap2/omap_hwmod_54xx_data.c
arch/arm/mach-omap2/omap_hwmod_7xx_data.c [new file with mode: 0644]
arch/arm/mach-omap2/powerdomain.h
arch/arm/mach-omap2/powerdomains3xxx_data.c
arch/arm/mach-omap2/powerdomains7xx_data.c [new file with mode: 0644]
arch/arm/mach-omap2/prcm-common.h
arch/arm/mach-omap2/prcm44xx.h
arch/arm/mach-omap2/prcm_mpu7xx.h [new file with mode: 0644]
arch/arm/mach-omap2/prm44xx.c
arch/arm/mach-omap2/prm7xx.h [new file with mode: 0644]
arch/arm/mach-omap2/prminst44xx.c
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-shmobile/Makefile
arch/arm/mach-shmobile/Makefile.boot
arch/arm/mach-shmobile/board-ag5evm.c [deleted file]
arch/arm/mach-shmobile/board-ape6evm-reference.c [new file with mode: 0644]
arch/arm/mach-shmobile/board-ape6evm.c
arch/arm/mach-shmobile/board-armadillo800eva-reference.c
arch/arm/mach-shmobile/board-armadillo800eva.c
arch/arm/mach-shmobile/board-bockw-reference.c [new file with mode: 0644]
arch/arm/mach-shmobile/board-bockw.c
arch/arm/mach-shmobile/board-kota2.c [deleted file]
arch/arm/mach-shmobile/board-kzm9g-reference.c
arch/arm/mach-shmobile/board-kzm9g.c
arch/arm/mach-shmobile/board-lager-reference.c [new file with mode: 0644]
arch/arm/mach-shmobile/board-lager.c
arch/arm/mach-shmobile/board-marzen-reference.c
arch/arm/mach-shmobile/board-marzen.c
arch/arm/mach-shmobile/headsmp.S
arch/arm/mach-shmobile/include/mach/common.h
arch/arm/mach-shmobile/include/mach/hardware.h [deleted file]
arch/arm/mach-shmobile/include/mach/r8a73a4.h
arch/arm/mach-shmobile/include/mach/r8a7740.h
arch/arm/mach-shmobile/include/mach/r8a7778.h
arch/arm/mach-shmobile/include/mach/r8a7779.h
arch/arm/mach-shmobile/include/mach/r8a7790.h
arch/arm/mach-shmobile/include/mach/sh73a0.h
arch/arm/mach-shmobile/intc-r8a7740.c [deleted file]
arch/arm/mach-shmobile/intc-r8a7779.c [deleted file]
arch/arm/mach-shmobile/platsmp-scu.c [new file with mode: 0644]
arch/arm/mach-shmobile/platsmp.c
arch/arm/mach-shmobile/setup-emev2.c
arch/arm/mach-shmobile/setup-r8a73a4.c
arch/arm/mach-shmobile/setup-r8a7740.c
arch/arm/mach-shmobile/setup-r8a7778.c
arch/arm/mach-shmobile/setup-r8a7779.c
arch/arm/mach-shmobile/setup-r8a7790.c
arch/arm/mach-shmobile/setup-sh7372.c
arch/arm/mach-shmobile/setup-sh73a0.c
arch/arm/mach-shmobile/smp-emev2.c
arch/arm/mach-shmobile/smp-r8a7779.c
arch/arm/mach-shmobile/smp-sh73a0.c
arch/arm/mach-shmobile/timer.c
arch/arm/mach-ux500/board-mop500-audio.c
arch/arm/mach-ux500/board-mop500-pins.c
arch/arm/mach-ux500/board-mop500.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm/mach-ux500/pins-db8500.h [deleted file]
arch/arm/mach-versatile/include/mach/platform.h
arch/arm/mach-versatile/pci.c
arch/arm/mach-vexpress/Makefile
arch/arm/mach-vexpress/tc2_pm.c
arch/arm/mm/fault.c
arch/arm/mm/hugetlbpage.c
arch/arm/mm/init.c
arch/arm/plat-pxa/ssp.c
arch/arm/xen/enlighten.c
arch/arm64/Kconfig
arch/arm64/kernel/setup.c
arch/arm64/mm/fault.c
arch/arm64/mm/hugetlbpage.c
arch/arm64/mm/init.c
arch/avr32/Kconfig
arch/avr32/mach-at32ap/at32ap700x.c
arch/avr32/mm/fault.c
arch/blackfin/Kconfig
arch/blackfin/boot/.gitignore
arch/blackfin/include/asm/scb.h [new file with mode: 0644]
arch/blackfin/kernel/setup.c
arch/blackfin/mach-bf609/Kconfig
arch/blackfin/mach-bf609/Makefile
arch/blackfin/mach-bf609/boards/ezkit.c
arch/blackfin/mach-bf609/clock.c
arch/blackfin/mach-bf609/include/mach/defBF60x_base.h
arch/blackfin/mach-bf609/scb.c [new file with mode: 0644]
arch/blackfin/mach-common/Makefile
arch/blackfin/mach-common/scb-init.c [new file with mode: 0644]
arch/c6x/Kconfig
arch/c6x/kernel/devicetree.c
arch/cris/Kconfig
arch/cris/arch-v10/drivers/Kconfig
arch/cris/arch-v10/drivers/Makefile
arch/cris/arch-v32/drivers/Kconfig
arch/cris/arch-v32/mach-a3/Kconfig
arch/cris/include/asm/processor.h
arch/cris/include/uapi/asm/kvm_para.h [new file with mode: 0644]
arch/cris/mm/fault.c
arch/frv/Kconfig
arch/frv/mm/fault.c
arch/h8300/Kconfig
arch/hexagon/Kconfig
arch/hexagon/mm/vm_fault.c
arch/ia64/Kconfig
arch/ia64/mm/fault.c
arch/ia64/mm/hugetlbpage.c
arch/m32r/Kconfig
arch/m32r/mm/fault.c
arch/m68k/Kconfig
arch/m68k/Kconfig.machine
arch/m68k/include/asm/io_no.h
arch/m68k/include/asm/page.h
arch/m68k/include/asm/page_mm.h
arch/m68k/kernel/setup_no.c
arch/m68k/kernel/signal.c
arch/m68k/mm/fault.c
arch/m68k/platform/68000/m68328.c
arch/m68k/platform/68000/m68EZ328.c
arch/m68k/platform/68000/m68VZ328.c
arch/m68k/platform/68360/commproc.c
arch/m68k/platform/68360/config.c
arch/metag/Kconfig
arch/metag/Kconfig.soc
arch/metag/boot/dts/tz1090.dtsi
arch/metag/mm/fault.c
arch/metag/mm/hugetlbpage.c
arch/metag/mm/init.c
arch/microblaze/Kconfig
arch/microblaze/kernel/prom.c
arch/microblaze/mm/fault.c
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/common/usb.c
arch/mips/ath79/clock.c
arch/mips/ath79/common.h
arch/mips/ath79/dev-common.c
arch/mips/ath79/setup.c
arch/mips/bcm63xx/cpu.c
arch/mips/bcm63xx/nvram.c
arch/mips/boot/.gitignore
arch/mips/boot/Makefile
arch/mips/boot/compressed/Makefile
arch/mips/boot/dts/include/dt-bindings [new symlink]
arch/mips/cavium-octeon/csrc-octeon.c
arch/mips/cavium-octeon/octeon-irq.c
arch/mips/cavium-octeon/setup.c
arch/mips/cavium-octeon/smp.c
arch/mips/configs/xway_defconfig [new file with mode: 0644]
arch/mips/dec/ioasic-irq.c
arch/mips/dec/prom/init.c
arch/mips/dec/time.c
arch/mips/include/asm/Kbuild
arch/mips/include/asm/bmips.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu-info.h
arch/mips/include/asm/cpu-type.h [new file with mode: 0644]
arch/mips/include/asm/cpu.h
arch/mips/include/asm/cputime.h [deleted file]
arch/mips/include/asm/current.h [deleted file]
arch/mips/include/asm/dec/ioasic.h
arch/mips/include/asm/emergency-restart.h [deleted file]
arch/mips/include/asm/local64.h [deleted file]
arch/mips/include/asm/mach-ath79/cpu-feature-overrides.h
arch/mips/include/asm/mach-au1x00/au1000.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_nvram.h
arch/mips/include/asm/mach-cavium-octeon/gpio.h [new file with mode: 0644]
arch/mips/include/asm/mach-ip22/cpu-feature-overrides.h
arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h
arch/mips/include/asm/mach-ip28/cpu-feature-overrides.h
arch/mips/include/asm/mach-lantiq/falcon/cpu-feature-overrides.h [new file with mode: 0644]
arch/mips/include/asm/mach-ralink/mt7620.h
arch/mips/include/asm/mach-ralink/mt7620/cpu-feature-overrides.h [new file with mode: 0644]
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/mutex.h [deleted file]
arch/mips/include/asm/netlogic/xlp-hal/bridge.h
arch/mips/include/asm/netlogic/xlp-hal/iomap.h
arch/mips/include/asm/netlogic/xlp-hal/pic.h
arch/mips/include/asm/netlogic/xlp-hal/sys.h
arch/mips/include/asm/netlogic/xlp-hal/xlp.h
arch/mips/include/asm/netlogic/xlr/pic.h
arch/mips/include/asm/octeon/octeon.h
arch/mips/include/asm/parport.h [deleted file]
arch/mips/include/asm/pci.h
arch/mips/include/asm/percpu.h [deleted file]
arch/mips/include/asm/scatterlist.h [deleted file]
arch/mips/include/asm/sections.h [deleted file]
arch/mips/include/asm/segment.h [deleted file]
arch/mips/include/asm/serial.h [deleted file]
arch/mips/include/asm/timex.h
arch/mips/include/asm/ucontext.h [deleted file]
arch/mips/include/asm/vga.h
arch/mips/include/asm/xor.h [deleted file]
arch/mips/include/uapi/asm/Kbuild
arch/mips/include/uapi/asm/auxvec.h [deleted file]
arch/mips/include/uapi/asm/ipcbuf.h [deleted file]
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/csrc-ioasic.c
arch/mips/kernel/idle.c
arch/mips/kernel/mcount.S
arch/mips/kernel/prom.c
arch/mips/kernel/relocate_kernel.S
arch/mips/kernel/setup.c
arch/mips/kernel/smp-cmp.c
arch/mips/kernel/time.c
arch/mips/kernel/traps.c
arch/mips/kernel/vmlinux.lds.S
arch/mips/kernel/vpe.c
arch/mips/lantiq/falcon/sysctrl.c
arch/mips/lantiq/xway/Makefile
arch/mips/lantiq/xway/dcdc.c [new file with mode: 0644]
arch/mips/lasat/image/Makefile
arch/mips/loongson/common/Makefile
arch/mips/math-emu/cp1emu.c
arch/mips/mm/c-octeon.c
arch/mips/mm/c-r4k.c
arch/mips/mm/dma-default.c
arch/mips/mm/fault.c
arch/mips/mm/gup.c
arch/mips/mm/hugetlbpage.c
arch/mips/mm/init.c
arch/mips/mm/page.c
arch/mips/mm/sc-mips.c
arch/mips/mm/tlb-funcs.S
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlbex.c
arch/mips/mti-malta/malta-time.c
arch/mips/mti-sead3/sead3-time.c
arch/mips/netlogic/Kconfig
arch/mips/netlogic/common/smp.c
arch/mips/netlogic/common/time.c
arch/mips/netlogic/dts/Makefile
arch/mips/netlogic/dts/xlp_evp.dts
arch/mips/netlogic/dts/xlp_fvp.dts [new file with mode: 0644]
arch/mips/netlogic/dts/xlp_svp.dts
arch/mips/netlogic/xlp/Makefile
arch/mips/netlogic/xlp/dt.c
arch/mips/netlogic/xlp/nlm_hal.c
arch/mips/netlogic/xlp/setup.c
arch/mips/netlogic/xlp/usb-init-xlp2.c [new file with mode: 0644]
arch/mips/netlogic/xlp/usb-init.c
arch/mips/netlogic/xlp/wakeup.c
arch/mips/netlogic/xlr/fmn-config.c
arch/mips/oprofile/common.c
arch/mips/pci/Makefile
arch/mips/pci/pci-bcm1480.c
arch/mips/pci/pci-octeon.c
arch/mips/pci/pci-rt3883.c [new file with mode: 0644]
arch/mips/powertv/Kconfig
arch/mips/powertv/asic/asic_devices.c
arch/mips/powertv/init.c
arch/mips/powertv/reset.c
arch/mips/ralink/Kconfig
arch/mips/ralink/Makefile
arch/mips/ralink/Platform
arch/mips/ralink/cevt-rt3352.c [new file with mode: 0644]
arch/mips/ralink/clk.c
arch/mips/ralink/common.h
arch/mips/ralink/mt7620.c
arch/mips/ralink/of.c
arch/mips/ralink/reset.c
arch/mips/ralink/timer.c [new file with mode: 0644]
arch/mips/sibyte/bcm1480/setup.c
arch/mips/sibyte/sb1250/setup.c
arch/mips/sni/setup.c
arch/mips/txx9/generic/setup.c
arch/mn10300/Kconfig
arch/mn10300/kernel/entry.S
arch/mn10300/mm/fault.c
arch/openrisc/Kconfig
arch/openrisc/kernel/prom.c
arch/openrisc/mm/fault.c
arch/parisc/Kconfig
arch/parisc/mm/fault.c
arch/powerpc/Kconfig
arch/powerpc/include/asm/device.h
arch/powerpc/include/asm/fsl_pamu_stash.h [new file with mode: 0644]
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/smp.c
arch/powerpc/mm/fault.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/sysdev/fsl_pci.h
arch/s390/Kconfig
arch/s390/defconfig
arch/s390/include/asm/irq.h
arch/s390/include/asm/kprobes.h
arch/s390/include/asm/sclp.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_signal.c
arch/s390/kernel/crash_dump.c
arch/s390/kernel/dumpstack.c
arch/s390/kernel/entry.h
arch/s390/kernel/ftrace.c
arch/s390/kernel/irq.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/perf_cpum_cf.c
arch/s390/kernel/perf_event.c
arch/s390/kernel/runtime_instr.c
arch/s390/kernel/smp.c
arch/s390/kernel/suspend.c
arch/s390/mm/fault.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/maccess.c
arch/s390/mm/pgtable.c
arch/s390/net/bpf_jit_comp.c
arch/s390/oprofile/hwsampler.c
arch/score/Kconfig
arch/score/mm/fault.c
arch/sh/Kconfig
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/mm/fault.c
arch/sh/mm/hugetlbpage.c
arch/sparc/Kconfig
arch/sparc/kernel/sys_sparc32.c
arch/sparc/mm/fault_32.c
arch/sparc/mm/fault_64.c
arch/sparc/mm/hugetlbpage.c
arch/tile/Kconfig
arch/tile/gxio/iorpc_mpipe.c
arch/tile/gxio/iorpc_mpipe_info.c
arch/tile/gxio/iorpc_trio.c
arch/tile/gxio/iorpc_usb_host.c
arch/tile/gxio/usb_host.c
arch/tile/include/arch/mpipe.h
arch/tile/include/arch/mpipe_constants.h
arch/tile/include/arch/mpipe_shm.h
arch/tile/include/arch/trio_constants.h
arch/tile/include/asm/page.h
arch/tile/include/asm/pgtable_32.h
arch/tile/include/asm/pgtable_64.h
arch/tile/include/gxio/iorpc_mpipe.h
arch/tile/include/gxio/iorpc_mpipe_info.h
arch/tile/include/gxio/iorpc_trio.h
arch/tile/include/gxio/iorpc_usb_host.h
arch/tile/include/gxio/usb_host.h
arch/tile/kernel/compat.c
arch/tile/kernel/futex_64.S [deleted file]
arch/tile/kernel/setup.c
arch/tile/kernel/unaligned.c
arch/tile/mm/fault.c
arch/tile/mm/hugetlbpage.c
arch/tile/mm/init.c
arch/tile/mm/pgtable.c
arch/um/Kconfig.common
arch/um/defconfig
arch/um/drivers/ubd.h
arch/um/drivers/ubd_kern.c
arch/um/drivers/ubd_user.c
arch/um/include/shared/os.h
arch/um/kernel/Makefile
arch/um/kernel/irq.c
arch/um/kernel/maccess.c [new file with mode: 0644]
arch/um/kernel/trap.c
arch/um/os-Linux/aio.c
arch/um/os-Linux/file.c
arch/um/os-Linux/main.c
arch/um/os-Linux/process.c
arch/um/os-Linux/sigio.c
arch/um/os-Linux/util.c
arch/unicore32/Kconfig
arch/unicore32/mm/fault.c
arch/x86/Kconfig
arch/x86/include/asm/dma-contiguous.h
arch/x86/include/asm/jump_label.h
arch/x86/include/asm/pgtable.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/tlbflush.h
arch/x86/kernel/cpu/mtrr/generic.c
arch/x86/kernel/cpu/perf_event_intel.c
arch/x86/kernel/cpu/perf_event_intel_ds.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/devicetree.c
arch/x86/kernel/early-quirks.c
arch/x86/kernel/entry_32.S
arch/x86/kernel/entry_64.S
arch/x86/kernel/jump_label.c
arch/x86/kernel/smpboot.c
arch/x86/kvm/emulate.c
arch/x86/kvm/mmu.c
arch/x86/kvm/paging_tmpl.h
arch/x86/kvm/vmx.c
arch/x86/lguest/boot.c
arch/x86/mm/fault.c
arch/x86/mm/hugetlbpage.c
arch/x86/mm/tlb.c
arch/x86/um/os-Linux/prctl.c
arch/x86/xen/enlighten.c
arch/x86/xen/p2m.c
arch/x86/xen/smp.c
arch/x86/xen/spinlock.c
arch/xtensa/Kconfig
arch/xtensa/Makefile
arch/xtensa/boot/Makefile
arch/xtensa/configs/common_defconfig
arch/xtensa/configs/iss_defconfig
arch/xtensa/configs/s6105_defconfig
arch/xtensa/include/asm/regs.h
arch/xtensa/include/asm/timex.h
arch/xtensa/kernel/align.S
arch/xtensa/kernel/coprocessor.S
arch/xtensa/kernel/entry.S
arch/xtensa/kernel/setup.c
arch/xtensa/kernel/time.c
arch/xtensa/kernel/vectors.S
arch/xtensa/kernel/xtensa_ksyms.c
arch/xtensa/mm/fault.c
block/Kconfig
block/Makefile
block/blk-ioc.c
block/blk-sysfs.c
block/cmdline-parser.c [new file with mode: 0644]
block/compat_ioctl.c
block/partitions/Kconfig
block/partitions/Makefile
block/partitions/check.c
block/partitions/cmdline.c [new file with mode: 0644]
block/partitions/cmdline.h [new file with mode: 0644]
block/partitions/efi.c
block/partitions/efi.h
crypto/Makefile
crypto/api.c
crypto/crct10dif.c [deleted file]
crypto/crct10dif_common.c [new file with mode: 0644]
crypto/crct10dif_generic.c [new file with mode: 0644]
drivers/acpi/acpi_lpss.c
drivers/acpi/acpica/exstore.c
drivers/acpi/glue.c
drivers/acpi/scan.c
drivers/atm/he.c
drivers/atm/nicstar.c
drivers/base/dma-buf.c
drivers/base/dma-contiguous.c
drivers/base/node.c
drivers/bcma/host_pci.c
drivers/block/aoe/aoe.h
drivers/block/aoe/aoeblk.c
drivers/block/aoe/aoecmd.c
drivers/block/aoe/aoedev.c
drivers/block/cciss.c
drivers/block/mg_disk.c
drivers/block/mtip32xx/Kconfig
drivers/block/nvme-core.c
drivers/block/nvme-scsi.c
drivers/block/osdblk.c
drivers/block/pktcdvd.c
drivers/block/rbd.c
drivers/block/swim.c
drivers/block/xen-blkback/xenbus.c
drivers/char/random.c
drivers/char/tpm/tpm_tis.c
drivers/char/virtio_console.c
drivers/clk/Kconfig
drivers/clk/Makefile
drivers/clk/clk-bcm2835.c
drivers/clk/clk-divider.c
drivers/clk/clk-fixed-factor.c
drivers/clk/clk-fixed-rate.c
drivers/clk/clk-gate.c
drivers/clk/clk-mux.c
drivers/clk/clk-nomadik.c
drivers/clk/clk-prima2.c
drivers/clk/clk-s2mps11.c [new file with mode: 0644]
drivers/clk/clk-u300.c
drivers/clk/clk-wm831x.c
drivers/clk/clk.c
drivers/clk/mmp/clk-mmp2.c
drivers/clk/mmp/clk-pxa168.c
drivers/clk/mmp/clk-pxa910.c
drivers/clk/mvebu/armada-370.c
drivers/clk/mvebu/armada-xp.c
drivers/clk/mvebu/clk-cpu.c
drivers/clk/mvebu/common.c
drivers/clk/mvebu/dove.c
drivers/clk/mvebu/kirkwood.c
drivers/clk/mxs/clk-imx23.c
drivers/clk/mxs/clk.h
drivers/clk/samsung/Makefile
drivers/clk/samsung/clk-exynos-audss.c
drivers/clk/samsung/clk-exynos4.c
drivers/clk/samsung/clk-exynos5250.c
drivers/clk/samsung/clk-exynos5420.c
drivers/clk/samsung/clk-exynos5440.c
drivers/clk/samsung/clk-pll.c
drivers/clk/samsung/clk-pll.h
drivers/clk/samsung/clk-s3c64xx.c [new file with mode: 0644]
drivers/clk/samsung/clk.c
drivers/clk/samsung/clk.h
drivers/clk/spear/spear1310_clock.c
drivers/clk/spear/spear1340_clock.c
drivers/clk/spear/spear3xx_clock.c
drivers/clk/spear/spear6xx_clock.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/tegra/clk-tegra114.c
drivers/clk/tegra/clk-tegra20.c
drivers/clk/tegra/clk-tegra30.c
drivers/clk/versatile/clk-vexpress.c
drivers/clk/zynq/clkc.c
drivers/clk/zynq/pll.c
drivers/clocksource/em_sti.c
drivers/clocksource/nomadik-mtu.c
drivers/clocksource/samsung_pwm_timer.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/time-armada-370-xp.c
drivers/cpufreq/cpufreq.c
drivers/cpufreq/cpufreq_stats.c
drivers/cpufreq/intel_pstate.c
drivers/cpuidle/Kconfig.arm
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-big_little.c [new file with mode: 0644]
drivers/cpuidle/driver.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/acpi-dma.c
drivers/dma/amba-pl08x.c
drivers/dma/dmaengine.c
drivers/dma/dmatest.c
drivers/dma/dw/Kconfig
drivers/dma/dw/core.c
drivers/dma/dw/platform.c
drivers/dma/edma.c
drivers/dma/ep93xx_dma.c
drivers/dma/fsldma.c
drivers/dma/imx-dma.c
drivers/dma/imx-sdma.c
drivers/dma/ioat/dma_v3.c
drivers/dma/iop-adma.c
drivers/dma/ipu/ipu_idmac.c
drivers/dma/k3dma.c [new file with mode: 0644]
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/mpc512x_dma.c
drivers/dma/mv_xor.c
drivers/dma/mv_xor.h
drivers/dma/mxs-dma.c
drivers/dma/of-dma.c
drivers/dma/pch_dma.c
drivers/dma/pl330.c
drivers/dma/sh/Kconfig
drivers/dma/sh/Makefile
drivers/dma/sh/rcar-hpbdma.c [new file with mode: 0644]
drivers/dma/sh/shdma-arm.h [new file with mode: 0644]
drivers/dma/sh/shdma-base.c
drivers/dma/sh/shdma-of.c
drivers/dma/sh/shdma-r8a73a4.c [new file with mode: 0644]
drivers/dma/sh/shdma.c [deleted file]
drivers/dma/sh/shdma.h
drivers/dma/sh/shdmac.c [new file with mode: 0644]
drivers/dma/sh/sudmac.c
drivers/dma/sirf-dma.c
drivers/dma/ste_dma40.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/timb_dma.c
drivers/dma/txx9dmac.c
drivers/firewire/core-cdev.c
drivers/firewire/core-transaction.c
drivers/firewire/ohci.c
drivers/firmware/dmi_scan.c
drivers/firmware/google/gsmi.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpio-octeon.c [new file with mode: 0644]
drivers/gpio/gpiolib-of.c
drivers/gpu/drm/ast/ast_drv.h
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_dmabuf.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_stolen.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/intel_crt.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sprite.c
drivers/gpu/drm/i915/intel_uncore.c
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/ci_smc.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cypress_dpm.c
drivers/gpu/drm/radeon/dce6_afmt.c
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/kv_dpm.h
drivers/gpu/drm/radeon/kv_smc.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/ppsmc.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/r600d.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_trace.h
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rs780_dpm.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/rv770_smc.c
drivers/gpu/drm/radeon/rv770_smc.h
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/si_smc.c
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.h
drivers/gpu/drm/radeon/trinity_smc.c
drivers/gpu/drm/ttm/ttm_object.c
drivers/gpu/drm/ttm/ttm_page_alloc.c
drivers/gpu/drm/ttm/ttm_page_alloc_dma.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/vga/vgaarb.c
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-input.c
drivers/hid/hid-lenovo-tpkbd.c
drivers/hid/hid-lg2ff.c
drivers/hid/hid-lg3ff.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-lgff.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-sony.c
drivers/hid/hid-steelseries.c
drivers/hid/hid-zpff.c
drivers/hwmon/amc6821.c
drivers/hwmon/emc2103.c
drivers/hwmon/hwmon-vid.c
drivers/hwmon/ibmaem.c
drivers/hwmon/ina2xx.c
drivers/hwmon/k10temp.c
drivers/hwmon/tmp421.c
drivers/i2c/Kconfig
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-davinci.c
drivers/iio/Kconfig
drivers/infiniband/hw/qib/Kconfig
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/input/evdev.c
drivers/input/keyboard/Kconfig
drivers/input/serio/Kconfig
drivers/input/touchscreen/Kconfig
drivers/iommu/Kconfig
drivers/iommu/Makefile
drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/arm-smmu.c
drivers/iommu/exynos-iommu.c
drivers/iommu/fsl_pamu.c [new file with mode: 0644]
drivers/iommu/fsl_pamu.h [new file with mode: 0644]
drivers/iommu/fsl_pamu_domain.c [new file with mode: 0644]
drivers/iommu/fsl_pamu_domain.h [new file with mode: 0644]
drivers/iommu/intel-iommu.c
drivers/iommu/msm_iommu_dev.c
drivers/iommu/omap-iommu.c
drivers/irqchip/Kconfig
drivers/irqchip/Makefile
drivers/irqchip/irq-gic.c
drivers/irqchip/irq-imgpdc.c [new file with mode: 0644]
drivers/irqchip/irq-mmp.c [new file with mode: 0644]
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/hisax/amd7930_fn.c
drivers/isdn/hisax/avm_pci.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/diva.c
drivers/isdn/hisax/elsa.c
drivers/isdn/hisax/elsa_ser.c
drivers/isdn/hisax/hfc_pci.c
drivers/isdn/hisax/hfc_sx.c
drivers/isdn/hisax/hscx_irq.c
drivers/isdn/hisax/icc.c
drivers/isdn/hisax/ipacx.c
drivers/isdn/hisax/isac.c
drivers/isdn/hisax/isar.c
drivers/isdn/hisax/jade.c
drivers/isdn/hisax/jade_irq.c
drivers/isdn/hisax/l3_1tr6.c
drivers/isdn/hisax/netjet.c
drivers/isdn/hisax/q931.c
drivers/isdn/hisax/w6692.c
drivers/leds/Kconfig
drivers/leds/Makefile
drivers/leds/leds-88pm860x.c
drivers/leds/leds-adp5520.c
drivers/leds/leds-asic3.c
drivers/leds/leds-atmel-pwm.c
drivers/leds/leds-bd2802.c
drivers/leds/leds-clevo-mail.c
drivers/leds/leds-da903x.c
drivers/leds/leds-da9052.c
drivers/leds/leds-gpio.c
drivers/leds/leds-lm3530.c
drivers/leds/leds-lm3533.c
drivers/leds/leds-lm355x.c
drivers/leds/leds-lm3642.c
drivers/leds/leds-lp3944.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lp5562.c
drivers/leds/leds-lp55xx-common.c
drivers/leds/leds-lp55xx-common.h
drivers/leds/leds-lp8501.c [new file with mode: 0644]
drivers/leds/leds-lt3593.c
drivers/leds/leds-netxbig.c
drivers/leds/leds-ns2.c
drivers/leds/leds-pca9532.c
drivers/leds/leds-pca955x.c
drivers/leds/leds-pca9633.c [deleted file]
drivers/leds/leds-pca963x.c [new file with mode: 0644]
drivers/leds/leds-pwm.c
drivers/leds/leds-regulator.c
drivers/leds/leds-s3c24xx.c
drivers/leds/leds-ss4200.c
drivers/leds/leds-tca6507.c
drivers/leds/leds-wm831x-status.c
drivers/leds/leds-wm8350.c
drivers/leds/trigger/ledtrig-backlight.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/page_tables.c
drivers/md/Makefile
drivers/md/bcache/btree.c
drivers/md/bcache/sysfs.c
drivers/md/dm-bufio.c
drivers/md/dm-cache-target.c
drivers/md/dm-crypt.c
drivers/md/dm-ioctl.c
drivers/md/dm-kcopyd.c
drivers/md/dm-raid1.c
drivers/md/dm-stats.c [new file with mode: 0644]
drivers/md/dm-stats.h [new file with mode: 0644]
drivers/md/dm-stripe.c
drivers/md/dm-table.c
drivers/md/dm-target.c
drivers/md/dm-thin.c
drivers/md/dm.c
drivers/md/dm.h
drivers/md/md.c
drivers/md/md.h
drivers/md/persistent-data/dm-block-manager.c
drivers/md/persistent-data/dm-block-manager.h
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-space-map-common.c
drivers/md/raid5.c
drivers/md/raid5.h
drivers/media/platform/Kconfig
drivers/media/radio/Kconfig
drivers/memstick/core/Kconfig
drivers/memstick/core/Makefile
drivers/memstick/core/ms_block.c [new file with mode: 0644]
drivers/memstick/core/ms_block.h [new file with mode: 0644]
drivers/memstick/host/rtsx_pci_ms.c
drivers/mfd/88pm800.c
drivers/mfd/88pm805.c
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/aat2870-core.c
drivers/mfd/ab3100-core.c
drivers/mfd/ab8500-debugfs.c
drivers/mfd/ab8500-gpadc.c
drivers/mfd/adp5520.c
drivers/mfd/arizona-core.c
drivers/mfd/as3711.c
drivers/mfd/asic3.c
drivers/mfd/da903x.c
drivers/mfd/da9052-core.c
drivers/mfd/da9055-core.c
drivers/mfd/da9055-i2c.c
drivers/mfd/da9063-core.c [new file with mode: 0644]
drivers/mfd/da9063-i2c.c [new file with mode: 0644]
drivers/mfd/da9063-irq.c [new file with mode: 0644]
drivers/mfd/davinci_voicecodec.c
drivers/mfd/db8500-prcmu.c
drivers/mfd/dm355evm_msp.c
drivers/mfd/ezx-pcap.c
drivers/mfd/htc-egpio.c
drivers/mfd/htc-i2cpld.c
drivers/mfd/htc-pasic3.c
drivers/mfd/intel_msic.c
drivers/mfd/kempld-core.c
drivers/mfd/lm3533-core.c
drivers/mfd/lp8788.c
drivers/mfd/lpc_ich.c
drivers/mfd/max77686.c
drivers/mfd/max77693.c
drivers/mfd/max8925-i2c.c
drivers/mfd/max8997.c
drivers/mfd/max8998.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/menelaus.c
drivers/mfd/mfd-core.c
drivers/mfd/omap-usb-host.c
drivers/mfd/palmas.c
drivers/mfd/pcf50633-adc.c
drivers/mfd/pcf50633-core.c
drivers/mfd/pm8921-core.c
drivers/mfd/rc5t583.c
drivers/mfd/rtl8411.c
drivers/mfd/rts5209.c
drivers/mfd/rts5227.c
drivers/mfd/rts5229.c
drivers/mfd/rts5249.c
drivers/mfd/rtsx_pcr.c
drivers/mfd/rtsx_pcr.h
drivers/mfd/sec-core.c
drivers/mfd/si476x-i2c.c
drivers/mfd/sm501.c
drivers/mfd/sta2x11-mfd.c
drivers/mfd/stmpe.c
drivers/mfd/syscon.c
drivers/mfd/t7l66xb.c
drivers/mfd/tc3589x.c
drivers/mfd/tc6387xb.c
drivers/mfd/tc6393xb.c
drivers/mfd/ti-ssp.c
drivers/mfd/ti_am335x_tscadc.c
drivers/mfd/timberdale.c
drivers/mfd/tps6105x.c
drivers/mfd/tps65010.c
drivers/mfd/tps65090.c
drivers/mfd/tps6586x.c
drivers/mfd/tps65912-core.c
drivers/mfd/tps80031.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-audio.c
drivers/mfd/twl4030-madc.c
drivers/mfd/twl4030-power.c
drivers/mfd/twl6030-irq.c
drivers/mfd/twl6040.c
drivers/mfd/ucb1400_core.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/wl1273-core.c
drivers/mfd/wm5110-tables.c
drivers/mfd/wm831x-core.c
drivers/mfd/wm831x-irq.c
drivers/mfd/wm831x-spi.c
drivers/mfd/wm8350-i2c.c
drivers/mfd/wm8400-core.c
drivers/mfd/wm8994-core.c
drivers/mfd/wm8994-irq.c
drivers/misc/cb710/Kconfig
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sd.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc-pci.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmc_spi.c
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/of_mmc_spi.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-bcm2835.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc_dma.c
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/vub300.c
drivers/mtd/bcm63xxpart.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/gen_probe.c
drivers/mtd/chips/jedec_probe.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/bcm47xxsflash.c
drivers/mtd/devices/bcm47xxsflash.h
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/elm.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/spear_smi.c
drivers/mtd/devices/sst25l.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/Makefile
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/cfi_flagadm.c
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/impa7.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/octagon-5066.c [deleted file]
drivers/mtd/maps/physmap.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/rbtx4939-flash.c
drivers/mtd/maps/sa1100-flash.c
drivers/mtd/maps/vmax301.c [deleted file]
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/mtdswap.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/Makefile
drivers/mtd/nand/alauda.c [deleted file]
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/atmel_nand_nfc.h [new file with mode: 0644]
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/docg4.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_bbt.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nandsim.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/r852.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/sm_common.c
drivers/mtd/nand/tmio_nand.c
drivers/mtd/nand/txx9ndfmc.c
drivers/mtd/ofpart.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/onenand_bbt.c
drivers/mtd/onenand/samsung.c
drivers/mtd/sm_ftl.c
drivers/mtd/tests/Makefile
drivers/mtd/tests/mtd_nandbiterrs.c [deleted file]
drivers/mtd/tests/mtd_oobtest.c [deleted file]
drivers/mtd/tests/mtd_pagetest.c [deleted file]
drivers/mtd/tests/mtd_readtest.c [deleted file]
drivers/mtd/tests/mtd_speedtest.c [deleted file]
drivers/mtd/tests/mtd_stresstest.c [deleted file]
drivers/mtd/tests/mtd_subpagetest.c [deleted file]
drivers/mtd/tests/mtd_test.c [new file with mode: 0644]
drivers/mtd/tests/mtd_test.h [new file with mode: 0644]
drivers/mtd/tests/mtd_torturetest.c [deleted file]
drivers/mtd/tests/nandbiterrs.c [new file with mode: 0644]
drivers/mtd/tests/oobtest.c [new file with mode: 0644]
drivers/mtd/tests/pagetest.c [new file with mode: 0644]
drivers/mtd/tests/readtest.c [new file with mode: 0644]
drivers/mtd/tests/speedtest.c [new file with mode: 0644]
drivers/mtd/tests/stresstest.c [new file with mode: 0644]
drivers/mtd/tests/subpagetest.c [new file with mode: 0644]
drivers/mtd/tests/torturetest.c [new file with mode: 0644]
drivers/mtd/ubi/fastmap.c
drivers/mtd/ubi/wl.c
drivers/net/bonding/bond_alb.c
drivers/net/bonding/bond_alb.h
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/ethernet/adi/bfin_mac.c
drivers/net/ethernet/amd/declance.c
drivers/net/ethernet/amd/sun3lance.c
drivers/net/ethernet/atheros/alx/main.c
drivers/net/ethernet/broadcom/bcm63xx_enet.c
drivers/net/ethernet/broadcom/bgmac.c
drivers/net/ethernet/broadcom/bgmac.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c
drivers/net/ethernet/broadcom/cnic.c
drivers/net/ethernet/broadcom/tg3.c
drivers/net/ethernet/broadcom/tg3.h
drivers/net/ethernet/cadence/Kconfig
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/dec/tulip/de4x5.c
drivers/net/ethernet/emulex/benet/be_main.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/ethernet/hp/hp100.c
drivers/net/ethernet/ibm/ehea/ehea_main.c
drivers/net/ethernet/intel/Kconfig
drivers/net/ethernet/intel/Makefile
drivers/net/ethernet/intel/e1000e/ethtool.c
drivers/net/ethernet/intel/e1000e/ich8lan.c
drivers/net/ethernet/intel/e1000e/ich8lan.h
drivers/net/ethernet/intel/e1000e/netdev.c
drivers/net/ethernet/intel/i40e/Makefile [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_adminq.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_adminq.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_alloc.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_common.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_debugfs.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_diag.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_diag.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_ethtool.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_hmc.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_hmc.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_main.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_nvm.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_osdep.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_prototype.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_register.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_status.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_txrx.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_txrx.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_type.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_virtchnl.h [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c [new file with mode: 0644]
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h [new file with mode: 0644]
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_mac.c
drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
drivers/net/ethernet/korina.c
drivers/net/ethernet/lantiq_etop.c
drivers/net/ethernet/marvell/pxa168_eth.c
drivers/net/ethernet/marvell/skge.c
drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
drivers/net/ethernet/micrel/ks8851_mll.c
drivers/net/ethernet/natsemi/jazzsonic.c
drivers/net/ethernet/natsemi/xtsonic.c
drivers/net/ethernet/pasemi/pasemi_mac.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/realtek/r8169.c
drivers/net/ethernet/sfc/Kconfig
drivers/net/ethernet/sfc/ef10.c
drivers/net/ethernet/sfc/mcdi_port.c
drivers/net/ethernet/sfc/nic.h
drivers/net/ethernet/smsc/smc91x.h
drivers/net/ethernet/smsc/smsc9420.c
drivers/net/ethernet/tile/tilegx.c
drivers/net/ethernet/toshiba/ps3_gelic_net.c
drivers/net/irda/donauboe.c
drivers/net/irda/mcs7780.c
drivers/net/irda/vlsi_ir.c
drivers/net/loopback.c
drivers/net/macvlan.c
drivers/net/netconsole.c
drivers/net/phy/cicada.c
drivers/net/ppp/pptp.c
drivers/net/tun.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/qmi_wwan.c
drivers/net/vxlan.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo.c
drivers/net/wireless/ath/Kconfig
drivers/net/wireless/ath/Makefile
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ath10k/bmi.c
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/htc.c
drivers/net/wireless/ath/ath10k/htc.h
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.h
drivers/net/wireless/ath/ath10k/rx_desc.h
drivers/net/wireless/ath/ath10k/trace.h
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/txrx.h
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath5k/ahb.c
drivers/net/wireless/ath/ath9k/ahb.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/antenna.c
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_phy.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9003_rtt.c
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ar9565_1p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/calib.c
drivers/net/wireless/ath/ath9k/common.c
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/dfs_debug.c
drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_debug.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/wmi.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/wcn36xx/Kconfig [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/Makefile [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/debug.c [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/debug.h [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/dxe.c [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/dxe.h [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/hal.h [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/main.c [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/pmc.c [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/pmc.h [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/smd.c [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/smd.h [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/txrx.c [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/txrx.h [new file with mode: 0644]
drivers/net/wireless/ath/wcn36xx/wcn36xx.h [new file with mode: 0644]
drivers/net/wireless/ath/wil6210/pcie_bus.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fweh.h
drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
drivers/net/wireless/cw1200/cw1200_spi.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/iwlegacy/3945-mac.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/orinoco_nortel.c
drivers/net/wireless/orinoco/orinoco_pci.c
drivers/net/wireless/orinoco/orinoco_plx.c
drivers/net/wireless/orinoco/orinoco_tmd.c
drivers/net/wireless/p54/Kconfig
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00crypto.c
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rt2x00/rt2x00pci.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rt2x00/rt2x00usb.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/base.h
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/rtl8188ee/hw.c
drivers/net/wireless/rtlwifi/rtl8188ee/phy.c
drivers/net/wireless/rtlwifi/rtl8188ee/phy.h
drivers/net/wireless/rtlwifi/rtl8188ee/sw.c
drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.h
drivers/net/wireless/rtlwifi/rtl8192ce/def.h
drivers/net/wireless/rtlwifi/rtl8192ce/phy.h
drivers/net/wireless/rtlwifi/rtl8192ce/reg.h
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/rtlwifi/rtl8192de/dm.c
drivers/net/wireless/rtlwifi/rtl8192de/hw.c
drivers/net/wireless/rtlwifi/rtl8192de/phy.c
drivers/net/wireless/rtlwifi/rtl8192de/phy.h
drivers/net/wireless/rtlwifi/rtl8192de/sw.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/reg.h
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wl1251/Kconfig
drivers/net/wireless/ti/wl1251/spi.c
drivers/net/wireless/ti/wl1251/wl1251.h
drivers/net/wireless/ti/wl12xx/main.c
drivers/net/wireless/ti/wl18xx/main.c
drivers/net/wireless/ti/wl18xx/reg.h
drivers/net/wireless/ti/wlcore/Kconfig
drivers/net/wireless/ti/wlcore/cmd.c
drivers/net/wireless/ti/wlcore/main.c
drivers/net/wireless/ti/wlcore/ps.c
drivers/net/wireless/ti/wlcore/scan.c
drivers/net/wireless/ti/wlcore/spi.c
drivers/net/wireless/ti/wlcore/testmode.c
drivers/net/wireless/ti/wlcore/tx.c
drivers/net/wireless/ti/wlcore/tx.h
drivers/net/wireless/ti/wlcore/wlcore.h
drivers/net/wireless/ti/wlcore/wlcore_i.h
drivers/net/xen-netback/common.h
drivers/net/xen-netback/interface.c
drivers/net/xen-netback/netback.c
drivers/net/xen-netback/xenbus.c
drivers/ntb/Kconfig
drivers/ntb/ntb_hw.c
drivers/ntb/ntb_hw.h
drivers/ntb/ntb_regs.h
drivers/ntb/ntb_transport.c
drivers/of/Kconfig
drivers/of/Makefile
drivers/of/base.c
drivers/of/fdt.c
drivers/of/irq.c
drivers/of/of_net.c
drivers/of/of_reserved_mem.c [new file with mode: 0644]
drivers/of/platform.c
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/msi.c
drivers/platform/x86/Kconfig
drivers/platform/x86/amilo-rfkill.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/classmate-laptop.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/hp-wmi.c
drivers/platform/x86/intel-rst.c
drivers/platform/x86/intel-smartconnect.c
drivers/platform/x86/intel_mid_powerbtn.c
drivers/platform/x86/intel_mid_thermal.c
drivers/platform/x86/panasonic-laptop.c
drivers/platform/x86/samsung-q10.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/wmi.c
drivers/pnp/driver.c
drivers/power/Kconfig
drivers/power/Makefile
drivers/power/ab8500_charger.c
drivers/power/bq24190_charger.c [new file with mode: 0644]
drivers/power/collie_battery.c
drivers/power/max8925_power.c
drivers/power/power_supply_core.c
drivers/power/power_supply_sysfs.c
drivers/power/reset/Kconfig
drivers/power/reset/Makefile
drivers/power/reset/msm-poweroff.c [new file with mode: 0644]
drivers/power/reset/xgene-reboot.c [new file with mode: 0644]
drivers/power/rx51_battery.c
drivers/power/tosa_battery.c
drivers/power/twl4030_charger.c
drivers/power/twl4030_madc_battery.c [new file with mode: 0644]
drivers/pps/clients/Kconfig
drivers/pps/clients/pps-gpio.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1742.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-hid-sensor-time.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-lpc32xx.c
drivers/rtc/rtc-max77686.c
drivers/rtc/rtc-moxart.c [new file with mode: 0644]
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-palmas.c
drivers/rtc/rtc-pcf2127.c
drivers/rtc/rtc-sirfsoc.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-tx4939.c
drivers/s390/block/dasd_diag.c
drivers/s390/char/fs3270.c
drivers/s390/char/sclp.c
drivers/s390/char/tty3270.c
drivers/s390/char/zcore.c
drivers/s390/crypto/ap_bus.c
drivers/s390/kvm/kvm_virtio.c
drivers/scsi/aic7xxx/aic7xxx_pci.c
drivers/scsi/bnx2fc/bnx2fc.h
drivers/scsi/bnx2fc/bnx2fc_hwi.c
drivers/scsi/bnx2i/bnx2i.h
drivers/scsi/bnx2i/bnx2i_hwi.c
drivers/scsi/esas2r/esas2r_flash.c
drivers/scsi/esas2r/esas2r_init.c
drivers/scsi/esas2r/esas2r_ioctl.c
drivers/scsi/esas2r/esas2r_vda.c
drivers/scsi/fnic/fnic.h
drivers/scsi/fnic/fnic_main.c
drivers/scsi/fnic/fnic_scsi.c
drivers/scsi/fnic/vnic_scsi.h
drivers/scsi/hpsa.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/ibmvscsi/viosrp.h
drivers/scsi/lpfc/lpfc.h
drivers/scsi/lpfc/lpfc_attr.c
drivers/scsi/lpfc/lpfc_bsg.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_scsi.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli.h
drivers/scsi/lpfc/lpfc_sli4.h
drivers/scsi/lpfc/lpfc_version.h
drivers/scsi/megaraid/megaraid_sas.h
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fp.c
drivers/scsi/megaraid/megaraid_sas_fusion.c
drivers/scsi/megaraid/megaraid_sas_fusion.h
drivers/scsi/mpt3sas/Makefile
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.h
drivers/scsi/sd.c
drivers/scsi/ufs/ufs.h
drivers/scsi/ufs/ufshcd.c
drivers/scsi/ufs/ufshcd.h
drivers/scsi/ufs/ufshci.h
drivers/scsi/ufs/unipro.h [new file with mode: 0644]
drivers/spi/Kconfig
drivers/staging/android/ashmem.c
drivers/staging/android/logger.c
drivers/staging/android/lowmemorykiller.c
drivers/staging/lustre/include/linux/libcfs/linux/linux-mem.h
drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
drivers/staging/lustre/lustre/llite/file.c
drivers/staging/lustre/lustre/obdclass/lu_object.c
drivers/staging/lustre/lustre/ptlrpc/sec_bulk.c
drivers/staging/octeon/ethernet-mem.c
drivers/staging/octeon/ethernet-rgmii.c
drivers/staging/octeon/ethernet-rx.c
drivers/target/Makefile
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target.h
drivers/target/iscsi/iscsi_target_auth.c
drivers/target/iscsi/iscsi_target_configfs.c
drivers/target/iscsi/iscsi_target_core.h
drivers/target/iscsi/iscsi_target_datain_values.c
drivers/target/iscsi/iscsi_target_device.c
drivers/target/iscsi/iscsi_target_erl0.c
drivers/target/iscsi/iscsi_target_erl1.c
drivers/target/iscsi/iscsi_target_erl2.c
drivers/target/iscsi/iscsi_target_login.c
drivers/target/iscsi/iscsi_target_login.h
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_nodeattrib.c
drivers/target/iscsi/iscsi_target_parameters.c
drivers/target/iscsi/iscsi_target_seq_pdu_list.c
drivers/target/iscsi/iscsi_target_stat.c
drivers/target/iscsi/iscsi_target_tmr.c
drivers/target/iscsi/iscsi_target_tpg.c
drivers/target/iscsi/iscsi_target_tpg.h
drivers/target/iscsi/iscsi_target_tq.c
drivers/target/iscsi/iscsi_target_tq.h
drivers/target/iscsi/iscsi_target_util.c
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_alua.c
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_fabric_lib.c
drivers/target/target_core_file.c
drivers/target/target_core_hba.c
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_pr.c
drivers/target/target_core_pscsi.c
drivers/target/target_core_rd.c
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_stat.c
drivers/target/target_core_tmr.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/target_core_ua.c
drivers/target/target_core_xcopy.c [new file with mode: 0644]
drivers/target/target_core_xcopy.h [new file with mode: 0644]
drivers/target/tcm_fc/tfc_conf.c
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/cpu_cooling.c
drivers/thermal/exynos_thermal.c [deleted file]
drivers/thermal/imx_thermal.c [new file with mode: 0644]
drivers/thermal/samsung/Kconfig [new file with mode: 0644]
drivers/thermal/samsung/Makefile [new file with mode: 0644]
drivers/thermal/samsung/exynos_thermal_common.c [new file with mode: 0644]
drivers/thermal/samsung/exynos_thermal_common.h [new file with mode: 0644]
drivers/thermal/samsung/exynos_tmu.c [new file with mode: 0644]
drivers/thermal/samsung/exynos_tmu.h [new file with mode: 0644]
drivers/thermal/samsung/exynos_tmu_data.c [new file with mode: 0644]
drivers/thermal/samsung/exynos_tmu_data.h [new file with mode: 0644]
drivers/thermal/step_wise.c
drivers/thermal/thermal_core.c
drivers/thermal/thermal_hwmon.c [new file with mode: 0644]
drivers/thermal/thermal_hwmon.h [new file with mode: 0644]
drivers/thermal/ti-soc-thermal/dra752-thermal-data.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
drivers/tty/serial/Kconfig
drivers/tty/tty_io.c
drivers/usb/dwc3/Kconfig
drivers/usb/gadget/Kconfig
drivers/usb/gadget/inode.c
drivers/usb/host/Kconfig
drivers/usb/musb/Kconfig
drivers/usb/renesas_usbhs/Kconfig
drivers/vfio/pci/vfio_pci.c
drivers/vfio/pci/vfio_pci_config.c
drivers/vfio/pci/vfio_pci_intrs.c
drivers/vfio/vfio.c
drivers/vhost/scsi.c
drivers/video/acornfb.c
drivers/video/acornfb.h
drivers/video/logo/logo_linux_clut224.ppm
drivers/video/ps3fb.c
drivers/virtio/virtio_pci.c
drivers/w1/masters/Kconfig
drivers/w1/masters/mxc_w1.c
drivers/w1/w1.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/ar7_wdt.c
drivers/watchdog/hpwdt.c
drivers/watchdog/nuc900_wdt.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sunxi_wdt.c [new file with mode: 0644]
drivers/watchdog/ts72xx_wdt.c
drivers/xen/balloon.c
fs/9p/v9fs.c
fs/9p/vfs_file.c
fs/9p/vfs_inode.c
fs/9p/vfs_inode_dotl.c
fs/adfs/inode.c
fs/affs/file.c
fs/afs/dir.c
fs/aio.c
fs/anon_inodes.c
fs/autofs4/dev-ioctl.c
fs/autofs4/waitq.c
fs/bfs/file.c
fs/bio-integrity.c
fs/block_dev.c
fs/btrfs/Kconfig
fs/btrfs/Makefile
fs/btrfs/backref.c
fs/btrfs/backref.h
fs/btrfs/btrfs_inode.h
fs/btrfs/check-integrity.c
fs/btrfs/compression.c
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/delayed-inode.c
fs/btrfs/delayed-ref.c
fs/btrfs/dev-replace.c
fs/btrfs/disk-io.c
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/free-space-cache.c
fs/btrfs/free-space-cache.h
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/lzo.c
fs/btrfs/ordered-data.c
fs/btrfs/ordered-data.h
fs/btrfs/print-tree.c
fs/btrfs/qgroup.c
fs/btrfs/raid56.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/tests/btrfs-tests.h [new file with mode: 0644]
fs/btrfs/tests/free-space-tests.c [new file with mode: 0644]
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/uuid-tree.c [new file with mode: 0644]
fs/btrfs/volumes.c
fs/btrfs/volumes.h
fs/cachefiles/interface.c
fs/cachefiles/internal.h
fs/cachefiles/xattr.c
fs/ceph/Kconfig
fs/ceph/Makefile
fs/ceph/addr.c
fs/ceph/cache.c [new file with mode: 0644]
fs/ceph/cache.h [new file with mode: 0644]
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/mds_client.c
fs/ceph/super.c
fs/ceph/super.h
fs/cifs/AUTHORS [deleted file]
fs/cifs/CHANGES [deleted file]
fs/cifs/Makefile
fs/cifs/README [deleted file]
fs/cifs/TODO [deleted file]
fs/cifs/cifs_unicode.h
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/cifspdu.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/file.c
fs/cifs/inode.c
fs/cifs/link.c
fs/cifs/misc.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/cifs/smb1ops.c
fs/cifs/smb2file.c
fs/cifs/smb2inode.c
fs/cifs/smb2misc.c
fs/cifs/smb2ops.c
fs/cifs/smb2pdu.c
fs/cifs/smb2pdu.h
fs/cifs/smb2proto.h
fs/cifs/smb2transport.c
fs/cifs/winucase.c [new file with mode: 0644]
fs/coredump.c
fs/dcache.c
fs/direct-io.c
fs/drop_caches.c
fs/ecryptfs/crypto.c
fs/eventpoll.c
fs/exec.c
fs/exofs/inode.c
fs/exportfs/expfs.c
fs/ext2/inode.c
fs/ext4/extents_status.c
fs/ext4/inode.c
fs/fat/inode.c
fs/file_table.c
fs/fs-writeback.c
fs/fscache/cookie.c
fs/fscache/internal.h
fs/fscache/page.c
fs/fuse/dev.c
fs/fuse/dir.c
fs/fuse/file.c
fs/fuse/fuse_i.h
fs/fuse/inode.c
fs/gfs2/aops.c
fs/gfs2/bmap.c
fs/gfs2/file.c
fs/gfs2/glock.c
fs/gfs2/inode.c
fs/gfs2/lops.c
fs/gfs2/main.c
fs/gfs2/meta_io.c
fs/gfs2/meta_io.h
fs/gfs2/ops_fstype.c
fs/gfs2/quota.c
fs/gfs2/quota.h
fs/hfs/inode.c
fs/hfsplus/Kconfig
fs/hfsplus/Makefile
fs/hfsplus/acl.h [new file with mode: 0644]
fs/hfsplus/dir.c
fs/hfsplus/hfsplus_fs.h
fs/hfsplus/inode.c
fs/hfsplus/posix_acl.c [new file with mode: 0644]
fs/hfsplus/xattr.c
fs/hfsplus/xattr.h
fs/hfsplus/xattr_security.c
fs/hostfs/hostfs_kern.c
fs/hpfs/file.c
fs/inode.c
fs/internal.h
fs/jfs/inode.c
fs/mbcache.c
fs/minix/inode.c
fs/namei.c
fs/namespace.c
fs/nfs/Makefile
fs/nfs/callback_proc.c
fs/nfs/client.c
fs/nfs/delegation.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4getroot.c
fs/nfs/nfs4namespace.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4session.c
fs/nfs/nfs4session.h
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c
fs/nfs/nfs4trace.c [new file with mode: 0644]
fs/nfs/nfs4trace.h [new file with mode: 0644]
fs/nfs/nfs4xdr.c
fs/nfs/nfstrace.c [new file with mode: 0644]
fs/nfs/nfstrace.h [new file with mode: 0644]
fs/nfs/pagelist.c
fs/nfs/pnfs.c
fs/nfs/proc.c
fs/nfs/read.c
fs/nfs/super.c
fs/nfs/unlink.c
fs/nfs/write.c
fs/nfsd/nfs4recover.c
fs/nfsd/nfs4state.c
fs/nfsd/nfscache.c
fs/nilfs2/inode.c
fs/ntfs/file.c
fs/ocfs2/acl.c
fs/ocfs2/aops.c
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/cluster/tcp.c
fs/ocfs2/dlm/dlmast.c
fs/ocfs2/dlm/dlmcommon.h
fs/ocfs2/dlm/dlmconvert.c
fs/ocfs2/dlm/dlmdebug.c
fs/ocfs2/dlm/dlmdomain.c
fs/ocfs2/dlm/dlmlock.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmrecovery.c
fs/ocfs2/dlm/dlmthread.c
fs/ocfs2/dlm/dlmunlock.c
fs/ocfs2/dlmfs/dlmfs.c
fs/ocfs2/extent_map.c
fs/ocfs2/file.c
fs/ocfs2/ioctl.c
fs/ocfs2/journal.c
fs/ocfs2/journal.h
fs/ocfs2/localalloc.c
fs/ocfs2/move_extents.c
fs/ocfs2/ocfs2_trace.h
fs/ocfs2/quota_global.c
fs/ocfs2/quota_local.c
fs/ocfs2/refcounttree.c
fs/ocfs2/xattr.c
fs/omfs/file.c
fs/open.c
fs/proc/fd.c
fs/proc/meminfo.c
fs/proc/task_mmu.c
fs/proc/vmcore.c
fs/pstore/platform.c
fs/quota/dquot.c
fs/quota/quota.c
fs/ramfs/inode.c
fs/read_write.c
fs/squashfs/block.c
fs/squashfs/dir.c
fs/squashfs/namei.c
fs/squashfs/squashfs_fs.h
fs/super.c
fs/sysv/itree.c
fs/ubifs/debug.c
fs/ubifs/shrinker.c
fs/ubifs/super.c
fs/ubifs/ubifs.h
fs/udf/file.c
fs/udf/inode.c
fs/ufs/inode.c
fs/xfs/Makefile
fs/xfs/kmem.c
fs/xfs/kmem.h
fs/xfs/xfs_acl.c
fs/xfs/xfs_ag.h
fs/xfs/xfs_alloc.c
fs/xfs/xfs_aops.c
fs/xfs/xfs_attr.c
fs/xfs/xfs_attr.h
fs/xfs/xfs_attr_inactive.c [new file with mode: 0644]
fs/xfs/xfs_attr_leaf.c
fs/xfs/xfs_attr_leaf.h
fs/xfs/xfs_attr_list.c [new file with mode: 0644]
fs/xfs/xfs_attr_remote.c
fs/xfs/xfs_bmap.c
fs/xfs/xfs_bmap.h
fs/xfs/xfs_bmap_btree.c
fs/xfs/xfs_bmap_btree.h
fs/xfs/xfs_bmap_util.c [new file with mode: 0644]
fs/xfs/xfs_bmap_util.h [new file with mode: 0644]
fs/xfs/xfs_btree.c
fs/xfs/xfs_btree.h
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_buf_item.c
fs/xfs/xfs_buf_item.h
fs/xfs/xfs_da_btree.c
fs/xfs/xfs_da_btree.h
fs/xfs/xfs_dfrag.c [deleted file]
fs/xfs/xfs_dfrag.h [deleted file]
fs/xfs/xfs_dir2.c
fs/xfs/xfs_dir2.h
fs/xfs/xfs_dir2_block.c
fs/xfs/xfs_dir2_data.c
fs/xfs/xfs_dir2_format.h
fs/xfs/xfs_dir2_leaf.c
fs/xfs/xfs_dir2_node.c
fs/xfs/xfs_dir2_priv.h
fs/xfs/xfs_dir2_readdir.c [new file with mode: 0644]
fs/xfs/xfs_dir2_sf.c
fs/xfs/xfs_discard.c
fs/xfs/xfs_dquot.c
fs/xfs/xfs_dquot_item.c
fs/xfs/xfs_error.c
fs/xfs/xfs_export.c
fs/xfs/xfs_extent_busy.c
fs/xfs/xfs_extfree_item.c
fs/xfs/xfs_extfree_item.h
fs/xfs/xfs_file.c
fs/xfs/xfs_filestream.c
fs/xfs/xfs_filestream.h
fs/xfs/xfs_format.h [new file with mode: 0644]
fs/xfs/xfs_fs.h
fs/xfs/xfs_fsops.c
fs/xfs/xfs_ialloc.c
fs/xfs/xfs_icache.c
fs/xfs/xfs_icache.h
fs/xfs/xfs_icreate_item.c
fs/xfs/xfs_icreate_item.h
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_inode_buf.c [new file with mode: 0644]
fs/xfs/xfs_inode_buf.h [new file with mode: 0644]
fs/xfs/xfs_inode_fork.c [new file with mode: 0644]
fs/xfs/xfs_inode_fork.h [new file with mode: 0644]
fs/xfs/xfs_inode_item.c
fs/xfs/xfs_inode_item.h
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_ioctl.h
fs/xfs/xfs_ioctl32.c
fs/xfs/xfs_iomap.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_iops.h
fs/xfs/xfs_itable.c
fs/xfs/xfs_linux.h
fs/xfs/xfs_log.c
fs/xfs/xfs_log.h
fs/xfs/xfs_log_cil.c
fs/xfs/xfs_log_format.h [new file with mode: 0644]
fs/xfs/xfs_log_priv.h
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_log_rlimit.c [new file with mode: 0644]
fs/xfs/xfs_mount.c
fs/xfs/xfs_mount.h
fs/xfs/xfs_qm.c
fs/xfs/xfs_qm.h
fs/xfs/xfs_qm_bhv.c
fs/xfs/xfs_qm_syscalls.c
fs/xfs/xfs_quota.h
fs/xfs/xfs_quota_defs.h [new file with mode: 0644]
fs/xfs/xfs_quotaops.c
fs/xfs/xfs_rename.c [deleted file]
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_rtalloc.h
fs/xfs/xfs_sb.c [new file with mode: 0644]
fs/xfs/xfs_sb.h
fs/xfs/xfs_super.c
fs/xfs/xfs_symlink.c
fs/xfs/xfs_symlink.h
fs/xfs/xfs_symlink_remote.c [new file with mode: 0644]
fs/xfs/xfs_trace.c
fs/xfs/xfs_trans.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_ail.c
fs/xfs/xfs_trans_buf.c
fs/xfs/xfs_trans_dquot.c
fs/xfs/xfs_trans_priv.h
fs/xfs/xfs_trans_resv.c [new file with mode: 0644]
fs/xfs/xfs_trans_resv.h [new file with mode: 0644]
fs/xfs/xfs_types.h
fs/xfs/xfs_utils.c [deleted file]
fs/xfs/xfs_utils.h [deleted file]
fs/xfs/xfs_vnodeops.c [deleted file]
fs/xfs/xfs_vnodeops.h [deleted file]
fs/xfs/xfs_xattr.c
include/asm-generic/dma-contiguous.h [deleted file]
include/drm/drm_pciids.h
include/drm/i915_drm.h
include/drm/i915_pciids.h [new file with mode: 0644]
include/dt-bindings/clock/samsung,s3c64xx-clock.h [new file with mode: 0644]
include/dt-bindings/input/input.h [new file with mode: 0644]
include/linux/aio.h
include/linux/amba/pl080.h
include/linux/anon_inodes.h
include/linux/backing-dev.h
include/linux/binfmts.h
include/linux/ceph/osd_client.h
include/linux/clk-private.h
include/linux/clk-provider.h
include/linux/cmdline-parser.h [new file with mode: 0644]
include/linux/compat.h
include/linux/cpu_rmap.h
include/linux/cpufreq.h
include/linux/crash_dump.h
include/linux/dcache.h
include/linux/device-mapper.h
include/linux/device.h
include/linux/dma-contiguous.h
include/linux/dma/mmp-pdma.h [new file with mode: 0644]
include/linux/dmaengine.h
include/linux/eventfd.h
include/linux/fs.h
include/linux/fs_struct.h
include/linux/fscache-cache.h
include/linux/fscache.h
include/linux/fsl/mxs-dma.h [deleted file]
include/linux/genalloc.h
include/linux/hardirq.h
include/linux/hid.h
include/linux/huge_mm.h
include/linux/hugetlb.h
include/linux/ieee80211.h
include/linux/init.h
include/linux/interrupt.h
include/linux/iommu.h
include/linux/ipc_namespace.h
include/linux/irq.h
include/linux/irqchip/arm-gic.h
include/linux/irqchip/mmp.h [new file with mode: 0644]
include/linux/irqdesc.h
include/linux/irqnr.h
include/linux/kernel_stat.h
include/linux/kprobes.h
include/linux/kvm_host.h
include/linux/list_lru.h [new file with mode: 0644]
include/linux/lz4.h
include/linux/math64.h
include/linux/memblock.h
include/linux/memcontrol.h
include/linux/mempolicy.h
include/linux/mfd/da9063/core.h [new file with mode: 0644]
include/linux/mfd/da9063/pdata.h [new file with mode: 0644]
include/linux/mfd/da9063/registers.h [new file with mode: 0644]
include/linux/mfd/davinci_voicecodec.h
include/linux/mfd/mcp.h
include/linux/mfd/palmas.h
include/linux/mfd/rtsx_common.h
include/linux/mfd/rtsx_pci.h
include/linux/mfd/samsung/s2mps11.h
include/linux/mfd/ti_am335x_tscadc.h
include/linux/mfd/tmio.h
include/linux/mfd/twl6040.h
include/linux/mfd/ucb1x00.h
include/linux/migrate.h
include/linux/mm.h
include/linux/mm_inline.h
include/linux/mm_types.h
include/linux/mmc/core.h
include/linux/mmc/sdhci.h
include/linux/mmc/sh_mmcif.h
include/linux/mmc/sh_mobile_sdhi.h
include/linux/mmc/slot-gpio.h
include/linux/mmzone.h
include/linux/mtd/bbm.h
include/linux/mtd/fsmc.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/namei.h
include/linux/netdevice.h
include/linux/netfilter/ipset/ip_set.h
include/linux/nfs_fs.h
include/linux/nfs_fs_sb.h
include/linux/nfs_xdr.h
include/linux/nvme.h
include/linux/of.h
include/linux/of_fdt.h
include/linux/of_net.h
include/linux/of_reserved_mem.h [new file with mode: 0644]
include/linux/pci_ids.h
include/linux/percpu_ida.h [new file with mode: 0644]
include/linux/platform_data/atmel.h
include/linux/platform_data/dma-rcar-hpbdma.h [new file with mode: 0644]
include/linux/platform_data/edma.h
include/linux/platform_data/exynos_thermal.h [deleted file]
include/linux/platform_data/leds-lp55xx.h
include/linux/platform_data/leds-pca9633.h [deleted file]
include/linux/platform_data/leds-pca963x.h [new file with mode: 0644]
include/linux/platform_data/mtd-nand-pxa3xx.h
include/linux/power/bq24190_charger.h [new file with mode: 0644]
include/linux/power/twl4030_madc_battery.h [new file with mode: 0644]
include/linux/power_supply.h
include/linux/quota.h
include/linux/radix-tree.h
include/linux/raid/pq.h
include/linux/ramfs.h
include/linux/rbtree.h
include/linux/res_counter.h
include/linux/sched.h
include/linux/seqlock.h
include/linux/sh_dma.h
include/linux/shdma-base.h
include/linux/shrinker.h
include/linux/slab.h
include/linux/slab_def.h
include/linux/slob_def.h [deleted file]
include/linux/slub_def.h
include/linux/smp.h
include/linux/spi/mmc_spi.h
include/linux/sunrpc/auth.h
include/linux/sunrpc/cache.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/rpc_pipe_fs.h
include/linux/sunrpc/sched.h
include/linux/sunrpc/svc.h
include/linux/swap.h
include/linux/syscalls.h
include/linux/thermal.h
include/linux/time-armada-370-xp.h [deleted file]
include/linux/timex.h
include/linux/vfio.h
include/linux/vgaarb.h
include/linux/vm_event_item.h
include/linux/vmstat.h
include/linux/writeback.h
include/net/9p/client.h
include/net/cfg80211.h
include/net/ip.h
include/net/mac80211.h
include/net/ndisc.h
include/net/netfilter/nf_conntrack_extend.h
include/scsi/scsi.h
include/sound/rcar_snd.h
include/target/iscsi/iscsi_transport.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/trace/events/btrfs.h
include/trace/events/kmem.h
include/trace/events/sunrpc.h
include/trace/events/vmscan.h
include/uapi/linux/Kbuild
include/uapi/linux/btrfs.h
include/uapi/linux/cifs/cifs_mount.h [new file with mode: 0644]
include/uapi/linux/dm-ioctl.h
include/uapi/linux/dqblk_xfs.h
include/uapi/linux/fs.h
include/uapi/linux/input.h
include/uapi/linux/nvme.h [new file with mode: 0644]
include/uapi/linux/perf_event.h
include/uapi/linux/vfio.h
init/Kconfig
init/do_mounts.c
ipc/msg.c
ipc/namespace.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/Makefile
kernel/capability.c
kernel/cgroup.c
kernel/events/core.c
kernel/events/uprobes.c
kernel/extable.c
kernel/fork.c
kernel/gcov/fs.c
kernel/irq/Kconfig
kernel/kexec.c
kernel/kprobes.c
kernel/ksysfs.c
kernel/modsign_pubkey.c
kernel/panic.c
kernel/params.c
kernel/power/hibernate.c
kernel/power/snapshot.c
kernel/power/user.c
kernel/ptrace.c
kernel/rcupdate.c
kernel/res_counter.c
kernel/sched/debug.c
kernel/sched/fair.c
kernel/sched/stats.h
kernel/signal.c
kernel/smp.c
kernel/softirq.c
kernel/spinlock.c
kernel/sysctl.c
kernel/task_work.c
kernel/time/ntp.c
kernel/time/timekeeping.c
kernel/trace/ftrace.c
kernel/trace/trace.c
kernel/trace/trace.h
kernel/trace/trace_events.c
kernel/trace/trace_syscalls.c
kernel/up.c
lib/Kconfig.debug
lib/Makefile
lib/cpu_rmap.c
lib/crc-t10dif.c
lib/crc32.c
lib/decompress_inflate.c
lib/div64.c
lib/genalloc.c
lib/lz4/lz4_decompress.c
lib/percpu_ida.c [new file with mode: 0644]
lib/radix-tree.c
lib/raid6/Makefile
lib/raid6/algos.c
lib/raid6/test/Makefile
lib/raid6/tilegx.uc [new file with mode: 0644]
lib/rbtree.c
lib/rbtree_test.c
mm/Kconfig
mm/Makefile
mm/backing-dev.c
mm/compaction.c
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/hwpoison-inject.c
mm/internal.h
mm/kmemleak.c
mm/ksm.c
mm/list_lru.c [new file with mode: 0644]
mm/madvise.c
mm/memblock.c
mm/memcontrol.c
mm/memory-failure.c
mm/memory.c
mm/memory_hotplug.c
mm/mempolicy.c
mm/mempool.c
mm/migrate.c
mm/mlock.c
mm/mmap.c
mm/mremap.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_io.c
mm/page_isolation.c
mm/pgtable-generic.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab_common.c
mm/slob.c
mm/slub.c
mm/sparse.c
mm/swap.c
mm/swap_state.c
mm/swapfile.c
mm/truncate.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
mm/zbud.c
mm/zswap.c
net/9p/client.c
net/9p/trans_virtio.c
net/Kconfig
net/batman-adv/soft-interface.c
net/bridge/br_netlink.c
net/bridge/br_private.h
net/bridge/br_stp.c
net/bridge/br_stp_if.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/flow_dissector.c
net/core/netpoll.c
net/dccp/ipv6.c
net/ipv4/igmp.c
net/ipv4/inetpeer.c
net/ipv4/ip_output.c
net/ipv4/ipmr.c
net/ipv4/raw.c
net/ipv4/tcp_memcontrol.c
net/ipv4/tcp_metrics.c
net/ipv4/xfrm4_mode_tunnel.c
net/ipv6/af_inet6.c
net/ipv6/exthdrs.c
net/ipv6/fib6_rules.c
net/ipv6/ip6_fib.c
net/ipv6/ip6_tunnel.c
net/ipv6/ndisc.c
net/ipv6/netfilter/nf_nat_proto_icmpv6.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/rc80211_pid_debugfs.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/vht.c
net/netfilter/ipset/ip_set_core.c
net/netfilter/ipset/ip_set_getport.c
net/netfilter/ipset/ip_set_hash_gen.h
net/netfilter/ipset/ip_set_hash_ipportnet.c
net/netfilter/ipset/ip_set_hash_net.c
net/netfilter/ipset/ip_set_hash_netiface.c
net/netfilter/ipset/ip_set_hash_netport.c
net/netfilter/ipvs/ip_vs_xmit.c
net/netfilter/nfnetlink_queue_core.c
net/openvswitch/flow.c
net/sched/sch_htb.c
net/sctp/input.c
net/sctp/ipv6.c
net/sctp/socket.c
net/socket.c
net/sunrpc/auth.c
net/sunrpc/auth_generic.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/gss_rpc_xdr.c
net/sunrpc/auth_gss/gss_rpc_xdr.h
net/sunrpc/auth_null.c
net/sunrpc/auth_unix.c
net/sunrpc/clnt.c
net/sunrpc/rpc_pipe.c
net/sunrpc/sched.c
net/sunrpc/stats.c
net/sunrpc/xprtsock.c
net/wireless/chan.c
net/wireless/core.h
net/wireless/debugfs.c
net/wireless/genregdb.awk
net/wireless/nl80211.c
net/wireless/reg.c
net/wireless/util.c
scripts/checkkconfigsymbols.sh
scripts/checkpatch.pl
scripts/coccinelle/misc/boolreturn.cocci [new file with mode: 0644]
scripts/config
scripts/diffconfig
scripts/kconfig/confdata.c
scripts/kconfig/mconf.c
scripts/kconfig/menu.c
scripts/kconfig/nconf.c
scripts/kconfig/symbol.c
scripts/kconfig/zconf.tab.c_shipped
scripts/kconfig/zconf.y
scripts/package/builddeb
scripts/package/buildtar
scripts/package/mkspec
scripts/sortextable.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_cirrus.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/soc/atmel/atmel_ssc_dai.c
sound/soc/codecs/Kconfig
sound/soc/codecs/mc13783.c
sound/soc/fsl/Kconfig
sound/soc/fsl/imx-audmux.c
sound/soc/kirkwood/kirkwood-i2s.c
sound/soc/samsung/Kconfig
sound/soc/sh/rcar/scu.c
tools/lguest/lguest.c
tools/perf/Makefile
tools/perf/builtin-annotate.c
tools/perf/builtin-inject.c
tools/perf/builtin-kvm.c
tools/perf/builtin-mem.c
tools/perf/builtin-report.c
tools/perf/builtin-script.c
tools/perf/builtin-trace.c
tools/perf/tests/builtin-test.c
tools/perf/tests/parse-no-sample-id-all.c [new file with mode: 0644]
tools/perf/tests/perf-record.c
tools/perf/tests/tests.h
tools/perf/ui/stdio/hist.c
tools/perf/util/build-id.c
tools/perf/util/event.c
tools/perf/util/event.h
tools/perf/util/evlist.c
tools/perf/util/evsel.c
tools/perf/util/header.c
tools/perf/util/machine.c
tools/perf/util/machine.h
tools/perf/util/map.c
tools/perf/util/map.h
tools/perf/util/session.c
tools/perf/util/tool.h
tools/virtio/.gitignore [new file with mode: 0644]
virt/kvm/async_pf.c
virt/kvm/kvm_main.c

index 3105644b3bfc45f27371765246f6d1deda46549b..bfd119ace6ad00c2ee56c4c16b25a78ec6b5d7f0 100644 (file)
@@ -128,9 +128,8 @@ KernelVersion:      3.4
 Contact:       linux-mtd@lists.infradead.org
 Description:
                Maximum number of bit errors that the device is capable of
-               correcting within each region covering an ecc step.  This will
-               always be a non-negative integer.  Note that some devices will
-               have multiple ecc steps within each writesize region.
+               correcting within each region covering an ECC step (see
+               ecc_step_size).  This will always be a non-negative integer.
 
                In the case of devices lacking any ECC capability, it is 0.
 
@@ -173,3 +172,15 @@ Description:
                This is generally applicable only to NAND flash devices with ECC
                capability.  It is ignored on devices lacking ECC capability;
                i.e., devices for which ecc_strength is zero.
+
+What:          /sys/class/mtd/mtdX/ecc_step_size
+Date:          May 2013
+KernelVersion: 3.10
+Contact:       linux-mtd@lists.infradead.org
+Description:
+               The size of a single region covered by ECC, known as the ECC
+               step.  Devices may have several equally sized ECC steps within
+               each writesize region.
+
+               It will always be a non-negative integer.  In the case of
+               devices lacking any ECC capability, it is 0.
index fe122d6e686f50e873d637d3f08929d042df4335..a248f42a121ef2a037fbab7a74ad684a431d1b52 100644 (file)
@@ -1224,8 +1224,6 @@ in this page</entry>
 #define NAND_BBT_CREATE                0x00000200
 /* Search good / bad pattern through all pages of a block */
 #define NAND_BBT_SCANALLPAGES  0x00000400
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY     0x00000800
 /* Write bbt if neccecary */
 #define NAND_BBT_WRITE         0x00001000
 /* Read and write back block contents when writing bbt */
index 8686e789542ed0b6f3ccce8f54b1ef794c2f7fe4..1f06daf03f5ba5ee1fb69089057cef26ca57f286 100644 (file)
@@ -23,4 +23,4 @@ SUBSYSTEM=="aoe", KERNEL=="revalidate",       NAME="etherd/%k", GROUP="disk", MODE="02
 SUBSYSTEM=="aoe", KERNEL=="flush",     NAME="etherd/%k", GROUP="disk", MODE="0220"
 
 # aoe block devices     
-KERNEL=="etherd*",       NAME="%k", GROUP="disk"
+KERNEL=="etherd*",       GROUP="disk"
diff --git a/Documentation/block/cmdline-partition.txt b/Documentation/block/cmdline-partition.txt
new file mode 100644 (file)
index 0000000..2bbf4cc
--- /dev/null
@@ -0,0 +1,39 @@
+Embedded device command line partition
+=====================================================================
+
+Read block device partition table from command line.
+The partition used for fixed block device (eMMC) embedded device.
+It is no MBR, save storage space. Bootloader can be easily accessed
+by absolute address of data on the block device.
+Users can easily change the partition.
+
+The format for the command line is just like mtdparts:
+
+blkdevparts=<blkdev-def>[;<blkdev-def>]
+  <blkdev-def> := <blkdev-id>:<partdef>[,<partdef>]
+    <partdef> := <size>[@<offset>](part-name)
+
+<blkdev-id>
+    block device disk name, embedded device used fixed block device,
+    it's disk name also fixed. such as: mmcblk0, mmcblk1, mmcblk0boot0.
+
+<size>
+    partition size, in bytes, such as: 512, 1m, 1G.
+
+<offset>
+    partition start address, in bytes.
+
+(part-name)
+    partition name, kernel send uevent with "PARTNAME". application can create
+    a link to block device partition with the name "PARTNAME".
+    user space application can access partition by partition name.
+
+Example:
+    eMMC disk name is "mmcblk0" and "mmcblk0boot0"
+
+  bootargs:
+    'blkdevparts=mmcblk0:1G(data0),1G(data1),-;mmcblk0boot0:1m(boot),-(kernel)'
+
+  dmesg:
+    mmcblk0: p1(data0) p2(data1) p3()
+    mmcblk0boot0: p1(boot) p2(kernel)
index 2a33306963727fba16c047610d9738b1076db38e..8af4ad12182869c4f972eeb9a5029c35e383b19a 100644 (file)
@@ -490,6 +490,8 @@ pgpgin              - # of charging events to the memory cgroup. The charging
 pgpgout                - # of uncharging events to the memory cgroup. The uncharging
                event happens each time a page is unaccounted from the cgroup.
 swap           - # of bytes of swap usage
+writeback      - # of bytes of file/anon cache that are queued for syncing to
+               disk.
 inactive_anon  - # of bytes of anonymous and swap cache memory on inactive
                LRU list.
 active_anon    - # of bytes of anonymous and swap cache memory on active
index 6f68ba0d1e01eea75c59b8547f2958ad20419333..3aeb5c4404424a49b86232f55b7e118e2a06ae7c 100644 (file)
@@ -70,6 +70,10 @@ the operations defined in clk.h:
                                                unsigned long parent_rate);
                long            (*round_rate)(struct clk_hw *hw, unsigned long,
                                                unsigned long *);
+               long            (*determine_rate)(struct clk_hw *hw,
+                                               unsigned long rate,
+                                               unsigned long *best_parent_rate,
+                                               struct clk **best_parent_clk);
                int             (*set_parent)(struct clk_hw *hw, u8 index);
                u8              (*get_parent)(struct clk_hw *hw);
                int             (*set_rate)(struct clk_hw *hw, unsigned long);
@@ -179,26 +183,28 @@ mandatory, a cell marked as "n" implies that either including that
 callback is invalid or otherwise unnecessary.  Empty cells are either
 optional or must be evaluated on a case-by-case basis.
 
-                           clock hardware characteristics
-            -----------------------------------------------------------
-             | gate | change rate | single parent | multiplexer | root |
-             |------|-------------|---------------|-------------|------|
-.prepare     |      |             |               |             |      |
-.unprepare   |      |             |               |             |      |
-             |      |             |               |             |      |
-.enable      | y    |             |               |             |      |
-.disable     | y    |             |               |             |      |
-.is_enabled  | y    |             |               |             |      |
-             |      |             |               |             |      |
-.recalc_rate |      | y           |               |             |      |
-.round_rate  |      | y           |               |             |      |
-.set_rate    |      | y           |               |             |      |
-             |      |             |               |             |      |
-.set_parent  |      |             | n             | y           | n    |
-.get_parent  |      |             | n             | y           | n    |
-             |      |             |               |             |      |
-.init        |      |             |               |             |      |
-            -----------------------------------------------------------
+                              clock hardware characteristics
+                -----------------------------------------------------------
+                | gate | change rate | single parent | multiplexer | root |
+                |------|-------------|---------------|-------------|------|
+.prepare        |      |             |               |             |      |
+.unprepare      |      |             |               |             |      |
+                |      |             |               |             |      |
+.enable         | y    |             |               |             |      |
+.disable        | y    |             |               |             |      |
+.is_enabled     | y    |             |               |             |      |
+                |      |             |               |             |      |
+.recalc_rate    |      | y           |               |             |      |
+.round_rate     |      | y [1]       |               |             |      |
+.determine_rate |      | y [1]       |               |             |      |
+.set_rate       |      | y           |               |             |      |
+                |      |             |               |             |      |
+.set_parent     |      |             | n             | y           | n    |
+.get_parent     |      |             | n             | y           | n    |
+                |      |             |               |             |      |
+.init           |      |             |               |             |      |
+                -----------------------------------------------------------
+[1] either one of round_rate or determine_rate is required.
 
 Finally, register your clock at run-time with a hardware-specific
 registration function.  This function simply populates struct clk_foo's
index e8cdf7241b66b3b413b0253042b4d4a54700dc4e..33d45ee0b737fade096136d50425caf46e344a47 100644 (file)
@@ -50,14 +50,16 @@ other parameters detailed later):
    which are dirty, and extra hints for use by the policy object.
    This information could be put on the cache device, but having it
    separate allows the volume manager to configure it differently,
-   e.g. as a mirror for extra robustness.
+   e.g. as a mirror for extra robustness.  This metadata device may only
+   be used by a single cache device.
 
 Fixed block size
 ----------------
 
 The origin is divided up into blocks of a fixed size.  This block size
 is configurable when you first create the cache.  Typically we've been
-using block sizes of 256k - 1024k.
+using block sizes of 256KB - 1024KB.  The block size must be between 64
+(32KB) and 2097152 (1GB) and a multiple of 64 (32KB).
 
 Having a fixed block size simplifies the target a lot.  But it is
 something of a compromise.  For instance, a small part of a block may be
diff --git a/Documentation/device-mapper/statistics.txt b/Documentation/device-mapper/statistics.txt
new file mode 100644 (file)
index 0000000..2a1673a
--- /dev/null
@@ -0,0 +1,186 @@
+DM statistics
+=============
+
+Device Mapper supports the collection of I/O statistics on user-defined
+regions of a DM device.         If no regions are defined no statistics are
+collected so there isn't any performance impact.  Only bio-based DM
+devices are currently supported.
+
+Each user-defined region specifies a starting sector, length and step.
+Individual statistics will be collected for each step-sized area within
+the range specified.
+
+The I/O statistics counters for each step-sized area of a region are
+in the same format as /sys/block/*/stat or /proc/diskstats (see:
+Documentation/iostats.txt).  But two extra counters (12 and 13) are
+provided: total time spent reading and writing in milliseconds.         All
+these counters may be accessed by sending the @stats_print message to
+the appropriate DM device via dmsetup.
+
+Each region has a corresponding unique identifier, which we call a
+region_id, that is assigned when the region is created.         The region_id
+must be supplied when querying statistics about the region, deleting the
+region, etc.  Unique region_ids enable multiple userspace programs to
+request and process statistics for the same DM device without stepping
+on each other's data.
+
+The creation of DM statistics will allocate memory via kmalloc or
+fallback to using vmalloc space.  At most, 1/4 of the overall system
+memory may be allocated by DM statistics.  The admin can see how much
+memory is used by reading
+/sys/module/dm_mod/parameters/stats_current_allocated_bytes
+
+Messages
+========
+
+    @stats_create <range> <step> [<program_id> [<aux_data>]]
+
+       Create a new region and return the region_id.
+
+       <range>
+         "-" - whole device
+         "<start_sector>+<length>" - a range of <length> 512-byte sectors
+                                     starting with <start_sector>.
+
+       <step>
+         "<area_size>" - the range is subdivided into areas each containing
+                         <area_size> sectors.
+         "/<number_of_areas>" - the range is subdivided into the specified
+                                number of areas.
+
+       <program_id>
+         An optional parameter.  A name that uniquely identifies
+         the userspace owner of the range.  This groups ranges together
+         so that userspace programs can identify the ranges they
+         created and ignore those created by others.
+         The kernel returns this string back in the output of
+         @stats_list message, but it doesn't use it for anything else.
+
+       <aux_data>
+         An optional parameter.  A word that provides auxiliary data
+         that is useful to the client program that created the range.
+         The kernel returns this string back in the output of
+         @stats_list message, but it doesn't use this value for anything.
+
+    @stats_delete <region_id>
+
+       Delete the region with the specified id.
+
+       <region_id>
+         region_id returned from @stats_create
+
+    @stats_clear <region_id>
+
+       Clear all the counters except the in-flight i/o counters.
+
+       <region_id>
+         region_id returned from @stats_create
+
+    @stats_list [<program_id>]
+
+       List all regions registered with @stats_create.
+
+       <program_id>
+         An optional parameter.
+         If this parameter is specified, only matching regions
+         are returned.
+         If it is not specified, all regions are returned.
+
+       Output format:
+         <region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
+
+    @stats_print <region_id> [<starting_line> <number_of_lines>]
+
+       Print counters for each step-sized area of a region.
+
+       <region_id>
+         region_id returned from @stats_create
+
+       <starting_line>
+         The index of the starting line in the output.
+         If omitted, all lines are returned.
+
+       <number_of_lines>
+         The number of lines to include in the output.
+         If omitted, all lines are returned.
+
+       Output format for each step-sized area of a region:
+
+         <start_sector>+<length> counters
+
+         The first 11 counters have the same meaning as
+         /sys/block/*/stat or /proc/diskstats.
+
+         Please refer to Documentation/iostats.txt for details.
+
+         1. the number of reads completed
+         2. the number of reads merged
+         3. the number of sectors read
+         4. the number of milliseconds spent reading
+         5. the number of writes completed
+         6. the number of writes merged
+         7. the number of sectors written
+         8. the number of milliseconds spent writing
+         9. the number of I/Os currently in progress
+         10. the number of milliseconds spent doing I/Os
+         11. the weighted number of milliseconds spent doing I/Os
+
+         Additional counters:
+         12. the total time spent reading in milliseconds
+         13. the total time spent writing in milliseconds
+
+    @stats_print_clear <region_id> [<starting_line> <number_of_lines>]
+
+       Atomically print and then clear all the counters except the
+       in-flight i/o counters.  Useful when the client consuming the
+       statistics does not want to lose any statistics (those updated
+       between printing and clearing).
+
+       <region_id>
+         region_id returned from @stats_create
+
+       <starting_line>
+         The index of the starting line in the output.
+         If omitted, all lines are printed and then cleared.
+
+       <number_of_lines>
+         The number of lines to process.
+         If omitted, all lines are printed and then cleared.
+
+    @stats_set_aux <region_id> <aux_data>
+
+       Store auxiliary data aux_data for the specified region.
+
+       <region_id>
+         region_id returned from @stats_create
+
+       <aux_data>
+         The string that identifies data which is useful to the client
+         program that created the range.  The kernel returns this
+         string back in the output of @stats_list message, but it
+         doesn't use this value for anything.
+
+Examples
+========
+
+Subdivide the DM device 'vol' into 100 pieces and start collecting
+statistics on them:
+
+  dmsetup message vol 0 @stats_create - /100
+
+Set the auxillary data string to "foo bar baz" (the escape for each
+space must also be escaped, otherwise the shell will consume them):
+
+  dmsetup message vol 0 @stats_set_aux 0 foo\\ bar\\ baz
+
+List the statistics:
+
+  dmsetup message vol 0 @stats_list
+
+Print the statistics:
+
+  dmsetup message vol 0 @stats_print 0
+
+Delete the statistics:
+
+  dmsetup message vol 0 @stats_delete 0
index 30b8b83bd333401a2cc1138d664d6086b4d47aef..50c44cf79b0e5f4467fc0af58e3af40234cef94e 100644 (file)
@@ -99,13 +99,14 @@ Using an existing pool device
                 $data_block_size $low_water_mark"
 
 $data_block_size gives the smallest unit of disk space that can be
-allocated at a time expressed in units of 512-byte sectors.  People
-primarily interested in thin provisioning may want to use a value such
-as 1024 (512KB).  People doing lots of snapshotting may want a smaller value
-such as 128 (64KB).  If you are not zeroing newly-allocated data,
-a larger $data_block_size in the region of 256000 (128MB) is suggested.
-$data_block_size must be the same for the lifetime of the
-metadata device.
+allocated at a time expressed in units of 512-byte sectors.
+$data_block_size must be between 128 (64KB) and 2097152 (1GB) and a
+multiple of 128 (64KB).  $data_block_size cannot be changed after the
+thin-pool is created.  People primarily interested in thin provisioning
+may want to use a value such as 1024 (512KB).  People doing lots of
+snapshotting may want a smaller value such as 128 (64KB).  If you are
+not zeroing newly-allocated data, a larger $data_block_size in the
+region of 256000 (128MB) is suggested.
 
 $low_water_mark is expressed in blocks of size $data_block_size.  If
 free space on the data device drops below this level then a dm event
index 14d5c2af26f4bec06f4fb507db6d647a3eb25255..c6bf8a6c8f52856b95af14e1e85134a246c1a44b 100644 (file)
@@ -236,6 +236,7 @@ Exynos4 SoC and this is specified where applicable.
   spi0_isp_sclk       380     Exynos4x12
   spi1_isp_sclk       381     Exynos4x12
   uart_isp_sclk       382     Exynos4x12
+  tmu_apbif           383
 
                [Mux Clocks]
 
index 781a6276adf75ca5eecac09eceb773fbe7fcef2f..24765c146e31d52ea4c732812c420ccdb5d3e670 100644 (file)
@@ -59,6 +59,9 @@ clock which they consume.
   sclk_spi0            154
   sclk_spi1            155
   sclk_spi2            156
+  div_i2s1             157
+  div_i2s2             158
+  sclk_hdmiphy         159
 
 
    [Peripheral Clock Gates]
@@ -154,7 +157,16 @@ clock which they consume.
   dsim0                        341
   dp                   342
   mixer                        343
-  hdmi                 345
+  hdmi                 344
+  g2d                  345
+
+
+   [Clock Muxes]
+
+  Clock                        ID
+  ----------------------------
+  mout_hdmi            1024
+
 
 Example 1: An example of a clock controller node is listed below.
 
index 9bcc4b1bff51c74b091c2decea3b134c2d34fdde..32aa34ecad364f6d3d0c613c471ec5752096b6ba 100644 (file)
@@ -59,6 +59,7 @@ clock which they consume.
   sclk_pwm             155
   sclk_gscl_wa         156
   sclk_gscl_wb         157
+  sclk_hdmiphy         158
 
    [Peripheral Clock Gates]
 
@@ -179,6 +180,17 @@ clock which they consume.
   fimc_lite3           495
   aclk_g3d             500
   g3d                  501
+  smmu_mixer           502
+
+  Mux                  ID
+  ----------------------------
+
+  mout_hdmi            640
+
+  Divider              ID
+  ----------------------------
+
+  dout_pixel           768
 
 Example 1: An example of a clock controller node is listed below.
 
diff --git a/Documentation/devicetree/bindings/clock/samsung,s3c64xx-clock.txt b/Documentation/devicetree/bindings/clock/samsung,s3c64xx-clock.txt
new file mode 100644 (file)
index 0000000..fa171dc
--- /dev/null
@@ -0,0 +1,77 @@
+* Samsung S3C64xx Clock Controller
+
+The S3C64xx clock controller generates and supplies clock to various controllers
+within the SoC. The clock binding described here is applicable to all SoCs in
+the S3C64xx family.
+
+Required Properties:
+
+- compatible: should be one of the following.
+  - "samsung,s3c6400-clock" - controller compatible with S3C6400 SoC.
+  - "samsung,s3c6410-clock" - controller compatible with S3C6410 SoC.
+
+- reg: physical base address of the controller and length of memory mapped
+  region.
+
+- #clock-cells: should be 1.
+
+Each clock is assigned an identifier and client nodes can use this identifier
+to specify the clock which they consume. Some of the clocks are available only
+on a particular S3C64xx SoC and this is specified where applicable.
+
+All available clocks are defined as preprocessor macros in
+dt-bindings/clock/samsung,s3c64xx-clock.h header and can be used in device
+tree sources.
+
+External clocks:
+
+There are several clocks that are generated outside the SoC. It is expected
+that they are defined using standard clock bindings with following
+clock-output-names:
+ - "fin_pll" - PLL input clock (xtal/extclk) - required,
+ - "xusbxti" - USB xtal - required,
+ - "iiscdclk0" - I2S0 codec clock - optional,
+ - "iiscdclk1" - I2S1 codec clock - optional,
+ - "iiscdclk2" - I2S2 codec clock - optional,
+ - "pcmcdclk0" - PCM0 codec clock - optional,
+ - "pcmcdclk1" - PCM1 codec clock - optional, only S3C6410.
+
+Example: Clock controller node:
+
+       clock: clock-controller@7e00f000 {
+               compatible = "samsung,s3c6410-clock";
+               reg = <0x7e00f000 0x1000>;
+               #clock-cells = <1>;
+       };
+
+Example: Required external clocks:
+
+       fin_pll: clock-fin-pll {
+               compatible = "fixed-clock";
+               clock-output-names = "fin_pll";
+               clock-frequency = <12000000>;
+               #clock-cells = <0>;
+       };
+
+       xusbxti: clock-xusbxti {
+               compatible = "fixed-clock";
+               clock-output-names = "xusbxti";
+               clock-frequency = <48000000>;
+               #clock-cells = <0>;
+       };
+
+Example: UART controller node that consumes the clock generated by the clock
+  controller (refer to the standard clock bindings for information about
+  "clocks" and "clock-names" properties):
+
+               uart0: serial@7f005000 {
+                       compatible = "samsung,s3c6400-uart";
+                       reg = <0x7f005000 0x100>;
+                       interrupt-parent = <&vic1>;
+                       interrupts = <5>;
+                       clock-names = "uart", "clk_uart_baud2",
+                                       "clk_uart_baud3";
+                       clocks = <&clock PCLK_UART0>, <&clocks PCLK_UART0>,
+                                       <&clock SCLK_UART>;
+                       status = "disabled";
+               };
index d495521a79d2c1fa028c43f50b77dd7423388432..00a5c26454eb773f4be1496b54d676f09bfcc0f1 100644 (file)
@@ -8,19 +8,31 @@ Required properties:
 - compatible : shall be one of the following:
        "allwinner,sun4i-osc-clk" - for a gatable oscillator
        "allwinner,sun4i-pll1-clk" - for the main PLL clock
+       "allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
        "allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
        "allwinner,sun4i-axi-clk" - for the AXI clock
        "allwinner,sun4i-axi-gates-clk" - for the AXI gates
        "allwinner,sun4i-ahb-clk" - for the AHB clock
        "allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
        "allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
+       "allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
+       "allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
+       "allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
+       "allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
        "allwinner,sun4i-apb0-clk" - for the APB0 clock
        "allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
        "allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
+       "allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
+       "allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
        "allwinner,sun4i-apb1-clk" - for the APB1 clock
        "allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
        "allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
        "allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
+       "allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
+       "allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
+       "allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
+       "allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
+       "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
 
 Required properties for all clocks:
 - reg : shall be the control register address for the clock.
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun5i-a10s-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun5i-a10s-gates.txt
new file mode 100644 (file)
index 0000000..d24279f
--- /dev/null
@@ -0,0 +1,75 @@
+Gate clock outputs
+------------------
+
+  * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+    DRAM                                       0
+
+  * AHB gates ("allwinner,sun5i-a10s-ahb-gates-clk")
+
+    USB0                                       0
+    EHCI0                                      1
+    OHCI0                                      2
+
+    SS                                         5
+    DMA                                                6
+    BIST                                       7
+    MMC0                                       8
+    MMC1                                       9
+    MMC2                                       10
+
+    NAND                                       13
+    SDRAM                                      14
+
+    EMAC                                       17
+    TS                                         18
+
+    SPI0                                       20
+    SPI1                                       21
+    SPI2                                       22
+
+    GPS                                                26
+
+    HSTIMER                                    28
+
+    VE                                         32
+
+    TVE                                                34
+
+    LCD                                                36
+
+    CSI                                                40
+
+    HDMI                                       43
+    DE_BE                                      44
+
+    DE_FE                                      46
+
+    IEP                                                51
+    MALI400                                    52
+
+  * APB0 gates ("allwinner,sun5i-a10s-apb0-gates-clk")
+
+    CODEC                                      0
+
+    IIS                                                3
+
+    PIO                                                5
+    IR                                         6
+
+    KEYPAD                                     10
+
+  * APB1 gates ("allwinner,sun5i-a10s-apb1-gates-clk")
+
+    I2C0                                       0
+    I2C1                                       1
+    I2C2                                       2
+
+    UART0                                      16
+    UART1                                      17
+    UART2                                      18
+    UART3                                      19
+
+Notation:
+ [*]:  The datasheet didn't mention these, but they are present on AW code
+ [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun6i-a31-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun6i-a31-gates.txt
new file mode 100644 (file)
index 0000000..fe44932
--- /dev/null
@@ -0,0 +1,83 @@
+Gate clock outputs
+------------------
+
+  * AHB1 gates ("allwinner,sun6i-a31-ahb1-gates-clk")
+
+    MIPI DSI                                   1
+
+    SS                                         5
+    DMA                                                6
+
+    MMC0                                       8
+    MMC1                                       9
+    MMC2                                       10
+    MMC3                                       11
+
+    NAND1                                      12
+    NAND0                                      13
+    SDRAM                                      14
+
+    GMAC                                       17
+    TS                                         18
+    HSTIMER                                    19
+    SPI0                                       20
+    SPI1                                       21
+    SPI2                                       22
+    SPI3                                       23
+    USB_OTG                                    24
+
+    EHCI0                                      26
+    EHCI1                                      27
+
+    OHCI0                                      29
+    OHCI1                                      30
+    OHCI2                                      31
+    VE                                         32
+
+    LCD0                                       36
+    LCD1                                       37
+
+    CSI                                                40
+
+    HDMI                                       43
+    DE_BE0                                     44
+    DE_BE1                                     45
+    DE_FE1                                     46
+    DE_FE1                                     47
+
+    MP                                         50
+
+    GPU                                                52
+
+    DEU0                                       55
+    DEU1                                       56
+    DRC0                                       57
+    DRC1                                       58
+
+  * APB1 gates ("allwinner,sun6i-a31-apb1-gates-clk")
+
+    CODEC                                      0
+
+    DIGITAL MIC                                        4
+    PIO                                                5
+
+    DAUDIO0                                    12
+    DAUDIO1                                    13
+
+  * APB2 gates ("allwinner,sun6i-a31-apb2-gates-clk")
+
+    I2C0                                       0
+    I2C1                                       1
+    I2C2                                       2
+    I2C3                                       3
+
+    UART0                                      16
+    UART1                                      17
+    UART2                                      18
+    UART3                                      19
+    UART4                                      20
+    UART5                                      21
+
+Notation:
+ [*]:  The datasheet didn't mention these, but they are present on AW code
+ [**]: The datasheet had this marked as "NC" but they are used on AW code
diff --git a/Documentation/devicetree/bindings/clock/sunxi/sun7i-a20-gates.txt b/Documentation/devicetree/bindings/clock/sunxi/sun7i-a20-gates.txt
new file mode 100644 (file)
index 0000000..357f4fd
--- /dev/null
@@ -0,0 +1,98 @@
+Gate clock outputs
+------------------
+
+  * AXI gates ("allwinner,sun4i-axi-gates-clk")
+
+    DRAM                                       0
+
+  * AHB gates ("allwinner,sun7i-a20-ahb-gates-clk")
+
+    USB0                                       0
+    EHCI0                                      1
+    OHCI0                                      2
+    EHCI1                                      3
+    OHCI1                                      4
+    SS                                         5
+    DMA                                                6
+    BIST                                       7
+    MMC0                                       8
+    MMC1                                       9
+    MMC2                                       10
+    MMC3                                       11
+    MS                                         12
+    NAND                                       13
+    SDRAM                                      14
+
+    ACE                                                16
+    EMAC                                       17
+    TS                                         18
+
+    SPI0                                       20
+    SPI1                                       21
+    SPI2                                       22
+    SPI3                                       23
+
+    SATA                                       25
+
+    HSTIMER                                    28
+
+    VE                                         32
+    TVD                                                33
+    TVE0                                       34
+    TVE1                                       35
+    LCD0                                       36
+    LCD1                                       37
+
+    CSI0                                       40
+    CSI1                                       41
+
+    HDMI1                                      42
+    HDMI0                                      43
+    DE_BE0                                     44
+    DE_BE1                                     45
+    DE_FE1                                     46
+    DE_FE1                                     47
+
+    GMAC                                       49
+    MP                                         50
+
+    MALI400                                    52
+
+  * APB0 gates ("allwinner,sun7i-a20-apb0-gates-clk")
+
+    CODEC                                      0
+    SPDIF                                      1
+    AC97                                       2
+    IIS0                                       3
+    IIS1                                       4
+    PIO                                                5
+    IR0                                                6
+    IR1                                                7
+    IIS2                                       8
+
+    KEYPAD                                     10
+
+  * APB1 gates ("allwinner,sun7i-a20-apb1-gates-clk")
+
+    I2C0                                       0
+    I2C1                                       1
+    I2C2                                       2
+    I2C3                                       3
+    CAN                                                4
+    SCR                                                5
+    PS20                                       6
+    PS21                                       7
+
+    I2C4                                       15
+    UART0                                      16
+    UART1                                      17
+    UART2                                      18
+    UART3                                      19
+    UART4                                      20
+    UART5                                      21
+    UART6                                      22
+    UART7                                      23
+
+Notation:
+ [*]:  The datasheet didn't mention these, but they are present on AW code
+ [**]: The datasheet had this marked as "NC" but they are used on AW code
index 68cee4f5539fcbf8274ab08456ab5fff54ea9b46..4fa814d3832124adb80f29ee777849739acbb7e4 100644 (file)
@@ -1,7 +1,12 @@
 * Freescale Smart Direct Memory Access (SDMA) Controller for i.MX
 
 Required properties:
-- compatible : Should be "fsl,<chip>-sdma"
+- compatible : Should be "fsl,imx31-sdma", "fsl,imx31-to1-sdma",
+  "fsl,imx31-to2-sdma", "fsl,imx35-sdma", "fsl,imx35-to1-sdma",
+  "fsl,imx35-to2-sdma", "fsl,imx51-sdma", "fsl,imx53-sdma" or
+  "fsl,imx6q-sdma". The -to variants should be preferred since they
+  allow to determnine the correct ROM script addresses needed for
+  the driver to work without additional firmware.
 - reg : Should contain SDMA registers location and length
 - interrupts : Should contain SDMA interrupt
 - #dma-cells : Must be <3>.
diff --git a/Documentation/devicetree/bindings/dma/k3dma.txt b/Documentation/devicetree/bindings/dma/k3dma.txt
new file mode 100644 (file)
index 0000000..23f8d71
--- /dev/null
@@ -0,0 +1,46 @@
+* Hisilicon K3 DMA controller
+
+See dma.txt first
+
+Required properties:
+- compatible: Should be "hisilicon,k3-dma-1.0"
+- reg: Should contain DMA registers location and length.
+- interrupts: Should contain one interrupt shared by all channel
+- #dma-cells: see dma.txt, should be 1, para number
+- dma-channels: physical channels supported
+- dma-requests: virtual channels supported, each virtual channel
+               have specific request line
+- clocks: clock required
+
+Example:
+
+Controller:
+               dma0: dma@fcd02000 {
+                       compatible = "hisilicon,k3-dma-1.0";
+                       reg = <0xfcd02000 0x1000>;
+                       #dma-cells = <1>;
+                       dma-channels = <16>;
+                       dma-requests = <27>;
+                       interrupts = <0 12 4>;
+                       clocks = <&pclk>;
+                       status = "disable";
+               };
+
+Client:
+Use specific request line passing from dmax
+For example, i2c0 read channel request line is 18, while write channel use 19
+
+               i2c0: i2c@fcb08000 {
+                       compatible = "snps,designware-i2c";
+                       dmas =  <&dma0 18          /* read channel */
+                                &dma0 19>;        /* write channel */
+                       dma-names = "rx", "tx";
+               };
+
+               i2c1: i2c@fcb09000 {
+                       compatible = "snps,designware-i2c";
+                       dmas =  <&dma0 20          /* read channel */
+                                &dma0 21>;        /* write channel */
+                       dma-names = "rx", "tx";
+               };
+
index c15994aa19395154c5439a7c903cb9e26df9038d..2a3f3b8946b998dfde5d2f8b33523fb5e64643ad 100644 (file)
@@ -22,42 +22,51 @@ Optional properties (currently unused):
 * DMA controller
 
 Required properties:
-- compatible:  should be "renesas,shdma"
+- compatible:  should be of the form "renesas,shdma-<soc>", where <soc> should
+               be replaced with the desired SoC model, e.g.
+               "renesas,shdma-r8a73a4" for the system DMAC on r8a73a4 SoC
 
 Example:
-       dmac: dma-mux0 {
+       dmac: dma-multiplexer@0 {
                compatible = "renesas,shdma-mux";
                #dma-cells = <1>;
-               dma-channels = <6>;
+               dma-channels = <20>;
                dma-requests = <256>;
-               reg = <0 0>;    /* Needed for AUXDATA */
-               #address-cells = <1>;
-               #size-cells = <1>;
+               #address-cells = <2>;
+               #size-cells = <2>;
                ranges;
 
-               dma0: shdma@fe008020 {
-                       compatible = "renesas,shdma";
-                       reg = <0xfe008020 0x270>,
-                               <0xfe009000 0xc>;
+               dma0: dma-controller@e6700020 {
+                       compatible = "renesas,shdma-r8a73a4";
+                       reg = <0 0xe6700020 0 0x89e0>;
                        interrupt-parent = <&gic>;
-                       interrupts = <0 34 4
-                                       0 28 4
-                                       0 29 4
-                                       0 30 4
-                                       0 31 4
-                                       0 32 4
-                                       0 33 4>;
+                       interrupts = <0 220 4
+                                       0 200 4
+                                       0 201 4
+                                       0 202 4
+                                       0 203 4
+                                       0 204 4
+                                       0 205 4
+                                       0 206 4
+                                       0 207 4
+                                       0 208 4
+                                       0 209 4
+                                       0 210 4
+                                       0 211 4
+                                       0 212 4
+                                       0 213 4
+                                       0 214 4
+                                       0 215 4
+                                       0 216 4
+                                       0 217 4
+                                       0 218 4
+                                       0 219 4>;
                        interrupt-names = "error",
                                        "ch0", "ch1", "ch2", "ch3",
-                                       "ch4", "ch5";
-               };
-
-               dma1: shdma@fe018020 {
-                       ...
-               };
-
-               dma2: shdma@fe028020 {
-                       ...
+                                       "ch4", "ch5", "ch6", "ch7",
+                                       "ch8", "ch9", "ch10", "ch11",
+                                       "ch12", "ch13", "ch14", "ch15",
+                                       "ch16", "ch17", "ch18", "ch19";
                };
        };
 
index 3f454ffc654a4c969d40542de5056b69f94c2961..c4f358dafdaa58c8a2d2c197789cf740a802202d 100644 (file)
@@ -11,8 +11,11 @@ Required properties:
 
   - interrupts : G2D interrupt number to the CPU.
   - clocks : from common clock binding: handle to G2D clocks.
-  - clock-names : from common clock binding: must contain "sclk_fimg2d" and
-                 "fimg2d", corresponding to entries in the clocks property.
+  - clock-names : names of clocks listed in clocks property, in the same
+                 order, depending on SoC type:
+                 - for S5PV210 and Exynos4 based SoCs: "fimg2d" and
+                   "sclk_fimg2d"
+                 - for Exynos5250 SoC: "fimg2d".
 
 Example:
        g2d@12800000 {
index d5176882d8b999563f11a25a6cb806caf0e863d6..a61727f9a6d171df79a83774b75a1462fea48865 100644 (file)
@@ -1,7 +1,7 @@
 Binding for TI/National Semiconductor LP55xx Led Drivers
 
 Required properties:
-- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562"
+- compatible: "national,lp5521" or "national,lp5523" or "ti,lp5562" or "ti,lp8501"
 - reg: I2C slave address
 - clock-mode: Input clock mode, (0: automode, 1: internal, 2: external)
 
@@ -11,6 +11,11 @@ Each child has own specific current settings
 
 Optional properties:
 - label: Used for naming LEDs
+- pwr-sel: LP8501 specific property. Power selection for output channels.
+         0: D1~9 are connected to VDD
+         1: D1~6 with VDD, D7~9 with VOUT
+         2: D1~6 with VOUT, D7~9 with VDD
+         3: D1~9 are connected to VOUT
 
 Alternatively, each child can have specific channel name
 - chan-name: Name of each channel name
@@ -145,3 +150,68 @@ lp5562@30 {
                max-cur = /bits/ 8 <0x60>;
        };
 };
+
+example 4) LP8501
+9 channels are defined. The 'pwr-sel' is LP8501 specific property.
+Others are same as LP5523.
+
+lp8501@32 {
+       compatible = "ti,lp8501";
+       reg = <0x32>;
+       clock-mode = /bits/ 8 <2>;
+       pwr-sel = /bits/ 8 <3>; /* D1~9 connected to VOUT */
+
+       chan0 {
+               chan-name = "d1";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan1 {
+               chan-name = "d2";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan2 {
+               chan-name = "d3";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan3 {
+               chan-name = "d4";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan4 {
+               chan-name = "d5";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan5 {
+               chan-name = "d6";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan6 {
+               chan-name = "d7";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan7 {
+               chan-name = "d8";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+
+       chan8 {
+               chan-name = "d9";
+               led-cur = /bits/ 8 <0x14>;
+               max-cur = /bits/ 8 <0x20>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/leds/pca963x.txt b/Documentation/devicetree/bindings/leds/pca963x.txt
new file mode 100644 (file)
index 0000000..aece3ea
--- /dev/null
@@ -0,0 +1,47 @@
+LEDs connected to pca9632, pca9633 or pca9634
+
+Required properties:
+- compatible : should be : "nxp,pca9632", "nxp,pca9633" or "nxp,pca9634"
+
+Optional properties:
+- nxp,totem-pole : use totem pole (push-pull) instead of default open-drain
+- nxp,hw-blink : use hardware blinking instead of software blinking
+
+Each led is represented as a sub-node of the nxp,pca963x device.
+
+LED sub-node properties:
+- label : (optional) see Documentation/devicetree/bindings/leds/common.txt
+- reg : number of LED line (could be from 0 to 3  in pca9632 or pca9633
+               or 0 to 7 in pca9634)
+- linux,default-trigger : (optional)
+   see Documentation/devicetree/bindings/leds/common.txt
+
+Examples:
+
+pca9632: pca9632 {
+       compatible = "nxp,pca9632";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0x62>;
+
+       red@0 {
+               label = "red";
+               reg = <0>;
+               linux,default-trigger = "none";
+       };
+       green@1 {
+               label = "green";
+               reg = <1>;
+               linux,default-trigger = "none";
+       };
+       blue@2 {
+               label = "blue";
+               reg = <2>;
+               linux,default-trigger = "none";
+       };
+       unused@3 {
+               label = "unused";
+               reg = <3>;
+               linux,default-trigger = "none";
+       };
+};
diff --git a/Documentation/devicetree/bindings/memory.txt b/Documentation/devicetree/bindings/memory.txt
new file mode 100644 (file)
index 0000000..eb24693
--- /dev/null
@@ -0,0 +1,168 @@
+*** Memory binding ***
+
+The /memory node provides basic information about the address and size
+of the physical memory. This node is usually filled or updated by the
+bootloader, depending on the actual memory configuration of the given
+hardware.
+
+The memory layout is described by the following node:
+
+/ {
+       #address-cells = <(n)>;
+       #size-cells = <(m)>;
+       memory {
+               device_type = "memory";
+               reg =  <(baseaddr1) (size1)
+                       (baseaddr2) (size2)
+                       ...
+                       (baseaddrN) (sizeN)>;
+       };
+       ...
+};
+
+A memory node follows the typical device tree rules for "reg" property:
+n:             number of cells used to store base address value
+m:             number of cells used to store size value
+baseaddrX:     defines a base address of the defined memory bank
+sizeX:         the size of the defined memory bank
+
+
+More than one memory bank can be defined.
+
+
+*** Reserved memory regions ***
+
+In /memory/reserved-memory node one can create child nodes describing
+particular reserved (excluded from normal use) memory regions. Such
+memory regions are usually designed for the special usage by various
+device drivers. A good example are contiguous memory allocations or
+memory sharing with other operating system on the same hardware board.
+Those special memory regions might depend on the board configuration and
+devices used on the target system.
+
+Parameters for each memory region can be encoded into the device tree
+with the following convention:
+
+[(label):] (name) {
+       compatible = "linux,contiguous-memory-region", "reserved-memory-region";
+       reg = <(address) (size)>;
+       (linux,default-contiguous-region);
+};
+
+compatible:    one or more of:
+       - "linux,contiguous-memory-region" - enables binding of this
+         region to Contiguous Memory Allocator (special region for
+         contiguous memory allocations, shared with movable system
+         memory, Linux kernel-specific).
+       - "reserved-memory-region" - compatibility is defined, given
+         region is assigned for exclusive usage for by the respective
+         devices.
+
+reg:   standard property defining the base address and size of
+       the memory region
+
+linux,default-contiguous-region: property indicating that the region
+       is the default region for all contiguous memory
+       allocations, Linux specific (optional)
+
+It is optional to specify the base address, so if one wants to use
+autoconfiguration of the base address, '0' can be specified as a base
+address in the 'reg' property.
+
+The /memory/reserved-memory node must contain the same #address-cells
+and #size-cells value as the root node.
+
+
+*** Device node's properties ***
+
+Once regions in the /memory/reserved-memory node have been defined, they
+may be referenced by other device nodes. Bindings that wish to reference
+memory regions should explicitly document their use of the following
+property:
+
+memory-region = <&phandle_to_defined_region>;
+
+This property indicates that the device driver should use the memory
+region pointed by the given phandle.
+
+
+*** Example ***
+
+This example defines a memory consisting of 4 memory banks. 3 contiguous
+regions are defined for Linux kernel, one default of all device drivers
+(named contig_mem, placed at 0x72000000, 64MiB), one dedicated to the
+framebuffer device (labelled display_mem, placed at 0x78000000, 8MiB)
+and one for multimedia processing (labelled multimedia_mem, placed at
+0x77000000, 64MiB). 'display_mem' region is then assigned to fb@12300000
+device for DMA memory allocations (Linux kernel drivers will use CMA is
+available or dma-exclusive usage otherwise). 'multimedia_mem' is
+assigned to scaler@12500000 and codec@12600000 devices for contiguous
+memory allocations when CMA driver is enabled.
+
+The reason for creating a separate region for framebuffer device is to
+match the framebuffer base address to the one configured by bootloader,
+so once Linux kernel drivers starts no glitches on the displayed boot
+logo appears. Scaller and codec drivers should share the memory
+allocations.
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       /* ... */
+
+       memory {
+               reg =  <0x40000000 0x10000000
+                       0x50000000 0x10000000
+                       0x60000000 0x10000000
+                       0x70000000 0x10000000>;
+
+               reserved-memory {
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       /*
+                        * global autoconfigured region for contiguous allocations
+                        * (used only with Contiguous Memory Allocator)
+                        */
+                       contig_region@0 {
+                               compatible = "linux,contiguous-memory-region";
+                               reg = <0x0 0x4000000>;
+                               linux,default-contiguous-region;
+                       };
+
+                       /*
+                        * special region for framebuffer
+                        */
+                       display_region: region@78000000 {
+                               compatible = "linux,contiguous-memory-region", "reserved-memory-region";
+                               reg = <0x78000000 0x800000>;
+                       };
+
+                       /*
+                        * special region for multimedia processing devices
+                        */
+                       multimedia_region: region@77000000 {
+                               compatible = "linux,contiguous-memory-region";
+                               reg = <0x77000000 0x4000000>;
+                       };
+               };
+       };
+
+       /* ... */
+
+       fb0: fb@12300000 {
+               status = "okay";
+               memory-region = <&display_region>;
+       };
+
+       scaler: scaler@12500000 {
+               status = "okay";
+               memory-region = <&multimedia_region>;
+       };
+
+       codec: codec@12600000 {
+               status = "okay";
+               memory-region = <&multimedia_region>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/metag/pdc-intc.txt b/Documentation/devicetree/bindings/metag/pdc-intc.txt
new file mode 100644 (file)
index 0000000..a691185
--- /dev/null
@@ -0,0 +1,105 @@
+* ImgTec Powerdown Controller (PDC) Interrupt Controller Binding
+
+This binding specifies what properties must be available in the device tree
+representation of a PDC IRQ controller. This has a number of input interrupt
+lines which can wake the system, and are passed on through output interrupt
+lines.
+
+Required properties:
+
+    - compatible: Specifies the compatibility list for the interrupt controller.
+      The type shall be <string> and the value shall include "img,pdc-intc".
+
+    - reg: Specifies the base PDC physical address(s) and size(s) of the
+      addressable register space. The type shall be <prop-encoded-array>.
+
+    - interrupt-controller: The presence of this property identifies the node
+      as an interrupt controller. No property value shall be defined.
+
+    - #interrupt-cells: Specifies the number of cells needed to encode an
+      interrupt source. The type shall be a <u32> and the value shall be 2.
+
+    - num-perips: Number of waking peripherals.
+
+    - num-syswakes: Number of SysWake inputs.
+
+    - interrupts: List of interrupt specifiers. The first specifier shall be the
+      shared SysWake interrupt, and remaining specifies shall be PDC peripheral
+      interrupts in order.
+
+* Interrupt Specifier Definition
+
+  Interrupt specifiers consists of 2 cells encoded as follows:
+
+    - <1st-cell>: The interrupt-number that identifies the interrupt source.
+                    0-7:  Peripheral interrupts
+                    8-15: SysWake interrupts
+
+    - <2nd-cell>: The level-sense information, encoded using the Linux interrupt
+                  flags as follows (only 4 valid for peripheral interrupts):
+                    0 = none (decided by software)
+                    1 = low-to-high edge triggered
+                    2 = high-to-low edge triggered
+                    3 = both edge triggered
+                    4 = active-high level-sensitive (required for perip irqs)
+                    8 = active-low level-sensitive
+
+* Examples
+
+Example 1:
+
+       /*
+        * TZ1090 PDC block
+        */
+       pdc: pdc@0x02006000 {
+               // This is an interrupt controller node.
+               interrupt-controller;
+
+               // Three cells to encode interrupt sources.
+               #interrupt-cells = <2>;
+
+               // Offset address of 0x02006000 and size of 0x1000.
+               reg = <0x02006000 0x1000>;
+
+               // Compatible with Meta hardware trigger block.
+               compatible = "img,pdc-intc";
+
+               // Three peripherals are connected.
+               num-perips = <3>;
+
+               // Four SysWakes are connected.
+               num-syswakes = <4>;
+
+               interrupts = <18 4 /* level */>, /* Syswakes */
+                            <30 4 /* level */>, /* Peripheral 0 (RTC) */
+                            <29 4 /* level */>, /* Peripheral 1 (IR) */
+                            <31 4 /* level */>; /* Peripheral 2 (WDT) */
+       };
+
+Example 2:
+
+       /*
+        * An SoC peripheral that is wired through the PDC.
+        */
+       rtc0 {
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&pdc>;
+
+               // Interrupt source Peripheral 0
+               interrupts = <0   /* Peripheral 0 (RTC) */
+                             4>  /* IRQ_TYPE_LEVEL_HIGH */
+       };
+
+Example 3:
+
+       /*
+        * An interrupt generating device that is wired to a SysWake pin.
+        */
+       touchscreen0 {
+               // The interrupt controller that this device is wired to.
+               interrupt-parent = <&pdc>;
+
+               // Interrupt source SysWake 0 that is active-low level-sensitive
+               interrupts = <8 /* SysWake0 */
+                             8 /* IRQ_TYPE_LEVEL_LOW */>;
+       };
index 892537d1a48f8fc394aa6c1330fa338c7a27bce7..e5f0f830346167e1a91f3430ecdbb0ca92ab1444 100644 (file)
@@ -5,6 +5,7 @@ twl6035 (palmas)
 twl6037 (palmas)
 tps65913 (palmas)
 tps65914 (palmas)
+tps659038
 
 Required properties:
 - compatible : Should be from the list
@@ -14,6 +15,7 @@ Required properties:
   ti,tps65913
   ti,tps65914
   ti,tps80036
+  ti,tps659038
 and also the generic series names
   ti,palmas
 - interrupt-controller : palmas has its own internal IRQs
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
new file mode 100644 (file)
index 0000000..c9332c6
--- /dev/null
@@ -0,0 +1,109 @@
+
+* Samsung S2MPS11 Voltage and Current Regulator
+
+The Samsung S2MP211 is a multi-function device which includes voltage and
+current regulators, RTC, charger controller and other sub-blocks. It is
+interfaced to the host controller using a I2C interface. Each sub-block is
+addressed by the host system using different I2C slave address.
+
+Required properties:
+- compatible: Should be "samsung,s2mps11-pmic".
+- reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
+
+Optional properties:
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the interrupts from s2mps11 are delivered to.
+- interrupts: Interrupt specifiers for interrupt sources.
+
+Optional nodes:
+- clocks: s2mps11 provides three(AP/CP/BT) buffered 32.768 KHz outputs, so to
+  register these as clocks with common clock framework instantiate a sub-node
+  named "clocks". It uses the common clock binding documented in :
+  [Documentation/devicetree/bindings/clock/clock-bindings.txt]
+  - #clock-cells: should be 1.
+
+  - The following is the list of clocks generated by the controller. Each clock
+    is assigned an identifier and client nodes use this identifier to specify
+    the clock which they consume.
+    Clock               ID
+    ----------------------
+    32KhzAP            0
+    32KhzCP            1
+    32KhzBT            2
+
+- regulators: The regulators of s2mps11 that have to be instantiated should be
+included in a sub-node named 'regulators'. Regulator nodes included in this
+sub-node should be of the format as listed below.
+
+       regulator_name {
+               [standard regulator constraints....];
+       };
+
+ regulator-ramp-delay for BUCKs = [6250/12500/25000(default)/50000] uV/us
+
+ BUCK[2/3/4/6] supports disabling ramp delay on hardware, so explictly
+ regulator-ramp-delay = <0> can be used for them to disable ramp delay.
+ In absence of regulator-ramp-delay property, default ramp delay will be used.
+
+NOTE: Some BUCKs share the ramp rate setting i.e. same ramp value will be set
+for a particular group of BUCKs. So provide same regulator-ramp-delay<value>.
+Grouping of BUCKs sharing ramp rate setting is as follow : BUCK[1, 6],
+BUCK[3, 4], and BUCK[7, 8, 10]
+
+The regulator constraints inside the regulator nodes use the standard regulator
+bindings which are documented elsewhere.
+
+The following are the names of the regulators that the s2mps11 pmic block
+supports. Note: The 'n' in LDOn and BUCKn represents the LDO or BUCK number
+as per the datasheet of s2mps11.
+
+       - LDOn
+                 - valid values for n are 1 to 28
+                 - Example: LDO0, LD01, LDO28
+       - BUCKn
+                 - valid values for n are 1 to 9.
+                 - Example: BUCK1, BUCK2, BUCK9
+
+Example:
+
+       s2mps11_pmic@66 {
+               compatible = "samsung,s2mps11-pmic";
+               reg = <0x66>;
+
+               s2m_osc: clocks{
+                       #clock-cells = 1;
+                       clock-output-names = "xx", "yy", "zz";
+               };
+
+               regulators {
+                       ldo1_reg: LDO1 {
+                               regulator-name = "VDD_ABB_3.3V";
+                               regulator-min-microvolt = <3300000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ldo2_reg: LDO2 {
+                               regulator-name = "VDD_ALIVE_1.1V";
+                               regulator-min-microvolt = <1100000>;
+                               regulator-max-microvolt = <1100000>;
+                               regulator-always-on;
+                       };
+
+                       buck1_reg: BUCK1 {
+                               regulator-name = "vdd_mif";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                       };
+
+                       buck2_reg: BUCK2 {
+                               regulator-name = "vdd_arm";
+                               regulator-min-microvolt = <950000>;
+                               regulator-max-microvolt = <1350000>;
+                               regulator-always-on;
+                               regulator-boot-on;
+                               regulator-ramp-delay = <50000>;
+                       };
+               };
+       };
index bd9be0b5bc2034279d628f07eece8a3d9c2b394d..b7943f3f999546cbaa1ec4170299c9221030427d 100644 (file)
@@ -19,6 +19,9 @@ Optional properties:
     "bus-width = <1>" property.
   - sdhci,auto-cmd12: specifies that a controller can only handle auto
     CMD12.
+  - voltage-ranges : two cells are required, first cell specifies minimum
+    slot voltage (mV), second cell specifies maximum slot voltage (mV).
+    Several ranges could be specified.
 
 Example:
 
@@ -29,4 +32,5 @@ sdhci@2e000 {
        interrupt-parent = <&ipic>;
        /* Filled in by U-Boot */
        clock-frequency = <0>;
+       voltage-ranges = <3300 3300>;
 };
index d555421ea49f8237d5a8a0c1822facd379b60f1b..c4728839d0c1333098b38fe4e7aa96e3e0ab7f9e 100644 (file)
@@ -15,6 +15,7 @@ Required properties:
   optional gpio and may be set to 0 if not present.
 
 Optional properties:
+- atmel,nand-has-dma : boolean to support dma transfer for nand read/write.
 - nand-ecc-mode : String, operation mode of the NAND ecc mode, soft by default.
   Supported values are: "none", "soft", "hw", "hw_syndrome", "hw_oob_first",
   "soft_bch".
@@ -29,6 +30,14 @@ Optional properties:
   sector size 1024.
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+- Nand Flash Controller(NFC) is a slave driver under Atmel nand flash
+  - Required properties:
+    - compatible : "atmel,sama5d3-nfc".
+    - reg : should specify the address and size used for NFC command registers,
+            NFC registers and NFC Sram. NFC Sram address and size can be absent
+            if don't want to use it.
+  - Optional properties:
+    - atmel,write-by-sram: boolean to enable NFC write by sram.
 
 Examples:
 nand0: nand@40000000,0 {
@@ -77,3 +86,22 @@ nand0: nand@40000000 {
                ...
        };
 };
+
+/* for NFC supported chips */
+nand0: nand@40000000 {
+       compatible = "atmel,at91rm9200-nand";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+        ...
+        nfc@70000000 {
+               compatible = "atmel,sama5d3-nfc";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <
+                       0x70000000 0x10000000   /* NFC Command Registers */
+                       0xffffc000 0x00000070   /* NFC HSMC regs */
+                       0x00200000 0x00100000   /* NFC SRAM banks */
+               >;
+       };
+};
index 2240ac09f6ba05cf1bea9aaa6788d01b9c3583e4..ec42935f390861810c1e7f6dd8e925220d46e6f1 100644 (file)
@@ -1,4 +1,5 @@
-* FSMC NAND
+ST Microelectronics Flexible Static Memory Controller (FSMC)
+NAND Interface
 
 Required properties:
 - compatible : "st,spear600-fsmc-nand", "stericsson,fsmc-nand"
@@ -9,6 +10,26 @@ Optional properties:
 - bank-width : Width (in bytes) of the device.  If not present, the width
   defaults to 1 byte
 - nand-skip-bbtscan: Indicates the the BBT scanning should be skipped
+- timings: array of 6 bytes for NAND timings. The meanings of these bytes
+  are:
+  byte 0 TCLR  : CLE to RE delay in number of AHB clock cycles, only 4 bits
+                 are valid. Zero means one clockcycle, 15 means 16 clock
+                 cycles.
+  byte 1 TAR   : ALE to RE delay, 4 bits are valid. Same format as TCLR.
+  byte 2 THIZ  : number of HCLK clock cycles during which the data bus is
+                 kept in Hi-Z (tristate) after the start of a write access.
+                 Only valid for write transactions. Zero means zero cycles,
+                 255 means 255 cycles.
+  byte 3 THOLD : number of HCLK clock cycles to hold the address (and data
+                 when writing) after the command deassertation. Zero means
+                 one cycle, 255 means 256 cycles.
+  byte 4 TWAIT : number of HCLK clock cycles to assert the command to the
+                 NAND flash in response to SMWAITn. Zero means 1 cycle,
+                 255 means 256 cycles.
+  byte 5 TSET  : number of HCLK clock cycles to assert the address before the
+                 command is asserted. Zero means one cycle, 255 means 256
+                 cycles.
+- bank: default NAND bank to use (0-3 are valid, 0 is the default).
 
 Example:
 
@@ -24,6 +45,8 @@ Example:
 
                bank-width = <1>;
                nand-skip-bbtscan;
+               timings = /bits/ 8 <0 0 0 2 3 0>;
+               bank = <1>;
 
                partition@0 {
                        ...
index 9315ac96b49b224665b674f1d0109805aaf0c9a8..8e5557da1955472b3b2faf8b6c638e9ef5e61293 100644 (file)
@@ -4,6 +4,7 @@ Partitions can be represented by sub-nodes of an mtd device. This can be used
 on platforms which have strong conventions about which portions of a flash are
 used for what purposes, but which don't use an on-flash partition table such
 as RedBoot.
+NOTE: if the sub-node has a compatible string, then it is not a partition.
 
 #address-cells & #size-cells must both be present in the mtd device. There are
 two valid values for both:
index c2dbcec0ee31d33482858367e097140a766516d4..f2105a47ec87c547fcd88d383d136ec4d11eb65b 100644 (file)
@@ -37,7 +37,7 @@ Optional properties:
        If not specified or if the specified value is 0, the CLKOUT pin
        will be disabled.
 
-- nxp,no-comparator-bypass : Allows to disable the CAN input comperator.
+- nxp,no-comparator-bypass : Allows to disable the CAN input comparator.
 
 For further information, please have a look to the SJA1000 data sheet.
 
diff --git a/Documentation/devicetree/bindings/pci/ralink,rt3883-pci.txt b/Documentation/devicetree/bindings/pci/ralink,rt3883-pci.txt
new file mode 100644 (file)
index 0000000..8e0a1eb
--- /dev/null
@@ -0,0 +1,190 @@
+* Mediatek/Ralink RT3883 PCI controller
+
+1) Main node
+
+   Required properties:
+
+   - compatible: must be "ralink,rt3883-pci"
+
+   - reg: specifies the physical base address of the controller and
+     the length of the memory mapped region.
+
+   - #address-cells: specifies the number of cells needed to encode an
+     address. The value must be 1.
+
+   - #size-cells: specifies the number of cells used to represent the size
+     of an address. The value must be 1.
+
+   - ranges: specifies the translation between child address space and parent
+     address space
+
+  Optional properties:
+
+   - status: indicates the operational status of the device.
+     Value must be either "disabled" or "okay".
+
+2) Child nodes
+
+   The main node must have two child nodes which describes the built-in
+   interrupt controller and the PCI host bridge.
+
+   a) Interrupt controller:
+
+   Required properties:
+
+   - interrupt-controller: identifies the node as an interrupt controller
+
+   - #address-cells: specifies the number of cells needed to encode an
+     address. The value must be 0. As such, 'interrupt-map' nodes do not
+     have to specify a parent unit address.
+
+   - #interrupt-cells: specifies the number of cells needed to encode an
+     interrupt source. The value must be 1.
+
+   - interrupt-parent: the phandle for the interrupt controller that
+     services interrupts for this device.
+
+   - interrupts: specifies the interrupt source of the parent interrupt
+     controller. The format of the interrupt specifier depends on the
+     parent interrupt controller.
+
+   b) PCI host bridge:
+
+   Required properties:
+
+   - #address-cells: specifies the number of cells needed to encode an
+     address. The value must be 0.
+
+   - #size-cells: specifies the number of cells used to represent the size
+     of an address. The value must be 2.
+
+   - #interrupt-cells: specifies the number of cells needed to encode an
+     interrupt source. The value must be 1.
+
+   - device_type: must be "pci"
+
+   - bus-range: PCI bus numbers covered
+
+   - ranges: specifies the ranges for the PCI memory and I/O regions
+
+   - interrupt-map-mask,
+   - interrupt-map: standard PCI properties to define the mapping of the
+     PCI interface to interrupt numbers.
+
+   The PCI host bridge node migh have additional sub-nodes representing
+   the onboard PCI devices/PCI slots. Each such sub-node must have the
+   following mandatory properties:
+
+     - reg: used only for interrupt mapping, so only the first four bytes
+       are used to refer to the correct bus number and device number.
+
+     - device_type: must be "pci"
+
+   If a given sub-node represents a PCI bridge it must have following
+   mandatory properties as well:
+
+     - #address-cells: must be set to <3>
+
+     - #size-cells: must set to <2>
+
+     - #interrupt-cells: must be set to <1>
+
+     - interrupt-map-mask,
+     - interrupt-map: standard PCI properties to define the mapping of the
+       PCI interface to interrupt numbers.
+
+   Besides the required properties the sub-nodes may have these optional
+   properties:
+
+     - status: indicates the operational status of the sub-node.
+       Value must be either "disabled" or "okay".
+
+3) Example:
+
+   a) SoC specific dtsi file:
+
+       pci@10140000 {
+               compatible = "ralink,rt3883-pci";
+               reg = <0x10140000 0x20000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges; /* direct mapping */
+
+               status = "disabled";
+
+               pciintc: interrupt-controller {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+
+                       interrupt-parent = <&cpuintc>;
+                       interrupts = <4>;
+               };
+
+               host-bridge {
+                       #address-cells = <3>;
+                       #size-cells = <2>;
+                       #interrupt-cells = <1>;
+
+                       device_type = "pci";
+
+                       bus-range = <0 255>;
+                       ranges = <
+                               0x02000000 0 0x00000000 0x20000000 0 0x10000000 /* pci memory */
+                               0x01000000 0 0x00000000 0x10160000 0 0x00010000 /* io space */
+                       >;
+
+                       interrupt-map-mask = <0xf800 0 0 7>;
+                       interrupt-map = <
+                               /* IDSEL 17 */
+                               0x8800 0 0 1 &pciintc 18
+                               0x8800 0 0 2 &pciintc 18
+                               0x8800 0 0 3 &pciintc 18
+                               0x8800 0 0 4 &pciintc 18
+                               /* IDSEL 18 */
+                               0x9000 0 0 1 &pciintc 19
+                               0x9000 0 0 2 &pciintc 19
+                               0x9000 0 0 3 &pciintc 19
+                               0x9000 0 0 4 &pciintc 19
+                       >;
+
+                       pci-bridge@1 {
+                               reg = <0x0800 0 0 0 0>;
+                               device_type = "pci";
+                               #interrupt-cells = <1>;
+                               #address-cells = <3>;
+                               #size-cells = <2>;
+
+                               interrupt-map-mask = <0x0 0 0 0>;
+                               interrupt-map = <0x0 0 0 0 &pciintc 20>;
+
+                               status = "disabled";
+                       };
+
+                       pci-slot@17 {
+                               reg = <0x8800 0 0 0 0>;
+                               device_type = "pci";
+
+                               status = "disabled";
+                       };
+
+                       pci-slot@18 {
+                               reg = <0x9000 0 0 0 0>;
+                               device_type = "pci";
+
+                               status = "disabled";
+                       };
+               };
+       };
+
+   b) Board specific dts file:
+
+       pci@10140000 {
+               status = "okay";
+
+               host-bridge {
+                       pci-bridge@1 {
+                               status = "okay";
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt b/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt
new file mode 100644 (file)
index 0000000..ce44ad3
--- /dev/null
@@ -0,0 +1,17 @@
+MSM Restart Driver
+
+A power supply hold (ps-hold) bit is set to power the msm chipsets.
+Clearing that bit allows us to restart/poweroff. The difference
+between poweroff and restart is determined by unique power manager IC
+settings.
+
+Required Properties:
+-compatible: "qcom,pshold"
+-reg: Specifies the physical address of the ps-hold register
+
+Example:
+
+       restart@fc4ab000 {
+               compatible = "qcom,pshold";
+               reg = <0xfc4ab000 0x4>;
+       };
index 4caa1a78863e088415ca6af4ebd756f354ab3455..d61fccd40bad42a746374c29f8589891bb75621f 100644 (file)
@@ -19,6 +19,16 @@ Required properties:
 - reg: base address and size of register area
 - interrupts: list of timer interrupts (one interrupt per timer, starting at
   timer 0)
+- clock-names: should contain all following required clock names:
+    - "timers" - PWM base clock used to generate PWM signals,
+  and any subset of following optional clock names:
+    - "pwm-tclk0" - first external PWM clock source,
+    - "pwm-tclk1" - second external PWM clock source.
+  Note that not all IP variants allow using all external clock sources.
+  Refer to SoC documentation to learn which clock source configurations
+  are available.
+- clocks: should contain clock specifiers of all clocks, which input names
+  have been specified in clock-names property, in same order.
 - #pwm-cells: should be 3. See pwm.txt in this directory for a description of
   the cells format. The only third cell flag supported by this binding is
   PWM_POLARITY_INVERTED.
@@ -34,6 +44,8 @@ Example:
                reg = <0x7f006000 0x1000>;
                interrupt-parent = <&vic0>;
                interrupts = <23>, <24>, <25>, <27>, <28>;
+               clocks = <&clock 67>;
+               clock-names = "timers";
                samsung,pwm-outputs = <0>, <1>;
                #pwm-cells = <3>;
        }
index a22e4c70db5cea846b3ee477822f6d73cb837668..875639ae0606e1e6637cacd9ef35dfde9ec0399a 100644 (file)
@@ -36,6 +36,9 @@ Optional nodes:
               ti,smps-range - OTP has the wrong range set for the hardware so override
               0 - low range, 1 - high range.
 
+- ti,system-power-controller: Telling whether or not this pmic is controlling
+                             the system power.
+
 Example:
 
 #include <dt-bindings/interrupt-controller/irq.h>
@@ -48,6 +51,8 @@ pmic {
 
        ti,ldo6-vibrator;
 
+       ti,system-power-controller;
+
        regulators {
                smps12_reg : smps12 {
                        regulator-name = "smps12";
diff --git a/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt b/Documentation/devicetree/bindings/rtc/moxa,moxart-rtc.txt
new file mode 100644 (file)
index 0000000..c9d3ac1
--- /dev/null
@@ -0,0 +1,17 @@
+MOXA ART real-time clock
+
+Required properties:
+
+- compatible : Should be "moxa,moxart-rtc"
+- gpio-rtc-sclk : RTC sclk gpio, with zero flags
+- gpio-rtc-data : RTC data gpio, with zero flags
+- gpio-rtc-reset : RTC reset gpio, with zero flags
+
+Example:
+
+       rtc: rtc {
+               compatible = "moxa,moxart-rtc";
+               gpio-rtc-sclk = <&gpio 5 0>;
+               gpio-rtc-data = <&gpio 6 0>;
+               gpio-rtc-reset = <&gpio 7 0>;
+       };
index b47aa415c8206f84347ef4bb146ada97a40c9a2b..5a0f02d34d9578a549fbf8ff05474a2abd96b9f3 100644 (file)
@@ -1,7 +1,11 @@
 TI Real Time Clock
 
 Required properties:
-- compatible: "ti,da830-rtc"
+- compatible:
+       - "ti,da830-rtc"  - for RTC IP used similar to that on DA8xx SoC family.
+       - "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family.
+                           This RTC IP has special WAKE-EN Register to enable
+                           Wakeup generation for event Alarm.
 - reg: Address range of rtc register set
 - interrupts: rtc timer, alarm interrupts in order
 - interrupt-parent: phandle for the interrupt controller
diff --git a/Documentation/devicetree/bindings/rtc/rtc-palmas.txt b/Documentation/devicetree/bindings/rtc/rtc-palmas.txt
new file mode 100644 (file)
index 0000000..adbccc0
--- /dev/null
@@ -0,0 +1,33 @@
+Palmas RTC controller bindings
+
+Required properties:
+- compatible:
+  - "ti,palmas-rtc" for palma series of the RTC controller
+- interrupt-parent: Parent interrupt device, must be handle of palmas node.
+- interrupts: Interrupt number of RTC submodule on device.
+
+Optional properties:
+
+- ti,backup-battery-chargeable: The Palmas series device like TPS65913 or
+       TPS80036 supports the backup battery for powering the RTC when main
+       battery is removed or in very low power state. The backup battery
+       can be chargeable or non-chargeable. This flag will tells whether
+       battery is chargeable or not. If charging battery then driver can
+       enable the charging.
+- ti,backup-battery-charge-high-current: Enable high current charging in
+       backup battery. Device supports the < 100mA and > 100mA charging.
+       The high current will be > 100mA. Absence of this property will
+       charge battery to lower current i.e. < 100mA.
+
+Example:
+       palmas: tps65913@58 {
+               ...
+               palmas_rtc: rtc {
+                       compatible = "ti,palmas-rtc";
+                       interrupt-parent = <&palmas>;
+                       interrupts = <8 0>;
+                       ti,backup-battery-chargeable;
+                       ti,backup-battery-charge-high-current;
+               };
+               ...
+       };
index 7e5fd37c1b3f4d7fa983b43a31eace9fb88ec238..f0062c5871b4d1d525af5dac77fa85a2398a83ec 100644 (file)
@@ -2,13 +2,17 @@
 
 Required properties:
 
-- compatible: "marvell,mvebu-audio"
+- compatible:
+  "marvell,kirkwood-audio" for Kirkwood platforms
+  "marvell,dove-audio" for Dove platforms
 
 - reg: physical base address of the controller and length of memory mapped
   region.
 
-- interrupts: list of two irq numbers.
-  The first irq is used for data flow and the second one is used for errors.
+- interrupts:
+  with "marvell,kirkwood-audio", the audio interrupt
+  with "marvell,dove-audio", a list of two interrupts, the first for
+  the data flow, and the second for errors.
 
 - clocks: one or two phandles.
   The first one is mandatory and defines the internal clock.
@@ -21,7 +25,7 @@ Required properties:
 Example:
 
 i2s1: audio-controller@b4000 {
-       compatible = "marvell,mvebu-audio";
+       compatible = "marvell,dove-audio";
        reg = <0xb4000 0x2210>;
        interrupts = <21>, <22>;
        clocks = <&gate_clk 13>;
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
new file mode 100644 (file)
index 0000000..284f530
--- /dev/null
@@ -0,0 +1,55 @@
+* Exynos Thermal Management Unit (TMU)
+
+** Required properties:
+
+- compatible : One of the following:
+              "samsung,exynos4412-tmu"
+              "samsung,exynos4210-tmu"
+              "samsung,exynos5250-tmu"
+              "samsung,exynos5440-tmu"
+- interrupt-parent : The phandle for the interrupt controller
+- reg : Address range of the thermal registers. For soc's which has multiple
+       instances of TMU and some registers are shared across all TMU's like
+       interrupt related then 2 set of register has to supplied. First set
+       belongs to each instance of TMU and second set belongs to common TMU
+       registers.
+- interrupts : Should contain interrupt for thermal system
+- clocks : The main clock for TMU device
+- clock-names : Thermal system clock name
+- vtmu-supply: This entry is optional and provides the regulator node supplying
+               voltage to TMU. If needed this entry can be placed inside
+               board/platform specific dts file.
+
+Example 1):
+
+       tmu@100C0000 {
+               compatible = "samsung,exynos4412-tmu";
+               interrupt-parent = <&combiner>;
+               reg = <0x100C0000 0x100>;
+               interrupts = <2 4>;
+               clocks = <&clock 383>;
+               clock-names = "tmu_apbif";
+               status = "disabled";
+               vtmu-supply = <&tmu_regulator_node>;
+       };
+
+Example 2):
+
+       tmuctrl_0: tmuctrl@160118 {
+               compatible = "samsung,exynos5440-tmu";
+               reg = <0x160118 0x230>, <0x160368 0x10>;
+               interrupts = <0 58 0>;
+               clocks = <&clock 21>;
+               clock-names = "tmu_apbif";
+       };
+
+Note: For multi-instance tmu each instance should have an alias correctly
+numbered in "aliases" node.
+
+Example:
+
+aliases {
+       tmuctrl0 = &tmuctrl_0;
+       tmuctrl1 = &tmuctrl_1;
+       tmuctrl2 = &tmuctrl_2;
+};
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
new file mode 100644 (file)
index 0000000..541c25e
--- /dev/null
@@ -0,0 +1,17 @@
+* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs
+
+Required properties:
+- compatible : "fsl,imx6q-thermal"
+- fsl,tempmon : phandle pointer to system controller that contains TEMPMON
+  control registers, e.g. ANATOP on imx6q.
+- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
+  calibration data, e.g. OCOTP on imx6q.  The details about calibration data
+  can be found in SoC Reference Manual.
+
+Example:
+
+tempmon {
+       compatible = "fsl,imx6q-tempmon";
+       fsl,tempmon = <&anatop>;
+       fsl,tempmon-data = <&ocotp>;
+};
index 36381129d141c47556fc5605670494fcfc4feb18..f455182b108653b058564c517f72d6bf4d4d83f8 100644 (file)
@@ -2,14 +2,40 @@ Marvell Armada 370 and Armada XP Timers
 ---------------------------------------
 
 Required properties:
-- compatible: Should be "marvell,armada-370-xp-timer"
+- compatible: Should be either "marvell,armada-370-timer" or
+  "marvell,armada-xp-timer" as appropriate.
 - interrupts: Should contain the list of Global Timer interrupts and
   then local timer interrupts
 - reg: Should contain location and length for timers register. First
   pair for the Global Timer registers, second pair for the
   local/private timers.
-- clocks: clock driving the timer hardware
 
-Optional properties:
-- marvell,timer-25Mhz: Tells whether the Global timer supports the 25
-  Mhz fixed mode (available on Armada XP and not on Armada 370)
+Clocks required for compatible = "marvell,armada-370-timer":
+- clocks : Must contain a single entry describing the clock input
+
+Clocks required for compatible = "marvell,armada-xp-timer":
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must include the following entries:
+  "nbclk" (L2/coherency fabric clock),
+  "fixed" (Reference 25 MHz fixed-clock).
+
+Examples:
+
+- Armada 370:
+
+       timer {
+               compatible = "marvell,armada-370-timer";
+               reg = <0x20300 0x30>, <0x21040 0x30>;
+               interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
+               clocks = <&coreclk 2>;
+       };
+
+- Armada XP:
+
+       timer {
+               compatible = "marvell,armada-xp-timer";
+               reg = <0x20300 0x30>, <0x21040 0x30>;
+               interrupts = <37>, <38>, <39>, <40>, <5>, <6>;
+               clocks = <&coreclk 2>, <&refclk>;
+               clock-names = "nbclk", "fixed";
+       };
index e31a2a9d2b075e9dda835218b63fd103cb91d6fa..505e71172ae7f17814cc87a5a18d489cd8cdf6a9 100644 (file)
@@ -407,6 +407,18 @@ Being able to mmap an export dma-buf buffer object has 2 main use-cases:
    interesting ways depending upong the exporter (if userspace starts depending
    upon this implicit synchronization).
 
+Other Interfaces Exposed to Userspace on the dma-buf FD
+------------------------------------------------------
+
+- Since kernel 3.12 the dma-buf FD supports the llseek system call, but only
+  with offset=0 and whence=SEEK_END|SEEK_SET. SEEK_SET is supported to allow
+  the usual size discover pattern size = SEEK_END(0); SEEK_SET(0). Every other
+  llseek operation will report -EINVAL.
+
+  If llseek on dma-buf FDs isn't support the kernel will report -ESPIPE for all
+  cases. Userspace can use this to detect support for discovering the dma-buf
+  size using llseek.
+
 Miscellaneous notes
 -------------------
 
index 132a094c7bc3790631b664efb20b6cfb21a3d42e..a2b5663eae266d2dcae8fcf9400ef9eb16b24709 100644 (file)
@@ -16,15 +16,16 @@ be built as module or inside kernel. Let's consider those cases.
        Part 2 - When dmatest is built as a module...
 
 After mounting debugfs and loading the module, the /sys/kernel/debug/dmatest
-folder with nodes will be created. They are the same as module parameters with
-addition of the 'run' node that controls run and stop phases of the test.
+folder with nodes will be created. There are two important files located. First
+is the 'run' node that controls run and stop phases of the test, and the second
+one, 'results', is used to get the test case results.
 
 Note that in this case test will not run on load automatically.
 
 Example of usage:
-       % echo dma0chan0 > /sys/kernel/debug/dmatest/channel
-       % echo 2000 > /sys/kernel/debug/dmatest/timeout
-       % echo 1 > /sys/kernel/debug/dmatest/iterations
+       % echo dma0chan0 > /sys/module/dmatest/parameters/channel
+       % echo 2000 > /sys/module/dmatest/parameters/timeout
+       % echo 1 > /sys/module/dmatest/parameters/iterations
        % echo 1 > /sys/kernel/debug/dmatest/run
 
 Hint: available channel list could be extracted by running the following
@@ -55,8 +56,8 @@ for the first performed test. After user gets a control, the test could be
 re-run with the same or different parameters. For the details see the above
 section "Part 2 - When dmatest is built as a module..."
 
-In both cases the module parameters are used as initial values for the test case.
-You always could check them at run-time by running
+In both cases the module parameters are used as the actual values for the test
+case. You always could check them at run-time by running
        % grep -H . /sys/module/dmatest/parameters/*
 
        Part 4 - Gathering the test results
index fb57d85e7316027f58c336a359e0b1eb6c320f64..fcb34a5697eaa4ec2c44a46791b711d5a78f1c7b 100644 (file)
@@ -299,3 +299,6 @@ PWM
 PHY
   devm_usb_get_phy()
   devm_usb_put_phy()
+
+SLAVE DMA ENGINE
+  devm_acpi_dma_controller_register()
index d78bab9622c63d8ff1b21f9886523f1b90d57ee8..277d1e810670d3678b1991b059758a69a497edef 100644 (file)
@@ -299,6 +299,15 @@ performed on the denizens of the cache.  These are held in a structure of type:
      enough space in the cache to permit this.
 
 
+ (*) Check coherency state of an object [mandatory]:
+
+       int (*check_consistency)(struct fscache_object *object)
+
+     This method is called to have the cache check the saved auxiliary data of
+     the object against the netfs's idea of the state.  0 should be returned
+     if they're consistent and -ESTALE otherwise.  -ENOMEM and -ERESTARTSYS
+     may also be returned.
+
  (*) Update object [mandatory]:
 
        int (*update_object)(struct fscache_object *object)
index 97e6c0ecc5efc0ad763b1d2d3e376c38e057ae07..11a0a40ce445fa5c2f6fb0276dd63907eb55574d 100644 (file)
@@ -32,7 +32,7 @@ This document contains the following sections:
         (9) Setting the data file size
        (10) Page alloc/read/write
        (11) Page uncaching
-       (12) Index and data file update
+       (12) Index and data file consistency
        (13) Miscellaneous cookie operations
        (14) Cookie unregistration
        (15) Index invalidation
@@ -433,7 +433,7 @@ to the caller.  The attribute adjustment excludes read and write operations.
 
 
 =====================
-PAGE READ/ALLOC/WRITE
+PAGE ALLOC/READ/WRITE
 =====================
 
 And the sixth step is to store and retrieve pages in the cache.  There are
@@ -499,7 +499,7 @@ Else if there's a copy of the page resident in the cache:
      (*) An argument that's 0 on success or negative for an error code.
 
      If an error occurs, it should be assumed that the page contains no usable
-     data.
+     data.  fscache_readpages_cancel() may need to be called.
 
      end_io_func() will be called in process context if the read is results in
      an error, but it might be called in interrupt context if the read is
@@ -623,6 +623,22 @@ some of the pages being read and some being allocated.  Those pages will have
 been marked appropriately and will need uncaching.
 
 
+CANCELLATION OF UNREAD PAGES
+----------------------------
+
+If one or more pages are passed to fscache_read_or_alloc_pages() but not then
+read from the cache and also not read from the underlying filesystem then
+those pages will need to have any marks and reservations removed.  This can be
+done by calling:
+
+       void fscache_readpages_cancel(struct fscache_cookie *cookie,
+                                     struct list_head *pages);
+
+prior to returning to the caller.  The cookie argument should be as passed to
+fscache_read_or_alloc_pages().  Every page in the pages list will be examined
+and any that have PG_fscache set will be uncached.
+
+
 ==============
 PAGE UNCACHING
 ==============
@@ -690,9 +706,18 @@ written to the cache and for the cache to finish with the page generally.  No
 error is returned.
 
 
-==========================
-INDEX AND DATA FILE UPDATE
-==========================
+===============================
+INDEX AND DATA FILE CONSISTENCY
+===============================
+
+To find out whether auxiliary data for an object is up to data within the
+cache, the following function can be called:
+
+       int fscache_check_consistency(struct fscache_cookie *cookie)
+
+This will call back to the netfs to check whether the auxiliary data associated
+with a cookie is correct.  It returns 0 if it is and -ESTALE if it isn't; it
+may also return -ENOMEM and -ERESTARTSYS.
 
 To request an update of the index data for an index or other object, the
 following function should be called:
diff --git a/Documentation/filesystems/cifs.txt b/Documentation/filesystems/cifs.txt
deleted file mode 100644 (file)
index 49cc923..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-  This is the client VFS module for the Common Internet File System
-  (CIFS) protocol which is the successor to the Server Message Block 
-  (SMB) protocol, the native file sharing mechanism for most early
-  PC operating systems.  CIFS is fully supported by current network
-  file servers such as Windows 2000, Windows 2003 (including  
-  Windows XP) as well by Samba (which provides excellent CIFS
-  server support for Linux and many other operating systems), so
-  this network filesystem client can mount to a wide variety of
-  servers.  The smbfs module should be used instead of this cifs module
-  for mounting to older SMB servers such as OS/2.  The smbfs and cifs
-  modules can coexist and do not conflict.  The CIFS VFS filesystem
-  module is designed to work well with servers that implement the
-  newer versions (dialects) of the SMB/CIFS protocol such as Samba, 
-  the program written by Andrew Tridgell that turns any Unix host 
-  into a SMB/CIFS file server.
-
-  The intent of this module is to provide the most advanced network
-  file system function for CIFS compliant servers, including better
-  POSIX compliance, secure per-user session establishment, high
-  performance safe distributed caching (oplock), optional packet
-  signing, large files, Unicode support and other internationalization
-  improvements. Since both Samba server and this filesystem client support
-  the CIFS Unix extensions, the combination can provide a reasonable 
-  alternative to NFSv4 for fileserving in some Linux to Linux environments,
-  not just in Linux to Windows environments.
-
-  This filesystem has an optional mount utility (mount.cifs) that can
-  be obtained from the project page and installed in the path in the same
-  directory with the other mount helpers (such as mount.smbfs). 
-  Mounting using the cifs filesystem without installing the mount helper
-  requires specifying the server's ip address.
-
-  For Linux 2.4:
-    mount //anything/here /mnt_target -o
-            user=username,pass=password,unc=//ip_address_of_server/sharename
-
-  For Linux 2.5: 
-    mount //ip_address_of_server/sharename /mnt_target -o user=username, pass=password
-
-
-  For more information on the module see the project page at
-
-      http://us1.samba.org/samba/Linux_CIFS_client.html 
-
-  For more information on CIFS see:
-
-      http://www.snia.org/tech_activities/CIFS
-
-  or the Samba site:
-     
-      http://www.samba.org
diff --git a/Documentation/filesystems/cifs/AUTHORS b/Documentation/filesystems/cifs/AUTHORS
new file mode 100644 (file)
index 0000000..ca4a67a
--- /dev/null
@@ -0,0 +1,56 @@
+Original Author
+===============
+Steve French (sfrench@samba.org)
+
+The author wishes to express his appreciation and thanks to:
+Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
+improvements. Thanks to IBM for allowing me time and test resources to pursue
+this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
+the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
+Jeremy Allison of the Samba team has done invaluable work in adding the server
+side of the original CIFS Unix extensions and reviewing and implementing
+portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank
+Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
+for proving years ago that very good smb/cifs clients could be done on Unix-like
+operating systems.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John 
+Newbigin and others for their work on the Linux smbfs module.  Thanks to
+the other members of the Storage Network Industry Association CIFS Technical
+Workgroup for their work specifying this highly complex protocol and finally
+thanks to the Samba team for their technical advice and encouragement.
+
+Patch Contributors
+------------------
+Zwane Mwaikambo
+Andi Kleen
+Amrut Joshi
+Shobhit Dayal
+Sergey Vlasov
+Richard Hughes
+Yury Umanets
+Mark Hamzy (for some of the early cifs IPv6 work)
+Domen Puncer
+Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
+Vince Negri and Dave Stahl (for finding an important caching bug)
+Adrian Bunk (kcalloc cleanups)
+Miklos Szeredi 
+Kazeon team for various fixes especially for 2.4 version.
+Asser Ferno (Change Notify support)
+Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanup
+Gunter Kukkukk (testing and suggestions for support of old servers)
+Igor Mammedov (DFS support)
+Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
+Scott Lovenberg
+
+Test case and Bug Report contributors
+-------------------------------------
+Thanks to those in the community who have submitted detailed bug reports
+and debug of problems they have found:  Jochen Dolze, David Blaine,
+Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
+Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
+Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special
+mention to the Stanford Checker (SWAT) which pointed out many minor
+bugs in error paths.  Valuable suggestions also have come from Al Viro
+and Dave Miller.
+
+And thanks to the IBM LTC and Power test teams and SuSE testers for
+finding multiple bugs during excellent stress test runs.
diff --git a/Documentation/filesystems/cifs/CHANGES b/Documentation/filesystems/cifs/CHANGES
new file mode 100644 (file)
index 0000000..bc0025c
--- /dev/null
@@ -0,0 +1,1065 @@
+Version 1.62
+------------
+Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened
+to more strictly handle corrupt frames.
+
+Version 1.61
+------------
+Fix append problem to Samba servers (files opened with O_APPEND could
+have duplicated data). Fix oops in cifs_lookup. Workaround problem
+mounting to OS/400 Netserve. Fix oops in cifs_get_tcp_session.
+Disable use of server inode numbers when server only
+partially supports them (e.g. for one server querying inode numbers on
+FindFirst fails but QPathInfo queries works). Fix oops with dfs in 
+cifs_put_smb_ses. Fix mmap to work on directio mounts (needed
+for OpenOffice when on forcedirectio mount e.g.)
+
+Version 1.60
+-------------
+Fix memory leak in reconnect.  Fix oops in DFS mount error path.
+Set s_maxbytes to smaller (the max that vfs can handle) so that
+sendfile will now work over cifs mounts again.  Add noforcegid
+and noforceuid mount parameters. Fix small mem leak when using
+ntlmv2. Fix 2nd mount to same server but with different port to
+be allowed (rather than reusing the 1st port) - only when the
+user explicitly overrides the port on the 2nd mount.
+
+Version 1.59
+------------
+Client uses server inode numbers (which are persistent) rather than
+client generated ones by default (mount option "serverino" turned
+on by default if server supports it).  Add forceuid and forcegid
+mount options (so that when negotiating unix extensions specifying
+which uid mounted does not immediately force the server's reported
+uids to be overridden).  Add support for scope mount parm. Improve
+hard link detection to use same inode for both.  Do not set
+read-only dos attribute on directories (for chmod) since Windows
+explorer special cases this attribute bit for directories for
+a different purpose.
+
+Version 1.58
+------------
+Guard against buffer overruns in various UCS-2 to UTF-8 string conversions
+when the UTF-8 string is composed of unusually long (more than 4 byte) converted
+characters. Add support for mounting root of a share which redirects immediately
+to DFS target. Convert string conversion functions from Unicode to more
+accurately mark string length before allocating memory (which may help the
+rare cases where a UTF-8 string is much larger than the UCS2 string that
+we converted from).  Fix endianness of the vcnum field used during
+session setup to distinguish multiple mounts to same server from different
+userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental
+flag to be set to 2, and mount must enable krb5 to turn on extended security).
+Performance of file create to Samba improved (posix create on lookup
+removes 1 of 2 network requests sent on file create)
+Version 1.57
+------------
+Improve support for multiple security contexts to the same server. We
+used to use the same "vcnumber" for all connections which could cause
+the server to treat subsequent connections, especially those that
+are authenticated as guest, as reconnections, invalidating the earlier
+user's smb session.  This fix allows cifs to mount multiple times to the
+same server with different userids without risking invalidating earlier
+established security contexts.  fsync now sends SMB Flush operation
+to better ensure that we wait for server to write all of the data to
+server disk (not just write it over the network).  Add new mount
+parameter to allow user to disable sending the (slow) SMB flush on
+fsync if desired (fsync still flushes all cached write data to the server).
+Posix file open support added (turned off after one attempt if server
+fails to support it properly, as with Samba server versions prior to 3.3.2)
+Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too
+little memory for the "nativeFileSystem" field returned by the server
+during mount).  Endian convert inode numbers if necessary (makes it easier
+to compare inode numbers on network files from big endian systems). 
+
+Version 1.56
+------------
+Add "forcemandatorylock" mount option to allow user to use mandatory
+rather than posix (advisory) byte range locks, even though server would
+support posix byte range locks.  Fix query of root inode when prefixpath
+specified and user does not have access to query information about the
+top of the share.  Fix problem in 2.6.28 resolving DFS paths to
+Samba servers (worked to Windows).  Fix rmdir so that pending search
+(readdir) requests do not get invalid results which include the now
+removed directory.  Fix oops in cifs_dfs_ref.c when prefixpath is not reachable
+when using DFS.  Add better file create support to servers which support
+the CIFS POSIX protocol extensions (this adds support for new flags
+on create, and improves semantics for write of locked ranges).
+
+Version 1.55
+------------
+Various fixes to make delete of open files behavior more predictable
+(when delete of an open file fails we mark the file as "delete-on-close"
+in a way that more servers accept, but only if we can first rename the
+file to a temporary name).  Add experimental support for more safely
+handling fcntl(F_SETLEASE).  Convert cifs to using blocking tcp
+sends, and also let tcp autotune the socket send and receive buffers.
+This reduces the number of EAGAIN errors returned by TCP/IP in
+high stress workloads (and the number of retries on socket writes
+when sending large SMBWriteX requests).  Fix case in which a portion of
+data can in some cases not get written to the file on the server before the
+file is closed.  Fix DFS parsing to properly handle path consumed field,
+and to handle certain codepage conversions better.  Fix mount and
+umount race that can cause oops in mount or umount or reconnect.
+
+Version 1.54
+------------
+Fix premature write failure on congested networks (we would give up
+on EAGAIN from the socket too quickly on large writes).
+Cifs_mkdir and cifs_create now respect the setgid bit on parent dir.
+Fix endian problems in acl (mode from/to cifs acl) on bigendian
+architectures.  Fix problems with preserving timestamps on copying open
+files (e.g. "cp -a") to Windows servers.  For mkdir and create honor setgid bit
+on parent directory when server supports Unix Extensions but not POSIX
+create. Update cifs.upcall version to handle new Kerberos sec flags
+(this requires update of cifs.upcall program from Samba).  Fix memory leak
+on dns_upcall (resolving DFS referralls).  Fix plain text password
+authentication (requires setting SecurityFlags to 0x30030 to enable
+lanman and plain text though).  Fix writes to be at correct offset when
+file is open with O_APPEND and file is on a directio (forcediretio) mount.
+Fix bug in rewinding readdir directory searches.  Add nodfs mount option.
+
+Version 1.53
+------------
+DFS support added (Microsoft Distributed File System client support needed
+for referrals which enable a hierarchical name space among servers).
+Disable temporary caching of mode bits to servers which do not support
+storing of mode (e.g. Windows servers, when client mounts without cifsacl
+mount option) and add new "dynperm" mount option to enable temporary caching
+of mode (enable old behavior).  Fix hang on mount caused when server crashes
+tcp session during negotiate protocol.
+
+Version 1.52
+------------
+Fix oops on second mount to server when null auth is used.
+Enable experimental Kerberos support.  Return writebehind errors on flush
+and sync so that events like out of disk space get reported properly on
+cached files. Fix setxattr failure to certain Samba versions. Fix mount
+of second share to disconnected server session (autoreconnect on this).
+Add ability to modify cifs acls for handling chmod (when mounted with
+cifsacl flag). Fix prefixpath path separator so we can handle mounts
+with prefixpaths longer than one directory (one path component) when
+mounted to Windows servers.  Fix slow file open when cifsacl
+enabled. Fix memory leak in FindNext when the SMB call returns -EBADF.
+
+
+Version 1.51
+------------
+Fix memory leak in statfs when mounted to very old servers (e.g.
+Windows 9x).  Add new feature "POSIX open" which allows servers
+which support the current POSIX Extensions to provide better semantics
+(e.g. delete for open files opened with posix open).  Take into
+account umask on posix mkdir not just older style mkdir.  Add
+ability to mount to IPC$ share (which allows CIFS named pipes to be
+opened, read and written as if they were files).  When 1st tree
+connect fails (e.g. due to signing negotiation failure) fix
+leak that causes cifsd not to stop and rmmod to fail to cleanup
+cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on
+bigendian architectures. Fix possible memory corruption when
+EAGAIN returned on kern_recvmsg. Return better error if server
+requires packet signing but client has disabled it. When mounted
+with cifsacl mount option - mode bits are approximated based
+on the contents of the ACL of the file or directory. When cifs
+mount helper is missing convert make sure that UNC name 
+has backslash (not forward slash) between ip address of server
+and the share name.
+
+Version 1.50
+------------
+Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
+done with "serverino" mount option).  Add support for POSIX Unlink
+(helps with certain sharing violation cases when server such as
+Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix"
+mount option to allow disabling the CIFS Unix Extensions for just
+that mount. Fix hang on spinlock in find_writable_file (race when
+reopening file after session crash).  Byte range unlock request to
+windows server could unlock more bytes (on server copy of file)
+than intended if start of unlock request is well before start of
+a previous byte range lock that we issued.
+
+Version 1.49
+------------
+IPv6 support.  Enable ipv6 addresses to be passed on mount (put the ipv6
+address after the "ip=" mount option, at least until mount.cifs is fixed to
+handle DNS host to ipv6 name translation).  Accept override of uid or gid
+on mount even when Unix Extensions are negotiated (it used to be ignored
+when Unix Extensions were ignored).  This allows users to override the
+default uid and gid for files when they are certain that the uids or
+gids on the server do not match those of the client.  Make "sec=none"
+mount override username (so that null user connection is attempted)
+to match what documentation said. Support for very large reads, over 127K,
+available to some newer servers (such as Samba 3.0.26 and later but
+note that it also requires setting CIFSMaxBufSize at module install
+time to a larger value which may hurt performance in some cases).
+Make sign option force signing (or fail if server does not support it).
+
+Version 1.48
+------------
+Fix mtime bouncing around from local idea of last write times to remote time.
+Fix hang (in i_size_read) when simultaneous size update of same remote file
+on smp system corrupts sequence number. Do not reread unnecessarily partial page
+(which we are about to overwrite anyway) when writing out file opened rw.
+When DOS attribute of file on non-Unix server's file changes on the server side
+from read-only back to read-write, reflect this change in default file mode
+(we had been leaving a file's mode read-only until the inode were reloaded).
+Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute
+when archive dos attribute not set and we are changing mode back to writeable
+on server which does not support the Unix Extensions).  Remove read only dos
+attribute on chmod when adding any write permission (ie on any of
+user/group/other (not all of user/group/other ie  0222) when
+mounted to windows.  Add support for POSIX MkDir (slight performance
+enhancement and eliminates the network race between the mkdir and set 
+path info of the mode).
+
+
+Version 1.47
+------------
+Fix oops in list_del during mount caused by unaligned string.
+Fix file corruption which could occur on some large file
+copies caused by writepages page i/o completion bug.
+Seek to SEEK_END forces check for update of file size for non-cached
+files. Allow file size to be updated on remote extend of locally open,
+non-cached file.  Fix reconnect to newer Samba servers (or other servers
+which support the CIFS Unix/POSIX extensions) so that we again tell the
+server the Unix/POSIX cifs capabilities which we support (SetFSInfo).
+Add experimental support for new POSIX Open/Mkdir (which returns
+stat information on the open, and allows setting the mode).
+
+Version 1.46
+------------
+Support deep tree mounts.  Better support OS/2, Win9x (DOS) time stamps.
+Allow null user to be specified on mount ("username="). Do not return
+EINVAL on readdir when filldir fails due to overwritten blocksize
+(fixes FC problem).  Return error in rename 2nd attempt retry (ie report
+if rename by handle also fails, after rename by path fails, we were
+not reporting whether the retry worked or not). Fix NTLMv2 to
+work to Windows servers (mount with option "sec=ntlmv2").
+
+Version 1.45
+------------
+Do not time out lockw calls when using posix extensions. Do not
+time out requests if server still responding reasonably fast
+on requests on other threads.  Improve POSIX locking emulation,
+(lock cancel now works, and unlock of merged range works even
+to Windows servers now).  Fix oops on mount to lanman servers
+(win9x, os/2 etc.) when null password.  Do not send listxattr
+(SMB to query all EAs) if nouser_xattr specified.  Fix SE Linux
+problem (instantiate inodes/dentries in right order for readdir).
+
+Version 1.44
+------------
+Rewritten sessionsetup support, including support for legacy SMB
+session setup needed for OS/2 and older servers such as Windows 95 and 98.
+Fix oops on ls to OS/2 servers.  Add support for level 1 FindFirst
+so we can do search (ls etc.) to OS/2.  Do not send NTCreateX
+or recent levels of FindFirst unless server says it supports NT SMBs
+(instead use legacy equivalents from LANMAN dialect). Fix to allow
+NTLMv2 authentication support (now can use stronger password hashing
+on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
+Allow override of global cifs security flags on mount via "sec=" option(s).
+
+Version 1.43
+------------
+POSIX locking to servers which support CIFS POSIX Extensions
+(disabled by default controlled by proc/fs/cifs/Experimental).
+Handle conversion of long share names (especially Asian languages)
+to Unicode during mount. Fix memory leak in sess struct on reconnect.
+Fix rare oops after acpi suspend.  Fix O_TRUNC opens to overwrite on
+cifs open which helps rare case when setpathinfo fails or server does
+not support it. 
+
+Version 1.42
+------------
+Fix slow oplock break when mounted to different servers at the same time and
+the tids match and we try to find matching fid on wrong server. Fix read
+looping when signing required by server (2.6.16 kernel only). Fix readdir
+vs. rename race which could cause each to hang. Return . and .. even
+if server does not.  Allow searches to skip first three entries and
+begin at any location. Fix oops in find_writeable_file.
+
+Version 1.41
+------------
+Fix NTLMv2 security (can be enabled in /proc/fs/cifs) so customers can
+configure stronger authentication.  Fix sfu symlinks so they can
+be followed (not just recognized).  Fix wraparound of bcc on
+read responses when buffer size over 64K and also fix wrap of
+max smb buffer size when CIFSMaxBufSize over 64K.  Fix oops in
+cifs_user_read and cifs_readpages (when EAGAIN on send of smb
+on socket is returned over and over).  Add POSIX (advisory) byte range
+locking support (requires server with newest CIFS UNIX Extensions
+to the protocol implemented). Slow down negprot slightly in port 139
+RFC1001 case to give session_init time on buggy servers.
+
+Version 1.40
+------------
+Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance
+of readpages by eliminating one extra memcpy. Allow update of file size
+from remote server even if file is open for write as long as mount is
+directio.  Recognize share mode security and send NTLM encrypted password
+on tree connect if share mode negotiated.
+
+Version 1.39
+------------
+Defer close of a file handle slightly if pending writes depend on that handle
+(this reduces the EBADF bad file handle errors that can be logged under heavy
+stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 
+Fix SFU style symlinks and mknod needed for servers which do not support the
+CIFS Unix Extensions.  Fix setfacl/getfacl on bigendian. Timeout negative
+dentries so files that the client sees as deleted but that later get created
+on the server will be recognized.  Add client side permission check on setattr.
+Timeout stuck requests better (where server has never responded or sent corrupt
+responses)
+
+Version 1.38
+------------
+Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
+to be smaller at first (but increasing) so large write performance performance
+over GigE is better.  Do not hang thread on illegal byte range lock response
+from Windows (Windows can send an RFC1001 size which does not match smb size) by
+allowing an SMBs TCP length to be up to a few bytes longer than it should be.
+wsize and rsize can now be larger than negotiated buffer size if server
+supports large readx/writex, even when directio mount flag not specified.
+Write size will in many cases now be 16K instead of 4K which greatly helps
+file copy performance on lightly loaded networks.  Fix oops in dnotify
+when experimental config flag enabled. Make cifsFYI more granular.
+
+Version 1.37
+------------
+Fix readdir caching when unlink removes file in current search buffer,
+and this is followed by a rewind search to just before the deleted entry.
+Do not attempt to set ctime unless atime and/or mtime change requested
+(most servers throw it away anyway). Fix length check of received smbs
+to be more accurate. Fix big endian problem with mapchars mount option,
+and with a field returned by statfs.
+
+Version 1.36
+------------
+Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
+For these older servers, add option for passing netbios name of server in
+on mount (servernetbiosname).  Add suspend support for power management, to
+avoid cifsd thread preventing software suspend from working.
+Add mount option for disabling the default behavior of sending byte range lock
+requests to the server (necessary for certain applications which break with
+mandatory lock behavior such as Evolution), and also mount option for
+requesting case insensitive matching for path based requests (requesting
+case sensitive is the default).
+
+Version 1.35
+------------
+Add writepage performance improvements.  Fix path name conversions
+for long filenames on mounts which were done with "mapchars" mount option
+specified.  Ensure multiplex ids do not collide.  Fix case in which 
+rmmod can oops if done soon after last unmount.  Fix truncated
+search (readdir) output when resume filename was a long filename.
+Fix filename conversion when mapchars mount option was specified and
+filename was a long filename.
+
+Version 1.34
+------------
+Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
+Do not oops if root user kills cifs oplock kernel thread or
+kills the cifsd thread (NB: killing the cifs kernel threads is not
+recommended, unmount and rmmod cifs will kill them when they are
+no longer needed).  Fix readdir to ASCII servers (ie older servers
+which do not support Unicode) and also require asterisk.
+Fix out of memory case in which data could be written one page
+off in the page cache.
+
+Version 1.33
+------------
+Fix caching problem, in which readdir of directory containing a file
+which was cached could cause the file's time stamp to be updated
+without invalidating the readahead data (so we could get stale
+file data on the client for that file even as the server copy changed).
+Cleanup response processing so cifsd can not loop when abnormally
+terminated.
+
+
+Version 1.32
+------------
+Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
+transact response for an SMB request and search entry split across two frames.
+Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
+as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
+unless server explicitly claims to support them in CIFS Unix extensions
+POSIX ACL capability bit. Fix packet signing when multiuser mounting with
+different users from the same client to the same server. Fix oops in
+cifs_close. Add mount option for remapping reserved characters in
+filenames (also allow recognizing files with created by SFU which have any
+of these seven reserved characters, except backslash, to be recognized).
+Fix invalid transact2 message (we were sometimes trying to interpret
+oplock breaks as SMB responses). Add ioctl for checking that the
+current uid matches the uid of the mounter (needed by umount.cifs).
+Reduce the number of large buffer allocations in cifs response processing
+(significantly reduces memory pressure under heavy stress with multiple
+processes accessing the same server at the same time).
+
+Version 1.31
+------------
+Fix updates of DOS attributes and time fields so that files on NT4 servers
+do not get marked delete on close. Display sizes of cifs buffer pools in
+cifs stats. Fix oops in unmount when cifsd thread being killed by 
+shutdown. Add generic readv/writev and aio support. Report inode numbers 
+consistently in readdir and lookup (when serverino mount option is
+specified use the inode number that the server reports - for both lookup
+and readdir, otherwise by default the locally generated inode number is used
+for inodes created in either path since servers are not always able to 
+provide unique inode numbers when exporting multiple volumes from under one
+sharename).
+
+Version 1.30
+------------
+Allow new nouser_xattr mount parm to disable xattr support for user namespace.
+Do not flag user_xattr mount parm in dmesg.  Retry failures setting file time  
+(mostly affects NT4 servers) by retry with handle based network operation. 
+Add new POSIX Query FS Info for returning statfs info more accurately.
+Handle passwords with multiple commas in them.
+
+Version 1.29
+------------
+Fix default mode in sysfs of cifs module parms.  Remove old readdir routine.
+Fix capabilities flags for large readx so as to allow reads larger than 64K.
+
+Version 1.28
+------------
+Add module init parm for large SMB buffer size (to allow it to be changed
+from its default of 16K) which is especially useful for large file copy
+when mounting with the directio mount option. Fix oops after 
+returning from mount when experimental ExtendedSecurity enabled and
+SpnegoNegotiated returning invalid error. Fix case to retry better when 
+peek returns from 1 to 3 bytes on socket which should have more data.
+Fixed path based calls (such as cifs lookup) to handle path names
+longer than 530 (now can handle PATH_MAX). Fix pass through authentication
+from Samba server to DC (Samba required dummy LM password).
+
+Version 1.27
+------------
+Turn off DNOTIFY (directory change notification support) by default
+(unless built with the experimental flag) to fix hang with KDE
+file browser. Fix DNOTIFY flag mappings.  Fix hang (in wait_event
+waiting on an SMB response) in SendReceive when session dies but
+reconnects quickly from another task.  Add module init  parms for
+minimum number of large and small network buffers in the buffer pools,
+and for the maximum number of simultaneous requests.
+
+Version 1.26
+------------
+Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later
+and other POSIX CIFS compliant servers.  Fix error mapping for getfacl 
+to EOPNOTSUPP when server does not support posix acls on the wire. Fix 
+improperly zeroed buffer in CIFS Unix extensions set times call. 
+
+Version 1.25
+------------
+Fix internationalization problem in cifs readdir with filenames that map to 
+longer UTF-8 strings than the string on the wire was in Unicode.  Add workaround
+for readdir to netapp servers. Fix search rewind (seek into readdir to return 
+non-consecutive entries).  Do not do readdir when server negotiates 
+buffer size to small to fit filename. Add support for reading POSIX ACLs from
+the server (add also acl and noacl mount options).
+
+Version 1.24
+------------
+Optionally allow using server side inode numbers, rather than client generated
+ones by specifying mount option "serverino" - this is required for some apps
+to work which double check hardlinked files and have persistent inode numbers.
+
+Version 1.23
+------------
+Multiple bigendian fixes. On little endian systems (for reconnect after
+network failure) fix tcp session reconnect code so we do not try first
+to reconnect on reverse of port 445. Treat reparse points (NTFS junctions)
+as directories rather than symlinks because we can do follow link on them.
+
+Version 1.22
+------------
+Add config option to enable XATTR (extended attribute) support, mapping
+xattr names in the "user." namespace space to SMB/CIFS EAs. Lots of
+minor fixes pointed out by the Stanford SWAT checker (mostly missing
+or out of order NULL pointer checks in little used error paths).
+
+Version 1.21
+------------
+Add new mount parm to control whether mode check (generic_permission) is done
+on the client.  If Unix extensions are enabled and the uids on the client
+and server do not match, client permission checks are meaningless on
+server uids that do not exist on the client (this does not affect the
+normal ACL check which occurs on the server).  Fix default uid
+on mknod to match create and mkdir. Add optional mount parm to allow
+override of the default uid behavior (in which the server sets the uid
+and gid of newly created files). Normally for network filesystem mounts
+user want the server to set the uid/gid on newly created files (rather than 
+using uid of the client processes you would in a local filesystem).
+
+Version 1.20
+------------
+Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps
+info into /proc/fs/cifs/DebugData.  Fix oops in rare oops in readdir 
+(in build_wildcard_path_from_dentry).  Fix mknod to pass type field
+(block/char/fifo) properly.  Remove spurious mount warning log entry when
+credentials passed as mount argument. Set major/minor device number in
+inode for block and char devices when unix extensions enabled.
+
+Version 1.19
+------------
+Fix /proc/fs/cifs/Stats and DebugData display to handle larger
+amounts of return data. Properly limit requests to MAX_REQ (50
+is the usual maximum active multiplex SMB/CIFS requests per server).
+Do not kill cifsd (and thus hurt the other SMB session) when more than one
+session to the same server (but with different userids) exists and one
+of the two user's smb sessions is being removed while leaving the other.
+Do not loop reconnecting in cifsd demultiplex thread when admin
+kills the thread without going through unmount.
+
+Version 1.18
+------------
+Do not rename hardlinked files (since that should be a noop). Flush
+cached write behind data when reopening a file after session abend,
+except when already in write. Grab per socket sem during reconnect 
+to avoid oops in sendmsg if overlapping with reconnect. Do not
+reset cached inode file size on readdir for files open for write on 
+client.
+
+
+Version 1.17
+------------
+Update number of blocks in file so du command is happier (in Linux a fake
+blocksize of 512 is required for calculating number of blocks in inode).
+Fix prepare write of partial pages to read in data from server if possible.
+Fix race on tcpStatus field between unmount and reconnection code, causing
+cifsd process sometimes to hang around forever. Improve out of memory
+checks in cifs_filldir
+
+Version 1.16
+------------
+Fix incorrect file size in file handle based setattr on big endian hardware.
+Fix oops in build_path_from_dentry when out of memory.  Add checks for invalid
+and closing file structs in writepage/partialpagewrite.  Add statistics
+for each mounted share (new menuconfig option). Fix endianness problem in
+volume information displayed in /proc/fs/cifs/DebugData (only affects
+affects big endian architectures). Prevent renames while constructing
+path names for open, mkdir and rmdir.
+
+Version 1.15
+------------
+Change to mempools for alloc smb request buffers and multiplex structs
+to better handle low memory problems (and potential deadlocks).
+
+Version 1.14
+------------
+Fix incomplete listings of large directories on Samba servers when Unix
+extensions enabled.  Fix oops when smb_buffer can not be allocated. Fix
+rename deadlock when writing out dirty pages at same time.
+
+Version 1.13
+------------
+Fix open of files in which O_CREATE can cause the mode to change in
+some cases. Fix case in which retry of write overlaps file close.
+Fix PPC64 build error.  Reduce excessive stack usage in smb password
+hashing. Fix overwrite of Linux user's view of file mode to Windows servers.
+
+Version 1.12
+------------
+Fixes for large file copy, signal handling, socket retry, buffer
+allocation and low memory situations.
+
+Version 1.11
+------------
+Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize)
+also now allowing support for specifying client netbiosname.  NT4 support added.
+
+Version 1.10
+------------
+Fix reconnection (and certain failed mounts) to properly wake up the
+blocked users thread so it does not seem hung (in some cases was blocked
+until the cifs receive timeout expired). Fix spurious error logging
+to kernel log when application with open network files killed. 
+
+Version 1.09
+------------
+Fix /proc/fs module unload warning message (that could be logged
+to the kernel log). Fix intermittent failure in connectathon
+test7 (hardlink count not immediately refreshed in case in which
+inode metadata can be incorrectly kept cached when time near zero)
+
+Version 1.08
+------------
+Allow file_mode and dir_mode (specified at mount time) to be enforced
+locally (the server already enforced its own ACLs too) for servers
+that do not report the correct mode (do not support the 
+CIFS Unix Extensions).
+
+Version 1.07
+------------
+Fix some small memory leaks in some unmount error paths. Fix major leak
+of cache pages in readpages causing multiple read oriented stress
+testcases (including fsx, and even large file copy) to fail over time. 
+
+Version 1.06
+------------
+Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server.
+This allows files that differ only in case and improves performance of file
+creation and file open to such servers.  Fix semaphore conflict which causes 
+slow delete of open file to Samba (which unfortunately can cause an oplock
+break to self while vfs_unlink held i_sem) which can hang for 20 seconds.
+
+Version 1.05
+------------
+fixes to cifs_readpages for fsx test case
+
+Version 1.04
+------------
+Fix caching data integrity bug when extending file size especially when no
+oplock on file.  Fix spurious logging of valid already parsed mount options
+that are parsed outside of the cifs vfs such as nosuid.
+
+
+Version 1.03
+------------
+Connect to server when port number override not specified, and tcp port
+unitialized.  Reset search to restart at correct file when kernel routine
+filldir returns error during large directory searches (readdir). 
+
+Version 1.02
+------------
+Fix caching problem when files opened by multiple clients in which 
+page cache could contain stale data, and write through did
+not occur often enough while file was still open when read ahead
+(read oplock) not allowed.  Treat "sep=" when first mount option
+as an override of comma as the default separator between mount
+options. 
+
+Version 1.01
+------------
+Allow passwords longer than 16 bytes. Allow null password string.
+
+Version 1.00
+------------
+Gracefully clean up failed mounts when attempting to mount to servers such as
+Windows 98 that terminate tcp sessions during protocol negotiation.  Handle
+embedded commas in mount parsing of passwords.
+
+Version 0.99
+------------
+Invalidate local inode cached pages on oplock break and when last file
+instance is closed so that the client does not continue using stale local
+copy rather than later modified server copy of file.  Do not reconnect
+when server drops the tcp session prematurely before negotiate
+protocol response.  Fix oops in reopen_file when dentry freed.  Allow
+the support for CIFS Unix Extensions to be disabled via proc interface.
+
+Version 0.98
+------------
+Fix hang in commit_write during reconnection of open files under heavy load.
+Fix unload_nls oops in a mount failure path. Serialize writes to same socket
+which also fixes any possible races when cifs signatures are enabled in SMBs
+being sent out of signature sequence number order.    
+
+Version 0.97
+------------
+Fix byte range locking bug (endian problem) causing bad offset and
+length.
+
+Version 0.96
+------------
+Fix oops (in send_sig) caused by CIFS unmount code trying to
+wake up the demultiplex thread after it had exited. Do not log
+error on harmless oplock release of closed handle.
+
+Version 0.95
+------------
+Fix unsafe global variable usage and password hash failure on gcc 3.3.1
+Fix problem reconnecting secondary mounts to same server after session 
+failure.  Fix invalid dentry - race in mkdir when directory gets created
+by another client between the lookup and mkdir.
+Version 0.94
+------------
+Fix to list processing in reopen_files. Fix reconnection when server hung
+but tcpip session still alive.  Set proper timeout on socket read.
+
+Version 0.93
+------------
+Add missing mount options including iocharset.  SMP fixes in write and open. 
+Fix errors in reconnecting after TCP session failure.  Fix module unloading
+of default nls codepage
+
+Version 0.92
+------------
+Active smb transactions should never go negative (fix double FreeXid). Fix
+list processing in file routines. Check return code on kmalloc in open.
+Fix spinlock usage for SMP.
+
+Version 0.91
+------------
+Fix oops in reopen_files when invalid dentry. drop dentry on server rename 
+and on revalidate errors. Fix cases where pid is now tgid.  Fix return code
+on create hard link when server does not support them. 
+
+Version 0.90
+------------
+Fix scheduling while atomic error in getting inode info on newly created file. 
+Fix truncate of existing files opened with O_CREAT but not O_TRUNC set.
+
+Version 0.89
+------------
+Fix oops on write to dead tcp session. Remove error log write for case when file open
+O_CREAT but not O_EXCL
+
+Version 0.88
+------------
+Fix non-POSIX behavior on rename of open file and delete of open file by taking 
+advantage of trans2 SetFileInfo rename facility if available on target server.
+Retry on ENOSPC and EAGAIN socket errors.
+
+Version 0.87
+------------
+Fix oops on big endian readdir.  Set blksize to be even power of two (2**blkbits) to fix
+allocation size miscalculation. After oplock token lost do not read through
+cache. 
+
+Version 0.86
+------------
+Fix oops on empty file readahead.  Fix for file size handling for locally cached files.
+
+Version 0.85
+------------
+Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files
+during auto reconnection to server after server recovered from failure.
+
+Version 0.84
+------------
+Finish support for Linux 2.5 open/create changes, which removes the
+redundant NTCreate/QPathInfo/close that was sent during file create.
+Enable oplock by default. Enable packet signing by default (needed to 
+access many recent Windows servers)
+
+Version 0.83
+------------
+Fix oops when mounting to long server names caused by inverted parms to kmalloc.
+Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled
+we will choose a cifs user session (smb uid) that better matches the local
+uid if a) the mount uid does not match the current uid and b) we have another
+session to the same server (ip address) for a different mount which
+matches the current local uid.
+
+Version 0.82
+------------
+Add support for mknod of block or character devices.  Fix oplock
+code (distributed caching) to properly send response to oplock
+break from server.
+
+Version 0.81
+------------
+Finish up CIFS packet digital signing for the default
+NTLM security case. This should help Windows 2003
+network interoperability since it is common for
+packet signing to be required now. Fix statfs (stat -f)
+which recently started returning errors due to 
+invalid value (-1 instead of 0) being set in the
+struct kstatfs f_ffiles field.
+
+Version 0.80
+-----------
+Fix oops on stopping oplock thread when removing cifs when
+built as module.
+
+Version 0.79
+------------
+Fix mount options for ro (readonly), uid, gid and file and directory mode. 
+
+Version 0.78
+------------
+Fix errors displayed on failed mounts to be more understandable.
+Fixed various incorrect or misleading smb to posix error code mappings.
+
+Version 0.77
+------------
+Fix display of NTFS DFS junctions to display as symlinks.
+They are the network equivalent.  Fix oops in 
+cifs_partialpagewrite caused by missing spinlock protection
+of openfile linked list.  Allow writebehind caching errors to 
+be returned to the application at file close.
+
+Version 0.76
+------------
+Clean up options displayed in /proc/mounts by show_options to
+be more consistent with other filesystems.
+
+Version 0.75
+------------
+Fix delete of readonly file to Windows servers.  Reflect
+presence or absence of read only dos attribute in mode
+bits for servers that do not support CIFS Unix extensions.
+Fix shortened results on readdir of large directories to
+servers supporting CIFS Unix extensions (caused by
+incorrect resume key).
+
+Version 0.74
+------------
+Fix truncate bug (set file size) that could cause hangs e.g. running fsx
+
+Version 0.73
+------------
+unload nls if mount fails.
+
+Version 0.72
+------------
+Add resume key support to search (readdir) code to workaround
+Windows bug.  Add /proc/fs/cifs/LookupCacheEnable which
+allows disabling caching of attribute information for
+lookups.
+
+Version 0.71
+------------
+Add more oplock handling (distributed caching code).  Remove
+dead code.  Remove excessive stack space utilization from
+symlink routines.
+
+Version 0.70
+------------
+Fix oops in get dfs referral (triggered when null path sent in to
+mount).  Add support for overriding rsize at mount time.
+
+Version 0.69
+------------
+Fix buffer overrun in readdir which caused intermittent kernel oopses.
+Fix writepage code to release kmap on write data.  Allow "-ip=" new 
+mount option to be passed in on parameter distinct from the first part
+(server name portion of) the UNC name.  Allow override of the
+tcp port of the target server via new mount option "-port="  
+
+Version 0.68
+------------
+Fix search handle leak on rewind.  Fix setuid and gid so that they are 
+reflected in the local inode immediately.  Cleanup of whitespace
+to make 2.4 and 2.5 versions more consistent.
+
+
+Version 0.67
+------------
+Fix signal sending so that captive thread (cifsd) exits on umount 
+(which was causing the warning in kmem_cache_free of the request buffers
+at rmmod time).  This had broken as a sideeffect of the recent global
+kernel change to daemonize.  Fix memory leak in readdir code which
+showed up in "ls -R" (and applications that did search rewinding).
+
+Version 0.66
+------------
+Reconnect tids and fids after session reconnection (still do not
+reconnect byte range locks though).  Fix problem caching
+lookup information for directory inodes, improving performance,
+especially in deep directory trees.  Fix various build warnings.
+
+Version 0.65
+------------
+Finish fixes to commit write for caching/readahead consistency.  fsx 
+now works to Samba servers.  Fix oops caused when readahead
+was interrupted by a signal.
+
+Version 0.64
+------------
+Fix data corruption (in partial page after truncate) that caused fsx to
+fail to Windows servers.  Cleaned up some extraneous error logging in
+common error paths.  Add generic sendfile support.
+
+Version 0.63
+------------
+Fix memory leak in AllocMidQEntry.
+Finish reconnection logic, so connection with server can be dropped
+(or server rebooted) and the cifs client will reconnect.  
+
+Version 0.62
+------------
+Fix temporary socket leak when bad userid or password specified 
+(or other SMBSessSetup failure).  Increase maximum buffer size to slightly
+over 16K to allow negotiation of up to Samba and Windows server default read 
+sizes.  Add support for readpages
+
+Version 0.61
+------------
+Fix oops when username not passed in on mount.  Extensive fixes and improvements
+to error logging (strip redundant newlines, change debug macros to ensure newline
+passed in and to be more consistent).  Fix writepage wrong file handle problem,
+a readonly file handle could be incorrectly used to attempt to write out
+file updates through the page cache to multiply open files.  This could cause
+the iozone benchmark to fail on the fwrite test. Fix bug mounting two different
+shares to the same Windows server when using different usernames
+(doing this to Samba servers worked but Windows was rejecting it) - now it is
+possible to use different userids when connecting to the same server from a
+Linux client. Fix oops when treeDisconnect called during unmount on
+previously freed socket.
+
+Version 0.60
+------------
+Fix oops in readpages caused by not setting address space operations in inode in 
+rare code path. 
+
+Version 0.59
+------------
+Includes support for deleting of open files and renaming over existing files (per POSIX
+requirement).  Add readlink support for Windows junction points (directory symlinks).
+
+Version 0.58
+------------
+Changed read and write to go through pagecache. Added additional address space operations.
+Memory mapped operations now working.
+
+Version 0.57
+------------
+Added writepage code for additional memory mapping support.  Fixed leak in xids causing
+the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on 
+every stat call.  Additional formatting cleanup. 
+
+Version 0.56
+------------
+Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version.  Formatting cleanup.   
+
+Version 0.55
+------------
+Fixes from Zwane Mwaikambo for adding missing return code checking in a few places.
+Also included a modified version of his fix to protect global list manipulation of
+the smb session and tree connection and mid related global variables.
+
+Version 0.54
+------------
+Fix problem with captive thread hanging around at unmount time.  Adjust to 2.5.42-pre
+changes to superblock layout.   Remove wasteful allocation of smb buffers (now the send 
+buffer is reused for responses).  Add more oplock handling. Additional minor cleanup.
+
+Version 0.53
+------------
+More stylistic updates to better match kernel style.  Add additional statistics
+for filesystem which can be viewed via /proc/fs/cifs.  Add more pieces of NTLMv2
+and CIFS Packet Signing enablement.
+
+Version 0.52
+------------
+Replace call to sleep_on with safer wait_on_event.
+Make stylistic changes to better match kernel style recommendations.
+Remove most typedef usage (except for the PDUs themselves).
+
+Version 0.51
+------------
+Update mount so the -unc mount option is no longer required (the ip address can be specified
+in a UNC style device name.   Implementation of readpage/writepage started.
+
+Version 0.50
+------------
+Fix intermittent problem with incorrect smb header checking on badly 
+fragmented tcp responses
+
+Version 0.49
+------------
+Fixes to setting of allocation size and file size.
+
+Version 0.48
+------------
+Various 2.5.38 fixes.  Now works on 2.5.38
+
+Version 0.47
+------------
+Prepare for 2.5 kernel merge.  Remove ifdefs.
+
+Version 0.46
+------------
+Socket buffer management fixes.  Fix dual free.
+
+Version 0.45
+------------
+Various big endian fixes for hardlinks and symlinks and also for dfs.
+
+Version 0.44
+------------
+Various big endian fixes for servers with Unix extensions such as Samba
+
+Version 0.43
+------------
+Various FindNext fixes for incorrect filenames on large directory searches on big endian
+clients.  basic posix file i/o tests now work on big endian machines, not just le
+
+Version 0.42
+------------
+SessionSetup and NegotiateProtocol now work from Big Endian machines.
+Various Big Endian fixes found during testing on the Linux on 390.  Various fixes for compatibility with older
+versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7).
+
+Version 0.41
+------------
+Various minor fixes for Connectathon Posix "basic" file i/o test suite.  Directory caching fixed so hardlinked
+files now return the correct number of links on fstat as they are repeatedly linked and unlinked.
+
+Version 0.40
+------------
+Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate
+session advanced session authentication).  Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP.
+Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs
+(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos).
+
+Version 0.38
+------------
+Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable
+it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU).
+
+Version 0.37
+------------
+Rewrote much of connection and mount/unmount logic to handle bugs with
+multiple uses to same share, multiple users to same server etc.
+
+Version 0.36
+------------
+Fixed major problem with dentry corruption (missing call to dput)
+
+Version 0.35
+------------
+Rewrite of readdir code to fix bug. Various fixes for bigendian machines.
+Begin adding oplock support.  Multiusermount and oplockEnabled flags added to /proc/fs/cifs
+although corresponding function not fully implemented in the vfs yet
+
+Version 0.34
+------------
+Fixed dentry caching bug, misc. cleanup 
+
+Version 0.33
+------------
+Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes.  Now can build
+on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels.
+Support for STATUS codes (newer 32 bit NT error codes) added.  DFS support begun to be added.
+
+Version 0.32
+------------
+Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented
+and tested against Samba 2.2.5
+
+
+Version 0.31
+------------
+1) Fixed lockrange to be correct (it was one byte too short)
+
+2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly 
+show range as locked when there is a conflict with an existing lock.
+
+3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories
+in most cases.  Eventually will offer optional ability to query server for the correct perms.
+
+3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded 
+but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb
+session) 
+
+4) Fixed error logging of valid mount options
+
+5) Removed logging of password field.
+
+6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c
+and cleaned them up and made them more consistent with other cifs functions. 
+
+7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 
+(with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
+nor is the symlink support using the Unix extensions
+
+8) Started adding the readlink and follow_link code 
+
+Version 0.3 
+-----------
+Initial drop
+
diff --git a/Documentation/filesystems/cifs/README b/Documentation/filesystems/cifs/README
new file mode 100644 (file)
index 0000000..2d5622f
--- /dev/null
@@ -0,0 +1,753 @@
+The CIFS VFS support for Linux supports many advanced network filesystem 
+features such as hierarchical dfs like namespace, hardlinks, locking and more.  
+It was designed to comply with the SNIA CIFS Technical Reference (which 
+supersedes the 1992 X/Open SMB Standard) as well as to perform best practice 
+practical interoperability with Windows 2000, Windows XP, Samba and equivalent 
+servers.  This code was developed in participation with the Protocol Freedom
+Information Foundation.
+
+Please see
+  http://protocolfreedom.org/ and
+  http://samba.org/samba/PFIF/
+for more details.
+
+
+For questions or bug reports please contact:
+    sfrench@samba.org (sfrench@us.ibm.com) 
+
+Build instructions:
+==================
+For Linux 2.4:
+1) Get the kernel source (e.g.from http://www.kernel.org)
+and download the cifs vfs source (see the project page
+at http://us1.samba.org/samba/Linux_CIFS_client.html)
+and change directory into the top of the kernel directory
+then patch the kernel (e.g. "patch -p1 < cifs_24.patch") 
+to add the cifs vfs to your kernel configure options if
+it has not already been added (e.g. current SuSE and UL
+users do not need to apply the cifs_24.patch since the cifs vfs is
+already in the kernel configure menu) and then
+mkdir linux/fs/cifs and then copy the current cifs vfs files from
+the cifs download to your kernel build directory e.g.
+
+       cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs
+       
+2) make menuconfig (or make xconfig)
+3) select cifs from within the network filesystem choices
+4) save and exit
+5) make dep
+6) make modules (or "make" if CIFS VFS not to be built as a module)
+
+For Linux 2.6:
+1) Download the kernel (e.g. from http://www.kernel.org)
+and change directory into the top of the kernel directory tree
+(e.g. /usr/src/linux-2.5.73)
+2) make menuconfig (or make xconfig)
+3) select cifs from within the network filesystem choices
+4) save and exit
+5) make
+
+
+Installation instructions:
+=========================
+If you have built the CIFS vfs as module (successfully) simply
+type "make modules_install" (or if you prefer, manually copy the file to
+the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
+
+If you have built the CIFS vfs into the kernel itself, follow the instructions
+for your distribution on how to install a new kernel (usually you
+would simply type "make install").
+
+If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on 
+the CIFS VFS web site) copy it to the same directory in which mount.smbfs and 
+similar files reside (usually /sbin).  Although the helper software is not  
+required, mount.cifs is recommended.  Eventually the Samba 3.0 utility program 
+"net" may also be helpful since it may someday provide easier mount syntax for
+users who are used to Windows e.g.
+       net use <mount point> <UNC name or cifs URL>
+Note that running the Winbind pam/nss module (logon service) on all of your
+Linux clients is useful in mapping Uids and Gids consistently across the
+domain to the proper network user.  The mount.cifs mount helper can be
+trivially built from Samba 3.0 or later source e.g. by executing:
+
+       gcc samba/source/client/mount.cifs.c -o mount.cifs
+
+If cifs is built as a module, then the size and number of network buffers
+and maximum number of simultaneous requests to one server can be configured.
+Changing these from their defaults is not recommended. By executing modinfo
+       modinfo kernel/fs/cifs/cifs.ko
+on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made
+at module initialization time (by running insmod cifs.ko) can be seen.
+
+Allowing User Mounts
+====================
+To permit users to mount and unmount over directories they own is possible
+with the cifs vfs.  A way to enable such mounting is to mark the mount.cifs
+utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to 
+umount shares they mount requires
+1) mount.cifs version 1.4 or later
+2) an entry for the share in /etc/fstab indicating that a user may
+unmount it e.g.
+//server/usersharename  /mnt/username cifs user 0 0
+
+Note that when the mount.cifs utility is run suid (allowing user mounts), 
+in order to reduce risks, the "nosuid" mount flag is passed in on mount to
+disallow execution of an suid program mounted on the remote target.
+When mount is executed as root, nosuid is not passed in by default,
+and execution of suid programs on the remote target would be enabled
+by default. This can be changed, as with nfs and other filesystems, 
+by simply specifying "nosuid" among the mount options. For user mounts 
+though to be able to pass the suid flag to mount requires rebuilding 
+mount.cifs with the following flag: 
+        gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs
+
+There is a corresponding manual page for cifs mounting in the Samba 3.0 and
+later source tree in docs/manpages/mount.cifs.8 
+
+Allowing User Unmounts
+======================
+To permit users to ummount directories that they have user mounted (see above),
+the utility umount.cifs may be used.  It may be invoked directly, or if 
+umount.cifs is placed in /sbin, umount can invoke the cifs umount helper
+(at least for most versions of the umount utility) for umount of cifs
+mounts, unless umount is invoked with -i (which will avoid invoking a umount
+helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked
+as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions
+allow adding entries to a file to the /etc/permissions file to achieve the
+equivalent suid effect).  For this utility to succeed the target path
+must be a cifs mount, and the uid of the current user must match the uid
+of the user who mounted the resource.
+
+Also note that the customary way of allowing user mounts and unmounts is 
+(instead of using mount.cifs and unmount.cifs as suid) to add a line
+to the file /etc/fstab for each //server/share you wish to mount, but
+this can become unwieldy when potential mount targets include many
+or  unpredictable UNC names.
+
+Samba Considerations 
+==================== 
+To get the maximum benefit from the CIFS VFS, we recommend using a server that 
+supports the SNIA CIFS Unix Extensions standard (e.g.  Samba 2.2.5 or later or 
+Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers.  
+Note that uid, gid and file permissions will display default values if you do 
+not have a server that supports the Unix extensions for CIFS (such as Samba 
+2.2.5 or later).  To enable the Unix CIFS Extensions in the Samba server, add 
+the line: 
+
+       unix extensions = yes
+       
+to your smb.conf file on the server.  Note that the following smb.conf settings 
+are also useful (on the Samba server) when the majority of clients are Unix or 
+Linux: 
+
+       case sensitive = yes
+       delete readonly = yes 
+       ea support = yes
+
+Note that server ea support is required for supporting xattrs from the Linux
+cifs client, and that EA support is present in later versions of Samba (e.g. 
+3.0.6 and later (also EA support works in all versions of Windows, at least to
+shares on NTFS filesystems).  Extended Attribute (xattr) support is an optional
+feature of most Linux filesystems which may require enabling via
+make menuconfig. Client support for extended attributes (user xattr) can be
+disabled on a per-mount basis by specifying "nouser_xattr" on mount.
+
+The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers
+version 3.10 and later.  Setting POSIX ACLs requires enabling both XATTR and 
+then POSIX support in the CIFS configuration options when building the cifs
+module.  POSIX ACL support can be disabled on a per mount basic by specifying
+"noacl" on mount.
+Some administrators may want to change Samba's smb.conf "map archive" and 
+"create mask" parameters from the default.  Unless the create mask is changed
+newly created files can end up with an unnecessarily restrictive default mode,
+which may not be what you want, although if the CIFS Unix extensions are
+enabled on the server and client, subsequent setattr calls (e.g. chmod) can
+fix the mode.  Note that creating special devices (mknod) remotely 
+may require specifying a mkdev function to Samba if you are not using 
+Samba 3.0.6 or later.  For more information on these see the manual pages
+("man smb.conf") on the Samba server system.  Note that the cifs vfs,
+unlike the smbfs vfs, does not read the smb.conf on the client system 
+(the few optional settings are passed in on mount via -o parameters instead).  
+Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete
+open files (required for strict POSIX compliance).  Windows Servers already 
+supported this feature. Samba server does not allow symlinks that refer to files
+outside of the share, so in Samba versions prior to 3.0.6, most symlinks to
+files with absolute paths (ie beginning with slash) such as:
+        ln -s /mnt/foo bar
+would be forbidden. Samba 3.0.6 server or later includes the ability to create 
+such symlinks safely by converting unsafe symlinks (ie symlinks to server 
+files that are outside of the share) to a samba specific format on the server
+that is ignored by local server applications and non-cifs clients and that will
+not be traversed by the Samba server).  This is opaque to the Linux client
+application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or
+later, but only for remote clients using the CIFS Unix extensions, and will
+be invisbile to Windows clients and typically will not affect local
+applications running on the same server as Samba.  
+
+Use instructions:
+================
+Once the CIFS VFS support is built into the kernel or installed as a module 
+(cifs.o), you can use mount syntax like the following to access Samba or Windows 
+servers: 
+
+  mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword
+
+Before -o the option -v may be specified to make the mount.cifs
+mount helper display the mount steps more verbosely.  
+After -o the following commonly used cifs vfs specific options
+are supported:
+
+  user=<username>
+  pass=<password>
+  domain=<domain name>
+  
+Other cifs mount options are described below.  Use of TCP names (in addition to
+ip addresses) is available if the mount helper (mount.cifs) is installed. If
+you do not trust the server to which are mounted, or if you do not have
+cifs signing enabled (and the physical network is insecure), consider use
+of the standard mount options "noexec" and "nosuid" to reduce the risk of 
+running an altered binary on your local system (downloaded from a hostile server
+or altered by a hostile router).
+
+Although mounting using format corresponding to the CIFS URL specification is
+not possible in mount.cifs yet, it is possible to use an alternate format
+for the server and sharename (which is somewhat similar to NFS style mount
+syntax) instead of the more widely used UNC format (i.e. \\server\share):
+  mount -t cifs tcp_name_of_server:share_name /mnt -o user=myname,pass=mypasswd
+
+When using the mount helper mount.cifs, passwords may be specified via alternate
+mechanisms, instead of specifying it after -o using the normal "pass=" syntax
+on the command line:
+1) By including it in a credential file. Specify credentials=filename as one
+of the mount options. Credential files contain two lines
+        username=someuser
+        password=your_password
+2) By specifying the password in the PASSWD environment variable (similarly
+the user name can be taken from the USER environment variable).
+3) By specifying the password in a file by name via PASSWD_FILE
+4) By specifying the password in a file by file descriptor via PASSWD_FD
+
+If no password is provided, mount.cifs will prompt for password entry
+
+Restrictions
+============
+Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 
+1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a 
+problem as most servers support this.
+
+Valid filenames differ between Windows and Linux.  Windows typically restricts
+filenames which contain certain reserved characters (e.g.the character : 
+which is used to delimit the beginning of a stream name by Windows), while
+Linux allows a slightly wider set of valid characters in filenames. Windows
+servers can remap such characters when an explicit mapping is specified in
+the Server's registry.  Samba starting with version 3.10 will allow such 
+filenames (ie those which contain valid Linux characters, which normally
+would be forbidden for Windows/CIFS semantics) as long as the server is
+configured for Unix Extensions (and the client has not disabled
+/proc/fs/cifs/LinuxExtensionsEnabled).
+  
+
+CIFS VFS Mount Options
+======================
+A partial list of the supported mount options follows:
+  user         The user name to use when trying to establish
+               the CIFS session.
+  password     The user password.  If the mount helper is
+               installed, the user will be prompted for password
+               if not supplied.
+  ip           The ip address of the target server
+  unc          The target server Universal Network Name (export) to 
+               mount.  
+  domain       Set the SMB/CIFS workgroup name prepended to the
+               username during CIFS session establishment
+  forceuid     Set the default uid for inodes to the uid
+               passed in on mount. For mounts to servers
+               which do support the CIFS Unix extensions, such as a
+               properly configured Samba server, the server provides
+               the uid, gid and mode so this parameter should not be
+               specified unless the server and clients uid and gid
+               numbering differ.  If the server and client are in the
+               same domain (e.g. running winbind or nss_ldap) and
+               the server supports the Unix Extensions then the uid
+               and gid can be retrieved from the server (and uid
+               and gid would not have to be specifed on the mount. 
+               For servers which do not support the CIFS Unix
+               extensions, the default uid (and gid) returned on lookup
+               of existing files will be the uid (gid) of the person
+               who executed the mount (root, except when mount.cifs
+               is configured setuid for user mounts) unless the "uid=" 
+               (gid) mount option is specified. Also note that permission
+               checks (authorization checks) on accesses to a file occur
+               at the server, but there are cases in which an administrator
+               may want to restrict at the client as well.  For those
+               servers which do not report a uid/gid owner
+               (such as Windows), permissions can also be checked at the
+               client, and a crude form of client side permission checking 
+               can be enabled by specifying file_mode and dir_mode on 
+               the client.  (default)
+  forcegid     (similar to above but for the groupid instead of uid) (default)
+  noforceuid   Fill in file owner information (uid) by requesting it from
+               the server if possible. With this option, the value given in
+               the uid= option (on mount) will only be used if the server
+               can not support returning uids on inodes.
+  noforcegid   (similar to above but for the group owner, gid, instead of uid)
+  uid          Set the default uid for inodes, and indicate to the
+               cifs kernel driver which local user mounted. If the server
+               supports the unix extensions the default uid is
+               not used to fill in the owner fields of inodes (files)
+               unless the "forceuid" parameter is specified.
+  gid          Set the default gid for inodes (similar to above).
+  file_mode     If CIFS Unix extensions are not supported by the server
+               this overrides the default mode for file inodes.
+  fsc          Enable local disk caching using FS-Cache (off by default). This
+               option could be useful to improve performance on a slow link,
+               heavily loaded server and/or network where reading from the
+               disk is faster than reading from the server (over the network).
+               This could also impact scalability positively as the
+               number of calls to the server are reduced. However, local
+               caching is not suitable for all workloads for e.g. read-once
+               type workloads. So, you need to consider carefully your
+               workload/scenario before using this option. Currently, local
+               disk caching is functional for CIFS files opened as read-only.
+  dir_mode      If CIFS Unix extensions are not supported by the server 
+               this overrides the default mode for directory inodes.
+  port         attempt to contact the server on this tcp port, before
+               trying the usual ports (port 445, then 139).
+  iocharset     Codepage used to convert local path names to and from
+               Unicode. Unicode is used by default for network path
+               names if the server supports it.  If iocharset is
+               not specified then the nls_default specified
+               during the local client kernel build will be used.
+               If server does not support Unicode, this parameter is
+               unused.
+  rsize                default read size (usually 16K). The client currently
+               can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize
+               defaults to 16K and may be changed (from 8K to the maximum
+               kmalloc size allowed by your kernel) at module install time
+               for cifs.ko. Setting CIFSMaxBufSize to a very large value
+               will cause cifs to use more memory and may reduce performance
+               in some cases.  To use rsize greater than 127K (the original
+               cifs protocol maximum) also requires that the server support
+               a new Unix Capability flag (for very large read) which some
+               newer servers (e.g. Samba 3.0.26 or later) do. rsize can be
+               set from a minimum of 2048 to a maximum of 130048 (127K or
+               CIFSMaxBufSize, whichever is smaller)
+  wsize                default write size (default 57344)
+               maximum wsize currently allowed by CIFS is 57344 (fourteen
+               4096 byte pages)
+  actimeo=n    attribute cache timeout in seconds (default 1 second).
+               After this timeout, the cifs client requests fresh attribute
+               information from the server. This option allows to tune the
+               attribute cache timeout to suit the workload needs. Shorter
+               timeouts mean better the cache coherency, but increased number
+               of calls to the server. Longer timeouts mean reduced number
+               of calls to the server at the expense of less stricter cache
+               coherency checks (i.e. incorrect attribute cache for a short
+               period of time).
+  rw           mount the network share read-write (note that the
+               server may still consider the share read-only)
+  ro           mount network share read-only
+  version      used to distinguish different versions of the
+               mount helper utility (not typically needed)
+  sep          if first mount option (after the -o), overrides
+               the comma as the separator between the mount
+               parms. e.g.
+                       -o user=myname,password=mypassword,domain=mydom
+               could be passed instead with period as the separator by
+                       -o sep=.user=myname.password=mypassword.domain=mydom
+               this might be useful when comma is contained within username
+               or password or domain. This option is less important
+               when the cifs mount helper cifs.mount (version 1.1 or later)
+               is used.
+  nosuid        Do not allow remote executables with the suid bit 
+               program to be executed.  This is only meaningful for mounts
+               to servers such as Samba which support the CIFS Unix Extensions.
+               If you do not trust the servers in your network (your mount
+               targets) it is recommended that you specify this option for
+               greater security.
+  exec         Permit execution of binaries on the mount.
+  noexec       Do not permit execution of binaries on the mount.
+  dev          Recognize block devices on the remote mount.
+  nodev                Do not recognize devices on the remote mount.
+  suid          Allow remote files on this mountpoint with suid enabled to 
+               be executed (default for mounts when executed as root,
+               nosuid is default for user mounts).
+  credentials   Although ignored by the cifs kernel component, it is used by 
+               the mount helper, mount.cifs. When mount.cifs is installed it
+               opens and reads the credential file specified in order  
+               to obtain the userid and password arguments which are passed to
+               the cifs vfs.
+  guest         Although ignored by the kernel component, the mount.cifs
+               mount helper will not prompt the user for a password
+               if guest is specified on the mount options.  If no
+               password is specified a null password will be used.
+  perm          Client does permission checks (vfs_permission check of uid
+               and gid of the file against the mode and desired operation),
+               Note that this is in addition to the normal ACL check on the
+               target machine done by the server software. 
+               Client permission checking is enabled by default.
+  noperm        Client does not do permission checks.  This can expose
+               files on this mount to access by other users on the local
+               client system. It is typically only needed when the server
+               supports the CIFS Unix Extensions but the UIDs/GIDs on the
+               client and server system do not match closely enough to allow
+               access by the user doing the mount, but it may be useful with
+               non CIFS Unix Extension mounts for cases in which the default
+               mode is specified on the mount but is not to be enforced on the
+               client (e.g. perhaps when MultiUserMount is enabled)
+               Note that this does not affect the normal ACL check on the
+               target machine done by the server software (of the server
+               ACL against the user name provided at mount time).
+  serverino    Use server's inode numbers instead of generating automatically
+               incrementing inode numbers on the client.  Although this will
+               make it easier to spot hardlinked files (as they will have
+               the same inode numbers) and inode numbers may be persistent,
+               note that the server does not guarantee that the inode numbers
+               are unique if multiple server side mounts are exported under a
+               single share (since inode numbers on the servers might not
+               be unique if multiple filesystems are mounted under the same
+               shared higher level directory).  Note that some older
+               (e.g. pre-Windows 2000) do not support returning UniqueIDs
+               or the CIFS Unix Extensions equivalent and for those
+               this mount option will have no effect.  Exporting cifs mounts
+               under nfsd requires this mount option on the cifs mount.
+               This is now the default if server supports the 
+               required network operation.
+  noserverino   Client generates inode numbers (rather than using the actual one
+               from the server). These inode numbers will vary after
+               unmount or reboot which can confuse some applications,
+               but not all server filesystems support unique inode
+               numbers.
+  setuids       If the CIFS Unix extensions are negotiated with the server
+               the client will attempt to set the effective uid and gid of
+               the local process on newly created files, directories, and
+               devices (create, mkdir, mknod).  If the CIFS Unix Extensions
+               are not negotiated, for newly created files and directories
+               instead of using the default uid and gid specified on
+               the mount, cache the new file's uid and gid locally which means
+               that the uid for the file can change when the inode is
+               reloaded (or the user remounts the share).
+  nosetuids     The client will not attempt to set the uid and gid on
+               on newly created files, directories, and devices (create, 
+               mkdir, mknod) which will result in the server setting the
+               uid and gid to the default (usually the server uid of the
+               user who mounted the share).  Letting the server (rather than
+               the client) set the uid and gid is the default. If the CIFS
+               Unix Extensions are not negotiated then the uid and gid for
+               new files will appear to be the uid (gid) of the mounter or the
+               uid (gid) parameter specified on the mount.
+  netbiosname   When mounting to servers via port 139, specifies the RFC1001
+               source name to use to represent the client netbios machine 
+               name when doing the RFC1001 netbios session initialize.
+  direct        Do not do inode data caching on files opened on this mount.
+               This precludes mmapping files on this mount. In some cases
+               with fast networks and little or no caching benefits on the
+               client (e.g. when the application is doing large sequential
+               reads bigger than page size without rereading the same data) 
+               this can provide better performance than the default
+               behavior which caches reads (readahead) and writes 
+               (writebehind) through the local Linux client pagecache 
+               if oplock (caching token) is granted and held. Note that
+               direct allows write operations larger than page size
+               to be sent to the server.
+  strictcache   Use for switching on strict cache mode. In this mode the
+               client read from the cache all the time it has Oplock Level II,
+               otherwise - read from the server. All written data are stored
+               in the cache, but if the client doesn't have Exclusive Oplock,
+               it writes the data to the server.
+  rwpidforward  Forward pid of a process who opened a file to any read or write
+               operation on that file. This prevent applications like WINE
+               from failing on read and write if we use mandatory brlock style.
+  acl          Allow setfacl and getfacl to manage posix ACLs if server
+               supports them.  (default)
+  noacl        Do not allow setfacl and getfacl calls on this mount
+  user_xattr    Allow getting and setting user xattrs (those attributes whose
+               name begins with "user." or "os2.") as OS/2 EAs (extended
+               attributes) to the server.  This allows support of the
+               setfattr and getfattr utilities. (default)
+  nouser_xattr  Do not allow getfattr/setfattr to get/set/list xattrs 
+  mapchars      Translate six of the seven reserved characters (not backslash)
+                       *?<>|:
+               to the remap range (above 0xF000), which also
+               allows the CIFS client to recognize files created with
+               such characters by Windows's POSIX emulation. This can
+               also be useful when mounting to most versions of Samba
+               (which also forbids creating and opening files
+               whose names contain any of these seven characters).
+               This has no effect if the server does not support
+               Unicode on the wire.
+ nomapchars     Do not translate any of these seven characters (default).
+ nocase         Request case insensitive path name matching (case
+               sensitive is the default if the server supports it).
+               (mount option "ignorecase" is identical to "nocase")
+ posixpaths     If CIFS Unix extensions are supported, attempt to
+               negotiate posix path name support which allows certain
+               characters forbidden in typical CIFS filenames, without
+               requiring remapping. (default)
+ noposixpaths   If CIFS Unix extensions are supported, do not request
+               posix path name support (this may cause servers to
+               reject creatingfile with certain reserved characters).
+ nounix         Disable the CIFS Unix Extensions for this mount (tree
+               connection). This is rarely needed, but it may be useful
+               in order to turn off multiple settings all at once (ie
+               posix acls, posix locks, posix paths, symlink support
+               and retrieving uids/gids/mode from the server) or to
+               work around a bug in server which implement the Unix
+               Extensions.
+ nobrl          Do not send byte range lock requests to the server.
+               This is necessary for certain applications that break
+               with cifs style mandatory byte range locks (and most
+               cifs servers do not yet support requesting advisory
+               byte range locks).
+ forcemandatorylock Even if the server supports posix (advisory) byte range
+               locking, send only mandatory lock requests.  For some
+               (presumably rare) applications, originally coded for
+               DOS/Windows, which require Windows style mandatory byte range
+               locking, they may be able to take advantage of this option,
+               forcing the cifs client to only send mandatory locks
+               even if the cifs server would support posix advisory locks.
+               "forcemand" is accepted as a shorter form of this mount
+               option.
+ nostrictsync   If this mount option is set, when an application does an
+               fsync call then the cifs client does not send an SMB Flush
+               to the server (to force the server to write all dirty data
+               for this file immediately to disk), although cifs still sends
+               all dirty (cached) file data to the server and waits for the
+               server to respond to the write.  Since SMB Flush can be
+               very slow, and some servers may be reliable enough (to risk
+               delaying slightly flushing the data to disk on the server),
+               turning on this option may be useful to improve performance for
+               applications that fsync too much, at a small risk of server
+               crash.  If this mount option is not set, by default cifs will
+               send an SMB flush request (and wait for a response) on every
+               fsync call.
+ nodfs          Disable DFS (global name space support) even if the
+               server claims to support it.  This can help work around
+               a problem with parsing of DFS paths with Samba server
+               versions 3.0.24 and 3.0.25.
+ remount        remount the share (often used to change from ro to rw mounts
+               or vice versa)
+ cifsacl        Report mode bits (e.g. on stat) based on the Windows ACL for
+               the file. (EXPERIMENTAL)
+ servern        Specify the server 's netbios name (RFC1001 name) to use
+               when attempting to setup a session to the server. 
+               This is needed for mounting to some older servers (such
+               as OS/2 or Windows 98 and Windows ME) since they do not
+               support a default server name.  A server name can be up
+               to 15 characters long and is usually uppercased.
+ sfu            When the CIFS Unix Extensions are not negotiated, attempt to
+               create device files and fifos in a format compatible with
+               Services for Unix (SFU).  In addition retrieve bits 10-12
+               of the mode via the SETFILEBITS extended attribute (as
+               SFU does).  In the future the bottom 9 bits of the
+               mode also will be emulated using queries of the security
+               descriptor (ACL).
+ mfsymlinks     Enable support for Minshall+French symlinks
+               (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks)
+               This option is ignored when specified together with the
+               'sfu' option. Minshall+French symlinks are used even if
+               the server supports the CIFS Unix Extensions.
+ sign           Must use packet signing (helps avoid unwanted data modification
+               by intermediate systems in the route).  Note that signing
+               does not work with lanman or plaintext authentication.
+ seal           Must seal (encrypt) all data on this mounted share before
+               sending on the network.  Requires support for Unix Extensions.
+               Note that this differs from the sign mount option in that it
+               causes encryption of data sent over this mounted share but other
+               shares mounted to the same server are unaffected.
+ locallease     This option is rarely needed. Fcntl F_SETLEASE is
+               used by some applications such as Samba and NFSv4 server to
+               check to see whether a file is cacheable.  CIFS has no way
+               to explicitly request a lease, but can check whether a file
+               is cacheable (oplocked).  Unfortunately, even if a file
+               is not oplocked, it could still be cacheable (ie cifs client
+               could grant fcntl leases if no other local processes are using
+               the file) for cases for example such as when the server does not
+               support oplocks and the user is sure that the only updates to
+               the file will be from this client. Specifying this mount option
+               will allow the cifs client to check for leases (only) locally
+               for files which are not oplocked instead of denying leases
+               in that case. (EXPERIMENTAL)
+ sec            Security mode.  Allowed values are:
+                       none    attempt to connection as a null user (no name)
+                       krb5    Use Kerberos version 5 authentication
+                       krb5i   Use Kerberos authentication and packet signing
+                       ntlm    Use NTLM password hashing (default)
+                       ntlmi   Use NTLM password hashing with signing (if
+                               /proc/fs/cifs/PacketSigningEnabled on or if
+                               server requires signing also can be the default) 
+                       ntlmv2  Use NTLMv2 password hashing      
+                       ntlmv2i Use NTLMv2 password hashing with packet signing
+                       lanman  (if configured in kernel config) use older
+                               lanman hash
+hard           Retry file operations if server is not responding
+soft           Limit retries to unresponsive servers (usually only
+               one retry) before returning an error.  (default)
+
+The mount.cifs mount helper also accepts a few mount options before -o
+including:
+
+       -S      take password from stdin (equivalent to setting the environment
+               variable "PASSWD_FD=0"
+       -V      print mount.cifs version
+       -?      display simple usage information
+
+With most 2.6 kernel versions of modutils, the version of the cifs kernel
+module can be displayed via modinfo.
+
+Misc /proc/fs/cifs Flags and Debug Info
+=======================================
+Informational pseudo-files:
+DebugData              Displays information about active CIFS sessions and
+                       shares, features enabled as well as the cifs.ko
+                       version.
+Stats                  Lists summary resource usage information as well as per
+                       share statistics, if CONFIG_CIFS_STATS in enabled
+                       in the kernel configuration.
+
+Configuration pseudo-files:
+PacketSigningEnabled   If set to one, cifs packet signing is enabled
+                       and will be used if the server requires 
+                       it.  If set to two, cifs packet signing is
+                       required even if the server considers packet
+                       signing optional. (default 1)
+SecurityFlags          Flags which control security negotiation and
+                       also packet signing. Authentication (may/must)
+                       flags (e.g. for NTLM and/or NTLMv2) may be combined with
+                       the signing flags.  Specifying two different password
+                       hashing mechanisms (as "must use") on the other hand 
+                       does not make much sense. Default flags are 
+                               0x07007 
+                       (NTLM, NTLMv2 and packet signing allowed).  The maximum 
+                       allowable flags if you want to allow mounts to servers
+                       using weaker password hashes is 0x37037 (lanman,
+                       plaintext, ntlm, ntlmv2, signing allowed).  Some
+                       SecurityFlags require the corresponding menuconfig
+                       options to be enabled (lanman and plaintext require
+                       CONFIG_CIFS_WEAK_PW_HASH for example).  Enabling
+                       plaintext authentication currently requires also
+                       enabling lanman authentication in the security flags
+                       because the cifs module only supports sending
+                       laintext passwords using the older lanman dialect
+                       form of the session setup SMB.  (e.g. for authentication
+                       using plain text passwords, set the SecurityFlags
+                       to 0x30030):
+                       may use packet signing                          0x00001
+                       must use packet signing                         0x01001
+                       may use NTLM (most common password hash)        0x00002
+                       must use NTLM                                   0x02002
+                       may use NTLMv2                                  0x00004
+                       must use NTLMv2                                 0x04004
+                       may use Kerberos security                       0x00008
+                       must use Kerberos                               0x08008
+                       may use lanman (weak) password hash             0x00010
+                       must use lanman password hash                   0x10010
+                       may use plaintext passwords                     0x00020
+                       must use plaintext passwords                    0x20020
+                       (reserved for future packet encryption)         0x00040
+
+cifsFYI                        If set to non-zero value, additional debug information
+                       will be logged to the system error log.  This field
+                       contains three flags controlling different classes of
+                       debugging entries.  The maximum value it can be set
+                       to is 7 which enables all debugging points (default 0).
+                       Some debugging statements are not compiled into the
+                       cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the
+                       kernel configuration. cifsFYI may be set to one or
+                       nore of the following flags (7 sets them all):
+
+                       log cifs informational messages                 0x01
+                       log return codes from cifs entry points         0x02
+                       log slow responses (ie which take longer than 1 second)
+                         CONFIG_CIFS_STATS2 must be enabled in .config 0x04
+                               
+                               
+traceSMB               If set to one, debug information is logged to the
+                       system error log with the start of smb requests
+                       and responses (default 0)
+LookupCacheEnable      If set to one, inode information is kept cached
+                       for one second improving performance of lookups
+                       (default 1)
+OplockEnabled          If set to one, safe distributed caching enabled.
+                       (default 1)
+LinuxExtensionsEnabled If set to one then the client will attempt to
+                       use the CIFS "UNIX" extensions which are optional
+                       protocol enhancements that allow CIFS servers
+                       to return accurate UID/GID information as well
+                       as support symbolic links. If you use servers
+                       such as Samba that support the CIFS Unix
+                       extensions but do not want to use symbolic link
+                       support and want to map the uid and gid fields 
+                       to values supplied at mount (rather than the 
+                       actual values, then set this to zero. (default 1)
+
+These experimental features and tracing can be enabled by changing flags in 
+/proc/fs/cifs (after the cifs module has been installed or built into the 
+kernel, e.g.  insmod cifs).  To enable a feature set it to 1 e.g.  to enable 
+tracing to the kernel message log type: 
+
+       echo 7 > /proc/fs/cifs/cifsFYI
+       
+cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
+logging of various informational messages.  2 enables logging of non-zero
+SMB return codes while 4 enables logging of requests that take longer
+than one second to complete (except for byte range lock requests). 
+Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
+source code (typically by setting it in the beginning of cifsglob.h),
+and setting it to seven enables all three.  Finally, tracing
+the start of smb requests and responses can be enabled via:
+
+       echo 1 > /proc/fs/cifs/traceSMB
+
+Per share (per client mount) statistics are available in /proc/fs/cifs/Stats
+if the kernel was configured with cifs statistics enabled.  The statistics
+represent the number of successful (ie non-zero return code from the server) 
+SMB responses to some of the more common commands (open, delete, mkdir etc.).
+Also recorded is the total bytes read and bytes written to the server for
+that share.  Note that due to client caching effects this can be less than the
+number of bytes read and written by the application running on the client.
+The statistics for the number of total SMBs and oplock breaks are different in
+that they represent all for that share, not just those for which the server
+returned success.
+       
+Also note that "cat /proc/fs/cifs/DebugData" will display information about
+the active sessions and the shares that are mounted.
+
+Enabling Kerberos (extended security) works but requires version 1.2 or later
+of the helper program cifs.upcall to be present and to be configured in the
+/etc/request-key.conf file.  The cifs.upcall helper program is from the Samba
+project(http://www.samba.org). NTLM and NTLMv2 and LANMAN support do not
+require this helper. Note that NTLMv2 security (which does not require the
+cifs.upcall helper program), instead of using Kerberos, is sufficient for
+some use cases.
+
+DFS support allows transparent redirection to shares in an MS-DFS name space.
+In addition, DFS support for target shares which are specified as UNC
+names which begin with host names (rather than IP addresses) requires
+a user space helper (such as cifs.upcall) to be present in order to
+translate host names to ip address, and the user space helper must also
+be configured in the file /etc/request-key.conf.  Samba, Windows servers and
+many NAS appliances support DFS as a way of constructing a global name
+space to ease network configuration and improve reliability.
+
+To use cifs Kerberos and DFS support, the Linux keyutils package should be
+installed and something like the following lines should be added to the
+/etc/request-key.conf file:
+
+create cifs.spnego * * /usr/local/sbin/cifs.upcall %k
+create dns_resolver * * /usr/local/sbin/cifs.upcall %k
+
+CIFS kernel module parameters
+=============================
+These module parameters can be specified or modified either during the time of
+module loading or during the runtime by using the interface
+       /proc/module/cifs/parameters/<param>
+
+i.e. echo "value" > /sys/module/cifs/parameters/<param>
+
+1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
+                   [Y/y/1]. To disable use any of [N/n/0].
+
diff --git a/Documentation/filesystems/cifs/TODO b/Documentation/filesystems/cifs/TODO
new file mode 100644 (file)
index 0000000..355abcd
--- /dev/null
@@ -0,0 +1,129 @@
+Version 1.53 May 20, 2008
+
+A Partial List of Missing Features
+==================================
+
+Contributions are welcome.  There are plenty of opportunities
+for visible, important contributions to this module.  Here
+is a partial list of the known problems and missing features:
+
+a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
+so that these operations can be supported to Windows servers
+
+b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
+SecurityDescriptors
+
+c) Better pam/winbind integration (e.g. to handle uid mapping
+better)
+
+d) Cleanup now unneeded SessSetup code in
+fs/cifs/connect.c and add back in NTLMSSP code if any servers
+need it
+
+e) fix NTLMv2 signing when two mounts with different users to same
+server.
+
+f) Directory entry caching relies on a 1 second timer, rather than 
+using FindNotify or equivalent.  - (started)
+
+g) quota support (needs minor kernel change since quota calls
+to make it to network filesystems or deviceless filesystems)
+
+h) investigate sync behavior (including syncpage) and check  
+for proper behavior of intr/nointr
+
+i) improve support for very old servers (OS/2 and Win9x for example)
+Including support for changing the time remotely (utimes command).
+
+j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
+extra copy in/out of the socket buffers in some cases.
+
+k) Better optimize open (and pathbased setfilesize) to reduce the
+oplock breaks coming from windows srv.  Piggyback identical file
+opens on top of each other by incrementing reference count rather
+than resending (helps reduce server resource utilization and avoid
+spurious oplock breaks).
+
+l) Improve performance of readpages by sending more than one read
+at a time when 8 pages or more are requested. In conjuntion
+add support for async_cifs_readpages.
+
+m) Add support for storing symlink info to Windows servers 
+in the Extended Attribute format their SFU clients would recognize.
+
+n) Finish fcntl D_NOTIFY support so kde and gnome file list windows
+will autorefresh (partially complete by Asser). Needs minor kernel
+vfs change to support removing D_NOTIFY on a file.   
+
+o) Add GUI tool to configure /proc/fs/cifs settings and for display of
+the CIFS statistics (started)
+
+p) implement support for security and trusted categories of xattrs
+(requires minor protocol extension) to enable better support for SELINUX
+
+q) Implement O_DIRECT flag on open (already supported on mount)
+
+r) Create UID mapping facility so server UIDs can be mapped on a per
+mount or a per server basis to client UIDs or nobody if no mapping
+exists.  This is helpful when Unix extensions are negotiated to
+allow better permission checking when UIDs differ on the server
+and client.  Add new protocol request to the CIFS protocol 
+standard for asking the server for the corresponding name of a
+particular uid.
+
+s) Add support for CIFS Unix and also the newer POSIX extensions to the
+server side for Samba 4.
+
+t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) 
+need to add ability to set time to server (utimes command)
+
+u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
+
+v) mount check for unmatched uids
+
+w) Add support for new vfs entry point for fallocate
+
+x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
+processes can proceed better in parallel (on the server)
+
+y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount
+restriction of wsize max being 127K) 
+
+KNOWN BUGS (updated April 24, 2007)
+====================================
+See http://bugzilla.samba.org - search on product "CifsVFS" for
+current bug list.
+
+1) existing symbolic links (Windows reparse points) are recognized but
+can not be created remotely. They are implemented for Samba and those that
+support the CIFS Unix extensions, although earlier versions of Samba
+overly restrict the pathnames.
+2) follow_link and readdir code does not follow dfs junctions
+but recognizes them
+3) create of new files to FAT partitions on Windows servers can
+succeed but still return access denied (appears to be Windows 
+server not cifs client problem) and has not been reproduced recently.
+NTFS partitions do not have this problem.
+4) Unix/POSIX capabilities are reset after reconnection, and affect
+a few fields in the tree connection but we do do not know which
+superblocks to apply these changes to.  We should probably walk
+the list of superblocks to set these.  Also need to check the
+flags on the second mount to the same share, and see if we
+can do the same trick that NFS does to remount duplicate shares.
+
+Misc testing to do
+==================
+1) check out max path names and max path name components against various server
+types. Try nested symlinks (8 deep). Return max path name in stat -f information
+
+2) Modify file portion of ltp so it can run against a mounted network
+share and run it against cifs vfs in automated fashion.
+
+3) Additional performance testing and optimization using iozone and similar - 
+there are some easy changes that can be done to parallelize sequential writes,
+and when signing is disabled to request larger read sizes (larger than 
+negotiated size) and send larger write sizes to modern servers.
+
+4) More exhaustively test against less common servers.  More testing
+against Windows 9x, Windows ME servers.
+
diff --git a/Documentation/filesystems/cifs/cifs.txt b/Documentation/filesystems/cifs/cifs.txt
new file mode 100644 (file)
index 0000000..2fac91a
--- /dev/null
@@ -0,0 +1,31 @@
+  This is the client VFS module for the Common Internet File System
+  (CIFS) protocol which is the successor to the Server Message Block 
+  (SMB) protocol, the native file sharing mechanism for most early
+  PC operating systems. New and improved versions of CIFS are now
+  called SMB2 and SMB3. These dialects are also supported by the
+  CIFS VFS module. CIFS is fully supported by network
+  file servers such as Windows 2000, 2003, 2008 and 2012
+  as well by Samba (which provides excellent CIFS
+  server support for Linux and many other operating systems), so
+  this network filesystem client can mount to a wide variety of
+  servers.
+
+  The intent of this module is to provide the most advanced network
+  file system function for CIFS compliant servers, including better
+  POSIX compliance, secure per-user session establishment, high
+  performance safe distributed caching (oplock), optional packet
+  signing, large files, Unicode support and other internationalization
+  improvements. Since both Samba server and this filesystem client support
+  the CIFS Unix extensions, the combination can provide a reasonable 
+  alternative to NFSv4 for fileserving in some Linux to Linux environments,
+  not just in Linux to Windows environments.
+
+  This filesystem has an mount utility (mount.cifs) that can be obtained from
+
+      https://ftp.samba.org/pub/linux-cifs/cifs-utils/
+
+  It must be installed in the directory with the other mount helpers.
+
+  For more information on the module see the project wiki page at
+
+      https://wiki.samba.org/index.php/LinuxCIFS_utils
diff --git a/Documentation/filesystems/cifs/winucase_convert.pl b/Documentation/filesystems/cifs/winucase_convert.pl
new file mode 100755 (executable)
index 0000000..322a9c8
--- /dev/null
@@ -0,0 +1,62 @@
+#!/usr/bin/perl -w
+#
+# winucase_convert.pl -- convert "Windows 8 Upper Case Mapping Table.txt" to
+#                        a two-level set of C arrays.
+#
+#   Copyright 2013: Jeff Layton <jlayton@redhat.com>
+#
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+while(<>) {
+       next if (!/^0x(..)(..)\t0x(....)\t/);
+       $firstchar = hex($1);
+       $secondchar = hex($2);
+       $uppercase = hex($3);
+
+       $top[$firstchar][$secondchar] = $uppercase;
+}
+
+for ($i = 0; $i < 256; $i++) {
+       next if (!$top[$i]);
+
+       printf("static const wchar_t t2_%2.2x[256] = {", $i);
+       for ($j = 0; $j < 256; $j++) {
+               if (($j % 8) == 0) {
+                       print "\n\t";
+               } else {
+                       print " ";
+               }
+               printf("0x%4.4x,", $top[$i][$j] ? $top[$i][$j] : 0);
+       }
+       print "\n};\n\n";
+}
+
+printf("static const wchar_t *const toplevel[256] = {", $i);
+for ($i = 0; $i < 256; $i++) {
+       if (($i % 8) == 0) {
+               print "\n\t";
+       } elsif ($top[$i]) {
+               print " ";
+       } else {
+               print "  ";
+       }
+
+       if ($top[$i]) {
+               printf("t2_%2.2x,", $i);
+       } else {
+               print "NULL,";
+       }
+}
+print "\n};\n\n";
index 206a1bdc7321cf59a1ccc8829d09a9dccd9bcded..f0890581f7f65a14d8451e85dcb2f59912db1d3d 100644 (file)
@@ -451,3 +451,7 @@ in your dentry operations instead.
 --
 [mandatory]
        ->readdir() is gone now; switch to ->iterate()
+[mandatory]
+       vfs_follow_link has been removed.  Filesystems must use nd_set_link
+       from ->follow_link for normal symlinks, or nd_jump_link for magic
+       /proc/<pid> style links.
index fcc22c982a25fe244a59135d7066ef156ef76be6..823c95faebd260af62618a647868ca904fd0eeab 100644 (file)
@@ -854,16 +854,15 @@ Committed_AS: The amount of memory presently allocated on the system.
               The committed memory is a sum of all of the memory which
               has been allocated by processes, even if it has not been
               "used" by them as of yet. A process which malloc()'s 1G
-              of memory, but only touches 300M of it will only show up
-              as using 300M of memory even if it has the address space
-              allocated for the entire 1G. This 1G is memory which has
-              been "committed" to by the VM and can be used at any time
-              by the allocating application. With strict overcommit
-              enabled on the system (mode 2 in 'vm.overcommit_memory'),
-              allocations which would exceed the CommitLimit (detailed
-              above) will not be permitted. This is useful if one needs
-              to guarantee that processes will not fail due to lack of
-              memory once that memory has been successfully allocated.
+              of memory, but only touches 300M of it will show up as
+             using 1G. This 1G is memory which has been "committed" to
+              by the VM and can be used at any time by the allocating
+              application. With strict overcommit enabled on the system
+              (mode 2 in 'vm.overcommit_memory'),allocations which would
+              exceed the CommitLimit (detailed above) will not be permitted.
+              This is useful if one needs to guarantee that processes will
+              not fail due to lack of memory once that memory has been
+              successfully allocated.
 VmallocTotal: total size of vmalloc memory area
  VmallocUsed: amount of vmalloc area which is used
 VmallocChunk: largest contiguous block of vmalloc area which is free
index 59b4a0962e0f54df08399c2364b8161ac1b6434a..b176928e69631f5efe3cb37506b3eb375cc3e23a 100644 (file)
@@ -79,6 +79,10 @@ to just make sure certain lists can't become empty.
 Most systems just mount another filesystem over rootfs and ignore it.  The
 amount of space an empty instance of ramfs takes up is tiny.
 
+If CONFIG_TMPFS is enabled, rootfs will use tmpfs instead of ramfs by
+default.  To force ramfs, add "rootfstype=ramfs" to the kernel command
+line.
+
 What is initramfs?
 ------------------
 
index f93a88250a448a99293d0a6d776af50b1a98453b..deb48b5fd88327d8249b19aa8de16aab6855c191 100644 (file)
@@ -359,11 +359,9 @@ struct inode_operations {
        ssize_t (*listxattr) (struct dentry *, char *, size_t);
        int (*removexattr) (struct dentry *, const char *);
        void (*update_time)(struct inode *, struct timespec *, int);
-       int (*atomic_open)(struct inode *, struct dentry *,
+       int (*atomic_open)(struct inode *, struct dentry *, struct file *,
+                       unsigned open_flag, umode_t create_mode, int *opened);
        int (*tmpfile) (struct inode *, struct dentry *, umode_t);
-} ____cacheline_aligned;
-                               struct file *, unsigned open_flag,
-                               umode_t create_mode, int *opened);
 };
 
 Again, all methods are called without any locks being held, unless
@@ -470,9 +468,11 @@ otherwise noted.
        method the filesystem can look up, possibly create and open the file in
        one atomic operation.  If it cannot perform this (e.g. the file type
        turned out to be wrong) it may signal this by returning 1 instead of
-       usual 0 or -ve .  This method is only called if the last
-       component is negative or needs lookup.  Cached positive dentries are
-       still handled by f_op->open().
+       usual 0 or -ve .  This method is only called if the last component is
+       negative or needs lookup.  Cached positive dentries are still handled by
+       f_op->open().  If the file was created, the FILE_CREATED flag should be
+       set in "opened".  In case of O_EXCL the method must only succeed if the
+       file didn't exist and hence FILE_CREATED shall always be set on success.
 
   tmpfile: called in the end of O_TMPFILE open().  Optional, equivalent to
        atomically creating, opening and unlinking a file in given directory.
index c858f8419ebafeeb7d700be52c919d6ee0770201..c420676c6fe31d3ac66c1b63f165888ccd0efd6e 100644 (file)
@@ -147,6 +147,7 @@ applicable everywhere (see syntax).
   - "modules"
     This declares the symbol to be used as the MODULES symbol, which
     enables the third modular state for all config symbols.
+    At most one symbol may have the "modules" option set.
 
   - "env"=<value>
     This imports the environment variable into Kconfig. It behaves like
index e349f293cc9829dc5cad185a41f95cb8627e90ea..8ef6dbb6a462d707401fe08289dfa51702125789 100644 (file)
@@ -175,11 +175,9 @@ Searching in menuconfig:
                /^hotplug
 
        When searching, symbols are sorted thus:
-         - exact match first: an exact match is when the search matches
-           the complete symbol name;
-         - alphabetical order: when two symbols do not match exactly,
-           they are sorted in alphabetical order (in the user's current
-           locale).
+         - first, exact matches, sorted alphabetically (an exact match
+           is when the search matches the complete symbol name);
+         - then, other matches, sorted alphabetically.
        For example: ^ATH.K matches:
            ATH5K ATH9K ATH5K_AHB ATH5K_DEBUG [...] ATH6KL ATH6KL_DEBUG
            [...] ATH9K_AHB ATH9K_BTCOEX_SUPPORT ATH9K_COMMON [...]
index 479eeaf440248b8d56dca90775be614b7cbc9e9e..1a036cd972fb0c205109ed66b968c3d771f66418 100644 (file)
@@ -1898,6 +1898,18 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        will be sent.
                        The default is to send the implementation identification
                        information.
+       
+       nfs.recover_lost_locks =
+                       [NFSv4] Attempt to recover locks that were lost due
+                       to a lease timeout on the server. Please note that
+                       doing this risks data corruption, since there are
+                       no guarantees that the file will remain unchanged
+                       after the locks are lost.
+                       If you want to enable the kernel legacy behaviour of
+                       attempting to recover these locks, then set this
+                       parameter to '1'.
+                       The default parameter value of '0' causes the kernel
+                       not to attempt recovery of lost locks.
 
        nfsd.nfs4_disable_idmapping=
                        [NFSv4] When set to the default of '1', the NFSv4
index 79e4c2e6e5e854639aa803e01683ae976eb4bdb2..d08d8c179f857e9973461b1d80892b9ed2b0ac2a 100644 (file)
@@ -18,7 +18,25 @@ All three channels can be also controlled using the engine micro programs.
 More details of the instructions can be found from the public data sheet.
 
 LP5521 has the internal program memory for running various LED patterns.
-For the details, please refer to 'firmware' section in leds-lp55xx.txt
+There are two ways to run LED patterns.
+
+1) Legacy interface - enginex_mode and enginex_load
+  Control interface for the engines:
+  x is 1 .. 3
+  enginex_mode : disabled, load, run
+  enginex_load : store program (visible only in engine load mode)
+
+  Example (start to blink the channel 2 led):
+  cd   /sys/class/leds/lp5521:channel2/device
+  echo "load" > engine3_mode
+  echo "037f4d0003ff6000" > engine3_load
+  echo "run" > engine3_mode
+
+  To stop the engine:
+  echo "disabled" > engine3_mode
+
+2) Firmware interface - LP55xx common interface
+  For the details, please refer to 'firmware' section in leds-lp55xx.txt
 
 sysfs contains a selftest entry.
 The test communicates with the chip and checks that
index 899fdad509fe81e97d1c18dc6e1dc7ad35471fdf..5b3e91d4ac5912011f0f4dfc59e1022f9ac24476 100644 (file)
@@ -28,7 +28,26 @@ If both fields are NULL, 'lp5523' is used by default.
 /sys/class/leds/lp5523:channelN  (N: 0 ~ 8)
 
 LP5523 has the internal program memory for running various LED patterns.
-For the details, please refer to 'firmware' section in leds-lp55xx.txt
+There are two ways to run LED patterns.
+
+1) Legacy interface - enginex_mode, enginex_load and enginex_leds
+  Control interface for the engines:
+  x is 1 .. 3
+  enginex_mode : disabled, load, run
+  enginex_load : microcode load (visible only in load mode)
+  enginex_leds : led mux control (visible only in load mode)
+
+  cd /sys/class/leds/lp5523:channel2/device
+  echo "load" > engine3_mode
+  echo "9d80400004ff05ff437f0000" > engine3_load
+  echo "111111111" > engine3_leds
+  echo "run" > engine3_mode
+
+  To stop the engine:
+  echo "disabled" > engine3_mode
+
+2) Firmware interface - LP55xx common interface
+  For the details, please refer to 'firmware' section in leds-lp55xx.txt
 
 Selftest uses always the current from the platform data.
 
index eec8fa2ffe4e5126cc63520d52f48f825ed81aca..82713ff92eb3e5c72a82ff6f1dc9d637e7f04376 100644 (file)
@@ -1,11 +1,11 @@
-LP5521/LP5523/LP55231 Common Driver
-===================================
+LP5521/LP5523/LP55231/LP5562/LP8501 Common Driver
+=================================================
 
 Authors: Milo(Woogyom) Kim <milo.kim@ti.com>
 
 Description
 -----------
-LP5521, LP5523/55231 and LP5562 have common features as below.
+LP5521, LP5523/55231, LP5562 and LP8501 have common features as below.
 
   Register access via the I2C
   Device initialization/deinitialization
@@ -109,6 +109,30 @@ As soon as 'loading' is set to 0, registered callback is called.
 Inside the callback, the selected engine is loaded and memory is updated.
 To run programmed pattern, 'run_engine' attribute should be enabled.
 
+The pattern sqeuence of LP8501 is same as LP5523.
+However pattern data is specific.
+Ex 1) Engine 1 is used
+echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
+echo 1 > /sys/class/firmware/lp8501/loading
+echo "9d0140ff7e0040007e00a001c000" > /sys/class/firmware/lp8501/data
+echo 0 > /sys/class/firmware/lp8501/loading
+echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
+
+Ex 2) Engine 2 and 3 are used at the same time
+echo 2 > /sys/bus/i2c/devices/xxxx/select_engine
+sleep 1
+echo 1 > /sys/class/firmware/lp8501/loading
+echo "9d0140ff7e0040007e00a001c000" > /sys/class/firmware/lp8501/data
+echo 0 > /sys/class/firmware/lp8501/loading
+sleep 1
+echo 3 > /sys/bus/i2c/devices/xxxx/select_engine
+sleep 1
+echo 1 > /sys/class/firmware/lp8501/loading
+echo "9d0340ff7e0040007e00a001c000" > /sys/class/firmware/lp8501/data
+echo 0 > /sys/class/firmware/lp8501/loading
+sleep 1
+echo 1 > /sys/class/leds/d1/device/run_engine
+
 ( 'run_engine' and 'firmware_cb' )
 The sequence of running the program data is common.
 But each device has own specific register addresses for commands.
index 18b64b2b8a682552b4c3fd08f607a817218615c5..f11580f8719a0cf6d939cbd0fd067c54bc9636db 100644 (file)
@@ -86,6 +86,8 @@ generic_netlink.txt
        - info on Generic Netlink
 gianfar.txt
        - Gianfar Ethernet Driver.
+i40e.txt
+       - README for the Intel Ethernet Controller XL710 Driver (i40e).
 ieee802154.txt
        - Linux IEEE 802.15.4 implementation, API and drivers
 igb.txt
index 87bbcfee2e067348c58aead44d54110112dd4a40..9b28e714831ae35fd0664debe4a1091825701024 100644 (file)
@@ -1362,6 +1362,12 @@ To add ARP targets:
 To remove an ARP target:
 # echo -192.168.0.100 > /sys/class/net/bond0/bonding/arp_ip_target
 
+To configure the interval between learning packet transmits:
+# echo 12 > /sys/class/net/bond0/bonding/lp_interval
+       NOTE: the lp_inteval is the number of seconds between instances where
+the bonding driver sends learning packets to each slaves peer switch.  The
+default interval is 1 second.
+
 Example Configuration
 ---------------------
        We begin with the same example that is shown in section 3.3,
diff --git a/Documentation/networking/i40e.txt b/Documentation/networking/i40e.txt
new file mode 100644 (file)
index 0000000..f737273
--- /dev/null
@@ -0,0 +1,115 @@
+Linux Base Driver for the Intel(R) Ethernet Controller XL710 Family
+===================================================================
+
+Intel i40e Linux driver.
+Copyright(c) 2013 Intel Corporation.
+
+Contents
+========
+
+- Identifying Your Adapter
+- Additional Configurations
+- Performance Tuning
+- Known Issues
+- Support
+
+
+Identifying Your Adapter
+========================
+
+The driver in this release is compatible with the Intel Ethernet
+Controller XL710 Family.
+
+For more information on how to identify your adapter, go to the Adapter &
+Driver ID Guide at:
+
+    http://support.intel.com/support/network/sb/CS-012904.htm
+
+
+Enabling the driver
+===================
+
+The driver is enabled via the standard kernel configuration system,
+using the make command:
+
+     Make oldconfig/silentoldconfig/menuconfig/etc.
+
+The driver is located in the menu structure at:
+
+       -> Device Drivers
+         -> Network device support (NETDEVICES [=y])
+           -> Ethernet driver support
+             -> Intel devices
+               -> Intel(R) Ethernet Controller XL710 Family
+
+Additional Configurations
+=========================
+
+  Generic Receive Offload (GRO)
+  -----------------------------
+  The driver supports the in-kernel software implementation of GRO.  GRO has
+  shown that by coalescing Rx traffic into larger chunks of data, CPU
+  utilization can be significantly reduced when under large Rx load.  GRO is
+  an evolution of the previously-used LRO interface.  GRO is able to coalesce
+  other protocols besides TCP.  It's also safe to use with configurations that
+  are problematic for LRO, namely bridging and iSCSI.
+
+  Ethtool
+  -------
+  The driver utilizes the ethtool interface for driver configuration and
+  diagnostics, as well as displaying statistical information. The latest
+  ethtool version is required for this functionality.
+
+  The latest release of ethtool can be found from
+  https://www.kernel.org/pub/software/network/ethtool
+
+  Data Center Bridging (DCB)
+  --------------------------
+  DCB configuration is not currently supported.
+
+  FCoE
+  ----
+  Fiber Channel over Ethernet (FCoE) hardware offload is not currently
+  supported.
+
+  MAC and VLAN anti-spoofing feature
+  ----------------------------------
+  When a malicious driver attempts to send a spoofed packet, it is dropped by
+  the hardware and not transmitted.  An interrupt is sent to the PF driver
+  notifying it of the spoof attempt.
+
+  When a spoofed packet is detected the PF driver will send the following
+  message to the system log (displayed by  the "dmesg" command):
+
+  Spoof event(s) detected on VF (n)
+
+  Where n=the VF that attempted to do the spoofing.
+
+
+Performance Tuning
+==================
+
+An excellent article on performance tuning can be found at:
+
+http://www.redhat.com/promo/summit/2008/downloads/pdf/Thursday/Mark_Wagner.pdf
+
+
+Known Issues
+============
+
+
+Support
+=======
+
+For general information, go to the Intel support website at:
+
+    http://support.intel.com
+
+or the Intel Wired Networking project hosted by Sourceforge at:
+
+    http://e1000.sourceforge.net
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related
+to the issue to e1000-devel@lists.sourceforge.net and copy
+netdev@vger.kernel.org.
index d529e02d928d4750c4acb6f3d6f7de4cf512d12f..f14f4930422224a64ea5e6be2575509e17229e12 100644 (file)
@@ -66,9 +66,7 @@ rq->cfs.load value, which is the sum of the weights of the tasks queued on the
 runqueue.
 
 CFS maintains a time-ordered rbtree, where all runnable tasks are sorted by the
-p->se.vruntime key (there is a subtraction using rq->cfs.min_vruntime to
-account for possible wraparounds).  CFS picks the "leftmost" task from this
-tree and sticks to it.
+p->se.vruntime key. CFS picks the "leftmost" task from this tree and sticks to it.
 As the system progresses forwards, the executed tasks are put into the tree
 more and more to the right --- slowly but surely giving a chance for every task
 to become the "leftmost task" and thus get on the CPU within a deterministic
index cc92ca8c8963e6953a6b09e68f38ecb3a6245ee8..6edaa65b0818218a046a0a0c11db88d1837b6a82 100644 (file)
@@ -1,3 +1,13 @@
+Release Date    : Sat. Aug 31, 2013 17:00:00 PST 2013 -
+                       (emaild-id:megaraidlinux@lsi.com)
+                       Adam Radford
+                       Kashyap Desai
+                       Sumit Saxena
+Current Version : 06.700.06.00-rc1
+Old Version     : 06.600.18.00-rc1
+    1. Add High Availability clustering support using shared Logical Disks.
+    2. Version and Changelog update.
+-------------------------------------------------------------------------------
 Release Date    : Wed. May 15, 2013 17:00:00 PST 2013 -
                        (emaild-id:megaraidlinux@lsi.com)
                        Adam Radford
index ab7d16efa96bf78bbfdddc029eb40b82da1e03fe..9d4c1d18ad447e0db3dbbbc9776a29e4c93450c0 100644 (file)
@@ -182,6 +182,7 @@ core_pattern is used to specify a core dumpfile pattern name.
        %<NUL>  '%' is dropped
        %%      output one '%'
        %p      pid
+       %P      global pid (init PID namespace)
        %u      uid
        %g      gid
        %d      dump mode, matches PR_SET_DUMPABLE and
index 36ecc26c74339519ce69c0138e88fb1ad3155010..79a797eb3e879ac2aac45e546c62bd504404e2eb 100644 (file)
@@ -200,17 +200,25 @@ 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
-create ZONE_MOVABLE for pages that may be reclaimed or migrated. Huge pages
-are not movable so are not normally allocated from ZONE_MOVABLE. A non-zero
-value written to hugepages_treat_as_movable allows huge pages to be allocated
-from ZONE_MOVABLE.
-
-Once enabled, the ZONE_MOVABLE is treated as an area of memory the huge
-pages pool can easily grow or shrink within. Assuming that applications are
-not running that mlock() a lot of memory, it is likely the huge pages pool
-can grow to the size of ZONE_MOVABLE by repeatedly entering the desired value
-into nr_hugepages and triggering page reclaim.
+This parameter controls whether we can allocate hugepages from ZONE_MOVABLE
+or not. If set to non-zero, hugepages can be allocated from ZONE_MOVABLE.
+ZONE_MOVABLE is created when kernel boot parameter kernelcore= is specified,
+so this parameter has no effect if used without kernelcore=.
+
+Hugepage migration is now available in some situations which depend on the
+architecture and/or the hugepage size. If a hugepage supports migration,
+allocation from ZONE_MOVABLE is always enabled for the hugepage regardless
+of the value of this parameter.
+IOW, this parameter affects only non-migratable hugepages.
+
+Assuming that hugepages are not migratable in your system, one usecase of
+this parameter is that users can make hugepage pool more extensible by
+enabling the allocation from ZONE_MOVABLE. This is because on ZONE_MOVABLE
+page reclaim/migration/compaction work more and you can get contiguous
+memory more likely. Note that using ZONE_MOVABLE for non-migratable
+hugepages can do harm to other features like memory hotremove (because
+memory hotremove expects that memory blocks on ZONE_MOVABLE are always
+removable,) so it's a trade-off responsible for the users.
 
 ==============================================================
 
index 2b46f67b1ccbfbc8ba0c8ec813e7c00f71d5582a..9010c441696743ec87bec451a71c2b1403c0fa37 100644 (file)
@@ -1,17 +1,17 @@
-Kernel driver exynos4_tmu
+Kernel driver exynos_tmu
 =================
 
 Supported chips:
-* ARM SAMSUNG EXYNOS4 series of SoC
-  Prefix: 'exynos4-tmu'
+* ARM SAMSUNG EXYNOS4, EXYNOS5 series of SoC
   Datasheet: Not publicly available
 
 Authors: Donggeun Kim <dg77.kim@samsung.com>
+Authors: Amit Daniel <amit.daniel@samsung.com>
 
-Description
------------
+TMU controller Description:
+---------------------------
 
-This driver allows to read temperature inside SAMSUNG EXYNOS4 series of SoC.
+This driver allows to read temperature inside SAMSUNG EXYNOS4/5 series of SoC.
 
 The chip only exposes the measured 8-bit temperature code value
 through a register.
@@ -34,9 +34,9 @@ The three equations are:
   TI2: Trimming info for 85 degree Celsius (stored at TRIMINFO register)
        Temperature code measured at 85 degree Celsius which is unchanged
 
-TMU(Thermal Management Unit) in EXYNOS4 generates interrupt
+TMU(Thermal Management Unit) in EXYNOS4/5 generates interrupt
 when temperature exceeds pre-defined levels.
-The maximum number of configurable threshold is four.
+The maximum number of configurable threshold is five.
 The threshold levels are defined as follows:
   Level_0: current temperature > trigger_level_0 + threshold
   Level_1: current temperature > trigger_level_1 + threshold
@@ -47,6 +47,31 @@ The threshold levels are defined as follows:
   through the corresponding registers.
 
 When an interrupt occurs, this driver notify kernel thermal framework
-with the function exynos4_report_trigger.
+with the function exynos_report_trigger.
 Although an interrupt condition for level_0 can be set,
 it can be used to synchronize the cooling action.
+
+TMU driver description:
+-----------------------
+
+The exynos thermal driver is structured as,
+
+                                       Kernel Core thermal framework
+                               (thermal_core.c, step_wise.c, cpu_cooling.c)
+                                                               ^
+                                                               |
+                                                               |
+TMU configuration data -------> TMU Driver  <------> Exynos Core thermal wrapper
+(exynos_tmu_data.c)          (exynos_tmu.c)       (exynos_thermal_common.c)
+(exynos_tmu_data.h)          (exynos_tmu.h)       (exynos_thermal_common.h)
+
+a) TMU configuration data: This consist of TMU register offsets/bitfields
+               described through structure exynos_tmu_registers. Also several
+               other platform data (struct exynos_tmu_platform_data) members
+               are used to configure the TMU.
+b) TMU driver: This component initialises the TMU controller and sets different
+               thresholds. It invokes core thermal implementation with the call
+               exynos_report_trigger.
+c) Exynos Core thermal wrapper: This provides 3 wrapper function to use the
+               Kernel core thermal framework. They are exynos_unregister_thermal,
+               exynos_register_thermal and exynos_report_trigger.
index a71bd5b90fe89ad68cc01d93e655bc7b79d69467..87519cb379ee45ade675499949ae91bf1051725d 100644 (file)
@@ -134,6 +134,13 @@ temperature) and throttle appropriate devices.
                this thermal zone and cdev, for a particular trip point.
                If nth bit is set, then the cdev and thermal zone are bound
                for trip point n.
+    .limits: This is an array of cooling state limits. Must have exactly
+         2 * thermal_zone.number_of_trip_points. It is an array consisting
+         of tuples <lower-state upper-state> of state limits. Each trip
+         will be associated with one state limit tuple when binding.
+         A NULL pointer means <THERMAL_NO_LIMITS THERMAL_NO_LIMITS>
+         on all trips. These limits are used when binding a cdev to a
+         trip point.
     .match: This call back returns success(0) if the 'tz and cdev' need to
            be bound, as per platform data.
 1.4.2 struct thermal_zone_params
@@ -142,6 +149,11 @@ temperature) and throttle appropriate devices.
     This is an optional feature where some platforms can choose not to
     provide this data.
     .governor_name: Name of the thermal governor used for this zone
+    .no_hwmon: a boolean to indicate if the thermal to hwmon sysfs interface
+               is required. when no_hwmon == false, a hwmon sysfs interface
+               will be created. when no_hwmon == true, nothing will be done.
+               In case the thermal_zone_params is NULL, the hwmon interface
+               will be created (for backward compatibility).
     .num_tbps: Number of thermal_bind_params entries for this zone
     .tbp: thermal_bind_params entries
 
index d7993dcf8537c657f0ad635410a25698d7b8d584..b9ca02370d466762310ed9415babf364355d5468 100644 (file)
@@ -167,8 +167,8 @@ group and can access them as follows:
        int container, group, device, i;
        struct vfio_group_status group_status =
                                        { .argsz = sizeof(group_status) };
-       struct vfio_iommu_x86_info iommu_info = { .argsz = sizeof(iommu_info) };
-       struct vfio_iommu_x86_dma_map dma_map = { .argsz = sizeof(dma_map) };
+       struct vfio_iommu_type1_info iommu_info = { .argsz = sizeof(iommu_info) };
+       struct vfio_iommu_type1_dma_map dma_map = { .argsz = sizeof(dma_map) };
        struct vfio_device_info device_info = { .argsz = sizeof(device_info) };
 
        /* Create a new container */
@@ -193,7 +193,7 @@ group and can access them as follows:
        ioctl(group, VFIO_GROUP_SET_CONTAINER, &container);
 
        /* Enable the IOMMU model we want */
-       ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU)
+       ioctl(container, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU);
 
        /* Get addition IOMMU info */
        ioctl(container, VFIO_IOMMU_GET_INFO, &iommu_info);
@@ -229,7 +229,7 @@ group and can access them as follows:
 
                irq.index = i;
 
-               ioctl(device, VFIO_DEVICE_GET_IRQ_INFO, &reg);
+               ioctl(device, VFIO_DEVICE_GET_IRQ_INFO, &irq);
 
                /* Setup IRQs... eventfds, VFIO_DEVICE_SET_IRQS */
        }
index 4ac359b7aa176d1d1b61a100bc196332d842029b..bdd4bb97fff709114f8374082b670e9f32ade7f9 100644 (file)
@@ -165,6 +165,7 @@ which function as described above for the default huge page-sized case.
 
 
 Interaction of Task Memory Policy with Huge Page Allocation/Freeing
+===================================================================
 
 Whether huge pages are allocated and freed via the /proc interface or
 the /sysfs interface using the nr_hugepages_mempolicy attribute, the NUMA
@@ -229,6 +230,7 @@ resulting effect on persistent huge page allocation is as follows:
    of huge pages over all on-lines nodes with memory.
 
 Per Node Hugepages Attributes
+=============================
 
 A subset of the contents of the root huge page control directory in sysfs,
 described above, will be replicated under each the system device of each
@@ -258,6 +260,7 @@ applied, from which node the huge page allocation will be attempted.
 
 
 Using Huge Pages
+================
 
 If the user applications are going to request huge pages using mmap system
 call, then it is required that system administrator mount a file system of
@@ -296,20 +299,16 @@ calls, though the mount of filesystem will be required for using mmap calls
 without MAP_HUGETLB.  For an example of how to use mmap with MAP_HUGETLB see
 map_hugetlb.c.
 
-*******************************************************************
+Examples
+========
 
-/*
- * map_hugetlb: see tools/testing/selftests/vm/map_hugetlb.c
- */
+1) map_hugetlb: see tools/testing/selftests/vm/map_hugetlb.c
 
-*******************************************************************
+2) hugepage-shm:  see tools/testing/selftests/vm/hugepage-shm.c
 
-/*
- * hugepage-shm:  see tools/testing/selftests/vm/hugepage-shm.c
- */
+3) hugepage-mmap:  see tools/testing/selftests/vm/hugepage-mmap.c
 
-*******************************************************************
-
-/*
- * hugepage-mmap:  see tools/testing/selftests/vm/hugepage-mmap.c
- */
+4) The libhugetlbfs (http://libhugetlbfs.sourceforge.net) library provides a
+   wide range of userspace tools to help with huge page usability, environment
+   setup, and control. Furthermore it provides useful test cases that should be
+   used when modifying code to ensure no regressions are introduced.
index 9a12a5956bc05cae45367e78e759655c924df30c..55684d11a1e806c9ee998649f9d75f88662a08df 100644 (file)
@@ -28,6 +28,13 @@ This is so, since the pages are still mapped to physical memory, and thus all
 the kernel does is finds this fact out and puts both writable and soft-dirty
 bits on the PTE.
 
+  While in most cases tracking memory changes by #PF-s is more than enough
+there is still a scenario when we can lose soft dirty bits -- a task
+unmaps a previously mapped memory region and then maps a new one at exactly
+the same place. When unmap is called, the kernel internally clears PTE values
+including soft dirty bits. To notify user space application about such
+memory region renewal the kernel always marks new memory regions (and
+expanded regions) as soft dirty.
 
   This feature is actively used by the checkpoint-restore project. You
 can find more details about it on http://criu.org
index b6b29c38b6b67d5c950188da793f35696e00e7be..da6cf1676f2ccadbfd08dee0348eba9b482b02be 100644 (file)
@@ -933,24 +933,24 @@ F:        arch/arm/mach-pxa/colibri-pxa270-income.c
 
 ARM/INTEL IOP32X ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IOP33X ARM ARCHITECTURE
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IOP13XX ARM ARCHITECTURE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
 ARM/INTEL IQ81342EX MACHINE SUPPORT
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -975,7 +975,7 @@ F:  drivers/pcmcia/pxa2xx_stargate2.c
 
 ARM/INTEL XSC3 (MANZANO) ARM CORE
 M:     Lennert Buytenhek <kernel@wantstofly.org>
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 
@@ -1028,7 +1028,7 @@ F:        arch/arm/mach-orion5x/ts78xx-*
 ARM/MICREL KS8695 ARCHITECTURE
 M:     Greg Ungerer <gerg@uclinux.org>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-F:     arch/arm/mach-ks8695
+F:     arch/arm/mach-ks8695/
 S:     Odd Fixes
 
 ARM/MIOA701 MACHINE SUPPORT
@@ -1048,7 +1048,6 @@ M:        STEricsson <STEricsson_nomadik_linux@list.st.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-nomadik/
-F:     arch/arm/plat-nomadik/
 F:     drivers/i2c/busses/i2c-nomadik.c
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-nomadik.git
 
@@ -1070,7 +1069,7 @@ F:        drivers/mmc/host/msm_sdcc.h
 F:     drivers/tty/serial/msm_serial.h
 F:     drivers/tty/serial/msm_serial.c
 F:     drivers/*/pm8???-*
-F:     drivers/ssbi/
+F:     drivers/mfd/ssbi/
 F:     include/linux/mfd/pm8xxx/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/davidb/linux-msm.git
 S:     Maintained
@@ -1156,7 +1155,6 @@ L:        linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
 W:     http://www.fluff.org/ben/linux/
 S:     Maintained
 F:     arch/arm/plat-samsung/
-F:     arch/arm/plat-s3c24xx/
 F:     arch/arm/mach-s3c24*/
 F:     arch/arm/mach-s3c64xx/
 F:     drivers/*/*s3c2410*
@@ -1179,8 +1177,6 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
 F:     arch/arm/mach-s5pv210/mach-aquila.c
 F:     arch/arm/mach-s5pv210/mach-goni.c
-F:     arch/arm/mach-exynos/mach-universal_c210.c
-F:     arch/arm/mach-exynos/mach-nuri.c
 
 ARM/SAMSUNG S5P SERIES 2D GRAPHICS ACCELERATION (G2D) SUPPORT
 M:     Kyungmin Park <kyungmin.park@samsung.com>
@@ -1325,7 +1321,7 @@ F:        drivers/mmc/host/wmt-sdmmc.c
 F:     drivers/pwm/pwm-vt8500.c
 F:     drivers/rtc/rtc-vt8500.c
 F:     drivers/tty/serial/vt8500_serial.c
-F:     drivers/usb/host/ehci-vt8500.c
+F:     drivers/usb/host/ehci-platform.c
 F:     drivers/usb/host/uhci-platform.c
 F:     drivers/video/vt8500lcdfb.*
 F:     drivers/video/wm8505fb*
@@ -1386,7 +1382,7 @@ F:        drivers/platform/x86/asus*.c
 F:     drivers/platform/x86/eeepc*.c
 
 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 W:     http://sourceforge.net/projects/xscaleiop
 S:     Maintained
 F:     Documentation/crypto/async-tx-api.txt
@@ -1815,6 +1811,17 @@ L:       netdev@vger.kernel.org
 S:     Supported
 F:     drivers/net/ethernet/broadcom/bnx2x/
 
+BROADCOM BCM281XX/BCM11XXX ARM ARCHITECTURE
+M:     Christian Daudt <csd@broadcom.com>
+T:     git git://git.github.com/broadcom/bcm11351
+S:     Maintained
+F:     arch/arm/mach-bcm/
+F:     arch/arm/boot/dts/bcm113*
+F:     arch/arm/boot/dts/bcm281*
+F:     arch/arm/configs/bcm_defconfig
+F:     drivers/mmc/host/sdhci_bcm_kona.c
+F:     drivers/clocksource/bcm_kona_timer.c
+
 BROADCOM BCM2835 ARM ARCHICTURE
 M:     Stephen Warren <swarren@wwwdotorg.org>
 L:     linux-rpi-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -2035,10 +2042,10 @@ W:      http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
 S:     Supported
 F:     Documentation/filesystems/ceph.txt
-F:     fs/ceph
-F:     net/ceph
-F:     include/linux/ceph
-F:     include/linux/crush
+F:     fs/ceph/
+F:     net/ceph/
+F:     include/linux/ceph/
+F:     include/linux/crush/
 
 CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
 L:     linux-usb@vger.kernel.org
@@ -2307,6 +2314,15 @@ F:       drivers/cpufreq/arm_big_little.h
 F:     drivers/cpufreq/arm_big_little.c
 F:     drivers/cpufreq/arm_big_little_dt.c
 
+CPUIDLE DRIVER - ARM BIG LITTLE
+M:      Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+M:      Daniel Lezcano <daniel.lezcano@linaro.org>
+L:      linux-pm@vger.kernel.org
+L:      linux-arm-kernel@lists.infradead.org
+T:      git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
+S:      Maintained
+F:      drivers/cpuidle/cpuidle-big_little.c
+
 CPUIDLE DRIVERS
 M:     Rafael J. Wysocki <rjw@sisk.pl>
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
@@ -2326,7 +2342,7 @@ CPU POWER MONITORING SUBSYSTEM
 M:     Dominik Brodowski <linux@dominikbrodowski.net>
 M:     Thomas Renninger <trenn@suse.de>
 S:     Maintained
-F:     tools/power/cpupower
+F:     tools/power/cpupower/
 
 CPUSETS
 M:     Li Zefan <lizefan@huawei.com>
@@ -2682,7 +2698,7 @@ T:        git git://git.linaro.org/people/sumitsemwal/linux-dma-buf.git
 
 DMA GENERIC OFFLOAD ENGINE SUBSYSTEM
 M:     Vinod Koul <vinod.koul@intel.com>
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 S:     Supported
 F:     drivers/dma/
 F:     include/linux/dma*
@@ -2764,7 +2780,7 @@ L:        intel-gfx@lists.freedesktop.org
 L:     dri-devel@lists.freedesktop.org
 T:     git git://people.freedesktop.org/~danvet/drm-intel
 S:     Supported
-F:     drivers/gpu/drm/i915
+F:     drivers/gpu/drm/i915/
 F:     include/drm/i915*
 F:     include/uapi/drm/i915*
 
@@ -2776,7 +2792,7 @@ M:        Kyungmin Park <kyungmin.park@samsung.com>
 L:     dri-devel@lists.freedesktop.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos.git
 S:     Supported
-F:     drivers/gpu/drm/exynos
+F:     drivers/gpu/drm/exynos/
 F:     include/drm/exynos*
 F:     include/uapi/drm/exynos*
 
@@ -3029,7 +3045,7 @@ M:        Mauro Carvalho Chehab <m.chehab@samsung.com>
 L:     linux-edac@vger.kernel.org
 W:     bluesmoke.sourceforge.net
 S:     Maintained
-F:     drivers/edac/ghes-edac.c
+F:     drivers/edac/ghes_edac.c
 
 EDAC-I82443BXGX
 M:     Tim Small <tim@buttersideup.com>
@@ -3635,8 +3651,8 @@ M:        Arnd Bergmann <arnd@arndb.de>
 L:     linux-arch@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/arnd/asm-generic.git
 S:     Maintained
-F:     include/asm-generic
-F:     include/uapi/asm-generic
+F:     include/asm-generic/
+F:     include/uapi/asm-generic/
 
 GENERIC UIO DRIVER FOR PCI DEVICES
 M:     "Michael S. Tsirkin" <mst@redhat.com>
@@ -3678,7 +3694,8 @@ GRE DEMULTIPLEXER DRIVER
 M:     Dmitry Kozlov <xeb@mail.ru>
 L:     netdev@vger.kernel.org
 S:     Maintained
-F:     net/ipv4/gre.c
+F:     net/ipv4/gre_demux.c
+F:     net/ipv4/gre_offload.c
 F:     include/net/gre.h
 
 GRETH 10/100/1G Ethernet MAC device driver
@@ -3756,7 +3773,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 W:     http://linuxtv.org
 S:     Odd Fixes
-F:     drivers/media/usb/hdpvr
+F:     drivers/media/usb/hdpvr/
 
 HWPOISON MEMORY FAILURE HANDLING
 M:     Andi Kleen <andi@firstfloor.org>
@@ -4314,7 +4331,7 @@ F:        arch/x86/kernel/microcode_core.c
 F:     arch/x86/kernel/microcode_intel.c
 
 INTEL I/OAT DMA DRIVER
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 S:     Maintained
 F:     drivers/dma/ioat*
 
@@ -4327,7 +4344,7 @@ F:        drivers/iommu/intel-iommu.c
 F:     include/linux/intel-iommu.h
 
 INTEL IOP-ADMA DMA DRIVER
-M:     Dan Williams <djbw@fb.com>
+M:     Dan Williams <dan.j.williams@intel.com>
 S:     Odd fixes
 F:     drivers/dma/iop-adma.c
 
@@ -4346,7 +4363,7 @@ M:        Deepak Saxena <dsaxena@plexity.net>
 S:     Maintained
 F:     drivers/char/hw_random/ixp4xx-rng.c
 
-INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe/ixgbevf)
+INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/igbvf/ixgb/ixgbe/ixgbevf/i40e)
 M:     Jeff Kirsher <jeffrey.t.kirsher@intel.com>
 M:     Jesse Brandeburg <jesse.brandeburg@intel.com>
 M:     Bruce Allan <bruce.w.allan@intel.com>
@@ -4371,6 +4388,7 @@ F:        Documentation/networking/igbvf.txt
 F:     Documentation/networking/ixgb.txt
 F:     Documentation/networking/ixgbe.txt
 F:     Documentation/networking/ixgbevf.txt
+F:     Documentation/networking/i40e.txt
 F:     drivers/net/ethernet/intel/
 
 INTEL PRO/WIRELESS 2100, 2200BG, 2915ABG NETWORK CONNECTION SUPPORT
@@ -4564,7 +4582,7 @@ S:        Supported
 W:     http://www.openfabrics.org
 W:     www.open-iscsi.org
 Q:     http://patchwork.kernel.org/project/linux-rdma/list/
-F:     drivers/infiniband/ulp/iser
+F:     drivers/infiniband/ulp/iser/
 
 ISDN SUBSYSTEM
 M:     Karsten Keil <isdn@linux-pingi.de>
@@ -4618,7 +4636,7 @@ W:        http://palosaari.fi/linux/
 Q:     http://patchwork.linuxtv.org/project/linux-media/list/
 T:     git git://linuxtv.org/anttip/media_tree.git
 S:     Maintained
-F:     drivers/media/tuners/it913x*
+F:     drivers/media/tuners/tuner_it913x*
 
 IVTV VIDEO4LINUX DRIVER
 M:     Andy Walls <awalls@md.metrocast.net>
@@ -5442,6 +5460,7 @@ F:        drivers/watchdog/mena21_wdt.c
 
 METAG ARCHITECTURE
 M:     James Hogan <james.hogan@imgtec.com>
+L:     linux-metag@vger.kernel.org
 S:     Supported
 F:     arch/metag/
 F:     Documentation/metag/
@@ -5889,6 +5908,8 @@ F:        drivers/scsi/nsp32*
 NTB DRIVER
 M:     Jon Mason <jon.mason@intel.com>
 S:     Supported
+W:     https://github.com/jonmason/ntb/wiki
+T:     git git://github.com/jonmason/ntb.git
 F:     drivers/ntb/
 F:     drivers/net/ntb_netdev.c
 F:     include/linux/ntb.h
@@ -5951,15 +5972,12 @@ S:      Maintained
 F:     arch/arm/*omap*/*pm*
 F:     drivers/cpufreq/omap-cpufreq.c
 
-OMAP POWERDOMAIN/CLOCKDOMAIN SOC ADAPTATION LAYER SUPPORT
+OMAP POWERDOMAIN SOC ADAPTATION LAYER SUPPORT
 M:     Rajendra Nayak <rnayak@ti.com>
 M:     Paul Walmsley <paul@pwsan.com>
 L:     linux-omap@vger.kernel.org
 S:     Maintained
-F:     arch/arm/mach-omap2/powerdomain2xxx_3xxx.c
-F:     arch/arm/mach-omap2/powerdomain44xx.c
-F:     arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
-F:     arch/arm/mach-omap2/clockdomain44xx.c
+F:     arch/arm/mach-omap2/prm*
 
 OMAP AUDIO SUPPORT
 M:     Peter Ujfalusi <peter.ujfalusi@ti.com>
@@ -6125,7 +6143,7 @@ W:        http://openrisc.net
 L:     linux@lists.openrisc.net (moderated for non-subscribers)
 S:     Maintained
 T:     git git://openrisc.net/~jonas/linux
-F:     arch/openrisc
+F:     arch/openrisc/
 
 OPENVSWITCH
 M:     Jesse Gross <jesse@nicira.com>
@@ -6416,7 +6434,7 @@ M:        Jamie Iles <jamie@jamieiles.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/jamieiles/linux-2.6-ji.git
 S:     Supported
-F:     arch/arm/mach-picoxcell
+F:     arch/arm/mach-picoxcell/
 F:     drivers/*/picoxcell*
 F:     drivers/*/*/picoxcell*
 
@@ -6689,7 +6707,7 @@ F:        drivers/spi/spi-pxa2xx*
 F:     drivers/usb/gadget/pxa2*
 F:     include/sound/pxa2xx-lib.h
 F:     sound/arm/pxa*
-F:     sound/soc/pxa
+F:     sound/soc/pxa/
 
 MMP SUPPORT
 M:     Eric Miao <eric.y.miao@gmail.com>
@@ -6798,6 +6816,14 @@ L:       linux-hexagon@vger.kernel.org
 S:     Supported
 F:     arch/hexagon/
 
+QUALCOMM WCN36XX WIRELESS DRIVER
+M:     Eugene Krasnikov <k.eugene.e@gmail.com>
+L:     wcn36xx@lists.infradead.org
+W:     http://wireless.kernel.org/en/users/Drivers/wcn36xx
+T:     git git://github.com/KrasnikovEugene/wcn36xx.git
+S:     Supported
+F:     drivers/net/wireless/ath/wcn36xx/
+
 QUICKCAM PARALLEL PORT WEBCAMS
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 L:     linux-media@vger.kernel.org
@@ -7142,7 +7168,7 @@ SAMSUNG AUDIO (ASoC) DRIVERS
 M:     Sangbeom Kim <sbkim73@samsung.com>
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 S:     Supported
-F:     sound/soc/samsung
+F:     sound/soc/samsung/
 
 SAMSUNG FRAMEBUFFER DRIVER
 M:     Jingoo Han <jg1.han@samsung.com>
@@ -7188,10 +7214,11 @@ SERIAL DRIVERS
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 L:     linux-serial@vger.kernel.org
 S:     Maintained
-F:     drivers/tty/serial
+F:     drivers/tty/serial/
 
 SYNOPSYS DESIGNWARE DMAC DRIVER
 M:     Viresh Kumar <viresh.linux@gmail.com>
+M:     Andy Shevchenko <andriy.shevchenko@linux.intel.com>
 S:     Maintained
 F:     include/linux/dw_dmac.h
 F:     drivers/dma/dw/
@@ -7222,7 +7249,7 @@ TLG2300 VIDEO4LINUX-2 DRIVER
 M:     Huang Shijie <shijie8@gmail.com>
 M:     Hans Verkuil <hverkuil@xs4all.nl>
 S:     Odd Fixes
-F:     drivers/media/usb/tlg2300
+F:     drivers/media/usb/tlg2300/
 
 SC1200 WDT DRIVER
 M:     Zwane Mwaikambo <zwane@arm.linux.org.uk>
@@ -7483,7 +7510,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 W:     http://linuxtv.org
 S:     Odd Fixes
-F:     drivers/media/radio/radio-si4713.h
+F:     drivers/media/radio/radio-si4713.c
 
 SIANO DVB DRIVER
 M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
@@ -7492,9 +7519,9 @@ W:        http://linuxtv.org
 T:     git git://linuxtv.org/media_tree.git
 S:     Odd fixes
 F:     drivers/media/common/siano/
-F:     drivers/media/dvb/siano/
 F:     drivers/media/usb/siano/
-F:     drivers/media/mmc/siano
+F:     drivers/media/usb/siano/
+F:     drivers/media/mmc/siano/
 
 SH_VEU V4L2 MEM2MEM DRIVER
 M:     Guennadi Liakhovetski <g.liakhovetski@gmx.de>
@@ -7532,9 +7559,9 @@ P:        Vincent Sanders <vince@simtec.co.uk>
 M:     Simtec Linux Team <linux@simtec.co.uk>
 W:     http://www.simtec.co.uk/products/EB2410ITX/
 S:     Supported
-F:     arch/arm/mach-s3c2410/mach-bast.c
-F:     arch/arm/mach-s3c2410/bast-ide.c
-F:     arch/arm/mach-s3c2410/bast-irq.c
+F:     arch/arm/mach-s3c24xx/mach-bast.c
+F:     arch/arm/mach-s3c24xx/bast-ide.c
+F:     arch/arm/mach-s3c24xx/bast-irq.c
 
 TI DAVINCI MACHINE SUPPORT
 M:     Sekhar Nori <nsekhar@ti.com>
@@ -7543,7 +7570,7 @@ L:        davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers
 T:     git git://gitorious.org/linux-davinci/linux-davinci.git
 Q:     http://patchwork.kernel.org/project/linux-davinci/list/
 S:     Supported
-F:     arch/arm/mach-davinci
+F:     arch/arm/mach-davinci/
 F:     drivers/i2c/busses/i2c-davinci.c
 
 TI DAVINCI SERIES MEDIA DRIVER
@@ -7611,6 +7638,14 @@ S:       Maintained
 F:     Documentation/security/Smack.txt
 F:     security/smack/
 
+SMARTREFLEX DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
+M:     Kevin Hilman <khilman@kernel.org>
+M:     Nishanth Menon <nm@ti.com>
+S:     Maintained
+F:     drivers/power/avs/smartreflex.c
+F:     include/linux/power/smartreflex.h
+L:     linux-pm@vger.kernel.org
+
 SMC91x ETHERNET DRIVER
 M:     Nicolas Pitre <nico@fluxnic.net>
 S:     Odd Fixes
@@ -7620,7 +7655,7 @@ SMIA AND SMIA++ IMAGE SENSOR DRIVER
 M:     Sakari Ailus <sakari.ailus@iki.fi>
 L:     linux-media@vger.kernel.org
 S:     Maintained
-F:     drivers/media/i2c/smiapp
+F:     drivers/media/i2c/smiapp/
 F:     include/media/smiapp.h
 F:     drivers/media/i2c/smiapp-pll.c
 F:     drivers/media/i2c/smiapp-pll.h
@@ -7723,6 +7758,11 @@ W:       http://tifmxx.berlios.de/
 S:     Maintained
 F:     drivers/memstick/host/tifm_ms.c
 
+SONY MEMORYSTICK STANDARD SUPPORT
+M:     Maxim Levitsky <maximlevitsky@gmail.com>
+S:     Maintained
+F:     drivers/memstick/core/ms_block.*
+
 SOUND
 M:     Jaroslav Kysela <perex@perex.cz>
 M:     Takashi Iwai <tiwai@suse.de>
@@ -7799,35 +7839,7 @@ L:       spear-devel@list.st.com
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 W:     http://www.st.com/spear
 S:     Maintained
-F:     arch/arm/plat-spear/
-
-SPEAR13XX MACHINE SUPPORT
-M:     Viresh Kumar <viresh.linux@gmail.com>
-M:     Shiraz Hashim <shiraz.hashim@st.com>
-L:     spear-devel@list.st.com
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.st.com/spear
-S:     Maintained
-F:     arch/arm/mach-spear13xx/
-
-SPEAR3XX MACHINE SUPPORT
-M:     Viresh Kumar <viresh.linux@gmail.com>
-M:     Shiraz Hashim <shiraz.hashim@st.com>
-L:     spear-devel@list.st.com
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.st.com/spear
-S:     Maintained
-F:     arch/arm/mach-spear3xx/
-
-SPEAR6XX MACHINE SUPPORT
-M:     Rajeev Kumar <rajeev-dlh.kumar@st.com>
-M:     Shiraz Hashim <shiraz.hashim@st.com>
-M:     Viresh Kumar <viresh.linux@gmail.com>
-L:     spear-devel@list.st.com
-L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-W:     http://www.st.com/spear
-S:     Maintained
-F:     arch/arm/mach-spear6xx/
+F:     arch/arm/mach-spear/
 
 SPEAR CLOCK FRAMEWORK SUPPORT
 M:     Viresh Kumar <viresh.linux@gmail.com>
@@ -8096,7 +8108,7 @@ M:        Vineet Gupta <vgupta@synopsys.com>
 S:     Supported
 F:     arch/arc/
 F:     Documentation/devicetree/bindings/arc/
-F:     drivers/tty/serial/arc-uart.c
+F:     drivers/tty/serial/arc_uart.c
 
 SYSV FILESYSTEM
 M:     Christoph Hellwig <hch@infradead.org>
@@ -8786,7 +8798,6 @@ L:        linux-usb@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
 S:     Maintained
 F:     drivers/usb/phy/
-F:     drivers/usb/otg/
 
 USB PRINTER DRIVER (usblp)
 M:     Pete Zaitcev <zaitcev@redhat.com>
@@ -9317,7 +9328,7 @@ M:        Matthew Garrett <matthew.garrett@nebula.com>
 L:     platform-driver-x86@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86.git
 S:     Maintained
-F:     drivers/platform/x86
+F:     drivers/platform/x86/
 
 X86 MCE INFRASTRUCTURE
 M:     Tony Luck <tony.luck@intel.com>
index fe8204be566d3fbd23e847ceddd368df0f37450c..de004ceb6b5e32d65e4b21c77855806bf709bbfc 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
 VERSION = 3
-PATCHLEVEL = 11
+PATCHLEVEL = 12
 SUBLEVEL = 0
-EXTRAVERSION =
-NAME = Linux for Workgroups
+EXTRAVERSION = -rc1
+NAME = One Giant Leap for Frogkind
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -794,10 +794,13 @@ PHONY += $(vmlinux-dirs)
 $(vmlinux-dirs): prepare scripts
        $(Q)$(MAKE) $(build)=$@
 
+define filechk_kernel.release
+       echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))"
+endef
+
 # Store (new) KERNELRELEASE string in include/config/kernel.release
 include/config/kernel.release: include/config/auto.conf FORCE
-       $(Q)rm -f $@
-       $(Q)echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" > $@
+       $(call filechk,kernel.release)
 
 
 # Things we need to do before we recursively start building the kernel
index 082d9b4b54723d0253e7ca3355387886b81f72f4..35a300d4a9fb37f3a08e3f63365c72bcc2a3ecbf 100644 (file)
@@ -7,7 +7,6 @@ config ALPHA
        select HAVE_PCSPKR_PLATFORM
        select HAVE_PERF_EVENTS
        select HAVE_DMA_ATTRS
-       select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_PROBE
        select AUTO_IRQ_AFFINITY if SMP
index 40736da9bea87aef7d5e43e4af8672d46a58ef9e..ffb19b7da999c67722d5690dcfcd6ef0d74123f8 100644 (file)
@@ -338,6 +338,11 @@ csum_partial_copy_from_user(const void __user *src, void *dst, int len,
        unsigned long doff = 7 & (unsigned long) dst;
 
        if (len) {
+               if (!access_ok(VERIFY_READ, src, len)) {
+                       *errp = -EFAULT;
+                       memset(dst, 0, len);
+                       return sum;
+               }
                if (!doff) {
                        if (!soff)
                                checksum = csum_partial_cfu_aligned(
index 0c4132dd3507a0b62b3c40c2fc6fd4065a325262..98838a05ba6d89f0459742131010f57c38cbed05 100644 (file)
@@ -89,8 +89,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
        const struct exception_table_entry *fixup;
        int fault, si_code = SEGV_MAPERR;
        siginfo_t info;
-       unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                             (cause > 0 ? FAULT_FLAG_WRITE : 0));
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        /* As of EV6, a load into $31/$f31 is a prefetch, and never faults
           (or is suppressed by the PALcode).  Support that for older CPUs
@@ -115,7 +114,8 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
        if (address >= TASK_SIZE)
                goto vmalloc_fault;
 #endif
-
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -142,6 +142,7 @@ retry:
        } else {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        }
 
        /* If for any reason at all we couldn't handle the fault,
index 68fcbb2d59e2abbaac1691652865f33f78949753..91dbb2757afd1d352d38faae2924c8861e435631 100644 (file)
@@ -20,7 +20,6 @@ config ARC
        select GENERIC_SMP_IDLE_THREAD
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_IOREMAP_PROT
        select HAVE_KPROBES
        select HAVE_KRETPROBES
diff --git a/arch/arc/boot/.gitignore b/arch/arc/boot/.gitignore
new file mode 100644 (file)
index 0000000..5d65b54
--- /dev/null
@@ -0,0 +1 @@
+*.dtb*
index 5802849a6caefa802b2a1d8cc6d26e845444767e..e4abdaac6f9fead2fc27807602090937d20addae 100644 (file)
@@ -57,7 +57,7 @@
 
 extern void arc_cache_init(void);
 extern char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len);
-extern void __init read_decode_cache_bcr(void);
+extern void read_decode_cache_bcr(void);
 
 #endif /* !__ASSEMBLY__ */
 
index 442ce5d0f7091f62740a1b32c13b30553c648ac0..43de302569815073bb4d4f23cb98b60a5e0c0552 100644 (file)
@@ -53,11 +53,10 @@ static inline void __udelay(unsigned long usecs)
 {
        unsigned long loops;
 
-       /* (long long) cast ensures 64 bit MPY - real or emulated
+       /* (u64) cast ensures 64 bit MPY - real or emulated
         * HZ * 4295 is pre-evaluated by gcc - hence only 2 mpy ops
         */
-       loops = ((long long)(usecs * 4295 * HZ) *
-                (long long)(loops_per_jiffy)) >> 32;
+       loops = ((u64) usecs * 4295 * HZ * loops_per_jiffy) >> 32;
 
        __delay(loops);
 }
index df57611652e50b73322a6eaf7005598684208d4a..884081099f800fd6b4ba133bc1f1746084845c49 100644 (file)
  * it to memory (non-SMP case) or SCRATCH0 Aux Reg (SMP).
  *
  * Before saving the full regfile - this reg is restored back, only
- * to be saved again on kernel mode stack, as part of ptregs.
+ * to be saved again on kernel mode stack, as part of pt_regs.
  *-------------------------------------------------------------*/
 .macro EXCPN_PROLOG_FREEUP_REG reg
 #ifdef CONFIG_SMP
 #endif
 .endm
 
+/*--------------------------------------------------------------
+ * Exception Entry prologue
+ * -Switches stack to K mode (if not already)
+ * -Saves the register file
+ *
+ * After this it is safe to call the "C" handlers
+ *-------------------------------------------------------------*/
+.macro EXCEPTION_PROLOGUE
+
+       /* Need at least 1 reg to code the early exception prologue */
+       EXCPN_PROLOG_FREEUP_REG r9
+
+       /* U/K mode at time of exception (stack not switched if already K) */
+       lr  r9, [erstatus]
+
+       /* ARC700 doesn't provide auto-stack switching */
+       SWITCH_TO_KERNEL_STK
+
+       /* save the regfile */
+       SAVE_ALL_SYS
+.endm
+
 /*--------------------------------------------------------------
  * Save all registers used by Exceptions (TLB Miss, Prot-V, Mem err etc)
  * Requires SP to be already switched to kernel mode Stack
index 473424d7528bd344985f3616e641f9823db24aa9..334ce7017a18e937961e81c00b97acfc9779b316 100644 (file)
@@ -100,6 +100,10 @@ static inline void __raw_writel(u32 w, volatile void __iomem *addr)
 
 }
 
+#define readb_relaxed readb
+#define readw_relaxed readw
+#define readl_relaxed readl
+
 #include <asm-generic/io.h>
 
 #endif /* _ASM_ARC_IO_H */
index d99f79bcf865a248ddb1c1dfa1eb35a58ae5f948..b68b53f458d1bc07f89b5b64c8f9fd9dc84ba323 100644 (file)
@@ -157,13 +157,6 @@ static inline void arch_unmask_irq(unsigned int irq)
        flag    \scratch
 .endm
 
-.macro IRQ_DISABLE_SAVE  scratch, save
-       lr      \scratch, [status32]
-       mov     \save, \scratch         /* Make a copy */
-       bic     \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
-       flag    \scratch
-.endm
-
 .macro IRQ_ENABLE  scratch
        lr      \scratch, [status32]
        or      \scratch, \scratch, (STATUS_E1_MASK | STATUS_E2_MASK)
index 7c03fe61759c2262d30550cfc6ad73dd363b2903..c2663b32866b5c142dfd5c8642320dd5446fc1ea 100644 (file)
@@ -32,6 +32,8 @@
 /* Error code if probe fails */
 #define TLB_LKUP_ERR           0x80000000
 
+#define TLB_DUP_ERR    (TLB_LKUP_ERR | 0x00000001)
+
 /* TLB Commands */
 #define TLBWrite    0x1
 #define TLBRead     0x2
 #ifndef __ASSEMBLY__
 
 typedef struct {
-       unsigned long asid;     /* Pvt Addr-Space ID for mm */
-#ifdef CONFIG_ARC_TLB_DBG
-       struct task_struct *tsk;
-#endif
+       unsigned long asid;     /* 8 bit MMU PID + Generation cycle */
 } mm_context_t;
 
 #ifdef CONFIG_ARC_DBG_TLB_PARANOIA
-void tlb_paranoid_check(unsigned int pid_sw, unsigned long address);
+void tlb_paranoid_check(unsigned int mm_asid, unsigned long address);
 #else
 #define tlb_paranoid_check(a, b)
 #endif
 
 void arc_mmu_init(void);
 extern char *arc_mmu_mumbojumbo(int cpu_id, char *buf, int len);
-void __init read_decode_mmu_bcr(void);
+void read_decode_mmu_bcr(void);
 
 #endif /* !__ASSEMBLY__ */
 
index 0d71fb11b57c753c5b1cb4dd13bd7b731b196e18..43a1b51bb8cc90b404c8225a9b6cdcb40862a0f2 100644 (file)
  * When it reaches max 255, the allocation cycle starts afresh by flushing
  * the entire TLB and wrapping ASID back to zero.
  *
- * For book-keeping, Linux uses a couple of data-structures:
- *  -mm_struct has an @asid field to keep a note of task's ASID (needed at the
- *   time of say switch_mm( )
- *  -An array of mm structs @asid_mm_map[] for asid->mm the reverse mapping,
- *  given an ASID, finding the mm struct associated.
- *
- * The round-robin allocation algorithm allows for ASID stealing.
- * If asid tracker is at "x-1", a new req will allocate "x", even if "x" was
- * already assigned to another (switched-out) task. Obviously the prev owner
- * is marked with an invalid ASID to make it request for a new ASID when it
- * gets scheduled next time. However its TLB entries (with ASID "x") could
- * exist, which must be cleared before the same ASID is used by the new owner.
- * Flushing them would be plausible but costly solution. Instead we force a
- * allocation policy quirk, which ensures that a stolen ASID won't have any
- * TLB entries associates, alleviating the need to flush.
- * The quirk essentially is not allowing ASID allocated in prev cycle
- * to be used past a roll-over in the next cycle.
- * When this happens (i.e. task ASID > asid tracker), task needs to refresh
- * its ASID, aligning it to current value of tracker. If the task doesn't get
- * scheduled past a roll-over, hence its ASID is not yet realigned with
- * tracker, such ASID is anyways safely reusable because it is
- * gauranteed that TLB entries with that ASID wont exist.
+ * A new allocation cycle, post rollover, could potentially reassign an ASID
+ * to a different task. Thus the rule is to refresh the ASID in a new cycle.
+ * The 32 bit @asid_cache (and mm->asid) have 8 bits MMU PID and rest 24 bits
+ * serve as cycle/generation indicator and natural 32 bit unsigned math
+ * automagically increments the generation when lower 8 bits rollover.
  */
 
-#define FIRST_ASID  0
-#define MAX_ASID    255                        /* 8 bit PID field in PID Aux reg */
-#define NO_ASID     (MAX_ASID + 1)     /* ASID Not alloc to mmu ctxt */
-#define NUM_ASID    ((MAX_ASID - FIRST_ASID) + 1)
+#define MM_CTXT_ASID_MASK      0x000000ff /* MMU PID reg :8 bit PID */
+#define MM_CTXT_CYCLE_MASK     (~MM_CTXT_ASID_MASK)
+
+#define MM_CTXT_FIRST_CYCLE    (MM_CTXT_ASID_MASK + 1)
+#define MM_CTXT_NO_ASID                0UL
 
-/* ASID to mm struct mapping */
-extern struct mm_struct *asid_mm_map[NUM_ASID + 1];
+#define hw_pid(mm)             (mm->context.asid & MM_CTXT_ASID_MASK)
 
-extern int asid_cache;
+extern unsigned int asid_cache;
 
 /*
- * Assign a new ASID to task. If the task already has an ASID, it is
- * relinquished.
+ * Get a new ASID if task doesn't have a valid one (unalloc or from prev cycle)
+ * Also set the MMU PID register to existing/updated ASID
  */
 static inline void get_new_mmu_context(struct mm_struct *mm)
 {
-       struct mm_struct *prev_owner;
        unsigned long flags;
 
        local_irq_save(flags);
 
        /*
-        * Relinquish the currently owned ASID (if any).
-        * Doing unconditionally saves a cmp-n-branch; for already unused
-        * ASID slot, the value was/remains NULL
+        * Move to new ASID if it was not from current alloc-cycle/generation.
+        * This is done by ensuring that the generation bits in both mm->ASID
+        * and cpu's ASID counter are exactly same.
+        *
+        * Note: Callers needing new ASID unconditionally, independent of
+        *       generation, e.g. local_flush_tlb_mm() for forking  parent,
+        *       first need to destroy the context, setting it to invalid
+        *       value.
         */
-       asid_mm_map[mm->context.asid] = (struct mm_struct *)NULL;
+       if (!((mm->context.asid ^ asid_cache) & MM_CTXT_CYCLE_MASK))
+               goto set_hw;
+
+       /* move to new ASID and handle rollover */
+       if (unlikely(!(++asid_cache & MM_CTXT_ASID_MASK))) {
 
-       /* move to new ASID */
-       if (++asid_cache > MAX_ASID) {  /* ASID roll-over */
-               asid_cache = FIRST_ASID;
                flush_tlb_all();
-       }
 
-       /*
-        * Is next ASID already owned by some-one else (we are stealing it).
-        * If so, let the orig owner be aware of this, so when it runs, it
-        * asks for a brand new ASID. This would only happen for a long-lived
-        * task with ASID from prev allocation cycle (before ASID roll-over).
-        *
-        * This might look wrong - if we are re-using some other task's ASID,
-        * won't we use it's stale TLB entries too. Actually switch_mm( ) takes
-        * care of such a case: it ensures that task with ASID from prev alloc
-        * cycle, when scheduled will refresh it's ASID: see switch_mm( ) below
-        * The stealing scenario described here will only happen if that task
-        * didn't get a chance to refresh it's ASID - implying stale entries
-        * won't exist.
-        */
-       prev_owner = asid_mm_map[asid_cache];
-       if (prev_owner)
-               prev_owner->context.asid = NO_ASID;
+               /*
+                * Above checke for rollover of 8 bit ASID in 32 bit container.
+                * If the container itself wrapped around, set it to a non zero
+                * "generation" to distinguish from no context
+                */
+               if (!asid_cache)
+                       asid_cache = MM_CTXT_FIRST_CYCLE;
+       }
 
        /* Assign new ASID to tsk */
-       asid_mm_map[asid_cache] = mm;
        mm->context.asid = asid_cache;
 
-#ifdef CONFIG_ARC_TLB_DBG
-       pr_info("ARC_TLB_DBG: NewMM=0x%x OldMM=0x%x task_struct=0x%x Task: %s,"
-              " pid:%u, assigned asid:%lu\n",
-              (unsigned int)mm, (unsigned int)prev_owner,
-              (unsigned int)(mm->context.tsk), (mm->context.tsk)->comm,
-              (mm->context.tsk)->pid, mm->context.asid);
-#endif
-
-       write_aux_reg(ARC_REG_PID, asid_cache | MMU_ENABLE);
+set_hw:
+       write_aux_reg(ARC_REG_PID, hw_pid(mm) | MMU_ENABLE);
 
        local_irq_restore(flags);
 }
@@ -134,10 +104,7 @@ static inline void get_new_mmu_context(struct mm_struct *mm)
 static inline int
 init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 {
-       mm->context.asid = NO_ASID;
-#ifdef CONFIG_ARC_TLB_DBG
-       mm->context.tsk = tsk;
-#endif
+       mm->context.asid = MM_CTXT_NO_ASID;
        return 0;
 }
 
@@ -152,40 +119,21 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
        write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
 #endif
 
-       /*
-        * Get a new ASID if task doesn't have a valid one. Possible when
-        *  -task never had an ASID (fresh after fork)
-        *  -it's ASID was stolen - past an ASID roll-over.
-        *  -There's a third obscure scenario (if this task is running for the
-        *   first time afer an ASID rollover), where despite having a valid
-        *   ASID, we force a get for new ASID - see comments at top.
-        *
-        * Both the non-alloc scenario and first-use-after-rollover can be
-        * detected using the single condition below:  NO_ASID = 256
-        * while asid_cache is always a valid ASID value (0-255).
-        */
-       if (next->context.asid > asid_cache) {
-               get_new_mmu_context(next);
-       } else {
-               /*
-                * XXX: This will never happen given the chks above
-                * BUG_ON(next->context.asid > MAX_ASID);
-                */
-               write_aux_reg(ARC_REG_PID, next->context.asid | MMU_ENABLE);
-       }
-
+       get_new_mmu_context(next);
 }
 
+/*
+ * Called at the time of execve() to get a new ASID
+ * Note the subtlety here: get_new_mmu_context() behaves differently here
+ * vs. in switch_mm(). Here it always returns a new ASID, because mm has
+ * an unallocated "initial" value, while in latter, it moves to a new ASID,
+ * only if it was unallocated
+ */
+#define activate_mm(prev, next)                switch_mm(prev, next, NULL)
+
 static inline void destroy_context(struct mm_struct *mm)
 {
-       unsigned long flags;
-
-       local_irq_save(flags);
-
-       asid_mm_map[mm->context.asid] = NULL;
-       mm->context.asid = NO_ASID;
-
-       local_irq_restore(flags);
+       mm->context.asid = MM_CTXT_NO_ASID;
 }
 
 /* it seemed that deactivate_mm( ) is a reasonable place to do book-keeping
@@ -197,17 +145,6 @@ static inline void destroy_context(struct mm_struct *mm)
  */
 #define deactivate_mm(tsk, mm)   do { } while (0)
 
-static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
-{
-#ifndef CONFIG_SMP
-       write_aux_reg(ARC_REG_SCRATCH_DATA0, next->pgd);
-#endif
-
-       /* Unconditionally get a new ASID */
-       get_new_mmu_context(next);
-
-}
-
 #define enter_lazy_tlb(mm, tsk)
 
 #endif /* __ASM_ARC_MMU_CONTEXT_H */
index 4749a0eee1cffcf3a06c916353af6db9facc19a1..6b0b7f7ef783cec0ecbd0bbd53e084be2011ae82 100644 (file)
 
 #define _PAGE_ACCESSED      (1<<1)     /* Page is accessed (S) */
 #define _PAGE_CACHEABLE     (1<<2)     /* Page is cached (H) */
-#define _PAGE_U_EXECUTE     (1<<3)     /* Page has user execute perm (H) */
-#define _PAGE_U_WRITE       (1<<4)     /* Page has user write perm (H) */
-#define _PAGE_U_READ        (1<<5)     /* Page has user read perm (H) */
-#define _PAGE_K_EXECUTE     (1<<6)     /* Page has kernel execute perm (H) */
-#define _PAGE_K_WRITE       (1<<7)     /* Page has kernel write perm (H) */
-#define _PAGE_K_READ        (1<<8)     /* Page has kernel perm (H) */
-#define _PAGE_GLOBAL        (1<<9)     /* Page is global (H) */
-#define _PAGE_MODIFIED      (1<<10)    /* Page modified (dirty) (S) */
-#define _PAGE_FILE          (1<<10)    /* page cache/ swap (S) */
-#define _PAGE_PRESENT       (1<<11)    /* TLB entry is valid (H) */
+#define _PAGE_EXECUTE       (1<<3)     /* Page has user execute perm (H) */
+#define _PAGE_WRITE         (1<<4)     /* Page has user write perm (H) */
+#define _PAGE_READ          (1<<5)     /* Page has user read perm (H) */
+#define _PAGE_MODIFIED      (1<<6)     /* Page modified (dirty) (S) */
+#define _PAGE_FILE          (1<<7)     /* page cache/ swap (S) */
+#define _PAGE_GLOBAL        (1<<8)     /* Page is global (H) */
+#define _PAGE_PRESENT       (1<<10)    /* TLB entry is valid (H) */
 
-#else
+#else  /* MMU v3 onwards */
 
-/* PD1 */
 #define _PAGE_CACHEABLE     (1<<0)     /* Page is cached (H) */
-#define _PAGE_U_EXECUTE     (1<<1)     /* Page has user execute perm (H) */
-#define _PAGE_U_WRITE       (1<<2)     /* Page has user write perm (H) */
-#define _PAGE_U_READ        (1<<3)     /* Page has user read perm (H) */
-#define _PAGE_K_EXECUTE     (1<<4)     /* Page has kernel execute perm (H) */
-#define _PAGE_K_WRITE       (1<<5)     /* Page has kernel write perm (H) */
-#define _PAGE_K_READ        (1<<6)     /* Page has kernel perm (H) */
-#define _PAGE_ACCESSED      (1<<7)     /* Page is accessed (S) */
-
-/* PD0 */
+#define _PAGE_EXECUTE       (1<<1)     /* Page has user execute perm (H) */
+#define _PAGE_WRITE         (1<<2)     /* Page has user write perm (H) */
+#define _PAGE_READ          (1<<3)     /* Page has user read perm (H) */
+#define _PAGE_ACCESSED      (1<<4)     /* Page is accessed (S) */
+#define _PAGE_MODIFIED      (1<<5)     /* Page modified (dirty) (S) */
+#define _PAGE_FILE          (1<<6)     /* page cache/ swap (S) */
 #define _PAGE_GLOBAL        (1<<8)     /* Page is global (H) */
 #define _PAGE_PRESENT       (1<<9)     /* TLB entry is valid (H) */
-#define _PAGE_SHARED_CODE   (1<<10)    /* Shared Code page with cmn vaddr
+#define _PAGE_SHARED_CODE   (1<<11)    /* Shared Code page with cmn vaddr
                                           usable for shared TLB entries (H) */
-
-#define _PAGE_MODIFIED      (1<<11)    /* Page modified (dirty) (S) */
-#define _PAGE_FILE          (1<<12)    /* page cache/ swap (S) */
-
-#define _PAGE_SHARED_CODE_H (1<<31)    /* Hardware counterpart of above */
 #endif
 
-/* Kernel allowed all permissions for all pages */
-#define _K_PAGE_PERMS  (_PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ | \
+/* vmalloc permissions */
+#define _K_PAGE_PERMS  (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ | \
                        _PAGE_GLOBAL | _PAGE_PRESENT)
 
 #ifdef CONFIG_ARC_CACHE_PAGES
  */
 #define ___DEF (_PAGE_PRESENT | _PAGE_DEF_CACHEABLE)
 
-#define _PAGE_READ     (_PAGE_U_READ    | _PAGE_K_READ)
-#define _PAGE_WRITE    (_PAGE_U_WRITE   | _PAGE_K_WRITE)
-#define _PAGE_EXECUTE  (_PAGE_U_EXECUTE | _PAGE_K_EXECUTE)
-
 /* Set of bits not changed in pte_modify */
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_MODIFIED)
 
 
 #define PAGE_SHARED    PAGE_U_W_R
 
-/* While kernel runs out of unstrslated space, vmalloc/modules use a chunk of
- * kernel vaddr space - visible in all addr spaces, but kernel mode only
+/* While kernel runs out of unstranslated space, vmalloc/modules use a chunk of
+ * user vaddr space - visible in all addr spaces, but kernel mode only
  * Thus Global, all-kernel-access, no-user-access, cached
  */
 #define PAGE_KERNEL          __pgprot(_K_PAGE_PERMS | _PAGE_DEF_CACHEABLE)
 #define PAGE_KERNEL_NO_CACHE __pgprot(_K_PAGE_PERMS)
 
 /* Masks for actual TLB "PD"s */
-#define PTE_BITS_IN_PD0        (_PAGE_GLOBAL | _PAGE_PRESENT)
-#define PTE_BITS_IN_PD1        (PAGE_MASK | _PAGE_CACHEABLE | \
-                        _PAGE_U_EXECUTE | _PAGE_U_WRITE | _PAGE_U_READ | \
-                        _PAGE_K_EXECUTE | _PAGE_K_WRITE | _PAGE_K_READ)
+#define PTE_BITS_IN_PD0                (_PAGE_GLOBAL | _PAGE_PRESENT)
+#define PTE_BITS_RWX           (_PAGE_EXECUTE | _PAGE_WRITE | _PAGE_READ)
+#define PTE_BITS_NON_RWX_IN_PD1        (PAGE_MASK | _PAGE_CACHEABLE)
 
 /**************************************************************************
  * Mapping of vm_flags (Generic VM) to PTE flags (arch specific)
index c9938e7a7dbd3b596fc3c0021d8ff57548719402..1bfeec2c0558c2f6f91142105bee0c6ff70c7a75 100644 (file)
@@ -20,27 +20,17 @@ struct pt_regs {
 
        /* Real registers */
        long bta;       /* bta_l1, bta_l2, erbta */
-       long lp_start;
-       long lp_end;
-       long lp_count;
+
+       long lp_start, lp_end, lp_count;
+
        long status32;  /* status32_l1, status32_l2, erstatus */
        long ret;       /* ilink1, ilink2 or eret */
        long blink;
        long fp;
        long r26;       /* gp */
-       long r12;
-       long r11;
-       long r10;
-       long r9;
-       long r8;
-       long r7;
-       long r6;
-       long r5;
-       long r4;
-       long r3;
-       long r2;
-       long r1;
-       long r0;
+
+       long r12, r11, r10, r9, r8, r7, r6, r5, r4, r3, r2, r1, r0;
+
        long sp;        /* user/kernel sp depending on where we came from  */
        long orig_r0;
 
@@ -70,19 +60,7 @@ struct pt_regs {
 /* Callee saved registers - need to be saved only when you are scheduled out */
 
 struct callee_regs {
-       long r25;
-       long r24;
-       long r23;
-       long r22;
-       long r21;
-       long r20;
-       long r19;
-       long r18;
-       long r17;
-       long r16;
-       long r15;
-       long r14;
-       long r13;
+       long r25, r24, r23, r22, r21, r20, r19, r18, r17, r16, r15, r14, r13;
 };
 
 #define instruction_pointer(regs)      ((regs)->ret)
index 6fc1159dfefe66a004183001720c3aee69f859d1..764f1e3ba7523b7101c3b9255e6b773a81a01269 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <asm-generic/sections.h>
 
-extern char _int_vec_base_lds[];
 extern char __arc_dccm_base[];
 extern char __dtb_start[];
 
index 8276bfd617046a2d2e09c7bb1561ff5c5acf591e..662627ced4f23a966c85feffb9f9d38a4f7df10a 100644 (file)
@@ -20,9 +20,9 @@ typedef struct {
 #define __ARCH_SPIN_LOCK_LOCKED                { __ARCH_SPIN_LOCK_LOCKED__ }
 
 /*
- * Unlocked:     0x01_00_00_00
- * Read lock(s): 0x00_FF_00_00 to say 0x01
- * Write lock:   0x0, but only possible if prior value "unlocked" 0x0100_0000
+ * Unlocked     : 0x0100_0000
+ * Read lock(s) : 0x00FF_FFFF to 0x01  (Multiple Readers decrement it)
+ * Write lock   : 0x0, but only if prior value is "unlocked" 0x0100_0000
  */
 typedef struct {
        volatile unsigned int   counter;
diff --git a/arch/arc/kernel/.gitignore b/arch/arc/kernel/.gitignore
new file mode 100644 (file)
index 0000000..c5f676c
--- /dev/null
@@ -0,0 +1 @@
+vmlinux.lds
index bdee3a8120521044fab496782b612157753abb83..2340af0e1d6f8c00b57b35a127bf73f673a244e2 100644 (file)
 #include <asm/clk.h>
 #include <asm/mach_desc.h>
 
-/* called from unflatten_device_tree() to bootstrap devicetree itself */
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-{
-       return __va(memblock_alloc(size, align));
-}
-
 /**
  * setup_machine_fdt - Machine setup when an dtb was passed to the kernel
  * @dt:                virtual address pointer to dt blob
index 1d7165156e1708ee6a24391ed9218de330603ccf..b908dde8a331c26a00a4912309af78cf643fc05b 100644 (file)
@@ -267,12 +267,7 @@ ARC_EXIT handle_interrupt_level1
 
 ARC_ENTRY instr_service
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
@@ -289,15 +284,13 @@ ARC_EXIT instr_service
 
 ARC_ENTRY mem_service
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
+
+       FAKE_RET_FROM_EXCPN r9
+
        bl  do_memory_error
        b   ret_from_exception
 ARC_EXIT mem_service
@@ -308,11 +301,7 @@ ARC_EXIT mem_service
 
 ARC_ENTRY EV_MachineCheck
 
-       EXCPN_PROLOG_FREEUP_REG r9
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r2, [ecr]
        lr  r0, [efa]
@@ -342,13 +331,7 @@ ARC_EXIT EV_MachineCheck
 
 ARC_ENTRY EV_TLBProtV
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       ;Which mode (user/kernel) was the system in when Exception occured
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        ;---------(3) Save some more regs-----------------
        ;  vineetg: Mar 6th: Random Seg Fault issue #1
@@ -406,12 +389,7 @@ ARC_EXIT EV_TLBProtV
 ; ---------------------------------------------
 ARC_ENTRY EV_PrivilegeV
 
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
@@ -427,14 +405,13 @@ ARC_EXIT EV_PrivilegeV
 ; ---------------------------------------------
 ARC_ENTRY EV_Extension
 
-       EXCPN_PROLOG_FREEUP_REG r9
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        lr  r0, [efa]
        mov r1, sp
+
+       FAKE_RET_FROM_EXCPN r9
+
        bl  do_extension_fault
        b   ret_from_exception
 ARC_EXIT EV_Extension
@@ -526,14 +503,7 @@ trap_with_param:
 
 ARC_ENTRY EV_Trap
 
-       ; Need at least 1 reg to code the early exception prolog
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       ;Which mode (user/kernel) was the system in when intr occured
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        ;------- (4) What caused the Trap --------------
        lr     r12, [ecr]
@@ -642,6 +612,9 @@ resume_kernel_mode:
 
 #ifdef CONFIG_PREEMPT
 
+       ; This is a must for preempt_schedule_irq()
+       IRQ_DISABLE     r9
+
        ; Can't preempt if preemption disabled
        GET_CURR_THR_INFO_FROM_SP   r10
        ld  r8, [r10, THREAD_INFO_PREEMPT_COUNT]
@@ -651,8 +624,6 @@ resume_kernel_mode:
        ld  r9, [r10, THREAD_INFO_FLAGS]
        bbit0  r9, TIF_NEED_RESCHED, restore_regs
 
-       IRQ_DISABLE     r9
-
        ; Invoke PREEMPTION
        bl      preempt_schedule_irq
 
@@ -665,12 +636,11 @@ resume_kernel_mode:
 ;
 ; Restore the saved sys context (common exit-path for EXCPN/IRQ/Trap)
 ; IRQ shd definitely not happen between now and rtie
+; All 2 entry points to here already disable interrupts
 
 restore_regs :
 
-       ; Disable Interrupts while restoring reg-file back
-       ; XXX can this be optimised out
-       IRQ_DISABLE_SAVE    r9, r10     ;@r10 has prisitine (pre-disable) copy
+       lr      r10, [status32]
 
        ; Restore REG File. In case multiple Events outstanding,
        ; use the same priorty as rtie: EXCPN, L2 IRQ, L1 IRQ, None
index 2a913f85a74793ae47c19e90deea0f9ef69793e1..0f944f0245134baa37b33b32550a1fc0c528932b 100644 (file)
@@ -34,6 +34,9 @@ stext:
        ;       IDENTITY Reg [ 3  2  1  0 ]
        ;       (cpu-id)             ^^^        => Zero for UP ARC700
        ;                                       => #Core-ID if SMP (Master 0)
+       ; Note that non-boot CPUs might not land here if halt-on-reset and
+       ; instead breath life from @first_lines_of_secondary, but we still
+       ; need to make sure only boot cpu takes this path.
        GET_CPU_ID  r5
        cmp     r5, 0
        jnz     arc_platform_smp_wait_to_boot
@@ -98,6 +101,8 @@ stext:
 
 first_lines_of_secondary:
 
+       sr      @_int_vec_base_lds, [AUX_INTR_VEC_BASE]
+
        ; setup per-cpu idle task as "current" on this CPU
        ld      r0, [@secondary_idle_tsk]
        SET_CURR_TASK_ON_CPU  r0, r1
index 305b3f866aa7107a027a61aa1752d021c44ab393..5fc92455da368132960515a7eb81faa72c7717ae 100644 (file)
@@ -24,7 +24,6 @@
  * -Needed for each CPU (hence not foldable into init_IRQ)
  *
  * what it does ?
- * -setup Vector Table Base Reg - in case Linux not linked at 0x8000_0000
  * -Disable all IRQs (on CPU side)
  * -Optionally, setup the High priority Interrupts as Level 2 IRQs
  */
index 6b083454d0391d2177511ac1eb24300dfc19861c..2c68bc7e6a784132a97d3ad6b04d8535cf546deb 100644 (file)
@@ -47,10 +47,7 @@ void read_arc_build_cfg_regs(void)
        READ_BCR(AUX_IDENTITY, cpu->core);
 
        cpu->timers = read_aux_reg(ARC_REG_TIMERS_BCR);
-
        cpu->vec_base = read_aux_reg(AUX_INTR_VEC_BASE);
-       if (cpu->vec_base == 0)
-               cpu->vec_base = (unsigned int)_int_vec_base_lds;
 
        READ_BCR(ARC_REG_D_UNCACH_BCR, uncached_space);
        cpu->uncached_base = uncached_space.start << 24;
@@ -357,8 +354,6 @@ void __init setup_arch(char **cmdline_p)
         */
        root_mountflags &= ~MS_RDONLY;
 
-       console_verbose();
-
 #if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
        conswitchp = &dummy_con;
 #endif
index c0f832f595d319d1aa21f05228b01fb946ab5591..28d1700607474eb01be14e0600832bf7ee4cf999 100644 (file)
 #include <linux/uaccess.h>
 #include <asm/disasm.h>
 
+#ifdef CONFIG_CPU_BIG_ENDIAN
+#define BE             1
+#define FIRST_BYTE_16  "swap %1, %1\n swape %1, %1\n"
+#define FIRST_BYTE_32  "swape %1, %1\n"
+#else
+#define BE             0
+#define FIRST_BYTE_16
+#define FIRST_BYTE_32
+#endif
+
 #define __get8_unaligned_check(val, addr, err)         \
        __asm__(                                        \
        "1:     ldb.ab  %1, [%2, 1]\n"                  \
@@ -36,9 +46,9 @@
        do {                                            \
                unsigned int err = 0, v, a = addr;      \
                __get8_unaligned_check(v, a, err);      \
-               val =  v ;                              \
+               val =  v << ((BE) ? 8 : 0);             \
                __get8_unaligned_check(v, a, err);      \
-               val |= v << 8;                          \
+               val |= v << ((BE) ? 0 : 8);             \
                if (err)                                \
                        goto fault;                     \
        } while (0)
        do {                                            \
                unsigned int err = 0, v, a = addr;      \
                __get8_unaligned_check(v, a, err);      \
-               val =  v << 0;                          \
+               val =  v << ((BE) ? 24 : 0);            \
                __get8_unaligned_check(v, a, err);      \
-               val |= v << 8;                          \
+               val |= v << ((BE) ? 16 : 8);            \
                __get8_unaligned_check(v, a, err);      \
-               val |= v << 16;                         \
+               val |= v << ((BE) ? 8 : 16);            \
                __get8_unaligned_check(v, a, err);      \
-               val |= v << 24;                         \
+               val |= v << ((BE) ? 0 : 24);            \
                if (err)                                \
                        goto fault;                     \
        } while (0)
@@ -63,6 +73,7 @@
                unsigned int err = 0, v = val, a = addr;\
                                                        \
                __asm__(                                \
+               FIRST_BYTE_16                           \
                "1:     stb.ab  %1, [%2, 1]\n"          \
                "       lsr %1, %1, 8\n"                \
                "2:     stb     %1, [%2]\n"             \
@@ -87,8 +98,9 @@
 #define put32_unaligned_check(val, addr)               \
        do {                                            \
                unsigned int err = 0, v = val, a = addr;\
-               __asm__(                                \
                                                        \
+               __asm__(                                \
+               FIRST_BYTE_32                           \
                "1:     stb.ab  %1, [%2, 1]\n"          \
                "       lsr %1, %1, 8\n"                \
                "2:     stb.ab  %1, [%2, 1]\n"          \
index f415d851b765888c500d70f887af96ed226fd88c..5a1259cd948c8ff91475f47b225aae3274e30fbd 100644 (file)
@@ -622,12 +622,12 @@ void flush_icache_range(unsigned long kstart, unsigned long kend)
 /*
  * General purpose helper to make I and D cache lines consistent.
  * @paddr is phy addr of region
- * @vaddr is typically user or kernel vaddr (vmalloc)
- *    Howver in one instance, flush_icache_range() by kprobe (for a breakpt in
+ * @vaddr is typically user vaddr (breakpoint) or kernel vaddr (vmalloc)
+ *    However in one instance, when called by kprobe (for a breakpt in
  *    builtin kernel code) @vaddr will be paddr only, meaning CDU operation will
  *    use a paddr to index the cache (despite VIPT). This is fine since since a
- *    built-in kernel page will not have any virtual mappings (not even kernel)
- *    kprobe on loadable module is different as it will have kvaddr.
+ *    builtin kernel page will not have any virtual mappings.
+ *    kprobe on loadable module will be kernel vaddr.
  */
 void __sync_icache_dcache(unsigned long paddr, unsigned long vaddr, int len)
 {
index 0fd1f0d515ffb394f64107ceb1ecdfb856a8858d..d63f3de0cd5bf60e209bf00be68fb8c628862126 100644 (file)
@@ -60,8 +60,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address)
        siginfo_t info;
        int fault, ret;
        int write = regs->ecr_cause & ECR_C_PROTV_STORE;  /* ST/EX */
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                               (write ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        /*
         * We fault-in kernel-space virtual memory on-demand. The
@@ -89,6 +88,8 @@ void do_page_fault(struct pt_regs *regs, unsigned long address)
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -117,12 +118,12 @@ good_area:
        if (write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
 
-survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -201,10 +202,6 @@ no_context:
        die("Oops", regs, address);
 
 out_of_memory:
-       if (is_global_init(tsk)) {
-               yield();
-               goto survive;
-       }
        up_read(&mm->mmap_sem);
 
        if (user_mode(regs)) {
index a08ce71854233e05510d45fc1183c19ecd35cb7c..81279ec73a6a7873b4a10fc8ec4c3546413bfd05 100644 (file)
@@ -127,9 +127,8 @@ void __init free_initrd_mem(unsigned long start, unsigned long end)
 #endif
 
 #ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
-       pr_err("%s(%lx, %lx)\n", __func__, start, end);
+       pr_err("%s(%llx, %llx)\n", __func__, start, end);
 }
 #endif /* CONFIG_OF_FLATTREE */
index 7957dc4e4d4a4c8acee3fe521d0ecf8bb939c39c..71cb26df42555feadce79409c44d097260bd06e7 100644 (file)
@@ -52,6 +52,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/bug.h>
 #include <asm/arcregs.h>
 #include <asm/setup.h>
 #include <asm/mmu_context.h>
 
 
 /* A copy of the ASID from the PID reg is kept in asid_cache */
-int asid_cache = FIRST_ASID;
-
-/* ASID to mm struct mapping. We have one extra entry corresponding to
- * NO_ASID to save us a compare when clearing the mm entry for old asid
- * see get_new_mmu_context (asm-arc/mmu_context.h)
- */
-struct mm_struct *asid_mm_map[NUM_ASID + 1];
+unsigned int asid_cache = MM_CTXT_FIRST_CYCLE;
 
 /*
  * Utility Routine to erase a J-TLB entry
- * The procedure is to look it up in the MMU. If found, ERASE it by
- *  issuing a TlbWrite CMD with PD0 = PD1 = 0
+ * Caller needs to setup Index Reg (manually or via getIndex)
  */
-
-static void __tlb_entry_erase(void)
+static inline void __tlb_entry_erase(void)
 {
        write_aux_reg(ARC_REG_TLBPD1, 0);
        write_aux_reg(ARC_REG_TLBPD0, 0);
        write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
 }
 
-static void tlb_entry_erase(unsigned int vaddr_n_asid)
+static inline unsigned int tlb_entry_lkup(unsigned long vaddr_n_asid)
 {
        unsigned int idx;
 
-       /* Locate the TLB entry for this vaddr + ASID */
        write_aux_reg(ARC_REG_TLBPD0, vaddr_n_asid);
+
        write_aux_reg(ARC_REG_TLBCOMMAND, TLBProbe);
        idx = read_aux_reg(ARC_REG_TLBINDEX);
 
+       return idx;
+}
+
+static void tlb_entry_erase(unsigned int vaddr_n_asid)
+{
+       unsigned int idx;
+
+       /* Locate the TLB entry for this vaddr + ASID */
+       idx = tlb_entry_lkup(vaddr_n_asid);
+
        /* No error means entry found, zero it out */
        if (likely(!(idx & TLB_LKUP_ERR))) {
                __tlb_entry_erase();
-       } else {                /* Some sort of Error */
-
+       } else {
                /* Duplicate entry error */
-               if (idx & 0x1) {
-                       /* TODO we need to handle this case too */
-                       pr_emerg("unhandled Duplicate flush for %x\n",
-                              vaddr_n_asid);
-               }
-               /* else entry not found so nothing to do */
+               WARN(idx == TLB_DUP_ERR, "Probe returned Dup PD for %x\n",
+                                          vaddr_n_asid);
        }
 }
 
@@ -159,7 +157,7 @@ static void utlb_invalidate(void)
 {
 #if (CONFIG_ARC_MMU_VER >= 2)
 
-#if (CONFIG_ARC_MMU_VER < 3)
+#if (CONFIG_ARC_MMU_VER == 2)
        /* MMU v2 introduced the uTLB Flush command.
         * There was however an obscure hardware bug, where uTLB flush would
         * fail when a prior probe for J-TLB (both totally unrelated) would
@@ -182,6 +180,36 @@ static void utlb_invalidate(void)
 
 }
 
+static void tlb_entry_insert(unsigned int pd0, unsigned int pd1)
+{
+       unsigned int idx;
+
+       /*
+        * First verify if entry for this vaddr+ASID already exists
+        * This also sets up PD0 (vaddr, ASID..) for final commit
+        */
+       idx = tlb_entry_lkup(pd0);
+
+       /*
+        * If Not already present get a free slot from MMU.
+        * Otherwise, Probe would have located the entry and set INDEX Reg
+        * with existing location. This will cause Write CMD to over-write
+        * existing entry with new PD0 and PD1
+        */
+       if (likely(idx & TLB_LKUP_ERR))
+               write_aux_reg(ARC_REG_TLBCOMMAND, TLBGetIndex);
+
+       /* setup the other half of TLB entry (pfn, rwx..) */
+       write_aux_reg(ARC_REG_TLBPD1, pd1);
+
+       /*
+        * Commit the Entry to MMU
+        * It doesnt sound safe to use the TLBWriteNI cmd here
+        * which doesn't flush uTLBs. I'd rather be safe than sorry.
+        */
+       write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+}
+
 /*
  * Un-conditionally (without lookup) erase the entire MMU contents
  */
@@ -224,13 +252,14 @@ noinline void local_flush_tlb_mm(struct mm_struct *mm)
                return;
 
        /*
-        * Workaround for Android weirdism:
-        * A binder VMA could end up in a task such that vma->mm != tsk->mm
-        * old code would cause h/w - s/w ASID to get out of sync
+        * - Move to a new ASID, but only if the mm is still wired in
+        *   (Android Binder ended up calling this for vma->mm != tsk->mm,
+        *    causing h/w - s/w ASID to get out of sync)
+        * - Also get_new_mmu_context() new implementation allocates a new
+        *   ASID only if it is not allocated already - so unallocate first
         */
-       if (current->mm != mm)
-               destroy_context(mm);
-       else
+       destroy_context(mm);
+       if (current->mm == mm)
                get_new_mmu_context(mm);
 }
 
@@ -246,7 +275,6 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                           unsigned long end)
 {
        unsigned long flags;
-       unsigned int asid;
 
        /* If range @start to @end is more than 32 TLB entries deep,
         * its better to move to a new ASID rather than searching for
@@ -268,11 +296,10 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
        start &= PAGE_MASK;
 
        local_irq_save(flags);
-       asid = vma->vm_mm->context.asid;
 
-       if (asid != NO_ASID) {
+       if (vma->vm_mm->context.asid != MM_CTXT_NO_ASID) {
                while (start < end) {
-                       tlb_entry_erase(start | (asid & 0xff));
+                       tlb_entry_erase(start | hw_pid(vma->vm_mm));
                        start += PAGE_SIZE;
                }
        }
@@ -326,9 +353,8 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
         */
        local_irq_save(flags);
 
-       if (vma->vm_mm->context.asid != NO_ASID) {
-               tlb_entry_erase((page & PAGE_MASK) |
-                               (vma->vm_mm->context.asid & 0xff));
+       if (vma->vm_mm->context.asid != MM_CTXT_NO_ASID) {
+               tlb_entry_erase((page & PAGE_MASK) | hw_pid(vma->vm_mm));
                utlb_invalidate();
        }
 
@@ -341,8 +367,8 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
 {
        unsigned long flags;
-       unsigned int idx, asid_or_sasid;
-       unsigned long pd0_flags;
+       unsigned int asid_or_sasid, rwx;
+       unsigned long pd0, pd1;
 
        /*
         * create_tlb() assumes that current->mm == vma->mm, since
@@ -381,40 +407,30 @@ void create_tlb(struct vm_area_struct *vma, unsigned long address, pte_t *ptep)
        /* update this PTE credentials */
        pte_val(*ptep) |= (_PAGE_PRESENT | _PAGE_ACCESSED);
 
-       /* Create HW TLB entry Flags (in PD0) from PTE Flags */
-#if (CONFIG_ARC_MMU_VER <= 2)
-       pd0_flags = ((pte_val(*ptep) & PTE_BITS_IN_PD0) >> 1);
-#else
-       pd0_flags = ((pte_val(*ptep) & PTE_BITS_IN_PD0));
-#endif
+       /* Create HW TLB(PD0,PD1) from PTE  */
 
        /* ASID for this task */
        asid_or_sasid = read_aux_reg(ARC_REG_PID) & 0xff;
 
-       write_aux_reg(ARC_REG_TLBPD0, address | pd0_flags | asid_or_sasid);
-
-       /* Load remaining info in PD1 (Page Frame Addr and Kx/Kw/Kr Flags) */
-       write_aux_reg(ARC_REG_TLBPD1, (pte_val(*ptep) & PTE_BITS_IN_PD1));
-
-       /* First verify if entry for this vaddr+ASID already exists */
-       write_aux_reg(ARC_REG_TLBCOMMAND, TLBProbe);
-       idx = read_aux_reg(ARC_REG_TLBINDEX);
+       pd0 = address | asid_or_sasid | (pte_val(*ptep) & PTE_BITS_IN_PD0);
 
        /*
-        * If Not already present get a free slot from MMU.
-        * Otherwise, Probe would have located the entry and set INDEX Reg
-        * with existing location. This will cause Write CMD to over-write
-        * existing entry with new PD0 and PD1
+        * ARC MMU provides fully orthogonal access bits for K/U mode,
+        * however Linux only saves 1 set to save PTE real-estate
+        * Here we convert 3 PTE bits into 6 MMU bits:
+        * -Kernel only entries have Kr Kw Kx 0 0 0
+        * -User entries have mirrored K and U bits
         */
-       if (likely(idx & TLB_LKUP_ERR))
-               write_aux_reg(ARC_REG_TLBCOMMAND, TLBGetIndex);
+       rwx = pte_val(*ptep) & PTE_BITS_RWX;
 
-       /*
-        * Commit the Entry to MMU
-        * It doesnt sound safe to use the TLBWriteNI cmd here
-        * which doesn't flush uTLBs. I'd rather be safe than sorry.
-        */
-       write_aux_reg(ARC_REG_TLBCOMMAND, TLBWrite);
+       if (pte_val(*ptep) & _PAGE_GLOBAL)
+               rwx <<= 3;              /* r w x => Kr Kw Kx 0 0 0 */
+       else
+               rwx |= (rwx << 3);      /* r w x => Kr Kw Kx Ur Uw Ux */
+
+       pd1 = rwx | (pte_val(*ptep) & PTE_BITS_NON_RWX_IN_PD1);
+
+       tlb_entry_insert(pd0, pd1);
 
        local_irq_restore(flags);
 }
@@ -553,13 +569,6 @@ void arc_mmu_init(void)
        if (mmu->pg_sz != PAGE_SIZE)
                panic("MMU pg size != PAGE_SIZE (%luk)\n", TO_KB(PAGE_SIZE));
 
-       /*
-        * ASID mgmt data structures are compile time init
-        *  asid_cache = FIRST_ASID and asid_mm_map[] all zeroes
-        */
-
-       local_flush_tlb_all();
-
        /* Enable the MMU */
        write_aux_reg(ARC_REG_PID, MMU_ENABLE);
 
@@ -671,25 +680,28 @@ void do_tlb_overlap_fault(unsigned long cause, unsigned long address,
  * Low Level ASM TLB handler calls this if it finds that HW and SW ASIDS
  * don't match
  */
-void print_asid_mismatch(int is_fast_path)
+void print_asid_mismatch(int mm_asid, int mmu_asid, int is_fast_path)
 {
-       int pid_sw, pid_hw;
-       pid_sw = current->active_mm->context.asid;
-       pid_hw = read_aux_reg(ARC_REG_PID) & 0xff;
-
        pr_emerg("ASID Mismatch in %s Path Handler: sw-pid=0x%x hw-pid=0x%x\n",
-              is_fast_path ? "Fast" : "Slow", pid_sw, pid_hw);
+              is_fast_path ? "Fast" : "Slow", mm_asid, mmu_asid);
 
        __asm__ __volatile__("flag 1");
 }
 
-void tlb_paranoid_check(unsigned int pid_sw, unsigned long addr)
+void tlb_paranoid_check(unsigned int mm_asid, unsigned long addr)
 {
-       unsigned int pid_hw;
+       unsigned int mmu_asid;
 
-       pid_hw = read_aux_reg(ARC_REG_PID) & 0xff;
+       mmu_asid = read_aux_reg(ARC_REG_PID) & 0xff;
 
-       if (addr < 0x70000000 && ((pid_hw != pid_sw) || (pid_sw == NO_ASID)))
-               print_asid_mismatch(0);
+       /*
+        * At the time of a TLB miss/installation
+        *   - HW version needs to match SW version
+        *   - SW needs to have a valid ASID
+        */
+       if (addr < 0x70000000 &&
+           ((mm_asid == MM_CTXT_NO_ASID) ||
+             (mmu_asid != (mm_asid & MM_CTXT_ASID_MASK))))
+               print_asid_mismatch(mm_asid, mmu_asid, 0);
 }
 #endif
index 5c5bb23001b071b02a0ea33dba44d72211656d28..cf7d7d9ad695c2e607ab10a9f0423215f079b1f7 100644 (file)
 #include <asm/arcregs.h>
 #include <asm/cache.h>
 #include <asm/processor.h>
-#if (CONFIG_ARC_MMU_VER == 1)
 #include <asm/tlb-mmu1.h>
-#endif
 
-;--------------------------------------------------------------------------
-; scratch memory to save the registers (r0-r3) used to code TLB refill Handler
-; For details refer to comments before TLBMISS_FREEUP_REGS below
+;-----------------------------------------------------------------
+; ARC700 Exception Handling doesn't auto-switch stack and it only provides
+; ONE scratch AUX reg "ARC_REG_SCRATCH_DATA0"
+;
+; For Non-SMP, the scratch AUX reg is repurposed to cache task PGD, so a
+; "global" is used to free-up FIRST core reg to be able to code the rest of
+; exception prologue (IRQ auto-disabled on Exceptions, so it's IRQ-safe).
+; Since the Fast Path TLB Miss handler is coded with 4 regs, the remaining 3
+; need to be saved as well by extending the "global" to be 4 words. Hence
+;      ".size   ex_saved_reg1, 16"
+; [All of this dance is to avoid stack switching for each TLB Miss, since we
+; only need to save only a handful of regs, as opposed to complete reg file]
+;
+; For ARC700 SMP, the "global" obviously can't be used for free up the FIRST
+; core reg as it will not be SMP safe.
+; Thus scratch AUX reg is used (and no longer used to cache task PGD).
+; To save the rest of 3 regs - per cpu, the global is made "per-cpu".
+; Epilogue thus has to locate the "per-cpu" storage for regs.
+; To avoid cache line bouncing the per-cpu global is aligned/sized per
+; L1_CACHE_SHIFT, despite fundamentally needing to be 12 bytes only. Hence
+;      ".size   ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)"
+
+; As simple as that....
 ;--------------------------------------------------------------------------
 
+; scratch memory to save [r0-r3] used to code TLB refill Handler
 ARCFP_DATA ex_saved_reg1
-       .align 1 << L1_CACHE_SHIFT      ; IMP: Must be Cache Line aligned
+       .align 1 << L1_CACHE_SHIFT
        .type   ex_saved_reg1, @object
 #ifdef CONFIG_SMP
        .size   ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)
@@ -66,6 +85,44 @@ ex_saved_reg1:
        .zero 16
 #endif
 
+.macro TLBMISS_FREEUP_REGS
+#ifdef CONFIG_SMP
+       sr  r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
+       GET_CPU_ID  r0                  ; get to per cpu scratch mem,
+       lsl r0, r0, L1_CACHE_SHIFT      ; cache line wide per cpu
+       add r0, @ex_saved_reg1, r0
+#else
+       st    r0, [@ex_saved_reg1]
+       mov_s r0, @ex_saved_reg1
+#endif
+       st_s  r1, [r0, 4]
+       st_s  r2, [r0, 8]
+       st_s  r3, [r0, 12]
+
+       ; VERIFY if the ASID in MMU-PID Reg is same as
+       ; one in Linux data structures
+
+       tlb_paranoid_check_asm
+.endm
+
+.macro TLBMISS_RESTORE_REGS
+#ifdef CONFIG_SMP
+       GET_CPU_ID  r0                  ; get to per cpu scratch mem
+       lsl r0, r0, L1_CACHE_SHIFT      ; each is cache line wide
+       add r0, @ex_saved_reg1, r0
+       ld_s  r3, [r0,12]
+       ld_s  r2, [r0, 8]
+       ld_s  r1, [r0, 4]
+       lr    r0, [ARC_REG_SCRATCH_DATA0]
+#else
+       mov_s r0, @ex_saved_reg1
+       ld_s  r3, [r0,12]
+       ld_s  r2, [r0, 8]
+       ld_s  r1, [r0, 4]
+       ld_s  r0, [r0]
+#endif
+.endm
+
 ;============================================================================
 ;  Troubleshooting Stuff
 ;============================================================================
@@ -76,34 +133,35 @@ ex_saved_reg1:
 ; In bizzare scenrios SW and HW ASID can get out-of-sync which is trouble.
 ; So we try to detect this in TLB Mis shandler
 
-
-.macro DBG_ASID_MISMATCH
+.macro tlb_paranoid_check_asm
 
 #ifdef CONFIG_ARC_DBG_TLB_PARANOIA
 
-       ; make sure h/w ASID is same as s/w ASID
-
        GET_CURR_TASK_ON_CPU  r3
        ld r0, [r3, TASK_ACT_MM]
        ld r0, [r0, MM_CTXT+MM_CTXT_ASID]
+       breq r0, 0, 55f ; Error if no ASID allocated
 
        lr r1, [ARC_REG_PID]
        and r1, r1, 0xFF
-       breq r1, r0, 5f
 
+       and r2, r0, 0xFF        ; MMU PID bits only for comparison
+       breq r1, r2, 5f
+
+55:
        ; Error if H/w and S/w ASID don't match, but NOT if in kernel mode
-       lr  r0, [erstatus]
-       bbit0 r0, STATUS_U_BIT, 5f
+       lr  r2, [erstatus]
+       bbit0 r2, STATUS_U_BIT, 5f
 
        ; We sure are in troubled waters, Flag the error, but to do so
        ; need to switch to kernel mode stack to call error routine
        GET_TSK_STACK_BASE   r3, sp
 
        ; Call printk to shoutout aloud
-       mov r0, 1
+       mov r2, 1
        j print_asid_mismatch
 
-5:   ; ASIDs match so proceed normally
+5:     ; ASIDs match so proceed normally
        nop
 
 #endif
@@ -161,13 +219,17 @@ ex_saved_reg1:
 ; IN: r0 = PTE, r1 = ptr to PTE
 
 .macro CONV_PTE_TO_TLB
-       and r3, r0, PTE_BITS_IN_PD1 ; Extract permission flags+PFN from PTE
-       sr  r3, [ARC_REG_TLBPD1]    ; these go in PD1
+       and    r3, r0, PTE_BITS_RWX     ;       r w x
+       lsl    r2, r3, 3                ; r w x 0 0 0
+       and.f  0,  r0, _PAGE_GLOBAL
+       or.z   r2, r2, r3               ; r w x r w x
+
+       and r3, r0, PTE_BITS_NON_RWX_IN_PD1 ; Extract PFN+cache bits from PTE
+       or  r3, r3, r2
+
+       sr  r3, [ARC_REG_TLBPD1]        ; these go in PD1
 
        and r2, r0, PTE_BITS_IN_PD0 ; Extract other PTE flags: (V)alid, (G)lb
-#if (CONFIG_ARC_MMU_VER <= 2)   /* Neednot be done with v3 onwards */
-       lsr r2, r2                  ; shift PTE flags to match layout in PD0
-#endif
 
        lr  r3,[ARC_REG_TLBPD0]     ; MMU prepares PD0 with vaddr and asid
 
@@ -191,68 +253,6 @@ ex_saved_reg1:
 #endif
 .endm
 
-;-----------------------------------------------------------------
-; ARC700 Exception Handling doesn't auto-switch stack and it only provides
-; ONE scratch AUX reg "ARC_REG_SCRATCH_DATA0"
-;
-; For Non-SMP, the scratch AUX reg is repurposed to cache task PGD, so a
-; "global" is used to free-up FIRST core reg to be able to code the rest of
-; exception prologue (IRQ auto-disabled on Exceptions, so it's IRQ-safe).
-; Since the Fast Path TLB Miss handler is coded with 4 regs, the remaining 3
-; need to be saved as well by extending the "global" to be 4 words. Hence
-;      ".size   ex_saved_reg1, 16"
-; [All of this dance is to avoid stack switching for each TLB Miss, since we
-; only need to save only a handful of regs, as opposed to complete reg file]
-;
-; For ARC700 SMP, the "global" obviously can't be used for free up the FIRST
-; core reg as it will not be SMP safe.
-; Thus scratch AUX reg is used (and no longer used to cache task PGD).
-; To save the rest of 3 regs - per cpu, the global is made "per-cpu".
-; Epilogue thus has to locate the "per-cpu" storage for regs.
-; To avoid cache line bouncing the per-cpu global is aligned/sized per
-; L1_CACHE_SHIFT, despite fundamentally needing to be 12 bytes only. Hence
-;      ".size   ex_saved_reg1, (CONFIG_NR_CPUS << L1_CACHE_SHIFT)"
-
-; As simple as that....
-
-.macro TLBMISS_FREEUP_REGS
-#ifdef CONFIG_SMP
-       sr  r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
-       GET_CPU_ID  r0                  ; get to per cpu scratch mem,
-       lsl r0, r0, L1_CACHE_SHIFT      ; cache line wide per cpu
-       add r0, @ex_saved_reg1, r0
-#else
-       st    r0, [@ex_saved_reg1]
-       mov_s r0, @ex_saved_reg1
-#endif
-       st_s  r1, [r0, 4]
-       st_s  r2, [r0, 8]
-       st_s  r3, [r0, 12]
-
-       ; VERIFY if the ASID in MMU-PID Reg is same as
-       ; one in Linux data structures
-
-       DBG_ASID_MISMATCH
-.endm
-
-;-----------------------------------------------------------------
-.macro TLBMISS_RESTORE_REGS
-#ifdef CONFIG_SMP
-       GET_CPU_ID  r0                  ; get to per cpu scratch mem
-       lsl r0, r0, L1_CACHE_SHIFT      ; each is cache line wide
-       add r0, @ex_saved_reg1, r0
-       ld_s  r3, [r0,12]
-       ld_s  r2, [r0, 8]
-       ld_s  r1, [r0, 4]
-       lr    r0, [ARC_REG_SCRATCH_DATA0]
-#else
-       mov_s r0, @ex_saved_reg1
-       ld_s  r3, [r0,12]
-       ld_s  r2, [r0, 8]
-       ld_s  r1, [r0, 4]
-       ld_s  r0, [r0]
-#endif
-.endm
 
 ARCFP_CODE     ;Fast Path Code, candidate for ICCM
 
@@ -277,8 +277,8 @@ ARC_ENTRY EV_TLBMissI
        ;----------------------------------------------------------------
        ; VERIFY_PTE: Check if PTE permissions approp for executing code
        cmp_s   r2, VMALLOC_START
-       mov.lo  r2, (_PAGE_PRESENT | _PAGE_U_EXECUTE)
-       mov.hs  r2, (_PAGE_PRESENT | _PAGE_K_EXECUTE)
+       mov_s   r2, (_PAGE_PRESENT | _PAGE_EXECUTE)
+       or.hs   r2, r2, _PAGE_GLOBAL
 
        and     r3, r0, r2  ; Mask out NON Flag bits from PTE
        xor.f   r3, r3, r2  ; check ( ( pte & flags_test ) == flags_test )
@@ -317,26 +317,21 @@ ARC_ENTRY EV_TLBMissD
        ;----------------------------------------------------------------
        ; VERIFY_PTE: Chk if PTE permissions approp for data access (R/W/R+W)
 
-       mov_s   r2, 0
+       cmp_s   r2, VMALLOC_START
+       mov_s   r2, _PAGE_PRESENT       ; common bit for K/U PTE
+       or.hs   r2, r2, _PAGE_GLOBAL    ; kernel PTE only
+
+       ; Linux PTE [RWX] bits are semantically overloaded:
+       ; -If PAGE_GLOBAL set, they refer to kernel-only flags (vmalloc)
+       ; -Otherwise they are user-mode permissions, and those are exactly
+       ;  same for kernel mode as well (e.g. copy_(to|from)_user)
+
        lr      r3, [ecr]
        btst_s  r3, ECR_C_BIT_DTLB_LD_MISS      ; Read Access
-       or.nz   r2, r2, _PAGE_U_READ            ; chk for Read flag in PTE
+       or.nz   r2, r2, _PAGE_READ              ; chk for Read flag in PTE
        btst_s  r3, ECR_C_BIT_DTLB_ST_MISS      ; Write Access
-       or.nz   r2, r2, _PAGE_U_WRITE           ; chk for Write flag in PTE
-       ; Above laddering takes care of XCHG access
-       ;   which is both Read and Write
-
-       ; If kernel mode access, ; make _PAGE_xx flags as _PAGE_K_xx
-       ; For copy_(to|from)_user, despite exception taken in kernel mode,
-       ; this code is not hit, because EFA would still be the user mode
-       ; address (EFA < 0x6000_0000).
-       ; This code is for legit kernel mode faults, vmalloc specifically
-       ; (EFA: 0x7000_0000 to 0x7FFF_FFFF)
-
-       lr      r3, [efa]
-       cmp     r3, VMALLOC_START - 1   ; If kernel mode access
-       asl.hi  r2, r2, 3               ; make _PAGE_xx flags as _PAGE_K_xx
-       or      r2, r2, _PAGE_PRESENT   ; Common flag for K/U mode
+       or.nz   r2, r2, _PAGE_WRITE             ; chk for Write flag in PTE
+       ; Above laddering takes care of XCHG access (both R and W)
 
        ; By now, r2 setup with all the Flags we need to check in PTE
        and     r3, r0, r2              ; Mask out NON Flag bits from PTE
@@ -371,13 +366,7 @@ do_slow_path_pf:
 
        ; Slow path TLB Miss handled as a regular ARC Exception
        ; (stack switching / save the complete reg-file).
-       ; That requires freeing up r9
-       EXCPN_PROLOG_FREEUP_REG r9
-
-       lr  r9, [erstatus]
-
-       SWITCH_TO_KERNEL_STK
-       SAVE_ALL_SYS
+       EXCEPTION_PROLOGUE
 
        ; ------- setup args for Linux Page fault Hanlder ---------
        mov_s r0, sp
index a00f4c1c7d71795dace4130a4f353edccda7ceef..3f7714d8d2d216bf3bbd7b4a5b227ea982997554 100644 (file)
@@ -3,20 +3,21 @@ config ARM
        default y
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
-       select ARCH_HAVE_CUSTOM_GPIO_H
        select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
+       select ARCH_HAVE_CUSTOM_GPIO_H
        select ARCH_WANT_IPC_PARSE_VERSION
        select BUILDTIME_EXTABLE_SORT if MMU
+       select CLONE_BACKWARDS
        select CPU_PM if (SUSPEND || CPU_IDLE)
        select DCACHE_WORD_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && !CPU_BIG_ENDIAN && MMU
        select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+       select GENERIC_IDLE_POLL_SETUP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select GENERIC_PCI_IOMAP
        select GENERIC_SCHED_CLOCK
        select GENERIC_SMP_IDLE_THREAD
-       select GENERIC_IDLE_POLL_SETUP
        select GENERIC_STRNCPY_FROM_USER
        select GENERIC_STRNLEN_USER
        select HARDIRQS_SW_RESEND
@@ -25,6 +26,7 @@ config ARM
        select HAVE_ARCH_SECCOMP_FILTER
        select HAVE_ARCH_TRACEHOOK
        select HAVE_BPF_JIT
+       select HAVE_CONTEXT_TRACKING
        select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DMA_API_DEBUG
@@ -35,7 +37,6 @@ config ARM
        select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
        select HAVE_FUNCTION_TRACER if (!XIP_KERNEL)
        select HAVE_GENERIC_DMA_COHERENT
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_HW_BREAKPOINT if (PERF_EVENTS && (CPU_V6 || CPU_V6K || CPU_V7))
        select HAVE_IDE if PCI || ISA || PCMCIA
        select HAVE_IRQ_TIME_ACCOUNTING
@@ -47,6 +48,7 @@ config ARM
        select HAVE_KPROBES if !XIP_KERNEL
        select HAVE_KRETPROBES if (HAVE_KPROBES)
        select HAVE_MEMBLOCK
+       select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
        select HAVE_OPROFILE if (HAVE_PERF_EVENTS)
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
@@ -54,15 +56,14 @@ config ARM
        select HAVE_UID16
        select IRQ_FORCED_THREADING
        select KTIME_SCALAR
+       select MODULES_USE_ELF_REL
+       select OLD_SIGACTION
+       select OLD_SIGSUSPEND3
        select PERF_USE_VMALLOC
        select RTC_LIB
        select SYS_SUPPORTS_APM_EMULATION
-       select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
-       select MODULES_USE_ELF_REL
-       select CLONE_BACKWARDS
-       select OLD_SIGSUSPEND3
-       select OLD_SIGACTION
-       select HAVE_CONTEXT_TRACKING
+       # Above selects are sorted alphabetically; please add new ones
+       # according to that.  Thanks.
        help
          The ARM series is a line of low-power-consumption RISC chip designs
          licensed by ARM Ltd and targeted at embedded applications and
@@ -386,8 +387,8 @@ config ARCH_GEMINI
        bool "Cortina Systems Gemini"
        select ARCH_REQUIRE_GPIOLIB
        select ARCH_USES_GETTIMEOFFSET
-       select NEED_MACH_GPIO_H
        select CPU_FA526
+       select NEED_MACH_GPIO_H
        help
          Support for the Cortina Systems Gemini family SoCs
 
@@ -487,8 +488,8 @@ config ARCH_IXP4XX
        select GENERIC_CLOCKEVENTS
        select MIGHT_HAVE_PCI
        select NEED_MACH_IO_H
-       select USB_EHCI_BIG_ENDIAN_MMIO
        select USB_EHCI_BIG_ENDIAN_DESC
+       select USB_EHCI_BIG_ENDIAN_MMIO
        help
          Support for Intel's IXP4XX (XScale) family of processors.
 
@@ -498,11 +499,11 @@ config ARCH_DOVE
        select CPU_PJ4
        select GENERIC_CLOCKEVENTS
        select MIGHT_HAVE_PCI
+       select MVEBU_MBUS
        select PINCTRL
        select PINCTRL_DOVE
        select PLAT_ORION_LEGACY
        select USB_ARCH_HAS_EHCI
-       select MVEBU_MBUS
        help
          Support for the Marvell Dove SoC 88AP510
 
@@ -512,12 +513,12 @@ config ARCH_KIRKWOOD
        select ARCH_REQUIRE_GPIOLIB
        select CPU_FEROCEON
        select GENERIC_CLOCKEVENTS
+       select MVEBU_MBUS
        select PCI
        select PCI_QUIRKS
        select PINCTRL
        select PINCTRL_KIRKWOOD
        select PLAT_ORION_LEGACY
-       select MVEBU_MBUS
        help
          Support for the following Marvell Kirkwood series SoCs:
          88F6180, 88F6192 and 88F6281.
@@ -527,9 +528,9 @@ config ARCH_MV78XX0
        select ARCH_REQUIRE_GPIOLIB
        select CPU_FEROCEON
        select GENERIC_CLOCKEVENTS
+       select MVEBU_MBUS
        select PCI
        select PLAT_ORION_LEGACY
-       select MVEBU_MBUS
        help
          Support for the following Marvell MV78xx0 series SoCs:
          MV781x0, MV782x0.
@@ -540,9 +541,9 @@ config ARCH_ORION5X
        select ARCH_REQUIRE_GPIOLIB
        select CPU_FEROCEON
        select GENERIC_CLOCKEVENTS
+       select MVEBU_MBUS
        select PCI
        select PLAT_ORION_LEGACY
-       select MVEBU_MBUS
        help
          Support for the following Marvell Orion 5x series SoCs:
          Orion-1 (5181), Orion-VoIP (5181L), Orion-NAS (5182),
@@ -557,6 +558,7 @@ config ARCH_MMP
        select GENERIC_CLOCKEVENTS
        select GPIO_PXA
        select IRQ_DOMAIN
+       select MULTI_IRQ_HANDLER
        select NEED_MACH_GPIO_H
        select PINCTRL
        select PLAT_PXA
@@ -757,8 +759,8 @@ config ARCH_S5P64X0
        select HAVE_S3C2410_WATCHDOG if WATCHDOG
        select HAVE_S3C_RTC if RTC_CLASS
        select NEED_MACH_GPIO_H
-       select SAMSUNG_WDT_RESET
        select SAMSUNG_ATAGS
+       select SAMSUNG_WDT_RESET
        help
          Samsung S5P64X0 CPU based systems, such as the Samsung SMDK6440,
          SMDK6450.
@@ -776,8 +778,8 @@ config ARCH_S5PC100
        select HAVE_S3C2410_WATCHDOG if WATCHDOG
        select HAVE_S3C_RTC if RTC_CLASS
        select NEED_MACH_GPIO_H
-       select SAMSUNG_WDT_RESET
        select SAMSUNG_ATAGS
+       select SAMSUNG_WDT_RESET
        help
          Samsung S5PC100 series based systems
 
@@ -1618,9 +1620,10 @@ config HZ_FIXED
                ARCH_S5PV210 || ARCH_EXYNOS4
        default AT91_TIMER_HZ if ARCH_AT91
        default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE
+       default 0
 
 choice
-       depends on !HZ_FIXED
+       depends on HZ_FIXED = 0
        prompt "Timer frequency"
 
 config HZ_100
@@ -1645,7 +1648,7 @@ endchoice
 
 config HZ
        int
-       default HZ_FIXED if HZ_FIXED
+       default HZ_FIXED if HZ_FIXED != 0
        default 100 if HZ_100
        default 200 if HZ_200
        default 250 if HZ_250
index 000cf7628e6e90f49357a25c42a73bf07cc97b67..cc0f1fb61753963d0d6f0a81d63f5d969c100d42 100644 (file)
@@ -198,12 +198,16 @@ dtb-$(CONFIG_ARCH_SHMOBILE) += emev2-kzm9d.dtb \
        emev2-kzm9d-reference.dtb \
        r8a7740-armadillo800eva.dtb \
        r8a7778-bockw.dtb \
+       r8a7778-bockw-reference.dtb \
        r8a7740-armadillo800eva-reference.dtb \
+       r8a7779-marzen.dtb \
        r8a7779-marzen-reference.dtb \
        r8a7790-lager.dtb \
+       r8a7790-lager-reference.dtb \
        sh73a0-kzm9g.dtb \
        sh73a0-kzm9g-reference.dtb \
        r8a73a4-ape6evm.dtb \
+       r8a73a4-ape6evm-reference.dtb \
        sh7372-mackerel.dtb
 dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d-reference.dtb
 dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_cyclone5.dtb \
@@ -227,6 +231,7 @@ dtb-$(CONFIG_ARCH_SUNXI) += \
        sun5i-a10s-olinuxino-micro.dtb \
        sun5i-a13-olinuxino.dtb \
        sun6i-a31-colombus.dtb \
+       sun7i-a20-cubieboard2.dtb \
        sun7i-a20-olinuxino-micro.dtb
 dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
        tegra20-iris-512.dtb \
index bed676b95c27fa6a8122702bc95ebffdca925fa0..cceefda268b62322ec89097fb1798e94bae6de7d 100644 (file)
@@ -21,7 +21,7 @@
        };
 
        chosen {
-               bootargs = "console=ttyS1,115200n81 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096";
+               bootargs = "console=ttyS1,115200n81 ignore_loglevel root=/dev/nfs ip=dhcp";
        };
 
        reg_1p8v: regulator@0 {
index dda13bc02f9f81406aa7bd8c732a9c2db62cf359..f92e812fdd9f3f5b00c7fc0f187e3b75eb90e8b4 100644 (file)
@@ -21,6 +21,6 @@
        };
 
        chosen {
-               bootargs = "console=ttyS1,115200n81 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096";
+               bootargs = "console=ttyS1,115200n81 ignore_loglevel root=/dev/nfs ip=dhcp";
        };
 };
index 99ad2b2e8e140f084596aa52df688260fc07db56..9063a4434d6a59b26e3bac76e24f1643bc6121e8 100644 (file)
                      <0xe0020000 0x0100>;
        };
 
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupts = <0 120 4>,
+                            <0 121 4>;
+       };
+
        sti@e0180000 {
                compatible = "renesas,em-sti";
                reg = <0xe0180000 0x54>;
index 93c2501391591ee32130b18ed2d371bffdcff038..caadc025734210362effb5fe01b5d0d500235e6d 100644 (file)
                compatible = "samsung,exynos4210-pwm";
                reg = <0x139D0000 0x1000>;
                interrupts = <0 37 0>, <0 38 0>, <0 39 0>, <0 40 0>, <0 41 0>;
+               clocks = <&clock 336>;
+               clock-names = "timers";
                #pwm-cells = <2>;
                status = "disabled";
        };
index 6afa57d2feccb15a35a0155e5d5a47dcb6e336f3..074739d39e2db04490c3575fbb2131519f6cf53d 100644 (file)
@@ -95,7 +95,7 @@
                interrupts = <0 54 0>;
        };
 
-       rtc {
+       rtc@101E0000 {
                compatible = "samsung,s3c6410-rtc";
                reg = <0x101E0000 0x100>;
                interrupts = <0 43 0>, <0 44 0>;
index 452d0b04d273274e6380e1712089e16e42f824ce..cee55fa33731195c7230aee40480aef77361b694 100644 (file)
                };
        };
 
-       rtc {
-               status = "okay";
-       };
-
        usb_hub_bus {
                compatible = "simple-bus";
                #address-cells = <1>;
index e79331dba12d24e7c9c7e73d4694894454cf660b..fd711e245e8d311f392bedfed7bb48dee4d4b7e6 100644 (file)
                };
        };
 
-       rtc {
-               status = "okay";
-       };
-
        /*
         * On Snow we've got SIP WiFi and so can keep drive strengths low to
         * reduce EMI.
index f7e2d3493f82d556fd66b88fd6bc6a3549300b5e..7d7cc777ff7b76099e8de5098a4a3a044a208ca9 100644 (file)
                clock-names = "mfc";
        };
 
-       rtc {
+       rtc@101E0000 {
                clocks = <&clock 337>;
                clock-names = "rtc";
+               status = "okay";
        };
 
        tmu@10060000 {
                clocks = <&clock 133>, <&clock 339>;
                clock-names = "sclk_fimd", "fimd";
        };
+
+       adc: adc@12D10000 {
+               compatible = "samsung,exynos-adc-v1";
+               reg = <0x12D10000 0x100>, <0x10040718 0x4>;
+               interrupts = <0 106 0>;
+               clocks = <&clock 303>;
+               clock-names = "adc";
+               #io-channel-cells = <1>;
+               io-channel-ranges;
+               status = "disabled";
+       };
 };
index 5353e32897a444a4f5d13a0bc7174c49fdcf4fca..d537cd704e190b89faec41f3d7509d2e2cb50059 100644 (file)
                interrupts = <0 47 0>;
        };
 
+       rtc@101E0000 {
+               clocks = <&clock 317>;
+               clock-names = "rtc";
+               status = "okay";
+       };
+
        serial@12C00000 {
                clocks = <&clock 257>, <&clock 128>;
                clock-names = "uart", "clk_uart_baud0";
                clocks = <&clock 147>, <&clock 421>;
                clock-names = "sclk_fimd", "fimd";
        };
+
+       adc: adc@12D10000 {
+               compatible = "samsung,exynos-adc-v2";
+               reg = <0x12D10000 0x100>, <0x10040720 0x4>;
+               interrupts = <0 106 0>;
+               clocks = <&clock 270>;
+               clock-names = "adc";
+               #io-channel-cells = <1>;
+               io-channel-ranges;
+               status = "disabled";
+       };
 };
diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
new file mode 100644 (file)
index 0000000..f444624
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Device Tree Source for the APE6EVM board
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/dts-v1/;
+/include/ "r8a73a4.dtsi"
+
+/ {
+       model = "APE6EVM";
+       compatible = "renesas,ape6evm-reference", "renesas,r8a73a4";
+
+       chosen {
+               bootargs = "console=ttySC0,115200 ignore_loglevel rw";
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0 0x40000000>;
+       };
+
+       lbsc {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges = <0 0 0 0x80000000>;
+       };
+};
+
+&i2c5 {
+       vdd_dvfs: max8973@1b {
+               compatible = "maxim,max8973";
+               reg = <0x1b>;
+
+               regulator-min-microvolt = <935000>;
+               regulator-max-microvolt = <1200000>;
+               regulator-boot-on;
+               regulator-always-on;
+       };
+};
+
+&cpu0 {
+       cpu0-supply = <&vdd_dvfs>;
+       operating-points = <
+               /* kHz  uV */
+               1950000 1115000
+               1462500  995000
+       >;
+       voltage-tolerance = <1>; /* 1% */
+};
+
+&pfc {
+       pinctrl-0 = <&scifa0_pins>;
+       pinctrl-names = "default";
+
+       scifa0_pins: scifa0 {
+               renesas,groups = "scifa0_data";
+               renesas,function = "scifa0";
+       };
+};
index e657a9db166612541d9900da8af96ba73a7201a3..72f867e657910e268858091d276353f2cc141d6d 100644 (file)
@@ -16,7 +16,7 @@
        compatible = "renesas,ape6evm", "renesas,r8a73a4";
 
        chosen {
-               bootargs = "console=ttySC0,115200 ignore_loglevel root=/dev/nfs ip=dhcp";
+               bootargs = "console=ttySC0,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw";
        };
 
        memory@40000000 {
index 366f72989dc369b886468d7f25eea7f2f87200c5..c638e4ab91b8ee95655ab0784803f8a2ffb5ce1c 100644 (file)
@@ -17,7 +17,7 @@
        compatible = "renesas,armadillo800eva-reference", "renesas,r8a7740";
 
        chosen {
-               bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096 rw";
+               bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw";
        };
 
        memory {
index 93da655b2598982e9e0635ad4bedd5477d002eb5..426cd9c3e1c430fc214651809be12c489b2765b9 100644 (file)
@@ -16,7 +16,7 @@
        compatible = "renesas,armadillo800eva";
 
        chosen {
-               bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp nfsroot=,rsize=4096,wsize=4096 rw";
+               bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw";
        };
 
        memory {
index e18a195b55f3c7fb7220a9ccdc8dd60b415474ed..44d3d520e01ffd0cce0c48527889d2ddf8e4c230 100644 (file)
                      <0xc2000000 0x1000>;
        };
 
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupts = <0 83 4>;
+       };
+
        /* irqpin0: IRQ0 - IRQ7 */
        irqpin0: irqpin@e6900000 {
                compatible = "renesas,intc-irqpin";
                gpio-controller;
                #gpio-cells = <2>;
        };
+
+       tpu: pwm@e6600000 {
+               compatible = "renesas,tpu-r8a7740", "renesas,tpu";
+               reg = <0xe6600000 0x100>;
+               status = "disabled";
+               #pwm-cells = <3>;
+       };
 };
diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts
new file mode 100644 (file)
index 0000000..9bb903a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Reference Device Tree Source for the Bock-W board
+ *
+ * Copyright (C) 2013  Renesas Solutions Corp.
+ * Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on r8a7779
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 Simon Horman
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/dts-v1/;
+/include/ "r8a7778.dtsi"
+
+/ {
+       model = "bockw";
+       compatible = "renesas,bockw-reference", "renesas,r8a7778";
+
+       chosen {
+               bootargs = "console=ttySC0,115200 ignore_loglevel rw";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x60000000 0x10000000>;
+       };
+};
index 0076b1e8a0fb0f010268cb50338a27e1831a9b3e..12bbebc9c95594bcbcc7093c472c42a4b0a492ca 100644 (file)
@@ -22,7 +22,7 @@
        compatible = "renesas,bockw", "renesas,r8a7778";
 
        chosen {
-               bootargs = "console=ttySC0,115200 ignore_loglevel ip=dhcp root=/dev/nfs";
+               bootargs = "console=ttySC0,115200 ignore_loglevel ip=dhcp root=/dev/nfs rw";
        };
 
        memory {
index b64705be258dd850b2240c469bcc3b85c6264624..6d55083922521619781af8c877ade660ae5ad057 100644 (file)
@@ -18,7 +18,7 @@
        compatible = "renesas,marzen-reference", "renesas,r8a7779";
 
        chosen {
-               bootargs = "console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel root=/dev/nfs ip=on";
+               bootargs = "console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel root=/dev/nfs ip=on rw";
        };
 
        memory {
diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts
new file mode 100644 (file)
index 0000000..f3f7f79
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Device Tree Source for the Marzen board
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ * Copyright (C) 2013 Simon Horman
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/dts-v1/;
+/include/ "r8a7779.dtsi"
+
+/ {
+       model = "marzen";
+       compatible = "renesas,marzen", "renesas,r8a7779";
+
+       chosen {
+               bootargs = "console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel root=/dev/nfs ip=on";
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x60000000 0x40000000>;
+       };
+};
index e9fbe3d572d79ae7a347942c8e233f93b84bb334..23a62447359c1a690f354bada3f3dbcabcbf6286 100644 (file)
                sense-bitfield-width = <2>;
        };
 
-       i2c0: i2c@0xffc70000 {
+       i2c0: i2c@ffc70000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "renesas,rmobile-iic";
                interrupts = <0 79 0x4>;
        };
 
-       i2c1: i2c@0xffc71000 {
+       i2c1: i2c@ffc71000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "renesas,rmobile-iic";
                interrupts = <0 82 0x4>;
        };
 
-       i2c2: i2c@0xffc72000 {
+       i2c2: i2c@ffc72000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "renesas,rmobile-iic";
                interrupts = <0 80 0x4>;
        };
 
-       i2c3: i2c@0xffc73000 {
+       i2c3: i2c@ffc73000 {
                #address-cells = <1>;
                #size-cells = <0>;
                compatible = "renesas,rmobile-iic";
diff --git a/arch/arm/boot/dts/r8a7790-lager-reference.dts b/arch/arm/boot/dts/r8a7790-lager-reference.dts
new file mode 100644 (file)
index 0000000..c462ef1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Device Tree Source for the Lager board
+ *
+ * Copyright (C) 2013 Renesas Solutions Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/dts-v1/;
+/include/ "r8a7790.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+       model = "Lager";
+       compatible = "renesas,lager-reference", "renesas,r8a7790";
+
+       chosen {
+               bootargs = "console=ttySC6,115200 ignore_loglevel rw";
+       };
+
+       memory@40000000 {
+               device_type = "memory";
+               reg = <0 0x40000000 0 0x80000000>;
+       };
+
+       lbsc {
+               #address-cells = <1>;
+               #size-cells = <1>;
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               led6 {
+                       gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
+               };
+               led7 {
+                       gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>;
+               };
+               led8 {
+                       gpios = <&gpio5 17 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
index 09a84fce89d6a3236b360f322af2bf34cb0329af..203bd089af29d83355ed9b2ebdc029045012320f 100644 (file)
@@ -16,7 +16,7 @@
        compatible = "renesas,lager", "renesas,r8a7790";
 
        chosen {
-               bootargs = "console=ttySC6,115200 ignore_loglevel";
+               bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp";
        };
 
        memory@40000000 {
index ff63fbbd18ab5cccf346a9e47590b9baa3e7bfe9..b7f49615120db6527bc9da1e2165b2133ba0e879 100644 (file)
                        compatible = "atmel,at91rm9200-nand";
                        #address-cells = <1>;
                        #size-cells = <1>;
+                       ranges;
                        reg = < 0x60000000 0x01000000   /* EBI CS3 */
                                0xffffc070 0x00000490   /* SMC PMECC regs */
                                0xffffc500 0x00000100   /* SMC PMECC Error Location regs */
-                               0x00100000 0x00100000   /* ROM code */
-                               0x70000000 0x10000000   /* NFC Command Registers */
-                               0xffffc000 0x00000070   /* NFC HSMC regs */
-                               0x00200000 0x00100000   /* NFC SRAM banks */
+                               0x00110000 0x00018000   /* ROM code */
                                >;
                        interrupts = <5 IRQ_TYPE_LEVEL_HIGH 6>;
                        atmel,nand-addr-offset = <21>;
                        atmel,nand-cmd-offset = <22>;
                        pinctrl-names = "default";
                        pinctrl-0 = <&pinctrl_nand0_ale_cle>;
-                       atmel,pmecc-lookup-table-offset = <0x10000 0x18000>;
+                       atmel,pmecc-lookup-table-offset = <0x0 0x8000>;
                        status = "disabled";
+
+                       nfc@70000000 {
+                               compatible = "atmel,sama5d3-nfc";
+                               #address-cells = <1>;
+                               #size-cells = <1>;
+                               reg = <
+                                       0x70000000 0x10000000   /* NFC Command Registers */
+                                       0xffffc000 0x00000070   /* NFC HSMC regs */
+                                       0x00200000 0x00100000   /* NFC SRAM banks */
+                                       >;
+                       };
                };
        };
 };
index 1f8050813a5485c76fecd41c3eef93b54bdcf80a..31ed9e3bb649ab9a6af644d58a36576bc0d3cabd 100644 (file)
@@ -47,8 +47,6 @@
                        atmel,has-pmecc;
                        atmel,pmecc-cap = <4>;
                        atmel,pmecc-sector-size = <512>;
-                       atmel,has-nfc;
-                       atmel,use-nfc-sram;
                        nand-on-flash-bbt;
                        status = "okay";
 
index b99e890def54d7e462da5a3065d0aa565295a910..212230629f271459950547d1af23c143fb67e981 100644 (file)
@@ -33,7 +33,7 @@
        };
 
        chosen {
-               bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200";
+               bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200 rw";
        };
 
        memory {
index 7c4071e7790c34f180e990db3b89293cb8665f1f..0f1ca7792c46acebbbce831371e04200aa89846d 100644 (file)
@@ -16,7 +16,7 @@
        compatible = "renesas,kzm9g", "renesas,sh73a0";
 
        chosen {
-               bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200";
+               bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel earlyprintk=sh-sci.4,115200 rw";
        };
 
        memory {
index 86e79feb7560f95648cad06deafb9e51f5373c26..ba59a5875a10689d14fd96d9102e21814baf2a54 100644 (file)
                      <0xf0000100 0x100>;
        };
 
+       pmu {
+               compatible = "arm,cortex-a9-pmu";
+               interrupts = <0 55 4>,
+                            <0 56 4>;
+       };
+
        irqpin0: irqpin@e6900000 {
                compatible = "renesas,intc-irqpin";
                #interrupt-cells = <2>;
index ee0ff9ba1bca16c592baa9882b63b4c003193c5d..3b4a0574f0689798b070e96970a33afeddd491df 100644 (file)
 
                ahb_gates: ahb_gates@01c20060 {
                        #clock-cells = <1>;
-                       compatible = "allwinner,sun4i-ahb-gates-clk";
+                       compatible = "allwinner,sun5i-a10s-ahb-gates-clk";
                        reg = <0x01c20060 0x8>;
                        clocks = <&ahb>;
-                       clock-output-names = "ahb_usb0", "ahb_ehci0",
-                               "ahb_ohci0", "ahb_ehci1", "ahb_ohci1", "ahb_ss",
-                               "ahb_dma", "ahb_bist", "ahb_mmc0", "ahb_mmc1",
-                               "ahb_mmc2", "ahb_mmc3", "ahb_ms", "ahb_nand",
-                               "ahb_sdram", "ahb_ace", "ahb_emac", "ahb_ts",
-                               "ahb_spi0", "ahb_spi1", "ahb_spi2", "ahb_spi3",
-                               "ahb_pata", "ahb_sata", "ahb_gps", "ahb_ve",
-                               "ahb_tvd", "ahb_tve0", "ahb_tve1", "ahb_lcd0",
-                               "ahb_lcd1", "ahb_csi0", "ahb_csi1", "ahb_hdmi",
-                               "ahb_de_be0", "ahb_de_be1", "ahb_de_fe0",
-                               "ahb_de_fe1", "ahb_mp", "ahb_mali400";
+                       clock-output-names = "ahb_usbotg", "ahb_ehci", "ahb_ohci",
+                               "ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
+                               "ahb_mmc1", "ahb_mmc2", "ahb_nand", "ahb_sdram",
+                               "ahb_emac", "ahb_ts", "ahb_spi0", "ahb_spi1",
+                               "ahb_spi2", "ahb_gps", "ahb_stimer", "ahb_ve",
+                               "ahb_tve", "ahb_lcd", "ahb_csi", "ahb_hdmi",
+                               "ahb_de_be", "ahb_de_fe", "ahb_iep", "ahb_mali400";
                };
 
                apb0: apb0@01c20054 {
 
                apb0_gates: apb0_gates@01c20068 {
                        #clock-cells = <1>;
-                       compatible = "allwinner,sun4i-apb0-gates-clk";
+                       compatible = "allwinner,sun5i-a10s-apb0-gates-clk";
                        reg = <0x01c20068 0x4>;
                        clocks = <&apb0>;
-                       clock-output-names = "apb0_codec", "apb0_spdif",
-                               "apb0_ac97", "apb0_iis", "apb0_pio", "apb0_ir0",
-                               "apb0_ir1", "apb0_keypad";
+                       clock-output-names = "apb0_codec", "apb0_iis", "apb0_pio",
+                               "apb0_ir", "apb0_keypad";
                };
 
                /* dummy is pll62 */
 
                apb1_gates: apb1_gates@01c2006c {
                        #clock-cells = <1>;
-                       compatible = "allwinner,sun4i-apb1-gates-clk";
+                       compatible = "allwinner,sun5i-a10s-apb1-gates-clk";
                        reg = <0x01c2006c 0x4>;
                        clocks = <&apb1>;
                        clock-output-names = "apb1_i2c0", "apb1_i2c1",
-                               "apb1_i2c2", "apb1_can", "apb1_scr",
-                               "apb1_ps20", "apb1_ps21", "apb1_uart0",
-                               "apb1_uart1", "apb1_uart2", "apb1_uart3",
-                               "apb1_uart4", "apb1_uart5", "apb1_uart6",
-                               "apb1_uart7";
+                               "apb1_i2c2", "apb1_uart0", "apb1_uart1",
+                               "apb1_uart2", "apb1_uart3";
                };
        };
 
index 99c4b1847cab6f004e3d9d468197edafaff650e4..e5adae30899b5617ecfefe23d4ff3ad6243cd0f6 100644 (file)
@@ -24,6 +24,8 @@
 
        soc@01c00000 {
                uart0: serial@01c28000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart0_pins_a>;
                        status = "okay";
                };
        };
index 4d076ec248858c64406d4e3cfde50f63e05e9c96..f244f5f02365161706b2442acdad508d3e9c17ec 100644 (file)
 
        clocks {
                #address-cells = <1>;
-               #size-cells = <0>;
+               #size-cells = <1>;
+               ranges;
 
-               osc: oscillator {
+               osc24M: osc24M {
                        #clock-cells = <0>;
                        compatible = "fixed-clock";
                        clock-frequency = <24000000>;
                };
+
+               osc32k: osc32k {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <32768>;
+               };
+
+               pll1: pll1@01c20000 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun6i-a31-pll1-clk";
+                       reg = <0x01c20000 0x4>;
+                       clocks = <&osc24M>;
+               };
+
+               /*
+                * This is a dummy clock, to be used as placeholder on
+                * other mux clocks when a specific parent clock is not
+                * yet implemented. It should be dropped when the driver
+                * is complete.
+                */
+               pll6: pll6 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <0>;
+               };
+
+               cpu: cpu@01c20050 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-cpu-clk";
+                       reg = <0x01c20050 0x4>;
+
+                       /*
+                        * PLL1 is listed twice here.
+                        * While it looks suspicious, it's actually documented
+                        * that way both in the datasheet and in the code from
+                        * Allwinner.
+                        */
+                       clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll1>;
+               };
+
+               axi: axi@01c20050 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-axi-clk";
+                       reg = <0x01c20050 0x4>;
+                       clocks = <&cpu>;
+               };
+
+               ahb1_mux: ahb1_mux@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>;
+               };
+
+               ahb1: ahb1@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-ahb-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&ahb1_mux>;
+               };
+
+               ahb1_gates: ahb1_gates@01c20060 {
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun6i-a31-ahb1-gates-clk";
+                       reg = <0x01c20060 0x8>;
+                       clocks = <&ahb1>;
+                       clock-output-names = "ahb1_mipidsi", "ahb1_ss",
+                                       "ahb1_dma", "ahb1_mmc0", "ahb1_mmc1",
+                                       "ahb1_mmc2", "ahb1_mmc3", "ahb1_nand1",
+                                       "ahb1_nand0", "ahb1_sdram",
+                                       "ahb1_gmac", "ahb1_ts", "ahb1_hstimer",
+                                       "ahb1_spi0", "ahb1_spi1", "ahb1_spi2",
+                                       "ahb1_spi3", "ahb1_otg", "ahb1_ehci0",
+                                       "ahb1_ehci1", "ahb1_ohci0",
+                                       "ahb1_ohci1", "ahb1_ohci2", "ahb1_ve",
+                                       "ahb1_lcd0", "ahb1_lcd1", "ahb1_csi",
+                                       "ahb1_hdmi", "ahb1_de0", "ahb1_de1",
+                                       "ahb1_fe0", "ahb1_fe1", "ahb1_mp",
+                                       "ahb1_gpu", "ahb1_deu0", "ahb1_deu1",
+                                       "ahb1_drc0", "ahb1_drc1";
+               };
+
+               apb1: apb1@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-apb0-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&ahb1>;
+               };
+
+               apb1_gates: apb1_gates@01c20060 {
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun6i-a31-apb1-gates-clk";
+                       reg = <0x01c20068 0x4>;
+                       clocks = <&apb1>;
+                       clock-output-names = "apb1_codec", "apb1_digital_mic",
+                                       "apb1_pio", "apb1_daudio0",
+                                       "apb1_daudio1";
+               };
+
+               apb2_mux: apb2_mux@01c20058 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-apb1-mux-clk";
+                       reg = <0x01c20058 0x4>;
+                       clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+               };
+
+               apb2: apb2@01c20058 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun6i-a31-apb2-div-clk";
+                       reg = <0x01c20058 0x4>;
+                       clocks = <&apb2_mux>;
+               };
+
+               apb2_gates: apb2_gates@01c2006c {
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun6i-a31-apb2-gates-clk";
+                       reg = <0x01c2006c 0x8>;
+                       clocks = <&apb2>;
+                       clock-output-names = "apb2_i2c0", "apb2_i2c1",
+                                       "apb2_i2c2", "apb2_i2c3", "apb2_uart0",
+                                       "apb2_uart1", "apb2_uart2", "apb2_uart3",
+                                       "apb2_uart4", "apb2_uart5";
+               };
        };
 
        soc@01c00000 {
                #size-cells = <1>;
                ranges;
 
+               pio: pinctrl@01c20800 {
+                       compatible = "allwinner,sun6i-a31-pinctrl";
+                       reg = <0x01c20800 0x400>;
+                       interrupts = <0 11 1>, <0 15 1>, <0 16 1>, <0 17 1>;
+                       clocks = <&apb1_gates 5>;
+                       gpio-controller;
+                       interrupt-controller;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #gpio-cells = <3>;
+
+                       uart0_pins_a: uart0@0 {
+                               allwinner,pins = "PH20", "PH21";
+                               allwinner,function = "uart0";
+                               allwinner,drive = <0>;
+                               allwinner,pull = <0>;
+                       };
+               };
+
                timer@01c20c00 {
                        compatible = "allwinner,sun4i-timer";
                        reg = <0x01c20c00 0xa0>;
                                     <0 20 1>,
                                     <0 21 1>,
                                     <0 22 1>;
-                       clocks = <&osc>;
+                       clocks = <&osc24M>;
                };
 
                wdt1: watchdog@01c20ca0 {
                        interrupts = <0 0 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc>;
+                       clocks = <&apb2_gates 16>;
                        status = "disabled";
                };
 
                        interrupts = <0 1 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc>;
+                       clocks = <&apb2_gates 17>;
                        status = "disabled";
                };
 
                        interrupts = <0 2 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc>;
+                       clocks = <&apb2_gates 18>;
                        status = "disabled";
                };
 
                        interrupts = <0 3 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc>;
+                       clocks = <&apb2_gates 19>;
                        status = "disabled";
                };
 
                        interrupts = <0 4 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc>;
+                       clocks = <&apb2_gates 20>;
                        status = "disabled";
                };
 
                        interrupts = <0 5 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc>;
+                       clocks = <&apb2_gates 21>;
                        status = "disabled";
                };
 
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
new file mode 100644 (file)
index 0000000..15e625e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2013 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+
+/ {
+       model = "Cubietech Cubieboard2";
+       compatible = "cubietech,cubieboard2", "allwinner,sun7i-a20";
+
+       soc@01c00000 {
+               emac: ethernet@01c0b000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&emac_pins_a>;
+                       phy = <&phy1>;
+                       status = "okay";
+               };
+
+               mdio@01c0b080 {
+                       status = "okay";
+
+                       phy1: ethernet-phy@1 {
+                               reg = <1>;
+                       };
+               };
+
+               pinctrl@01c20800 {
+                       led_pins_cubieboard2: led_pins@0 {
+                               allwinner,pins = "PH20", "PH21";
+                               allwinner,function = "gpio_out";
+                               allwinner,drive = <0>;
+                               allwinner,pull = <0>;
+                       };
+               };
+
+               uart0: serial@01c28000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart0_pins_a>;
+                       status = "okay";
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&led_pins_cubieboard2>;
+
+               blue {
+                       label = "cubieboard2:blue:usr";
+                       gpios = <&pio 7 21 0>;
+               };
+
+               green {
+                       label = "cubieboard2:green:usr";
+                       gpios = <&pio 7 20 0>;
+               };
+       };
+};
index d3395846491c79ecd37acc2d2f79d5c9e891809c..9e778557fadb4b17eac49c86bf78d4855e229dc4 100644 (file)
        compatible = "olimex,a20-olinuxino-micro", "allwinner,sun7i-a20";
 
        soc@01c00000 {
+               emac: ethernet@01c0b000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&emac_pins_a>;
+                       phy = <&phy1>;
+                       status = "okay";
+               };
+
+               mdio@01c0b080 {
+                       status = "okay";
+
+                       phy1: ethernet-phy@1 {
+                               reg = <1>;
+                       };
+               };
+
+               pinctrl@01c20800 {
+                       led_pins_olinuxino: led_pins@0 {
+                               allwinner,pins = "PH2";
+                               allwinner,function = "gpio_out";
+                               allwinner,drive = <1>;
+                               allwinner,pull = <0>;
+                       };
+               };
+
                uart0: serial@01c28000 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart0_pins_a>;
                        status = "okay";
                };
 
                uart6: serial@01c29800 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart6_pins_a>;
                        status = "okay";
                };
 
                uart7: serial@01c29c00 {
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&uart7_pins_a>;
                        status = "okay";
                };
        };
+
+       leds {
+               compatible = "gpio-leds";
+               pinctrl-names = "default";
+               pinctrl-0 = <&led_pins_olinuxino>;
+
+               green {
+                       label = "a20-olinuxino-micro:green:usr";
+                       gpios = <&pio 7 2 0>;
+                       default-state = "on";
+               };
+       };
 };
index 33391517118cd396d7acb7d421008b50ebea0a3f..80559cbdbc879106d21e6794814f6e767d1653c1 100644 (file)
@@ -44,7 +44,8 @@
 
                osc24M: osc24M@01c20050 {
                        #clock-cells = <0>;
-                       compatible = "fixed-clock";
+                       compatible = "allwinner,sun4i-osc-clk";
+                       reg = <0x01c20050 0x4>;
                        clock-frequency = <24000000>;
                };
 
                        compatible = "fixed-clock";
                        clock-frequency = <32768>;
                };
+
+               pll1: pll1@01c20000 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-pll1-clk";
+                       reg = <0x01c20000 0x4>;
+                       clocks = <&osc24M>;
+               };
+
+               /*
+                * This is a dummy clock, to be used as placeholder on
+                * other mux clocks when a specific parent clock is not
+                * yet implemented. It should be dropped when the driver
+                * is complete.
+                */
+               pll6: pll6 {
+                       #clock-cells = <0>;
+                       compatible = "fixed-clock";
+                       clock-frequency = <0>;
+               };
+
+               cpu: cpu@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-cpu-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&osc32k>, <&osc24M>, <&pll1>, <&pll6>;
+               };
+
+               axi: axi@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-axi-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&cpu>;
+               };
+
+               ahb: ahb@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-ahb-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&axi>;
+               };
+
+               ahb_gates: ahb_gates@01c20060 {
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun7i-a20-ahb-gates-clk";
+                       reg = <0x01c20060 0x8>;
+                       clocks = <&ahb>;
+                       clock-output-names = "ahb_usb0", "ahb_ehci0",
+                               "ahb_ohci0", "ahb_ehci1", "ahb_ohci1",
+                               "ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
+                               "ahb_mmc1", "ahb_mmc2", "ahb_mmc3", "ahb_ms",
+                               "ahb_nand", "ahb_sdram", "ahb_ace",
+                               "ahb_emac", "ahb_ts", "ahb_spi0", "ahb_spi1",
+                               "ahb_spi2", "ahb_spi3", "ahb_sata",
+                               "ahb_hstimer", "ahb_ve", "ahb_tvd", "ahb_tve0",
+                               "ahb_tve1", "ahb_lcd0", "ahb_lcd1", "ahb_csi0",
+                               "ahb_csi1", "ahb_hdmi1", "ahb_hdmi0",
+                               "ahb_de_be0", "ahb_de_be1", "ahb_de_fe0",
+                               "ahb_de_fe1", "ahb_gmac", "ahb_mp",
+                               "ahb_mali";
+               };
+
+               apb0: apb0@01c20054 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-apb0-clk";
+                       reg = <0x01c20054 0x4>;
+                       clocks = <&ahb>;
+               };
+
+               apb0_gates: apb0_gates@01c20068 {
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun7i-a20-apb0-gates-clk";
+                       reg = <0x01c20068 0x4>;
+                       clocks = <&apb0>;
+                       clock-output-names = "apb0_codec", "apb0_spdif",
+                               "apb0_ac97", "apb0_iis0", "apb0_iis1",
+                               "apb0_pio", "apb0_ir0", "apb0_ir1",
+                               "apb0_iis2", "apb0_keypad";
+               };
+
+               apb1_mux: apb1_mux@01c20058 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-apb1-mux-clk";
+                       reg = <0x01c20058 0x4>;
+                       clocks = <&osc24M>, <&pll6>, <&osc32k>;
+               };
+
+               apb1: apb1@01c20058 {
+                       #clock-cells = <0>;
+                       compatible = "allwinner,sun4i-apb1-clk";
+                       reg = <0x01c20058 0x4>;
+                       clocks = <&apb1_mux>;
+               };
+
+               apb1_gates: apb1_gates@01c2006c {
+                       #clock-cells = <1>;
+                       compatible = "allwinner,sun7i-a20-apb1-gates-clk";
+                       reg = <0x01c2006c 0x4>;
+                       clocks = <&apb1>;
+                       clock-output-names = "apb1_i2c0", "apb1_i2c1",
+                               "apb1_i2c2", "apb1_i2c3", "apb1_can",
+                               "apb1_scr", "apb1_ps20", "apb1_ps21",
+                               "apb1_i2c4", "apb1_uart0", "apb1_uart1",
+                               "apb1_uart2", "apb1_uart3", "apb1_uart4",
+                               "apb1_uart5", "apb1_uart6", "apb1_uart7";
+               };
        };
 
        soc@01c00000 {
                #size-cells = <1>;
                ranges;
 
+               emac: ethernet@01c0b000 {
+                       compatible = "allwinner,sun4i-emac";
+                       reg = <0x01c0b000 0x1000>;
+                       interrupts = <0 55 1>;
+                       clocks = <&ahb_gates 17>;
+                       status = "disabled";
+               };
+
+               mdio@01c0b080 {
+                       compatible = "allwinner,sun4i-mdio";
+                       reg = <0x01c0b080 0x14>;
+                       status = "disabled";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+               };
+
+               pio: pinctrl@01c20800 {
+                       compatible = "allwinner,sun7i-a20-pinctrl";
+                       reg = <0x01c20800 0x400>;
+                       interrupts = <0 28 1>;
+                       clocks = <&apb0_gates 5>;
+                       gpio-controller;
+                       interrupt-controller;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       #gpio-cells = <3>;
+
+                       uart0_pins_a: uart0@0 {
+                               allwinner,pins = "PB22", "PB23";
+                               allwinner,function = "uart0";
+                               allwinner,drive = <0>;
+                               allwinner,pull = <0>;
+                       };
+
+                       uart6_pins_a: uart6@0 {
+                               allwinner,pins = "PI12", "PI13";
+                               allwinner,function = "uart6";
+                               allwinner,drive = <0>;
+                               allwinner,pull = <0>;
+                       };
+
+                       uart7_pins_a: uart7@0 {
+                               allwinner,pins = "PI20", "PI21";
+                               allwinner,function = "uart7";
+                               allwinner,drive = <0>;
+                               allwinner,pull = <0>;
+                       };
+
+                       emac_pins_a: emac0@0 {
+                               allwinner,pins = "PA0", "PA1", "PA2",
+                                               "PA3", "PA4", "PA5", "PA6",
+                                               "PA7", "PA8", "PA9", "PA10",
+                                               "PA11", "PA12", "PA13", "PA14",
+                                               "PA15", "PA16";
+                               allwinner,function = "emac";
+                               allwinner,drive = <0>;
+                               allwinner,pull = <0>;
+                       };
+               };
+
                timer@01c20c00 {
                        compatible = "allwinner,sun4i-timer";
                        reg = <0x01c20c00 0x90>;
                        interrupts = <0 1 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 16>;
                        status = "disabled";
                };
 
                        interrupts = <0 2 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 17>;
                        status = "disabled";
                };
 
                        interrupts = <0 3 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 18>;
                        status = "disabled";
                };
 
                        interrupts = <0 4 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 19>;
                        status = "disabled";
                };
 
                        interrupts = <0 17 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 20>;
                        status = "disabled";
                };
 
                        interrupts = <0 18 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 21>;
                        status = "disabled";
                };
 
                        interrupts = <0 19 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 22>;
                        status = "disabled";
                };
 
                        interrupts = <0 20 1>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       clocks = <&osc24M>;
+                       clocks = <&apb1_gates 23>;
                        status = "disabled";
                };
 
index 759b0cd2001333ee323da4dc70a330a6a532c72f..15f98cbcb75a3be41737c208b772db8a161ed8d1 100644 (file)
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <0>;
+                       cci-control-port = <&cci_control1>;
                };
 
                cpu1: cpu@1 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a15";
                        reg = <1>;
+                       cci-control-port = <&cci_control1>;
                };
 
                cpu2: cpu@2 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
                        reg = <0x100>;
+                       cci-control-port = <&cci_control2>;
                };
 
                cpu3: cpu@3 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
                        reg = <0x101>;
+                       cci-control-port = <&cci_control2>;
                };
 
                cpu4: cpu@4 {
                        device_type = "cpu";
                        compatible = "arm,cortex-a7";
                        reg = <0x102>;
+                       cci-control-port = <&cci_control2>;
                };
        };
 
                interrupts = <1 9 0xf04>;
        };
 
+       cci@2c090000 {
+               compatible = "arm,cci-400";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0 0x2c090000 0 0x1000>;
+               ranges = <0x0 0x0 0x2c090000 0x10000>;
+
+               cci_control1: slave-if@4000 {
+                       compatible = "arm,cci-400-ctrl-if";
+                       interface-type = "ace";
+                       reg = <0x4000 0x1000>;
+               };
+
+               cci_control2: slave-if@5000 {
+                       compatible = "arm,cci-400-ctrl-if";
+                       interface-type = "ace";
+                       reg = <0x5000 0x1000>;
+               };
+       };
+
        memory-controller@7ffd0000 {
                compatible = "arm,pl354", "arm,primecell";
                reg = <0 0x7ffd0000 0 0x1000>;
index 39ad030ac0c72b529b9cf3166a003b9feaa1f879..117f955a2a063b7e57cbbd0a05806ce3413814a7 100644 (file)
@@ -1235,6 +1235,23 @@ void edma_resume(unsigned channel)
 }
 EXPORT_SYMBOL(edma_resume);
 
+int edma_trigger_channel(unsigned channel)
+{
+       unsigned ctlr;
+       unsigned int mask;
+
+       ctlr = EDMA_CTLR(channel);
+       channel = EDMA_CHAN_SLOT(channel);
+       mask = BIT(channel & 0x1f);
+
+       edma_shadow0_write_array(ctlr, SH_ESR, (channel >> 5), mask);
+
+       pr_debug("EDMA: ESR%d %08x\n", (channel >> 5),
+                edma_shadow0_read_array(ctlr, SH_ESR, (channel >> 5)));
+       return 0;
+}
+EXPORT_SYMBOL(edma_trigger_channel);
+
 /**
  * edma_start - start dma on a channel
  * @channel: channel being activated
index 023ee63827a2baad853768e740759c9551b28cfa..e901d0f3e0bbcd735f5cf7e62bd653536ff8aa71 100644 (file)
@@ -166,7 +166,8 @@ static int sp804_set_next_event(unsigned long next,
 }
 
 static struct clock_event_device sp804_clockevent = {
-       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+       .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+               CLOCK_EVT_FEAT_DYNIRQ,
        .set_mode       = sp804_set_mode,
        .set_next_event = sp804_set_next_event,
        .rating         = 300,
diff --git a/arch/arm/configs/ag5evm_defconfig b/arch/arm/configs/ag5evm_defconfig
deleted file mode 100644 (file)
index 212ead3..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_EXPERT=y
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_SHMOBILE=y
-CONFIG_ARCH_SH73A0=y
-CONFIG_MACH_AG5EVM=y
-CONFIG_MEMORY_SIZE=0x10000000
-CONFIG_CPU_BPREDICT_DISABLE=y
-CONFIG_ARM_ERRATA_430973=y
-CONFIG_ARM_ERRATA_458693=y
-CONFIG_NO_HZ=y
-CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=tty0 console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel"
-CONFIG_CMDLINE_FORCE=y
-CONFIG_KEXEC=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM=y
-# CONFIG_SUSPEND is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_BLK_DEV is not set
-CONFIG_NETDEVICES=y
-CONFIG_NET_ETHERNET=y
-CONFIG_SMSC911X=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-# CONFIG_WLAN is not set
-CONFIG_INPUT_SPARSEKMAP=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=9
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_SH_MOBILE=y
-# CONFIG_HWMON is not set
-# CONFIG_MFD_SUPPORT is not set
-CONFIG_FB=y
-CONFIG_FB_SH_MOBILE_LCDC=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-# CONFIG_INOTIFY_USER is not set
-CONFIG_TMPFS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_FTRACE is not set
index 75fd842d4071336cc5cb88cfee58beebdf72425e..690e89273230b06c2ca87c01bc623f21a9c5ef32 100644 (file)
@@ -14,11 +14,13 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_IOSCHED_DEADLINE is not set
 # CONFIG_IOSCHED_CFQ is not set
 CONFIG_ARCH_AT91=y
+CONFIG_SOC_AT91RM9200=y
 CONFIG_SOC_AT91SAM9260=y
 CONFIG_SOC_AT91SAM9263=y
 CONFIG_SOC_AT91SAM9G45=y
 CONFIG_SOC_AT91SAM9X5=y
 CONFIG_SOC_AT91SAM9N12=y
+CONFIG_MACH_AT91RM9200_DT=y
 CONFIG_MACH_AT91SAM9_DT=y
 CONFIG_AT91_PROGRAMMABLE_CLOCKS=y
 CONFIG_AT91_TIMER_HZ=128
@@ -62,6 +64,7 @@ CONFIG_MTD=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
+CONFIG_MTD_DATAFLASH=y
 CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_ATMEL=y
 CONFIG_MTD_UBI=y
@@ -78,7 +81,6 @@ CONFIG_BLK_DEV_SD=y
 CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_LOWLEVEL is not set
 CONFIG_NETDEVICES=y
-CONFIG_MII=y
 CONFIG_MACB=y
 # CONFIG_NET_VENDOR_BROADCOM is not set
 # CONFIG_NET_VENDOR_FARADAY is not set
diff --git a/arch/arm/configs/kota2_defconfig b/arch/arm/configs/kota2_defconfig
deleted file mode 100644 (file)
index 57ad3d4..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_EXPERIMENTAL=y
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_CGROUPS=y
-CONFIG_CPUSETS=y
-CONFIG_NAMESPACES=y
-# CONFIG_UTS_NS is not set
-# CONFIG_IPC_NS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_PID_NS is not set
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_SHMOBILE=y
-CONFIG_KEYBOARD_GPIO_POLLED=y
-CONFIG_ARCH_SH73A0=y
-CONFIG_MACH_KOTA2=y
-CONFIG_MEMORY_SIZE=0x1e000000
-# CONFIG_SH_TIMER_TMU is not set
-# CONFIG_SWP_EMULATE is not set
-CONFIG_CPU_BPREDICT_DISABLE=y
-CONFIG_ARM_ERRATA_460075=y
-CONFIG_ARM_ERRATA_742230=y
-CONFIG_ARM_ERRATA_742231=y
-CONFIG_PL310_ERRATA_588369=y
-CONFIG_ARM_ERRATA_720789=y
-CONFIG_PL310_ERRATA_727915=y
-CONFIG_ARM_ERRATA_743622=y
-CONFIG_ARM_ERRATA_751472=y
-CONFIG_PL310_ERRATA_753970=y
-CONFIG_ARM_ERRATA_754322=y
-CONFIG_PL310_ERRATA_769419=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttySC2,115200 earlyprintk=sh-sci.2,115200 ignore_loglevel"
-CONFIG_CMDLINE_FORCE=y
-CONFIG_KEXEC=y
-CONFIG_CPU_IDLE=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_CFG80211=y
-CONFIG_WIRELESS_EXT_SYSFS=y
-CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-# CONFIG_BLK_DEV is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_CHELSIO is not set
-# CONFIG_NET_VENDOR_FARADAY is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-# CONFIG_NET_VENDOR_SEEQ is not set
-CONFIG_SMSC911X=y
-# CONFIG_NET_VENDOR_STMICRO is not set
-CONFIG_B43=y
-CONFIG_B43_PHY_N=y
-CONFIG_B43_DEBUG=y
-CONFIG_INPUT_SPARSEKMAP=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-CONFIG_KEYBOARD_SH_KEYSC=y
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=9
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C_SH_MOBILE=y
-# CONFIG_HWMON is not set
-CONFIG_BCMA=y
-CONFIG_BCMA_DEBUG=y
-CONFIG_FB=y
-CONFIG_FB_SH_MOBILE_LCDC=y
-CONFIG_LCD_PLATFORM=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-# CONFIG_HID_SUPPORT is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-CONFIG_MMC_SDHI=y
-CONFIG_MMC_SH_MMCIF=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_RENESAS_TPU=y
-CONFIG_LEDS_TRIGGERS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_INFO_REDUCED=y
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_USER=y
index e072bb2ba1b12761d579b44cf951ba97d28b0386..4f8e9e5514b14486c8b9a6fdcc652af966bceeda 100644 (file)
@@ -5,7 +5,6 @@
 #ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
-#include <asm-generic/dma-contiguous.h>
 
 void dma_contiguous_early_fixup(phys_addr_t base, unsigned long size);
 
index 69b879ac0289fde3a1ce8776b7d3602078286be7..402a2bc6aa687b94b09af6efa039c58fb80436d2 100644 (file)
@@ -35,7 +35,7 @@ struct machine_desc {
        unsigned int            nr_irqs;        /* number of IRQs */
 
 #ifdef CONFIG_ZONE_DMA
-       unsigned long           dma_zone_size;  /* size of DMA-able area */
+       phys_addr_t             dma_zone_size;  /* size of DMA-able area */
 #endif
 
        unsigned int            video_start;    /* start of video RAM   */
index 12f71a19042253bdd107e78bff70235bb970b75b..f94784f0e3a6cee0a094125799111c302e2eed25 100644 (file)
@@ -37,10 +37,10 @@ struct outer_cache_fns {
        void (*resume)(void);
 };
 
-#ifdef CONFIG_OUTER_CACHE
-
 extern struct outer_cache_fns outer_cache;
 
+#ifdef CONFIG_OUTER_CACHE
+
 static inline void outer_inv_range(phys_addr_t start, phys_addr_t end)
 {
        if (outer_cache.inv_range)
index aaf3a87311360d5c9db1531db9c3436af26237cd..bd454b09133e38274d6af8fbe6ba2a36fab7dab7 100644 (file)
@@ -49,5 +49,5 @@ $(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S
 ifeq ($(CONFIG_KERNEL_MODE_NEON),y)
   NEON_FLAGS                   := -mfloat-abi=softfp -mfpu=neon
   CFLAGS_xor-neon.o            += $(NEON_FLAGS)
-  lib-$(CONFIG_XOR_BLOCKS)     += xor-neon.o
+  obj-$(CONFIG_XOR_BLOCKS)     += xor-neon.o
 endif
index f485e5a2af4bbbe2e931668adbc69fc7f4ec6359..2c40aeab3eaae8cb038a283b6fa2dc422d744d08 100644 (file)
@@ -9,6 +9,9 @@
  */
 
 #include <linux/raid/xor.h>
+#include <linux/module.h>
+
+MODULE_LICENSE("GPL");
 
 #ifndef __ARM_NEON__
 #error You should compile this file with '-mfloat-abi=softfp -mfpu=neon'
@@ -40,3 +43,4 @@ struct xor_block_template const xor_block_neon_inner = {
        .do_4   = xor_8regs_4,
        .do_5   = xor_8regs_5,
 };
+EXPORT_SYMBOL(xor_block_neon_inner);
index a832e0707611714246e36ef37ff9b2a59faaf53e..f17aa3150019bfe3e16ed1fa67e48a434f9c12ae 100644 (file)
@@ -33,6 +33,7 @@
 #include <mach/at91sam9g45.h>
 #include <mach/at91sam9x5.h>
 #include <mach/at91sam9n12.h>
+#include <mach/sama5d3.h>
 
 /*
  * On all at91 except rm9200 and x40 have the System Controller starts
index 6dc81ee38048c3ee1e874e37352fccea5adcef0b..31096a8aaf1d507287d62f6ef8250096f7ee09ea 100644 (file)
 #define SAMA5D3_ID_TRNG                45      /* True Random Generator Number */
 #define SAMA5D3_ID_IRQ0                47      /* Advanced Interrupt Controller (IRQ0) */
 
+/*
+ * User Peripheral physical base addresses.
+ */
+#define SAMA5D3_BASE_USART0    0xf001c000
+#define SAMA5D3_BASE_USART1    0xf0020000
+#define SAMA5D3_BASE_USART2    0xf8020000
+#define SAMA5D3_BASE_USART3    0xf8024000
+
 /*
  * Internal Memory
  */
index 5659f7c72120ef8600cd77ffb5bc6fee458d94fe..4bb644f8e87c08a9119688968893b8cda217f927 100644 (file)
@@ -94,6 +94,15 @@ static const u32 uarts_sam9x5[] = {
        0,
 };
 
+static const u32 uarts_sama5[] = {
+       AT91_BASE_DBGU1,
+       SAMA5D3_BASE_USART0,
+       SAMA5D3_BASE_USART1,
+       SAMA5D3_BASE_USART2,
+       SAMA5D3_BASE_USART3,
+       0,
+};
+
 static inline const u32* decomp_soc_detect(void __iomem *dbgu_base)
 {
        u32 cidr, socid;
@@ -121,8 +130,12 @@ static inline const u32* decomp_soc_detect(void __iomem *dbgu_base)
        case ARCH_ID_AT91SAM9RL64:
                return uarts_sam9rl;
 
+       case ARCH_ID_AT91SAM9N12:
        case ARCH_ID_AT91SAM9X5:
                return uarts_sam9x5;
+
+       case ARCH_ID_SAMA5D3:
+               return uarts_sama5;
        }
 
        /* at91sam9g10 */
index df8612fbbc9c185f80c100c40569e2171657acf2..3f12b885c083ac37424bdb9e44ca478f09a3c12b 100644 (file)
@@ -281,7 +281,7 @@ static AMBA_APB_DEVICE(uart1, "apb:uart1", 0x00041010, EP93XX_UART1_PHYS_BASE,
        { IRQ_EP93XX_UART1 }, &ep93xx_uart_data);
 
 static AMBA_APB_DEVICE(uart2, "apb:uart2", 0x00041010, EP93XX_UART2_PHYS_BASE,
-       { IRQ_EP93XX_UART2 }, &ep93xx_uart_data);
+       { IRQ_EP93XX_UART2 }, NULL);
 
 static AMBA_APB_DEVICE(uart3, "apb:uart3", 0x00041010, EP93XX_UART3_PHYS_BASE,
        { IRQ_EP93XX_UART3 }, &ep93xx_uart_data);
index 64f2e50e19ca10d9ae7a7105c72e66011f1a2f6d..6bc1c181581d5767376a13f60c61d8cf8a7dc65c 100644 (file)
@@ -224,62 +224,15 @@ static struct ep93xx_spi_chip_ops vision_spi_flash_hw = {
 #define VISION_SPI_MMC_WP      EP93XX_GPIO_LINE_F(0)
 #define VISION_SPI_MMC_CD      EP93XX_GPIO_LINE_EGPIO15
 
-static struct gpio vision_spi_mmc_gpios[] = {
-       { VISION_SPI_MMC_WP, GPIOF_DIR_IN, "mmc_spi:wp" },
-       { VISION_SPI_MMC_CD, GPIOF_DIR_IN, "mmc_spi:cd" },
-};
-
-static int vision_spi_mmc_init(struct device *pdev,
-                       irqreturn_t (*func)(int, void *), void *pdata)
-{
-       int err;
-
-       err = gpio_request_array(vision_spi_mmc_gpios,
-                                ARRAY_SIZE(vision_spi_mmc_gpios));
-       if (err)
-               return err;
-
-       err = gpio_set_debounce(VISION_SPI_MMC_CD, 1);
-       if (err)
-               goto exit_err;
-
-       err = request_irq(gpio_to_irq(VISION_SPI_MMC_CD), func,
-                       IRQ_TYPE_EDGE_BOTH, "mmc_spi:cd", pdata);
-       if (err)
-               goto exit_err;
-
-       return 0;
-
-exit_err:
-       gpio_free_array(vision_spi_mmc_gpios, ARRAY_SIZE(vision_spi_mmc_gpios));
-       return err;
-
-}
-
-static void vision_spi_mmc_exit(struct device *pdev, void *pdata)
-{
-       free_irq(gpio_to_irq(VISION_SPI_MMC_CD), pdata);
-       gpio_free_array(vision_spi_mmc_gpios, ARRAY_SIZE(vision_spi_mmc_gpios));
-}
-
-static int vision_spi_mmc_get_ro(struct device *pdev)
-{
-       return !!gpio_get_value(VISION_SPI_MMC_WP);
-}
-
-static int vision_spi_mmc_get_cd(struct device *pdev)
-{
-       return !gpio_get_value(VISION_SPI_MMC_CD);
-}
-
 static struct mmc_spi_platform_data vision_spi_mmc_data = {
-       .init           = vision_spi_mmc_init,
-       .exit           = vision_spi_mmc_exit,
-       .get_ro         = vision_spi_mmc_get_ro,
-       .get_cd         = vision_spi_mmc_get_cd,
        .detect_delay   = 100,
        .powerup_msecs  = 100,
        .ocr_mask       = MMC_VDD_32_33 | MMC_VDD_33_34,
+       .flags          = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
+       .cd_gpio        = VISION_SPI_MMC_CD,
+       .cd_debounce    = 1,
+       .ro_gpio        = VISION_SPI_MMC_WP,
+       .caps2          = MMC_CAP2_RO_ACTIVE_HIGH,
 };
 
 static int vision_spi_mmc_hw_setup(struct spi_device *spi)
index 5952e68c76c40e622e828a9e1849542b69f12aad..56fe819ee10b0dd17919e61fdec71cd403b1d6de 100644 (file)
@@ -36,6 +36,7 @@ config CPU_EXYNOS4210
        bool "SAMSUNG EXYNOS4210"
        default y
        depends on ARCH_EXYNOS4
+       select ARCH_HAS_BANDGAP
        select ARM_CPU_SUSPEND if PM
        select PINCTRL_EXYNOS
        select PM_GENERIC_DOMAINS if PM
@@ -49,7 +50,9 @@ config SOC_EXYNOS4212
        bool "SAMSUNG EXYNOS4212"
        default y
        depends on ARCH_EXYNOS4
+       select ARCH_HAS_BANDGAP
        select PINCTRL_EXYNOS
+       select PM_GENERIC_DOMAINS if PM
        select S5P_PM if PM
        select S5P_SLEEP if PM
        select SAMSUNG_DMADEV
@@ -60,7 +63,9 @@ config SOC_EXYNOS4412
        bool "SAMSUNG EXYNOS4412"
        default y
        depends on ARCH_EXYNOS4
+       select ARCH_HAS_BANDGAP
        select PINCTRL_EXYNOS
+       select PM_GENERIC_DOMAINS if PM
        select SAMSUNG_DMADEV
        help
          Enable EXYNOS4412 SoC support
@@ -69,6 +74,7 @@ config SOC_EXYNOS5250
        bool "SAMSUNG EXYNOS5250"
        default y
        depends on ARCH_EXYNOS5
+       select ARCH_HAS_BANDGAP
        select PINCTRL_EXYNOS
        select PM_GENERIC_DOMAINS if PM
        select S5P_PM if PM
@@ -93,6 +99,7 @@ config SOC_EXYNOS5440
        default y
        depends on ARCH_EXYNOS5
        select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
+       select ARCH_HAS_BANDGAP
        select ARCH_HAS_OPP
        select HAVE_ARM_ARCH_TIMER
        select AUTO_ZRELADDR
index 225ee8431c7282d1301d17c255687189482e7042..ac139226d63c1d1aefe86a7e25087ad7e6da36da 100644 (file)
@@ -200,6 +200,9 @@ static int __init exynos4_init_cpuidle(void)
        if (soc_is_exynos5250())
                exynos5_core_down_clk();
 
+       if (soc_is_exynos5440())
+               exynos4_idle_driver.state_count = 1;
+
        ret = cpuidle_register_driver(&exynos4_idle_driver);
        if (ret) {
                printk(KERN_ERR "CPUidle failed to register driver\n");
index 6acbdabf62226d01063f8468e883c38dc50c8f80..8e8437dea3ce7742da2cd8cae56df82efa2dfe93 100644 (file)
@@ -1,9 +1,14 @@
 config ARCH_HIGHBANK
        bool "Calxeda ECX-1000/2000 (Highbank/Midway)" if ARCH_MULTI_V7
+       select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
        select ARCH_HAS_CPUFREQ
+       select ARCH_HAS_HOLES_MEMORYMODEL
        select ARCH_HAS_OPP
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select ARM_AMBA
+       select ARM_ERRATA_764369
+       select ARM_ERRATA_775420
+       select ARM_ERRATA_798181
        select ARM_GIC
        select ARM_TIMER_SP804
        select CACHE_L2X0
@@ -18,3 +23,4 @@ config ARCH_HIGHBANK
        select PL320_MBOX
        select SPARSE_IRQ
        select USE_OF
+       select ZONE_DMA if ARM_LPAE
index 88815795fe2678f7c41e54fd296397ace8de9a62..8e63ccdb0de3c9c80923e46eadec91e6e9e1689e 100644 (file)
 #include <linux/clocksource.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
-#include <linux/irq.h>
 #include <linux/irqchip.h>
-#include <linux/irqdomain.h>
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 #include <linux/of_address.h>
-#include <linux/smp.h>
 #include <linux/amba/bus.h>
 #include <linux/clk-provider.h>
 
@@ -35,7 +32,6 @@
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
-#include <asm/mach/time.h>
 
 #include "core.h"
 #include "sysregs.h"
@@ -65,13 +61,11 @@ void highbank_set_cpu_jump(int cpu, void *jump_addr)
                          HB_JUMP_TABLE_PHYS(cpu) + 15);
 }
 
-#ifdef CONFIG_CACHE_L2X0
 static void highbank_l2x0_disable(void)
 {
        /* Disable PL310 L2 Cache controller */
        highbank_smc1(0x102, 0x0);
 }
-#endif
 
 static void __init highbank_init_irq(void)
 {
@@ -80,12 +74,13 @@ static void __init highbank_init_irq(void)
        if (of_find_compatible_node(NULL, NULL, "arm,cortex-a9"))
                highbank_scu_map_io();
 
-#ifdef CONFIG_CACHE_L2X0
        /* Enable PL310 L2 Cache controller */
-       highbank_smc1(0x102, 0x1);
-       l2x0_of_init(0, ~0UL);
-       outer_cache.disable = highbank_l2x0_disable;
-#endif
+       if (IS_ENABLED(CONFIG_CACHE_L2X0) &&
+           of_find_compatible_node(NULL, NULL, "arm,pl310-cache")) {
+               highbank_smc1(0x102, 0x1);
+               l2x0_of_init(0, ~0UL);
+               outer_cache.disable = highbank_l2x0_disable;
+       }
 }
 
 static void __init highbank_timer_init(void)
@@ -176,6 +171,9 @@ static const char *highbank_match[] __initconst = {
 };
 
 DT_MACHINE_START(HIGHBANK, "Highbank")
+#if defined(CONFIG_ZONE_DMA) && defined(CONFIG_ARM_LPAE)
+       .dma_zone_size  = (4ULL * SZ_1G),
+#endif
        .smp            = smp_ops(highbank_smp_ops),
        .init_irq       = highbank_init_irq,
        .init_time      = highbank_timer_init,
index 3451f1f8ba1ffbbde02f11984158ae09b8d4e1c6..048c5ad8a80b67ed54b7d2dfa7f2d746a1356f30 100644 (file)
@@ -89,7 +89,8 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
 static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
                u8 shift, u8 width, const char **parents, int num_parents)
 {
-       return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift,
+       return clk_register_mux(NULL, name, parents, num_parents,
+                       CLK_SET_RATE_NO_REPARENT, reg, shift,
                        width, 0, &imx_ccm_lock);
 }
 
@@ -98,7 +99,7 @@ static inline struct clk *imx_clk_mux_flags(const char *name,
                int num_parents, unsigned long flags)
 {
        return clk_register_mux(NULL, name, parents, num_parents,
-                       flags, reg, shift, width, 0,
+                       flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
                        &imx_ccm_lock);
 }
 
index e065c117f5a6452156eab28e41fe5315b35af43a..5211f62c624e3d4977bb57333bbf173556900166 100644 (file)
@@ -61,25 +61,8 @@ void __init mx25_init_irq(void)
        mxc_init_irq(MX25_IO_ADDRESS(MX25_AVIC_BASE_ADDR));
 }
 
-static struct sdma_script_start_addrs imx25_sdma_script __initdata = {
-       .ap_2_ap_addr = 729,
-       .uart_2_mcu_addr = 904,
-       .per_2_app_addr = 1255,
-       .mcu_2_app_addr = 834,
-       .uartsh_2_mcu_addr = 1120,
-       .per_2_shp_addr = 1329,
-       .mcu_2_shp_addr = 1048,
-       .ata_2_mcu_addr = 1560,
-       .mcu_2_ata_addr = 1479,
-       .app_2_per_addr = 1189,
-       .app_2_mcu_addr = 770,
-       .shp_2_per_addr = 1407,
-       .shp_2_mcu_addr = 979,
-};
-
 static struct sdma_platform_data imx25_sdma_pdata __initdata = {
        .fw_name = "sdma-imx25.bin",
-       .script_addrs = &imx25_sdma_script,
 };
 
 static const struct resource imx25_audmux_res[] __initconst = {
index a8229b7f10bf0bf2380e747d8194b1c35f5bed18..eb3cce38c70d3f09eb29d9b7d51343bca5327989 100644 (file)
@@ -103,22 +103,8 @@ void __init mx53_init_irq(void)
        tzic_init_irq(MX53_IO_ADDRESS(MX53_TZIC_BASE_ADDR));
 }
 
-static struct sdma_script_start_addrs imx51_sdma_script __initdata = {
-       .ap_2_ap_addr = 642,
-       .uart_2_mcu_addr = 817,
-       .mcu_2_app_addr = 747,
-       .mcu_2_shp_addr = 961,
-       .ata_2_mcu_addr = 1473,
-       .mcu_2_ata_addr = 1392,
-       .app_2_per_addr = 1033,
-       .app_2_mcu_addr = 683,
-       .shp_2_per_addr = 1251,
-       .shp_2_mcu_addr = 892,
-};
-
 static struct sdma_platform_data imx51_sdma_pdata __initdata = {
        .fw_name = "sdma-imx51.bin",
-       .script_addrs = &imx51_sdma_script,
 };
 
 static const struct resource imx51_audmux_res[] __initconst = {
index 095c155d6fb8532580fbf564bdc5180d8c48afdf..9b702a1dc7b04a48d374ba01e200395ce7d341ff 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for Marvell's PXA168 processors line
 #
 
-obj-y                          += common.o devices.o time.o irq.o
+obj-y                          += common.o devices.o time.o
 
 # SoC support
 obj-$(CONFIG_CPU_PXA168)       += pxa168.o
index 991d7e9877de77b7afbbf37929ef2dd2e20c37f5..cf445bae6d773158c57f1287ea03ee7f8b5ab92e 100644 (file)
@@ -3,7 +3,6 @@
 
 extern void timer_init(int irq);
 
-extern void __init icu_init_irq(void);
 extern void __init mmp_map_io(void);
 extern void mmp_restart(enum reboot_mode, const char *);
 extern void __init pxa168_clk_init(void);
diff --git a/arch/arm/mach-mmp/include/mach/entry-macro.S b/arch/arm/mach-mmp/include/mach/entry-macro.S
deleted file mode 100644 (file)
index bd152e2..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/arch/arm/mach-mmp/include/mach/entry-macro.S
- *
- * 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 <asm/irq.h>
-#include <mach/regs-icu.h>
-
-       .macro  get_irqnr_preamble, base, tmp
-       mrc     p15, 0, \tmp, c0, c0, 0         @ CPUID
-       and     \tmp, \tmp, #0xff00
-       cmp     \tmp, #0x5800
-       ldr     \base, =mmp_icu_base
-       ldr     \base, [\base, #0]
-       addne   \base, \base, #0x10c            @ PJ1 AP INT SEL register
-       addeq   \base, \base, #0x104            @ PJ4 IRQ SEL register
-       .endm
-
-       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-       ldr     \tmp, [\base, #0]
-       and     \irqnr, \tmp, #0x3f
-       tst     \tmp, #(1 << 6)
-       .endm
index 459c2d03eb5c26ab34e06981b55f0b75bf8451ae..a83ba7cb525d82a502ec845a0d76bfafd101d436 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/reboot.h>
 
 extern void pxa168_timer_init(void);
+extern void __init icu_init_irq(void);
 extern void __init pxa168_init_irq(void);
 extern void pxa168_restart(enum reboot_mode, const char *);
 extern void pxa168_clear_keypad_wakeup(void);
index b914afa1fcdc9163337b7e08d36a7f10b41fb865..92253203f5b457c5421b7c4f45d09bc3d97bcc68 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_MACH_PXA910_H
 
 extern void pxa910_timer_init(void);
+extern void __init icu_init_irq(void);
 extern void __init pxa910_init_irq(void);
 
 #include <linux/i2c.h>
diff --git a/arch/arm/mach-mmp/irq.c b/arch/arm/mach-mmp/irq.c
deleted file mode 100644 (file)
index 3c71246..0000000
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- *  linux/arch/arm/mach-mmp/irq.c
- *
- *  Generic IRQ handling, GPIO IRQ demultiplexing, etc.
- *  Copyright (C) 2008 - 2012 Marvell Technology Group Ltd.
- *
- *  Author:    Bin Yang <bin.yang@marvell.com>
- *              Haojian Zhuang <haojian.zhuang@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/module.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-
-#include <mach/irqs.h>
-
-#ifdef CONFIG_CPU_MMP2
-#include <mach/pm-mmp2.h>
-#endif
-#ifdef CONFIG_CPU_PXA910
-#include <mach/pm-pxa910.h>
-#endif
-
-#include "common.h"
-
-#define MAX_ICU_NR             16
-
-struct icu_chip_data {
-       int                     nr_irqs;
-       unsigned int            virq_base;
-       unsigned int            cascade_irq;
-       void __iomem            *reg_status;
-       void __iomem            *reg_mask;
-       unsigned int            conf_enable;
-       unsigned int            conf_disable;
-       unsigned int            conf_mask;
-       unsigned int            clr_mfp_irq_base;
-       unsigned int            clr_mfp_hwirq;
-       struct irq_domain       *domain;
-};
-
-struct mmp_intc_conf {
-       unsigned int    conf_enable;
-       unsigned int    conf_disable;
-       unsigned int    conf_mask;
-};
-
-void __iomem *mmp_icu_base;
-static struct icu_chip_data icu_data[MAX_ICU_NR];
-static int max_icu_nr;
-
-extern void mmp2_clear_pmic_int(void);
-
-static void icu_mask_ack_irq(struct irq_data *d)
-{
-       struct irq_domain *domain = d->domain;
-       struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
-       int hwirq;
-       u32 r;
-
-       hwirq = d->irq - data->virq_base;
-       if (data == &icu_data[0]) {
-               r = readl_relaxed(mmp_icu_base + (hwirq << 2));
-               r &= ~data->conf_mask;
-               r |= data->conf_disable;
-               writel_relaxed(r, mmp_icu_base + (hwirq << 2));
-       } else {
-#ifdef CONFIG_CPU_MMP2
-               if ((data->virq_base == data->clr_mfp_irq_base)
-                       && (hwirq == data->clr_mfp_hwirq))
-                       mmp2_clear_pmic_int();
-#endif
-               r = readl_relaxed(data->reg_mask) | (1 << hwirq);
-               writel_relaxed(r, data->reg_mask);
-       }
-}
-
-static void icu_mask_irq(struct irq_data *d)
-{
-       struct irq_domain *domain = d->domain;
-       struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
-       int hwirq;
-       u32 r;
-
-       hwirq = d->irq - data->virq_base;
-       if (data == &icu_data[0]) {
-               r = readl_relaxed(mmp_icu_base + (hwirq << 2));
-               r &= ~data->conf_mask;
-               r |= data->conf_disable;
-               writel_relaxed(r, mmp_icu_base + (hwirq << 2));
-       } else {
-               r = readl_relaxed(data->reg_mask) | (1 << hwirq);
-               writel_relaxed(r, data->reg_mask);
-       }
-}
-
-static void icu_unmask_irq(struct irq_data *d)
-{
-       struct irq_domain *domain = d->domain;
-       struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
-       int hwirq;
-       u32 r;
-
-       hwirq = d->irq - data->virq_base;
-       if (data == &icu_data[0]) {
-               r = readl_relaxed(mmp_icu_base + (hwirq << 2));
-               r &= ~data->conf_mask;
-               r |= data->conf_enable;
-               writel_relaxed(r, mmp_icu_base + (hwirq << 2));
-       } else {
-               r = readl_relaxed(data->reg_mask) & ~(1 << hwirq);
-               writel_relaxed(r, data->reg_mask);
-       }
-}
-
-static struct irq_chip icu_irq_chip = {
-       .name           = "icu_irq",
-       .irq_mask       = icu_mask_irq,
-       .irq_mask_ack   = icu_mask_ack_irq,
-       .irq_unmask     = icu_unmask_irq,
-};
-
-static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_domain *domain;
-       struct icu_chip_data *data;
-       int i;
-       unsigned long mask, status, n;
-
-       for (i = 1; i < max_icu_nr; i++) {
-               if (irq == icu_data[i].cascade_irq) {
-                       domain = icu_data[i].domain;
-                       data = (struct icu_chip_data *)domain->host_data;
-                       break;
-               }
-       }
-       if (i >= max_icu_nr) {
-               pr_err("Spurious irq %d in MMP INTC\n", irq);
-               return;
-       }
-
-       mask = readl_relaxed(data->reg_mask);
-       while (1) {
-               status = readl_relaxed(data->reg_status) & ~mask;
-               if (status == 0)
-                       break;
-               for_each_set_bit(n, &status, BITS_PER_LONG) {
-                       generic_handle_irq(icu_data[i].virq_base + n);
-               }
-       }
-}
-
-static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
-                             irq_hw_number_t hw)
-{
-       irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
-       set_irq_flags(irq, IRQF_VALID);
-       return 0;
-}
-
-static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
-                               const u32 *intspec, unsigned int intsize,
-                               unsigned long *out_hwirq,
-                               unsigned int *out_type)
-{
-       *out_hwirq = intspec[0];
-       return 0;
-}
-
-const struct irq_domain_ops mmp_irq_domain_ops = {
-       .map            = mmp_irq_domain_map,
-       .xlate          = mmp_irq_domain_xlate,
-};
-
-static struct mmp_intc_conf mmp_conf = {
-       .conf_enable    = 0x51,
-       .conf_disable   = 0x0,
-       .conf_mask      = 0x7f,
-};
-
-static struct mmp_intc_conf mmp2_conf = {
-       .conf_enable    = 0x20,
-       .conf_disable   = 0x0,
-       .conf_mask      = 0x7f,
-};
-
-/* MMP (ARMv5) */
-void __init icu_init_irq(void)
-{
-       int irq;
-
-       max_icu_nr = 1;
-       mmp_icu_base = ioremap(0xd4282000, 0x1000);
-       icu_data[0].conf_enable = mmp_conf.conf_enable;
-       icu_data[0].conf_disable = mmp_conf.conf_disable;
-       icu_data[0].conf_mask = mmp_conf.conf_mask;
-       icu_data[0].nr_irqs = 64;
-       icu_data[0].virq_base = 0;
-       icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[0]);
-       for (irq = 0; irq < 64; irq++) {
-               icu_mask_irq(irq_get_irq_data(irq));
-               irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
-               set_irq_flags(irq, IRQF_VALID);
-       }
-       irq_set_default_host(icu_data[0].domain);
-#ifdef CONFIG_CPU_PXA910
-       icu_irq_chip.irq_set_wake = pxa910_set_wake;
-#endif
-}
-
-/* MMP2 (ARMv7) */
-void __init mmp2_init_icu(void)
-{
-       int irq;
-
-       max_icu_nr = 8;
-       mmp_icu_base = ioremap(0xd4282000, 0x1000);
-       icu_data[0].conf_enable = mmp2_conf.conf_enable;
-       icu_data[0].conf_disable = mmp2_conf.conf_disable;
-       icu_data[0].conf_mask = mmp2_conf.conf_mask;
-       icu_data[0].nr_irqs = 64;
-       icu_data[0].virq_base = 0;
-       icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[0]);
-       icu_data[1].reg_status = mmp_icu_base + 0x150;
-       icu_data[1].reg_mask = mmp_icu_base + 0x168;
-       icu_data[1].clr_mfp_irq_base = IRQ_MMP2_PMIC_BASE;
-       icu_data[1].clr_mfp_hwirq = IRQ_MMP2_PMIC - IRQ_MMP2_PMIC_BASE;
-       icu_data[1].nr_irqs = 2;
-       icu_data[1].cascade_irq = 4;
-       icu_data[1].virq_base = IRQ_MMP2_PMIC_BASE;
-       icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs,
-                                                  icu_data[1].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[1]);
-       icu_data[2].reg_status = mmp_icu_base + 0x154;
-       icu_data[2].reg_mask = mmp_icu_base + 0x16c;
-       icu_data[2].nr_irqs = 2;
-       icu_data[2].cascade_irq = 5;
-       icu_data[2].virq_base = IRQ_MMP2_RTC_BASE;
-       icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs,
-                                                  icu_data[2].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[2]);
-       icu_data[3].reg_status = mmp_icu_base + 0x180;
-       icu_data[3].reg_mask = mmp_icu_base + 0x17c;
-       icu_data[3].nr_irqs = 3;
-       icu_data[3].cascade_irq = 9;
-       icu_data[3].virq_base = IRQ_MMP2_KEYPAD_BASE;
-       icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs,
-                                                  icu_data[3].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[3]);
-       icu_data[4].reg_status = mmp_icu_base + 0x158;
-       icu_data[4].reg_mask = mmp_icu_base + 0x170;
-       icu_data[4].nr_irqs = 5;
-       icu_data[4].cascade_irq = 17;
-       icu_data[4].virq_base = IRQ_MMP2_TWSI_BASE;
-       icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs,
-                                                  icu_data[4].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[4]);
-       icu_data[5].reg_status = mmp_icu_base + 0x15c;
-       icu_data[5].reg_mask = mmp_icu_base + 0x174;
-       icu_data[5].nr_irqs = 15;
-       icu_data[5].cascade_irq = 35;
-       icu_data[5].virq_base = IRQ_MMP2_MISC_BASE;
-       icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs,
-                                                  icu_data[5].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[5]);
-       icu_data[6].reg_status = mmp_icu_base + 0x160;
-       icu_data[6].reg_mask = mmp_icu_base + 0x178;
-       icu_data[6].nr_irqs = 2;
-       icu_data[6].cascade_irq = 51;
-       icu_data[6].virq_base = IRQ_MMP2_MIPI_HSI1_BASE;
-       icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs,
-                                                  icu_data[6].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[6]);
-       icu_data[7].reg_status = mmp_icu_base + 0x188;
-       icu_data[7].reg_mask = mmp_icu_base + 0x184;
-       icu_data[7].nr_irqs = 2;
-       icu_data[7].cascade_irq = 55;
-       icu_data[7].virq_base = IRQ_MMP2_MIPI_HSI0_BASE;
-       icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs,
-                                                  icu_data[7].virq_base, 0,
-                                                  &irq_domain_simple_ops,
-                                                  &icu_data[7]);
-       for (irq = 0; irq < IRQ_MMP2_MUX_END; irq++) {
-               icu_mask_irq(irq_get_irq_data(irq));
-               switch (irq) {
-               case IRQ_MMP2_PMIC_MUX:
-               case IRQ_MMP2_RTC_MUX:
-               case IRQ_MMP2_KEYPAD_MUX:
-               case IRQ_MMP2_TWSI_MUX:
-               case IRQ_MMP2_MISC_MUX:
-               case IRQ_MMP2_MIPI_HSI1_MUX:
-               case IRQ_MMP2_MIPI_HSI0_MUX:
-                       irq_set_chip(irq, &icu_irq_chip);
-                       irq_set_chained_handler(irq, icu_mux_irq_demux);
-                       break;
-               default:
-                       irq_set_chip_and_handler(irq, &icu_irq_chip,
-                                                handle_level_irq);
-                       break;
-               }
-               set_irq_flags(irq, IRQF_VALID);
-       }
-       irq_set_default_host(icu_data[0].domain);
-#ifdef CONFIG_CPU_MMP2
-       icu_irq_chip.irq_set_wake = mmp2_set_wake;
-#endif
-}
-
-#ifdef CONFIG_OF
-static const struct of_device_id intc_ids[] __initconst = {
-       { .compatible = "mrvl,mmp-intc", .data = &mmp_conf },
-       { .compatible = "mrvl,mmp2-intc", .data = &mmp2_conf },
-       {}
-};
-
-static const struct of_device_id mmp_mux_irq_match[] __initconst = {
-       { .compatible = "mrvl,mmp2-mux-intc" },
-       {}
-};
-
-int __init mmp2_mux_init(struct device_node *parent)
-{
-       struct device_node *node;
-       const struct of_device_id *of_id;
-       struct resource res;
-       int i, irq_base, ret, irq;
-       u32 nr_irqs, mfp_irq;
-
-       node = parent;
-       max_icu_nr = 1;
-       for (i = 1; i < MAX_ICU_NR; i++) {
-               node = of_find_matching_node(node, mmp_mux_irq_match);
-               if (!node)
-                       break;
-               of_id = of_match_node(&mmp_mux_irq_match[0], node);
-               ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
-                                          &nr_irqs);
-               if (ret) {
-                       pr_err("Not found mrvl,intc-nr-irqs property\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-               ret = of_address_to_resource(node, 0, &res);
-               if (ret < 0) {
-                       pr_err("Not found reg property\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-               icu_data[i].reg_status = mmp_icu_base + res.start;
-               ret = of_address_to_resource(node, 1, &res);
-               if (ret < 0) {
-                       pr_err("Not found reg property\n");
-                       ret = -EINVAL;
-                       goto err;
-               }
-               icu_data[i].reg_mask = mmp_icu_base + res.start;
-               icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
-               if (!icu_data[i].cascade_irq) {
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-               if (irq_base < 0) {
-                       pr_err("Failed to allocate IRQ numbers for mux intc\n");
-                       ret = irq_base;
-                       goto err;
-               }
-               if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
-                                         &mfp_irq)) {
-                       icu_data[i].clr_mfp_irq_base = irq_base;
-                       icu_data[i].clr_mfp_hwirq = mfp_irq;
-               }
-               irq_set_chained_handler(icu_data[i].cascade_irq,
-                                       icu_mux_irq_demux);
-               icu_data[i].nr_irqs = nr_irqs;
-               icu_data[i].virq_base = irq_base;
-               icu_data[i].domain = irq_domain_add_legacy(node, nr_irqs,
-                                                          irq_base, 0,
-                                                          &mmp_irq_domain_ops,
-                                                          &icu_data[i]);
-               for (irq = irq_base; irq < irq_base + nr_irqs; irq++)
-                       icu_mask_irq(irq_get_irq_data(irq));
-       }
-       max_icu_nr = i;
-       return 0;
-err:
-       of_node_put(node);
-       max_icu_nr = i;
-       return ret;
-}
-
-void __init mmp_dt_irq_init(void)
-{
-       struct device_node *node;
-       const struct of_device_id *of_id;
-       struct mmp_intc_conf *conf;
-       int nr_irqs, irq_base, ret, irq;
-
-       node = of_find_matching_node(NULL, intc_ids);
-       if (!node) {
-               pr_err("Failed to find interrupt controller in arch-mmp\n");
-               return;
-       }
-       of_id = of_match_node(intc_ids, node);
-       conf = of_id->data;
-
-       ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
-       if (ret) {
-               pr_err("Not found mrvl,intc-nr-irqs property\n");
-               return;
-       }
-
-       mmp_icu_base = of_iomap(node, 0);
-       if (!mmp_icu_base) {
-               pr_err("Failed to get interrupt controller register\n");
-               return;
-       }
-
-       irq_base = irq_alloc_descs(-1, 0, nr_irqs - NR_IRQS_LEGACY, 0);
-       if (irq_base < 0) {
-               pr_err("Failed to allocate IRQ numbers\n");
-               goto err;
-       } else if (irq_base != NR_IRQS_LEGACY) {
-               pr_err("ICU's irqbase should be started from 0\n");
-               goto err;
-       }
-       icu_data[0].conf_enable = conf->conf_enable;
-       icu_data[0].conf_disable = conf->conf_disable;
-       icu_data[0].conf_mask = conf->conf_mask;
-       icu_data[0].nr_irqs = nr_irqs;
-       icu_data[0].virq_base = 0;
-       icu_data[0].domain = irq_domain_add_legacy(node, nr_irqs, 0, 0,
-                                                  &mmp_irq_domain_ops,
-                                                  &icu_data[0]);
-       irq_set_default_host(icu_data[0].domain);
-       for (irq = 0; irq < nr_irqs; irq++)
-               icu_mask_irq(irq_get_irq_data(irq));
-       mmp2_mux_init(node);
-       return;
-err:
-       iounmap(mmp_icu_base);
-}
-#endif
index b37915dc44709852f39d716f11df69c66054abe3..cca529ceecb758101f0120faa547c2790b004e80 100644 (file)
@@ -9,17 +9,13 @@
  *  publishhed by the Free Software Foundation.
  */
 
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
-#include <mach/irqs.h>
 
 #include "common.h"
 
-extern void __init mmp_dt_irq_init(void);
 extern void __init mmp_dt_init_timer(void);
 
 static const struct of_dev_auxdata pxa168_auxdata_lookup[] __initconst = {
@@ -64,7 +60,6 @@ static const char *mmp_dt_board_compat[] __initdata = {
 
 DT_MACHINE_START(PXA168_DT, "Marvell PXA168 (Device Tree Support)")
        .map_io         = mmp_map_io,
-       .init_irq       = mmp_dt_irq_init,
        .init_time      = mmp_dt_init_timer,
        .init_machine   = pxa168_dt_init,
        .dt_compat      = mmp_dt_board_compat,
@@ -72,7 +67,6 @@ MACHINE_END
 
 DT_MACHINE_START(PXA910_DT, "Marvell PXA910 (Device Tree Support)")
        .map_io         = mmp_map_io,
-       .init_irq       = mmp_dt_irq_init,
        .init_time      = mmp_dt_init_timer,
        .init_machine   = pxa910_dt_init,
        .dt_compat      = mmp_dt_board_compat,
index 4ac256720f7db089531bdbb0452b11b9f7d47d3d..023cb453f157ff621110d6c17b6f0cc185b8d8ba 100644 (file)
  */
 
 #include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/irqdomain.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
 #include <linux/of_platform.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/time.h>
-#include <mach/irqs.h>
-#include <mach/regs-apbc.h>
 
 #include "common.h"
 
-extern void __init mmp_dt_irq_init(void);
 extern void __init mmp_dt_init_timer(void);
 
 static const struct of_dev_auxdata mmp2_auxdata_lookup[] __initconst = {
@@ -49,7 +44,6 @@ static const char *mmp2_dt_board_compat[] __initdata = {
 
 DT_MACHINE_START(MMP2_DT, "Marvell MMP2 (Device Tree Support)")
        .map_io         = mmp_map_io,
-       .init_irq       = mmp_dt_irq_init,
        .init_time      = mmp_dt_init_timer,
        .init_machine   = mmp2_dt_init,
        .dt_compat      = mmp2_dt_board_compat,
index c7592f168bbdcc1e51b9de81afe7ff791bd49466..a70b5530bd42535be7b98a788e656a1ce956e153 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/mmp.h>
 #include <linux/platform_device.h>
 
 #include <asm/hardware/cache-tauros2.h>
@@ -26,6 +28,7 @@
 #include <mach/mfp.h>
 #include <mach/devices.h>
 #include <mach/mmp2.h>
+#include <mach/pm-mmp2.h>
 
 #include "common.h"
 
@@ -94,6 +97,9 @@ void mmp2_clear_pmic_int(void)
 void __init mmp2_init_irq(void)
 {
        mmp2_init_icu();
+#ifdef CONFIG_PM
+       icu_irq_chip.irq_set_wake = mmp2_set_wake;
+#endif
 }
 
 static int __init mmp2_init(void)
index ce6393acad86a4cf90b67cac71611c3e22f8c3aa..eb57ee19684295c94e7e10acfad245e519bf8e38 100644 (file)
@@ -12,6 +12,8 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip/mmp.h>
 #include <linux/platform_device.h>
 
 #include <asm/hardware/cache-tauros2.h>
@@ -23,6 +25,8 @@
 #include <mach/dma.h>
 #include <mach/mfp.h>
 #include <mach/devices.h>
+#include <mach/pm-pxa910.h>
+#include <mach/pxa910.h>
 
 #include "common.h"
 
@@ -79,6 +83,9 @@ static struct mfp_addr_map pxa910_mfp_addr_map[] __initdata =
 void __init pxa910_init_irq(void)
 {
        icu_init_irq();
+#ifdef CONFIG_PM
+       icu_irq_chip.irq_set_wake = pxa910_set_wake;
+#endif
 }
 
 static int __init pxa910_init(void)
index 829b5730632864b7da0158e8e6c6f833e421e579..e2acff98e750a013dd54356249306259cb055091 100644 (file)
@@ -18,7 +18,7 @@
 #include <linux/of_address.h>
 #include <linux/of_platform.h>
 #include <linux/io.h>
-#include <linux/time-armada-370-xp.h>
+#include <linux/clocksource.h>
 #include <linux/dma-mapping.h>
 #include <linux/mbus.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -37,7 +37,7 @@ static void __init armada_370_xp_map_io(void)
 static void __init armada_370_xp_timer_and_clk_init(void)
 {
        of_clk_init(NULL);
-       armada_370_xp_timer_init();
+       clocksource_of_init();
        coherency_init();
        BUG_ON(mvebu_mbus_dt_init());
 #ifdef CONFIG_CACHE_L2X0
index cc36bfe104fec312db82afb52c33e0e41fb40c8d..afb457c3135b18707ea23cc7019c68da0ec4c099 100644 (file)
@@ -63,6 +63,7 @@ obj-$(CONFIG_SOC_AM33XX)              += am33xx-restart.o
 obj-$(CONFIG_ARCH_OMAP3)               += omap3-restart.o
 obj-$(CONFIG_ARCH_OMAP4)               += omap4-restart.o
 obj-$(CONFIG_SOC_OMAP5)                        += omap4-restart.o
+obj-$(CONFIG_SOC_DRA7XX)               += omap4-restart.o
 
 # Pin multiplexing
 obj-$(CONFIG_SOC_OMAP2420)             += mux2420.o
@@ -148,6 +149,7 @@ obj-$(CONFIG_SOC_AM43XX)            += $(powerdomain-common)
 obj-$(CONFIG_SOC_OMAP5)                        += $(powerdomain-common)
 obj-$(CONFIG_SOC_OMAP5)                        += powerdomains54xx_data.o
 obj-$(CONFIG_SOC_DRA7XX)               += $(powerdomain-common)
+obj-$(CONFIG_SOC_DRA7XX)               += powerdomains7xx_data.o
 
 # PRCM clockdomain control
 clockdomain-common                     += clockdomain.o
@@ -166,6 +168,7 @@ obj-$(CONFIG_SOC_AM43XX)            += $(clockdomain-common)
 obj-$(CONFIG_SOC_OMAP5)                        += $(clockdomain-common)
 obj-$(CONFIG_SOC_OMAP5)                        += clockdomains54xx_data.o
 obj-$(CONFIG_SOC_DRA7XX)               += $(clockdomain-common)
+obj-$(CONFIG_SOC_DRA7XX)               += clockdomains7xx_data.o
 
 # Clock framework
 obj-$(CONFIG_ARCH_OMAP2)               += $(clock-common) clock2xxx.o
@@ -209,6 +212,7 @@ obj-$(CONFIG_ARCH_OMAP3)            += omap_hwmod_3xxx_data.o
 obj-$(CONFIG_SOC_AM33XX)               += omap_hwmod_33xx_data.o
 obj-$(CONFIG_ARCH_OMAP4)               += omap_hwmod_44xx_data.o
 obj-$(CONFIG_SOC_OMAP5)                        += omap_hwmod_54xx_data.o
+obj-$(CONFIG_SOC_DRA7XX)               += omap_hwmod_7xx_data.o
 
 # EMU peripherals
 obj-$(CONFIG_OMAP3_EMU)                        += emu.o
index b89e55ba2c13a517a1118992229966d250a07d16..39c78387ddecb1b287ebfe732d7de0f3c62ca4db 100644 (file)
@@ -238,5 +238,6 @@ DT_MACHINE_START(DRA7XX_DT, "Generic DRA7XX (Flattened Device Tree)")
        .init_machine   = omap_generic_init,
        .init_time      = omap5_realtime_timer_init,
        .dt_compat      = dra7xx_boards_compat,
+       .restart        = omap44xx_restart,
 MACHINE_END
 #endif
index ba6534d7f155a6adc94a5ecb201d5cd7815c939f..865d30ee812f1902b04dbdd70d2b57ed4e391290 100644 (file)
@@ -421,6 +421,10 @@ static struct clk aes0_fck;
 DEFINE_STRUCT_CLK_HW_OMAP(aes0_fck, NULL);
 DEFINE_STRUCT_CLK(aes0_fck, dpll_core_ck_parents, clk_ops_null);
 
+static struct clk rng_fck;
+DEFINE_STRUCT_CLK_HW_OMAP(rng_fck, NULL);
+DEFINE_STRUCT_CLK(rng_fck, dpll_core_ck_parents, clk_ops_null);
+
 /*
  * Modules clock nodes
  *
@@ -966,6 +970,7 @@ static struct omap_clk am33xx_clks[] = {
        CLK(NULL,       "smartreflex1_fck",     &smartreflex1_fck),
        CLK(NULL,       "sha0_fck",             &sha0_fck),
        CLK(NULL,       "aes0_fck",             &aes0_fck),
+       CLK(NULL,       "rng_fck",              &rng_fck),
        CLK(NULL,       "timer1_fck",           &timer1_fck),
        CLK(NULL,       "timer2_fck",           &timer2_fck),
        CLK(NULL,       "timer3_fck",           &timer3_fck),
index 88e37a474334df7589fc866bbf37fbd645258b00..1d5b5290d2af3db91f5d57b0a9c945a2ccaa2e28 100644 (file)
@@ -1706,6 +1706,18 @@ int __init omap4xxx_clk_init(void)
 
        omap2_clk_disable_autoidle_all();
 
+       /*
+        * A set rate of ABE DPLL inturn triggers a set rate of USB DPLL
+        * when its in bypass. So always lock USB before ABE DPLL.
+        */
+       /*
+        * Lock USB DPLL on OMAP4 devices so that the L3INIT power
+        * domain can transition to retention state when not in use.
+        */
+       rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure USB DPLL!\n", __func__);
+
        /*
         * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
         * state when turning the ABE clock domain. Workaround this by
@@ -1718,13 +1730,5 @@ int __init omap4xxx_clk_init(void)
        if (rc)
                pr_err("%s: failed to configure ABE DPLL!\n", __func__);
 
-       /*
-        * Lock USB DPLL on OMAP4 devices so that the L3INIT power
-        * domain can transition to retention state when not in use.
-        */
-       rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ);
-       if (rc)
-               pr_err("%s: failed to configure USB DPLL!\n", __func__);
-
        return 0;
 }
index daeecf1b89fa837c7672c3d0de192c9f4fb8d552..4b03394fa0c5307bdd31182c6bfd025d3c0aa2df 100644 (file)
@@ -217,6 +217,7 @@ extern void __init omap3xxx_clockdomains_init(void);
 extern void __init am33xx_clockdomains_init(void);
 extern void __init omap44xx_clockdomains_init(void);
 extern void __init omap54xx_clockdomains_init(void);
+extern void __init dra7xx_clockdomains_init(void);
 
 extern void clkdm_add_autodeps(struct clockdomain *clkdm);
 extern void clkdm_del_autodeps(struct clockdomain *clkdm);
diff --git a/arch/arm/mach-omap2/clockdomains7xx_data.c b/arch/arm/mach-omap2/clockdomains7xx_data.c
new file mode 100644 (file)
index 0000000..57d5df0
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+ * DRA7xx Clock domains framework
+ *
+ * Copyright (C) 2009-2013 Texas Instruments, Inc.
+ * Copyright (C) 2009-2011 Nokia Corporation
+ *
+ * Generated by code originally written by:
+ * Abhijit Pagare (abhijitpagare@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ * Paul Walmsley (paul@pwsan.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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/io.h>
+
+#include "clockdomain.h"
+#include "cm1_7xx.h"
+#include "cm2_7xx.h"
+
+#include "cm-regbits-7xx.h"
+#include "prm7xx.h"
+#include "prcm44xx.h"
+#include "prcm_mpu7xx.h"
+
+/* Static Dependencies for DRA7xx Clock Domains */
+
+static struct clkdm_dep cam_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep dma_wkup_sleep_deps[] = {
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "ipu2_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l4cfg_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "pcie_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep dsp1_wkup_sleep_deps[] = {
+       { .clkdm_name = "atl_clkdm" },
+       { .clkdm_name = "cam_clkdm" },
+       { .clkdm_name = "dsp2_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "gmac_clkdm" },
+       { .clkdm_name = "gpu_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "ipu2_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "pcie_clkdm" },
+       { .clkdm_name = "vpe_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep dsp2_wkup_sleep_deps[] = {
+       { .clkdm_name = "atl_clkdm" },
+       { .clkdm_name = "cam_clkdm" },
+       { .clkdm_name = "dsp1_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "gmac_clkdm" },
+       { .clkdm_name = "gpu_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "ipu2_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "pcie_clkdm" },
+       { .clkdm_name = "vpe_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep dss_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep eve1_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep eve2_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep eve3_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep eve4_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep gmac_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep gpu_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep ipu1_wkup_sleep_deps[] = {
+       { .clkdm_name = "atl_clkdm" },
+       { .clkdm_name = "dsp1_clkdm" },
+       { .clkdm_name = "dsp2_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "gmac_clkdm" },
+       { .clkdm_name = "gpu_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu2_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l3main1_clkdm" },
+       { .clkdm_name = "l4cfg_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "pcie_clkdm" },
+       { .clkdm_name = "vpe_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep ipu2_wkup_sleep_deps[] = {
+       { .clkdm_name = "atl_clkdm" },
+       { .clkdm_name = "dsp1_clkdm" },
+       { .clkdm_name = "dsp2_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "gmac_clkdm" },
+       { .clkdm_name = "gpu_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l3main1_clkdm" },
+       { .clkdm_name = "l4cfg_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "pcie_clkdm" },
+       { .clkdm_name = "vpe_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep iva_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep l3init_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l4cfg_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep l4per2_wkup_sleep_deps[] = {
+       { .clkdm_name = "dsp1_clkdm" },
+       { .clkdm_name = "dsp2_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "ipu2_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep l4sec_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep mpu_wkup_sleep_deps[] = {
+       { .clkdm_name = "cam_clkdm" },
+       { .clkdm_name = "dsp1_clkdm" },
+       { .clkdm_name = "dsp2_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "gmac_clkdm" },
+       { .clkdm_name = "gpu_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "ipu2_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l3main1_clkdm" },
+       { .clkdm_name = "l4cfg_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "pcie_clkdm" },
+       { .clkdm_name = "vpe_clkdm" },
+       { .clkdm_name = "wkupaon_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep pcie_wkup_sleep_deps[] = {
+       { .clkdm_name = "atl_clkdm" },
+       { .clkdm_name = "cam_clkdm" },
+       { .clkdm_name = "dsp1_clkdm" },
+       { .clkdm_name = "dsp2_clkdm" },
+       { .clkdm_name = "dss_clkdm" },
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "eve1_clkdm" },
+       { .clkdm_name = "eve2_clkdm" },
+       { .clkdm_name = "eve3_clkdm" },
+       { .clkdm_name = "eve4_clkdm" },
+       { .clkdm_name = "gmac_clkdm" },
+       { .clkdm_name = "gpu_clkdm" },
+       { .clkdm_name = "ipu_clkdm" },
+       { .clkdm_name = "ipu1_clkdm" },
+       { .clkdm_name = "iva_clkdm" },
+       { .clkdm_name = "l3init_clkdm" },
+       { .clkdm_name = "l4cfg_clkdm" },
+       { .clkdm_name = "l4per_clkdm" },
+       { .clkdm_name = "l4per2_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { .clkdm_name = "l4sec_clkdm" },
+       { .clkdm_name = "vpe_clkdm" },
+       { NULL },
+};
+
+static struct clkdm_dep vpe_wkup_sleep_deps[] = {
+       { .clkdm_name = "emif_clkdm" },
+       { .clkdm_name = "l4per3_clkdm" },
+       { NULL },
+};
+
+static struct clockdomain l4per3_7xx_clkdm = {
+       .name             = "l4per3_clkdm",
+       .pwrdm            = { .name = "l4per_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L4PER_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L4PER_L4PER3_CDOFFS,
+       .dep_bit          = DRA7XX_L4PER3_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain l4per2_7xx_clkdm = {
+       .name             = "l4per2_clkdm",
+       .pwrdm            = { .name = "l4per_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L4PER_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L4PER_L4PER2_CDOFFS,
+       .dep_bit          = DRA7XX_L4PER2_STATDEP_SHIFT,
+       .wkdep_srcs       = l4per2_wkup_sleep_deps,
+       .sleepdep_srcs    = l4per2_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain mpu0_7xx_clkdm = {
+       .name             = "mpu0_clkdm",
+       .pwrdm            = { .name = "cpu0_pwrdm" },
+       .prcm_partition   = DRA7XX_MPU_PRCM_PARTITION,
+       .cm_inst          = DRA7XX_MPU_PRCM_CM_C0_INST,
+       .clkdm_offs       = DRA7XX_MPU_PRCM_CM_C0_CPU0_CDOFFS,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain iva_7xx_clkdm = {
+       .name             = "iva_clkdm",
+       .pwrdm            = { .name = "iva_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_IVA_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_IVA_IVA_CDOFFS,
+       .dep_bit          = DRA7XX_IVA_STATDEP_SHIFT,
+       .wkdep_srcs       = iva_wkup_sleep_deps,
+       .sleepdep_srcs    = iva_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain coreaon_7xx_clkdm = {
+       .name             = "coreaon_clkdm",
+       .pwrdm            = { .name = "coreaon_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_COREAON_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_COREAON_COREAON_CDOFFS,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain ipu1_7xx_clkdm = {
+       .name             = "ipu1_clkdm",
+       .pwrdm            = { .name = "ipu_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_IPU_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_IPU_IPU1_CDOFFS,
+       .dep_bit          = DRA7XX_IPU1_STATDEP_SHIFT,
+       .wkdep_srcs       = ipu1_wkup_sleep_deps,
+       .sleepdep_srcs    = ipu1_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain ipu2_7xx_clkdm = {
+       .name             = "ipu2_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_IPU2_CDOFFS,
+       .dep_bit          = DRA7XX_IPU2_STATDEP_SHIFT,
+       .wkdep_srcs       = ipu2_wkup_sleep_deps,
+       .sleepdep_srcs    = ipu2_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain l3init_7xx_clkdm = {
+       .name             = "l3init_clkdm",
+       .pwrdm            = { .name = "l3init_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L3INIT_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L3INIT_L3INIT_CDOFFS,
+       .dep_bit          = DRA7XX_L3INIT_STATDEP_SHIFT,
+       .wkdep_srcs       = l3init_wkup_sleep_deps,
+       .sleepdep_srcs    = l3init_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain l4sec_7xx_clkdm = {
+       .name             = "l4sec_clkdm",
+       .pwrdm            = { .name = "l4per_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L4PER_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L4PER_L4SEC_CDOFFS,
+       .dep_bit          = DRA7XX_L4SEC_STATDEP_SHIFT,
+       .wkdep_srcs       = l4sec_wkup_sleep_deps,
+       .sleepdep_srcs    = l4sec_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain l3main1_7xx_clkdm = {
+       .name             = "l3main1_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_L3MAIN1_CDOFFS,
+       .dep_bit          = DRA7XX_L3MAIN1_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain vpe_7xx_clkdm = {
+       .name             = "vpe_clkdm",
+       .pwrdm            = { .name = "vpe_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_VPE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_VPE_VPE_CDOFFS,
+       .dep_bit          = DRA7XX_VPE_STATDEP_SHIFT,
+       .wkdep_srcs       = vpe_wkup_sleep_deps,
+       .sleepdep_srcs    = vpe_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain mpu_7xx_clkdm = {
+       .name             = "mpu_clkdm",
+       .pwrdm            = { .name = "mpu_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_MPU_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_MPU_MPU_CDOFFS,
+       .wkdep_srcs       = mpu_wkup_sleep_deps,
+       .sleepdep_srcs    = mpu_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain custefuse_7xx_clkdm = {
+       .name             = "custefuse_clkdm",
+       .pwrdm            = { .name = "custefuse_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CUSTEFUSE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CUSTEFUSE_CUSTEFUSE_CDOFFS,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain ipu_7xx_clkdm = {
+       .name             = "ipu_clkdm",
+       .pwrdm            = { .name = "ipu_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_IPU_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_IPU_IPU_CDOFFS,
+       .dep_bit          = DRA7XX_IPU_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain mpu1_7xx_clkdm = {
+       .name             = "mpu1_clkdm",
+       .pwrdm            = { .name = "cpu1_pwrdm" },
+       .prcm_partition   = DRA7XX_MPU_PRCM_PARTITION,
+       .cm_inst          = DRA7XX_MPU_PRCM_CM_C1_INST,
+       .clkdm_offs       = DRA7XX_MPU_PRCM_CM_C1_CPU1_CDOFFS,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain gmac_7xx_clkdm = {
+       .name             = "gmac_clkdm",
+       .pwrdm            = { .name = "l3init_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L3INIT_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L3INIT_GMAC_CDOFFS,
+       .dep_bit          = DRA7XX_GMAC_STATDEP_SHIFT,
+       .wkdep_srcs       = gmac_wkup_sleep_deps,
+       .sleepdep_srcs    = gmac_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain l4cfg_7xx_clkdm = {
+       .name             = "l4cfg_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_L4CFG_CDOFFS,
+       .dep_bit          = DRA7XX_L4CFG_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain dma_7xx_clkdm = {
+       .name             = "dma_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_DMA_CDOFFS,
+       .wkdep_srcs       = dma_wkup_sleep_deps,
+       .sleepdep_srcs    = dma_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain rtc_7xx_clkdm = {
+       .name             = "rtc_clkdm",
+       .pwrdm            = { .name = "rtc_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_RTC_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_RTC_RTC_CDOFFS,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain pcie_7xx_clkdm = {
+       .name             = "pcie_clkdm",
+       .pwrdm            = { .name = "l3init_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L3INIT_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L3INIT_PCIE_CDOFFS,
+       .dep_bit          = DRA7XX_PCIE_STATDEP_SHIFT,
+       .wkdep_srcs       = pcie_wkup_sleep_deps,
+       .sleepdep_srcs    = pcie_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain atl_7xx_clkdm = {
+       .name             = "atl_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_ATL_CDOFFS,
+       .dep_bit          = DRA7XX_ATL_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain l3instr_7xx_clkdm = {
+       .name             = "l3instr_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_L3INSTR_CDOFFS,
+};
+
+static struct clockdomain dss_7xx_clkdm = {
+       .name             = "dss_clkdm",
+       .pwrdm            = { .name = "dss_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_DSS_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_DSS_DSS_CDOFFS,
+       .dep_bit          = DRA7XX_DSS_STATDEP_SHIFT,
+       .wkdep_srcs       = dss_wkup_sleep_deps,
+       .sleepdep_srcs    = dss_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain emif_7xx_clkdm = {
+       .name             = "emif_clkdm",
+       .pwrdm            = { .name = "core_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CORE_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CORE_EMIF_CDOFFS,
+       .dep_bit          = DRA7XX_EMIF_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain emu_7xx_clkdm = {
+       .name             = "emu_clkdm",
+       .pwrdm            = { .name = "emu_pwrdm" },
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .cm_inst          = DRA7XX_PRM_EMU_CM_INST,
+       .clkdm_offs       = DRA7XX_PRM_EMU_CM_EMU_CDOFFS,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain dsp2_7xx_clkdm = {
+       .name             = "dsp2_clkdm",
+       .pwrdm            = { .name = "dsp2_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_DSP2_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_DSP2_DSP2_CDOFFS,
+       .dep_bit          = DRA7XX_DSP2_STATDEP_SHIFT,
+       .wkdep_srcs       = dsp2_wkup_sleep_deps,
+       .sleepdep_srcs    = dsp2_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain dsp1_7xx_clkdm = {
+       .name             = "dsp1_clkdm",
+       .pwrdm            = { .name = "dsp1_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_DSP1_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_DSP1_DSP1_CDOFFS,
+       .dep_bit          = DRA7XX_DSP1_STATDEP_SHIFT,
+       .wkdep_srcs       = dsp1_wkup_sleep_deps,
+       .sleepdep_srcs    = dsp1_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain cam_7xx_clkdm = {
+       .name             = "cam_clkdm",
+       .pwrdm            = { .name = "cam_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_CAM_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_CAM_CAM_CDOFFS,
+       .dep_bit          = DRA7XX_CAM_STATDEP_SHIFT,
+       .wkdep_srcs       = cam_wkup_sleep_deps,
+       .sleepdep_srcs    = cam_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain l4per_7xx_clkdm = {
+       .name             = "l4per_clkdm",
+       .pwrdm            = { .name = "l4per_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_L4PER_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_L4PER_L4PER_CDOFFS,
+       .dep_bit          = DRA7XX_L4PER_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain gpu_7xx_clkdm = {
+       .name             = "gpu_clkdm",
+       .pwrdm            = { .name = "gpu_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_GPU_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_GPU_GPU_CDOFFS,
+       .dep_bit          = DRA7XX_GPU_STATDEP_SHIFT,
+       .wkdep_srcs       = gpu_wkup_sleep_deps,
+       .sleepdep_srcs    = gpu_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain eve4_7xx_clkdm = {
+       .name             = "eve4_clkdm",
+       .pwrdm            = { .name = "eve4_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_EVE4_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_EVE4_EVE4_CDOFFS,
+       .dep_bit          = DRA7XX_EVE4_STATDEP_SHIFT,
+       .wkdep_srcs       = eve4_wkup_sleep_deps,
+       .sleepdep_srcs    = eve4_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain eve2_7xx_clkdm = {
+       .name             = "eve2_clkdm",
+       .pwrdm            = { .name = "eve2_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_EVE2_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_EVE2_EVE2_CDOFFS,
+       .dep_bit          = DRA7XX_EVE2_STATDEP_SHIFT,
+       .wkdep_srcs       = eve2_wkup_sleep_deps,
+       .sleepdep_srcs    = eve2_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain eve3_7xx_clkdm = {
+       .name             = "eve3_clkdm",
+       .pwrdm            = { .name = "eve3_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_EVE3_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_EVE3_EVE3_CDOFFS,
+       .dep_bit          = DRA7XX_EVE3_STATDEP_SHIFT,
+       .wkdep_srcs       = eve3_wkup_sleep_deps,
+       .sleepdep_srcs    = eve3_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+static struct clockdomain wkupaon_7xx_clkdm = {
+       .name             = "wkupaon_clkdm",
+       .pwrdm            = { .name = "wkupaon_pwrdm" },
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .cm_inst          = DRA7XX_PRM_WKUPAON_CM_INST,
+       .clkdm_offs       = DRA7XX_PRM_WKUPAON_CM_WKUPAON_CDOFFS,
+       .dep_bit          = DRA7XX_WKUPAON_STATDEP_SHIFT,
+       .flags            = CLKDM_CAN_FORCE_WAKEUP | CLKDM_CAN_HWSUP,
+};
+
+static struct clockdomain eve1_7xx_clkdm = {
+       .name             = "eve1_clkdm",
+       .pwrdm            = { .name = "eve1_pwrdm" },
+       .prcm_partition   = DRA7XX_CM_CORE_AON_PARTITION,
+       .cm_inst          = DRA7XX_CM_CORE_AON_EVE1_INST,
+       .clkdm_offs       = DRA7XX_CM_CORE_AON_EVE1_EVE1_CDOFFS,
+       .dep_bit          = DRA7XX_EVE1_STATDEP_SHIFT,
+       .wkdep_srcs       = eve1_wkup_sleep_deps,
+       .sleepdep_srcs    = eve1_wkup_sleep_deps,
+       .flags            = CLKDM_CAN_HWSUP_SWSUP,
+};
+
+/* As clockdomains are added or removed above, this list must also be changed */
+static struct clockdomain *clockdomains_dra7xx[] __initdata = {
+       &l4per3_7xx_clkdm,
+       &l4per2_7xx_clkdm,
+       &mpu0_7xx_clkdm,
+       &iva_7xx_clkdm,
+       &coreaon_7xx_clkdm,
+       &ipu1_7xx_clkdm,
+       &ipu2_7xx_clkdm,
+       &l3init_7xx_clkdm,
+       &l4sec_7xx_clkdm,
+       &l3main1_7xx_clkdm,
+       &vpe_7xx_clkdm,
+       &mpu_7xx_clkdm,
+       &custefuse_7xx_clkdm,
+       &ipu_7xx_clkdm,
+       &mpu1_7xx_clkdm,
+       &gmac_7xx_clkdm,
+       &l4cfg_7xx_clkdm,
+       &dma_7xx_clkdm,
+       &rtc_7xx_clkdm,
+       &pcie_7xx_clkdm,
+       &atl_7xx_clkdm,
+       &l3instr_7xx_clkdm,
+       &dss_7xx_clkdm,
+       &emif_7xx_clkdm,
+       &emu_7xx_clkdm,
+       &dsp2_7xx_clkdm,
+       &dsp1_7xx_clkdm,
+       &cam_7xx_clkdm,
+       &l4per_7xx_clkdm,
+       &gpu_7xx_clkdm,
+       &eve4_7xx_clkdm,
+       &eve2_7xx_clkdm,
+       &eve3_7xx_clkdm,
+       &wkupaon_7xx_clkdm,
+       &eve1_7xx_clkdm,
+       NULL
+};
+
+void __init dra7xx_clockdomains_init(void)
+{
+       clkdm_register_platform_funcs(&omap4_clkdm_operations);
+       clkdm_register_clkdms(clockdomains_dra7xx);
+       clkdm_complete_init();
+}
diff --git a/arch/arm/mach-omap2/cm-regbits-7xx.h b/arch/arm/mach-omap2/cm-regbits-7xx.h
new file mode 100644 (file)
index 0000000..ad8f81c
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * DRA7xx Clock Management register bits
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Generated by code originally written by:
+ * Paul Walmsley (paul@pwsan.com)
+ * Rajendra Nayak (rnayak@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CM_REGBITS_7XX_H
+#define __ARCH_ARM_MACH_OMAP2_CM_REGBITS_7XX_H
+
+#define DRA7XX_ATL_STATDEP_SHIFT                               30
+#define DRA7XX_CAM_STATDEP_SHIFT                               9
+#define DRA7XX_DSP1_STATDEP_SHIFT                              1
+#define DRA7XX_DSP2_STATDEP_SHIFT                              18
+#define DRA7XX_DSS_STATDEP_SHIFT                               8
+#define DRA7XX_EMIF_STATDEP_SHIFT                              4
+#define DRA7XX_EVE1_STATDEP_SHIFT                              19
+#define DRA7XX_EVE2_STATDEP_SHIFT                              20
+#define DRA7XX_EVE3_STATDEP_SHIFT                              21
+#define DRA7XX_EVE4_STATDEP_SHIFT                              22
+#define DRA7XX_GMAC_STATDEP_SHIFT                              25
+#define DRA7XX_GPU_STATDEP_SHIFT                               10
+#define DRA7XX_IPU1_STATDEP_SHIFT                              23
+#define DRA7XX_IPU2_STATDEP_SHIFT                              0
+#define DRA7XX_IPU_STATDEP_SHIFT                               24
+#define DRA7XX_IVA_STATDEP_SHIFT                               2
+#define DRA7XX_L3INIT_STATDEP_SHIFT                            7
+#define DRA7XX_L3MAIN1_STATDEP_SHIFT                           5
+#define DRA7XX_L4CFG_STATDEP_SHIFT                             12
+#define DRA7XX_L4PER2_STATDEP_SHIFT                            26
+#define DRA7XX_L4PER3_STATDEP_SHIFT                            27
+#define DRA7XX_L4PER_STATDEP_SHIFT                             13
+#define DRA7XX_L4SEC_STATDEP_SHIFT                             14
+#define DRA7XX_PCIE_STATDEP_SHIFT                              29
+#define DRA7XX_VPE_STATDEP_SHIFT                               28
+#define DRA7XX_WKUPAON_STATDEP_SHIFT                           15
+#endif
diff --git a/arch/arm/mach-omap2/cm1_7xx.h b/arch/arm/mach-omap2/cm1_7xx.h
new file mode 100644 (file)
index 0000000..ca6fa1f
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * DRA7xx CM1 instance offset macros
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Generated by code originally written by:
+ * Paul Walmsley (paul@pwsan.com)
+ * Rajendra Nayak (rnayak@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CM1_7XX_H
+#define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H
+
+#include "cm_44xx_54xx.h"
+
+/* CM1 base address */
+#define DRA7XX_CM_CORE_AON_BASE                0x4a005000
+
+#define DRA7XX_CM_CORE_AON_REGADDR(inst, reg)                          \
+       OMAP2_L4_IO_ADDRESS(DRA7XX_CM_CORE_AON_BASE + (inst) + (reg))
+
+/* CM_CORE_AON instances */
+#define DRA7XX_CM_CORE_AON_OCP_SOCKET_INST     0x0000
+#define DRA7XX_CM_CORE_AON_CKGEN_INST          0x0100
+#define DRA7XX_CM_CORE_AON_MPU_INST            0x0300
+#define DRA7XX_CM_CORE_AON_DSP1_INST           0x0400
+#define DRA7XX_CM_CORE_AON_IPU_INST            0x0500
+#define DRA7XX_CM_CORE_AON_DSP2_INST           0x0600
+#define DRA7XX_CM_CORE_AON_EVE1_INST           0x0640
+#define DRA7XX_CM_CORE_AON_EVE2_INST           0x0680
+#define DRA7XX_CM_CORE_AON_EVE3_INST           0x06c0
+#define DRA7XX_CM_CORE_AON_EVE4_INST           0x0700
+#define DRA7XX_CM_CORE_AON_RTC_INST            0x0740
+#define DRA7XX_CM_CORE_AON_VPE_INST            0x0760
+#define DRA7XX_CM_CORE_AON_RESTORE_INST                0x0e00
+#define DRA7XX_CM_CORE_AON_INSTR_INST          0x0f00
+
+/* CM_CORE_AON clockdomain register offsets (from instance start) */
+#define DRA7XX_CM_CORE_AON_MPU_MPU_CDOFFS      0x0000
+#define DRA7XX_CM_CORE_AON_DSP1_DSP1_CDOFFS    0x0000
+#define DRA7XX_CM_CORE_AON_IPU_IPU1_CDOFFS     0x0000
+#define DRA7XX_CM_CORE_AON_IPU_IPU_CDOFFS      0x0040
+#define DRA7XX_CM_CORE_AON_DSP2_DSP2_CDOFFS    0x0000
+#define DRA7XX_CM_CORE_AON_EVE1_EVE1_CDOFFS    0x0000
+#define DRA7XX_CM_CORE_AON_EVE2_EVE2_CDOFFS    0x0000
+#define DRA7XX_CM_CORE_AON_EVE3_EVE3_CDOFFS    0x0000
+#define DRA7XX_CM_CORE_AON_EVE4_EVE4_CDOFFS    0x0000
+#define DRA7XX_CM_CORE_AON_RTC_RTC_CDOFFS      0x0000
+#define DRA7XX_CM_CORE_AON_VPE_VPE_CDOFFS      0x0000
+
+/* CM_CORE_AON */
+
+/* CM_CORE_AON.OCP_SOCKET_CM_CORE_AON register offsets */
+#define DRA7XX_REVISION_CM_CORE_AON_OFFSET             0x0000
+#define DRA7XX_CM_CM_CORE_AON_PROFILING_CLKCTRL_OFFSET 0x0040
+#define DRA7XX_CM_CM_CORE_AON_PROFILING_CLKCTRL                DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_OCP_SOCKET_INST, 0x0040)
+#define DRA7XX_CM_CORE_AON_DEBUG_OUT_OFFSET            0x00ec
+#define DRA7XX_CM_CORE_AON_DEBUG_CFG0_OFFSET           0x00f0
+#define DRA7XX_CM_CORE_AON_DEBUG_CFG1_OFFSET           0x00f4
+#define DRA7XX_CM_CORE_AON_DEBUG_CFG2_OFFSET           0x00f8
+#define DRA7XX_CM_CORE_AON_DEBUG_CFG3_OFFSET           0x00fc
+
+/* CM_CORE_AON.CKGEN_CM_CORE_AON register offsets */
+#define DRA7XX_CM_CLKSEL_CORE_OFFSET                   0x0000
+#define DRA7XX_CM_CLKSEL_CORE                          DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0000)
+#define DRA7XX_CM_CLKSEL_ABE_OFFSET                    0x0008
+#define DRA7XX_CM_CLKSEL_ABE                           DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0008)
+#define DRA7XX_CM_DLL_CTRL_OFFSET                      0x0010
+#define DRA7XX_CM_CLKMODE_DPLL_CORE_OFFSET             0x0020
+#define DRA7XX_CM_CLKMODE_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0020)
+#define DRA7XX_CM_IDLEST_DPLL_CORE_OFFSET              0x0024
+#define DRA7XX_CM_IDLEST_DPLL_CORE                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0024)
+#define DRA7XX_CM_AUTOIDLE_DPLL_CORE_OFFSET            0x0028
+#define DRA7XX_CM_AUTOIDLE_DPLL_CORE                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0028)
+#define DRA7XX_CM_CLKSEL_DPLL_CORE_OFFSET              0x002c
+#define DRA7XX_CM_CLKSEL_DPLL_CORE                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x002c)
+#define DRA7XX_CM_DIV_M2_DPLL_CORE_OFFSET              0x0030
+#define DRA7XX_CM_DIV_M2_DPLL_CORE                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0030)
+#define DRA7XX_CM_DIV_M3_DPLL_CORE_OFFSET              0x0034
+#define DRA7XX_CM_DIV_M3_DPLL_CORE                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0034)
+#define DRA7XX_CM_DIV_H11_DPLL_CORE_OFFSET             0x0038
+#define DRA7XX_CM_DIV_H11_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0038)
+#define DRA7XX_CM_DIV_H12_DPLL_CORE_OFFSET             0x003c
+#define DRA7XX_CM_DIV_H12_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x003c)
+#define DRA7XX_CM_DIV_H13_DPLL_CORE_OFFSET             0x0040
+#define DRA7XX_CM_DIV_H13_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0040)
+#define DRA7XX_CM_DIV_H14_DPLL_CORE_OFFSET             0x0044
+#define DRA7XX_CM_DIV_H14_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0044)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_CORE_OFFSET      0x0048
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_CORE_OFFSET      0x004c
+#define DRA7XX_CM_DIV_H21_DPLL_CORE_OFFSET             0x0050
+#define DRA7XX_CM_DIV_H21_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0050)
+#define DRA7XX_CM_DIV_H22_DPLL_CORE_OFFSET             0x0054
+#define DRA7XX_CM_DIV_H22_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0054)
+#define DRA7XX_CM_DIV_H23_DPLL_CORE_OFFSET             0x0058
+#define DRA7XX_CM_DIV_H23_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0058)
+#define DRA7XX_CM_DIV_H24_DPLL_CORE_OFFSET             0x005c
+#define DRA7XX_CM_DIV_H24_DPLL_CORE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x005c)
+#define DRA7XX_CM_CLKMODE_DPLL_MPU_OFFSET              0x0060
+#define DRA7XX_CM_CLKMODE_DPLL_MPU                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0060)
+#define DRA7XX_CM_IDLEST_DPLL_MPU_OFFSET               0x0064
+#define DRA7XX_CM_IDLEST_DPLL_MPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0064)
+#define DRA7XX_CM_AUTOIDLE_DPLL_MPU_OFFSET             0x0068
+#define DRA7XX_CM_AUTOIDLE_DPLL_MPU                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0068)
+#define DRA7XX_CM_CLKSEL_DPLL_MPU_OFFSET               0x006c
+#define DRA7XX_CM_CLKSEL_DPLL_MPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x006c)
+#define DRA7XX_CM_DIV_M2_DPLL_MPU_OFFSET               0x0070
+#define DRA7XX_CM_DIV_M2_DPLL_MPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0070)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_MPU_OFFSET       0x0088
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_MPU_OFFSET       0x008c
+#define DRA7XX_CM_BYPCLK_DPLL_MPU_OFFSET               0x009c
+#define DRA7XX_CM_BYPCLK_DPLL_MPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x009c)
+#define DRA7XX_CM_CLKMODE_DPLL_IVA_OFFSET              0x00a0
+#define DRA7XX_CM_CLKMODE_DPLL_IVA                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00a0)
+#define DRA7XX_CM_IDLEST_DPLL_IVA_OFFSET               0x00a4
+#define DRA7XX_CM_IDLEST_DPLL_IVA                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00a4)
+#define DRA7XX_CM_AUTOIDLE_DPLL_IVA_OFFSET             0x00a8
+#define DRA7XX_CM_AUTOIDLE_DPLL_IVA                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00a8)
+#define DRA7XX_CM_CLKSEL_DPLL_IVA_OFFSET               0x00ac
+#define DRA7XX_CM_CLKSEL_DPLL_IVA                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00ac)
+#define DRA7XX_CM_DIV_M2_DPLL_IVA_OFFSET               0x00b0
+#define DRA7XX_CM_DIV_M2_DPLL_IVA                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00b0)
+#define DRA7XX_CM_DIV_M3_DPLL_IVA_OFFSET               0x00b4
+#define DRA7XX_CM_DIV_M3_DPLL_IVA                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00b4)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_IVA_OFFSET       0x00c8
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_IVA_OFFSET       0x00cc
+#define DRA7XX_CM_BYPCLK_DPLL_IVA_OFFSET               0x00dc
+#define DRA7XX_CM_BYPCLK_DPLL_IVA                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00dc)
+#define DRA7XX_CM_CLKMODE_DPLL_ABE_OFFSET              0x00e0
+#define DRA7XX_CM_CLKMODE_DPLL_ABE                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00e0)
+#define DRA7XX_CM_IDLEST_DPLL_ABE_OFFSET               0x00e4
+#define DRA7XX_CM_IDLEST_DPLL_ABE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00e4)
+#define DRA7XX_CM_AUTOIDLE_DPLL_ABE_OFFSET             0x00e8
+#define DRA7XX_CM_AUTOIDLE_DPLL_ABE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00e8)
+#define DRA7XX_CM_CLKSEL_DPLL_ABE_OFFSET               0x00ec
+#define DRA7XX_CM_CLKSEL_DPLL_ABE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00ec)
+#define DRA7XX_CM_DIV_M2_DPLL_ABE_OFFSET               0x00f0
+#define DRA7XX_CM_DIV_M2_DPLL_ABE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00f0)
+#define DRA7XX_CM_DIV_M3_DPLL_ABE_OFFSET               0x00f4
+#define DRA7XX_CM_DIV_M3_DPLL_ABE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x00f4)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_ABE_OFFSET       0x0108
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_ABE_OFFSET       0x010c
+#define DRA7XX_CM_CLKMODE_DPLL_DDR_OFFSET              0x0110
+#define DRA7XX_CM_CLKMODE_DPLL_DDR                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0110)
+#define DRA7XX_CM_IDLEST_DPLL_DDR_OFFSET               0x0114
+#define DRA7XX_CM_IDLEST_DPLL_DDR                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0114)
+#define DRA7XX_CM_AUTOIDLE_DPLL_DDR_OFFSET             0x0118
+#define DRA7XX_CM_AUTOIDLE_DPLL_DDR                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0118)
+#define DRA7XX_CM_CLKSEL_DPLL_DDR_OFFSET               0x011c
+#define DRA7XX_CM_CLKSEL_DPLL_DDR                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x011c)
+#define DRA7XX_CM_DIV_M2_DPLL_DDR_OFFSET               0x0120
+#define DRA7XX_CM_DIV_M2_DPLL_DDR                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0120)
+#define DRA7XX_CM_DIV_M3_DPLL_DDR_OFFSET               0x0124
+#define DRA7XX_CM_DIV_M3_DPLL_DDR                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0124)
+#define DRA7XX_CM_DIV_H11_DPLL_DDR_OFFSET              0x0128
+#define DRA7XX_CM_DIV_H11_DPLL_DDR                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0128)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_DDR_OFFSET       0x012c
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_DDR_OFFSET       0x0130
+#define DRA7XX_CM_CLKMODE_DPLL_DSP_OFFSET              0x0134
+#define DRA7XX_CM_CLKMODE_DPLL_DSP                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0134)
+#define DRA7XX_CM_IDLEST_DPLL_DSP_OFFSET               0x0138
+#define DRA7XX_CM_IDLEST_DPLL_DSP                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0138)
+#define DRA7XX_CM_AUTOIDLE_DPLL_DSP_OFFSET             0x013c
+#define DRA7XX_CM_AUTOIDLE_DPLL_DSP                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x013c)
+#define DRA7XX_CM_CLKSEL_DPLL_DSP_OFFSET               0x0140
+#define DRA7XX_CM_CLKSEL_DPLL_DSP                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0140)
+#define DRA7XX_CM_DIV_M2_DPLL_DSP_OFFSET               0x0144
+#define DRA7XX_CM_DIV_M2_DPLL_DSP                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0144)
+#define DRA7XX_CM_DIV_M3_DPLL_DSP_OFFSET               0x0148
+#define DRA7XX_CM_DIV_M3_DPLL_DSP                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0148)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_DSP_OFFSET       0x014c
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_DSP_OFFSET       0x0150
+#define DRA7XX_CM_BYPCLK_DPLL_DSP_OFFSET               0x0154
+#define DRA7XX_CM_BYPCLK_DPLL_DSP                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0154)
+#define DRA7XX_CM_SHADOW_FREQ_CONFIG1_OFFSET           0x0160
+#define DRA7XX_CM_SHADOW_FREQ_CONFIG2_OFFSET           0x0164
+#define DRA7XX_CM_DYN_DEP_PRESCAL_OFFSET               0x0170
+#define DRA7XX_CM_RESTORE_ST_OFFSET                    0x0180
+#define DRA7XX_CM_CLKMODE_DPLL_EVE_OFFSET              0x0184
+#define DRA7XX_CM_CLKMODE_DPLL_EVE                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0184)
+#define DRA7XX_CM_IDLEST_DPLL_EVE_OFFSET               0x0188
+#define DRA7XX_CM_IDLEST_DPLL_EVE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0188)
+#define DRA7XX_CM_AUTOIDLE_DPLL_EVE_OFFSET             0x018c
+#define DRA7XX_CM_AUTOIDLE_DPLL_EVE                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x018c)
+#define DRA7XX_CM_CLKSEL_DPLL_EVE_OFFSET               0x0190
+#define DRA7XX_CM_CLKSEL_DPLL_EVE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0190)
+#define DRA7XX_CM_DIV_M2_DPLL_EVE_OFFSET               0x0194
+#define DRA7XX_CM_DIV_M2_DPLL_EVE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0194)
+#define DRA7XX_CM_DIV_M3_DPLL_EVE_OFFSET               0x0198
+#define DRA7XX_CM_DIV_M3_DPLL_EVE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x0198)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_EVE_OFFSET       0x019c
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_EVE_OFFSET       0x01a0
+#define DRA7XX_CM_BYPCLK_DPLL_EVE_OFFSET               0x01a4
+#define DRA7XX_CM_BYPCLK_DPLL_EVE                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01a4)
+#define DRA7XX_CM_CLKMODE_DPLL_GMAC_OFFSET             0x01a8
+#define DRA7XX_CM_CLKMODE_DPLL_GMAC                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01a8)
+#define DRA7XX_CM_IDLEST_DPLL_GMAC_OFFSET              0x01ac
+#define DRA7XX_CM_IDLEST_DPLL_GMAC                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01ac)
+#define DRA7XX_CM_AUTOIDLE_DPLL_GMAC_OFFSET            0x01b0
+#define DRA7XX_CM_AUTOIDLE_DPLL_GMAC                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01b0)
+#define DRA7XX_CM_CLKSEL_DPLL_GMAC_OFFSET              0x01b4
+#define DRA7XX_CM_CLKSEL_DPLL_GMAC                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01b4)
+#define DRA7XX_CM_DIV_M2_DPLL_GMAC_OFFSET              0x01b8
+#define DRA7XX_CM_DIV_M2_DPLL_GMAC                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01b8)
+#define DRA7XX_CM_DIV_M3_DPLL_GMAC_OFFSET              0x01bc
+#define DRA7XX_CM_DIV_M3_DPLL_GMAC                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01bc)
+#define DRA7XX_CM_DIV_H11_DPLL_GMAC_OFFSET             0x01c0
+#define DRA7XX_CM_DIV_H11_DPLL_GMAC                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01c0)
+#define DRA7XX_CM_DIV_H12_DPLL_GMAC_OFFSET             0x01c4
+#define DRA7XX_CM_DIV_H12_DPLL_GMAC                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01c4)
+#define DRA7XX_CM_DIV_H13_DPLL_GMAC_OFFSET             0x01c8
+#define DRA7XX_CM_DIV_H13_DPLL_GMAC                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01c8)
+#define DRA7XX_CM_DIV_H14_DPLL_GMAC_OFFSET             0x01cc
+#define DRA7XX_CM_DIV_H14_DPLL_GMAC                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01cc)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_GMAC_OFFSET      0x01d0
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_GMAC_OFFSET      0x01d4
+#define DRA7XX_CM_CLKMODE_DPLL_GPU_OFFSET              0x01d8
+#define DRA7XX_CM_CLKMODE_DPLL_GPU                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01d8)
+#define DRA7XX_CM_IDLEST_DPLL_GPU_OFFSET               0x01dc
+#define DRA7XX_CM_IDLEST_DPLL_GPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01dc)
+#define DRA7XX_CM_AUTOIDLE_DPLL_GPU_OFFSET             0x01e0
+#define DRA7XX_CM_AUTOIDLE_DPLL_GPU                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01e0)
+#define DRA7XX_CM_CLKSEL_DPLL_GPU_OFFSET               0x01e4
+#define DRA7XX_CM_CLKSEL_DPLL_GPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01e4)
+#define DRA7XX_CM_DIV_M2_DPLL_GPU_OFFSET               0x01e8
+#define DRA7XX_CM_DIV_M2_DPLL_GPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01e8)
+#define DRA7XX_CM_DIV_M3_DPLL_GPU_OFFSET               0x01ec
+#define DRA7XX_CM_DIV_M3_DPLL_GPU                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_CKGEN_INST, 0x01ec)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_GPU_OFFSET       0x01f0
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_GPU_OFFSET       0x01f4
+
+/* CM_CORE_AON.MPU_CM_CORE_AON register offsets */
+#define DRA7XX_CM_MPU_CLKSTCTRL_OFFSET                 0x0000
+#define DRA7XX_CM_MPU_STATICDEP_OFFSET                 0x0004
+#define DRA7XX_CM_MPU_DYNAMICDEP_OFFSET                        0x0008
+#define DRA7XX_CM_MPU_MPU_CLKCTRL_OFFSET               0x0020
+#define DRA7XX_CM_MPU_MPU_CLKCTRL                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_MPU_INST, 0x0020)
+#define DRA7XX_CM_MPU_MPU_MPU_DBG_CLKCTRL_OFFSET       0x0028
+#define DRA7XX_CM_MPU_MPU_MPU_DBG_CLKCTRL              DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_MPU_INST, 0x0028)
+
+/* CM_CORE_AON.DSP1_CM_CORE_AON register offsets */
+#define DRA7XX_CM_DSP1_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_DSP1_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_DSP1_DYNAMICDEP_OFFSET               0x0008
+#define DRA7XX_CM_DSP1_DSP1_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_DSP1_DSP1_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_DSP1_INST, 0x0020)
+
+/* CM_CORE_AON.IPU_CM_CORE_AON register offsets */
+#define DRA7XX_CM_IPU1_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_IPU1_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_IPU1_DYNAMICDEP_OFFSET               0x0008
+#define DRA7XX_CM_IPU1_IPU1_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_IPU1_IPU1_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0020)
+#define DRA7XX_CM_IPU_CLKSTCTRL_OFFSET                 0x0040
+#define DRA7XX_CM_IPU_MCASP1_CLKCTRL_OFFSET            0x0050
+#define DRA7XX_CM_IPU_MCASP1_CLKCTRL                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0050)
+#define DRA7XX_CM_IPU_TIMER5_CLKCTRL_OFFSET            0x0058
+#define DRA7XX_CM_IPU_TIMER5_CLKCTRL                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0058)
+#define DRA7XX_CM_IPU_TIMER6_CLKCTRL_OFFSET            0x0060
+#define DRA7XX_CM_IPU_TIMER6_CLKCTRL                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0060)
+#define DRA7XX_CM_IPU_TIMER7_CLKCTRL_OFFSET            0x0068
+#define DRA7XX_CM_IPU_TIMER7_CLKCTRL                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0068)
+#define DRA7XX_CM_IPU_TIMER8_CLKCTRL_OFFSET            0x0070
+#define DRA7XX_CM_IPU_TIMER8_CLKCTRL                   DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0070)
+#define DRA7XX_CM_IPU_I2C5_CLKCTRL_OFFSET              0x0078
+#define DRA7XX_CM_IPU_I2C5_CLKCTRL                     DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0078)
+#define DRA7XX_CM_IPU_UART6_CLKCTRL_OFFSET             0x0080
+#define DRA7XX_CM_IPU_UART6_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_IPU_INST, 0x0080)
+
+/* CM_CORE_AON.DSP2_CM_CORE_AON register offsets */
+#define DRA7XX_CM_DSP2_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_DSP2_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_DSP2_DYNAMICDEP_OFFSET               0x0008
+#define DRA7XX_CM_DSP2_DSP2_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_DSP2_DSP2_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_DSP2_INST, 0x0020)
+
+/* CM_CORE_AON.EVE1_CM_CORE_AON register offsets */
+#define DRA7XX_CM_EVE1_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_EVE1_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_EVE1_EVE1_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_EVE1_EVE1_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_EVE1_INST, 0x0020)
+
+/* CM_CORE_AON.EVE2_CM_CORE_AON register offsets */
+#define DRA7XX_CM_EVE2_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_EVE2_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_EVE2_EVE2_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_EVE2_EVE2_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_EVE2_INST, 0x0020)
+
+/* CM_CORE_AON.EVE3_CM_CORE_AON register offsets */
+#define DRA7XX_CM_EVE3_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_EVE3_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_EVE3_EVE3_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_EVE3_EVE3_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_EVE3_INST, 0x0020)
+
+/* CM_CORE_AON.EVE4_CM_CORE_AON register offsets */
+#define DRA7XX_CM_EVE4_CLKSTCTRL_OFFSET                        0x0000
+#define DRA7XX_CM_EVE4_STATICDEP_OFFSET                        0x0004
+#define DRA7XX_CM_EVE4_EVE4_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_EVE4_EVE4_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_EVE4_INST, 0x0020)
+
+/* CM_CORE_AON.RTC_CM_CORE_AON register offsets */
+#define DRA7XX_CM_RTC_CLKSTCTRL_OFFSET                 0x0000
+#define DRA7XX_CM_RTC_RTCSS_CLKCTRL_OFFSET             0x0004
+#define DRA7XX_CM_RTC_RTCSS_CLKCTRL                    DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_RTC_INST, 0x0004)
+
+/* CM_CORE_AON.VPE_CM_CORE_AON register offsets */
+#define DRA7XX_CM_VPE_CLKSTCTRL_OFFSET                 0x0000
+#define DRA7XX_CM_VPE_VPE_CLKCTRL_OFFSET               0x0004
+#define DRA7XX_CM_VPE_VPE_CLKCTRL                      DRA7XX_CM_CORE_AON_REGADDR(DRA7XX_CM_CORE_AON_VPE_INST, 0x0004)
+#define DRA7XX_CM_VPE_STATICDEP_OFFSET                 0x0008
+
+#endif
diff --git a/arch/arm/mach-omap2/cm2_7xx.h b/arch/arm/mach-omap2/cm2_7xx.h
new file mode 100644 (file)
index 0000000..9ad7594
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * DRA7xx CM2 instance offset macros
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Generated by code originally written by:
+ * Paul Walmsley (paul@pwsan.com)
+ * Rajendra Nayak (rnayak@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_CM2_7XX_H
+#define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H
+
+#include "cm_44xx_54xx.h"
+
+/* CM2 base address */
+#define DRA7XX_CM_CORE_BASE            0x4a008000
+
+#define DRA7XX_CM_CORE_REGADDR(inst, reg)                              \
+       OMAP2_L4_IO_ADDRESS(DRA7XX_CM_CORE_BASE + (inst) + (reg))
+
+/* CM_CORE instances */
+#define DRA7XX_CM_CORE_OCP_SOCKET_INST 0x0000
+#define DRA7XX_CM_CORE_CKGEN_INST      0x0104
+#define DRA7XX_CM_CORE_COREAON_INST    0x0600
+#define DRA7XX_CM_CORE_CORE_INST       0x0700
+#define DRA7XX_CM_CORE_IVA_INST                0x0f00
+#define DRA7XX_CM_CORE_CAM_INST                0x1000
+#define DRA7XX_CM_CORE_DSS_INST                0x1100
+#define DRA7XX_CM_CORE_GPU_INST                0x1200
+#define DRA7XX_CM_CORE_L3INIT_INST     0x1300
+#define DRA7XX_CM_CORE_CUSTEFUSE_INST  0x1600
+#define DRA7XX_CM_CORE_L4PER_INST      0x1700
+#define DRA7XX_CM_CORE_RESTORE_INST    0x1e18
+
+/* CM_CORE clockdomain register offsets (from instance start) */
+#define DRA7XX_CM_CORE_COREAON_COREAON_CDOFFS          0x0000
+#define DRA7XX_CM_CORE_CORE_L3MAIN1_CDOFFS             0x0000
+#define DRA7XX_CM_CORE_CORE_IPU2_CDOFFS                        0x0200
+#define DRA7XX_CM_CORE_CORE_DMA_CDOFFS                 0x0300
+#define DRA7XX_CM_CORE_CORE_EMIF_CDOFFS                        0x0400
+#define DRA7XX_CM_CORE_CORE_ATL_CDOFFS                 0x0520
+#define DRA7XX_CM_CORE_CORE_L4CFG_CDOFFS               0x0600
+#define DRA7XX_CM_CORE_CORE_L3INSTR_CDOFFS             0x0700
+#define DRA7XX_CM_CORE_IVA_IVA_CDOFFS                  0x0000
+#define DRA7XX_CM_CORE_CAM_CAM_CDOFFS                  0x0000
+#define DRA7XX_CM_CORE_DSS_DSS_CDOFFS                  0x0000
+#define DRA7XX_CM_CORE_GPU_GPU_CDOFFS                  0x0000
+#define DRA7XX_CM_CORE_L3INIT_L3INIT_CDOFFS            0x0000
+#define DRA7XX_CM_CORE_L3INIT_PCIE_CDOFFS              0x00a0
+#define DRA7XX_CM_CORE_L3INIT_GMAC_CDOFFS              0x00c0
+#define DRA7XX_CM_CORE_CUSTEFUSE_CUSTEFUSE_CDOFFS      0x0000
+#define DRA7XX_CM_CORE_L4PER_L4PER_CDOFFS              0x0000
+#define DRA7XX_CM_CORE_L4PER_L4SEC_CDOFFS              0x0180
+#define DRA7XX_CM_CORE_L4PER_L4PER2_CDOFFS             0x01fc
+#define DRA7XX_CM_CORE_L4PER_L4PER3_CDOFFS             0x0210
+
+/* CM_CORE */
+
+/* CM_CORE.OCP_SOCKET_CM_CORE register offsets */
+#define DRA7XX_REVISION_CM_CORE_OFFSET                         0x0000
+#define DRA7XX_CM_CM_CORE_PROFILING_CLKCTRL_OFFSET             0x0040
+#define DRA7XX_CM_CM_CORE_PROFILING_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_OCP_SOCKET_INST, 0x0040)
+#define DRA7XX_CM_CORE_DEBUG_CFG_OFFSET                                0x00f0
+
+/* CM_CORE.CKGEN_CM_CORE register offsets */
+#define DRA7XX_CM_CLKSEL_USB_60MHZ_OFFSET                      0x0000
+#define DRA7XX_CM_CLKSEL_USB_60MHZ                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0000)
+#define DRA7XX_CM_CLKMODE_DPLL_PER_OFFSET                      0x003c
+#define DRA7XX_CM_CLKMODE_DPLL_PER                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x003c)
+#define DRA7XX_CM_IDLEST_DPLL_PER_OFFSET                       0x0040
+#define DRA7XX_CM_IDLEST_DPLL_PER                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0040)
+#define DRA7XX_CM_AUTOIDLE_DPLL_PER_OFFSET                     0x0044
+#define DRA7XX_CM_AUTOIDLE_DPLL_PER                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0044)
+#define DRA7XX_CM_CLKSEL_DPLL_PER_OFFSET                       0x0048
+#define DRA7XX_CM_CLKSEL_DPLL_PER                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0048)
+#define DRA7XX_CM_DIV_M2_DPLL_PER_OFFSET                       0x004c
+#define DRA7XX_CM_DIV_M2_DPLL_PER                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x004c)
+#define DRA7XX_CM_DIV_M3_DPLL_PER_OFFSET                       0x0050
+#define DRA7XX_CM_DIV_M3_DPLL_PER                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0050)
+#define DRA7XX_CM_DIV_H11_DPLL_PER_OFFSET                      0x0054
+#define DRA7XX_CM_DIV_H11_DPLL_PER                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0054)
+#define DRA7XX_CM_DIV_H12_DPLL_PER_OFFSET                      0x0058
+#define DRA7XX_CM_DIV_H12_DPLL_PER                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0058)
+#define DRA7XX_CM_DIV_H13_DPLL_PER_OFFSET                      0x005c
+#define DRA7XX_CM_DIV_H13_DPLL_PER                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x005c)
+#define DRA7XX_CM_DIV_H14_DPLL_PER_OFFSET                      0x0060
+#define DRA7XX_CM_DIV_H14_DPLL_PER                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0060)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_PER_OFFSET               0x0064
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_PER_OFFSET               0x0068
+#define DRA7XX_CM_CLKMODE_DPLL_USB_OFFSET                      0x007c
+#define DRA7XX_CM_CLKMODE_DPLL_USB                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x007c)
+#define DRA7XX_CM_IDLEST_DPLL_USB_OFFSET                       0x0080
+#define DRA7XX_CM_IDLEST_DPLL_USB                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0080)
+#define DRA7XX_CM_AUTOIDLE_DPLL_USB_OFFSET                     0x0084
+#define DRA7XX_CM_AUTOIDLE_DPLL_USB                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0084)
+#define DRA7XX_CM_CLKSEL_DPLL_USB_OFFSET                       0x0088
+#define DRA7XX_CM_CLKSEL_DPLL_USB                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0088)
+#define DRA7XX_CM_DIV_M2_DPLL_USB_OFFSET                       0x008c
+#define DRA7XX_CM_DIV_M2_DPLL_USB                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x008c)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_USB_OFFSET               0x00a4
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_USB_OFFSET               0x00a8
+#define DRA7XX_CM_CLKDCOLDO_DPLL_USB_OFFSET                    0x00b0
+#define DRA7XX_CM_CLKDCOLDO_DPLL_USB                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x00b0)
+#define DRA7XX_CM_CLKMODE_DPLL_PCIE_REF_OFFSET                 0x00fc
+#define DRA7XX_CM_CLKMODE_DPLL_PCIE_REF                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x00fc)
+#define DRA7XX_CM_IDLEST_DPLL_PCIE_REF_OFFSET                  0x0100
+#define DRA7XX_CM_IDLEST_DPLL_PCIE_REF                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0100)
+#define DRA7XX_CM_AUTOIDLE_DPLL_PCIE_REF_OFFSET                        0x0104
+#define DRA7XX_CM_AUTOIDLE_DPLL_PCIE_REF                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0104)
+#define DRA7XX_CM_CLKSEL_DPLL_PCIE_REF_OFFSET                  0x0108
+#define DRA7XX_CM_CLKSEL_DPLL_PCIE_REF                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0108)
+#define DRA7XX_CM_DIV_M2_DPLL_PCIE_REF_OFFSET                  0x010c
+#define DRA7XX_CM_DIV_M2_DPLL_PCIE_REF                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x010c)
+#define DRA7XX_CM_SSC_DELTAMSTEP_DPLL_PCIE_REF_OFFSET          0x0110
+#define DRA7XX_CM_SSC_MODFREQDIV_DPLL_PCIE_REF_OFFSET          0x0114
+#define DRA7XX_CM_CLKMODE_APLL_PCIE_OFFSET                     0x0118
+#define DRA7XX_CM_CLKMODE_APLL_PCIE                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0118)
+#define DRA7XX_CM_IDLEST_APLL_PCIE_OFFSET                      0x011c
+#define DRA7XX_CM_IDLEST_APLL_PCIE                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x011c)
+#define DRA7XX_CM_DIV_M2_APLL_PCIE_OFFSET                      0x0120
+#define DRA7XX_CM_DIV_M2_APLL_PCIE                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0120)
+#define DRA7XX_CM_CLKVCOLDO_APLL_PCIE_OFFSET                   0x0124
+#define DRA7XX_CM_CLKVCOLDO_APLL_PCIE                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CKGEN_INST, 0x0124)
+
+/* CM_CORE.COREAON_CM_CORE register offsets */
+#define DRA7XX_CM_COREAON_CLKSTCTRL_OFFSET                     0x0000
+#define DRA7XX_CM_COREAON_SMARTREFLEX_MPU_CLKCTRL_OFFSET       0x0028
+#define DRA7XX_CM_COREAON_SMARTREFLEX_MPU_CLKCTRL              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0028)
+#define DRA7XX_CM_COREAON_SMARTREFLEX_CORE_CLKCTRL_OFFSET      0x0038
+#define DRA7XX_CM_COREAON_SMARTREFLEX_CORE_CLKCTRL             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0038)
+#define DRA7XX_CM_COREAON_USB_PHY1_CORE_CLKCTRL_OFFSET         0x0040
+#define DRA7XX_CM_COREAON_USB_PHY1_CORE_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0040)
+#define DRA7XX_CM_COREAON_IO_SRCOMP_CLKCTRL_OFFSET             0x0050
+#define DRA7XX_CM_COREAON_IO_SRCOMP_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0050)
+#define DRA7XX_CM_COREAON_SMARTREFLEX_GPU_CLKCTRL_OFFSET       0x0058
+#define DRA7XX_CM_COREAON_SMARTREFLEX_GPU_CLKCTRL              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0058)
+#define DRA7XX_CM_COREAON_SMARTREFLEX_DSPEVE_CLKCTRL_OFFSET    0x0068
+#define DRA7XX_CM_COREAON_SMARTREFLEX_DSPEVE_CLKCTRL           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0068)
+#define DRA7XX_CM_COREAON_SMARTREFLEX_IVAHD_CLKCTRL_OFFSET     0x0078
+#define DRA7XX_CM_COREAON_SMARTREFLEX_IVAHD_CLKCTRL            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0078)
+#define DRA7XX_CM_COREAON_USB_PHY2_CORE_CLKCTRL_OFFSET         0x0088
+#define DRA7XX_CM_COREAON_USB_PHY2_CORE_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0088)
+#define DRA7XX_CM_COREAON_USB_PHY3_CORE_CLKCTRL_OFFSET         0x0098
+#define DRA7XX_CM_COREAON_USB_PHY3_CORE_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x0098)
+#define DRA7XX_CM_COREAON_DUMMY_MODULE1_CLKCTRL_OFFSET         0x00a0
+#define DRA7XX_CM_COREAON_DUMMY_MODULE1_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x00a0)
+#define DRA7XX_CM_COREAON_DUMMY_MODULE2_CLKCTRL_OFFSET         0x00b0
+#define DRA7XX_CM_COREAON_DUMMY_MODULE2_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x00b0)
+#define DRA7XX_CM_COREAON_DUMMY_MODULE3_CLKCTRL_OFFSET         0x00c0
+#define DRA7XX_CM_COREAON_DUMMY_MODULE3_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x00c0)
+#define DRA7XX_CM_COREAON_DUMMY_MODULE4_CLKCTRL_OFFSET         0x00d0
+#define DRA7XX_CM_COREAON_DUMMY_MODULE4_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_COREAON_INST, 0x00d0)
+
+/* CM_CORE.CORE_CM_CORE register offsets */
+#define DRA7XX_CM_L3MAIN1_CLKSTCTRL_OFFSET                     0x0000
+#define DRA7XX_CM_L3MAIN1_DYNAMICDEP_OFFSET                    0x0008
+#define DRA7XX_CM_L3MAIN1_L3_MAIN_1_CLKCTRL_OFFSET             0x0020
+#define DRA7XX_CM_L3MAIN1_L3_MAIN_1_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0020)
+#define DRA7XX_CM_L3MAIN1_GPMC_CLKCTRL_OFFSET                  0x0028
+#define DRA7XX_CM_L3MAIN1_GPMC_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0028)
+#define DRA7XX_CM_L3MAIN1_MMU_EDMA_CLKCTRL_OFFSET              0x0030
+#define DRA7XX_CM_L3MAIN1_MMU_EDMA_CLKCTRL                     DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0030)
+#define DRA7XX_CM_L3MAIN1_OCMC_RAM1_CLKCTRL_OFFSET             0x0050
+#define DRA7XX_CM_L3MAIN1_OCMC_RAM1_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0050)
+#define DRA7XX_CM_L3MAIN1_OCMC_RAM2_CLKCTRL_OFFSET             0x0058
+#define DRA7XX_CM_L3MAIN1_OCMC_RAM2_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0058)
+#define DRA7XX_CM_L3MAIN1_OCMC_RAM3_CLKCTRL_OFFSET             0x0060
+#define DRA7XX_CM_L3MAIN1_OCMC_RAM3_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0060)
+#define DRA7XX_CM_L3MAIN1_OCMC_ROM_CLKCTRL_OFFSET              0x0068
+#define DRA7XX_CM_L3MAIN1_OCMC_ROM_CLKCTRL                     DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0068)
+#define DRA7XX_CM_L3MAIN1_TPCC_CLKCTRL_OFFSET                  0x0070
+#define DRA7XX_CM_L3MAIN1_TPCC_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0070)
+#define DRA7XX_CM_L3MAIN1_TPTC1_CLKCTRL_OFFSET                 0x0078
+#define DRA7XX_CM_L3MAIN1_TPTC1_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0078)
+#define DRA7XX_CM_L3MAIN1_TPTC2_CLKCTRL_OFFSET                 0x0080
+#define DRA7XX_CM_L3MAIN1_TPTC2_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0080)
+#define DRA7XX_CM_L3MAIN1_VCP1_CLKCTRL_OFFSET                  0x0088
+#define DRA7XX_CM_L3MAIN1_VCP1_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0088)
+#define DRA7XX_CM_L3MAIN1_VCP2_CLKCTRL_OFFSET                  0x0090
+#define DRA7XX_CM_L3MAIN1_VCP2_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0090)
+#define DRA7XX_CM_L3MAIN1_SPARE_CME_CLKCTRL_OFFSET             0x0098
+#define DRA7XX_CM_L3MAIN1_SPARE_CME_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0098)
+#define DRA7XX_CM_L3MAIN1_SPARE_HDMI_CLKCTRL_OFFSET            0x00a0
+#define DRA7XX_CM_L3MAIN1_SPARE_HDMI_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00a0)
+#define DRA7XX_CM_L3MAIN1_SPARE_ICM_CLKCTRL_OFFSET             0x00a8
+#define DRA7XX_CM_L3MAIN1_SPARE_ICM_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00a8)
+#define DRA7XX_CM_L3MAIN1_SPARE_IVA2_CLKCTRL_OFFSET            0x00b0
+#define DRA7XX_CM_L3MAIN1_SPARE_IVA2_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00b0)
+#define DRA7XX_CM_L3MAIN1_SPARE_SATA2_CLKCTRL_OFFSET           0x00b8
+#define DRA7XX_CM_L3MAIN1_SPARE_SATA2_CLKCTRL                  DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00b8)
+#define DRA7XX_CM_L3MAIN1_SPARE_UNKNOWN4_CLKCTRL_OFFSET                0x00c0
+#define DRA7XX_CM_L3MAIN1_SPARE_UNKNOWN4_CLKCTRL               DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00c0)
+#define DRA7XX_CM_L3MAIN1_SPARE_UNKNOWN5_CLKCTRL_OFFSET                0x00c8
+#define DRA7XX_CM_L3MAIN1_SPARE_UNKNOWN5_CLKCTRL               DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00c8)
+#define DRA7XX_CM_L3MAIN1_SPARE_UNKNOWN6_CLKCTRL_OFFSET                0x00d0
+#define DRA7XX_CM_L3MAIN1_SPARE_UNKNOWN6_CLKCTRL               DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00d0)
+#define DRA7XX_CM_L3MAIN1_SPARE_VIDEOPLL1_CLKCTRL_OFFSET       0x00d8
+#define DRA7XX_CM_L3MAIN1_SPARE_VIDEOPLL1_CLKCTRL              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00d8)
+#define DRA7XX_CM_L3MAIN1_SPARE_VIDEOPLL2_CLKCTRL_OFFSET       0x00f0
+#define DRA7XX_CM_L3MAIN1_SPARE_VIDEOPLL2_CLKCTRL              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00f0)
+#define DRA7XX_CM_L3MAIN1_SPARE_VIDEOPLL3_CLKCTRL_OFFSET       0x00f8
+#define DRA7XX_CM_L3MAIN1_SPARE_VIDEOPLL3_CLKCTRL              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x00f8)
+#define DRA7XX_CM_IPU2_CLKSTCTRL_OFFSET                                0x0200
+#define DRA7XX_CM_IPU2_STATICDEP_OFFSET                                0x0204
+#define DRA7XX_CM_IPU2_DYNAMICDEP_OFFSET                       0x0208
+#define DRA7XX_CM_IPU2_IPU2_CLKCTRL_OFFSET                     0x0220
+#define DRA7XX_CM_IPU2_IPU2_CLKCTRL                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0220)
+#define DRA7XX_CM_DMA_CLKSTCTRL_OFFSET                         0x0300
+#define DRA7XX_CM_DMA_STATICDEP_OFFSET                         0x0304
+#define DRA7XX_CM_DMA_DYNAMICDEP_OFFSET                                0x0308
+#define DRA7XX_CM_DMA_DMA_SYSTEM_CLKCTRL_OFFSET                        0x0320
+#define DRA7XX_CM_DMA_DMA_SYSTEM_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0320)
+#define DRA7XX_CM_EMIF_CLKSTCTRL_OFFSET                                0x0400
+#define DRA7XX_CM_EMIF_DMM_CLKCTRL_OFFSET                      0x0420
+#define DRA7XX_CM_EMIF_DMM_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0420)
+#define DRA7XX_CM_EMIF_EMIF_OCP_FW_CLKCTRL_OFFSET              0x0428
+#define DRA7XX_CM_EMIF_EMIF_OCP_FW_CLKCTRL                     DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0428)
+#define DRA7XX_CM_EMIF_EMIF1_CLKCTRL_OFFSET                    0x0430
+#define DRA7XX_CM_EMIF_EMIF1_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0430)
+#define DRA7XX_CM_EMIF_EMIF2_CLKCTRL_OFFSET                    0x0438
+#define DRA7XX_CM_EMIF_EMIF2_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0438)
+#define DRA7XX_CM_EMIF_EMIF_DLL_CLKCTRL_OFFSET                 0x0440
+#define DRA7XX_CM_EMIF_EMIF_DLL_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0440)
+#define DRA7XX_CM_ATL_ATL_CLKCTRL_OFFSET                       0x0500
+#define DRA7XX_CM_ATL_ATL_CLKCTRL                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0500)
+#define DRA7XX_CM_ATL_CLKSTCTRL_OFFSET                         0x0520
+#define DRA7XX_CM_L4CFG_CLKSTCTRL_OFFSET                       0x0600
+#define DRA7XX_CM_L4CFG_DYNAMICDEP_OFFSET                      0x0608
+#define DRA7XX_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET                  0x0620
+#define DRA7XX_CM_L4CFG_L4_CFG_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0620)
+#define DRA7XX_CM_L4CFG_SPINLOCK_CLKCTRL_OFFSET                        0x0628
+#define DRA7XX_CM_L4CFG_SPINLOCK_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0628)
+#define DRA7XX_CM_L4CFG_MAILBOX1_CLKCTRL_OFFSET                        0x0630
+#define DRA7XX_CM_L4CFG_MAILBOX1_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0630)
+#define DRA7XX_CM_L4CFG_SAR_ROM_CLKCTRL_OFFSET                 0x0638
+#define DRA7XX_CM_L4CFG_SAR_ROM_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0638)
+#define DRA7XX_CM_L4CFG_OCP2SCP2_CLKCTRL_OFFSET                        0x0640
+#define DRA7XX_CM_L4CFG_OCP2SCP2_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0640)
+#define DRA7XX_CM_L4CFG_MAILBOX2_CLKCTRL_OFFSET                        0x0648
+#define DRA7XX_CM_L4CFG_MAILBOX2_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0648)
+#define DRA7XX_CM_L4CFG_MAILBOX3_CLKCTRL_OFFSET                        0x0650
+#define DRA7XX_CM_L4CFG_MAILBOX3_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0650)
+#define DRA7XX_CM_L4CFG_MAILBOX4_CLKCTRL_OFFSET                        0x0658
+#define DRA7XX_CM_L4CFG_MAILBOX4_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0658)
+#define DRA7XX_CM_L4CFG_MAILBOX5_CLKCTRL_OFFSET                        0x0660
+#define DRA7XX_CM_L4CFG_MAILBOX5_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0660)
+#define DRA7XX_CM_L4CFG_MAILBOX6_CLKCTRL_OFFSET                        0x0668
+#define DRA7XX_CM_L4CFG_MAILBOX6_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0668)
+#define DRA7XX_CM_L4CFG_MAILBOX7_CLKCTRL_OFFSET                        0x0670
+#define DRA7XX_CM_L4CFG_MAILBOX7_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0670)
+#define DRA7XX_CM_L4CFG_MAILBOX8_CLKCTRL_OFFSET                        0x0678
+#define DRA7XX_CM_L4CFG_MAILBOX8_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0678)
+#define DRA7XX_CM_L4CFG_MAILBOX9_CLKCTRL_OFFSET                        0x0680
+#define DRA7XX_CM_L4CFG_MAILBOX9_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0680)
+#define DRA7XX_CM_L4CFG_MAILBOX10_CLKCTRL_OFFSET               0x0688
+#define DRA7XX_CM_L4CFG_MAILBOX10_CLKCTRL                      DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0688)
+#define DRA7XX_CM_L4CFG_MAILBOX11_CLKCTRL_OFFSET               0x0690
+#define DRA7XX_CM_L4CFG_MAILBOX11_CLKCTRL                      DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0690)
+#define DRA7XX_CM_L4CFG_MAILBOX12_CLKCTRL_OFFSET               0x0698
+#define DRA7XX_CM_L4CFG_MAILBOX12_CLKCTRL                      DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0698)
+#define DRA7XX_CM_L4CFG_MAILBOX13_CLKCTRL_OFFSET               0x06a0
+#define DRA7XX_CM_L4CFG_MAILBOX13_CLKCTRL                      DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x06a0)
+#define DRA7XX_CM_L4CFG_SPARE_SMARTREFLEX_RTC_CLKCTRL_OFFSET   0x06a8
+#define DRA7XX_CM_L4CFG_SPARE_SMARTREFLEX_RTC_CLKCTRL          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x06a8)
+#define DRA7XX_CM_L4CFG_SPARE_SMARTREFLEX_SDRAM_CLKCTRL_OFFSET 0x06b0
+#define DRA7XX_CM_L4CFG_SPARE_SMARTREFLEX_SDRAM_CLKCTRL                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x06b0)
+#define DRA7XX_CM_L4CFG_SPARE_SMARTREFLEX_WKUP_CLKCTRL_OFFSET  0x06b8
+#define DRA7XX_CM_L4CFG_SPARE_SMARTREFLEX_WKUP_CLKCTRL         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x06b8)
+#define DRA7XX_CM_L4CFG_IO_DELAY_BLOCK_CLKCTRL_OFFSET          0x06c0
+#define DRA7XX_CM_L4CFG_IO_DELAY_BLOCK_CLKCTRL                 DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x06c0)
+#define DRA7XX_CM_L3INSTR_CLKSTCTRL_OFFSET                     0x0700
+#define DRA7XX_CM_L3INSTR_L3_MAIN_2_CLKCTRL_OFFSET             0x0720
+#define DRA7XX_CM_L3INSTR_L3_MAIN_2_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0720)
+#define DRA7XX_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET              0x0728
+#define DRA7XX_CM_L3INSTR_L3_INSTR_CLKCTRL                     DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0728)
+#define DRA7XX_CM_L3INSTR_OCP_WP_NOC_CLKCTRL_OFFSET            0x0740
+#define DRA7XX_CM_L3INSTR_OCP_WP_NOC_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0740)
+#define DRA7XX_CM_L3INSTR_DLL_AGING_CLKCTRL_OFFSET             0x0748
+#define DRA7XX_CM_L3INSTR_DLL_AGING_CLKCTRL                    DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0748)
+#define DRA7XX_CM_L3INSTR_CTRL_MODULE_BANDGAP_CLKCTRL_OFFSET   0x0750
+#define DRA7XX_CM_L3INSTR_CTRL_MODULE_BANDGAP_CLKCTRL          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CORE_INST, 0x0750)
+
+/* CM_CORE.IVA_CM_CORE register offsets */
+#define DRA7XX_CM_IVA_CLKSTCTRL_OFFSET                         0x0000
+#define DRA7XX_CM_IVA_STATICDEP_OFFSET                         0x0004
+#define DRA7XX_CM_IVA_DYNAMICDEP_OFFSET                                0x0008
+#define DRA7XX_CM_IVA_IVA_CLKCTRL_OFFSET                       0x0020
+#define DRA7XX_CM_IVA_IVA_CLKCTRL                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_IVA_INST, 0x0020)
+#define DRA7XX_CM_IVA_SL2_CLKCTRL_OFFSET                       0x0028
+#define DRA7XX_CM_IVA_SL2_CLKCTRL                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_IVA_INST, 0x0028)
+
+/* CM_CORE.CAM_CM_CORE register offsets */
+#define DRA7XX_CM_CAM_CLKSTCTRL_OFFSET                         0x0000
+#define DRA7XX_CM_CAM_STATICDEP_OFFSET                         0x0004
+#define DRA7XX_CM_CAM_VIP1_CLKCTRL_OFFSET                      0x0020
+#define DRA7XX_CM_CAM_VIP1_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CAM_INST, 0x0020)
+#define DRA7XX_CM_CAM_VIP2_CLKCTRL_OFFSET                      0x0028
+#define DRA7XX_CM_CAM_VIP2_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CAM_INST, 0x0028)
+#define DRA7XX_CM_CAM_VIP3_CLKCTRL_OFFSET                      0x0030
+#define DRA7XX_CM_CAM_VIP3_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CAM_INST, 0x0030)
+#define DRA7XX_CM_CAM_LVDSRX_CLKCTRL_OFFSET                    0x0038
+#define DRA7XX_CM_CAM_LVDSRX_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CAM_INST, 0x0038)
+#define DRA7XX_CM_CAM_CSI1_CLKCTRL_OFFSET                      0x0040
+#define DRA7XX_CM_CAM_CSI1_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CAM_INST, 0x0040)
+#define DRA7XX_CM_CAM_CSI2_CLKCTRL_OFFSET                      0x0048
+#define DRA7XX_CM_CAM_CSI2_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CAM_INST, 0x0048)
+
+/* CM_CORE.DSS_CM_CORE register offsets */
+#define DRA7XX_CM_DSS_CLKSTCTRL_OFFSET                         0x0000
+#define DRA7XX_CM_DSS_STATICDEP_OFFSET                         0x0004
+#define DRA7XX_CM_DSS_DYNAMICDEP_OFFSET                                0x0008
+#define DRA7XX_CM_DSS_DSS_CLKCTRL_OFFSET                       0x0020
+#define DRA7XX_CM_DSS_DSS_CLKCTRL                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_DSS_INST, 0x0020)
+#define DRA7XX_CM_DSS_BB2D_CLKCTRL_OFFSET                      0x0030
+#define DRA7XX_CM_DSS_BB2D_CLKCTRL                             DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_DSS_INST, 0x0030)
+#define DRA7XX_CM_DSS_SDVENC_CLKCTRL_OFFSET                    0x003c
+#define DRA7XX_CM_DSS_SDVENC_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_DSS_INST, 0x003c)
+
+/* CM_CORE.GPU_CM_CORE register offsets */
+#define DRA7XX_CM_GPU_CLKSTCTRL_OFFSET                         0x0000
+#define DRA7XX_CM_GPU_STATICDEP_OFFSET                         0x0004
+#define DRA7XX_CM_GPU_DYNAMICDEP_OFFSET                                0x0008
+#define DRA7XX_CM_GPU_GPU_CLKCTRL_OFFSET                       0x0020
+#define DRA7XX_CM_GPU_GPU_CLKCTRL                              DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_GPU_INST, 0x0020)
+
+/* CM_CORE.L3INIT_CM_CORE register offsets */
+#define DRA7XX_CM_L3INIT_CLKSTCTRL_OFFSET                      0x0000
+#define DRA7XX_CM_L3INIT_STATICDEP_OFFSET                      0x0004
+#define DRA7XX_CM_L3INIT_DYNAMICDEP_OFFSET                     0x0008
+#define DRA7XX_CM_L3INIT_MMC1_CLKCTRL_OFFSET                   0x0028
+#define DRA7XX_CM_L3INIT_MMC1_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0028)
+#define DRA7XX_CM_L3INIT_MMC2_CLKCTRL_OFFSET                   0x0030
+#define DRA7XX_CM_L3INIT_MMC2_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0030)
+#define DRA7XX_CM_L3INIT_USB_OTG_SS2_CLKCTRL_OFFSET            0x0040
+#define DRA7XX_CM_L3INIT_USB_OTG_SS2_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0040)
+#define DRA7XX_CM_L3INIT_USB_OTG_SS3_CLKCTRL_OFFSET            0x0048
+#define DRA7XX_CM_L3INIT_USB_OTG_SS3_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0048)
+#define DRA7XX_CM_L3INIT_USB_OTG_SS4_CLKCTRL_OFFSET            0x0050
+#define DRA7XX_CM_L3INIT_USB_OTG_SS4_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0050)
+#define DRA7XX_CM_L3INIT_MLB_SS_CLKCTRL_OFFSET                 0x0058
+#define DRA7XX_CM_L3INIT_MLB_SS_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0058)
+#define DRA7XX_CM_L3INIT_IEEE1500_2_OCP_CLKCTRL_OFFSET         0x0078
+#define DRA7XX_CM_L3INIT_IEEE1500_2_OCP_CLKCTRL                        DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0078)
+#define DRA7XX_CM_L3INIT_SATA_CLKCTRL_OFFSET                   0x0088
+#define DRA7XX_CM_L3INIT_SATA_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x0088)
+#define DRA7XX_CM_PCIE_CLKSTCTRL_OFFSET                                0x00a0
+#define DRA7XX_CM_PCIE_STATICDEP_OFFSET                                0x00a4
+#define DRA7XX_CM_GMAC_CLKSTCTRL_OFFSET                                0x00c0
+#define DRA7XX_CM_GMAC_STATICDEP_OFFSET                                0x00c4
+#define DRA7XX_CM_GMAC_DYNAMICDEP_OFFSET                       0x00c8
+#define DRA7XX_CM_GMAC_GMAC_CLKCTRL_OFFSET                     0x00d0
+#define DRA7XX_CM_GMAC_GMAC_CLKCTRL                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x00d0)
+#define DRA7XX_CM_L3INIT_OCP2SCP1_CLKCTRL_OFFSET               0x00e0
+#define DRA7XX_CM_L3INIT_OCP2SCP1_CLKCTRL                      DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x00e0)
+#define DRA7XX_CM_L3INIT_OCP2SCP3_CLKCTRL_OFFSET               0x00e8
+#define DRA7XX_CM_L3INIT_OCP2SCP3_CLKCTRL                      DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x00e8)
+#define DRA7XX_CM_L3INIT_USB_OTG_SS1_CLKCTRL_OFFSET            0x00f0
+#define DRA7XX_CM_L3INIT_USB_OTG_SS1_CLKCTRL                   DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L3INIT_INST, 0x00f0)
+
+/* CM_CORE.CUSTEFUSE_CM_CORE register offsets */
+#define DRA7XX_CM_CUSTEFUSE_CLKSTCTRL_OFFSET                   0x0000
+#define DRA7XX_CM_CUSTEFUSE_EFUSE_CTRL_CUST_CLKCTRL_OFFSET     0x0020
+#define DRA7XX_CM_CUSTEFUSE_EFUSE_CTRL_CUST_CLKCTRL            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_CUSTEFUSE_INST, 0x0020)
+
+/* CM_CORE.L4PER_CM_CORE register offsets */
+#define DRA7XX_CM_L4PER_CLKSTCTRL_OFFSET                       0x0000
+#define DRA7XX_CM_L4PER_DYNAMICDEP_OFFSET                      0x0008
+#define DRA7XX_CM_L4PER2_L4_PER2_CLKCTRL_OFFSET                        0x000c
+#define DRA7XX_CM_L4PER2_L4_PER2_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x000c)
+#define DRA7XX_CM_L4PER3_L4_PER3_CLKCTRL_OFFSET                        0x0014
+#define DRA7XX_CM_L4PER3_L4_PER3_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0014)
+#define DRA7XX_CM_L4PER2_PRUSS1_CLKCTRL_OFFSET                 0x0018
+#define DRA7XX_CM_L4PER2_PRUSS1_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0018)
+#define DRA7XX_CM_L4PER2_PRUSS2_CLKCTRL_OFFSET                 0x0020
+#define DRA7XX_CM_L4PER2_PRUSS2_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0020)
+#define DRA7XX_CM_L4PER_TIMER10_CLKCTRL_OFFSET                 0x0028
+#define DRA7XX_CM_L4PER_TIMER10_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0028)
+#define DRA7XX_CM_L4PER_TIMER11_CLKCTRL_OFFSET                 0x0030
+#define DRA7XX_CM_L4PER_TIMER11_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0030)
+#define DRA7XX_CM_L4PER_TIMER2_CLKCTRL_OFFSET                  0x0038
+#define DRA7XX_CM_L4PER_TIMER2_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0038)
+#define DRA7XX_CM_L4PER_TIMER3_CLKCTRL_OFFSET                  0x0040
+#define DRA7XX_CM_L4PER_TIMER3_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0040)
+#define DRA7XX_CM_L4PER_TIMER4_CLKCTRL_OFFSET                  0x0048
+#define DRA7XX_CM_L4PER_TIMER4_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0048)
+#define DRA7XX_CM_L4PER_TIMER9_CLKCTRL_OFFSET                  0x0050
+#define DRA7XX_CM_L4PER_TIMER9_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0050)
+#define DRA7XX_CM_L4PER_ELM_CLKCTRL_OFFSET                     0x0058
+#define DRA7XX_CM_L4PER_ELM_CLKCTRL                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0058)
+#define DRA7XX_CM_L4PER_GPIO2_CLKCTRL_OFFSET                   0x0060
+#define DRA7XX_CM_L4PER_GPIO2_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0060)
+#define DRA7XX_CM_L4PER_GPIO3_CLKCTRL_OFFSET                   0x0068
+#define DRA7XX_CM_L4PER_GPIO3_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0068)
+#define DRA7XX_CM_L4PER_GPIO4_CLKCTRL_OFFSET                   0x0070
+#define DRA7XX_CM_L4PER_GPIO4_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0070)
+#define DRA7XX_CM_L4PER_GPIO5_CLKCTRL_OFFSET                   0x0078
+#define DRA7XX_CM_L4PER_GPIO5_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0078)
+#define DRA7XX_CM_L4PER_GPIO6_CLKCTRL_OFFSET                   0x0080
+#define DRA7XX_CM_L4PER_GPIO6_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0080)
+#define DRA7XX_CM_L4PER_HDQ1W_CLKCTRL_OFFSET                   0x0088
+#define DRA7XX_CM_L4PER_HDQ1W_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0088)
+#define DRA7XX_CM_L4PER2_PWMSS2_CLKCTRL_OFFSET                 0x0090
+#define DRA7XX_CM_L4PER2_PWMSS2_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0090)
+#define DRA7XX_CM_L4PER2_PWMSS3_CLKCTRL_OFFSET                 0x0098
+#define DRA7XX_CM_L4PER2_PWMSS3_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0098)
+#define DRA7XX_CM_L4PER_I2C1_CLKCTRL_OFFSET                    0x00a0
+#define DRA7XX_CM_L4PER_I2C1_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00a0)
+#define DRA7XX_CM_L4PER_I2C2_CLKCTRL_OFFSET                    0x00a8
+#define DRA7XX_CM_L4PER_I2C2_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00a8)
+#define DRA7XX_CM_L4PER_I2C3_CLKCTRL_OFFSET                    0x00b0
+#define DRA7XX_CM_L4PER_I2C3_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00b0)
+#define DRA7XX_CM_L4PER_I2C4_CLKCTRL_OFFSET                    0x00b8
+#define DRA7XX_CM_L4PER_I2C4_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00b8)
+#define DRA7XX_CM_L4PER_L4_PER1_CLKCTRL_OFFSET                 0x00c0
+#define DRA7XX_CM_L4PER_L4_PER1_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00c0)
+#define DRA7XX_CM_L4PER2_PWMSS1_CLKCTRL_OFFSET                 0x00c4
+#define DRA7XX_CM_L4PER2_PWMSS1_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00c4)
+#define DRA7XX_CM_L4PER3_TIMER13_CLKCTRL_OFFSET                        0x00c8
+#define DRA7XX_CM_L4PER3_TIMER13_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00c8)
+#define DRA7XX_CM_L4PER3_TIMER14_CLKCTRL_OFFSET                        0x00d0
+#define DRA7XX_CM_L4PER3_TIMER14_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00d0)
+#define DRA7XX_CM_L4PER3_TIMER15_CLKCTRL_OFFSET                        0x00d8
+#define DRA7XX_CM_L4PER3_TIMER15_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00d8)
+#define DRA7XX_CM_L4PER_MCSPI1_CLKCTRL_OFFSET                  0x00f0
+#define DRA7XX_CM_L4PER_MCSPI1_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00f0)
+#define DRA7XX_CM_L4PER_MCSPI2_CLKCTRL_OFFSET                  0x00f8
+#define DRA7XX_CM_L4PER_MCSPI2_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x00f8)
+#define DRA7XX_CM_L4PER_MCSPI3_CLKCTRL_OFFSET                  0x0100
+#define DRA7XX_CM_L4PER_MCSPI3_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0100)
+#define DRA7XX_CM_L4PER_MCSPI4_CLKCTRL_OFFSET                  0x0108
+#define DRA7XX_CM_L4PER_MCSPI4_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0108)
+#define DRA7XX_CM_L4PER_GPIO7_CLKCTRL_OFFSET                   0x0110
+#define DRA7XX_CM_L4PER_GPIO7_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0110)
+#define DRA7XX_CM_L4PER_GPIO8_CLKCTRL_OFFSET                   0x0118
+#define DRA7XX_CM_L4PER_GPIO8_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0118)
+#define DRA7XX_CM_L4PER_MMC3_CLKCTRL_OFFSET                    0x0120
+#define DRA7XX_CM_L4PER_MMC3_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0120)
+#define DRA7XX_CM_L4PER_MMC4_CLKCTRL_OFFSET                    0x0128
+#define DRA7XX_CM_L4PER_MMC4_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0128)
+#define DRA7XX_CM_L4PER3_TIMER16_CLKCTRL_OFFSET                        0x0130
+#define DRA7XX_CM_L4PER3_TIMER16_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0130)
+#define DRA7XX_CM_L4PER2_QSPI_CLKCTRL_OFFSET                   0x0138
+#define DRA7XX_CM_L4PER2_QSPI_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0138)
+#define DRA7XX_CM_L4PER_UART1_CLKCTRL_OFFSET                   0x0140
+#define DRA7XX_CM_L4PER_UART1_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0140)
+#define DRA7XX_CM_L4PER_UART2_CLKCTRL_OFFSET                   0x0148
+#define DRA7XX_CM_L4PER_UART2_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0148)
+#define DRA7XX_CM_L4PER_UART3_CLKCTRL_OFFSET                   0x0150
+#define DRA7XX_CM_L4PER_UART3_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0150)
+#define DRA7XX_CM_L4PER_UART4_CLKCTRL_OFFSET                   0x0158
+#define DRA7XX_CM_L4PER_UART4_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0158)
+#define DRA7XX_CM_L4PER2_MCASP2_CLKCTRL_OFFSET                 0x0160
+#define DRA7XX_CM_L4PER2_MCASP2_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0160)
+#define DRA7XX_CM_L4PER2_MCASP3_CLKCTRL_OFFSET                 0x0168
+#define DRA7XX_CM_L4PER2_MCASP3_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0168)
+#define DRA7XX_CM_L4PER_UART5_CLKCTRL_OFFSET                   0x0170
+#define DRA7XX_CM_L4PER_UART5_CLKCTRL                          DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0170)
+#define DRA7XX_CM_L4PER2_MCASP5_CLKCTRL_OFFSET                 0x0178
+#define DRA7XX_CM_L4PER2_MCASP5_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0178)
+#define DRA7XX_CM_L4SEC_CLKSTCTRL_OFFSET                       0x0180
+#define DRA7XX_CM_L4SEC_STATICDEP_OFFSET                       0x0184
+#define DRA7XX_CM_L4SEC_DYNAMICDEP_OFFSET                      0x0188
+#define DRA7XX_CM_L4PER2_MCASP8_CLKCTRL_OFFSET                 0x0190
+#define DRA7XX_CM_L4PER2_MCASP8_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0190)
+#define DRA7XX_CM_L4PER2_MCASP4_CLKCTRL_OFFSET                 0x0198
+#define DRA7XX_CM_L4PER2_MCASP4_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0198)
+#define DRA7XX_CM_L4SEC_AES1_CLKCTRL_OFFSET                    0x01a0
+#define DRA7XX_CM_L4SEC_AES1_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01a0)
+#define DRA7XX_CM_L4SEC_AES2_CLKCTRL_OFFSET                    0x01a8
+#define DRA7XX_CM_L4SEC_AES2_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01a8)
+#define DRA7XX_CM_L4SEC_DES3DES_CLKCTRL_OFFSET                 0x01b0
+#define DRA7XX_CM_L4SEC_DES3DES_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01b0)
+#define DRA7XX_CM_L4SEC_FPKA_CLKCTRL_OFFSET                    0x01b8
+#define DRA7XX_CM_L4SEC_FPKA_CLKCTRL                           DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01b8)
+#define DRA7XX_CM_L4SEC_RNG_CLKCTRL_OFFSET                     0x01c0
+#define DRA7XX_CM_L4SEC_RNG_CLKCTRL                            DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01c0)
+#define DRA7XX_CM_L4SEC_SHA2MD51_CLKCTRL_OFFSET                        0x01c8
+#define DRA7XX_CM_L4SEC_SHA2MD51_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01c8)
+#define DRA7XX_CM_L4PER2_UART7_CLKCTRL_OFFSET                  0x01d0
+#define DRA7XX_CM_L4PER2_UART7_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01d0)
+#define DRA7XX_CM_L4SEC_DMA_CRYPTO_CLKCTRL_OFFSET              0x01d8
+#define DRA7XX_CM_L4SEC_DMA_CRYPTO_CLKCTRL                     DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01d8)
+#define DRA7XX_CM_L4PER2_UART8_CLKCTRL_OFFSET                  0x01e0
+#define DRA7XX_CM_L4PER2_UART8_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01e0)
+#define DRA7XX_CM_L4PER2_UART9_CLKCTRL_OFFSET                  0x01e8
+#define DRA7XX_CM_L4PER2_UART9_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01e8)
+#define DRA7XX_CM_L4PER2_DCAN2_CLKCTRL_OFFSET                  0x01f0
+#define DRA7XX_CM_L4PER2_DCAN2_CLKCTRL                         DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01f0)
+#define DRA7XX_CM_L4SEC_SHA2MD52_CLKCTRL_OFFSET                        0x01f8
+#define DRA7XX_CM_L4SEC_SHA2MD52_CLKCTRL                       DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x01f8)
+#define DRA7XX_CM_L4PER2_CLKSTCTRL_OFFSET                      0x01fc
+#define DRA7XX_CM_L4PER2_DYNAMICDEP_OFFSET                     0x0200
+#define DRA7XX_CM_L4PER2_MCASP6_CLKCTRL_OFFSET                 0x0204
+#define DRA7XX_CM_L4PER2_MCASP6_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0204)
+#define DRA7XX_CM_L4PER2_MCASP7_CLKCTRL_OFFSET                 0x0208
+#define DRA7XX_CM_L4PER2_MCASP7_CLKCTRL                                DRA7XX_CM_CORE_REGADDR(DRA7XX_CM_CORE_L4PER_INST, 0x0208)
+#define DRA7XX_CM_L4PER2_STATICDEP_OFFSET                      0x020c
+#define DRA7XX_CM_L4PER3_CLKSTCTRL_OFFSET                      0x0210
+#define DRA7XX_CM_L4PER3_DYNAMICDEP_OFFSET                     0x0214
+
+#endif
index 3656b8009a1cd0bb4c09f8a64def5180a6099965..ff2113ce40141ab87001c912b3924fe1803cdec3 100644 (file)
@@ -665,6 +665,11 @@ void __init dra7xx_init_early(void)
        omap2_set_globals_prcm_mpu(OMAP2_L4_IO_ADDRESS(OMAP54XX_PRCM_MPU_BASE));
        omap_prm_base_init();
        omap_cm_base_init();
+       omap44xx_prm_init();
+       dra7xx_powerdomains_init();
+       dra7xx_clockdomains_init();
+       dra7xx_hwmod_init();
+       omap_hwmod_init_postsetup();
 }
 #endif
 
index b4ecd2c7db8e87d52dd7047a45049a3f2e033519..d9ee0ff094d4bcfdd395131601664be618367073 100644 (file)
@@ -1405,7 +1405,9 @@ static void _enable_sysc(struct omap_hwmod *oh)
            (sf & SYSC_HAS_CLOCKACTIVITY))
                _set_clockactivity(oh, oh->class->sysc->clockact, &v);
 
-       _write_sysconfig(v, oh);
+       /* If the cached value is the same as the new value, skip the write */
+       if (oh->_sysc_cache != v)
+               _write_sysconfig(v, oh);
 
        /*
         * Set the autoidle bit only after setting the smartidle bit
index e1482a9b3bc22f7cd7de82ac9f66474e1efbccc8..d02acf9308d3acc7deb06a42a830323774097572 100644 (file)
@@ -751,6 +751,7 @@ extern int omap3xxx_hwmod_init(void);
 extern int omap44xx_hwmod_init(void);
 extern int omap54xx_hwmod_init(void);
 extern int am33xx_hwmod_init(void);
+extern int dra7xx_hwmod_init(void);
 
 extern int __init omap_hwmod_register_links(struct omap_hwmod_ocp_if **ois);
 
index eb2f3b93b51c9a4d7ce32eed8f23d63cb3083d33..215894f8910d407d30eac10f23b22ee0ee003fb1 100644 (file)
@@ -325,7 +325,6 @@ static struct omap_hwmod am33xx_adc_tsc_hwmod = {
  *
  *    - cEFUSE (doesn't fall under any ocp_if)
  *    - clkdiv32k
- *    - debugss
  *    - ocp watch point
  */
 #if 0
@@ -369,27 +368,6 @@ static struct omap_hwmod am33xx_clkdiv32k_hwmod = {
        },
 };
 
-/*
- * 'debugss' class
- * debug sub system
- */
-static struct omap_hwmod_class am33xx_debugss_hwmod_class = {
-       .name           = "debugss",
-};
-
-static struct omap_hwmod am33xx_debugss_hwmod = {
-       .name           = "debugss",
-       .class          = &am33xx_debugss_hwmod_class,
-       .clkdm_name     = "l3_aon_clkdm",
-       .main_clk       = "debugss_ick",
-       .prcm           = {
-               .omap4  = {
-                       .clkctrl_offs   = AM33XX_CM_WKUP_DEBUGSS_CLKCTRL_OFFSET,
-                       .modulemode     = MODULEMODE_SWCTRL,
-               },
-       },
-};
-
 /* ocpwp */
 static struct omap_hwmod_class am33xx_ocpwp_hwmod_class = {
        .name           = "ocpwp",
@@ -482,6 +460,34 @@ static struct omap_hwmod am33xx_ocmcram_hwmod = {
        },
 };
 
+/*
+ * 'debugss' class
+ * debug sub system
+ */
+static struct omap_hwmod_opt_clk debugss_opt_clks[] = {
+       { .role = "dbg_sysclk", .clk = "dbg_sysclk_ck" },
+       { .role = "dbg_clka", .clk = "dbg_clka_ck" },
+};
+
+static struct omap_hwmod_class am33xx_debugss_hwmod_class = {
+       .name           = "debugss",
+};
+
+static struct omap_hwmod am33xx_debugss_hwmod = {
+       .name           = "debugss",
+       .class          = &am33xx_debugss_hwmod_class,
+       .clkdm_name     = "l3_aon_clkdm",
+       .main_clk       = "trace_clk_div_ck",
+       .prcm           = {
+               .omap4  = {
+                       .clkctrl_offs   = AM33XX_CM_WKUP_DEBUGSS_CLKCTRL_OFFSET,
+                       .modulemode     = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = debugss_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(debugss_opt_clks),
+};
+
 /* 'smartreflex' class */
 static struct omap_hwmod_class am33xx_smartreflex_hwmod_class = {
        .name           = "smartreflex",
@@ -1796,6 +1802,24 @@ static struct omap_hwmod_ocp_if am33xx_l3_main__gfx = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* l3_main -> debugss */
+static struct omap_hwmod_addr_space am33xx_debugss_addrs[] = {
+       {
+               .pa_start       = 0x4b000000,
+               .pa_end         = 0x4b000000 + SZ_16M - 1,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+static struct omap_hwmod_ocp_if am33xx_l3_main__debugss = {
+       .master         = &am33xx_l3_main_hwmod,
+       .slave          = &am33xx_debugss_hwmod,
+       .clk            = "dpll_core_m4_ck",
+       .addr           = am33xx_debugss_addrs,
+       .user           = OCP_USER_MPU,
+};
+
 /* l4 wkup -> smartreflex0 */
 static struct omap_hwmod_ocp_if am33xx_l4_wkup__smartreflex0 = {
        .master         = &am33xx_l4_wkup_hwmod,
@@ -2470,6 +2494,7 @@ static struct omap_hwmod_ocp_if *am33xx_hwmod_ocp_ifs[] __initdata = {
        &am33xx_pruss__l3_main,
        &am33xx_wkup_m3__l4_wkup,
        &am33xx_gfx__l3_main,
+       &am33xx_l3_main__debugss,
        &am33xx_l4_wkup__wkup_m3,
        &am33xx_l4_wkup__control,
        &am33xx_l4_wkup__smartreflex0,
index b4d04748576b1bceabea86fc7a84b9cdeaf04fac..cde415570e0465caffebba3b4edbac1976cf92ed 100644 (file)
@@ -739,6 +739,39 @@ static struct omap_hwmod omap54xx_kbd_hwmod = {
        },
 };
 
+/*
+ * 'mailbox' class
+ * mailbox module allowing communication between the on-chip processors using a
+ * queued mailbox-interrupt mechanism.
+ */
+
+static struct omap_hwmod_class_sysconfig omap54xx_mailbox_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class omap54xx_mailbox_hwmod_class = {
+       .name   = "mailbox",
+       .sysc   = &omap54xx_mailbox_sysc,
+};
+
+/* mailbox */
+static struct omap_hwmod omap54xx_mailbox_hwmod = {
+       .name           = "mailbox",
+       .class          = &omap54xx_mailbox_hwmod_class,
+       .clkdm_name     = "l4cfg_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = OMAP54XX_CM_L4CFG_MAILBOX_CLKCTRL_OFFSET,
+                       .context_offs = OMAP54XX_RM_L4CFG_MAILBOX_CONTEXT_OFFSET,
+               },
+       },
+};
+
 /*
  * 'mcbsp' class
  * multi channel buffered serial port controller
@@ -1807,6 +1840,14 @@ static struct omap_hwmod_ocp_if omap54xx_l4_wkup__kbd = {
        .user           = OCP_USER_MPU | OCP_USER_SDMA,
 };
 
+/* l4_cfg -> mailbox */
+static struct omap_hwmod_ocp_if omap54xx_l4_cfg__mailbox = {
+       .master         = &omap54xx_l4_cfg_hwmod,
+       .slave          = &omap54xx_mailbox_hwmod,
+       .clk            = "l4_root_clk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
 /* l4_abe -> mcbsp1 */
 static struct omap_hwmod_ocp_if omap54xx_l4_abe__mcbsp1 = {
        .master         = &omap54xx_l4_abe_hwmod,
@@ -2107,6 +2148,7 @@ static struct omap_hwmod_ocp_if *omap54xx_hwmod_ocp_ifs[] __initdata = {
        &omap54xx_l4_per__i2c4,
        &omap54xx_l4_per__i2c5,
        &omap54xx_l4_wkup__kbd,
+       &omap54xx_l4_cfg__mailbox,
        &omap54xx_l4_abe__mcbsp1,
        &omap54xx_l4_abe__mcbsp2,
        &omap54xx_l4_abe__mcbsp3,
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
new file mode 100644 (file)
index 0000000..db32d53
--- /dev/null
@@ -0,0 +1,2724 @@
+/*
+ * Hardware modules present on the DRA7xx chips
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Paul Walmsley
+ * Benoit Cousson
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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/platform_data/gpio-omap.h>
+#include <linux/power/smartreflex.h>
+#include <linux/i2c-omap.h>
+
+#include <linux/omap-dma.h>
+#include <linux/platform_data/spi-omap2-mcspi.h>
+#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <plat/dmtimer.h>
+
+#include "omap_hwmod.h"
+#include "omap_hwmod_common_data.h"
+#include "cm1_7xx.h"
+#include "cm2_7xx.h"
+#include "prm7xx.h"
+#include "i2c.h"
+#include "mmc.h"
+#include "wd_timer.h"
+
+/* Base offset for all DRA7XX interrupts external to MPUSS */
+#define DRA7XX_IRQ_GIC_START   32
+
+/* Base offset for all DRA7XX dma requests */
+#define DRA7XX_DMA_REQ_START   1
+
+
+/*
+ * IP blocks
+ */
+
+/*
+ * 'l3' class
+ * instance(s): l3_instr, l3_main_1, l3_main_2
+ */
+static struct omap_hwmod_class dra7xx_l3_hwmod_class = {
+       .name   = "l3",
+};
+
+/* l3_instr */
+static struct omap_hwmod dra7xx_l3_instr_hwmod = {
+       .name           = "l3_instr",
+       .class          = &dra7xx_l3_hwmod_class,
+       .clkdm_name     = "l3instr_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INSTR_L3_INSTR_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+};
+
+/* l3_main_1 */
+static struct omap_hwmod dra7xx_l3_main_1_hwmod = {
+       .name           = "l3_main_1",
+       .class          = &dra7xx_l3_hwmod_class,
+       .clkdm_name     = "l3main1_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3MAIN1_L3_MAIN_1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3MAIN1_L3_MAIN_1_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/* l3_main_2 */
+static struct omap_hwmod dra7xx_l3_main_2_hwmod = {
+       .name           = "l3_main_2",
+       .class          = &dra7xx_l3_hwmod_class,
+       .clkdm_name     = "l3instr_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INSTR_L3_MAIN_2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INSTR_L3_MAIN_2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+};
+
+/*
+ * 'l4' class
+ * instance(s): l4_cfg, l4_per1, l4_per2, l4_per3, l4_wkup
+ */
+static struct omap_hwmod_class dra7xx_l4_hwmod_class = {
+       .name   = "l4",
+};
+
+/* l4_cfg */
+static struct omap_hwmod dra7xx_l4_cfg_hwmod = {
+       .name           = "l4_cfg",
+       .class          = &dra7xx_l4_hwmod_class,
+       .clkdm_name     = "l4cfg_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4CFG_L4_CFG_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4CFG_L4_CFG_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/* l4_per1 */
+static struct omap_hwmod dra7xx_l4_per1_hwmod = {
+       .name           = "l4_per1",
+       .class          = &dra7xx_l4_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_L4_PER1_CLKCTRL_OFFSET,
+                       .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
+               },
+       },
+};
+
+/* l4_per2 */
+static struct omap_hwmod dra7xx_l4_per2_hwmod = {
+       .name           = "l4_per2",
+       .class          = &dra7xx_l4_hwmod_class,
+       .clkdm_name     = "l4per2_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER2_L4_PER2_CLKCTRL_OFFSET,
+                       .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
+               },
+       },
+};
+
+/* l4_per3 */
+static struct omap_hwmod dra7xx_l4_per3_hwmod = {
+       .name           = "l4_per3",
+       .class          = &dra7xx_l4_hwmod_class,
+       .clkdm_name     = "l4per3_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER3_L4_PER3_CLKCTRL_OFFSET,
+                       .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
+               },
+       },
+};
+
+/* l4_wkup */
+static struct omap_hwmod dra7xx_l4_wkup_hwmod = {
+       .name           = "l4_wkup",
+       .class          = &dra7xx_l4_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_WKUPAON_L4_WKUP_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_WKUPAON_L4_WKUP_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/*
+ * 'atl' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_atl_hwmod_class = {
+       .name   = "atl",
+};
+
+/* atl */
+static struct omap_hwmod dra7xx_atl_hwmod = {
+       .name           = "atl",
+       .class          = &dra7xx_atl_hwmod_class,
+       .clkdm_name     = "atl_clkdm",
+       .main_clk       = "atl_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_ATL_ATL_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_ATL_ATL_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'bb2d' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_bb2d_hwmod_class = {
+       .name   = "bb2d",
+};
+
+/* bb2d */
+static struct omap_hwmod dra7xx_bb2d_hwmod = {
+       .name           = "bb2d",
+       .class          = &dra7xx_bb2d_hwmod_class,
+       .clkdm_name     = "dss_clkdm",
+       .main_clk       = "dpll_core_h24x2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_DSS_BB2D_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_DSS_BB2D_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'counter' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_counter_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = SYSC_HAS_SIDLEMODE,
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_counter_hwmod_class = {
+       .name   = "counter",
+       .sysc   = &dra7xx_counter_sysc,
+};
+
+/* counter_32k */
+static struct omap_hwmod dra7xx_counter_32k_hwmod = {
+       .name           = "counter_32k",
+       .class          = &dra7xx_counter_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .flags          = HWMOD_SWSUP_SIDLE,
+       .main_clk       = "wkupaon_iclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_WKUPAON_COUNTER_32K_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_WKUPAON_COUNTER_32K_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/*
+ * 'ctrl_module' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_ctrl_module_hwmod_class = {
+       .name   = "ctrl_module",
+};
+
+/* ctrl_module_wkup */
+static struct omap_hwmod dra7xx_ctrl_module_wkup_hwmod = {
+       .name           = "ctrl_module_wkup",
+       .class          = &dra7xx_ctrl_module_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .prcm = {
+               .omap4 = {
+                       .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
+               },
+       },
+};
+
+/*
+ * 'dcan' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_dcan_hwmod_class = {
+       .name   = "dcan",
+};
+
+/* dcan1 */
+static struct omap_hwmod dra7xx_dcan1_hwmod = {
+       .name           = "dcan1",
+       .class          = &dra7xx_dcan_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .main_clk       = "dcan1_sys_clk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_WKUPAON_DCAN1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_WKUPAON_DCAN1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* dcan2 */
+static struct omap_hwmod dra7xx_dcan2_hwmod = {
+       .name           = "dcan2",
+       .class          = &dra7xx_dcan_hwmod_class,
+       .clkdm_name     = "l4per2_clkdm",
+       .main_clk       = "sys_clkin1",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER2_DCAN2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER2_DCAN2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'dma' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_dma_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x002c,
+       .syss_offs      = 0x0028,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+                          SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+                          MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_dma_hwmod_class = {
+       .name   = "dma",
+       .sysc   = &dra7xx_dma_sysc,
+};
+
+/* dma dev_attr */
+static struct omap_dma_dev_attr dma_dev_attr = {
+       .dev_caps       = RESERVE_CHANNEL | DMA_LINKED_LCH | GLOBAL_PRIORITY |
+                         IS_CSSA_32 | IS_CDSA_32 | IS_RW_PRIORITY,
+       .lch_count      = 32,
+};
+
+/* dma_system */
+static struct omap_hwmod_irq_info dra7xx_dma_system_irqs[] = {
+       { .name = "0", .irq = 12 + DRA7XX_IRQ_GIC_START },
+       { .name = "1", .irq = 13 + DRA7XX_IRQ_GIC_START },
+       { .name = "2", .irq = 14 + DRA7XX_IRQ_GIC_START },
+       { .name = "3", .irq = 15 + DRA7XX_IRQ_GIC_START },
+       { .irq = -1 }
+};
+
+static struct omap_hwmod dra7xx_dma_system_hwmod = {
+       .name           = "dma_system",
+       .class          = &dra7xx_dma_hwmod_class,
+       .clkdm_name     = "dma_clkdm",
+       .mpu_irqs       = dra7xx_dma_system_irqs,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_DMA_DMA_SYSTEM_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_DMA_DMA_SYSTEM_CONTEXT_OFFSET,
+               },
+       },
+       .dev_attr       = &dma_dev_attr,
+};
+
+/*
+ * 'dss' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_dss_sysc = {
+       .rev_offs       = 0x0000,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = SYSS_HAS_RESET_STATUS,
+};
+
+static struct omap_hwmod_class dra7xx_dss_hwmod_class = {
+       .name   = "dss",
+       .sysc   = &dra7xx_dss_sysc,
+       .reset  = omap_dss_reset,
+};
+
+/* dss */
+static struct omap_hwmod_dma_info dra7xx_dss_sdma_reqs[] = {
+       { .dma_req = 75 + DRA7XX_DMA_REQ_START },
+       { .dma_req = -1 }
+};
+
+static struct omap_hwmod_opt_clk dss_opt_clks[] = {
+       { .role = "dss_clk", .clk = "dss_dss_clk" },
+       { .role = "hdmi_phy_clk", .clk = "dss_48mhz_clk" },
+       { .role = "32khz_clk", .clk = "dss_32khz_clk" },
+       { .role = "video2_clk", .clk = "dss_video2_clk" },
+       { .role = "video1_clk", .clk = "dss_video1_clk" },
+       { .role = "hdmi_clk", .clk = "dss_hdmi_clk" },
+};
+
+static struct omap_hwmod dra7xx_dss_hwmod = {
+       .name           = "dss_core",
+       .class          = &dra7xx_dss_hwmod_class,
+       .clkdm_name     = "dss_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .sdma_reqs      = dra7xx_dss_sdma_reqs,
+       .main_clk       = "dss_dss_clk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_DSS_DSS_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = dss_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(dss_opt_clks),
+};
+
+/*
+ * 'dispc' class
+ * display controller
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_dispc_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_MIDLEMODE |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          MSTANDBY_FORCE | MSTANDBY_NO | MSTANDBY_SMART),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_dispc_hwmod_class = {
+       .name   = "dispc",
+       .sysc   = &dra7xx_dispc_sysc,
+};
+
+/* dss_dispc */
+/* dss_dispc dev_attr */
+static struct omap_dss_dispc_dev_attr dss_dispc_dev_attr = {
+       .has_framedonetv_irq    = 1,
+       .manager_count          = 4,
+};
+
+static struct omap_hwmod dra7xx_dss_dispc_hwmod = {
+       .name           = "dss_dispc",
+       .class          = &dra7xx_dispc_hwmod_class,
+       .clkdm_name     = "dss_clkdm",
+       .main_clk       = "dss_dss_clk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
+               },
+       },
+       .dev_attr       = &dss_dispc_dev_attr,
+};
+
+/*
+ * 'hdmi' class
+ * hdmi controller
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_hdmi_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_hdmi_hwmod_class = {
+       .name   = "hdmi",
+       .sysc   = &dra7xx_hdmi_sysc,
+};
+
+/* dss_hdmi */
+
+static struct omap_hwmod_opt_clk dss_hdmi_opt_clks[] = {
+       { .role = "sys_clk", .clk = "dss_hdmi_clk" },
+};
+
+static struct omap_hwmod dra7xx_dss_hdmi_hwmod = {
+       .name           = "dss_hdmi",
+       .class          = &dra7xx_hdmi_hwmod_class,
+       .clkdm_name     = "dss_clkdm",
+       .main_clk       = "dss_48mhz_clk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_DSS_DSS_CLKCTRL_OFFSET,
+                       .flags = HWMOD_OMAP4_NO_CONTEXT_LOSS_BIT,
+               },
+       },
+       .opt_clks       = dss_hdmi_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(dss_hdmi_opt_clks),
+};
+
+/*
+ * 'elm' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_elm_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_elm_hwmod_class = {
+       .name   = "elm",
+       .sysc   = &dra7xx_elm_sysc,
+};
+
+/* elm */
+
+static struct omap_hwmod dra7xx_elm_hwmod = {
+       .name           = "elm",
+       .class          = &dra7xx_elm_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_ELM_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_ELM_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/*
+ * 'gpio' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_gpio_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0114,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_gpio_hwmod_class = {
+       .name   = "gpio",
+       .sysc   = &dra7xx_gpio_sysc,
+       .rev    = 2,
+};
+
+/* gpio dev_attr */
+static struct omap_gpio_dev_attr gpio_dev_attr = {
+       .bank_width     = 32,
+       .dbck_flag      = true,
+};
+
+/* gpio1 */
+static struct omap_hwmod_opt_clk gpio1_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio1_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio1_hwmod = {
+       .name           = "gpio1",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .main_clk       = "wkupaon_iclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_WKUPAON_GPIO1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_WKUPAON_GPIO1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio1_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio1_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio2 */
+static struct omap_hwmod_opt_clk gpio2_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio2_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio2_hwmod = {
+       .name           = "gpio2",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio2_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio2_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio3 */
+static struct omap_hwmod_opt_clk gpio3_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio3_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio3_hwmod = {
+       .name           = "gpio3",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio3_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio3_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio4 */
+static struct omap_hwmod_opt_clk gpio4_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio4_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio4_hwmod = {
+       .name           = "gpio4",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio4_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio4_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio5 */
+static struct omap_hwmod_opt_clk gpio5_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio5_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio5_hwmod = {
+       .name           = "gpio5",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO5_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio5_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio5_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio6 */
+static struct omap_hwmod_opt_clk gpio6_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio6_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio6_hwmod = {
+       .name           = "gpio6",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO6_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO6_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio6_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio6_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio7 */
+static struct omap_hwmod_opt_clk gpio7_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio7_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio7_hwmod = {
+       .name           = "gpio7",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO7_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO7_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio7_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio7_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/* gpio8 */
+static struct omap_hwmod_opt_clk gpio8_opt_clks[] = {
+       { .role = "dbclk", .clk = "gpio8_dbclk" },
+};
+
+static struct omap_hwmod dra7xx_gpio8_hwmod = {
+       .name           = "gpio8",
+       .class          = &dra7xx_gpio_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_CONTROL_OPT_CLKS_IN_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_GPIO8_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_GPIO8_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = gpio8_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(gpio8_opt_clks),
+       .dev_attr       = &gpio_dev_attr,
+};
+
+/*
+ * 'gpmc' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_gpmc_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_gpmc_hwmod_class = {
+       .name   = "gpmc",
+       .sysc   = &dra7xx_gpmc_sysc,
+};
+
+/* gpmc */
+
+static struct omap_hwmod dra7xx_gpmc_hwmod = {
+       .name           = "gpmc",
+       .class          = &dra7xx_gpmc_hwmod_class,
+       .clkdm_name     = "l3main1_clkdm",
+       .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3MAIN1_GPMC_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3MAIN1_GPMC_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+};
+
+/*
+ * 'hdq1w' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_hdq1w_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0014,
+       .syss_offs      = 0x0018,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_hdq1w_hwmod_class = {
+       .name   = "hdq1w",
+       .sysc   = &dra7xx_hdq1w_sysc,
+};
+
+/* hdq1w */
+
+static struct omap_hwmod dra7xx_hdq1w_hwmod = {
+       .name           = "hdq1w",
+       .class          = &dra7xx_hdq1w_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_INIT_NO_RESET,
+       .main_clk       = "func_12m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_HDQ1W_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_HDQ1W_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'i2c' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_i2c_sysc = {
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0090,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .clockact       = CLOCKACT_TEST_ICLK,
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_i2c_hwmod_class = {
+       .name   = "i2c",
+       .sysc   = &dra7xx_i2c_sysc,
+       .reset  = &omap_i2c_reset,
+       .rev    = OMAP_I2C_IP_VERSION_2,
+};
+
+/* i2c dev_attr */
+static struct omap_i2c_dev_attr i2c_dev_attr = {
+       .flags  = OMAP_I2C_FLAG_BUS_SHIFT_NONE,
+};
+
+/* i2c1 */
+static struct omap_hwmod dra7xx_i2c1_hwmod = {
+       .name           = "i2c1",
+       .class          = &dra7xx_i2c_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+       .main_clk       = "func_96m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_I2C1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &i2c_dev_attr,
+};
+
+/* i2c2 */
+static struct omap_hwmod dra7xx_i2c2_hwmod = {
+       .name           = "i2c2",
+       .class          = &dra7xx_i2c_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+       .main_clk       = "func_96m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_I2C2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &i2c_dev_attr,
+};
+
+/* i2c3 */
+static struct omap_hwmod dra7xx_i2c3_hwmod = {
+       .name           = "i2c3",
+       .class          = &dra7xx_i2c_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+       .main_clk       = "func_96m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_I2C3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &i2c_dev_attr,
+};
+
+/* i2c4 */
+static struct omap_hwmod dra7xx_i2c4_hwmod = {
+       .name           = "i2c4",
+       .class          = &dra7xx_i2c_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+       .main_clk       = "func_96m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_I2C4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_I2C4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &i2c_dev_attr,
+};
+
+/* i2c5 */
+static struct omap_hwmod dra7xx_i2c5_hwmod = {
+       .name           = "i2c5",
+       .class          = &dra7xx_i2c_hwmod_class,
+       .clkdm_name     = "ipu_clkdm",
+       .flags          = HWMOD_16BIT_REG | HWMOD_SET_DEFAULT_CLOCKACT,
+       .main_clk       = "func_96m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_IPU_I2C5_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_IPU_I2C5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &i2c_dev_attr,
+};
+
+/*
+ * 'mcspi' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_mcspi_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_mcspi_hwmod_class = {
+       .name   = "mcspi",
+       .sysc   = &dra7xx_mcspi_sysc,
+       .rev    = OMAP4_MCSPI_REV,
+};
+
+/* mcspi1 */
+/* mcspi1 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi1_dev_attr = {
+       .num_chipselect = 4,
+};
+
+static struct omap_hwmod dra7xx_mcspi1_hwmod = {
+       .name           = "mcspi1",
+       .class          = &dra7xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "func_48m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_MCSPI1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_MCSPI1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &mcspi1_dev_attr,
+};
+
+/* mcspi2 */
+/* mcspi2 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi2_dev_attr = {
+       .num_chipselect = 2,
+};
+
+static struct omap_hwmod dra7xx_mcspi2_hwmod = {
+       .name           = "mcspi2",
+       .class          = &dra7xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "func_48m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_MCSPI2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_MCSPI2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &mcspi2_dev_attr,
+};
+
+/* mcspi3 */
+/* mcspi3 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi3_dev_attr = {
+       .num_chipselect = 2,
+};
+
+static struct omap_hwmod dra7xx_mcspi3_hwmod = {
+       .name           = "mcspi3",
+       .class          = &dra7xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "func_48m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_MCSPI3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_MCSPI3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &mcspi3_dev_attr,
+};
+
+/* mcspi4 */
+/* mcspi4 dev_attr */
+static struct omap2_mcspi_dev_attr mcspi4_dev_attr = {
+       .num_chipselect = 1,
+};
+
+static struct omap_hwmod dra7xx_mcspi4_hwmod = {
+       .name           = "mcspi4",
+       .class          = &dra7xx_mcspi_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "func_48m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_MCSPI4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_MCSPI4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &mcspi4_dev_attr,
+};
+
+/*
+ * 'mmc' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_mmc_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_MIDLEMODE |
+                          SYSC_HAS_RESET_STATUS | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+                          MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_mmc_hwmod_class = {
+       .name   = "mmc",
+       .sysc   = &dra7xx_mmc_sysc,
+};
+
+/* mmc1 */
+static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
+       { .role = "clk32k", .clk = "mmc1_clk32k" },
+};
+
+/* mmc1 dev_attr */
+static struct omap_mmc_dev_attr mmc1_dev_attr = {
+       .flags  = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
+};
+
+static struct omap_hwmod dra7xx_mmc1_hwmod = {
+       .name           = "mmc1",
+       .class          = &dra7xx_mmc_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "mmc1_fclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_MMC1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_MMC1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = mmc1_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(mmc1_opt_clks),
+       .dev_attr       = &mmc1_dev_attr,
+};
+
+/* mmc2 */
+static struct omap_hwmod_opt_clk mmc2_opt_clks[] = {
+       { .role = "clk32k", .clk = "mmc2_clk32k" },
+};
+
+static struct omap_hwmod dra7xx_mmc2_hwmod = {
+       .name           = "mmc2",
+       .class          = &dra7xx_mmc_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "mmc2_fclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_MMC2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_MMC2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = mmc2_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(mmc2_opt_clks),
+};
+
+/* mmc3 */
+static struct omap_hwmod_opt_clk mmc3_opt_clks[] = {
+       { .role = "clk32k", .clk = "mmc3_clk32k" },
+};
+
+static struct omap_hwmod dra7xx_mmc3_hwmod = {
+       .name           = "mmc3",
+       .class          = &dra7xx_mmc_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "mmc3_gfclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_MMC3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_MMC3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = mmc3_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(mmc3_opt_clks),
+};
+
+/* mmc4 */
+static struct omap_hwmod_opt_clk mmc4_opt_clks[] = {
+       { .role = "clk32k", .clk = "mmc4_clk32k" },
+};
+
+static struct omap_hwmod dra7xx_mmc4_hwmod = {
+       .name           = "mmc4",
+       .class          = &dra7xx_mmc_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "mmc4_gfclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_MMC4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_MMC4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = mmc4_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(mmc4_opt_clks),
+};
+
+/*
+ * 'mpu' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_mpu_hwmod_class = {
+       .name   = "mpu",
+};
+
+/* mpu */
+static struct omap_hwmod dra7xx_mpu_hwmod = {
+       .name           = "mpu",
+       .class          = &dra7xx_mpu_hwmod_class,
+       .clkdm_name     = "mpu_clkdm",
+       .flags          = HWMOD_INIT_NO_IDLE | HWMOD_INIT_NO_RESET,
+       .main_clk       = "dpll_mpu_m2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_MPU_MPU_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_MPU_MPU_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/*
+ * 'ocp2scp' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_ocp2scp_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_ocp2scp_hwmod_class = {
+       .name   = "ocp2scp",
+       .sysc   = &dra7xx_ocp2scp_sysc,
+};
+
+/* ocp2scp1 */
+static struct omap_hwmod dra7xx_ocp2scp1_hwmod = {
+       .name           = "ocp2scp1",
+       .class          = &dra7xx_ocp2scp_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "l4_root_clk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_OCP2SCP1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_OCP2SCP1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+};
+
+/*
+ * 'qspi' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_qspi_sysc = {
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = SYSC_HAS_SIDLEMODE,
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_qspi_hwmod_class = {
+       .name   = "qspi",
+       .sysc   = &dra7xx_qspi_sysc,
+};
+
+/* qspi */
+static struct omap_hwmod dra7xx_qspi_hwmod = {
+       .name           = "qspi",
+       .class          = &dra7xx_qspi_hwmod_class,
+       .clkdm_name     = "l4per2_clkdm",
+       .main_clk       = "qspi_gfclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER2_QSPI_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER2_QSPI_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'sata' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_sata_sysc = {
+       .sysc_offs      = 0x0000,
+       .sysc_flags     = (SYSC_HAS_MIDLEMODE | SYSC_HAS_SIDLEMODE),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
+                          MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_sata_hwmod_class = {
+       .name   = "sata",
+       .sysc   = &dra7xx_sata_sysc,
+};
+
+/* sata */
+static struct omap_hwmod_opt_clk sata_opt_clks[] = {
+       { .role = "ref_clk", .clk = "sata_ref_clk" },
+};
+
+static struct omap_hwmod dra7xx_sata_hwmod = {
+       .name           = "sata",
+       .class          = &dra7xx_sata_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .flags          = HWMOD_SWSUP_SIDLE | HWMOD_SWSUP_MSTANDBY,
+       .main_clk       = "func_48m_fclk",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_SATA_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_SATA_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .opt_clks       = sata_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(sata_opt_clks),
+};
+
+/*
+ * 'smartreflex' class
+ *
+ */
+
+/* The IP is not compliant to type1 / type2 scheme */
+static struct omap_hwmod_sysc_fields omap_hwmod_sysc_type_smartreflex = {
+       .sidle_shift    = 24,
+       .enwkup_shift   = 26,
+};
+
+static struct omap_hwmod_class_sysconfig dra7xx_smartreflex_sysc = {
+       .sysc_offs      = 0x0038,
+       .sysc_flags     = (SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type_smartreflex,
+};
+
+static struct omap_hwmod_class dra7xx_smartreflex_hwmod_class = {
+       .name   = "smartreflex",
+       .sysc   = &dra7xx_smartreflex_sysc,
+       .rev    = 2,
+};
+
+/* smartreflex_core */
+/* smartreflex_core dev_attr */
+static struct omap_smartreflex_dev_attr smartreflex_core_dev_attr = {
+       .sensor_voltdm_name     = "core",
+};
+
+static struct omap_hwmod dra7xx_smartreflex_core_hwmod = {
+       .name           = "smartreflex_core",
+       .class          = &dra7xx_smartreflex_hwmod_class,
+       .clkdm_name     = "coreaon_clkdm",
+       .main_clk       = "wkupaon_iclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_COREAON_SMARTREFLEX_CORE_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_COREAON_SMARTREFLEX_CORE_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &smartreflex_core_dev_attr,
+};
+
+/* smartreflex_mpu */
+/* smartreflex_mpu dev_attr */
+static struct omap_smartreflex_dev_attr smartreflex_mpu_dev_attr = {
+       .sensor_voltdm_name     = "mpu",
+};
+
+static struct omap_hwmod dra7xx_smartreflex_mpu_hwmod = {
+       .name           = "smartreflex_mpu",
+       .class          = &dra7xx_smartreflex_hwmod_class,
+       .clkdm_name     = "coreaon_clkdm",
+       .main_clk       = "wkupaon_iclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_COREAON_SMARTREFLEX_MPU_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_COREAON_SMARTREFLEX_MPU_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+       .dev_attr       = &smartreflex_mpu_dev_attr,
+};
+
+/*
+ * 'spinlock' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_spinlock_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_CLOCKACTIVITY |
+                          SYSC_HAS_ENAWAKEUP | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_spinlock_hwmod_class = {
+       .name   = "spinlock",
+       .sysc   = &dra7xx_spinlock_sysc,
+};
+
+/* spinlock */
+static struct omap_hwmod dra7xx_spinlock_hwmod = {
+       .name           = "spinlock",
+       .class          = &dra7xx_spinlock_hwmod_class,
+       .clkdm_name     = "l4cfg_clkdm",
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4CFG_SPINLOCK_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4CFG_SPINLOCK_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/*
+ * 'timer' class
+ *
+ * This class contains several variants: ['timer_1ms', 'timer_secure',
+ * 'timer']
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_timer_1ms_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_timer_1ms_hwmod_class = {
+       .name   = "timer",
+       .sysc   = &dra7xx_timer_1ms_sysc,
+};
+
+static struct omap_hwmod_class_sysconfig dra7xx_timer_secure_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_timer_secure_hwmod_class = {
+       .name   = "timer",
+       .sysc   = &dra7xx_timer_secure_sysc,
+};
+
+static struct omap_hwmod_class_sysconfig dra7xx_timer_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_RESET_STATUS |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class dra7xx_timer_hwmod_class = {
+       .name   = "timer",
+       .sysc   = &dra7xx_timer_sysc,
+};
+
+/* timer1 */
+static struct omap_hwmod dra7xx_timer1_hwmod = {
+       .name           = "timer1",
+       .class          = &dra7xx_timer_1ms_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .main_clk       = "timer1_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_WKUPAON_TIMER1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_WKUPAON_TIMER1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer2 */
+static struct omap_hwmod dra7xx_timer2_hwmod = {
+       .name           = "timer2",
+       .class          = &dra7xx_timer_1ms_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "timer2_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_TIMER2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_TIMER2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer3 */
+static struct omap_hwmod dra7xx_timer3_hwmod = {
+       .name           = "timer3",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "timer3_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_TIMER3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_TIMER3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer4 */
+static struct omap_hwmod dra7xx_timer4_hwmod = {
+       .name           = "timer4",
+       .class          = &dra7xx_timer_secure_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "timer4_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_TIMER4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_TIMER4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer5 */
+static struct omap_hwmod dra7xx_timer5_hwmod = {
+       .name           = "timer5",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "ipu_clkdm",
+       .main_clk       = "timer5_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_IPU_TIMER5_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_IPU_TIMER5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer6 */
+static struct omap_hwmod dra7xx_timer6_hwmod = {
+       .name           = "timer6",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "ipu_clkdm",
+       .main_clk       = "timer6_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_IPU_TIMER6_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_IPU_TIMER6_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer7 */
+static struct omap_hwmod dra7xx_timer7_hwmod = {
+       .name           = "timer7",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "ipu_clkdm",
+       .main_clk       = "timer7_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_IPU_TIMER7_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_IPU_TIMER7_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer8 */
+static struct omap_hwmod dra7xx_timer8_hwmod = {
+       .name           = "timer8",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "ipu_clkdm",
+       .main_clk       = "timer8_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_IPU_TIMER8_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_IPU_TIMER8_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer9 */
+static struct omap_hwmod dra7xx_timer9_hwmod = {
+       .name           = "timer9",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "timer9_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_TIMER9_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_TIMER9_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer10 */
+static struct omap_hwmod dra7xx_timer10_hwmod = {
+       .name           = "timer10",
+       .class          = &dra7xx_timer_1ms_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "timer10_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_TIMER10_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_TIMER10_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* timer11 */
+static struct omap_hwmod dra7xx_timer11_hwmod = {
+       .name           = "timer11",
+       .class          = &dra7xx_timer_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "timer11_gfclk_mux",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_TIMER11_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_TIMER11_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'uart' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_uart_sysc = {
+       .rev_offs       = 0x0050,
+       .sysc_offs      = 0x0054,
+       .syss_offs      = 0x0058,
+       .sysc_flags     = (SYSC_HAS_AUTOIDLE | SYSC_HAS_ENAWAKEUP |
+                          SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
+                          SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_uart_hwmod_class = {
+       .name   = "uart",
+       .sysc   = &dra7xx_uart_sysc,
+};
+
+/* uart1 */
+static struct omap_hwmod dra7xx_uart1_hwmod = {
+       .name           = "uart1",
+       .class          = &dra7xx_uart_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "uart1_gfclk_mux",
+       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_UART1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_UART1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* uart2 */
+static struct omap_hwmod dra7xx_uart2_hwmod = {
+       .name           = "uart2",
+       .class          = &dra7xx_uart_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "uart2_gfclk_mux",
+       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_UART2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_UART2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* uart3 */
+static struct omap_hwmod dra7xx_uart3_hwmod = {
+       .name           = "uart3",
+       .class          = &dra7xx_uart_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "uart3_gfclk_mux",
+       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_UART3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_UART3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* uart4 */
+static struct omap_hwmod dra7xx_uart4_hwmod = {
+       .name           = "uart4",
+       .class          = &dra7xx_uart_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "uart4_gfclk_mux",
+       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_UART4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_UART4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* uart5 */
+static struct omap_hwmod dra7xx_uart5_hwmod = {
+       .name           = "uart5",
+       .class          = &dra7xx_uart_hwmod_class,
+       .clkdm_name     = "l4per_clkdm",
+       .main_clk       = "uart5_gfclk_mux",
+       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L4PER_UART5_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L4PER_UART5_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/* uart6 */
+static struct omap_hwmod dra7xx_uart6_hwmod = {
+       .name           = "uart6",
+       .class          = &dra7xx_uart_hwmod_class,
+       .clkdm_name     = "ipu_clkdm",
+       .main_clk       = "uart6_gfclk_mux",
+       .flags          = HWMOD_SWSUP_SIDLE_ACT,
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_IPU_UART6_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_IPU_UART6_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+/*
+ * 'usb_otg_ss' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_usb_otg_ss_hwmod_class = {
+       .name   = "usb_otg_ss",
+};
+
+/* usb_otg_ss1 */
+static struct omap_hwmod_opt_clk usb_otg_ss1_opt_clks[] = {
+       { .role = "refclk960m", .clk = "usb_otg_ss1_refclk960m" },
+};
+
+static struct omap_hwmod dra7xx_usb_otg_ss1_hwmod = {
+       .name           = "usb_otg_ss1",
+       .class          = &dra7xx_usb_otg_ss_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "dpll_core_h13x2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_USB_OTG_SS1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_USB_OTG_SS1_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = usb_otg_ss1_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(usb_otg_ss1_opt_clks),
+};
+
+/* usb_otg_ss2 */
+static struct omap_hwmod_opt_clk usb_otg_ss2_opt_clks[] = {
+       { .role = "refclk960m", .clk = "usb_otg_ss2_refclk960m" },
+};
+
+static struct omap_hwmod dra7xx_usb_otg_ss2_hwmod = {
+       .name           = "usb_otg_ss2",
+       .class          = &dra7xx_usb_otg_ss_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "dpll_core_h13x2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_USB_OTG_SS2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_USB_OTG_SS2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+       .opt_clks       = usb_otg_ss2_opt_clks,
+       .opt_clks_cnt   = ARRAY_SIZE(usb_otg_ss2_opt_clks),
+};
+
+/* usb_otg_ss3 */
+static struct omap_hwmod dra7xx_usb_otg_ss3_hwmod = {
+       .name           = "usb_otg_ss3",
+       .class          = &dra7xx_usb_otg_ss_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "dpll_core_h13x2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_USB_OTG_SS3_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_USB_OTG_SS3_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+};
+
+/* usb_otg_ss4 */
+static struct omap_hwmod dra7xx_usb_otg_ss4_hwmod = {
+       .name           = "usb_otg_ss4",
+       .class          = &dra7xx_usb_otg_ss_hwmod_class,
+       .clkdm_name     = "l3init_clkdm",
+       .main_clk       = "dpll_core_h13x2_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3INIT_USB_OTG_SS4_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3INIT_USB_OTG_SS4_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_HWCTRL,
+               },
+       },
+};
+
+/*
+ * 'vcp' class
+ *
+ */
+
+static struct omap_hwmod_class dra7xx_vcp_hwmod_class = {
+       .name   = "vcp",
+};
+
+/* vcp1 */
+static struct omap_hwmod dra7xx_vcp1_hwmod = {
+       .name           = "vcp1",
+       .class          = &dra7xx_vcp_hwmod_class,
+       .clkdm_name     = "l3main1_clkdm",
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3MAIN1_VCP1_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3MAIN1_VCP1_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/* vcp2 */
+static struct omap_hwmod dra7xx_vcp2_hwmod = {
+       .name           = "vcp2",
+       .class          = &dra7xx_vcp_hwmod_class,
+       .clkdm_name     = "l3main1_clkdm",
+       .main_clk       = "l3_iclk_div",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_L3MAIN1_VCP2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_L3MAIN1_VCP2_CONTEXT_OFFSET,
+               },
+       },
+};
+
+/*
+ * 'wd_timer' class
+ *
+ */
+
+static struct omap_hwmod_class_sysconfig dra7xx_wd_timer_sysc = {
+       .rev_offs       = 0x0000,
+       .sysc_offs      = 0x0010,
+       .syss_offs      = 0x0014,
+       .sysc_flags     = (SYSC_HAS_EMUFREE | SYSC_HAS_SIDLEMODE |
+                          SYSC_HAS_SOFTRESET | SYSS_HAS_RESET_STATUS),
+       .idlemodes      = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+                          SIDLE_SMART_WKUP),
+       .sysc_fields    = &omap_hwmod_sysc_type1,
+};
+
+static struct omap_hwmod_class dra7xx_wd_timer_hwmod_class = {
+       .name           = "wd_timer",
+       .sysc           = &dra7xx_wd_timer_sysc,
+       .pre_shutdown   = &omap2_wd_timer_disable,
+       .reset          = &omap2_wd_timer_reset,
+};
+
+/* wd_timer2 */
+static struct omap_hwmod dra7xx_wd_timer2_hwmod = {
+       .name           = "wd_timer2",
+       .class          = &dra7xx_wd_timer_hwmod_class,
+       .clkdm_name     = "wkupaon_clkdm",
+       .main_clk       = "sys_32k_ck",
+       .prcm = {
+               .omap4 = {
+                       .clkctrl_offs = DRA7XX_CM_WKUPAON_WD_TIMER2_CLKCTRL_OFFSET,
+                       .context_offs = DRA7XX_RM_WKUPAON_WD_TIMER2_CONTEXT_OFFSET,
+                       .modulemode   = MODULEMODE_SWCTRL,
+               },
+       },
+};
+
+
+/*
+ * Interfaces
+ */
+
+/* l3_main_2 -> l3_instr */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_2__l3_instr = {
+       .master         = &dra7xx_l3_main_2_hwmod,
+       .slave          = &dra7xx_l3_instr_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> l3_main_1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__l3_main_1 = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_l3_main_1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* mpu -> l3_main_1 */
+static struct omap_hwmod_ocp_if dra7xx_mpu__l3_main_1 = {
+       .master         = &dra7xx_mpu_hwmod,
+       .slave          = &dra7xx_l3_main_1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU,
+};
+
+/* l3_main_1 -> l3_main_2 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l3_main_2 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_l3_main_2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU,
+};
+
+/* l4_cfg -> l3_main_2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__l3_main_2 = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_l3_main_2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_cfg */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_cfg = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_l4_cfg_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_per1 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_per1 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_l4_per1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_per2 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_per2 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_l4_per2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_per3 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_per3 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_l4_per3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> l4_wkup */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__l4_wkup = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_l4_wkup_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per2 -> atl */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__atl = {
+       .master         = &dra7xx_l4_per2_hwmod,
+       .slave          = &dra7xx_atl_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> bb2d */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__bb2d = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_bb2d_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> counter_32k */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__counter_32k = {
+       .master         = &dra7xx_l4_wkup_hwmod,
+       .slave          = &dra7xx_counter_32k_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> ctrl_module_wkup */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__ctrl_module_wkup = {
+       .master         = &dra7xx_l4_wkup_hwmod,
+       .slave          = &dra7xx_ctrl_module_wkup_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> dcan1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__dcan1 = {
+       .master         = &dra7xx_l4_wkup_hwmod,
+       .slave          = &dra7xx_dcan1_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per2 -> dcan2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__dcan2 = {
+       .master         = &dra7xx_l4_per2_hwmod,
+       .slave          = &dra7xx_dcan2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_dma_system_addrs[] = {
+       {
+               .pa_start       = 0x4a056000,
+               .pa_end         = 0x4a056fff,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_cfg -> dma_system */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__dma_system = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_dma_system_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_dma_system_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_dss_addrs[] = {
+       {
+               .name           = "family",
+               .pa_start       = 0x58000000,
+               .pa_end         = 0x5800007f,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l3_main_1 -> dss */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__dss = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_dss_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_dss_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_dss_dispc_addrs[] = {
+       {
+               .name           = "dispc",
+               .pa_start       = 0x58001000,
+               .pa_end         = 0x58001fff,
+               .flags          = ADDR_TYPE_RT
+       },
+};
+
+/* l3_main_1 -> dispc */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__dispc = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_dss_dispc_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_dss_dispc_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_dss_hdmi_addrs[] = {
+       {
+               .name           = "hdmi_wp",
+               .pa_start       = 0x58040000,
+               .pa_end         = 0x580400ff,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l3_main_1 -> dispc */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__hdmi = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_dss_hdmi_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_dss_hdmi_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_elm_addrs[] = {
+       {
+               .pa_start       = 0x48078000,
+               .pa_end         = 0x48078fff,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_per1 -> elm */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__elm = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_elm_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_elm_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> gpio1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__gpio1 = {
+       .master         = &dra7xx_l4_wkup_hwmod,
+       .slave          = &dra7xx_gpio1_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio2 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio3 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio4 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio4_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio5 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio5 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio5_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio6 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio6 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio6_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio7 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio7 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio7_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> gpio8 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio8 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_gpio8_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_gpmc_addrs[] = {
+       {
+               .pa_start       = 0x50000000,
+               .pa_end         = 0x500003ff,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l3_main_1 -> gpmc */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__gpmc = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_gpmc_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_gpmc_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_hdq1w_addrs[] = {
+       {
+               .pa_start       = 0x480b2000,
+               .pa_end         = 0x480b201f,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_per1 -> hdq1w */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__hdq1w = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_hdq1w_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_hdq1w_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> i2c1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c1 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_i2c1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> i2c2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c2 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_i2c2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> i2c3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c3 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_i2c3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> i2c4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c4 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_i2c4_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> i2c5 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__i2c5 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_i2c5_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mcspi1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mcspi1 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mcspi1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mcspi2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mcspi2 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mcspi2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mcspi3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mcspi3 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mcspi3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mcspi4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mcspi4 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mcspi4_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mmc1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc1 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mmc1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mmc2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc2 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mmc2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mmc3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc3 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mmc3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> mmc4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__mmc4 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_mmc4_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_cfg -> mpu */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__mpu = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_mpu_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_ocp2scp1_addrs[] = {
+       {
+               .pa_start       = 0x4a080000,
+               .pa_end         = 0x4a08001f,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_cfg -> ocp2scp1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__ocp2scp1 = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_ocp2scp1_hwmod,
+       .clk            = "l4_root_clk_div",
+       .addr           = dra7xx_ocp2scp1_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_qspi_addrs[] = {
+       {
+               .pa_start       = 0x4b300000,
+               .pa_end         = 0x4b30007f,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l3_main_1 -> qspi */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__qspi = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_qspi_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_qspi_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_sata_addrs[] = {
+       {
+               .name           = "sysc",
+               .pa_start       = 0x4a141100,
+               .pa_end         = 0x4a141107,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_cfg -> sata */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__sata = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_sata_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_sata_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_smartreflex_core_addrs[] = {
+       {
+               .pa_start       = 0x4a0dd000,
+               .pa_end         = 0x4a0dd07f,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_cfg -> smartreflex_core */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__smartreflex_core = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_smartreflex_core_hwmod,
+       .clk            = "l4_root_clk_div",
+       .addr           = dra7xx_smartreflex_core_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_smartreflex_mpu_addrs[] = {
+       {
+               .pa_start       = 0x4a0d9000,
+               .pa_end         = 0x4a0d907f,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_cfg -> smartreflex_mpu */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__smartreflex_mpu = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_smartreflex_mpu_hwmod,
+       .clk            = "l4_root_clk_div",
+       .addr           = dra7xx_smartreflex_mpu_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_addr_space dra7xx_spinlock_addrs[] = {
+       {
+               .pa_start       = 0x4a0f6000,
+               .pa_end         = 0x4a0f6fff,
+               .flags          = ADDR_TYPE_RT
+       },
+       { }
+};
+
+/* l4_cfg -> spinlock */
+static struct omap_hwmod_ocp_if dra7xx_l4_cfg__spinlock = {
+       .master         = &dra7xx_l4_cfg_hwmod,
+       .slave          = &dra7xx_spinlock_hwmod,
+       .clk            = "l3_iclk_div",
+       .addr           = dra7xx_spinlock_addrs,
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> timer1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__timer1 = {
+       .master         = &dra7xx_l4_wkup_hwmod,
+       .slave          = &dra7xx_timer1_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> timer2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer2 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_timer2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> timer3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer3 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_timer3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> timer4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer4 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_timer4_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer5 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer5 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer5_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer6 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer6 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer6_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer7 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer7 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer7_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> timer8 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__timer8 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_timer8_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> timer9 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer9 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_timer9_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> timer10 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer10 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_timer10_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> timer11 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__timer11 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_timer11_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> uart1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart1 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_uart1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> uart2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart2 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_uart2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> uart3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart3 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_uart3_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> uart4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart4 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_uart4_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> uart5 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart5 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_uart5_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per1 -> uart6 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = {
+       .master         = &dra7xx_l4_per1_hwmod,
+       .slave          = &dra7xx_uart6_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> usb_otg_ss1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_usb_otg_ss1_hwmod,
+       .clk            = "dpll_core_h13x2_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> usb_otg_ss2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss2 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_usb_otg_ss2_hwmod,
+       .clk            = "dpll_core_h13x2_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> usb_otg_ss3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss3 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_usb_otg_ss3_hwmod,
+       .clk            = "dpll_core_h13x2_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per3 -> usb_otg_ss4 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss4 = {
+       .master         = &dra7xx_l4_per3_hwmod,
+       .slave          = &dra7xx_usb_otg_ss4_hwmod,
+       .clk            = "dpll_core_h13x2_ck",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> vcp1 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__vcp1 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_vcp1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per2 -> vcp1 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__vcp1 = {
+       .master         = &dra7xx_l4_per2_hwmod,
+       .slave          = &dra7xx_vcp1_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> vcp2 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__vcp2 = {
+       .master         = &dra7xx_l3_main_1_hwmod,
+       .slave          = &dra7xx_vcp2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per2 -> vcp2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__vcp2 = {
+       .master         = &dra7xx_l4_per2_hwmod,
+       .slave          = &dra7xx_vcp2_hwmod,
+       .clk            = "l3_iclk_div",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> wd_timer2 */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__wd_timer2 = {
+       .master         = &dra7xx_l4_wkup_hwmod,
+       .slave          = &dra7xx_wd_timer2_hwmod,
+       .clk            = "wkupaon_iclk_mux",
+       .user           = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
+       &dra7xx_l3_main_2__l3_instr,
+       &dra7xx_l4_cfg__l3_main_1,
+       &dra7xx_mpu__l3_main_1,
+       &dra7xx_l3_main_1__l3_main_2,
+       &dra7xx_l4_cfg__l3_main_2,
+       &dra7xx_l3_main_1__l4_cfg,
+       &dra7xx_l3_main_1__l4_per1,
+       &dra7xx_l3_main_1__l4_per2,
+       &dra7xx_l3_main_1__l4_per3,
+       &dra7xx_l3_main_1__l4_wkup,
+       &dra7xx_l4_per2__atl,
+       &dra7xx_l3_main_1__bb2d,
+       &dra7xx_l4_wkup__counter_32k,
+       &dra7xx_l4_wkup__ctrl_module_wkup,
+       &dra7xx_l4_wkup__dcan1,
+       &dra7xx_l4_per2__dcan2,
+       &dra7xx_l4_cfg__dma_system,
+       &dra7xx_l3_main_1__dss,
+       &dra7xx_l3_main_1__dispc,
+       &dra7xx_l3_main_1__hdmi,
+       &dra7xx_l4_per1__elm,
+       &dra7xx_l4_wkup__gpio1,
+       &dra7xx_l4_per1__gpio2,
+       &dra7xx_l4_per1__gpio3,
+       &dra7xx_l4_per1__gpio4,
+       &dra7xx_l4_per1__gpio5,
+       &dra7xx_l4_per1__gpio6,
+       &dra7xx_l4_per1__gpio7,
+       &dra7xx_l4_per1__gpio8,
+       &dra7xx_l3_main_1__gpmc,
+       &dra7xx_l4_per1__hdq1w,
+       &dra7xx_l4_per1__i2c1,
+       &dra7xx_l4_per1__i2c2,
+       &dra7xx_l4_per1__i2c3,
+       &dra7xx_l4_per1__i2c4,
+       &dra7xx_l4_per1__i2c5,
+       &dra7xx_l4_per1__mcspi1,
+       &dra7xx_l4_per1__mcspi2,
+       &dra7xx_l4_per1__mcspi3,
+       &dra7xx_l4_per1__mcspi4,
+       &dra7xx_l4_per1__mmc1,
+       &dra7xx_l4_per1__mmc2,
+       &dra7xx_l4_per1__mmc3,
+       &dra7xx_l4_per1__mmc4,
+       &dra7xx_l4_cfg__mpu,
+       &dra7xx_l4_cfg__ocp2scp1,
+       &dra7xx_l3_main_1__qspi,
+       &dra7xx_l4_cfg__sata,
+       &dra7xx_l4_cfg__smartreflex_core,
+       &dra7xx_l4_cfg__smartreflex_mpu,
+       &dra7xx_l4_cfg__spinlock,
+       &dra7xx_l4_wkup__timer1,
+       &dra7xx_l4_per1__timer2,
+       &dra7xx_l4_per1__timer3,
+       &dra7xx_l4_per1__timer4,
+       &dra7xx_l4_per3__timer5,
+       &dra7xx_l4_per3__timer6,
+       &dra7xx_l4_per3__timer7,
+       &dra7xx_l4_per3__timer8,
+       &dra7xx_l4_per1__timer9,
+       &dra7xx_l4_per1__timer10,
+       &dra7xx_l4_per1__timer11,
+       &dra7xx_l4_per1__uart1,
+       &dra7xx_l4_per1__uart2,
+       &dra7xx_l4_per1__uart3,
+       &dra7xx_l4_per1__uart4,
+       &dra7xx_l4_per1__uart5,
+       &dra7xx_l4_per1__uart6,
+       &dra7xx_l4_per3__usb_otg_ss1,
+       &dra7xx_l4_per3__usb_otg_ss2,
+       &dra7xx_l4_per3__usb_otg_ss3,
+       &dra7xx_l4_per3__usb_otg_ss4,
+       &dra7xx_l3_main_1__vcp1,
+       &dra7xx_l4_per2__vcp1,
+       &dra7xx_l3_main_1__vcp2,
+       &dra7xx_l4_per2__vcp2,
+       &dra7xx_l4_wkup__wd_timer2,
+       NULL,
+};
+
+int __init dra7xx_hwmod_init(void)
+{
+       omap_hwmod_init();
+       return omap_hwmod_register_links(dra7xx_hwmod_ocp_ifs);
+}
index e4d7bd6f94b89bda9e20f9e80ed46116d03b1338..baf3d8bf6beabcf51c50fca4d56ca4e33f667024 100644 (file)
@@ -256,6 +256,7 @@ extern void omap3xxx_powerdomains_init(void);
 extern void am33xx_powerdomains_init(void);
 extern void omap44xx_powerdomains_init(void);
 extern void omap54xx_powerdomains_init(void);
+extern void dra7xx_powerdomains_init(void);
 
 extern struct pwrdm_ops omap2_pwrdm_operations;
 extern struct pwrdm_ops omap3_pwrdm_operations;
index e2d4bd804523316e5b9400d4870916a01827834c..328c1037cb60e86902732b119b8bd72eed8d7701 100644 (file)
@@ -336,6 +336,13 @@ static struct powerdomain dpll5_pwrdm = {
        .voltdm           = { .name = "core" },
 };
 
+static struct powerdomain alwon_81xx_pwrdm = {
+       .name             = "alwon_pwrdm",
+       .prcm_offs        = TI81XX_PRM_ALWON_MOD,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .voltdm           = { .name = "core" },
+};
+
 static struct powerdomain device_81xx_pwrdm = {
        .name             = "device_pwrdm",
        .prcm_offs        = TI81XX_PRM_DEVICE_MOD,
@@ -442,6 +449,7 @@ static struct powerdomain *powerdomains_am35x[] __initdata = {
 };
 
 static struct powerdomain *powerdomains_ti81xx[] __initdata = {
+       &alwon_81xx_pwrdm,
        &device_81xx_pwrdm,
        &active_816x_pwrdm,
        &default_816x_pwrdm,
diff --git a/arch/arm/mach-omap2/powerdomains7xx_data.c b/arch/arm/mach-omap2/powerdomains7xx_data.c
new file mode 100644 (file)
index 0000000..48151d1
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * DRA7xx Power domains framework
+ *
+ * Copyright (C) 2009-2013 Texas Instruments, Inc.
+ * Copyright (C) 2009-2011 Nokia Corporation
+ *
+ * Generated by code originally written by:
+ * Abhijit Pagare (abhijitpagare@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ * Paul Walmsley (paul@pwsan.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 "powerdomain.h"
+
+#include "prcm-common.h"
+#include "prcm44xx.h"
+#include "prm7xx.h"
+#include "prcm_mpu7xx.h"
+
+/* iva_7xx_pwrdm: IVA-HD power domain */
+static struct powerdomain iva_7xx_pwrdm = {
+       .name             = "iva_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_IVA_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF,
+       .banks            = 4,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* hwa_mem */
+               [1] = PWRSTS_OFF_RET,   /* sl2_mem */
+               [2] = PWRSTS_OFF_RET,   /* tcm1_mem */
+               [3] = PWRSTS_OFF_RET,   /* tcm2_mem */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* hwa_mem */
+               [1] = PWRSTS_OFF_RET,   /* sl2_mem */
+               [2] = PWRSTS_OFF_RET,   /* tcm1_mem */
+               [3] = PWRSTS_OFF_RET,   /* tcm2_mem */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* rtc_7xx_pwrdm:  */
+static struct powerdomain rtc_7xx_pwrdm = {
+       .name             = "rtc_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_RTC_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_ON,
+};
+
+/* custefuse_7xx_pwrdm: Customer efuse controller power domain */
+static struct powerdomain custefuse_7xx_pwrdm = {
+       .name             = "custefuse_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_CUSTEFUSE_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* ipu_7xx_pwrdm: Audio back end power domain */
+static struct powerdomain ipu_7xx_pwrdm = {
+       .name             = "ipu_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_IPU_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF,
+       .banks            = 2,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* aessmem */
+               [1] = PWRSTS_OFF_RET,   /* periphmem */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* aessmem */
+               [1] = PWRSTS_OFF_RET,   /* periphmem */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* dss_7xx_pwrdm: Display subsystem power domain */
+static struct powerdomain dss_7xx_pwrdm = {
+       .name             = "dss_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_DSS_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* dss_mem */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* dss_mem */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* l4per_7xx_pwrdm: Target peripherals power domain */
+static struct powerdomain l4per_7xx_pwrdm = {
+       .name             = "l4per_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_L4PER_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 2,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* nonretained_bank */
+               [1] = PWRSTS_OFF_RET,   /* retained_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* nonretained_bank */
+               [1] = PWRSTS_OFF_RET,   /* retained_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* gpu_7xx_pwrdm: 3D accelerator power domain */
+static struct powerdomain gpu_7xx_pwrdm = {
+       .name             = "gpu_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_GPU_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* gpu_mem */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* gpu_mem */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* wkupaon_7xx_pwrdm: Wake-up power domain */
+static struct powerdomain wkupaon_7xx_pwrdm = {
+       .name             = "wkupaon_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_WKUPAON_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_ON,        /* wkup_bank */
+       },
+};
+
+/* core_7xx_pwrdm: CORE power domain */
+static struct powerdomain core_7xx_pwrdm = {
+       .name             = "core_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_CORE_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 5,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* core_nret_bank */
+               [1] = PWRSTS_OFF_RET,   /* core_ocmram */
+               [2] = PWRSTS_OFF_RET,   /* core_other_bank */
+               [3] = PWRSTS_OFF_RET,   /* ipu_l2ram */
+               [4] = PWRSTS_OFF_RET,   /* ipu_unicache */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* core_nret_bank */
+               [1] = PWRSTS_OFF_RET,   /* core_ocmram */
+               [2] = PWRSTS_OFF_RET,   /* core_other_bank */
+               [3] = PWRSTS_OFF_RET,   /* ipu_l2ram */
+               [4] = PWRSTS_OFF_RET,   /* ipu_unicache */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* coreaon_7xx_pwrdm: Always ON logic that sits in VDD_CORE voltage domain */
+static struct powerdomain coreaon_7xx_pwrdm = {
+       .name             = "coreaon_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_COREAON_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_ON,
+};
+
+/* cpu0_7xx_pwrdm: MPU0 processor and Neon coprocessor power domain */
+static struct powerdomain cpu0_7xx_pwrdm = {
+       .name             = "cpu0_pwrdm",
+       .prcm_offs        = DRA7XX_MPU_PRCM_PRM_C0_INST,
+       .prcm_partition   = DRA7XX_MPU_PRCM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* cpu0_l1 */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_ON,        /* cpu0_l1 */
+       },
+};
+
+/* cpu1_7xx_pwrdm: MPU1 processor and Neon coprocessor power domain */
+static struct powerdomain cpu1_7xx_pwrdm = {
+       .name             = "cpu1_pwrdm",
+       .prcm_offs        = DRA7XX_MPU_PRCM_PRM_C1_INST,
+       .prcm_partition   = DRA7XX_MPU_PRCM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* cpu1_l1 */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_ON,        /* cpu1_l1 */
+       },
+};
+
+/* vpe_7xx_pwrdm:  */
+static struct powerdomain vpe_7xx_pwrdm = {
+       .name             = "vpe_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_VPE_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* vpe_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* vpe_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* mpu_7xx_pwrdm: Modena processor and the Neon coprocessor power domain */
+static struct powerdomain mpu_7xx_pwrdm = {
+       .name             = "mpu_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_MPU_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 2,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* mpu_l2 */
+               [1] = PWRSTS_RET,       /* mpu_ram */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* mpu_l2 */
+               [1] = PWRSTS_OFF_RET,   /* mpu_ram */
+       },
+};
+
+/* l3init_7xx_pwrdm: L3 initators pheripherals power domain  */
+static struct powerdomain l3init_7xx_pwrdm = {
+       .name             = "l3init_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_L3INIT_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_RET_ON,
+       .pwrsts_logic_ret = PWRSTS_OFF_RET,
+       .banks            = 3,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* gmac_bank */
+               [1] = PWRSTS_OFF_RET,   /* l3init_bank1 */
+               [2] = PWRSTS_OFF_RET,   /* l3init_bank2 */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* gmac_bank */
+               [1] = PWRSTS_OFF_RET,   /* l3init_bank1 */
+               [2] = PWRSTS_OFF_RET,   /* l3init_bank2 */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* eve3_7xx_pwrdm:  */
+static struct powerdomain eve3_7xx_pwrdm = {
+       .name             = "eve3_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_EVE3_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* eve3_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* eve3_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* emu_7xx_pwrdm: Emulation power domain */
+static struct powerdomain emu_7xx_pwrdm = {
+       .name             = "emu_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_EMU_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* emu_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* emu_bank */
+       },
+};
+
+/* dsp2_7xx_pwrdm:  */
+static struct powerdomain dsp2_7xx_pwrdm = {
+       .name             = "dsp2_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_DSP2_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 3,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* dsp2_edma */
+               [1] = PWRSTS_OFF_RET,   /* dsp2_l1 */
+               [2] = PWRSTS_OFF_RET,   /* dsp2_l2 */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* dsp2_edma */
+               [1] = PWRSTS_OFF_RET,   /* dsp2_l1 */
+               [2] = PWRSTS_OFF_RET,   /* dsp2_l2 */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* dsp1_7xx_pwrdm: Tesla processor power domain */
+static struct powerdomain dsp1_7xx_pwrdm = {
+       .name             = "dsp1_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_DSP1_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 3,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* dsp1_edma */
+               [1] = PWRSTS_OFF_RET,   /* dsp1_l1 */
+               [2] = PWRSTS_OFF_RET,   /* dsp1_l2 */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* dsp1_edma */
+               [1] = PWRSTS_OFF_RET,   /* dsp1_l1 */
+               [2] = PWRSTS_OFF_RET,   /* dsp1_l2 */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* cam_7xx_pwrdm: Camera subsystem power domain */
+static struct powerdomain cam_7xx_pwrdm = {
+       .name             = "cam_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_CAM_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* vip_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* vip_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* eve4_7xx_pwrdm:  */
+static struct powerdomain eve4_7xx_pwrdm = {
+       .name             = "eve4_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_EVE4_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* eve4_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* eve4_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* eve2_7xx_pwrdm:  */
+static struct powerdomain eve2_7xx_pwrdm = {
+       .name             = "eve2_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_EVE2_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* eve2_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* eve2_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/* eve1_7xx_pwrdm:  */
+static struct powerdomain eve1_7xx_pwrdm = {
+       .name             = "eve1_pwrdm",
+       .prcm_offs        = DRA7XX_PRM_EVE1_INST,
+       .prcm_partition   = DRA7XX_PRM_PARTITION,
+       .pwrsts           = PWRSTS_OFF_ON,
+       .banks            = 1,
+       .pwrsts_mem_ret = {
+               [0] = PWRSTS_OFF_RET,   /* eve1_bank */
+       },
+       .pwrsts_mem_on  = {
+               [0] = PWRSTS_OFF_RET,   /* eve1_bank */
+       },
+       .flags            = PWRDM_HAS_LOWPOWERSTATECHANGE,
+};
+
+/*
+ * The following power domains are not under SW control
+ *
+ * mpuaon
+ * mmaon
+ */
+
+/* As powerdomains are added or removed above, this list must also be changed */
+static struct powerdomain *powerdomains_dra7xx[] __initdata = {
+       &iva_7xx_pwrdm,
+       &rtc_7xx_pwrdm,
+       &custefuse_7xx_pwrdm,
+       &ipu_7xx_pwrdm,
+       &dss_7xx_pwrdm,
+       &l4per_7xx_pwrdm,
+       &gpu_7xx_pwrdm,
+       &wkupaon_7xx_pwrdm,
+       &core_7xx_pwrdm,
+       &coreaon_7xx_pwrdm,
+       &cpu0_7xx_pwrdm,
+       &cpu1_7xx_pwrdm,
+       &vpe_7xx_pwrdm,
+       &mpu_7xx_pwrdm,
+       &l3init_7xx_pwrdm,
+       &eve3_7xx_pwrdm,
+       &emu_7xx_pwrdm,
+       &dsp2_7xx_pwrdm,
+       &dsp1_7xx_pwrdm,
+       &cam_7xx_pwrdm,
+       &eve4_7xx_pwrdm,
+       &eve2_7xx_pwrdm,
+       &eve1_7xx_pwrdm,
+       NULL
+};
+
+void __init dra7xx_powerdomains_init(void)
+{
+       pwrdm_register_platform_funcs(&omap4_pwrdm_operations);
+       pwrdm_register_pwrdms(powerdomains_dra7xx);
+       pwrdm_complete_init();
+}
index ff1ac4a82a04a036b15e6a5f33c9f645ffb7d2f3..0e841fd9498ac4ee2c4daf4a58c34a070b302c60 100644 (file)
@@ -58,6 +58,7 @@
 #define TI816X_PRM_IVAHD1_MOD                  0x0d00
 #define TI816X_PRM_IVAHD2_MOD                  0x0e00
 #define TI816X_PRM_SGX_MOD                             0x0f00
+#define TI81XX_PRM_ALWON_MOD                   0x1800
 
 /* 24XX register bits shared between CM & PRM registers */
 
index f429cdd5a118aa5ca3ea647b1ee3307b18c3bf20..4fea2cfdf2c3a8c08794baa169509c24ca158ba2 100644 (file)
 #define OMAP54XX_SCRM_PARTITION                        4
 #define OMAP54XX_PRCM_MPU_PARTITION            5
 
+#define DRA7XX_PRM_PARTITION                   1
+#define DRA7XX_CM_CORE_AON_PARTITION           2
+#define DRA7XX_CM_CORE_PARTITION               3
+#define DRA7XX_MPU_PRCM_PARTITION              5
+
 /*
  * OMAP4_MAX_PRCM_PARTITIONS: set to the highest value of the PRCM partition
  * IDs, plus one
diff --git a/arch/arm/mach-omap2/prcm_mpu7xx.h b/arch/arm/mach-omap2/prcm_mpu7xx.h
new file mode 100644 (file)
index 0000000..9ebb5ce
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * DRA7xx PRCM MPU instance offset macros
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Generated by code originally written by:
+ * Paul Walmsley (paul@pwsan.com)
+ * Rajendra Nayak (rnayak@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_PRCM_MPU7XX_H
+#define __ARCH_ARM_MACH_OMAP2_PRCM_MPU7XX_H
+
+#include "prcm_mpu_44xx_54xx.h"
+
+#define DRA7XX_PRCM_MPU_BASE                   0x48243000
+
+#define DRA7XX_PRCM_MPU_REGADDR(inst, reg)                             \
+       OMAP2_L4_IO_ADDRESS(DRA7XX_PRCM_MPU_BASE + (inst) + (reg))
+
+/* MPU_PRCM instances */
+#define DRA7XX_MPU_PRCM_OCP_SOCKET_INST        0x0000
+#define DRA7XX_MPU_PRCM_DEVICE_INST    0x0200
+#define DRA7XX_MPU_PRCM_PRM_C0_INST    0x0400
+#define DRA7XX_MPU_PRCM_CM_C0_INST     0x0600
+#define DRA7XX_MPU_PRCM_PRM_C1_INST    0x0800
+#define DRA7XX_MPU_PRCM_CM_C1_INST     0x0a00
+
+/* PRCM_MPU clockdomain register offsets (from instance start) */
+#define DRA7XX_MPU_PRCM_CM_C0_CPU0_CDOFFS      0x0000
+#define DRA7XX_MPU_PRCM_CM_C1_CPU1_CDOFFS      0x0000
+
+
+/* MPU_PRCM */
+
+/* MPU_PRCM.PRCM_MPU_OCP_SOCKET register offsets */
+#define DRA7XX_REVISION_PRCM_MPU_OFFSET                                0x0000
+
+/* MPU_PRCM.PRCM_MPU_DEVICE register offsets */
+#define DRA7XX_PRM_FRAC_INCREMENTER_NUMERATOR_OFFSET           0x0010
+#define DRA7XX_PRM_FRAC_INCREMENTER_DENUMERATOR_RELOAD_OFFSET  0x0014
+
+/* MPU_PRCM.PRCM_MPU_PRM_C0 register offsets */
+#define DRA7XX_PM_CPU0_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_CPU0_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_CPU0_CPU0_RSTCTRL_OFFSET                     0x0010
+#define DRA7XX_RM_CPU0_CPU0_RSTST_OFFSET                       0x0014
+#define DRA7XX_RM_CPU0_CPU0_CONTEXT_OFFSET                     0x0024
+
+/* MPU_PRCM.PRCM_MPU_CM_C0 register offsets */
+#define DRA7XX_CM_CPU0_CLKSTCTRL_OFFSET                                0x0000
+#define DRA7XX_CM_CPU0_CPU0_CLKCTRL_OFFSET                     0x0020
+#define DRA7XX_CM_CPU0_CPU0_CLKCTRL                            DRA7XX_MPU_PRCM_REGADDR(DRA7XX_MPU_PRCM_CM_C0_INST, 0x0020)
+
+/* MPU_PRCM.PRCM_MPU_PRM_C1 register offsets */
+#define DRA7XX_PM_CPU1_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_CPU1_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_CPU1_CPU1_RSTCTRL_OFFSET                     0x0010
+#define DRA7XX_RM_CPU1_CPU1_RSTST_OFFSET                       0x0014
+#define DRA7XX_RM_CPU1_CPU1_CONTEXT_OFFSET                     0x0024
+
+/* MPU_PRCM.PRCM_MPU_CM_C1 register offsets */
+#define DRA7XX_CM_CPU1_CLKSTCTRL_OFFSET                                0x0000
+#define DRA7XX_CM_CPU1_CPU1_CLKCTRL_OFFSET                     0x0020
+#define DRA7XX_CM_CPU1_CPU1_CLKCTRL                            DRA7XX_MPU_PRCM_REGADDR(DRA7XX_MPU_PRCM_CM_C1_INST, 0x0020)
+
+#endif
index 415c7e0c9393ad3e85f45591a3fbf68a93a1df12..03a603476cfc451790cc02294d950fc6cab1abcf 100644 (file)
@@ -620,6 +620,15 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
        return 0;
 }
 
+static int omap4_check_vcvp(void)
+{
+       /* No VC/VP on dra7xx devices */
+       if (soc_is_dra7xx())
+               return 0;
+
+       return 1;
+}
+
 struct pwrdm_ops omap4_pwrdm_operations = {
        .pwrdm_set_next_pwrst   = omap4_pwrdm_set_next_pwrst,
        .pwrdm_read_next_pwrst  = omap4_pwrdm_read_next_pwrst,
@@ -637,6 +646,7 @@ struct pwrdm_ops omap4_pwrdm_operations = {
        .pwrdm_set_mem_onst     = omap4_pwrdm_set_mem_onst,
        .pwrdm_set_mem_retst    = omap4_pwrdm_set_mem_retst,
        .pwrdm_wait_transition  = omap4_pwrdm_wait_transition,
+       .pwrdm_has_voltdm       = omap4_check_vcvp,
 };
 
 /*
@@ -650,7 +660,7 @@ static struct prm_ll_data omap44xx_prm_ll_data = {
 
 int __init omap44xx_prm_init(void)
 {
-       if (!cpu_is_omap44xx() && !soc_is_omap54xx())
+       if (!cpu_is_omap44xx() && !soc_is_omap54xx() && !soc_is_dra7xx())
                return 0;
 
        return prm_register(&omap44xx_prm_ll_data);
diff --git a/arch/arm/mach-omap2/prm7xx.h b/arch/arm/mach-omap2/prm7xx.h
new file mode 100644 (file)
index 0000000..d92a840
--- /dev/null
@@ -0,0 +1,678 @@
+/*
+ * DRA7xx PRM instance offset macros
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Generated by code originally written by:
+ * Paul Walmsley (paul@pwsan.com)
+ * Rajendra Nayak (rnayak@ti.com)
+ * Benoit Cousson (b-cousson@ti.com)
+ *
+ * This file is automatically generated from the OMAP hardware databases.
+ * We respectfully ask that any modifications to this file be coordinated
+ * with the public linux-omap@vger.kernel.org mailing list and the
+ * authors above to ensure that the autogeneration scripts are kept
+ * up-to-date with the file contents.
+ *
+ * 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 __ARCH_ARM_MACH_OMAP2_PRM7XX_H
+#define __ARCH_ARM_MACH_OMAP2_PRM7XX_H
+
+#include "prm44xx_54xx.h"
+#include "prcm-common.h"
+#include "prm.h"
+
+#define DRA7XX_PRM_BASE                0x4ae06000
+
+#define DRA7XX_PRM_REGADDR(inst, reg)                          \
+       OMAP2_L4_IO_ADDRESS(DRA7XX_PRM_BASE + (inst) + (reg))
+
+
+/* PRM instances */
+#define DRA7XX_PRM_OCP_SOCKET_INST     0x0000
+#define DRA7XX_PRM_CKGEN_INST          0x0100
+#define DRA7XX_PRM_MPU_INST            0x0300
+#define DRA7XX_PRM_DSP1_INST           0x0400
+#define DRA7XX_PRM_IPU_INST            0x0500
+#define DRA7XX_PRM_COREAON_INST                0x0628
+#define DRA7XX_PRM_CORE_INST           0x0700
+#define DRA7XX_PRM_IVA_INST            0x0f00
+#define DRA7XX_PRM_CAM_INST            0x1000
+#define DRA7XX_PRM_DSS_INST            0x1100
+#define DRA7XX_PRM_GPU_INST            0x1200
+#define DRA7XX_PRM_L3INIT_INST         0x1300
+#define DRA7XX_PRM_L4PER_INST          0x1400
+#define DRA7XX_PRM_CUSTEFUSE_INST      0x1600
+#define DRA7XX_PRM_WKUPAON_INST                0x1724
+#define DRA7XX_PRM_WKUPAON_CM_INST     0x1800
+#define DRA7XX_PRM_EMU_INST            0x1900
+#define DRA7XX_PRM_EMU_CM_INST         0x1a00
+#define DRA7XX_PRM_DSP2_INST           0x1b00
+#define DRA7XX_PRM_EVE1_INST           0x1b40
+#define DRA7XX_PRM_EVE2_INST           0x1b80
+#define DRA7XX_PRM_EVE3_INST           0x1bc0
+#define DRA7XX_PRM_EVE4_INST           0x1c00
+#define DRA7XX_PRM_RTC_INST            0x1c60
+#define DRA7XX_PRM_VPE_INST            0x1c80
+#define DRA7XX_PRM_DEVICE_INST         0x1d00
+#define DRA7XX_PRM_INSTR_INST          0x1f00
+
+/* PRM clockdomain register offsets (from instance start) */
+#define DRA7XX_PRM_WKUPAON_CM_WKUPAON_CDOFFS   0x0000
+#define DRA7XX_PRM_EMU_CM_EMU_CDOFFS           0x0000
+
+/* PRM */
+
+/* PRM.OCP_SOCKET_PRM register offsets */
+#define DRA7XX_REVISION_PRM_OFFSET                             0x0000
+#define DRA7XX_PRM_IRQSTATUS_MPU_OFFSET                                0x0010
+#define DRA7XX_PRM_IRQSTATUS_MPU_2_OFFSET                      0x0014
+#define DRA7XX_PRM_IRQENABLE_MPU_OFFSET                                0x0018
+#define DRA7XX_PRM_IRQENABLE_MPU_2_OFFSET                      0x001c
+#define DRA7XX_PRM_IRQSTATUS_IPU2_OFFSET                       0x0020
+#define DRA7XX_PRM_IRQENABLE_IPU2_OFFSET                       0x0028
+#define DRA7XX_PRM_IRQSTATUS_DSP1_OFFSET                       0x0030
+#define DRA7XX_PRM_IRQENABLE_DSP1_OFFSET                       0x0038
+#define DRA7XX_CM_PRM_PROFILING_CLKCTRL_OFFSET                 0x0040
+#define DRA7XX_CM_PRM_PROFILING_CLKCTRL                                DRA7XX_PRM_REGADDR(DRA7XX_PRM_OCP_SOCKET_INST, 0x0040)
+#define DRA7XX_PRM_IRQENABLE_DSP2_OFFSET                       0x0044
+#define DRA7XX_PRM_IRQENABLE_EVE1_OFFSET                       0x0048
+#define DRA7XX_PRM_IRQENABLE_EVE2_OFFSET                       0x004c
+#define DRA7XX_PRM_IRQENABLE_EVE3_OFFSET                       0x0050
+#define DRA7XX_PRM_IRQENABLE_EVE4_OFFSET                       0x0054
+#define DRA7XX_PRM_IRQENABLE_IPU1_OFFSET                       0x0058
+#define DRA7XX_PRM_IRQSTATUS_DSP2_OFFSET                       0x005c
+#define DRA7XX_PRM_IRQSTATUS_EVE1_OFFSET                       0x0060
+#define DRA7XX_PRM_IRQSTATUS_EVE2_OFFSET                       0x0064
+#define DRA7XX_PRM_IRQSTATUS_EVE3_OFFSET                       0x0068
+#define DRA7XX_PRM_IRQSTATUS_EVE4_OFFSET                       0x006c
+#define DRA7XX_PRM_IRQSTATUS_IPU1_OFFSET                       0x0070
+#define DRA7XX_PRM_DEBUG_CFG1_OFFSET                           0x00e4
+#define DRA7XX_PRM_DEBUG_CFG2_OFFSET                           0x00e8
+#define DRA7XX_PRM_DEBUG_CFG3_OFFSET                           0x00ec
+#define DRA7XX_PRM_DEBUG_OUT_OFFSET                            0x00f4
+
+/* PRM.CKGEN_PRM register offsets */
+#define DRA7XX_CM_CLKSEL_SYSCLK1_OFFSET                                0x0000
+#define DRA7XX_CM_CLKSEL_SYSCLK1                               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0000)
+#define DRA7XX_CM_CLKSEL_WKUPAON_OFFSET                                0x0008
+#define DRA7XX_CM_CLKSEL_WKUPAON                               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0008)
+#define DRA7XX_CM_CLKSEL_ABE_PLL_REF_OFFSET                    0x000c
+#define DRA7XX_CM_CLKSEL_ABE_PLL_REF                           DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x000c)
+#define DRA7XX_CM_CLKSEL_SYS_OFFSET                            0x0010
+#define DRA7XX_CM_CLKSEL_SYS                                   DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0010)
+#define DRA7XX_CM_CLKSEL_ABE_PLL_BYPAS_OFFSET                  0x0014
+#define DRA7XX_CM_CLKSEL_ABE_PLL_BYPAS                         DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0014)
+#define DRA7XX_CM_CLKSEL_ABE_PLL_SYS_OFFSET                    0x0018
+#define DRA7XX_CM_CLKSEL_ABE_PLL_SYS                           DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0018)
+#define DRA7XX_CM_CLKSEL_ABE_24M_OFFSET                                0x001c
+#define DRA7XX_CM_CLKSEL_ABE_24M                               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x001c)
+#define DRA7XX_CM_CLKSEL_ABE_SYS_OFFSET                                0x0020
+#define DRA7XX_CM_CLKSEL_ABE_SYS                               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0020)
+#define DRA7XX_CM_CLKSEL_HDMI_MCASP_AUX_OFFSET                 0x0024
+#define DRA7XX_CM_CLKSEL_HDMI_MCASP_AUX                                DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0024)
+#define DRA7XX_CM_CLKSEL_HDMI_TIMER_OFFSET                     0x0028
+#define DRA7XX_CM_CLKSEL_HDMI_TIMER                            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0028)
+#define DRA7XX_CM_CLKSEL_MCASP_SYS_OFFSET                      0x002c
+#define DRA7XX_CM_CLKSEL_MCASP_SYS                             DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x002c)
+#define DRA7XX_CM_CLKSEL_MLBP_MCASP_OFFSET                     0x0030
+#define DRA7XX_CM_CLKSEL_MLBP_MCASP                            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0030)
+#define DRA7XX_CM_CLKSEL_MLB_MCASP_OFFSET                      0x0034
+#define DRA7XX_CM_CLKSEL_MLB_MCASP                             DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0034)
+#define DRA7XX_CM_CLKSEL_PER_ABE_X1_GFCLK_MCASP_AUX_OFFSET     0x0038
+#define DRA7XX_CM_CLKSEL_PER_ABE_X1_GFCLK_MCASP_AUX            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0038)
+#define DRA7XX_CM_CLKSEL_SYS_CLK1_32K_OFFSET                   0x0040
+#define DRA7XX_CM_CLKSEL_SYS_CLK1_32K                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0040)
+#define DRA7XX_CM_CLKSEL_TIMER_SYS_OFFSET                      0x0044
+#define DRA7XX_CM_CLKSEL_TIMER_SYS                             DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0044)
+#define DRA7XX_CM_CLKSEL_VIDEO1_MCASP_AUX_OFFSET               0x0048
+#define DRA7XX_CM_CLKSEL_VIDEO1_MCASP_AUX                      DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0048)
+#define DRA7XX_CM_CLKSEL_VIDEO1_TIMER_OFFSET                   0x004c
+#define DRA7XX_CM_CLKSEL_VIDEO1_TIMER                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x004c)
+#define DRA7XX_CM_CLKSEL_VIDEO2_MCASP_AUX_OFFSET               0x0050
+#define DRA7XX_CM_CLKSEL_VIDEO2_MCASP_AUX                      DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0050)
+#define DRA7XX_CM_CLKSEL_VIDEO2_TIMER_OFFSET                   0x0054
+#define DRA7XX_CM_CLKSEL_VIDEO2_TIMER                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0054)
+#define DRA7XX_CM_CLKSEL_CLKOUTMUX0_OFFSET                     0x0058
+#define DRA7XX_CM_CLKSEL_CLKOUTMUX0                            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0058)
+#define DRA7XX_CM_CLKSEL_CLKOUTMUX1_OFFSET                     0x005c
+#define DRA7XX_CM_CLKSEL_CLKOUTMUX1                            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x005c)
+#define DRA7XX_CM_CLKSEL_CLKOUTMUX2_OFFSET                     0x0060
+#define DRA7XX_CM_CLKSEL_CLKOUTMUX2                            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0060)
+#define DRA7XX_CM_CLKSEL_HDMI_PLL_SYS_OFFSET                   0x0064
+#define DRA7XX_CM_CLKSEL_HDMI_PLL_SYS                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0064)
+#define DRA7XX_CM_CLKSEL_VIDEO1_PLL_SYS_OFFSET                 0x0068
+#define DRA7XX_CM_CLKSEL_VIDEO1_PLL_SYS                                DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0068)
+#define DRA7XX_CM_CLKSEL_VIDEO2_PLL_SYS_OFFSET                 0x006c
+#define DRA7XX_CM_CLKSEL_VIDEO2_PLL_SYS                                DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x006c)
+#define DRA7XX_CM_CLKSEL_ABE_CLK_DIV_OFFSET                    0x0070
+#define DRA7XX_CM_CLKSEL_ABE_CLK_DIV                           DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0070)
+#define DRA7XX_CM_CLKSEL_ABE_GICLK_DIV_OFFSET                  0x0074
+#define DRA7XX_CM_CLKSEL_ABE_GICLK_DIV                         DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0074)
+#define DRA7XX_CM_CLKSEL_AESS_FCLK_DIV_OFFSET                  0x0078
+#define DRA7XX_CM_CLKSEL_AESS_FCLK_DIV                         DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0078)
+#define DRA7XX_CM_CLKSEL_EVE_CLK_OFFSET                                0x0080
+#define DRA7XX_CM_CLKSEL_EVE_CLK                               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0080)
+#define DRA7XX_CM_CLKSEL_USB_OTG_CLK_CLKOUTMUX_OFFSET          0x0084
+#define DRA7XX_CM_CLKSEL_USB_OTG_CLK_CLKOUTMUX                 DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0084)
+#define DRA7XX_CM_CLKSEL_CORE_DPLL_OUT_CLK_CLKOUTMUX_OFFSET    0x0088
+#define DRA7XX_CM_CLKSEL_CORE_DPLL_OUT_CLK_CLKOUTMUX           DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0088)
+#define DRA7XX_CM_CLKSEL_DSP_GFCLK_CLKOUTMUX_OFFSET            0x008c
+#define DRA7XX_CM_CLKSEL_DSP_GFCLK_CLKOUTMUX                   DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x008c)
+#define DRA7XX_CM_CLKSEL_EMIF_PHY_GCLK_CLKOUTMUX_OFFSET                0x0090
+#define DRA7XX_CM_CLKSEL_EMIF_PHY_GCLK_CLKOUTMUX               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0090)
+#define DRA7XX_CM_CLKSEL_EMU_CLK_CLKOUTMUX_OFFSET              0x0094
+#define DRA7XX_CM_CLKSEL_EMU_CLK_CLKOUTMUX                     DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0094)
+#define DRA7XX_CM_CLKSEL_FUNC_96M_AON_CLK_CLKOUTMUX_OFFSET     0x0098
+#define DRA7XX_CM_CLKSEL_FUNC_96M_AON_CLK_CLKOUTMUX            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x0098)
+#define DRA7XX_CM_CLKSEL_GMAC_250M_CLK_CLKOUTMUX_OFFSET                0x009c
+#define DRA7XX_CM_CLKSEL_GMAC_250M_CLK_CLKOUTMUX               DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x009c)
+#define DRA7XX_CM_CLKSEL_GPU_GCLK_CLKOUTMUX_OFFSET             0x00a0
+#define DRA7XX_CM_CLKSEL_GPU_GCLK_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00a0)
+#define DRA7XX_CM_CLKSEL_HDMI_CLK_CLKOUTMUX_OFFSET             0x00a4
+#define DRA7XX_CM_CLKSEL_HDMI_CLK_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00a4)
+#define DRA7XX_CM_CLKSEL_IVA_GCLK_CLKOUTMUX_OFFSET             0x00a8
+#define DRA7XX_CM_CLKSEL_IVA_GCLK_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00a8)
+#define DRA7XX_CM_CLKSEL_L3INIT_480M_GFCLK_CLKOUTMUX_OFFSET    0x00ac
+#define DRA7XX_CM_CLKSEL_L3INIT_480M_GFCLK_CLKOUTMUX           DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00ac)
+#define DRA7XX_CM_CLKSEL_MPU_GCLK_CLKOUTMUX_OFFSET             0x00b0
+#define DRA7XX_CM_CLKSEL_MPU_GCLK_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00b0)
+#define DRA7XX_CM_CLKSEL_PCIE1_CLK_CLKOUTMUX_OFFSET            0x00b4
+#define DRA7XX_CM_CLKSEL_PCIE1_CLK_CLKOUTMUX                   DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00b4)
+#define DRA7XX_CM_CLKSEL_PCIE2_CLK_CLKOUTMUX_OFFSET            0x00b8
+#define DRA7XX_CM_CLKSEL_PCIE2_CLK_CLKOUTMUX                   DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00b8)
+#define DRA7XX_CM_CLKSEL_PER_ABE_X1_CLK_CLKOUTMUX_OFFSET       0x00bc
+#define DRA7XX_CM_CLKSEL_PER_ABE_X1_CLK_CLKOUTMUX              DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00bc)
+#define DRA7XX_CM_CLKSEL_SATA_CLK_CLKOUTMUX_OFFSET             0x00c0
+#define DRA7XX_CM_CLKSEL_SATA_CLK_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00c0)
+#define DRA7XX_CM_CLKSEL_SECURE_32K_CLK_CLKOUTMUX_OFFSET       0x00c4
+#define DRA7XX_CM_CLKSEL_SECURE_32K_CLK_CLKOUTMUX              DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00c4)
+#define DRA7XX_CM_CLKSEL_SYS_CLK1_CLKOUTMUX_OFFSET             0x00c8
+#define DRA7XX_CM_CLKSEL_SYS_CLK1_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00c8)
+#define DRA7XX_CM_CLKSEL_SYS_CLK2_CLKOUTMUX_OFFSET             0x00cc
+#define DRA7XX_CM_CLKSEL_SYS_CLK2_CLKOUTMUX                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00cc)
+#define DRA7XX_CM_CLKSEL_VIDEO1_CLK_CLKOUTMUX_OFFSET           0x00d0
+#define DRA7XX_CM_CLKSEL_VIDEO1_CLK_CLKOUTMUX                  DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00d0)
+#define DRA7XX_CM_CLKSEL_VIDEO2_CLK_CLKOUTMUX_OFFSET           0x00d4
+#define DRA7XX_CM_CLKSEL_VIDEO2_CLK_CLKOUTMUX                  DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00d4)
+#define DRA7XX_CM_CLKSEL_ABE_LP_CLK_OFFSET                     0x00d8
+#define DRA7XX_CM_CLKSEL_ABE_LP_CLK                            DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00d8)
+#define DRA7XX_CM_CLKSEL_ADC_GFCLK_OFFSET                      0x00dc
+#define DRA7XX_CM_CLKSEL_ADC_GFCLK                             DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00dc)
+#define DRA7XX_CM_CLKSEL_EVE_GFCLK_CLKOUTMUX_OFFSET            0x00e0
+#define DRA7XX_CM_CLKSEL_EVE_GFCLK_CLKOUTMUX                   DRA7XX_PRM_REGADDR(DRA7XX_PRM_CKGEN_INST, 0x00e0)
+
+/* PRM.MPU_PRM register offsets */
+#define DRA7XX_PM_MPU_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_MPU_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_RM_MPU_MPU_CONTEXT_OFFSET                       0x0024
+
+/* PRM.DSP1_PRM register offsets */
+#define DRA7XX_PM_DSP1_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_DSP1_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_DSP1_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_DSP1_RSTST_OFFSET                            0x0014
+#define DRA7XX_RM_DSP1_DSP1_CONTEXT_OFFSET                     0x0024
+
+/* PRM.IPU_PRM register offsets */
+#define DRA7XX_PM_IPU_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_IPU_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_RM_IPU1_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_IPU1_RSTST_OFFSET                            0x0014
+#define DRA7XX_RM_IPU1_IPU1_CONTEXT_OFFSET                     0x0024
+#define DRA7XX_PM_IPU_MCASP1_WKDEP_OFFSET                      0x0050
+#define DRA7XX_RM_IPU_MCASP1_CONTEXT_OFFSET                    0x0054
+#define DRA7XX_PM_IPU_TIMER5_WKDEP_OFFSET                      0x0058
+#define DRA7XX_RM_IPU_TIMER5_CONTEXT_OFFSET                    0x005c
+#define DRA7XX_PM_IPU_TIMER6_WKDEP_OFFSET                      0x0060
+#define DRA7XX_RM_IPU_TIMER6_CONTEXT_OFFSET                    0x0064
+#define DRA7XX_PM_IPU_TIMER7_WKDEP_OFFSET                      0x0068
+#define DRA7XX_RM_IPU_TIMER7_CONTEXT_OFFSET                    0x006c
+#define DRA7XX_PM_IPU_TIMER8_WKDEP_OFFSET                      0x0070
+#define DRA7XX_RM_IPU_TIMER8_CONTEXT_OFFSET                    0x0074
+#define DRA7XX_PM_IPU_I2C5_WKDEP_OFFSET                                0x0078
+#define DRA7XX_RM_IPU_I2C5_CONTEXT_OFFSET                      0x007c
+#define DRA7XX_PM_IPU_UART6_WKDEP_OFFSET                       0x0080
+#define DRA7XX_RM_IPU_UART6_CONTEXT_OFFSET                     0x0084
+
+/* PRM.COREAON_PRM register offsets */
+#define DRA7XX_PM_COREAON_SMARTREFLEX_MPU_WKDEP_OFFSET         0x0000
+#define DRA7XX_RM_COREAON_SMARTREFLEX_MPU_CONTEXT_OFFSET       0x0004
+#define DRA7XX_PM_COREAON_SMARTREFLEX_CORE_WKDEP_OFFSET                0x0010
+#define DRA7XX_RM_COREAON_SMARTREFLEX_CORE_CONTEXT_OFFSET      0x0014
+#define DRA7XX_PM_COREAON_SMARTREFLEX_GPU_WKDEP_OFFSET         0x0030
+#define DRA7XX_RM_COREAON_SMARTREFLEX_GPU_CONTEXT_OFFSET       0x0034
+#define DRA7XX_PM_COREAON_SMARTREFLEX_DSPEVE_WKDEP_OFFSET      0x0040
+#define DRA7XX_RM_COREAON_SMARTREFLEX_DSPEVE_CONTEXT_OFFSET    0x0044
+#define DRA7XX_PM_COREAON_SMARTREFLEX_IVAHD_WKDEP_OFFSET       0x0050
+#define DRA7XX_RM_COREAON_SMARTREFLEX_IVAHD_CONTEXT_OFFSET     0x0054
+#define DRA7XX_RM_COREAON_DUMMY_MODULE1_CONTEXT_OFFSET         0x0084
+#define DRA7XX_RM_COREAON_DUMMY_MODULE2_CONTEXT_OFFSET         0x0094
+#define DRA7XX_RM_COREAON_DUMMY_MODULE3_CONTEXT_OFFSET         0x00a4
+#define DRA7XX_RM_COREAON_DUMMY_MODULE4_CONTEXT_OFFSET         0x00b4
+
+/* PRM.CORE_PRM register offsets */
+#define DRA7XX_PM_CORE_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_CORE_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_L3MAIN1_L3_MAIN_1_CONTEXT_OFFSET             0x0024
+#define DRA7XX_RM_L3MAIN1_GPMC_CONTEXT_OFFSET                  0x002c
+#define DRA7XX_RM_L3MAIN1_MMU_EDMA_CONTEXT_OFFSET              0x0034
+#define DRA7XX_PM_L3MAIN1_OCMC_RAM1_WKDEP_OFFSET               0x0050
+#define DRA7XX_RM_L3MAIN1_OCMC_RAM1_CONTEXT_OFFSET             0x0054
+#define DRA7XX_PM_L3MAIN1_OCMC_RAM2_WKDEP_OFFSET               0x0058
+#define DRA7XX_RM_L3MAIN1_OCMC_RAM2_CONTEXT_OFFSET             0x005c
+#define DRA7XX_PM_L3MAIN1_OCMC_RAM3_WKDEP_OFFSET               0x0060
+#define DRA7XX_RM_L3MAIN1_OCMC_RAM3_CONTEXT_OFFSET             0x0064
+#define DRA7XX_RM_L3MAIN1_OCMC_ROM_CONTEXT_OFFSET              0x006c
+#define DRA7XX_PM_L3MAIN1_TPCC_WKDEP_OFFSET                    0x0070
+#define DRA7XX_RM_L3MAIN1_TPCC_CONTEXT_OFFSET                  0x0074
+#define DRA7XX_PM_L3MAIN1_TPTC1_WKDEP_OFFSET                   0x0078
+#define DRA7XX_RM_L3MAIN1_TPTC1_CONTEXT_OFFSET                 0x007c
+#define DRA7XX_PM_L3MAIN1_TPTC2_WKDEP_OFFSET                   0x0080
+#define DRA7XX_RM_L3MAIN1_TPTC2_CONTEXT_OFFSET                 0x0084
+#define DRA7XX_RM_L3MAIN1_VCP1_CONTEXT_OFFSET                  0x008c
+#define DRA7XX_RM_L3MAIN1_VCP2_CONTEXT_OFFSET                  0x0094
+#define DRA7XX_RM_L3MAIN1_SPARE_CME_CONTEXT_OFFSET             0x009c
+#define DRA7XX_RM_L3MAIN1_SPARE_HDMI_CONTEXT_OFFSET            0x00a4
+#define DRA7XX_RM_L3MAIN1_SPARE_ICM_CONTEXT_OFFSET             0x00ac
+#define DRA7XX_RM_L3MAIN1_SPARE_IVA2_CONTEXT_OFFSET            0x00b4
+#define DRA7XX_RM_L3MAIN1_SPARE_SATA2_CONTEXT_OFFSET           0x00bc
+#define DRA7XX_RM_L3MAIN1_SPARE_UNKNOWN4_CONTEXT_OFFSET                0x00c4
+#define DRA7XX_RM_L3MAIN1_SPARE_UNKNOWN5_CONTEXT_OFFSET                0x00cc
+#define DRA7XX_RM_L3MAIN1_SPARE_UNKNOWN6_CONTEXT_OFFSET                0x00d4
+#define DRA7XX_RM_L3MAIN1_SPARE_VIDEOPLL1_CONTEXT_OFFSET       0x00dc
+#define DRA7XX_RM_L3MAIN1_SPARE_VIDEOPLL2_CONTEXT_OFFSET       0x00f4
+#define DRA7XX_RM_L3MAIN1_SPARE_VIDEOPLL3_CONTEXT_OFFSET       0x00fc
+#define DRA7XX_RM_IPU2_RSTCTRL_OFFSET                          0x0210
+#define DRA7XX_RM_IPU2_RSTST_OFFSET                            0x0214
+#define DRA7XX_RM_IPU2_IPU2_CONTEXT_OFFSET                     0x0224
+#define DRA7XX_RM_DMA_DMA_SYSTEM_CONTEXT_OFFSET                        0x0324
+#define DRA7XX_RM_EMIF_DMM_CONTEXT_OFFSET                      0x0424
+#define DRA7XX_RM_EMIF_EMIF_OCP_FW_CONTEXT_OFFSET              0x042c
+#define DRA7XX_RM_EMIF_EMIF1_CONTEXT_OFFSET                    0x0434
+#define DRA7XX_RM_EMIF_EMIF2_CONTEXT_OFFSET                    0x043c
+#define DRA7XX_RM_EMIF_EMIF_DLL_CONTEXT_OFFSET                 0x0444
+#define DRA7XX_RM_ATL_ATL_CONTEXT_OFFSET                       0x0524
+#define DRA7XX_RM_L4CFG_L4_CFG_CONTEXT_OFFSET                  0x0624
+#define DRA7XX_RM_L4CFG_SPINLOCK_CONTEXT_OFFSET                        0x062c
+#define DRA7XX_RM_L4CFG_MAILBOX1_CONTEXT_OFFSET                        0x0634
+#define DRA7XX_RM_L4CFG_SAR_ROM_CONTEXT_OFFSET                 0x063c
+#define DRA7XX_RM_L4CFG_OCP2SCP2_CONTEXT_OFFSET                        0x0644
+#define DRA7XX_RM_L4CFG_MAILBOX2_CONTEXT_OFFSET                        0x064c
+#define DRA7XX_RM_L4CFG_MAILBOX3_CONTEXT_OFFSET                        0x0654
+#define DRA7XX_RM_L4CFG_MAILBOX4_CONTEXT_OFFSET                        0x065c
+#define DRA7XX_RM_L4CFG_MAILBOX5_CONTEXT_OFFSET                        0x0664
+#define DRA7XX_RM_L4CFG_MAILBOX6_CONTEXT_OFFSET                        0x066c
+#define DRA7XX_RM_L4CFG_MAILBOX7_CONTEXT_OFFSET                        0x0674
+#define DRA7XX_RM_L4CFG_MAILBOX8_CONTEXT_OFFSET                        0x067c
+#define DRA7XX_RM_L4CFG_MAILBOX9_CONTEXT_OFFSET                        0x0684
+#define DRA7XX_RM_L4CFG_MAILBOX10_CONTEXT_OFFSET               0x068c
+#define DRA7XX_RM_L4CFG_MAILBOX11_CONTEXT_OFFSET               0x0694
+#define DRA7XX_RM_L4CFG_MAILBOX12_CONTEXT_OFFSET               0x069c
+#define DRA7XX_RM_L4CFG_MAILBOX13_CONTEXT_OFFSET               0x06a4
+#define DRA7XX_RM_L4CFG_SPARE_SMARTREFLEX_RTC_CONTEXT_OFFSET   0x06ac
+#define DRA7XX_RM_L4CFG_SPARE_SMARTREFLEX_SDRAM_CONTEXT_OFFSET 0x06b4
+#define DRA7XX_RM_L4CFG_SPARE_SMARTREFLEX_WKUP_CONTEXT_OFFSET  0x06bc
+#define DRA7XX_RM_L4CFG_IO_DELAY_BLOCK_CONTEXT_OFFSET          0x06c4
+#define DRA7XX_RM_L3INSTR_L3_MAIN_2_CONTEXT_OFFSET             0x0724
+#define DRA7XX_RM_L3INSTR_L3_INSTR_CONTEXT_OFFSET              0x072c
+#define DRA7XX_RM_L3INSTR_OCP_WP_NOC_CONTEXT_OFFSET            0x0744
+
+/* PRM.IVA_PRM register offsets */
+#define DRA7XX_PM_IVA_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_IVA_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_RM_IVA_RSTCTRL_OFFSET                           0x0010
+#define DRA7XX_RM_IVA_RSTST_OFFSET                             0x0014
+#define DRA7XX_RM_IVA_IVA_CONTEXT_OFFSET                       0x0024
+#define DRA7XX_RM_IVA_SL2_CONTEXT_OFFSET                       0x002c
+
+/* PRM.CAM_PRM register offsets */
+#define DRA7XX_PM_CAM_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_CAM_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_PM_CAM_VIP1_WKDEP_OFFSET                                0x0020
+#define DRA7XX_RM_CAM_VIP1_CONTEXT_OFFSET                      0x0024
+#define DRA7XX_PM_CAM_VIP2_WKDEP_OFFSET                                0x0028
+#define DRA7XX_RM_CAM_VIP2_CONTEXT_OFFSET                      0x002c
+#define DRA7XX_PM_CAM_VIP3_WKDEP_OFFSET                                0x0030
+#define DRA7XX_RM_CAM_VIP3_CONTEXT_OFFSET                      0x0034
+#define DRA7XX_RM_CAM_LVDSRX_CONTEXT_OFFSET                    0x003c
+#define DRA7XX_RM_CAM_CSI1_CONTEXT_OFFSET                      0x0044
+#define DRA7XX_RM_CAM_CSI2_CONTEXT_OFFSET                      0x004c
+
+/* PRM.DSS_PRM register offsets */
+#define DRA7XX_PM_DSS_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_DSS_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_PM_DSS_DSS_WKDEP_OFFSET                         0x0020
+#define DRA7XX_RM_DSS_DSS_CONTEXT_OFFSET                       0x0024
+#define DRA7XX_PM_DSS_DSS2_WKDEP_OFFSET                                0x0028
+#define DRA7XX_RM_DSS_BB2D_CONTEXT_OFFSET                      0x0034
+#define DRA7XX_RM_DSS_SDVENC_CONTEXT_OFFSET                    0x003c
+
+/* PRM.GPU_PRM register offsets */
+#define DRA7XX_PM_GPU_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_GPU_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_RM_GPU_GPU_CONTEXT_OFFSET                       0x0024
+
+/* PRM.L3INIT_PRM register offsets */
+#define DRA7XX_PM_L3INIT_PWRSTCTRL_OFFSET                      0x0000
+#define DRA7XX_PM_L3INIT_PWRSTST_OFFSET                                0x0004
+#define DRA7XX_PM_L3INIT_MMC1_WKDEP_OFFSET                     0x0028
+#define DRA7XX_RM_L3INIT_MMC1_CONTEXT_OFFSET                   0x002c
+#define DRA7XX_PM_L3INIT_MMC2_WKDEP_OFFSET                     0x0030
+#define DRA7XX_RM_L3INIT_MMC2_CONTEXT_OFFSET                   0x0034
+#define DRA7XX_PM_L3INIT_USB_OTG_SS2_WKDEP_OFFSET              0x0040
+#define DRA7XX_RM_L3INIT_USB_OTG_SS2_CONTEXT_OFFSET            0x0044
+#define DRA7XX_PM_L3INIT_USB_OTG_SS3_WKDEP_OFFSET              0x0048
+#define DRA7XX_RM_L3INIT_USB_OTG_SS3_CONTEXT_OFFSET            0x004c
+#define DRA7XX_PM_L3INIT_USB_OTG_SS4_WKDEP_OFFSET              0x0050
+#define DRA7XX_RM_L3INIT_USB_OTG_SS4_CONTEXT_OFFSET            0x0054
+#define DRA7XX_RM_L3INIT_MLB_SS_CONTEXT_OFFSET                 0x005c
+#define DRA7XX_RM_L3INIT_IEEE1500_2_OCP_CONTEXT_OFFSET         0x007c
+#define DRA7XX_PM_L3INIT_SATA_WKDEP_OFFSET                     0x0088
+#define DRA7XX_RM_L3INIT_SATA_CONTEXT_OFFSET                   0x008c
+#define DRA7XX_RM_GMAC_GMAC_CONTEXT_OFFSET                     0x00d4
+#define DRA7XX_RM_L3INIT_OCP2SCP1_CONTEXT_OFFSET               0x00e4
+#define DRA7XX_RM_L3INIT_OCP2SCP3_CONTEXT_OFFSET               0x00ec
+#define DRA7XX_PM_L3INIT_USB_OTG_SS1_WKDEP_OFFSET              0x00f0
+#define DRA7XX_RM_L3INIT_USB_OTG_SS1_CONTEXT_OFFSET            0x00f4
+
+/* PRM.L4PER_PRM register offsets */
+#define DRA7XX_PM_L4PER_PWRSTCTRL_OFFSET                       0x0000
+#define DRA7XX_PM_L4PER_PWRSTST_OFFSET                         0x0004
+#define DRA7XX_RM_L4PER2_L4PER2_CONTEXT_OFFSET                 0x000c
+#define DRA7XX_RM_L4PER3_L4PER3_CONTEXT_OFFSET                 0x0014
+#define DRA7XX_RM_L4PER2_PRUSS1_CONTEXT_OFFSET                 0x001c
+#define DRA7XX_RM_L4PER2_PRUSS2_CONTEXT_OFFSET                 0x0024
+#define DRA7XX_PM_L4PER_TIMER10_WKDEP_OFFSET                   0x0028
+#define DRA7XX_RM_L4PER_TIMER10_CONTEXT_OFFSET                 0x002c
+#define DRA7XX_PM_L4PER_TIMER11_WKDEP_OFFSET                   0x0030
+#define DRA7XX_RM_L4PER_TIMER11_CONTEXT_OFFSET                 0x0034
+#define DRA7XX_PM_L4PER_TIMER2_WKDEP_OFFSET                    0x0038
+#define DRA7XX_RM_L4PER_TIMER2_CONTEXT_OFFSET                  0x003c
+#define DRA7XX_PM_L4PER_TIMER3_WKDEP_OFFSET                    0x0040
+#define DRA7XX_RM_L4PER_TIMER3_CONTEXT_OFFSET                  0x0044
+#define DRA7XX_PM_L4PER_TIMER4_WKDEP_OFFSET                    0x0048
+#define DRA7XX_RM_L4PER_TIMER4_CONTEXT_OFFSET                  0x004c
+#define DRA7XX_PM_L4PER_TIMER9_WKDEP_OFFSET                    0x0050
+#define DRA7XX_RM_L4PER_TIMER9_CONTEXT_OFFSET                  0x0054
+#define DRA7XX_RM_L4PER_ELM_CONTEXT_OFFSET                     0x005c
+#define DRA7XX_PM_L4PER_GPIO2_WKDEP_OFFSET                     0x0060
+#define DRA7XX_RM_L4PER_GPIO2_CONTEXT_OFFSET                   0x0064
+#define DRA7XX_PM_L4PER_GPIO3_WKDEP_OFFSET                     0x0068
+#define DRA7XX_RM_L4PER_GPIO3_CONTEXT_OFFSET                   0x006c
+#define DRA7XX_PM_L4PER_GPIO4_WKDEP_OFFSET                     0x0070
+#define DRA7XX_RM_L4PER_GPIO4_CONTEXT_OFFSET                   0x0074
+#define DRA7XX_PM_L4PER_GPIO5_WKDEP_OFFSET                     0x0078
+#define DRA7XX_RM_L4PER_GPIO5_CONTEXT_OFFSET                   0x007c
+#define DRA7XX_PM_L4PER_GPIO6_WKDEP_OFFSET                     0x0080
+#define DRA7XX_RM_L4PER_GPIO6_CONTEXT_OFFSET                   0x0084
+#define DRA7XX_RM_L4PER_HDQ1W_CONTEXT_OFFSET                   0x008c
+#define DRA7XX_RM_L4PER2_PWMSS2_CONTEXT_OFFSET                 0x0094
+#define DRA7XX_RM_L4PER2_PWMSS3_CONTEXT_OFFSET                 0x009c
+#define DRA7XX_PM_L4PER_I2C1_WKDEP_OFFSET                      0x00a0
+#define DRA7XX_RM_L4PER_I2C1_CONTEXT_OFFSET                    0x00a4
+#define DRA7XX_PM_L4PER_I2C2_WKDEP_OFFSET                      0x00a8
+#define DRA7XX_RM_L4PER_I2C2_CONTEXT_OFFSET                    0x00ac
+#define DRA7XX_PM_L4PER_I2C3_WKDEP_OFFSET                      0x00b0
+#define DRA7XX_RM_L4PER_I2C3_CONTEXT_OFFSET                    0x00b4
+#define DRA7XX_PM_L4PER_I2C4_WKDEP_OFFSET                      0x00b8
+#define DRA7XX_RM_L4PER_I2C4_CONTEXT_OFFSET                    0x00bc
+#define DRA7XX_RM_L4PER_L4PER1_CONTEXT_OFFSET                  0x00c0
+#define DRA7XX_RM_L4PER2_PWMSS1_CONTEXT_OFFSET                 0x00c4
+#define DRA7XX_PM_L4PER_TIMER13_WKDEP_OFFSET                   0x00c8
+#define DRA7XX_RM_L4PER3_TIMER13_CONTEXT_OFFSET                        0x00cc
+#define DRA7XX_PM_L4PER_TIMER14_WKDEP_OFFSET                   0x00d0
+#define DRA7XX_RM_L4PER3_TIMER14_CONTEXT_OFFSET                        0x00d4
+#define DRA7XX_PM_L4PER_TIMER15_WKDEP_OFFSET                   0x00d8
+#define DRA7XX_RM_L4PER3_TIMER15_CONTEXT_OFFSET                        0x00dc
+#define DRA7XX_PM_L4PER_MCSPI1_WKDEP_OFFSET                    0x00f0
+#define DRA7XX_RM_L4PER_MCSPI1_CONTEXT_OFFSET                  0x00f4
+#define DRA7XX_PM_L4PER_MCSPI2_WKDEP_OFFSET                    0x00f8
+#define DRA7XX_RM_L4PER_MCSPI2_CONTEXT_OFFSET                  0x00fc
+#define DRA7XX_PM_L4PER_MCSPI3_WKDEP_OFFSET                    0x0100
+#define DRA7XX_RM_L4PER_MCSPI3_CONTEXT_OFFSET                  0x0104
+#define DRA7XX_PM_L4PER_MCSPI4_WKDEP_OFFSET                    0x0108
+#define DRA7XX_RM_L4PER_MCSPI4_CONTEXT_OFFSET                  0x010c
+#define DRA7XX_PM_L4PER_GPIO7_WKDEP_OFFSET                     0x0110
+#define DRA7XX_RM_L4PER_GPIO7_CONTEXT_OFFSET                   0x0114
+#define DRA7XX_PM_L4PER_GPIO8_WKDEP_OFFSET                     0x0118
+#define DRA7XX_RM_L4PER_GPIO8_CONTEXT_OFFSET                   0x011c
+#define DRA7XX_PM_L4PER_MMC3_WKDEP_OFFSET                      0x0120
+#define DRA7XX_RM_L4PER_MMC3_CONTEXT_OFFSET                    0x0124
+#define DRA7XX_PM_L4PER_MMC4_WKDEP_OFFSET                      0x0128
+#define DRA7XX_RM_L4PER_MMC4_CONTEXT_OFFSET                    0x012c
+#define DRA7XX_PM_L4PER_TIMER16_WKDEP_OFFSET                   0x0130
+#define DRA7XX_RM_L4PER3_TIMER16_CONTEXT_OFFSET                        0x0134
+#define DRA7XX_PM_L4PER2_QSPI_WKDEP_OFFSET                     0x0138
+#define DRA7XX_RM_L4PER2_QSPI_CONTEXT_OFFSET                   0x013c
+#define DRA7XX_PM_L4PER_UART1_WKDEP_OFFSET                     0x0140
+#define DRA7XX_RM_L4PER_UART1_CONTEXT_OFFSET                   0x0144
+#define DRA7XX_PM_L4PER_UART2_WKDEP_OFFSET                     0x0148
+#define DRA7XX_RM_L4PER_UART2_CONTEXT_OFFSET                   0x014c
+#define DRA7XX_PM_L4PER_UART3_WKDEP_OFFSET                     0x0150
+#define DRA7XX_RM_L4PER_UART3_CONTEXT_OFFSET                   0x0154
+#define DRA7XX_PM_L4PER_UART4_WKDEP_OFFSET                     0x0158
+#define DRA7XX_RM_L4PER_UART4_CONTEXT_OFFSET                   0x015c
+#define DRA7XX_PM_L4PER2_MCASP2_WKDEP_OFFSET                   0x0160
+#define DRA7XX_RM_L4PER2_MCASP2_CONTEXT_OFFSET                 0x0164
+#define DRA7XX_PM_L4PER2_MCASP3_WKDEP_OFFSET                   0x0168
+#define DRA7XX_RM_L4PER2_MCASP3_CONTEXT_OFFSET                 0x016c
+#define DRA7XX_PM_L4PER_UART5_WKDEP_OFFSET                     0x0170
+#define DRA7XX_RM_L4PER_UART5_CONTEXT_OFFSET                   0x0174
+#define DRA7XX_PM_L4PER2_MCASP5_WKDEP_OFFSET                   0x0178
+#define DRA7XX_RM_L4PER2_MCASP5_CONTEXT_OFFSET                 0x017c
+#define DRA7XX_PM_L4PER2_MCASP6_WKDEP_OFFSET                   0x0180
+#define DRA7XX_RM_L4PER2_MCASP6_CONTEXT_OFFSET                 0x0184
+#define DRA7XX_PM_L4PER2_MCASP7_WKDEP_OFFSET                   0x0188
+#define DRA7XX_RM_L4PER2_MCASP7_CONTEXT_OFFSET                 0x018c
+#define DRA7XX_PM_L4PER2_MCASP8_WKDEP_OFFSET                   0x0190
+#define DRA7XX_RM_L4PER2_MCASP8_CONTEXT_OFFSET                 0x0194
+#define DRA7XX_PM_L4PER2_MCASP4_WKDEP_OFFSET                   0x0198
+#define DRA7XX_RM_L4PER2_MCASP4_CONTEXT_OFFSET                 0x019c
+#define DRA7XX_RM_L4SEC_AES1_CONTEXT_OFFSET                    0x01a4
+#define DRA7XX_RM_L4SEC_AES2_CONTEXT_OFFSET                    0x01ac
+#define DRA7XX_RM_L4SEC_DES3DES_CONTEXT_OFFSET                 0x01b4
+#define DRA7XX_RM_L4SEC_FPKA_CONTEXT_OFFSET                    0x01bc
+#define DRA7XX_RM_L4SEC_RNG_CONTEXT_OFFSET                     0x01c4
+#define DRA7XX_RM_L4SEC_SHA2MD51_CONTEXT_OFFSET                        0x01cc
+#define DRA7XX_PM_L4PER2_UART7_WKDEP_OFFSET                    0x01d0
+#define DRA7XX_RM_L4PER2_UART7_CONTEXT_OFFSET                  0x01d4
+#define DRA7XX_RM_L4SEC_DMA_CRYPTO_CONTEXT_OFFSET              0x01dc
+#define DRA7XX_PM_L4PER2_UART8_WKDEP_OFFSET                    0x01e0
+#define DRA7XX_RM_L4PER2_UART8_CONTEXT_OFFSET                  0x01e4
+#define DRA7XX_PM_L4PER2_UART9_WKDEP_OFFSET                    0x01e8
+#define DRA7XX_RM_L4PER2_UART9_CONTEXT_OFFSET                  0x01ec
+#define DRA7XX_PM_L4PER2_DCAN2_WKDEP_OFFSET                    0x01f0
+#define DRA7XX_RM_L4PER2_DCAN2_CONTEXT_OFFSET                  0x01f4
+#define DRA7XX_RM_L4SEC_SHA2MD52_CONTEXT_OFFSET                        0x01fc
+
+/* PRM.CUSTEFUSE_PRM register offsets */
+#define DRA7XX_PM_CUSTEFUSE_PWRSTCTRL_OFFSET                   0x0000
+#define DRA7XX_PM_CUSTEFUSE_PWRSTST_OFFSET                     0x0004
+#define DRA7XX_RM_CUSTEFUSE_EFUSE_CTRL_CUST_CONTEXT_OFFSET     0x0024
+
+/* PRM.WKUPAON_PRM register offsets */
+#define DRA7XX_RM_WKUPAON_L4_WKUP_CONTEXT_OFFSET               0x0000
+#define DRA7XX_PM_WKUPAON_WD_TIMER1_WKDEP_OFFSET               0x0004
+#define DRA7XX_RM_WKUPAON_WD_TIMER1_CONTEXT_OFFSET             0x0008
+#define DRA7XX_PM_WKUPAON_WD_TIMER2_WKDEP_OFFSET               0x000c
+#define DRA7XX_RM_WKUPAON_WD_TIMER2_CONTEXT_OFFSET             0x0010
+#define DRA7XX_PM_WKUPAON_GPIO1_WKDEP_OFFSET                   0x0014
+#define DRA7XX_RM_WKUPAON_GPIO1_CONTEXT_OFFSET                 0x0018
+#define DRA7XX_PM_WKUPAON_TIMER1_WKDEP_OFFSET                  0x001c
+#define DRA7XX_RM_WKUPAON_TIMER1_CONTEXT_OFFSET                        0x0020
+#define DRA7XX_PM_WKUPAON_TIMER12_WKDEP_OFFSET                 0x0024
+#define DRA7XX_RM_WKUPAON_TIMER12_CONTEXT_OFFSET               0x0028
+#define DRA7XX_RM_WKUPAON_COUNTER_32K_CONTEXT_OFFSET           0x0030
+#define DRA7XX_RM_WKUPAON_SAR_RAM_CONTEXT_OFFSET               0x0040
+#define DRA7XX_PM_WKUPAON_KBD_WKDEP_OFFSET                     0x0054
+#define DRA7XX_RM_WKUPAON_KBD_CONTEXT_OFFSET                   0x0058
+#define DRA7XX_PM_WKUPAON_UART10_WKDEP_OFFSET                  0x005c
+#define DRA7XX_RM_WKUPAON_UART10_CONTEXT_OFFSET                        0x0060
+#define DRA7XX_PM_WKUPAON_DCAN1_WKDEP_OFFSET                   0x0064
+#define DRA7XX_RM_WKUPAON_DCAN1_CONTEXT_OFFSET                 0x0068
+#define DRA7XX_PM_WKUPAON_ADC_WKDEP_OFFSET                             0x007c
+#define DRA7XX_RM_WKUPAON_ADC_CONTEXT_OFFSET                   0x0080
+#define DRA7XX_RM_WKUPAON_SPARE_SAFETY1_CONTEXT_OFFSET         0x0090
+#define DRA7XX_RM_WKUPAON_SPARE_SAFETY2_CONTEXT_OFFSET         0x0098
+#define DRA7XX_RM_WKUPAON_SPARE_SAFETY3_CONTEXT_OFFSET         0x00a0
+#define DRA7XX_RM_WKUPAON_SPARE_SAFETY4_CONTEXT_OFFSET         0x00a8
+#define DRA7XX_RM_WKUPAON_SPARE_UNKNOWN2_CONTEXT_OFFSET                0x00b0
+#define DRA7XX_RM_WKUPAON_SPARE_UNKNOWN3_CONTEXT_OFFSET                0x00b8
+
+/* PRM.WKUPAON_CM register offsets */
+#define DRA7XX_CM_WKUPAON_CLKSTCTRL_OFFSET                     0x0000
+#define DRA7XX_CM_WKUPAON_L4_WKUP_CLKCTRL_OFFSET               0x0020
+#define DRA7XX_CM_WKUPAON_L4_WKUP_CLKCTRL                      DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0020)
+#define DRA7XX_CM_WKUPAON_WD_TIMER1_CLKCTRL_OFFSET             0x0028
+#define DRA7XX_CM_WKUPAON_WD_TIMER1_CLKCTRL                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0028)
+#define DRA7XX_CM_WKUPAON_WD_TIMER2_CLKCTRL_OFFSET             0x0030
+#define DRA7XX_CM_WKUPAON_WD_TIMER2_CLKCTRL                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0030)
+#define DRA7XX_CM_WKUPAON_GPIO1_CLKCTRL_OFFSET                 0x0038
+#define DRA7XX_CM_WKUPAON_GPIO1_CLKCTRL                                DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0038)
+#define DRA7XX_CM_WKUPAON_TIMER1_CLKCTRL_OFFSET                        0x0040
+#define DRA7XX_CM_WKUPAON_TIMER1_CLKCTRL                       DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0040)
+#define DRA7XX_CM_WKUPAON_TIMER12_CLKCTRL_OFFSET               0x0048
+#define DRA7XX_CM_WKUPAON_TIMER12_CLKCTRL                      DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0048)
+#define DRA7XX_CM_WKUPAON_COUNTER_32K_CLKCTRL_OFFSET           0x0050
+#define DRA7XX_CM_WKUPAON_COUNTER_32K_CLKCTRL                  DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0050)
+#define DRA7XX_CM_WKUPAON_SAR_RAM_CLKCTRL_OFFSET               0x0060
+#define DRA7XX_CM_WKUPAON_SAR_RAM_CLKCTRL                      DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0060)
+#define DRA7XX_CM_WKUPAON_KBD_CLKCTRL_OFFSET                   0x0078
+#define DRA7XX_CM_WKUPAON_KBD_CLKCTRL                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0078)
+#define DRA7XX_CM_WKUPAON_UART10_CLKCTRL_OFFSET                        0x0080
+#define DRA7XX_CM_WKUPAON_UART10_CLKCTRL                       DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0080)
+#define DRA7XX_CM_WKUPAON_DCAN1_CLKCTRL_OFFSET                 0x0088
+#define DRA7XX_CM_WKUPAON_DCAN1_CLKCTRL                                DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0088)
+#define DRA7XX_CM_WKUPAON_SCRM_CLKCTRL_OFFSET                  0x0090
+#define DRA7XX_CM_WKUPAON_SCRM_CLKCTRL                         DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0090)
+#define DRA7XX_CM_WKUPAON_IO_SRCOMP_CLKCTRL_OFFSET             0x0098
+#define DRA7XX_CM_WKUPAON_IO_SRCOMP_CLKCTRL                    DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x0098)
+#define DRA7XX_CM_WKUPAON_ADC_CLKCTRL_OFFSET                   0x00a0
+#define DRA7XX_CM_WKUPAON_ADC_CLKCTRL                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00a0)
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY1_CLKCTRL_OFFSET         0x00b0
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY1_CLKCTRL                        DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00b0)
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY2_CLKCTRL_OFFSET         0x00b8
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY2_CLKCTRL                        DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00b8)
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY3_CLKCTRL_OFFSET         0x00c0
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY3_CLKCTRL                        DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00c0)
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY4_CLKCTRL_OFFSET         0x00c8
+#define DRA7XX_CM_WKUPAON_SPARE_SAFETY4_CLKCTRL                        DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00c8)
+#define DRA7XX_CM_WKUPAON_SPARE_UNKNOWN2_CLKCTRL_OFFSET                0x00d0
+#define DRA7XX_CM_WKUPAON_SPARE_UNKNOWN2_CLKCTRL               DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00d0)
+#define DRA7XX_CM_WKUPAON_SPARE_UNKNOWN3_CLKCTRL_OFFSET                0x00d8
+#define DRA7XX_CM_WKUPAON_SPARE_UNKNOWN3_CLKCTRL               DRA7XX_PRM_REGADDR(DRA7XX_PRM_WKUPAON_CM_INST, 0x00d8)
+
+/* PRM.EMU_PRM register offsets */
+#define DRA7XX_PM_EMU_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_EMU_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_RM_EMU_DEBUGSS_CONTEXT_OFFSET                   0x0024
+
+/* PRM.EMU_CM register offsets */
+#define DRA7XX_CM_EMU_CLKSTCTRL_OFFSET                         0x0000
+#define DRA7XX_CM_EMU_DEBUGSS_CLKCTRL_OFFSET                   0x0004
+#define DRA7XX_CM_EMU_DEBUGSS_CLKCTRL                          DRA7XX_PRM_REGADDR(DRA7XX_PRM_EMU_CM_INST, 0x0004)
+#define DRA7XX_CM_EMU_DYNAMICDEP_OFFSET                                0x0008
+#define DRA7XX_CM_EMU_MPU_EMU_DBG_CLKCTRL_OFFSET               0x000c
+#define DRA7XX_CM_EMU_MPU_EMU_DBG_CLKCTRL                      DRA7XX_PRM_REGADDR(DRA7XX_PRM_EMU_CM_INST, 0x000c)
+
+/* PRM.DSP2_PRM register offsets */
+#define DRA7XX_PM_DSP2_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_DSP2_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_DSP2_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_DSP2_RSTST_OFFSET                            0x0014
+#define DRA7XX_RM_DSP2_DSP2_CONTEXT_OFFSET                     0x0024
+
+/* PRM.EVE1_PRM register offsets */
+#define DRA7XX_PM_EVE1_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_EVE1_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_EVE1_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_EVE1_RSTST_OFFSET                            0x0014
+#define DRA7XX_PM_EVE1_EVE1_WKDEP_OFFSET                       0x0020
+#define DRA7XX_RM_EVE1_EVE1_CONTEXT_OFFSET                     0x0024
+
+/* PRM.EVE2_PRM register offsets */
+#define DRA7XX_PM_EVE2_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_EVE2_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_EVE2_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_EVE2_RSTST_OFFSET                            0x0014
+#define DRA7XX_PM_EVE2_EVE2_WKDEP_OFFSET                       0x0020
+#define DRA7XX_RM_EVE2_EVE2_CONTEXT_OFFSET                     0x0024
+
+/* PRM.EVE3_PRM register offsets */
+#define DRA7XX_PM_EVE3_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_EVE3_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_EVE3_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_EVE3_RSTST_OFFSET                            0x0014
+#define DRA7XX_PM_EVE3_EVE3_WKDEP_OFFSET                       0x0020
+#define DRA7XX_RM_EVE3_EVE3_CONTEXT_OFFSET                     0x0024
+
+/* PRM.EVE4_PRM register offsets */
+#define DRA7XX_PM_EVE4_PWRSTCTRL_OFFSET                                0x0000
+#define DRA7XX_PM_EVE4_PWRSTST_OFFSET                          0x0004
+#define DRA7XX_RM_EVE4_RSTCTRL_OFFSET                          0x0010
+#define DRA7XX_RM_EVE4_RSTST_OFFSET                            0x0014
+#define DRA7XX_PM_EVE4_EVE4_WKDEP_OFFSET                       0x0020
+#define DRA7XX_RM_EVE4_EVE4_CONTEXT_OFFSET                     0x0024
+
+/* PRM.RTC_PRM register offsets */
+#define DRA7XX_PM_RTC_RTCSS_WKDEP_OFFSET                       0x0000
+#define DRA7XX_RM_RTC_RTCSS_CONTEXT_OFFSET                     0x0004
+
+/* PRM.VPE_PRM register offsets */
+#define DRA7XX_PM_VPE_PWRSTCTRL_OFFSET                         0x0000
+#define DRA7XX_PM_VPE_PWRSTST_OFFSET                           0x0004
+#define DRA7XX_PM_VPE_VPE_WKDEP_OFFSET                         0x0020
+#define DRA7XX_RM_VPE_VPE_CONTEXT_OFFSET                       0x0024
+
+/* PRM.DEVICE_PRM register offsets */
+#define DRA7XX_PRM_RSTCTRL_OFFSET                              0x0000
+#define DRA7XX_PRM_RSTST_OFFSET                                        0x0004
+#define DRA7XX_PRM_RSTTIME_OFFSET                              0x0008
+#define DRA7XX_PRM_CLKREQCTRL_OFFSET                           0x000c
+#define DRA7XX_PRM_VOLTCTRL_OFFSET                             0x0010
+#define DRA7XX_PRM_PWRREQCTRL_OFFSET                           0x0014
+#define DRA7XX_PRM_PSCON_COUNT_OFFSET                          0x0018
+#define DRA7XX_PRM_IO_COUNT_OFFSET                             0x001c
+#define DRA7XX_PRM_IO_PMCTRL_OFFSET                            0x0020
+#define DRA7XX_PRM_VOLTSETUP_WARMRESET_OFFSET                  0x0024
+#define DRA7XX_PRM_VOLTSETUP_CORE_OFF_OFFSET                   0x0028
+#define DRA7XX_PRM_VOLTSETUP_MPU_OFF_OFFSET                    0x002c
+#define DRA7XX_PRM_VOLTSETUP_MM_OFF_OFFSET                     0x0030
+#define DRA7XX_PRM_VOLTSETUP_CORE_RET_SLEEP_OFFSET             0x0034
+#define DRA7XX_PRM_VOLTSETUP_MPU_RET_SLEEP_OFFSET              0x0038
+#define DRA7XX_PRM_VOLTSETUP_MM_RET_SLEEP_OFFSET               0x003c
+#define DRA7XX_PRM_SRAM_COUNT_OFFSET                           0x00bc
+#define DRA7XX_PRM_SRAM_WKUP_SETUP_OFFSET                      0x00c0
+#define DRA7XX_PRM_SLDO_CORE_SETUP_OFFSET                      0x00c4
+#define DRA7XX_PRM_SLDO_CORE_CTRL_OFFSET                       0x00c8
+#define DRA7XX_PRM_SLDO_MPU_SETUP_OFFSET                       0x00cc
+#define DRA7XX_PRM_SLDO_MPU_CTRL_OFFSET                                0x00d0
+#define DRA7XX_PRM_SLDO_GPU_SETUP_OFFSET                       0x00d4
+#define DRA7XX_PRM_SLDO_GPU_CTRL_OFFSET                                0x00d8
+#define DRA7XX_PRM_ABBLDO_MPU_SETUP_OFFSET                     0x00dc
+#define DRA7XX_PRM_ABBLDO_MPU_CTRL_OFFSET                      0x00e0
+#define DRA7XX_PRM_ABBLDO_GPU_SETUP_OFFSET                     0x00e4
+#define DRA7XX_PRM_ABBLDO_GPU_CTRL_OFFSET                      0x00e8
+#define DRA7XX_PRM_BANDGAP_SETUP_OFFSET                                0x00ec
+#define DRA7XX_PRM_DEVICE_OFF_CTRL_OFFSET                      0x00f0
+#define DRA7XX_PRM_PHASE1_CNDP_OFFSET                          0x00f4
+#define DRA7XX_PRM_PHASE2A_CNDP_OFFSET                         0x00f8
+#define DRA7XX_PRM_PHASE2B_CNDP_OFFSET                         0x00fc
+#define DRA7XX_PRM_MODEM_IF_CTRL_OFFSET                                0x0100
+#define DRA7XX_PRM_VOLTST_MPU_OFFSET                           0x0110
+#define DRA7XX_PRM_VOLTST_MM_OFFSET                            0x0114
+#define DRA7XX_PRM_SLDO_DSPEVE_SETUP_OFFSET                    0x0118
+#define DRA7XX_PRM_SLDO_IVA_SETUP_OFFSET                       0x011c
+#define DRA7XX_PRM_ABBLDO_DSPEVE_CTRL_OFFSET                   0x0120
+#define DRA7XX_PRM_ABBLDO_IVA_CTRL_OFFSET                      0x0124
+#define DRA7XX_PRM_SLDO_DSPEVE_CTRL_OFFSET                     0x0128
+#define DRA7XX_PRM_SLDO_IVA_CTRL_OFFSET                                0x012c
+#define DRA7XX_PRM_ABBLDO_DSPEVE_SETUP_OFFSET                  0x0130
+#define DRA7XX_PRM_ABBLDO_IVA_SETUP_OFFSET                     0x0134
+
+#endif
index c12320c0ae952e46d05a40d50d6d260994ff98d7..6334b96b4097b6977ae29047040bf6990aed06a7 100644 (file)
 #include "common.h"
 #include "prcm-common.h"
 #include "prm44xx.h"
+#include "prm54xx.h"
+#include "prm7xx.h"
 #include "prminst44xx.h"
 #include "prm-regbits-44xx.h"
 #include "prcm44xx.h"
 #include "prcm_mpu44xx.h"
+#include "soc.h"
 
 static void __iomem *_prm_bases[OMAP4_MAX_PRCM_PARTITIONS];
 
@@ -165,10 +168,19 @@ int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst,
 void omap4_prminst_global_warm_sw_reset(void)
 {
        u32 v;
-
-       v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION,
-                                   OMAP4430_PRM_DEVICE_INST,
-                                   OMAP4_PRM_RSTCTRL_OFFSET);
+       s16 dev_inst;
+
+       if (cpu_is_omap44xx())
+               dev_inst = OMAP4430_PRM_DEVICE_INST;
+       else if (soc_is_omap54xx())
+               dev_inst = OMAP54XX_PRM_DEVICE_INST;
+       else if (soc_is_dra7xx())
+               dev_inst = DRA7XX_PRM_DEVICE_INST;
+       else
+               return;
+
+       v = omap4_prminst_read_inst_reg(OMAP4430_PRM_PARTITION, dev_inst,
+                                       OMAP4_PRM_RSTCTRL_OFFSET);
        v |= OMAP4430_RST_GLOBAL_WARM_SW_MASK;
        omap4_prminst_write_inst_reg(v, OMAP4430_PRM_PARTITION,
                                 OMAP4430_PRM_DEVICE_INST,
index e817fde6729a7ac55e07bf5e3f5b33f34c2fc043..1f94c310c4775f3a40e168e84845d4da6dbd40ab 100644 (file)
@@ -109,18 +109,22 @@ config ARCH_EMEV2
 
 comment "SH-Mobile Board Type"
 
-config MACH_AG5EVM
-       bool "AG5EVM board"
-       depends on ARCH_SH73A0
-       select ARCH_REQUIRE_GPIOLIB
-       select REGULATOR_FIXED_VOLTAGE if REGULATOR
-       select SH_LCD_MIPI_DSI
-
 config MACH_APE6EVM
        bool "APE6EVM board"
        depends on ARCH_R8A73A4
        select USE_OF
 
+config MACH_APE6EVM_REFERENCE
+       bool "APE6EVM board - Reference Device Tree Implementation"
+       depends on ARCH_R8A73A4
+       select USE_OF
+       ---help---
+          Use reference implementation of APE6EVM board support
+          which makes a greater use of device tree at the expense
+          of not supporting a number of devices.
+
+          This is intended to aid developers
+
 config MACH_MACKEREL
        bool "mackerel board"
        depends on ARCH_SH7372
@@ -129,12 +133,6 @@ config MACH_MACKEREL
        select SND_SOC_AK4642 if SND_SIMPLE_CARD
        select USE_OF
 
-config MACH_KOTA2
-       bool "KOTA2 board"
-       depends on ARCH_SH73A0
-       select ARCH_REQUIRE_GPIOLIB
-       select REGULATOR_FIXED_VOLTAGE if REGULATOR
-
 config MACH_ARMADILLO800EVA
        bool "Armadillo-800 EVA board"
        depends on ARCH_R8A7740
@@ -165,11 +163,26 @@ config MACH_BOCKW
        select REGULATOR_FIXED_VOLTAGE if REGULATOR
        select USE_OF
 
+config MACH_BOCKW_REFERENCE
+       bool "BOCK-W  - Reference Device Tree Implementation"
+       depends on ARCH_R8A7778
+       select ARCH_REQUIRE_GPIOLIB
+       select RENESAS_INTC_IRQPIN
+       select REGULATOR_FIXED_VOLTAGE if REGULATOR
+       select USE_OF
+       ---help---
+          Use reference implementation of BockW board support
+          which makes use of device tree at the expense
+          of not supporting a number of devices.
+
+          This is intended to aid developers
+
 config MACH_MARZEN
        bool "MARZEN board"
        depends on ARCH_R8A7779
        select ARCH_REQUIRE_GPIOLIB
        select REGULATOR_FIXED_VOLTAGE if REGULATOR
+       select USE_OF
 
 config MACH_MARZEN_REFERENCE
        bool "MARZEN board - Reference Device Tree Implementation"
@@ -189,6 +202,17 @@ config MACH_LAGER
        depends on ARCH_R8A7790
        select USE_OF
 
+config MACH_LAGER_REFERENCE
+       bool "Lager board - Reference Device Tree Implementation"
+       depends on ARCH_R8A7790
+       select USE_OF
+       ---help---
+          Use reference implementation of Lager board support
+          which makes use of device tree at the expense
+          of not supporting a number of devices.
+
+          This is intended to aid developers
+
 config MACH_KZM9D
        bool "KZM9D board"
        depends on ARCH_EMEV2
index b150c4508237beac48a76e2ee37b60125cfae1d8..2705bfa8c113161d0368e11e7f7158a294cb26a6 100644 (file)
@@ -11,9 +11,9 @@ obj-y                         := timer.o console.o
 obj-$(CONFIG_ARCH_SH7372)      += setup-sh7372.o intc-sh7372.o
 obj-$(CONFIG_ARCH_SH73A0)      += setup-sh73a0.o intc-sh73a0.o
 obj-$(CONFIG_ARCH_R8A73A4)     += setup-r8a73a4.o
-obj-$(CONFIG_ARCH_R8A7740)     += setup-r8a7740.o intc-r8a7740.o
+obj-$(CONFIG_ARCH_R8A7740)     += setup-r8a7740.o
 obj-$(CONFIG_ARCH_R8A7778)     += setup-r8a7778.o
-obj-$(CONFIG_ARCH_R8A7779)     += setup-r8a7779.o intc-r8a7779.o
+obj-$(CONFIG_ARCH_R8A7779)     += setup-r8a7779.o
 obj-$(CONFIG_ARCH_R8A7790)     += setup-r8a7790.o
 obj-$(CONFIG_ARCH_EMEV2)       += setup-emev2.o
 
@@ -32,32 +32,31 @@ endif
 
 # SMP objects
 smp-y                          := platsmp.o headsmp.o
-smp-$(CONFIG_ARCH_SH73A0)      += smp-sh73a0.o headsmp-scu.o
-smp-$(CONFIG_ARCH_R8A7779)     += smp-r8a7779.o headsmp-scu.o
-smp-$(CONFIG_ARCH_EMEV2)       += smp-emev2.o headsmp-scu.o
+smp-$(CONFIG_ARCH_SH73A0)      += smp-sh73a0.o headsmp-scu.o platsmp-scu.o
+smp-$(CONFIG_ARCH_R8A7779)     += smp-r8a7779.o headsmp-scu.o platsmp-scu.o
+smp-$(CONFIG_ARCH_EMEV2)       += smp-emev2.o headsmp-scu.o platsmp-scu.o
 
 # IRQ objects
 obj-$(CONFIG_ARCH_SH7372)      += entry-intc.o
-obj-$(CONFIG_ARCH_R8A7740)     += entry-intc.o
 
 # PM objects
 obj-$(CONFIG_SUSPEND)          += suspend.o
 obj-$(CONFIG_CPU_IDLE)         += cpuidle.o
-obj-$(CONFIG_ARCH_SHMOBILE)    += pm-rmobile.o
-obj-$(CONFIG_ARCH_SH7372)      += pm-sh7372.o sleep-sh7372.o
-obj-$(CONFIG_ARCH_R8A7740)     += pm-r8a7740.o
-obj-$(CONFIG_ARCH_R8A7779)     += pm-r8a7779.o
+obj-$(CONFIG_ARCH_SH7372)      += pm-sh7372.o sleep-sh7372.o pm-rmobile.o
 obj-$(CONFIG_ARCH_SH73A0)      += pm-sh73a0.o
+obj-$(CONFIG_ARCH_R8A7740)     += pm-r8a7740.o pm-rmobile.o
+obj-$(CONFIG_ARCH_R8A7779)     += pm-r8a7779.o
 
 # Board objects
-obj-$(CONFIG_MACH_AG5EVM)      += board-ag5evm.o
 obj-$(CONFIG_MACH_APE6EVM)     += board-ape6evm.o
+obj-$(CONFIG_MACH_APE6EVM_REFERENCE)   += board-ape6evm-reference.o
 obj-$(CONFIG_MACH_MACKEREL)    += board-mackerel.o
-obj-$(CONFIG_MACH_KOTA2)       += board-kota2.o
 obj-$(CONFIG_MACH_BOCKW)       += board-bockw.o
+obj-$(CONFIG_MACH_BOCKW_REFERENCE)     += board-bockw-reference.o
 obj-$(CONFIG_MACH_MARZEN)      += board-marzen.o
 obj-$(CONFIG_MACH_MARZEN_REFERENCE)    += board-marzen-reference.o
 obj-$(CONFIG_MACH_LAGER)       += board-lager.o
+obj-$(CONFIG_MACH_LAGER_REFERENCE)     += board-lager-reference.o
 obj-$(CONFIG_MACH_ARMADILLO800EVA)     += board-armadillo800eva.o
 obj-$(CONFIG_MACH_ARMADILLO800EVA_REFERENCE)   += board-armadillo800eva-reference.o
 obj-$(CONFIG_MACH_KZM9D)       += board-kzm9d.o
index 7785c52b5cfdfd0f509375c6491a50d501057930..6a504fe7d86c45cb1c9c43a746bfe5beecfca7bb 100644 (file)
@@ -1,16 +1,17 @@
 # per-board load address for uImage
 loadaddr-y     :=
-loadaddr-$(CONFIG_MACH_AG5EVM) += 0x40008000
 loadaddr-$(CONFIG_MACH_APE6EVM) += 0x40008000
+loadaddr-$(CONFIG_MACH_APE6EVM_REFERENCE) += 0x40008000
 loadaddr-$(CONFIG_MACH_ARMADILLO800EVA) += 0x40008000
 loadaddr-$(CONFIG_MACH_ARMADILLO800EVA_REFERENCE) += 0x40008000
 loadaddr-$(CONFIG_MACH_BOCKW) += 0x60008000
-loadaddr-$(CONFIG_MACH_KOTA2) += 0x41008000
+loadaddr-$(CONFIG_MACH_BOCKW_REFERENCE) += 0x60008000
 loadaddr-$(CONFIG_MACH_KZM9D) += 0x40008000
 loadaddr-$(CONFIG_MACH_KZM9D_REFERENCE) += 0x40008000
 loadaddr-$(CONFIG_MACH_KZM9G) += 0x41008000
 loadaddr-$(CONFIG_MACH_KZM9G_REFERENCE) += 0x41008000
 loadaddr-$(CONFIG_MACH_LAGER) += 0x40008000
+loadaddr-$(CONFIG_MACH_LAGER_REFERENCE) += 0x40008000
 loadaddr-$(CONFIG_MACH_MACKEREL) += 0x40008000
 loadaddr-$(CONFIG_MACH_MARZEN) += 0x60008000
 loadaddr-$(CONFIG_MACH_MARZEN_REFERENCE) += 0x60008000
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c
deleted file mode 100644 (file)
index f6d6449..0000000
+++ /dev/null
@@ -1,639 +0,0 @@
-/*
- * arch/arm/mach-shmobile/board-ag5evm.c
- *
- * Copyright (C) 2010  Takashi Yoshii <yoshii.takashi.zj@renesas.com>
- * Copyright (C) 2009  Yoshihiro Shimoda <shimoda.yoshihiro@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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/pinctrl/pinconf-generic.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/dma-mapping.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-#include <linux/serial_sci.h>
-#include <linux/smsc911x.h>
-#include <linux/gpio.h>
-#include <linux/videodev2.h>
-#include <linux/input.h>
-#include <linux/input/sh_keysc.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <linux/mfd/tmio.h>
-#include <linux/platform_data/bd6107.h>
-#include <linux/sh_clk.h>
-#include <linux/irqchip/arm-gic.h>
-#include <video/sh_mobile_lcdc.h>
-#include <video/sh_mipi_dsi.h>
-#include <sound/sh_fsi.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/sh73a0.h>
-#include <mach/common.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <asm/traps.h>
-
-/* Dummy supplies, where voltage doesn't matter */
-static struct regulator_consumer_supply dummy_supplies[] = {
-       REGULATOR_SUPPLY("vddvario", "smsc911x"),
-       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
-};
-
-static struct resource smsc9220_resources[] = {
-       [0] = {
-               .start          = 0x14000000,
-               .end            = 0x14000000 + SZ_64K - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = SH73A0_PINT0_IRQ(2), /* PINTA2 */
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct smsc911x_platform_config smsc9220_platdata = {
-       .flags          = SMSC911X_USE_32BIT | SMSC911X_SAVE_MAC_ADDRESS,
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
-};
-
-static struct platform_device eth_device = {
-       .name           = "smsc911x",
-       .id             = 0,
-       .dev  = {
-               .platform_data = &smsc9220_platdata,
-       },
-       .resource       = smsc9220_resources,
-       .num_resources  = ARRAY_SIZE(smsc9220_resources),
-};
-
-static struct sh_keysc_info keysc_platdata = {
-       .mode           = SH_KEYSC_MODE_6,
-       .scan_timing    = 3,
-       .delay          = 100,
-       .keycodes       = {
-               KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G,
-               KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N,
-               KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U,
-               KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_HOME, KEY_SLEEP,
-               KEY_SPACE, KEY_9, KEY_6, KEY_3, KEY_WAKEUP, KEY_RIGHT, \
-               KEY_COFFEE,
-               KEY_0, KEY_8, KEY_5, KEY_2, KEY_DOWN, KEY_ENTER, KEY_UP,
-               KEY_KPASTERISK, KEY_7, KEY_4, KEY_1, KEY_STOP, KEY_LEFT, \
-               KEY_COMPUTER,
-       },
-};
-
-static struct resource keysc_resources[] = {
-       [0] = {
-               .name   = "KEYSC",
-               .start  = 0xe61b0000,
-               .end    = 0xe61b0098 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(71),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device keysc_device = {
-       .name           = "sh_keysc",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(keysc_resources),
-       .resource       = keysc_resources,
-       .dev            = {
-               .platform_data  = &keysc_platdata,
-       },
-};
-
-/* FSI A */
-static struct resource fsi_resources[] = {
-       [0] = {
-               .name   = "FSI",
-               .start  = 0xEC230000,
-               .end    = 0xEC230400 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(146),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device fsi_device = {
-       .name           = "sh_fsi2",
-       .id             = -1,
-       .num_resources  = ARRAY_SIZE(fsi_resources),
-       .resource       = fsi_resources,
-};
-
-/* Fixed 1.8V regulator to be used by MMCIF */
-static struct regulator_consumer_supply fixed1v8_power_consumers[] =
-{
-       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
-       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
-};
-
-static struct resource sh_mmcif_resources[] = {
-       [0] = {
-               .name   = "MMCIF",
-               .start  = 0xe6bd0000,
-               .end    = 0xe6bd00ff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(141),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = gic_spi(140),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct sh_mmcif_plat_data sh_mmcif_platdata = {
-       .sup_pclk       = 0,
-       .ocr            = MMC_VDD_165_195,
-       .caps           = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
-       .slave_id_tx    = SHDMA_SLAVE_MMCIF_TX,
-       .slave_id_rx    = SHDMA_SLAVE_MMCIF_RX,
-};
-
-static struct platform_device mmc_device = {
-       .name           = "sh_mmcif",
-       .id             = 0,
-       .dev            = {
-               .dma_mask               = NULL,
-               .coherent_dma_mask      = 0xffffffff,
-               .platform_data          = &sh_mmcif_platdata,
-       },
-       .num_resources  = ARRAY_SIZE(sh_mmcif_resources),
-       .resource       = sh_mmcif_resources,
-};
-
-/* IrDA */
-static struct resource irda_resources[] = {
-       [0] = {
-               .start  = 0xE6D00000,
-               .end    = 0xE6D01FD4 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(95),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device irda_device = {
-       .name           = "sh_irda",
-       .id             = 0,
-       .resource       = irda_resources,
-       .num_resources  = ARRAY_SIZE(irda_resources),
-};
-
-/* MIPI-DSI */
-static struct resource mipidsi0_resources[] = {
-       [0] = {
-               .name   = "DSI0",
-               .start  = 0xfeab0000,
-               .end    = 0xfeab3fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .name   = "DSI0",
-               .start  = 0xfeab4000,
-               .end    = 0xfeab7fff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static int sh_mipi_set_dot_clock(struct platform_device *pdev,
-                                void __iomem *base,
-                                int enable)
-{
-       struct clk *pck, *phy;
-       int ret;
-
-       pck = clk_get(&pdev->dev, "dsip_clk");
-       if (IS_ERR(pck)) {
-               ret = PTR_ERR(pck);
-               goto sh_mipi_set_dot_clock_pck_err;
-       }
-
-       phy = clk_get(&pdev->dev, "dsiphy_clk");
-       if (IS_ERR(phy)) {
-               ret = PTR_ERR(phy);
-               goto sh_mipi_set_dot_clock_phy_err;
-       }
-
-       if (enable) {
-               clk_set_rate(pck, clk_round_rate(pck,  24000000));
-               clk_set_rate(phy, clk_round_rate(pck, 510000000));
-               clk_enable(pck);
-               clk_enable(phy);
-       } else {
-               clk_disable(pck);
-               clk_disable(phy);
-       }
-
-       ret = 0;
-
-       clk_put(phy);
-sh_mipi_set_dot_clock_phy_err:
-       clk_put(pck);
-sh_mipi_set_dot_clock_pck_err:
-       return ret;
-}
-
-static struct sh_mipi_dsi_info mipidsi0_info = {
-       .data_format    = MIPI_RGB888,
-       .channel        = LCDC_CHAN_MAINLCD,
-       .lane           = 2,
-       .vsynw_offset   = 20,
-       .clksrc         = 1,
-       .flags          = SH_MIPI_DSI_HSABM             |
-                         SH_MIPI_DSI_SYNC_PULSES_MODE  |
-                         SH_MIPI_DSI_HSbyteCLK,
-       .set_dot_clock  = sh_mipi_set_dot_clock,
-};
-
-static struct platform_device mipidsi0_device = {
-       .name           = "sh-mipi-dsi",
-       .num_resources  = ARRAY_SIZE(mipidsi0_resources),
-       .resource       = mipidsi0_resources,
-       .id             = 0,
-       .dev    = {
-               .platform_data  = &mipidsi0_info,
-       },
-};
-
-/* LCDC0 and backlight */
-static const struct fb_videomode lcdc0_modes[] = {
-       {
-               .name           = "R63302(QHD)",
-               .xres           = 544,
-               .yres           = 961,
-               .left_margin    = 72,
-               .right_margin   = 600,
-               .hsync_len      = 16,
-               .upper_margin   = 8,
-               .lower_margin   = 8,
-               .vsync_len      = 2,
-               .sync           = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
-       },
-};
-
-static struct sh_mobile_lcdc_info lcdc0_info = {
-       .clock_source = LCDC_CLK_PERIPHERAL,
-       .ch[0] = {
-               .chan = LCDC_CHAN_MAINLCD,
-               .interface_type = RGB24,
-               .clock_divider = 1,
-               .flags = LCDC_FLAGS_DWPOL,
-               .fourcc = V4L2_PIX_FMT_RGB565,
-               .lcd_modes = lcdc0_modes,
-               .num_modes = ARRAY_SIZE(lcdc0_modes),
-               .panel_cfg = {
-                       .width = 44,
-                       .height = 79,
-               },
-               .tx_dev = &mipidsi0_device,
-       }
-};
-
-static struct resource lcdc0_resources[] = {
-       [0] = {
-               .name   = "LCDC0",
-               .start  = 0xfe940000, /* P4-only space */
-               .end    = 0xfe943fff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = intcs_evt2irq(0x580),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device lcdc0_device = {
-       .name           = "sh_mobile_lcdc_fb",
-       .num_resources  = ARRAY_SIZE(lcdc0_resources),
-       .resource       = lcdc0_resources,
-       .id             = 0,
-       .dev    = {
-               .platform_data  = &lcdc0_info,
-               .coherent_dma_mask = ~0,
-       },
-};
-
-static struct bd6107_platform_data backlight_data = {
-       .fbdev = &lcdc0_device.dev,
-       .reset = 235,
-       .def_value = 0,
-};
-
-static struct i2c_board_info backlight_board_info = {
-       I2C_BOARD_INFO("bd6107", 0x6d),
-       .platform_data = &backlight_data,
-};
-
-/* Fixed 2.8V regulators to be used by SDHI0 */
-static struct regulator_consumer_supply fixed2v8_power_consumers[] =
-{
-       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
-       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
-};
-
-/* SDHI0 */
-static struct sh_mobile_sdhi_info sdhi0_info = {
-       .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
-       .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
-       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_USE_GPIO_CD,
-       .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
-       .tmio_ocr_mask  = MMC_VDD_27_28 | MMC_VDD_28_29,
-       .cd_gpio        = 251,
-};
-
-static struct resource sdhi0_resources[] = {
-       [0] = {
-               .name   = "SDHI0",
-               .start  = 0xee100000,
-               .end    = 0xee1000ff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .name   = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
-               .start  = gic_spi(83),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .name   = SH_MOBILE_SDHI_IRQ_SDCARD,
-               .start  = gic_spi(84),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .name   = SH_MOBILE_SDHI_IRQ_SDIO,
-               .start  = gic_spi(85),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device sdhi0_device = {
-       .name           = "sh_mobile_sdhi",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(sdhi0_resources),
-       .resource       = sdhi0_resources,
-       .dev    = {
-               .platform_data  = &sdhi0_info,
-       },
-};
-
-/* Fixed 3.3V regulator to be used by SDHI1 */
-static struct regulator_consumer_supply cn4_power_consumers[] =
-{
-       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
-       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
-};
-
-static struct regulator_init_data cn4_power_init_data = {
-       .constraints = {
-               .valid_ops_mask = REGULATOR_CHANGE_STATUS,
-       },
-       .num_consumer_supplies  = ARRAY_SIZE(cn4_power_consumers),
-       .consumer_supplies      = cn4_power_consumers,
-};
-
-static struct fixed_voltage_config cn4_power_info = {
-       .supply_name = "CN4 SD/MMC Vdd",
-       .microvolts = 3300000,
-       .gpio = 114,
-       .enable_high = 1,
-       .init_data = &cn4_power_init_data,
-};
-
-static struct platform_device cn4_power = {
-       .name = "reg-fixed-voltage",
-       .id   = 2,
-       .dev  = {
-               .platform_data = &cn4_power_info,
-       },
-};
-
-static void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state)
-{
-       static int power_gpio = -EINVAL;
-
-       if (power_gpio < 0) {
-               int ret = gpio_request_one(114, GPIOF_OUT_INIT_LOW,
-                                          "sdhi1_power");
-               if (!ret)
-                       power_gpio = 114;
-       }
-
-       /*
-        * If requesting the GPIO above failed, it means, that the regulator got
-        * probed and grabbed the GPIO, but we don't know, whether the sdhi
-        * driver already uses the regulator. If it doesn't, we have to toggle
-        * the GPIO ourselves, even though it is now owned by the fixed
-        * regulator driver. We have to live with the race in case the driver
-        * gets unloaded and the GPIO freed between these two steps.
-        */
-       gpio_set_value(114, state);
-}
-
-static struct sh_mobile_sdhi_info sh_sdhi1_info = {
-       .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
-       .tmio_caps      = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
-       .tmio_ocr_mask  = MMC_VDD_32_33 | MMC_VDD_33_34,
-       .set_pwr        = ag5evm_sdhi1_set_pwr,
-};
-
-static struct resource sdhi1_resources[] = {
-       [0] = {
-               .name   = "SDHI1",
-               .start  = 0xee120000,
-               .end    = 0xee1200ff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .name   = SH_MOBILE_SDHI_IRQ_CARD_DETECT,
-               .start  = gic_spi(87),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .name   = SH_MOBILE_SDHI_IRQ_SDCARD,
-               .start  = gic_spi(88),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .name   = SH_MOBILE_SDHI_IRQ_SDIO,
-               .start  = gic_spi(89),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device sdhi1_device = {
-       .name           = "sh_mobile_sdhi",
-       .id             = 1,
-       .dev            = {
-               .platform_data  = &sh_sdhi1_info,
-       },
-       .num_resources  = ARRAY_SIZE(sdhi1_resources),
-       .resource       = sdhi1_resources,
-};
-
-static struct platform_device *ag5evm_devices[] __initdata = {
-       &cn4_power,
-       &eth_device,
-       &keysc_device,
-       &fsi_device,
-       &mmc_device,
-       &irda_device,
-       &mipidsi0_device,
-       &lcdc0_device,
-       &sdhi0_device,
-       &sdhi1_device,
-};
-
-static unsigned long pin_pullup_conf[] = {
-       PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP, 0),
-};
-
-static const struct pinctrl_map ag5evm_pinctrl_map[] = {
-       /* FSIA */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_fsi2.0", "pfc-sh73a0",
-                                 "fsia_mclk_in", "fsia"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_fsi2.0", "pfc-sh73a0",
-                                 "fsia_sclk_in", "fsia"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_fsi2.0", "pfc-sh73a0",
-                                 "fsia_data_in", "fsia"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_fsi2.0", "pfc-sh73a0",
-                                 "fsia_data_out", "fsia"),
-       /* I2C2 & I2C3 */
-       PIN_MAP_MUX_GROUP_DEFAULT("i2c-sh_mobile.2", "pfc-sh73a0",
-                                 "i2c2_0", "i2c2"),
-       PIN_MAP_MUX_GROUP_DEFAULT("i2c-sh_mobile.3", "pfc-sh73a0",
-                                 "i2c3_0", "i2c3"),
-       /* IrDA */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_irda.0", "pfc-sh73a0",
-                                 "irda_0", "irda"),
-       /* KEYSC */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_in8", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out04", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out5", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out6_0", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out7_0", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out8_0", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out9_2", "keysc"),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                     "keysc_in8", pin_pullup_conf),
-       /* MMCIF */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                 "mmc0_data8_0", "mmc0"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                 "mmc0_ctrl_0", "mmc0"),
-       PIN_MAP_CONFIGS_PIN_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                   "PORT279", pin_pullup_conf),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                     "mmc0_data8_0", pin_pullup_conf),
-       /* SCIFA2 */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.2", "pfc-sh73a0",
-                                 "scifa2_data_0", "scifa2"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.2", "pfc-sh73a0",
-                                 "scifa2_ctrl_0", "scifa2"),
-       /* SDHI0 (CN15 [SD I/F]) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                 "sdhi0_data4", "sdhi0"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                 "sdhi0_ctrl", "sdhi0"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                 "sdhi0_wp", "sdhi0"),
-       /* SDHI1 (CN4 [WLAN I/F]) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                 "sdhi1_data4", "sdhi1"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                 "sdhi1_ctrl", "sdhi1"),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                     "sdhi1_data4", pin_pullup_conf),
-       PIN_MAP_CONFIGS_PIN_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                   "PORT263", pin_pullup_conf),
-};
-
-static void __init ag5evm_init(void)
-{
-       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
-                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
-       regulator_register_always_on(1, "fixed-2.8V", fixed2v8_power_consumers,
-                                    ARRAY_SIZE(fixed2v8_power_consumers), 3300000);
-       regulator_register_fixed(3, dummy_supplies, ARRAY_SIZE(dummy_supplies));
-
-       pinctrl_register_mappings(ag5evm_pinctrl_map,
-                                 ARRAY_SIZE(ag5evm_pinctrl_map));
-       sh73a0_pinmux_init();
-
-       /* enable MMCIF */
-       gpio_request_one(208, GPIOF_OUT_INIT_HIGH, NULL); /* Reset */
-
-       /* enable SMSC911X */
-       gpio_request_one(144, GPIOF_IN, NULL); /* PINTA2 */
-       gpio_request_one(145, GPIOF_OUT_INIT_HIGH, NULL); /* RESET */
-
-       /* LCD panel */
-       gpio_request_one(217, GPIOF_OUT_INIT_LOW, NULL); /* RESET */
-       mdelay(1);
-       gpio_set_value(217, 1);
-       mdelay(100);
-
-
-#ifdef CONFIG_CACHE_L2X0
-       /* Shared attribute override enable, 64K*8way */
-       l2x0_init(IOMEM(0xf0100000), 0x00460000, 0xc2000fff);
-#endif
-       sh73a0_add_standard_devices();
-
-       i2c_register_board_info(1, &backlight_board_info, 1);
-
-       platform_add_devices(ag5evm_devices, ARRAY_SIZE(ag5evm_devices));
-}
-
-MACHINE_START(AG5EVM, "ag5evm")
-       .smp            = smp_ops(sh73a0_smp_ops),
-       .map_io         = sh73a0_map_io,
-       .init_early     = sh73a0_add_early_devices,
-       .nr_irqs        = NR_IRQS_LEGACY,
-       .init_irq       = sh73a0_init_irq,
-       .init_machine   = ag5evm_init,
-       .init_late      = shmobile_init_late,
-       .init_time      = sh73a0_earlytimer_init,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c
new file mode 100644 (file)
index 0000000..a23fa71
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * APE6EVM board support
+ *
+ * Copyright (C) 2013  Renesas Solutions Corp.
+ * Copyright (C) 2013  Magnus Damm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/gpio.h>
+#include <linux/kernel.h>
+#include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
+#include <linux/platform_device.h>
+#include <linux/sh_clk.h>
+#include <mach/common.h>
+#include <mach/r8a73a4.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static void __init ape6evm_add_standard_devices(void)
+{
+
+       struct clk *parent;
+       struct clk *mp;
+
+       r8a73a4_clock_init();
+
+       /* MP clock parent = extal2 */
+       parent      = clk_get(NULL, "extal2");
+       mp          = clk_get(NULL, "mp");
+       BUG_ON(IS_ERR(parent) || IS_ERR(mp));
+
+       clk_set_parent(mp, parent);
+       clk_put(parent);
+       clk_put(mp);
+
+       r8a73a4_add_dt_devices();
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+       platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0);
+}
+
+static const char *ape6evm_boards_compat_dt[] __initdata = {
+       "renesas,ape6evm-reference",
+       NULL,
+};
+
+DT_MACHINE_START(APE6EVM_DT, "ape6evm")
+       .init_early     = r8a73a4_init_delay,
+       .init_machine   = ape6evm_add_standard_devices,
+       .dt_compat      = ape6evm_boards_compat_dt,
+MACHINE_END
index 38c6c733fabf82284c20e1e661c4463c04f00d1e..24b87eea9da36d2f029a668a4bbacd7223c40683 100644 (file)
@@ -241,7 +241,6 @@ static const char *ape6evm_boards_compat_dt[] __initdata = {
 
 DT_MACHINE_START(APE6EVM_DT, "ape6evm")
        .init_early     = r8a73a4_init_delay,
-       .init_time      = shmobile_timer_init,
        .init_machine   = ape6evm_add_standard_devices,
        .dt_compat      = ape6evm_boards_compat_dt,
 MACHINE_END
index fd2446d995adfb66f1257ae711461b8de90f705e..57d1a78367b6aa17accfddc013132b8328d9b5f5 100644 (file)
@@ -190,7 +190,6 @@ DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva-reference")
        .init_early     = r8a7740_init_delay,
        .init_irq       = r8a7740_init_irq_of,
        .init_machine   = eva_init,
-       .init_time      = shmobile_timer_init,
        .init_late      = shmobile_init_late,
        .dt_compat      = eva_boards_compat_dt,
        .restart        = eva_restart,
index 6b4b77dd2c29336b3312a4d855e416f98084659a..5bd1479d3deb7e98a0d38c3c192abd2824b2825d 100644 (file)
@@ -1313,7 +1313,7 @@ static const char *eva_boards_compat_dt[] __initdata = {
 DT_MACHINE_START(ARMADILLO800EVA_DT, "armadillo800eva")
        .map_io         = r8a7740_map_io,
        .init_early     = eva_add_early_devices,
-       .init_irq       = r8a7740_init_irq,
+       .init_irq       = r8a7740_init_irq_of,
        .init_machine   = eva_init,
        .init_late      = shmobile_init_late,
        .init_time      = eva_earlytimer_init,
diff --git a/arch/arm/mach-shmobile/board-bockw-reference.c b/arch/arm/mach-shmobile/board-bockw-reference.c
new file mode 100644 (file)
index 0000000..1a7c893
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Bock-W board support
+ *
+ * Copyright (C) 2013  Renesas Solutions Corp.
+ * Copyright (C) 2013  Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/of_platform.h>
+#include <linux/pinctrl/machine.h>
+#include <mach/common.h>
+#include <mach/r8a7778.h>
+#include <asm/mach/arch.h>
+
+/*
+ *     see board-bock.c for checking detail of dip-switch
+ */
+
+static const struct pinctrl_map bockw_pinctrl_map[] = {
+       /* SCIF0 */
+       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.0", "pfc-r8a7778",
+                                 "scif0_data_a", "scif0"),
+       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.0", "pfc-r8a7778",
+                                 "scif0_ctrl", "scif0"),
+};
+
+static void __init bockw_init(void)
+{
+       r8a7778_clock_init();
+
+       pinctrl_register_mappings(bockw_pinctrl_map,
+                                 ARRAY_SIZE(bockw_pinctrl_map));
+       r8a7778_pinmux_init();
+       r8a7778_add_dt_devices();
+
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *bockw_boards_compat_dt[] __initdata = {
+       "renesas,bockw-reference",
+       NULL,
+};
+
+DT_MACHINE_START(BOCKW_DT, "bockw")
+       .init_early     = r8a7778_init_delay,
+       .init_irq       = r8a7778_init_irq_dt,
+       .init_machine   = bockw_init,
+       .dt_compat      = bockw_boards_compat_dt,
+MACHINE_END
index 35dd7f201a1637b7589f2a7f92cc6d9c349872d4..6b9faf3908f72b2f23bd3a1a3b07887c6581bc9b 100644 (file)
 
 #include <linux/mfd/tmio.h>
 #include <linux/mmc/host.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
+#include <linux/mmc/sh_mmcif.h>
 #include <linux/mtd/partitions.h>
 #include <linux/pinctrl/machine.h>
+#include <linux/platform_data/usb-rcar-phy.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
@@ -66,28 +69,38 @@ static struct regulator_consumer_supply dummy_supplies[] = {
        REGULATOR_SUPPLY("vdd33a", "smsc911x"),
 };
 
-static struct smsc911x_platform_config smsc911x_data = {
+static struct smsc911x_platform_config smsc911x_data __initdata = {
        .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
        .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
        .flags          = SMSC911X_USE_32BIT,
        .phy_interface  = PHY_INTERFACE_MODE_MII,
 };
 
-static struct resource smsc911x_resources[] = {
+static struct resource smsc911x_resources[] __initdata = {
        DEFINE_RES_MEM(0x18300000, 0x1000),
        DEFINE_RES_IRQ(irq_pin(0)), /* IRQ 0 */
 };
 
 /* USB */
+static struct resource usb_phy_resources[] __initdata = {
+       DEFINE_RES_MEM(0xffe70800, 0x100),
+       DEFINE_RES_MEM(0xffe76000, 0x100),
+};
+
 static struct rcar_phy_platform_data usb_phy_platform_data __initdata;
 
 /* SDHI */
-static struct sh_mobile_sdhi_info sdhi0_info = {
+static struct sh_mobile_sdhi_info sdhi0_info __initdata = {
        .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
        .tmio_ocr_mask  = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
        .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT,
 };
 
+static struct resource sdhi0_resources[] __initdata = {
+       DEFINE_RES_MEM(0xFFE4C000, 0x100),
+       DEFINE_RES_IRQ(gic_iid(0x77)),
+};
+
 static struct sh_eth_plat_data ether_platform_data __initdata = {
        .phy            = 0x01,
        .edmac_endian   = EDMAC_LITTLE_ENDIAN,
@@ -136,7 +149,12 @@ static struct spi_board_info spi_board_info[] __initdata = {
 };
 
 /* MMC */
-static struct sh_mmcif_plat_data sh_mmcif_plat = {
+static struct resource mmc_resources[] __initdata = {
+       DEFINE_RES_MEM(0xffe4e000, 0x100),
+       DEFINE_RES_IRQ(gic_iid(0x5d)),
+};
+
+static struct sh_mmcif_plat_data sh_mmcif_plat __initdata = {
        .sup_pclk       = 0,
        .ocr            = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
        .caps           = MMC_CAP_4_BIT_DATA |
@@ -217,11 +235,7 @@ static void __init bockw_init(void)
        r8a7778_clock_init();
        r8a7778_init_irq_extpin(1);
        r8a7778_add_standard_devices();
-       r8a7778_add_usb_phy_device(&usb_phy_platform_data);
        r8a7778_add_ether_device(&ether_platform_data);
-       r8a7778_add_i2c_device(0);
-       r8a7778_add_hspi_device(0);
-       r8a7778_add_mmc_device(&sh_mmcif_plat);
        r8a7778_add_vin_device(0, &vin_platform_data);
        /* VIN1 has a pin conflict with Ether */
        if (!IS_ENABLED(CONFIG_SH_ETH))
@@ -241,6 +255,19 @@ static void __init bockw_init(void)
                                  ARRAY_SIZE(bockw_pinctrl_map));
        r8a7778_pinmux_init();
 
+       platform_device_register_resndata(
+               &platform_bus, "sh_mmcif", -1,
+               mmc_resources, ARRAY_SIZE(mmc_resources),
+               &sh_mmcif_plat, sizeof(struct sh_mmcif_plat_data));
+
+       platform_device_register_resndata(
+               &platform_bus, "rcar_usb_phy", -1,
+               usb_phy_resources,
+               ARRAY_SIZE(usb_phy_resources),
+               &usb_phy_platform_data,
+               sizeof(struct rcar_phy_platform_data));
+
+
        /* for SMSC */
        base = ioremap_nocache(FPGA, SZ_1M);
        if (base) {
@@ -276,7 +303,10 @@ static void __init bockw_init(void)
                iowrite32(ioread32(base + PUPR4) | (3 << 26), base + PUPR4);
                iounmap(base);
 
-               r8a7778_sdhi_init(0, &sdhi0_info);
+               platform_device_register_resndata(
+                       &platform_bus, "sh_mobile_sdhi", 0,
+                       sdhi0_resources, ARRAY_SIZE(sdhi0_resources),
+                       &sdhi0_info, sizeof(struct sh_mobile_sdhi_info));
        }
 }
 
@@ -289,7 +319,6 @@ DT_MACHINE_START(BOCKW_DT, "bockw")
        .init_early     = r8a7778_init_delay,
        .init_irq       = r8a7778_init_irq_dt,
        .init_machine   = bockw_init,
-       .init_time      = shmobile_timer_init,
        .dt_compat      = bockw_boards_compat_dt,
        .init_late      = r8a7778_init_late,
 MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kota2.c b/arch/arm/mach-shmobile/board-kota2.c
deleted file mode 100644 (file)
index 6af20d9..0000000
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * kota2 board support
- *
- * Copyright (C) 2011  Renesas Solutions Corp.
- * Copyright (C) 2011  Magnus Damm
- * Copyright (C) 2010  Takashi Yoshii <yoshii.takashi.zj@renesas.com>
- * Copyright (C) 2009  Yoshihiro Shimoda <shimoda.yoshihiro@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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/pinctrl/pinconf-generic.h>
-#include <linux/platform_data/pwm-renesas-tpu.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-#include <linux/smsc911x.h>
-#include <linux/gpio.h>
-#include <linux/input.h>
-#include <linux/input/sh_keysc.h>
-#include <linux/gpio_keys.h>
-#include <linux/leds.h>
-#include <linux/leds_pwm.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <mach/hardware.h>
-#include <mach/irqs.h>
-#include <mach/sh73a0.h>
-#include <mach/common.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/time.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <asm/traps.h>
-
-/* Dummy supplies, where voltage doesn't matter */
-static struct regulator_consumer_supply dummy_supplies[] = {
-       REGULATOR_SUPPLY("vddvario", "smsc911x"),
-       REGULATOR_SUPPLY("vdd33a", "smsc911x"),
-};
-
-/* SMSC 9220 */
-static struct resource smsc9220_resources[] = {
-       [0] = {
-               .start          = 0x14000000, /* CS5A */
-               .end            = 0x140000ff, /* A1->A7 */
-               .flags          = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start          = SH73A0_PINT0_IRQ(2), /* PINTA2 */
-               .flags          = IORESOURCE_IRQ,
-       },
-};
-
-static struct smsc911x_platform_config smsc9220_platdata = {
-       .flags          = SMSC911X_USE_32BIT, /* 32-bit SW on 16-bit HW bus */
-       .phy_interface  = PHY_INTERFACE_MODE_MII,
-       .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
-       .irq_type       = SMSC911X_IRQ_TYPE_PUSH_PULL,
-};
-
-static struct platform_device eth_device = {
-       .name           = "smsc911x",
-       .id             = 0,
-       .dev  = {
-               .platform_data = &smsc9220_platdata,
-       },
-       .resource       = smsc9220_resources,
-       .num_resources  = ARRAY_SIZE(smsc9220_resources),
-};
-
-/* KEYSC */
-static struct sh_keysc_info keysc_platdata = {
-       .mode           = SH_KEYSC_MODE_6,
-       .scan_timing    = 3,
-       .delay          = 100,
-       .keycodes       = {
-               KEY_NUMERIC_STAR, KEY_NUMERIC_0, KEY_NUMERIC_POUND,
-               0, 0, 0, 0, 0,
-               KEY_NUMERIC_7, KEY_NUMERIC_8, KEY_NUMERIC_9,
-               0, KEY_DOWN, 0, 0, 0,
-               KEY_NUMERIC_4, KEY_NUMERIC_5, KEY_NUMERIC_6,
-               KEY_LEFT, KEY_ENTER, KEY_RIGHT, 0, 0,
-               KEY_NUMERIC_1, KEY_NUMERIC_2, KEY_NUMERIC_3,
-               0, KEY_UP, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0,
-               0, 0, 0, 0, 0, 0, 0, 0,
-       },
-};
-
-static struct resource keysc_resources[] = {
-       [0] = {
-               .name   = "KEYSC",
-               .start  = 0xe61b0000,
-               .end    = 0xe61b0098 - 1,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(71),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device keysc_device = {
-       .name           = "sh_keysc",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(keysc_resources),
-       .resource       = keysc_resources,
-       .dev            = {
-               .platform_data  = &keysc_platdata,
-       },
-};
-
-/* GPIO KEY */
-#define GPIO_KEY(c, g, d) { .code = c, .gpio = g, .desc = d, .active_low = 1 }
-
-static struct gpio_keys_button gpio_buttons[] = {
-       GPIO_KEY(KEY_VOLUMEUP, 56, "+"), /* S2: VOL+ [IRQ9] */
-       GPIO_KEY(KEY_VOLUMEDOWN, 54, "-"), /* S3: VOL- [IRQ10] */
-       GPIO_KEY(KEY_MENU, 27, "Menu"), /* S4: MENU [IRQ30] */
-       GPIO_KEY(KEY_HOMEPAGE, 26, "Home"), /* S5: HOME [IRQ31] */
-       GPIO_KEY(KEY_BACK, 11, "Back"), /* S6: BACK [IRQ0] */
-       GPIO_KEY(KEY_PHONE, 238, "Tel"), /* S7: TEL [IRQ11] */
-       GPIO_KEY(KEY_POWER, 239, "C1"), /* S8: CAM [IRQ13] */
-       GPIO_KEY(KEY_MAIL, 224, "Mail"), /* S9: MAIL [IRQ3] */
-       /* Omitted button "C3?": 223 - S10: CUST [IRQ8] */
-       GPIO_KEY(KEY_CAMERA, 164, "C2"), /* S11: CAM_HALF [IRQ25] */
-       /* Omitted button "?": 152 - S12: CAM_FULL [No IRQ] */
-};
-
-static struct gpio_keys_platform_data gpio_key_info = {
-       .buttons        = gpio_buttons,
-       .nbuttons       = ARRAY_SIZE(gpio_buttons),
-};
-
-static struct platform_device gpio_keys_device = {
-       .name   = "gpio-keys",
-       .id     = -1,
-       .dev    = {
-               .platform_data  = &gpio_key_info,
-       },
-};
-
-/* GPIO LED */
-#define GPIO_LED(n, g) { .name = n, .gpio = g }
-
-static struct gpio_led gpio_leds[] = {
-       GPIO_LED("G", 20), /* PORT20 [GPO0] -> LED7 -> "G" */
-       GPIO_LED("H", 21), /* PORT21 [GPO1] -> LED8 -> "H" */
-       GPIO_LED("J", 22), /* PORT22 [GPO2] -> LED9 -> "J" */
-};
-
-static struct gpio_led_platform_data gpio_leds_info = {
-       .leds           = gpio_leds,
-       .num_leds       = ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device gpio_leds_device = {
-       .name   = "leds-gpio",
-       .id     = -1,
-       .dev    = {
-               .platform_data  = &gpio_leds_info,
-       },
-};
-
-/* TPU LED */
-static struct resource tpu1_pwm_resources[] = {
-       [0] = {
-               .start  = 0xe6610000,
-               .end    = 0xe66100ff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device tpu1_pwm_device = {
-       .name = "renesas-tpu-pwm",
-       .id = 1,
-       .num_resources  = ARRAY_SIZE(tpu1_pwm_resources),
-       .resource       = tpu1_pwm_resources,
-};
-
-static struct resource tpu2_pwm_resources[] = {
-       [0] = {
-               .start  = 0xe6620000,
-               .end    = 0xe66200ff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device tpu2_pwm_device = {
-       .name = "renesas-tpu-pwm",
-       .id = 2,
-       .num_resources  = ARRAY_SIZE(tpu2_pwm_resources),
-       .resource       = tpu2_pwm_resources,
-};
-
-static struct resource tpu3_pwm_resources[] = {
-       [0] = {
-               .start  = 0xe6630000,
-               .end    = 0xe66300ff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device tpu3_pwm_device = {
-       .name = "renesas-tpu-pwm",
-       .id = 3,
-       .num_resources  = ARRAY_SIZE(tpu3_pwm_resources),
-       .resource       = tpu3_pwm_resources,
-};
-
-static struct resource tpu4_pwm_resources[] = {
-       [0] = {
-               .start  = 0xe6640000,
-               .end    = 0xe66400ff,
-               .flags  = IORESOURCE_MEM,
-       },
-};
-
-static struct platform_device tpu4_pwm_device = {
-       .name = "renesas-tpu-pwm",
-       .id = 4,
-       .num_resources  = ARRAY_SIZE(tpu4_pwm_resources),
-       .resource       = tpu4_pwm_resources,
-};
-
-static struct pwm_lookup pwm_lookup[] = {
-       PWM_LOOKUP("renesas-tpu-pwm.1", 2, "leds-pwm.0", "V2513"),
-       PWM_LOOKUP("renesas-tpu-pwm.2", 1, "leds-pwm.0", "V2515"),
-       PWM_LOOKUP("renesas-tpu-pwm.3", 0, "leds-pwm.0", "KEYLED"),
-       PWM_LOOKUP("renesas-tpu-pwm.4", 1, "leds-pwm.0", "V2514"),
-};
-
-static struct led_pwm tpu_pwm_leds[] = {
-       {
-               .name           = "V2513",
-               .max_brightness = 1000,
-       }, {
-               .name           = "V2515",
-               .max_brightness = 1000,
-       }, {
-               .name           = "KEYLED",
-               .max_brightness = 1000,
-       }, {
-               .name           = "V2514",
-               .max_brightness = 1000,
-       },
-};
-
-static struct led_pwm_platform_data leds_pwm_pdata = {
-       .num_leds = ARRAY_SIZE(tpu_pwm_leds),
-       .leds = tpu_pwm_leds,
-};
-
-static struct platform_device leds_pwm_device = {
-       .name = "leds-pwm",
-       .id = 0,
-       .dev = {
-               .platform_data = &leds_pwm_pdata,
-       },
-};
-
-/* Fixed 1.8V regulator to be used by MMCIF */
-static struct regulator_consumer_supply fixed1v8_power_consumers[] =
-{
-       REGULATOR_SUPPLY("vmmc", "sh_mmcif.0"),
-       REGULATOR_SUPPLY("vqmmc", "sh_mmcif.0"),
-};
-
-/* MMCIF */
-static struct resource mmcif_resources[] = {
-       [0] = {
-               .name   = "MMCIF",
-               .start  = 0xe6bd0000,
-               .end    = 0xe6bd00ff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(140),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = gic_spi(141),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct sh_mmcif_plat_data mmcif_info = {
-       .ocr            = MMC_VDD_165_195,
-       .caps           = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE,
-};
-
-static struct platform_device mmcif_device = {
-       .name           = "sh_mmcif",
-       .id             = 0,
-       .dev            = {
-               .platform_data          = &mmcif_info,
-       },
-       .num_resources  = ARRAY_SIZE(mmcif_resources),
-       .resource       = mmcif_resources,
-};
-
-/* Fixed 3.3V regulator to be used by SDHI0 and SDHI1 */
-static struct regulator_consumer_supply fixed3v3_power_consumers[] =
-{
-       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.0"),
-       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.0"),
-       REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi.1"),
-       REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi.1"),
-};
-
-/* SDHI0 */
-static struct sh_mobile_sdhi_info sdhi0_info = {
-       .tmio_caps      = MMC_CAP_SD_HIGHSPEED,
-       .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static struct resource sdhi0_resources[] = {
-       [0] = {
-               .name   = "SDHI0",
-               .start  = 0xee100000,
-               .end    = 0xee1000ff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(83),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = gic_spi(84),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = gic_spi(85),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device sdhi0_device = {
-       .name           = "sh_mobile_sdhi",
-       .id             = 0,
-       .num_resources  = ARRAY_SIZE(sdhi0_resources),
-       .resource       = sdhi0_resources,
-       .dev    = {
-               .platform_data  = &sdhi0_info,
-       },
-};
-
-/* SDHI1 */
-static struct sh_mobile_sdhi_info sdhi1_info = {
-       .tmio_caps      = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ,
-       .tmio_flags     = TMIO_MMC_WRPROTECT_DISABLE | TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static struct resource sdhi1_resources[] = {
-       [0] = {
-               .name   = "SDHI1",
-               .start  = 0xee120000,
-               .end    = 0xee1200ff,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = gic_spi(87),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [2] = {
-               .start  = gic_spi(88),
-               .flags  = IORESOURCE_IRQ,
-       },
-       [3] = {
-               .start  = gic_spi(89),
-               .flags  = IORESOURCE_IRQ,
-       },
-};
-
-static struct platform_device sdhi1_device = {
-       .name           = "sh_mobile_sdhi",
-       .id             = 1,
-       .num_resources  = ARRAY_SIZE(sdhi1_resources),
-       .resource       = sdhi1_resources,
-       .dev    = {
-               .platform_data  = &sdhi1_info,
-       },
-};
-
-static struct platform_device *kota2_devices[] __initdata = {
-       &eth_device,
-       &keysc_device,
-       &gpio_keys_device,
-       &gpio_leds_device,
-       &tpu1_pwm_device,
-       &tpu2_pwm_device,
-       &tpu3_pwm_device,
-       &tpu4_pwm_device,
-       &leds_pwm_device,
-       &mmcif_device,
-       &sdhi0_device,
-       &sdhi1_device,
-};
-
-static unsigned long pin_pullup_conf[] = {
-       PIN_CONF_PACKED(PIN_CONFIG_BIAS_PULL_UP, 0),
-};
-
-static const struct pinctrl_map kota2_pinctrl_map[] = {
-       /* KEYSC */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_in8", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out04", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out5", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out6_0", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out7_0", "keysc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                 "keysc_out8_0", "keysc"),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_keysc.0", "pfc-sh73a0",
-                                     "keysc_in8", pin_pullup_conf),
-       /* MMCIF */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                 "mmc0_data8_0", "mmc0"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                 "mmc0_ctrl_0", "mmc0"),
-       PIN_MAP_CONFIGS_PIN_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                   "PORT279", pin_pullup_conf),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_mmcif.0", "pfc-sh73a0",
-                                     "mmc0_data8_0", pin_pullup_conf),
-       /* SCIFA2 (UART2) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.2", "pfc-sh73a0",
-                                 "scifa2_data_0", "scifa2"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.2", "pfc-sh73a0",
-                                 "scifa2_ctrl_0", "scifa2"),
-       /* SCIFA4 (UART1) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.4", "pfc-sh73a0",
-                                 "scifa4_data", "scifa4"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.4", "pfc-sh73a0",
-                                 "scifa4_ctrl", "scifa4"),
-       /* SCIFB (BT) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.8", "pfc-sh73a0",
-                                 "scifb_data_0", "scifb"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.8", "pfc-sh73a0",
-                                 "scifb_clk_0", "scifb"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.8", "pfc-sh73a0",
-                                 "scifb_ctrl_0", "scifb"),
-       /* SDHI0 (microSD) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                 "sdhi0_data4", "sdhi0"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                 "sdhi0_ctrl", "sdhi0"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                 "sdhi0_cd", "sdhi0"),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                     "sdhi0_data4", pin_pullup_conf),
-       PIN_MAP_CONFIGS_PIN_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                   "PORT256", pin_pullup_conf),
-       PIN_MAP_CONFIGS_PIN_DEFAULT("sh_mobile_sdhi.0", "pfc-sh73a0",
-                                   "PORT251", pin_pullup_conf),
-       /* SDHI1 (BCM4330) */
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                 "sdhi1_data4", "sdhi1"),
-       PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                 "sdhi1_ctrl", "sdhi1"),
-       PIN_MAP_CONFIGS_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                     "sdhi1_data4", pin_pullup_conf),
-       PIN_MAP_CONFIGS_PIN_DEFAULT("sh_mobile_sdhi.1", "pfc-sh73a0",
-                                   "PORT263", pin_pullup_conf),
-       /* SMSC911X */
-       PIN_MAP_MUX_GROUP_DEFAULT("smsc911x.0", "pfc-sh73a0",
-                                 "bsc_data_0_7", "bsc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("smsc911x.0", "pfc-sh73a0",
-                                 "bsc_data_8_15", "bsc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("smsc911x.0", "pfc-sh73a0",
-                                 "bsc_cs5_a", "bsc"),
-       PIN_MAP_MUX_GROUP_DEFAULT("smsc911x.0", "pfc-sh73a0",
-                                 "bsc_we0", "bsc"),
-       /* TPU */
-       PIN_MAP_MUX_GROUP_DEFAULT("renesas-tpu-pwm.1", "pfc-sh73a0",
-                                 "tpu1_to2", "tpu1"),
-       PIN_MAP_MUX_GROUP_DEFAULT("renesas-tpu-pwm.2", "pfc-sh73a0",
-                                 "tpu2_to1", "tpu2"),
-       PIN_MAP_MUX_GROUP_DEFAULT("renesas-tpu-pwm.3", "pfc-sh73a0",
-                                 "tpu3_to0", "tpu3"),
-       PIN_MAP_MUX_GROUP_DEFAULT("renesas-tpu-pwm.4", "pfc-sh73a0",
-                                 "tpu4_to1", "tpu4"),
-};
-
-static void __init kota2_init(void)
-{
-       regulator_register_always_on(0, "fixed-1.8V", fixed1v8_power_consumers,
-                                    ARRAY_SIZE(fixed1v8_power_consumers), 1800000);
-       regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers,
-                                    ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
-       regulator_register_fixed(2, dummy_supplies, ARRAY_SIZE(dummy_supplies));
-
-       pinctrl_register_mappings(kota2_pinctrl_map,
-                                 ARRAY_SIZE(kota2_pinctrl_map));
-       pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
-
-       sh73a0_pinmux_init();
-
-       /* SMSC911X */
-       gpio_request_one(144, GPIOF_IN, NULL); /* PINTA2 */
-       gpio_request_one(145, GPIOF_OUT_INIT_HIGH, NULL); /* RESET */
-
-       /* MMCIF */
-       gpio_request_one(208, GPIOF_OUT_INIT_HIGH, NULL); /* Reset */
-
-#ifdef CONFIG_CACHE_L2X0
-       /* Early BRESP enable, Shared attribute override enable, 64K*8way */
-       l2x0_init(IOMEM(0xf0100000), 0x40460000, 0x82000fff);
-#endif
-       sh73a0_add_standard_devices();
-       platform_add_devices(kota2_devices, ARRAY_SIZE(kota2_devices));
-}
-
-MACHINE_START(KOTA2, "kota2")
-       .smp            = smp_ops(sh73a0_smp_ops),
-       .map_io         = sh73a0_map_io,
-       .init_early     = sh73a0_add_early_devices,
-       .nr_irqs        = NR_IRQS_LEGACY,
-       .init_irq       = sh73a0_init_irq,
-       .init_machine   = kota2_init,
-       .init_late      = shmobile_init_late,
-       .init_time      = sh73a0_earlytimer_init,
-MACHINE_END
index a66a808db01269495317c4d41ac3172a4d3763ff..598e32488410f2dae49c34f9a33681691e004ba1 100644 (file)
@@ -52,6 +52,5 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference")
        .init_early     = sh73a0_init_delay,
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_machine   = kzm_init,
-       .init_time      = shmobile_timer_init,
        .dt_compat      = kzm9g_boards_compat_dt,
 MACHINE_END
index 1068120d339fafe189f298d94c00a4b0e4862fa0..f1994968d303eac3bf022501c2d8007343b261e0 100644 (file)
 /*
  * external GPIO
  */
-#define GPIO_PCF8575_BASE      (GPIO_NR)
-#define GPIO_PCF8575_PORT10    (GPIO_NR + 8)
-#define GPIO_PCF8575_PORT11    (GPIO_NR + 9)
-#define GPIO_PCF8575_PORT12    (GPIO_NR + 10)
-#define GPIO_PCF8575_PORT13    (GPIO_NR + 11)
-#define GPIO_PCF8575_PORT14    (GPIO_NR + 12)
-#define GPIO_PCF8575_PORT15    (GPIO_NR + 13)
-#define GPIO_PCF8575_PORT16    (GPIO_NR + 14)
+#define GPIO_PCF8575_BASE      (310)
+#define GPIO_PCF8575_PORT10    (GPIO_PCF8575_BASE + 8)
+#define GPIO_PCF8575_PORT11    (GPIO_PCF8575_BASE + 9)
+#define GPIO_PCF8575_PORT12    (GPIO_PCF8575_BASE + 10)
+#define GPIO_PCF8575_PORT13    (GPIO_PCF8575_BASE + 11)
+#define GPIO_PCF8575_PORT14    (GPIO_PCF8575_BASE + 12)
+#define GPIO_PCF8575_PORT15    (GPIO_PCF8575_BASE + 13)
+#define GPIO_PCF8575_PORT16    (GPIO_PCF8575_BASE + 14)
 
 /* Dummy supplies, where voltage doesn't matter */
 static struct regulator_consumer_supply dummy_supplies[] = {
diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c
new file mode 100644 (file)
index 0000000..9c316a1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Lager board support - Reference DT implementation
+ *
+ * Copyright (C) 2013  Renesas Solutions Corp.
+ * Copyright (C) 2013  Simon Horman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <mach/r8a7790.h>
+#include <asm/mach/arch.h>
+
+static void __init lager_add_standard_devices(void)
+{
+       /* clocks are setup late during boot in the case of DT */
+       r8a7790_clock_init();
+
+       r8a7790_add_dt_devices();
+        of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *lager_boards_compat_dt[] __initdata = {
+       "renesas,lager-reference",
+       NULL,
+};
+
+DT_MACHINE_START(LAGER_DT, "lager")
+       .init_early     = r8a7790_init_delay,
+       .init_machine   = lager_add_standard_devices,
+       .init_time      = r8a7790_timer_init,
+       .dt_compat      = lager_boards_compat_dt,
+MACHINE_END
index 4872939cdba238772a4aa523798aad0c376ada15..ffb6f0ac760643b79075441fe23f048d69d293c1 100644 (file)
@@ -96,7 +96,6 @@ static struct resource mmcif1_resources[] __initdata = {
 static struct sh_eth_plat_data ether_pdata __initdata = {
        .phy                    = 0x1,
        .edmac_endian           = EDMAC_LITTLE_ENDIAN,
-       .register_type          = SH_ETH_REG_FAST_RCAR,
        .phy_interface          = PHY_INTERFACE_MODE_RMII,
        .ether_link_active_low  = 1,
 };
index 3d1c439b4998ba9e0aed870912024a07df40cbca..3f4250a2d4eb50f86a6b0ed4ff5b837b741dcd6e 100644 (file)
@@ -42,6 +42,5 @@ DT_MACHINE_START(MARZEN, "marzen")
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_irq       = r8a7779_init_irq_dt,
        .init_machine   = marzen_init,
-       .init_time      = shmobile_timer_init,
        .dt_compat      = marzen_boards_compat_dt,
 MACHINE_END
index ca7fb2e63c604e5806778784f19b26aa4adaf155..3f5044fda4e30ec20610c677188f9647430f1bf0 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/gpio-rcar.h>
+#include <linux/platform_data/usb-rcar-phy.h>
 #include <linux/regulator/fixed.h>
 #include <linux/regulator/machine.h>
 #include <linux/smsc911x.h>
@@ -39,7 +40,6 @@
 #include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/mfd/tmio.h>
 #include <media/soc_camera.h>
-#include <mach/hardware.h>
 #include <mach/r8a7779.h>
 #include <mach/common.h>
 #include <mach/irqs.h>
@@ -59,7 +59,26 @@ static struct regulator_consumer_supply dummy_supplies[] = {
        REGULATOR_SUPPLY("vdd33a", "smsc911x"),
 };
 
-static struct rcar_phy_platform_data usb_phy_platform_data __initdata;
+/* USB PHY */
+static struct resource usb_phy_resources[] = {
+       [0] = {
+               .start          = 0xffe70800,
+               .end            = 0xffe70900 - 1,
+               .flags          = IORESOURCE_MEM,
+       },
+};
+
+static struct rcar_phy_platform_data usb_phy_platform_data;
+
+static struct platform_device usb_phy = {
+       .name           = "rcar_usb_phy",
+       .id             = -1,
+       .dev  = {
+               .platform_data = &usb_phy_platform_data,
+       },
+       .resource       = usb_phy_resources,
+       .num_resources  = ARRAY_SIZE(usb_phy_resources),
+};
 
 /* SMSC LAN89218 */
 static struct resource smsc911x_resources[] = {
@@ -212,6 +231,7 @@ static struct platform_device *marzen_devices[] __initdata = {
        &thermal_device,
        &hspi_device,
        &leds_device,
+       &usb_phy,
        &camera0_device,
        &camera1_device,
 };
@@ -274,19 +294,23 @@ static void __init marzen_init(void)
        r8a7779_init_irq_extpin(1); /* IRQ1 as individual interrupt */
 
        r8a7779_add_standard_devices();
-       r8a7779_add_usb_phy_device(&usb_phy_platform_data);
        r8a7779_add_vin_device(1, &vin_platform_data);
        r8a7779_add_vin_device(3, &vin_platform_data);
        platform_add_devices(marzen_devices, ARRAY_SIZE(marzen_devices));
 }
 
-MACHINE_START(MARZEN, "marzen")
+static const char *marzen_boards_compat_dt[] __initdata = {
+        "renesas,marzen",
+        NULL,
+};
+
+DT_MACHINE_START(MARZEN, "marzen")
        .smp            = smp_ops(r8a7779_smp_ops),
        .map_io         = r8a7779_map_io,
        .init_early     = r8a7779_add_early_devices,
-       .nr_irqs        = NR_IRQS_LEGACY,
-       .init_irq       = r8a7779_init_irq,
+       .init_irq       = r8a7779_init_irq_dt,
        .init_machine   = marzen_init,
        .init_late      = r8a7779_init_late,
+       .dt_compat      = marzen_boards_compat_dt,
        .init_time      = r8a7779_earlytimer_init,
 MACHINE_END
index 2667db806c3954991757dd721420ecea3d75acdd..f93751caf5cbf5f4d34e2099d494249b0eac02e8 100644 (file)
@@ -40,3 +40,52 @@ shmobile_boot_fn:
        .globl  shmobile_boot_arg
 shmobile_boot_arg:
 2:     .space  4
+
+/*
+ * Per-CPU SMP boot function/argument selection code based on MPIDR
+ */
+
+ENTRY(shmobile_smp_boot)
+                                               @ r0 = MPIDR_HWID_BITMASK
+       mrc     p15, 0, r1, c0, c0, 5           @ r1 = MPIDR
+       and     r0, r1, r0                      @ r0 = cpu_logical_map() value
+       mov     r1, #0                          @ r1 = CPU index
+       adr     r5, 1f                          @ array of per-cpu mpidr values
+       adr     r6, 2f                          @ array of per-cpu functions
+       adr     r7, 3f                          @ array of per-cpu arguments
+
+shmobile_smp_boot_find_mpidr:
+       ldr     r8, [r5, r1, lsl #2]
+       cmp     r8, r0
+       bne     shmobile_smp_boot_next
+
+       ldr     r9, [r6, r1, lsl #2]
+       cmp     r9, #0
+       bne     shmobile_smp_boot_found
+
+shmobile_smp_boot_next:
+       add     r1, r1, #1
+       cmp     r1, #CONFIG_NR_CPUS
+       blo     shmobile_smp_boot_find_mpidr
+
+       b       shmobile_smp_sleep
+
+shmobile_smp_boot_found:
+       ldr     r0, [r7, r1, lsl #2]
+       mov     pc, r9
+ENDPROC(shmobile_smp_boot)
+
+ENTRY(shmobile_smp_sleep)
+       wfi
+       b       shmobile_smp_boot
+ENDPROC(shmobile_smp_sleep)
+
+       .globl  shmobile_smp_mpidr
+shmobile_smp_mpidr:
+1:     .space  CONFIG_NR_CPUS * 4
+       .globl  shmobile_smp_fn
+shmobile_smp_fn:
+2:     .space  CONFIG_NR_CPUS * 4
+       .globl  shmobile_smp_arg
+shmobile_smp_arg:
+3:     .space  CONFIG_NR_CPUS * 4
index e818f029d8e3e863dfe9a83beef21ebc84328811..7b938681e7569d29231b232d2be8f46d81f6be39 100644 (file)
@@ -2,7 +2,6 @@
 #define __ARCH_MACH_COMMON_H
 
 extern void shmobile_earlytimer_init(void);
-extern void shmobile_timer_init(void);
 extern void shmobile_setup_delay(unsigned int max_cpu_core_mhz,
                         unsigned int mult, unsigned int div);
 struct twd_local_timer;
@@ -10,7 +9,16 @@ extern void shmobile_setup_console(void);
 extern void shmobile_boot_vector(void);
 extern unsigned long shmobile_boot_fn;
 extern unsigned long shmobile_boot_arg;
+extern void shmobile_smp_boot(void);
+extern void shmobile_smp_sleep(void);
+extern void shmobile_smp_hook(unsigned int cpu, unsigned long fn,
+                             unsigned long arg);
 extern void shmobile_boot_scu(void);
+extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus);
+extern int shmobile_smp_scu_boot_secondary(unsigned int cpu,
+                                          struct task_struct *idle);
+extern void shmobile_smp_scu_cpu_die(unsigned int cpu);
+extern int shmobile_smp_scu_cpu_kill(unsigned int cpu);
 struct clk;
 extern int shmobile_clk_init(void);
 extern void shmobile_handle_irq_intc(struct pt_regs *);
diff --git a/arch/arm/mach-shmobile/include/mach/hardware.h b/arch/arm/mach-shmobile/include/mach/hardware.h
deleted file mode 100644 (file)
index 99264a5..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef __ASM_MACH_HARDWARE_H
-#define __ASM_MACH_HARDWARE_H
-
-#endif /* __ASM_MACH_HARDWARE_H */
index 144a85e29245dabcc12ef5f0ae89f755c0f26f1a..f3a9b702da56f326055029c8ffb81275b619d2ec 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_R8A73A4_H__
 
 void r8a73a4_add_standard_devices(void);
+void r8a73a4_add_dt_devices(void);
 void r8a73a4_clock_init(void);
 void r8a73a4_pinmux_init(void);
 void r8a73a4_init_delay(void);
index 56f375005fcd7953757243bc9f3bb775b50ad309..d07932f872b6770273a5b227231c60a5cbf5a06f 100644 (file)
@@ -48,7 +48,6 @@ enum {
 
 extern void r8a7740_meram_workaround(void);
 extern void r8a7740_init_delay(void);
-extern void r8a7740_init_irq(void);
 extern void r8a7740_init_irq_of(void);
 extern void r8a7740_map_io(void);
 extern void r8a7740_add_early_devices(void);
index 2866704e7afd8a7102d08d3ca51b4c8519b60719..adfcf51b163dcd0503f51ec4961647534428daa5 100644 (file)
 #ifndef __ASM_R8A7778_H__
 #define __ASM_R8A7778_H__
 
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
 #include <linux/sh_eth.h>
-#include <linux/platform_data/usb-rcar-phy.h>
 #include <linux/platform_data/camera-rcar.h>
 
 extern void r8a7778_add_standard_devices(void);
 extern void r8a7778_add_standard_devices_dt(void);
 extern void r8a7778_add_ether_device(struct sh_eth_plat_data *pdata);
-extern void r8a7778_add_usb_phy_device(struct rcar_phy_platform_data *pdata);
-extern void r8a7778_add_i2c_device(int id);
-extern void r8a7778_add_hspi_device(int id);
-extern void r8a7778_add_mmc_device(struct sh_mmcif_plat_data *info);
 extern void r8a7778_add_vin_device(int id,
                                   struct rcar_vin_platform_data *pdata);
+extern void r8a7778_add_dt_devices(void);
 
 extern void r8a7778_init_late(void);
 extern void r8a7778_init_delay(void);
@@ -40,6 +34,5 @@ extern void r8a7778_init_irq_dt(void);
 extern void r8a7778_clock_init(void);
 extern void r8a7778_init_irq_extpin(int irlm);
 extern void r8a7778_pinmux_init(void);
-extern void r8a7778_sdhi_init(int id, struct sh_mobile_sdhi_info *info);
 
 #endif /* __ASM_R8A7778_H__ */
index 6d2b6417fe2affd35f3e572453a24d10a8f09334..11c740047e14cae3d8cef131e30961ee04e7bcd9 100644 (file)
@@ -4,7 +4,6 @@
 #include <linux/sh_clk.h>
 #include <linux/pm_domain.h>
 #include <linux/sh_eth.h>
-#include <linux/platform_data/usb-rcar-phy.h>
 #include <linux/platform_data/camera-rcar.h>
 
 struct platform_device;
@@ -26,7 +25,6 @@ static inline struct r8a7779_pm_ch *to_r8a7779_ch(struct generic_pm_domain *d)
 }
 
 extern void r8a7779_init_delay(void);
-extern void r8a7779_init_irq(void);
 extern void r8a7779_init_irq_extpin(int irlm);
 extern void r8a7779_init_irq_dt(void);
 extern void r8a7779_map_io(void);
@@ -35,7 +33,6 @@ extern void r8a7779_add_early_devices(void);
 extern void r8a7779_add_standard_devices(void);
 extern void r8a7779_add_standard_devices_dt(void);
 extern void r8a7779_add_ether_device(struct sh_eth_plat_data *pdata);
-extern void r8a7779_add_usb_phy_device(struct rcar_phy_platform_data *pdata);
 extern void r8a7779_add_vin_device(int idx,
                                   struct rcar_vin_platform_data *pdata);
 extern void r8a7779_init_late(void);
index 7aaef409a059f17411b3cfb55537cd69924b5658..788d55952091b3f04ddd47f8b1847f2638503c92 100644 (file)
@@ -2,6 +2,7 @@
 #define __ASM_R8A7790_H__
 
 void r8a7790_add_standard_devices(void);
+void r8a7790_add_dt_devices(void);
 void r8a7790_clock_init(void);
 void r8a7790_pinmux_init(void);
 void r8a7790_init_delay(void);
index 680dc5f1655ab46c4eaafc7a46c430bd141a6ccd..359b582dc270d6a96408b145a063f7ebf12b6a3c 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef __ASM_SH73A0_H__
 #define __ASM_SH73A0_H__
 
-#define GPIO_NR                        310
-
 /* DMA slave IDs */
 enum {
        SHDMA_SLAVE_INVALID,
diff --git a/arch/arm/mach-shmobile/intc-r8a7740.c b/arch/arm/mach-shmobile/intc-r8a7740.c
deleted file mode 100644 (file)
index 8871f77..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * R8A7740 processor support
- *
- * Copyright (C) 2011  Renesas Solutions Corp.
- * Copyright (C) 2011  Kuninori Morimoto <kuninori.morimoto.gx@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; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/irqchip.h>
-#include <linux/irqchip/arm-gic.h>
-
-static void __init r8a7740_init_irq_common(void)
-{
-       void __iomem *intc_prio_base = ioremap_nocache(0xe6900010, 0x10);
-       void __iomem *intc_msk_base = ioremap_nocache(0xe6900040, 0x10);
-       void __iomem *pfc_inta_ctrl = ioremap_nocache(0xe605807c, 0x4);
-
-       /* route signals to GIC */
-       iowrite32(0x0, pfc_inta_ctrl);
-
-       /*
-        * To mask the shared interrupt to SPI 149 we must ensure to set
-        * PRIO *and* MASK. Else we run into IRQ floods when registering
-        * the intc_irqpin devices
-        */
-       iowrite32(0x0, intc_prio_base + 0x0);
-       iowrite32(0x0, intc_prio_base + 0x4);
-       iowrite32(0x0, intc_prio_base + 0x8);
-       iowrite32(0x0, intc_prio_base + 0xc);
-       iowrite8(0xff, intc_msk_base + 0x0);
-       iowrite8(0xff, intc_msk_base + 0x4);
-       iowrite8(0xff, intc_msk_base + 0x8);
-       iowrite8(0xff, intc_msk_base + 0xc);
-
-       iounmap(intc_prio_base);
-       iounmap(intc_msk_base);
-       iounmap(pfc_inta_ctrl);
-}
-
-void __init r8a7740_init_irq_of(void)
-{
-       irqchip_init();
-       r8a7740_init_irq_common();
-}
-
-void __init r8a7740_init_irq(void)
-{
-       void __iomem *gic_dist_base = ioremap_nocache(0xc2800000, 0x1000);
-       void __iomem *gic_cpu_base = ioremap_nocache(0xc2000000, 0x1000);
-
-       /* initialize the Generic Interrupt Controller PL390 r0p0 */
-       gic_init(0, 29, gic_dist_base, gic_cpu_base);
-       r8a7740_init_irq_common();
-}
diff --git a/arch/arm/mach-shmobile/intc-r8a7779.c b/arch/arm/mach-shmobile/intc-r8a7779.c
deleted file mode 100644 (file)
index b86dc89..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * r8a7779 processor support - INTC hardware block
- *
- * Copyright (C) 2011  Renesas Solutions Corp.
- * Copyright (C) 2011  Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/platform_data/irq-renesas-intc-irqpin.h>
-#include <linux/irqchip.h>
-#include <mach/common.h>
-#include <mach/intc.h>
-#include <mach/irqs.h>
-#include <mach/r8a7779.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#define INT2SMSKCR0 IOMEM(0xfe7822a0)
-#define INT2SMSKCR1 IOMEM(0xfe7822a4)
-#define INT2SMSKCR2 IOMEM(0xfe7822a8)
-#define INT2SMSKCR3 IOMEM(0xfe7822ac)
-#define INT2SMSKCR4 IOMEM(0xfe7822b0)
-
-#define INT2NTSR0 IOMEM(0xfe700060)
-#define INT2NTSR1 IOMEM(0xfe700064)
-
-static struct renesas_intc_irqpin_config irqpin0_platform_data = {
-       .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
-       .sense_bitfield_width = 2,
-};
-
-static struct resource irqpin0_resources[] = {
-       DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */
-       DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */
-       DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */
-       DEFINE_RES_MEM(0xfe780044, 4), /* INTMSK0 */
-       DEFINE_RES_MEM(0xfe780064, 4), /* INTMSKCLR0 */
-       DEFINE_RES_IRQ(gic_spi(27)), /* IRQ0 */
-       DEFINE_RES_IRQ(gic_spi(28)), /* IRQ1 */
-       DEFINE_RES_IRQ(gic_spi(29)), /* IRQ2 */
-       DEFINE_RES_IRQ(gic_spi(30)), /* IRQ3 */
-};
-
-static struct platform_device irqpin0_device = {
-       .name           = "renesas_intc_irqpin",
-       .id             = 0,
-       .resource       = irqpin0_resources,
-       .num_resources  = ARRAY_SIZE(irqpin0_resources),
-       .dev            = {
-               .platform_data  = &irqpin0_platform_data,
-       },
-};
-
-void __init r8a7779_init_irq_extpin(int irlm)
-{
-       void __iomem *icr0 = ioremap_nocache(0xfe780000, PAGE_SIZE);
-       unsigned long tmp;
-
-       if (icr0) {
-               tmp = ioread32(icr0);
-               if (irlm)
-                       tmp |= 1 << 23; /* IRQ0 -> IRQ3 as individual pins */
-               else
-                       tmp &= ~(1 << 23); /* IRL mode - not supported */
-               tmp |= (1 << 21); /* LVLMODE = 1 */
-               iowrite32(tmp, icr0);
-               iounmap(icr0);
-
-               if (irlm)
-                       platform_device_register(&irqpin0_device);
-       } else
-               pr_warn("r8a7779: unable to setup external irq pin mode\n");
-}
-
-static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
-{
-       return 0; /* always allow wakeup */
-}
-
-static void __init r8a7779_init_irq_common(void)
-{
-       gic_arch_extn.irq_set_wake = r8a7779_set_wake;
-
-       /* route all interrupts to ARM */
-       __raw_writel(0xffffffff, INT2NTSR0);
-       __raw_writel(0x3fffffff, INT2NTSR1);
-
-       /* unmask all known interrupts in INTCS2 */
-       __raw_writel(0xfffffff0, INT2SMSKCR0);
-       __raw_writel(0xfff7ffff, INT2SMSKCR1);
-       __raw_writel(0xfffbffdf, INT2SMSKCR2);
-       __raw_writel(0xbffffffc, INT2SMSKCR3);
-       __raw_writel(0x003fee3f, INT2SMSKCR4);
-}
-
-void __init r8a7779_init_irq(void)
-{
-       void __iomem *gic_dist_base = IOMEM(0xf0001000);
-       void __iomem *gic_cpu_base = IOMEM(0xf0000100);
-
-       /* use GIC to handle interrupts */
-       gic_init(0, 29, gic_dist_base, gic_cpu_base);
-
-       r8a7779_init_irq_common();
-}
-
-#ifdef CONFIG_OF
-void __init r8a7779_init_irq_dt(void)
-{
-       irqchip_init();
-       r8a7779_init_irq_common();
-}
-#endif
diff --git a/arch/arm/mach-shmobile/platsmp-scu.c b/arch/arm/mach-shmobile/platsmp-scu.c
new file mode 100644 (file)
index 0000000..c96f501
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * SMP support for SoCs with SCU covered by mach-shmobile
+ *
+ * Copyright (C) 2013  Magnus Damm
+ *
+ * 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/init.h>
+#include <linux/io.h>
+#include <linux/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <asm/smp_scu.h>
+#include <mach/common.h>
+
+void __init shmobile_smp_scu_prepare_cpus(unsigned int max_cpus)
+{
+       /* install boot code shared by all CPUs */
+       shmobile_boot_fn = virt_to_phys(shmobile_smp_boot);
+       shmobile_boot_arg = MPIDR_HWID_BITMASK;
+
+       /* enable SCU and cache coherency on booting CPU */
+       scu_enable(shmobile_scu_base);
+       scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);
+}
+
+int shmobile_smp_scu_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+       /* For this particular CPU register SCU boot vector */
+       shmobile_smp_hook(cpu, virt_to_phys(shmobile_boot_scu),
+                         (unsigned long)shmobile_scu_base);
+       return 0;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void shmobile_smp_scu_cpu_die(unsigned int cpu)
+{
+       /* For this particular CPU deregister boot vector */
+       shmobile_smp_hook(cpu, 0, 0);
+
+       dsb();
+       flush_cache_all();
+
+       /* disable cache coherency */
+       scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF);
+
+       /* jump to shared mach-shmobile sleep / reset code */
+       shmobile_smp_sleep();
+}
+
+static int shmobile_smp_scu_psr_core_disabled(int cpu)
+{
+       unsigned long mask = SCU_PM_POWEROFF << (cpu * 8);
+
+       if ((__raw_readl(shmobile_scu_base + 8) & mask) == mask)
+               return 1;
+
+       return 0;
+}
+
+int shmobile_smp_scu_cpu_kill(unsigned int cpu)
+{
+       int k;
+
+       /* this function is running on another CPU than the offline target,
+        * here we need wait for shutdown code in platform_cpu_die() to
+        * finish before asking SoC-specific code to power off the CPU core.
+        */
+       for (k = 0; k < 1000; k++) {
+               if (shmobile_smp_scu_psr_core_disabled(cpu))
+                       return 1;
+
+               mdelay(1);
+       }
+
+       return 0;
+}
+#endif
index 1f958d7b0bac77d7eff13ac83eb7d02309fe9092..d4ae616bcedb4f09c4342a8e19a0d9c7dc98f581 100644 (file)
@@ -12,6 +12,9 @@
  */
 #include <linux/init.h>
 #include <linux/smp.h>
+#include <asm/cacheflush.h>
+#include <asm/smp_plat.h>
+#include <mach/common.h>
 
 void __init shmobile_smp_init_cpus(unsigned int ncores)
 {
@@ -26,3 +29,18 @@ void __init shmobile_smp_init_cpus(unsigned int ncores)
        for (i = 0; i < ncores; i++)
                set_cpu_possible(i, true);
 }
+
+extern unsigned long shmobile_smp_fn[];
+extern unsigned long shmobile_smp_arg[];
+extern unsigned long shmobile_smp_mpidr[];
+
+void shmobile_smp_hook(unsigned int cpu, unsigned long fn, unsigned long arg)
+{
+       shmobile_smp_fn[cpu] = 0;
+       flush_cache_all();
+
+       shmobile_smp_mpidr[cpu] = cpu_logical_map(cpu);
+       shmobile_smp_fn[cpu] = fn;
+       shmobile_smp_arg[cpu] = arg;
+       flush_cache_all();
+}
index 1553af8e04ff39fca308c2cb507565c86bafb4af..3ad531caf4f098a172d01824263546c5e2cc2c08 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/irqchip/arm-gic.h>
-#include <mach/hardware.h>
 #include <mach/common.h>
 #include <mach/emev2.h>
 #include <mach/irqs.h>
index d533bd23865c70e408c74374946ee5d355a41289..89491700afb78b8c706aba61b638ffb699031610 100644 (file)
@@ -188,7 +188,7 @@ static struct resource cmt10_resources[] = {
                                          &cmt##idx##_platform_data,    \
                                          sizeof(struct sh_timer_config))
 
-void __init r8a73a4_add_standard_devices(void)
+void __init r8a73a4_add_dt_devices(void)
 {
        r8a73a4_register_scif(SCIFA0);
        r8a73a4_register_scif(SCIFA1);
@@ -196,10 +196,15 @@ void __init r8a73a4_add_standard_devices(void)
        r8a73a4_register_scif(SCIFB1);
        r8a73a4_register_scif(SCIFB2);
        r8a73a4_register_scif(SCIFB3);
+       r8a7790_register_cmt(10);
+}
+
+void __init r8a73a4_add_standard_devices(void)
+{
+       r8a73a4_add_dt_devices();
        r8a73a4_register_irqc(0);
        r8a73a4_register_irqc(1);
        r8a73a4_register_thermal();
-       r8a7790_register_cmt(10);
 }
 
 void __init r8a73a4_init_delay(void)
@@ -210,11 +215,6 @@ void __init r8a73a4_init_delay(void)
 }
 
 #ifdef CONFIG_USE_OF
-void __init r8a73a4_add_standard_devices_dt(void)
-{
-       platform_device_register_simple("cpufreq-cpu0", -1, NULL, 0);
-       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
 
 static const char *r8a73a4_boards_compat_dt[] __initdata = {
        "renesas,r8a73a4",
@@ -223,8 +223,6 @@ static const char *r8a73a4_boards_compat_dt[] __initdata = {
 
 DT_MACHINE_START(R8A73A4_DT, "Generic R8A73A4 (Flattened Device Tree)")
        .init_early     = r8a73a4_init_delay,
-       .init_machine   = r8a73a4_add_standard_devices_dt,
-       .init_time      = shmobile_timer_init,
        .dt_compat      = r8a73a4_boards_compat_dt,
 MACHINE_END
 #endif /* CONFIG_USE_OF */
index 84c5bb6d9725b7c76a6e37e7bbc0d3083bac414e..b7d4b2c3bc2974d5778414ac5335f9042f7bc2d2 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/io.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/platform_data/irq-renesas-intc-irqpin.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
@@ -1019,6 +1021,36 @@ void __init r8a7740_init_delay(void)
        shmobile_setup_delay(800, 1, 3); /* Cortex-A9 @ 800MHz */
 };
 
+void __init r8a7740_init_irq_of(void)
+{
+       void __iomem *intc_prio_base = ioremap_nocache(0xe6900010, 0x10);
+       void __iomem *intc_msk_base = ioremap_nocache(0xe6900040, 0x10);
+       void __iomem *pfc_inta_ctrl = ioremap_nocache(0xe605807c, 0x4);
+
+       irqchip_init();
+
+       /* route signals to GIC */
+       iowrite32(0x0, pfc_inta_ctrl);
+
+       /*
+        * To mask the shared interrupt to SPI 149 we must ensure to set
+        * PRIO *and* MASK. Else we run into IRQ floods when registering
+        * the intc_irqpin devices
+        */
+       iowrite32(0x0, intc_prio_base + 0x0);
+       iowrite32(0x0, intc_prio_base + 0x4);
+       iowrite32(0x0, intc_prio_base + 0x8);
+       iowrite32(0x0, intc_prio_base + 0xc);
+       iowrite8(0xff, intc_msk_base + 0x0);
+       iowrite8(0xff, intc_msk_base + 0x4);
+       iowrite8(0xff, intc_msk_base + 0x8);
+       iowrite8(0xff, intc_msk_base + 0xc);
+
+       iounmap(intc_prio_base);
+       iounmap(intc_msk_base);
+       iounmap(pfc_inta_ctrl);
+}
+
 static void __init r8a7740_generic_init(void)
 {
        r8a7740_clock_init(0);
@@ -1035,7 +1067,6 @@ DT_MACHINE_START(R8A7740_DT, "Generic R8A7740 (Flattened Device Tree)")
        .init_early     = r8a7740_init_delay,
        .init_irq       = r8a7740_init_irq_of,
        .init_machine   = r8a7740_generic_init,
-       .init_time      = shmobile_timer_init,
        .dt_compat      = r8a7740_boards_compat_dt,
 MACHINE_END
 
index 203becfc6e31b99064f838619402fb81ad617082..6a2657ebd19775c4a9c79bae91f7aa0dac2bc812 100644 (file)
@@ -95,20 +95,6 @@ static struct sh_timer_config sh_tmu1_platform_data __initdata = {
                &sh_tmu##idx##_platform_data,           \
                sizeof(sh_tmu##idx##_platform_data))
 
-/* USB PHY */
-static struct resource usb_phy_resources[] __initdata = {
-       DEFINE_RES_MEM(0xffe70800, 0x100),
-       DEFINE_RES_MEM(0xffe76000, 0x100),
-};
-
-void __init r8a7778_add_usb_phy_device(struct rcar_phy_platform_data *pdata)
-{
-       platform_device_register_resndata(&platform_bus, "rcar_usb_phy", -1,
-                                         usb_phy_resources,
-                                         ARRAY_SIZE(usb_phy_resources),
-                                         pdata, sizeof(*pdata));
-}
-
 /* USB */
 static struct usb_phy *phy;
 
@@ -248,30 +234,6 @@ void __init r8a7778_pinmux_init(void)
        r8a7778_register_gpio(4);
 };
 
-/* SDHI */
-static struct resource sdhi_resources[] __initdata = {
-       /* SDHI0 */
-       DEFINE_RES_MEM(0xFFE4C000, 0x100),
-       DEFINE_RES_IRQ(gic_iid(0x77)),
-       /* SDHI1 */
-       DEFINE_RES_MEM(0xFFE4D000, 0x100),
-       DEFINE_RES_IRQ(gic_iid(0x78)),
-       /* SDHI2 */
-       DEFINE_RES_MEM(0xFFE4F000, 0x100),
-       DEFINE_RES_IRQ(gic_iid(0x76)),
-};
-
-void __init r8a7778_sdhi_init(int id,
-                             struct sh_mobile_sdhi_info *info)
-{
-       BUG_ON(id < 0 || id > 2);
-
-       platform_device_register_resndata(
-               &platform_bus, "sh_mobile_sdhi", id,
-               sdhi_resources + (2 * id), 2,
-               info, sizeof(*info));
-}
-
 /* I2C */
 static struct resource i2c_resources[] __initdata = {
        /* I2C0 */
@@ -288,7 +250,7 @@ static struct resource i2c_resources[] __initdata = {
        DEFINE_RES_IRQ(gic_iid(0x6d)),
 };
 
-void __init r8a7778_add_i2c_device(int id)
+static void __init r8a7778_register_i2c(int id)
 {
        BUG_ON(id < 0 || id > 3);
 
@@ -310,7 +272,7 @@ static struct resource hspi_resources[] __initdata = {
        DEFINE_RES_IRQ(gic_iid(0x75)),
 };
 
-void __init r8a7778_add_hspi_device(int id)
+void __init r8a7778_register_hspi(int id)
 {
        BUG_ON(id < 0 || id > 2);
 
@@ -319,20 +281,6 @@ void __init r8a7778_add_hspi_device(int id)
                hspi_resources + (2 * id), 2);
 }
 
-/* MMC */
-static struct resource mmc_resources[] __initdata = {
-       DEFINE_RES_MEM(0xffe4e000, 0x100),
-       DEFINE_RES_IRQ(gic_iid(0x5d)),
-};
-
-void __init r8a7778_add_mmc_device(struct sh_mmcif_plat_data *info)
-{
-       platform_device_register_resndata(
-               &platform_bus, "sh_mmcif", -1,
-               mmc_resources, ARRAY_SIZE(mmc_resources),
-               info, sizeof(*info));
-}
-
 /* VIN */
 #define R8A7778_VIN(idx)                                               \
 static struct resource vin##idx##_resources[] __initdata = {           \
@@ -367,7 +315,7 @@ void __init r8a7778_add_vin_device(int id, struct rcar_vin_platform_data *pdata)
        platform_device_register_full(vin_info_table[id]);
 }
 
-void __init r8a7778_add_standard_devices(void)
+void __init r8a7778_add_dt_devices(void)
 {
        int i;
 
@@ -391,6 +339,18 @@ void __init r8a7778_add_standard_devices(void)
        r8a7778_register_tmu(1);
 }
 
+void __init r8a7778_add_standard_devices(void)
+{
+       r8a7778_add_dt_devices();
+       r8a7778_register_i2c(0);
+       r8a7778_register_i2c(1);
+       r8a7778_register_i2c(2);
+       r8a7778_register_i2c(3);
+       r8a7778_register_hspi(0);
+       r8a7778_register_hspi(1);
+       r8a7778_register_hspi(2);
+}
+
 void __init r8a7778_init_late(void)
 {
        phy = usb_get_phy(USB_PHY_TYPE_USB2);
@@ -480,7 +440,6 @@ static const char *r8a7778_compat_dt[] __initdata = {
 DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)")
        .init_early     = r8a7778_init_delay,
        .init_irq       = r8a7778_init_irq_dt,
-       .init_time      = shmobile_timer_init,
        .dt_compat      = r8a7778_compat_dt,
        .init_late      = r8a7778_init_late,
 MACHINE_END
index 41bab625341e0318392c3bc778b662f2014a31ee..ecd0148ee1e1711144eb2fd75bc146d97a582bb6 100644 (file)
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
 #include <linux/of_platform.h>
 #include <linux/platform_data/gpio-rcar.h>
+#include <linux/platform_data/irq-renesas-intc-irqpin.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/io.h>
 #include <linux/serial_sci.h>
-#include <linux/sh_intc.h>
 #include <linux/sh_timer.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb/otg.h>
@@ -37,7 +39,6 @@
 #include <linux/usb/ehci_pdriver.h>
 #include <linux/usb/ohci_pdriver.h>
 #include <linux/pm_runtime.h>
-#include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/r8a7779.h>
 #include <mach/common.h>
@@ -69,6 +70,60 @@ void __init r8a7779_map_io(void)
        iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc));
 }
 
+/* IRQ */
+#define INT2SMSKCR0 IOMEM(0xfe7822a0)
+#define INT2SMSKCR1 IOMEM(0xfe7822a4)
+#define INT2SMSKCR2 IOMEM(0xfe7822a8)
+#define INT2SMSKCR3 IOMEM(0xfe7822ac)
+#define INT2SMSKCR4 IOMEM(0xfe7822b0)
+
+#define INT2NTSR0 IOMEM(0xfe700060)
+#define INT2NTSR1 IOMEM(0xfe700064)
+
+static struct renesas_intc_irqpin_config irqpin0_platform_data __initdata = {
+       .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
+       .sense_bitfield_width = 2,
+};
+
+static struct resource irqpin0_resources[] __initdata = {
+       DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */
+       DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */
+       DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */
+       DEFINE_RES_MEM(0xfe780044, 4), /* INTMSK0 */
+       DEFINE_RES_MEM(0xfe780064, 4), /* INTMSKCLR0 */
+       DEFINE_RES_IRQ(gic_spi(27)), /* IRQ0 */
+       DEFINE_RES_IRQ(gic_spi(28)), /* IRQ1 */
+       DEFINE_RES_IRQ(gic_spi(29)), /* IRQ2 */
+       DEFINE_RES_IRQ(gic_spi(30)), /* IRQ3 */
+};
+
+void __init r8a7779_init_irq_extpin(int irlm)
+{
+       void __iomem *icr0 = ioremap_nocache(0xfe780000, PAGE_SIZE);
+       u32 tmp;
+
+       if (!icr0) {
+               pr_warn("r8a7779: unable to setup external irq pin mode\n");
+               return;
+       }
+
+       tmp = ioread32(icr0);
+       if (irlm)
+               tmp |= 1 << 23; /* IRQ0 -> IRQ3 as individual pins */
+       else
+               tmp &= ~(1 << 23); /* IRL mode - not supported */
+       tmp |= (1 << 21); /* LVLMODE = 1 */
+       iowrite32(tmp, icr0);
+       iounmap(icr0);
+
+       if (irlm)
+               platform_device_register_resndata(
+                       &platform_bus, "renesas_intc_irqpin", -1,
+                       irqpin0_resources, ARRAY_SIZE(irqpin0_resources),
+                       &irqpin0_platform_data, sizeof(irqpin0_platform_data));
+}
+
+/* PFC/GPIO */
 static struct resource r8a7779_pfc_resources[] = {
        DEFINE_RES_MEM(0xfffc0000, 0x023c),
 };
@@ -388,15 +443,6 @@ static struct platform_device sata_device = {
        },
 };
 
-/* USB PHY */
-static struct resource usb_phy_resources[] __initdata = {
-       [0] = {
-               .start          = 0xffe70800,
-               .end            = 0xffe70900 - 1,
-               .flags          = IORESOURCE_MEM,
-       },
-};
-
 /* USB */
 static struct usb_phy *phy;
 
@@ -548,7 +594,7 @@ static struct platform_device ohci1_device = {
 };
 
 /* Ether */
-static struct resource ether_resources[] = {
+static struct resource ether_resources[] __initdata = {
        {
                .start  = 0xfde00000,
                .end    = 0xfde003ff,
@@ -629,14 +675,6 @@ void __init r8a7779_add_ether_device(struct sh_eth_plat_data *pdata)
                                          pdata, sizeof(*pdata));
 }
 
-void __init r8a7779_add_usb_phy_device(struct rcar_phy_platform_data *pdata)
-{
-       platform_device_register_resndata(&platform_bus, "rcar_usb_phy", -1,
-                                         usb_phy_resources,
-                                         ARRAY_SIZE(usb_phy_resources),
-                                         pdata, sizeof(*pdata));
-}
-
 void __init r8a7779_add_vin_device(int id, struct rcar_vin_platform_data *pdata)
 {
        BUG_ON(id < 0 || id > 3);
@@ -653,8 +691,8 @@ void __init __weak r8a7779_register_twd(void) { }
 void __init r8a7779_earlytimer_init(void)
 {
        r8a7779_clock_init();
-       shmobile_earlytimer_init();
        r8a7779_register_twd();
+       shmobile_earlytimer_init();
 }
 
 void __init r8a7779_add_early_devices(void)
@@ -697,6 +735,29 @@ void __init r8a7779_init_late(void)
 }
 
 #ifdef CONFIG_USE_OF
+static int r8a7779_set_wake(struct irq_data *data, unsigned int on)
+{
+       return 0; /* always allow wakeup */
+}
+
+void __init r8a7779_init_irq_dt(void)
+{
+       gic_arch_extn.irq_set_wake = r8a7779_set_wake;
+
+       irqchip_init();
+
+       /* route all interrupts to ARM */
+       __raw_writel(0xffffffff, INT2NTSR0);
+       __raw_writel(0x3fffffff, INT2NTSR1);
+
+       /* unmask all known interrupts in INTCS2 */
+       __raw_writel(0xfffffff0, INT2SMSKCR0);
+       __raw_writel(0xfff7ffff, INT2SMSKCR1);
+       __raw_writel(0xfffbffdf, INT2SMSKCR2);
+       __raw_writel(0xbffffffc, INT2SMSKCR3);
+       __raw_writel(0x003fee3f, INT2SMSKCR4);
+}
+
 void __init r8a7779_init_delay(void)
 {
        shmobile_setup_delay(1000, 2, 4); /* Cortex-A9 @ 1000MHz */
@@ -723,7 +784,6 @@ DT_MACHINE_START(R8A7779_DT, "Generic R8A7779 (Flattened Device Tree)")
        .nr_irqs        = NR_IRQS_LEGACY,
        .init_irq       = r8a7779_init_irq_dt,
        .init_machine   = r8a7779_add_standard_devices_dt,
-       .init_time      = shmobile_timer_init,
        .init_late      = r8a7779_init_late,
        .dt_compat      = r8a7779_compat_dt,
 MACHINE_END
index 4c96dad21195092d91f18ce3b97b0d9fd91122ec..d0f5c9f9349a186412da1f912fc9dbcac0e851d0 100644 (file)
@@ -18,6 +18,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
+#include <linux/clocksource.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
 #include <linux/of_platform.h>
@@ -160,13 +161,13 @@ static struct resource thermal_resources[] __initdata = {
                                        thermal_resources,              \
                                        ARRAY_SIZE(thermal_resources))
 
-static struct sh_timer_config cmt00_platform_data = {
+static struct sh_timer_config cmt00_platform_data __initdata = {
        .name = "CMT00",
        .timer_bit = 0,
        .clockevent_rating = 80,
 };
 
-static struct resource cmt00_resources[] = {
+static struct resource cmt00_resources[] __initdata = {
        DEFINE_RES_MEM(0xffca0510, 0x0c),
        DEFINE_RES_MEM(0xffca0500, 0x04),
        DEFINE_RES_IRQ(gic_spi(142)), /* CMT0_0 */
@@ -179,7 +180,7 @@ static struct resource cmt00_resources[] = {
                                          &cmt##idx##_platform_data,    \
                                          sizeof(struct sh_timer_config))
 
-void __init r8a7790_add_standard_devices(void)
+void __init r8a7790_add_dt_devices(void)
 {
        r8a7790_register_scif(SCIFA0);
        r8a7790_register_scif(SCIFA1);
@@ -191,9 +192,14 @@ void __init r8a7790_add_standard_devices(void)
        r8a7790_register_scif(SCIF1);
        r8a7790_register_scif(HSCIF0);
        r8a7790_register_scif(HSCIF1);
+       r8a7790_register_cmt(00);
+}
+
+void __init r8a7790_add_standard_devices(void)
+{
+       r8a7790_add_dt_devices();
        r8a7790_register_irqc(0);
        r8a7790_register_thermal();
-       r8a7790_register_cmt(00);
 }
 
 #define MODEMR 0xe6160060
@@ -258,7 +264,7 @@ void __init r8a7790_timer_init(void)
        iounmap(base);
 #endif /* CONFIG_ARM_ARCH_TIMER */
 
-       shmobile_timer_init();
+       clocksource_of_init();
 }
 
 void __init r8a7790_init_delay(void)
index 13e6fdbde0a5d20525ce152372a3232c5991e7aa..311878391e188f64dbb5fc46d737782e7e4666ae 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/platform_data/sh_ipmmu.h>
 #include <mach/dma-register.h>
-#include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/sh7372.h>
 #include <mach/common.h>
index 516c2391b47aeb4af44117efd313b8102f3cf97a..22de17417fd7c83a4ae4c9b66162cd3c16f1cb04 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/platform_data/sh_ipmmu.h>
 #include <linux/platform_data/irq-renesas-intc-irqpin.h>
 #include <mach/dma-register.h>
-#include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/sh73a0.h>
 #include <mach/common.h>
index 78e84c58245309a83c44251c606335336f0a3a96..522de5ebb55fd727004e3934e4a38d8e2357462c 100644 (file)
 
 static int emev2_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
+       int ret;
+
+       ret = shmobile_smp_scu_boot_secondary(cpu, idle);
+       if (ret)
+               return ret;
+
        arch_send_wakeup_ipi_mask(cpumask_of(cpu_logical_map(cpu)));
        return 0;
 }
@@ -42,21 +48,16 @@ static void __init emev2_smp_prepare_cpus(unsigned int max_cpus)
 {
        void __iomem *smu;
 
-       /* setup EMEV2 specific SCU base, enable */
-       shmobile_scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
-       scu_enable(shmobile_scu_base);
-
-       /* Tell ROM loader about our vector (in headsmp-scu.S, headsmp.S) */
+       /* Tell ROM loader about our vector (in headsmp.S) */
        smu = ioremap(EMEV2_SMU_BASE, PAGE_SIZE);
        if (smu) {
                iowrite32(__pa(shmobile_boot_vector), smu + SMU_GENERAL_REG0);
                iounmap(smu);
        }
-       shmobile_boot_fn = virt_to_phys(shmobile_boot_scu);
-       shmobile_boot_arg = (unsigned long)shmobile_scu_base;
 
-       /* enable cache coherency on booting CPU */
-       scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);
+       /* setup EMEV2 specific SCU bits */
+       shmobile_scu_base = ioremap(EMEV2_SCU_BASE, PAGE_SIZE);
+       shmobile_smp_scu_prepare_cpus(max_cpus);
 }
 
 struct smp_operations emev2_smp_ops __initdata = {
index 9bdf810f2a87489677394138a47f54f121bc3f91..0f05e9fb722fbfd0c3b921b6caa5a85d68b5d25d 100644 (file)
@@ -84,30 +84,34 @@ static int r8a7779_platform_cpu_kill(unsigned int cpu)
 static int r8a7779_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
        struct r8a7779_pm_ch *ch = NULL;
-       int ret = -EIO;
+       unsigned int lcpu = cpu_logical_map(cpu);
+       int ret;
 
-       cpu = cpu_logical_map(cpu);
+       ret = shmobile_smp_scu_boot_secondary(cpu, idle);
+       if (ret)
+               return ret;
 
-       if (cpu < ARRAY_SIZE(r8a7779_ch_cpu))
-               ch = r8a7779_ch_cpu[cpu];
+       if (lcpu < ARRAY_SIZE(r8a7779_ch_cpu))
+               ch = r8a7779_ch_cpu[lcpu];
 
        if (ch)
                ret = r8a7779_sysc_power_up(ch);
+       else
+               ret = -EIO;
 
        return ret;
 }
 
 static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus)
 {
-       scu_enable(shmobile_scu_base);
-
        /* Map the reset vector (in headsmp-scu.S, headsmp.S) */
        __raw_writel(__pa(shmobile_boot_vector), AVECR);
        shmobile_boot_fn = virt_to_phys(shmobile_boot_scu);
        shmobile_boot_arg = (unsigned long)shmobile_scu_base;
 
-       /* enable cache coherency on booting CPU */
-       scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);
+       /* setup r8a7779 specific SCU bits */
+       shmobile_scu_base = IOMEM(R8A7779_SCU_BASE);
+       shmobile_smp_scu_prepare_cpus(max_cpus);
 
        r8a7779_pm_init();
 
@@ -117,56 +121,15 @@ static void __init r8a7779_smp_prepare_cpus(unsigned int max_cpus)
        r8a7779_platform_cpu_kill(3);
 }
 
-static void __init r8a7779_smp_init_cpus(void)
-{
-       /* setup r8a7779 specific SCU base */
-       shmobile_scu_base = IOMEM(R8A7779_SCU_BASE);
-
-       shmobile_smp_init_cpus(scu_get_core_count(shmobile_scu_base));
-}
-
 #ifdef CONFIG_HOTPLUG_CPU
-static int r8a7779_scu_psr_core_disabled(int cpu)
-{
-       unsigned long mask = 3 << (cpu * 8);
-
-       if ((__raw_readl(shmobile_scu_base + 8) & mask) == mask)
-               return 1;
-
-       return 0;
-}
-
 static int r8a7779_cpu_kill(unsigned int cpu)
 {
-       int k;
-
-       /* this function is running on another CPU than the offline target,
-        * here we need wait for shutdown code in platform_cpu_die() to
-        * finish before asking SoC-specific code to power off the CPU core.
-        */
-       for (k = 0; k < 1000; k++) {
-               if (r8a7779_scu_psr_core_disabled(cpu))
-                       return r8a7779_platform_cpu_kill(cpu);
-
-               mdelay(1);
-       }
+       if (shmobile_smp_scu_cpu_kill(cpu))
+               return r8a7779_platform_cpu_kill(cpu);
 
        return 0;
 }
 
-static void r8a7779_cpu_die(unsigned int cpu)
-{
-       dsb();
-       flush_cache_all();
-
-       /* disable cache coherency */
-       scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF);
-
-       /* Endless loop until power off from r8a7779_cpu_kill() */
-       while (1)
-               cpu_do_idle();
-}
-
 static int r8a7779_cpu_disable(unsigned int cpu)
 {
        /* only CPU1->3 have power domains, do not allow hotplug of CPU0 */
@@ -175,12 +138,11 @@ static int r8a7779_cpu_disable(unsigned int cpu)
 #endif /* CONFIG_HOTPLUG_CPU */
 
 struct smp_operations r8a7779_smp_ops  __initdata = {
-       .smp_init_cpus          = r8a7779_smp_init_cpus,
        .smp_prepare_cpus       = r8a7779_smp_prepare_cpus,
        .smp_boot_secondary     = r8a7779_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
-       .cpu_kill               = r8a7779_cpu_kill,
-       .cpu_die                = r8a7779_cpu_die,
        .cpu_disable            = r8a7779_cpu_disable,
+       .cpu_die                = shmobile_smp_scu_cpu_die,
+       .cpu_kill               = r8a7779_cpu_kill,
 #endif
 };
index d5fc3ed4e31542c2bc1c8a68fb0ebe923105a21d..0baa24443793402b2313969e8a2bdb0ac81e0038 100644 (file)
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/smp.h>
-#include <linux/spinlock.h>
 #include <linux/io.h>
 #include <linux/delay.h>
 #include <mach/common.h>
-#include <asm/cacheflush.h>
-#include <asm/smp_plat.h>
 #include <mach/sh73a0.h>
-#include <asm/smp_scu.h>
+#include <asm/smp_plat.h>
 #include <asm/smp_twd.h>
 
 #define WUPCR          IOMEM(0xe6151010)
@@ -36,8 +33,6 @@
 #define SBAR           IOMEM(0xe6180020)
 #define APARMBAREA     IOMEM(0xe6f10020)
 
-#define PSTR_SHUTDOWN_MODE     3
-
 #define SH73A0_SCU_BASE 0xf0000000
 
 #ifdef CONFIG_HAVE_ARM_TWD
@@ -50,69 +45,33 @@ void __init sh73a0_register_twd(void)
 
 static int sh73a0_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-       cpu = cpu_logical_map(cpu);
+       unsigned int lcpu = cpu_logical_map(cpu);
+       int ret;
 
-       if (((__raw_readl(PSTR) >> (4 * cpu)) & 3) == 3)
-               __raw_writel(1 << cpu, WUPCR);  /* wake up */
+       ret = shmobile_smp_scu_boot_secondary(cpu, idle);
+       if (ret)
+               return ret;
+
+       if (((__raw_readl(PSTR) >> (4 * lcpu)) & 3) == 3)
+               __raw_writel(1 << lcpu, WUPCR); /* wake up */
        else
-               __raw_writel(1 << cpu, SRESCR); /* reset */
+               __raw_writel(1 << lcpu, SRESCR);        /* reset */
 
        return 0;
 }
 
 static void __init sh73a0_smp_prepare_cpus(unsigned int max_cpus)
 {
-       scu_enable(shmobile_scu_base);
-
-       /* Map the reset vector (in headsmp-scu.S, headsmp.S) */
+       /* Map the reset vector (in headsmp.S) */
        __raw_writel(0, APARMBAREA);      /* 4k */
        __raw_writel(__pa(shmobile_boot_vector), SBAR);
-       shmobile_boot_fn = virt_to_phys(shmobile_boot_scu);
-       shmobile_boot_arg = (unsigned long)shmobile_scu_base;
 
-       /* enable cache coherency on booting CPU */
-       scu_power_mode(shmobile_scu_base, SCU_PM_NORMAL);
-}
-
-static void __init sh73a0_smp_init_cpus(void)
-{
-       /* setup sh73a0 specific SCU base */
+       /* setup sh73a0 specific SCU bits */
        shmobile_scu_base = IOMEM(SH73A0_SCU_BASE);
-
-       shmobile_smp_init_cpus(scu_get_core_count(shmobile_scu_base));
+       shmobile_smp_scu_prepare_cpus(max_cpus);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static int sh73a0_cpu_kill(unsigned int cpu)
-{
-
-       int k;
-       u32 pstr;
-
-       /*
-        * wait until the power status register confirms the shutdown of the
-        * offline target
-        */
-       for (k = 0; k < 1000; k++) {
-               pstr = (__raw_readl(PSTR) >> (4 * cpu)) & 3;
-               if (pstr == PSTR_SHUTDOWN_MODE)
-                       return 1;
-
-               mdelay(1);
-       }
-
-       return 0;
-}
-
-static void sh73a0_cpu_die(unsigned int cpu)
-{
-       /* Set power off mode. This takes the CPU out of the MP cluster */
-       scu_power_mode(shmobile_scu_base, SCU_PM_POWEROFF);
-
-       /* Enter shutdown mode */
-       cpu_do_idle();
-}
-
 static int sh73a0_cpu_disable(unsigned int cpu)
 {
        return 0; /* CPU0 and CPU1 supported */
@@ -120,12 +79,11 @@ static int sh73a0_cpu_disable(unsigned int cpu)
 #endif /* CONFIG_HOTPLUG_CPU */
 
 struct smp_operations sh73a0_smp_ops __initdata = {
-       .smp_init_cpus          = sh73a0_smp_init_cpus,
        .smp_prepare_cpus       = sh73a0_smp_prepare_cpus,
        .smp_boot_secondary     = sh73a0_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
-       .cpu_kill               = sh73a0_cpu_kill,
-       .cpu_die                = sh73a0_cpu_die,
        .cpu_disable            = sh73a0_cpu_disable,
+       .cpu_die                = shmobile_smp_scu_cpu_die,
+       .cpu_kill               = shmobile_smp_scu_cpu_kill,
 #endif
 };
index f321dbeb23795b7af850985ae59d16bffdcfc8c6..62d7052d6f215f7679d88f12365dc8fb048de253 100644 (file)
@@ -59,7 +59,3 @@ void __init shmobile_earlytimer_init(void)
        late_time_init = shmobile_late_time_init;
 }
 
-void __init shmobile_timer_init(void)
-{
-       clocksource_of_init();
-}
index bfe443daf4b06d1aba8fc33f0266887c1cf88ab7..ec0807247e60cb1a40d1f4f8dbdb23b266932b31 100644 (file)
@@ -17,7 +17,6 @@
 #include "ste-dma40-db8500.h"
 #include "board-mop500.h"
 #include "devices-db8500.h"
-#include "pins-db8500.h"
 
 static struct stedma40_chan_cfg msp0_dma_rx = {
        .high_priority = true,
index 7936d40a5c37198b3615ea2eb997c41bb3ae4890..0efb1560fc355dc4f1f7887bfcba4cca260fda27 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <asm/mach-types.h>
 
-#include "pins-db8500.h"
 #include "board-mop500.h"
 
 enum custom_pin_cfg_t {
index 4e7ab3a0dd6041f250d1f37c44d5b7e774d5664f..ad0806eff7624da302513909ab41a3af400ed820 100644 (file)
@@ -324,21 +324,19 @@ static struct lp55xx_platform_data __initdata lp5521_sec_data = {
        .clock_mode     = LP55XX_CLOCK_EXT,
 };
 
+/* I2C0 devices only available on the first HREF/MOP500 */
 static struct i2c_board_info __initdata mop500_i2c0_devices[] = {
        {
                I2C_BOARD_INFO("tc3589x", 0x42),
                .irq            = NOMADIK_GPIO_TO_IRQ(217),
                .platform_data  = &mop500_tc35892_data,
        },
-       /* I2C0 devices only available prior to HREFv60 */
        {
                I2C_BOARD_INFO("tps61052", 0x33),
                .platform_data  = &mop500_tps61052_data,
        },
 };
 
-#define NUM_PRE_V60_I2C0_DEVICES 1
-
 static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
        {
                /* lp5521 LED driver, 1st device */
@@ -356,6 +354,17 @@ static struct i2c_board_info __initdata mop500_i2c2_devices[] = {
        },
 };
 
+static int __init mop500_i2c_board_init(void)
+{
+       if (machine_is_u8500())
+               mop500_uib_i2c_add(0, mop500_i2c0_devices,
+                                  ARRAY_SIZE(mop500_i2c0_devices));
+       mop500_uib_i2c_add(2, mop500_i2c2_devices,
+                          ARRAY_SIZE(mop500_i2c2_devices));
+       return 0;
+}
+device_initcall(mop500_i2c_board_init);
+
 static void __init mop500_i2c_init(struct device *parent)
 {
        db8500_add_i2c0(parent, NULL);
@@ -564,7 +573,6 @@ static struct platform_device *snowball_platform_devs[] __initdata = {
 static void __init mop500_init_machine(void)
 {
        struct device *parent = NULL;
-       int i2c0_devs;
        int i;
 
        platform_device_register(&db8500_prcmu_device);
@@ -587,19 +595,13 @@ static void __init mop500_init_machine(void)
        mop500_spi_init(parent);
        mop500_audio_init(parent);
        mop500_uart_init(parent);
-
        u8500_cryp1_hash1_init(parent);
 
-       i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
-
-       i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
-       i2c_register_board_info(2, mop500_i2c2_devices,
-                               ARRAY_SIZE(mop500_i2c2_devices));
-
        /* This board has full regulator constraints */
        regulator_has_full_constraints();
 }
 
+
 static void __init snowball_init_machine(void)
 {
        struct device *parent = NULL;
@@ -634,7 +636,6 @@ static void __init snowball_init_machine(void)
 static void __init hrefv60_init_machine(void)
 {
        struct device *parent = NULL;
-       int i2c0_devs;
        int i;
 
        platform_device_register(&db8500_prcmu_device);
@@ -663,14 +664,6 @@ static void __init hrefv60_init_machine(void)
        mop500_audio_init(parent);
        mop500_uart_init(parent);
 
-       i2c0_devs = ARRAY_SIZE(mop500_i2c0_devices);
-
-       i2c0_devs -= NUM_PRE_V60_I2C0_DEVICES;
-
-       i2c_register_board_info(0, mop500_i2c0_devices, i2c0_devs);
-       i2c_register_board_info(2, mop500_i2c2_devices,
-                               ARRAY_SIZE(mop500_i2c2_devices));
-
        /* This board has full regulator constraints */
        regulator_has_full_constraints();
 }
index bfaf95d22cbb8bd3ee620f5930dc2cf533a96284..301c3460d96af48f8bed5f3f89378cad8893c486 100644 (file)
@@ -156,7 +156,8 @@ static void __init db8500_add_gpios(struct device *parent)
                .supports_sleepmode = true,
        };
 
-       dbx500_add_gpios(parent, ARRAY_AND_SIZE(db8500_gpio_base),
+       dbx500_add_gpios(parent, db8500_gpio_base,
+                        ARRAY_SIZE(db8500_gpio_base),
                         IRQ_DB8500_GPIO0, &pdata);
        dbx500_add_pinctrl(parent, "pinctrl-db8500", U8500_PRCMU_BASE);
 }
diff --git a/arch/arm/mach-ux500/pins-db8500.h b/arch/arm/mach-ux500/pins-db8500.h
deleted file mode 100644 (file)
index 062c7ac..0000000
+++ /dev/null
@@ -1,746 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * License terms: GNU General Public License, version 2
- * Author: Rabin Vincent <rabin.vincent@stericsson.com>
- */
-
-#ifndef __MACH_PINS_DB8500_H
-#define __MACH_PINS_DB8500_H
-
-/*
- * TODO: Eventually encode all non-board specific pull up/down configuration
- * here.
- */
-
-#define GPIO0_GPIO             PIN_CFG(0, GPIO)
-#define GPIO0_U0_CTSn          PIN_CFG(0, ALT_A)
-#define GPIO0_TRIG_OUT         PIN_CFG(0, ALT_B)
-#define GPIO0_IP_TDO           PIN_CFG(0, ALT_C)
-
-#define GPIO1_GPIO             PIN_CFG(1, GPIO)
-#define GPIO1_U0_RTSn          PIN_CFG(1, ALT_A)
-#define GPIO1_TRIG_IN          PIN_CFG(1, ALT_B)
-#define GPIO1_IP_TDI           PIN_CFG(1, ALT_C)
-
-#define GPIO2_GPIO             PIN_CFG(2, GPIO)
-#define GPIO2_U0_RXD           PIN_CFG(2, ALT_A)
-#define GPIO2_NONE             PIN_CFG(2, ALT_B)
-#define GPIO2_IP_TMS           PIN_CFG(2, ALT_C)
-
-#define GPIO3_GPIO             PIN_CFG(3, GPIO)
-#define GPIO3_U0_TXD           PIN_CFG(3, ALT_A)
-#define GPIO3_NONE             PIN_CFG(3, ALT_B)
-#define GPIO3_IP_TCK           PIN_CFG(3, ALT_C)
-
-#define GPIO4_GPIO             PIN_CFG(4, GPIO)
-#define GPIO4_U1_RXD           PIN_CFG(4, ALT_A)
-#define GPIO4_I2C4_SCL         PIN_CFG(4, ALT_B)
-#define GPIO4_IP_TRSTn         PIN_CFG(4, ALT_C)
-
-#define GPIO5_GPIO             PIN_CFG(5, GPIO)
-#define GPIO5_U1_TXD           PIN_CFG(5, ALT_A)
-#define GPIO5_I2C4_SDA         PIN_CFG(5, ALT_B)
-#define GPIO5_IP_GPIO6         PIN_CFG(5, ALT_C)
-
-#define GPIO6_GPIO             PIN_CFG(6, GPIO)
-#define GPIO6_U1_CTSn          PIN_CFG(6, ALT_A)
-#define GPIO6_I2C1_SCL         PIN_CFG(6, ALT_B)
-#define GPIO6_IP_GPIO0         PIN_CFG(6, ALT_C)
-
-#define GPIO7_GPIO             PIN_CFG(7, GPIO)
-#define GPIO7_U1_RTSn          PIN_CFG(7, ALT_A)
-#define GPIO7_I2C1_SDA         PIN_CFG(7, ALT_B)
-#define GPIO7_IP_GPIO1         PIN_CFG(7, ALT_C)
-
-#define GPIO8_GPIO             PIN_CFG(8, GPIO)
-#define GPIO8_IPI2C_SDA                PIN_CFG(8, ALT_A)
-#define GPIO8_I2C2_SDA         PIN_CFG(8, ALT_B)
-
-#define GPIO9_GPIO             PIN_CFG(9, GPIO)
-#define GPIO9_IPI2C_SCL                PIN_CFG(9, ALT_A)
-#define GPIO9_I2C2_SCL         PIN_CFG(9, ALT_B)
-
-#define GPIO10_GPIO            PIN_CFG(10, GPIO)
-#define GPIO10_IPI2C_SDA       PIN_CFG(10, ALT_A)
-#define GPIO10_I2C2_SDA                PIN_CFG(10, ALT_B)
-#define GPIO10_IP_GPIO3                PIN_CFG(10, ALT_C)
-
-#define GPIO11_GPIO            PIN_CFG(11, GPIO)
-#define GPIO11_IPI2C_SCL       PIN_CFG(11, ALT_A)
-#define GPIO11_I2C2_SCL                PIN_CFG(11, ALT_B)
-#define GPIO11_IP_GPIO2                PIN_CFG(11, ALT_C)
-
-#define GPIO12_GPIO            PIN_CFG(12, GPIO)
-#define GPIO12_MSP0_TXD                PIN_CFG(12, ALT_A)
-#define GPIO12_MSP0_RXD                PIN_CFG(12, ALT_B)
-
-#define GPIO13_GPIO            PIN_CFG(13, GPIO)
-#define GPIO13_MSP0_TFS                PIN_CFG(13, ALT_A)
-
-#define GPIO14_GPIO            PIN_CFG(14, GPIO)
-#define GPIO14_MSP0_TCK                PIN_CFG(14, ALT_A)
-
-#define GPIO15_GPIO            PIN_CFG(15, GPIO)
-#define GPIO15_MSP0_RXD                PIN_CFG(15, ALT_A)
-#define GPIO15_MSP0_TXD                PIN_CFG(15, ALT_B)
-
-#define GPIO16_GPIO            PIN_CFG(16, GPIO)
-#define GPIO16_MSP0_RFS                PIN_CFG(16, ALT_A)
-#define GPIO16_I2C1_SCL                PIN_CFG(16, ALT_B)
-#define GPIO16_SLIM0_DAT       PIN_CFG(16, ALT_C)
-
-#define GPIO17_GPIO            PIN_CFG(17, GPIO)
-#define GPIO17_MSP0_RCK                PIN_CFG(17, ALT_A)
-#define GPIO17_I2C1_SDA                PIN_CFG(17, ALT_B)
-#define GPIO17_SLIM0_CLK       PIN_CFG(17, ALT_C)
-
-#define GPIO18_GPIO            PIN_CFG(18, GPIO)
-#define GPIO18_MC0_CMDDIR      PIN_CFG_INPUT(18, ALT_A, PULLUP)
-#define GPIO18_U2_RXD          PIN_CFG(18, ALT_B)
-#define GPIO18_MS_IEP          PIN_CFG(18, ALT_C)
-
-#define GPIO19_GPIO            PIN_CFG(19, GPIO)
-#define GPIO19_MC0_DAT0DIR     PIN_CFG_INPUT(19, ALT_A, PULLUP)
-#define GPIO19_U2_TXD          PIN_CFG(19, ALT_B)
-#define GPIO19_MS_DAT0DIR      PIN_CFG(19, ALT_C)
-
-#define GPIO20_GPIO            PIN_CFG(20, GPIO)
-#define GPIO20_MC0_DAT2DIR     PIN_CFG_INPUT(20, ALT_A, PULLUP)
-#define GPIO20_UARTMOD_TXD     PIN_CFG(20, ALT_B)
-#define GPIO20_IP_TRIGOUT      PIN_CFG(20, ALT_C)
-
-#define GPIO21_GPIO            PIN_CFG(21, GPIO)
-#define GPIO21_MC0_DAT31DIR    PIN_CFG_INPUT(21, ALT_A, PULLUP)
-#define GPIO21_MSP0_SCK                PIN_CFG(21, ALT_B)
-#define GPIO21_MS_DAT31DIR     PIN_CFG(21, ALT_C)
-
-#define GPIO22_GPIO            PIN_CFG(22, GPIO)
-#define GPIO22_MC0_FBCLK       PIN_CFG_INPUT(22, ALT_A, PULLUP)
-#define GPIO22_UARTMOD_RXD     PIN_CFG(22, ALT_B)
-#define GPIO22_MS_FBCLK                PIN_CFG(22, ALT_C)
-
-#define GPIO23_GPIO            PIN_CFG(23, GPIO)
-#define GPIO23_MC0_CLK         PIN_CFG_INPUT(23, ALT_A, PULLUP)
-#define GPIO23_STMMOD_CLK      PIN_CFG(23, ALT_B)
-#define GPIO23_MS_CLK          PIN_CFG(23, ALT_C)
-
-#define GPIO24_GPIO            PIN_CFG(24, GPIO)
-#define GPIO24_MC0_CMD         PIN_CFG_INPUT(24, ALT_A, PULLUP)
-#define GPIO24_UARTMOD_RXD     PIN_CFG(24, ALT_B)
-#define GPIO24_MS_BS           PIN_CFG(24, ALT_C)
-
-#define GPIO25_GPIO            PIN_CFG(25, GPIO)
-#define GPIO25_MC0_DAT0                PIN_CFG_INPUT(25, ALT_A, PULLUP)
-#define GPIO25_STMMOD_DAT0     PIN_CFG(25, ALT_B)
-#define GPIO25_MS_DAT0         PIN_CFG(25, ALT_C)
-
-#define GPIO26_GPIO            PIN_CFG(26, GPIO)
-#define GPIO26_MC0_DAT1                PIN_CFG_INPUT(26, ALT_A, PULLUP)
-#define GPIO26_STMMOD_DAT1     PIN_CFG(26, ALT_B)
-#define GPIO26_MS_DAT1         PIN_CFG(26, ALT_C)
-
-#define GPIO27_GPIO            PIN_CFG(27, GPIO)
-#define GPIO27_MC0_DAT2                PIN_CFG_INPUT(27, ALT_A, PULLUP)
-#define GPIO27_STMMOD_DAT2     PIN_CFG(27, ALT_B)
-#define GPIO27_MS_DAT2         PIN_CFG(27, ALT_C)
-
-#define GPIO28_GPIO            PIN_CFG(28, GPIO)
-#define GPIO28_MC0_DAT3                PIN_CFG_INPUT(28, ALT_A, PULLUP)
-#define GPIO28_STMMOD_DAT3     PIN_CFG(28, ALT_B)
-#define GPIO28_MS_DAT3         PIN_CFG(28, ALT_C)
-
-#define GPIO29_GPIO            PIN_CFG(29, GPIO)
-#define GPIO29_MC0_DAT4                PIN_CFG(29, ALT_A)
-#define GPIO29_SPI3_CLK                PIN_CFG(29, ALT_B)
-#define GPIO29_U2_RXD          PIN_CFG(29, ALT_C)
-
-#define GPIO30_GPIO            PIN_CFG(30, GPIO)
-#define GPIO30_MC0_DAT5                PIN_CFG(30, ALT_A)
-#define GPIO30_SPI3_RXD                PIN_CFG(30, ALT_B)
-#define GPIO30_U2_TXD          PIN_CFG(30, ALT_C)
-
-#define GPIO31_GPIO            PIN_CFG(31, GPIO)
-#define GPIO31_MC0_DAT6                PIN_CFG(31, ALT_A)
-#define GPIO31_SPI3_FRM                PIN_CFG(31, ALT_B)
-#define GPIO31_U2_CTSn         PIN_CFG(31, ALT_C)
-
-#define GPIO32_GPIO            PIN_CFG(32, GPIO)
-#define GPIO32_MC0_DAT7                PIN_CFG(32, ALT_A)
-#define GPIO32_SPI3_TXD                PIN_CFG(32, ALT_B)
-#define GPIO32_U2_RTSn         PIN_CFG(32, ALT_C)
-
-#define GPIO33_GPIO            PIN_CFG(33, GPIO)
-#define GPIO33_MSP1_TXD                PIN_CFG(33, ALT_A)
-#define GPIO33_MSP1_RXD                PIN_CFG(33, ALT_B)
-#define GPIO33_U0_DTRn         PIN_CFG(33, ALT_C)
-
-#define GPIO34_GPIO            PIN_CFG(34, GPIO)
-#define GPIO34_MSP1_TFS                PIN_CFG(34, ALT_A)
-#define GPIO34_NONE            PIN_CFG(34, ALT_B)
-#define GPIO34_U0_DCDn         PIN_CFG(34, ALT_C)
-
-#define GPIO35_GPIO            PIN_CFG(35, GPIO)
-#define GPIO35_MSP1_TCK                PIN_CFG(35, ALT_A)
-#define GPIO35_NONE            PIN_CFG(35, ALT_B)
-#define GPIO35_U0_DSRn         PIN_CFG(35, ALT_C)
-
-#define GPIO36_GPIO            PIN_CFG(36, GPIO)
-#define GPIO36_MSP1_RXD                PIN_CFG(36, ALT_A)
-#define GPIO36_MSP1_TXD                PIN_CFG(36, ALT_B)
-#define GPIO36_U0_RIn          PIN_CFG(36, ALT_C)
-
-#define GPIO64_GPIO            PIN_CFG(64, GPIO)
-#define GPIO64_LCDB_DE         PIN_CFG(64, ALT_A)
-#define GPIO64_KP_O1           PIN_CFG(64, ALT_B)
-#define GPIO64_IP_GPIO4                PIN_CFG(64, ALT_C)
-
-#define GPIO65_GPIO            PIN_CFG(65, GPIO)
-#define GPIO65_LCDB_HSO                PIN_CFG(65, ALT_A)
-#define GPIO65_KP_O0           PIN_CFG(65, ALT_B)
-#define GPIO65_IP_GPIO5                PIN_CFG(65, ALT_C)
-
-#define GPIO66_GPIO            PIN_CFG(66, GPIO)
-#define GPIO66_LCDB_VSO                PIN_CFG(66, ALT_A)
-#define GPIO66_KP_I1           PIN_CFG(66, ALT_B)
-#define GPIO66_IP_GPIO6                PIN_CFG(66, ALT_C)
-
-#define GPIO67_GPIO            PIN_CFG(67, GPIO)
-#define GPIO67_LCDB_CLK                PIN_CFG(67, ALT_A)
-#define GPIO67_KP_I0           PIN_CFG(67, ALT_B)
-#define GPIO67_IP_GPIO7                PIN_CFG(67, ALT_C)
-
-#define GPIO68_GPIO            PIN_CFG(68, GPIO)
-#define GPIO68_LCD_VSI0                PIN_CFG(68, ALT_A)
-#define GPIO68_KP_O7           PIN_CFG(68, ALT_B)
-#define GPIO68_SM_CLE          PIN_CFG(68, ALT_C)
-
-#define GPIO69_GPIO            PIN_CFG(69, GPIO)
-#define GPIO69_LCD_VSI1                PIN_CFG(69, ALT_A)
-#define GPIO69_KP_I7           PIN_CFG(69, ALT_B)
-#define GPIO69_SM_ALE          PIN_CFG(69, ALT_C)
-
-#define GPIO70_GPIO            PIN_CFG(70, GPIO)
-#define GPIO70_LCD_D0          PIN_CFG(70, ALT_A)
-#define GPIO70_KP_O5           PIN_CFG(70, ALT_B)
-#define GPIO70_STMAPE_CLK      PIN_CFG(70, ALT_C)
-
-#define GPIO71_GPIO            PIN_CFG(71, GPIO)
-#define GPIO71_LCD_D1          PIN_CFG(71, ALT_A)
-#define GPIO71_KP_O4           PIN_CFG(71, ALT_B)
-#define GPIO71_STMAPE_DAT3     PIN_CFG(71, ALT_C)
-
-#define GPIO72_GPIO            PIN_CFG(72, GPIO)
-#define GPIO72_LCD_D2          PIN_CFG(72, ALT_A)
-#define GPIO72_KP_O3           PIN_CFG(72, ALT_B)
-#define GPIO72_STMAPE_DAT2     PIN_CFG(72, ALT_C)
-
-#define GPIO73_GPIO            PIN_CFG(73, GPIO)
-#define GPIO73_LCD_D3          PIN_CFG(73, ALT_A)
-#define GPIO73_KP_O2           PIN_CFG(73, ALT_B)
-#define GPIO73_STMAPE_DAT1     PIN_CFG(73, ALT_C)
-
-#define GPIO74_GPIO            PIN_CFG(74, GPIO)
-#define GPIO74_LCD_D4          PIN_CFG(74, ALT_A)
-#define GPIO74_KP_I5           PIN_CFG(74, ALT_B)
-#define GPIO74_STMAPE_DAT0     PIN_CFG(74, ALT_C)
-
-#define GPIO75_GPIO            PIN_CFG(75, GPIO)
-#define GPIO75_LCD_D5          PIN_CFG(75, ALT_A)
-#define GPIO75_KP_I4           PIN_CFG(75, ALT_B)
-#define GPIO75_U2_RXD          PIN_CFG(75, ALT_C)
-
-#define GPIO76_GPIO            PIN_CFG(76, GPIO)
-#define GPIO76_LCD_D6          PIN_CFG(76, ALT_A)
-#define GPIO76_KP_I3           PIN_CFG(76, ALT_B)
-#define GPIO76_U2_TXD          PIN_CFG(76, ALT_C)
-
-#define GPIO77_GPIO            PIN_CFG(77, GPIO)
-#define GPIO77_LCD_D7          PIN_CFG(77, ALT_A)
-#define GPIO77_KP_I2           PIN_CFG(77, ALT_B)
-#define GPIO77_NONE            PIN_CFG(77, ALT_C)
-
-#define GPIO78_GPIO            PIN_CFG(78, GPIO)
-#define GPIO78_LCD_D8          PIN_CFG(78, ALT_A)
-#define GPIO78_KP_O6           PIN_CFG(78, ALT_B)
-#define GPIO78_IP_GPIO2                PIN_CFG(78, ALT_C)
-
-#define GPIO79_GPIO            PIN_CFG(79, GPIO)
-#define GPIO79_LCD_D9          PIN_CFG(79, ALT_A)
-#define GPIO79_KP_I6           PIN_CFG(79, ALT_B)
-#define GPIO79_IP_GPIO3                PIN_CFG(79, ALT_C)
-
-#define GPIO80_GPIO            PIN_CFG(80, GPIO)
-#define GPIO80_LCD_D10         PIN_CFG(80, ALT_A)
-#define GPIO80_KP_SKA0         PIN_CFG(80, ALT_B)
-#define GPIO80_IP_GPIO4                PIN_CFG(80, ALT_C)
-
-#define GPIO81_GPIO            PIN_CFG(81, GPIO)
-#define GPIO81_LCD_D11         PIN_CFG(81, ALT_A)
-#define GPIO81_KP_SKB0         PIN_CFG(81, ALT_B)
-#define GPIO81_IP_GPIO5                PIN_CFG(81, ALT_C)
-
-#define GPIO82_GPIO            PIN_CFG(82, GPIO)
-#define GPIO82_LCD_D12         PIN_CFG(82, ALT_A)
-#define GPIO82_KP_O5           PIN_CFG(82, ALT_B)
-
-#define GPIO83_GPIO            PIN_CFG(83, GPIO)
-#define GPIO83_LCD_D13         PIN_CFG(83, ALT_A)
-#define GPIO83_KP_O4           PIN_CFG(83, ALT_B)
-
-#define GPIO84_GPIO            PIN_CFG(84, GPIO)
-#define GPIO84_LCD_D14         PIN_CFG(84, ALT_A)
-#define GPIO84_KP_I5           PIN_CFG(84, ALT_B)
-
-#define GPIO85_GPIO            PIN_CFG(85, GPIO)
-#define GPIO85_LCD_D15         PIN_CFG(85, ALT_A)
-#define GPIO85_KP_I4           PIN_CFG(85, ALT_B)
-
-#define GPIO86_GPIO            PIN_CFG(86, GPIO)
-#define GPIO86_LCD_D16         PIN_CFG(86, ALT_A)
-#define GPIO86_SM_ADQ0         PIN_CFG(86, ALT_B)
-#define GPIO86_MC5_DAT0                PIN_CFG(86, ALT_C)
-
-#define GPIO87_GPIO            PIN_CFG(87, GPIO)
-#define GPIO87_LCD_D17         PIN_CFG(87, ALT_A)
-#define GPIO87_SM_ADQ1         PIN_CFG(87, ALT_B)
-#define GPIO87_MC5_DAT1                PIN_CFG(87, ALT_C)
-
-#define GPIO88_GPIO            PIN_CFG(88, GPIO)
-#define GPIO88_LCD_D18         PIN_CFG(88, ALT_A)
-#define GPIO88_SM_ADQ2         PIN_CFG(88, ALT_B)
-#define GPIO88_MC5_DAT2                PIN_CFG(88, ALT_C)
-
-#define GPIO89_GPIO            PIN_CFG(89, GPIO)
-#define GPIO89_LCD_D19         PIN_CFG(89, ALT_A)
-#define GPIO89_SM_ADQ3         PIN_CFG(89, ALT_B)
-#define GPIO89_MC5_DAT3                PIN_CFG(89, ALT_C)
-
-#define GPIO90_GPIO            PIN_CFG(90, GPIO)
-#define GPIO90_LCD_D20         PIN_CFG(90, ALT_A)
-#define GPIO90_SM_ADQ4         PIN_CFG(90, ALT_B)
-#define GPIO90_MC5_CMD         PIN_CFG(90, ALT_C)
-
-#define GPIO91_GPIO            PIN_CFG(91, GPIO)
-#define GPIO91_LCD_D21         PIN_CFG(91, ALT_A)
-#define GPIO91_SM_ADQ5         PIN_CFG(91, ALT_B)
-#define GPIO91_MC5_FBCLK       PIN_CFG(91, ALT_C)
-
-#define GPIO92_GPIO            PIN_CFG(92, GPIO)
-#define GPIO92_LCD_D22         PIN_CFG(92, ALT_A)
-#define GPIO92_SM_ADQ6         PIN_CFG(92, ALT_B)
-#define GPIO92_MC5_CLK         PIN_CFG(92, ALT_C)
-
-#define GPIO93_GPIO            PIN_CFG(93, GPIO)
-#define GPIO93_LCD_D23         PIN_CFG(93, ALT_A)
-#define GPIO93_SM_ADQ7         PIN_CFG(93, ALT_B)
-#define GPIO93_MC5_DAT4                PIN_CFG(93, ALT_C)
-
-#define GPIO94_GPIO            PIN_CFG(94, GPIO)
-#define GPIO94_KP_O7           PIN_CFG(94, ALT_A)
-#define GPIO94_SM_ADVn         PIN_CFG(94, ALT_B)
-#define GPIO94_MC5_DAT5                PIN_CFG(94, ALT_C)
-
-#define GPIO95_GPIO            PIN_CFG(95, GPIO)
-#define GPIO95_KP_I7           PIN_CFG(95, ALT_A)
-#define GPIO95_SM_CS0n         PIN_CFG(95, ALT_B)
-#define GPIO95_SM_PS0n         PIN_CFG(95, ALT_C)
-
-#define GPIO96_GPIO            PIN_CFG(96, GPIO)
-#define GPIO96_KP_O6           PIN_CFG(96, ALT_A)
-#define GPIO96_SM_OEn          PIN_CFG(96, ALT_B)
-#define GPIO96_MC5_DAT6                PIN_CFG(96, ALT_C)
-
-#define GPIO97_GPIO            PIN_CFG(97, GPIO)
-#define GPIO97_KP_I6           PIN_CFG(97, ALT_A)
-#define GPIO97_SM_WEn          PIN_CFG(97, ALT_B)
-#define GPIO97_MC5_DAT7                PIN_CFG(97, ALT_C)
-
-#define GPIO128_GPIO           PIN_CFG(128, GPIO)
-#define GPIO128_MC2_CLK                PIN_CFG_INPUT(128, ALT_A, PULLUP)
-#define GPIO128_SM_CKO         PIN_CFG(128, ALT_B)
-
-#define GPIO129_GPIO           PIN_CFG(129, GPIO)
-#define GPIO129_MC2_CMD                PIN_CFG_INPUT(129, ALT_A, PULLUP)
-#define GPIO129_SM_WAIT0n      PIN_CFG(129, ALT_B)
-
-#define GPIO130_GPIO           PIN_CFG(130, GPIO)
-#define GPIO130_MC2_FBCLK      PIN_CFG_INPUT(130, ALT_A, PULLUP)
-#define GPIO130_SM_FBCLK       PIN_CFG(130, ALT_B)
-#define GPIO130_MC2_RSTN       PIN_CFG(130, ALT_C)
-
-#define GPIO131_GPIO           PIN_CFG(131, GPIO)
-#define GPIO131_MC2_DAT0       PIN_CFG_INPUT(131, ALT_A, PULLUP)
-#define GPIO131_SM_ADQ8                PIN_CFG(131, ALT_B)
-
-#define GPIO132_GPIO           PIN_CFG(132, GPIO)
-#define GPIO132_MC2_DAT1       PIN_CFG_INPUT(132, ALT_A, PULLUP)
-#define GPIO132_SM_ADQ9                PIN_CFG(132, ALT_B)
-
-#define GPIO133_GPIO           PIN_CFG(133, GPIO)
-#define GPIO133_MC2_DAT2       PIN_CFG_INPUT(133, ALT_A, PULLUP)
-#define GPIO133_SM_ADQ10       PIN_CFG(133, ALT_B)
-
-#define GPIO134_GPIO           PIN_CFG(134, GPIO)
-#define GPIO134_MC2_DAT3       PIN_CFG_INPUT(134, ALT_A, PULLUP)
-#define GPIO134_SM_ADQ11       PIN_CFG(134, ALT_B)
-
-#define GPIO135_GPIO           PIN_CFG(135, GPIO)
-#define GPIO135_MC2_DAT4       PIN_CFG_INPUT(135, ALT_A, PULLUP)
-#define GPIO135_SM_ADQ12       PIN_CFG(135, ALT_B)
-
-#define GPIO136_GPIO           PIN_CFG(136, GPIO)
-#define GPIO136_MC2_DAT5       PIN_CFG_INPUT(136, ALT_A, PULLUP)
-#define GPIO136_SM_ADQ13       PIN_CFG(136, ALT_B)
-
-#define GPIO137_GPIO           PIN_CFG(137, GPIO)
-#define GPIO137_MC2_DAT6       PIN_CFG_INPUT(137, ALT_A, PULLUP)
-#define GPIO137_SM_ADQ14       PIN_CFG(137, ALT_B)
-
-#define GPIO138_GPIO           PIN_CFG(138, GPIO)
-#define GPIO138_MC2_DAT7       PIN_CFG_INPUT(138, ALT_A, PULLUP)
-#define GPIO138_SM_ADQ15       PIN_CFG(138, ALT_B)
-
-#define GPIO139_GPIO           PIN_CFG(139, GPIO)
-#define GPIO139_SSP1_RXD       PIN_CFG(139, ALT_A)
-#define GPIO139_SM_WAIT1n      PIN_CFG(139, ALT_B)
-#define GPIO139_KP_O8          PIN_CFG(139, ALT_C)
-
-#define GPIO140_GPIO           PIN_CFG(140, GPIO)
-#define GPIO140_SSP1_TXD       PIN_CFG(140, ALT_A)
-#define GPIO140_IP_GPIO7       PIN_CFG(140, ALT_B)
-#define GPIO140_KP_SKA1                PIN_CFG(140, ALT_C)
-
-#define GPIO141_GPIO           PIN_CFG(141, GPIO)
-#define GPIO141_SSP1_CLK       PIN_CFG(141, ALT_A)
-#define GPIO141_IP_GPIO2       PIN_CFG(141, ALT_B)
-#define GPIO141_KP_O9          PIN_CFG(141, ALT_C)
-
-#define GPIO142_GPIO           PIN_CFG(142, GPIO)
-#define GPIO142_SSP1_FRM       PIN_CFG(142, ALT_A)
-#define GPIO142_IP_GPIO3       PIN_CFG(142, ALT_B)
-#define GPIO142_KP_SKB1                PIN_CFG(142, ALT_C)
-
-#define GPIO143_GPIO           PIN_CFG(143, GPIO)
-#define GPIO143_SSP0_CLK       PIN_CFG(143, ALT_A)
-
-#define GPIO144_GPIO           PIN_CFG(144, GPIO)
-#define GPIO144_SSP0_FRM       PIN_CFG(144, ALT_A)
-
-#define GPIO145_GPIO           PIN_CFG(145, GPIO)
-#define GPIO145_SSP0_RXD       PIN_CFG(145, ALT_A)
-
-#define GPIO146_GPIO           PIN_CFG(146, GPIO)
-#define GPIO146_SSP0_TXD       PIN_CFG(146, ALT_A)
-
-#define GPIO147_GPIO           PIN_CFG(147, GPIO)
-#define GPIO147_I2C0_SCL       PIN_CFG(147, ALT_A)
-
-#define GPIO148_GPIO           PIN_CFG(148, GPIO)
-#define GPIO148_I2C0_SDA       PIN_CFG(148, ALT_A)
-
-#define GPIO149_GPIO           PIN_CFG(149, GPIO)
-#define GPIO149_IP_GPIO0       PIN_CFG(149, ALT_A)
-#define GPIO149_SM_CS1n                PIN_CFG(149, ALT_B)
-#define GPIO149_SM_PS1n                PIN_CFG(149, ALT_C)
-
-#define GPIO150_GPIO           PIN_CFG(150, GPIO)
-#define GPIO150_IP_GPIO1       PIN_CFG(150, ALT_A)
-#define GPIO150_LCDA_CLK       PIN_CFG(150, ALT_B)
-
-#define GPIO151_GPIO           PIN_CFG(151, GPIO)
-#define GPIO151_KP_SKA0                PIN_CFG(151, ALT_A)
-#define GPIO151_LCD_VSI0       PIN_CFG(151, ALT_B)
-#define GPIO151_KP_O8          PIN_CFG(151, ALT_C)
-
-#define GPIO152_GPIO           PIN_CFG(152, GPIO)
-#define GPIO152_KP_SKB0                PIN_CFG(152, ALT_A)
-#define GPIO152_LCD_VSI1       PIN_CFG(152, ALT_B)
-#define GPIO152_KP_O9          PIN_CFG(152, ALT_C)
-
-#define GPIO153_GPIO           PIN_CFG(153, GPIO)
-#define GPIO153_KP_I7          PIN_CFG(153, ALT_A)
-#define GPIO153_LCD_D24                PIN_CFG(153, ALT_B)
-#define GPIO153_U2_RXD         PIN_CFG(153, ALT_C)
-
-#define GPIO154_GPIO           PIN_CFG(154, GPIO)
-#define GPIO154_KP_I6          PIN_CFG(154, ALT_A)
-#define GPIO154_LCD_D25                PIN_CFG(154, ALT_B)
-#define GPIO154_U2_TXD         PIN_CFG(154, ALT_C)
-
-#define GPIO155_GPIO           PIN_CFG(155, GPIO)
-#define GPIO155_KP_I5          PIN_CFG(155, ALT_A)
-#define GPIO155_LCD_D26                PIN_CFG(155, ALT_B)
-#define GPIO155_STMAPE_CLK     PIN_CFG(155, ALT_C)
-
-#define GPIO156_GPIO           PIN_CFG(156, GPIO)
-#define GPIO156_KP_I4          PIN_CFG(156, ALT_A)
-#define GPIO156_LCD_D27                PIN_CFG(156, ALT_B)
-#define GPIO156_STMAPE_DAT3    PIN_CFG(156, ALT_C)
-
-#define GPIO157_GPIO           PIN_CFG(157, GPIO)
-#define GPIO157_KP_O7          PIN_CFG(157, ALT_A)
-#define GPIO157_LCD_D28                PIN_CFG(157, ALT_B)
-#define GPIO157_STMAPE_DAT2    PIN_CFG(157, ALT_C)
-
-#define GPIO158_GPIO           PIN_CFG(158, GPIO)
-#define GPIO158_KP_O6          PIN_CFG(158, ALT_A)
-#define GPIO158_LCD_D29                PIN_CFG(158, ALT_B)
-#define GPIO158_STMAPE_DAT1    PIN_CFG(158, ALT_C)
-
-#define GPIO159_GPIO           PIN_CFG(159, GPIO)
-#define GPIO159_KP_O5          PIN_CFG(159, ALT_A)
-#define GPIO159_LCD_D30                PIN_CFG(159, ALT_B)
-#define GPIO159_STMAPE_DAT0    PIN_CFG(159, ALT_C)
-
-#define GPIO160_GPIO           PIN_CFG(160, GPIO)
-#define GPIO160_KP_O4          PIN_CFG(160, ALT_A)
-#define GPIO160_LCD_D31                PIN_CFG(160, ALT_B)
-#define GPIO160_NONE           PIN_CFG(160, ALT_C)
-
-#define GPIO161_GPIO           PIN_CFG(161, GPIO)
-#define GPIO161_KP_I3          PIN_CFG(161, ALT_A)
-#define GPIO161_LCD_D32                PIN_CFG(161, ALT_B)
-#define GPIO161_UARTMOD_RXD    PIN_CFG(161, ALT_C)
-
-#define GPIO162_GPIO           PIN_CFG(162, GPIO)
-#define GPIO162_KP_I2          PIN_CFG(162, ALT_A)
-#define GPIO162_LCD_D33                PIN_CFG(162, ALT_B)
-#define GPIO162_UARTMOD_TXD    PIN_CFG(162, ALT_C)
-
-#define GPIO163_GPIO           PIN_CFG(163, GPIO)
-#define GPIO163_KP_I1          PIN_CFG(163, ALT_A)
-#define GPIO163_LCD_D34                PIN_CFG(163, ALT_B)
-#define GPIO163_STMMOD_CLK     PIN_CFG(163, ALT_C)
-
-#define GPIO164_GPIO           PIN_CFG(164, GPIO)
-#define GPIO164_KP_I0          PIN_CFG(164, ALT_A)
-#define GPIO164_LCD_D35                PIN_CFG(164, ALT_B)
-#define GPIO164_STMMOD_DAT3    PIN_CFG(164, ALT_C)
-
-#define GPIO165_GPIO           PIN_CFG(165, GPIO)
-#define GPIO165_KP_O3          PIN_CFG(165, ALT_A)
-#define GPIO165_LCD_D36                PIN_CFG(165, ALT_B)
-#define GPIO165_STMMOD_DAT2    PIN_CFG(165, ALT_C)
-
-#define GPIO166_GPIO           PIN_CFG(166, GPIO)
-#define GPIO166_KP_O2          PIN_CFG(166, ALT_A)
-#define GPIO166_LCD_D37                PIN_CFG(166, ALT_B)
-#define GPIO166_STMMOD_DAT1    PIN_CFG(166, ALT_C)
-
-#define GPIO167_GPIO           PIN_CFG(167, GPIO)
-#define GPIO167_KP_O1          PIN_CFG(167, ALT_A)
-#define GPIO167_LCD_D38                PIN_CFG(167, ALT_B)
-#define GPIO167_STMMOD_DAT0    PIN_CFG(167, ALT_C)
-
-#define GPIO168_GPIO           PIN_CFG(168, GPIO)
-#define GPIO168_KP_O0          PIN_CFG(168, ALT_A)
-#define GPIO168_LCD_D39                PIN_CFG(168, ALT_B)
-#define GPIO168_NONE           PIN_CFG(168, ALT_C)
-
-#define GPIO169_GPIO           PIN_CFG(169, GPIO)
-#define GPIO169_RF_PURn                PIN_CFG(169, ALT_A)
-#define GPIO169_LCDA_DE                PIN_CFG(169, ALT_B)
-#define GPIO169_USBSIM_PDC     PIN_CFG(169, ALT_C)
-
-#define GPIO170_GPIO           PIN_CFG(170, GPIO)
-#define GPIO170_MODEM_STATE    PIN_CFG(170, ALT_A)
-#define GPIO170_LCDA_VSO       PIN_CFG(170, ALT_B)
-#define GPIO170_KP_SKA1                PIN_CFG(170, ALT_C)
-
-#define GPIO171_GPIO           PIN_CFG(171, GPIO)
-#define GPIO171_MODEM_PWREN    PIN_CFG(171, ALT_A)
-#define GPIO171_LCDA_HSO       PIN_CFG(171, ALT_B)
-#define GPIO171_KP_SKB1                PIN_CFG(171, ALT_C)
-
-#define GPIO192_GPIO           PIN_CFG(192, GPIO)
-#define GPIO192_MSP2_SCK       PIN_CFG(192, ALT_A)
-
-#define GPIO193_GPIO           PIN_CFG(193, GPIO)
-#define GPIO193_MSP2_TXD       PIN_CFG(193, ALT_A)
-
-#define GPIO194_GPIO           PIN_CFG(194, GPIO)
-#define GPIO194_MSP2_TCK       PIN_CFG(194, ALT_A)
-
-#define GPIO195_GPIO           PIN_CFG(195, GPIO)
-#define GPIO195_MSP2_TFS       PIN_CFG(195, ALT_A)
-
-#define GPIO196_GPIO           PIN_CFG(196, GPIO)
-#define GPIO196_MSP2_RXD       PIN_CFG(196, ALT_A)
-
-#define GPIO197_GPIO           PIN_CFG(197, GPIO)
-#define GPIO197_MC4_DAT3       PIN_CFG_INPUT(197, ALT_A, PULLUP)
-
-#define GPIO198_GPIO           PIN_CFG(198, GPIO)
-#define GPIO198_MC4_DAT2       PIN_CFG_INPUT(198, ALT_A, PULLUP)
-
-#define GPIO199_GPIO           PIN_CFG(199, GPIO)
-#define GPIO199_MC4_DAT1       PIN_CFG_INPUT(199, ALT_A, PULLUP)
-
-#define GPIO200_GPIO           PIN_CFG(200, GPIO)
-#define GPIO200_MC4_DAT0       PIN_CFG_INPUT(200, ALT_A, PULLUP)
-
-#define GPIO201_GPIO           PIN_CFG(201, GPIO)
-#define GPIO201_MC4_CMD                PIN_CFG_INPUT(201, ALT_A, PULLUP)
-
-#define GPIO202_GPIO           PIN_CFG(202, GPIO)
-#define GPIO202_MC4_FBCLK      PIN_CFG_INPUT(202, ALT_A, PULLUP)
-#define GPIO202_PWL            PIN_CFG(202, ALT_B)
-#define GPIO202_MC4_RSTN       PIN_CFG(202, ALT_C)
-
-#define GPIO203_GPIO           PIN_CFG(203, GPIO)
-#define GPIO203_MC4_CLK                PIN_CFG_INPUT(203, ALT_A, PULLUP)
-
-#define GPIO204_GPIO           PIN_CFG(204, GPIO)
-#define GPIO204_MC4_DAT7       PIN_CFG_INPUT(204, ALT_A, PULLUP)
-
-#define GPIO205_GPIO           PIN_CFG(205, GPIO)
-#define GPIO205_MC4_DAT6       PIN_CFG_INPUT(205, ALT_A, PULLUP)
-
-#define GPIO206_GPIO           PIN_CFG(206, GPIO)
-#define GPIO206_MC4_DAT5       PIN_CFG_INPUT(206, ALT_A, PULLUP)
-
-#define GPIO207_GPIO           PIN_CFG(207, GPIO)
-#define GPIO207_MC4_DAT4       PIN_CFG_INPUT(207, ALT_A, PULLUP)
-
-#define GPIO208_GPIO           PIN_CFG(208, GPIO)
-#define GPIO208_MC1_CLK                PIN_CFG(208, ALT_A)
-
-#define GPIO209_GPIO           PIN_CFG(209, GPIO)
-#define GPIO209_MC1_FBCLK      PIN_CFG(209, ALT_A)
-#define GPIO209_SPI1_CLK       PIN_CFG(209, ALT_B)
-
-#define GPIO210_GPIO           PIN_CFG(210, GPIO)
-#define GPIO210_MC1_CMD                PIN_CFG(210, ALT_A)
-
-#define GPIO211_GPIO           PIN_CFG(211, GPIO)
-#define GPIO211_MC1_DAT0       PIN_CFG(211, ALT_A)
-
-#define GPIO212_GPIO           PIN_CFG(212, GPIO)
-#define GPIO212_MC1_DAT1       PIN_CFG(212, ALT_A)
-#define GPIO212_SPI1_FRM       PIN_CFG(212, ALT_B)
-
-#define GPIO213_GPIO           PIN_CFG(213, GPIO)
-#define GPIO213_MC1_DAT2       PIN_CFG(213, ALT_A)
-#define GPIO213_SPI1_TXD       PIN_CFG(213, ALT_B)
-
-#define GPIO214_GPIO           PIN_CFG(214, GPIO)
-#define GPIO214_MC1_DAT3       PIN_CFG(214, ALT_A)
-#define GPIO214_SPI1_RXD       PIN_CFG(214, ALT_B)
-
-#define GPIO215_GPIO           PIN_CFG(215, GPIO)
-#define GPIO215_MC1_CMDDIR     PIN_CFG(215, ALT_A)
-#define GPIO215_MC3_DAT2DIR    PIN_CFG(215, ALT_B)
-#define GPIO215_CLKOUT1                PIN_CFG(215, ALT_C)
-#define GPIO215_SPI2_TXD       PIN_CFG(215, ALT_C)
-
-#define GPIO216_GPIO           PIN_CFG(216, GPIO)
-#define GPIO216_MC1_DAT2DIR    PIN_CFG(216, ALT_A)
-#define GPIO216_MC3_CMDDIR     PIN_CFG(216, ALT_B)
-#define GPIO216_I2C3_SDA       PIN_CFG(216, ALT_C)
-#define GPIO216_SPI2_FRM       PIN_CFG(216, ALT_C)
-
-#define GPIO217_GPIO           PIN_CFG(217, GPIO)
-#define GPIO217_MC1_DAT0DIR    PIN_CFG(217, ALT_A)
-#define GPIO217_MC3_DAT31DIR   PIN_CFG(217, ALT_B)
-#define GPIO217_CLKOUT2                PIN_CFG(217, ALT_C)
-#define GPIO217_SPI2_CLK       PIN_CFG(217, ALT_C)
-
-#define GPIO218_GPIO           PIN_CFG(218, GPIO)
-#define GPIO218_MC1_DAT31DIR   PIN_CFG(218, ALT_A)
-#define GPIO218_MC3_DAT0DIR    PIN_CFG(218, ALT_B)
-#define GPIO218_I2C3_SCL       PIN_CFG(218, ALT_C)
-#define GPIO218_SPI2_RXD       PIN_CFG(218, ALT_C)
-
-#define GPIO219_GPIO           PIN_CFG(219, GPIO)
-#define GPIO219_HSIR_FLA0      PIN_CFG(219, ALT_A)
-#define GPIO219_MC3_CLK                PIN_CFG(219, ALT_B)
-
-#define GPIO220_GPIO           PIN_CFG(220, GPIO)
-#define GPIO220_HSIR_DAT0      PIN_CFG(220, ALT_A)
-#define GPIO220_MC3_FBCLK      PIN_CFG(220, ALT_B)
-#define GPIO220_SPI0_CLK       PIN_CFG(220, ALT_C)
-
-#define GPIO221_GPIO           PIN_CFG(221, GPIO)
-#define GPIO221_HSIR_RDY0      PIN_CFG(221, ALT_A)
-#define GPIO221_MC3_CMD                PIN_CFG(221, ALT_B)
-
-#define GPIO222_GPIO           PIN_CFG(222, GPIO)
-#define GPIO222_HSIT_FLA0      PIN_CFG(222, ALT_A)
-#define GPIO222_MC3_DAT0       PIN_CFG(222, ALT_B)
-
-#define GPIO223_GPIO           PIN_CFG(223, GPIO)
-#define GPIO223_HSIT_DAT0      PIN_CFG(223, ALT_A)
-#define GPIO223_MC3_DAT1       PIN_CFG(223, ALT_B)
-#define GPIO223_SPI0_FRM       PIN_CFG(223, ALT_C)
-
-#define GPIO224_GPIO           PIN_CFG(224, GPIO)
-#define GPIO224_HSIT_RDY0      PIN_CFG(224, ALT_A)
-#define GPIO224_MC3_DAT2       PIN_CFG(224, ALT_B)
-#define GPIO224_SPI0_TXD       PIN_CFG(224, ALT_C)
-
-#define GPIO225_GPIO           PIN_CFG(225, GPIO)
-#define GPIO225_HSIT_CAWAKE0   PIN_CFG(225, ALT_A)
-#define GPIO225_MC3_DAT3       PIN_CFG(225, ALT_B)
-#define GPIO225_SPI0_RXD       PIN_CFG(225, ALT_C)
-
-#define GPIO226_GPIO           PIN_CFG(226, GPIO)
-#define GPIO226_HSIT_ACWAKE0   PIN_CFG(226, ALT_A)
-#define GPIO226_PWL            PIN_CFG(226, ALT_B)
-#define GPIO226_USBSIM_PDC     PIN_CFG(226, ALT_C)
-
-#define GPIO227_GPIO           PIN_CFG(227, GPIO)
-#define GPIO227_CLKOUT1                PIN_CFG(227, ALT_A)
-
-#define GPIO228_GPIO           PIN_CFG(228, GPIO)
-#define GPIO228_CLKOUT2                PIN_CFG(228, ALT_A)
-
-#define GPIO229_GPIO           PIN_CFG(229, GPIO)
-#define GPIO229_CLKOUT1                PIN_CFG(229, ALT_A)
-#define GPIO229_PWL            PIN_CFG(229, ALT_B)
-#define GPIO229_I2C3_SDA       PIN_CFG(229, ALT_C)
-
-#define GPIO230_GPIO           PIN_CFG(230, GPIO)
-#define GPIO230_CLKOUT2                PIN_CFG(230, ALT_A)
-#define GPIO230_PWL            PIN_CFG(230, ALT_B)
-#define GPIO230_I2C3_SCL       PIN_CFG(230, ALT_C)
-
-#define GPIO256_GPIO           PIN_CFG(256, GPIO)
-#define GPIO256_USB_NXT                PIN_CFG(256, ALT_A)
-
-#define GPIO257_GPIO           PIN_CFG(257, GPIO)
-#define GPIO257_USB_STP                PIN_CFG(257, ALT_A)
-
-#define GPIO258_GPIO           PIN_CFG(258, GPIO)
-#define GPIO258_USB_XCLK       PIN_CFG(258, ALT_A)
-#define GPIO258_NONE           PIN_CFG(258, ALT_B)
-#define GPIO258_DDR_TRIG       PIN_CFG(258, ALT_C)
-
-#define GPIO259_GPIO           PIN_CFG(259, GPIO)
-#define GPIO259_USB_DIR                PIN_CFG(259, ALT_A)
-
-#define GPIO260_GPIO           PIN_CFG(260, GPIO)
-#define GPIO260_USB_DAT7       PIN_CFG(260, ALT_A)
-
-#define GPIO261_GPIO           PIN_CFG(261, GPIO)
-#define GPIO261_USB_DAT6       PIN_CFG(261, ALT_A)
-
-#define GPIO262_GPIO           PIN_CFG(262, GPIO)
-#define GPIO262_USB_DAT5       PIN_CFG(262, ALT_A)
-
-#define GPIO263_GPIO           PIN_CFG(263, GPIO)
-#define GPIO263_USB_DAT4       PIN_CFG(263, ALT_A)
-
-#define GPIO264_GPIO           PIN_CFG(264, GPIO)
-#define GPIO264_USB_DAT3       PIN_CFG(264, ALT_A)
-
-#define GPIO265_GPIO           PIN_CFG(265, GPIO)
-#define GPIO265_USB_DAT2       PIN_CFG(265, ALT_A)
-
-#define GPIO266_GPIO           PIN_CFG(266, GPIO)
-#define GPIO266_USB_DAT1       PIN_CFG(266, ALT_A)
-
-#define GPIO267_GPIO           PIN_CFG(267, GPIO)
-#define GPIO267_USB_DAT0       PIN_CFG(267, ALT_A)
-
-#endif
index ec087407b163a4a5a22144c4a5a92ebaed570335..6f938ccb0c546fbc24c4ec19c656799811d84106 100644 (file)
 /* PCI space */
 #define VERSATILE_PCI_BASE             0x41000000      /* PCI Interface */
 #define VERSATILE_PCI_CFG_BASE        0x42000000
+#define VERSATILE_PCI_IO_BASE          0x43000000
 #define VERSATILE_PCI_MEM_BASE0        0x44000000
 #define VERSATILE_PCI_MEM_BASE1        0x50000000
 #define VERSATILE_PCI_MEM_BASE2        0x60000000
 /* Sizes of above maps */
 #define VERSATILE_PCI_BASE_SIZE               0x01000000
 #define VERSATILE_PCI_CFG_BASE_SIZE    0x02000000
+#define VERSATILE_PCI_IO_BASE_SIZE     0x01000000
 #define VERSATILE_PCI_MEM_BASE0_SIZE   0x0c000000      /* 32Mb */
 #define VERSATILE_PCI_MEM_BASE1_SIZE   0x10000000      /* 256Mb */
 #define VERSATILE_PCI_MEM_BASE2_SIZE   0x10000000      /* 256Mb */
index e92e5e0705bc945321779c6b6023e57adf9ff582..c97be4ea76d216d4dbbeb856ed200fbb0cd9e458 100644 (file)
@@ -43,9 +43,9 @@
 #define PCI_IMAP0              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
 #define PCI_IMAP1              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
 #define PCI_IMAP2              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
-#define PCI_SMAP0              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
-#define PCI_SMAP1              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
-#define PCI_SMAP2              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
+#define PCI_SMAP0              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
+#define PCI_SMAP1              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
+#define PCI_SMAP2              __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x1c)
 #define PCI_SELFID             __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
 
 #define DEVICE_ID_OFFSET               0x00
@@ -170,8 +170,8 @@ static struct pci_ops pci_versatile_ops = {
        .write  = versatile_write_config,
 };
 
-static struct resource io_mem = {
-       .name   = "PCI I/O space",
+static struct resource unused_mem = {
+       .name   = "PCI unused",
        .start  = VERSATILE_PCI_MEM_BASE0,
        .end    = VERSATILE_PCI_MEM_BASE0+VERSATILE_PCI_MEM_BASE0_SIZE-1,
        .flags  = IORESOURCE_MEM,
@@ -195,9 +195,9 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
 {
        int ret = 0;
 
-       ret = request_resource(&iomem_resource, &io_mem);
+       ret = request_resource(&iomem_resource, &unused_mem);
        if (ret) {
-               printk(KERN_ERR "PCI: unable to allocate I/O "
+               printk(KERN_ERR "PCI: unable to allocate unused "
                       "memory region (%d)\n", ret);
                goto out;
        }
@@ -205,7 +205,7 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
        if (ret) {
                printk(KERN_ERR "PCI: unable to allocate non-prefetchable "
                       "memory region (%d)\n", ret);
-               goto release_io_mem;
+               goto release_unused_mem;
        }
        ret = request_resource(&iomem_resource, &pre_mem);
        if (ret) {
@@ -225,8 +225,8 @@ static int __init pci_versatile_setup_resources(struct pci_sys_data *sys)
 
  release_non_mem:
        release_resource(&non_mem);
- release_io_mem:
-       release_resource(&io_mem);
+ release_unused_mem:
+       release_resource(&unused_mem);
  out:
        return ret;
 }
@@ -246,7 +246,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
                goto out;
        }
 
-       ret = pci_ioremap_io(0, VERSATILE_PCI_MEM_BASE0);
+       ret = pci_ioremap_io(0, VERSATILE_PCI_IO_BASE);
        if (ret)
                goto out;
 
@@ -294,6 +294,19 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
        __raw_writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
 
+       /*
+        * For many years the kernel and QEMU were symbiotically buggy
+        * in that they both assumed the same broken IRQ mapping.
+        * QEMU therefore attempts to auto-detect old broken kernels
+        * so that they still work on newer QEMU as they did on old
+        * QEMU. Since we now use the correct (ie matching-hardware)
+        * IRQ mapping we write a definitely different value to a
+        * PCI_INTERRUPT_LINE register to tell QEMU that we expect
+        * real hardware behaviour and it need not be backwards
+        * compatible for us. This write is harmless on real hardware.
+        */
+       __raw_writel(0, VERSATILE_PCI_VIRT_BASE+PCI_INTERRUPT_LINE);
+
        /*
         * Do not to map Versatile FPGA PCI device into memory space
         */
@@ -327,13 +340,13 @@ static int __init versatile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        int irq;
 
-       /* slot,  pin,  irq
-        *  24     1     IRQ_SIC_PCI0
-        *  25     1     IRQ_SIC_PCI1
-        *  26     1     IRQ_SIC_PCI2
-        *  27     1     IRQ_SIC_PCI3
+       /*
+        * Slot INTA    INTB    INTC    INTD
+        * 31   PCI1    PCI2    PCI3    PCI0
+        * 30   PCI0    PCI1    PCI2    PCI3
+        * 29   PCI3    PCI0    PCI1    PCI2
         */
-       irq = IRQ_SIC_PCI0 + ((slot - 24 + pin - 1) & 3);
+       irq = IRQ_SIC_PCI0 + ((slot + 2 + pin - 1) & 3);
 
        return irq;
 }
index 36ea8247123a6188fdc20c7953d77eb0fc2397d8..505e64ab3eae68f471d0d494f619f7360c67b5c2 100644 (file)
@@ -7,6 +7,8 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 obj-y                                  := v2m.o
 obj-$(CONFIG_ARCH_VEXPRESS_CA9X4)      += ct-ca9x4.o
 obj-$(CONFIG_ARCH_VEXPRESS_DCSCB)      += dcscb.o      dcscb_setup.o
+CFLAGS_dcscb.o                         += -march=armv7-a
 obj-$(CONFIG_ARCH_VEXPRESS_TC2_PM)     += tc2_pm.o spc.o
+CFLAGS_tc2_pm.o                                += -march=armv7-a
 obj-$(CONFIG_SMP)                      += platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)              += hotplug.o
index 2b7c93a724ede88c7f755f5fcd4750ad77e0e8ad..7aeb5d60e484642d08ed119ecfd083b3c4074a46 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/of_address.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
+#include <linux/irqchip/arm-gic.h>
 
 #include <asm/mcpm.h>
 #include <asm/proc-fns.h>
@@ -230,6 +231,7 @@ static void tc2_pm_suspend(u64 residency)
        cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
        cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
        ve_spc_set_resume_addr(cluster, cpu, virt_to_phys(mcpm_entry_point));
+       gic_cpu_if_down();
        tc2_pm_down(residency);
 }
 
index c97f7940cb9553d52ba3b6c711f2dab430aea110..eb8830a4c5edeb8c1be7b9fa396cc100f020af42 100644 (file)
@@ -261,9 +261,7 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        struct task_struct *tsk;
        struct mm_struct *mm;
        int fault, sig, code;
-       int write = fsr & FSR_WRITE;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                               (write ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        if (notify_page_fault(regs, fsr))
                return 0;
@@ -282,6 +280,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+       if (fsr & FSR_WRITE)
+               flags |= FAULT_FLAG_WRITE;
+
        /*
         * As per x86, we may deadlock here.  However, since the kernel only
         * validly references user space from well defined areas of the code,
@@ -349,6 +352,13 @@ retry:
        if (likely(!(fault & (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
                return 0;
 
+       /*
+        * If we are in kernel mode at this point, we
+        * have no context to handle this fault with.
+        */
+       if (!user_mode(regs))
+               goto no_context;
+
        if (fault & VM_FAULT_OOM) {
                /*
                 * We ran out of memory, call the OOM killer, and return to
@@ -359,13 +369,6 @@ retry:
                return 0;
        }
 
-       /*
-        * If we are in kernel mode at this point, we
-        * have no context to handle this fault with.
-        */
-       if (!user_mode(regs))
-               goto no_context;
-
        if (fault & VM_FAULT_SIGBUS) {
                /*
                 * We had some memory, but were unable to
index 66781bf34077cb540a67f845eeeb919c2decfc4e..54ee6163c1814453298272fdb182341e3a5ffcdf 100644 (file)
@@ -56,3 +56,8 @@ int pmd_huge(pmd_t pmd)
 {
        return pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT);
 }
+
+int pmd_huge_support(void)
+{
+       return 1;
+}
index 2958e74fc42c8f45444fca0a48f5f38856f32a73..febaee7ca57be76487290a2ac45c6cf74e53759c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/nodemask.h>
 #include <linux/initrd.h>
 #include <linux/of_fdt.h>
+#include <linux/of_reserved_mem.h>
 #include <linux/highmem.h>
 #include <linux/gfp.h>
 #include <linux/memblock.h>
@@ -77,7 +78,7 @@ static int __init parse_tag_initrd2(const struct tag *tag)
 __tagtable(ATAG_INITRD2, parse_tag_initrd2);
 
 #ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start, unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        phys_initrd_start = start;
        phys_initrd_size = end - start;
@@ -207,7 +208,7 @@ static void __init arm_bootmem_init(unsigned long start_pfn,
 
 #ifdef CONFIG_ZONE_DMA
 
-unsigned long arm_dma_zone_size __read_mostly;
+phys_addr_t arm_dma_zone_size __read_mostly;
 EXPORT_SYMBOL(arm_dma_zone_size);
 
 /*
@@ -378,6 +379,8 @@ void __init arm_memblock_init(struct meminfo *mi,
        if (mdesc->reserve)
                mdesc->reserve();
 
+       early_init_dt_scan_reserved_mem();
+
        /*
         * reserve memory for DMA contigouos allocations,
         * must come from DMA area inside low memory
index c83f27b6bdda0eac2c566d40b4d99e5428be650b..3ea02903d75af6a86cfda0abbc7d7532139f3e9e 100644 (file)
@@ -132,6 +132,7 @@ static int pxa_ssp_probe(struct platform_device *pdev)
        if (dev->of_node) {
                struct of_phandle_args dma_spec;
                struct device_node *np = dev->of_node;
+               int ret;
 
                /*
                 * FIXME: we should allocate the DMA channel from this
@@ -140,14 +141,23 @@ static int pxa_ssp_probe(struct platform_device *pdev)
                 */
 
                /* rx */
-               of_parse_phandle_with_args(np, "dmas", "#dma-cells",
-                                          0, &dma_spec);
+               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+                                                0, &dma_spec);
+
+               if (ret) {
+                       dev_err(dev, "Can't parse dmas property\n");
+                       return -ENODEV;
+               }
                ssp->drcmr_rx = dma_spec.args[0];
                of_node_put(dma_spec.np);
 
                /* tx */
-               of_parse_phandle_with_args(np, "dmas", "#dma-cells",
-                                          1, &dma_spec);
+               ret = of_parse_phandle_with_args(np, "dmas", "#dma-cells",
+                                                1, &dma_spec);
+               if (ret) {
+                       dev_err(dev, "Can't parse dmas property\n");
+                       return -ENODEV;
+               }
                ssp->drcmr_tx = dma_spec.args[0];
                of_node_put(dma_spec.np);
        } else {
index 8a6295c86209cd982076a8f79662bd20c2c0f02b..83e4f959ee47c6b9b18a77d9f50995b7b4fc5ab0 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/of.h>
 #include <linux/of_irq.h>
 #include <linux/of_address.h>
+#include <linux/cpuidle.h>
+#include <linux/cpufreq.h>
 
 #include <linux/mm.h>
 
@@ -267,18 +269,28 @@ static int __init xen_guest_init(void)
        if (!xen_initial_domain())
                xenbus_probe(NULL);
 
+       /*
+        * Making sure board specific code will not set up ops for
+        * cpu idle and cpu freq.
+        */
+       disable_cpuidle();
+       disable_cpufreq();
+
        return 0;
 }
 core_initcall(xen_guest_init);
 
 static int __init xen_pm_init(void)
 {
+       if (!xen_domain())
+               return -ENODEV;
+
        pm_power_off = xen_power_off;
        arm_pm_restart = xen_restart;
 
        return 0;
 }
-subsys_initcall(xen_pm_init);
+late_initcall(xen_pm_init);
 
 static irqreturn_t xen_arm_callback(int irq, void *arg)
 {
index ae323a45c28c2dac8c18a71c2c1f7a526132536e..c04454876bcbe6520a52ada910a7d193ff884e85 100644 (file)
@@ -23,7 +23,6 @@ config ARM64
        select HAVE_DMA_API_DEBUG
        select HAVE_DMA_ATTRS
        select HAVE_GENERIC_DMA_COHERENT
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_HW_BREAKPOINT if PERF_EVENTS
        select HAVE_MEMBLOCK
        select HAVE_PERF_EVENTS
index bca4c1c2052ad87af9d883bef4a4e70b2524a128..12ad8f3d0cfd32c4f5409a0b8f29b499b7f5cf80 100644 (file)
@@ -190,11 +190,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        memblock_add(base, size);
 }
 
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-{
-       return __va(memblock_alloc(size, align));
-}
-
 /*
  * Limit the memory size that was specified via FDT.
  */
index 6c8ba25bf6bb39eed908ea23edb05c9bb605fed2..6d6acf153bffb276b5fa9affd87e48a1cb17a318 100644 (file)
@@ -199,13 +199,6 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        unsigned long vm_flags = VM_READ | VM_WRITE | VM_EXEC;
        unsigned int mm_flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
-       if (esr & ESR_LNX_EXEC) {
-               vm_flags = VM_EXEC;
-       } else if ((esr & ESR_WRITE) && !(esr & ESR_CM)) {
-               vm_flags = VM_WRITE;
-               mm_flags |= FAULT_FLAG_WRITE;
-       }
-
        tsk = current;
        mm  = tsk->mm;
 
@@ -220,6 +213,16 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               mm_flags |= FAULT_FLAG_USER;
+
+       if (esr & ESR_LNX_EXEC) {
+               vm_flags = VM_EXEC;
+       } else if ((esr & ESR_WRITE) && !(esr & ESR_CM)) {
+               vm_flags = VM_WRITE;
+               mm_flags |= FAULT_FLAG_WRITE;
+       }
+
        /*
         * As per x86, we may deadlock here. However, since the kernel only
         * validly references user space from well defined areas of the code,
@@ -288,6 +291,13 @@ retry:
                              VM_FAULT_BADACCESS))))
                return 0;
 
+       /*
+        * If we are in kernel mode at this point, we have no context to
+        * handle this fault with.
+        */
+       if (!user_mode(regs))
+               goto no_context;
+
        if (fault & VM_FAULT_OOM) {
                /*
                 * We ran out of memory, call the OOM killer, and return to
@@ -298,13 +308,6 @@ retry:
                return 0;
        }
 
-       /*
-        * If we are in kernel mode at this point, we have no context to
-        * handle this fault with.
-        */
-       if (!user_mode(regs))
-               goto no_context;
-
        if (fault & VM_FAULT_SIGBUS) {
                /*
                 * We had some memory, but were unable to successfully fix up
index 2fc8258bab2df614ab51a0bf1ffb4a36a236ba41..5e9aec358306f0c13bdd0bb70758dde88be9e961 100644 (file)
@@ -54,6 +54,11 @@ int pud_huge(pud_t pud)
        return !(pud_val(pud) & PUD_TABLE_BIT);
 }
 
+int pmd_huge_support(void)
+{
+       return 1;
+}
+
 static __init int setup_hugepagesz(char *opt)
 {
        unsigned long ps = memparse(opt, &opt);
index 67e8d7ce3fe7a68ac1c974058de83b8d6226086e..de2de5db628de2382e555b4256b9ad1f0f92ada5 100644 (file)
@@ -44,8 +44,7 @@ static unsigned long phys_initrd_size __initdata = 0;
 
 phys_addr_t memstart_addr __read_mostly = 0;
 
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        phys_initrd_start = start;
        phys_initrd_size = end - start;
index 549903cfc2cbe6f223025ff1b04017939f7dd336..b6878eb6488483d9d7222f69c43e8390c7610fd2 100644 (file)
@@ -6,7 +6,6 @@ config AVR32
        select HAVE_CLK
        select HAVE_OPROFILE
        select HAVE_KPROBES
-       select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_PROBE
        select GENERIC_ATOMIC64
index 7f8759a8a92a08b8ed8e772d9f08c9d3404d8697..a68f3cf7c3c1bda0f3d02dc8d45672a4f3db0793 100644 (file)
@@ -1983,6 +1983,9 @@ at32_add_device_nand(unsigned int id, struct atmel_nand_data *data)
                                ARRAY_SIZE(smc_cs3_resource)))
                goto fail;
 
+       /* For at32ap7000, we use the reset workaround for nand driver */
+       data->need_reset_workaround = true;
+
        if (platform_device_add_data(pdev, data,
                                sizeof(struct atmel_nand_data)))
                goto fail;
index b2f2d2d668491905dbbc37c385449852a9e7fdde..0eca93327195077ec16bdfd99efd7294c6ab2de6 100644 (file)
@@ -86,6 +86,8 @@ asmlinkage void do_page_fault(unsigned long ecr, struct pt_regs *regs)
 
        local_irq_enable();
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
 
@@ -228,9 +230,9 @@ no_context:
         */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       pagefault_out_of_memory();
        if (!user_mode(regs))
                goto no_context;
+       pagefault_out_of_memory();
        return;
 
 do_sigbus:
index 3b6abc54b0150c8f02488d7221a70756baf08682..f78c9a2c7e281f2d441a40719e6735226231ceaa 100644 (file)
@@ -32,7 +32,6 @@ config BLACKFIN
        select HAVE_UNDERSCORE_SYMBOL_PREFIX
        select VIRT_TO_BUS
        select ARCH_WANT_IPC_PARSE_VERSION
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_ATOMIC64
        select GENERIC_IRQ_PROBE
        select USE_GENERIC_SMP_HELPERS if SMP
index 229e5080867770d755f4721911774dddfa40ab05..1287a5487e7d6fb72296f69adcf59a6caba51991 100644 (file)
@@ -1,2 +1,3 @@
 vmImage*
 vmlinux*
+uImage*
diff --git a/arch/blackfin/include/asm/scb.h b/arch/blackfin/include/asm/scb.h
new file mode 100644 (file)
index 0000000..a294cc0
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * arch/blackfin/mach-common/scb-init.c - reprogram system cross bar priority
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#define SCB_SLOT_OFFSET        24
+#define SCB_MI_MAX_SLOT 32
+
+struct scb_mi_prio {
+       unsigned long scb_mi_arbr;
+       unsigned long scb_mi_arbw;
+       unsigned char scb_mi_slots;
+       unsigned char scb_mi_prio[SCB_MI_MAX_SLOT];
+};
+
+extern struct scb_mi_prio scb_data[];
+
+extern void init_scb(void);
index 19ad0637e8ff0e6081b8253c38a41a025da74ba8..3961930421274b9f89e47f691554c6dbad61ecb6 100644 (file)
@@ -35,6 +35,9 @@
 #ifdef CONFIG_BF60x
 #include <mach/pm.h>
 #endif
+#ifdef CONFIG_SCB_PRIORITY
+#include <asm/scb.h>
+#endif
 
 u16 _bfin_swrst;
 EXPORT_SYMBOL(_bfin_swrst);
@@ -1101,6 +1104,9 @@ void __init setup_arch(char **cmdline_p)
 #endif
        init_exception_vectors();
        bfin_cache_init();      /* Initialize caches for the boot CPU */
+#ifdef CONFIG_SCB_PRIORITY
+       init_scb();
+#endif
 }
 
 static int __init topology_init(void)
index 95a4f1b676cead2006dfa3b44280020b4cb248ab..2bcbf94b1edf4cbe9108b108f85bd253bb201d11 100644 (file)
@@ -59,6 +59,1661 @@ config SEC_IRQ_PRIORITY_LEVELS
          Divide the total number of interrupt priority levels into sub-levels.
          There is 2 ^ (SEC_IRQ_PRIORITY_LEVELS + 1) different levels.
 
+
+comment "System Cross Bar Priority Assignment"
+
+config SCB_PRIORITY
+       bool "Init System Cross Bar Priority"
+       default n
+
+menuconfig     SCB0_MI0
+       bool "SCB0 Master Interface 0 (DDR)"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       Core 0  -- 0
+       Core 1  -- 2
+       SCB1    -- 9
+       SCB2    -- 10
+       SCB3    -- 11
+       SCB4    -- 12
+       SCB5    -- 5
+       SCB6    -- 6
+       SCB7    -- 8
+       SCB8    -- 7
+       SCB9    -- 4
+       USB     -- 13
+
+if SCB0_MI0
+
+config SCB0_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 13
+
+config SCB0_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 2
+       range 0 13
+
+config SCB0_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI0_SLOT8
+       int "Slot 8 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI0_SLOT9
+       int "Slot 9 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI0_SLOT10
+       int "Slot 10 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI0_SLOT11
+       int "Slot 11 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI0_SLOT12
+       int "Slot 12 slave interface id"
+       default 0
+       range 0 13
+
+config SCB0_MI0_SLOT13
+       int "Slot 13 slave interface id"
+       default 2
+       range 0 13
+
+config SCB0_MI0_SLOT14
+       int "Slot 14 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI0_SLOT15
+       int "Slot 15 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI0_SLOT16
+       int "Slot 16 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI0_SLOT17
+       int "Slot 17 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI0_SLOT18
+       int "Slot 18 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI0_SLOT19
+       int "Slot 19 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI0_SLOT20
+       int "Slot 20 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI0_SLOT21
+       int "Slot 21 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI0_SLOT22
+       int "Slot 22 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI0_SLOT23
+       int "Slot 23 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI0_SLOT24
+       int "Slot 24 slave interface id"
+       default 0
+       range 0 13
+
+config SCB0_MI0_SLOT25
+       int "Slot 25 slave interface id"
+       default 2
+       range 0 13
+
+config SCB0_MI0_SLOT26
+       int "Slot 26 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI0_SLOT27
+       int "Slot 27 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI0_SLOT28
+       int "Slot 28 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI0_SLOT29
+       int "Slot 29 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI0_SLOT30
+       int "Slot 30 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI0_SLOT31
+       int "Slot 31 slave interface id"
+       default 13
+       range 0 13
+
+endif # SCB0_MI0
+
+menuconfig     SCB0_MI1
+       bool "SCB0 Master Interface 1 (SMC)"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       Core 0  -- 0
+       Core 1  -- 2
+       SCB1    -- 9
+       SCB2    -- 10
+       SCB3    -- 11
+       SCB4    -- 12
+       SCB5    -- 5
+       SCB6    -- 6
+       SCB7    -- 8
+       SCB8    -- 7
+       SCB9    -- 4
+       USB     -- 13
+
+if SCB0_MI1
+
+config SCB0_MI1_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 13
+
+config SCB0_MI1_SLOT1
+       int "Slot 1 slave interface id"
+       default 2
+       range 0 13
+
+config SCB0_MI1_SLOT2
+       int "Slot 2 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI1_SLOT3
+       int "Slot 3 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI1_SLOT4
+       int "Slot 4 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI1_SLOT5
+       int "Slot 5 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI1_SLOT6
+       int "Slot 6 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI1_SLOT7
+       int "Slot 7 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI1_SLOT8
+       int "Slot 8 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI1_SLOT9
+       int "Slot 9 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI1_SLOT10
+       int "Slot 10 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI1_SLOT11
+       int "Slot 11 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI1_SLOT12
+       int "Slot 12 slave interface id"
+       default 0
+       range 0 13
+
+config SCB0_MI1_SLOT13
+       int "Slot 13 slave interface id"
+       default 2
+       range 0 13
+
+config SCB0_MI1_SLOT14
+       int "Slot 14 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI1_SLOT15
+       int "Slot 15 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI1_SLOT16
+       int "Slot 16 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI1_SLOT17
+       int "Slot 17 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI1_SLOT18
+       int "Slot 18 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI1_SLOT19
+       int "Slot 19 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI1_SLOT20
+       int "Slot 20 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI1_SLOT21
+       int "Slot 21 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI1_SLOT22
+       int "Slot 22 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI1_SLOT23
+       int "Slot 23 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI1_SLOT24
+       int "Slot 24 slave interface id"
+       default 0
+       range 0 13
+
+config SCB0_MI1_SLOT25
+       int "Slot 25 slave interface id"
+       default 2
+       range 0 13
+
+config SCB0_MI1_SLOT26
+       int "Slot 26 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI1_SLOT27
+       int "Slot 27 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI1_SLOT28
+       int "Slot 28 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI1_SLOT29
+       int "Slot 29 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI1_SLOT30
+       int "Slot 30 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI1_SLOT31
+       int "Slot 31 slave interface id"
+       default 13
+       range 0 13
+
+endif # SCB0_MI1
+
+menuconfig     SCB0_MI2
+       bool "SCB0 Master Interface 2 (Data L2)"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       Core 0  -- 0
+       Core 1  -- 2
+       SCB1    -- 9
+       SCB2    -- 10
+       SCB3    -- 11
+       SCB4    -- 12
+       SCB5    -- 5
+       SCB6    -- 6
+       SCB7    -- 8
+       SCB8    -- 7
+       SCB9    -- 4
+       USB     -- 13
+
+if SCB0_MI2
+
+config SCB0_MI2_SLOT0
+       int "Slot 0 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI2_SLOT1
+       int "Slot 1 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI2_SLOT2
+       int "Slot 2 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI2_SLOT3
+       int "Slot 3 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI2_SLOT4
+       int "Slot 4 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI2_SLOT5
+       int "Slot 5 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI2_SLOT6
+       int "Slot 6 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI2_SLOT7
+       int "Slot 7 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI2_SLOT8
+       int "Slot 8 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI2_SLOT9
+       int "Slot 9 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI2_SLOT10
+       int "Slot 10 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI2_SLOT11
+       int "Slot 11 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI2_SLOT12
+       int "Slot 12 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI2_SLOT13
+       int "Slot 13 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI2_SLOT14
+       int "Slot 14 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI2_SLOT15
+       int "Slot 15 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI2_SLOT16
+       int "Slot 16 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI2_SLOT17
+       int "Slot 17 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI2_SLOT18
+       int "Slot 18 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI2_SLOT19
+       int "Slot 19 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI2_SLOT20
+       int "Slot 20 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI2_SLOT21
+       int "Slot 21 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI2_SLOT22
+       int "Slot 22 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI2_SLOT23
+       int "Slot 23 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI2_SLOT24
+       int "Slot 24 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI2_SLOT25
+       int "Slot 25 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI2_SLOT26
+       int "Slot 26 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI2_SLOT27
+       int "Slot 27 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI2_SLOT28
+       int "Slot 28 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI2_SLOT29
+       int "Slot 29 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI2_SLOT30
+       int "Slot 30 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI2_SLOT31
+       int "Slot 31 slave interface id"
+       default 7
+       range 0 13
+
+endif # SCB0_MI2
+
+menuconfig     SCB0_MI3
+       bool "SCB0 Master Interface 3 (L1A)"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       Core 0  -- 0
+       Core 1  -- 2
+       SCB1    -- 9
+       SCB2    -- 10
+       SCB3    -- 11
+       SCB4    -- 12
+       SCB5    -- 5
+       SCB6    -- 6
+       SCB7    -- 8
+       SCB8    -- 7
+       SCB9    -- 4
+       USB     -- 13
+
+if SCB0_MI3
+
+config SCB0_MI3_SLOT0
+       int "Slot 0 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI3_SLOT1
+       int "Slot 1 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI3_SLOT2
+       int "Slot 2 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI3_SLOT3
+       int "Slot 3 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI3_SLOT4
+       int "Slot 4 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI3_SLOT5
+       int "Slot 5 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI3_SLOT6
+       int "Slot 6 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI3_SLOT7
+       int "Slot 7 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI3_SLOT8
+       int "Slot 8 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI3_SLOT9
+       int "Slot 9 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI3_SLOT10
+       int "Slot 10 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI3_SLOT11
+       int "Slot 11 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI3_SLOT12
+       int "Slot 12 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI3_SLOT13
+       int "Slot 13 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI3_SLOT14
+       int "Slot 14 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI3_SLOT15
+       int "Slot 15 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI3_SLOT16
+       int "Slot 16 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI3_SLOT17
+       int "Slot 17 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI3_SLOT18
+       int "Slot 18 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI3_SLOT19
+       int "Slot 19 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI3_SLOT20
+       int "Slot 20 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI3_SLOT21
+       int "Slot 21 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI3_SLOT22
+       int "Slot 22 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI3_SLOT23
+       int "Slot 23 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI3_SLOT24
+       int "Slot 24 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI3_SLOT25
+       int "Slot 25 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI3_SLOT26
+       int "Slot 26 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI3_SLOT27
+       int "Slot 27 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI3_SLOT28
+       int "Slot 28 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI3_SLOT29
+       int "Slot 29 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI3_SLOT30
+       int "Slot 30 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI3_SLOT31
+       int "Slot 31 slave interface id"
+       default 7
+       range 0 13
+
+endif # SCB0_MI3
+
+menuconfig     SCB0_MI4
+       bool "SCB0 Master Interface 4 (L1B)"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       Core 0  -- 0
+       Core 1  -- 2
+       SCB1    -- 9
+       SCB2    -- 10
+       SCB3    -- 11
+       SCB4    -- 12
+       SCB5    -- 5
+       SCB6    -- 6
+       SCB7    -- 8
+       SCB8    -- 7
+       SCB9    -- 4
+       USB     -- 13
+
+if SCB0_MI4
+
+config SCB0_MI4_SLOT0
+       int "Slot 0 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI4_SLOT1
+       int "Slot 1 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI4_SLOT2
+       int "Slot 2 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI4_SLOT3
+       int "Slot 3 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI4_SLOT4
+       int "Slot 4 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI4_SLOT5
+       int "Slot 5 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI4_SLOT6
+       int "Slot 6 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI4_SLOT7
+       int "Slot 7 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI4_SLOT8
+       int "Slot 8 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI4_SLOT9
+       int "Slot 9 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI4_SLOT10
+       int "Slot 10 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI4_SLOT11
+       int "Slot 11 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI4_SLOT12
+       int "Slot 12 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI4_SLOT13
+       int "Slot 13 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI4_SLOT14
+       int "Slot 14 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI4_SLOT15
+       int "Slot 15 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI4_SLOT16
+       int "Slot 16 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI4_SLOT17
+       int "Slot 17 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI4_SLOT18
+       int "Slot 18 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI4_SLOT19
+       int "Slot 19 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI4_SLOT20
+       int "Slot 20 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI4_SLOT21
+       int "Slot 21 slave interface id"
+       default 5
+       range 0 13
+
+config SCB0_MI4_SLOT22
+       int "Slot 22 slave interface id"
+       default 6
+       range 0 13
+
+config SCB0_MI4_SLOT23
+       int "Slot 23 slave interface id"
+       default 7
+       range 0 13
+
+config SCB0_MI4_SLOT24
+       int "Slot 24 slave interface id"
+       default 8
+       range 0 13
+
+config SCB0_MI4_SLOT25
+       int "Slot 25 slave interface id"
+       default 9
+       range 0 13
+
+config SCB0_MI4_SLOT26
+       int "Slot 26 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI4_SLOT27
+       int "Slot 27 slave interface id"
+       default 11
+       range 0 13
+
+config SCB0_MI4_SLOT28
+       int "Slot 28 slave interface id"
+       default 13
+       range 0 13
+
+config SCB0_MI4_SLOT29
+       int "Slot 29 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI4_SLOT30
+       int "Slot 30 slave interface id"
+       default 4
+       range 0 13
+
+config SCB0_MI4_SLOT31
+       int "Slot 31 slave interface id"
+       default 7
+       range 0 13
+
+endif # SCB0_MI4
+
+menuconfig     SCB0_MI5
+       bool "SCB0 Master Interface 5 (SMMR)"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       MMR0    -- 1
+       MMR1    -- 3
+       SCB2    -- 10
+       SCB4    -- 12
+
+if SCB0_MI5
+
+config SCB0_MI5_SLOT0
+       int "Slot 0 slave interface id"
+       default 1
+       range 0 13
+
+config SCB0_MI5_SLOT1
+       int "Slot 1 slave interface id"
+       default 3
+       range 0 13
+
+config SCB0_MI5_SLOT2
+       int "Slot 2 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI5_SLOT3
+       int "Slot 3 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI5_SLOT4
+       int "Slot 4 slave interface id"
+       default 1
+       range 0 13
+
+config SCB0_MI5_SLOT5
+       int "Slot 5 slave interface id"
+       default 3
+       range 0 13
+
+config SCB0_MI5_SLOT6
+       int "Slot 6 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI5_SLOT7
+       int "Slot 7 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI5_SLOT8
+       int "Slot 8 slave interface id"
+       default 1
+       range 0 13
+
+config SCB0_MI5_SLOT9
+       int "Slot 9 slave interface id"
+       default 3
+       range 0 13
+
+config SCB0_MI5_SLOT10
+       int "Slot 10 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI5_SLOT11
+       int "Slot 11 slave interface id"
+       default 12
+       range 0 13
+
+config SCB0_MI5_SLOT12
+       int "Slot 12 slave interface id"
+       default 1
+       range 0 13
+
+config SCB0_MI5_SLOT13
+       int "Slot 13 slave interface id"
+       default 3
+       range 0 13
+
+config SCB0_MI5_SLOT14
+       int "Slot 14 slave interface id"
+       default 10
+       range 0 13
+
+config SCB0_MI5_SLOT15
+       int "Slot 15 slave interface id"
+       default 12
+       range 0 13
+
+endif # SCB0_MI5
+
+menuconfig     SCB1_MI0
+       bool "SCB1 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       SPORT0A -- 0
+       SPORT0B -- 1
+       SPORT1A -- 2
+       SPORT1B -- 3
+       SPORT2A -- 4
+       SPORT2B -- 5
+       SPI0TX  -- 6
+       SPI0RX  -- 7
+       SPI1TX  -- 8
+       SPI1RX  -- 9
+
+if SCB1_MI0
+
+config SCB1_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 9
+
+config SCB1_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 9
+
+config SCB1_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 9
+
+config SCB1_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 9
+
+config SCB1_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 4
+       range 0 9
+
+config SCB1_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 5
+       range 0 9
+
+config SCB1_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 6
+       range 0 9
+
+config SCB1_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 7
+       range 0 9
+
+config SCB1_MI0_SLOT8
+       int "Slot 8 slave interface id"
+       default 8
+       range 0 9
+
+config SCB1_MI0_SLOT9
+       int "Slot 9 slave interface id"
+       default 9
+       range 0 9
+
+config SCB1_MI0_SLOT10
+       int "Slot 10 slave interface id"
+       default 0
+       range 0 9
+
+config SCB1_MI0_SLOT11
+       int "Slot 11 slave interface id"
+       default 1
+       range 0 9
+
+config SCB1_MI0_SLOT12
+       int "Slot 12 slave interface id"
+       default 2
+       range 0 9
+
+config SCB1_MI0_SLOT13
+       int "Slot 13 slave interface id"
+       default 3
+       range 0 9
+
+config SCB1_MI0_SLOT14
+       int "Slot 14 slave interface id"
+       default 4
+       range 0 9
+
+config SCB1_MI0_SLOT15
+       int "Slot 15 slave interface id"
+       default 5
+       range 0 9
+
+config SCB1_MI0_SLOT16
+       int "Slot 16 slave interface id"
+       default 6
+       range 0 13
+
+config SCB1_MI0_SLOT17
+       int "Slot 17 slave interface id"
+       default 7
+       range 0 13
+
+config SCB1_MI0_SLOT18
+       int "Slot 18 slave interface id"
+       default 8
+       range 0 13
+
+config SCB1_MI0_SLOT19
+       int "Slot 19 slave interface id"
+       default 9
+       range 0 13
+
+endif # SCB1_MI0
+
+menuconfig     SCB2_MI0
+       bool "SCB2 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       RSI     -- 0
+       SDU DMA -- 1
+       SDU     -- 2
+       EMAC0   -- 3
+       EMAC1   -- 4
+
+if SCB2_MI0
+
+config SCB2_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 4
+
+config SCB2_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 4
+
+config SCB2_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 4
+
+config SCB2_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 4
+
+config SCB2_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 4
+       range 0 4
+
+config SCB2_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 0
+       range 0 4
+
+config SCB2_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 1
+       range 0 4
+
+config SCB2_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 2
+       range 0 4
+
+config SCB2_MI0_SLOT8
+       int "Slot 8 slave interface id"
+       default 3
+       range 0 4
+
+config SCB2_MI0_SLOT9
+       int "Slot 9 slave interface id"
+       default 4
+       range 0 4
+
+endif # SCB2_MI0
+
+menuconfig     SCB3_MI0
+       bool "SCB3 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       LP0     -- 0
+       LP1     -- 1
+       LP2     -- 2
+       LP3     -- 3
+       UART0TX -- 4
+       UART0RX -- 5
+       UART1TX -- 4
+       UART1RX -- 5
+
+if SCB3_MI0
+
+config SCB3_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 7
+
+config SCB3_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 7
+
+config SCB3_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 7
+
+config SCB3_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 7
+
+config SCB3_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 4
+       range 0 7
+
+config SCB3_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 5
+       range 0 7
+
+config SCB3_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 6
+       range 0 7
+
+config SCB3_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 7
+       range 0 7
+
+config SCB3_MI0_SLOT8
+       int "Slot 8 slave interface id"
+       default 0
+       range 0 7
+
+config SCB3_MI0_SLOT9
+       int "Slot 9 slave interface id"
+       default 1
+       range 0 7
+
+config SCB3_MI0_SLOT10
+       int "Slot 10 slave interface id"
+       default 2
+       range 0 7
+
+config SCB3_MI0_SLOT11
+       int "Slot 11 slave interface id"
+       default 3
+       range 0 7
+
+config SCB3_MI0_SLOT12
+       int "Slot 12 slave interface id"
+       default 4
+       range 0 7
+
+config SCB3_MI0_SLOT13
+       int "Slot 13 slave interface id"
+       default 5
+       range 0 7
+
+config SCB3_MI0_SLOT14
+       int "Slot 14 slave interface id"
+       default 6
+       range 0 7
+
+config SCB3_MI0_SLOT15
+       int "Slot 15 slave interface id"
+       default 7
+       range 0 7
+
+endif # SCB3_MI0
+
+menuconfig     SCB4_MI0
+       bool "SCB4 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       MDA21   -- 0
+       MDA22   -- 1
+       MDA23   -- 2
+       MDA24   -- 3
+       MDA25   -- 4
+       MDA26   -- 5
+       MDA27   -- 6
+       MDA28   -- 7
+
+if SCB4_MI0
+
+config SCB4_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 7
+
+config SCB4_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 7
+
+config SCB4_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 7
+
+config SCB4_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 7
+
+config SCB4_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 4
+       range 0 7
+
+config SCB4_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 5
+       range 0 7
+
+config SCB4_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 6
+       range 0 7
+
+config SCB4_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 7
+       range 0 7
+
+config SCB4_MI0_SLOT8
+       int "Slot 8 slave interface id"
+       default 0
+       range 0 7
+
+config SCB4_MI0_SLOT9
+       int "Slot 9 slave interface id"
+       default 1
+       range 0 7
+
+config SCB4_MI0_SLOT10
+       int "Slot 10 slave interface id"
+       default 2
+       range 0 7
+
+config SCB4_MI0_SLOT11
+       int "Slot 11 slave interface id"
+       default 3
+       range 0 7
+
+config SCB4_MI0_SLOT12
+       int "Slot 12 slave interface id"
+       default 4
+       range 0 7
+
+config SCB4_MI0_SLOT13
+       int "Slot 13 slave interface id"
+       default 5
+       range 0 7
+
+config SCB4_MI0_SLOT14
+       int "Slot 14 slave interface id"
+       default 6
+       range 0 7
+
+config SCB4_MI0_SLOT15
+       int "Slot 15 slave interface id"
+       default 7
+       range 0 7
+
+endif # SCB4_MI0
+
+menuconfig     SCB5_MI0
+       bool "SCB5 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       PPI0 MDA29      -- 0
+       PPI0 MDA30      -- 1
+       PPI2 MDA31      -- 2
+       PPI2 MDA32      -- 3
+
+if SCB5_MI0
+
+config SCB5_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 3
+
+config SCB5_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 3
+
+config SCB5_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 3
+
+config SCB5_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 3
+
+config SCB5_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 0
+       range 0 3
+
+config SCB5_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 1
+       range 0 3
+
+config SCB5_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 2
+       range 0 3
+
+config SCB5_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 3
+       range 0 3
+
+endif # SCB5_MI0
+
+menuconfig     SCB6_MI0
+       bool "SCB6 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       PPI1 MDA33      -- 0
+       PPI1 MDA34      -- 1
+
+if SCB6_MI0
+
+config SCB6_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 1
+
+config SCB6_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 1
+
+config SCB6_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 0
+       range 0 1
+
+config SCB6_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 1
+       range 0 1
+
+endif # SCB6_MI0
+
+menuconfig     SCB7_MI0
+       bool "SCB7 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       PIXC0   -- 0
+       PIXC1   -- 1
+       PIXC2   -- 2
+
+if SCB7_MI0
+
+config SCB7_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 2
+
+config SCB7_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 2
+
+config SCB7_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 2
+
+config SCB7_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 0
+       range 0 2
+
+config SCB7_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 1
+       range 0 2
+
+config SCB7_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 2
+       range 0 2
+
+endif # SCB7_MI0
+
+menuconfig     SCB8_MI0
+       bool "SCB8 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       PVP CPDOB       -- 0
+       PVP CPDOC       -- 1
+       PVP CPCO        -- 2
+       PVP CPCI        -- 3
+
+if SCB8_MI0
+
+config SCB8_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 3
+
+config SCB8_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 3
+
+config SCB8_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 3
+
+config SCB8_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 3
+
+config SCB8_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 0
+       range 0 3
+
+config SCB8_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 1
+       range 0 3
+
+config SCB8_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 2
+       range 0 3
+
+config SCB8_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 3
+       range 0 3
+
+endif # SCB8_MI0
+
+menuconfig     SCB9_MI0
+       bool "SCB9 Master Interface 0"
+       default n
+       depends on SCB_PRIORITY
+       help
+       The slave interface id of each slot should be set according following table.
+       PVP MPDO        -- 0
+       PVP MPDI        -- 1
+       PVP MPCO        -- 2
+       PVP MPCI        -- 3
+       PVP CPDOA       -- 4
+
+if SCB9_MI0
+
+config SCB9_MI0_SLOT0
+       int "Slot 0 slave interface id"
+       default 0
+       range 0 4
+
+config SCB9_MI0_SLOT1
+       int "Slot 1 slave interface id"
+       default 1
+       range 0 4
+
+config SCB9_MI0_SLOT2
+       int "Slot 2 slave interface id"
+       default 2
+       range 0 4
+
+config SCB9_MI0_SLOT3
+       int "Slot 3 slave interface id"
+       default 3
+       range 0 4
+
+config SCB9_MI0_SLOT4
+       int "Slot 4 slave interface id"
+       default 4
+       range 0 4
+
+config SCB9_MI0_SLOT5
+       int "Slot 5 slave interface id"
+       default 0
+       range 0 4
+
+config SCB9_MI0_SLOT6
+       int "Slot 6 slave interface id"
+       default 1
+       range 0 4
+
+config SCB9_MI0_SLOT7
+       int "Slot 7 slave interface id"
+       default 2
+       range 0 4
+
+config SCB9_MI0_SLOT8
+       int "Slot 8 slave interface id"
+       default 3
+       range 0 4
+
+config SCB9_MI0_SLOT9
+       int "Slot 9 slave interface id"
+       default 4
+       range 0 4
+
+endif # SCB9_MI0
+
 endmenu
 
 endif
index 234fe1b4bb0e90bd8121fdae991f5428357ea20d..60ffaf85d3037dc3cf0e6b58fe076dee9269a998 100644 (file)
@@ -4,3 +4,4 @@
 
 obj-y := dma.o clock.o ints-priority.o
 obj-$(CONFIG_PM) += pm.o dpm.o
+obj-$(CONFIG_SCB_PRIORITY) += scb.o
index 0bc47231540bfa97fcd9711cea1c01afc76a15a7..d56a55ad83a7c2340a43744dcaeca8522909cb01 100644 (file)
@@ -104,6 +104,7 @@ static struct platform_device bfin_rotary_device = {
 
 #if defined(CONFIG_STMMAC_ETH) || defined(CONFIG_STMMAC_ETH_MODULE)
 #include <linux/stmmac.h>
+#include <linux/phy.h>
 
 static unsigned short pins[] = P_RMII0;
 
@@ -111,11 +112,26 @@ static struct stmmac_mdio_bus_data phy_private_data = {
        .phy_mask = 1,
 };
 
+static struct stmmac_dma_cfg eth_dma_cfg = {
+       .pbl    = 2,
+};
+
+int stmmac_ptp_clk_init(struct platform_device *pdev)
+{
+       bfin_write32(PADS0_EMAC_PTP_CLKSEL, 0);
+       return 0;
+}
+
 static struct plat_stmmacenet_data eth_private_data = {
+       .has_gmac = 1,
        .bus_id   = 0,
        .enh_desc = 1,
        .phy_addr = 1,
        .mdio_bus_data = &phy_private_data,
+       .dma_cfg  = &eth_dma_cfg,
+       .force_thresh_dma_mode = 1,
+       .interface = PHY_INTERFACE_MODE_RMII,
+       .init = stmmac_ptp_clk_init,
 };
 
 static struct platform_device bfin_eth_device = {
@@ -1107,6 +1123,81 @@ static struct bfin_display_config bfin_display_data = {
 };
 #endif
 
+#if IS_ENABLED(CONFIG_VIDEO_ADV7343)
+#include <media/adv7343.h>
+
+static struct v4l2_output adv7343_outputs[] = {
+       {
+               .index = 0,
+               .name = "Composite",
+               .type = V4L2_OUTPUT_TYPE_ANALOG,
+               .std = V4L2_STD_ALL,
+               .capabilities = V4L2_OUT_CAP_STD,
+       },
+       {
+               .index = 1,
+               .name = "S-Video",
+               .type = V4L2_OUTPUT_TYPE_ANALOG,
+               .std = V4L2_STD_ALL,
+               .capabilities = V4L2_OUT_CAP_STD,
+       },
+       {
+               .index = 2,
+               .name = "Component",
+               .type = V4L2_OUTPUT_TYPE_ANALOG,
+               .std = V4L2_STD_ALL,
+               .capabilities = V4L2_OUT_CAP_STD,
+       },
+
+};
+
+static struct disp_route adv7343_routes[] = {
+       {
+               .output = ADV7343_COMPOSITE_ID,
+       },
+       {
+               .output = ADV7343_SVIDEO_ID,
+       },
+       {
+               .output = ADV7343_COMPONENT_ID,
+       },
+};
+
+static struct adv7343_platform_data adv7343_data = {
+       .mode_config = {
+               .sleep_mode = false,
+               .pll_control = false,
+               .dac_1 = true,
+               .dac_2 = true,
+               .dac_3 = true,
+               .dac_4 = true,
+               .dac_5 = true,
+               .dac_6 = true,
+       },
+       .sd_config = {
+               .sd_dac_out1 = false,
+               .sd_dac_out2 = false,
+       },
+};
+
+static struct bfin_display_config bfin_display_data = {
+       .card_name = "BF609",
+       .outputs = adv7343_outputs,
+       .num_outputs = ARRAY_SIZE(adv7343_outputs),
+       .routes = adv7343_routes,
+       .i2c_adapter_id = 0,
+       .board_info = {
+               .type = "adv7343",
+               .addr = 0x2b,
+               .platform_data = (void *)&adv7343_data,
+       },
+       .ppi_info = &ppi_info_disp,
+       .ppi_control = (PACK_EN | DLEN_8 | EPPI_CTL_FS1LO_FS2LO
+                       | EPPI_CTL_POLC3 | EPPI_CTL_BLANKGEN | EPPI_CTL_SYNC2
+                       | EPPI_CTL_NON656 | EPPI_CTL_DIR),
+};
+#endif
+
 static struct platform_device bfin_display_device = {
        .name = "bfin_display",
        .dev = {
index 437d56c8228132301fce013f6ebf49e9f9467df6..dab8849af884a5a2032081eff51005c6daf08151 100644 (file)
@@ -220,6 +220,12 @@ unsigned long sys_clk_get_rate(struct clk *clk)
        }
 }
 
+unsigned long dummy_get_rate(struct clk *clk)
+{
+       clk->parent->rate = clk_get_rate(clk->parent);
+       return clk->parent->rate;
+}
+
 unsigned long sys_clk_round_rate(struct clk *clk, unsigned long rate)
 {
        unsigned long max_rate;
@@ -283,6 +289,10 @@ static struct clk_ops sys_clk_ops = {
        .round_rate = sys_clk_round_rate,
 };
 
+static struct clk_ops dummy_clk_ops = {
+       .get_rate = dummy_get_rate,
+};
+
 static struct clk sys_clkin = {
        .name       = "SYS_CLKIN",
        .rate       = CONFIG_CLKIN_HZ,
@@ -364,6 +374,12 @@ static struct clk oclk = {
        .parent     = &pll_clk,
 };
 
+static struct clk ethclk = {
+       .name       = "stmmaceth",
+       .parent     = &sclk0,
+       .ops        = &dummy_clk_ops,
+};
+
 static struct clk_lookup bf609_clks[] = {
        CLK(sys_clkin, NULL, "SYS_CLKIN"),
        CLK(pll_clk, NULL, "PLLCLK"),
@@ -375,6 +391,7 @@ static struct clk_lookup bf609_clks[] = {
        CLK(sclk1, NULL, "SCLK1"),
        CLK(dclk, NULL, "DCLK"),
        CLK(oclk, NULL, "OCLK"),
+       CLK(ethclk, NULL, "stmmaceth"),
 };
 
 int __init clk_init(void)
index f1a6afae1a714a85255731213323a5684b07057c..35caa7bc192cad95027115a8c34f0be6732a85dd 100644 (file)
 #define PORTG_LOCK                  0xFFC03344         /* PORTG Port x GPIO Lock Register */
 #define PORTG_REVID                 0xFFC0337C         /* PORTG Port x GPIO Revision ID */
 
+/* ==================================================
+        Pads Controller Registers
+   ================================================== */
+
+/* =========================
+        PADS0
+   ========================= */
+#define PADS0_EMAC_PTP_CLKSEL      0xFFC03404         /* PADS0 Clock Selection for EMAC and PTP */
+#define PADS0_TWI_VSEL             0xFFC03408         /* PADS0 TWI Voltage Selection */
+#define PADS0_PORTS_HYST           0xFFC03440         /* PADS0 Hysteresis Enable Register */
 
 /* =========================
         PINT Registers
diff --git a/arch/blackfin/mach-bf609/scb.c b/arch/blackfin/mach-bf609/scb.c
new file mode 100644 (file)
index 0000000..ac1f07c
--- /dev/null
@@ -0,0 +1,363 @@
+/*
+ * arch/blackfin/mach-common/scb-init.c - reprogram system cross bar priority
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <asm/blackfin.h>
+#include <asm/scb.h>
+
+struct scb_mi_prio scb_data[] = {
+#ifdef CONFIG_SCB0_MI0
+       { REG_SCB0_ARBR0, REG_SCB0_ARBW0, 32, {
+               CONFIG_SCB0_MI0_SLOT0,
+               CONFIG_SCB0_MI0_SLOT1,
+               CONFIG_SCB0_MI0_SLOT2,
+               CONFIG_SCB0_MI0_SLOT3,
+               CONFIG_SCB0_MI0_SLOT4,
+               CONFIG_SCB0_MI0_SLOT5,
+               CONFIG_SCB0_MI0_SLOT6,
+               CONFIG_SCB0_MI0_SLOT7,
+               CONFIG_SCB0_MI0_SLOT8,
+               CONFIG_SCB0_MI0_SLOT9,
+               CONFIG_SCB0_MI0_SLOT10,
+               CONFIG_SCB0_MI0_SLOT11,
+               CONFIG_SCB0_MI0_SLOT12,
+               CONFIG_SCB0_MI0_SLOT13,
+               CONFIG_SCB0_MI0_SLOT14,
+               CONFIG_SCB0_MI0_SLOT15,
+               CONFIG_SCB0_MI0_SLOT16,
+               CONFIG_SCB0_MI0_SLOT17,
+               CONFIG_SCB0_MI0_SLOT18,
+               CONFIG_SCB0_MI0_SLOT19,
+               CONFIG_SCB0_MI0_SLOT20,
+               CONFIG_SCB0_MI0_SLOT21,
+               CONFIG_SCB0_MI0_SLOT22,
+               CONFIG_SCB0_MI0_SLOT23,
+               CONFIG_SCB0_MI0_SLOT24,
+               CONFIG_SCB0_MI0_SLOT25,
+               CONFIG_SCB0_MI0_SLOT26,
+               CONFIG_SCB0_MI0_SLOT27,
+               CONFIG_SCB0_MI0_SLOT28,
+               CONFIG_SCB0_MI0_SLOT29,
+               CONFIG_SCB0_MI0_SLOT30,
+               CONFIG_SCB0_MI0_SLOT31
+               },
+       },
+#endif
+#ifdef CONFIG_SCB0_MI1
+       { REG_SCB0_ARBR1, REG_SCB0_ARBW1, 32, {
+               CONFIG_SCB0_MI1_SLOT0,
+               CONFIG_SCB0_MI1_SLOT1,
+               CONFIG_SCB0_MI1_SLOT2,
+               CONFIG_SCB0_MI1_SLOT3,
+               CONFIG_SCB0_MI1_SLOT4,
+               CONFIG_SCB0_MI1_SLOT5,
+               CONFIG_SCB0_MI1_SLOT6,
+               CONFIG_SCB0_MI1_SLOT7,
+               CONFIG_SCB0_MI1_SLOT8,
+               CONFIG_SCB0_MI1_SLOT9,
+               CONFIG_SCB0_MI1_SLOT10,
+               CONFIG_SCB0_MI1_SLOT11,
+               CONFIG_SCB0_MI1_SLOT12,
+               CONFIG_SCB0_MI1_SLOT13,
+               CONFIG_SCB0_MI1_SLOT14,
+               CONFIG_SCB0_MI1_SLOT15,
+               CONFIG_SCB0_MI1_SLOT16,
+               CONFIG_SCB0_MI1_SLOT17,
+               CONFIG_SCB0_MI1_SLOT18,
+               CONFIG_SCB0_MI1_SLOT19,
+               CONFIG_SCB0_MI1_SLOT20,
+               CONFIG_SCB0_MI1_SLOT21,
+               CONFIG_SCB0_MI1_SLOT22,
+               CONFIG_SCB0_MI1_SLOT23,
+               CONFIG_SCB0_MI1_SLOT24,
+               CONFIG_SCB0_MI1_SLOT25,
+               CONFIG_SCB0_MI1_SLOT26,
+               CONFIG_SCB0_MI1_SLOT27,
+               CONFIG_SCB0_MI1_SLOT28,
+               CONFIG_SCB0_MI1_SLOT29,
+               CONFIG_SCB0_MI1_SLOT30,
+               CONFIG_SCB0_MI1_SLOT31
+               },
+       },
+#endif
+#ifdef CONFIG_SCB0_MI2
+       { REG_SCB0_ARBR2, REG_SCB0_ARBW2, 32, {
+               CONFIG_SCB0_MI2_SLOT0,
+               CONFIG_SCB0_MI2_SLOT1,
+               CONFIG_SCB0_MI2_SLOT2,
+               CONFIG_SCB0_MI2_SLOT3,
+               CONFIG_SCB0_MI2_SLOT4,
+               CONFIG_SCB0_MI2_SLOT5,
+               CONFIG_SCB0_MI2_SLOT6,
+               CONFIG_SCB0_MI2_SLOT7,
+               CONFIG_SCB0_MI2_SLOT8,
+               CONFIG_SCB0_MI2_SLOT9,
+               CONFIG_SCB0_MI2_SLOT10,
+               CONFIG_SCB0_MI2_SLOT11,
+               CONFIG_SCB0_MI2_SLOT12,
+               CONFIG_SCB0_MI2_SLOT13,
+               CONFIG_SCB0_MI2_SLOT14,
+               CONFIG_SCB0_MI2_SLOT15,
+               CONFIG_SCB0_MI2_SLOT16,
+               CONFIG_SCB0_MI2_SLOT17,
+               CONFIG_SCB0_MI2_SLOT18,
+               CONFIG_SCB0_MI2_SLOT19,
+               CONFIG_SCB0_MI2_SLOT20,
+               CONFIG_SCB0_MI2_SLOT21,
+               CONFIG_SCB0_MI2_SLOT22,
+               CONFIG_SCB0_MI2_SLOT23,
+               CONFIG_SCB0_MI2_SLOT24,
+               CONFIG_SCB0_MI2_SLOT25,
+               CONFIG_SCB0_MI2_SLOT26,
+               CONFIG_SCB0_MI2_SLOT27,
+               CONFIG_SCB0_MI2_SLOT28,
+               CONFIG_SCB0_MI2_SLOT29,
+               CONFIG_SCB0_MI2_SLOT30,
+               CONFIG_SCB0_MI2_SLOT31
+               },
+       },
+#endif
+#ifdef CONFIG_SCB0_MI3
+       { REG_SCB0_ARBR3, REG_SCB0_ARBW3, 32, {
+               CONFIG_SCB0_MI3_SLOT0,
+               CONFIG_SCB0_MI3_SLOT1,
+               CONFIG_SCB0_MI3_SLOT2,
+               CONFIG_SCB0_MI3_SLOT3,
+               CONFIG_SCB0_MI3_SLOT4,
+               CONFIG_SCB0_MI3_SLOT5,
+               CONFIG_SCB0_MI3_SLOT6,
+               CONFIG_SCB0_MI3_SLOT7,
+               CONFIG_SCB0_MI3_SLOT8,
+               CONFIG_SCB0_MI3_SLOT9,
+               CONFIG_SCB0_MI3_SLOT10,
+               CONFIG_SCB0_MI3_SLOT11,
+               CONFIG_SCB0_MI3_SLOT12,
+               CONFIG_SCB0_MI3_SLOT13,
+               CONFIG_SCB0_MI3_SLOT14,
+               CONFIG_SCB0_MI3_SLOT15,
+               CONFIG_SCB0_MI3_SLOT16,
+               CONFIG_SCB0_MI3_SLOT17,
+               CONFIG_SCB0_MI3_SLOT18,
+               CONFIG_SCB0_MI3_SLOT19,
+               CONFIG_SCB0_MI3_SLOT20,
+               CONFIG_SCB0_MI3_SLOT21,
+               CONFIG_SCB0_MI3_SLOT22,
+               CONFIG_SCB0_MI3_SLOT23,
+               CONFIG_SCB0_MI3_SLOT24,
+               CONFIG_SCB0_MI3_SLOT25,
+               CONFIG_SCB0_MI3_SLOT26,
+               CONFIG_SCB0_MI3_SLOT27,
+               CONFIG_SCB0_MI3_SLOT28,
+               CONFIG_SCB0_MI3_SLOT29,
+               CONFIG_SCB0_MI3_SLOT30,
+               CONFIG_SCB0_MI3_SLOT31
+               },
+       },
+#endif
+#ifdef CONFIG_SCB0_MI4
+       { REG_SCB0_ARBR4, REG_SCB4_ARBW0, 32, {
+               CONFIG_SCB0_MI4_SLOT0,
+               CONFIG_SCB0_MI4_SLOT1,
+               CONFIG_SCB0_MI4_SLOT2,
+               CONFIG_SCB0_MI4_SLOT3,
+               CONFIG_SCB0_MI4_SLOT4,
+               CONFIG_SCB0_MI4_SLOT5,
+               CONFIG_SCB0_MI4_SLOT6,
+               CONFIG_SCB0_MI4_SLOT7,
+               CONFIG_SCB0_MI4_SLOT8,
+               CONFIG_SCB0_MI4_SLOT9,
+               CONFIG_SCB0_MI4_SLOT10,
+               CONFIG_SCB0_MI4_SLOT11,
+               CONFIG_SCB0_MI4_SLOT12,
+               CONFIG_SCB0_MI4_SLOT13,
+               CONFIG_SCB0_MI4_SLOT14,
+               CONFIG_SCB0_MI4_SLOT15,
+               CONFIG_SCB0_MI4_SLOT16,
+               CONFIG_SCB0_MI4_SLOT17,
+               CONFIG_SCB0_MI4_SLOT18,
+               CONFIG_SCB0_MI4_SLOT19,
+               CONFIG_SCB0_MI4_SLOT20,
+               CONFIG_SCB0_MI4_SLOT21,
+               CONFIG_SCB0_MI4_SLOT22,
+               CONFIG_SCB0_MI4_SLOT23,
+               CONFIG_SCB0_MI4_SLOT24,
+               CONFIG_SCB0_MI4_SLOT25,
+               CONFIG_SCB0_MI4_SLOT26,
+               CONFIG_SCB0_MI4_SLOT27,
+               CONFIG_SCB0_MI4_SLOT28,
+               CONFIG_SCB0_MI4_SLOT29,
+               CONFIG_SCB0_MI4_SLOT30,
+               CONFIG_SCB0_MI4_SLOT31
+               },
+       },
+#endif
+#ifdef CONFIG_SCB0_MI5
+       { REG_SCB0_ARBR5, REG_SCB0_ARBW5, 16, {
+               CONFIG_SCB0_MI5_SLOT0,
+               CONFIG_SCB0_MI5_SLOT1,
+               CONFIG_SCB0_MI5_SLOT2,
+               CONFIG_SCB0_MI5_SLOT3,
+               CONFIG_SCB0_MI5_SLOT4,
+               CONFIG_SCB0_MI5_SLOT5,
+               CONFIG_SCB0_MI5_SLOT6,
+               CONFIG_SCB0_MI5_SLOT7,
+               CONFIG_SCB0_MI5_SLOT8,
+               CONFIG_SCB0_MI5_SLOT9,
+               CONFIG_SCB0_MI5_SLOT10,
+               CONFIG_SCB0_MI5_SLOT11,
+               CONFIG_SCB0_MI5_SLOT12,
+               CONFIG_SCB0_MI5_SLOT13,
+               CONFIG_SCB0_MI5_SLOT14,
+               CONFIG_SCB0_MI5_SLOT15
+               },
+       },
+#endif
+#ifdef CONFIG_SCB1_MI0
+       { REG_SCB1_ARBR0, REG_SCB1_ARBW0, 20, {
+               CONFIG_SCB1_MI0_SLOT0,
+               CONFIG_SCB1_MI0_SLOT1,
+               CONFIG_SCB1_MI0_SLOT2,
+               CONFIG_SCB1_MI0_SLOT3,
+               CONFIG_SCB1_MI0_SLOT4,
+               CONFIG_SCB1_MI0_SLOT5,
+               CONFIG_SCB1_MI0_SLOT6,
+               CONFIG_SCB1_MI0_SLOT7,
+               CONFIG_SCB1_MI0_SLOT8,
+               CONFIG_SCB1_MI0_SLOT9,
+               CONFIG_SCB1_MI0_SLOT10,
+               CONFIG_SCB1_MI0_SLOT11,
+               CONFIG_SCB1_MI0_SLOT12,
+               CONFIG_SCB1_MI0_SLOT13,
+               CONFIG_SCB1_MI0_SLOT14,
+               CONFIG_SCB1_MI0_SLOT15,
+               CONFIG_SCB1_MI0_SLOT16,
+               CONFIG_SCB1_MI0_SLOT17,
+               CONFIG_SCB1_MI0_SLOT18,
+               CONFIG_SCB1_MI0_SLOT19
+               },
+       },
+#endif
+#ifdef CONFIG_SCB2_MI0
+       { REG_SCB2_ARBR0, REG_SCB2_ARBW0, 10, {
+               CONFIG_SCB2_MI0_SLOT0,
+               CONFIG_SCB2_MI0_SLOT1,
+               CONFIG_SCB2_MI0_SLOT2,
+               CONFIG_SCB2_MI0_SLOT3,
+               CONFIG_SCB2_MI0_SLOT4,
+               CONFIG_SCB2_MI0_SLOT5,
+               CONFIG_SCB2_MI0_SLOT6,
+               CONFIG_SCB2_MI0_SLOT7,
+               CONFIG_SCB2_MI0_SLOT8,
+               CONFIG_SCB2_MI0_SLOT9
+               },
+       },
+#endif
+#ifdef CONFIG_SCB3_MI0
+       { REG_SCB3_ARBR0, REG_SCB3_ARBW0, 16, {
+               CONFIG_SCB3_MI0_SLOT0,
+               CONFIG_SCB3_MI0_SLOT1,
+               CONFIG_SCB3_MI0_SLOT2,
+               CONFIG_SCB3_MI0_SLOT3,
+               CONFIG_SCB3_MI0_SLOT4,
+               CONFIG_SCB3_MI0_SLOT5,
+               CONFIG_SCB3_MI0_SLOT6,
+               CONFIG_SCB3_MI0_SLOT7,
+               CONFIG_SCB3_MI0_SLOT8,
+               CONFIG_SCB3_MI0_SLOT9,
+               CONFIG_SCB3_MI0_SLOT10,
+               CONFIG_SCB3_MI0_SLOT11,
+               CONFIG_SCB3_MI0_SLOT12,
+               CONFIG_SCB3_MI0_SLOT13,
+               CONFIG_SCB3_MI0_SLOT14,
+               CONFIG_SCB3_MI0_SLOT15
+               },
+       },
+#endif
+#ifdef CONFIG_SCB4_MI0
+       { REG_SCB4_ARBR0, REG_SCB4_ARBW0, 16, {
+               CONFIG_SCB4_MI0_SLOT0,
+               CONFIG_SCB4_MI0_SLOT1,
+               CONFIG_SCB4_MI0_SLOT2,
+               CONFIG_SCB4_MI0_SLOT3,
+               CONFIG_SCB4_MI0_SLOT4,
+               CONFIG_SCB4_MI0_SLOT5,
+               CONFIG_SCB4_MI0_SLOT6,
+               CONFIG_SCB4_MI0_SLOT7,
+               CONFIG_SCB4_MI0_SLOT8,
+               CONFIG_SCB4_MI0_SLOT9,
+               CONFIG_SCB4_MI0_SLOT10,
+               CONFIG_SCB4_MI0_SLOT11,
+               CONFIG_SCB4_MI0_SLOT12,
+               CONFIG_SCB4_MI0_SLOT13,
+               CONFIG_SCB4_MI0_SLOT14,
+               CONFIG_SCB4_MI0_SLOT15
+               },
+       },
+#endif
+#ifdef CONFIG_SCB5_MI0
+       { REG_SCB5_ARBR0, REG_SCB5_ARBW0, 8, {
+               CONFIG_SCB5_MI0_SLOT0,
+               CONFIG_SCB5_MI0_SLOT1,
+               CONFIG_SCB5_MI0_SLOT2,
+               CONFIG_SCB5_MI0_SLOT3,
+               CONFIG_SCB5_MI0_SLOT4,
+               CONFIG_SCB5_MI0_SLOT5,
+               CONFIG_SCB5_MI0_SLOT6,
+               CONFIG_SCB5_MI0_SLOT7
+               },
+       },
+#endif
+#ifdef CONFIG_SCB6_MI0
+       { REG_SCB6_ARBR0, REG_SCB6_ARBW0, 4, {
+               CONFIG_SCB6_MI0_SLOT0,
+               CONFIG_SCB6_MI0_SLOT1,
+               CONFIG_SCB6_MI0_SLOT2,
+               CONFIG_SCB6_MI0_SLOT3
+               },
+       },
+#endif
+#ifdef CONFIG_SCB7_MI0
+       { REG_SCB7_ARBR0, REG_SCB7_ARBW0, 6, {
+               CONFIG_SCB7_MI0_SLOT0,
+               CONFIG_SCB7_MI0_SLOT1,
+               CONFIG_SCB7_MI0_SLOT2,
+               CONFIG_SCB7_MI0_SLOT3,
+               CONFIG_SCB7_MI0_SLOT4,
+               CONFIG_SCB7_MI0_SLOT5
+               },
+       },
+#endif
+#ifdef CONFIG_SCB8_MI0
+       { REG_SCB8_ARBR0, REG_SCB8_ARBW0, 8, {
+               CONFIG_SCB8_MI0_SLOT0,
+               CONFIG_SCB8_MI0_SLOT1,
+               CONFIG_SCB8_MI0_SLOT2,
+               CONFIG_SCB8_MI0_SLOT3,
+               CONFIG_SCB8_MI0_SLOT4,
+               CONFIG_SCB8_MI0_SLOT5,
+               CONFIG_SCB8_MI0_SLOT6,
+               CONFIG_SCB8_MI0_SLOT7
+               },
+       },
+#endif
+#ifdef CONFIG_SCB9_MI0
+       { REG_SCB9_ARBR0, REG_SCB9_ARBW0, 10, {
+               CONFIG_SCB9_MI0_SLOT0,
+               CONFIG_SCB9_MI0_SLOT1,
+               CONFIG_SCB9_MI0_SLOT2,
+               CONFIG_SCB9_MI0_SLOT3,
+               CONFIG_SCB9_MI0_SLOT4,
+               CONFIG_SCB9_MI0_SLOT5,
+               CONFIG_SCB9_MI0_SLOT6,
+               CONFIG_SCB9_MI0_SLOT7,
+               CONFIG_SCB9_MI0_SLOT8,
+               CONFIG_SCB9_MI0_SLOT9
+               },
+       },
+#endif
+       { 0, }
+};
index 675466d490d4dfd7ff0fbd596647f54d68710925..f099792040402fd9a08006c7f5c85782178cd625 100644 (file)
@@ -10,6 +10,7 @@ obj-$(CONFIG_PM)          += pm.o
 ifneq ($(CONFIG_BF60x),y)
 obj-$(CONFIG_PM)         += dpmc_modes.o
 endif
+obj-$(CONFIG_SCB_PRIORITY)     += scb-init.o
 obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o
 obj-$(CONFIG_SMP)         += smp.o
 obj-$(CONFIG_BFIN_KERNEL_CLOCK) += clocks-init.o
diff --git a/arch/blackfin/mach-common/scb-init.c b/arch/blackfin/mach-common/scb-init.c
new file mode 100644 (file)
index 0000000..2cbfb0b
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * arch/blackfin/mach-common/scb-init.c - reprogram system cross bar priority
+ *
+ * Copyright 2012 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <asm/scb.h>
+
+__attribute__((l1_text))
+inline void scb_mi_write(unsigned long scb_mi_arbw, unsigned int slots,
+               unsigned char *scb_mi_prio)
+{
+       unsigned int i;
+
+       for (i = 0; i < slots; ++i)
+               bfin_write32(scb_mi_arbw, (i << SCB_SLOT_OFFSET) | scb_mi_prio[i]);
+}
+
+__attribute__((l1_text))
+inline void scb_mi_read(unsigned long scb_mi_arbw, unsigned int slots,
+               unsigned char *scb_mi_prio)
+{
+       unsigned int i;
+
+       for (i = 0; i < slots; ++i) {
+               bfin_write32(scb_mi_arbw, (0xFF << SCB_SLOT_OFFSET) | i);
+               scb_mi_prio[i] = bfin_read32(scb_mi_arbw);
+       }
+}
+
+__attribute__((l1_text))
+void init_scb(void)
+{
+       unsigned int i, j;
+       unsigned char scb_tmp_prio[32];
+
+       pr_info("Init System Crossbar\n");
+       for (i = 0; scb_data[i].scb_mi_arbr > 0; ++i) {
+
+               scb_mi_write(scb_data[i].scb_mi_arbw, scb_data[i].scb_mi_slots, scb_data[i].scb_mi_prio);
+
+               pr_debug("scb priority at 0x%lx:\n", scb_data[i].scb_mi_arbr);
+               scb_mi_read(scb_data[i].scb_mi_arbw, scb_data[i].scb_mi_slots, scb_tmp_prio);
+               for (j = 0; j < scb_data[i].scb_mi_slots; ++j)
+                       pr_debug("slot %d = %d\n", j, scb_tmp_prio[j]);
+       }
+
+}
index f6a3648f5ec3c7030a8c4294be4e3bee54a25b6c..957dd00ea561ce3881a0af87394d349fab04f449 100644 (file)
@@ -10,7 +10,6 @@ config C6X
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_MEMBLOCK
        select SPARSE_IRQ
        select IRQ_DOMAIN
index bdb56f09d0acc42eacf87398e48e08645ac727c8..9e15ab9199b24fe234780941299757246b92b6cb 100644 (file)
@@ -33,8 +33,7 @@ void __init early_init_devtree(void *params)
 
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
@@ -46,8 +45,3 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
        c6x_add_memory(base, size);
 }
-
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-{
-       return __va(memblock_alloc(size, align));
-}
index 3201ddb8da6a039d3fd56b3fa13969648a004d08..02380bed189c6fda4920412a18f1baab6203d1c1 100644 (file)
@@ -41,7 +41,6 @@ config CRIS
        default y
        select HAVE_IDE
        select GENERIC_ATOMIC64
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_UID16
        select VIRT_TO_BUS
        select ARCH_WANT_IPC_PARSE_VERSION
@@ -99,9 +98,6 @@ config ETRAX_KMALLOCED_MODULES
        help
          Enable module allocation with kmalloc instead of vmalloc.
 
-config OOM_REBOOT
-       bool "Enable reboot at out of memory"
-
 source "kernel/Kconfig.preempt"
 
 source mm/Kconfig
@@ -175,12 +171,6 @@ config ETRAX_FLASH_BUSWIDTH
        help
          Width in bytes of the NOR Flash bus (1, 2 or 4). Is usually 2.
 
-config ETRAX_NANDFLASH_BUSWIDTH
-       int "Buswidth of NAND flash in bytes"
-       default "1"
-       help
-         Width in bytes of the NAND flash (1 or 2).
-
 config ETRAX_FLASH1_SIZE
        int "FLASH1 size (dec, in MB. 0 = Unknown)"
        default "0"
@@ -272,38 +262,6 @@ config ETRAX_AXISFLASHMAP
          This option enables MTD mapping of flash devices.  Needed to use
          flash memories.  If unsure, say Y.
 
-config ETRAX_RTC
-       bool "Real Time Clock support"
-       depends on ETRAX_I2C
-       help
-         Enables drivers for the Real-Time Clock battery-backed chips on
-         some products. The kernel reads the time when booting, and
-         the date can be set using ioctl(fd, RTC_SET_TIME, &rt) with rt a
-         rtc_time struct (see <file:arch/cris/include/asm/rtc.h>) on the
-         /dev/rtc device.  You can check the time with cat /proc/rtc, but
-         normal time reading should be done using libc function time and
-         friends.
-
-choice
-       prompt "RTC chip"
-       depends on ETRAX_RTC
-       default ETRAX_DS1302
-
-config ETRAX_DS1302
-       depends on ETRAX_ARCH_V10
-       bool "DS1302"
-       help
-         Enables the driver for the DS1302 Real-Time Clock battery-backed
-         chip on some products.
-
-config ETRAX_PCF8563
-       bool "PCF8563"
-       help
-         Enables the driver for the PCF8563 Real-Time Clock battery-backed
-         chip on some products.
-
-endchoice
-
 config ETRAX_SYNCHRONOUS_SERIAL
        bool "Synchronous serial-port support"
        help
@@ -578,26 +536,6 @@ config ETRAX_SERIAL_PORT3_DMA5_IN
        depends on ETRAX_ARCH_V10
        bool "DMA 5"
 
-config ETRAX_SERIAL_PORT3_DMA9_IN
-       bool "Ser3 uses DMA9 for input"
-       depends on ETRAXFS
-       help
-         Enables the DMA9 input channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when receiving data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
-config ETRAX_SERIAL_PORT3_DMA3_IN
-       bool "Ser3 uses DMA3 for input"
-       depends on CRIS_MACH_ARTPEC3
-       help
-         Enables the DMA3 input channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when receiving data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
 endchoice
 
 choice
@@ -615,26 +553,6 @@ config ETRAX_SERIAL_PORT3_DMA4_OUT
        depends on ETRAX_ARCH_V10
        bool "DMA 4"
 
-config ETRAX_SERIAL_PORT3_DMA8_OUT
-       bool "Ser3 uses DMA8 for output"
-       depends on ETRAXFS
-       help
-         Enables the DMA8 output channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when transmitting data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
-config ETRAX_SERIAL_PORT3_DMA2_OUT
-       bool "Ser3 uses DMA2 for output"
-       depends on CRIS_MACH_ARTPEC3
-       help
-         Enables the DMA2 output channel for ser3 (ttyS3).
-         If you do not enable DMA, an interrupt for each character will be
-         used when transmitting data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
 endchoice
 
 endmenu
index daf5f19b61a12bd54e23acd09a0db76132228993..239dab0b95c131034a8aaba771bcb53c833be3e9 100644 (file)
@@ -417,16 +417,6 @@ config ETRAX_USB_HOST
           for CTRL and BULK traffic only, INTR traffic may work as well
           however (depending on the requirements of timeliness).
 
-config ETRAX_USB_HOST_PORT1
-       bool "USB port 1 enabled"
-       depends on ETRAX_USB_HOST
-       default n
-
-config ETRAX_USB_HOST_PORT2
-       bool "USB port 2 enabled"
-       depends on ETRAX_USB_HOST
-       default n
-
 config ETRAX_PTABLE_SECTOR
        int "Byte-offset of partition table sector"
        depends on ETRAX_AXISFLASHMAP
@@ -527,19 +517,6 @@ config ETRAX_GPIO
          Remember that you need to setup the port directions appropriately in
          the General configuration.
 
-config ETRAX_PA_BUTTON_BITMASK
-       hex "PA-buttons bitmask"
-       depends on ETRAX_GPIO
-       default "02"
-       help
-         This is a bitmask with information about what bits on PA that
-         are used for buttons.
-         Most products has a so called TEST button on PA1, if that's true
-         use 02 here.
-         Use 00 if there are no buttons on PA.
-         If the bitmask is <> 00 a button driver will be included in the gpio
-         driver. ETRAX general I/O support must be enabled.
-
 config ETRAX_PA_CHANGEABLE_DIR
        hex "PA user changeable dir mask"
        depends on ETRAX_GPIO
@@ -580,51 +557,4 @@ config ETRAX_PB_CHANGEABLE_BITS
          Bit set = changeable.
          You probably want 00 here.
 
-config ETRAX_DS1302_RST_ON_GENERIC_PORT
-       bool "DS1302 RST on Generic Port"
-       depends on ETRAX_DS1302
-       help
-         If your product has the RST signal line for the DS1302 RTC on the
-         Generic Port then say Y here, otherwise leave it as N in which
-         case the RST signal line is assumed to be connected to Port PB
-         (just like the SCL and SDA lines).
-
-config ETRAX_DS1302_RSTBIT
-       int "DS1302 RST bit number"
-       depends on ETRAX_DS1302
-       default "2"
-       help
-         This is the bit number for the RST signal line of the DS1302 RTC on
-         the selected port. If you have selected the generic port then it
-         should be bit 27, otherwise your best bet is bit 5.
-
-config ETRAX_DS1302_SCLBIT
-       int "DS1302 SCL bit number"
-       depends on ETRAX_DS1302
-       default "1"
-       help
-         This is the bit number for the SCL signal line of the DS1302 RTC on
-         Port PB. This is probably best left at 3.
-
-config ETRAX_DS1302_SDABIT
-       int "DS1302 SDA bit number"
-       depends on ETRAX_DS1302
-       default "0"
-       help
-         This is the bit number for the SDA signal line of the DS1302 RTC on
-         Port PB. This is probably best left at 2.
-
-config ETRAX_DS1302_TRICKLE_CHARGE
-       int "DS1302 Trickle charger value"
-       depends on ETRAX_DS1302
-       default "0"
-       help
-         This controls the initial value of the trickle charge register.
-         0 = disabled (use this if you are unsure or have a non rechargeable battery)
-         Otherwise the following values can be OR:ed together to control the
-         charge current:
-         1 = 2kohm, 2 = 4kohm, 3 = 4kohm
-         4 = 1 diode, 8 = 2 diodes
-         Allowed values are (increasing current): 0, 11, 10, 9, 7, 6, 5
-
 endif
index 44bf2e88c26e49a7308bcec4df4da97297bfa6c7..e5c13183b97c99fd52ad454cf2dfd7593bcb6c7d 100644 (file)
@@ -6,7 +6,5 @@ obj-$(CONFIG_ETRAX_AXISFLASHMAP)        += axisflashmap.o
 obj-$(CONFIG_ETRAX_I2C)                        += i2c.o
 obj-$(CONFIG_ETRAX_I2C_EEPROM)         += eeprom.o
 obj-$(CONFIG_ETRAX_GPIO)               += gpio.o
-obj-$(CONFIG_ETRAX_DS1302)             += ds1302.o
-obj-$(CONFIG_ETRAX_PCF8563)            += pcf8563.o
 obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o
 
index 1d866d3ee2f85329bfbd4b94130c6ccaf1035804..6792503aaf79effd5adfcf50591d0978de6c729c 100644 (file)
@@ -19,64 +19,6 @@ config ETRAX_NO_PHY
          switch. This option should normally be disabled. If enabled,
          speed and duplex will be locked to 100 Mbit and full duplex.
 
-config ETRAX_ETHERNET_IFACE0
-       depends on ETRAX_ETHERNET
-       bool "Enable network interface 0"
-
-config ETRAX_ETHERNET_IFACE1
-       depends on (ETRAX_ETHERNET && ETRAXFS)
-       bool "Enable network interface 1 (uses DMA6 and DMA7)"
-
-config ETRAX_ETHERNET_GBIT
-       depends on (ETRAX_ETHERNET && CRIS_MACH_ARTPEC3)
-       bool "Enable gigabit Ethernet support"
-
-choice
-       prompt "Eth0 led group"
-       depends on ETRAX_ETHERNET_IFACE0
-       default ETRAX_ETH0_USE_LEDGRP0
-
-config ETRAX_ETH0_USE_LEDGRP0
-       bool "Use LED grp 0"
-       depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 0 for eth0
-
-config ETRAX_ETH0_USE_LEDGRP1
-       bool "Use LED grp 1"
-       depends on ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 1 for eth0
-
-config ETRAX_ETH0_USE_LEDGRPNULL
-       bool "Use no LEDs for eth0"
-       help
-         Use no LEDs for eth0
-endchoice
-
-choice
-       prompt "Eth1 led group"
-       depends on ETRAX_ETHERNET_IFACE1
-       default ETRAX_ETH1_USE_LEDGRP1
-
-config ETRAX_ETH1_USE_LEDGRP0
-       bool "Use LED grp 0"
-       depends on ETRAX_NBR_LED_GRP_ONE || ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 0 for eth1
-
-config ETRAX_ETH1_USE_LEDGRP1
-       bool "Use LED grp 1"
-       depends on ETRAX_NBR_LED_GRP_TWO
-       help
-         Use LED grp 1 for eth1
-
-config ETRAX_ETH1_USE_LEDGRPNULL
-       bool "Use no LEDs for eth1"
-       help
-         Use no LEDs for eth1
-endchoice
-
 config ETRAXFS_SERIAL
        bool "Serial-port support"
        depends on ETRAX_ARCH_V32
@@ -108,261 +50,24 @@ config ETRAX_SERIAL_PORT0
          if you do not need DMA to something else.
          ser0 can use dma4 or dma6 for output and dma5 or dma7 for input.
 
-choice
-       prompt "Ser0 default port type "
-       depends on ETRAX_SERIAL_PORT0
-       default ETRAX_SERIAL_PORT0_TYPE_232
-       help
-         Type of serial port.
-
-config ETRAX_SERIAL_PORT0_TYPE_232
-       bool "Ser0 is a RS-232 port"
-       help
-         Configure serial port 0 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT0_TYPE_485HD
-       bool "Ser0 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 0 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT0_TYPE_485FD
-       bool "Ser0 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 0 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-config ETRAX_SER0_DTR_BIT
-       string "Ser 0 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
-config ETRAX_SER0_RI_BIT
-       string "Ser 0 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
-config ETRAX_SER0_DSR_BIT
-       string "Ser 0 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
-config ETRAX_SER0_CD_BIT
-       string "Ser 0 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT0
-
 config ETRAX_SERIAL_PORT1
        bool "Serial port 1 enabled"
        depends on ETRAXFS_SERIAL
        help
          Enables the ETRAX FS serial driver for ser1 (ttyS1).
 
-choice
-       prompt "Ser1 default port type"
-       depends on ETRAX_SERIAL_PORT1
-       default ETRAX_SERIAL_PORT1_TYPE_232
-       help
-         Type of serial port.
-
-config ETRAX_SERIAL_PORT1_TYPE_232
-       bool "Ser1 is a RS-232 port"
-       help
-         Configure serial port 1 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT1_TYPE_485HD
-       bool "Ser1 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 1 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT1_TYPE_485FD
-       bool "Ser1 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 1 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-config ETRAX_SER1_DTR_BIT
-       string "Ser 1 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
-config ETRAX_SER1_RI_BIT
-       string "Ser 1 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
-config ETRAX_SER1_DSR_BIT
-       string "Ser 1 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
-config ETRAX_SER1_CD_BIT
-       string "Ser 1 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT1
-
 config ETRAX_SERIAL_PORT2
        bool "Serial port 2 enabled"
        depends on ETRAXFS_SERIAL
        help
          Enables the ETRAX FS serial driver for ser2 (ttyS2).
 
-choice
-       prompt "Ser2 default port type"
-       depends on ETRAX_SERIAL_PORT2
-       default ETRAX_SERIAL_PORT2_TYPE_232
-       help
-         What DMA channel to use for ser2
-
-config ETRAX_SERIAL_PORT2_TYPE_232
-       bool "Ser2 is a RS-232 port"
-       help
-         Configure serial port 2 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT2_TYPE_485HD
-       bool "Ser2 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 2 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT2_TYPE_485FD
-       bool "Ser2 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 2 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-
-config ETRAX_SER2_DTR_BIT
-       string "Ser 2 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
-config ETRAX_SER2_RI_BIT
-       string "Ser 2 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
-config ETRAX_SER2_DSR_BIT
-       string "Ser 2 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
-config ETRAX_SER2_CD_BIT
-       string "Ser 2 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT2
-
 config ETRAX_SERIAL_PORT3
        bool "Serial port 3 enabled"
        depends on ETRAXFS_SERIAL
        help
          Enables the ETRAX FS serial driver for ser3 (ttyS3).
 
-choice
-       prompt "Ser3 default port type"
-       depends on ETRAX_SERIAL_PORT3
-       default ETRAX_SERIAL_PORT3_TYPE_232
-       help
-         What DMA channel to use for ser3.
-
-config ETRAX_SERIAL_PORT3_TYPE_232
-       bool "Ser3 is a RS-232 port"
-       help
-         Configure serial port 3 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT3_TYPE_485HD
-       bool "Ser3 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 3 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT3_TYPE_485FD
-       bool "Ser3 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 3 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-config ETRAX_SER3_DTR_BIT
-       string "Ser 3 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SER3_RI_BIT
-       string "Ser 3 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SER3_DSR_BIT
-       string "Ser 3 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SER3_CD_BIT
-       string "Ser 3 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT3
-
-config ETRAX_SERIAL_PORT4
-       bool "Serial port 4 enabled"
-       depends on ETRAXFS_SERIAL && CRIS_MACH_ARTPEC3
-       help
-         Enables the ETRAX FS serial driver for ser4 (ttyS4).
-
-choice
-       prompt "Ser4 default port type"
-       depends on ETRAX_SERIAL_PORT4
-       default ETRAX_SERIAL_PORT4_TYPE_232
-       help
-         What DMA channel to use for ser4.
-
-config ETRAX_SERIAL_PORT4_TYPE_232
-       bool "Ser4 is a RS-232 port"
-       help
-         Configure serial port 4 to be a RS-232 port.
-
-config ETRAX_SERIAL_PORT4_TYPE_485HD
-       bool "Ser4 is a half duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 4 to be a half duplex (two wires) RS-485 port.
-
-config ETRAX_SERIAL_PORT4_TYPE_485FD
-       bool "Ser4 is a full duplex RS-485 port"
-       depends on ETRAX_RS485
-       help
-         Configure serial port 4 to be a full duplex (four wires) RS-485 port.
-endchoice
-
-choice
-       prompt "Ser4 DMA in channel "
-       depends on ETRAX_SERIAL_PORT4
-       default ETRAX_SERIAL_PORT4_NO_DMA_IN
-       help
-         What DMA channel to use for ser4.
-
-
-config ETRAX_SERIAL_PORT4_NO_DMA_IN
-       bool "Ser4 uses no DMA for input"
-       help
-         Do not use DMA for ser4 input.
-
-config ETRAX_SERIAL_PORT4_DMA9_IN
-       bool "Ser4 uses DMA9 for input"
-       depends on ETRAX_SERIAL_PORT4
-       help
-         Enables the DMA9 input channel for ser4 (ttyS4).
-         If you do not enable DMA, an interrupt for each character will be
-         used when receiving data.
-         Normally you want to use DMA, unless you use the DMA channel for
-         something else.
-
-endchoice
-
-config ETRAX_SER4_DTR_BIT
-       string "Ser 4 DTR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
-config ETRAX_SER4_RI_BIT
-       string "Ser 4 RI bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
-config ETRAX_SER4_DSR_BIT
-       string "Ser 4 DSR bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
-config ETRAX_SER4_CD_BIT
-       string "Ser 4 CD bit (empty = not used)"
-       depends on ETRAX_SERIAL_PORT4
-
 config ETRAX_SYNCHRONOUS_SERIAL
        bool "Synchronous serial-port support"
        depends on ETRAX_ARCH_V32
@@ -703,32 +408,6 @@ config ETRAX_SPI_SSER0
          want to build it as a module, which will be named spi_crisv32_sser.
          (You need to select MMC separately.)
 
-config ETRAX_SPI_SSER0_DMA
-       bool "DMA for SPI on sser0 enabled"
-       depends on ETRAX_SPI_SSER0
-       depends on !ETRAX_SERIAL_PORT1_DMA4_OUT && !ETRAX_SERIAL_PORT1_DMA5_IN
-       default y
-       help
-         Say Y if using DMA (dma4/dma5) for SPI on synchronous serial port 0.
-
-config ETRAX_SPI_MMC_CD_SSER0_PIN
-       string "MMC/SD card detect pin for SPI on sser0"
-       depends on ETRAX_SPI_SSER0 && MMC_SPI
-       default "pd11"
-       help
-         The pin to use for SD/MMC card detect.  This pin should be pulled up
-         and grounded when a card is present.  If defined as " " (space), no
-         pin is selected.  A card must then always be inserted for proper
-         action.
-
-config ETRAX_SPI_MMC_WP_SSER0_PIN
-       string "MMC/SD card write-protect pin for SPI on sser0"
-       depends on ETRAX_SPI_SSER0 && MMC_SPI
-       default "pd10"
-       help
-         The pin to use for the SD/MMC write-protect signal for a memory
-         card.  If defined as " " (space), the card is considered writable.
-
 config ETRAX_SPI_SSER1
        tristate "SPI using synchronous serial port 1 (sser1)"
        depends on ETRAX_SPI_MMC
@@ -742,32 +421,6 @@ config ETRAX_SPI_SSER1
          want to build it as a module, which will be named spi_crisv32_sser.
          (You need to select MMC separately.)
 
-config ETRAX_SPI_SSER1_DMA
-       bool "DMA for SPI on sser1 enabled"
-       depends on ETRAX_SPI_SSER1 && !ETRAX_ETHERNET_IFACE1
-       depends on !ETRAX_SERIAL_PORT0_DMA6_OUT && !ETRAX_SERIAL_PORT0_DMA7_IN
-       default y
-       help
-         Say Y if using DMA (dma6/dma7) for SPI on synchronous serial port 1.
-
-config ETRAX_SPI_MMC_CD_SSER1_PIN
-       string "MMC/SD card detect pin for SPI on sser1"
-       depends on ETRAX_SPI_SSER1 && MMC_SPI
-       default "pd12"
-       help
-         The pin to use for SD/MMC card detect.  This pin should be pulled up
-         and grounded when a card is present.  If defined as " " (space), no
-         pin is selected.  A card must then always be inserted for proper
-         action.
-
-config ETRAX_SPI_MMC_WP_SSER1_PIN
-       string "MMC/SD card write-protect pin for SPI on sser1"
-       depends on ETRAX_SPI_SSER1 && MMC_SPI
-       default "pd9"
-       help
-         The pin to use for the SD/MMC write-protect signal for a memory
-         card.  If defined as " " (space), the card is considered writable.
-
 config ETRAX_SPI_GPIO
        tristate "Bitbanged SPI using gpio pins"
        depends on ETRAX_SPI_MMC
@@ -782,51 +435,4 @@ config ETRAX_SPI_GPIO
          Say m to build it as a module, which will be called spi_crisv32_gpio.
          (You need to select MMC separately.)
 
-# The default match that of sser0, only because that's how it was tested.
-config ETRAX_SPI_CS_PIN
-       string "SPI chip select pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc3"
-       help
-         The pin to use for SPI chip select.
-
-config ETRAX_SPI_CLK_PIN
-       string "SPI clock pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc1"
-       help
-         The pin to use for the SPI clock.
-
-config ETRAX_SPI_DATAIN_PIN
-       string "SPI MISO (data in) pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc16"
-       help
-         The pin to use for SPI data in from the device.
-
-config ETRAX_SPI_DATAOUT_PIN
-       string "SPI MOSI (data out) pin"
-       depends on ETRAX_SPI_GPIO
-       default "pc0"
-       help
-         The pin to use for SPI data out to the device.
-
-config ETRAX_SPI_MMC_CD_GPIO_PIN
-       string "MMC/SD card detect pin for SPI using gpio (space for none)"
-       depends on ETRAX_SPI_GPIO && MMC_SPI
-       default "pd11"
-       help
-         The pin to use for SD/MMC card detect.  This pin should be pulled up
-         and grounded when a card is present.  If defined as " " (space), no
-         pin is selected.  A card must then always be inserted for proper
-         action.
-
-config ETRAX_SPI_MMC_WP_GPIO_PIN
-       string "MMC/SD card write-protect pin for SPI using gpio (space for none)"
-       depends on ETRAX_SPI_GPIO && MMC_SPI
-       default "pd10"
-       help
-         The pin to use for the SD/MMC write-protect signal for a memory
-         card.  If defined as " " (space), the card is considered writable.
-
 endif
index 7796aafc711e6582f006089c86d42ef6592dbcf4..87547271a595fca051e42e998a19f853a50a1a8f 100644 (file)
@@ -15,10 +15,6 @@ config ETRAX_SERIAL_PORTS
        int
        default 5
 
-config ETRAX_DDR
-       bool
-       default y
-
 config ETRAX_DDR2_MRS
        hex "DDR2 MRS"
        default "0"
index c0a29b96b92b032fdcdddb47702e3383724781e8..15b815df29c165809c4e6e229ede6a077d9e8e71 100644 (file)
@@ -47,7 +47,6 @@ struct task_struct;
  */
 
 #define task_pt_regs(task) user_regs(task_thread_info(task))
-#define current_regs() task_pt_regs(current)
 
 unsigned long get_wchan(struct task_struct *p);
 
diff --git a/arch/cris/include/uapi/asm/kvm_para.h b/arch/cris/include/uapi/asm/kvm_para.h
new file mode 100644 (file)
index 0000000..14fab8f
--- /dev/null
@@ -0,0 +1 @@
+#include <asm-generic/kvm_para.h>
index 73312ab6c696c160f7fd58df02a50890390ad650..1790f22e71a21a859b2b7b1942cbbc503c2d557e 100644 (file)
@@ -58,8 +58,7 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
        struct vm_area_struct * vma;
        siginfo_t info;
        int fault;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                               ((writeaccess & 1) ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        D(printk(KERN_DEBUG
                 "Page fault for %lX on %X at %lX, prot %d write %d\n",
@@ -117,6 +116,8 @@ do_page_fault(unsigned long address, struct pt_regs *regs,
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -155,6 +156,7 @@ retry:
        } else if (writeaccess == 1) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
index 4b6628ea381e45be866e571683b38cf1d45a5177..34aa19352dc1ab87cc2cf11f38e1161dc547a518 100644 (file)
@@ -5,7 +5,6 @@ config FRV
        select HAVE_ARCH_TRACEHOOK
        select HAVE_PERF_EVENTS
        select HAVE_UID16
-       select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_SHOW
        select HAVE_DEBUG_BUGVERBOSE
index 331c1e2cfb6760ee7ed3f38d4e5c92a2526d44bf..9a66372fc7c76019ca874a9c3780c2fc8392266c 100644 (file)
@@ -34,11 +34,11 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
        struct vm_area_struct *vma;
        struct mm_struct *mm;
        unsigned long _pme, lrai, lrad, fixup;
+       unsigned long flags = 0;
        siginfo_t info;
        pgd_t *pge;
        pud_t *pue;
        pte_t *pte;
-       int write;
        int fault;
 
 #if 0
@@ -81,6 +81,9 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(__frame))
+               flags |= FAULT_FLAG_USER;
+
        down_read(&mm->mmap_sem);
 
        vma = find_vma(mm, ear0);
@@ -129,7 +132,6 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
  */
  good_area:
        info.si_code = SEGV_ACCERR;
-       write = 0;
        switch (esr0 & ESR0_ATXC) {
        default:
                /* handle write to write protected page */
@@ -140,7 +142,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
 #endif
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
-               write = 1;
+               flags |= FAULT_FLAG_WRITE;
                break;
 
                 /* handle read from protected page */
@@ -162,7 +164,7 @@ asmlinkage void do_page_fault(int datammu, unsigned long esr0, unsigned long ear
         * make sure we exit gracefully rather than endlessly redo
         * the fault.
         */
-       fault = handle_mm_fault(mm, vma, ear0, write ? FAULT_FLAG_WRITE : 0);
+       fault = handle_mm_fault(mm, vma, ear0, flags);
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
index 3d6759ee382f2721e29fd5a44f9c06e937fd7e3b..24b1dc2564f1676272c0e230eeda1e7c0d78d9d6 100644 (file)
@@ -2,7 +2,6 @@ config H8300
        bool
        default y
        select HAVE_IDE
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_ATOMIC64
        select HAVE_UID16
        select VIRT_TO_BUS
index 77d442ab28c8625860c1787df12ac9dd74d7f004..99041b07e61094d964fd1289481c11f739407d04 100644 (file)
@@ -15,7 +15,6 @@ config HEXAGON
        # select GENERIC_PENDING_IRQ if SMP
        select GENERIC_ATOMIC64
        select HAVE_PERF_EVENTS
-       select HAVE_GENERIC_HARDIRQS
        # GENERIC_ALLOCATOR is used by dma_alloc_coherent()
        select GENERIC_ALLOCATOR
        select GENERIC_IRQ_SHOW
index 1bd276dbec7d3503f92a19fc7cb5a39df1051621..8704c9320032705cf7de10d6a94f3c4d70cf8b12 100644 (file)
@@ -53,8 +53,7 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
        int si_code = SEGV_MAPERR;
        int fault;
        const struct exception_table_entry *fixup;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                                (cause > 0 ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        /*
         * If we're in an interrupt or have no user context,
@@ -65,6 +64,8 @@ void do_page_fault(unsigned long address, long cause, struct pt_regs *regs)
 
        local_irq_enable();
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -96,6 +97,7 @@ good_area:
        case FLT_STORE:
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
                break;
        }
 
index a86a56d9e73f9512d45c7904f45a8ab45363448f..7740ab10a17192cb0596d0ee442282d549b3ba33 100644 (file)
@@ -21,7 +21,6 @@ config IA64
        select HAVE_KVM
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select HAVE_VIRT_CPU_ACCOUNTING
index 6cf0341f978e59ddf235c44e70dcf615799390ed..7225dad87094d81e89459e5a61909fa5b2d10ca0 100644 (file)
@@ -90,8 +90,6 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        mask = ((((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT)
                | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT));
 
-       flags |= ((mask & VM_WRITE) ? FAULT_FLAG_WRITE : 0);
-
        /* mmap_sem is performance critical.... */
        prefetchw(&mm->mmap_sem);
 
@@ -119,6 +117,10 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
        if (notify_page_fault(regs, TRAP_BRKPT))
                return;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+       if (mask & VM_WRITE)
+               flags |= FAULT_FLAG_WRITE;
 retry:
        down_read(&mm->mmap_sem);
 
index 76069c18ee42c186edf37c680ee78249d553b4fc..68232db98baa74856752a86fc63cc12678e76787 100644 (file)
@@ -114,6 +114,11 @@ int pud_huge(pud_t pud)
        return 0;
 }
 
+int pmd_huge_support(void)
+{
+       return 0;
+}
+
 struct page *
 follow_huge_pmd(struct mm_struct *mm, unsigned long address, pmd_t *pmd, int write)
 {
index 29a7ef4e448b06d2ae8bd9aa0aa1a2fa5f901802..75661fbf4529e6c903fcb2bb61e3b48e5656fd04 100644 (file)
@@ -9,7 +9,6 @@ config M32R
        select HAVE_KERNEL_LZMA
        select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_DEBUG_BUGVERBOSE
-       select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index 3cdfa9c1d0915b71969c0943b27da64e64156d53..e9c6a8014bd647eec50a66afb5bc75b076b35e4d 100644 (file)
@@ -78,7 +78,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
        struct mm_struct *mm;
        struct vm_area_struct * vma;
        unsigned long page, addr;
-       int write;
+       unsigned long flags = 0;
        int fault;
        siginfo_t info;
 
@@ -117,6 +117,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
        if (in_atomic() || !mm)
                goto bad_area_nosemaphore;
 
+       if (error_code & ACE_USERMODE)
+               flags |= FAULT_FLAG_USER;
+
        /* When running in the kernel we expect faults to occur only to
         * addresses in user space.  All other faults represent errors in the
         * kernel and should generate an OOPS.  Unfortunately, in the case of an
@@ -166,14 +169,13 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code,
  */
 good_area:
        info.si_code = SEGV_ACCERR;
-       write = 0;
        switch (error_code & (ACE_WRITE|ACE_PROTECTION)) {
                default:        /* 3: write, present */
                        /* fall through */
                case ACE_WRITE: /* write, not present */
                        if (!(vma->vm_flags & VM_WRITE))
                                goto bad_area;
-                       write++;
+                       flags |= FAULT_FLAG_WRITE;
                        break;
                case ACE_PROTECTION:    /* read, present */
                case 0:         /* read, not present */
@@ -194,7 +196,7 @@ good_area:
         */
        addr = (address & PAGE_MASK);
        set_thread_fault_code(error_code);
-       fault = handle_mm_fault(mm, vma, addr, write ? FAULT_FLAG_WRITE : 0);
+       fault = handle_mm_fault(mm, vma, addr, flags);
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
index 821170e5f6ed4e29e2135af409258d60d7fb4b4f..311a300d48cca82b82a5faa0bf6abbaee42cacef 100644 (file)
@@ -4,13 +4,13 @@ config M68K
        select HAVE_IDE
        select HAVE_AOUT if MMU
        select HAVE_DEBUG_BUGVERBOSE
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select GENERIC_ATOMIC64
        select HAVE_UID16
        select VIRT_TO_BUS
        select ARCH_HAVE_NMI_SAFE_CMPXCHG if RMW_INSNS
        select GENERIC_CPU_DEVICES
+       select GENERIC_IOMAP
        select GENERIC_STRNCPY_FROM_USER if MMU
        select GENERIC_STRNLEN_USER if MMU
        select FPU if MMU
@@ -72,7 +72,6 @@ source "kernel/Kconfig.freezer"
 config MMU
        bool "MMU-based Paged Memory Management Support"
        default y
-       select GENERIC_IOMAP
        help
          Select if you want MMU-based virtualised addressing space
          support by paged memory management. If unsure, say 'Y'.
index b9ab0a69561cac3de87657e06700f8c0cf456413..61dc643c0b05ca458d3a6370756ec9d4cd72771e 100644 (file)
@@ -150,18 +150,6 @@ config XCOPILOT_BUGS
        help
          Support the bugs of Xcopilot.
 
-config UC5272
-       bool "Arcturus Networks uC5272 dimm board support"
-       depends on M5272
-       help
-         Support for the Arcturus Networks uC5272 dimm board.
-
-config UC5282
-       bool "Arcturus Networks uC5282 board support"
-       depends on M528x
-       help
-         Support for the Arcturus Networks uC5282 dimm board.
-
 config UCSIMM
        bool "uCsimm module support"
        depends on M68EZ328
@@ -205,23 +193,15 @@ config UCQUICC
        help
          Support for the Lineo uCquicc board.
 
-config ARNEWSH
-       bool
-
 config ARN5206
        bool "Arnewsh 5206 board support"
        depends on M5206
-       select ARNEWSH
        help
          Support for the Arnewsh 5206 board.
 
-config FREESCALE
-       bool
-
 config M5206eC3
        bool "Motorola M5206eC3 board support"
        depends on M5206e
-       select FREESCALE
        help
          Support for the Motorola M5206eC3 board.
 
@@ -231,88 +211,24 @@ config ELITE
        help
          Support for the Motorola M5206eLITE board.
 
-config M5208EVB
-       bool "Freescale M5208EVB board support"
-       depends on M520x
-       select FREESCALE
-       help
-         Support for the Freescale Coldfire M5208EVB.
-
 config M5235EVB
        bool "Freescale M5235EVB support"
        depends on M523x
-       select FREESCALE
        help
          Support for the Freescale M5235EVB board.
 
 config M5249C3
        bool "Motorola M5249C3 board support"
        depends on M5249
-       select FREESCALE
        help
          Support for the Motorola M5249C3 board.
 
-config M5271EVB
-       bool "Freescale (Motorola) M5271EVB board support"
-       depends on M5271
-       select FREESCALE
-       help
-         Support for the Freescale (Motorola) M5271EVB board.
-
-config M5275EVB
-       bool "Freescale (Motorola) M5275EVB board support"
-       depends on M5275
-       select FREESCALE
-       help
-         Support for the Freescale (Motorola) M5275EVB board.
-
 config M5272C3
        bool "Motorola M5272C3 board support"
        depends on M5272
-       select FREESCALE
        help
          Support for the Motorola M5272C3 board.
 
-config senTec
-       bool
-
-config COBRA5272
-       bool "senTec COBRA5272 board support"
-       depends on M5272
-       select senTec
-       help
-         Support for the senTec COBRA5272 board.
-
-config AVNET
-       bool
-
-config AVNET5282
-       bool "Avnet 5282 board support"
-       depends on M528x
-       select AVNET
-       help
-         Support for the Avnet 5282 board.
-
-config M5282EVB
-       bool "Motorola M5282EVB board support"
-       depends on M528x
-       select FREESCALE
-       help
-         Support for the Motorola M5282EVB board.
-
-config COBRA5282
-       bool "senTec COBRA5282 board support"
-       depends on M528x
-       select senTec
-       help
-         Support for the senTec COBRA5282 board.
-
-config SOM5282EM
-       bool "EMAC.Inc SOM5282EM board support"
-       depends on M528x
-       help
-         Support for the EMAC.Inc SOM5282EM module.
-
 config WILDFIRE
        bool "Intec Automation Inc. WildFire board support"
        depends on M528x
@@ -328,14 +244,12 @@ config WILDFIREMOD
 config ARN5307
        bool "Arnewsh 5307 board support"
        depends on M5307
-       select ARNEWSH
        help
          Support for the Arnewsh 5307 board.
 
 config M5307C3
        bool "Motorola M5307C3 board support"
        depends on M5307
-       select FREESCALE
        help
          Support for the Motorola M5307C3 board.
 
@@ -345,30 +259,9 @@ config SECUREEDGEMP3
        help
          Support for the SnapGear SecureEdge/MP3 platform.
 
-config M5329EVB
-       bool "Freescale (Motorola) M5329EVB board support"
-       depends on M532x
-       select FREESCALE
-       help
-         Support for the Freescale (Motorola) M5329EVB board.
-
-config COBRA5329
-       bool "senTec COBRA5329 board support"
-       depends on M532x
-       help
-         Support for the senTec COBRA5329 board.
-
-config M5373EVB
-       bool "Freescale M5373EVB board support"
-       depends on M537x
-       select FREESCALE
-       help
-         Support for the Freescale M5373EVB board.
-
 config M5407C3
        bool "Motorola M5407C3 board support"
        depends on M5407
-       select FREESCALE
        help
          Support for the Motorola M5407C3 board.
 
@@ -402,39 +295,12 @@ config NETtel
        help
          Support for the SnapGear NETtel/SecureEdge/SnapGear boards.
 
-config SNAPGEAR
-       bool "SnapGear router board support"
-       depends on NETtel
-       help
-         Special additional support for SnapGear router boards.
-
-config SNEHA
-       bool
-
-config CPU16B
-       bool "Sneha Technologies S.L. Sarasvati board support"
-       depends on M5272
-       select SNEHA
-       help
-         Support for the SNEHA CPU16B board.
-
 config MOD5272
        bool "Netburner MOD-5272 board support"
        depends on M5272
        help
          Support for the Netburner MOD-5272 board.
 
-config SAVANT
-       bool
-
-config SAVANTrosie1
-       bool "Savant Rosie1 board support"
-       depends on M523x
-       select SAVANT
-       help
-         Support for the Savant Rosie1 board.
-
-
 if !MMU || COLDFIRE
 
 comment "Machine Options"
index 353bf754a9725a490e12eb9528555d256fd797fd..e1534783e94e5f1c7d47e7fb713bcace07bf080f 100644 (file)
@@ -4,6 +4,7 @@
 #ifdef __KERNEL__
 
 #include <asm/virtconvert.h>
+#include <asm-generic/iomap.h>
 
 /*
  * These are for ISA/PCI shared memory _only_ and should never be used
index 7c360dac00b7e39bf7b3336e16810962374575b2..38b024a0b0451ba7a934ea5d4f5563411d406b6d 100644 (file)
@@ -48,6 +48,9 @@ extern unsigned long _ramend;
 #include <asm/page_no.h>
 #endif
 
+#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
+                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
 #include <asm-generic/getorder.h>
 
 #endif /* _M68K_PAGE_H */
index 89f201434b5aa2575a5837bc6730346e06cc7e30..5029f73e6294763239b7f1766ad073e29b273520 100644 (file)
@@ -173,7 +173,4 @@ static inline __attribute_const__ int __virt_to_node_shift(void)
 
 #endif /* __ASSEMBLY__ */
 
-#define VM_DATA_DEFAULT_FLAGS  (VM_READ | VM_WRITE | VM_EXEC | \
-                                VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
 #endif /* _M68K_PAGE_MM_H */
index 911ba472e6c4abbd83dac862a561d98eb22526aa..5b16f5d61b44cb4f2cbcb7372d4f98061bef6da0 100644 (file)
@@ -118,7 +118,7 @@ void (*mach_power_off)(void);
  *
  * Returns:
  */
-void parse_uboot_commandline(char *commandp, int size)
+static void __init parse_uboot_commandline(char *commandp, int size)
 {
        extern unsigned long _init_sp;
        unsigned long *sp;
index 2a16df3d931283f0f55ac4c95571dbe3629678c3..57fd286e4b0b410fe93cb0596c93488afa8b4b4e 100644 (file)
@@ -50,6 +50,7 @@
 #include <asm/pgtable.h>
 #include <asm/traps.h>
 #include <asm/ucontext.h>
+#include <asm/cacheflush.h>
 
 #ifdef CONFIG_MMU
 
@@ -181,6 +182,13 @@ static inline void push_cache (unsigned long vaddr)
                asm volatile ("movec %0,%%caar\n\t"
                              "movec %1,%%cacr"
                              : : "r" (vaddr + 4), "r" (temp));
+       } else {
+               /* CPU_IS_COLDFIRE */
+#if defined(CONFIG_CACHE_COPYBACK)
+               flush_cf_dcache(0, DCACHE_MAX_ADDR);
+#endif
+               /* Invalidate instruction cache for the pushed bytes */
+               clear_cf_icache(vaddr, vaddr + 8);
        }
 }
 
index a563727806bf922b5b3315559b9b46b5bbb9d7fc..eb1d61f6872549991dae7d5e491a74627d8456d0 100644 (file)
@@ -88,6 +88,8 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
 
index a86eb66835aaaf11b7125960987a44ea9c84941d..e53caf4c3bfbf9d141e1f49857ce08f8da785cc2 100644 (file)
@@ -15,6 +15,7 @@
 
 /***************************************************************************/
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/rtc.h>
@@ -42,7 +43,7 @@ void m68328_reset (void)
 
 /***************************************************************************/
 
-void config_BSP(char *command, int len)
+void __init config_BSP(char *command, int len)
 {
   printk(KERN_INFO "\n68328 support D. Jeff Dionne <jeff@uclinux.org>\n");
   printk(KERN_INFO "68328 support Kenneth Albanowski <kjahds@kjshds.com>\n");
index a6eb72d750084f9a19dae6a6d43a80724a8a9d7f..332b5e8605fcdf2d81772babc7b54bde55dd802d 100644 (file)
@@ -13,6 +13,7 @@
 
 /***************************************************************************/
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/rtc.h>
@@ -52,7 +53,7 @@ _bsc1(unsigned char *, gethwaddr, int, a)
 _bsc1(char *, getbenv, char *, a)
 #endif
 
-void config_BSP(char *command, int len)
+void __init config_BSP(char *command, int len)
 {
   unsigned char *p;
 
index eb6964fbec09a7f703702b2f8219d5c27f85e564..fd6658358af1aa00c95848bf62f7aed8cf8d15c6 100644 (file)
@@ -14,6 +14,7 @@
 
 /***************************************************************************/
 
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/kd.h>
@@ -59,7 +60,7 @@ static void m68vz328_reset(void)
        );
 }
 
-static void init_hardware(char *command, int size)
+static void __init init_hardware(char *command, int size)
 {
 #ifdef CONFIG_DIRECT_IO_ACCESS
        SCR = 0x10;                                     /* allow user access to internal registers */
@@ -145,7 +146,7 @@ _bsc0(char *, getserialnum)
 _bsc1(unsigned char *, gethwaddr, int, a)
 _bsc1(char *, getbenv, char *, a)
 
-static void init_hardware(char *command, int size)
+static void __init init_hardware(char *command, int size)
 {
        char *p;
 
@@ -167,7 +168,7 @@ static void m68vz328_reset(void)
 {
 }
 
-static void init_hardware(char *command, int size)
+static void __init init_hardware(char *command, int size)
 {
 }
 
@@ -175,7 +176,7 @@ static void init_hardware(char *command, int size)
 #endif
 /***************************************************************************/
 
-void config_BSP(char *command, int size)
+void __init config_BSP(char *command, int size)
 {
        printk(KERN_INFO "68VZ328 DragonBallVZ support (c) 2001 Lineo, Inc.\n");
 
index 8e4e10cc00803387b8386afdb0fe8c655f37a356..315727b7ff40f4170cc05e5d432bd4542dd1102f 100644 (file)
@@ -31,6 +31,7 @@
  */
 
 #include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/param.h>
@@ -77,7 +78,7 @@ void m360_cpm_reset(void);
 
 
 
-void m360_cpm_reset()
+void __init m360_cpm_reset()
 {
 /*     pte_t              *pte; */
 
index 9877cefad1e7640dd27622410c04f882acdb37e3..0570741e5500b221003e3295f4596673cfa53b4b 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <stdarg.h>
+#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
@@ -140,7 +141,7 @@ _bsc1(char *, getbenv, char *, a)
 #endif
 
 
-void config_BSP(char *command, int len)
+void __init config_BSP(char *command, int len)
 {
   unsigned char *p;
 
index cfd831c2982424fb305671993ce5bd99cfcb1453..36368eb07e13fe629d00ac1f1fdcc8ff06220ba2 100644 (file)
@@ -13,7 +13,6 @@ config METAG
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZO
index 2a3c860c75250c15bc5bcf8c4c9532aa2772e2de..973640f46752f0247c75de8f5940c3005b23841b 100644 (file)
@@ -16,6 +16,8 @@ config META21_FPGA
 
 config SOC_TZ1090
        bool "Toumaz Xenif TZ1090 SoC (Comet)"
+       select ARCH_WANT_OPTIONAL_GPIOLIB
+       select IMGPDC_IRQ
        select METAG_LNKGET_AROUND_CACHE
        select METAG_META21
        select METAG_SMP_WRITE_REORDERING
index 853744652b93460875cc9a36caf2fad3fc3953b5..24ea7d2e9138032c713088e70f5175cfa26155a4 100644 (file)
@@ -8,6 +8,8 @@
 
 #include "skeleton.dtsi"
 
+#include <dt-bindings/interrupt-controller/irq.h>
+
 / {
        compatible = "toumaz,tz1090", "img,meta";
 
                #size-cells = <1>;
                ranges;
 
+               pdc: pdc@0x02006000 {
+                       interrupt-controller;
+                       #interrupt-cells = <2>;
+
+                       reg = <0x02006000 0x1000>;
+                       compatible = "img,pdc-intc";
+
+                       num-perips = <3>;
+                       num-syswakes = <3>;
+
+                       interrupts = <18 IRQ_TYPE_LEVEL_HIGH>, /* Syswakes */
+                                    <30 IRQ_TYPE_LEVEL_HIGH>, /* Perip 0 (RTC) */
+                                    <29 IRQ_TYPE_LEVEL_HIGH>, /* Perip 1 (IR) */
+                                    <31 IRQ_TYPE_LEVEL_HIGH>; /* Perip 2 (WDT) */
+               };
+
                pinctrl: pinctrl@02005800 {
                        #gpio-range-cells = <3>;
                        compatible = "img,tz1090-pinctrl";
                        compatible = "img,tz1090-pdc-pinctrl";
                        reg = <0x02006500 0x100>;
                };
+
+               gpios: gpios@02005800 {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       compatible = "img,tz1090-gpio";
+                       reg = <0x02005800 0x90>;
+
+                       gpios0: bank@0 {
+                               gpio-controller;
+                               interrupt-controller;
+                               #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
+                               reg = <0>;
+                               interrupts = <13 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 0 30>;
+                       };
+                       gpios1: bank@1 {
+                               gpio-controller;
+                               interrupt-controller;
+                               #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
+                               reg = <1>;
+                               interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 30 30>;
+                       };
+                       gpios2: bank@2 {
+                               gpio-controller;
+                               interrupt-controller;
+                               #gpio-cells = <2>;
+                               #interrupt-cells = <2>;
+                               reg = <2>;
+                               interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
+                               gpio-ranges = <&pinctrl 0 60 30>;
+                       };
+               };
+
+               pdc_gpios: gpios@02006500 {
+                       gpio-controller;
+                       #gpio-cells = <2>;
+
+                       compatible = "img,tz1090-pdc-gpio";
+                       reg = <0x02006500 0x100>;
+
+                       interrupt-parent = <&pdc>;
+                       interrupts =    <8  IRQ_TYPE_NONE>,
+                                       <9  IRQ_TYPE_NONE>,
+                                       <10 IRQ_TYPE_NONE>;
+                       gpio-ranges = <&pdc_pinctrl 0 0 7>;
+               };
        };
 };
index 8fddf46e6c62f3d7570a65d5d0034a185e46985e..332680e5ebf23c7909b796c415c2273efd77ba3c 100644 (file)
@@ -53,8 +53,7 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
        struct vm_area_struct *vma, *prev_vma;
        siginfo_t info;
        int fault;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                               (write_access ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        tsk = current;
 
@@ -109,6 +108,8 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
 
@@ -121,6 +122,7 @@ good_area:
        if (write_access) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
                        goto bad_area;
index 3c52fa6d0f8e24030294fecacc26498f5de9ffe5..042431509b5664bca9bc6c930b296c77a064079a 100644 (file)
@@ -110,6 +110,11 @@ int pud_huge(pud_t pud)
        return 0;
 }
 
+int pmd_huge_support(void)
+{
+       return 1;
+}
+
 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
                             pmd_t *pmd, int write)
 {
index 28813f164730f7110ccf470d6ef610932f166580..123919534b80fe3724612b61697441305d5b10a6 100644 (file)
@@ -407,10 +407,9 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 #endif
 
 #ifdef CONFIG_OF_FLATTREE
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
-       pr_err("%s(%lx, %lx)\n",
+       pr_err("%s(%llx, %llx)\n",
               __func__, start, end);
 }
 #endif /* CONFIG_OF_FLATTREE */
index 3f6659cbc969134e14f8a5500a8bc119368a2d7f..b82f82b743199ac4ff5b54d8cdbe6cc8c1246078 100644 (file)
@@ -18,7 +18,6 @@ config MICROBLAZE
        select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_DEBUG_KMEMLEAK
        select IRQ_DOMAIN
-       select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index 0a2c68f9f9b0d61cf14e3f28de7ef23d87adcced..0c4453f134cbb7daf0f615002d8841ccd79957a0 100644 (file)
@@ -46,11 +46,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        memblock_add(base, size);
 }
 
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-{
-       return __va(memblock_alloc(size, align));
-}
-
 #ifdef CONFIG_EARLY_PRINTK
 static char *stdout;
 
@@ -136,8 +131,7 @@ void __init early_init_devtree(void *params)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 731f739d17a1be6c485a7759f9479adc592377d1..fa4cf52aa7a6d386711690005a314ece7d67fc53 100644 (file)
@@ -92,8 +92,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
        int code = SEGV_MAPERR;
        int is_write = error_code & ESR_S;
        int fault;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                                        (is_write ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        regs->ear = address;
        regs->esr = error_code;
@@ -121,6 +120,9 @@ void do_page_fault(struct pt_regs *regs, unsigned long address,
                die("Weird page fault", regs, SIGSEGV);
        }
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+
        /* When running in the kernel we expect faults to occur only to
         * addresses in user space.  All other faults represent errors in the
         * kernel and should generate an OOPS.  Unfortunately, in the case of an
@@ -199,6 +201,7 @@ good_area:
        if (unlikely(is_write)) {
                if (unlikely(!(vma->vm_flags & VM_WRITE)))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        /* a read */
        } else {
                /* protection fault */
index 71f15e73bc89027697426d0a709cd15f9fbcba19..f75ab4a2f2460a0d5652cbcacf25c2b68a2d24c3 100644 (file)
@@ -25,7 +25,6 @@ config MIPS
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
        select GENERIC_PCI_IOMAP
@@ -95,6 +94,7 @@ config ATH79
        select CSRC_R4K
        select DMA_NONCOHERENT
        select HAVE_CLK
+       select CLKDEV_LOOKUP
        select IRQ_CPU
        select MIPS_MACHINE
        select SYS_HAS_CPU_MIPS32_R2
@@ -131,7 +131,6 @@ config BCM63XX
        select IRQ_CPU
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_CPU_BMIPS4350 if !BCM63XX_CPU_6338 && !BCM63XX_CPU_6345 && !BCM63XX_CPU_6348
-       select NR_CPUS_DEFAULT_2
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_HAS_EARLY_PRINTK
@@ -445,6 +444,8 @@ config RALINK
        select SYS_HAS_EARLY_PRINTK
        select HAVE_MACH_CLKDEV
        select CLKDEV_LOOKUP
+       select ARCH_HAS_RESET_CONTROLLER
+       select RESET_CONTROLLER
 
 config SGI_IP22
        bool "SGI IP22 (Indy/Indigo2)"
@@ -609,7 +610,6 @@ config SIBYTE_SWARM
        select BOOT_ELF32
        select DMA_COHERENT
        select HAVE_PATA_PLATFORM
-       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -623,7 +623,6 @@ config SIBYTE_LITTLESUR
        select BOOT_ELF32
        select DMA_COHERENT
        select HAVE_PATA_PLATFORM
-       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -635,7 +634,6 @@ config SIBYTE_SENTOSA
        bool "Sibyte BCM91250E-Sentosa"
        select BOOT_ELF32
        select DMA_COHERENT
-       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -731,6 +729,7 @@ config CAVIUM_OCTEON_SOC
        select USB_ARCH_HAS_OHCI
        select USB_ARCH_HAS_EHCI
        select HOLES_IN_ZONE
+       select ARCH_REQUIRE_GPIOLIB
        help
          This option supports all of the Octeon reference boards from Cavium
          Networks. It builds a kernel that dynamically determines the Octeon
@@ -1860,7 +1859,6 @@ config MIPS_MT_SMP
        select CPU_MIPSR2_IRQ_VI
        select CPU_MIPSR2_IRQ_EI
        select MIPS_MT
-       select NR_CPUS_DEFAULT_2
        select SMP
        select SYS_SUPPORTS_SCHED_SMT if SMP
        select SYS_SUPPORTS_SMP
@@ -2171,12 +2169,6 @@ config SYS_SUPPORTS_MIPS_CMP
 config SYS_SUPPORTS_SMP
        bool
 
-config NR_CPUS_DEFAULT_1
-       bool
-
-config NR_CPUS_DEFAULT_2
-       bool
-
 config NR_CPUS_DEFAULT_4
        bool
 
@@ -2194,10 +2186,8 @@ config NR_CPUS_DEFAULT_64
 
 config NR_CPUS
        int "Maximum number of CPUs (2-64)"
-       range 1 64 if NR_CPUS_DEFAULT_1
+       range 2 64
        depends on SMP
-       default "1" if NR_CPUS_DEFAULT_1
-       default "2" if NR_CPUS_DEFAULT_2
        default "4" if NR_CPUS_DEFAULT_4
        default "8" if NR_CPUS_DEFAULT_8
        default "16" if NR_CPUS_DEFAULT_16
index 37f9ef324f2fdea6568f93d2f4d2d12f5f2fc4a4..ca8f8340d75f535b1cad5c1c8eed14bbc71f9634 100644 (file)
@@ -194,6 +194,8 @@ include $(srctree)/arch/mips/Kbuild.platforms
 ifdef CONFIG_PHYSICAL_START
 load-y                                 = $(CONFIG_PHYSICAL_START)
 endif
+entry-y                                = 0x$(shell $(NM) vmlinux 2>/dev/null \
+                                       | grep "\bkernel_entry\b" | cut -f1 -d \ )
 
 cflags-y                       += -I$(srctree)/arch/mips/include/asm/mach-generic
 drivers-$(CONFIG_PCI)          += arch/mips/pci/
@@ -225,6 +227,9 @@ KBUILD_CFLAGS       += $(cflags-y)
 KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y)
 KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0)
 
+bootvars-y     = VMLINUX_LOAD_ADDRESS=$(load-y) \
+                 VMLINUX_ENTRY_ADDRESS=$(entry-y)
+
 LDFLAGS                        += -m $(ld-emul)
 
 ifdef CONFIG_CC_STACKPROTECTOR
@@ -254,9 +259,25 @@ drivers-$(CONFIG_OPROFILE) += arch/mips/oprofile/
 # suspend and hibernation support
 drivers-$(CONFIG_PM)   += arch/mips/power/
 
+# boot image targets (arch/mips/boot/)
+boot-y                 := vmlinux.bin
+boot-y                 += vmlinux.ecoff
+boot-y                 += vmlinux.srec
+ifeq ($(shell expr $(load-y) \< 0xffffffff80000000 2> /dev/null), 0)
+boot-y                 += uImage
+boot-y                 += uImage.gz
+endif
+
+# compressed boot image targets (arch/mips/boot/compressed/)
+bootz-y                        := vmlinuz
+bootz-y                        += vmlinuz.bin
+bootz-y                        += vmlinuz.ecoff
+bootz-y                        += vmlinuz.srec
+
 ifdef CONFIG_LASAT
 rom.bin rom.sw: vmlinux
-       $(Q)$(MAKE) $(build)=arch/mips/lasat/image $@
+       $(Q)$(MAKE) $(build)=arch/mips/lasat/image \
+               $(bootvars-y) $@
 endif
 
 #
@@ -267,9 +288,6 @@ endif
 vmlinux.32: vmlinux
        $(OBJCOPY) -O $(32bit-bfd) $(OBJCOPYFLAGS) $< $@
 
-
-#obj-$(CONFIG_KPROBES)         += kprobes.o
-
 #
 # The 64-bit ELF tools are pretty broken so at this time we generate 64-bit
 # ELF files from 32-bit files by conversion.
@@ -280,13 +298,14 @@ vmlinux.64: vmlinux
 all:   $(all-y)
 
 # boot
-vmlinux.bin vmlinux.ecoff vmlinux.srec: $(vmlinux-32) FORCE
-       $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) arch/mips/boot/$@
+$(boot-y): $(vmlinux-32) FORCE
+       $(Q)$(MAKE) $(build)=arch/mips/boot VMLINUX=$(vmlinux-32) \
+               $(bootvars-y) arch/mips/boot/$@
 
 # boot/compressed
-vmlinuz vmlinuz.bin vmlinuz.ecoff vmlinuz.srec: $(vmlinux-32) FORCE
+$(bootz-y): $(vmlinux-32) FORCE
        $(Q)$(MAKE) $(build)=arch/mips/boot/compressed \
-          VMLINUX_LOAD_ADDRESS=$(load-y) 32bit-bfd=$(32bit-bfd) $@
+               $(bootvars-y) 32bit-bfd=$(32bit-bfd) $@
 
 
 CLEAN_FILES += vmlinux.32 vmlinux.64
@@ -323,6 +342,8 @@ define archhelp
        echo '  vmlinuz.ecoff        - ECOFF zboot image'
        echo '  vmlinuz.bin          - Raw binary zboot image'
        echo '  vmlinuz.srec         - SREC zboot image'
+       echo '  uImage               - U-Boot image'
+       echo '  uImage.gz            - U-Boot image (gzip)'
        echo
        echo '  These will be default as appropriate for a configured platform.'
 endef
index fcc69562611716957cdec6b268ff36dac49f0664..2adc7edda49c931a9930b7c54fbbe6f749f47d7c 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/syscore_ops.h>
+#include <asm/cpu.h>
 #include <asm/mach-au1x00/au1000.h>
 
 /* control register offsets */
@@ -358,7 +359,7 @@ static inline int au1200_coherency_bug(void)
 {
 #if defined(CONFIG_DMA_COHERENT)
        /* Au1200 AB USB does not support coherent memory */
-       if (!(read_c0_prid() & 0xff)) {
+       if (!(read_c0_prid() & PRID_REV_MASK)) {
                printk(KERN_INFO "Au1200 USB: this is chip revision AB !!\n");
                printk(KERN_INFO "Au1200 USB: update your board or re-configure"
                                 " the kernel\n");
index 765ef30e3e1c470d0d4ed69740718113b838daf8..26479f437675164c080c4fa1f98f080d8bedc72e 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/clkdev.h>
 
 #include <asm/div64.h>
 
@@ -31,92 +32,132 @@ struct clk {
        unsigned long rate;
 };
 
-static struct clk ath79_ref_clk;
-static struct clk ath79_cpu_clk;
-static struct clk ath79_ddr_clk;
-static struct clk ath79_ahb_clk;
-static struct clk ath79_wdt_clk;
-static struct clk ath79_uart_clk;
+static void __init ath79_add_sys_clkdev(const char *id, unsigned long rate)
+{
+       struct clk *clk;
+       int err;
+
+       clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+       if (!clk)
+               panic("failed to allocate %s clock structure", id);
+
+       clk->rate = rate;
+
+       err = clk_register_clkdev(clk, id, NULL);
+       if (err)
+               panic("unable to register %s clock device", id);
+}
 
 static void __init ar71xx_clocks_init(void)
 {
+       unsigned long ref_rate;
+       unsigned long cpu_rate;
+       unsigned long ddr_rate;
+       unsigned long ahb_rate;
        u32 pll;
        u32 freq;
        u32 div;
 
-       ath79_ref_clk.rate = AR71XX_BASE_FREQ;
+       ref_rate = AR71XX_BASE_FREQ;
 
        pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG);
 
        div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1;
-       freq = div * ath79_ref_clk.rate;
+       freq = div * ref_rate;
 
        div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1;
-       ath79_cpu_clk.rate = freq / div;
+       cpu_rate = freq / div;
 
        div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1;
-       ath79_ddr_clk.rate = freq / div;
+       ddr_rate = freq / div;
 
        div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2;
-       ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+       ahb_rate = cpu_rate / div;
+
+       ath79_add_sys_clkdev("ref", ref_rate);
+       ath79_add_sys_clkdev("cpu", cpu_rate);
+       ath79_add_sys_clkdev("ddr", ddr_rate);
+       ath79_add_sys_clkdev("ahb", ahb_rate);
 
-       ath79_wdt_clk.rate = ath79_ahb_clk.rate;
-       ath79_uart_clk.rate = ath79_ahb_clk.rate;
+       clk_add_alias("wdt", NULL, "ahb", NULL);
+       clk_add_alias("uart", NULL, "ahb", NULL);
 }
 
 static void __init ar724x_clocks_init(void)
 {
+       unsigned long ref_rate;
+       unsigned long cpu_rate;
+       unsigned long ddr_rate;
+       unsigned long ahb_rate;
        u32 pll;
        u32 freq;
        u32 div;
 
-       ath79_ref_clk.rate = AR724X_BASE_FREQ;
+       ref_rate = AR724X_BASE_FREQ;
        pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG);
 
        div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK);
-       freq = div * ath79_ref_clk.rate;
+       freq = div * ref_rate;
 
        div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK);
        freq *= div;
 
-       ath79_cpu_clk.rate = freq;
+       cpu_rate = freq;
 
        div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1;
-       ath79_ddr_clk.rate = freq / div;
+       ddr_rate = freq / div;
 
        div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2;
-       ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+       ahb_rate = cpu_rate / div;
+
+       ath79_add_sys_clkdev("ref", ref_rate);
+       ath79_add_sys_clkdev("cpu", cpu_rate);
+       ath79_add_sys_clkdev("ddr", ddr_rate);
+       ath79_add_sys_clkdev("ahb", ahb_rate);
 
-       ath79_wdt_clk.rate = ath79_ahb_clk.rate;
-       ath79_uart_clk.rate = ath79_ahb_clk.rate;
+       clk_add_alias("wdt", NULL, "ahb", NULL);
+       clk_add_alias("uart", NULL, "ahb", NULL);
 }
 
 static void __init ar913x_clocks_init(void)
 {
+       unsigned long ref_rate;
+       unsigned long cpu_rate;
+       unsigned long ddr_rate;
+       unsigned long ahb_rate;
        u32 pll;
        u32 freq;
        u32 div;
 
-       ath79_ref_clk.rate = AR913X_BASE_FREQ;
+       ref_rate = AR913X_BASE_FREQ;
        pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG);
 
        div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK);
-       freq = div * ath79_ref_clk.rate;
+       freq = div * ref_rate;
 
-       ath79_cpu_clk.rate = freq;
+       cpu_rate = freq;
 
        div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1;
-       ath79_ddr_clk.rate = freq / div;
+       ddr_rate = freq / div;
 
        div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2;
-       ath79_ahb_clk.rate = ath79_cpu_clk.rate / div;
+       ahb_rate = cpu_rate / div;
 
-       ath79_wdt_clk.rate = ath79_ahb_clk.rate;
-       ath79_uart_clk.rate = ath79_ahb_clk.rate;
+       ath79_add_sys_clkdev("ref", ref_rate);
+       ath79_add_sys_clkdev("cpu", cpu_rate);
+       ath79_add_sys_clkdev("ddr", ddr_rate);
+       ath79_add_sys_clkdev("ahb", ahb_rate);
+
+       clk_add_alias("wdt", NULL, "ahb", NULL);
+       clk_add_alias("uart", NULL, "ahb", NULL);
 }
 
 static void __init ar933x_clocks_init(void)
 {
+       unsigned long ref_rate;
+       unsigned long cpu_rate;
+       unsigned long ddr_rate;
+       unsigned long ahb_rate;
        u32 clock_ctrl;
        u32 cpu_config;
        u32 freq;
@@ -124,21 +165,21 @@ static void __init ar933x_clocks_init(void)
 
        t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP);
        if (t & AR933X_BOOTSTRAP_REF_CLK_40)
-               ath79_ref_clk.rate = (40 * 1000 * 1000);
+               ref_rate = (40 * 1000 * 1000);
        else
-               ath79_ref_clk.rate = (25 * 1000 * 1000);
+               ref_rate = (25 * 1000 * 1000);
 
        clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG);
        if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) {
-               ath79_cpu_clk.rate = ath79_ref_clk.rate;
-               ath79_ahb_clk.rate = ath79_ref_clk.rate;
-               ath79_ddr_clk.rate = ath79_ref_clk.rate;
+               cpu_rate = ref_rate;
+               ahb_rate = ref_rate;
+               ddr_rate = ref_rate;
        } else {
                cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG);
 
                t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
                    AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
-               freq = ath79_ref_clk.rate / t;
+               freq = ref_rate / t;
 
                t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) &
                    AR933X_PLL_CPU_CONFIG_NINT_MASK;
@@ -153,19 +194,24 @@ static void __init ar933x_clocks_init(void)
 
                t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) &
                     AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1;
-               ath79_cpu_clk.rate = freq / t;
+               cpu_rate = freq / t;
 
                t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) &
                      AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1;
-               ath79_ddr_clk.rate = freq / t;
+               ddr_rate = freq / t;
 
                t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) &
                     AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1;
-               ath79_ahb_clk.rate = freq / t;
+               ahb_rate = freq / t;
        }
 
-       ath79_wdt_clk.rate = ath79_ref_clk.rate;
-       ath79_uart_clk.rate = ath79_ref_clk.rate;
+       ath79_add_sys_clkdev("ref", ref_rate);
+       ath79_add_sys_clkdev("cpu", cpu_rate);
+       ath79_add_sys_clkdev("ddr", ddr_rate);
+       ath79_add_sys_clkdev("ahb", ahb_rate);
+
+       clk_add_alias("wdt", NULL, "ahb", NULL);
+       clk_add_alias("uart", NULL, "ref", NULL);
 }
 
 static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
@@ -174,12 +220,12 @@ static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
        u64 t;
        u32 ret;
 
-       t = ath79_ref_clk.rate;
+       t = ref;
        t *= nint;
        do_div(t, ref_div);
        ret = t;
 
-       t = ath79_ref_clk.rate;
+       t = ref;
        t *= nfrac;
        do_div(t, ref_div * frac);
        ret += t;
@@ -190,6 +236,10 @@ static u32 __init ar934x_get_pll_freq(u32 ref, u32 ref_div, u32 nint, u32 nfrac,
 
 static void __init ar934x_clocks_init(void)
 {
+       unsigned long ref_rate;
+       unsigned long cpu_rate;
+       unsigned long ddr_rate;
+       unsigned long ahb_rate;
        u32 pll, out_div, ref_div, nint, nfrac, frac, clk_ctrl, postdiv;
        u32 cpu_pll, ddr_pll;
        u32 bootstrap;
@@ -199,9 +249,9 @@ static void __init ar934x_clocks_init(void)
 
        bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP);
        if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40)
-               ath79_ref_clk.rate = 40 * 1000 * 1000;
+               ref_rate = 40 * 1000 * 1000;
        else
-               ath79_ref_clk.rate = 25 * 1000 * 1000;
+               ref_rate = 25 * 1000 * 1000;
 
        pll = __raw_readl(dpll_base + AR934X_SRIF_CPU_DPLL2_REG);
        if (pll & AR934X_SRIF_DPLL2_LOCAL_PLL) {
@@ -227,7 +277,7 @@ static void __init ar934x_clocks_init(void)
                frac = 1 << 6;
        }
 
-       cpu_pll = ar934x_get_pll_freq(ath79_ref_clk.rate, ref_div, nint,
+       cpu_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
                                      nfrac, frac, out_div);
 
        pll = __raw_readl(dpll_base + AR934X_SRIF_DDR_DPLL2_REG);
@@ -254,7 +304,7 @@ static void __init ar934x_clocks_init(void)
                frac = 1 << 10;
        }
 
-       ddr_pll = ar934x_get_pll_freq(ath79_ref_clk.rate, ref_div, nint,
+       ddr_pll = ar934x_get_pll_freq(ref_rate, ref_div, nint,
                                      nfrac, frac, out_div);
 
        clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
@@ -263,49 +313,58 @@ static void __init ar934x_clocks_init(void)
                  AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK;
 
        if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS)
-               ath79_cpu_clk.rate = ath79_ref_clk.rate;
+               cpu_rate = ref_rate;
        else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL)
-               ath79_cpu_clk.rate = cpu_pll / (postdiv + 1);
+               cpu_rate = cpu_pll / (postdiv + 1);
        else
-               ath79_cpu_clk.rate = ddr_pll / (postdiv + 1);
+               cpu_rate = ddr_pll / (postdiv + 1);
 
        postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) &
                  AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK;
 
        if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS)
-               ath79_ddr_clk.rate = ath79_ref_clk.rate;
+               ddr_rate = ref_rate;
        else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL)
-               ath79_ddr_clk.rate = ddr_pll / (postdiv + 1);
+               ddr_rate = ddr_pll / (postdiv + 1);
        else
-               ath79_ddr_clk.rate = cpu_pll / (postdiv + 1);
+               ddr_rate = cpu_pll / (postdiv + 1);
 
        postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) &
                  AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK;
 
        if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS)
-               ath79_ahb_clk.rate = ath79_ref_clk.rate;
+               ahb_rate = ref_rate;
        else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL)
-               ath79_ahb_clk.rate = ddr_pll / (postdiv + 1);
+               ahb_rate = ddr_pll / (postdiv + 1);
        else
-               ath79_ahb_clk.rate = cpu_pll / (postdiv + 1);
+               ahb_rate = cpu_pll / (postdiv + 1);
+
+       ath79_add_sys_clkdev("ref", ref_rate);
+       ath79_add_sys_clkdev("cpu", cpu_rate);
+       ath79_add_sys_clkdev("ddr", ddr_rate);
+       ath79_add_sys_clkdev("ahb", ahb_rate);
 
-       ath79_wdt_clk.rate = ath79_ref_clk.rate;
-       ath79_uart_clk.rate = ath79_ref_clk.rate;
+       clk_add_alias("wdt", NULL, "ref", NULL);
+       clk_add_alias("uart", NULL, "ref", NULL);
 
        iounmap(dpll_base);
 }
 
 static void __init qca955x_clocks_init(void)
 {
+       unsigned long ref_rate;
+       unsigned long cpu_rate;
+       unsigned long ddr_rate;
+       unsigned long ahb_rate;
        u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv;
        u32 cpu_pll, ddr_pll;
        u32 bootstrap;
 
        bootstrap = ath79_reset_rr(QCA955X_RESET_REG_BOOTSTRAP);
        if (bootstrap & QCA955X_BOOTSTRAP_REF_CLK_40)
-               ath79_ref_clk.rate = 40 * 1000 * 1000;
+               ref_rate = 40 * 1000 * 1000;
        else
-               ath79_ref_clk.rate = 25 * 1000 * 1000;
+               ref_rate = 25 * 1000 * 1000;
 
        pll = ath79_pll_rr(QCA955X_PLL_CPU_CONFIG_REG);
        out_div = (pll >> QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
@@ -317,8 +376,8 @@ static void __init qca955x_clocks_init(void)
        frac = (pll >> QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
               QCA955X_PLL_CPU_CONFIG_NFRAC_MASK;
 
-       cpu_pll = nint * ath79_ref_clk.rate / ref_div;
-       cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 6));
+       cpu_pll = nint * ref_rate / ref_div;
+       cpu_pll += frac * ref_rate / (ref_div * (1 << 6));
        cpu_pll /= (1 << out_div);
 
        pll = ath79_pll_rr(QCA955X_PLL_DDR_CONFIG_REG);
@@ -331,8 +390,8 @@ static void __init qca955x_clocks_init(void)
        frac = (pll >> QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
               QCA955X_PLL_DDR_CONFIG_NFRAC_MASK;
 
-       ddr_pll = nint * ath79_ref_clk.rate / ref_div;
-       ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (1 << 10));
+       ddr_pll = nint * ref_rate / ref_div;
+       ddr_pll += frac * ref_rate / (ref_div * (1 << 10));
        ddr_pll /= (1 << out_div);
 
        clk_ctrl = ath79_pll_rr(QCA955X_PLL_CLK_CTRL_REG);
@@ -341,34 +400,39 @@ static void __init qca955x_clocks_init(void)
                  QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
 
        if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
-               ath79_cpu_clk.rate = ath79_ref_clk.rate;
+               cpu_rate = ref_rate;
        else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
-               ath79_cpu_clk.rate = ddr_pll / (postdiv + 1);
+               cpu_rate = ddr_pll / (postdiv + 1);
        else
-               ath79_cpu_clk.rate = cpu_pll / (postdiv + 1);
+               cpu_rate = cpu_pll / (postdiv + 1);
 
        postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
                  QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
 
        if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
-               ath79_ddr_clk.rate = ath79_ref_clk.rate;
+               ddr_rate = ref_rate;
        else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
-               ath79_ddr_clk.rate = cpu_pll / (postdiv + 1);
+               ddr_rate = cpu_pll / (postdiv + 1);
        else
-               ath79_ddr_clk.rate = ddr_pll / (postdiv + 1);
+               ddr_rate = ddr_pll / (postdiv + 1);
 
        postdiv = (clk_ctrl >> QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
                  QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
 
        if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
-               ath79_ahb_clk.rate = ath79_ref_clk.rate;
+               ahb_rate = ref_rate;
        else if (clk_ctrl & QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
-               ath79_ahb_clk.rate = ddr_pll / (postdiv + 1);
+               ahb_rate = ddr_pll / (postdiv + 1);
        else
-               ath79_ahb_clk.rate = cpu_pll / (postdiv + 1);
+               ahb_rate = cpu_pll / (postdiv + 1);
 
-       ath79_wdt_clk.rate = ath79_ref_clk.rate;
-       ath79_uart_clk.rate = ath79_ref_clk.rate;
+       ath79_add_sys_clkdev("ref", ref_rate);
+       ath79_add_sys_clkdev("cpu", cpu_rate);
+       ath79_add_sys_clkdev("ddr", ddr_rate);
+       ath79_add_sys_clkdev("ahb", ahb_rate);
+
+       clk_add_alias("wdt", NULL, "ref", NULL);
+       clk_add_alias("uart", NULL, "ref", NULL);
 }
 
 void __init ath79_clocks_init(void)
@@ -387,46 +451,27 @@ void __init ath79_clocks_init(void)
                qca955x_clocks_init();
        else
                BUG();
-
-       pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, "
-               "Ref:%lu.%03luMHz",
-               ath79_cpu_clk.rate / 1000000,
-               (ath79_cpu_clk.rate / 1000) % 1000,
-               ath79_ddr_clk.rate / 1000000,
-               (ath79_ddr_clk.rate / 1000) % 1000,
-               ath79_ahb_clk.rate / 1000000,
-               (ath79_ahb_clk.rate / 1000) % 1000,
-               ath79_ref_clk.rate / 1000000,
-               (ath79_ref_clk.rate / 1000) % 1000);
 }
 
-/*
- * Linux clock API
- */
-struct clk *clk_get(struct device *dev, const char *id)
+unsigned long __init
+ath79_get_sys_clk_rate(const char *id)
 {
-       if (!strcmp(id, "ref"))
-               return &ath79_ref_clk;
-
-       if (!strcmp(id, "cpu"))
-               return &ath79_cpu_clk;
-
-       if (!strcmp(id, "ddr"))
-               return &ath79_ddr_clk;
-
-       if (!strcmp(id, "ahb"))
-               return &ath79_ahb_clk;
+       struct clk *clk;
+       unsigned long rate;
 
-       if (!strcmp(id, "wdt"))
-               return &ath79_wdt_clk;
+       clk = clk_get(NULL, id);
+       if (IS_ERR(clk))
+               panic("unable to get %s clock, err=%d", id, (int) PTR_ERR(clk));
 
-       if (!strcmp(id, "uart"))
-               return &ath79_uart_clk;
+       rate = clk_get_rate(clk);
+       clk_put(clk);
 
-       return ERR_PTR(-ENOENT);
+       return rate;
 }
-EXPORT_SYMBOL(clk_get);
 
+/*
+ * Linux clock API
+ */
 int clk_enable(struct clk *clk)
 {
        return 0;
@@ -443,8 +488,3 @@ unsigned long clk_get_rate(struct clk *clk)
        return clk->rate;
 }
 EXPORT_SYMBOL(clk_get_rate);
-
-void clk_put(struct clk *clk)
-{
-}
-EXPORT_SYMBOL(clk_put);
index 561906c2345e112d9a6e3630aa71d9f1ad849256..648d2dafbc56bf59b60671c1792173685f04e8b1 100644 (file)
@@ -21,6 +21,8 @@
 #define ATH79_MEM_SIZE_MAX     (128 * 1024 * 1024)
 
 void ath79_clocks_init(void);
+unsigned long ath79_get_sys_clk_rate(const char *id);
+
 void ath79_ddr_wb_flush(unsigned int reg);
 
 void ath79_gpio_function_enable(u32 mask);
index a3a2741d06882b6b0ee908eaf5559ee4bda9f38a..c3b04c929f29b552014013f253d18e8500faae5b 100644 (file)
@@ -81,21 +81,19 @@ static struct platform_device ar933x_uart_device = {
 
 void __init ath79_register_uart(void)
 {
-       struct clk *clk;
+       unsigned long uart_clk_rate;
 
-       clk = clk_get(NULL, "uart");
-       if (IS_ERR(clk))
-               panic("unable to get UART clock, err=%ld", PTR_ERR(clk));
+       uart_clk_rate = ath79_get_sys_clk_rate("uart");
 
        if (soc_is_ar71xx() ||
            soc_is_ar724x() ||
            soc_is_ar913x() ||
            soc_is_ar934x() ||
            soc_is_qca955x()) {
-               ath79_uart_data[0].uartclk = clk_get_rate(clk);
+               ath79_uart_data[0].uartclk = uart_clk_rate;
                platform_device_register(&ath79_uart_device);
        } else if (soc_is_ar933x()) {
-               ar933x_uart_data.uartclk = clk_get_rate(clk);
+               ar933x_uart_data.uartclk = uart_clk_rate;
                platform_device_register(&ar933x_uart_device);
        } else {
                BUG();
index 80f4ecd42b0dc3ca21a57bf2e52745d0c389b769..64807a4809d0a4b6f367ad52f15fe2fcbfc6a843 100644 (file)
@@ -200,7 +200,6 @@ void __init plat_mem_setup(void)
 
        ath79_detect_sys_type();
        detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
-       ath79_clocks_init();
 
        _machine_restart = ath79_restart;
        _machine_halt = ath79_halt;
@@ -209,13 +208,25 @@ void __init plat_mem_setup(void)
 
 void __init plat_time_init(void)
 {
-       struct clk *clk;
+       unsigned long cpu_clk_rate;
+       unsigned long ahb_clk_rate;
+       unsigned long ddr_clk_rate;
+       unsigned long ref_clk_rate;
+
+       ath79_clocks_init();
+
+       cpu_clk_rate = ath79_get_sys_clk_rate("cpu");
+       ahb_clk_rate = ath79_get_sys_clk_rate("ahb");
+       ddr_clk_rate = ath79_get_sys_clk_rate("ddr");
+       ref_clk_rate = ath79_get_sys_clk_rate("ref");
 
-       clk = clk_get(NULL, "cpu");
-       if (IS_ERR(clk))
-               panic("unable to get CPU clock, err=%ld", PTR_ERR(clk));
+       pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, Ref:%lu.%03luMHz",
+               cpu_clk_rate / 1000000, (cpu_clk_rate / 1000) % 1000,
+               ddr_clk_rate / 1000000, (ddr_clk_rate / 1000) % 1000,
+               ahb_clk_rate / 1000000, (ahb_clk_rate / 1000) % 1000,
+               ref_clk_rate / 1000000, (ref_clk_rate / 1000) % 1000);
 
-       mips_hpt_frequency = clk_get_rate(clk) / 2;
+       mips_hpt_frequency = cpu_clk_rate / 2;
 }
 
 static int __init ath79_setup(void)
index 7e17374a9ae89fc79257b021c464c3a10d2a7f6a..b713cd64b08740f083f2a25026ee063f8ae5cfdd 100644 (file)
@@ -306,14 +306,14 @@ void __init bcm63xx_cpu_init(void)
 
        switch (c->cputype) {
        case CPU_BMIPS3300:
-               if ((read_c0_prid() & 0xff00) != PRID_IMP_BMIPS3300_ALT)
+               if ((read_c0_prid() & PRID_IMP_MASK) != PRID_IMP_BMIPS3300_ALT)
                        __cpu_name[cpu] = "Broadcom BCM6338";
                /* fall-through */
        case CPU_BMIPS32:
                chipid_reg = BCM_6345_PERF_BASE;
                break;
        case CPU_BMIPS4350:
-               switch ((read_c0_prid() & 0xff)) {
+               switch ((read_c0_prid() & PRID_REV_MASK)) {
                case 0x04:
                        chipid_reg = BCM_3368_PERF_BASE;
                        break;
index e652e578a679aa3d1c5c41e336121bedb298ad72..4b50d40f7451ad86eba859b8a02ea792ff060b35 100644 (file)
@@ -35,6 +35,8 @@ struct bcm963xx_nvram {
        u32     checksum_high;
 };
 
+#define BCM63XX_DEFAULT_PSI_SIZE       64
+
 static struct bcm963xx_nvram nvram;
 static int mac_addr_used;
 
@@ -114,3 +116,12 @@ int bcm63xx_nvram_get_mac_address(u8 *mac)
        return 0;
 }
 EXPORT_SYMBOL(bcm63xx_nvram_get_mac_address);
+
+int bcm63xx_nvram_get_psi_size(void)
+{
+       if (nvram.psi_size > 0)
+               return nvram.psi_size;
+
+       return BCM63XX_DEFAULT_PSI_SIZE;
+}
+EXPORT_SYMBOL(bcm63xx_nvram_get_psi_size);
index f210b09ececcf0fe9ab0ee282da0f9332c050394..a73d6e2c4f64fe55e033c05e0ec4aa1eed8eed4e 100644 (file)
@@ -4,3 +4,4 @@ vmlinux.*
 zImage
 zImage.tmp
 calc_vmlinuz_load_addr
+uImage
index 851261e9fdc0a948bb1bfbb9e1f930a0ff8beec1..1466c00260936c7e387877c8c9e296d430cd6240 100644 (file)
@@ -40,3 +40,18 @@ quiet_cmd_srec = OBJCOPY $@
       cmd_srec = $(OBJCOPY) -S -O srec $(strip-flags) $(VMLINUX) $@
 $(obj)/vmlinux.srec: $(VMLINUX) FORCE
        $(call if_changed,srec)
+
+UIMAGE_LOADADDR  = $(VMLINUX_LOAD_ADDRESS)
+UIMAGE_ENTRYADDR = $(VMLINUX_ENTRY_ADDRESS)
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+       $(call if_changed,gzip)
+
+targets += uImage.gz
+$(obj)/uImage.gz: $(obj)/vmlinux.bin.gz FORCE
+       $(call if_changed,uimage,gzip)
+
+targets += uImage
+$(obj)/uImage: $(obj)/uImage.gz FORCE
+       @ln -sf $(notdir $<) $@
+       @echo '  Image $@ is ready'
index bb1dbf4abb9d6516c1bea99229dd68a12d4cce2d..0048c08978965428a32a03bf211c3f86909c12fb 100644 (file)
@@ -25,7 +25,7 @@ KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \
 
 KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
        -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
-       -DKERNEL_ENTRY=0x$(shell $(NM) $(objtree)/$(KBUILD_IMAGE) 2>/dev/null | grep " kernel_entry" | cut -f1 -d \ )
+       -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS)
 
 targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o
 
diff --git a/arch/mips/boot/dts/include/dt-bindings b/arch/mips/boot/dts/include/dt-bindings
new file mode 120000 (symlink)
index 0000000..08c00e4
--- /dev/null
@@ -0,0 +1 @@
+../../../../../include/dt-bindings
\ No newline at end of file
index 02193953eb9e6ccb56529ee6880027ad92219a04..b752c4ed0b797938c6ff58e7e1583982cdbdd5ac 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/smp.h>
 
 #include <asm/cpu-info.h>
+#include <asm/cpu-type.h>
 #include <asm/time.h>
 
 #include <asm/octeon/octeon.h>
index 9d36774bded117b6658327e249d1fd4e4e187d0d..25fbfae06c1f8585359c65d975bfc3240e00faa8 100644 (file)
@@ -1776,7 +1776,7 @@ asmlinkage void plat_irq_dispatch(void)
 
 #ifdef CONFIG_HOTPLUG_CPU
 
-void fixup_irqs(void)
+void octeon_fixup_irqs(void)
 {
        irq_cpu_offline();
 }
index 48b08eb9d9e4bd29dc97f5ec97c3f763852ff4aa..b212ae12e5ac7dc8ca35dfb24324ba638353f85e 100644 (file)
@@ -8,6 +8,7 @@
  *   written by Ralf Baechle <ralf@linux-mips.org>
  */
 #include <linux/compiler.h>
+#include <linux/vmalloc.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/console.h>
@@ -1139,3 +1140,30 @@ static int __init edac_devinit(void)
        return err;
 }
 device_initcall(edac_devinit);
+
+static void __initdata *octeon_dummy_iospace;
+
+static int __init octeon_no_pci_init(void)
+{
+       /*
+        * Initially assume there is no PCI. The PCI/PCIe platform code will
+        * later re-initialize these to correct values if they are present.
+        */
+       octeon_dummy_iospace = vzalloc(IO_SPACE_LIMIT);
+       set_io_port_base((unsigned long)octeon_dummy_iospace);
+       ioport_resource.start = MAX_RESOURCE;
+       ioport_resource.end = 0;
+       return 0;
+}
+core_initcall(octeon_no_pci_init);
+
+static int __init octeon_no_pci_release(void)
+{
+       /*
+        * Release the allocated memory if a real IO space is there.
+        */
+       if ((unsigned long)octeon_dummy_iospace != mips_io_port_base)
+               vfree(octeon_dummy_iospace);
+       return 0;
+}
+late_initcall(octeon_no_pci_release);
index 138cc80c592817d523b4b7a82c2f2aadaa37eae8..24a2167db7780398e67d7b8d369bbc4ac015469a 100644 (file)
@@ -255,8 +255,6 @@ static void octeon_cpus_done(void)
 /* State of each CPU. */
 DEFINE_PER_CPU(int, cpu_state);
 
-extern void fixup_irqs(void);
-
 static int octeon_cpu_disable(void)
 {
        unsigned int cpu = smp_processor_id();
@@ -267,7 +265,7 @@ static int octeon_cpu_disable(void)
        set_cpu_online(cpu, false);
        cpu_clear(cpu, cpu_callin_map);
        local_irq_disable();
-       fixup_irqs();
+       octeon_fixup_irqs();
        local_irq_enable();
 
        flush_cache_all();
diff --git a/arch/mips/configs/xway_defconfig b/arch/mips/configs/xway_defconfig
new file mode 100644 (file)
index 0000000..8987846
--- /dev/null
@@ -0,0 +1,159 @@
+CONFIG_LANTIQ=y
+CONFIG_XRX200_PHY_FW=y
+CONFIG_CPU_MIPS32_R2=y
+# CONFIG_COMPACTION is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_HZ_100=y
+# CONFIG_SECCOMP is not set
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_RD_GZIP is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_SLUB_DEBUG is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_COREDUMP is not set
+# CONFIG_SUSPEND is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_WESTWOOD is not set
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+# CONFIG_BRIDGE_NETFILTER is not set
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NETFILTER_XT_TARGET_CT=m
+CONFIG_NETFILTER_XT_TARGET_LOG=m
+CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NF_CONNTRACK_IPV4=m
+# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_RAW=m
+CONFIG_BRIDGE=y
+# CONFIG_BRIDGE_IGMP_SNOOPING is not set
+CONFIG_VLAN_8021Q=y
+CONFIG_NET_SCHED=y
+CONFIG_HAMRADIO=y
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_LANTIQ=y
+CONFIG_EEPROM_93CX6=m
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_NETDEVICES=y
+CONFIG_LANTIQ_ETOP=y
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+CONFIG_PPP=m
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPPOE=m
+CONFIG_PPP_ASYNC=m
+CONFIG_ISDN=y
+CONFIG_INPUT=m
+CONFIG_INPUT_POLLDEV=m
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_SERIO is not set
+# CONFIG_VT is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SPI=y
+CONFIG_GPIO_MM_LANTIQ=y
+CONFIG_GPIO_STP_XWAY=y
+# CONFIG_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_HID is not set
+# CONFIG_USB_HID is not set
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_STORAGE_DEBUG=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_STAGING=y
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_FS_XATTR=y
+# CONFIG_JFFS2_FS_POSIX_ACL is not set
+# CONFIG_JFFS2_FS_SECURITY is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+# CONFIG_JFFS2_ZLIB is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_ZLIB is not set
+CONFIG_SQUASHFS_XZ=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_DEBUG_FS=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32_SARWATE=y
+CONFIG_AVERAGE=y
index 824e08c737981d8d9be039892b49f876b4c54bd0..4b3e3a4375a6756b2af743c3f163d50055fb2c45 100644 (file)
@@ -51,6 +51,14 @@ static struct irq_chip ioasic_irq_type = {
        .irq_unmask = unmask_ioasic_irq,
 };
 
+void clear_ioasic_dma_irq(unsigned int irq)
+{
+       u32 sir;
+
+       sir = ~(1 << (irq - ioasic_irq_base));
+       ioasic_write(IO_REG_SIR, sir);
+}
+
 static struct irq_chip ioasic_dma_irq_type = {
        .name = "IO-ASIC-DMA",
        .irq_ack = ack_ioasic_irq,
index ab169046e442a9c44a74e2db2fcb2cf14a11081f..468f665de7bb731e5d8cf71dcef5c1461c146e48 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <asm/bootinfo.h>
 #include <asm/cpu.h>
+#include <asm/cpu-type.h>
 #include <asm/processor.h>
 
 #include <asm/dec/prom.h>
index ea57f39e67362d19f5954d7ca0cd4ebd46590097..1914e56f0d963c149e9ac66c8852986f7fca84bd 100644 (file)
@@ -125,13 +125,18 @@ int rtc_mips_set_mmss(unsigned long nowtime)
 
 void __init plat_time_init(void)
 {
+       int ioasic_clock = 0;
        u32 start, end;
-       int i = HZ / 10;
+       int i = HZ / 8;
 
        /* Set up the rate of periodic DS1287 interrupts. */
        ds1287_set_base_clock(HZ);
 
+       /* On some I/O ASIC systems we have the I/O ASIC's counter.  */
+       if (IOASIC)
+               ioasic_clock = dec_ioasic_clocksource_init() == 0;
        if (cpu_has_counter) {
+               ds1287_timer_state();
                while (!ds1287_timer_state())
                        ;
 
@@ -143,12 +148,24 @@ void __init plat_time_init(void)
 
                end = read_c0_count();
 
-               mips_hpt_frequency = (end - start) * 10;
+               mips_hpt_frequency = (end - start) * 8;
                printk(KERN_INFO "MIPS counter frequency %dHz\n",
                        mips_hpt_frequency);
-       } else if (IOASIC)
-               /* For pre-R4k systems we use the I/O ASIC's counter.  */
-               dec_ioasic_clocksource_init();
+
+               /*
+                * All R4k DECstations suffer from the CP0 Count erratum,
+                * so we can't use the timer as a clock source, and a clock
+                * event both at a time.  An accurate wall clock is more
+                * important than a high-precision interval timer so only
+                * use the timer as a clock source, and not a clock event
+                * if there's no I/O ASIC counter available to serve as a
+                * clock source.
+                */
+               if (!ioasic_clock) {
+                       init_r4k_clocksource();
+                       mips_hpt_frequency = 0;
+               }
+       }
 
        ds1287_clockevent_init(dec_interrupt[DEC_IRQ_RTC]);
 }
index 9b54b7a403d446b59073fe39fec03e0db7a432e8..454ddf9bb76f8a5fc5660bc6ab02c4d5380f7593 100644 (file)
@@ -1,2 +1,15 @@
 # MIPS headers
+generic-y += cputime.h
+generic-y += current.h
+generic-y += emergency-restart.h
+generic-y += local64.h
+generic-y += mutex.h
+generic-y += parport.h
+generic-y += percpu.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += segment.h
+generic-y += serial.h
 generic-y += trace_clock.h
+generic-y += ucontext.h
+generic-y += xor.h
index 552a65a0cf2b5438778d6b3d975a8e518a522373..27bd060d716e334e65be1e547a8c478d45273fa7 100644 (file)
@@ -65,44 +65,33 @@ static inline unsigned long bmips_read_zscm_reg(unsigned int offset)
 {
        unsigned long ret;
 
-       __asm__ __volatile__(
-               ".set push\n"
-               ".set noreorder\n"
-               "cache %1, 0(%2)\n"
-               "sync\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "mfc0 %0, $28, 3\n"
-               "_ssnop\n"
-               ".set pop\n"
-               : "=&r" (ret)
-               : "i" (Index_Load_Tag_S), "r" (ZSCM_REG_BASE + offset)
-               : "memory");
+       barrier();
+       cache_op(Index_Load_Tag_S, ZSCM_REG_BASE + offset);
+       __sync();
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       ret = read_c0_ddatalo();
+       _ssnop();
+
        return ret;
 }
 
 static inline void bmips_write_zscm_reg(unsigned int offset, unsigned long data)
 {
-       __asm__ __volatile__(
-               ".set push\n"
-               ".set noreorder\n"
-               "mtc0 %0, $28, 3\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "cache %1, 0(%2)\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               "_ssnop\n"
-               : /* no outputs */
-               : "r" (data),
-                 "i" (Index_Store_Tag_S), "r" (ZSCM_REG_BASE + offset)
-               : "memory");
+       write_c0_ddatalo(data);
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       cache_op(Index_Store_Tag_S, ZSCM_REG_BASE + offset);
+       _ssnop();
+       _ssnop();
+       _ssnop();
+       barrier();
 }
 
 #endif /* !defined(__ASSEMBLY__) */
index fa44f3ec530214f5014664cda4611b1a5a027251..51680d15ca8ec2b2971365573506b39f473170aa 100644 (file)
 #include <asm/cpu-info.h>
 #include <cpu-feature-overrides.h>
 
-#ifndef current_cpu_type
-#define current_cpu_type()     current_cpu_data.cputype
-#endif
-
-#define boot_cpu_type()                cpu_data[0].cputype
-
 /*
  * SMP assumption: Options of CPU 0 are a superset of all processors.
  * This is true for all known MIPS systems.
index 41401d8eb7d1a3ca13bfbe77c7d78575307e3531..21c8e29c8f91e87486f90d3aaa7fbe79220add5b 100644 (file)
@@ -84,6 +84,7 @@ struct cpuinfo_mips {
 extern struct cpuinfo_mips cpu_data[];
 #define current_cpu_data cpu_data[smp_processor_id()]
 #define raw_current_cpu_data cpu_data[raw_smp_processor_id()]
+#define boot_cpu_data cpu_data[0]
 
 extern void cpu_probe(void);
 extern void cpu_report(void);
diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h
new file mode 100644 (file)
index 0000000..4a402cc
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2003, 2004 Ralf Baechle
+ * Copyright (C) 2004  Maciej W. Rozycki
+ */
+#ifndef __ASM_CPU_TYPE_H
+#define __ASM_CPU_TYPE_H
+
+#include <linux/smp.h>
+#include <linux/compiler.h>
+
+static inline int __pure __get_cpu_type(const int cpu_type)
+{
+       switch (cpu_type) {
+#if defined(CONFIG_SYS_HAS_CPU_LOONGSON2E) || \
+    defined(CONFIG_SYS_HAS_CPU_LOONGSON2F)
+       case CPU_LOONGSON2:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_LOONGSON1B
+       case CPU_LOONGSON1:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_MIPS32_R1
+       case CPU_4KC:
+       case CPU_ALCHEMY:
+       case CPU_BMIPS3300:
+       case CPU_BMIPS4350:
+       case CPU_PR4450:
+       case CPU_BMIPS32:
+       case CPU_JZRISC:
+#endif
+
+#if defined(CONFIG_SYS_HAS_CPU_MIPS32_R1) || \
+    defined(CONFIG_SYS_HAS_CPU_MIPS32_R2)
+       case CPU_4KEC:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_MIPS32_R2
+       case CPU_4KSC:
+       case CPU_24K:
+       case CPU_34K:
+       case CPU_1004K:
+       case CPU_74K:
+       case CPU_M14KC:
+       case CPU_M14KEC:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R1
+       case CPU_5KC:
+       case CPU_5KE:
+       case CPU_20KC:
+       case CPU_25KF:
+       case CPU_SB1:
+       case CPU_SB1A:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R2
+       /*
+        * All MIPS64 R2 processors have their own special symbols.  That is,
+        * there currently is no pure R2 core
+        */
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R3000
+       case CPU_R2000:
+       case CPU_R3000:
+       case CPU_R3000A:
+       case CPU_R3041:
+       case CPU_R3051:
+       case CPU_R3052:
+       case CPU_R3081:
+       case CPU_R3081E:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_TX39XX
+       case CPU_TX3912:
+       case CPU_TX3922:
+       case CPU_TX3927:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_VR41XX
+       case CPU_VR41XX:
+       case CPU_VR4111:
+       case CPU_VR4121:
+       case CPU_VR4122:
+       case CPU_VR4131:
+       case CPU_VR4133:
+       case CPU_VR4181:
+       case CPU_VR4181A:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R4300
+       case CPU_R4300:
+       case CPU_R4310:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R4X00
+       case CPU_R4000PC:
+       case CPU_R4000SC:
+       case CPU_R4000MC:
+       case CPU_R4200:
+       case CPU_R4400PC:
+       case CPU_R4400SC:
+       case CPU_R4400MC:
+       case CPU_R4600:
+       case CPU_R4700:
+       case CPU_R4640:
+       case CPU_R4650:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_TX49XX
+       case CPU_TX49XX:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R5000
+       case CPU_R5000:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R5432
+       case CPU_R5432:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R5500
+       case CPU_R5500:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R6000
+       case CPU_R6000:
+       case CPU_R6000A:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_NEVADA
+       case CPU_NEVADA:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R8000
+       case CPU_R8000:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_R10000
+       case CPU_R10000:
+       case CPU_R12000:
+       case CPU_R14000:
+#endif
+#ifdef CONFIG_SYS_HAS_CPU_RM7000
+       case CPU_RM7000:
+       case CPU_SR71000:
+#endif
+#ifdef CONFIG_SYS_HAS_CPU_RM9000
+       case CPU_RM9000:
+#endif
+#ifdef CONFIG_SYS_HAS_CPU_SB1
+       case CPU_SB1:
+       case CPU_SB1A:
+#endif
+#ifdef CONFIG_SYS_HAS_CPU_CAVIUM_OCTEON
+       case CPU_CAVIUM_OCTEON:
+       case CPU_CAVIUM_OCTEON_PLUS:
+       case CPU_CAVIUM_OCTEON2:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_BMIPS4380
+       case CPU_BMIPS4380:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_BMIPS5000
+       case CPU_BMIPS5000:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_XLP
+       case CPU_XLP:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_XLR
+       case CPU_XLR:
+#endif
+               break;
+       default:
+               unreachable();
+       }
+
+       return cpu_type;
+}
+
+static inline int __pure current_cpu_type(void)
+{
+       const int cpu_type = current_cpu_data.cputype;
+
+       return __get_cpu_type(cpu_type);
+}
+
+static inline int __pure boot_cpu_type(void)
+{
+       const int cpu_type = cpu_data[0].cputype;
+
+       return __get_cpu_type(cpu_type);
+}
+
+#endif /* __ASM_CPU_TYPE_H */
index 632bbe5a79ea5bfe53769939964ce3a4d3bfd8e9..d2035e16502a7d98cfe3e015f9855da2617308f2 100644 (file)
@@ -3,15 +3,14 @@
  *       various MIPS cpu types.
  *
  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
- * Copyright (C) 2004  Maciej W. Rozycki
+ * Copyright (C) 2004, 2013  Maciej W. Rozycki
  */
 #ifndef _ASM_CPU_H
 #define _ASM_CPU_H
 
-/* Assigned Company values for bits 23:16 of the PRId Register
-   (CP0 register 15, select 0).         As of the MIPS32 and MIPS64 specs from
-   MTI, the PRId register is defined in this (backwards compatible)
-   way:
+/*
+   As of the MIPS32 and MIPS64 specs from MTI, the PRId register (CP0
+   register 15, select 0) is defined in this (backwards compatible) way:
 
   +----------------+----------------+----------------+----------------+
   | Company Options| Company ID            | Processor ID   | Revision       |
    spec.
 */
 
+#define PRID_OPT_MASK          0xff000000
+
+/*
+ * Assigned Company values for bits 23:16 of the PRId register.
+ */
+
+#define PRID_COMP_MASK         0xff0000
+
 #define PRID_COMP_LEGACY       0x000000
 #define PRID_COMP_MIPS         0x010000
 #define PRID_COMP_BROADCOM     0x020000
 #define PRID_COMP_INGENIC      0xd00000
 
 /*
- * Assigned values for the product ID register.         In order to detect a
- * certain CPU type exactly eventually additional registers may need to
- * be examined.         These are valid when 23:16 == PRID_COMP_LEGACY
+ * Assigned Processor ID (implementation) values for bits 15:8 of the PRId
+ * register.  In order to detect a certain CPU type exactly eventually
+ * additional registers may need to be examined.
  */
+
+#define PRID_IMP_MASK          0xff00
+
+/*
+ * These are valid when 23:16 == PRID_COMP_LEGACY
+ */
+
 #define PRID_IMP_R2000         0x0100
 #define PRID_IMP_AU1_REV1      0x0100
 #define PRID_IMP_AU1_REV2      0x0200
 #define PRID_IMP_CAVIUM_CN68XX 0x9100
 #define PRID_IMP_CAVIUM_CN66XX 0x9200
 #define PRID_IMP_CAVIUM_CN61XX 0x9300
+#define PRID_IMP_CAVIUM_CNF71XX 0x9400
+#define PRID_IMP_CAVIUM_CN78XX 0x9500
+#define PRID_IMP_CAVIUM_CN70XX 0x9600
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_INGENIC
 
 #define PRID_IMP_NETLOGIC_XLP8XX       0x1000
 #define PRID_IMP_NETLOGIC_XLP3XX       0x1100
+#define PRID_IMP_NETLOGIC_XLP2XX       0x1200
 
 /*
- * Definitions for 7:0 on legacy processors
+ * Particular Revision values for bits 7:0 of the PRId register.
  */
 
 #define PRID_REV_MASK          0x00ff
 
+/*
+ * Definitions for 7:0 on legacy processors
+ */
+
 #define PRID_REV_TX4927                0x0022
 #define PRID_REV_TX4937                0x0030
 #define PRID_REV_R4400         0x0040
  *  31                            16 15             8 7              0
  */
 
+#define FPIR_IMP_MASK          0xff00
+
 #define FPIR_IMP_NONE          0x0000
 
 enum cpu_type_enum {
@@ -272,7 +296,7 @@ enum cpu_type_enum {
         */
        CPU_5KC, CPU_5KE, CPU_20KC, CPU_25KF, CPU_SB1, CPU_SB1A, CPU_LOONGSON2,
        CPU_CAVIUM_OCTEON, CPU_CAVIUM_OCTEON_PLUS, CPU_CAVIUM_OCTEON2,
-       CPU_XLR, CPU_XLP,
+       CPU_CAVIUM_OCTEON3, CPU_XLR, CPU_XLP,
 
        CPU_LAST
 };
diff --git a/arch/mips/include/asm/cputime.h b/arch/mips/include/asm/cputime.h
deleted file mode 100644 (file)
index c00eacb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __MIPS_CPUTIME_H
-#define __MIPS_CPUTIME_H
-
-#include <asm-generic/cputime.h>
-
-#endif /* __MIPS_CPUTIME_H */
diff --git a/arch/mips/include/asm/current.h b/arch/mips/include/asm/current.h
deleted file mode 100644 (file)
index 4c51401..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/current.h>
index 98badd6bf22dd6ca386a62d1df19f9d0c8759874..a6e505a0e44b4b119a6967fd5f8938ffb211a73e 100644 (file)
@@ -31,8 +31,10 @@ static inline u32 ioasic_read(unsigned int reg)
        return ioasic_base[reg / 4];
 }
 
+extern void clear_ioasic_dma_irq(unsigned int irq);
+
 extern void init_ioasic_irqs(int base);
 
-extern void dec_ioasic_clocksource_init(void);
+extern int dec_ioasic_clocksource_init(void);
 
 #endif /* __ASM_DEC_IOASIC_H */
diff --git a/arch/mips/include/asm/emergency-restart.h b/arch/mips/include/asm/emergency-restart.h
deleted file mode 100644 (file)
index 108d8c4..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_EMERGENCY_RESTART_H
-#define _ASM_EMERGENCY_RESTART_H
-
-#include <asm-generic/emergency-restart.h>
-
-#endif /* _ASM_EMERGENCY_RESTART_H */
diff --git a/arch/mips/include/asm/local64.h b/arch/mips/include/asm/local64.h
deleted file mode 100644 (file)
index 36c93b5..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/local64.h>
index ddb947e9221f13e631ddef8c4164255abdbebed8..0089a740e5aed1a17fab5c247a568f4e5100b09b 100644 (file)
@@ -42,8 +42,6 @@
 #define cpu_has_mips64r1       0
 #define cpu_has_mips64r2       0
 
-#define cpu_has_dsp            0
-#define cpu_has_dsp2           0
 #define cpu_has_mipsmt         0
 
 #define cpu_has_64bits         0
index 3e11a468cdf83de964bba1d718adfc49222da395..54f9e84db8ac14a0c1ac2cb57077ec4fb231aa21 100644 (file)
@@ -43,6 +43,8 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 
+#include <asm/cpu.h>
+
 /* cpu pipeline flush */
 void static inline au_sync(void)
 {
@@ -140,7 +142,7 @@ static inline int au1xxx_cpu_needs_config_od(void)
 
 static inline int alchemy_get_cputype(void)
 {
-       switch (read_c0_prid() & 0xffff0000) {
+       switch (read_c0_prid() & (PRID_OPT_MASK | PRID_COMP_MASK)) {
        case 0x00030000:
                return ALCHEMY_CPU_AU1000;
                break;
index 4e0b6bc1165edcbae2f44663390daa2c63c017d9..348df49dcc9f35ad7ce4129bde4ab66d1a103b00 100644 (file)
@@ -30,4 +30,6 @@ u8 *bcm63xx_nvram_get_name(void);
  */
 int bcm63xx_nvram_get_mac_address(u8 *mac);
 
+int bcm63xx_nvram_get_psi_size(void);
+
 #endif /* BCM63XX_NVRAM_H */
diff --git a/arch/mips/include/asm/mach-cavium-octeon/gpio.h b/arch/mips/include/asm/mach-cavium-octeon/gpio.h
new file mode 100644 (file)
index 0000000..34e9f7a
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __ASM_MACH_CAVIUM_OCTEON_GPIO_H
+#define __ASM_MACH_CAVIUM_OCTEON_GPIO_H
+
+#ifdef CONFIG_GPIOLIB
+#define gpio_get_value __gpio_get_value
+#define gpio_set_value __gpio_set_value
+#define gpio_cansleep  __gpio_cansleep
+#else
+int gpio_request(unsigned gpio, const char *label);
+void gpio_free(unsigned gpio);
+int gpio_direction_input(unsigned gpio);
+int gpio_direction_output(unsigned gpio, int value);
+int gpio_get_value(unsigned gpio);
+void gpio_set_value(unsigned gpio, int value);
+#endif
+
+#include <asm-generic/gpio.h>
+
+#define gpio_to_irq    __gpio_to_irq
+
+#endif /* __ASM_MACH_GENERIC_GPIO_H */
index f4caacd255528ef1a0bc86f0cf2a522a9243e470..1bcb6421205e3d92913a93f7dcdb04c726c0f447 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP22_CPU_FEATURE_OVERRIDES_H
 
+#include <asm/cpu.h>
+
 /*
  * IP22 with a variety of processors so we can't use defaults for everything.
  */
index 1d2b6ff60d339ccc8ebdd80b7e374f201a2b6e4f..d6111aa2e8864f0a9452a4a08e178255aca12e94 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP27_CPU_FEATURE_OVERRIDES_H
 
+#include <asm/cpu.h>
+
 /*
  * IP27 only comes with R10000 family processors all using the same config
  */
index 65e9c856390d9d43fcf24f7d7c301c4dea665a74..4cec06d133db238b785816bb9c0488e7caf3cd15 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef __ASM_MACH_IP28_CPU_FEATURE_OVERRIDES_H
 #define __ASM_MACH_IP28_CPU_FEATURE_OVERRIDES_H
 
+#include <asm/cpu.h>
+
 /*
  * IP28 only comes with R10000 family processors all using the same config
  */
diff --git a/arch/mips/include/asm/mach-lantiq/falcon/cpu-feature-overrides.h b/arch/mips/include/asm/mach-lantiq/falcon/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..096a100
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  Lantiq FALCON specific CPU feature overrides
+ *
+ *  Copyright (C) 2013 Thomas Langer, Lantiq Deutschland
+ *
+ *  This file was derived from: include/asm-mips/cpu-features.h
+ *     Copyright (C) 2003, 2004 Ralf Baechle
+ *     Copyright (C) 2004 Maciej W. Rozycki
+ *
+ *  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_MACH_FALCON_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_FALCON_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb            1
+#define cpu_has_4kex           1
+#define cpu_has_3k_cache       0
+#define cpu_has_4k_cache       1
+#define cpu_has_tx39_cache     0
+#define cpu_has_sb1_cache      0
+#define cpu_has_fpu            0
+#define cpu_has_32fpr          0
+#define cpu_has_counter                1
+#define cpu_has_watch          1
+#define cpu_has_divec          1
+
+#define cpu_has_prefetch       1
+#define cpu_has_ejtag          1
+#define cpu_has_llsc           1
+
+#define cpu_has_mips16         1
+#define cpu_has_mdmx           0
+#define cpu_has_mips3d         0
+#define cpu_has_smartmips      0
+
+#define cpu_has_mips32r1       1
+#define cpu_has_mips32r2       1
+#define cpu_has_mips64r1       0
+#define cpu_has_mips64r2       0
+
+#define cpu_has_dsp            1
+#define cpu_has_mipsmt         1
+
+#define cpu_has_vint           1
+#define cpu_has_veic           1
+
+#define cpu_has_64bits         0
+#define cpu_has_64bit_zero_reg 0
+#define cpu_has_64bit_gp_regs  0
+#define cpu_has_64bit_addresses        0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+
+#endif /* __ASM_MACH_FALCON_CPU_FEATURE_OVERRIDES_H */
index 9809972ea8822908680fc5c79cc95fad5342c1df..6f9b24f51157571cf9e80d77028051e06e384610 100644 (file)
@@ -20,6 +20,8 @@
 #define SYSC_REG_CHIP_REV              0x0c
 #define SYSC_REG_SYSTEM_CONFIG0                0x10
 #define SYSC_REG_SYSTEM_CONFIG1                0x14
+#define SYSC_REG_CLKCFG0               0x2c
+#define SYSC_REG_CPU_SYS_CLKCFG                0x3c
 #define SYSC_REG_CPLL_CONFIG0          0x54
 #define SYSC_REG_CPLL_CONFIG1          0x58
 
 #define MT7620A_CHIP_NAME0             0x3637544d
 #define MT7620A_CHIP_NAME1             0x20203032
 
+#define SYSCFG0_XTAL_FREQ_SEL          BIT(6)
+
 #define CHIP_REV_PKG_MASK              0x1
 #define CHIP_REV_PKG_SHIFT             16
 #define CHIP_REV_VER_MASK              0xf
 #define CHIP_REV_VER_SHIFT             8
 #define CHIP_REV_ECO_MASK              0xf
 
-#define CPLL_SW_CONFIG_SHIFT           31
-#define CPLL_SW_CONFIG_MASK            0x1
-#define CPLL_CPU_CLK_SHIFT             24
-#define CPLL_CPU_CLK_MASK              0x1
-#define CPLL_MULT_RATIO_SHIFT           16
-#define CPLL_MULT_RATIO                 0x7
-#define CPLL_DIV_RATIO_SHIFT            10
-#define CPLL_DIV_RATIO                  0x3
+#define CLKCFG0_PERI_CLK_SEL           BIT(4)
+
+#define CPU_SYS_CLKCFG_OCP_RATIO_SHIFT 16
+#define CPU_SYS_CLKCFG_OCP_RATIO_MASK  0xf
+#define CPU_SYS_CLKCFG_OCP_RATIO_1     0       /* 1:1   (Reserved) */
+#define CPU_SYS_CLKCFG_OCP_RATIO_1_5   1       /* 1:1.5 (Reserved) */
+#define CPU_SYS_CLKCFG_OCP_RATIO_2     2       /* 1:2   */
+#define CPU_SYS_CLKCFG_OCP_RATIO_2_5   3       /* 1:2.5 (Reserved) */
+#define CPU_SYS_CLKCFG_OCP_RATIO_3     4       /* 1:3   */
+#define CPU_SYS_CLKCFG_OCP_RATIO_3_5   5       /* 1:3.5 (Reserved) */
+#define CPU_SYS_CLKCFG_OCP_RATIO_4     6       /* 1:4   */
+#define CPU_SYS_CLKCFG_OCP_RATIO_5     7       /* 1:5   */
+#define CPU_SYS_CLKCFG_OCP_RATIO_10    8       /* 1:10  */
+#define CPU_SYS_CLKCFG_CPU_FDIV_SHIFT  8
+#define CPU_SYS_CLKCFG_CPU_FDIV_MASK   0x1f
+#define CPU_SYS_CLKCFG_CPU_FFRAC_SHIFT 0
+#define CPU_SYS_CLKCFG_CPU_FFRAC_MASK  0x1f
+
+#define CPLL_CFG0_SW_CFG               BIT(31)
+#define CPLL_CFG0_PLL_MULT_RATIO_SHIFT 16
+#define CPLL_CFG0_PLL_MULT_RATIO_MASK   0x7
+#define CPLL_CFG0_LC_CURFCK            BIT(15)
+#define CPLL_CFG0_BYPASS_REF_CLK       BIT(14)
+#define CPLL_CFG0_PLL_DIV_RATIO_SHIFT  10
+#define CPLL_CFG0_PLL_DIV_RATIO_MASK   0x3
+
+#define CPLL_CFG1_CPU_AUX1             BIT(25)
+#define CPLL_CFG1_CPU_AUX0             BIT(24)
 
 #define SYSCFG0_DRAM_TYPE_MASK         0x3
 #define SYSCFG0_DRAM_TYPE_SHIFT                4
diff --git a/arch/mips/include/asm/mach-ralink/mt7620/cpu-feature-overrides.h b/arch/mips/include/asm/mach-ralink/mt7620/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..f7bb8cf
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Ralink MT7620 specific CPU feature overrides
+ *
+ * Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * This file was derived from: include/asm-mips/cpu-features.h
+ *     Copyright (C) 2003, 2004 Ralf Baechle
+ *     Copyright (C) 2004 Maciej W. Rozycki
+ *
+ * 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 _MT7620_CPU_FEATURE_OVERRIDES_H
+#define _MT7620_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb            1
+#define cpu_has_4kex           1
+#define cpu_has_3k_cache       0
+#define cpu_has_4k_cache       1
+#define cpu_has_tx39_cache     0
+#define cpu_has_sb1_cache      0
+#define cpu_has_fpu            0
+#define cpu_has_32fpr          0
+#define cpu_has_counter                1
+#define cpu_has_watch          1
+#define cpu_has_divec          1
+
+#define cpu_has_prefetch       1
+#define cpu_has_ejtag          1
+#define cpu_has_llsc           1
+
+#define cpu_has_mips16         1
+#define cpu_has_mdmx           0
+#define cpu_has_mips3d         0
+#define cpu_has_smartmips      0
+
+#define cpu_has_mips32r1       1
+#define cpu_has_mips32r2       1
+#define cpu_has_mips64r1       0
+#define cpu_has_mips64r2       0
+
+#define cpu_has_dsp            1
+#define cpu_has_dsp2           0
+#define cpu_has_mipsmt         0
+
+#define cpu_has_64bits         0
+#define cpu_has_64bit_zero_reg 0
+#define cpu_has_64bit_gp_regs  0
+#define cpu_has_64bit_addresses        0
+
+#define cpu_dcache_line_size() 32
+#define cpu_icache_line_size() 32
+
+#endif /* _MT7620_CPU_FEATURE_OVERRIDES_H */
index fed1c3e9b486b7bf044f66cdedf9e2a1c302c80c..e0331414c7d60f05cab6dc1c40788d513d71da23 100644 (file)
 #define MIPS_CONF4_MMUEXTDEF   (_ULCAST_(3) << 14)
 #define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14)
 
+#define MIPS_CONF5_NF          (_ULCAST_(1) << 0)
+#define MIPS_CONF5_UFR         (_ULCAST_(1) << 2)
+#define MIPS_CONF5_MSAEN       (_ULCAST_(1) << 27)
+#define MIPS_CONF5_EVA         (_ULCAST_(1) << 28)
+#define MIPS_CONF5_CV          (_ULCAST_(1) << 29)
+#define MIPS_CONF5_K           (_ULCAST_(1) << 30)
+
 #define MIPS_CONF6_SYND                (_ULCAST_(1) << 13)
 
 #define MIPS_CONF7_WII         (_ULCAST_(1) << 31)
diff --git a/arch/mips/include/asm/mutex.h b/arch/mips/include/asm/mutex.h
deleted file mode 100644 (file)
index 458c1f7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- * Pull in the generic implementation for the mutex fastpath.
- *
- * TODO: implement optimized primitives instead, or leave the generic
- * implementation in place, or pick the atomic_xchg() based generic
- * implementation. (see asm-generic/mutex-xchg.h for details)
- */
-
-#include <asm-generic/mutex-dec.h>
index 790f0f1e55c6a7bcc271ce26ee509e7cf10eb40d..4e8eacb9588a2b1a69f81d56715c49d719102921 100644 (file)
@@ -88,6 +88,7 @@
 #define BRIDGE_DRAM_LIMIT6             0x22
 #define BRIDGE_DRAM_LIMIT7             0x23
 
+#define BRIDGE_DRAM_NODE_TRANSLN(i)    (0x24 + (i))
 #define BRIDGE_DRAM_NODE_TRANSLN0      0x24
 #define BRIDGE_DRAM_NODE_TRANSLN1      0x25
 #define BRIDGE_DRAM_NODE_TRANSLN2      0x26
@@ -96,6 +97,8 @@
 #define BRIDGE_DRAM_NODE_TRANSLN5      0x29
 #define BRIDGE_DRAM_NODE_TRANSLN6      0x2a
 #define BRIDGE_DRAM_NODE_TRANSLN7      0x2b
+
+#define BRIDGE_DRAM_CHNL_TRANSLN(i)    (0x2c + (i))
 #define BRIDGE_DRAM_CHNL_TRANSLN0      0x2c
 #define BRIDGE_DRAM_CHNL_TRANSLN1      0x2d
 #define BRIDGE_DRAM_CHNL_TRANSLN2      0x2e
 #define BRIDGE_DRAM_CHNL_TRANSLN5      0x31
 #define BRIDGE_DRAM_CHNL_TRANSLN6      0x32
 #define BRIDGE_DRAM_CHNL_TRANSLN7      0x33
+
 #define BRIDGE_PCIEMEM_BASE0           0x34
 #define BRIDGE_PCIEMEM_BASE1           0x35
 #define BRIDGE_PCIEMEM_BASE2           0x36
index 9fac46fb791398a6e76271bb1f229fbad068779e..55eee77adaca5d121affce8e3566fc7476ec113e 100644 (file)
 #define XLP_IO_USB_OHCI2_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 4)
 #define XLP_IO_USB_OHCI3_OFFSET(node)  XLP_HDR_OFFSET(node, 0, 2, 5)
 
+/* XLP2xx has an updated USB block */
+#define XLP2XX_IO_USB_OFFSET(node, i)  XLP_HDR_OFFSET(node, 0, 4, i)
+#define XLP2XX_IO_USB_XHCI0_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 4, 1)
+#define XLP2XX_IO_USB_XHCI1_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 4, 2)
+#define XLP2XX_IO_USB_XHCI2_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 4, 3)
+
 #define XLP_IO_NAE_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 3, 0)
 #define XLP_IO_POE_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 3, 1)
 
@@ -88,6 +94,9 @@
 #define XLP_IO_I2C0_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 2)
 #define XLP_IO_I2C1_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 3)
 #define XLP_IO_GPIO_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 4)
+/* on 2XX, all I2C busses are on the same block */
+#define XLP2XX_IO_I2C_OFFSET(node)     XLP_HDR_OFFSET(node, 0, 6, 7)
+
 /* system management */
 #define XLP_IO_SYS_OFFSET(node)                XLP_HDR_OFFSET(node, 0, 6, 5)
 #define XLP_IO_JTAG_OFFSET(node)       XLP_HDR_OFFSET(node, 0, 6, 6)
 #define PCI_DEVICE_ID_NLM_NOR          0x1015
 #define PCI_DEVICE_ID_NLM_NAND         0x1016
 #define PCI_DEVICE_ID_NLM_MMC          0x1018
+#define PCI_DEVICE_ID_NLM_XHCI         0x101d
 
 #ifndef __ASSEMBLY__
 
index 4b5108dfaa16ade2de259fab7c65e4cae9d05140..105389b79f09392d1d6ebe086adfb4d0ffb9d091 100644 (file)
 #define PIC_LOCAL_SCHEDULING           1
 #define PIC_GLOBAL_SCHEDULING          0
 
-#define PIC_CLK_HZ                     133333333
-
 #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r)
 #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v)
 #define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node))
 #define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ)
 
+/* We use PIC on node 0 as a timer */
+#define pic_timer_freq()               nlm_get_pic_frequency(0)
+
 /* IRT and h/w interrupt routines */
 static inline int
 nlm_pic_read_irt(uint64_t base, int irt_index)
index 470e52bfc061ea5ff9f57f4d966af592be92a8b8..fcf2833c16ca9d42c5119b3250cba8b20452d09e 100644 (file)
 #define SYS_SCRTCH2                            0x4b
 #define SYS_SCRTCH3                            0x4c
 
+/* PLL registers XLP2XX */
+#define SYS_PLL_CTRL0                          0x240
+#define SYS_PLL_CTRL1                          0x241
+#define SYS_PLL_CTRL2                          0x242
+#define SYS_PLL_CTRL3                          0x243
+#define SYS_DMC_PLL_CTRL0                      0x244
+#define SYS_DMC_PLL_CTRL1                      0x245
+#define SYS_DMC_PLL_CTRL2                      0x246
+#define SYS_DMC_PLL_CTRL3                      0x247
+
+#define SYS_PLL_CTRL0_DEVX(x)                  (0x248 + (x) * 4)
+#define SYS_PLL_CTRL1_DEVX(x)                  (0x249 + (x) * 4)
+#define SYS_PLL_CTRL2_DEVX(x)                  (0x24a + (x) * 4)
+#define SYS_PLL_CTRL3_DEVX(x)                  (0x24b + (x) * 4)
+
+#define SYS_CPU_PLL_CHG_CTRL                   0x288
+#define SYS_PLL_CHG_CTRL                       0x289
+#define SYS_CLK_DEV_DIS                                0x28a
+#define SYS_CLK_DEV_SEL                                0x28b
+#define SYS_CLK_DEV_DIV                                0x28c
+#define SYS_CLK_DEV_CHG                                0x28d
+#define SYS_CLK_DEV_SEL_REG                    0x28e
+#define SYS_CLK_DEV_DIV_REG                    0x28f
+#define SYS_CPU_PLL_LOCK                       0x29f
+#define SYS_SYS_PLL_LOCK                       0x2a0
+#define SYS_PLL_MEM_CMD                                0x2a1
+#define SYS_CPU_PLL_MEM_REQ                    0x2a2
+#define SYS_SYS_PLL_MEM_REQ                    0x2a3
+#define SYS_PLL_MEM_STAT                       0x2a4
+
 #ifndef __ASSEMBLY__
 
 #define nlm_read_sys_reg(b, r)         nlm_read_reg(b, r)
 #define nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node))
 #define nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ)
 
+unsigned int nlm_get_pic_frequency(int node);
 #endif
 #endif
index f4ea0f7f39657d1b30554b77c0fc6282e536c14a..17daffb280a30f602dfd3edd119cabe5989a997d 100644 (file)
 #define PIC_PCIE_LINK_1_IRQ            20
 #define PIC_PCIE_LINK_2_IRQ            21
 #define PIC_PCIE_LINK_3_IRQ            22
+
 #define PIC_EHCI_0_IRQ                 23
 #define PIC_EHCI_1_IRQ                 24
 #define PIC_OHCI_0_IRQ                 25
 #define PIC_OHCI_1_IRQ                 26
 #define PIC_OHCI_2_IRQ                 27
 #define PIC_OHCI_3_IRQ                 28
+#define PIC_2XX_XHCI_0_IRQ             23
+#define PIC_2XX_XHCI_1_IRQ             24
+#define PIC_2XX_XHCI_2_IRQ             25
+
 #define PIC_MMC_IRQ                    29
 #define PIC_I2C_0_IRQ                  30
 #define PIC_I2C_1_IRQ                  31
+#define PIC_I2C_2_IRQ                  32
+#define PIC_I2C_3_IRQ                  33
 
 #ifndef __ASSEMBLY__
 
@@ -59,7 +66,17 @@ void xlp_wakeup_secondary_cpus(void);
 
 void xlp_mmu_init(void);
 void nlm_hal_init(void);
+int xlp_get_dram_map(int n, uint64_t *dram_map);
+
+/* Device tree related */
 void *xlp_dt_init(void *fdtp);
 
+static inline int cpu_is_xlpii(void)
+{
+       int chip = read_c0_prid() & 0xff00;
+
+       return chip == PRID_IMP_NETLOGIC_XLP2XX;
+}
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_NLM_XLP_H */
index 63c99176dffe98c29a31c16c561b3766c1ff0b87..3c80a75233bd0a8a53830c669504e7678576517c 100644 (file)
@@ -36,6 +36,8 @@
 #define _ASM_NLM_XLR_PIC_H
 
 #define PIC_CLK_HZ                     66666666
+#define pic_timer_freq()               PIC_CLK_HZ
+
 /* PIC hardware interrupt numbers */
 #define PIC_IRT_WD_INDEX               0
 #define PIC_IRT_TIMER_0_INDEX          1
index a2eed23c49a958145df685d0386bd0cadf20f539..f5d77b91537fc0b67558d2d444b46f527cc382f8 100644 (file)
@@ -251,4 +251,6 @@ extern void (*octeon_irq_setup_secondary)(void);
 typedef void (*octeon_irq_ip4_handler_t)(void);
 void octeon_irq_set_ip4_handler(octeon_irq_ip4_handler_t);
 
+extern void octeon_fixup_irqs(void);
+
 #endif /* __ASM_OCTEON_OCTEON_H */
diff --git a/arch/mips/include/asm/parport.h b/arch/mips/include/asm/parport.h
deleted file mode 100644 (file)
index cf252af..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/parport.h>
index f194c08bd057b58393f37a3ce149eab1a282617f..12d6842962bedc8987a689eeff86aea8e5761a10 100644 (file)
@@ -83,6 +83,18 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
 extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
        enum pci_mmap_state mmap_state, int write_combine);
 
+#define HAVE_ARCH_PCI_RESOURCE_TO_USER
+
+static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
+               const struct resource *rsrc, resource_size_t *start,
+               resource_size_t *end)
+{
+       phys_t size = resource_size(rsrc);
+
+       *start = fixup_bigphys_addr(rsrc->start, size);
+       *end = rsrc->start + size;
+}
+
 /*
  * Dynamic DMA mapping stuff.
  * MIPS has everything mapped statically.
diff --git a/arch/mips/include/asm/percpu.h b/arch/mips/include/asm/percpu.h
deleted file mode 100644 (file)
index 844e763..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_PERCPU_H
-#define __ASM_PERCPU_H
-
-#include <asm-generic/percpu.h>
-
-#endif /* __ASM_PERCPU_H */
diff --git a/arch/mips/include/asm/scatterlist.h b/arch/mips/include/asm/scatterlist.h
deleted file mode 100644 (file)
index 7ee0e64..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __ASM_SCATTERLIST_H
-#define __ASM_SCATTERLIST_H
-
-#include <asm-generic/scatterlist.h>
-
-#endif /* __ASM_SCATTERLIST_H */
diff --git a/arch/mips/include/asm/sections.h b/arch/mips/include/asm/sections.h
deleted file mode 100644 (file)
index b7e3726..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SECTIONS_H
-#define _ASM_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-#endif /* _ASM_SECTIONS_H */
diff --git a/arch/mips/include/asm/segment.h b/arch/mips/include/asm/segment.h
deleted file mode 100644 (file)
index 92ac001..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _ASM_SEGMENT_H
-#define _ASM_SEGMENT_H
-
-/* Only here because we have some old header files that expect it.. */
-
-#endif /* _ASM_SEGMENT_H */
diff --git a/arch/mips/include/asm/serial.h b/arch/mips/include/asm/serial.h
deleted file mode 100644 (file)
index a0cb0ca..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/serial.h>
index 6529704aa73ae0c3cee7789648fb5328b3948168..c5424757da6568dcad750863d7ecabcd312ec08d 100644 (file)
@@ -10,7 +10,9 @@
 
 #ifdef __KERNEL__
 
+#include <asm/cpu-features.h>
 #include <asm/mipsregs.h>
+#include <asm/cpu-type.h>
 
 /*
  * This is the clock rate of the i8253 PIT.  A MIPS system may not have
 
 typedef unsigned int cycles_t;
 
+/*
+ * On R4000/R4400 before version 5.0 an erratum exists such that if the
+ * cycle counter is read in the exact moment that it is matching the
+ * compare register, no interrupt will be generated.
+ *
+ * There is a suggested workaround and also the erratum can't strike if
+ * the compare interrupt isn't being used as the clock source device.
+ * However for now the implementaton of this function doesn't get these
+ * fine details right.
+ */
 static inline cycles_t get_cycles(void)
 {
-       return 0;
+       switch (boot_cpu_type()) {
+       case CPU_R4400PC:
+       case CPU_R4400SC:
+       case CPU_R4400MC:
+               if ((read_c0_prid() & 0xff) >= 0x0050)
+                       return read_c0_count();
+               break;
+
+        case CPU_R4000PC:
+        case CPU_R4000SC:
+        case CPU_R4000MC:
+               break;
+
+       default:
+               if (cpu_has_counter)
+                       return read_c0_count();
+               break;
+       }
+
+       return 0;       /* no usable counter */
 }
 
 #endif /* __KERNEL__ */
diff --git a/arch/mips/include/asm/ucontext.h b/arch/mips/include/asm/ucontext.h
deleted file mode 100644 (file)
index 9bc07b9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ucontext.h>
index f4cff7e4fa8a2a531a80e2374eb4056c46dab7aa..f82c83749a089bf26d5a06846ebd73edcc4130a8 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef _ASM_VGA_H
 #define _ASM_VGA_H
 
+#include <asm/addrspace.h>
 #include <asm/byteorder.h>
 
 /*
@@ -13,7 +14,7 @@
  *     access the videoram directly without any black magic.
  */
 
-#define VGA_MAP_MEM(x, s)      (0xb0000000L + (unsigned long)(x))
+#define VGA_MAP_MEM(x, s)      CKSEG1ADDR(0x10000000L + (unsigned long)(x))
 
 #define vga_readb(x)   (*(x))
 #define vga_writeb(x, y)       (*(y) = (x))
diff --git a/arch/mips/include/asm/xor.h b/arch/mips/include/asm/xor.h
deleted file mode 100644 (file)
index c82eb12..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/xor.h>
index 350ccccadcb99e3696540d77a208989b93ac01a4..be7196eacb8890a1875123a6473ee620d65f5514 100644 (file)
@@ -1,7 +1,9 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
-header-y += auxvec.h
+generic-y += auxvec.h
+generic-y += ipcbuf.h
+
 header-y += bitsperlong.h
 header-y += break.h
 header-y += byteorder.h
@@ -11,7 +13,6 @@ header-y += fcntl.h
 header-y += inst.h
 header-y += ioctl.h
 header-y += ioctls.h
-header-y += ipcbuf.h
 header-y += kvm_para.h
 header-y += mman.h
 header-y += msgbuf.h
diff --git a/arch/mips/include/uapi/asm/auxvec.h b/arch/mips/include/uapi/asm/auxvec.h
deleted file mode 100644 (file)
index 7cf7f2d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef _ASM_AUXVEC_H
-#define _ASM_AUXVEC_H
-
-#endif /* _ASM_AUXVEC_H */
diff --git a/arch/mips/include/uapi/asm/ipcbuf.h b/arch/mips/include/uapi/asm/ipcbuf.h
deleted file mode 100644 (file)
index 84c7e51..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/ipcbuf.h>
index 4c6167a178754ecab7b0b456129c6d979626b399..5465dc183e5ac4d26e36d300b1df36fb4cf4d2b5 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <asm/bugs.h>
 #include <asm/cpu.h>
+#include <asm/cpu-type.h>
 #include <asm/fpu.h>
 #include <asm/mipsregs.h>
 #include <asm/watch.h>
@@ -55,7 +56,7 @@ static inline void check_errata(void)
 {
        struct cpuinfo_mips *c = &current_cpu_data;
 
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_34K:
                /*
                 * Erratum "RPS May Cause Incorrect Instruction Execution"
@@ -122,7 +123,7 @@ static inline unsigned long cpu_get_fpu_id(void)
  */
 static inline int __cpu_has_fpu(void)
 {
-       return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
+       return ((cpu_get_fpu_id() & FPIR_IMP_MASK) != FPIR_IMP_NONE);
 }
 
 static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
@@ -290,6 +291,17 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c)
        return config4 & MIPS_CONF_M;
 }
 
+static inline unsigned int decode_config5(struct cpuinfo_mips *c)
+{
+       unsigned int config5;
+
+       config5 = read_c0_config5();
+       config5 &= ~MIPS_CONF5_UFR;
+       write_c0_config5(config5);
+
+       return config5 & MIPS_CONF_M;
+}
+
 static void decode_configs(struct cpuinfo_mips *c)
 {
        int ok;
@@ -310,6 +322,8 @@ static void decode_configs(struct cpuinfo_mips *c)
                ok = decode_config3(c);
        if (ok)
                ok = decode_config4(c);
+       if (ok)
+               ok = decode_config5(c);
 
        mips_probe_watch_registers(c);
 
@@ -322,7 +336,7 @@ static void decode_configs(struct cpuinfo_mips *c)
 
 static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
 {
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_R2000:
                c->cputype = CPU_R2000;
                __cpu_name[cpu] = "R2000";
@@ -333,7 +347,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                c->tlbsize = 64;
                break;
        case PRID_IMP_R3000:
-               if ((c->processor_id & 0xff) == PRID_REV_R3000A) {
+               if ((c->processor_id & PRID_REV_MASK) == PRID_REV_R3000A) {
                        if (cpu_has_confreg()) {
                                c->cputype = CPU_R3081E;
                                __cpu_name[cpu] = "R3081";
@@ -353,7 +367,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                break;
        case PRID_IMP_R4000:
                if (read_c0_config() & CONF_SC) {
-                       if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+                       if ((c->processor_id & PRID_REV_MASK) >=
+                           PRID_REV_R4400) {
                                c->cputype = CPU_R4400PC;
                                __cpu_name[cpu] = "R4400PC";
                        } else {
@@ -361,7 +376,8 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                                __cpu_name[cpu] = "R4000PC";
                        }
                } else {
-                       if ((c->processor_id & 0xff) >= PRID_REV_R4400) {
+                       if ((c->processor_id & PRID_REV_MASK) >=
+                           PRID_REV_R4400) {
                                c->cputype = CPU_R4400SC;
                                __cpu_name[cpu] = "R4400SC";
                        } else {
@@ -454,7 +470,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
                        __cpu_name[cpu] = "TX3927";
                        c->tlbsize = 64;
                } else {
-                       switch (c->processor_id & 0xff) {
+                       switch (c->processor_id & PRID_REV_MASK) {
                        case PRID_REV_TX3912:
                                c->cputype = CPU_TX3912;
                                __cpu_name[cpu] = "TX3912";
@@ -640,7 +656,7 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
 static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_4KC:
                c->cputype = CPU_4KC;
                __cpu_name[cpu] = "MIPS 4Kc";
@@ -711,7 +727,7 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
 static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_AU1_REV1:
        case PRID_IMP_AU1_REV2:
                c->cputype = CPU_ALCHEMY;
@@ -730,7 +746,7 @@ static inline void cpu_probe_alchemy(struct cpuinfo_mips *c, unsigned int cpu)
                        break;
                case 4:
                        __cpu_name[cpu] = "Au1200";
-                       if ((c->processor_id & 0xff) == 2)
+                       if ((c->processor_id & PRID_REV_MASK) == 2)
                                __cpu_name[cpu] = "Au1250";
                        break;
                case 5:
@@ -748,12 +764,12 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
 
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_SB1:
                c->cputype = CPU_SB1;
                __cpu_name[cpu] = "SiByte SB1";
                /* FPU in pass1 is known to have issues. */
-               if ((c->processor_id & 0xff) < 0x02)
+               if ((c->processor_id & PRID_REV_MASK) < 0x02)
                        c->options &= ~(MIPS_CPU_FPU | MIPS_CPU_32FPR);
                break;
        case PRID_IMP_SB1A:
@@ -766,7 +782,7 @@ static inline void cpu_probe_sibyte(struct cpuinfo_mips *c, unsigned int cpu)
 static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_SR71000:
                c->cputype = CPU_SR71000;
                __cpu_name[cpu] = "Sandcraft SR71000";
@@ -779,7 +795,7 @@ static inline void cpu_probe_sandcraft(struct cpuinfo_mips *c, unsigned int cpu)
 static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_PR4450:
                c->cputype = CPU_PR4450;
                __cpu_name[cpu] = "Philips PR4450";
@@ -791,7 +807,7 @@ static inline void cpu_probe_nxp(struct cpuinfo_mips *c, unsigned int cpu)
 static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_BMIPS32_REV4:
        case PRID_IMP_BMIPS32_REV8:
                c->cputype = CPU_BMIPS32;
@@ -806,7 +822,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
                set_elf_platform(cpu, "bmips3300");
                break;
        case PRID_IMP_BMIPS43XX: {
-               int rev = c->processor_id & 0xff;
+               int rev = c->processor_id & PRID_REV_MASK;
 
                if (rev >= PRID_REV_BMIPS4380_LO &&
                                rev <= PRID_REV_BMIPS4380_HI) {
@@ -832,7 +848,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
 static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
 {
        decode_configs(c);
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_CAVIUM_CN38XX:
        case PRID_IMP_CAVIUM_CN31XX:
        case PRID_IMP_CAVIUM_CN30XX:
@@ -852,10 +868,17 @@ platform:
        case PRID_IMP_CAVIUM_CN63XX:
        case PRID_IMP_CAVIUM_CN66XX:
        case PRID_IMP_CAVIUM_CN68XX:
+       case PRID_IMP_CAVIUM_CNF71XX:
                c->cputype = CPU_CAVIUM_OCTEON2;
                __cpu_name[cpu] = "Cavium Octeon II";
                set_elf_platform(cpu, "octeon2");
                break;
+       case PRID_IMP_CAVIUM_CN70XX:
+       case PRID_IMP_CAVIUM_CN78XX:
+               c->cputype = CPU_CAVIUM_OCTEON3;
+               __cpu_name[cpu] = "Cavium Octeon III";
+               set_elf_platform(cpu, "octeon3");
+               break;
        default:
                printk(KERN_INFO "Unknown Octeon chip!\n");
                c->cputype = CPU_UNKNOWN;
@@ -868,7 +891,7 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu)
        decode_configs(c);
        /* JZRISC does not implement the CP0 counter. */
        c->options &= ~MIPS_CPU_COUNTER;
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_JZRISC:
                c->cputype = CPU_JZRISC;
                __cpu_name[cpu] = "Ingenic JZRISC";
@@ -883,7 +906,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
 {
        decode_configs(c);
 
-       if ((c->processor_id & 0xff00) == PRID_IMP_NETLOGIC_AU13XX) {
+       if ((c->processor_id & PRID_IMP_MASK) == PRID_IMP_NETLOGIC_AU13XX) {
                c->cputype = CPU_ALCHEMY;
                __cpu_name[cpu] = "Au1300";
                /* following stuff is not for Alchemy */
@@ -898,7 +921,12 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
                        MIPS_CPU_EJTAG   |
                        MIPS_CPU_LLSC);
 
-       switch (c->processor_id & 0xff00) {
+       switch (c->processor_id & PRID_IMP_MASK) {
+       case PRID_IMP_NETLOGIC_XLP2XX:
+               c->cputype = CPU_XLP;
+               __cpu_name[cpu] = "Broadcom XLPII";
+               break;
+
        case PRID_IMP_NETLOGIC_XLP8XX:
        case PRID_IMP_NETLOGIC_XLP3XX:
                c->cputype = CPU_XLP;
@@ -972,7 +1000,7 @@ void cpu_probe(void)
        c->cputype      = CPU_UNKNOWN;
 
        c->processor_id = read_c0_prid();
-       switch (c->processor_id & 0xff0000) {
+       switch (c->processor_id & PRID_COMP_MASK) {
        case PRID_COMP_LEGACY:
                cpu_probe_legacy(c, cpu);
                break;
index 0654bff9b69c5b0ea701e965cf3b7587d9dc4dd1..6cbbf6e106b97e4df26060ab285b5525a8085291 100644 (file)
@@ -37,13 +37,13 @@ static struct clocksource clocksource_dec = {
        .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
 };
 
-void __init dec_ioasic_clocksource_init(void)
+int __init dec_ioasic_clocksource_init(void)
 {
        unsigned int freq;
        u32 start, end;
-       int i = HZ / 10;
-
+       int i = HZ / 8;
 
+       ds1287_timer_state();
        while (!ds1287_timer_state())
                ;
 
@@ -55,9 +55,15 @@ void __init dec_ioasic_clocksource_init(void)
 
        end = dec_ioasic_hpt_read(&clocksource_dec);
 
-       freq = (end - start) * 10;
+       freq = (end - start) * 8;
+
+       /* An early revision of the I/O ASIC didn't have the counter.  */
+       if (!freq)
+               return -ENXIO;
+
        printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq);
 
        clocksource_dec.rating = 200 + freq / 10000000;
        clocksource_register_hz(&clocksource_dec, freq);
+       return 0;
 }
index 0c655deeea4adff8fd575cd5d09b372cd3f820e5..f7991d95bff9a67374501ee4b3ce5f3c25973742 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <asm/cpu.h>
 #include <asm/cpu-info.h>
+#include <asm/cpu-type.h>
 #include <asm/idle.h>
 #include <asm/mipsregs.h>
 
@@ -136,7 +137,7 @@ void __init check_wait(void)
                return;
        }
 
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_R3081:
        case CPU_R3081E:
                cpu_wait = r3081_wait;
@@ -166,6 +167,7 @@ void __init check_wait(void)
        case CPU_CAVIUM_OCTEON:
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
+       case CPU_CAVIUM_OCTEON3:
        case CPU_JZRISC:
        case CPU_LOONGSON1:
        case CPU_XLR:
index a03e93c4a94634b786c873f41e8b2f56846bad26..539b6294b613c84fcff1286d267c4b7a5aba401c 100644 (file)
@@ -83,7 +83,7 @@ _mcount:
        PTR_S   MCOUNT_RA_ADDRESS_REG, PT_R12(sp)
 #endif
 
-       move    a0, ra          /* arg1: self return address */
+       PTR_SUBU a0, ra, 8      /* arg1: self address */
        .globl ftrace_call
 ftrace_call:
        nop     /* a placeholder for the call to a real tracing function */
index 7e954042f2526e66f21579f73d609452a5b1d726..0fa0b69cdd53bcc7e7d7d0bf836d3e40c767b4a4 100644 (file)
@@ -58,8 +58,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 43d2d78d3287dfbfa52ad7fb1a52f6571d9deaa3..74bab9ddd0e1984c9d4e4e95c038bb1d269b60dd 100644 (file)
@@ -26,6 +26,12 @@ process_entry:
        PTR_L           s2, (s0)
        PTR_ADD         s0, s0, SZREG
 
+       /*
+        * In case of a kdump/crash kernel, the indirection page is not
+        * populated as the kernel is directly copied to a reserved location
+        */
+       beqz            s2, done
+
        /* destination page */
        and             s3, s2, 0x1
        beq             s3, zero, 1f
index c7f90519e58ce0ade98dd826752fbaa1d2287da0..c538d6e01b7b744cb4af330a5de15b78963cfa7f 100644 (file)
@@ -552,6 +552,52 @@ static void __init arch_mem_addpart(phys_t mem, phys_t end, int type)
        add_memory_region(mem, size, type);
 }
 
+#ifdef CONFIG_KEXEC
+static inline unsigned long long get_total_mem(void)
+{
+       unsigned long long total;
+
+       total = max_pfn - min_low_pfn;
+       return total << PAGE_SHIFT;
+}
+
+static void __init mips_parse_crashkernel(void)
+{
+       unsigned long long total_mem;
+       unsigned long long crash_size, crash_base;
+       int ret;
+
+       total_mem = get_total_mem();
+       ret = parse_crashkernel(boot_command_line, total_mem,
+                               &crash_size, &crash_base);
+       if (ret != 0 || crash_size <= 0)
+               return;
+
+       crashk_res.start = crash_base;
+       crashk_res.end   = crash_base + crash_size - 1;
+}
+
+static void __init request_crashkernel(struct resource *res)
+{
+       int ret;
+
+       ret = request_resource(res, &crashk_res);
+       if (!ret)
+               pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
+                       (unsigned long)((crashk_res.end -
+                                        crashk_res.start + 1) >> 20),
+                       (unsigned long)(crashk_res.start  >> 20));
+}
+#else /* !defined(CONFIG_KEXEC)                */
+static void __init mips_parse_crashkernel(void)
+{
+}
+
+static void __init request_crashkernel(struct resource *res)
+{
+}
+#endif /* !defined(CONFIG_KEXEC)  */
+
 static void __init arch_mem_init(char **cmdline_p)
 {
        extern void plat_mem_setup(void);
@@ -608,6 +654,8 @@ static void __init arch_mem_init(char **cmdline_p)
                                BOOTMEM_DEFAULT);
        }
 #endif
+
+       mips_parse_crashkernel();
 #ifdef CONFIG_KEXEC
        if (crashk_res.start != crashk_res.end)
                reserve_bootmem(crashk_res.start,
@@ -620,52 +668,6 @@ static void __init arch_mem_init(char **cmdline_p)
        paging_init();
 }
 
-#ifdef CONFIG_KEXEC
-static inline unsigned long long get_total_mem(void)
-{
-       unsigned long long total;
-
-       total = max_pfn - min_low_pfn;
-       return total << PAGE_SHIFT;
-}
-
-static void __init mips_parse_crashkernel(void)
-{
-       unsigned long long total_mem;
-       unsigned long long crash_size, crash_base;
-       int ret;
-
-       total_mem = get_total_mem();
-       ret = parse_crashkernel(boot_command_line, total_mem,
-                               &crash_size, &crash_base);
-       if (ret != 0 || crash_size <= 0)
-               return;
-
-       crashk_res.start = crash_base;
-       crashk_res.end   = crash_base + crash_size - 1;
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
-       int ret;
-
-       ret = request_resource(res, &crashk_res);
-       if (!ret)
-               pr_info("Reserving %ldMB of memory at %ldMB for crashkernel\n",
-                       (unsigned long)((crashk_res.end -
-                               crashk_res.start + 1) >> 20),
-                       (unsigned long)(crashk_res.start  >> 20));
-}
-#else /* !defined(CONFIG_KEXEC)         */
-static void __init mips_parse_crashkernel(void)
-{
-}
-
-static void __init request_crashkernel(struct resource *res)
-{
-}
-#endif /* !defined(CONFIG_KEXEC)  */
-
 static void __init resource_init(void)
 {
        int i;
@@ -678,11 +680,6 @@ static void __init resource_init(void)
        data_resource.start = __pa_symbol(&_etext);
        data_resource.end = __pa_symbol(&_edata) - 1;
 
-       /*
-        * Request address space for all standard RAM.
-        */
-       mips_parse_crashkernel();
-
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                struct resource *res;
                unsigned long start, end;
index c2e5d74739b49fa6dcd8be06dd6e51b7b71864e4..5969f1e9b62a5c2b8fa0fc2645de79bc1dfa4aa7 100644 (file)
@@ -99,7 +99,9 @@ static void cmp_init_secondary(void)
 
        c->core = (read_c0_ebase() >> 1) & 0x1ff;
 #if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
-       c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) & TCBIND_CURVPE;
+       if (cpu_has_mipsmt)
+               c->vpe_id = (read_c0_tcbind() >> TCBIND_CURVPE_SHIFT) &
+                       TCBIND_CURVPE;
 #endif
 #ifdef CONFIG_MIPS_MT_SMTC
        c->tc_id  = (read_c0_tcbind() & TCBIND_CURTC) >> TCBIND_CURTC_SHIFT;
@@ -177,9 +179,16 @@ void __init cmp_smp_setup(void)
        }
 
        if (cpu_has_mipsmt) {
-               unsigned int nvpe, mvpconf0 = read_c0_mvpconf0();
+               unsigned int nvpe = 1;
+#ifdef CONFIG_MIPS_MT_SMP
+               unsigned int mvpconf0 = read_c0_mvpconf0();
+
+               nvpe = ((mvpconf0 & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+#elif defined(CONFIG_MIPS_MT_SMTC)
+               unsigned int mvpconf0 = read_c0_mvpconf0();
 
                nvpe = ((mvpconf0 & MVPCONF0_PTC) >> MVPCONF0_PTC_SHIFT) + 1;
+#endif
                smp_num_siblings = nvpe;
        }
        pr_info("Detected %i available secondary CPU(s)\n", ncpu);
index 9d686bf97b0e35a598dfe3c5711553b5148d8329..dcb8e5d3bb8a11d603e8829cc88739215206ca7b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/export.h>
 
 #include <asm/cpu-features.h>
+#include <asm/cpu-type.h>
 #include <asm/div64.h>
 #include <asm/smtc_ipi.h>
 #include <asm/time.h>
@@ -121,6 +122,14 @@ void __init time_init(void)
 {
        plat_time_init();
 
-       if (!mips_clockevent_init() || !cpu_has_mfc0_count_bug())
+       /*
+        * The use of the R4k timer as a clock event takes precedence;
+        * if reading the Count register might interfere with the timer
+        * interrupt, then we don't use the timer as a clock source.
+        * We may still use the timer as a clock source though if the
+        * timer interrupt isn't reliable; the interference doesn't
+        * matter then, because we don't use the interrupt.
+        */
+       if (mips_clockevent_init() != 0 || !cpu_has_mfc0_count_bug())
                init_mips_clocksource();
 }
index aec3408edd4b9c52d6d1b69bc68ac60368e60b48..524841f0280370600966d20f38b41d0eefdb4744 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/break.h>
 #include <asm/cop2.h>
 #include <asm/cpu.h>
+#include <asm/cpu-type.h>
 #include <asm/dsp.h>
 #include <asm/fpu.h>
 #include <asm/fpu_emulator.h>
@@ -622,7 +623,7 @@ static int simulate_rdhwr(struct pt_regs *regs, int rd, int rt)
                regs->regs[rt] = read_c0_count();
                return 0;
        case 3:         /* Count register resolution */
-               switch (current_cpu_data.cputype) {
+               switch (current_cpu_type()) {
                case CPU_20KC:
                case CPU_25KF:
                        regs->regs[rt] = 1;
index 05826d20a7923a47d06a7affb196f6388c6f1d70..3b46f7ce9ca75bc5f81f9bb2939880277289bd20 100644 (file)
@@ -179,5 +179,6 @@ SECTIONS
                *(.options)
                *(.pdr)
                *(.reginfo)
+               *(.eh_frame)
        }
 }
index faf84c5f26293d130089f0b50d10709b13927a69..59b2b3cd78852d8d41a16c7d4752cfc6557123a8 100644 (file)
@@ -1368,7 +1368,7 @@ out_einval:
 }
 static DEVICE_ATTR_RW(ntcs);
 
-static struct attribute vpe_attrs[] = {
+static struct attribute *vpe_attrs[] = {
        &dev_attr_kill.attr,
        &dev_attr_ntcs.attr,
        NULL,
index ff4894a833eef290d111351ef78719459e9ddba2..8f1866d8124d67b2fd3ba3f3a31063933b826d29 100644 (file)
@@ -48,6 +48,7 @@
 #define CPU0CC_CPUDIV          0x0001
 
 /* Activation Status Register */
+#define ACTS_ASC0_ACT  0x00001000
 #define ACTS_ASC1_ACT  0x00000800
 #define ACTS_I2C_ACT   0x00004000
 #define ACTS_P0                0x00010000
@@ -108,6 +109,7 @@ static void sysctl_deactivate(struct clk *clk)
 static int sysctl_clken(struct clk *clk)
 {
        sysctl_w32(clk->module, clk->bits, SYSCTL_CLKEN);
+       sysctl_w32(clk->module, clk->bits, SYSCTL_ACT);
        sysctl_wait(clk, clk->bits, SYSCTL_CLKS);
        return 0;
 }
@@ -256,6 +258,7 @@ void __init ltq_soc_init(void)
        clkdev_add_sys("1e800400.pad", SYSCTL_SYS1, ACTS_PADCTRL1);
        clkdev_add_sys("1e800500.pad", SYSCTL_SYS1, ACTS_PADCTRL3);
        clkdev_add_sys("1e800600.pad", SYSCTL_SYS1, ACTS_PADCTRL4);
-       clkdev_add_sys("1e100C00.serial", SYSCTL_SYS1, ACTS_ASC1_ACT);
+       clkdev_add_sys("1e100b00.serial", SYSCTL_SYS1, ACTS_ASC1_ACT);
+       clkdev_add_sys("1e100c00.serial", SYSCTL_SYS1, ACTS_ASC0_ACT);
        clkdev_add_sys("1e200000.i2c", SYSCTL_SYS1, ACTS_I2C_ACT);
 }
index 7a13660d630d1303af12f98d53abfcbf51367287..087497d9735789047b89dbe4d00d14431ef7a376 100644 (file)
@@ -1,3 +1,3 @@
-obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o
+obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o dcdc.o
 
 obj-$(CONFIG_XRX200_PHY_FW) += xrx200_phy_fw.o
diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c
new file mode 100644 (file)
index 0000000..7688ac0
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License version 2 as published
+ *  by the Free Software Foundation.
+ *
+ *  Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ *  Copyright (C) 2010 Sameer Ahmad, Lantiq GmbH
+ */
+
+#include <linux/ioport.h>
+#include <linux/of_platform.h>
+
+#include <lantiq_soc.h>
+
+/* Bias and regulator Setup Register */
+#define DCDC_BIAS_VREG0        0xa
+/* Bias and regulator Setup Register */
+#define DCDC_BIAS_VREG1        0xb
+
+#define dcdc_w8(x, y)  ltq_w8((x), dcdc_membase + (y))
+#define dcdc_r8(x)     ltq_r8(dcdc_membase + (x))
+
+static void __iomem *dcdc_membase;
+
+static int dcdc_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dcdc_membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dcdc_membase))
+               return PTR_ERR(dcdc_membase);
+
+       dev_info(&pdev->dev, "Core Voltage : %d mV\n",
+               dcdc_r8(DCDC_BIAS_VREG1) * 8);
+
+       return 0;
+}
+
+static const struct of_device_id dcdc_match[] = {
+       { .compatible = "lantiq,dcdc-xrx200" },
+       {},
+};
+
+static struct platform_driver dcdc_driver = {
+       .probe = dcdc_probe,
+       .driver = {
+               .name = "dcdc-xrx200",
+               .owner = THIS_MODULE,
+               .of_match_table = dcdc_match,
+       },
+};
+
+int __init dcdc_init(void)
+{
+       int ret = platform_driver_register(&dcdc_driver);
+
+       if (ret)
+               pr_info("dcdc: Error registering platform driver\n");
+       return ret;
+}
+
+arch_initcall(dcdc_init);
index dfb509d21d8e544e4c552b7b222f901e90930aaa..fd32075679c66b3fc6cf2ebdff6e3f15fb3a83c6 100644 (file)
@@ -13,13 +13,11 @@ endif
 MKLASATIMG = mklasatimg
 MKLASATIMG_ARCH = mq2,mqpro,sp100,sp200
 KERNEL_IMAGE = vmlinux
-KERNEL_START = $(shell $(NM) $(KERNEL_IMAGE) | grep " _text" | cut -f1 -d\ )
-KERNEL_ENTRY = $(shell $(NM) $(KERNEL_IMAGE) | grep kernel_entry | cut -f1 -d\ )
 
 LDSCRIPT= -L$(srctree)/$(src) -Tromscript.normal
 
-HEAD_DEFINES := -D_kernel_start=0x$(KERNEL_START) \
-               -D_kernel_entry=0x$(KERNEL_ENTRY) \
+HEAD_DEFINES := -D_kernel_start=$(VMLINUX_LOAD_ADDRESS) \
+               -D_kernel_entry=$(VMLINUX_ENTRY_ADDRESS) \
                -D VERSION="\"$(Version)\"" \
                -D TIMESTAMP=$(shell date +%s)
 
index 4c57b3e5743f749f8be549605cabdbf56b2d677b..9e4484ccbb036e91c0dc849421d24accc1d06729 100644 (file)
@@ -3,8 +3,9 @@
 #
 
 obj-y += setup.o init.o cmdline.o env.o time.o reset.o irq.o \
-    pci.o bonito-irq.o mem.o machtype.o platform.o
+    bonito-irq.o mem.o machtype.o platform.o
 obj-$(CONFIG_GPIOLIB) += gpio.o
+obj-$(CONFIG_PCI) += pci.o
 
 #
 # Serial port support
index 46048d24328c759b0bf4189c612929015f139f69..efe008846ed056759dd2e66c83a54cfe2d4d789c 100644 (file)
@@ -436,7 +436,6 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
                                break;
                        default:
                                return SIGILL;
-                               break;
                        }
                        break;
                case mm_32f_74_op:      /* c.cond.fmt */
@@ -451,12 +450,10 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
                        break;
                default:
                        return SIGILL;
-                       break;
                }
                break;
        default:
                return SIGILL;
-               break;
        }
 
        *insn_ptr = mips32_insn;
@@ -491,7 +488,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                                dec_insn.next_pc_inc;
                                *contpc = regs->regs[insn.mm_i_format.rs];
                                return 1;
-                               break;
                        }
                }
                break;
@@ -513,7 +509,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        return 1;
-                       break;
                case mm_bgezals_op:
                case mm_bgezal_op:
                        regs->regs[31] = regs->cp0_epc +
@@ -530,7 +525,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        return 1;
-                       break;
                case mm_blez_op:
                        if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
                                *contpc = regs->cp0_epc +
@@ -541,7 +535,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        return 1;
-                       break;
                case mm_bgtz_op:
                        if ((long)regs->regs[insn.mm_i_format.rs] <= 0)
                                *contpc = regs->cp0_epc +
@@ -552,7 +545,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        return 1;
-                       break;
                case mm_bc2f_op:
                case mm_bc1f_op:
                        bc_false = 1;
@@ -580,7 +572,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                *contpc = regs->cp0_epc +
                                        dec_insn.pc_inc + dec_insn.next_pc_inc;
                        return 1;
-                       break;
                }
                break;
        case mm_pool16c_op:
@@ -593,7 +584,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                case mm_jr16_op:
                        *contpc = regs->regs[insn.mm_i_format.rs];
                        return 1;
-                       break;
                }
                break;
        case mm_beqz16_op:
@@ -605,7 +595,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        *contpc = regs->cp0_epc +
                                dec_insn.pc_inc + dec_insn.next_pc_inc;
                return 1;
-               break;
        case mm_bnez16_op:
                if ((long)regs->regs[reg16to32map[insn.mm_b1_format.rs]] != 0)
                        *contpc = regs->cp0_epc +
@@ -615,12 +604,10 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        *contpc = regs->cp0_epc +
                                dec_insn.pc_inc + dec_insn.next_pc_inc;
                return 1;
-               break;
        case mm_b16_op:
                *contpc = regs->cp0_epc + dec_insn.pc_inc +
                         (insn.mm_b0_format.simmediate << 1);
                return 1;
-               break;
        case mm_beq32_op:
                if (regs->regs[insn.mm_i_format.rs] ==
                    regs->regs[insn.mm_i_format.rt])
@@ -632,7 +619,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-               break;
        case mm_bne32_op:
                if (regs->regs[insn.mm_i_format.rs] !=
                    regs->regs[insn.mm_i_format.rt])
@@ -643,7 +629,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                        *contpc = regs->cp0_epc +
                                dec_insn.pc_inc + dec_insn.next_pc_inc;
                return 1;
-               break;
        case mm_jalx32_op:
                regs->regs[31] = regs->cp0_epc +
                        dec_insn.pc_inc + dec_insn.next_pc_inc;
@@ -652,7 +637,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                *contpc <<= 28;
                *contpc |= (insn.j_format.target << 2);
                return 1;
-               break;
        case mm_jals32_op:
        case mm_jal32_op:
                regs->regs[31] = regs->cp0_epc +
@@ -665,7 +649,6 @@ int mm_isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                *contpc |= (insn.j_format.target << 1);
                set_isa16_mode(*contpc);
                return 1;
-               break;
        }
        return 0;
 }
@@ -694,7 +677,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                case jr_op:
                        *contpc = regs->regs[insn.r_format.rs];
                        return 1;
-                       break;
                }
                break;
        case bcond_op:
@@ -716,7 +698,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        return 1;
-                       break;
                case bgezal_op:
                case bgezall_op:
                        regs->regs[31] = regs->cp0_epc +
@@ -734,7 +715,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                        dec_insn.pc_inc +
                                        dec_insn.next_pc_inc;
                        return 1;
-                       break;
                }
                break;
        case jalx_op:
@@ -752,7 +732,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                /* Set microMIPS mode bit: XOR for jalx. */
                *contpc ^= bit;
                return 1;
-               break;
        case beq_op:
        case beql_op:
                if (regs->regs[insn.i_format.rs] ==
@@ -765,7 +744,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-               break;
        case bne_op:
        case bnel_op:
                if (regs->regs[insn.i_format.rs] !=
@@ -778,7 +756,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-               break;
        case blez_op:
        case blezl_op:
                if ((long)regs->regs[insn.i_format.rs] <= 0)
@@ -790,7 +767,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-               break;
        case bgtz_op:
        case bgtzl_op:
                if ((long)regs->regs[insn.i_format.rs] > 0)
@@ -802,7 +778,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                dec_insn.pc_inc +
                                dec_insn.next_pc_inc;
                return 1;
-               break;
 #ifdef CONFIG_CPU_CAVIUM_OCTEON
        case lwc2_op: /* This is bbit0 on Octeon */
                if ((regs->regs[insn.i_format.rs] & (1ull<<insn.i_format.rt)) == 0)
@@ -856,7 +831,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                                dec_insn.pc_inc +
                                                dec_insn.next_pc_inc;
                                return 1;
-                               break;
                        case 1: /* bc1t */
                        case 3: /* bc1tl */
                                if (fcr31 & (1 << bit))
@@ -868,7 +842,6 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
                                                dec_insn.pc_inc +
                                                dec_insn.next_pc_inc;
                                return 1;
-                               break;
                        }
                }
                break;
index a0bcdbb81d410c31fd41507dd4f0d200e3eb865b..c8efdb5b6ee0297df1799fe41a3ca94750688119 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/bootinfo.h>
 #include <asm/cacheops.h>
 #include <asm/cpu-features.h>
+#include <asm/cpu-type.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/r4kcache.h>
@@ -186,9 +187,10 @@ static void probe_octeon(void)
        unsigned long dcache_size;
        unsigned int config1;
        struct cpuinfo_mips *c = &current_cpu_data;
+       int cputype = current_cpu_type();
 
        config1 = read_c0_config1();
-       switch (c->cputype) {
+       switch (cputype) {
        case CPU_CAVIUM_OCTEON:
        case CPU_CAVIUM_OCTEON_PLUS:
                c->icache.linesz = 2 << ((config1 >> 19) & 7);
@@ -199,7 +201,7 @@ static void probe_octeon(void)
                        c->icache.sets * c->icache.ways * c->icache.linesz;
                c->icache.waybit = ffs(icache_size / c->icache.ways) - 1;
                c->dcache.linesz = 128;
-               if (c->cputype == CPU_CAVIUM_OCTEON_PLUS)
+               if (cputype == CPU_CAVIUM_OCTEON_PLUS)
                        c->dcache.sets = 2; /* CN5XXX has two Dcache sets */
                else
                        c->dcache.sets = 1; /* CN3XXX has one Dcache set */
@@ -224,6 +226,20 @@ static void probe_octeon(void)
                c->options |= MIPS_CPU_PREFETCH;
                break;
 
+       case CPU_CAVIUM_OCTEON3:
+               c->icache.linesz = 128;
+               c->icache.sets = 16;
+               c->icache.ways = 39;
+               c->icache.flags |= MIPS_CACHE_VTAG;
+               icache_size = c->icache.sets * c->icache.ways * c->icache.linesz;
+
+               c->dcache.linesz = 128;
+               c->dcache.ways = 32;
+               c->dcache.sets = 8;
+               dcache_size = c->dcache.sets * c->dcache.ways * c->dcache.linesz;
+               c->options |= MIPS_CPU_PREFETCH;
+               break;
+
        default:
                panic("Unsupported Cavium Networks CPU type");
                break;
index f749f687ee87796e118a13d9807a917b54549d69..627883bc6d5f29f4a4510373ddb8e552398cb5ed 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/highmem.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
+#include <linux/preempt.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
@@ -24,6 +25,7 @@
 #include <asm/cacheops.h>
 #include <asm/cpu.h>
 #include <asm/cpu-features.h>
+#include <asm/cpu-type.h>
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -601,6 +603,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
        /* Catch bad driver code */
        BUG_ON(size == 0);
 
+       preempt_disable();
        if (cpu_has_inclusive_pcaches) {
                if (size >= scache_size)
                        r4k_blast_scache();
@@ -621,6 +624,7 @@ static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
                R4600_HIT_CACHEOP_WAR_IMPL;
                blast_dcache_range(addr, addr + size);
        }
+       preempt_enable();
 
        bc_wback_inv(addr, size);
        __sync();
@@ -631,6 +635,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
        /* Catch bad driver code */
        BUG_ON(size == 0);
 
+       preempt_disable();
        if (cpu_has_inclusive_pcaches) {
                if (size >= scache_size)
                        r4k_blast_scache();
@@ -655,6 +660,7 @@ static void r4k_dma_cache_inv(unsigned long addr, unsigned long size)
                R4600_HIT_CACHEOP_WAR_IMPL;
                blast_inv_dcache_range(addr, addr + size);
        }
+       preempt_enable();
 
        bc_inv(addr, size);
        __sync();
@@ -780,20 +786,30 @@ static inline void rm7k_erratum31(void)
 
 static inline void alias_74k_erratum(struct cpuinfo_mips *c)
 {
+       unsigned int imp = c->processor_id & PRID_IMP_MASK;
+       unsigned int rev = c->processor_id & PRID_REV_MASK;
+
        /*
         * Early versions of the 74K do not update the cache tags on a
         * vtag miss/ptag hit which can occur in the case of KSEG0/KUSEG
         * aliases. In this case it is better to treat the cache as always
         * having aliases.
         */
-       if ((c->processor_id & 0xff) <= PRID_REV_ENCODE_332(2, 4, 0))
-               c->dcache.flags |= MIPS_CACHE_VTAG;
-       if ((c->processor_id & 0xff) == PRID_REV_ENCODE_332(2, 4, 0))
-               write_c0_config6(read_c0_config6() | MIPS_CONF6_SYND);
-       if (((c->processor_id & 0xff00) == PRID_IMP_1074K) &&
-           ((c->processor_id & 0xff) <= PRID_REV_ENCODE_332(1, 1, 0))) {
-               c->dcache.flags |= MIPS_CACHE_VTAG;
-               write_c0_config6(read_c0_config6() | MIPS_CONF6_SYND);
+       switch (imp) {
+       case PRID_IMP_74K:
+               if (rev <= PRID_REV_ENCODE_332(2, 4, 0))
+                       c->dcache.flags |= MIPS_CACHE_VTAG;
+               if (rev == PRID_REV_ENCODE_332(2, 4, 0))
+                       write_c0_config6(read_c0_config6() | MIPS_CONF6_SYND);
+               break;
+       case PRID_IMP_1074K:
+               if (rev <= PRID_REV_ENCODE_332(1, 1, 0)) {
+                       c->dcache.flags |= MIPS_CACHE_VTAG;
+                       write_c0_config6(read_c0_config6() | MIPS_CONF6_SYND);
+               }
+               break;
+       default:
+               BUG();
        }
 }
 
@@ -809,7 +825,7 @@ static void probe_pcache(void)
        unsigned long config1;
        unsigned int lsize;
 
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_R4600:                 /* QED style two way caches? */
        case CPU_R4700:
        case CPU_R5000:
@@ -1025,7 +1041,8 @@ static void probe_pcache(void)
         * presumably no vendor is shipping his hardware in the "bad"
         * configuration.
         */
-       if ((prid & 0xff00) == PRID_IMP_R4000 && (prid & 0xff) < 0x40 &&
+       if ((prid & PRID_IMP_MASK) == PRID_IMP_R4000 &&
+           (prid & PRID_REV_MASK) < PRID_REV_R4400 &&
            !(config & CONF_SC) && c->icache.linesz != 16 &&
            PAGE_SIZE <= 0x8000)
                panic("Improper R4000SC processor configuration detected");
@@ -1045,7 +1062,7 @@ static void probe_pcache(void)
         * normally they'd suffer from aliases but magic in the hardware deals
         * with that for us so we don't need to take care ourselves.
         */
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_20KC:
        case CPU_25KF:
        case CPU_SB1:
@@ -1065,7 +1082,7 @@ static void probe_pcache(void)
        case CPU_34K:
        case CPU_74K:
        case CPU_1004K:
-               if (c->cputype == CPU_74K)
+               if (current_cpu_type() == CPU_74K)
                        alias_74k_erratum(c);
                if ((read_c0_config7() & (1 << 16))) {
                        /* effectively physically indexed dcache,
@@ -1078,7 +1095,7 @@ static void probe_pcache(void)
                        c->dcache.flags |= MIPS_CACHE_ALIASES;
        }
 
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_20KC:
                /*
                 * Some older 20Kc chips doesn't have the 'VI' bit in
@@ -1207,7 +1224,7 @@ static void setup_scache(void)
         * processors don't have a S-cache that would be relevant to the
         * Linux memory management.
         */
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_R4000SC:
        case CPU_R4000MC:
        case CPU_R4400SC:
@@ -1384,9 +1401,8 @@ static void r4k_cache_error_setup(void)
 {
        extern char __weak except_vec2_generic;
        extern char __weak except_vec2_sb1;
-       struct cpuinfo_mips *c = &current_cpu_data;
 
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_SB1:
        case CPU_SB1A:
                set_uncached_handler(0x100, &except_vec2_sb1, 0x80);
index aaccf1c106997aecc8fa7050a4bfa8072212dab0..f25a7e9f8cbc56e320df0c6c51cc7bf8a45cb40e 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/highmem.h>
 
 #include <asm/cache.h>
+#include <asm/cpu-type.h>
 #include <asm/io.h>
 
 #include <dma-coherence.h>
@@ -50,16 +51,20 @@ static inline struct page *dma_addr_to_page(struct device *dev,
 }
 
 /*
+ * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
+ * speculatively fill random cachelines with stale data at any time,
+ * requiring an extra flush post-DMA.
+ *
  * Warning on the terminology - Linux calls an uncached area coherent;
  * MIPS terminology calls memory areas with hardware maintained coherency
  * coherent.
  */
-
-static inline int cpu_is_noncoherent_r10000(struct device *dev)
+static inline int cpu_needs_post_dma_flush(struct device *dev)
 {
        return !plat_device_is_coherent(dev) &&
-              (current_cpu_type() == CPU_R10000 ||
-              current_cpu_type() == CPU_R12000);
+              (boot_cpu_type() == CPU_R10000 ||
+               boot_cpu_type() == CPU_R12000 ||
+               boot_cpu_type() == CPU_BMIPS5000);
 }
 
 static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
@@ -230,7 +235,7 @@ static inline void __dma_sync(struct page *page,
 static void mips_dma_unmap_page(struct device *dev, dma_addr_t dma_addr,
        size_t size, enum dma_data_direction direction, struct dma_attrs *attrs)
 {
-       if (cpu_is_noncoherent_r10000(dev))
+       if (cpu_needs_post_dma_flush(dev))
                __dma_sync(dma_addr_to_page(dev, dma_addr),
                           dma_addr & ~PAGE_MASK, size, direction);
 
@@ -284,7 +289,7 @@ static void mips_dma_unmap_sg(struct device *dev, struct scatterlist *sg,
 static void mips_dma_sync_single_for_cpu(struct device *dev,
        dma_addr_t dma_handle, size_t size, enum dma_data_direction direction)
 {
-       if (cpu_is_noncoherent_r10000(dev))
+       if (cpu_needs_post_dma_flush(dev))
                __dma_sync(dma_addr_to_page(dev, dma_handle),
                           dma_handle & ~PAGE_MASK, size, direction);
 }
@@ -305,7 +310,7 @@ static void mips_dma_sync_sg_for_cpu(struct device *dev,
 
        /* Make sure that gcc doesn't leave the empty loop body.  */
        for (i = 0; i < nelems; i++, sg++) {
-               if (cpu_is_noncoherent_r10000(dev))
+               if (cpu_needs_post_dma_flush(dev))
                        __dma_sync(sg_page(sg), sg->offset, sg->length,
                                   direction);
        }
index 85df1cd8d446c0b7b1fccbbcb3617175f6314289..becc42bb18495adf98389bd039bc111c1893cedd 100644 (file)
@@ -42,8 +42,7 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
        const int field = sizeof(unsigned long) * 2;
        siginfo_t info;
        int fault;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                                                (write ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
 #if 0
        printk("Cpu%d[%s:%d:%0*lx:%ld:%0*lx]\n", raw_smp_processor_id(),
@@ -93,6 +92,8 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write,
        if (in_atomic() || !mm)
                goto bad_area_nosemaphore;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -114,6 +115,7 @@ good_area:
        if (write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (cpu_has_rixi) {
                        if (address == regs->cp0_epc && !(vma->vm_flags & VM_EXEC)) {
@@ -241,6 +243,8 @@ out_of_memory:
         * (which will retry the fault, or kill us if we got oom-killed).
         */
        up_read(&mm->mmap_sem);
+       if (!user_mode(regs))
+               goto no_context;
        pagefault_out_of_memory();
        return;
 
index d4ea5c9c4a93add70ec6e33b1efce8ab5b810c54..06ce17c2a905af5be1bb9bae744d2f03abc64a6e 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/swap.h>
 #include <linux/hugetlb.h>
 
+#include <asm/cpu-features.h>
 #include <asm/pgtable.h>
 
 static inline pte_t gup_get_pte(pte_t *ptep)
@@ -273,7 +274,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
        len = (unsigned long) nr_pages << PAGE_SHIFT;
 
        end = start + len;
-       if (end < start)
+       if (end < start || cpu_has_dc_aliases)
                goto slow_irqon;
 
        /* XXX: batch / limit 'nr' */
index a7fee0dfb7a9daaeb67616804f00cac7365d778f..01fda4419ed09de2e5adbfcd0b318023f3cc7664 100644 (file)
@@ -85,6 +85,11 @@ int pud_huge(pud_t pud)
        return (pud_val(pud) & _PAGE_HUGE) != 0;
 }
 
+int pmd_huge_support(void)
+{
+       return 1;
+}
+
 struct page *
 follow_huge_pmd(struct mm_struct *mm, unsigned long address,
                pmd_t *pmd, int write)
index 4e73f10a751957b677da6ca8186f6294777ad709..e205ef598e97bcc16becade0f627397a157987e1 100644 (file)
@@ -254,6 +254,7 @@ void copy_from_user_page(struct vm_area_struct *vma,
                        SetPageDcacheDirty(page);
        }
 }
+EXPORT_SYMBOL_GPL(copy_from_user_page);
 
 void __init fixrange_init(unsigned long start, unsigned long end,
        pgd_t *pgd_base)
index 218c2109a55d7fd6f4be10e1e860f00e50c2bc7f..cbd81d17793a71b617ed28b92a2510d89d08114a 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/bugs.h>
 #include <asm/cacheops.h>
+#include <asm/cpu-type.h>
 #include <asm/inst.h>
 #include <asm/io.h>
 #include <asm/page.h>
index 5d01392e3518d1166b1cf82c6bee69475a30021e..08d05aee8788beecdf0a6e3cc8d21ee3901e17da 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/sched.h>
 #include <linux/mm.h>
 
+#include <asm/cpu-type.h>
 #include <asm/mipsregs.h>
 #include <asm/bcache.h>
 #include <asm/cacheops.h>
@@ -71,7 +72,7 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
        unsigned int tmp;
 
        /* Check the bypass bit (L2B) */
-       switch (c->cputype) {
+       switch (current_cpu_type()) {
        case CPU_34K:
        case CPU_74K:
        case CPU_1004K:
index 30a494db99c2a0eb4d51aa64ca410de956801837..79bca3130bd15f51bccae23012fa9a821cadb653 100644 (file)
 
 #define FASTPATH_SIZE  128
 
+#ifdef CONFIG_MIPS_PGD_C0_CONTEXT
 LEAF(tlbmiss_handler_setup_pgd)
        .space          16 * 4
 END(tlbmiss_handler_setup_pgd)
 EXPORT(tlbmiss_handler_setup_pgd_end)
+#endif
 
 LEAF(handle_tlbm)
        .space          FASTPATH_SIZE * 4
index 00b26a67a06d8c0693f15999aa08db864dbe2a93..bb3a5f643e974a27a7d81246d4d7bb6b5f13a390 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 
 #include <asm/cpu.h>
+#include <asm/cpu-type.h>
 #include <asm/bootinfo.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
index 556cb48157704d8c576da3fc0dda6fb10c375c3e..9bb3a9363b0618df3e19a43fafc68eb91dff18ba 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/cache.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cpu-type.h>
 #include <asm/pgtable.h>
 #include <asm/war.h>
 #include <asm/uasm.h>
@@ -85,6 +86,7 @@ static int use_bbit_insns(void)
        case CPU_CAVIUM_OCTEON:
        case CPU_CAVIUM_OCTEON_PLUS:
        case CPU_CAVIUM_OCTEON2:
+       case CPU_CAVIUM_OCTEON3:
                return 1;
        default:
                return 0;
@@ -95,6 +97,7 @@ static int use_lwx_insns(void)
 {
        switch (current_cpu_type()) {
        case CPU_CAVIUM_OCTEON2:
+       case CPU_CAVIUM_OCTEON3:
                return 1;
        default:
                return 0;
index 53aad4a3537569d3a33b1953c1d42b76db6e40e3..a18af5fce67eb704d223742f6f15f7062604ff7b 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/timex.h>
 #include <linux/mc146818rtc.h>
 
+#include <asm/cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/hardirq.h>
@@ -76,7 +77,7 @@ static void __init estimate_frequencies(void)
 #endif
 
 #if defined (CONFIG_KVM_GUEST) && defined (CONFIG_KVM_HOST_FREQ)
-       unsigned int prid = read_c0_prid() & 0xffff00;
+       unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
 
        /*
         * XXXKYMA: hardwire the CPU frequency to Host Freq/4
@@ -169,7 +170,7 @@ unsigned int get_c0_compare_int(void)
 
 void __init plat_time_init(void)
 {
-       unsigned int prid = read_c0_prid() & 0xffff00;
+       unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
        unsigned int freq;
 
        estimate_frequencies();
index a43ea3cc0a3bf61bdbe458f3e38b639ea896b319..552d26c343869fe6c02778dec476215626a7b356 100644 (file)
@@ -7,6 +7,7 @@
  */
 #include <linux/init.h>
 
+#include <asm/cpu.h>
 #include <asm/setup.h>
 #include <asm/time.h>
 #include <asm/irq.h>
@@ -34,7 +35,7 @@ static void __iomem *status_reg = (void __iomem *)0xbf000410;
  */
 static unsigned int __init estimate_cpu_frequency(void)
 {
-       unsigned int prid = read_c0_prid() & 0xffff00;
+       unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
        unsigned int tick = 0;
        unsigned int freq;
        unsigned int orig;
index 2447bf97d35ad8a30032d4773dadaba234ff6dae..852a4ee09954dacd635a2cfe6827b56bcd48acdc 100644 (file)
@@ -19,6 +19,15 @@ config DT_XLP_SVP
          pointer to the kernel.  The corresponding DTS file is at
          arch/mips/netlogic/dts/xlp_svp.dts
 
+config DT_XLP_FVP
+       bool "Built-in device tree for XLP FVP boards"
+       default y
+       help
+         Add an FDT blob for XLP FVP board into the kernel.
+         This DTB will be used if the firmware does not pass in a DTB
+         pointer to the kernel.  The corresponding DTS file is at
+         arch/mips/netlogic/dts/xlp_fvp.dts
+
 config NLM_MULTINODE
        bool "Support for multi-chip boards"
        depends on NLM_XLP_BOARD
index 4e35d9c453e2d98cb99555af3f16ad634bb9a7fb..6f8feb9efcff9e64174534233133b6d097d957fc 100644 (file)
@@ -106,9 +106,7 @@ void nlm_early_init_secondary(int cpu)
 {
        change_c0_config(CONF_CM_CMASK, 0x3);
 #ifdef CONFIG_CPU_XLP
-       /* mmu init, once per core */
-       if (cpu % NLM_THREADS_PER_CORE == 0)
-               xlp_mmu_init();
+       xlp_mmu_init();
 #endif
        write_c0_ebase(nlm_current_node()->ebase);
 }
index 045a396c57ced6bf25736c6ee6ef3f734ed6cf7f..13391b8a60317337ac212751edb25d1f9868d8e8 100644 (file)
@@ -45,6 +45,7 @@
 #if defined(CONFIG_CPU_XLP)
 #include <asm/netlogic/xlp-hal/iomap.h>
 #include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/sys.h>
 #include <asm/netlogic/xlp-hal/pic.h>
 #elif defined(CONFIG_CPU_XLR)
 #include <asm/netlogic/xlr/iomap.h>
@@ -91,7 +92,7 @@ static void nlm_init_pic_timer(void)
                csrc_pic.read   = nlm_get_pic_timer;
        }
        csrc_pic.rating = 1000;
-       clocksource_register_hz(&csrc_pic, PIC_CLK_HZ);
+       clocksource_register_hz(&csrc_pic, pic_timer_freq());
 }
 
 void __init plat_time_init(void)
index aecb6fa9a9c33968a187c872672d835c5ee39845..0b9be5fd2e466e771ec51ec40a7f1ffeae0a8e47 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_DT_XLP_EVP) := xlp_evp.dtb.o
 obj-$(CONFIG_DT_XLP_SVP) += xlp_svp.dtb.o
+obj-$(CONFIG_DT_XLP_FVP) += xlp_fvp.dtb.o
index 06407033678e67262b04d747b9fe957c87cff99f..89ad04808c024758232fb2afeb06ac0e68a7dde3 100644 (file)
@@ -9,19 +9,12 @@
        #address-cells = <2>;
        #size-cells = <2>;
 
-       memory {
-               device_type = "memory";
-               reg =  <0 0x00100000 0 0x0FF00000       // 255M at 1M
-                       0 0x20000000 0 0xa0000000       // 2560M at 512M
-                       0 0xe0000000 1 0x00000000>;
-       };
-
        soc {
                #address-cells = <2>;
                #size-cells = <1>;
                compatible = "simple-bus";
                ranges = <0 0  0 0x18000000  0x04000000   // PCIe CFG
-                         1 0  0 0x16000000  0x01000000>; // GBU chipselects
+                         1 0  0 0x16000000  0x02000000>; // GBU chipselects
 
                serial0: serial@30000 {
                        device_type = "serial";
diff --git a/arch/mips/netlogic/dts/xlp_fvp.dts b/arch/mips/netlogic/dts/xlp_fvp.dts
new file mode 100644 (file)
index 0000000..63e62b7
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * XLP2XX Device Tree Source for FVP boards
+ */
+
+/dts-v1/;
+/ {
+       model = "netlogic,XLP-FVP";
+       compatible = "netlogic,xlp";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       soc {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               ranges = <0 0  0 0x18000000  0x04000000   // PCIe CFG
+                         1 0  0 0x16000000  0x02000000>; // GBU chipselects
+
+               serial0: serial@30000 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0 0x30100 0xa00>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clock-frequency = <133333333>;
+                       interrupt-parent = <&pic>;
+                       interrupts = <17>;
+               };
+               serial1: serial@31000 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0 0x31100 0xa00>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clock-frequency = <133333333>;
+                       interrupt-parent = <&pic>;
+                       interrupts = <18>;
+               };
+               i2c0: ocores@37100 {
+                       compatible = "opencores,i2c-ocores";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x37100 0x20>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clock-frequency = <32000000>;
+                       interrupt-parent = <&pic>;
+                       interrupts = <30>;
+               };
+               i2c1: ocores@37120 {
+                       compatible = "opencores,i2c-ocores";
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       reg = <0 0x37120 0x20>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clock-frequency = <32000000>;
+                       interrupt-parent = <&pic>;
+                       interrupts = <31>;
+
+                       rtc@68 {
+                               compatible = "dallas,ds1374";
+                               reg = <0x68>;
+                       };
+
+                       dtt@4c {
+                               compatible = "national,lm90";
+                               reg = <0x4c>;
+                       };
+               };
+               pic: pic@4000 {
+                       compatible = "netlogic,xlp-pic";
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       reg = <0 0x4000 0x200>;
+                       interrupt-controller;
+               };
+
+               nor_flash@1,0 {
+                       compatible = "cfi-flash";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       bank-width = <2>;
+                       reg = <1 0 0x1000000>;
+
+                       partition@0 {
+                               label = "x-loader";
+                               reg = <0x0 0x100000>; /* 1M */
+                               read-only;
+                       };
+
+                       partition@100000 {
+                               label = "u-boot";
+                               reg = <0x100000 0x100000>; /* 1M */
+                       };
+
+                       partition@200000 {
+                               label = "kernel";
+                               reg = <0x200000 0x500000>; /* 5M */
+                       };
+
+                       partition@700000 {
+                               label = "rootfs";
+                               reg = <0x700000 0x800000>; /* 8M */
+                       };
+
+                       partition@f00000 {
+                               label = "env";
+                               reg = <0xf00000 0x100000>; /* 1M */
+                               read-only;
+                       };
+               };
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200 rdinit=/sbin/init";
+       };
+};
index 9c5db102df53a7223e1e04ad1cd64d7460fede60..1ebd00edaacc4490d3f95db0484aeb008787faca 100644 (file)
@@ -9,19 +9,12 @@
        #address-cells = <2>;
        #size-cells = <2>;
 
-       memory {
-               device_type = "memory";
-               reg =  <0 0x00100000 0 0x0FF00000       // 255M at 1M
-                       0 0x20000000 0 0xa0000000       // 2560M at 512M
-                       0 0xe0000000 0 0x40000000>;
-       };
-
        soc {
                #address-cells = <2>;
                #size-cells = <1>;
                compatible = "simple-bus";
                ranges = <0 0  0 0x18000000  0x04000000   // PCIe CFG
-                         1 0  0 0x16000000  0x01000000>; // GBU chipselects
+                         1 0  0 0x16000000  0x02000000>; // GBU chipselects
 
                serial0: serial@30000 {
                        device_type = "serial";
index 85ac4a892cedd0f18fb8e80970b2b81870f7538b..ed9a93c046503a483eaec06a2600f321b513211f 100644 (file)
@@ -1,3 +1,4 @@
 obj-y                          += setup.o nlm_hal.o cop2-ex.o dt.o
 obj-$(CONFIG_SMP)              += wakeup.o
 obj-$(CONFIG_USB)              += usb-init.o
+obj-$(CONFIG_USB)              += usb-init-xlp2.o
index a15cdbb8d0bdf53a96ad652bec6a2994edded1ca..88df445dda76b596f3f2d3b374e1730a69480122 100644 (file)
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 
-extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[], __dtb_start[];
+extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[],
+       __dtb_xlp_fvp_begin[], __dtb_start[];
 
 void __init *xlp_dt_init(void *fdtp)
 {
        if (!fdtp) {
                switch (current_cpu_data.processor_id & 0xff00) {
+#ifdef CONFIG_DT_XLP_FVP
+               case PRID_IMP_NETLOGIC_XLP2XX:
+                       fdtp = __dtb_xlp_fvp_begin;
+                       break;
+#endif
 #ifdef CONFIG_DT_XLP_SVP
                case PRID_IMP_NETLOGIC_XLP3XX:
                        fdtp = __dtb_xlp_svp_begin;
index 87560e4db35f148e87028b6ce34fcaf1485177bf..56c50ba43c9b0bb74cc13e016e92477c6d95c6e3 100644 (file)
@@ -44,6 +44,7 @@
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/xlp-hal/iomap.h>
 #include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/bridge.h>
 #include <asm/netlogic/xlp-hal/pic.h>
 #include <asm/netlogic/xlp-hal/sys.h>
 
@@ -64,6 +65,7 @@ int nlm_irq_to_irt(int irq)
        uint64_t pcibase;
        int devoff, irt;
 
+       devoff = 0;
        switch (irq) {
        case PIC_UART_0_IRQ:
                devoff = XLP_IO_UART0_OFFSET(0);
@@ -71,44 +73,68 @@ int nlm_irq_to_irt(int irq)
        case PIC_UART_1_IRQ:
                devoff = XLP_IO_UART1_OFFSET(0);
                break;
-       case PIC_EHCI_0_IRQ:
-               devoff = XLP_IO_USB_EHCI0_OFFSET(0);
-               break;
-       case PIC_EHCI_1_IRQ:
-               devoff = XLP_IO_USB_EHCI1_OFFSET(0);
-               break;
-       case PIC_OHCI_0_IRQ:
-               devoff = XLP_IO_USB_OHCI0_OFFSET(0);
-               break;
-       case PIC_OHCI_1_IRQ:
-               devoff = XLP_IO_USB_OHCI1_OFFSET(0);
-               break;
-       case PIC_OHCI_2_IRQ:
-               devoff = XLP_IO_USB_OHCI2_OFFSET(0);
-               break;
-       case PIC_OHCI_3_IRQ:
-               devoff = XLP_IO_USB_OHCI3_OFFSET(0);
-               break;
        case PIC_MMC_IRQ:
                devoff = XLP_IO_SD_OFFSET(0);
                break;
-       case PIC_I2C_0_IRQ:
-               devoff = XLP_IO_I2C0_OFFSET(0);
-               break;
+       case PIC_I2C_0_IRQ:     /* I2C will be fixed up */
        case PIC_I2C_1_IRQ:
-               devoff = XLP_IO_I2C1_OFFSET(0);
+       case PIC_I2C_2_IRQ:
+       case PIC_I2C_3_IRQ:
+               if (cpu_is_xlpii())
+                       devoff = XLP2XX_IO_I2C_OFFSET(0);
+               else
+                       devoff = XLP_IO_I2C0_OFFSET(0);
                break;
        default:
-               devoff = 0;
-               break;
+               if (cpu_is_xlpii()) {
+                       switch (irq) {
+                               /* XLP2XX has three XHCI USB controller */
+                       case PIC_2XX_XHCI_0_IRQ:
+                               devoff = XLP2XX_IO_USB_XHCI0_OFFSET(0);
+                               break;
+                       case PIC_2XX_XHCI_1_IRQ:
+                               devoff = XLP2XX_IO_USB_XHCI1_OFFSET(0);
+                               break;
+                       case PIC_2XX_XHCI_2_IRQ:
+                               devoff = XLP2XX_IO_USB_XHCI2_OFFSET(0);
+                               break;
+                       }
+               } else {
+                       switch (irq) {
+                       case PIC_EHCI_0_IRQ:
+                               devoff = XLP_IO_USB_EHCI0_OFFSET(0);
+                               break;
+                       case PIC_EHCI_1_IRQ:
+                               devoff = XLP_IO_USB_EHCI1_OFFSET(0);
+                               break;
+                       case PIC_OHCI_0_IRQ:
+                               devoff = XLP_IO_USB_OHCI0_OFFSET(0);
+                               break;
+                       case PIC_OHCI_1_IRQ:
+                               devoff = XLP_IO_USB_OHCI1_OFFSET(0);
+                               break;
+                       case PIC_OHCI_2_IRQ:
+                               devoff = XLP_IO_USB_OHCI2_OFFSET(0);
+                               break;
+                       case PIC_OHCI_3_IRQ:
+                               devoff = XLP_IO_USB_OHCI3_OFFSET(0);
+                               break;
+                       }
+               }
        }
 
        if (devoff != 0) {
                pcibase = nlm_pcicfg_base(devoff);
                irt = nlm_read_reg(pcibase, XLP_PCI_IRTINFO_REG) & 0xffff;
-               /* HW bug, I2C 1 irt entry is off by one */
-               if (irq == PIC_I2C_1_IRQ)
-                       irt = irt + 1;
+               /* HW weirdness, I2C IRT entry has to be fixed up */
+               switch (irq) {
+               case PIC_I2C_1_IRQ:
+                       irt = irt + 1; break;
+               case PIC_I2C_2_IRQ:
+                       irt = irt + 2; break;
+               case PIC_I2C_3_IRQ:
+                       irt = irt + 3; break;
+               }
        } else if (irq >= PIC_PCIE_LINK_0_IRQ && irq <= PIC_PCIE_LINK_3_IRQ) {
                /* HW bug, PCI IRT entries are bad on early silicon, fix */
                irt = PIC_IRT_PCIE_LINK_INDEX(irq - PIC_PCIE_LINK_0_IRQ);
@@ -126,19 +152,160 @@ unsigned int nlm_get_core_frequency(int node, int core)
 
        sysbase = nlm_get_node(node)->sysbase;
        rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG);
-       dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE);
-       pll_divf = ((rstval >> 10) & 0x7f) + 1;
-       pll_divr = ((rstval >> 8)  & 0x3) + 1;
-       ext_div  = ((rstval >> 30) & 0x3) + 1;
-       dfs_div  = ((dfsval >> (core * 4)) & 0xf) + 1;
-
-       num = 800000000ULL * pll_divf;
-       denom = 3 * pll_divr * ext_div * dfs_div;
+       if (cpu_is_xlpii()) {
+               num = 1000000ULL * (400 * 3 + 100 * (rstval >> 26));
+               denom = 3;
+       } else {
+               dfsval = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIV_VALUE);
+               pll_divf = ((rstval >> 10) & 0x7f) + 1;
+               pll_divr = ((rstval >> 8)  & 0x3) + 1;
+               ext_div  = ((rstval >> 30) & 0x3) + 1;
+               dfs_div  = ((dfsval >> (core * 4)) & 0xf) + 1;
+
+               num = 800000000ULL * pll_divf;
+               denom = 3 * pll_divr * ext_div * dfs_div;
+       }
        do_div(num, denom);
        return (unsigned int)num;
 }
 
+/* Calculate Frequency to the PIC from PLL.
+ * freq_out = ( ref_freq/2 * (6 + ctrl2[7:0]) + ctrl2[20:8]/2^13 ) /
+ * ((2^ctrl0[7:5]) * Table(ctrl0[26:24]))
+ */
+static unsigned int nlm_2xx_get_pic_frequency(int node)
+{
+       u32 ctrl_val0, ctrl_val2, vco_post_div, pll_post_div;
+       u32 mdiv, fdiv, pll_out_freq_den, reg_select, ref_div, pic_div;
+       u64 ref_clk, sysbase, pll_out_freq_num, ref_clk_select;
+
+       sysbase = nlm_get_node(node)->sysbase;
+
+       /* Find ref_clk_base */
+       ref_clk_select =
+               (nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG) >> 18) & 0x3;
+       switch (ref_clk_select) {
+       case 0:
+               ref_clk = 200000000ULL;
+               ref_div = 3;
+               break;
+       case 1:
+               ref_clk = 100000000ULL;
+               ref_div = 1;
+               break;
+       case 2:
+               ref_clk = 125000000ULL;
+               ref_div = 1;
+               break;
+       case 3:
+               ref_clk = 400000000ULL;
+               ref_div = 3;
+               break;
+       }
+
+       /* Find the clock source PLL device for PIC */
+       reg_select = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_SEL) >> 22) & 0x3;
+       switch (reg_select) {
+       case 0:
+               ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0);
+               ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2);
+               break;
+       case 1:
+               ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(0));
+               ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(0));
+               break;
+       case 2:
+               ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(1));
+               ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(1));
+               break;
+       case 3:
+               ctrl_val0 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL0_DEVX(2));
+               ctrl_val2 = nlm_read_sys_reg(sysbase, SYS_PLL_CTRL2_DEVX(2));
+               break;
+       }
+
+       vco_post_div = (ctrl_val0 >> 5) & 0x7;
+       pll_post_div = (ctrl_val0 >> 24) & 0x7;
+       mdiv = ctrl_val2 & 0xff;
+       fdiv = (ctrl_val2 >> 8) & 0xfff;
+
+       /* Find PLL post divider value */
+       switch (pll_post_div) {
+       case 1:
+               pll_post_div = 2;
+               break;
+       case 3:
+               pll_post_div = 4;
+               break;
+       case 7:
+               pll_post_div = 8;
+               break;
+       case 6:
+               pll_post_div = 16;
+               break;
+       case 0:
+       default:
+               pll_post_div = 1;
+               break;
+       }
+
+       fdiv = fdiv/(1 << 13);
+       pll_out_freq_num = ((ref_clk >> 1) * (6 + mdiv)) + fdiv;
+       pll_out_freq_den = (1 << vco_post_div) * pll_post_div * 3;
+
+       if (pll_out_freq_den > 0)
+               do_div(pll_out_freq_num, pll_out_freq_den);
+
+       /* PIC post divider, which happens after PLL */
+       pic_div = (nlm_read_sys_reg(sysbase, SYS_CLK_DEV_DIV) >> 22) & 0x3;
+       do_div(pll_out_freq_num, 1 << pic_div);
+
+       return pll_out_freq_num;
+}
+
+unsigned int nlm_get_pic_frequency(int node)
+{
+       if (cpu_is_xlpii())
+               return nlm_2xx_get_pic_frequency(node);
+       else
+               return 133333333;
+}
+
 unsigned int nlm_get_cpu_frequency(void)
 {
        return nlm_get_core_frequency(0, 0);
 }
+
+/*
+ * Fills upto 8 pairs of entries containing the DRAM map of a node
+ * if n < 0, get dram map for all nodes
+ */
+int xlp_get_dram_map(int n, uint64_t *dram_map)
+{
+       uint64_t bridgebase, base, lim;
+       uint32_t val;
+       int i, node, rv;
+
+       /* Look only at mapping on Node 0, we don't handle crazy configs */
+       bridgebase = nlm_get_bridge_regbase(0);
+       rv = 0;
+       for (i = 0; i < 8; i++) {
+               val = nlm_read_bridge_reg(bridgebase,
+                                       BRIDGE_DRAM_NODE_TRANSLN(i));
+               node = (val >> 1) & 0x3;
+               if (n >= 0 && n != node)
+                       continue;
+               val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i));
+               val = (val >>  12) & 0xfffff;
+               base = (uint64_t) val << 20;
+               val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i));
+               val = (val >>  12) & 0xfffff;
+               if (val == 0)   /* BAR not used */
+                       continue;
+               lim = ((uint64_t)val + 1) << 20;
+               dram_map[rv] = base;
+               dram_map[rv + 1] = lim;
+               rv += 2;
+       }
+       return rv;
+}
index 7b638f7be49143988b58dc8da50f9f3b186d332d..76a7131e486ee49fe5e6831f35eea11244c7c8a2 100644 (file)
@@ -73,6 +73,23 @@ static void nlm_fixup_mem(void)
        }
 }
 
+static void __init xlp_init_mem_from_bars(void)
+{
+       uint64_t map[16];
+       int i, n;
+
+       n = xlp_get_dram_map(-1, map);  /* -1: info for all nodes */
+       for (i = 0; i < n; i += 2) {
+               /* exclude 0x1000_0000-0x2000_0000, u-boot device */
+               if (map[i] <= 0x10000000 && map[i+1] > 0x10000000)
+                       map[i+1] = 0x10000000;
+               if (map[i] > 0x10000000 && map[i] < 0x20000000)
+                       map[i] = 0x20000000;
+
+               add_memory_region(map[i], map[i+1] - map[i], BOOT_MEM_RAM);
+       }
+}
+
 void __init plat_mem_setup(void)
 {
        panic_timeout   = 5;
@@ -82,12 +99,23 @@ void __init plat_mem_setup(void)
 
        /* memory and bootargs from DT */
        early_init_devtree(initial_boot_params);
+
+       if (boot_mem_map.nr_map == 0) {
+               pr_info("Using DRAM BARs for memory map.\n");
+               xlp_init_mem_from_bars();
+       }
+       /* Calculate and setup wired entries for mapped kernel */
        nlm_fixup_mem();
 }
 
 const char *get_system_type(void)
 {
-       return "Netlogic XLP Series";
+       switch (read_c0_prid() & 0xff00) {
+       case PRID_IMP_NETLOGIC_XLP2XX:
+               return "Broadcom XLPII Series";
+       default:
+               return "Netlogic XLP Series";
+       }
 }
 
 void __init prom_free_prom_memory(void)
@@ -97,12 +125,20 @@ void __init prom_free_prom_memory(void)
 
 void xlp_mmu_init(void)
 {
-       /* enable extended TLB and Large Fixed TLB */
-       write_c0_config6(read_c0_config6() | 0x24);
-
-       /* set page mask of Fixed TLB in config7 */
-       write_c0_config7(PM_DEFAULT_MASK >>
-               (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2)));
+       u32 conf4;
+
+       if (cpu_is_xlpii()) {
+               /* XLPII series has extended pagesize in config 4 */
+               conf4 = read_c0_config4() & ~0x1f00u;
+               write_c0_config4(conf4 | ((PAGE_SHIFT - 10) / 2 << 8));
+       } else {
+               /* enable extended TLB and Large Fixed TLB */
+               write_c0_config6(read_c0_config6() | 0x24);
+
+               /* set page mask of extended Fixed TLB in config7 */
+               write_c0_config7(PM_DEFAULT_MASK >>
+                       (13 + (ffz(PM_DEFAULT_MASK >> 13) / 2)));
+       }
 }
 
 void nlm_percpu_init(int hwcpuid)
diff --git a/arch/mips/netlogic/xlp/usb-init-xlp2.c b/arch/mips/netlogic/xlp/usb-init-xlp2.c
new file mode 100644 (file)
index 0000000..36e9c22
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2003-2013 Broadcom 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 Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/irq.h>
+
+#include <asm/netlogic/common.h>
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+
+#define XLPII_USB3_CTL_0               0xc0
+#define XLPII_VAUXRST                  BIT(0)
+#define XLPII_VCCRST                   BIT(1)
+#define XLPII_NUM2PORT                 9
+#define XLPII_NUM3PORT                 13
+#define XLPII_RTUNEREQ                 BIT(20)
+#define XLPII_MS_CSYSREQ               BIT(21)
+#define XLPII_XS_CSYSREQ               BIT(22)
+#define XLPII_RETENABLEN               BIT(23)
+#define XLPII_TX2RX                    BIT(24)
+#define XLPII_XHCIREV                  BIT(25)
+#define XLPII_ECCDIS                   BIT(26)
+
+#define XLPII_USB3_INT_REG             0xc2
+#define XLPII_USB3_INT_MASK            0xc3
+
+#define XLPII_USB_PHY_TEST             0xc6
+#define XLPII_PRESET                   BIT(0)
+#define XLPII_ATERESET                 BIT(1)
+#define XLPII_LOOPEN                   BIT(2)
+#define XLPII_TESTPDHSP                        BIT(3)
+#define XLPII_TESTPDSSP                        BIT(4)
+#define XLPII_TESTBURNIN               BIT(5)
+
+#define XLPII_USB_PHY_LOS_LV           0xc9
+#define XLPII_LOSLEV                   0
+#define XLPII_LOSBIAS                  5
+#define XLPII_SQRXTX                   8
+#define XLPII_TXBOOST                  11
+#define XLPII_RSLKSEL                  16
+#define XLPII_FSEL                     20
+
+#define XLPII_USB_RFCLK_REG            0xcc
+#define XLPII_VVLD                     30
+
+#define nlm_read_usb_reg(b, r)         nlm_read_reg(b, r)
+#define nlm_write_usb_reg(b, r, v)     nlm_write_reg(b, r, v)
+
+#define nlm_xlpii_get_usb_pcibase(node, inst)          \
+       nlm_pcicfg_base(XLP2XX_IO_USB_OFFSET(node, inst))
+#define nlm_xlpii_get_usb_regbase(node, inst)          \
+       (nlm_xlpii_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ)
+
+static void xlpii_usb_ack(struct irq_data *data)
+{
+       u64 port_addr;
+
+       switch (data->irq) {
+       case PIC_2XX_XHCI_0_IRQ:
+               port_addr = nlm_xlpii_get_usb_regbase(0, 1);
+               break;
+       case PIC_2XX_XHCI_1_IRQ:
+               port_addr = nlm_xlpii_get_usb_regbase(0, 2);
+               break;
+       case PIC_2XX_XHCI_2_IRQ:
+               port_addr = nlm_xlpii_get_usb_regbase(0, 3);
+               break;
+       default:
+               pr_err("No matching USB irq!\n");
+               return;
+       }
+       nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff);
+}
+
+static void nlm_xlpii_usb_hw_reset(int node, int port)
+{
+       u64 port_addr, xhci_base, pci_base;
+       void __iomem *corebase;
+       u32 val;
+
+       port_addr = nlm_xlpii_get_usb_regbase(node, port);
+
+       /* Set frequency */
+       val = nlm_read_usb_reg(port_addr, XLPII_USB_PHY_LOS_LV);
+       val &= ~(0x3f << XLPII_FSEL);
+       val |= (0x27 << XLPII_FSEL);
+       nlm_write_usb_reg(port_addr, XLPII_USB_PHY_LOS_LV, val);
+
+       val = nlm_read_usb_reg(port_addr, XLPII_USB_RFCLK_REG);
+       val |= (1 << XLPII_VVLD);
+       nlm_write_usb_reg(port_addr, XLPII_USB_RFCLK_REG, val);
+
+       /* PHY reset */
+       val = nlm_read_usb_reg(port_addr, XLPII_USB_PHY_TEST);
+       val &= (XLPII_ATERESET | XLPII_LOOPEN | XLPII_TESTPDHSP
+               | XLPII_TESTPDSSP | XLPII_TESTBURNIN);
+       nlm_write_usb_reg(port_addr, XLPII_USB_PHY_TEST, val);
+
+       /* Setup control register */
+       val =  XLPII_VAUXRST | XLPII_VCCRST | (1 << XLPII_NUM2PORT)
+               | (1 << XLPII_NUM3PORT) | XLPII_MS_CSYSREQ | XLPII_XS_CSYSREQ
+               | XLPII_RETENABLEN | XLPII_XHCIREV;
+       nlm_write_usb_reg(port_addr, XLPII_USB3_CTL_0, val);
+
+       /* Enable interrupts */
+       nlm_write_usb_reg(port_addr, XLPII_USB3_INT_MASK, 0x00000001);
+
+       /* Clear all interrupts */
+       nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff);
+
+       udelay(2000);
+
+       /* XHCI configuration at PCI mem */
+       pci_base = nlm_xlpii_get_usb_pcibase(node, port);
+       xhci_base = nlm_read_usb_reg(pci_base, 0x4) & ~0xf;
+       corebase = ioremap(xhci_base, 0x10000);
+       if (!corebase)
+               return;
+
+       writel(0x240002, corebase + 0xc2c0);
+       /* GCTL 0xc110 */
+       val = readl(corebase + 0xc110);
+       val &= ~(0x3 << 12);
+       val |= (1 << 12);
+       writel(val, corebase + 0xc110);
+       udelay(100);
+
+       /* PHYCFG 0xc200 */
+       val = readl(corebase + 0xc200);
+       val &= ~(1 << 6);
+       writel(val, corebase + 0xc200);
+       udelay(100);
+
+       /* PIPECTL 0xc2c0 */
+       val = readl(corebase + 0xc2c0);
+       val &= ~(1 << 17);
+       writel(val, corebase + 0xc2c0);
+
+       iounmap(corebase);
+}
+
+static int __init nlm_platform_xlpii_usb_init(void)
+{
+       if (!cpu_is_xlpii())
+               return 0;
+
+       pr_info("Initializing 2XX USB Interface\n");
+       nlm_xlpii_usb_hw_reset(0, 1);
+       nlm_xlpii_usb_hw_reset(0, 2);
+       nlm_xlpii_usb_hw_reset(0, 3);
+       nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlpii_usb_ack);
+       nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlpii_usb_ack);
+       nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlpii_usb_ack);
+
+       return 0;
+}
+
+arch_initcall(nlm_platform_xlpii_usb_init);
+
+static u64 xlp_usb_dmamask = ~(u32)0;
+
+/* Fixup IRQ for USB devices on XLP the SoC PCIe bus */
+static void nlm_usb_fixup_final(struct pci_dev *dev)
+{
+       dev->dev.dma_mask               = &xlp_usb_dmamask;
+       dev->dev.coherent_dma_mask      = DMA_BIT_MASK(32);
+       switch (dev->devfn) {
+       case 0x21:
+               dev->irq = PIC_2XX_XHCI_0_IRQ;
+               break;
+       case 0x22:
+               dev->irq = PIC_2XX_XHCI_1_IRQ;
+               break;
+       case 0x23:
+               dev->irq = PIC_2XX_XHCI_2_IRQ;
+               break;
+       }
+}
+
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_XHCI,
+               nlm_usb_fixup_final);
index ef3897ef0dc711d05ea06383b2080f17d2eaa643..f8117985f0f89b50f20290324f9d4fe41f7d93e6 100644 (file)
@@ -75,8 +75,7 @@ static void nlm_usb_intr_en(int node, int port)
        port_addr = nlm_get_usb_regbase(node, port);
        val = nlm_read_usb_reg(port_addr, USB_INT_EN);
        val = USB_CTRL_INTERRUPT_EN  | USB_OHCI_INTERRUPT_EN |
-               USB_OHCI_INTERRUPT1_EN | USB_CTRL_INTERRUPT_EN  |
-               USB_OHCI_INTERRUPT_EN | USB_OHCI_INTERRUPT2_EN;
+               USB_OHCI_INTERRUPT1_EN | USB_OHCI_INTERRUPT2_EN;
        nlm_write_usb_reg(port_addr, USB_INT_EN, val);
 }
 
@@ -100,6 +99,9 @@ static void nlm_usb_hw_reset(int node, int port)
 
 static int __init nlm_platform_usb_init(void)
 {
+       if (cpu_is_xlpii())
+               return 0;
+
        pr_info("Initializing USB Interface\n");
        nlm_usb_hw_reset(0, 0);
        nlm_usb_hw_reset(0, 3);
index 0cce37cbffef06816c99a0f4efcf8ae40a98d163..682d5638dc01cafcbf72ec5700e802a80116fe8f 100644 (file)
@@ -58,10 +58,12 @@ static int xlp_wakeup_core(uint64_t sysbase, int node, int core)
 
        coremask = (1 << core);
 
-       /* Enable CPU clock */
-       value = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL);
-       value &= ~coremask;
-       nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value);
+       /* Enable CPU clock in case of 8xx/3xx */
+       if (!cpu_is_xlpii()) {
+               value = nlm_read_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL);
+               value &= ~coremask;
+               nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value);
+       }
 
        /* Remove CPU Reset */
        value = nlm_read_sys_reg(sysbase, SYS_CPU_RESET);
index ed3bf0e3f3093d7004d984bfb59c4ed8cce7cab1..c7622c6e5f676cd8f20a6a926487029d8ba47ea1 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 
+#include <asm/cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/netlogic/xlr/fmn.h>
 #include <asm/netlogic/xlr/xlr.h>
@@ -187,7 +188,7 @@ void xlr_board_info_setup(void)
        int processor_id, num_core;
 
        num_core = hweight32(nlm_current_node()->coremask);
-       processor_id = read_c0_prid() & 0xff00;
+       processor_id = read_c0_prid() & PRID_IMP_MASK;
 
        setup_cpu_fmninfo(cpu, num_core);
        switch (processor_id) {
index 5e5424753b5624b9c66511db86d7c98fed11d2f0..4d1736fc19557b793fd707f2543500a043bf6488 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/oprofile.h>
 #include <linux/smp.h>
 #include <asm/cpu-info.h>
+#include <asm/cpu-type.h>
 
 #include "op_impl.h"
 
index c382042911ddfe138f3bdebe6b17697a80999c2a..719e4557e22e551288d6a84e877a831335b2cd91 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_SIBYTE_BCM1x80)  += pci-bcm1480.o pci-bcm1480ht.o
 obj-$(CONFIG_SNI_RM)           += fixup-sni.o ops-sni.o
 obj-$(CONFIG_LANTIQ)           += fixup-lantiq.o
 obj-$(CONFIG_PCI_LANTIQ)       += pci-lantiq.o ops-lantiq.o
+obj-$(CONFIG_SOC_RT3883)       += pci-rt3883.o
 obj-$(CONFIG_TANBAC_TB0219)    += fixup-tb0219.o
 obj-$(CONFIG_TANBAC_TB0226)    += fixup-tb0226.o
 obj-$(CONFIG_TANBAC_TB0287)    += fixup-tb0287.o
index 44dd5aa2e36f2d44fdc78ef9baca79234c80d510..5ec2a7bae02c80b1d9894e1c77e5cad4f99336a1 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/mm.h>
 #include <linux/console.h>
 #include <linux/tty.h>
+#include <linux/vt.h>
 
 #include <asm/sibyte/bcm1480_regs.h>
 #include <asm/sibyte/bcm1480_scd.h>
index 95c2ea815cacc4c6962025086fd4de4bcc0ef4a9..59cccd95688b500fa809b90edc71f24bf17a9859 100644 (file)
@@ -586,15 +586,16 @@ static int __init octeon_pci_setup(void)
        else
                octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG;
 
-       /* PCI I/O and PCI MEM values */
-       set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
-       ioport_resource.start = 0;
-       ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1;
        if (!octeon_is_pci_host()) {
                pr_notice("Not in host mode, PCI Controller not initialized\n");
                return 0;
        }
 
+       /* PCI I/O and PCI MEM values */
+       set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
+       ioport_resource.start = 0;
+       ioport_resource.end = OCTEON_PCI_IOSPACE_SIZE - 1;
+
        pr_notice("%s Octeon big bar support\n",
                  (octeon_dma_bar_type ==
                  OCTEON_DMA_BAR_TYPE_BIG) ? "Enabling" : "Disabling");
diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c
new file mode 100644 (file)
index 0000000..95c9d41
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ *  Ralink RT3662/RT3883 SoC PCI support
+ *
+ *  Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org>
+ *
+ *  Parts of this file are based on Ralink's 2.6.21 BSP
+ *
+ *  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/types.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_pci.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-ralink/rt3883.h>
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define RT3883_MEMORY_BASE             0x00000000
+#define RT3883_MEMORY_SIZE             0x02000000
+
+#define RT3883_PCI_REG_PCICFG          0x00
+#define   RT3883_PCICFG_P2P_BR_DEVNUM_M 0xf
+#define   RT3883_PCICFG_P2P_BR_DEVNUM_S 16
+#define   RT3883_PCICFG_PCIRST         BIT(1)
+#define RT3883_PCI_REG_PCIRAW          0x04
+#define RT3883_PCI_REG_PCIINT          0x08
+#define RT3883_PCI_REG_PCIENA          0x0c
+
+#define RT3883_PCI_REG_CFGADDR         0x20
+#define RT3883_PCI_REG_CFGDATA         0x24
+#define RT3883_PCI_REG_MEMBASE         0x28
+#define RT3883_PCI_REG_IOBASE          0x2c
+#define RT3883_PCI_REG_ARBCTL          0x80
+
+#define RT3883_PCI_REG_BASE(_x)                (0x1000 + (_x) * 0x1000)
+#define RT3883_PCI_REG_BAR0SETUP(_x)   (RT3883_PCI_REG_BASE((_x)) + 0x10)
+#define RT3883_PCI_REG_IMBASEBAR0(_x)  (RT3883_PCI_REG_BASE((_x)) + 0x18)
+#define RT3883_PCI_REG_ID(_x)          (RT3883_PCI_REG_BASE((_x)) + 0x30)
+#define RT3883_PCI_REG_CLASS(_x)       (RT3883_PCI_REG_BASE((_x)) + 0x34)
+#define RT3883_PCI_REG_SUBID(_x)       (RT3883_PCI_REG_BASE((_x)) + 0x38)
+#define RT3883_PCI_REG_STATUS(_x)      (RT3883_PCI_REG_BASE((_x)) + 0x50)
+
+#define RT3883_PCI_MODE_NONE   0
+#define RT3883_PCI_MODE_PCI    BIT(0)
+#define RT3883_PCI_MODE_PCIE   BIT(1)
+#define RT3883_PCI_MODE_BOTH   (RT3883_PCI_MODE_PCI | RT3883_PCI_MODE_PCIE)
+
+#define RT3883_PCI_IRQ_COUNT   32
+
+#define RT3883_P2P_BR_DEVNUM   1
+
+struct rt3883_pci_controller {
+       void __iomem *base;
+       spinlock_t lock;
+
+       struct device_node *intc_of_node;
+       struct irq_domain *irq_domain;
+
+       struct pci_controller pci_controller;
+       struct resource io_res;
+       struct resource mem_res;
+
+       bool pcie_ready;
+};
+
+static inline struct rt3883_pci_controller *
+pci_bus_to_rt3883_controller(struct pci_bus *bus)
+{
+       struct pci_controller *hose;
+
+       hose = (struct pci_controller *) bus->sysdata;
+       return container_of(hose, struct rt3883_pci_controller, pci_controller);
+}
+
+static inline u32 rt3883_pci_r32(struct rt3883_pci_controller *rpc,
+                                unsigned reg)
+{
+       return ioread32(rpc->base + reg);
+}
+
+static inline void rt3883_pci_w32(struct rt3883_pci_controller *rpc,
+                                 u32 val, unsigned reg)
+{
+       iowrite32(val, rpc->base + reg);
+}
+
+static inline u32 rt3883_pci_get_cfgaddr(unsigned int bus, unsigned int slot,
+                                        unsigned int func, unsigned int where)
+{
+       return (bus << 16) | (slot << 11) | (func << 8) | (where & 0xfc) |
+              0x80000000;
+}
+
+static u32 rt3883_pci_read_cfg32(struct rt3883_pci_controller *rpc,
+                              unsigned bus, unsigned slot,
+                              unsigned func, unsigned reg)
+{
+       unsigned long flags;
+       u32 address;
+       u32 ret;
+
+       address = rt3883_pci_get_cfgaddr(bus, slot, func, reg);
+
+       spin_lock_irqsave(&rpc->lock, flags);
+       rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+       ret = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
+       spin_unlock_irqrestore(&rpc->lock, flags);
+
+       return ret;
+}
+
+static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc,
+                                unsigned bus, unsigned slot,
+                                unsigned func, unsigned reg, u32 val)
+{
+       unsigned long flags;
+       u32 address;
+
+       address = rt3883_pci_get_cfgaddr(bus, slot, func, reg);
+
+       spin_lock_irqsave(&rpc->lock, flags);
+       rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+       rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA);
+       spin_unlock_irqrestore(&rpc->lock, flags);
+}
+
+static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct rt3883_pci_controller *rpc;
+       u32 pending;
+
+       rpc = irq_get_handler_data(irq);
+
+       pending = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIINT) &
+                 rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+
+       if (!pending) {
+               spurious_interrupt();
+               return;
+       }
+
+       while (pending) {
+               unsigned bit = __ffs(pending);
+
+               irq = irq_find_mapping(rpc->irq_domain, bit);
+               generic_handle_irq(irq);
+
+               pending &= ~BIT(bit);
+       }
+}
+
+static void rt3883_pci_irq_unmask(struct irq_data *d)
+{
+       struct rt3883_pci_controller *rpc;
+       u32 t;
+
+       rpc = irq_data_get_irq_chip_data(d);
+
+       t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+       rt3883_pci_w32(rpc, t | BIT(d->hwirq), RT3883_PCI_REG_PCIENA);
+       /* flush write */
+       rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+}
+
+static void rt3883_pci_irq_mask(struct irq_data *d)
+{
+       struct rt3883_pci_controller *rpc;
+       u32 t;
+
+       rpc = irq_data_get_irq_chip_data(d);
+
+       t = rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+       rt3883_pci_w32(rpc, t & ~BIT(d->hwirq), RT3883_PCI_REG_PCIENA);
+       /* flush write */
+       rt3883_pci_r32(rpc, RT3883_PCI_REG_PCIENA);
+}
+
+static struct irq_chip rt3883_pci_irq_chip = {
+       .name           = "RT3883 PCI",
+       .irq_mask       = rt3883_pci_irq_mask,
+       .irq_unmask     = rt3883_pci_irq_unmask,
+       .irq_mask_ack   = rt3883_pci_irq_mask,
+};
+
+static int rt3883_pci_irq_map(struct irq_domain *d, unsigned int irq,
+                             irq_hw_number_t hw)
+{
+       irq_set_chip_and_handler(irq, &rt3883_pci_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, d->host_data);
+
+       return 0;
+}
+
+static const struct irq_domain_ops rt3883_pci_irq_domain_ops = {
+       .map = rt3883_pci_irq_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
+static int rt3883_pci_irq_init(struct device *dev,
+                              struct rt3883_pci_controller *rpc)
+{
+       int irq;
+
+       irq = irq_of_parse_and_map(rpc->intc_of_node, 0);
+       if (irq == 0) {
+               dev_err(dev, "%s has no IRQ",
+                       of_node_full_name(rpc->intc_of_node));
+               return -EINVAL;
+       }
+
+       /* disable all interrupts */
+       rt3883_pci_w32(rpc, 0, RT3883_PCI_REG_PCIENA);
+
+       rpc->irq_domain =
+               irq_domain_add_linear(rpc->intc_of_node, RT3883_PCI_IRQ_COUNT,
+                                     &rt3883_pci_irq_domain_ops,
+                                     rpc);
+       if (!rpc->irq_domain) {
+               dev_err(dev, "unable to add IRQ domain\n");
+               return -ENODEV;
+       }
+
+       irq_set_handler_data(irq, rpc);
+       irq_set_chained_handler(irq, rt3883_pci_irq_handler);
+
+       return 0;
+}
+
+static int rt3883_pci_config_read(struct pci_bus *bus, unsigned int devfn,
+                                 int where, int size, u32 *val)
+{
+       struct rt3883_pci_controller *rpc;
+       unsigned long flags;
+       u32 address;
+       u32 data;
+
+       rpc = pci_bus_to_rt3883_controller(bus);
+
+       if (!rpc->pcie_ready && bus->number == 1)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
+                                        PCI_FUNC(devfn), where);
+
+       spin_lock_irqsave(&rpc->lock, flags);
+       rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+       data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
+       spin_unlock_irqrestore(&rpc->lock, flags);
+
+       switch (size) {
+       case 1:
+               *val = (data >> ((where & 3) << 3)) & 0xff;
+               break;
+       case 2:
+               *val = (data >> ((where & 3) << 3)) & 0xffff;
+               break;
+       case 4:
+               *val = data;
+               break;
+       }
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static int rt3883_pci_config_write(struct pci_bus *bus, unsigned int devfn,
+                                  int where, int size, u32 val)
+{
+       struct rt3883_pci_controller *rpc;
+       unsigned long flags;
+       u32 address;
+       u32 data;
+
+       rpc = pci_bus_to_rt3883_controller(bus);
+
+       if (!rpc->pcie_ready && bus->number == 1)
+               return PCIBIOS_DEVICE_NOT_FOUND;
+
+       address = rt3883_pci_get_cfgaddr(bus->number, PCI_SLOT(devfn),
+                                        PCI_FUNC(devfn), where);
+
+       spin_lock_irqsave(&rpc->lock, flags);
+       rt3883_pci_w32(rpc, address, RT3883_PCI_REG_CFGADDR);
+       data = rt3883_pci_r32(rpc, RT3883_PCI_REG_CFGDATA);
+
+       switch (size) {
+       case 1:
+               data = (data & ~(0xff << ((where & 3) << 3))) |
+                      (val << ((where & 3) << 3));
+               break;
+       case 2:
+               data = (data & ~(0xffff << ((where & 3) << 3))) |
+                      (val << ((where & 3) << 3));
+               break;
+       case 4:
+               data = val;
+               break;
+       }
+
+       rt3883_pci_w32(rpc, data, RT3883_PCI_REG_CFGDATA);
+       spin_unlock_irqrestore(&rpc->lock, flags);
+
+       return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops rt3883_pci_ops = {
+       .read   = rt3883_pci_config_read,
+       .write  = rt3883_pci_config_write,
+};
+
+static void rt3883_pci_preinit(struct rt3883_pci_controller *rpc, unsigned mode)
+{
+       u32 syscfg1;
+       u32 rstctrl;
+       u32 clkcfg1;
+       u32 t;
+
+       rstctrl = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL);
+       syscfg1 = rt_sysc_r32(RT3883_SYSC_REG_SYSCFG1);
+       clkcfg1 = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1);
+
+       if (mode & RT3883_PCI_MODE_PCIE) {
+               rstctrl |= RT3883_RSTCTRL_PCIE;
+               rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
+
+               /* setup PCI PAD drive mode */
+               syscfg1 &= ~(0x30);
+               syscfg1 |= (2 << 4);
+               rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1);
+
+               t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0);
+               t &= ~BIT(31);
+               rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0);
+
+               t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1);
+               t &= 0x80ffffff;
+               rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1);
+
+               t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN1);
+               t |= 0xa << 24;
+               rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN1);
+
+               t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0);
+               t |= BIT(31);
+               rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0);
+
+               msleep(50);
+
+               rstctrl &= ~RT3883_RSTCTRL_PCIE;
+               rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
+       }
+
+       syscfg1 |= (RT3883_SYSCFG1_PCIE_RC_MODE | RT3883_SYSCFG1_PCI_HOST_MODE);
+
+       clkcfg1 &= ~(RT3883_CLKCFG1_PCI_CLK_EN | RT3883_CLKCFG1_PCIE_CLK_EN);
+
+       if (mode & RT3883_PCI_MODE_PCI) {
+               clkcfg1 |= RT3883_CLKCFG1_PCI_CLK_EN;
+               rstctrl &= ~RT3883_RSTCTRL_PCI;
+       }
+
+       if (mode & RT3883_PCI_MODE_PCIE) {
+               clkcfg1 |= RT3883_CLKCFG1_PCIE_CLK_EN;
+               rstctrl &= ~RT3883_RSTCTRL_PCIE;
+       }
+
+       rt_sysc_w32(syscfg1, RT3883_SYSC_REG_SYSCFG1);
+       rt_sysc_w32(rstctrl, RT3883_SYSC_REG_RSTCTRL);
+       rt_sysc_w32(clkcfg1, RT3883_SYSC_REG_CLKCFG1);
+
+       msleep(500);
+
+       /*
+        * setup the device number of the P2P bridge
+        * and de-assert the reset line
+        */
+       t = (RT3883_P2P_BR_DEVNUM << RT3883_PCICFG_P2P_BR_DEVNUM_S);
+       rt3883_pci_w32(rpc, t, RT3883_PCI_REG_PCICFG);
+
+       /* flush write */
+       rt3883_pci_r32(rpc, RT3883_PCI_REG_PCICFG);
+       msleep(500);
+
+       if (mode & RT3883_PCI_MODE_PCIE) {
+               msleep(500);
+
+               t = rt3883_pci_r32(rpc, RT3883_PCI_REG_STATUS(1));
+
+               rpc->pcie_ready = t & BIT(0);
+
+               if (!rpc->pcie_ready) {
+                       /* reset the PCIe block */
+                       t = rt_sysc_r32(RT3883_SYSC_REG_RSTCTRL);
+                       t |= RT3883_RSTCTRL_PCIE;
+                       rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL);
+                       t &= ~RT3883_RSTCTRL_PCIE;
+                       rt_sysc_w32(t, RT3883_SYSC_REG_RSTCTRL);
+
+                       /* turn off PCIe clock */
+                       t = rt_sysc_r32(RT3883_SYSC_REG_CLKCFG1);
+                       t &= ~RT3883_CLKCFG1_PCIE_CLK_EN;
+                       rt_sysc_w32(t, RT3883_SYSC_REG_CLKCFG1);
+
+                       t = rt_sysc_r32(RT3883_SYSC_REG_PCIE_CLK_GEN0);
+                       t &= ~0xf000c080;
+                       rt_sysc_w32(t, RT3883_SYSC_REG_PCIE_CLK_GEN0);
+               }
+       }
+
+       /* enable PCI arbiter */
+       rt3883_pci_w32(rpc, 0x79, RT3883_PCI_REG_ARBCTL);
+}
+
+static int rt3883_pci_probe(struct platform_device *pdev)
+{
+       struct rt3883_pci_controller *rpc;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct resource *res;
+       struct device_node *child;
+       u32 val;
+       int err;
+       int mode;
+
+       rpc = devm_kzalloc(dev, sizeof(*rpc), GFP_KERNEL);
+       if (!rpc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -EINVAL;
+
+       rpc->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(rpc->base))
+               return PTR_ERR(rpc->base);
+
+       /* find the interrupt controller child node */
+       for_each_child_of_node(np, child) {
+               if (of_get_property(child, "interrupt-controller", NULL) &&
+                   of_node_get(child)) {
+                       rpc->intc_of_node = child;
+                       break;
+               }
+       }
+
+       if (!rpc->intc_of_node) {
+               dev_err(dev, "%s has no %s child node",
+                       of_node_full_name(rpc->intc_of_node),
+                       "interrupt controller");
+               return -EINVAL;
+       }
+
+       /* find the PCI host bridge child node */
+       for_each_child_of_node(np, child) {
+               if (child->type &&
+                   of_node_cmp(child->type, "pci") == 0 &&
+                   of_node_get(child)) {
+                       rpc->pci_controller.of_node = child;
+                       break;
+               }
+       }
+
+       if (!rpc->pci_controller.of_node) {
+               dev_err(dev, "%s has no %s child node",
+                       of_node_full_name(rpc->intc_of_node),
+                       "PCI host bridge");
+               err = -EINVAL;
+               goto err_put_intc_node;
+       }
+
+       mode = RT3883_PCI_MODE_NONE;
+       for_each_available_child_of_node(rpc->pci_controller.of_node, child) {
+               int devfn;
+
+               if (!child->type ||
+                   of_node_cmp(child->type, "pci") != 0)
+                       continue;
+
+               devfn = of_pci_get_devfn(child);
+               if (devfn < 0)
+                       continue;
+
+               switch (PCI_SLOT(devfn)) {
+               case 1:
+                       mode |= RT3883_PCI_MODE_PCIE;
+                       break;
+
+               case 17:
+               case 18:
+                       mode |= RT3883_PCI_MODE_PCI;
+                       break;
+               }
+       }
+
+       if (mode == RT3883_PCI_MODE_NONE) {
+               dev_err(dev, "unable to determine PCI mode\n");
+               err = -EINVAL;
+               goto err_put_hb_node;
+       }
+
+       dev_info(dev, "mode:%s%s\n",
+                (mode & RT3883_PCI_MODE_PCI) ? " PCI" : "",
+                (mode & RT3883_PCI_MODE_PCIE) ? " PCIe" : "");
+
+       rt3883_pci_preinit(rpc, mode);
+
+       rpc->pci_controller.pci_ops = &rt3883_pci_ops;
+       rpc->pci_controller.io_resource = &rpc->io_res;
+       rpc->pci_controller.mem_resource = &rpc->mem_res;
+
+       /* Load PCI I/O and memory resources from DT */
+       pci_load_of_ranges(&rpc->pci_controller,
+                          rpc->pci_controller.of_node);
+
+       rt3883_pci_w32(rpc, rpc->mem_res.start, RT3883_PCI_REG_MEMBASE);
+       rt3883_pci_w32(rpc, rpc->io_res.start, RT3883_PCI_REG_IOBASE);
+
+       ioport_resource.start = rpc->io_res.start;
+       ioport_resource.end = rpc->io_res.end;
+
+       /* PCI */
+       rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(0));
+       rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(0));
+       rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(0));
+       rt3883_pci_w32(rpc, 0x00800001, RT3883_PCI_REG_CLASS(0));
+       rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(0));
+
+       /* PCIe */
+       rt3883_pci_w32(rpc, 0x03ff0000, RT3883_PCI_REG_BAR0SETUP(1));
+       rt3883_pci_w32(rpc, RT3883_MEMORY_BASE, RT3883_PCI_REG_IMBASEBAR0(1));
+       rt3883_pci_w32(rpc, 0x08021814, RT3883_PCI_REG_ID(1));
+       rt3883_pci_w32(rpc, 0x06040001, RT3883_PCI_REG_CLASS(1));
+       rt3883_pci_w32(rpc, 0x28801814, RT3883_PCI_REG_SUBID(1));
+
+       err = rt3883_pci_irq_init(dev, rpc);
+       if (err)
+               goto err_put_hb_node;
+
+       /* PCIe */
+       val = rt3883_pci_read_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND);
+       val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+       rt3883_pci_write_cfg32(rpc, 0, 0x01, 0, PCI_COMMAND, val);
+
+       /* PCI */
+       val = rt3883_pci_read_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND);
+       val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+       rt3883_pci_write_cfg32(rpc, 0, 0x00, 0, PCI_COMMAND, val);
+
+       if (mode == RT3883_PCI_MODE_PCIE) {
+               rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(0));
+               rt3883_pci_w32(rpc, 0x03ff0001, RT3883_PCI_REG_BAR0SETUP(1));
+
+               rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0,
+                                      PCI_BASE_ADDRESS_0,
+                                      RT3883_MEMORY_BASE);
+               /* flush write */
+               rt3883_pci_read_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0,
+                                     PCI_BASE_ADDRESS_0);
+       } else {
+               rt3883_pci_write_cfg32(rpc, 0, RT3883_P2P_BR_DEVNUM, 0,
+                                      PCI_IO_BASE, 0x00000101);
+       }
+
+       register_pci_controller(&rpc->pci_controller);
+
+       return 0;
+
+err_put_hb_node:
+       of_node_put(rpc->pci_controller.of_node);
+err_put_intc_node:
+       of_node_put(rpc->intc_of_node);
+       return err;
+}
+
+int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
+{
+       struct of_irq dev_irq;
+       int err;
+       int irq;
+
+       err = of_irq_map_pci(dev, &dev_irq);
+       if (err) {
+               pr_err("pci %s: unable to get irq map, err=%d\n",
+                      pci_name((struct pci_dev *) dev), err);
+               return 0;
+       }
+
+       irq = irq_create_of_mapping(dev_irq.controller,
+                                   dev_irq.specifier,
+                                   dev_irq.size);
+
+       if (irq == 0)
+               pr_crit("pci %s: no irq found for pin %u\n",
+                       pci_name((struct pci_dev *) dev), pin);
+       else
+               pr_info("pci %s: using irq %d for pin %u\n",
+                       pci_name((struct pci_dev *) dev), irq, pin);
+
+       return irq;
+}
+
+int pcibios_plat_dev_init(struct pci_dev *dev)
+{
+       return 0;
+}
+
+static const struct of_device_id rt3883_pci_ids[] = {
+       { .compatible = "ralink,rt3883-pci" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rt3883_pci_ids);
+
+static struct platform_driver rt3883_pci_driver = {
+       .probe = rt3883_pci_probe,
+       .driver = {
+               .name = "rt3883-pci",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(rt3883_pci_ids),
+       },
+};
+
+static int __init rt3883_pci_init(void)
+{
+       return platform_driver_register(&rt3883_pci_driver);
+}
+
+postcore_initcall(rt3883_pci_init);
index 1a1b03ea639800afce418ea6e2d2e8ec1287aaee..dd91fbacbcbaee493b7553f576dc96f7b39d51b0 100644 (file)
@@ -1,14 +1,7 @@
-config BOOTLOADER_DRIVER
-       bool "PowerTV Bootloader Driver Support"
-       default n
-       depends on POWERTV
-       help
-         Use this option if you want to load bootloader driver.
-
 config BOOTLOADER_FAMILY
        string "POWERTV Bootloader Family string"
        default "85"
-       depends on POWERTV && !BOOTLOADER_DRIVER
+       depends on POWERTV
        help
          This value should be specified when the bootloader driver is disabled
          and must be exactly two characters long. Families supported are:
index 0238af1ba50383689138a929c268a1a592a1464d..8380605d597d3082d09801bb9cbba1a82230658a 100644 (file)
@@ -147,20 +147,10 @@ static __init noinline void platform_set_family(void)
        if (check_forcefamily(forced_family) == 0)
                bootldr_family = BOOTLDRFAMILY(forced_family[0],
                        forced_family[1]);
-       else {
-
-#ifdef CONFIG_BOOTLOADER_DRIVER
-               bootldr_family = (unsigned short) kbldr_GetSWFamily();
-#else
-#if defined(CONFIG_BOOTLOADER_FAMILY)
+       else
                bootldr_family = (unsigned short) BOOTLDRFAMILY(
                        CONFIG_BOOTLOADER_FAMILY[0],
                        CONFIG_BOOTLOADER_FAMILY[1]);
-#else
-#error "Unknown Bootloader Family"
-#endif
-#endif
-       }
 
        pr_info("Bootloader Family = 0x%04X\n", bootldr_family);
 
index a01baff52cae0ab1ad652574843049c6cf640097..498926377e51e4e53ba6017b1d46ebeb94e322a2 100644 (file)
@@ -87,8 +87,4 @@ void __init prom_init(void)
 
        configure_platform();
        prom_meminit();
-
-#ifndef CONFIG_BOOTLOADER_DRIVER
-       pr_info("\nBootloader driver isn't loaded...\n");
-#endif
 }
index 0007652cb774afbaddbe8a494ca08ed76f8999d7..11c32fbf2784657ec2afc47c8f098f00c0f7fa82 100644 (file)
 #include <linux/io.h>
 #include <asm/reboot.h>                        /* Not included by linux/reboot.h */
 
-#ifdef CONFIG_BOOTLOADER_DRIVER
-#include <asm/mach-powertv/kbldr.h>
-#endif
-
 #include <asm/mach-powertv/asic_regs.h>
 #include "reset.h"
 
 static void mips_machine_restart(char *command)
 {
-#ifdef CONFIG_BOOTLOADER_DRIVER
-       /*
-        * Call the bootloader's reset function to ensure
-        * that persistent data is flushed before hard reset
-        */
-       kbldr_SetCauseAndReset();
-#else
        writel(0x1, asic_reg_addr(watchdog));
-#endif
 }
 
 void mips_reboot_setup(void)
index 026e823d871d34e8952ba22b064e59cd4b778fda..424f03496d14ad6de256329d967083990faf98ca 100644 (file)
@@ -1,5 +1,12 @@
 if RALINK
 
+config CLKEVT_RT3352
+       bool
+       depends on SOC_RT305X || SOC_MT7620
+       default y
+       select CLKSRC_OF
+       select CLKSRC_MMIO
+
 choice
        prompt "Ralink SoC selection"
        default SOC_RT305X
@@ -19,9 +26,12 @@ choice
                bool "RT3883"
                select USB_ARCH_HAS_OHCI
                select USB_ARCH_HAS_EHCI
+               select HW_HAS_PCI
 
        config SOC_MT7620
                bool "MT7620"
+               select USB_ARCH_HAS_OHCI
+               select USB_ARCH_HAS_EHCI
 
 endchoice
 
index 38cf1a880aaac21ca6b0e38b3561e1832aa5e4c3..98ae349827be8068943e16db9e851cbfd1cc4501 100644 (file)
@@ -6,7 +6,9 @@
 # Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org>
 # Copyright (C) 2013 John Crispin <blogic@openwrt.org>
 
-obj-y := prom.o of.o reset.o clk.o irq.o
+obj-y := prom.o of.o reset.o clk.o irq.o timer.o
+
+obj-$(CONFIG_CLKEVT_RT3352) += cevt-rt3352.o
 
 obj-$(CONFIG_SOC_RT288X) += rt288x.o
 obj-$(CONFIG_SOC_RT305X) += rt305x.o
index cda4b6645c50587da40f9ad9ffa0357d27fe74ab..6d9c8c499f988d4949f72c6484f8e948dff6fec2 100644 (file)
@@ -26,3 +26,4 @@ cflags-$(CONFIG_SOC_RT3883)   += -I$(srctree)/arch/mips/include/asm/mach-ralink/rt
 # Ralink MT7620
 #
 load-$(CONFIG_SOC_MT7620)      += 0xffffffff80000000
+cflags-$(CONFIG_SOC_MT7620)    += -I$(srctree)/arch/mips/include/asm/mach-ralink/mt7620
diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c
new file mode 100644 (file)
index 0000000..cc17566
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2013 by John Crispin <blogic@openwrt.org>
+ */
+
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/interrupt.h>
+#include <linux/reset.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define SYSTICK_FREQ           (50 * 1000)
+
+#define SYSTICK_CONFIG         0x00
+#define SYSTICK_COMPARE                0x04
+#define SYSTICK_COUNT          0x08
+
+/* route systick irq to mips irq 7 instead of the r4k-timer */
+#define CFG_EXT_STK_EN         0x2
+/* enable the counter */
+#define CFG_CNT_EN             0x1
+
+struct systick_device {
+       void __iomem *membase;
+       struct clock_event_device dev;
+       int irq_requested;
+       int freq_scale;
+};
+
+static void systick_set_clock_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt);
+
+static int systick_next_event(unsigned long delta,
+                               struct clock_event_device *evt)
+{
+       struct systick_device *sdev;
+       u32 count;
+
+       sdev = container_of(evt, struct systick_device, dev);
+       count = ioread32(sdev->membase + SYSTICK_COUNT);
+       count = (count + delta) % SYSTICK_FREQ;
+       iowrite32(count + delta, sdev->membase + SYSTICK_COMPARE);
+
+       return 0;
+}
+
+static void systick_event_handler(struct clock_event_device *dev)
+{
+       /* noting to do here */
+}
+
+static irqreturn_t systick_interrupt(int irq, void *dev_id)
+{
+       struct clock_event_device *dev = (struct clock_event_device *) dev_id;
+
+       dev->event_handler(dev);
+
+       return IRQ_HANDLED;
+}
+
+static struct systick_device systick = {
+       .dev = {
+               /*
+                * cevt-r4k uses 300, make sure systick
+                * gets used if available
+                */
+               .rating         = 310,
+               .features       = CLOCK_EVT_FEAT_ONESHOT,
+               .set_next_event = systick_next_event,
+               .set_mode       = systick_set_clock_mode,
+               .event_handler  = systick_event_handler,
+       },
+};
+
+static struct irqaction systick_irqaction = {
+       .handler = systick_interrupt,
+       .flags = IRQF_PERCPU | IRQF_TIMER,
+       .dev_id = &systick.dev,
+};
+
+static void systick_set_clock_mode(enum clock_event_mode mode,
+                               struct clock_event_device *evt)
+{
+       struct systick_device *sdev;
+
+       sdev = container_of(evt, struct systick_device, dev);
+
+       switch (mode) {
+       case CLOCK_EVT_MODE_ONESHOT:
+               if (!sdev->irq_requested)
+                       setup_irq(systick.dev.irq, &systick_irqaction);
+               sdev->irq_requested = 1;
+               iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN,
+                               systick.membase + SYSTICK_CONFIG);
+               break;
+
+       case CLOCK_EVT_MODE_SHUTDOWN:
+               if (sdev->irq_requested)
+                       free_irq(systick.dev.irq, &systick_irqaction);
+               sdev->irq_requested = 0;
+               iowrite32(0, systick.membase + SYSTICK_CONFIG);
+               break;
+
+       default:
+               pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name);
+               break;
+       }
+}
+
+static void __init ralink_systick_init(struct device_node *np)
+{
+       systick.membase = of_iomap(np, 0);
+       if (!systick.membase)
+               return;
+
+       systick_irqaction.name = np->name;
+       systick.dev.name = np->name;
+       clockevents_calc_mult_shift(&systick.dev, SYSTICK_FREQ, 60);
+       systick.dev.max_delta_ns = clockevent_delta2ns(0x7fff, &systick.dev);
+       systick.dev.min_delta_ns = clockevent_delta2ns(0x3, &systick.dev);
+       systick.dev.irq = irq_of_parse_and_map(np, 0);
+       if (!systick.dev.irq) {
+               pr_err("%s: request_irq failed", np->name);
+               return;
+       }
+
+       clocksource_mmio_init(systick.membase + SYSTICK_COUNT, np->name,
+                       SYSTICK_FREQ, 301, 16, clocksource_mmio_readl_up);
+
+       clockevents_register_device(&systick.dev);
+
+       pr_info("%s: runing - mult: %d, shift: %d\n",
+                       np->name, systick.dev.mult, systick.dev.shift);
+}
+
+CLOCKSOURCE_OF_DECLARE(systick, "ralink,cevt-systick", ralink_systick_init);
index 8dfa22ff300b610cba4af13e6806da023a8ca5c3..bba0cdfd83bcd37b2278dce3fdec6f8980bfbb19 100644 (file)
@@ -69,4 +69,5 @@ void __init plat_time_init(void)
        pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
        mips_hpt_frequency = clk_get_rate(clk) / 2;
        clk_put(clk);
+       clocksource_of_init();
 }
index 83144c3fc5acc32c0b619b7b7f4ac9949a4e4e1e..42dfd6100a2decde80ae81c6b88d81e316c40dff 100644 (file)
@@ -46,6 +46,8 @@ extern void ralink_of_remap(void);
 extern void ralink_clk_init(void);
 extern void ralink_clk_add(const char *dev, unsigned long rate);
 
+extern void ralink_rst_init(void);
+
 extern void prom_soc_init(struct ralink_soc_info *soc_info);
 
 __iomem void *plat_of_remap_node(const char *node);
index 0018b1a661f6a0a193ea29601cb319b32f200ef4..d217509e530093f0154783c32f8b016ff419f8a4 100644 (file)
@@ -23,9 +23,6 @@
 /* does the board have sdram or ddram */
 static int dram_type;
 
-/* the pll dividers */
-static u32 mt7620_clk_divider[] = { 2, 3, 4, 8 };
-
 static struct ralink_pinmux_grp mode_mux[] = {
        {
                .name = "i2c",
@@ -140,34 +137,189 @@ struct ralink_pinmux rt_gpio_pinmux = {
        .uart_mask = MT7620_GPIO_MODE_UART0_MASK,
 };
 
-void __init ralink_clk_init(void)
+static __init u32
+mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div)
 {
-       unsigned long cpu_rate, sys_rate;
-       u32 c0 = rt_sysc_r32(SYSC_REG_CPLL_CONFIG0);
-       u32 c1 = rt_sysc_r32(SYSC_REG_CPLL_CONFIG1);
-       u32 swconfig = (c0 >> CPLL_SW_CONFIG_SHIFT) & CPLL_SW_CONFIG_MASK;
-       u32 cpu_clk = (c1 >> CPLL_CPU_CLK_SHIFT) & CPLL_CPU_CLK_MASK;
-
-       if (cpu_clk) {
-               cpu_rate = 480000000;
-       } else if (!swconfig) {
-               cpu_rate = 600000000;
-       } else {
-               u32 m = (c0 >> CPLL_MULT_RATIO_SHIFT) & CPLL_MULT_RATIO;
-               u32 d = (c0 >> CPLL_DIV_RATIO_SHIFT) & CPLL_DIV_RATIO;
+       u64 t;
 
-               cpu_rate = ((40 * (m + 24)) / mt7620_clk_divider[d]) * 1000000;
-       }
+       t = ref_rate;
+       t *= mul;
+       do_div(t, div);
+
+       return t;
+}
+
+#define MHZ(x)         ((x) * 1000 * 1000)
+
+static __init unsigned long
+mt7620_get_xtal_rate(void)
+{
+       u32 reg;
+
+       reg = rt_sysc_r32(SYSC_REG_SYSTEM_CONFIG0);
+       if (reg & SYSCFG0_XTAL_FREQ_SEL)
+               return MHZ(40);
+
+       return MHZ(20);
+}
+
+static __init unsigned long
+mt7620_get_periph_rate(unsigned long xtal_rate)
+{
+       u32 reg;
+
+       reg = rt_sysc_r32(SYSC_REG_CLKCFG0);
+       if (reg & CLKCFG0_PERI_CLK_SEL)
+               return xtal_rate;
+
+       return MHZ(40);
+}
+
+static const u32 mt7620_clk_divider[] __initconst = { 2, 3, 4, 8 };
+
+static __init unsigned long
+mt7620_get_cpu_pll_rate(unsigned long xtal_rate)
+{
+       u32 reg;
+       u32 mul;
+       u32 div;
+
+       reg = rt_sysc_r32(SYSC_REG_CPLL_CONFIG0);
+       if (reg & CPLL_CFG0_BYPASS_REF_CLK)
+               return xtal_rate;
+
+       if ((reg & CPLL_CFG0_SW_CFG) == 0)
+               return MHZ(600);
+
+       mul = (reg >> CPLL_CFG0_PLL_MULT_RATIO_SHIFT) &
+             CPLL_CFG0_PLL_MULT_RATIO_MASK;
+       mul += 24;
+       if (reg & CPLL_CFG0_LC_CURFCK)
+               mul *= 2;
+
+       div = (reg >> CPLL_CFG0_PLL_DIV_RATIO_SHIFT) &
+             CPLL_CFG0_PLL_DIV_RATIO_MASK;
+
+       WARN_ON(div >= ARRAY_SIZE(mt7620_clk_divider));
+
+       return mt7620_calc_rate(xtal_rate, mul, mt7620_clk_divider[div]);
+}
+
+static __init unsigned long
+mt7620_get_pll_rate(unsigned long xtal_rate, unsigned long cpu_pll_rate)
+{
+       u32 reg;
+
+       reg = rt_sysc_r32(SYSC_REG_CPLL_CONFIG1);
+       if (reg & CPLL_CFG1_CPU_AUX1)
+               return xtal_rate;
+
+       if (reg & CPLL_CFG1_CPU_AUX0)
+               return MHZ(480);
 
+       return cpu_pll_rate;
+}
+
+static __init unsigned long
+mt7620_get_cpu_rate(unsigned long pll_rate)
+{
+       u32 reg;
+       u32 mul;
+       u32 div;
+
+       reg = rt_sysc_r32(SYSC_REG_CPU_SYS_CLKCFG);
+
+       mul = reg & CPU_SYS_CLKCFG_CPU_FFRAC_MASK;
+       div = (reg >> CPU_SYS_CLKCFG_CPU_FDIV_SHIFT) &
+             CPU_SYS_CLKCFG_CPU_FDIV_MASK;
+
+       return mt7620_calc_rate(pll_rate, mul, div);
+}
+
+static const u32 mt7620_ocp_dividers[16] __initconst = {
+       [CPU_SYS_CLKCFG_OCP_RATIO_2] = 2,
+       [CPU_SYS_CLKCFG_OCP_RATIO_3] = 3,
+       [CPU_SYS_CLKCFG_OCP_RATIO_4] = 4,
+       [CPU_SYS_CLKCFG_OCP_RATIO_5] = 5,
+       [CPU_SYS_CLKCFG_OCP_RATIO_10] = 10,
+};
+
+static __init unsigned long
+mt7620_get_dram_rate(unsigned long pll_rate)
+{
        if (dram_type == SYSCFG0_DRAM_TYPE_SDRAM)
-               sys_rate = cpu_rate / 4;
-       else
-               sys_rate = cpu_rate / 3;
+               return pll_rate / 4;
+
+       return pll_rate / 3;
+}
+
+static __init unsigned long
+mt7620_get_sys_rate(unsigned long cpu_rate)
+{
+       u32 reg;
+       u32 ocp_ratio;
+       u32 div;
+
+       reg = rt_sysc_r32(SYSC_REG_CPU_SYS_CLKCFG);
+
+       ocp_ratio = (reg >> CPU_SYS_CLKCFG_OCP_RATIO_SHIFT) &
+                   CPU_SYS_CLKCFG_OCP_RATIO_MASK;
+
+       if (WARN_ON(ocp_ratio >= ARRAY_SIZE(mt7620_ocp_dividers)))
+               return cpu_rate;
+
+       div = mt7620_ocp_dividers[ocp_ratio];
+       if (WARN(!div, "invalid divider for OCP ratio %u", ocp_ratio))
+               return cpu_rate;
+
+       return cpu_rate / div;
+}
+
+void __init ralink_clk_init(void)
+{
+       unsigned long xtal_rate;
+       unsigned long cpu_pll_rate;
+       unsigned long pll_rate;
+       unsigned long cpu_rate;
+       unsigned long sys_rate;
+       unsigned long dram_rate;
+       unsigned long periph_rate;
+
+       xtal_rate = mt7620_get_xtal_rate();
+
+       cpu_pll_rate = mt7620_get_cpu_pll_rate(xtal_rate);
+       pll_rate = mt7620_get_pll_rate(xtal_rate, cpu_pll_rate);
+
+       cpu_rate = mt7620_get_cpu_rate(pll_rate);
+       dram_rate = mt7620_get_dram_rate(pll_rate);
+       sys_rate = mt7620_get_sys_rate(cpu_rate);
+       periph_rate = mt7620_get_periph_rate(xtal_rate);
+
+#define RFMT(label)    label ":%lu.%03luMHz "
+#define RINT(x)                ((x) / 1000000)
+#define RFRAC(x)       (((x) / 1000) % 1000)
+
+       pr_debug(RFMT("XTAL") RFMT("CPU_PLL") RFMT("PLL"),
+                RINT(xtal_rate), RFRAC(xtal_rate),
+                RINT(cpu_pll_rate), RFRAC(cpu_pll_rate),
+                RINT(pll_rate), RFRAC(pll_rate));
+
+       pr_debug(RFMT("CPU") RFMT("DRAM") RFMT("SYS") RFMT("PERIPH"),
+                RINT(cpu_rate), RFRAC(cpu_rate),
+                RINT(dram_rate), RFRAC(dram_rate),
+                RINT(sys_rate), RFRAC(sys_rate),
+                RINT(periph_rate), RFRAC(periph_rate));
+
+#undef RFRAC
+#undef RINT
+#undef RFMT
 
        ralink_clk_add("cpu", cpu_rate);
-       ralink_clk_add("10000100.timer", 40000000);
-       ralink_clk_add("10000500.uart", 40000000);
-       ralink_clk_add("10000c00.uartlite", 40000000);
+       ralink_clk_add("10000100.timer", periph_rate);
+       ralink_clk_add("10000120.watchdog", periph_rate);
+       ralink_clk_add("10000500.uart", periph_rate);
+       ralink_clk_add("10000b00.spi", sys_rate);
+       ralink_clk_add("10000c00.uartlite", periph_rate);
 }
 
 void __init ralink_of_remap(void)
@@ -214,16 +366,19 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
 
        switch (dram_type) {
        case SYSCFG0_DRAM_TYPE_SDRAM:
+               pr_info("Board has SDRAM\n");
                soc_info->mem_size_min = MT7620_SDRAM_SIZE_MIN;
                soc_info->mem_size_max = MT7620_SDRAM_SIZE_MAX;
                break;
 
        case SYSCFG0_DRAM_TYPE_DDR1:
+               pr_info("Board has DDR1\n");
                soc_info->mem_size_min = MT7620_DDR1_SIZE_MIN;
                soc_info->mem_size_max = MT7620_DDR1_SIZE_MAX;
                break;
 
        case SYSCFG0_DRAM_TYPE_DDR2:
+               pr_info("Board has DDR2\n");
                soc_info->mem_size_min = MT7620_DDR2_SIZE_MIN;
                soc_info->mem_size_max = MT7620_DDR2_SIZE_MAX;
                break;
index f25ea5b45051dc8b6a28f369f7c1a5a0623cfa7f..ce38d11f9da5bdb3baaec1821dec2a6a25ae4836 100644 (file)
@@ -110,6 +110,9 @@ static int __init plat_of_setup(void)
        if (of_platform_populate(NULL, of_ids, NULL, NULL))
                panic("failed to populate DT\n");
 
+       /* make sure ithat the reset controller is setup early */
+       ralink_rst_init();
+
        return 0;
 }
 
index 22120e512e7e2b92b999c9905baee20edcf29268..55c7ec59df3cca8a73259ee84731189a91db49ce 100644 (file)
@@ -10,6 +10,8 @@
 
 #include <linux/pm.h>
 #include <linux/io.h>
+#include <linux/of.h>
+#include <linux/reset-controller.h>
 
 #include <asm/reboot.h>
 
 #define SYSC_REG_RESET_CTRL     0x034
 #define RSTCTL_RESET_SYSTEM     BIT(0)
 
+static int ralink_assert_device(struct reset_controller_dev *rcdev,
+                               unsigned long id)
+{
+       u32 val;
+
+       if (id < 8)
+               return -1;
+
+       val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
+       val |= BIT(id);
+       rt_sysc_w32(val, SYSC_REG_RESET_CTRL);
+
+       return 0;
+}
+
+static int ralink_deassert_device(struct reset_controller_dev *rcdev,
+                                 unsigned long id)
+{
+       u32 val;
+
+       if (id < 8)
+               return -1;
+
+       val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
+       val &= ~BIT(id);
+       rt_sysc_w32(val, SYSC_REG_RESET_CTRL);
+
+       return 0;
+}
+
+static int ralink_reset_device(struct reset_controller_dev *rcdev,
+                              unsigned long id)
+{
+       ralink_assert_device(rcdev, id);
+       return ralink_deassert_device(rcdev, id);
+}
+
+static struct reset_control_ops reset_ops = {
+       .reset = ralink_reset_device,
+       .assert = ralink_assert_device,
+       .deassert = ralink_deassert_device,
+};
+
+static struct reset_controller_dev reset_dev = {
+       .ops                    = &reset_ops,
+       .owner                  = THIS_MODULE,
+       .nr_resets              = 32,
+       .of_reset_n_cells       = 1,
+};
+
+void ralink_rst_init(void)
+{
+       reset_dev.of_node = of_find_compatible_node(NULL, NULL,
+                                               "ralink,rt2880-reset");
+       if (!reset_dev.of_node)
+               pr_err("Failed to find reset controller node");
+       else
+               reset_controller_register(&reset_dev);
+}
+
 static void ralink_restart(char *command)
 {
        local_irq_disable();
diff --git a/arch/mips/ralink/timer.c b/arch/mips/ralink/timer.c
new file mode 100644 (file)
index 0000000..e49241a
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
+*/
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/of_gpio.h>
+#include <linux/clk.h>
+
+#include <asm/mach-ralink/ralink_regs.h>
+
+#define TIMER_REG_TMRSTAT              0x00
+#define TIMER_REG_TMR0LOAD             0x10
+#define TIMER_REG_TMR0CTL              0x18
+
+#define TMRSTAT_TMR0INT                        BIT(0)
+
+#define TMR0CTL_ENABLE                 BIT(7)
+#define TMR0CTL_MODE_PERIODIC          BIT(4)
+#define TMR0CTL_PRESCALER              1
+#define TMR0CTL_PRESCALE_VAL           (0xf - TMR0CTL_PRESCALER)
+#define TMR0CTL_PRESCALE_DIV           (65536 / BIT(TMR0CTL_PRESCALER))
+
+struct rt_timer {
+       struct device   *dev;
+       void __iomem    *membase;
+       int             irq;
+       unsigned long   timer_freq;
+       unsigned long   timer_div;
+};
+
+static inline void rt_timer_w32(struct rt_timer *rt, u8 reg, u32 val)
+{
+       __raw_writel(val, rt->membase + reg);
+}
+
+static inline u32 rt_timer_r32(struct rt_timer *rt, u8 reg)
+{
+       return __raw_readl(rt->membase + reg);
+}
+
+static irqreturn_t rt_timer_irq(int irq, void *_rt)
+{
+       struct rt_timer *rt =  (struct rt_timer *) _rt;
+
+       rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+       rt_timer_w32(rt, TIMER_REG_TMRSTAT, TMRSTAT_TMR0INT);
+
+       return IRQ_HANDLED;
+}
+
+
+static int rt_timer_request(struct rt_timer *rt)
+{
+       int err = request_irq(rt->irq, rt_timer_irq, IRQF_DISABLED,
+                                               dev_name(rt->dev), rt);
+       if (err) {
+               dev_err(rt->dev, "failed to request irq\n");
+       } else {
+               u32 t = TMR0CTL_MODE_PERIODIC | TMR0CTL_PRESCALE_VAL;
+               rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
+       }
+       return err;
+}
+
+static void rt_timer_free(struct rt_timer *rt)
+{
+       free_irq(rt->irq, rt);
+}
+
+static int rt_timer_config(struct rt_timer *rt, unsigned long divisor)
+{
+       if (rt->timer_freq < divisor)
+               rt->timer_div = rt->timer_freq;
+       else
+               rt->timer_div = divisor;
+
+       rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+
+       return 0;
+}
+
+static int rt_timer_enable(struct rt_timer *rt)
+{
+       u32 t;
+
+       rt_timer_w32(rt, TIMER_REG_TMR0LOAD, rt->timer_freq / rt->timer_div);
+
+       t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
+       t |= TMR0CTL_ENABLE;
+       rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
+
+       return 0;
+}
+
+static void rt_timer_disable(struct rt_timer *rt)
+{
+       u32 t;
+
+       t = rt_timer_r32(rt, TIMER_REG_TMR0CTL);
+       t &= ~TMR0CTL_ENABLE;
+       rt_timer_w32(rt, TIMER_REG_TMR0CTL, t);
+}
+
+static int rt_timer_probe(struct platform_device *pdev)
+{
+       struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       struct rt_timer *rt;
+       struct clk *clk;
+
+       rt = devm_kzalloc(&pdev->dev, sizeof(*rt), GFP_KERNEL);
+       if (!rt) {
+               dev_err(&pdev->dev, "failed to allocate memory\n");
+               return -ENOMEM;
+       }
+
+       rt->irq = platform_get_irq(pdev, 0);
+       if (!rt->irq) {
+               dev_err(&pdev->dev, "failed to load irq\n");
+               return -ENOENT;
+       }
+
+       rt->membase = devm_request_and_ioremap(&pdev->dev, res);
+       if (IS_ERR(rt->membase))
+               return PTR_ERR(rt->membase);
+
+       clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(clk)) {
+               dev_err(&pdev->dev, "failed get clock rate\n");
+               return PTR_ERR(clk);
+       }
+
+       rt->timer_freq = clk_get_rate(clk) / TMR0CTL_PRESCALE_DIV;
+       if (!rt->timer_freq)
+               return -EINVAL;
+
+       rt->dev = &pdev->dev;
+       platform_set_drvdata(pdev, rt);
+
+       rt_timer_request(rt);
+       rt_timer_config(rt, 2);
+       rt_timer_enable(rt);
+
+       dev_info(&pdev->dev, "maximum frequncy is %luHz\n", rt->timer_freq);
+
+       return 0;
+}
+
+static int rt_timer_remove(struct platform_device *pdev)
+{
+       struct rt_timer *rt = platform_get_drvdata(pdev);
+
+       rt_timer_disable(rt);
+       rt_timer_free(rt);
+
+       return 0;
+}
+
+static const struct of_device_id rt_timer_match[] = {
+       { .compatible = "ralink,rt2880-timer" },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rt_timer_match);
+
+static struct platform_driver rt_timer_driver = {
+       .probe = rt_timer_probe,
+       .remove = rt_timer_remove,
+       .driver = {
+               .name           = "rt-timer",
+               .owner          = THIS_MODULE,
+               .of_match_table = rt_timer_match
+       },
+};
+
+module_platform_driver(rt_timer_driver);
+
+MODULE_DESCRIPTION("Ralink RT2880 timer");
+MODULE_AUTHOR("John Crispin <blogic@openwrt.org");
+MODULE_LICENSE("GPL");
index 05ed92c92b696f20d6c1356086ef3f79d94026f6..8e2e04f7787068bdd2d3421d14b33ef3cc283867 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 
 #include <asm/bootinfo.h>
+#include <asm/cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/io.h>
 #include <asm/sibyte/sb1250.h>
@@ -119,7 +120,7 @@ void __init bcm1480_setup(void)
        uint64_t sys_rev;
        int plldiv;
 
-       sb1_pass = read_c0_prid() & 0xff;
+       sb1_pass = read_c0_prid() & PRID_REV_MASK;
        sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION));
        soc_type = SYS_SOC_TYPE(sys_rev);
        part_type = G_SYS_PART(sys_rev);
index a14bd4cb0bc0cd70fd2468b0cea55ad5ba9da091..3c02b2a77ae996b0d84ebe085fe697d6879cb144 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 
 #include <asm/bootinfo.h>
+#include <asm/cpu.h>
 #include <asm/mipsregs.h>
 #include <asm/io.h>
 #include <asm/sibyte/sb1250.h>
@@ -182,7 +183,7 @@ void __init sb1250_setup(void)
        int plldiv;
        int bad_config = 0;
 
-       sb1_pass = read_c0_prid() & 0xff;
+       sb1_pass = read_c0_prid() & PRID_REV_MASK;
        sys_rev = __raw_readq(IOADDR(A_SCD_SYSTEM_REVISION));
        soc_type = SYS_SOC_TYPE(sys_rev);
        soc_pass = G_SYS_REVISION(sys_rev);
index 5b09b3544edd156583603d37e3575669f6211fd2..efad85c8c823b9377c88322d5def836eb494eb59 100644 (file)
@@ -25,6 +25,7 @@
 #endif
 
 #include <asm/bootinfo.h>
+#include <asm/cpu.h>
 #include <asm/io.h>
 #include <asm/reboot.h>
 #include <asm/sni.h>
@@ -173,7 +174,7 @@ void __init plat_mem_setup(void)
                system_type = "RM300-Cxx";
                break;
        case SNI_BRD_PCI_DESKTOP:
-               switch (read_c0_prid() & 0xff00) {
+               switch (read_c0_prid() & PRID_IMP_MASK) {
                case PRID_IMP_R4600:
                case PRID_IMP_R4700:
                        system_type = "RM200-C20";
index 681e7f86c08000f29884ce369efafab86afe1b29..2b0b83c171e0959dfb946fd027ef32aa2ec31ca4 100644 (file)
@@ -350,7 +350,7 @@ static void __init select_board(void)
        }
 
        /* select "default" board */
-#ifdef CONFIG_CPU_TX39XX
+#ifdef CONFIG_TOSHIBA_JMR3927
        txx9_board_vec = &jmr3927_vec;
 #endif
 #ifdef CONFIG_CPU_TX49XX
index 70e4f663ebd2818d6532bd14cf71c0893867f3b1..6aaa1607001a42980c95a1984c7775bc5359826a 100644 (file)
@@ -1,7 +1,6 @@
 config MN10300
        def_bool y
        select HAVE_OPROFILE
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_ARCH_TRACEHOOK
index 222152a3f75195b429a6794e036c279cdb2e6160..177d61de51c938557596658847b6903d13d24ed9 100644 (file)
@@ -171,10 +171,10 @@ ret_from_intr:
        mov     (REG_EPSW,fp),d0        # need to deliver signals before
                                        # returning to userspace
        and     EPSW_nSL,d0
-       beq     resume_kernel           # returning to supervisor mode
+       bne     resume_userspace        # returning to userspace
 
 #ifdef CONFIG_PREEMPT
-ENTRY(resume_kernel)
+resume_kernel:
        LOCAL_IRQ_DISABLE
        mov     (TI_preempt_count,a2),d0        # non-zero preempt_count ?
        cmp     0,d0
@@ -189,6 +189,8 @@ need_resched:
        bne     restore_all
        call    preempt_schedule_irq[],0
        jmp     need_resched
+#else
+       jmp     resume_kernel
 #endif
 
 
index 8a2e6ded9a4465e247890166f6a9ddadd25c7987..3516cbdf1ee93acb82ebef6428f79df9af104514 100644 (file)
@@ -171,6 +171,8 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long fault_code,
        if (in_atomic() || !mm)
                goto no_context;
 
+       if ((fault_code & MMUFCR_xFC_ACCESS) == MMUFCR_xFC_ACCESS_USR)
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
 
index d60bf98fa5cf399430d5beaaed9e3cd9c7188e67..9488209a52533432b7e42392d1bdd918a45dc840 100644 (file)
@@ -11,7 +11,6 @@ config OPENRISC
        select HAVE_MEMBLOCK
        select ARCH_REQUIRE_GPIOLIB
         select HAVE_ARCH_TRACEHOOK
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_CHIP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
index 5869e3fa5dd3ac4f9b31cd63140ac01592593ddd..a63e76872f84da088c8d28105f55d3687807f2f5 100644 (file)
@@ -55,11 +55,6 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        memblock_add(base, size);
 }
 
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-{
-       return __va(memblock_alloc(size, align));
-}
-
 void __init early_init_devtree(void *params)
 {
        void *alloc;
@@ -96,8 +91,7 @@ void __init early_init_devtree(void *params)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 4a41f8493ab0b4d9276a05315884d076fb440db9..0703acf7d3276811919fd3d398ada99b1b9c6d50 100644 (file)
@@ -86,6 +86,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long address,
        if (user_mode(regs)) {
                /* Exception was in userspace: reenable interrupts */
                local_irq_enable();
+               flags |= FAULT_FLAG_USER;
        } else {
                /* If exception was in a syscall, then IRQ's may have
                 * been enabled or disabled.  If they were enabled,
index aa399a5259b6ce406302ac79a8770312ca688aad..ad2ce8dab9963c4dd6867ee83064460576084089 100644 (file)
@@ -14,7 +14,6 @@ config PARISC
        select HAVE_PERF_EVENTS
        select GENERIC_ATOMIC64 if !64BIT
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
-       select HAVE_GENERIC_HARDIRQS
        select BROKEN_RODATA
        select GENERIC_IRQ_PROBE
        select GENERIC_PCI_IOMAP
index f247a3480e8e0cd7e276f4fd04004cbb608b3e11..d10d27a720c0d1f323c2248f01cc93193e73ca1e 100644 (file)
@@ -180,6 +180,10 @@ void do_page_fault(struct pt_regs *regs, unsigned long code,
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+       if (acc_type & VM_WRITE)
+               flags |= FAULT_FLAG_WRITE;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma_prev(mm, address, &prev_vma);
@@ -203,8 +207,7 @@ good_area:
         * fault.
         */
 
-       fault = handle_mm_fault(mm, vma, address,
-                       flags | ((acc_type & VM_WRITE) ? FAULT_FLAG_WRITE : 0));
+       fault = handle_mm_fault(mm, vma, address, flags);
 
        if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
                return;
index 6b7530f8183c3c98a0fd42a8cdef3b1643ce33ce..38f3b7e47ec5efd190018de0d9bba1d2ef5b4011 100644 (file)
@@ -114,7 +114,6 @@ config PPC
        select HAVE_PERF_EVENTS
        select HAVE_REGS_AND_STACK_ACCESS_API
        select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64
-       select HAVE_GENERIC_HARDIRQS
        select ARCH_WANT_IPC_PARSE_VERSION
        select SPARSE_IRQ
        select IRQ_DOMAIN
index 77e97dd0c15d8b495ee245a3fbcc14aa38a2f785..38faeded7d595d506de55188ca8180c6e31ba67f 100644 (file)
@@ -28,6 +28,9 @@ struct dev_archdata {
                void            *iommu_table_base;
        } dma_data;
 
+#ifdef CONFIG_IOMMU_API
+       void                    *iommu_domain;
+#endif
 #ifdef CONFIG_SWIOTLB
        dma_addr_t              max_direct_dma_addr;
 #endif
diff --git a/arch/powerpc/include/asm/fsl_pamu_stash.h b/arch/powerpc/include/asm/fsl_pamu_stash.h
new file mode 100644 (file)
index 0000000..caa1b21
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 (C) 2013 Freescale Semiconductor, Inc.
+ *
+ */
+
+#ifndef __FSL_PAMU_STASH_H
+#define __FSL_PAMU_STASH_H
+
+/* cache stash targets */
+enum pamu_stash_target {
+       PAMU_ATTR_CACHE_L1 = 1,
+       PAMU_ATTR_CACHE_L2,
+       PAMU_ATTR_CACHE_L3,
+};
+
+/*
+ * This attribute allows configuring stashig specific parameters
+ * in the PAMU hardware.
+ */
+
+struct pamu_stash_attribute {
+       u32     cpu;    /* cpu number */
+       u32     cache;  /* cache to stash to: L1,L2,L3 */
+};
+
+#endif  /* __FSL_PAMU_STASH_H */
index 6bfcab97c981a9b7978dac1491d5362247b24006..b7634ce41dbc92bd67cd5ed1c6c7cd584924ccc4 100644 (file)
@@ -546,14 +546,8 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        memblock_add(base, size);
 }
 
-void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
-{
-       return __va(memblock_alloc(size, align));
-}
-
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 7b6391b68fb882b20abdf59703e6addd64ac27fc..12e656ffe60ea86a00a531578efd55ef98e3faef 100644 (file)
@@ -1297,7 +1297,8 @@ static void __init prom_query_opal(void)
                prom_opal_align = 0x10000;
 }
 
-static int prom_rtas_call(int token, int nargs, int nret, int *outputs, ...)
+static int __init prom_rtas_call(int token, int nargs, int nret,
+                                int *outputs, ...)
 {
        struct rtas_args rtas_args;
        va_list list;
index 442d8e23f8f4088368c6ebda73375a28de2ce66a..8e59abc237d7f17c96effa20583206e75b2e4b7a 100644 (file)
@@ -611,6 +611,7 @@ int cpu_to_chip_id(int cpu)
        of_node_put(np);
        return of_get_ibm_chip_id(np);
 }
+EXPORT_SYMBOL(cpu_to_chip_id);
 
 /* Helper routines for cpu to core mapping */
 int cpu_core_index_of_thread(int cpu)
index 76d8e7cc7805348098f622e0043a4364c9a7f1a1..51ab9e7e6c391b9497a08730a7b5e4c625c96304 100644 (file)
@@ -206,7 +206,7 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        int trap = TRAP(regs);
        int is_exec = trap == 0x400;
        int fault;
-       int rc = 0;
+       int rc = 0, store_update_sp = 0;
 
 #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE))
        /*
@@ -223,9 +223,6 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
        is_write = error_code & ESR_DST;
 #endif /* CONFIG_4xx || CONFIG_BOOKE */
 
-       if (is_write)
-               flags |= FAULT_FLAG_WRITE;
-
 #ifdef CONFIG_PPC_ICSWX
        /*
         * we need to do this early because this "data storage
@@ -280,6 +277,17 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address,
 
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
 
+       /*
+        * We want to do this outside mmap_sem, because reading code around nip
+        * can result in fault, which will cause a deadlock when called with
+        * mmap_sem held
+        */
+       if (user_mode(regs))
+               store_update_sp = store_updates_sp(regs);
+
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+
        /* When running in the kernel we expect faults to occur only to
         * addresses in user space.  All other faults represent errors in the
         * kernel and should generate an OOPS.  Unfortunately, in the case of an
@@ -345,8 +353,7 @@ retry:
                 * between the last mapped region and the stack will
                 * expand the stack rather than segfaulting.
                 */
-               if (address + 2048 < uregs->gpr[1]
-                   && (!user_mode(regs) || !store_updates_sp(regs)))
+               if (address + 2048 < uregs->gpr[1] && !store_update_sp)
                        goto bad_area;
        }
        if (expand_stack(vma, address))
@@ -408,6 +415,7 @@ good_area:
        } else if (is_write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        /* a read */
        } else {
                /* protection fault */
index 834ca8eb38f202e01c5151fdb56b13197ed6acc8..d67db4bd672dd4223065c9b5470ee368a9456d1d 100644 (file)
@@ -86,6 +86,11 @@ int pgd_huge(pgd_t pgd)
         */
        return ((pgd_val(pgd) & 0x3) != 0x0);
 }
+
+int pmd_huge_support(void)
+{
+       return 1;
+}
 #else
 int pmd_huge(pmd_t pmd)
 {
@@ -101,6 +106,11 @@ int pgd_huge(pgd_t pgd)
 {
        return 0;
 }
+
+int pmd_huge_support(void)
+{
+       return 0;
+}
 #endif
 
 pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
index f3900427ffab5173ee05041a7375b9633312e835..87ba7cf99cd754590ffaf2f038926ae9098f4ca9 100644 (file)
@@ -620,12 +620,16 @@ spufs_parse_options(struct super_block *sb, char *options, struct inode *root)
                case Opt_uid:
                        if (match_int(&args[0], &option))
                                return 0;
-                       root->i_uid = option;
+                       root->i_uid = make_kuid(current_user_ns(), option);
+                       if (!uid_valid(root->i_uid))
+                               return 0;
                        break;
                case Opt_gid:
                        if (match_int(&args[0], &option))
                                return 0;
-                       root->i_gid = option;
+                       root->i_gid = make_kgid(current_user_ns(), option);
+                       if (!gid_valid(root->i_gid))
+                               return 0;
                        break;
                case Opt_mode:
                        if (match_octal(&args[0], &option))
index d64feb3ea0be48600d71ca97f3bbd3c561181ed8..1f97e2b87a62b85d30bf848a8dbab31938304f21 100644 (file)
@@ -354,7 +354,7 @@ static int alloc_dispatch_log_kmem_cache(void)
 }
 early_initcall(alloc_dispatch_log_kmem_cache);
 
-static void pSeries_idle(void)
+static void pseries_lpar_idle(void)
 {
        /* This would call on the cpuidle framework, and the back-end pseries
         * driver to  go to idle states
@@ -362,10 +362,22 @@ static void pSeries_idle(void)
        if (cpuidle_idle_call()) {
                /* On error, execute default handler
                 * to go into low thread priority and possibly
-                * low power mode.
+                * low power mode by cedeing processor to hypervisor
                 */
-               HMT_low();
-               HMT_very_low();
+
+               /* Indicate to hypervisor that we are idle. */
+               get_lppaca()->idle = 1;
+
+               /*
+                * Yield the processor to the hypervisor.  We return if
+                * an external interrupt occurs (which are driven prior
+                * to returning here) or if a prod occurs from another
+                * processor. When returning here, external interrupts
+                * are enabled.
+                */
+               cede_processor();
+
+               get_lppaca()->idle = 0;
        }
 }
 
@@ -456,15 +468,14 @@ static void __init pSeries_setup_arch(void)
 
        pSeries_nvram_init();
 
-       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+       if (firmware_has_feature(FW_FEATURE_LPAR)) {
                vpa_init(boot_cpuid);
-               ppc_md.power_save = pSeries_idle;
-       }
-
-       if (firmware_has_feature(FW_FEATURE_LPAR))
+               ppc_md.power_save = pseries_lpar_idle;
                ppc_md.enable_pmcs = pseries_lpar_enable_pmcs;
-       else
+       } else {
+               /* No special idle routine */
                ppc_md.enable_pmcs = power4_enable_pmcs;
+       }
 
        ppc_md.pcibios_root_bridge_prepare = pseries_root_bridge_prepare;
 
index defc422a375f1083703c47962c4a245b48284061..8d455df584711c84c004468be1656fd4b55e36eb 100644 (file)
 
 struct platform_device;
 
+
+/* FSL PCI controller BRR1 register */
+#define PCI_FSL_BRR1      0xbf8
+#define PCI_FSL_BRR1_VER 0xffff
+
 #define PCIE_LTSSM     0x0404          /* PCIE Link Training and Status */
 #define PCIE_LTSSM_L0  0x16            /* L0 state */
 #define PCIE_IP_REV_2_2                0x02080202 /* PCIE IP block version Rev2.2 */
index c696ad7d3439d55e0d763caa14325a5b2447edbc..dcc6ac2d802637ab6e5fb9c004eaa69ba5e01479 100644 (file)
@@ -62,6 +62,7 @@ config S390
        def_bool y
        select ARCH_DISCARD_MEMBLOCK
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+       select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_INLINE_READ_LOCK
        select ARCH_INLINE_READ_LOCK_BH
@@ -91,7 +92,6 @@ config S390
        select ARCH_INLINE_WRITE_UNLOCK_BH
        select ARCH_INLINE_WRITE_UNLOCK_IRQ
        select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE
-       select ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS
        select ARCH_SAVE_PAGE_KEYS if HIBERNATION
        select ARCH_WANT_IPC_PARSE_VERSION
        select BUILDTIME_EXTABLE_SORT
@@ -116,7 +116,6 @@ config S390
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_FUNCTION_TRACER
        select HAVE_FUNCTION_TRACE_MCOUNT_TEST
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZ4
@@ -135,15 +134,15 @@ config S390
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_UID16 if 32BIT
        select HAVE_VIRT_CPU_ACCOUNTING
-       select VIRT_TO_BUS
        select INIT_ALL_POSSIBLE
        select KTIME_SCALAR if 32BIT
        select MODULES_USE_ELF_RELA
-       select OLD_SIGSUSPEND3
        select OLD_SIGACTION
+       select OLD_SIGSUSPEND3
        select SYSCTL_EXCEPTION_TRACE
        select USE_GENERIC_SMP_HELPERS if SMP
        select VIRT_CPU_ACCOUNTING
+       select VIRT_TO_BUS
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
@@ -526,6 +525,7 @@ config CRASH_DUMP
        bool "kernel crash dumps"
        depends on 64BIT && SMP
        select KEXEC
+       select ZFCPDUMP
        help
          Generate crash dump after being started by kexec.
          Crash dump kernels are loaded in the main kernel with kexec-tools
@@ -536,7 +536,7 @@ config CRASH_DUMP
 config ZFCPDUMP
        def_bool n
        prompt "zfcpdump support"
-       select SMP
+       depends on SMP
        help
          Select this option if you want to build an zfcpdump enabled kernel.
          Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
index b74400e3e035f3ce5fc1668bd1bd15ab7a11b1a2..d204c65bf722cf7ad35d12d3643830cee5880d8c 100644 (file)
@@ -1,14 +1,13 @@
-CONFIG_EXPERIMENTAL=y
 CONFIG_SYSVIPC=y
 CONFIG_POSIX_MQUEUE=y
 CONFIG_FHANDLE=y
+CONFIG_AUDIT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
 CONFIG_TASKSTATS=y
 CONFIG_TASK_DELAY_ACCT=y
 CONFIG_TASK_XACCT=y
 CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_AUDIT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
 CONFIG_RCU_FAST_NO_HZ=y
 CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
@@ -27,6 +26,7 @@ CONFIG_RD_BZIP2=y
 CONFIG_RD_LZMA=y
 CONFIG_RD_XZ=y
 CONFIG_RD_LZO=y
+CONFIG_RD_LZ4=y
 CONFIG_EXPERT=y
 # CONFIG_COMPAT_BRK is not set
 CONFIG_PROFILING=y
@@ -38,11 +38,13 @@ CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_IBM_PARTITION=y
+# CONFIG_EFI_PARTITION is not set
 CONFIG_DEFAULT_DEADLINE=y
 CONFIG_HZ_100=y
 CONFIG_MEMORY_HOTPLUG=y
 CONFIG_MEMORY_HOTREMOVE=y
 CONFIG_KSM=y
+CONFIG_TRANSPARENT_HUGEPAGE=y
 CONFIG_CRASH_DUMP=y
 CONFIG_BINFMT_MISC=m
 CONFIG_HIBERNATION=y
@@ -92,40 +94,49 @@ CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 CONFIG_SCSI_SCAN_ASYNC=y
 CONFIG_ZFCP=y
+CONFIG_SCSI_VIRTIO=y
 CONFIG_NETDEVICES=y
 CONFIG_BONDING=m
 CONFIG_DUMMY=m
 CONFIG_EQUALIZER=m
 CONFIG_TUN=m
 CONFIG_VIRTIO_NET=y
+# CONFIG_INPUT is not set
+# CONFIG_SERIO is not set
 CONFIG_RAW_DRIVER=m
 CONFIG_VIRTIO_BALLOON=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT4_FS=y
 CONFIG_EXT4_FS_POSIX_ACL=y
 CONFIG_EXT4_FS_SECURITY=y
+CONFIG_XFS_FS=y
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_POSIX_ACL=y
+CONFIG_XFS_RT=y
+CONFIG_BTRFS_FS=y
+CONFIG_BTRFS_FS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_FUSE_FS=y
 CONFIG_PROC_KCORE=y
 CONFIG_TMPFS=y
 CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_HUGETLBFS=y
 # CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
 CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_TIMER_STATS=y
 CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
 CONFIG_LOCK_STAT=y
 CONFIG_DEBUG_LOCKDEP=y
 CONFIG_DEBUG_LIST=y
 CONFIG_DEBUG_NOTIFIERS=y
+CONFIG_PROVE_RCU=y
+CONFIG_RCU_CPU_STALL_TIMEOUT=60
 CONFIG_RCU_TRACE=y
-CONFIG_KPROBES_SANITY_TEST=y
-CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y
 CONFIG_LATENCYTOP=y
-CONFIG_DEBUG_PAGEALLOC=y
 CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_KPROBES_SANITY_TEST=y
 # CONFIG_STRICT_DEVMEM is not set
-CONFIG_CRYPTO_NULL=m
 CONFIG_CRYPTO_CRYPTD=m
 CONFIG_CRYPTO_AUTHENC=m
 CONFIG_CRYPTO_TEST=m
@@ -137,8 +148,10 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_LRW=m
 CONFIG_CRYPTO_PCBC=m
 CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_CMAC=m
 CONFIG_CRYPTO_XCBC=m
 CONFIG_CRYPTO_VMAC=m
+CONFIG_CRYPTO_CRC32=m
 CONFIG_CRYPTO_MD4=m
 CONFIG_CRYPTO_MICHAEL_MIC=m
 CONFIG_CRYPTO_RMD128=m
@@ -165,6 +178,8 @@ CONFIG_CRYPTO_TWOFISH=m
 CONFIG_CRYPTO_DEFLATE=m
 CONFIG_CRYPTO_ZLIB=m
 CONFIG_CRYPTO_LZO=m
+CONFIG_CRYPTO_LZ4=m
+CONFIG_CRYPTO_LZ4HC=m
 CONFIG_ZCRYPT=m
 CONFIG_CRYPTO_SHA1_S390=m
 CONFIG_CRYPTO_SHA256_S390=m
index 1eaa3625803c1d30f41ee4a98847c82619a93857..5f8bcc5fe423abc27f64064cf1602a2ecff370a3 100644 (file)
@@ -78,10 +78,14 @@ typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long);
 
 int register_external_interrupt(u16 code, ext_int_handler_t handler);
 int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
-void service_subclass_irq_register(void);
-void service_subclass_irq_unregister(void);
-void measurement_alert_subclass_register(void);
-void measurement_alert_subclass_unregister(void);
+
+enum irq_subclass {
+       IRQ_SUBCLASS_MEASUREMENT_ALERT = 5,
+       IRQ_SUBCLASS_SERVICE_SIGNAL = 9,
+};
+
+void irq_subclass_register(enum irq_subclass subclass);
+void irq_subclass_unregister(enum irq_subclass subclass);
 
 #define irq_canonicalize(irq)  (irq)
 
index dcf6948a875ca6d0b12b08100cc3d2362d28224b..4176dfe0fba1c75ed253966ecab56eeea54c174b 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/ptrace.h>
 #include <linux/percpu.h>
 
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+
 struct pt_regs;
 struct kprobe;
 
@@ -57,7 +59,7 @@ typedef u16 kprobe_opcode_t;
 /* Architecture specific copy of original instruction */
 struct arch_specific_insn {
        /* copy of original instruction */
-       kprobe_opcode_t insn[MAX_INSN_SIZE];
+       kprobe_opcode_t *insn;
 };
 
 struct prev_kprobe {
index 06a136136047735afb0bb3abddddc4166c97519c..7dc7f9c63b65f35f62de8566de198c97333acef6 100644 (file)
@@ -56,5 +56,6 @@ bool sclp_has_linemode(void);
 bool sclp_has_vt220(void);
 int sclp_pci_configure(u32 fid);
 int sclp_pci_deconfigure(u32 fid);
+int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
 
 #endif /* _ASM_S390_SCLP_H */
index 8b6e4f5288a29cc155fb1a3f20d46c08da38be07..1f1b8c70ab97ce9e5b9445d5dc020f8a75bfac77 100644 (file)
@@ -221,25 +221,26 @@ static int groups16_from_user(struct group_info *group_info, u16 __user *groupli
 
 asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist)
 {
+       const struct cred *cred = current_cred();
        int i;
 
        if (gidsetsize < 0)
                return -EINVAL;
 
-       get_group_info(current->cred->group_info);
-       i = current->cred->group_info->ngroups;
+       get_group_info(cred->group_info);
+       i = cred->group_info->ngroups;
        if (gidsetsize) {
                if (i > gidsetsize) {
                        i = -EINVAL;
                        goto out;
                }
-               if (groups16_to_user(grouplist, current->cred->group_info)) {
+               if (groups16_to_user(grouplist, cred->group_info)) {
                        i = -EFAULT;
                        goto out;
                }
        }
 out:
-       put_group_info(current->cred->group_info);
+       put_group_info(cred->group_info);
        return i;
 }
 
index c439ac9ced092a6a8c4ea710b3127c4bb6cb3014..1389b637dae55018e3eab8b18dd3f44e9440e078 100644 (file)
@@ -332,9 +332,9 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
+               regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
        } else {
-               regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
+               regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;
                if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn,
                               (u16 __force __user *)(frame->retcode)))
                        goto give_sigsegv;
@@ -400,9 +400,9 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
        /* Set up to return from userspace.  If provided, use a stub
           already in userspace.  */
        if (ka->sa.sa_flags & SA_RESTORER) {
-               regs->gprs[14] = (__u64) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
+               regs->gprs[14] = (__u64 __force) ka->sa.sa_restorer | PSW32_ADDR_AMODE;
        } else {
-               regs->gprs[14] = (__u64) frame->retcode | PSW32_ADDR_AMODE;
+               regs->gprs[14] = (__u64 __force) frame->retcode | PSW32_ADDR_AMODE;
                err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn,
                                  (u16 __force __user *)(frame->retcode));
        }
@@ -417,7 +417,7 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->psw.mask = PSW_MASK_BA |
                (psw_user_bits & PSW_MASK_ASC) |
                (regs->psw.mask & ~PSW_MASK_ASC);
-       regs->psw.addr = (__u64) ka->sa.sa_handler;
+       regs->psw.addr = (__u64 __force) ka->sa.sa_handler;
 
        regs->gprs[2] = map_signal(sig);
        regs->gprs[3] = (__force __u64) &frame->info;
index d8f3556571717dd7cc8b4c21efc07268110fb15c..c84f33d51f7b45d92d66b870f9b35c23d5054568 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/os_info.h>
 #include <asm/elf.h>
 #include <asm/ipl.h>
+#include <asm/sclp.h>
 
 #define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
 #define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
@@ -64,22 +65,46 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize)
 }
 
 /*
- * Copy one page from "oldmem"
+ * Pointer to ELF header in new kernel
+ */
+static void *elfcorehdr_newmem;
+
+/*
+ * Copy one page from zfcpdump "oldmem"
+ *
+ * For pages below ZFCPDUMP_HSA_SIZE memory from the HSA is copied. Otherwise
+ * real memory copy is used.
+ */
+static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
+                                        unsigned long src, int userbuf)
+{
+       int rc;
+
+       if (src < ZFCPDUMP_HSA_SIZE) {
+               rc = memcpy_hsa(buf, src, csize, userbuf);
+       } else {
+               if (userbuf)
+                       rc = copy_to_user_real((void __force __user *) buf,
+                                              (void *) src, csize);
+               else
+                       rc = memcpy_real(buf, (void *) src, csize);
+       }
+       return rc ? rc : csize;
+}
+
+/*
+ * Copy one page from kdump "oldmem"
  *
  * For the kdump reserved memory this functions performs a swap operation:
  *  - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
  *  - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
  */
-ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
-                        size_t csize, unsigned long offset, int userbuf)
+static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
+                                     unsigned long src, int userbuf)
+
 {
-       unsigned long src;
        int rc;
 
-       if (!csize)
-               return 0;
-
-       src = (pfn << PAGE_SHIFT) + offset;
        if (src < OLDMEM_SIZE)
                src += OLDMEM_BASE;
        else if (src > OLDMEM_BASE &&
@@ -90,7 +115,88 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
                                       (void *) src, csize);
        else
                rc = copy_page_real(buf, (void *) src, csize);
-       return (rc == 0) ? csize : rc;
+       return (rc == 0) ? rc : csize;
+}
+
+/*
+ * Copy one page from "oldmem"
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
+                        unsigned long offset, int userbuf)
+{
+       unsigned long src;
+
+       if (!csize)
+               return 0;
+       src = (pfn << PAGE_SHIFT) + offset;
+       if (OLDMEM_BASE)
+               return copy_oldmem_page_kdump(buf, csize, src, userbuf);
+       else
+               return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf);
+}
+
+/*
+ * Remap "oldmem" for kdump
+ *
+ * For the kdump reserved memory this functions performs a swap operation:
+ * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
+ */
+static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
+                                       unsigned long from, unsigned long pfn,
+                                       unsigned long size, pgprot_t prot)
+{
+       unsigned long size_old;
+       int rc;
+
+       if (pfn < OLDMEM_SIZE >> PAGE_SHIFT) {
+               size_old = min(size, OLDMEM_SIZE - (pfn << PAGE_SHIFT));
+               rc = remap_pfn_range(vma, from,
+                                    pfn + (OLDMEM_BASE >> PAGE_SHIFT),
+                                    size_old, prot);
+               if (rc || size == size_old)
+                       return rc;
+               size -= size_old;
+               from += size_old;
+               pfn += size_old >> PAGE_SHIFT;
+       }
+       return remap_pfn_range(vma, from, pfn, size, prot);
+}
+
+/*
+ * Remap "oldmem" for zfcpdump
+ *
+ * We only map available memory above ZFCPDUMP_HSA_SIZE. Memory below
+ * ZFCPDUMP_HSA_SIZE is read on demand using the copy_oldmem_page() function.
+ */
+static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
+                                          unsigned long from,
+                                          unsigned long pfn,
+                                          unsigned long size, pgprot_t prot)
+{
+       unsigned long size_hsa;
+
+       if (pfn < ZFCPDUMP_HSA_SIZE >> PAGE_SHIFT) {
+               size_hsa = min(size, ZFCPDUMP_HSA_SIZE - (pfn << PAGE_SHIFT));
+               if (size == size_hsa)
+                       return 0;
+               size -= size_hsa;
+               from += size_hsa;
+               pfn += size_hsa >> PAGE_SHIFT;
+       }
+       return remap_pfn_range(vma, from, pfn, size, prot);
+}
+
+/*
+ * Remap "oldmem" for kdump or zfcpdump
+ */
+int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
+                          unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+       if (OLDMEM_BASE)
+               return remap_oldmem_pfn_range_kdump(vma, from, pfn, size, prot);
+       else
+               return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size,
+                                                      prot);
 }
 
 /*
@@ -101,11 +207,21 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
        unsigned long copied = 0;
        int rc;
 
-       if ((unsigned long) src < OLDMEM_SIZE) {
-               copied = min(count, OLDMEM_SIZE - (unsigned long) src);
-               rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
-               if (rc)
-                       return rc;
+       if (OLDMEM_BASE) {
+               if ((unsigned long) src < OLDMEM_SIZE) {
+                       copied = min(count, OLDMEM_SIZE - (unsigned long) src);
+                       rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
+                       if (rc)
+                               return rc;
+               }
+       } else {
+               if ((unsigned long) src < ZFCPDUMP_HSA_SIZE) {
+                       copied = min(count,
+                                    ZFCPDUMP_HSA_SIZE - (unsigned long) src);
+                       rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
+                       if (rc)
+                               return rc;
+               }
        }
        return memcpy_real(dest + copied, src + copied, count - copied);
 }
@@ -367,14 +483,6 @@ static int get_mem_chunk_cnt(void)
        return cnt;
 }
 
-/*
- * Relocate pointer in order to allow vmcore code access the data
- */
-static inline unsigned long relocate(unsigned long addr)
-{
-       return OLDMEM_BASE + addr;
-}
-
 /*
  * Initialize ELF loads (new kernel)
  */
@@ -426,7 +534,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
        ptr = nt_vmcoreinfo(ptr);
        memset(phdr, 0, sizeof(*phdr));
        phdr->p_type = PT_NOTE;
-       phdr->p_offset = relocate(notes_offset);
+       phdr->p_offset = notes_offset;
        phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
        phdr->p_memsz = phdr->p_filesz;
        return ptr;
@@ -435,7 +543,7 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
 /*
  * Create ELF core header (new kernel)
  */
-static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz)
+int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
 {
        Elf64_Phdr *phdr_notes, *phdr_loads;
        int mem_chunk_cnt;
@@ -443,6 +551,12 @@ static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz)
        u32 alloc_size;
        u64 hdr_off;
 
+       /* If we are not in kdump or zfcpdump mode return */
+       if (!OLDMEM_BASE && ipl_info.type != IPL_TYPE_FCP_DUMP)
+               return 0;
+       /* If elfcorehdr= has been passed via cmdline, we use that one */
+       if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
+               return 0;
        mem_chunk_cnt = get_mem_chunk_cnt();
 
        alloc_size = 0x1000 + get_cpu_cnt() * 0x300 +
@@ -460,27 +574,52 @@ static void s390_elf_corehdr_create(char **elfcorebuf, size_t *elfcorebuf_sz)
        ptr = notes_init(phdr_notes, ptr, ((unsigned long) hdr) + hdr_off);
        /* Init loads */
        hdr_off = PTR_DIFF(ptr, hdr);
-       loads_init(phdr_loads, ((unsigned long) hdr) + hdr_off);
-       *elfcorebuf_sz = hdr_off;
-       *elfcorebuf = (void *) relocate((unsigned long) hdr);
-       BUG_ON(*elfcorebuf_sz > alloc_size);
+       loads_init(phdr_loads, hdr_off);
+       *addr = (unsigned long long) hdr;
+       elfcorehdr_newmem = hdr;
+       *size = (unsigned long long) hdr_off;
+       BUG_ON(elfcorehdr_size > alloc_size);
+       return 0;
 }
 
 /*
- * Create kdump ELF core header in new kernel, if it has not been passed via
- * the "elfcorehdr" kernel parameter
+ * Free ELF core header (new kernel)
  */
-static int setup_kdump_elfcorehdr(void)
+void elfcorehdr_free(unsigned long long addr)
 {
-       size_t elfcorebuf_sz;
-       char *elfcorebuf;
+       if (!elfcorehdr_newmem)
+               return;
+       kfree((void *)(unsigned long)addr);
+}
 
-       if (!OLDMEM_BASE || is_kdump_kernel())
-               return -EINVAL;
-       s390_elf_corehdr_create(&elfcorebuf, &elfcorebuf_sz);
-       elfcorehdr_addr = (unsigned long long) elfcorebuf;
-       elfcorehdr_size = elfcorebuf_sz;
-       return 0;
+/*
+ * Read from ELF header
+ */
+ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
+{
+       void *src = (void *)(unsigned long)*ppos;
+
+       src = elfcorehdr_newmem ? src : src - OLDMEM_BASE;
+       memcpy(buf, src, count);
+       *ppos += count;
+       return count;
 }
 
-subsys_initcall(setup_kdump_elfcorehdr);
+/*
+ * Read from ELF notes data
+ */
+ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
+{
+       void *src = (void *)(unsigned long)*ppos;
+       int rc;
+
+       if (elfcorehdr_newmem) {
+               memcpy(buf, src, count);
+       } else {
+               rc = copy_from_oldmem(buf, src, count);
+               if (rc)
+                       return rc;
+       }
+       *ppos += count;
+       return count;
+}
index 87acc38f73c63b5631c25bfc55d619fb9128f842..99e7f6035895e0cceccbc0ae6bf123a871a5d6a3 100644 (file)
@@ -40,14 +40,15 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high)
 {
        struct stack_frame *sf;
        struct pt_regs *regs;
+       unsigned long addr;
 
        while (1) {
                sp = sp & PSW_ADDR_INSN;
                if (sp < low || sp > high - sizeof(*sf))
                        return sp;
                sf = (struct stack_frame *) sp;
-               printk("([<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
-               print_symbol("%s)\n", sf->gprs[8] & PSW_ADDR_INSN);
+               addr = sf->gprs[8] & PSW_ADDR_INSN;
+               printk("([<%016lx>] %pSR)\n", addr, (void *)addr);
                /* Follow the backchain. */
                while (1) {
                        low = sp;
@@ -57,16 +58,16 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high)
                        if (sp <= low || sp > high - sizeof(*sf))
                                return sp;
                        sf = (struct stack_frame *) sp;
-                       printk(" [<%016lx>] ", sf->gprs[8] & PSW_ADDR_INSN);
-                       print_symbol("%s\n", sf->gprs[8] & PSW_ADDR_INSN);
+                       addr = sf->gprs[8] & PSW_ADDR_INSN;
+                       printk(" [<%016lx>] %pSR\n", addr, (void *)addr);
                }
                /* Zero backchain detected, check for interrupt frame. */
                sp = (unsigned long) (sf + 1);
                if (sp <= low || sp > high - sizeof(*regs))
                        return sp;
                regs = (struct pt_regs *) sp;
-               printk(" [<%016lx>] ", regs->psw.addr & PSW_ADDR_INSN);
-               print_symbol("%s\n", regs->psw.addr & PSW_ADDR_INSN);
+               addr = regs->psw.addr & PSW_ADDR_INSN;
+               printk(" [<%016lx>] %pSR\n", addr, (void *)addr);
                low = sp;
                sp = regs->gprs[15];
        }
@@ -128,8 +129,7 @@ static void show_last_breaking_event(struct pt_regs *regs)
 {
 #ifdef CONFIG_64BIT
        printk("Last Breaking-Event-Address:\n");
-       printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
-       print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
+       printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]);
 #endif
 }
 
@@ -143,10 +143,10 @@ void show_registers(struct pt_regs *regs)
        char *mode;
 
        mode = user_mode(regs) ? "User" : "Krnl";
-       printk("%s PSW : %p %p",
+       printk("%s PSW : %p %p (%pSR)\n",
               mode, (void *) regs->psw.mask,
+              (void *) regs->psw.addr,
               (void *) regs->psw.addr);
-       print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN);
        printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
               "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
               mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
index 3ddbc26d246e399a0e01bd295c1d9bbec741f034..e9b04c33d38306781f1c5d3ead2c5a3ba3b0d009 100644 (file)
@@ -53,27 +53,21 @@ void handle_signal32(unsigned long sig, struct k_sigaction *ka,
                    siginfo_t *info, sigset_t *oldset, struct pt_regs *regs);
 void do_notify_resume(struct pt_regs *regs);
 
-struct ext_code;
-void do_extint(struct pt_regs *regs);
+void __init init_IRQ(void);
+void do_IRQ(struct pt_regs *regs, int irq);
 void do_restart(void);
 void __init startup_init(void);
 void die(struct pt_regs *regs, const char *str);
-
+int setup_profiling_timer(unsigned int multiplier);
 void __init time_init(void);
+int pfn_is_nosave(unsigned long);
+void s390_early_resume(void);
+unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip);
 
 struct s390_mmap_arg_struct;
 struct fadvise64_64_args;
 struct old_sigaction;
 
-long sys_mmap2(struct s390_mmap_arg_struct __user  *arg);
-long sys_s390_ipc(uint call, int first, unsigned long second,
-            unsigned long third, void __user *ptr);
-long sys_s390_personality(unsigned int personality);
-long sys_s390_fadvise64(int fd, u32 offset_high, u32 offset_low,
-                   size_t len, int advice);
-long sys_s390_fadvise64_64(struct fadvise64_64_args __user *args);
-long sys_s390_fallocate(int fd, int mode, loff_t offset, u32 len_high,
-                       u32 len_low);
 long sys_sigreturn(void);
 long sys_rt_sigreturn(void);
 long sys32_sigreturn(void);
index e3043aef87a96d17d62defc3c14a828625668507..1014ad5f7693eda79c3caa4ad8b7e8b5edb5f3fc 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/kprobes.h>
 #include <trace/syscall.h>
 #include <asm/asm-offsets.h>
+#include "entry.h"
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 
@@ -177,7 +178,7 @@ int ftrace_enable_ftrace_graph_caller(void)
 
        offset = ((void *) prepare_ftrace_return -
                  (void *) ftrace_graph_caller) / 2;
-       return probe_kernel_write(ftrace_graph_caller + 2,
+       return probe_kernel_write((void *) ftrace_graph_caller + 2,
                                  &offset, sizeof(offset));
 }
 
@@ -185,7 +186,7 @@ int ftrace_disable_ftrace_graph_caller(void)
 {
        static unsigned short offset = 0x0002;
 
-       return probe_kernel_write(ftrace_graph_caller + 2,
+       return probe_kernel_write((void *) ftrace_graph_caller + 2,
                                  &offset, sizeof(offset));
 }
 
index b34ba0ea96a9e86e4f391ba6088a827b75b84b5b..8ac2097f13d4e99eeaf913baca503f4532e3a055 100644 (file)
@@ -196,21 +196,23 @@ asmlinkage void do_softirq(void)
  * ext_int_hash[index] is the list head for all external interrupts that hash
  * to this index.
  */
-static struct list_head ext_int_hash[256];
+static struct hlist_head ext_int_hash[32] ____cacheline_aligned;
 
 struct ext_int_info {
        ext_int_handler_t handler;
-       u16 code;
-       struct list_head entry;
+       struct hlist_node entry;
        struct rcu_head rcu;
+       u16 code;
 };
 
 /* ext_int_hash_lock protects the handler lists for external interrupts */
-DEFINE_SPINLOCK(ext_int_hash_lock);
+static DEFINE_SPINLOCK(ext_int_hash_lock);
 
 static inline int ext_hash(u16 code)
 {
-       return (code + (code >> 9)) & 0xff;
+       BUILD_BUG_ON(!is_power_of_2(ARRAY_SIZE(ext_int_hash)));
+
+       return (code + (code >> 9)) & (ARRAY_SIZE(ext_int_hash) - 1);
 }
 
 int register_external_interrupt(u16 code, ext_int_handler_t handler)
@@ -227,7 +229,7 @@ int register_external_interrupt(u16 code, ext_int_handler_t handler)
        index = ext_hash(code);
 
        spin_lock_irqsave(&ext_int_hash_lock, flags);
-       list_add_rcu(&p->entry, &ext_int_hash[index]);
+       hlist_add_head_rcu(&p->entry, &ext_int_hash[index]);
        spin_unlock_irqrestore(&ext_int_hash_lock, flags);
        return 0;
 }
@@ -240,9 +242,9 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
        int index = ext_hash(code);
 
        spin_lock_irqsave(&ext_int_hash_lock, flags);
-       list_for_each_entry_rcu(p, &ext_int_hash[index], entry) {
+       hlist_for_each_entry_rcu(p, &ext_int_hash[index], entry) {
                if (p->code == code && p->handler == handler) {
-                       list_del_rcu(&p->entry);
+                       hlist_del_rcu(&p->entry);
                        kfree_rcu(p, rcu);
                }
        }
@@ -264,12 +266,12 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy)
 
        index = ext_hash(ext_code.code);
        rcu_read_lock();
-       list_for_each_entry_rcu(p, &ext_int_hash[index], entry)
-               if (likely(p->code == ext_code.code))
-                       p->handler(ext_code, regs->int_parm,
-                                  regs->int_parm_long);
+       hlist_for_each_entry_rcu(p, &ext_int_hash[index], entry) {
+               if (unlikely(p->code != ext_code.code))
+                       continue;
+               p->handler(ext_code, regs->int_parm, regs->int_parm_long);
+       }
        rcu_read_unlock();
-
        return IRQ_HANDLED;
 }
 
@@ -283,55 +285,32 @@ void __init init_ext_interrupts(void)
        int idx;
 
        for (idx = 0; idx < ARRAY_SIZE(ext_int_hash); idx++)
-               INIT_LIST_HEAD(&ext_int_hash[idx]);
+               INIT_HLIST_HEAD(&ext_int_hash[idx]);
 
        irq_set_chip_and_handler(EXT_INTERRUPT,
                                 &dummy_irq_chip, handle_percpu_irq);
        setup_irq(EXT_INTERRUPT, &external_interrupt);
 }
 
-static DEFINE_SPINLOCK(sc_irq_lock);
-static int sc_irq_refcount;
-
-void service_subclass_irq_register(void)
-{
-       spin_lock(&sc_irq_lock);
-       if (!sc_irq_refcount)
-               ctl_set_bit(0, 9);
-       sc_irq_refcount++;
-       spin_unlock(&sc_irq_lock);
-}
-EXPORT_SYMBOL(service_subclass_irq_register);
-
-void service_subclass_irq_unregister(void)
-{
-       spin_lock(&sc_irq_lock);
-       sc_irq_refcount--;
-       if (!sc_irq_refcount)
-               ctl_clear_bit(0, 9);
-       spin_unlock(&sc_irq_lock);
-}
-EXPORT_SYMBOL(service_subclass_irq_unregister);
-
-static DEFINE_SPINLOCK(ma_subclass_lock);
-static int ma_subclass_refcount;
+static DEFINE_SPINLOCK(irq_subclass_lock);
+static unsigned char irq_subclass_refcount[64];
 
-void measurement_alert_subclass_register(void)
+void irq_subclass_register(enum irq_subclass subclass)
 {
-       spin_lock(&ma_subclass_lock);
-       if (!ma_subclass_refcount)
-               ctl_set_bit(0, 5);
-       ma_subclass_refcount++;
-       spin_unlock(&ma_subclass_lock);
+       spin_lock(&irq_subclass_lock);
+       if (!irq_subclass_refcount[subclass])
+               ctl_set_bit(0, subclass);
+       irq_subclass_refcount[subclass]++;
+       spin_unlock(&irq_subclass_lock);
 }
-EXPORT_SYMBOL(measurement_alert_subclass_register);
+EXPORT_SYMBOL(irq_subclass_register);
 
-void measurement_alert_subclass_unregister(void)
+void irq_subclass_unregister(enum irq_subclass subclass)
 {
-       spin_lock(&ma_subclass_lock);
-       ma_subclass_refcount--;
-       if (!ma_subclass_refcount)
-               ctl_clear_bit(0, 5);
-       spin_unlock(&ma_subclass_lock);
+       spin_lock(&irq_subclass_lock);
+       irq_subclass_refcount[subclass]--;
+       if (!irq_subclass_refcount[subclass])
+               ctl_clear_bit(0, subclass);
+       spin_unlock(&irq_subclass_lock);
 }
-EXPORT_SYMBOL(measurement_alert_subclass_unregister);
+EXPORT_SYMBOL(irq_subclass_unregister);
index adbbe7f1cb0d19ab0b4ea7711952ec03723ed7d0..0ce9fb245034d67bf8f44dd7c9234ef954679a51 100644 (file)
@@ -37,6 +37,26 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
 
 struct kretprobe_blackpoint kretprobe_blacklist[] = { };
 
+DEFINE_INSN_CACHE_OPS(dmainsn);
+
+static void *alloc_dmainsn_page(void)
+{
+       return (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
+}
+
+static void free_dmainsn_page(void *page)
+{
+       free_page((unsigned long)page);
+}
+
+struct kprobe_insn_cache kprobe_dmainsn_slots = {
+       .mutex = __MUTEX_INITIALIZER(kprobe_dmainsn_slots.mutex),
+       .alloc = alloc_dmainsn_page,
+       .free = free_dmainsn_page,
+       .pages = LIST_HEAD_INIT(kprobe_dmainsn_slots.pages),
+       .insn_size = MAX_INSN_SIZE,
+};
+
 static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn)
 {
        switch (insn[0] >> 8) {
@@ -100,9 +120,8 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
                        fixup |= FIXUP_RETURN_REGISTER;
                break;
        case 0xc0:
-               if ((insn[0] & 0x0f) == 0x00 || /* larl  */
-                   (insn[0] & 0x0f) == 0x05)   /* brasl */
-               fixup |= FIXUP_RETURN_REGISTER;
+               if ((insn[0] & 0x0f) == 0x05)   /* brasl */
+                       fixup |= FIXUP_RETURN_REGISTER;
                break;
        case 0xeb:
                switch (insn[2] & 0xff) {
@@ -134,18 +153,128 @@ static int __kprobes get_fixup_type(kprobe_opcode_t *insn)
        return fixup;
 }
 
+static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn)
+{
+       /* Check if we have a RIL-b or RIL-c format instruction which
+        * we need to modify in order to avoid instruction emulation. */
+       switch (insn[0] >> 8) {
+       case 0xc0:
+               if ((insn[0] & 0x0f) == 0x00) /* larl */
+                       return true;
+               break;
+       case 0xc4:
+               switch (insn[0] & 0x0f) {
+               case 0x02: /* llhrl  */
+               case 0x04: /* lghrl  */
+               case 0x05: /* lhrl   */
+               case 0x06: /* llghrl */
+               case 0x07: /* sthrl  */
+               case 0x08: /* lgrl   */
+               case 0x0b: /* stgrl  */
+               case 0x0c: /* lgfrl  */
+               case 0x0d: /* lrl    */
+               case 0x0e: /* llgfrl */
+               case 0x0f: /* strl   */
+                       return true;
+               }
+               break;
+       case 0xc6:
+               switch (insn[0] & 0x0f) {
+               case 0x00: /* exrl   */
+               case 0x02: /* pfdrl  */
+               case 0x04: /* cghrl  */
+               case 0x05: /* chrl   */
+               case 0x06: /* clghrl */
+               case 0x07: /* clhrl  */
+               case 0x08: /* cgrl   */
+               case 0x0a: /* clgrl  */
+               case 0x0c: /* cgfrl  */
+               case 0x0d: /* crl    */
+               case 0x0e: /* clgfrl */
+               case 0x0f: /* clrl   */
+                       return true;
+               }
+               break;
+       }
+       return false;
+}
+
+static void __kprobes copy_instruction(struct kprobe *p)
+{
+       s64 disp, new_disp;
+       u64 addr, new_addr;
+
+       memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2);
+       if (!is_insn_relative_long(p->ainsn.insn))
+               return;
+       /*
+        * For pc-relative instructions in RIL-b or RIL-c format patch the
+        * RI2 displacement field. We have already made sure that the insn
+        * slot for the patched instruction is within the same 2GB area
+        * as the original instruction (either kernel image or module area).
+        * Therefore the new displacement will always fit.
+        */
+       disp = *(s32 *)&p->ainsn.insn[1];
+       addr = (u64)(unsigned long)p->addr;
+       new_addr = (u64)(unsigned long)p->ainsn.insn;
+       new_disp = ((addr + (disp * 2)) - new_addr) / 2;
+       *(s32 *)&p->ainsn.insn[1] = new_disp;
+}
+
+static inline int is_kernel_addr(void *addr)
+{
+       return addr < (void *)_end;
+}
+
+static inline int is_module_addr(void *addr)
+{
+#ifdef CONFIG_64BIT
+       BUILD_BUG_ON(MODULES_LEN > (1UL << 31));
+       if (addr < (void *)MODULES_VADDR)
+               return 0;
+       if (addr > (void *)MODULES_END)
+               return 0;
+#endif
+       return 1;
+}
+
+static int __kprobes s390_get_insn_slot(struct kprobe *p)
+{
+       /*
+        * Get an insn slot that is within the same 2GB area like the original
+        * instruction. That way instructions with a 32bit signed displacement
+        * field can be patched and executed within the insn slot.
+        */
+       p->ainsn.insn = NULL;
+       if (is_kernel_addr(p->addr))
+               p->ainsn.insn = get_dmainsn_slot();
+       if (is_module_addr(p->addr))
+               p->ainsn.insn = get_insn_slot();
+       return p->ainsn.insn ? 0 : -ENOMEM;
+}
+
+static void __kprobes s390_free_insn_slot(struct kprobe *p)
+{
+       if (!p->ainsn.insn)
+               return;
+       if (is_kernel_addr(p->addr))
+               free_dmainsn_slot(p->ainsn.insn, 0);
+       else
+               free_insn_slot(p->ainsn.insn, 0);
+       p->ainsn.insn = NULL;
+}
+
 int __kprobes arch_prepare_kprobe(struct kprobe *p)
 {
        if ((unsigned long) p->addr & 0x01)
                return -EINVAL;
-
        /* Make sure the probe isn't going on a difficult instruction */
        if (is_prohibited_opcode(p->addr))
                return -EINVAL;
-
+       if (s390_get_insn_slot(p))
+               return -ENOMEM;
        p->opcode = *p->addr;
-       memcpy(p->ainsn.insn, p->addr, ((p->opcode >> 14) + 3) & -2);
-
+       copy_instruction(p);
        return 0;
 }
 
@@ -186,6 +315,7 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
 
 void __kprobes arch_remove_kprobe(struct kprobe *p)
 {
+       s390_free_insn_slot(p);
 }
 
 static void __kprobes enable_singlestep(struct kprobe_ctlblk *kcb,
index ac2178161ec3b80bae5324728e62ead072f97c91..719e27b2cf2264b4000d65635ad26b6e06284043 100644 (file)
@@ -50,7 +50,7 @@ static void add_elf_notes(int cpu)
 /*
  * Initialize CPU ELF notes
  */
-void setup_regs(void)
+static void setup_regs(void)
 {
        unsigned long sa = S390_lowcore.prefixreg_save_area + SAVE_AREA_BASE;
        int cpu, this_cpu;
index fb99c2057b85366c96b5f5795e1fdc51580eb595..1105502bf6e976c98bb63dbac703939dacab9677 100644 (file)
@@ -274,7 +274,7 @@ static int reserve_pmc_hardware(void)
        int flags = PMC_INIT;
 
        on_each_cpu(setup_pmc_cpu, &flags, 1);
-       measurement_alert_subclass_register();
+       irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
 
        return 0;
 }
@@ -285,7 +285,7 @@ static void release_pmc_hardware(void)
        int flags = PMC_RELEASE;
 
        on_each_cpu(setup_pmc_cpu, &flags, 1);
-       measurement_alert_subclass_unregister();
+       irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
 }
 
 /* Release the PMU if event is the last perf event */
index 500aa1029bcb2d2ed12ae352a91cec068322615b..2343c218b8f991224e0d3fb44e6838354cfb7e7e 100644 (file)
@@ -105,13 +105,10 @@ void perf_event_print_debug(void)
 
        cpu = smp_processor_id();
        memset(&cf_info, 0, sizeof(cf_info));
-       if (!qctri(&cf_info)) {
+       if (!qctri(&cf_info))
                pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n",
                        cpu, cf_info.cfvn, cf_info.csvn,
                        cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl);
-               print_hex_dump_bytes("CPUMF Query: ", DUMP_PREFIX_OFFSET,
-                                    &cf_info, sizeof(cf_info));
-       }
 
        local_irq_restore(flags);
 }
index 077a99389b07919a2e0575b6b46249589f3cf968..e1c9d1c292fa2ce4afa9a7d777b2d1db08024044 100644 (file)
@@ -139,10 +139,10 @@ static int __init runtime_instr_init(void)
        if (!runtime_instr_avail())
                return 0;
 
-       measurement_alert_subclass_register();
+       irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
        rc = register_external_interrupt(0x1407, runtime_instr_int_handler);
        if (rc)
-               measurement_alert_subclass_unregister();
+               irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
        else
                pr_info("Runtime instrumentation facility initialized\n");
        return rc;
index d386c4e9d2e5924a55b635cdcd28c967548fd7b6..1a4313a1b60f76e20ac50ff31b5c0d2e0bf95492 100644 (file)
@@ -362,7 +362,7 @@ void smp_yield_cpu(int cpu)
  * Send cpus emergency shutdown signal. This gives the cpus the
  * opportunity to complete outstanding interrupts.
  */
-void smp_emergency_stop(cpumask_t *cpumask)
+static void smp_emergency_stop(cpumask_t *cpumask)
 {
        u64 end;
        int cpu;
index 737bff38e3eeed4ed9d77cb87962d35205b47951..a7a7537ce1e7e415460199098a609b8732de1175 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/ipl.h>
 #include <asm/cio.h>
 #include <asm/pci.h>
+#include "entry.h"
 
 /*
  * References to section boundaries
index f00aefb66a4e03144a3283c04186e1a5e1177e1e..fc6679210d83249e9b34c2f44070ab1021852e91 100644 (file)
@@ -302,6 +302,8 @@ static inline int do_exception(struct pt_regs *regs, int access)
        address = trans_exc_code & __FAIL_ADDR_MASK;
        perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
        flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
        if (access == VM_WRITE || (trans_exc_code & store_indication) == 0x400)
                flags |= FAULT_FLAG_WRITE;
        down_read(&mm->mmap_sem);
@@ -673,7 +675,7 @@ static int __init pfault_irq_init(void)
        rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
        if (rc)
                goto out_pfault;
-       service_subclass_irq_register();
+       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
        hotcpu_notifier(pfault_cpu_notify, 0);
        return 0;
 
index 248445f92604efff09a5188352c3e6fba1248bb0..d261c62e40a68f8c885d6019e6a0ef27d9497c4c 100644 (file)
@@ -223,6 +223,11 @@ int pud_huge(pud_t pud)
        return 0;
 }
 
+int pmd_huge_support(void)
+{
+       return 1;
+}
+
 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
                             pmd_t *pmdp, int write)
 {
index 921fa541dc0431050dfc6b429b4836b94972d6a0..d1e0e0c7a7e22e44f7f136a0bcef51bf412f1099 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/gfp.h>
 #include <linux/cpu.h>
 #include <asm/ctl_reg.h>
+#include <asm/io.h>
 
 /*
  * This function writes to kernel memory bypassing DAT and possible
index bf7c0dc64a76111d307b7b48585cc40ecb6741aa..de8cbc30dcd1be13cb34dd0fc0e7ad5a8a68372e 100644 (file)
@@ -245,7 +245,9 @@ EXPORT_SYMBOL_GPL(gmap_disable);
  * gmap_alloc_table is assumed to be called with mmap_sem held
  */
 static int gmap_alloc_table(struct gmap *gmap,
-                              unsigned long *table, unsigned long init)
+                           unsigned long *table, unsigned long init)
+       __releases(&gmap->mm->page_table_lock)
+       __acquires(&gmap->mm->page_table_lock)
 {
        struct page *page;
        unsigned long *new;
@@ -966,7 +968,7 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table)
        tlb_remove_table(tlb, table);
 }
 
-void __tlb_remove_table(void *_table)
+static void __tlb_remove_table(void *_table)
 {
        const unsigned long mask = (FRAG_MASK << 4) | FRAG_MASK;
        void *table = (void *)((unsigned long) _table & ~mask);
index d5f10a43a58fb145b5514b897121fd9471fdabb2..709239285869caa29fde3db90ea31da213cb5cb2 100644 (file)
@@ -805,7 +805,7 @@ static struct bpf_binary_header *bpf_alloc_binary(unsigned int bpfsize,
                return NULL;
        memset(header, 0, sz);
        header->pages = sz / PAGE_SIZE;
-       hole = sz - bpfsize + sizeof(*header);
+       hole = sz - (bpfsize + sizeof(*header));
        /* Insert random number of illegal instructions before BPF code
         * and make sure the first instruction starts at an even address.
         */
index b5b2916895e08dd8b562fb7784628c4a0294f55b..231cecafc2f147d4aa90564dc1907b6f9cc4661c 100644 (file)
@@ -1001,7 +1001,7 @@ int hwsampler_deallocate(void)
        if (hws_state != HWS_STOPPED)
                goto deallocate_exit;
 
-       measurement_alert_subclass_unregister();
+       irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
        deallocate_sdbt();
 
        hws_state = HWS_DEALLOCATED;
@@ -1115,7 +1115,7 @@ int hwsampler_shutdown(void)
                mutex_lock(&hws_sem);
 
                if (hws_state == HWS_STOPPED) {
-                       measurement_alert_subclass_unregister();
+                       irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
                        deallocate_sdbt();
                }
                if (hws_wq) {
@@ -1190,7 +1190,7 @@ start_all_exit:
        hws_oom = 1;
        hws_flush_all = 0;
        /* now let them in, 1407 CPUMF external interrupts */
-       measurement_alert_subclass_register();
+       irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
 
        return 0;
 }
index 5fc237581caf3a6f3b40c41246f4d39d28f8ee55..a1be70db75fec95d9cfa087008edf86a6baf7280 100644 (file)
@@ -2,7 +2,6 @@ menu "Machine selection"
 
 config SCORE
        def_bool y
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select GENERIC_IOMAP
        select GENERIC_ATOMIC64
index 6b18fb0189ae4ff0d06fea13b717b42a8f58c664..52238983527d605914853fd5415ea39617944ffe 100644 (file)
@@ -47,6 +47,7 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
        const int field = sizeof(unsigned long) * 2;
+       unsigned long flags = 0;
        siginfo_t info;
        int fault;
 
@@ -75,6 +76,9 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long write,
        if (in_atomic() || !mm)
                goto bad_area_nosemaphore;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
        if (!vma)
@@ -95,18 +99,18 @@ good_area:
        if (write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
                        goto bad_area;
        }
 
-survive:
        /*
        * If for any reason at all we couldn't handle the fault,
        * make sure we exit gracefully rather than endlessly redo
        * the fault.
        */
-       fault = handle_mm_fault(mm, vma, address, write);
+       fault = handle_mm_fault(mm, vma, address, flags);
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
                        goto out_of_memory;
@@ -167,11 +171,6 @@ no_context:
        */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
        if (!user_mode(regs))
                goto no_context;
        pagefault_out_of_memory();
index 1018ed3a3ca58e4fc677663006ee8a4ead381c25..224f4bc9925ece7f38c85a145cf615aa78082569 100644 (file)
@@ -26,7 +26,6 @@ config SUPERH
        select ARCH_WANT_IPC_PARSE_VERSION
        select HAVE_SYSCALL_TRACEPOINTS
        select HAVE_REGS_AND_STACK_ACCESS_API
-       select HAVE_GENERIC_HARDIRQS
        select MAY_HAVE_SPARSE_IRQ
        select IRQ_FORCED_THREADING
        select RTC_LIB
index 65dd81baa7f62604b7cf892e8637dfb8dbec28a4..1fa8be4097715360363c41f21043d184f68517fa 100644 (file)
@@ -600,37 +600,13 @@ static struct platform_device sdhi0_power = {
        },
 };
 
-static void sdhi0_set_pwr(struct platform_device *pdev, int state)
-{
-       static int power_gpio = -EINVAL;
-
-       if (power_gpio < 0) {
-               int ret = gpio_request(GPIO_PTB6, NULL);
-               if (!ret) {
-                       power_gpio = GPIO_PTB6;
-                       gpio_direction_output(power_gpio, 0);
-               }
-       }
-
-       /*
-        * Toggle the GPIO regardless, whether we managed to grab it above or
-        * the fixed regulator driver did.
-        */
-       gpio_set_value(GPIO_PTB6, state);
-}
-
-static int sdhi0_get_cd(struct platform_device *pdev)
-{
-       return !gpio_get_value(GPIO_PTY7);
-}
-
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
        .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
-       .set_pwr        = sdhi0_set_pwr,
        .tmio_caps      = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
                          MMC_CAP_NEEDS_POLL,
-       .get_cd         = sdhi0_get_cd,
+       .tmio_flags     = TMIO_MMC_USE_GPIO_CD,
+       .cd_gpio        = GPIO_PTY7,
 };
 
 static struct resource sdhi0_resources[] = {
@@ -656,39 +632,15 @@ static struct platform_device sdhi0_device = {
        },
 };
 
-static void cn12_set_pwr(struct platform_device *pdev, int state)
-{
-       static int power_gpio = -EINVAL;
-
-       if (power_gpio < 0) {
-               int ret = gpio_request(GPIO_PTB7, NULL);
-               if (!ret) {
-                       power_gpio = GPIO_PTB7;
-                       gpio_direction_output(power_gpio, 0);
-               }
-       }
-
-       /*
-        * Toggle the GPIO regardless, whether we managed to grab it above or
-        * the fixed regulator driver did.
-        */
-       gpio_set_value(GPIO_PTB7, state);
-}
-
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
 /* SDHI1 */
-static int sdhi1_get_cd(struct platform_device *pdev)
-{
-       return !gpio_get_value(GPIO_PTW7);
-}
-
 static struct sh_mobile_sdhi_info sdhi1_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI1_TX,
        .dma_slave_rx   = SHDMA_SLAVE_SDHI1_RX,
        .tmio_caps      = MMC_CAP_SDIO_IRQ | MMC_CAP_POWER_OFF_CARD |
                          MMC_CAP_NEEDS_POLL,
-       .set_pwr        = cn12_set_pwr,
-       .get_cd         = sdhi1_get_cd,
+       .tmio_flags     = TMIO_MMC_USE_GPIO_CD,
+       .cd_gpio        = GPIO_PTW7,
 };
 
 static struct resource sdhi1_resources[] = {
@@ -718,27 +670,19 @@ static struct platform_device sdhi1_device = {
 #else
 
 /* MMC SPI */
-static int mmc_spi_get_ro(struct device *dev)
-{
-       return gpio_get_value(GPIO_PTY6);
-}
-
-static int mmc_spi_get_cd(struct device *dev)
-{
-       return !gpio_get_value(GPIO_PTY7);
-}
-
 static void mmc_spi_setpower(struct device *dev, unsigned int maskval)
 {
        gpio_set_value(GPIO_PTB6, maskval ? 1 : 0);
 }
 
 static struct mmc_spi_platform_data mmc_spi_info = {
-       .get_ro = mmc_spi_get_ro,
-       .get_cd = mmc_spi_get_cd,
        .caps = MMC_CAP_NEEDS_POLL,
+       .caps2 = MMC_CAP2_RO_ACTIVE_HIGH,
        .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, /* 3.3V only */
        .setpower = mmc_spi_setpower,
+       .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO,
+       .cd_gpio = GPIO_PTY7,
+       .ro_gpio = GPIO_PTY6,
 };
 
 static struct spi_board_info spi_bus[] = {
@@ -998,11 +942,6 @@ static struct platform_device vou_device = {
 
 #if defined(CONFIG_MMC_SH_MMCIF) || defined(CONFIG_MMC_SH_MMCIF_MODULE)
 /* SH_MMCIF */
-static void mmcif_down_pwr(struct platform_device *pdev)
-{
-       cn12_set_pwr(pdev, 0);
-}
-
 static struct resource sh_mmcif_resources[] = {
        [0] = {
                .name   = "SH_MMCIF",
@@ -1023,8 +962,6 @@ static struct resource sh_mmcif_resources[] = {
 };
 
 static struct sh_mmcif_plat_data sh_mmcif_plat = {
-       .set_pwr        = cn12_set_pwr,
-       .down_pwr       = mmcif_down_pwr,
        .sup_pclk       = 0, /* SH7724: Max Pclk/2 */
        .caps           = MMC_CAP_4_BIT_DATA |
                          MMC_CAP_8_BIT_DATA |
@@ -1341,10 +1278,6 @@ static int __init arch_setup(void)
        gpio_direction_input(GPIO_PTR6);
 
        /* SD-card slot CN11 */
-       /* Card-detect, used on CN11, either with SDHI0 or with SPI */
-       gpio_request(GPIO_PTY7, NULL);
-       gpio_direction_input(GPIO_PTY7);
-
 #if defined(CONFIG_MMC_SDHI) || defined(CONFIG_MMC_SDHI_MODULE)
        /* enable SDHI0 on CN11 (needs DS2.4 set to ON) */
        gpio_request(GPIO_FN_SDHI0WP,  NULL);
@@ -1363,8 +1296,6 @@ static int __init arch_setup(void)
        gpio_direction_output(GPIO_PTM4, 1); /* active low CS */
        gpio_request(GPIO_PTB6, NULL); /* 3.3V power control */
        gpio_direction_output(GPIO_PTB6, 0); /* disable power by default */
-       gpio_request(GPIO_PTY6, NULL); /* write protect */
-       gpio_direction_input(GPIO_PTY6);
 
        spi_register_board_info(spi_bus, ARRAY_SIZE(spi_bus));
 #endif
@@ -1394,10 +1325,6 @@ static int __init arch_setup(void)
        gpio_request(GPIO_FN_SDHI1D1,  NULL);
        gpio_request(GPIO_FN_SDHI1D0,  NULL);
 
-       /* Card-detect, used on CN12 with SDHI1 */
-       gpio_request(GPIO_PTW7, NULL);
-       gpio_direction_input(GPIO_PTW7);
-
        cn12_enabled = true;
 #endif
 
index 1f49c28affa90495047c6b82577b2d5221bc089b..541dc610150888e706977c7944c42ab1d61d7437 100644 (file)
@@ -400,9 +400,7 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
        struct mm_struct *mm;
        struct vm_area_struct * vma;
        int fault;
-       int write = error_code & FAULT_CODE_WRITE;
-       unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                             (write ? FAULT_FLAG_WRITE : 0));
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        tsk = current;
        mm = tsk->mm;
@@ -476,6 +474,11 @@ good_area:
 
        set_thread_fault_code(error_code);
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+       if (error_code & FAULT_CODE_WRITE)
+               flags |= FAULT_FLAG_WRITE;
+
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
index d7762349ea4869be1b40898a5ae7e6ff8e79c6aa..0d676a41081e873582a68cf3c1d179ab51dd529d 100644 (file)
@@ -83,6 +83,11 @@ int pud_huge(pud_t pud)
        return 0;
 }
 
+int pmd_huge_support(void)
+{
+       return 0;
+}
+
 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
                             pmd_t *pmd, int write)
 {
index 1570ad2802b3e4620a17f32074324a3248996855..2137ad6674388a8e920fba2d7b9fba0cf88512e6 100644 (file)
@@ -26,7 +26,6 @@ config SPARC
        select HAVE_DMA_ATTRS
        select HAVE_DMA_API_DEBUG
        select HAVE_ARCH_JUMP_LABEL
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_SHOW
        select ARCH_WANT_IPC_PARSE_VERSION
        select USE_GENERIC_SMP_HELPERS if SMP
index 3d0ddbc005fe6b2766eca2ed3205a198641173e4..71368850dfc03b05257bf38db7c17f3b4bd0f6ec 100644 (file)
@@ -169,10 +169,10 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig,
                new_ka.ka_restorer = restorer;
                ret = get_user(u_handler, &act->sa_handler);
                new_ka.sa.sa_handler =  compat_ptr(u_handler);
-               ret |= __copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
+               ret |= copy_from_user(&set32, &act->sa_mask, sizeof(compat_sigset_t));
                sigset_from_compat(&new_ka.sa.sa_mask, &set32);
-               ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
-               ret |= __get_user(u_restorer, &act->sa_restorer);
+               ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               ret |= get_user(u_restorer, &act->sa_restorer);
                new_ka.sa.sa_restorer = compat_ptr(u_restorer);
                 if (ret)
                        return -EFAULT;
@@ -183,9 +183,9 @@ COMPAT_SYSCALL_DEFINE5(rt_sigaction, int, sig,
        if (!ret && oact) {
                sigset_to_compat(&set32, &old_ka.sa.sa_mask);
                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), &oact->sa_handler);
-               ret |= __copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
-               ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-               ret |= __put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
+               ret |= copy_to_user(&oact->sa_mask, &set32, sizeof(compat_sigset_t));
+               ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer), &oact->sa_restorer);
                if (ret)
                        ret = -EFAULT;
         }
index e98bfda205a2beb97bcaa49a27d5a9412bf03dc3..59dbd46457250b050ce84a48370a4f96afa3746d 100644 (file)
@@ -177,8 +177,7 @@ asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
        unsigned long g2;
        int from_user = !(regs->psr & PSR_PS);
        int fault, code;
-       unsigned int flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                             (write ? FAULT_FLAG_WRITE : 0));
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        if (text_fault)
                address = regs->pc;
@@ -235,6 +234,11 @@ good_area:
                        goto bad_area;
        }
 
+       if (from_user)
+               flags |= FAULT_FLAG_USER;
+       if (write)
+               flags |= FAULT_FLAG_WRITE;
+
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -383,6 +387,7 @@ static void force_user_fault(unsigned long address, int write)
        struct vm_area_struct *vma;
        struct task_struct *tsk = current;
        struct mm_struct *mm = tsk->mm;
+       unsigned int flags = FAULT_FLAG_USER;
        int code;
 
        code = SEGV_MAPERR;
@@ -402,11 +407,12 @@ good_area:
        if (write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
-       switch (handle_mm_fault(mm, vma, address, write ? FAULT_FLAG_WRITE : 0)) {
+       switch (handle_mm_fault(mm, vma, address, flags)) {
        case VM_FAULT_SIGBUS:
        case VM_FAULT_OOM:
                goto do_sigbus;
index 5062ff389e83bb3b2865deaabb0a4d5338256e09..2ebec263d6859f317041d75d0172abde1fd4e4d5 100644 (file)
@@ -315,7 +315,8 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
                        bad_kernel_pc(regs, address);
                        return;
                }
-       }
+       } else
+               flags |= FAULT_FLAG_USER;
 
        /*
         * If we're in an interrupt or have no user
@@ -418,13 +419,14 @@ good_area:
                    vma->vm_file != NULL)
                        set_thread_fault_code(fault_code |
                                              FAULT_CODE_BLKCOMMIT);
+
+               flags |= FAULT_FLAG_WRITE;
        } else {
                /* Allow reads even for write-only mappings */
                if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
                        goto bad_area;
        }
 
-       flags |= ((fault_code & FAULT_CODE_WRITE) ? FAULT_FLAG_WRITE : 0);
        fault = handle_mm_fault(mm, vma, address, flags);
 
        if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
index d2b59441ebddfb84080da0fcadff6921e71342f6..96399646570a780e1b38a6324994c5f71470bb0b 100644 (file)
@@ -234,6 +234,11 @@ int pud_huge(pud_t pud)
        return 0;
 }
 
+int pmd_huge_support(void)
+{
+       return 0;
+}
+
 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
                             pmd_t *pmd, int write)
 {
index 932fa14de5fe7ddac20b4c9c4b418731c8f84847..d45a2c48f1850d65fe01a0c23a91eea1115fc1dd 100644 (file)
@@ -11,7 +11,6 @@ config TILE
        select USE_GENERIC_SMP_HELPERS
        select CC_OPTIMIZE_FOR_SIZE
        select HAVE_DEBUG_KMEMLEAK
-       select HAVE_GENERIC_HARDIRQS
        select GENERIC_IRQ_PROBE
        select GENERIC_PENDING_IRQ if SMP
        select GENERIC_IRQ_SHOW
@@ -362,7 +361,7 @@ config CMDLINE_OVERRIDE
 
 config VMALLOC_RESERVE
        hex
-       default 0x1000000
+       default 0x2000000
 
 config HARDWALL
        bool "Hardwall support to allow access to user dynamic network"
index 4f8f3d619c4a652b428029f0bc2c0362775d79dd..e19325c4c43168ace7298a123b0f0d210b25172b 100644 (file)
@@ -21,7 +21,7 @@ struct alloc_buffer_stacks_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t *context,
                                   unsigned int count, unsigned int first,
                                   unsigned int flags)
 {
@@ -45,7 +45,7 @@ struct init_buffer_stack_aux_param {
        unsigned int buffer_size_enum;
 };
 
-int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t * context,
+int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t *context,
                                     void *mem_va, size_t mem_size,
                                     unsigned int mem_flags, unsigned int stack,
                                     unsigned int buffer_size_enum)
@@ -80,7 +80,7 @@ struct alloc_notif_rings_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t *context,
                                 unsigned int count, unsigned int first,
                                 unsigned int flags)
 {
@@ -102,7 +102,7 @@ struct init_notif_ring_aux_param {
        unsigned int ring;
 };
 
-int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t *context, void *mem_va,
                                   size_t mem_size, unsigned int mem_flags,
                                   unsigned int ring)
 {
@@ -133,7 +133,7 @@ struct request_notif_ring_interrupt_param {
        unsigned int ring;
 };
 
-int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t * context,
+int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t *context,
                                            int inter_x, int inter_y,
                                            int inter_ipi, int inter_event,
                                            unsigned int ring)
@@ -158,7 +158,7 @@ struct enable_notif_ring_interrupt_param {
        unsigned int ring;
 };
 
-int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t * context,
+int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t *context,
                                           unsigned int ring)
 {
        struct enable_notif_ring_interrupt_param temp;
@@ -179,7 +179,7 @@ struct alloc_notif_groups_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t *context,
                                  unsigned int count, unsigned int first,
                                  unsigned int flags)
 {
@@ -201,7 +201,7 @@ struct init_notif_group_param {
        gxio_mpipe_notif_group_bits_t bits;
 };
 
-int gxio_mpipe_init_notif_group(gxio_mpipe_context_t * context,
+int gxio_mpipe_init_notif_group(gxio_mpipe_context_t *context,
                                unsigned int group,
                                gxio_mpipe_notif_group_bits_t bits)
 {
@@ -223,7 +223,7 @@ struct alloc_buckets_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t * context, unsigned int count,
+int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t *context, unsigned int count,
                             unsigned int first, unsigned int flags)
 {
        struct alloc_buckets_param temp;
@@ -244,7 +244,7 @@ struct init_bucket_param {
        MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info;
 };
 
-int gxio_mpipe_init_bucket(gxio_mpipe_context_t * context, unsigned int bucket,
+int gxio_mpipe_init_bucket(gxio_mpipe_context_t *context, unsigned int bucket,
                           MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info)
 {
        struct init_bucket_param temp;
@@ -265,7 +265,7 @@ struct alloc_edma_rings_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context,
                                unsigned int count, unsigned int first,
                                unsigned int flags)
 {
@@ -288,7 +288,7 @@ struct init_edma_ring_aux_param {
        unsigned int channel;
 };
 
-int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t *context, void *mem_va,
                                  size_t mem_size, unsigned int mem_flags,
                                  unsigned int ring, unsigned int channel)
 {
@@ -315,7 +315,7 @@ int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
 EXPORT_SYMBOL(gxio_mpipe_init_edma_ring_aux);
 
 
-int gxio_mpipe_commit_rules(gxio_mpipe_context_t * context, const void *blob,
+int gxio_mpipe_commit_rules(gxio_mpipe_context_t *context, const void *blob,
                            size_t blob_size)
 {
        const void *params = blob;
@@ -332,7 +332,7 @@ struct register_client_memory_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_register_client_memory(gxio_mpipe_context_t * context,
+int gxio_mpipe_register_client_memory(gxio_mpipe_context_t *context,
                                      unsigned int iotlb, HV_PTE pte,
                                      unsigned int flags)
 {
@@ -355,7 +355,7 @@ struct link_open_aux_param {
        unsigned int flags;
 };
 
-int gxio_mpipe_link_open_aux(gxio_mpipe_context_t * context,
+int gxio_mpipe_link_open_aux(gxio_mpipe_context_t *context,
                             _gxio_mpipe_link_name_t name, unsigned int flags)
 {
        struct link_open_aux_param temp;
@@ -374,7 +374,7 @@ struct link_close_aux_param {
        int mac;
 };
 
-int gxio_mpipe_link_close_aux(gxio_mpipe_context_t * context, int mac)
+int gxio_mpipe_link_close_aux(gxio_mpipe_context_t *context, int mac)
 {
        struct link_close_aux_param temp;
        struct link_close_aux_param *params = &temp;
@@ -393,7 +393,7 @@ struct link_set_attr_aux_param {
        int64_t val;
 };
 
-int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t * context, int mac,
+int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t *context, int mac,
                                 uint32_t attr, int64_t val)
 {
        struct link_set_attr_aux_param temp;
@@ -415,8 +415,8 @@ struct get_timestamp_aux_param {
        uint64_t cycles;
 };
 
-int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t * context, uint64_t * sec,
-                                uint64_t * nsec, uint64_t * cycles)
+int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t *context, uint64_t *sec,
+                                uint64_t *nsec, uint64_t *cycles)
 {
        int __result;
        struct get_timestamp_aux_param temp;
@@ -440,7 +440,7 @@ struct set_timestamp_aux_param {
        uint64_t cycles;
 };
 
-int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t * context, uint64_t sec,
+int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t *context, uint64_t sec,
                                 uint64_t nsec, uint64_t cycles)
 {
        struct set_timestamp_aux_param temp;
@@ -460,8 +460,7 @@ struct adjust_timestamp_aux_param {
        int64_t nsec;
 };
 
-int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
-                                   int64_t nsec)
+int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t *context, int64_t nsec)
 {
        struct adjust_timestamp_aux_param temp;
        struct adjust_timestamp_aux_param *params = &temp;
@@ -475,25 +474,6 @@ int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
 
 EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux);
 
-struct adjust_timestamp_freq_param {
-       int32_t ppb;
-};
-
-int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context,
-                                    int32_t ppb)
-{
-       struct adjust_timestamp_freq_param temp;
-       struct adjust_timestamp_freq_param *params = &temp;
-
-       params->ppb = ppb;
-
-       return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
-                            sizeof(*params),
-                            GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ);
-}
-
-EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_freq);
-
 struct config_edma_ring_blks_param {
        unsigned int ering;
        unsigned int max_blks;
@@ -501,7 +481,7 @@ struct config_edma_ring_blks_param {
        unsigned int db;
 };
 
-int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t * context,
+int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t *context,
                                     unsigned int ering, unsigned int max_blks,
                                     unsigned int min_snf_blks, unsigned int db)
 {
@@ -520,11 +500,29 @@ int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t * context,
 
 EXPORT_SYMBOL(gxio_mpipe_config_edma_ring_blks);
 
+struct adjust_timestamp_freq_param {
+       int32_t ppb;
+};
+
+int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t *context, int32_t ppb)
+{
+       struct adjust_timestamp_freq_param temp;
+       struct adjust_timestamp_freq_param *params = &temp;
+
+       params->ppb = ppb;
+
+       return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params,
+                            sizeof(*params),
+                            GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ);
+}
+
+EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_freq);
+
 struct arm_pollfd_param {
        union iorpc_pollfd pollfd;
 };
 
-int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie)
+int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie)
 {
        struct arm_pollfd_param temp;
        struct arm_pollfd_param *params = &temp;
@@ -541,7 +539,7 @@ struct close_pollfd_param {
        union iorpc_pollfd pollfd;
 };
 
-int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie)
+int gxio_mpipe_close_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie)
 {
        struct close_pollfd_param temp;
        struct close_pollfd_param *params = &temp;
@@ -558,7 +556,7 @@ struct get_mmio_base_param {
        HV_PTE base;
 };
 
-int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t * context, HV_PTE *base)
+int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t *context, HV_PTE *base)
 {
        int __result;
        struct get_mmio_base_param temp;
@@ -579,7 +577,7 @@ struct check_mmio_offset_param {
        unsigned long size;
 };
 
-int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t * context,
+int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t *context,
                                 unsigned long offset, unsigned long size)
 {
        struct check_mmio_offset_param temp;
index 64883aabeb9c19d2ce3d5e72f4c4040813c33e83..77019c6e9b4ab1178cafff23e6b33a9780934545 100644 (file)
 /* This file is machine-generated; DO NOT EDIT! */
 #include "gxio/iorpc_mpipe_info.h"
 
-
 struct instance_aux_param {
        _gxio_mpipe_link_name_t name;
 };
 
-int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t *context,
                                 _gxio_mpipe_link_name_t name)
 {
        struct instance_aux_param temp;
@@ -39,10 +38,10 @@ struct enumerate_aux_param {
        _gxio_mpipe_link_mac_t mac;
 };
 
-int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t *context,
                                  unsigned int idx,
-                                 _gxio_mpipe_link_name_t * name,
-                                 _gxio_mpipe_link_mac_t * mac)
+                                 _gxio_mpipe_link_name_t *name,
+                                 _gxio_mpipe_link_mac_t *mac)
 {
        int __result;
        struct enumerate_aux_param temp;
@@ -50,7 +49,7 @@ int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t * context,
 
        __result =
            hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params),
-                        (((uint64_t) idx << 32) |
+                        (((uint64_t)idx << 32) |
                          GXIO_MPIPE_INFO_OP_ENUMERATE_AUX));
        *name = params->name;
        *mac = params->mac;
@@ -64,7 +63,7 @@ struct get_mmio_base_param {
        HV_PTE base;
 };
 
-int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t *context,
                                  HV_PTE *base)
 {
        int __result;
@@ -86,7 +85,7 @@ struct check_mmio_offset_param {
        unsigned long size;
 };
 
-int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t *context,
                                      unsigned long offset, unsigned long size)
 {
        struct check_mmio_offset_param temp;
index da6e18e049c35a5093d90522993cfdcf75dd2b76..1d3cedb9aeb42714d018f9b8e4aef1fcc6b908e3 100644 (file)
@@ -21,7 +21,7 @@ struct alloc_asids_param {
        unsigned int flags;
 };
 
-int gxio_trio_alloc_asids(gxio_trio_context_t * context, unsigned int count,
+int gxio_trio_alloc_asids(gxio_trio_context_t *context, unsigned int count,
                          unsigned int first, unsigned int flags)
 {
        struct alloc_asids_param temp;
@@ -44,7 +44,7 @@ struct alloc_memory_maps_param {
        unsigned int flags;
 };
 
-int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context,
+int gxio_trio_alloc_memory_maps(gxio_trio_context_t *context,
                                unsigned int count, unsigned int first,
                                unsigned int flags)
 {
@@ -67,7 +67,7 @@ struct alloc_scatter_queues_param {
        unsigned int flags;
 };
 
-int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context,
+int gxio_trio_alloc_scatter_queues(gxio_trio_context_t *context,
                                   unsigned int count, unsigned int first,
                                   unsigned int flags)
 {
@@ -91,7 +91,7 @@ struct alloc_pio_regions_param {
        unsigned int flags;
 };
 
-int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context,
+int gxio_trio_alloc_pio_regions(gxio_trio_context_t *context,
                                unsigned int count, unsigned int first,
                                unsigned int flags)
 {
@@ -115,7 +115,7 @@ struct init_pio_region_aux_param {
        unsigned int flags;
 };
 
-int gxio_trio_init_pio_region_aux(gxio_trio_context_t * context,
+int gxio_trio_init_pio_region_aux(gxio_trio_context_t *context,
                                  unsigned int pio_region, unsigned int mac,
                                  uint32_t bus_address_hi, unsigned int flags)
 {
@@ -145,7 +145,7 @@ struct init_memory_map_mmu_aux_param {
        unsigned int order_mode;
 };
 
-int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t * context,
+int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t *context,
                                      unsigned int map, unsigned long va,
                                      uint64_t size, unsigned int asid,
                                      unsigned int mac, uint64_t bus_address,
@@ -175,7 +175,7 @@ struct get_port_property_param {
        struct pcie_trio_ports_property trio_ports;
 };
 
-int gxio_trio_get_port_property(gxio_trio_context_t * context,
+int gxio_trio_get_port_property(gxio_trio_context_t *context,
                                struct pcie_trio_ports_property *trio_ports)
 {
        int __result;
@@ -198,7 +198,7 @@ struct config_legacy_intr_param {
        unsigned int intx;
 };
 
-int gxio_trio_config_legacy_intr(gxio_trio_context_t * context, int inter_x,
+int gxio_trio_config_legacy_intr(gxio_trio_context_t *context, int inter_x,
                                 int inter_y, int inter_ipi, int inter_event,
                                 unsigned int mac, unsigned int intx)
 {
@@ -227,7 +227,7 @@ struct config_msi_intr_param {
        unsigned int asid;
 };
 
-int gxio_trio_config_msi_intr(gxio_trio_context_t * context, int inter_x,
+int gxio_trio_config_msi_intr(gxio_trio_context_t *context, int inter_x,
                              int inter_y, int inter_ipi, int inter_event,
                              unsigned int mac, unsigned int mem_map,
                              uint64_t mem_map_base, uint64_t mem_map_limit,
@@ -259,7 +259,7 @@ struct set_mps_mrs_param {
        unsigned int mac;
 };
 
-int gxio_trio_set_mps_mrs(gxio_trio_context_t * context, uint16_t mps,
+int gxio_trio_set_mps_mrs(gxio_trio_context_t *context, uint16_t mps,
                          uint16_t mrs, unsigned int mac)
 {
        struct set_mps_mrs_param temp;
@@ -279,7 +279,7 @@ struct force_rc_link_up_param {
        unsigned int mac;
 };
 
-int gxio_trio_force_rc_link_up(gxio_trio_context_t * context, unsigned int mac)
+int gxio_trio_force_rc_link_up(gxio_trio_context_t *context, unsigned int mac)
 {
        struct force_rc_link_up_param temp;
        struct force_rc_link_up_param *params = &temp;
@@ -296,7 +296,7 @@ struct force_ep_link_up_param {
        unsigned int mac;
 };
 
-int gxio_trio_force_ep_link_up(gxio_trio_context_t * context, unsigned int mac)
+int gxio_trio_force_ep_link_up(gxio_trio_context_t *context, unsigned int mac)
 {
        struct force_ep_link_up_param temp;
        struct force_ep_link_up_param *params = &temp;
@@ -313,7 +313,7 @@ struct get_mmio_base_param {
        HV_PTE base;
 };
 
-int gxio_trio_get_mmio_base(gxio_trio_context_t * context, HV_PTE *base)
+int gxio_trio_get_mmio_base(gxio_trio_context_t *context, HV_PTE *base)
 {
        int __result;
        struct get_mmio_base_param temp;
@@ -334,7 +334,7 @@ struct check_mmio_offset_param {
        unsigned long size;
 };
 
-int gxio_trio_check_mmio_offset(gxio_trio_context_t * context,
+int gxio_trio_check_mmio_offset(gxio_trio_context_t *context,
                                unsigned long offset, unsigned long size)
 {
        struct check_mmio_offset_param temp;
index cf3c3cc122048ddb1d93390e9c864849abfc706a..9c820073bfc01bcdc92c946e904c1a600eb801a8 100644 (file)
@@ -19,7 +19,7 @@ struct cfg_interrupt_param {
        union iorpc_interrupt interrupt;
 };
 
-int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t * context, int inter_x,
+int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t *context, int inter_x,
                                int inter_y, int inter_ipi, int inter_event)
 {
        struct cfg_interrupt_param temp;
@@ -41,7 +41,7 @@ struct register_client_memory_param {
        unsigned int flags;
 };
 
-int gxio_usb_host_register_client_memory(gxio_usb_host_context_t * context,
+int gxio_usb_host_register_client_memory(gxio_usb_host_context_t *context,
                                         HV_PTE pte, unsigned int flags)
 {
        struct register_client_memory_param temp;
@@ -61,7 +61,7 @@ struct get_mmio_base_param {
        HV_PTE base;
 };
 
-int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t * context, HV_PTE *base)
+int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t *context, HV_PTE *base)
 {
        int __result;
        struct get_mmio_base_param temp;
@@ -82,7 +82,7 @@ struct check_mmio_offset_param {
        unsigned long size;
 };
 
-int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t * context,
+int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t *context,
                                    unsigned long offset, unsigned long size)
 {
        struct check_mmio_offset_param temp;
index 66b002f54ecc1cfa157c9aa2989a074876a96be1..785afad7922eed1d1837a36d488ca7a30d399022 100644 (file)
@@ -26,7 +26,7 @@
 #include <gxio/kiorpc.h>
 #include <gxio/usb_host.h>
 
-int gxio_usb_host_init(gxio_usb_host_context_t * context, int usb_index,
+int gxio_usb_host_init(gxio_usb_host_context_t *context, int usb_index,
                       int is_ehci)
 {
        char file[32];
@@ -63,7 +63,7 @@ int gxio_usb_host_init(gxio_usb_host_context_t * context, int usb_index,
 
 EXPORT_SYMBOL_GPL(gxio_usb_host_init);
 
-int gxio_usb_host_destroy(gxio_usb_host_context_t * context)
+int gxio_usb_host_destroy(gxio_usb_host_context_t *context)
 {
        iounmap((void __force __iomem *)(context->mmio_base));
        hv_dev_close(context->fd);
@@ -76,14 +76,14 @@ int gxio_usb_host_destroy(gxio_usb_host_context_t * context)
 
 EXPORT_SYMBOL_GPL(gxio_usb_host_destroy);
 
-void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t * context)
+void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t *context)
 {
        return context->mmio_base;
 }
 
 EXPORT_SYMBOL_GPL(gxio_usb_host_get_reg_start);
 
-size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t * context)
+size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t *context)
 {
        return HV_USB_HOST_MMIO_SIZE;
 }
index 8a33912fd6cc941053bcbab6d1103cb6a8eec203..904538e754d8ad62888a15e3963f00a2963416eb 100644 (file)
@@ -176,7 +176,18 @@ typedef union
      */
     uint_reg_t stack_idx    : 5;
     /* Reserved. */
-    uint_reg_t __reserved_2 : 5;
+    uint_reg_t __reserved_2 : 3;
+    /*
+     * Instance ID.  For devices that support automatic buffer return between
+     * mPIPE instances, this field indicates the buffer owner.  If the INST
+     * field does not match the mPIPE's instance number when a packet is
+     * egressed, buffers with HWB set will be returned to the other mPIPE
+     * instance.  Note that not all devices support multi-mPIPE buffer
+     * return.  The MPIPE_EDMA_INFO.REMOTE_BUFF_RTN_SUPPORT bit indicates
+     * whether the INST field in the buffer descriptor is populated by iDMA
+     * hardware. This field is ignored on writes.
+     */
+    uint_reg_t inst         : 2;
     /*
      * Reads as one to indicate that this is a hardware managed buffer.
      * Ignored on writes since all buffers on a given stack are the same size.
@@ -205,7 +216,8 @@ typedef union
     uint_reg_t c            : 2;
     uint_reg_t size         : 3;
     uint_reg_t hwb          : 1;
-    uint_reg_t __reserved_2 : 5;
+    uint_reg_t inst         : 2;
+    uint_reg_t __reserved_2 : 3;
     uint_reg_t stack_idx    : 5;
     uint_reg_t __reserved_1 : 6;
     int_reg_t va           : 35;
@@ -231,9 +243,9 @@ typedef union
     /* Reserved. */
     uint_reg_t __reserved_0 : 3;
     /* eDMA ring being accessed */
-    uint_reg_t ring         : 5;
+    uint_reg_t ring         : 6;
     /* Reserved. */
-    uint_reg_t __reserved_1 : 18;
+    uint_reg_t __reserved_1 : 17;
     /*
      * This field of the address selects the region (address space) to be
      * accessed.  For the egress DMA post region, this field must be 5.
@@ -250,8 +262,8 @@ typedef union
     uint_reg_t svc_dom      : 5;
     uint_reg_t __reserved_2 : 6;
     uint_reg_t region       : 3;
-    uint_reg_t __reserved_1 : 18;
-    uint_reg_t ring         : 5;
+    uint_reg_t __reserved_1 : 17;
+    uint_reg_t ring         : 6;
     uint_reg_t __reserved_0 : 3;
 #endif
   };
index 410a0400e0558d50586118cbbbe273cfac2a4b58..84022ac5fe8287bf7ef7629643b388a33cdfb9c3 100644 (file)
 #ifndef __ARCH_MPIPE_CONSTANTS_H__
 #define __ARCH_MPIPE_CONSTANTS_H__
 
-#define MPIPE_NUM_CLASSIFIERS 10
+#define MPIPE_NUM_CLASSIFIERS 16
 #define MPIPE_CLS_MHZ 1200
 
-#define MPIPE_NUM_EDMA_RINGS 32
+#define MPIPE_NUM_EDMA_RINGS 64
 
 #define MPIPE_NUM_SGMII_MACS 16
-#define MPIPE_NUM_XAUI_MACS 4
+#define MPIPE_NUM_XAUI_MACS 16
 #define MPIPE_NUM_LOOPBACK_CHANNELS 4
 #define MPIPE_NUM_NON_LB_CHANNELS 28
 
index f2e9e122818d09d6e5a5df9fd100576487591c59..13b3c4300e500f97f80ab1d801c6a2d5b98c5eea 100644 (file)
@@ -44,8 +44,14 @@ typedef union
      * descriptors toggles each time the ring tail pointer wraps.
      */
     uint_reg_t gen        : 1;
+    /**
+     * For devices with EDMA reorder support, this field allows the
+     * descriptor to select the egress FIFO.  The associated DMA ring must
+     * have ALLOW_EFIFO_SEL enabled.
+     */
+    uint_reg_t efifo_sel  : 6;
     /** Reserved.  Must be zero. */
-    uint_reg_t r0         : 7;
+    uint_reg_t r0         : 1;
     /** Checksum generation enabled for this transfer. */
     uint_reg_t csum       : 1;
     /**
@@ -110,7 +116,8 @@ typedef union
     uint_reg_t notif      : 1;
     uint_reg_t ns         : 1;
     uint_reg_t csum       : 1;
-    uint_reg_t r0         : 7;
+    uint_reg_t r0         : 1;
+    uint_reg_t efifo_sel  : 6;
     uint_reg_t gen        : 1;
 #endif
 
@@ -126,14 +133,16 @@ typedef union
     /** Reserved. */
     uint_reg_t __reserved_1 : 3;
     /**
-     * Instance ID.  For devices that support more than one mPIPE instance,
-     * this field indicates the buffer owner.  If the INST field does not
-     * match the mPIPE's instance number when a packet is egressed, buffers
-     * with HWB set will be returned to the other mPIPE instance.
+     * Instance ID.  For devices that support automatic buffer return between
+     * mPIPE instances, this field indicates the buffer owner.  If the INST
+     * field does not match the mPIPE's instance number when a packet is
+     * egressed, buffers with HWB set will be returned to the other mPIPE
+     * instance.  Note that not all devices support multi-mPIPE buffer
+     * return.  The MPIPE_EDMA_INFO.REMOTE_BUFF_RTN_SUPPORT bit indicates
+     * whether the INST field in the buffer descriptor is populated by iDMA
+     * hardware.
      */
-    uint_reg_t inst         : 1;
-    /** Reserved. */
-    uint_reg_t __reserved_2 : 1;
+    uint_reg_t inst         : 2;
     /**
      * Always set to one by hardware in iDMA packet descriptors.  For eDMA,
      * indicates whether the buffer will be released to the buffer stack
@@ -166,8 +175,7 @@ typedef union
     uint_reg_t c            : 2;
     uint_reg_t size         : 3;
     uint_reg_t hwb          : 1;
-    uint_reg_t __reserved_2 : 1;
-    uint_reg_t inst         : 1;
+    uint_reg_t inst         : 2;
     uint_reg_t __reserved_1 : 3;
     uint_reg_t stack_idx    : 5;
     uint_reg_t __reserved_0 : 6;
@@ -408,7 +416,10 @@ typedef union
     /**
      * Sequence number applied when packet is distributed.   Classifier
      * selects which sequence number is to be applied by writing the 13-bit
-     * SQN-selector into this field.
+     * SQN-selector into this field.  For devices that support EXT_SQN (as
+     * indicated in IDMA_INFO.EXT_SQN_SUPPORT), the GP_SQN can be extended to
+     * 32-bits via the IDMA_CTL.EXT_SQN register.  In this case the
+     * PACKET_SQN will be reduced to 32 bits.
      */
     uint_reg_t gp_sqn     : 16;
     /**
@@ -451,14 +462,16 @@ typedef union
     /** Reserved. */
     uint_reg_t __reserved_5 : 3;
     /**
-     * Instance ID.  For devices that support more than one mPIPE instance,
-     * this field indicates the buffer owner.  If the INST field does not
-     * match the mPIPE's instance number when a packet is egressed, buffers
-     * with HWB set will be returned to the other mPIPE instance.
+     * Instance ID.  For devices that support automatic buffer return between
+     * mPIPE instances, this field indicates the buffer owner.  If the INST
+     * field does not match the mPIPE's instance number when a packet is
+     * egressed, buffers with HWB set will be returned to the other mPIPE
+     * instance.  Note that not all devices support multi-mPIPE buffer
+     * return.  The MPIPE_EDMA_INFO.REMOTE_BUFF_RTN_SUPPORT bit indicates
+     * whether the INST field in the buffer descriptor is populated by iDMA
+     * hardware.
      */
-    uint_reg_t inst         : 1;
-    /** Reserved. */
-    uint_reg_t __reserved_6 : 1;
+    uint_reg_t inst         : 2;
     /**
      * Always set to one by hardware in iDMA packet descriptors.  For eDMA,
      * indicates whether the buffer will be released to the buffer stack
@@ -491,8 +504,7 @@ typedef union
     uint_reg_t c            : 2;
     uint_reg_t size         : 3;
     uint_reg_t hwb          : 1;
-    uint_reg_t __reserved_6 : 1;
-    uint_reg_t inst         : 1;
+    uint_reg_t inst         : 2;
     uint_reg_t __reserved_5 : 3;
     uint_reg_t stack_idx    : 5;
     uint_reg_t __reserved_4 : 6;
index 628b045436b8969e6287fd401e13e35aa06b9e7e..85647e91a4584c0db815bebc1cbb2fa85fce71d0 100644 (file)
 #ifndef __ARCH_TRIO_CONSTANTS_H__
 #define __ARCH_TRIO_CONSTANTS_H__
 
-#define TRIO_NUM_ASIDS 16
+#define TRIO_NUM_ASIDS 32
 #define TRIO_NUM_TLBS_PER_ASID 16
 
 #define TRIO_NUM_TPIO_REGIONS 8
 #define TRIO_LOG2_NUM_TPIO_REGIONS 3
 
-#define TRIO_NUM_MAP_MEM_REGIONS 16
-#define TRIO_LOG2_NUM_MAP_MEM_REGIONS 4
+#define TRIO_NUM_MAP_MEM_REGIONS 32
+#define TRIO_LOG2_NUM_MAP_MEM_REGIONS 5
 #define TRIO_NUM_MAP_SQ_REGIONS 8
 #define TRIO_LOG2_NUM_MAP_SQ_REGIONS 3
 
 #define TRIO_LOG2_NUM_SQ_FIFO_ENTRIES 6
 
-#define TRIO_NUM_PUSH_DMA_RINGS 32
+#define TRIO_NUM_PUSH_DMA_RINGS 64
 
-#define TRIO_NUM_PULL_DMA_RINGS 32
+#define TRIO_NUM_PULL_DMA_RINGS 64
 
 #endif /* __ARCH_TRIO_CONSTANTS_H__ */
index 6346888f7bdc9359b38ee17104385adb9e501856..67276800861833f674422a10cf47440f7864af3b 100644 (file)
@@ -182,10 +182,9 @@ static inline __attribute_const__ int get_order(unsigned long size)
 
 #define PAGE_OFFSET            (-(_AC(1, UL) << (MAX_VA_WIDTH - 1)))
 #define KERNEL_HIGH_VADDR      _AC(0xfffffff800000000, UL)  /* high 32GB */
-#define FIXADDR_BASE           (KERNEL_HIGH_VADDR - 0x400000000) /* 4 GB */
-#define FIXADDR_TOP            (KERNEL_HIGH_VADDR - 0x300000000) /* 4 GB */
+#define FIXADDR_BASE           (KERNEL_HIGH_VADDR - 0x300000000) /* 4 GB */
+#define FIXADDR_TOP            (KERNEL_HIGH_VADDR - 0x200000000) /* 4 GB */
 #define _VMALLOC_START         FIXADDR_TOP
-#define HUGE_VMAP_BASE         (KERNEL_HIGH_VADDR - 0x200000000) /* 4 GB */
 #define MEM_SV_START           (KERNEL_HIGH_VADDR - 0x100000000) /* 256 MB */
 #define MEM_MODULE_START       (MEM_SV_START + (256*1024*1024)) /* 256 MB */
 #define MEM_MODULE_END         (MEM_MODULE_START + (256*1024*1024))
index 63142ab3b3dd8337bf1b6cc2c165af65fc85181a..d26a42279036837b760ea4b93593b45fe4394f83 100644 (file)
 #define PKMAP_BASE   ((FIXADDR_BOOT_START - PAGE_SIZE*LAST_PKMAP) & PGDIR_MASK)
 
 #ifdef CONFIG_HIGHMEM
-# define __VMAPPING_END        (PKMAP_BASE & ~(HPAGE_SIZE-1))
+# define _VMALLOC_END  (PKMAP_BASE & ~(HPAGE_SIZE-1))
 #else
-# define __VMAPPING_END        (FIXADDR_START & ~(HPAGE_SIZE-1))
-#endif
-
-#ifdef CONFIG_HUGEVMAP
-#define HUGE_VMAP_END  __VMAPPING_END
-#define HUGE_VMAP_BASE (HUGE_VMAP_END - CONFIG_NR_HUGE_VMAPS * HPAGE_SIZE)
-#define _VMALLOC_END   HUGE_VMAP_BASE
-#else
-#define _VMALLOC_END   __VMAPPING_END
+# define _VMALLOC_END  (FIXADDR_START & ~(HPAGE_SIZE-1))
 #endif
 
 /*
index 3421177f737002ee8c8addf515e30615729d08b5..2c8a9cd102d359f8a8ec5eb1cf4c515e7ad567ce 100644 (file)
  * memory allocation code).  The vmalloc code puts in an internal
  * guard page between each allocation.
  */
-#define _VMALLOC_END   HUGE_VMAP_BASE
+#define _VMALLOC_END   MEM_SV_START
 #define VMALLOC_END    _VMALLOC_END
 #define VMALLOC_START  _VMALLOC_START
 
-#define HUGE_VMAP_END  (HUGE_VMAP_BASE + PGDIR_SIZE)
-
 #ifndef __ASSEMBLY__
 
 /* We have no pud since we are a three-level page table. */
index fdd07f88cfd7124458a4d31fb1a098764e15bb9a..4cda03de734f5162bc43359483ce4eeace9ea1dd 100644 (file)
 #define GXIO_MPIPE_OP_GET_MMIO_BASE    IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
 #define GXIO_MPIPE_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 
-int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t *context,
                                   unsigned int count, unsigned int first,
                                   unsigned int flags);
 
-int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t * context,
+int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t *context,
                                     void *mem_va, size_t mem_size,
                                     unsigned int mem_flags, unsigned int stack,
                                     unsigned int buffer_size_enum);
 
 
-int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t *context,
                                 unsigned int count, unsigned int first,
                                 unsigned int flags);
 
-int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t *context, void *mem_va,
                                   size_t mem_size, unsigned int mem_flags,
                                   unsigned int ring);
 
-int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t * context,
+int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t *context,
                                            int inter_x, int inter_y,
                                            int inter_ipi, int inter_event,
                                            unsigned int ring);
 
-int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t * context,
+int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t *context,
                                           unsigned int ring);
 
-int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t *context,
                                  unsigned int count, unsigned int first,
                                  unsigned int flags);
 
-int gxio_mpipe_init_notif_group(gxio_mpipe_context_t * context,
+int gxio_mpipe_init_notif_group(gxio_mpipe_context_t *context,
                                unsigned int group,
                                gxio_mpipe_notif_group_bits_t bits);
 
-int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t * context, unsigned int count,
+int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t *context, unsigned int count,
                             unsigned int first, unsigned int flags);
 
-int gxio_mpipe_init_bucket(gxio_mpipe_context_t * context, unsigned int bucket,
+int gxio_mpipe_init_bucket(gxio_mpipe_context_t *context, unsigned int bucket,
                           MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info);
 
-int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t * context,
+int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context,
                                unsigned int count, unsigned int first,
                                unsigned int flags);
 
-int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t * context, void *mem_va,
+int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t *context, void *mem_va,
                                  size_t mem_size, unsigned int mem_flags,
                                  unsigned int ring, unsigned int channel);
 
 
-int gxio_mpipe_commit_rules(gxio_mpipe_context_t * context, const void *blob,
+int gxio_mpipe_commit_rules(gxio_mpipe_context_t *context, const void *blob,
                            size_t blob_size);
 
-int gxio_mpipe_register_client_memory(gxio_mpipe_context_t * context,
+int gxio_mpipe_register_client_memory(gxio_mpipe_context_t *context,
                                      unsigned int iotlb, HV_PTE pte,
                                      unsigned int flags);
 
-int gxio_mpipe_link_open_aux(gxio_mpipe_context_t * context,
+int gxio_mpipe_link_open_aux(gxio_mpipe_context_t *context,
                             _gxio_mpipe_link_name_t name, unsigned int flags);
 
-int gxio_mpipe_link_close_aux(gxio_mpipe_context_t * context, int mac);
+int gxio_mpipe_link_close_aux(gxio_mpipe_context_t *context, int mac);
 
-int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t * context, int mac,
+int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t *context, int mac,
                                 uint32_t attr, int64_t val);
 
-int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t * context, uint64_t * sec,
-                                uint64_t * nsec, uint64_t * cycles);
+int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t *context, uint64_t *sec,
+                                uint64_t *nsec, uint64_t *cycles);
 
-int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t * context, uint64_t sec,
+int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t *context, uint64_t sec,
                                 uint64_t nsec, uint64_t cycles);
 
-int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t * context,
+int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t *context,
                                    int64_t nsec);
 
-int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t * context,
+int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t *context,
                                     int32_t ppb);
 
-int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
+int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie);
 
-int gxio_mpipe_close_pollfd(gxio_mpipe_context_t * context, int pollfd_cookie);
+int gxio_mpipe_close_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie);
 
-int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t * context, HV_PTE *base);
+int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t *context, HV_PTE *base);
 
-int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t * context,
+int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t *context,
                                 unsigned long offset, unsigned long size);
 
 #endif /* !__GXIO_MPIPE_LINUX_RPC_H__ */
index 476c5e5ca22cfe53714e699b667abf2995a192de..f0b04284468b804c424bf2b45e49cfdb3cb6972a 100644 (file)
 #define GXIO_MPIPE_INFO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 
 
-int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t *context,
                                 _gxio_mpipe_link_name_t name);
 
-int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t *context,
                                  unsigned int idx,
-                                 _gxio_mpipe_link_name_t * name,
-                                 _gxio_mpipe_link_mac_t * mac);
+                                 _gxio_mpipe_link_name_t *name,
+                                 _gxio_mpipe_link_mac_t *mac);
 
-int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t *context,
                                  HV_PTE *base);
 
-int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t * context,
+int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t *context,
                                      unsigned long offset, unsigned long size);
 
 #endif /* !__GXIO_MPIPE_INFO_LINUX_RPC_H__ */
index d95b96fd6c934d284f3b0669db7e960cc1c37b7a..376a4f771167ce9fec47c926da1938af2fd2ff88 100644 (file)
 #define GXIO_TRIO_OP_GET_MMIO_BASE     IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
 #define GXIO_TRIO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 
-int gxio_trio_alloc_asids(gxio_trio_context_t * context, unsigned int count,
+int gxio_trio_alloc_asids(gxio_trio_context_t *context, unsigned int count,
                          unsigned int first, unsigned int flags);
 
 
-int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context,
+int gxio_trio_alloc_memory_maps(gxio_trio_context_t *context,
                                unsigned int count, unsigned int first,
                                unsigned int flags);
 
 
-int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context,
+int gxio_trio_alloc_scatter_queues(gxio_trio_context_t *context,
                                   unsigned int count, unsigned int first,
                                   unsigned int flags);
 
-int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context,
+int gxio_trio_alloc_pio_regions(gxio_trio_context_t *context,
                                unsigned int count, unsigned int first,
                                unsigned int flags);
 
-int gxio_trio_init_pio_region_aux(gxio_trio_context_t * context,
+int gxio_trio_init_pio_region_aux(gxio_trio_context_t *context,
                                  unsigned int pio_region, unsigned int mac,
                                  uint32_t bus_address_hi, unsigned int flags);
 
 
-int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t * context,
+int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t *context,
                                      unsigned int map, unsigned long va,
                                      uint64_t size, unsigned int asid,
                                      unsigned int mac, uint64_t bus_address,
                                      unsigned int node,
                                      unsigned int order_mode);
 
-int gxio_trio_get_port_property(gxio_trio_context_t * context,
+int gxio_trio_get_port_property(gxio_trio_context_t *context,
                                struct pcie_trio_ports_property *trio_ports);
 
-int gxio_trio_config_legacy_intr(gxio_trio_context_t * context, int inter_x,
+int gxio_trio_config_legacy_intr(gxio_trio_context_t *context, int inter_x,
                                 int inter_y, int inter_ipi, int inter_event,
                                 unsigned int mac, unsigned int intx);
 
-int gxio_trio_config_msi_intr(gxio_trio_context_t * context, int inter_x,
+int gxio_trio_config_msi_intr(gxio_trio_context_t *context, int inter_x,
                              int inter_y, int inter_ipi, int inter_event,
                              unsigned int mac, unsigned int mem_map,
                              uint64_t mem_map_base, uint64_t mem_map_limit,
                              unsigned int asid);
 
 
-int gxio_trio_set_mps_mrs(gxio_trio_context_t * context, uint16_t mps,
+int gxio_trio_set_mps_mrs(gxio_trio_context_t *context, uint16_t mps,
                          uint16_t mrs, unsigned int mac);
 
-int gxio_trio_force_rc_link_up(gxio_trio_context_t * context, unsigned int mac);
+int gxio_trio_force_rc_link_up(gxio_trio_context_t *context, unsigned int mac);
 
-int gxio_trio_force_ep_link_up(gxio_trio_context_t * context, unsigned int mac);
+int gxio_trio_force_ep_link_up(gxio_trio_context_t *context, unsigned int mac);
 
-int gxio_trio_get_mmio_base(gxio_trio_context_t * context, HV_PTE *base);
+int gxio_trio_get_mmio_base(gxio_trio_context_t *context, HV_PTE *base);
 
-int gxio_trio_check_mmio_offset(gxio_trio_context_t * context,
+int gxio_trio_check_mmio_offset(gxio_trio_context_t *context,
                                unsigned long offset, unsigned long size);
 
 #endif /* !__GXIO_TRIO_LINUX_RPC_H__ */
index 8622e7d126adcec2c51af5366f86ff86a37ca0ae..79962a97de8e09a81d2e7ebcd7d8c5aecaed98f0 100644 (file)
 #define GXIO_USB_HOST_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000)
 #define GXIO_USB_HOST_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001)
 
-int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t * context, int inter_x,
+int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t *context, int inter_x,
                                int inter_y, int inter_ipi, int inter_event);
 
-int gxio_usb_host_register_client_memory(gxio_usb_host_context_t * context,
+int gxio_usb_host_register_client_memory(gxio_usb_host_context_t *context,
                                         HV_PTE pte, unsigned int flags);
 
-int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t * context,
+int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t *context,
                                HV_PTE *base);
 
-int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t * context,
+int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t *context,
                                    unsigned long offset, unsigned long size);
 
 #endif /* !__GXIO_USB_HOST_LINUX_RPC_H__ */
index 5eedec0e988ef09392a4716329a25c1a760b06df..93c9636d2dd7879bf4867a17c65039ebd325eb93 100644 (file)
@@ -53,7 +53,7 @@ typedef struct {
  * @return Zero if the context was successfully initialized, else a
  *  GXIO_ERR_xxx error code.
  */
-extern int gxio_usb_host_init(gxio_usb_host_context_t * context, int usb_index,
+extern int gxio_usb_host_init(gxio_usb_host_context_t *context, int usb_index,
                              int is_ehci);
 
 /* Destroy a USB context.
@@ -68,20 +68,20 @@ extern int gxio_usb_host_init(gxio_usb_host_context_t * context, int usb_index,
  * @return Zero if the context was successfully destroyed, else a
  *  GXIO_ERR_xxx error code.
  */
-extern int gxio_usb_host_destroy(gxio_usb_host_context_t * context);
+extern int gxio_usb_host_destroy(gxio_usb_host_context_t *context);
 
 /* Retrieve the address of the shim's MMIO registers.
  *
  * @param context Pointer to a properly initialized gxio_usb_host_context_t.
  * @return The address of the shim's MMIO registers.
  */
-extern void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t * context);
+extern void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t *context);
 
 /* Retrieve the length of the shim's MMIO registers.
  *
  * @param context Pointer to a properly initialized gxio_usb_host_context_t.
  * @return The length of the shim's MMIO registers.
  */
-extern size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t * context);
+extern size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t *context);
 
 #endif /* _GXIO_USB_H_ */
index ed378416b86aa128b3eed7a3f20e010fedad740a..49120843ff96987feef36eff57365371fd07296b 100644 (file)
@@ -84,7 +84,7 @@ COMPAT_SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned int, offset_high,
 {
        return sys_llseek(fd, offset_high, offset_low, result, origin);
 }
+
 /* Provide the compat syscall number to call mapping. */
 #undef __SYSCALL
 #define __SYSCALL(nr, call) [nr] = (call),
diff --git a/arch/tile/kernel/futex_64.S b/arch/tile/kernel/futex_64.S
deleted file mode 100644 (file)
index f465d1e..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2011 Tilera Corporation. All Rights Reserved.
- *
- *   This program is free software; you can redistribute it and/or
- *   modify it under the terms of the GNU General Public License
- *   as published by the Free Software Foundation, version 2.
- *
- *   This program is distributed in the hope that it will be useful, but
- *   WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- *   NON INFRINGEMENT.  See the GNU General Public License for
- *   more details.
- *
- * Atomically access user memory, but use MMU to avoid propagating
- * kernel exceptions.
- */
-
-#include <linux/linkage.h>
-#include <asm/errno.h>
-#include <asm/futex.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-
-/*
- * Provide a set of atomic memory operations supporting <asm/futex.h>.
- *
- * r0: user address to manipulate
- * r1: new value to write, or for cmpxchg, old value to compare against
- * r2: (cmpxchg only) new value to write
- *
- * Return __get_user struct, r0 with value, r1 with error.
- */
-#define FUTEX_OP(name, ...) \
-STD_ENTRY(futex_##name)                        \
-       __VA_ARGS__;                    \
-       {                               \
-        move   r1, zero;               \
-        jrp    lr                      \
-       };                              \
-       STD_ENDPROC(futex_##name);      \
-       .pushsection __ex_table,"a";    \
-       .quad 1b, get_user_fault;       \
-       .popsection
-
-       .pushsection .fixup,"ax"
-get_user_fault:
-       { movei r1, -EFAULT; jrp lr }
-       ENDPROC(get_user_fault)
-       .popsection
-
-FUTEX_OP(cmpxchg, mtspr CMPEXCH_VALUE, r1; 1: cmpexch4 r0, r0, r2)
-FUTEX_OP(set, 1: exch4 r0, r0, r1)
-FUTEX_OP(add, 1: fetchadd4 r0, r0, r1)
-FUTEX_OP(or, 1: fetchor4 r0, r0, r1)
-FUTEX_OP(andn, nor r1, r1, zero; 1: fetchand4 r0, r0, r1)
index 4c34caea9dd31041bdf263a5c72ec3a3ba46f19c..74c91729a62a9290e12bb31ea96ab7ad240aebc2 100644 (file)
@@ -1268,8 +1268,7 @@ static void __init validate_va(void)
        if ((long)VMALLOC_START >= 0)
                early_panic(
                        "Linux VMALLOC region below the 2GB line (%#lx)!\n"
-                       "Reconfigure the kernel with fewer NR_HUGE_VMAPS\n"
-                       "or smaller VMALLOC_RESERVE.\n",
+                       "Reconfigure the kernel with smaller VMALLOC_RESERVE.\n",
                        VMALLOC_START);
 #endif
 }
index b425fb6a480d3e40c6d7fd2fab4bed1a41c7dbc0..b030b4e78845b596c1fc429687e360a2791e7046 100644 (file)
@@ -551,8 +551,8 @@ static tilegx_bundle_bits  jit_x1_bnezt(int ra, int broff)
 /*
  * This function generates unalign fixup JIT.
  *
- * We fist find unalign load/store instruction's destination, source
- * reguisters: ra, rb and rd. and 3 scratch registers by calling
+ * We first find unalign load/store instruction's destination, source
+ * registers: ra, rb and rd. and 3 scratch registers by calling
  * find_regs(...). 3 scratch clobbers should not alias with any register
  * used in the fault bundle. Then analyze the fault bundle to determine
  * if it's a load or store, operand width, branch or address increment etc.
index 111d5a9b76f146c541d4fb17d56aacead9e7782d..6c0571216a9d67f81a09ff331a601d22ae881566 100644 (file)
@@ -149,8 +149,6 @@ static inline int vmalloc_fault(pgd_t *pgd, unsigned long address)
        pmd_k = vmalloc_sync_one(pgd, address);
        if (!pmd_k)
                return -1;
-       if (pmd_huge(*pmd_k))
-               return 0;   /* support TILE huge_vmap() API */
        pte_k = pte_offset_kernel(pmd_k, address);
        if (!pte_present(*pte_k))
                return -1;
@@ -280,8 +278,7 @@ static int handle_page_fault(struct pt_regs *regs,
        if (!is_page_fault)
                write = 1;
 
-       flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                (write ? FAULT_FLAG_WRITE : 0));
+       flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        is_kernel_mode = !user_mode(regs);
 
@@ -365,6 +362,9 @@ static int handle_page_fault(struct pt_regs *regs,
                goto bad_area_nosemaphore;
        }
 
+       if (!is_kernel_mode)
+               flags |= FAULT_FLAG_USER;
+
        /*
         * When running in the kernel we expect faults to occur only to
         * addresses in user space.  All other faults represent errors in the
@@ -425,12 +425,12 @@ good_area:
 #endif
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
+               flags |= FAULT_FLAG_WRITE;
        } else {
                if (!is_page_fault || !(vma->vm_flags & VM_READ))
                        goto bad_area;
        }
 
- survive:
        /*
         * If for any reason at all we couldn't handle the fault,
         * make sure we exit gracefully rather than endlessly redo
@@ -555,11 +555,6 @@ no_context:
  */
 out_of_memory:
        up_read(&mm->mmap_sem);
-       if (is_global_init(tsk)) {
-               yield();
-               down_read(&mm->mmap_sem);
-               goto survive;
-       }
        if (is_kernel_mode)
                goto no_context;
        pagefault_out_of_memory();
index e514899e1100319dc83fe69530f1aad67b17ceea..0cb3bbaa580c5dbc5ed00417ffd4b6e002c03813 100644 (file)
@@ -166,6 +166,11 @@ int pud_huge(pud_t pud)
        return !!(pud_val(pud) & _PAGE_HUGE_PAGE);
 }
 
+int pmd_huge_support(void)
+{
+       return 1;
+}
+
 struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
                             pmd_t *pmd, int write)
 {
index 4e316deb92fd58f084e57d01a42104e65c68c29b..0fa1acfac79ad2a25ba82aed6607e36f868ade7c 100644 (file)
@@ -827,10 +827,6 @@ void __init mem_init(void)
               FIXADDR_START, FIXADDR_TOP + PAGE_SIZE - 1);
        printk(KERN_DEBUG "  PKMAP   %#lx - %#lx\n",
               PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP) - 1);
-#endif
-#ifdef CONFIG_HUGEVMAP
-       printk(KERN_DEBUG "  HUGEMAP %#lx - %#lx\n",
-              HUGE_VMAP_BASE, HUGE_VMAP_END - 1);
 #endif
        printk(KERN_DEBUG "  VMALLOC %#lx - %#lx\n",
               _VMALLOC_START, _VMALLOC_END - 1);
index 2deaddf3e01f2329c2aded0d083c65e005a115f2..4fd9ec0b58edcb57d0b3346d41eea54c6f66c35f 100644 (file)
@@ -127,8 +127,7 @@ void shatter_huge_page(unsigned long addr)
        }
 
        /* Shatter the huge page into the preallocated L2 page table. */
-       pmd_populate_kernel(&init_mm, pmd,
-                           get_prealloc_pte(pte_pfn(*(pte_t *)pmd)));
+       pmd_populate_kernel(&init_mm, pmd, get_prealloc_pte(pmd_pfn(*pmd)));
 
 #ifdef __PAGETABLE_PMD_FOLDED
        /* Walk every pgd on the system and update the pmd there. */
index bceee6623b00134023918cd5b62ec6144e3c66eb..8ddea1f8006a5a0732a3550ff6a5883aabd7fdec 100644 (file)
@@ -6,7 +6,6 @@ config DEFCONFIG_LIST
 config UML
        bool
        default y
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_UID16
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
index 08107a795062c55b0e9633bdd0b2da02351e96c4..2665e6b683f5dbca8de227aeb0d97cccac49803c 100644 (file)
@@ -129,12 +129,10 @@ CONFIG_BSD_PROCESS_ACCT=y
 # CONFIG_FHANDLE is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
-CONFIG_HAVE_GENERIC_HARDIRQS=y
 
 #
 # IRQ subsystem
 #
-CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_SHOW=y
 
 #
index 3845051f1b10a34bbd83a96bad9a23bab30b057d..3b48cd2081ee112cb9eabdb3e2fab145c2084c06 100644 (file)
@@ -7,7 +7,6 @@
 #ifndef __UM_UBD_USER_H
 #define __UM_UBD_USER_H
 
-extern void ignore_sigwinch_sig(void);
 extern int start_io_thread(unsigned long sp, int *fds_out);
 extern int io_thread(void *arg);
 extern int kernel_fd;
index 879990cb66c6264e4db70e4ed812a1710ea6b1df..3716e69525546c984f8e730a458c6e22a4cc35af 100644 (file)
@@ -41,7 +41,7 @@
 #include <os.h>
 #include "cow.h"
 
-enum ubd_req { UBD_READ, UBD_WRITE };
+enum ubd_req { UBD_READ, UBD_WRITE, UBD_FLUSH };
 
 struct io_thread_req {
        struct request *req;
@@ -866,6 +866,7 @@ static int ubd_add(int n, char **error_out)
                goto out;
        }
        ubd_dev->queue->queuedata = ubd_dev;
+       blk_queue_flush(ubd_dev->queue, REQ_FLUSH);
 
        blk_queue_max_segments(ubd_dev->queue, MAX_SG);
        err = ubd_disk_register(UBD_MAJOR, ubd_dev->size, n, &ubd_gendisk[n]);
@@ -1238,12 +1239,41 @@ static void prepare_request(struct request *req, struct io_thread_req *io_req,
 
 }
 
+/* Called with dev->lock held */
+static void prepare_flush_request(struct request *req,
+                                 struct io_thread_req *io_req)
+{
+       struct gendisk *disk = req->rq_disk;
+       struct ubd *ubd_dev = disk->private_data;
+
+       io_req->req = req;
+       io_req->fds[0] = (ubd_dev->cow.file != NULL) ? ubd_dev->cow.fd :
+               ubd_dev->fd;
+       io_req->op = UBD_FLUSH;
+}
+
+static bool submit_request(struct io_thread_req *io_req, struct ubd *dev)
+{
+       int n = os_write_file(thread_fd, &io_req,
+                            sizeof(io_req));
+       if (n != sizeof(io_req)) {
+               if (n != -EAGAIN)
+                       printk("write to io thread failed, "
+                              "errno = %d\n", -n);
+               else if (list_empty(&dev->restart))
+                       list_add(&dev->restart, &restart);
+
+               kfree(io_req);
+               return false;
+       }
+       return true;
+}
+
 /* Called with dev->lock held */
 static void do_ubd_request(struct request_queue *q)
 {
        struct io_thread_req *io_req;
        struct request *req;
-       int n;
 
        while(1){
                struct ubd *dev = q->queuedata;
@@ -1259,6 +1289,19 @@ static void do_ubd_request(struct request_queue *q)
                }
 
                req = dev->request;
+
+               if (req->cmd_flags & REQ_FLUSH) {
+                       io_req = kmalloc(sizeof(struct io_thread_req),
+                                        GFP_ATOMIC);
+                       if (io_req == NULL) {
+                               if (list_empty(&dev->restart))
+                                       list_add(&dev->restart, &restart);
+                               return;
+                       }
+                       prepare_flush_request(req, io_req);
+                       submit_request(io_req, dev);
+               }
+
                while(dev->start_sg < dev->end_sg){
                        struct scatterlist *sg = &dev->sg[dev->start_sg];
 
@@ -1273,17 +1316,8 @@ static void do_ubd_request(struct request_queue *q)
                                        (unsigned long long)dev->rq_pos << 9,
                                        sg->offset, sg->length, sg_page(sg));
 
-                       n = os_write_file(thread_fd, &io_req,
-                                         sizeof(struct io_thread_req *));
-                       if(n != sizeof(struct io_thread_req *)){
-                               if(n != -EAGAIN)
-                                       printk("write to io thread failed, "
-                                              "errno = %d\n", -n);
-                               else if(list_empty(&dev->restart))
-                                       list_add(&dev->restart, &restart);
-                               kfree(io_req);
+                       if (submit_request(io_req, dev) == false)
                                return;
-                       }
 
                        dev->rq_pos += sg->length >> 9;
                        dev->start_sg++;
@@ -1367,6 +1401,17 @@ static void do_io(struct io_thread_req *req)
        int err;
        __u64 off;
 
+       if (req->op == UBD_FLUSH) {
+               /* fds[0] is always either the rw image or our cow file */
+               n = os_sync_file(req->fds[0]);
+               if (n != 0) {
+                       printk("do_io - sync failed err = %d "
+                              "fd = %d\n", -n, req->fds[0]);
+                       req->error = 1;
+               }
+               return;
+       }
+
        nsectors = req->length / req->sectorsize;
        start = 0;
        do {
@@ -1431,7 +1476,8 @@ int io_thread(void *arg)
        struct io_thread_req *req;
        int n;
 
-       ignore_sigwinch_sig();
+       os_fix_helper_signals();
+
        while(1){
                n = os_read_file(kernel_fd, &req,
                                 sizeof(struct io_thread_req *));
index a703e45d8aac3d421da9b25d6622e98de01a36b9..e376f9b9c68d8986f5a74536916d34c08848758d 100644 (file)
 #include "ubd.h"
 #include <os.h>
 
-void ignore_sigwinch_sig(void)
-{
-       signal(SIGWINCH, SIG_IGN);
-}
-
 int start_io_thread(unsigned long sp, int *fd_out)
 {
        int pid, fds[2], err;
index 95feaa47a2fbb369512daeb67ffdc19554f837ad..021104d98cb351d66f9f44353a6ddfa2da71b23d 100644 (file)
@@ -141,6 +141,7 @@ extern int os_seek_file(int fd, unsigned long long offset);
 extern int os_open_file(const char *file, struct openflags flags, int mode);
 extern int os_read_file(int fd, void *buf, int len);
 extern int os_write_file(int fd, const void *buf, int count);
+extern int os_sync_file(int fd);
 extern int os_file_size(const char *file, unsigned long long *size_out);
 extern int os_file_modtime(const char *file, unsigned long *modtime);
 extern int os_pipe(int *fd, int stream, int close_on_exec);
@@ -200,6 +201,7 @@ extern int os_unmap_memory(void *addr, int len);
 extern int os_drop_memory(void *addr, int length);
 extern int can_drop_memory(void);
 extern void os_flush_stdout(void);
+extern int os_mincore(void *addr, unsigned long len);
 
 /* execvp.c */
 extern int execvp_noalloc(char *buf, const char *file, char *const argv[]);
@@ -233,6 +235,7 @@ extern void setup_machinename(char *machine_out);
 extern void setup_hostinfo(char *buf, int len);
 extern void os_dump_core(void) __attribute__ ((noreturn));
 extern void um_early_printk(const char *s, unsigned int n);
+extern void os_fix_helper_signals(void);
 
 /* time.c */
 extern void idle_sleep(unsigned long long nsecs);
index babe21826e3ed80e2cae8d1956c53b69adb45705..d8b78a03855c6a1ad4c7ada6c96938f5e62ee02a 100644 (file)
@@ -13,7 +13,7 @@ clean-files :=
 obj-y = config.o exec.o exitcode.o irq.o ksyms.o mem.o \
        physmem.o process.o ptrace.o reboot.o sigio.o \
        signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o \
-       um_arch.o umid.o skas/
+       um_arch.o umid.o maccess.o skas/
 
 obj-$(CONFIG_BLK_DEV_INITRD) += initrd.o
 obj-$(CONFIG_GPROF)    += gprof_syms.o
index 36e12f0cefd5e95a688df0c56e0390377ded2028..1d8505b1e2908289b49961019b885908d312fed8 100644 (file)
@@ -337,6 +337,8 @@ static struct irq_chip normal_irq_type = {
        .irq_disable = dummy,
        .irq_enable = dummy,
        .irq_ack = dummy,
+       .irq_mask = dummy,
+       .irq_unmask = dummy,
 };
 
 static struct irq_chip SIGVTALRM_irq_type = {
@@ -344,6 +346,8 @@ static struct irq_chip SIGVTALRM_irq_type = {
        .irq_disable = dummy,
        .irq_enable = dummy,
        .irq_ack = dummy,
+       .irq_mask = dummy,
+       .irq_unmask = dummy,
 };
 
 void __init init_IRQ(void)
diff --git a/arch/um/kernel/maccess.c b/arch/um/kernel/maccess.c
new file mode 100644 (file)
index 0000000..1f3d5c4
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2013 Richard Weinberger <richrd@nod.at>
+ *
+ * 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/uaccess.h>
+#include <linux/kernel.h>
+#include <os.h>
+
+long probe_kernel_read(void *dst, const void *src, size_t size)
+{
+       void *psrc = (void *)rounddown((unsigned long)src, PAGE_SIZE);
+
+       if ((unsigned long)src < PAGE_SIZE || size <= 0)
+               return -EFAULT;
+
+       if (os_mincore(psrc, size + src - psrc) <= 0)
+               return -EFAULT;
+
+       return __probe_kernel_read(dst, src, size);
+}
index 089f3987e273a2c3f9576ef923dbd8ba8648cca5..5c3aef74237ffda72a0b252d4ee4b118d14a969a 100644 (file)
@@ -30,8 +30,7 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        pmd_t *pmd;
        pte_t *pte;
        int err = -EFAULT;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                                (is_write ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        *code_out = SEGV_MAPERR;
 
@@ -42,6 +41,8 @@ int handle_page_fault(unsigned long address, unsigned long ip,
        if (in_atomic())
                goto out_nosemaphore;
 
+       if (is_user)
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
@@ -58,12 +59,15 @@ retry:
 
 good_area:
        *code_out = SEGV_ACCERR;
-       if (is_write && !(vma->vm_flags & VM_WRITE))
-               goto out;
-
-       /* Don't require VM_READ|VM_EXEC for write faults! */
-       if (!is_write && !(vma->vm_flags & (VM_READ | VM_EXEC)))
-               goto out;
+       if (is_write) {
+               if (!(vma->vm_flags & VM_WRITE))
+                       goto out;
+               flags |= FAULT_FLAG_WRITE;
+       } else {
+               /* Don't require VM_READ|VM_EXEC for write faults! */
+               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+                       goto out;
+       }
 
        do {
                int fault;
@@ -124,6 +128,8 @@ out_of_memory:
         * (which will retry the fault, or kill us if we got oom-killed).
         */
        up_read(&mm->mmap_sem);
+       if (!is_user)
+               goto out_nosemaphore;
        pagefault_out_of_memory();
        return 0;
 }
index 3a6bc2af09615378886ebcc6a15f2f439cbb4407..014eb35fd13b424dd03fc1b7b03f159815106c28 100644 (file)
@@ -104,8 +104,7 @@ static int aio_thread(void *arg)
        struct io_event event;
        int err, n, reply_fd;
 
-       signal(SIGWINCH, SIG_IGN);
-
+       os_fix_helper_signals();
        while (1) {
                n = io_getevents(ctx, 1, 1, &event, NULL);
                if (n < 0) {
@@ -173,7 +172,7 @@ static int not_aio_thread(void *arg)
        struct aio_thread_reply reply;
        int err;
 
-       signal(SIGWINCH, SIG_IGN);
+       os_fix_helper_signals();
        while (1) {
                err = read(aio_req_fd_r, &req, sizeof(req));
                if (err != sizeof(req)) {
index c17bd6f7d674d98ad745ffb21c0ccab11fd515b9..07a750197bb09d3b5ce59b631aed874d58603386 100644 (file)
@@ -266,6 +266,15 @@ int os_write_file(int fd, const void *buf, int len)
        return n;
 }
 
+int os_sync_file(int fd)
+{
+       int n = fsync(fd);
+
+       if (n < 0)
+               return -errno;
+       return n;
+}
+
 int os_file_size(const char *file, unsigned long long *size_out)
 {
        struct uml_stat buf;
index 749c96da7b99492a4656faf29be190fa9908b330..e1704ff600ff9e677a98a4711d5c8b7b2ff8cf6a 100644 (file)
@@ -123,6 +123,8 @@ int __init main(int argc, char **argv, char **envp)
 
        setup_env_path();
 
+       setsid();
+
        new_argv = malloc((argc + 1) * sizeof(char *));
        if (new_argv == NULL) {
                perror("Mallocing argv");
index b8f34c9e53ae9fc820f81e215253ec2bc70f9ffc..33496fe2bb52f428bc8229749dc6b224ab60242a 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
 #include <signal.h>
@@ -232,6 +233,57 @@ out:
        return ok;
 }
 
+static int os_page_mincore(void *addr)
+{
+       char vec[2];
+       int ret;
+
+       ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
+       if (ret < 0) {
+               if (errno == ENOMEM || errno == EINVAL)
+                       return 0;
+               else
+                       return -errno;
+       }
+
+       return vec[0] & 1;
+}
+
+int os_mincore(void *addr, unsigned long len)
+{
+       char *vec;
+       int ret, i;
+
+       if (len <= UM_KERN_PAGE_SIZE)
+               return os_page_mincore(addr);
+
+       vec = calloc(1, (len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE);
+       if (!vec)
+               return -ENOMEM;
+
+       ret = mincore(addr, UM_KERN_PAGE_SIZE, vec);
+       if (ret < 0) {
+               if (errno == ENOMEM || errno == EINVAL)
+                       ret = 0;
+               else
+                       ret = -errno;
+
+               goto out;
+       }
+
+       for (i = 0; i < ((len + UM_KERN_PAGE_SIZE - 1) / UM_KERN_PAGE_SIZE); i++) {
+               if (!(vec[i] & 1)) {
+                       ret = 0;
+                       goto out;
+               }
+       }
+
+       ret = 1;
+out:
+       free(vec);
+       return ret;
+}
+
 void init_new_thread_signals(void)
 {
        set_handler(SIGSEGV);
@@ -242,5 +294,4 @@ void init_new_thread_signals(void)
        signal(SIGHUP, SIG_IGN);
        set_handler(SIGIO);
        signal(SIGWINCH, SIG_IGN);
-       signal(SIGTERM, SIG_DFL);
 }
index 8b61cc0e82c8e8752e2f8a68fdeb31be3441ebe8..46e762f926eb9def51ad29fbc8dc6ac17f7bc485 100644 (file)
@@ -55,7 +55,7 @@ static int write_sigio_thread(void *unused)
        int i, n, respond_fd;
        char c;
 
-       signal(SIGWINCH, SIG_IGN);
+       os_fix_helper_signals();
        fds = &current_poll;
        while (1) {
                n = poll(fds->poll, fds->used, -1);
index 492ef5e6e166e082969fda850698f75d281bac47..faee55ef6d2f4954aa9770c2d8985554e40797d7 100644 (file)
@@ -94,6 +94,16 @@ static inline void __attribute__ ((noreturn)) uml_abort(void)
                        exit(127);
 }
 
+/*
+ * UML helper threads must not handle SIGWINCH/INT/TERM
+ */
+void os_fix_helper_signals(void)
+{
+       signal(SIGWINCH, SIG_IGN);
+       signal(SIGINT, SIG_DFL);
+       signal(SIGTERM, SIG_DFL);
+}
+
 void os_dump_core(void)
 {
        int pid;
index 41bcc001344201b7487fc339264c1a513026a5dc..82cdd8906f3d6ff70e3317a78ae00c08a0bed39e 100644 (file)
@@ -2,7 +2,6 @@ config UNICORE32
        def_bool y
        select HAVE_MEMBLOCK
        select HAVE_GENERIC_DMA_COHERENT
-       select HAVE_GENERIC_HARDIRQS
        select HAVE_DMA_ATTRS
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_BZIP2
index f9b5c10bccee96e8838484aaf6effc39b3c89bd1..0dc922dba9154d7cfcfe5352ec8ec77169e8082f 100644 (file)
@@ -209,8 +209,7 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        struct task_struct *tsk;
        struct mm_struct *mm;
        int fault, sig, code;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                                ((!(fsr ^ 0x12)) ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        tsk = current;
        mm = tsk->mm;
@@ -222,6 +221,11 @@ static int do_pf(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
        if (in_atomic() || !mm)
                goto no_context;
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
+       if (!(fsr ^ 0x12))
+               flags |= FAULT_FLAG_WRITE;
+
        /*
         * As per x86, we may deadlock here.  However, since the kernel only
         * validly references user space from well defined areas of the code,
@@ -278,6 +282,13 @@ retry:
               (VM_FAULT_ERROR | VM_FAULT_BADMAP | VM_FAULT_BADACCESS))))
                return 0;
 
+       /*
+        * If we are in kernel mode at this point, we
+        * have no context to handle this fault with.
+        */
+       if (!user_mode(regs))
+               goto no_context;
+
        if (fault & VM_FAULT_OOM) {
                /*
                 * We ran out of memory, call the OOM killer, and return to
@@ -288,13 +299,6 @@ retry:
                return 0;
        }
 
-       /*
-        * If we are in kernel mode at this point, we
-        * have no context to handle this fault with.
-        */
-       if (!user_mode(regs))
-               goto no_context;
-
        if (fault & VM_FAULT_SIGBUS) {
                /*
                 * We had some memory, but were unable to
index 30c40f08a3d461346b06d4a8ebc7fa5acae121bf..ee2fb9d37745887eb16255cbd30adacbdcc1ecae 100644 (file)
@@ -82,7 +82,6 @@ config X86
        select HAVE_USER_RETURN_NOTIFIER
        select ARCH_BINFMT_ELF_RANDOMIZE_PIE
        select HAVE_ARCH_JUMP_LABEL
-       select HAVE_GENERIC_HARDIRQS
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
        select SPARSE_IRQ
        select GENERIC_FIND_FIRST_BIT
@@ -482,11 +481,12 @@ config X86_INTEL_LPSS
        bool "Intel Low Power Subsystem Support"
        depends on ACPI
        select COMMON_CLK
+       select PINCTRL
        ---help---
          Select to build support for Intel Low Power Subsystem such as
          found on Intel Lynxpoint PCH. Selecting this option enables
-         things like clock tree (common clock framework) which are needed
-         by the LPSS peripheral drivers.
+         things like clock tree (common clock framework) and pincontrol
+         which are needed by the LPSS peripheral drivers.
 
 config X86_RDC321X
        bool "RDC R-321x SoC"
index c09241659971addba17d25a552f755303560361e..b4b38bacb404090f4ac6f1679553877ab702f414 100644 (file)
@@ -4,7 +4,6 @@
 #ifdef __KERNEL__
 
 #include <linux/types.h>
-#include <asm-generic/dma-contiguous.h>
 
 static inline void
 dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { }
index 3a16c1483b459a144b32b042dd202d0467814646..64507f35800ce23e9c867e1c80b5dc3d0a835ec1 100644 (file)
@@ -3,18 +3,23 @@
 
 #ifdef __KERNEL__
 
+#include <linux/stringify.h>
 #include <linux/types.h>
 #include <asm/nops.h>
 #include <asm/asm.h>
 
 #define JUMP_LABEL_NOP_SIZE 5
 
-#define STATIC_KEY_INITIAL_NOP ".byte 0xe9 \n\t .long 0\n\t"
+#ifdef CONFIG_X86_64
+# define STATIC_KEY_INIT_NOP P6_NOP5_ATOMIC
+#else
+# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
+#endif
 
 static __always_inline bool arch_static_branch(struct static_key *key)
 {
        asm goto("1:"
-               STATIC_KEY_INITIAL_NOP
+               ".byte " __stringify(STATIC_KEY_INIT_NOP) "\n\t"
                ".pushsection __jump_table,  \"aw\" \n\t"
                _ASM_ALIGN "\n\t"
                _ASM_PTR "1b, %l[l_yes], %c0 \n\t"
index 8d16befdec88c671dcf29776a835435f9a946c2d..3d1999458709231affdc977df99530acf3a833ac 100644 (file)
@@ -315,21 +315,6 @@ static inline pmd_t pmd_mksoft_dirty(pmd_t pmd)
        return pmd_set_flags(pmd, _PAGE_SOFT_DIRTY);
 }
 
-static inline pte_t pte_swp_mksoft_dirty(pte_t pte)
-{
-       return pte_set_flags(pte, _PAGE_SWP_SOFT_DIRTY);
-}
-
-static inline int pte_swp_soft_dirty(pte_t pte)
-{
-       return pte_flags(pte) & _PAGE_SWP_SOFT_DIRTY;
-}
-
-static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
-{
-       return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY);
-}
-
 static inline pte_t pte_file_clear_soft_dirty(pte_t pte)
 {
        return pte_clear_flags(pte, _PAGE_SOFT_DIRTY);
@@ -446,6 +431,7 @@ pte_t *populate_extra_pte(unsigned long vaddr);
 
 #ifndef __ASSEMBLY__
 #include <linux/mm_types.h>
+#include <linux/mmdebug.h>
 #include <linux/log2.h>
 
 static inline int pte_none(pte_t pte)
@@ -864,6 +850,24 @@ static inline void update_mmu_cache_pmd(struct vm_area_struct *vma,
 {
 }
 
+static inline pte_t pte_swp_mksoft_dirty(pte_t pte)
+{
+       VM_BUG_ON(pte_present(pte));
+       return pte_set_flags(pte, _PAGE_SWP_SOFT_DIRTY);
+}
+
+static inline int pte_swp_soft_dirty(pte_t pte)
+{
+       VM_BUG_ON(pte_present(pte));
+       return pte_flags(pte) & _PAGE_SWP_SOFT_DIRTY;
+}
+
+static inline pte_t pte_swp_clear_soft_dirty(pte_t pte)
+{
+       VM_BUG_ON(pte_present(pte));
+       return pte_clear_flags(pte, _PAGE_SWP_SOFT_DIRTY);
+}
+
 #include <asm-generic/pgtable.h>
 #endif /* __ASSEMBLY__ */
 
index f4843e031131d224280c4c0d845def9a094f3082..0ecac257fb26cffd2bb9a6ece7b7a5976eca3c84 100644 (file)
@@ -75,6 +75,9 @@
  * with swap entry format. On x86 bits 6 and 7 are *not* involved
  * into swap entry computation, but bit 6 is used for nonlinear
  * file mapping, so we borrow bit 7 for soft dirty tracking.
+ *
+ * Please note that this bit must be treated as swap dirty page
+ * mark if and only if the PTE has present bit clear!
  */
 #ifdef CONFIG_MEM_SOFT_DIRTY
 #define _PAGE_SWP_SOFT_DIRTY   _PAGE_PSE
index cf512003e6633309587e15f179d0745976f6b510..e6d90babc245c1c2713bea64d436fb2a736b83e6 100644 (file)
@@ -62,6 +62,7 @@ static inline void __flush_tlb_all(void)
 
 static inline void __flush_tlb_one(unsigned long addr)
 {
+       count_vm_event(NR_TLB_LOCAL_FLUSH_ONE);
        __flush_tlb_single(addr);
 }
 
@@ -84,14 +85,38 @@ static inline void __flush_tlb_one(unsigned long addr)
 
 #ifndef CONFIG_SMP
 
-#define flush_tlb() __flush_tlb()
-#define flush_tlb_all() __flush_tlb_all()
-#define local_flush_tlb() __flush_tlb()
+/* "_up" is for UniProcessor.
+ *
+ * This is a helper for other header functions.  *Not* intended to be called
+ * directly.  All global TLB flushes need to either call this, or to bump the
+ * vm statistics themselves.
+ */
+static inline void __flush_tlb_up(void)
+{
+       count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
+       __flush_tlb();
+}
+
+static inline void flush_tlb_all(void)
+{
+       count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
+       __flush_tlb_all();
+}
+
+static inline void flush_tlb(void)
+{
+       __flush_tlb_up();
+}
+
+static inline void local_flush_tlb(void)
+{
+       __flush_tlb_up();
+}
 
 static inline void flush_tlb_mm(struct mm_struct *mm)
 {
        if (mm == current->active_mm)
-               __flush_tlb();
+               __flush_tlb_up();
 }
 
 static inline void flush_tlb_page(struct vm_area_struct *vma,
@@ -105,14 +130,14 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
                                   unsigned long start, unsigned long end)
 {
        if (vma->vm_mm == current->active_mm)
-               __flush_tlb();
+               __flush_tlb_up();
 }
 
 static inline void flush_tlb_mm_range(struct mm_struct *mm,
           unsigned long start, unsigned long end, unsigned long vmflag)
 {
        if (mm == current->active_mm)
-               __flush_tlb();
+               __flush_tlb_up();
 }
 
 static inline void native_flush_tlb_others(const struct cpumask *cpumask,
index d4cdfa67509ec266b787ec7a284e04065bb01c60..ce2d0a2c3e4ff56819152574eefded2e8d64ea69 100644 (file)
@@ -683,6 +683,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
        }
 
        /* Flush all TLBs via a mov %cr3, %reg; mov %reg, %cr3 */
+       count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
        __flush_tlb();
 
        /* Save MTRR state */
@@ -696,6 +697,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock)
 static void post_set(void) __releases(set_atomicity_lock)
 {
        /* Flush TLBs (no need to flush caches - they are disabled) */
+       count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
        __flush_tlb();
 
        /* Intel (P6) standard MTRRs */
index 0abf6742a8b0476a94d740f9cfb95b2fb090caba..9db76c31b3c311bf1f78633f87bef6853cb3db6b 100644 (file)
@@ -124,6 +124,7 @@ static struct event_constraint intel_ivb_event_constraints[] __read_mostly =
        INTEL_UEVENT_CONSTRAINT(0x0148, 0x4), /* L1D_PEND_MISS.PENDING */
        INTEL_UEVENT_CONSTRAINT(0x0279, 0xf), /* IDQ.EMTPY */
        INTEL_UEVENT_CONSTRAINT(0x019c, 0xf), /* IDQ_UOPS_NOT_DELIVERED.CORE */
+       INTEL_UEVENT_CONSTRAINT(0x02a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_LDM_PENDING */
        INTEL_UEVENT_CONSTRAINT(0x04a3, 0xf), /* CYCLE_ACTIVITY.CYCLES_NO_EXECUTE */
        INTEL_UEVENT_CONSTRAINT(0x05a3, 0xf), /* CYCLE_ACTIVITY.STALLS_L2_PENDING */
        INTEL_UEVENT_CONSTRAINT(0x06a3, 0xf), /* CYCLE_ACTIVITY.STALLS_LDM_PENDING */
@@ -898,8 +899,8 @@ static __initconst const u64 atom_hw_cache_event_ids
 static struct extra_reg intel_slm_extra_regs[] __read_mostly =
 {
        /* must define OFFCORE_RSP_X first, see intel_fixup_er() */
-       INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x768005ffff, RSP_0),
-       INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0x768005ffff, RSP_1),
+       INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x768005ffffull, RSP_0),
+       INTEL_UEVENT_EXTRA_REG(0x02b7, MSR_OFFCORE_RSP_1, 0x768005ffffull, RSP_1),
        EVENT_EXTRA_END
 };
 
index 63438aad177fc0c8e664066f80cf46f3493acfbe..ab3ba1c1b7dd2c425dd5edf4c2b5091d76355b34 100644 (file)
@@ -584,6 +584,7 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {
        INTEL_EVENT_CONSTRAINT(0xd0, 0xf),    /* MEM_UOP_RETIRED.* */
        INTEL_EVENT_CONSTRAINT(0xd1, 0xf),    /* MEM_LOAD_UOPS_RETIRED.* */
        INTEL_EVENT_CONSTRAINT(0xd2, 0xf),    /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
+       INTEL_EVENT_CONSTRAINT(0xd3, 0xf),    /* MEM_LOAD_UOPS_LLC_MISS_RETIRED.* */
        INTEL_UEVENT_CONSTRAINT(0x02d4, 0xf), /* MEM_LOAD_UOPS_MISC_RETIRED.LLC_MISS */
        EVENT_CONSTRAINT_END
 };
index fd8011ed4dcd512025bb4efc2fbbd412e568a29f..8ed44589b0e486eda5a45efa74f3f4d3836a730f 100644 (file)
@@ -2808,7 +2808,7 @@ uncore_get_event_constraint(struct intel_uncore_box *box, struct perf_event *eve
                        return c;
        }
 
-       if (event->hw.config == ~0ULL)
+       if (event->attr.config == UNCORE_FIXED_EVENT)
                return &constraint_fixed;
 
        if (type->constraints) {
@@ -3112,7 +3112,9 @@ static int uncore_pmu_event_init(struct perf_event *event)
                 */
                if (pmu->type->single_fixed && pmu->pmu_idx > 0)
                        return -EINVAL;
-               hwc->config = ~0ULL;
+
+               /* fixed counters have event field hardcoded to zero */
+               hwc->config = 0ULL;
        } else {
                hwc->config = event->attr.config & pmu->type->event_mask;
                if (pmu->type->ops->hw_config) {
index 69eb2fa254942e23537266c4e8a4d0a77c7ee04f..376dc7873447c80e27b8b765e6ff41a8f737da8a 100644 (file)
@@ -52,8 +52,7 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (unsigned long)__va(start);
        initrd_end = (unsigned long)__va(end);
index 63bdb29b25497edfb0a97ec7cfb9aa5b746d200a..b3cd3ebae0774001391548d7cad0582fcbfeb50d 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/pci.h>
 #include <linux/acpi.h>
 #include <linux/pci_ids.h>
+#include <drm/i915_drm.h>
 #include <asm/pci-direct.h>
 #include <asm/dma.h>
 #include <asm/io_apic.h>
@@ -216,6 +217,157 @@ static void __init intel_remapping_check(int num, int slot, int func)
 
 }
 
+/*
+ * Systems with Intel graphics controllers set aside memory exclusively
+ * for gfx driver use.  This memory is not marked in the E820 as reserved
+ * or as RAM, and so is subject to overlap from E820 manipulation later
+ * in the boot process.  On some systems, MMIO space is allocated on top,
+ * despite the efforts of the "RAM buffer" approach, which simply rounds
+ * memory boundaries up to 64M to try to catch space that may decode
+ * as RAM and so is not suitable for MMIO.
+ *
+ * And yes, so far on current devices the base addr is always under 4G.
+ */
+static u32 __init intel_stolen_base(int num, int slot, int func)
+{
+       u32 base;
+
+       /*
+        * For the PCI IDs in this quirk, the stolen base is always
+        * in 0x5c, aka the BDSM register (yes that's really what
+        * it's called).
+        */
+       base = read_pci_config(num, slot, func, 0x5c);
+       base &= ~((1<<20) - 1);
+
+       return base;
+}
+
+#define KB(x)  ((x) * 1024)
+#define MB(x)  (KB (KB (x)))
+#define GB(x)  (MB (KB (x)))
+
+static size_t __init gen3_stolen_size(int num, int slot, int func)
+{
+       size_t stolen_size;
+       u16 gmch_ctrl;
+
+       gmch_ctrl = read_pci_config_16(0, 0, 0, I830_GMCH_CTRL);
+
+       switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
+       case I855_GMCH_GMS_STOLEN_1M:
+               stolen_size = MB(1);
+               break;
+       case I855_GMCH_GMS_STOLEN_4M:
+               stolen_size = MB(4);
+               break;
+       case I855_GMCH_GMS_STOLEN_8M:
+               stolen_size = MB(8);
+               break;
+       case I855_GMCH_GMS_STOLEN_16M:
+               stolen_size = MB(16);
+               break;
+       case I855_GMCH_GMS_STOLEN_32M:
+               stolen_size = MB(32);
+               break;
+       case I915_GMCH_GMS_STOLEN_48M:
+               stolen_size = MB(48);
+               break;
+       case I915_GMCH_GMS_STOLEN_64M:
+               stolen_size = MB(64);
+               break;
+       case G33_GMCH_GMS_STOLEN_128M:
+               stolen_size = MB(128);
+               break;
+       case G33_GMCH_GMS_STOLEN_256M:
+               stolen_size = MB(256);
+               break;
+       case INTEL_GMCH_GMS_STOLEN_96M:
+               stolen_size = MB(96);
+               break;
+       case INTEL_GMCH_GMS_STOLEN_160M:
+               stolen_size = MB(160);
+               break;
+       case INTEL_GMCH_GMS_STOLEN_224M:
+               stolen_size = MB(224);
+               break;
+       case INTEL_GMCH_GMS_STOLEN_352M:
+               stolen_size = MB(352);
+               break;
+       default:
+               stolen_size = 0;
+               break;
+       }
+
+       return stolen_size;
+}
+
+static size_t __init gen6_stolen_size(int num, int slot, int func)
+{
+       u16 gmch_ctrl;
+
+       gmch_ctrl = read_pci_config_16(num, slot, func, SNB_GMCH_CTRL);
+       gmch_ctrl >>= SNB_GMCH_GMS_SHIFT;
+       gmch_ctrl &= SNB_GMCH_GMS_MASK;
+
+       return gmch_ctrl << 25; /* 32 MB units */
+}
+
+typedef size_t (*stolen_size_fn)(int num, int slot, int func);
+
+static struct pci_device_id intel_stolen_ids[] __initdata = {
+       INTEL_I915G_IDS(gen3_stolen_size),
+       INTEL_I915GM_IDS(gen3_stolen_size),
+       INTEL_I945G_IDS(gen3_stolen_size),
+       INTEL_I945GM_IDS(gen3_stolen_size),
+       INTEL_VLV_M_IDS(gen3_stolen_size),
+       INTEL_VLV_D_IDS(gen3_stolen_size),
+       INTEL_PINEVIEW_IDS(gen3_stolen_size),
+       INTEL_I965G_IDS(gen3_stolen_size),
+       INTEL_G33_IDS(gen3_stolen_size),
+       INTEL_I965GM_IDS(gen3_stolen_size),
+       INTEL_GM45_IDS(gen3_stolen_size),
+       INTEL_G45_IDS(gen3_stolen_size),
+       INTEL_IRONLAKE_D_IDS(gen3_stolen_size),
+       INTEL_IRONLAKE_M_IDS(gen3_stolen_size),
+       INTEL_SNB_D_IDS(gen6_stolen_size),
+       INTEL_SNB_M_IDS(gen6_stolen_size),
+       INTEL_IVB_M_IDS(gen6_stolen_size),
+       INTEL_IVB_D_IDS(gen6_stolen_size),
+       INTEL_HSW_D_IDS(gen6_stolen_size),
+       INTEL_HSW_M_IDS(gen6_stolen_size),
+};
+
+static void __init intel_graphics_stolen(int num, int slot, int func)
+{
+       size_t size;
+       int i;
+       u32 start;
+       u16 device, subvendor, subdevice;
+
+       device = read_pci_config_16(num, slot, func, PCI_DEVICE_ID);
+       subvendor = read_pci_config_16(num, slot, func,
+                                      PCI_SUBSYSTEM_VENDOR_ID);
+       subdevice = read_pci_config_16(num, slot, func, PCI_SUBSYSTEM_ID);
+
+       for (i = 0; i < ARRAY_SIZE(intel_stolen_ids); i++) {
+               if (intel_stolen_ids[i].device == device) {
+                       stolen_size_fn stolen_size =
+                               (stolen_size_fn)intel_stolen_ids[i].driver_data;
+                       size = stolen_size(num, slot, func);
+                       start = intel_stolen_base(num, slot, func);
+                       if (size && start) {
+                               /* Mark this space as reserved */
+                               e820_add_region(start, size, E820_RESERVED);
+                               sanitize_e820_map(e820.map,
+                                                 ARRAY_SIZE(e820.map),
+                                                 &e820.nr_map);
+                       }
+                       return;
+               }
+       }
+}
+
 #define QFLAG_APPLY_ONCE       0x1
 #define QFLAG_APPLIED          0x2
 #define QFLAG_DONE             (QFLAG_APPLY_ONCE|QFLAG_APPLIED)
@@ -251,6 +403,8 @@ static struct chipset early_qrk[] __initdata = {
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
        { PCI_VENDOR_ID_INTEL, 0x3406, PCI_CLASS_BRIDGE_HOST,
          PCI_BASE_CLASS_BRIDGE, 0, intel_remapping_check },
+       { PCI_VENDOR_ID_INTEL, PCI_ANY_ID, PCI_CLASS_DISPLAY_VGA, PCI_ANY_ID,
+         QFLAG_APPLY_ONCE, intel_graphics_stolen },
        {}
 };
 
index 2cfbc3a3a2dd61055bccc6633a80a5910c293529..f0dcb0ceb6a2eda24d298b8a05650374e753bcf6 100644 (file)
@@ -1176,6 +1176,9 @@ ftrace_restore_flags:
 #else /* ! CONFIG_DYNAMIC_FTRACE */
 
 ENTRY(mcount)
+       cmpl $__PAGE_OFFSET, %esp
+       jb ftrace_stub          /* Paging not enabled yet? */
+
        cmpl $0, function_trace_stop
        jne  ftrace_stub
 
index 1b69951a81e2b61bff752621872d5750736f96d4..b077f4cc225a29764e89389e099fbd0ae2006707 100644 (file)
@@ -487,21 +487,6 @@ ENDPROC(native_usergs_sysret64)
        TRACE_IRQS_OFF
        .endm
 
-ENTRY(save_rest)
-       PARTIAL_FRAME 1 (REST_SKIP+8)
-       movq 5*8+16(%rsp), %r11 /* save return address */
-       movq_cfi rbx, RBX+16
-       movq_cfi rbp, RBP+16
-       movq_cfi r12, R12+16
-       movq_cfi r13, R13+16
-       movq_cfi r14, R14+16
-       movq_cfi r15, R15+16
-       movq %r11, 8(%rsp)      /* return address */
-       FIXUP_TOP_OF_STACK %r11, 16
-       ret
-       CFI_ENDPROC
-END(save_rest)
-
 /* save complete stack frame */
        .pushsection .kprobes.text, "ax"
 ENTRY(save_paranoid)
index 460f5d9ceebb65c5337a6d3b57edbad7925b8c1a..ee11b7dfbfbb6676eb94a28360bce88b286ceac1 100644 (file)
@@ -24,18 +24,57 @@ union jump_code_union {
        } __attribute__((packed));
 };
 
+static void bug_at(unsigned char *ip, int line)
+{
+       /*
+        * The location is not an op that we were expecting.
+        * Something went wrong. Crash the box, as something could be
+        * corrupting the kernel.
+        */
+       pr_warning("Unexpected op at %pS [%p] (%02x %02x %02x %02x %02x) %s:%d\n",
+              ip, ip, ip[0], ip[1], ip[2], ip[3], ip[4], __FILE__, line);
+       BUG();
+}
+
 static void __jump_label_transform(struct jump_entry *entry,
                                   enum jump_label_type type,
-                                  void *(*poker)(void *, const void *, size_t))
+                                  void *(*poker)(void *, const void *, size_t),
+                                  int init)
 {
        union jump_code_union code;
+       const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
 
        if (type == JUMP_LABEL_ENABLE) {
+               /*
+                * We are enabling this jump label. If it is not a nop
+                * then something must have gone wrong.
+                */
+               if (unlikely(memcmp((void *)entry->code, ideal_nop, 5) != 0))
+                       bug_at((void *)entry->code, __LINE__);
+
                code.jump = 0xe9;
                code.offset = entry->target -
                                (entry->code + JUMP_LABEL_NOP_SIZE);
-       } else
+       } else {
+               /*
+                * We are disabling this jump label. If it is not what
+                * we think it is, then something must have gone wrong.
+                * If this is the first initialization call, then we
+                * are converting the default nop to the ideal nop.
+                */
+               if (init) {
+                       const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
+                       if (unlikely(memcmp((void *)entry->code, default_nop, 5) != 0))
+                               bug_at((void *)entry->code, __LINE__);
+               } else {
+                       code.jump = 0xe9;
+                       code.offset = entry->target -
+                               (entry->code + JUMP_LABEL_NOP_SIZE);
+                       if (unlikely(memcmp((void *)entry->code, &code, 5) != 0))
+                               bug_at((void *)entry->code, __LINE__);
+               }
                memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE);
+       }
 
        /*
         * Make text_poke_bp() a default fallback poker.
@@ -57,15 +96,38 @@ void arch_jump_label_transform(struct jump_entry *entry,
 {
        get_online_cpus();
        mutex_lock(&text_mutex);
-       __jump_label_transform(entry, type, NULL);
+       __jump_label_transform(entry, type, NULL, 0);
        mutex_unlock(&text_mutex);
        put_online_cpus();
 }
 
+static enum {
+       JL_STATE_START,
+       JL_STATE_NO_UPDATE,
+       JL_STATE_UPDATE,
+} jlstate __initdata_or_module = JL_STATE_START;
+
 __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry,
                                      enum jump_label_type type)
 {
-       __jump_label_transform(entry, type, text_poke_early);
+       /*
+        * This function is called at boot up and when modules are
+        * first loaded. Check if the default nop, the one that is
+        * inserted at compile time, is the ideal nop. If it is, then
+        * we do not need to update the nop, and we can leave it as is.
+        * If it is not, then we need to update the nop to the ideal nop.
+        */
+       if (jlstate == JL_STATE_START) {
+               const unsigned char default_nop[] = { STATIC_KEY_INIT_NOP };
+               const unsigned char *ideal_nop = ideal_nops[NOP_ATOMIC5];
+
+               if (memcmp(ideal_nop, default_nop, 5) != 0)
+                       jlstate = JL_STATE_UPDATE;
+               else
+                       jlstate = JL_STATE_NO_UPDATE;
+       }
+       if (jlstate == JL_STATE_UPDATE)
+               __jump_label_transform(entry, type, text_poke_early, 1);
 }
 
 #endif
index aecc98a93d1b42f39261fcc9102be5515185d78a..6cacab671f9b76a35aaf49d41431b12e788e5bbe 100644 (file)
@@ -653,6 +653,7 @@ static void announce_cpu(int cpu, int apicid)
 {
        static int current_node = -1;
        int node = early_cpu_to_node(cpu);
+       int max_cpu_present = find_last_bit(cpumask_bits(cpu_present_mask), NR_CPUS);
 
        if (system_state == SYSTEM_BOOTING) {
                if (node != current_node) {
@@ -661,7 +662,7 @@ static void announce_cpu(int cpu, int apicid)
                        current_node = node;
                        pr_info("Booting Node %3d, Processors ", node);
                }
-               pr_cont(" #%d%s", cpu, cpu == (nr_cpu_ids - 1) ? " OK\n" : "");
+               pr_cont(" #%4d%s", cpu, cpu == max_cpu_present ? " OK\n" : "");
                return;
        } else
                pr_info("Booting Node %d Processor %d APIC 0x%x\n",
index 2bc1e81045b0f20f90ad2500c3acae318de1e8ee..ddc3f3d2afdb155b3ce39f4049c800356fb42d04 100644 (file)
@@ -2025,6 +2025,17 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
        return rc;
 }
 
+static int em_ret_far_imm(struct x86_emulate_ctxt *ctxt)
+{
+        int rc;
+
+        rc = em_ret_far(ctxt);
+        if (rc != X86EMUL_CONTINUE)
+                return rc;
+        rsp_increment(ctxt, ctxt->src.val);
+        return X86EMUL_CONTINUE;
+}
+
 static int em_cmpxchg(struct x86_emulate_ctxt *ctxt)
 {
        /* Save real source value, then compare EAX against destination. */
@@ -3763,7 +3774,8 @@ static const struct opcode opcode_table[256] = {
        G(ByteOp, group11), G(0, group11),
        /* 0xC8 - 0xCF */
        I(Stack | SrcImmU16 | Src2ImmByte, em_enter), I(Stack, em_leave),
-       N, I(ImplicitOps | Stack, em_ret_far),
+       I(ImplicitOps | Stack | SrcImmU16, em_ret_far_imm),
+       I(ImplicitOps | Stack, em_ret_far),
        D(ImplicitOps), DI(SrcImmByte, intn),
        D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret),
        /* 0xD0 - 0xD7 */
index 6e2d2c8f230bea3202896156be9a8196785241aa..dce0df8150df23709607ca05ef4d09cb867cc035 100644 (file)
@@ -4421,13 +4421,12 @@ void kvm_mmu_invalidate_mmio_sptes(struct kvm *kvm)
        }
 }
 
-static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long
+mmu_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct kvm *kvm;
        int nr_to_scan = sc->nr_to_scan;
-
-       if (nr_to_scan == 0)
-               goto out;
+       unsigned long freed = 0;
 
        raw_spin_lock(&kvm_lock);
 
@@ -4462,25 +4461,37 @@ static int mmu_shrink(struct shrinker *shrink, struct shrink_control *sc)
                        goto unlock;
                }
 
-               prepare_zap_oldest_mmu_page(kvm, &invalid_list);
+               if (prepare_zap_oldest_mmu_page(kvm, &invalid_list))
+                       freed++;
                kvm_mmu_commit_zap_page(kvm, &invalid_list);
 
 unlock:
                spin_unlock(&kvm->mmu_lock);
                srcu_read_unlock(&kvm->srcu, idx);
 
+               /*
+                * unfair on small ones
+                * per-vm shrinkers cry out
+                * sadness comes quickly
+                */
                list_move_tail(&kvm->vm_list, &vm_list);
                break;
        }
 
        raw_spin_unlock(&kvm_lock);
+       return freed;
 
-out:
+}
+
+static unsigned long
+mmu_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
        return percpu_counter_read_positive(&kvm_total_used_mmu_pages);
 }
 
 static struct shrinker mmu_shrinker = {
-       .shrink = mmu_shrink,
+       .count_objects = mmu_shrink_count,
+       .scan_objects = mmu_shrink_scan,
        .seeks = DEFAULT_SEEKS * 10,
 };
 
index 04333015917984a6b65f3fd0ab4ecbad2f5b1f2a..ad75d77999d085037469539d42a5df140533971d 100644 (file)
@@ -99,6 +99,7 @@ struct guest_walker {
        pt_element_t prefetch_ptes[PTE_PREFETCH_NUM];
        gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
        pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS];
+       bool pte_writable[PT_MAX_FULL_LEVELS];
        unsigned pt_access;
        unsigned pte_access;
        gfn_t gfn;
@@ -235,6 +236,22 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
                if (pte == orig_pte)
                        continue;
 
+               /*
+                * If the slot is read-only, simply do not process the accessed
+                * and dirty bits.  This is the correct thing to do if the slot
+                * is ROM, and page tables in read-as-ROM/write-as-MMIO slots
+                * are only supported if the accessed and dirty bits are already
+                * set in the ROM (so that MMIO writes are never needed).
+                *
+                * Note that NPT does not allow this at all and faults, since
+                * it always wants nested page table entries for the guest
+                * page tables to be writable.  And EPT works but will simply
+                * overwrite the read-only memory to set the accessed and dirty
+                * bits.
+                */
+               if (unlikely(!walker->pte_writable[level - 1]))
+                       continue;
+
                ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, orig_pte, pte);
                if (ret)
                        return ret;
@@ -309,7 +326,8 @@ retry_walk:
                        goto error;
                real_gfn = gpa_to_gfn(real_gfn);
 
-               host_addr = gfn_to_hva(vcpu->kvm, real_gfn);
+               host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn,
+                                           &walker->pte_writable[walker->level - 1]);
                if (unlikely(kvm_is_error_hva(host_addr)))
                        goto error;
 
index 1f1da43ff2a2ca66a137c434cf738dbf7a03e704..a1216de9ffda3b8ed6c38565c66e1e5c7c87c313 100644 (file)
@@ -5339,6 +5339,15 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
                return 0;
        }
 
+       /*
+        * EPT violation happened while executing iret from NMI,
+        * "blocked by NMI" bit has to be set before next VM entry.
+        * There are errata that may cause this bit to not be set:
+        * AAK134, BY25.
+        */
+       if (exit_qualification & INTR_INFO_UNBLOCK_NMI)
+               vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI);
+
        gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
        trace_kvm_page_fault(gpa, exit_qualification);
 
@@ -7766,6 +7775,10 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
                vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1);
                vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2);
                vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
+               __clear_bit(VCPU_EXREG_PDPTR,
+                               (unsigned long *)&vcpu->arch.regs_avail);
+               __clear_bit(VCPU_EXREG_PDPTR,
+                               (unsigned long *)&vcpu->arch.regs_dirty);
        }
 
        kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp);
index 6a22c19da6633601c73c1136964950d61f1c855b..bdf8532494fed0cc459ba46e19b9cc26e4d6366f 100644 (file)
@@ -7,8 +7,7 @@
  * kernel and insert a module (lg.ko) which allows us to run other Linux
  * kernels the same way we'd run processes.  We call the first kernel the Host,
  * and the others the Guests.  The program which sets up and configures Guests
- * (such as the example in Documentation/virtual/lguest/lguest.c) is called the
- * Launcher.
+ * (such as the example in tools/lguest/lguest.c) is called the Launcher.
  *
  * Secondly, we only run specially modified Guests, not normal kernels: setting
  * CONFIG_LGUEST_GUEST to "y" compiles this file into the kernel so it knows
@@ -1057,6 +1056,12 @@ static void lguest_load_sp0(struct tss_struct *tss,
 }
 
 /* Let's just say, I wouldn't do debugging under a Guest. */
+static unsigned long lguest_get_debugreg(int regno)
+{
+       /* FIXME: Implement */
+       return 0;
+}
+
 static void lguest_set_debugreg(int regno, unsigned long value)
 {
        /* FIXME: Implement */
@@ -1304,6 +1309,7 @@ __init void lguest_init(void)
        pv_cpu_ops.load_tr_desc = lguest_load_tr_desc;
        pv_cpu_ops.set_ldt = lguest_set_ldt;
        pv_cpu_ops.load_tls = lguest_load_tls;
+       pv_cpu_ops.get_debugreg = lguest_get_debugreg;
        pv_cpu_ops.set_debugreg = lguest_set_debugreg;
        pv_cpu_ops.clts = lguest_clts;
        pv_cpu_ops.read_cr0 = lguest_read_cr0;
index 654be4ae30475d881dc07831cb3129d153d5f7c9..3aaeffcfd67a6d9ae3b3e89514fed55c31e2ea4d 100644 (file)
@@ -842,23 +842,15 @@ do_sigbus(struct pt_regs *regs, unsigned long error_code, unsigned long address,
        force_sig_info_fault(SIGBUS, code, address, tsk, fault);
 }
 
-static noinline int
+static noinline void
 mm_fault_error(struct pt_regs *regs, unsigned long error_code,
               unsigned long address, unsigned int fault)
 {
-       /*
-        * Pagefault was interrupted by SIGKILL. We have no reason to
-        * continue pagefault.
-        */
-       if (fatal_signal_pending(current)) {
-               if (!(fault & VM_FAULT_RETRY))
-                       up_read(&current->mm->mmap_sem);
-               if (!(error_code & PF_USER))
-                       no_context(regs, error_code, address, 0, 0);
-               return 1;
+       if (fatal_signal_pending(current) && !(error_code & PF_USER)) {
+               up_read(&current->mm->mmap_sem);
+               no_context(regs, error_code, address, 0, 0);
+               return;
        }
-       if (!(fault & VM_FAULT_ERROR))
-               return 0;
 
        if (fault & VM_FAULT_OOM) {
                /* Kernel mode? Handle exceptions or die: */
@@ -866,7 +858,7 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
                        up_read(&current->mm->mmap_sem);
                        no_context(regs, error_code, address,
                                   SIGSEGV, SEGV_MAPERR);
-                       return 1;
+                       return;
                }
 
                up_read(&current->mm->mmap_sem);
@@ -884,7 +876,6 @@ mm_fault_error(struct pt_regs *regs, unsigned long error_code,
                else
                        BUG();
        }
-       return 1;
 }
 
 static int spurious_fault_check(unsigned long error_code, pte_t *pte)
@@ -1011,9 +1002,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
        unsigned long address;
        struct mm_struct *mm;
        int fault;
-       int write = error_code & PF_WRITE;
-       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
-                                       (write ? FAULT_FLAG_WRITE : 0);
+       unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;
 
        tsk = current;
        mm = tsk->mm;
@@ -1083,6 +1072,7 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
        if (user_mode_vm(regs)) {
                local_irq_enable();
                error_code |= PF_USER;
+               flags |= FAULT_FLAG_USER;
        } else {
                if (regs->flags & X86_EFLAGS_IF)
                        local_irq_enable();
@@ -1109,6 +1099,9 @@ __do_page_fault(struct pt_regs *regs, unsigned long error_code)
                return;
        }
 
+       if (error_code & PF_WRITE)
+               flags |= FAULT_FLAG_WRITE;
+
        /*
         * When running in the kernel we expect faults to occur only to
         * addresses in user space.  All other faults represent errors in
@@ -1187,9 +1180,17 @@ good_area:
         */
        fault = handle_mm_fault(mm, vma, address, flags);
 
-       if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) {
-               if (mm_fault_error(regs, error_code, address, fault))
-                       return;
+       /*
+        * If we need to retry but a fatal signal is pending, handle the
+        * signal first. We do not need to release the mmap_sem because it
+        * would already be released in __lock_page_or_retry in mm/filemap.c.
+        */
+       if (unlikely((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)))
+               return;
+
+       if (unlikely(fault & VM_FAULT_ERROR)) {
+               mm_fault_error(regs, error_code, address, fault);
+               return;
        }
 
        /*
index 7e73e8c690966dccbd8a7ef9f3d5397a367828f1..9d980d88b7477a82f757e75d0efda0c867c76d43 100644 (file)
@@ -59,6 +59,10 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address,
        return NULL;
 }
 
+int pmd_huge_support(void)
+{
+       return 0;
+}
 #else
 
 struct page *
@@ -77,6 +81,10 @@ int pud_huge(pud_t pud)
        return !!(pud_val(pud) & _PAGE_PSE);
 }
 
+int pmd_huge_support(void)
+{
+       return 1;
+}
 #endif
 
 /* x86_64 also uses this file */
index 282375f13c7edddf30cba2f57202790cc8cd60a4..ae699b3bbac84a920042349c1fc8605a8f93aba0 100644 (file)
@@ -103,6 +103,7 @@ static void flush_tlb_func(void *info)
        if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
                return;
 
+       count_vm_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
        if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {
                if (f->flush_end == TLB_FLUSH_ALL)
                        local_flush_tlb();
@@ -130,6 +131,7 @@ void native_flush_tlb_others(const struct cpumask *cpumask,
        info.flush_start = start;
        info.flush_end = end;
 
+       count_vm_event(NR_TLB_REMOTE_FLUSH);
        if (is_uv_system()) {
                unsigned int cpu;
 
@@ -149,6 +151,7 @@ void flush_tlb_current_task(void)
 
        preempt_disable();
 
+       count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
        local_flush_tlb();
        if (cpumask_any_but(mm_cpumask(mm), smp_processor_id()) < nr_cpu_ids)
                flush_tlb_others(mm_cpumask(mm), mm, 0UL, TLB_FLUSH_ALL);
@@ -211,16 +214,19 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,
        act_entries = mm->total_vm > tlb_entries ? tlb_entries : mm->total_vm;
 
        /* tlb_flushall_shift is on balance point, details in commit log */
-       if ((end - start) >> PAGE_SHIFT > act_entries >> tlb_flushall_shift)
+       if ((end - start) >> PAGE_SHIFT > act_entries >> tlb_flushall_shift) {
+               count_vm_event(NR_TLB_LOCAL_FLUSH_ALL);
                local_flush_tlb();
-       else {
+       else {
                if (has_large_page(mm, start, end)) {
                        local_flush_tlb();
                        goto flush_all;
                }
                /* flush range by one by one 'invlpg' */
-               for (addr = start; addr < end;  addr += PAGE_SIZE)
+               for (addr = start; addr < end;  addr += PAGE_SIZE) {
+                       count_vm_event(NR_TLB_LOCAL_FLUSH_ONE);
                        __flush_tlb_single(addr);
+               }
 
                if (cpumask_any_but(mm_cpumask(mm),
                                smp_processor_id()) < nr_cpu_ids)
@@ -256,6 +262,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start)
 
 static void do_flush_tlb_all(void *info)
 {
+       count_vm_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
        __flush_tlb_all();
        if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_LAZY)
                leave_mm(smp_processor_id());
@@ -263,6 +270,7 @@ static void do_flush_tlb_all(void *info)
 
 void flush_tlb_all(void)
 {
+       count_vm_event(NR_TLB_REMOTE_FLUSH);
        on_each_cpu(do_flush_tlb_all, NULL, 1);
 }
 
index 9d34eddb517fdca9f3495588d4d1d32e62ceecc1..96eb2bd288320b28e1ff6278bd0d410f1536ceab 100644 (file)
@@ -4,7 +4,7 @@
  */
 
 #include <sys/ptrace.h>
-#include <linux/ptrace.h>
+#include <asm/ptrace.h>
 
 int os_arch_prctl(int pid, int code, unsigned long *addr)
 {
index 2fc216dfbd9c6c8a08dd0a386a621cdb7d2c2b41..fa6ade76ef3fc084c5f4911e145979aebe10c5bb 100644 (file)
@@ -1692,7 +1692,6 @@ static int xen_hvm_cpu_notify(struct notifier_block *self, unsigned long action,
        case CPU_UP_PREPARE:
                xen_vcpu_setup(cpu);
                if (xen_have_vector_callback) {
-                       xen_init_lock_cpu(cpu);
                        if (xen_feature(XENFEAT_hvm_safe_pvclock))
                                xen_setup_timer(cpu);
                }
index 0d4ec35895d425c64567110f9d2285aaae3dc1b4..8b901e8d782dadf00091ac88a6fc859c54c4d1de 100644 (file)
@@ -990,10 +990,13 @@ int m2p_remove_override(struct page *page,
                                printk(KERN_WARNING "m2p_remove_override: "
                                                "pfn %lx mfn %lx, failed to modify kernel mappings",
                                                pfn, mfn);
+                               put_balloon_scratch_page();
                                return -1;
                        }
 
-                       mcs = xen_mc_entry(
+                       xen_mc_batch();
+
+                       mcs = __xen_mc_entry(
                                        sizeof(struct gnttab_unmap_and_replace));
                        unmap_op = mcs.args;
                        unmap_op->host_addr = kmap_op->host_addr;
@@ -1003,12 +1006,11 @@ int m2p_remove_override(struct page *page,
                        MULTI_grant_table_op(mcs.mc,
                                        GNTTABOP_unmap_and_replace, unmap_op, 1);
 
-                       xen_mc_issue(PARAVIRT_LAZY_MMU);
-
                        mcs = __xen_mc_entry(0);
                        MULTI_update_va_mapping(mcs.mc, scratch_page_address,
-                                       pfn_pte(page_to_pfn(get_balloon_scratch_page()),
+                                       pfn_pte(page_to_pfn(scratch_page),
                                        PAGE_KERNEL_RO), 0);
+
                        xen_mc_issue(PARAVIRT_LAZY_MMU);
 
                        kmap_op->host_addr = 0;
index 9235842cd76a14bf39ae61f9e1026754beee9f8a..d1e4777b4e75352fea33ca6a3e3d43a679e19c6d 100644 (file)
@@ -273,12 +273,20 @@ static void __init xen_smp_prepare_boot_cpu(void)
        BUG_ON(smp_processor_id() != 0);
        native_smp_prepare_boot_cpu();
 
-       /* We've switched to the "real" per-cpu gdt, so make sure the
-          old memory can be recycled */
-       make_lowmem_page_readwrite(xen_initial_gdt);
+       if (xen_pv_domain()) {
+               /* We've switched to the "real" per-cpu gdt, so make sure the
+                  old memory can be recycled */
+               make_lowmem_page_readwrite(xen_initial_gdt);
 
-       xen_filter_cpu_maps();
-       xen_setup_vcpu_info_placement();
+               xen_filter_cpu_maps();
+               xen_setup_vcpu_info_placement();
+       }
+       /*
+        * The alternative logic (which patches the unlock/lock) runs before
+        * the smp bootup up code is activated. Hence we need to set this up
+        * the core kernel is being patched. Otherwise we will have only
+        * modules patched but not core code.
+        */
        xen_init_spinlocks();
 }
 
@@ -709,6 +717,15 @@ static int xen_hvm_cpu_up(unsigned int cpu, struct task_struct *tidle)
        WARN_ON(rc);
        if (!rc)
                rc =  native_cpu_up(cpu, tidle);
+
+       /*
+        * We must initialize the slowpath CPU kicker _after_ the native
+        * path has executed. If we initialized it before none of the
+        * unlocker IPI kicks would reach the booting CPU as the booting
+        * CPU had not set itself 'online' in cpu_online_mask. That mask
+        * is checked when IPIs are sent (on HVM at least).
+        */
+       xen_init_lock_cpu(cpu);
        return rc;
 }
 
@@ -728,4 +745,5 @@ void __init xen_hvm_smp_init(void)
        smp_ops.cpu_die = xen_hvm_cpu_die;
        smp_ops.send_call_func_ipi = xen_smp_send_call_function_ipi;
        smp_ops.send_call_func_single_ipi = xen_smp_send_call_function_single_ipi;
+       smp_ops.smp_prepare_boot_cpu = xen_smp_prepare_boot_cpu;
 }
index 0438b9324a72175cad44f55eb44f841e5b268322..253f63fceea104978c6e5d1f54ba81e1e3581b20 100644 (file)
@@ -81,7 +81,6 @@ static inline void spin_time_accum_blocked(u64 start)
        spinlock_stats.time_blocked += delta;
 }
 #else  /* !CONFIG_XEN_DEBUG_FS */
-#define TIMEOUT                        (1 << 10)
 static inline void add_stats(enum xen_contention_stat var, u32 val)
 {
 }
@@ -96,23 +95,6 @@ static inline void spin_time_accum_blocked(u64 start)
 }
 #endif  /* CONFIG_XEN_DEBUG_FS */
 
-/*
- * Size struct xen_spinlock so it's the same as arch_spinlock_t.
- */
-#if NR_CPUS < 256
-typedef u8 xen_spinners_t;
-# define inc_spinners(xl) \
-       asm(LOCK_PREFIX " incb %0" : "+m" ((xl)->spinners) : : "memory");
-# define dec_spinners(xl) \
-       asm(LOCK_PREFIX " decb %0" : "+m" ((xl)->spinners) : : "memory");
-#else
-typedef u16 xen_spinners_t;
-# define inc_spinners(xl) \
-       asm(LOCK_PREFIX " incw %0" : "+m" ((xl)->spinners) : : "memory");
-# define dec_spinners(xl) \
-       asm(LOCK_PREFIX " decw %0" : "+m" ((xl)->spinners) : : "memory");
-#endif
-
 struct xen_lock_waiting {
        struct arch_spinlock *lock;
        __ticket_t want;
@@ -123,6 +105,7 @@ static DEFINE_PER_CPU(char *, irq_name);
 static DEFINE_PER_CPU(struct xen_lock_waiting, lock_waiting);
 static cpumask_t waiting_cpus;
 
+static bool xen_pvspin = true;
 static void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
 {
        int irq = __this_cpu_read(lock_kicker_irq);
@@ -241,16 +224,12 @@ void xen_init_lock_cpu(int cpu)
        int irq;
        char *name;
 
+       if (!xen_pvspin)
+               return;
+
        WARN(per_cpu(lock_kicker_irq, cpu) >= 0, "spinlock on CPU%d exists on IRQ%d!\n",
             cpu, per_cpu(lock_kicker_irq, cpu));
 
-       /*
-        * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
-        * (xen: disable PV spinlocks on HVM)
-        */
-       if (xen_hvm_domain())
-               return;
-
        name = kasprintf(GFP_KERNEL, "spinlock%d", cpu);
        irq = bind_ipi_to_irqhandler(XEN_SPIN_UNLOCK_VECTOR,
                                     cpu,
@@ -270,11 +249,7 @@ void xen_init_lock_cpu(int cpu)
 
 void xen_uninit_lock_cpu(int cpu)
 {
-       /*
-        * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
-        * (xen: disable PV spinlocks on HVM)
-        */
-       if (xen_hvm_domain())
+       if (!xen_pvspin)
                return;
 
        unbind_from_irqhandler(per_cpu(lock_kicker_irq, cpu), NULL);
@@ -283,16 +258,9 @@ void xen_uninit_lock_cpu(int cpu)
        per_cpu(irq_name, cpu) = NULL;
 }
 
-static bool xen_pvspin __initdata = true;
 
 void __init xen_init_spinlocks(void)
 {
-       /*
-        * See git commit f10cd522c5fbfec9ae3cc01967868c9c2401ed23
-        * (xen: disable PV spinlocks on HVM)
-        */
-       if (xen_hvm_domain())
-               return;
 
        if (!xen_pvspin) {
                printk(KERN_DEBUG "xen: PV spinlocks disabled\n");
@@ -323,6 +291,9 @@ static int __init xen_spinlock_debugfs(void)
        if (d_xen == NULL)
                return -ENOMEM;
 
+       if (!xen_pvspin)
+               return 0;
+
        d_spin_debug = debugfs_create_dir("spinlocks", d_xen);
 
        debugfs_create_u8("zero_stats", 0644, d_spin_debug, &zero_stats);
index 7ea6451a3a33207508660141670cafeb309c309e..8d24dcb7cdac6df122e6779080b5e31b234a6ee5 100644 (file)
@@ -7,7 +7,6 @@ config XTENSA
        select HAVE_IDE
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
-       select HAVE_GENERIC_HARDIRQS
        select VIRT_TO_BUS
        select GENERIC_IRQ_SHOW
        select GENERIC_CPU_DEVICES
index 136224b74d4f0e99f9970fd011916cf1133499ba..81250ece3062ae914628d8b49f777ac7de580263 100644 (file)
@@ -55,10 +55,10 @@ ifneq ($(CONFIG_LD_NO_RELAX),)
 LDFLAGS := --no-relax
 endif
 
-ifeq ($(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1)
+ifeq ($(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#"),1)
 CHECKFLAGS += -D__XTENSA_EB__
 endif
-ifeq ($(shell echo -e __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1)
+ifeq ($(shell echo __XTENSA_EL__ | $(CC) -E - | grep -v "\#"),1)
 CHECKFLAGS += -D__XTENSA_EL__
 endif
 
index 64ffc4b53df6468484379f302f96bc194e292361..ca20a892021bb6dae74b2ba02e5278efe9cb798d 100644 (file)
@@ -12,7 +12,7 @@
 KBUILD_CFLAGS  += -fno-builtin -Iarch/$(ARCH)/boot/include
 HOSTFLAGS      += -Iarch/$(ARCH)/boot/include
 
-BIG_ENDIAN     := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
+BIG_ENDIAN     := $(shell echo __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
 
 export ccflags-y
 export BIG_ENDIAN
index a182a4e6d688085ed9f108642d763fe987110800..f6000fe05119a1a9ad5f79cff94c4516b106809d 100644 (file)
@@ -8,7 +8,6 @@ CONFIG_XTENSA=y
 # CONFIG_UID16 is not set
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_HAVE_DEC_LOCK=y
-CONFIG_GENERIC_HARDIRQS=y
 
 #
 # Code maturity level options
index 77c52f80187a220cc1b6982d235d0055a779f208..4f233204faf99b751682308c22dab254f6798fa7 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_XTENSA=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_HARDIRQS=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_NO_IOPORT=y
index 4799c6a526b582658af0ebf34ffc08132b42dacf..d929f77a0360629e599079048eab6061fa1ac5e8 100644 (file)
@@ -9,7 +9,6 @@ CONFIG_XTENSA=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_HARDIRQS=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_NO_IOPORT=y
index b24de67170202548122605b1603147bd6aaf2f54..4ba9f516b0e27b934e174592b8ad0653c7af62ac 100644 (file)
@@ -82,6 +82,7 @@
 #define PS_CALLINC_SHIFT       16
 #define PS_CALLINC_MASK                0x00030000
 #define PS_OWB_SHIFT           8
+#define PS_OWB_WIDTH           4
 #define PS_OWB_MASK            0x00000F00
 #define PS_RING_SHIFT          6
 #define PS_RING_MASK           0x000000C0
index 69f901713fb6fd754301d35372eaf2f54a543c7f..27fa3c1706623805168f6914f952d777993edbf2 100644 (file)
 # error "Bad timer number for Linux configurations!"
 #endif
 
-#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 extern unsigned long ccount_freq;
-#define CCOUNT_PER_JIFFY (ccount_freq / HZ)
-#else
-#define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ))
-#endif
-
 
 typedef unsigned long long cycles_t;
 
index aa2e87b8566a7dbabb7c0227ea6a8f489674ab05..d4cef6039a5c1ab785d4dead614ad7c9f92d0d6d 100644 (file)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -171,7 +171,6 @@ ENTRY(fast_unaligned)
        s32i    a8, a2, PT_AREG8
 
        rsr     a0, depc
-       xsr     a3, excsave1
        s32i    a0, a2, PT_AREG2
        s32i    a3, a2, PT_AREG3
 
index 647657484866dde30f8dd92217c3cb719fc31bea..a482df5df2b2c54c536f03fccebe9464e93603ff 100644 (file)
@@ -32,9 +32,9 @@
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -225,9 +225,9 @@ ENDPROC(coprocessor_restore)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -245,7 +245,6 @@ ENTRY(fast_coprocessor)
 
        /* Save remaining registers a1-a3 and SAR */
 
-       xsr     a3, excsave1
        s32i    a3, a2, PT_AREG3
        rsr     a3, sar
        s32i    a1, a2, PT_AREG1
index 9298742f0fd0a01f9df2af3af0c689d9248c9545..de1dfa18d0a11953c037af6c276603c20b1e346f 100644 (file)
@@ -31,8 +31,6 @@
 /* Unimplemented features. */
 
 #undef KERNEL_STACK_OVERFLOW_CHECK
-#undef PREEMPTIBLE_KERNEL
-#undef ALLOCA_EXCEPTION_IN_IRAM
 
 /* Not well tested.
  *
@@ -92,9 +90,9 @@
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original value in depc
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave1: a3
+ *   excsave1: dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
 
 ENTRY(user_exception)
 
-       /* Save a2, a3, and depc, restore excsave_1 and set SP. */
+       /* Save a1, a2, a3, and set SP. */
 
-       xsr     a3, excsave1
        rsr     a0, depc
        s32i    a1, a2, PT_AREG1
        s32i    a0, a2, PT_AREG2
@@ -238,9 +235,9 @@ ENDPROC(user_exception)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -256,9 +253,8 @@ ENDPROC(user_exception)
 
 ENTRY(kernel_exception)
 
-       /* Save a0, a2, a3, DEPC and set SP. */
+       /* Save a1, a2, a3, and set SP. */
 
-       xsr     a3, excsave1            # restore a3, excsave_1
        rsr     a0, depc                # get a2
        s32i    a1, a2, PT_AREG1
        s32i    a0, a2, PT_AREG2
@@ -409,7 +405,7 @@ common_exception:
         * exception handler and call the exception handler.
         */
 
-       movi    a4, exc_table
+       rsr     a4, excsave1
        mov     a6, a1                  # pass stack frame
        mov     a7, a0                  # pass EXCCAUSE
        addx4   a4, a0, a4
@@ -423,28 +419,15 @@ common_exception:
        .global common_exception_return
 common_exception_return:
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-       l32i    a4, a1, PT_DEPC
-       /* Double exception means we came here with an exception
-        * while PS.EXCM was set, i.e. interrupts disabled.
-        */
-       bgeui   a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
-       l32i    a4, a1, PT_EXCCAUSE
-       bnei    a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f
-       /* We came here with an interrupt means interrupts were enabled
-        * and we'll reenable them on return.
-        */
-       movi    a4, trace_hardirqs_on
-       callx4  a4
 1:
-#endif
+       rsil    a2, LOCKLEVEL
 
        /* Jump if we are returning from kernel exceptions. */
 
-1:     l32i    a3, a1, PT_PS
-       _bbci.l a3, PS_UM_BIT, 4f
-
-       rsil    a2, 0
+       l32i    a3, a1, PT_PS
+       GET_THREAD_INFO(a2, a1)
+       l32i    a4, a2, TI_FLAGS
+       _bbci.l a3, PS_UM_BIT, 6f
 
        /* Specific to a user exception exit:
         * We need to check some flags for signal handling and rescheduling,
@@ -453,9 +436,6 @@ common_exception_return:
         * Note that we don't disable interrupts here. 
         */
 
-       GET_THREAD_INFO(a2,a1)
-       l32i    a4, a2, TI_FLAGS
-
        _bbsi.l a4, TIF_NEED_RESCHED, 3f
        _bbsi.l a4, TIF_NOTIFY_RESUME, 2f
        _bbci.l a4, TIF_SIGPENDING, 5f
@@ -465,6 +445,7 @@ common_exception_return:
 
        /* Call do_signal() */
 
+       rsil    a2, 0
        movi    a4, do_notify_resume    # int do_notify_resume(struct pt_regs*)
        mov     a6, a1
        callx4  a4
@@ -472,10 +453,24 @@ common_exception_return:
 
 3:     /* Reschedule */
 
+       rsil    a2, 0
        movi    a4, schedule    # void schedule (void)
        callx4  a4
        j       1b
 
+#ifdef CONFIG_PREEMPT
+6:
+       _bbci.l a4, TIF_NEED_RESCHED, 4f
+
+       /* Check current_thread_info->preempt_count */
+
+       l32i    a4, a2, TI_PRE_COUNT
+       bnez    a4, 4f
+       movi    a4, preempt_schedule_irq
+       callx4  a4
+       j       1b
+#endif
+
 5:
 #ifdef CONFIG_DEBUG_TLB_SANITY
        l32i    a4, a1, PT_DEPC
@@ -483,7 +478,24 @@ common_exception_return:
        movi    a4, check_tlb_sanity
        callx4  a4
 #endif
-4:     /* Restore optional registers. */
+6:
+4:
+#ifdef CONFIG_TRACE_IRQFLAGS
+       l32i    a4, a1, PT_DEPC
+       /* Double exception means we came here with an exception
+        * while PS.EXCM was set, i.e. interrupts disabled.
+        */
+       bgeui   a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+       l32i    a4, a1, PT_EXCCAUSE
+       bnei    a4, EXCCAUSE_LEVEL1_INTERRUPT, 1f
+       /* We came here with an interrupt means interrupts were enabled
+        * and we'll reenable them on return.
+        */
+       movi    a4, trace_hardirqs_on
+       callx4  a4
+1:
+#endif
+       /* Restore optional registers. */
 
        load_xtregs_opt a1 a2 a4 a5 a6 a7 PT_XTREGS_OPT
 
@@ -570,29 +582,6 @@ user_exception_exit:
 
 kernel_exception_exit:
 
-#ifdef PREEMPTIBLE_KERNEL
-
-#ifdef CONFIG_PREEMPT
-
-       /*
-        * Note: We've just returned from a call4, so we have
-        * at least 4 addt'l regs.
-        */
-
-       /* Check current_thread_info->preempt_count */
-
-       GET_THREAD_INFO(a2)
-       l32i    a3, a2, TI_PREEMPT
-       bnez    a3, 1f
-
-       l32i    a2, a2, TI_FLAGS
-
-1:
-
-#endif
-
-#endif
-
        /* Check if we have to do a movsp.
         *
         * We only have to do a movsp if the previous window-frame has
@@ -829,176 +818,63 @@ ENDPROC(unrecoverable_exception)
  *
  *  The ALLOCA handler is entered when user code executes the MOVSP
  *  instruction and the caller's frame is not in the register file.
- *  In this case, the caller frame's a0..a3 are on the stack just
- *  below sp (a1), and this handler moves them.
  *
- *  For "MOVSP <ar>,<as>" without destination register a1, this routine
- *  simply moves the value from <as> to <ar> without moving the save area.
+ * This algorithm was taken from the Ross Morley's RTOS Porting Layer:
+ *
+ *    /home/ross/rtos/porting/XtensaRTOS-PortingLayer-20090507/xtensa_vectors.S
+ *
+ * It leverages the existing window spill/fill routines and their support for
+ * double exceptions. The 'movsp' instruction will only cause an exception if
+ * the next window needs to be loaded. In fact this ALLOCA exception may be
+ * replaced at some point by changing the hardware to do a underflow exception
+ * of the proper size instead.
+ *
+ * This algorithm simply backs out the register changes started by the user
+ * excpetion handler, makes it appear that we have started a window underflow
+ * by rotating the window back and then setting the old window base (OWB) in
+ * the 'ps' register with the rolled back window base. The 'movsp' instruction
+ * will be re-executed and this time since the next window frames is in the
+ * active AR registers it won't cause an exception.
+ *
+ * If the WindowUnderflow code gets a TLB miss the page will get mapped
+ * the the partial windeowUnderflow will be handeled in the double exception
+ * handler.
  *
  * Entry condition:
  *
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
  */
 
-#if XCHAL_HAVE_BE
-#define _EXTUI_MOVSP_SRC(ar)   extui ar, ar, 4, 4
-#define _EXTUI_MOVSP_DST(ar)   extui ar, ar, 0, 4
-#else
-#define _EXTUI_MOVSP_SRC(ar)   extui ar, ar, 0, 4
-#define _EXTUI_MOVSP_DST(ar)   extui ar, ar, 4, 4
-#endif
-
 ENTRY(fast_alloca)
+       rsr     a0, windowbase
+       rotw    -1
+       rsr     a2, ps
+       extui   a3, a2, PS_OWB_SHIFT, PS_OWB_WIDTH
+       xor     a3, a3, a4
+       l32i    a4, a6, PT_AREG0
+       l32i    a1, a6, PT_DEPC
+       rsr     a6, depc
+       wsr     a1, depc
+       slli    a3, a3, PS_OWB_SHIFT
+       xor     a2, a2, a3
+       wsr     a2, ps
+       rsync
 
-       /* We shouldn't be in a double exception. */
-
-       l32i    a0, a2, PT_DEPC
-       _bgeui  a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double
-
-       rsr     a0, depc                # get a2
-       s32i    a4, a2, PT_AREG4        # save a4 and
-       s32i    a0, a2, PT_AREG2        # a2 to stack
-
-       /* Exit critical section. */
-
-       movi    a0, 0
-       s32i    a0, a3, EXC_TABLE_FIXUP
-
-       /* Restore a3, excsave_1 */
-
-       xsr     a3, excsave1            # make sure excsave_1 is valid for dbl.
-       rsr     a4, epc1                # get exception address
-       s32i    a3, a2, PT_AREG3        # save a3 to stack
-
-#ifdef ALLOCA_EXCEPTION_IN_IRAM
-#error iram not supported
-#else
-       /* Note: l8ui not allowed in IRAM/IROM!! */
-       l8ui    a0, a4, 1               # read as(src) from MOVSP instruction
-#endif
-       movi    a3, .Lmovsp_src
-       _EXTUI_MOVSP_SRC(a0)            # extract source register number
-       addx8   a3, a0, a3
-       jx      a3
-
-.Lunhandled_double:
-       wsr     a0, excsave1
-       movi    a0, unrecoverable_exception
-       callx0  a0
-
-       .align 8
-.Lmovsp_src:
-       l32i    a3, a2, PT_AREG0;       _j 1f;  .align 8
-       mov     a3, a1;                 _j 1f;  .align 8
-       l32i    a3, a2, PT_AREG2;       _j 1f;  .align 8
-       l32i    a3, a2, PT_AREG3;       _j 1f;  .align 8
-       l32i    a3, a2, PT_AREG4;       _j 1f;  .align 8
-       mov     a3, a5;                 _j 1f;  .align 8
-       mov     a3, a6;                 _j 1f;  .align 8
-       mov     a3, a7;                 _j 1f;  .align 8
-       mov     a3, a8;                 _j 1f;  .align 8
-       mov     a3, a9;                 _j 1f;  .align 8
-       mov     a3, a10;                _j 1f;  .align 8
-       mov     a3, a11;                _j 1f;  .align 8
-       mov     a3, a12;                _j 1f;  .align 8
-       mov     a3, a13;                _j 1f;  .align 8
-       mov     a3, a14;                _j 1f;  .align 8
-       mov     a3, a15;                _j 1f;  .align 8
-
-1:
-
-#ifdef ALLOCA_EXCEPTION_IN_IRAM
-#error iram not supported
-#else
-       l8ui    a0, a4, 0               # read ar(dst) from MOVSP instruction
-#endif
-       addi    a4, a4, 3               # step over movsp
-       _EXTUI_MOVSP_DST(a0)            # extract destination register
-       wsr     a4, epc1                # save new epc_1
-
-       _bnei   a0, 1, 1f               # no 'movsp a1, ax': jump
-
-       /* Move the save area. This implies the use of the L32E
-        * and S32E instructions, because this move must be done with
-        * the user's PS.RING privilege levels, not with ring 0
-        * (kernel's) privileges currently active with PS.EXCM
-        * set. Note that we have stil registered a fixup routine with the
-        * double exception vector in case a double exception occurs.
-        */
-
-       /* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */
-
-       l32e    a0, a1, -16
-       l32e    a4, a1, -12
-       s32e    a0, a3, -16
-       s32e    a4, a3, -12
-       l32e    a0, a1, -8
-       l32e    a4, a1, -4
-       s32e    a0, a3, -8
-       s32e    a4, a3, -4
-
-       /* Restore stack-pointer and all the other saved registers. */
-
-       mov     a1, a3
-
-       l32i    a4, a2, PT_AREG4
-       l32i    a3, a2, PT_AREG3
-       l32i    a0, a2, PT_AREG0
-       l32i    a2, a2, PT_AREG2
-       rfe
-
-       /*  MOVSP <at>,<as>  was invoked with <at> != a1.
-        *  Because the stack pointer is not being modified,
-        *  we should be able to just modify the pointer
-        *  without moving any save area.
-        *  The processor only traps these occurrences if the
-        *  caller window isn't live, so unfortunately we can't
-        *  use this as an alternate trap mechanism.
-        *  So we just do the move.  This requires that we
-        *  resolve the destination register, not just the source,
-        *  so there's some extra work.
-        *  (PERHAPS NOT REALLY NEEDED, BUT CLEANER...)
-        */
-
-       /* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */
-
-1:     movi    a4, .Lmovsp_dst
-       addx8   a4, a0, a4
-       jx      a4
-
-       .align 8
-.Lmovsp_dst:
-       s32i    a3, a2, PT_AREG0;       _j 1f;  .align 8
-       mov     a1, a3;                 _j 1f;  .align 8
-       s32i    a3, a2, PT_AREG2;       _j 1f;  .align 8
-       s32i    a3, a2, PT_AREG3;       _j 1f;  .align 8
-       s32i    a3, a2, PT_AREG4;       _j 1f;  .align 8
-       mov     a5, a3;                 _j 1f;  .align 8
-       mov     a6, a3;                 _j 1f;  .align 8
-       mov     a7, a3;                 _j 1f;  .align 8
-       mov     a8, a3;                 _j 1f;  .align 8
-       mov     a9, a3;                 _j 1f;  .align 8
-       mov     a10, a3;                _j 1f;  .align 8
-       mov     a11, a3;                _j 1f;  .align 8
-       mov     a12, a3;                _j 1f;  .align 8
-       mov     a13, a3;                _j 1f;  .align 8
-       mov     a14, a3;                _j 1f;  .align 8
-       mov     a15, a3;                _j 1f;  .align 8
-
-1:     l32i    a4, a2, PT_AREG4
-       l32i    a3, a2, PT_AREG3
-       l32i    a0, a2, PT_AREG0
-       l32i    a2, a2, PT_AREG2
-       rfe
-
+       _bbci.l a4, 31, 4f
+       rotw    -1
+       _bbci.l a8, 30, 8f
+       rotw    -1
+       j       _WindowUnderflow12
+8:     j       _WindowUnderflow8
+4:     j       _WindowUnderflow4
 ENDPROC(fast_alloca)
 
 /*
@@ -1015,9 +891,9 @@ ENDPROC(fast_alloca)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  */
 
 ENTRY(fast_syscall_kernel)
@@ -1064,7 +940,6 @@ ENTRY(fast_syscall_unrecoverable)
 
        l32i    a0, a2, PT_AREG0        # restore a0
        xsr     a2, depc                # restore a2, depc
-       rsr     a3, excsave1
 
        wsr     a0, excsave1
        movi    a0, unrecoverable_exception
@@ -1086,10 +961,10 @@ ENDPROC(fast_syscall_unrecoverable)
  *   a0:       a2 (syscall-nr), original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in a0 and DEPC
- *   a3:       dispatch table, original in excsave_1
+ *   a3:       a3
  *   a4..a15:  unchanged
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1122,8 +997,6 @@ ENDPROC(fast_syscall_unrecoverable)
 
 ENTRY(fast_syscall_xtensa)
 
-       xsr     a3, excsave1            # restore a3, excsave1
-
        s32i    a7, a2, PT_AREG7        # we need an additional register
        movi    a7, 4                   # sizeof(unsigned int)
        access_ok a3, a7, a0, a2, .Leac # a0: scratch reg, a2: sp
@@ -1186,9 +1059,9 @@ ENDPROC(fast_syscall_xtensa)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
  */
@@ -1197,15 +1070,16 @@ ENTRY(fast_syscall_spill_registers)
 
        /* Register a FIXUP handler (pass current wb as a parameter) */
 
+       xsr     a3, excsave1
        movi    a0, fast_syscall_spill_registers_fixup
        s32i    a0, a3, EXC_TABLE_FIXUP
        rsr     a0, windowbase
        s32i    a0, a3, EXC_TABLE_PARAM
+       xsr     a3, excsave1            # restore a3 and excsave_1
 
-       /* Save a3 and SAR on stack. */
+       /* Save a3, a4 and SAR on stack. */
 
        rsr     a0, sar
-       xsr     a3, excsave1            # restore a3 and excsave_1
        s32i    a3, a2, PT_AREG3
        s32i    a4, a2, PT_AREG4
        s32i    a0, a2, PT_AREG5        # store SAR to PT_AREG5
@@ -1259,14 +1133,14 @@ fast_syscall_spill_registers_fixup:
         * in WS, so that the exception handlers save them to the task stack.
         */
 
-       rsr     a3, excsave1    # get spill-mask
+       xsr     a3, excsave1    # get spill-mask
        slli    a2, a3, 1       # shift left by one
 
        slli    a3, a2, 32-WSBITS
        src     a2, a2, a3      # a1 = xxwww1yyxxxwww1yy......
        wsr     a2, windowstart # set corrected windowstart
 
-       movi    a3, exc_table
+       rsr     a3, excsave1
        l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # restore a2
        l32i    a3, a3, EXC_TABLE_PARAM # original WB (in user task)
 
@@ -1303,7 +1177,7 @@ fast_syscall_spill_registers_fixup:
 
        /* Jump to the exception handler. */
 
-       movi    a3, exc_table
+       rsr     a3, excsave1
        rsr     a0, exccause
        addx4   a0, a0, a3                      # find entry in table
        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
@@ -1320,6 +1194,7 @@ fast_syscall_spill_registers_fixup_return:
        xsr     a3, excsave1
        movi    a2, fast_syscall_spill_registers_fixup
        s32i    a2, a3, EXC_TABLE_FIXUP
+       s32i    a0, a3, EXC_TABLE_DOUBLE_SAVE
        rsr     a2, windowbase
        s32i    a2, a3, EXC_TABLE_PARAM
        l32i    a2, a3, EXC_TABLE_KSTK
@@ -1331,11 +1206,6 @@ fast_syscall_spill_registers_fixup_return:
        wsr     a3, windowbase
        rsync
 
-       /* Restore a3 and return. */
-
-       movi    a3, exc_table
-       xsr     a3, excsave1
-
        rfde
 
 
@@ -1522,9 +1392,8 @@ ENTRY(_spill_registers)
 
        movi    a0, 0
 
-       movi    a3, exc_table
+       rsr     a3, excsave1
        l32i    a1, a3, EXC_TABLE_KSTK
-       wsr     a3, excsave1
 
        movi    a4, (1 << PS_WOE_BIT) | LOCKLEVEL
        wsr     a4, ps
@@ -1568,9 +1437,9 @@ ENDPROC(fast_second_level_miss_double_kernel)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1578,9 +1447,10 @@ ENDPROC(fast_second_level_miss_double_kernel)
 
 ENTRY(fast_second_level_miss)
 
-       /* Save a1. Note: we don't expect a double exception. */
+       /* Save a1 and a3. Note: we don't expect a double exception. */
 
        s32i    a1, a2, PT_AREG1
+       s32i    a3, a2, PT_AREG3
 
        /* We need to map the page of PTEs for the user task.  Find
         * the pointer to that page.  Also, it's possible for tsk->mm
@@ -1602,9 +1472,6 @@ ENTRY(fast_second_level_miss)
        l32i    a0, a1, TASK_MM         # tsk->mm
        beqz    a0, 9f
 
-
-       /* We deliberately destroy a3 that holds the exception table. */
-
 8:     rsr     a3, excvaddr            # fault address
        _PGD_OFFSET(a0, a3, a1)
        l32i    a0, a0, 0               # read pmdval
@@ -1655,7 +1522,7 @@ ENTRY(fast_second_level_miss)
 
        /* Exit critical section. */
 
-4:     movi    a3, exc_table           # restore a3
+4:     rsr     a3, excsave1
        movi    a0, 0
        s32i    a0, a3, EXC_TABLE_FIXUP
 
@@ -1663,8 +1530,8 @@ ENTRY(fast_second_level_miss)
 
        l32i    a0, a2, PT_AREG0
        l32i    a1, a2, PT_AREG1
+       l32i    a3, a2, PT_AREG3
        l32i    a2, a2, PT_DEPC
-       xsr     a3, excsave1
 
        bgeui   a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
 
@@ -1751,11 +1618,8 @@ ENTRY(fast_second_level_miss)
 
 2:     /* Invalid PGD, default exception handling */
 
-       movi    a3, exc_table
        rsr     a1, depc
-       xsr     a3, excsave1
        s32i    a1, a2, PT_AREG2
-       s32i    a3, a2, PT_AREG3
        mov     a1, a2
 
        rsr     a2, ps
@@ -1775,9 +1639,9 @@ ENDPROC(fast_second_level_miss)
  *   a0:       trashed, original value saved on stack (PT_AREG0)
  *   a1:       a1
  *   a2:       new stack pointer, original in DEPC
- *   a3:       dispatch table
+ *   a3:       a3
  *   depc:     a2, original value saved on stack (PT_DEPC)
- *   excsave_1:        a3
+ *   excsave_1:        dispatch table
  *
  *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
  *          <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
@@ -1785,17 +1649,17 @@ ENDPROC(fast_second_level_miss)
 
 ENTRY(fast_store_prohibited)
 
-       /* Save a1 and a4. */
+       /* Save a1 and a3. */
 
        s32i    a1, a2, PT_AREG1
-       s32i    a4, a2, PT_AREG4
+       s32i    a3, a2, PT_AREG3
 
        GET_CURRENT(a1,a2)
        l32i    a0, a1, TASK_MM         # tsk->mm
        beqz    a0, 9f
 
 8:     rsr     a1, excvaddr            # fault address
-       _PGD_OFFSET(a0, a1, a4)
+       _PGD_OFFSET(a0, a1, a3)
        l32i    a0, a0, 0
        beqz    a0, 2f
 
@@ -1804,39 +1668,37 @@ ENTRY(fast_store_prohibited)
         * and is not PAGE_NONE. See pgtable.h for possible PTE layouts.
         */
 
-       _PTE_OFFSET(a0, a1, a4)
-       l32i    a4, a0, 0               # read pteval
+       _PTE_OFFSET(a0, a1, a3)
+       l32i    a3, a0, 0               # read pteval
        movi    a1, _PAGE_CA_INVALID
-       ball    a4, a1, 2f
-       bbci.l  a4, _PAGE_WRITABLE_BIT, 2f
+       ball    a3, a1, 2f
+       bbci.l  a3, _PAGE_WRITABLE_BIT, 2f
 
        movi    a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
-       or      a4, a4, a1
+       or      a3, a3, a1
        rsr     a1, excvaddr
-       s32i    a4, a0, 0
+       s32i    a3, a0, 0
 
        /* We need to flush the cache if we have page coloring. */
 #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
        dhwb    a0, 0
 #endif
        pdtlb   a0, a1
-       wdtlb   a4, a0
+       wdtlb   a3, a0
 
        /* Exit critical section. */
 
        movi    a0, 0
+       rsr     a3, excsave1
        s32i    a0, a3, EXC_TABLE_FIXUP
 
        /* Restore the working registers, and return. */
 
-       l32i    a4, a2, PT_AREG4
+       l32i    a3, a2, PT_AREG3
        l32i    a1, a2, PT_AREG1
        l32i    a0, a2, PT_AREG0
        l32i    a2, a2, PT_DEPC
 
-       /* Restore excsave1 and a3. */
-
-       xsr     a3, excsave1
        bgeui   a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
 
        rsr     a2, depc
@@ -1853,11 +1715,8 @@ ENTRY(fast_store_prohibited)
 
 2:     /* If there was a problem, handle fault in C */
 
-       rsr     a4, depc        # still holds a2
-       xsr     a3, excsave1
-       s32i    a4, a2, PT_AREG2
-       s32i    a3, a2, PT_AREG3
-       l32i    a4, a2, PT_AREG4
+       rsr     a3, depc        # still holds a2
+       s32i    a3, a2, PT_AREG2
        mov     a1, a2
 
        rsr     a2, ps
index 42a8bba0b0ead4235add5133b7e849187641da53..946fb8d06c8b48479b021a0f2da7be06961a2d71 100644 (file)
@@ -170,8 +170,7 @@ static int __init parse_tag_fdt(const bp_tag_t *tag)
 
 __tagtable(BP_TAG_FDT, parse_tag_fdt);
 
-void __init early_init_dt_setup_initrd_arch(unsigned long start,
-               unsigned long end)
+void __init early_init_dt_setup_initrd_arch(u64 start, u64 end)
 {
        initrd_start = (void *)__va(start);
        initrd_end = (void *)__va(end);
@@ -585,8 +584,8 @@ c_show(struct seq_file *f, void *slot)
                     "bogomips\t: %lu.%02lu\n",
                     XCHAL_BUILD_UNIQUE_ID,
                     XCHAL_HAVE_BE ?  "big" : "little",
-                    CCOUNT_PER_JIFFY/(1000000/HZ),
-                    (CCOUNT_PER_JIFFY/(10000/HZ)) % 100,
+                    ccount_freq/1000000,
+                    (ccount_freq/10000) % 100,
                     loops_per_jiffy/(500000/HZ),
                     (loops_per_jiffy/(5000/HZ)) % 100);
 
index 24bb0c1776ba860fb03a72b94e0107ac8bcfe1f1..9af3dd88ad7eac172e4fb835e94c70e369547438 100644 (file)
@@ -29,9 +29,7 @@
 #include <asm/timex.h>
 #include <asm/platform.h>
 
-#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
 unsigned long ccount_freq;             /* ccount Hz */
-#endif
 
 static cycle_t ccount_read(struct clocksource *cs)
 {
@@ -129,8 +127,10 @@ void __init time_init(void)
        platform_calibrate_ccount();
        printk("%d.%02d MHz\n", (int)ccount_freq/1000000,
                        (int)(ccount_freq/10000)%100);
+#else
+       ccount_freq = CONFIG_XTENSA_CPU_CLOCK*1000000UL;
 #endif
-       clocksource_register_hz(&ccount_clocksource, CCOUNT_PER_JIFFY * HZ);
+       clocksource_register_hz(&ccount_clocksource, ccount_freq);
 
        ccount_timer.evt.cpumask = cpumask_of(0);
        ccount_timer.evt.irq = irq_create_mapping(NULL, LINUX_TIMER_INT);
@@ -164,7 +164,7 @@ irqreturn_t timer_interrupt (int irq, void *dev_id)
 #ifndef CONFIG_GENERIC_CALIBRATE_DELAY
 void calibrate_delay(void)
 {
-       loops_per_jiffy = CCOUNT_PER_JIFFY;
+       loops_per_jiffy = ccount_freq / HZ;
        printk("Calibrating delay loop (skipped)... "
               "%lu.%02lu BogoMIPS preset\n",
               loops_per_jiffy/(1000000/HZ),
index f9e175382aa9b7dbe930992cbdbe58842a2f0d68..cb8fd44caabc6d246ce7975dfc0f370d87052fc2 100644 (file)
@@ -78,6 +78,7 @@ ENTRY(_UserExceptionVector)
        s32i    a0, a2, PT_DEPC         # mark it as a regular exception
        addx4   a0, a0, a3              # find entry in table
        l32i    a0, a0, EXC_TABLE_FAST_USER     # load handler
+       xsr     a3, excsave1            # restore a3 and dispatch table
        jx      a0
 
 ENDPROC(_UserExceptionVector)
@@ -104,6 +105,7 @@ ENTRY(_KernelExceptionVector)
        s32i    a0, a2, PT_DEPC         # mark it as a regular exception
        addx4   a0, a0, a3              # find entry in table
        l32i    a0, a0, EXC_TABLE_FAST_KERNEL   # load handler address
+       xsr     a3, excsave1            # restore a3 and dispatch table
        jx      a0
 
 ENDPROC(_KernelExceptionVector)
@@ -168,7 +170,7 @@ ENDPROC(_KernelExceptionVector)
  *
  *     a0:        DEPC
  *     a1:        a1
- *     a2:        trashed, original value in EXC_TABLE_DOUBLE_A2
+ *     a2:        trashed, original value in EXC_TABLE_DOUBLE_SAVE
  *     a3:        exctable
  *     depc:      a0
  *     excsave_1: a3
@@ -204,47 +206,46 @@ ENDPROC(_KernelExceptionVector)
 
        .section .DoubleExceptionVector.text, "ax"
        .begin literal_prefix .DoubleExceptionVector
+       .globl _DoubleExceptionVector_WindowUnderflow
+       .globl _DoubleExceptionVector_WindowOverflow
 
 ENTRY(_DoubleExceptionVector)
 
-       /* Deliberately destroy excsave (don't assume it's value was valid). */
-
-       wsr     a3, excsave1            # save a3
+       xsr     a3, excsave1
+       s32i    a2, a3, EXC_TABLE_DOUBLE_SAVE
 
        /* Check for kernel double exception (usually fatal). */
 
-       rsr     a3, ps
-       _bbci.l a3, PS_UM_BIT, .Lksp
+       rsr     a2, ps
+       _bbci.l a2, PS_UM_BIT, .Lksp
 
        /* Check if we are currently handling a window exception. */
        /* Note: We don't need to indicate that we enter a critical section. */
 
        xsr     a0, depc                # get DEPC, save a0
 
-       movi    a3, WINDOW_VECTORS_VADDR
-       _bltu   a0, a3, .Lfixup
-       addi    a3, a3, WINDOW_VECTORS_SIZE
-       _bgeu   a0, a3, .Lfixup
+       movi    a2, WINDOW_VECTORS_VADDR
+       _bltu   a0, a2, .Lfixup
+       addi    a2, a2, WINDOW_VECTORS_SIZE
+       _bgeu   a0, a2, .Lfixup
 
        /* Window overflow/underflow exception. Get stack pointer. */
 
-       mov     a3, a2
-       /* This explicit literal and the following references to it are made
-        * in order to fit DoubleExceptionVector.literals into the available
-        * 16-byte gap before DoubleExceptionVector.text in the absence of
-        * link time relaxation. See kernel/vmlinux.lds.S
-        */
-       .literal .Lexc_table, exc_table
-       l32r    a2, .Lexc_table
-       l32i    a2, a2, EXC_TABLE_KSTK
+       l32i    a2, a3, EXC_TABLE_KSTK
 
        /* Check for overflow/underflow exception, jump if overflow. */
 
-       _bbci.l a0, 6, .Lovfl
-
-       /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3  */
+       _bbci.l a0, 6, _DoubleExceptionVector_WindowOverflow
 
-       /* Restart window underflow exception.
+       /*
+        * Restart window underflow exception.
+        * Currently:
+        *      depc = orig a0,
+        *      a0 = orig DEPC,
+        *      a2 = new sp based on KSTK from exc_table
+        *      a3 = excsave_1
+        *      excsave_1 = orig a3
+        *
         * We return to the instruction in user space that caused the window
         * underflow exception. Therefore, we change window base to the value
         * before we entered the window underflow exception and prepare the
@@ -252,10 +253,11 @@ ENTRY(_DoubleExceptionVector)
         * by changing depc (in a0).
         * Note: We can trash the current window frame (a0...a3) and depc!
         */
-
+_DoubleExceptionVector_WindowUnderflow:
+       xsr     a3, excsave1
        wsr     a2, depc                # save stack pointer temporarily
        rsr     a0, ps
-       extui   a0, a0, PS_OWB_SHIFT, 4
+       extui   a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
        wsr     a0, windowbase
        rsync
 
@@ -263,28 +265,57 @@ ENTRY(_DoubleExceptionVector)
 
        xsr     a2, depc                # save a2 and get stack pointer
        s32i    a0, a2, PT_AREG0
-
-       wsr     a3, excsave1            # save a3
-       l32r    a3, .Lexc_table
-
+       xsr     a3, excsave1
        rsr     a0, exccause
        s32i    a0, a2, PT_DEPC         # mark it as a regular exception
        addx4   a0, a0, a3
+       xsr     a3, excsave1
        l32i    a0, a0, EXC_TABLE_FAST_USER
        jx      a0
 
-.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
+       /*
+        * We only allow the ITLB miss exception if we are in kernel space.
+        * All other exceptions are unexpected and thus unrecoverable!
+        */
+
+#ifdef CONFIG_MMU
+       .extern fast_second_level_miss_double_kernel
+
+.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
+
+       rsr     a3, exccause
+       beqi    a3, EXCCAUSE_ITLB_MISS, 1f
+       addi    a3, a3, -EXCCAUSE_DTLB_MISS
+       bnez    a3, .Lunrecoverable
+1:     movi    a3, fast_second_level_miss_double_kernel
+       jx      a3
+#else
+.equ   .Lksp,  .Lunrecoverable
+#endif
+
+       /* Critical! We can't handle this situation. PANIC! */
 
-       /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
+       .extern unrecoverable_exception
 
-       l32r    a3, .Lexc_table
-       s32i    a2, a3, EXC_TABLE_DOUBLE_SAVE   # temporary variable
+.Lunrecoverable_fixup:
+       l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE
+       xsr     a0, depc
+
+.Lunrecoverable:
+       rsr     a3, excsave1
+       wsr     a0, excsave1
+       movi    a0, unrecoverable_exception
+       callx0  a0
+
+.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
+
+       /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave1: a3 */
 
        /* Enter critical section. */
 
        l32i    a2, a3, EXC_TABLE_FIXUP
        s32i    a3, a3, EXC_TABLE_FIXUP
-       beq     a2, a3, .Lunrecoverable_fixup   # critical!
+       beq     a2, a3, .Lunrecoverable_fixup   # critical section
        beqz    a2, .Ldflt                      # no handler was registered
 
        /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
@@ -293,58 +324,145 @@ ENTRY(_DoubleExceptionVector)
 
 .Ldflt:        /* Get stack pointer. */
 
-       l32i    a3, a3, EXC_TABLE_DOUBLE_SAVE
-       addi    a2, a3, -PT_USER_SIZE
-
-.Lovfl:        /* Jump to default handlers. */
+       l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE
+       addi    a2, a2, -PT_USER_SIZE
 
-       /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
+       /* a0: depc, a1: a1, a2: kstk, a3: exctable, depc: a0, excsave: a3 */
 
-       xsr     a3, depc
        s32i    a0, a2, PT_DEPC
-       s32i    a3, a2, PT_AREG0
+       l32i    a0, a3, EXC_TABLE_DOUBLE_SAVE
+       xsr     a0, depc
+       s32i    a0, a2, PT_AREG0
 
-       /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
+       /* a0: avail, a1: a1, a2: kstk, a3: exctable, depc: a2, excsave: a3 */
 
-       l32r    a3, .Lexc_table
        rsr     a0, exccause
        addx4   a0, a0, a3
+       xsr     a3, excsave1
        l32i    a0, a0, EXC_TABLE_FAST_USER
        jx      a0
 
        /*
-        * We only allow the ITLB miss exception if we are in kernel space.
-        * All other exceptions are unexpected and thus unrecoverable!
+        * Restart window OVERFLOW exception.
+        * Currently:
+        *      depc = orig a0,
+        *      a0 = orig DEPC,
+        *      a2 = new sp based on KSTK from exc_table
+        *      a3 = EXCSAVE_1
+        *      excsave_1 = orig a3
+        *
+        * We return to the instruction in user space that caused the window
+        * overflow exception. Therefore, we change window base to the value
+        * before we entered the window overflow exception and prepare the
+        * registers to return as if we were coming from a regular exception
+        * by changing DEPC (in a0).
+        *
+        * NOTE: We CANNOT trash the current window frame (a0...a3), but we
+        * can clobber depc.
+        *
+        * The tricky part here is that overflow8 and overflow12 handlers
+        * save a0, then clobber a0.  To restart the handler, we have to restore
+        * a0 if the double exception was past the point where a0 was clobbered.
+        *
+        * To keep things simple, we take advantage of the fact all overflow
+        * handlers save a0 in their very first instruction.  If DEPC was past
+        * that instruction, we can safely restore a0 from where it was saved
+        * on the stack.
+        *
+        * a0: depc, a1: a1, a2: kstk, a3: exc_table, depc: a0, excsave1: a3
         */
+_DoubleExceptionVector_WindowOverflow:
+       extui   a2, a0, 0, 6    # get offset into 64-byte vector handler
+       beqz    a2, 1f          # if at start of vector, don't restore
 
-#ifdef CONFIG_MMU
-       .extern fast_second_level_miss_double_kernel
+       addi    a0, a0, -128
+       bbsi    a0, 8, 1f       # don't restore except for overflow 8 and 12
+       bbsi    a0, 7, 2f
 
-.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
+       /*
+        * Restore a0 as saved by _WindowOverflow8().
+        *
+        * FIXME:  we really need a fixup handler for this L32E,
+        * for the extremely unlikely case where the overflow handler's
+        * reference thru a0 gets a hardware TLB refill that bumps out
+        * the (distinct, aliasing) TLB entry that mapped its prior
+        * references thru a9, and where our reference now thru a9
+        * gets a 2nd-level miss exception (not hardware TLB refill).
+        */
 
-       rsr     a3, exccause
-       beqi    a3, EXCCAUSE_ITLB_MISS, 1f
-       addi    a3, a3, -EXCCAUSE_DTLB_MISS
-       bnez    a3, .Lunrecoverable
-1:     movi    a3, fast_second_level_miss_double_kernel
-       jx      a3
-#else
-.equ   .Lksp,  .Lunrecoverable
-#endif
+       l32e    a2, a9, -16
+       wsr     a2, depc        # replace the saved a0
+       j       1f
 
-       /* Critical! We can't handle this situation. PANIC! */
+2:
+       /*
+        * Restore a0 as saved by _WindowOverflow12().
+        *
+        * FIXME:  we really need a fixup handler for this L32E,
+        * for the extremely unlikely case where the overflow handler's
+        * reference thru a0 gets a hardware TLB refill that bumps out
+        * the (distinct, aliasing) TLB entry that mapped its prior
+        * references thru a13, and where our reference now thru a13
+        * gets a 2nd-level miss exception (not hardware TLB refill).
+        */
 
-       .extern unrecoverable_exception
+       l32e    a2, a13, -16
+       wsr     a2, depc        # replace the saved a0
+1:
+       /*
+        * Restore WindowBase while leaving all address registers restored.
+        * We have to use ROTW for this, because WSR.WINDOWBASE requires
+        * an address register (which would prevent restore).
+        *
+        * Window Base goes from 0 ... 7 (Module 8)
+        * Window Start is 8 bits; Ex: (0b1010 1010):0x55 from series of call4s
+        */
+
+       rsr     a0, ps
+       extui   a0, a0, PS_OWB_SHIFT, PS_OWB_WIDTH
+       rsr     a2, windowbase
+       sub     a0, a2, a0
+       extui   a0, a0, 0, 3
 
-.Lunrecoverable_fixup:
        l32i    a2, a3, EXC_TABLE_DOUBLE_SAVE
-       xsr     a0, depc
+       xsr     a3, excsave1
+       beqi    a0, 1, .L1pane
+       beqi    a0, 3, .L3pane
 
-.Lunrecoverable:
-       rsr     a3, excsave1
-       wsr     a0, excsave1
-       movi    a0, unrecoverable_exception
-       callx0  a0
+       rsr     a0, depc
+       rotw    -2
+
+       /*
+        * We are now in the user code's original window frame.
+        * Process the exception as a user exception as if it was
+        * taken by the user code.
+        *
+        * This is similar to the user exception vector,
+        * except that PT_DEPC isn't set to EXCCAUSE.
+        */
+1:
+       xsr     a3, excsave1
+       wsr     a2, depc
+       l32i    a2, a3, EXC_TABLE_KSTK
+       s32i    a0, a2, PT_AREG0
+       rsr     a0, exccause
+
+       s32i    a0, a2, PT_DEPC
+
+       addx4   a0, a0, a3
+       l32i    a0, a0, EXC_TABLE_FAST_USER
+       xsr     a3, excsave1
+       jx      a0
+
+.L1pane:
+       rsr     a0, depc
+       rotw    -1
+       j       1b
+
+.L3pane:
+       rsr     a0, depc
+       rotw    -3
+       j       1b
 
        .end literal_prefix
 
index d8507f812f46ef6cb05425381ac54e323d028126..74a60c7e085ea40349336089889de2d52f9d142c 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/io.h>
 #include <asm/page.h>
 #include <asm/pgalloc.h>
+#include <asm/ftrace.h>
 #ifdef CONFIG_BLK_DEV_FD
 #include <asm/floppy.h>
 #endif
index 4b7bc8db170ff8ac6befadb8246ac15938b74cae..70fa7bc42b4a0853012af6f6daaeb254f9c5a086 100644 (file)
@@ -72,6 +72,8 @@ void do_page_fault(struct pt_regs *regs)
               address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
 #endif
 
+       if (user_mode(regs))
+               flags |= FAULT_FLAG_USER;
 retry:
        down_read(&mm->mmap_sem);
        vma = find_vma(mm, address);
index a7e40a7c821427cd27f6c7019411030ea00e33e8..7f38e40fee0819a74ec6b3d10c759c07d3b04bb4 100644 (file)
@@ -99,6 +99,12 @@ config BLK_DEV_THROTTLING
 
        See Documentation/cgroups/blkio-controller.txt for more information.
 
+config CMDLINE_PARSER
+       bool "Block device command line partition parser"
+       default n
+       ---help---
+       Parsing command line, get the partitions information.
+
 menu "Partition Types"
 
 source "block/partitions/Kconfig"
index 39b76ba66ffd5e3a5bdca0fcda2f5fbf0f4b9b55..4fa4be544ece94c05d0956a0c6f488c1f7a65161 100644 (file)
@@ -18,3 +18,4 @@ obj-$(CONFIG_IOSCHED_CFQ)     += cfq-iosched.o
 
 obj-$(CONFIG_BLOCK_COMPAT)     += compat_ioctl.o
 obj-$(CONFIG_BLK_DEV_INTEGRITY)        += blk-integrity.o
+obj-$(CONFIG_CMDLINE_PARSER)   += cmdline-parser.o
index 4464c823cff2a0f3228a2dd5d54da3c9cdcbbde4..46cd7bd18b347c580bfee1f4b86fb59321070e56 100644 (file)
@@ -367,7 +367,7 @@ struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q,
        if (!icq)
                return NULL;
 
-       if (radix_tree_preload(gfp_mask) < 0) {
+       if (radix_tree_maybe_preload(gfp_mask) < 0) {
                kmem_cache_free(et->icq_cache, icq);
                return NULL;
        }
index 5efc5a647183b688fe0e4312c7ad5bcb3dad403b..3aa5b195f4dd45e7519e9053cf1593197efc86bd 100644 (file)
@@ -29,7 +29,7 @@ queue_var_store(unsigned long *var, const char *page, size_t count)
        int err;
        unsigned long v;
 
-       err = strict_strtoul(page, 10, &v);
+       err = kstrtoul(page, 10, &v);
        if (err || v > UINT_MAX)
                return -EINVAL;
 
diff --git a/block/cmdline-parser.c b/block/cmdline-parser.c
new file mode 100644 (file)
index 0000000..cc2637f
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Parse command line, get partition information
+ *
+ * Written by Cai Zhiyong <caizhiyong@huawei.com>
+ *
+ */
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/cmdline-parser.h>
+
+static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
+{
+       int ret = 0;
+       struct cmdline_subpart *new_subpart;
+
+       *subpart = NULL;
+
+       new_subpart = kzalloc(sizeof(struct cmdline_subpart), GFP_KERNEL);
+       if (!new_subpart)
+               return -ENOMEM;
+
+       if (*partdef == '-') {
+               new_subpart->size = (sector_t)(~0ULL);
+               partdef++;
+       } else {
+               new_subpart->size = (sector_t)memparse(partdef, &partdef);
+               if (new_subpart->size < (sector_t)PAGE_SIZE) {
+                       pr_warn("cmdline partition size is invalid.");
+                       ret = -EINVAL;
+                       goto fail;
+               }
+       }
+
+       if (*partdef == '@') {
+               partdef++;
+               new_subpart->from = (sector_t)memparse(partdef, &partdef);
+       } else {
+               new_subpart->from = (sector_t)(~0ULL);
+       }
+
+       if (*partdef == '(') {
+               int length;
+               char *next = strchr(++partdef, ')');
+
+               if (!next) {
+                       pr_warn("cmdline partition format is invalid.");
+                       ret = -EINVAL;
+                       goto fail;
+               }
+
+               length = min_t(int, next - partdef,
+                              sizeof(new_subpart->name) - 1);
+               strncpy(new_subpart->name, partdef, length);
+               new_subpart->name[length] = '\0';
+
+               partdef = ++next;
+       } else
+               new_subpart->name[0] = '\0';
+
+       new_subpart->flags = 0;
+
+       if (!strncmp(partdef, "ro", 2)) {
+               new_subpart->flags |= PF_RDONLY;
+               partdef += 2;
+       }
+
+       if (!strncmp(partdef, "lk", 2)) {
+               new_subpart->flags |= PF_POWERUP_LOCK;
+               partdef += 2;
+       }
+
+       *subpart = new_subpart;
+       return 0;
+fail:
+       kfree(new_subpart);
+       return ret;
+}
+
+static void free_subpart(struct cmdline_parts *parts)
+{
+       struct cmdline_subpart *subpart;
+
+       while (parts->subpart) {
+               subpart = parts->subpart;
+               parts->subpart = subpart->next_subpart;
+               kfree(subpart);
+       }
+}
+
+static int parse_parts(struct cmdline_parts **parts, const char *bdevdef)
+{
+       int ret = -EINVAL;
+       char *next;
+       int length;
+       struct cmdline_subpart **next_subpart;
+       struct cmdline_parts *newparts;
+       char buf[BDEVNAME_SIZE + 32 + 4];
+
+       *parts = NULL;
+
+       newparts = kzalloc(sizeof(struct cmdline_parts), GFP_KERNEL);
+       if (!newparts)
+               return -ENOMEM;
+
+       next = strchr(bdevdef, ':');
+       if (!next) {
+               pr_warn("cmdline partition has no block device.");
+               goto fail;
+       }
+
+       length = min_t(int, next - bdevdef, sizeof(newparts->name) - 1);
+       strncpy(newparts->name, bdevdef, length);
+       newparts->name[length] = '\0';
+       newparts->nr_subparts = 0;
+
+       next_subpart = &newparts->subpart;
+
+       while (next && *(++next)) {
+               bdevdef = next;
+               next = strchr(bdevdef, ',');
+
+               length = (!next) ? (sizeof(buf) - 1) :
+                       min_t(int, next - bdevdef, sizeof(buf) - 1);
+
+               strncpy(buf, bdevdef, length);
+               buf[length] = '\0';
+
+               ret = parse_subpart(next_subpart, buf);
+               if (ret)
+                       goto fail;
+
+               newparts->nr_subparts++;
+               next_subpart = &(*next_subpart)->next_subpart;
+       }
+
+       if (!newparts->subpart) {
+               pr_warn("cmdline partition has no valid partition.");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       *parts = newparts;
+
+       return 0;
+fail:
+       free_subpart(newparts);
+       kfree(newparts);
+       return ret;
+}
+
+void cmdline_parts_free(struct cmdline_parts **parts)
+{
+       struct cmdline_parts *next_parts;
+
+       while (*parts) {
+               next_parts = (*parts)->next_parts;
+               free_subpart(*parts);
+               kfree(*parts);
+               *parts = next_parts;
+       }
+}
+
+int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline)
+{
+       int ret;
+       char *buf;
+       char *pbuf;
+       char *next;
+       struct cmdline_parts **next_parts;
+
+       *parts = NULL;
+
+       next = pbuf = buf = kstrdup(cmdline, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       next_parts = parts;
+
+       while (next && *pbuf) {
+               next = strchr(pbuf, ';');
+               if (next)
+                       *next = '\0';
+
+               ret = parse_parts(next_parts, pbuf);
+               if (ret)
+                       goto fail;
+
+               if (next)
+                       pbuf = ++next;
+
+               next_parts = &(*next_parts)->next_parts;
+       }
+
+       if (!*parts) {
+               pr_warn("cmdline partition has no valid partition.");
+               ret = -EINVAL;
+               goto fail;
+       }
+
+       ret = 0;
+done:
+       kfree(buf);
+       return ret;
+
+fail:
+       cmdline_parts_free(parts);
+       goto done;
+}
+
+struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
+                                        const char *bdev)
+{
+       while (parts && strncmp(bdev, parts->name, sizeof(parts->name)))
+               parts = parts->next_parts;
+       return parts;
+}
+
+/*
+ *  add_part()
+ *    0 success.
+ *    1 can not add so many partitions.
+ */
+void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
+                      int slot,
+                      int (*add_part)(int, struct cmdline_subpart *, void *),
+                      void *param)
+
+{
+       sector_t from = 0;
+       struct cmdline_subpart *subpart;
+
+       for (subpart = parts->subpart; subpart;
+            subpart = subpart->next_subpart, slot++) {
+               if (subpart->from == (sector_t)(~0ULL))
+                       subpart->from = from;
+               else
+                       from = subpart->from;
+
+               if (from >= disk_size)
+                       break;
+
+               if (subpart->size > (disk_size - from))
+                       subpart->size = disk_size - from;
+
+               from += subpart->size;
+
+               if (add_part(slot, subpart, param))
+                       break;
+       }
+}
index 7e5d474dc6ba8a3028abe19e296d3b19a9d4bded..fbd5a67cb773886104cac49698ee589b8fbc9933 100644 (file)
@@ -70,7 +70,7 @@ static int compat_hdio_getgeo(struct gendisk *disk, struct block_device *bdev,
                return ret;
 
        ret = copy_to_user(ugeo, &geo, 4);
-       ret |= __put_user(geo.start, &ugeo->start);
+       ret |= put_user(geo.start, &ugeo->start);
        if (ret)
                ret = -EFAULT;
 
index 4cebb2f0d2f406d6b11af7aad8e70c3d50bf3232..87a32086535d5228b513af3935d29765b763b2ec 100644 (file)
@@ -260,3 +260,10 @@ config SYSV68_PARTITION
          partition table format used by Motorola Delta machines (using
          sysv68).
          Otherwise, say N.
+
+config CMDLINE_PARTITION
+       bool "Command line partition support" if PARTITION_ADVANCED
+       select CMDLINE_PARSER
+       help
+         Say Y here if you would read the partitions table from bootargs.
+         The format for the command line is just like mtdparts.
index 2be4d7ba4e3ab4a3615cc3beb814b66f981b2619..37a95270503c495ce74f793245b4c65f24b5562d 100644 (file)
@@ -8,6 +8,7 @@ obj-$(CONFIG_ACORN_PARTITION) += acorn.o
 obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
 obj-$(CONFIG_ATARI_PARTITION) += atari.o
 obj-$(CONFIG_AIX_PARTITION) += aix.o
+obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o
 obj-$(CONFIG_MAC_PARTITION) += mac.o
 obj-$(CONFIG_LDM_PARTITION) += ldm.o
 obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
index 19ba207ea7d12de48ae0a6182c71df3d188c2b3a..9ac1df74f69940c068333537e082299955a4a90b 100644 (file)
@@ -34,6 +34,7 @@
 #include "efi.h"
 #include "karma.h"
 #include "sysv68.h"
+#include "cmdline.h"
 
 int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/
 
@@ -65,6 +66,9 @@ static int (*check_part[])(struct parsed_partitions *) = {
        adfspart_check_ADFS,
 #endif
 
+#ifdef CONFIG_CMDLINE_PARTITION
+       cmdline_partition,
+#endif
 #ifdef CONFIG_EFI_PARTITION
        efi_partition,          /* this must come before msdos */
 #endif
diff --git a/block/partitions/cmdline.c b/block/partitions/cmdline.c
new file mode 100644 (file)
index 0000000..56cf4ff
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2013 HUAWEI
+ * Author: Cai Zhiyong <caizhiyong@huawei.com>
+ *
+ * Read block device partition table from command line.
+ * The partition used for fixed block device (eMMC) embedded device.
+ * It is no MBR, save storage space. Bootloader can be easily accessed
+ * by absolute address of data on the block device.
+ * Users can easily change the partition.
+ *
+ * The format for the command line is just like mtdparts.
+ *
+ * Verbose config please reference "Documentation/block/cmdline-partition.txt"
+ *
+ */
+
+#include <linux/cmdline-parser.h>
+
+#include "check.h"
+#include "cmdline.h"
+
+static char *cmdline;
+static struct cmdline_parts *bdev_parts;
+
+static int add_part(int slot, struct cmdline_subpart *subpart, void *param)
+{
+       int label_min;
+       struct partition_meta_info *info;
+       char tmp[sizeof(info->volname) + 4];
+       struct parsed_partitions *state = (struct parsed_partitions *)param;
+
+       if (slot >= state->limit)
+               return 1;
+
+       put_partition(state, slot, subpart->from >> 9,
+                     subpart->size >> 9);
+
+       info = &state->parts[slot].info;
+
+       label_min = min_t(int, sizeof(info->volname) - 1,
+                         sizeof(subpart->name));
+       strncpy(info->volname, subpart->name, label_min);
+       info->volname[label_min] = '\0';
+
+       snprintf(tmp, sizeof(tmp), "(%s)", info->volname);
+       strlcat(state->pp_buf, tmp, PAGE_SIZE);
+
+       state->parts[slot].has_info = true;
+
+       return 0;
+}
+
+static int __init cmdline_parts_setup(char *s)
+{
+       cmdline = s;
+       return 1;
+}
+__setup("blkdevparts=", cmdline_parts_setup);
+
+/*
+ * Purpose: allocate cmdline partitions.
+ * Returns:
+ * -1 if unable to read the partition table
+ *  0 if this isn't our partition table
+ *  1 if successful
+ */
+int cmdline_partition(struct parsed_partitions *state)
+{
+       sector_t disk_size;
+       char bdev[BDEVNAME_SIZE];
+       struct cmdline_parts *parts;
+
+       if (cmdline) {
+               if (bdev_parts)
+                       cmdline_parts_free(&bdev_parts);
+
+               if (cmdline_parts_parse(&bdev_parts, cmdline)) {
+                       cmdline = NULL;
+                       return -1;
+               }
+               cmdline = NULL;
+       }
+
+       if (!bdev_parts)
+               return 0;
+
+       bdevname(state->bdev, bdev);
+       parts = cmdline_parts_find(bdev_parts, bdev);
+       if (!parts)
+               return 0;
+
+       disk_size = get_capacity(state->bdev->bd_disk) << 9;
+
+       cmdline_parts_set(parts, disk_size, 1, add_part, (void *)state);
+
+       strlcat(state->pp_buf, "\n", PAGE_SIZE);
+
+       return 1;
+}
diff --git a/block/partitions/cmdline.h b/block/partitions/cmdline.h
new file mode 100644 (file)
index 0000000..26e0f8d
--- /dev/null
@@ -0,0 +1,2 @@
+
+int cmdline_partition(struct parsed_partitions *state);
index c85fc895ecdbbeba25b624e1af909bfa61f3acc2..1eb09ee5311b414e448b28eb26a72f7ff6bbaa1c 100644 (file)
@@ -25,6 +25,9 @@
  * TODO:
  *
  * Changelog:
+ * Mon August 5th, 2013 Davidlohr Bueso <davidlohr@hp.com>
+ * - detect hybrid MBRs, tighter pMBR checking & cleanups.
+ *
  * Mon Nov 09 2004 Matt Domsch <Matt_Domsch@dell.com>
  * - test for valid PMBR and valid PGPT before ever reading
  *   AGPT, allow override with 'gpt' kernel command line option.
@@ -149,34 +152,84 @@ static u64 last_lba(struct block_device *bdev)
                       bdev_logical_block_size(bdev)) - 1ULL;
 }
 
-static inline int
-pmbr_part_valid(struct partition *part)
+static inline int pmbr_part_valid(gpt_mbr_record *part)
 {
-        if (part->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT &&
-            le32_to_cpu(part->start_sect) == 1UL)
-                return 1;
-        return 0;
+       if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT)
+               goto invalid;
+
+       /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */
+       if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA)
+               goto invalid;
+
+       return GPT_MBR_PROTECTIVE;
+invalid:
+       return 0;
 }
 
 /**
  * is_pmbr_valid(): test Protective MBR for validity
  * @mbr: pointer to a legacy mbr structure
+ * @total_sectors: amount of sectors in the device
  *
- * Description: Returns 1 if PMBR is valid, 0 otherwise.
- * Validity depends on two things:
+ * Description: Checks for a valid protective or hybrid
+ * master boot record (MBR). The validity of a pMBR depends
+ * on all of the following properties:
  *  1) MSDOS signature is in the last two bytes of the MBR
  *  2) One partition of type 0xEE is found
+ *
+ * In addition, a hybrid MBR will have up to three additional
+ * primary partitions, which point to the same space that's
+ * marked out by up to three GPT partitions.
+ *
+ * Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or
+ * GPT_MBR_HYBRID depending on the device layout.
  */
-static int
-is_pmbr_valid(legacy_mbr *mbr)
+static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors)
 {
-       int i;
+       uint32_t sz = 0;
+       int i, part = 0, ret = 0; /* invalid by default */
+
        if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE)
-                return 0;
+               goto done;
+
+       for (i = 0; i < 4; i++) {
+               ret = pmbr_part_valid(&mbr->partition_record[i]);
+               if (ret == GPT_MBR_PROTECTIVE) {
+                       part = i;
+                       /*
+                        * Ok, we at least know that there's a protective MBR,
+                        * now check if there are other partition types for
+                        * hybrid MBR.
+                        */
+                       goto check_hybrid;
+               }
+       }
+
+       if (ret != GPT_MBR_PROTECTIVE)
+               goto done;
+check_hybrid:
        for (i = 0; i < 4; i++)
-               if (pmbr_part_valid(&mbr->partition_record[i]))
-                        return 1;
-       return 0;
+               if ((mbr->partition_record[i].os_type !=
+                       EFI_PMBR_OSTYPE_EFI_GPT) &&
+                   (mbr->partition_record[i].os_type != 0x00))
+                       ret = GPT_MBR_HYBRID;
+
+       /*
+        * Protective MBRs take up the lesser of the whole disk
+        * or 2 TiB (32bit LBA), ignoring the rest of the disk.
+        * Some partitioning programs, nonetheless, choose to set
+        * the size to the maximum 32-bit limitation, disregarding
+        * the disk size.
+        *
+        * Hybrid MBRs do not necessarily comply with this.
+        */
+       if (ret == GPT_MBR_PROTECTIVE) {
+               sz = le32_to_cpu(mbr->partition_record[part].size_in_lba);
+               if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF)
+                       ret = 0;
+       }
+done:
+       return ret;
 }
 
 /**
@@ -243,8 +296,7 @@ static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state,
                return NULL;
 
        if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba),
-                     (u8 *) pte,
-                    count) < count) {
+                       (u8 *) pte, count) < count) {
                kfree(pte);
                 pte=NULL;
                return NULL;
@@ -364,7 +416,12 @@ static int is_gpt_valid(struct parsed_partitions *state, u64 lba,
                         (unsigned long long)lastlba);
                goto fail;
        }
-
+       if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) {
+               pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n",
+                        (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba),
+                        (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba));
+               goto fail;
+       }
        /* Check that sizeof_partition_entry has the correct value */
        if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) {
                pr_debug("GUID Partitition Entry Size check failed.\n");
@@ -429,44 +486,42 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
        if (!pgpt || !agpt)
                return;
        if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) {
-               printk(KERN_WARNING
-                      "GPT:Primary header LBA != Alt. header alternate_lba\n");
-               printk(KERN_WARNING "GPT:%lld != %lld\n",
+               pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n");
+               pr_warn("GPT:%lld != %lld\n",
                       (unsigned long long)le64_to_cpu(pgpt->my_lba),
                        (unsigned long long)le64_to_cpu(agpt->alternate_lba));
                error_found++;
        }
        if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) {
-               printk(KERN_WARNING
-                      "GPT:Primary header alternate_lba != Alt. header my_lba\n");
-               printk(KERN_WARNING "GPT:%lld != %lld\n",
+               pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n");
+               pr_warn("GPT:%lld != %lld\n",
                       (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
                        (unsigned long long)le64_to_cpu(agpt->my_lba));
                error_found++;
        }
        if (le64_to_cpu(pgpt->first_usable_lba) !=
             le64_to_cpu(agpt->first_usable_lba)) {
-               printk(KERN_WARNING "GPT:first_usable_lbas don't match.\n");
-               printk(KERN_WARNING "GPT:%lld != %lld\n",
+               pr_warn("GPT:first_usable_lbas don't match.\n");
+               pr_warn("GPT:%lld != %lld\n",
                       (unsigned long long)le64_to_cpu(pgpt->first_usable_lba),
                        (unsigned long long)le64_to_cpu(agpt->first_usable_lba));
                error_found++;
        }
        if (le64_to_cpu(pgpt->last_usable_lba) !=
             le64_to_cpu(agpt->last_usable_lba)) {
-               printk(KERN_WARNING "GPT:last_usable_lbas don't match.\n");
-               printk(KERN_WARNING "GPT:%lld != %lld\n",
+               pr_warn("GPT:last_usable_lbas don't match.\n");
+               pr_warn("GPT:%lld != %lld\n",
                       (unsigned long long)le64_to_cpu(pgpt->last_usable_lba),
                        (unsigned long long)le64_to_cpu(agpt->last_usable_lba));
                error_found++;
        }
        if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) {
-               printk(KERN_WARNING "GPT:disk_guids don't match.\n");
+               pr_warn("GPT:disk_guids don't match.\n");
                error_found++;
        }
        if (le32_to_cpu(pgpt->num_partition_entries) !=
             le32_to_cpu(agpt->num_partition_entries)) {
-               printk(KERN_WARNING "GPT:num_partition_entries don't match: "
+               pr_warn("GPT:num_partition_entries don't match: "
                       "0x%x != 0x%x\n",
                       le32_to_cpu(pgpt->num_partition_entries),
                       le32_to_cpu(agpt->num_partition_entries));
@@ -474,8 +529,7 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
        }
        if (le32_to_cpu(pgpt->sizeof_partition_entry) !=
             le32_to_cpu(agpt->sizeof_partition_entry)) {
-               printk(KERN_WARNING
-                      "GPT:sizeof_partition_entry values don't match: "
+               pr_warn("GPT:sizeof_partition_entry values don't match: "
                       "0x%x != 0x%x\n",
                        le32_to_cpu(pgpt->sizeof_partition_entry),
                       le32_to_cpu(agpt->sizeof_partition_entry));
@@ -483,34 +537,30 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba)
        }
        if (le32_to_cpu(pgpt->partition_entry_array_crc32) !=
             le32_to_cpu(agpt->partition_entry_array_crc32)) {
-               printk(KERN_WARNING
-                      "GPT:partition_entry_array_crc32 values don't match: "
+               pr_warn("GPT:partition_entry_array_crc32 values don't match: "
                       "0x%x != 0x%x\n",
                        le32_to_cpu(pgpt->partition_entry_array_crc32),
                       le32_to_cpu(agpt->partition_entry_array_crc32));
                error_found++;
        }
        if (le64_to_cpu(pgpt->alternate_lba) != lastlba) {
-               printk(KERN_WARNING
-                      "GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
-               printk(KERN_WARNING "GPT:%lld != %lld\n",
+               pr_warn("GPT:Primary header thinks Alt. header is not at the end of the disk.\n");
+               pr_warn("GPT:%lld != %lld\n",
                        (unsigned long long)le64_to_cpu(pgpt->alternate_lba),
                        (unsigned long long)lastlba);
                error_found++;
        }
 
        if (le64_to_cpu(agpt->my_lba) != lastlba) {
-               printk(KERN_WARNING
-                      "GPT:Alternate GPT header not at the end of the disk.\n");
-               printk(KERN_WARNING "GPT:%lld != %lld\n",
+               pr_warn("GPT:Alternate GPT header not at the end of the disk.\n");
+               pr_warn("GPT:%lld != %lld\n",
                        (unsigned long long)le64_to_cpu(agpt->my_lba),
                        (unsigned long long)lastlba);
                error_found++;
        }
 
        if (error_found)
-               printk(KERN_WARNING
-                      "GPT: Use GNU Parted to correct GPT errors.\n");
+               pr_warn("GPT: Use GNU Parted to correct GPT errors.\n");
        return;
 }
 
@@ -536,6 +586,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
        gpt_header *pgpt = NULL, *agpt = NULL;
        gpt_entry *pptes = NULL, *aptes = NULL;
        legacy_mbr *legacymbr;
+       sector_t total_sectors = i_size_read(state->bdev->bd_inode) >> 9;
        u64 lastlba;
 
        if (!ptes)
@@ -543,17 +594,22 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
 
        lastlba = last_lba(state->bdev);
         if (!force_gpt) {
-                /* This will be added to the EFI Spec. per Intel after v1.02. */
-                legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
-                if (legacymbr) {
-                        read_lba(state, 0, (u8 *) legacymbr,
-                                sizeof (*legacymbr));
-                        good_pmbr = is_pmbr_valid(legacymbr);
-                        kfree(legacymbr);
-                }
-                if (!good_pmbr)
-                        goto fail;
-        }
+               /* This will be added to the EFI Spec. per Intel after v1.02. */
+               legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL);
+               if (!legacymbr)
+                       goto fail;
+
+               read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr));
+               good_pmbr = is_pmbr_valid(legacymbr, total_sectors);
+               kfree(legacymbr);
+
+               if (!good_pmbr)
+                       goto fail;
+
+               pr_debug("Device has a %s MBR\n",
+                        good_pmbr == GPT_MBR_PROTECTIVE ?
+                                               "protective" : "hybrid");
+       }
 
        good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA,
                                 &pgpt, &pptes);
@@ -576,11 +632,8 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
                 *ptes = pptes;
                 kfree(agpt);
                 kfree(aptes);
-                if (!good_agpt) {
-                        printk(KERN_WARNING 
-                              "Alternate GPT is invalid, "
-                               "using primary GPT.\n");
-                }
+               if (!good_agpt)
+                        pr_warn("Alternate GPT is invalid, using primary GPT.\n");
                 return 1;
         }
         else if (good_agpt) {
@@ -588,8 +641,7 @@ static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt,
                 *ptes = aptes;
                 kfree(pgpt);
                 kfree(pptes);
-                printk(KERN_WARNING 
-                       "Primary GPT is invalid, using alternate GPT.\n");
+               pr_warn("Primary GPT is invalid, using alternate GPT.\n");
                 return 1;
         }
 
@@ -651,8 +703,7 @@ int efi_partition(struct parsed_partitions *state)
                put_partition(state, i+1, start * ssz, size * ssz);
 
                /* If this is a RAID volume, tell md */
-               if (!efi_guidcmp(ptes[i].partition_type_guid,
-                                PARTITION_LINUX_RAID_GUID))
+               if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID))
                        state->parts[i + 1].flags = ADDPART_FLAG_RAID;
 
                info = &state->parts[i + 1].info;
index b69ab729558f96763c950384cba2e619d2e444fc..4efcafba7e6455acd1361087eafcf086722f98d9 100644 (file)
@@ -37,6 +37,9 @@
 #define EFI_PMBR_OSTYPE_EFI 0xEF
 #define EFI_PMBR_OSTYPE_EFI_GPT 0xEE
 
+#define GPT_MBR_PROTECTIVE  1
+#define GPT_MBR_HYBRID      2
+
 #define GPT_HEADER_SIGNATURE 0x5452415020494645ULL
 #define GPT_HEADER_REVISION_V1 0x00010000
 #define GPT_PRIMARY_PARTITION_TABLE_LBA 1
@@ -101,11 +104,25 @@ typedef struct _gpt_entry {
        efi_char16_t partition_name[72 / sizeof (efi_char16_t)];
 } __attribute__ ((packed)) gpt_entry;
 
+typedef struct _gpt_mbr_record {
+       u8      boot_indicator; /* unused by EFI, set to 0x80 for bootable */
+       u8      start_head;     /* unused by EFI, pt start in CHS */
+       u8      start_sector;   /* unused by EFI, pt start in CHS */
+       u8      start_track;
+       u8      os_type;        /* EFI and legacy non-EFI OS types */
+       u8      end_head;       /* unused by EFI, pt end in CHS */
+       u8      end_sector;     /* unused by EFI, pt end in CHS */
+       u8      end_track;      /* unused by EFI, pt end in CHS */
+       __le32  starting_lba;   /* used by EFI - start addr of the on disk pt */
+       __le32  size_in_lba;    /* used by EFI - size of pt in LBA */
+} __packed gpt_mbr_record;
+
+
 typedef struct _legacy_mbr {
        u8 boot_code[440];
        __le32 unique_mbr_signature;
        __le16 unknown;
-       struct partition partition_record[4];
+       gpt_mbr_record partition_record[4];
        __le16 signature;
 } __attribute__ ((packed)) legacy_mbr;
 
@@ -113,22 +130,3 @@ typedef struct _legacy_mbr {
 extern int efi_partition(struct parsed_partitions *state);
 
 #endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * --------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4 
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
index 2d5ed08a239fa3e79110c9dfd077d30da8954192..80019ba8da3a2113ce8a48bf924bba9ca7d96e50 100644 (file)
@@ -83,7 +83,7 @@ obj-$(CONFIG_CRYPTO_ZLIB) += zlib.o
 obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o
 obj-$(CONFIG_CRYPTO_CRC32C) += crc32c.o
 obj-$(CONFIG_CRYPTO_CRC32) += crc32.o
-obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif.o
+obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o
 obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o
 obj-$(CONFIG_CRYPTO_LZO) += lzo.o
 obj-$(CONFIG_CRYPTO_LZ4) += lz4.o
index 320ea4d8a0f516422942273c7b36fa50d34bdbc7..a2b39c5f3649de2c513ecbec7fd45c2fd6bbdaf4 100644 (file)
@@ -34,6 +34,8 @@ EXPORT_SYMBOL_GPL(crypto_alg_sem);
 BLOCKING_NOTIFIER_HEAD(crypto_chain);
 EXPORT_SYMBOL_GPL(crypto_chain);
 
+static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg);
+
 struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
 {
        return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
@@ -144,8 +146,11 @@ static struct crypto_alg *crypto_larval_add(const char *name, u32 type,
        }
        up_write(&crypto_alg_sem);
 
-       if (alg != &larval->alg)
+       if (alg != &larval->alg) {
                kfree(larval);
+               if (crypto_is_larval(alg))
+                       alg = crypto_larval_wait(alg);
+       }
 
        return alg;
 }
diff --git a/crypto/crct10dif.c b/crypto/crct10dif.c
deleted file mode 100644 (file)
index 92aca96..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Cryptographic API.
- *
- * T10 Data Integrity Field CRC16 Crypto Transform
- *
- * Copyright (c) 2007 Oracle Corporation.  All rights reserved.
- * Written by Martin K. Petersen <martin.petersen@oracle.com>
- * Copyright (C) 2013 Intel Corporation
- * Author: Tim Chen <tim.c.chen@linux.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; either version 2 of the License, or (at your option)
- * any later version.
- *
- * 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/module.h>
-#include <linux/crc-t10dif.h>
-#include <crypto/internal/hash.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-struct chksum_desc_ctx {
-       __u16 crc;
-};
-
-/* Table generated using the following polynomium:
- * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
- * gt: 0x8bb7
- */
-static const __u16 t10_dif_crc_table[256] = {
-       0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
-       0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
-       0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
-       0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
-       0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
-       0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
-       0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
-       0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
-       0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
-       0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
-       0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
-       0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
-       0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
-       0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
-       0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
-       0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
-       0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
-       0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
-       0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
-       0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
-       0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
-       0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
-       0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
-       0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
-       0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
-       0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
-       0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
-       0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
-       0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
-       0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
-       0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
-       0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
-};
-
-__u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len)
-{
-       unsigned int i;
-
-       for (i = 0 ; i < len ; i++)
-               crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
-
-       return crc;
-}
-EXPORT_SYMBOL(crc_t10dif_generic);
-
-/*
- * Steps through buffer one byte at at time, calculates reflected
- * crc using table.
- */
-
-static int chksum_init(struct shash_desc *desc)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       ctx->crc = 0;
-
-       return 0;
-}
-
-static int chksum_update(struct shash_desc *desc, const u8 *data,
-                        unsigned int length)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
-       return 0;
-}
-
-static int chksum_final(struct shash_desc *desc, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       *(__u16 *)out = ctx->crc;
-       return 0;
-}
-
-static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
-                       u8 *out)
-{
-       *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
-       return 0;
-}
-
-static int chksum_finup(struct shash_desc *desc, const u8 *data,
-                       unsigned int len, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       return __chksum_finup(&ctx->crc, data, len, out);
-}
-
-static int chksum_digest(struct shash_desc *desc, const u8 *data,
-                        unsigned int length, u8 *out)
-{
-       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
-
-       return __chksum_finup(&ctx->crc, data, length, out);
-}
-
-static struct shash_alg alg = {
-       .digestsize             =       CRC_T10DIF_DIGEST_SIZE,
-       .init           =       chksum_init,
-       .update         =       chksum_update,
-       .final          =       chksum_final,
-       .finup          =       chksum_finup,
-       .digest         =       chksum_digest,
-       .descsize               =       sizeof(struct chksum_desc_ctx),
-       .base                   =       {
-               .cra_name               =       "crct10dif",
-               .cra_driver_name        =       "crct10dif-generic",
-               .cra_priority           =       100,
-               .cra_blocksize          =       CRC_T10DIF_BLOCK_SIZE,
-               .cra_module             =       THIS_MODULE,
-       }
-};
-
-static int __init crct10dif_mod_init(void)
-{
-       int ret;
-
-       ret = crypto_register_shash(&alg);
-       return ret;
-}
-
-static void __exit crct10dif_mod_fini(void)
-{
-       crypto_unregister_shash(&alg);
-}
-
-module_init(crct10dif_mod_init);
-module_exit(crct10dif_mod_fini);
-
-MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
-MODULE_DESCRIPTION("T10 DIF CRC calculation.");
-MODULE_LICENSE("GPL");
diff --git a/crypto/crct10dif_common.c b/crypto/crct10dif_common.c
new file mode 100644 (file)
index 0000000..b2fab36
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Cryptographic API.
+ *
+ * T10 Data Integrity Field CRC16 Crypto Transform
+ *
+ * Copyright (c) 2007 Oracle Corporation.  All rights reserved.
+ * Written by Martin K. Petersen <martin.petersen@oracle.com>
+ * Copyright (C) 2013 Intel Corporation
+ * Author: Tim Chen <tim.c.chen@linux.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; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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/crc-t10dif.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+/* Table generated using the following polynomium:
+ * x^16 + x^15 + x^11 + x^9 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
+ * gt: 0x8bb7
+ */
+static const __u16 t10_dif_crc_table[256] = {
+       0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
+       0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
+       0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
+       0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
+       0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
+       0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
+       0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
+       0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
+       0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
+       0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
+       0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
+       0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
+       0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
+       0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
+       0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
+       0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
+       0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
+       0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
+       0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
+       0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
+       0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
+       0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
+       0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
+       0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
+       0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
+       0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
+       0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
+       0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
+       0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
+       0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
+       0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
+       0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
+};
+
+__u16 crc_t10dif_generic(__u16 crc, const unsigned char *buffer, size_t len)
+{
+       unsigned int i;
+
+       for (i = 0 ; i < len ; i++)
+               crc = (crc << 8) ^ t10_dif_crc_table[((crc >> 8) ^ buffer[i]) & 0xff];
+
+       return crc;
+}
+EXPORT_SYMBOL(crc_t10dif_generic);
+
+MODULE_DESCRIPTION("T10 DIF CRC calculation common code");
+MODULE_LICENSE("GPL");
diff --git a/crypto/crct10dif_generic.c b/crypto/crct10dif_generic.c
new file mode 100644 (file)
index 0000000..877e711
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Cryptographic API.
+ *
+ * T10 Data Integrity Field CRC16 Crypto Transform
+ *
+ * Copyright (c) 2007 Oracle Corporation.  All rights reserved.
+ * Written by Martin K. Petersen <martin.petersen@oracle.com>
+ * Copyright (C) 2013 Intel Corporation
+ * Author: Tim Chen <tim.c.chen@linux.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; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * 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/crc-t10dif.h>
+#include <crypto/internal/hash.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+struct chksum_desc_ctx {
+       __u16 crc;
+};
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static int chksum_init(struct shash_desc *desc)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       ctx->crc = 0;
+
+       return 0;
+}
+
+static int chksum_update(struct shash_desc *desc, const u8 *data,
+                        unsigned int length)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       ctx->crc = crc_t10dif_generic(ctx->crc, data, length);
+       return 0;
+}
+
+static int chksum_final(struct shash_desc *desc, u8 *out)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       *(__u16 *)out = ctx->crc;
+       return 0;
+}
+
+static int __chksum_finup(__u16 *crcp, const u8 *data, unsigned int len,
+                       u8 *out)
+{
+       *(__u16 *)out = crc_t10dif_generic(*crcp, data, len);
+       return 0;
+}
+
+static int chksum_finup(struct shash_desc *desc, const u8 *data,
+                       unsigned int len, u8 *out)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       return __chksum_finup(&ctx->crc, data, len, out);
+}
+
+static int chksum_digest(struct shash_desc *desc, const u8 *data,
+                        unsigned int length, u8 *out)
+{
+       struct chksum_desc_ctx *ctx = shash_desc_ctx(desc);
+
+       return __chksum_finup(&ctx->crc, data, length, out);
+}
+
+static struct shash_alg alg = {
+       .digestsize             =       CRC_T10DIF_DIGEST_SIZE,
+       .init           =       chksum_init,
+       .update         =       chksum_update,
+       .final          =       chksum_final,
+       .finup          =       chksum_finup,
+       .digest         =       chksum_digest,
+       .descsize               =       sizeof(struct chksum_desc_ctx),
+       .base                   =       {
+               .cra_name               =       "crct10dif",
+               .cra_driver_name        =       "crct10dif-generic",
+               .cra_priority           =       100,
+               .cra_blocksize          =       CRC_T10DIF_BLOCK_SIZE,
+               .cra_module             =       THIS_MODULE,
+       }
+};
+
+static int __init crct10dif_mod_init(void)
+{
+       int ret;
+
+       ret = crypto_register_shash(&alg);
+       return ret;
+}
+
+static void __exit crct10dif_mod_fini(void)
+{
+       crypto_unregister_shash(&alg);
+}
+
+module_init(crct10dif_mod_init);
+module_exit(crct10dif_mod_fini);
+
+MODULE_AUTHOR("Tim Chen <tim.c.chen@linux.intel.com>");
+MODULE_DESCRIPTION("T10 DIF CRC calculation.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("crct10dif");
index 6a382188fa20a7f2f67f8f45d506439f8e45db7b..fb78bb9ad8f65888817fc6f7a3ecb2563b975134 100644 (file)
@@ -257,12 +257,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
                                pdata->mmio_size = resource_size(&rentry->res);
                        pdata->mmio_base = ioremap(rentry->res.start,
                                                   pdata->mmio_size);
-                       pdata->dev_desc = dev_desc;
                        break;
                }
 
        acpi_dev_free_resource_list(&resource_list);
 
+       pdata->dev_desc = dev_desc;
+
        if (dev_desc->clk_required) {
                ret = register_device_clock(adev, pdata);
                if (ret) {
index 2bdba6f7d7620c43a8f6dafcbe83d5a14679f8b4..f0b09bf9887d605ee78e03a7a9aa2c84f2a4c98c 100644 (file)
@@ -57,6 +57,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *val_desc,
                              union acpi_operand_object *dest_desc,
                              struct acpi_walk_state *walk_state);
 
+static acpi_status
+acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,
+                            struct acpi_namespace_node *node,
+                            struct acpi_walk_state *walk_state);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_store
@@ -375,7 +380,11 @@ acpi_ex_store_object_to_index(union acpi_operand_object *source_desc,
  *              When storing into an object the data is converted to the
  *              target object type then stored in the object. This means
  *              that the target object type (for an initialized target) will
- *              not be changed by a store operation.
+ *              not be changed by a store operation. A copy_object can change
+ *              the target type, however.
+ *
+ *              The implicit_conversion flag is set to NO/FALSE only when
+ *              storing to an arg_x -- as per the rules of the ACPI spec.
  *
  *              Assumes parameters are already validated.
  *
@@ -399,7 +408,7 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
        target_type = acpi_ns_get_type(node);
        target_desc = acpi_ns_get_attached_object(node);
 
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Storing %p (%s) to node %p (%s)\n",
                          source_desc,
                          acpi_ut_get_object_type_name(source_desc), node,
                          acpi_ut_get_type_name(target_type)));
@@ -413,45 +422,30 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
                return_ACPI_STATUS(status);
        }
 
-       /* If no implicit conversion, drop into the default case below */
-
-       if ((!implicit_conversion) ||
-           ((walk_state->opcode == AML_COPY_OP) &&
-            (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) &&
-            (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) &&
-            (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) {
-               /*
-                * Force execution of default (no implicit conversion). Note:
-                * copy_object does not perform an implicit conversion, as per the ACPI
-                * spec -- except in case of region/bank/index fields -- because these
-                * objects must retain their original type permanently.
-                */
-               target_type = ACPI_TYPE_ANY;
-       }
-
        /* Do the actual store operation */
 
        switch (target_type) {
-       case ACPI_TYPE_BUFFER_FIELD:
-       case ACPI_TYPE_LOCAL_REGION_FIELD:
-       case ACPI_TYPE_LOCAL_BANK_FIELD:
-       case ACPI_TYPE_LOCAL_INDEX_FIELD:
-
-               /* For fields, copy the source data to the target field. */
-
-               status = acpi_ex_write_data_to_field(source_desc, target_desc,
-                                                    &walk_state->result_obj);
-               break;
-
        case ACPI_TYPE_INTEGER:
        case ACPI_TYPE_STRING:
        case ACPI_TYPE_BUFFER:
                /*
-                * These target types are all of type Integer/String/Buffer, and
-                * therefore support implicit conversion before the store.
-                *
-                * Copy and/or convert the source object to a new target object
+                * The simple data types all support implicit source operand
+                * conversion before the store.
                 */
+
+               if ((walk_state->opcode == AML_COPY_OP) || !implicit_conversion) {
+                       /*
+                        * However, copy_object and Stores to arg_x do not perform
+                        * an implicit conversion, as per the ACPI specification.
+                        * A direct store is performed instead.
+                        */
+                       status = acpi_ex_store_direct_to_node(source_desc, node,
+                                                             walk_state);
+                       break;
+               }
+
+               /* Store with implicit source operand conversion support */
+
                status =
                    acpi_ex_store_object_to_object(source_desc, target_desc,
                                                   &new_desc, walk_state);
@@ -465,13 +459,12 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
                         * the Name's type to that of the value being stored in it.
                         * source_desc reference count is incremented by attach_object.
                         *
-                        * Note: This may change the type of the node if an explicit store
-                        * has been performed such that the node/object type has been
-                        * changed.
+                        * Note: This may change the type of the node if an explicit
+                        * store has been performed such that the node/object type
+                        * has been changed.
                         */
-                       status =
-                           acpi_ns_attach_object(node, new_desc,
-                                                 new_desc->common.type);
+                       status = acpi_ns_attach_object(node, new_desc,
+                                                      new_desc->common.type);
 
                        ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
                                          "Store %s into %s via Convert/Attach\n",
@@ -482,38 +475,83 @@ acpi_ex_store_object_to_node(union acpi_operand_object *source_desc,
                }
                break;
 
-       default:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "Storing [%s] (%p) directly into node [%s] (%p)"
-                                 " with no implicit conversion\n",
-                                 acpi_ut_get_object_type_name(source_desc),
-                                 source_desc,
-                                 acpi_ut_get_object_type_name(target_desc),
-                                 node));
+       case ACPI_TYPE_BUFFER_FIELD:
+       case ACPI_TYPE_LOCAL_REGION_FIELD:
+       case ACPI_TYPE_LOCAL_BANK_FIELD:
+       case ACPI_TYPE_LOCAL_INDEX_FIELD:
+               /*
+                * For all fields, always write the source data to the target
+                * field. Any required implicit source operand conversion is
+                * performed in the function below as necessary. Note, field
+                * objects must retain their original type permanently.
+                */
+               status = acpi_ex_write_data_to_field(source_desc, target_desc,
+                                                    &walk_state->result_obj);
+               break;
 
+       default:
                /*
                 * No conversions for all other types. Directly store a copy of
-                * the source object. NOTE: This is a departure from the ACPI
-                * spec, which states "If conversion is impossible, abort the
-                * running control method".
+                * the source object. This is the ACPI spec-defined behavior for
+                * the copy_object operator.
                 *
-                * This code implements "If conversion is impossible, treat the
-                * Store operation as a CopyObject".
+                * NOTE: For the Store operator, this is a departure from the
+                * ACPI spec, which states "If conversion is impossible, abort
+                * the running control method". Instead, this code implements
+                * "If conversion is impossible, treat the Store operation as
+                * a CopyObject".
                 */
-               status =
-                   acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
-                                                   walk_state);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-
-               status =
-                   acpi_ns_attach_object(node, new_desc,
-                                         new_desc->common.type);
-               acpi_ut_remove_reference(new_desc);
+               status = acpi_ex_store_direct_to_node(source_desc, node,
+                                                     walk_state);
                break;
        }
 
        return_ACPI_STATUS(status);
 }
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_store_direct_to_node
+ *
+ * PARAMETERS:  source_desc             - Value to be stored
+ *              node                    - Named object to receive the value
+ *              walk_state              - Current walk state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: "Store" an object directly to a node. This involves a copy
+ *              and an attach.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ex_store_direct_to_node(union acpi_operand_object *source_desc,
+                            struct acpi_namespace_node *node,
+                            struct acpi_walk_state *walk_state)
+{
+       acpi_status status;
+       union acpi_operand_object *new_desc;
+
+       ACPI_FUNCTION_TRACE(ex_store_direct_to_node);
+
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                         "Storing [%s] (%p) directly into node [%s] (%p)"
+                         " with no implicit conversion\n",
+                         acpi_ut_get_object_type_name(source_desc),
+                         source_desc, acpi_ut_get_type_name(node->type),
+                         node));
+
+       /* Copy the source object to a new object */
+
+       status =
+           acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc, walk_state);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       /* Attach the new object to the node */
+
+       status = acpi_ns_attach_object(node, new_desc, new_desc->common.type);
+       acpi_ut_remove_reference(new_desc);
+       return_ACPI_STATUS(status);
+}
index 94672297e1b1bc6f3b482b3e0985cda28786ee10..10f0f40587bb73309eee9e959fc1049cbaf6dc05 100644 (file)
@@ -79,6 +79,9 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev)
        return ret;
 }
 
+#define FIND_CHILD_MIN_SCORE   1
+#define FIND_CHILD_MAX_SCORE   2
+
 static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
                                  void *not_used, void **ret_p)
 {
@@ -92,14 +95,17 @@ static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used,
        return AE_OK;
 }
 
-static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
+static int do_find_child_checks(acpi_handle handle, bool is_bridge)
 {
+       bool sta_present = true;
        unsigned long long sta;
        acpi_status status;
 
-       status = acpi_bus_get_status_handle(handle, &sta);
-       if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
-               return false;
+       status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+       if (status == AE_NOT_FOUND)
+               sta_present = false;
+       else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED))
+               return -ENODEV;
 
        if (is_bridge) {
                void *test = NULL;
@@ -107,16 +113,17 @@ static bool acpi_extra_checks_passed(acpi_handle handle, bool is_bridge)
                /* Check if this object has at least one child device. */
                acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
                                    acpi_dev_present, NULL, NULL, &test);
-               return !!test;
+               if (!test)
+                       return -ENODEV;
        }
-       return true;
+       return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE;
 }
 
 struct find_child_context {
        u64 addr;
        bool is_bridge;
        acpi_handle ret;
-       bool ret_checked;
+       int ret_score;
 };
 
 static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
@@ -125,6 +132,7 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
        struct find_child_context *context = data;
        unsigned long long addr;
        acpi_status status;
+       int score;
 
        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr);
        if (ACPI_FAILURE(status) || addr != context->addr)
@@ -144,15 +152,20 @@ static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used,
         * its handle if so.  Second, check the same for the object that we've
         * just found.
         */
-       if (!context->ret_checked) {
-               if (acpi_extra_checks_passed(context->ret, context->is_bridge))
+       if (!context->ret_score) {
+               score = do_find_child_checks(context->ret, context->is_bridge);
+               if (score == FIND_CHILD_MAX_SCORE)
                        return AE_CTRL_TERMINATE;
                else
-                       context->ret_checked = true;
+                       context->ret_score = score;
        }
-       if (acpi_extra_checks_passed(handle, context->is_bridge)) {
+       score = do_find_child_checks(handle, context->is_bridge);
+       if (score == FIND_CHILD_MAX_SCORE) {
                context->ret = handle;
                return AE_CTRL_TERMINATE;
+       } else if (score > context->ret_score) {
+               context->ret = handle;
+               context->ret_score = score;
        }
        return AE_OK;
 }
index 61d090b6ce254007047aaaeaac2620fdcef60951..fbdb82e70d10623c0bbf94aa73723a40fd32e77d 100644 (file)
@@ -204,8 +204,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
                return -EINVAL;
        }
 
-       lock_device_hotplug();
-
        /*
         * Carry out two passes here and ignore errors in the first pass,
         * because if the devices in question are memory blocks and
@@ -236,9 +234,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
                                            ACPI_UINT32_MAX,
                                            acpi_bus_online_companions, NULL,
                                            NULL, NULL);
-
-                       unlock_device_hotplug();
-
                        put_device(&device->dev);
                        return -EBUSY;
                }
@@ -249,8 +244,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device)
 
        acpi_bus_trim(device);
 
-       unlock_device_hotplug();
-
        /* Device node has been unregistered. */
        put_device(&device->dev);
        device = NULL;
@@ -289,6 +282,7 @@ static void acpi_bus_device_eject(void *context)
        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
        int error;
 
+       lock_device_hotplug();
        mutex_lock(&acpi_scan_lock);
 
        acpi_bus_get_device(handle, &device);
@@ -312,6 +306,7 @@ static void acpi_bus_device_eject(void *context)
 
  out:
        mutex_unlock(&acpi_scan_lock);
+       unlock_device_hotplug();
        return;
 
  err_out:
@@ -326,8 +321,8 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
        int error;
 
-       mutex_lock(&acpi_scan_lock);
        lock_device_hotplug();
+       mutex_lock(&acpi_scan_lock);
 
        if (ost_source != ACPI_NOTIFY_BUS_CHECK) {
                acpi_bus_get_device(handle, &device);
@@ -353,9 +348,9 @@ static void acpi_scan_bus_device_check(acpi_handle handle, u32 ost_source)
                kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
 
  out:
-       unlock_device_hotplug();
        acpi_evaluate_hotplug_ost(handle, ost_source, ost_code, NULL);
        mutex_unlock(&acpi_scan_lock);
+       unlock_device_hotplug();
 }
 
 static void acpi_scan_bus_check(void *context)
@@ -446,6 +441,7 @@ void acpi_bus_hot_remove_device(void *context)
        acpi_handle handle = device->handle;
        int error;
 
+       lock_device_hotplug();
        mutex_lock(&acpi_scan_lock);
 
        error = acpi_scan_hot_remove(device);
@@ -455,6 +451,7 @@ void acpi_bus_hot_remove_device(void *context)
                                          NULL);
 
        mutex_unlock(&acpi_scan_lock);
+       unlock_device_hotplug();
        kfree(context);
 }
 EXPORT_SYMBOL(acpi_bus_hot_remove_device);
index 449f6298dc8937a437ec1f7c4ab6283db3289c40..8557adcd34ee88a82cfb9a805859cba5ad79bef2 100644 (file)
@@ -2865,15 +2865,4 @@ static struct pci_driver he_driver = {
        .id_table =     he_pci_tbl,
 };
 
-static int __init he_init(void)
-{
-       return pci_register_driver(&he_driver);
-}
-
-static void __exit he_cleanup(void)
-{
-       pci_unregister_driver(&he_driver);
-}
-
-module_init(he_init);
-module_exit(he_cleanup);
+module_pci_driver(he_driver);
index 409502a78e7ebcc964ed1ae3cf4500b1c92139a8..5aca5f4c545896c567c892716a64b6cb22452b43 100644 (file)
@@ -778,7 +778,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
                return error;
        }
 
-       if (mac[i] == NULL || mac_pton(mac[i], card->atmdev->esi)) {
+       if (mac[i] == NULL || !mac_pton(mac[i], card->atmdev->esi)) {
                nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
                                   card->atmdev->esi, 6);
                if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) ==
index 1219ab7c310757cdd493baf9101000b0c5d286b0..1e16cbd61da27877bf372cc90f1323d950676db2 100644 (file)
@@ -77,9 +77,36 @@ static int dma_buf_mmap_internal(struct file *file, struct vm_area_struct *vma)
        return dmabuf->ops->mmap(dmabuf, vma);
 }
 
+static loff_t dma_buf_llseek(struct file *file, loff_t offset, int whence)
+{
+       struct dma_buf *dmabuf;
+       loff_t base;
+
+       if (!is_dma_buf_file(file))
+               return -EBADF;
+
+       dmabuf = file->private_data;
+
+       /* only support discovering the end of the buffer,
+          but also allow SEEK_SET to maintain the idiomatic
+          SEEK_END(0), SEEK_CUR(0) pattern */
+       if (whence == SEEK_END)
+               base = dmabuf->size;
+       else if (whence == SEEK_SET)
+               base = 0;
+       else
+               return -EINVAL;
+
+       if (offset != 0)
+               return -EINVAL;
+
+       return base + offset;
+}
+
 static const struct file_operations dma_buf_fops = {
        .release        = dma_buf_release,
        .mmap           = dma_buf_mmap_internal,
+       .llseek         = dma_buf_llseek,
 };
 
 /*
@@ -133,7 +160,12 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops,
        dmabuf->exp_name = exp_name;
 
        file = anon_inode_getfile("dmabuf", &dma_buf_fops, dmabuf, flags);
+       if (IS_ERR(file)) {
+               kfree(dmabuf);
+               return ERR_CAST(file);
+       }
 
+       file->f_mode |= FMODE_LSEEK;
        dmabuf->file = file;
 
        mutex_init(&dmabuf->lock);
index 6c9cdaa9200d795d6cadee62d8af4b59ae36ae51..99802d6f3c60f603efcff5d342ba0c9f4c937ccd 100644 (file)
@@ -96,7 +96,7 @@ static inline __maybe_unused phys_addr_t cma_early_percent_memory(void)
 #endif
 
 /**
- * dma_contiguous_reserve() - reserve area for contiguous memory handling
+ * dma_contiguous_reserve() - reserve area(s) for contiguous memory handling
  * @limit: End address of the reserved memory (optional, 0 for any).
  *
  * This function reserves memory from early allocator. It should be
@@ -124,22 +124,29 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 #endif
        }
 
-       if (selected_size) {
+       if (selected_size && !dma_contiguous_default_area) {
                pr_debug("%s: reserving %ld MiB for global area\n", __func__,
                         (unsigned long)selected_size / SZ_1M);
 
-               dma_declare_contiguous(NULL, selected_size, 0, limit);
+               dma_contiguous_reserve_area(selected_size, 0, limit,
+                                           &dma_contiguous_default_area);
        }
 };
 
 static DEFINE_MUTEX(cma_mutex);
 
-static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
+static int __init cma_activate_area(struct cma *cma)
 {
-       unsigned long pfn = base_pfn;
-       unsigned i = count >> pageblock_order;
+       int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
+       unsigned long base_pfn = cma->base_pfn, pfn = base_pfn;
+       unsigned i = cma->count >> pageblock_order;
        struct zone *zone;
 
+       cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
+
+       if (!cma->bitmap)
+               return -ENOMEM;
+
        WARN_ON_ONCE(!pfn_valid(pfn));
        zone = page_zone(pfn_to_page(pfn));
 
@@ -153,92 +160,53 @@ static int __init cma_activate_area(unsigned long base_pfn, unsigned long count)
                }
                init_cma_reserved_pageblock(pfn_to_page(base_pfn));
        } while (--i);
-       return 0;
-}
-
-static struct cma * __init cma_create_area(unsigned long base_pfn,
-                                    unsigned long count)
-{
-       int bitmap_size = BITS_TO_LONGS(count) * sizeof(long);
-       struct cma *cma;
-       int ret = -ENOMEM;
-
-       pr_debug("%s(base %08lx, count %lx)\n", __func__, base_pfn, count);
-
-       cma = kmalloc(sizeof *cma, GFP_KERNEL);
-       if (!cma)
-               return ERR_PTR(-ENOMEM);
-
-       cma->base_pfn = base_pfn;
-       cma->count = count;
-       cma->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
 
-       if (!cma->bitmap)
-               goto no_mem;
-
-       ret = cma_activate_area(base_pfn, count);
-       if (ret)
-               goto error;
-
-       pr_debug("%s: returned %p\n", __func__, (void *)cma);
-       return cma;
-
-error:
-       kfree(cma->bitmap);
-no_mem:
-       kfree(cma);
-       return ERR_PTR(ret);
+       return 0;
 }
 
-static struct cma_reserved {
-       phys_addr_t start;
-       unsigned long size;
-       struct device *dev;
-} cma_reserved[MAX_CMA_AREAS] __initdata;
-static unsigned cma_reserved_count __initdata;
+static struct cma cma_areas[MAX_CMA_AREAS];
+static unsigned cma_area_count;
 
 static int __init cma_init_reserved_areas(void)
 {
-       struct cma_reserved *r = cma_reserved;
-       unsigned i = cma_reserved_count;
-
-       pr_debug("%s()\n", __func__);
+       int i;
 
-       for (; i; --i, ++r) {
-               struct cma *cma;
-               cma = cma_create_area(PFN_DOWN(r->start),
-                                     r->size >> PAGE_SHIFT);
-               if (!IS_ERR(cma))
-                       dev_set_cma_area(r->dev, cma);
+       for (i = 0; i < cma_area_count; i++) {
+               int ret = cma_activate_area(&cma_areas[i]);
+               if (ret)
+                       return ret;
        }
+
        return 0;
 }
 core_initcall(cma_init_reserved_areas);
 
 /**
- * dma_declare_contiguous() - reserve area for contiguous memory handling
- *                           for particular device
- * @dev:   Pointer to device structure.
- * @size:  Size of the reserved memory.
- * @base:  Start address of the reserved memory (optional, 0 for any).
+ * dma_contiguous_reserve_area() - reserve custom contiguous area
+ * @size: Size of the reserved area (in bytes),
+ * @base: Base address of the reserved area optional, use 0 for any
  * @limit: End address of the reserved memory (optional, 0 for any).
+ * @res_cma: Pointer to store the created cma region.
  *
- * This function reserves memory for specified device. It should be
- * called by board specific code when early allocator (memblock or bootmem)
- * is still activate.
+ * This function reserves memory from early allocator. It should be
+ * called by arch specific code once the early allocator (memblock or bootmem)
+ * has been activated and all other subsystems have already allocated/reserved
+ * memory. This function allows to create custom reserved areas for specific
+ * devices.
  */
-int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
-                                 phys_addr_t base, phys_addr_t limit)
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+                                      phys_addr_t limit, struct cma **res_cma)
 {
-       struct cma_reserved *r = &cma_reserved[cma_reserved_count];
+       struct cma *cma = &cma_areas[cma_area_count];
        phys_addr_t alignment;
+       int ret = 0;
 
        pr_debug("%s(size %lx, base %08lx, limit %08lx)\n", __func__,
                 (unsigned long)size, (unsigned long)base,
                 (unsigned long)limit);
 
        /* Sanity checks */
-       if (cma_reserved_count == ARRAY_SIZE(cma_reserved)) {
+       if (cma_area_count == ARRAY_SIZE(cma_areas)) {
                pr_err("Not enough slots for CMA reserved regions!\n");
                return -ENOSPC;
        }
@@ -256,7 +224,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
        if (base) {
                if (memblock_is_region_reserved(base, size) ||
                    memblock_reserve(base, size) < 0) {
-                       base = -EBUSY;
+                       ret = -EBUSY;
                        goto err;
                }
        } else {
@@ -266,7 +234,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
                 */
                phys_addr_t addr = __memblock_alloc_base(size, alignment, limit);
                if (!addr) {
-                       base = -ENOMEM;
+                       ret = -ENOMEM;
                        goto err;
                } else {
                        base = addr;
@@ -277,10 +245,11 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
         * Each reserved area must be initialised later, when more kernel
         * subsystems (like slab allocator) are available.
         */
-       r->start = base;
-       r->size = size;
-       r->dev = dev;
-       cma_reserved_count++;
+       cma->base_pfn = PFN_DOWN(base);
+       cma->count = size >> PAGE_SHIFT;
+       *res_cma = cma;
+       cma_area_count++;
+
        pr_info("CMA: reserved %ld MiB at %08lx\n", (unsigned long)size / SZ_1M,
                (unsigned long)base);
 
@@ -289,7 +258,7 @@ int __init dma_declare_contiguous(struct device *dev, phys_addr_t size,
        return 0;
 err:
        pr_err("CMA: failed to reserve %ld MiB\n", (unsigned long)size / SZ_1M);
-       return base;
+       return ret;
 }
 
 /**
index 7616a77ca322580958d4f21fff99a54d883440c0..bc9f43bf7e29a46714cb1f220bb0d866c5d3eab8 100644 (file)
@@ -125,13 +125,7 @@ static ssize_t node_read_meminfo(struct device *dev,
                       nid, K(node_page_state(nid, NR_WRITEBACK)),
                       nid, K(node_page_state(nid, NR_FILE_PAGES)),
                       nid, K(node_page_state(nid, NR_FILE_MAPPED)),
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-                      nid, K(node_page_state(nid, NR_ANON_PAGES)
-                       + node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) *
-                       HPAGE_PMD_NR),
-#else
                       nid, K(node_page_state(nid, NR_ANON_PAGES)),
-#endif
                       nid, K(node_page_state(nid, NR_SHMEM)),
                       nid, node_page_state(nid, NR_KERNEL_STACK) *
                                THREAD_SIZE / 1024,
index a355e63a3838cb7ff7e7ef66194888adc65d6232..6fb98b53533f9d708dfc2a530e1033f3f09008b9 100644 (file)
@@ -188,8 +188,11 @@ static int bcma_host_pci_probe(struct pci_dev *dev,
                pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
 
        /* SSB needed additional powering up, do we have any AMBA PCI cards? */
-       if (!pci_is_pcie(dev))
-               bcma_err(bus, "PCI card detected, report problems.\n");
+       if (!pci_is_pcie(dev)) {
+               bcma_err(bus, "PCI card detected, they are not supported.\n");
+               err = -ENXIO;
+               goto err_pci_release_regions;
+       }
 
        /* Map MMIO */
        err = -ENOMEM;
@@ -269,6 +272,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,
 
 static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
+       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4313) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
index 025c41d3cb335b8f6df1a683a7e3080dd0a62aa5..14a9d1912318b99fe764108420b143159c2bca32 100644 (file)
@@ -1,5 +1,5 @@
 /* Copyright (c) 2013 Coraid, Inc.  See COPYING for GPL terms. */
-#define VERSION "83"
+#define VERSION "85"
 #define AOE_MAJOR 152
 #define DEVICE_NAME "aoe"
 
@@ -169,6 +169,7 @@ struct aoedev {
        ulong ref;
        struct work_struct work;/* disk create work struct */
        struct gendisk *gd;
+       struct dentry *debugfs;
        struct request_queue *blkq;
        struct hd_geometry geo;
        sector_t ssize;
@@ -206,6 +207,7 @@ struct ktstate {
 int aoeblk_init(void);
 void aoeblk_exit(void);
 void aoeblk_gdalloc(void *);
+void aoedisk_rm_debugfs(struct aoedev *d);
 void aoedisk_rm_sysfs(struct aoedev *d);
 
 int aoechr_init(void);
index 916d9ed5c8aa6d1f1ae3873a924f056015cd651c..dd73e1ff1759c902db1734ac94975abea11e1b02 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012 Coraid, Inc.  See COPYING for GPL terms. */
+/* Copyright (c) 2013 Coraid, Inc.  See COPYING for GPL terms. */
 /*
  * aoeblk.c
  * block device routines
 #include <linux/mutex.h>
 #include <linux/export.h>
 #include <linux/moduleparam.h>
+#include <linux/debugfs.h>
 #include <scsi/sg.h>
 #include "aoe.h"
 
 static DEFINE_MUTEX(aoeblk_mutex);
 static struct kmem_cache *buf_pool_cache;
+static struct dentry *aoe_debugfs_dir;
 
 /* GPFS needs a larger value than the default. */
 static int aoe_maxsectors;
@@ -108,6 +110,55 @@ static ssize_t aoedisk_show_payload(struct device *dev,
        return snprintf(page, PAGE_SIZE, "%lu\n", d->maxbcnt);
 }
 
+static int aoedisk_debugfs_show(struct seq_file *s, void *ignored)
+{
+       struct aoedev *d;
+       struct aoetgt **t, **te;
+       struct aoeif *ifp, *ife;
+       unsigned long flags;
+       char c;
+
+       d = s->private;
+       seq_printf(s, "rttavg: %d rttdev: %d\n",
+               d->rttavg >> RTTSCALE,
+               d->rttdev >> RTTDSCALE);
+       seq_printf(s, "nskbpool: %d\n", skb_queue_len(&d->skbpool));
+       seq_printf(s, "kicked: %ld\n", d->kicked);
+       seq_printf(s, "maxbcnt: %ld\n", d->maxbcnt);
+       seq_printf(s, "ref: %ld\n", d->ref);
+
+       spin_lock_irqsave(&d->lock, flags);
+       t = d->targets;
+       te = t + d->ntargets;
+       for (; t < te && *t; t++) {
+               c = '\t';
+               seq_printf(s, "falloc: %ld\n", (*t)->falloc);
+               seq_printf(s, "ffree: %p\n",
+                       list_empty(&(*t)->ffree) ? NULL : (*t)->ffree.next);
+               seq_printf(s, "%pm:%d:%d:%d\n", (*t)->addr, (*t)->nout,
+                       (*t)->maxout, (*t)->nframes);
+               seq_printf(s, "\tssthresh:%d\n", (*t)->ssthresh);
+               seq_printf(s, "\ttaint:%d\n", (*t)->taint);
+               seq_printf(s, "\tr:%d\n", (*t)->rpkts);
+               seq_printf(s, "\tw:%d\n", (*t)->wpkts);
+               ifp = (*t)->ifs;
+               ife = ifp + ARRAY_SIZE((*t)->ifs);
+               for (; ifp->nd && ifp < ife; ifp++) {
+                       seq_printf(s, "%c%s", c, ifp->nd->name);
+                       c = ',';
+               }
+               seq_puts(s, "\n");
+       }
+       spin_unlock_irqrestore(&d->lock, flags);
+
+       return 0;
+}
+
+static int aoe_debugfs_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, aoedisk_debugfs_show, inode->i_private);
+}
+
 static DEVICE_ATTR(state, S_IRUGO, aoedisk_show_state, NULL);
 static DEVICE_ATTR(mac, S_IRUGO, aoedisk_show_mac, NULL);
 static DEVICE_ATTR(netif, S_IRUGO, aoedisk_show_netif, NULL);
@@ -130,6 +181,44 @@ static const struct attribute_group attr_group = {
        .attrs = aoe_attrs,
 };
 
+static const struct file_operations aoe_debugfs_fops = {
+       .open = aoe_debugfs_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+static void
+aoedisk_add_debugfs(struct aoedev *d)
+{
+       struct dentry *entry;
+       char *p;
+
+       if (aoe_debugfs_dir == NULL)
+               return;
+       p = strchr(d->gd->disk_name, '/');
+       if (p == NULL)
+               p = d->gd->disk_name;
+       else
+               p++;
+       BUG_ON(*p == '\0');
+       entry = debugfs_create_file(p, 0444, aoe_debugfs_dir, d,
+                                   &aoe_debugfs_fops);
+       if (IS_ERR_OR_NULL(entry)) {
+               pr_info("aoe: cannot create debugfs file for %s\n",
+                       d->gd->disk_name);
+               return;
+       }
+       BUG_ON(d->debugfs);
+       d->debugfs = entry;
+}
+void
+aoedisk_rm_debugfs(struct aoedev *d)
+{
+       debugfs_remove(d->debugfs);
+       d->debugfs = NULL;
+}
+
 static int
 aoedisk_add_sysfs(struct aoedev *d)
 {
@@ -330,6 +419,7 @@ aoeblk_gdalloc(void *vp)
 
        add_disk(gd);
        aoedisk_add_sysfs(d);
+       aoedisk_add_debugfs(d);
 
        spin_lock_irqsave(&d->lock, flags);
        WARN_ON(!(d->flags & DEVFL_GD_NOW));
@@ -351,6 +441,8 @@ err:
 void
 aoeblk_exit(void)
 {
+       debugfs_remove_recursive(aoe_debugfs_dir);
+       aoe_debugfs_dir = NULL;
        kmem_cache_destroy(buf_pool_cache);
 }
 
@@ -362,7 +454,11 @@ aoeblk_init(void)
                                           0, 0, NULL);
        if (buf_pool_cache == NULL)
                return -ENOMEM;
-
+       aoe_debugfs_dir = debugfs_create_dir("aoe", NULL);
+       if (IS_ERR_OR_NULL(aoe_debugfs_dir)) {
+               pr_info("aoe: cannot create debugfs directory\n");
+               aoe_debugfs_dir = NULL;
+       }
        return 0;
 }
 
index 4d45dba7fb8f9f1c6e97d8fa4192ff4e63d6230d..d2515435e23f2f87215558ec703f5a625ab8ac80 100644 (file)
@@ -380,7 +380,6 @@ aoecmd_ata_rw(struct aoedev *d)
 {
        struct frame *f;
        struct buf *buf;
-       struct aoetgt *t;
        struct sk_buff *skb;
        struct sk_buff_head queue;
        ulong bcnt, fbcnt;
@@ -391,7 +390,6 @@ aoecmd_ata_rw(struct aoedev *d)
        f = newframe(d);
        if (f == NULL)
                return 0;
-       t = *d->tgt;
        bcnt = d->maxbcnt;
        if (bcnt == 0)
                bcnt = DEFAULTBCNT;
@@ -485,7 +483,6 @@ resend(struct aoedev *d, struct frame *f)
        struct sk_buff *skb;
        struct sk_buff_head queue;
        struct aoe_hdr *h;
-       struct aoe_atahdr *ah;
        struct aoetgt *t;
        char buf[128];
        u32 n;
@@ -500,7 +497,6 @@ resend(struct aoedev *d, struct frame *f)
                return;
        }
        h = (struct aoe_hdr *) skb_mac_header(skb);
-       ah = (struct aoe_atahdr *) (h+1);
 
        if (!(f->flags & FFL_PROBE)) {
                snprintf(buf, sizeof(buf),
index 784c92e038d1461de3b2048fc263bf55a3e758a6..e774c50b684273557767da0f72693f981eabac95 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/bitmap.h>
 #include <linux/kdev_t.h>
 #include <linux/moduleparam.h>
+#include <linux/string.h>
 #include "aoe.h"
 
 static void dummy_timer(ulong);
@@ -241,16 +242,12 @@ aoedev_downdev(struct aoedev *d)
 static int
 user_req(char *s, size_t slen, struct aoedev *d)
 {
-       char *p;
+       const char *p;
        size_t lim;
 
        if (!d->gd)
                return 0;
-       p = strrchr(d->gd->disk_name, '/');
-       if (!p)
-               p = d->gd->disk_name;
-       else
-               p += 1;
+       p = kbasename(d->gd->disk_name);
        lim = sizeof(d->gd->disk_name);
        lim -= p - d->gd->disk_name;
        if (slen < lim)
@@ -278,6 +275,7 @@ freedev(struct aoedev *d)
 
        del_timer_sync(&d->timer);
        if (d->gd) {
+               aoedisk_rm_debugfs(d);
                aoedisk_rm_sysfs(d);
                del_gendisk(d->gd);
                put_disk(d->gd);
index 62b6c2cc80b5e9d7ef68a7ff84a447e24bb7ade5..d2d95ff5353b08a4f49d1c3da4179090751851bf 100644 (file)
@@ -4257,6 +4257,13 @@ static void cciss_find_board_params(ctlr_info_t *h)
        cciss_get_max_perf_mode_cmds(h);
        h->nr_cmds = h->max_commands - 4 - cciss_tape_cmds;
        h->maxsgentries = readl(&(h->cfgtable->MaxSGElements));
+       /*
+        * The P600 may exhibit poor performnace under some workloads
+        * if we use the value in the configuration table. Limit this
+        * controller to MAXSGENTRIES (32) instead.
+        */
+       if (h->board_id == 0x3225103C)
+               h->maxsgentries = MAXSGENTRIES;
        /*
         * Limit in-command s/g elements to 32 save dma'able memory.
         * Howvever spec says if 0, use 31
index a56cfcd5d648c928401a56052243b61805ca7f4c..77a60bedd7a3216d1a10c7b8e37ca2d35ff22bf8 100644 (file)
@@ -636,7 +636,7 @@ ok_to_write:
                mg_request(host->breq);
 }
 
-void mg_times_out(unsigned long data)
+static void mg_times_out(unsigned long data)
 {
        struct mg_host *host = (struct mg_host *)data;
        char *name;
index 1fca1f996b45e478f781da6b4414b57e90181d3e..0ba837fc62a874511a910dd077feea2f26dfbd37 100644 (file)
@@ -4,6 +4,6 @@
 
 config BLK_DEV_PCIESSD_MTIP32XX
        tristate "Block Device Driver for Micron PCIe SSDs"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        help
           This enables the block driver for Micron PCIe SSDs.
index ce79a590b45bff7c9c9e3e5ed206f1d7342c1a55..da52092980e2312987b6a1040df5c0ba444852c3 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/poison.h>
+#include <linux/ptrace.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -79,7 +80,9 @@ struct nvme_queue {
        u16 sq_head;
        u16 sq_tail;
        u16 cq_head;
-       u16 cq_phase;
+       u8 cq_phase;
+       u8 cqe_seen;
+       u8 q_suspended;
        unsigned long cmdid_data[];
 };
 
@@ -115,6 +118,11 @@ static struct nvme_cmd_info *nvme_cmd_info(struct nvme_queue *nvmeq)
        return (void *)&nvmeq->cmdid_data[BITS_TO_LONGS(nvmeq->q_depth)];
 }
 
+static unsigned nvme_queue_extra(int depth)
+{
+       return DIV_ROUND_UP(depth, 8) + (depth * sizeof(struct nvme_cmd_info));
+}
+
 /**
  * alloc_cmdid() - Allocate a Command ID
  * @nvmeq: The queue that will be used for this command
@@ -285,6 +293,7 @@ nvme_alloc_iod(unsigned nseg, unsigned nbytes, gfp_t gfp)
                iod->npages = -1;
                iod->length = nbytes;
                iod->nents = 0;
+               iod->start_time = jiffies;
        }
 
        return iod;
@@ -308,6 +317,30 @@ void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
        kfree(iod);
 }
 
+static void nvme_start_io_acct(struct bio *bio)
+{
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+       const int rw = bio_data_dir(bio);
+       int cpu = part_stat_lock();
+       part_round_stats(cpu, &disk->part0);
+       part_stat_inc(cpu, &disk->part0, ios[rw]);
+       part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio));
+       part_inc_in_flight(&disk->part0, rw);
+       part_stat_unlock();
+}
+
+static void nvme_end_io_acct(struct bio *bio, unsigned long start_time)
+{
+       struct gendisk *disk = bio->bi_bdev->bd_disk;
+       const int rw = bio_data_dir(bio);
+       unsigned long duration = jiffies - start_time;
+       int cpu = part_stat_lock();
+       part_stat_add(cpu, &disk->part0, ticks[rw], duration);
+       part_round_stats(cpu, &disk->part0);
+       part_dec_in_flight(&disk->part0, rw);
+       part_stat_unlock();
+}
+
 static void bio_completion(struct nvme_dev *dev, void *ctx,
                                                struct nvme_completion *cqe)
 {
@@ -315,9 +348,11 @@ static void bio_completion(struct nvme_dev *dev, void *ctx,
        struct bio *bio = iod->private;
        u16 status = le16_to_cpup(&cqe->status) >> 1;
 
-       if (iod->nents)
+       if (iod->nents) {
                dma_unmap_sg(&dev->pci_dev->dev, iod->sg, iod->nents,
                        bio_data_dir(bio) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               nvme_end_io_acct(bio, iod->start_time);
+       }
        nvme_free_iod(dev, iod);
        if (status)
                bio_endio(bio, -EIO);
@@ -422,10 +457,8 @@ static void nvme_bio_pair_endio(struct bio *bio, int err)
 
        if (atomic_dec_and_test(&bp->cnt)) {
                bio_endio(bp->parent, bp->err);
-               if (bp->bv1)
-                       kfree(bp->bv1);
-               if (bp->bv2)
-                       kfree(bp->bv2);
+               kfree(bp->bv1);
+               kfree(bp->bv2);
                kfree(bp);
        }
 }
@@ -695,6 +728,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        cmnd->rw.control = cpu_to_le16(control);
        cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
 
+       nvme_start_io_acct(bio);
        if (++nvmeq->sq_tail == nvmeq->q_depth)
                nvmeq->sq_tail = 0;
        writel(nvmeq->sq_tail, nvmeq->q_db);
@@ -709,26 +743,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        return result;
 }
 
-static void nvme_make_request(struct request_queue *q, struct bio *bio)
-{
-       struct nvme_ns *ns = q->queuedata;
-       struct nvme_queue *nvmeq = get_nvmeq(ns->dev);
-       int result = -EBUSY;
-
-       spin_lock_irq(&nvmeq->q_lock);
-       if (bio_list_empty(&nvmeq->sq_cong))
-               result = nvme_submit_bio_queue(nvmeq, ns, bio);
-       if (unlikely(result)) {
-               if (bio_list_empty(&nvmeq->sq_cong))
-                       add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait);
-               bio_list_add(&nvmeq->sq_cong, bio);
-       }
-
-       spin_unlock_irq(&nvmeq->q_lock);
-       put_nvmeq(nvmeq);
-}
-
-static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)
+static int nvme_process_cq(struct nvme_queue *nvmeq)
 {
        u16 head, phase;
 
@@ -758,13 +773,40 @@ static irqreturn_t nvme_process_cq(struct nvme_queue *nvmeq)
         * a big problem.
         */
        if (head == nvmeq->cq_head && phase == nvmeq->cq_phase)
-               return IRQ_NONE;
+               return 0;
 
        writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride));
        nvmeq->cq_head = head;
        nvmeq->cq_phase = phase;
 
-       return IRQ_HANDLED;
+       nvmeq->cqe_seen = 1;
+       return 1;
+}
+
+static void nvme_make_request(struct request_queue *q, struct bio *bio)
+{
+       struct nvme_ns *ns = q->queuedata;
+       struct nvme_queue *nvmeq = get_nvmeq(ns->dev);
+       int result = -EBUSY;
+
+       if (!nvmeq) {
+               put_nvmeq(NULL);
+               bio_endio(bio, -EIO);
+               return;
+       }
+
+       spin_lock_irq(&nvmeq->q_lock);
+       if (!nvmeq->q_suspended && bio_list_empty(&nvmeq->sq_cong))
+               result = nvme_submit_bio_queue(nvmeq, ns, bio);
+       if (unlikely(result)) {
+               if (bio_list_empty(&nvmeq->sq_cong))
+                       add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait);
+               bio_list_add(&nvmeq->sq_cong, bio);
+       }
+
+       nvme_process_cq(nvmeq);
+       spin_unlock_irq(&nvmeq->q_lock);
+       put_nvmeq(nvmeq);
 }
 
 static irqreturn_t nvme_irq(int irq, void *data)
@@ -772,7 +814,9 @@ static irqreturn_t nvme_irq(int irq, void *data)
        irqreturn_t result;
        struct nvme_queue *nvmeq = data;
        spin_lock(&nvmeq->q_lock);
-       result = nvme_process_cq(nvmeq);
+       nvme_process_cq(nvmeq);
+       result = nvmeq->cqe_seen ? IRQ_HANDLED : IRQ_NONE;
+       nvmeq->cqe_seen = 0;
        spin_unlock(&nvmeq->q_lock);
        return result;
 }
@@ -986,8 +1030,15 @@ static void nvme_cancel_ios(struct nvme_queue *nvmeq, bool timeout)
        }
 }
 
-static void nvme_free_queue_mem(struct nvme_queue *nvmeq)
+static void nvme_free_queue(struct nvme_queue *nvmeq)
 {
+       spin_lock_irq(&nvmeq->q_lock);
+       while (bio_list_peek(&nvmeq->sq_cong)) {
+               struct bio *bio = bio_list_pop(&nvmeq->sq_cong);
+               bio_endio(bio, -EIO);
+       }
+       spin_unlock_irq(&nvmeq->q_lock);
+
        dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
                                (void *)nvmeq->cqes, nvmeq->cq_dma_addr);
        dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
@@ -995,17 +1046,28 @@ static void nvme_free_queue_mem(struct nvme_queue *nvmeq)
        kfree(nvmeq);
 }
 
-static void nvme_free_queue(struct nvme_dev *dev, int qid)
+static void nvme_free_queues(struct nvme_dev *dev)
+{
+       int i;
+
+       for (i = dev->queue_count - 1; i >= 0; i--) {
+               nvme_free_queue(dev->queues[i]);
+               dev->queue_count--;
+               dev->queues[i] = NULL;
+       }
+}
+
+static void nvme_disable_queue(struct nvme_dev *dev, int qid)
 {
        struct nvme_queue *nvmeq = dev->queues[qid];
        int vector = dev->entry[nvmeq->cq_vector].vector;
 
        spin_lock_irq(&nvmeq->q_lock);
-       nvme_cancel_ios(nvmeq, false);
-       while (bio_list_peek(&nvmeq->sq_cong)) {
-               struct bio *bio = bio_list_pop(&nvmeq->sq_cong);
-               bio_endio(bio, -EIO);
+       if (nvmeq->q_suspended) {
+               spin_unlock_irq(&nvmeq->q_lock);
+               return;
        }
+       nvmeq->q_suspended = 1;
        spin_unlock_irq(&nvmeq->q_lock);
 
        irq_set_affinity_hint(vector, NULL);
@@ -1017,15 +1079,17 @@ static void nvme_free_queue(struct nvme_dev *dev, int qid)
                adapter_delete_cq(dev, qid);
        }
 
-       nvme_free_queue_mem(nvmeq);
+       spin_lock_irq(&nvmeq->q_lock);
+       nvme_process_cq(nvmeq);
+       nvme_cancel_ios(nvmeq, false);
+       spin_unlock_irq(&nvmeq->q_lock);
 }
 
 static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
                                                        int depth, int vector)
 {
        struct device *dmadev = &dev->pci_dev->dev;
-       unsigned extra = DIV_ROUND_UP(depth, 8) + (depth *
-                                               sizeof(struct nvme_cmd_info));
+       unsigned extra = nvme_queue_extra(depth);
        struct nvme_queue *nvmeq = kzalloc(sizeof(*nvmeq) + extra, GFP_KERNEL);
        if (!nvmeq)
                return NULL;
@@ -1052,6 +1116,8 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
        nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)];
        nvmeq->q_depth = depth;
        nvmeq->cq_vector = vector;
+       nvmeq->q_suspended = 1;
+       dev->queue_count++;
 
        return nvmeq;
 
@@ -1075,18 +1141,29 @@ static int queue_request_irq(struct nvme_dev *dev, struct nvme_queue *nvmeq,
                                IRQF_DISABLED | IRQF_SHARED, name, nvmeq);
 }
 
-static struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, int qid,
-                                           int cq_size, int vector)
+static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid)
 {
-       int result;
-       struct nvme_queue *nvmeq = nvme_alloc_queue(dev, qid, cq_size, vector);
+       struct nvme_dev *dev = nvmeq->dev;
+       unsigned extra = nvme_queue_extra(nvmeq->q_depth);
 
-       if (!nvmeq)
-               return ERR_PTR(-ENOMEM);
+       nvmeq->sq_tail = 0;
+       nvmeq->cq_head = 0;
+       nvmeq->cq_phase = 1;
+       nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)];
+       memset(nvmeq->cmdid_data, 0, extra);
+       memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth));
+       nvme_cancel_ios(nvmeq, false);
+       nvmeq->q_suspended = 0;
+}
+
+static int nvme_create_queue(struct nvme_queue *nvmeq, int qid)
+{
+       struct nvme_dev *dev = nvmeq->dev;
+       int result;
 
        result = adapter_alloc_cq(dev, qid, nvmeq);
        if (result < 0)
-               goto free_nvmeq;
+               return result;
 
        result = adapter_alloc_sq(dev, qid, nvmeq);
        if (result < 0)
@@ -1096,19 +1173,17 @@ static struct nvme_queue *nvme_create_queue(struct nvme_dev *dev, int qid,
        if (result < 0)
                goto release_sq;
 
-       return nvmeq;
+       spin_lock(&nvmeq->q_lock);
+       nvme_init_queue(nvmeq, qid);
+       spin_unlock(&nvmeq->q_lock);
+
+       return result;
 
  release_sq:
        adapter_delete_sq(dev, qid);
  release_cq:
        adapter_delete_cq(dev, qid);
- free_nvmeq:
-       dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth),
-                               (void *)nvmeq->cqes, nvmeq->cq_dma_addr);
-       dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth),
-                                       nvmeq->sq_cmds, nvmeq->sq_dma_addr);
-       kfree(nvmeq);
-       return ERR_PTR(result);
+       return result;
 }
 
 static int nvme_wait_ready(struct nvme_dev *dev, u64 cap, bool enabled)
@@ -1152,6 +1227,30 @@ static int nvme_enable_ctrl(struct nvme_dev *dev, u64 cap)
        return nvme_wait_ready(dev, cap, true);
 }
 
+static int nvme_shutdown_ctrl(struct nvme_dev *dev)
+{
+       unsigned long timeout;
+       u32 cc;
+
+       cc = (readl(&dev->bar->cc) & ~NVME_CC_SHN_MASK) | NVME_CC_SHN_NORMAL;
+       writel(cc, &dev->bar->cc);
+
+       timeout = 2 * HZ + jiffies;
+       while ((readl(&dev->bar->csts) & NVME_CSTS_SHST_MASK) !=
+                                                       NVME_CSTS_SHST_CMPLT) {
+               msleep(100);
+               if (fatal_signal_pending(current))
+                       return -EINTR;
+               if (time_after(jiffies, timeout)) {
+                       dev_err(&dev->pci_dev->dev,
+                               "Device shutdown incomplete; abort shutdown\n");
+                       return -ENODEV;
+               }
+       }
+
+       return 0;
+}
+
 static int nvme_configure_admin_queue(struct nvme_dev *dev)
 {
        int result;
@@ -1159,16 +1258,17 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
        u64 cap = readq(&dev->bar->cap);
        struct nvme_queue *nvmeq;
 
-       dev->dbs = ((void __iomem *)dev->bar) + 4096;
-       dev->db_stride = NVME_CAP_STRIDE(cap);
-
        result = nvme_disable_ctrl(dev, cap);
        if (result < 0)
                return result;
 
-       nvmeq = nvme_alloc_queue(dev, 0, 64, 0);
-       if (!nvmeq)
-               return -ENOMEM;
+       nvmeq = dev->queues[0];
+       if (!nvmeq) {
+               nvmeq = nvme_alloc_queue(dev, 0, 64, 0);
+               if (!nvmeq)
+                       return -ENOMEM;
+               dev->queues[0] = nvmeq;
+       }
 
        aqa = nvmeq->q_depth - 1;
        aqa |= aqa << 16;
@@ -1185,17 +1285,15 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
 
        result = nvme_enable_ctrl(dev, cap);
        if (result)
-               goto free_q;
+               return result;
 
        result = queue_request_irq(dev, nvmeq, "nvme admin");
        if (result)
-               goto free_q;
-
-       dev->queues[0] = nvmeq;
-       return result;
+               return result;
 
- free_q:
-       nvme_free_queue_mem(nvmeq);
+       spin_lock(&nvmeq->q_lock);
+       nvme_init_queue(nvmeq, 0);
+       spin_unlock(&nvmeq->q_lock);
        return result;
 }
 
@@ -1314,7 +1412,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        c.rw.appmask = cpu_to_le16(io.appmask);
 
        if (meta_len) {
-               meta_iod = nvme_map_user_pages(dev, io.opcode & 1, io.metadata, meta_len);
+               meta_iod = nvme_map_user_pages(dev, io.opcode & 1, io.metadata,
+                                                               meta_len);
                if (IS_ERR(meta_iod)) {
                        status = PTR_ERR(meta_iod);
                        meta_iod = NULL;
@@ -1356,6 +1455,8 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
        put_nvmeq(nvmeq);
        if (length != (io.nblocks + 1) << ns->lba_shift)
                status = -ENOMEM;
+       else if (!nvmeq || nvmeq->q_suspended)
+               status = -EBUSY;
        else
                status = nvme_submit_sync_cmd(nvmeq, &c, NULL, NVME_IO_TIMEOUT);
 
@@ -1453,6 +1554,7 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
 
        switch (cmd) {
        case NVME_IOCTL_ID:
+               force_successful_syscall_return();
                return ns->ns_id;
        case NVME_IOCTL_ADMIN_CMD:
                return nvme_user_admin_cmd(ns->dev, (void __user *)arg);
@@ -1506,10 +1608,12 @@ static int nvme_kthread(void *data)
                                if (!nvmeq)
                                        continue;
                                spin_lock_irq(&nvmeq->q_lock);
-                               if (nvme_process_cq(nvmeq))
-                                       printk("process_cq did something\n");
+                               if (nvmeq->q_suspended)
+                                       goto unlock;
+                               nvme_process_cq(nvmeq);
                                nvme_cancel_ios(nvmeq, true);
                                nvme_resubmit_bios(nvmeq);
+ unlock:
                                spin_unlock_irq(&nvmeq->q_lock);
                        }
                }
@@ -1556,7 +1660,7 @@ static void nvme_config_discard(struct nvme_ns *ns)
        queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
 }
 
-static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, int nsid,
+static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid,
                        struct nvme_id_ns *id, struct nvme_lba_range_type *rt)
 {
        struct nvme_ns *ns;
@@ -1631,14 +1735,19 @@ static int set_queue_count(struct nvme_dev *dev, int count)
        status = nvme_set_features(dev, NVME_FEAT_NUM_QUEUES, q_count, 0,
                                                                &result);
        if (status)
-               return -EIO;
+               return status < 0 ? -EIO : -EBUSY;
        return min(result & 0xffff, result >> 16) + 1;
 }
 
+static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues)
+{
+       return 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3));
+}
+
 static int nvme_setup_io_queues(struct nvme_dev *dev)
 {
        struct pci_dev *pdev = dev->pci_dev;
-       int result, cpu, i, nr_io_queues, db_bar_size, q_depth, q_count;
+       int result, cpu, i, vecs, nr_io_queues, size, q_depth;
 
        nr_io_queues = num_online_cpus();
        result = set_queue_count(dev, nr_io_queues);
@@ -1647,53 +1756,80 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
        if (result < nr_io_queues)
                nr_io_queues = result;
 
-       q_count = nr_io_queues;
-       /* Deregister the admin queue's interrupt */
-       free_irq(dev->entry[0].vector, dev->queues[0]);
-
-       db_bar_size = 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3));
-       if (db_bar_size > 8192) {
+       size = db_bar_size(dev, nr_io_queues);
+       if (size > 8192) {
                iounmap(dev->bar);
-               dev->bar = ioremap(pci_resource_start(pdev, 0), db_bar_size);
+               do {
+                       dev->bar = ioremap(pci_resource_start(pdev, 0), size);
+                       if (dev->bar)
+                               break;
+                       if (!--nr_io_queues)
+                               return -ENOMEM;
+                       size = db_bar_size(dev, nr_io_queues);
+               } while (1);
                dev->dbs = ((void __iomem *)dev->bar) + 4096;
                dev->queues[0]->q_db = dev->dbs;
        }
 
-       for (i = 0; i < nr_io_queues; i++)
+       /* Deregister the admin queue's interrupt */
+       free_irq(dev->entry[0].vector, dev->queues[0]);
+
+       vecs = nr_io_queues;
+       for (i = 0; i < vecs; i++)
                dev->entry[i].entry = i;
        for (;;) {
-               result = pci_enable_msix(pdev, dev->entry, nr_io_queues);
-               if (result == 0) {
-                       break;
-               } else if (result > 0) {
-                       nr_io_queues = result;
-                       continue;
-               } else {
-                       nr_io_queues = 0;
+               result = pci_enable_msix(pdev, dev->entry, vecs);
+               if (result <= 0)
                        break;
-               }
+               vecs = result;
        }
 
-       if (nr_io_queues == 0) {
-               nr_io_queues = q_count;
+       if (result < 0) {
+               vecs = nr_io_queues;
+               if (vecs > 32)
+                       vecs = 32;
                for (;;) {
-                       result = pci_enable_msi_block(pdev, nr_io_queues);
+                       result = pci_enable_msi_block(pdev, vecs);
                        if (result == 0) {
-                               for (i = 0; i < nr_io_queues; i++)
+                               for (i = 0; i < vecs; i++)
                                        dev->entry[i].vector = i + pdev->irq;
                                break;
-                       } else if (result > 0) {
-                               nr_io_queues = result;
-                               continue;
-                       } else {
-                               nr_io_queues = 1;
+                       } else if (result < 0) {
+                               vecs = 1;
                                break;
                        }
+                       vecs = result;
                }
        }
 
+       /*
+        * Should investigate if there's a performance win from allocating
+        * more queues than interrupt vectors; it might allow the submission
+        * path to scale better, even if the receive path is limited by the
+        * number of interrupts.
+        */
+       nr_io_queues = vecs;
+
        result = queue_request_irq(dev, dev->queues[0], "nvme admin");
-       /* XXX: handle failure here */
+       if (result) {
+               dev->queues[0]->q_suspended = 1;
+               goto free_queues;
+       }
+
+       /* Free previously allocated queues that are no longer usable */
+       spin_lock(&dev_list_lock);
+       for (i = dev->queue_count - 1; i > nr_io_queues; i--) {
+               struct nvme_queue *nvmeq = dev->queues[i];
+
+               spin_lock(&nvmeq->q_lock);
+               nvme_cancel_ios(nvmeq, false);
+               spin_unlock(&nvmeq->q_lock);
+
+               nvme_free_queue(nvmeq);
+               dev->queue_count--;
+               dev->queues[i] = NULL;
+       }
+       spin_unlock(&dev_list_lock);
 
        cpu = cpumask_first(cpu_online_mask);
        for (i = 0; i < nr_io_queues; i++) {
@@ -1703,11 +1839,12 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
 
        q_depth = min_t(int, NVME_CAP_MQES(readq(&dev->bar->cap)) + 1,
                                                                NVME_Q_DEPTH);
-       for (i = 0; i < nr_io_queues; i++) {
-               dev->queues[i + 1] = nvme_create_queue(dev, i + 1, q_depth, i);
-               if (IS_ERR(dev->queues[i + 1]))
-                       return PTR_ERR(dev->queues[i + 1]);
-               dev->queue_count++;
+       for (i = dev->queue_count - 1; i < nr_io_queues; i++) {
+               dev->queues[i + 1] = nvme_alloc_queue(dev, i + 1, q_depth, i);
+               if (!dev->queues[i + 1]) {
+                       result = -ENOMEM;
+                       goto free_queues;
+               }
        }
 
        for (; i < num_possible_cpus(); i++) {
@@ -1715,15 +1852,20 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)
                dev->queues[i + 1] = dev->queues[target + 1];
        }
 
-       return 0;
-}
+       for (i = 1; i < dev->queue_count; i++) {
+               result = nvme_create_queue(dev->queues[i], i);
+               if (result) {
+                       for (--i; i > 0; i--)
+                               nvme_disable_queue(dev, i);
+                       goto free_queues;
+               }
+       }
 
-static void nvme_free_queues(struct nvme_dev *dev)
-{
-       int i;
+       return 0;
 
-       for (i = dev->queue_count - 1; i >= 0; i--)
-               nvme_free_queue(dev, i);
+ free_queues:
+       nvme_free_queues(dev);
+       return result;
 }
 
 /*
@@ -1734,7 +1876,8 @@ static void nvme_free_queues(struct nvme_dev *dev)
  */
 static int nvme_dev_add(struct nvme_dev *dev)
 {
-       int res, nn, i;
+       int res;
+       unsigned nn, i;
        struct nvme_ns *ns;
        struct nvme_id_ctrl *ctrl;
        struct nvme_id_ns *id_ns;
@@ -1742,10 +1885,6 @@ static int nvme_dev_add(struct nvme_dev *dev)
        dma_addr_t dma_addr;
        int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
 
-       res = nvme_setup_io_queues(dev);
-       if (res)
-               return res;
-
        mem = dma_alloc_coherent(&dev->pci_dev->dev, 8192, &dma_addr,
                                                                GFP_KERNEL);
        if (!mem)
@@ -1796,23 +1935,86 @@ static int nvme_dev_add(struct nvme_dev *dev)
        return res;
 }
 
-static int nvme_dev_remove(struct nvme_dev *dev)
+static int nvme_dev_map(struct nvme_dev *dev)
 {
-       struct nvme_ns *ns, *next;
+       int bars, result = -ENOMEM;
+       struct pci_dev *pdev = dev->pci_dev;
+
+       if (pci_enable_device_mem(pdev))
+               return result;
+
+       dev->entry[0].vector = pdev->irq;
+       pci_set_master(pdev);
+       bars = pci_select_bars(pdev, IORESOURCE_MEM);
+       if (pci_request_selected_regions(pdev, bars, "nvme"))
+               goto disable_pci;
+
+       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)))
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+       else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)))
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       else
+               goto disable_pci;
+
+       pci_set_drvdata(pdev, dev);
+       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
+       if (!dev->bar)
+               goto disable;
+
+       dev->db_stride = NVME_CAP_STRIDE(readq(&dev->bar->cap));
+       dev->dbs = ((void __iomem *)dev->bar) + 4096;
+
+       return 0;
+
+ disable:
+       pci_release_regions(pdev);
+ disable_pci:
+       pci_disable_device(pdev);
+       return result;
+}
+
+static void nvme_dev_unmap(struct nvme_dev *dev)
+{
+       if (dev->pci_dev->msi_enabled)
+               pci_disable_msi(dev->pci_dev);
+       else if (dev->pci_dev->msix_enabled)
+               pci_disable_msix(dev->pci_dev);
+
+       if (dev->bar) {
+               iounmap(dev->bar);
+               dev->bar = NULL;
+       }
+
+       pci_release_regions(dev->pci_dev);
+       if (pci_is_enabled(dev->pci_dev))
+               pci_disable_device(dev->pci_dev);
+}
+
+static void nvme_dev_shutdown(struct nvme_dev *dev)
+{
+       int i;
+
+       for (i = dev->queue_count - 1; i >= 0; i--)
+               nvme_disable_queue(dev, i);
 
        spin_lock(&dev_list_lock);
-       list_del(&dev->node);
+       list_del_init(&dev->node);
        spin_unlock(&dev_list_lock);
 
+       if (dev->bar)
+               nvme_shutdown_ctrl(dev);
+       nvme_dev_unmap(dev);
+}
+
+static void nvme_dev_remove(struct nvme_dev *dev)
+{
+       struct nvme_ns *ns, *next;
+
        list_for_each_entry_safe(ns, next, &dev->namespaces, list) {
                list_del(&ns->list);
                del_gendisk(ns->disk);
                nvme_ns_free(ns);
        }
-
-       nvme_free_queues(dev);
-
-       return 0;
 }
 
 static int nvme_setup_prp_pools(struct nvme_dev *dev)
@@ -1872,15 +2074,10 @@ static void nvme_free_dev(struct kref *kref)
 {
        struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
        nvme_dev_remove(dev);
-       if (dev->pci_dev->msi_enabled)
-               pci_disable_msi(dev->pci_dev);
-       else if (dev->pci_dev->msix_enabled)
-               pci_disable_msix(dev->pci_dev);
-       iounmap(dev->bar);
+       nvme_dev_shutdown(dev);
+       nvme_free_queues(dev);
        nvme_release_instance(dev);
        nvme_release_prp_pools(dev);
-       pci_disable_device(dev->pci_dev);
-       pci_release_regions(dev->pci_dev);
        kfree(dev->queues);
        kfree(dev->entry);
        kfree(dev);
@@ -1921,9 +2118,40 @@ static const struct file_operations nvme_dev_fops = {
        .compat_ioctl   = nvme_dev_ioctl,
 };
 
+static int nvme_dev_start(struct nvme_dev *dev)
+{
+       int result;
+
+       result = nvme_dev_map(dev);
+       if (result)
+               return result;
+
+       result = nvme_configure_admin_queue(dev);
+       if (result)
+               goto unmap;
+
+       spin_lock(&dev_list_lock);
+       list_add(&dev->node, &dev_list);
+       spin_unlock(&dev_list_lock);
+
+       result = nvme_setup_io_queues(dev);
+       if (result && result != -EBUSY)
+               goto disable;
+
+       return result;
+
+ disable:
+       spin_lock(&dev_list_lock);
+       list_del_init(&dev->node);
+       spin_unlock(&dev_list_lock);
+ unmap:
+       nvme_dev_unmap(dev);
+       return result;
+}
+
 static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
-       int bars, result = -ENOMEM;
+       int result = -ENOMEM;
        struct nvme_dev *dev;
 
        dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1938,53 +2166,28 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (!dev->queues)
                goto free;
 
-       if (pci_enable_device_mem(pdev))
-               goto free;
-       pci_set_master(pdev);
-       bars = pci_select_bars(pdev, IORESOURCE_MEM);
-       if (pci_request_selected_regions(pdev, bars, "nvme"))
-               goto disable;
-
        INIT_LIST_HEAD(&dev->namespaces);
        dev->pci_dev = pdev;
-       pci_set_drvdata(pdev, dev);
-
-       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)))
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
-       else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)))
-               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-       else
-               goto disable;
-
        result = nvme_set_instance(dev);
        if (result)
-               goto disable;
-
-       dev->entry[0].vector = pdev->irq;
+               goto free;
 
        result = nvme_setup_prp_pools(dev);
        if (result)
-               goto disable_msix;
+               goto release;
 
-       dev->bar = ioremap(pci_resource_start(pdev, 0), 8192);
-       if (!dev->bar) {
-               result = -ENOMEM;
-               goto disable_msix;
+       result = nvme_dev_start(dev);
+       if (result) {
+               if (result == -EBUSY)
+                       goto create_cdev;
+               goto release_pools;
        }
 
-       result = nvme_configure_admin_queue(dev);
-       if (result)
-               goto unmap;
-       dev->queue_count++;
-
-       spin_lock(&dev_list_lock);
-       list_add(&dev->node, &dev_list);
-       spin_unlock(&dev_list_lock);
-
        result = nvme_dev_add(dev);
        if (result)
-               goto delete;
+               goto shutdown;
 
+ create_cdev:
        scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance);
        dev->miscdev.minor = MISC_DYNAMIC_MINOR;
        dev->miscdev.parent = &pdev->dev;
@@ -1999,24 +2202,13 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
  remove:
        nvme_dev_remove(dev);
- delete:
-       spin_lock(&dev_list_lock);
-       list_del(&dev->node);
-       spin_unlock(&dev_list_lock);
-
+ shutdown:
+       nvme_dev_shutdown(dev);
+ release_pools:
        nvme_free_queues(dev);
- unmap:
-       iounmap(dev->bar);
- disable_msix:
-       if (dev->pci_dev->msi_enabled)
-               pci_disable_msi(dev->pci_dev);
-       else if (dev->pci_dev->msix_enabled)
-               pci_disable_msix(dev->pci_dev);
-       nvme_release_instance(dev);
        nvme_release_prp_pools(dev);
- disable:
-       pci_disable_device(pdev);
-       pci_release_regions(pdev);
+ release:
+       nvme_release_instance(dev);
  free:
        kfree(dev->queues);
        kfree(dev->entry);
@@ -2037,8 +2229,30 @@ static void nvme_remove(struct pci_dev *pdev)
 #define nvme_link_reset NULL
 #define nvme_slot_reset NULL
 #define nvme_error_resume NULL
-#define nvme_suspend NULL
-#define nvme_resume NULL
+
+static int nvme_suspend(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct nvme_dev *ndev = pci_get_drvdata(pdev);
+
+       nvme_dev_shutdown(ndev);
+       return 0;
+}
+
+static int nvme_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct nvme_dev *ndev = pci_get_drvdata(pdev);
+       int ret;
+
+       ret = nvme_dev_start(ndev);
+       /* XXX: should remove gendisks if resume fails */
+       if (ret)
+               nvme_free_queues(ndev);
+       return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume);
 
 static const struct pci_error_handlers nvme_err_handler = {
        .error_detected = nvme_error_detected,
@@ -2062,8 +2276,9 @@ static struct pci_driver nvme_driver = {
        .id_table       = nvme_id_table,
        .probe          = nvme_probe,
        .remove         = nvme_remove,
-       .suspend        = nvme_suspend,
-       .resume         = nvme_resume,
+       .driver         = {
+               .pm     = &nvme_dev_pm_ops,
+       },
        .err_handler    = &nvme_err_handler,
 };
 
index 102de2f52b5c5fa7b4dd877121f156041bb20be7..4a4ff4eb8e233141d879fd52da3cade426b838b5 100644 (file)
@@ -933,13 +933,12 @@ static int nvme_trans_bdev_char_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
        int res = SNTI_TRANSLATION_SUCCESS;
        int xfer_len;
 
-       inq_response = kmalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH, GFP_KERNEL);
+       inq_response = kzalloc(EXTENDED_INQUIRY_DATA_PAGE_LENGTH, GFP_KERNEL);
        if (inq_response == NULL) {
                res = -ENOMEM;
                goto out_mem;
        }
 
-       memset(inq_response, 0, EXTENDED_INQUIRY_DATA_PAGE_LENGTH);
        inq_response[1] = INQ_BDEV_CHARACTERISTICS_PAGE;    /* Page Code */
        inq_response[2] = 0x00;    /* Page Length MSB */
        inq_response[3] = 0x3C;    /* Page Length LSB */
@@ -964,12 +963,11 @@ static int nvme_trans_log_supp_pages(struct nvme_ns *ns, struct sg_io_hdr *hdr,
        int xfer_len;
        u8 *log_response;
 
-       log_response = kmalloc(LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH, GFP_KERNEL);
+       log_response = kzalloc(LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH, GFP_KERNEL);
        if (log_response == NULL) {
                res = -ENOMEM;
                goto out_mem;
        }
-       memset(log_response, 0, LOG_PAGE_SUPPORTED_LOG_PAGES_LENGTH);
 
        log_response[0] = LOG_PAGE_SUPPORTED_LOG_PAGES_PAGE;
        /* Subpage=0x00, Page Length MSB=0 */
@@ -1000,12 +998,11 @@ static int nvme_trans_log_info_exceptions(struct nvme_ns *ns,
        u8 temp_c;
        u16 temp_k;
 
-       log_response = kmalloc(LOG_INFO_EXCP_PAGE_LENGTH, GFP_KERNEL);
+       log_response = kzalloc(LOG_INFO_EXCP_PAGE_LENGTH, GFP_KERNEL);
        if (log_response == NULL) {
                res = -ENOMEM;
                goto out_mem;
        }
-       memset(log_response, 0, LOG_INFO_EXCP_PAGE_LENGTH);
 
        mem = dma_alloc_coherent(&dev->pci_dev->dev,
                                        sizeof(struct nvme_smart_log),
@@ -1069,12 +1066,11 @@ static int nvme_trans_log_temperature(struct nvme_ns *ns, struct sg_io_hdr *hdr,
        u8 temp_c_cur, temp_c_thresh;
        u16 temp_k;
 
-       log_response = kmalloc(LOG_TEMP_PAGE_LENGTH, GFP_KERNEL);
+       log_response = kzalloc(LOG_TEMP_PAGE_LENGTH, GFP_KERNEL);
        if (log_response == NULL) {
                res = -ENOMEM;
                goto out_mem;
        }
-       memset(log_response, 0, LOG_TEMP_PAGE_LENGTH);
 
        mem = dma_alloc_coherent(&dev->pci_dev->dev,
                                        sizeof(struct nvme_smart_log),
@@ -1380,12 +1376,11 @@ static int nvme_trans_mode_page_create(struct nvme_ns *ns,
        blk_desc_offset = mph_size;
        mode_pages_offset_1 = blk_desc_offset + blk_desc_len;
 
-       response = kmalloc(resp_size, GFP_KERNEL);
+       response = kzalloc(resp_size, GFP_KERNEL);
        if (response == NULL) {
                res = -ENOMEM;
                goto out_mem;
        }
-       memset(response, 0, resp_size);
 
        res = nvme_trans_fill_mode_parm_hdr(&response[0], mph_size, cdb10,
                                        llbaa, mode_data_length, blk_desc_len);
@@ -2480,12 +2475,11 @@ static int nvme_trans_read_capacity(struct nvme_ns *ns, struct sg_io_hdr *hdr,
        }
        id_ns = mem;
 
-       response = kmalloc(resp_size, GFP_KERNEL);
+       response = kzalloc(resp_size, GFP_KERNEL);
        if (response == NULL) {
                res = -ENOMEM;
                goto out_dma;
        }
-       memset(response, 0, resp_size);
        nvme_trans_fill_read_cap(response, id_ns, cdb16);
 
        xfer_len = min(alloc_len, resp_size);
@@ -2554,12 +2548,11 @@ static int nvme_trans_report_luns(struct nvme_ns *ns, struct sg_io_hdr *hdr,
                        goto out_dma;
                }
 
-               response = kmalloc(resp_size, GFP_KERNEL);
+               response = kzalloc(resp_size, GFP_KERNEL);
                if (response == NULL) {
                        res = -ENOMEM;
                        goto out_dma;
                }
-               memset(response, 0, resp_size);
 
                /* The first LUN ID will always be 0 per the SAM spec */
                for (lun_id = 0; lun_id < le32_to_cpu(id_ctrl->nn); lun_id++) {
@@ -2600,12 +2593,11 @@ static int nvme_trans_request_sense(struct nvme_ns *ns, struct sg_io_hdr *hdr,
 
        resp_size = ((desc_format) ? (DESC_FMT_SENSE_DATA_SIZE) :
                                        (FIXED_FMT_SENSE_DATA_SIZE));
-       response = kmalloc(resp_size, GFP_KERNEL);
+       response = kzalloc(resp_size, GFP_KERNEL);
        if (response == NULL) {
                res = -ENOMEM;
                goto out;
        }
-       memset(response, 0, resp_size);
 
        if (desc_format == DESCRIPTOR_FORMAT_SENSE_DATA_TYPE) {
                /* Descriptor Format Sense Data */
index 1bbc681688e4375aa5098bd1b99d85b38baa796e..79aa179305b5e6fc5a84c5a7e80506626cb26e38 100644 (file)
@@ -598,7 +598,7 @@ static ssize_t class_osdblk_remove(struct class *c,
        unsigned long ul;
        struct list_head *tmp;
 
-       rc = strict_strtoul(buf, 10, &ul);
+       rc = kstrtoul(buf, 10, &ul);
        if (rc)
                return rc;
 
index f5d0ea11d9fda8a4f1b8ad3f23d285bb7887250b..56188475cfd3e23f9fece3039deee7f721b8a2cf 100644 (file)
@@ -44,6 +44,8 @@
  *
  *************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/pktcdvd.h>
 #include <linux/module.h>
 #include <linux/types.h>
 
 #define DRIVER_NAME    "pktcdvd"
 
-#if PACKET_DEBUG
-#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
-#else
-#define DPRINTK(fmt, args...)
-#endif
-
-#if PACKET_DEBUG > 1
-#define VPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
-#else
-#define VPRINTK(fmt, args...)
-#endif
+#define pkt_err(pd, fmt, ...)                                          \
+       pr_err("%s: " fmt, pd->name, ##__VA_ARGS__)
+#define pkt_notice(pd, fmt, ...)                                       \
+       pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__)
+#define pkt_info(pd, fmt, ...)                                         \
+       pr_info("%s: " fmt, pd->name, ##__VA_ARGS__)
+
+#define pkt_dbg(level, pd, fmt, ...)                                   \
+do {                                                                   \
+       if (level == 2 && PACKET_DEBUG >= 2)                            \
+               pr_notice("%s: %s():" fmt,                              \
+                         pd->name, __func__, ##__VA_ARGS__);           \
+       else if (level == 1 && PACKET_DEBUG >= 1)                       \
+               pr_notice("%s: " fmt, pd->name, ##__VA_ARGS__);         \
+} while (0)
 
 #define MAX_SPEED 0xffff
 
-#define ZONE(sector, pd) (((sector) + (pd)->offset) & \
-                       ~(sector_t)((pd)->settings.size - 1))
-
 static DEFINE_MUTEX(pktcdvd_mutex);
 static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
 static struct proc_dir_entry *pkt_proc;
@@ -103,7 +106,10 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev);
 static int pkt_remove_dev(dev_t pkt_dev);
 static int pkt_seq_show(struct seq_file *m, void *p);
 
-
+static sector_t get_zone(sector_t sector, struct pktcdvd_device *pd)
+{
+       return (sector + pd->offset) & ~(sector_t)(pd->settings.size - 1);
+}
 
 /*
  * create and register a pktcdvd kernel object.
@@ -424,7 +430,7 @@ static int pkt_sysfs_init(void)
        if (ret) {
                kfree(class_pktcdvd);
                class_pktcdvd = NULL;
-               printk(DRIVER_NAME": failed to create class pktcdvd\n");
+               pr_err("failed to create class pktcdvd\n");
                return ret;
        }
        return 0;
@@ -517,7 +523,7 @@ static void pkt_bio_finished(struct pktcdvd_device *pd)
 {
        BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
        if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
-               VPRINTK(DRIVER_NAME": queue empty\n");
+               pkt_dbg(2, pd, "queue empty\n");
                atomic_set(&pd->iosched.attention, 1);
                wake_up(&pd->wqueue);
        }
@@ -734,36 +740,33 @@ out:
        return ret;
 }
 
+static const char *sense_key_string(__u8 index)
+{
+       static const char * const info[] = {
+               "No sense", "Recovered error", "Not ready",
+               "Medium error", "Hardware error", "Illegal request",
+               "Unit attention", "Data protect", "Blank check",
+       };
+
+       return index < ARRAY_SIZE(info) ? info[index] : "INVALID";
+}
+
 /*
  * A generic sense dump / resolve mechanism should be implemented across
  * all ATAPI + SCSI devices.
  */
-static void pkt_dump_sense(struct packet_command *cgc)
+static void pkt_dump_sense(struct pktcdvd_device *pd,
+                          struct packet_command *cgc)
 {
-       static char *info[9] = { "No sense", "Recovered error", "Not ready",
-                                "Medium error", "Hardware error", "Illegal request",
-                                "Unit attention", "Data protect", "Blank check" };
-       int i;
        struct request_sense *sense = cgc->sense;
 
-       printk(DRIVER_NAME":");
-       for (i = 0; i < CDROM_PACKET_SIZE; i++)
-               printk(" %02x", cgc->cmd[i]);
-       printk(" - ");
-
-       if (sense == NULL) {
-               printk("no sense\n");
-               return;
-       }
-
-       printk("sense %02x.%02x.%02x", sense->sense_key, sense->asc, sense->ascq);
-
-       if (sense->sense_key > 8) {
-               printk(" (INVALID)\n");
-               return;
-       }
-
-       printk(" (%s)\n", info[sense->sense_key]);
+       if (sense)
+               pkt_err(pd, "%*ph - sense %02x.%02x.%02x (%s)\n",
+                       CDROM_PACKET_SIZE, cgc->cmd,
+                       sense->sense_key, sense->asc, sense->ascq,
+                       sense_key_string(sense->sense_key));
+       else
+               pkt_err(pd, "%*ph - no sense\n", CDROM_PACKET_SIZE, cgc->cmd);
 }
 
 /*
@@ -806,7 +809,7 @@ static noinline_for_stack int pkt_set_speed(struct pktcdvd_device *pd,
        cgc.cmd[5] = write_speed & 0xff;
 
        if ((ret = pkt_generic_packet(pd, &cgc)))
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
 
        return ret;
 }
@@ -872,7 +875,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                                need_write_seek = 0;
                        if (need_write_seek && reads_queued) {
                                if (atomic_read(&pd->cdrw.pending_bios) > 0) {
-                                       VPRINTK(DRIVER_NAME": write, waiting\n");
+                                       pkt_dbg(2, pd, "write, waiting\n");
                                        break;
                                }
                                pkt_flush_cache(pd);
@@ -881,7 +884,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                } else {
                        if (!reads_queued && writes_queued) {
                                if (atomic_read(&pd->cdrw.pending_bios) > 0) {
-                                       VPRINTK(DRIVER_NAME": read, waiting\n");
+                                       pkt_dbg(2, pd, "read, waiting\n");
                                        break;
                                }
                                pd->iosched.writing = 1;
@@ -943,7 +946,7 @@ static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_que
                set_bit(PACKET_MERGE_SEGS, &pd->flags);
                return 0;
        } else {
-               printk(DRIVER_NAME": cdrom max_phys_segments too small\n");
+               pkt_err(pd, "cdrom max_phys_segments too small\n");
                return -EIO;
        }
 }
@@ -987,8 +990,9 @@ static void pkt_end_io_read(struct bio *bio, int err)
        struct pktcdvd_device *pd = pkt->pd;
        BUG_ON(!pd);
 
-       VPRINTK("pkt_end_io_read: bio=%p sec0=%llx sec=%llx err=%d\n", bio,
-               (unsigned long long)pkt->sector, (unsigned long long)bio->bi_sector, err);
+       pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n",
+               bio, (unsigned long long)pkt->sector,
+               (unsigned long long)bio->bi_sector, err);
 
        if (err)
                atomic_inc(&pkt->io_errors);
@@ -1005,7 +1009,7 @@ static void pkt_end_io_packet_write(struct bio *bio, int err)
        struct pktcdvd_device *pd = pkt->pd;
        BUG_ON(!pd);
 
-       VPRINTK("pkt_end_io_packet_write: id=%d, err=%d\n", pkt->id, err);
+       pkt_dbg(2, pd, "id=%d, err=%d\n", pkt->id, err);
 
        pd->stats.pkt_ended++;
 
@@ -1047,7 +1051,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        spin_unlock(&pkt->lock);
 
        if (pkt->cache_valid) {
-               VPRINTK("pkt_gather_data: zone %llx cached\n",
+               pkt_dbg(2, pd, "zone %llx cached\n",
                        (unsigned long long)pkt->sector);
                goto out_account;
        }
@@ -1070,7 +1074,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
 
                p = (f * CD_FRAMESIZE) / PAGE_SIZE;
                offset = (f * CD_FRAMESIZE) % PAGE_SIZE;
-               VPRINTK("pkt_gather_data: Adding frame %d, page:%p offs:%d\n",
+               pkt_dbg(2, pd, "Adding frame %d, page:%p offs:%d\n",
                        f, pkt->pages[p], offset);
                if (!bio_add_page(bio, pkt->pages[p], CD_FRAMESIZE, offset))
                        BUG();
@@ -1082,7 +1086,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        }
 
 out_account:
-       VPRINTK("pkt_gather_data: need %d frames for zone %llx\n",
+       pkt_dbg(2, pd, "need %d frames for zone %llx\n",
                frames_read, (unsigned long long)pkt->sector);
        pd->stats.pkt_started++;
        pd->stats.secs_rg += frames_read * (CD_FRAMESIZE >> 9);
@@ -1183,7 +1187,8 @@ static inline void pkt_set_state(struct packet_data *pkt, enum packet_data_state
                "IDLE", "WAITING", "READ_WAIT", "WRITE_WAIT", "RECOVERY", "FINISHED"
        };
        enum packet_data_state old_state = pkt->state;
-       VPRINTK("pkt %2d : s=%6llx %s -> %s\n", pkt->id, (unsigned long long)pkt->sector,
+       pkt_dbg(2, pd, "pkt %2d : s=%6llx %s -> %s\n",
+               pkt->id, (unsigned long long)pkt->sector,
                state_name[old_state], state_name[state]);
 #endif
        pkt->state = state;
@@ -1202,12 +1207,10 @@ static int pkt_handle_queue(struct pktcdvd_device *pd)
        struct rb_node *n;
        int wakeup;
 
-       VPRINTK("handle_queue\n");
-
        atomic_set(&pd->scan_queue, 0);
 
        if (list_empty(&pd->cdrw.pkt_free_list)) {
-               VPRINTK("handle_queue: no pkt\n");
+               pkt_dbg(2, pd, "no pkt\n");
                return 0;
        }
 
@@ -1224,7 +1227,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd)
        node = first_node;
        while (node) {
                bio = node->bio;
-               zone = ZONE(bio->bi_sector, pd);
+               zone = get_zone(bio->bi_sector, pd);
                list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
                        if (p->sector == zone) {
                                bio = NULL;
@@ -1244,7 +1247,7 @@ try_next_bio:
        }
        spin_unlock(&pd->lock);
        if (!bio) {
-               VPRINTK("handle_queue: no bio\n");
+               pkt_dbg(2, pd, "no bio\n");
                return 0;
        }
 
@@ -1260,12 +1263,12 @@ try_next_bio:
         * to this packet.
         */
        spin_lock(&pd->lock);
-       VPRINTK("pkt_handle_queue: looking for zone %llx\n", (unsigned long long)zone);
+       pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone);
        while ((node = pkt_rbtree_find(pd, zone)) != NULL) {
                bio = node->bio;
-               VPRINTK("pkt_handle_queue: found zone=%llx\n",
-                       (unsigned long long)ZONE(bio->bi_sector, pd));
-               if (ZONE(bio->bi_sector, pd) != zone)
+               pkt_dbg(2, pd, "found zone=%llx\n",
+                       (unsigned long long)get_zone(bio->bi_sector, pd));
+               if (get_zone(bio->bi_sector, pd) != zone)
                        break;
                pkt_rbtree_erase(pd, node);
                spin_lock(&pkt->lock);
@@ -1316,7 +1319,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
                if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
                        BUG();
        }
-       VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt);
+       pkt_dbg(2, pd, "vcnt=%d\n", pkt->w_bio->bi_vcnt);
 
        /*
         * Fill-in bvec with data from orig_bios.
@@ -1327,7 +1330,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
        pkt_set_state(pkt, PACKET_WRITE_WAIT_STATE);
        spin_unlock(&pkt->lock);
 
-       VPRINTK("pkt_start_write: Writing %d frames for zone %llx\n",
+       pkt_dbg(2, pd, "Writing %d frames for zone %llx\n",
                pkt->write_size, (unsigned long long)pkt->sector);
 
        if (test_bit(PACKET_MERGE_SEGS, &pd->flags) || (pkt->write_size < pkt->frames)) {
@@ -1359,7 +1362,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data
 {
        int uptodate;
 
-       VPRINTK("run_state_machine: pkt %d\n", pkt->id);
+       pkt_dbg(2, pd, "pkt %d\n", pkt->id);
 
        for (;;) {
                switch (pkt->state) {
@@ -1398,7 +1401,7 @@ static void pkt_run_state_machine(struct pktcdvd_device *pd, struct packet_data
                        if (pkt_start_recovery(pkt)) {
                                pkt_start_write(pd, pkt);
                        } else {
-                               VPRINTK("No recovery possible\n");
+                               pkt_dbg(2, pd, "No recovery possible\n");
                                pkt_set_state(pkt, PACKET_FINISHED_STATE);
                        }
                        break;
@@ -1419,8 +1422,6 @@ static void pkt_handle_packets(struct pktcdvd_device *pd)
 {
        struct packet_data *pkt, *next;
 
-       VPRINTK("pkt_handle_packets\n");
-
        /*
         * Run state machine for active packets
         */
@@ -1502,9 +1503,9 @@ static int kcdrwd(void *foobar)
                        if (PACKET_DEBUG > 1) {
                                int states[PACKET_NUM_STATES];
                                pkt_count_states(pd, states);
-                               VPRINTK("kcdrwd: i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
-                                       states[0], states[1], states[2], states[3],
-                                       states[4], states[5]);
+                               pkt_dbg(2, pd, "i:%d ow:%d rw:%d ww:%d rec:%d fin:%d\n",
+                                       states[0], states[1], states[2],
+                                       states[3], states[4], states[5]);
                        }
 
                        min_sleep_time = MAX_SCHEDULE_TIMEOUT;
@@ -1513,9 +1514,9 @@ static int kcdrwd(void *foobar)
                                        min_sleep_time = pkt->sleep_time;
                        }
 
-                       VPRINTK("kcdrwd: sleeping\n");
+                       pkt_dbg(2, pd, "sleeping\n");
                        residue = schedule_timeout(min_sleep_time);
-                       VPRINTK("kcdrwd: wake up\n");
+                       pkt_dbg(2, pd, "wake up\n");
 
                        /* make swsusp happy with our thread */
                        try_to_freeze();
@@ -1563,9 +1564,10 @@ work_to_do:
 
 static void pkt_print_settings(struct pktcdvd_device *pd)
 {
-       printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
-       printk("%u blocks, ", pd->settings.size >> 2);
-       printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2');
+       pkt_info(pd, "%s packets, %u blocks, Mode-%c disc\n",
+                pd->settings.fp ? "Fixed" : "Variable",
+                pd->settings.size >> 2,
+                pd->settings.block_mode == 8 ? '1' : '2');
 }
 
 static int pkt_mode_sense(struct pktcdvd_device *pd, struct packet_command *cgc, int page_code, int page_control)
@@ -1699,7 +1701,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd)
        init_cdrom_command(&cgc, buffer, sizeof(*wp), CGC_DATA_READ);
        cgc.sense = &sense;
        if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) {
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
                return ret;
        }
 
@@ -1714,7 +1716,7 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd)
        init_cdrom_command(&cgc, buffer, size, CGC_DATA_READ);
        cgc.sense = &sense;
        if ((ret = pkt_mode_sense(pd, &cgc, GPMODE_WRITE_PARMS_PAGE, 0))) {
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
                return ret;
        }
 
@@ -1749,14 +1751,14 @@ static noinline_for_stack int pkt_set_write_settings(struct pktcdvd_device *pd)
                /*
                 * paranoia
                 */
-               printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type);
+               pkt_err(pd, "write mode wrong %d\n", wp->data_block_type);
                return 1;
        }
        wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
 
        cgc.buflen = cgc.cmd[8] = size;
        if ((ret = pkt_mode_select(pd, &cgc))) {
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
                return ret;
        }
 
@@ -1793,7 +1795,7 @@ static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
        if (ti->rt == 1 && ti->blank == 0)
                return 1;
 
-       printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+       pkt_err(pd, "bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
        return 0;
 }
 
@@ -1811,7 +1813,8 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
                case 0x12: /* DVD-RAM */
                        return 1;
                default:
-                       VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile);
+                       pkt_dbg(2, pd, "Wrong disc profile (%x)\n",
+                               pd->mmc3_profile);
                        return 0;
        }
 
@@ -1820,22 +1823,22 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
         * but i'm not sure, should we leave this to user apps? probably.
         */
        if (di->disc_type == 0xff) {
-               printk(DRIVER_NAME": Unknown disc. No track?\n");
+               pkt_notice(pd, "unknown disc - no track?\n");
                return 0;
        }
 
        if (di->disc_type != 0x20 && di->disc_type != 0) {
-               printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type);
+               pkt_err(pd, "wrong disc type (%x)\n", di->disc_type);
                return 0;
        }
 
        if (di->erasable == 0) {
-               printk(DRIVER_NAME": Disc not erasable\n");
+               pkt_notice(pd, "disc not erasable\n");
                return 0;
        }
 
        if (di->border_status == PACKET_SESSION_RESERVED) {
-               printk(DRIVER_NAME": Can't write to last track (reserved)\n");
+               pkt_err(pd, "can't write to last track (reserved)\n");
                return 0;
        }
 
@@ -1860,7 +1863,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
        memset(&ti, 0, sizeof(track_information));
 
        if ((ret = pkt_get_disc_info(pd, &di))) {
-               printk("failed get_disc\n");
+               pkt_err(pd, "failed get_disc\n");
                return ret;
        }
 
@@ -1871,12 +1874,12 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
 
        track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
        if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
-               printk(DRIVER_NAME": failed get_track\n");
+               pkt_err(pd, "failed get_track\n");
                return ret;
        }
 
        if (!pkt_writable_track(pd, &ti)) {
-               printk(DRIVER_NAME": can't write to this track\n");
+               pkt_err(pd, "can't write to this track\n");
                return -EROFS;
        }
 
@@ -1886,11 +1889,11 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
         */
        pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
        if (pd->settings.size == 0) {
-               printk(DRIVER_NAME": detected zero packet size!\n");
+               pkt_notice(pd, "detected zero packet size!\n");
                return -ENXIO;
        }
        if (pd->settings.size > PACKET_MAX_SECTORS) {
-               printk(DRIVER_NAME": packet size is too big\n");
+               pkt_err(pd, "packet size is too big\n");
                return -EROFS;
        }
        pd->settings.fp = ti.fp;
@@ -1932,7 +1935,7 @@ static noinline_for_stack int pkt_probe_settings(struct pktcdvd_device *pd)
                        pd->settings.block_mode = PACKET_BLOCK_MODE2;
                        break;
                default:
-                       printk(DRIVER_NAME": unknown data mode\n");
+                       pkt_err(pd, "unknown data mode\n");
                        return -EROFS;
        }
        return 0;
@@ -1966,10 +1969,10 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd,
        cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
        ret = pkt_mode_select(pd, &cgc);
        if (ret) {
-               printk(DRIVER_NAME": write caching control failed\n");
-               pkt_dump_sense(&cgc);
+               pkt_err(pd, "write caching control failed\n");
+               pkt_dump_sense(pd, &cgc);
        } else if (!ret && set)
-               printk(DRIVER_NAME": enabled write caching on %s\n", pd->name);
+               pkt_notice(pd, "enabled write caching\n");
        return ret;
 }
 
@@ -2005,7 +2008,7 @@ static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd,
                             sizeof(struct mode_page_header);
                ret = pkt_mode_sense(pd, &cgc, GPMODE_CAPABILITIES_PAGE, 0);
                if (ret) {
-                       pkt_dump_sense(&cgc);
+                       pkt_dump_sense(pd, &cgc);
                        return ret;
                }
        }
@@ -2064,7 +2067,7 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd,
        cgc.cmd[8] = 2;
        ret = pkt_generic_packet(pd, &cgc);
        if (ret) {
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
                return ret;
        }
        size = ((unsigned int) buf[0]<<8) + buf[1] + 2;
@@ -2079,16 +2082,16 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd,
        cgc.cmd[8] = size;
        ret = pkt_generic_packet(pd, &cgc);
        if (ret) {
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
                return ret;
        }
 
        if (!(buf[6] & 0x40)) {
-               printk(DRIVER_NAME": Disc type is not CD-RW\n");
+               pkt_notice(pd, "disc type is not CD-RW\n");
                return 1;
        }
        if (!(buf[6] & 0x4)) {
-               printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
+               pkt_notice(pd, "A1 values on media are not valid, maybe not CDRW?\n");
                return 1;
        }
 
@@ -2108,14 +2111,14 @@ static noinline_for_stack int pkt_media_speed(struct pktcdvd_device *pd,
                        *speed = us_clv_to_speed[sp];
                        break;
                default:
-                       printk(DRIVER_NAME": Unknown disc sub-type %d\n",st);
+                       pkt_notice(pd, "unknown disc sub-type %d\n", st);
                        return 1;
        }
        if (*speed) {
-               printk(DRIVER_NAME": Max. media speed: %d\n",*speed);
+               pkt_info(pd, "maximum media speed: %d\n", *speed);
                return 0;
        } else {
-               printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st);
+               pkt_notice(pd, "unknown speed %d for sub-type %d\n", sp, st);
                return 1;
        }
 }
@@ -2126,7 +2129,7 @@ static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd)
        struct request_sense sense;
        int ret;
 
-       VPRINTK(DRIVER_NAME": Performing OPC\n");
+       pkt_dbg(2, pd, "Performing OPC\n");
 
        init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
        cgc.sense = &sense;
@@ -2134,7 +2137,7 @@ static noinline_for_stack int pkt_perform_opc(struct pktcdvd_device *pd)
        cgc.cmd[0] = GPCMD_SEND_OPC;
        cgc.cmd[1] = 1;
        if ((ret = pkt_generic_packet(pd, &cgc)))
-               pkt_dump_sense(&cgc);
+               pkt_dump_sense(pd, &cgc);
        return ret;
 }
 
@@ -2144,12 +2147,12 @@ static int pkt_open_write(struct pktcdvd_device *pd)
        unsigned int write_speed, media_write_speed, read_speed;
 
        if ((ret = pkt_probe_settings(pd))) {
-               VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name);
+               pkt_dbg(2, pd, "failed probe\n");
                return ret;
        }
 
        if ((ret = pkt_set_write_settings(pd))) {
-               DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name);
+               pkt_dbg(1, pd, "failed saving write settings\n");
                return -EIO;
        }
 
@@ -2161,26 +2164,26 @@ static int pkt_open_write(struct pktcdvd_device *pd)
                case 0x13: /* DVD-RW */
                case 0x1a: /* DVD+RW */
                case 0x12: /* DVD-RAM */
-                       DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed);
+                       pkt_dbg(1, pd, "write speed %ukB/s\n", write_speed);
                        break;
                default:
                        if ((ret = pkt_media_speed(pd, &media_write_speed)))
                                media_write_speed = 16;
                        write_speed = min(write_speed, media_write_speed * 177);
-                       DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176);
+                       pkt_dbg(1, pd, "write speed %ux\n", write_speed / 176);
                        break;
        }
        read_speed = write_speed;
 
        if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
-               DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name);
+               pkt_dbg(1, pd, "couldn't set write speed\n");
                return -EIO;
        }
        pd->write_speed = write_speed;
        pd->read_speed = read_speed;
 
        if ((ret = pkt_perform_opc(pd))) {
-               DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name);
+               pkt_dbg(1, pd, "Optimum Power Calibration failed\n");
        }
 
        return 0;
@@ -2205,7 +2208,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
                goto out;
 
        if ((ret = pkt_get_last_written(pd, &lba))) {
-               printk(DRIVER_NAME": pkt_get_last_written failed\n");
+               pkt_err(pd, "pkt_get_last_written failed\n");
                goto out_putdev;
        }
 
@@ -2235,11 +2238,11 @@ static int pkt_open_dev(struct pktcdvd_device *pd, fmode_t write)
 
        if (write) {
                if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
-                       printk(DRIVER_NAME": not enough memory for buffers\n");
+                       pkt_err(pd, "not enough memory for buffers\n");
                        ret = -ENOMEM;
                        goto out_putdev;
                }
-               printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
+               pkt_info(pd, "%lukB available on disc\n", lba << 1);
        }
 
        return 0;
@@ -2257,7 +2260,7 @@ out:
 static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
 {
        if (flush && pkt_flush_cache(pd))
-               DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name);
+               pkt_dbg(1, pd, "not flushing cache\n");
 
        pkt_lock_door(pd, 0);
 
@@ -2279,8 +2282,6 @@ static int pkt_open(struct block_device *bdev, fmode_t mode)
        struct pktcdvd_device *pd = NULL;
        int ret;
 
-       VPRINTK(DRIVER_NAME": entering open\n");
-
        mutex_lock(&pktcdvd_mutex);
        mutex_lock(&ctl_mutex);
        pd = pkt_find_dev_from_minor(MINOR(bdev->bd_dev));
@@ -2315,7 +2316,6 @@ static int pkt_open(struct block_device *bdev, fmode_t mode)
 out_dec:
        pd->refcnt--;
 out:
-       VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
        mutex_unlock(&ctl_mutex);
        mutex_unlock(&pktcdvd_mutex);
        return ret;
@@ -2360,7 +2360,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
 
        pd = q->queuedata;
        if (!pd) {
-               printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+               pr_err("%s incorrect request queue\n",
+                      bdevname(bio->bi_bdev, b));
                goto end_io;
        }
 
@@ -2382,20 +2383,20 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
        }
 
        if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
-               printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n",
-                       pd->name, (unsigned long long)bio->bi_sector);
+               pkt_notice(pd, "WRITE for ro device (%llu)\n",
+                          (unsigned long long)bio->bi_sector);
                goto end_io;
        }
 
        if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
-               printk(DRIVER_NAME": wrong bio size\n");
+               pkt_err(pd, "wrong bio size\n");
                goto end_io;
        }
 
        blk_queue_bounce(q, &bio);
 
-       zone = ZONE(bio->bi_sector, pd);
-       VPRINTK("pkt_make_request: start = %6llx stop = %6llx\n",
+       zone = get_zone(bio->bi_sector, pd);
+       pkt_dbg(2, pd, "start = %6llx stop = %6llx\n",
                (unsigned long long)bio->bi_sector,
                (unsigned long long)bio_end_sector(bio));
 
@@ -2405,7 +2406,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
                sector_t last_zone;
                int first_sectors;
 
-               last_zone = ZONE(bio_end_sector(bio) - 1, pd);
+               last_zone = get_zone(bio_end_sector(bio) - 1, pd);
                if (last_zone != zone) {
                        BUG_ON(last_zone != zone + pd->settings.size);
                        first_sectors = last_zone - bio->bi_sector;
@@ -2500,7 +2501,7 @@ static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd,
                          struct bio_vec *bvec)
 {
        struct pktcdvd_device *pd = q->queuedata;
-       sector_t zone = ZONE(bmd->bi_sector, pd);
+       sector_t zone = get_zone(bmd->bi_sector, pd);
        int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size;
        int remaining = (pd->settings.size << 9) - used;
        int remaining2;
@@ -2609,7 +2610,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
        struct block_device *bdev;
 
        if (pd->pkt_dev == dev) {
-               printk(DRIVER_NAME": Recursive setup not allowed\n");
+               pkt_err(pd, "recursive setup not allowed\n");
                return -EBUSY;
        }
        for (i = 0; i < MAX_WRITERS; i++) {
@@ -2617,11 +2618,12 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
                if (!pd2)
                        continue;
                if (pd2->bdev->bd_dev == dev) {
-                       printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b));
+                       pkt_err(pd, "%s already setup\n",
+                               bdevname(pd2->bdev, b));
                        return -EBUSY;
                }
                if (pd2->pkt_dev == dev) {
-                       printk(DRIVER_NAME": Can't chain pktcdvd devices\n");
+                       pkt_err(pd, "can't chain pktcdvd devices\n");
                        return -EBUSY;
                }
        }
@@ -2644,13 +2646,13 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
        atomic_set(&pd->cdrw.pending_bios, 0);
        pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
        if (IS_ERR(pd->cdrw.thread)) {
-               printk(DRIVER_NAME": can't start kernel thread\n");
+               pkt_err(pd, "can't start kernel thread\n");
                ret = -ENOMEM;
                goto out_mem;
        }
 
        proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd);
-       DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+       pkt_dbg(1, pd, "writer mapped to %s\n", bdevname(bdev, b));
        return 0;
 
 out_mem:
@@ -2665,8 +2667,8 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
        struct pktcdvd_device *pd = bdev->bd_disk->private_data;
        int ret;
 
-       VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd,
-               MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
+       pkt_dbg(2, pd, "cmd %x, dev %d:%d\n",
+               cmd, MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev));
 
        mutex_lock(&pktcdvd_mutex);
        switch (cmd) {
@@ -2690,7 +2692,7 @@ static int pkt_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
                break;
 
        default:
-               VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
+               pkt_dbg(2, pd, "Unknown ioctl (%x)\n", cmd);
                ret = -ENOTTY;
        }
        mutex_unlock(&pktcdvd_mutex);
@@ -2743,7 +2745,7 @@ static int pkt_setup_dev(dev_t dev, dev_t* pkt_dev)
                if (!pkt_devs[idx])
                        break;
        if (idx == MAX_WRITERS) {
-               printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
+               pr_err("max %d writers supported\n", MAX_WRITERS);
                ret = -EBUSY;
                goto out_mutex;
        }
@@ -2818,7 +2820,7 @@ out_mem:
        kfree(pd);
 out_mutex:
        mutex_unlock(&ctl_mutex);
-       printk(DRIVER_NAME": setup of pktcdvd device failed\n");
+       pr_err("setup of pktcdvd device failed\n");
        return ret;
 }
 
@@ -2839,7 +2841,7 @@ static int pkt_remove_dev(dev_t pkt_dev)
                        break;
        }
        if (idx == MAX_WRITERS) {
-               DPRINTK(DRIVER_NAME": dev not setup\n");
+               pr_debug("dev not setup\n");
                ret = -ENXIO;
                goto out;
        }
@@ -2859,7 +2861,7 @@ static int pkt_remove_dev(dev_t pkt_dev)
        blkdev_put(pd->bdev, FMODE_READ | FMODE_NDELAY);
 
        remove_proc_entry(pd->name, pkt_proc);
-       DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
+       pkt_dbg(1, pd, "writer unmapped\n");
 
        del_gendisk(pd->disk);
        blk_cleanup_queue(pd->disk->queue);
@@ -2969,7 +2971,7 @@ static int __init pkt_init(void)
 
        ret = register_blkdev(pktdev_major, DRIVER_NAME);
        if (ret < 0) {
-               printk(DRIVER_NAME": Unable to register block device\n");
+               pr_err("unable to register block device\n");
                goto out2;
        }
        if (!pktdev_major)
@@ -2983,7 +2985,7 @@ static int __init pkt_init(void)
 
        ret = misc_register(&pkt_misc);
        if (ret) {
-               printk(DRIVER_NAME": Unable to register misc device\n");
+               pr_err("unable to register misc device\n");
                goto out_misc;
        }
 
index 191cd177fef2e938b69d9eccc10bcfbb8f9d695e..cb1db2979d3d7b5417a8a4b131e09c5c5f6767c0 100644 (file)
@@ -931,12 +931,14 @@ static const char *rbd_dev_v1_snap_name(struct rbd_device *rbd_dev,
                                        u64 snap_id)
 {
        u32 which;
+       const char *snap_name;
 
        which = rbd_dev_snap_index(rbd_dev, snap_id);
        if (which == BAD_SNAP_INDEX)
-               return NULL;
+               return ERR_PTR(-ENOENT);
 
-       return _rbd_dev_v1_snap_name(rbd_dev, which);
+       snap_name = _rbd_dev_v1_snap_name(rbd_dev, which);
+       return snap_name ? snap_name : ERR_PTR(-ENOMEM);
 }
 
 static const char *rbd_snap_name(struct rbd_device *rbd_dev, u64 snap_id)
@@ -1561,11 +1563,12 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
                obj_request, obj_request->img_request, obj_request->result,
                xferred, length);
        /*
-        * ENOENT means a hole in the image.  We zero-fill the
-        * entire length of the request.  A short read also implies
-        * zero-fill to the end of the request.  Either way we
-        * update the xferred count to indicate the whole request
-        * was satisfied.
+        * ENOENT means a hole in the image.  We zero-fill the entire
+        * length of the request.  A short read also implies zero-fill
+        * to the end of the request.  An error requires the whole
+        * length of the request to be reported finished with an error
+        * to the block layer.  In each case we update the xferred
+        * count to indicate the whole request was satisfied.
         */
        rbd_assert(obj_request->type != OBJ_REQUEST_NODATA);
        if (obj_request->result == -ENOENT) {
@@ -1574,14 +1577,13 @@ rbd_img_obj_request_read_callback(struct rbd_obj_request *obj_request)
                else
                        zero_pages(obj_request->pages, 0, length);
                obj_request->result = 0;
-               obj_request->xferred = length;
        } else if (xferred < length && !obj_request->result) {
                if (obj_request->type == OBJ_REQUEST_BIO)
                        zero_bio_chain(obj_request->bio_list, xferred);
                else
                        zero_pages(obj_request->pages, xferred, length);
-               obj_request->xferred = length;
        }
+       obj_request->xferred = length;
        obj_request_done_set(obj_request);
 }
 
@@ -2167,9 +2169,9 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
        struct rbd_obj_request *obj_request = NULL;
        struct rbd_obj_request *next_obj_request;
        bool write_request = img_request_write_test(img_request);
-       struct bio *bio_list = 0;
+       struct bio *bio_list = NULL;
        unsigned int bio_offset = 0;
-       struct page **pages = 0;
+       struct page **pages = NULL;
        u64 img_offset;
        u64 resid;
        u16 opcode;
@@ -2207,6 +2209,11 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                rbd_segment_name_free(object_name);
                if (!obj_request)
                        goto out_unwind;
+               /*
+                * set obj_request->img_request before creating the
+                * osd_request so that it gets the right snapc
+                */
+               rbd_img_obj_request_add(img_request, obj_request);
 
                if (type == OBJ_REQUEST_BIO) {
                        unsigned int clone_size;
@@ -2248,11 +2255,6 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                                        obj_request->pages, length,
                                        offset & ~PAGE_MASK, false, false);
 
-               /*
-                * set obj_request->img_request before formatting
-                * the osd_request so that it gets the right snapc
-                */
-               rbd_img_obj_request_add(img_request, obj_request);
                if (write_request)
                        rbd_osd_req_format_write(obj_request);
                else
@@ -2812,7 +2814,7 @@ out_err:
        obj_request_done_set(obj_request);
 }
 
-static int rbd_obj_notify_ack(struct rbd_device *rbd_dev, u64 notify_id)
+static int rbd_obj_notify_ack_sync(struct rbd_device *rbd_dev, u64 notify_id)
 {
        struct rbd_obj_request *obj_request;
        struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
@@ -2827,16 +2829,17 @@ static int rbd_obj_notify_ack(struct rbd_device *rbd_dev, u64 notify_id)
        obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, obj_request);
        if (!obj_request->osd_req)
                goto out;
-       obj_request->callback = rbd_obj_request_put;
 
        osd_req_op_watch_init(obj_request->osd_req, 0, CEPH_OSD_OP_NOTIFY_ACK,
                                        notify_id, 0, 0);
        rbd_osd_req_format_read(obj_request);
 
        ret = rbd_obj_request_submit(osdc, obj_request);
-out:
        if (ret)
-               rbd_obj_request_put(obj_request);
+               goto out;
+       ret = rbd_obj_request_wait(obj_request);
+out:
+       rbd_obj_request_put(obj_request);
 
        return ret;
 }
@@ -2856,7 +2859,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
        if (ret)
                rbd_warn(rbd_dev, "header refresh error (%d)\n", ret);
 
-       rbd_obj_notify_ack(rbd_dev, notify_id);
+       rbd_obj_notify_ack_sync(rbd_dev, notify_id);
 }
 
 /*
@@ -3328,6 +3331,31 @@ static void rbd_exists_validate(struct rbd_device *rbd_dev)
                clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
 }
 
+static void rbd_dev_update_size(struct rbd_device *rbd_dev)
+{
+       sector_t size;
+       bool removing;
+
+       /*
+        * Don't hold the lock while doing disk operations,
+        * or lock ordering will conflict with the bdev mutex via:
+        * rbd_add() -> blkdev_get() -> rbd_open()
+        */
+       spin_lock_irq(&rbd_dev->lock);
+       removing = test_bit(RBD_DEV_FLAG_REMOVING, &rbd_dev->flags);
+       spin_unlock_irq(&rbd_dev->lock);
+       /*
+        * If the device is being removed, rbd_dev->disk has
+        * been destroyed, so don't try to update its size
+        */
+       if (!removing) {
+               size = (sector_t)rbd_dev->mapping.size / SECTOR_SIZE;
+               dout("setting size to %llu sectors", (unsigned long long)size);
+               set_capacity(rbd_dev->disk, size);
+               revalidate_disk(rbd_dev->disk);
+       }
+}
+
 static int rbd_dev_refresh(struct rbd_device *rbd_dev)
 {
        u64 mapping_size;
@@ -3347,12 +3375,7 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
        up_write(&rbd_dev->header_rwsem);
 
        if (mapping_size != rbd_dev->mapping.size) {
-               sector_t size;
-
-               size = (sector_t)rbd_dev->mapping.size / SECTOR_SIZE;
-               dout("setting size to %llu sectors", (unsigned long long)size);
-               set_capacity(rbd_dev->disk, size);
-               revalidate_disk(rbd_dev->disk);
+               rbd_dev_update_size(rbd_dev);
        }
 
        return ret;
@@ -3706,12 +3729,14 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id,
        if (ret < sizeof (size_buf))
                return -ERANGE;
 
-       if (order)
+       if (order) {
                *order = size_buf.order;
+               dout("  order %u", (unsigned int)*order);
+       }
        *snap_size = le64_to_cpu(size_buf.size);
 
-       dout("  snap_id 0x%016llx order = %u, snap_size = %llu\n",
-               (unsigned long long)snap_id, (unsigned int)*order,
+       dout("  snap_id 0x%016llx snap_size = %llu\n",
+               (unsigned long long)snap_id,
                (unsigned long long)*snap_size);
 
        return 0;
@@ -4059,8 +4084,13 @@ static u64 rbd_v2_snap_id_by_name(struct rbd_device *rbd_dev, const char *name)
 
                snap_id = snapc->snaps[which];
                snap_name = rbd_dev_v2_snap_name(rbd_dev, snap_id);
-               if (IS_ERR(snap_name))
-                       break;
+               if (IS_ERR(snap_name)) {
+                       /* ignore no-longer existing snapshots */
+                       if (PTR_ERR(snap_name) == -ENOENT)
+                               continue;
+                       else
+                               break;
+               }
                found = !strcmp(name, snap_name);
                kfree(snap_name);
        }
@@ -4139,8 +4169,8 @@ static int rbd_dev_spec_update(struct rbd_device *rbd_dev)
        /* Look up the snapshot name, and make a copy */
 
        snap_name = rbd_snap_name(rbd_dev, spec->snap_id);
-       if (!snap_name) {
-               ret = -ENOMEM;
+       if (IS_ERR(snap_name)) {
+               ret = PTR_ERR(snap_name);
                goto out_err;
        }
 
@@ -5130,7 +5160,7 @@ static ssize_t rbd_remove(struct bus_type *bus,
        bool already = false;
        int ret;
 
-       ret = strict_strtoul(buf, 10, &ul);
+       ret = kstrtoul(buf, 10, &ul);
        if (ret)
                return ret;
 
@@ -5161,10 +5191,23 @@ static ssize_t rbd_remove(struct bus_type *bus,
        if (ret < 0 || already)
                return ret;
 
-       rbd_bus_del_dev(rbd_dev);
        ret = rbd_dev_header_watch_sync(rbd_dev, false);
        if (ret)
                rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret);
+
+       /*
+        * flush remaining watch callbacks - these must be complete
+        * before the osd_client is shutdown
+        */
+       dout("%s: flushing notifies", __func__);
+       ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc);
+       /*
+        * Don't free anything from rbd_dev->disk until after all
+        * notifies are completely processed. Otherwise
+        * rbd_bus_del_dev() will race with rbd_watch_cb(), resulting
+        * in a potential use after free of rbd_dev->disk or rbd_dev.
+        */
+       rbd_bus_del_dev(rbd_dev);
        rbd_dev_image_release(rbd_dev);
        module_put(THIS_MODULE);
 
index 8ed6ccb748cffa996f38a4f4c5acf935f00a18c0..b02d53a399f37818f58950fd50e2184b43c216ba 100644 (file)
@@ -924,7 +924,6 @@ static int swim_probe(struct platform_device *dev)
        return 0;
 
 out_kfree:
-       platform_set_drvdata(dev, NULL);
        kfree(swd);
 out_iounmap:
        iounmap(swim_base);
@@ -962,7 +961,6 @@ static int swim_remove(struct platform_device *dev)
        if (res)
                release_mem_region(res->start, resource_size(res));
 
-       platform_set_drvdata(dev, NULL);
        kfree(swd);
 
        return 0;
index fe5c3cd10c341045ca63aeacb15edc93c185a88b..c2014a0aa206b2ec1b1ee328e84bde4407026616 100644 (file)
@@ -620,7 +620,7 @@ static void backend_changed(struct xenbus_watch *watch,
        }
 
        /* Front end dir is a number, which is used as the handle. */
-       err = strict_strtoul(strrchr(dev->otherend, '/') + 1, 0, &handle);
+       err = kstrtoul(strrchr(dev->otherend, '/') + 1, 0, &handle);
        if (err)
                return;
 
index 0d91fe52f3f5eee10397563361a4b1dd1579e8cf..7737b5bd26af816e4361a906ad9d0cd6966b7287 100644 (file)
 #include <linux/fips.h>
 #include <linux/ptrace.h>
 #include <linux/kmemcheck.h>
-
-#ifdef CONFIG_GENERIC_HARDIRQS
-# include <linux/irq.h>
-#endif
+#include <linux/irq.h>
 
 #include <asm/processor.h>
 #include <asm/uaccess.h>
index 4519cb332987bc1ac840f9d8ac26cac4be3b964b..5796d0157ce0c3bbd82c662bf61f8035e9d9daf8 100644 (file)
@@ -766,6 +766,25 @@ static void tpm_tis_reenable_interrupts(struct tpm_chip *chip)
 }
 #endif
 
+#ifdef CONFIG_PM_SLEEP
+static int tpm_tis_resume(struct device *dev)
+{
+       struct tpm_chip *chip = dev_get_drvdata(dev);
+       int ret;
+
+       if (chip->vendor.irq)
+               tpm_tis_reenable_interrupts(chip);
+
+       ret = tpm_pm_resume(dev);
+       if (!ret)
+               tpm_do_selftest(chip);
+
+       return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
+
 #ifdef CONFIG_PNP
 static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
                                      const struct pnp_device_id *pnp_id)
@@ -787,26 +806,6 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
        return tpm_tis_init(&pnp_dev->dev, start, len, irq);
 }
 
-static int tpm_tis_pnp_suspend(struct pnp_dev *dev, pm_message_t msg)
-{
-       return tpm_pm_suspend(&dev->dev);
-}
-
-static int tpm_tis_pnp_resume(struct pnp_dev *dev)
-{
-       struct tpm_chip *chip = pnp_get_drvdata(dev);
-       int ret;
-
-       if (chip->vendor.irq)
-               tpm_tis_reenable_interrupts(chip);
-
-       ret = tpm_pm_resume(&dev->dev);
-       if (!ret)
-               tpm_do_selftest(chip);
-
-       return ret;
-}
-
 static struct pnp_device_id tpm_pnp_tbl[] = {
        {"PNP0C31", 0},         /* TPM */
        {"ATM1200", 0},         /* Atmel */
@@ -835,9 +834,12 @@ static struct pnp_driver tis_pnp_driver = {
        .name = "tpm_tis",
        .id_table = tpm_pnp_tbl,
        .probe = tpm_tis_pnp_init,
-       .suspend = tpm_tis_pnp_suspend,
-       .resume = tpm_tis_pnp_resume,
        .remove = tpm_tis_pnp_remove,
+#ifdef CONFIG_PM_SLEEP
+       .driver = {
+               .pm = &tpm_tis_pm,
+       },
+#endif
 };
 
 #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2
@@ -846,20 +848,6 @@ module_param_string(hid, tpm_pnp_tbl[TIS_HID_USR_IDX].id,
 MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
 #endif
 
-#ifdef CONFIG_PM_SLEEP
-static int tpm_tis_resume(struct device *dev)
-{
-       struct tpm_chip *chip = dev_get_drvdata(dev);
-
-       if (chip->vendor.irq)
-               tpm_tis_reenable_interrupts(chip);
-
-       return tpm_pm_resume(dev);
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(tpm_tis_pm, tpm_pm_suspend, tpm_tis_resume);
-
 static struct platform_driver tis_drv = {
        .driver = {
                .name = "tpm_tis",
index fc45567ad3acef079db496c9a2f495e19e5b5bba..b79cf3e1b793dca8f652067718d4ece3c0b3335d 100644 (file)
@@ -1529,18 +1529,22 @@ static void remove_port_data(struct port *port)
 {
        struct port_buffer *buf;
 
+       spin_lock_irq(&port->inbuf_lock);
        /* 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 = virtqueue_detach_unused_buf(port->in_vq)))
                free_buf(buf, true);
+       spin_unlock_irq(&port->inbuf_lock);
+
+       spin_lock_irq(&port->outvq_lock);
+       reclaim_consumed_buffers(port);
 
        /* Free pending buffers from the out-queue. */
        while ((buf = virtqueue_detach_unused_buf(port->out_vq)))
                free_buf(buf, true);
+       spin_unlock_irq(&port->outvq_lock);
 }
 
 /*
@@ -1554,6 +1558,7 @@ static void unplug_port(struct port *port)
        list_del(&port->list);
        spin_unlock_irq(&port->portdev->ports_lock);
 
+       spin_lock_irq(&port->inbuf_lock);
        if (port->guest_connected) {
                /* Let the app know the port is going down. */
                send_sigio_to_port(port);
@@ -1564,6 +1569,7 @@ static void unplug_port(struct port *port)
 
                wake_up_interruptible(&port->waitqueue);
        }
+       spin_unlock_irq(&port->inbuf_lock);
 
        if (is_console_port(port)) {
                spin_lock_irq(&pdrvdata_lock);
@@ -1585,9 +1591,8 @@ static void unplug_port(struct port *port)
        device_destroy(pdrvdata.class, port->dev->devt);
        cdev_del(port->cdev);
 
-       kfree(port->name);
-
        debugfs_remove(port->debugfs_file);
+       kfree(port->name);
 
        /*
         * Locks around here are not necessary - a port can't be
@@ -1681,7 +1686,9 @@ static void handle_control_message(struct ports_device *portdev,
                 * If the guest is connected, it'll be interested in
                 * knowing the host connection state changed.
                 */
+               spin_lock_irq(&port->inbuf_lock);
                send_sigio_to_port(port);
+               spin_unlock_irq(&port->inbuf_lock);
                break;
        case VIRTIO_CONSOLE_PORT_NAME:
                /*
@@ -1801,13 +1808,13 @@ static void in_intr(struct virtqueue *vq)
        if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
                discard_port_data(port);
 
+       /* Send a SIGIO indicating new data in case the process asked for it */
+       send_sigio_to_port(port);
+
        spin_unlock_irqrestore(&port->inbuf_lock, flags);
 
        wake_up_interruptible(&port->waitqueue);
 
-       /* Send a SIGIO indicating new data in case the process asked for it */
-       send_sigio_to_port(port);
-
        if (is_console_port(port) && hvc_poll(port->cons.hvc))
                hvc_kick();
 }
@@ -2241,10 +2248,8 @@ static int __init init(void)
        }
 
        pdrvdata.debugfs_dir = debugfs_create_dir("virtio-ports", NULL);
-       if (!pdrvdata.debugfs_dir) {
-               pr_warning("Error %ld creating debugfs dir for virtio-ports\n",
-                          PTR_ERR(pdrvdata.debugfs_dir));
-       }
+       if (!pdrvdata.debugfs_dir)
+               pr_warning("Error creating debugfs dir for virtio-ports\n");
        INIT_LIST_HEAD(&pdrvdata.consoles);
        INIT_LIST_HEAD(&pdrvdata.portdevs);
 
index 51380d655d1aff80ab4368dddfe2d4284becc59c..279407a36391eccc6194c5086b1d0e26e3deb1d6 100644 (file)
@@ -27,7 +27,7 @@ config COMMON_CLK_DEBUG
        bool "DebugFS representation of clock tree"
        select DEBUG_FS
        ---help---
-         Creates a directory hierchy in debugfs for visualizing the clk
+         Creates a directory hierarchy in debugfs for visualizing the clk
          tree structure.  Each directory contains read-only members
          that export information specific to that clk node: clk_rate,
          clk_flags, clk_prepare_count, clk_enable_count &
@@ -64,6 +64,12 @@ config COMMON_CLK_SI5351
          This driver supports Silicon Labs 5351A/B/C programmable clock
          generators.
 
+config COMMON_CLK_S2MPS11
+       tristate "Clock driver for S2MPS11 MFD"
+       depends on MFD_SEC_CORE
+       ---help---
+         This driver supports S2MPS11 crystal oscillator clock.
+
 config CLK_TWL6040
        tristate "External McPDM functional clock from twl6040"
        depends on TWL6040_CORE
index 4038c2bdf334ddd4f6ac605b91292af5dabe2713..7b111062ccba2d152e53d2093affce3f273ada2f 100644 (file)
@@ -40,5 +40,6 @@ obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
 obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
 obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
+obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
 obj-$(CONFIG_CLK_TWL6040)      += clk-twl6040.o
 obj-$(CONFIG_CLK_PPC_CORENET)  += clk-ppc-corenet.o
index 792bc57a9db7c910d247eb47d4801a27f08792c8..5fb4ff53d0887eca089a7a853b29a11df9cab6a5 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 
-static const __initconst struct of_device_id clk_match[] = {
+static const struct of_device_id clk_match[] __initconst = {
        { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
        { }
 };
index 6d55eb2cb959baafc949cae9db15097f38c51c76..8d3009e44fba40d4fba82825bd59d98febf53984 100644 (file)
@@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
        struct clk_divider *divider = to_clk_divider(hw);
        unsigned int div, val;
 
-       val = readl(divider->reg) >> divider->shift;
+       val = clk_readl(divider->reg) >> divider->shift;
        val &= div_mask(divider);
 
        div = _get_div(divider, val);
@@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
        if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
                val = div_mask(divider) << (divider->shift + 16);
        } else {
-               val = readl(divider->reg);
+               val = clk_readl(divider->reg);
                val &= ~(div_mask(divider) << divider->shift);
        }
        val |= value << divider->shift;
-       writel(val, divider->reg);
+       clk_writel(val, divider->reg);
 
        if (divider->lock)
                spin_unlock_irqrestore(divider->lock, flags);
@@ -317,6 +317,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
        return _register_divider(dev, name, parent_name, flags, reg, shift,
                        width, clk_divider_flags, NULL, lock);
 }
+EXPORT_SYMBOL_GPL(clk_register_divider);
 
 /**
  * clk_register_divider_table - register a table based divider clock with
@@ -341,3 +342,4 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
        return _register_divider(dev, name, parent_name, flags, reg, shift,
                        width, clk_divider_flags, table, lock);
 }
+EXPORT_SYMBOL_GPL(clk_register_divider_table);
index 9ff7d510faa35e7fcb5ed37e0982b5d4b3735d1e..0e1d89b4321b7de9b4bcb49e96f1363c9498e44c 100644 (file)
@@ -97,6 +97,8 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
 
        return clk;
 }
+EXPORT_SYMBOL_GPL(clk_register_fixed_factor);
+
 #ifdef CONFIG_OF
 /**
  * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
index dc58fbd8516f6e377472e962f3090cf06b299a8d..1ed591ab8b1d9d468a3da08c6c31c50e77b66d7b 100644 (file)
@@ -80,6 +80,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
 
        return clk;
 }
+EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
 
 #ifdef CONFIG_OF
 /**
index 790306e921c8ad55bcad26adaeb77c2b378c8db7..4a58c55255bd884f3f1e7deea52048712b297729 100644 (file)
@@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                if (set)
                        reg |= BIT(gate->bit_idx);
        } else {
-               reg = readl(gate->reg);
+               reg = clk_readl(gate->reg);
 
                if (set)
                        reg |= BIT(gate->bit_idx);
@@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
                        reg &= ~BIT(gate->bit_idx);
        }
 
-       writel(reg, gate->reg);
+       clk_writel(reg, gate->reg);
 
        if (gate->lock)
                spin_unlock_irqrestore(gate->lock, flags);
@@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
        u32 reg;
        struct clk_gate *gate = to_clk_gate(hw);
 
-       reg = readl(gate->reg);
+       reg = clk_readl(gate->reg);
 
        /* if a set bit disables this clk, flip it before masking */
        if (gate->flags & CLK_GATE_SET_TO_DISABLE)
@@ -161,3 +161,4 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
 
        return clk;
 }
+EXPORT_SYMBOL_GPL(clk_register_gate);
index 614444ca40cd638bbf3283c75b8ea7f80f7fdfe0..4f96ff3ba728321563cbdc6b728f9a25c65d74c6 100644 (file)
@@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
         * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
         * val = 0x4 really means "bit 2, index starts at bit 0"
         */
-       val = readl(mux->reg) >> mux->shift;
+       val = clk_readl(mux->reg) >> mux->shift;
        val &= mux->mask;
 
        if (mux->table) {
@@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
        if (mux->flags & CLK_MUX_HIWORD_MASK) {
                val = mux->mask << (mux->shift + 16);
        } else {
-               val = readl(mux->reg);
+               val = clk_readl(mux->reg);
                val &= ~(mux->mask << mux->shift);
        }
        val |= index << mux->shift;
-       writel(val, mux->reg);
+       clk_writel(val, mux->reg);
 
        if (mux->lock)
                spin_unlock_irqrestore(mux->lock, flags);
@@ -104,9 +104,15 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
 const struct clk_ops clk_mux_ops = {
        .get_parent = clk_mux_get_parent,
        .set_parent = clk_mux_set_parent,
+       .determine_rate = __clk_mux_determine_rate,
 };
 EXPORT_SYMBOL_GPL(clk_mux_ops);
 
+const struct clk_ops clk_mux_ro_ops = {
+       .get_parent = clk_mux_get_parent,
+};
+EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
+
 struct clk *clk_register_mux_table(struct device *dev, const char *name,
                const char **parent_names, u8 num_parents, unsigned long flags,
                void __iomem *reg, u8 shift, u32 mask,
@@ -133,7 +139,10 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
        }
 
        init.name = name;
-       init.ops = &clk_mux_ops;
+       if (clk_mux_flags & CLK_MUX_READ_ONLY)
+               init.ops = &clk_mux_ro_ops;
+       else
+               init.ops = &clk_mux_ops;
        init.flags = flags | CLK_IS_BASIC;
        init.parent_names = parent_names;
        init.num_parents = num_parents;
@@ -154,6 +163,7 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
 
        return clk;
 }
+EXPORT_SYMBOL_GPL(clk_register_mux_table);
 
 struct clk *clk_register_mux(struct device *dev, const char *name,
                const char **parent_names, u8 num_parents, unsigned long flags,
@@ -166,3 +176,4 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
                                      flags, reg, shift, mask, clk_mux_flags,
                                      NULL, lock);
 }
+EXPORT_SYMBOL_GPL(clk_register_mux);
index 6d819a37f647cb6fb85d64f95d8729fc0fb6145c..51410c2ac2cb617b9a98b9c0fd869e1ddd541870 100644 (file)
@@ -479,12 +479,12 @@ static void __init of_nomadik_src_clk_setup(struct device_node *np)
                of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
 
-static const __initconst struct of_device_id nomadik_src_match[] = {
+static const struct of_device_id nomadik_src_match[] __initconst = {
        { .compatible = "stericsson,nomadik-src" },
        { /* sentinel */ }
 };
 
-static const __initconst struct of_device_id nomadik_src_clk_match[] = {
+static const struct of_device_id nomadik_src_clk_match[] __initconst = {
        {
                .compatible = "fixed-clock",
                .data = of_fixed_clk_setup,
index 643ca653fef026b2de60235a1ef401e67c88148a..5ab95f1ad579288c516dc782b14a2b5a871ad7dc 100644 (file)
@@ -1034,7 +1034,7 @@ enum prima2_clk_index {
        usb0,  usb1,  maxclk,
 };
 
-static __initdata struct clk_hw* prima2_clk_hw_array[maxclk] = {
+static struct clk_hw *prima2_clk_hw_array[maxclk] __initdata = {
        NULL, /* dummy */
        NULL,
        &clk_pll1.hw,
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
new file mode 100644 (file)
index 0000000..7be41e6
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * clk-s2mps11.c - Clock driver for S2MPS11.
+ *
+ * Copyright (C) 2013 Samsung Electornics
+ *
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/clkdev.h>
+#include <linux/regmap.h>
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/core.h>
+
+#define s2mps11_name(a) (a->hw.init->name)
+
+static struct clk **clk_table;
+static struct clk_onecell_data clk_data;
+
+enum {
+       S2MPS11_CLK_AP = 0,
+       S2MPS11_CLK_CP,
+       S2MPS11_CLK_BT,
+       S2MPS11_CLKS_NUM,
+};
+
+struct s2mps11_clk {
+       struct sec_pmic_dev *iodev;
+       struct clk_hw hw;
+       struct clk *clk;
+       struct clk_lookup *lookup;
+       u32 mask;
+       bool enabled;
+};
+
+static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
+{
+       return container_of(hw, struct s2mps11_clk, hw);
+}
+
+static int s2mps11_clk_prepare(struct clk_hw *hw)
+{
+       struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
+       int ret;
+
+       ret = regmap_update_bits(s2mps11->iodev->regmap,
+                               S2MPS11_REG_RTC_CTRL,
+                                s2mps11->mask, s2mps11->mask);
+       if (!ret)
+               s2mps11->enabled = true;
+
+       return ret;
+}
+
+static void s2mps11_clk_unprepare(struct clk_hw *hw)
+{
+       struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
+       int ret;
+
+       ret = regmap_update_bits(s2mps11->iodev->regmap, S2MPS11_REG_RTC_CTRL,
+                          s2mps11->mask, ~s2mps11->mask);
+
+       if (!ret)
+               s2mps11->enabled = false;
+}
+
+static int s2mps11_clk_is_enabled(struct clk_hw *hw)
+{
+       struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
+
+       return s2mps11->enabled;
+}
+
+static unsigned long s2mps11_clk_recalc_rate(struct clk_hw *hw,
+                                            unsigned long parent_rate)
+{
+       struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
+       if (s2mps11->enabled)
+               return 32768;
+       else
+               return 0;
+}
+
+static struct clk_ops s2mps11_clk_ops = {
+       .prepare        = s2mps11_clk_prepare,
+       .unprepare      = s2mps11_clk_unprepare,
+       .is_enabled     = s2mps11_clk_is_enabled,
+       .recalc_rate    = s2mps11_clk_recalc_rate,
+};
+
+static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
+       [S2MPS11_CLK_AP] = {
+               .name = "s2mps11_ap",
+               .ops = &s2mps11_clk_ops,
+               .flags = CLK_IS_ROOT,
+       },
+       [S2MPS11_CLK_CP] = {
+               .name = "s2mps11_cp",
+               .ops = &s2mps11_clk_ops,
+               .flags = CLK_IS_ROOT,
+       },
+       [S2MPS11_CLK_BT] = {
+               .name = "s2mps11_bt",
+               .ops = &s2mps11_clk_ops,
+               .flags = CLK_IS_ROOT,
+       },
+};
+
+static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev)
+{
+       struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct device_node *clk_np;
+       int i;
+
+       if (!iodev->dev->of_node)
+               return NULL;
+
+       clk_np = of_find_node_by_name(iodev->dev->of_node, "clocks");
+       if (!clk_np) {
+               dev_err(&pdev->dev, "could not find clock sub-node\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
+                                S2MPS11_CLKS_NUM, GFP_KERNEL);
+       if (!clk_table)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < S2MPS11_CLKS_NUM; i++)
+               of_property_read_string_index(clk_np, "clock-output-names", i,
+                               &s2mps11_clks_init[i].name);
+
+       return clk_np;
+}
+
+static int s2mps11_clk_probe(struct platform_device *pdev)
+{
+       struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
+       struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
+       struct device_node *clk_np = NULL;
+       int i, ret = 0;
+       u32 val;
+
+       s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) *
+                                       S2MPS11_CLKS_NUM, GFP_KERNEL);
+       if (!s2mps11_clks)
+               return -ENOMEM;
+
+       s2mps11_clk = s2mps11_clks;
+
+       clk_np = s2mps11_clk_parse_dt(pdev);
+       if (IS_ERR(clk_np))
+               return PTR_ERR(clk_np);
+
+       for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
+               s2mps11_clk->iodev = iodev;
+               s2mps11_clk->hw.init = &s2mps11_clks_init[i];
+               s2mps11_clk->mask = 1 << i;
+
+               ret = regmap_read(s2mps11_clk->iodev->regmap,
+                                 S2MPS11_REG_RTC_CTRL, &val);
+               if (ret < 0)
+                       goto err_reg;
+
+               s2mps11_clk->enabled = val & s2mps11_clk->mask;
+
+               s2mps11_clk->clk = devm_clk_register(&pdev->dev,
+                                                       &s2mps11_clk->hw);
+               if (IS_ERR(s2mps11_clk->clk)) {
+                       dev_err(&pdev->dev, "Fail to register : %s\n",
+                                               s2mps11_name(s2mps11_clk));
+                       ret = PTR_ERR(s2mps11_clk->clk);
+                       goto err_reg;
+               }
+
+               s2mps11_clk->lookup = devm_kzalloc(&pdev->dev,
+                                       sizeof(struct clk_lookup), GFP_KERNEL);
+               if (!s2mps11_clk->lookup) {
+                       ret = -ENOMEM;
+                       goto err_lup;
+               }
+
+               s2mps11_clk->lookup->con_id = s2mps11_name(s2mps11_clk);
+               s2mps11_clk->lookup->clk = s2mps11_clk->clk;
+
+               clkdev_add(s2mps11_clk->lookup);
+       }
+
+       if (clk_table) {
+               for (i = 0; i < S2MPS11_CLKS_NUM; i++)
+                       clk_table[i] = s2mps11_clks[i].clk;
+
+               clk_data.clks = clk_table;
+               clk_data.clk_num = S2MPS11_CLKS_NUM;
+               of_clk_add_provider(clk_np, of_clk_src_onecell_get, &clk_data);
+       }
+
+       platform_set_drvdata(pdev, s2mps11_clks);
+
+       return ret;
+err_lup:
+       devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
+err_reg:
+       while (s2mps11_clk > s2mps11_clks) {
+               if (s2mps11_clk->lookup) {
+                       clkdev_drop(s2mps11_clk->lookup);
+                       devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
+               }
+               s2mps11_clk--;
+       }
+
+       return ret;
+}
+
+static int s2mps11_clk_remove(struct platform_device *pdev)
+{
+       struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev);
+       int i;
+
+       for (i = 0; i < S2MPS11_CLKS_NUM; i++)
+               clkdev_drop(s2mps11_clks[i].lookup);
+
+       return 0;
+}
+
+static const struct platform_device_id s2mps11_clk_id[] = {
+       { "s2mps11-clk", 0},
+       { },
+};
+MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
+
+static struct platform_driver s2mps11_clk_driver = {
+       .driver = {
+               .name  = "s2mps11-clk",
+               .owner = THIS_MODULE,
+       },
+       .probe = s2mps11_clk_probe,
+       .remove = s2mps11_clk_remove,
+       .id_table = s2mps11_clk_id,
+};
+
+static int __init s2mps11_clk_init(void)
+{
+       return platform_driver_register(&s2mps11_clk_driver);
+}
+subsys_initcall(s2mps11_clk_init);
+
+static void __init s2mps11_clk_cleanup(void)
+{
+       platform_driver_unregister(&s2mps11_clk_driver);
+}
+module_exit(s2mps11_clk_cleanup);
+
+MODULE_DESCRIPTION("S2MPS11 Clock Driver");
+MODULE_AUTHOR("Yadwinder Singh Brar <yadi.brar@samsung.com>");
+MODULE_LICENSE("GPL");
index 8774e058cb6cb5db9e290d2d45091ae839c149b3..3efbdd078d146c882bc1561c9c32040ec95c781a 100644 (file)
@@ -746,7 +746,7 @@ struct u300_clock {
        u16 clk_val;
 };
 
-struct u300_clock const __initconst u300_clk_lookup[] = {
+static struct u300_clock const u300_clk_lookup[] __initconst = {
        {
                .type = U300_CLK_TYPE_REST,
                .id = 3,
@@ -1151,7 +1151,7 @@ static void __init of_u300_syscon_mclk_init(struct device_node *np)
                of_clk_add_provider(np, of_clk_src_simple_get, clk);
 }
 
-static const __initconst struct of_device_id u300_clk_match[] = {
+static const struct of_device_id u300_clk_match[] __initconst = {
        {
                .compatible = "fixed-clock",
                .data = of_fixed_clk_setup,
index 1b3f8c9b98cc60d78d062ee8c587bfb397a668ac..805b4c3440064ad5509e7a749adc5092e2230583 100644 (file)
@@ -31,7 +31,7 @@ struct wm831x_clk {
        bool xtal_ena;
 };
 
-static int wm831x_xtal_is_enabled(struct clk_hw *hw)
+static int wm831x_xtal_is_prepared(struct clk_hw *hw)
 {
        struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
                                                  xtal_hw);
@@ -52,7 +52,7 @@ static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw,
 }
 
 static const struct clk_ops wm831x_xtal_ops = {
-       .is_enabled = wm831x_xtal_is_enabled,
+       .is_prepared = wm831x_xtal_is_prepared,
        .recalc_rate = wm831x_xtal_recalc_rate,
 };
 
@@ -73,7 +73,7 @@ static const unsigned long wm831x_fll_auto_rates[] = {
        24576000,
 };
 
-static int wm831x_fll_is_enabled(struct clk_hw *hw)
+static int wm831x_fll_is_prepared(struct clk_hw *hw)
 {
        struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
                                                  fll_hw);
@@ -170,7 +170,7 @@ static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
        if (i == ARRAY_SIZE(wm831x_fll_auto_rates))
                return -EINVAL;
 
-       if (wm831x_fll_is_enabled(hw))
+       if (wm831x_fll_is_prepared(hw))
                return -EPERM;
 
        return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2,
@@ -220,7 +220,7 @@ static u8 wm831x_fll_get_parent(struct clk_hw *hw)
 }
 
 static const struct clk_ops wm831x_fll_ops = {
-       .is_enabled = wm831x_fll_is_enabled,
+       .is_prepared = wm831x_fll_is_prepared,
        .prepare = wm831x_fll_prepare,
        .unprepare = wm831x_fll_unprepare,
        .round_rate = wm831x_fll_round_rate,
@@ -237,7 +237,7 @@ static struct clk_init_data wm831x_fll_init = {
        .flags = CLK_SET_RATE_GATE,
 };
 
-static int wm831x_clkout_is_enabled(struct clk_hw *hw)
+static int wm831x_clkout_is_prepared(struct clk_hw *hw)
 {
        struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
                                                  clkout_hw);
@@ -335,7 +335,7 @@ static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
 }
 
 static const struct clk_ops wm831x_clkout_ops = {
-       .is_enabled = wm831x_clkout_is_enabled,
+       .is_prepared = wm831x_clkout_is_prepared,
        .prepare = wm831x_clkout_prepare,
        .unprepare = wm831x_clkout_unprepare,
        .get_parent = wm831x_clkout_get_parent,
@@ -360,6 +360,8 @@ static int wm831x_clk_probe(struct platform_device *pdev)
        if (!clkdata)
                return -ENOMEM;
 
+       clkdata->wm831x = wm831x;
+
        /* XTAL_ENA can only be set via OTP/InstantConfig so just read once */
        ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
        if (ret < 0) {
index 54a191c5bbf0e3f4c1b23807c12a59cdb0d74031..a004769528e68a815293d1832f49e04eec7ca08a 100644 (file)
@@ -458,7 +458,6 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
                        clk->ops->unprepare(clk->hw);
        }
 }
-EXPORT_SYMBOL_GPL(__clk_get_flags);
 
 /* caller must hold prepare_lock */
 static void clk_disable_unused_subtree(struct clk *clk)
@@ -559,6 +558,19 @@ struct clk *__clk_get_parent(struct clk *clk)
        return !clk ? NULL : clk->parent;
 }
 
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+       if (!clk || index >= clk->num_parents)
+               return NULL;
+       else if (!clk->parents)
+               return __clk_lookup(clk->parent_names[index]);
+       else if (!clk->parents[index])
+               return clk->parents[index] =
+                       __clk_lookup(clk->parent_names[index]);
+       else
+               return clk->parents[index];
+}
+
 unsigned int __clk_get_enable_count(struct clk *clk)
 {
        return !clk ? 0 : clk->enable_count;
@@ -594,6 +606,7 @@ unsigned long __clk_get_flags(struct clk *clk)
 {
        return !clk ? 0 : clk->flags;
 }
+EXPORT_SYMBOL_GPL(__clk_get_flags);
 
 bool __clk_is_prepared(struct clk *clk)
 {
@@ -679,6 +692,55 @@ struct clk *__clk_lookup(const char *name)
        return NULL;
 }
 
+/*
+ * Helper for finding best parent to provide a given frequency. This can be used
+ * directly as a determine_rate callback (e.g. for a mux), or from a more
+ * complex clock that may combine a mux with other operations.
+ */
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *best_parent_rate,
+                             struct clk **best_parent_p)
+{
+       struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+       int i, num_parents;
+       unsigned long parent_rate, best = 0;
+
+       /* if NO_REPARENT flag set, pass through to current parent */
+       if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
+               parent = clk->parent;
+               if (clk->flags & CLK_SET_RATE_PARENT)
+                       best = __clk_round_rate(parent, rate);
+               else if (parent)
+                       best = __clk_get_rate(parent);
+               else
+                       best = __clk_get_rate(clk);
+               goto out;
+       }
+
+       /* find the parent that can provide the fastest rate <= rate */
+       num_parents = clk->num_parents;
+       for (i = 0; i < num_parents; i++) {
+               parent = clk_get_parent_by_index(clk, i);
+               if (!parent)
+                       continue;
+               if (clk->flags & CLK_SET_RATE_PARENT)
+                       parent_rate = __clk_round_rate(parent, rate);
+               else
+                       parent_rate = __clk_get_rate(parent);
+               if (parent_rate <= rate && parent_rate > best) {
+                       best_parent = parent;
+                       best = parent_rate;
+               }
+       }
+
+out:
+       if (best_parent)
+               *best_parent_p = best_parent;
+       *best_parent_rate = best;
+
+       return best;
+}
+
 /***        clk api        ***/
 
 void __clk_unprepare(struct clk *clk)
@@ -702,7 +764,7 @@ void __clk_unprepare(struct clk *clk)
 
 /**
  * clk_unprepare - undo preparation of a clock source
- * @clk: the clk being unprepare
+ * @clk: the clk being unprepared
  *
  * clk_unprepare may sleep, which differentiates it from clk_disable.  In a
  * simple case, clk_unprepare can be used instead of clk_disable to gate a clk
@@ -869,27 +931,31 @@ EXPORT_SYMBOL_GPL(clk_enable);
 /**
  * __clk_round_rate - round the given rate for a clk
  * @clk: round the rate of this clock
+ * @rate: the rate which is to be rounded
  *
  * Caller must hold prepare_lock.  Useful for clk_ops such as .set_rate
  */
 unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
 {
        unsigned long parent_rate = 0;
+       struct clk *parent;
 
        if (!clk)
                return 0;
 
-       if (!clk->ops->round_rate) {
-               if (clk->flags & CLK_SET_RATE_PARENT)
-                       return __clk_round_rate(clk->parent, rate);
-               else
-                       return clk->rate;
-       }
-
-       if (clk->parent)
-               parent_rate = clk->parent->rate;
-
-       return clk->ops->round_rate(clk->hw, rate, &parent_rate);
+       parent = clk->parent;
+       if (parent)
+               parent_rate = parent->rate;
+
+       if (clk->ops->determine_rate)
+               return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
+                                               &parent);
+       else if (clk->ops->round_rate)
+               return clk->ops->round_rate(clk->hw, rate, &parent_rate);
+       else if (clk->flags & CLK_SET_RATE_PARENT)
+               return __clk_round_rate(clk->parent, rate);
+       else
+               return clk->rate;
 }
 
 /**
@@ -956,7 +1022,7 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
  *
  * Walks the subtree of clks starting with clk and recalculates rates as it
  * goes.  Note that if a clk does not implement the .recalc_rate callback then
- * it is assumed that the clock will take on the rate of it's parent.
+ * it is assumed that the clock will take on the rate of its parent.
  *
  * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
  * if necessary.
@@ -1014,6 +1080,115 @@ unsigned long clk_get_rate(struct clk *clk)
 }
 EXPORT_SYMBOL_GPL(clk_get_rate);
 
+static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
+{
+       u8 i;
+
+       if (!clk->parents)
+               clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
+                                                               GFP_KERNEL);
+
+       /*
+        * find index of new parent clock using cached parent ptrs,
+        * or if not yet cached, use string name comparison and cache
+        * them now to avoid future calls to __clk_lookup.
+        */
+       for (i = 0; i < clk->num_parents; i++) {
+               if (clk->parents && clk->parents[i] == parent)
+                       break;
+               else if (!strcmp(clk->parent_names[i], parent->name)) {
+                       if (clk->parents)
+                               clk->parents[i] = __clk_lookup(parent->name);
+                       break;
+               }
+       }
+
+       return i;
+}
+
+static void clk_reparent(struct clk *clk, struct clk *new_parent)
+{
+       hlist_del(&clk->child_node);
+
+       if (new_parent) {
+               /* avoid duplicate POST_RATE_CHANGE notifications */
+               if (new_parent->new_child == clk)
+                       new_parent->new_child = NULL;
+
+               hlist_add_head(&clk->child_node, &new_parent->children);
+       } else {
+               hlist_add_head(&clk->child_node, &clk_orphan_list);
+       }
+
+       clk->parent = new_parent;
+}
+
+static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+{
+       unsigned long flags;
+       int ret = 0;
+       struct clk *old_parent = clk->parent;
+
+       /*
+        * Migrate prepare state between parents and prevent race with
+        * clk_enable().
+        *
+        * If the clock is not prepared, then a race with
+        * clk_enable/disable() is impossible since we already have the
+        * prepare lock (future calls to clk_enable() need to be preceded by
+        * a clk_prepare()).
+        *
+        * If the clock is prepared, migrate the prepared state to the new
+        * parent and also protect against a race with clk_enable() by
+        * forcing the clock and the new parent on.  This ensures that all
+        * future calls to clk_enable() are practically NOPs with respect to
+        * hardware and software states.
+        *
+        * See also: Comment for clk_set_parent() below.
+        */
+       if (clk->prepare_count) {
+               __clk_prepare(parent);
+               clk_enable(parent);
+               clk_enable(clk);
+       }
+
+       /* update the clk tree topology */
+       flags = clk_enable_lock();
+       clk_reparent(clk, parent);
+       clk_enable_unlock(flags);
+
+       /* change clock input source */
+       if (parent && clk->ops->set_parent)
+               ret = clk->ops->set_parent(clk->hw, p_index);
+
+       if (ret) {
+               flags = clk_enable_lock();
+               clk_reparent(clk, old_parent);
+               clk_enable_unlock(flags);
+
+               if (clk->prepare_count) {
+                       clk_disable(clk);
+                       clk_disable(parent);
+                       __clk_unprepare(parent);
+               }
+               return ret;
+       }
+
+       /*
+        * Finish the migration of prepare state and undo the changes done
+        * for preventing a race with clk_enable().
+        */
+       if (clk->prepare_count) {
+               clk_disable(clk);
+               clk_disable(old_parent);
+               __clk_unprepare(old_parent);
+       }
+
+       /* update debugfs with new clk tree topology */
+       clk_debug_reparent(clk, parent);
+       return 0;
+}
+
 /**
  * __clk_speculate_rates
  * @clk: first clk in the subtree
@@ -1026,7 +1201,7 @@ EXPORT_SYMBOL_GPL(clk_get_rate);
  * pre-rate change notifications and returns early if no clks in the
  * subtree have subscribed to the notifications.  Note that if a clk does not
  * implement the .recalc_rate callback then it is assumed that the clock will
- * take on the rate of it's parent.
+ * take on the rate of its parent.
  *
  * Caller must hold prepare_lock.
  */
@@ -1058,18 +1233,25 @@ out:
        return ret;
 }
 
-static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
+static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
+                            struct clk *new_parent, u8 p_index)
 {
        struct clk *child;
 
        clk->new_rate = new_rate;
+       clk->new_parent = new_parent;
+       clk->new_parent_index = p_index;
+       /* include clk in new parent's PRE_RATE_CHANGE notifications */
+       clk->new_child = NULL;
+       if (new_parent && new_parent != clk->parent)
+               new_parent->new_child = clk;
 
        hlist_for_each_entry(child, &clk->children, child_node) {
                if (child->ops->recalc_rate)
                        child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
                else
                        child->new_rate = new_rate;
-               clk_calc_subtree(child, child->new_rate);
+               clk_calc_subtree(child, child->new_rate, NULL, 0);
        }
 }
 
@@ -1080,50 +1262,63 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
 static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
 {
        struct clk *top = clk;
+       struct clk *old_parent, *parent;
        unsigned long best_parent_rate = 0;
        unsigned long new_rate;
+       u8 p_index = 0;
 
        /* sanity */
        if (IS_ERR_OR_NULL(clk))
                return NULL;
 
        /* save parent rate, if it exists */
-       if (clk->parent)
-               best_parent_rate = clk->parent->rate;
-
-       /* never propagate up to the parent */
-       if (!(clk->flags & CLK_SET_RATE_PARENT)) {
-               if (!clk->ops->round_rate) {
-                       clk->new_rate = clk->rate;
-                       return NULL;
-               }
-               new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
+       parent = old_parent = clk->parent;
+       if (parent)
+               best_parent_rate = parent->rate;
+
+       /* find the closest rate and parent clk/rate */
+       if (clk->ops->determine_rate) {
+               new_rate = clk->ops->determine_rate(clk->hw, rate,
+                                                   &best_parent_rate,
+                                                   &parent);
+       } else if (clk->ops->round_rate) {
+               new_rate = clk->ops->round_rate(clk->hw, rate,
+                                               &best_parent_rate);
+       } else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
+               /* pass-through clock without adjustable parent */
+               clk->new_rate = clk->rate;
+               return NULL;
+       } else {
+               /* pass-through clock with adjustable parent */
+               top = clk_calc_new_rates(parent, rate);
+               new_rate = parent->new_rate;
                goto out;
        }
 
-       /* need clk->parent from here on out */
-       if (!clk->parent) {
-               pr_debug("%s: %s has NULL parent\n", __func__, clk->name);
+       /* some clocks must be gated to change parent */
+       if (parent != old_parent &&
+           (clk->flags & CLK_SET_PARENT_GATE) && clk->prepare_count) {
+               pr_debug("%s: %s not gated but wants to reparent\n",
+                        __func__, clk->name);
                return NULL;
        }
 
-       if (!clk->ops->round_rate) {
-               top = clk_calc_new_rates(clk->parent, rate);
-               new_rate = clk->parent->new_rate;
-
-               goto out;
+       /* try finding the new parent index */
+       if (parent) {
+               p_index = clk_fetch_parent_index(clk, parent);
+               if (p_index == clk->num_parents) {
+                       pr_debug("%s: clk %s can not be parent of clk %s\n",
+                                __func__, parent->name, clk->name);
+                       return NULL;
+               }
        }
 
-       new_rate = clk->ops->round_rate(clk->hw, rate, &best_parent_rate);
-
-       if (best_parent_rate != clk->parent->rate) {
-               top = clk_calc_new_rates(clk->parent, best_parent_rate);
-
-               goto out;
-       }
+       if ((clk->flags & CLK_SET_RATE_PARENT) && parent &&
+           best_parent_rate != parent->rate)
+               top = clk_calc_new_rates(parent, best_parent_rate);
 
 out:
-       clk_calc_subtree(clk, new_rate);
+       clk_calc_subtree(clk, new_rate, parent, p_index);
 
        return top;
 }
@@ -1135,7 +1330,7 @@ out:
  */
 static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
 {
-       struct clk *child, *fail_clk = NULL;
+       struct clk *child, *tmp_clk, *fail_clk = NULL;
        int ret = NOTIFY_DONE;
 
        if (clk->rate == clk->new_rate)
@@ -1148,9 +1343,19 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
        }
 
        hlist_for_each_entry(child, &clk->children, child_node) {
-               clk = clk_propagate_rate_change(child, event);
-               if (clk)
-                       fail_clk = clk;
+               /* Skip children who will be reparented to another clock */
+               if (child->new_parent && child->new_parent != clk)
+                       continue;
+               tmp_clk = clk_propagate_rate_change(child, event);
+               if (tmp_clk)
+                       fail_clk = tmp_clk;
+       }
+
+       /* handle the new child who might not be in clk->children yet */
+       if (clk->new_child) {
+               tmp_clk = clk_propagate_rate_change(clk->new_child, event);
+               if (tmp_clk)
+                       fail_clk = tmp_clk;
        }
 
        return fail_clk;
@@ -1168,6 +1373,10 @@ static void clk_change_rate(struct clk *clk)
 
        old_rate = clk->rate;
 
+       /* set parent */
+       if (clk->new_parent && clk->new_parent != clk->parent)
+               __clk_set_parent(clk, clk->new_parent, clk->new_parent_index);
+
        if (clk->parent)
                best_parent_rate = clk->parent->rate;
 
@@ -1182,8 +1391,16 @@ static void clk_change_rate(struct clk *clk)
        if (clk->notifier_count && old_rate != clk->rate)
                __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
 
-       hlist_for_each_entry(child, &clk->children, child_node)
+       hlist_for_each_entry(child, &clk->children, child_node) {
+               /* Skip children who will be reparented to another clock */
+               if (child->new_parent && child->new_parent != clk)
+                       continue;
                clk_change_rate(child);
+       }
+
+       /* handle the new child who might not be in clk->children yet */
+       if (clk->new_child)
+               clk_change_rate(clk->new_child);
 }
 
 /**
@@ -1198,7 +1415,7 @@ static void clk_change_rate(struct clk *clk)
  * outcome of clk's .round_rate implementation.  If *parent_rate is unchanged
  * after calling .round_rate then upstream parent propagation is ignored.  If
  * *parent_rate comes back with a new rate for clk's parent then we propagate
- * up to clk's parent and set it's rate.  Upward propagation will continue
+ * up to clk's parent and set its rate.  Upward propagation will continue
  * until either a clk does not support the CLK_SET_RATE_PARENT flag or
  * .round_rate stops requesting changes to clk's parent_rate.
  *
@@ -1212,6 +1429,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        struct clk *top, *fail_clk;
        int ret = 0;
 
+       if (!clk)
+               return 0;
+
        /* prevent racing with updates to the clock topology */
        clk_prepare_lock();
 
@@ -1315,30 +1535,12 @@ static struct clk *__clk_init_parent(struct clk *clk)
                        kzalloc((sizeof(struct clk*) * clk->num_parents),
                                        GFP_KERNEL);
 
-       if (!clk->parents)
-               ret = __clk_lookup(clk->parent_names[index]);
-       else if (!clk->parents[index])
-               ret = clk->parents[index] =
-                       __clk_lookup(clk->parent_names[index]);
-       else
-               ret = clk->parents[index];
+       ret = clk_get_parent_by_index(clk, index);
 
 out:
        return ret;
 }
 
-static void clk_reparent(struct clk *clk, struct clk *new_parent)
-{
-       hlist_del(&clk->child_node);
-
-       if (new_parent)
-               hlist_add_head(&clk->child_node, &new_parent->children);
-       else
-               hlist_add_head(&clk->child_node, &clk_orphan_list);
-
-       clk->parent = new_parent;
-}
-
 void __clk_reparent(struct clk *clk, struct clk *new_parent)
 {
        clk_reparent(clk, new_parent);
@@ -1346,98 +1548,6 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
        __clk_recalc_rates(clk, POST_RATE_CHANGE);
 }
 
-static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
-{
-       u8 i;
-
-       if (!clk->parents)
-               clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
-                                                               GFP_KERNEL);
-
-       /*
-        * find index of new parent clock using cached parent ptrs,
-        * or if not yet cached, use string name comparison and cache
-        * them now to avoid future calls to __clk_lookup.
-        */
-       for (i = 0; i < clk->num_parents; i++) {
-               if (clk->parents && clk->parents[i] == parent)
-                       break;
-               else if (!strcmp(clk->parent_names[i], parent->name)) {
-                       if (clk->parents)
-                               clk->parents[i] = __clk_lookup(parent->name);
-                       break;
-               }
-       }
-
-       return i;
-}
-
-static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
-{
-       unsigned long flags;
-       int ret = 0;
-       struct clk *old_parent = clk->parent;
-
-       /*
-        * Migrate prepare state between parents and prevent race with
-        * clk_enable().
-        *
-        * If the clock is not prepared, then a race with
-        * clk_enable/disable() is impossible since we already have the
-        * prepare lock (future calls to clk_enable() need to be preceded by
-        * a clk_prepare()).
-        *
-        * If the clock is prepared, migrate the prepared state to the new
-        * parent and also protect against a race with clk_enable() by
-        * forcing the clock and the new parent on.  This ensures that all
-        * future calls to clk_enable() are practically NOPs with respect to
-        * hardware and software states.
-        *
-        * See also: Comment for clk_set_parent() below.
-        */
-       if (clk->prepare_count) {
-               __clk_prepare(parent);
-               clk_enable(parent);
-               clk_enable(clk);
-       }
-
-       /* update the clk tree topology */
-       flags = clk_enable_lock();
-       clk_reparent(clk, parent);
-       clk_enable_unlock(flags);
-
-       /* change clock input source */
-       if (parent && clk->ops->set_parent)
-               ret = clk->ops->set_parent(clk->hw, p_index);
-
-       if (ret) {
-               flags = clk_enable_lock();
-               clk_reparent(clk, old_parent);
-               clk_enable_unlock(flags);
-
-               if (clk->prepare_count) {
-                       clk_disable(clk);
-                       clk_disable(parent);
-                       __clk_unprepare(parent);
-               }
-               return ret;
-       }
-
-       /*
-        * Finish the migration of prepare state and undo the changes done
-        * for preventing a race with clk_enable().
-        */
-       if (clk->prepare_count) {
-               clk_disable(clk);
-               clk_disable(old_parent);
-               __clk_unprepare(old_parent);
-       }
-
-       /* update debugfs with new clk tree topology */
-       clk_debug_reparent(clk, parent);
-       return 0;
-}
-
 /**
  * clk_set_parent - switch the parent of a mux clk
  * @clk: the mux clk whose input we are switching
@@ -1461,7 +1571,10 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
        u8 p_index = 0;
        unsigned long p_rate = 0;
 
-       if (!clk || !clk->ops)
+       if (!clk)
+               return 0;
+
+       if (!clk->ops)
                return -EINVAL;
 
        /* verify ops for for multi-parent clks */
@@ -1544,8 +1657,9 @@ int __clk_init(struct device *dev, struct clk *clk)
 
        /* check that clk_ops are sane.  See Documentation/clk.txt */
        if (clk->ops->set_rate &&
-                       !(clk->ops->round_rate && clk->ops->recalc_rate)) {
-               pr_warning("%s: %s must implement .round_rate & .recalc_rate\n",
+           !((clk->ops->round_rate || clk->ops->determine_rate) &&
+             clk->ops->recalc_rate)) {
+               pr_warning("%s: %s must implement .round_rate or .determine_rate in addition to .recalc_rate\n",
                                __func__, clk->name);
                ret = -EINVAL;
                goto out;
@@ -1628,7 +1742,7 @@ int __clk_init(struct device *dev, struct clk *clk)
         * this clock
         */
        hlist_for_each_entry_safe(orphan, tmp2, &clk_orphan_list, child_node) {
-               if (orphan->ops->get_parent) {
+               if (orphan->num_parents && orphan->ops->get_parent) {
                        i = orphan->ops->get_parent(orphan->hw);
                        if (!strcmp(clk->name, orphan->parent_names[i]))
                                __clk_reparent(orphan, clk);
@@ -1648,7 +1762,7 @@ int __clk_init(struct device *dev, struct clk *clk)
         * The .init callback is not used by any of the basic clock types, but
         * exists for weird hardware that must perform initialization magic.
         * Please consider other ways of solving initialization problems before
-        * using this callback, as it's use is discouraged.
+        * using this callback, as its use is discouraged.
         */
        if (clk->ops->init)
                clk->ops->init(clk->hw);
@@ -1675,7 +1789,7 @@ out:
  * very large numbers of clocks that need to be statically initialized.  It is
  * a layering violation to include clk-private.h from any code which implements
  * a clock's .ops; as such any statically initialized clock data MUST be in a
- * separate C file from the logic that implements it's operations.  Returns 0
+ * separate C file from the logic that implements its operations.  Returns 0
  * on success, otherwise an error code.
  */
 struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
@@ -2115,13 +2229,13 @@ EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
  */
 void __init of_clk_init(const struct of_device_id *matches)
 {
+       const struct of_device_id *match;
        struct device_node *np;
 
        if (!matches)
                matches = __clk_of_table;
 
-       for_each_matching_node(np, matches) {
-               const struct of_device_id *match = of_match_node(matches, np);
+       for_each_matching_node_and_match(np, matches, &match) {
                of_clk_init_cb_t clk_init_cb = match->data;
                clk_init_cb(np);
        }
index d1f1a19d4351e8e9d2fb5fe580d46babf39c0487..b2721cae257adcca4a106cee4e9a9e443bf5d808 100644 (file)
@@ -248,7 +248,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp2-pwm.3");
 
        clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, vctcxo);
        clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -258,7 +259,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
 
        clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, vctcxo);
        clk_register_clkdev(clk, "uart_mux.1", NULL);
@@ -268,7 +270,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
 
        clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, vctcxo);
        clk_register_clkdev(clk, "uart_mux.2", NULL);
@@ -278,7 +281,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
 
        clk = clk_register_mux(NULL, "uart3_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART3, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, vctcxo);
        clk_register_clkdev(clk, "uart_mux.3", NULL);
@@ -288,7 +292,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.3");
 
        clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "uart_mux.0", NULL);
 
@@ -297,7 +302,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.0");
 
        clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.1", NULL);
 
@@ -306,7 +312,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.1");
 
        clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.2", NULL);
 
@@ -315,7 +322,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.2");
 
        clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.3", NULL);
 
@@ -324,7 +332,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.3");
 
        clk = clk_register_mux(NULL, "sdh_mux", sdh_parent,
-                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(sdh_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_SDH0, 8, 2, 0, &clk_lock);
        clk_register_clkdev(clk, "sdh_mux", NULL);
 
@@ -354,7 +363,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, "usb_clk", NULL);
 
        clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
-                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(disp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_DISP0, 6, 2, 0, &clk_lock);
        clk_register_clkdev(clk, "disp_mux.0", NULL);
 
@@ -376,7 +386,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, "disp_sphy.0", NULL);
 
        clk = clk_register_mux(NULL, "disp1_mux", disp_parent,
-                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(disp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_DISP1, 6, 2, 0, &clk_lock);
        clk_register_clkdev(clk, "disp_mux.1", NULL);
 
@@ -394,7 +405,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, "ccic_arbiter", NULL);
 
        clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
-                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ccic_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_CCIC0, 6, 2, 0, &clk_lock);
        clk_register_clkdev(clk, "ccic_mux.0", NULL);
 
@@ -421,7 +433,8 @@ void __init mmp2_clk_init(void)
        clk_register_clkdev(clk, "sphyclk", "mmp-ccic.0");
 
        clk = clk_register_mux(NULL, "ccic1_mux", ccic_parent,
-                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ccic_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_CCIC1, 6, 2, 0, &clk_lock);
        clk_register_clkdev(clk, "ccic_mux.1", NULL);
 
index 28b3b51c794b1600aa58df38a3533589f06101e9..014396b028a2c8c137723ccf2063f2dba6404f02 100644 (file)
@@ -199,7 +199,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa168-pwm.3");
 
        clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, uart_pll);
        clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -209,7 +210,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
 
        clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, uart_pll);
        clk_register_clkdev(clk, "uart_mux.1", NULL);
@@ -219,7 +221,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
 
        clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART2, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, uart_pll);
        clk_register_clkdev(clk, "uart_mux.2", NULL);
@@ -229,7 +232,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
 
        clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "uart_mux.0", NULL);
 
@@ -238,7 +242,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.0");
 
        clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.1", NULL);
 
@@ -247,7 +252,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.1");
 
        clk = clk_register_mux(NULL, "ssp2_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP2, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.2", NULL);
 
@@ -256,7 +262,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.2");
 
        clk = clk_register_mux(NULL, "ssp3_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP3, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.3", NULL);
 
@@ -265,7 +272,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.3");
 
        clk = clk_register_mux(NULL, "ssp4_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP4, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.4", NULL);
 
@@ -278,7 +286,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
 
        clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
-                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(sdh_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "sdh0_mux", NULL);
 
@@ -287,7 +296,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
 
        clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
-                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(sdh_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "sdh1_mux", NULL);
 
@@ -304,7 +314,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, "sph_clk", NULL);
 
        clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
-                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(disp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "disp_mux.0", NULL);
 
@@ -317,7 +328,8 @@ void __init pxa168_clk_init(void)
        clk_register_clkdev(clk, "hclk", "mmp-disp.0");
 
        clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
-                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ccic_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "ccic_mux.0", NULL);
 
@@ -327,8 +339,8 @@ void __init pxa168_clk_init(void)
 
        clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
                                ARRAY_SIZE(ccic_phy_parent),
-                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
-                               7, 1, 0, &clk_lock);
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+                               apmu_base + APMU_CCIC0, 7, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
 
        clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
index 6ec05698ed38cf9ff651ad0159f533d2ebad8711..9efc6a47535d3bf07747e3373078daef8162794a 100644 (file)
@@ -204,7 +204,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa910-pwm.3");
 
        clk = clk_register_mux(NULL, "uart0_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART0, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, uart_pll);
        clk_register_clkdev(clk, "uart_mux.0", NULL);
@@ -214,7 +215,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.0");
 
        clk = clk_register_mux(NULL, "uart1_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_UART1, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, uart_pll);
        clk_register_clkdev(clk, "uart_mux.1", NULL);
@@ -224,7 +226,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.1");
 
        clk = clk_register_mux(NULL, "uart2_mux", uart_parent,
-                               ARRAY_SIZE(uart_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(uart_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbcp_base + APBCP_UART2, 4, 3, 0, &clk_lock);
        clk_set_parent(clk, uart_pll);
        clk_register_clkdev(clk, "uart_mux.2", NULL);
@@ -234,7 +237,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa2xx-uart.2");
 
        clk = clk_register_mux(NULL, "ssp0_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP0, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "uart_mux.0", NULL);
 
@@ -243,7 +247,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-ssp.0");
 
        clk = clk_register_mux(NULL, "ssp1_mux", ssp_parent,
-                               ARRAY_SIZE(ssp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ssp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apbc_base + APBC_SSP1, 4, 3, 0, &clk_lock);
        clk_register_clkdev(clk, "ssp_mux.1", NULL);
 
@@ -256,7 +261,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "pxa3xx-nand.0");
 
        clk = clk_register_mux(NULL, "sdh0_mux", sdh_parent,
-                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(sdh_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_SDH0, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "sdh0_mux", NULL);
 
@@ -265,7 +271,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "sdhci-pxa.0");
 
        clk = clk_register_mux(NULL, "sdh1_mux", sdh_parent,
-                               ARRAY_SIZE(sdh_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(sdh_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_SDH1, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "sdh1_mux", NULL);
 
@@ -282,7 +289,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, "sph_clk", NULL);
 
        clk = clk_register_mux(NULL, "disp0_mux", disp_parent,
-                               ARRAY_SIZE(disp_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(disp_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_DISP0, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "disp_mux.0", NULL);
 
@@ -291,7 +299,8 @@ void __init pxa910_clk_init(void)
        clk_register_clkdev(clk, NULL, "mmp-disp.0");
 
        clk = clk_register_mux(NULL, "ccic0_mux", ccic_parent,
-                               ARRAY_SIZE(ccic_parent), CLK_SET_RATE_PARENT,
+                               ARRAY_SIZE(ccic_parent),
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                                apmu_base + APMU_CCIC0, 6, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "ccic_mux.0", NULL);
 
@@ -301,8 +310,8 @@ void __init pxa910_clk_init(void)
 
        clk = clk_register_mux(NULL, "ccic0_phy_mux", ccic_phy_parent,
                                ARRAY_SIZE(ccic_phy_parent),
-                               CLK_SET_RATE_PARENT, apmu_base + APMU_CCIC0,
-                               7, 1, 0, &clk_lock);
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+                               apmu_base + APMU_CCIC0, 7, 1, 0, &clk_lock);
        clk_register_clkdev(clk, "ccic_phy_mux.0", NULL);
 
        clk = mmp_clk_register_apmu("ccic0_phy", "ccic0_phy_mux",
index 079960e7c304baca3b809eafec9b4be5f79bbfef..fc777bdc1886586d2f7e0e253ddc1e78758d4927 100644 (file)
 
 enum { A370_CPU_TO_NBCLK, A370_CPU_TO_HCLK, A370_CPU_TO_DRAMCLK };
 
-static const struct coreclk_ratio __initconst a370_coreclk_ratios[] = {
+static const struct coreclk_ratio a370_coreclk_ratios[] __initconst = {
        { .id = A370_CPU_TO_NBCLK, .name = "nbclk" },
        { .id = A370_CPU_TO_HCLK, .name = "hclk" },
        { .id = A370_CPU_TO_DRAMCLK, .name = "dramclk" },
 };
 
-static const u32 __initconst a370_tclk_freqs[] = {
+static const u32 a370_tclk_freqs[] __initconst = {
        16600000,
        20000000,
 };
@@ -52,7 +52,7 @@ static u32 __init a370_get_tclk_freq(void __iomem *sar)
        return a370_tclk_freqs[tclk_freq_select];
 }
 
-static const u32 __initconst a370_cpu_freqs[] = {
+static const u32 a370_cpu_freqs[] __initconst = {
        400000000,
        533000000,
        667000000,
@@ -78,7 +78,7 @@ static u32 __init a370_get_cpu_freq(void __iomem *sar)
        return cpu_freq;
 }
 
-static const int __initconst a370_nbclk_ratios[32][2] = {
+static const int a370_nbclk_ratios[32][2] __initconst = {
        {0, 1}, {1, 2}, {2, 2}, {2, 2},
        {1, 2}, {1, 2}, {1, 1}, {2, 3},
        {0, 1}, {1, 2}, {2, 4}, {0, 1},
@@ -89,7 +89,7 @@ static const int __initconst a370_nbclk_ratios[32][2] = {
        {0, 1}, {0, 1}, {0, 1}, {0, 1},
 };
 
-static const int __initconst a370_hclk_ratios[32][2] = {
+static const int a370_hclk_ratios[32][2] __initconst = {
        {0, 1}, {1, 2}, {2, 6}, {2, 3},
        {1, 3}, {1, 4}, {1, 2}, {2, 6},
        {0, 1}, {1, 6}, {2, 10}, {0, 1},
@@ -100,7 +100,7 @@ static const int __initconst a370_hclk_ratios[32][2] = {
        {0, 1}, {0, 1}, {0, 1}, {0, 1},
 };
 
-static const int __initconst a370_dramclk_ratios[32][2] = {
+static const int a370_dramclk_ratios[32][2] __initconst = {
        {0, 1}, {1, 2}, {2, 3}, {2, 3},
        {1, 3}, {1, 2}, {1, 2}, {2, 6},
        {0, 1}, {1, 3}, {2, 5}, {0, 1},
@@ -152,7 +152,7 @@ CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock",
  * Clock Gating Control
  */
 
-static const struct clk_gating_soc_desc __initconst a370_gating_desc[] = {
+static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = {
        { "audio", NULL, 0, 0 },
        { "pex0_en", NULL, 1, 0 },
        { "pex1_en", NULL,  2, 0 },
index 13b62ceb340794f2c88be8307c35b78084b8e887..9922c4475aa8b3f7d01c2881c8a757b94f9027af 100644 (file)
@@ -40,7 +40,7 @@
 
 enum { AXP_CPU_TO_NBCLK, AXP_CPU_TO_HCLK, AXP_CPU_TO_DRAMCLK };
 
-static const struct coreclk_ratio __initconst axp_coreclk_ratios[] = {
+static const struct coreclk_ratio axp_coreclk_ratios[] __initconst = {
        { .id = AXP_CPU_TO_NBCLK, .name = "nbclk" },
        { .id = AXP_CPU_TO_HCLK, .name = "hclk" },
        { .id = AXP_CPU_TO_DRAMCLK, .name = "dramclk" },
@@ -52,7 +52,7 @@ static u32 __init axp_get_tclk_freq(void __iomem *sar)
        return 250000000;
 }
 
-static const u32 __initconst axp_cpu_freqs[] = {
+static const u32 axp_cpu_freqs[] __initconst = {
        1000000000,
        1066000000,
        1200000000,
@@ -89,7 +89,7 @@ static u32 __init axp_get_cpu_freq(void __iomem *sar)
        return cpu_freq;
 }
 
-static const int __initconst axp_nbclk_ratios[32][2] = {
+static const int axp_nbclk_ratios[32][2] __initconst = {
        {0, 1}, {1, 2}, {2, 2}, {2, 2},
        {1, 2}, {1, 2}, {1, 1}, {2, 3},
        {0, 1}, {1, 2}, {2, 4}, {0, 1},
@@ -100,7 +100,7 @@ static const int __initconst axp_nbclk_ratios[32][2] = {
        {0, 1}, {0, 1}, {0, 1}, {0, 1},
 };
 
-static const int __initconst axp_hclk_ratios[32][2] = {
+static const int axp_hclk_ratios[32][2] __initconst = {
        {0, 1}, {1, 2}, {2, 6}, {2, 3},
        {1, 3}, {1, 4}, {1, 2}, {2, 6},
        {0, 1}, {1, 6}, {2, 10}, {0, 1},
@@ -111,7 +111,7 @@ static const int __initconst axp_hclk_ratios[32][2] = {
        {0, 1}, {0, 1}, {0, 1}, {0, 1},
 };
 
-static const int __initconst axp_dramclk_ratios[32][2] = {
+static const int axp_dramclk_ratios[32][2] __initconst = {
        {0, 1}, {1, 2}, {2, 3}, {2, 3},
        {1, 3}, {1, 2}, {1, 2}, {2, 6},
        {0, 1}, {1, 3}, {2, 5}, {0, 1},
@@ -169,7 +169,7 @@ CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock",
  * Clock Gating Control
  */
 
-static const struct clk_gating_soc_desc __initconst axp_gating_desc[] = {
+static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = {
        { "audio", NULL, 0, 0 },
        { "ge3", NULL, 1, 0 },
        { "ge2", NULL,  2, 0 },
index b0fbc07154912072bce34e4684e0a0fb57d2cf52..1466865b0743bf2110b74a6832acbef832743b77 100644 (file)
@@ -119,7 +119,7 @@ void __init of_cpu_clk_setup(struct device_node *node)
 
        cpuclk = kzalloc(ncpus * sizeof(*cpuclk), GFP_KERNEL);
        if (WARN_ON(!cpuclk))
-               return;
+               goto cpuclk_out;
 
        clks = kzalloc(ncpus * sizeof(*clks), GFP_KERNEL);
        if (WARN_ON(!clks))
@@ -170,6 +170,8 @@ bail_out:
                kfree(cpuclk[ncpus].clk_name);
 clks_out:
        kfree(cpuclk);
+cpuclk_out:
+       iounmap(clock_complex_base);
 }
 
 CLK_OF_DECLARE(armada_xp_cpu_clock, "marvell,armada-xp-cpu-clock",
index adaa4a1821b843a3f63a883e0e4f082d6a8e3c41..25ceccf939ad2f33cdc71907d91e68b8e69a64be 100644 (file)
@@ -45,8 +45,10 @@ void __init mvebu_coreclk_setup(struct device_node *np,
        clk_data.clk_num = 2 + desc->num_ratios;
        clk_data.clks = kzalloc(clk_data.clk_num * sizeof(struct clk *),
                                GFP_KERNEL);
-       if (WARN_ON(!clk_data.clks))
+       if (WARN_ON(!clk_data.clks)) {
+               iounmap(base);
                return;
+       }
 
        /* Register TCLK */
        of_property_read_string_index(np, "clock-output-names", 0,
@@ -134,7 +136,7 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
 
        ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
        if (WARN_ON(!ctrl))
-               return;
+               goto ctrl_out;
 
        spin_lock_init(&ctrl->lock);
 
@@ -145,10 +147,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
        ctrl->num_gates = n;
        ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *),
                              GFP_KERNEL);
-       if (WARN_ON(!ctrl->gates)) {
-               kfree(ctrl);
-               return;
-       }
+       if (WARN_ON(!ctrl->gates))
+               goto gates_out;
 
        for (n = 0; n < ctrl->num_gates; n++) {
                const char *parent =
@@ -160,4 +160,10 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
        }
 
        of_clk_add_provider(np, clk_gating_get_src, ctrl);
+
+       return;
+gates_out:
+       kfree(ctrl);
+ctrl_out:
+       iounmap(base);
 }
index 79d7aedf03fb95b7e81e1907e1703341d2f014ad..38aee1e3f242b237079aaeb775aa2fd8dae89453 100644 (file)
 
 enum { DOVE_CPU_TO_L2, DOVE_CPU_TO_DDR };
 
-static const struct coreclk_ratio __initconst dove_coreclk_ratios[] = {
+static const struct coreclk_ratio dove_coreclk_ratios[] __initconst = {
        { .id = DOVE_CPU_TO_L2, .name = "l2clk", },
        { .id = DOVE_CPU_TO_DDR, .name = "ddrclk", }
 };
 
-static const u32 __initconst dove_tclk_freqs[] = {
+static const u32 dove_tclk_freqs[] __initconst = {
        166666667,
        125000000,
        0, 0
@@ -92,7 +92,7 @@ static u32 __init dove_get_tclk_freq(void __iomem *sar)
        return dove_tclk_freqs[opt];
 }
 
-static const u32 __initconst dove_cpu_freqs[] = {
+static const u32 dove_cpu_freqs[] __initconst = {
        0, 0, 0, 0, 0,
        1000000000,
        933333333, 933333333,
@@ -111,12 +111,12 @@ static u32 __init dove_get_cpu_freq(void __iomem *sar)
        return dove_cpu_freqs[opt];
 }
 
-static const int __initconst dove_cpu_l2_ratios[8][2] = {
+static const int dove_cpu_l2_ratios[8][2] __initconst = {
        { 1, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
        { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 }
 };
 
-static const int __initconst dove_cpu_ddr_ratios[16][2] = {
+static const int dove_cpu_ddr_ratios[16][2] __initconst = {
        { 1, 1 }, { 0, 1 }, { 1, 2 }, { 2, 5 },
        { 1, 3 }, { 0, 1 }, { 1, 4 }, { 0, 1 },
        { 1, 5 }, { 0, 1 }, { 1, 6 }, { 0, 1 },
@@ -164,7 +164,7 @@ CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init);
  * Clock Gating Control
  */
 
-static const struct clk_gating_soc_desc __initconst dove_gating_desc[] = {
+static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = {
        { "usb0", NULL, 0, 0 },
        { "usb1", NULL, 1, 0 },
        { "ge", "gephy", 2, 0 },
index 71d24619ccdb14400c5c7e0ada911125b923e80d..2636a55f29f9403df92aec0c11e5a504fc7f9deb 100644 (file)
@@ -78,7 +78,7 @@
 
 enum { KIRKWOOD_CPU_TO_L2, KIRKWOOD_CPU_TO_DDR };
 
-static const struct coreclk_ratio __initconst kirkwood_coreclk_ratios[] = {
+static const struct coreclk_ratio kirkwood_coreclk_ratios[] __initconst = {
        { .id = KIRKWOOD_CPU_TO_L2, .name = "l2clk", },
        { .id = KIRKWOOD_CPU_TO_DDR, .name = "ddrclk", }
 };
@@ -90,7 +90,7 @@ static u32 __init kirkwood_get_tclk_freq(void __iomem *sar)
        return (opt) ? 166666667 : 200000000;
 }
 
-static const u32 __initconst kirkwood_cpu_freqs[] = {
+static const u32 kirkwood_cpu_freqs[] __initconst = {
        0, 0, 0, 0,
        600000000,
        0,
@@ -111,12 +111,12 @@ static u32 __init kirkwood_get_cpu_freq(void __iomem *sar)
        return kirkwood_cpu_freqs[opt];
 }
 
-static const int __initconst kirkwood_cpu_l2_ratios[8][2] = {
+static const int kirkwood_cpu_l2_ratios[8][2] __initconst = {
        { 0, 1 }, { 1, 2 }, { 0, 1 }, { 1, 3 },
        { 0, 1 }, { 1, 4 }, { 0, 1 }, { 0, 1 }
 };
 
-static const int __initconst kirkwood_cpu_ddr_ratios[16][2] = {
+static const int kirkwood_cpu_ddr_ratios[16][2] __initconst = {
        { 0, 1 }, { 0, 1 }, { 1, 2 }, { 0, 1 },
        { 1, 3 }, { 0, 1 }, { 1, 4 }, { 2, 9 },
        { 1, 5 }, { 1, 6 }, { 0, 1 }, { 0, 1 },
@@ -145,7 +145,7 @@ static void __init kirkwood_get_clk_ratio(
        }
 }
 
-static const u32 __initconst mv88f6180_cpu_freqs[] = {
+static const u32 mv88f6180_cpu_freqs[] __initconst = {
        0, 0, 0, 0, 0,
        600000000,
        800000000,
@@ -158,7 +158,7 @@ static u32 __init mv88f6180_get_cpu_freq(void __iomem *sar)
        return mv88f6180_cpu_freqs[opt];
 }
 
-static const int __initconst mv88f6180_cpu_ddr_ratios[8][2] = {
+static const int mv88f6180_cpu_ddr_ratios[8][2] __initconst = {
        { 0, 1 }, { 0, 1 }, { 0, 1 }, { 0, 1 },
        { 0, 1 }, { 1, 3 }, { 1, 4 }, { 1, 5 }
 };
@@ -219,7 +219,7 @@ CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock",
  * Clock Gating Control
  */
 
-static const struct clk_gating_soc_desc __initconst kirkwood_gating_desc[] = {
+static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = {
        { "ge0", NULL, 0, 0 },
        { "pex0", NULL, 2, 0 },
        { "usb0", NULL, 3, 0 },
index f6a74872f14ee78a1a91b3cca813949bb814059a..c396fe3615891501e6f7a21ca6c3bfe88d81acec 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/clk.h>
+#include <linux/clk/mxs.h>
 #include <linux/clkdev.h>
 #include <linux/err.h>
 #include <linux/init.h>
index 81421e28e69ca8e7b7a28bb8dabd526f3006ad64..ef10ad9b5daa0b48601670d0e40fe3d01da60dfa 100644 (file)
@@ -52,8 +52,8 @@ static inline struct clk *mxs_clk_mux(const char *name, void __iomem *reg,
                u8 shift, u8 width, const char **parent_names, int num_parents)
 {
        return clk_register_mux(NULL, name, parent_names, num_parents,
-                               CLK_SET_RATE_PARENT, reg, shift, width,
-                               0, &mxs_lock);
+                               CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+                               reg, shift, width, 0, &mxs_lock);
 }
 
 static inline struct clk *mxs_clk_fixed_factor(const char *name,
index 5d4d432cc4acc1086fba972e9140b37a7c47c17b..3413380086d5b22f7e9a618231e33af9a1e37b1e 100644 (file)
@@ -8,3 +8,6 @@ obj-$(CONFIG_SOC_EXYNOS5250)    += clk-exynos5250.o
 obj-$(CONFIG_SOC_EXYNOS5420)   += clk-exynos5420.o
 obj-$(CONFIG_SOC_EXYNOS5440)   += clk-exynos5440.o
 obj-$(CONFIG_ARCH_EXYNOS)      += clk-exynos-audss.o
+ifdef CONFIG_COMMON_CLK
+obj-$(CONFIG_ARCH_S3C64XX)     += clk-s3c64xx.o
+endif
index 9b1bbd52fd1f227b01a460a24b7dcb4db562c58f..39b40aaede2b36a3bd92546ff344420b480fb569 100644 (file)
@@ -62,7 +62,7 @@ static struct syscore_ops exynos_audss_clk_syscore_ops = {
 #endif /* CONFIG_PM_SLEEP */
 
 /* register exynos_audss clocks */
-void __init exynos_audss_clk_init(struct device_node *np)
+static void __init exynos_audss_clk_init(struct device_node *np)
 {
        reg_base = of_iomap(np, 0);
        if (!reg_base) {
@@ -82,11 +82,13 @@ void __init exynos_audss_clk_init(struct device_node *np)
        of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
        clk_table[EXYNOS_MOUT_AUDSS] = clk_register_mux(NULL, "mout_audss",
-                               mout_audss_p, ARRAY_SIZE(mout_audss_p), 0,
+                               mout_audss_p, ARRAY_SIZE(mout_audss_p),
+                               CLK_SET_RATE_NO_REPARENT,
                                reg_base + ASS_CLK_SRC, 0, 1, 0, &lock);
 
        clk_table[EXYNOS_MOUT_I2S] = clk_register_mux(NULL, "mout_i2s",
-                               mout_i2s_p, ARRAY_SIZE(mout_i2s_p), 0,
+                               mout_i2s_p, ARRAY_SIZE(mout_i2s_p),
+                               CLK_SET_RATE_NO_REPARENT,
                                reg_base + ASS_CLK_SRC, 2, 2, 0, &lock);
 
        clk_table[EXYNOS_DOUT_SRP] = clk_register_divider(NULL, "dout_srp",
index 4e5739773c33a25f6bf5503e9261b18a11a473d2..ad5ff50c5f281a5e1c31c498c78c5a717aa464de 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/of_address.h>
 
 #include "clk.h"
-#include "clk-pll.h"
 
 /* Exynos4 clock controller register offsets */
 #define SRC_LEFTBUS            0x4200
 #define GATE_IP_PERIL          0xc950
 #define E4210_GATE_IP_PERIR    0xc960
 #define GATE_BLOCK             0xc970
+#define E4X12_MPLL_LOCK                0x10008
 #define E4X12_MPLL_CON0                0x10108
 #define SRC_DMC                        0x10200
 #define SRC_MASK_DMC           0x10300
 #define DIV_DMC0               0x10500
 #define DIV_DMC1               0x10504
 #define GATE_IP_DMC            0x10900
+#define APLL_LOCK              0x14000
+#define E4210_MPLL_LOCK                0x14008
 #define APLL_CON0              0x14100
 #define E4210_MPLL_CON0                0x14108
 #define SRC_CPU                        0x14200
@@ -121,6 +123,12 @@ enum exynos4_soc {
        EXYNOS4X12,
 };
 
+/* list of PLLs to be registered */
+enum exynos4_plls {
+       apll, mpll, epll, vpll,
+       nr_plls                 /* number of PLLs */
+};
+
 /*
  * Let each supported clock get a unique id. This id is used to lookup the clock
  * for device tree based platforms. The clocks are categorized into three
@@ -169,7 +177,7 @@ enum exynos4_clks {
        gicisp, smmu_isp, smmu_drc, smmu_fd, smmu_lite0, smmu_lite1, mcuctl_isp,
        mpwm_isp, i2c0_isp, i2c1_isp, mtcadc_isp, pwm_isp, wdt_isp, uart_isp,
        asyncaxim, smmu_ispcx, spi0_isp, spi1_isp, pwm_isp_sclk, spi0_isp_sclk,
-       spi1_isp_sclk, uart_isp_sclk,
+       spi1_isp_sclk, uart_isp_sclk, tmu_apbif,
 
        /* mux clocks */
        mout_fimc0 = 384, mout_fimc1, mout_fimc2, mout_fimc3, mout_cam0,
@@ -187,7 +195,7 @@ enum exynos4_clks {
  * list of controller registers to be saved and restored during a
  * suspend/resume cycle.
  */
-static __initdata unsigned long exynos4210_clk_save[] = {
+static unsigned long exynos4210_clk_save[] __initdata = {
        E4210_SRC_IMAGE,
        E4210_SRC_LCD1,
        E4210_SRC_MASK_LCD1,
@@ -198,7 +206,7 @@ static __initdata unsigned long exynos4210_clk_save[] = {
        E4210_MPLL_CON0,
 };
 
-static __initdata unsigned long exynos4x12_clk_save[] = {
+static unsigned long exynos4x12_clk_save[] __initdata = {
        E4X12_GATE_IP_IMAGE,
        E4X12_GATE_IP_PERIR,
        E4X12_SRC_CAM1,
@@ -207,7 +215,7 @@ static __initdata unsigned long exynos4x12_clk_save[] = {
        E4X12_MPLL_CON0,
 };
 
-static __initdata unsigned long exynos4_clk_regs[] = {
+static unsigned long exynos4_clk_regs[] __initdata = {
        SRC_LEFTBUS,
        DIV_LEFTBUS,
        GATE_IP_LEFTBUS,
@@ -338,24 +346,24 @@ PNAME(mout_user_aclk200_p4x12) = {"fin_pll", "div_aclk200", };
 PNAME(mout_user_aclk266_gps_p4x12) = {"fin_pll", "div_aclk266_gps", };
 
 /* fixed rate clocks generated outside the soc */
-struct samsung_fixed_rate_clock exynos4_fixed_rate_ext_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos4_fixed_rate_ext_clks[] __initdata = {
        FRATE(xxti, "xxti", NULL, CLK_IS_ROOT, 0),
        FRATE(xusbxti, "xusbxti", NULL, CLK_IS_ROOT, 0),
 };
 
 /* fixed rate clocks generated inside the soc */
-struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos4_fixed_rate_clks[] __initdata = {
        FRATE(none, "sclk_hdmi24m", NULL, CLK_IS_ROOT, 24000000),
        FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 27000000),
        FRATE(none, "sclk_usbphy0", NULL, CLK_IS_ROOT, 48000000),
 };
 
-struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {
        FRATE(none, "sclk_usbphy1", NULL, CLK_IS_ROOT, 48000000),
 };
 
 /* list of mux clocks supported in all exynos4 soc's */
-struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
        MUX_FA(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
                        CLK_SET_RATE_PARENT, 0, "mout_apll"),
        MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
@@ -367,17 +375,20 @@ struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
                        CLK_SET_RATE_PARENT, 0),
        MUX(none, "mout_spdif", mout_spdif_p, SRC_PERIL1, 8, 2),
        MUX(none, "mout_onenand1", mout_onenand1_p, SRC_TOP0, 0, 1),
-       MUX_A(sclk_epll, "sclk_epll", mout_epll_p, SRC_TOP0, 4, 1, "sclk_epll"),
+       MUX(sclk_epll, "sclk_epll", mout_epll_p, SRC_TOP0, 4, 1),
        MUX(none, "mout_onenand", mout_onenand_p, SRC_TOP0, 28, 1),
 };
 
 /* list of mux clocks supported in exynos4210 soc */
-struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos4210_mux_early[] __initdata = {
+       MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP1, 0, 1),
+};
+
+static struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
        MUX(none, "mout_aclk200", sclk_ampll_p4210, SRC_TOP0, 12, 1),
        MUX(none, "mout_aclk100", sclk_ampll_p4210, SRC_TOP0, 16, 1),
        MUX(none, "mout_aclk160", sclk_ampll_p4210, SRC_TOP0, 20, 1),
        MUX(none, "mout_aclk133", sclk_ampll_p4210, SRC_TOP0, 24, 1),
-       MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP1, 0, 1),
        MUX(none, "mout_mixer", mout_mixer_p4210, SRC_TV, 4, 1),
        MUX(none, "mout_dac", mout_dac_p4210, SRC_TV, 8, 1),
        MUX(none, "mout_g2d0", sclk_ampll_p4210, E4210_SRC_IMAGE, 0, 1),
@@ -385,11 +396,9 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
        MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1),
        MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
        MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
-       MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "mout_mpll"),
-       MUX_A(mout_core, "mout_core", mout_core_p4210,
-                       SRC_CPU, 16, 1, "moutcore"),
-       MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210,
-                       SRC_TOP0, 8, 1, "sclk_vpll"),
+       MUX(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1),
+       MUX(mout_core, "mout_core", mout_core_p4210, SRC_CPU, 16, 1),
+       MUX(sclk_vpll, "sclk_vpll", sclk_vpll_p4210, SRC_TOP0, 8, 1),
        MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
        MUX(mout_fimc1, "mout_fimc1", group1_p4210, SRC_CAM, 4, 4),
        MUX(mout_fimc2, "mout_fimc2", group1_p4210, SRC_CAM, 8, 4),
@@ -423,9 +432,9 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
 };
 
 /* list of mux clocks supported in exynos4x12 soc */
-struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
-       MUX_A(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
-                       SRC_CPU, 24, 1, "mout_mpll"),
+static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
+       MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
+                       SRC_CPU, 24, 1),
        MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1),
        MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1),
        MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12,
@@ -445,12 +454,9 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
        MUX(none, "mout_jpeg0", sclk_ampll_p4x12, E4X12_SRC_CAM1, 0, 1),
        MUX(none, "mout_jpeg1", sclk_evpll_p, E4X12_SRC_CAM1, 4, 1),
        MUX(none, "mout_jpeg", mout_jpeg_p, E4X12_SRC_CAM1, 8, 1),
-       MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p,
-                       SRC_DMC, 12, 1, "sclk_mpll"),
-       MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p,
-                       SRC_TOP0, 8, 1, "sclk_vpll"),
-       MUX_A(mout_core, "mout_core", mout_core_p4x12,
-                       SRC_CPU, 16, 1, "moutcore"),
+       MUX(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_DMC, 12, 1),
+       MUX(sclk_vpll, "sclk_vpll", mout_vpll_p, SRC_TOP0, 8, 1),
+       MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
        MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
        MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
        MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
@@ -491,7 +497,7 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
 };
 
 /* list of divider clocks supported in all exynos4 soc's */
-struct samsung_div_clock exynos4_div_clks[] __initdata = {
+static struct samsung_div_clock exynos4_div_clks[] __initdata = {
        DIV(none, "div_core", "mout_core", DIV_CPU0, 0, 3),
        DIV(none, "div_core2", "div_core", DIV_CPU0, 28, 3),
        DIV(none, "div_fimc0", "mout_fimc0", DIV_CAM, 0, 4),
@@ -538,9 +544,8 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {
        DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),
        DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
        DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
-       DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "armclk"),
-       DIV_A(sclk_apll, "sclk_apll", "mout_apll",
-                       DIV_CPU0, 24, 3, "sclk_apll"),
+       DIV(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3),
+       DIV(sclk_apll, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3),
        DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
                        CLK_SET_RATE_PARENT, 0),
        DIV_F(none, "div_mmc_pre0", "div_mmc0", DIV_FSYS1, 8, 8,
@@ -554,7 +559,7 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {
 };
 
 /* list of divider clocks supported in exynos4210 soc */
-struct samsung_div_clock exynos4210_div_clks[] __initdata = {
+static struct samsung_div_clock exynos4210_div_clks[] __initdata = {
        DIV(aclk200, "aclk200", "mout_aclk200", DIV_TOP, 0, 3),
        DIV(sclk_fimg2d, "sclk_fimg2d", "mout_g2d", DIV_IMAGE, 0, 4),
        DIV(none, "div_fimd1", "mout_fimd1", E4210_DIV_LCD1, 0, 4),
@@ -565,7 +570,7 @@ struct samsung_div_clock exynos4210_div_clks[] __initdata = {
 };
 
 /* list of divider clocks supported in exynos4x12 soc */
-struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
+static struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
        DIV(none, "div_mdnie0", "mout_mdnie0", DIV_LCD0, 4, 4),
        DIV(none, "div_mdnie_pwm0", "mout_mdnie_pwm0", DIV_LCD0, 8, 4),
        DIV(none, "div_mdnie_pwm_pre0", "div_mdnie_pwm0", DIV_LCD0, 12, 4),
@@ -594,7 +599,7 @@ struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
 };
 
 /* list of gate clocks supported in all exynos4 soc's */
-struct samsung_gate_clock exynos4_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos4_gate_clks[] __initdata = {
        /*
         * After all Exynos4 based platforms are migrated to use device tree,
         * the device name and clock alias names specified below for some
@@ -629,164 +634,151 @@ struct samsung_gate_clock exynos4_gate_clks[] __initdata = {
                        CLK_SET_RATE_PARENT, 0),
        GATE(sclk_audio1, "sclk_audio1", "div_audio1", SRC_MASK_PERIL1, 0,
                        CLK_SET_RATE_PARENT, 0),
-       GATE_D(vp, "s5p-mixer", "vp", "aclk160", GATE_IP_TV, 0, 0, 0),
-       GATE_D(mixer, "s5p-mixer", "mixer", "aclk160", GATE_IP_TV, 1, 0, 0),
-       GATE_D(hdmi, "exynos4-hdmi", "hdmi", "aclk160", GATE_IP_TV, 3, 0, 0),
-       GATE_A(pwm, "pwm", "aclk100", GATE_IP_PERIL, 24, 0, 0, "timers"),
-       GATE_A(sdmmc4, "sdmmc4", "aclk133", GATE_IP_FSYS, 9, 0, 0, "biu"),
-       GATE_A(usb_host, "usb_host", "aclk133",
-                       GATE_IP_FSYS, 12, 0, 0, "usbhost"),
-       GATE_DA(sclk_fimc0, "exynos4-fimc.0", "sclk_fimc0", "div_fimc0",
-                       SRC_MASK_CAM, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
-       GATE_DA(sclk_fimc1, "exynos4-fimc.1", "sclk_fimc1", "div_fimc1",
-                       SRC_MASK_CAM, 4, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
-       GATE_DA(sclk_fimc2, "exynos4-fimc.2", "sclk_fimc2", "div_fimc2",
-                       SRC_MASK_CAM, 8, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
-       GATE_DA(sclk_fimc3, "exynos4-fimc.3", "sclk_fimc3", "div_fimc3",
-                       SRC_MASK_CAM, 12, CLK_SET_RATE_PARENT, 0, "sclk_fimc"),
-       GATE_DA(sclk_csis0, "s5p-mipi-csis.0", "sclk_csis0", "div_csis0",
-                       SRC_MASK_CAM, 24, CLK_SET_RATE_PARENT, 0, "sclk_csis"),
-       GATE_DA(sclk_csis1, "s5p-mipi-csis.1", "sclk_csis1", "div_csis1",
-                       SRC_MASK_CAM, 28, CLK_SET_RATE_PARENT, 0, "sclk_csis"),
-       GATE_DA(sclk_fimd0, "exynos4-fb.0", "sclk_fimd0", "div_fimd0",
-                       SRC_MASK_LCD0, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimd"),
-       GATE_DA(sclk_mmc0, "exynos4-sdhci.0", "sclk_mmc0", "div_mmc_pre0",
-                       SRC_MASK_FSYS, 0, CLK_SET_RATE_PARENT, 0,
-                       "mmc_busclk.2"),
-       GATE_DA(sclk_mmc1, "exynos4-sdhci.1", "sclk_mmc1", "div_mmc_pre1",
-                       SRC_MASK_FSYS, 4, CLK_SET_RATE_PARENT, 0,
-                       "mmc_busclk.2"),
-       GATE_DA(sclk_mmc2, "exynos4-sdhci.2", "sclk_mmc2", "div_mmc_pre2",
-                       SRC_MASK_FSYS, 8, CLK_SET_RATE_PARENT, 0,
-                       "mmc_busclk.2"),
-       GATE_DA(sclk_mmc3, "exynos4-sdhci.3", "sclk_mmc3", "div_mmc_pre3",
-                       SRC_MASK_FSYS, 12, CLK_SET_RATE_PARENT, 0,
-                       "mmc_busclk.2"),
-       GATE_DA(sclk_mmc4, NULL, "sclk_mmc4", "div_mmc_pre4",
-                       SRC_MASK_FSYS, 16, CLK_SET_RATE_PARENT, 0, "ciu"),
-       GATE_DA(sclk_uart0, "exynos4210-uart.0", "uclk0", "div_uart0",
-                       SRC_MASK_PERIL0, 0, CLK_SET_RATE_PARENT,
-                       0, "clk_uart_baud0"),
-       GATE_DA(sclk_uart1, "exynos4210-uart.1", "uclk1", "div_uart1",
-                       SRC_MASK_PERIL0, 4, CLK_SET_RATE_PARENT,
-                       0, "clk_uart_baud0"),
-       GATE_DA(sclk_uart2, "exynos4210-uart.2", "uclk2", "div_uart2",
-                       SRC_MASK_PERIL0, 8, CLK_SET_RATE_PARENT,
-                       0, "clk_uart_baud0"),
-       GATE_DA(sclk_uart3, "exynos4210-uart.3", "uclk3", "div_uart3",
-                       SRC_MASK_PERIL0, 12, CLK_SET_RATE_PARENT,
-                       0, "clk_uart_baud0"),
-       GATE_DA(sclk_uart4, "exynos4210-uart.4", "uclk4", "div_uart4",
-                       SRC_MASK_PERIL0, 16, CLK_SET_RATE_PARENT,
-                       0, "clk_uart_baud0"),
+       GATE(vp, "vp", "aclk160", GATE_IP_TV, 0, 0, 0),
+       GATE(mixer, "mixer", "aclk160", GATE_IP_TV, 1, 0, 0),
+       GATE(hdmi, "hdmi", "aclk160", GATE_IP_TV, 3, 0, 0),
+       GATE(pwm, "pwm", "aclk100", GATE_IP_PERIL, 24, 0, 0),
+       GATE(sdmmc4, "sdmmc4", "aclk133", GATE_IP_FSYS, 9, 0, 0),
+       GATE(usb_host, "usb_host", "aclk133", GATE_IP_FSYS, 12, 0, 0),
+       GATE(sclk_fimc0, "sclk_fimc0", "div_fimc0", SRC_MASK_CAM, 0,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_fimc1, "sclk_fimc1", "div_fimc1", SRC_MASK_CAM, 4,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_fimc2, "sclk_fimc2", "div_fimc2", SRC_MASK_CAM, 8,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_fimc3, "sclk_fimc3", "div_fimc3", SRC_MASK_CAM, 12,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_csis0, "sclk_csis0", "div_csis0", SRC_MASK_CAM, 24,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_csis1, "sclk_csis1", "div_csis1", SRC_MASK_CAM, 28,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_fimd0, "sclk_fimd0", "div_fimd0", SRC_MASK_LCD0, 0,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_mmc0, "sclk_mmc0", "div_mmc_pre0", SRC_MASK_FSYS, 0,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_mmc1, "sclk_mmc1", "div_mmc_pre1", SRC_MASK_FSYS, 4,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_mmc2, "sclk_mmc2", "div_mmc_pre2", SRC_MASK_FSYS, 8,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_mmc3, "sclk_mmc3", "div_mmc_pre3", SRC_MASK_FSYS, 12,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_mmc4, "sclk_mmc4", "div_mmc_pre4", SRC_MASK_FSYS, 16,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_uart0, "uclk0", "div_uart0", SRC_MASK_PERIL0, 0,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_uart1, "uclk1", "div_uart1", SRC_MASK_PERIL0, 4,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_uart2, "uclk2", "div_uart2", SRC_MASK_PERIL0, 8,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_uart3, "uclk3", "div_uart3", SRC_MASK_PERIL0, 12,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_uart4, "uclk4", "div_uart4", SRC_MASK_PERIL0, 16,
+                       CLK_SET_RATE_PARENT, 0),
        GATE(sclk_audio2, "sclk_audio2", "div_audio2", SRC_MASK_PERIL1, 4,
                        CLK_SET_RATE_PARENT, 0),
-       GATE_DA(sclk_spi0, "exynos4210-spi.0", "sclk_spi0", "div_spi_pre0",
-                       SRC_MASK_PERIL1, 16, CLK_SET_RATE_PARENT,
-                       0, "spi_busclk0"),
-       GATE_DA(sclk_spi1, "exynos4210-spi.1", "sclk_spi1", "div_spi_pre1",
-                       SRC_MASK_PERIL1, 20, CLK_SET_RATE_PARENT,
-                       0, "spi_busclk0"),
-       GATE_DA(sclk_spi2, "exynos4210-spi.2", "sclk_spi2", "div_spi_pre2",
-                       SRC_MASK_PERIL1, 24, CLK_SET_RATE_PARENT,
-                       0, "spi_busclk0"),
-       GATE_DA(fimc0, "exynos4-fimc.0", "fimc0", "aclk160",
-                       GATE_IP_CAM, 0, 0, 0, "fimc"),
-       GATE_DA(fimc1, "exynos4-fimc.1", "fimc1", "aclk160",
-                       GATE_IP_CAM, 1, 0, 0, "fimc"),
-       GATE_DA(fimc2, "exynos4-fimc.2", "fimc2", "aclk160",
-                       GATE_IP_CAM, 2, 0, 0, "fimc"),
-       GATE_DA(fimc3, "exynos4-fimc.3", "fimc3", "aclk160",
-                       GATE_IP_CAM, 3, 0, 0, "fimc"),
-       GATE_DA(csis0, "s5p-mipi-csis.0", "csis0", "aclk160",
-                       GATE_IP_CAM, 4, 0, 0, "fimc"),
-       GATE_DA(csis1, "s5p-mipi-csis.1", "csis1", "aclk160",
-                       GATE_IP_CAM, 5, 0, 0, "fimc"),
-       GATE_DA(smmu_fimc0, "exynos-sysmmu.5", "smmu_fimc0", "aclk160",
-                       GATE_IP_CAM, 7, 0, 0, "sysmmu"),
-       GATE_DA(smmu_fimc1, "exynos-sysmmu.6", "smmu_fimc1", "aclk160",
-                       GATE_IP_CAM, 8, 0, 0, "sysmmu"),
-       GATE_DA(smmu_fimc2, "exynos-sysmmu.7", "smmu_fimc2", "aclk160",
-                       GATE_IP_CAM, 9, 0, 0, "sysmmu"),
-       GATE_DA(smmu_fimc3, "exynos-sysmmu.8", "smmu_fimc3", "aclk160",
-                       GATE_IP_CAM, 10, 0, 0, "sysmmu"),
-       GATE_DA(smmu_jpeg, "exynos-sysmmu.3", "smmu_jpeg", "aclk160",
-                       GATE_IP_CAM, 11, 0, 0, "sysmmu"),
+       GATE(sclk_spi0, "sclk_spi0", "div_spi_pre0", SRC_MASK_PERIL1, 16,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_spi1, "sclk_spi1", "div_spi_pre1", SRC_MASK_PERIL1, 20,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(sclk_spi2, "sclk_spi2", "div_spi_pre2", SRC_MASK_PERIL1, 24,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(fimc0, "fimc0", "aclk160", GATE_IP_CAM, 0,
+                       0, 0),
+       GATE(fimc1, "fimc1", "aclk160", GATE_IP_CAM, 1,
+                       0, 0),
+       GATE(fimc2, "fimc2", "aclk160", GATE_IP_CAM, 2,
+                       0, 0),
+       GATE(fimc3, "fimc3", "aclk160", GATE_IP_CAM, 3,
+                       0, 0),
+       GATE(csis0, "csis0", "aclk160", GATE_IP_CAM, 4,
+                       0, 0),
+       GATE(csis1, "csis1", "aclk160", GATE_IP_CAM, 5,
+                       0, 0),
+       GATE(smmu_fimc0, "smmu_fimc0", "aclk160", GATE_IP_CAM, 7,
+                       0, 0),
+       GATE(smmu_fimc1, "smmu_fimc1", "aclk160", GATE_IP_CAM, 8,
+                       0, 0),
+       GATE(smmu_fimc2, "smmu_fimc2", "aclk160", GATE_IP_CAM, 9,
+                       0, 0),
+       GATE(smmu_fimc3, "smmu_fimc3", "aclk160", GATE_IP_CAM, 10,
+                       0, 0),
+       GATE(smmu_jpeg, "smmu_jpeg", "aclk160", GATE_IP_CAM, 11,
+                       0, 0),
        GATE(pixelasyncm0, "pxl_async0", "aclk160", GATE_IP_CAM, 17, 0, 0),
        GATE(pixelasyncm1, "pxl_async1", "aclk160", GATE_IP_CAM, 18, 0, 0),
-       GATE_DA(smmu_tv, "exynos-sysmmu.2", "smmu_tv", "aclk160",
-                       GATE_IP_TV, 4, 0, 0, "sysmmu"),
-       GATE_DA(mfc, "s5p-mfc", "mfc", "aclk100", GATE_IP_MFC, 0, 0, 0, "mfc"),
-       GATE_DA(smmu_mfcl, "exynos-sysmmu.0", "smmu_mfcl", "aclk100",
-                       GATE_IP_MFC, 1, 0, 0, "sysmmu"),
-       GATE_DA(smmu_mfcr, "exynos-sysmmu.1", "smmu_mfcr", "aclk100",
-                       GATE_IP_MFC, 2, 0, 0, "sysmmu"),
-       GATE_DA(fimd0, "exynos4-fb.0", "fimd0", "aclk160",
-                       GATE_IP_LCD0, 0, 0, 0, "fimd"),
-       GATE_DA(smmu_fimd0, "exynos-sysmmu.10", "smmu_fimd0", "aclk160",
-                       GATE_IP_LCD0, 4, 0, 0, "sysmmu"),
-       GATE_DA(pdma0, "dma-pl330.0", "pdma0", "aclk133",
-                       GATE_IP_FSYS, 0, 0, 0, "dma"),
-       GATE_DA(pdma1, "dma-pl330.1", "pdma1", "aclk133",
-                       GATE_IP_FSYS, 1, 0, 0, "dma"),
-       GATE_DA(sdmmc0, "exynos4-sdhci.0", "sdmmc0", "aclk133",
-                       GATE_IP_FSYS, 5, 0, 0, "hsmmc"),
-       GATE_DA(sdmmc1, "exynos4-sdhci.1", "sdmmc1", "aclk133",
-                       GATE_IP_FSYS, 6, 0, 0, "hsmmc"),
-       GATE_DA(sdmmc2, "exynos4-sdhci.2", "sdmmc2", "aclk133",
-                       GATE_IP_FSYS, 7, 0, 0, "hsmmc"),
-       GATE_DA(sdmmc3, "exynos4-sdhci.3", "sdmmc3", "aclk133",
-                       GATE_IP_FSYS, 8, 0, 0, "hsmmc"),
-       GATE_DA(uart0, "exynos4210-uart.0", "uart0", "aclk100",
-                       GATE_IP_PERIL, 0, 0, 0, "uart"),
-       GATE_DA(uart1, "exynos4210-uart.1", "uart1", "aclk100",
-                       GATE_IP_PERIL, 1, 0, 0, "uart"),
-       GATE_DA(uart2, "exynos4210-uart.2", "uart2", "aclk100",
-                       GATE_IP_PERIL, 2, 0, 0, "uart"),
-       GATE_DA(uart3, "exynos4210-uart.3", "uart3", "aclk100",
-                       GATE_IP_PERIL, 3, 0, 0, "uart"),
-       GATE_DA(uart4, "exynos4210-uart.4", "uart4", "aclk100",
-                       GATE_IP_PERIL, 4, 0, 0, "uart"),
-       GATE_DA(i2c0, "s3c2440-i2c.0", "i2c0", "aclk100",
-                       GATE_IP_PERIL, 6, 0, 0, "i2c"),
-       GATE_DA(i2c1, "s3c2440-i2c.1", "i2c1", "aclk100",
-                       GATE_IP_PERIL, 7, 0, 0, "i2c"),
-       GATE_DA(i2c2, "s3c2440-i2c.2", "i2c2", "aclk100",
-                       GATE_IP_PERIL, 8, 0, 0, "i2c"),
-       GATE_DA(i2c3, "s3c2440-i2c.3", "i2c3", "aclk100",
-                       GATE_IP_PERIL, 9, 0, 0, "i2c"),
-       GATE_DA(i2c4, "s3c2440-i2c.4", "i2c4", "aclk100",
-                       GATE_IP_PERIL, 10, 0, 0, "i2c"),
-       GATE_DA(i2c5, "s3c2440-i2c.5", "i2c5", "aclk100",
-                       GATE_IP_PERIL, 11, 0, 0, "i2c"),
-       GATE_DA(i2c6, "s3c2440-i2c.6", "i2c6", "aclk100",
-                       GATE_IP_PERIL, 12, 0, 0, "i2c"),
-       GATE_DA(i2c7, "s3c2440-i2c.7", "i2c7", "aclk100",
-                       GATE_IP_PERIL, 13, 0, 0, "i2c"),
-       GATE_DA(i2c_hdmi, "s3c2440-hdmiphy-i2c", "i2c-hdmi", "aclk100",
-                       GATE_IP_PERIL, 14, 0, 0, "i2c"),
-       GATE_DA(spi0, "exynos4210-spi.0", "spi0", "aclk100",
-                       GATE_IP_PERIL, 16, 0, 0, "spi"),
-       GATE_DA(spi1, "exynos4210-spi.1", "spi1", "aclk100",
-                       GATE_IP_PERIL, 17, 0, 0, "spi"),
-       GATE_DA(spi2, "exynos4210-spi.2", "spi2", "aclk100",
-                       GATE_IP_PERIL, 18, 0, 0, "spi"),
-       GATE_DA(i2s1, "samsung-i2s.1", "i2s1", "aclk100",
-                       GATE_IP_PERIL, 20, 0, 0, "iis"),
-       GATE_DA(i2s2, "samsung-i2s.2", "i2s2", "aclk100",
-                       GATE_IP_PERIL, 21, 0, 0, "iis"),
-       GATE_DA(pcm1, "samsung-pcm.1", "pcm1", "aclk100",
-                       GATE_IP_PERIL, 22, 0, 0, "pcm"),
-       GATE_DA(pcm2, "samsung-pcm.2", "pcm2", "aclk100",
-                       GATE_IP_PERIL, 23, 0, 0, "pcm"),
-       GATE_DA(spdif, "samsung-spdif", "spdif", "aclk100",
-                       GATE_IP_PERIL, 26, 0, 0, "spdif"),
-       GATE_DA(ac97, "samsung-ac97", "ac97", "aclk100",
-                       GATE_IP_PERIL, 27, 0, 0, "ac97"),
+       GATE(smmu_tv, "smmu_tv", "aclk160", GATE_IP_TV, 4,
+                       0, 0),
+       GATE(mfc, "mfc", "aclk100", GATE_IP_MFC, 0, 0, 0),
+       GATE(smmu_mfcl, "smmu_mfcl", "aclk100", GATE_IP_MFC, 1,
+                       0, 0),
+       GATE(smmu_mfcr, "smmu_mfcr", "aclk100", GATE_IP_MFC, 2,
+                       0, 0),
+       GATE(fimd0, "fimd0", "aclk160", GATE_IP_LCD0, 0,
+                       0, 0),
+       GATE(smmu_fimd0, "smmu_fimd0", "aclk160", GATE_IP_LCD0, 4,
+                       0, 0),
+       GATE(pdma0, "pdma0", "aclk133", GATE_IP_FSYS, 0,
+                       0, 0),
+       GATE(pdma1, "pdma1", "aclk133", GATE_IP_FSYS, 1,
+                       0, 0),
+       GATE(sdmmc0, "sdmmc0", "aclk133", GATE_IP_FSYS, 5,
+                       0, 0),
+       GATE(sdmmc1, "sdmmc1", "aclk133", GATE_IP_FSYS, 6,
+                       0, 0),
+       GATE(sdmmc2, "sdmmc2", "aclk133", GATE_IP_FSYS, 7,
+                       0, 0),
+       GATE(sdmmc3, "sdmmc3", "aclk133", GATE_IP_FSYS, 8,
+                       0, 0),
+       GATE(uart0, "uart0", "aclk100", GATE_IP_PERIL, 0,
+                       0, 0),
+       GATE(uart1, "uart1", "aclk100", GATE_IP_PERIL, 1,
+                       0, 0),
+       GATE(uart2, "uart2", "aclk100", GATE_IP_PERIL, 2,
+                       0, 0),
+       GATE(uart3, "uart3", "aclk100", GATE_IP_PERIL, 3,
+                       0, 0),
+       GATE(uart4, "uart4", "aclk100", GATE_IP_PERIL, 4,
+                       0, 0),
+       GATE(i2c0, "i2c0", "aclk100", GATE_IP_PERIL, 6,
+                       0, 0),
+       GATE(i2c1, "i2c1", "aclk100", GATE_IP_PERIL, 7,
+                       0, 0),
+       GATE(i2c2, "i2c2", "aclk100", GATE_IP_PERIL, 8,
+                       0, 0),
+       GATE(i2c3, "i2c3", "aclk100", GATE_IP_PERIL, 9,
+                       0, 0),
+       GATE(i2c4, "i2c4", "aclk100", GATE_IP_PERIL, 10,
+                       0, 0),
+       GATE(i2c5, "i2c5", "aclk100", GATE_IP_PERIL, 11,
+                       0, 0),
+       GATE(i2c6, "i2c6", "aclk100", GATE_IP_PERIL, 12,
+                       0, 0),
+       GATE(i2c7, "i2c7", "aclk100", GATE_IP_PERIL, 13,
+                       0, 0),
+       GATE(i2c_hdmi, "i2c-hdmi", "aclk100", GATE_IP_PERIL, 14,
+                       0, 0),
+       GATE(spi0, "spi0", "aclk100", GATE_IP_PERIL, 16,
+                       0, 0),
+       GATE(spi1, "spi1", "aclk100", GATE_IP_PERIL, 17,
+                       0, 0),
+       GATE(spi2, "spi2", "aclk100", GATE_IP_PERIL, 18,
+                       0, 0),
+       GATE(i2s1, "i2s1", "aclk100", GATE_IP_PERIL, 20,
+                       0, 0),
+       GATE(i2s2, "i2s2", "aclk100", GATE_IP_PERIL, 21,
+                       0, 0),
+       GATE(pcm1, "pcm1", "aclk100", GATE_IP_PERIL, 22,
+                       0, 0),
+       GATE(pcm2, "pcm2", "aclk100", GATE_IP_PERIL, 23,
+                       0, 0),
+       GATE(spdif, "spdif", "aclk100", GATE_IP_PERIL, 26,
+                       0, 0),
+       GATE(ac97, "ac97", "aclk100", GATE_IP_PERIL, 27,
+                       0, 0),
 };
 
 /* list of gate clocks supported in exynos4210 soc */
-struct samsung_gate_clock exynos4210_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos4210_gate_clks[] __initdata = {
        GATE(tvenc, "tvenc", "aclk160", GATE_IP_TV, 2, 0, 0),
        GATE(g2d, "g2d", "aclk200", E4210_GATE_IP_IMAGE, 0, 0, 0),
        GATE(rotator, "rotator", "aclk200", E4210_GATE_IP_IMAGE, 1, 0, 0),
@@ -811,17 +803,23 @@ struct samsung_gate_clock exynos4210_gate_clks[] __initdata = {
                        SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
        GATE(sclk_mixer, "sclk_mixer", "mout_mixer", SRC_MASK_TV, 4, 0, 0),
        GATE(sclk_dac, "sclk_dac", "mout_dac", SRC_MASK_TV, 8, 0, 0),
-       GATE_A(tsadc, "tsadc", "aclk100", GATE_IP_PERIL, 15, 0, 0, "adc"),
-       GATE_A(mct, "mct", "aclk100", E4210_GATE_IP_PERIR, 13, 0, 0, "mct"),
-       GATE_A(wdt, "watchdog", "aclk100", E4210_GATE_IP_PERIR, 14, 0, 0, "watchdog"),
-       GATE_A(rtc, "rtc", "aclk100", E4210_GATE_IP_PERIR, 15, 0, 0, "rtc"),
-       GATE_A(keyif, "keyif", "aclk100", E4210_GATE_IP_PERIR, 16, 0, 0, "keypad"),
-       GATE_DA(sclk_fimd1, "exynos4-fb.1", "sclk_fimd1", "div_fimd1",
-                       E4210_SRC_MASK_LCD1, 0, CLK_SET_RATE_PARENT, 0, "sclk_fimd"),
+       GATE(tsadc, "tsadc", "aclk100", GATE_IP_PERIL, 15,
+                       0, 0),
+       GATE(mct, "mct", "aclk100", E4210_GATE_IP_PERIR, 13,
+                       0, 0),
+       GATE(wdt, "watchdog", "aclk100", E4210_GATE_IP_PERIR, 14,
+                       0, 0),
+       GATE(rtc, "rtc", "aclk100", E4210_GATE_IP_PERIR, 15,
+                       0, 0),
+       GATE(keyif, "keyif", "aclk100", E4210_GATE_IP_PERIR, 16,
+                       0, 0),
+       GATE(sclk_fimd1, "sclk_fimd1", "div_fimd1", E4210_SRC_MASK_LCD1, 0,
+                       CLK_SET_RATE_PARENT, 0),
+       GATE(tmu_apbif, "tmu_apbif", "aclk100", E4210_GATE_IP_PERIR, 17, 0, 0),
 };
 
 /* list of gate clocks supported in exynos4x12 soc */
-struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
        GATE(audss, "audss", "sclk_epll", E4X12_GATE_IP_MAUDIO, 0, 0, 0),
        GATE(mdnie0, "mdnie0", "aclk160", GATE_IP_LCD0, 2, 0, 0),
        GATE(rotator, "rotator", "aclk200", E4X12_GATE_IP_IMAGE, 1, 0, 0),
@@ -840,10 +838,11 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
                        SRC_MASK_FSYS, 24, CLK_SET_RATE_PARENT, 0),
        GATE(smmu_rotator, "smmu_rotator", "aclk200",
                        E4X12_GATE_IP_IMAGE, 4, 0, 0),
-       GATE_A(mct, "mct", "aclk100", E4X12_GATE_IP_PERIR, 13, 0, 0, "mct"),
-       GATE_A(rtc, "rtc", "aclk100", E4X12_GATE_IP_PERIR, 15, 0, 0, "rtc"),
-       GATE_A(keyif, "keyif", "aclk100",
-                       E4X12_GATE_IP_PERIR, 16, 0, 0, "keypad"),
+       GATE(mct, "mct", "aclk100", E4X12_GATE_IP_PERIR, 13,
+                       0, 0),
+       GATE(rtc, "rtc", "aclk100", E4X12_GATE_IP_PERIR, 15,
+                       0, 0),
+       GATE(keyif, "keyif", "aclk100", E4X12_GATE_IP_PERIR, 16, 0, 0),
        GATE(sclk_pwm_isp, "sclk_pwm_isp", "div_pwm_isp",
                        E4X12_SRC_MASK_ISP, 0, CLK_SET_RATE_PARENT, 0),
        GATE(sclk_spi0_isp, "sclk_spi0_isp", "div_spi0_isp_pre",
@@ -860,12 +859,11 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
                        E4X12_GATE_IP_ISP, 2, 0, 0),
        GATE(uart_isp_sclk, "uart_isp_sclk", "sclk_uart_isp",
                        E4X12_GATE_IP_ISP, 3, 0, 0),
-       GATE_A(wdt, "watchdog", "aclk100",
-                       E4X12_GATE_IP_PERIR, 14, 0, 0, "watchdog"),
-       GATE_DA(pcm0, "samsung-pcm.0", "pcm0", "aclk100",
-                       E4X12_GATE_IP_MAUDIO, 2, 0, 0, "pcm"),
-       GATE_DA(i2s0, "samsung-i2s.0", "i2s0", "aclk100",
-                       E4X12_GATE_IP_MAUDIO, 3, 0, 0, "iis"),
+       GATE(wdt, "watchdog", "aclk100", E4X12_GATE_IP_PERIR, 14, 0, 0),
+       GATE(pcm0, "pcm0", "aclk100", E4X12_GATE_IP_MAUDIO, 2,
+                       0, 0),
+       GATE(i2s0, "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3,
+                       0, 0),
        GATE(fimc_isp, "isp", "aclk200", E4X12_GATE_ISP0, 0,
                        CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(fimc_drc, "drc", "aclk200", E4X12_GATE_ISP0, 1,
@@ -919,6 +917,21 @@ struct samsung_gate_clock exynos4x12_gate_clks[] __initdata = {
        GATE(spi1_isp, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13,
                        CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0),
        GATE(g2d, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0),
+       GATE(tmu_apbif, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, 0),
+};
+
+static struct samsung_clock_alias exynos4_aliases[] __initdata = {
+       ALIAS(mout_core, NULL, "moutcore"),
+       ALIAS(arm_clk, NULL, "armclk"),
+       ALIAS(sclk_apll, NULL, "mout_apll"),
+};
+
+static struct samsung_clock_alias exynos4210_aliases[] __initdata = {
+       ALIAS(sclk_mpll, NULL, "mout_mpll"),
+};
+
+static struct samsung_clock_alias exynos4x12_aliases[] __initdata = {
+       ALIAS(mout_mpll_user_c, NULL, "mout_mpll"),
 };
 
 /*
@@ -973,36 +986,116 @@ static void __init exynos4_clk_register_finpll(unsigned long xom)
 
 }
 
-/*
- * This function allows non-dt platforms to specify the clock speed of the
- * xxti and xusbxti clocks. These clocks are then registered with the specified
- * clock speed.
- */
-void __init exynos4_clk_register_fixed_ext(unsigned long xxti_f,
-                                               unsigned long xusbxti_f)
-{
-       exynos4_fixed_rate_ext_clks[0].fixed_rate = xxti_f;
-       exynos4_fixed_rate_ext_clks[1].fixed_rate = xusbxti_f;
-       samsung_clk_register_fixed_rate(exynos4_fixed_rate_ext_clks,
-                       ARRAY_SIZE(exynos4_fixed_rate_ext_clks));
-}
-
-static __initdata struct of_device_id ext_clk_match[] = {
+static struct of_device_id ext_clk_match[] __initdata = {
        { .compatible = "samsung,clock-xxti", .data = (void *)0, },
        { .compatible = "samsung,clock-xusbxti", .data = (void *)1, },
        {},
 };
 
+/* PLLs PMS values */
+static struct samsung_pll_rate_table exynos4210_apll_rates[] __initdata = {
+       PLL_45XX_RATE(1200000000, 150,  3, 1, 28),
+       PLL_45XX_RATE(1000000000, 250,  6, 1, 28),
+       PLL_45XX_RATE( 800000000, 200,  6, 1, 28),
+       PLL_45XX_RATE( 666857142, 389, 14, 1, 13),
+       PLL_45XX_RATE( 600000000, 100,  4, 1, 13),
+       PLL_45XX_RATE( 533000000, 533, 24, 1,  5),
+       PLL_45XX_RATE( 500000000, 250,  6, 2, 28),
+       PLL_45XX_RATE( 400000000, 200,  6, 2, 28),
+       PLL_45XX_RATE( 200000000, 200,  6, 3, 28),
+       { /* sentinel */ }
+};
+
+static struct samsung_pll_rate_table exynos4210_epll_rates[] __initdata = {
+       PLL_4600_RATE(192000000, 48, 3, 1,     0, 0),
+       PLL_4600_RATE(180633605, 45, 3, 1, 10381, 0),
+       PLL_4600_RATE(180000000, 45, 3, 1,     0, 0),
+       PLL_4600_RATE( 73727996, 73, 3, 3, 47710, 1),
+       PLL_4600_RATE( 67737602, 90, 4, 3, 20762, 1),
+       PLL_4600_RATE( 49151992, 49, 3, 3,  9961, 0),
+       PLL_4600_RATE( 45158401, 45, 3, 3, 10381, 0),
+       { /* sentinel */ }
+};
+
+static struct samsung_pll_rate_table exynos4210_vpll_rates[] __initdata = {
+       PLL_4650_RATE(360000000, 44, 3, 0, 1024, 0, 14, 0),
+       PLL_4650_RATE(324000000, 53, 2, 1, 1024, 1,  1, 1),
+       PLL_4650_RATE(259617187, 63, 3, 1, 1950, 0, 20, 1),
+       PLL_4650_RATE(110000000, 53, 3, 2, 2048, 0, 17, 0),
+       PLL_4650_RATE( 55360351, 53, 3, 3, 2417, 0, 17, 0),
+       { /* sentinel */ }
+};
+
+static struct samsung_pll_rate_table exynos4x12_apll_rates[] __initdata = {
+       PLL_35XX_RATE(1500000000, 250, 4, 0),
+       PLL_35XX_RATE(1400000000, 175, 3, 0),
+       PLL_35XX_RATE(1300000000, 325, 6, 0),
+       PLL_35XX_RATE(1200000000, 200, 4, 0),
+       PLL_35XX_RATE(1100000000, 275, 6, 0),
+       PLL_35XX_RATE(1000000000, 125, 3, 0),
+       PLL_35XX_RATE( 900000000, 150, 4, 0),
+       PLL_35XX_RATE( 800000000, 100, 3, 0),
+       PLL_35XX_RATE( 700000000, 175, 3, 1),
+       PLL_35XX_RATE( 600000000, 200, 4, 1),
+       PLL_35XX_RATE( 500000000, 125, 3, 1),
+       PLL_35XX_RATE( 400000000, 100, 3, 1),
+       PLL_35XX_RATE( 300000000, 200, 4, 2),
+       PLL_35XX_RATE( 200000000, 100, 3, 2),
+       { /* sentinel */ }
+};
+
+static struct samsung_pll_rate_table exynos4x12_epll_rates[] __initdata = {
+       PLL_36XX_RATE(192000000, 48, 3, 1,     0),
+       PLL_36XX_RATE(180633605, 45, 3, 1, 10381),
+       PLL_36XX_RATE(180000000, 45, 3, 1,     0),
+       PLL_36XX_RATE( 73727996, 73, 3, 3, 47710),
+       PLL_36XX_RATE( 67737602, 90, 4, 3, 20762),
+       PLL_36XX_RATE( 49151992, 49, 3, 3,  9961),
+       PLL_36XX_RATE( 45158401, 45, 3, 3, 10381),
+       { /* sentinel */ }
+};
+
+static struct samsung_pll_rate_table exynos4x12_vpll_rates[] __initdata = {
+       PLL_36XX_RATE(533000000, 133, 3, 1, 16384),
+       PLL_36XX_RATE(440000000, 110, 3, 1,     0),
+       PLL_36XX_RATE(350000000, 175, 3, 2,     0),
+       PLL_36XX_RATE(266000000, 133, 3, 2,     0),
+       PLL_36XX_RATE(160000000, 160, 3, 3,     0),
+       PLL_36XX_RATE(106031250,  53, 3, 2,  1024),
+       PLL_36XX_RATE( 53015625,  53, 3, 3,  1024),
+       { /* sentinel */ }
+};
+
+static struct samsung_pll_clock exynos4210_plls[nr_plls] __initdata = {
+       [apll] = PLL_A(pll_4508, fout_apll, "fout_apll", "fin_pll", APLL_LOCK,
+               APLL_CON0, "fout_apll", NULL),
+       [mpll] = PLL_A(pll_4508, fout_mpll, "fout_mpll", "fin_pll",
+               E4210_MPLL_LOCK, E4210_MPLL_CON0, "fout_mpll", NULL),
+       [epll] = PLL_A(pll_4600, fout_epll, "fout_epll", "fin_pll", EPLL_LOCK,
+               EPLL_CON0, "fout_epll", NULL),
+       [vpll] = PLL_A(pll_4650c, fout_vpll, "fout_vpll", "mout_vpllsrc",
+               VPLL_LOCK, VPLL_CON0, "fout_vpll", NULL),
+};
+
+static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = {
+       [apll] = PLL(pll_35xx, fout_apll, "fout_apll", "fin_pll",
+                       APLL_LOCK, APLL_CON0, NULL),
+       [mpll] = PLL(pll_35xx, fout_mpll, "fout_mpll", "fin_pll",
+                       E4X12_MPLL_LOCK, E4X12_MPLL_CON0, NULL),
+       [epll] = PLL(pll_36xx, fout_epll, "fout_epll", "fin_pll",
+                       EPLL_LOCK, EPLL_CON0, NULL),
+       [vpll] = PLL(pll_36xx, fout_vpll, "fout_vpll", "fin_pll",
+                       VPLL_LOCK, VPLL_CON0, NULL),
+};
+
 /* register exynos4 clocks */
-void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_soc, void __iomem *reg_base, unsigned long xom)
+static void __init exynos4_clk_init(struct device_node *np,
+                                   enum exynos4_soc exynos4_soc,
+                                   void __iomem *reg_base, unsigned long xom)
 {
-       struct clk *apll, *mpll, *epll, *vpll;
-
-       if (np) {
-               reg_base = of_iomap(np, 0);
-               if (!reg_base)
-                       panic("%s: failed to map registers\n", __func__);
-       }
+       reg_base = of_iomap(np, 0);
+       if (!reg_base)
+               panic("%s: failed to map registers\n", __func__);
 
        if (exynos4_soc == EXYNOS4210)
                samsung_clk_init(np, reg_base, nr_clks,
@@ -1013,37 +1106,42 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
                        exynos4_clk_regs, ARRAY_SIZE(exynos4_clk_regs),
                        exynos4x12_clk_save, ARRAY_SIZE(exynos4x12_clk_save));
 
-       if (np)
-               samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
+       samsung_clk_of_register_fixed_ext(exynos4_fixed_rate_ext_clks,
                        ARRAY_SIZE(exynos4_fixed_rate_ext_clks),
                        ext_clk_match);
 
        exynos4_clk_register_finpll(xom);
 
        if (exynos4_soc == EXYNOS4210) {
-               apll = samsung_clk_register_pll45xx("fout_apll", "fin_pll",
-                                       reg_base + APLL_CON0, pll_4508);
-               mpll = samsung_clk_register_pll45xx("fout_mpll", "fin_pll",
-                                       reg_base + E4210_MPLL_CON0, pll_4508);
-               epll = samsung_clk_register_pll46xx("fout_epll", "fin_pll",
-                                       reg_base + EPLL_CON0, pll_4600);
-               vpll = samsung_clk_register_pll46xx("fout_vpll", "mout_vpllsrc",
-                                       reg_base + VPLL_CON0, pll_4650c);
+               samsung_clk_register_mux(exynos4210_mux_early,
+                                       ARRAY_SIZE(exynos4210_mux_early));
+
+               if (_get_rate("fin_pll") == 24000000) {
+                       exynos4210_plls[apll].rate_table =
+                                                       exynos4210_apll_rates;
+                       exynos4210_plls[epll].rate_table =
+                                                       exynos4210_epll_rates;
+               }
+
+               if (_get_rate("mout_vpllsrc") == 24000000)
+                       exynos4210_plls[vpll].rate_table =
+                                                       exynos4210_vpll_rates;
+
+               samsung_clk_register_pll(exynos4210_plls,
+                                       ARRAY_SIZE(exynos4210_plls), reg_base);
        } else {
-               apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
-                                       reg_base + APLL_CON0);
-               mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
-                                       reg_base + E4X12_MPLL_CON0);
-               epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
-                                       reg_base + EPLL_CON0);
-               vpll = samsung_clk_register_pll36xx("fout_vpll", "fin_pll",
-                                       reg_base + VPLL_CON0);
-       }
+               if (_get_rate("fin_pll") == 24000000) {
+                       exynos4x12_plls[apll].rate_table =
+                                                       exynos4x12_apll_rates;
+                       exynos4x12_plls[epll].rate_table =
+                                                       exynos4x12_epll_rates;
+                       exynos4x12_plls[vpll].rate_table =
+                                                       exynos4x12_vpll_rates;
+               }
 
-       samsung_clk_add_lookup(apll, fout_apll);
-       samsung_clk_add_lookup(mpll, fout_mpll);
-       samsung_clk_add_lookup(epll, fout_epll);
-       samsung_clk_add_lookup(vpll, fout_vpll);
+               samsung_clk_register_pll(exynos4x12_plls,
+                                       ARRAY_SIZE(exynos4x12_plls), reg_base);
+       }
 
        samsung_clk_register_fixed_rate(exynos4_fixed_rate_clks,
                        ARRAY_SIZE(exynos4_fixed_rate_clks));
@@ -1063,6 +1161,8 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
                        ARRAY_SIZE(exynos4210_div_clks));
                samsung_clk_register_gate(exynos4210_gate_clks,
                        ARRAY_SIZE(exynos4210_gate_clks));
+               samsung_clk_register_alias(exynos4210_aliases,
+                       ARRAY_SIZE(exynos4210_aliases));
        } else {
                samsung_clk_register_mux(exynos4x12_mux_clks,
                        ARRAY_SIZE(exynos4x12_mux_clks));
@@ -1070,14 +1170,19 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
                        ARRAY_SIZE(exynos4x12_div_clks));
                samsung_clk_register_gate(exynos4x12_gate_clks,
                        ARRAY_SIZE(exynos4x12_gate_clks));
+               samsung_clk_register_alias(exynos4x12_aliases,
+                       ARRAY_SIZE(exynos4x12_aliases));
        }
 
+       samsung_clk_register_alias(exynos4_aliases,
+                       ARRAY_SIZE(exynos4_aliases));
+
        pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
                "\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
                exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
-               _get_rate("sclk_apll"), _get_rate("mout_mpll"),
+               _get_rate("sclk_apll"), _get_rate("sclk_mpll"),
                _get_rate("sclk_epll"), _get_rate("sclk_vpll"),
-               _get_rate("armclk"));
+               _get_rate("arm_clk"));
 }
 
 
index 6f767c515ec77df4d100edcdabfb78da7cb60e9e..adf32343c9f9c408f5b8bc7c78a6ce3bc66c27a7 100644 (file)
 #include <linux/of_address.h>
 
 #include "clk.h"
-#include "clk-pll.h"
 
+#define APLL_LOCK              0x0
+#define APLL_CON0              0x100
 #define SRC_CPU                        0x200
 #define DIV_CPU0               0x500
+#define MPLL_LOCK              0x4000
+#define MPLL_CON0              0x4100
 #define SRC_CORE1              0x4204
+#define CPLL_LOCK              0x10020
+#define EPLL_LOCK              0x10030
+#define VPLL_LOCK              0x10040
+#define GPLL_LOCK              0x10050
+#define CPLL_CON0              0x10120
+#define EPLL_CON0              0x10130
+#define VPLL_CON0              0x10140
+#define GPLL_CON0              0x10150
 #define SRC_TOP0               0x10210
 #define SRC_TOP2               0x10218
 #define SRC_GSCL               0x10220
 #define GATE_IP_FSYS           0x10944
 #define GATE_IP_PERIC          0x10950
 #define GATE_IP_PERIS          0x10960
+#define BPLL_LOCK              0x20010
+#define BPLL_CON0              0x20110
 #define SRC_CDREX              0x20200
 #define PLL_DIV2_SEL           0x20a24
 #define GATE_IP_DISP1          0x10928
+#define GATE_IP_ACP            0x10000
+
+/* list of PLLs to be registered */
+enum exynos5250_plls {
+       apll, mpll, cpll, epll, vpll, gpll, bpll,
+       nr_plls                 /* number of PLLs */
+};
 
 /*
  * Let each supported clock get a unique id. This id is used to lookup the clock
@@ -79,7 +99,8 @@ enum exynos5250_clks {
        none,
 
        /* core clocks */
-       fin_pll,
+       fin_pll, fout_apll, fout_mpll, fout_bpll, fout_gpll, fout_cpll,
+       fout_epll, fout_vpll,
 
        /* gate for special clocks (sclk) */
        sclk_cam_bayer = 128, sclk_cam0, sclk_cam1, sclk_gscl_wa, sclk_gscl_wb,
@@ -87,7 +108,7 @@ enum exynos5250_clks {
        sclk_mmc0, sclk_mmc1, sclk_mmc2, sclk_mmc3, sclk_sata, sclk_usb3,
        sclk_jpeg, sclk_uart0, sclk_uart1, sclk_uart2, sclk_uart3, sclk_pwm,
        sclk_audio1, sclk_audio2, sclk_spdif, sclk_spi0, sclk_spi1, sclk_spi2,
-       div_i2s1, div_i2s2,
+       div_i2s1, div_i2s2, sclk_hdmiphy,
 
        /* gate clocks */
        gscl0 = 256, gscl1, gscl2, gscl3, gscl_wa, gscl_wb, smmu_gscl0,
@@ -99,7 +120,10 @@ enum exynos5250_clks {
        spi2, i2s1, i2s2, pcm1, pcm2, pwm, spdif, ac97, hsi2c0, hsi2c1, hsi2c2,
        hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1,
        tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct,
-       wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi,
+       wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, g2d,
+
+       /* mux clocks */
+       mout_hdmi = 1024,
 
        nr_clks,
 };
@@ -108,7 +132,7 @@ enum exynos5250_clks {
  * list of controller registers to be saved and restored during a
  * suspend/resume cycle.
  */
-static __initdata unsigned long exynos5250_clk_regs[] = {
+static unsigned long exynos5250_clk_regs[] __initdata = {
        SRC_CPU,
        DIV_CPU0,
        SRC_CORE1,
@@ -152,6 +176,7 @@ static __initdata unsigned long exynos5250_clk_regs[] = {
        SRC_CDREX,
        PLL_DIV2_SEL,
        GATE_IP_DISP1,
+       GATE_IP_ACP,
 };
 
 /* list of all parent clock list */
@@ -191,31 +216,34 @@ PNAME(mout_spdif_p)       = { "sclk_audio0", "sclk_audio1", "sclk_audio2",
                                "spdif_extclk" };
 
 /* fixed rate clocks generated outside the soc */
-struct samsung_fixed_rate_clock exynos5250_fixed_rate_ext_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos5250_fixed_rate_ext_clks[] __initdata = {
        FRATE(fin_pll, "fin_pll", NULL, CLK_IS_ROOT, 0),
 };
 
 /* fixed rate clocks generated inside the soc */
-struct samsung_fixed_rate_clock exynos5250_fixed_rate_clks[] __initdata = {
-       FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
+static struct samsung_fixed_rate_clock exynos5250_fixed_rate_clks[] __initdata = {
+       FRATE(sclk_hdmiphy, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
        FRATE(none, "sclk_hdmi27m", NULL, CLK_IS_ROOT, 27000000),
        FRATE(none, "sclk_dptxphy", NULL, CLK_IS_ROOT, 24000000),
        FRATE(none, "sclk_uhostphy", NULL, CLK_IS_ROOT, 48000000),
 };
 
-struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = {
+static struct samsung_fixed_factor_clock exynos5250_fixed_factor_clks[] __initdata = {
        FFACTOR(none, "fout_mplldiv2", "fout_mpll", 1, 2, 0),
        FFACTOR(none, "fout_bplldiv2", "fout_bpll", 1, 2, 0),
 };
 
-struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos5250_pll_pmux_clks[] __initdata = {
+       MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1),
+};
+
+static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
        MUX_A(none, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, "mout_apll"),
        MUX_A(none, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1, "mout_cpu"),
        MUX(none, "mout_mpll_fout", mout_mpll_fout_p, PLL_DIV2_SEL, 4, 1),
        MUX_A(none, "sclk_mpll", mout_mpll_p, SRC_CORE1, 8, 1, "mout_mpll"),
        MUX(none, "mout_bpll_fout", mout_bpll_fout_p, PLL_DIV2_SEL, 0, 1),
        MUX(none, "sclk_bpll", mout_bpll_p, SRC_CDREX, 0, 1),
-       MUX(none, "mout_vpllsrc", mout_vpllsrc_p, SRC_TOP2, 0, 1),
        MUX(none, "sclk_vpll", mout_vpll_p, SRC_TOP2, 16, 1),
        MUX(none, "sclk_epll", mout_epll_p, SRC_TOP2, 12, 1),
        MUX(none, "sclk_cpll", mout_cpll_p, SRC_TOP2, 8, 1),
@@ -232,7 +260,7 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
        MUX(none, "mout_fimd1", mout_group1_p, SRC_DISP1_0, 0, 4),
        MUX(none, "mout_mipi1", mout_group1_p, SRC_DISP1_0, 12, 4),
        MUX(none, "mout_dp", mout_group1_p, SRC_DISP1_0, 16, 4),
-       MUX(none, "mout_hdmi", mout_hdmi_p, SRC_DISP1_0, 20, 1),
+       MUX(mout_hdmi, "mout_hdmi", mout_hdmi_p, SRC_DISP1_0, 20, 1),
        MUX(none, "mout_audio0", mout_audio0_p, SRC_MAU, 0, 4),
        MUX(none, "mout_mmc0", mout_group1_p, SRC_FSYS, 0, 4),
        MUX(none, "mout_mmc1", mout_group1_p, SRC_FSYS, 4, 4),
@@ -254,7 +282,7 @@ struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
        MUX(none, "mout_spi2", mout_group1_p, SRC_PERIC1, 24, 4),
 };
 
-struct samsung_div_clock exynos5250_div_clks[] __initdata = {
+static struct samsung_div_clock exynos5250_div_clks[] __initdata = {
        DIV(none, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
        DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3),
        DIV(none, "aclk66_pre", "sclk_mpll_user", DIV_TOP1, 24, 3),
@@ -314,7 +342,7 @@ struct samsung_div_clock exynos5250_div_clks[] __initdata = {
                        DIV_PERIC2, 8, 8, CLK_SET_RATE_PARENT, 0),
 };
 
-struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
        GATE(gscl0, "gscl0", "none", GATE_IP_GSCL, 0, 0, 0),
        GATE(gscl1, "gscl1", "none", GATE_IP_GSCL, 1, 0, 0),
        GATE(gscl2, "gscl2", "aclk266", GATE_IP_GSCL, 2, 0, 0),
@@ -461,20 +489,60 @@ struct samsung_gate_clock exynos5250_gate_clks[] __initdata = {
        GATE(mie1, "mie1", "aclk200", GATE_IP_DISP1, 1, 0, 0),
        GATE(dsim0, "dsim0", "aclk200", GATE_IP_DISP1, 3, 0, 0),
        GATE(dp, "dp", "aclk200", GATE_IP_DISP1, 4, 0, 0),
-       GATE(mixer, "mixer", "aclk200", GATE_IP_DISP1, 5, 0, 0),
-       GATE(hdmi, "hdmi", "aclk200", GATE_IP_DISP1, 6, 0, 0),
+       GATE(mixer, "mixer", "mout_aclk200_disp1", GATE_IP_DISP1, 5, 0, 0),
+       GATE(hdmi, "hdmi", "mout_aclk200_disp1", GATE_IP_DISP1, 6, 0, 0),
+       GATE(g2d, "g2d", "aclk200", GATE_IP_ACP, 3, 0, 0),
+};
+
+static struct samsung_pll_rate_table vpll_24mhz_tbl[] __initdata = {
+       /* sorted in descending order */
+       /* PLL_36XX_RATE(rate, m, p, s, k) */
+       PLL_36XX_RATE(266000000, 266, 3, 3, 0),
+       /* Not in UM, but need for eDP on snow */
+       PLL_36XX_RATE(70500000, 94, 2, 4, 0),
+       { },
+};
+
+static struct samsung_pll_rate_table epll_24mhz_tbl[] __initdata = {
+       /* sorted in descending order */
+       /* PLL_36XX_RATE(rate, m, p, s, k) */
+       PLL_36XX_RATE(192000000, 64, 2, 2, 0),
+       PLL_36XX_RATE(180633600, 90, 3, 2, 20762),
+       PLL_36XX_RATE(180000000, 90, 3, 2, 0),
+       PLL_36XX_RATE(73728000, 98, 2, 4, 19923),
+       PLL_36XX_RATE(67737600, 90, 2, 4, 20762),
+       PLL_36XX_RATE(49152000, 98, 3, 4, 19923),
+       PLL_36XX_RATE(45158400, 90, 3, 4, 20762),
+       PLL_36XX_RATE(32768000, 131, 3, 5, 4719),
+       { },
+};
+
+static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = {
+       [apll] = PLL_A(pll_35xx, fout_apll, "fout_apll", "fin_pll", APLL_LOCK,
+               APLL_CON0, "fout_apll", NULL),
+       [mpll] = PLL_A(pll_35xx, fout_mpll, "fout_mpll", "fin_pll", MPLL_LOCK,
+               MPLL_CON0, "fout_mpll", NULL),
+       [bpll] = PLL(pll_35xx, fout_bpll, "fout_bpll", "fin_pll", BPLL_LOCK,
+               BPLL_CON0, NULL),
+       [gpll] = PLL(pll_35xx, fout_gpll, "fout_gpll", "fin_pll", GPLL_LOCK,
+               GPLL_CON0, NULL),
+       [cpll] = PLL(pll_35xx, fout_cpll, "fout_cpll", "fin_pll", CPLL_LOCK,
+               CPLL_CON0, NULL),
+       [epll] = PLL(pll_36xx, fout_epll, "fout_epll", "fin_pll", EPLL_LOCK,
+               EPLL_CON0, NULL),
+       [vpll] = PLL(pll_36xx, fout_vpll, "fout_vpll", "mout_vpllsrc",
+               VPLL_LOCK, VPLL_CON0, NULL),
 };
 
-static __initdata struct of_device_id ext_clk_match[] = {
+static struct of_device_id ext_clk_match[] __initdata = {
        { .compatible = "samsung,clock-xxti", .data = (void *)0, },
        { },
 };
 
 /* register exynox5250 clocks */
-void __init exynos5250_clk_init(struct device_node *np)
+static void __init exynos5250_clk_init(struct device_node *np)
 {
        void __iomem *reg_base;
-       struct clk *apll, *mpll, *epll, *vpll, *bpll, *gpll, *cpll;
 
        if (np) {
                reg_base = of_iomap(np, 0);
@@ -490,22 +558,17 @@ void __init exynos5250_clk_init(struct device_node *np)
        samsung_clk_of_register_fixed_ext(exynos5250_fixed_rate_ext_clks,
                        ARRAY_SIZE(exynos5250_fixed_rate_ext_clks),
                        ext_clk_match);
+       samsung_clk_register_mux(exynos5250_pll_pmux_clks,
+                               ARRAY_SIZE(exynos5250_pll_pmux_clks));
+
+       if (_get_rate("fin_pll") == 24 * MHZ)
+               exynos5250_plls[epll].rate_table = epll_24mhz_tbl;
 
-       apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
-                       reg_base + 0x100);
-       mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
-                       reg_base + 0x4100);
-       bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll",
-                       reg_base + 0x20110);
-       gpll = samsung_clk_register_pll35xx("fout_gpll", "fin_pll",
-                       reg_base + 0x10150);
-       cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll",
-                       reg_base + 0x10120);
-       epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
-                       reg_base + 0x10130);
-       vpll = samsung_clk_register_pll36xx("fout_vpll", "mout_vpllsrc",
-                       reg_base + 0x10140);
+       if (_get_rate("mout_vpllsrc") == 24 * MHZ)
+               exynos5250_plls[vpll].rate_table =  vpll_24mhz_tbl;
 
+       samsung_clk_register_pll(exynos5250_plls, ARRAY_SIZE(exynos5250_plls),
+                                       reg_base);
        samsung_clk_register_fixed_rate(exynos5250_fixed_rate_clks,
                        ARRAY_SIZE(exynos5250_fixed_rate_clks));
        samsung_clk_register_fixed_factor(exynos5250_fixed_factor_clks,
index 68a96cbd4936724da2919498cb3821b52724ed3d..48c4a9350b91172d6222ed74b95862e223f802ad 100644 (file)
 #include <linux/of_address.h>
 
 #include "clk.h"
-#include "clk-pll.h"
 
+#define APLL_LOCK              0x0
+#define APLL_CON0              0x100
 #define SRC_CPU                        0x200
 #define DIV_CPU0               0x500
 #define DIV_CPU1               0x504
 #define GATE_BUS_CPU           0x700
 #define GATE_SCLK_CPU          0x800
+#define CPLL_LOCK              0x10020
+#define DPLL_LOCK              0x10030
+#define EPLL_LOCK              0x10040
+#define RPLL_LOCK              0x10050
+#define IPLL_LOCK              0x10060
+#define SPLL_LOCK              0x10070
+#define VPLL_LOCK              0x10070
+#define MPLL_LOCK              0x10090
+#define CPLL_CON0              0x10120
+#define DPLL_CON0              0x10128
+#define EPLL_CON0              0x10130
+#define RPLL_CON0              0x10140
+#define IPLL_CON0              0x10150
+#define SPLL_CON0              0x10160
+#define VPLL_CON0              0x10170
+#define MPLL_CON0              0x10180
 #define SRC_TOP0               0x10200
 #define SRC_TOP1               0x10204
 #define SRC_TOP2               0x10208
 #define GATE_TOP_SCLK_MAU      0x1083c
 #define GATE_TOP_SCLK_FSYS     0x10840
 #define GATE_TOP_SCLK_PERIC    0x10850
+#define BPLL_LOCK              0x20010
+#define BPLL_CON0              0x20110
 #define SRC_CDREX              0x20200
+#define KPLL_LOCK              0x28000
+#define KPLL_CON0              0x28100
 #define SRC_KFC                        0x28200
 #define DIV_KFC0               0x28500
 
+/* list of PLLs */
+enum exynos5420_plls {
+       apll, cpll, dpll, epll, rpll, ipll, spll, vpll, mpll,
+       bpll, kpll,
+       nr_plls                 /* number of PLLs */
+};
+
 enum exynos5420_clks {
        none,
 
        /* core clocks */
-       fin_pll,
+       fin_pll,  fout_apll, fout_cpll, fout_dpll, fout_epll, fout_rpll,
+       fout_ipll, fout_spll, fout_vpll, fout_mpll, fout_bpll, fout_kpll,
 
        /* gate for special clocks (sclk) */
        sclk_uart0 = 128, sclk_uart1, sclk_uart2, sclk_uart3, sclk_mmc0,
@@ -91,7 +120,7 @@ enum exynos5420_clks {
        sclk_i2s2, sclk_pcm1, sclk_pcm2, sclk_spdif, sclk_hdmi, sclk_pixel,
        sclk_dp1, sclk_mipi1, sclk_fimd1, sclk_maudio0, sclk_maupcm0,
        sclk_usbd300, sclk_usbd301, sclk_usbphy300, sclk_usbphy301, sclk_unipro,
-       sclk_pwm, sclk_gscl_wa, sclk_gscl_wb,
+       sclk_pwm, sclk_gscl_wa, sclk_gscl_wb, sclk_hdmiphy,
 
        /* gate clocks */
        aclk66_peric = 256, uart0, uart1, uart2, uart3, i2c0, i2c1, i2c2, i2c3,
@@ -109,7 +138,13 @@ enum exynos5420_clks {
        aclk300_gscl = 460, smmu_gscl0, smmu_gscl1, gscl_wa, gscl_wb, gscl0,
        gscl1, clk_3aa, aclk266_g2d = 470, sss, slim_sss, mdma0,
        aclk333_g2d = 480, g2d, aclk333_432_gscl = 490, smmu_3aa, smmu_fimcl0,
-       smmu_fimcl1, smmu_fimcl3, fimc_lite3, aclk_g3d = 500, g3d,
+       smmu_fimcl1, smmu_fimcl3, fimc_lite3, aclk_g3d = 500, g3d, smmu_mixer,
+
+       /* mux clocks */
+       mout_hdmi = 640,
+
+       /* divider clocks */
+       dout_pixel = 768,
 
        nr_clks,
 };
@@ -118,7 +153,7 @@ enum exynos5420_clks {
  * list of controller registers to be saved and restored during a
  * suspend/resume cycle.
  */
-static __initdata unsigned long exynos5420_clk_regs[] = {
+static unsigned long exynos5420_clk_regs[] __initdata = {
        SRC_CPU,
        DIV_CPU0,
        DIV_CPU1,
@@ -257,29 +292,29 @@ PNAME(audio2_p)   = { "fin_pll", "cdclk2", "sclk_dpll", "sclk_mpll",
                  "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
 PNAME(spdif_p) = { "fin_pll", "dout_audio0", "dout_audio1", "dout_audio2",
                  "spdif_extclk", "sclk_ipll", "sclk_epll", "sclk_rpll" };
-PNAME(hdmi_p)  = { "sclk_hdmiphy", "dout_hdmi_pixel" };
+PNAME(hdmi_p)  = { "dout_hdmi_pixel", "sclk_hdmiphy" };
 PNAME(maudio0_p)       = { "fin_pll", "maudio_clk", "sclk_dpll", "sclk_mpll",
                          "sclk_spll", "sclk_ipll", "sclk_epll", "sclk_rpll" };
 
 /* fixed rate clocks generated outside the soc */
-struct samsung_fixed_rate_clock exynos5420_fixed_rate_ext_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos5420_fixed_rate_ext_clks[] __initdata = {
        FRATE(fin_pll, "fin_pll", NULL, CLK_IS_ROOT, 0),
 };
 
 /* fixed rate clocks generated inside the soc */
-struct samsung_fixed_rate_clock exynos5420_fixed_rate_clks[] __initdata = {
-       FRATE(none, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
+static struct samsung_fixed_rate_clock exynos5420_fixed_rate_clks[] __initdata = {
+       FRATE(sclk_hdmiphy, "sclk_hdmiphy", NULL, CLK_IS_ROOT, 24000000),
        FRATE(none, "sclk_pwi", NULL, CLK_IS_ROOT, 24000000),
        FRATE(none, "sclk_usbh20", NULL, CLK_IS_ROOT, 48000000),
        FRATE(none, "mphy_refclk_ixtal24", NULL, CLK_IS_ROOT, 48000000),
        FRATE(none, "sclk_usbh20_scan_clk", NULL, CLK_IS_ROOT, 480000000),
 };
 
-struct samsung_fixed_factor_clock exynos5420_fixed_factor_clks[] __initdata = {
+static struct samsung_fixed_factor_clock exynos5420_fixed_factor_clks[] __initdata = {
        FFACTOR(none, "sclk_hsic_12m", "fin_pll", 1, 2, 0),
 };
 
-struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
        MUX(none, "mout_mspll_kfc", mspll_cpu_p, SRC_TOP7, 8, 2),
        MUX(none, "mout_mspll_cpu", mspll_cpu_p, SRC_TOP7, 12, 2),
        MUX(none, "mout_apll", apll_p, SRC_CPU, 0, 1),
@@ -371,7 +406,7 @@ struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
        MUX(none, "mout_mipi1", group2_p, SRC_DISP10, 16, 3),
        MUX(none, "mout_dp1", group2_p, SRC_DISP10, 20, 3),
        MUX(none, "mout_pixel", group2_p, SRC_DISP10, 24, 3),
-       MUX(none, "mout_hdmi", hdmi_p, SRC_DISP10, 28, 1),
+       MUX(mout_hdmi, "mout_hdmi", hdmi_p, SRC_DISP10, 28, 1),
 
        /* MAU Block */
        MUX(none, "mout_maudio0", maudio0_p, SRC_MAU, 28, 3),
@@ -399,7 +434,7 @@ struct samsung_mux_clock exynos5420_mux_clks[] __initdata = {
        MUX(none, "mout_spi2", group2_p, SRC_PERIC1, 28, 3),
 };
 
-struct samsung_div_clock exynos5420_div_clks[] __initdata = {
+static struct samsung_div_clock exynos5420_div_clks[] __initdata = {
        DIV(none, "div_arm", "mout_cpu", DIV_CPU0, 0, 3),
        DIV(none, "sclk_apll", "mout_apll", DIV_CPU0, 24, 3),
        DIV(none, "armclk2", "div_arm", DIV_CPU0, 28, 3),
@@ -431,7 +466,7 @@ struct samsung_div_clock exynos5420_div_clks[] __initdata = {
        DIV(none, "dout_fimd1", "mout_fimd1", DIV_DISP10, 0, 4),
        DIV(none, "dout_mipi1", "mout_mipi1", DIV_DISP10, 16, 8),
        DIV(none, "dout_dp1", "mout_dp1", DIV_DISP10, 24, 4),
-       DIV(none, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4),
+       DIV(dout_pixel, "dout_hdmi_pixel", "mout_pixel", DIV_DISP10, 28, 4),
 
        /* Audio Block */
        DIV(none, "dout_maudio0", "mout_maudio0", DIV_MAU, 20, 4),
@@ -479,7 +514,7 @@ struct samsung_div_clock exynos5420_div_clks[] __initdata = {
        DIV(none, "dout_pre_spi2", "dout_spi2", DIV_PERIC4, 24, 8),
 };
 
-struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
        /* TODO: Re-verify the CG bits for all the gate clocks */
        GATE_A(mct, "pclk_st", "aclk66_psgen", GATE_BUS_PERIS1, 2, 0, 0, "mct"),
 
@@ -696,19 +731,43 @@ struct samsung_gate_clock exynos5420_gate_clks[] __initdata = {
        GATE(smmu_mscl0, "smmu_mscl0", "aclk400_mscl", GATE_IP_MSCL, 8, 0, 0),
        GATE(smmu_mscl1, "smmu_mscl1", "aclk400_mscl", GATE_IP_MSCL, 9, 0, 0),
        GATE(smmu_mscl2, "smmu_mscl2", "aclk400_mscl", GATE_IP_MSCL, 10, 0, 0),
+       GATE(smmu_mixer, "smmu_mixer", "aclk200_disp1", GATE_IP_DISP1, 9, 0, 0),
 };
 
-static __initdata struct of_device_id ext_clk_match[] = {
+static struct samsung_pll_clock exynos5420_plls[nr_plls] __initdata = {
+       [apll] = PLL(pll_2550, fout_apll, "fout_apll", "fin_pll", APLL_LOCK,
+               APLL_CON0, NULL),
+       [cpll] = PLL(pll_2550, fout_mpll, "fout_mpll", "fin_pll", MPLL_LOCK,
+               MPLL_CON0, NULL),
+       [dpll] = PLL(pll_2550, fout_dpll, "fout_dpll", "fin_pll", DPLL_LOCK,
+               DPLL_CON0, NULL),
+       [epll] = PLL(pll_2650, fout_epll, "fout_epll", "fin_pll", EPLL_LOCK,
+               EPLL_CON0, NULL),
+       [rpll] = PLL(pll_2650, fout_rpll, "fout_rpll", "fin_pll", RPLL_LOCK,
+               RPLL_CON0, NULL),
+       [ipll] = PLL(pll_2550, fout_ipll, "fout_ipll", "fin_pll", IPLL_LOCK,
+               IPLL_CON0, NULL),
+       [spll] = PLL(pll_2550, fout_spll, "fout_spll", "fin_pll", SPLL_LOCK,
+               SPLL_CON0, NULL),
+       [vpll] = PLL(pll_2550, fout_vpll, "fout_vpll", "fin_pll", VPLL_LOCK,
+               VPLL_CON0, NULL),
+       [mpll] = PLL(pll_2550, fout_mpll, "fout_mpll", "fin_pll", MPLL_LOCK,
+               MPLL_CON0, NULL),
+       [bpll] = PLL(pll_2550, fout_bpll, "fout_bpll", "fin_pll", BPLL_LOCK,
+               BPLL_CON0, NULL),
+       [kpll] = PLL(pll_2550, fout_kpll, "fout_kpll", "fin_pll", KPLL_LOCK,
+               KPLL_CON0, NULL),
+};
+
+static struct of_device_id ext_clk_match[] __initdata = {
        { .compatible = "samsung,exynos5420-oscclk", .data = (void *)0, },
        { },
 };
 
 /* register exynos5420 clocks */
-void __init exynos5420_clk_init(struct device_node *np)
+static void __init exynos5420_clk_init(struct device_node *np)
 {
        void __iomem *reg_base;
-       struct clk *apll, *bpll, *cpll, *dpll, *epll, *ipll, *kpll, *mpll;
-       struct clk *rpll, *spll, *vpll;
 
        if (np) {
                reg_base = of_iomap(np, 0);
@@ -724,30 +783,8 @@ void __init exynos5420_clk_init(struct device_node *np)
        samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks,
                        ARRAY_SIZE(exynos5420_fixed_rate_ext_clks),
                        ext_clk_match);
-
-       apll = samsung_clk_register_pll35xx("fout_apll", "fin_pll",
-                       reg_base + 0x100);
-       bpll = samsung_clk_register_pll35xx("fout_bpll", "fin_pll",
-                       reg_base + 0x20110);
-       cpll = samsung_clk_register_pll35xx("fout_cpll", "fin_pll",
-                       reg_base + 0x10120);
-       dpll = samsung_clk_register_pll35xx("fout_dpll", "fin_pll",
-                       reg_base + 0x10128);
-       epll = samsung_clk_register_pll36xx("fout_epll", "fin_pll",
-                       reg_base + 0x10130);
-       ipll = samsung_clk_register_pll35xx("fout_ipll", "fin_pll",
-                       reg_base + 0x10150);
-       kpll = samsung_clk_register_pll35xx("fout_kpll", "fin_pll",
-                       reg_base + 0x28100);
-       mpll = samsung_clk_register_pll35xx("fout_mpll", "fin_pll",
-                       reg_base + 0x10180);
-       rpll = samsung_clk_register_pll36xx("fout_rpll", "fin_pll",
-                       reg_base + 0x10140);
-       spll = samsung_clk_register_pll35xx("fout_spll", "fin_pll",
-                       reg_base + 0x10160);
-       vpll = samsung_clk_register_pll35xx("fout_vpll", "fin_pll",
-                       reg_base + 0x10170);
-
+       samsung_clk_register_pll(exynos5420_plls, ARRAY_SIZE(exynos5420_plls),
+                                       reg_base);
        samsung_clk_register_fixed_rate(exynos5420_fixed_rate_clks,
                        ARRAY_SIZE(exynos5420_fixed_rate_clks));
        samsung_clk_register_fixed_factor(exynos5420_fixed_factor_clks,
index 7d5434167a96839dc7bb3f0e4fd92c065cdce21e..f8658945bfd2a7a1d51f2dabb1d761ac4d58eae0 100644 (file)
@@ -41,12 +41,12 @@ PNAME(mout_armclk_p)        = { "cplla", "cpllb" };
 PNAME(mout_spi_p)      = { "div125", "div200" };
 
 /* fixed rate clocks generated outside the soc */
-struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = {
        FRATE(none, "xtal", NULL, CLK_IS_ROOT, 0),
 };
 
 /* fixed rate clocks */
-struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initdata = {
+static struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initdata = {
        FRATE(none, "ppll", NULL, CLK_IS_ROOT, 1000000000),
        FRATE(none, "usb_phy0", NULL, CLK_IS_ROOT, 60000000),
        FRATE(none, "usb_phy1", NULL, CLK_IS_ROOT, 60000000),
@@ -55,26 +55,26 @@ struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initdata = {
 };
 
 /* fixed factor clocks */
-struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initdata = {
+static struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initdata = {
        FFACTOR(none, "div250", "ppll", 1, 4, 0),
        FFACTOR(none, "div200", "ppll", 1, 5, 0),
        FFACTOR(none, "div125", "div250", 1, 2, 0),
 };
 
 /* mux clocks */
-struct samsung_mux_clock exynos5440_mux_clks[] __initdata = {
+static struct samsung_mux_clock exynos5440_mux_clks[] __initdata = {
        MUX(none, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1),
        MUX_A(arm_clk, "arm_clk", mout_armclk_p,
                        CPU_CLK_STATUS, 0, 1, "armclk"),
 };
 
 /* divider clocks */
-struct samsung_div_clock exynos5440_div_clks[] __initdata = {
+static struct samsung_div_clock exynos5440_div_clks[] __initdata = {
        DIV(spi_baud, "div_spi", "mout_spi", MISC_DOUT1, 3, 2),
 };
 
 /* gate clocks */
-struct samsung_gate_clock exynos5440_gate_clks[] __initdata = {
+static struct samsung_gate_clock exynos5440_gate_clks[] __initdata = {
        GATE(pb0_250, "pb0_250", "div250", CLKEN_OV_VAL, 3, 0, 0),
        GATE(pr0_250, "pr0_250", "div250", CLKEN_OV_VAL, 4, 0, 0),
        GATE(pr1_250, "pr1_250", "div250", CLKEN_OV_VAL, 5, 0, 0),
@@ -97,13 +97,13 @@ struct samsung_gate_clock exynos5440_gate_clks[] __initdata = {
        GATE(cs250_o, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0),
 };
 
-static __initdata struct of_device_id ext_clk_match[] = {
+static struct of_device_id ext_clk_match[] __initdata = {
        { .compatible = "samsung,clock-xtal", .data = (void *)0, },
        {},
 };
 
 /* register exynos5440 clocks */
-void __init exynos5440_clk_init(struct device_node *np)
+static void __init exynos5440_clk_init(struct device_node *np)
 {
        void __iomem *reg_base;
 
@@ -132,7 +132,7 @@ void __init exynos5440_clk_init(struct device_node *np)
        samsung_clk_register_gate(exynos5440_gate_clks,
                        ARRAY_SIZE(exynos5440_gate_clks));
 
-       pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("armclk"));
+       pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk"));
        pr_info("exynos5440 clock initialization complete\n");
 }
 CLK_OF_DECLARE(exynos5440_clk, "samsung,exynos5440-clock", exynos5440_clk_init);
index 362f12dcd94422fd7fb6c9da1c9b71684e649cef..529e11dc2c6b0e8af21506211a7756f04b324123 100644 (file)
 */
 
 #include <linux/errno.h>
+#include <linux/hrtimer.h>
 #include "clk.h"
 #include "clk-pll.h"
 
+#define PLL_TIMEOUT_MS         10
+
+struct samsung_clk_pll {
+       struct clk_hw           hw;
+       void __iomem            *lock_reg;
+       void __iomem            *con_reg;
+       enum samsung_pll_type   type;
+       unsigned int            rate_count;
+       const struct samsung_pll_rate_table *rate_table;
+};
+
+#define to_clk_pll(_hw) container_of(_hw, struct samsung_clk_pll, hw)
+
+static const struct samsung_pll_rate_table *samsung_get_pll_settings(
+                               struct samsung_clk_pll *pll, unsigned long rate)
+{
+       const struct samsung_pll_rate_table  *rate_table = pll->rate_table;
+       int i;
+
+       for (i = 0; i < pll->rate_count; i++) {
+               if (rate == rate_table[i].rate)
+                       return &rate_table[i];
+       }
+
+       return NULL;
+}
+
+static long samsung_pll_round_rate(struct clk_hw *hw,
+                       unsigned long drate, unsigned long *prate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       const struct samsung_pll_rate_table *rate_table = pll->rate_table;
+       int i;
+
+       /* Assumming rate_table is in descending order */
+       for (i = 0; i < pll->rate_count; i++) {
+               if (drate >= rate_table[i].rate)
+                       return rate_table[i].rate;
+       }
+
+       /* return minimum supported value */
+       return rate_table[i - 1].rate;
+}
+
 /*
  * PLL35xx Clock Type
  */
+/* Maximum lock time can be 270 * PDIV cycles */
+#define PLL35XX_LOCK_FACTOR    (270)
 
 #define PLL35XX_MDIV_MASK       (0x3FF)
 #define PLL35XX_PDIV_MASK       (0x3F)
 #define PLL35XX_SDIV_MASK       (0x7)
+#define PLL35XX_LOCK_STAT_MASK (0x1)
 #define PLL35XX_MDIV_SHIFT      (16)
 #define PLL35XX_PDIV_SHIFT      (8)
 #define PLL35XX_SDIV_SHIFT      (0)
-
-struct samsung_clk_pll35xx {
-       struct clk_hw           hw;
-       const void __iomem      *con_reg;
-};
-
-#define to_clk_pll35xx(_hw) container_of(_hw, struct samsung_clk_pll35xx, hw)
+#define PLL35XX_LOCK_STAT_SHIFT        (29)
 
 static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
                                unsigned long parent_rate)
 {
-       struct samsung_clk_pll35xx *pll = to_clk_pll35xx(hw);
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
        u32 mdiv, pdiv, sdiv, pll_con;
        u64 fvco = parent_rate;
 
@@ -49,48 +91,80 @@ static unsigned long samsung_pll35xx_recalc_rate(struct clk_hw *hw,
        return (unsigned long)fvco;
 }
 
-static const struct clk_ops samsung_pll35xx_clk_ops = {
-       .recalc_rate = samsung_pll35xx_recalc_rate,
-};
-
-struct clk * __init samsung_clk_register_pll35xx(const char *name,
-                       const char *pname, const void __iomem *con_reg)
+static inline bool samsung_pll35xx_mp_change(
+               const struct samsung_pll_rate_table *rate, u32 pll_con)
 {
-       struct samsung_clk_pll35xx *pll;
-       struct clk *clk;
-       struct clk_init_data init;
+       u32 old_mdiv, old_pdiv;
 
-       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-       if (!pll) {
-               pr_err("%s: could not allocate pll clk %s\n", __func__, name);
-               return NULL;
+       old_mdiv = (pll_con >> PLL35XX_MDIV_SHIFT) & PLL35XX_MDIV_MASK;
+       old_pdiv = (pll_con >> PLL35XX_PDIV_SHIFT) & PLL35XX_PDIV_MASK;
+
+       return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv);
+}
+
+static int samsung_pll35xx_set_rate(struct clk_hw *hw, unsigned long drate,
+                                       unsigned long prate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       const struct samsung_pll_rate_table *rate;
+       u32 tmp;
+
+       /* Get required rate settings from table */
+       rate = samsung_get_pll_settings(pll, drate);
+       if (!rate) {
+               pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+                       drate, __clk_get_name(hw->clk));
+               return -EINVAL;
        }
 
-       init.name = name;
-       init.ops = &samsung_pll35xx_clk_ops;
-       init.flags = CLK_GET_RATE_NOCACHE;
-       init.parent_names = &pname;
-       init.num_parents = 1;
+       tmp = __raw_readl(pll->con_reg);
 
-       pll->hw.init = &init;
-       pll->con_reg = con_reg;
+       if (!(samsung_pll35xx_mp_change(rate, tmp))) {
+               /* If only s change, change just s value only*/
+               tmp &= ~(PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT);
+               tmp |= rate->sdiv << PLL35XX_SDIV_SHIFT;
+               __raw_writel(tmp, pll->con_reg);
 
-       clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk)) {
-               pr_err("%s: failed to register pll clock %s\n", __func__,
-                               name);
-               kfree(pll);
+               return 0;
        }
 
-       if (clk_register_clkdev(clk, name, NULL))
-               pr_err("%s: failed to register lookup for %s", __func__, name);
-
-       return clk;
+       /* Set PLL lock time. */
+       __raw_writel(rate->pdiv * PLL35XX_LOCK_FACTOR,
+                       pll->lock_reg);
+
+       /* Change PLL PMS values */
+       tmp &= ~((PLL35XX_MDIV_MASK << PLL35XX_MDIV_SHIFT) |
+                       (PLL35XX_PDIV_MASK << PLL35XX_PDIV_SHIFT) |
+                       (PLL35XX_SDIV_MASK << PLL35XX_SDIV_SHIFT));
+       tmp |= (rate->mdiv << PLL35XX_MDIV_SHIFT) |
+                       (rate->pdiv << PLL35XX_PDIV_SHIFT) |
+                       (rate->sdiv << PLL35XX_SDIV_SHIFT);
+       __raw_writel(tmp, pll->con_reg);
+
+       /* wait_lock_time */
+       do {
+               cpu_relax();
+               tmp = __raw_readl(pll->con_reg);
+       } while (!(tmp & (PLL35XX_LOCK_STAT_MASK
+                               << PLL35XX_LOCK_STAT_SHIFT)));
+       return 0;
 }
 
+static const struct clk_ops samsung_pll35xx_clk_ops = {
+       .recalc_rate = samsung_pll35xx_recalc_rate,
+       .round_rate = samsung_pll_round_rate,
+       .set_rate = samsung_pll35xx_set_rate,
+};
+
+static const struct clk_ops samsung_pll35xx_clk_min_ops = {
+       .recalc_rate = samsung_pll35xx_recalc_rate,
+};
+
 /*
  * PLL36xx Clock Type
  */
+/* Maximum lock time can be 3000 * PDIV cycles */
+#define PLL36XX_LOCK_FACTOR    (3000)
 
 #define PLL36XX_KDIV_MASK      (0xFFFF)
 #define PLL36XX_MDIV_MASK      (0x1FF)
@@ -99,18 +173,13 @@ struct clk * __init samsung_clk_register_pll35xx(const char *name,
 #define PLL36XX_MDIV_SHIFT     (16)
 #define PLL36XX_PDIV_SHIFT     (8)
 #define PLL36XX_SDIV_SHIFT     (0)
-
-struct samsung_clk_pll36xx {
-       struct clk_hw           hw;
-       const void __iomem      *con_reg;
-};
-
-#define to_clk_pll36xx(_hw) container_of(_hw, struct samsung_clk_pll36xx, hw)
+#define PLL36XX_KDIV_SHIFT     (0)
+#define PLL36XX_LOCK_STAT_SHIFT        (29)
 
 static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
                                unsigned long parent_rate)
 {
-       struct samsung_clk_pll36xx *pll = to_clk_pll36xx(hw);
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
        u32 mdiv, pdiv, sdiv, pll_con0, pll_con1;
        s16 kdiv;
        u64 fvco = parent_rate;
@@ -129,68 +198,102 @@ static unsigned long samsung_pll36xx_recalc_rate(struct clk_hw *hw,
        return (unsigned long)fvco;
 }
 
-static const struct clk_ops samsung_pll36xx_clk_ops = {
-       .recalc_rate = samsung_pll36xx_recalc_rate,
-};
-
-struct clk * __init samsung_clk_register_pll36xx(const char *name,
-                       const char *pname, const void __iomem *con_reg)
+static inline bool samsung_pll36xx_mpk_change(
+       const struct samsung_pll_rate_table *rate, u32 pll_con0, u32 pll_con1)
 {
-       struct samsung_clk_pll36xx *pll;
-       struct clk *clk;
-       struct clk_init_data init;
+       u32 old_mdiv, old_pdiv, old_kdiv;
 
-       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-       if (!pll) {
-               pr_err("%s: could not allocate pll clk %s\n", __func__, name);
-               return NULL;
+       old_mdiv = (pll_con0 >> PLL36XX_MDIV_SHIFT) & PLL36XX_MDIV_MASK;
+       old_pdiv = (pll_con0 >> PLL36XX_PDIV_SHIFT) & PLL36XX_PDIV_MASK;
+       old_kdiv = (pll_con1 >> PLL36XX_KDIV_SHIFT) & PLL36XX_KDIV_MASK;
+
+       return (rate->mdiv != old_mdiv || rate->pdiv != old_pdiv ||
+               rate->kdiv != old_kdiv);
+}
+
+static int samsung_pll36xx_set_rate(struct clk_hw *hw, unsigned long drate,
+                                       unsigned long parent_rate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 tmp, pll_con0, pll_con1;
+       const struct samsung_pll_rate_table *rate;
+
+       rate = samsung_get_pll_settings(pll, drate);
+       if (!rate) {
+               pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+                       drate, __clk_get_name(hw->clk));
+               return -EINVAL;
        }
 
-       init.name = name;
-       init.ops = &samsung_pll36xx_clk_ops;
-       init.flags = CLK_GET_RATE_NOCACHE;
-       init.parent_names = &pname;
-       init.num_parents = 1;
+       pll_con0 = __raw_readl(pll->con_reg);
+       pll_con1 = __raw_readl(pll->con_reg + 4);
 
-       pll->hw.init = &init;
-       pll->con_reg = con_reg;
+       if (!(samsung_pll36xx_mpk_change(rate, pll_con0, pll_con1))) {
+               /* If only s change, change just s value only*/
+               pll_con0 &= ~(PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT);
+               pll_con0 |= (rate->sdiv << PLL36XX_SDIV_SHIFT);
+               __raw_writel(pll_con0, pll->con_reg);
 
-       clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk)) {
-               pr_err("%s: failed to register pll clock %s\n", __func__,
-                               name);
-               kfree(pll);
+               return 0;
        }
 
-       if (clk_register_clkdev(clk, name, NULL))
-               pr_err("%s: failed to register lookup for %s", __func__, name);
-
-       return clk;
+       /* Set PLL lock time. */
+       __raw_writel(rate->pdiv * PLL36XX_LOCK_FACTOR, pll->lock_reg);
+
+        /* Change PLL PMS values */
+       pll_con0 &= ~((PLL36XX_MDIV_MASK << PLL36XX_MDIV_SHIFT) |
+                       (PLL36XX_PDIV_MASK << PLL36XX_PDIV_SHIFT) |
+                       (PLL36XX_SDIV_MASK << PLL36XX_SDIV_SHIFT));
+       pll_con0 |= (rate->mdiv << PLL36XX_MDIV_SHIFT) |
+                       (rate->pdiv << PLL36XX_PDIV_SHIFT) |
+                       (rate->sdiv << PLL36XX_SDIV_SHIFT);
+       __raw_writel(pll_con0, pll->con_reg);
+
+       pll_con1 &= ~(PLL36XX_KDIV_MASK << PLL36XX_KDIV_SHIFT);
+       pll_con1 |= rate->kdiv << PLL36XX_KDIV_SHIFT;
+       __raw_writel(pll_con1, pll->con_reg + 4);
+
+       /* wait_lock_time */
+       do {
+               cpu_relax();
+               tmp = __raw_readl(pll->con_reg);
+       } while (!(tmp & (1 << PLL36XX_LOCK_STAT_SHIFT)));
+
+       return 0;
 }
 
+static const struct clk_ops samsung_pll36xx_clk_ops = {
+       .recalc_rate = samsung_pll36xx_recalc_rate,
+       .set_rate = samsung_pll36xx_set_rate,
+       .round_rate = samsung_pll_round_rate,
+};
+
+static const struct clk_ops samsung_pll36xx_clk_min_ops = {
+       .recalc_rate = samsung_pll36xx_recalc_rate,
+};
+
 /*
  * PLL45xx Clock Type
  */
+#define PLL4502_LOCK_FACTOR    400
+#define PLL4508_LOCK_FACTOR    240
 
 #define PLL45XX_MDIV_MASK      (0x3FF)
 #define PLL45XX_PDIV_MASK      (0x3F)
 #define PLL45XX_SDIV_MASK      (0x7)
+#define PLL45XX_AFC_MASK       (0x1F)
 #define PLL45XX_MDIV_SHIFT     (16)
 #define PLL45XX_PDIV_SHIFT     (8)
 #define PLL45XX_SDIV_SHIFT     (0)
+#define PLL45XX_AFC_SHIFT      (0)
 
-struct samsung_clk_pll45xx {
-       struct clk_hw           hw;
-       enum pll45xx_type       type;
-       const void __iomem      *con_reg;
-};
-
-#define to_clk_pll45xx(_hw) container_of(_hw, struct samsung_clk_pll45xx, hw)
+#define PLL45XX_ENABLE         BIT(31)
+#define PLL45XX_LOCKED         BIT(29)
 
 static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
                                unsigned long parent_rate)
 {
-       struct samsung_clk_pll45xx *pll = to_clk_pll45xx(hw);
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
        u32 mdiv, pdiv, sdiv, pll_con;
        u64 fvco = parent_rate;
 
@@ -208,54 +311,113 @@ static unsigned long samsung_pll45xx_recalc_rate(struct clk_hw *hw,
        return (unsigned long)fvco;
 }
 
-static const struct clk_ops samsung_pll45xx_clk_ops = {
-       .recalc_rate = samsung_pll45xx_recalc_rate,
-};
-
-struct clk * __init samsung_clk_register_pll45xx(const char *name,
-                       const char *pname, const void __iomem *con_reg,
-                       enum pll45xx_type type)
+static bool samsung_pll45xx_mp_change(u32 pll_con0, u32 pll_con1,
+                               const struct samsung_pll_rate_table *rate)
 {
-       struct samsung_clk_pll45xx *pll;
-       struct clk *clk;
-       struct clk_init_data init;
+       u32 old_mdiv, old_pdiv, old_afc;
 
-       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-       if (!pll) {
-               pr_err("%s: could not allocate pll clk %s\n", __func__, name);
-               return NULL;
+       old_mdiv = (pll_con0 >> PLL45XX_MDIV_SHIFT) & PLL45XX_MDIV_MASK;
+       old_pdiv = (pll_con0 >> PLL45XX_PDIV_SHIFT) & PLL45XX_PDIV_MASK;
+       old_afc = (pll_con1 >> PLL45XX_AFC_SHIFT) & PLL45XX_AFC_MASK;
+
+       return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
+               || old_afc != rate->afc);
+}
+
+static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
+                                       unsigned long prate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       const struct samsung_pll_rate_table *rate;
+       u32 con0, con1;
+       ktime_t start;
+
+       /* Get required rate settings from table */
+       rate = samsung_get_pll_settings(pll, drate);
+       if (!rate) {
+               pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+                       drate, __clk_get_name(hw->clk));
+               return -EINVAL;
        }
 
-       init.name = name;
-       init.ops = &samsung_pll45xx_clk_ops;
-       init.flags = CLK_GET_RATE_NOCACHE;
-       init.parent_names = &pname;
-       init.num_parents = 1;
+       con0 = __raw_readl(pll->con_reg);
+       con1 = __raw_readl(pll->con_reg + 0x4);
 
-       pll->hw.init = &init;
-       pll->con_reg = con_reg;
-       pll->type = type;
+       if (!(samsung_pll45xx_mp_change(con0, con1, rate))) {
+               /* If only s change, change just s value only*/
+               con0 &= ~(PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT);
+               con0 |= rate->sdiv << PLL45XX_SDIV_SHIFT;
+               __raw_writel(con0, pll->con_reg);
 
-       clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk)) {
-               pr_err("%s: failed to register pll clock %s\n", __func__,
-                               name);
-               kfree(pll);
+               return 0;
        }
 
-       if (clk_register_clkdev(clk, name, NULL))
-               pr_err("%s: failed to register lookup for %s", __func__, name);
+       /* Set PLL PMS values. */
+       con0 &= ~((PLL45XX_MDIV_MASK << PLL45XX_MDIV_SHIFT) |
+                       (PLL45XX_PDIV_MASK << PLL45XX_PDIV_SHIFT) |
+                       (PLL45XX_SDIV_MASK << PLL45XX_SDIV_SHIFT));
+       con0 |= (rate->mdiv << PLL45XX_MDIV_SHIFT) |
+                       (rate->pdiv << PLL45XX_PDIV_SHIFT) |
+                       (rate->sdiv << PLL45XX_SDIV_SHIFT);
+
+       /* Set PLL AFC value. */
+       con1 = __raw_readl(pll->con_reg + 0x4);
+       con1 &= ~(PLL45XX_AFC_MASK << PLL45XX_AFC_SHIFT);
+       con1 |= (rate->afc << PLL45XX_AFC_SHIFT);
+
+       /* Set PLL lock time. */
+       switch (pll->type) {
+       case pll_4502:
+               __raw_writel(rate->pdiv * PLL4502_LOCK_FACTOR, pll->lock_reg);
+               break;
+       case pll_4508:
+               __raw_writel(rate->pdiv * PLL4508_LOCK_FACTOR, pll->lock_reg);
+               break;
+       default:
+               break;
+       };
+
+       /* Set new configuration. */
+       __raw_writel(con1, pll->con_reg + 0x4);
+       __raw_writel(con0, pll->con_reg);
+
+       /* Wait for locking. */
+       start = ktime_get();
+       while (!(__raw_readl(pll->con_reg) & PLL45XX_LOCKED)) {
+               ktime_t delta = ktime_sub(ktime_get(), start);
+
+               if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
+                       pr_err("%s: could not lock PLL %s\n",
+                                       __func__, __clk_get_name(hw->clk));
+                       return -EFAULT;
+               }
+
+               cpu_relax();
+       }
 
-       return clk;
+       return 0;
 }
 
+static const struct clk_ops samsung_pll45xx_clk_ops = {
+       .recalc_rate = samsung_pll45xx_recalc_rate,
+       .round_rate = samsung_pll_round_rate,
+       .set_rate = samsung_pll45xx_set_rate,
+};
+
+static const struct clk_ops samsung_pll45xx_clk_min_ops = {
+       .recalc_rate = samsung_pll45xx_recalc_rate,
+};
+
 /*
  * PLL46xx Clock Type
  */
+#define PLL46XX_LOCK_FACTOR    3000
 
+#define PLL46XX_VSEL_MASK      (1)
 #define PLL46XX_MDIV_MASK      (0x1FF)
 #define PLL46XX_PDIV_MASK      (0x3F)
 #define PLL46XX_SDIV_MASK      (0x7)
+#define PLL46XX_VSEL_SHIFT     (27)
 #define PLL46XX_MDIV_SHIFT     (16)
 #define PLL46XX_PDIV_SHIFT     (8)
 #define PLL46XX_SDIV_SHIFT     (0)
@@ -263,19 +425,20 @@ struct clk * __init samsung_clk_register_pll45xx(const char *name,
 #define PLL46XX_KDIV_MASK      (0xFFFF)
 #define PLL4650C_KDIV_MASK     (0xFFF)
 #define PLL46XX_KDIV_SHIFT     (0)
+#define PLL46XX_MFR_MASK       (0x3F)
+#define PLL46XX_MRR_MASK       (0x1F)
+#define PLL46XX_KDIV_SHIFT     (0)
+#define PLL46XX_MFR_SHIFT      (16)
+#define PLL46XX_MRR_SHIFT      (24)
 
-struct samsung_clk_pll46xx {
-       struct clk_hw           hw;
-       enum pll46xx_type       type;
-       const void __iomem      *con_reg;
-};
-
-#define to_clk_pll46xx(_hw) container_of(_hw, struct samsung_clk_pll46xx, hw)
+#define PLL46XX_ENABLE         BIT(31)
+#define PLL46XX_LOCKED         BIT(29)
+#define PLL46XX_VSEL           BIT(27)
 
 static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
                                unsigned long parent_rate)
 {
-       struct samsung_clk_pll46xx *pll = to_clk_pll46xx(hw);
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
        u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1, shift;
        u64 fvco = parent_rate;
 
@@ -295,47 +458,175 @@ static unsigned long samsung_pll46xx_recalc_rate(struct clk_hw *hw,
        return (unsigned long)fvco;
 }
 
+static bool samsung_pll46xx_mpk_change(u32 pll_con0, u32 pll_con1,
+                               const struct samsung_pll_rate_table *rate)
+{
+       u32 old_mdiv, old_pdiv, old_kdiv;
+
+       old_mdiv = (pll_con0 >> PLL46XX_MDIV_SHIFT) & PLL46XX_MDIV_MASK;
+       old_pdiv = (pll_con0 >> PLL46XX_PDIV_SHIFT) & PLL46XX_PDIV_MASK;
+       old_kdiv = (pll_con1 >> PLL46XX_KDIV_SHIFT) & PLL46XX_KDIV_MASK;
+
+       return (old_mdiv != rate->mdiv || old_pdiv != rate->pdiv
+               || old_kdiv != rate->kdiv);
+}
+
+static int samsung_pll46xx_set_rate(struct clk_hw *hw, unsigned long drate,
+                                       unsigned long prate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       const struct samsung_pll_rate_table *rate;
+       u32 con0, con1, lock;
+       ktime_t start;
+
+       /* Get required rate settings from table */
+       rate = samsung_get_pll_settings(pll, drate);
+       if (!rate) {
+               pr_err("%s: Invalid rate : %lu for pll clk %s\n", __func__,
+                       drate, __clk_get_name(hw->clk));
+               return -EINVAL;
+       }
+
+       con0 = __raw_readl(pll->con_reg);
+       con1 = __raw_readl(pll->con_reg + 0x4);
+
+       if (!(samsung_pll46xx_mpk_change(con0, con1, rate))) {
+               /* If only s change, change just s value only*/
+               con0 &= ~(PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT);
+               con0 |= rate->sdiv << PLL46XX_SDIV_SHIFT;
+               __raw_writel(con0, pll->con_reg);
+
+               return 0;
+       }
+
+       /* Set PLL lock time. */
+       lock = rate->pdiv * PLL46XX_LOCK_FACTOR;
+       if (lock > 0xffff)
+               /* Maximum lock time bitfield is 16-bit. */
+               lock = 0xffff;
+
+       /* Set PLL PMS and VSEL values. */
+       con0 &= ~((PLL46XX_MDIV_MASK << PLL46XX_MDIV_SHIFT) |
+                       (PLL46XX_PDIV_MASK << PLL46XX_PDIV_SHIFT) |
+                       (PLL46XX_SDIV_MASK << PLL46XX_SDIV_SHIFT) |
+                       (PLL46XX_VSEL_MASK << PLL46XX_VSEL_SHIFT));
+       con0 |= (rate->mdiv << PLL46XX_MDIV_SHIFT) |
+                       (rate->pdiv << PLL46XX_PDIV_SHIFT) |
+                       (rate->sdiv << PLL46XX_SDIV_SHIFT) |
+                       (rate->vsel << PLL46XX_VSEL_SHIFT);
+
+       /* Set PLL K, MFR and MRR values. */
+       con1 = __raw_readl(pll->con_reg + 0x4);
+       con1 &= ~((PLL46XX_KDIV_MASK << PLL46XX_KDIV_SHIFT) |
+                       (PLL46XX_MFR_MASK << PLL46XX_MFR_SHIFT) |
+                       (PLL46XX_MRR_MASK << PLL46XX_MRR_SHIFT));
+       con1 |= (rate->kdiv << PLL46XX_KDIV_SHIFT) |
+                       (rate->mfr << PLL46XX_MFR_SHIFT) |
+                       (rate->mrr << PLL46XX_MRR_SHIFT);
+
+       /* Write configuration to PLL */
+       __raw_writel(lock, pll->lock_reg);
+       __raw_writel(con0, pll->con_reg);
+       __raw_writel(con1, pll->con_reg + 0x4);
+
+       /* Wait for locking. */
+       start = ktime_get();
+       while (!(__raw_readl(pll->con_reg) & PLL46XX_LOCKED)) {
+               ktime_t delta = ktime_sub(ktime_get(), start);
+
+               if (ktime_to_ms(delta) > PLL_TIMEOUT_MS) {
+                       pr_err("%s: could not lock PLL %s\n",
+                                       __func__, __clk_get_name(hw->clk));
+                       return -EFAULT;
+               }
+
+               cpu_relax();
+       }
+
+       return 0;
+}
+
 static const struct clk_ops samsung_pll46xx_clk_ops = {
        .recalc_rate = samsung_pll46xx_recalc_rate,
+       .round_rate = samsung_pll_round_rate,
+       .set_rate = samsung_pll46xx_set_rate,
+};
+
+static const struct clk_ops samsung_pll46xx_clk_min_ops = {
+       .recalc_rate = samsung_pll46xx_recalc_rate,
 };
 
-struct clk * __init samsung_clk_register_pll46xx(const char *name,
-                       const char *pname, const void __iomem *con_reg,
-                       enum pll46xx_type type)
+/*
+ * PLL6552 Clock Type
+ */
+
+#define PLL6552_MDIV_MASK      0x3ff
+#define PLL6552_PDIV_MASK      0x3f
+#define PLL6552_SDIV_MASK      0x7
+#define PLL6552_MDIV_SHIFT     16
+#define PLL6552_PDIV_SHIFT     8
+#define PLL6552_SDIV_SHIFT     0
+
+static unsigned long samsung_pll6552_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
 {
-       struct samsung_clk_pll46xx *pll;
-       struct clk *clk;
-       struct clk_init_data init;
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 mdiv, pdiv, sdiv, pll_con;
+       u64 fvco = parent_rate;
 
-       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
-       if (!pll) {
-               pr_err("%s: could not allocate pll clk %s\n", __func__, name);
-               return NULL;
-       }
+       pll_con = __raw_readl(pll->con_reg);
+       mdiv = (pll_con >> PLL6552_MDIV_SHIFT) & PLL6552_MDIV_MASK;
+       pdiv = (pll_con >> PLL6552_PDIV_SHIFT) & PLL6552_PDIV_MASK;
+       sdiv = (pll_con >> PLL6552_SDIV_SHIFT) & PLL6552_SDIV_MASK;
 
-       init.name = name;
-       init.ops = &samsung_pll46xx_clk_ops;
-       init.flags = CLK_GET_RATE_NOCACHE;
-       init.parent_names = &pname;
-       init.num_parents = 1;
+       fvco *= mdiv;
+       do_div(fvco, (pdiv << sdiv));
 
-       pll->hw.init = &init;
-       pll->con_reg = con_reg;
-       pll->type = type;
+       return (unsigned long)fvco;
+}
 
-       clk = clk_register(NULL, &pll->hw);
-       if (IS_ERR(clk)) {
-               pr_err("%s: failed to register pll clock %s\n", __func__,
-                               name);
-               kfree(pll);
-       }
+static const struct clk_ops samsung_pll6552_clk_ops = {
+       .recalc_rate = samsung_pll6552_recalc_rate,
+};
 
-       if (clk_register_clkdev(clk, name, NULL))
-               pr_err("%s: failed to register lookup for %s", __func__, name);
+/*
+ * PLL6553 Clock Type
+ */
 
-       return clk;
+#define PLL6553_MDIV_MASK      0xff
+#define PLL6553_PDIV_MASK      0x3f
+#define PLL6553_SDIV_MASK      0x7
+#define PLL6553_KDIV_MASK      0xffff
+#define PLL6553_MDIV_SHIFT     16
+#define PLL6553_PDIV_SHIFT     8
+#define PLL6553_SDIV_SHIFT     0
+#define PLL6553_KDIV_SHIFT     0
+
+static unsigned long samsung_pll6553_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct samsung_clk_pll *pll = to_clk_pll(hw);
+       u32 mdiv, pdiv, sdiv, kdiv, pll_con0, pll_con1;
+       u64 fvco = parent_rate;
+
+       pll_con0 = __raw_readl(pll->con_reg);
+       pll_con1 = __raw_readl(pll->con_reg + 0x4);
+       mdiv = (pll_con0 >> PLL6553_MDIV_SHIFT) & PLL6553_MDIV_MASK;
+       pdiv = (pll_con0 >> PLL6553_PDIV_SHIFT) & PLL6553_PDIV_MASK;
+       sdiv = (pll_con0 >> PLL6553_SDIV_SHIFT) & PLL6553_SDIV_MASK;
+       kdiv = (pll_con1 >> PLL6553_KDIV_SHIFT) & PLL6553_KDIV_MASK;
+
+       fvco *= (mdiv << 16) + kdiv;
+       do_div(fvco, (pdiv << sdiv));
+       fvco >>= 16;
+
+       return (unsigned long)fvco;
 }
 
+static const struct clk_ops samsung_pll6553_clk_ops = {
+       .recalc_rate = samsung_pll6553_recalc_rate,
+};
+
 /*
  * PLL2550x Clock Type
  */
@@ -418,3 +709,117 @@ struct clk * __init samsung_clk_register_pll2550x(const char *name,
 
        return clk;
 }
+
+static void __init _samsung_clk_register_pll(struct samsung_pll_clock *pll_clk,
+                                               void __iomem *base)
+{
+       struct samsung_clk_pll *pll;
+       struct clk *clk;
+       struct clk_init_data init;
+       int ret, len;
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll) {
+               pr_err("%s: could not allocate pll clk %s\n",
+                       __func__, pll_clk->name);
+               return;
+       }
+
+       init.name = pll_clk->name;
+       init.flags = pll_clk->flags;
+       init.parent_names = &pll_clk->parent_name;
+       init.num_parents = 1;
+
+       if (pll_clk->rate_table) {
+               /* find count of rates in rate_table */
+               for (len = 0; pll_clk->rate_table[len].rate != 0; )
+                       len++;
+
+               pll->rate_count = len;
+               pll->rate_table = kmemdup(pll_clk->rate_table,
+                                       pll->rate_count *
+                                       sizeof(struct samsung_pll_rate_table),
+                                       GFP_KERNEL);
+               WARN(!pll->rate_table,
+                       "%s: could not allocate rate table for %s\n",
+                       __func__, pll_clk->name);
+       }
+
+       switch (pll_clk->type) {
+       /* clk_ops for 35xx and 2550 are similar */
+       case pll_35xx:
+       case pll_2550:
+               if (!pll->rate_table)
+                       init.ops = &samsung_pll35xx_clk_min_ops;
+               else
+                       init.ops = &samsung_pll35xx_clk_ops;
+               break;
+       case pll_4500:
+               init.ops = &samsung_pll45xx_clk_min_ops;
+               break;
+       case pll_4502:
+       case pll_4508:
+               if (!pll->rate_table)
+                       init.ops = &samsung_pll45xx_clk_min_ops;
+               else
+                       init.ops = &samsung_pll45xx_clk_ops;
+               break;
+       /* clk_ops for 36xx and 2650 are similar */
+       case pll_36xx:
+       case pll_2650:
+               if (!pll->rate_table)
+                       init.ops = &samsung_pll36xx_clk_min_ops;
+               else
+                       init.ops = &samsung_pll36xx_clk_ops;
+               break;
+       case pll_6552:
+               init.ops = &samsung_pll6552_clk_ops;
+               break;
+       case pll_6553:
+               init.ops = &samsung_pll6553_clk_ops;
+               break;
+       case pll_4600:
+       case pll_4650:
+       case pll_4650c:
+               if (!pll->rate_table)
+                       init.ops = &samsung_pll46xx_clk_min_ops;
+               else
+                       init.ops = &samsung_pll46xx_clk_ops;
+               break;
+       default:
+               pr_warn("%s: Unknown pll type for pll clk %s\n",
+                       __func__, pll_clk->name);
+       }
+
+       pll->hw.init = &init;
+       pll->type = pll_clk->type;
+       pll->lock_reg = base + pll_clk->lock_offset;
+       pll->con_reg = base + pll_clk->con_offset;
+
+       clk = clk_register(NULL, &pll->hw);
+       if (IS_ERR(clk)) {
+               pr_err("%s: failed to register pll clock %s : %ld\n",
+                       __func__, pll_clk->name, PTR_ERR(clk));
+               kfree(pll);
+               return;
+       }
+
+       samsung_clk_add_lookup(clk, pll_clk->id);
+
+       if (!pll_clk->alias)
+               return;
+
+       ret = clk_register_clkdev(clk, pll_clk->alias, pll_clk->dev_name);
+       if (ret)
+               pr_err("%s: failed to register lookup for %s : %d",
+                       __func__, pll_clk->name, ret);
+}
+
+void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
+                               unsigned int nr_pll, void __iomem *base)
+{
+       int cnt;
+
+       for (cnt = 0; cnt < nr_pll; cnt++)
+               _samsung_clk_register_pll(&pll_list[cnt], base);
+}
index f33786e9a78bea4ba4c247a42edc39ad6fc045b7..6c39030080fbede41fe6a4e52cdd87a7263aae18 100644 (file)
 #ifndef __SAMSUNG_CLK_PLL_H
 #define __SAMSUNG_CLK_PLL_H
 
-enum pll45xx_type {
+enum samsung_pll_type {
+       pll_35xx,
+       pll_36xx,
+       pll_2550,
+       pll_2650,
        pll_4500,
        pll_4502,
-       pll_4508
-};
-
-enum pll46xx_type {
+       pll_4508,
        pll_4600,
        pll_4650,
        pll_4650c,
+       pll_6552,
+       pll_6553,
+};
+
+#define PLL_35XX_RATE(_rate, _m, _p, _s)                       \
+       {                                                       \
+               .rate   =       (_rate),                                \
+               .mdiv   =       (_m),                           \
+               .pdiv   =       (_p),                           \
+               .sdiv   =       (_s),                           \
+       }
+
+#define PLL_36XX_RATE(_rate, _m, _p, _s, _k)                   \
+       {                                                       \
+               .rate   =       (_rate),                                \
+               .mdiv   =       (_m),                           \
+               .pdiv   =       (_p),                           \
+               .sdiv   =       (_s),                           \
+               .kdiv   =       (_k),                           \
+       }
+
+#define PLL_45XX_RATE(_rate, _m, _p, _s, _afc)                 \
+       {                                                       \
+               .rate   =       (_rate),                        \
+               .mdiv   =       (_m),                           \
+               .pdiv   =       (_p),                           \
+               .sdiv   =       (_s),                           \
+               .afc    =       (_afc),                         \
+       }
+
+#define PLL_4600_RATE(_rate, _m, _p, _s, _k, _vsel)            \
+       {                                                       \
+               .rate   =       (_rate),                        \
+               .mdiv   =       (_m),                           \
+               .pdiv   =       (_p),                           \
+               .sdiv   =       (_s),                           \
+               .kdiv   =       (_k),                           \
+               .vsel   =       (_vsel),                        \
+       }
+
+#define PLL_4650_RATE(_rate, _m, _p, _s, _k, _mfr, _mrr, _vsel)        \
+       {                                                       \
+               .rate   =       (_rate),                        \
+               .mdiv   =       (_m),                           \
+               .pdiv   =       (_p),                           \
+               .sdiv   =       (_s),                           \
+               .kdiv   =       (_k),                           \
+               .mfr    =       (_mfr),                         \
+               .mrr    =       (_mrr),                         \
+               .vsel   =       (_vsel),                        \
+       }
+
+/* NOTE: Rate table should be kept sorted in descending order. */
+
+struct samsung_pll_rate_table {
+       unsigned int rate;
+       unsigned int pdiv;
+       unsigned int mdiv;
+       unsigned int sdiv;
+       unsigned int kdiv;
+       unsigned int afc;
+       unsigned int mfr;
+       unsigned int mrr;
+       unsigned int vsel;
 };
 
-extern struct clk * __init samsung_clk_register_pll35xx(const char *name,
-                       const char *pname, const void __iomem *con_reg);
-extern struct clk * __init samsung_clk_register_pll36xx(const char *name,
-                       const char *pname, const void __iomem *con_reg);
-extern struct clk * __init samsung_clk_register_pll45xx(const char *name,
-                       const char *pname, const void __iomem *con_reg,
-                       enum pll45xx_type type);
-extern struct clk * __init samsung_clk_register_pll46xx(const char *name,
-                       const char *pname, const void __iomem *con_reg,
-                       enum pll46xx_type type);
 extern struct clk * __init samsung_clk_register_pll2550x(const char *name,
                        const char *pname, const void __iomem *reg_base,
                        const unsigned long offset);
diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c
new file mode 100644 (file)
index 0000000..7d2c842
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa at 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.
+ *
+ * Common Clock Framework support for all S3C64xx SoCs.
+*/
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/samsung,s3c64xx-clock.h>
+
+#include "clk.h"
+#include "clk-pll.h"
+
+/* S3C64xx clock controller register offsets. */
+#define APLL_LOCK              0x000
+#define MPLL_LOCK              0x004
+#define EPLL_LOCK              0x008
+#define APLL_CON               0x00c
+#define MPLL_CON               0x010
+#define EPLL_CON0              0x014
+#define EPLL_CON1              0x018
+#define CLK_SRC                        0x01c
+#define CLK_DIV0               0x020
+#define CLK_DIV1               0x024
+#define CLK_DIV2               0x028
+#define HCLK_GATE              0x030
+#define PCLK_GATE              0x034
+#define SCLK_GATE              0x038
+#define MEM0_GATE              0x03c
+#define CLK_SRC2               0x10c
+#define OTHERS                 0x900
+
+/* Helper macros to define clock arrays. */
+#define FIXED_RATE_CLOCKS(name)        \
+               static struct samsung_fixed_rate_clock name[]
+#define MUX_CLOCKS(name)       \
+               static struct samsung_mux_clock name[]
+#define DIV_CLOCKS(name)       \
+               static struct samsung_div_clock name[]
+#define GATE_CLOCKS(name)      \
+               static struct samsung_gate_clock name[]
+
+/* Helper macros for gate types present on S3C64xx. */
+#define GATE_BUS(_id, cname, pname, o, b) \
+               GATE(_id, cname, pname, o, b, 0, 0)
+#define GATE_SCLK(_id, cname, pname, o, b) \
+               GATE(_id, cname, pname, o, b, CLK_SET_RATE_PARENT, 0)
+#define GATE_ON(_id, cname, pname, o, b) \
+               GATE(_id, cname, pname, o, b, CLK_IGNORE_UNUSED, 0)
+
+/* list of PLLs to be registered */
+enum s3c64xx_plls {
+       apll, mpll, epll,
+};
+
+/*
+ * List of controller registers to be saved and restored during
+ * a suspend/resume cycle.
+ */
+static unsigned long s3c64xx_clk_regs[] __initdata = {
+       APLL_LOCK,
+       MPLL_LOCK,
+       EPLL_LOCK,
+       APLL_CON,
+       MPLL_CON,
+       EPLL_CON0,
+       EPLL_CON1,
+       CLK_SRC,
+       CLK_DIV0,
+       CLK_DIV1,
+       CLK_DIV2,
+       HCLK_GATE,
+       PCLK_GATE,
+       SCLK_GATE,
+};
+
+static unsigned long s3c6410_clk_regs[] __initdata = {
+       CLK_SRC2,
+       MEM0_GATE,
+};
+
+/* List of parent clocks common for all S3C64xx SoCs. */
+PNAME(spi_mmc_p)       = { "mout_epll", "dout_mpll", "fin_pll", "clk27m" };
+PNAME(uart_p)          = { "mout_epll", "dout_mpll" };
+PNAME(audio0_p)                = { "mout_epll", "dout_mpll", "fin_pll", "iiscdclk0",
+                               "pcmcdclk0", "none", "none", "none" };
+PNAME(audio1_p)                = { "mout_epll", "dout_mpll", "fin_pll", "iiscdclk1",
+                               "pcmcdclk0", "none", "none", "none" };
+PNAME(mfc_p)           = { "hclkx2", "mout_epll" };
+PNAME(apll_p)          = { "fin_pll", "fout_apll" };
+PNAME(mpll_p)          = { "fin_pll", "fout_mpll" };
+PNAME(epll_p)          = { "fin_pll", "fout_epll" };
+PNAME(hclkx2_p)                = { "mout_mpll", "mout_apll" };
+
+/* S3C6400-specific parent clocks. */
+PNAME(scaler_lcd_p6400)        = { "mout_epll", "dout_mpll", "none", "none" };
+PNAME(irda_p6400)      = { "mout_epll", "dout_mpll", "none", "clk48m" };
+PNAME(uhost_p6400)     = { "clk48m", "mout_epll", "dout_mpll", "none" };
+
+/* S3C6410-specific parent clocks. */
+PNAME(clk27_p6410)     = { "clk27m", "fin_pll" };
+PNAME(scaler_lcd_p6410)        = { "mout_epll", "dout_mpll", "fin_pll", "none" };
+PNAME(irda_p6410)      = { "mout_epll", "dout_mpll", "fin_pll", "clk48m" };
+PNAME(uhost_p6410)     = { "clk48m", "mout_epll", "dout_mpll", "fin_pll" };
+PNAME(audio2_p6410)    = { "mout_epll", "dout_mpll", "fin_pll", "iiscdclk2",
+                               "pcmcdclk1", "none", "none", "none" };
+
+/* Fixed rate clocks generated outside the SoC. */
+FIXED_RATE_CLOCKS(s3c64xx_fixed_rate_ext_clks) __initdata = {
+       FRATE(0, "fin_pll", NULL, CLK_IS_ROOT, 0),
+       FRATE(0, "xusbxti", NULL, CLK_IS_ROOT, 0),
+};
+
+/* Fixed rate clocks generated inside the SoC. */
+FIXED_RATE_CLOCKS(s3c64xx_fixed_rate_clks) __initdata = {
+       FRATE(CLK27M, "clk27m", NULL, CLK_IS_ROOT, 27000000),
+       FRATE(CLK48M, "clk48m", NULL, CLK_IS_ROOT, 48000000),
+};
+
+/* List of clock muxes present on all S3C64xx SoCs. */
+MUX_CLOCKS(s3c64xx_mux_clks) __initdata = {
+       MUX_F(0, "mout_syncmux", hclkx2_p, OTHERS, 6, 1, 0, CLK_MUX_READ_ONLY),
+       MUX(MOUT_APLL, "mout_apll", apll_p, CLK_SRC, 0, 1),
+       MUX(MOUT_MPLL, "mout_mpll", mpll_p, CLK_SRC, 1, 1),
+       MUX(MOUT_EPLL, "mout_epll", epll_p, CLK_SRC, 2, 1),
+       MUX(MOUT_MFC, "mout_mfc", mfc_p, CLK_SRC, 4, 1),
+       MUX(MOUT_AUDIO0, "mout_audio0", audio0_p, CLK_SRC, 7, 3),
+       MUX(MOUT_AUDIO1, "mout_audio1", audio1_p, CLK_SRC, 10, 3),
+       MUX(MOUT_UART, "mout_uart", uart_p, CLK_SRC, 13, 1),
+       MUX(MOUT_SPI0, "mout_spi0", spi_mmc_p, CLK_SRC, 14, 2),
+       MUX(MOUT_SPI1, "mout_spi1", spi_mmc_p, CLK_SRC, 16, 2),
+       MUX(MOUT_MMC0, "mout_mmc0", spi_mmc_p, CLK_SRC, 18, 2),
+       MUX(MOUT_MMC1, "mout_mmc1", spi_mmc_p, CLK_SRC, 20, 2),
+       MUX(MOUT_MMC2, "mout_mmc2", spi_mmc_p, CLK_SRC, 22, 2),
+};
+
+/* List of clock muxes present on S3C6400. */
+MUX_CLOCKS(s3c6400_mux_clks) __initdata = {
+       MUX(MOUT_UHOST, "mout_uhost", uhost_p6400, CLK_SRC, 5, 2),
+       MUX(MOUT_IRDA, "mout_irda", irda_p6400, CLK_SRC, 24, 2),
+       MUX(MOUT_LCD, "mout_lcd", scaler_lcd_p6400, CLK_SRC, 26, 2),
+       MUX(MOUT_SCALER, "mout_scaler", scaler_lcd_p6400, CLK_SRC, 28, 2),
+};
+
+/* List of clock muxes present on S3C6410. */
+MUX_CLOCKS(s3c6410_mux_clks) __initdata = {
+       MUX(MOUT_UHOST, "mout_uhost", uhost_p6410, CLK_SRC, 5, 2),
+       MUX(MOUT_IRDA, "mout_irda", irda_p6410, CLK_SRC, 24, 2),
+       MUX(MOUT_LCD, "mout_lcd", scaler_lcd_p6410, CLK_SRC, 26, 2),
+       MUX(MOUT_SCALER, "mout_scaler", scaler_lcd_p6410, CLK_SRC, 28, 2),
+       MUX(MOUT_DAC27, "mout_dac27", clk27_p6410, CLK_SRC, 30, 1),
+       MUX(MOUT_TV27, "mout_tv27", clk27_p6410, CLK_SRC, 31, 1),
+       MUX(MOUT_AUDIO2, "mout_audio2", audio2_p6410, CLK_SRC2, 0, 3),
+};
+
+/* List of clock dividers present on all S3C64xx SoCs. */
+DIV_CLOCKS(s3c64xx_div_clks) __initdata = {
+       DIV(DOUT_MPLL, "dout_mpll", "mout_mpll", CLK_DIV0, 4, 1),
+       DIV(HCLKX2, "hclkx2", "mout_syncmux", CLK_DIV0, 9, 3),
+       DIV(HCLK, "hclk", "hclkx2", CLK_DIV0, 8, 1),
+       DIV(PCLK, "pclk", "hclkx2", CLK_DIV0, 12, 4),
+       DIV(DOUT_SECUR, "dout_secur", "hclkx2", CLK_DIV0, 18, 2),
+       DIV(DOUT_CAM, "dout_cam", "hclkx2", CLK_DIV0, 20, 4),
+       DIV(DOUT_JPEG, "dout_jpeg", "hclkx2", CLK_DIV0, 24, 4),
+       DIV(DOUT_MFC, "dout_mfc", "mout_mfc", CLK_DIV0, 28, 4),
+       DIV(DOUT_MMC0, "dout_mmc0", "mout_mmc0", CLK_DIV1, 0, 4),
+       DIV(DOUT_MMC1, "dout_mmc1", "mout_mmc1", CLK_DIV1, 4, 4),
+       DIV(DOUT_MMC2, "dout_mmc2", "mout_mmc2", CLK_DIV1, 8, 4),
+       DIV(DOUT_LCD, "dout_lcd", "mout_lcd", CLK_DIV1, 12, 4),
+       DIV(DOUT_SCALER, "dout_scaler", "mout_scaler", CLK_DIV1, 16, 4),
+       DIV(DOUT_UHOST, "dout_uhost", "mout_uhost", CLK_DIV1, 20, 4),
+       DIV(DOUT_SPI0, "dout_spi0", "mout_spi0", CLK_DIV2, 0, 4),
+       DIV(DOUT_SPI1, "dout_spi1", "mout_spi1", CLK_DIV2, 4, 4),
+       DIV(DOUT_AUDIO0, "dout_audio0", "mout_audio0", CLK_DIV2, 8, 4),
+       DIV(DOUT_AUDIO1, "dout_audio1", "mout_audio1", CLK_DIV2, 12, 4),
+       DIV(DOUT_UART, "dout_uart", "mout_uart", CLK_DIV2, 16, 4),
+       DIV(DOUT_IRDA, "dout_irda", "mout_irda", CLK_DIV2, 20, 4),
+};
+
+/* List of clock dividers present on S3C6400. */
+DIV_CLOCKS(s3c6400_div_clks) __initdata = {
+       DIV(ARMCLK, "armclk", "mout_apll", CLK_DIV0, 0, 3),
+};
+
+/* List of clock dividers present on S3C6410. */
+DIV_CLOCKS(s3c6410_div_clks) __initdata = {
+       DIV(ARMCLK, "armclk", "mout_apll", CLK_DIV0, 0, 4),
+       DIV(DOUT_FIMC, "dout_fimc", "hclk", CLK_DIV1, 24, 4),
+       DIV(DOUT_AUDIO2, "dout_audio2", "mout_audio2", CLK_DIV2, 24, 4),
+};
+
+/* List of clock gates present on all S3C64xx SoCs. */
+GATE_CLOCKS(s3c64xx_gate_clks) __initdata = {
+       GATE_BUS(HCLK_UHOST, "hclk_uhost", "hclk", HCLK_GATE, 29),
+       GATE_BUS(HCLK_SECUR, "hclk_secur", "hclk", HCLK_GATE, 28),
+       GATE_BUS(HCLK_SDMA1, "hclk_sdma1", "hclk", HCLK_GATE, 27),
+       GATE_BUS(HCLK_SDMA0, "hclk_sdma0", "hclk", HCLK_GATE, 26),
+       GATE_ON(HCLK_DDR1, "hclk_ddr1", "hclk", HCLK_GATE, 24),
+       GATE_BUS(HCLK_USB, "hclk_usb", "hclk", HCLK_GATE, 20),
+       GATE_BUS(HCLK_HSMMC2, "hclk_hsmmc2", "hclk", HCLK_GATE, 19),
+       GATE_BUS(HCLK_HSMMC1, "hclk_hsmmc1", "hclk", HCLK_GATE, 18),
+       GATE_BUS(HCLK_HSMMC0, "hclk_hsmmc0", "hclk", HCLK_GATE, 17),
+       GATE_BUS(HCLK_MDP, "hclk_mdp", "hclk", HCLK_GATE, 16),
+       GATE_BUS(HCLK_DHOST, "hclk_dhost", "hclk", HCLK_GATE, 15),
+       GATE_BUS(HCLK_IHOST, "hclk_ihost", "hclk", HCLK_GATE, 14),
+       GATE_BUS(HCLK_DMA1, "hclk_dma1", "hclk", HCLK_GATE, 13),
+       GATE_BUS(HCLK_DMA0, "hclk_dma0", "hclk", HCLK_GATE, 12),
+       GATE_BUS(HCLK_JPEG, "hclk_jpeg", "hclk", HCLK_GATE, 11),
+       GATE_BUS(HCLK_CAMIF, "hclk_camif", "hclk", HCLK_GATE, 10),
+       GATE_BUS(HCLK_SCALER, "hclk_scaler", "hclk", HCLK_GATE, 9),
+       GATE_BUS(HCLK_2D, "hclk_2d", "hclk", HCLK_GATE, 8),
+       GATE_BUS(HCLK_TV, "hclk_tv", "hclk", HCLK_GATE, 7),
+       GATE_BUS(HCLK_POST0, "hclk_post0", "hclk", HCLK_GATE, 5),
+       GATE_BUS(HCLK_ROT, "hclk_rot", "hclk", HCLK_GATE, 4),
+       GATE_BUS(HCLK_LCD, "hclk_lcd", "hclk", HCLK_GATE, 3),
+       GATE_BUS(HCLK_TZIC, "hclk_tzic", "hclk", HCLK_GATE, 2),
+       GATE_ON(HCLK_INTC, "hclk_intc", "hclk", HCLK_GATE, 1),
+       GATE_ON(PCLK_SKEY, "pclk_skey", "pclk", PCLK_GATE, 24),
+       GATE_ON(PCLK_CHIPID, "pclk_chipid", "pclk", PCLK_GATE, 23),
+       GATE_BUS(PCLK_SPI1, "pclk_spi1", "pclk", PCLK_GATE, 22),
+       GATE_BUS(PCLK_SPI0, "pclk_spi0", "pclk", PCLK_GATE, 21),
+       GATE_BUS(PCLK_HSIRX, "pclk_hsirx", "pclk", PCLK_GATE, 20),
+       GATE_BUS(PCLK_HSITX, "pclk_hsitx", "pclk", PCLK_GATE, 19),
+       GATE_ON(PCLK_GPIO, "pclk_gpio", "pclk", PCLK_GATE, 18),
+       GATE_BUS(PCLK_IIC0, "pclk_iic0", "pclk", PCLK_GATE, 17),
+       GATE_BUS(PCLK_IIS1, "pclk_iis1", "pclk", PCLK_GATE, 16),
+       GATE_BUS(PCLK_IIS0, "pclk_iis0", "pclk", PCLK_GATE, 15),
+       GATE_BUS(PCLK_AC97, "pclk_ac97", "pclk", PCLK_GATE, 14),
+       GATE_BUS(PCLK_TZPC, "pclk_tzpc", "pclk", PCLK_GATE, 13),
+       GATE_BUS(PCLK_TSADC, "pclk_tsadc", "pclk", PCLK_GATE, 12),
+       GATE_BUS(PCLK_KEYPAD, "pclk_keypad", "pclk", PCLK_GATE, 11),
+       GATE_BUS(PCLK_IRDA, "pclk_irda", "pclk", PCLK_GATE, 10),
+       GATE_BUS(PCLK_PCM1, "pclk_pcm1", "pclk", PCLK_GATE, 9),
+       GATE_BUS(PCLK_PCM0, "pclk_pcm0", "pclk", PCLK_GATE, 8),
+       GATE_BUS(PCLK_PWM, "pclk_pwm", "pclk", PCLK_GATE, 7),
+       GATE_BUS(PCLK_RTC, "pclk_rtc", "pclk", PCLK_GATE, 6),
+       GATE_BUS(PCLK_WDT, "pclk_wdt", "pclk", PCLK_GATE, 5),
+       GATE_BUS(PCLK_UART3, "pclk_uart3", "pclk", PCLK_GATE, 4),
+       GATE_BUS(PCLK_UART2, "pclk_uart2", "pclk", PCLK_GATE, 3),
+       GATE_BUS(PCLK_UART1, "pclk_uart1", "pclk", PCLK_GATE, 2),
+       GATE_BUS(PCLK_UART0, "pclk_uart0", "pclk", PCLK_GATE, 1),
+       GATE_BUS(PCLK_MFC, "pclk_mfc", "pclk", PCLK_GATE, 0),
+       GATE_SCLK(SCLK_UHOST, "sclk_uhost", "dout_uhost", SCLK_GATE, 30),
+       GATE_SCLK(SCLK_MMC2_48, "sclk_mmc2_48", "clk48m", SCLK_GATE, 29),
+       GATE_SCLK(SCLK_MMC1_48, "sclk_mmc1_48", "clk48m", SCLK_GATE, 28),
+       GATE_SCLK(SCLK_MMC0_48, "sclk_mmc0_48", "clk48m", SCLK_GATE, 27),
+       GATE_SCLK(SCLK_MMC2, "sclk_mmc2", "dout_mmc2", SCLK_GATE, 26),
+       GATE_SCLK(SCLK_MMC1, "sclk_mmc1", "dout_mmc1", SCLK_GATE, 25),
+       GATE_SCLK(SCLK_MMC0, "sclk_mmc0", "dout_mmc0", SCLK_GATE, 24),
+       GATE_SCLK(SCLK_SPI1_48, "sclk_spi1_48", "clk48m", SCLK_GATE, 23),
+       GATE_SCLK(SCLK_SPI0_48, "sclk_spi0_48", "clk48m", SCLK_GATE, 22),
+       GATE_SCLK(SCLK_SPI1, "sclk_spi1", "dout_spi1", SCLK_GATE, 21),
+       GATE_SCLK(SCLK_SPI0, "sclk_spi0", "dout_spi0", SCLK_GATE, 20),
+       GATE_SCLK(SCLK_DAC27, "sclk_dac27", "mout_dac27", SCLK_GATE, 19),
+       GATE_SCLK(SCLK_TV27, "sclk_tv27", "mout_tv27", SCLK_GATE, 18),
+       GATE_SCLK(SCLK_SCALER27, "sclk_scaler27", "clk27m", SCLK_GATE, 17),
+       GATE_SCLK(SCLK_SCALER, "sclk_scaler", "dout_scaler", SCLK_GATE, 16),
+       GATE_SCLK(SCLK_LCD27, "sclk_lcd27", "clk27m", SCLK_GATE, 15),
+       GATE_SCLK(SCLK_LCD, "sclk_lcd", "dout_lcd", SCLK_GATE, 14),
+       GATE_SCLK(SCLK_POST0_27, "sclk_post0_27", "clk27m", SCLK_GATE, 12),
+       GATE_SCLK(SCLK_POST0, "sclk_post0", "dout_lcd", SCLK_GATE, 10),
+       GATE_SCLK(SCLK_AUDIO1, "sclk_audio1", "dout_audio1", SCLK_GATE, 9),
+       GATE_SCLK(SCLK_AUDIO0, "sclk_audio0", "dout_audio0", SCLK_GATE, 8),
+       GATE_SCLK(SCLK_SECUR, "sclk_secur", "dout_secur", SCLK_GATE, 7),
+       GATE_SCLK(SCLK_IRDA, "sclk_irda", "dout_irda", SCLK_GATE, 6),
+       GATE_SCLK(SCLK_UART, "sclk_uart", "dout_uart", SCLK_GATE, 5),
+       GATE_SCLK(SCLK_MFC, "sclk_mfc", "dout_mfc", SCLK_GATE, 3),
+       GATE_SCLK(SCLK_CAM, "sclk_cam", "dout_cam", SCLK_GATE, 2),
+       GATE_SCLK(SCLK_JPEG, "sclk_jpeg", "dout_jpeg", SCLK_GATE, 1),
+};
+
+/* List of clock gates present on S3C6400. */
+GATE_CLOCKS(s3c6400_gate_clks) __initdata = {
+       GATE_ON(HCLK_DDR0, "hclk_ddr0", "hclk", HCLK_GATE, 23),
+       GATE_SCLK(SCLK_ONENAND, "sclk_onenand", "parent", SCLK_GATE, 4),
+};
+
+/* List of clock gates present on S3C6410. */
+GATE_CLOCKS(s3c6410_gate_clks) __initdata = {
+       GATE_BUS(HCLK_3DSE, "hclk_3dse", "hclk", HCLK_GATE, 31),
+       GATE_ON(HCLK_IROM, "hclk_irom", "hclk", HCLK_GATE, 25),
+       GATE_ON(HCLK_MEM1, "hclk_mem1", "hclk", HCLK_GATE, 22),
+       GATE_ON(HCLK_MEM0, "hclk_mem0", "hclk", HCLK_GATE, 21),
+       GATE_BUS(HCLK_MFC, "hclk_mfc", "hclk", HCLK_GATE, 0),
+       GATE_BUS(PCLK_IIC1, "pclk_iic1", "pclk", PCLK_GATE, 27),
+       GATE_BUS(PCLK_IIS2, "pclk_iis2", "pclk", PCLK_GATE, 26),
+       GATE_SCLK(SCLK_FIMC, "sclk_fimc", "dout_fimc", SCLK_GATE, 13),
+       GATE_SCLK(SCLK_AUDIO2, "sclk_audio2", "dout_audio2", SCLK_GATE, 11),
+       GATE_BUS(MEM0_CFCON, "mem0_cfcon", "hclk_mem0", MEM0_GATE, 5),
+       GATE_BUS(MEM0_ONENAND1, "mem0_onenand1", "hclk_mem0", MEM0_GATE, 4),
+       GATE_BUS(MEM0_ONENAND0, "mem0_onenand0", "hclk_mem0", MEM0_GATE, 3),
+       GATE_BUS(MEM0_NFCON, "mem0_nfcon", "hclk_mem0", MEM0_GATE, 2),
+       GATE_ON(MEM0_SROM, "mem0_srom", "hclk_mem0", MEM0_GATE, 1),
+};
+
+/* List of PLL clocks. */
+static struct samsung_pll_clock s3c64xx_pll_clks[] __initdata = {
+       [apll] = PLL(pll_6552, FOUT_APLL, "fout_apll", "fin_pll",
+                                               APLL_LOCK, APLL_CON, NULL),
+       [mpll] = PLL(pll_6552, FOUT_MPLL, "fout_mpll", "fin_pll",
+                                               MPLL_LOCK, MPLL_CON, NULL),
+       [epll] = PLL(pll_6553, FOUT_EPLL, "fout_epll", "fin_pll",
+                                               EPLL_LOCK, EPLL_CON0, NULL),
+};
+
+/* Aliases for common s3c64xx clocks. */
+static struct samsung_clock_alias s3c64xx_clock_aliases[] = {
+       ALIAS(FOUT_APLL, NULL, "fout_apll"),
+       ALIAS(FOUT_MPLL, NULL, "fout_mpll"),
+       ALIAS(FOUT_EPLL, NULL, "fout_epll"),
+       ALIAS(MOUT_EPLL, NULL, "mout_epll"),
+       ALIAS(DOUT_MPLL, NULL, "dout_mpll"),
+       ALIAS(HCLKX2, NULL, "hclk2"),
+       ALIAS(HCLK, NULL, "hclk"),
+       ALIAS(PCLK, NULL, "pclk"),
+       ALIAS(PCLK, NULL, "clk_uart_baud2"),
+       ALIAS(ARMCLK, NULL, "armclk"),
+       ALIAS(HCLK_UHOST, "s3c2410-ohci", "usb-host"),
+       ALIAS(HCLK_USB, "s3c-hsotg", "otg"),
+       ALIAS(HCLK_HSMMC2, "s3c-sdhci.2", "hsmmc"),
+       ALIAS(HCLK_HSMMC2, "s3c-sdhci.2", "mmc_busclk.0"),
+       ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "hsmmc"),
+       ALIAS(HCLK_HSMMC1, "s3c-sdhci.1", "mmc_busclk.0"),
+       ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "hsmmc"),
+       ALIAS(HCLK_HSMMC0, "s3c-sdhci.0", "mmc_busclk.0"),
+       ALIAS(HCLK_DMA1, NULL, "dma1"),
+       ALIAS(HCLK_DMA0, NULL, "dma0"),
+       ALIAS(HCLK_CAMIF, "s3c-camif", "camif"),
+       ALIAS(HCLK_LCD, "s3c-fb", "lcd"),
+       ALIAS(PCLK_SPI1, "s3c6410-spi.1", "spi"),
+       ALIAS(PCLK_SPI0, "s3c6410-spi.0", "spi"),
+       ALIAS(PCLK_IIC0, "s3c2440-i2c.0", "i2c"),
+       ALIAS(PCLK_IIS1, "samsung-i2s.1", "iis"),
+       ALIAS(PCLK_IIS0, "samsung-i2s.0", "iis"),
+       ALIAS(PCLK_AC97, "samsung-ac97", "ac97"),
+       ALIAS(PCLK_TSADC, "s3c64xx-adc", "adc"),
+       ALIAS(PCLK_KEYPAD, "samsung-keypad", "keypad"),
+       ALIAS(PCLK_PCM1, "samsung-pcm.1", "pcm"),
+       ALIAS(PCLK_PCM0, "samsung-pcm.0", "pcm"),
+       ALIAS(PCLK_PWM, NULL, "timers"),
+       ALIAS(PCLK_RTC, "s3c64xx-rtc", "rtc"),
+       ALIAS(PCLK_WDT, NULL, "watchdog"),
+       ALIAS(PCLK_UART3, "s3c6400-uart.3", "uart"),
+       ALIAS(PCLK_UART2, "s3c6400-uart.2", "uart"),
+       ALIAS(PCLK_UART1, "s3c6400-uart.1", "uart"),
+       ALIAS(PCLK_UART0, "s3c6400-uart.0", "uart"),
+       ALIAS(SCLK_UHOST, "s3c2410-ohci", "usb-bus-host"),
+       ALIAS(SCLK_MMC2, "s3c-sdhci.2", "mmc_busclk.2"),
+       ALIAS(SCLK_MMC1, "s3c-sdhci.1", "mmc_busclk.2"),
+       ALIAS(SCLK_MMC0, "s3c-sdhci.0", "mmc_busclk.2"),
+       ALIAS(SCLK_SPI1, "s3c6410-spi.1", "spi-bus"),
+       ALIAS(SCLK_SPI0, "s3c6410-spi.0", "spi-bus"),
+       ALIAS(SCLK_AUDIO1, "samsung-pcm.1", "audio-bus"),
+       ALIAS(SCLK_AUDIO1, "samsung-i2s.1", "audio-bus"),
+       ALIAS(SCLK_AUDIO0, "samsung-pcm.0", "audio-bus"),
+       ALIAS(SCLK_AUDIO0, "samsung-i2s.0", "audio-bus"),
+       ALIAS(SCLK_UART, NULL, "clk_uart_baud3"),
+       ALIAS(SCLK_CAM, "s3c-camif", "camera"),
+};
+
+/* Aliases for s3c6400-specific clocks. */
+static struct samsung_clock_alias s3c6400_clock_aliases[] = {
+       /* Nothing to place here yet. */
+};
+
+/* Aliases for s3c6410-specific clocks. */
+static struct samsung_clock_alias s3c6410_clock_aliases[] = {
+       ALIAS(PCLK_IIC1, "s3c2440-i2c.1", "i2c"),
+       ALIAS(PCLK_IIS2, "samsung-i2s.2", "iis"),
+       ALIAS(SCLK_FIMC, "s3c-camif", "fimc"),
+       ALIAS(SCLK_AUDIO2, "samsung-i2s.2", "audio-bus"),
+       ALIAS(MEM0_SROM, NULL, "srom"),
+};
+
+static void __init s3c64xx_clk_register_fixed_ext(unsigned long fin_pll_f,
+                                                       unsigned long xusbxti_f)
+{
+       s3c64xx_fixed_rate_ext_clks[0].fixed_rate = fin_pll_f;
+       s3c64xx_fixed_rate_ext_clks[1].fixed_rate = xusbxti_f;
+       samsung_clk_register_fixed_rate(s3c64xx_fixed_rate_ext_clks,
+                               ARRAY_SIZE(s3c64xx_fixed_rate_ext_clks));
+}
+
+/* Register s3c64xx clocks. */
+void __init s3c64xx_clk_init(struct device_node *np, unsigned long xtal_f,
+                            unsigned long xusbxti_f, bool is_s3c6400,
+                            void __iomem *reg_base)
+{
+       unsigned long *soc_regs = NULL;
+       unsigned long nr_soc_regs = 0;
+
+       if (np) {
+               reg_base = of_iomap(np, 0);
+               if (!reg_base)
+                       panic("%s: failed to map registers\n", __func__);
+       }
+
+       if (!is_s3c6400) {
+               soc_regs = s3c6410_clk_regs;
+               nr_soc_regs = ARRAY_SIZE(s3c6410_clk_regs);
+       }
+
+       samsung_clk_init(np, reg_base, NR_CLKS, s3c64xx_clk_regs,
+                       ARRAY_SIZE(s3c64xx_clk_regs), soc_regs, nr_soc_regs);
+
+       /* Register external clocks. */
+       if (!np)
+               s3c64xx_clk_register_fixed_ext(xtal_f, xusbxti_f);
+
+       /* Register PLLs. */
+       samsung_clk_register_pll(s3c64xx_pll_clks,
+                               ARRAY_SIZE(s3c64xx_pll_clks), reg_base);
+
+       /* Register common internal clocks. */
+       samsung_clk_register_fixed_rate(s3c64xx_fixed_rate_clks,
+                                       ARRAY_SIZE(s3c64xx_fixed_rate_clks));
+       samsung_clk_register_mux(s3c64xx_mux_clks,
+                                       ARRAY_SIZE(s3c64xx_mux_clks));
+       samsung_clk_register_div(s3c64xx_div_clks,
+                                       ARRAY_SIZE(s3c64xx_div_clks));
+       samsung_clk_register_gate(s3c64xx_gate_clks,
+                                       ARRAY_SIZE(s3c64xx_gate_clks));
+
+       /* Register SoC-specific clocks. */
+       if (is_s3c6400) {
+               samsung_clk_register_mux(s3c6400_mux_clks,
+                                       ARRAY_SIZE(s3c6400_mux_clks));
+               samsung_clk_register_div(s3c6400_div_clks,
+                                       ARRAY_SIZE(s3c6400_div_clks));
+               samsung_clk_register_gate(s3c6400_gate_clks,
+                                       ARRAY_SIZE(s3c6400_gate_clks));
+               samsung_clk_register_alias(s3c6400_clock_aliases,
+                                       ARRAY_SIZE(s3c6400_clock_aliases));
+       } else {
+               samsung_clk_register_mux(s3c6410_mux_clks,
+                                       ARRAY_SIZE(s3c6410_mux_clks));
+               samsung_clk_register_div(s3c6410_div_clks,
+                                       ARRAY_SIZE(s3c6410_div_clks));
+               samsung_clk_register_gate(s3c6410_gate_clks,
+                                       ARRAY_SIZE(s3c6410_gate_clks));
+               samsung_clk_register_alias(s3c6410_clock_aliases,
+                                       ARRAY_SIZE(s3c6410_clock_aliases));
+       }
+
+       samsung_clk_register_alias(s3c64xx_clock_aliases,
+                                       ARRAY_SIZE(s3c64xx_clock_aliases));
+
+       pr_info("%s clocks: apll = %lu, mpll = %lu\n"
+               "\tepll = %lu, arm_clk = %lu\n",
+               is_s3c6400 ? "S3C6400" : "S3C6410",
+               _get_rate("fout_apll"), _get_rate("fout_mpll"),
+               _get_rate("fout_epll"), _get_rate("armclk"));
+}
+
+static void __init s3c6400_clk_init(struct device_node *np)
+{
+       s3c64xx_clk_init(np, 0, 0, true, NULL);
+}
+CLK_OF_DECLARE(s3c6400_clk, "samsung,s3c6400-clock", s3c6400_clk_init);
+
+static void __init s3c6410_clk_init(struct device_node *np)
+{
+       s3c64xx_clk_init(np, 0, 0, false, NULL);
+}
+CLK_OF_DECLARE(s3c6410_clk, "samsung,s3c6410-clock", s3c6410_clk_init);
index cd3c40ab50f3d57c50c63bc24cf2f89f7555d819..f503f32e2f80b2832519927894e8c84ba0d81e60 100644 (file)
@@ -307,14 +307,12 @@ void __init samsung_clk_of_register_fixed_ext(
 unsigned long _get_rate(const char *clk_name)
 {
        struct clk *clk;
-       unsigned long rate;
 
-       clk = clk_get(NULL, clk_name);
-       if (IS_ERR(clk)) {
+       clk = __clk_lookup(clk_name);
+       if (!clk) {
                pr_err("%s: could not find clock %s\n", __func__, clk_name);
                return 0;
        }
-       rate = clk_get_rate(clk);
-       clk_put(clk);
-       return rate;
+
+       return clk_get_rate(clk);
 }
index 2f7dba20ced8b9145f261b817be65387f3048662..31b4174e7a5bfa1b47fd2d9e0e5da6240a305acf 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include "clk-pll.h"
 
 /**
  * struct samsung_clock_alias: information about mux clock
@@ -39,6 +40,8 @@ struct samsung_clock_alias {
                .alias          = a,                            \
        }
 
+#define MHZ (1000 * 1000)
+
 /**
  * struct samsung_fixed_rate_clock: information about fixed-rate clock
  * @id: platform specific id of the clock.
@@ -127,7 +130,7 @@ struct samsung_mux_clock {
                .name           = cname,                        \
                .parent_names   = pnames,                       \
                .num_parents    = ARRAY_SIZE(pnames),           \
-               .flags          = f,                            \
+               .flags          = (f) | CLK_SET_RATE_NO_REPARENT, \
                .offset         = o,                            \
                .shift          = s,                            \
                .width          = w,                            \
@@ -261,6 +264,54 @@ struct samsung_clk_reg_dump {
        u32     value;
 };
 
+/**
+ * struct samsung_pll_clock: information about pll clock
+ * @id: platform specific id of the clock.
+ * @dev_name: name of the device to which this clock belongs.
+ * @name: name of this pll clock.
+ * @parent_name: name of the parent clock.
+ * @flags: optional flags for basic clock.
+ * @con_offset: offset of the register for configuring the PLL.
+ * @lock_offset: offset of the register for locking the PLL.
+ * @type: Type of PLL to be registered.
+ * @alias: optional clock alias name to be assigned to this clock.
+ */
+struct samsung_pll_clock {
+       unsigned int            id;
+       const char              *dev_name;
+       const char              *name;
+       const char              *parent_name;
+       unsigned long           flags;
+       int                     con_offset;
+       int                     lock_offset;
+       enum samsung_pll_type   type;
+       const struct samsung_pll_rate_table *rate_table;
+       const char              *alias;
+};
+
+#define __PLL(_typ, _id, _dname, _name, _pname, _flags, _lock, _con,   \
+               _rtable, _alias)                                        \
+       {                                                               \
+               .id             = _id,                                  \
+               .type           = _typ,                                 \
+               .dev_name       = _dname,                               \
+               .name           = _name,                                \
+               .parent_name    = _pname,                               \
+               .flags          = CLK_GET_RATE_NOCACHE,                 \
+               .con_offset     = _con,                                 \
+               .lock_offset    = _lock,                                \
+               .rate_table     = _rtable,                              \
+               .alias          = _alias,                               \
+       }
+
+#define PLL(_typ, _id, _name, _pname, _lock, _con, _rtable)    \
+       __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE,     \
+               _lock, _con, _rtable, _name)
+
+#define PLL_A(_typ, _id, _name, _pname, _lock, _con, _alias, _rtable) \
+       __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE,     \
+               _lock, _con, _rtable, _alias)
+
 extern void __init samsung_clk_init(struct device_node *np, void __iomem *base,
                unsigned long nr_clks, unsigned long *rdump,
                unsigned long nr_rdump, unsigned long *soc_rdump,
@@ -284,6 +335,8 @@ extern void __init samsung_clk_register_div(struct samsung_div_clock *clk_list,
                unsigned int nr_clk);
 extern void __init samsung_clk_register_gate(
                struct samsung_gate_clock *clk_list, unsigned int nr_clk);
+extern void __init samsung_clk_register_pll(struct samsung_pll_clock *pll_list,
+               unsigned int nr_clk, void __iomem *base);
 
 extern unsigned long _get_rate(const char *clk_name);
 
index aedbbe12f321bb448b3e1336ead9b74e6ba27501..65894f7687ed33cf4ff1a52bfb6da59680e35db0 100644 (file)
@@ -416,9 +416,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        /* clock derived from 24 or 25 MHz osc clk */
        /* vco-pll */
        clk = clk_register_mux(NULL, "vco1_mclk", vco_parents,
-                       ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
-                       SPEAR1310_PLL1_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PLL_CFG, SPEAR1310_PLL1_CLK_SHIFT,
+                       SPEAR1310_PLL_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "vco1_mclk", NULL);
        clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk",
                        0, SPEAR1310_PLL1_CTR, SPEAR1310_PLL1_FRQ, pll_rtbl,
@@ -427,9 +427,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk1, "pll1_clk", NULL);
 
        clk = clk_register_mux(NULL, "vco2_mclk", vco_parents,
-                       ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
-                       SPEAR1310_PLL2_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PLL_CFG, SPEAR1310_PLL2_CLK_SHIFT,
+                       SPEAR1310_PLL_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "vco2_mclk", NULL);
        clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk",
                        0, SPEAR1310_PLL2_CTR, SPEAR1310_PLL2_FRQ, pll_rtbl,
@@ -438,9 +438,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk1, "pll2_clk", NULL);
 
        clk = clk_register_mux(NULL, "vco3_mclk", vco_parents,
-                       ARRAY_SIZE(vco_parents), 0, SPEAR1310_PLL_CFG,
-                       SPEAR1310_PLL3_CLK_SHIFT, SPEAR1310_PLL_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PLL_CFG, SPEAR1310_PLL3_CLK_SHIFT,
+                       SPEAR1310_PLL_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "vco3_mclk", NULL);
        clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk",
                        0, SPEAR1310_PLL3_CTR, SPEAR1310_PLL3_FRQ, pll_rtbl,
@@ -515,9 +515,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
 
        /* gpt clocks */
        clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
-                       SPEAR1310_GPT0_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT0_CLK_SHIFT,
+                       SPEAR1310_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt0_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT0_CLK_ENB, 0,
@@ -525,9 +525,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "gpt0");
 
        clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
-                       SPEAR1310_GPT1_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT1_CLK_SHIFT,
+                       SPEAR1310_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt1_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
                        SPEAR1310_PERIP1_CLK_ENB, SPEAR1310_GPT1_CLK_ENB, 0,
@@ -535,9 +535,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "gpt1");
 
        clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
-                       SPEAR1310_GPT2_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT2_CLK_SHIFT,
+                       SPEAR1310_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt2_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
                        SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT2_CLK_ENB, 0,
@@ -545,9 +545,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "gpt2");
 
        clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1310_PERIP_CLK_CFG,
-                       SPEAR1310_GPT3_CLK_SHIFT, SPEAR1310_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GPT3_CLK_SHIFT,
+                       SPEAR1310_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt3_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
                        SPEAR1310_PERIP2_CLK_ENB, SPEAR1310_GPT3_CLK_ENB, 0,
@@ -562,7 +562,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
-                       ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uart0_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1310_PERIP_CLK_CFG, SPEAR1310_UART_CLK_SHIFT,
                        SPEAR1310_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart0_mclk", NULL);
@@ -602,7 +603,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
-                       ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(c3_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1310_PERIP_CLK_CFG, SPEAR1310_C3_CLK_SHIFT,
                        SPEAR1310_C3_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "c3_mclk", NULL);
@@ -614,8 +616,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
 
        /* gmac */
        clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
-                       ARRAY_SIZE(gmac_phy_input_parents), 0,
-                       SPEAR1310_GMAC_CLK_CFG,
+                       ARRAY_SIZE(gmac_phy_input_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1310_GMAC_CLK_CFG,
                        SPEAR1310_GMAC_PHY_INPUT_CLK_SHIFT,
                        SPEAR1310_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "phy_input_mclk", NULL);
@@ -627,15 +629,16 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk1, "phy_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents,
-                       ARRAY_SIZE(gmac_phy_parents), 0,
+                       ARRAY_SIZE(gmac_phy_parents), CLK_SET_RATE_NO_REPARENT,
                        SPEAR1310_PERIP_CLK_CFG, SPEAR1310_GMAC_PHY_CLK_SHIFT,
                        SPEAR1310_GMAC_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "stmmacphy.0", NULL);
 
        /* clcd */
        clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
-                       ARRAY_SIZE(clcd_synth_parents), 0,
-                       SPEAR1310_CLCD_CLK_SYNT, SPEAR1310_CLCD_SYNT_CLK_SHIFT,
+                       ARRAY_SIZE(clcd_synth_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1310_CLCD_CLK_SYNT,
+                       SPEAR1310_CLCD_SYNT_CLK_SHIFT,
                        SPEAR1310_CLCD_SYNT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "clcd_syn_mclk", NULL);
 
@@ -645,7 +648,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, "clcd_syn_clk", NULL);
 
        clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
-                       ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(clcd_pixel_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1310_PERIP_CLK_CFG, SPEAR1310_CLCD_CLK_SHIFT,
                        SPEAR1310_CLCD_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
@@ -657,9 +661,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
 
        /* i2s */
        clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
-                       ARRAY_SIZE(i2s_src_parents), 0, SPEAR1310_I2S_CLK_CFG,
-                       SPEAR1310_I2S_SRC_CLK_SHIFT, SPEAR1310_I2S_SRC_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(i2s_src_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_SRC_CLK_SHIFT,
+                       SPEAR1310_I2S_SRC_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2s_src_mclk", NULL);
 
        clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk", 0,
@@ -668,7 +672,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
 
        clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
-                       ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(i2s_ref_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1310_I2S_CLK_CFG, SPEAR1310_I2S_REF_SHIFT,
                        SPEAR1310_I2S_REF_SEL_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
@@ -806,13 +811,15 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
 
        /* RAS clks */
        clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents,
-                       ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1310_PLL_CFG,
+                       ARRAY_SIZE(gen_synth0_1_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1310_PLL_CFG,
                        SPEAR1310_RAS_SYNT0_1_CLK_SHIFT,
                        SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gen_syn0_1_clk", NULL);
 
        clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
-                       ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1310_PLL_CFG,
+                       ARRAY_SIZE(gen_synth2_3_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1310_PLL_CFG,
                        SPEAR1310_RAS_SYNT2_3_CLK_SHIFT,
                        SPEAR1310_RAS_SYNT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gen_syn2_3_clk", NULL);
@@ -929,8 +936,8 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
 
        clk = clk_register_mux(NULL, "smii_rgmii_phy_mclk",
                        smii_rgmii_phy_parents,
-                       ARRAY_SIZE(smii_rgmii_phy_parents), 0,
-                       SPEAR1310_RAS_CTRL_REG1,
+                       ARRAY_SIZE(smii_rgmii_phy_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1310_RAS_CTRL_REG1,
                        SPEAR1310_SMII_RGMII_PHY_CLK_SHIFT,
                        SPEAR1310_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "stmmacphy.1", NULL);
@@ -938,15 +945,15 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, "stmmacphy.4", NULL);
 
        clk = clk_register_mux(NULL, "rmii_phy_mclk", rmii_phy_parents,
-                       ARRAY_SIZE(rmii_phy_parents), 0,
+                       ARRAY_SIZE(rmii_phy_parents), CLK_SET_RATE_NO_REPARENT,
                        SPEAR1310_RAS_CTRL_REG1, SPEAR1310_RMII_PHY_CLK_SHIFT,
                        SPEAR1310_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "stmmacphy.3", NULL);
 
        clk = clk_register_mux(NULL, "uart1_mclk", uart_parents,
-                       ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_UART1_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART1_CLK_SHIFT,
+                       SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart1_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0,
@@ -955,9 +962,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5c800000.serial");
 
        clk = clk_register_mux(NULL, "uart2_mclk", uart_parents,
-                       ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_UART2_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART2_CLK_SHIFT,
+                       SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart2_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart2_clk", "uart2_mclk", 0,
@@ -966,9 +973,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5c900000.serial");
 
        clk = clk_register_mux(NULL, "uart3_mclk", uart_parents,
-                       ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_UART3_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART3_CLK_SHIFT,
+                       SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart3_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart3_clk", "uart3_mclk", 0,
@@ -977,9 +984,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5ca00000.serial");
 
        clk = clk_register_mux(NULL, "uart4_mclk", uart_parents,
-                       ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_UART4_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART4_CLK_SHIFT,
+                       SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart4_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart4_clk", "uart4_mclk", 0,
@@ -988,9 +995,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5cb00000.serial");
 
        clk = clk_register_mux(NULL, "uart5_mclk", uart_parents,
-                       ARRAY_SIZE(uart_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_UART5_CLK_SHIFT, SPEAR1310_RAS_UART_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_UART5_CLK_SHIFT,
+                       SPEAR1310_RAS_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart5_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart5_clk", "uart5_mclk", 0,
@@ -999,9 +1006,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5cc00000.serial");
 
        clk = clk_register_mux(NULL, "i2c1_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C1_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C1_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c1_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c1_clk", "i2c1_mclk", 0,
@@ -1010,9 +1017,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5cd00000.i2c");
 
        clk = clk_register_mux(NULL, "i2c2_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C2_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C2_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c2_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c2_clk", "i2c2_mclk", 0,
@@ -1021,9 +1028,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5ce00000.i2c");
 
        clk = clk_register_mux(NULL, "i2c3_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C3_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C3_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c3_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c3_clk", "i2c3_mclk", 0,
@@ -1032,9 +1039,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5cf00000.i2c");
 
        clk = clk_register_mux(NULL, "i2c4_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C4_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C4_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c4_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c4_clk", "i2c4_mclk", 0,
@@ -1043,9 +1050,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5d000000.i2c");
 
        clk = clk_register_mux(NULL, "i2c5_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C5_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C5_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c5_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c5_clk", "i2c5_mclk", 0,
@@ -1054,9 +1061,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5d100000.i2c");
 
        clk = clk_register_mux(NULL, "i2c6_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C6_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C6_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c6_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c6_clk", "i2c6_mclk", 0,
@@ -1065,9 +1072,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5d200000.i2c");
 
        clk = clk_register_mux(NULL, "i2c7_mclk", i2c_parents,
-                       ARRAY_SIZE(i2c_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_I2C7_CLK_SHIFT, SPEAR1310_I2C_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(i2c_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_I2C7_CLK_SHIFT,
+                       SPEAR1310_I2C_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2c7_mclk", NULL);
 
        clk = clk_register_gate(NULL, "i2c7_clk", "i2c7_mclk", 0,
@@ -1076,9 +1083,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5d300000.i2c");
 
        clk = clk_register_mux(NULL, "ssp1_mclk", ssp1_parents,
-                       ARRAY_SIZE(ssp1_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_SSP1_CLK_SHIFT, SPEAR1310_SSP1_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(ssp1_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_SSP1_CLK_SHIFT,
+                       SPEAR1310_SSP1_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ssp1_mclk", NULL);
 
        clk = clk_register_gate(NULL, "ssp1_clk", "ssp1_mclk", 0,
@@ -1087,9 +1094,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "5d400000.spi");
 
        clk = clk_register_mux(NULL, "pci_mclk", pci_parents,
-                       ARRAY_SIZE(pci_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_PCI_CLK_SHIFT, SPEAR1310_PCI_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(pci_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_PCI_CLK_SHIFT,
+                       SPEAR1310_PCI_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "pci_mclk", NULL);
 
        clk = clk_register_gate(NULL, "pci_clk", "pci_mclk", 0,
@@ -1098,9 +1105,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "pci");
 
        clk = clk_register_mux(NULL, "tdm1_mclk", tdm_parents,
-                       ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_TDM1_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(tdm_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_TDM1_CLK_SHIFT,
+                       SPEAR1310_TDM_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "tdm1_mclk", NULL);
 
        clk = clk_register_gate(NULL, "tdm1_clk", "tdm1_mclk", 0,
@@ -1109,9 +1116,9 @@ void __init spear1310_clk_init(void __iomem *misc_base, void __iomem *ras_base)
        clk_register_clkdev(clk, NULL, "tdm_hdlc.0");
 
        clk = clk_register_mux(NULL, "tdm2_mclk", tdm_parents,
-                       ARRAY_SIZE(tdm_parents), 0, SPEAR1310_RAS_CTRL_REG0,
-                       SPEAR1310_TDM2_CLK_SHIFT, SPEAR1310_TDM_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(tdm_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1310_RAS_CTRL_REG0, SPEAR1310_TDM2_CLK_SHIFT,
+                       SPEAR1310_TDM_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "tdm2_mclk", NULL);
 
        clk = clk_register_gate(NULL, "tdm2_clk", "tdm2_mclk", 0,
index 9d0b3949db30da927ce37d45aa4ca4eafe9c4cfe..fe835c1845fe9d32d1ddfbf46f331134e696322c 100644 (file)
@@ -473,9 +473,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        /* clock derived from 24 or 25 MHz osc clk */
        /* vco-pll */
        clk = clk_register_mux(NULL, "vco1_mclk", vco_parents,
-                       ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
-                       SPEAR1340_PLL1_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PLL_CFG, SPEAR1340_PLL1_CLK_SHIFT,
+                       SPEAR1340_PLL_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "vco1_mclk", NULL);
        clk = clk_register_vco_pll("vco1_clk", "pll1_clk", NULL, "vco1_mclk", 0,
                        SPEAR1340_PLL1_CTR, SPEAR1340_PLL1_FRQ, pll_rtbl,
@@ -484,9 +484,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "pll1_clk", NULL);
 
        clk = clk_register_mux(NULL, "vco2_mclk", vco_parents,
-                       ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
-                       SPEAR1340_PLL2_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PLL_CFG, SPEAR1340_PLL2_CLK_SHIFT,
+                       SPEAR1340_PLL_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "vco2_mclk", NULL);
        clk = clk_register_vco_pll("vco2_clk", "pll2_clk", NULL, "vco2_mclk", 0,
                        SPEAR1340_PLL2_CTR, SPEAR1340_PLL2_FRQ, pll_rtbl,
@@ -495,9 +495,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "pll2_clk", NULL);
 
        clk = clk_register_mux(NULL, "vco3_mclk", vco_parents,
-                       ARRAY_SIZE(vco_parents), 0, SPEAR1340_PLL_CFG,
-                       SPEAR1340_PLL3_CLK_SHIFT, SPEAR1340_PLL_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(vco_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PLL_CFG, SPEAR1340_PLL3_CLK_SHIFT,
+                       SPEAR1340_PLL_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "vco3_mclk", NULL);
        clk = clk_register_vco_pll("vco3_clk", "pll3_clk", NULL, "vco3_mclk", 0,
                        SPEAR1340_PLL3_CTR, SPEAR1340_PLL3_FRQ, pll_rtbl,
@@ -561,8 +561,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "amba_syn_clk", NULL);
 
        clk = clk_register_mux(NULL, "sys_mclk", sys_parents,
-                       ARRAY_SIZE(sys_parents), 0, SPEAR1340_SYS_CLK_CTRL,
-                       SPEAR1340_SCLK_SRC_SEL_SHIFT,
+                       ARRAY_SIZE(sys_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_SYS_CLK_CTRL, SPEAR1340_SCLK_SRC_SEL_SHIFT,
                        SPEAR1340_SCLK_SRC_SEL_MASK, 0, &_lock);
        clk_register_clkdev(clk, "sys_mclk", NULL);
 
@@ -583,8 +583,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, NULL, "smp_twd");
 
        clk = clk_register_mux(NULL, "ahb_clk", ahb_parents,
-                       ARRAY_SIZE(ahb_parents), 0, SPEAR1340_SYS_CLK_CTRL,
-                       SPEAR1340_HCLK_SRC_SEL_SHIFT,
+                       ARRAY_SIZE(ahb_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_SYS_CLK_CTRL, SPEAR1340_HCLK_SRC_SEL_SHIFT,
                        SPEAR1340_HCLK_SRC_SEL_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ahb_clk", NULL);
 
@@ -594,9 +594,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
 
        /* gpt clocks */
        clk = clk_register_mux(NULL, "gpt0_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
-                       SPEAR1340_GPT0_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT0_CLK_SHIFT,
+                       SPEAR1340_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt0_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt0_clk", "gpt0_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT0_CLK_ENB, 0,
@@ -604,9 +604,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, NULL, "gpt0");
 
        clk = clk_register_mux(NULL, "gpt1_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
-                       SPEAR1340_GPT1_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT1_CLK_SHIFT,
+                       SPEAR1340_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt1_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
                        SPEAR1340_PERIP1_CLK_ENB, SPEAR1340_GPT1_CLK_ENB, 0,
@@ -614,9 +614,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, NULL, "gpt1");
 
        clk = clk_register_mux(NULL, "gpt2_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
-                       SPEAR1340_GPT2_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT2_CLK_SHIFT,
+                       SPEAR1340_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt2_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT2_CLK_ENB, 0,
@@ -624,9 +624,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, NULL, "gpt2");
 
        clk = clk_register_mux(NULL, "gpt3_mclk", gpt_parents,
-                       ARRAY_SIZE(gpt_parents), 0, SPEAR1340_PERIP_CLK_CFG,
-                       SPEAR1340_GPT3_CLK_SHIFT, SPEAR1340_GPT_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gpt_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GPT3_CLK_SHIFT,
+                       SPEAR1340_GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt3_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
                        SPEAR1340_PERIP2_CLK_ENB, SPEAR1340_GPT3_CLK_ENB, 0,
@@ -641,7 +641,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "uart0_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
-                       ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uart0_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART0_CLK_SHIFT,
                        SPEAR1340_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart0_mclk", NULL);
@@ -658,9 +659,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "uart1_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "uart1_mclk", uart1_parents,
-                       ARRAY_SIZE(uart1_parents), 0, SPEAR1340_PERIP_CLK_CFG,
-                       SPEAR1340_UART1_CLK_SHIFT, SPEAR1340_UART_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(uart1_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_PERIP_CLK_CFG, SPEAR1340_UART1_CLK_SHIFT,
+                       SPEAR1340_UART_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "uart1_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart1_clk", "uart1_mclk", 0,
@@ -698,7 +699,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "c3_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "c3_mclk", c3_parents,
-                       ARRAY_SIZE(c3_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(c3_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_C3_CLK_SHIFT,
                        SPEAR1340_C3_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "c3_mclk", NULL);
@@ -710,8 +712,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
 
        /* gmac */
        clk = clk_register_mux(NULL, "phy_input_mclk", gmac_phy_input_parents,
-                       ARRAY_SIZE(gmac_phy_input_parents), 0,
-                       SPEAR1340_GMAC_CLK_CFG,
+                       ARRAY_SIZE(gmac_phy_input_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1340_GMAC_CLK_CFG,
                        SPEAR1340_GMAC_PHY_INPUT_CLK_SHIFT,
                        SPEAR1340_GMAC_PHY_INPUT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "phy_input_mclk", NULL);
@@ -723,15 +725,16 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "phy_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "phy_mclk", gmac_phy_parents,
-                       ARRAY_SIZE(gmac_phy_parents), 0,
+                       ARRAY_SIZE(gmac_phy_parents), CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_GMAC_PHY_CLK_SHIFT,
                        SPEAR1340_GMAC_PHY_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "stmmacphy.0", NULL);
 
        /* clcd */
        clk = clk_register_mux(NULL, "clcd_syn_mclk", clcd_synth_parents,
-                       ARRAY_SIZE(clcd_synth_parents), 0,
-                       SPEAR1340_CLCD_CLK_SYNT, SPEAR1340_CLCD_SYNT_CLK_SHIFT,
+                       ARRAY_SIZE(clcd_synth_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1340_CLCD_CLK_SYNT,
+                       SPEAR1340_CLCD_SYNT_CLK_SHIFT,
                        SPEAR1340_CLCD_SYNT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "clcd_syn_mclk", NULL);
 
@@ -741,7 +744,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "clcd_syn_clk", NULL);
 
        clk = clk_register_mux(NULL, "clcd_pixel_mclk", clcd_pixel_parents,
-                       ARRAY_SIZE(clcd_pixel_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(clcd_pixel_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_CLCD_CLK_SHIFT,
                        SPEAR1340_CLCD_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "clcd_pixel_mclk", NULL);
@@ -753,9 +757,9 @@ void __init spear1340_clk_init(void __iomem *misc_base)
 
        /* i2s */
        clk = clk_register_mux(NULL, "i2s_src_mclk", i2s_src_parents,
-                       ARRAY_SIZE(i2s_src_parents), 0, SPEAR1340_I2S_CLK_CFG,
-                       SPEAR1340_I2S_SRC_CLK_SHIFT, SPEAR1340_I2S_SRC_CLK_MASK,
-                       0, &_lock);
+                       ARRAY_SIZE(i2s_src_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_SRC_CLK_SHIFT,
+                       SPEAR1340_I2S_SRC_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2s_src_mclk", NULL);
 
        clk = clk_register_aux("i2s_prs1_clk", NULL, "i2s_src_mclk",
@@ -765,7 +769,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "i2s_prs1_clk", NULL);
 
        clk = clk_register_mux(NULL, "i2s_ref_mclk", i2s_ref_parents,
-                       ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(i2s_ref_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_I2S_CLK_CFG, SPEAR1340_I2S_REF_SHIFT,
                        SPEAR1340_I2S_REF_SEL_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2s_ref_mclk", NULL);
@@ -891,13 +896,15 @@ void __init spear1340_clk_init(void __iomem *misc_base)
 
        /* RAS clks */
        clk = clk_register_mux(NULL, "gen_syn0_1_mclk", gen_synth0_1_parents,
-                       ARRAY_SIZE(gen_synth0_1_parents), 0, SPEAR1340_PLL_CFG,
+                       ARRAY_SIZE(gen_synth0_1_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1340_PLL_CFG,
                        SPEAR1340_GEN_SYNT0_1_CLK_SHIFT,
                        SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gen_syn0_1_mclk", NULL);
 
        clk = clk_register_mux(NULL, "gen_syn2_3_mclk", gen_synth2_3_parents,
-                       ARRAY_SIZE(gen_synth2_3_parents), 0, SPEAR1340_PLL_CFG,
+                       ARRAY_SIZE(gen_synth2_3_parents),
+                       CLK_SET_RATE_NO_REPARENT, SPEAR1340_PLL_CFG,
                        SPEAR1340_GEN_SYNT2_3_CLK_SHIFT,
                        SPEAR1340_GEN_SYNT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gen_syn2_3_mclk", NULL);
@@ -938,7 +945,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, NULL, "spear_cec.1");
 
        clk = clk_register_mux(NULL, "spdif_out_mclk", spdif_out_parents,
-                       ARRAY_SIZE(spdif_out_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(spdif_out_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_OUT_CLK_SHIFT,
                        SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "spdif_out_mclk", NULL);
@@ -949,7 +957,8 @@ void __init spear1340_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, NULL, "d0000000.spdif-out");
 
        clk = clk_register_mux(NULL, "spdif_in_mclk", spdif_in_parents,
-                       ARRAY_SIZE(spdif_in_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(spdif_in_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR1340_PERIP_CLK_CFG, SPEAR1340_SPDIF_IN_CLK_SHIFT,
                        SPEAR1340_SPDIF_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "spdif_in_mclk", NULL);
index 080c3c5e33f67823c28b79ad1c0fa4707afeaaee..c2d204315546b5398e79b698615645c9568e445e 100644 (file)
@@ -294,7 +294,8 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
        clk_register_clkdev(clk, NULL, "a9400000.i2s");
 
        clk = clk_register_mux(NULL, "i2s_ref_clk", i2s_ref_parents,
-                       ARRAY_SIZE(i2s_ref_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(i2s_ref_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_CONTROL_REG, I2S_REF_PCLK_SHIFT,
                        I2S_REF_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "i2s_ref_clk", NULL);
@@ -313,57 +314,66 @@ static void __init spear320_clk_init(void __iomem *soc_config_base)
        clk_register_clkdev(clk, "hclk", "ab000000.eth");
 
        clk = clk_register_mux(NULL, "rs485_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_EXT_CTRL_REG, SPEAR320_RS485_PCLK_SHIFT,
                        SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "a9300000.serial");
 
        clk = clk_register_mux(NULL, "sdhci_clk", sdhci_parents,
-                       ARRAY_SIZE(sdhci_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(sdhci_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_CONTROL_REG, SDHCI_PCLK_SHIFT, SDHCI_PCLK_MASK,
                        0, &_lock);
        clk_register_clkdev(clk, NULL, "70000000.sdhci");
 
        clk = clk_register_mux(NULL, "smii_pclk", smii0_parents,
-                       ARRAY_SIZE(smii0_parents), 0, SPEAR320_CONTROL_REG,
-                       SMII_PCLK_SHIFT, SMII_PCLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(smii0_parents), CLK_SET_RATE_NO_REPARENT,
+                       SPEAR320_CONTROL_REG, SMII_PCLK_SHIFT, SMII_PCLK_MASK,
+                       0, &_lock);
        clk_register_clkdev(clk, NULL, "smii_pclk");
 
        clk = clk_register_fixed_factor(NULL, "smii_clk", "smii_pclk", 0, 1, 1);
        clk_register_clkdev(clk, NULL, "smii");
 
        clk = clk_register_mux(NULL, "uart1_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_CONTROL_REG, UART1_PCLK_SHIFT, UART1_PCLK_MASK,
                        0, &_lock);
        clk_register_clkdev(clk, NULL, "a3000000.serial");
 
        clk = clk_register_mux(NULL, "uart2_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_EXT_CTRL_REG, SPEAR320_UART2_PCLK_SHIFT,
                        SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "a4000000.serial");
 
        clk = clk_register_mux(NULL, "uart3_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_EXT_CTRL_REG, SPEAR320_UART3_PCLK_SHIFT,
                        SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "a9100000.serial");
 
        clk = clk_register_mux(NULL, "uart4_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_EXT_CTRL_REG, SPEAR320_UART4_PCLK_SHIFT,
                        SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "a9200000.serial");
 
        clk = clk_register_mux(NULL, "uart5_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_EXT_CTRL_REG, SPEAR320_UART5_PCLK_SHIFT,
                        SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "60000000.serial");
 
        clk = clk_register_mux(NULL, "uart6_clk", uartx_parents,
-                       ARRAY_SIZE(uartx_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uartx_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        SPEAR320_EXT_CTRL_REG, SPEAR320_UART6_PCLK_SHIFT,
                        SPEAR320_UARTX_PCLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "60100000.serial");
@@ -427,7 +437,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
        clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "uart0_mclk", uart0_parents,
-                       ARRAY_SIZE(uart0_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(uart0_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0,
                        &_lock);
        clk_register_clkdev(clk, "uart0_mclk", NULL);
@@ -444,7 +455,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
        clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
-                       ARRAY_SIZE(firda_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(firda_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0,
                        &_lock);
        clk_register_clkdev(clk, "firda_mclk", NULL);
@@ -458,14 +470,16 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
        clk_register_gpt("gpt0_syn_clk", "pll1_clk", 0, PRSC0_CLK_CFG, gpt_rtbl,
                        ARRAY_SIZE(gpt_rtbl), &_lock);
        clk = clk_register_mux(NULL, "gpt0_clk", gpt0_parents,
-                       ARRAY_SIZE(gpt0_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(gpt0_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt0");
 
        clk_register_gpt("gpt1_syn_clk", "pll1_clk", 0, PRSC1_CLK_CFG, gpt_rtbl,
                        ARRAY_SIZE(gpt_rtbl), &_lock);
        clk = clk_register_mux(NULL, "gpt1_mclk", gpt1_parents,
-                       ARRAY_SIZE(gpt1_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(gpt1_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt1_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk",
@@ -476,7 +490,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
        clk_register_gpt("gpt2_syn_clk", "pll1_clk", 0, PRSC2_CLK_CFG, gpt_rtbl,
                        ARRAY_SIZE(gpt_rtbl), &_lock);
        clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
-                       ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_PARENT,
+                       ARRAY_SIZE(gpt2_parents),
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
                        PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt2_mclk", NULL);
        clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk",
@@ -498,9 +513,9 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
        clk_register_clkdev(clk1, "gen1_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "gen2_3_par_clk", gen2_3_parents,
-                       ARRAY_SIZE(gen2_3_parents), 0, CORE_CLK_CFG,
-                       GEN_SYNTH2_3_CLK_SHIFT, GEN_SYNTH2_3_CLK_MASK, 0,
-                       &_lock);
+                       ARRAY_SIZE(gen2_3_parents), CLK_SET_RATE_NO_REPARENT,
+                       CORE_CLK_CFG, GEN_SYNTH2_3_CLK_SHIFT,
+                       GEN_SYNTH2_3_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gen2_3_par_clk", NULL);
 
        clk = clk_register_aux("gen2_syn_clk", "gen2_syn_gclk",
@@ -540,8 +555,8 @@ void __init spear3xx_clk_init(void __iomem *misc_base, void __iomem *soc_config_
        clk_register_clkdev(clk, "ahbmult2_clk", NULL);
 
        clk = clk_register_mux(NULL, "ddr_clk", ddr_parents,
-                       ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT,
-                       MCTR_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(ddr_parents), CLK_SET_RATE_NO_REPARENT,
+                       PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ddr_clk", NULL);
 
        clk = clk_register_divider(NULL, "apb_clk", "ahb_clk",
index 9406f2426d64723f30764442eef1bb67ecac280a..4f649c9cb094e2c9019cc5528d64819a632e0489 100644 (file)
@@ -169,8 +169,9 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "uart_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "uart_mclk", uart_parents,
-                       ARRAY_SIZE(uart_parents), 0, PERIP_CLK_CFG,
-                       UART_CLK_SHIFT, UART_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(uart_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, UART_CLK_SHIFT, UART_CLK_MASK, 0,
+                       &_lock);
        clk_register_clkdev(clk, "uart_mclk", NULL);
 
        clk = clk_register_gate(NULL, "uart0", "uart_mclk", 0, PERIP1_CLK_ENB,
@@ -188,8 +189,9 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "firda_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "firda_mclk", firda_parents,
-                       ARRAY_SIZE(firda_parents), 0, PERIP_CLK_CFG,
-                       FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(firda_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, FIRDA_CLK_SHIFT, FIRDA_CLK_MASK, 0,
+                       &_lock);
        clk_register_clkdev(clk, "firda_mclk", NULL);
 
        clk = clk_register_gate(NULL, "firda_clk", "firda_mclk", 0,
@@ -203,8 +205,9 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk1, "clcd_syn_gclk", NULL);
 
        clk = clk_register_mux(NULL, "clcd_mclk", clcd_parents,
-                       ARRAY_SIZE(clcd_parents), 0, PERIP_CLK_CFG,
-                       CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(clcd_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, CLCD_CLK_SHIFT, CLCD_CLK_MASK, 0,
+                       &_lock);
        clk_register_clkdev(clk, "clcd_mclk", NULL);
 
        clk = clk_register_gate(NULL, "clcd_clk", "clcd_mclk", 0,
@@ -217,13 +220,13 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "gpt0_1_syn_clk", NULL);
 
        clk = clk_register_mux(NULL, "gpt0_mclk", gpt0_1_parents,
-                       ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG,
-                       GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(gpt0_1_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, GPT0_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, NULL, "gpt0");
 
        clk = clk_register_mux(NULL, "gpt1_mclk", gpt0_1_parents,
-                       ARRAY_SIZE(gpt0_1_parents), 0, PERIP_CLK_CFG,
-                       GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(gpt0_1_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, GPT1_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt1_mclk", NULL);
 
        clk = clk_register_gate(NULL, "gpt1_clk", "gpt1_mclk", 0,
@@ -235,8 +238,8 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "gpt2_syn_clk", NULL);
 
        clk = clk_register_mux(NULL, "gpt2_mclk", gpt2_parents,
-                       ARRAY_SIZE(gpt2_parents), 0, PERIP_CLK_CFG,
-                       GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(gpt2_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, GPT2_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt2_mclk", NULL);
 
        clk = clk_register_gate(NULL, "gpt2_clk", "gpt2_mclk", 0,
@@ -248,8 +251,8 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "gpt3_syn_clk", NULL);
 
        clk = clk_register_mux(NULL, "gpt3_mclk", gpt3_parents,
-                       ARRAY_SIZE(gpt3_parents), 0, PERIP_CLK_CFG,
-                       GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(gpt3_parents), CLK_SET_RATE_NO_REPARENT,
+                       PERIP_CLK_CFG, GPT3_CLK_SHIFT, GPT_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "gpt3_mclk", NULL);
 
        clk = clk_register_gate(NULL, "gpt3_clk", "gpt3_mclk", 0,
@@ -277,8 +280,8 @@ void __init spear6xx_clk_init(void __iomem *misc_base)
        clk_register_clkdev(clk, "ahbmult2_clk", NULL);
 
        clk = clk_register_mux(NULL, "ddr_clk", ddr_parents,
-                       ARRAY_SIZE(ddr_parents), 0, PLL_CLK_CFG, MCTR_CLK_SHIFT,
-                       MCTR_CLK_MASK, 0, &_lock);
+                       ARRAY_SIZE(ddr_parents), CLK_SET_RATE_NO_REPARENT,
+                       PLL_CLK_CFG, MCTR_CLK_SHIFT, MCTR_CLK_MASK, 0, &_lock);
        clk_register_clkdev(clk, "ddr_clk", NULL);
 
        clk = clk_register_divider(NULL, "apb_clk", "ahb_clk",
index 412912bbba53c6806f58cb7dc1d4a8daa45d084e..34ee69f4d50c5bd574ceeed4893b0bb9f67a3686 100644 (file)
 static DEFINE_SPINLOCK(clk_lock);
 
 /**
- * sunxi_osc_clk_setup() - Setup function for gatable oscillator
+ * sun4i_osc_clk_setup() - Setup function for gatable oscillator
  */
 
 #define SUNXI_OSC24M_GATE      0
 
-static void __init sunxi_osc_clk_setup(struct device_node *node)
+static void __init sun4i_osc_clk_setup(struct device_node *node)
 {
        struct clk *clk;
        struct clk_fixed_rate *fixed;
@@ -64,22 +64,23 @@ static void __init sunxi_osc_clk_setup(struct device_node *node)
                        &gate->hw, &clk_gate_ops,
                        CLK_IS_ROOT);
 
-       if (clk) {
+       if (!IS_ERR(clk)) {
                of_clk_add_provider(node, of_clk_src_simple_get, clk);
                clk_register_clkdev(clk, clk_name, NULL);
        }
 }
+CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-osc-clk", sun4i_osc_clk_setup);
 
 
 
 /**
- * sunxi_get_pll1_factors() - calculates n, k, m, p factors for PLL1
+ * sun4i_get_pll1_factors() - calculates n, k, m, p factors for PLL1
  * PLL1 rate is calculated as follows
  * rate = (parent_rate * n * (k + 1) >> p) / (m + 1);
  * parent_rate is always 24Mhz
  */
 
-static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate,
+static void sun4i_get_pll1_factors(u32 *freq, u32 parent_rate,
                                   u8 *n, u8 *k, u8 *m, u8 *p)
 {
        u8 div;
@@ -124,15 +125,97 @@ static void sunxi_get_pll1_factors(u32 *freq, u32 parent_rate,
        *n = div / 4;
 }
 
+/**
+ * sun6i_a31_get_pll1_factors() - calculates n, k and m factors for PLL1
+ * PLL1 rate is calculated as follows
+ * rate = parent_rate * (n + 1) * (k + 1) / (m + 1);
+ * parent_rate should always be 24MHz
+ */
+static void sun6i_a31_get_pll1_factors(u32 *freq, u32 parent_rate,
+                                      u8 *n, u8 *k, u8 *m, u8 *p)
+{
+       /*
+        * We can operate only on MHz, this will make our life easier
+        * later.
+        */
+       u32 freq_mhz = *freq / 1000000;
+       u32 parent_freq_mhz = parent_rate / 1000000;
+
+       /*
+        * Round down the frequency to the closest multiple of either
+        * 6 or 16
+        */
+       u32 round_freq_6 = round_down(freq_mhz, 6);
+       u32 round_freq_16 = round_down(freq_mhz, 16);
+
+       if (round_freq_6 > round_freq_16)
+               freq_mhz = round_freq_6;
+       else
+               freq_mhz = round_freq_16;
+
+       *freq = freq_mhz * 1000000;
 
+       /*
+        * If the factors pointer are null, we were just called to
+        * round down the frequency.
+        * Exit.
+        */
+       if (n == NULL)
+               return;
+
+       /* If the frequency is a multiple of 32 MHz, k is always 3 */
+       if (!(freq_mhz % 32))
+               *k = 3;
+       /* If the frequency is a multiple of 9 MHz, k is always 2 */
+       else if (!(freq_mhz % 9))
+               *k = 2;
+       /* If the frequency is a multiple of 8 MHz, k is always 1 */
+       else if (!(freq_mhz % 8))
+               *k = 1;
+       /* Otherwise, we don't use the k factor */
+       else
+               *k = 0;
+
+       /*
+        * If the frequency is a multiple of 2 but not a multiple of
+        * 3, m is 3. This is the first time we use 6 here, yet we
+        * will use it on several other places.
+        * We use this number because it's the lowest frequency we can
+        * generate (with n = 0, k = 0, m = 3), so every other frequency
+        * somehow relates to this frequency.
+        */
+       if ((freq_mhz % 6) == 2 || (freq_mhz % 6) == 4)
+               *m = 2;
+       /*
+        * If the frequency is a multiple of 6MHz, but the factor is
+        * odd, m will be 3
+        */
+       else if ((freq_mhz / 6) & 1)
+               *m = 3;
+       /* Otherwise, we end up with m = 1 */
+       else
+               *m = 1;
+
+       /* Calculate n thanks to the above factors we already got */
+       *n = freq_mhz * (*m + 1) / ((*k + 1) * parent_freq_mhz) - 1;
+
+       /*
+        * If n end up being outbound, and that we can still decrease
+        * m, do it.
+        */
+       if ((*n + 1) > 31 && (*m + 1) > 1) {
+               *n = (*n + 1) / 2 - 1;
+               *m = (*m + 1) / 2 - 1;
+       }
+}
 
 /**
- * sunxi_get_apb1_factors() - calculates m, p factors for APB1
+ * sun4i_get_apb1_factors() - calculates m, p factors for APB1
  * APB1 rate is calculated as follows
  * rate = (parent_rate >> p) / (m + 1);
  */
 
-static void sunxi_get_apb1_factors(u32 *freq, u32 parent_rate,
+static void sun4i_get_apb1_factors(u32 *freq, u32 parent_rate,
                                   u8 *n, u8 *k, u8 *m, u8 *p)
 {
        u8 calcm, calcp;
@@ -178,7 +261,7 @@ struct factors_data {
        void (*getter) (u32 *rate, u32 parent_rate, u8 *n, u8 *k, u8 *m, u8 *p);
 };
 
-static struct clk_factors_config pll1_config = {
+static struct clk_factors_config sun4i_pll1_config = {
        .nshift = 8,
        .nwidth = 5,
        .kshift = 4,
@@ -189,21 +272,35 @@ static struct clk_factors_config pll1_config = {
        .pwidth = 2,
 };
 
-static struct clk_factors_config apb1_config = {
+static struct clk_factors_config sun6i_a31_pll1_config = {
+       .nshift = 8,
+       .nwidth = 5,
+       .kshift = 4,
+       .kwidth = 2,
+       .mshift = 0,
+       .mwidth = 2,
+};
+
+static struct clk_factors_config sun4i_apb1_config = {
        .mshift = 0,
        .mwidth = 5,
        .pshift = 16,
        .pwidth = 2,
 };
 
-static const __initconst struct factors_data pll1_data = {
-       .table = &pll1_config,
-       .getter = sunxi_get_pll1_factors,
+static const struct factors_data sun4i_pll1_data __initconst = {
+       .table = &sun4i_pll1_config,
+       .getter = sun4i_get_pll1_factors,
 };
 
-static const __initconst struct factors_data apb1_data = {
-       .table = &apb1_config,
-       .getter = sunxi_get_apb1_factors,
+static const struct factors_data sun6i_a31_pll1_data __initconst = {
+       .table = &sun6i_a31_pll1_config,
+       .getter = sun6i_a31_get_pll1_factors,
+};
+
+static const struct factors_data sun4i_apb1_data __initconst = {
+       .table = &sun4i_apb1_config,
+       .getter = sun4i_get_apb1_factors,
 };
 
 static void __init sunxi_factors_clk_setup(struct device_node *node,
@@ -221,7 +318,7 @@ static void __init sunxi_factors_clk_setup(struct device_node *node,
        clk = clk_register_factors(NULL, clk_name, parent, 0, reg,
                                   data->table, data->getter, &clk_lock);
 
-       if (clk) {
+       if (!IS_ERR(clk)) {
                of_clk_add_provider(node, of_clk_src_simple_get, clk);
                clk_register_clkdev(clk, clk_name, NULL);
        }
@@ -239,11 +336,15 @@ struct mux_data {
        u8 shift;
 };
 
-static const __initconst struct mux_data cpu_mux_data = {
+static const struct mux_data sun4i_cpu_mux_data __initconst = {
        .shift = 16,
 };
 
-static const __initconst struct mux_data apb1_mux_data = {
+static const struct mux_data sun6i_a31_ahb1_mux_data __initconst = {
+       .shift = 12,
+};
+
+static const struct mux_data sun4i_apb1_mux_data __initconst = {
        .shift = 24,
 };
 
@@ -261,7 +362,8 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
        while (i < 5 && (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
                i++;
 
-       clk = clk_register_mux(NULL, clk_name, parents, i, 0, reg,
+       clk = clk_register_mux(NULL, clk_name, parents, i,
+                              CLK_SET_RATE_NO_REPARENT, reg,
                               data->shift, SUNXI_MUX_GATE_WIDTH,
                               0, &clk_lock);
 
@@ -277,26 +379,34 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
  * sunxi_divider_clk_setup() - Setup function for simple divider clocks
  */
 
-#define SUNXI_DIVISOR_WIDTH    2
-
 struct div_data {
-       u8 shift;
-       u8 pow;
+       u8      shift;
+       u8      pow;
+       u8      width;
 };
 
-static const __initconst struct div_data axi_data = {
-       .shift = 0,
-       .pow = 0,
+static const struct div_data sun4i_axi_data __initconst = {
+       .shift  = 0,
+       .pow    = 0,
+       .width  = 2,
 };
 
-static const __initconst struct div_data ahb_data = {
-       .shift = 4,
-       .pow = 1,
+static const struct div_data sun4i_ahb_data __initconst = {
+       .shift  = 4,
+       .pow    = 1,
+       .width  = 2,
 };
 
-static const __initconst struct div_data apb0_data = {
-       .shift = 8,
-       .pow = 1,
+static const struct div_data sun4i_apb0_data __initconst = {
+       .shift  = 8,
+       .pow    = 1,
+       .width  = 2,
+};
+
+static const struct div_data sun6i_a31_apb2_div_data __initconst = {
+       .shift  = 0,
+       .pow    = 0,
+       .width  = 4,
 };
 
 static void __init sunxi_divider_clk_setup(struct device_node *node,
@@ -312,7 +422,7 @@ static void __init sunxi_divider_clk_setup(struct device_node *node,
        clk_parent = of_clk_get_parent_name(node, 0);
 
        clk = clk_register_divider(NULL, clk_name, clk_parent, 0,
-                                  reg, data->shift, SUNXI_DIVISOR_WIDTH,
+                                  reg, data->shift, data->width,
                                   data->pow ? CLK_DIVIDER_POWER_OF_TWO : 0,
                                   &clk_lock);
        if (clk) {
@@ -333,34 +443,70 @@ struct gates_data {
        DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
 };
 
-static const __initconst struct gates_data sun4i_axi_gates_data = {
+static const struct gates_data sun4i_axi_gates_data __initconst = {
        .mask = {1},
 };
 
-static const __initconst struct gates_data sun4i_ahb_gates_data = {
+static const struct gates_data sun4i_ahb_gates_data __initconst = {
        .mask = {0x7F77FFF, 0x14FB3F},
 };
 
-static const __initconst struct gates_data sun5i_a13_ahb_gates_data = {
+static const struct gates_data sun5i_a10s_ahb_gates_data __initconst = {
+       .mask = {0x147667e7, 0x185915},
+};
+
+static const struct gates_data sun5i_a13_ahb_gates_data __initconst = {
        .mask = {0x107067e7, 0x185111},
 };
 
-static const __initconst struct gates_data sun4i_apb0_gates_data = {
+static const struct gates_data sun6i_a31_ahb1_gates_data __initconst = {
+       .mask = {0xEDFE7F62, 0x794F931},
+};
+
+static const struct gates_data sun7i_a20_ahb_gates_data __initconst = {
+       .mask = { 0x12f77fff, 0x16ff3f },
+};
+
+static const struct gates_data sun4i_apb0_gates_data __initconst = {
        .mask = {0x4EF},
 };
 
-static const __initconst struct gates_data sun5i_a13_apb0_gates_data = {
+static const struct gates_data sun5i_a10s_apb0_gates_data __initconst = {
+       .mask = {0x469},
+};
+
+static const struct gates_data sun5i_a13_apb0_gates_data __initconst = {
        .mask = {0x61},
 };
 
-static const __initconst struct gates_data sun4i_apb1_gates_data = {
+static const struct gates_data sun7i_a20_apb0_gates_data __initconst = {
+       .mask = { 0x4ff },
+};
+
+static const struct gates_data sun4i_apb1_gates_data __initconst = {
        .mask = {0xFF00F7},
 };
 
-static const __initconst struct gates_data sun5i_a13_apb1_gates_data = {
+static const struct gates_data sun5i_a10s_apb1_gates_data __initconst = {
+       .mask = {0xf0007},
+};
+
+static const struct gates_data sun5i_a13_apb1_gates_data __initconst = {
        .mask = {0xa0007},
 };
 
+static const struct gates_data sun6i_a31_apb1_gates_data __initconst = {
+       .mask = {0x3031},
+};
+
+static const struct gates_data sun6i_a31_apb2_gates_data __initconst = {
+       .mask = {0x3F000F},
+};
+
+static const struct gates_data sun7i_a20_apb1_gates_data __initconst = {
+       .mask = { 0xff80ff },
+};
+
 static void __init sunxi_gates_clk_setup(struct device_node *node,
                                         struct gates_data *data)
 {
@@ -410,43 +556,49 @@ static void __init sunxi_gates_clk_setup(struct device_node *node,
        of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
 }
 
-/* Matches for of_clk_init */
-static const __initconst struct of_device_id clk_match[] = {
-       {.compatible = "allwinner,sun4i-osc-clk", .data = sunxi_osc_clk_setup,},
-       {}
-};
-
 /* Matches for factors clocks */
-static const __initconst struct of_device_id clk_factors_match[] = {
-       {.compatible = "allwinner,sun4i-pll1-clk", .data = &pll1_data,},
-       {.compatible = "allwinner,sun4i-apb1-clk", .data = &apb1_data,},
+static const struct of_device_id clk_factors_match[] __initconst = {
+       {.compatible = "allwinner,sun4i-pll1-clk", .data = &sun4i_pll1_data,},
+       {.compatible = "allwinner,sun6i-a31-pll1-clk", .data = &sun6i_a31_pll1_data,},
+       {.compatible = "allwinner,sun4i-apb1-clk", .data = &sun4i_apb1_data,},
        {}
 };
 
 /* Matches for divider clocks */
-static const __initconst struct of_device_id clk_div_match[] = {
-       {.compatible = "allwinner,sun4i-axi-clk", .data = &axi_data,},
-       {.compatible = "allwinner,sun4i-ahb-clk", .data = &ahb_data,},
-       {.compatible = "allwinner,sun4i-apb0-clk", .data = &apb0_data,},
+static const struct of_device_id clk_div_match[] __initconst = {
+       {.compatible = "allwinner,sun4i-axi-clk", .data = &sun4i_axi_data,},
+       {.compatible = "allwinner,sun4i-ahb-clk", .data = &sun4i_ahb_data,},
+       {.compatible = "allwinner,sun4i-apb0-clk", .data = &sun4i_apb0_data,},
+       {.compatible = "allwinner,sun6i-a31-apb2-div-clk", .data = &sun6i_a31_apb2_div_data,},
        {}
 };
 
 /* Matches for mux clocks */
-static const __initconst struct of_device_id clk_mux_match[] = {
-       {.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_mux_data,},
-       {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
+static const struct of_device_id clk_mux_match[] __initconst = {
+       {.compatible = "allwinner,sun4i-cpu-clk", .data = &sun4i_cpu_mux_data,},
+       {.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &sun4i_apb1_mux_data,},
+       {.compatible = "allwinner,sun6i-a31-ahb1-mux-clk", .data = &sun6i_a31_ahb1_mux_data,},
        {}
 };
 
 /* Matches for gate clocks */
-static const __initconst struct of_device_id clk_gates_match[] = {
+static const struct of_device_id clk_gates_match[] __initconst = {
        {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
        {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
+       {.compatible = "allwinner,sun5i-a10s-ahb-gates-clk", .data = &sun5i_a10s_ahb_gates_data,},
        {.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
+       {.compatible = "allwinner,sun6i-a31-ahb1-gates-clk", .data = &sun6i_a31_ahb1_gates_data,},
+       {.compatible = "allwinner,sun7i-a20-ahb-gates-clk", .data = &sun7i_a20_ahb_gates_data,},
        {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
+       {.compatible = "allwinner,sun5i-a10s-apb0-gates-clk", .data = &sun5i_a10s_apb0_gates_data,},
        {.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
+       {.compatible = "allwinner,sun7i-a20-apb0-gates-clk", .data = &sun7i_a20_apb0_gates_data,},
        {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
+       {.compatible = "allwinner,sun5i-a10s-apb1-gates-clk", .data = &sun5i_a10s_apb1_gates_data,},
        {.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
+       {.compatible = "allwinner,sun6i-a31-apb1-gates-clk", .data = &sun6i_a31_apb1_gates_data,},
+       {.compatible = "allwinner,sun7i-a20-apb1-gates-clk", .data = &sun7i_a20_apb1_gates_data,},
+       {.compatible = "allwinner,sun6i-a31-apb2-gates-clk", .data = &sun6i_a31_apb2_gates_data,},
        {}
 };
 
@@ -467,8 +619,8 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
 
 void __init sunxi_init_clocks(void)
 {
-       /* Register all the simple sunxi clocks on DT */
-       of_clk_init(clk_match);
+       /* Register all the simple and basic clocks on DT */
+       of_clk_init(NULL);
 
        /* Register factor clocks */
        of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
index 806d80366c543707db13e10a873815ce2d1ed5df..9467da7dee4918a60762700442d9685fc658ab3c 100644 (file)
@@ -1566,7 +1566,8 @@ static void __init tegra114_audio_clk_init(void __iomem *clk_base)
 
        /* audio0 */
        clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk,
-                              ARRAY_SIZE(mux_audio_sync_clk), 0,
+                              ARRAY_SIZE(mux_audio_sync_clk),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0,
                               NULL);
        clks[audio0_mux] = clk;
@@ -1578,7 +1579,8 @@ static void __init tegra114_audio_clk_init(void __iomem *clk_base)
 
        /* audio1 */
        clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk,
-                              ARRAY_SIZE(mux_audio_sync_clk), 0,
+                              ARRAY_SIZE(mux_audio_sync_clk),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0,
                               NULL);
        clks[audio1_mux] = clk;
@@ -1590,7 +1592,8 @@ static void __init tegra114_audio_clk_init(void __iomem *clk_base)
 
        /* audio2 */
        clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk,
-                              ARRAY_SIZE(mux_audio_sync_clk), 0,
+                              ARRAY_SIZE(mux_audio_sync_clk),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0,
                               NULL);
        clks[audio2_mux] = clk;
@@ -1602,7 +1605,8 @@ static void __init tegra114_audio_clk_init(void __iomem *clk_base)
 
        /* audio3 */
        clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk,
-                              ARRAY_SIZE(mux_audio_sync_clk), 0,
+                              ARRAY_SIZE(mux_audio_sync_clk),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0,
                               NULL);
        clks[audio3_mux] = clk;
@@ -1614,7 +1618,8 @@ static void __init tegra114_audio_clk_init(void __iomem *clk_base)
 
        /* audio4 */
        clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk,
-                              ARRAY_SIZE(mux_audio_sync_clk), 0,
+                              ARRAY_SIZE(mux_audio_sync_clk),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0,
                               NULL);
        clks[audio4_mux] = clk;
@@ -1626,7 +1631,8 @@ static void __init tegra114_audio_clk_init(void __iomem *clk_base)
 
        /* spdif */
        clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk,
-                              ARRAY_SIZE(mux_audio_sync_clk), 0,
+                              ARRAY_SIZE(mux_audio_sync_clk),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0,
                               NULL);
        clks[spdif_mux] = clk;
@@ -1721,7 +1727,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
 
        /* clk_out_1 */
        clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents,
-                              ARRAY_SIZE(clk_out1_parents), 0,
+                              ARRAY_SIZE(clk_out1_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0,
                               &clk_out_lock);
        clks[clk_out_1_mux] = clk;
@@ -1733,7 +1740,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
 
        /* clk_out_2 */
        clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
-                              ARRAY_SIZE(clk_out2_parents), 0,
+                              ARRAY_SIZE(clk_out2_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
                               &clk_out_lock);
        clks[clk_out_2_mux] = clk;
@@ -1745,7 +1753,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
 
        /* clk_out_3 */
        clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
-                              ARRAY_SIZE(clk_out3_parents), 0,
+                              ARRAY_SIZE(clk_out3_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
                               &clk_out_lock);
        clks[clk_out_3_mux] = clk;
@@ -2063,7 +2072,8 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base)
 
        /* dsia */
        clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
-                              ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
+                              ARRAY_SIZE(mux_plld_out0_plld2_out0),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock);
        clks[dsia_mux] = clk;
        clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base,
@@ -2073,7 +2083,8 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base)
 
        /* dsib */
        clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0,
-                              ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
+                              ARRAY_SIZE(mux_plld_out0_plld2_out0),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
        clks[dsib_mux] = clk;
        clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base,
@@ -2110,7 +2121,8 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base)
 
        /* emc */
        clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
-                              ARRAY_SIZE(mux_pllmcp_clkm), 0,
+                              ARRAY_SIZE(mux_pllmcp_clkm),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + CLK_SOURCE_EMC,
                               29, 3, 0, NULL);
        clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base,
@@ -2194,7 +2206,7 @@ static const struct of_device_id pmc_match[] __initconst = {
  * dfll_soc/dfll_ref apparently must be kept enabled, otherwise I2C5
  * breaks
  */
-static __initdata struct tegra_clk_init_table init_table[] = {
+static struct tegra_clk_init_table init_table[] __initdata = {
        {uarta, pll_p, 408000000, 0},
        {uartb, pll_p, 408000000, 0},
        {uartc, pll_p, 408000000, 0},
index 759ca47be7533c608e3b20f12b324851d180fde0..056f649d0d8908b7f6de919a3ca7fc95c3d4e089 100644 (file)
@@ -778,7 +778,8 @@ static void __init tegra20_audio_clk_init(void)
 
        /* audio */
        clk = clk_register_mux(NULL, "audio_mux", audio_parents,
-                               ARRAY_SIZE(audio_parents), 0,
+                               ARRAY_SIZE(audio_parents),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "audio", "audio_mux", 0,
                                clk_base + AUDIO_SYNC_CLK, 4,
@@ -941,7 +942,8 @@ static void __init tegra20_periph_clk_init(void)
 
        /* emc */
        clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
-                              ARRAY_SIZE(mux_pllmcp_clkm), 0,
+                              ARRAY_SIZE(mux_pllmcp_clkm),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + CLK_SOURCE_EMC,
                               30, 2, 0, NULL);
        clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
@@ -1223,7 +1225,7 @@ static struct tegra_cpu_car_ops tegra20_cpu_car_ops = {
 #endif
 };
 
-static __initdata struct tegra_clk_init_table init_table[] = {
+static struct tegra_clk_init_table init_table[] __initdata = {
        {pll_p, clk_max, 216000000, 1},
        {pll_p_out1, clk_max, 28800000, 1},
        {pll_p_out2, clk_max, 48000000, 1},
index e2c6ca0431d662c141742c46eb7dc91bc040dda3..dbe7c8003c5c4392244b7161e5b7771634e7e8c3 100644 (file)
@@ -971,7 +971,7 @@ static void __init tegra30_pll_init(void)
        /* PLLU */
        clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0,
                            0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON |
-                           TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK,
+                           TEGRA_PLL_SET_LFCON,
                            pll_u_freq_table,
                            NULL);
        clk_register_clkdev(clk, "pll_u", NULL);
@@ -1026,7 +1026,8 @@ static void __init tegra30_pll_init(void)
 
        /* PLLE */
        clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents,
-                              ARRAY_SIZE(pll_e_parents), 0,
+                              ARRAY_SIZE(pll_e_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + PLLE_AUX, 2, 1, 0, NULL);
        clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base,
                             CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params,
@@ -1086,7 +1087,8 @@ static void __init tegra30_audio_clk_init(void)
 
        /* audio0 */
        clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk,
-                               ARRAY_SIZE(mux_audio_sync_clk), 0,
+                               ARRAY_SIZE(mux_audio_sync_clk),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0,
                                clk_base + AUDIO_SYNC_CLK_I2S0, 4,
@@ -1096,7 +1098,8 @@ static void __init tegra30_audio_clk_init(void)
 
        /* audio1 */
        clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk,
-                               ARRAY_SIZE(mux_audio_sync_clk), 0,
+                               ARRAY_SIZE(mux_audio_sync_clk),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0,
                                clk_base + AUDIO_SYNC_CLK_I2S1, 4,
@@ -1106,7 +1109,8 @@ static void __init tegra30_audio_clk_init(void)
 
        /* audio2 */
        clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk,
-                               ARRAY_SIZE(mux_audio_sync_clk), 0,
+                               ARRAY_SIZE(mux_audio_sync_clk),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0,
                                clk_base + AUDIO_SYNC_CLK_I2S2, 4,
@@ -1116,7 +1120,8 @@ static void __init tegra30_audio_clk_init(void)
 
        /* audio3 */
        clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk,
-                               ARRAY_SIZE(mux_audio_sync_clk), 0,
+                               ARRAY_SIZE(mux_audio_sync_clk),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0,
                                clk_base + AUDIO_SYNC_CLK_I2S3, 4,
@@ -1126,7 +1131,8 @@ static void __init tegra30_audio_clk_init(void)
 
        /* audio4 */
        clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk,
-                               ARRAY_SIZE(mux_audio_sync_clk), 0,
+                               ARRAY_SIZE(mux_audio_sync_clk),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0,
                                clk_base + AUDIO_SYNC_CLK_I2S4, 4,
@@ -1136,7 +1142,8 @@ static void __init tegra30_audio_clk_init(void)
 
        /* spdif */
        clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk,
-                               ARRAY_SIZE(mux_audio_sync_clk), 0,
+                               ARRAY_SIZE(mux_audio_sync_clk),
+                               CLK_SET_RATE_NO_REPARENT,
                                clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL);
        clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0,
                                clk_base + AUDIO_SYNC_CLK_SPDIF, 4,
@@ -1229,7 +1236,8 @@ static void __init tegra30_pmc_clk_init(void)
 
        /* clk_out_1 */
        clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents,
-                              ARRAY_SIZE(clk_out1_parents), 0,
+                              ARRAY_SIZE(clk_out1_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0,
                               &clk_out_lock);
        clks[clk_out_1_mux] = clk;
@@ -1241,7 +1249,8 @@ static void __init tegra30_pmc_clk_init(void)
 
        /* clk_out_2 */
        clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
-                              ARRAY_SIZE(clk_out2_parents), 0,
+                              ARRAY_SIZE(clk_out2_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
                               &clk_out_lock);
        clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
@@ -1252,7 +1261,8 @@ static void __init tegra30_pmc_clk_init(void)
 
        /* clk_out_3 */
        clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
-                              ARRAY_SIZE(clk_out3_parents), 0,
+                              ARRAY_SIZE(clk_out3_parents),
+                              CLK_SET_RATE_NO_REPARENT,
                               pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
                               &clk_out_lock);
        clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
@@ -1679,7 +1689,8 @@ static void __init tegra30_periph_clk_init(void)
 
        /* emc */
        clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
-                              ARRAY_SIZE(mux_pllmcp_clkm), 0,
+                              ARRAY_SIZE(mux_pllmcp_clkm),
+                              CLK_SET_RATE_NO_REPARENT,
                               clk_base + CLK_SOURCE_EMC,
                               30, 2, 0, NULL);
        clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
@@ -1901,7 +1912,7 @@ static struct tegra_cpu_car_ops tegra30_cpu_car_ops = {
 #endif
 };
 
-static __initdata struct tegra_clk_init_table init_table[] = {
+static struct tegra_clk_init_table init_table[] __initdata = {
        {uarta, pll_p, 408000000, 0},
        {uartb, pll_p, 408000000, 0},
        {uartc, pll_p, 408000000, 0},
index a4a728d0509258b32bf5752ba2f3fcd91901a831..2d5e1b4820e0919cc08f78151a0df7bb61c6cd77 100644 (file)
@@ -37,8 +37,8 @@ static void __init vexpress_sp810_init(void __iomem *base)
                snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
 
                vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
-                               parents, 2, 0, base + SCCTRL,
-                               SCCTRL_TIMERENnSEL_SHIFT(i), 1,
+                               parents, 2, CLK_SET_RATE_NO_REPARENT,
+                               base + SCCTRL, SCCTRL_TIMERENnSEL_SHIFT(i), 1,
                                0, &vexpress_sp810_lock);
 
                if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
index 089d3e30e2216e44b20067fdaf9ded66708d0bb2..cc40fe64f2dc681c44205151537a71222e8d4990 100644 (file)
@@ -125,8 +125,9 @@ static void __init zynq_clk_register_fclk(enum zynq_clk fclk,
        div0_name = kasprintf(GFP_KERNEL, "%s_div0", clk_name);
        div1_name = kasprintf(GFP_KERNEL, "%s_div1", clk_name);
 
-       clk = clk_register_mux(NULL, mux_name, parents, 4, 0,
-                       fclk_ctrl_reg, 4, 2, 0, fclk_lock);
+       clk = clk_register_mux(NULL, mux_name, parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, fclk_ctrl_reg, 4, 2, 0,
+                       fclk_lock);
 
        clk = clk_register_divider(NULL, div0_name, mux_name,
                        0, fclk_ctrl_reg, 8, 6, CLK_DIVIDER_ONE_BASED |
@@ -168,8 +169,8 @@ static void __init zynq_clk_register_periph_clk(enum zynq_clk clk0,
        mux_name = kasprintf(GFP_KERNEL, "%s_mux", clk_name0);
        div_name = kasprintf(GFP_KERNEL, "%s_div", clk_name0);
 
-       clk = clk_register_mux(NULL, mux_name, parents, 4, 0,
-                       clk_ctrl, 4, 2, 0, lock);
+       clk = clk_register_mux(NULL, mux_name, parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, clk_ctrl, 4, 2, 0, lock);
 
        clk = clk_register_divider(NULL, div_name, mux_name, 0, clk_ctrl, 8, 6,
                        CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, lock);
@@ -236,25 +237,26 @@ static void __init zynq_clk_setup(struct device_node *np)
        clk = clk_register_zynq_pll("armpll_int", "ps_clk", SLCR_ARMPLL_CTRL,
                        SLCR_PLL_STATUS, 0, &armpll_lock);
        clks[armpll] = clk_register_mux(NULL, clk_output_name[armpll],
-                       armpll_parents, 2, 0, SLCR_ARMPLL_CTRL, 4, 1, 0,
-                       &armpll_lock);
+                       armpll_parents, 2, CLK_SET_RATE_NO_REPARENT,
+                       SLCR_ARMPLL_CTRL, 4, 1, 0, &armpll_lock);
 
        clk = clk_register_zynq_pll("ddrpll_int", "ps_clk", SLCR_DDRPLL_CTRL,
                        SLCR_PLL_STATUS, 1, &ddrpll_lock);
        clks[ddrpll] = clk_register_mux(NULL, clk_output_name[ddrpll],
-                       ddrpll_parents, 2, 0, SLCR_DDRPLL_CTRL, 4, 1, 0,
-                       &ddrpll_lock);
+                       ddrpll_parents, 2, CLK_SET_RATE_NO_REPARENT,
+                       SLCR_DDRPLL_CTRL, 4, 1, 0, &ddrpll_lock);
 
        clk = clk_register_zynq_pll("iopll_int", "ps_clk", SLCR_IOPLL_CTRL,
                        SLCR_PLL_STATUS, 2, &iopll_lock);
        clks[iopll] = clk_register_mux(NULL, clk_output_name[iopll],
-                       iopll_parents, 2, 0, SLCR_IOPLL_CTRL, 4, 1, 0,
-                       &iopll_lock);
+                       iopll_parents, 2, CLK_SET_RATE_NO_REPARENT,
+                       SLCR_IOPLL_CTRL, 4, 1, 0, &iopll_lock);
 
        /* CPU clocks */
        tmp = readl(SLCR_621_TRUE) & 1;
-       clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, 0,
-                       SLCR_ARM_CLK_CTRL, 4, 2, 0, &armclk_lock);
+       clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, SLCR_ARM_CLK_CTRL, 4, 2, 0,
+                       &armclk_lock);
        clk = clk_register_divider(NULL, "cpu_div", "cpu_mux", 0,
                        SLCR_ARM_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                        CLK_DIVIDER_ALLOW_ZERO, &armclk_lock);
@@ -293,8 +295,9 @@ static void __init zynq_clk_setup(struct device_node *np)
                        swdt_ext_clk_mux_parents[i + 1] = dummy_nm;
        }
        clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt],
-                       swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT,
-                       SLCR_SWDT_CLK_SEL, 0, 1, 0, &swdtclk_lock);
+                       swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT |
+                       CLK_SET_RATE_NO_REPARENT, SLCR_SWDT_CLK_SEL, 0, 1, 0,
+                       &swdtclk_lock);
 
        /* DDR clocks */
        clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0,
@@ -356,8 +359,9 @@ static void __init zynq_clk_setup(struct device_node *np)
                        gem0_mux_parents[i + 1] = of_clk_get_parent_name(np,
                                        idx);
        }
-       clk = clk_register_mux(NULL, "gem0_mux", periph_parents, 4, 0,
-                       SLCR_GEM0_CLK_CTRL, 4, 2, 0, &gem0clk_lock);
+       clk = clk_register_mux(NULL, "gem0_mux", periph_parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, SLCR_GEM0_CLK_CTRL, 4, 2, 0,
+                       &gem0clk_lock);
        clk = clk_register_divider(NULL, "gem0_div0", "gem0_mux", 0,
                        SLCR_GEM0_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                        CLK_DIVIDER_ALLOW_ZERO, &gem0clk_lock);
@@ -366,7 +370,8 @@ static void __init zynq_clk_setup(struct device_node *np)
                        CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                        &gem0clk_lock);
        clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2,
-                       CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 6, 1, 0,
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+                       SLCR_GEM0_CLK_CTRL, 6, 1, 0,
                        &gem0clk_lock);
        clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0],
                        "gem0_emio_mux", CLK_SET_RATE_PARENT,
@@ -379,8 +384,9 @@ static void __init zynq_clk_setup(struct device_node *np)
                        gem1_mux_parents[i + 1] = of_clk_get_parent_name(np,
                                        idx);
        }
-       clk = clk_register_mux(NULL, "gem1_mux", periph_parents, 4, 0,
-                       SLCR_GEM1_CLK_CTRL, 4, 2, 0, &gem1clk_lock);
+       clk = clk_register_mux(NULL, "gem1_mux", periph_parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, SLCR_GEM1_CLK_CTRL, 4, 2, 0,
+                       &gem1clk_lock);
        clk = clk_register_divider(NULL, "gem1_div0", "gem1_mux", 0,
                        SLCR_GEM1_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                        CLK_DIVIDER_ALLOW_ZERO, &gem1clk_lock);
@@ -389,7 +395,8 @@ static void __init zynq_clk_setup(struct device_node *np)
                        CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                        &gem1clk_lock);
        clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2,
-                       CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 6, 1, 0,
+                       CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT,
+                       SLCR_GEM1_CLK_CTRL, 6, 1, 0,
                        &gem1clk_lock);
        clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1],
                        "gem1_emio_mux", CLK_SET_RATE_PARENT,
@@ -409,8 +416,9 @@ static void __init zynq_clk_setup(struct device_node *np)
                        can_mio_mux_parents[i] = dummy_nm;
        }
        kfree(clk_name);
-       clk = clk_register_mux(NULL, "can_mux", periph_parents, 4, 0,
-                       SLCR_CAN_CLK_CTRL, 4, 2, 0, &canclk_lock);
+       clk = clk_register_mux(NULL, "can_mux", periph_parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, SLCR_CAN_CLK_CTRL, 4, 2, 0,
+                       &canclk_lock);
        clk = clk_register_divider(NULL, "can_div0", "can_mux", 0,
                        SLCR_CAN_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                        CLK_DIVIDER_ALLOW_ZERO, &canclk_lock);
@@ -425,17 +433,21 @@ static void __init zynq_clk_setup(struct device_node *np)
                        CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 1, 0,
                        &canclk_lock);
        clk = clk_register_mux(NULL, "can0_mio_mux",
-                       can_mio_mux_parents, 54, CLK_SET_RATE_PARENT,
-                       SLCR_CAN_MIOCLK_CTRL, 0, 6, 0, &canmioclk_lock);
+                       can_mio_mux_parents, 54, CLK_SET_RATE_PARENT |
+                       CLK_SET_RATE_NO_REPARENT, SLCR_CAN_MIOCLK_CTRL, 0, 6, 0,
+                       &canmioclk_lock);
        clk = clk_register_mux(NULL, "can1_mio_mux",
-                       can_mio_mux_parents, 54, CLK_SET_RATE_PARENT,
-                       SLCR_CAN_MIOCLK_CTRL, 16, 6, 0, &canmioclk_lock);
+                       can_mio_mux_parents, 54, CLK_SET_RATE_PARENT |
+                       CLK_SET_RATE_NO_REPARENT, SLCR_CAN_MIOCLK_CTRL, 16, 6,
+                       0, &canmioclk_lock);
        clks[can0] = clk_register_mux(NULL, clk_output_name[can0],
-                       can0_mio_mux2_parents, 2, CLK_SET_RATE_PARENT,
-                       SLCR_CAN_MIOCLK_CTRL, 6, 1, 0, &canmioclk_lock);
+                       can0_mio_mux2_parents, 2, CLK_SET_RATE_PARENT |
+                       CLK_SET_RATE_NO_REPARENT, SLCR_CAN_MIOCLK_CTRL, 6, 1, 0,
+                       &canmioclk_lock);
        clks[can1] = clk_register_mux(NULL, clk_output_name[can1],
-                       can1_mio_mux2_parents, 2, CLK_SET_RATE_PARENT,
-                       SLCR_CAN_MIOCLK_CTRL, 22, 1, 0, &canmioclk_lock);
+                       can1_mio_mux2_parents, 2, CLK_SET_RATE_PARENT |
+                       CLK_SET_RATE_NO_REPARENT, SLCR_CAN_MIOCLK_CTRL, 22, 1,
+                       0, &canmioclk_lock);
 
        for (i = 0; i < ARRAY_SIZE(dbgtrc_emio_input_names); i++) {
                int idx = of_property_match_string(np, "clock-names",
@@ -444,13 +456,15 @@ static void __init zynq_clk_setup(struct device_node *np)
                        dbg_emio_mux_parents[i + 1] = of_clk_get_parent_name(np,
                                        idx);
        }
-       clk = clk_register_mux(NULL, "dbg_mux", periph_parents, 4, 0,
-                       SLCR_DBG_CLK_CTRL, 4, 2, 0, &dbgclk_lock);
+       clk = clk_register_mux(NULL, "dbg_mux", periph_parents, 4,
+                       CLK_SET_RATE_NO_REPARENT, SLCR_DBG_CLK_CTRL, 4, 2, 0,
+                       &dbgclk_lock);
        clk = clk_register_divider(NULL, "dbg_div", "dbg_mux", 0,
                        SLCR_DBG_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                        CLK_DIVIDER_ALLOW_ZERO, &dbgclk_lock);
-       clk = clk_register_mux(NULL, "dbg_emio_mux", dbg_emio_mux_parents, 2, 0,
-                       SLCR_DBG_CLK_CTRL, 6, 1, 0, &dbgclk_lock);
+       clk = clk_register_mux(NULL, "dbg_emio_mux", dbg_emio_mux_parents, 2,
+                       CLK_SET_RATE_NO_REPARENT, SLCR_DBG_CLK_CTRL, 6, 1, 0,
+                       &dbgclk_lock);
        clks[dbg_trc] = clk_register_gate(NULL, clk_output_name[dbg_trc],
                        "dbg_emio_mux", CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL,
                        0, 0, &dbgclk_lock);
index 47e307c25a7b0703170be22449674677dce54eec..3226f54fa5956a357104f3f8675779179067b717 100644 (file)
@@ -50,6 +50,9 @@ struct zynq_pll {
 #define PLLCTRL_RESET_MASK     1
 #define PLLCTRL_RESET_SHIFT    0
 
+#define PLL_FBDIV_MIN  13
+#define PLL_FBDIV_MAX  66
+
 /**
  * zynq_pll_round_rate() - Round a clock frequency
  * @hw:                Handle between common and hardware-specific interfaces
@@ -63,10 +66,10 @@ static long zynq_pll_round_rate(struct clk_hw *hw, unsigned long rate,
        u32 fbdiv;
 
        fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
-       if (fbdiv < 13)
-               fbdiv = 13;
-       else if (fbdiv > 66)
-               fbdiv = 66;
+       if (fbdiv < PLL_FBDIV_MIN)
+               fbdiv = PLL_FBDIV_MIN;
+       else if (fbdiv > PLL_FBDIV_MAX)
+               fbdiv = PLL_FBDIV_MAX;
 
        return *prate * fbdiv;
 }
@@ -182,7 +185,13 @@ static const struct clk_ops zynq_pll_ops = {
 
 /**
  * clk_register_zynq_pll() - Register PLL with the clock framework
- * @np Pointer to the DT device node
+ * @name       PLL name
+ * @parent     Parent clock name
+ * @pll_ctrl   Pointer to PLL control register
+ * @pll_status Pointer to PLL status register
+ * @lock_index Bit index to this PLL's lock status bit in @pll_status
+ * @lock       Register lock
+ * Returns handle to the registered clock.
  */
 struct clk *clk_register_zynq_pll(const char *name, const char *parent,
                void __iomem *pll_ctrl, void __iomem *pll_status, u8 lock_index,
index 4329a29a5310d046eaedc12cd14229791c6e14f1..b9c81b7c3a3bfa5a251129e42c687b1e0aeeb851 100644 (file)
@@ -315,68 +315,47 @@ static int em_sti_probe(struct platform_device *pdev)
 {
        struct em_sti_priv *p;
        struct resource *res;
-       int irq, ret;
+       int irq;
 
-       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
        if (p == NULL) {
                dev_err(&pdev->dev, "failed to allocate driver data\n");
-               ret = -ENOMEM;
-               goto err0;
+               return -ENOMEM;
        }
 
        p->pdev = pdev;
        platform_set_drvdata(pdev, p);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get I/O memory\n");
-               ret = -EINVAL;
-               goto err0;
-       }
-
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "failed to get irq\n");
-               ret = -EINVAL;
-               goto err0;
+               return -EINVAL;
        }
 
        /* map memory, let base point to the STI instance */
-       p->base = ioremap_nocache(res->start, resource_size(res));
-       if (p->base == NULL) {
-               dev_err(&pdev->dev, "failed to remap I/O memory\n");
-               ret = -ENXIO;
-               goto err0;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       p->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(p->base))
+               return PTR_ERR(p->base);
 
        /* get hold of clock */
-       p->clk = clk_get(&pdev->dev, "sclk");
+       p->clk = devm_clk_get(&pdev->dev, "sclk");
        if (IS_ERR(p->clk)) {
                dev_err(&pdev->dev, "cannot get clock\n");
-               ret = PTR_ERR(p->clk);
-               goto err1;
+               return PTR_ERR(p->clk);
        }
 
-       if (request_irq(irq, em_sti_interrupt,
-                       IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
-                       dev_name(&pdev->dev), p)) {
+       if (devm_request_irq(&pdev->dev, irq, em_sti_interrupt,
+                            IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING,
+                            dev_name(&pdev->dev), p)) {
                dev_err(&pdev->dev, "failed to request low IRQ\n");
-               ret = -ENOENT;
-               goto err2;
+               return -ENOENT;
        }
 
        raw_spin_lock_init(&p->lock);
        em_sti_register_clockevent(p);
        em_sti_register_clocksource(p);
        return 0;
-
-err2:
-       clk_put(p->clk);
-err1:
-       iounmap(p->base);
-err0:
-       kfree(p);
-       return ret;
 }
 
 static int em_sti_remove(struct platform_device *pdev)
index 7d2c2c56f73c3044d5d4a6106975ab857ee076fa..1b74bea12385a20acd695f2d422665be1dfd90f3 100644 (file)
@@ -165,7 +165,8 @@ static void nmdk_clkevt_resume(struct clock_event_device *cedev)
 
 static struct clock_event_device nmdk_clkevt = {
        .name           = "mtu_1",
-       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+       .features       = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC |
+                         CLOCK_EVT_FEAT_DYNIRQ,
        .rating         = 200,
        .set_mode       = nmdk_clkevt_mode,
        .set_next_event = nmdk_clkevt_next,
index ac60f8b8a5f71241f8d29fe999c428abfba20985..ab29476ee5f9e21dd85de872a45df747dec4a0e4 100644 (file)
@@ -368,10 +368,6 @@ static void __init samsung_clocksource_init(void)
 
 static void __init samsung_timer_resources(void)
 {
-       pwm.timerclk = clk_get(NULL, "timers");
-       if (IS_ERR(pwm.timerclk))
-               panic("failed to get timers clock for timer");
-
        clk_prepare_enable(pwm.timerclk);
 
        pwm.tcnt_max = (1UL << pwm.variant.bits) - 1;
@@ -416,6 +412,10 @@ void __init samsung_pwm_clocksource_init(void __iomem *base,
        memcpy(&pwm.variant, variant, sizeof(pwm.variant));
        memcpy(pwm.irq, irqs, SAMSUNG_PWM_NUM * sizeof(*irqs));
 
+       pwm.timerclk = clk_get(NULL, "timers");
+       if (IS_ERR(pwm.timerclk))
+               panic("failed to get timers clock for timer");
+
        _samsung_pwm_clocksource_init();
 }
 
@@ -447,6 +447,10 @@ static void __init samsung_pwm_alloc(struct device_node *np,
                return;
        }
 
+       pwm.timerclk = of_clk_get_by_name(np, "timers");
+       if (IS_ERR(pwm.timerclk))
+               panic("failed to get timers clock for timer");
+
        _samsung_pwm_clocksource_init();
 }
 
index 08d0c418c94ae5ed3e4c5791ab929fc6501d0de3..0965e9848b3d1893df4511f4ed70e1d39ffcbc96 100644 (file)
@@ -37,6 +37,7 @@
 
 struct sh_cmt_priv {
        void __iomem *mapbase;
+       void __iomem *mapbase_str;
        struct clk *clk;
        unsigned long width; /* 16 or 32 bit version of hardware block */
        unsigned long overflow_bit;
@@ -79,6 +80,12 @@ struct sh_cmt_priv {
  * CMCSR 0xffca0060 16-bit
  * CMCNT 0xffca0064 32-bit
  * CMCOR 0xffca0068 32-bit
+ *
+ * "32-bit counter and 32-bit control" as found on r8a73a4 and r8a7790:
+ * CMSTR 0xffca0500 32-bit
+ * CMCSR 0xffca0510 32-bit
+ * CMCNT 0xffca0514 32-bit
+ * CMCOR 0xffca0518 32-bit
  */
 
 static unsigned long sh_cmt_read16(void __iomem *base, unsigned long offs)
@@ -109,9 +116,7 @@ static void sh_cmt_write32(void __iomem *base, unsigned long offs,
 
 static inline unsigned long sh_cmt_read_cmstr(struct sh_cmt_priv *p)
 {
-       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
-
-       return p->read_control(p->mapbase - cfg->channel_offset, 0);
+       return p->read_control(p->mapbase_str, 0);
 }
 
 static inline unsigned long sh_cmt_read_cmcsr(struct sh_cmt_priv *p)
@@ -127,9 +132,7 @@ static inline unsigned long sh_cmt_read_cmcnt(struct sh_cmt_priv *p)
 static inline void sh_cmt_write_cmstr(struct sh_cmt_priv *p,
                                      unsigned long value)
 {
-       struct sh_timer_config *cfg = p->pdev->dev.platform_data;
-
-       p->write_control(p->mapbase - cfg->channel_offset, 0, value);
+       p->write_control(p->mapbase_str, 0, value);
 }
 
 static inline void sh_cmt_write_cmcsr(struct sh_cmt_priv *p,
@@ -676,7 +679,7 @@ static int sh_cmt_register(struct sh_cmt_priv *p, char *name,
 static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
 {
        struct sh_timer_config *cfg = pdev->dev.platform_data;
-       struct resource *res;
+       struct resource *res, *res2;
        int irq, ret;
        ret = -ENXIO;
 
@@ -694,6 +697,9 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
                goto err0;
        }
 
+       /* optional resource for the shared timer start/stop register */
+       res2 = platform_get_resource(p->pdev, IORESOURCE_MEM, 1);
+
        irq = platform_get_irq(p->pdev, 0);
        if (irq < 0) {
                dev_err(&p->pdev->dev, "failed to get irq\n");
@@ -707,6 +713,15 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
                goto err0;
        }
 
+       /* map second resource for CMSTR */
+       p->mapbase_str = ioremap_nocache(res2 ? res2->start :
+                                        res->start - cfg->channel_offset,
+                                        res2 ? resource_size(res2) : 2);
+       if (p->mapbase_str == NULL) {
+               dev_err(&p->pdev->dev, "failed to remap I/O second memory\n");
+               goto err1;
+       }
+
        /* request irq using setup_irq() (too early for request_irq()) */
        p->irqaction.name = dev_name(&p->pdev->dev);
        p->irqaction.handler = sh_cmt_interrupt;
@@ -719,11 +734,17 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
        if (IS_ERR(p->clk)) {
                dev_err(&p->pdev->dev, "cannot get clock\n");
                ret = PTR_ERR(p->clk);
-               goto err1;
+               goto err2;
        }
 
-       p->read_control = sh_cmt_read16;
-       p->write_control = sh_cmt_write16;
+       if (res2 && (resource_size(res2) == 4)) {
+               /* assume both CMSTR and CMCSR to be 32-bit */
+               p->read_control = sh_cmt_read32;
+               p->write_control = sh_cmt_write32;
+       } else {
+               p->read_control = sh_cmt_read16;
+               p->write_control = sh_cmt_write16;
+       }
 
        if (resource_size(res) == 6) {
                p->width = 16;
@@ -752,22 +773,23 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
                              cfg->clocksource_rating);
        if (ret) {
                dev_err(&p->pdev->dev, "registration failed\n");
-               goto err2;
+               goto err3;
        }
        p->cs_enabled = false;
 
        ret = setup_irq(irq, &p->irqaction);
        if (ret) {
                dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
-               goto err2;
+               goto err3;
        }
 
        platform_set_drvdata(pdev, p);
 
        return 0;
-err2:
+err3:
        clk_put(p->clk);
-
+err2:
+       iounmap(p->mapbase_str);
 err1:
        iounmap(p->mapbase);
 err0:
index 847cab6f6e31009f9a97560642ee4685497ead18..0198504ef6b02388c8847bc4897eca4e58328479 100644 (file)
  *
  * Timer 0 is used as free-running clocksource, while timer 1 is
  * used as clock_event_device.
+ *
+ * ---
+ * Clocksource driver for Armada 370 and Armada XP SoC.
+ * This driver implements one compatible string for each SoC, given
+ * each has its own characteristics:
+ *
+ *   * Armada 370 has no 25 MHz fixed timer.
+ *
+ *   * Armada XP cannot work properly without such 25 MHz fixed timer as
+ *     doing otherwise leads to using a clocksource whose frequency varies
+ *     when doing cpufreq frequency changes.
+ *
+ * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
  */
 
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sched_clock.h>
 #include <linux/percpu.h>
-#include <linux/time-armada-370-xp.h>
 
 /*
  * Timer block registers.
  */
 #define TIMER_CTRL_OFF         0x0000
-#define  TIMER0_EN              0x0001
-#define  TIMER0_RELOAD_EN       0x0002
-#define  TIMER0_25MHZ            0x0800
+#define  TIMER0_EN              BIT(0)
+#define  TIMER0_RELOAD_EN       BIT(1)
+#define  TIMER0_25MHZ            BIT(11)
 #define  TIMER0_DIV(div)         ((div) << 19)
-#define  TIMER1_EN              0x0004
-#define  TIMER1_RELOAD_EN       0x0008
-#define  TIMER1_25MHZ            0x1000
+#define  TIMER1_EN              BIT(2)
+#define  TIMER1_RELOAD_EN       BIT(3)
+#define  TIMER1_25MHZ            BIT(12)
 #define  TIMER1_DIV(div)         ((div) << 22)
 #define TIMER_EVENTS_STATUS    0x0004
 #define  TIMER0_CLR_MASK         (~0x1)
@@ -72,6 +84,18 @@ static u32 ticks_per_jiffy;
 
 static struct clock_event_device __percpu *armada_370_xp_evt;
 
+static void timer_ctrl_clrset(u32 clr, u32 set)
+{
+       writel((readl(timer_base + TIMER_CTRL_OFF) & ~clr) | set,
+               timer_base + TIMER_CTRL_OFF);
+}
+
+static void local_timer_ctrl_clrset(u32 clr, u32 set)
+{
+       writel((readl(local_base + TIMER_CTRL_OFF) & ~clr) | set,
+               local_base + TIMER_CTRL_OFF);
+}
+
 static u32 notrace armada_370_xp_read_sched_clock(void)
 {
        return ~readl(timer_base + TIMER0_VAL_OFF);
@@ -84,7 +108,6 @@ static int
 armada_370_xp_clkevt_next_event(unsigned long delta,
                                struct clock_event_device *dev)
 {
-       u32 u;
        /*
         * Clear clockevent timer interrupt.
         */
@@ -98,11 +121,8 @@ armada_370_xp_clkevt_next_event(unsigned long delta,
        /*
         * Enable the timer.
         */
-       u = readl(local_base + TIMER_CTRL_OFF);
-       u = ((u & ~TIMER0_RELOAD_EN) | TIMER0_EN |
-            TIMER0_DIV(TIMER_DIVIDER_SHIFT));
-       writel(u, local_base + TIMER_CTRL_OFF);
-
+       local_timer_ctrl_clrset(TIMER0_RELOAD_EN,
+                               TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT));
        return 0;
 }
 
@@ -110,8 +130,6 @@ static void
 armada_370_xp_clkevt_mode(enum clock_event_mode mode,
                          struct clock_event_device *dev)
 {
-       u32 u;
-
        if (mode == CLOCK_EVT_MODE_PERIODIC) {
 
                /*
@@ -123,18 +141,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode,
                /*
                 * Enable timer.
                 */
-
-               u = readl(local_base + TIMER_CTRL_OFF);
-
-               writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
-                       TIMER0_DIV(TIMER_DIVIDER_SHIFT)),
-                       local_base + TIMER_CTRL_OFF);
+               local_timer_ctrl_clrset(0, TIMER0_RELOAD_EN |
+                                          TIMER0_EN |
+                                          TIMER0_DIV(TIMER_DIVIDER_SHIFT));
        } else {
                /*
                 * Disable timer.
                 */
-               u = readl(local_base + TIMER_CTRL_OFF);
-               writel(u & ~TIMER0_EN, local_base + TIMER_CTRL_OFF);
+               local_timer_ctrl_clrset(TIMER0_EN, 0);
 
                /*
                 * ACK pending timer interrupt.
@@ -163,14 +177,14 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
  */
 static int armada_370_xp_timer_setup(struct clock_event_device *evt)
 {
-       u32 u;
+       u32 clr = 0, set = 0;
        int cpu = smp_processor_id();
 
-       u = readl(local_base + TIMER_CTRL_OFF);
        if (timer25Mhz)
-               writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
+               set = TIMER0_25MHZ;
        else
-               writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF);
+               clr = TIMER0_25MHZ;
+       local_timer_ctrl_clrset(clr, set);
 
        evt->name               = "armada_370_xp_per_cpu_tick",
        evt->features           = CLOCK_EVT_FEAT_ONESHOT |
@@ -217,36 +231,21 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = {
        .notifier_call = armada_370_xp_timer_cpu_notify,
 };
 
-void __init armada_370_xp_timer_init(void)
+static void __init armada_370_xp_timer_common_init(struct device_node *np)
 {
-       u32 u;
-       struct device_node *np;
+       u32 clr = 0, set = 0;
        int res;
 
-       np = of_find_compatible_node(NULL, NULL, "marvell,armada-370-xp-timer");
        timer_base = of_iomap(np, 0);
        WARN_ON(!timer_base);
        local_base = of_iomap(np, 1);
 
-       if (of_find_property(np, "marvell,timer-25Mhz", NULL)) {
-               /* The fixed 25MHz timer is available so let's use it */
-               u = readl(timer_base + TIMER_CTRL_OFF);
-               writel(u | TIMER0_25MHZ,
-                      timer_base + TIMER_CTRL_OFF);
-               timer_clk = 25000000;
-       } else {
-               unsigned long rate = 0;
-               struct clk *clk = of_clk_get(np, 0);
-               WARN_ON(IS_ERR(clk));
-               rate =  clk_get_rate(clk);
-
-               u = readl(timer_base + TIMER_CTRL_OFF);
-               writel(u & ~(TIMER0_25MHZ),
-                      timer_base + TIMER_CTRL_OFF);
-
-               timer_clk = rate / TIMER_DIVIDER;
-               timer25Mhz = false;
-       }
+       if (timer25Mhz)
+               set = TIMER0_25MHZ;             
+       else
+               clr = TIMER0_25MHZ;
+       timer_ctrl_clrset(clr, set);
+       local_timer_ctrl_clrset(clr, set);
 
        /*
         * We use timer 0 as clocksource, and private(local) timer 0
@@ -268,10 +267,8 @@ void __init armada_370_xp_timer_init(void)
        writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
        writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
 
-       u = readl(timer_base + TIMER_CTRL_OFF);
-
-       writel((u | TIMER0_EN | TIMER0_RELOAD_EN |
-               TIMER0_DIV(TIMER_DIVIDER_SHIFT)), timer_base + TIMER_CTRL_OFF);
+       timer_ctrl_clrset(0, TIMER0_EN | TIMER0_RELOAD_EN |
+                            TIMER0_DIV(TIMER_DIVIDER_SHIFT));
 
        clocksource_mmio_init(timer_base + TIMER0_VAL_OFF,
                              "armada_370_xp_clocksource",
@@ -293,3 +290,29 @@ void __init armada_370_xp_timer_init(void)
        if (!res)
                armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
 }
+
+static void __init armada_xp_timer_init(struct device_node *np)
+{
+       struct clk *clk = of_clk_get_by_name(np, "fixed");
+
+       /* The 25Mhz fixed clock is mandatory, and must always be available */
+       BUG_ON(IS_ERR(clk));
+       timer_clk = clk_get_rate(clk);
+
+       armada_370_xp_timer_common_init(np);
+}
+CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
+                      armada_xp_timer_init);
+
+static void __init armada_370_timer_init(struct device_node *np)
+{
+       struct clk *clk = of_clk_get(np, 0);
+
+       BUG_ON(IS_ERR(clk));
+       timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
+       timer25Mhz = false;
+
+       armada_370_xp_timer_common_init(np);
+}
+CLOCKSOURCE_OF_DECLARE(armada_370, "marvell,armada-370-timer",
+                      armada_370_timer_init);
index 5c75e3147a607ca70a6d880500f9a9b6fb336316..43c24aa756f6f29935af8eb0614945a442a36a19 100644 (file)
@@ -280,13 +280,6 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
        switch (state) {
 
        case CPUFREQ_PRECHANGE:
-               if (WARN(policy->transition_ongoing ==
-                                       cpumask_weight(policy->cpus),
-                               "In middle of another frequency transition\n"))
-                       return;
-
-               policy->transition_ongoing++;
-
                /* detect if the driver reported a value as "old frequency"
                 * which is not equal to what the cpufreq core thinks is
                 * "old frequency".
@@ -306,12 +299,6 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
                break;
 
        case CPUFREQ_POSTCHANGE:
-               if (WARN(!policy->transition_ongoing,
-                               "No frequency transition in progress\n"))
-                       return;
-
-               policy->transition_ongoing--;
-
                adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
                pr_debug("FREQ: %lu - CPU: %lu", (unsigned long)freqs->new,
                        (unsigned long)freqs->cpu);
@@ -437,7 +424,7 @@ static int __cpufreq_set_policy(struct cpufreq_policy *policy,
 static ssize_t store_##file_name                                       \
 (struct cpufreq_policy *policy, const char *buf, size_t count)         \
 {                                                                      \
-       unsigned int ret;                                               \
+       int ret;                                                        \
        struct cpufreq_policy new_policy;                               \
                                                                        \
        ret = cpufreq_get_policy(&new_policy, policy->cpu);             \
@@ -490,7 +477,7 @@ static ssize_t show_scaling_governor(struct cpufreq_policy *policy, char *buf)
 static ssize_t store_scaling_governor(struct cpufreq_policy *policy,
                                        const char *buf, size_t count)
 {
-       unsigned int ret;
+       int ret;
        char    str_governor[16];
        struct cpufreq_policy new_policy;
 
@@ -694,8 +681,13 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
        struct freq_attr *fattr = to_attr(attr);
        ssize_t ret = -EINVAL;
 
+       get_online_cpus();
+
+       if (!cpu_online(policy->cpu))
+               goto unlock;
+
        if (!down_read_trylock(&cpufreq_rwsem))
-               goto exit;
+               goto unlock;
 
        if (lock_policy_rwsem_write(policy->cpu) < 0)
                goto up_read;
@@ -709,7 +701,9 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
 
 up_read:
        up_read(&cpufreq_rwsem);
-exit:
+unlock:
+       put_online_cpus();
+
        return ret;
 }
 
@@ -912,11 +906,11 @@ static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
        struct cpufreq_policy *policy;
        unsigned long flags;
 
-       write_lock_irqsave(&cpufreq_driver_lock, flags);
+       read_lock_irqsave(&cpufreq_driver_lock, flags);
 
        policy = per_cpu(cpufreq_cpu_data_fallback, cpu);
 
-       write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+       read_unlock_irqrestore(&cpufreq_driver_lock, flags);
 
        return policy;
 }
@@ -953,6 +947,21 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
        kfree(policy);
 }
 
+static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
+{
+       if (cpu == policy->cpu)
+               return;
+
+       policy->last_cpu = policy->cpu;
+       policy->cpu = cpu;
+
+#ifdef CONFIG_CPU_FREQ_TABLE
+       cpufreq_frequency_table_update_policy_cpu(policy);
+#endif
+       blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
+                       CPUFREQ_UPDATE_POLICY_CPU, policy);
+}
+
 static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
                             bool frozen)
 {
@@ -1006,7 +1015,18 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif,
        if (!policy)
                goto nomem_out;
 
-       policy->cpu = cpu;
+
+       /*
+        * In the resume path, since we restore a saved policy, the assignment
+        * to policy->cpu is like an update of the existing policy, rather than
+        * the creation of a brand new one. So we need to perform this update
+        * by invoking update_policy_cpu().
+        */
+       if (frozen && cpu != policy->cpu)
+               update_policy_cpu(policy, cpu);
+       else
+               policy->cpu = cpu;
+
        policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
        cpumask_copy(policy->cpus, cpumask_of(cpu));
 
@@ -1098,18 +1118,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
        return __cpufreq_add_dev(dev, sif, false);
 }
 
-static void update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu)
-{
-       policy->last_cpu = policy->cpu;
-       policy->cpu = cpu;
-
-#ifdef CONFIG_CPU_FREQ_TABLE
-       cpufreq_frequency_table_update_policy_cpu(policy);
-#endif
-       blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
-                       CPUFREQ_UPDATE_POLICY_CPU, policy);
-}
-
 static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
                                           unsigned int old_cpu, bool frozen)
 {
@@ -1141,22 +1149,14 @@ static int cpufreq_nominate_new_policy_cpu(struct cpufreq_policy *policy,
        return cpu_dev->id;
 }
 
-/**
- * __cpufreq_remove_dev - remove a CPU device
- *
- * Removes the cpufreq interface for a CPU device.
- * Caller should already have policy_rwsem in write mode for this CPU.
- * This routine frees the rwsem before returning.
- */
-static int __cpufreq_remove_dev(struct device *dev,
-                               struct subsys_interface *sif, bool frozen)
+static int __cpufreq_remove_dev_prepare(struct device *dev,
+                                       struct subsys_interface *sif,
+                                       bool frozen)
 {
        unsigned int cpu = dev->id, cpus;
        int new_cpu, ret;
        unsigned long flags;
        struct cpufreq_policy *policy;
-       struct kobject *kobj;
-       struct completion *cmp;
 
        pr_debug("%s: unregistering CPU %u\n", __func__, cpu);
 
@@ -1196,8 +1196,9 @@ static int __cpufreq_remove_dev(struct device *dev,
                cpumask_clear_cpu(cpu, policy->cpus);
        unlock_policy_rwsem_write(cpu);
 
-       if (cpu != policy->cpu && !frozen) {
-               sysfs_remove_link(&dev->kobj, "cpufreq");
+       if (cpu != policy->cpu) {
+               if (!frozen)
+                       sysfs_remove_link(&dev->kobj, "cpufreq");
        } else if (cpus > 1) {
 
                new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu, frozen);
@@ -1213,6 +1214,33 @@ static int __cpufreq_remove_dev(struct device *dev,
                }
        }
 
+       return 0;
+}
+
+static int __cpufreq_remove_dev_finish(struct device *dev,
+                                      struct subsys_interface *sif,
+                                      bool frozen)
+{
+       unsigned int cpu = dev->id, cpus;
+       int ret;
+       unsigned long flags;
+       struct cpufreq_policy *policy;
+       struct kobject *kobj;
+       struct completion *cmp;
+
+       read_lock_irqsave(&cpufreq_driver_lock, flags);
+       policy = per_cpu(cpufreq_cpu_data, cpu);
+       read_unlock_irqrestore(&cpufreq_driver_lock, flags);
+
+       if (!policy) {
+               pr_debug("%s: No cpu_data found\n", __func__);
+               return -EINVAL;
+       }
+
+       lock_policy_rwsem_read(cpu);
+       cpus = cpumask_weight(policy->cpus);
+       unlock_policy_rwsem_read(cpu);
+
        /* If cpu is last user of policy, free policy */
        if (cpus == 1) {
                if (cpufreq_driver->target) {
@@ -1272,6 +1300,27 @@ static int __cpufreq_remove_dev(struct device *dev,
        return 0;
 }
 
+/**
+ * __cpufreq_remove_dev - remove a CPU device
+ *
+ * Removes the cpufreq interface for a CPU device.
+ * Caller should already have policy_rwsem in write mode for this CPU.
+ * This routine frees the rwsem before returning.
+ */
+static inline int __cpufreq_remove_dev(struct device *dev,
+                                      struct subsys_interface *sif,
+                                      bool frozen)
+{
+       int ret;
+
+       ret = __cpufreq_remove_dev_prepare(dev, sif, frozen);
+
+       if (!ret)
+               ret = __cpufreq_remove_dev_finish(dev, sif, frozen);
+
+       return ret;
+}
+
 static int cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
 {
        unsigned int cpu = dev->id;
@@ -1610,8 +1659,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
 
        if (cpufreq_disabled())
                return -ENODEV;
-       if (policy->transition_ongoing)
-               return -EBUSY;
 
        /* Make sure that target_freq is within supported range */
        if (target_freq > policy->max)
@@ -1692,8 +1739,9 @@ static int __cpufreq_governor(struct cpufreq_policy *policy,
                                                policy->cpu, event);
 
        mutex_lock(&cpufreq_governor_lock);
-       if ((!policy->governor_enabled && (event == CPUFREQ_GOV_STOP)) ||
-           (policy->governor_enabled && (event == CPUFREQ_GOV_START))) {
+       if ((policy->governor_enabled && event == CPUFREQ_GOV_START)
+           || (!policy->governor_enabled
+           && (event == CPUFREQ_GOV_LIMITS || event == CPUFREQ_GOV_STOP))) {
                mutex_unlock(&cpufreq_governor_lock);
                return -EBUSY;
        }
@@ -1994,7 +2042,11 @@ static int cpufreq_cpu_callback(struct notifier_block *nfb,
                        break;
 
                case CPU_DOWN_PREPARE:
-                       __cpufreq_remove_dev(dev, NULL, frozen);
+                       __cpufreq_remove_dev_prepare(dev, NULL, frozen);
+                       break;
+
+               case CPU_POST_DEAD:
+                       __cpufreq_remove_dev_finish(dev, NULL, frozen);
                        break;
 
                case CPU_DOWN_FAILED:
index 04452f026ed085a7b61f87c623c8677a2e242864..4cf0d2805cb2a10baecfb7ba3e900e3a28d1a7bd 100644 (file)
@@ -74,7 +74,7 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
        for (i = 0; i < stat->state_num; i++) {
                len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
                        (unsigned long long)
-                       cputime64_to_clock_t(stat->time_in_state[i]));
+                       jiffies_64_to_clock_t(stat->time_in_state[i]));
        }
        return len;
 }
index 6efd96c196b2efff80e41b1851e4b445350ccf5b..9733f29ed148f840a35171df38e32cbd1ce7bca8 100644 (file)
@@ -522,6 +522,11 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
        ICPU(0x2a, default_policy),
        ICPU(0x2d, default_policy),
        ICPU(0x3a, default_policy),
+       ICPU(0x3c, default_policy),
+       ICPU(0x3e, default_policy),
+       ICPU(0x3f, default_policy),
+       ICPU(0x45, default_policy),
+       ICPU(0x46, default_policy),
        {}
 };
 MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
index b3302193c15a73861422c9bdff9b100efbca6713..8e366032230893dc35c0d03f55138a20e0a33f07 100644 (file)
@@ -27,3 +27,13 @@ config ARM_U8500_CPUIDLE
        help
          Select this to enable cpuidle for ST-E u8500 processors
 
+config CPU_IDLE_BIG_LITTLE
+       bool "Support for ARM big.LITTLE processors"
+       depends on ARCH_VEXPRESS_TC2_PM
+       select ARM_CPU_SUSPEND
+       select CPU_IDLE_MULTIPLE_DRIVERS
+       help
+         Select this option to enable CPU idle driver for big.LITTLE based
+         ARM systems. Driver manages CPUs coordination through MCPM and
+         define different C-states for little and big cores through the
+         multiple CPU idle drivers infrastructure.
index 0b9d200c7e454eefd4864abbc83bfee7f7dcb129..cea5ef58876d8202521545008afb9026565fbe7e 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE)    += cpuidle-calxeda.o
 obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)     += cpuidle-kirkwood.o
 obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)         += cpuidle-zynq.o
 obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
+obj-$(CONFIG_CPU_IDLE_BIG_LITTLE)      += cpuidle-big_little.o
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
new file mode 100644 (file)
index 0000000..b45fc62
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013 ARM/Linaro
+ *
+ * Authors: Daniel Lezcano <daniel.lezcano@linaro.org>
+ *          Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ *          Nicolas Pitre <nicolas.pitre@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Maintainer: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+ * Maintainer: Daniel Lezcano <daniel.lezcano@linaro.org>
+ */
+#include <linux/cpuidle.h>
+#include <linux/cpu_pm.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include <asm/cpu.h>
+#include <asm/cputype.h>
+#include <asm/cpuidle.h>
+#include <asm/mcpm.h>
+#include <asm/smp_plat.h>
+#include <asm/suspend.h>
+
+static int bl_enter_powerdown(struct cpuidle_device *dev,
+                             struct cpuidle_driver *drv, int idx);
+
+/*
+ * NB: Owing to current menu governor behaviour big and LITTLE
+ * index 1 states have to define exit_latency and target_residency for
+ * cluster state since, when all CPUs in a cluster hit it, the cluster
+ * can be shutdown. This means that when a single CPU enters this state
+ * the exit_latency and target_residency values are somewhat overkill.
+ * There is no notion of cluster states in the menu governor, so CPUs
+ * have to define CPU states where possibly the cluster will be shutdown
+ * depending on the state of other CPUs. idle states entry and exit happen
+ * at random times; however the cluster state provides target_residency
+ * values as if all CPUs in a cluster enter the state at once; this is
+ * somewhat optimistic and behaviour should be fixed either in the governor
+ * or in the MCPM back-ends.
+ * To make this driver 100% generic the number of states and the exit_latency
+ * target_residency values must be obtained from device tree bindings.
+ *
+ * exit_latency: refers to the TC2 vexpress test chip and depends on the
+ * current cluster operating point. It is the time it takes to get the CPU
+ * up and running when the CPU is powered up on cluster wake-up from shutdown.
+ * Current values for big and LITTLE clusters are provided for clusters
+ * running at default operating points.
+ *
+ * target_residency: it is the minimum amount of time the cluster has
+ * to be down to break even in terms of power consumption. cluster
+ * shutdown has inherent dynamic power costs (L2 writebacks to DRAM
+ * being the main factor) that depend on the current operating points.
+ * The current values for both clusters are provided for a CPU whose half
+ * of L2 lines are dirty and require cleaning to DRAM, and takes into
+ * account leakage static power values related to the vexpress TC2 testchip.
+ */
+static struct cpuidle_driver bl_idle_little_driver = {
+       .name = "little_idle",
+       .owner = THIS_MODULE,
+       .states[0] = ARM_CPUIDLE_WFI_STATE,
+       .states[1] = {
+               .enter                  = bl_enter_powerdown,
+               .exit_latency           = 700,
+               .target_residency       = 2500,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID |
+                                         CPUIDLE_FLAG_TIMER_STOP,
+               .name                   = "C1",
+               .desc                   = "ARM little-cluster power down",
+       },
+       .state_count = 2,
+};
+
+static struct cpuidle_driver bl_idle_big_driver = {
+       .name = "big_idle",
+       .owner = THIS_MODULE,
+       .states[0] = ARM_CPUIDLE_WFI_STATE,
+       .states[1] = {
+               .enter                  = bl_enter_powerdown,
+               .exit_latency           = 500,
+               .target_residency       = 2000,
+               .flags                  = CPUIDLE_FLAG_TIME_VALID |
+                                         CPUIDLE_FLAG_TIMER_STOP,
+               .name                   = "C1",
+               .desc                   = "ARM big-cluster power down",
+       },
+       .state_count = 2,
+};
+
+/*
+ * notrace prevents trace shims from getting inserted where they
+ * should not. Global jumps and ldrex/strex must not be inserted
+ * in power down sequences where caches and MMU may be turned off.
+ */
+static int notrace bl_powerdown_finisher(unsigned long arg)
+{
+       /* MCPM works with HW CPU identifiers */
+       unsigned int mpidr = read_cpuid_mpidr();
+       unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+       unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+
+       mcpm_set_entry_vector(cpu, cluster, cpu_resume);
+
+       /*
+        * Residency value passed to mcpm_cpu_suspend back-end
+        * has to be given clear semantics. Set to 0 as a
+        * temporary value.
+        */
+       mcpm_cpu_suspend(0);
+
+       /* return value != 0 means failure */
+       return 1;
+}
+
+/**
+ * bl_enter_powerdown - Programs CPU to enter the specified state
+ * @dev: cpuidle device
+ * @drv: The target state to be programmed
+ * @idx: state index
+ *
+ * Called from the CPUidle framework to program the device to the
+ * specified target state selected by the governor.
+ */
+static int bl_enter_powerdown(struct cpuidle_device *dev,
+                               struct cpuidle_driver *drv, int idx)
+{
+       cpu_pm_enter();
+
+       cpu_suspend(0, bl_powerdown_finisher);
+
+       /* signals the MCPM core that CPU is out of low power state */
+       mcpm_cpu_powered_up();
+
+       cpu_pm_exit();
+
+       return idx;
+}
+
+static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int cpu_id)
+{
+       struct cpuinfo_arm *cpu_info;
+       struct cpumask *cpumask;
+       unsigned long cpuid;
+       int cpu;
+
+       cpumask = kzalloc(cpumask_size(), GFP_KERNEL);
+       if (!cpumask)
+               return -ENOMEM;
+
+       for_each_possible_cpu(cpu) {
+               cpu_info = &per_cpu(cpu_data, cpu);
+               cpuid = is_smp() ? cpu_info->cpuid : read_cpuid_id();
+
+               /* read cpu id part number */
+               if ((cpuid & 0xFFF0) == cpu_id)
+                       cpumask_set_cpu(cpu, cpumask);
+       }
+
+       drv->cpumask = cpumask;
+
+       return 0;
+}
+
+static int __init bl_idle_init(void)
+{
+       int ret;
+
+       /*
+        * Initialize the driver just for a compliant set of machines
+        */
+       if (!of_machine_is_compatible("arm,vexpress,v2p-ca15_a7"))
+               return -ENODEV;
+       /*
+        * For now the differentiation between little and big cores
+        * is based on the part number. A7 cores are considered little
+        * cores, A15 are considered big cores. This distinction may
+        * evolve in the future with a more generic matching approach.
+        */
+       ret = bl_idle_driver_init(&bl_idle_little_driver,
+                                 ARM_CPU_PART_CORTEX_A7);
+       if (ret)
+               return ret;
+
+       ret = bl_idle_driver_init(&bl_idle_big_driver, ARM_CPU_PART_CORTEX_A15);
+       if (ret)
+               goto out_uninit_little;
+
+       ret = cpuidle_register(&bl_idle_little_driver, NULL);
+       if (ret)
+               goto out_uninit_big;
+
+       ret = cpuidle_register(&bl_idle_big_driver, NULL);
+       if (ret)
+               goto out_unregister_little;
+
+       return 0;
+
+out_unregister_little:
+       cpuidle_unregister(&bl_idle_little_driver);
+out_uninit_big:
+       kfree(bl_idle_big_driver.cpumask);
+out_uninit_little:
+       kfree(bl_idle_little_driver.cpumask);
+
+       return ret;
+}
+device_initcall(bl_idle_init);
index 3ac499d5a20784c0432e91f51575022f95c3d3d5..6e11701f0fcaef8430e2e8544108df8e337ebbed 100644 (file)
@@ -331,7 +331,8 @@ struct cpuidle_driver *cpuidle_driver_ref(void)
        spin_lock(&cpuidle_driver_lock);
 
        drv = cpuidle_get_driver();
-       drv->refcnt++;
+       if (drv)
+               drv->refcnt++;
 
        spin_unlock(&cpuidle_driver_lock);
        return drv;
index daa4da281e5ebedf83e791b2e94af1ed6f45d990..526ec77c7ba032b9af1c6772484028051a4950ef 100644 (file)
@@ -308,6 +308,15 @@ config DMA_JZ4740
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
 
+config K3_DMA
+       tristate "Hisilicon K3 DMA support"
+       depends on ARCH_HI3xxx
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Support the DMA engine for Hisilicon K3 platform
+         devices.
+
 config DMA_ENGINE
        bool
 
index 6d62ec30c4bc594fcd02bdb1ce79e56a28b9a41f..db89035b362612304a3334ab5c9834770cab1303 100644 (file)
@@ -40,3 +40,4 @@ obj-$(CONFIG_DMA_OMAP) += omap-dma.o
 obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
 obj-$(CONFIG_TI_CPPI41) += cppi41.o
+obj-$(CONFIG_K3_DMA) += k3dma.o
index 5a18f82f732af57a319628190713e6bd054cf8b3..e69b03c0fa50cfae7ca6528f5eef0d9eaf1d8d53 100644 (file)
@@ -43,7 +43,6 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
        struct list_head resource_list;
        struct resource_list_entry *rentry;
        resource_size_t mem = 0, irq = 0;
-       u32 vendor_id;
        int ret;
 
        if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info))
@@ -73,9 +72,8 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
        if (si->mmio_base_low != mem || si->gsi_interrupt != irq)
                return 0;
 
-       vendor_id = le32_to_cpu(grp->vendor_id);
        dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n",
-               (char *)&vendor_id, grp->device_id, grp->revision);
+               (char *)&grp->vendor_id, grp->device_id, grp->revision);
 
        /* Check if the request line range is available */
        if (si->base_request_line == 0 && si->num_handshake_signals == 0)
index 06fe45c74de57b3151e8520e9d7154f7ba7906e2..fce46c5bf1c74e3d76accde7570ffa2d423eb9f1 100644 (file)
@@ -24,6 +24,7 @@
  *
  * Documentation: ARM DDI 0196G == PL080
  * Documentation: ARM DDI 0218E == PL081
+ * Documentation: S3C6410 User's Manual == PL080S
  *
  * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any
  * channel.
  *
  * The PL080 has a dual bus master, PL081 has a single master.
  *
+ * PL080S is a version modified by Samsung and used in S3C64xx SoCs.
+ * It differs in following aspects:
+ * - CH_CONFIG register at different offset,
+ * - separate CH_CONTROL2 register for transfer size,
+ * - bigger maximum transfer size,
+ * - 8-word aligned LLI, instead of 4-word, due to extra CCTL2 word,
+ * - no support for peripheral flow control.
+ *
  * Memory to peripheral transfer may be visualized as
  *     Get data from memory to DMAC
  *     Until no data left
  *  - Peripheral flow control: the transfer size is ignored (and should be
  *    zero).  The data is transferred from the current LLI entry, until
  *    after the final transfer signalled by LBREQ or LSREQ.  The DMAC
- *    will then move to the next LLI entry.
- *
- * Global TODO:
- * - Break out common code from arch/arm/mach-s3c64xx and share
+ *    will then move to the next LLI entry. Unsupported by PL080S.
  */
 #include <linux/amba/bus.h>
 #include <linux/amba/pl08x.h>
@@ -100,24 +106,16 @@ struct pl08x_driver_data;
  * @nomadik: whether the channels have Nomadik security extension bits
  *     that need to be checked for permission before use and some registers are
  *     missing
+ * @pl080s: whether this version is a PL080S, which has separate register and
+ *     LLI word for transfer size.
  */
 struct vendor_data {
+       u8 config_offset;
        u8 channels;
        bool dualmaster;
        bool nomadik;
-};
-
-/*
- * PL08X private data structures
- * An LLI struct - see PL08x TRM.  Note that next uses bit[0] as a bus bit,
- * start & end do not - their bus bit info is in cctl.  Also note that these
- * are fixed 32-bit quantities.
- */
-struct pl08x_lli {
-       u32 src;
-       u32 dst;
-       u32 lli;
-       u32 cctl;
+       bool pl080s;
+       u32 max_transfer_size;
 };
 
 /**
@@ -133,6 +131,8 @@ struct pl08x_bus_data {
        u8 buswidth;
 };
 
+#define IS_BUS_ALIGNED(bus) IS_ALIGNED((bus)->addr, (bus)->buswidth)
+
 /**
  * struct pl08x_phy_chan - holder for the physical channels
  * @id: physical index to this channel
@@ -145,6 +145,7 @@ struct pl08x_bus_data {
 struct pl08x_phy_chan {
        unsigned int id;
        void __iomem *base;
+       void __iomem *reg_config;
        spinlock_t lock;
        struct pl08x_dma_chan *serving;
        bool locked;
@@ -174,12 +175,13 @@ struct pl08x_sg {
  * @ccfg: config reg values for current txd
  * @done: this marks completed descriptors, which should not have their
  *   mux released.
+ * @cyclic: indicate cyclic transfers
  */
 struct pl08x_txd {
        struct virt_dma_desc vd;
        struct list_head dsg_list;
        dma_addr_t llis_bus;
-       struct pl08x_lli *llis_va;
+       u32 *llis_va;
        /* Default cctl value for LLIs */
        u32 cctl;
        /*
@@ -188,6 +190,7 @@ struct pl08x_txd {
         */
        u32 ccfg;
        bool done;
+       bool cyclic;
 };
 
 /**
@@ -263,17 +266,29 @@ struct pl08x_driver_data {
        struct dma_pool *pool;
        u8 lli_buses;
        u8 mem_buses;
+       u8 lli_words;
 };
 
 /*
  * PL08X specific defines
  */
 
-/* Size (bytes) of each LLI buffer allocated for one transfer */
-# define PL08X_LLI_TSFR_SIZE   0x2000
+/* The order of words in an LLI. */
+#define PL080_LLI_SRC          0
+#define PL080_LLI_DST          1
+#define PL080_LLI_LLI          2
+#define PL080_LLI_CCTL         3
+#define PL080S_LLI_CCTL2       4
+
+/* Total words in an LLI. */
+#define PL080_LLI_WORDS                4
+#define PL080S_LLI_WORDS       8
 
-/* Maximum times we call dma_pool_alloc on this pool without freeing */
-#define MAX_NUM_TSFR_LLIS      (PL08X_LLI_TSFR_SIZE/sizeof(struct pl08x_lli))
+/*
+ * Number of LLIs in each LLI buffer allocated for one transfer
+ * (maximum times we call dma_pool_alloc on this pool without freeing)
+ */
+#define MAX_NUM_TSFR_LLIS      512
 #define PL08X_ALIGN            8
 
 static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
@@ -334,10 +349,39 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
 {
        unsigned int val;
 
-       val = readl(ch->base + PL080_CH_CONFIG);
+       val = readl(ch->reg_config);
        return val & PL080_CONFIG_ACTIVE;
 }
 
+static void pl08x_write_lli(struct pl08x_driver_data *pl08x,
+               struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg)
+{
+       if (pl08x->vd->pl080s)
+               dev_vdbg(&pl08x->adev->dev,
+                       "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+                       "clli=0x%08x, cctl=0x%08x, cctl2=0x%08x, ccfg=0x%08x\n",
+                       phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
+                       lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL],
+                       lli[PL080S_LLI_CCTL2], ccfg);
+       else
+               dev_vdbg(&pl08x->adev->dev,
+                       "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
+                       "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
+                       phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
+                       lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg);
+
+       writel_relaxed(lli[PL080_LLI_SRC], phychan->base + PL080_CH_SRC_ADDR);
+       writel_relaxed(lli[PL080_LLI_DST], phychan->base + PL080_CH_DST_ADDR);
+       writel_relaxed(lli[PL080_LLI_LLI], phychan->base + PL080_CH_LLI);
+       writel_relaxed(lli[PL080_LLI_CCTL], phychan->base + PL080_CH_CONTROL);
+
+       if (pl08x->vd->pl080s)
+               writel_relaxed(lli[PL080S_LLI_CCTL2],
+                               phychan->base + PL080S_CH_CONTROL2);
+
+       writel(ccfg, phychan->reg_config);
+}
+
 /*
  * Set the initial DMA register values i.e. those for the first LLI
  * The next LLI pointer and the configuration interrupt bit have
@@ -350,7 +394,6 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
        struct pl08x_phy_chan *phychan = plchan->phychan;
        struct virt_dma_desc *vd = vchan_next_desc(&plchan->vc);
        struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
-       struct pl08x_lli *lli;
        u32 val;
 
        list_del(&txd->vd.node);
@@ -361,19 +404,7 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
        while (pl08x_phy_channel_busy(phychan))
                cpu_relax();
 
-       lli = &txd->llis_va[0];
-
-       dev_vdbg(&pl08x->adev->dev,
-               "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
-               "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
-               phychan->id, lli->src, lli->dst, lli->lli, lli->cctl,
-               txd->ccfg);
-
-       writel(lli->src, phychan->base + PL080_CH_SRC_ADDR);
-       writel(lli->dst, phychan->base + PL080_CH_DST_ADDR);
-       writel(lli->lli, phychan->base + PL080_CH_LLI);
-       writel(lli->cctl, phychan->base + PL080_CH_CONTROL);
-       writel(txd->ccfg, phychan->base + PL080_CH_CONFIG);
+       pl08x_write_lli(pl08x, phychan, &txd->llis_va[0], txd->ccfg);
 
        /* Enable the DMA channel */
        /* Do not access config register until channel shows as disabled */
@@ -381,11 +412,11 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
                cpu_relax();
 
        /* Do not access config register until channel shows as inactive */
-       val = readl(phychan->base + PL080_CH_CONFIG);
+       val = readl(phychan->reg_config);
        while ((val & PL080_CONFIG_ACTIVE) || (val & PL080_CONFIG_ENABLE))
-               val = readl(phychan->base + PL080_CH_CONFIG);
+               val = readl(phychan->reg_config);
 
-       writel(val | PL080_CONFIG_ENABLE, phychan->base + PL080_CH_CONFIG);
+       writel(val | PL080_CONFIG_ENABLE, phychan->reg_config);
 }
 
 /*
@@ -404,9 +435,9 @@ static void pl08x_pause_phy_chan(struct pl08x_phy_chan *ch)
        int timeout;
 
        /* Set the HALT bit and wait for the FIFO to drain */
-       val = readl(ch->base + PL080_CH_CONFIG);
+       val = readl(ch->reg_config);
        val |= PL080_CONFIG_HALT;
-       writel(val, ch->base + PL080_CH_CONFIG);
+       writel(val, ch->reg_config);
 
        /* Wait for channel inactive */
        for (timeout = 1000; timeout; timeout--) {
@@ -423,9 +454,9 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
        u32 val;
 
        /* Clear the HALT bit */
-       val = readl(ch->base + PL080_CH_CONFIG);
+       val = readl(ch->reg_config);
        val &= ~PL080_CONFIG_HALT;
-       writel(val, ch->base + PL080_CH_CONFIG);
+       writel(val, ch->reg_config);
 }
 
 /*
@@ -437,12 +468,12 @@ static void pl08x_resume_phy_chan(struct pl08x_phy_chan *ch)
 static void pl08x_terminate_phy_chan(struct pl08x_driver_data *pl08x,
        struct pl08x_phy_chan *ch)
 {
-       u32 val = readl(ch->base + PL080_CH_CONFIG);
+       u32 val = readl(ch->reg_config);
 
        val &= ~(PL080_CONFIG_ENABLE | PL080_CONFIG_ERR_IRQ_MASK |
                 PL080_CONFIG_TC_IRQ_MASK);
 
-       writel(val, ch->base + PL080_CH_CONFIG);
+       writel(val, ch->reg_config);
 
        writel(1 << ch->id, pl08x->base + PL080_ERR_CLEAR);
        writel(1 << ch->id, pl08x->base + PL080_TC_CLEAR);
@@ -453,6 +484,28 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
        /* The source width defines the number of bytes */
        u32 bytes = cctl & PL080_CONTROL_TRANSFER_SIZE_MASK;
 
+       cctl &= PL080_CONTROL_SWIDTH_MASK;
+
+       switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
+       case PL080_WIDTH_8BIT:
+               break;
+       case PL080_WIDTH_16BIT:
+               bytes *= 2;
+               break;
+       case PL080_WIDTH_32BIT:
+               bytes *= 4;
+               break;
+       }
+       return bytes;
+}
+
+static inline u32 get_bytes_in_cctl_pl080s(u32 cctl, u32 cctl1)
+{
+       /* The source width defines the number of bytes */
+       u32 bytes = cctl1 & PL080S_CONTROL_TRANSFER_SIZE_MASK;
+
+       cctl &= PL080_CONTROL_SWIDTH_MASK;
+
        switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
        case PL080_WIDTH_8BIT:
                break;
@@ -469,47 +522,66 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
 /* The channel should be paused when calling this */
 static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 {
+       struct pl08x_driver_data *pl08x = plchan->host;
+       const u32 *llis_va, *llis_va_limit;
        struct pl08x_phy_chan *ch;
+       dma_addr_t llis_bus;
        struct pl08x_txd *txd;
-       size_t bytes = 0;
+       u32 llis_max_words;
+       size_t bytes;
+       u32 clli;
 
        ch = plchan->phychan;
        txd = plchan->at;
 
+       if (!ch || !txd)
+               return 0;
+
        /*
         * Follow the LLIs to get the number of remaining
         * bytes in the currently active transaction.
         */
-       if (ch && txd) {
-               u32 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
+       clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
 
-               /* First get the remaining bytes in the active transfer */
+       /* First get the remaining bytes in the active transfer */
+       if (pl08x->vd->pl080s)
+               bytes = get_bytes_in_cctl_pl080s(
+                               readl(ch->base + PL080_CH_CONTROL),
+                               readl(ch->base + PL080S_CH_CONTROL2));
+       else
                bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
 
-               if (clli) {
-                       struct pl08x_lli *llis_va = txd->llis_va;
-                       dma_addr_t llis_bus = txd->llis_bus;
-                       int index;
+       if (!clli)
+               return bytes;
 
-                       BUG_ON(clli < llis_bus || clli >= llis_bus +
-                               sizeof(struct pl08x_lli) * MAX_NUM_TSFR_LLIS);
+       llis_va = txd->llis_va;
+       llis_bus = txd->llis_bus;
 
-                       /*
-                        * Locate the next LLI - as this is an array,
-                        * it's simple maths to find.
-                        */
-                       index = (clli - llis_bus) / sizeof(struct pl08x_lli);
+       llis_max_words = pl08x->lli_words * MAX_NUM_TSFR_LLIS;
+       BUG_ON(clli < llis_bus || clli >= llis_bus +
+                                               sizeof(u32) * llis_max_words);
 
-                       for (; index < MAX_NUM_TSFR_LLIS; index++) {
-                               bytes += get_bytes_in_cctl(llis_va[index].cctl);
+       /*
+        * Locate the next LLI - as this is an array,
+        * it's simple maths to find.
+        */
+       llis_va += (clli - llis_bus) / sizeof(u32);
 
-                               /*
-                                * A LLI pointer of 0 terminates the LLI list
-                                */
-                               if (!llis_va[index].lli)
-                                       break;
-                       }
-               }
+       llis_va_limit = llis_va + llis_max_words;
+
+       for (; llis_va < llis_va_limit; llis_va += pl08x->lli_words) {
+               if (pl08x->vd->pl080s)
+                       bytes += get_bytes_in_cctl_pl080s(
+                                               llis_va[PL080_LLI_CCTL],
+                                               llis_va[PL080S_LLI_CCTL2]);
+               else
+                       bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]);
+
+               /*
+                * A LLI pointer going backward terminates the LLI list
+                */
+               if (llis_va[PL080_LLI_LLI] <= clli)
+                       break;
        }
 
        return bytes;
@@ -720,6 +792,7 @@ static inline u32 pl08x_cctl_bits(u32 cctl, u8 srcwidth, u8 dstwidth,
                break;
        }
 
+       tsize &= PL080_CONTROL_TRANSFER_SIZE_MASK;
        retbits |= tsize << PL080_CONTROL_TRANSFER_SIZE_SHIFT;
        return retbits;
 }
@@ -764,20 +837,26 @@ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
 /*
  * Fills in one LLI for a certain transfer descriptor and advance the counter
  */
-static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
-       int num_llis, int len, u32 cctl)
+static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
+                                   struct pl08x_lli_build_data *bd,
+                                   int num_llis, int len, u32 cctl, u32 cctl2)
 {
-       struct pl08x_lli *llis_va = bd->txd->llis_va;
+       u32 offset = num_llis * pl08x->lli_words;
+       u32 *llis_va = bd->txd->llis_va + offset;
        dma_addr_t llis_bus = bd->txd->llis_bus;
 
        BUG_ON(num_llis >= MAX_NUM_TSFR_LLIS);
 
-       llis_va[num_llis].cctl = cctl;
-       llis_va[num_llis].src = bd->srcbus.addr;
-       llis_va[num_llis].dst = bd->dstbus.addr;
-       llis_va[num_llis].lli = llis_bus + (num_llis + 1) *
-               sizeof(struct pl08x_lli);
-       llis_va[num_llis].lli |= bd->lli_bus;
+       /* Advance the offset to next LLI. */
+       offset += pl08x->lli_words;
+
+       llis_va[PL080_LLI_SRC] = bd->srcbus.addr;
+       llis_va[PL080_LLI_DST] = bd->dstbus.addr;
+       llis_va[PL080_LLI_LLI] = (llis_bus + sizeof(u32) * offset);
+       llis_va[PL080_LLI_LLI] |= bd->lli_bus;
+       llis_va[PL080_LLI_CCTL] = cctl;
+       if (pl08x->vd->pl080s)
+               llis_va[PL080S_LLI_CCTL2] = cctl2;
 
        if (cctl & PL080_CONTROL_SRC_INCR)
                bd->srcbus.addr += len;
@@ -789,14 +868,53 @@ static void pl08x_fill_lli_for_desc(struct pl08x_lli_build_data *bd,
        bd->remainder -= len;
 }
 
-static inline void prep_byte_width_lli(struct pl08x_lli_build_data *bd,
-               u32 *cctl, u32 len, int num_llis, size_t *total_bytes)
+static inline void prep_byte_width_lli(struct pl08x_driver_data *pl08x,
+                       struct pl08x_lli_build_data *bd, u32 *cctl, u32 len,
+                       int num_llis, size_t *total_bytes)
 {
        *cctl = pl08x_cctl_bits(*cctl, 1, 1, len);
-       pl08x_fill_lli_for_desc(bd, num_llis, len, *cctl);
+       pl08x_fill_lli_for_desc(pl08x, bd, num_llis, len, *cctl, len);
        (*total_bytes) += len;
 }
 
+#ifdef VERBOSE_DEBUG
+static void pl08x_dump_lli(struct pl08x_driver_data *pl08x,
+                          const u32 *llis_va, int num_llis)
+{
+       int i;
+
+       if (pl08x->vd->pl080s) {
+               dev_vdbg(&pl08x->adev->dev,
+                       "%-3s %-9s  %-10s %-10s %-10s %-10s %s\n",
+                       "lli", "", "csrc", "cdst", "clli", "cctl", "cctl2");
+               for (i = 0; i < num_llis; i++) {
+                       dev_vdbg(&pl08x->adev->dev,
+                               "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                               i, llis_va, llis_va[PL080_LLI_SRC],
+                               llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
+                               llis_va[PL080_LLI_CCTL],
+                               llis_va[PL080S_LLI_CCTL2]);
+                       llis_va += pl08x->lli_words;
+               }
+       } else {
+               dev_vdbg(&pl08x->adev->dev,
+                       "%-3s %-9s  %-10s %-10s %-10s %s\n",
+                       "lli", "", "csrc", "cdst", "clli", "cctl");
+               for (i = 0; i < num_llis; i++) {
+                       dev_vdbg(&pl08x->adev->dev,
+                               "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                               i, llis_va, llis_va[PL080_LLI_SRC],
+                               llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
+                               llis_va[PL080_LLI_CCTL]);
+                       llis_va += pl08x->lli_words;
+               }
+       }
+}
+#else
+static inline void pl08x_dump_lli(struct pl08x_driver_data *pl08x,
+                                 const u32 *llis_va, int num_llis) {}
+#endif
+
 /*
  * This fills in the table of LLIs for the transfer descriptor
  * Note that we assume we never have to change the burst sizes
@@ -810,7 +928,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
        int num_llis = 0;
        u32 cctl, early_bytes = 0;
        size_t max_bytes_per_lli, total_bytes;
-       struct pl08x_lli *llis_va;
+       u32 *llis_va, *last_lli;
        struct pl08x_sg *dsg;
 
        txd->llis_va = dma_pool_alloc(pl08x->pool, GFP_NOWAIT, &txd->llis_bus);
@@ -845,10 +963,13 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 
                pl08x_choose_master_bus(&bd, &mbus, &sbus, cctl);
 
-               dev_vdbg(&pl08x->adev->dev, "src=0x%08x%s/%u dst=0x%08x%s/%u len=%zu\n",
-                       bd.srcbus.addr, cctl & PL080_CONTROL_SRC_INCR ? "+" : "",
+               dev_vdbg(&pl08x->adev->dev,
+                       "src=0x%08llx%s/%u dst=0x%08llx%s/%u len=%zu\n",
+                       (u64)bd.srcbus.addr,
+                       cctl & PL080_CONTROL_SRC_INCR ? "+" : "",
                        bd.srcbus.buswidth,
-                       bd.dstbus.addr, cctl & PL080_CONTROL_DST_INCR ? "+" : "",
+                       (u64)bd.dstbus.addr,
+                       cctl & PL080_CONTROL_DST_INCR ? "+" : "",
                        bd.dstbus.buswidth,
                        bd.remainder);
                dev_vdbg(&pl08x->adev->dev, "mbus=%s sbus=%s\n",
@@ -886,8 +1007,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                                return 0;
                        }
 
-                       if ((bd.srcbus.addr % bd.srcbus.buswidth) ||
-                                       (bd.dstbus.addr % bd.dstbus.buswidth)) {
+                       if (!IS_BUS_ALIGNED(&bd.srcbus) ||
+                               !IS_BUS_ALIGNED(&bd.dstbus)) {
                                dev_err(&pl08x->adev->dev,
                                        "%s src & dst address must be aligned to src"
                                        " & dst width if peripheral is flow controller",
@@ -897,7 +1018,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 
                        cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
                                        bd.dstbus.buswidth, 0);
-                       pl08x_fill_lli_for_desc(&bd, num_llis++, 0, cctl);
+                       pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
+                                       0, cctl, 0);
                        break;
                }
 
@@ -908,9 +1030,9 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                 */
                if (bd.remainder < mbus->buswidth)
                        early_bytes = bd.remainder;
-               else if ((mbus->addr) % (mbus->buswidth)) {
-                       early_bytes = mbus->buswidth - (mbus->addr) %
-                               (mbus->buswidth);
+               else if (!IS_BUS_ALIGNED(mbus)) {
+                       early_bytes = mbus->buswidth -
+                               (mbus->addr & (mbus->buswidth - 1));
                        if ((bd.remainder - early_bytes) < mbus->buswidth)
                                early_bytes = bd.remainder;
                }
@@ -919,8 +1041,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                        dev_vdbg(&pl08x->adev->dev,
                                "%s byte width LLIs (remain 0x%08x)\n",
                                __func__, bd.remainder);
-                       prep_byte_width_lli(&bd, &cctl, early_bytes, num_llis++,
-                               &total_bytes);
+                       prep_byte_width_lli(pl08x, &bd, &cctl, early_bytes,
+                               num_llis++, &total_bytes);
                }
 
                if (bd.remainder) {
@@ -928,7 +1050,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                         * Master now aligned
                         * - if slave is not then we must set its width down
                         */
-                       if (sbus->addr % sbus->buswidth) {
+                       if (!IS_BUS_ALIGNED(sbus)) {
                                dev_dbg(&pl08x->adev->dev,
                                        "%s set down bus width to one byte\n",
                                        __func__);
@@ -941,7 +1063,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                         * MIN(buswidths)
                         */
                        max_bytes_per_lli = bd.srcbus.buswidth *
-                               PL080_CONTROL_TRANSFER_SIZE_MASK;
+                                               pl08x->vd->max_transfer_size;
                        dev_vdbg(&pl08x->adev->dev,
                                "%s max bytes per lli = %zu\n",
                                __func__, max_bytes_per_lli);
@@ -976,8 +1098,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 
                                cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
                                        bd.dstbus.buswidth, tsize);
-                               pl08x_fill_lli_for_desc(&bd, num_llis++,
-                                               lli_len, cctl);
+                               pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
+                                               lli_len, cctl, tsize);
                                total_bytes += lli_len;
                        }
 
@@ -988,8 +1110,8 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                                dev_vdbg(&pl08x->adev->dev,
                                        "%s align with boundary, send odd bytes (remain %zu)\n",
                                        __func__, bd.remainder);
-                               prep_byte_width_lli(&bd, &cctl, bd.remainder,
-                                               num_llis++, &total_bytes);
+                               prep_byte_width_lli(pl08x, &bd, &cctl,
+                                       bd.remainder, num_llis++, &total_bytes);
                        }
                }
 
@@ -1003,33 +1125,25 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
                if (num_llis >= MAX_NUM_TSFR_LLIS) {
                        dev_err(&pl08x->adev->dev,
                                "%s need to increase MAX_NUM_TSFR_LLIS from 0x%08x\n",
-                               __func__, (u32) MAX_NUM_TSFR_LLIS);
+                               __func__, MAX_NUM_TSFR_LLIS);
                        return 0;
                }
        }
 
        llis_va = txd->llis_va;
-       /* The final LLI terminates the LLI. */
-       llis_va[num_llis - 1].lli = 0;
-       /* The final LLI element shall also fire an interrupt. */
-       llis_va[num_llis - 1].cctl |= PL080_CONTROL_TC_IRQ_EN;
+       last_lli = llis_va + (num_llis - 1) * pl08x->lli_words;
 
-#ifdef VERBOSE_DEBUG
-       {
-               int i;
-
-               dev_vdbg(&pl08x->adev->dev,
-                        "%-3s %-9s  %-10s %-10s %-10s %s\n",
-                        "lli", "", "csrc", "cdst", "clli", "cctl");
-               for (i = 0; i < num_llis; i++) {
-                       dev_vdbg(&pl08x->adev->dev,
-                                "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
-                                i, &llis_va[i], llis_va[i].src,
-                                llis_va[i].dst, llis_va[i].lli, llis_va[i].cctl
-                               );
-               }
+       if (txd->cyclic) {
+               /* Link back to the first LLI. */
+               last_lli[PL080_LLI_LLI] = txd->llis_bus | bd.lli_bus;
+       } else {
+               /* The final LLI terminates the LLI. */
+               last_lli[PL080_LLI_LLI] = 0;
+               /* The final LLI element shall also fire an interrupt. */
+               last_lli[PL080_LLI_CCTL] |= PL080_CONTROL_TC_IRQ_EN;
        }
-#endif
+
+       pl08x_dump_lli(pl08x, llis_va, num_llis);
 
        return num_llis;
 }
@@ -1305,6 +1419,7 @@ static int dma_set_runtime_config(struct dma_chan *chan,
                                  struct dma_slave_config *config)
 {
        struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+       struct pl08x_driver_data *pl08x = plchan->host;
 
        if (!plchan->slave)
                return -EINVAL;
@@ -1314,6 +1429,13 @@ static int dma_set_runtime_config(struct dma_chan *chan,
            config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
                return -EINVAL;
 
+       if (config->device_fc && pl08x->vd->pl080s) {
+               dev_err(&pl08x->adev->dev,
+                       "%s: PL080S does not support peripheral flow control\n",
+                       __func__);
+               return -EINVAL;
+       }
+
        plchan->cfg = *config;
 
        return 0;
@@ -1404,25 +1526,19 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
        return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
 }
 
-static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
-               struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_transfer_direction direction,
-               unsigned long flags, void *context)
+static struct pl08x_txd *pl08x_init_txd(
+               struct dma_chan *chan,
+               enum dma_transfer_direction direction,
+               dma_addr_t *slave_addr)
 {
        struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
        struct pl08x_driver_data *pl08x = plchan->host;
        struct pl08x_txd *txd;
-       struct pl08x_sg *dsg;
-       struct scatterlist *sg;
        enum dma_slave_buswidth addr_width;
-       dma_addr_t slave_addr;
        int ret, tmp;
        u8 src_buses, dst_buses;
        u32 maxburst, cctl;
 
-       dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
-                       __func__, sg_dma_len(sgl), plchan->name);
-
        txd = pl08x_get_txd(plchan);
        if (!txd) {
                dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
@@ -1436,14 +1552,14 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
         */
        if (direction == DMA_MEM_TO_DEV) {
                cctl = PL080_CONTROL_SRC_INCR;
-               slave_addr = plchan->cfg.dst_addr;
+               *slave_addr = plchan->cfg.dst_addr;
                addr_width = plchan->cfg.dst_addr_width;
                maxburst = plchan->cfg.dst_maxburst;
                src_buses = pl08x->mem_buses;
                dst_buses = plchan->cd->periph_buses;
        } else if (direction == DMA_DEV_TO_MEM) {
                cctl = PL080_CONTROL_DST_INCR;
-               slave_addr = plchan->cfg.src_addr;
+               *slave_addr = plchan->cfg.src_addr;
                addr_width = plchan->cfg.src_addr_width;
                maxburst = plchan->cfg.src_maxburst;
                src_buses = plchan->cd->periph_buses;
@@ -1492,24 +1608,107 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
        else
                txd->ccfg |= plchan->signal << PL080_CONFIG_SRC_SEL_SHIFT;
 
+       return txd;
+}
+
+static int pl08x_tx_add_sg(struct pl08x_txd *txd,
+                          enum dma_transfer_direction direction,
+                          dma_addr_t slave_addr,
+                          dma_addr_t buf_addr,
+                          unsigned int len)
+{
+       struct pl08x_sg *dsg;
+
+       dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
+       if (!dsg)
+               return -ENOMEM;
+
+       list_add_tail(&dsg->node, &txd->dsg_list);
+
+       dsg->len = len;
+       if (direction == DMA_MEM_TO_DEV) {
+               dsg->src_addr = buf_addr;
+               dsg->dst_addr = slave_addr;
+       } else {
+               dsg->src_addr = slave_addr;
+               dsg->dst_addr = buf_addr;
+       }
+
+       return 0;
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_transfer_direction direction,
+               unsigned long flags, void *context)
+{
+       struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+       struct pl08x_driver_data *pl08x = plchan->host;
+       struct pl08x_txd *txd;
+       struct scatterlist *sg;
+       int ret, tmp;
+       dma_addr_t slave_addr;
+
+       dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
+                       __func__, sg_dma_len(sgl), plchan->name);
+
+       txd = pl08x_init_txd(chan, direction, &slave_addr);
+       if (!txd)
+               return NULL;
+
        for_each_sg(sgl, sg, sg_len, tmp) {
-               dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
-               if (!dsg) {
+               ret = pl08x_tx_add_sg(txd, direction, slave_addr,
+                                     sg_dma_address(sg),
+                                     sg_dma_len(sg));
+               if (ret) {
                        pl08x_release_mux(plchan);
                        pl08x_free_txd(pl08x, txd);
                        dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n",
                                        __func__);
                        return NULL;
                }
-               list_add_tail(&dsg->node, &txd->dsg_list);
+       }
 
-               dsg->len = sg_dma_len(sg);
-               if (direction == DMA_MEM_TO_DEV) {
-                       dsg->src_addr = sg_dma_address(sg);
-                       dsg->dst_addr = slave_addr;
-               } else {
-                       dsg->src_addr = slave_addr;
-                       dsg->dst_addr = sg_dma_address(sg);
+       ret = pl08x_fill_llis_for_desc(plchan->host, txd);
+       if (!ret) {
+               pl08x_release_mux(plchan);
+               pl08x_free_txd(pl08x, txd);
+               return NULL;
+       }
+
+       return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+               size_t period_len, enum dma_transfer_direction direction,
+               unsigned long flags, void *context)
+{
+       struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+       struct pl08x_driver_data *pl08x = plchan->host;
+       struct pl08x_txd *txd;
+       int ret, tmp;
+       dma_addr_t slave_addr;
+
+       dev_dbg(&pl08x->adev->dev,
+               "%s prepare cyclic transaction of %d/%d bytes %s %s\n",
+               __func__, period_len, buf_len,
+               direction == DMA_MEM_TO_DEV ? "to" : "from",
+               plchan->name);
+
+       txd = pl08x_init_txd(chan, direction, &slave_addr);
+       if (!txd)
+               return NULL;
+
+       txd->cyclic = true;
+       txd->cctl |= PL080_CONTROL_TC_IRQ_EN;
+       for (tmp = 0; tmp < buf_len; tmp += period_len) {
+               ret = pl08x_tx_add_sg(txd, direction, slave_addr,
+                                     buf_addr + tmp, period_len);
+               if (ret) {
+                       pl08x_release_mux(plchan);
+                       pl08x_free_txd(pl08x, txd);
+                       return NULL;
                }
        }
 
@@ -1652,7 +1851,9 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 
                        spin_lock(&plchan->vc.lock);
                        tx = plchan->at;
-                       if (tx) {
+                       if (tx && tx->cyclic) {
+                               vchan_cyclic_callback(&tx->vd);
+                       } else if (tx) {
                                plchan->at = NULL;
                                /*
                                 * This descriptor is done, release its mux
@@ -1846,6 +2047,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 {
        struct pl08x_driver_data *pl08x;
        const struct vendor_data *vd = id->data;
+       u32 tsfr_size;
        int ret = 0;
        int i;
 
@@ -1873,6 +2075,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 
        /* Initialize slave engine */
        dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
+       dma_cap_set(DMA_CYCLIC, pl08x->slave.cap_mask);
        pl08x->slave.dev = &adev->dev;
        pl08x->slave.device_alloc_chan_resources = pl08x_alloc_chan_resources;
        pl08x->slave.device_free_chan_resources = pl08x_free_chan_resources;
@@ -1880,6 +2083,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        pl08x->slave.device_tx_status = pl08x_dma_tx_status;
        pl08x->slave.device_issue_pending = pl08x_issue_pending;
        pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
+       pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic;
        pl08x->slave.device_control = pl08x_control;
 
        /* Get the platform data */
@@ -1902,9 +2106,15 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
                pl08x->mem_buses = pl08x->pd->mem_buses;
        }
 
+       if (vd->pl080s)
+               pl08x->lli_words = PL080S_LLI_WORDS;
+       else
+               pl08x->lli_words = PL080_LLI_WORDS;
+       tsfr_size = MAX_NUM_TSFR_LLIS * pl08x->lli_words * sizeof(u32);
+
        /* A DMA memory pool for LLIs, align on 1-byte boundary */
        pl08x->pool = dma_pool_create(DRIVER_NAME, &pl08x->adev->dev,
-                       PL08X_LLI_TSFR_SIZE, PL08X_ALIGN, 0);
+                                               tsfr_size, PL08X_ALIGN, 0);
        if (!pl08x->pool) {
                ret = -ENOMEM;
                goto out_no_lli_pool;
@@ -1947,6 +2157,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 
                ch->id = i;
                ch->base = pl08x->base + PL080_Cx_BASE(i);
+               ch->reg_config = ch->base + vd->config_offset;
                spin_lock_init(&ch->lock);
 
                /*
@@ -1957,7 +2168,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
                if (vd->nomadik) {
                        u32 val;
 
-                       val = readl(ch->base + PL080_CH_CONFIG);
+                       val = readl(ch->reg_config);
                        if (val & (PL080N_CONFIG_ITPROT | PL080N_CONFIG_SECPROT)) {
                                dev_info(&adev->dev, "physical channel %d reserved for secure access only\n", i);
                                ch->locked = true;
@@ -2008,8 +2219,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 
        amba_set_drvdata(adev, pl08x);
        init_pl08x_debugfs(pl08x);
-       dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n",
-                amba_part(adev), amba_rev(adev),
+       dev_info(&pl08x->adev->dev, "DMA: PL%03x%s rev%u at 0x%08llx irq %d\n",
+                amba_part(adev), pl08x->vd->pl080s ? "s" : "", amba_rev(adev),
                 (unsigned long long)adev->res.start, adev->irq[0]);
 
        return 0;
@@ -2038,22 +2249,41 @@ out_no_pl08x:
 
 /* PL080 has 8 channels and the PL080 have just 2 */
 static struct vendor_data vendor_pl080 = {
+       .config_offset = PL080_CH_CONFIG,
        .channels = 8,
        .dualmaster = true,
+       .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct vendor_data vendor_nomadik = {
+       .config_offset = PL080_CH_CONFIG,
        .channels = 8,
        .dualmaster = true,
        .nomadik = true,
+       .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
+};
+
+static struct vendor_data vendor_pl080s = {
+       .config_offset = PL080S_CH_CONFIG,
+       .channels = 8,
+       .pl080s = true,
+       .max_transfer_size = PL080S_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct vendor_data vendor_pl081 = {
+       .config_offset = PL080_CH_CONFIG,
        .channels = 2,
        .dualmaster = false,
+       .max_transfer_size = PL080_CONTROL_TRANSFER_SIZE_MASK,
 };
 
 static struct amba_id pl08x_ids[] = {
+       /* Samsung PL080S variant */
+       {
+               .id     = 0x0a141080,
+               .mask   = 0xffffffff,
+               .data   = &vendor_pl080s,
+       },
        /* PL080 */
        {
                .id     = 0x00041080,
index 99af4db5948bc9406d85ef841077baff2ffd5f40..9162ac80c18f303ac9a509eb97298eba33d4753b 100644 (file)
@@ -382,20 +382,30 @@ void dma_issue_pending_all(void)
 EXPORT_SYMBOL(dma_issue_pending_all);
 
 /**
- * nth_chan - returns the nth channel of the given capability
+ * dma_chan_is_local - returns true if the channel is in the same numa-node as the cpu
+ */
+static bool dma_chan_is_local(struct dma_chan *chan, int cpu)
+{
+       int node = dev_to_node(chan->device->dev);
+       return node == -1 || cpumask_test_cpu(cpu, cpumask_of_node(node));
+}
+
+/**
+ * min_chan - returns the channel with min count and in the same numa-node as the cpu
  * @cap: capability to match
- * @n: nth channel desired
+ * @cpu: cpu index which the channel should be close to
  *
- * Defaults to returning the channel with the desired capability and the
- * lowest reference count when 'n' cannot be satisfied.  Must be called
- * under dma_list_mutex.
+ * If some channels are close to the given cpu, the one with the lowest
+ * reference count is returned. Otherwise, cpu is ignored and only the
+ * reference count is taken into account.
+ * Must be called under dma_list_mutex.
  */
-static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
+static struct dma_chan *min_chan(enum dma_transaction_type cap, int cpu)
 {
        struct dma_device *device;
        struct dma_chan *chan;
-       struct dma_chan *ret = NULL;
        struct dma_chan *min = NULL;
+       struct dma_chan *localmin = NULL;
 
        list_for_each_entry(device, &dma_device_list, global_node) {
                if (!dma_has_cap(cap, device->cap_mask) ||
@@ -404,27 +414,22 @@ static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n)
                list_for_each_entry(chan, &device->channels, device_node) {
                        if (!chan->client_count)
                                continue;
-                       if (!min)
-                               min = chan;
-                       else if (chan->table_count < min->table_count)
+                       if (!min || chan->table_count < min->table_count)
                                min = chan;
 
-                       if (n-- == 0) {
-                               ret = chan;
-                               break; /* done */
-                       }
+                       if (dma_chan_is_local(chan, cpu))
+                               if (!localmin ||
+                                   chan->table_count < localmin->table_count)
+                                       localmin = chan;
                }
-               if (ret)
-                       break; /* done */
        }
 
-       if (!ret)
-               ret = min;
+       chan = localmin ? localmin : min;
 
-       if (ret)
-               ret->table_count++;
+       if (chan)
+               chan->table_count++;
 
-       return ret;
+       return chan;
 }
 
 /**
@@ -441,7 +446,6 @@ static void dma_channel_rebalance(void)
        struct dma_device *device;
        int cpu;
        int cap;
-       int n;
 
        /* undo the last distribution */
        for_each_dma_cap_mask(cap, dma_cap_mask_all)
@@ -460,14 +464,9 @@ static void dma_channel_rebalance(void)
                return;
 
        /* redistribute available channels */
-       n = 0;
        for_each_dma_cap_mask(cap, dma_cap_mask_all)
                for_each_online_cpu(cpu) {
-                       if (num_possible_cpus() > 1)
-                               chan = nth_chan(cap, n++);
-                       else
-                               chan = nth_chan(cap, -1);
-
+                       chan = min_chan(cap, cpu);
                        per_cpu_ptr(channel_table[cap], cpu)->chan = chan;
                }
 }
@@ -510,7 +509,33 @@ static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
 }
 
 /**
- * dma_request_channel - try to allocate an exclusive channel
+ * dma_request_slave_channel - try to get specific channel exclusively
+ * @chan: target channel
+ */
+struct dma_chan *dma_get_slave_channel(struct dma_chan *chan)
+{
+       int err = -EBUSY;
+
+       /* lock against __dma_request_channel */
+       mutex_lock(&dma_list_mutex);
+
+       if (chan->client_count == 0) {
+               err = dma_chan_get(chan);
+               if (err)
+                       pr_debug("%s: failed to get %s: (%d)\n",
+                               __func__, dma_chan_name(chan), err);
+       } else
+               chan = NULL;
+
+       mutex_unlock(&dma_list_mutex);
+
+
+       return chan;
+}
+EXPORT_SYMBOL_GPL(dma_get_slave_channel);
+
+/**
+ * __dma_request_channel - try to allocate an exclusive channel
  * @mask: capabilities that the channel must satisfy
  * @fn: optional callback to disposition available channels
  * @fn_param: opaque parameter to pass to dma_filter_fn
index e88ded2c8d2f1bc8d73223ef2175fcbd391be5bf..92f796cdc6ab1dc12c6b895fb2d6e16e5dd92264 100644 (file)
 #include <linux/seq_file.h>
 
 static unsigned int test_buf_size = 16384;
-module_param(test_buf_size, uint, S_IRUGO);
+module_param(test_buf_size, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(test_buf_size, "Size of the memcpy test buffer");
 
 static char test_channel[20];
-module_param_string(channel, test_channel, sizeof(test_channel), S_IRUGO);
+module_param_string(channel, test_channel, sizeof(test_channel),
+               S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
 
 static char test_device[20];
-module_param_string(device, test_device, sizeof(test_device), S_IRUGO);
+module_param_string(device, test_device, sizeof(test_device),
+               S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
 
 static unsigned int threads_per_chan = 1;
-module_param(threads_per_chan, uint, S_IRUGO);
+module_param(threads_per_chan, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(threads_per_chan,
                "Number of threads to start per channel (default: 1)");
 
 static unsigned int max_channels;
-module_param(max_channels, uint, S_IRUGO);
+module_param(max_channels, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(max_channels,
                "Maximum number of channels to use (default: all)");
 
 static unsigned int iterations;
-module_param(iterations, uint, S_IRUGO);
+module_param(iterations, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(iterations,
                "Iterations before stopping test (default: infinite)");
 
 static unsigned int xor_sources = 3;
-module_param(xor_sources, uint, S_IRUGO);
+module_param(xor_sources, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(xor_sources,
                "Number of xor source buffers (default: 3)");
 
 static unsigned int pq_sources = 3;
-module_param(pq_sources, uint, S_IRUGO);
+module_param(pq_sources, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(pq_sources,
                "Number of p+q source buffers (default: 3)");
 
 static int timeout = 3000;
-module_param(timeout, uint, S_IRUGO);
+module_param(timeout, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(timeout, "Transfer Timeout in msec (default: 3000), "
                 "Pass -1 for infinite timeout");
 
@@ -193,7 +195,6 @@ struct dmatest_info {
 
        /* debugfs related stuff */
        struct dentry           *root;
-       struct dmatest_params   dbgfs_params;
 
        /* Test results */
        struct list_head        results;
@@ -406,7 +407,11 @@ static int thread_result_add(struct dmatest_info *info,
        list_add_tail(&tr->node, &r->results);
        mutex_unlock(&info->results_lock);
 
-       pr_warn("%s\n", thread_result_get(r->name, tr));
+       if (tr->type == DMATEST_ET_OK)
+               pr_debug("%s\n", thread_result_get(r->name, tr));
+       else
+               pr_warn("%s\n", thread_result_get(r->name, tr));
+
        return 0;
 }
 
@@ -1007,7 +1012,15 @@ static int __restart_threaded_test(struct dmatest_info *info, bool run)
        result_free(info, NULL);
 
        /* Copy test parameters */
-       memcpy(params, &info->dbgfs_params, sizeof(*params));
+       params->buf_size = test_buf_size;
+       strlcpy(params->channel, strim(test_channel), sizeof(params->channel));
+       strlcpy(params->device, strim(test_device), sizeof(params->device));
+       params->threads_per_chan = threads_per_chan;
+       params->max_channels = max_channels;
+       params->iterations = iterations;
+       params->xor_sources = xor_sources;
+       params->pq_sources = pq_sources;
+       params->timeout = timeout;
 
        /* Run test with new parameters */
        return __run_threaded_test(info);
@@ -1029,71 +1042,6 @@ static bool __is_threaded_test_run(struct dmatest_info *info)
        return false;
 }
 
-static ssize_t dtf_write_string(void *to, size_t available, loff_t *ppos,
-               const void __user *from, size_t count)
-{
-       char tmp[20];
-       ssize_t len;
-
-       len = simple_write_to_buffer(tmp, sizeof(tmp) - 1, ppos, from, count);
-       if (len >= 0) {
-               tmp[len] = '\0';
-               strlcpy(to, strim(tmp), available);
-       }
-
-       return len;
-}
-
-static ssize_t dtf_read_channel(struct file *file, char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       struct dmatest_info *info = file->private_data;
-       return simple_read_from_buffer(buf, count, ppos,
-                       info->dbgfs_params.channel,
-                       strlen(info->dbgfs_params.channel));
-}
-
-static ssize_t dtf_write_channel(struct file *file, const char __user *buf,
-               size_t size, loff_t *ppos)
-{
-       struct dmatest_info *info = file->private_data;
-       return dtf_write_string(info->dbgfs_params.channel,
-                               sizeof(info->dbgfs_params.channel),
-                               ppos, buf, size);
-}
-
-static const struct file_operations dtf_channel_fops = {
-       .read   = dtf_read_channel,
-       .write  = dtf_write_channel,
-       .open   = simple_open,
-       .llseek = default_llseek,
-};
-
-static ssize_t dtf_read_device(struct file *file, char __user *buf,
-               size_t count, loff_t *ppos)
-{
-       struct dmatest_info *info = file->private_data;
-       return simple_read_from_buffer(buf, count, ppos,
-                       info->dbgfs_params.device,
-                       strlen(info->dbgfs_params.device));
-}
-
-static ssize_t dtf_write_device(struct file *file, const char __user *buf,
-               size_t size, loff_t *ppos)
-{
-       struct dmatest_info *info = file->private_data;
-       return dtf_write_string(info->dbgfs_params.device,
-                               sizeof(info->dbgfs_params.device),
-                               ppos, buf, size);
-}
-
-static const struct file_operations dtf_device_fops = {
-       .read   = dtf_read_device,
-       .write  = dtf_write_device,
-       .open   = simple_open,
-       .llseek = default_llseek,
-};
-
 static ssize_t dtf_read_run(struct file *file, char __user *user_buf,
                size_t count, loff_t *ppos)
 {
@@ -1187,8 +1135,6 @@ static const struct file_operations dtf_results_fops = {
 static int dmatest_register_dbgfs(struct dmatest_info *info)
 {
        struct dentry *d;
-       struct dmatest_params *params = &info->dbgfs_params;
-       int ret = -ENOMEM;
 
        d = debugfs_create_dir("dmatest", NULL);
        if (IS_ERR(d))
@@ -1198,81 +1144,24 @@ static int dmatest_register_dbgfs(struct dmatest_info *info)
 
        info->root = d;
 
-       /* Copy initial values */
-       memcpy(params, &info->params, sizeof(*params));
-
-       /* Test parameters */
-
-       d = debugfs_create_u32("test_buf_size", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->buf_size);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_file("channel", S_IRUGO | S_IWUSR, info->root,
-                               info, &dtf_channel_fops);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_file("device", S_IRUGO | S_IWUSR, info->root,
-                               info, &dtf_device_fops);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_u32("threads_per_chan", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->threads_per_chan);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_u32("max_channels", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->max_channels);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_u32("iterations", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->iterations);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_u32("xor_sources", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->xor_sources);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_u32("pq_sources", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->pq_sources);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
-       d = debugfs_create_u32("timeout", S_IWUSR | S_IRUGO, info->root,
-                              (u32 *)&params->timeout);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
-
        /* Run or stop threaded test */
-       d = debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root,
-                               info, &dtf_run_fops);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
+       debugfs_create_file("run", S_IWUSR | S_IRUGO, info->root, info,
+                           &dtf_run_fops);
 
        /* Results of test in progress */
-       d = debugfs_create_file("results", S_IRUGO, info->root, info,
-                               &dtf_results_fops);
-       if (IS_ERR_OR_NULL(d))
-               goto err_node;
+       debugfs_create_file("results", S_IRUGO, info->root, info,
+                           &dtf_results_fops);
 
        return 0;
 
-err_node:
-       debugfs_remove_recursive(info->root);
 err_root:
        pr_err("dmatest: Failed to initialize debugfs\n");
-       return ret;
+       return -ENOMEM;
 }
 
 static int __init dmatest_init(void)
 {
        struct dmatest_info *info = &test_info;
-       struct dmatest_params *params = &info->params;
        int ret;
 
        memset(info, 0, sizeof(*info));
@@ -1283,17 +1172,6 @@ static int __init dmatest_init(void)
        mutex_init(&info->results_lock);
        INIT_LIST_HEAD(&info->results);
 
-       /* Set default parameters */
-       params->buf_size = test_buf_size;
-       strlcpy(params->channel, test_channel, sizeof(params->channel));
-       strlcpy(params->device, test_device, sizeof(params->device));
-       params->threads_per_chan = threads_per_chan;
-       params->max_channels = max_channels;
-       params->iterations = iterations;
-       params->xor_sources = xor_sources;
-       params->pq_sources = pq_sources;
-       params->timeout = timeout;
-
        ret = dmatest_register_dbgfs(info);
        if (ret)
                return ret;
index dde13248b6818a00cae16afb5dae55d081592847..dcfe964cc8dc3138da6262fb6f453b3a421b45f7 100644 (file)
@@ -4,7 +4,6 @@
 
 config DW_DMAC_CORE
        tristate "Synopsys DesignWare AHB DMA support"
-       depends on GENERIC_HARDIRQS
        select DMA_ENGINE
 
 config DW_DMAC
index eea479c121736e20c6e52f71059df1b4e14a364b..89eb89f222846e0ff5d20cfc5e14619fc05d6600 100644 (file)
  * which does not support descriptor writeback.
  */
 
+static inline bool is_request_line_unset(struct dw_dma_chan *dwc)
+{
+       return dwc->request_line == (typeof(dwc->request_line))~0;
+}
+
 static inline void dwc_set_masters(struct dw_dma_chan *dwc)
 {
        struct dw_dma *dw = to_dw_dma(dwc->chan.device);
        struct dw_dma_slave *dws = dwc->chan.private;
        unsigned char mmax = dw->nr_masters - 1;
 
-       if (dwc->request_line == ~0) {
-               dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws));
-               dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws));
-       }
+       if (!is_request_line_unset(dwc))
+               return;
+
+       dwc->src_master = min_t(unsigned char, mmax, dwc_get_sms(dws));
+       dwc->dst_master = min_t(unsigned char, mmax, dwc_get_dms(dws));
 }
 
 #define DWC_DEFAULT_CTLLO(_chan) ({                            \
@@ -644,10 +650,13 @@ static void dw_dma_tasklet(unsigned long data)
 static irqreturn_t dw_dma_interrupt(int irq, void *dev_id)
 {
        struct dw_dma *dw = dev_id;
-       u32 status;
+       u32 status = dma_readl(dw, STATUS_INT);
+
+       dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__, status);
 
-       dev_vdbg(dw->dma.dev, "%s: status=0x%x\n", __func__,
-                       dma_readl(dw, STATUS_INT));
+       /* Check if we have any interrupt from the DMAC */
+       if (!status)
+               return IRQ_NONE;
 
        /*
         * Just disable the interrupts. We'll turn them back on in the
@@ -984,7 +993,7 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
        dwc->direction = sconfig->direction;
 
        /* Take the request line from slave_id member */
-       if (dwc->request_line == ~0)
+       if (is_request_line_unset(dwc))
                dwc->request_line = sconfig->slave_id;
 
        convert_burst(&dwc->dma_sconfig.src_maxburst);
@@ -1089,16 +1098,16 @@ dwc_tx_status(struct dma_chan *chan,
        enum dma_status         ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret != DMA_SUCCESS) {
-               dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
+       if (ret == DMA_SUCCESS)
+               return ret;
 
-               ret = dma_cookie_status(chan, cookie, txstate);
-       }
+       dwc_scan_descriptors(to_dw_dma(chan->device), dwc);
 
+       ret = dma_cookie_status(chan, cookie, txstate);
        if (ret != DMA_SUCCESS)
                dma_set_residue(txstate, dwc_get_residue(dwc));
 
-       if (dwc->paused)
+       if (dwc->paused && ret == DMA_IN_PROGRESS)
                return DMA_PAUSED;
 
        return ret;
@@ -1560,8 +1569,8 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        /* Disable BLOCK interrupts as well */
        channel_clear_bit(dw, MASK.BLOCK, dw->all_chan_mask);
 
-       err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt, 0,
-                              "dw_dmac", dw);
+       err = devm_request_irq(chip->dev, chip->irq, dw_dma_interrupt,
+                              IRQF_SHARED, "dw_dmac", dw);
        if (err)
                return err;
 
index 6c9449cffae81b90fd20c0ba9f2df7c7166e8f1c..e35d97590311329fe1f7bd93be5cc4b845f3a7c2 100644 (file)
@@ -253,6 +253,7 @@ static const struct acpi_device_id dw_dma_acpi_id_table[] = {
        { "INTL9C60", 0 },
        { }
 };
+MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
 #endif
 
 #ifdef CONFIG_PM_SLEEP
index 5f3e532436ee40c5f035b4c9bd6b2b008700b350..ff50ff4c6a57148c3a015a6ba3ebb1c81f69c6f8 100644 (file)
@@ -56,6 +56,7 @@ struct edma_desc {
        struct list_head                node;
        int                             absync;
        int                             pset_nr;
+       int                             processed;
        struct edmacc_param             pset[0];
 };
 
@@ -69,6 +70,7 @@ struct edma_chan {
        int                             ch_num;
        bool                            alloced;
        int                             slot[EDMA_MAX_SLOTS];
+       int                             missed;
        struct dma_slave_config         cfg;
 };
 
@@ -104,22 +106,34 @@ static void edma_desc_free(struct virt_dma_desc *vdesc)
 /* Dispatch a queued descriptor to the controller (caller holds lock) */
 static void edma_execute(struct edma_chan *echan)
 {
-       struct virt_dma_desc *vdesc = vchan_next_desc(&echan->vchan);
+       struct virt_dma_desc *vdesc;
        struct edma_desc *edesc;
-       int i;
-
-       if (!vdesc) {
-               echan->edesc = NULL;
-               return;
+       struct device *dev = echan->vchan.chan.device->dev;
+       int i, j, left, nslots;
+
+       /* If either we processed all psets or we're still not started */
+       if (!echan->edesc ||
+           echan->edesc->pset_nr == echan->edesc->processed) {
+               /* Get next vdesc */
+               vdesc = vchan_next_desc(&echan->vchan);
+               if (!vdesc) {
+                       echan->edesc = NULL;
+                       return;
+               }
+               list_del(&vdesc->node);
+               echan->edesc = to_edma_desc(&vdesc->tx);
        }
 
-       list_del(&vdesc->node);
+       edesc = echan->edesc;
 
-       echan->edesc = edesc = to_edma_desc(&vdesc->tx);
+       /* Find out how many left */
+       left = edesc->pset_nr - edesc->processed;
+       nslots = min(MAX_NR_SG, left);
 
        /* Write descriptor PaRAM set(s) */
-       for (i = 0; i < edesc->pset_nr; i++) {
-               edma_write_slot(echan->slot[i], &edesc->pset[i]);
+       for (i = 0; i < nslots; i++) {
+               j = i + edesc->processed;
+               edma_write_slot(echan->slot[i], &edesc->pset[j]);
                dev_dbg(echan->vchan.chan.device->dev,
                        "\n pset[%d]:\n"
                        "  chnum\t%d\n"
@@ -132,24 +146,50 @@ static void edma_execute(struct edma_chan *echan)
                        "  bidx\t%08x\n"
                        "  cidx\t%08x\n"
                        "  lkrld\t%08x\n",
-                       i, echan->ch_num, echan->slot[i],
-                       edesc->pset[i].opt,
-                       edesc->pset[i].src,
-                       edesc->pset[i].dst,
-                       edesc->pset[i].a_b_cnt,
-                       edesc->pset[i].ccnt,
-                       edesc->pset[i].src_dst_bidx,
-                       edesc->pset[i].src_dst_cidx,
-                       edesc->pset[i].link_bcntrld);
+                       j, echan->ch_num, echan->slot[i],
+                       edesc->pset[j].opt,
+                       edesc->pset[j].src,
+                       edesc->pset[j].dst,
+                       edesc->pset[j].a_b_cnt,
+                       edesc->pset[j].ccnt,
+                       edesc->pset[j].src_dst_bidx,
+                       edesc->pset[j].src_dst_cidx,
+                       edesc->pset[j].link_bcntrld);
                /* Link to the previous slot if not the last set */
-               if (i != (edesc->pset_nr - 1))
+               if (i != (nslots - 1))
                        edma_link(echan->slot[i], echan->slot[i+1]);
-               /* Final pset links to the dummy pset */
-               else
-                       edma_link(echan->slot[i], echan->ecc->dummy_slot);
        }
 
-       edma_start(echan->ch_num);
+       edesc->processed += nslots;
+
+       /*
+        * If this is either the last set in a set of SG-list transactions
+        * then setup a link to the dummy slot, this results in all future
+        * events being absorbed and that's OK because we're done
+        */
+       if (edesc->processed == edesc->pset_nr)
+               edma_link(echan->slot[nslots-1], echan->ecc->dummy_slot);
+
+       edma_resume(echan->ch_num);
+
+       if (edesc->processed <= MAX_NR_SG) {
+               dev_dbg(dev, "first transfer starting %d\n", echan->ch_num);
+               edma_start(echan->ch_num);
+       }
+
+       /*
+        * This happens due to setup times between intermediate transfers
+        * in long SG lists which have to be broken up into transfers of
+        * MAX_NR_SG
+        */
+       if (echan->missed) {
+               dev_dbg(dev, "missed event in execute detected\n");
+               edma_clean_channel(echan->ch_num);
+               edma_stop(echan->ch_num);
+               edma_start(echan->ch_num);
+               edma_trigger_channel(echan->ch_num);
+               echan->missed = 0;
+       }
 }
 
 static int edma_terminate_all(struct edma_chan *echan)
@@ -222,9 +262,9 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
        enum dma_slave_buswidth dev_width;
        u32 burst;
        struct scatterlist *sg;
-       int i;
        int acnt, bcnt, ccnt, src, dst, cidx;
        int src_bidx, dst_bidx, src_cidx, dst_cidx;
+       int i, nslots;
 
        if (unlikely(!echan || !sgl || !sg_len))
                return NULL;
@@ -247,12 +287,6 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                return NULL;
        }
 
-       if (sg_len > MAX_NR_SG) {
-               dev_err(dev, "Exceeded max SG segments %d > %d\n",
-                       sg_len, MAX_NR_SG);
-               return NULL;
-       }
-
        edesc = kzalloc(sizeof(*edesc) + sg_len *
                sizeof(edesc->pset[0]), GFP_ATOMIC);
        if (!edesc) {
@@ -262,8 +296,10 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
 
        edesc->pset_nr = sg_len;
 
-       for_each_sg(sgl, sg, sg_len, i) {
-               /* Allocate a PaRAM slot, if needed */
+       /* Allocate a PaRAM slot, if needed */
+       nslots = min_t(unsigned, MAX_NR_SG, sg_len);
+
+       for (i = 0; i < nslots; i++) {
                if (echan->slot[i] < 0) {
                        echan->slot[i] =
                                edma_alloc_slot(EDMA_CTLR(echan->ch_num),
@@ -273,6 +309,10 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                                return NULL;
                        }
                }
+       }
+
+       /* Configure PaRAM sets for each SG */
+       for_each_sg(sgl, sg, sg_len, i) {
 
                acnt = dev_width;
 
@@ -330,6 +370,12 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
                /* Configure A or AB synchronized transfers */
                if (edesc->absync)
                        edesc->pset[i].opt |= SYNCDIM;
+
+               /* If this is the last in a current SG set of transactions,
+                  enable interrupts so that next set is processed */
+               if (!((i+1) % MAX_NR_SG))
+                       edesc->pset[i].opt |= TCINTEN;
+
                /* If this is the last set, enable completion interrupt flag */
                if (i == sg_len - 1)
                        edesc->pset[i].opt |= TCINTEN;
@@ -355,27 +401,65 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
        struct device *dev = echan->vchan.chan.device->dev;
        struct edma_desc *edesc;
        unsigned long flags;
+       struct edmacc_param p;
 
-       /* Stop the channel */
-       edma_stop(echan->ch_num);
+       /* Pause the channel */
+       edma_pause(echan->ch_num);
 
        switch (ch_status) {
        case DMA_COMPLETE:
-               dev_dbg(dev, "transfer complete on channel %d\n", ch_num);
-
                spin_lock_irqsave(&echan->vchan.lock, flags);
 
                edesc = echan->edesc;
                if (edesc) {
+                       if (edesc->processed == edesc->pset_nr) {
+                               dev_dbg(dev, "Transfer complete, stopping channel %d\n", ch_num);
+                               edma_stop(echan->ch_num);
+                               vchan_cookie_complete(&edesc->vdesc);
+                       } else {
+                               dev_dbg(dev, "Intermediate transfer complete on channel %d\n", ch_num);
+                       }
+
                        edma_execute(echan);
-                       vchan_cookie_complete(&edesc->vdesc);
                }
 
                spin_unlock_irqrestore(&echan->vchan.lock, flags);
 
                break;
        case DMA_CC_ERROR:
-               dev_dbg(dev, "transfer error on channel %d\n", ch_num);
+               spin_lock_irqsave(&echan->vchan.lock, flags);
+
+               edma_read_slot(EDMA_CHAN_SLOT(echan->slot[0]), &p);
+
+               /*
+                * Issue later based on missed flag which will be sure
+                * to happen as:
+                * (1) we finished transmitting an intermediate slot and
+                *     edma_execute is coming up.
+                * (2) or we finished current transfer and issue will
+                *     call edma_execute.
+                *
+                * Important note: issuing can be dangerous here and
+                * lead to some nasty recursion when we are in a NULL
+                * slot. So we avoid doing so and set the missed flag.
+                */
+               if (p.a_b_cnt == 0 && p.ccnt == 0) {
+                       dev_dbg(dev, "Error occurred, looks like slot is null, just setting miss\n");
+                       echan->missed = 1;
+               } else {
+                       /*
+                        * The slot is already programmed but the event got
+                        * missed, so its safe to issue it here.
+                        */
+                       dev_dbg(dev, "Error occurred but slot is non-null, TRIGGERING\n");
+                       edma_clean_channel(echan->ch_num);
+                       edma_stop(echan->ch_num);
+                       edma_start(echan->ch_num);
+                       edma_trigger_channel(echan->ch_num);
+               }
+
+               spin_unlock_irqrestore(&echan->vchan.lock, flags);
+
                break;
        default:
                break;
@@ -502,8 +586,6 @@ static enum dma_status edma_tx_status(struct dma_chan *chan,
        } else if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) {
                struct edma_desc *edesc = echan->edesc;
                txstate->residue = edma_desc_size(edesc);
-       } else {
-               txstate->residue = 0;
        }
        spin_unlock_irqrestore(&echan->vchan.lock, flags);
 
index f2bf8c0c46757d0dbd351af10660cc5643f2cfbd..591cd8c63abbcb081a4cd2ca264ed118f7f3d782 100644 (file)
@@ -1313,15 +1313,7 @@ static enum dma_status ep93xx_dma_tx_status(struct dma_chan *chan,
                                            dma_cookie_t cookie,
                                            struct dma_tx_state *state)
 {
-       struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&edmac->lock, flags);
-       ret = dma_cookie_status(chan, cookie, state);
-       spin_unlock_irqrestore(&edmac->lock, flags);
-
-       return ret;
+       return dma_cookie_status(chan, cookie, state);
 }
 
 /**
index 49e8fbdb898388703ac5db7e306e4c5f39d88a19..b3f3e90054f2ab956e8019dd8abe539b85fa0301 100644 (file)
@@ -979,15 +979,7 @@ static enum dma_status fsl_tx_status(struct dma_chan *dchan,
                                        dma_cookie_t cookie,
                                        struct dma_tx_state *txstate)
 {
-       struct fsldma_chan *chan = to_fsl_chan(dchan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
-       ret = dma_cookie_status(dchan, cookie, txstate);
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
-
-       return ret;
+       return dma_cookie_status(dchan, cookie, txstate);
 }
 
 /*----------------------------------------------------------------------------*/
index ff2aab973b45dd1594fc5445380627589a1791c8..78f8ca5fccee91e7a422c419df4ee0ab427d4ad4 100644 (file)
@@ -805,10 +805,8 @@ static void imxdma_free_chan_resources(struct dma_chan *chan)
        }
        INIT_LIST_HEAD(&imxdmac->ld_free);
 
-       if (imxdmac->sg_list) {
-               kfree(imxdmac->sg_list);
-               imxdmac->sg_list = NULL;
-       }
+       kfree(imxdmac->sg_list);
+       imxdmac->sg_list = NULL;
 }
 
 static struct dma_async_tx_descriptor *imxdma_prep_slave_sg(
index 1e44b8cf95dabca6b220c05e8afd33740f8a8455..fc43603cf0bbeca883aa260d880c86898b49e793 100644 (file)
@@ -243,7 +243,6 @@ struct sdma_engine;
  * @event_id1          for channels that use 2 events
  * @word_size          peripheral access size
  * @buf_tail           ID of the buffer that was processed
- * @done               channel completion
  * @num_bd             max NUM_BD. number of descriptors currently handling
  */
 struct sdma_channel {
@@ -255,7 +254,6 @@ struct sdma_channel {
        unsigned int                    event_id1;
        enum dma_slave_buswidth         word_size;
        unsigned int                    buf_tail;
-       struct completion               done;
        unsigned int                    num_bd;
        struct sdma_buffer_descriptor   *bd;
        dma_addr_t                      bd_phys;
@@ -307,9 +305,10 @@ struct sdma_firmware_header {
        u32     ram_code_size;
 };
 
-enum sdma_devtype {
-       IMX31_SDMA,     /* runs on i.mx31 */
-       IMX35_SDMA,     /* runs on i.mx35 and later */
+struct sdma_driver_data {
+       int chnenbl0;
+       int num_events;
+       struct sdma_script_start_addrs  *script_addrs;
 };
 
 struct sdma_engine {
@@ -318,8 +317,6 @@ struct sdma_engine {
        struct sdma_channel             channel[MAX_DMA_CHANNELS];
        struct sdma_channel_control     *channel_control;
        void __iomem                    *regs;
-       enum sdma_devtype               devtype;
-       unsigned int                    num_events;
        struct sdma_context_data        *context;
        dma_addr_t                      context_phys;
        struct dma_device               dma_device;
@@ -327,15 +324,118 @@ struct sdma_engine {
        struct clk                      *clk_ahb;
        spinlock_t                      channel_0_lock;
        struct sdma_script_start_addrs  *script_addrs;
+       const struct sdma_driver_data   *drvdata;
+};
+
+static struct sdma_driver_data sdma_imx31 = {
+       .chnenbl0 = SDMA_CHNENBL0_IMX31,
+       .num_events = 32,
+};
+
+static struct sdma_script_start_addrs sdma_script_imx25 = {
+       .ap_2_ap_addr = 729,
+       .uart_2_mcu_addr = 904,
+       .per_2_app_addr = 1255,
+       .mcu_2_app_addr = 834,
+       .uartsh_2_mcu_addr = 1120,
+       .per_2_shp_addr = 1329,
+       .mcu_2_shp_addr = 1048,
+       .ata_2_mcu_addr = 1560,
+       .mcu_2_ata_addr = 1479,
+       .app_2_per_addr = 1189,
+       .app_2_mcu_addr = 770,
+       .shp_2_per_addr = 1407,
+       .shp_2_mcu_addr = 979,
+};
+
+static struct sdma_driver_data sdma_imx25 = {
+       .chnenbl0 = SDMA_CHNENBL0_IMX35,
+       .num_events = 48,
+       .script_addrs = &sdma_script_imx25,
+};
+
+static struct sdma_driver_data sdma_imx35 = {
+       .chnenbl0 = SDMA_CHNENBL0_IMX35,
+       .num_events = 48,
+};
+
+static struct sdma_script_start_addrs sdma_script_imx51 = {
+       .ap_2_ap_addr = 642,
+       .uart_2_mcu_addr = 817,
+       .mcu_2_app_addr = 747,
+       .mcu_2_shp_addr = 961,
+       .ata_2_mcu_addr = 1473,
+       .mcu_2_ata_addr = 1392,
+       .app_2_per_addr = 1033,
+       .app_2_mcu_addr = 683,
+       .shp_2_per_addr = 1251,
+       .shp_2_mcu_addr = 892,
+};
+
+static struct sdma_driver_data sdma_imx51 = {
+       .chnenbl0 = SDMA_CHNENBL0_IMX35,
+       .num_events = 48,
+       .script_addrs = &sdma_script_imx51,
+};
+
+static struct sdma_script_start_addrs sdma_script_imx53 = {
+       .ap_2_ap_addr = 642,
+       .app_2_mcu_addr = 683,
+       .mcu_2_app_addr = 747,
+       .uart_2_mcu_addr = 817,
+       .shp_2_mcu_addr = 891,
+       .mcu_2_shp_addr = 960,
+       .uartsh_2_mcu_addr = 1032,
+       .spdif_2_mcu_addr = 1100,
+       .mcu_2_spdif_addr = 1134,
+       .firi_2_mcu_addr = 1193,
+       .mcu_2_firi_addr = 1290,
+};
+
+static struct sdma_driver_data sdma_imx53 = {
+       .chnenbl0 = SDMA_CHNENBL0_IMX35,
+       .num_events = 48,
+       .script_addrs = &sdma_script_imx53,
+};
+
+static struct sdma_script_start_addrs sdma_script_imx6q = {
+       .ap_2_ap_addr = 642,
+       .uart_2_mcu_addr = 817,
+       .mcu_2_app_addr = 747,
+       .per_2_per_addr = 6331,
+       .uartsh_2_mcu_addr = 1032,
+       .mcu_2_shp_addr = 960,
+       .app_2_mcu_addr = 683,
+       .shp_2_mcu_addr = 891,
+       .spdif_2_mcu_addr = 1100,
+       .mcu_2_spdif_addr = 1134,
+};
+
+static struct sdma_driver_data sdma_imx6q = {
+       .chnenbl0 = SDMA_CHNENBL0_IMX35,
+       .num_events = 48,
+       .script_addrs = &sdma_script_imx6q,
 };
 
 static struct platform_device_id sdma_devtypes[] = {
        {
+               .name = "imx25-sdma",
+               .driver_data = (unsigned long)&sdma_imx25,
+       }, {
                .name = "imx31-sdma",
-               .driver_data = IMX31_SDMA,
+               .driver_data = (unsigned long)&sdma_imx31,
        }, {
                .name = "imx35-sdma",
-               .driver_data = IMX35_SDMA,
+               .driver_data = (unsigned long)&sdma_imx35,
+       }, {
+               .name = "imx51-sdma",
+               .driver_data = (unsigned long)&sdma_imx51,
+       }, {
+               .name = "imx53-sdma",
+               .driver_data = (unsigned long)&sdma_imx53,
+       }, {
+               .name = "imx6q-sdma",
+               .driver_data = (unsigned long)&sdma_imx6q,
        }, {
                /* sentinel */
        }
@@ -343,8 +443,11 @@ static struct platform_device_id sdma_devtypes[] = {
 MODULE_DEVICE_TABLE(platform, sdma_devtypes);
 
 static const struct of_device_id sdma_dt_ids[] = {
-       { .compatible = "fsl,imx31-sdma", .data = &sdma_devtypes[IMX31_SDMA], },
-       { .compatible = "fsl,imx35-sdma", .data = &sdma_devtypes[IMX35_SDMA], },
+       { .compatible = "fsl,imx6q-sdma", .data = &sdma_imx6q, },
+       { .compatible = "fsl,imx53-sdma", .data = &sdma_imx53, },
+       { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, },
+       { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, },
+       { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, },
        { /* sentinel */ }
 };
 MODULE_DEVICE_TABLE(of, sdma_dt_ids);
@@ -356,8 +459,7 @@ MODULE_DEVICE_TABLE(of, sdma_dt_ids);
 
 static inline u32 chnenbl_ofs(struct sdma_engine *sdma, unsigned int event)
 {
-       u32 chnenbl0 = (sdma->devtype == IMX31_SDMA ? SDMA_CHNENBL0_IMX31 :
-                                                     SDMA_CHNENBL0_IMX35);
+       u32 chnenbl0 = sdma->drvdata->chnenbl0;
        return chnenbl0 + event * 4;
 }
 
@@ -547,8 +649,6 @@ static void sdma_tasklet(unsigned long data)
 {
        struct sdma_channel *sdmac = (struct sdma_channel *) data;
 
-       complete(&sdmac->done);
-
        if (sdmac->flags & IMX_DMA_SG_LOOP)
                sdma_handle_channel_loop(sdmac);
        else
@@ -733,7 +833,7 @@ static int sdma_config_channel(struct sdma_channel *sdmac)
        sdmac->per_addr = 0;
 
        if (sdmac->event_id0) {
-               if (sdmac->event_id0 >= sdmac->sdma->num_events)
+               if (sdmac->event_id0 >= sdmac->sdma->drvdata->num_events)
                        return -EINVAL;
                sdma_event_enable(sdmac, sdmac->event_id0);
        }
@@ -812,9 +912,6 @@ static int sdma_request_channel(struct sdma_channel *sdmac)
        sdma->channel_control[channel].current_bd_ptr = sdmac->bd_phys;
 
        sdma_set_channel_priority(sdmac, MXC_SDMA_DEFAULT_PRIORITY);
-
-       init_completion(&sdmac->done);
-
        return 0;
 out:
 
@@ -1120,15 +1217,12 @@ static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 }
 
 static enum dma_status sdma_tx_status(struct dma_chan *chan,
-                                           dma_cookie_t cookie,
-                                           struct dma_tx_state *txstate)
+                                     dma_cookie_t cookie,
+                                     struct dma_tx_state *txstate)
 {
        struct sdma_channel *sdmac = to_sdma_chan(chan);
-       dma_cookie_t last_used;
-
-       last_used = chan->cookie;
 
-       dma_set_tx_state(txstate, chan->completed_cookie, last_used,
+       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
                        sdmac->chn_count - sdmac->chn_real_count);
 
        return sdmac->status;
@@ -1218,19 +1312,6 @@ static int __init sdma_init(struct sdma_engine *sdma)
        int i, ret;
        dma_addr_t ccb_phys;
 
-       switch (sdma->devtype) {
-       case IMX31_SDMA:
-               sdma->num_events = 32;
-               break;
-       case IMX35_SDMA:
-               sdma->num_events = 48;
-               break;
-       default:
-               dev_err(sdma->dev, "Unknown sdma type %d. aborting\n",
-                       sdma->devtype);
-               return -ENODEV;
-       }
-
        clk_enable(sdma->clk_ipg);
        clk_enable(sdma->clk_ahb);
 
@@ -1257,7 +1338,7 @@ static int __init sdma_init(struct sdma_engine *sdma)
                        MAX_DMA_CHANNELS * sizeof (struct sdma_channel_control));
 
        /* disable all channels */
-       for (i = 0; i < sdma->num_events; i++)
+       for (i = 0; i < sdma->drvdata->num_events; i++)
                writel_relaxed(0, sdma->regs + chnenbl_ofs(sdma, i));
 
        /* All channels have priority 0 */
@@ -1335,10 +1416,21 @@ static int __init sdma_probe(struct platform_device *pdev)
        int ret;
        int irq;
        struct resource *iores;
-       struct sdma_platform_data *pdata = pdev->dev.platform_data;
+       struct sdma_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int i;
        struct sdma_engine *sdma;
        s32 *saddr_arr;
+       const struct sdma_driver_data *drvdata = NULL;
+
+       if (of_id)
+               drvdata = of_id->data;
+       else if (pdev->id_entry)
+               drvdata = (void *)pdev->id_entry->driver_data;
+
+       if (!drvdata) {
+               dev_err(&pdev->dev, "unable to find driver data\n");
+               return -EINVAL;
+       }
 
        sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
        if (!sdma)
@@ -1347,6 +1439,7 @@ static int __init sdma_probe(struct platform_device *pdev)
        spin_lock_init(&sdma->channel_0_lock);
 
        sdma->dev = &pdev->dev;
+       sdma->drvdata = drvdata;
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq = platform_get_irq(pdev, 0);
@@ -1396,10 +1489,6 @@ static int __init sdma_probe(struct platform_device *pdev)
        for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
                saddr_arr[i] = -EINVAL;
 
-       if (of_id)
-               pdev->id_entry = of_id->data;
-       sdma->devtype = pdev->id_entry->driver_data;
-
        dma_cap_set(DMA_SLAVE, sdma->dma_device.cap_mask);
        dma_cap_set(DMA_CYCLIC, sdma->dma_device.cap_mask);
 
@@ -1431,6 +1520,8 @@ static int __init sdma_probe(struct platform_device *pdev)
        if (ret)
                goto err_init;
 
+       if (sdma->drvdata->script_addrs)
+               sdma_add_scripts(sdma, sdma->drvdata->script_addrs);
        if (pdata && pdata->script_addrs)
                sdma_add_scripts(sdma, pdata->script_addrs);
 
index b642e035579b0b468a42ea2772ff17c62c6b684b..d8ececaf1b57082cc5709aca68714542657b5566 100644 (file)
@@ -251,7 +251,7 @@ static bool is_bwd_noraid(struct pci_dev *pdev)
 }
 
 static void pq16_set_src(struct ioat_raw_descriptor *desc[3],
-                       dma_addr_t addr, u32 offset, u8 coef, int idx)
+                       dma_addr_t addr, u32 offset, u8 coef, unsigned idx)
 {
        struct ioat_pq_descriptor *pq = (struct ioat_pq_descriptor *)desc[0];
        struct ioat_pq16a_descriptor *pq16 =
@@ -1775,15 +1775,12 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
        dma->device_alloc_chan_resources = ioat2_alloc_chan_resources;
        dma->device_free_chan_resources = ioat2_free_chan_resources;
 
-       if (is_xeon_cb32(pdev))
-               dma->copy_align = 6;
-
        dma_cap_set(DMA_INTERRUPT, dma->cap_mask);
        dma->device_prep_dma_interrupt = ioat3_prep_interrupt_lock;
 
        device->cap = readl(device->reg_base + IOAT_DMA_CAP_OFFSET);
 
-       if (is_bwd_noraid(pdev))
+       if (is_xeon_cb32(pdev) || is_bwd_noraid(pdev))
                device->cap &= ~(IOAT_CAP_XOR | IOAT_CAP_PQ | IOAT_CAP_RAID16SS);
 
        /* dca is incompatible with raid operations */
@@ -1793,7 +1790,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
        if (device->cap & IOAT_CAP_XOR) {
                is_raid_device = true;
                dma->max_xor = 8;
-               dma->xor_align = 6;
 
                dma_cap_set(DMA_XOR, dma->cap_mask);
                dma->device_prep_dma_xor = ioat3_prep_xor;
@@ -1812,13 +1808,8 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
 
                if (device->cap & IOAT_CAP_RAID16SS) {
                        dma_set_maxpq(dma, 16, 0);
-                       dma->pq_align = 0;
                } else {
                        dma_set_maxpq(dma, 8, 0);
-                       if (is_xeon_cb32(pdev))
-                               dma->pq_align = 6;
-                       else
-                               dma->pq_align = 0;
                }
 
                if (!(device->cap & IOAT_CAP_XOR)) {
@@ -1829,13 +1820,8 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
 
                        if (device->cap & IOAT_CAP_RAID16SS) {
                                dma->max_xor = 16;
-                               dma->xor_align = 0;
                        } else {
                                dma->max_xor = 8;
-                               if (is_xeon_cb32(pdev))
-                                       dma->xor_align = 6;
-                               else
-                                       dma->xor_align = 0;
                        }
                }
        }
@@ -1844,14 +1830,6 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca)
        device->cleanup_fn = ioat3_cleanup_event;
        device->timer_fn = ioat3_timer_event;
 
-       if (is_xeon_cb32(pdev)) {
-               dma_cap_clear(DMA_XOR_VAL, dma->cap_mask);
-               dma->device_prep_dma_xor_val = NULL;
-
-               dma_cap_clear(DMA_PQ_VAL, dma->cap_mask);
-               dma->device_prep_dma_pq_val = NULL;
-       }
-
        /* starting with CB3.3 super extended descriptors are supported */
        if (device->cap & IOAT_CAP_RAID16SS) {
                char pool_name[14];
index cc727ec78c4e4ed668a2eb341d7eeb228bf84a98..dd8b44a56e5d0f7090b8dd65bce87a73a60c90ef 100644 (file)
@@ -518,7 +518,7 @@ static int iop_adma_alloc_chan_resources(struct dma_chan *chan)
        struct iop_adma_desc_slot *slot = NULL;
        int init = iop_chan->slots_allocated ? 0 : 1;
        struct iop_adma_platform_data *plat_data =
-               iop_chan->device->pdev->dev.platform_data;
+               dev_get_platdata(&iop_chan->device->pdev->dev);
        int num_descs_in_pool = plat_data->pool_size/IOP_ADMA_SLOT_SIZE;
 
        /* Allocate descriptor slots */
@@ -1351,7 +1351,7 @@ static int iop_adma_remove(struct platform_device *dev)
        struct iop_adma_device *device = platform_get_drvdata(dev);
        struct dma_chan *chan, *_chan;
        struct iop_adma_chan *iop_chan;
-       struct iop_adma_platform_data *plat_data = dev->dev.platform_data;
+       struct iop_adma_platform_data *plat_data = dev_get_platdata(&dev->dev);
 
        dma_async_device_unregister(&device->common);
 
@@ -1376,7 +1376,7 @@ static int iop_adma_probe(struct platform_device *pdev)
        struct iop_adma_device *adev;
        struct iop_adma_chan *iop_chan;
        struct dma_device *dma_dev;
-       struct iop_adma_platform_data *plat_data = pdev->dev.platform_data;
+       struct iop_adma_platform_data *plat_data = dev_get_platdata(&pdev->dev);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
index d39c2cd0795d71437935d22ce90ca636c8fae0aa..cb9c0bc317e89ed6acebba276ed1be2788cc901e 100644 (file)
@@ -1593,10 +1593,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan)
 static enum dma_status idmac_tx_status(struct dma_chan *chan,
                       dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
-       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 0);
-       if (cookie != chan->cookie)
-               return DMA_ERROR;
-       return DMA_SUCCESS;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 static int __init ipu_idmac_init(struct ipu *ipu)
@@ -1767,7 +1764,6 @@ static int ipu_remove(struct platform_device *pdev)
        iounmap(ipu->reg_ic);
        iounmap(ipu->reg_ipu);
        tasklet_kill(&ipu->tasklet);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
new file mode 100644 (file)
index 0000000..a2c330f
--- /dev/null
@@ -0,0 +1,837 @@
+/*
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2013 Hisilicon Limited.
+ *
+ * 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/sched.h>
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+#define DRIVER_NAME            "k3-dma"
+#define DMA_ALIGN              3
+#define DMA_MAX_SIZE           0x1ffc
+
+#define INT_STAT               0x00
+#define INT_TC1                        0x04
+#define INT_ERR1               0x0c
+#define INT_ERR2               0x10
+#define INT_TC1_MASK           0x18
+#define INT_ERR1_MASK          0x20
+#define INT_ERR2_MASK          0x24
+#define INT_TC1_RAW            0x600
+#define INT_ERR1_RAW           0x608
+#define INT_ERR2_RAW           0x610
+#define CH_PRI                 0x688
+#define CH_STAT                        0x690
+#define CX_CUR_CNT             0x704
+#define CX_LLI                 0x800
+#define CX_CNT                 0x810
+#define CX_SRC                 0x814
+#define CX_DST                 0x818
+#define CX_CFG                 0x81c
+#define AXI_CFG                        0x820
+#define AXI_CFG_DEFAULT                0x201201
+
+#define CX_LLI_CHAIN_EN                0x2
+#define CX_CFG_EN              0x1
+#define CX_CFG_MEM2PER         (0x1 << 2)
+#define CX_CFG_PER2MEM         (0x2 << 2)
+#define CX_CFG_SRCINCR         (0x1 << 31)
+#define CX_CFG_DSTINCR         (0x1 << 30)
+
+struct k3_desc_hw {
+       u32 lli;
+       u32 reserved[3];
+       u32 count;
+       u32 saddr;
+       u32 daddr;
+       u32 config;
+} __aligned(32);
+
+struct k3_dma_desc_sw {
+       struct virt_dma_desc    vd;
+       dma_addr_t              desc_hw_lli;
+       size_t                  desc_num;
+       size_t                  size;
+       struct k3_desc_hw       desc_hw[0];
+};
+
+struct k3_dma_phy;
+
+struct k3_dma_chan {
+       u32                     ccfg;
+       struct virt_dma_chan    vc;
+       struct k3_dma_phy       *phy;
+       struct list_head        node;
+       enum dma_transfer_direction dir;
+       dma_addr_t              dev_addr;
+       enum dma_status         status;
+};
+
+struct k3_dma_phy {
+       u32                     idx;
+       void __iomem            *base;
+       struct k3_dma_chan      *vchan;
+       struct k3_dma_desc_sw   *ds_run;
+       struct k3_dma_desc_sw   *ds_done;
+};
+
+struct k3_dma_dev {
+       struct dma_device       slave;
+       void __iomem            *base;
+       struct tasklet_struct   task;
+       spinlock_t              lock;
+       struct list_head        chan_pending;
+       struct k3_dma_phy       *phy;
+       struct k3_dma_chan      *chans;
+       struct clk              *clk;
+       u32                     dma_channels;
+       u32                     dma_requests;
+};
+
+#define to_k3_dma(dmadev) container_of(dmadev, struct k3_dma_dev, slave)
+
+static struct k3_dma_chan *to_k3_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct k3_dma_chan, vc.chan);
+}
+
+static void k3_dma_pause_dma(struct k3_dma_phy *phy, bool on)
+{
+       u32 val = 0;
+
+       if (on) {
+               val = readl_relaxed(phy->base + CX_CFG);
+               val |= CX_CFG_EN;
+               writel_relaxed(val, phy->base + CX_CFG);
+       } else {
+               val = readl_relaxed(phy->base + CX_CFG);
+               val &= ~CX_CFG_EN;
+               writel_relaxed(val, phy->base + CX_CFG);
+       }
+}
+
+static void k3_dma_terminate_chan(struct k3_dma_phy *phy, struct k3_dma_dev *d)
+{
+       u32 val = 0;
+
+       k3_dma_pause_dma(phy, false);
+
+       val = 0x1 << phy->idx;
+       writel_relaxed(val, d->base + INT_TC1_RAW);
+       writel_relaxed(val, d->base + INT_ERR1_RAW);
+       writel_relaxed(val, d->base + INT_ERR2_RAW);
+}
+
+static void k3_dma_set_desc(struct k3_dma_phy *phy, struct k3_desc_hw *hw)
+{
+       writel_relaxed(hw->lli, phy->base + CX_LLI);
+       writel_relaxed(hw->count, phy->base + CX_CNT);
+       writel_relaxed(hw->saddr, phy->base + CX_SRC);
+       writel_relaxed(hw->daddr, phy->base + CX_DST);
+       writel_relaxed(AXI_CFG_DEFAULT, phy->base + AXI_CFG);
+       writel_relaxed(hw->config, phy->base + CX_CFG);
+}
+
+static u32 k3_dma_get_curr_cnt(struct k3_dma_dev *d, struct k3_dma_phy *phy)
+{
+       u32 cnt = 0;
+
+       cnt = readl_relaxed(d->base + CX_CUR_CNT + phy->idx * 0x10);
+       cnt &= 0xffff;
+       return cnt;
+}
+
+static u32 k3_dma_get_curr_lli(struct k3_dma_phy *phy)
+{
+       return readl_relaxed(phy->base + CX_LLI);
+}
+
+static u32 k3_dma_get_chan_stat(struct k3_dma_dev *d)
+{
+       return readl_relaxed(d->base + CH_STAT);
+}
+
+static void k3_dma_enable_dma(struct k3_dma_dev *d, bool on)
+{
+       if (on) {
+               /* set same priority */
+               writel_relaxed(0x0, d->base + CH_PRI);
+
+               /* unmask irq */
+               writel_relaxed(0xffff, d->base + INT_TC1_MASK);
+               writel_relaxed(0xffff, d->base + INT_ERR1_MASK);
+               writel_relaxed(0xffff, d->base + INT_ERR2_MASK);
+       } else {
+               /* mask irq */
+               writel_relaxed(0x0, d->base + INT_TC1_MASK);
+               writel_relaxed(0x0, d->base + INT_ERR1_MASK);
+               writel_relaxed(0x0, d->base + INT_ERR2_MASK);
+       }
+}
+
+static irqreturn_t k3_dma_int_handler(int irq, void *dev_id)
+{
+       struct k3_dma_dev *d = (struct k3_dma_dev *)dev_id;
+       struct k3_dma_phy *p;
+       struct k3_dma_chan *c;
+       u32 stat = readl_relaxed(d->base + INT_STAT);
+       u32 tc1  = readl_relaxed(d->base + INT_TC1);
+       u32 err1 = readl_relaxed(d->base + INT_ERR1);
+       u32 err2 = readl_relaxed(d->base + INT_ERR2);
+       u32 i, irq_chan = 0;
+
+       while (stat) {
+               i = __ffs(stat);
+               stat &= (stat - 1);
+               if (likely(tc1 & BIT(i))) {
+                       p = &d->phy[i];
+                       c = p->vchan;
+                       if (c) {
+                               unsigned long flags;
+
+                               spin_lock_irqsave(&c->vc.lock, flags);
+                               vchan_cookie_complete(&p->ds_run->vd);
+                               p->ds_done = p->ds_run;
+                               spin_unlock_irqrestore(&c->vc.lock, flags);
+                       }
+                       irq_chan |= BIT(i);
+               }
+               if (unlikely((err1 & BIT(i)) || (err2 & BIT(i))))
+                       dev_warn(d->slave.dev, "DMA ERR\n");
+       }
+
+       writel_relaxed(irq_chan, d->base + INT_TC1_RAW);
+       writel_relaxed(err1, d->base + INT_ERR1_RAW);
+       writel_relaxed(err2, d->base + INT_ERR2_RAW);
+
+       if (irq_chan) {
+               tasklet_schedule(&d->task);
+               return IRQ_HANDLED;
+       } else
+               return IRQ_NONE;
+}
+
+static int k3_dma_start_txd(struct k3_dma_chan *c)
+{
+       struct k3_dma_dev *d = to_k3_dma(c->vc.chan.device);
+       struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+
+       if (!c->phy)
+               return -EAGAIN;
+
+       if (BIT(c->phy->idx) & k3_dma_get_chan_stat(d))
+               return -EAGAIN;
+
+       if (vd) {
+               struct k3_dma_desc_sw *ds =
+                       container_of(vd, struct k3_dma_desc_sw, vd);
+               /*
+                * fetch and remove request from vc->desc_issued
+                * so vc->desc_issued only contains desc pending
+                */
+               list_del(&ds->vd.node);
+               c->phy->ds_run = ds;
+               c->phy->ds_done = NULL;
+               /* start dma */
+               k3_dma_set_desc(c->phy, &ds->desc_hw[0]);
+               return 0;
+       }
+       c->phy->ds_done = NULL;
+       c->phy->ds_run = NULL;
+       return -EAGAIN;
+}
+
+static void k3_dma_tasklet(unsigned long arg)
+{
+       struct k3_dma_dev *d = (struct k3_dma_dev *)arg;
+       struct k3_dma_phy *p;
+       struct k3_dma_chan *c, *cn;
+       unsigned pch, pch_alloc = 0;
+
+       /* check new dma request of running channel in vc->desc_issued */
+       list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
+               spin_lock_irq(&c->vc.lock);
+               p = c->phy;
+               if (p && p->ds_done) {
+                       if (k3_dma_start_txd(c)) {
+                               /* No current txd associated with this channel */
+                               dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx);
+                               /* Mark this channel free */
+                               c->phy = NULL;
+                               p->vchan = NULL;
+                       }
+               }
+               spin_unlock_irq(&c->vc.lock);
+       }
+
+       /* check new channel request in d->chan_pending */
+       spin_lock_irq(&d->lock);
+       for (pch = 0; pch < d->dma_channels; pch++) {
+               p = &d->phy[pch];
+
+               if (p->vchan == NULL && !list_empty(&d->chan_pending)) {
+                       c = list_first_entry(&d->chan_pending,
+                               struct k3_dma_chan, node);
+                       /* remove from d->chan_pending */
+                       list_del_init(&c->node);
+                       pch_alloc |= 1 << pch;
+                       /* Mark this channel allocated */
+                       p->vchan = c;
+                       c->phy = p;
+                       dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
+               }
+       }
+       spin_unlock_irq(&d->lock);
+
+       for (pch = 0; pch < d->dma_channels; pch++) {
+               if (pch_alloc & (1 << pch)) {
+                       p = &d->phy[pch];
+                       c = p->vchan;
+                       if (c) {
+                               spin_lock_irq(&c->vc.lock);
+                               k3_dma_start_txd(c);
+                               spin_unlock_irq(&c->vc.lock);
+                       }
+               }
+       }
+}
+
+static int k3_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       return 0;
+}
+
+static void k3_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
+       struct k3_dma_dev *d = to_k3_dma(chan->device);
+       unsigned long flags;
+
+       spin_lock_irqsave(&d->lock, flags);
+       list_del_init(&c->node);
+       spin_unlock_irqrestore(&d->lock, flags);
+
+       vchan_free_chan_resources(&c->vc);
+       c->ccfg = 0;
+}
+
+static enum dma_status k3_dma_tx_status(struct dma_chan *chan,
+       dma_cookie_t cookie, struct dma_tx_state *state)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
+       struct k3_dma_dev *d = to_k3_dma(chan->device);
+       struct k3_dma_phy *p;
+       struct virt_dma_desc *vd;
+       unsigned long flags;
+       enum dma_status ret;
+       size_t bytes = 0;
+
+       ret = dma_cookie_status(&c->vc.chan, cookie, state);
+       if (ret == DMA_SUCCESS)
+               return ret;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       p = c->phy;
+       ret = c->status;
+
+       /*
+        * If the cookie is on our issue queue, then the residue is
+        * its total size.
+        */
+       vd = vchan_find_desc(&c->vc, cookie);
+       if (vd) {
+               bytes = container_of(vd, struct k3_dma_desc_sw, vd)->size;
+       } else if ((!p) || (!p->ds_run)) {
+               bytes = 0;
+       } else {
+               struct k3_dma_desc_sw *ds = p->ds_run;
+               u32 clli = 0, index = 0;
+
+               bytes = k3_dma_get_curr_cnt(d, p);
+               clli = k3_dma_get_curr_lli(p);
+               index = (clli - ds->desc_hw_lli) / sizeof(struct k3_desc_hw);
+               for (; index < ds->desc_num; index++) {
+                       bytes += ds->desc_hw[index].count;
+                       /* end of lli */
+                       if (!ds->desc_hw[index].lli)
+                               break;
+               }
+       }
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+       dma_set_residue(state, bytes);
+       return ret;
+}
+
+static void k3_dma_issue_pending(struct dma_chan *chan)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
+       struct k3_dma_dev *d = to_k3_dma(chan->device);
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       /* add request to vc->desc_issued */
+       if (vchan_issue_pending(&c->vc)) {
+               spin_lock(&d->lock);
+               if (!c->phy) {
+                       if (list_empty(&c->node)) {
+                               /* if new channel, add chan_pending */
+                               list_add_tail(&c->node, &d->chan_pending);
+                               /* check in tasklet */
+                               tasklet_schedule(&d->task);
+                               dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
+                       }
+               }
+               spin_unlock(&d->lock);
+       } else
+               dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static void k3_dma_fill_desc(struct k3_dma_desc_sw *ds, dma_addr_t dst,
+                       dma_addr_t src, size_t len, u32 num, u32 ccfg)
+{
+       if ((num + 1) < ds->desc_num)
+               ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) *
+                       sizeof(struct k3_desc_hw);
+       ds->desc_hw[num].lli |= CX_LLI_CHAIN_EN;
+       ds->desc_hw[num].count = len;
+       ds->desc_hw[num].saddr = src;
+       ds->desc_hw[num].daddr = dst;
+       ds->desc_hw[num].config = ccfg;
+}
+
+static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
+       struct dma_chan *chan,  dma_addr_t dst, dma_addr_t src,
+       size_t len, unsigned long flags)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
+       struct k3_dma_desc_sw *ds;
+       size_t copy = 0;
+       int num = 0;
+
+       if (!len)
+               return NULL;
+
+       num = DIV_ROUND_UP(len, DMA_MAX_SIZE);
+       ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
+       if (!ds) {
+               dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+               return NULL;
+       }
+       ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
+       ds->size = len;
+       ds->desc_num = num;
+       num = 0;
+
+       if (!c->ccfg) {
+               /* default is memtomem, without calling device_control */
+               c->ccfg = CX_CFG_SRCINCR | CX_CFG_DSTINCR | CX_CFG_EN;
+               c->ccfg |= (0xf << 20) | (0xf << 24);   /* burst = 16 */
+               c->ccfg |= (0x3 << 12) | (0x3 << 16);   /* width = 64 bit */
+       }
+
+       do {
+               copy = min_t(size_t, len, DMA_MAX_SIZE);
+               k3_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg);
+
+               if (c->dir == DMA_MEM_TO_DEV) {
+                       src += copy;
+               } else if (c->dir == DMA_DEV_TO_MEM) {
+                       dst += copy;
+               } else {
+                       src += copy;
+                       dst += copy;
+               }
+               len -= copy;
+       } while (len);
+
+       ds->desc_hw[num-1].lli = 0;     /* end of link */
+       return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
+       struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen,
+       enum dma_transfer_direction dir, unsigned long flags, void *context)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
+       struct k3_dma_desc_sw *ds;
+       size_t len, avail, total = 0;
+       struct scatterlist *sg;
+       dma_addr_t addr, src = 0, dst = 0;
+       int num = sglen, i;
+
+       if (sgl == 0)
+               return NULL;
+
+       for_each_sg(sgl, sg, sglen, i) {
+               avail = sg_dma_len(sg);
+               if (avail > DMA_MAX_SIZE)
+                       num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1;
+       }
+
+       ds = kzalloc(sizeof(*ds) + num * sizeof(ds->desc_hw[0]), GFP_ATOMIC);
+       if (!ds) {
+               dev_dbg(chan->device->dev, "vchan %p: kzalloc fail\n", &c->vc);
+               return NULL;
+       }
+       ds->desc_hw_lli = __virt_to_phys((unsigned long)&ds->desc_hw[0]);
+       ds->desc_num = num;
+       num = 0;
+
+       for_each_sg(sgl, sg, sglen, i) {
+               addr = sg_dma_address(sg);
+               avail = sg_dma_len(sg);
+               total += avail;
+
+               do {
+                       len = min_t(size_t, avail, DMA_MAX_SIZE);
+
+                       if (dir == DMA_MEM_TO_DEV) {
+                               src = addr;
+                               dst = c->dev_addr;
+                       } else if (dir == DMA_DEV_TO_MEM) {
+                               src = c->dev_addr;
+                               dst = addr;
+                       }
+
+                       k3_dma_fill_desc(ds, dst, src, len, num++, c->ccfg);
+
+                       addr += len;
+                       avail -= len;
+               } while (avail);
+       }
+
+       ds->desc_hw[num-1].lli = 0;     /* end of link */
+       ds->size = total;
+       return vchan_tx_prep(&c->vc, &ds->vd, flags);
+}
+
+static int k3_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct k3_dma_chan *c = to_k3_chan(chan);
+       struct k3_dma_dev *d = to_k3_dma(chan->device);
+       struct dma_slave_config *cfg = (void *)arg;
+       struct k3_dma_phy *p = c->phy;
+       unsigned long flags;
+       u32 maxburst = 0, val = 0;
+       enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+       LIST_HEAD(head);
+
+       switch (cmd) {
+       case DMA_SLAVE_CONFIG:
+               if (cfg == NULL)
+                       return -EINVAL;
+               c->dir = cfg->direction;
+               if (c->dir == DMA_DEV_TO_MEM) {
+                       c->ccfg = CX_CFG_DSTINCR;
+                       c->dev_addr = cfg->src_addr;
+                       maxburst = cfg->src_maxburst;
+                       width = cfg->src_addr_width;
+               } else if (c->dir == DMA_MEM_TO_DEV) {
+                       c->ccfg = CX_CFG_SRCINCR;
+                       c->dev_addr = cfg->dst_addr;
+                       maxburst = cfg->dst_maxburst;
+                       width = cfg->dst_addr_width;
+               }
+               switch (width) {
+               case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               case DMA_SLAVE_BUSWIDTH_8_BYTES:
+                       val =  __ffs(width);
+                       break;
+               default:
+                       val = 3;
+                       break;
+               }
+               c->ccfg |= (val << 12) | (val << 16);
+
+               if ((maxburst == 0) || (maxburst > 16))
+                       val = 16;
+               else
+                       val = maxburst - 1;
+               c->ccfg |= (val << 20) | (val << 24);
+               c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;
+
+               /* specific request line */
+               c->ccfg |= c->vc.chan.chan_id << 4;
+               break;
+
+       case DMA_TERMINATE_ALL:
+               dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
+
+               /* Prevent this channel being scheduled */
+               spin_lock(&d->lock);
+               list_del_init(&c->node);
+               spin_unlock(&d->lock);
+
+               /* Clear the tx descriptor lists */
+               spin_lock_irqsave(&c->vc.lock, flags);
+               vchan_get_all_descriptors(&c->vc, &head);
+               if (p) {
+                       /* vchan is assigned to a pchan - stop the channel */
+                       k3_dma_terminate_chan(p, d);
+                       c->phy = NULL;
+                       p->vchan = NULL;
+                       p->ds_run = p->ds_done = NULL;
+               }
+               spin_unlock_irqrestore(&c->vc.lock, flags);
+               vchan_dma_desc_free_list(&c->vc, &head);
+               break;
+
+       case DMA_PAUSE:
+               dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
+               if (c->status == DMA_IN_PROGRESS) {
+                       c->status = DMA_PAUSED;
+                       if (p) {
+                               k3_dma_pause_dma(p, false);
+                       } else {
+                               spin_lock(&d->lock);
+                               list_del_init(&c->node);
+                               spin_unlock(&d->lock);
+                       }
+               }
+               break;
+
+       case DMA_RESUME:
+               dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
+               spin_lock_irqsave(&c->vc.lock, flags);
+               if (c->status == DMA_PAUSED) {
+                       c->status = DMA_IN_PROGRESS;
+                       if (p) {
+                               k3_dma_pause_dma(p, true);
+                       } else if (!list_empty(&c->vc.desc_issued)) {
+                               spin_lock(&d->lock);
+                               list_add_tail(&c->node, &d->chan_pending);
+                               spin_unlock(&d->lock);
+                       }
+               }
+               spin_unlock_irqrestore(&c->vc.lock, flags);
+               break;
+       default:
+               return -ENXIO;
+       }
+       return 0;
+}
+
+static void k3_dma_free_desc(struct virt_dma_desc *vd)
+{
+       struct k3_dma_desc_sw *ds =
+               container_of(vd, struct k3_dma_desc_sw, vd);
+
+       kfree(ds);
+}
+
+static struct of_device_id k3_pdma_dt_ids[] = {
+       { .compatible = "hisilicon,k3-dma-1.0", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, k3_pdma_dt_ids);
+
+static struct dma_chan *k3_of_dma_simple_xlate(struct of_phandle_args *dma_spec,
+                                               struct of_dma *ofdma)
+{
+       struct k3_dma_dev *d = ofdma->of_dma_data;
+       unsigned int request = dma_spec->args[0];
+
+       if (request > d->dma_requests)
+               return NULL;
+
+       return dma_get_slave_channel(&(d->chans[request].vc.chan));
+}
+
+static int k3_dma_probe(struct platform_device *op)
+{
+       struct k3_dma_dev *d;
+       const struct of_device_id *of_id;
+       struct resource *iores;
+       int i, ret, irq = 0;
+
+       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
+       if (!iores)
+               return -EINVAL;
+
+       d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL);
+       if (!d)
+               return -ENOMEM;
+
+       d->base = devm_ioremap_resource(&op->dev, iores);
+       if (IS_ERR(d->base))
+               return PTR_ERR(d->base);
+
+       of_id = of_match_device(k3_pdma_dt_ids, &op->dev);
+       if (of_id) {
+               of_property_read_u32((&op->dev)->of_node,
+                               "dma-channels", &d->dma_channels);
+               of_property_read_u32((&op->dev)->of_node,
+                               "dma-requests", &d->dma_requests);
+       }
+
+       d->clk = devm_clk_get(&op->dev, NULL);
+       if (IS_ERR(d->clk)) {
+               dev_err(&op->dev, "no dma clk\n");
+               return PTR_ERR(d->clk);
+       }
+
+       irq = platform_get_irq(op, 0);
+       ret = devm_request_irq(&op->dev, irq,
+                       k3_dma_int_handler, IRQF_DISABLED, DRIVER_NAME, d);
+       if (ret)
+               return ret;
+
+       /* init phy channel */
+       d->phy = devm_kzalloc(&op->dev,
+               d->dma_channels * sizeof(struct k3_dma_phy), GFP_KERNEL);
+       if (d->phy == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < d->dma_channels; i++) {
+               struct k3_dma_phy *p = &d->phy[i];
+
+               p->idx = i;
+               p->base = d->base + i * 0x40;
+       }
+
+       INIT_LIST_HEAD(&d->slave.channels);
+       dma_cap_set(DMA_SLAVE, d->slave.cap_mask);
+       dma_cap_set(DMA_MEMCPY, d->slave.cap_mask);
+       d->slave.dev = &op->dev;
+       d->slave.device_alloc_chan_resources = k3_dma_alloc_chan_resources;
+       d->slave.device_free_chan_resources = k3_dma_free_chan_resources;
+       d->slave.device_tx_status = k3_dma_tx_status;
+       d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
+       d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
+       d->slave.device_issue_pending = k3_dma_issue_pending;
+       d->slave.device_control = k3_dma_control;
+       d->slave.copy_align = DMA_ALIGN;
+       d->slave.chancnt = d->dma_requests;
+
+       /* init virtual channel */
+       d->chans = devm_kzalloc(&op->dev,
+               d->dma_requests * sizeof(struct k3_dma_chan), GFP_KERNEL);
+       if (d->chans == NULL)
+               return -ENOMEM;
+
+       for (i = 0; i < d->dma_requests; i++) {
+               struct k3_dma_chan *c = &d->chans[i];
+
+               c->status = DMA_IN_PROGRESS;
+               INIT_LIST_HEAD(&c->node);
+               c->vc.desc_free = k3_dma_free_desc;
+               vchan_init(&c->vc, &d->slave);
+       }
+
+       /* Enable clock before accessing registers */
+       ret = clk_prepare_enable(d->clk);
+       if (ret < 0) {
+               dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       k3_dma_enable_dma(d, true);
+
+       ret = dma_async_device_register(&d->slave);
+       if (ret)
+               return ret;
+
+       ret = of_dma_controller_register((&op->dev)->of_node,
+                                       k3_of_dma_simple_xlate, d);
+       if (ret)
+               goto of_dma_register_fail;
+
+       spin_lock_init(&d->lock);
+       INIT_LIST_HEAD(&d->chan_pending);
+       tasklet_init(&d->task, k3_dma_tasklet, (unsigned long)d);
+       platform_set_drvdata(op, d);
+       dev_info(&op->dev, "initialized\n");
+
+       return 0;
+
+of_dma_register_fail:
+       dma_async_device_unregister(&d->slave);
+       return ret;
+}
+
+static int k3_dma_remove(struct platform_device *op)
+{
+       struct k3_dma_chan *c, *cn;
+       struct k3_dma_dev *d = platform_get_drvdata(op);
+
+       dma_async_device_unregister(&d->slave);
+       of_dma_controller_free((&op->dev)->of_node);
+
+       list_for_each_entry_safe(c, cn, &d->slave.channels, vc.chan.device_node) {
+               list_del(&c->vc.chan.device_node);
+               tasklet_kill(&c->vc.task);
+       }
+       tasklet_kill(&d->task);
+       clk_disable_unprepare(d->clk);
+       return 0;
+}
+
+static int k3_dma_suspend(struct device *dev)
+{
+       struct k3_dma_dev *d = dev_get_drvdata(dev);
+       u32 stat = 0;
+
+       stat = k3_dma_get_chan_stat(d);
+       if (stat) {
+               dev_warn(d->slave.dev,
+                       "chan %d is running fail to suspend\n", stat);
+               return -1;
+       }
+       k3_dma_enable_dma(d, false);
+       clk_disable_unprepare(d->clk);
+       return 0;
+}
+
+static int k3_dma_resume(struct device *dev)
+{
+       struct k3_dma_dev *d = dev_get_drvdata(dev);
+       int ret = 0;
+
+       ret = clk_prepare_enable(d->clk);
+       if (ret < 0) {
+               dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret);
+               return ret;
+       }
+       k3_dma_enable_dma(d, true);
+       return 0;
+}
+
+SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume);
+
+static struct platform_driver k3_pdma_driver = {
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+               .pm     = &k3_dma_pmops,
+               .of_match_table = k3_pdma_dt_ids,
+       },
+       .probe          = k3_dma_probe,
+       .remove         = k3_dma_remove,
+};
+
+module_platform_driver(k3_pdma_driver);
+
+MODULE_DESCRIPTION("Hisilicon k3 DMA Driver");
+MODULE_ALIAS("platform:k3dma");
+MODULE_LICENSE("GPL v2");
index c26699f9c4dfdbcec1c3f0d6ee0cf3d173227294..ff8d7827f8cbe80e2c66d78db1f50ad6fdd91b5a 100644 (file)
@@ -18,7 +18,9 @@
 #include <linux/platform_data/mmp_dma.h>
 #include <linux/dmapool.h>
 #include <linux/of_device.h>
+#include <linux/of_dma.h>
 #include <linux/of.h>
+#include <linux/dma/mmp-pdma.h>
 
 #include "dmaengine.h"
 
@@ -47,6 +49,8 @@
 #define DCSR_CMPST     (1 << 10)       /* The Descriptor Compare Status */
 #define DCSR_EORINTR   (1 << 9)        /* The end of Receive */
 
+#define DRCMR(n)       ((((n) < 64) ? 0x0100 : 0x1100) + \
+                                (((n) & 0x3f) << 2))
 #define DRCMR_MAPVLD   (1 << 7)        /* Map Valid (read / write) */
 #define DRCMR_CHLNUM   0x1f            /* mask for Channel Number (read / write) */
 
@@ -69,7 +73,7 @@
 #define DCMD_LENGTH    0x01fff         /* length mask (max = 8K - 1) */
 
 #define PDMA_ALIGNMENT         3
-#define PDMA_MAX_DESC_BYTES    0x1000
+#define PDMA_MAX_DESC_BYTES    DCMD_LENGTH
 
 struct mmp_pdma_desc_hw {
        u32 ddadr;      /* Points to the next descriptor + flags */
@@ -94,6 +98,9 @@ struct mmp_pdma_chan {
        struct mmp_pdma_phy *phy;
        enum dma_transfer_direction dir;
 
+       struct mmp_pdma_desc_sw *cyclic_first;  /* first desc_sw if channel
+                                                * is in cyclic mode */
+
        /* channel's basic info */
        struct tasklet_struct tasklet;
        u32 dcmd;
@@ -105,6 +112,7 @@ struct mmp_pdma_chan {
        struct list_head chain_pending; /* Link descriptors queue for pending */
        struct list_head chain_running; /* Link descriptors queue for running */
        bool idle;                      /* channel statue machine */
+       bool byte_align;
 
        struct dma_pool *desc_pool;     /* Descriptors pool */
 };
@@ -121,6 +129,7 @@ struct mmp_pdma_device {
        struct device                   *dev;
        struct dma_device               device;
        struct mmp_pdma_phy             *phy;
+       spinlock_t phy_lock; /* protect alloc/free phy channels */
 };
 
 #define tx_to_mmp_pdma_desc(tx) container_of(tx, struct mmp_pdma_desc_sw, async_tx)
@@ -137,15 +146,21 @@ static void set_desc(struct mmp_pdma_phy *phy, dma_addr_t addr)
 
 static void enable_chan(struct mmp_pdma_phy *phy)
 {
-       u32 reg;
+       u32 reg, dalgn;
 
        if (!phy->vchan)
                return;
 
-       reg = phy->vchan->drcmr;
-       reg = (((reg) < 64) ? 0x0100 : 0x1100) + (((reg) & 0x3f) << 2);
+       reg = DRCMR(phy->vchan->drcmr);
        writel(DRCMR_MAPVLD | phy->idx, phy->base + reg);
 
+       dalgn = readl(phy->base + DALGN);
+       if (phy->vchan->byte_align)
+               dalgn |= 1 << phy->idx;
+       else
+               dalgn &= ~(1 << phy->idx);
+       writel(dalgn, phy->base + DALGN);
+
        reg = (phy->idx << 2) + DCSR;
        writel(readl(phy->base + reg) | DCSR_RUN,
                                        phy->base + reg);
@@ -218,7 +233,8 @@ static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan)
 {
        int prio, i;
        struct mmp_pdma_device *pdev = to_mmp_pdma_dev(pchan->chan.device);
-       struct mmp_pdma_phy *phy;
+       struct mmp_pdma_phy *phy, *found = NULL;
+       unsigned long flags;
 
        /*
         * dma channel priorities
@@ -227,6 +243,8 @@ static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan)
         * ch 8 - 11, 24 - 27  <--> (2)
         * ch 12 - 15, 28 - 31  <--> (3)
         */
+
+       spin_lock_irqsave(&pdev->phy_lock, flags);
        for (prio = 0; prio <= (((pdev->dma_channels - 1) & 0xf) >> 2); prio++) {
                for (i = 0; i < pdev->dma_channels; i++) {
                        if (prio != ((i & 0xf) >> 2))
@@ -234,31 +252,34 @@ static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan)
                        phy = &pdev->phy[i];
                        if (!phy->vchan) {
                                phy->vchan = pchan;
-                               return phy;
+                               found = phy;
+                               goto out_unlock;
                        }
                }
        }
 
-       return NULL;
+out_unlock:
+       spin_unlock_irqrestore(&pdev->phy_lock, flags);
+       return found;
 }
 
-/* desc->tx_list ==> pending list */
-static void append_pending_queue(struct mmp_pdma_chan *chan,
-                                       struct mmp_pdma_desc_sw *desc)
+static void mmp_pdma_free_phy(struct mmp_pdma_chan *pchan)
 {
-       struct mmp_pdma_desc_sw *tail =
-                               to_mmp_pdma_desc(chan->chain_pending.prev);
+       struct mmp_pdma_device *pdev = to_mmp_pdma_dev(pchan->chan.device);
+       unsigned long flags;
+       u32 reg;
 
-       if (list_empty(&chan->chain_pending))
-               goto out_splice;
+       if (!pchan->phy)
+               return;
 
-       /* one irq per queue, even appended */
-       tail->desc.ddadr = desc->async_tx.phys;
-       tail->desc.dcmd &= ~DCMD_ENDIRQEN;
+       /* clear the channel mapping in DRCMR */
+       reg = DRCMR(pchan->phy->vchan->drcmr);
+       writel(0, pchan->phy->base + reg);
 
-       /* softly link to pending list */
-out_splice:
-       list_splice_tail_init(&desc->tx_list, &chan->chain_pending);
+       spin_lock_irqsave(&pdev->phy_lock, flags);
+       pchan->phy->vchan = NULL;
+       pchan->phy = NULL;
+       spin_unlock_irqrestore(&pdev->phy_lock, flags);
 }
 
 /**
@@ -277,10 +298,7 @@ static void start_pending_queue(struct mmp_pdma_chan *chan)
 
        if (list_empty(&chan->chain_pending)) {
                /* chance to re-fetch phy channel with higher prio */
-               if (chan->phy) {
-                       chan->phy->vchan = NULL;
-                       chan->phy = NULL;
-               }
+               mmp_pdma_free_phy(chan);
                dev_dbg(chan->dev, "no pending list\n");
                return;
        }
@@ -326,14 +344,16 @@ static dma_cookie_t mmp_pdma_tx_submit(struct dma_async_tx_descriptor *tx)
                cookie = dma_cookie_assign(&child->async_tx);
        }
 
-       append_pending_queue(chan, desc);
+       /* softly link to pending list - desc->tx_list ==> pending list */
+       list_splice_tail_init(&desc->tx_list, &chan->chain_pending);
 
        spin_unlock_irqrestore(&chan->desc_lock, flags);
 
        return cookie;
 }
 
-struct mmp_pdma_desc_sw *mmp_pdma_alloc_descriptor(struct mmp_pdma_chan *chan)
+static struct mmp_pdma_desc_sw *
+mmp_pdma_alloc_descriptor(struct mmp_pdma_chan *chan)
 {
        struct mmp_pdma_desc_sw *desc;
        dma_addr_t pdesc;
@@ -377,10 +397,7 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
                dev_err(chan->dev, "unable to allocate descriptor pool\n");
                return -ENOMEM;
        }
-       if (chan->phy) {
-               chan->phy->vchan = NULL;
-               chan->phy = NULL;
-       }
+       mmp_pdma_free_phy(chan);
        chan->idle = true;
        chan->dev_addr = 0;
        return 1;
@@ -411,10 +428,7 @@ static void mmp_pdma_free_chan_resources(struct dma_chan *dchan)
        chan->desc_pool = NULL;
        chan->idle = true;
        chan->dev_addr = 0;
-       if (chan->phy) {
-               chan->phy->vchan = NULL;
-               chan->phy = NULL;
-       }
+       mmp_pdma_free_phy(chan);
        return;
 }
 
@@ -434,6 +448,7 @@ mmp_pdma_prep_memcpy(struct dma_chan *dchan,
                return NULL;
 
        chan = to_mmp_pdma_chan(dchan);
+       chan->byte_align = false;
 
        if (!chan->dir) {
                chan->dir = DMA_MEM_TO_MEM;
@@ -450,6 +465,8 @@ mmp_pdma_prep_memcpy(struct dma_chan *dchan,
                }
 
                copy = min_t(size_t, len, PDMA_MAX_DESC_BYTES);
+               if (dma_src & 0x7 || dma_dst & 0x7)
+                       chan->byte_align = true;
 
                new->desc.dcmd = chan->dcmd | (DCMD_LENGTH & copy);
                new->desc.dsadr = dma_src;
@@ -486,6 +503,8 @@ mmp_pdma_prep_memcpy(struct dma_chan *dchan,
        new->desc.ddadr = DDADR_STOP;
        new->desc.dcmd |= DCMD_ENDIRQEN;
 
+       chan->cyclic_first = NULL;
+
        return &first->async_tx;
 
 fail:
@@ -509,12 +528,16 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
        if ((sgl == NULL) || (sg_len == 0))
                return NULL;
 
+       chan->byte_align = false;
+
        for_each_sg(sgl, sg, sg_len, i) {
                addr = sg_dma_address(sg);
                avail = sg_dma_len(sgl);
 
                do {
                        len = min_t(size_t, avail, PDMA_MAX_DESC_BYTES);
+                       if (addr & 0x7)
+                               chan->byte_align = true;
 
                        /* allocate and populate the descriptor */
                        new = mmp_pdma_alloc_descriptor(chan);
@@ -557,6 +580,94 @@ mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
        new->desc.ddadr = DDADR_STOP;
        new->desc.dcmd |= DCMD_ENDIRQEN;
 
+       chan->dir = dir;
+       chan->cyclic_first = NULL;
+
+       return &first->async_tx;
+
+fail:
+       if (first)
+               mmp_pdma_free_desc_list(chan, &first->tx_list);
+       return NULL;
+}
+
+static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic(
+       struct dma_chan *dchan, dma_addr_t buf_addr, size_t len,
+       size_t period_len, enum dma_transfer_direction direction,
+       unsigned long flags, void *context)
+{
+       struct mmp_pdma_chan *chan;
+       struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new;
+       dma_addr_t dma_src, dma_dst;
+
+       if (!dchan || !len || !period_len)
+               return NULL;
+
+       /* the buffer length must be a multiple of period_len */
+       if (len % period_len != 0)
+               return NULL;
+
+       if (period_len > PDMA_MAX_DESC_BYTES)
+               return NULL;
+
+       chan = to_mmp_pdma_chan(dchan);
+
+       switch (direction) {
+       case DMA_MEM_TO_DEV:
+               dma_src = buf_addr;
+               dma_dst = chan->dev_addr;
+               break;
+       case DMA_DEV_TO_MEM:
+               dma_dst = buf_addr;
+               dma_src = chan->dev_addr;
+               break;
+       default:
+               dev_err(chan->dev, "Unsupported direction for cyclic DMA\n");
+               return NULL;
+       }
+
+       chan->dir = direction;
+
+       do {
+               /* Allocate the link descriptor from DMA pool */
+               new = mmp_pdma_alloc_descriptor(chan);
+               if (!new) {
+                       dev_err(chan->dev, "no memory for desc\n");
+                       goto fail;
+               }
+
+               new->desc.dcmd = chan->dcmd | DCMD_ENDIRQEN |
+                                       (DCMD_LENGTH & period_len);
+               new->desc.dsadr = dma_src;
+               new->desc.dtadr = dma_dst;
+
+               if (!first)
+                       first = new;
+               else
+                       prev->desc.ddadr = new->async_tx.phys;
+
+               new->async_tx.cookie = 0;
+               async_tx_ack(&new->async_tx);
+
+               prev = new;
+               len -= period_len;
+
+               if (chan->dir == DMA_MEM_TO_DEV)
+                       dma_src += period_len;
+               else
+                       dma_dst += period_len;
+
+               /* Insert the link descriptor to the LD ring */
+               list_add_tail(&new->node, &first->tx_list);
+       } while (len);
+
+       first->async_tx.flags = flags; /* client is in control of this ack */
+       first->async_tx.cookie = -EBUSY;
+
+       /* make the cyclic link */
+       new->desc.ddadr = first->async_tx.phys;
+       chan->cyclic_first = first;
+
        return &first->async_tx;
 
 fail:
@@ -581,10 +692,7 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
        switch (cmd) {
        case DMA_TERMINATE_ALL:
                disable_chan(chan->phy);
-               if (chan->phy) {
-                       chan->phy->vchan = NULL;
-                       chan->phy = NULL;
-               }
+               mmp_pdma_free_phy(chan);
                spin_lock_irqsave(&chan->desc_lock, flags);
                mmp_pdma_free_desc_list(chan, &chan->chain_pending);
                mmp_pdma_free_desc_list(chan, &chan->chain_running);
@@ -619,8 +727,13 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
                        chan->dcmd |= DCMD_BURST32;
 
                chan->dir = cfg->direction;
-               chan->drcmr = cfg->slave_id;
                chan->dev_addr = addr;
+               /* FIXME: drivers should be ported over to use the filter
+                * function. Once that's done, the following two lines can
+                * be removed.
+                */
+               if (cfg->slave_id)
+                       chan->drcmr = cfg->slave_id;
                break;
        default:
                return -ENOSYS;
@@ -632,15 +745,7 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
 static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan,
                        dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
-       struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->desc_lock, flags);
-       ret = dma_cookie_status(dchan, cookie, txstate);
-       spin_unlock_irqrestore(&chan->desc_lock, flags);
-
-       return ret;
+       return dma_cookie_status(dchan, cookie, txstate);
 }
 
 /**
@@ -669,29 +774,51 @@ static void dma_do_tasklet(unsigned long data)
        LIST_HEAD(chain_cleanup);
        unsigned long flags;
 
-       /* submit pending list; callback for each desc; free desc */
+       if (chan->cyclic_first) {
+               dma_async_tx_callback cb = NULL;
+               void *cb_data = NULL;
 
-       spin_lock_irqsave(&chan->desc_lock, flags);
+               spin_lock_irqsave(&chan->desc_lock, flags);
+               desc = chan->cyclic_first;
+               cb = desc->async_tx.callback;
+               cb_data = desc->async_tx.callback_param;
+               spin_unlock_irqrestore(&chan->desc_lock, flags);
+
+               if (cb)
+                       cb(cb_data);
 
-       /* update the cookie if we have some descriptors to cleanup */
-       if (!list_empty(&chan->chain_running)) {
-               dma_cookie_t cookie;
+               return;
+       }
 
-               desc = to_mmp_pdma_desc(chan->chain_running.prev);
-               cookie = desc->async_tx.cookie;
-               dma_cookie_complete(&desc->async_tx);
+       /* submit pending list; callback for each desc; free desc */
+       spin_lock_irqsave(&chan->desc_lock, flags);
 
-               dev_dbg(chan->dev, "completed_cookie=%d\n", cookie);
+       list_for_each_entry_safe(desc, _desc, &chan->chain_running, node) {
+               /*
+                * move the descriptors to a temporary list so we can drop
+                * the lock during the entire cleanup operation
+                */
+               list_del(&desc->node);
+               list_add(&desc->node, &chain_cleanup);
+
+               /*
+                * Look for the first list entry which has the ENDIRQEN flag
+                * set. That is the descriptor we got an interrupt for, so
+                * complete that transaction and its cookie.
+                */
+               if (desc->desc.dcmd & DCMD_ENDIRQEN) {
+                       dma_cookie_t cookie = desc->async_tx.cookie;
+                       dma_cookie_complete(&desc->async_tx);
+                       dev_dbg(chan->dev, "completed_cookie=%d\n", cookie);
+                       break;
+               }
        }
 
        /*
-        * move the descriptors to a temporary list so we can drop the lock
-        * during the entire cleanup operation
+        * The hardware is idle and ready for more when the
+        * chain_running list is empty.
         */
-       list_splice_tail_init(&chan->chain_running, &chain_cleanup);
-
-       /* the hardware is now idle and ready for more */
-       chan->idle = true;
+       chan->idle = list_empty(&chan->chain_running);
 
        /* Start any pending transactions automatically */
        start_pending_queue(chan);
@@ -763,6 +890,39 @@ static struct of_device_id mmp_pdma_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, mmp_pdma_dt_ids);
 
+static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec,
+                                          struct of_dma *ofdma)
+{
+       struct mmp_pdma_device *d = ofdma->of_dma_data;
+       struct dma_chan *chan, *candidate;
+
+retry:
+       candidate = NULL;
+
+       /* walk the list of channels registered with the current instance and
+        * find one that is currently unused */
+       list_for_each_entry(chan, &d->device.channels, device_node)
+               if (chan->client_count == 0) {
+                       candidate = chan;
+                       break;
+               }
+
+       if (!candidate)
+               return NULL;
+
+       /* dma_get_slave_channel will return NULL if we lost a race between
+        * the lookup and the reservation */
+       chan = dma_get_slave_channel(candidate);
+
+       if (chan) {
+               struct mmp_pdma_chan *c = to_mmp_pdma_chan(chan);
+               c->drcmr = dma_spec->args[0];
+               return chan;
+       }
+
+       goto retry;
+}
+
 static int mmp_pdma_probe(struct platform_device *op)
 {
        struct mmp_pdma_device *pdev;
@@ -777,10 +937,9 @@ static int mmp_pdma_probe(struct platform_device *op)
                return -ENOMEM;
        pdev->dev = &op->dev;
 
-       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -EINVAL;
+       spin_lock_init(&pdev->phy_lock);
 
+       iores = platform_get_resource(op, IORESOURCE_MEM, 0);
        pdev->base = devm_ioremap_resource(pdev->dev, iores);
        if (IS_ERR(pdev->base))
                return PTR_ERR(pdev->base);
@@ -825,13 +984,15 @@ static int mmp_pdma_probe(struct platform_device *op)
 
        dma_cap_set(DMA_SLAVE, pdev->device.cap_mask);
        dma_cap_set(DMA_MEMCPY, pdev->device.cap_mask);
-       dma_cap_set(DMA_SLAVE, pdev->device.cap_mask);
+       dma_cap_set(DMA_CYCLIC, pdev->device.cap_mask);
+       dma_cap_set(DMA_PRIVATE, pdev->device.cap_mask);
        pdev->device.dev = &op->dev;
        pdev->device.device_alloc_chan_resources = mmp_pdma_alloc_chan_resources;
        pdev->device.device_free_chan_resources = mmp_pdma_free_chan_resources;
        pdev->device.device_tx_status = mmp_pdma_tx_status;
        pdev->device.device_prep_dma_memcpy = mmp_pdma_prep_memcpy;
        pdev->device.device_prep_slave_sg = mmp_pdma_prep_slave_sg;
+       pdev->device.device_prep_dma_cyclic = mmp_pdma_prep_dma_cyclic;
        pdev->device.device_issue_pending = mmp_pdma_issue_pending;
        pdev->device.device_control = mmp_pdma_control;
        pdev->device.copy_align = PDMA_ALIGNMENT;
@@ -847,7 +1008,17 @@ static int mmp_pdma_probe(struct platform_device *op)
                return ret;
        }
 
-       dev_info(pdev->device.dev, "initialized\n");
+       if (op->dev.of_node) {
+               /* Device-tree DMA controller registration */
+               ret = of_dma_controller_register(op->dev.of_node,
+                                                mmp_pdma_dma_xlate, pdev);
+               if (ret < 0) {
+                       dev_err(&op->dev, "of_dma_controller_register failed\n");
+                       return ret;
+               }
+       }
+
+       dev_info(pdev->device.dev, "initialized %d channels\n", dma_channels);
        return 0;
 }
 
@@ -867,6 +1038,19 @@ static struct platform_driver mmp_pdma_driver = {
        .remove         = mmp_pdma_remove,
 };
 
+bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param)
+{
+       struct mmp_pdma_chan *c = to_mmp_pdma_chan(chan);
+
+       if (chan->device->dev->driver != &mmp_pdma_driver.driver)
+               return false;
+
+       c->drcmr = *(unsigned int *) param;
+
+       return true;
+}
+EXPORT_SYMBOL_GPL(mmp_pdma_filter_fn);
+
 module_platform_driver(mmp_pdma_driver);
 
 MODULE_DESCRIPTION("MARVELL MMP Periphera DMA Driver");
index 9b9366537d73e87c2e6a81113eaa3f0025ae6330..38cb517fb2ebd82034b02e2ab7d5cabfc9992cbd 100644 (file)
@@ -460,7 +460,8 @@ static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
 {
        struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
 
-       dma_set_residue(txstate, tdmac->buf_len - tdmac->pos);
+       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie,
+                        tdmac->buf_len - tdmac->pos);
 
        return tdmac->status;
 }
@@ -549,9 +550,6 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        }
 
        iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iores)
-               return -EINVAL;
-
        tdev->base = devm_ioremap_resource(&pdev->dev, iores);
        if (IS_ERR(tdev->base))
                return PTR_ERR(tdev->base);
index 2d956732aa3d262aa2c5e1c603ff530bab31db78..2fe4353773338234375df48855ec7c941798bb31 100644 (file)
@@ -556,15 +556,7 @@ static enum dma_status
 mpc_dma_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
               struct dma_tx_state *txstate)
 {
-       struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
-       enum dma_status ret;
-       unsigned long flags;
-
-       spin_lock_irqsave(&mchan->lock, flags);
-       ret = dma_cookie_status(chan, cookie, txstate);
-       spin_unlock_irqrestore(&mchan->lock, flags);
-
-       return ret;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 /* Prepare descriptor for memory to memory copy */
index 200f1a3c9a449d2fe297fa6620c148f74c463f18..536dcb8ba5fdfe69ed5f726fc6b5897f00266698 100644 (file)
@@ -64,7 +64,7 @@ static u32 mv_desc_get_src_addr(struct mv_xor_desc_slot *desc,
                                int src_idx)
 {
        struct mv_xor_desc *hw_desc = desc->hw_desc;
-       return hw_desc->phy_src_addr[src_idx];
+       return hw_desc->phy_src_addr[mv_phy_src_idx(src_idx)];
 }
 
 
@@ -107,32 +107,32 @@ static void mv_desc_set_src_addr(struct mv_xor_desc_slot *desc,
                                 int index, dma_addr_t addr)
 {
        struct mv_xor_desc *hw_desc = desc->hw_desc;
-       hw_desc->phy_src_addr[index] = addr;
+       hw_desc->phy_src_addr[mv_phy_src_idx(index)] = addr;
        if (desc->type == DMA_XOR)
                hw_desc->desc_command |= (1 << index);
 }
 
 static u32 mv_chan_get_current_desc(struct mv_xor_chan *chan)
 {
-       return __raw_readl(XOR_CURR_DESC(chan));
+       return readl_relaxed(XOR_CURR_DESC(chan));
 }
 
 static void mv_chan_set_next_descriptor(struct mv_xor_chan *chan,
                                        u32 next_desc_addr)
 {
-       __raw_writel(next_desc_addr, XOR_NEXT_DESC(chan));
+       writel_relaxed(next_desc_addr, XOR_NEXT_DESC(chan));
 }
 
 static void mv_chan_unmask_interrupts(struct mv_xor_chan *chan)
 {
-       u32 val = __raw_readl(XOR_INTR_MASK(chan));
+       u32 val = readl_relaxed(XOR_INTR_MASK(chan));
        val |= XOR_INTR_MASK_VALUE << (chan->idx * 16);
-       __raw_writel(val, XOR_INTR_MASK(chan));
+       writel_relaxed(val, XOR_INTR_MASK(chan));
 }
 
 static u32 mv_chan_get_intr_cause(struct mv_xor_chan *chan)
 {
-       u32 intr_cause = __raw_readl(XOR_INTR_CAUSE(chan));
+       u32 intr_cause = readl_relaxed(XOR_INTR_CAUSE(chan));
        intr_cause = (intr_cause >> (chan->idx * 16)) & 0xFFFF;
        return intr_cause;
 }
@@ -149,13 +149,13 @@ static void mv_xor_device_clear_eoc_cause(struct mv_xor_chan *chan)
 {
        u32 val = ~(1 << (chan->idx * 16));
        dev_dbg(mv_chan_to_devp(chan), "%s, val 0x%08x\n", __func__, val);
-       __raw_writel(val, XOR_INTR_CAUSE(chan));
+       writel_relaxed(val, XOR_INTR_CAUSE(chan));
 }
 
 static void mv_xor_device_clear_err_status(struct mv_xor_chan *chan)
 {
        u32 val = 0xFFFF0000 >> (chan->idx * 16);
-       __raw_writel(val, XOR_INTR_CAUSE(chan));
+       writel_relaxed(val, XOR_INTR_CAUSE(chan));
 }
 
 static int mv_can_chain(struct mv_xor_desc_slot *desc)
@@ -173,7 +173,7 @@ static void mv_set_mode(struct mv_xor_chan *chan,
                               enum dma_transaction_type type)
 {
        u32 op_mode;
-       u32 config = __raw_readl(XOR_CONFIG(chan));
+       u32 config = readl_relaxed(XOR_CONFIG(chan));
 
        switch (type) {
        case DMA_XOR:
@@ -192,7 +192,14 @@ static void mv_set_mode(struct mv_xor_chan *chan,
 
        config &= ~0x7;
        config |= op_mode;
-       __raw_writel(config, XOR_CONFIG(chan));
+
+#if defined(__BIG_ENDIAN)
+       config |= XOR_DESCRIPTOR_SWAP;
+#else
+       config &= ~XOR_DESCRIPTOR_SWAP;
+#endif
+
+       writel_relaxed(config, XOR_CONFIG(chan));
        chan->current_type = type;
 }
 
@@ -201,14 +208,14 @@ static void mv_chan_activate(struct mv_xor_chan *chan)
        u32 activation;
 
        dev_dbg(mv_chan_to_devp(chan), " activate chan.\n");
-       activation = __raw_readl(XOR_ACTIVATION(chan));
+       activation = readl_relaxed(XOR_ACTIVATION(chan));
        activation |= 0x1;
-       __raw_writel(activation, XOR_ACTIVATION(chan));
+       writel_relaxed(activation, XOR_ACTIVATION(chan));
 }
 
 static char mv_chan_is_busy(struct mv_xor_chan *chan)
 {
-       u32 state = __raw_readl(XOR_ACTIVATION(chan));
+       u32 state = readl_relaxed(XOR_ACTIVATION(chan));
 
        state = (state >> 4) & 0x3;
 
@@ -647,7 +654,7 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
 
        dev_dbg(mv_chan_to_devp(mv_chan),
                "%s sw_desc %p async_tx %p\n",
-               __func__, sw_desc, sw_desc ? &sw_desc->async_tx : 0);
+               __func__, sw_desc, sw_desc ? &sw_desc->async_tx : NULL);
 
        return sw_desc ? &sw_desc->async_tx : NULL;
 }
@@ -755,22 +762,22 @@ static void mv_dump_xor_regs(struct mv_xor_chan *chan)
 {
        u32 val;
 
-       val = __raw_readl(XOR_CONFIG(chan));
+       val = readl_relaxed(XOR_CONFIG(chan));
        dev_err(mv_chan_to_devp(chan), "config       0x%08x\n", val);
 
-       val = __raw_readl(XOR_ACTIVATION(chan));
+       val = readl_relaxed(XOR_ACTIVATION(chan));
        dev_err(mv_chan_to_devp(chan), "activation   0x%08x\n", val);
 
-       val = __raw_readl(XOR_INTR_CAUSE(chan));
+       val = readl_relaxed(XOR_INTR_CAUSE(chan));
        dev_err(mv_chan_to_devp(chan), "intr cause   0x%08x\n", val);
 
-       val = __raw_readl(XOR_INTR_MASK(chan));
+       val = readl_relaxed(XOR_INTR_MASK(chan));
        dev_err(mv_chan_to_devp(chan), "intr mask    0x%08x\n", val);
 
-       val = __raw_readl(XOR_ERROR_CAUSE(chan));
+       val = readl_relaxed(XOR_ERROR_CAUSE(chan));
        dev_err(mv_chan_to_devp(chan), "error cause  0x%08x\n", val);
 
-       val = __raw_readl(XOR_ERROR_ADDR(chan));
+       val = readl_relaxed(XOR_ERROR_ADDR(chan));
        dev_err(mv_chan_to_devp(chan), "error addr   0x%08x\n", val);
 }
 
@@ -1029,10 +1036,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
        struct dma_device *dma_dev;
 
        mv_chan = devm_kzalloc(&pdev->dev, sizeof(*mv_chan), GFP_KERNEL);
-       if (!mv_chan) {
-               ret = -ENOMEM;
-               goto err_free_dma;
-       }
+       if (!mv_chan)
+               return ERR_PTR(-ENOMEM);
 
        mv_chan->idx = idx;
        mv_chan->irq = irq;
@@ -1166,7 +1171,7 @@ static int mv_xor_probe(struct platform_device *pdev)
 {
        const struct mbus_dram_target_info *dram;
        struct mv_xor_device *xordev;
-       struct mv_xor_platform_data *pdata = pdev->dev.platform_data;
+       struct mv_xor_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct resource *res;
        int i, ret;
 
index c619359cb7febd1406d06773320f2281928d3274..06b067f24c9b33f7592d65a4ece98bf99c3cb776 100644 (file)
 #define MV_XOR_THRESHOLD               1
 #define MV_XOR_MAX_CHANNELS             2
 
+/* Values for the XOR_CONFIG register */
 #define XOR_OPERATION_MODE_XOR         0
 #define XOR_OPERATION_MODE_MEMCPY      2
+#define XOR_DESCRIPTOR_SWAP            BIT(14)
 
 #define XOR_CURR_DESC(chan)    (chan->mmr_base + 0x210 + (chan->idx * 4))
 #define XOR_NEXT_DESC(chan)    (chan->mmr_base + 0x200 + (chan->idx * 4))
@@ -143,7 +145,16 @@ struct mv_xor_desc_slot {
 #endif
 };
 
-/* This structure describes XOR descriptor size 64bytes        */
+/*
+ * This structure describes XOR descriptor size 64bytes. The
+ * mv_phy_src_idx() macro must be used when indexing the values of the
+ * phy_src_addr[] array. This is due to the fact that the 'descriptor
+ * swap' feature, used on big endian systems, swaps descriptors data
+ * within blocks of 8 bytes. So two consecutive values of the
+ * phy_src_addr[] array are actually swapped in big-endian, which
+ * explains the different mv_phy_src_idx() implementation.
+ */
+#if defined(__LITTLE_ENDIAN)
 struct mv_xor_desc {
        u32 status;             /* descriptor execution status */
        u32 crc32_result;       /* result of CRC-32 calculation */
@@ -155,6 +166,21 @@ struct mv_xor_desc {
        u32 reserved0;
        u32 reserved1;
 };
+#define mv_phy_src_idx(src_idx) (src_idx)
+#else
+struct mv_xor_desc {
+       u32 crc32_result;       /* result of CRC-32 calculation */
+       u32 status;             /* descriptor execution status */
+       u32 phy_next_desc;      /* next descriptor address pointer */
+       u32 desc_command;       /* type of operation to be carried out */
+       u32 phy_dest_addr;      /* destination block address */
+       u32 byte_count;         /* size of src/dst blocks in bytes */
+       u32 phy_src_addr[8];    /* source block addresses */
+       u32 reserved1;
+       u32 reserved0;
+};
+#define mv_phy_src_idx(src_idx) (src_idx ^ 1)
+#endif
 
 #define to_mv_sw_desc(addr_hw_desc)            \
        container_of(addr_hw_desc, struct mv_xor_desc_slot, hw_desc)
index 719593002ab7866051aa9cf7c52633ce60000ba6..ccd13df841db790ff9eabc9cbc9df79f5f8bb9af 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/dmaengine.h>
 #include <linux/delay.h>
 #include <linux/module.h>
-#include <linux/fsl/mxs-dma.h>
 #include <linux/stmp_device.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -197,24 +196,6 @@ static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
        return container_of(chan, struct mxs_dma_chan, chan);
 }
 
-int mxs_dma_is_apbh(struct dma_chan *chan)
-{
-       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
-       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
-
-       return dma_is_apbh(mxs_dma);
-}
-EXPORT_SYMBOL_GPL(mxs_dma_is_apbh);
-
-int mxs_dma_is_apbx(struct dma_chan *chan)
-{
-       struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
-       struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
-
-       return !dma_is_apbh(mxs_dma);
-}
-EXPORT_SYMBOL_GPL(mxs_dma_is_apbx);
-
 static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
 {
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
@@ -349,13 +330,9 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
 static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
 {
        struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
-       struct mxs_dma_data *data = chan->private;
        struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
        int ret;
 
-       if (data)
-               mxs_chan->chan_irq = data->chan_irq;
-
        mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev,
                                CCW_BLOCK_SIZE, &mxs_chan->ccw_phys,
                                GFP_KERNEL);
@@ -622,10 +599,8 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
                        dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
        struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
-       dma_cookie_t last_used;
 
-       last_used = chan->cookie;
-       dma_set_tx_state(txstate, chan->completed_cookie, last_used, 0);
+       dma_set_tx_state(txstate, chan->completed_cookie, chan->cookie, 0);
 
        return mxs_chan->status;
 }
index 75334bdd2c56bc29a18b24466d1114d7928cad58..0b88dd3d05f4880f41561f455f79c5eb9ca0a885 100644 (file)
@@ -160,7 +160,8 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
 
        count = of_property_count_strings(np, "dma-names");
        if (count < 0) {
-               pr_err("%s: dma-names property missing or empty\n", __func__);
+               pr_err("%s: dma-names property of node '%s' missing or empty\n",
+                       __func__, np->full_name);
                return NULL;
        }
 
index 0bbdea5059f3b693a8929a4d6ee82db24c90b768..61fdc54a3c889d133058e046356d5b2f96bfeede 100644 (file)
@@ -564,14 +564,7 @@ static void pd_free_chan_resources(struct dma_chan *chan)
 static enum dma_status pd_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
                                    struct dma_tx_state *txstate)
 {
-       struct pch_dma_chan *pd_chan = to_pd_chan(chan);
-       enum dma_status ret;
-
-       spin_lock_irq(&pd_chan->lock);
-       ret = dma_cookie_status(chan, cookie, txstate);
-       spin_unlock_irq(&pd_chan->lock);
-
-       return ret;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 static void pd_issue_pending(struct dma_chan *chan)
@@ -1036,3 +1029,4 @@ MODULE_DESCRIPTION("Intel EG20T PCH / LAPIS Semicon ML7213/ML7223/ML7831 IOH "
                   "DMA controller driver");
 MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>");
 MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, pch_dma_id_table);
index fa645d8250091943ba8d47aa42852b99b74ca1ce..a562d24d20bf55179436d16086ca90f63d1b1894 100644 (file)
@@ -545,6 +545,8 @@ struct dma_pl330_chan {
 
        /* List of to be xfered descriptors */
        struct list_head work_list;
+       /* List of completed descriptors */
+       struct list_head completed_list;
 
        /* Pointer to the DMAC that manages this channel,
         * NULL if the channel is available to be acquired.
@@ -2198,66 +2200,6 @@ to_desc(struct dma_async_tx_descriptor *tx)
        return container_of(tx, struct dma_pl330_desc, txd);
 }
 
-static inline void free_desc_list(struct list_head *list)
-{
-       struct dma_pl330_dmac *pdmac;
-       struct dma_pl330_desc *desc;
-       struct dma_pl330_chan *pch = NULL;
-       unsigned long flags;
-
-       /* Finish off the work list */
-       list_for_each_entry(desc, list, node) {
-               dma_async_tx_callback callback;
-               void *param;
-
-               /* All desc in a list belong to same channel */
-               pch = desc->pchan;
-               callback = desc->txd.callback;
-               param = desc->txd.callback_param;
-
-               if (callback)
-                       callback(param);
-
-               desc->pchan = NULL;
-       }
-
-       /* pch will be unset if list was empty */
-       if (!pch)
-               return;
-
-       pdmac = pch->dmac;
-
-       spin_lock_irqsave(&pdmac->pool_lock, flags);
-       list_splice_tail_init(list, &pdmac->desc_pool);
-       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
-}
-
-static inline void handle_cyclic_desc_list(struct list_head *list)
-{
-       struct dma_pl330_desc *desc;
-       struct dma_pl330_chan *pch = NULL;
-       unsigned long flags;
-
-       list_for_each_entry(desc, list, node) {
-               dma_async_tx_callback callback;
-
-               /* Change status to reload it */
-               desc->status = PREP;
-               pch = desc->pchan;
-               callback = desc->txd.callback;
-               if (callback)
-                       callback(desc->txd.callback_param);
-       }
-
-       /* pch will be unset if list was empty */
-       if (!pch)
-               return;
-
-       spin_lock_irqsave(&pch->lock, flags);
-       list_splice_tail_init(list, &pch->work_list);
-       spin_unlock_irqrestore(&pch->lock, flags);
-}
-
 static inline void fill_queue(struct dma_pl330_chan *pch)
 {
        struct dma_pl330_desc *desc;
@@ -2291,7 +2233,6 @@ static void pl330_tasklet(unsigned long data)
        struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
        struct dma_pl330_desc *desc, *_dt;
        unsigned long flags;
-       LIST_HEAD(list);
 
        spin_lock_irqsave(&pch->lock, flags);
 
@@ -2300,7 +2241,7 @@ static void pl330_tasklet(unsigned long data)
                if (desc->status == DONE) {
                        if (!pch->cyclic)
                                dma_cookie_complete(&desc->txd);
-                       list_move_tail(&desc->node, &list);
+                       list_move_tail(&desc->node, &pch->completed_list);
                }
 
        /* Try to submit a req imm. next to the last completed cookie */
@@ -2309,12 +2250,31 @@ static void pl330_tasklet(unsigned long data)
        /* Make sure the PL330 Channel thread is active */
        pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
 
-       spin_unlock_irqrestore(&pch->lock, flags);
+       while (!list_empty(&pch->completed_list)) {
+               dma_async_tx_callback callback;
+               void *callback_param;
 
-       if (pch->cyclic)
-               handle_cyclic_desc_list(&list);
-       else
-               free_desc_list(&list);
+               desc = list_first_entry(&pch->completed_list,
+                                       struct dma_pl330_desc, node);
+
+               callback = desc->txd.callback;
+               callback_param = desc->txd.callback_param;
+
+               if (pch->cyclic) {
+                       desc->status = PREP;
+                       list_move_tail(&desc->node, &pch->work_list);
+               } else {
+                       desc->status = FREE;
+                       list_move_tail(&desc->node, &pch->dmac->desc_pool);
+               }
+
+               if (callback) {
+                       spin_unlock_irqrestore(&pch->lock, flags);
+                       callback(callback_param);
+                       spin_lock_irqsave(&pch->lock, flags);
+               }
+       }
+       spin_unlock_irqrestore(&pch->lock, flags);
 }
 
 static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
@@ -2409,7 +2369,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
 {
        struct dma_pl330_chan *pch = to_pchan(chan);
-       struct dma_pl330_desc *desc, *_dt;
+       struct dma_pl330_desc *desc;
        unsigned long flags;
        struct dma_pl330_dmac *pdmac = pch->dmac;
        struct dma_slave_config *slave_config;
@@ -2423,12 +2383,18 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
                pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
                /* Mark all desc done */
-               list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
-                       desc->status = DONE;
-                       list_move_tail(&desc->node, &list);
+               list_for_each_entry(desc, &pch->work_list , node) {
+                       desc->status = FREE;
+                       dma_cookie_complete(&desc->txd);
                }
 
-               list_splice_tail_init(&list, &pdmac->desc_pool);
+               list_for_each_entry(desc, &pch->completed_list , node) {
+                       desc->status = FREE;
+                       dma_cookie_complete(&desc->txd);
+               }
+
+               list_splice_tail_init(&pch->work_list, &pdmac->desc_pool);
+               list_splice_tail_init(&pch->completed_list, &pdmac->desc_pool);
                spin_unlock_irqrestore(&pch->lock, flags);
                break;
        case DMA_SLAVE_CONFIG:
@@ -2814,6 +2780,28 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
        return &desc->txd;
 }
 
+static void __pl330_giveback_desc(struct dma_pl330_dmac *pdmac,
+                                 struct dma_pl330_desc *first)
+{
+       unsigned long flags;
+       struct dma_pl330_desc *desc;
+
+       if (!first)
+               return;
+
+       spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+       while (!list_empty(&first->node)) {
+               desc = list_entry(first->node.next,
+                               struct dma_pl330_desc, node);
+               list_move_tail(&desc->node, &pdmac->desc_pool);
+       }
+
+       list_move_tail(&first->node, &pdmac->desc_pool);
+
+       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+}
+
 static struct dma_async_tx_descriptor *
 pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                unsigned int sg_len, enum dma_transfer_direction direction,
@@ -2822,7 +2810,6 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
        struct dma_pl330_desc *first, *desc = NULL;
        struct dma_pl330_chan *pch = to_pchan(chan);
        struct scatterlist *sg;
-       unsigned long flags;
        int i;
        dma_addr_t addr;
 
@@ -2842,20 +2829,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                        dev_err(pch->dmac->pif.dev,
                                "%s:%d Unable to fetch desc\n",
                                __func__, __LINE__);
-                       if (!first)
-                               return NULL;
-
-                       spin_lock_irqsave(&pdmac->pool_lock, flags);
-
-                       while (!list_empty(&first->node)) {
-                               desc = list_entry(first->node.next,
-                                               struct dma_pl330_desc, node);
-                               list_move_tail(&desc->node, &pdmac->desc_pool);
-                       }
-
-                       list_move_tail(&first->node, &pdmac->desc_pool);
-
-                       spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+                       __pl330_giveback_desc(pdmac, first);
 
                        return NULL;
                }
@@ -2896,6 +2870,25 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
                return IRQ_NONE;
 }
 
+#define PL330_DMA_BUSWIDTHS \
+       BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+
+static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
+       struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = PL330_DMA_BUSWIDTHS;
+       caps->dstn_addr_widths = PL330_DMA_BUSWIDTHS;
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = false;
+       caps->cmd_terminate = true;
+
+       return 0;
+}
+
 static int
 pl330_probe(struct amba_device *adev, const struct amba_id *id)
 {
@@ -2908,7 +2901,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        int i, ret, irq;
        int num_chan;
 
-       pdat = adev->dev.platform_data;
+       pdat = dev_get_platdata(&adev->dev);
 
        /* Allocate a new DMAC and its Channels */
        pdmac = devm_kzalloc(&adev->dev, sizeof(*pdmac), GFP_KERNEL);
@@ -2971,6 +2964,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
                        pch->chan.private = adev->dev.of_node;
 
                INIT_LIST_HEAD(&pch->work_list);
+               INIT_LIST_HEAD(&pch->completed_list);
                spin_lock_init(&pch->lock);
                pch->pl330_chid = NULL;
                pch->chan.device = pd;
@@ -3000,6 +2994,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        pd->device_prep_slave_sg = pl330_prep_slave_sg;
        pd->device_control = pl330_control;
        pd->device_issue_pending = pl330_issue_pending;
+       pd->device_slave_caps = pl330_dma_device_slave_caps;
 
        ret = dma_async_device_register(pd);
        if (ret) {
@@ -3015,6 +3010,14 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
                        "unable to register DMA to the generic DT DMA helpers\n");
                }
        }
+       /*
+        * This is the limit for transfers with a buswidth of 1, larger
+        * buswidths will have larger limits.
+        */
+       ret = dma_set_max_seg_size(&adev->dev, 1900800);
+       if (ret)
+               dev_err(&adev->dev, "unable to set the seg size\n");
+
 
        dev_info(&adev->dev,
                "Loaded driver for PL330 DMAC-%d\n", adev->periphid);
index 5c1dee20c13ed5021ae24715ad08a84c23879506..dadd9e010c0b0979f15a5a195109af1e1e1e13de 100644 (file)
@@ -22,3 +22,13 @@ config SUDMAC
        depends on SH_DMAE_BASE
        help
          Enable support for the Renesas SUDMAC controllers.
+
+config RCAR_HPB_DMAE
+       tristate "Renesas R-Car HPB DMAC support"
+       depends on SH_DMAE_BASE
+       help
+         Enable support for the Renesas R-Car series DMA controllers.
+
+config SHDMA_R8A73A4
+       def_bool y
+       depends on ARCH_R8A73A4 && SH_DMAE != n
index c962138dde96fdac734b62f9b3f1cdf57bad21b1..e856af23b789567da9986ad2bc487d3f26487991 100644 (file)
@@ -1,3 +1,9 @@
 obj-$(CONFIG_SH_DMAE_BASE) += shdma-base.o shdma-of.o
 obj-$(CONFIG_SH_DMAE) += shdma.o
+shdma-y := shdmac.o
+ifeq ($(CONFIG_OF),y)
+shdma-$(CONFIG_SHDMA_R8A73A4) += shdma-r8a73a4.o
+endif
+shdma-objs := $(shdma-y)
 obj-$(CONFIG_SUDMAC) += sudmac.o
+obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
diff --git a/drivers/dma/sh/rcar-hpbdma.c b/drivers/dma/sh/rcar-hpbdma.c
new file mode 100644 (file)
index 0000000..45a5202
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2011-2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * This file is based on the drivers/dma/sh/shdma.c
+ *
+ * Renesas SuperH DMA Engine support
+ *
+ * This 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.
+ *
+ * - DMA of SuperH does not have Hardware DMA chain mode.
+ * - max DMA size is 16MB.
+ *
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_data/dma-rcar-hpbdma.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/shdma-base.h>
+#include <linux/slab.h>
+
+/* DMA channel registers */
+#define HPB_DMAE_DSAR0 0x00
+#define HPB_DMAE_DDAR0 0x04
+#define HPB_DMAE_DTCR0 0x08
+#define HPB_DMAE_DSAR1 0x0C
+#define HPB_DMAE_DDAR1 0x10
+#define HPB_DMAE_DTCR1 0x14
+#define HPB_DMAE_DSASR 0x18
+#define HPB_DMAE_DDASR 0x1C
+#define HPB_DMAE_DTCSR 0x20
+#define HPB_DMAE_DPTR  0x24
+#define HPB_DMAE_DCR   0x28
+#define HPB_DMAE_DCMDR 0x2C
+#define HPB_DMAE_DSTPR 0x30
+#define HPB_DMAE_DSTSR 0x34
+#define HPB_DMAE_DDBGR 0x38
+#define HPB_DMAE_DDBGR2        0x3C
+#define HPB_DMAE_CHAN(n)       (0x40 * (n))
+
+/* DMA command register (DCMDR) bits */
+#define HPB_DMAE_DCMDR_BDOUT   BIT(7)
+#define HPB_DMAE_DCMDR_DQSPD   BIT(6)
+#define HPB_DMAE_DCMDR_DQSPC   BIT(5)
+#define HPB_DMAE_DCMDR_DMSPD   BIT(4)
+#define HPB_DMAE_DCMDR_DMSPC   BIT(3)
+#define HPB_DMAE_DCMDR_DQEND   BIT(2)
+#define HPB_DMAE_DCMDR_DNXT    BIT(1)
+#define HPB_DMAE_DCMDR_DMEN    BIT(0)
+
+/* DMA forced stop register (DSTPR) bits */
+#define HPB_DMAE_DSTPR_DMSTP   BIT(0)
+
+/* DMA status register (DSTSR) bits */
+#define HPB_DMAE_DSTSR_DMSTS   BIT(0)
+
+/* DMA common registers */
+#define HPB_DMAE_DTIMR         0x00
+#define HPB_DMAE_DINTSR0               0x0C
+#define HPB_DMAE_DINTSR1               0x10
+#define HPB_DMAE_DINTCR0               0x14
+#define HPB_DMAE_DINTCR1               0x18
+#define HPB_DMAE_DINTMR0               0x1C
+#define HPB_DMAE_DINTMR1               0x20
+#define HPB_DMAE_DACTSR0               0x24
+#define HPB_DMAE_DACTSR1               0x28
+#define HPB_DMAE_HSRSTR(n)     (0x40 + (n) * 4)
+#define HPB_DMAE_HPB_DMASPR(n) (0x140 + (n) * 4)
+#define HPB_DMAE_HPB_DMLVLR0   0x160
+#define HPB_DMAE_HPB_DMLVLR1   0x164
+#define HPB_DMAE_HPB_DMSHPT0   0x168
+#define HPB_DMAE_HPB_DMSHPT1   0x16C
+
+#define HPB_DMA_SLAVE_NUMBER 256
+#define HPB_DMA_TCR_MAX 0x01000000     /* 16 MiB */
+
+struct hpb_dmae_chan {
+       struct shdma_chan shdma_chan;
+       int xfer_mode;                  /* DMA transfer mode */
+#define XFER_SINGLE    1
+#define XFER_DOUBLE    2
+       unsigned plane_idx;             /* current DMA information set */
+       bool first_desc;                /* first/next transfer */
+       int xmit_shift;                 /* log_2(bytes_per_xfer) */
+       void __iomem *base;
+       const struct hpb_dmae_slave_config *cfg;
+       char dev_id[16];                /* unique name per DMAC of channel */
+};
+
+struct hpb_dmae_device {
+       struct shdma_dev shdma_dev;
+       spinlock_t reg_lock;            /* comm_reg operation lock */
+       struct hpb_dmae_pdata *pdata;
+       void __iomem *chan_reg;
+       void __iomem *comm_reg;
+       void __iomem *reset_reg;
+       void __iomem *mode_reg;
+};
+
+struct hpb_dmae_regs {
+       u32 sar; /* SAR / source address */
+       u32 dar; /* DAR / destination address */
+       u32 tcr; /* TCR / transfer count */
+};
+
+struct hpb_desc {
+       struct shdma_desc shdma_desc;
+       struct hpb_dmae_regs hw;
+       unsigned plane_idx;
+};
+
+#define to_chan(schan) container_of(schan, struct hpb_dmae_chan, shdma_chan)
+#define to_desc(sdesc) container_of(sdesc, struct hpb_desc, shdma_desc)
+#define to_dev(sc) container_of(sc->shdma_chan.dma_chan.device, \
+                               struct hpb_dmae_device, shdma_dev.dma_dev)
+
+static void ch_reg_write(struct hpb_dmae_chan *hpb_dc, u32 data, u32 reg)
+{
+       iowrite32(data, hpb_dc->base + reg);
+}
+
+static u32 ch_reg_read(struct hpb_dmae_chan *hpb_dc, u32 reg)
+{
+       return ioread32(hpb_dc->base + reg);
+}
+
+static void dcmdr_write(struct hpb_dmae_device *hpbdev, u32 data)
+{
+       iowrite32(data, hpbdev->chan_reg + HPB_DMAE_DCMDR);
+}
+
+static void hsrstr_write(struct hpb_dmae_device *hpbdev, u32 ch)
+{
+       iowrite32(0x1, hpbdev->comm_reg + HPB_DMAE_HSRSTR(ch));
+}
+
+static u32 dintsr_read(struct hpb_dmae_device *hpbdev, u32 ch)
+{
+       u32 v;
+
+       if (ch < 32)
+               v = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTSR0) >> ch;
+       else
+               v = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTSR1) >> (ch - 32);
+       return v & 0x1;
+}
+
+static void dintcr_write(struct hpb_dmae_device *hpbdev, u32 ch)
+{
+       if (ch < 32)
+               iowrite32((0x1 << ch), hpbdev->comm_reg + HPB_DMAE_DINTCR0);
+       else
+               iowrite32((0x1 << (ch - 32)),
+                         hpbdev->comm_reg + HPB_DMAE_DINTCR1);
+}
+
+static void asyncmdr_write(struct hpb_dmae_device *hpbdev, u32 data)
+{
+       iowrite32(data, hpbdev->mode_reg);
+}
+
+static u32 asyncmdr_read(struct hpb_dmae_device *hpbdev)
+{
+       return ioread32(hpbdev->mode_reg);
+}
+
+static void hpb_dmae_enable_int(struct hpb_dmae_device *hpbdev, u32 ch)
+{
+       u32 intreg;
+
+       spin_lock_irq(&hpbdev->reg_lock);
+       if (ch < 32) {
+               intreg = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTMR0);
+               iowrite32(BIT(ch) | intreg,
+                         hpbdev->comm_reg + HPB_DMAE_DINTMR0);
+       } else {
+               intreg = ioread32(hpbdev->comm_reg + HPB_DMAE_DINTMR1);
+               iowrite32(BIT(ch - 32) | intreg,
+                         hpbdev->comm_reg + HPB_DMAE_DINTMR1);
+       }
+       spin_unlock_irq(&hpbdev->reg_lock);
+}
+
+static void hpb_dmae_async_reset(struct hpb_dmae_device *hpbdev, u32 data)
+{
+       u32 rstr;
+       int timeout = 10000;    /* 100 ms */
+
+       spin_lock(&hpbdev->reg_lock);
+       rstr = ioread32(hpbdev->reset_reg);
+       rstr |= data;
+       iowrite32(rstr, hpbdev->reset_reg);
+       do {
+               rstr = ioread32(hpbdev->reset_reg);
+               if ((rstr & data) == data)
+                       break;
+               udelay(10);
+       } while (timeout--);
+
+       if (timeout < 0)
+               dev_err(hpbdev->shdma_dev.dma_dev.dev,
+                       "%s timeout\n", __func__);
+
+       rstr &= ~data;
+       iowrite32(rstr, hpbdev->reset_reg);
+       spin_unlock(&hpbdev->reg_lock);
+}
+
+static void hpb_dmae_set_async_mode(struct hpb_dmae_device *hpbdev,
+                                   u32 mask, u32 data)
+{
+       u32 mode;
+
+       spin_lock_irq(&hpbdev->reg_lock);
+       mode = asyncmdr_read(hpbdev);
+       mode &= ~mask;
+       mode |= data;
+       asyncmdr_write(hpbdev, mode);
+       spin_unlock_irq(&hpbdev->reg_lock);
+}
+
+static void hpb_dmae_ctl_stop(struct hpb_dmae_device *hpbdev)
+{
+       dcmdr_write(hpbdev, HPB_DMAE_DCMDR_DQSPD);
+}
+
+static void hpb_dmae_reset(struct hpb_dmae_device *hpbdev)
+{
+       u32 ch;
+
+       for (ch = 0; ch < hpbdev->pdata->num_hw_channels; ch++)
+               hsrstr_write(hpbdev, ch);
+}
+
+static unsigned int calc_xmit_shift(struct hpb_dmae_chan *hpb_chan)
+{
+       struct hpb_dmae_device *hpbdev = to_dev(hpb_chan);
+       struct hpb_dmae_pdata *pdata = hpbdev->pdata;
+       int width = ch_reg_read(hpb_chan, HPB_DMAE_DCR);
+       int i;
+
+       switch (width & (HPB_DMAE_DCR_SPDS_MASK | HPB_DMAE_DCR_DPDS_MASK)) {
+       case HPB_DMAE_DCR_SPDS_8BIT | HPB_DMAE_DCR_DPDS_8BIT:
+       default:
+               i = XMIT_SZ_8BIT;
+               break;
+       case HPB_DMAE_DCR_SPDS_16BIT | HPB_DMAE_DCR_DPDS_16BIT:
+               i = XMIT_SZ_16BIT;
+               break;
+       case HPB_DMAE_DCR_SPDS_32BIT | HPB_DMAE_DCR_DPDS_32BIT:
+               i = XMIT_SZ_32BIT;
+               break;
+       }
+       return pdata->ts_shift[i];
+}
+
+static void hpb_dmae_set_reg(struct hpb_dmae_chan *hpb_chan,
+                            struct hpb_dmae_regs *hw, unsigned plane)
+{
+       ch_reg_write(hpb_chan, hw->sar,
+                    plane ? HPB_DMAE_DSAR1 : HPB_DMAE_DSAR0);
+       ch_reg_write(hpb_chan, hw->dar,
+                    plane ? HPB_DMAE_DDAR1 : HPB_DMAE_DDAR0);
+       ch_reg_write(hpb_chan, hw->tcr >> hpb_chan->xmit_shift,
+                    plane ? HPB_DMAE_DTCR1 : HPB_DMAE_DTCR0);
+}
+
+static void hpb_dmae_start(struct hpb_dmae_chan *hpb_chan, bool next)
+{
+       ch_reg_write(hpb_chan, (next ? HPB_DMAE_DCMDR_DNXT : 0) |
+                    HPB_DMAE_DCMDR_DMEN, HPB_DMAE_DCMDR);
+}
+
+static void hpb_dmae_halt(struct shdma_chan *schan)
+{
+       struct hpb_dmae_chan *chan = to_chan(schan);
+
+       ch_reg_write(chan, HPB_DMAE_DCMDR_DQEND, HPB_DMAE_DCMDR);
+       ch_reg_write(chan, HPB_DMAE_DSTPR_DMSTP, HPB_DMAE_DSTPR);
+}
+
+static const struct hpb_dmae_slave_config *
+hpb_dmae_find_slave(struct hpb_dmae_chan *hpb_chan, int slave_id)
+{
+       struct hpb_dmae_device *hpbdev = to_dev(hpb_chan);
+       struct hpb_dmae_pdata *pdata = hpbdev->pdata;
+       int i;
+
+       if (slave_id >= HPB_DMA_SLAVE_NUMBER)
+               return NULL;
+
+       for (i = 0; i < pdata->num_slaves; i++)
+               if (pdata->slaves[i].id == slave_id)
+                       return pdata->slaves + i;
+
+       return NULL;
+}
+
+static void hpb_dmae_start_xfer(struct shdma_chan *schan,
+                               struct shdma_desc *sdesc)
+{
+       struct hpb_dmae_chan *chan = to_chan(schan);
+       struct hpb_dmae_device *hpbdev = to_dev(chan);
+       struct hpb_desc *desc = to_desc(sdesc);
+
+       if (chan->cfg->flags & HPB_DMAE_SET_ASYNC_RESET)
+               hpb_dmae_async_reset(hpbdev, chan->cfg->rstr);
+
+       desc->plane_idx = chan->plane_idx;
+       hpb_dmae_set_reg(chan, &desc->hw, chan->plane_idx);
+       hpb_dmae_start(chan, !chan->first_desc);
+
+       if (chan->xfer_mode == XFER_DOUBLE) {
+               chan->plane_idx ^= 1;
+               chan->first_desc = false;
+       }
+}
+
+static bool hpb_dmae_desc_completed(struct shdma_chan *schan,
+                                   struct shdma_desc *sdesc)
+{
+       /*
+        * This is correct since we always have at most single
+        * outstanding DMA transfer per channel, and by the time
+        * we get completion interrupt the transfer is completed.
+        * This will change if we ever use alternating DMA
+        * information sets and submit two descriptors at once.
+        */
+       return true;
+}
+
+static bool hpb_dmae_chan_irq(struct shdma_chan *schan, int irq)
+{
+       struct hpb_dmae_chan *chan = to_chan(schan);
+       struct hpb_dmae_device *hpbdev = to_dev(chan);
+       int ch = chan->cfg->dma_ch;
+
+       /* Check Complete DMA Transfer */
+       if (dintsr_read(hpbdev, ch)) {
+               /* Clear Interrupt status */
+               dintcr_write(hpbdev, ch);
+               return true;
+       }
+       return false;
+}
+
+static int hpb_dmae_desc_setup(struct shdma_chan *schan,
+                              struct shdma_desc *sdesc,
+                              dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+       struct hpb_desc *desc = to_desc(sdesc);
+
+       if (*len > (size_t)HPB_DMA_TCR_MAX)
+               *len = (size_t)HPB_DMA_TCR_MAX;
+
+       desc->hw.sar = src;
+       desc->hw.dar = dst;
+       desc->hw.tcr = *len;
+
+       return 0;
+}
+
+static size_t hpb_dmae_get_partial(struct shdma_chan *schan,
+                                  struct shdma_desc *sdesc)
+{
+       struct hpb_desc *desc = to_desc(sdesc);
+       struct hpb_dmae_chan *chan = to_chan(schan);
+       u32 tcr = ch_reg_read(chan, desc->plane_idx ?
+                             HPB_DMAE_DTCR1 : HPB_DMAE_DTCR0);
+
+       return (desc->hw.tcr - tcr) << chan->xmit_shift;
+}
+
+static bool hpb_dmae_channel_busy(struct shdma_chan *schan)
+{
+       struct hpb_dmae_chan *chan = to_chan(schan);
+       u32 dstsr = ch_reg_read(chan, HPB_DMAE_DSTSR);
+
+       return (dstsr & HPB_DMAE_DSTSR_DMSTS) == HPB_DMAE_DSTSR_DMSTS;
+}
+
+static int
+hpb_dmae_alloc_chan_resources(struct hpb_dmae_chan *hpb_chan,
+                             const struct hpb_dmae_slave_config *cfg)
+{
+       struct hpb_dmae_device *hpbdev = to_dev(hpb_chan);
+       struct hpb_dmae_pdata *pdata = hpbdev->pdata;
+       const struct hpb_dmae_channel *channel = pdata->channels;
+       int slave_id = cfg->id;
+       int i, err;
+
+       for (i = 0; i < pdata->num_channels; i++, channel++) {
+               if (channel->s_id == slave_id) {
+                       struct device *dev = hpb_chan->shdma_chan.dev;
+
+                       hpb_chan->base = hpbdev->chan_reg +
+                               HPB_DMAE_CHAN(cfg->dma_ch);
+
+                       dev_dbg(dev, "Detected Slave device\n");
+                       dev_dbg(dev, " -- slave_id       : 0x%x\n", slave_id);
+                       dev_dbg(dev, " -- cfg->dma_ch    : %d\n", cfg->dma_ch);
+                       dev_dbg(dev, " -- channel->ch_irq: %d\n",
+                               channel->ch_irq);
+                       break;
+               }
+       }
+
+       err = shdma_request_irq(&hpb_chan->shdma_chan, channel->ch_irq,
+                               IRQF_SHARED, hpb_chan->dev_id);
+       if (err) {
+               dev_err(hpb_chan->shdma_chan.dev,
+                       "DMA channel request_irq %d failed with error %d\n",
+                       channel->ch_irq, err);
+               return err;
+       }
+
+       hpb_chan->plane_idx = 0;
+       hpb_chan->first_desc = true;
+
+       if ((cfg->dcr & (HPB_DMAE_DCR_CT | HPB_DMAE_DCR_DIP)) == 0) {
+               hpb_chan->xfer_mode = XFER_SINGLE;
+       } else if ((cfg->dcr & (HPB_DMAE_DCR_CT | HPB_DMAE_DCR_DIP)) ==
+                  (HPB_DMAE_DCR_CT | HPB_DMAE_DCR_DIP)) {
+               hpb_chan->xfer_mode = XFER_DOUBLE;
+       } else {
+               dev_err(hpb_chan->shdma_chan.dev, "DCR setting error");
+               shdma_free_irq(&hpb_chan->shdma_chan);
+               return -EINVAL;
+       }
+
+       if (cfg->flags & HPB_DMAE_SET_ASYNC_MODE)
+               hpb_dmae_set_async_mode(hpbdev, cfg->mdm, cfg->mdr);
+       ch_reg_write(hpb_chan, cfg->dcr, HPB_DMAE_DCR);
+       ch_reg_write(hpb_chan, cfg->port, HPB_DMAE_DPTR);
+       hpb_chan->xmit_shift = calc_xmit_shift(hpb_chan);
+       hpb_dmae_enable_int(hpbdev, cfg->dma_ch);
+
+       return 0;
+}
+
+static int hpb_dmae_set_slave(struct shdma_chan *schan, int slave_id, bool try)
+{
+       struct hpb_dmae_chan *chan = to_chan(schan);
+       const struct hpb_dmae_slave_config *sc =
+               hpb_dmae_find_slave(chan, slave_id);
+
+       if (!sc)
+               return -ENODEV;
+       if (try)
+               return 0;
+       chan->cfg = sc;
+       return hpb_dmae_alloc_chan_resources(chan, sc);
+}
+
+static void hpb_dmae_setup_xfer(struct shdma_chan *schan, int slave_id)
+{
+}
+
+static dma_addr_t hpb_dmae_slave_addr(struct shdma_chan *schan)
+{
+       struct hpb_dmae_chan *chan = to_chan(schan);
+
+       return chan->cfg->addr;
+}
+
+static struct shdma_desc *hpb_dmae_embedded_desc(void *buf, int i)
+{
+       return &((struct hpb_desc *)buf)[i].shdma_desc;
+}
+
+static const struct shdma_ops hpb_dmae_ops = {
+       .desc_completed = hpb_dmae_desc_completed,
+       .halt_channel = hpb_dmae_halt,
+       .channel_busy = hpb_dmae_channel_busy,
+       .slave_addr = hpb_dmae_slave_addr,
+       .desc_setup = hpb_dmae_desc_setup,
+       .set_slave = hpb_dmae_set_slave,
+       .setup_xfer = hpb_dmae_setup_xfer,
+       .start_xfer = hpb_dmae_start_xfer,
+       .embedded_desc = hpb_dmae_embedded_desc,
+       .chan_irq = hpb_dmae_chan_irq,
+       .get_partial = hpb_dmae_get_partial,
+};
+
+static int hpb_dmae_chan_probe(struct hpb_dmae_device *hpbdev, int id)
+{
+       struct shdma_dev *sdev = &hpbdev->shdma_dev;
+       struct platform_device *pdev =
+               to_platform_device(hpbdev->shdma_dev.dma_dev.dev);
+       struct hpb_dmae_chan *new_hpb_chan;
+       struct shdma_chan *schan;
+
+       /* Alloc channel */
+       new_hpb_chan = devm_kzalloc(&pdev->dev,
+                                   sizeof(struct hpb_dmae_chan), GFP_KERNEL);
+       if (!new_hpb_chan) {
+               dev_err(hpbdev->shdma_dev.dma_dev.dev,
+                       "No free memory for allocating DMA channels!\n");
+               return -ENOMEM;
+       }
+
+       schan = &new_hpb_chan->shdma_chan;
+       shdma_chan_probe(sdev, schan, id);
+
+       if (pdev->id >= 0)
+               snprintf(new_hpb_chan->dev_id, sizeof(new_hpb_chan->dev_id),
+                        "hpb-dmae%d.%d", pdev->id, id);
+       else
+               snprintf(new_hpb_chan->dev_id, sizeof(new_hpb_chan->dev_id),
+                        "hpb-dma.%d", id);
+
+       return 0;
+}
+
+static int hpb_dmae_probe(struct platform_device *pdev)
+{
+       struct hpb_dmae_pdata *pdata = pdev->dev.platform_data;
+       struct hpb_dmae_device *hpbdev;
+       struct dma_device *dma_dev;
+       struct resource *chan, *comm, *rest, *mode, *irq_res;
+       int err, i;
+
+       /* Get platform data */
+       if (!pdata || !pdata->num_channels)
+               return -ENODEV;
+
+       chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       comm = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       rest = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       mode = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+
+       irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!irq_res)
+               return -ENODEV;
+
+       hpbdev = devm_kzalloc(&pdev->dev, sizeof(struct hpb_dmae_device),
+                             GFP_KERNEL);
+       if (!hpbdev) {
+               dev_err(&pdev->dev, "Not enough memory\n");
+               return -ENOMEM;
+       }
+
+       hpbdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
+       if (IS_ERR(hpbdev->chan_reg))
+               return PTR_ERR(hpbdev->chan_reg);
+
+       hpbdev->comm_reg = devm_ioremap_resource(&pdev->dev, comm);
+       if (IS_ERR(hpbdev->comm_reg))
+               return PTR_ERR(hpbdev->comm_reg);
+
+       hpbdev->reset_reg = devm_ioremap_resource(&pdev->dev, rest);
+       if (IS_ERR(hpbdev->reset_reg))
+               return PTR_ERR(hpbdev->reset_reg);
+
+       hpbdev->mode_reg = devm_ioremap_resource(&pdev->dev, mode);
+       if (IS_ERR(hpbdev->mode_reg))
+               return PTR_ERR(hpbdev->mode_reg);
+
+       dma_dev = &hpbdev->shdma_dev.dma_dev;
+
+       spin_lock_init(&hpbdev->reg_lock);
+
+       /* Platform data */
+       hpbdev->pdata = pdata;
+
+       pm_runtime_enable(&pdev->dev);
+       err = pm_runtime_get_sync(&pdev->dev);
+       if (err < 0)
+               dev_err(&pdev->dev, "%s(): GET = %d\n", __func__, err);
+
+       /* Reset DMA controller */
+       hpb_dmae_reset(hpbdev);
+
+       pm_runtime_put(&pdev->dev);
+
+       dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+       dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+       hpbdev->shdma_dev.ops = &hpb_dmae_ops;
+       hpbdev->shdma_dev.desc_size = sizeof(struct hpb_desc);
+       err = shdma_init(&pdev->dev, &hpbdev->shdma_dev, pdata->num_channels);
+       if (err < 0)
+               goto error;
+
+       /* Create DMA channels */
+       for (i = 0; i < pdata->num_channels; i++)
+               hpb_dmae_chan_probe(hpbdev, i);
+
+       platform_set_drvdata(pdev, hpbdev);
+       err = dma_async_device_register(dma_dev);
+       if (!err)
+               return 0;
+
+       shdma_cleanup(&hpbdev->shdma_dev);
+error:
+       pm_runtime_disable(&pdev->dev);
+       return err;
+}
+
+static void hpb_dmae_chan_remove(struct hpb_dmae_device *hpbdev)
+{
+       struct dma_device *dma_dev = &hpbdev->shdma_dev.dma_dev;
+       struct shdma_chan *schan;
+       int i;
+
+       shdma_for_each_chan(schan, &hpbdev->shdma_dev, i) {
+               BUG_ON(!schan);
+
+               shdma_free_irq(schan);
+               shdma_chan_remove(schan);
+       }
+       dma_dev->chancnt = 0;
+}
+
+static int hpb_dmae_remove(struct platform_device *pdev)
+{
+       struct hpb_dmae_device *hpbdev = platform_get_drvdata(pdev);
+
+       dma_async_device_unregister(&hpbdev->shdma_dev.dma_dev);
+
+       pm_runtime_disable(&pdev->dev);
+
+       hpb_dmae_chan_remove(hpbdev);
+
+       return 0;
+}
+
+static void hpb_dmae_shutdown(struct platform_device *pdev)
+{
+       struct hpb_dmae_device *hpbdev = platform_get_drvdata(pdev);
+       hpb_dmae_ctl_stop(hpbdev);
+}
+
+static struct platform_driver hpb_dmae_driver = {
+       .probe          = hpb_dmae_probe,
+       .remove         = hpb_dmae_remove,
+       .shutdown       = hpb_dmae_shutdown,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "hpb-dma-engine",
+       },
+};
+module_platform_driver(hpb_dmae_driver);
+
+MODULE_AUTHOR("Max Filippov <max.filippov@cogentembedded.com>");
+MODULE_DESCRIPTION("Renesas HPB DMA Engine driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/sh/shdma-arm.h b/drivers/dma/sh/shdma-arm.h
new file mode 100644 (file)
index 0000000..a2b8258
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Renesas SuperH DMA Engine support
+ *
+ * Copyright (C) 2013 Renesas Electronics, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of version 2 the GNU General Public License as published by the Free
+ * Software Foundation.
+ */
+
+#ifndef SHDMA_ARM_H
+#define SHDMA_ARM_H
+
+#include "shdma.h"
+
+/* Transmit sizes and respective CHCR register values */
+enum {
+       XMIT_SZ_8BIT            = 0,
+       XMIT_SZ_16BIT           = 1,
+       XMIT_SZ_32BIT           = 2,
+       XMIT_SZ_64BIT           = 7,
+       XMIT_SZ_128BIT          = 3,
+       XMIT_SZ_256BIT          = 4,
+       XMIT_SZ_512BIT          = 5,
+};
+
+/* log2(size / 8) - used to calculate number of transfers */
+#define SH_DMAE_TS_SHIFT {             \
+       [XMIT_SZ_8BIT]          = 0,    \
+       [XMIT_SZ_16BIT]         = 1,    \
+       [XMIT_SZ_32BIT]         = 2,    \
+       [XMIT_SZ_64BIT]         = 3,    \
+       [XMIT_SZ_128BIT]        = 4,    \
+       [XMIT_SZ_256BIT]        = 5,    \
+       [XMIT_SZ_512BIT]        = 6,    \
+}
+
+#define TS_LOW_BIT     0x3 /* --xx */
+#define TS_HI_BIT      0xc /* xx-- */
+
+#define TS_LOW_SHIFT   (3)
+#define TS_HI_SHIFT    (20 - 2)        /* 2 bits for shifted low TS */
+
+#define TS_INDEX2VAL(i) \
+       ((((i) & TS_LOW_BIT) << TS_LOW_SHIFT) |\
+        (((i) & TS_HI_BIT)  << TS_HI_SHIFT))
+
+#define CHCR_TX(xmit_sz) (DM_FIX | SM_INC | 0x800 | TS_INDEX2VAL((xmit_sz)))
+#define CHCR_RX(xmit_sz) (DM_INC | SM_FIX | 0x800 | TS_INDEX2VAL((xmit_sz)))
+
+#endif
index 28ca3612163194f89fe9053c8c0c97ea78809c9d..d94ab592cc1bb21b92c851debe381609b599fa48 100644 (file)
@@ -171,7 +171,8 @@ static struct shdma_desc *shdma_get_desc(struct shdma_chan *schan)
        return NULL;
 }
 
-static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
+static int shdma_setup_slave(struct shdma_chan *schan, int slave_id,
+                            dma_addr_t slave_addr)
 {
        struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
        const struct shdma_ops *ops = sdev->ops;
@@ -179,7 +180,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
 
        if (schan->dev->of_node) {
                match = schan->hw_req;
-               ret = ops->set_slave(schan, match, true);
+               ret = ops->set_slave(schan, match, slave_addr, true);
                if (ret < 0)
                        return ret;
 
@@ -194,7 +195,7 @@ static int shdma_setup_slave(struct shdma_chan *schan, int slave_id)
        if (test_and_set_bit(slave_id, shdma_slave_used))
                return -EBUSY;
 
-       ret = ops->set_slave(schan, match, false);
+       ret = ops->set_slave(schan, match, slave_addr, false);
        if (ret < 0) {
                clear_bit(slave_id, shdma_slave_used);
                return ret;
@@ -236,7 +237,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
        if (!schan->dev->of_node && match >= slave_num)
                return false;
 
-       ret = ops->set_slave(schan, match, true);
+       ret = ops->set_slave(schan, match, 0, true);
        if (ret < 0)
                return false;
 
@@ -259,7 +260,7 @@ static int shdma_alloc_chan_resources(struct dma_chan *chan)
         */
        if (slave) {
                /* Legacy mode: .private is set in filter */
-               ret = shdma_setup_slave(schan, slave->slave_id);
+               ret = shdma_setup_slave(schan, slave->slave_id, 0);
                if (ret < 0)
                        goto esetslave;
        } else {
@@ -680,7 +681,9 @@ static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
                 * channel, while using it...
                 */
                config = (struct dma_slave_config *)arg;
-               ret = shdma_setup_slave(schan, config->slave_id);
+               ret = shdma_setup_slave(schan, config->slave_id,
+                                       config->direction == DMA_DEV_TO_MEM ?
+                                       config->src_addr : config->dst_addr);
                if (ret < 0)
                        return ret;
                break;
@@ -831,8 +834,8 @@ static irqreturn_t chan_irqt(int irq, void *dev)
 int shdma_request_irq(struct shdma_chan *schan, int irq,
                           unsigned long flags, const char *name)
 {
-       int ret = request_threaded_irq(irq, chan_irq, chan_irqt,
-                                      flags, name, schan);
+       int ret = devm_request_threaded_irq(schan->dev, irq, chan_irq,
+                                           chan_irqt, flags, name, schan);
 
        schan->irq = ret < 0 ? ret : irq;
 
@@ -840,13 +843,6 @@ int shdma_request_irq(struct shdma_chan *schan, int irq,
 }
 EXPORT_SYMBOL(shdma_request_irq);
 
-void shdma_free_irq(struct shdma_chan *schan)
-{
-       if (schan->irq >= 0)
-               free_irq(schan->irq, schan);
-}
-EXPORT_SYMBOL(shdma_free_irq);
-
 void shdma_chan_probe(struct shdma_dev *sdev,
                           struct shdma_chan *schan, int id)
 {
index 11bcb05cd79c9eb6e9f6258d6d8cfcabc46bdf28..06473a05fe4ebc97a7b925772604987dd476c3a4 100644 (file)
@@ -42,12 +42,9 @@ static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
 
 static int shdma_of_probe(struct platform_device *pdev)
 {
-       const struct of_dev_auxdata *lookup = pdev->dev.platform_data;
+       const struct of_dev_auxdata *lookup = dev_get_platdata(&pdev->dev);
        int ret;
 
-       if (!lookup)
-               return -EINVAL;
-
        ret = of_dma_controller_register(pdev->dev.of_node,
                                         shdma_of_xlate, pdev);
        if (ret < 0)
diff --git a/drivers/dma/sh/shdma-r8a73a4.c b/drivers/dma/sh/shdma-r8a73a4.c
new file mode 100644 (file)
index 0000000..4fb9997
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Renesas SuperH DMA Engine support for r8a73a4 (APE6) SoCs
+ *
+ * Copyright (C) 2013 Renesas Electronics, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under the
+ * terms of version 2 the GNU General Public License as published by the Free
+ * Software Foundation.
+ */
+#include <linux/sh_dma.h>
+
+#include "shdma-arm.h"
+
+const unsigned int dma_ts_shift[] = SH_DMAE_TS_SHIFT;
+
+static const struct sh_dmae_slave_config dma_slaves[] = {
+       {
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd1,         /* MMC0 Tx */
+       }, {
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xd2,         /* MMC0 Rx */
+       }, {
+               .chcr           = CHCR_TX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xe1,         /* MMC1 Tx */
+       }, {
+               .chcr           = CHCR_RX(XMIT_SZ_32BIT),
+               .mid_rid        = 0xe2,         /* MMC1 Rx */
+       },
+};
+
+#define DMAE_CHANNEL(a, b)                             \
+       {                                               \
+               .offset         = (a) - 0x20,           \
+               .dmars          = (a) - 0x20 + 0x40,    \
+               .chclr_bit      = (b),                  \
+               .chclr_offset   = 0x80 - 0x20,          \
+       }
+
+static const struct sh_dmae_channel dma_channels[] = {
+       DMAE_CHANNEL(0x8000, 0),
+       DMAE_CHANNEL(0x8080, 1),
+       DMAE_CHANNEL(0x8100, 2),
+       DMAE_CHANNEL(0x8180, 3),
+       DMAE_CHANNEL(0x8200, 4),
+       DMAE_CHANNEL(0x8280, 5),
+       DMAE_CHANNEL(0x8300, 6),
+       DMAE_CHANNEL(0x8380, 7),
+       DMAE_CHANNEL(0x8400, 8),
+       DMAE_CHANNEL(0x8480, 9),
+       DMAE_CHANNEL(0x8500, 10),
+       DMAE_CHANNEL(0x8580, 11),
+       DMAE_CHANNEL(0x8600, 12),
+       DMAE_CHANNEL(0x8680, 13),
+       DMAE_CHANNEL(0x8700, 14),
+       DMAE_CHANNEL(0x8780, 15),
+       DMAE_CHANNEL(0x8800, 16),
+       DMAE_CHANNEL(0x8880, 17),
+       DMAE_CHANNEL(0x8900, 18),
+       DMAE_CHANNEL(0x8980, 19),
+};
+
+const struct sh_dmae_pdata r8a73a4_dma_pdata = {
+       .slave          = dma_slaves,
+       .slave_num      = ARRAY_SIZE(dma_slaves),
+       .channel        = dma_channels,
+       .channel_num    = ARRAY_SIZE(dma_channels),
+       .ts_low_shift   = TS_LOW_SHIFT,
+       .ts_low_mask    = TS_LOW_BIT << TS_LOW_SHIFT,
+       .ts_high_shift  = TS_HI_SHIFT,
+       .ts_high_mask   = TS_HI_BIT << TS_HI_SHIFT,
+       .ts_shift       = dma_ts_shift,
+       .ts_shift_num   = ARRAY_SIZE(dma_ts_shift),
+       .dmaor_init     = DMAOR_DME,
+       .chclr_present  = 1,
+       .chclr_bitwise  = 1,
+};
diff --git a/drivers/dma/sh/shdma.c b/drivers/dma/sh/shdma.c
deleted file mode 100644 (file)
index 5039fbc..0000000
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- * Renesas SuperH DMA Engine support
- *
- * base is drivers/dma/flsdma.c
- *
- * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
- * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
- * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
- *
- * This 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.
- *
- * - DMA of SuperH does not have Hardware DMA chain mode.
- * - MAX DMA size is 16MB.
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/dmaengine.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-#include <linux/sh_dma.h>
-#include <linux/notifier.h>
-#include <linux/kdebug.h>
-#include <linux/spinlock.h>
-#include <linux/rculist.h>
-
-#include "../dmaengine.h"
-#include "shdma.h"
-
-#define SH_DMAE_DRV_NAME "sh-dma-engine"
-
-/* Default MEMCPY transfer size = 2^2 = 4 bytes */
-#define LOG2_DEFAULT_XFER_SIZE 2
-#define SH_DMA_SLAVE_NUMBER 256
-#define SH_DMA_TCR_MAX (16 * 1024 * 1024 - 1)
-
-/*
- * Used for write-side mutual exclusion for the global device list,
- * read-side synchronization by way of RCU, and per-controller data.
- */
-static DEFINE_SPINLOCK(sh_dmae_lock);
-static LIST_HEAD(sh_dmae_devices);
-
-static void chclr_write(struct sh_dmae_chan *sh_dc, u32 data)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
-
-       __raw_writel(data, shdev->chan_reg +
-                    shdev->pdata->channel[sh_dc->shdma_chan.id].chclr_offset);
-}
-
-static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
-{
-       __raw_writel(data, sh_dc->base + reg / sizeof(u32));
-}
-
-static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
-{
-       return __raw_readl(sh_dc->base + reg / sizeof(u32));
-}
-
-static u16 dmaor_read(struct sh_dmae_device *shdev)
-{
-       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
-
-       if (shdev->pdata->dmaor_is_32bit)
-               return __raw_readl(addr);
-       else
-               return __raw_readw(addr);
-}
-
-static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
-{
-       u32 __iomem *addr = shdev->chan_reg + DMAOR / sizeof(u32);
-
-       if (shdev->pdata->dmaor_is_32bit)
-               __raw_writel(data, addr);
-       else
-               __raw_writew(data, addr);
-}
-
-static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
-
-       __raw_writel(data, sh_dc->base + shdev->chcr_offset / sizeof(u32));
-}
-
-static u32 chcr_read(struct sh_dmae_chan *sh_dc)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
-
-       return __raw_readl(sh_dc->base + shdev->chcr_offset / sizeof(u32));
-}
-
-/*
- * Reset DMA controller
- *
- * SH7780 has two DMAOR register
- */
-static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
-{
-       unsigned short dmaor;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sh_dmae_lock, flags);
-
-       dmaor = dmaor_read(shdev);
-       dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME));
-
-       spin_unlock_irqrestore(&sh_dmae_lock, flags);
-}
-
-static int sh_dmae_rst(struct sh_dmae_device *shdev)
-{
-       unsigned short dmaor;
-       unsigned long flags;
-
-       spin_lock_irqsave(&sh_dmae_lock, flags);
-
-       dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
-
-       if (shdev->pdata->chclr_present) {
-               int i;
-               for (i = 0; i < shdev->pdata->channel_num; i++) {
-                       struct sh_dmae_chan *sh_chan = shdev->chan[i];
-                       if (sh_chan)
-                               chclr_write(sh_chan, 0);
-               }
-       }
-
-       dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init);
-
-       dmaor = dmaor_read(shdev);
-
-       spin_unlock_irqrestore(&sh_dmae_lock, flags);
-
-       if (dmaor & (DMAOR_AE | DMAOR_NMIF)) {
-               dev_warn(shdev->shdma_dev.dma_dev.dev, "Can't initialize DMAOR.\n");
-               return -EIO;
-       }
-       if (shdev->pdata->dmaor_init & ~dmaor)
-               dev_warn(shdev->shdma_dev.dma_dev.dev,
-                        "DMAOR=0x%x hasn't latched the initial value 0x%x.\n",
-                        dmaor, shdev->pdata->dmaor_init);
-       return 0;
-}
-
-static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
-{
-       u32 chcr = chcr_read(sh_chan);
-
-       if ((chcr & (CHCR_DE | CHCR_TE)) == CHCR_DE)
-               return true; /* working */
-
-       return false; /* waiting */
-}
-
-static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
-       struct sh_dmae_pdata *pdata = shdev->pdata;
-       int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
-               ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
-
-       if (cnt >= pdata->ts_shift_num)
-               cnt = 0;
-
-       return pdata->ts_shift[cnt];
-}
-
-static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
-       struct sh_dmae_pdata *pdata = shdev->pdata;
-       int i;
-
-       for (i = 0; i < pdata->ts_shift_num; i++)
-               if (pdata->ts_shift[i] == l2size)
-                       break;
-
-       if (i == pdata->ts_shift_num)
-               i = 0;
-
-       return ((i << pdata->ts_low_shift) & pdata->ts_low_mask) |
-               ((i << pdata->ts_high_shift) & pdata->ts_high_mask);
-}
-
-static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw)
-{
-       sh_dmae_writel(sh_chan, hw->sar, SAR);
-       sh_dmae_writel(sh_chan, hw->dar, DAR);
-       sh_dmae_writel(sh_chan, hw->tcr >> sh_chan->xmit_shift, TCR);
-}
-
-static void dmae_start(struct sh_dmae_chan *sh_chan)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
-       u32 chcr = chcr_read(sh_chan);
-
-       if (shdev->pdata->needs_tend_set)
-               sh_dmae_writel(sh_chan, 0xFFFFFFFF, TEND);
-
-       chcr |= CHCR_DE | shdev->chcr_ie_bit;
-       chcr_write(sh_chan, chcr & ~CHCR_TE);
-}
-
-static void dmae_init(struct sh_dmae_chan *sh_chan)
-{
-       /*
-        * Default configuration for dual address memory-memory transfer.
-        * 0x400 represents auto-request.
-        */
-       u32 chcr = DM_INC | SM_INC | 0x400 | log2size_to_chcr(sh_chan,
-                                                  LOG2_DEFAULT_XFER_SIZE);
-       sh_chan->xmit_shift = calc_xmit_shift(sh_chan, chcr);
-       chcr_write(sh_chan, chcr);
-}
-
-static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
-{
-       /* If DMA is active, cannot set CHCR. TODO: remove this superfluous check */
-       if (dmae_is_busy(sh_chan))
-               return -EBUSY;
-
-       sh_chan->xmit_shift = calc_xmit_shift(sh_chan, val);
-       chcr_write(sh_chan, val);
-
-       return 0;
-}
-
-static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
-       struct sh_dmae_pdata *pdata = shdev->pdata;
-       const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id];
-       u16 __iomem *addr = shdev->dmars;
-       unsigned int shift = chan_pdata->dmars_bit;
-
-       if (dmae_is_busy(sh_chan))
-               return -EBUSY;
-
-       if (pdata->no_dmars)
-               return 0;
-
-       /* in the case of a missing DMARS resource use first memory window */
-       if (!addr)
-               addr = (u16 __iomem *)shdev->chan_reg;
-       addr += chan_pdata->dmars / sizeof(u16);
-
-       __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
-                    addr);
-
-       return 0;
-}
-
-static void sh_dmae_start_xfer(struct shdma_chan *schan,
-                              struct shdma_desc *sdesc)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-       struct sh_dmae_desc *sh_desc = container_of(sdesc,
-                                       struct sh_dmae_desc, shdma_desc);
-       dev_dbg(sh_chan->shdma_chan.dev, "Queue #%d to %d: %u@%x -> %x\n",
-               sdesc->async_tx.cookie, sh_chan->shdma_chan.id,
-               sh_desc->hw.tcr, sh_desc->hw.sar, sh_desc->hw.dar);
-       /* Get the ld start address from ld_queue */
-       dmae_set_reg(sh_chan, &sh_desc->hw);
-       dmae_start(sh_chan);
-}
-
-static bool sh_dmae_channel_busy(struct shdma_chan *schan)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-       return dmae_is_busy(sh_chan);
-}
-
-static void sh_dmae_setup_xfer(struct shdma_chan *schan,
-                              int slave_id)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-
-       if (slave_id >= 0) {
-               const struct sh_dmae_slave_config *cfg =
-                       sh_chan->config;
-
-               dmae_set_dmars(sh_chan, cfg->mid_rid);
-               dmae_set_chcr(sh_chan, cfg->chcr);
-       } else {
-               dmae_init(sh_chan);
-       }
-}
-
-/*
- * Find a slave channel configuration from the contoller list by either a slave
- * ID in the non-DT case, or by a MID/RID value in the DT case
- */
-static const struct sh_dmae_slave_config *dmae_find_slave(
-       struct sh_dmae_chan *sh_chan, int match)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
-       struct sh_dmae_pdata *pdata = shdev->pdata;
-       const struct sh_dmae_slave_config *cfg;
-       int i;
-
-       if (!sh_chan->shdma_chan.dev->of_node) {
-               if (match >= SH_DMA_SLAVE_NUMBER)
-                       return NULL;
-
-               for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
-                       if (cfg->slave_id == match)
-                               return cfg;
-       } else {
-               for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
-                       if (cfg->mid_rid == match) {
-                               sh_chan->shdma_chan.slave_id = cfg->slave_id;
-                               return cfg;
-                       }
-       }
-
-       return NULL;
-}
-
-static int sh_dmae_set_slave(struct shdma_chan *schan,
-                            int slave_id, bool try)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-       const struct sh_dmae_slave_config *cfg = dmae_find_slave(sh_chan, slave_id);
-       if (!cfg)
-               return -ENXIO;
-
-       if (!try)
-               sh_chan->config = cfg;
-
-       return 0;
-}
-
-static void dmae_halt(struct sh_dmae_chan *sh_chan)
-{
-       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
-       u32 chcr = chcr_read(sh_chan);
-
-       chcr &= ~(CHCR_DE | CHCR_TE | shdev->chcr_ie_bit);
-       chcr_write(sh_chan, chcr);
-}
-
-static int sh_dmae_desc_setup(struct shdma_chan *schan,
-                             struct shdma_desc *sdesc,
-                             dma_addr_t src, dma_addr_t dst, size_t *len)
-{
-       struct sh_dmae_desc *sh_desc = container_of(sdesc,
-                                       struct sh_dmae_desc, shdma_desc);
-
-       if (*len > schan->max_xfer_len)
-               *len = schan->max_xfer_len;
-
-       sh_desc->hw.sar = src;
-       sh_desc->hw.dar = dst;
-       sh_desc->hw.tcr = *len;
-
-       return 0;
-}
-
-static void sh_dmae_halt(struct shdma_chan *schan)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-       dmae_halt(sh_chan);
-}
-
-static bool sh_dmae_chan_irq(struct shdma_chan *schan, int irq)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-
-       if (!(chcr_read(sh_chan) & CHCR_TE))
-               return false;
-
-       /* DMA stop */
-       dmae_halt(sh_chan);
-
-       return true;
-}
-
-static size_t sh_dmae_get_partial(struct shdma_chan *schan,
-                                 struct shdma_desc *sdesc)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
-                                                   shdma_chan);
-       struct sh_dmae_desc *sh_desc = container_of(sdesc,
-                                       struct sh_dmae_desc, shdma_desc);
-       return sh_desc->hw.tcr -
-               (sh_dmae_readl(sh_chan, TCR) << sh_chan->xmit_shift);
-}
-
-/* Called from error IRQ or NMI */
-static bool sh_dmae_reset(struct sh_dmae_device *shdev)
-{
-       bool ret;
-
-       /* halt the dma controller */
-       sh_dmae_ctl_stop(shdev);
-
-       /* We cannot detect, which channel caused the error, have to reset all */
-       ret = shdma_reset(&shdev->shdma_dev);
-
-       sh_dmae_rst(shdev);
-
-       return ret;
-}
-
-static irqreturn_t sh_dmae_err(int irq, void *data)
-{
-       struct sh_dmae_device *shdev = data;
-
-       if (!(dmaor_read(shdev) & DMAOR_AE))
-               return IRQ_NONE;
-
-       sh_dmae_reset(shdev);
-       return IRQ_HANDLED;
-}
-
-static bool sh_dmae_desc_completed(struct shdma_chan *schan,
-                                  struct shdma_desc *sdesc)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan,
-                                       struct sh_dmae_chan, shdma_chan);
-       struct sh_dmae_desc *sh_desc = container_of(sdesc,
-                                       struct sh_dmae_desc, shdma_desc);
-       u32 sar_buf = sh_dmae_readl(sh_chan, SAR);
-       u32 dar_buf = sh_dmae_readl(sh_chan, DAR);
-
-       return  (sdesc->direction == DMA_DEV_TO_MEM &&
-                (sh_desc->hw.dar + sh_desc->hw.tcr) == dar_buf) ||
-               (sdesc->direction != DMA_DEV_TO_MEM &&
-                (sh_desc->hw.sar + sh_desc->hw.tcr) == sar_buf);
-}
-
-static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
-{
-       /* Fast path out if NMIF is not asserted for this controller */
-       if ((dmaor_read(shdev) & DMAOR_NMIF) == 0)
-               return false;
-
-       return sh_dmae_reset(shdev);
-}
-
-static int sh_dmae_nmi_handler(struct notifier_block *self,
-                              unsigned long cmd, void *data)
-{
-       struct sh_dmae_device *shdev;
-       int ret = NOTIFY_DONE;
-       bool triggered;
-
-       /*
-        * Only concern ourselves with NMI events.
-        *
-        * Normally we would check the die chain value, but as this needs
-        * to be architecture independent, check for NMI context instead.
-        */
-       if (!in_nmi())
-               return NOTIFY_DONE;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(shdev, &sh_dmae_devices, node) {
-               /*
-                * Only stop if one of the controllers has NMIF asserted,
-                * we do not want to interfere with regular address error
-                * handling or NMI events that don't concern the DMACs.
-                */
-               triggered = sh_dmae_nmi_notify(shdev);
-               if (triggered == true)
-                       ret = NOTIFY_OK;
-       }
-       rcu_read_unlock();
-
-       return ret;
-}
-
-static struct notifier_block sh_dmae_nmi_notifier __read_mostly = {
-       .notifier_call  = sh_dmae_nmi_handler,
-
-       /* Run before NMI debug handler and KGDB */
-       .priority       = 1,
-};
-
-static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
-                                       int irq, unsigned long flags)
-{
-       const struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id];
-       struct shdma_dev *sdev = &shdev->shdma_dev;
-       struct platform_device *pdev = to_platform_device(sdev->dma_dev.dev);
-       struct sh_dmae_chan *sh_chan;
-       struct shdma_chan *schan;
-       int err;
-
-       sh_chan = kzalloc(sizeof(struct sh_dmae_chan), GFP_KERNEL);
-       if (!sh_chan) {
-               dev_err(sdev->dma_dev.dev,
-                       "No free memory for allocating dma channels!\n");
-               return -ENOMEM;
-       }
-
-       schan = &sh_chan->shdma_chan;
-       schan->max_xfer_len = SH_DMA_TCR_MAX + 1;
-
-       shdma_chan_probe(sdev, schan, id);
-
-       sh_chan->base = shdev->chan_reg + chan_pdata->offset / sizeof(u32);
-
-       /* set up channel irq */
-       if (pdev->id >= 0)
-               snprintf(sh_chan->dev_id, sizeof(sh_chan->dev_id),
-                        "sh-dmae%d.%d", pdev->id, id);
-       else
-               snprintf(sh_chan->dev_id, sizeof(sh_chan->dev_id),
-                        "sh-dma%d", id);
-
-       err = shdma_request_irq(schan, irq, flags, sh_chan->dev_id);
-       if (err) {
-               dev_err(sdev->dma_dev.dev,
-                       "DMA channel %d request_irq error %d\n",
-                       id, err);
-               goto err_no_irq;
-       }
-
-       shdev->chan[id] = sh_chan;
-       return 0;
-
-err_no_irq:
-       /* remove from dmaengine device node */
-       shdma_chan_remove(schan);
-       kfree(sh_chan);
-       return err;
-}
-
-static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
-{
-       struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
-       struct shdma_chan *schan;
-       int i;
-
-       shdma_for_each_chan(schan, &shdev->shdma_dev, i) {
-               struct sh_dmae_chan *sh_chan = container_of(schan,
-                                       struct sh_dmae_chan, shdma_chan);
-               BUG_ON(!schan);
-
-               shdma_free_irq(&sh_chan->shdma_chan);
-
-               shdma_chan_remove(schan);
-               kfree(sh_chan);
-       }
-       dma_dev->chancnt = 0;
-}
-
-static void sh_dmae_shutdown(struct platform_device *pdev)
-{
-       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
-       sh_dmae_ctl_stop(shdev);
-}
-
-static int sh_dmae_runtime_suspend(struct device *dev)
-{
-       return 0;
-}
-
-static int sh_dmae_runtime_resume(struct device *dev)
-{
-       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
-
-       return sh_dmae_rst(shdev);
-}
-
-#ifdef CONFIG_PM
-static int sh_dmae_suspend(struct device *dev)
-{
-       return 0;
-}
-
-static int sh_dmae_resume(struct device *dev)
-{
-       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
-       int i, ret;
-
-       ret = sh_dmae_rst(shdev);
-       if (ret < 0)
-               dev_err(dev, "Failed to reset!\n");
-
-       for (i = 0; i < shdev->pdata->channel_num; i++) {
-               struct sh_dmae_chan *sh_chan = shdev->chan[i];
-
-               if (!sh_chan->shdma_chan.desc_num)
-                       continue;
-
-               if (sh_chan->shdma_chan.slave_id >= 0) {
-                       const struct sh_dmae_slave_config *cfg = sh_chan->config;
-                       dmae_set_dmars(sh_chan, cfg->mid_rid);
-                       dmae_set_chcr(sh_chan, cfg->chcr);
-               } else {
-                       dmae_init(sh_chan);
-               }
-       }
-
-       return 0;
-}
-#else
-#define sh_dmae_suspend NULL
-#define sh_dmae_resume NULL
-#endif
-
-const struct dev_pm_ops sh_dmae_pm = {
-       .suspend                = sh_dmae_suspend,
-       .resume                 = sh_dmae_resume,
-       .runtime_suspend        = sh_dmae_runtime_suspend,
-       .runtime_resume         = sh_dmae_runtime_resume,
-};
-
-static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan)
-{
-       struct sh_dmae_chan *sh_chan = container_of(schan,
-                                       struct sh_dmae_chan, shdma_chan);
-
-       /*
-        * Implicit BUG_ON(!sh_chan->config)
-        * This is an exclusive slave DMA operation, may only be called after a
-        * successful slave configuration.
-        */
-       return sh_chan->config->addr;
-}
-
-static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i)
-{
-       return &((struct sh_dmae_desc *)buf)[i].shdma_desc;
-}
-
-static const struct shdma_ops sh_dmae_shdma_ops = {
-       .desc_completed = sh_dmae_desc_completed,
-       .halt_channel = sh_dmae_halt,
-       .channel_busy = sh_dmae_channel_busy,
-       .slave_addr = sh_dmae_slave_addr,
-       .desc_setup = sh_dmae_desc_setup,
-       .set_slave = sh_dmae_set_slave,
-       .setup_xfer = sh_dmae_setup_xfer,
-       .start_xfer = sh_dmae_start_xfer,
-       .embedded_desc = sh_dmae_embedded_desc,
-       .chan_irq = sh_dmae_chan_irq,
-       .get_partial = sh_dmae_get_partial,
-};
-
-static int sh_dmae_probe(struct platform_device *pdev)
-{
-       struct sh_dmae_pdata *pdata = pdev->dev.platform_data;
-       unsigned long irqflags = IRQF_DISABLED,
-               chan_flag[SH_DMAE_MAX_CHANNELS] = {};
-       int errirq, chan_irq[SH_DMAE_MAX_CHANNELS];
-       int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
-       struct sh_dmae_device *shdev;
-       struct dma_device *dma_dev;
-       struct resource *chan, *dmars, *errirq_res, *chanirq_res;
-
-       /* get platform data */
-       if (!pdata || !pdata->channel_num)
-               return -ENODEV;
-
-       chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       /* DMARS area is optional */
-       dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       /*
-        * IRQ resources:
-        * 1. there always must be at least one IRQ IO-resource. On SH4 it is
-        *    the error IRQ, in which case it is the only IRQ in this resource:
-        *    start == end. If it is the only IRQ resource, all channels also
-        *    use the same IRQ.
-        * 2. DMA channel IRQ resources can be specified one per resource or in
-        *    ranges (start != end)
-        * 3. iff all events (channels and, optionally, error) on this
-        *    controller use the same IRQ, only one IRQ resource can be
-        *    specified, otherwise there must be one IRQ per channel, even if
-        *    some of them are equal
-        * 4. if all IRQs on this controller are equal or if some specific IRQs
-        *    specify IORESOURCE_IRQ_SHAREABLE in their resources, they will be
-        *    requested with the IRQF_SHARED flag
-        */
-       errirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!chan || !errirq_res)
-               return -ENODEV;
-
-       if (!request_mem_region(chan->start, resource_size(chan), pdev->name)) {
-               dev_err(&pdev->dev, "DMAC register region already claimed\n");
-               return -EBUSY;
-       }
-
-       if (dmars && !request_mem_region(dmars->start, resource_size(dmars), pdev->name)) {
-               dev_err(&pdev->dev, "DMAC DMARS region already claimed\n");
-               err = -EBUSY;
-               goto ermrdmars;
-       }
-
-       err = -ENOMEM;
-       shdev = kzalloc(sizeof(struct sh_dmae_device), GFP_KERNEL);
-       if (!shdev) {
-               dev_err(&pdev->dev, "Not enough memory\n");
-               goto ealloc;
-       }
-
-       dma_dev = &shdev->shdma_dev.dma_dev;
-
-       shdev->chan_reg = ioremap(chan->start, resource_size(chan));
-       if (!shdev->chan_reg)
-               goto emapchan;
-       if (dmars) {
-               shdev->dmars = ioremap(dmars->start, resource_size(dmars));
-               if (!shdev->dmars)
-                       goto emapdmars;
-       }
-
-       if (!pdata->slave_only)
-               dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
-       if (pdata->slave && pdata->slave_num)
-               dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
-
-       /* Default transfer size of 32 bytes requires 32-byte alignment */
-       dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
-
-       shdev->shdma_dev.ops = &sh_dmae_shdma_ops;
-       shdev->shdma_dev.desc_size = sizeof(struct sh_dmae_desc);
-       err = shdma_init(&pdev->dev, &shdev->shdma_dev,
-                             pdata->channel_num);
-       if (err < 0)
-               goto eshdma;
-
-       /* platform data */
-       shdev->pdata = pdata;
-
-       if (pdata->chcr_offset)
-               shdev->chcr_offset = pdata->chcr_offset;
-       else
-               shdev->chcr_offset = CHCR;
-
-       if (pdata->chcr_ie_bit)
-               shdev->chcr_ie_bit = pdata->chcr_ie_bit;
-       else
-               shdev->chcr_ie_bit = CHCR_IE;
-
-       platform_set_drvdata(pdev, shdev);
-
-       pm_runtime_enable(&pdev->dev);
-       err = pm_runtime_get_sync(&pdev->dev);
-       if (err < 0)
-               dev_err(&pdev->dev, "%s(): GET = %d\n", __func__, err);
-
-       spin_lock_irq(&sh_dmae_lock);
-       list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
-       spin_unlock_irq(&sh_dmae_lock);
-
-       /* reset dma controller - only needed as a test */
-       err = sh_dmae_rst(shdev);
-       if (err)
-               goto rst_err;
-
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
-       chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
-
-       if (!chanirq_res)
-               chanirq_res = errirq_res;
-       else
-               irqres++;
-
-       if (chanirq_res == errirq_res ||
-           (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE)
-               irqflags = IRQF_SHARED;
-
-       errirq = errirq_res->start;
-
-       err = request_irq(errirq, sh_dmae_err, irqflags,
-                         "DMAC Address Error", shdev);
-       if (err) {
-               dev_err(&pdev->dev,
-                       "DMA failed requesting irq #%d, error %d\n",
-                       errirq, err);
-               goto eirq_err;
-       }
-
-#else
-       chanirq_res = errirq_res;
-#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */
-
-       if (chanirq_res->start == chanirq_res->end &&
-           !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
-               /* Special case - all multiplexed */
-               for (; irq_cnt < pdata->channel_num; irq_cnt++) {
-                       if (irq_cnt < SH_DMAE_MAX_CHANNELS) {
-                               chan_irq[irq_cnt] = chanirq_res->start;
-                               chan_flag[irq_cnt] = IRQF_SHARED;
-                       } else {
-                               irq_cap = 1;
-                               break;
-                       }
-               }
-       } else {
-               do {
-                       for (i = chanirq_res->start; i <= chanirq_res->end; i++) {
-                               if (irq_cnt >= SH_DMAE_MAX_CHANNELS) {
-                                       irq_cap = 1;
-                                       break;
-                               }
-
-                               if ((errirq_res->flags & IORESOURCE_BITS) ==
-                                   IORESOURCE_IRQ_SHAREABLE)
-                                       chan_flag[irq_cnt] = IRQF_SHARED;
-                               else
-                                       chan_flag[irq_cnt] = IRQF_DISABLED;
-                               dev_dbg(&pdev->dev,
-                                       "Found IRQ %d for channel %d\n",
-                                       i, irq_cnt);
-                               chan_irq[irq_cnt++] = i;
-                       }
-
-                       if (irq_cnt >= SH_DMAE_MAX_CHANNELS)
-                               break;
-
-                       chanirq_res = platform_get_resource(pdev,
-                                               IORESOURCE_IRQ, ++irqres);
-               } while (irq_cnt < pdata->channel_num && chanirq_res);
-       }
-
-       /* Create DMA Channel */
-       for (i = 0; i < irq_cnt; i++) {
-               err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
-               if (err)
-                       goto chan_probe_err;
-       }
-
-       if (irq_cap)
-               dev_notice(&pdev->dev, "Attempting to register %d DMA "
-                          "channels when a maximum of %d are supported.\n",
-                          pdata->channel_num, SH_DMAE_MAX_CHANNELS);
-
-       pm_runtime_put(&pdev->dev);
-
-       err = dma_async_device_register(&shdev->shdma_dev.dma_dev);
-       if (err < 0)
-               goto edmadevreg;
-
-       return err;
-
-edmadevreg:
-       pm_runtime_get(&pdev->dev);
-
-chan_probe_err:
-       sh_dmae_chan_remove(shdev);
-
-#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
-       free_irq(errirq, shdev);
-eirq_err:
-#endif
-rst_err:
-       spin_lock_irq(&sh_dmae_lock);
-       list_del_rcu(&shdev->node);
-       spin_unlock_irq(&sh_dmae_lock);
-
-       pm_runtime_put(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
-
-       platform_set_drvdata(pdev, NULL);
-       shdma_cleanup(&shdev->shdma_dev);
-eshdma:
-       if (dmars)
-               iounmap(shdev->dmars);
-emapdmars:
-       iounmap(shdev->chan_reg);
-       synchronize_rcu();
-emapchan:
-       kfree(shdev);
-ealloc:
-       if (dmars)
-               release_mem_region(dmars->start, resource_size(dmars));
-ermrdmars:
-       release_mem_region(chan->start, resource_size(chan));
-
-       return err;
-}
-
-static int sh_dmae_remove(struct platform_device *pdev)
-{
-       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
-       struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
-       struct resource *res;
-       int errirq = platform_get_irq(pdev, 0);
-
-       dma_async_device_unregister(dma_dev);
-
-       if (errirq > 0)
-               free_irq(errirq, shdev);
-
-       spin_lock_irq(&sh_dmae_lock);
-       list_del_rcu(&shdev->node);
-       spin_unlock_irq(&sh_dmae_lock);
-
-       pm_runtime_disable(&pdev->dev);
-
-       sh_dmae_chan_remove(shdev);
-       shdma_cleanup(&shdev->shdma_dev);
-
-       if (shdev->dmars)
-               iounmap(shdev->dmars);
-       iounmap(shdev->chan_reg);
-
-       platform_set_drvdata(pdev, NULL);
-
-       synchronize_rcu();
-       kfree(shdev);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res)
-               release_mem_region(res->start, resource_size(res));
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (res)
-               release_mem_region(res->start, resource_size(res));
-
-       return 0;
-}
-
-static const struct of_device_id sh_dmae_of_match[] = {
-       { .compatible = "renesas,shdma", },
-       { }
-};
-MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
-
-static struct platform_driver sh_dmae_driver = {
-       .driver         = {
-               .owner  = THIS_MODULE,
-               .pm     = &sh_dmae_pm,
-               .name   = SH_DMAE_DRV_NAME,
-               .of_match_table = sh_dmae_of_match,
-       },
-       .remove         = sh_dmae_remove,
-       .shutdown       = sh_dmae_shutdown,
-};
-
-static int __init sh_dmae_init(void)
-{
-       /* Wire up NMI handling */
-       int err = register_die_notifier(&sh_dmae_nmi_notifier);
-       if (err)
-               return err;
-
-       return platform_driver_probe(&sh_dmae_driver, sh_dmae_probe);
-}
-module_init(sh_dmae_init);
-
-static void __exit sh_dmae_exit(void)
-{
-       platform_driver_unregister(&sh_dmae_driver);
-
-       unregister_die_notifier(&sh_dmae_nmi_notifier);
-}
-module_exit(sh_dmae_exit);
-
-MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>");
-MODULE_DESCRIPTION("Renesas SH DMA Engine driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" SH_DMAE_DRV_NAME);
index 9314e93225db73ca7cf9dadc9c336c1d828ce105..758a57b51875b38d84b999775d306a84ca85bcad 100644 (file)
@@ -28,18 +28,19 @@ struct sh_dmae_chan {
        struct shdma_chan shdma_chan;
        const struct sh_dmae_slave_config *config; /* Slave DMA configuration */
        int xmit_shift;                 /* log_2(bytes_per_xfer) */
-       u32 __iomem *base;
+       void __iomem *base;
        char dev_id[16];                /* unique name per DMAC of channel */
        int pm_error;
+       dma_addr_t slave_addr;
 };
 
 struct sh_dmae_device {
        struct shdma_dev shdma_dev;
        struct sh_dmae_chan *chan[SH_DMAE_MAX_CHANNELS];
-       struct sh_dmae_pdata *pdata;
+       const struct sh_dmae_pdata *pdata;
        struct list_head node;
-       u32 __iomem *chan_reg;
-       u16 __iomem *dmars;
+       void __iomem *chan_reg;
+       void __iomem *dmars;
        unsigned int chcr_offset;
        u32 chcr_ie_bit;
 };
@@ -61,4 +62,11 @@ struct sh_dmae_desc {
 #define to_sh_dev(chan) container_of(chan->shdma_chan.dma_chan.device,\
                                     struct sh_dmae_device, shdma_dev.dma_dev)
 
+#ifdef CONFIG_SHDMA_R8A73A4
+extern const struct sh_dmae_pdata r8a73a4_dma_pdata;
+#define r8a73a4_shdma_devid (&r8a73a4_dma_pdata)
+#else
+#define r8a73a4_shdma_devid NULL
+#endif
+
 #endif /* __DMA_SHDMA_H */
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
new file mode 100644 (file)
index 0000000..1069e88
--- /dev/null
@@ -0,0 +1,954 @@
+/*
+ * Renesas SuperH DMA Engine support
+ *
+ * base is drivers/dma/flsdma.c
+ *
+ * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This 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.
+ *
+ * - DMA of SuperH does not have Hardware DMA chain mode.
+ * - MAX DMA size is 16MB.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/sh_dma.h>
+#include <linux/notifier.h>
+#include <linux/kdebug.h>
+#include <linux/spinlock.h>
+#include <linux/rculist.h>
+
+#include "../dmaengine.h"
+#include "shdma.h"
+
+/* DMA register */
+#define SAR    0x00
+#define DAR    0x04
+#define TCR    0x08
+#define CHCR   0x0C
+#define DMAOR  0x40
+
+#define TEND   0x18 /* USB-DMAC */
+
+#define SH_DMAE_DRV_NAME "sh-dma-engine"
+
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+#define SH_DMA_SLAVE_NUMBER 256
+#define SH_DMA_TCR_MAX (16 * 1024 * 1024 - 1)
+
+/*
+ * Used for write-side mutual exclusion for the global device list,
+ * read-side synchronization by way of RCU, and per-controller data.
+ */
+static DEFINE_SPINLOCK(sh_dmae_lock);
+static LIST_HEAD(sh_dmae_devices);
+
+/*
+ * Different DMAC implementations provide different ways to clear DMA channels:
+ * (1) none - no CHCLR registers are available
+ * (2) one CHCLR register per channel - 0 has to be written to it to clear
+ *     channel buffers
+ * (3) one CHCLR per several channels - 1 has to be written to the bit,
+ *     corresponding to the specific channel to reset it
+ */
+static void channel_clear(struct sh_dmae_chan *sh_dc)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+       const struct sh_dmae_channel *chan_pdata = shdev->pdata->channel +
+               sh_dc->shdma_chan.id;
+       u32 val = shdev->pdata->chclr_bitwise ? 1 << chan_pdata->chclr_bit : 0;
+
+       __raw_writel(val, shdev->chan_reg + chan_pdata->chclr_offset);
+}
+
+static void sh_dmae_writel(struct sh_dmae_chan *sh_dc, u32 data, u32 reg)
+{
+       __raw_writel(data, sh_dc->base + reg);
+}
+
+static u32 sh_dmae_readl(struct sh_dmae_chan *sh_dc, u32 reg)
+{
+       return __raw_readl(sh_dc->base + reg);
+}
+
+static u16 dmaor_read(struct sh_dmae_device *shdev)
+{
+       void __iomem *addr = shdev->chan_reg + DMAOR;
+
+       if (shdev->pdata->dmaor_is_32bit)
+               return __raw_readl(addr);
+       else
+               return __raw_readw(addr);
+}
+
+static void dmaor_write(struct sh_dmae_device *shdev, u16 data)
+{
+       void __iomem *addr = shdev->chan_reg + DMAOR;
+
+       if (shdev->pdata->dmaor_is_32bit)
+               __raw_writel(data, addr);
+       else
+               __raw_writew(data, addr);
+}
+
+static void chcr_write(struct sh_dmae_chan *sh_dc, u32 data)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       __raw_writel(data, sh_dc->base + shdev->chcr_offset);
+}
+
+static u32 chcr_read(struct sh_dmae_chan *sh_dc)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_dc);
+
+       return __raw_readl(sh_dc->base + shdev->chcr_offset);
+}
+
+/*
+ * Reset DMA controller
+ *
+ * SH7780 has two DMAOR register
+ */
+static void sh_dmae_ctl_stop(struct sh_dmae_device *shdev)
+{
+       unsigned short dmaor;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sh_dmae_lock, flags);
+
+       dmaor = dmaor_read(shdev);
+       dmaor_write(shdev, dmaor & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME));
+
+       spin_unlock_irqrestore(&sh_dmae_lock, flags);
+}
+
+static int sh_dmae_rst(struct sh_dmae_device *shdev)
+{
+       unsigned short dmaor;
+       unsigned long flags;
+
+       spin_lock_irqsave(&sh_dmae_lock, flags);
+
+       dmaor = dmaor_read(shdev) & ~(DMAOR_NMIF | DMAOR_AE | DMAOR_DME);
+
+       if (shdev->pdata->chclr_present) {
+               int i;
+               for (i = 0; i < shdev->pdata->channel_num; i++) {
+                       struct sh_dmae_chan *sh_chan = shdev->chan[i];
+                       if (sh_chan)
+                               channel_clear(sh_chan);
+               }
+       }
+
+       dmaor_write(shdev, dmaor | shdev->pdata->dmaor_init);
+
+       dmaor = dmaor_read(shdev);
+
+       spin_unlock_irqrestore(&sh_dmae_lock, flags);
+
+       if (dmaor & (DMAOR_AE | DMAOR_NMIF)) {
+               dev_warn(shdev->shdma_dev.dma_dev.dev, "Can't initialize DMAOR.\n");
+               return -EIO;
+       }
+       if (shdev->pdata->dmaor_init & ~dmaor)
+               dev_warn(shdev->shdma_dev.dma_dev.dev,
+                        "DMAOR=0x%x hasn't latched the initial value 0x%x.\n",
+                        dmaor, shdev->pdata->dmaor_init);
+       return 0;
+}
+
+static bool dmae_is_busy(struct sh_dmae_chan *sh_chan)
+{
+       u32 chcr = chcr_read(sh_chan);
+
+       if ((chcr & (CHCR_DE | CHCR_TE)) == CHCR_DE)
+               return true; /* working */
+
+       return false; /* waiting */
+}
+
+static unsigned int calc_xmit_shift(struct sh_dmae_chan *sh_chan, u32 chcr)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       const struct sh_dmae_pdata *pdata = shdev->pdata;
+       int cnt = ((chcr & pdata->ts_low_mask) >> pdata->ts_low_shift) |
+               ((chcr & pdata->ts_high_mask) >> pdata->ts_high_shift);
+
+       if (cnt >= pdata->ts_shift_num)
+               cnt = 0;
+
+       return pdata->ts_shift[cnt];
+}
+
+static u32 log2size_to_chcr(struct sh_dmae_chan *sh_chan, int l2size)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       const struct sh_dmae_pdata *pdata = shdev->pdata;
+       int i;
+
+       for (i = 0; i < pdata->ts_shift_num; i++)
+               if (pdata->ts_shift[i] == l2size)
+                       break;
+
+       if (i == pdata->ts_shift_num)
+               i = 0;
+
+       return ((i << pdata->ts_low_shift) & pdata->ts_low_mask) |
+               ((i << pdata->ts_high_shift) & pdata->ts_high_mask);
+}
+
+static void dmae_set_reg(struct sh_dmae_chan *sh_chan, struct sh_dmae_regs *hw)
+{
+       sh_dmae_writel(sh_chan, hw->sar, SAR);
+       sh_dmae_writel(sh_chan, hw->dar, DAR);
+       sh_dmae_writel(sh_chan, hw->tcr >> sh_chan->xmit_shift, TCR);
+}
+
+static void dmae_start(struct sh_dmae_chan *sh_chan)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       u32 chcr = chcr_read(sh_chan);
+
+       if (shdev->pdata->needs_tend_set)
+               sh_dmae_writel(sh_chan, 0xFFFFFFFF, TEND);
+
+       chcr |= CHCR_DE | shdev->chcr_ie_bit;
+       chcr_write(sh_chan, chcr & ~CHCR_TE);
+}
+
+static void dmae_init(struct sh_dmae_chan *sh_chan)
+{
+       /*
+        * Default configuration for dual address memory-memory transfer.
+        * 0x400 represents auto-request.
+        */
+       u32 chcr = DM_INC | SM_INC | 0x400 | log2size_to_chcr(sh_chan,
+                                                  LOG2_DEFAULT_XFER_SIZE);
+       sh_chan->xmit_shift = calc_xmit_shift(sh_chan, chcr);
+       chcr_write(sh_chan, chcr);
+}
+
+static int dmae_set_chcr(struct sh_dmae_chan *sh_chan, u32 val)
+{
+       /* If DMA is active, cannot set CHCR. TODO: remove this superfluous check */
+       if (dmae_is_busy(sh_chan))
+               return -EBUSY;
+
+       sh_chan->xmit_shift = calc_xmit_shift(sh_chan, val);
+       chcr_write(sh_chan, val);
+
+       return 0;
+}
+
+static int dmae_set_dmars(struct sh_dmae_chan *sh_chan, u16 val)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       const struct sh_dmae_pdata *pdata = shdev->pdata;
+       const struct sh_dmae_channel *chan_pdata = &pdata->channel[sh_chan->shdma_chan.id];
+       void __iomem *addr = shdev->dmars;
+       unsigned int shift = chan_pdata->dmars_bit;
+
+       if (dmae_is_busy(sh_chan))
+               return -EBUSY;
+
+       if (pdata->no_dmars)
+               return 0;
+
+       /* in the case of a missing DMARS resource use first memory window */
+       if (!addr)
+               addr = shdev->chan_reg;
+       addr += chan_pdata->dmars;
+
+       __raw_writew((__raw_readw(addr) & (0xff00 >> shift)) | (val << shift),
+                    addr);
+
+       return 0;
+}
+
+static void sh_dmae_start_xfer(struct shdma_chan *schan,
+                              struct shdma_desc *sdesc)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+       struct sh_dmae_desc *sh_desc = container_of(sdesc,
+                                       struct sh_dmae_desc, shdma_desc);
+       dev_dbg(sh_chan->shdma_chan.dev, "Queue #%d to %d: %u@%x -> %x\n",
+               sdesc->async_tx.cookie, sh_chan->shdma_chan.id,
+               sh_desc->hw.tcr, sh_desc->hw.sar, sh_desc->hw.dar);
+       /* Get the ld start address from ld_queue */
+       dmae_set_reg(sh_chan, &sh_desc->hw);
+       dmae_start(sh_chan);
+}
+
+static bool sh_dmae_channel_busy(struct shdma_chan *schan)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+       return dmae_is_busy(sh_chan);
+}
+
+static void sh_dmae_setup_xfer(struct shdma_chan *schan,
+                              int slave_id)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+
+       if (slave_id >= 0) {
+               const struct sh_dmae_slave_config *cfg =
+                       sh_chan->config;
+
+               dmae_set_dmars(sh_chan, cfg->mid_rid);
+               dmae_set_chcr(sh_chan, cfg->chcr);
+       } else {
+               dmae_init(sh_chan);
+       }
+}
+
+/*
+ * Find a slave channel configuration from the contoller list by either a slave
+ * ID in the non-DT case, or by a MID/RID value in the DT case
+ */
+static const struct sh_dmae_slave_config *dmae_find_slave(
+       struct sh_dmae_chan *sh_chan, int match)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       const struct sh_dmae_pdata *pdata = shdev->pdata;
+       const struct sh_dmae_slave_config *cfg;
+       int i;
+
+       if (!sh_chan->shdma_chan.dev->of_node) {
+               if (match >= SH_DMA_SLAVE_NUMBER)
+                       return NULL;
+
+               for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+                       if (cfg->slave_id == match)
+                               return cfg;
+       } else {
+               for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+                       if (cfg->mid_rid == match) {
+                               sh_chan->shdma_chan.slave_id = i;
+                               return cfg;
+                       }
+       }
+
+       return NULL;
+}
+
+static int sh_dmae_set_slave(struct shdma_chan *schan,
+                            int slave_id, dma_addr_t slave_addr, bool try)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+       const struct sh_dmae_slave_config *cfg = dmae_find_slave(sh_chan, slave_id);
+       if (!cfg)
+               return -ENXIO;
+
+       if (!try) {
+               sh_chan->config = cfg;
+               sh_chan->slave_addr = slave_addr ? : cfg->addr;
+       }
+
+       return 0;
+}
+
+static void dmae_halt(struct sh_dmae_chan *sh_chan)
+{
+       struct sh_dmae_device *shdev = to_sh_dev(sh_chan);
+       u32 chcr = chcr_read(sh_chan);
+
+       chcr &= ~(CHCR_DE | CHCR_TE | shdev->chcr_ie_bit);
+       chcr_write(sh_chan, chcr);
+}
+
+static int sh_dmae_desc_setup(struct shdma_chan *schan,
+                             struct shdma_desc *sdesc,
+                             dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+       struct sh_dmae_desc *sh_desc = container_of(sdesc,
+                                       struct sh_dmae_desc, shdma_desc);
+
+       if (*len > schan->max_xfer_len)
+               *len = schan->max_xfer_len;
+
+       sh_desc->hw.sar = src;
+       sh_desc->hw.dar = dst;
+       sh_desc->hw.tcr = *len;
+
+       return 0;
+}
+
+static void sh_dmae_halt(struct shdma_chan *schan)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+       dmae_halt(sh_chan);
+}
+
+static bool sh_dmae_chan_irq(struct shdma_chan *schan, int irq)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+
+       if (!(chcr_read(sh_chan) & CHCR_TE))
+               return false;
+
+       /* DMA stop */
+       dmae_halt(sh_chan);
+
+       return true;
+}
+
+static size_t sh_dmae_get_partial(struct shdma_chan *schan,
+                                 struct shdma_desc *sdesc)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan, struct sh_dmae_chan,
+                                                   shdma_chan);
+       struct sh_dmae_desc *sh_desc = container_of(sdesc,
+                                       struct sh_dmae_desc, shdma_desc);
+       return sh_desc->hw.tcr -
+               (sh_dmae_readl(sh_chan, TCR) << sh_chan->xmit_shift);
+}
+
+/* Called from error IRQ or NMI */
+static bool sh_dmae_reset(struct sh_dmae_device *shdev)
+{
+       bool ret;
+
+       /* halt the dma controller */
+       sh_dmae_ctl_stop(shdev);
+
+       /* We cannot detect, which channel caused the error, have to reset all */
+       ret = shdma_reset(&shdev->shdma_dev);
+
+       sh_dmae_rst(shdev);
+
+       return ret;
+}
+
+static irqreturn_t sh_dmae_err(int irq, void *data)
+{
+       struct sh_dmae_device *shdev = data;
+
+       if (!(dmaor_read(shdev) & DMAOR_AE))
+               return IRQ_NONE;
+
+       sh_dmae_reset(shdev);
+       return IRQ_HANDLED;
+}
+
+static bool sh_dmae_desc_completed(struct shdma_chan *schan,
+                                  struct shdma_desc *sdesc)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan,
+                                       struct sh_dmae_chan, shdma_chan);
+       struct sh_dmae_desc *sh_desc = container_of(sdesc,
+                                       struct sh_dmae_desc, shdma_desc);
+       u32 sar_buf = sh_dmae_readl(sh_chan, SAR);
+       u32 dar_buf = sh_dmae_readl(sh_chan, DAR);
+
+       return  (sdesc->direction == DMA_DEV_TO_MEM &&
+                (sh_desc->hw.dar + sh_desc->hw.tcr) == dar_buf) ||
+               (sdesc->direction != DMA_DEV_TO_MEM &&
+                (sh_desc->hw.sar + sh_desc->hw.tcr) == sar_buf);
+}
+
+static bool sh_dmae_nmi_notify(struct sh_dmae_device *shdev)
+{
+       /* Fast path out if NMIF is not asserted for this controller */
+       if ((dmaor_read(shdev) & DMAOR_NMIF) == 0)
+               return false;
+
+       return sh_dmae_reset(shdev);
+}
+
+static int sh_dmae_nmi_handler(struct notifier_block *self,
+                              unsigned long cmd, void *data)
+{
+       struct sh_dmae_device *shdev;
+       int ret = NOTIFY_DONE;
+       bool triggered;
+
+       /*
+        * Only concern ourselves with NMI events.
+        *
+        * Normally we would check the die chain value, but as this needs
+        * to be architecture independent, check for NMI context instead.
+        */
+       if (!in_nmi())
+               return NOTIFY_DONE;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(shdev, &sh_dmae_devices, node) {
+               /*
+                * Only stop if one of the controllers has NMIF asserted,
+                * we do not want to interfere with regular address error
+                * handling or NMI events that don't concern the DMACs.
+                */
+               triggered = sh_dmae_nmi_notify(shdev);
+               if (triggered == true)
+                       ret = NOTIFY_OK;
+       }
+       rcu_read_unlock();
+
+       return ret;
+}
+
+static struct notifier_block sh_dmae_nmi_notifier __read_mostly = {
+       .notifier_call  = sh_dmae_nmi_handler,
+
+       /* Run before NMI debug handler and KGDB */
+       .priority       = 1,
+};
+
+static int sh_dmae_chan_probe(struct sh_dmae_device *shdev, int id,
+                                       int irq, unsigned long flags)
+{
+       const struct sh_dmae_channel *chan_pdata = &shdev->pdata->channel[id];
+       struct shdma_dev *sdev = &shdev->shdma_dev;
+       struct platform_device *pdev = to_platform_device(sdev->dma_dev.dev);
+       struct sh_dmae_chan *sh_chan;
+       struct shdma_chan *schan;
+       int err;
+
+       sh_chan = devm_kzalloc(sdev->dma_dev.dev, sizeof(struct sh_dmae_chan),
+                              GFP_KERNEL);
+       if (!sh_chan) {
+               dev_err(sdev->dma_dev.dev,
+                       "No free memory for allocating dma channels!\n");
+               return -ENOMEM;
+       }
+
+       schan = &sh_chan->shdma_chan;
+       schan->max_xfer_len = SH_DMA_TCR_MAX + 1;
+
+       shdma_chan_probe(sdev, schan, id);
+
+       sh_chan->base = shdev->chan_reg + chan_pdata->offset;
+
+       /* set up channel irq */
+       if (pdev->id >= 0)
+               snprintf(sh_chan->dev_id, sizeof(sh_chan->dev_id),
+                        "sh-dmae%d.%d", pdev->id, id);
+       else
+               snprintf(sh_chan->dev_id, sizeof(sh_chan->dev_id),
+                        "sh-dma%d", id);
+
+       err = shdma_request_irq(schan, irq, flags, sh_chan->dev_id);
+       if (err) {
+               dev_err(sdev->dma_dev.dev,
+                       "DMA channel %d request_irq error %d\n",
+                       id, err);
+               goto err_no_irq;
+       }
+
+       shdev->chan[id] = sh_chan;
+       return 0;
+
+err_no_irq:
+       /* remove from dmaengine device node */
+       shdma_chan_remove(schan);
+       return err;
+}
+
+static void sh_dmae_chan_remove(struct sh_dmae_device *shdev)
+{
+       struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
+       struct shdma_chan *schan;
+       int i;
+
+       shdma_for_each_chan(schan, &shdev->shdma_dev, i) {
+               BUG_ON(!schan);
+
+               shdma_chan_remove(schan);
+       }
+       dma_dev->chancnt = 0;
+}
+
+static void sh_dmae_shutdown(struct platform_device *pdev)
+{
+       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
+       sh_dmae_ctl_stop(shdev);
+}
+
+static int sh_dmae_runtime_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int sh_dmae_runtime_resume(struct device *dev)
+{
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+
+       return sh_dmae_rst(shdev);
+}
+
+#ifdef CONFIG_PM
+static int sh_dmae_suspend(struct device *dev)
+{
+       return 0;
+}
+
+static int sh_dmae_resume(struct device *dev)
+{
+       struct sh_dmae_device *shdev = dev_get_drvdata(dev);
+       int i, ret;
+
+       ret = sh_dmae_rst(shdev);
+       if (ret < 0)
+               dev_err(dev, "Failed to reset!\n");
+
+       for (i = 0; i < shdev->pdata->channel_num; i++) {
+               struct sh_dmae_chan *sh_chan = shdev->chan[i];
+
+               if (!sh_chan->shdma_chan.desc_num)
+                       continue;
+
+               if (sh_chan->shdma_chan.slave_id >= 0) {
+                       const struct sh_dmae_slave_config *cfg = sh_chan->config;
+                       dmae_set_dmars(sh_chan, cfg->mid_rid);
+                       dmae_set_chcr(sh_chan, cfg->chcr);
+               } else {
+                       dmae_init(sh_chan);
+               }
+       }
+
+       return 0;
+}
+#else
+#define sh_dmae_suspend NULL
+#define sh_dmae_resume NULL
+#endif
+
+const struct dev_pm_ops sh_dmae_pm = {
+       .suspend                = sh_dmae_suspend,
+       .resume                 = sh_dmae_resume,
+       .runtime_suspend        = sh_dmae_runtime_suspend,
+       .runtime_resume         = sh_dmae_runtime_resume,
+};
+
+static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan)
+{
+       struct sh_dmae_chan *sh_chan = container_of(schan,
+                                       struct sh_dmae_chan, shdma_chan);
+
+       /*
+        * Implicit BUG_ON(!sh_chan->config)
+        * This is an exclusive slave DMA operation, may only be called after a
+        * successful slave configuration.
+        */
+       return sh_chan->slave_addr;
+}
+
+static struct shdma_desc *sh_dmae_embedded_desc(void *buf, int i)
+{
+       return &((struct sh_dmae_desc *)buf)[i].shdma_desc;
+}
+
+static const struct shdma_ops sh_dmae_shdma_ops = {
+       .desc_completed = sh_dmae_desc_completed,
+       .halt_channel = sh_dmae_halt,
+       .channel_busy = sh_dmae_channel_busy,
+       .slave_addr = sh_dmae_slave_addr,
+       .desc_setup = sh_dmae_desc_setup,
+       .set_slave = sh_dmae_set_slave,
+       .setup_xfer = sh_dmae_setup_xfer,
+       .start_xfer = sh_dmae_start_xfer,
+       .embedded_desc = sh_dmae_embedded_desc,
+       .chan_irq = sh_dmae_chan_irq,
+       .get_partial = sh_dmae_get_partial,
+};
+
+static const struct of_device_id sh_dmae_of_match[] = {
+       {.compatible = "renesas,shdma-r8a73a4", .data = r8a73a4_shdma_devid,},
+       {}
+};
+MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
+
+static int sh_dmae_probe(struct platform_device *pdev)
+{
+       const struct sh_dmae_pdata *pdata;
+       unsigned long irqflags = IRQF_DISABLED,
+               chan_flag[SH_DMAE_MAX_CHANNELS] = {};
+       int errirq, chan_irq[SH_DMAE_MAX_CHANNELS];
+       int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
+       struct sh_dmae_device *shdev;
+       struct dma_device *dma_dev;
+       struct resource *chan, *dmars, *errirq_res, *chanirq_res;
+
+       if (pdev->dev.of_node)
+               pdata = of_match_device(sh_dmae_of_match, &pdev->dev)->data;
+       else
+               pdata = dev_get_platdata(&pdev->dev);
+
+       /* get platform data */
+       if (!pdata || !pdata->channel_num)
+               return -ENODEV;
+
+       chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       /* DMARS area is optional */
+       dmars = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       /*
+        * IRQ resources:
+        * 1. there always must be at least one IRQ IO-resource. On SH4 it is
+        *    the error IRQ, in which case it is the only IRQ in this resource:
+        *    start == end. If it is the only IRQ resource, all channels also
+        *    use the same IRQ.
+        * 2. DMA channel IRQ resources can be specified one per resource or in
+        *    ranges (start != end)
+        * 3. iff all events (channels and, optionally, error) on this
+        *    controller use the same IRQ, only one IRQ resource can be
+        *    specified, otherwise there must be one IRQ per channel, even if
+        *    some of them are equal
+        * 4. if all IRQs on this controller are equal or if some specific IRQs
+        *    specify IORESOURCE_IRQ_SHAREABLE in their resources, they will be
+        *    requested with the IRQF_SHARED flag
+        */
+       errirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!chan || !errirq_res)
+               return -ENODEV;
+
+       shdev = devm_kzalloc(&pdev->dev, sizeof(struct sh_dmae_device),
+                            GFP_KERNEL);
+       if (!shdev) {
+               dev_err(&pdev->dev, "Not enough memory\n");
+               return -ENOMEM;
+       }
+
+       dma_dev = &shdev->shdma_dev.dma_dev;
+
+       shdev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
+       if (IS_ERR(shdev->chan_reg))
+               return PTR_ERR(shdev->chan_reg);
+       if (dmars) {
+               shdev->dmars = devm_ioremap_resource(&pdev->dev, dmars);
+               if (IS_ERR(shdev->dmars))
+                       return PTR_ERR(shdev->dmars);
+       }
+
+       if (!pdata->slave_only)
+               dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
+       if (pdata->slave && pdata->slave_num)
+               dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+       /* Default transfer size of 32 bytes requires 32-byte alignment */
+       dma_dev->copy_align = LOG2_DEFAULT_XFER_SIZE;
+
+       shdev->shdma_dev.ops = &sh_dmae_shdma_ops;
+       shdev->shdma_dev.desc_size = sizeof(struct sh_dmae_desc);
+       err = shdma_init(&pdev->dev, &shdev->shdma_dev,
+                             pdata->channel_num);
+       if (err < 0)
+               goto eshdma;
+
+       /* platform data */
+       shdev->pdata = pdata;
+
+       if (pdata->chcr_offset)
+               shdev->chcr_offset = pdata->chcr_offset;
+       else
+               shdev->chcr_offset = CHCR;
+
+       if (pdata->chcr_ie_bit)
+               shdev->chcr_ie_bit = pdata->chcr_ie_bit;
+       else
+               shdev->chcr_ie_bit = CHCR_IE;
+
+       platform_set_drvdata(pdev, shdev);
+
+       pm_runtime_enable(&pdev->dev);
+       err = pm_runtime_get_sync(&pdev->dev);
+       if (err < 0)
+               dev_err(&pdev->dev, "%s(): GET = %d\n", __func__, err);
+
+       spin_lock_irq(&sh_dmae_lock);
+       list_add_tail_rcu(&shdev->node, &sh_dmae_devices);
+       spin_unlock_irq(&sh_dmae_lock);
+
+       /* reset dma controller - only needed as a test */
+       err = sh_dmae_rst(shdev);
+       if (err)
+               goto rst_err;
+
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
+       chanirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
+
+       if (!chanirq_res)
+               chanirq_res = errirq_res;
+       else
+               irqres++;
+
+       if (chanirq_res == errirq_res ||
+           (errirq_res->flags & IORESOURCE_BITS) == IORESOURCE_IRQ_SHAREABLE)
+               irqflags = IRQF_SHARED;
+
+       errirq = errirq_res->start;
+
+       err = devm_request_irq(&pdev->dev, errirq, sh_dmae_err, irqflags,
+                              "DMAC Address Error", shdev);
+       if (err) {
+               dev_err(&pdev->dev,
+                       "DMA failed requesting irq #%d, error %d\n",
+                       errirq, err);
+               goto eirq_err;
+       }
+
+#else
+       chanirq_res = errirq_res;
+#endif /* CONFIG_CPU_SH4 || CONFIG_ARCH_SHMOBILE */
+
+       if (chanirq_res->start == chanirq_res->end &&
+           !platform_get_resource(pdev, IORESOURCE_IRQ, 1)) {
+               /* Special case - all multiplexed */
+               for (; irq_cnt < pdata->channel_num; irq_cnt++) {
+                       if (irq_cnt < SH_DMAE_MAX_CHANNELS) {
+                               chan_irq[irq_cnt] = chanirq_res->start;
+                               chan_flag[irq_cnt] = IRQF_SHARED;
+                       } else {
+                               irq_cap = 1;
+                               break;
+                       }
+               }
+       } else {
+               do {
+                       for (i = chanirq_res->start; i <= chanirq_res->end; i++) {
+                               if (irq_cnt >= SH_DMAE_MAX_CHANNELS) {
+                                       irq_cap = 1;
+                                       break;
+                               }
+
+                               if ((errirq_res->flags & IORESOURCE_BITS) ==
+                                   IORESOURCE_IRQ_SHAREABLE)
+                                       chan_flag[irq_cnt] = IRQF_SHARED;
+                               else
+                                       chan_flag[irq_cnt] = IRQF_DISABLED;
+                               dev_dbg(&pdev->dev,
+                                       "Found IRQ %d for channel %d\n",
+                                       i, irq_cnt);
+                               chan_irq[irq_cnt++] = i;
+                       }
+
+                       if (irq_cnt >= SH_DMAE_MAX_CHANNELS)
+                               break;
+
+                       chanirq_res = platform_get_resource(pdev,
+                                               IORESOURCE_IRQ, ++irqres);
+               } while (irq_cnt < pdata->channel_num && chanirq_res);
+       }
+
+       /* Create DMA Channel */
+       for (i = 0; i < irq_cnt; i++) {
+               err = sh_dmae_chan_probe(shdev, i, chan_irq[i], chan_flag[i]);
+               if (err)
+                       goto chan_probe_err;
+       }
+
+       if (irq_cap)
+               dev_notice(&pdev->dev, "Attempting to register %d DMA "
+                          "channels when a maximum of %d are supported.\n",
+                          pdata->channel_num, SH_DMAE_MAX_CHANNELS);
+
+       pm_runtime_put(&pdev->dev);
+
+       err = dma_async_device_register(&shdev->shdma_dev.dma_dev);
+       if (err < 0)
+               goto edmadevreg;
+
+       return err;
+
+edmadevreg:
+       pm_runtime_get(&pdev->dev);
+
+chan_probe_err:
+       sh_dmae_chan_remove(shdev);
+
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE)
+eirq_err:
+#endif
+rst_err:
+       spin_lock_irq(&sh_dmae_lock);
+       list_del_rcu(&shdev->node);
+       spin_unlock_irq(&sh_dmae_lock);
+
+       pm_runtime_put(&pdev->dev);
+       pm_runtime_disable(&pdev->dev);
+
+       shdma_cleanup(&shdev->shdma_dev);
+eshdma:
+       synchronize_rcu();
+
+       return err;
+}
+
+static int sh_dmae_remove(struct platform_device *pdev)
+{
+       struct sh_dmae_device *shdev = platform_get_drvdata(pdev);
+       struct dma_device *dma_dev = &shdev->shdma_dev.dma_dev;
+
+       dma_async_device_unregister(dma_dev);
+
+       spin_lock_irq(&sh_dmae_lock);
+       list_del_rcu(&shdev->node);
+       spin_unlock_irq(&sh_dmae_lock);
+
+       pm_runtime_disable(&pdev->dev);
+
+       sh_dmae_chan_remove(shdev);
+       shdma_cleanup(&shdev->shdma_dev);
+
+       synchronize_rcu();
+
+       return 0;
+}
+
+static struct platform_driver sh_dmae_driver = {
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .pm     = &sh_dmae_pm,
+               .name   = SH_DMAE_DRV_NAME,
+               .of_match_table = sh_dmae_of_match,
+       },
+       .remove         = sh_dmae_remove,
+       .shutdown       = sh_dmae_shutdown,
+};
+
+static int __init sh_dmae_init(void)
+{
+       /* Wire up NMI handling */
+       int err = register_die_notifier(&sh_dmae_nmi_notifier);
+       if (err)
+               return err;
+
+       return platform_driver_probe(&sh_dmae_driver, sh_dmae_probe);
+}
+module_init(sh_dmae_init);
+
+static void __exit sh_dmae_exit(void)
+{
+       platform_driver_unregister(&sh_dmae_driver);
+
+       unregister_die_notifier(&sh_dmae_nmi_notifier);
+}
+module_exit(sh_dmae_exit);
+
+MODULE_AUTHOR("Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>");
+MODULE_DESCRIPTION("Renesas SH DMA Engine driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" SH_DMAE_DRV_NAME);
index e7c94bbddb536b8e44822e684e7301487bb9ee94..c7e9cdff0708125d885e301324f4f5d52c5269d5 100644 (file)
@@ -150,7 +150,8 @@ static const struct sudmac_slave_config *sudmac_find_slave(
        return NULL;
 }
 
-static int sudmac_set_slave(struct shdma_chan *schan, int slave_id, bool try)
+static int sudmac_set_slave(struct shdma_chan *schan, int slave_id,
+                           dma_addr_t slave_addr, bool try)
 {
        struct sudmac_chan *sc = to_chan(schan);
        const struct sudmac_slave_config *cfg = sudmac_find_slave(sc, slave_id);
@@ -298,11 +299,8 @@ static void sudmac_chan_remove(struct sudmac_device *su_dev)
        int i;
 
        shdma_for_each_chan(schan, &su_dev->shdma_dev, i) {
-               struct sudmac_chan *sc = to_chan(schan);
-
                BUG_ON(!schan);
 
-               shdma_free_irq(&sc->shdma_chan);
                shdma_chan_remove(schan);
        }
        dma_dev->chancnt = 0;
@@ -335,7 +333,7 @@ static const struct shdma_ops sudmac_shdma_ops = {
 
 static int sudmac_probe(struct platform_device *pdev)
 {
-       struct sudmac_pdata *pdata = pdev->dev.platform_data;
+       struct sudmac_pdata *pdata = dev_get_platdata(&pdev->dev);
        int err, i;
        struct sudmac_device *su_dev;
        struct dma_device *dma_dev;
@@ -345,9 +343,8 @@ static int sudmac_probe(struct platform_device *pdev)
        if (!pdata)
                return -ENODEV;
 
-       chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!chan || !irq_res)
+       if (!irq_res)
                return -ENODEV;
 
        err = -ENOMEM;
@@ -360,9 +357,10 @@ static int sudmac_probe(struct platform_device *pdev)
 
        dma_dev = &su_dev->shdma_dev.dma_dev;
 
-       su_dev->chan_reg = devm_request_and_ioremap(&pdev->dev, chan);
-       if (!su_dev->chan_reg)
-               return err;
+       chan = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       su_dev->chan_reg = devm_ioremap_resource(&pdev->dev, chan);
+       if (IS_ERR(su_dev->chan_reg))
+               return PTR_ERR(su_dev->chan_reg);
 
        dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
 
@@ -373,7 +371,7 @@ static int sudmac_probe(struct platform_device *pdev)
                return err;
 
        /* platform data */
-       su_dev->pdata = pdev->dev.platform_data;
+       su_dev->pdata = dev_get_platdata(&pdev->dev);
 
        platform_set_drvdata(pdev, su_dev);
 
@@ -393,7 +391,6 @@ static int sudmac_probe(struct platform_device *pdev)
 chan_probe_err:
        sudmac_chan_remove(su_dev);
 
-       platform_set_drvdata(pdev, NULL);
        shdma_cleanup(&su_dev->shdma_dev);
 
        return err;
@@ -407,7 +404,6 @@ static int sudmac_remove(struct platform_device *pdev)
        dma_async_device_unregister(dma_dev);
        sudmac_chan_remove(su_dev);
        shdma_cleanup(&su_dev->shdma_dev);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 716b23e4f327e13d96be6b046bc6926f8988b3dd..6aec3ad814d37f16b69c51f44347d9826e411885 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
+#include <linux/pm_runtime.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/slab.h>
@@ -73,6 +74,11 @@ struct sirfsoc_dma_chan {
        int                             mode;
 };
 
+struct sirfsoc_dma_regs {
+       u32                             ctrl[SIRFSOC_DMA_CHANNELS];
+       u32                             interrupt_en;
+};
+
 struct sirfsoc_dma {
        struct dma_device               dma;
        struct tasklet_struct           tasklet;
@@ -81,10 +87,13 @@ struct sirfsoc_dma {
        int                             irq;
        struct clk                      *clk;
        bool                            is_marco;
+       struct sirfsoc_dma_regs         regs_save;
 };
 
 #define DRV_NAME       "sirfsoc_dma"
 
+static int sirfsoc_dma_runtime_suspend(struct device *dev);
+
 /* Convert struct dma_chan to struct sirfsoc_dma_chan */
 static inline
 struct sirfsoc_dma_chan *dma_chan_to_sirfsoc_dma_chan(struct dma_chan *c)
@@ -393,6 +402,8 @@ static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
        LIST_HEAD(descs);
        int i;
 
+       pm_runtime_get_sync(sdma->dma.dev);
+
        /* Alloc descriptors for this channel */
        for (i = 0; i < SIRFSOC_DMA_DESCRIPTORS; i++) {
                sdesc = kzalloc(sizeof(*sdesc), GFP_KERNEL);
@@ -425,6 +436,7 @@ static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
 static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
 {
        struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
+       struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(chan);
        struct sirfsoc_dma_desc *sdesc, *tmp;
        unsigned long flags;
        LIST_HEAD(descs);
@@ -445,6 +457,8 @@ static void sirfsoc_dma_free_chan_resources(struct dma_chan *chan)
        /* Free descriptors */
        list_for_each_entry_safe(sdesc, tmp, &descs, node)
                kfree(sdesc);
+
+       pm_runtime_put(sdma->dma.dev);
 }
 
 /* Send pending descriptor to hardware */
@@ -595,7 +609,7 @@ sirfsoc_dma_prep_cyclic(struct dma_chan *chan, dma_addr_t addr,
        spin_unlock_irqrestore(&schan->lock, iflags);
 
        if (!sdesc)
-               return 0;
+               return NULL;
 
        /* Place descriptor in prepared list */
        spin_lock_irqsave(&schan->lock, iflags);
@@ -723,14 +737,14 @@ static int sirfsoc_dma_probe(struct platform_device *op)
 
        tasklet_init(&sdma->tasklet, sirfsoc_dma_tasklet, (unsigned long)sdma);
 
-       clk_prepare_enable(sdma->clk);
-
        /* Register DMA engine */
        dev_set_drvdata(dev, sdma);
+
        ret = dma_async_device_register(dma);
        if (ret)
                goto free_irq;
 
+       pm_runtime_enable(&op->dev);
        dev_info(dev, "initialized SIRFSOC DMAC driver\n");
 
        return 0;
@@ -747,13 +761,124 @@ static int sirfsoc_dma_remove(struct platform_device *op)
        struct device *dev = &op->dev;
        struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
 
-       clk_disable_unprepare(sdma->clk);
        dma_async_device_unregister(&sdma->dma);
        free_irq(sdma->irq, sdma);
        irq_dispose_mapping(sdma->irq);
+       pm_runtime_disable(&op->dev);
+       if (!pm_runtime_status_suspended(&op->dev))
+               sirfsoc_dma_runtime_suspend(&op->dev);
+
+       return 0;
+}
+
+static int sirfsoc_dma_runtime_suspend(struct device *dev)
+{
+       struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(sdma->clk);
+       return 0;
+}
+
+static int sirfsoc_dma_runtime_resume(struct device *dev)
+{
+       struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(sdma->clk);
+       if (ret < 0) {
+               dev_err(dev, "clk_enable failed: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int sirfsoc_dma_pm_suspend(struct device *dev)
+{
+       struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+       struct sirfsoc_dma_regs *save = &sdma->regs_save;
+       struct sirfsoc_dma_desc *sdesc;
+       struct sirfsoc_dma_chan *schan;
+       int ch;
+       int ret;
+
+       /*
+        * if we were runtime-suspended before, resume to enable clock
+        * before accessing register
+        */
+       if (pm_runtime_status_suspended(dev)) {
+               ret = sirfsoc_dma_runtime_resume(dev);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /*
+        * DMA controller will lose all registers while suspending
+        * so we need to save registers for active channels
+        */
+       for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
+               schan = &sdma->channels[ch];
+               if (list_empty(&schan->active))
+                       continue;
+               sdesc = list_first_entry(&schan->active,
+                       struct sirfsoc_dma_desc,
+                       node);
+               save->ctrl[ch] = readl_relaxed(sdma->base +
+                       ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
+       }
+       save->interrupt_en = readl_relaxed(sdma->base + SIRFSOC_DMA_INT_EN);
+
+       /* Disable clock */
+       sirfsoc_dma_runtime_suspend(dev);
+
+       return 0;
+}
+
+static int sirfsoc_dma_pm_resume(struct device *dev)
+{
+       struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
+       struct sirfsoc_dma_regs *save = &sdma->regs_save;
+       struct sirfsoc_dma_desc *sdesc;
+       struct sirfsoc_dma_chan *schan;
+       int ch;
+       int ret;
+
+       /* Enable clock before accessing register */
+       ret = sirfsoc_dma_runtime_resume(dev);
+       if (ret < 0)
+               return ret;
+
+       writel_relaxed(save->interrupt_en, sdma->base + SIRFSOC_DMA_INT_EN);
+       for (ch = 0; ch < SIRFSOC_DMA_CHANNELS; ch++) {
+               schan = &sdma->channels[ch];
+               if (list_empty(&schan->active))
+                       continue;
+               sdesc = list_first_entry(&schan->active,
+                       struct sirfsoc_dma_desc,
+                       node);
+               writel_relaxed(sdesc->width,
+                       sdma->base + SIRFSOC_DMA_WIDTH_0 + ch * 4);
+               writel_relaxed(sdesc->xlen,
+                       sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_XLEN);
+               writel_relaxed(sdesc->ylen,
+                       sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_YLEN);
+               writel_relaxed(save->ctrl[ch],
+                       sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_CTRL);
+               writel_relaxed(sdesc->addr >> 2,
+                       sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_ADDR);
+       }
+
+       /* if we were runtime-suspended before, suspend again */
+       if (pm_runtime_status_suspended(dev))
+               sirfsoc_dma_runtime_suspend(dev);
+
        return 0;
 }
 
+static const struct dev_pm_ops sirfsoc_dma_pm_ops = {
+       SET_RUNTIME_PM_OPS(sirfsoc_dma_runtime_suspend, sirfsoc_dma_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(sirfsoc_dma_pm_suspend, sirfsoc_dma_pm_resume)
+};
+
 static struct of_device_id sirfsoc_dma_match[] = {
        { .compatible = "sirf,prima2-dmac", },
        { .compatible = "sirf,marco-dmac", },
@@ -766,6 +891,7 @@ static struct platform_driver sirfsoc_dma_driver = {
        .driver = {
                .name = DRV_NAME,
                .owner = THIS_MODULE,
+               .pm = &sirfsoc_dma_pm_ops,
                .of_match_table = sirfsoc_dma_match,
        },
 };
index 5ab5880d5c9041203bdb38a4d242c888777e8f2d..82d2b97ad942f96f2064c0ac58b11141fb85b54c 100644 (file)
@@ -2591,6 +2591,9 @@ dma40_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
        int i;
 
        sg = kcalloc(periods + 1, sizeof(struct scatterlist), GFP_NOWAIT);
+       if (!sg)
+               return NULL;
+
        for (i = 0; i < periods; i++) {
                sg_dma_address(&sg[i]) = dma_addr;
                sg_dma_len(&sg[i]) = period_len;
@@ -3139,7 +3142,7 @@ static int __init d40_phy_res_init(struct d40_base *base)
 
 static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
 {
-       struct stedma40_platform_data *plat_data = pdev->dev.platform_data;
+       struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev);
        struct clk *clk = NULL;
        void __iomem *virtbase = NULL;
        struct resource *res = NULL;
@@ -3226,8 +3229,8 @@ static struct d40_base * __init d40_hw_detect_init(struct platform_device *pdev)
        num_log_chans = num_phy_chans * D40_MAX_LOG_CHAN_PER_PHY;
 
        dev_info(&pdev->dev,
-                "hardware rev: %d @ 0x%x with %d physical and %d logical channels\n",
-                rev, res->start, num_phy_chans, num_log_chans);
+                "hardware rev: %d @ %pa with %d physical and %d logical channels\n",
+                rev, &res->start, num_phy_chans, num_log_chans);
 
        base = kzalloc(ALIGN(sizeof(struct d40_base), 4) +
                       (num_phy_chans + num_log_chans + num_memcpy_chans) *
@@ -3485,7 +3488,7 @@ static int __init d40_of_probe(struct platform_device *pdev,
 {
        struct stedma40_platform_data *pdata;
        int num_phy = 0, num_memcpy = 0, num_disabled = 0;
-       const const __be32 *list;
+       const __be32 *list;
 
        pdata = devm_kzalloc(&pdev->dev,
                             sizeof(struct stedma40_platform_data),
@@ -3516,7 +3519,7 @@ static int __init d40_of_probe(struct platform_device *pdev,
        list = of_get_property(np, "disabled-channels", &num_disabled);
        num_disabled /= sizeof(*list);
 
-       if (num_disabled > STEDMA40_MAX_PHYS || num_disabled < 0) {
+       if (num_disabled >= STEDMA40_MAX_PHYS || num_disabled < 0) {
                d40_err(&pdev->dev,
                        "Invalid number of disabled channels specified (%d)\n",
                        num_disabled);
@@ -3535,7 +3538,7 @@ static int __init d40_of_probe(struct platform_device *pdev,
 
 static int __init d40_probe(struct platform_device *pdev)
 {
-       struct stedma40_platform_data *plat_data = pdev->dev.platform_data;
+       struct stedma40_platform_data *plat_data = dev_get_platdata(&pdev->dev);
        struct device_node *np = pdev->dev.of_node;
        int ret = -ENOENT;
        struct d40_base *base = NULL;
@@ -3579,9 +3582,7 @@ static int __init d40_probe(struct platform_device *pdev)
        if (request_mem_region(res->start, resource_size(res),
                               D40_NAME " I/O lcpa") == NULL) {
                ret = -EBUSY;
-               d40_err(&pdev->dev,
-                       "Failed to request LCPA region 0x%x-0x%x\n",
-                       res->start, res->end);
+               d40_err(&pdev->dev, "Failed to request LCPA region %pR\n", res);
                goto failure;
        }
 
@@ -3589,8 +3590,8 @@ static int __init d40_probe(struct platform_device *pdev)
        val = readl(base->virtbase + D40_DREG_LCPA);
        if (res->start != val && val != 0) {
                dev_warn(&pdev->dev,
-                        "[%s] Mismatch LCPA dma 0x%x, def 0x%x\n",
-                        __func__, val, res->start);
+                        "[%s] Mismatch LCPA dma 0x%x, def %pa\n",
+                        __func__, val, &res->start);
        } else
                writel(res->start, base->virtbase + D40_DREG_LCPA);
 
index f137914d7b1650d285ee2c294ae941c12ac124fc..5d4986e5f5fa6b21423084b688bd0a8afbba0c2e 100644 (file)
@@ -767,13 +767,11 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
        unsigned long flags;
        unsigned int residual;
 
-       spin_lock_irqsave(&tdc->lock, flags);
-
        ret = dma_cookie_status(dc, cookie, txstate);
-       if (ret == DMA_SUCCESS) {
-               spin_unlock_irqrestore(&tdc->lock, flags);
+       if (ret == DMA_SUCCESS)
                return ret;
-       }
+
+       spin_lock_irqsave(&tdc->lock, flags);
 
        /* Check on wait_ack desc status */
        list_for_each_entry(dma_desc, &tdc->free_dma_desc, node) {
index 0ef43c136aa7dbbd30c65b9b1ebb43984b1baea0..28af214fce049db85fc02fb903a748fdbef6e0a1 100644 (file)
@@ -669,7 +669,7 @@ static irqreturn_t td_irq(int irq, void *devid)
 
 static int td_probe(struct platform_device *pdev)
 {
-       struct timb_dma_platform_data *pdata = pdev->dev.platform_data;
+       struct timb_dma_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct timb_dma *td;
        struct resource *iomem;
        int irq;
index a59fb4841d4c18283eae911c076c43dc042f0748..71e8e775189e0df5568d474ea00157a2675f9260 100644 (file)
@@ -962,15 +962,14 @@ txx9dmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        enum dma_status ret;
 
        ret = dma_cookie_status(chan, cookie, txstate);
-       if (ret != DMA_SUCCESS) {
-               spin_lock_bh(&dc->lock);
-               txx9dmac_scan_descriptors(dc);
-               spin_unlock_bh(&dc->lock);
+       if (ret == DMA_SUCCESS)
+               return DMA_SUCCESS;
 
-               ret = dma_cookie_status(chan, cookie, txstate);
-       }
+       spin_lock_bh(&dc->lock);
+       txx9dmac_scan_descriptors(dc);
+       spin_unlock_bh(&dc->lock);
 
-       return ret;
+       return dma_cookie_status(chan, cookie, txstate);
 }
 
 static void txx9dmac_chain_dynamic(struct txx9dmac_chan *dc,
@@ -1118,9 +1117,10 @@ static void txx9dmac_off(struct txx9dmac_dev *ddev)
 
 static int __init txx9dmac_chan_probe(struct platform_device *pdev)
 {
-       struct txx9dmac_chan_platform_data *cpdata = pdev->dev.platform_data;
+       struct txx9dmac_chan_platform_data *cpdata =
+                       dev_get_platdata(&pdev->dev);
        struct platform_device *dmac_dev = cpdata->dmac_dev;
-       struct txx9dmac_platform_data *pdata = dmac_dev->dev.platform_data;
+       struct txx9dmac_platform_data *pdata = dev_get_platdata(&dmac_dev->dev);
        struct txx9dmac_chan *dc;
        int err;
        int ch = pdev->id % TXX9_DMA_MAX_NR_CHANNELS;
@@ -1203,7 +1203,7 @@ static int txx9dmac_chan_remove(struct platform_device *pdev)
 
 static int __init txx9dmac_probe(struct platform_device *pdev)
 {
-       struct txx9dmac_platform_data *pdata = pdev->dev.platform_data;
+       struct txx9dmac_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct resource *io;
        struct txx9dmac_dev *ddev;
        u32 mcr;
@@ -1282,7 +1282,7 @@ static int txx9dmac_resume_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct txx9dmac_dev *ddev = platform_get_drvdata(pdev);
-       struct txx9dmac_platform_data *pdata = pdev->dev.platform_data;
+       struct txx9dmac_platform_data *pdata = dev_get_platdata(&pdev->dev);
        u32 mcr;
 
        mcr = TXX9_DMA_MCR_MSTEN | MCR_LE;
index ac1b43a0428531273c4fdaefd56a0b83f1545ce2..d7d5c8af92b9754fa79aa632c69d9ffc1fb27420 100644 (file)
@@ -486,7 +486,7 @@ static int ioctl_get_info(struct client *client, union ioctl_arg *arg)
 static int add_client_resource(struct client *client,
                               struct client_resource *resource, gfp_t gfp_mask)
 {
-       bool preload = gfp_mask & __GFP_WAIT;
+       bool preload = !!(gfp_mask & __GFP_WAIT);
        unsigned long flags;
        int ret;
 
index 28a94c7ec6e5bad3af57ed258e0615266ab7b135..e5af0e3a26ec9345a9a775e77ab76b78db94ba25 100644 (file)
@@ -1262,8 +1262,7 @@ static int __init fw_core_init(void)
 {
        int ret;
 
-       fw_workqueue = alloc_workqueue("firewire",
-                                      WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+       fw_workqueue = alloc_workqueue("firewire", WQ_MEM_RECLAIM, 0);
        if (!fw_workqueue)
                return -ENOMEM;
 
index afb701ec90cabd50ceb03b1298beba38e97717b4..6aa8a86cb83b33223aa7e2d26db2308aa440bdd8 100644 (file)
@@ -235,13 +235,15 @@ struct fw_ohci {
        dma_addr_t next_config_rom_bus;
        __be32     next_header;
 
-       __le32    *self_id_cpu;
+       __le32    *self_id;
        dma_addr_t self_id_bus;
        struct work_struct bus_reset_work;
 
        u32 self_id_buffer[512];
 };
 
+static struct workqueue_struct *selfid_workqueue;
+
 static inline struct fw_ohci *fw_ohci(struct fw_card *card)
 {
        return container_of(card, struct fw_ohci, card);
@@ -271,6 +273,7 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
 
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
+#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
 #define PCI_DEVICE_ID_AGERE_FW643      0x5901
 #define PCI_DEVICE_ID_CREATIVE_SB1394  0x4001
 #define PCI_DEVICE_ID_JMICRON_JMB38X_FW        0x2380
@@ -278,17 +281,16 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
 #define PCI_DEVICE_ID_TI_TSB12LV26     0x8020
 #define PCI_DEVICE_ID_TI_TSB82AA2      0x8025
 #define PCI_DEVICE_ID_VIA_VT630X       0x3044
-#define PCI_VENDOR_ID_PINNACLE_SYSTEMS 0x11bd
 #define PCI_REV_ID_VIA_VT6306          0x46
 
-#define QUIRK_CYCLE_TIMER              1
-#define QUIRK_RESET_PACKET             2
-#define QUIRK_BE_HEADERS               4
-#define QUIRK_NO_1394A                 8
-#define QUIRK_NO_MSI                   16
-#define QUIRK_TI_SLLZ059               32
-#define QUIRK_IR_WAKE                  64
-#define QUIRK_PHY_LCTRL_TIMEOUT                128
+#define QUIRK_CYCLE_TIMER              0x1
+#define QUIRK_RESET_PACKET             0x2
+#define QUIRK_BE_HEADERS               0x4
+#define QUIRK_NO_1394A                 0x8
+#define QUIRK_NO_MSI                   0x10
+#define QUIRK_TI_SLLZ059               0x20
+#define QUIRK_IR_WAKE                  0x40
+#define QUIRK_PHY_LCTRL_TIMEOUT                0x80
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
@@ -1929,12 +1931,12 @@ static void bus_reset_work(struct work_struct *work)
                return;
        }
 
-       generation = (cond_le32_to_cpu(ohci->self_id_cpu[0]) >> 16) & 0xff;
+       generation = (cond_le32_to_cpu(ohci->self_id[0]) >> 16) & 0xff;
        rmb();
 
        for (i = 1, j = 0; j < self_id_count; i += 2, j++) {
-               u32 id  = cond_le32_to_cpu(ohci->self_id_cpu[i]);
-               u32 id2 = cond_le32_to_cpu(ohci->self_id_cpu[i + 1]);
+               u32 id  = cond_le32_to_cpu(ohci->self_id[i]);
+               u32 id2 = cond_le32_to_cpu(ohci->self_id[i + 1]);
 
                if (id != ~id2) {
                        /*
@@ -2087,7 +2089,7 @@ static irqreturn_t irq_handler(int irq, void *data)
        log_irqs(ohci, event);
 
        if (event & OHCI1394_selfIDComplete)
-               queue_work(fw_workqueue, &ohci->bus_reset_work);
+               queue_work(selfid_workqueue, &ohci->bus_reset_work);
 
        if (event & OHCI1394_RQPkt)
                tasklet_schedule(&ohci->ar_request_ctx.tasklet);
@@ -3692,7 +3694,7 @@ static int pci_probe(struct pci_dev *dev,
                goto fail_contexts;
        }
 
-       ohci->self_id_cpu = ohci->misc_buffer     + PAGE_SIZE/2;
+       ohci->self_id     = ohci->misc_buffer     + PAGE_SIZE/2;
        ohci->self_id_bus = ohci->misc_buffer_bus + PAGE_SIZE/2;
 
        bus_options = reg_read(ohci, OHCI1394_BusOptions);
@@ -3870,7 +3872,23 @@ static struct pci_driver fw_ohci_pci_driver = {
 #endif
 };
 
-module_pci_driver(fw_ohci_pci_driver);
+static int __init fw_ohci_init(void)
+{
+       selfid_workqueue = alloc_workqueue(KBUILD_MODNAME, WQ_MEM_RECLAIM, 0);
+       if (!selfid_workqueue)
+               return -ENOMEM;
+
+       return pci_register_driver(&fw_ohci_pci_driver);
+}
+
+static void __exit fw_ohci_cleanup(void)
+{
+       pci_unregister_driver(&fw_ohci_pci_driver);
+       destroy_workqueue(selfid_workqueue);
+}
+
+module_init(fw_ohci_init);
+module_exit(fw_ohci_cleanup);
 
 MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
 MODULE_DESCRIPTION("Driver for PCI OHCI IEEE1394 controllers");
index 232fa8fce26a5d0ffddf5fdc3ee01ed3c63eed7f..fa0affb699b42f51a070fb336d2f66df38b9dce6 100644 (file)
@@ -14,7 +14,7 @@
  * of and an antecedent to, SMBIOS, which stands for System
  * Management BIOS.  See further: http://www.dmtf.org/standards
  */
-static char dmi_empty_string[] = "        ";
+static const char dmi_empty_string[] = "        ";
 
 static u16 __initdata dmi_ver;
 /*
@@ -49,7 +49,7 @@ static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s)
        return "";
 }
 
-static char * __init dmi_string(const struct dmi_header *dm, u8 s)
+static const char * __init dmi_string(const struct dmi_header *dm, u8 s)
 {
        const char *bp = dmi_string_nosave(dm, s);
        char *str;
@@ -62,8 +62,6 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
        str = dmi_alloc(len);
        if (str != NULL)
                strcpy(str, bp);
-       else
-               printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len);
 
        return str;
 }
@@ -133,17 +131,18 @@ static int __init dmi_checksum(const u8 *buf, u8 len)
        return sum == 0;
 }
 
-static char *dmi_ident[DMI_STRING_MAX];
+static const char *dmi_ident[DMI_STRING_MAX];
 static LIST_HEAD(dmi_devices);
 int dmi_available;
 
 /*
  *     Save a DMI string
  */
-static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string)
+static void __init dmi_save_ident(const struct dmi_header *dm, int slot,
+               int string)
 {
-       const char *d = (const char*) dm;
-       char *p;
+       const char *d = (const char *) dm;
+       const char *p;
 
        if (dmi_ident[slot])
                return;
@@ -155,9 +154,10 @@ static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int str
        dmi_ident[slot] = p;
 }
 
-static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_uuid(const struct dmi_header *dm, int slot,
+               int index)
 {
-       const u8 *d = (u8*) dm + index;
+       const u8 *d = (u8 *) dm + index;
        char *s;
        int is_ff = 1, is_00 = 1, i;
 
@@ -188,12 +188,13 @@ static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int inde
        else
                sprintf(s, "%pUB", d);
 
-        dmi_ident[slot] = s;
+       dmi_ident[slot] = s;
 }
 
-static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index)
+static void __init dmi_save_type(const struct dmi_header *dm, int slot,
+               int index)
 {
-       const u8 *d = (u8*) dm + index;
+       const u8 *d = (u8 *) dm + index;
        char *s;
 
        if (dmi_ident[slot])
@@ -216,10 +217,8 @@ static void __init dmi_save_one_device(int type, const char *name)
                return;
 
        dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1);
-       if (!dev) {
-               printk(KERN_ERR "dmi_save_one_device: out of memory.\n");
+       if (!dev)
                return;
-       }
 
        dev->type = type;
        strcpy((char *)(dev + 1), name);
@@ -249,17 +248,14 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
        struct dmi_device *dev;
 
        for (i = 1; i <= count; i++) {
-               char *devname = dmi_string(dm, i);
+               const char *devname = dmi_string(dm, i);
 
                if (devname == dmi_empty_string)
                        continue;
 
                dev = dmi_alloc(sizeof(*dev));
-               if (!dev) {
-                       printk(KERN_ERR
-                          "dmi_save_oem_strings_devices: out of memory.\n");
+               if (!dev)
                        break;
-               }
 
                dev->type = DMI_DEV_TYPE_OEM_STRING;
                dev->name = devname;
@@ -272,21 +268,17 @@ static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm)
 static void __init dmi_save_ipmi_device(const struct dmi_header *dm)
 {
        struct dmi_device *dev;
-       void * data;
+       void *data;
 
        data = dmi_alloc(dm->length);
-       if (data == NULL) {
-               printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
+       if (data == NULL)
                return;
-       }
 
        memcpy(data, dm, dm->length);
 
        dev = dmi_alloc(sizeof(*dev));
-       if (!dev) {
-               printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
+       if (!dev)
                return;
-       }
 
        dev->type = DMI_DEV_TYPE_IPMI;
        dev->name = "IPMI controller";
@@ -301,10 +293,9 @@ static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
        struct dmi_dev_onboard *onboard_dev;
 
        onboard_dev = dmi_alloc(sizeof(*onboard_dev) + strlen(name) + 1);
-       if (!onboard_dev) {
-               printk(KERN_ERR "dmi_save_dev_onboard: out of memory.\n");
+       if (!onboard_dev)
                return;
-       }
+
        onboard_dev->instance = instance;
        onboard_dev->segment = segment;
        onboard_dev->bus = bus;
@@ -320,7 +311,7 @@ static void __init dmi_save_dev_onboard(int instance, int segment, int bus,
 
 static void __init dmi_save_extended_devices(const struct dmi_header *dm)
 {
-       const u8 *d = (u8*) dm + 5;
+       const u8 *d = (u8 *) dm + 5;
 
        /* Skip disabled device */
        if ((*d & 0x80) == 0)
@@ -338,7 +329,7 @@ static void __init dmi_save_extended_devices(const struct dmi_header *dm)
  */
 static void __init dmi_decode(const struct dmi_header *dm, void *dummy)
 {
-       switch(dm->type) {
+       switch (dm->type) {
        case 0:         /* BIOS Information */
                dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
                dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
@@ -502,13 +493,7 @@ void __init dmi_scan_machine(void)
                        dmi_available = 1;
                        goto out;
                }
-       }
-       else {
-               /*
-                * no iounmap() for that ioremap(); it would be a no-op, but
-                * it's so early in setup that sucker gets confused into doing
-                * what it shouldn't if we actually call it.
-                */
+       } else {
                p = dmi_ioremap(0xF0000, 0x10000);
                if (p == NULL)
                        goto error;
@@ -533,7 +518,7 @@ void __init dmi_scan_machine(void)
                dmi_iounmap(p, 0x10000);
        }
  error:
-       printk(KERN_INFO "DMI not present or invalid.\n");
+       pr_info("DMI not present or invalid.\n");
  out:
        dmi_initialized = 1;
 }
@@ -669,7 +654,7 @@ int dmi_name_in_serial(const char *str)
 
 /**
  *     dmi_name_in_vendors - Check if string is in the DMI system or board vendor name
- *     @str:   Case sensitive Name
+ *     @str: Case sensitive Name
  */
 int dmi_name_in_vendors(const char *str)
 {
@@ -696,13 +681,13 @@ EXPORT_SYMBOL(dmi_name_in_vendors);
  *     A new search is initiated by passing %NULL as the @from argument.
  *     If @from is not %NULL, searches continue from next device.
  */
-const struct dmi_device * dmi_find_device(int type, const char *name,
+const struct dmi_device *dmi_find_device(int type, const char *name,
                                    const struct dmi_device *from)
 {
        const struct list_head *head = from ? &from->list : &dmi_devices;
        struct list_head *d;
 
-       for(d = head->next; d != &dmi_devices; d = d->next) {
+       for (d = head->next; d != &dmi_devices; d = d->next) {
                const struct dmi_device *dev =
                        list_entry(d, struct dmi_device, list);
 
index acba0b9f4406ae972ad554e0eb3541d572b8dc92..6eb535ffeddc2ea7787f648d1d35734f24c305d5 100644 (file)
@@ -525,7 +525,7 @@ static ssize_t gsmi_clear_eventlog_store(struct kobject *kobj,
                u32 data_type;
        } param;
 
-       rc = strict_strtoul(buf, 0, &val);
+       rc = kstrtoul(buf, 0, &val);
        if (rc)
                return rc;
 
index 349b16160ac9b8b4cd2943751c6d8478d5cb0962..b6ed304863eb97dc68e4afd0f35e359ca53903fd 100644 (file)
@@ -203,6 +203,14 @@ config GPIO_MXS
        select GPIO_GENERIC
        select GENERIC_IRQ_CHIP
 
+config GPIO_OCTEON
+       tristate "Cavium OCTEON GPIO"
+       depends on GPIOLIB && CAVIUM_OCTEON_SOC
+       default y
+       help
+         Say yes here to support the on-chip GPIO lines on the OCTEON
+         family of SOCs.
+
 config GPIO_PL061
        bool "PrimeCell PL061 GPIO support"
        depends on ARM && ARM_AMBA
@@ -314,7 +322,7 @@ config GPIO_ICH
 
 config GPIO_VX855
        tristate "VIA VX855/VX875 GPIO"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select MFD_CORE
        select MFD_VX855
        help
@@ -388,7 +396,7 @@ config GPIO_MAX732X
 
 config GPIO_MAX732X_IRQ
        bool "Interrupt controller support for MAX732x"
-       depends on GPIO_MAX732X=y && GENERIC_HARDIRQS
+       depends on GPIO_MAX732X=y
        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.
@@ -653,7 +661,7 @@ config GPIO_TIMBERDALE
 
 config GPIO_RDC321X
        tristate "RDC R-321x GPIO support"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select MFD_CORE
        select MFD_RDC321X
        help
index 97438bf8434a76aee67c06bb526044b38817f12f..98e23ebba2cffa73eec7f0a9a113f820f9a14404 100644 (file)
@@ -52,6 +52,7 @@ obj-$(CONFIG_GPIO_MSM_V2)     += gpio-msm-v2.o
 obj-$(CONFIG_GPIO_MVEBU)        += gpio-mvebu.o
 obj-$(CONFIG_GPIO_MXC)         += gpio-mxc.o
 obj-$(CONFIG_GPIO_MXS)         += gpio-mxs.o
+obj-$(CONFIG_GPIO_OCTEON)      += gpio-octeon.o
 obj-$(CONFIG_ARCH_OMAP)                += gpio-omap.o
 obj-$(CONFIG_GPIO_PCA953X)     += gpio-pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += gpio-pcf857x.o
diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c
new file mode 100644 (file)
index 0000000..71a4a31
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2011, 2012 Cavium Inc.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <asm/octeon/octeon.h>
+#include <asm/octeon/cvmx-gpio-defs.h>
+
+#define RX_DAT 0x80
+#define TX_SET 0x88
+#define TX_CLEAR 0x90
+/*
+ * The address offset of the GPIO configuration register for a given
+ * line.
+ */
+static unsigned int bit_cfg_reg(unsigned int offset)
+{
+       /*
+        * The register stride is 8, with a discontinuity after the
+        * first 16.
+        */
+       if (offset < 16)
+               return 8 * offset;
+       else
+               return 8 * (offset - 16) + 0x100;
+}
+
+struct octeon_gpio {
+       struct gpio_chip chip;
+       u64 register_base;
+};
+
+static int octeon_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
+{
+       struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+
+       cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), 0);
+       return 0;
+}
+
+static void octeon_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+       struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+       u64 mask = 1ull << offset;
+       u64 reg = gpio->register_base + (value ? TX_SET : TX_CLEAR);
+       cvmx_write_csr(reg, mask);
+}
+
+static int octeon_gpio_dir_out(struct gpio_chip *chip, unsigned offset,
+                              int value)
+{
+       struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+       union cvmx_gpio_bit_cfgx cfgx;
+
+       octeon_gpio_set(chip, offset, value);
+
+       cfgx.u64 = 0;
+       cfgx.s.tx_oe = 1;
+
+       cvmx_write_csr(gpio->register_base + bit_cfg_reg(offset), cfgx.u64);
+       return 0;
+}
+
+static int octeon_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+       struct octeon_gpio *gpio = container_of(chip, struct octeon_gpio, chip);
+       u64 read_bits = cvmx_read_csr(gpio->register_base + RX_DAT);
+
+       return ((1ull << offset) & read_bits) != 0;
+}
+
+static int octeon_gpio_probe(struct platform_device *pdev)
+{
+       struct octeon_gpio *gpio;
+       struct gpio_chip *chip;
+       struct resource *res_mem;
+       int err = 0;
+
+       gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+       if (!gpio)
+               return -ENOMEM;
+       chip = &gpio->chip;
+
+       res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_mem == NULL) {
+               dev_err(&pdev->dev, "found no memory resource\n");
+               err = -ENXIO;
+               goto out;
+       }
+       if (!devm_request_mem_region(&pdev->dev, res_mem->start,
+                                       resource_size(res_mem),
+                                    res_mem->name)) {
+               dev_err(&pdev->dev, "request_mem_region failed\n");
+               err = -ENXIO;
+               goto out;
+       }
+       gpio->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start,
+                                               resource_size(res_mem));
+
+       pdev->dev.platform_data = chip;
+       chip->label = "octeon-gpio";
+       chip->dev = &pdev->dev;
+       chip->owner = THIS_MODULE;
+       chip->base = 0;
+       chip->can_sleep = 0;
+       chip->ngpio = 20;
+       chip->direction_input = octeon_gpio_dir_in;
+       chip->get = octeon_gpio_get;
+       chip->direction_output = octeon_gpio_dir_out;
+       chip->set = octeon_gpio_set;
+       err = gpiochip_add(chip);
+       if (err)
+               goto out;
+
+       dev_info(&pdev->dev, "OCTEON GPIO driver probed.\n");
+out:
+       return err;
+}
+
+static int octeon_gpio_remove(struct platform_device *pdev)
+{
+       struct gpio_chip *chip = pdev->dev.platform_data;
+       return gpiochip_remove(chip);
+}
+
+static struct of_device_id octeon_gpio_match[] = {
+       {
+               .compatible = "cavium,octeon-3860-gpio",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, octeon_gpio_match);
+
+static struct platform_driver octeon_gpio_driver = {
+       .driver = {
+               .name           = "octeon_gpio",
+               .owner          = THIS_MODULE,
+               .of_match_table = octeon_gpio_match,
+       },
+       .probe          = octeon_gpio_probe,
+       .remove         = octeon_gpio_remove,
+};
+
+module_platform_driver(octeon_gpio_driver);
+
+MODULE_DESCRIPTION("Cavium Inc. OCTEON GPIO Driver");
+MODULE_AUTHOR("David Daney");
+MODULE_LICENSE("GPL");
index ba9876ffb017ba3c8874512e73acbbf9c97d0cbb..0dfaf20e4dad4175fc7d5f49e6989d609876b123 100644 (file)
@@ -195,8 +195,8 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
                return;
 
        for (;; index++) {
-               ret = of_parse_phandle_with_args(np, "gpio-ranges",
-                               "#gpio-range-cells", index, &pinspec);
+               ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
+                               index, &pinspec);
                if (ret)
                        break;
 
index 796dbb212a4138180f7bda2e50fb765f22805c93..8492b68e873c174cda6e99e70cf976a90e5ddaff 100644 (file)
@@ -177,7 +177,7 @@ uint8_t ast_get_index_reg_mask(struct ast_private *ast,
 
 static inline void ast_open_key(struct ast_private *ast)
 {
-       ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xA1, 0xFF, 0x04);
+       ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x80, 0xA8);
 }
 
 #define AST_VIDMEM_SIZE_8M    0x00800000
index 3d13ca6e257f0f2c6bd366a49f8b7f3622e592dd..f6f6cc7fc133292e9fe3375502466b0abd1b0fa9 100644 (file)
@@ -407,6 +407,14 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
        struct drm_connector *connector;
        int i, j;
 
+       /*
+        * fbdev->blank can be called from irq context in case of a panic.
+        * Since we already have our own special panic handler which will
+        * restore the fbdev console mode completely, just bail out early.
+        */
+       if (oops_in_progress)
+               return;
+
        /*
         * fbdev->blank can be called from irq context in case of a panic.
         * Since we already have our own special panic handler which will
index 55ab9246e1b97c77d3e4a82acdbf04e2c904881f..a6f4cb5af18529308096b827bd50b68b94181f79 100644 (file)
@@ -857,7 +857,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
                u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS);
                u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-               u32 rpstat, cagf;
+               u32 rpstat, cagf, reqf;
                u32 rpupei, rpcurup, rpprevup;
                u32 rpdownei, rpcurdown, rpprevdown;
                int max_freq;
@@ -869,6 +869,14 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
 
                gen6_gt_force_wake_get(dev_priv);
 
+               reqf = I915_READ(GEN6_RPNSWREQ);
+               reqf &= ~GEN6_TURBO_DISABLE;
+               if (IS_HASWELL(dev))
+                       reqf >>= 24;
+               else
+                       reqf >>= 25;
+               reqf *= GT_FREQUENCY_MULTIPLIER;
+
                rpstat = I915_READ(GEN6_RPSTAT1);
                rpupei = I915_READ(GEN6_RP_CUR_UP_EI);
                rpcurup = I915_READ(GEN6_RP_CUR_UP);
@@ -893,6 +901,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                           gt_perf_status & 0xff);
                seq_printf(m, "Render p-state limit: %d\n",
                           rp_state_limits & 0xff);
+               seq_printf(m, "RPNSWREQ: %dMHz\n", reqf);
                seq_printf(m, "CAGF: %dMHz\n", cagf);
                seq_printf(m, "RP CUR UP EI: %dus\n", rpupei &
                           GEN6_CURICONT_MASK);
index fdaa0915ce56cfe25bf403a3833b4d46cbb88693..c27a21034a5e56e6fca41d6ff710c9abef59bf72 100644 (file)
@@ -1290,9 +1290,12 @@ static int i915_load_modeset_init(struct drm_device *dev)
         * then we do not take part in VGA arbitration and the
         * vga_client_register() fails with -ENODEV.
         */
-       ret = vga_client_register(dev->pdev, dev, NULL, i915_vga_set_decode);
-       if (ret && ret != -ENODEV)
-               goto out;
+       if (!HAS_PCH_SPLIT(dev)) {
+               ret = vga_client_register(dev->pdev, dev, NULL,
+                                         i915_vga_set_decode);
+               if (ret && ret != -ENODEV)
+                       goto out;
+       }
 
        intel_register_dsm_handler();
 
@@ -1348,6 +1351,12 @@ static int i915_load_modeset_init(struct drm_device *dev)
         */
        intel_fbdev_initial_config(dev);
 
+       /*
+        * Must do this after fbcon init so that
+        * vgacon_save_screen() works during the handover.
+        */
+       i915_disable_vga_mem(dev);
+
        /* Only enable hotplug handling once the fbdev is fully set up. */
        dev_priv->enable_hotplug_processing = true;
 
@@ -1667,7 +1676,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        return 0;
 
 out_gem_unload:
-       if (dev_priv->mm.inactive_shrinker.shrink)
+       if (dev_priv->mm.inactive_shrinker.scan_objects)
                unregister_shrinker(&dev_priv->mm.inactive_shrinker);
 
        if (dev->pdev->msi_enabled)
@@ -1706,7 +1715,7 @@ int i915_driver_unload(struct drm_device *dev)
 
        i915_teardown_sysfs(dev);
 
-       if (dev_priv->mm.inactive_shrinker.shrink)
+       if (dev_priv->mm.inactive_shrinker.scan_objects)
                unregister_shrinker(&dev_priv->mm.inactive_shrinker);
 
        mutex_lock(&dev->struct_mutex);
index ccb28ead3501e7a96d6adfbf5cecbd6438d3a0ad..69d8ed5416c31b2e80538fabec553e333fd741ea 100644 (file)
@@ -157,25 +157,6 @@ MODULE_PARM_DESC(prefault_disable,
 static struct drm_driver driver;
 extern int intel_agp_enabled;
 
-#define INTEL_VGA_DEVICE(id, info) {           \
-       .class = PCI_BASE_CLASS_DISPLAY << 16,  \
-       .class_mask = 0xff0000,                 \
-       .vendor = 0x8086,                       \
-       .device = id,                           \
-       .subvendor = PCI_ANY_ID,                \
-       .subdevice = PCI_ANY_ID,                \
-       .driver_data = (unsigned long) info }
-
-#define INTEL_QUANTA_VGA_DEVICE(info) {                \
-       .class = PCI_BASE_CLASS_DISPLAY << 16,  \
-       .class_mask = 0xff0000,                 \
-       .vendor = 0x8086,                       \
-       .device = 0x16a,                        \
-       .subvendor = 0x152d,                    \
-       .subdevice = 0x8990,                    \
-       .driver_data = (unsigned long) info }
-
-
 static const struct intel_device_info intel_i830_info = {
        .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
@@ -350,118 +331,41 @@ static const struct intel_device_info intel_haswell_m_info = {
        .has_vebox_ring = 1,
 };
 
+/*
+ * Make sure any device matches here are from most specific to most
+ * general.  For example, since the Quanta match is based on the subsystem
+ * and subvendor IDs, we need it to come before the more general IVB
+ * PCI ID matches, otherwise we'll use the wrong info struct above.
+ */
+#define INTEL_PCI_IDS \
+       INTEL_I830_IDS(&intel_i830_info),       \
+       INTEL_I845G_IDS(&intel_845g_info),      \
+       INTEL_I85X_IDS(&intel_i85x_info),       \
+       INTEL_I865G_IDS(&intel_i865g_info),     \
+       INTEL_I915G_IDS(&intel_i915g_info),     \
+       INTEL_I915GM_IDS(&intel_i915gm_info),   \
+       INTEL_I945G_IDS(&intel_i945g_info),     \
+       INTEL_I945GM_IDS(&intel_i945gm_info),   \
+       INTEL_I965G_IDS(&intel_i965g_info),     \
+       INTEL_G33_IDS(&intel_g33_info),         \
+       INTEL_I965GM_IDS(&intel_i965gm_info),   \
+       INTEL_GM45_IDS(&intel_gm45_info),       \
+       INTEL_G45_IDS(&intel_g45_info),         \
+       INTEL_PINEVIEW_IDS(&intel_pineview_info),       \
+       INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info),   \
+       INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info),   \
+       INTEL_SNB_D_IDS(&intel_sandybridge_d_info),     \
+       INTEL_SNB_M_IDS(&intel_sandybridge_m_info),     \
+       INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */ \
+       INTEL_IVB_M_IDS(&intel_ivybridge_m_info),       \
+       INTEL_IVB_D_IDS(&intel_ivybridge_d_info),       \
+       INTEL_HSW_D_IDS(&intel_haswell_d_info), \
+       INTEL_HSW_M_IDS(&intel_haswell_m_info), \
+       INTEL_VLV_M_IDS(&intel_valleyview_m_info),      \
+       INTEL_VLV_D_IDS(&intel_valleyview_d_info)
+
 static const struct pci_device_id pciidlist[] = {              /* aka */
-       INTEL_VGA_DEVICE(0x3577, &intel_i830_info),             /* I830_M */
-       INTEL_VGA_DEVICE(0x2562, &intel_845g_info),             /* 845_G */
-       INTEL_VGA_DEVICE(0x3582, &intel_i85x_info),             /* I855_GM */
-       INTEL_VGA_DEVICE(0x358e, &intel_i85x_info),
-       INTEL_VGA_DEVICE(0x2572, &intel_i865g_info),            /* I865_G */
-       INTEL_VGA_DEVICE(0x2582, &intel_i915g_info),            /* I915_G */
-       INTEL_VGA_DEVICE(0x258a, &intel_i915g_info),            /* E7221_G */
-       INTEL_VGA_DEVICE(0x2592, &intel_i915gm_info),           /* I915_GM */
-       INTEL_VGA_DEVICE(0x2772, &intel_i945g_info),            /* I945_G */
-       INTEL_VGA_DEVICE(0x27a2, &intel_i945gm_info),           /* I945_GM */
-       INTEL_VGA_DEVICE(0x27ae, &intel_i945gm_info),           /* I945_GME */
-       INTEL_VGA_DEVICE(0x2972, &intel_i965g_info),            /* I946_GZ */
-       INTEL_VGA_DEVICE(0x2982, &intel_i965g_info),            /* G35_G */
-       INTEL_VGA_DEVICE(0x2992, &intel_i965g_info),            /* I965_Q */
-       INTEL_VGA_DEVICE(0x29a2, &intel_i965g_info),            /* I965_G */
-       INTEL_VGA_DEVICE(0x29b2, &intel_g33_info),              /* Q35_G */
-       INTEL_VGA_DEVICE(0x29c2, &intel_g33_info),              /* G33_G */
-       INTEL_VGA_DEVICE(0x29d2, &intel_g33_info),              /* Q33_G */
-       INTEL_VGA_DEVICE(0x2a02, &intel_i965gm_info),           /* I965_GM */
-       INTEL_VGA_DEVICE(0x2a12, &intel_i965gm_info),           /* I965_GME */
-       INTEL_VGA_DEVICE(0x2a42, &intel_gm45_info),             /* GM45_G */
-       INTEL_VGA_DEVICE(0x2e02, &intel_g45_info),              /* IGD_E_G */
-       INTEL_VGA_DEVICE(0x2e12, &intel_g45_info),              /* Q45_G */
-       INTEL_VGA_DEVICE(0x2e22, &intel_g45_info),              /* G45_G */
-       INTEL_VGA_DEVICE(0x2e32, &intel_g45_info),              /* G41_G */
-       INTEL_VGA_DEVICE(0x2e42, &intel_g45_info),              /* B43_G */
-       INTEL_VGA_DEVICE(0x2e92, &intel_g45_info),              /* B43_G.1 */
-       INTEL_VGA_DEVICE(0xa001, &intel_pineview_info),
-       INTEL_VGA_DEVICE(0xa011, &intel_pineview_info),
-       INTEL_VGA_DEVICE(0x0042, &intel_ironlake_d_info),
-       INTEL_VGA_DEVICE(0x0046, &intel_ironlake_m_info),
-       INTEL_VGA_DEVICE(0x0102, &intel_sandybridge_d_info),
-       INTEL_VGA_DEVICE(0x0112, &intel_sandybridge_d_info),
-       INTEL_VGA_DEVICE(0x0122, &intel_sandybridge_d_info),
-       INTEL_VGA_DEVICE(0x0106, &intel_sandybridge_m_info),
-       INTEL_VGA_DEVICE(0x0116, &intel_sandybridge_m_info),
-       INTEL_VGA_DEVICE(0x0126, &intel_sandybridge_m_info),
-       INTEL_VGA_DEVICE(0x010A, &intel_sandybridge_d_info),
-       INTEL_VGA_DEVICE(0x0156, &intel_ivybridge_m_info), /* GT1 mobile */
-       INTEL_VGA_DEVICE(0x0166, &intel_ivybridge_m_info), /* GT2 mobile */
-       INTEL_VGA_DEVICE(0x0152, &intel_ivybridge_d_info), /* GT1 desktop */
-       INTEL_VGA_DEVICE(0x0162, &intel_ivybridge_d_info), /* GT2 desktop */
-       INTEL_VGA_DEVICE(0x015a, &intel_ivybridge_d_info), /* GT1 server */
-       INTEL_QUANTA_VGA_DEVICE(&intel_ivybridge_q_info), /* Quanta transcode */
-       INTEL_VGA_DEVICE(0x016a, &intel_ivybridge_d_info), /* GT2 server */
-       INTEL_VGA_DEVICE(0x0402, &intel_haswell_d_info), /* GT1 desktop */
-       INTEL_VGA_DEVICE(0x0412, &intel_haswell_d_info), /* GT2 desktop */
-       INTEL_VGA_DEVICE(0x0422, &intel_haswell_d_info), /* GT3 desktop */
-       INTEL_VGA_DEVICE(0x040a, &intel_haswell_d_info), /* GT1 server */
-       INTEL_VGA_DEVICE(0x041a, &intel_haswell_d_info), /* GT2 server */
-       INTEL_VGA_DEVICE(0x042a, &intel_haswell_d_info), /* GT3 server */
-       INTEL_VGA_DEVICE(0x0406, &intel_haswell_m_info), /* GT1 mobile */
-       INTEL_VGA_DEVICE(0x0416, &intel_haswell_m_info), /* GT2 mobile */
-       INTEL_VGA_DEVICE(0x0426, &intel_haswell_m_info), /* GT2 mobile */
-       INTEL_VGA_DEVICE(0x040B, &intel_haswell_d_info), /* GT1 reserved */
-       INTEL_VGA_DEVICE(0x041B, &intel_haswell_d_info), /* GT2 reserved */
-       INTEL_VGA_DEVICE(0x042B, &intel_haswell_d_info), /* GT3 reserved */
-       INTEL_VGA_DEVICE(0x040E, &intel_haswell_d_info), /* GT1 reserved */
-       INTEL_VGA_DEVICE(0x041E, &intel_haswell_d_info), /* GT2 reserved */
-       INTEL_VGA_DEVICE(0x042E, &intel_haswell_d_info), /* GT3 reserved */
-       INTEL_VGA_DEVICE(0x0C02, &intel_haswell_d_info), /* SDV GT1 desktop */
-       INTEL_VGA_DEVICE(0x0C12, &intel_haswell_d_info), /* SDV GT2 desktop */
-       INTEL_VGA_DEVICE(0x0C22, &intel_haswell_d_info), /* SDV GT3 desktop */
-       INTEL_VGA_DEVICE(0x0C0A, &intel_haswell_d_info), /* SDV GT1 server */
-       INTEL_VGA_DEVICE(0x0C1A, &intel_haswell_d_info), /* SDV GT2 server */
-       INTEL_VGA_DEVICE(0x0C2A, &intel_haswell_d_info), /* SDV GT3 server */
-       INTEL_VGA_DEVICE(0x0C06, &intel_haswell_m_info), /* SDV GT1 mobile */
-       INTEL_VGA_DEVICE(0x0C16, &intel_haswell_m_info), /* SDV GT2 mobile */
-       INTEL_VGA_DEVICE(0x0C26, &intel_haswell_m_info), /* SDV GT3 mobile */
-       INTEL_VGA_DEVICE(0x0C0B, &intel_haswell_d_info), /* SDV GT1 reserved */
-       INTEL_VGA_DEVICE(0x0C1B, &intel_haswell_d_info), /* SDV GT2 reserved */
-       INTEL_VGA_DEVICE(0x0C2B, &intel_haswell_d_info), /* SDV GT3 reserved */
-       INTEL_VGA_DEVICE(0x0C0E, &intel_haswell_d_info), /* SDV GT1 reserved */
-       INTEL_VGA_DEVICE(0x0C1E, &intel_haswell_d_info), /* SDV GT2 reserved */
-       INTEL_VGA_DEVICE(0x0C2E, &intel_haswell_d_info), /* SDV GT3 reserved */
-       INTEL_VGA_DEVICE(0x0A02, &intel_haswell_d_info), /* ULT GT1 desktop */
-       INTEL_VGA_DEVICE(0x0A12, &intel_haswell_d_info), /* ULT GT2 desktop */
-       INTEL_VGA_DEVICE(0x0A22, &intel_haswell_d_info), /* ULT GT3 desktop */
-       INTEL_VGA_DEVICE(0x0A0A, &intel_haswell_d_info), /* ULT GT1 server */
-       INTEL_VGA_DEVICE(0x0A1A, &intel_haswell_d_info), /* ULT GT2 server */
-       INTEL_VGA_DEVICE(0x0A2A, &intel_haswell_d_info), /* ULT GT3 server */
-       INTEL_VGA_DEVICE(0x0A06, &intel_haswell_m_info), /* ULT GT1 mobile */
-       INTEL_VGA_DEVICE(0x0A16, &intel_haswell_m_info), /* ULT GT2 mobile */
-       INTEL_VGA_DEVICE(0x0A26, &intel_haswell_m_info), /* ULT GT3 mobile */
-       INTEL_VGA_DEVICE(0x0A0B, &intel_haswell_d_info), /* ULT GT1 reserved */
-       INTEL_VGA_DEVICE(0x0A1B, &intel_haswell_d_info), /* ULT GT2 reserved */
-       INTEL_VGA_DEVICE(0x0A2B, &intel_haswell_d_info), /* ULT GT3 reserved */
-       INTEL_VGA_DEVICE(0x0A0E, &intel_haswell_m_info), /* ULT GT1 reserved */
-       INTEL_VGA_DEVICE(0x0A1E, &intel_haswell_m_info), /* ULT GT2 reserved */
-       INTEL_VGA_DEVICE(0x0A2E, &intel_haswell_m_info), /* ULT GT3 reserved */
-       INTEL_VGA_DEVICE(0x0D02, &intel_haswell_d_info), /* CRW GT1 desktop */
-       INTEL_VGA_DEVICE(0x0D12, &intel_haswell_d_info), /* CRW GT2 desktop */
-       INTEL_VGA_DEVICE(0x0D22, &intel_haswell_d_info), /* CRW GT3 desktop */
-       INTEL_VGA_DEVICE(0x0D0A, &intel_haswell_d_info), /* CRW GT1 server */
-       INTEL_VGA_DEVICE(0x0D1A, &intel_haswell_d_info), /* CRW GT2 server */
-       INTEL_VGA_DEVICE(0x0D2A, &intel_haswell_d_info), /* CRW GT3 server */
-       INTEL_VGA_DEVICE(0x0D06, &intel_haswell_m_info), /* CRW GT1 mobile */
-       INTEL_VGA_DEVICE(0x0D16, &intel_haswell_m_info), /* CRW GT2 mobile */
-       INTEL_VGA_DEVICE(0x0D26, &intel_haswell_m_info), /* CRW GT3 mobile */
-       INTEL_VGA_DEVICE(0x0D0B, &intel_haswell_d_info), /* CRW GT1 reserved */
-       INTEL_VGA_DEVICE(0x0D1B, &intel_haswell_d_info), /* CRW GT2 reserved */
-       INTEL_VGA_DEVICE(0x0D2B, &intel_haswell_d_info), /* CRW GT3 reserved */
-       INTEL_VGA_DEVICE(0x0D0E, &intel_haswell_d_info), /* CRW GT1 reserved */
-       INTEL_VGA_DEVICE(0x0D1E, &intel_haswell_d_info), /* CRW GT2 reserved */
-       INTEL_VGA_DEVICE(0x0D2E, &intel_haswell_d_info), /* CRW GT3 reserved */
-       INTEL_VGA_DEVICE(0x0f30, &intel_valleyview_m_info),
-       INTEL_VGA_DEVICE(0x0f31, &intel_valleyview_m_info),
-       INTEL_VGA_DEVICE(0x0f32, &intel_valleyview_m_info),
-       INTEL_VGA_DEVICE(0x0f33, &intel_valleyview_m_info),
-       INTEL_VGA_DEVICE(0x0157, &intel_valleyview_m_info),
-       INTEL_VGA_DEVICE(0x0155, &intel_valleyview_d_info),
+       INTEL_PCI_IDS,
        {0, 0, 0}
 };
 
index 52a3785a3fdfa59fbab49f9098f8448418ff2155..35874b3a86dcc917c9bb68e1cb4879d81a0fc76b 100644 (file)
@@ -1236,6 +1236,13 @@ typedef struct drm_i915_private {
 
        unsigned int fsb_freq, mem_freq, is_ddr3;
 
+       /**
+        * wq - Driver workqueue for GEM.
+        *
+        * NOTE: Work items scheduled here are not allowed to grab any modeset
+        * locks, for otherwise the flushing done in the pageflip code will
+        * result in deadlocks.
+        */
        struct workqueue_struct *wq;
 
        /* Display functions */
index 2d1cb10d846f376073d2da03e9c974300ee98f88..8507c6d1e642d872c48f41834a5dbeca53d99c6b 100644 (file)
@@ -57,10 +57,12 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
                                         struct drm_i915_fence_reg *fence,
                                         bool enable);
 
-static int i915_gem_inactive_shrink(struct shrinker *shrinker,
-                                   struct shrink_control *sc);
+static unsigned long i915_gem_inactive_count(struct shrinker *shrinker,
+                                            struct shrink_control *sc);
+static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker,
+                                           struct shrink_control *sc);
 static long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
-static void i915_gem_shrink_all(struct drm_i915_private *dev_priv);
+static long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
 static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
@@ -212,7 +214,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
 void *i915_gem_object_alloc(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       return kmem_cache_alloc(dev_priv->slab, GFP_KERNEL | __GFP_ZERO);
+       return kmem_cache_zalloc(dev_priv->slab, GFP_KERNEL);
 }
 
 void i915_gem_object_free(struct drm_i915_gem_object *obj)
@@ -1695,6 +1697,7 @@ static long
 __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                  bool purgeable_only)
 {
+       struct list_head still_bound_list;
        struct drm_i915_gem_object *obj, *next;
        long count = 0;
 
@@ -1709,23 +1712,55 @@ __i915_gem_shrink(struct drm_i915_private *dev_priv, long target,
                }
        }
 
-       list_for_each_entry_safe(obj, next, &dev_priv->mm.bound_list,
-                                global_list) {
+       /*
+        * As we may completely rewrite the bound list whilst unbinding
+        * (due to retiring requests) we have to strictly process only
+        * one element of the list at the time, and recheck the list
+        * on every iteration.
+        */
+       INIT_LIST_HEAD(&still_bound_list);
+       while (count < target && !list_empty(&dev_priv->mm.bound_list)) {
                struct i915_vma *vma, *v;
 
+               obj = list_first_entry(&dev_priv->mm.bound_list,
+                                      typeof(*obj), global_list);
+               list_move_tail(&obj->global_list, &still_bound_list);
+
                if (!i915_gem_object_is_purgeable(obj) && purgeable_only)
                        continue;
 
+               /*
+                * Hold a reference whilst we unbind this object, as we may
+                * end up waiting for and retiring requests. This might
+                * release the final reference (held by the active list)
+                * and result in the object being freed from under us.
+                * in this object being freed.
+                *
+                * Note 1: Shrinking the bound list is special since only active
+                * (and hence bound objects) can contain such limbo objects, so
+                * we don't need special tricks for shrinking the unbound list.
+                * The only other place where we have to be careful with active
+                * objects suddenly disappearing due to retiring requests is the
+                * eviction code.
+                *
+                * Note 2: Even though the bound list doesn't hold a reference
+                * to the object we can safely grab one here: The final object
+                * unreferencing and the bound_list are both protected by the
+                * dev->struct_mutex and so we won't ever be able to observe an
+                * object on the bound_list with a reference count equals 0.
+                */
+               drm_gem_object_reference(&obj->base);
+
                list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
                        if (i915_vma_unbind(vma))
                                break;
 
-               if (!i915_gem_object_put_pages(obj)) {
+               if (i915_gem_object_put_pages(obj) == 0)
                        count += obj->base.size >> PAGE_SHIFT;
-                       if (count >= target)
-                               return count;
-               }
+
+               drm_gem_object_unreference(&obj->base);
        }
+       list_splice(&still_bound_list, &dev_priv->mm.bound_list);
 
        return count;
 }
@@ -1736,16 +1771,21 @@ i915_gem_purge(struct drm_i915_private *dev_priv, long target)
        return __i915_gem_shrink(dev_priv, target, true);
 }
 
-static void
+static long
 i915_gem_shrink_all(struct drm_i915_private *dev_priv)
 {
        struct drm_i915_gem_object *obj, *next;
+       long freed = 0;
 
        i915_gem_evict_everything(dev_priv->dev);
 
        list_for_each_entry_safe(obj, next, &dev_priv->mm.unbound_list,
-                                global_list)
+                                global_list) {
+               if (obj->pages_pin_count == 0)
+                       freed += obj->base.size >> PAGE_SHIFT;
                i915_gem_object_put_pages(obj);
+       }
+       return freed;
 }
 
 static int
@@ -1774,7 +1814,6 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj)
 
        page_count = obj->base.size / PAGE_SIZE;
        if (sg_alloc_table(st, page_count, GFP_KERNEL)) {
-               sg_free_table(st);
                kfree(st);
                return -ENOMEM;
        }
@@ -4526,7 +4565,8 @@ i915_gem_load(struct drm_device *dev)
 
        dev_priv->mm.interruptible = true;
 
-       dev_priv->mm.inactive_shrinker.shrink = i915_gem_inactive_shrink;
+       dev_priv->mm.inactive_shrinker.scan_objects = i915_gem_inactive_scan;
+       dev_priv->mm.inactive_shrinker.count_objects = i915_gem_inactive_count;
        dev_priv->mm.inactive_shrinker.seeks = DEFAULT_SEEKS;
        register_shrinker(&dev_priv->mm.inactive_shrinker);
 }
@@ -4749,8 +4789,8 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
 #endif
 }
 
-static int
-i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
+static unsigned long
+i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
 {
        struct drm_i915_private *dev_priv =
                container_of(shrinker,
@@ -4758,45 +4798,35 @@ i915_gem_inactive_shrink(struct shrinker *shrinker, struct shrink_control *sc)
                             mm.inactive_shrinker);
        struct drm_device *dev = dev_priv->dev;
        struct drm_i915_gem_object *obj;
-       int nr_to_scan = sc->nr_to_scan;
        bool unlock = true;
-       int cnt;
+       unsigned long count;
 
        if (!mutex_trylock(&dev->struct_mutex)) {
                if (!mutex_is_locked_by(&dev->struct_mutex, current))
-                       return 0;
+                       return SHRINK_STOP;
 
                if (dev_priv->mm.shrinker_no_lock_stealing)
-                       return 0;
+                       return SHRINK_STOP;
 
                unlock = false;
        }
 
-       if (nr_to_scan) {
-               nr_to_scan -= i915_gem_purge(dev_priv, nr_to_scan);
-               if (nr_to_scan > 0)
-                       nr_to_scan -= __i915_gem_shrink(dev_priv, nr_to_scan,
-                                                       false);
-               if (nr_to_scan > 0)
-                       i915_gem_shrink_all(dev_priv);
-       }
-
-       cnt = 0;
+       count = 0;
        list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
                if (obj->pages_pin_count == 0)
-                       cnt += obj->base.size >> PAGE_SHIFT;
+                       count += obj->base.size >> PAGE_SHIFT;
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                if (obj->active)
                        continue;
 
                if (obj->pin_count == 0 && obj->pages_pin_count == 0)
-                       cnt += obj->base.size >> PAGE_SHIFT;
+                       count += obj->base.size >> PAGE_SHIFT;
        }
 
        if (unlock)
                mutex_unlock(&dev->struct_mutex);
-       return cnt;
+       return count;
 }
 
 /* All the new VM stuff */
@@ -4860,6 +4890,40 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
        return 0;
 }
 
+static unsigned long
+i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(shrinker,
+                            struct drm_i915_private,
+                            mm.inactive_shrinker);
+       struct drm_device *dev = dev_priv->dev;
+       int nr_to_scan = sc->nr_to_scan;
+       unsigned long freed;
+       bool unlock = true;
+
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               if (!mutex_is_locked_by(&dev->struct_mutex, current))
+                       return 0;
+
+               if (dev_priv->mm.shrinker_no_lock_stealing)
+                       return 0;
+
+               unlock = false;
+       }
+
+       freed = i915_gem_purge(dev_priv, nr_to_scan);
+       if (freed < nr_to_scan)
+               freed += __i915_gem_shrink(dev_priv, nr_to_scan,
+                                                       false);
+       if (freed < nr_to_scan)
+               freed += i915_gem_shrink_all(dev_priv);
+
+       if (unlock)
+               mutex_unlock(&dev->struct_mutex);
+       return freed;
+}
+
 struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
                                     struct i915_address_space *vm)
 {
index e918b05fcbdd16e238457f7e286b345bdf651731..7d5752fda5f18b7850beeed588a6f1b3a85cd79a 100644 (file)
@@ -42,27 +42,24 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme
 
        ret = i915_mutex_lock_interruptible(obj->base.dev);
        if (ret)
-               return ERR_PTR(ret);
+               goto err;
 
        ret = i915_gem_object_get_pages(obj);
-       if (ret) {
-               st = ERR_PTR(ret);
-               goto out;
-       }
+       if (ret)
+               goto err_unlock;
+
+       i915_gem_object_pin_pages(obj);
 
        /* Copy sg so that we make an independent mapping */
        st = kmalloc(sizeof(struct sg_table), GFP_KERNEL);
        if (st == NULL) {
-               st = ERR_PTR(-ENOMEM);
-               goto out;
+               ret = -ENOMEM;
+               goto err_unpin;
        }
 
        ret = sg_alloc_table(st, obj->pages->nents, GFP_KERNEL);
-       if (ret) {
-               kfree(st);
-               st = ERR_PTR(ret);
-               goto out;
-       }
+       if (ret)
+               goto err_free;
 
        src = obj->pages->sgl;
        dst = st->sgl;
@@ -73,17 +70,23 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme
        }
 
        if (!dma_map_sg(attachment->dev, st->sgl, st->nents, dir)) {
-               sg_free_table(st);
-               kfree(st);
-               st = ERR_PTR(-ENOMEM);
-               goto out;
+               ret =-ENOMEM;
+               goto err_free_sg;
        }
 
-       i915_gem_object_pin_pages(obj);
-
-out:
        mutex_unlock(&obj->base.dev->struct_mutex);
        return st;
+
+err_free_sg:
+       sg_free_table(st);
+err_free:
+       kfree(st);
+err_unpin:
+       i915_gem_object_unpin_pages(obj);
+err_unlock:
+       mutex_unlock(&obj->base.dev->struct_mutex);
+err:
+       return ERR_PTR(ret);
 }
 
 static void i915_gem_unmap_dma_buf(struct dma_buf_attachment *attachment,
index 792c52a235eeb4cf7aee039688160bf16e21bc96..bf345777ae9f76ec41e76c5ccf6ed3624cf4ef13 100644 (file)
@@ -310,6 +310,9 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        else
                ret = relocate_entry_gtt(obj, reloc);
 
+       if (ret)
+               return ret;
+
        /* and update the user's relocation entry */
        reloc->presumed_offset = target_offset;
 
index 9969d10b80f518c6d032d45ff57cf2839afbd5bf..e15a1d90037d7709b2f4c489074ef5779ac6c1a8 100644 (file)
@@ -201,6 +201,9 @@ int i915_gem_init_stolen(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int bios_reserved = 0;
 
+       if (dev_priv->gtt.stolen_size == 0)
+               return 0;
+
        dev_priv->mm.stolen_base = i915_stolen_to_physical(dev);
        if (dev_priv->mm.stolen_base == 0)
                return 0;
index 558e568d5b459614f8820242c8539fa750d84b5a..aba9d7498996c29845e6691ac4eff83c8fe85223 100644 (file)
@@ -641,7 +641,7 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
                if (WARN_ON(ring->id != RCS))
                        return NULL;
 
-               obj = ring->private;
+               obj = ring->scratch.obj;
                if (acthd >= i915_gem_obj_ggtt_offset(obj) &&
                    acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size)
                        return i915_error_object_create(dev_priv, obj);
index a03b445ceb5f94988f1df38b0cd07fdb7f0b3a13..83cce0cdb7691a9aa6024defc01c869a57b4a90a 100644 (file)
@@ -1027,8 +1027,13 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
                dev_priv->display.hpd_irq_setup(dev);
        spin_unlock(&dev_priv->irq_lock);
 
-       queue_work(dev_priv->wq,
-                  &dev_priv->hotplug_work);
+       /*
+        * Our hotplug handler can grab modeset locks (by calling down into the
+        * fb helpers). Hence it must not be run on our own dev-priv->wq work
+        * queue for otherwise the flush_work in the pageflip code will
+        * deadlock.
+        */
+       schedule_work(&dev_priv->hotplug_work);
 }
 
 static void gmbus_irq_handler(struct drm_device *dev)
@@ -1655,7 +1660,13 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
                        wake_up_all(&ring->irq_queue);
        }
 
-       queue_work(dev_priv->wq, &dev_priv->gpu_error.work);
+       /*
+        * Our reset work can grab modeset locks (since it needs to reset the
+        * state of outstanding pagelips). Hence it must not be run on our own
+        * dev-priv->wq work queue for otherwise the flush_work in the pageflip
+        * code will deadlock.
+        */
+       schedule_work(&dev_priv->gpu_error.work);
 }
 
 static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
@@ -2027,9 +2038,9 @@ static void i915_hangcheck_elapsed(unsigned long data)
 
        for_each_ring(ring, dev_priv, i) {
                if (ring->hangcheck.score > FIRE) {
-                       DRM_ERROR("%s on %s\n",
-                                 stuck[i] ? "stuck" : "no progress",
-                                 ring->name);
+                       DRM_INFO("%s on %s\n",
+                                stuck[i] ? "stuck" : "no progress",
+                                ring->name);
                        rings_hung++;
                }
        }
index b6a58f720f9a576fe7081b8225bb4e72a5db81d7..c159e1a6810fbd8f04e60520dfc5fdb884d8dbff 100644 (file)
 #define _MASKED_BIT_ENABLE(a) (((a) << 16) | (a))
 #define _MASKED_BIT_DISABLE(a) ((a) << 16)
 
-/*
- * The Bridge device's PCI config space has information about the
- * fb aperture size and the amount of pre-reserved memory.
- * This is all handled in the intel-gtt.ko module. i915.ko only
- * cares about the vga bit for the vga rbiter.
- */
-#define INTEL_GMCH_CTRL                0x52
-#define INTEL_GMCH_VGA_DISABLE  (1 << 1)
-#define SNB_GMCH_CTRL          0x50
-#define    SNB_GMCH_GGMS_SHIFT 8 /* GTT Graphics Memory Size */
-#define    SNB_GMCH_GGMS_MASK  0x3
-#define    SNB_GMCH_GMS_SHIFT   3 /* Graphics Mode Select */
-#define    SNB_GMCH_GMS_MASK    0x1f
-
-
 /* PCI config space */
 
 #define HPLLCC 0xc0 /* 855 only */
  *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
  */
 #define MI_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*x-1)
+#define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1)
 #define MI_FLUSH_DW            MI_INSTR(0x26, 1) /* for GEN6 */
 #define   MI_FLUSH_DW_STORE_INDEX      (1<<21)
 #define   MI_INVALIDATE_TLB            (1<<18)
 #define   FPGA_DBG_RM_NOCLAIM  (1<<31)
 
 #define DERRMR         0x44050
+#define   DERRMR_PIPEA_SCANLINE                (1<<0)
+#define   DERRMR_PIPEA_PRI_FLIP_DONE   (1<<1)
+#define   DERRMR_PIPEA_SPR_FLIP_DONE   (1<<2)
+#define   DERRMR_PIPEA_VBLANK          (1<<3)
+#define   DERRMR_PIPEA_HBLANK          (1<<5)
+#define   DERRMR_PIPEB_SCANLINE        (1<<8)
+#define   DERRMR_PIPEB_PRI_FLIP_DONE   (1<<9)
+#define   DERRMR_PIPEB_SPR_FLIP_DONE   (1<<10)
+#define   DERRMR_PIPEB_VBLANK          (1<<11)
+#define   DERRMR_PIPEB_HBLANK          (1<<13)
+/* Note that PIPEC is not a simple translation of PIPEA/PIPEB */
+#define   DERRMR_PIPEC_SCANLINE                (1<<14)
+#define   DERRMR_PIPEC_PRI_FLIP_DONE   (1<<15)
+#define   DERRMR_PIPEC_SPR_FLIP_DONE   (1<<20)
+#define   DERRMR_PIPEC_VBLANK          (1<<21)
+#define   DERRMR_PIPEC_HBLANK          (1<<22)
+
 
 /* GM45+ chicken bits -- debug workaround bits that may be required
  * for various sorts of correct behavior.  The top 16 bits of each are
 #define   MCURSOR_PIPE_A       0x00
 #define   MCURSOR_PIPE_B       (1 << 28)
 #define   MCURSOR_GAMMA_ENABLE  (1 << 26)
+#define   CURSOR_TRICKLE_FEED_DISABLE  (1 << 14)
 #define _CURABASE              (dev_priv->info->display_mmio_offset + 0x70084)
 #define _CURAPOS               (dev_priv->info->display_mmio_offset + 0x70088)
 #define   CURSOR_POS_MASK       0x007FF
index a777e7f3b0df924c7e7d2401b3994f6b8e963f3c..c8c4112de1108e9293066305eca079fdac8651d2 100644 (file)
@@ -224,6 +224,18 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
        return snprintf(buf, PAGE_SIZE, "%d\n", ret);
 }
 
+static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
+                                    struct device_attribute *attr, char *buf)
+{
+       struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
+       struct drm_device *dev = minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       vlv_gpu_freq(dev_priv->mem_freq,
+                                    dev_priv->rps.rpe_delay));
+}
+
 static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
 {
        struct drm_minor *minor = container_of(kdev, struct drm_minor, kdev);
@@ -366,6 +378,7 @@ static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
 static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
 static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
 
+static DEVICE_ATTR(vlv_rpe_freq_mhz, S_IRUGO, vlv_rpe_freq_mhz_show, NULL);
 
 static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf);
 static DEVICE_ATTR(gt_RP0_freq_mhz, S_IRUGO, gt_rp_mhz_show, NULL);
@@ -409,6 +422,14 @@ static const struct attribute *gen6_attrs[] = {
        NULL,
 };
 
+static const struct attribute *vlv_attrs[] = {
+       &dev_attr_gt_cur_freq_mhz.attr,
+       &dev_attr_gt_max_freq_mhz.attr,
+       &dev_attr_gt_min_freq_mhz.attr,
+       &dev_attr_vlv_rpe_freq_mhz.attr,
+       NULL,
+};
+
 static ssize_t error_state_read(struct file *filp, struct kobject *kobj,
                                struct bin_attribute *attr, char *buf,
                                loff_t off, size_t count)
@@ -492,11 +513,13 @@ void i915_setup_sysfs(struct drm_device *dev)
                        DRM_ERROR("l3 parity sysfs setup failed\n");
        }
 
-       if (INTEL_INFO(dev)->gen >= 6) {
+       ret = 0;
+       if (IS_VALLEYVIEW(dev))
+               ret = sysfs_create_files(&dev->primary->kdev.kobj, vlv_attrs);
+       else if (INTEL_INFO(dev)->gen >= 6)
                ret = sysfs_create_files(&dev->primary->kdev.kobj, gen6_attrs);
-               if (ret)
-                       DRM_ERROR("gen6 sysfs setup failed\n");
-       }
+       if (ret)
+               DRM_ERROR("RPS sysfs setup failed\n");
 
        ret = sysfs_create_bin_file(&dev->primary->kdev.kobj,
                                    &error_state_attr);
@@ -507,7 +530,10 @@ void i915_setup_sysfs(struct drm_device *dev)
 void i915_teardown_sysfs(struct drm_device *dev)
 {
        sysfs_remove_bin_file(&dev->primary->kdev.kobj, &error_state_attr);
-       sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
+       if (IS_VALLEYVIEW(dev))
+               sysfs_remove_files(&dev->primary->kdev.kobj, vlv_attrs);
+       else
+               sysfs_remove_files(&dev->primary->kdev.kobj, gen6_attrs);
        device_remove_bin_file(&dev->primary->kdev,  &dpf_attrs);
 #ifdef CONFIG_PM
        sysfs_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
index b5a3875f22c7cb5d18550b6be3b1c4b48b527274..ea9022ef15d5bdffc40e5c0bf9a941c7f0b38677 100644 (file)
@@ -688,7 +688,7 @@ static void intel_crt_reset(struct drm_connector *connector)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crt *crt = intel_attached_crt(connector);
 
-       if (HAS_PCH_SPLIT(dev)) {
+       if (INTEL_INFO(dev)->gen >= 5) {
                u32 adpa;
 
                adpa = I915_READ(crt->adpa_reg);
index 38452d82ac7dc4d57c603151de925d8aecf63ae6..2489d0b4c7d2db8a8b5d74c04107f1b405c8ad35 100644 (file)
@@ -2077,8 +2077,10 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        else
                dspcntr &= ~DISPPLANE_TILED;
 
-       /* must disable */
-       dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
+       if (IS_HASWELL(dev))
+               dspcntr &= ~DISPPLANE_TRICKLE_FEED_DISABLE;
+       else
+               dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
        I915_WRITE(reg, dspcntr);
 
@@ -6762,8 +6764,10 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
                        cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
                        cntl |= CURSOR_MODE_DISABLE;
                }
-               if (IS_HASWELL(dev))
+               if (IS_HASWELL(dev)) {
                        cntl |= CURSOR_PIPE_CSC_ENABLE;
+                       cntl &= ~CURSOR_TRICKLE_FEED_DISABLE;
+               }
                I915_WRITE(CURCNTR_IVB(pipe), cntl);
 
                intel_crtc->cursor_visible = visible;
@@ -7309,8 +7313,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
                }
        }
 
-       pipe_config->adjusted_mode.clock = clock.dot *
-               pipe_config->pixel_multiplier;
+       pipe_config->adjusted_mode.clock = clock.dot;
 }
 
 static void ironlake_crtc_clock_get(struct intel_crtc *crtc,
@@ -7828,12 +7831,6 @@ err:
        return ret;
 }
 
-/*
- * On gen7 we currently use the blit ring because (in early silicon at least)
- * the render ring doesn't give us interrpts for page flip completion, which
- * means clients will hang after the first flip is queued.  Fortunately the
- * blit ring generates interrupts properly, so use it instead.
- */
 static int intel_gen7_queue_flip(struct drm_device *dev,
                                 struct drm_crtc *crtc,
                                 struct drm_framebuffer *fb,
@@ -7842,9 +7839,13 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_ring_buffer *ring = &dev_priv->ring[BCS];
+       struct intel_ring_buffer *ring;
        uint32_t plane_bit = 0;
-       int ret;
+       int len, ret;
+
+       ring = obj->ring;
+       if (IS_VALLEYVIEW(dev) || ring == NULL || ring->id != RCS)
+               ring = &dev_priv->ring[BCS];
 
        ret = intel_pin_and_fence_fb_obj(dev, obj, ring);
        if (ret)
@@ -7866,10 +7867,34 @@ static int intel_gen7_queue_flip(struct drm_device *dev,
                goto err_unpin;
        }
 
-       ret = intel_ring_begin(ring, 4);
+       len = 4;
+       if (ring->id == RCS)
+               len += 6;
+
+       ret = intel_ring_begin(ring, len);
        if (ret)
                goto err_unpin;
 
+       /* Unmask the flip-done completion message. Note that the bspec says that
+        * we should do this for both the BCS and RCS, and that we must not unmask
+        * more than one flip event at any time (or ensure that one flip message
+        * can be sent by waiting for flip-done prior to queueing new flips).
+        * Experimentation says that BCS works despite DERRMR masking all
+        * flip-done completion events and that unmasking all planes at once
+        * for the RCS also doesn't appear to drop events. Setting the DERRMR
+        * to zero does lead to lockups within MI_DISPLAY_FLIP.
+        */
+       if (ring->id == RCS) {
+               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+               intel_ring_emit(ring, DERRMR);
+               intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE |
+                                       DERRMR_PIPEB_PRI_FLIP_DONE |
+                                       DERRMR_PIPEC_PRI_FLIP_DONE));
+               intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1));
+               intel_ring_emit(ring, DERRMR);
+               intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
+       }
+
        intel_ring_emit(ring, MI_DISPLAY_FLIP_I915 | plane_bit);
        intel_ring_emit(ring, (fb->pitches[0] | obj->tiling_mode));
        intel_ring_emit(ring, i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
@@ -10022,6 +10047,33 @@ static void i915_disable_vga(struct drm_device *dev)
        POSTING_READ(vga_reg);
 }
 
+static void i915_enable_vga_mem(struct drm_device *dev)
+{
+       /* Enable VGA memory on Intel HD */
+       if (HAS_PCH_SPLIT(dev)) {
+               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+               outb(inb(VGA_MSR_READ) | VGA_MSR_MEM_EN, VGA_MSR_WRITE);
+               vga_set_legacy_decoding(dev->pdev, VGA_RSRC_LEGACY_IO |
+                                                  VGA_RSRC_LEGACY_MEM |
+                                                  VGA_RSRC_NORMAL_IO |
+                                                  VGA_RSRC_NORMAL_MEM);
+               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+       }
+}
+
+void i915_disable_vga_mem(struct drm_device *dev)
+{
+       /* Disable VGA memory on Intel HD */
+       if (HAS_PCH_SPLIT(dev)) {
+               vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+               outb(inb(VGA_MSR_READ) & ~VGA_MSR_MEM_EN, VGA_MSR_WRITE);
+               vga_set_legacy_decoding(dev->pdev, VGA_RSRC_LEGACY_IO |
+                                                  VGA_RSRC_NORMAL_IO |
+                                                  VGA_RSRC_NORMAL_MEM);
+               vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+       }
+}
+
 void intel_modeset_init_hw(struct drm_device *dev)
 {
        intel_init_power_well(dev);
@@ -10300,6 +10352,7 @@ void i915_redisable_vga(struct drm_device *dev)
        if (I915_READ(vga_reg) != VGA_DISP_DISABLE) {
                DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
                i915_disable_vga(dev);
+               i915_disable_vga_mem(dev);
        }
 }
 
@@ -10513,6 +10566,8 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        intel_disable_fbc(dev);
 
+       i915_enable_vga_mem(dev);
+
        intel_disable_gt_powersave(dev);
 
        ironlake_teardown_rc6(dev);
index 176080822a74d1e76d099615cb218c9a93736300..a47799e832c6e61f5ff02afbf35ebe2cde73a4ed 100644 (file)
@@ -551,7 +551,7 @@ extern int intel_panel_init(struct intel_panel *panel,
                            struct drm_display_mode *fixed_mode);
 extern void intel_panel_fini(struct intel_panel *panel);
 
-extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
+extern void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
                                   struct drm_display_mode *adjusted_mode);
 extern void intel_pch_panel_fitting(struct intel_crtc *crtc,
                                    struct intel_crtc_config *pipe_config,
@@ -792,5 +792,6 @@ extern void hsw_pc8_disable_interrupts(struct drm_device *dev);
 extern void hsw_pc8_restore_interrupts(struct drm_device *dev);
 extern void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
 extern void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
+extern void i915_disable_vga_mem(struct drm_device *dev);
 
 #endif /* __INTEL_DRV_H__ */
index 4d33278e31fb805dae4430a5ab493f801a1c6ced..831a5c021c4bdefd2495ca0736d8fcb3f78ff57d 100644 (file)
@@ -128,8 +128,8 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
-       struct drm_display_mode *fixed_mode =
-               lvds_encoder->attached_connector->base.panel.fixed_mode;
+       const struct drm_display_mode *adjusted_mode =
+               &crtc->config.adjusted_mode;
        int pipe = crtc->pipe;
        u32 temp;
 
@@ -183,9 +183,9 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
                        temp &= ~LVDS_ENABLE_DITHER;
        }
        temp &= ~(LVDS_HSYNC_POLARITY | LVDS_VSYNC_POLARITY);
-       if (fixed_mode->flags & DRM_MODE_FLAG_NHSYNC)
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC)
                temp |= LVDS_HSYNC_POLARITY;
-       if (fixed_mode->flags & DRM_MODE_FLAG_NVSYNC)
+       if (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC)
                temp |= LVDS_VSYNC_POLARITY;
 
        I915_WRITE(lvds_encoder->reg, temp);
index cfb8fb68f09c87e7da468a57dd2375530ddc0345..119771ff46ab5178047c018efc5f9f31a06f068d 100644 (file)
@@ -173,7 +173,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
                return ASLE_BACKLIGHT_FAILED;
 
        intel_panel_set_backlight(dev, bclp, 255);
-       iowrite32((bclp*0x64)/0xff | ASLE_CBLV_VALID, &asle->cblv);
+       iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
 
        return 0;
 }
index a43c33bc4a3582ece3758ae7286b87fb2a8256ec..42114ecbae0e3c4c8dc51b7b02a1f658de857873 100644 (file)
 #define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
 
 void
-intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
+intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
                       struct drm_display_mode *adjusted_mode)
 {
-       adjusted_mode->hdisplay = fixed_mode->hdisplay;
-       adjusted_mode->hsync_start = fixed_mode->hsync_start;
-       adjusted_mode->hsync_end = fixed_mode->hsync_end;
-       adjusted_mode->htotal = fixed_mode->htotal;
+       drm_mode_copy(adjusted_mode, fixed_mode);
 
-       adjusted_mode->vdisplay = fixed_mode->vdisplay;
-       adjusted_mode->vsync_start = fixed_mode->vsync_start;
-       adjusted_mode->vsync_end = fixed_mode->vsync_end;
-       adjusted_mode->vtotal = fixed_mode->vtotal;
-
-       adjusted_mode->clock = fixed_mode->clock;
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
 }
 
 /* adjusted_mode has been preset to be the panel's fixed mode */
index 46056820d1d2200db076c2e5f3291fdde1068915..0c115cc4899ffbe00de6ca305d5cd32bd2590405 100644 (file)
@@ -3447,14 +3447,24 @@ int intel_enable_rc6(const struct drm_device *dev)
 static void gen6_enable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 enabled_intrs;
 
        spin_lock_irq(&dev_priv->irq_lock);
        WARN_ON(dev_priv->rps.pm_iir);
        snb_enable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS);
        I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
        spin_unlock_irq(&dev_priv->irq_lock);
+
        /* only unmask PM interrupts we need. Mask all others. */
-       I915_WRITE(GEN6_PMINTRMSK, ~GEN6_PM_RPS_EVENTS);
+       enabled_intrs = GEN6_PM_RPS_EVENTS;
+
+       /* IVB and SNB hard hangs on looping batchbuffer
+        * if GEN6_PM_UP_EI_EXPIRED is masked.
+        */
+       if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
+               enabled_intrs |= GEN6_PM_RP_UP_EI_EXPIRED;
+
+       I915_WRITE(GEN6_PMINTRMSK, ~enabled_intrs);
 }
 
 static void gen6_enable_rps(struct drm_device *dev)
@@ -4950,8 +4960,6 @@ static void haswell_init_clock_gating(struct drm_device *dev)
                        I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
                        GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
 
-       g4x_disable_trickle_feed(dev);
-
        /* WaVSRefCountFullforceMissDisable:hsw */
        gen7_setup_fixed_func_scheduler(dev_priv);
 
index f05cceac5a52326ad203bb234816cbd2f6c4bb04..460ee1026fcad63249e83af59da0353b40b04460 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
-/*
- * 965+ support PIPE_CONTROL commands, which provide finer grained control
- * over cache flushing.
- */
-struct pipe_control {
-       struct drm_i915_gem_object *obj;
-       volatile u32 *cpu_page;
-       u32 gtt_offset;
-};
-
 static inline int ring_space(struct intel_ring_buffer *ring)
 {
        int space = (ring->head & HEAD_ADDR) - (ring->tail + I915_RING_FREE_SPACE);
@@ -175,8 +165,7 @@ gen4_render_ring_flush(struct intel_ring_buffer *ring,
 static int
 intel_emit_post_sync_nonzero_flush(struct intel_ring_buffer *ring)
 {
-       struct pipe_control *pc = ring->private;
-       u32 scratch_addr = pc->gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 128;
        int ret;
 
 
@@ -213,8 +202,7 @@ gen6_render_ring_flush(struct intel_ring_buffer *ring,
                          u32 invalidate_domains, u32 flush_domains)
 {
        u32 flags = 0;
-       struct pipe_control *pc = ring->private;
-       u32 scratch_addr = pc->gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 128;
        int ret;
 
        /* Force SNB workarounds for PIPE_CONTROL flushes */
@@ -306,8 +294,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
                       u32 invalidate_domains, u32 flush_domains)
 {
        u32 flags = 0;
-       struct pipe_control *pc = ring->private;
-       u32 scratch_addr = pc->gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 128;
        int ret;
 
        /*
@@ -481,68 +468,43 @@ out:
 static int
 init_pipe_control(struct intel_ring_buffer *ring)
 {
-       struct pipe_control *pc;
-       struct drm_i915_gem_object *obj;
        int ret;
 
-       if (ring->private)
+       if (ring->scratch.obj)
                return 0;
 
-       pc = kmalloc(sizeof(*pc), GFP_KERNEL);
-       if (!pc)
-               return -ENOMEM;
-
-       obj = i915_gem_alloc_object(ring->dev, 4096);
-       if (obj == NULL) {
+       ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096);
+       if (ring->scratch.obj == NULL) {
                DRM_ERROR("Failed to allocate seqno page\n");
                ret = -ENOMEM;
                goto err;
        }
 
-       i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
+       i915_gem_object_set_cache_level(ring->scratch.obj, I915_CACHE_LLC);
 
-       ret = i915_gem_obj_ggtt_pin(obj, 4096, true, false);
+       ret = i915_gem_obj_ggtt_pin(ring->scratch.obj, 4096, true, false);
        if (ret)
                goto err_unref;
 
-       pc->gtt_offset = i915_gem_obj_ggtt_offset(obj);
-       pc->cpu_page = kmap(sg_page(obj->pages->sgl));
-       if (pc->cpu_page == NULL) {
+       ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(ring->scratch.obj);
+       ring->scratch.cpu_page = kmap(sg_page(ring->scratch.obj->pages->sgl));
+       if (ring->scratch.cpu_page == NULL) {
                ret = -ENOMEM;
                goto err_unpin;
        }
 
        DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
-                        ring->name, pc->gtt_offset);
-
-       pc->obj = obj;
-       ring->private = pc;
+                        ring->name, ring->scratch.gtt_offset);
        return 0;
 
 err_unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_unpin(ring->scratch.obj);
 err_unref:
-       drm_gem_object_unreference(&obj->base);
+       drm_gem_object_unreference(&ring->scratch.obj->base);
 err:
-       kfree(pc);
        return ret;
 }
 
-static void
-cleanup_pipe_control(struct intel_ring_buffer *ring)
-{
-       struct pipe_control *pc = ring->private;
-       struct drm_i915_gem_object *obj;
-
-       obj = pc->obj;
-
-       kunmap(sg_page(obj->pages->sgl));
-       i915_gem_object_unpin(obj);
-       drm_gem_object_unreference(&obj->base);
-
-       kfree(pc);
-}
-
 static int init_render_ring(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
@@ -607,16 +569,16 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
 
-       if (!ring->private)
+       if (ring->scratch.obj == NULL)
                return;
 
-       if (HAS_BROKEN_CS_TLB(dev))
-               drm_gem_object_unreference(to_gem_object(ring->private));
-
-       if (INTEL_INFO(dev)->gen >= 5)
-               cleanup_pipe_control(ring);
+       if (INTEL_INFO(dev)->gen >= 5) {
+               kunmap(sg_page(ring->scratch.obj->pages->sgl));
+               i915_gem_object_unpin(ring->scratch.obj);
+       }
 
-       ring->private = NULL;
+       drm_gem_object_unreference(&ring->scratch.obj->base);
+       ring->scratch.obj = NULL;
 }
 
 static void
@@ -742,8 +704,7 @@ do {                                                                        \
 static int
 pc_render_add_request(struct intel_ring_buffer *ring)
 {
-       struct pipe_control *pc = ring->private;
-       u32 scratch_addr = pc->gtt_offset + 128;
+       u32 scratch_addr = ring->scratch.gtt_offset + 128;
        int ret;
 
        /* For Ironlake, MI_USER_INTERRUPT was deprecated and apparently
@@ -761,7 +722,7 @@ pc_render_add_request(struct intel_ring_buffer *ring)
        intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE |
                        PIPE_CONTROL_WRITE_FLUSH |
                        PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
-       intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
+       intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
        intel_ring_emit(ring, ring->outstanding_lazy_request);
        intel_ring_emit(ring, 0);
        PIPE_CONTROL_FLUSH(ring, scratch_addr);
@@ -780,7 +741,7 @@ pc_render_add_request(struct intel_ring_buffer *ring)
                        PIPE_CONTROL_WRITE_FLUSH |
                        PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
                        PIPE_CONTROL_NOTIFY);
-       intel_ring_emit(ring, pc->gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
+       intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
        intel_ring_emit(ring, ring->outstanding_lazy_request);
        intel_ring_emit(ring, 0);
        intel_ring_advance(ring);
@@ -814,15 +775,13 @@ ring_set_seqno(struct intel_ring_buffer *ring, u32 seqno)
 static u32
 pc_render_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
 {
-       struct pipe_control *pc = ring->private;
-       return pc->cpu_page[0];
+       return ring->scratch.cpu_page[0];
 }
 
 static void
 pc_render_set_seqno(struct intel_ring_buffer *ring, u32 seqno)
 {
-       struct pipe_control *pc = ring->private;
-       pc->cpu_page[0] = seqno;
+       ring->scratch.cpu_page[0] = seqno;
 }
 
 static bool
@@ -1141,8 +1100,7 @@ i830_dispatch_execbuffer(struct intel_ring_buffer *ring,
                intel_ring_emit(ring, MI_NOOP);
                intel_ring_advance(ring);
        } else {
-               struct drm_i915_gem_object *obj = ring->private;
-               u32 cs_offset = i915_gem_obj_ggtt_offset(obj);
+               u32 cs_offset = ring->scratch.gtt_offset;
 
                if (len > I830_BATCH_LIMIT)
                        return -ENOSPC;
@@ -1835,7 +1793,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                        return ret;
                }
 
-               ring->private = obj;
+               ring->scratch.obj = obj;
+               ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
        }
 
        return intel_init_ring_buffer(dev, ring);
index 432ad5311ba62693633f79d6c5d59429704ac1cb..68b1ca974d594dc483827fdc0dba724563a07f8d 100644 (file)
@@ -155,7 +155,11 @@ struct  intel_ring_buffer {
 
        struct intel_ring_hangcheck hangcheck;
 
-       void *private;
+       struct {
+               struct drm_i915_gem_object *obj;
+               u32 gtt_offset;
+               volatile u32 *cpu_page;
+       } scratch;
 };
 
 static inline bool
index 317e058fb3cf1205563c3a57079ae99e4bc0d3dc..85037b9d4934d406306634c486ed93cc92b771f3 100644 (file)
@@ -1151,11 +1151,10 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
 {
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_crtc *crtc = intel_encoder->base.crtc;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc);
        struct drm_display_mode *adjusted_mode =
-               &intel_crtc->config.adjusted_mode;
-       struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
+               &crtc->config.adjusted_mode;
+       struct drm_display_mode *mode = &crtc->config.requested_mode;
        struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
        u32 sdvox;
        struct intel_sdvo_in_out_map in_out;
@@ -1213,13 +1212,15 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
         * adjusted_mode.
         */
        intel_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
+       input_dtd.part1.clock /= crtc->config.pixel_multiplier;
+
        if (intel_sdvo->is_tv || intel_sdvo->is_lvds)
                input_dtd.part2.sdvo_flags = intel_sdvo->dtd_sdvo_flags;
        if (!intel_sdvo_set_input_timing(intel_sdvo, &input_dtd))
                DRM_INFO("Setting input timings on %s failed\n",
                         SDVO_NAME(intel_sdvo));
 
-       switch (intel_crtc->config.pixel_multiplier) {
+       switch (crtc->config.pixel_multiplier) {
        default:
                WARN(1, "unknown pixel mutlipler specified\n");
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
@@ -1252,9 +1253,9 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
        }
 
        if (INTEL_PCH_TYPE(dev) >= PCH_CPT)
-               sdvox |= SDVO_PIPE_SEL_CPT(intel_crtc->pipe);
+               sdvox |= SDVO_PIPE_SEL_CPT(crtc->pipe);
        else
-               sdvox |= SDVO_PIPE_SEL(intel_crtc->pipe);
+               sdvox |= SDVO_PIPE_SEL(crtc->pipe);
 
        if (intel_sdvo->has_hdmi_audio)
                sdvox |= SDVO_AUDIO_ENABLE;
@@ -1264,7 +1265,7 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
        } else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
                /* done in crtc_mode_set as it lives inside the dpll register */
        } else {
-               sdvox |= (intel_crtc->config.pixel_multiplier - 1)
+               sdvox |= (crtc->config.pixel_multiplier - 1)
                        << SDVO_PORT_MULTIPLY_SHIFT;
        }
 
index 78b621cdd108f13ae061c27a1499df71c84da5bd..ad6ec4b39005e8c6bfe6a41f65be48eaf4c7ebc6 100644 (file)
@@ -260,8 +260,11 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (obj->tiling_mode != I915_TILING_NONE)
                sprctl |= SPRITE_TILED;
 
-       /* must disable */
-       sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
+       if (IS_HASWELL(dev))
+               sprctl &= ~SPRITE_TRICKLE_FEED_DISABLE;
+       else
+               sprctl |= SPRITE_TRICKLE_FEED_DISABLE;
+
        sprctl |= SPRITE_ENABLE;
 
        if (IS_HASWELL(dev))
index 8f5bc869c02373402ce5c3d03197137adaee75e8..8649f1c36b007f89ea5b2bbf8bf3bb26090d9f52 100644 (file)
@@ -261,7 +261,7 @@ void intel_uncore_init(struct drm_device *dev)
        }
 }
 
-void intel_uncore_sanitize(struct drm_device *dev)
+static void intel_uncore_forcewake_reset(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -272,6 +272,11 @@ void intel_uncore_sanitize(struct drm_device *dev)
                if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
                        __gen6_gt_force_wake_mt_reset(dev_priv);
        }
+}
+
+void intel_uncore_sanitize(struct drm_device *dev)
+{
+       intel_uncore_forcewake_reset(dev);
 
        /* BIOS often leaves RC6 enabled, but disable it for hw init */
        intel_disable_gt_powersave(dev);
@@ -549,6 +554,8 @@ static int gen6_do_reset(struct drm_device *dev)
        /* Spin waiting for the device to ack the reset request */
        ret = wait_for((__raw_i915_read32(dev_priv, GEN6_GDRST) & GEN6_GRDOM_FULL) == 0, 500);
 
+       intel_uncore_forcewake_reset(dev);
+
        /* If reset with a user forcewake, try to restore, otherwise turn it off */
        if (dev_priv->uncore.forcewake_count)
                dev_priv->uncore.funcs.force_wake_get(dev_priv);
index 2e11ea02cf879ea1d99dcb6c45450bd821bbb13f..57cda2a1437b0d2076d0661d5202ec73337e0ad8 100644 (file)
@@ -579,8 +579,22 @@ static void
 init_reserved(struct nvbios_init *init)
 {
        u8 opcode = nv_ro08(init->bios, init->offset);
-       trace("RESERVED\t0x%02x\n", opcode);
-       init->offset += 1;
+       u8 length, i;
+
+       switch (opcode) {
+       case 0xaa:
+               length = 4;
+               break;
+       default:
+               length = 1;
+               break;
+       }
+
+       trace("RESERVED 0x%02x\t", opcode);
+       for (i = 1; i < length; i++)
+               cont(" 0x%02x", nv_ro08(init->bios, init->offset + i));
+       cont("\n");
+       init->offset += length;
 }
 
 /**
@@ -1437,7 +1451,7 @@ init_configure_mem(struct nvbios_init *init)
        data = init_rdvgai(init, 0x03c4, 0x01);
        init_wrvgai(init, 0x03c4, 0x01, data | 0x20);
 
-       while ((addr = nv_ro32(bios, sdata)) != 0xffffffff) {
+       for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) {
                switch (addr) {
                case 0x10021c: /* CKE_NORMAL */
                case 0x1002d0: /* CMD_REFRESH */
@@ -2135,6 +2149,7 @@ static struct nvbios_init_opcode {
        [0x99] = { init_zm_auxch },
        [0x9a] = { init_i2c_long_if },
        [0xa9] = { init_gpio_ne },
+       [0xaa] = { init_reserved },
 };
 
 #define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0]))
index d2712e6e5d313030baeaa4873a1553def7bffe93..7848590f5568e4142457a0f121d9282ca6d1ae17 100644 (file)
@@ -278,7 +278,6 @@ nouveau_display_create(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_display *disp;
-       u32 pclass = dev->pdev->class >> 8;
        int ret, gen;
 
        disp = drm->display = kzalloc(sizeof(*disp), GFP_KERNEL);
@@ -340,29 +339,25 @@ nouveau_display_create(struct drm_device *dev)
        drm_kms_helper_poll_init(dev);
        drm_kms_helper_poll_disable(dev);
 
-       if (nouveau_modeset == 1 ||
-           (nouveau_modeset < 0 && pclass == PCI_CLASS_DISPLAY_VGA)) {
-               if (drm->vbios.dcb.entries) {
-                       if (nv_device(drm->device)->card_type < NV_50)
-                               ret = nv04_display_create(dev);
-                       else
-                               ret = nv50_display_create(dev);
-               } else {
-                       ret = 0;
-               }
-
-               if (ret)
-                       goto disp_create_err;
+       if (drm->vbios.dcb.entries) {
+               if (nv_device(drm->device)->card_type < NV_50)
+                       ret = nv04_display_create(dev);
+               else
+                       ret = nv50_display_create(dev);
+       } else {
+               ret = 0;
+       }
 
-               if (dev->mode_config.num_crtc) {
-                       ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
-                       if (ret)
-                               goto vblank_err;
-               }
+       if (ret)
+               goto disp_create_err;
 
-               nouveau_backlight_init(dev);
+       if (dev->mode_config.num_crtc) {
+               ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
+               if (ret)
+                       goto vblank_err;
        }
 
+       nouveau_backlight_init(dev);
        return 0;
 
 vblank_err:
index 8863644024b78b71d97451d9f6f9407c9c551fe3..e893c53624024751930f51c28517546d7fc7cb9d 100644 (file)
@@ -636,7 +636,8 @@ int nouveau_pmops_resume(struct device *dev)
                nouveau_fbcon_set_suspend(drm_dev, 0);
 
        nouveau_fbcon_zfill_all(drm_dev);
-       nouveau_display_resume(drm_dev);
+       if (drm_dev->mode_config.num_crtc)
+               nouveau_display_resume(drm_dev);
        nv_suspend_set_printk_level(NV_DBG_DEBUG);
        return 0;
 }
@@ -671,7 +672,8 @@ static int nouveau_pmops_thaw(struct device *dev)
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 0);
        nouveau_fbcon_zfill_all(drm_dev);
-       nouveau_display_resume(drm_dev);
+       if (drm_dev->mode_config.num_crtc)
+               nouveau_display_resume(drm_dev);
        nv_suspend_set_printk_level(NV_DBG_DEBUG);
        return 0;
 }
@@ -906,7 +908,8 @@ static int nouveau_pmops_runtime_resume(struct device *dev)
        pci_set_master(pdev);
 
        ret = nouveau_do_resume(drm_dev);
-       nouveau_display_resume(drm_dev);
+       if (drm_dev->mode_config.num_crtc)
+               nouveau_display_resume(drm_dev);
        drm_kms_helper_poll_enable(drm_dev);
        /* do magic */
        nv_mask(device, 0x88488, (1 << 25), (1 << 25));
index 8f6d63d7edd314c4f6a6ff7e492c3b37be88930e..a86ecf65c1642b2372e9a0e0136a69c7b068e041 100644 (file)
@@ -454,7 +454,8 @@ nouveau_fbcon_init(struct drm_device *dev)
        int preferred_bpp;
        int ret;
 
-       if (!dev->mode_config.num_crtc)
+       if (!dev->mode_config.num_crtc ||
+           (dev->pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
                return 0;
 
        fbcon = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL);
index ca5492ac2da53bb792425f4d0ae9c0758d0cde96..0843ebc910d4d6062ce94023f70dde1f1cc00ea0 100644 (file)
@@ -104,9 +104,7 @@ nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev,
        else
                nvbe->ttm.ttm.func = &nv50_sgdma_backend;
 
-       if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page)) {
-               kfree(nvbe);
+       if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page))
                return NULL;
-       }
        return &nvbe->ttm.ttm;
 }
index dfac7965ea28002b562a4838e143c9ea66501e93..32923d2f60021105a5092826bcd7810ca054c960 100644 (file)
@@ -707,8 +707,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        switch (connector->connector_type) {
        case DRM_MODE_CONNECTOR_DVII:
        case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */
-               if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                   radeon_audio)
+               if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) ||
+                   (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                    (radeon_connector->audio == RADEON_AUDIO_AUTO)))
                        return ATOM_ENCODER_MODE_HDMI;
                else if (radeon_connector->use_digital)
                        return ATOM_ENCODER_MODE_DVI;
@@ -718,8 +719,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
        case DRM_MODE_CONNECTOR_DVID:
        case DRM_MODE_CONNECTOR_HDMIA:
        default:
-               if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                   radeon_audio)
+               if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) ||
+                   (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                    (radeon_connector->audio == RADEON_AUDIO_AUTO)))
                        return ATOM_ENCODER_MODE_HDMI;
                else
                        return ATOM_ENCODER_MODE_DVI;
@@ -732,8 +734,9 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
                if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
                    (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP))
                        return ATOM_ENCODER_MODE_DP;
-               else if (drm_detect_hdmi_monitor(radeon_connector->edid) &&
-                        radeon_audio)
+               else if ((radeon_connector->audio == RADEON_AUDIO_ENABLE) ||
+                        (drm_detect_hdmi_monitor(radeon_connector->edid) &&
+                         (radeon_connector->audio == RADEON_AUDIO_AUTO)))
                        return ATOM_ENCODER_MODE_HDMI;
                else
                        return ATOM_ENCODER_MODE_DVI;
@@ -1647,8 +1650,12 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
                        atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
-                       /* some early dce3.2 boards have a bug in their transmitter control table */
-                       if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730))
+                       /* some dce3.x boards have a bug in their transmitter control table.
+                        * ACTION_ENABLE_OUTPUT can probably be dropped since ACTION_ENABLE
+                        * does the same thing and more.
+                        */
+                       if ((rdev->family != CHIP_RV710) && (rdev->family != CHIP_RV730) &&
+                           (rdev->family != CHIP_RS880))
                                atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0);
                }
                if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
index 084e69414fd15405d03417b0e73ab8e8f1488c58..05ff315e8e9e03f4d2ba242b4680894cea8632cd 100644 (file)
@@ -2340,12 +2340,6 @@ int btc_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-       ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
-       if (ret) {
-               DRM_ERROR("rv770_dpm_force_performance_level failed\n");
-               return ret;
-       }
-
        return 0;
 }
 
index 3cce533397c6583e345bd27cc79bd6b725926097..8996274430303ab3c2137b080381df612f3f181b 100644 (file)
@@ -4748,12 +4748,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
        if (pi->pcie_performance_request)
                ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
-       ret = ci_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
-       if (ret) {
-               DRM_ERROR("ci_dpm_force_performance_level failed\n");
-               return ret;
-       }
-
        cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
                             RADEON_CG_BLOCK_MC |
                             RADEON_CG_BLOCK_SDMA |
index 53b43dd3cf1eb40d5dffcab0e5f0376346e0f14b..252e10a41cf5a065872ee50597a7e5f2b2e3035d 100644 (file)
@@ -47,10 +47,11 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev,
                         u32 smc_start_address,
                         const u8 *src, u32 byte_count, u32 limit)
 {
+       unsigned long flags;
        u32 data, original_data;
        u32 addr;
        u32 extra_shift;
-       int ret;
+       int ret = 0;
 
        if (smc_start_address & 3)
                return -EINVAL;
@@ -59,13 +60,14 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev,
 
        addr = smc_start_address;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        while (byte_count >= 4) {
                /* SMC address space is BE */
                data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
 
                ret = ci_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                WREG32(SMC_IND_DATA_0, data);
 
@@ -80,7 +82,7 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev,
 
                ret = ci_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                original_data = RREG32(SMC_IND_DATA_0);
 
@@ -97,11 +99,15 @@ int ci_copy_bytes_to_smc(struct radeon_device *rdev,
 
                ret = ci_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                WREG32(SMC_IND_DATA_0, data);
        }
-       return 0;
+
+done:
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
+
+       return ret;
 }
 
 void ci_start_smc(struct radeon_device *rdev)
@@ -197,6 +203,7 @@ PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
 
 int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
 {
+       unsigned long flags;
        u32 ucode_start_address;
        u32 ucode_size;
        const u8 *src;
@@ -219,6 +226,7 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
                return -EINVAL;
 
        src = (const u8 *)rdev->smc_fw->data;
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        WREG32(SMC_IND_INDEX_0, ucode_start_address);
        WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
        while (ucode_size >= 4) {
@@ -231,6 +239,7 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
                ucode_size -= 4;
        }
        WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
        return 0;
 }
@@ -238,25 +247,29 @@ int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
 int ci_read_smc_sram_dword(struct radeon_device *rdev,
                           u32 smc_address, u32 *value, u32 limit)
 {
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        ret = ci_set_smc_sram_address(rdev, smc_address, limit);
-       if (ret)
-               return ret;
+       if (ret == 0)
+               *value = RREG32(SMC_IND_DATA_0);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
-       *value = RREG32(SMC_IND_DATA_0);
-       return 0;
+       return ret;
 }
 
 int ci_write_smc_sram_dword(struct radeon_device *rdev,
                            u32 smc_address, u32 value, u32 limit)
 {
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        ret = ci_set_smc_sram_address(rdev, smc_address, limit);
-       if (ret)
-               return ret;
+       if (ret == 0)
+               WREG32(SMC_IND_DATA_0, value);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
-       WREG32(SMC_IND_DATA_0, value);
-       return 0;
+       return ret;
 }
index a3bba05872769fa77d1561681de9639aae95acf9..adbdb6503b0564b98867d67ac513b0d02f602054 100644 (file)
@@ -77,6 +77,8 @@ static void cik_pcie_gen3_enable(struct radeon_device *rdev);
 static void cik_program_aspm(struct radeon_device *rdev);
 static void cik_init_pg(struct radeon_device *rdev);
 static void cik_init_cg(struct radeon_device *rdev);
+static void cik_enable_gui_idle_interrupt(struct radeon_device *rdev,
+                                         bool enable);
 
 /* get temperature in millidegrees */
 int ci_get_temp(struct radeon_device *rdev)
@@ -120,20 +122,27 @@ int kv_get_temp(struct radeon_device *rdev)
  */
 u32 cik_pciep_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->pciep_idx_lock, flags);
        WREG32(PCIE_INDEX, reg);
        (void)RREG32(PCIE_INDEX);
        r = RREG32(PCIE_DATA);
+       spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags);
        return r;
 }
 
 void cik_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->pciep_idx_lock, flags);
        WREG32(PCIE_INDEX, reg);
        (void)RREG32(PCIE_INDEX);
        WREG32(PCIE_DATA, v);
        (void)RREG32(PCIE_DATA);
+       spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags);
 }
 
 static const u32 spectre_rlc_save_restore_register_list[] =
@@ -2722,7 +2731,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
                } else if ((rdev->pdev->device == 0x1309) ||
                           (rdev->pdev->device == 0x130A) ||
                           (rdev->pdev->device == 0x130D) ||
-                          (rdev->pdev->device == 0x1313)) {
+                          (rdev->pdev->device == 0x1313) ||
+                          (rdev->pdev->device == 0x131D)) {
                        rdev->config.cik.max_cu_per_sh = 6;
                        rdev->config.cik.max_backends_per_se = 2;
                } else if ((rdev->pdev->device == 0x1306) ||
@@ -4013,6 +4023,8 @@ static int cik_cp_resume(struct radeon_device *rdev)
 {
        int r;
 
+       cik_enable_gui_idle_interrupt(rdev, false);
+
        r = cik_cp_load_microcode(rdev);
        if (r)
                return r;
@@ -4024,6 +4036,8 @@ static int cik_cp_resume(struct radeon_device *rdev)
        if (r)
                return r;
 
+       cik_enable_gui_idle_interrupt(rdev, true);
+
        return 0;
 }
 
@@ -5376,7 +5390,9 @@ static void cik_enable_hdp_ls(struct radeon_device *rdev,
 void cik_update_cg(struct radeon_device *rdev,
                   u32 block, bool enable)
 {
+
        if (block & RADEON_CG_BLOCK_GFX) {
+               cik_enable_gui_idle_interrupt(rdev, false);
                /* order matters! */
                if (enable) {
                        cik_enable_mgcg(rdev, true);
@@ -5385,6 +5401,7 @@ void cik_update_cg(struct radeon_device *rdev,
                        cik_enable_cgcg(rdev, false);
                        cik_enable_mgcg(rdev, false);
                }
+               cik_enable_gui_idle_interrupt(rdev, true);
        }
 
        if (block & RADEON_CG_BLOCK_MC) {
@@ -5541,7 +5558,7 @@ static void cik_enable_gfx_cgpg(struct radeon_device *rdev,
 {
        u32 data, orig;
 
-       if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_CG)) {
+       if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG)) {
                orig = data = RREG32(RLC_PG_CNTL);
                data |= GFX_PG_ENABLE;
                if (orig != data)
@@ -5805,7 +5822,7 @@ static void cik_init_pg(struct radeon_device *rdev)
        if (rdev->pg_flags) {
                cik_enable_sck_slowdown_on_pu(rdev, true);
                cik_enable_sck_slowdown_on_pd(rdev, true);
-               if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_CG) {
+               if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) {
                        cik_init_gfx_cgpg(rdev);
                        cik_enable_cp_pg(rdev, true);
                        cik_enable_gds_pg(rdev, true);
@@ -5819,7 +5836,7 @@ static void cik_fini_pg(struct radeon_device *rdev)
 {
        if (rdev->pg_flags) {
                cik_update_gfx_pg(rdev, false);
-               if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_CG) {
+               if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) {
                        cik_enable_cp_pg(rdev, false);
                        cik_enable_gds_pg(rdev, false);
                }
@@ -5895,7 +5912,9 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)
        u32 tmp;
 
        /* gfx ring */
-       WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       tmp = RREG32(CP_INT_CNTL_RING0) &
+               (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       WREG32(CP_INT_CNTL_RING0, tmp);
        /* sdma */
        tmp = RREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
        WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, tmp);
@@ -6036,8 +6055,7 @@ static int cik_irq_init(struct radeon_device *rdev)
  */
 int cik_irq_set(struct radeon_device *rdev)
 {
-       u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE |
-               PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+       u32 cp_int_cntl;
        u32 cp_m1p0, cp_m1p1, cp_m1p2, cp_m1p3;
        u32 cp_m2p0, cp_m2p1, cp_m2p2, cp_m2p3;
        u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
@@ -6058,6 +6076,10 @@ int cik_irq_set(struct radeon_device *rdev)
                return 0;
        }
 
+       cp_int_cntl = RREG32(CP_INT_CNTL_RING0) &
+               (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       cp_int_cntl |= PRIV_INSTR_INT_ENABLE | PRIV_REG_INT_ENABLE;
+
        hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
        hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
        hpd3 = RREG32(DC_HPD3_INT_CONTROL) & ~DC_HPDx_INT_EN;
index 95a66db08d9bedabe1b9564fe53939acc7ecca43..91bb470de0a39e4db9713cb58b356a9b6ccbac86 100644 (file)
@@ -2014,12 +2014,6 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
        if (eg_pi->pcie_performance_request)
                cypress_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
-       ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
-       if (ret) {
-               DRM_ERROR("rv770_dpm_force_performance_level failed\n");
-               return ret;
-       }
-
        return 0;
 }
 
index 8953255e894b2524e020fd10b99898eceedfd4c9..85a69d2ea3d2c8d86c9c552902d260dd576ac927 100644 (file)
 static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
                              u32 block_offset, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->end_idx_lock, flags);
        WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
        r = RREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset);
+       spin_unlock_irqrestore(&rdev->end_idx_lock, flags);
+
        return r;
 }
 
 static void dce6_endpoint_wreg(struct radeon_device *rdev,
                               u32 block_offset, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->end_idx_lock, flags);
        if (ASIC_IS_DCE8(rdev))
                WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset, reg);
        else
                WREG32(AZ_F0_CODEC_ENDPOINT_INDEX + block_offset,
                       AZ_ENDPOINT_REG_WRITE_EN | AZ_ENDPOINT_REG_INDEX(reg));
        WREG32(AZ_F0_CODEC_ENDPOINT_DATA + block_offset, v);
+       spin_unlock_irqrestore(&rdev->end_idx_lock, flags);
 }
 
 #define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg))
@@ -86,12 +94,12 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
        struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
        u32 offset = dig->afmt->offset;
-       u32 id = dig->afmt->pin->id;
 
        if (!dig->afmt->pin)
                return;
 
-       WREG32(AFMT_AUDIO_SRC_CONTROL + offset, AFMT_AUDIO_SRC_SELECT(id));
+       WREG32(AFMT_AUDIO_SRC_CONTROL + offset,
+              AFMT_AUDIO_SRC_SELECT(dig->afmt->pin->id));
 }
 
 void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
index ecd60809db4ec700910a5451f27b8979febc5ec7..71399065db04d309104b98ede05b69226ad3b271 100644 (file)
@@ -40,6 +40,7 @@ static int kv_calculate_dpm_settings(struct radeon_device *rdev);
 static void kv_enable_new_levels(struct radeon_device *rdev);
 static void kv_program_nbps_index_settings(struct radeon_device *rdev,
                                           struct radeon_ps *new_rps);
+static int kv_set_enabled_level(struct radeon_device *rdev, u32 level);
 static int kv_set_enabled_levels(struct radeon_device *rdev);
 static int kv_force_dpm_highest(struct radeon_device *rdev);
 static int kv_force_dpm_lowest(struct radeon_device *rdev);
@@ -519,7 +520,7 @@ static int kv_set_dpm_boot_state(struct radeon_device *rdev)
 
 static void kv_program_vc(struct radeon_device *rdev)
 {
-       WREG32_SMC(CG_FTV_0, 0x3FFFC000);
+       WREG32_SMC(CG_FTV_0, 0x3FFFC100);
 }
 
 static void kv_clear_vc(struct radeon_device *rdev)
@@ -638,7 +639,10 @@ static int kv_force_lowest_valid(struct radeon_device *rdev)
 
 static int kv_unforce_levels(struct radeon_device *rdev)
 {
-       return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
+       if (rdev->family == CHIP_KABINI)
+               return kv_notify_message_to_smu(rdev, PPSMC_MSG_NoForcedLevel);
+       else
+               return kv_set_enabled_levels(rdev);
 }
 
 static int kv_update_sclk_t(struct radeon_device *rdev)
@@ -667,9 +671,8 @@ static int kv_program_bootup_state(struct radeon_device *rdev)
                &rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk;
 
        if (table && table->count) {
-               for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) {
-                       if ((table->entries[i].clk == pi->boot_pl.sclk) ||
-                           (i == 0))
+               for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
+                       if (table->entries[i].clk == pi->boot_pl.sclk)
                                break;
                }
 
@@ -682,9 +685,8 @@ static int kv_program_bootup_state(struct radeon_device *rdev)
                if (table->num_max_dpm_entries == 0)
                        return -EINVAL;
 
-               for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) {
-                       if ((table->entries[i].sclk_frequency == pi->boot_pl.sclk) ||
-                           (i == 0))
+               for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
+                       if (table->entries[i].sclk_frequency == pi->boot_pl.sclk)
                                break;
                }
 
@@ -1078,6 +1080,13 @@ static int kv_enable_ulv(struct radeon_device *rdev, bool enable)
                                        PPSMC_MSG_EnableULV : PPSMC_MSG_DisableULV);
 }
 
+static void kv_reset_acp_boot_level(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+
+       pi->acp_boot_level = 0xff;
+}
+
 static void kv_update_current_ps(struct radeon_device *rdev,
                                 struct radeon_ps *rps)
 {
@@ -1100,6 +1109,18 @@ static void kv_update_requested_ps(struct radeon_device *rdev,
        pi->requested_rps.ps_priv = &pi->requested_ps;
 }
 
+void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+       int ret;
+
+       if (pi->bapm_enable) {
+               ret = kv_smc_bapm_enable(rdev, enable);
+               if (ret)
+                       DRM_ERROR("kv_smc_bapm_enable failed\n");
+       }
+}
+
 int kv_dpm_enable(struct radeon_device *rdev)
 {
        struct kv_power_info *pi = kv_get_pi(rdev);
@@ -1192,6 +1213,8 @@ int kv_dpm_enable(struct radeon_device *rdev)
                return ret;
        }
 
+       kv_reset_acp_boot_level(rdev);
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
                ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
@@ -1203,6 +1226,12 @@ int kv_dpm_enable(struct radeon_device *rdev)
                radeon_irq_set(rdev);
        }
 
+       ret = kv_smc_bapm_enable(rdev, false);
+       if (ret) {
+               DRM_ERROR("kv_smc_bapm_enable failed\n");
+               return ret;
+       }
+
        /* powerdown unused blocks for now */
        kv_dpm_powergate_acp(rdev, true);
        kv_dpm_powergate_samu(rdev, true);
@@ -1226,6 +1255,8 @@ void kv_dpm_disable(struct radeon_device *rdev)
                             RADEON_CG_BLOCK_BIF |
                             RADEON_CG_BLOCK_HDP), false);
 
+       kv_smc_bapm_enable(rdev, false);
+
        /* powerup blocks */
        kv_dpm_powergate_acp(rdev, false);
        kv_dpm_powergate_samu(rdev, false);
@@ -1450,6 +1481,39 @@ static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate)
        return kv_enable_samu_dpm(rdev, !gate);
 }
 
+static u8 kv_get_acp_boot_level(struct radeon_device *rdev)
+{
+       u8 i;
+       struct radeon_clock_voltage_dependency_table *table =
+               &rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table;
+
+       for (i = 0; i < table->count; i++) {
+               if (table->entries[i].clk >= 0) /* XXX */
+                       break;
+       }
+
+       if (i >= table->count)
+               i = table->count - 1;
+
+       return i;
+}
+
+static void kv_update_acp_boot_level(struct radeon_device *rdev)
+{
+       struct kv_power_info *pi = kv_get_pi(rdev);
+       u8 acp_boot_level;
+
+       if (!pi->caps_stable_p_state) {
+               acp_boot_level = kv_get_acp_boot_level(rdev);
+               if (acp_boot_level != pi->acp_boot_level) {
+                       pi->acp_boot_level = acp_boot_level;
+                       kv_send_msg_to_smc_with_parameter(rdev,
+                                                         PPSMC_MSG_ACPDPM_SetEnabledMask,
+                                                         (1 << pi->acp_boot_level));
+               }
+       }
+}
+
 static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate)
 {
        struct kv_power_info *pi = kv_get_pi(rdev);
@@ -1461,7 +1525,7 @@ static int kv_update_acp_dpm(struct radeon_device *rdev, bool gate)
                if (pi->caps_stable_p_state)
                        pi->acp_boot_level = table->count - 1;
                else
-                       pi->acp_boot_level = 0;
+                       pi->acp_boot_level = kv_get_acp_boot_level(rdev);
 
                ret = kv_copy_bytes_to_smc(rdev,
                                           pi->dpm_table_start +
@@ -1588,13 +1652,11 @@ static void kv_set_valid_clock_range(struct radeon_device *rdev,
                        }
                }
 
-               for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) {
-                       if ((table->entries[i].clk <= new_ps->levels[new_ps->num_levels -1].sclk) ||
-                           (i == 0)) {
-                               pi->highest_valid = i;
+               for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
+                       if (table->entries[i].clk <= new_ps->levels[new_ps->num_levels - 1].sclk)
                                break;
-                       }
                }
+               pi->highest_valid = i;
 
                if (pi->lowest_valid > pi->highest_valid) {
                        if ((new_ps->levels[0].sclk - table->entries[pi->highest_valid].clk) >
@@ -1615,14 +1677,12 @@ static void kv_set_valid_clock_range(struct radeon_device *rdev,
                        }
                }
 
-               for (i = pi->graphics_dpm_level_count - 1; i >= 0; i--) {
+               for (i = pi->graphics_dpm_level_count - 1; i > 0; i--) {
                        if (table->entries[i].sclk_frequency <=
-                           new_ps->levels[new_ps->num_levels - 1].sclk ||
-                           i == 0) {
-                               pi->highest_valid = i;
+                           new_ps->levels[new_ps->num_levels - 1].sclk)
                                break;
-                       }
                }
+               pi->highest_valid = i;
 
                if (pi->lowest_valid > pi->highest_valid) {
                        if ((new_ps->levels[0].sclk -
@@ -1724,6 +1784,14 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
                             RADEON_CG_BLOCK_BIF |
                             RADEON_CG_BLOCK_HDP), false);
 
+       if (pi->bapm_enable) {
+               ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power);
+               if (ret) {
+                       DRM_ERROR("kv_smc_bapm_enable failed\n");
+                       return ret;
+               }
+       }
+
        if (rdev->family == CHIP_KABINI) {
                if (pi->enable_dpm) {
                        kv_set_valid_clock_range(rdev, new_ps);
@@ -1775,6 +1843,7 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
                                return ret;
                        }
 #endif
+                       kv_update_acp_boot_level(rdev);
                        kv_update_sclk_t(rdev);
                        kv_enable_nb_dpm(rdev);
                }
@@ -1785,7 +1854,6 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
                             RADEON_CG_BLOCK_BIF |
                             RADEON_CG_BLOCK_HDP), true);
 
-       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
        return 0;
 }
 
@@ -1806,12 +1874,23 @@ void kv_dpm_setup_asic(struct radeon_device *rdev)
 
 void kv_dpm_reset_asic(struct radeon_device *rdev)
 {
-       kv_force_lowest_valid(rdev);
-       kv_init_graphics_levels(rdev);
-       kv_program_bootup_state(rdev);
-       kv_upload_dpm_settings(rdev);
-       kv_force_lowest_valid(rdev);
-       kv_unforce_levels(rdev);
+       struct kv_power_info *pi = kv_get_pi(rdev);
+
+       if (rdev->family == CHIP_KABINI) {
+               kv_force_lowest_valid(rdev);
+               kv_init_graphics_levels(rdev);
+               kv_program_bootup_state(rdev);
+               kv_upload_dpm_settings(rdev);
+               kv_force_lowest_valid(rdev);
+               kv_unforce_levels(rdev);
+       } else {
+               kv_init_graphics_levels(rdev);
+               kv_program_bootup_state(rdev);
+               kv_freeze_sclk_dpm(rdev, true);
+               kv_upload_dpm_settings(rdev);
+               kv_freeze_sclk_dpm(rdev, false);
+               kv_set_enabled_level(rdev, pi->graphics_boot_level);
+       }
 }
 
 //XXX use sumo_dpm_display_configuration_changed
@@ -1871,12 +1950,15 @@ static int kv_force_dpm_highest(struct radeon_device *rdev)
        if (ret)
                return ret;
 
-       for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i >= 0; i--) {
+       for (i = SMU7_MAX_LEVELS_GRAPHICS - 1; i > 0; i--) {
                if (enable_mask & (1 << i))
                        break;
        }
 
-       return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);
+       if (rdev->family == CHIP_KABINI)
+               return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);
+       else
+               return kv_set_enabled_level(rdev, i);
 }
 
 static int kv_force_dpm_lowest(struct radeon_device *rdev)
@@ -1893,7 +1975,10 @@ static int kv_force_dpm_lowest(struct radeon_device *rdev)
                        break;
        }
 
-       return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);
+       if (rdev->family == CHIP_KABINI)
+               return kv_send_msg_to_smc_with_parameter(rdev, PPSMC_MSG_DPM_ForceState, i);
+       else
+               return kv_set_enabled_level(rdev, i);
 }
 
 static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
@@ -1911,9 +1996,9 @@ static u8 kv_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
        if (!pi->caps_sclk_ds)
                return 0;
 
-       for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i <= 0; i--) {
+       for (i = KV_MAX_DEEPSLEEP_DIVIDER_ID; i > 0; i--) {
                temp = sclk / sumo_get_sleep_divider_from_id(i);
-               if ((temp >= min) || (i == 0))
+               if (temp >= min)
                        break;
        }
 
@@ -2039,12 +2124,12 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,
                ps->dpmx_nb_ps_lo = 0x1;
                ps->dpmx_nb_ps_hi = 0x0;
        } else {
-               ps->dpm0_pg_nb_ps_lo = 0x1;
+               ps->dpm0_pg_nb_ps_lo = 0x3;
                ps->dpm0_pg_nb_ps_hi = 0x0;
-               ps->dpmx_nb_ps_lo = 0x2;
-               ps->dpmx_nb_ps_hi = 0x1;
+               ps->dpmx_nb_ps_lo = 0x3;
+               ps->dpmx_nb_ps_hi = 0x0;
 
-               if (pi->sys_info.nb_dpm_enable && pi->battery_state) {
+               if (pi->sys_info.nb_dpm_enable) {
                        force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) ||
                                pi->video_start || (rdev->pm.dpm.new_active_crtc_count >= 3) ||
                                pi->disable_nb_ps3_in_battery;
@@ -2210,6 +2295,15 @@ static void kv_enable_new_levels(struct radeon_device *rdev)
        }
 }
 
+static int kv_set_enabled_level(struct radeon_device *rdev, u32 level)
+{
+       u32 new_mask = (1 << level);
+
+       return kv_send_msg_to_smc_with_parameter(rdev,
+                                                PPSMC_MSG_SCLKDPM_SetEnabledMask,
+                                                new_mask);
+}
+
 static int kv_set_enabled_levels(struct radeon_device *rdev)
 {
        struct kv_power_info *pi = kv_get_pi(rdev);
index 32bb079572d757ab7b58309a506cf113ce2d1e41..8cef7525d7a87500f07ad709cd203c481d7b4350 100644 (file)
@@ -192,6 +192,7 @@ int kv_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
 int kv_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
                           u32 *value, u32 limit);
 int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable);
+int kv_smc_bapm_enable(struct radeon_device *rdev, bool enable);
 int kv_copy_bytes_to_smc(struct radeon_device *rdev,
                         u32 smc_start_address,
                         const u8 *src, u32 byte_count, u32 limit);
index 34a226d7e34aafc72649d77854f4e3a3a3844912..0000b59a6d0599c4c0e080f2a58815ee6c3e8f43 100644 (file)
@@ -107,6 +107,14 @@ int kv_smc_dpm_enable(struct radeon_device *rdev, bool enable)
                return kv_notify_message_to_smu(rdev, PPSMC_MSG_DPM_Disable);
 }
 
+int kv_smc_bapm_enable(struct radeon_device *rdev, bool enable)
+{
+       if (enable)
+               return kv_notify_message_to_smu(rdev, PPSMC_MSG_EnableBAPM);
+       else
+               return kv_notify_message_to_smu(rdev, PPSMC_MSG_DisableBAPM);
+}
+
 int kv_copy_bytes_to_smc(struct radeon_device *rdev,
                         u32 smc_start_address,
                         const u8 *src, u32 byte_count, u32 limit)
index f7b625c9e0e9cfa355ad27b0f1f2952bc9de8427..6c398a456d78b53668a73dbc82f369157c918647 100644 (file)
@@ -3865,12 +3865,6 @@ int ni_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-       ret = ni_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
-       if (ret) {
-               DRM_ERROR("ni_dpm_force_performance_level failed\n");
-               return ret;
-       }
-
        return 0;
 }
 
index 682842804bce3e47ffe5d961a0125747f132d6e1..5670b8291285d6827e87abd7a66b447ee774d315 100644 (file)
@@ -163,6 +163,8 @@ typedef uint8_t PPSMC_Result;
 #define PPSMC_MSG_VCEPowerON                ((uint32_t) 0x10f)
 #define PPSMC_MSG_DCE_RemoveVoltageAdjustment   ((uint32_t) 0x11d)
 #define PPSMC_MSG_DCE_AllowVoltageAdjustment    ((uint32_t) 0x11e)
+#define PPSMC_MSG_EnableBAPM                ((uint32_t) 0x120)
+#define PPSMC_MSG_DisableBAPM               ((uint32_t) 0x121)
 #define PPSMC_MSG_UVD_DPM_Config            ((uint32_t) 0x124)
 
 
index 9fc61dd68bc073b4b2fd82976caef85f66696c9c..24175717307bc23ca336f3e998df192f3036fccd 100644 (file)
@@ -2853,21 +2853,28 @@ static void r100_pll_errata_after_data(struct radeon_device *rdev)
 
 uint32_t r100_pll_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
        uint32_t data;
 
+       spin_lock_irqsave(&rdev->pll_idx_lock, flags);
        WREG8(RADEON_CLOCK_CNTL_INDEX, reg & 0x3f);
        r100_pll_errata_after_index(rdev);
        data = RREG32(RADEON_CLOCK_CNTL_DATA);
        r100_pll_errata_after_data(rdev);
+       spin_unlock_irqrestore(&rdev->pll_idx_lock, flags);
        return data;
 }
 
 void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->pll_idx_lock, flags);
        WREG8(RADEON_CLOCK_CNTL_INDEX, ((reg & 0x3f) | RADEON_PLL_WR_EN));
        r100_pll_errata_after_index(rdev);
        WREG32(RADEON_CLOCK_CNTL_DATA, v);
        r100_pll_errata_after_data(rdev);
+       spin_unlock_irqrestore(&rdev->pll_idx_lock, flags);
 }
 
 static void r100_set_safe_registers(struct radeon_device *rdev)
index 4e796ecf9ea4770e2388a56032cd135f5e861605..6edf2b3a52b4d7e4ba82cc063048ffb73733a984 100644 (file)
@@ -160,18 +160,25 @@ void r420_pipes_init(struct radeon_device *rdev)
 
 u32 r420_mc_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg));
        r = RREG32(R_0001FC_MC_IND_DATA);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
        return r;
 }
 
 void r420_mc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_0001F8_MC_IND_INDEX, S_0001F8_MC_IND_ADDR(reg) |
                S_0001F8_MC_IND_WR_EN(1));
        WREG32(R_0001FC_MC_IND_DATA, v);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
 }
 
 static void r420_debugfs(struct radeon_device *rdev)
index ea4d3734e6d9ce269efa5bb1eb98c7da5bccd819..2a1b1876b4312eb332c017cb027aeb346bf2c850 100644 (file)
@@ -119,6 +119,11 @@ u32 r600_get_xclk(struct radeon_device *rdev)
        return rdev->clock.spll.reference_freq;
 }
 
+int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
+{
+       return 0;
+}
+
 /* get temperature in millidegrees */
 int rv6xx_get_temp(struct radeon_device *rdev)
 {
@@ -1045,20 +1050,27 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev)
 
 uint32_t rs780_mc_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
        uint32_t r;
 
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg));
        r = RREG32(R_0028FC_MC_DATA);
        WREG32(R_0028F8_MC_INDEX, ~C_0028F8_MC_IND_ADDR);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
        return r;
 }
 
 void rs780_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_0028F8_MC_INDEX, S_0028F8_MC_IND_ADDR(reg) |
                S_0028F8_MC_IND_WR_EN(1));
        WREG32(R_0028FC_MC_DATA, v);
        WREG32(R_0028F8_MC_INDEX, 0x7F);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
 }
 
 static void r600_mc_program(struct radeon_device *rdev)
@@ -2092,20 +2104,27 @@ static void r600_gpu_init(struct radeon_device *rdev)
  */
 u32 r600_pciep_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->pciep_idx_lock, flags);
        WREG32(PCIE_PORT_INDEX, ((reg) & 0xff));
        (void)RREG32(PCIE_PORT_INDEX);
        r = RREG32(PCIE_PORT_DATA);
+       spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags);
        return r;
 }
 
 void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->pciep_idx_lock, flags);
        WREG32(PCIE_PORT_INDEX, ((reg) & 0xff));
        (void)RREG32(PCIE_PORT_INDEX);
        WREG32(PCIE_PORT_DATA, (v));
        (void)RREG32(PCIE_PORT_DATA);
+       spin_unlock_irqrestore(&rdev->pciep_idx_lock, flags);
 }
 
 /*
index fa0de46fcc0d1cc5d714f6c8c6cc8e0a958d8001..e65f211a7be016eb9e3fe09e550ff87e8a12ae9e 100644 (file)
@@ -1219,30 +1219,20 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
 
 void r600_free_extended_power_table(struct radeon_device *rdev)
 {
-       if (rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries)
-               kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries);
-       if (rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries)
-               kfree(rdev->pm.dpm.dyn_state.vddci_dependency_on_mclk.entries);
-       if (rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries)
-               kfree(rdev->pm.dpm.dyn_state.vddc_dependency_on_mclk.entries);
-       if (rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries)
-               kfree(rdev->pm.dpm.dyn_state.mvdd_dependency_on_mclk.entries);
-       if (rdev->pm.dpm.dyn_state.cac_leakage_table.entries)
-               kfree(rdev->pm.dpm.dyn_state.cac_leakage_table.entries);
-       if (rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries)
-               kfree(rdev->pm.dpm.dyn_state.phase_shedding_limits_table.entries);
-       if (rdev->pm.dpm.dyn_state.ppm_table)
-               kfree(rdev->pm.dpm.dyn_state.ppm_table);
-       if (rdev->pm.dpm.dyn_state.cac_tdp_table)
-               kfree(rdev->pm.dpm.dyn_state.cac_tdp_table);
-       if (rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries)
-               kfree(rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries);
-       if (rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries)
-               kfree(rdev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries);
-       if (rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries)
-               kfree(rdev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries);
-       if (rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries)
-               kfree(rdev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries);
+       struct radeon_dpm_dynamic_state *dyn_state = &rdev->pm.dpm.dyn_state;
+
+       kfree(dyn_state->vddc_dependency_on_sclk.entries);
+       kfree(dyn_state->vddci_dependency_on_mclk.entries);
+       kfree(dyn_state->vddc_dependency_on_mclk.entries);
+       kfree(dyn_state->mvdd_dependency_on_mclk.entries);
+       kfree(dyn_state->cac_leakage_table.entries);
+       kfree(dyn_state->phase_shedding_limits_table.entries);
+       kfree(dyn_state->ppm_table);
+       kfree(dyn_state->cac_tdp_table);
+       kfree(dyn_state->vce_clock_voltage_dependency_table.entries);
+       kfree(dyn_state->uvd_clock_voltage_dependency_table.entries);
+       kfree(dyn_state->samu_clock_voltage_dependency_table.entries);
+       kfree(dyn_state->acp_clock_voltage_dependency_table.entries);
 }
 
 enum radeon_pcie_gen r600_get_pcie_gen_support(struct radeon_device *rdev,
index 454f90a849e47d6ef6e6b87c0bf6c97d3a31b54f..e673fe26ea84d00b292f77c456089c4312372ab7 100644 (file)
 #       define HDMI0_AVI_INFO_CONT   (1 << 1)
 #       define HDMI0_AUDIO_INFO_SEND (1 << 4)
 #       define HDMI0_AUDIO_INFO_CONT (1 << 5)
-#       define HDMI0_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hmdi regs */
+#       define HDMI0_AUDIO_INFO_SOURCE (1 << 6) /* 0 - sound block; 1 - hdmi regs */
 #       define HDMI0_AUDIO_INFO_UPDATE (1 << 7)
 #       define HDMI0_MPEG_INFO_SEND  (1 << 8)
 #       define HDMI0_MPEG_INFO_CONT  (1 << 9)
index ff8b564ce2b2d37033de4b4795569beaad0903fa..a400ac1c414715423064874d37f047b426f7fe19 100644 (file)
@@ -181,7 +181,7 @@ extern int radeon_aspm;
 #define RADEON_CG_SUPPORT_HDP_MGCG             (1 << 16)
 
 /* PG flags */
-#define RADEON_PG_SUPPORT_GFX_CG               (1 << 0)
+#define RADEON_PG_SUPPORT_GFX_PG               (1 << 0)
 #define RADEON_PG_SUPPORT_GFX_SMG              (1 << 1)
 #define RADEON_PG_SUPPORT_GFX_DMG              (1 << 2)
 #define RADEON_PG_SUPPORT_UVD                  (1 << 3)
@@ -1778,6 +1778,7 @@ struct radeon_asic {
                int (*force_performance_level)(struct radeon_device *rdev, enum radeon_dpm_forced_level level);
                bool (*vblank_too_short)(struct radeon_device *rdev);
                void (*powergate_uvd)(struct radeon_device *rdev, bool gate);
+               void (*enable_bapm)(struct radeon_device *rdev, bool enable);
        } dpm;
        /* pageflipping */
        struct {
@@ -2110,6 +2111,28 @@ struct radeon_device {
        resource_size_t                 rmmio_size;
        /* protects concurrent MM_INDEX/DATA based register access */
        spinlock_t mmio_idx_lock;
+       /* protects concurrent SMC based register access */
+       spinlock_t smc_idx_lock;
+       /* protects concurrent PLL register access */
+       spinlock_t pll_idx_lock;
+       /* protects concurrent MC register access */
+       spinlock_t mc_idx_lock;
+       /* protects concurrent PCIE register access */
+       spinlock_t pcie_idx_lock;
+       /* protects concurrent PCIE_PORT register access */
+       spinlock_t pciep_idx_lock;
+       /* protects concurrent PIF register access */
+       spinlock_t pif_idx_lock;
+       /* protects concurrent CG register access */
+       spinlock_t cg_idx_lock;
+       /* protects concurrent UVD register access */
+       spinlock_t uvd_idx_lock;
+       /* protects concurrent RCU register access */
+       spinlock_t rcu_idx_lock;
+       /* protects concurrent DIDT register access */
+       spinlock_t didt_idx_lock;
+       /* protects concurrent ENDPOINT (audio) register access */
+       spinlock_t end_idx_lock;
        void __iomem                    *rmmio;
        radeon_rreg_t                   mc_rreg;
        radeon_wreg_t                   mc_wreg;
@@ -2277,123 +2300,179 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
  */
 static inline uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
        uint32_t r;
 
+       spin_lock_irqsave(&rdev->pcie_idx_lock, flags);
        WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask));
        r = RREG32(RADEON_PCIE_DATA);
+       spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags);
        return r;
 }
 
 static inline void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->pcie_idx_lock, flags);
        WREG32(RADEON_PCIE_INDEX, ((reg) & rdev->pcie_reg_mask));
        WREG32(RADEON_PCIE_DATA, (v));
+       spin_unlock_irqrestore(&rdev->pcie_idx_lock, flags);
 }
 
 static inline u32 tn_smc_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        WREG32(TN_SMC_IND_INDEX_0, (reg));
        r = RREG32(TN_SMC_IND_DATA_0);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
        return r;
 }
 
 static inline void tn_smc_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        WREG32(TN_SMC_IND_INDEX_0, (reg));
        WREG32(TN_SMC_IND_DATA_0, (v));
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 }
 
 static inline u32 r600_rcu_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->rcu_idx_lock, flags);
        WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
        r = RREG32(R600_RCU_DATA);
+       spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags);
        return r;
 }
 
 static inline void r600_rcu_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->rcu_idx_lock, flags);
        WREG32(R600_RCU_INDEX, ((reg) & 0x1fff));
        WREG32(R600_RCU_DATA, (v));
+       spin_unlock_irqrestore(&rdev->rcu_idx_lock, flags);
 }
 
 static inline u32 eg_cg_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->cg_idx_lock, flags);
        WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
        r = RREG32(EVERGREEN_CG_IND_DATA);
+       spin_unlock_irqrestore(&rdev->cg_idx_lock, flags);
        return r;
 }
 
 static inline void eg_cg_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->cg_idx_lock, flags);
        WREG32(EVERGREEN_CG_IND_ADDR, ((reg) & 0xffff));
        WREG32(EVERGREEN_CG_IND_DATA, (v));
+       spin_unlock_irqrestore(&rdev->cg_idx_lock, flags);
 }
 
 static inline u32 eg_pif_phy0_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->pif_idx_lock, flags);
        WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
        r = RREG32(EVERGREEN_PIF_PHY0_DATA);
+       spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
        return r;
 }
 
 static inline void eg_pif_phy0_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->pif_idx_lock, flags);
        WREG32(EVERGREEN_PIF_PHY0_INDEX, ((reg) & 0xffff));
        WREG32(EVERGREEN_PIF_PHY0_DATA, (v));
+       spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
 }
 
 static inline u32 eg_pif_phy1_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->pif_idx_lock, flags);
        WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
        r = RREG32(EVERGREEN_PIF_PHY1_DATA);
+       spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
        return r;
 }
 
 static inline void eg_pif_phy1_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->pif_idx_lock, flags);
        WREG32(EVERGREEN_PIF_PHY1_INDEX, ((reg) & 0xffff));
        WREG32(EVERGREEN_PIF_PHY1_DATA, (v));
+       spin_unlock_irqrestore(&rdev->pif_idx_lock, flags);
 }
 
 static inline u32 r600_uvd_ctx_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->uvd_idx_lock, flags);
        WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff));
        r = RREG32(R600_UVD_CTX_DATA);
+       spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags);
        return r;
 }
 
 static inline void r600_uvd_ctx_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->uvd_idx_lock, flags);
        WREG32(R600_UVD_CTX_INDEX, ((reg) & 0x1ff));
        WREG32(R600_UVD_CTX_DATA, (v));
+       spin_unlock_irqrestore(&rdev->uvd_idx_lock, flags);
 }
 
 
 static inline u32 cik_didt_rreg(struct radeon_device *rdev, u32 reg)
 {
+       unsigned long flags;
        u32 r;
 
+       spin_lock_irqsave(&rdev->didt_idx_lock, flags);
        WREG32(CIK_DIDT_IND_INDEX, (reg));
        r = RREG32(CIK_DIDT_IND_DATA);
+       spin_unlock_irqrestore(&rdev->didt_idx_lock, flags);
        return r;
 }
 
 static inline void cik_didt_wreg(struct radeon_device *rdev, u32 reg, u32 v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->didt_idx_lock, flags);
        WREG32(CIK_DIDT_IND_INDEX, (reg));
        WREG32(CIK_DIDT_IND_DATA, (v));
+       spin_unlock_irqrestore(&rdev->didt_idx_lock, flags);
 }
 
 void r100_pll_errata_after_index(struct radeon_device *rdev);
@@ -2569,6 +2648,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_dpm_force_performance_level(rdev, l) rdev->asic->dpm.force_performance_level((rdev), (l))
 #define radeon_dpm_vblank_too_short(rdev) rdev->asic->dpm.vblank_too_short((rdev))
 #define radeon_dpm_powergate_uvd(rdev, g) rdev->asic->dpm.powergate_uvd((rdev), (g))
+#define radeon_dpm_enable_bapm(rdev, e) rdev->asic->dpm.enable_bapm((rdev), (e))
 
 /* Common functions */
 /* AGP */
index 630853b96841c2d23e6633981d9efc3ae021f703..5003385a75129098e7519702f49bf86d67fbc8b2 100644 (file)
@@ -1037,6 +1037,7 @@ static struct radeon_asic rv6xx_asic = {
                .set_pcie_lanes = &r600_set_pcie_lanes,
                .set_clock_gating = NULL,
                .get_temperature = &rv6xx_get_temp,
+               .set_uvd_clocks = &r600_set_uvd_clocks,
        },
        .dpm = {
                .init = &rv6xx_dpm_init,
@@ -1126,6 +1127,7 @@ static struct radeon_asic rs780_asic = {
                .set_pcie_lanes = NULL,
                .set_clock_gating = NULL,
                .get_temperature = &rv6xx_get_temp,
+               .set_uvd_clocks = &r600_set_uvd_clocks,
        },
        .dpm = {
                .init = &rs780_dpm_init,
@@ -1141,6 +1143,7 @@ static struct radeon_asic rs780_asic = {
                .get_mclk = &rs780_dpm_get_mclk,
                .print_power_state = &rs780_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rs780_dpm_debugfs_print_current_performance_level,
+               .force_performance_level = &rs780_dpm_force_performance_level,
        },
        .pflip = {
                .pre_page_flip = &rs600_pre_page_flip,
@@ -1791,6 +1794,7 @@ static struct radeon_asic trinity_asic = {
                .print_power_state = &trinity_dpm_print_power_state,
                .debugfs_print_current_performance_level = &trinity_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &trinity_dpm_force_performance_level,
+               .enable_bapm = &trinity_dpm_enable_bapm,
        },
        .pflip = {
                .pre_page_flip = &evergreen_pre_page_flip,
@@ -2166,6 +2170,7 @@ static struct radeon_asic kv_asic = {
                .debugfs_print_current_performance_level = &kv_dpm_debugfs_print_current_performance_level,
                .force_performance_level = &kv_dpm_force_performance_level,
                .powergate_uvd = &kv_dpm_powergate_uvd,
+               .enable_bapm = &kv_dpm_enable_bapm,
        },
        .pflip = {
                .pre_page_flip = &evergreen_pre_page_flip,
@@ -2390,7 +2395,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                                RADEON_CG_SUPPORT_HDP_LS |
                                RADEON_CG_SUPPORT_HDP_MGCG;
                        rdev->pg_flags = 0 |
-                               /*RADEON_PG_SUPPORT_GFX_CG | */
+                               /*RADEON_PG_SUPPORT_GFX_PG | */
                                RADEON_PG_SUPPORT_SDMA;
                        break;
                case CHIP_OLAND:
@@ -2479,7 +2484,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                                RADEON_CG_SUPPORT_HDP_LS |
                                RADEON_CG_SUPPORT_HDP_MGCG;
                        rdev->pg_flags = 0;
-                               /*RADEON_PG_SUPPORT_GFX_CG |
+                               /*RADEON_PG_SUPPORT_GFX_PG |
                                RADEON_PG_SUPPORT_GFX_SMG |
                                RADEON_PG_SUPPORT_GFX_DMG |
                                RADEON_PG_SUPPORT_UVD |
@@ -2507,7 +2512,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                                RADEON_CG_SUPPORT_HDP_LS |
                                RADEON_CG_SUPPORT_HDP_MGCG;
                        rdev->pg_flags = 0;
-                               /*RADEON_PG_SUPPORT_GFX_CG |
+                               /*RADEON_PG_SUPPORT_GFX_PG |
                                RADEON_PG_SUPPORT_GFX_SMG |
                                RADEON_PG_SUPPORT_UVD |
                                RADEON_PG_SUPPORT_VCE |
index 818bbe6b884b309c6ac24d0907ab89cc8d5b5041..70c29d5e080dfffdf1a3511e12e0a663c7a57a8f 100644 (file)
@@ -389,6 +389,7 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
 u32 r600_get_xclk(struct radeon_device *rdev);
 uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
 int rv6xx_get_temp(struct radeon_device *rdev);
+int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int r600_dpm_pre_set_power_state(struct radeon_device *rdev);
 void r600_dpm_post_set_power_state(struct radeon_device *rdev);
 /* r600 dma */
@@ -428,6 +429,8 @@ void rs780_dpm_print_power_state(struct radeon_device *rdev,
                                 struct radeon_ps *ps);
 void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                       struct seq_file *m);
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level);
 
 /*
  * rv770,rv730,rv710,rv740
@@ -625,6 +628,7 @@ void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *r
                                                         struct seq_file *m);
 int trinity_dpm_force_performance_level(struct radeon_device *rdev,
                                        enum radeon_dpm_forced_level level);
+void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
 
 /* DCE6 - SI */
 void dce6_bandwidth_update(struct radeon_device *rdev);
@@ -781,6 +785,7 @@ void kv_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
 int kv_dpm_force_performance_level(struct radeon_device *rdev,
                                   enum radeon_dpm_forced_level level);
 void kv_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
+void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
 
 /* uvd v1.0 */
 uint32_t uvd_v1_0_get_rptr(struct radeon_device *rdev,
index 2399f25ec0370cfba03b256174de69e407e01353..79159b5da05bc778dc71b819a32c4139d28f967b 100644 (file)
@@ -396,6 +396,21 @@ static int radeon_connector_set_property(struct drm_connector *connector, struct
                }
        }
 
+       if (property == rdev->mode_info.audio_property) {
+               struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+               /* need to find digital encoder on connector */
+               encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
+               if (!encoder)
+                       return 0;
+
+               radeon_encoder = to_radeon_encoder(encoder);
+
+               if (radeon_connector->audio != val) {
+                       radeon_connector->audio = val;
+                       radeon_property_change_mode(&radeon_encoder->base);
+               }
+       }
+
        if (property == rdev->mode_info.underscan_property) {
                /* need to find digital encoder on connector */
                encoder = radeon_find_encoder(connector, DRM_MODE_ENCODER_TMDS);
@@ -1420,7 +1435,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
                                if (radeon_dp_getdpcd(radeon_connector))
                                        ret = connector_status_connected;
                        } else {
-                               /* try non-aux ddc (DP to DVI/HMDI/etc. adapter) */
+                               /* try non-aux ddc (DP to DVI/HDMI/etc. adapter) */
                                if (radeon_ddc_probe(radeon_connector, false))
                                        ret = connector_status_connected;
                        }
@@ -1489,6 +1504,24 @@ static const struct drm_connector_funcs radeon_dp_connector_funcs = {
        .force = radeon_dvi_force,
 };
 
+static const struct drm_connector_funcs radeon_edp_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = radeon_lvds_set_property,
+       .destroy = radeon_dp_connector_destroy,
+       .force = radeon_dvi_force,
+};
+
+static const struct drm_connector_funcs radeon_lvds_bridge_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = radeon_dp_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .set_property = radeon_lvds_set_property,
+       .destroy = radeon_dp_connector_destroy,
+       .force = radeon_dvi_force,
+};
+
 void
 radeon_add_atom_connector(struct drm_device *dev,
                          uint32_t connector_id,
@@ -1580,8 +1613,6 @@ radeon_add_atom_connector(struct drm_device *dev,
                        goto failed;
                radeon_dig_connector->igp_lane_info = igp_lane_info;
                radeon_connector->con_priv = radeon_dig_connector;
-               drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
-               drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
                if (i2c_bus->valid) {
                        /* add DP i2c bus */
                        if (connector_type == DRM_MODE_CONNECTOR_eDP)
@@ -1598,6 +1629,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                case DRM_MODE_CONNECTOR_VGA:
                case DRM_MODE_CONNECTOR_DVIA:
                default:
+                       drm_connector_init(dev, &radeon_connector->base,
+                                          &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base,
+                                                &radeon_dp_connector_helper_funcs);
                        connector->interlace_allowed = true;
                        connector->doublescan_allowed = true;
                        radeon_connector->dac_load_detect = true;
@@ -1610,6 +1645,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                case DRM_MODE_CONNECTOR_HDMIA:
                case DRM_MODE_CONNECTOR_HDMIB:
                case DRM_MODE_CONNECTOR_DisplayPort:
+                       drm_connector_init(dev, &radeon_connector->base,
+                                          &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base,
+                                                &radeon_dp_connector_helper_funcs);
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.underscan_property,
                                                      UNDERSCAN_OFF);
@@ -1619,6 +1658,9 @@ radeon_add_atom_connector(struct drm_device *dev,
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      rdev->mode_info.underscan_vborder_property,
                                                      0);
+                       drm_object_attach_property(&radeon_connector->base.base,
+                                                  rdev->mode_info.audio_property,
+                                                  RADEON_AUDIO_DISABLE);
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -1634,6 +1676,10 @@ radeon_add_atom_connector(struct drm_device *dev,
                        break;
                case DRM_MODE_CONNECTOR_LVDS:
                case DRM_MODE_CONNECTOR_eDP:
+                       drm_connector_init(dev, &radeon_connector->base,
+                                          &radeon_lvds_bridge_connector_funcs, connector_type);
+                       drm_connector_helper_add(&radeon_connector->base,
+                                                &radeon_dp_connector_helper_funcs);
                        drm_object_attach_property(&radeon_connector->base.base,
                                                      dev->mode_config.scaling_mode_property,
                                                      DRM_MODE_SCALE_FULLSCREEN);
@@ -1708,6 +1754,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
+                       if (ASIC_IS_DCE2(rdev)) {
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                             rdev->mode_info.audio_property,
+                                                             RADEON_AUDIO_DISABLE);
+                       }
                        if (connector_type == DRM_MODE_CONNECTOR_DVII) {
                                radeon_connector->dac_load_detect = true;
                                drm_object_attach_property(&radeon_connector->base.base,
@@ -1748,6 +1799,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
+                       if (ASIC_IS_DCE2(rdev)) {
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                             rdev->mode_info.audio_property,
+                                                             RADEON_AUDIO_DISABLE);
+                       }
                        subpixel_order = SubPixelHorizontalRGB;
                        connector->interlace_allowed = true;
                        if (connector_type == DRM_MODE_CONNECTOR_HDMIB)
@@ -1787,6 +1843,11 @@ radeon_add_atom_connector(struct drm_device *dev,
                                                              rdev->mode_info.underscan_vborder_property,
                                                              0);
                        }
+                       if (ASIC_IS_DCE2(rdev)) {
+                               drm_object_attach_property(&radeon_connector->base.base,
+                                                             rdev->mode_info.audio_property,
+                                                             RADEON_AUDIO_DISABLE);
+                       }
                        connector->interlace_allowed = true;
                        /* in theory with a DP to VGA converter... */
                        connector->doublescan_allowed = false;
@@ -1797,7 +1858,7 @@ radeon_add_atom_connector(struct drm_device *dev,
                                goto failed;
                        radeon_dig_connector->igp_lane_info = igp_lane_info;
                        radeon_connector->con_priv = radeon_dig_connector;
-                       drm_connector_init(dev, &radeon_connector->base, &radeon_dp_connector_funcs, connector_type);
+                       drm_connector_init(dev, &radeon_connector->base, &radeon_edp_connector_funcs, connector_type);
                        drm_connector_helper_add(&radeon_connector->base, &radeon_dp_connector_helper_funcs);
                        if (i2c_bus->valid) {
                                /* add DP i2c bus */
index a560844103727dce62d2b8ef88290cd321a28936..ac6ece61a47627931e9a3bcb68c3a34c636efe0a 100644 (file)
@@ -28,6 +28,7 @@
 #include <drm/radeon_drm.h>
 #include "radeon_reg.h"
 #include "radeon.h"
+#include "radeon_trace.h"
 
 static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
 {
@@ -80,9 +81,11 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                p->relocs[i].lobj.bo = p->relocs[i].robj;
                p->relocs[i].lobj.written = !!r->write_domain;
 
-               /* the first reloc of an UVD job is the
-                  msg and that must be in VRAM */
-               if (p->ring == R600_RING_TYPE_UVD_INDEX && i == 0) {
+               /* the first reloc of an UVD job is the msg and that must be in
+                  VRAM, also but everything into VRAM on AGP cards to avoid
+                  image corruptions */
+               if (p->ring == R600_RING_TYPE_UVD_INDEX &&
+                   (i == 0 || p->rdev->flags & RADEON_IS_AGP)) {
                        /* TODO: is this still needed for NI+ ? */
                        p->relocs[i].lobj.domain =
                                RADEON_GEM_DOMAIN_VRAM;
@@ -559,6 +562,8 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                return r;
        }
 
+       trace_radeon_cs(&parser);
+
        r = radeon_cs_ib_chunk(rdev, &parser);
        if (r) {
                goto out;
index 16cb8792b1e665f9048ec24f8c521eb052115662..e29faa73b574c6b989a9c501d15032a218ae849b 100644 (file)
@@ -1249,6 +1249,17 @@ int radeon_device_init(struct radeon_device *rdev,
        /* Registers mapping */
        /* TODO: block userspace mapping of io register */
        spin_lock_init(&rdev->mmio_idx_lock);
+       spin_lock_init(&rdev->smc_idx_lock);
+       spin_lock_init(&rdev->pll_idx_lock);
+       spin_lock_init(&rdev->mc_idx_lock);
+       spin_lock_init(&rdev->pcie_idx_lock);
+       spin_lock_init(&rdev->pciep_idx_lock);
+       spin_lock_init(&rdev->pif_idx_lock);
+       spin_lock_init(&rdev->cg_idx_lock);
+       spin_lock_init(&rdev->uvd_idx_lock);
+       spin_lock_init(&rdev->rcu_idx_lock);
+       spin_lock_init(&rdev->didt_idx_lock);
+       spin_lock_init(&rdev->end_idx_lock);
        if (rdev->family >= CHIP_BONAIRE) {
                rdev->rmmio_base = pci_resource_start(rdev->pdev, 5);
                rdev->rmmio_size = pci_resource_len(rdev->pdev, 5);
index b055bddaa94c3d85e4b497721b8d239082c035a4..0d1aa050d41de7b02a1fd12065246c4239d817be 100644 (file)
@@ -1172,6 +1172,12 @@ static struct drm_prop_enum_list radeon_underscan_enum_list[] =
        { UNDERSCAN_AUTO, "auto" },
 };
 
+static struct drm_prop_enum_list radeon_audio_enum_list[] =
+{      { RADEON_AUDIO_DISABLE, "off" },
+       { RADEON_AUDIO_ENABLE, "on" },
+       { RADEON_AUDIO_AUTO, "auto" },
+};
+
 static int radeon_modeset_create_props(struct radeon_device *rdev)
 {
        int sz;
@@ -1222,6 +1228,12 @@ static int radeon_modeset_create_props(struct radeon_device *rdev)
        if (!rdev->mode_info.underscan_vborder_property)
                return -ENOMEM;
 
+       sz = ARRAY_SIZE(radeon_audio_enum_list);
+       rdev->mode_info.audio_property =
+               drm_property_create_enum(rdev->ddev, 0,
+                                        "audio",
+                                        radeon_audio_enum_list, sz);
+
        return 0;
 }
 
index cb4445f55a96c3aa10c703e868db1707b864170e..cdd12dcd988b1ed3260076b6d984cbf388dc35a7 100644 (file)
@@ -153,7 +153,7 @@ int radeon_benchmarking = 0;
 int radeon_testing = 0;
 int radeon_connector_table = 0;
 int radeon_tv = 1;
-int radeon_audio = 0;
+int radeon_audio = 1;
 int radeon_disp_priority = 0;
 int radeon_hw_i2c = 0;
 int radeon_pcie_gen2 = -1;
index d908d8d68f6ba73b77df6d7f98ba64f164f59412..ef63d3f00b2ffb3d212c46315d2f8226a1605f68 100644 (file)
@@ -247,6 +247,8 @@ struct radeon_mode_info {
        struct drm_property *underscan_property;
        struct drm_property *underscan_hborder_property;
        struct drm_property *underscan_vborder_property;
+       /* audio */
+       struct drm_property *audio_property;
        /* hardcoded DFP edid from BIOS */
        struct edid *bios_hardcoded_edid;
        int bios_hardcoded_edid_size;
@@ -471,6 +473,12 @@ struct radeon_router {
        u8 cd_mux_state;
 };
 
+enum radeon_connector_audio {
+       RADEON_AUDIO_DISABLE = 0,
+       RADEON_AUDIO_ENABLE = 1,
+       RADEON_AUDIO_AUTO = 2
+};
+
 struct radeon_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -489,6 +497,7 @@ struct radeon_connector {
        struct radeon_hpd hpd;
        struct radeon_router router;
        struct radeon_i2c_chan *router_bus;
+       enum radeon_connector_audio audio;
 };
 
 struct radeon_framebuffer {
index d7555369a3e53101aa773309eff481a8f1f1c4ee..87e1d69e8fdb3b859af4ed3d809ea93db40f2c07 100644 (file)
@@ -67,7 +67,16 @@ int radeon_pm_get_type_index(struct radeon_device *rdev,
 
 void radeon_pm_acpi_event_handler(struct radeon_device *rdev)
 {
-       if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
+       if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+               mutex_lock(&rdev->pm.mutex);
+               if (power_supply_is_system_supplied() > 0)
+                       rdev->pm.dpm.ac_power = true;
+               else
+                       rdev->pm.dpm.ac_power = false;
+               if (rdev->asic->dpm.enable_bapm)
+                       radeon_dpm_enable_bapm(rdev, rdev->pm.dpm.ac_power);
+               mutex_unlock(&rdev->pm.mutex);
+        } else if (rdev->pm.pm_method == PM_METHOD_PROFILE) {
                if (rdev->pm.profile == PM_PROFILE_AUTO) {
                        mutex_lock(&rdev->pm.mutex);
                        radeon_pm_update_profile(rdev);
@@ -333,7 +342,7 @@ static ssize_t radeon_get_pm_profile(struct device *dev,
                                     struct device_attribute *attr,
                                     char *buf)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
        int cp = rdev->pm.profile;
 
@@ -349,7 +358,7 @@ static ssize_t radeon_set_pm_profile(struct device *dev,
                                     const char *buf,
                                     size_t count)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
 
        mutex_lock(&rdev->pm.mutex);
@@ -383,7 +392,7 @@ static ssize_t radeon_get_pm_method(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
        int pm = rdev->pm.pm_method;
 
@@ -397,7 +406,7 @@ static ssize_t radeon_set_pm_method(struct device *dev,
                                    const char *buf,
                                    size_t count)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
 
        /* we don't support the legacy modes with dpm */
@@ -433,7 +442,7 @@ static ssize_t radeon_get_dpm_state(struct device *dev,
                                    struct device_attribute *attr,
                                    char *buf)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
        enum radeon_pm_state_type pm = rdev->pm.dpm.user_state;
 
@@ -447,7 +456,7 @@ static ssize_t radeon_set_dpm_state(struct device *dev,
                                    const char *buf,
                                    size_t count)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
 
        mutex_lock(&rdev->pm.mutex);
@@ -472,7 +481,7 @@ static ssize_t radeon_get_dpm_forced_performance_level(struct device *dev,
                                                       struct device_attribute *attr,
                                                       char *buf)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
        enum radeon_dpm_forced_level level = rdev->pm.dpm.forced_level;
 
@@ -486,7 +495,7 @@ static ssize_t radeon_set_dpm_forced_performance_level(struct device *dev,
                                                       const char *buf,
                                                       size_t count)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
        enum radeon_dpm_forced_level level;
        int ret = 0;
@@ -524,7 +533,7 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
 {
-       struct drm_device *ddev = pci_get_drvdata(to_pci_dev(dev));
+       struct drm_device *ddev = dev_get_drvdata(dev);
        struct radeon_device *rdev = ddev->dev_private;
        int temp;
 
@@ -536,6 +545,23 @@ static ssize_t radeon_hwmon_show_temp(struct device *dev,
        return snprintf(buf, PAGE_SIZE, "%d\n", temp);
 }
 
+static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
+                                            struct device_attribute *attr,
+                                            char *buf)
+{
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct radeon_device *rdev = ddev->dev_private;
+       int hyst = to_sensor_dev_attr(attr)->index;
+       int temp;
+
+       if (hyst)
+               temp = rdev->pm.dpm.thermal.min_temp;
+       else
+               temp = rdev->pm.dpm.thermal.max_temp;
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", temp);
+}
+
 static ssize_t radeon_hwmon_show_name(struct device *dev,
                                      struct device_attribute *attr,
                                      char *buf)
@@ -544,16 +570,37 @@ static ssize_t radeon_hwmon_show_name(struct device *dev,
 }
 
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
 static SENSOR_DEVICE_ATTR(name, S_IRUGO, radeon_hwmon_show_name, NULL, 0);
 
 static struct attribute *hwmon_attributes[] = {
        &sensor_dev_attr_temp1_input.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit.dev_attr.attr,
+       &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
        &sensor_dev_attr_name.dev_attr.attr,
        NULL
 };
 
+static umode_t hwmon_attributes_visible(struct kobject *kobj,
+                                       struct attribute *attr, int index)
+{
+       struct device *dev = container_of(kobj, struct device, kobj);
+       struct drm_device *ddev = dev_get_drvdata(dev);
+       struct radeon_device *rdev = ddev->dev_private;
+
+       /* Skip limit attributes if DPM is not enabled */
+       if (rdev->pm.pm_method != PM_METHOD_DPM &&
+           (attr == &sensor_dev_attr_temp1_crit.dev_attr.attr ||
+            attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
+               return 0;
+
+       return attr->mode;
+}
+
 static const struct attribute_group hwmon_attrgroup = {
        .attrs = hwmon_attributes,
+       .is_visible = hwmon_attributes_visible,
 };
 
 static int radeon_hwmon_init(struct radeon_device *rdev)
@@ -870,10 +917,13 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 
        radeon_dpm_post_set_power_state(rdev);
 
-       /* force low perf level for thermal */
-       if (rdev->pm.dpm.thermal_active &&
-           rdev->asic->dpm.force_performance_level) {
-               radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_LOW);
+       if (rdev->asic->dpm.force_performance_level) {
+               if (rdev->pm.dpm.thermal_active)
+                       /* force low perf level for thermal */
+                       radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_LOW);
+               else
+                       /* otherwise, enable auto */
+                       radeon_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
        }
 
 done:
@@ -1102,9 +1152,10 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev)
 {
        int ret;
 
-       /* default to performance state */
+       /* default to balanced state */
        rdev->pm.dpm.state = POWER_STATE_TYPE_BALANCED;
        rdev->pm.dpm.user_state = POWER_STATE_TYPE_BALANCED;
+       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
        rdev->pm.default_sclk = rdev->clock.default_sclk;
        rdev->pm.default_mclk = rdev->clock.default_mclk;
        rdev->pm.current_sclk = rdev->clock.default_sclk;
index eafd8160a15563c3aa762eabb6ea532aa766529a..f7e367815964f34756a13691935018ae95978ca1 100644 (file)
@@ -27,6 +27,26 @@ TRACE_EVENT(radeon_bo_create,
            TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages)
 );
 
+TRACE_EVENT(radeon_cs,
+           TP_PROTO(struct radeon_cs_parser *p),
+           TP_ARGS(p),
+           TP_STRUCT__entry(
+                            __field(u32, ring)
+                            __field(u32, dw)
+                            __field(u32, fences)
+                            ),
+
+           TP_fast_assign(
+                          __entry->ring = p->ring;
+                          __entry->dw = p->chunks[p->chunk_ib_idx].length_dw;
+                          __entry->fences = radeon_fence_count_emitted(
+                               p->rdev, p->ring);
+                          ),
+           TP_printk("ring=%u, dw=%u, fences=%u",
+                     __entry->ring, __entry->dw,
+                     __entry->fences)
+);
+
 DECLARE_EVENT_CLASS(radeon_fence_request,
 
            TP_PROTO(struct drm_device *dev, u32 seqno),
@@ -53,13 +73,6 @@ DEFINE_EVENT(radeon_fence_request, radeon_fence_emit,
            TP_ARGS(dev, seqno)
 );
 
-DEFINE_EVENT(radeon_fence_request, radeon_fence_retire,
-
-           TP_PROTO(struct drm_device *dev, u32 seqno),
-
-           TP_ARGS(dev, seqno)
-);
-
 DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin,
 
            TP_PROTO(struct drm_device *dev, u32 seqno),
index b8074a8ec75a93c0566cfefa5ae5375041841e18..9566b5940a5ae723f90dfa11427e3f09bac233b3 100644 (file)
@@ -274,19 +274,26 @@ static void rs400_mc_init(struct radeon_device *rdev)
 
 uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
        uint32_t r;
 
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(RS480_NB_MC_INDEX, reg & 0xff);
        r = RREG32(RS480_NB_MC_DATA);
        WREG32(RS480_NB_MC_INDEX, 0xff);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
        return r;
 }
 
 void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(RS480_NB_MC_INDEX, ((reg) & 0xff) | RS480_NB_MC_IND_WR_EN);
        WREG32(RS480_NB_MC_DATA, (v));
        WREG32(RS480_NB_MC_INDEX, 0xff);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
 }
 
 #if defined(CONFIG_DEBUG_FS)
index 670b555d2ca229c3b39ac46cbbbf8e06e678f25b..6acba8017b9afd24d63b906a2fb9b8ec5934ec1f 100644 (file)
@@ -847,16 +847,26 @@ void rs600_bandwidth_update(struct radeon_device *rdev)
 
 uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
+       u32 r;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) |
                S_000070_MC_IND_CITF_ARB0(1));
-       return RREG32(R_000074_MC_IND_DATA);
+       r = RREG32(R_000074_MC_IND_DATA);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
+       return r;
 }
 
 void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) |
                S_000070_MC_IND_CITF_ARB0(1) | S_000070_MC_IND_WR_EN(1));
        WREG32(R_000074_MC_IND_DATA, v);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
 }
 
 static void rs600_debugfs(struct radeon_device *rdev)
index d8ddfb34545de8dce3fb55f2315ce4121a4bab8e..1447d794c22ad21648408a390e4b78bc84493af0 100644 (file)
@@ -631,20 +631,27 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
 
 uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
        uint32_t r;
 
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg));
        r = RREG32(R_00007C_MC_DATA);
        WREG32(R_000078_MC_INDEX, ~C_000078_MC_IND_ADDR);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
        return r;
 }
 
 void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg) |
                S_000078_MC_IND_WR_EN(1));
        WREG32(R_00007C_MC_DATA, v);
        WREG32(R_000078_MC_INDEX, 0x7F);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
 }
 
 static void rs690_mc_program(struct radeon_device *rdev)
index d1a1ce73bd45548392deabbef5815e463a97dcd2..6af8505cf4d2db624ee64811ba4575158d90e974 100644 (file)
@@ -62,9 +62,7 @@ static void rs780_get_pm_mode_parameters(struct radeon_device *rdev)
                        radeon_crtc = to_radeon_crtc(crtc);
                        pi->crtc_id = radeon_crtc->crtc_id;
                        if (crtc->mode.htotal && crtc->mode.vtotal)
-                               pi->refresh_rate =
-                                       (crtc->mode.clock * 1000) /
-                                       (crtc->mode.htotal * crtc->mode.vtotal);
+                               pi->refresh_rate = drm_mode_vrefresh(&crtc->mode);
                        break;
                }
        }
@@ -376,9 +374,8 @@ static void rs780_disable_vbios_powersaving(struct radeon_device *rdev)
        WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
 }
 
-static void rs780_force_voltage_to_high(struct radeon_device *rdev)
+static void rs780_force_voltage(struct radeon_device *rdev, u16 voltage)
 {
-       struct igp_power_info *pi = rs780_get_pi(rdev);
        struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
 
        if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
@@ -390,7 +387,7 @@ static void rs780_force_voltage_to_high(struct radeon_device *rdev)
        udelay(1);
 
        WREG32_P(FVTHROT_PWM_CTRL_REG0,
-                STARTING_PWM_HIGHTIME(pi->max_voltage),
+                STARTING_PWM_HIGHTIME(voltage),
                 ~STARTING_PWM_HIGHTIME_MASK);
 
        WREG32_P(FVTHROT_PWM_CTRL_REG0,
@@ -404,6 +401,26 @@ static void rs780_force_voltage_to_high(struct radeon_device *rdev)
        WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
 }
 
+static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
+{
+       struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+       if (current_state->sclk_low == current_state->sclk_high)
+               return;
+
+       WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+       WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
+                ~FORCED_FEEDBACK_DIV_MASK);
+       WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
+                ~STARTING_FEEDBACK_DIV_MASK);
+       WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+       udelay(100);
+
+       WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
 static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
                                          struct radeon_ps *new_ps,
                                          struct radeon_ps *old_ps)
@@ -432,17 +449,13 @@ static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
        if (ret)
                return ret;
 
-       WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
-
-       WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
-                ~FORCED_FEEDBACK_DIV_MASK);
-       WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
-                ~STARTING_FEEDBACK_DIV_MASK);
-       WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
-
-       udelay(100);
+       if ((min_dividers.ref_div != max_dividers.ref_div) ||
+           (min_dividers.post_div != max_dividers.post_div) ||
+           (max_dividers.ref_div != current_max_dividers.ref_div) ||
+           (max_dividers.post_div != current_max_dividers.post_div))
+               return -EINVAL;
 
-       WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+       rs780_force_fbdiv(rdev, max_dividers.fb_div);
 
        if (max_dividers.fb_div > min_dividers.fb_div) {
                WREG32_P(FVTHROT_FBDIV_REG0,
@@ -486,6 +499,9 @@ static void rs780_activate_engine_clk_scaling(struct radeon_device *rdev,
            (new_state->sclk_low == old_state->sclk_low))
                return;
 
+       if (new_state->sclk_high == new_state->sclk_low)
+               return;
+
        rs780_clk_scaling_enable(rdev, true);
 }
 
@@ -649,7 +665,7 @@ int rs780_dpm_set_power_state(struct radeon_device *rdev)
        rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 
        if (pi->voltage_control) {
-               rs780_force_voltage_to_high(rdev);
+               rs780_force_voltage(rdev, pi->max_voltage);
                mdelay(5);
        }
 
@@ -717,14 +733,18 @@ static void rs780_parse_pplib_non_clock_info(struct radeon_device *rdev,
        if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
                rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
                rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
-       } else if (r600_is_uvd_state(rps->class, rps->class2)) {
-               rps->vclk = RS780_DEFAULT_VCLK_FREQ;
-               rps->dclk = RS780_DEFAULT_DCLK_FREQ;
        } else {
                rps->vclk = 0;
                rps->dclk = 0;
        }
 
+       if (r600_is_uvd_state(rps->class, rps->class2)) {
+               if ((rps->vclk == 0) || (rps->dclk == 0)) {
+                       rps->vclk = RS780_DEFAULT_VCLK_FREQ;
+                       rps->dclk = RS780_DEFAULT_DCLK_FREQ;
+               }
+       }
+
        if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
                rdev->pm.dpm.boot_ps = rps;
        if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
@@ -986,3 +1006,55 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
                seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
                           ps->sclk_high, ps->max_voltage);
 }
+
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level)
+{
+       struct igp_power_info *pi = rs780_get_pi(rdev);
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct igp_ps *ps = rs780_get_ps(rps);
+       struct atom_clock_dividers dividers;
+       int ret;
+
+       rs780_clk_scaling_enable(rdev, false);
+       rs780_voltage_scaling_enable(rdev, false);
+
+       if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+               if (pi->voltage_control)
+                       rs780_force_voltage(rdev, pi->max_voltage);
+
+               ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                                    ps->sclk_high, false, &dividers);
+               if (ret)
+                       return ret;
+
+               rs780_force_fbdiv(rdev, dividers.fb_div);
+       } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+               ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                                    ps->sclk_low, false, &dividers);
+               if (ret)
+                       return ret;
+
+               rs780_force_fbdiv(rdev, dividers.fb_div);
+
+               if (pi->voltage_control)
+                       rs780_force_voltage(rdev, pi->min_voltage);
+       } else {
+               if (pi->voltage_control)
+                       rs780_force_voltage(rdev, pi->max_voltage);
+
+               if (ps->sclk_high != ps->sclk_low) {
+                       WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+                       rs780_clk_scaling_enable(rdev, true);
+               }
+
+               if (pi->voltage_control) {
+                       rs780_voltage_scaling_enable(rdev, true);
+                       rs780_enable_voltage_scaling(rdev, rps);
+               }
+       }
+
+       rdev->pm.dpm.forced_level = level;
+
+       return 0;
+}
index 8ea1573ae820ef62202a30c680f6540fec127cec..873eb4b193b4f86c35fa2cc02417adbdee54344d 100644 (file)
@@ -209,19 +209,27 @@ static void rv515_mc_init(struct radeon_device *rdev)
 
 uint32_t rv515_mc_rreg(struct radeon_device *rdev, uint32_t reg)
 {
+       unsigned long flags;
        uint32_t r;
 
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(MC_IND_INDEX, 0x7f0000 | (reg & 0xffff));
        r = RREG32(MC_IND_DATA);
        WREG32(MC_IND_INDEX, 0);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
+
        return r;
 }
 
 void rv515_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
 {
+       unsigned long flags;
+
+       spin_lock_irqsave(&rdev->mc_idx_lock, flags);
        WREG32(MC_IND_INDEX, 0xff0000 | ((reg) & 0xffff));
        WREG32(MC_IND_DATA, (v));
        WREG32(MC_IND_INDEX, 0);
+       spin_unlock_irqrestore(&rdev->mc_idx_lock, flags);
 }
 
 #if defined(CONFIG_DEBUG_FS)
index ab1f2016f21e44461e42892440df17b695b17f09..5811d277a36a60ec845cbcadf9588326a01a488b 100644 (file)
@@ -1758,8 +1758,6 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 
        rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
-       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
-
        return 0;
 }
 
index 8cbb85dae5aa38500ac5803754ffcf94af613593..913b025ae9b399695bed47af97cccf08fe68caf7 100644 (file)
@@ -2064,12 +2064,6 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev)
                rv770_program_dcodt_after_state_switch(rdev, new_ps, old_ps);
        rv770_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
-       ret = rv770_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
-       if (ret) {
-               DRM_ERROR("rv770_dpm_force_performance_level failed\n");
-               return ret;
-       }
-
        return 0;
 }
 
@@ -2147,14 +2141,18 @@ static void rv7xx_parse_pplib_non_clock_info(struct radeon_device *rdev,
        if (ATOM_PPLIB_NONCLOCKINFO_VER1 < table_rev) {
                rps->vclk = le32_to_cpu(non_clock_info->ulVCLK);
                rps->dclk = le32_to_cpu(non_clock_info->ulDCLK);
-       } else if (r600_is_uvd_state(rps->class, rps->class2)) {
-               rps->vclk = RV770_DEFAULT_VCLK_FREQ;
-               rps->dclk = RV770_DEFAULT_DCLK_FREQ;
        } else {
                rps->vclk = 0;
                rps->dclk = 0;
        }
 
+       if (r600_is_uvd_state(rps->class, rps->class2)) {
+               if ((rps->vclk == 0) || (rps->dclk == 0)) {
+                       rps->vclk = RV770_DEFAULT_VCLK_FREQ;
+                       rps->dclk = RV770_DEFAULT_DCLK_FREQ;
+               }
+       }
+
        if (rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT)
                rdev->pm.dpm.boot_ps = rps;
        if (rps->class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
index ab95da570215b7c68895be5bbe7765dd92ea758a..b2a224407365da6750572c30309466c025fb57ee 100644 (file)
@@ -274,8 +274,8 @@ static const u8 cayman_smc_int_vectors[] =
        0x08, 0x72, 0x08, 0x72
 };
 
-int rv770_set_smc_sram_address(struct radeon_device *rdev,
-                              u16 smc_address, u16 limit)
+static int rv770_set_smc_sram_address(struct radeon_device *rdev,
+                                     u16 smc_address, u16 limit)
 {
        u32 addr;
 
@@ -296,9 +296,10 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
                            u16 smc_start_address, const u8 *src,
                            u16 byte_count, u16 limit)
 {
+       unsigned long flags;
        u32 data, original_data, extra_shift;
        u16 addr;
-       int ret;
+       int ret = 0;
 
        if (smc_start_address & 3)
                return -EINVAL;
@@ -307,13 +308,14 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
 
        addr = smc_start_address;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        while (byte_count >= 4) {
                /* SMC address space is BE */
                data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
 
                ret = rv770_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                WREG32(SMC_SRAM_DATA, data);
 
@@ -328,7 +330,7 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
 
                ret = rv770_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                original_data = RREG32(SMC_SRAM_DATA);
 
@@ -346,12 +348,15 @@ int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
 
                ret = rv770_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                WREG32(SMC_SRAM_DATA, data);
        }
 
-       return 0;
+done:
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
+
+       return ret;
 }
 
 static int rv770_program_interrupt_vectors(struct radeon_device *rdev,
@@ -461,12 +466,15 @@ PPSMC_Result rv770_wait_for_smc_inactive(struct radeon_device *rdev)
 
 static void rv770_clear_smc_sram(struct radeon_device *rdev, u16 limit)
 {
+       unsigned long flags;
        u16 i;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        for (i = 0;  i < limit; i += 4) {
                rv770_set_smc_sram_address(rdev, i, limit);
                WREG32(SMC_SRAM_DATA, 0);
        }
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 }
 
 int rv770_load_smc_ucode(struct radeon_device *rdev,
@@ -595,27 +603,29 @@ int rv770_load_smc_ucode(struct radeon_device *rdev,
 int rv770_read_smc_sram_dword(struct radeon_device *rdev,
                              u16 smc_address, u32 *value, u16 limit)
 {
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
-       if (ret)
-               return ret;
-
-       *value = RREG32(SMC_SRAM_DATA);
+       if (ret == 0)
+               *value = RREG32(SMC_SRAM_DATA);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
-       return 0;
+       return ret;
 }
 
 int rv770_write_smc_sram_dword(struct radeon_device *rdev,
                               u16 smc_address, u32 value, u16 limit)
 {
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        ret = rv770_set_smc_sram_address(rdev, smc_address, limit);
-       if (ret)
-               return ret;
+       if (ret == 0)
+               WREG32(SMC_SRAM_DATA, value);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
-       WREG32(SMC_SRAM_DATA, value);
-
-       return 0;
+       return ret;
 }
index f78d92a4b3259b4d779b8a448ba02f412fd1d41b..3b2c963c4880048646d6b80bf80ade153f505db3 100644 (file)
@@ -187,8 +187,6 @@ typedef struct RV770_SMC_STATETABLE RV770_SMC_STATETABLE;
 #define RV770_SMC_SOFT_REGISTER_uvd_enabled             0x9C
 #define RV770_SMC_SOFT_REGISTER_is_asic_lombok          0xA0
 
-int rv770_set_smc_sram_address(struct radeon_device *rdev,
-                              u16 smc_address, u16 limit);
 int rv770_copy_bytes_to_smc(struct radeon_device *rdev,
                            u16 smc_start_address, const u8 *src,
                            u16 byte_count, u16 limit);
index 9fe60e5429223c6cb5688af3ca50225d4570aa67..1ae277152cc7f0c66f7babbcb0cdfcec5ab04f71 100644 (file)
 #define AFMT_VBI_PACKET_CONTROL              0x7608
 #       define AFMT_GENERIC0_UPDATE          (1 << 2)
 #define AFMT_INFOFRAME_CONTROL0              0x760c
-#       define AFMT_AUDIO_INFO_SOURCE        (1 << 6) /* 0 - sound block; 1 - hmdi regs */
+#       define AFMT_AUDIO_INFO_SOURCE        (1 << 6) /* 0 - sound block; 1 - hdmi regs */
 #       define AFMT_AUDIO_INFO_UPDATE        (1 << 7)
 #       define AFMT_MPEG_INFO_UPDATE         (1 << 10)
 #define AFMT_GENERIC0_7                      0x7610
index 3e23b757dcfa578859d7ff5d96b04a9c7ed85691..c354c1094967990a46caea46612caed123bc9b51 100644 (file)
@@ -83,6 +83,8 @@ extern void si_dma_vm_set_page(struct radeon_device *rdev,
                               uint64_t pe,
                               uint64_t addr, unsigned count,
                               uint32_t incr, uint32_t flags);
+static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
+                                        bool enable);
 
 static const u32 verde_rlc_save_restore_register_list[] =
 {
@@ -3386,6 +3388,8 @@ static int si_cp_resume(struct radeon_device *rdev)
        u32 rb_bufsz;
        int r;
 
+       si_enable_gui_idle_interrupt(rdev, false);
+
        WREG32(CP_SEM_WAIT_TIMER, 0x0);
        WREG32(CP_SEM_INCOMPLETE_TIMER_CNTL, 0x0);
 
@@ -3501,6 +3505,8 @@ static int si_cp_resume(struct radeon_device *rdev)
                rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX].ready = false;
        }
 
+       si_enable_gui_idle_interrupt(rdev, true);
+
        return 0;
 }
 
@@ -4888,7 +4894,7 @@ static void si_enable_gfx_cgpg(struct radeon_device *rdev,
 {
        u32 tmp;
 
-       if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_CG)) {
+       if (enable && (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG)) {
                tmp = RLC_PUD(0x10) | RLC_PDD(0x10) | RLC_TTPD(0x10) | RLC_MSD(0x10);
                WREG32(RLC_TTOP_D, tmp);
 
@@ -5250,6 +5256,7 @@ void si_update_cg(struct radeon_device *rdev,
                  u32 block, bool enable)
 {
        if (block & RADEON_CG_BLOCK_GFX) {
+               si_enable_gui_idle_interrupt(rdev, false);
                /* order matters! */
                if (enable) {
                        si_enable_mgcg(rdev, true);
@@ -5258,6 +5265,7 @@ void si_update_cg(struct radeon_device *rdev,
                        si_enable_cgcg(rdev, false);
                        si_enable_mgcg(rdev, false);
                }
+               si_enable_gui_idle_interrupt(rdev, true);
        }
 
        if (block & RADEON_CG_BLOCK_MC) {
@@ -5408,7 +5416,7 @@ static void si_init_pg(struct radeon_device *rdev)
                        si_init_dma_pg(rdev);
                }
                si_init_ao_cu_mask(rdev);
-               if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_CG) {
+               if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) {
                        si_init_gfx_cgpg(rdev);
                }
                si_enable_dma_pg(rdev, true);
@@ -5560,7 +5568,9 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
 {
        u32 tmp;
 
-       WREG32(CP_INT_CNTL_RING0, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       tmp = RREG32(CP_INT_CNTL_RING0) &
+               (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+       WREG32(CP_INT_CNTL_RING0, tmp);
        WREG32(CP_INT_CNTL_RING1, 0);
        WREG32(CP_INT_CNTL_RING2, 0);
        tmp = RREG32(DMA_CNTL + DMA0_REGISTER_OFFSET) & ~TRAP_ENABLE;
@@ -5685,7 +5695,7 @@ static int si_irq_init(struct radeon_device *rdev)
 
 int si_irq_set(struct radeon_device *rdev)
 {
-       u32 cp_int_cntl = CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE;
+       u32 cp_int_cntl;
        u32 cp_int_cntl1 = 0, cp_int_cntl2 = 0;
        u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0;
        u32 hpd1 = 0, hpd2 = 0, hpd3 = 0, hpd4 = 0, hpd5 = 0, hpd6 = 0;
@@ -5706,6 +5716,9 @@ int si_irq_set(struct radeon_device *rdev)
                return 0;
        }
 
+       cp_int_cntl = RREG32(CP_INT_CNTL_RING0) &
+               (CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE);
+
        if (!ASIC_IS_NODCE(rdev)) {
                hpd1 = RREG32(DC_HPD1_INT_CONTROL) & ~DC_HPDx_INT_EN;
                hpd2 = RREG32(DC_HPD2_INT_CONTROL) & ~DC_HPDx_INT_EN;
index 5be9b4e723507ea1992df820b96aef9fec8de5b9..cfe5d4d289159c832d71375e6eca8090adab7c3f 100644 (file)
@@ -6075,12 +6075,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-       ret = si_dpm_force_performance_level(rdev, RADEON_DPM_FORCED_LEVEL_AUTO);
-       if (ret) {
-               DRM_ERROR("si_dpm_force_performance_level failed\n");
-               return ret;
-       }
-
        si_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
                            RADEON_CG_BLOCK_MC |
                            RADEON_CG_BLOCK_SDMA |
index 5f524c0a541e453b3b882375ca2febeddf18c867..d422a1cbf727b375c467bcf78dc417431c7db2fd 100644 (file)
@@ -29,8 +29,8 @@
 #include "ppsmc.h"
 #include "radeon_ucode.h"
 
-int si_set_smc_sram_address(struct radeon_device *rdev,
-                           u32 smc_address, u32 limit)
+static int si_set_smc_sram_address(struct radeon_device *rdev,
+                                  u32 smc_address, u32 limit)
 {
        if (smc_address & 3)
                return -EINVAL;
@@ -47,7 +47,8 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev,
                         u32 smc_start_address,
                         const u8 *src, u32 byte_count, u32 limit)
 {
-       int ret;
+       unsigned long flags;
+       int ret = 0;
        u32 data, original_data, addr, extra_shift;
 
        if (smc_start_address & 3)
@@ -57,13 +58,14 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev,
 
        addr = smc_start_address;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        while (byte_count >= 4) {
                /* SMC address space is BE */
                data = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | src[3];
 
                ret = si_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                WREG32(SMC_IND_DATA_0, data);
 
@@ -78,7 +80,7 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev,
 
                ret = si_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                original_data = RREG32(SMC_IND_DATA_0);
 
@@ -96,11 +98,15 @@ int si_copy_bytes_to_smc(struct radeon_device *rdev,
 
                ret = si_set_smc_sram_address(rdev, addr, limit);
                if (ret)
-                       return ret;
+                       goto done;
 
                WREG32(SMC_IND_DATA_0, data);
        }
-       return 0;
+
+done:
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
+
+       return ret;
 }
 
 void si_start_smc(struct radeon_device *rdev)
@@ -203,6 +209,7 @@ PPSMC_Result si_wait_for_smc_inactive(struct radeon_device *rdev)
 
 int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
 {
+       unsigned long flags;
        u32 ucode_start_address;
        u32 ucode_size;
        const u8 *src;
@@ -241,6 +248,7 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
                return -EINVAL;
 
        src = (const u8 *)rdev->smc_fw->data;
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        WREG32(SMC_IND_INDEX_0, ucode_start_address);
        WREG32_P(SMC_IND_ACCESS_CNTL, AUTO_INCREMENT_IND_0, ~AUTO_INCREMENT_IND_0);
        while (ucode_size >= 4) {
@@ -253,6 +261,7 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
                ucode_size -= 4;
        }
        WREG32_P(SMC_IND_ACCESS_CNTL, 0, ~AUTO_INCREMENT_IND_0);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
        return 0;
 }
@@ -260,25 +269,29 @@ int si_load_smc_ucode(struct radeon_device *rdev, u32 limit)
 int si_read_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
                           u32 *value, u32 limit)
 {
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        ret = si_set_smc_sram_address(rdev, smc_address, limit);
-       if (ret)
-               return ret;
+       if (ret == 0)
+               *value = RREG32(SMC_IND_DATA_0);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
-       *value = RREG32(SMC_IND_DATA_0);
-       return 0;
+       return ret;
 }
 
 int si_write_smc_sram_dword(struct radeon_device *rdev, u32 smc_address,
                            u32 value, u32 limit)
 {
+       unsigned long flags;
        int ret;
 
+       spin_lock_irqsave(&rdev->smc_idx_lock, flags);
        ret = si_set_smc_sram_address(rdev, smc_address, limit);
-       if (ret)
-               return ret;
+       if (ret == 0)
+               WREG32(SMC_IND_DATA_0, value);
+       spin_unlock_irqrestore(&rdev->smc_idx_lock, flags);
 
-       WREG32(SMC_IND_DATA_0, value);
-       return 0;
+       return ret;
 }
index 864761c0120ecfaa5239d31fd9b06b278ad7d76c..96ea6db8bf575e7a45f6af501e26120f7e996a9a 100644 (file)
@@ -1319,8 +1319,6 @@ int sumo_dpm_set_power_state(struct radeon_device *rdev)
        if (pi->enable_dpm)
                sumo_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
-       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
-
        return 0;
 }
 
index b07b7b8f1aff4523bfe955a0beddbc041efb9164..7f998bf1cc9dd796b412dae45184dc5f1c76f184 100644 (file)
@@ -1068,6 +1068,17 @@ static void trinity_update_requested_ps(struct radeon_device *rdev,
        pi->requested_rps.ps_priv = &pi->requested_ps;
 }
 
+void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
+{
+       struct trinity_power_info *pi = trinity_get_pi(rdev);
+
+       if (pi->enable_bapm) {
+               trinity_acquire_mutex(rdev);
+               trinity_dpm_bapm_enable(rdev, enable);
+               trinity_release_mutex(rdev);
+       }
+}
+
 int trinity_dpm_enable(struct radeon_device *rdev)
 {
        struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1091,6 +1102,7 @@ int trinity_dpm_enable(struct radeon_device *rdev)
        trinity_program_sclk_dpm(rdev);
        trinity_start_dpm(rdev);
        trinity_wait_for_dpm_enabled(rdev);
+       trinity_dpm_bapm_enable(rdev, false);
        trinity_release_mutex(rdev);
 
        if (rdev->irq.installed &&
@@ -1116,6 +1128,7 @@ void trinity_dpm_disable(struct radeon_device *rdev)
                trinity_release_mutex(rdev);
                return;
        }
+       trinity_dpm_bapm_enable(rdev, false);
        trinity_disable_clock_power_gating(rdev);
        sumo_clear_vc(rdev);
        trinity_wait_for_level_0(rdev);
@@ -1212,6 +1225,8 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
 
        trinity_acquire_mutex(rdev);
        if (pi->enable_dpm) {
+               if (pi->enable_bapm)
+                       trinity_dpm_bapm_enable(rdev, rdev->pm.dpm.ac_power);
                trinity_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
                trinity_enable_power_level_0(rdev);
                trinity_force_level_0(rdev);
@@ -1221,7 +1236,6 @@ int trinity_dpm_set_power_state(struct radeon_device *rdev)
                trinity_force_level_0(rdev);
                trinity_unforce_levels(rdev);
                trinity_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
-               rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
        }
        trinity_release_mutex(rdev);
 
@@ -1854,6 +1868,7 @@ int trinity_dpm_init(struct radeon_device *rdev)
        for (i = 0; i < SUMO_MAX_HARDWARE_POWERLEVELS; i++)
                pi->at[i] = TRINITY_AT_DFLT;
 
+       pi->enable_bapm = true;
        pi->enable_nbps_policy = true;
        pi->enable_sclk_ds = true;
        pi->enable_gfx_power_gating = true;
index e82df071f8b3e5e6f64265f150aa3c1fffb90b5a..c261657750cacd791876db78b1bea618cced24ac 100644 (file)
@@ -108,6 +108,7 @@ struct trinity_power_info {
        bool enable_auto_thermal_throttling;
        bool enable_dpm;
        bool enable_sclk_ds;
+       bool enable_bapm;
        bool uvd_dpm;
        struct radeon_ps current_rps;
        struct trinity_ps current_ps;
@@ -118,6 +119,7 @@ struct trinity_power_info {
 #define TRINITY_AT_DFLT            30
 
 /* trinity_smc.c */
+int trinity_dpm_bapm_enable(struct radeon_device *rdev, bool enable);
 int trinity_dpm_config(struct radeon_device *rdev, bool enable);
 int trinity_uvd_dpm_config(struct radeon_device *rdev);
 int trinity_dpm_force_state(struct radeon_device *rdev, u32 n);
index a42d89f1830cce2ae6611163601755c9de5243d6..9672bcbc7312218a357f07ae54393ed511284279 100644 (file)
@@ -56,6 +56,14 @@ static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id)
        return 0;
 }
 
+int trinity_dpm_bapm_enable(struct radeon_device *rdev, bool enable)
+{
+       if (enable)
+               return trinity_notify_message_to_smu(rdev, PPSMC_MSG_EnableBAPM);
+       else
+               return trinity_notify_message_to_smu(rdev, PPSMC_MSG_DisableBAPM);
+}
+
 int trinity_dpm_config(struct radeon_device *rdev, bool enable)
 {
        if (enable)
index 58a5f3261c0b083f026087f8722bf6e6915ea25f..a868176c258a95aee788253038637b83ec54a78f 100644 (file)
@@ -218,7 +218,7 @@ struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
                                               uint32_t key)
 {
        struct ttm_object_device *tdev = tfile->tdev;
-       struct ttm_base_object *base;
+       struct ttm_base_object *uninitialized_var(base);
        struct drm_hash_item *hash;
        int ret;
 
index bd2a3b40cd129b30d4445a8cdca8adec2eb492f9..863bef9f923422e4670e3f11ff07384f568afc67 100644 (file)
@@ -377,28 +377,26 @@ out:
        return nr_free;
 }
 
-/* Get good estimation how many pages are free in pools */
-static int ttm_pool_get_num_unused_pages(void)
-{
-       unsigned i;
-       int total = 0;
-       for (i = 0; i < NUM_POOLS; ++i)
-               total += _manager->pools[i].npages;
-
-       return total;
-}
-
 /**
  * Callback for mm to request pool to reduce number of page held.
+ *
+ * XXX: (dchinner) Deadlock warning!
+ *
+ * ttm_page_pool_free() does memory allocation using GFP_KERNEL.  that means
+ * this can deadlock when called a sc->gfp_mask that is not equal to
+ * GFP_KERNEL.
+ *
+ * This code is crying out for a shrinker per pool....
  */
-static int ttm_pool_mm_shrink(struct shrinker *shrink,
-                             struct shrink_control *sc)
+static unsigned long
+ttm_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        static atomic_t start_pool = ATOMIC_INIT(0);
        unsigned i;
        unsigned pool_offset = atomic_add_return(1, &start_pool);
        struct ttm_page_pool *pool;
        int shrink_pages = sc->nr_to_scan;
+       unsigned long freed = 0;
 
        pool_offset = pool_offset % NUM_POOLS;
        /* select start pool in round robin fashion */
@@ -408,14 +406,28 @@ static int ttm_pool_mm_shrink(struct shrinker *shrink,
                        break;
                pool = &_manager->pools[(i + pool_offset)%NUM_POOLS];
                shrink_pages = ttm_page_pool_free(pool, nr_free);
+               freed += nr_free - shrink_pages;
        }
-       /* return estimated number of unused pages in pool */
-       return ttm_pool_get_num_unused_pages();
+       return freed;
+}
+
+
+static unsigned long
+ttm_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+       unsigned i;
+       unsigned long count = 0;
+
+       for (i = 0; i < NUM_POOLS; ++i)
+               count += _manager->pools[i].npages;
+
+       return count;
 }
 
 static void ttm_pool_mm_shrink_init(struct ttm_pool_manager *manager)
 {
-       manager->mm_shrink.shrink = &ttm_pool_mm_shrink;
+       manager->mm_shrink.count_objects = ttm_pool_shrink_count;
+       manager->mm_shrink.scan_objects = ttm_pool_shrink_scan;
        manager->mm_shrink.seeks = 1;
        register_shrinker(&manager->mm_shrink);
 }
index b8b394319b45947facd37036817b73ac39a2661c..7957beeeaf733752e58c6b57f5d5a5a531113a09 100644 (file)
@@ -918,19 +918,6 @@ int ttm_dma_populate(struct ttm_dma_tt *ttm_dma, struct device *dev)
 }
 EXPORT_SYMBOL_GPL(ttm_dma_populate);
 
-/* Get good estimation how many pages are free in pools */
-static int ttm_dma_pool_get_num_unused_pages(void)
-{
-       struct device_pools *p;
-       unsigned total = 0;
-
-       mutex_lock(&_manager->lock);
-       list_for_each_entry(p, &_manager->pools, pools)
-               total += p->pool->npages_free;
-       mutex_unlock(&_manager->lock);
-       return total;
-}
-
 /* Put all pages in pages list to correct pool to wait for reuse */
 void ttm_dma_unpopulate(struct ttm_dma_tt *ttm_dma, struct device *dev)
 {
@@ -1002,18 +989,29 @@ EXPORT_SYMBOL_GPL(ttm_dma_unpopulate);
 
 /**
  * Callback for mm to request pool to reduce number of page held.
+ *
+ * XXX: (dchinner) Deadlock warning!
+ *
+ * ttm_dma_page_pool_free() does GFP_KERNEL memory allocation, and so attention
+ * needs to be paid to sc->gfp_mask to determine if this can be done or not.
+ * GFP_KERNEL memory allocation in a GFP_ATOMIC reclaim context woul dbe really
+ * bad.
+ *
+ * I'm getting sadder as I hear more pathetical whimpers about needing per-pool
+ * shrinkers
  */
-static int ttm_dma_pool_mm_shrink(struct shrinker *shrink,
-                                 struct shrink_control *sc)
+static unsigned long
+ttm_dma_pool_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        static atomic_t start_pool = ATOMIC_INIT(0);
        unsigned idx = 0;
        unsigned pool_offset = atomic_add_return(1, &start_pool);
        unsigned shrink_pages = sc->nr_to_scan;
        struct device_pools *p;
+       unsigned long freed = 0;
 
        if (list_empty(&_manager->pools))
-               return 0;
+               return SHRINK_STOP;
 
        mutex_lock(&_manager->lock);
        pool_offset = pool_offset % _manager->npools;
@@ -1029,18 +1027,33 @@ static int ttm_dma_pool_mm_shrink(struct shrinker *shrink,
                        continue;
                nr_free = shrink_pages;
                shrink_pages = ttm_dma_page_pool_free(p->pool, nr_free);
+               freed += nr_free - shrink_pages;
+
                pr_debug("%s: (%s:%d) Asked to shrink %d, have %d more to go\n",
                         p->pool->dev_name, p->pool->name, current->pid,
                         nr_free, shrink_pages);
        }
        mutex_unlock(&_manager->lock);
-       /* return estimated number of unused pages in pool */
-       return ttm_dma_pool_get_num_unused_pages();
+       return freed;
+}
+
+static unsigned long
+ttm_dma_pool_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+       struct device_pools *p;
+       unsigned long count = 0;
+
+       mutex_lock(&_manager->lock);
+       list_for_each_entry(p, &_manager->pools, pools)
+               count += p->pool->npages_free;
+       mutex_unlock(&_manager->lock);
+       return count;
 }
 
 static void ttm_dma_pool_mm_shrink_init(struct ttm_pool_manager *manager)
 {
-       manager->mm_shrink.shrink = &ttm_dma_pool_mm_shrink;
+       manager->mm_shrink.count_objects = ttm_dma_pool_shrink_count;
+       manager->mm_shrink.scan_objects = &ttm_dma_pool_shrink_scan;
        manager->mm_shrink.seeks = 1;
        register_shrinker(&manager->mm_shrink);
 }
index 5e93a52d4f2c7a6183a36e70c976d8a1bbf9871e..210d50365162d39d8b2048ba3d8c0e567ed95bf9 100644 (file)
@@ -170,7 +170,7 @@ void ttm_tt_destroy(struct ttm_tt *ttm)
                ttm_tt_unbind(ttm);
        }
 
-       if (likely(ttm->pages != NULL)) {
+       if (ttm->state == tt_unbound) {
                ttm->bdev->driver->ttm_tt_unpopulate(ttm);
        }
 
index 8dbe9d0ae9a73840ae6270bac3776ca239954a11..8bf646183bac837a24f335bb46237c5c4a5d5e43 100644 (file)
@@ -97,7 +97,6 @@ int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page);
        switch (ret) {
        case -EAGAIN:
-               set_need_resched();
        case 0:
        case -ERESTARTSYS:
                return VM_FAULT_NOPAGE;
index e893f6e1937d7c79e2de772e00d1ed0b9a936e33..af02597083586d9f6dc7df613cb825455f3f0e67 100644 (file)
@@ -257,9 +257,9 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
                if (!conflict->bridge_has_one_vga) {
                        vga_irq_set_state(conflict, false);
                        flags |= PCI_VGA_STATE_CHANGE_DECODES;
-                       if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                       if (match & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
                                pci_bits |= PCI_COMMAND_MEMORY;
-                       if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                       if (match & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
                                pci_bits |= PCI_COMMAND_IO;
                }
 
@@ -267,11 +267,11 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
                        flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
 
                pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
-               conflict->owns &= ~lwants;
+               conflict->owns &= ~match;
                /* If he also owned non-legacy, that is no longer the case */
-               if (lwants & VGA_RSRC_LEGACY_MEM)
+               if (match & VGA_RSRC_LEGACY_MEM)
                        conflict->owns &= ~VGA_RSRC_NORMAL_MEM;
-               if (lwants & VGA_RSRC_LEGACY_IO)
+               if (match & VGA_RSRC_LEGACY_IO)
                        conflict->owns &= ~VGA_RSRC_NORMAL_IO;
        }
 
@@ -644,10 +644,12 @@ bail:
 static inline void vga_update_device_decodes(struct vga_device *vgadev,
                                             int new_decodes)
 {
-       int old_decodes;
-       struct vga_device *new_vgadev, *conflict;
+       int old_decodes, decodes_removed, decodes_unlocked;
 
        old_decodes = vgadev->decodes;
+       decodes_removed = ~new_decodes & old_decodes;
+       decodes_unlocked = vgadev->locks & decodes_removed;
+       vgadev->owns &= ~decodes_removed;
        vgadev->decodes = new_decodes;
 
        pr_info("vgaarb: device changed decodes: PCI:%s,olddecodes=%s,decodes=%s:owns=%s\n",
@@ -656,31 +658,22 @@ static inline void vga_update_device_decodes(struct vga_device *vgadev,
                vga_iostate_to_str(vgadev->decodes),
                vga_iostate_to_str(vgadev->owns));
 
-
-       /* if we own the decodes we should move them along to
-          another card */
-       if ((vgadev->owns & old_decodes) && (vga_count > 1)) {
-               /* set us to own nothing */
-               vgadev->owns &= ~old_decodes;
-               list_for_each_entry(new_vgadev, &vga_list, list) {
-                       if ((new_vgadev != vgadev) &&
-                           (new_vgadev->decodes & VGA_RSRC_LEGACY_MASK)) {
-                               pr_info("vgaarb: transferring owner from PCI:%s to PCI:%s\n", pci_name(vgadev->pdev), pci_name(new_vgadev->pdev));
-                               conflict = __vga_tryget(new_vgadev, VGA_RSRC_LEGACY_MASK);
-                               if (!conflict)
-                                       __vga_put(new_vgadev, VGA_RSRC_LEGACY_MASK);
-                               break;
-                       }
-               }
+       /* if we removed locked decodes, lock count goes to zero, and release */
+       if (decodes_unlocked) {
+               if (decodes_unlocked & VGA_RSRC_LEGACY_IO)
+                       vgadev->io_lock_cnt = 0;
+               if (decodes_unlocked & VGA_RSRC_LEGACY_MEM)
+                       vgadev->mem_lock_cnt = 0;
+               __vga_put(vgadev, decodes_unlocked);
        }
 
        /* change decodes counter */
-       if (old_decodes != new_decodes) {
-               if (new_decodes & (VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM))
-                       vga_decode_count++;
-               else
-                       vga_decode_count--;
-       }
+       if (old_decodes & VGA_RSRC_LEGACY_MASK &&
+           !(new_decodes & VGA_RSRC_LEGACY_MASK))
+               vga_decode_count--;
+       if (!(old_decodes & VGA_RSRC_LEGACY_MASK) &&
+           new_decodes & VGA_RSRC_LEGACY_MASK)
+               vga_decode_count++;
        pr_debug("vgaarb: decoding count now is: %d\n", vga_decode_count);
 }
 
index 3d7c9f67b6d7631504b9fbaed82fff152e295bb0..71b70e3a7a7183068dbc18d3b224bf3894444497 100644 (file)
@@ -773,7 +773,7 @@ config HID_ZYDACRON
 
 config HID_SENSOR_HUB
        tristate "HID Sensors framework support"
-       depends on HID && GENERIC_HARDIRQS
+       depends on HID
        select MFD_CORE
        default n
        ---help---
index ae88a97f976e614fe776d451bd5e5abc5ec1e01e..b8470b1a10fe8b40bef83386a0476591e5a067d7 100644 (file)
@@ -94,7 +94,6 @@ EXPORT_SYMBOL_GPL(hid_register_report);
 static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
 {
        struct hid_field *field;
-       int i;
 
        if (report->maxfield == HID_MAX_FIELDS) {
                hid_err(report->device, "too many fields in report\n");
@@ -113,9 +112,6 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
        field->value = (s32 *)(field->usage + usages);
        field->report = report;
 
-       for (i = 0; i < usages; i++)
-               field->usage[i].usage_index = i;
-
        return field;
 }
 
@@ -226,9 +222,9 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
 {
        struct hid_report *report;
        struct hid_field *field;
-       int usages;
+       unsigned usages;
        unsigned offset;
-       int i;
+       unsigned i;
 
        report = hid_register_report(parser->device, report_type, parser->global.report_id);
        if (!report) {
@@ -255,7 +251,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
        if (!parser->local.usage_index) /* Ignore padding fields */
                return 0;
 
-       usages = max_t(int, parser->local.usage_index, parser->global.report_count);
+       usages = max_t(unsigned, parser->local.usage_index,
+                                parser->global.report_count);
 
        field = hid_register_field(report, usages, parser->global.report_count);
        if (!field)
@@ -266,13 +263,14 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
        field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
 
        for (i = 0; i < usages; i++) {
-               int j = i;
+               unsigned j = i;
                /* Duplicate the last usage we parsed if we have excess values */
                if (i >= parser->local.usage_index)
                        j = parser->local.usage_index - 1;
                field->usage[i].hid = parser->local.usage[j];
                field->usage[i].collection_index =
                        parser->local.collection_index[j];
+               field->usage[i].usage_index = i;
        }
 
        field->maxusage = usages;
@@ -801,6 +799,64 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size)
 }
 EXPORT_SYMBOL_GPL(hid_parse_report);
 
+static const char * const hid_report_names[] = {
+       "HID_INPUT_REPORT",
+       "HID_OUTPUT_REPORT",
+       "HID_FEATURE_REPORT",
+};
+/**
+ * hid_validate_values - validate existing device report's value indexes
+ *
+ * @device: hid device
+ * @type: which report type to examine
+ * @id: which report ID to examine (0 for first)
+ * @field_index: which report field to examine
+ * @report_counts: expected number of values
+ *
+ * Validate the number of values in a given field of a given report, after
+ * parsing.
+ */
+struct hid_report *hid_validate_values(struct hid_device *hid,
+                                      unsigned int type, unsigned int id,
+                                      unsigned int field_index,
+                                      unsigned int report_counts)
+{
+       struct hid_report *report;
+
+       if (type > HID_FEATURE_REPORT) {
+               hid_err(hid, "invalid HID report type %u\n", type);
+               return NULL;
+       }
+
+       if (id >= HID_MAX_IDS) {
+               hid_err(hid, "invalid HID report id %u\n", id);
+               return NULL;
+       }
+
+       /*
+        * Explicitly not using hid_get_report() here since it depends on
+        * ->numbered being checked, which may not always be the case when
+        * drivers go to access report values.
+        */
+       report = hid->report_enum[type].report_id_hash[id];
+       if (!report) {
+               hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
+               return NULL;
+       }
+       if (report->maxfield <= field_index) {
+               hid_err(hid, "not enough fields in %s %u\n",
+                       hid_report_names[type], id);
+               return NULL;
+       }
+       if (report->field[field_index]->report_count < report_counts) {
+               hid_err(hid, "not enough values in %s %u field %u\n",
+                       hid_report_names[type], id, field_index);
+               return NULL;
+       }
+       return report;
+}
+EXPORT_SYMBOL_GPL(hid_validate_values);
+
 /**
  * hid_open_report - open a driver-specific device report
  *
@@ -1296,7 +1352,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
                        goto out;
        }
 
-       if (hid->claimed != HID_CLAIMED_HIDRAW) {
+       if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
                for (a = 0; a < report->maxfield; a++)
                        hid_input_field(hid, report->field[a], cdata, interrupt);
                hdrv = hid->driver;
index b420f4a0fd28101e0e697a48e581fe31826f9a56..8741d953dcc80acb552bac187ffe6997ad95ca4e 100644 (file)
@@ -485,6 +485,10 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
        if (field->flags & HID_MAIN_ITEM_CONSTANT)
                goto ignore;
 
+       /* Ignore if report count is out of bounds. */
+       if (field->report_count < 1)
+               goto ignore;
+
        /* only LED usages are supported in output fields */
        if (field->report_type == HID_OUTPUT_REPORT &&
                        (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) {
@@ -1236,7 +1240,11 @@ static void report_features(struct hid_device *hid)
 
        rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
        list_for_each_entry(rep, &rep_enum->report_list, list)
-               for (i = 0; i < rep->maxfield; i++)
+               for (i = 0; i < rep->maxfield; i++) {
+                       /* Ignore if report count is out of bounds. */
+                       if (rep->field[i]->report_count < 1)
+                               continue;
+
                        for (j = 0; j < rep->field[i]->maxusage; j++) {
                                /* Verify if Battery Strength feature is available */
                                hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
@@ -1245,6 +1253,7 @@ static void report_features(struct hid_device *hid)
                                        drv->feature_mapping(hid, rep->field[i],
                                                             rep->field[i]->usage + j);
                        }
+               }
 }
 
 static struct hid_input *hidinput_allocate(struct hid_device *hid)
index 07837f5a4eb88adaae7ba8c20f4517a15754b440..31cf29a6ba17551ff5244a0f243d48a4719e662c 100644 (file)
@@ -339,7 +339,15 @@ static int tpkbd_probe_tp(struct hid_device *hdev)
        struct tpkbd_data_pointer *data_pointer;
        size_t name_sz = strlen(dev_name(dev)) + 16;
        char *name_mute, *name_micmute;
-       int ret;
+       int i, ret;
+
+       /* Validate required reports. */
+       for (i = 0; i < 4; i++) {
+               if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
+                       return -ENODEV;
+       }
+       if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
+               return -ENODEV;
 
        if (sysfs_create_group(&hdev->dev.kobj,
                                &tpkbd_attr_group_pointer)) {
@@ -406,22 +414,27 @@ static int tpkbd_probe(struct hid_device *hdev,
        ret = hid_parse(hdev);
        if (ret) {
                hid_err(hdev, "hid_parse failed\n");
-               goto err_free;
+               goto err;
        }
 
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "hid_hw_start failed\n");
-               goto err_free;
+               goto err;
        }
 
        uhdev = (struct usbhid_device *) hdev->driver_data;
 
-       if (uhdev->ifnum == 1)
-               return tpkbd_probe_tp(hdev);
+       if (uhdev->ifnum == 1) {
+               ret = tpkbd_probe_tp(hdev);
+               if (ret)
+                       goto err_hid;
+       }
 
        return 0;
-err_free:
+err_hid:
+       hid_hw_stop(hdev);
+err:
        return ret;
 }
 
index b3cd1507dda2eab0eb09c0c48e006505eabac153..1a42eaa6ca0234a054631544732db69484c5eb82 100644 (file)
@@ -64,26 +64,13 @@ int lg2ff_init(struct hid_device *hid)
        struct hid_report *report;
        struct hid_input *hidinput = list_entry(hid->inputs.next,
                                                struct hid_input, list);
-       struct list_head *report_list =
-                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct input_dev *dev = hidinput->input;
        int error;
 
-       if (list_empty(report_list)) {
-               hid_err(hid, "no output report found\n");
+       /* Check that the report looks ok */
+       report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7);
+       if (!report)
                return -ENODEV;
-       }
-
-       report = list_entry(report_list->next, struct hid_report, list);
-
-       if (report->maxfield < 1) {
-               hid_err(hid, "output report is empty\n");
-               return -ENODEV;
-       }
-       if (report->field[0]->report_count < 7) {
-               hid_err(hid, "not enough values in the field\n");
-               return -ENODEV;
-       }
 
        lg2ff = kmalloc(sizeof(struct lg2ff_device), GFP_KERNEL);
        if (!lg2ff)
index e52f181f6aa14dd4fd8229ce2ecb379ccf80533c..8c2da183d3bc71354d82b635b5234a70ca106850 100644 (file)
@@ -66,10 +66,11 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
        int x, y;
 
 /*
- * Maxusage should always be 63 (maximum fields)
- * likely a better way to ensure this data is clean
+ * Available values in the field should always be 63, but we only use up to
+ * 35. Instead, clear the entire area, however big it is.
  */
-       memset(report->field[0]->value, 0, sizeof(__s32)*report->field[0]->maxusage);
+       memset(report->field[0]->value, 0,
+              sizeof(__s32) * report->field[0]->report_count);
 
        switch (effect->type) {
        case FF_CONSTANT:
@@ -129,32 +130,14 @@ static const signed short ff3_joystick_ac[] = {
 int lg3ff_init(struct hid_device *hid)
 {
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct input_dev *dev = hidinput->input;
-       struct hid_report *report;
-       struct hid_field *field;
        const signed short *ff_bits = ff3_joystick_ac;
        int error;
        int i;
 
-       /* Find the report to use */
-       if (list_empty(report_list)) {
-               hid_err(hid, "No output report found\n");
-               return -1;
-       }
-
        /* Check that the report looks ok */
-       report = list_entry(report_list->next, struct hid_report, list);
-       if (!report) {
-               hid_err(hid, "NULL output report\n");
-               return -1;
-       }
-
-       field = report->field[0];
-       if (!field) {
-               hid_err(hid, "NULL field\n");
-               return -1;
-       }
+       if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 35))
+               return -ENODEV;
 
        /* Assume single fixed device G940 */
        for (i = 0; ff_bits[i] >= 0; i++)
index 0ddae2a00d59a595b4d7ad436dc8cedcfdde7b71..8782fe1aaa0796e42d17f1ad39d1c72c652d58c5 100644 (file)
@@ -484,34 +484,16 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde
 int lg4ff_init(struct hid_device *hid)
 {
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct input_dev *dev = hidinput->input;
-       struct hid_report *report;
-       struct hid_field *field;
        struct lg4ff_device_entry *entry;
        struct lg_drv_data *drv_data;
        struct usb_device_descriptor *udesc;
        int error, i, j;
        __u16 bcdDevice, rev_maj, rev_min;
 
-       /* Find the report to use */
-       if (list_empty(report_list)) {
-               hid_err(hid, "No output report found\n");
-               return -1;
-       }
-
        /* Check that the report looks ok */
-       report = list_entry(report_list->next, struct hid_report, list);
-       if (!report) {
-               hid_err(hid, "NULL output report\n");
+       if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
                return -1;
-       }
-
-       field = report->field[0];
-       if (!field) {
-               hid_err(hid, "NULL field\n");
-               return -1;
-       }
 
        /* Check what wheel has been connected */
        for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) {
index d7ea8c845b4038ec2a943baa6f169ade22e82e3d..e1394af0ae7ba06701ad106896fb9391c417d6c0 100644 (file)
@@ -128,27 +128,14 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
 int lgff_init(struct hid_device* hid)
 {
        struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
-       struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct input_dev *dev = hidinput->input;
-       struct hid_report *report;
-       struct hid_field *field;
        const signed short *ff_bits = ff_joystick;
        int error;
        int i;
 
-       /* Find the report to use */
-       if (list_empty(report_list)) {
-               hid_err(hid, "No output report found\n");
-               return -1;
-       }
-
        /* Check that the report looks ok */
-       report = list_entry(report_list->next, struct hid_report, list);
-       field = report->field[0];
-       if (!field) {
-               hid_err(hid, "NULL field\n");
-               return -1;
-       }
+       if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7))
+               return -ENODEV;
 
        for (i = 0; i < ARRAY_SIZE(devices); i++) {
                if (dev->id.vendor == devices[i].idVendor &&
index 7800b141056243400bfa316b7289e2c8431aa82a..2e5302462efb088b3f3019b26fedfc816ca493f5 100644 (file)
@@ -461,7 +461,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
        struct hid_report *report;
        struct hid_report_enum *output_report_enum;
        u8 *data = (u8 *)(&dj_report->device_index);
-       int i;
+       unsigned int i;
 
        output_report_enum = &hdev->report_enum[HID_OUTPUT_REPORT];
        report = output_report_enum->report_id_hash[REPORT_ID_DJ_SHORT];
@@ -471,7 +471,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
                return -ENODEV;
        }
 
-       for (i = 0; i < report->field[0]->report_count; i++)
+       for (i = 0; i < DJREPORT_SHORT_LENGTH - 1; i++)
                report->field[0]->value[i] = data[i];
 
        hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
@@ -791,6 +791,12 @@ static int logi_dj_probe(struct hid_device *hdev,
                goto hid_parse_fail;
        }
 
+       if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, REPORT_ID_DJ_SHORT,
+                                0, DJREPORT_SHORT_LENGTH - 1)) {
+               retval = -ENODEV;
+               goto hid_parse_fail;
+       }
+
        /* Starts the usb device and connects to upper interfaces hiddev and
         * hidraw */
        retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
index ac28f08c38660b0051500242f8562b587007cf90..5e5fe1b8eebb73e5d4533997a889eee87d637150 100644 (file)
@@ -101,9 +101,9 @@ struct mt_device {
        unsigned last_slot_field;       /* the last field of a slot */
        unsigned mt_report_id;  /* the report ID of the multitouch device */
        unsigned pen_report_id; /* the report ID of the pen device */
-       __s8 inputmode;         /* InputMode HID feature, -1 if non-existent */
-       __s8 inputmode_index;   /* InputMode HID feature index in the report */
-       __s8 maxcontact_report_id;      /* Maximum Contact Number HID feature,
+       __s16 inputmode;        /* InputMode HID feature, -1 if non-existent */
+       __s16 inputmode_index;  /* InputMode HID feature index in the report */
+       __s16 maxcontact_report_id;     /* Maximum Contact Number HID feature,
                                   -1 if non-existent */
        __u8 num_received;      /* how many contacts we received */
        __u8 num_expected;      /* expected last contact index */
@@ -312,20 +312,18 @@ static void mt_feature_mapping(struct hid_device *hdev,
                struct hid_field *field, struct hid_usage *usage)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
-       int i;
 
        switch (usage->hid) {
        case HID_DG_INPUTMODE:
-               td->inputmode = field->report->id;
-               td->inputmode_index = 0; /* has to be updated below */
-
-               for (i=0; i < field->maxusage; i++) {
-                       if (field->usage[i].hid == usage->hid) {
-                               td->inputmode_index = i;
-                               break;
-                       }
+               /* Ignore if value index is out of bounds. */
+               if (usage->usage_index >= field->report_count) {
+                       dev_err(&hdev->dev, "HID_DG_INPUTMODE out of range\n");
+                       break;
                }
 
+               td->inputmode = field->report->id;
+               td->inputmode_index = usage->usage_index;
+
                break;
        case HID_DG_CONTACTMAX:
                td->maxcontact_report_id = field->report->id;
@@ -511,6 +509,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        mt_store_field(usage, td, hi);
                        return 1;
                case HID_DG_CONTACTCOUNT:
+                       /* Ignore if indexes are out of bounds. */
+                       if (field->index >= field->report->maxfield ||
+                           usage->usage_index >= field->report_count)
+                               return 1;
                        td->cc_index = field->index;
                        td->cc_value_index = usage->usage_index;
                        return 1;
index 30dbb6b40bbf17e93c63b2bd6d3eb3b7f8111593..b18320db5f7d18cba708ecd306ee3f394abebddb 100644 (file)
@@ -537,6 +537,10 @@ static int buzz_init(struct hid_device *hdev)
        drv_data = hid_get_drvdata(hdev);
        BUG_ON(!(drv_data->quirks & BUZZ_CONTROLLER));
 
+       /* Validate expected report characteristics. */
+       if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
+               return -ENODEV;
+
        buzz = kzalloc(sizeof(*buzz), GFP_KERNEL);
        if (!buzz) {
                hid_err(hdev, "Insufficient memory, cannot allocate driver data\n");
index d1649119211277275840a1bee984ed93de28c025..29f328f411fb5454e03d46406c880fc9a5de0516 100644 (file)
@@ -249,6 +249,11 @@ static int steelseries_srws1_probe(struct hid_device *hdev,
                goto err_free;
        }
 
+       if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 16)) {
+               ret = -ENODEV;
+               goto err_free;
+       }
+
        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
        if (ret) {
                hid_err(hdev, "hw start failed\n");
index 6ec28a37c146ab58d623ef1ccaafc38b3dcd9477..a29756c6ca02d064faee371143e750b19094f26c 100644 (file)
@@ -68,21 +68,13 @@ static int zpff_init(struct hid_device *hid)
        struct hid_report *report;
        struct hid_input *hidinput = list_entry(hid->inputs.next,
                                                struct hid_input, list);
-       struct list_head *report_list =
-                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
        struct input_dev *dev = hidinput->input;
-       int error;
+       int i, error;
 
-       if (list_empty(report_list)) {
-               hid_err(hid, "no output report found\n");
-               return -ENODEV;
-       }
-
-       report = list_entry(report_list->next, struct hid_report, list);
-
-       if (report->maxfield < 4) {
-               hid_err(hid, "not enough fields in report\n");
-               return -ENODEV;
+       for (i = 0; i < 4; i++) {
+               report = hid_validate_values(hid, HID_OUTPUT_REPORT, 0, i, 1);
+               if (!report)
+                       return -ENODEV;
        }
 
        zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
index 4fe49d2bfe1de5c44b61b6bb3cbcfa3acecec41e..eea81729651309b0598791d04778822e1f7cc7ff 100644 (file)
@@ -364,7 +364,7 @@ static ssize_t set_pwm1_enable(
        if (config < 0) {
                        dev_err(&client->dev,
                        "Error reading configuration register, aborting.\n");
-                       return -EIO;
+                       return config;
        }
 
        switch (val) {
@@ -416,11 +416,9 @@ static ssize_t get_temp_auto_point_temp(
        case 1:
                return sprintf(buf, "%d\n",
                        data->temp1_auto_point_temp[ix] * 1000);
-               break;
        case 2:
                return sprintf(buf, "%d\n",
                        data->temp2_auto_point_temp[ix] * 1000);
-               break;
        default:
                dev_dbg(dev, "Unknown attr->nr (%d).\n", nr);
                return -EINVAL;
@@ -513,7 +511,6 @@ static ssize_t set_temp_auto_point_temp(
                                count = -EIO;
                }
                goto EXIT;
-               break;
        case 1:
                ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124);
                ptemp[1] &= 0x7C;
@@ -665,7 +662,7 @@ static ssize_t set_fan1_div(
        if (config < 0) {
                dev_err(&client->dev,
                        "Error reading configuration register, aborting.\n");
-               return -EIO;
+               return config;
        }
        mutex_lock(&data->update_lock);
        switch (val) {
index b073056220873d4e147150b4e376b0f9c40c363d..2c137b26acb48bbe188243a189f05c1c8ed693c5 100644 (file)
@@ -248,7 +248,7 @@ static ssize_t set_temp_min(struct device *dev, struct device_attribute *da,
 
        int result = kstrtol(buf, 10, &val);
        if (result < 0)
-               return -EINVAL;
+               return result;
 
        val = DIV_ROUND_CLOSEST(val, 1000);
        if ((val < -63) || (val > 127))
@@ -272,7 +272,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *da,
 
        int result = kstrtol(buf, 10, &val);
        if (result < 0)
-               return -EINVAL;
+               return result;
 
        val = DIV_ROUND_CLOSEST(val, 1000);
        if ((val < -63) || (val > 127))
@@ -320,7 +320,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da,
 
        int status = kstrtol(buf, 10, &new_div);
        if (status < 0)
-               return -EINVAL;
+               return status;
 
        if (new_div == old_div) /* No change */
                return count;
@@ -394,7 +394,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
 
        int result = kstrtol(buf, 10, &rpm_target);
        if (result < 0)
-               return -EINVAL;
+               return result;
 
        /* Datasheet states 16384 as maximum RPM target (table 3.2) */
        if ((rpm_target < 0) || (rpm_target > 16384))
@@ -440,7 +440,7 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *da,
 
        int result = kstrtol(buf, 10, &new_value);
        if (result < 0)
-               return -EINVAL;
+               return result;
 
        mutex_lock(&data->update_lock);
        switch (new_value) {
index 89cfd64b3373880e94bd296dcdd3f2bbf1d69df2..ef91b8a6754924319c781b89eb83b2ec393fb3a9 100644 (file)
@@ -246,7 +246,7 @@ static struct vrm_model vrm_models[] = {
  */
 static u8 get_via_model_d_vrm(void)
 {
-       unsigned int vid, brand, dummy;
+       unsigned int vid, brand, __maybe_unused dummy;
        static const char *brands[4] = {
                "C7-M", "C7", "Eden", "C7-D"
        };
index e2b56a2b756c85b9e9e7aedcd76e8c7fe13f9672..632f1dc0fe1f90b3ccd85c3932d81460a7340767 100644 (file)
@@ -292,7 +292,7 @@ static int aem_init_ipmi_data(struct aem_ipmi_data *data, int iface,
                dev_err(bmc,
                        "Unable to register user with IPMI interface %d\n",
                        data->interface);
-               return -EACCES;
+               return err;
        }
 
        return 0;
index 18c062360ca7950e77ef4573ddf3dbc9fc16be82..70a39a8ac0160e520f6017225c71d1efedebca2c 100644 (file)
@@ -233,8 +233,7 @@ static int ina2xx_probe(struct i2c_client *client,
                return -ENOMEM;
 
        if (dev_get_platdata(&client->dev)) {
-               pdata =
-                 (struct ina2xx_platform_data *)dev_get_platdata(&client->dev);
+               pdata = dev_get_platdata(&client->dev);
                shunt = pdata->shunt_uohms;
        } else if (!of_property_read_u32(client->dev.of_node,
                                "shunt-resistor", &val)) {
index e633856370cf403247d5a44152f776fc39e56241..d65f3fd895ddda22d23164f1a0c94c870b77e2ce 100644 (file)
@@ -202,7 +202,6 @@ static void k10temp_remove(struct pci_dev *pdev)
                           &sensor_dev_attr_temp1_crit.dev_attr);
        device_remove_file(&pdev->dev,
                           &sensor_dev_attr_temp1_crit_hyst.dev_attr);
-       pci_set_drvdata(pdev, NULL);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(k10temp_id_table) = {
index 964c1d68827400ec9ac6d5ce515418c74294d3aa..ae26b06fa8190dd478456d12a637889c61bde0fe 100644 (file)
@@ -210,7 +210,7 @@ static int tmp421_init_client(struct i2c_client *client)
        if (config < 0) {
                dev_err(&client->dev,
                        "Could not read configuration register (%d)\n", config);
-               return -ENODEV;
+               return config;
        }
 
        config_orig = config;
index e380c6eef3af6500edc94b3a8db668bb59dfa258..7b7ea320a2588c9dfcfb107cbc6ab7f43e3e02c8 100644 (file)
@@ -75,7 +75,6 @@ config I2C_HELPER_AUTO
 
 config I2C_SMBUS
        tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO
-       depends on GENERIC_HARDIRQS
        help
          Say Y here if you want support for SMBus extensions to the I2C
          specification. At the moment, the only supported extension is
index fcdd321f709ecb2f284c3afefce962a2b1a8a42c..cdcbd8368ed344d205d7edb2edcdfe90919fd42f 100644 (file)
@@ -115,7 +115,7 @@ config I2C_I801
 
 config I2C_ISCH
        tristate "Intel SCH SMBus 1.0"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select LPC_SCH
        help
          Say Y here if you want to use SMBus controller on the Intel SCH
@@ -546,7 +546,6 @@ config I2C_NUC900
 
 config I2C_OCORES
        tristate "OpenCores I2C Controller"
-       depends on GENERIC_HARDIRQS
        help
          If you say yes to this option, support will be included for the
          OpenCores I2C controller. For details see
@@ -791,7 +790,7 @@ config I2C_DIOLAN_U2C
 
 config I2C_PARPORT
        tristate "Parallel port adapter"
-       depends on PARPORT && GENERIC_HARDIRQS
+       depends on PARPORT
        select I2C_ALGOBIT
        select I2C_SMBUS
        help
@@ -816,7 +815,6 @@ config I2C_PARPORT
 
 config I2C_PARPORT_LIGHT
        tristate "Parallel port adapter (light)"
-       depends on GENERIC_HARDIRQS
        select I2C_ALGOBIT
        select I2C_SMBUS
        help
index 57473415be10b3654fa1bbbbd30215082a01a9ba..132369fad4e0fefe09e10dd88ade2eaf9a8b1972 100644 (file)
@@ -662,7 +662,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
 #endif
        dev->dev = &pdev->dev;
        dev->irq = irq->start;
-       dev->pdata = dev_get_platdata(&dev->dev);
+       dev->pdata = dev_get_platdata(&pdev->dev);
        platform_set_drvdata(pdev, dev);
 
        if (!dev->pdata && pdev->dev.of_node) {
index cbea3271c1b1a43e564392b0107ac40a6356bc02..90cf0cda50c49e8f5db63298f182dd50708d3e57 100644 (file)
@@ -4,7 +4,6 @@
 
 menuconfig IIO
        tristate "Industrial I/O support"
-       depends on GENERIC_HARDIRQS
        help
          The industrial I/O subsystem provides a unified framework for
          drivers for many different types of embedded sensors using a
index d03ca4c1ff250d8345d5ebbda2c84d49a38a4ff4..495be09781b11e9baff1a181db5137b88f0b15d6 100644 (file)
@@ -8,7 +8,7 @@ config INFINIBAND_QIB
 
 config INFINIBAND_QIB_DCA
        bool "QIB DCA support"
-       depends on INFINIBAND_QIB && DCA && SMP && GENERIC_HARDIRQS && !(INFINIBAND_QIB=y && DCA=m)
+       depends on INFINIBAND_QIB && DCA && SMP && !(INFINIBAND_QIB=y && DCA=m)
        default y
        ---help---
        Setting this enables DCA support on some Intel chip sets
index 3f62041222f2131a308277218e9260d1e4ba5692..3591855cc5b54caeca1e9675757a43579537b4be 100644 (file)
@@ -1,7 +1,7 @@
 /*******************************************************************************
  * This file contains iSCSI extentions for RDMA (iSER) Verbs
  *
- * (c) Copyright 2013 RisingTide Systems LLC.
+ * (c) Copyright 2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -39,7 +39,17 @@ static DEFINE_MUTEX(device_list_mutex);
 static LIST_HEAD(device_list);
 static struct workqueue_struct *isert_rx_wq;
 static struct workqueue_struct *isert_comp_wq;
-static struct kmem_cache *isert_cmd_cache;
+
+static void
+isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn);
+static int
+isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+              struct isert_rdma_wr *wr);
+static void
+isert_unreg_rdma_frwr(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn);
+static int
+isert_reg_rdma_frwr(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                   struct isert_rdma_wr *wr);
 
 static void
 isert_qp_event_callback(struct ib_event *e, void *context)
@@ -80,14 +90,8 @@ isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id)
 {
        struct isert_device *device = isert_conn->conn_device;
        struct ib_qp_init_attr attr;
-       struct ib_device_attr devattr;
        int ret, index, min_index = 0;
 
-       memset(&devattr, 0, sizeof(struct ib_device_attr));
-       ret = isert_query_device(cma_id->device, &devattr);
-       if (ret)
-               return ret;
-
        mutex_lock(&device_list_mutex);
        for (index = 0; index < device->cqs_used; index++)
                if (device->cq_active_qps[index] <
@@ -108,7 +112,7 @@ isert_conn_setup_qp(struct isert_conn *isert_conn, struct rdma_cm_id *cma_id)
         * FIXME: Use devattr.max_sge - 2 for max_send_sge as
         * work-around for RDMA_READ..
         */
-       attr.cap.max_send_sge = devattr.max_sge - 2;
+       attr.cap.max_send_sge = device->dev_attr.max_sge - 2;
        isert_conn->max_sge = attr.cap.max_send_sge;
 
        attr.cap.max_recv_sge = 1;
@@ -210,14 +214,31 @@ isert_create_device_ib_res(struct isert_device *device)
 {
        struct ib_device *ib_dev = device->ib_device;
        struct isert_cq_desc *cq_desc;
+       struct ib_device_attr *dev_attr;
        int ret = 0, i, j;
 
+       dev_attr = &device->dev_attr;
+       ret = isert_query_device(ib_dev, dev_attr);
+       if (ret)
+               return ret;
+
+       /* asign function handlers */
+       if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
+               device->use_frwr = 1;
+               device->reg_rdma_mem = isert_reg_rdma_frwr;
+               device->unreg_rdma_mem = isert_unreg_rdma_frwr;
+       } else {
+               device->use_frwr = 0;
+               device->reg_rdma_mem = isert_map_rdma;
+               device->unreg_rdma_mem = isert_unmap_cmd;
+       }
+
        device->cqs_used = min_t(int, num_online_cpus(),
                                 device->ib_device->num_comp_vectors);
        device->cqs_used = min(ISERT_MAX_CQ, device->cqs_used);
-       pr_debug("Using %d CQs, device %s supports %d vectors\n",
+       pr_debug("Using %d CQs, device %s supports %d vectors support FRWR %d\n",
                 device->cqs_used, device->ib_device->name,
-                device->ib_device->num_comp_vectors);
+                device->ib_device->num_comp_vectors, device->use_frwr);
        device->cq_desc = kzalloc(sizeof(struct isert_cq_desc) *
                                device->cqs_used, GFP_KERNEL);
        if (!device->cq_desc) {
@@ -363,6 +384,85 @@ isert_device_find_by_ib_dev(struct rdma_cm_id *cma_id)
        return device;
 }
 
+static void
+isert_conn_free_frwr_pool(struct isert_conn *isert_conn)
+{
+       struct fast_reg_descriptor *fr_desc, *tmp;
+       int i = 0;
+
+       if (list_empty(&isert_conn->conn_frwr_pool))
+               return;
+
+       pr_debug("Freeing conn %p frwr pool", isert_conn);
+
+       list_for_each_entry_safe(fr_desc, tmp,
+                                &isert_conn->conn_frwr_pool, list) {
+               list_del(&fr_desc->list);
+               ib_free_fast_reg_page_list(fr_desc->data_frpl);
+               ib_dereg_mr(fr_desc->data_mr);
+               kfree(fr_desc);
+               ++i;
+       }
+
+       if (i < isert_conn->conn_frwr_pool_size)
+               pr_warn("Pool still has %d regions registered\n",
+                       isert_conn->conn_frwr_pool_size - i);
+}
+
+static int
+isert_conn_create_frwr_pool(struct isert_conn *isert_conn)
+{
+       struct fast_reg_descriptor *fr_desc;
+       struct isert_device *device = isert_conn->conn_device;
+       int i, ret;
+
+       INIT_LIST_HEAD(&isert_conn->conn_frwr_pool);
+       isert_conn->conn_frwr_pool_size = 0;
+       for (i = 0; i < ISCSI_DEF_XMIT_CMDS_MAX; i++) {
+               fr_desc = kzalloc(sizeof(*fr_desc), GFP_KERNEL);
+               if (!fr_desc) {
+                       pr_err("Failed to allocate fast_reg descriptor\n");
+                       ret = -ENOMEM;
+                       goto err;
+               }
+
+               fr_desc->data_frpl =
+                       ib_alloc_fast_reg_page_list(device->ib_device,
+                                                   ISCSI_ISER_SG_TABLESIZE);
+               if (IS_ERR(fr_desc->data_frpl)) {
+                       pr_err("Failed to allocate fr_pg_list err=%ld\n",
+                              PTR_ERR(fr_desc->data_frpl));
+                       ret = PTR_ERR(fr_desc->data_frpl);
+                       goto err;
+               }
+
+               fr_desc->data_mr = ib_alloc_fast_reg_mr(device->dev_pd,
+                                       ISCSI_ISER_SG_TABLESIZE);
+               if (IS_ERR(fr_desc->data_mr)) {
+                       pr_err("Failed to allocate frmr err=%ld\n",
+                              PTR_ERR(fr_desc->data_mr));
+                       ret = PTR_ERR(fr_desc->data_mr);
+                       ib_free_fast_reg_page_list(fr_desc->data_frpl);
+                       goto err;
+               }
+               pr_debug("Create fr_desc %p page_list %p\n",
+                        fr_desc, fr_desc->data_frpl->page_list);
+
+               fr_desc->valid = true;
+               list_add_tail(&fr_desc->list, &isert_conn->conn_frwr_pool);
+               isert_conn->conn_frwr_pool_size++;
+       }
+
+       pr_debug("Creating conn %p frwr pool size=%d",
+                isert_conn, isert_conn->conn_frwr_pool_size);
+
+       return 0;
+
+err:
+       isert_conn_free_frwr_pool(isert_conn);
+       return ret;
+}
+
 static int
 isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
 {
@@ -389,6 +489,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        kref_init(&isert_conn->conn_kref);
        kref_get(&isert_conn->conn_kref);
        mutex_init(&isert_conn->conn_mutex);
+       spin_lock_init(&isert_conn->conn_lock);
 
        cma_id->context = isert_conn;
        isert_conn->conn_cm_id = cma_id;
@@ -446,6 +547,14 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        isert_conn->conn_pd = device->dev_pd;
        isert_conn->conn_mr = device->dev_mr;
 
+       if (device->use_frwr) {
+               ret = isert_conn_create_frwr_pool(isert_conn);
+               if (ret) {
+                       pr_err("Conn: %p failed to create frwr_pool\n", isert_conn);
+                       goto out_frwr;
+               }
+       }
+
        ret = isert_conn_setup_qp(isert_conn, cma_id);
        if (ret)
                goto out_conn_dev;
@@ -459,6 +568,9 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        return 0;
 
 out_conn_dev:
+       if (device->use_frwr)
+               isert_conn_free_frwr_pool(isert_conn);
+out_frwr:
        isert_device_try_release(device);
 out_rsp_dma_map:
        ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
@@ -482,6 +594,9 @@ isert_connect_release(struct isert_conn *isert_conn)
 
        pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
 
+       if (device->use_frwr)
+               isert_conn_free_frwr_pool(isert_conn);
+
        if (isert_conn->conn_qp) {
                cq_index = ((struct isert_cq_desc *)
                        isert_conn->conn_qp->recv_cq->cq_context)->cq_index;
@@ -869,46 +984,37 @@ isert_rx_login_req(struct iser_rx_desc *rx_desc, int rx_buflen,
                 size, rx_buflen, MAX_KEY_VALUE_PAIRS);
        memcpy(login->req_buf, &rx_desc->data[0], size);
 
-       complete(&isert_conn->conn_login_comp);
-}
-
-static void
-isert_release_cmd(struct iscsi_cmd *cmd)
-{
-       struct isert_cmd *isert_cmd = container_of(cmd, struct isert_cmd,
-                                                  iscsi_cmd);
-
-       pr_debug("Entering isert_release_cmd %p >>>>>>>>>>>>>>>.\n", isert_cmd);
-
-       kfree(cmd->buf_ptr);
-       kfree(cmd->tmr_req);
-
-       kmem_cache_free(isert_cmd_cache, isert_cmd);
+       if (login->first_request) {
+               complete(&isert_conn->conn_login_comp);
+               return;
+       }
+       schedule_delayed_work(&conn->login_work, 0);
 }
 
 static struct iscsi_cmd
-*isert_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp)
+*isert_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp)
 {
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct isert_cmd *isert_cmd;
+       struct iscsi_cmd *cmd;
 
-       isert_cmd = kmem_cache_zalloc(isert_cmd_cache, gfp);
-       if (!isert_cmd) {
-               pr_err("Unable to allocate isert_cmd\n");
+       cmd = iscsit_allocate_cmd(conn, gfp);
+       if (!cmd) {
+               pr_err("Unable to allocate iscsi_cmd + isert_cmd\n");
                return NULL;
        }
+       isert_cmd = iscsit_priv_cmd(cmd);
        isert_cmd->conn = isert_conn;
-       isert_cmd->iscsi_cmd.release_cmd = &isert_release_cmd;
+       isert_cmd->iscsi_cmd = cmd;
 
-       return &isert_cmd->iscsi_cmd;
+       return cmd;
 }
 
 static int
 isert_handle_scsi_cmd(struct isert_conn *isert_conn,
-                     struct isert_cmd *isert_cmd, struct iser_rx_desc *rx_desc,
-                     unsigned char *buf)
+                     struct isert_cmd *isert_cmd, struct iscsi_cmd *cmd,
+                     struct iser_rx_desc *rx_desc, unsigned char *buf)
 {
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
        struct iscsi_conn *conn = isert_conn->conn;
        struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf;
        struct scatterlist *sg;
@@ -1015,9 +1121,9 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn,
 
 static int
 isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
-                    struct iser_rx_desc *rx_desc, unsigned char *buf)
+                    struct iscsi_cmd *cmd, struct iser_rx_desc *rx_desc,
+                    unsigned char *buf)
 {
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
        struct iscsi_conn *conn = isert_conn->conn;
        struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf;
        int rc;
@@ -1034,9 +1140,9 @@ isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
 
 static int
 isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
-                     struct iser_rx_desc *rx_desc, struct iscsi_text *hdr)
+                     struct iscsi_cmd *cmd, struct iser_rx_desc *rx_desc,
+                     struct iscsi_text *hdr)
 {
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
        struct iscsi_conn *conn = isert_conn->conn;
        u32 payload_length = ntoh24(hdr->dlength);
        int rc;
@@ -1081,26 +1187,26 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
 
        switch (opcode) {
        case ISCSI_OP_SCSI_CMD:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
                        break;
 
-               isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
+               isert_cmd = iscsit_priv_cmd(cmd);
                isert_cmd->read_stag = read_stag;
                isert_cmd->read_va = read_va;
                isert_cmd->write_stag = write_stag;
                isert_cmd->write_va = write_va;
 
-               ret = isert_handle_scsi_cmd(isert_conn, isert_cmd,
+               ret = isert_handle_scsi_cmd(isert_conn, isert_cmd, cmd,
                                        rx_desc, (unsigned char *)hdr);
                break;
        case ISCSI_OP_NOOP_OUT:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
                        break;
 
-               isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
-               ret = isert_handle_nop_out(isert_conn, isert_cmd,
+               isert_cmd = iscsit_priv_cmd(cmd);
+               ret = isert_handle_nop_out(isert_conn, isert_cmd, cmd,
                                           rx_desc, (unsigned char *)hdr);
                break;
        case ISCSI_OP_SCSI_DATA_OUT:
@@ -1108,7 +1214,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                (unsigned char *)hdr);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
                        break;
 
@@ -1116,7 +1222,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                (unsigned char *)hdr);
                break;
        case ISCSI_OP_LOGOUT:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
                        break;
 
@@ -1127,12 +1233,12 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                    HZ);
                break;
        case ISCSI_OP_TEXT:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
                if (!cmd)
                        break;
 
-               isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd);
-               ret = isert_handle_text_cmd(isert_conn, isert_cmd,
+               isert_cmd = iscsit_priv_cmd(cmd);
+               ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd,
                                            rx_desc, (struct iscsi_text *)hdr);
                break;
        default:
@@ -1243,26 +1349,65 @@ isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
        struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
 
-       pr_debug("isert_unmap_cmd >>>>>>>>>>>>>>>>>>>>>>>\n");
+       pr_debug("isert_unmap_cmd: %p\n", isert_cmd);
+       if (wr->sge) {
+               pr_debug("isert_unmap_cmd: %p unmap_sg op\n", isert_cmd);
+               ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge,
+                               (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
+                               DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               wr->sge = NULL;
+       }
+
+       if (wr->send_wr) {
+               pr_debug("isert_unmap_cmd: %p free send_wr\n", isert_cmd);
+               kfree(wr->send_wr);
+               wr->send_wr = NULL;
+       }
+
+       if (wr->ib_sge) {
+               pr_debug("isert_unmap_cmd: %p free ib_sge\n", isert_cmd);
+               kfree(wr->ib_sge);
+               wr->ib_sge = NULL;
+       }
+}
+
+static void
+isert_unreg_rdma_frwr(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
+{
+       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       LIST_HEAD(unmap_list);
+
+       pr_debug("unreg_frwr_cmd: %p\n", isert_cmd);
+
+       if (wr->fr_desc) {
+               pr_debug("unreg_frwr_cmd: %p free fr_desc %p\n",
+                        isert_cmd, wr->fr_desc);
+               spin_lock_bh(&isert_conn->conn_lock);
+               list_add_tail(&wr->fr_desc->list, &isert_conn->conn_frwr_pool);
+               spin_unlock_bh(&isert_conn->conn_lock);
+               wr->fr_desc = NULL;
+       }
 
        if (wr->sge) {
-               ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE);
+               pr_debug("unreg_frwr_cmd: %p unmap_sg op\n", isert_cmd);
+               ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge,
+                               (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
+                               DMA_TO_DEVICE : DMA_FROM_DEVICE);
                wr->sge = NULL;
        }
 
-       kfree(wr->send_wr);
+       wr->ib_sge = NULL;
        wr->send_wr = NULL;
-
-       kfree(isert_cmd->ib_sge);
-       isert_cmd->ib_sge = NULL;
 }
 
 static void
 isert_put_cmd(struct isert_cmd *isert_cmd)
 {
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
        struct isert_conn *isert_conn = isert_cmd->conn;
        struct iscsi_conn *conn = isert_conn->conn;
+       struct isert_device *device = isert_conn->conn_device;
 
        pr_debug("Entering isert_put_cmd: %p\n", isert_cmd);
 
@@ -1276,7 +1421,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
                if (cmd->data_direction == DMA_TO_DEVICE)
                        iscsit_stop_dataout_timer(cmd);
 
-               isert_unmap_cmd(isert_cmd, isert_conn);
+               device->unreg_rdma_mem(isert_cmd, isert_conn);
                transport_generic_free_cmd(&cmd->se_cmd, 0);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
@@ -1311,7 +1456,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd)
                 * Fall-through
                 */
        default:
-               isert_release_cmd(cmd);
+               iscsit_release_cmd(cmd);
                break;
        }
 }
@@ -1347,27 +1492,16 @@ isert_completion_rdma_read(struct iser_tx_desc *tx_desc,
                           struct isert_cmd *isert_cmd)
 {
        struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
        struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct ib_device *ib_dev = isert_cmd->conn->conn_cm_id->device;
+       struct isert_conn *isert_conn = isert_cmd->conn;
+       struct isert_device *device = isert_conn->conn_device;
 
        iscsit_stop_dataout_timer(cmd);
+       device->unreg_rdma_mem(isert_cmd, isert_conn);
+       cmd->write_data_done = wr->cur_rdma_length;
 
-       if (wr->sge) {
-               pr_debug("isert_do_rdma_read_comp: Unmapping wr->sge from t_data_sg\n");
-               ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge, DMA_TO_DEVICE);
-               wr->sge = NULL;
-       }
-
-       if (isert_cmd->ib_sge) {
-               pr_debug("isert_do_rdma_read_comp: Freeing isert_cmd->ib_sge\n");
-               kfree(isert_cmd->ib_sge);
-               isert_cmd->ib_sge = NULL;
-       }
-
-       cmd->write_data_done = se_cmd->data_length;
-
-       pr_debug("isert_do_rdma_read_comp, calling target_execute_cmd\n");
+       pr_debug("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd);
        spin_lock_bh(&cmd->istate_lock);
        cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT;
        cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT;
@@ -1383,7 +1517,7 @@ isert_do_control_comp(struct work_struct *work)
                        struct isert_cmd, comp_work);
        struct isert_conn *isert_conn = isert_cmd->conn;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
 
        switch (cmd->i_state) {
        case ISTATE_SEND_TASKMGTRSP:
@@ -1429,7 +1563,7 @@ isert_response_completion(struct iser_tx_desc *tx_desc,
                          struct isert_conn *isert_conn,
                          struct ib_device *ib_dev)
 {
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
 
        if (cmd->i_state == ISTATE_SEND_TASKMGTRSP ||
            cmd->i_state == ISTATE_SEND_LOGOUTRSP ||
@@ -1621,8 +1755,7 @@ isert_post_response(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd)
 static int
 isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
 {
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                                       struct isert_cmd, iscsi_cmd);
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
        struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)
@@ -1671,8 +1804,7 @@ static int
 isert_put_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
                bool nopout_response)
 {
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                               struct isert_cmd, iscsi_cmd);
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
 
@@ -1691,8 +1823,7 @@ isert_put_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
 static int
 isert_put_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 {
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                               struct isert_cmd, iscsi_cmd);
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
 
@@ -1710,8 +1841,7 @@ isert_put_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 static int
 isert_put_tm_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 {
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                               struct isert_cmd, iscsi_cmd);
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
 
@@ -1729,8 +1859,7 @@ isert_put_tm_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 static int
 isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 {
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                               struct isert_cmd, iscsi_cmd);
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
@@ -1762,8 +1891,7 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 static int
 isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
 {
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                               struct isert_cmd, iscsi_cmd);
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr;
        struct iscsi_text_rsp *hdr =
@@ -1805,7 +1933,7 @@ isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
                    struct ib_sge *ib_sge, struct ib_send_wr *send_wr,
                    u32 data_left, u32 offset)
 {
-       struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd;
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
        struct scatterlist *sg_start, *tmp_sg;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
        u32 sg_off, page_off;
@@ -1832,8 +1960,8 @@ isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
                                ib_sg_dma_len(ib_dev, tmp_sg) - page_off);
                ib_sge->lkey = isert_conn->conn_mr->lkey;
 
-               pr_debug("RDMA ib_sge: addr: 0x%16llx  length: %u\n",
-                        ib_sge->addr, ib_sge->length);
+               pr_debug("RDMA ib_sge: addr: 0x%16llx  length: %u lkey: %08x\n",
+                        ib_sge->addr, ib_sge->length, ib_sge->lkey);
                page_off = 0;
                data_left -= ib_sge->length;
                ib_sge++;
@@ -1847,200 +1975,373 @@ isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd,
 }
 
 static int
-isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+              struct isert_rdma_wr *wr)
 {
        struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                                       struct isert_cmd, iscsi_cmd);
-       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
-       struct ib_send_wr *wr_failed, *send_wr;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct ib_send_wr *send_wr;
        struct ib_sge *ib_sge;
-       struct scatterlist *sg;
-       u32 offset = 0, data_len, data_left, rdma_write_max;
-       int rc, ret = 0, count, sg_nents, i, ib_sge_cnt;
-
-       pr_debug("RDMA_WRITE: data_length: %u\n", se_cmd->data_length);
+       struct scatterlist *sg_start;
+       u32 sg_off = 0, sg_nents;
+       u32 offset = 0, data_len, data_left, rdma_write_max, va_offset = 0;
+       int ret = 0, count, i, ib_sge_cnt;
+
+       if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
+               data_left = se_cmd->data_length;
+               iscsit_increment_maxcmdsn(cmd, conn->sess);
+               cmd->stat_sn = conn->stat_sn++;
+       } else {
+               sg_off = cmd->write_data_done / PAGE_SIZE;
+               data_left = se_cmd->data_length - cmd->write_data_done;
+               offset = cmd->write_data_done;
+               isert_cmd->tx_desc.isert_cmd = isert_cmd;
+       }
 
-       sg = &se_cmd->t_data_sg[0];
-       sg_nents = se_cmd->t_data_nents;
+       sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+       sg_nents = se_cmd->t_data_nents - sg_off;
 
-       count = ib_dma_map_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE);
+       count = ib_dma_map_sg(ib_dev, sg_start, sg_nents,
+                             (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
+                             DMA_TO_DEVICE : DMA_FROM_DEVICE);
        if (unlikely(!count)) {
-               pr_err("Unable to map put_datain SGs\n");
+               pr_err("Cmd: %p unrable to map SGs\n", isert_cmd);
                return -EINVAL;
        }
-       wr->sge = sg;
+       wr->sge = sg_start;
        wr->num_sge = sg_nents;
-       pr_debug("Mapped IB count: %u sg: %p sg_nents: %u for RDMA_WRITE\n",
-                count, sg, sg_nents);
+       wr->cur_rdma_length = data_left;
+       pr_debug("Mapped cmd: %p count: %u sg: %p sg_nents: %u rdma_len %d\n",
+                isert_cmd, count, sg_start, sg_nents, data_left);
 
        ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL);
        if (!ib_sge) {
-               pr_warn("Unable to allocate datain ib_sge\n");
+               pr_warn("Unable to allocate ib_sge\n");
                ret = -ENOMEM;
                goto unmap_sg;
        }
-       isert_cmd->ib_sge = ib_sge;
-
-       pr_debug("Allocated ib_sge: %p from t_data_ents: %d for RDMA_WRITE\n",
-                ib_sge, se_cmd->t_data_nents);
+       wr->ib_sge = ib_sge;
 
        wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge);
        wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
                                GFP_KERNEL);
        if (!wr->send_wr) {
-               pr_err("Unable to allocate wr->send_wr\n");
+               pr_debug("Unable to allocate wr->send_wr\n");
                ret = -ENOMEM;
                goto unmap_sg;
        }
-       pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n",
-                wr->send_wr, wr->send_wr_num);
-
-       iscsit_increment_maxcmdsn(cmd, conn->sess);
-       cmd->stat_sn = conn->stat_sn++;
 
        wr->isert_cmd = isert_cmd;
        rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
-       data_left = se_cmd->data_length;
 
        for (i = 0; i < wr->send_wr_num; i++) {
                send_wr = &isert_cmd->rdma_wr.send_wr[i];
                data_len = min(data_left, rdma_write_max);
 
-               send_wr->opcode = IB_WR_RDMA_WRITE;
                send_wr->send_flags = 0;
-               send_wr->wr.rdma.remote_addr = isert_cmd->read_va + offset;
-               send_wr->wr.rdma.rkey = isert_cmd->read_stag;
+               if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
+                       send_wr->opcode = IB_WR_RDMA_WRITE;
+                       send_wr->wr.rdma.remote_addr = isert_cmd->read_va + offset;
+                       send_wr->wr.rdma.rkey = isert_cmd->read_stag;
+                       if (i + 1 == wr->send_wr_num)
+                               send_wr->next = &isert_cmd->tx_desc.send_wr;
+                       else
+                               send_wr->next = &wr->send_wr[i + 1];
+               } else {
+                       send_wr->opcode = IB_WR_RDMA_READ;
+                       send_wr->wr.rdma.remote_addr = isert_cmd->write_va + va_offset;
+                       send_wr->wr.rdma.rkey = isert_cmd->write_stag;
+                       if (i + 1 == wr->send_wr_num)
+                               send_wr->send_flags = IB_SEND_SIGNALED;
+                       else
+                               send_wr->next = &wr->send_wr[i + 1];
+               }
 
                ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
                                        send_wr, data_len, offset);
                ib_sge += ib_sge_cnt;
 
-               if (i + 1 == wr->send_wr_num)
-                       send_wr->next = &isert_cmd->tx_desc.send_wr;
-               else
-                       send_wr->next = &wr->send_wr[i + 1];
-
                offset += data_len;
+               va_offset += data_len;
                data_left -= data_len;
        }
-       /*
-        * Build isert_conn->tx_desc for iSCSI response PDU and attach
-        */
-       isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
-       iscsit_build_rsp_pdu(cmd, conn, false, (struct iscsi_scsi_rsp *)
-                            &isert_cmd->tx_desc.iscsi_header);
-       isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
-       isert_init_send_wr(isert_cmd, &isert_cmd->tx_desc.send_wr);
 
-       atomic_inc(&isert_conn->post_send_buf_count);
+       return 0;
+unmap_sg:
+       ib_dma_unmap_sg(ib_dev, sg_start, sg_nents,
+                       (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
+                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       return ret;
+}
 
-       rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
-       if (rc) {
-               pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
-               atomic_dec(&isert_conn->post_send_buf_count);
+static int
+isert_map_fr_pagelist(struct ib_device *ib_dev,
+                     struct scatterlist *sg_start, int sg_nents, u64 *fr_pl)
+{
+       u64 start_addr, end_addr, page, chunk_start = 0;
+       struct scatterlist *tmp_sg;
+       int i = 0, new_chunk, last_ent, n_pages;
+
+       n_pages = 0;
+       new_chunk = 1;
+       last_ent = sg_nents - 1;
+       for_each_sg(sg_start, tmp_sg, sg_nents, i) {
+               start_addr = ib_sg_dma_address(ib_dev, tmp_sg);
+               if (new_chunk)
+                       chunk_start = start_addr;
+               end_addr = start_addr + ib_sg_dma_len(ib_dev, tmp_sg);
+
+               pr_debug("SGL[%d] dma_addr: 0x%16llx len: %u\n",
+                        i, (unsigned long long)tmp_sg->dma_address,
+                        tmp_sg->length);
+
+               if ((end_addr & ~PAGE_MASK) && i < last_ent) {
+                       new_chunk = 0;
+                       continue;
+               }
+               new_chunk = 1;
+
+               page = chunk_start & PAGE_MASK;
+               do {
+                       fr_pl[n_pages++] = page;
+                       pr_debug("Mapped page_list[%d] page_addr: 0x%16llx\n",
+                                n_pages - 1, page);
+                       page += PAGE_SIZE;
+               } while (page < end_addr);
        }
-       pr_debug("Posted RDMA_WRITE + Response for iSER Data READ\n");
-       return 1;
 
-unmap_sg:
-       ib_dma_unmap_sg(ib_dev, sg, sg_nents, DMA_TO_DEVICE);
+       return n_pages;
+}
+
+static int
+isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
+                 struct isert_cmd *isert_cmd, struct isert_conn *isert_conn,
+                 struct ib_sge *ib_sge, u32 offset, unsigned int data_len)
+{
+       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
+       struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct scatterlist *sg_start;
+       u32 sg_off, page_off;
+       struct ib_send_wr fr_wr, inv_wr;
+       struct ib_send_wr *bad_wr, *wr = NULL;
+       u8 key;
+       int ret, sg_nents, pagelist_len;
+
+       sg_off = offset / PAGE_SIZE;
+       sg_start = &cmd->se_cmd.t_data_sg[sg_off];
+       sg_nents = min_t(unsigned int, cmd->se_cmd.t_data_nents - sg_off,
+                        ISCSI_ISER_SG_TABLESIZE);
+       page_off = offset % PAGE_SIZE;
+
+       pr_debug("Cmd: %p use fr_desc %p sg_nents %d sg_off %d offset %u\n",
+                isert_cmd, fr_desc, sg_nents, sg_off, offset);
+
+       pagelist_len = isert_map_fr_pagelist(ib_dev, sg_start, sg_nents,
+                                            &fr_desc->data_frpl->page_list[0]);
+
+       if (!fr_desc->valid) {
+               memset(&inv_wr, 0, sizeof(inv_wr));
+               inv_wr.opcode = IB_WR_LOCAL_INV;
+               inv_wr.ex.invalidate_rkey = fr_desc->data_mr->rkey;
+               wr = &inv_wr;
+               /* Bump the key */
+               key = (u8)(fr_desc->data_mr->rkey & 0x000000FF);
+               ib_update_fast_reg_key(fr_desc->data_mr, ++key);
+       }
+
+       /* Prepare FASTREG WR */
+       memset(&fr_wr, 0, sizeof(fr_wr));
+       fr_wr.opcode = IB_WR_FAST_REG_MR;
+       fr_wr.wr.fast_reg.iova_start =
+               fr_desc->data_frpl->page_list[0] + page_off;
+       fr_wr.wr.fast_reg.page_list = fr_desc->data_frpl;
+       fr_wr.wr.fast_reg.page_list_len = pagelist_len;
+       fr_wr.wr.fast_reg.page_shift = PAGE_SHIFT;
+       fr_wr.wr.fast_reg.length = data_len;
+       fr_wr.wr.fast_reg.rkey = fr_desc->data_mr->rkey;
+       fr_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE;
+
+       if (!wr)
+               wr = &fr_wr;
+       else
+               wr->next = &fr_wr;
+
+       ret = ib_post_send(isert_conn->conn_qp, wr, &bad_wr);
+       if (ret) {
+               pr_err("fast registration failed, ret:%d\n", ret);
+               return ret;
+       }
+       fr_desc->valid = false;
+
+       ib_sge->lkey = fr_desc->data_mr->lkey;
+       ib_sge->addr = fr_desc->data_frpl->page_list[0] + page_off;
+       ib_sge->length = data_len;
+
+       pr_debug("RDMA ib_sge: addr: 0x%16llx  length: %u lkey: %08x\n",
+                ib_sge->addr, ib_sge->length, ib_sge->lkey);
+
        return ret;
 }
 
 static int
-isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
+isert_reg_rdma_frwr(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+                   struct isert_rdma_wr *wr)
 {
        struct se_cmd *se_cmd = &cmd->se_cmd;
-       struct isert_cmd *isert_cmd = container_of(cmd,
-                                       struct isert_cmd, iscsi_cmd);
-       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
-       struct ib_send_wr *wr_failed, *send_wr;
-       struct ib_sge *ib_sge;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
+       struct ib_send_wr *send_wr;
+       struct ib_sge *ib_sge;
        struct scatterlist *sg_start;
-       u32 sg_off, sg_nents, page_off, va_offset = 0;
+       struct fast_reg_descriptor *fr_desc;
+       u32 sg_off = 0, sg_nents;
        u32 offset = 0, data_len, data_left, rdma_write_max;
-       int rc, ret = 0, count, i, ib_sge_cnt;
+       int ret = 0, count;
+       unsigned long flags;
 
-       pr_debug("RDMA_READ: data_length: %u write_data_done: %u\n",
-                se_cmd->data_length, cmd->write_data_done);
+       if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
+               data_left = se_cmd->data_length;
+               iscsit_increment_maxcmdsn(cmd, conn->sess);
+               cmd->stat_sn = conn->stat_sn++;
+       } else {
+               sg_off = cmd->write_data_done / PAGE_SIZE;
+               data_left = se_cmd->data_length - cmd->write_data_done;
+               offset = cmd->write_data_done;
+               isert_cmd->tx_desc.isert_cmd = isert_cmd;
+       }
 
-       sg_off = cmd->write_data_done / PAGE_SIZE;
        sg_start = &cmd->se_cmd.t_data_sg[sg_off];
-       page_off = cmd->write_data_done % PAGE_SIZE;
-
-       pr_debug("RDMA_READ: sg_off: %d, sg_start: %p page_off: %d\n",
-                sg_off, sg_start, page_off);
-
-       data_left = se_cmd->data_length - cmd->write_data_done;
        sg_nents = se_cmd->t_data_nents - sg_off;
 
-       pr_debug("RDMA_READ: data_left: %d, sg_nents: %d\n",
-                data_left, sg_nents);
-
-       count = ib_dma_map_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE);
+       count = ib_dma_map_sg(ib_dev, sg_start, sg_nents,
+                             (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
+                             DMA_TO_DEVICE : DMA_FROM_DEVICE);
        if (unlikely(!count)) {
-               pr_err("Unable to map get_dataout SGs\n");
+               pr_err("Cmd: %p unrable to map SGs\n", isert_cmd);
                return -EINVAL;
        }
        wr->sge = sg_start;
        wr->num_sge = sg_nents;
-       pr_debug("Mapped IB count: %u sg_start: %p sg_nents: %u for RDMA_READ\n",
-                count, sg_start, sg_nents);
+       pr_debug("Mapped cmd: %p count: %u sg: %p sg_nents: %u rdma_len %d\n",
+                isert_cmd, count, sg_start, sg_nents, data_left);
 
-       ib_sge = kzalloc(sizeof(struct ib_sge) * sg_nents, GFP_KERNEL);
-       if (!ib_sge) {
-               pr_warn("Unable to allocate dataout ib_sge\n");
-               ret = -ENOMEM;
-               goto unmap_sg;
+       memset(&wr->s_ib_sge, 0, sizeof(*ib_sge));
+       ib_sge = &wr->s_ib_sge;
+       wr->ib_sge = ib_sge;
+
+       wr->send_wr_num = 1;
+       memset(&wr->s_send_wr, 0, sizeof(*send_wr));
+       wr->send_wr = &wr->s_send_wr;
+
+       wr->isert_cmd = isert_cmd;
+       rdma_write_max = ISCSI_ISER_SG_TABLESIZE * PAGE_SIZE;
+
+       send_wr = &isert_cmd->rdma_wr.s_send_wr;
+       send_wr->sg_list = ib_sge;
+       send_wr->num_sge = 1;
+       send_wr->wr_id = (unsigned long)&isert_cmd->tx_desc;
+       if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
+               send_wr->opcode = IB_WR_RDMA_WRITE;
+               send_wr->wr.rdma.remote_addr = isert_cmd->read_va;
+               send_wr->wr.rdma.rkey = isert_cmd->read_stag;
+               send_wr->send_flags = 0;
+               send_wr->next = &isert_cmd->tx_desc.send_wr;
+       } else {
+               send_wr->opcode = IB_WR_RDMA_READ;
+               send_wr->wr.rdma.remote_addr = isert_cmd->write_va;
+               send_wr->wr.rdma.rkey = isert_cmd->write_stag;
+               send_wr->send_flags = IB_SEND_SIGNALED;
        }
-       isert_cmd->ib_sge = ib_sge;
 
-       pr_debug("Using ib_sge: %p from sg_ents: %d for RDMA_READ\n",
-                ib_sge, sg_nents);
+       data_len = min(data_left, rdma_write_max);
+       wr->cur_rdma_length = data_len;
 
-       wr->send_wr_num = DIV_ROUND_UP(sg_nents, isert_conn->max_sge);
-       wr->send_wr = kzalloc(sizeof(struct ib_send_wr) * wr->send_wr_num,
-                               GFP_KERNEL);
-       if (!wr->send_wr) {
-               pr_debug("Unable to allocate wr->send_wr\n");
-               ret = -ENOMEM;
+       spin_lock_irqsave(&isert_conn->conn_lock, flags);
+       fr_desc = list_first_entry(&isert_conn->conn_frwr_pool,
+                                  struct fast_reg_descriptor, list);
+       list_del(&fr_desc->list);
+       spin_unlock_irqrestore(&isert_conn->conn_lock, flags);
+       wr->fr_desc = fr_desc;
+
+       ret = isert_fast_reg_mr(fr_desc, isert_cmd, isert_conn,
+                         ib_sge, offset, data_len);
+       if (ret) {
+               list_add_tail(&fr_desc->list, &isert_conn->conn_frwr_pool);
                goto unmap_sg;
        }
-       pr_debug("Allocated wr->send_wr: %p wr->send_wr_num: %u\n",
-                wr->send_wr, wr->send_wr_num);
 
-       isert_cmd->tx_desc.isert_cmd = isert_cmd;
+       return 0;
 
-       wr->iser_ib_op = ISER_IB_RDMA_READ;
-       wr->isert_cmd = isert_cmd;
-       rdma_write_max = isert_conn->max_sge * PAGE_SIZE;
-       offset = cmd->write_data_done;
+unmap_sg:
+       ib_dma_unmap_sg(ib_dev, sg_start, sg_nents,
+                       (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
+                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
+       return ret;
+}
 
-       for (i = 0; i < wr->send_wr_num; i++) {
-               send_wr = &isert_cmd->rdma_wr.send_wr[i];
-               data_len = min(data_left, rdma_write_max);
+static int
+isert_put_datain(struct iscsi_conn *conn, struct iscsi_cmd *cmd)
+{
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
+       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+       struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+       struct isert_device *device = isert_conn->conn_device;
+       struct ib_send_wr *wr_failed;
+       int rc;
 
-               send_wr->opcode = IB_WR_RDMA_READ;
-               send_wr->wr.rdma.remote_addr = isert_cmd->write_va + va_offset;
-               send_wr->wr.rdma.rkey = isert_cmd->write_stag;
+       pr_debug("Cmd: %p RDMA_WRITE data_length: %u\n",
+                isert_cmd, se_cmd->data_length);
+       wr->iser_ib_op = ISER_IB_RDMA_WRITE;
+       rc = device->reg_rdma_mem(conn, cmd, wr);
+       if (rc) {
+               pr_err("Cmd: %p failed to prepare RDMA res\n", isert_cmd);
+               return rc;
+       }
 
-               ib_sge_cnt = isert_build_rdma_wr(isert_conn, isert_cmd, ib_sge,
-                                       send_wr, data_len, offset);
-               ib_sge += ib_sge_cnt;
+       /*
+        * Build isert_conn->tx_desc for iSCSI response PDU and attach
+        */
+       isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc);
+       iscsit_build_rsp_pdu(cmd, conn, false, (struct iscsi_scsi_rsp *)
+                            &isert_cmd->tx_desc.iscsi_header);
+       isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc);
+       isert_init_send_wr(isert_cmd, &isert_cmd->tx_desc.send_wr);
 
-               if (i + 1 == wr->send_wr_num)
-                       send_wr->send_flags = IB_SEND_SIGNALED;
-               else
-                       send_wr->next = &wr->send_wr[i + 1];
+       atomic_inc(&isert_conn->post_send_buf_count);
 
-               offset += data_len;
-               va_offset += data_len;
-               data_left -= data_len;
+       rc = ib_post_send(isert_conn->conn_qp, wr->send_wr, &wr_failed);
+       if (rc) {
+               pr_warn("ib_post_send() failed for IB_WR_RDMA_WRITE\n");
+               atomic_dec(&isert_conn->post_send_buf_count);
+       }
+       pr_debug("Cmd: %p posted RDMA_WRITE + Response for iSER Data READ\n",
+                isert_cmd);
+
+       return 1;
+}
+
+static int
+isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
+{
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+       struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
+       struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
+       struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
+       struct isert_device *device = isert_conn->conn_device;
+       struct ib_send_wr *wr_failed;
+       int rc;
+
+       pr_debug("Cmd: %p RDMA_READ data_length: %u write_data_done: %u\n",
+                isert_cmd, se_cmd->data_length, cmd->write_data_done);
+       wr->iser_ib_op = ISER_IB_RDMA_READ;
+       rc = device->reg_rdma_mem(conn, cmd, wr);
+       if (rc) {
+               pr_err("Cmd: %p failed to prepare RDMA res\n", isert_cmd);
+               return rc;
        }
 
        atomic_inc(&isert_conn->post_send_buf_count);
@@ -2050,12 +2351,10 @@ isert_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, bool recovery)
                pr_warn("ib_post_send() failed for IB_WR_RDMA_READ\n");
                atomic_dec(&isert_conn->post_send_buf_count);
        }
-       pr_debug("Posted RDMA_READ memory for ISER Data WRITE\n");
-       return 0;
+       pr_debug("Cmd: %p posted RDMA_READ memory for ISER Data WRITE\n",
+                isert_cmd);
 
-unmap_sg:
-       ib_dma_unmap_sg(ib_dev, sg_start, sg_nents, DMA_FROM_DEVICE);
-       return ret;
+       return 0;
 }
 
 static int
@@ -2224,6 +2523,14 @@ isert_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login)
        int ret;
 
        pr_debug("isert_get_login_rx before conn_login_comp conn: %p\n", conn);
+       /*
+        * For login requests after the first PDU, isert_rx_login_req() will
+        * kick schedule_delayed_work(&conn->login_work) as the packet is
+        * received, which turns this callback from iscsi_target_do_login_rx()
+        * into a NOP.
+        */
+       if (!login->first_request)
+               return 0;
 
        ret = wait_for_completion_interruptible(&isert_conn->conn_login_comp);
        if (ret)
@@ -2393,12 +2700,12 @@ static void isert_free_conn(struct iscsi_conn *conn)
 static struct iscsit_transport iser_target_transport = {
        .name                   = "IB/iSER",
        .transport_type         = ISCSI_INFINIBAND,
+       .priv_size              = sizeof(struct isert_cmd),
        .owner                  = THIS_MODULE,
        .iscsit_setup_np        = isert_setup_np,
        .iscsit_accept_np       = isert_accept_np,
        .iscsit_free_np         = isert_free_np,
        .iscsit_free_conn       = isert_free_conn,
-       .iscsit_alloc_cmd       = isert_alloc_cmd,
        .iscsit_get_login_rx    = isert_get_login_rx,
        .iscsit_put_login_tx    = isert_put_login_tx,
        .iscsit_immediate_queue = isert_immediate_queue,
@@ -2425,21 +2732,10 @@ static int __init isert_init(void)
                goto destroy_rx_wq;
        }
 
-       isert_cmd_cache = kmem_cache_create("isert_cmd_cache",
-                       sizeof(struct isert_cmd), __alignof__(struct isert_cmd),
-                       0, NULL);
-       if (!isert_cmd_cache) {
-               pr_err("Unable to create isert_cmd_cache\n");
-               ret = -ENOMEM;
-               goto destroy_tx_cq;
-       }
-
        iscsit_register_transport(&iser_target_transport);
        pr_debug("iSER_TARGET[0] - Loaded iser_target_transport\n");
        return 0;
 
-destroy_tx_cq:
-       destroy_workqueue(isert_comp_wq);
 destroy_rx_wq:
        destroy_workqueue(isert_rx_wq);
        return ret;
@@ -2447,7 +2743,6 @@ destroy_rx_wq:
 
 static void __exit isert_exit(void)
 {
-       kmem_cache_destroy(isert_cmd_cache);
        destroy_workqueue(isert_comp_wq);
        destroy_workqueue(isert_rx_wq);
        iscsit_unregister_transport(&iser_target_transport);
index 191117b5b508771bf7a4fb42d9423bb26f72319a..631f2090f0b8cfde2db02d17c9162d3e97558298 100644 (file)
@@ -5,6 +5,7 @@
 #include <rdma/rdma_cm.h>
 
 #define ISERT_RDMA_LISTEN_BACKLOG      10
+#define ISCSI_ISER_SG_TABLESIZE                256
 
 enum isert_desc_type {
        ISCSI_TX_CONTROL,
@@ -45,15 +46,26 @@ struct iser_tx_desc {
        struct ib_send_wr send_wr;
 } __packed;
 
+struct fast_reg_descriptor {
+       struct list_head        list;
+       struct ib_mr            *data_mr;
+       struct ib_fast_reg_page_list    *data_frpl;
+       bool                    valid;
+};
+
 struct isert_rdma_wr {
        struct list_head        wr_list;
        struct isert_cmd        *isert_cmd;
        enum iser_ib_op_code    iser_ib_op;
        struct ib_sge           *ib_sge;
+       struct ib_sge           s_ib_sge;
        int                     num_sge;
        struct scatterlist      *sge;
        int                     send_wr_num;
        struct ib_send_wr       *send_wr;
+       struct ib_send_wr       s_send_wr;
+       u32                     cur_rdma_length;
+       struct fast_reg_descriptor *fr_desc;
 };
 
 struct isert_cmd {
@@ -67,8 +79,7 @@ struct isert_cmd {
        u32                     write_va_off;
        u32                     rdma_wr_num;
        struct isert_conn       *conn;
-       struct iscsi_cmd        iscsi_cmd;
-       struct ib_sge           *ib_sge;
+       struct iscsi_cmd        *iscsi_cmd;
        struct iser_tx_desc     tx_desc;
        struct isert_rdma_wr    rdma_wr;
        struct work_struct      comp_work;
@@ -106,6 +117,10 @@ struct isert_conn {
        wait_queue_head_t       conn_wait;
        wait_queue_head_t       conn_wait_comp_err;
        struct kref             conn_kref;
+       struct list_head        conn_frwr_pool;
+       int                     conn_frwr_pool_size;
+       /* lock to protect frwr_pool */
+       spinlock_t              conn_lock;
 };
 
 #define ISERT_MAX_CQ 64
@@ -118,6 +133,7 @@ struct isert_cq_desc {
 };
 
 struct isert_device {
+       int                     use_frwr;
        int                     cqs_used;
        int                     refcount;
        int                     cq_active_qps[ISERT_MAX_CQ];
@@ -128,6 +144,12 @@ struct isert_device {
        struct ib_cq            *dev_tx_cq[ISERT_MAX_CQ];
        struct isert_cq_desc    *cq_desc;
        struct list_head        dev_node;
+       struct ib_device_attr   dev_attr;
+       int                     (*reg_rdma_mem)(struct iscsi_conn *conn,
+                                                   struct iscsi_cmd *cmd,
+                                                   struct isert_rdma_wr *wr);
+       void                    (*unreg_rdma_mem)(struct isert_cmd *isert_cmd,
+                                                 struct isert_conn *isert_conn);
 };
 
 struct isert_np {
index d2b34fbbc42e78ed6b7a59c7ff2a63a6d32b5bf0..b6ded17b3be3adda86ca93bf582f679f837442aa 100644 (file)
@@ -48,6 +48,7 @@ struct evdev_client {
        struct evdev *evdev;
        struct list_head node;
        int clkid;
+       bool revoked;
        unsigned int bufsize;
        struct input_event buffer[];
 };
@@ -164,6 +165,9 @@ static void evdev_pass_values(struct evdev_client *client,
        struct input_event event;
        bool wakeup = false;
 
+       if (client->revoked)
+               return;
+
        event.time = ktime_to_timeval(client->clkid == CLOCK_MONOTONIC ?
                                      mono : real);
 
@@ -240,7 +244,7 @@ static int evdev_flush(struct file *file, fl_owner_t id)
        if (retval)
                return retval;
 
-       if (!evdev->exist)
+       if (!evdev->exist || client->revoked)
                retval = -ENODEV;
        else
                retval = input_flush_device(&evdev->handle, file);
@@ -429,7 +433,7 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
        if (retval)
                return retval;
 
-       if (!evdev->exist) {
+       if (!evdev->exist || client->revoked) {
                retval = -ENODEV;
                goto out;
        }
@@ -482,7 +486,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
                return -EINVAL;
 
        for (;;) {
-               if (!evdev->exist)
+               if (!evdev->exist || client->revoked)
                        return -ENODEV;
 
                if (client->packet_head == client->tail &&
@@ -511,7 +515,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
                if (!(file->f_flags & O_NONBLOCK)) {
                        error = wait_event_interruptible(evdev->wait,
                                        client->packet_head != client->tail ||
-                                       !evdev->exist);
+                                       !evdev->exist || client->revoked);
                        if (error)
                                return error;
                }
@@ -529,7 +533,11 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &evdev->wait, wait);
 
-       mask = evdev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR;
+       if (evdev->exist && !client->revoked)
+               mask = POLLOUT | POLLWRNORM;
+       else
+               mask = POLLHUP | POLLERR;
+
        if (client->packet_head != client->tail)
                mask |= POLLIN | POLLRDNORM;
 
@@ -795,6 +803,17 @@ static int evdev_handle_mt_request(struct input_dev *dev,
        return 0;
 }
 
+static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
+                       struct file *file)
+{
+       client->revoked = true;
+       evdev_ungrab(evdev, client);
+       input_flush_device(&evdev->handle, file);
+       wake_up_interruptible(&evdev->wait);
+
+       return 0;
+}
+
 static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                           void __user *p, int compat_mode)
 {
@@ -857,6 +876,12 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
                else
                        return evdev_ungrab(evdev, client);
 
+       case EVIOCREVOKE:
+               if (p)
+                       return -EINVAL;
+               else
+                       return evdev_revoke(evdev, client, file);
+
        case EVIOCSCLOCKID:
                if (copy_from_user(&i, p, sizeof(unsigned int)))
                        return -EFAULT;
@@ -1002,7 +1027,7 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
        if (retval)
                return retval;
 
-       if (!evdev->exist) {
+       if (!evdev->exist || client->revoked) {
                retval = -ENODEV;
                goto out;
        }
index 269d4c3658cb062926972f9cae6ede7faa8d9522..c1edd39bc5ba1c1c39c81cd895f3e3ab8cbb5c01 100644 (file)
@@ -224,7 +224,7 @@ config KEYBOARD_TCA6416
 
 config KEYBOARD_TCA8418
        tristate "TCA8418 Keypad Support"
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        select INPUT_MATRIXKMAP
        help
          This driver implements basic keypad functionality
@@ -303,7 +303,7 @@ config KEYBOARD_HP7XX
 
 config KEYBOARD_LM8323
        tristate "LM8323 keypad chip"
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        depends on LEDS_CLASS
        help
          If you say yes here you get support for the National Semiconductor
index 1e691a3a79cbaffd054789bb4b7f586cff792bba..33b3e88fe4a2312f0047a4a700a2733c9ef81ee4 100644 (file)
@@ -239,7 +239,6 @@ config SERIO_PS2MULT
 
 config SERIO_ARC_PS2
        tristate "ARC PS/2 support"
-       depends on GENERIC_HARDIRQS
        help
          Say Y here if you have an ARC FPGA platform with a PS/2
          controller in it.
index 3b9758b5f4d7addee5e5d5ec4e706b2421e1a4b7..e09ec67957a3c32b185dd451fedba467729d0b77 100644 (file)
@@ -389,7 +389,7 @@ config TOUCHSCREEN_MCS5000
 
 config TOUCHSCREEN_MMS114
        tristate "MELFAS MMS114 touchscreen"
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        help
          Say Y here if you have the MELFAS MMS114 touchscreen controller
          chip in your system.
@@ -845,7 +845,7 @@ config TOUCHSCREEN_TSC_SERIO
 
 config TOUCHSCREEN_TSC2005
         tristate "TSC2005 based touchscreens"
-        depends on SPI_MASTER && GENERIC_HARDIRQS
+        depends on SPI_MASTER
         help
           Say Y here if you have a TSC2005 based touchscreen.
 
index 820d85c4a4a0f8c2b8fc813adfa30a07c529a953..fe302e33f72e7b2da024180e697422461b017bc7 100644 (file)
@@ -17,6 +17,16 @@ config OF_IOMMU
        def_bool y
        depends on OF
 
+config FSL_PAMU
+       bool "Freescale IOMMU support"
+       depends on PPC_E500MC
+       select IOMMU_API
+       select GENERIC_ALLOCATOR
+       help
+         Freescale PAMU support. PAMU is the IOMMU present on Freescale QorIQ platforms.
+         PAMU can authorize memory access, remap the memory address, and remap I/O
+         transaction types.
+
 # MSM IOMMU support
 config MSM_IOMMU
        bool "MSM IOMMU Support"
index bbe7041212dd64e3ff934cc23c45fdee3adcdda4..14c1f474cf1188008316e7e480c7e3c6d22f04f5 100644 (file)
@@ -16,3 +16,4 @@ obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
 obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
 obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o
 obj-$(CONFIG_SHMOBILE_IPMMU) += shmobile-ipmmu.o
+obj-$(CONFIG_FSL_PAMU) += fsl_pamu.o fsl_pamu_domain.o
index 6dc659426a51f5cca55fdbaf2348b3c28fa03dde..72531f008a5e34ea871e7d3d3569a724af695d86 100644 (file)
@@ -456,8 +456,10 @@ static int iommu_init_device(struct device *dev)
        }
 
        ret = init_iommu_group(dev);
-       if (ret)
+       if (ret) {
+               free_dev_data(dev_data);
                return ret;
+       }
 
        if (pci_iommuv2_capable(pdev)) {
                struct amd_iommu *iommu;
index 7acbf351e9af2d52b80909177ce89dae6a8fc558..8f798be6e398d98ccacc5ba85f3f5b76c4096683 100644 (file)
@@ -1384,7 +1384,7 @@ static int iommu_init_msi(struct amd_iommu *iommu)
        if (iommu->int_enabled)
                goto enable_faults;
 
-       if (pci_find_capability(iommu->dev, PCI_CAP_ID_MSI))
+       if (iommu->dev->msi_cap)
                ret = iommu_setup_msi(iommu);
        else
                ret = -ENODEV;
index ebd0a4cff049a7479a32884d6ed86199208b7b94..f417e89e1e7e47e812fef6e16faf9a19432ce0b4 100644 (file)
@@ -56,9 +56,6 @@
 /* Maximum number of mapping groups per SMMU */
 #define ARM_SMMU_MAX_SMRS              128
 
-/* Number of VMIDs per SMMU */
-#define ARM_SMMU_NUM_VMIDS             256
-
 /* SMMU global address space */
 #define ARM_SMMU_GR0(smmu)             ((smmu)->base)
 #define ARM_SMMU_GR1(smmu)             ((smmu)->base + (smmu)->pagesize)
@@ -87,6 +84,7 @@
 #define ARM_SMMU_PTE_AP_UNPRIV         (((pteval_t)1) << 6)
 #define ARM_SMMU_PTE_AP_RDONLY         (((pteval_t)2) << 6)
 #define ARM_SMMU_PTE_ATTRINDX_SHIFT    2
+#define ARM_SMMU_PTE_nG                        (((pteval_t)1) << 11)
 
 /* Stage-2 PTE */
 #define ARM_SMMU_PTE_HAP_FAULT         (((pteval_t)0) << 6)
 #define ARM_SMMU_CB_FAR_LO             0x60
 #define ARM_SMMU_CB_FAR_HI             0x64
 #define ARM_SMMU_CB_FSYNR0             0x68
+#define ARM_SMMU_CB_S1_TLBIASID                0x610
 
 #define SCTLR_S1_ASIDPNE               (1 << 12)
 #define SCTLR_CFCFG                    (1 << 7)
 #define TTBCR2_ADDR_44                 4
 #define TTBCR2_ADDR_48                 5
 
+#define TTBRn_HI_ASID_SHIFT            16
+
 #define MAIR_ATTR_SHIFT(n)             ((n) << 3)
 #define MAIR_ATTR_MASK                 0xff
 #define MAIR_ATTR_DEVICE               0x04
 #define FSR_IGN                                (FSR_AFF | FSR_ASF | FSR_TLBMCF |       \
                                         FSR_TLBLKF)
 #define FSR_FAULT                      (FSR_MULTI | FSR_SS | FSR_UUT |         \
-                                        FSR_EF | FSR_PF | FSR_TF)
+                                        FSR_EF | FSR_PF | FSR_TF | FSR_IGN)
 
 #define FSYNR0_WNR                     (1 << 4)
 
@@ -365,21 +366,21 @@ struct arm_smmu_device {
        u32                             num_context_irqs;
        unsigned int                    *irqs;
 
-       DECLARE_BITMAP(vmid_map, ARM_SMMU_NUM_VMIDS);
-
        struct list_head                list;
        struct rb_root                  masters;
 };
 
 struct arm_smmu_cfg {
        struct arm_smmu_device          *smmu;
-       u8                              vmid;
        u8                              cbndx;
        u8                              irptndx;
        u32                             cbar;
        pgd_t                           *pgd;
 };
 
+#define ARM_SMMU_CB_ASID(cfg)          ((cfg)->cbndx)
+#define ARM_SMMU_CB_VMID(cfg)          ((cfg)->cbndx + 1)
+
 struct arm_smmu_domain {
        /*
         * A domain can span across multiple, chained SMMUs and requires
@@ -533,6 +534,25 @@ static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
        }
 }
 
+static void arm_smmu_tlb_inv_context(struct arm_smmu_cfg *cfg)
+{
+       struct arm_smmu_device *smmu = cfg->smmu;
+       void __iomem *base = ARM_SMMU_GR0(smmu);
+       bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
+
+       if (stage1) {
+               base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+               writel_relaxed(ARM_SMMU_CB_ASID(cfg),
+                              base + ARM_SMMU_CB_S1_TLBIASID);
+       } else {
+               base = ARM_SMMU_GR0(smmu);
+               writel_relaxed(ARM_SMMU_CB_VMID(cfg),
+                              base + ARM_SMMU_GR0_TLBIVMID);
+       }
+
+       arm_smmu_tlb_sync(smmu);
+}
+
 static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
 {
        int flags, ret;
@@ -590,6 +610,9 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
        void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
 
        gfsr = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSR);
+       if (!gfsr)
+               return IRQ_NONE;
+
        gfsynr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR0);
        gfsynr1 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR1);
        gfsynr2 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sGFSYNR2);
@@ -601,7 +624,7 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
                gfsr, gfsynr0, gfsynr1, gfsynr2);
 
        writel(gfsr, gr0_base + ARM_SMMU_GR0_sGFSR);
-       return IRQ_NONE;
+       return IRQ_HANDLED;
 }
 
 static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
@@ -618,14 +641,15 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
        cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
 
        /* CBAR */
-       reg = root_cfg->cbar |
-             (root_cfg->vmid << CBAR_VMID_SHIFT);
+       reg = root_cfg->cbar;
        if (smmu->version == 1)
              reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT;
 
        /* Use the weakest memory type, so it is overridden by the pte */
        if (stage1)
                reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT);
+       else
+               reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT;
        writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx));
 
        if (smmu->version > 1) {
@@ -687,15 +711,11 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
 
        /* TTBR0 */
        reg = __pa(root_cfg->pgd);
-#ifndef __BIG_ENDIAN
        writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
        reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
+       if (stage1)
+               reg |= ARM_SMMU_CB_ASID(root_cfg) << TTBRn_HI_ASID_SHIFT;
        writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
-#else
-       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
-       reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32;
-       writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
-#endif
 
        /*
         * TTBCR
@@ -750,10 +770,6 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
                writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
        }
 
-       /* Nuke the TLB */
-       writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
-       arm_smmu_tlb_sync(smmu);
-
        /* SCTLR */
        reg = SCTLR_CFCFG | SCTLR_CFIE | SCTLR_CFRE | SCTLR_M | SCTLR_EAE_SBOP;
        if (stage1)
@@ -790,11 +806,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
                return -ENODEV;
        }
 
-       ret = __arm_smmu_alloc_bitmap(smmu->vmid_map, 0, ARM_SMMU_NUM_VMIDS);
-       if (IS_ERR_VALUE(ret))
-               return ret;
-
-       root_cfg->vmid = ret;
        if (smmu->features & ARM_SMMU_FEAT_TRANS_NESTED) {
                /*
                 * We will likely want to change this if/when KVM gets
@@ -813,10 +824,9 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
        ret = __arm_smmu_alloc_bitmap(smmu->context_map, start,
                                      smmu->num_context_banks);
        if (IS_ERR_VALUE(ret))
-               goto out_free_vmid;
+               return ret;
 
        root_cfg->cbndx = ret;
-
        if (smmu->version == 1) {
                root_cfg->irptndx = atomic_inc_return(&smmu->irptndx);
                root_cfg->irptndx %= smmu->num_context_irqs;
@@ -840,8 +850,6 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
 
 out_free_context:
        __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
-out_free_vmid:
-       __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
        return ret;
 }
 
@@ -850,17 +858,22 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
        struct arm_smmu_domain *smmu_domain = domain->priv;
        struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
        struct arm_smmu_device *smmu = root_cfg->smmu;
+       void __iomem *cb_base;
        int irq;
 
        if (!smmu)
                return;
 
+       /* Disable the context bank and nuke the TLB before freeing it. */
+       cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, root_cfg->cbndx);
+       writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
+       arm_smmu_tlb_inv_context(root_cfg);
+
        if (root_cfg->irptndx != -1) {
                irq = smmu->irqs[smmu->num_global_irqs + root_cfg->irptndx];
                free_irq(irq, domain);
        }
 
-       __arm_smmu_free_bitmap(smmu->vmid_map, root_cfg->vmid);
        __arm_smmu_free_bitmap(smmu->context_map, root_cfg->cbndx);
 }
 
@@ -959,6 +972,11 @@ static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain)
 static void arm_smmu_domain_destroy(struct iommu_domain *domain)
 {
        struct arm_smmu_domain *smmu_domain = domain->priv;
+
+       /*
+        * Free the domain resources. We assume that all devices have
+        * already been detached.
+        */
        arm_smmu_destroy_domain_context(domain);
        arm_smmu_free_pgtables(smmu_domain);
        kfree(smmu_domain);
@@ -1199,7 +1217,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
        }
 
        if (stage == 1) {
-               pteval |= ARM_SMMU_PTE_AP_UNPRIV;
+               pteval |= ARM_SMMU_PTE_AP_UNPRIV | ARM_SMMU_PTE_nG;
                if (!(flags & IOMMU_WRITE) && (flags & IOMMU_READ))
                        pteval |= ARM_SMMU_PTE_AP_RDONLY;
 
@@ -1415,13 +1433,9 @@ static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
 {
        int ret;
        struct arm_smmu_domain *smmu_domain = domain->priv;
-       struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg;
-       struct arm_smmu_device *smmu = root_cfg->smmu;
-       void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
 
        ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
-       writel_relaxed(root_cfg->vmid, gr0_base + ARM_SMMU_GR0_TLBIVMID);
-       arm_smmu_tlb_sync(smmu);
+       arm_smmu_tlb_inv_context(&smmu_domain->root_cfg);
        return ret ? ret : size;
 }
 
@@ -1544,6 +1558,7 @@ static struct iommu_ops arm_smmu_ops = {
 static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
 {
        void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
+       void __iomem *sctlr_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB_SCTLR;
        int i = 0;
        u32 scr0 = readl_relaxed(gr0_base + ARM_SMMU_GR0_sCR0);
 
@@ -1553,6 +1568,10 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
                writel_relaxed(S2CR_TYPE_BYPASS, gr0_base + ARM_SMMU_GR0_S2CR(i));
        }
 
+       /* Make sure all context banks are disabled */
+       for (i = 0; i < smmu->num_context_banks; ++i)
+               writel_relaxed(0, sctlr_base + ARM_SMMU_CB(smmu, i));
+
        /* Invalidate the TLB, just in case */
        writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
        writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
@@ -1906,7 +1925,7 @@ static int arm_smmu_device_remove(struct platform_device *pdev)
                of_node_put(master->of_node);
        }
 
-       if (!bitmap_empty(smmu->vmid_map, ARM_SMMU_NUM_VMIDS))
+       if (!bitmap_empty(smmu->context_map, ARM_SMMU_MAX_CBS))
                dev_err(dev, "removing device with active domains!\n");
 
        for (i = 0; i < smmu->num_global_irqs; ++i)
index 3f32d64ab87a4f98f910212b1f1a8a8d66d99b5f..074018979cdfb047f96619bf050b0f26ba5a623f 100644 (file)
@@ -247,50 +247,6 @@ static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
        __raw_writel(size - 1 + base,  sfrbase + REG_PB0_EADDR + idx * 8);
 }
 
-void exynos_sysmmu_set_prefbuf(struct device *dev,
-                               unsigned long base0, unsigned long size0,
-                               unsigned long base1, unsigned long size1)
-{
-       struct sysmmu_drvdata *data = dev_get_drvdata(dev->archdata.iommu);
-       unsigned long flags;
-       int i;
-
-       BUG_ON((base0 + size0) <= base0);
-       BUG_ON((size1 > 0) && ((base1 + size1) <= base1));
-
-       read_lock_irqsave(&data->lock, flags);
-       if (!is_sysmmu_active(data))
-               goto finish;
-
-       for (i = 0; i < data->nsfrs; i++) {
-               if ((readl(data->sfrbases[i] + REG_MMU_VERSION) >> 28) == 3) {
-                       if (!sysmmu_block(data->sfrbases[i]))
-                               continue;
-
-                       if (size1 == 0) {
-                               if (size0 <= SZ_128K) {
-                                       base1 = base0;
-                                       size1 = size0;
-                               } else {
-                                       size1 = size0 -
-                                               ALIGN(size0 / 2, SZ_64K);
-                                       size0 = size0 - size1;
-                                       base1 = base0 + size0;
-                               }
-                       }
-
-                       __sysmmu_set_prefbuf(
-                                       data->sfrbases[i], base0, size0, 0);
-                       __sysmmu_set_prefbuf(
-                                       data->sfrbases[i], base1, size1, 1);
-
-                       sysmmu_unblock(data->sfrbases[i]);
-               }
-       }
-finish:
-       read_unlock_irqrestore(&data->lock, flags);
-}
-
 static void __set_fault_handler(struct sysmmu_drvdata *data,
                                        sysmmu_fault_handler_t handler)
 {
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
new file mode 100644 (file)
index 0000000..cba0498
--- /dev/null
@@ -0,0 +1,1309 @@
+/*
+ * 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 (C) 2013 Freescale Semiconductor, Inc.
+ *
+ */
+
+#define pr_fmt(fmt)    "fsl-pamu: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/iommu.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/bootmem.h>
+#include <linux/genalloc.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/fsl_guts.h>
+
+#include "fsl_pamu.h"
+
+/* define indexes for each operation mapping scenario */
+#define OMI_QMAN        0x00
+#define OMI_FMAN        0x01
+#define OMI_QMAN_PRIV   0x02
+#define OMI_CAAM        0x03
+
+#define make64(high, low) (((u64)(high) << 32) | (low))
+
+struct pamu_isr_data {
+       void __iomem *pamu_reg_base;    /* Base address of PAMU regs*/
+       unsigned int count;             /* The number of PAMUs */
+};
+
+static struct paace *ppaact;
+static struct paace *spaact;
+static struct ome *omt;
+
+/*
+ * Table for matching compatible strings, for device tree
+ * guts node, for QorIQ SOCs.
+ * "fsl,qoriq-device-config-2.0" corresponds to T4 & B4
+ * SOCs. For the older SOCs "fsl,qoriq-device-config-1.0"
+ * string would be used.
+*/
+static const struct of_device_id guts_device_ids[] = {
+       { .compatible = "fsl,qoriq-device-config-1.0", },
+       { .compatible = "fsl,qoriq-device-config-2.0", },
+       {}
+};
+
+
+/*
+ * Table for matching compatible strings, for device tree
+ * L3 cache controller node.
+ * "fsl,t4240-l3-cache-controller" corresponds to T4,
+ * "fsl,b4860-l3-cache-controller" corresponds to B4 &
+ * "fsl,p4080-l3-cache-controller" corresponds to other,
+ * SOCs.
+*/
+static const struct of_device_id l3_device_ids[] = {
+       { .compatible = "fsl,t4240-l3-cache-controller", },
+       { .compatible = "fsl,b4860-l3-cache-controller", },
+       { .compatible = "fsl,p4080-l3-cache-controller", },
+       {}
+};
+
+/* maximum subwindows permitted per liodn */
+static u32 max_subwindow_count;
+
+/* Pool for fspi allocation */
+struct gen_pool *spaace_pool;
+
+/**
+ * pamu_get_max_subwin_cnt() - Return the maximum supported
+ * subwindow count per liodn.
+ *
+ */
+u32 pamu_get_max_subwin_cnt()
+{
+       return max_subwindow_count;
+}
+
+/**
+ * pamu_get_ppaace() - Return the primary PACCE
+ * @liodn: liodn PAACT index for desired PAACE
+ *
+ * Returns the ppace pointer upon success else return
+ * null.
+ */
+static struct paace *pamu_get_ppaace(int liodn)
+{
+       if (!ppaact || liodn >= PAACE_NUMBER_ENTRIES) {
+               pr_debug("PPAACT doesn't exist\n");
+               return NULL;
+       }
+
+       return &ppaact[liodn];
+}
+
+/**
+ * pamu_enable_liodn() - Set valid bit of PACCE
+ * @liodn: liodn PAACT index for desired PAACE
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_enable_liodn(int liodn)
+{
+       struct paace *ppaace;
+
+       ppaace = pamu_get_ppaace(liodn);
+       if (!ppaace) {
+               pr_debug("Invalid primary paace entry\n");
+               return -ENOENT;
+       }
+
+       if (!get_bf(ppaace->addr_bitfields, PPAACE_AF_WSE)) {
+               pr_debug("liodn %d not configured\n", liodn);
+               return -EINVAL;
+       }
+
+       /* Ensure that all other stores to the ppaace complete first */
+       mb();
+
+       set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_VALID);
+       mb();
+
+       return 0;
+}
+
+/**
+ * pamu_disable_liodn() - Clears valid bit of PACCE
+ * @liodn: liodn PAACT index for desired PAACE
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_disable_liodn(int liodn)
+{
+       struct paace *ppaace;
+
+       ppaace = pamu_get_ppaace(liodn);
+       if (!ppaace) {
+               pr_debug("Invalid primary paace entry\n");
+               return -ENOENT;
+       }
+
+       set_bf(ppaace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID);
+       mb();
+
+       return 0;
+}
+
+/* Derive the window size encoding for a particular PAACE entry */
+static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size)
+{
+       /* Bug if not a power of 2 */
+       BUG_ON(!is_power_of_2(addrspace_size));
+
+       /* window size is 2^(WSE+1) bytes */
+       return __ffs(addrspace_size) - 1;
+}
+
+/* Derive the PAACE window count encoding for the subwindow count */
+static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt)
+{
+       /* window count is 2^(WCE+1) bytes */
+       return __ffs(subwindow_cnt) - 1;
+}
+
+/*
+ * Set the PAACE type as primary and set the coherency required domain
+ * attribute
+ */
+static void pamu_init_ppaace(struct paace *ppaace)
+{
+       set_bf(ppaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_PRIMARY);
+
+       set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+              PAACE_M_COHERENCE_REQ);
+}
+
+/*
+ * Set the PAACE type as secondary and set the coherency required domain
+ * attribute.
+ */
+static void pamu_init_spaace(struct paace *spaace)
+{
+       set_bf(spaace->addr_bitfields, PAACE_AF_PT, PAACE_PT_SECONDARY);
+       set_bf(spaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+              PAACE_M_COHERENCE_REQ);
+}
+
+/*
+ * Return the spaace (corresponding to the secondary window index)
+ * for a particular ppaace.
+ */
+static struct paace *pamu_get_spaace(struct paace *paace, u32 wnum)
+{
+       u32 subwin_cnt;
+       struct paace *spaace = NULL;
+
+       subwin_cnt = 1UL << (get_bf(paace->impl_attr, PAACE_IA_WCE) + 1);
+
+       if (wnum < subwin_cnt)
+               spaace = &spaact[paace->fspi + wnum];
+       else
+               pr_debug("secondary paace out of bounds\n");
+
+       return spaace;
+}
+
+/**
+ * pamu_get_fspi_and_allocate() - Allocates fspi index and reserves subwindows
+ *                                required for primary PAACE in the secondary
+ *                                PAACE table.
+ * @subwin_cnt: Number of subwindows to be reserved.
+ *
+ * A PPAACE entry may have a number of associated subwindows. A subwindow
+ * corresponds to a SPAACE entry in the SPAACT table. Each PAACE entry stores
+ * the index (fspi) of the first SPAACE entry in the SPAACT table. This
+ * function returns the index of the first SPAACE entry. The remaining
+ * SPAACE entries are reserved contiguously from that index.
+ *
+ * Returns a valid fspi index in the range of 0 - SPAACE_NUMBER_ENTRIES on success.
+ * If no SPAACE entry is available or the allocator can not reserve the required
+ * number of contiguous entries function returns ULONG_MAX indicating a failure.
+ *
+*/
+static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt)
+{
+       unsigned long spaace_addr;
+
+       spaace_addr = gen_pool_alloc(spaace_pool, subwin_cnt * sizeof(struct paace));
+       if (!spaace_addr)
+               return ULONG_MAX;
+
+       return (spaace_addr - (unsigned long)spaact) / (sizeof(struct paace));
+}
+
+/* Release the subwindows reserved for a particular LIODN */
+void pamu_free_subwins(int liodn)
+{
+       struct paace *ppaace;
+       u32 subwin_cnt, size;
+
+       ppaace = pamu_get_ppaace(liodn);
+       if (!ppaace) {
+               pr_debug("Invalid liodn entry\n");
+               return;
+       }
+
+       if (get_bf(ppaace->addr_bitfields, PPAACE_AF_MW)) {
+               subwin_cnt = 1UL << (get_bf(ppaace->impl_attr, PAACE_IA_WCE) + 1);
+               size = (subwin_cnt - 1) * sizeof(struct paace);
+               gen_pool_free(spaace_pool, (unsigned long)&spaact[ppaace->fspi], size);
+               set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
+       }
+}
+
+/*
+ * Function used for updating stash destination for the coressponding
+ * LIODN.
+ */
+int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value)
+{
+       struct paace *paace;
+
+       paace = pamu_get_ppaace(liodn);
+       if (!paace) {
+               pr_debug("Invalid liodn entry\n");
+               return -ENOENT;
+       }
+       if (subwin) {
+               paace = pamu_get_spaace(paace, subwin - 1);
+               if (!paace) {
+                       return -ENOENT;
+               }
+       }
+       set_bf(paace->impl_attr, PAACE_IA_CID, value);
+
+       mb();
+
+       return 0;
+}
+
+/* Disable a subwindow corresponding to the LIODN */
+int pamu_disable_spaace(int liodn, u32 subwin)
+{
+       struct paace *paace;
+
+       paace = pamu_get_ppaace(liodn);
+       if (!paace) {
+               pr_debug("Invalid liodn entry\n");
+               return -ENOENT;
+       }
+       if (subwin) {
+               paace = pamu_get_spaace(paace, subwin - 1);
+               if (!paace) {
+                       return -ENOENT;
+               }
+               set_bf(paace->addr_bitfields, PAACE_AF_V,
+                        PAACE_V_INVALID);
+       } else {
+               set_bf(paace->addr_bitfields, PAACE_AF_AP,
+                        PAACE_AP_PERMS_DENIED);
+       }
+
+       mb();
+
+       return 0;
+}
+
+
+/**
+ * pamu_config_paace() - Sets up PPAACE entry for specified liodn
+ *
+ * @liodn: Logical IO device number
+ * @win_addr: starting address of DSA window
+ * @win-size: size of DSA window
+ * @omi: Operation mapping index -- if ~omi == 0 then omi not defined
+ * @rpn: real (true physical) page number
+ * @stashid: cache stash id for associated cpu -- if ~stashid == 0 then
+ *          stashid not defined
+ * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then
+ *          snoopid not defined
+ * @subwin_cnt: number of sub-windows
+ * @prot: window permissions
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
+                      u32 omi, unsigned long rpn, u32 snoopid, u32 stashid,
+                      u32 subwin_cnt, int prot)
+{
+       struct paace *ppaace;
+       unsigned long fspi;
+
+       if (!is_power_of_2(win_size) || win_size < PAMU_PAGE_SIZE) {
+               pr_debug("window size too small or not a power of two %llx\n", win_size);
+               return -EINVAL;
+       }
+
+       if (win_addr & (win_size - 1)) {
+               pr_debug("window address is not aligned with window size\n");
+               return -EINVAL;
+       }
+
+       ppaace = pamu_get_ppaace(liodn);
+       if (!ppaace) {
+               return -ENOENT;
+       }
+
+       /* window size is 2^(WSE+1) bytes */
+       set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE,
+               map_addrspace_size_to_wse(win_size));
+
+       pamu_init_ppaace(ppaace);
+
+       ppaace->wbah = win_addr >> (PAMU_PAGE_SHIFT + 20);
+       set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL,
+              (win_addr >> PAMU_PAGE_SHIFT));
+
+       /* set up operation mapping if it's configured */
+       if (omi < OME_NUMBER_ENTRIES) {
+               set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+               ppaace->op_encode.index_ot.omi = omi;
+       } else if (~omi != 0) {
+               pr_debug("bad operation mapping index: %d\n", omi);
+               return -EINVAL;
+       }
+
+       /* configure stash id */
+       if (~stashid != 0)
+               set_bf(ppaace->impl_attr, PAACE_IA_CID, stashid);
+
+       /* configure snoop id */
+       if (~snoopid != 0)
+               ppaace->domain_attr.to_host.snpid = snoopid;
+
+       if (subwin_cnt) {
+               /* The first entry is in the primary PAACE instead */
+               fspi = pamu_get_fspi_and_allocate(subwin_cnt - 1);
+               if (fspi == ULONG_MAX) {
+                       pr_debug("spaace indexes exhausted\n");
+                       return -EINVAL;
+               }
+
+               /* window count is 2^(WCE+1) bytes */
+               set_bf(ppaace->impl_attr, PAACE_IA_WCE,
+                      map_subwindow_cnt_to_wce(subwin_cnt));
+               set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0x1);
+               ppaace->fspi = fspi;
+       } else {
+               set_bf(ppaace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE);
+               ppaace->twbah = rpn >> 20;
+               set_bf(ppaace->win_bitfields, PAACE_WIN_TWBAL, rpn);
+               set_bf(ppaace->addr_bitfields, PAACE_AF_AP, prot);
+               set_bf(ppaace->impl_attr, PAACE_IA_WCE, 0);
+               set_bf(ppaace->addr_bitfields, PPAACE_AF_MW, 0);
+       }
+       mb();
+
+       return 0;
+}
+
+/**
+ * pamu_config_spaace() - Sets up SPAACE entry for specified subwindow
+ *
+ * @liodn:  Logical IO device number
+ * @subwin_cnt:  number of sub-windows associated with dma-window
+ * @subwin: subwindow index
+ * @subwin_size: size of subwindow
+ * @omi: Operation mapping index
+ * @rpn: real (true physical) page number
+ * @snoopid: snoop id for hardware coherency -- if ~snoopid == 0 then
+ *                       snoopid not defined
+ * @stashid: cache stash id for associated cpu
+ * @enable: enable/disable subwindow after reconfiguration
+ * @prot: sub window permissions
+ *
+ * Returns 0 upon success else error code < 0 returned
+ */
+int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin,
+                      phys_addr_t subwin_size, u32 omi, unsigned long rpn,
+                      u32 snoopid, u32 stashid, int enable, int prot)
+{
+       struct paace *paace;
+
+
+       /* setup sub-windows */
+       if (!subwin_cnt) {
+               pr_debug("Invalid subwindow count\n");
+               return -EINVAL;
+       }
+
+       paace = pamu_get_ppaace(liodn);
+       if (subwin > 0 && subwin < subwin_cnt && paace) {
+               paace = pamu_get_spaace(paace, subwin - 1);
+
+               if (paace && !(paace->addr_bitfields & PAACE_V_VALID)) {
+                       pamu_init_spaace(paace);
+                       set_bf(paace->addr_bitfields, SPAACE_AF_LIODN, liodn);
+               }
+       }
+
+       if (!paace) {
+               pr_debug("Invalid liodn entry\n");
+               return -ENOENT;
+       }
+
+       if (!is_power_of_2(subwin_size) || subwin_size < PAMU_PAGE_SIZE) {
+               pr_debug("subwindow size out of range, or not a power of 2\n");
+               return -EINVAL;
+       }
+
+       if (rpn == ULONG_MAX) {
+               pr_debug("real page number out of range\n");
+               return -EINVAL;
+       }
+
+       /* window size is 2^(WSE+1) bytes */
+       set_bf(paace->win_bitfields, PAACE_WIN_SWSE,
+              map_addrspace_size_to_wse(subwin_size));
+
+       set_bf(paace->impl_attr, PAACE_IA_ATM, PAACE_ATM_WINDOW_XLATE);
+       paace->twbah = rpn >> 20;
+       set_bf(paace->win_bitfields, PAACE_WIN_TWBAL, rpn);
+       set_bf(paace->addr_bitfields, PAACE_AF_AP, prot);
+
+       /* configure snoop id */
+       if (~snoopid != 0)
+               paace->domain_attr.to_host.snpid = snoopid;
+
+       /* set up operation mapping if it's configured */
+       if (omi < OME_NUMBER_ENTRIES) {
+               set_bf(paace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+               paace->op_encode.index_ot.omi = omi;
+       } else if (~omi != 0) {
+               pr_debug("bad operation mapping index: %d\n", omi);
+               return -EINVAL;
+       }
+
+       if (~stashid != 0)
+               set_bf(paace->impl_attr, PAACE_IA_CID, stashid);
+
+       smp_wmb();
+
+       if (enable)
+               set_bf(paace->addr_bitfields, PAACE_AF_V, PAACE_V_VALID);
+
+       mb();
+
+       return 0;
+}
+
+/**
+* get_ome_index() - Returns the index in the operation mapping table
+*                   for device.
+* @*omi_index: pointer for storing the index value
+*
+*/
+void get_ome_index(u32 *omi_index, struct device *dev)
+{
+       if (of_device_is_compatible(dev->of_node, "fsl,qman-portal"))
+               *omi_index = OMI_QMAN;
+       if (of_device_is_compatible(dev->of_node, "fsl,qman"))
+               *omi_index = OMI_QMAN_PRIV;
+}
+
+/**
+ * get_stash_id - Returns stash destination id corresponding to a
+ *                cache type and vcpu.
+ * @stash_dest_hint: L1, L2 or L3
+ * @vcpu: vpcu target for a particular cache type.
+ *
+ * Returs stash on success or ~(u32)0 on failure.
+ *
+ */
+u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
+{
+       const u32 *prop;
+       struct device_node *node;
+       u32 cache_level;
+       int len, found = 0;
+       int i;
+
+       /* Fastpath, exit early if L3/CPC cache is target for stashing */
+       if (stash_dest_hint == PAMU_ATTR_CACHE_L3) {
+               node = of_find_matching_node(NULL, l3_device_ids);
+               if (node) {
+                       prop = of_get_property(node, "cache-stash-id", 0);
+                       if (!prop) {
+                               pr_debug("missing cache-stash-id at %s\n", node->full_name);
+                               of_node_put(node);
+                               return ~(u32)0;
+                       }
+                       of_node_put(node);
+                       return be32_to_cpup(prop);
+               }
+               return ~(u32)0;
+       }
+
+       for_each_node_by_type(node, "cpu") {
+               prop = of_get_property(node, "reg", &len);
+               for (i = 0; i < len / sizeof(u32); i++) {
+                       if (be32_to_cpup(&prop[i]) == vcpu) {
+                               found = 1;
+                               goto found_cpu_node;
+                       }
+               }
+       }
+found_cpu_node:
+
+       /* find the hwnode that represents the cache */
+       for (cache_level = PAMU_ATTR_CACHE_L1; (cache_level < PAMU_ATTR_CACHE_L3) && found; cache_level++) {
+               if (stash_dest_hint == cache_level) {
+                       prop = of_get_property(node, "cache-stash-id", 0);
+                       if (!prop) {
+                               pr_debug("missing cache-stash-id at %s\n", node->full_name);
+                               of_node_put(node);
+                               return ~(u32)0;
+                       }
+                       of_node_put(node);
+                       return be32_to_cpup(prop);
+               }
+
+               prop = of_get_property(node, "next-level-cache", 0);
+               if (!prop) {
+                       pr_debug("can't find next-level-cache at %s\n",
+                               node->full_name);
+                       of_node_put(node);
+                       return ~(u32)0;  /* can't traverse any further */
+               }
+               of_node_put(node);
+
+               /* advance to next node in cache hierarchy */
+               node = of_find_node_by_phandle(*prop);
+               if (!node) {
+                       pr_debug("Invalid node for cache hierarchy %s\n",
+                               node->full_name);
+                       return ~(u32)0;
+               }
+       }
+
+       pr_debug("stash dest not found for %d on vcpu %d\n",
+                 stash_dest_hint, vcpu);
+       return ~(u32)0;
+}
+
+/* Identify if the PAACT table entry belongs to QMAN, BMAN or QMAN Portal */
+#define QMAN_PAACE 1
+#define QMAN_PORTAL_PAACE 2
+#define BMAN_PAACE 3
+
+/**
+ * Setup operation mapping and stash destinations for QMAN and QMAN portal.
+ * Memory accesses to QMAN and BMAN private memory need not be coherent, so
+ * clear the PAACE entry coherency attribute for them.
+ */
+static void setup_qbman_paace(struct paace *ppaace, int  paace_type)
+{
+       switch (paace_type) {
+       case QMAN_PAACE:
+               set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+               ppaace->op_encode.index_ot.omi = OMI_QMAN_PRIV;
+               /* setup QMAN Private data stashing for the L3 cache */
+               set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0));
+               set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+                      0);
+               break;
+       case QMAN_PORTAL_PAACE:
+               set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
+               ppaace->op_encode.index_ot.omi = OMI_QMAN;
+               /*Set DQRR and Frame stashing for the L3 cache */
+               set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0));
+               break;
+       case BMAN_PAACE:
+               set_bf(ppaace->domain_attr.to_host.coherency_required, PAACE_DA_HOST_CR,
+                      0);
+               break;
+       }
+}
+
+/**
+ * Setup the operation mapping table for various devices. This is a static
+ * table where each table index corresponds to a particular device. PAMU uses
+ * this table to translate device transaction to appropriate corenet
+ * transaction.
+ */
+static void __init setup_omt(struct ome *omt)
+{
+       struct ome *ome;
+
+       /* Configure OMI_QMAN */
+       ome = &omt[OMI_QMAN];
+
+       ome->moe[IOE_READ_IDX] = EOE_VALID | EOE_READ;
+       ome->moe[IOE_EREAD0_IDX] = EOE_VALID | EOE_RSA;
+       ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+       ome->moe[IOE_EWRITE0_IDX] = EOE_VALID | EOE_WWSAO;
+
+       ome->moe[IOE_DIRECT0_IDX] = EOE_VALID | EOE_LDEC;
+       ome->moe[IOE_DIRECT1_IDX] = EOE_VALID | EOE_LDECPE;
+
+       /* Configure OMI_FMAN */
+       ome = &omt[OMI_FMAN];
+       ome->moe[IOE_READ_IDX]  = EOE_VALID | EOE_READI;
+       ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+
+       /* Configure OMI_QMAN private */
+       ome = &omt[OMI_QMAN_PRIV];
+       ome->moe[IOE_READ_IDX]  = EOE_VALID | EOE_READ;
+       ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+       ome->moe[IOE_EREAD0_IDX] = EOE_VALID | EOE_RSA;
+       ome->moe[IOE_EWRITE0_IDX] = EOE_VALID | EOE_WWSA;
+
+       /* Configure OMI_CAAM */
+       ome = &omt[OMI_CAAM];
+       ome->moe[IOE_READ_IDX]  = EOE_VALID | EOE_READI;
+       ome->moe[IOE_WRITE_IDX] = EOE_VALID | EOE_WRITE;
+}
+
+/*
+ * Get the maximum number of PAACT table entries
+ * and subwindows supported by PAMU
+ */
+static void get_pamu_cap_values(unsigned long pamu_reg_base)
+{
+       u32 pc_val;
+
+       pc_val = in_be32((u32 *)(pamu_reg_base + PAMU_PC3));
+       /* Maximum number of subwindows per liodn */
+       max_subwindow_count = 1 << (1 + PAMU_PC3_MWCE(pc_val));
+}
+
+/* Setup PAMU registers pointing to PAACT, SPAACT and OMT */
+int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size,
+                  phys_addr_t ppaact_phys, phys_addr_t spaact_phys,
+                  phys_addr_t omt_phys)
+{
+       u32 *pc;
+       struct pamu_mmap_regs *pamu_regs;
+
+       pc = (u32 *) (pamu_reg_base + PAMU_PC);
+       pamu_regs = (struct pamu_mmap_regs *)
+               (pamu_reg_base + PAMU_MMAP_REGS_BASE);
+
+       /* set up pointers to corenet control blocks */
+
+       out_be32(&pamu_regs->ppbah, upper_32_bits(ppaact_phys));
+       out_be32(&pamu_regs->ppbal, lower_32_bits(ppaact_phys));
+       ppaact_phys = ppaact_phys + PAACT_SIZE;
+       out_be32(&pamu_regs->pplah, upper_32_bits(ppaact_phys));
+       out_be32(&pamu_regs->pplal, lower_32_bits(ppaact_phys));
+
+       out_be32(&pamu_regs->spbah, upper_32_bits(spaact_phys));
+       out_be32(&pamu_regs->spbal, lower_32_bits(spaact_phys));
+       spaact_phys = spaact_phys + SPAACT_SIZE;
+       out_be32(&pamu_regs->splah, upper_32_bits(spaact_phys));
+       out_be32(&pamu_regs->splal, lower_32_bits(spaact_phys));
+
+       out_be32(&pamu_regs->obah, upper_32_bits(omt_phys));
+       out_be32(&pamu_regs->obal, lower_32_bits(omt_phys));
+       omt_phys = omt_phys + OMT_SIZE;
+       out_be32(&pamu_regs->olah, upper_32_bits(omt_phys));
+       out_be32(&pamu_regs->olal, lower_32_bits(omt_phys));
+
+       /*
+        * set PAMU enable bit,
+        * allow ppaact & omt to be cached
+        * & enable PAMU access violation interrupts.
+        */
+
+       out_be32((u32 *)(pamu_reg_base + PAMU_PICS),
+                       PAMU_ACCESS_VIOLATION_ENABLE);
+       out_be32(pc, PAMU_PC_PE | PAMU_PC_OCE | PAMU_PC_SPCC | PAMU_PC_PPCC);
+       return 0;
+}
+
+/* Enable all device LIODNS */
+static void __init setup_liodns(void)
+{
+       int i, len;
+       struct paace *ppaace;
+       struct device_node *node = NULL;
+       const u32 *prop;
+
+       for_each_node_with_property(node, "fsl,liodn") {
+               prop = of_get_property(node, "fsl,liodn", &len);
+               for (i = 0; i < len / sizeof(u32); i++) {
+                       int liodn;
+
+                       liodn = be32_to_cpup(&prop[i]);
+                       if (liodn >= PAACE_NUMBER_ENTRIES) {
+                               pr_debug("Invalid LIODN value %d\n", liodn);
+                               continue;
+                       }
+                       ppaace = pamu_get_ppaace(liodn);
+                       pamu_init_ppaace(ppaace);
+                       /* window size is 2^(WSE+1) bytes */
+                       set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
+                       ppaace->wbah = 0;
+                       set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
+                       set_bf(ppaace->impl_attr, PAACE_IA_ATM,
+                               PAACE_ATM_NO_XLATE);
+                       set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
+                               PAACE_AP_PERMS_ALL);
+                       if (of_device_is_compatible(node, "fsl,qman-portal"))
+                               setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE);
+                       if (of_device_is_compatible(node, "fsl,qman"))
+                               setup_qbman_paace(ppaace, QMAN_PAACE);
+                       if (of_device_is_compatible(node, "fsl,bman"))
+                               setup_qbman_paace(ppaace, BMAN_PAACE);
+                       mb();
+                       pamu_enable_liodn(liodn);
+               }
+       }
+}
+
+irqreturn_t pamu_av_isr(int irq, void *arg)
+{
+       struct pamu_isr_data *data = arg;
+       phys_addr_t phys;
+       unsigned int i, j, ret;
+
+       pr_emerg("access violation interrupt\n");
+
+       for (i = 0; i < data->count; i++) {
+               void __iomem *p = data->pamu_reg_base + i * PAMU_OFFSET;
+               u32 pics = in_be32(p + PAMU_PICS);
+
+               if (pics & PAMU_ACCESS_VIOLATION_STAT) {
+                       u32 avs1 = in_be32(p + PAMU_AVS1);
+                       struct paace *paace;
+
+                       pr_emerg("POES1=%08x\n", in_be32(p + PAMU_POES1));
+                       pr_emerg("POES2=%08x\n", in_be32(p + PAMU_POES2));
+                       pr_emerg("AVS1=%08x\n", avs1);
+                       pr_emerg("AVS2=%08x\n", in_be32(p + PAMU_AVS2));
+                       pr_emerg("AVA=%016llx\n", make64(in_be32(p + PAMU_AVAH),
+                               in_be32(p + PAMU_AVAL)));
+                       pr_emerg("UDAD=%08x\n", in_be32(p + PAMU_UDAD));
+                       pr_emerg("POEA=%016llx\n", make64(in_be32(p + PAMU_POEAH),
+                               in_be32(p + PAMU_POEAL)));
+
+                       phys = make64(in_be32(p + PAMU_POEAH),
+                               in_be32(p + PAMU_POEAL));
+
+                       /* Assume that POEA points to a PAACE */
+                       if (phys) {
+                               u32 *paace = phys_to_virt(phys);
+
+                               /* Only the first four words are relevant */
+                               for (j = 0; j < 4; j++)
+                                       pr_emerg("PAACE[%u]=%08x\n", j, in_be32(paace + j));
+                       }
+
+                       /* clear access violation condition */
+                       out_be32((p + PAMU_AVS1), avs1 & PAMU_AV_MASK);
+                       paace = pamu_get_ppaace(avs1 >> PAMU_AVS1_LIODN_SHIFT);
+                       BUG_ON(!paace);
+                       /* check if we got a violation for a disabled LIODN */
+                       if (!get_bf(paace->addr_bitfields, PAACE_AF_V)) {
+                               /*
+                                * As per hardware erratum A-003638, access
+                                * violation can be reported for a disabled
+                                * LIODN. If we hit that condition, disable
+                                * access violation reporting.
+                                */
+                               pics &= ~PAMU_ACCESS_VIOLATION_ENABLE;
+                       } else {
+                               /* Disable the LIODN */
+                               ret = pamu_disable_liodn(avs1 >> PAMU_AVS1_LIODN_SHIFT);
+                               BUG_ON(ret);
+                               pr_emerg("Disabling liodn %x\n", avs1 >> PAMU_AVS1_LIODN_SHIFT);
+                       }
+                       out_be32((p + PAMU_PICS), pics);
+               }
+       }
+
+
+       return IRQ_HANDLED;
+}
+
+#define LAWAR_EN               0x80000000
+#define LAWAR_TARGET_MASK      0x0FF00000
+#define LAWAR_TARGET_SHIFT     20
+#define LAWAR_SIZE_MASK                0x0000003F
+#define LAWAR_CSDID_MASK       0x000FF000
+#define LAWAR_CSDID_SHIFT      12
+
+#define LAW_SIZE_4K            0xb
+
+struct ccsr_law {
+       u32     lawbarh;        /* LAWn base address high */
+       u32     lawbarl;        /* LAWn base address low */
+       u32     lawar;          /* LAWn attributes */
+       u32     reserved;
+};
+
+/*
+ * Create a coherence subdomain for a given memory block.
+ */
+static int __init create_csd(phys_addr_t phys, size_t size, u32 csd_port_id)
+{
+       struct device_node *np;
+       const __be32 *iprop;
+       void __iomem *lac = NULL;       /* Local Access Control registers */
+       struct ccsr_law __iomem *law;
+       void __iomem *ccm = NULL;
+       u32 __iomem *csdids;
+       unsigned int i, num_laws, num_csds;
+       u32 law_target = 0;
+       u32 csd_id = 0;
+       int ret = 0;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,corenet-law");
+       if (!np)
+               return -ENODEV;
+
+       iprop = of_get_property(np, "fsl,num-laws", NULL);
+       if (!iprop) {
+               ret = -ENODEV;
+               goto error;
+       }
+
+       num_laws = be32_to_cpup(iprop);
+       if (!num_laws) {
+               ret = -ENODEV;
+               goto error;
+       }
+
+       lac = of_iomap(np, 0);
+       if (!lac) {
+               ret = -ENODEV;
+               goto error;
+       }
+
+       /* LAW registers are at offset 0xC00 */
+       law = lac + 0xC00;
+
+       of_node_put(np);
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,corenet-cf");
+       if (!np) {
+               ret = -ENODEV;
+               goto error;
+       }
+
+       iprop = of_get_property(np, "fsl,ccf-num-csdids", NULL);
+       if (!iprop) {
+               ret = -ENODEV;
+               goto error;
+       }
+
+       num_csds = be32_to_cpup(iprop);
+       if (!num_csds) {
+               ret = -ENODEV;
+               goto error;
+       }
+
+       ccm = of_iomap(np, 0);
+       if (!ccm) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       /* The undocumented CSDID registers are at offset 0x600 */
+       csdids = ccm + 0x600;
+
+       of_node_put(np);
+       np = NULL;
+
+       /* Find an unused coherence subdomain ID */
+       for (csd_id = 0; csd_id < num_csds; csd_id++) {
+               if (!csdids[csd_id])
+                       break;
+       }
+
+       /* Store the Port ID in the (undocumented) proper CIDMRxx register */
+       csdids[csd_id] = csd_port_id;
+
+       /* Find the DDR LAW that maps to our buffer. */
+       for (i = 0; i < num_laws; i++) {
+               if (law[i].lawar & LAWAR_EN) {
+                       phys_addr_t law_start, law_end;
+
+                       law_start = make64(law[i].lawbarh, law[i].lawbarl);
+                       law_end = law_start +
+                               (2ULL << (law[i].lawar & LAWAR_SIZE_MASK));
+
+                       if (law_start <= phys && phys < law_end) {
+                               law_target = law[i].lawar & LAWAR_TARGET_MASK;
+                               break;
+                       }
+               }
+       }
+
+       if (i == 0 || i == num_laws) {
+               /* This should never happen*/
+               ret = -ENOENT;
+               goto error;
+       }
+
+       /* Find a free LAW entry */
+       while (law[--i].lawar & LAWAR_EN) {
+               if (i == 0) {
+                       /* No higher priority LAW slots available */
+                       ret = -ENOENT;
+                       goto error;
+               }
+       }
+
+       law[i].lawbarh = upper_32_bits(phys);
+       law[i].lawbarl = lower_32_bits(phys);
+       wmb();
+       law[i].lawar = LAWAR_EN | law_target | (csd_id << LAWAR_CSDID_SHIFT) |
+               (LAW_SIZE_4K + get_order(size));
+       wmb();
+
+error:
+       if (ccm)
+               iounmap(ccm);
+
+       if (lac)
+               iounmap(lac);
+
+       if (np)
+               of_node_put(np);
+
+       return ret;
+}
+
+/*
+ * Table of SVRs and the corresponding PORT_ID values. Port ID corresponds to a
+ * bit map of snoopers for a given range of memory mapped by a LAW.
+ *
+ * All future CoreNet-enabled SOCs will have this erratum(A-004510) fixed, so this
+ * table should never need to be updated.  SVRs are guaranteed to be unique, so
+ * there is no worry that a future SOC will inadvertently have one of these
+ * values.
+ */
+static const struct {
+       u32 svr;
+       u32 port_id;
+} port_id_map[] = {
+       {0x82100010, 0xFF000000},       /* P2040 1.0 */
+       {0x82100011, 0xFF000000},       /* P2040 1.1 */
+       {0x82100110, 0xFF000000},       /* P2041 1.0 */
+       {0x82100111, 0xFF000000},       /* P2041 1.1 */
+       {0x82110310, 0xFF000000},       /* P3041 1.0 */
+       {0x82110311, 0xFF000000},       /* P3041 1.1 */
+       {0x82010020, 0xFFF80000},       /* P4040 2.0 */
+       {0x82000020, 0xFFF80000},       /* P4080 2.0 */
+       {0x82210010, 0xFC000000},       /* P5010 1.0 */
+       {0x82210020, 0xFC000000},       /* P5010 2.0 */
+       {0x82200010, 0xFC000000},       /* P5020 1.0 */
+       {0x82050010, 0xFF800000},       /* P5021 1.0 */
+       {0x82040010, 0xFF800000},       /* P5040 1.0 */
+};
+
+#define SVR_SECURITY   0x80000 /* The Security (E) bit */
+
+static int __init fsl_pamu_probe(struct platform_device *pdev)
+{
+       void __iomem *pamu_regs = NULL;
+       struct ccsr_guts __iomem *guts_regs = NULL;
+       u32 pamubypenr, pamu_counter;
+       unsigned long pamu_reg_off;
+       unsigned long pamu_reg_base;
+       struct pamu_isr_data *data = NULL;
+       struct device_node *guts_node;
+       u64 size;
+       struct page *p;
+       int ret = 0;
+       int irq;
+       phys_addr_t ppaact_phys;
+       phys_addr_t spaact_phys;
+       phys_addr_t omt_phys;
+       size_t mem_size = 0;
+       unsigned int order = 0;
+       u32 csd_port_id = 0;
+       unsigned i;
+       /*
+        * enumerate all PAMUs and allocate and setup PAMU tables
+        * for each of them,
+        * NOTE : All PAMUs share the same LIODN tables.
+        */
+
+       pamu_regs = of_iomap(pdev->dev.of_node, 0);
+       if (!pamu_regs) {
+               dev_err(&pdev->dev, "ioremap of PAMU node failed\n");
+               return -ENOMEM;
+       }
+       of_get_address(pdev->dev.of_node, 0, &size, NULL);
+
+       irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (irq == NO_IRQ) {
+               dev_warn(&pdev->dev, "no interrupts listed in PAMU node\n");
+               goto error;
+       }
+
+       data = kzalloc(sizeof(struct pamu_isr_data), GFP_KERNEL);
+       if (!data) {
+               dev_err(&pdev->dev, "PAMU isr data memory allocation failed\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+       data->pamu_reg_base = pamu_regs;
+       data->count = size / PAMU_OFFSET;
+
+       /* The ISR needs access to the regs, so we won't iounmap them */
+       ret = request_irq(irq, pamu_av_isr, 0, "pamu", data);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "error %i installing ISR for irq %i\n",
+                       ret, irq);
+               goto error;
+       }
+
+       guts_node = of_find_matching_node(NULL, guts_device_ids);
+       if (!guts_node) {
+               dev_err(&pdev->dev, "could not find GUTS node %s\n",
+                       pdev->dev.of_node->full_name);
+               ret = -ENODEV;
+               goto error;
+       }
+
+       guts_regs = of_iomap(guts_node, 0);
+       of_node_put(guts_node);
+       if (!guts_regs) {
+               dev_err(&pdev->dev, "ioremap of GUTS node failed\n");
+               ret = -ENODEV;
+               goto error;
+       }
+
+       /* read in the PAMU capability registers */
+       get_pamu_cap_values((unsigned long)pamu_regs);
+       /*
+        * To simplify the allocation of a coherency domain, we allocate the
+        * PAACT and the OMT in the same memory buffer.  Unfortunately, this
+        * wastes more memory compared to allocating the buffers separately.
+        */
+       /* Determine how much memory we need */
+       mem_size = (PAGE_SIZE << get_order(PAACT_SIZE)) +
+               (PAGE_SIZE << get_order(SPAACT_SIZE)) +
+               (PAGE_SIZE << get_order(OMT_SIZE));
+       order = get_order(mem_size);
+
+       p = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+       if (!p) {
+               dev_err(&pdev->dev, "unable to allocate PAACT/SPAACT/OMT block\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       ppaact = page_address(p);
+       ppaact_phys = page_to_phys(p);
+
+       /* Make sure the memory is naturally aligned */
+       if (ppaact_phys & ((PAGE_SIZE << order) - 1)) {
+               dev_err(&pdev->dev, "PAACT/OMT block is unaligned\n");
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       spaact = (void *)ppaact + (PAGE_SIZE << get_order(PAACT_SIZE));
+       omt = (void *)spaact + (PAGE_SIZE << get_order(SPAACT_SIZE));
+
+       dev_dbg(&pdev->dev, "ppaact virt=%p phys=0x%llx\n", ppaact,
+               (unsigned long long) ppaact_phys);
+
+       /* Check to see if we need to implement the work-around on this SOC */
+
+       /* Determine the Port ID for our coherence subdomain */
+       for (i = 0; i < ARRAY_SIZE(port_id_map); i++) {
+               if (port_id_map[i].svr == (mfspr(SPRN_SVR) & ~SVR_SECURITY)) {
+                       csd_port_id = port_id_map[i].port_id;
+                       dev_dbg(&pdev->dev, "found matching SVR %08x\n",
+                               port_id_map[i].svr);
+                       break;
+               }
+       }
+
+       if (csd_port_id) {
+               dev_dbg(&pdev->dev, "creating coherency subdomain at address "
+                       "0x%llx, size %zu, port id 0x%08x", ppaact_phys,
+                       mem_size, csd_port_id);
+
+               ret = create_csd(ppaact_phys, mem_size, csd_port_id);
+               if (ret) {
+                       dev_err(&pdev->dev, "could not create coherence "
+                               "subdomain\n");
+                       return ret;
+               }
+       }
+
+       spaact_phys = virt_to_phys(spaact);
+       omt_phys = virt_to_phys(omt);
+
+       spaace_pool = gen_pool_create(ilog2(sizeof(struct paace)), -1);
+       if (!spaace_pool) {
+               ret = -ENOMEM;
+               dev_err(&pdev->dev, "PAMU : failed to allocate spaace gen pool\n");
+               goto error;
+       }
+
+       ret = gen_pool_add(spaace_pool, (unsigned long)spaact, SPAACT_SIZE, -1);
+       if (ret)
+               goto error_genpool;
+
+       pamubypenr = in_be32(&guts_regs->pamubypenr);
+
+       for (pamu_reg_off = 0, pamu_counter = 0x80000000; pamu_reg_off < size;
+            pamu_reg_off += PAMU_OFFSET, pamu_counter >>= 1) {
+
+               pamu_reg_base = (unsigned long) pamu_regs + pamu_reg_off;
+               setup_one_pamu(pamu_reg_base, pamu_reg_off, ppaact_phys,
+                                spaact_phys, omt_phys);
+               /* Disable PAMU bypass for this PAMU */
+               pamubypenr &= ~pamu_counter;
+       }
+
+       setup_omt(omt);
+
+       /* Enable all relevant PAMU(s) */
+       out_be32(&guts_regs->pamubypenr, pamubypenr);
+
+       iounmap(guts_regs);
+
+       /* Enable DMA for the LIODNs in the device tree*/
+
+       setup_liodns();
+
+       return 0;
+
+error_genpool:
+       gen_pool_destroy(spaace_pool);
+
+error:
+       if (irq != NO_IRQ)
+               free_irq(irq, data);
+
+       if (data) {
+               memset(data, 0, sizeof(struct pamu_isr_data));
+               kfree(data);
+       }
+
+       if (pamu_regs)
+               iounmap(pamu_regs);
+
+       if (guts_regs)
+               iounmap(guts_regs);
+
+       if (ppaact)
+               free_pages((unsigned long)ppaact, order);
+
+       ppaact = NULL;
+
+       return ret;
+}
+
+static const struct of_device_id fsl_of_pamu_ids[] = {
+       {
+               .compatible = "fsl,p4080-pamu",
+       },
+       {
+               .compatible = "fsl,pamu",
+       },
+       {},
+};
+
+static struct platform_driver fsl_of_pamu_driver = {
+       .driver = {
+               .name = "fsl-of-pamu",
+               .owner = THIS_MODULE,
+       },
+       .probe = fsl_pamu_probe,
+};
+
+static __init int fsl_pamu_init(void)
+{
+       struct platform_device *pdev = NULL;
+       struct device_node *np;
+       int ret;
+
+       /*
+        * The normal OF process calls the probe function at some
+        * indeterminate later time, after most drivers have loaded.  This is
+        * too late for us, because PAMU clients (like the Qman driver)
+        * depend on PAMU being initialized early.
+        *
+        * So instead, we "manually" call our probe function by creating the
+        * platform devices ourselves.
+        */
+
+       /*
+        * We assume that there is only one PAMU node in the device tree.  A
+        * single PAMU node represents all of the PAMU devices in the SOC
+        * already.   Everything else already makes that assumption, and the
+        * binding for the PAMU nodes doesn't allow for any parent-child
+        * relationships anyway.  In other words, support for more than one
+        * PAMU node would require significant changes to a lot of code.
+        */
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,pamu");
+       if (!np) {
+               pr_err("could not find a PAMU node\n");
+               return -ENODEV;
+       }
+
+       ret = platform_driver_register(&fsl_of_pamu_driver);
+       if (ret) {
+               pr_err("could not register driver (err=%i)\n", ret);
+               goto error_driver_register;
+       }
+
+       pdev = platform_device_alloc("fsl-of-pamu", 0);
+       if (!pdev) {
+               pr_err("could not allocate device %s\n",
+                      np->full_name);
+               ret = -ENOMEM;
+               goto error_device_alloc;
+       }
+       pdev->dev.of_node = of_node_get(np);
+
+       ret = pamu_domain_init();
+       if (ret)
+               goto error_device_add;
+
+       ret = platform_device_add(pdev);
+       if (ret) {
+               pr_err("could not add device %s (err=%i)\n",
+                      np->full_name, ret);
+               goto error_device_add;
+       }
+
+       return 0;
+
+error_device_add:
+       of_node_put(pdev->dev.of_node);
+       pdev->dev.of_node = NULL;
+
+       platform_device_put(pdev);
+
+error_device_alloc:
+       platform_driver_unregister(&fsl_of_pamu_driver);
+
+error_driver_register:
+       of_node_put(np);
+
+       return ret;
+}
+arch_initcall(fsl_pamu_init);
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
new file mode 100644 (file)
index 0000000..8fc1a12
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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 (C) 2013 Freescale Semiconductor, Inc.
+ *
+ */
+
+#ifndef __FSL_PAMU_H
+#define __FSL_PAMU_H
+
+#include <asm/fsl_pamu_stash.h>
+
+/* Bit Field macros
+ *     v = bit field variable; m = mask, m##_SHIFT = shift, x = value to load
+ */
+#define set_bf(v, m, x)                (v = ((v) & ~(m)) | (((x) << (m##_SHIFT)) & (m)))
+#define get_bf(v, m)           (((v) & (m)) >> (m##_SHIFT))
+
+/* PAMU CCSR space */
+#define PAMU_PGC 0x00000000     /* Allows all peripheral accesses */
+#define PAMU_PE 0x40000000      /* enable PAMU                    */
+
+/* PAMU_OFFSET to the next pamu space in ccsr */
+#define PAMU_OFFSET 0x1000
+
+#define PAMU_MMAP_REGS_BASE 0
+
+struct pamu_mmap_regs {
+       u32 ppbah;
+       u32 ppbal;
+       u32 pplah;
+       u32 pplal;
+       u32 spbah;
+       u32 spbal;
+       u32 splah;
+       u32 splal;
+       u32 obah;
+       u32 obal;
+       u32 olah;
+       u32 olal;
+};
+
+/* PAMU Error Registers */
+#define PAMU_POES1 0x0040
+#define PAMU_POES2 0x0044
+#define PAMU_POEAH 0x0048
+#define PAMU_POEAL 0x004C
+#define PAMU_AVS1  0x0050
+#define PAMU_AVS1_AV    0x1
+#define PAMU_AVS1_OTV   0x6
+#define PAMU_AVS1_APV   0x78
+#define PAMU_AVS1_WAV   0x380
+#define PAMU_AVS1_LAV   0x1c00
+#define PAMU_AVS1_GCV   0x2000
+#define PAMU_AVS1_PDV   0x4000
+#define PAMU_AV_MASK    (PAMU_AVS1_AV | PAMU_AVS1_OTV | PAMU_AVS1_APV | PAMU_AVS1_WAV \
+                       | PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV)
+#define PAMU_AVS1_LIODN_SHIFT 16
+#define PAMU_LAV_LIODN_NOT_IN_PPAACT 0x400
+
+#define PAMU_AVS2  0x0054
+#define PAMU_AVAH  0x0058
+#define PAMU_AVAL  0x005C
+#define PAMU_EECTL 0x0060
+#define PAMU_EEDIS 0x0064
+#define PAMU_EEINTEN 0x0068
+#define PAMU_EEDET 0x006C
+#define PAMU_EEATTR 0x0070
+#define PAMU_EEAHI 0x0074
+#define PAMU_EEALO 0x0078
+#define PAMU_EEDHI 0X007C
+#define PAMU_EEDLO 0x0080
+#define PAMU_EECC  0x0084
+#define PAMU_UDAD  0x0090
+
+/* PAMU Revision Registers */
+#define PAMU_PR1 0x0BF8
+#define PAMU_PR2 0x0BFC
+
+/* PAMU version mask */
+#define PAMU_PR1_MASK 0xffff
+
+/* PAMU Capabilities Registers */
+#define PAMU_PC1 0x0C00
+#define PAMU_PC2 0x0C04
+#define PAMU_PC3 0x0C08
+#define PAMU_PC4 0x0C0C
+
+/* PAMU Control Register */
+#define PAMU_PC 0x0C10
+
+/* PAMU control defs */
+#define PAMU_CONTROL 0x0C10
+#define PAMU_PC_PGC 0x80000000  /* PAMU gate closed bit */
+#define PAMU_PC_PE   0x40000000 /* PAMU enable bit */
+#define PAMU_PC_SPCC 0x00000010 /* sPAACE cache enable */
+#define PAMU_PC_PPCC 0x00000001 /* pPAACE cache enable */
+#define PAMU_PC_OCE  0x00001000 /* OMT cache enable */
+
+#define PAMU_PFA1 0x0C14
+#define PAMU_PFA2 0x0C18
+
+#define PAMU_PC2_MLIODN(X) ((X) >> 16)
+#define PAMU_PC3_MWCE(X) (((X) >> 21) & 0xf)
+
+/* PAMU Interrupt control and Status Register */
+#define PAMU_PICS 0x0C1C
+#define PAMU_ACCESS_VIOLATION_STAT   0x8
+#define PAMU_ACCESS_VIOLATION_ENABLE 0x4
+
+/* PAMU Debug Registers */
+#define PAMU_PD1 0x0F00
+#define PAMU_PD2 0x0F04
+#define PAMU_PD3 0x0F08
+#define PAMU_PD4 0x0F0C
+
+#define PAACE_AP_PERMS_DENIED  0x0
+#define PAACE_AP_PERMS_QUERY   0x1
+#define PAACE_AP_PERMS_UPDATE  0x2
+#define PAACE_AP_PERMS_ALL     0x3
+
+#define PAACE_DD_TO_HOST       0x0
+#define PAACE_DD_TO_IO         0x1
+#define PAACE_PT_PRIMARY       0x0
+#define PAACE_PT_SECONDARY     0x1
+#define PAACE_V_INVALID        0x0
+#define PAACE_V_VALID          0x1
+#define PAACE_MW_SUBWINDOWS    0x1
+
+#define PAACE_WSE_4K           0xB
+#define PAACE_WSE_8K           0xC
+#define PAACE_WSE_16K          0xD
+#define PAACE_WSE_32K          0xE
+#define PAACE_WSE_64K          0xF
+#define PAACE_WSE_128K         0x10
+#define PAACE_WSE_256K         0x11
+#define PAACE_WSE_512K         0x12
+#define PAACE_WSE_1M           0x13
+#define PAACE_WSE_2M           0x14
+#define PAACE_WSE_4M           0x15
+#define PAACE_WSE_8M           0x16
+#define PAACE_WSE_16M          0x17
+#define PAACE_WSE_32M          0x18
+#define PAACE_WSE_64M          0x19
+#define PAACE_WSE_128M         0x1A
+#define PAACE_WSE_256M         0x1B
+#define PAACE_WSE_512M         0x1C
+#define PAACE_WSE_1G           0x1D
+#define PAACE_WSE_2G           0x1E
+#define PAACE_WSE_4G           0x1F
+
+#define PAACE_DID_PCI_EXPRESS_1 0x00
+#define PAACE_DID_PCI_EXPRESS_2 0x01
+#define PAACE_DID_PCI_EXPRESS_3 0x02
+#define PAACE_DID_PCI_EXPRESS_4 0x03
+#define PAACE_DID_LOCAL_BUS     0x04
+#define PAACE_DID_SRIO          0x0C
+#define PAACE_DID_MEM_1         0x10
+#define PAACE_DID_MEM_2         0x11
+#define PAACE_DID_MEM_3         0x12
+#define PAACE_DID_MEM_4         0x13
+#define PAACE_DID_MEM_1_2       0x14
+#define PAACE_DID_MEM_3_4       0x15
+#define PAACE_DID_MEM_1_4       0x16
+#define PAACE_DID_BM_SW_PORTAL  0x18
+#define PAACE_DID_PAMU          0x1C
+#define PAACE_DID_CAAM          0x21
+#define PAACE_DID_QM_SW_PORTAL  0x3C
+#define PAACE_DID_CORE0_INST    0x80
+#define PAACE_DID_CORE0_DATA    0x81
+#define PAACE_DID_CORE1_INST    0x82
+#define PAACE_DID_CORE1_DATA    0x83
+#define PAACE_DID_CORE2_INST    0x84
+#define PAACE_DID_CORE2_DATA    0x85
+#define PAACE_DID_CORE3_INST    0x86
+#define PAACE_DID_CORE3_DATA    0x87
+#define PAACE_DID_CORE4_INST    0x88
+#define PAACE_DID_CORE4_DATA    0x89
+#define PAACE_DID_CORE5_INST    0x8A
+#define PAACE_DID_CORE5_DATA    0x8B
+#define PAACE_DID_CORE6_INST    0x8C
+#define PAACE_DID_CORE6_DATA    0x8D
+#define PAACE_DID_CORE7_INST    0x8E
+#define PAACE_DID_CORE7_DATA    0x8F
+#define PAACE_DID_BROADCAST     0xFF
+
+#define PAACE_ATM_NO_XLATE      0x00
+#define PAACE_ATM_WINDOW_XLATE  0x01
+#define PAACE_ATM_PAGE_XLATE    0x02
+#define PAACE_ATM_WIN_PG_XLATE  \
+                (PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE)
+#define PAACE_OTM_NO_XLATE      0x00
+#define PAACE_OTM_IMMEDIATE     0x01
+#define PAACE_OTM_INDEXED       0x02
+#define PAACE_OTM_RESERVED      0x03
+
+#define PAACE_M_COHERENCE_REQ   0x01
+
+#define PAACE_PID_0             0x0
+#define PAACE_PID_1             0x1
+#define PAACE_PID_2             0x2
+#define PAACE_PID_3             0x3
+#define PAACE_PID_4             0x4
+#define PAACE_PID_5             0x5
+#define PAACE_PID_6             0x6
+#define PAACE_PID_7             0x7
+
+#define PAACE_TCEF_FORMAT0_8B   0x00
+#define PAACE_TCEF_FORMAT1_RSVD 0x01
+/*
+ * Hard coded value for the PAACT size to accomodate
+ * maximum LIODN value generated by u-boot.
+ */
+#define PAACE_NUMBER_ENTRIES    0x500
+/* Hard coded value for the SPAACT size */
+#define SPAACE_NUMBER_ENTRIES  0x800
+
+#define        OME_NUMBER_ENTRIES      16
+
+/* PAACE Bit Field Defines */
+#define PPAACE_AF_WBAL                 0xfffff000
+#define PPAACE_AF_WBAL_SHIFT           12
+#define PPAACE_AF_WSE                  0x00000fc0
+#define PPAACE_AF_WSE_SHIFT            6
+#define PPAACE_AF_MW                   0x00000020
+#define PPAACE_AF_MW_SHIFT             5
+
+#define SPAACE_AF_LIODN                        0xffff0000
+#define SPAACE_AF_LIODN_SHIFT          16
+
+#define PAACE_AF_AP                    0x00000018
+#define PAACE_AF_AP_SHIFT              3
+#define PAACE_AF_DD                    0x00000004
+#define PAACE_AF_DD_SHIFT              2
+#define PAACE_AF_PT                    0x00000002
+#define PAACE_AF_PT_SHIFT              1
+#define PAACE_AF_V                     0x00000001
+#define PAACE_AF_V_SHIFT               0
+
+#define PAACE_DA_HOST_CR               0x80
+#define PAACE_DA_HOST_CR_SHIFT         7
+
+#define PAACE_IA_CID                   0x00FF0000
+#define PAACE_IA_CID_SHIFT             16
+#define PAACE_IA_WCE                   0x000000F0
+#define PAACE_IA_WCE_SHIFT             4
+#define PAACE_IA_ATM                   0x0000000C
+#define PAACE_IA_ATM_SHIFT             2
+#define PAACE_IA_OTM                   0x00000003
+#define PAACE_IA_OTM_SHIFT             0
+
+#define PAACE_WIN_TWBAL                        0xfffff000
+#define PAACE_WIN_TWBAL_SHIFT          12
+#define PAACE_WIN_SWSE                 0x00000fc0
+#define PAACE_WIN_SWSE_SHIFT           6
+
+/* PAMU Data Structures */
+/* primary / secondary paact structure */
+struct paace {
+       /* PAACE Offset 0x00 */
+       u32 wbah;                               /* only valid for Primary PAACE */
+       u32 addr_bitfields;             /* See P/S PAACE_AF_* */
+
+       /* PAACE Offset 0x08 */
+       /* Interpretation of first 32 bits dependent on DD above */
+       union {
+               struct {
+                       /* Destination ID, see PAACE_DID_* defines */
+                       u8 did;
+                       /* Partition ID */
+                       u8 pid;
+                       /* Snoop ID */
+                       u8 snpid;
+                       /* coherency_required : 1 reserved : 7 */
+                       u8 coherency_required; /* See PAACE_DA_* */
+               } to_host;
+               struct {
+                       /* Destination ID, see PAACE_DID_* defines */
+                       u8  did;
+                       u8  reserved1;
+                       u16 reserved2;
+               } to_io;
+       } domain_attr;
+
+       /* Implementation attributes + window count + address & operation translation modes */
+       u32 impl_attr;                  /* See PAACE_IA_* */
+
+       /* PAACE Offset 0x10 */
+       /* Translated window base address */
+       u32 twbah;
+       u32 win_bitfields;                      /* See PAACE_WIN_* */
+
+       /* PAACE Offset 0x18 */
+       /* first secondary paace entry */
+       u32 fspi;                               /* only valid for Primary PAACE */
+       union {
+               struct {
+                       u8 ioea;
+                       u8 moea;
+                       u8 ioeb;
+                       u8 moeb;
+               } immed_ot;
+               struct {
+                       u16 reserved;
+                       u16 omi;
+               } index_ot;
+       } op_encode;
+
+       /* PAACE Offsets 0x20-0x38 */
+       u32 reserved[8];                        /* not currently implemented */
+};
+
+/* OME : Operation mapping entry
+ * MOE : Mapped Operation Encodings
+ * The operation mapping table is table containing operation mapping entries (OME).
+ * The index of a particular OME is programmed in the PAACE entry for translation
+ * in bound I/O operations corresponding to an LIODN. The OMT is used for translation
+ * specifically in case of the indexed translation mode. Each OME contains a 128
+ * byte mapped operation encoding (MOE), where each byte represents an MOE.
+ */
+#define NUM_MOE 128
+struct ome {
+       u8 moe[NUM_MOE];
+} __attribute__((packed));
+
+#define PAACT_SIZE              (sizeof(struct paace) * PAACE_NUMBER_ENTRIES)
+#define SPAACT_SIZE              (sizeof(struct paace) * SPAACE_NUMBER_ENTRIES)
+#define OMT_SIZE                (sizeof(struct ome) * OME_NUMBER_ENTRIES)
+
+#define PAMU_PAGE_SHIFT 12
+#define PAMU_PAGE_SIZE  4096ULL
+
+#define IOE_READ        0x00
+#define IOE_READ_IDX    0x00
+#define IOE_WRITE       0x81
+#define IOE_WRITE_IDX   0x01
+#define IOE_EREAD0      0x82    /* Enhanced read type 0 */
+#define IOE_EREAD0_IDX  0x02    /* Enhanced read type 0 */
+#define IOE_EWRITE0     0x83    /* Enhanced write type 0 */
+#define IOE_EWRITE0_IDX 0x03    /* Enhanced write type 0 */
+#define IOE_DIRECT0     0x84    /* Directive type 0 */
+#define IOE_DIRECT0_IDX 0x04    /* Directive type 0 */
+#define IOE_EREAD1      0x85    /* Enhanced read type 1 */
+#define IOE_EREAD1_IDX  0x05    /* Enhanced read type 1 */
+#define IOE_EWRITE1     0x86    /* Enhanced write type 1 */
+#define IOE_EWRITE1_IDX 0x06    /* Enhanced write type 1 */
+#define IOE_DIRECT1     0x87    /* Directive type 1 */
+#define IOE_DIRECT1_IDX 0x07    /* Directive type 1 */
+#define IOE_RAC         0x8c    /* Read with Atomic clear */
+#define IOE_RAC_IDX     0x0c    /* Read with Atomic clear */
+#define IOE_RAS         0x8d    /* Read with Atomic set */
+#define IOE_RAS_IDX     0x0d    /* Read with Atomic set */
+#define IOE_RAD         0x8e    /* Read with Atomic decrement */
+#define IOE_RAD_IDX     0x0e    /* Read with Atomic decrement */
+#define IOE_RAI         0x8f    /* Read with Atomic increment */
+#define IOE_RAI_IDX     0x0f    /* Read with Atomic increment */
+
+#define EOE_READ        0x00
+#define EOE_WRITE       0x01
+#define EOE_RAC         0x0c    /* Read with Atomic clear */
+#define EOE_RAS         0x0d    /* Read with Atomic set */
+#define EOE_RAD         0x0e    /* Read with Atomic decrement */
+#define EOE_RAI         0x0f    /* Read with Atomic increment */
+#define EOE_LDEC        0x10    /* Load external cache */
+#define EOE_LDECL       0x11    /* Load external cache with stash lock */
+#define EOE_LDECPE      0x12    /* Load external cache with preferred exclusive */
+#define EOE_LDECPEL     0x13    /* Load external cache with preferred exclusive and lock */
+#define EOE_LDECFE      0x14    /* Load external cache with forced exclusive */
+#define EOE_LDECFEL     0x15    /* Load external cache with forced exclusive and lock */
+#define EOE_RSA         0x16    /* Read with stash allocate */
+#define EOE_RSAU        0x17    /* Read with stash allocate and unlock */
+#define EOE_READI       0x18    /* Read with invalidate */
+#define EOE_RWNITC      0x19    /* Read with no intention to cache */
+#define EOE_WCI         0x1a    /* Write cache inhibited */
+#define EOE_WWSA        0x1b    /* Write with stash allocate */
+#define EOE_WWSAL       0x1c    /* Write with stash allocate and lock */
+#define EOE_WWSAO       0x1d    /* Write with stash allocate only */
+#define EOE_WWSAOL      0x1e    /* Write with stash allocate only and lock */
+#define EOE_VALID       0x80
+
+/* Function prototypes */
+int pamu_domain_init(void);
+int pamu_enable_liodn(int liodn);
+int pamu_disable_liodn(int liodn);
+void pamu_free_subwins(int liodn);
+int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
+                      u32 omi, unsigned long rpn, u32 snoopid, uint32_t stashid,
+                      u32 subwin_cnt, int prot);
+int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin_addr,
+                      phys_addr_t subwin_size, u32 omi, unsigned long rpn,
+                      uint32_t snoopid, u32 stashid, int enable, int prot);
+
+u32 get_stash_id(u32 stash_dest_hint, u32 vcpu);
+void get_ome_index(u32 *omi_index, struct device *dev);
+int  pamu_update_paace_stash(int liodn, u32 subwin, u32 value);
+int pamu_disable_spaace(int liodn, u32 subwin);
+u32 pamu_get_max_subwin_cnt(void);
+
+#endif  /* __FSL_PAMU_H */
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
new file mode 100644 (file)
index 0000000..c857c30
--- /dev/null
@@ -0,0 +1,1172 @@
+/*
+ * 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 (C) 2013 Freescale Semiconductor, Inc.
+ * Author: Varun Sethi <varun.sethi@freescale.com>
+ *
+ */
+
+#define pr_fmt(fmt)    "fsl-pamu-domain: %s: " fmt, __func__
+
+#include <linux/init.h>
+#include <linux/iommu.h>
+#include <linux/notifier.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/bootmem.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <asm/bitops.h>
+
+#include <asm/pci-bridge.h>
+#include <sysdev/fsl_pci.h>
+
+#include "fsl_pamu_domain.h"
+#include "pci.h"
+
+/*
+ * Global spinlock that needs to be held while
+ * configuring PAMU.
+ */
+static DEFINE_SPINLOCK(iommu_lock);
+
+static struct kmem_cache *fsl_pamu_domain_cache;
+static struct kmem_cache *iommu_devinfo_cache;
+static DEFINE_SPINLOCK(device_domain_lock);
+
+static int __init iommu_init_mempool(void)
+{
+
+       fsl_pamu_domain_cache = kmem_cache_create("fsl_pamu_domain",
+                                        sizeof(struct fsl_dma_domain),
+                                        0,
+                                        SLAB_HWCACHE_ALIGN,
+
+                                        NULL);
+       if (!fsl_pamu_domain_cache) {
+               pr_debug("Couldn't create fsl iommu_domain cache\n");
+               return -ENOMEM;
+       }
+
+       iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
+                                        sizeof(struct device_domain_info),
+                                        0,
+                                        SLAB_HWCACHE_ALIGN,
+                                        NULL);
+       if (!iommu_devinfo_cache) {
+               pr_debug("Couldn't create devinfo cache\n");
+               kmem_cache_destroy(fsl_pamu_domain_cache);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t iova)
+{
+       u32 win_cnt = dma_domain->win_cnt;
+       struct dma_window *win_ptr =
+                               &dma_domain->win_arr[0];
+       struct iommu_domain_geometry *geom;
+
+       geom = &dma_domain->iommu_domain->geometry;
+
+       if (!win_cnt || !dma_domain->geom_size) {
+               pr_debug("Number of windows/geometry not configured for the domain\n");
+               return 0;
+       }
+
+       if (win_cnt > 1) {
+               u64 subwin_size;
+               dma_addr_t subwin_iova;
+               u32 wnd;
+
+               subwin_size = dma_domain->geom_size >> ilog2(win_cnt);
+               subwin_iova = iova & ~(subwin_size - 1);
+               wnd = (subwin_iova - geom->aperture_start) >> ilog2(subwin_size);
+               win_ptr = &dma_domain->win_arr[wnd];
+       }
+
+       if (win_ptr->valid)
+               return (win_ptr->paddr + (iova & (win_ptr->size - 1)));
+
+       return 0;
+}
+
+static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain)
+{
+       struct dma_window *sub_win_ptr =
+                               &dma_domain->win_arr[0];
+       int i, ret;
+       unsigned long rpn, flags;
+
+       for (i = 0; i < dma_domain->win_cnt; i++) {
+               if (sub_win_ptr[i].valid) {
+                       rpn = sub_win_ptr[i].paddr >>
+                                PAMU_PAGE_SHIFT;
+                       spin_lock_irqsave(&iommu_lock, flags);
+                       ret = pamu_config_spaace(liodn, dma_domain->win_cnt, i,
+                                                sub_win_ptr[i].size,
+                                                ~(u32)0,
+                                                rpn,
+                                                dma_domain->snoop_id,
+                                                dma_domain->stash_id,
+                                                (i > 0) ? 1 : 0,
+                                                sub_win_ptr[i].prot);
+                       spin_unlock_irqrestore(&iommu_lock, flags);
+                       if (ret) {
+                               pr_debug("PAMU SPAACE configuration failed for liodn %d\n",
+                                        liodn);
+                               return ret;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static int map_win(int liodn, struct fsl_dma_domain *dma_domain)
+{
+       int ret;
+       struct dma_window *wnd = &dma_domain->win_arr[0];
+       phys_addr_t wnd_addr = dma_domain->iommu_domain->geometry.aperture_start;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu_lock, flags);
+       ret = pamu_config_ppaace(liodn, wnd_addr,
+                                wnd->size,
+                                ~(u32)0,
+                                wnd->paddr >> PAMU_PAGE_SHIFT,
+                                dma_domain->snoop_id, dma_domain->stash_id,
+                                0, wnd->prot);
+       spin_unlock_irqrestore(&iommu_lock, flags);
+       if (ret)
+               pr_debug("PAMU PAACE configuration failed for liodn %d\n",
+                       liodn);
+
+       return ret;
+}
+
+/* Map the DMA window corresponding to the LIODN */
+static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
+{
+       if (dma_domain->win_cnt > 1)
+               return map_subwins(liodn, dma_domain);
+       else
+               return map_win(liodn, dma_domain);
+
+}
+
+/* Update window/subwindow mapping for the LIODN */
+static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr)
+{
+       int ret;
+       struct dma_window *wnd = &dma_domain->win_arr[wnd_nr];
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu_lock, flags);
+       if (dma_domain->win_cnt > 1) {
+               ret = pamu_config_spaace(liodn, dma_domain->win_cnt, wnd_nr,
+                                        wnd->size,
+                                        ~(u32)0,
+                                        wnd->paddr >> PAMU_PAGE_SHIFT,
+                                        dma_domain->snoop_id,
+                                        dma_domain->stash_id,
+                                        (wnd_nr > 0) ? 1 : 0,
+                                        wnd->prot);
+               if (ret)
+                       pr_debug("Subwindow reconfiguration failed for liodn %d\n", liodn);
+       } else {
+               phys_addr_t wnd_addr;
+
+               wnd_addr = dma_domain->iommu_domain->geometry.aperture_start;
+
+               ret = pamu_config_ppaace(liodn, wnd_addr,
+                                        wnd->size,
+                                        ~(u32)0,
+                                        wnd->paddr >> PAMU_PAGE_SHIFT,
+                                       dma_domain->snoop_id, dma_domain->stash_id,
+                                       0, wnd->prot);
+               if (ret)
+                       pr_debug("Window reconfiguration failed for liodn %d\n", liodn);
+       }
+
+       spin_unlock_irqrestore(&iommu_lock, flags);
+
+       return ret;
+}
+
+static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
+                                u32 val)
+{
+       int ret = 0, i;
+       unsigned long flags;
+
+       spin_lock_irqsave(&iommu_lock, flags);
+       if (!dma_domain->win_arr) {
+               pr_debug("Windows not configured, stash destination update failed for liodn %d\n", liodn);
+               spin_unlock_irqrestore(&iommu_lock, flags);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < dma_domain->win_cnt; i++) {
+               ret = pamu_update_paace_stash(liodn, i, val);
+               if (ret) {
+                       pr_debug("Failed to update SPAACE %d field for liodn %d\n ", i, liodn);
+                       spin_unlock_irqrestore(&iommu_lock, flags);
+                       return ret;
+               }
+       }
+
+       spin_unlock_irqrestore(&iommu_lock, flags);
+
+       return ret;
+}
+
+/* Set the geometry parameters for a LIODN */
+static int pamu_set_liodn(int liodn, struct device *dev,
+                          struct fsl_dma_domain *dma_domain,
+                          struct iommu_domain_geometry *geom_attr,
+                          u32 win_cnt)
+{
+       phys_addr_t window_addr, window_size;
+       phys_addr_t subwin_size;
+       int ret = 0, i;
+       u32 omi_index = ~(u32)0;
+       unsigned long flags;
+
+       /*
+        * Configure the omi_index at the geometry setup time.
+        * This is a static value which depends on the type of
+        * device and would not change thereafter.
+        */
+       get_ome_index(&omi_index, dev);
+
+       window_addr = geom_attr->aperture_start;
+       window_size = dma_domain->geom_size;
+
+       spin_lock_irqsave(&iommu_lock, flags);
+       ret = pamu_disable_liodn(liodn);
+       if (!ret)
+               ret = pamu_config_ppaace(liodn, window_addr, window_size, omi_index,
+                                        0, dma_domain->snoop_id,
+                                        dma_domain->stash_id, win_cnt, 0);
+       spin_unlock_irqrestore(&iommu_lock, flags);
+       if (ret) {
+               pr_debug("PAMU PAACE configuration failed for liodn %d, win_cnt =%d\n", liodn, win_cnt);
+               return ret;
+       }
+
+       if (win_cnt > 1) {
+               subwin_size = window_size >> ilog2(win_cnt);
+               for (i = 0; i < win_cnt; i++) {
+                       spin_lock_irqsave(&iommu_lock, flags);
+                       ret = pamu_disable_spaace(liodn, i);
+                       if (!ret)
+                               ret = pamu_config_spaace(liodn, win_cnt, i,
+                                                        subwin_size, omi_index,
+                                                        0, dma_domain->snoop_id,
+                                                        dma_domain->stash_id,
+                                                        0, 0);
+                       spin_unlock_irqrestore(&iommu_lock, flags);
+                       if (ret) {
+                               pr_debug("PAMU SPAACE configuration failed for liodn %d\n", liodn);
+                               return ret;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+static int check_size(u64 size, dma_addr_t iova)
+{
+       /*
+        * Size must be a power of two and at least be equal
+        * to PAMU page size.
+        */
+       if (!is_power_of_2(size) || size < PAMU_PAGE_SIZE) {
+               pr_debug("%s: size too small or not a power of two\n", __func__);
+               return -EINVAL;
+       }
+
+       /* iova must be page size aligned*/
+       if (iova & (size - 1)) {
+               pr_debug("%s: address is not aligned with window size\n", __func__);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static struct fsl_dma_domain *iommu_alloc_dma_domain(void)
+{
+       struct fsl_dma_domain *domain;
+
+       domain = kmem_cache_zalloc(fsl_pamu_domain_cache, GFP_KERNEL);
+       if (!domain)
+               return NULL;
+
+       domain->stash_id = ~(u32)0;
+       domain->snoop_id = ~(u32)0;
+       domain->win_cnt = pamu_get_max_subwin_cnt();
+       domain->geom_size = 0;
+
+       INIT_LIST_HEAD(&domain->devices);
+
+       spin_lock_init(&domain->domain_lock);
+
+       return domain;
+}
+
+static inline struct device_domain_info *find_domain(struct device *dev)
+{
+       return dev->archdata.iommu_domain;
+}
+
+static void remove_device_ref(struct device_domain_info *info, u32 win_cnt)
+{
+       unsigned long flags;
+
+       list_del(&info->link);
+       spin_lock_irqsave(&iommu_lock, flags);
+       if (win_cnt > 1)
+               pamu_free_subwins(info->liodn);
+       pamu_disable_liodn(info->liodn);
+       spin_unlock_irqrestore(&iommu_lock, flags);
+       spin_lock_irqsave(&device_domain_lock, flags);
+       info->dev->archdata.iommu_domain = NULL;
+       kmem_cache_free(iommu_devinfo_cache, info);
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+}
+
+static void detach_device(struct device *dev, struct fsl_dma_domain *dma_domain)
+{
+       struct device_domain_info *info, *tmp;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+       /* Remove the device from the domain device list */
+       list_for_each_entry_safe(info, tmp, &dma_domain->devices, link) {
+               if (!dev || (info->dev == dev))
+                       remove_device_ref(info, dma_domain->win_cnt);
+       }
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+}
+
+static void attach_device(struct fsl_dma_domain *dma_domain, int liodn, struct device *dev)
+{
+       struct device_domain_info *info, *old_domain_info;
+       unsigned long flags;
+
+       spin_lock_irqsave(&device_domain_lock, flags);
+       /*
+        * Check here if the device is already attached to domain or not.
+        * If the device is already attached to a domain detach it.
+        */
+       old_domain_info = find_domain(dev);
+       if (old_domain_info && old_domain_info->domain != dma_domain) {
+               spin_unlock_irqrestore(&device_domain_lock, flags);
+               detach_device(dev, old_domain_info->domain);
+               spin_lock_irqsave(&device_domain_lock, flags);
+       }
+
+       info = kmem_cache_zalloc(iommu_devinfo_cache, GFP_ATOMIC);
+
+       info->dev = dev;
+       info->liodn = liodn;
+       info->domain = dma_domain;
+
+       list_add(&info->link, &dma_domain->devices);
+       /*
+        * In case of devices with multiple LIODNs just store
+        * the info for the first LIODN as all
+        * LIODNs share the same domain
+        */
+       if (!old_domain_info)
+               dev->archdata.iommu_domain = info;
+       spin_unlock_irqrestore(&device_domain_lock, flags);
+
+}
+
+static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
+                                           dma_addr_t iova)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+
+       if ((iova < domain->geometry.aperture_start) ||
+               iova > (domain->geometry.aperture_end))
+               return 0;
+
+       return get_phys_addr(dma_domain, iova);
+}
+
+static int fsl_pamu_domain_has_cap(struct iommu_domain *domain,
+                                     unsigned long cap)
+{
+       return cap == IOMMU_CAP_CACHE_COHERENCY;
+}
+
+static void fsl_pamu_domain_destroy(struct iommu_domain *domain)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+
+       domain->priv = NULL;
+
+       /* remove all the devices from the device list */
+       detach_device(NULL, dma_domain);
+
+       dma_domain->enabled = 0;
+       dma_domain->mapped = 0;
+
+       kmem_cache_free(fsl_pamu_domain_cache, dma_domain);
+}
+
+static int fsl_pamu_domain_init(struct iommu_domain *domain)
+{
+       struct fsl_dma_domain *dma_domain;
+
+       dma_domain = iommu_alloc_dma_domain();
+       if (!dma_domain) {
+               pr_debug("dma_domain allocation failed\n");
+               return -ENOMEM;
+       }
+       domain->priv = dma_domain;
+       dma_domain->iommu_domain = domain;
+       /* defaul geometry 64 GB i.e. maximum system address */
+       domain->geometry.aperture_start = 0;
+       domain->geometry.aperture_end = (1ULL << 36) - 1;
+       domain->geometry.force_aperture = true;
+
+       return 0;
+}
+
+/* Configure geometry settings for all LIODNs associated with domain */
+static int pamu_set_domain_geometry(struct fsl_dma_domain *dma_domain,
+                                   struct iommu_domain_geometry *geom_attr,
+                                   u32 win_cnt)
+{
+       struct device_domain_info *info;
+       int ret = 0;
+
+       list_for_each_entry(info, &dma_domain->devices, link) {
+               ret = pamu_set_liodn(info->liodn, info->dev, dma_domain,
+                                     geom_attr, win_cnt);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/* Update stash destination for all LIODNs associated with the domain */
+static int update_domain_stash(struct fsl_dma_domain *dma_domain, u32 val)
+{
+       struct device_domain_info *info;
+       int ret = 0;
+
+       list_for_each_entry(info, &dma_domain->devices, link) {
+               ret = update_liodn_stash(info->liodn, dma_domain, val);
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+/* Update domain mappings for all LIODNs associated with the domain */
+static int update_domain_mapping(struct fsl_dma_domain *dma_domain, u32 wnd_nr)
+{
+       struct device_domain_info *info;
+       int ret = 0;
+
+       list_for_each_entry(info, &dma_domain->devices, link) {
+               ret = update_liodn(info->liodn, dma_domain, wnd_nr);
+               if (ret)
+                       break;
+       }
+       return ret;
+}
+
+static int disable_domain_win(struct fsl_dma_domain *dma_domain, u32 wnd_nr)
+{
+       struct device_domain_info *info;
+       int ret = 0;
+
+       list_for_each_entry(info, &dma_domain->devices, link) {
+               if (dma_domain->win_cnt == 1 && dma_domain->enabled) {
+                       ret = pamu_disable_liodn(info->liodn);
+                       if (!ret)
+                               dma_domain->enabled = 0;
+               } else {
+                       ret = pamu_disable_spaace(info->liodn, wnd_nr);
+               }
+       }
+
+       return ret;
+}
+
+static void fsl_pamu_window_disable(struct iommu_domain *domain, u32 wnd_nr)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+       if (!dma_domain->win_arr) {
+               pr_debug("Number of windows not configured\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return;
+       }
+
+       if (wnd_nr >= dma_domain->win_cnt) {
+               pr_debug("Invalid window index\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return;
+       }
+
+       if (dma_domain->win_arr[wnd_nr].valid) {
+               ret = disable_domain_win(dma_domain, wnd_nr);
+               if (!ret) {
+                       dma_domain->win_arr[wnd_nr].valid = 0;
+                       dma_domain->mapped--;
+               }
+       }
+
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+}
+
+static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr,
+                                 phys_addr_t paddr, u64 size, int prot)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       struct dma_window *wnd;
+       int pamu_prot = 0;
+       int ret;
+       unsigned long flags;
+       u64 win_size;
+
+       if (prot & IOMMU_READ)
+               pamu_prot |= PAACE_AP_PERMS_QUERY;
+       if (prot & IOMMU_WRITE)
+               pamu_prot |= PAACE_AP_PERMS_UPDATE;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+       if (!dma_domain->win_arr) {
+               pr_debug("Number of windows not configured\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -ENODEV;
+       }
+
+       if (wnd_nr >= dma_domain->win_cnt) {
+               pr_debug("Invalid window index\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -EINVAL;
+       }
+
+       win_size = dma_domain->geom_size >> ilog2(dma_domain->win_cnt);
+       if (size > win_size) {
+               pr_debug("Invalid window size \n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -EINVAL;
+       }
+
+       if (dma_domain->win_cnt == 1) {
+               if (dma_domain->enabled) {
+                       pr_debug("Disable the window before updating the mapping\n");
+                       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+                       return -EBUSY;
+               }
+
+               ret = check_size(size, domain->geometry.aperture_start);
+               if (ret) {
+                       pr_debug("Aperture start not aligned to the size\n");
+                       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+                       return -EINVAL;
+               }
+       }
+
+       wnd = &dma_domain->win_arr[wnd_nr];
+       if (!wnd->valid) {
+               wnd->paddr = paddr;
+               wnd->size = size;
+               wnd->prot = pamu_prot;
+
+               ret = update_domain_mapping(dma_domain, wnd_nr);
+               if (!ret) {
+                       wnd->valid = 1;
+                       dma_domain->mapped++;
+               }
+       } else {
+               pr_debug("Disable the window before updating the mapping\n");
+               ret = -EBUSY;
+       }
+
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+       return ret;
+}
+
+/*
+ * Attach the LIODN to the DMA domain and configure the geometry
+ * and window mappings.
+ */
+static int handle_attach_device(struct fsl_dma_domain *dma_domain,
+                                struct device *dev, const u32 *liodn,
+                                int num)
+{
+       unsigned long flags;
+       struct iommu_domain *domain = dma_domain->iommu_domain;
+       int ret = 0;
+       int i;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+       for (i = 0; i < num; i++) {
+
+               /* Ensure that LIODN value is valid */
+               if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
+                       pr_debug("Invalid liodn %d, attach device failed for %s\n",
+                               liodn[i], dev->of_node->full_name);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               attach_device(dma_domain, liodn[i], dev);
+               /*
+                * Check if geometry has already been configured
+                * for the domain. If yes, set the geometry for
+                * the LIODN.
+                */
+               if (dma_domain->win_arr) {
+                       u32 win_cnt = dma_domain->win_cnt > 1 ? dma_domain->win_cnt : 0;
+                       ret = pamu_set_liodn(liodn[i], dev, dma_domain,
+                                             &domain->geometry,
+                                             win_cnt);
+                       if (ret)
+                               break;
+                       if (dma_domain->mapped) {
+                               /*
+                                * Create window/subwindow mapping for
+                                * the LIODN.
+                                */
+                               ret = map_liodn(liodn[i], dma_domain);
+                               if (ret)
+                                       break;
+                       }
+               }
+       }
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+       return ret;
+}
+
+static int fsl_pamu_attach_device(struct iommu_domain *domain,
+                                 struct device *dev)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       const u32 *liodn;
+       u32 liodn_cnt;
+       int len, ret = 0;
+       struct pci_dev *pdev = NULL;
+       struct pci_controller *pci_ctl;
+
+       /*
+        * Use LIODN of the PCI controller while attaching a
+        * PCI device.
+        */
+       if (dev->bus == &pci_bus_type) {
+               pdev = to_pci_dev(dev);
+               pci_ctl = pci_bus_to_host(pdev->bus);
+               /*
+                * make dev point to pci controller device
+                * so we can get the LIODN programmed by
+                * u-boot.
+                */
+               dev = pci_ctl->parent;
+       }
+
+       liodn = of_get_property(dev->of_node, "fsl,liodn", &len);
+       if (liodn) {
+               liodn_cnt = len / sizeof(u32);
+               ret = handle_attach_device(dma_domain, dev,
+                                        liodn, liodn_cnt);
+       } else {
+               pr_debug("missing fsl,liodn property at %s\n",
+                         dev->of_node->full_name);
+                       ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+static void fsl_pamu_detach_device(struct iommu_domain *domain,
+                                     struct device *dev)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       const u32 *prop;
+       int len;
+       struct pci_dev *pdev = NULL;
+       struct pci_controller *pci_ctl;
+
+       /*
+        * Use LIODN of the PCI controller while detaching a
+        * PCI device.
+        */
+       if (dev->bus == &pci_bus_type) {
+               pdev = to_pci_dev(dev);
+               pci_ctl = pci_bus_to_host(pdev->bus);
+               /*
+                * make dev point to pci controller device
+                * so we can get the LIODN programmed by
+                * u-boot.
+                */
+               dev = pci_ctl->parent;
+       }
+
+       prop = of_get_property(dev->of_node, "fsl,liodn", &len);
+       if (prop)
+               detach_device(dev, dma_domain);
+       else
+               pr_debug("missing fsl,liodn property at %s\n",
+                         dev->of_node->full_name);
+}
+
+static  int configure_domain_geometry(struct iommu_domain *domain, void *data)
+{
+       struct iommu_domain_geometry *geom_attr = data;
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       dma_addr_t geom_size;
+       unsigned long flags;
+
+       geom_size = geom_attr->aperture_end - geom_attr->aperture_start + 1;
+       /*
+        * Sanity check the geometry size. Also, we do not support
+        * DMA outside of the geometry.
+        */
+       if (check_size(geom_size, geom_attr->aperture_start) ||
+               !geom_attr->force_aperture) {
+                       pr_debug("Invalid PAMU geometry attributes\n");
+                       return -EINVAL;
+               }
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+       if (dma_domain->enabled) {
+               pr_debug("Can't set geometry attributes as domain is active\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return  -EBUSY;
+       }
+
+       /* Copy the domain geometry information */
+       memcpy(&domain->geometry, geom_attr,
+              sizeof(struct iommu_domain_geometry));
+       dma_domain->geom_size = geom_size;
+
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+       return 0;
+}
+
+/* Set the domain stash attribute */
+static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data)
+{
+       struct pamu_stash_attribute *stash_attr = data;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+
+       memcpy(&dma_domain->dma_stash, stash_attr,
+                sizeof(struct pamu_stash_attribute));
+
+       dma_domain->stash_id = get_stash_id(stash_attr->cache,
+                                           stash_attr->cpu);
+       if (dma_domain->stash_id == ~(u32)0) {
+               pr_debug("Invalid stash attributes\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -EINVAL;
+       }
+
+       ret = update_domain_stash(dma_domain, dma_domain->stash_id);
+
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+       return ret;
+}
+
+/* Configure domain dma state i.e. enable/disable DMA*/
+static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool enable)
+{
+       struct device_domain_info *info;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+
+       if (enable && !dma_domain->mapped) {
+               pr_debug("Can't enable DMA domain without valid mapping\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -ENODEV;
+       }
+
+       dma_domain->enabled = enable;
+       list_for_each_entry(info, &dma_domain->devices,
+                                link) {
+               ret = (enable) ? pamu_enable_liodn(info->liodn) :
+                       pamu_disable_liodn(info->liodn);
+               if (ret)
+                       pr_debug("Unable to set dma state for liodn %d",
+                                info->liodn);
+       }
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+       return 0;
+}
+
+static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
+                                enum iommu_attr attr_type, void *data)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       int ret = 0;
+
+
+       switch (attr_type) {
+       case DOMAIN_ATTR_GEOMETRY:
+               ret = configure_domain_geometry(domain, data);
+               break;
+       case DOMAIN_ATTR_FSL_PAMU_STASH:
+               ret = configure_domain_stash(dma_domain, data);
+               break;
+       case DOMAIN_ATTR_FSL_PAMU_ENABLE:
+               ret = configure_domain_dma_state(dma_domain, *(int *)data);
+               break;
+       default:
+               pr_debug("Unsupported attribute type\n");
+               ret = -EINVAL;
+               break;
+       };
+
+       return ret;
+}
+
+static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
+                                enum iommu_attr attr_type, void *data)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       int ret = 0;
+
+
+       switch (attr_type) {
+       case DOMAIN_ATTR_FSL_PAMU_STASH:
+               memcpy((struct pamu_stash_attribute *) data, &dma_domain->dma_stash,
+                                sizeof(struct pamu_stash_attribute));
+               break;
+       case DOMAIN_ATTR_FSL_PAMU_ENABLE:
+               *(int *)data = dma_domain->enabled;
+               break;
+       case DOMAIN_ATTR_FSL_PAMUV1:
+               *(int *)data = DOMAIN_ATTR_FSL_PAMUV1;
+               break;
+       default:
+               pr_debug("Unsupported attribute type\n");
+               ret = -EINVAL;
+               break;
+       };
+
+       return ret;
+}
+
+#define REQ_ACS_FLAGS  (PCI_ACS_SV | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF)
+
+static struct iommu_group *get_device_iommu_group(struct device *dev)
+{
+       struct iommu_group *group;
+
+       group = iommu_group_get(dev);
+       if (!group)
+               group = iommu_group_alloc();
+
+       return group;
+}
+
+static  bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl)
+{
+       u32 version;
+
+       /* Check the PCI controller version number by readding BRR1 register */
+       version = in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2));
+       version &= PCI_FSL_BRR1_VER;
+       /* If PCI controller version is >= 0x204 we can partition endpoints*/
+       if (version >= 0x204)
+               return 1;
+
+       return 0;
+}
+
+/* Get iommu group information from peer devices or devices on the parent bus */
+static struct iommu_group *get_shared_pci_device_group(struct pci_dev *pdev)
+{
+       struct pci_dev *tmp;
+       struct iommu_group *group;
+       struct pci_bus *bus = pdev->bus;
+
+       /*
+        * Traverese the pci bus device list to get
+        * the shared iommu group.
+        */
+       while (bus) {
+               list_for_each_entry(tmp, &bus->devices, bus_list) {
+                       if (tmp == pdev)
+                               continue;
+                       group = iommu_group_get(&tmp->dev);
+                       if (group)
+                               return group;
+               }
+
+               bus = bus->parent;
+       }
+
+       return NULL;
+}
+
+static struct iommu_group *get_pci_device_group(struct pci_dev *pdev)
+{
+       struct pci_controller *pci_ctl;
+       bool pci_endpt_partioning;
+       struct iommu_group *group = NULL;
+       struct pci_dev *bridge, *dma_pdev = NULL;
+
+       pci_ctl = pci_bus_to_host(pdev->bus);
+       pci_endpt_partioning = check_pci_ctl_endpt_part(pci_ctl);
+       /* We can partition PCIe devices so assign device group to the device */
+       if (pci_endpt_partioning) {
+               bridge = pci_find_upstream_pcie_bridge(pdev);
+               if (bridge) {
+                       if (pci_is_pcie(bridge))
+                               dma_pdev = pci_get_domain_bus_and_slot(
+                                               pci_domain_nr(pdev->bus),
+                                               bridge->subordinate->number, 0);
+                       if (!dma_pdev)
+                               dma_pdev = pci_dev_get(bridge);
+               } else
+                       dma_pdev = pci_dev_get(pdev);
+
+               /* Account for quirked devices */
+               swap_pci_ref(&dma_pdev, pci_get_dma_source(dma_pdev));
+
+               /*
+                * If it's a multifunction device that does not support our
+                * required ACS flags, add to the same group as lowest numbered
+                * function that also does not suport the required ACS flags.
+                */
+               if (dma_pdev->multifunction &&
+                   !pci_acs_enabled(dma_pdev, REQ_ACS_FLAGS)) {
+                       u8 i, slot = PCI_SLOT(dma_pdev->devfn);
+
+                       for (i = 0; i < 8; i++) {
+                               struct pci_dev *tmp;
+
+                               tmp = pci_get_slot(dma_pdev->bus, PCI_DEVFN(slot, i));
+                               if (!tmp)
+                                       continue;
+
+                               if (!pci_acs_enabled(tmp, REQ_ACS_FLAGS)) {
+                                       swap_pci_ref(&dma_pdev, tmp);
+                                       break;
+                               }
+                               pci_dev_put(tmp);
+                       }
+               }
+
+               /*
+                * Devices on the root bus go through the iommu.  If that's not us,
+                * find the next upstream device and test ACS up to the root bus.
+                * Finding the next device may require skipping virtual buses.
+                */
+               while (!pci_is_root_bus(dma_pdev->bus)) {
+                       struct pci_bus *bus = dma_pdev->bus;
+
+                       while (!bus->self) {
+                               if (!pci_is_root_bus(bus))
+                                       bus = bus->parent;
+                               else
+                                       goto root_bus;
+                       }
+
+                       if (pci_acs_path_enabled(bus->self, NULL, REQ_ACS_FLAGS))
+                               break;
+
+                       swap_pci_ref(&dma_pdev, pci_dev_get(bus->self));
+               }
+
+root_bus:
+               group = get_device_iommu_group(&dma_pdev->dev);
+               pci_dev_put(dma_pdev);
+               /*
+                * PCIe controller is not a paritionable entity
+                * free the controller device iommu_group.
+                */
+               if (pci_ctl->parent->iommu_group)
+                       iommu_group_remove_device(pci_ctl->parent);
+       } else {
+               /*
+                * All devices connected to the controller will share the
+                * PCI controllers device group. If this is the first
+                * device to be probed for the pci controller, copy the
+                * device group information from the PCI controller device
+                * node and remove the PCI controller iommu group.
+                * For subsequent devices, the iommu group information can
+                * be obtained from sibling devices (i.e. from the bus_devices
+                * link list).
+                */
+               if (pci_ctl->parent->iommu_group) {
+                       group = get_device_iommu_group(pci_ctl->parent);
+                       iommu_group_remove_device(pci_ctl->parent);
+               } else
+                       group = get_shared_pci_device_group(pdev);
+       }
+
+       return group;
+}
+
+static int fsl_pamu_add_device(struct device *dev)
+{
+       struct iommu_group *group = NULL;
+       struct pci_dev *pdev;
+       const u32 *prop;
+       int ret, len;
+
+       /*
+        * For platform devices we allocate a separate group for
+        * each of the devices.
+        */
+       if (dev->bus == &pci_bus_type) {
+               pdev = to_pci_dev(dev);
+               /* Don't create device groups for virtual PCI bridges */
+               if (pdev->subordinate)
+                       return 0;
+
+               group = get_pci_device_group(pdev);
+
+       } else {
+               prop = of_get_property(dev->of_node, "fsl,liodn", &len);
+               if (prop)
+                       group = get_device_iommu_group(dev);
+       }
+
+       if (!group || IS_ERR(group))
+               return PTR_ERR(group);
+
+       ret = iommu_group_add_device(group, dev);
+
+       iommu_group_put(group);
+       return ret;
+}
+
+static void fsl_pamu_remove_device(struct device *dev)
+{
+       iommu_group_remove_device(dev);
+}
+
+static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&dma_domain->domain_lock, flags);
+       /* Ensure domain is inactive i.e. DMA should be disabled for the domain */
+       if (dma_domain->enabled) {
+               pr_debug("Can't set geometry attributes as domain is active\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return  -EBUSY;
+       }
+
+       /* Ensure that the geometry has been set for the domain */
+       if (!dma_domain->geom_size) {
+               pr_debug("Please configure geometry before setting the number of windows\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -EINVAL;
+       }
+
+       /*
+        * Ensure we have valid window count i.e. it should be less than
+        * maximum permissible limit and should be a power of two.
+        */
+       if (w_count > pamu_get_max_subwin_cnt() || !is_power_of_2(w_count)) {
+               pr_debug("Invalid window count\n");
+               spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+               return -EINVAL;
+       }
+
+       ret = pamu_set_domain_geometry(dma_domain, &domain->geometry,
+                               ((w_count > 1) ? w_count : 0));
+       if (!ret) {
+               if (dma_domain->win_arr)
+                       kfree(dma_domain->win_arr);
+               dma_domain->win_arr = kzalloc(sizeof(struct dma_window) *
+                                                         w_count, GFP_ATOMIC);
+               if (!dma_domain->win_arr) {
+                       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+                       return -ENOMEM;
+               }
+               dma_domain->win_cnt = w_count;
+       }
+       spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
+
+       return ret;
+}
+
+static u32 fsl_pamu_get_windows(struct iommu_domain *domain)
+{
+       struct fsl_dma_domain *dma_domain = domain->priv;
+
+       return dma_domain->win_cnt;
+}
+
+static struct iommu_ops fsl_pamu_ops = {
+       .domain_init    = fsl_pamu_domain_init,
+       .domain_destroy = fsl_pamu_domain_destroy,
+       .attach_dev     = fsl_pamu_attach_device,
+       .detach_dev     = fsl_pamu_detach_device,
+       .domain_window_enable = fsl_pamu_window_enable,
+       .domain_window_disable = fsl_pamu_window_disable,
+       .domain_get_windows = fsl_pamu_get_windows,
+       .domain_set_windows = fsl_pamu_set_windows,
+       .iova_to_phys   = fsl_pamu_iova_to_phys,
+       .domain_has_cap = fsl_pamu_domain_has_cap,
+       .domain_set_attr = fsl_pamu_set_domain_attr,
+       .domain_get_attr = fsl_pamu_get_domain_attr,
+       .add_device     = fsl_pamu_add_device,
+       .remove_device  = fsl_pamu_remove_device,
+};
+
+int pamu_domain_init()
+{
+       int ret = 0;
+
+       ret = iommu_init_mempool();
+       if (ret)
+               return ret;
+
+       bus_set_iommu(&platform_bus_type, &fsl_pamu_ops);
+       bus_set_iommu(&pci_bus_type, &fsl_pamu_ops);
+
+       return ret;
+}
diff --git a/drivers/iommu/fsl_pamu_domain.h b/drivers/iommu/fsl_pamu_domain.h
new file mode 100644 (file)
index 0000000..c90293f
--- /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 (C) 2013 Freescale Semiconductor, Inc.
+ *
+ */
+
+#ifndef __FSL_PAMU_DOMAIN_H
+#define __FSL_PAMU_DOMAIN_H
+
+#include "fsl_pamu.h"
+
+struct dma_window {
+       phys_addr_t paddr;
+       u64 size;
+       int valid;
+       int prot;
+};
+
+struct fsl_dma_domain {
+       /*
+        * Indicates the geometry size for the domain.
+        * This would be set when the geometry is
+        * configured for the domain.
+        */
+       dma_addr_t                      geom_size;
+       /*
+        * Number of windows assocaited with this domain.
+        * During domain initialization, it is set to the
+        * the maximum number of subwindows allowed for a LIODN.
+        * Minimum value for this is 1 indicating a single PAMU
+        * window, without any sub windows. Value can be set/
+        * queried by set_attr/get_attr API for DOMAIN_ATTR_WINDOWS.
+        * Value can only be set once the geometry has been configured.
+        */
+       u32                             win_cnt;
+       /*
+        * win_arr contains information of the configured
+        * windows for a domain. This is allocated only
+        * when the number of windows for the domain are
+        * set.
+        */
+       struct dma_window               *win_arr;
+       /* list of devices associated with the domain */
+       struct list_head                devices;
+       /* dma_domain states:
+        * mapped - A particular mapping has been created
+        * within the configured geometry.
+        * enabled - DMA has been enabled for the given
+        * domain. This translates to setting of the
+        * valid bit for the primary PAACE in the PAMU
+        * PAACT table. Domain geometry should be set and
+        * it must have a valid mapping before DMA can be
+        * enabled for it.
+        *
+        */
+       int                             mapped;
+       int                             enabled;
+       /* stash_id obtained from the stash attribute details */
+       u32                             stash_id;
+       struct pamu_stash_attribute     dma_stash;
+       u32                             snoop_id;
+       struct iommu_domain             *iommu_domain;
+       spinlock_t                      domain_lock;
+};
+
+/* domain-device relationship */
+struct device_domain_info {
+       struct list_head link;  /* link to domain siblings */
+       struct device *dev;
+       u32 liodn;
+       struct fsl_dma_domain *domain; /* pointer to domain */
+};
+#endif  /* __FSL_PAMU_DOMAIN_H */
index eec0d3e04bf578ab6a6afe36e1c55ad5d4b0c969..15e9b57e9cf05ba43e19d76f37e64275d3e6db44 100644 (file)
@@ -890,56 +890,54 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
        return order;
 }
 
+static void dma_pte_free_level(struct dmar_domain *domain, int level,
+                              struct dma_pte *pte, unsigned long pfn,
+                              unsigned long start_pfn, unsigned long last_pfn)
+{
+       pfn = max(start_pfn, pfn);
+       pte = &pte[pfn_level_offset(pfn, level)];
+
+       do {
+               unsigned long level_pfn;
+               struct dma_pte *level_pte;
+
+               if (!dma_pte_present(pte) || dma_pte_superpage(pte))
+                       goto next;
+
+               level_pfn = pfn & level_mask(level - 1);
+               level_pte = phys_to_virt(dma_pte_addr(pte));
+
+               if (level > 2)
+                       dma_pte_free_level(domain, level - 1, level_pte,
+                                          level_pfn, start_pfn, last_pfn);
+
+               /* If range covers entire pagetable, free it */
+               if (!(start_pfn > level_pfn ||
+                     last_pfn < level_pfn + level_size(level))) {
+                       dma_clear_pte(pte);
+                       domain_flush_cache(domain, pte, sizeof(*pte));
+                       free_pgtable_page(level_pte);
+               }
+next:
+               pfn += level_size(level);
+       } while (!first_pte_in_page(++pte) && pfn <= last_pfn);
+}
+
 /* free page table pages. last level pte should already be cleared */
 static void dma_pte_free_pagetable(struct dmar_domain *domain,
                                   unsigned long start_pfn,
                                   unsigned long last_pfn)
 {
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
-       struct dma_pte *first_pte, *pte;
-       int total = agaw_to_level(domain->agaw);
-       int level;
-       unsigned long tmp;
-       int large_page = 2;
 
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
        BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
        BUG_ON(start_pfn > last_pfn);
 
        /* We don't need lock here; nobody else touches the iova range */
-       level = 2;
-       while (level <= total) {
-               tmp = align_to_level(start_pfn, level);
-
-               /* If we can't even clear one PTE at this level, we're done */
-               if (tmp + level_size(level) - 1 > last_pfn)
-                       return;
-
-               do {
-                       large_page = level;
-                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
-                       if (large_page > level)
-                               level = large_page + 1;
-                       if (!pte) {
-                               tmp = align_to_level(tmp + 1, level + 1);
-                               continue;
-                       }
-                       do {
-                               if (dma_pte_present(pte)) {
-                                       free_pgtable_page(phys_to_virt(dma_pte_addr(pte)));
-                                       dma_clear_pte(pte);
-                               }
-                               pte++;
-                               tmp += level_size(level);
-                       } while (!first_pte_in_page(pte) &&
-                                tmp + level_size(level) - 1 <= last_pfn);
+       dma_pte_free_level(domain, agaw_to_level(domain->agaw),
+                          domain->pgd, 0, start_pfn, last_pfn);
 
-                       domain_flush_cache(domain, first_pte,
-                                          (void *)pte - (void *)first_pte);
-                       
-               } while (tmp && tmp + level_size(level) - 1 <= last_pfn);
-               level++;
-       }
        /* free pgd */
        if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
                free_pgtable_page(domain->pgd);
index 0a1c9626aa9ebd4ff1b569ebb9f87d84ec01536d..08ba4972da9d2543a8ec9ad9f312451647bcd1e9 100644 (file)
@@ -282,7 +282,6 @@ static int msm_iommu_remove(struct platform_device *pdev)
                clk_put(drv->pclk);
                memset(drv, 0, sizeof(*drv));
                kfree(drv);
-               platform_set_drvdata(pdev, NULL);
        }
        return 0;
 }
@@ -366,7 +365,6 @@ static int msm_iommu_ctx_remove(struct platform_device *pdev)
        if (drv) {
                memset(drv, 0, sizeof(struct msm_iommu_ctx_drvdata));
                kfree(drv);
-               platform_set_drvdata(pdev, NULL);
        }
        return 0;
 }
index 0ba3766240d5b7e37ae3f52ed8fb72a8196865cf..bcd78a720630782313f413d0db8a99adbd7e77da 100644 (file)
@@ -1008,8 +1008,6 @@ static int omap_iommu_remove(struct platform_device *pdev)
        struct resource *res;
        struct omap_iommu *obj = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        iopgtable_clear_entry_all(obj);
 
        irq = platform_get_irq(pdev, 0);
index 1fea003ed33f63c6cef961cbc1629dd71d3656ea..3792a1aa52b88d3439cdc66195230cc1b20f0f2a 100644 (file)
@@ -30,6 +30,11 @@ config ARM_VIC_NR
          The maximum number of VICs available in the system, for
          power management.
 
+config IMGPDC_IRQ
+       bool
+       select GENERIC_IRQ_CHIP
+       select IRQ_DOMAIN
+
 config ORION_IRQCHIP
        bool
        select IRQ_DOMAIN
index e65c41a7366bf1f6887ab5a5315622f1e1341478..c60b9010b152cf4980336eac485daa8bceec9412 100644 (file)
@@ -2,6 +2,7 @@ obj-$(CONFIG_IRQCHIP)                   += irqchip.o
 
 obj-$(CONFIG_ARCH_BCM2835)             += irq-bcm2835.o
 obj-$(CONFIG_ARCH_EXYNOS)              += exynos-combiner.o
+obj-$(CONFIG_ARCH_MMP)                 += irq-mmp.o
 obj-$(CONFIG_ARCH_MVEBU)               += irq-armada-370-xp.o
 obj-$(CONFIG_ARCH_MXS)                 += irq-mxs.o
 obj-$(CONFIG_ARCH_S3C24XX)             += irq-s3c24xx.o
@@ -14,6 +15,7 @@ obj-$(CONFIG_ARCH_SPEAR3XX)           += spear-shirq.o
 obj-$(CONFIG_ARM_GIC)                  += irq-gic.o
 obj-$(CONFIG_ARM_NVIC)                 += irq-nvic.o
 obj-$(CONFIG_ARM_VIC)                  += irq-vic.o
+obj-$(CONFIG_IMGPDC_IRQ)               += irq-imgpdc.o
 obj-$(CONFIG_SIRF_IRQ)                 += irq-sirfsoc.o
 obj-$(CONFIG_RENESAS_INTC_IRQPIN)      += irq-renesas-intc-irqpin.o
 obj-$(CONFIG_RENESAS_IRQC)             += irq-renesas-irqc.o
index ee7c50312066cc4b750ee592fdd2956809eeebd8..d0e948084eaf7e2211c323f5976ecc08e5681136 100644 (file)
@@ -453,6 +453,12 @@ static void gic_cpu_init(struct gic_chip_data *gic)
        writel_relaxed(1, base + GIC_CPU_CTRL);
 }
 
+void gic_cpu_if_down(void)
+{
+       void __iomem *cpu_base = gic_data_cpu_base(&gic_data[0]);
+       writel_relaxed(0, cpu_base + GIC_CPU_CTRL);
+}
+
 #ifdef CONFIG_CPU_PM
 /*
  * Saves the GIC distributor registers during suspend or idle.  Must be called
diff --git a/drivers/irqchip/irq-imgpdc.c b/drivers/irqchip/irq-imgpdc.c
new file mode 100644 (file)
index 0000000..8071c2e
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * IMG PowerDown Controller (PDC)
+ *
+ * Copyright 2010-2013 Imagination Technologies Ltd.
+ *
+ * Exposes the syswake and PDC peripheral wake interrupts to the system.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+/* PDC interrupt register numbers */
+
+#define PDC_IRQ_STATUS                 0x310
+#define PDC_IRQ_ENABLE                 0x314
+#define PDC_IRQ_CLEAR                  0x318
+#define PDC_IRQ_ROUTE                  0x31c
+#define PDC_SYS_WAKE_BASE              0x330
+#define PDC_SYS_WAKE_STRIDE            0x8
+#define PDC_SYS_WAKE_CONFIG_BASE       0x334
+#define PDC_SYS_WAKE_CONFIG_STRIDE     0x8
+
+/* PDC interrupt register field masks */
+
+#define PDC_IRQ_SYS3                   0x08
+#define PDC_IRQ_SYS2                   0x04
+#define PDC_IRQ_SYS1                   0x02
+#define PDC_IRQ_SYS0                   0x01
+#define PDC_IRQ_ROUTE_WU_EN_SYS3       0x08000000
+#define PDC_IRQ_ROUTE_WU_EN_SYS2       0x04000000
+#define PDC_IRQ_ROUTE_WU_EN_SYS1       0x02000000
+#define PDC_IRQ_ROUTE_WU_EN_SYS0       0x01000000
+#define PDC_IRQ_ROUTE_WU_EN_WD         0x00040000
+#define PDC_IRQ_ROUTE_WU_EN_IR         0x00020000
+#define PDC_IRQ_ROUTE_WU_EN_RTC                0x00010000
+#define PDC_IRQ_ROUTE_EXT_EN_SYS3      0x00000800
+#define PDC_IRQ_ROUTE_EXT_EN_SYS2      0x00000400
+#define PDC_IRQ_ROUTE_EXT_EN_SYS1      0x00000200
+#define PDC_IRQ_ROUTE_EXT_EN_SYS0      0x00000100
+#define PDC_IRQ_ROUTE_EXT_EN_WD                0x00000004
+#define PDC_IRQ_ROUTE_EXT_EN_IR                0x00000002
+#define PDC_IRQ_ROUTE_EXT_EN_RTC       0x00000001
+#define PDC_SYS_WAKE_RESET             0x00000010
+#define PDC_SYS_WAKE_INT_MODE          0x0000000e
+#define PDC_SYS_WAKE_INT_MODE_SHIFT    1
+#define PDC_SYS_WAKE_PIN_VAL           0x00000001
+
+/* PDC interrupt constants */
+
+#define PDC_SYS_WAKE_INT_LOW           0x0
+#define PDC_SYS_WAKE_INT_HIGH          0x1
+#define PDC_SYS_WAKE_INT_DOWN          0x2
+#define PDC_SYS_WAKE_INT_UP            0x3
+#define PDC_SYS_WAKE_INT_CHANGE                0x6
+#define PDC_SYS_WAKE_INT_NONE          0x4
+
+/**
+ * struct pdc_intc_priv - private pdc interrupt data.
+ * @nr_perips:         Number of peripheral interrupt signals.
+ * @nr_syswakes:       Number of syswake signals.
+ * @perip_irqs:                List of peripheral IRQ numbers handled.
+ * @syswake_irq:       Shared PDC syswake IRQ number.
+ * @domain:            IRQ domain for PDC peripheral and syswake IRQs.
+ * @pdc_base:          Base of PDC registers.
+ * @irq_route:         Cached version of PDC_IRQ_ROUTE register.
+ * @lock:              Lock to protect the PDC syswake registers and the cached
+ *                     values of those registers in this struct.
+ */
+struct pdc_intc_priv {
+       unsigned int            nr_perips;
+       unsigned int            nr_syswakes;
+       unsigned int            *perip_irqs;
+       unsigned int            syswake_irq;
+       struct irq_domain       *domain;
+       void __iomem            *pdc_base;
+
+       u32                     irq_route;
+       raw_spinlock_t          lock;
+};
+
+static void pdc_write(struct pdc_intc_priv *priv, unsigned int reg_offs,
+                     unsigned int data)
+{
+       iowrite32(data, priv->pdc_base + reg_offs);
+}
+
+static unsigned int pdc_read(struct pdc_intc_priv *priv,
+                            unsigned int reg_offs)
+{
+       return ioread32(priv->pdc_base + reg_offs);
+}
+
+/* Generic IRQ callbacks */
+
+#define SYS0_HWIRQ     8
+
+static unsigned int hwirq_is_syswake(irq_hw_number_t hw)
+{
+       return hw >= SYS0_HWIRQ;
+}
+
+static unsigned int hwirq_to_syswake(irq_hw_number_t hw)
+{
+       return hw - SYS0_HWIRQ;
+}
+
+static irq_hw_number_t syswake_to_hwirq(unsigned int syswake)
+{
+       return SYS0_HWIRQ + syswake;
+}
+
+static struct pdc_intc_priv *irqd_to_priv(struct irq_data *data)
+{
+       return (struct pdc_intc_priv *)data->domain->host_data;
+}
+
+/*
+ * perip_irq_mask() and perip_irq_unmask() use IRQ_ROUTE which also contains
+ * wake bits, therefore we cannot use the generic irqchip mask callbacks as they
+ * cache the mask.
+ */
+
+static void perip_irq_mask(struct irq_data *data)
+{
+       struct pdc_intc_priv *priv = irqd_to_priv(data);
+
+       raw_spin_lock(&priv->lock);
+       priv->irq_route &= ~data->mask;
+       pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
+       raw_spin_unlock(&priv->lock);
+}
+
+static void perip_irq_unmask(struct irq_data *data)
+{
+       struct pdc_intc_priv *priv = irqd_to_priv(data);
+
+       raw_spin_lock(&priv->lock);
+       priv->irq_route |= data->mask;
+       pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
+       raw_spin_unlock(&priv->lock);
+}
+
+static int syswake_irq_set_type(struct irq_data *data, unsigned int flow_type)
+{
+       struct pdc_intc_priv *priv = irqd_to_priv(data);
+       unsigned int syswake = hwirq_to_syswake(data->hwirq);
+       unsigned int irq_mode;
+       unsigned int soc_sys_wake_regoff, soc_sys_wake;
+
+       /* translate to syswake IRQ mode */
+       switch (flow_type) {
+       case IRQ_TYPE_EDGE_BOTH:
+               irq_mode = PDC_SYS_WAKE_INT_CHANGE;
+               break;
+       case IRQ_TYPE_EDGE_RISING:
+               irq_mode = PDC_SYS_WAKE_INT_UP;
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               irq_mode = PDC_SYS_WAKE_INT_DOWN;
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
+               irq_mode = PDC_SYS_WAKE_INT_HIGH;
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
+               irq_mode = PDC_SYS_WAKE_INT_LOW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       raw_spin_lock(&priv->lock);
+
+       /* set the IRQ mode */
+       soc_sys_wake_regoff = PDC_SYS_WAKE_BASE + syswake*PDC_SYS_WAKE_STRIDE;
+       soc_sys_wake = pdc_read(priv, soc_sys_wake_regoff);
+       soc_sys_wake &= ~PDC_SYS_WAKE_INT_MODE;
+       soc_sys_wake |= irq_mode << PDC_SYS_WAKE_INT_MODE_SHIFT;
+       pdc_write(priv, soc_sys_wake_regoff, soc_sys_wake);
+
+       /* and update the handler */
+       irq_setup_alt_chip(data, flow_type);
+
+       raw_spin_unlock(&priv->lock);
+
+       return 0;
+}
+
+/* applies to both peripheral and syswake interrupts */
+static int pdc_irq_set_wake(struct irq_data *data, unsigned int on)
+{
+       struct pdc_intc_priv *priv = irqd_to_priv(data);
+       irq_hw_number_t hw = data->hwirq;
+       unsigned int mask = (1 << 16) << hw;
+       unsigned int dst_irq;
+
+       raw_spin_lock(&priv->lock);
+       if (on)
+               priv->irq_route |= mask;
+       else
+               priv->irq_route &= ~mask;
+       pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
+       raw_spin_unlock(&priv->lock);
+
+       /* control the destination IRQ wakeup too for standby mode */
+       if (hwirq_is_syswake(hw))
+               dst_irq = priv->syswake_irq;
+       else
+               dst_irq = priv->perip_irqs[hw];
+       irq_set_irq_wake(dst_irq, on);
+
+       return 0;
+}
+
+static void pdc_intc_perip_isr(unsigned int irq, struct irq_desc *desc)
+{
+       struct pdc_intc_priv *priv;
+       unsigned int i, irq_no;
+
+       priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
+
+       /* find the peripheral number */
+       for (i = 0; i < priv->nr_perips; ++i)
+               if (irq == priv->perip_irqs[i])
+                       goto found;
+
+       /* should never get here */
+       return;
+found:
+
+       /* pass on the interrupt */
+       irq_no = irq_linear_revmap(priv->domain, i);
+       generic_handle_irq(irq_no);
+}
+
+static void pdc_intc_syswake_isr(unsigned int irq, struct irq_desc *desc)
+{
+       struct pdc_intc_priv *priv;
+       unsigned int syswake, irq_no;
+       unsigned int status;
+
+       priv = (struct pdc_intc_priv *)irq_desc_get_handler_data(desc);
+
+       status = pdc_read(priv, PDC_IRQ_STATUS) &
+                pdc_read(priv, PDC_IRQ_ENABLE);
+       status &= (1 << priv->nr_syswakes) - 1;
+
+       for (syswake = 0; status; status >>= 1, ++syswake) {
+               /* Has this sys_wake triggered? */
+               if (!(status & 1))
+                       continue;
+
+               irq_no = irq_linear_revmap(priv->domain,
+                                          syswake_to_hwirq(syswake));
+               generic_handle_irq(irq_no);
+       }
+}
+
+static void pdc_intc_setup(struct pdc_intc_priv *priv)
+{
+       int i;
+       unsigned int soc_sys_wake_regoff;
+       unsigned int soc_sys_wake;
+
+       /*
+        * Mask all syswake interrupts before routing, or we could receive an
+        * interrupt before we're ready to handle it.
+        */
+       pdc_write(priv, PDC_IRQ_ENABLE, 0);
+
+       /*
+        * Enable routing of all syswakes
+        * Disable all wake sources
+        */
+       priv->irq_route = ((PDC_IRQ_ROUTE_EXT_EN_SYS0 << priv->nr_syswakes) -
+                               PDC_IRQ_ROUTE_EXT_EN_SYS0);
+       pdc_write(priv, PDC_IRQ_ROUTE, priv->irq_route);
+
+       /* Initialise syswake IRQ */
+       for (i = 0; i < priv->nr_syswakes; ++i) {
+               /* set the IRQ mode to none */
+               soc_sys_wake_regoff = PDC_SYS_WAKE_BASE + i*PDC_SYS_WAKE_STRIDE;
+               soc_sys_wake = PDC_SYS_WAKE_INT_NONE
+                               << PDC_SYS_WAKE_INT_MODE_SHIFT;
+               pdc_write(priv, soc_sys_wake_regoff, soc_sys_wake);
+       }
+}
+
+static int pdc_intc_probe(struct platform_device *pdev)
+{
+       struct pdc_intc_priv *priv;
+       struct device_node *node = pdev->dev.of_node;
+       struct resource *res_regs;
+       struct irq_chip_generic *gc;
+       unsigned int i;
+       int irq, ret;
+       u32 val;
+
+       if (!node)
+               return -ENOENT;
+
+       /* Get registers */
+       res_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res_regs == NULL) {
+               dev_err(&pdev->dev, "cannot find registers resource\n");
+               return -ENOENT;
+       }
+
+       /* Allocate driver data */
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               dev_err(&pdev->dev, "cannot allocate device data\n");
+               return -ENOMEM;
+       }
+       raw_spin_lock_init(&priv->lock);
+       platform_set_drvdata(pdev, priv);
+
+       /* Ioremap the registers */
+       priv->pdc_base = devm_ioremap(&pdev->dev, res_regs->start,
+                                     res_regs->end - res_regs->start);
+       if (!priv->pdc_base)
+               return -EIO;
+
+       /* Get number of peripherals */
+       ret = of_property_read_u32(node, "num-perips", &val);
+       if (ret) {
+               dev_err(&pdev->dev, "No num-perips node property found\n");
+               return -EINVAL;
+       }
+       if (val > SYS0_HWIRQ) {
+               dev_err(&pdev->dev, "num-perips (%u) out of range\n", val);
+               return -EINVAL;
+       }
+       priv->nr_perips = val;
+
+       /* Get number of syswakes */
+       ret = of_property_read_u32(node, "num-syswakes", &val);
+       if (ret) {
+               dev_err(&pdev->dev, "No num-syswakes node property found\n");
+               return -EINVAL;
+       }
+       if (val > SYS0_HWIRQ) {
+               dev_err(&pdev->dev, "num-syswakes (%u) out of range\n", val);
+               return -EINVAL;
+       }
+       priv->nr_syswakes = val;
+
+       /* Get peripheral IRQ numbers */
+       priv->perip_irqs = devm_kzalloc(&pdev->dev, 4 * priv->nr_perips,
+                                       GFP_KERNEL);
+       if (!priv->perip_irqs) {
+               dev_err(&pdev->dev, "cannot allocate perip IRQ list\n");
+               return -ENOMEM;
+       }
+       for (i = 0; i < priv->nr_perips; ++i) {
+               irq = platform_get_irq(pdev, 1 + i);
+               if (irq < 0) {
+                       dev_err(&pdev->dev, "cannot find perip IRQ #%u\n", i);
+                       return irq;
+               }
+               priv->perip_irqs[i] = irq;
+       }
+       /* check if too many were provided */
+       if (platform_get_irq(pdev, 1 + i) >= 0) {
+               dev_err(&pdev->dev, "surplus perip IRQs detected\n");
+               return -EINVAL;
+       }
+
+       /* Get syswake IRQ number */
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "cannot find syswake IRQ\n");
+               return irq;
+       }
+       priv->syswake_irq = irq;
+
+       /* Set up an IRQ domain */
+       priv->domain = irq_domain_add_linear(node, 16, &irq_generic_chip_ops,
+                                            priv);
+       if (unlikely(!priv->domain)) {
+               dev_err(&pdev->dev, "cannot add IRQ domain\n");
+               return -ENOMEM;
+       }
+
+       /*
+        * Set up 2 generic irq chips with 2 chip types.
+        * The first one for peripheral irqs (only 1 chip type used)
+        * The second one for syswake irqs (edge and level chip types)
+        */
+       ret = irq_alloc_domain_generic_chips(priv->domain, 8, 2, "pdc",
+                                            handle_level_irq, 0, 0,
+                                            IRQ_GC_INIT_NESTED_LOCK);
+       if (ret)
+               goto err_generic;
+
+       /* peripheral interrupt chip */
+
+       gc = irq_get_domain_generic_chip(priv->domain, 0);
+       gc->unused      = ~(BIT(priv->nr_perips) - 1);
+       gc->reg_base    = priv->pdc_base;
+       /*
+        * IRQ_ROUTE contains wake bits, so we can't use the generic versions as
+        * they cache the mask
+        */
+       gc->chip_types[0].regs.mask             = PDC_IRQ_ROUTE;
+       gc->chip_types[0].chip.irq_mask         = perip_irq_mask;
+       gc->chip_types[0].chip.irq_unmask       = perip_irq_unmask;
+       gc->chip_types[0].chip.irq_set_wake     = pdc_irq_set_wake;
+
+       /* syswake interrupt chip */
+
+       gc = irq_get_domain_generic_chip(priv->domain, 8);
+       gc->unused      = ~(BIT(priv->nr_syswakes) - 1);
+       gc->reg_base    = priv->pdc_base;
+
+       /* edge interrupts */
+       gc->chip_types[0].type                  = IRQ_TYPE_EDGE_BOTH;
+       gc->chip_types[0].handler               = handle_edge_irq;
+       gc->chip_types[0].regs.ack              = PDC_IRQ_CLEAR;
+       gc->chip_types[0].regs.mask             = PDC_IRQ_ENABLE;
+       gc->chip_types[0].chip.irq_ack          = irq_gc_ack_set_bit;
+       gc->chip_types[0].chip.irq_mask         = irq_gc_mask_clr_bit;
+       gc->chip_types[0].chip.irq_unmask       = irq_gc_mask_set_bit;
+       gc->chip_types[0].chip.irq_set_type     = syswake_irq_set_type;
+       gc->chip_types[0].chip.irq_set_wake     = pdc_irq_set_wake;
+       /* for standby we pass on to the shared syswake IRQ */
+       gc->chip_types[0].chip.flags            = IRQCHIP_MASK_ON_SUSPEND;
+
+       /* level interrupts */
+       gc->chip_types[1].type                  = IRQ_TYPE_LEVEL_MASK;
+       gc->chip_types[1].handler               = handle_level_irq;
+       gc->chip_types[1].regs.ack              = PDC_IRQ_CLEAR;
+       gc->chip_types[1].regs.mask             = PDC_IRQ_ENABLE;
+       gc->chip_types[1].chip.irq_ack          = irq_gc_ack_set_bit;
+       gc->chip_types[1].chip.irq_mask         = irq_gc_mask_clr_bit;
+       gc->chip_types[1].chip.irq_unmask       = irq_gc_mask_set_bit;
+       gc->chip_types[1].chip.irq_set_type     = syswake_irq_set_type;
+       gc->chip_types[1].chip.irq_set_wake     = pdc_irq_set_wake;
+       /* for standby we pass on to the shared syswake IRQ */
+       gc->chip_types[1].chip.flags            = IRQCHIP_MASK_ON_SUSPEND;
+
+       /* Set up the hardware to enable interrupt routing */
+       pdc_intc_setup(priv);
+
+       /* Setup chained handlers for the peripheral IRQs */
+       for (i = 0; i < priv->nr_perips; ++i) {
+               irq = priv->perip_irqs[i];
+               irq_set_handler_data(irq, priv);
+               irq_set_chained_handler(irq, pdc_intc_perip_isr);
+       }
+
+       /* Setup chained handler for the syswake IRQ */
+       irq_set_handler_data(priv->syswake_irq, priv);
+       irq_set_chained_handler(priv->syswake_irq, pdc_intc_syswake_isr);
+
+       dev_info(&pdev->dev,
+                "PDC IRQ controller initialised (%u perip IRQs, %u syswake IRQs)\n",
+                priv->nr_perips,
+                priv->nr_syswakes);
+
+       return 0;
+err_generic:
+       irq_domain_remove(priv->domain);
+       return ret;
+}
+
+static int pdc_intc_remove(struct platform_device *pdev)
+{
+       struct pdc_intc_priv *priv = platform_get_drvdata(pdev);
+
+       irq_domain_remove(priv->domain);
+       return 0;
+}
+
+static const struct of_device_id pdc_intc_match[] = {
+       { .compatible = "img,pdc-intc" },
+       {}
+};
+
+static struct platform_driver pdc_intc_driver = {
+       .driver = {
+               .name           = "pdc-intc",
+               .of_match_table = pdc_intc_match,
+       },
+       .probe = pdc_intc_probe,
+       .remove = pdc_intc_remove,
+};
+
+static int __init pdc_intc_init(void)
+{
+       return platform_driver_register(&pdc_intc_driver);
+}
+core_initcall(pdc_intc_init);
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
new file mode 100644 (file)
index 0000000..2cb7cd0
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ *  linux/arch/arm/mach-mmp/irq.c
+ *
+ *  Generic IRQ handling, GPIO IRQ demultiplexing, etc.
+ *  Copyright (C) 2008 - 2012 Marvell Technology Group Ltd.
+ *
+ *  Author:    Bin Yang <bin.yang@marvell.com>
+ *              Haojian Zhuang <haojian.zhuang@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/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/exception.h>
+#include <asm/mach/irq.h>
+
+#include "irqchip.h"
+
+#define MAX_ICU_NR             16
+
+#define PJ1_INT_SEL            0x10c
+#define PJ4_INT_SEL            0x104
+
+/* bit fields in PJ1_INT_SEL and PJ4_INT_SEL */
+#define SEL_INT_PENDING                (1 << 6)
+#define SEL_INT_NUM_MASK       0x3f
+
+struct icu_chip_data {
+       int                     nr_irqs;
+       unsigned int            virq_base;
+       unsigned int            cascade_irq;
+       void __iomem            *reg_status;
+       void __iomem            *reg_mask;
+       unsigned int            conf_enable;
+       unsigned int            conf_disable;
+       unsigned int            conf_mask;
+       unsigned int            clr_mfp_irq_base;
+       unsigned int            clr_mfp_hwirq;
+       struct irq_domain       *domain;
+};
+
+struct mmp_intc_conf {
+       unsigned int    conf_enable;
+       unsigned int    conf_disable;
+       unsigned int    conf_mask;
+};
+
+static void __iomem *mmp_icu_base;
+static struct icu_chip_data icu_data[MAX_ICU_NR];
+static int max_icu_nr;
+
+extern void mmp2_clear_pmic_int(void);
+
+static void icu_mask_ack_irq(struct irq_data *d)
+{
+       struct irq_domain *domain = d->domain;
+       struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+       int hwirq;
+       u32 r;
+
+       hwirq = d->irq - data->virq_base;
+       if (data == &icu_data[0]) {
+               r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+               r &= ~data->conf_mask;
+               r |= data->conf_disable;
+               writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+       } else {
+#ifdef CONFIG_CPU_MMP2
+               if ((data->virq_base == data->clr_mfp_irq_base)
+                       && (hwirq == data->clr_mfp_hwirq))
+                       mmp2_clear_pmic_int();
+#endif
+               r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+               writel_relaxed(r, data->reg_mask);
+       }
+}
+
+static void icu_mask_irq(struct irq_data *d)
+{
+       struct irq_domain *domain = d->domain;
+       struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+       int hwirq;
+       u32 r;
+
+       hwirq = d->irq - data->virq_base;
+       if (data == &icu_data[0]) {
+               r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+               r &= ~data->conf_mask;
+               r |= data->conf_disable;
+               writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+       } else {
+               r = readl_relaxed(data->reg_mask) | (1 << hwirq);
+               writel_relaxed(r, data->reg_mask);
+       }
+}
+
+static void icu_unmask_irq(struct irq_data *d)
+{
+       struct irq_domain *domain = d->domain;
+       struct icu_chip_data *data = (struct icu_chip_data *)domain->host_data;
+       int hwirq;
+       u32 r;
+
+       hwirq = d->irq - data->virq_base;
+       if (data == &icu_data[0]) {
+               r = readl_relaxed(mmp_icu_base + (hwirq << 2));
+               r &= ~data->conf_mask;
+               r |= data->conf_enable;
+               writel_relaxed(r, mmp_icu_base + (hwirq << 2));
+       } else {
+               r = readl_relaxed(data->reg_mask) & ~(1 << hwirq);
+               writel_relaxed(r, data->reg_mask);
+       }
+}
+
+struct irq_chip icu_irq_chip = {
+       .name           = "icu_irq",
+       .irq_mask       = icu_mask_irq,
+       .irq_mask_ack   = icu_mask_ack_irq,
+       .irq_unmask     = icu_unmask_irq,
+};
+
+static void icu_mux_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_domain *domain;
+       struct icu_chip_data *data;
+       int i;
+       unsigned long mask, status, n;
+
+       for (i = 1; i < max_icu_nr; i++) {
+               if (irq == icu_data[i].cascade_irq) {
+                       domain = icu_data[i].domain;
+                       data = (struct icu_chip_data *)domain->host_data;
+                       break;
+               }
+       }
+       if (i >= max_icu_nr) {
+               pr_err("Spurious irq %d in MMP INTC\n", irq);
+               return;
+       }
+
+       mask = readl_relaxed(data->reg_mask);
+       while (1) {
+               status = readl_relaxed(data->reg_status) & ~mask;
+               if (status == 0)
+                       break;
+               for_each_set_bit(n, &status, BITS_PER_LONG) {
+                       generic_handle_irq(icu_data[i].virq_base + n);
+               }
+       }
+}
+
+static int mmp_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                             irq_hw_number_t hw)
+{
+       irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+       set_irq_flags(irq, IRQF_VALID);
+       return 0;
+}
+
+static int mmp_irq_domain_xlate(struct irq_domain *d, struct device_node *node,
+                               const u32 *intspec, unsigned int intsize,
+                               unsigned long *out_hwirq,
+                               unsigned int *out_type)
+{
+       *out_hwirq = intspec[0];
+       return 0;
+}
+
+const struct irq_domain_ops mmp_irq_domain_ops = {
+       .map            = mmp_irq_domain_map,
+       .xlate          = mmp_irq_domain_xlate,
+};
+
+static struct mmp_intc_conf mmp_conf = {
+       .conf_enable    = 0x51,
+       .conf_disable   = 0x0,
+       .conf_mask      = 0x7f,
+};
+
+static struct mmp_intc_conf mmp2_conf = {
+       .conf_enable    = 0x20,
+       .conf_disable   = 0x0,
+       .conf_mask      = 0x7f,
+};
+
+static asmlinkage void __exception_irq_entry
+mmp_handle_irq(struct pt_regs *regs)
+{
+       int irq, hwirq;
+
+       hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL);
+       if (!(hwirq & SEL_INT_PENDING))
+               return;
+       hwirq &= SEL_INT_NUM_MASK;
+       irq = irq_find_mapping(icu_data[0].domain, hwirq);
+       handle_IRQ(irq, regs);
+}
+
+static asmlinkage void __exception_irq_entry
+mmp2_handle_irq(struct pt_regs *regs)
+{
+       int irq, hwirq;
+
+       hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL);
+       if (!(hwirq & SEL_INT_PENDING))
+               return;
+       hwirq &= SEL_INT_NUM_MASK;
+       irq = irq_find_mapping(icu_data[0].domain, hwirq);
+       handle_IRQ(irq, regs);
+}
+
+/* MMP (ARMv5) */
+void __init icu_init_irq(void)
+{
+       int irq;
+
+       max_icu_nr = 1;
+       mmp_icu_base = ioremap(0xd4282000, 0x1000);
+       icu_data[0].conf_enable = mmp_conf.conf_enable;
+       icu_data[0].conf_disable = mmp_conf.conf_disable;
+       icu_data[0].conf_mask = mmp_conf.conf_mask;
+       icu_data[0].nr_irqs = 64;
+       icu_data[0].virq_base = 0;
+       icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[0]);
+       for (irq = 0; irq < 64; irq++) {
+               icu_mask_irq(irq_get_irq_data(irq));
+               irq_set_chip_and_handler(irq, &icu_irq_chip, handle_level_irq);
+               set_irq_flags(irq, IRQF_VALID);
+       }
+       irq_set_default_host(icu_data[0].domain);
+       set_handle_irq(mmp_handle_irq);
+}
+
+/* MMP2 (ARMv7) */
+void __init mmp2_init_icu(void)
+{
+       int irq, end;
+
+       max_icu_nr = 8;
+       mmp_icu_base = ioremap(0xd4282000, 0x1000);
+       icu_data[0].conf_enable = mmp2_conf.conf_enable;
+       icu_data[0].conf_disable = mmp2_conf.conf_disable;
+       icu_data[0].conf_mask = mmp2_conf.conf_mask;
+       icu_data[0].nr_irqs = 64;
+       icu_data[0].virq_base = 0;
+       icu_data[0].domain = irq_domain_add_legacy(NULL, 64, 0, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[0]);
+       icu_data[1].reg_status = mmp_icu_base + 0x150;
+       icu_data[1].reg_mask = mmp_icu_base + 0x168;
+       icu_data[1].clr_mfp_irq_base = icu_data[0].virq_base +
+                               icu_data[0].nr_irqs;
+       icu_data[1].clr_mfp_hwirq = 1;          /* offset to IRQ_MMP2_PMIC_BASE */
+       icu_data[1].nr_irqs = 2;
+       icu_data[1].cascade_irq = 4;
+       icu_data[1].virq_base = icu_data[0].virq_base + icu_data[0].nr_irqs;
+       icu_data[1].domain = irq_domain_add_legacy(NULL, icu_data[1].nr_irqs,
+                                                  icu_data[1].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[1]);
+       icu_data[2].reg_status = mmp_icu_base + 0x154;
+       icu_data[2].reg_mask = mmp_icu_base + 0x16c;
+       icu_data[2].nr_irqs = 2;
+       icu_data[2].cascade_irq = 5;
+       icu_data[2].virq_base = icu_data[1].virq_base + icu_data[1].nr_irqs;
+       icu_data[2].domain = irq_domain_add_legacy(NULL, icu_data[2].nr_irqs,
+                                                  icu_data[2].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[2]);
+       icu_data[3].reg_status = mmp_icu_base + 0x180;
+       icu_data[3].reg_mask = mmp_icu_base + 0x17c;
+       icu_data[3].nr_irqs = 3;
+       icu_data[3].cascade_irq = 9;
+       icu_data[3].virq_base = icu_data[2].virq_base + icu_data[2].nr_irqs;
+       icu_data[3].domain = irq_domain_add_legacy(NULL, icu_data[3].nr_irqs,
+                                                  icu_data[3].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[3]);
+       icu_data[4].reg_status = mmp_icu_base + 0x158;
+       icu_data[4].reg_mask = mmp_icu_base + 0x170;
+       icu_data[4].nr_irqs = 5;
+       icu_data[4].cascade_irq = 17;
+       icu_data[4].virq_base = icu_data[3].virq_base + icu_data[3].nr_irqs;
+       icu_data[4].domain = irq_domain_add_legacy(NULL, icu_data[4].nr_irqs,
+                                                  icu_data[4].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[4]);
+       icu_data[5].reg_status = mmp_icu_base + 0x15c;
+       icu_data[5].reg_mask = mmp_icu_base + 0x174;
+       icu_data[5].nr_irqs = 15;
+       icu_data[5].cascade_irq = 35;
+       icu_data[5].virq_base = icu_data[4].virq_base + icu_data[4].nr_irqs;
+       icu_data[5].domain = irq_domain_add_legacy(NULL, icu_data[5].nr_irqs,
+                                                  icu_data[5].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[5]);
+       icu_data[6].reg_status = mmp_icu_base + 0x160;
+       icu_data[6].reg_mask = mmp_icu_base + 0x178;
+       icu_data[6].nr_irqs = 2;
+       icu_data[6].cascade_irq = 51;
+       icu_data[6].virq_base = icu_data[5].virq_base + icu_data[5].nr_irqs;
+       icu_data[6].domain = irq_domain_add_legacy(NULL, icu_data[6].nr_irqs,
+                                                  icu_data[6].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[6]);
+       icu_data[7].reg_status = mmp_icu_base + 0x188;
+       icu_data[7].reg_mask = mmp_icu_base + 0x184;
+       icu_data[7].nr_irqs = 2;
+       icu_data[7].cascade_irq = 55;
+       icu_data[7].virq_base = icu_data[6].virq_base + icu_data[6].nr_irqs;
+       icu_data[7].domain = irq_domain_add_legacy(NULL, icu_data[7].nr_irqs,
+                                                  icu_data[7].virq_base, 0,
+                                                  &irq_domain_simple_ops,
+                                                  &icu_data[7]);
+       end = icu_data[7].virq_base + icu_data[7].nr_irqs;
+       for (irq = 0; irq < end; irq++) {
+               icu_mask_irq(irq_get_irq_data(irq));
+               if (irq == icu_data[1].cascade_irq ||
+                   irq == icu_data[2].cascade_irq ||
+                   irq == icu_data[3].cascade_irq ||
+                   irq == icu_data[4].cascade_irq ||
+                   irq == icu_data[5].cascade_irq ||
+                   irq == icu_data[6].cascade_irq ||
+                   irq == icu_data[7].cascade_irq) {
+                       irq_set_chip(irq, &icu_irq_chip);
+                       irq_set_chained_handler(irq, icu_mux_irq_demux);
+               } else {
+                       irq_set_chip_and_handler(irq, &icu_irq_chip,
+                                                handle_level_irq);
+               }
+               set_irq_flags(irq, IRQF_VALID);
+       }
+       irq_set_default_host(icu_data[0].domain);
+       set_handle_irq(mmp2_handle_irq);
+}
+
+#ifdef CONFIG_OF
+static int __init mmp_init_bases(struct device_node *node)
+{
+       int ret, nr_irqs, irq, i = 0;
+
+       ret = of_property_read_u32(node, "mrvl,intc-nr-irqs", &nr_irqs);
+       if (ret) {
+               pr_err("Not found mrvl,intc-nr-irqs property\n");
+               return ret;
+       }
+
+       mmp_icu_base = of_iomap(node, 0);
+       if (!mmp_icu_base) {
+               pr_err("Failed to get interrupt controller register\n");
+               return -ENOMEM;
+       }
+
+       icu_data[0].virq_base = 0;
+       icu_data[0].domain = irq_domain_add_linear(node, nr_irqs,
+                                                  &mmp_irq_domain_ops,
+                                                  &icu_data[0]);
+       for (irq = 0; irq < nr_irqs; irq++) {
+               ret = irq_create_mapping(icu_data[0].domain, irq);
+               if (!ret) {
+                       pr_err("Failed to mapping hwirq\n");
+                       goto err;
+               }
+               if (!irq)
+                       icu_data[0].virq_base = ret;
+       }
+       icu_data[0].nr_irqs = nr_irqs;
+       return 0;
+err:
+       if (icu_data[0].virq_base) {
+               for (i = 0; i < irq; i++)
+                       irq_dispose_mapping(icu_data[0].virq_base + i);
+       }
+       irq_domain_remove(icu_data[0].domain);
+       iounmap(mmp_icu_base);
+       return -EINVAL;
+}
+
+static int __init mmp_of_init(struct device_node *node,
+                             struct device_node *parent)
+{
+       int ret;
+
+       ret = mmp_init_bases(node);
+       if (ret < 0)
+               return ret;
+
+       icu_data[0].conf_enable = mmp_conf.conf_enable;
+       icu_data[0].conf_disable = mmp_conf.conf_disable;
+       icu_data[0].conf_mask = mmp_conf.conf_mask;
+       irq_set_default_host(icu_data[0].domain);
+       set_handle_irq(mmp_handle_irq);
+       max_icu_nr = 1;
+       return 0;
+}
+IRQCHIP_DECLARE(mmp_intc, "mrvl,mmp-intc", mmp_of_init);
+
+static int __init mmp2_of_init(struct device_node *node,
+                              struct device_node *parent)
+{
+       int ret;
+
+       ret = mmp_init_bases(node);
+       if (ret < 0)
+               return ret;
+
+       icu_data[0].conf_enable = mmp2_conf.conf_enable;
+       icu_data[0].conf_disable = mmp2_conf.conf_disable;
+       icu_data[0].conf_mask = mmp2_conf.conf_mask;
+       irq_set_default_host(icu_data[0].domain);
+       set_handle_irq(mmp2_handle_irq);
+       max_icu_nr = 1;
+       return 0;
+}
+IRQCHIP_DECLARE(mmp2_intc, "mrvl,mmp2-intc", mmp2_of_init);
+
+static int __init mmp2_mux_of_init(struct device_node *node,
+                                  struct device_node *parent)
+{
+       struct resource res;
+       int i, ret, irq, j = 0;
+       u32 nr_irqs, mfp_irq;
+
+       if (!parent)
+               return -ENODEV;
+
+       i = max_icu_nr;
+       ret = of_property_read_u32(node, "mrvl,intc-nr-irqs",
+                                  &nr_irqs);
+       if (ret) {
+               pr_err("Not found mrvl,intc-nr-irqs property\n");
+               return -EINVAL;
+       }
+       ret = of_address_to_resource(node, 0, &res);
+       if (ret < 0) {
+               pr_err("Not found reg property\n");
+               return -EINVAL;
+       }
+       icu_data[i].reg_status = mmp_icu_base + res.start;
+       ret = of_address_to_resource(node, 1, &res);
+       if (ret < 0) {
+               pr_err("Not found reg property\n");
+               return -EINVAL;
+       }
+       icu_data[i].reg_mask = mmp_icu_base + res.start;
+       icu_data[i].cascade_irq = irq_of_parse_and_map(node, 0);
+       if (!icu_data[i].cascade_irq)
+               return -EINVAL;
+
+       icu_data[i].virq_base = 0;
+       icu_data[i].domain = irq_domain_add_linear(node, nr_irqs,
+                                                  &mmp_irq_domain_ops,
+                                                  &icu_data[i]);
+       for (irq = 0; irq < nr_irqs; irq++) {
+               ret = irq_create_mapping(icu_data[i].domain, irq);
+               if (!ret) {
+                       pr_err("Failed to mapping hwirq\n");
+                       goto err;
+               }
+               if (!irq)
+                       icu_data[i].virq_base = ret;
+       }
+       icu_data[i].nr_irqs = nr_irqs;
+       if (!of_property_read_u32(node, "mrvl,clr-mfp-irq",
+                                 &mfp_irq)) {
+               icu_data[i].clr_mfp_irq_base = icu_data[i].virq_base;
+               icu_data[i].clr_mfp_hwirq = mfp_irq;
+       }
+       irq_set_chained_handler(icu_data[i].cascade_irq,
+                               icu_mux_irq_demux);
+       max_icu_nr++;
+       return 0;
+err:
+       if (icu_data[i].virq_base) {
+               for (j = 0; j < irq; j++)
+                       irq_dispose_mapping(icu_data[i].virq_base + j);
+       }
+       irq_domain_remove(icu_data[i].domain);
+       return -EINVAL;
+}
+IRQCHIP_DECLARE(mmp2_mux_intc, "mrvl,mmp2-mux-intc", mmp2_mux_of_init);
+#endif
index 7f910c76ca0a340a967737345c7e733e2c4eced4..3c92780bda09e17843f3cea5c7c35161e103c25c 100644 (file)
@@ -2295,8 +2295,8 @@ _hfcpci_softirq(struct device *dev, void *arg)
 static void
 hfcpci_softirq(void *arg)
 {
-       (void) driver_for_each_device(&hfc_driver.driver, NULL, arg,
-                                     _hfcpci_softirq);
+       WARN_ON_ONCE(driver_for_each_device(&hfc_driver.driver, NULL, arg,
+                                     _hfcpci_softirq) != 0);
 
        /* if next event would be in the past ... */
        if ((s32)(hfc_jiffies + tics - jiffies) <= 0)
index 1063babe1d3ae1ba38ab43ed5cb1ee7407a87fed..36817e0a0b9465df6d1f9f8c4eee7cb0e5d24157 100644 (file)
@@ -314,7 +314,7 @@ Amd7930_empty_Dfifo(struct IsdnCardState *cs, int flag)
 
                                                        t += sprintf(t, "Amd7930: empty_Dfifo cnt: %d |", cs->rcvidx);
                                                        QuickHex(t, cs->rcvbuf, cs->rcvidx);
-                                                       debugl1(cs, cs->dlog);
+                                                       debugl1(cs, "%s", cs->dlog);
                                                }
                                                /* moves received data in sk-buffer */
                                                memcpy(skb_put(skb, cs->rcvidx), cs->rcvbuf, cs->rcvidx);
@@ -406,7 +406,7 @@ Amd7930_fill_Dfifo(struct IsdnCardState *cs)
 
                t += sprintf(t, "Amd7930: fill_Dfifo cnt: %d |", count);
                QuickHex(t, deb_ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
        /* AMD interrupts on */
        AmdIrqOn(cs);
index ee9b9a03cffa04d8bfe4a751cb24ce0f2824ec35..d1427bd6452dacd5b2fedfa6d8bf9a33a4207e85 100644 (file)
@@ -285,7 +285,7 @@ hdlc_empty_fifo(struct BCState *bcs, int count)
                t += sprintf(t, "hdlc_empty_fifo %c cnt %d",
                             bcs->channel ? 'B' : 'A', count);
                QuickHex(t, p, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
@@ -345,7 +345,7 @@ hdlc_fill_fifo(struct BCState *bcs)
                t += sprintf(t, "hdlc_fill_fifo %c cnt %d",
                             bcs->channel ? 'B' : 'A', count);
                QuickHex(t, p, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
index bf04d2a3cf4afe4614765b2b3d08d32ec77571a6..b33f53b3ca93257a6ec34f409c46e5f1d7662172 100644 (file)
@@ -1896,7 +1896,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
                                ptr--;
                                *ptr++ = '\n';
                                *ptr = 0;
-                               HiSax_putstatus(cs, NULL, cs->dlog);
+                               HiSax_putstatus(cs, NULL, "%s", cs->dlog);
                        } else
                                HiSax_putstatus(cs, "LogEcho: ",
                                                "warning Frame too big (%d)",
index 8d0cf6e4dc00590a7d62f455d77bcc192de9dfa1..4fc90de68d18a46941cfd8c629dd5f6624600173 100644 (file)
@@ -427,7 +427,7 @@ Memhscx_empty_fifo(struct BCState *bcs, int count)
                t += sprintf(t, "hscx_empty_fifo %c cnt %d",
                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
@@ -469,7 +469,7 @@ Memhscx_fill_fifo(struct BCState *bcs)
                t += sprintf(t, "hscx_fill_fifo %c cnt %d",
                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
index 1df6f9a56ca26926a9e684869e5471cfebc98e82..2be1c8a3bb5f2b7fd84f0d3cd039fb8dc5da3dd0 100644 (file)
@@ -535,7 +535,7 @@ check_arcofi(struct IsdnCardState *cs)
                t = tmp;
                t += sprintf(tmp, "Arcofi data");
                QuickHex(t, p, cs->dc.isac.mon_rxp);
-               debugl1(cs, tmp);
+               debugl1(cs, "%s", tmp);
                if ((cs->dc.isac.mon_rxp == 2) && (cs->dc.isac.mon_rx[0] == 0xa0)) {
                        switch (cs->dc.isac.mon_rx[1]) {
                        case 0x80:
index d4c98d330bfe3223087a3195e25b2e6719ec8065..3f84dd8f1757d8b645af7bf6b3088b7ce084d320 100644 (file)
@@ -344,7 +344,7 @@ static inline void receive_chars(struct IsdnCardState *cs,
 
                t += sprintf(t, "modem read cnt %d", cs->hw.elsa.rcvcnt);
                QuickHex(t, cs->hw.elsa.rcvbuf, cs->hw.elsa.rcvcnt);
-               debugl1(cs, tmp);
+               debugl1(cs, "%s", tmp);
        }
        cs->hw.elsa.rcvcnt = 0;
 }
index 3ccd724ff8c2812eb0af3fae58e6742d16970cd5..497bd026c2378eec6e781df68d007c135be4c1f7 100644 (file)
@@ -901,7 +901,7 @@ Begin:
                                        ptr--;
                                        *ptr++ = '\n';
                                        *ptr = 0;
-                                       HiSax_putstatus(cs, NULL, cs->dlog);
+                                       HiSax_putstatus(cs, NULL, "%s", cs->dlog);
                                } else
                                        HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
                        }
index dc4574f735ef59f24fecbeaf576e58280a56404f..fa1fefd711cde875fbcdf9b56a20f5375f39ced3 100644 (file)
@@ -674,7 +674,7 @@ receive_emsg(struct IsdnCardState *cs)
                                        ptr--;
                                        *ptr++ = '\n';
                                        *ptr = 0;
-                                       HiSax_putstatus(cs, NULL, cs->dlog);
+                                       HiSax_putstatus(cs, NULL, "%s", cs->dlog);
                                } else
                                        HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
                        }
index f398d4838937a3f4eaee68d7dfb2269cbd4ec8c6..a8d6188402c6eacec11ebe4379e1ee9e10dcfe58 100644 (file)
@@ -75,7 +75,7 @@ hscx_empty_fifo(struct BCState *bcs, int count)
                t += sprintf(t, "hscx_empty_fifo %c cnt %d",
                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
@@ -115,7 +115,7 @@ hscx_fill_fifo(struct BCState *bcs)
                t += sprintf(t, "hscx_fill_fifo %c cnt %d",
                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
index db5321f6379b0a454ffba83241abf540070138f9..51dae9167238a3ed1ff972508a02f338de6702a0 100644 (file)
@@ -134,7 +134,7 @@ icc_empty_fifo(struct IsdnCardState *cs, int count)
 
                t += sprintf(t, "icc_empty_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
@@ -176,7 +176,7 @@ icc_fill_fifo(struct IsdnCardState *cs)
 
                t += sprintf(t, "icc_fill_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
index 74feb5c830671340de67784b6f26e2a60251f348..5faa5de24305623bd38bcd4b0047f0063708f172 100644 (file)
@@ -260,7 +260,7 @@ dch_empty_fifo(struct IsdnCardState *cs, int count)
 
                t += sprintf(t, "dch_empty_fifo() cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
@@ -307,7 +307,7 @@ dch_fill_fifo(struct IsdnCardState *cs)
 
                t += sprintf(t, "dch_fill_fifo() cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
@@ -539,7 +539,7 @@ bch_empty_fifo(struct BCState *bcs, int count)
 
                t += sprintf(t, "bch_empty_fifo() B-%d cnt %d", hscx, count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
@@ -582,7 +582,7 @@ bch_fill_fifo(struct BCState *bcs)
 
                t += sprintf(t, "chb_fill_fifo() B-%d cnt %d", hscx, count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
index a365ccc1c99c886f94df163ab3b60280e20b9b49..7fdf78f4643394a493abb1545a284bf5b6b9bddd 100644 (file)
@@ -137,7 +137,7 @@ isac_empty_fifo(struct IsdnCardState *cs, int count)
 
                t += sprintf(t, "isac_empty_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
@@ -179,7 +179,7 @@ isac_fill_fifo(struct IsdnCardState *cs)
 
                t += sprintf(t, "isac_fill_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
index 7fdf34704fe5d3469f815f7c44b79f6fb8e15e35..f4956c73aa116de71a99a9ae705c81088f3fbed2 100644 (file)
@@ -74,7 +74,7 @@ sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
                                t = tmp;
                                t += sprintf(t, "sendmbox cnt %d", len);
                                QuickHex(t, &msg[len-i], (i > 64) ? 64 : i);
-                               debugl1(cs, tmp);
+                               debugl1(cs, "%s", tmp);
                                i -= 64;
                        }
                }
@@ -105,7 +105,7 @@ rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
                                t = tmp;
                                t += sprintf(t, "rcv_mbox cnt %d", ireg->clsb);
                                QuickHex(t, &msg[ireg->clsb - i], (i > 64) ? 64 : i);
-                               debugl1(cs, tmp);
+                               debugl1(cs, "%s", tmp);
                                i -= 64;
                        }
                }
@@ -1248,7 +1248,7 @@ isar_int_main(struct IsdnCardState *cs)
                        tp += sprintf(debbuf, "msg iis(%x) msb(%x)",
                                      ireg->iis, ireg->cmsb);
                        QuickHex(tp, (u_char *)ireg->par, ireg->clsb);
-                       debugl1(cs, debbuf);
+                       debugl1(cs, "%s", debbuf);
                }
                break;
        case ISAR_IIS_INVMSG:
index f946c58d8ab17d86fc8d0242dc25ecc7cbafdb82..e2ae7871a2095ddd8f82f229b8fab14dafd0e6c6 100644 (file)
@@ -81,10 +81,7 @@ modejade(struct BCState *bcs, int mode, int bc)
        int jade = bcs->hw.hscx.hscx;
 
        if (cs->debug & L1_DEB_HSCX) {
-               char tmp[40];
-               sprintf(tmp, "jade %c mode %d ichan %d",
-                       'A' + jade, mode, bc);
-               debugl1(cs, tmp);
+               debugl1(cs, "jade %c mode %d ichan %d", 'A' + jade, mode, bc);
        }
        bcs->mode = mode;
        bcs->channel = bc;
@@ -257,23 +254,18 @@ void
 clear_pending_jade_ints(struct IsdnCardState *cs)
 {
        int val;
-       char tmp[64];
 
        cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
        cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
 
        val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
-       sprintf(tmp, "jade B ISTA %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "jade B ISTA %x", val);
        val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
-       sprintf(tmp, "jade A ISTA %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "jade A ISTA %x", val);
        val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
-       sprintf(tmp, "jade B STAR %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "jade B STAR %x", val);
        val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
-       sprintf(tmp, "jade A STAR %x", val);
-       debugl1(cs, tmp);
+       debugl1(cs, "jade A STAR %x", val);
        /* Unmask ints */
        cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
        cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
index f521fc83dc766d389c7dc650e9fa1a584024b983..b930da9b5aa685043aca9d8375d31f5bef14020a 100644 (file)
@@ -65,7 +65,7 @@ jade_empty_fifo(struct BCState *bcs, int count)
                t += sprintf(t, "jade_empty_fifo %c cnt %d",
                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
@@ -105,7 +105,7 @@ jade_fill_fifo(struct BCState *bcs)
                t += sprintf(t, "jade_fill_fifo %c cnt %d",
                             bcs->hw.hscx.hscx ? 'B' : 'A', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
index 4c1bca5caa1d0075353cc0451922b8624dd111cb..875402e76d0ad62cf7e400f6da19734998bd6129 100644 (file)
@@ -63,7 +63,7 @@ l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb)
 {
        dev_kfree_skb(skb);
        if (pc->st->l3.debug & L3_DEB_WARN)
-               l3_debug(pc->st, msg);
+               l3_debug(pc->st, "%s", msg);
        l3_1tr6_release_req(pc, 0, NULL);
 }
 
@@ -161,7 +161,6 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        int bcfound = 0;
-       char tmp[80];
        struct sk_buff *skb = arg;
 
        /* Channel Identification */
@@ -214,10 +213,9 @@ l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg)
        /* Signal all services, linklevel takes care of Service-Indicator */
        if (bcfound) {
                if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) {
-                       sprintf(tmp, "non-digital call: %s -> %s",
+                       l3_debug(pc->st, "non-digital call: %s -> %s",
                                pc->para.setup.phone,
                                pc->para.setup.eazmsn);
-                       l3_debug(pc->st, tmp);
                }
                newl3state(pc, 6);
                pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
@@ -301,7 +299,7 @@ l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
 {
        u_char *p;
        int i, tmpcharge = 0;
-       char a_charge[8], tmp[32];
+       char a_charge[8];
        struct sk_buff *skb = arg;
 
        p = skb->data;
@@ -316,8 +314,8 @@ l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg)
                        pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
                }
                if (pc->st->l3.debug & L3_DEB_CHARGE) {
-                       sprintf(tmp, "charging info %d", pc->para.chargeinfo);
-                       l3_debug(pc->st, tmp);
+                       l3_debug(pc->st, "charging info %d",
+                                pc->para.chargeinfo);
                }
        } else if (pc->st->l3.debug & L3_DEB_CHARGE)
                l3_debug(pc->st, "charging info not found");
@@ -399,7 +397,7 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
        struct sk_buff *skb = arg;
        u_char *p;
        int i, tmpcharge = 0;
-       char a_charge[8], tmp[32];
+       char a_charge[8];
 
        StopAllL3Timer(pc);
        p = skb->data;
@@ -414,8 +412,8 @@ l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg)
                        pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc);
                }
                if (pc->st->l3.debug & L3_DEB_CHARGE) {
-                       sprintf(tmp, "charging info %d", pc->para.chargeinfo);
-                       l3_debug(pc->st, tmp);
+                       l3_debug(pc->st, "charging info %d",
+                                pc->para.chargeinfo);
                }
        } else if (pc->st->l3.debug & L3_DEB_CHARGE)
                l3_debug(pc->st, "charging info not found");
@@ -746,7 +744,6 @@ up1tr6(struct PStack *st, int pr, void *arg)
        int i, mt, cr;
        struct l3_process *proc;
        struct sk_buff *skb = arg;
-       char tmp[80];
 
        switch (pr) {
        case (DL_DATA | INDICATION):
@@ -762,26 +759,23 @@ up1tr6(struct PStack *st, int pr, void *arg)
        }
        if (skb->len < 4) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "up1tr6 len only %d", skb->len);
-                       l3_debug(st, tmp);
+                       l3_debug(st, "up1tr6 len only %d", skb->len);
                }
                dev_kfree_skb(skb);
                return;
        }
        if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d",
+                       l3_debug(st, "up1tr6%sunexpected discriminator %x message len %d",
                                (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                skb->data[0], skb->len);
-                       l3_debug(st, tmp);
                }
                dev_kfree_skb(skb);
                return;
        }
        if (skb->data[1] != 1) {
                if (st->l3.debug & L3_DEB_PROTERR) {
-                       sprintf(tmp, "up1tr6 CR len not 1");
-                       l3_debug(st, tmp);
+                       l3_debug(st, "up1tr6 CR len not 1");
                }
                dev_kfree_skb(skb);
                return;
@@ -791,9 +785,8 @@ up1tr6(struct PStack *st, int pr, void *arg)
        if (skb->data[0] == PROTO_DIS_N0) {
                dev_kfree_skb(skb);
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "up1tr6%s N0 mt %x unhandled",
+                       l3_debug(st, "up1tr6%s N0 mt %x unhandled",
                                (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt);
-                       l3_debug(st, tmp);
                }
        } else if (skb->data[0] == PROTO_DIS_N1) {
                if (!(proc = getl3proc(st, cr))) {
@@ -801,8 +794,7 @@ up1tr6(struct PStack *st, int pr, void *arg)
                                if (cr < 128) {
                                        if (!(proc = new_l3_process(st, cr))) {
                                                if (st->l3.debug & L3_DEB_PROTERR) {
-                                                       sprintf(tmp, "up1tr6 no roc mem");
-                                                       l3_debug(st, tmp);
+                                                       l3_debug(st, "up1tr6 no roc mem");
                                                }
                                                dev_kfree_skb(skb);
                                                return;
@@ -821,8 +813,7 @@ up1tr6(struct PStack *st, int pr, void *arg)
                        } else {
                                if (!(proc = new_l3_process(st, cr))) {
                                        if (st->l3.debug & L3_DEB_PROTERR) {
-                                               sprintf(tmp, "up1tr6 no roc mem");
-                                               l3_debug(st, tmp);
+                                               l3_debug(st, "up1tr6 no roc mem");
                                        }
                                        dev_kfree_skb(skb);
                                        return;
@@ -837,18 +828,16 @@ up1tr6(struct PStack *st, int pr, void *arg)
                if (i == ARRAY_SIZE(datastln1)) {
                        dev_kfree_skb(skb);
                        if (st->l3.debug & L3_DEB_STATE) {
-                               sprintf(tmp, "up1tr6%sstate %d mt %x unhandled",
+                               l3_debug(st, "up1tr6%sstate %d mt %x unhandled",
                                        (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                        proc->state, mt);
-                               l3_debug(st, tmp);
                        }
                        return;
                } else {
                        if (st->l3.debug & L3_DEB_STATE) {
-                               sprintf(tmp, "up1tr6%sstate %d mt %x",
+                               l3_debug(st, "up1tr6%sstate %d mt %x",
                                        (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
                                        proc->state, mt);
-                               l3_debug(st, tmp);
                        }
                        datastln1[i].rout(proc, pr, skb);
                }
@@ -861,7 +850,6 @@ down1tr6(struct PStack *st, int pr, void *arg)
        int i, cr;
        struct l3_process *proc;
        struct Channel *chan;
-       char tmp[80];
 
        if ((DL_ESTABLISH | REQUEST) == pr) {
                l3_msg(st, pr, NULL);
@@ -888,15 +876,13 @@ down1tr6(struct PStack *st, int pr, void *arg)
                        break;
        if (i == ARRAY_SIZE(downstl)) {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "down1tr6 state %d prim %d unhandled",
+                       l3_debug(st, "down1tr6 state %d prim %d unhandled",
                                proc->state, pr);
-                       l3_debug(st, tmp);
                }
        } else {
                if (st->l3.debug & L3_DEB_STATE) {
-                       sprintf(tmp, "down1tr6 state %d prim %d",
+                       l3_debug(st, "down1tr6 state %d prim %d",
                                proc->state, pr);
-                       l3_debug(st, tmp);
                }
                downstl[i].rout(proc, pr, arg);
        }
index b646eed379dfb52134b828d80c61a74262188168..233e432e06f69ef03e5ae32f56f24ba133a4d249 100644 (file)
@@ -176,7 +176,7 @@ static void printframe(struct IsdnCardState *cs, u_char *buf, int count, char *s
                else
                        j = i;
                QuickHex(t, p, j);
-               debugl1(cs, tmp);
+               debugl1(cs, "%s", tmp);
                p += j;
                i -= j;
                t = tmp;
index 041bf52d9d0acf2a75ec15a702608a269d83d446..af1b020a81f1814eb28b8fea83fca30b3b4332fc 100644 (file)
@@ -1179,7 +1179,7 @@ LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
                dp--;
                *dp++ = '\n';
                *dp = 0;
-               HiSax_putstatus(cs, NULL, cs->dlog);
+               HiSax_putstatus(cs, NULL, "%s", cs->dlog);
        } else
                HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
 }
@@ -1246,7 +1246,7 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
        }
        if (finish) {
                *dp = 0;
-               HiSax_putstatus(cs, NULL, cs->dlog);
+               HiSax_putstatus(cs, NULL, "%s", cs->dlog);
                return;
        }
        if ((0xfe & buf[0]) == PROTO_DIS_N0) {  /* 1TR6 */
@@ -1509,5 +1509,5 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
                dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
        }
        *dp = 0;
-       HiSax_putstatus(cs, NULL, cs->dlog);
+       HiSax_putstatus(cs, NULL, "%s", cs->dlog);
 }
index d8cac69358180ee455c92d99a0c58b8203372203..a85895585d906a6367db5cce95b00f031484d05d 100644 (file)
@@ -154,7 +154,7 @@ W6692_empty_fifo(struct IsdnCardState *cs, int count)
 
                t += sprintf(t, "W6692_empty_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
@@ -196,7 +196,7 @@ W6692_fill_fifo(struct IsdnCardState *cs)
 
                t += sprintf(t, "W6692_fill_fifo cnt %d", count);
                QuickHex(t, ptr, count);
-               debugl1(cs, cs->dlog);
+               debugl1(cs, "%s", cs->dlog);
        }
 }
 
@@ -226,7 +226,7 @@ W6692B_empty_fifo(struct BCState *bcs, int count)
                t += sprintf(t, "W6692B_empty_fifo %c cnt %d",
                             bcs->channel + '1', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
@@ -264,7 +264,7 @@ W6692B_fill_fifo(struct BCState *bcs)
                t += sprintf(t, "W6692B_fill_fifo %c cnt %d",
                             bcs->channel + '1', count);
                QuickHex(t, ptr, count);
-               debugl1(cs, bcs->blog);
+               debugl1(cs, "%s", bcs->blog);
        }
 }
 
index 074bcb3892b56ad92aea059694b5f3d4ef89bea2..875bbe4c962ea4a0229b073edab2e1c301575055 100644 (file)
@@ -194,11 +194,11 @@ config LEDS_LP3944
          module will be called leds-lp3944.
 
 config LEDS_LP55XX_COMMON
-       tristate "Common Driver for TI/National LP5521, LP5523/55231 and LP5562"
-       depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562
+       tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501"
+       depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501
        select FW_LOADER
        help
-         This option supports common operations for LP5521 and LP5523/55231
+         This option supports common operations for LP5521/5523/55231/5562/8501
          devices.
 
 config LEDS_LP5521
@@ -232,6 +232,18 @@ config LEDS_LP5562
          Driver provides direct control via LED class and interface for
          programming the engines.
 
+config LEDS_LP8501
+       tristate "LED Support for TI LP8501 LED driver chip"
+       depends on LEDS_CLASS && I2C
+       select LEDS_LP55XX_COMMON
+       help
+         If you say yes here you get support for TI LP8501 LED driver.
+         It is 9 channel chip with programmable engines.
+         Driver provides direct control via LED class and interface for
+         programming the engines.
+         It is similar as LP5523, but output power selection is available.
+         And register layout and engine program schemes are different.
+
 config LEDS_LP8788
        tristate "LED support for the TI LP8788 PMIC"
        depends on LEDS_CLASS
@@ -279,13 +291,14 @@ config LEDS_PCA955X
          LED driver chips accessed via the I2C bus.  Supported
          devices include PCA9550, PCA9551, PCA9552, and PCA9553.
 
-config LEDS_PCA9633
-       tristate "LED support for PCA9633 I2C chip"
+config LEDS_PCA963X
+       tristate "LED support for PCA963x I2C chip"
        depends on LEDS_CLASS
        depends on I2C
        help
-         This option enables support for LEDs connected to the PCA9633
-         LED driver chip accessed via the I2C bus.
+         This option enables support for LEDs connected to the PCA963x
+         LED driver chip accessed via the I2C bus. Supported
+         devices include PCA9633 and PCA9634
 
 config LEDS_WM831X_STATUS
        tristate "LED support for status LEDs on WM831x PMICs"
@@ -398,10 +411,7 @@ config LEDS_MC13783
 config LEDS_NS2
        tristate "LED support for Network Space v2 GPIO LEDs"
        depends on LEDS_CLASS
-       depends on MACH_NETSPACE_V2 || MACH_INETSPACE_V2 || \
-                  MACH_NETSPACE_MAX_V2 || MACH_D2NET_V2 || \
-                  MACH_NETSPACE_V2_DT || MACH_INETSPACE_V2_DT || \
-                  MACH_NETSPACE_MAX_V2_DT || MACH_NETSPACE_MINI_V2_DT
+       depends on ARCH_KIRKWOOD
        default y
        help
          This option enable support for the dual-GPIO LED found on the
@@ -410,8 +420,8 @@ config LEDS_NS2
 
 config LEDS_NETXBIG
        tristate "LED support for Big Network series LEDs"
-       depends on MACH_NET2BIG_V2 || MACH_NET5BIG_V2
        depends on LEDS_CLASS
+       depends on ARCH_KIRKWOOD
        default y
        help
          This option enable support for LEDs found on the LaCie 2Big
index ae4b6135f66513fb7f3eefc90ad6d261ab2ca2a6..8979b0b2c85ed03e37ab880e14823f17f66922ed 100644 (file)
@@ -27,6 +27,7 @@ obj-$(CONFIG_LEDS_LP55XX_COMMON)      += leds-lp55xx-common.o
 obj-$(CONFIG_LEDS_LP5521)              += leds-lp5521.o
 obj-$(CONFIG_LEDS_LP5523)              += leds-lp5523.o
 obj-$(CONFIG_LEDS_LP5562)              += leds-lp5562.o
+obj-$(CONFIG_LEDS_LP8501)              += leds-lp8501.o
 obj-$(CONFIG_LEDS_LP8788)              += leds-lp8788.o
 obj-$(CONFIG_LEDS_TCA6507)             += leds-tca6507.o
 obj-$(CONFIG_LEDS_CLEVO_MAIL)          += leds-clevo-mail.o
@@ -34,7 +35,7 @@ obj-$(CONFIG_LEDS_HP6XX)              += leds-hp6xx.o
 obj-$(CONFIG_LEDS_OT200)               += leds-ot200.o
 obj-$(CONFIG_LEDS_FSG)                 += leds-fsg.o
 obj-$(CONFIG_LEDS_PCA955X)             += leds-pca955x.o
-obj-$(CONFIG_LEDS_PCA9633)             += leds-pca9633.o
+obj-$(CONFIG_LEDS_PCA963X)             += leds-pca963x.o
 obj-$(CONFIG_LEDS_DA903X)              += leds-da903x.o
 obj-$(CONFIG_LEDS_DA9052)              += leds-da9052.o
 obj-$(CONFIG_LEDS_WM831X_STATUS)       += leds-wm831x-status.o
index 232b3ce902e55f6d3c7ea696a93808121e304ace..5f588c0a376eb0eaec12843fea7022c65f9a1418 100644 (file)
@@ -157,7 +157,7 @@ static int pm860x_led_dt_init(struct platform_device *pdev,
 static int pm860x_led_probe(struct platform_device *pdev)
 {
        struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
-       struct pm860x_led_pdata *pdata = pdev->dev.platform_data;
+       struct pm860x_led_pdata *pdata = dev_get_platdata(&pdev->dev);
        struct pm860x_led *data;
        struct resource *res;
        int ret = 0;
index e8072abe76e5fb81e1e155ac25c9a7d8481b0673..7e311a120b11abe9f457550ffc85df2c4cbf1748 100644 (file)
@@ -87,7 +87,7 @@ static int adp5520_led_setup(struct adp5520_led *led)
 
 static int adp5520_led_prepare(struct platform_device *pdev)
 {
-       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = pdev->dev.parent;
        int ret = 0;
 
@@ -103,7 +103,7 @@ static int adp5520_led_prepare(struct platform_device *pdev)
 
 static int adp5520_led_probe(struct platform_device *pdev)
 {
-       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct adp5520_led *led, *led_dat;
        struct led_info *cur_led;
        int ret, i;
@@ -185,7 +185,7 @@ err:
 
 static int adp5520_led_remove(struct platform_device *pdev)
 {
-       struct adp5520_leds_platform_data *pdata = pdev->dev.platform_data;
+       struct adp5520_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct adp5520_led *led;
        int i;
 
index cf9efe421c2be0674ddc2db79a0059811b5df859..6de216a89a0c1d3dc766f45f1e19466b80fe316f 100644 (file)
@@ -94,7 +94,7 @@ static int blink_set(struct led_classdev *cdev,
 
 static int asic3_led_probe(struct platform_device *pdev)
 {
-       struct asic3_led *led = pdev->dev.platform_data;
+       struct asic3_led *led = dev_get_platdata(&pdev->dev);
        int ret;
 
        ret = mfd_cell_enable(pdev);
@@ -127,7 +127,7 @@ out:
 
 static int asic3_led_remove(struct platform_device *pdev)
 {
-       struct asic3_led *led = pdev->dev.platform_data;
+       struct asic3_led *led = dev_get_platdata(&pdev->dev);
 
        led_classdev_unregister(led->cdev);
 
index 90518f84b9c07aeacf06664c0adcf32671512269..56cec8d6a2ac7a56de5b4f03d6d0f2a0920b3bfc 100644 (file)
@@ -42,7 +42,7 @@ static int pwmled_probe(struct platform_device *pdev)
        int                                     i;
        int                                     status;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata || pdata->num_leds < 1)
                return -ENODEV;
 
@@ -119,7 +119,7 @@ static int pwmled_remove(struct platform_device *pdev)
        struct pwmled                           *leds;
        unsigned                                i;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        leds = platform_get_drvdata(pdev);
 
        for (i = 0; i < pdata->num_leds; i++) {
index 2db04231a79276e049a930469aef66b90b3eb4ca..fb5a3472d61444c1cd8d491ee8a5ee571f39765c 100644 (file)
@@ -684,7 +684,7 @@ static int bd2802_probe(struct i2c_client *client,
        }
 
        led->client = client;
-       pdata = led->pdata = client->dev.platform_data;
+       pdata = led->pdata = dev_get_platdata(&client->dev);
        i2c_set_clientdata(client, led);
 
        /* Configure RESET GPIO (L: RESET, H: RESET cancel) */
index 6a8405df76a3dd7200983a04f8ec8832734cd4ea..d93e2455da5c43af5fbdf59659cf9e61d5c9ffd1 100644 (file)
@@ -40,7 +40,7 @@ static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
  * detected as working, but in reality it is not) as low as
  * possible.
  */
-static struct dmi_system_id __initdata clevo_mail_led_dmi_table[] = {
+static struct dmi_system_id clevo_mail_led_dmi_table[] __initdata = {
        {
                .callback = clevo_mail_led_dmi_callback,
                .ident = "Clevo D410J",
index c263a21db8298d057ca1cf5b9b28196d0af8e864..2a4b87f8091ab699706577e1442efe68de645049 100644 (file)
@@ -93,7 +93,7 @@ static void da903x_led_set(struct led_classdev *led_cdev,
 
 static int da903x_led_probe(struct platform_device *pdev)
 {
-       struct led_info *pdata = pdev->dev.platform_data;
+       struct led_info *pdata = dev_get_platdata(&pdev->dev);
        struct da903x_led *led;
        int id, ret;
 
index efec43344e9f98b1ab56ae20f800d9fb5348ad56..865d4faf874a627424611314eb454e8ca2ba9d6e 100644 (file)
@@ -112,7 +112,7 @@ static int da9052_led_probe(struct platform_device *pdev)
        int i;
 
        da9052 = dev_get_drvdata(pdev->dev.parent);
-       pdata = da9052->dev->platform_data;
+       pdata = dev_get_platdata(da9052->dev);
        if (pdata == NULL) {
                dev_err(&pdev->dev, "No platform data\n");
                goto err;
@@ -185,7 +185,7 @@ static int da9052_led_remove(struct platform_device *pdev)
        int i;
 
        da9052 = dev_get_drvdata(pdev->dev.parent);
-       pdata = da9052->dev->platform_data;
+       pdata = dev_get_platdata(da9052->dev);
        pled = pdata->pled;
 
        for (i = 0; i < pled->num_leds; i++) {
index 84d74c373cae89cd046554f653b7da34fb761a64..e8b01e57348d675cae0821ddb9179b85d92a03f1 100644 (file)
@@ -233,7 +233,7 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
 
 static int gpio_led_probe(struct platform_device *pdev)
 {
-       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct gpio_leds_priv *priv;
        int i, ret = 0;
 
index a036a19040fea90b70ba93a93eac99401f85567a..652368c2ea9a5b9ca1d806de4057747a2c2fea0a 100644 (file)
@@ -403,7 +403,7 @@ static DEVICE_ATTR(mode, 0644, lm3530_mode_get, lm3530_mode_set);
 static int lm3530_probe(struct i2c_client *client,
                           const struct i2c_device_id *id)
 {
-       struct lm3530_platform_data *pdata = client->dev.platform_data;
+       struct lm3530_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lm3530_data *drvdata;
        int err = 0;
 
index bbf24d038a7fc2139b0c78845b52bbb266f13b2c..027ede73b80da01d716aacd6dbd2d07e20b90092 100644 (file)
@@ -671,7 +671,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
        if (!lm3533)
                return -EINVAL;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data\n");
                return -EINVAL;
index d81a8e7afd6ce2a6ae3d21adfa95e4cb25a0d2fe..591eb5e58ae3f80ad3766cee4ded90917cf167b0 100644 (file)
@@ -423,7 +423,7 @@ static const struct regmap_config lm355x_regmap = {
 static int lm355x_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct lm355x_platform_data *pdata = client->dev.platform_data;
+       struct lm355x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lm355x_chip_data *chip;
 
        int err;
index f361bbef2decc2aa7d1e6d904587dea147c30146..ceb6b3cde6fe8a3dd261d9b94a94cd0c8cebb7b3 100644 (file)
@@ -316,7 +316,7 @@ static const struct regmap_config lm3642_regmap = {
 static int lm3642_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct lm3642_platform_data *pdata = client->dev.platform_data;
+       struct lm3642_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lm3642_chip_data *chip;
 
        int err;
index 0c4386e656c162fcea462743d618638037094124..8e1abdcd4c9d9789c207258c82ff9f33daa3a0df 100644 (file)
@@ -289,7 +289,7 @@ static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
        dev_dbg(&led->client->dev, "%s: %s, %d\n",
                __func__, led_cdev->name, brightness);
 
-       led->status = brightness;
+       led->status = !!brightness;
        schedule_work(&led->work);
 }
 
@@ -377,7 +377,8 @@ exit:
 static int lp3944_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct lp3944_platform_data *lp3944_pdata = client->dev.platform_data;
+       struct lp3944_platform_data *lp3944_pdata =
+                       dev_get_platdata(&client->dev);
        struct lp3944_data *data;
        int err;
 
@@ -413,7 +414,7 @@ static int lp3944_probe(struct i2c_client *client,
 
 static int lp3944_remove(struct i2c_client *client)
 {
-       struct lp3944_platform_data *pdata = client->dev.platform_data;
+       struct lp3944_platform_data *pdata = dev_get_platdata(&client->dev);
        struct lp3944_data *data = i2c_get_clientdata(client);
        int i;
 
index 1392feb1bcf7849559ba29b38f163afa01a305bb..05188351711d2d80f5ac8cd0a006159b732b2c90 100644 (file)
@@ -220,17 +220,11 @@ static int lp5521_update_program_memory(struct lp55xx_chip *chip,
        };
        unsigned cmd;
        char c[3];
-       int program_size;
        int nrchars;
-       int offset = 0;
        int ret;
-       int i;
-
-       /* clear program memory before updating */
-       for (i = 0; i < LP5521_PROGRAM_LENGTH; i++)
-               lp55xx_write(chip, addr[idx] + i, 0);
+       int offset = 0;
+       int i = 0;
 
-       i = 0;
        while ((offset < size - 1) && (i < LP5521_PROGRAM_LENGTH)) {
                /* separate sscanfs because length is working only for %s */
                ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
@@ -250,11 +244,19 @@ static int lp5521_update_program_memory(struct lp55xx_chip *chip,
        if (i % 2)
                goto err;
 
-       program_size = i;
-       for (i = 0; i < program_size; i++)
-               lp55xx_write(chip, addr[idx] + i, pattern[i]);
+       mutex_lock(&chip->lock);
 
-       return 0;
+       for (i = 0; i < LP5521_PROGRAM_LENGTH; i++) {
+               ret = lp55xx_write(chip, addr[idx] + i, pattern[i]);
+               if (ret) {
+                       mutex_unlock(&chip->lock);
+                       return -EINVAL;
+               }
+       }
+
+       mutex_unlock(&chip->lock);
+
+       return size;
 
 err:
        dev_err(&chip->cl->dev, "wrong pattern format\n");
@@ -365,6 +367,80 @@ static void lp5521_led_brightness_work(struct work_struct *work)
        mutex_unlock(&chip->lock);
 }
 
+static ssize_t show_engine_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+       enum lp55xx_engine_mode mode = chip->engines[nr - 1].mode;
+
+       switch (mode) {
+       case LP55XX_ENGINE_RUN:
+               return sprintf(buf, "run\n");
+       case LP55XX_ENGINE_LOAD:
+               return sprintf(buf, "load\n");
+       case LP55XX_ENGINE_DISABLED:
+       default:
+               return sprintf(buf, "disabled\n");
+       }
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+       struct lp55xx_engine *engine = &chip->engines[nr - 1];
+
+       mutex_lock(&chip->lock);
+
+       chip->engine_idx = nr;
+
+       if (!strncmp(buf, "run", 3)) {
+               lp5521_run_engine(chip, true);
+               engine->mode = LP55XX_ENGINE_RUN;
+       } else if (!strncmp(buf, "load", 4)) {
+               lp5521_stop_engine(chip);
+               lp5521_load_engine(chip);
+               engine->mode = LP55XX_ENGINE_LOAD;
+       } else if (!strncmp(buf, "disabled", 8)) {
+               lp5521_stop_engine(chip);
+               engine->mode = LP55XX_ENGINE_DISABLED;
+       }
+
+       mutex_unlock(&chip->lock);
+
+       return len;
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static ssize_t store_engine_load(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+
+       mutex_lock(&chip->lock);
+
+       chip->engine_idx = nr;
+       lp5521_load_engine(chip);
+
+       mutex_unlock(&chip->lock);
+
+       return lp5521_update_program_memory(chip, buf, len);
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
 static ssize_t lp5521_selftest(struct device *dev,
                               struct device_attribute *attr,
                               char *buf)
@@ -381,9 +457,21 @@ static ssize_t lp5521_selftest(struct device *dev,
 }
 
 /* device attributes */
-static DEVICE_ATTR(selftest, S_IRUGO, lp5521_selftest, NULL);
+static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode);
+static LP55XX_DEV_ATTR_RW(engine2_mode, show_engine2_mode, store_engine2_mode);
+static LP55XX_DEV_ATTR_RW(engine3_mode, show_engine3_mode, store_engine3_mode);
+static LP55XX_DEV_ATTR_WO(engine1_load, store_engine1_load);
+static LP55XX_DEV_ATTR_WO(engine2_load, store_engine2_load);
+static LP55XX_DEV_ATTR_WO(engine3_load, store_engine3_load);
+static LP55XX_DEV_ATTR_RO(selftest, lp5521_selftest);
 
 static struct attribute *lp5521_attributes[] = {
+       &dev_attr_engine1_mode.attr,
+       &dev_attr_engine2_mode.attr,
+       &dev_attr_engine3_mode.attr,
+       &dev_attr_engine1_load.attr,
+       &dev_attr_engine2_load.attr,
+       &dev_attr_engine3_load.attr,
        &dev_attr_selftest.attr,
        NULL
 };
@@ -420,7 +508,7 @@ static int lp5521_probe(struct i2c_client *client,
        struct lp55xx_platform_data *pdata;
        struct device_node *np = client->dev.of_node;
 
-       if (!client->dev.platform_data) {
+       if (!dev_get_platdata(&client->dev)) {
                if (np) {
                        ret = lp55xx_of_populate_pdata(&client->dev, np);
                        if (ret < 0)
@@ -430,7 +518,7 @@ static int lp5521_probe(struct i2c_client *client,
                        return -EINVAL;
                }
        }
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index 3979428f3100ab9d274a5e3bb3afa1333399efee..fe3bcbb5747f95a57965b7958f400b823dcbe3dd 100644 (file)
@@ -49,6 +49,9 @@
 #define LP5523_REG_RESET               0x3D
 #define LP5523_REG_LED_TEST_CTRL       0x41
 #define LP5523_REG_LED_TEST_ADC                0x42
+#define LP5523_REG_CH1_PROG_START      0x4C
+#define LP5523_REG_CH2_PROG_START      0x4D
+#define LP5523_REG_CH3_PROG_START      0x4E
 #define LP5523_REG_PROG_PAGE_SEL       0x4F
 #define LP5523_REG_PROG_MEM            0x50
 
 #define LP5523_RESET                   0xFF
 #define LP5523_ADC_SHORTCIRC_LIM       80
 #define LP5523_EXT_CLK_USED            0x08
+#define LP5523_ENG_STATUS_MASK         0x07
 
 /* Memory Page Selection */
 #define LP5523_PAGE_ENG1               0
 #define LP5523_PAGE_ENG2               1
 #define LP5523_PAGE_ENG3               2
+#define LP5523_PAGE_MUX1               3
+#define LP5523_PAGE_MUX2               4
+#define LP5523_PAGE_MUX3               5
 
 /* Program Memory Operations */
 #define LP5523_MODE_ENG1_M             0x30    /* Operation Mode Register */
 #define LP5523_RUN_ENG2                        0x08
 #define LP5523_RUN_ENG3                        0x02
 
+#define LED_ACTIVE(mux, led)           (!!(mux & (0x0001 << led)))
+
 enum lp5523_chip_id {
        LP5523,
        LP55231,
 };
 
+static int lp5523_init_program_engine(struct lp55xx_chip *chip);
+
 static inline void lp5523_wait_opmode_done(void)
 {
        usleep_range(1000, 2000);
@@ -134,7 +145,11 @@ static int lp5523_post_init_device(struct lp55xx_chip *chip)
        if (ret)
                return ret;
 
-       return lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
+       ret = lp55xx_write(chip, LP5523_REG_ENABLE_LEDS_LSB, 0xff);
+       if (ret)
+               return ret;
+
+       return lp5523_init_program_engine(chip);
 }
 
 static void lp5523_load_engine(struct lp55xx_chip *chip)
@@ -152,15 +167,21 @@ static void lp5523_load_engine(struct lp55xx_chip *chip)
                [LP55XX_ENGINE_3] = LP5523_LOAD_ENG3,
        };
 
+       lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], val[idx]);
+
+       lp5523_wait_opmode_done();
+}
+
+static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip)
+{
+       enum lp55xx_engine_index idx = chip->engine_idx;
        u8 page_sel[] = {
                [LP55XX_ENGINE_1] = LP5523_PAGE_ENG1,
                [LP55XX_ENGINE_2] = LP5523_PAGE_ENG2,
                [LP55XX_ENGINE_3] = LP5523_PAGE_ENG3,
        };
 
-       lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], val[idx]);
-
-       lp5523_wait_opmode_done();
+       lp5523_load_engine(chip);
 
        lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]);
 }
@@ -227,23 +248,75 @@ static void lp5523_run_engine(struct lp55xx_chip *chip, bool start)
        lp55xx_update_bits(chip, LP5523_REG_ENABLE, LP5523_EXEC_M, exec);
 }
 
+static int lp5523_init_program_engine(struct lp55xx_chip *chip)
+{
+       int i;
+       int j;
+       int ret;
+       u8 status;
+       /* one pattern per engine setting LED MUX start and stop addresses */
+       static const u8 pattern[][LP5523_PROGRAM_LENGTH] =  {
+               { 0x9c, 0x30, 0x9c, 0xb0, 0x9d, 0x80, 0xd8, 0x00, 0},
+               { 0x9c, 0x40, 0x9c, 0xc0, 0x9d, 0x80, 0xd8, 0x00, 0},
+               { 0x9c, 0x50, 0x9c, 0xd0, 0x9d, 0x80, 0xd8, 0x00, 0},
+       };
+
+       /* hardcode 32 bytes of memory for each engine from program memory */
+       ret = lp55xx_write(chip, LP5523_REG_CH1_PROG_START, 0x00);
+       if (ret)
+               return ret;
+
+       ret = lp55xx_write(chip, LP5523_REG_CH2_PROG_START, 0x10);
+       if (ret)
+               return ret;
+
+       ret = lp55xx_write(chip, LP5523_REG_CH3_PROG_START, 0x20);
+       if (ret)
+               return ret;
+
+       /* write LED MUX address space for each engine */
+       for (i = LP55XX_ENGINE_1; i <= LP55XX_ENGINE_3; i++) {
+               chip->engine_idx = i;
+               lp5523_load_engine_and_select_page(chip);
+
+               for (j = 0; j < LP5523_PROGRAM_LENGTH; j++) {
+                       ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + j,
+                                       pattern[i - 1][j]);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       lp5523_run_engine(chip, true);
+
+       /* Let the programs run for couple of ms and check the engine status */
+       usleep_range(3000, 6000);
+       lp55xx_read(chip, LP5523_REG_STATUS, &status);
+       status &= LP5523_ENG_STATUS_MASK;
+
+       if (status != LP5523_ENG_STATUS_MASK) {
+               dev_err(&chip->cl->dev,
+                       "cound not configure LED engine, status = 0x%.2x\n",
+                       status);
+               ret = -1;
+       }
+
+out:
+       lp5523_stop_engine(chip);
+       return ret;
+}
+
 static int lp5523_update_program_memory(struct lp55xx_chip *chip,
                                        const u8 *data, size_t size)
 {
        u8 pattern[LP5523_PROGRAM_LENGTH] = {0};
        unsigned cmd;
        char c[3];
-       int update_size;
        int nrchars;
-       int offset = 0;
        int ret;
-       int i;
-
-       /* clear program memory before updating */
-       for (i = 0; i < LP5523_PROGRAM_LENGTH; i++)
-               lp55xx_write(chip, LP5523_REG_PROG_MEM + i, 0);
+       int offset = 0;
+       int i = 0;
 
-       i = 0;
        while ((offset < size - 1) && (i < LP5523_PROGRAM_LENGTH)) {
                /* separate sscanfs because length is working only for %s */
                ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
@@ -263,11 +336,19 @@ static int lp5523_update_program_memory(struct lp55xx_chip *chip,
        if (i % 2)
                goto err;
 
-       update_size = i;
-       for (i = 0; i < update_size; i++)
-               lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]);
+       mutex_lock(&chip->lock);
 
-       return 0;
+       for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) {
+               ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]);
+               if (ret) {
+                       mutex_unlock(&chip->lock);
+                       return -EINVAL;
+               }
+       }
+
+       mutex_unlock(&chip->lock);
+
+       return size;
 
 err:
        dev_err(&chip->cl->dev, "wrong pattern format\n");
@@ -290,10 +371,196 @@ static void lp5523_firmware_loaded(struct lp55xx_chip *chip)
         *  2) write firmware data into program memory
         */
 
-       lp5523_load_engine(chip);
+       lp5523_load_engine_and_select_page(chip);
        lp5523_update_program_memory(chip, fw->data, fw->size);
 }
 
+static ssize_t show_engine_mode(struct device *dev,
+                               struct device_attribute *attr,
+                               char *buf, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+       enum lp55xx_engine_mode mode = chip->engines[nr - 1].mode;
+
+       switch (mode) {
+       case LP55XX_ENGINE_RUN:
+               return sprintf(buf, "run\n");
+       case LP55XX_ENGINE_LOAD:
+               return sprintf(buf, "load\n");
+       case LP55XX_ENGINE_DISABLED:
+       default:
+               return sprintf(buf, "disabled\n");
+       }
+}
+show_mode(1)
+show_mode(2)
+show_mode(3)
+
+static ssize_t store_engine_mode(struct device *dev,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+       struct lp55xx_engine *engine = &chip->engines[nr - 1];
+
+       mutex_lock(&chip->lock);
+
+       chip->engine_idx = nr;
+
+       if (!strncmp(buf, "run", 3)) {
+               lp5523_run_engine(chip, true);
+               engine->mode = LP55XX_ENGINE_RUN;
+       } else if (!strncmp(buf, "load", 4)) {
+               lp5523_stop_engine(chip);
+               lp5523_load_engine(chip);
+               engine->mode = LP55XX_ENGINE_LOAD;
+       } else if (!strncmp(buf, "disabled", 8)) {
+               lp5523_stop_engine(chip);
+               engine->mode = LP55XX_ENGINE_DISABLED;
+       }
+
+       mutex_unlock(&chip->lock);
+
+       return len;
+}
+store_mode(1)
+store_mode(2)
+store_mode(3)
+
+static int lp5523_mux_parse(const char *buf, u16 *mux, size_t len)
+{
+       u16 tmp_mux = 0;
+       int i;
+
+       len = min_t(int, len, LP5523_MAX_LEDS);
+
+       for (i = 0; i < len; i++) {
+               switch (buf[i]) {
+               case '1':
+                       tmp_mux |= (1 << i);
+                       break;
+               case '0':
+                       break;
+               case '\n':
+                       i = len;
+                       break;
+               default:
+                       return -1;
+               }
+       }
+       *mux = tmp_mux;
+
+       return 0;
+}
+
+static void lp5523_mux_to_array(u16 led_mux, char *array)
+{
+       int i, pos = 0;
+       for (i = 0; i < LP5523_MAX_LEDS; i++)
+               pos += sprintf(array + pos, "%x", LED_ACTIVE(led_mux, i));
+
+       array[pos] = '\0';
+}
+
+static ssize_t show_engine_leds(struct device *dev,
+                           struct device_attribute *attr,
+                           char *buf, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+       char mux[LP5523_MAX_LEDS + 1];
+
+       lp5523_mux_to_array(chip->engines[nr - 1].led_mux, mux);
+
+       return sprintf(buf, "%s\n", mux);
+}
+show_leds(1)
+show_leds(2)
+show_leds(3)
+
+static int lp5523_load_mux(struct lp55xx_chip *chip, u16 mux, int nr)
+{
+       struct lp55xx_engine *engine = &chip->engines[nr - 1];
+       int ret;
+       u8 mux_page[] = {
+               [LP55XX_ENGINE_1] = LP5523_PAGE_MUX1,
+               [LP55XX_ENGINE_2] = LP5523_PAGE_MUX2,
+               [LP55XX_ENGINE_3] = LP5523_PAGE_MUX3,
+       };
+
+       lp5523_load_engine(chip);
+
+       ret = lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, mux_page[nr]);
+       if (ret)
+               return ret;
+
+       ret = lp55xx_write(chip, LP5523_REG_PROG_MEM , (u8)(mux >> 8));
+       if (ret)
+               return ret;
+
+       ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + 1, (u8)(mux));
+       if (ret)
+               return ret;
+
+       engine->led_mux = mux;
+       return 0;
+}
+
+static ssize_t store_engine_leds(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+       struct lp55xx_engine *engine = &chip->engines[nr - 1];
+       u16 mux = 0;
+       ssize_t ret;
+
+       if (lp5523_mux_parse(buf, &mux, len))
+               return -EINVAL;
+
+       mutex_lock(&chip->lock);
+
+       chip->engine_idx = nr;
+       ret = -EINVAL;
+
+       if (engine->mode != LP55XX_ENGINE_LOAD)
+               goto leave;
+
+       if (lp5523_load_mux(chip, mux, nr))
+               goto leave;
+
+       ret = len;
+leave:
+       mutex_unlock(&chip->lock);
+       return ret;
+}
+store_leds(1)
+store_leds(2)
+store_leds(3)
+
+static ssize_t store_engine_load(struct device *dev,
+                            struct device_attribute *attr,
+                            const char *buf, size_t len, int nr)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev));
+       struct lp55xx_chip *chip = led->chip;
+
+       mutex_lock(&chip->lock);
+
+       chip->engine_idx = nr;
+       lp5523_load_engine_and_select_page(chip);
+
+       mutex_unlock(&chip->lock);
+
+       return lp5523_update_program_memory(chip, buf, len);
+}
+store_load(1)
+store_load(2)
+store_load(3)
+
 static ssize_t lp5523_selftest(struct device *dev,
                               struct device_attribute *attr,
                               char *buf)
@@ -393,9 +660,27 @@ static void lp5523_led_brightness_work(struct work_struct *work)
        mutex_unlock(&chip->lock);
 }
 
-static DEVICE_ATTR(selftest, S_IRUGO, lp5523_selftest, NULL);
+static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode);
+static LP55XX_DEV_ATTR_RW(engine2_mode, show_engine2_mode, store_engine2_mode);
+static LP55XX_DEV_ATTR_RW(engine3_mode, show_engine3_mode, store_engine3_mode);
+static LP55XX_DEV_ATTR_RW(engine1_leds, show_engine1_leds, store_engine1_leds);
+static LP55XX_DEV_ATTR_RW(engine2_leds, show_engine2_leds, store_engine2_leds);
+static LP55XX_DEV_ATTR_RW(engine3_leds, show_engine3_leds, store_engine3_leds);
+static LP55XX_DEV_ATTR_WO(engine1_load, store_engine1_load);
+static LP55XX_DEV_ATTR_WO(engine2_load, store_engine2_load);
+static LP55XX_DEV_ATTR_WO(engine3_load, store_engine3_load);
+static LP55XX_DEV_ATTR_RO(selftest, lp5523_selftest);
 
 static struct attribute *lp5523_attributes[] = {
+       &dev_attr_engine1_mode.attr,
+       &dev_attr_engine2_mode.attr,
+       &dev_attr_engine3_mode.attr,
+       &dev_attr_engine1_load.attr,
+       &dev_attr_engine2_load.attr,
+       &dev_attr_engine3_load.attr,
+       &dev_attr_engine1_leds.attr,
+       &dev_attr_engine2_leds.attr,
+       &dev_attr_engine3_leds.attr,
        &dev_attr_selftest.attr,
        NULL,
 };
@@ -432,7 +717,7 @@ static int lp5523_probe(struct i2c_client *client,
        struct lp55xx_platform_data *pdata;
        struct device_node *np = client->dev.of_node;
 
-       if (!client->dev.platform_data) {
+       if (!dev_get_platdata(&client->dev)) {
                if (np) {
                        ret = lp55xx_of_populate_pdata(&client->dev, np);
                        if (ret < 0)
@@ -442,7 +727,7 @@ static int lp5523_probe(struct i2c_client *client,
                        return -EINVAL;
                }
        }
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index cbd856dac15041c3c6396741aa7913bfee85ab34..2585cfd57711cba3feee4e664ef010402e2db841 100644 (file)
@@ -477,8 +477,8 @@ static ssize_t lp5562_store_engine_mux(struct device *dev,
        return len;
 }
 
-static DEVICE_ATTR(led_pattern, S_IWUSR, NULL, lp5562_store_pattern);
-static DEVICE_ATTR(engine_mux, S_IWUSR, NULL, lp5562_store_engine_mux);
+static LP55XX_DEV_ATTR_WO(led_pattern, lp5562_store_pattern);
+static LP55XX_DEV_ATTR_WO(engine_mux, lp5562_store_engine_mux);
 
 static struct attribute *lp5562_attributes[] = {
        &dev_attr_led_pattern.attr,
@@ -518,7 +518,7 @@ static int lp5562_probe(struct i2c_client *client,
        struct lp55xx_platform_data *pdata;
        struct device_node *np = client->dev.of_node;
 
-       if (!client->dev.platform_data) {
+       if (!dev_get_platdata(&client->dev)) {
                if (np) {
                        ret = lp55xx_of_populate_pdata(&client->dev, np);
                        if (ret < 0)
@@ -528,7 +528,7 @@ static int lp5562_probe(struct i2c_client *client,
                        return -EINVAL;
                }
        }
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
index c2fecd4d391ce33cee56aad60d3d1d80a62ffc02..351825b96f16b534923b36d97e5fd0ccaacbdf6c 100644 (file)
@@ -593,6 +593,9 @@ int lp55xx_of_populate_pdata(struct device *dev, struct device_node *np)
        of_property_read_string(np, "label", &pdata->label);
        of_property_read_u8(np, "clock-mode", &pdata->clock_mode);
 
+       /* LP8501 specific */
+       of_property_read_u8(np, "pwr-sel", (u8 *)&pdata->pwr_sel);
+
        dev->platform_data = pdata;
 
        return 0;
index dbbf86df0f1fcdbe4d14de589b7fc90ef85f1a24..cceab483edd04a14174224a0d8b253a738376e66 100644 (file)
@@ -20,8 +20,62 @@ enum lp55xx_engine_index {
        LP55XX_ENGINE_1,
        LP55XX_ENGINE_2,
        LP55XX_ENGINE_3,
+       LP55XX_ENGINE_MAX = LP55XX_ENGINE_3,
 };
 
+enum lp55xx_engine_mode {
+       LP55XX_ENGINE_DISABLED,
+       LP55XX_ENGINE_LOAD,
+       LP55XX_ENGINE_RUN,
+};
+
+#define LP55XX_DEV_ATTR_RW(name, show, store)  \
+       DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show, store)
+#define LP55XX_DEV_ATTR_RO(name, show)         \
+       DEVICE_ATTR(name, S_IRUGO, show, NULL)
+#define LP55XX_DEV_ATTR_WO(name, store)                \
+       DEVICE_ATTR(name, S_IWUSR, NULL, store)
+
+#define show_mode(nr)                                                  \
+static ssize_t show_engine##nr##_mode(struct device *dev,              \
+                                   struct device_attribute *attr,      \
+                                   char *buf)                          \
+{                                                                      \
+       return show_engine_mode(dev, attr, buf, nr);                    \
+}
+
+#define store_mode(nr)                                                 \
+static ssize_t store_engine##nr##_mode(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_mode(dev, attr, buf, len, nr);              \
+}
+
+#define show_leds(nr)                                                  \
+static ssize_t show_engine##nr##_leds(struct device *dev,              \
+                           struct device_attribute *attr,              \
+                           char *buf)                                  \
+{                                                                      \
+       return show_engine_leds(dev, attr, buf, nr);                    \
+}
+
+#define store_leds(nr)                                         \
+static ssize_t store_engine##nr##_leds(struct device *dev,     \
+                            struct device_attribute *attr,     \
+                            const char *buf, size_t len)       \
+{                                                              \
+       return store_engine_leds(dev, attr, buf, len, nr);      \
+}
+
+#define store_load(nr)                                                 \
+static ssize_t store_engine##nr##_load(struct device *dev,             \
+                                    struct device_attribute *attr,     \
+                                    const char *buf, size_t len)       \
+{                                                                      \
+       return store_engine_load(dev, attr, buf, len, nr);              \
+}
+
 struct lp55xx_led;
 struct lp55xx_chip;
 
@@ -71,6 +125,16 @@ struct lp55xx_device_config {
        const struct attribute_group *dev_attr_group;
 };
 
+/*
+ * struct lp55xx_engine
+ * @mode       : Engine mode
+ * @led_mux    : Mux bits for LED selection. Only used in LP5523
+ */
+struct lp55xx_engine {
+       enum lp55xx_engine_mode mode;
+       u16 led_mux;
+};
+
 /*
  * struct lp55xx_chip
  * @cl         : I2C communication for access registers
@@ -79,6 +143,7 @@ struct lp55xx_device_config {
  * @num_leds   : Number of registered LEDs
  * @cfg        : Device specific configuration data
  * @engine_idx : Selected engine number
+ * @engines    : Engine structure for the device attribute R/W interface
  * @fw         : Firmware data for running a LED pattern
  */
 struct lp55xx_chip {
@@ -89,6 +154,7 @@ struct lp55xx_chip {
        int num_leds;
        struct lp55xx_device_config *cfg;
        enum lp55xx_engine_index engine_idx;
+       struct lp55xx_engine engines[LP55XX_ENGINE_MAX];
        const struct firmware *fw;
 };
 
diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c
new file mode 100644 (file)
index 0000000..8d55a78
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * TI LP8501 9 channel LED Driver
+ *
+ * Copyright (C) 2013 Texas Instruments
+ *
+ * Author: Milo(Woogyom) Kim <milo.kim@ti.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/delay.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_data/leds-lp55xx.h>
+#include <linux/slab.h>
+
+#include "leds-lp55xx-common.h"
+
+#define LP8501_PROGRAM_LENGTH          32
+#define LP8501_MAX_LEDS                        9
+
+/* Registers */
+#define LP8501_REG_ENABLE              0x00
+#define LP8501_ENABLE                  BIT(6)
+#define LP8501_EXEC_M                  0x3F
+#define LP8501_EXEC_ENG1_M             0x30
+#define LP8501_EXEC_ENG2_M             0x0C
+#define LP8501_EXEC_ENG3_M             0x03
+#define LP8501_RUN_ENG1                        0x20
+#define LP8501_RUN_ENG2                        0x08
+#define LP8501_RUN_ENG3                        0x02
+
+#define LP8501_REG_OP_MODE             0x01
+#define LP8501_MODE_ENG1_M             0x30
+#define LP8501_MODE_ENG2_M             0x0C
+#define LP8501_MODE_ENG3_M             0x03
+#define LP8501_LOAD_ENG1               0x10
+#define LP8501_LOAD_ENG2               0x04
+#define LP8501_LOAD_ENG3               0x01
+
+#define LP8501_REG_PWR_CONFIG          0x05
+#define LP8501_PWR_CONFIG_M            0x03
+
+#define LP8501_REG_LED_PWM_BASE                0x16
+
+#define LP8501_REG_LED_CURRENT_BASE    0x26
+
+#define LP8501_REG_CONFIG              0x36
+#define LP8501_PWM_PSAVE               BIT(7)
+#define LP8501_AUTO_INC                        BIT(6)
+#define LP8501_PWR_SAVE                        BIT(5)
+#define LP8501_CP_AUTO                 0x18
+#define LP8501_INT_CLK                 BIT(0)
+#define LP8501_DEFAULT_CFG     \
+       (LP8501_PWM_PSAVE | LP8501_AUTO_INC | LP8501_PWR_SAVE | LP8501_CP_AUTO)
+
+#define LP8501_REG_RESET               0x3D
+#define LP8501_RESET                   0xFF
+
+#define LP8501_REG_PROG_PAGE_SEL       0x4F
+#define LP8501_PAGE_ENG1               0
+#define LP8501_PAGE_ENG2               1
+#define LP8501_PAGE_ENG3               2
+
+#define LP8501_REG_PROG_MEM            0x50
+
+#define LP8501_ENG1_IS_LOADING(mode)   \
+       ((mode & LP8501_MODE_ENG1_M) == LP8501_LOAD_ENG1)
+#define LP8501_ENG2_IS_LOADING(mode)   \
+       ((mode & LP8501_MODE_ENG2_M) == LP8501_LOAD_ENG2)
+#define LP8501_ENG3_IS_LOADING(mode)   \
+       ((mode & LP8501_MODE_ENG3_M) == LP8501_LOAD_ENG3)
+
+static inline void lp8501_wait_opmode_done(void)
+{
+       usleep_range(1000, 2000);
+}
+
+static void lp8501_set_led_current(struct lp55xx_led *led, u8 led_current)
+{
+       led->led_current = led_current;
+       lp55xx_write(led->chip, LP8501_REG_LED_CURRENT_BASE + led->chan_nr,
+               led_current);
+}
+
+static int lp8501_post_init_device(struct lp55xx_chip *chip)
+{
+       int ret;
+       u8 val = LP8501_DEFAULT_CFG;
+
+       ret = lp55xx_write(chip, LP8501_REG_ENABLE, LP8501_ENABLE);
+       if (ret)
+               return ret;
+
+       /* Chip startup time is 500 us, 1 - 2 ms gives some margin */
+       usleep_range(1000, 2000);
+
+       if (chip->pdata->clock_mode != LP55XX_CLOCK_EXT)
+               val |= LP8501_INT_CLK;
+
+       ret = lp55xx_write(chip, LP8501_REG_CONFIG, val);
+       if (ret)
+               return ret;
+
+       /* Power selection for each output */
+       return lp55xx_update_bits(chip, LP8501_REG_PWR_CONFIG,
+                               LP8501_PWR_CONFIG_M, chip->pdata->pwr_sel);
+}
+
+static void lp8501_load_engine(struct lp55xx_chip *chip)
+{
+       enum lp55xx_engine_index idx = chip->engine_idx;
+       u8 mask[] = {
+               [LP55XX_ENGINE_1] = LP8501_MODE_ENG1_M,
+               [LP55XX_ENGINE_2] = LP8501_MODE_ENG2_M,
+               [LP55XX_ENGINE_3] = LP8501_MODE_ENG3_M,
+       };
+
+       u8 val[] = {
+               [LP55XX_ENGINE_1] = LP8501_LOAD_ENG1,
+               [LP55XX_ENGINE_2] = LP8501_LOAD_ENG2,
+               [LP55XX_ENGINE_3] = LP8501_LOAD_ENG3,
+       };
+
+       u8 page_sel[] = {
+               [LP55XX_ENGINE_1] = LP8501_PAGE_ENG1,
+               [LP55XX_ENGINE_2] = LP8501_PAGE_ENG2,
+               [LP55XX_ENGINE_3] = LP8501_PAGE_ENG3,
+       };
+
+       lp55xx_update_bits(chip, LP8501_REG_OP_MODE, mask[idx], val[idx]);
+
+       lp8501_wait_opmode_done();
+
+       lp55xx_write(chip, LP8501_REG_PROG_PAGE_SEL, page_sel[idx]);
+}
+
+static void lp8501_stop_engine(struct lp55xx_chip *chip)
+{
+       lp55xx_write(chip, LP8501_REG_OP_MODE, 0);
+       lp8501_wait_opmode_done();
+}
+
+static void lp8501_turn_off_channels(struct lp55xx_chip *chip)
+{
+       int i;
+
+       for (i = 0; i < LP8501_MAX_LEDS; i++)
+               lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + i, 0);
+}
+
+static void lp8501_run_engine(struct lp55xx_chip *chip, bool start)
+{
+       int ret;
+       u8 mode;
+       u8 exec;
+
+       /* stop engine */
+       if (!start) {
+               lp8501_stop_engine(chip);
+               lp8501_turn_off_channels(chip);
+               return;
+       }
+
+       /*
+        * To run the engine,
+        * operation mode and enable register should updated at the same time
+        */
+
+       ret = lp55xx_read(chip, LP8501_REG_OP_MODE, &mode);
+       if (ret)
+               return;
+
+       ret = lp55xx_read(chip, LP8501_REG_ENABLE, &exec);
+       if (ret)
+               return;
+
+       /* change operation mode to RUN only when each engine is loading */
+       if (LP8501_ENG1_IS_LOADING(mode)) {
+               mode = (mode & ~LP8501_MODE_ENG1_M) | LP8501_RUN_ENG1;
+               exec = (exec & ~LP8501_EXEC_ENG1_M) | LP8501_RUN_ENG1;
+       }
+
+       if (LP8501_ENG2_IS_LOADING(mode)) {
+               mode = (mode & ~LP8501_MODE_ENG2_M) | LP8501_RUN_ENG2;
+               exec = (exec & ~LP8501_EXEC_ENG2_M) | LP8501_RUN_ENG2;
+       }
+
+       if (LP8501_ENG3_IS_LOADING(mode)) {
+               mode = (mode & ~LP8501_MODE_ENG3_M) | LP8501_RUN_ENG3;
+               exec = (exec & ~LP8501_EXEC_ENG3_M) | LP8501_RUN_ENG3;
+       }
+
+       lp55xx_write(chip, LP8501_REG_OP_MODE, mode);
+       lp8501_wait_opmode_done();
+
+       lp55xx_update_bits(chip, LP8501_REG_ENABLE, LP8501_EXEC_M, exec);
+}
+
+static int lp8501_update_program_memory(struct lp55xx_chip *chip,
+                                       const u8 *data, size_t size)
+{
+       u8 pattern[LP8501_PROGRAM_LENGTH] = {0};
+       unsigned cmd;
+       char c[3];
+       int update_size;
+       int nrchars;
+       int offset = 0;
+       int ret;
+       int i;
+
+       /* clear program memory before updating */
+       for (i = 0; i < LP8501_PROGRAM_LENGTH; i++)
+               lp55xx_write(chip, LP8501_REG_PROG_MEM + i, 0);
+
+       i = 0;
+       while ((offset < size - 1) && (i < LP8501_PROGRAM_LENGTH)) {
+               /* separate sscanfs because length is working only for %s */
+               ret = sscanf(data + offset, "%2s%n ", c, &nrchars);
+               if (ret != 1)
+                       goto err;
+
+               ret = sscanf(c, "%2x", &cmd);
+               if (ret != 1)
+                       goto err;
+
+               pattern[i] = (u8)cmd;
+               offset += nrchars;
+               i++;
+       }
+
+       /* Each instruction is 16bit long. Check that length is even */
+       if (i % 2)
+               goto err;
+
+       update_size = i;
+       for (i = 0; i < update_size; i++)
+               lp55xx_write(chip, LP8501_REG_PROG_MEM + i, pattern[i]);
+
+       return 0;
+
+err:
+       dev_err(&chip->cl->dev, "wrong pattern format\n");
+       return -EINVAL;
+}
+
+static void lp8501_firmware_loaded(struct lp55xx_chip *chip)
+{
+       const struct firmware *fw = chip->fw;
+
+       if (fw->size > LP8501_PROGRAM_LENGTH) {
+               dev_err(&chip->cl->dev, "firmware data size overflow: %zu\n",
+                       fw->size);
+               return;
+       }
+
+       /*
+        * Program momery sequence
+        *  1) set engine mode to "LOAD"
+        *  2) write firmware data into program memory
+        */
+
+       lp8501_load_engine(chip);
+       lp8501_update_program_memory(chip, fw->data, fw->size);
+}
+
+static void lp8501_led_brightness_work(struct work_struct *work)
+{
+       struct lp55xx_led *led = container_of(work, struct lp55xx_led,
+                                             brightness_work);
+       struct lp55xx_chip *chip = led->chip;
+
+       mutex_lock(&chip->lock);
+       lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
+                    led->brightness);
+       mutex_unlock(&chip->lock);
+}
+
+/* Chip specific configurations */
+static struct lp55xx_device_config lp8501_cfg = {
+       .reset = {
+               .addr = LP8501_REG_RESET,
+               .val  = LP8501_RESET,
+       },
+       .enable = {
+               .addr = LP8501_REG_ENABLE,
+               .val  = LP8501_ENABLE,
+       },
+       .max_channel  = LP8501_MAX_LEDS,
+       .post_init_device   = lp8501_post_init_device,
+       .brightness_work_fn = lp8501_led_brightness_work,
+       .set_led_current    = lp8501_set_led_current,
+       .firmware_cb        = lp8501_firmware_loaded,
+       .run_engine         = lp8501_run_engine,
+};
+
+static int lp8501_probe(struct i2c_client *client,
+                       const struct i2c_device_id *id)
+{
+       int ret;
+       struct lp55xx_chip *chip;
+       struct lp55xx_led *led;
+       struct lp55xx_platform_data *pdata;
+       struct device_node *np = client->dev.of_node;
+
+       if (!dev_get_platdata(&client->dev)) {
+               if (np) {
+                       ret = lp55xx_of_populate_pdata(&client->dev, np);
+                       if (ret < 0)
+                               return ret;
+               } else {
+                       dev_err(&client->dev, "no platform data\n");
+                       return -EINVAL;
+               }
+       }
+       pdata = dev_get_platdata(&client->dev);
+
+       chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       led = devm_kzalloc(&client->dev,
+                       sizeof(*led) * pdata->num_channels, GFP_KERNEL);
+       if (!led)
+               return -ENOMEM;
+
+       chip->cl = client;
+       chip->pdata = pdata;
+       chip->cfg = &lp8501_cfg;
+
+       mutex_init(&chip->lock);
+
+       i2c_set_clientdata(client, led);
+
+       ret = lp55xx_init_device(chip);
+       if (ret)
+               goto err_init;
+
+       dev_info(&client->dev, "%s Programmable led chip found\n", id->name);
+
+       ret = lp55xx_register_leds(led, chip);
+       if (ret)
+               goto err_register_leds;
+
+       ret = lp55xx_register_sysfs(chip);
+       if (ret) {
+               dev_err(&client->dev, "registering sysfs failed\n");
+               goto err_register_sysfs;
+       }
+
+       return 0;
+
+err_register_sysfs:
+       lp55xx_unregister_leds(led, chip);
+err_register_leds:
+       lp55xx_deinit_device(chip);
+err_init:
+       return ret;
+}
+
+static int lp8501_remove(struct i2c_client *client)
+{
+       struct lp55xx_led *led = i2c_get_clientdata(client);
+       struct lp55xx_chip *chip = led->chip;
+
+       lp8501_stop_engine(chip);
+       lp55xx_unregister_sysfs(chip);
+       lp55xx_unregister_leds(led, chip);
+       lp55xx_deinit_device(chip);
+
+       return 0;
+}
+
+static const struct i2c_device_id lp8501_id[] = {
+       { "lp8501",  0 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, lp8501_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_lp8501_leds_match[] = {
+       { .compatible = "ti,lp8501", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, of_lp8501_leds_match);
+#endif
+
+static struct i2c_driver lp8501_driver = {
+       .driver = {
+               .name   = "lp8501",
+               .of_match_table = of_match_ptr(of_lp8501_leds_match),
+       },
+       .probe          = lp8501_probe,
+       .remove         = lp8501_remove,
+       .id_table       = lp8501_id,
+};
+
+module_i2c_driver(lp8501_driver);
+
+MODULE_DESCRIPTION("Texas Instruments LP8501 LED drvier");
+MODULE_AUTHOR("Milo Kim");
+MODULE_LICENSE("GPL");
index ca48a7d5502d35fb919de639a4ddb067b6f80baf..3417e5be7b575fa8b44185a2f9fc9bfa9bd154a3 100644 (file)
@@ -135,7 +135,7 @@ static void delete_lt3593_led(struct lt3593_led_data *led)
 
 static int lt3593_led_probe(struct platform_device *pdev)
 {
-       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct lt3593_led_data *leds_data;
        int i, ret = 0;
 
@@ -169,7 +169,7 @@ err:
 static int lt3593_led_remove(struct platform_device *pdev)
 {
        int i;
-       struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
+       struct gpio_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct lt3593_led_data *leds_data;
 
        leds_data = platform_get_drvdata(pdev);
index c61c5ebcc08e824e4bea68e3184aabf191632a02..2f9f141084baa2c2743105fa06c30170b84c89ef 100644 (file)
@@ -306,7 +306,7 @@ create_netxbig_led(struct platform_device *pdev,
                   struct netxbig_led_data *led_dat,
                   const struct netxbig_led *template)
 {
-       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret;
 
        spin_lock_init(&led_dat->lock);
@@ -354,7 +354,7 @@ create_netxbig_led(struct platform_device *pdev,
 
 static int netxbig_led_probe(struct platform_device *pdev)
 {
-       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct netxbig_led_data *leds_data;
        int i;
        int ret;
@@ -391,7 +391,7 @@ err_free_leds:
 
 static int netxbig_led_remove(struct platform_device *pdev)
 {
-       struct netxbig_led_platform_data *pdata = pdev->dev.platform_data;
+       struct netxbig_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct netxbig_led_data *leds_data;
        int i;
 
index e7df9875c400f3af314a8aaf8d74ce0f323e720e..141f13438e80ff3c9846c79948cc954466511719 100644 (file)
@@ -321,7 +321,7 @@ static inline int sizeof_ns2_led_priv(int num_leds)
 
 static int ns2_led_probe(struct platform_device *pdev)
 {
-       struct ns2_led_platform_data *pdata = pdev->dev.platform_data;
+       struct ns2_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct ns2_led_priv *priv;
        int i;
        int ret;
index 0c597bdd23f9d175ed4e6ad69af6b446d02746f9..4a0e786b7832bb8834ea4e6a46e20f4e24cf7898 100644 (file)
@@ -446,7 +446,8 @@ static int pca9532_probe(struct i2c_client *client,
        const struct i2c_device_id *id)
 {
        struct pca9532_data *data = i2c_get_clientdata(client);
-       struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data;
+       struct pca9532_platform_data *pca9532_pdata =
+                       dev_get_platdata(&client->dev);
 
        if (!pca9532_pdata)
                return -EIO;
index edf485b773c8730960e0923615d0f8aba348ba04..c3a08b60535bc31048d1246c1d5ef01dd5c12c6b 100644 (file)
@@ -267,7 +267,7 @@ static int pca955x_probe(struct i2c_client *client,
 
        chip = &pca955x_chipdefs[id->driver_data];
        adapter = to_i2c_adapter(client->dev.parent);
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        /* Make sure the slave address / chip type combo given is possible */
        if ((client->addr & ~((1 << chip->slv_addr_shift) - 1)) !=
diff --git a/drivers/leds/leds-pca9633.c b/drivers/leds/leds-pca9633.c
deleted file mode 100644 (file)
index 9aae567..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright 2011 bct electronic GmbH
- *
- * Author: Peter Meerwald <p.meerwald@bct-electronic.com>
- *
- * Based on leds-pca955x.c
- *
- * This file is subject to the terms and conditions of version 2 of
- * the GNU General Public License.  See the file COPYING in the main
- * directory of this archive for more details.
- *
- * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
- *
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/leds.h>
-#include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/workqueue.h>
-#include <linux/slab.h>
-#include <linux/platform_data/leds-pca9633.h>
-
-/* LED select registers determine the source that drives LED outputs */
-#define PCA9633_LED_OFF                0x0     /* LED driver off */
-#define PCA9633_LED_ON         0x1     /* LED driver on */
-#define PCA9633_LED_PWM                0x2     /* Controlled through PWM */
-#define PCA9633_LED_GRP_PWM    0x3     /* Controlled through PWM/GRPPWM */
-
-#define PCA9633_MODE1          0x00
-#define PCA9633_MODE2          0x01
-#define PCA9633_PWM_BASE       0x02
-#define PCA9633_LEDOUT         0x08
-
-static const struct i2c_device_id pca9633_id[] = {
-       { "pca9633", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, pca9633_id);
-
-struct pca9633_led {
-       struct i2c_client *client;
-       struct work_struct work;
-       enum led_brightness brightness;
-       struct led_classdev led_cdev;
-       int led_num; /* 0 .. 3 potentially */
-       char name[32];
-};
-
-static void pca9633_led_work(struct work_struct *work)
-{
-       struct pca9633_led *pca9633 = container_of(work,
-               struct pca9633_led, work);
-       u8 ledout = i2c_smbus_read_byte_data(pca9633->client, PCA9633_LEDOUT);
-       int shift = 2 * pca9633->led_num;
-       u8 mask = 0x3 << shift;
-
-       switch (pca9633->brightness) {
-       case LED_FULL:
-               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
-                       (ledout & ~mask) | (PCA9633_LED_ON << shift));
-               break;
-       case LED_OFF:
-               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
-                       ledout & ~mask);
-               break;
-       default:
-               i2c_smbus_write_byte_data(pca9633->client,
-                       PCA9633_PWM_BASE + pca9633->led_num,
-                       pca9633->brightness);
-               i2c_smbus_write_byte_data(pca9633->client, PCA9633_LEDOUT,
-                       (ledout & ~mask) | (PCA9633_LED_PWM << shift));
-               break;
-       }
-}
-
-static void pca9633_led_set(struct led_classdev *led_cdev,
-       enum led_brightness value)
-{
-       struct pca9633_led *pca9633;
-
-       pca9633 = container_of(led_cdev, struct pca9633_led, led_cdev);
-
-       pca9633->brightness = value;
-
-       /*
-        * Must use workqueue for the actual I/O since I2C operations
-        * can sleep.
-        */
-       schedule_work(&pca9633->work);
-}
-
-static int pca9633_probe(struct i2c_client *client,
-                                       const struct i2c_device_id *id)
-{
-       struct pca9633_led *pca9633;
-       struct pca9633_platform_data *pdata;
-       int i, err;
-
-       pdata = client->dev.platform_data;
-
-       if (pdata) {
-               if (pdata->leds.num_leds <= 0 || pdata->leds.num_leds > 4) {
-                       dev_err(&client->dev, "board info must claim at most 4 LEDs");
-                       return -EINVAL;
-               }
-       }
-
-       pca9633 = devm_kzalloc(&client->dev, 4 * sizeof(*pca9633), GFP_KERNEL);
-       if (!pca9633)
-               return -ENOMEM;
-
-       i2c_set_clientdata(client, pca9633);
-
-       for (i = 0; i < 4; i++) {
-               pca9633[i].client = client;
-               pca9633[i].led_num = i;
-
-               /* Platform data can specify LED names and default triggers */
-               if (pdata && i < pdata->leds.num_leds) {
-                       if (pdata->leds.leds[i].name)
-                               snprintf(pca9633[i].name,
-                                        sizeof(pca9633[i].name), "pca9633:%s",
-                                        pdata->leds.leds[i].name);
-                       if (pdata->leds.leds[i].default_trigger)
-                               pca9633[i].led_cdev.default_trigger =
-                                       pdata->leds.leds[i].default_trigger;
-               } else {
-                       snprintf(pca9633[i].name, sizeof(pca9633[i].name),
-                                "pca9633:%d", i);
-               }
-
-               pca9633[i].led_cdev.name = pca9633[i].name;
-               pca9633[i].led_cdev.brightness_set = pca9633_led_set;
-
-               INIT_WORK(&pca9633[i].work, pca9633_led_work);
-
-               err = led_classdev_register(&client->dev, &pca9633[i].led_cdev);
-               if (err < 0)
-                       goto exit;
-       }
-
-       /* Disable LED all-call address and set normal mode */
-       i2c_smbus_write_byte_data(client, PCA9633_MODE1, 0x00);
-
-       /* Configure output: open-drain or totem pole (push-pull) */
-       if (pdata && pdata->outdrv == PCA9633_OPEN_DRAIN)
-               i2c_smbus_write_byte_data(client, PCA9633_MODE2, 0x01);
-
-       /* Turn off LEDs */
-       i2c_smbus_write_byte_data(client, PCA9633_LEDOUT, 0x00);
-
-       return 0;
-
-exit:
-       while (i--) {
-               led_classdev_unregister(&pca9633[i].led_cdev);
-               cancel_work_sync(&pca9633[i].work);
-       }
-
-       return err;
-}
-
-static int pca9633_remove(struct i2c_client *client)
-{
-       struct pca9633_led *pca9633 = i2c_get_clientdata(client);
-       int i;
-
-       for (i = 0; i < 4; i++) {
-               led_classdev_unregister(&pca9633[i].led_cdev);
-               cancel_work_sync(&pca9633[i].work);
-       }
-
-       return 0;
-}
-
-static struct i2c_driver pca9633_driver = {
-       .driver = {
-               .name   = "leds-pca9633",
-               .owner  = THIS_MODULE,
-       },
-       .probe  = pca9633_probe,
-       .remove = pca9633_remove,
-       .id_table = pca9633_id,
-};
-
-module_i2c_driver(pca9633_driver);
-
-MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>");
-MODULE_DESCRIPTION("PCA9633 LED driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c
new file mode 100644 (file)
index 0000000..82589c0
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2011 bct electronic GmbH
+ * Copyright 2013 Qtechnology/AS
+ *
+ * Author: Peter Meerwald <p.meerwald@bct-electronic.com>
+ * Author: Ricardo Ribalda <ricardo.ribalda@gmail.com>
+ *
+ * Based on leds-pca955x.c
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * LED driver for the PCA9633 I2C LED driver (7-bit slave address 0x62)
+ * LED driver for the PCA9634 I2C LED driver (7-bit slave address set by hw.)
+ *
+ * Note that hardware blinking violates the leds infrastructure driver
+ * interface since the hardware only supports blinking all LEDs with the
+ * same delay_on/delay_off rates.  That is, only the LEDs that are set to
+ * blink will actually blink but all LEDs that are set to blink will blink
+ * in identical fashion.  The delay_on/delay_off values of the last LED
+ * that is set to blink will be used for all of the blinking LEDs.
+ * Hardware blinking is disabled by default but can be enabled by setting
+ * the 'blink_type' member in the platform_data struct to 'PCA963X_HW_BLINK'
+ * or by adding the 'nxp,hw-blink' property to the DTS.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/leds.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/platform_data/leds-pca963x.h>
+
+/* LED select registers determine the source that drives LED outputs */
+#define PCA963X_LED_OFF                0x0     /* LED driver off */
+#define PCA963X_LED_ON         0x1     /* LED driver on */
+#define PCA963X_LED_PWM                0x2     /* Controlled through PWM */
+#define PCA963X_LED_GRP_PWM    0x3     /* Controlled through PWM/GRPPWM */
+
+#define PCA963X_MODE2_DMBLNK   0x20    /* Enable blinking */
+
+#define PCA963X_MODE1          0x00
+#define PCA963X_MODE2          0x01
+#define PCA963X_PWM_BASE       0x02
+
+enum pca963x_type {
+       pca9633,
+       pca9634,
+};
+
+struct pca963x_chipdef {
+       u8                      grppwm;
+       u8                      grpfreq;
+       u8                      ledout_base;
+       int                     n_leds;
+};
+
+static struct pca963x_chipdef pca963x_chipdefs[] = {
+       [pca9633] = {
+               .grppwm         = 0x6,
+               .grpfreq        = 0x7,
+               .ledout_base    = 0x8,
+               .n_leds         = 4,
+       },
+       [pca9634] = {
+               .grppwm         = 0xa,
+               .grpfreq        = 0xb,
+               .ledout_base    = 0xc,
+               .n_leds         = 8,
+       },
+};
+
+/* Total blink period in milliseconds */
+#define PCA963X_BLINK_PERIOD_MIN       42
+#define PCA963X_BLINK_PERIOD_MAX       10667
+
+static const struct i2c_device_id pca963x_id[] = {
+       { "pca9632", pca9633 },
+       { "pca9633", pca9633 },
+       { "pca9634", pca9634 },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, pca963x_id);
+
+enum pca963x_cmd {
+       BRIGHTNESS_SET,
+       BLINK_SET,
+};
+
+struct pca963x_led;
+
+struct pca963x {
+       struct pca963x_chipdef *chipdef;
+       struct mutex mutex;
+       struct i2c_client *client;
+       struct pca963x_led *leds;
+};
+
+struct pca963x_led {
+       struct pca963x *chip;
+       struct work_struct work;
+       enum led_brightness brightness;
+       struct led_classdev led_cdev;
+       int led_num; /* 0 .. 7 potentially */
+       enum pca963x_cmd cmd;
+       char name[32];
+       u8 gdc;
+       u8 gfrq;
+};
+
+static void pca963x_brightness_work(struct pca963x_led *pca963x)
+{
+       u8 ledout_addr = pca963x->chip->chipdef->ledout_base
+               + (pca963x->led_num / 4);
+       u8 ledout;
+       int shift = 2 * (pca963x->led_num % 4);
+       u8 mask = 0x3 << shift;
+
+       mutex_lock(&pca963x->chip->mutex);
+       ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
+       switch (pca963x->brightness) {
+       case LED_FULL:
+               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+                       (ledout & ~mask) | (PCA963X_LED_ON << shift));
+               break;
+       case LED_OFF:
+               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+                       ledout & ~mask);
+               break;
+       default:
+               i2c_smbus_write_byte_data(pca963x->chip->client,
+                       PCA963X_PWM_BASE + pca963x->led_num,
+                       pca963x->brightness);
+               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+                       (ledout & ~mask) | (PCA963X_LED_PWM << shift));
+               break;
+       }
+       mutex_unlock(&pca963x->chip->mutex);
+}
+
+static void pca963x_blink_work(struct pca963x_led *pca963x)
+{
+       u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
+               (pca963x->led_num / 4);
+       u8 ledout;
+       u8 mode2 = i2c_smbus_read_byte_data(pca963x->chip->client,
+                                                       PCA963X_MODE2);
+       int shift = 2 * (pca963x->led_num % 4);
+       u8 mask = 0x3 << shift;
+
+       i2c_smbus_write_byte_data(pca963x->chip->client,
+                       pca963x->chip->chipdef->grppwm, pca963x->gdc);
+
+       i2c_smbus_write_byte_data(pca963x->chip->client,
+                       pca963x->chip->chipdef->grpfreq, pca963x->gfrq);
+
+       if (!(mode2 & PCA963X_MODE2_DMBLNK))
+               i2c_smbus_write_byte_data(pca963x->chip->client, PCA963X_MODE2,
+                       mode2 | PCA963X_MODE2_DMBLNK);
+
+       mutex_lock(&pca963x->chip->mutex);
+       ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
+       if ((ledout & mask) != (PCA963X_LED_GRP_PWM << shift))
+               i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+                       (ledout & ~mask) | (PCA963X_LED_GRP_PWM << shift));
+       mutex_unlock(&pca963x->chip->mutex);
+}
+
+static void pca963x_work(struct work_struct *work)
+{
+       struct pca963x_led *pca963x = container_of(work,
+               struct pca963x_led, work);
+
+       switch (pca963x->cmd) {
+       case BRIGHTNESS_SET:
+               pca963x_brightness_work(pca963x);
+               break;
+       case BLINK_SET:
+               pca963x_blink_work(pca963x);
+               break;
+       }
+}
+
+static void pca963x_led_set(struct led_classdev *led_cdev,
+       enum led_brightness value)
+{
+       struct pca963x_led *pca963x;
+
+       pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
+
+       pca963x->cmd = BRIGHTNESS_SET;
+       pca963x->brightness = value;
+
+       /*
+        * Must use workqueue for the actual I/O since I2C operations
+        * can sleep.
+        */
+       schedule_work(&pca963x->work);
+}
+
+static int pca963x_blink_set(struct led_classdev *led_cdev,
+               unsigned long *delay_on, unsigned long *delay_off)
+{
+       struct pca963x_led *pca963x;
+       unsigned long time_on, time_off, period;
+       u8 gdc, gfrq;
+
+       pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
+
+       time_on = *delay_on;
+       time_off = *delay_off;
+
+       /* If both zero, pick reasonable defaults of 500ms each */
+       if (!time_on && !time_off) {
+               time_on = 500;
+               time_off = 500;
+       }
+
+       period = time_on + time_off;
+
+       /* If period not supported by hardware, default to someting sane. */
+       if ((period < PCA963X_BLINK_PERIOD_MIN) ||
+           (period > PCA963X_BLINK_PERIOD_MAX)) {
+               time_on = 500;
+               time_off = 500;
+               period = time_on + time_off;
+       }
+
+       /*
+        * From manual: duty cycle = (GDC / 256) ->
+        *      (time_on / period) = (GDC / 256) ->
+        *              GDC = ((time_on * 256) / period)
+        */
+       gdc = (time_on * 256) / period;
+
+       /*
+        * From manual: period = ((GFRQ + 1) / 24) in seconds.
+        * So, period (in ms) = (((GFRQ + 1) / 24) * 1000) ->
+        *              GFRQ = ((period * 24 / 1000) - 1)
+        */
+       gfrq = (period * 24 / 1000) - 1;
+
+       pca963x->cmd = BLINK_SET;
+       pca963x->gdc = gdc;
+       pca963x->gfrq = gfrq;
+
+       /*
+        * Must use workqueue for the actual I/O since I2C operations
+        * can sleep.
+        */
+       schedule_work(&pca963x->work);
+
+       *delay_on = time_on;
+       *delay_off = time_off;
+
+       return 0;
+}
+
+#if IS_ENABLED(CONFIG_OF)
+static struct pca963x_platform_data *
+pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip)
+{
+       struct device_node *np = client->dev.of_node, *child;
+       struct pca963x_platform_data *pdata;
+       struct led_info *pca963x_leds;
+       int count;
+
+       count = of_get_child_count(np);
+       if (!count || count > chip->n_leds)
+               return ERR_PTR(-ENODEV);
+
+       pca963x_leds = devm_kzalloc(&client->dev,
+                       sizeof(struct led_info) * chip->n_leds, GFP_KERNEL);
+       if (!pca963x_leds)
+               return ERR_PTR(-ENOMEM);
+
+       for_each_child_of_node(np, child) {
+               struct led_info led;
+               u32 reg;
+               int res;
+
+               res = of_property_read_u32(child, "reg", &reg);
+               if ((res != 0) || (reg >= chip->n_leds))
+                       continue;
+               led.name =
+                       of_get_property(child, "label", NULL) ? : child->name;
+               led.default_trigger =
+                       of_get_property(child, "linux,default-trigger", NULL);
+               pca963x_leds[reg] = led;
+       }
+       pdata = devm_kzalloc(&client->dev,
+                            sizeof(struct pca963x_platform_data), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       pdata->leds.leds = pca963x_leds;
+       pdata->leds.num_leds = chip->n_leds;
+
+       /* default to open-drain unless totem pole (push-pull) is specified */
+       if (of_property_read_bool(np, "nxp,totem-pole"))
+               pdata->outdrv = PCA963X_TOTEM_POLE;
+       else
+               pdata->outdrv = PCA963X_OPEN_DRAIN;
+
+       /* default to software blinking unless hardware blinking is specified */
+       if (of_property_read_bool(np, "nxp,hw-blink"))
+               pdata->blink_type = PCA963X_HW_BLINK;
+       else
+               pdata->blink_type = PCA963X_SW_BLINK;
+
+       return pdata;
+}
+
+static const struct of_device_id of_pca963x_match[] = {
+       { .compatible = "nxp,pca9632", },
+       { .compatible = "nxp,pca9633", },
+       { .compatible = "nxp,pca9634", },
+       {},
+};
+#else
+static struct pca963x_platform_data *
+pca963x_dt_init(struct i2c_client *client, struct pca963x_chipdef *chip)
+{
+       return ERR_PTR(-ENODEV);
+}
+#endif
+
+static int pca963x_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct pca963x *pca963x_chip;
+       struct pca963x_led *pca963x;
+       struct pca963x_platform_data *pdata;
+       struct pca963x_chipdef *chip;
+       int i, err;
+
+       chip = &pca963x_chipdefs[id->driver_data];
+       pdata = dev_get_platdata(&client->dev);
+
+       if (!pdata) {
+               pdata = pca963x_dt_init(client, chip);
+               if (IS_ERR(pdata)) {
+                       dev_warn(&client->dev, "could not parse configuration\n");
+                       pdata = NULL;
+               }
+       }
+
+       if (pdata && (pdata->leds.num_leds < 1 ||
+                                pdata->leds.num_leds > chip->n_leds)) {
+               dev_err(&client->dev, "board info must claim 1-%d LEDs",
+                                                               chip->n_leds);
+               return -EINVAL;
+       }
+
+       pca963x_chip = devm_kzalloc(&client->dev, sizeof(*pca963x_chip),
+                                                               GFP_KERNEL);
+       if (!pca963x_chip)
+               return -ENOMEM;
+       pca963x = devm_kzalloc(&client->dev, chip->n_leds * sizeof(*pca963x),
+                                                               GFP_KERNEL);
+       if (!pca963x)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, pca963x_chip);
+
+       mutex_init(&pca963x_chip->mutex);
+       pca963x_chip->chipdef = chip;
+       pca963x_chip->client = client;
+       pca963x_chip->leds = pca963x;
+
+       /* Turn off LEDs by default*/
+       i2c_smbus_write_byte_data(client, chip->ledout_base, 0x00);
+       if (chip->n_leds > 4)
+               i2c_smbus_write_byte_data(client, chip->ledout_base + 1, 0x00);
+
+       for (i = 0; i < chip->n_leds; i++) {
+               pca963x[i].led_num = i;
+               pca963x[i].chip = pca963x_chip;
+
+               /* Platform data can specify LED names and default triggers */
+               if (pdata && i < pdata->leds.num_leds) {
+                       if (pdata->leds.leds[i].name)
+                               snprintf(pca963x[i].name,
+                                        sizeof(pca963x[i].name), "pca963x:%s",
+                                        pdata->leds.leds[i].name);
+                       if (pdata->leds.leds[i].default_trigger)
+                               pca963x[i].led_cdev.default_trigger =
+                                       pdata->leds.leds[i].default_trigger;
+               }
+               if (!pdata || i >= pdata->leds.num_leds ||
+                                               !pdata->leds.leds[i].name)
+                       snprintf(pca963x[i].name, sizeof(pca963x[i].name),
+                                "pca963x:%d:%.2x:%d", client->adapter->nr,
+                                client->addr, i);
+
+               pca963x[i].led_cdev.name = pca963x[i].name;
+               pca963x[i].led_cdev.brightness_set = pca963x_led_set;
+
+               if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
+                       pca963x[i].led_cdev.blink_set = pca963x_blink_set;
+
+               INIT_WORK(&pca963x[i].work, pca963x_work);
+
+               err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
+               if (err < 0)
+                       goto exit;
+       }
+
+       /* Disable LED all-call address and set normal mode */
+       i2c_smbus_write_byte_data(client, PCA963X_MODE1, 0x00);
+
+       /* Configure output: open-drain or totem pole (push-pull) */
+       if (pdata && pdata->outdrv == PCA963X_OPEN_DRAIN)
+               i2c_smbus_write_byte_data(client, PCA963X_MODE2, 0x01);
+
+       return 0;
+
+exit:
+       while (i--) {
+               led_classdev_unregister(&pca963x[i].led_cdev);
+               cancel_work_sync(&pca963x[i].work);
+       }
+
+       return err;
+}
+
+static int pca963x_remove(struct i2c_client *client)
+{
+       struct pca963x *pca963x = i2c_get_clientdata(client);
+       int i;
+
+       for (i = 0; i < pca963x->chipdef->n_leds; i++) {
+               led_classdev_unregister(&pca963x->leds[i].led_cdev);
+               cancel_work_sync(&pca963x->leds[i].work);
+       }
+
+       return 0;
+}
+
+static struct i2c_driver pca963x_driver = {
+       .driver = {
+               .name   = "leds-pca963x",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(of_pca963x_match),
+       },
+       .probe  = pca963x_probe,
+       .remove = pca963x_remove,
+       .id_table = pca963x_id,
+};
+
+module_i2c_driver(pca963x_driver);
+
+MODULE_AUTHOR("Peter Meerwald <p.meerwald@bct-electronic.com>");
+MODULE_DESCRIPTION("PCA963X LED driver");
+MODULE_LICENSE("GPL v2");
index faf52c005e8c230ef255407294e3f44b6beb6b0b..bb6f948985413d4e8c1f5a6b575493a00b2ecef6 100644 (file)
@@ -147,7 +147,7 @@ err:
 
 static int led_pwm_probe(struct platform_device *pdev)
 {
-       struct led_pwm_platform_data *pdata = pdev->dev.platform_data;
+       struct led_pwm_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct led_pwm_priv *priv;
        int i, ret = 0;
 
index 4253a9b03dbfd6b520691003e640bb8e6f0cf29e..358430db6e66d2e2adce01fff0a0ffa66ed8c830 100644 (file)
@@ -142,7 +142,8 @@ static void regulator_led_brightness_set(struct led_classdev *led_cdev,
 
 static int regulator_led_probe(struct platform_device *pdev)
 {
-       struct led_regulator_platform_data *pdata = pdev->dev.platform_data;
+       struct led_regulator_platform_data *pdata =
+                       dev_get_platdata(&pdev->dev);
        struct regulator_led *led;
        struct regulator *vcc;
        int ret = 0;
index e1a0df63a37f7dcdfdf73660a7a9643c4ba68a3d..76483fb5ee45e4f04a025265cb75fffc47c7b932 100644 (file)
@@ -71,7 +71,7 @@ static int s3c24xx_led_remove(struct platform_device *dev)
 
 static int s3c24xx_led_probe(struct platform_device *dev)
 {
-       struct s3c24xx_led_platdata *pdata = dev->dev.platform_data;
+       struct s3c24xx_led_platdata *pdata = dev_get_platdata(&dev->dev);
        struct s3c24xx_gpio_led *led;
        int ret;
 
index 64e204e714f66127caee347fe11089af4a8d164d..5b8f938a8d734995e43eda073c3db077d2875183 100644 (file)
@@ -91,7 +91,7 @@ MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
  * detected as working, but in reality it is not) as low as
  * possible.
  */
-static struct dmi_system_id __initdata nas_led_whitelist[] = {
+static struct dmi_system_id nas_led_whitelist[] __initdata = {
        {
                .callback = ss4200_led_dmi_callback,
                .ident = "Intel SS4200-E",
@@ -197,7 +197,7 @@ static void nasgpio_led_set_attr(struct led_classdev *led_cdev,
        spin_unlock(&nasgpio_gpio_lock);
 }
 
-u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
+static u32 nasgpio_led_get_attr(struct led_classdev *led_cdev, u32 port)
 {
        struct nasgpio_led *led = led_classdev_to_nasgpio_led(led_cdev);
        u32 gpio_in;
index 98fe021ba276f9db64fccc23cca6896245c15e1f..8cc304f36728a4e217cbf6716f893a3e6f5aed0c 100644 (file)
@@ -737,7 +737,7 @@ static int tca6507_probe(struct i2c_client *client,
        int i = 0;
 
        adapter = to_i2c_adapter(client->dev.parent);
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
                return -EIO;
index 120815a427014dc80bf5ebb5ccce35c52e4ec46b..0a1a13f3a6a51b1037bc7f61899d645c5aa8b115 100644 (file)
@@ -230,9 +230,9 @@ static int wm831x_status_probe(struct platform_device *pdev)
        int id = pdev->id % ARRAY_SIZE(chip_pdata->status);
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+       res = platform_get_resource(pdev, IORESOURCE_REG, 0);
        if (res == NULL) {
-               dev_err(&pdev->dev, "No I/O resource\n");
+               dev_err(&pdev->dev, "No register resource\n");
                ret = -EINVAL;
                goto err;
        }
@@ -246,8 +246,8 @@ static int wm831x_status_probe(struct platform_device *pdev)
        drvdata->wm831x = wm831x;
        drvdata->reg = res->start;
 
-       if (wm831x->dev->platform_data)
-               chip_pdata = wm831x->dev->platform_data;
+       if (dev_get_platdata(wm831x->dev))
+               chip_pdata = dev_get_platdata(wm831x->dev);
        else
                chip_pdata = NULL;
 
index 8a181d56602d89f601ebfdc4766b8744f141b759..3f75fd22fd495d0db8bf552061355be43315a8e8 100644 (file)
@@ -203,7 +203,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
 {
        struct regulator *isink, *dcdc;
        struct wm8350_led *led;
-       struct wm8350_led_platform_data *pdata = pdev->dev.platform_data;
+       struct wm8350_led_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int i;
 
        if (pdata == NULL) {
index 3c9c88a07eb8e45b42e78704940feb3ce4ff804c..47e55aa9eefae1571b4f45060a0532d9733019ec 100644 (file)
@@ -36,26 +36,28 @@ static int fb_notifier_callback(struct notifier_block *p,
                                        struct bl_trig_notifier, notifier);
        struct led_classdev *led = n->led;
        struct fb_event *fb_event = data;
-       int *blank = fb_event->data;
-       int new_status = *blank ? BLANK : UNBLANK;
+       int *blank;
+       int new_status;
 
-       switch (event) {
-       case FB_EVENT_BLANK:
-               if (new_status == n->old_status)
-                       break;
+       /* If we aren't interested in this event, skip it immediately ... */
+       if (event != FB_EVENT_BLANK)
+               return 0;
 
-               if ((n->old_status == UNBLANK) ^ n->invert) {
-                       n->brightness = led->brightness;
-                       __led_set_brightness(led, LED_OFF);
-               } else {
-                       __led_set_brightness(led, n->brightness);
-               }
+       blank = fb_event->data;
+       new_status = *blank ? BLANK : UNBLANK;
 
-               n->old_status = new_status;
+       if (new_status == n->old_status)
+               return 0;
 
-               break;
+       if ((n->old_status == UNBLANK) ^ n->invert) {
+               n->brightness = led->brightness;
+               __led_set_brightness(led, LED_OFF);
+       } else {
+               __led_set_brightness(led, n->brightness);
        }
 
+       n->old_status = new_status;
+
        return 0;
 }
 
index 28433a155d67da1599dd2b63c852737d7ab9c67f..70dfcdc29f1f9e9d8cfc764d69ab7a965daf5c25 100644 (file)
@@ -139,6 +139,16 @@ static void set_guest_interrupt(struct lg_cpu *cpu, u32 lo, u32 hi,
        cpu->regs->cs = (__KERNEL_CS|GUEST_PL);
        cpu->regs->eip = idt_address(lo, hi);
 
+       /*
+        * Trapping always clears these flags:
+        * TF: Trap flag
+        * VM: Virtual 8086 mode
+        * RF: Resume
+        * NT: Nested task.
+        */
+       cpu->regs->eflags &=
+               ~(X86_EFLAGS_TF|X86_EFLAGS_VM|X86_EFLAGS_RF|X86_EFLAGS_NT);
+
        /*
         * There are two kinds of interrupt handlers: 0xE is an "interrupt
         * gate" which expects interrupts to be disabled on entry.
index a35d8d100165e6efaf1536f90f37aa002b87f1ad..bfb39bb56ef1b3cd03204a9cd010fa81ec418350 100644 (file)
@@ -669,8 +669,10 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
 
 #ifdef CONFIG_X86_PAE
        gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
-       if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+       if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) {
                kill_guest(cpu, "Bad address %#lx", vaddr);
+               return -1UL;
+       }
        gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
 #else
        gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);
index 5ef78efc27f2812155b50aca064e1a5679015f8f..2acc43fe02297dff29fe0b00635100cb42703708 100644 (file)
@@ -3,7 +3,7 @@
 #
 
 dm-mod-y       += dm.o dm-table.o dm-target.o dm-linear.o dm-stripe.o \
-                  dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o
+                  dm-ioctl.o dm-io.o dm-kcopyd.o dm-sysfs.o dm-stats.o
 dm-multipath-y += dm-path-selector.o dm-mpath.o
 dm-snapshot-y  += dm-snap.o dm-exception-store.o dm-snap-transient.o \
                    dm-snap-persistent.o
index ee372884c405444886671901e45c3834626f383a..f9764e61978b5749487862b5ab88eb73b13f18ba 100644 (file)
@@ -597,24 +597,19 @@ static int mca_reap(struct btree *b, struct closure *cl, unsigned min_order)
        return 0;
 }
 
-static int bch_mca_shrink(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long bch_mca_scan(struct shrinker *shrink,
+                                 struct shrink_control *sc)
 {
        struct cache_set *c = container_of(shrink, struct cache_set, shrink);
        struct btree *b, *t;
        unsigned long i, nr = sc->nr_to_scan;
+       unsigned long freed = 0;
 
        if (c->shrinker_disabled)
-               return 0;
+               return SHRINK_STOP;
 
        if (c->try_harder)
-               return 0;
-
-       /*
-        * If nr == 0, we're supposed to return the number of items we have
-        * cached. Not allowed to return -1.
-        */
-       if (!nr)
-               return mca_can_free(c) * c->btree_pages;
+               return SHRINK_STOP;
 
        /* Return -1 if we can't do anything right now */
        if (sc->gfp_mask & __GFP_WAIT)
@@ -634,14 +629,14 @@ static int bch_mca_shrink(struct shrinker *shrink, struct shrink_control *sc)
 
        i = 0;
        list_for_each_entry_safe(b, t, &c->btree_cache_freeable, list) {
-               if (!nr)
+               if (freed >= nr)
                        break;
 
                if (++i > 3 &&
                    !mca_reap(b, NULL, 0)) {
                        mca_data_free(b);
                        rw_unlock(true, b);
-                       --nr;
+                       freed++;
                }
        }
 
@@ -652,7 +647,7 @@ static int bch_mca_shrink(struct shrinker *shrink, struct shrink_control *sc)
        if (list_empty(&c->btree_cache))
                goto out;
 
-       for (i = 0; nr && i < c->bucket_cache_used; i++) {
+       for (i = 0; (nr--) && i < c->bucket_cache_used; i++) {
                b = list_first_entry(&c->btree_cache, struct btree, list);
                list_rotate_left(&c->btree_cache);
 
@@ -661,14 +656,27 @@ static int bch_mca_shrink(struct shrinker *shrink, struct shrink_control *sc)
                        mca_bucket_free(b);
                        mca_data_free(b);
                        rw_unlock(true, b);
-                       --nr;
+                       freed++;
                } else
                        b->accessed = 0;
        }
 out:
-       nr = mca_can_free(c) * c->btree_pages;
        mutex_unlock(&c->bucket_lock);
-       return nr;
+       return freed;
+}
+
+static unsigned long bch_mca_count(struct shrinker *shrink,
+                                  struct shrink_control *sc)
+{
+       struct cache_set *c = container_of(shrink, struct cache_set, shrink);
+
+       if (c->shrinker_disabled)
+               return 0;
+
+       if (c->try_harder)
+               return 0;
+
+       return mca_can_free(c) * c->btree_pages;
 }
 
 void bch_btree_cache_free(struct cache_set *c)
@@ -737,7 +745,8 @@ int bch_btree_cache_alloc(struct cache_set *c)
                c->verify_data = NULL;
 #endif
 
-       c->shrink.shrink = bch_mca_shrink;
+       c->shrink.count_objects = bch_mca_count;
+       c->shrink.scan_objects = bch_mca_scan;
        c->shrink.seeks = 4;
        c->shrink.batch = c->btree_pages * 2;
        register_shrinker(&c->shrink);
index 12a2c2846f994a1e2d51bf79374426df96893418..4fe6ab2fbe2ede59644441521aa4cc2f27f5d312 100644 (file)
@@ -556,7 +556,7 @@ STORE(__bch_cache_set)
                struct shrink_control sc;
                sc.gfp_mask = GFP_KERNEL;
                sc.nr_to_scan = strtoul_or_return(buf);
-               c->shrink.shrink(&c->shrink, &sc);
+               c->shrink.scan_objects(&c->shrink, &sc);
        }
 
        sysfs_strtoul(congested_read_threshold_us,
index 5227e079a6e3b27afd71bcbdc2d03fa01e211ceb..173cbb20d10498b21440ada78b27f241b47af2cc 100644 (file)
@@ -1425,62 +1425,75 @@ static int __cleanup_old_buffer(struct dm_buffer *b, gfp_t gfp,
                                unsigned long max_jiffies)
 {
        if (jiffies - b->last_accessed < max_jiffies)
-               return 1;
+               return 0;
 
        if (!(gfp & __GFP_IO)) {
                if (test_bit(B_READING, &b->state) ||
                    test_bit(B_WRITING, &b->state) ||
                    test_bit(B_DIRTY, &b->state))
-                       return 1;
+                       return 0;
        }
 
        if (b->hold_count)
-               return 1;
+               return 0;
 
        __make_buffer_clean(b);
        __unlink_buffer(b);
        __free_buffer_wake(b);
 
-       return 0;
+       return 1;
 }
 
-static void __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
-                  struct shrink_control *sc)
+static long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
+                  gfp_t gfp_mask)
 {
        int l;
        struct dm_buffer *b, *tmp;
+       long freed = 0;
 
        for (l = 0; l < LIST_SIZE; l++) {
-               list_for_each_entry_safe_reverse(b, tmp, &c->lru[l], lru_list)
-                       if (!__cleanup_old_buffer(b, sc->gfp_mask, 0) &&
-                           !--nr_to_scan)
-                               return;
+               list_for_each_entry_safe_reverse(b, tmp, &c->lru[l], lru_list) {
+                       freed += __cleanup_old_buffer(b, gfp_mask, 0);
+                       if (!--nr_to_scan)
+                               break;
+               }
                dm_bufio_cond_resched();
        }
+       return freed;
 }
 
-static int shrink(struct shrinker *shrinker, struct shrink_control *sc)
+static unsigned long
+dm_bufio_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
-       struct dm_bufio_client *c =
-           container_of(shrinker, struct dm_bufio_client, shrinker);
-       unsigned long r;
-       unsigned long nr_to_scan = sc->nr_to_scan;
+       struct dm_bufio_client *c;
+       unsigned long freed;
 
+       c = container_of(shrink, struct dm_bufio_client, shrinker);
        if (sc->gfp_mask & __GFP_IO)
                dm_bufio_lock(c);
        else if (!dm_bufio_trylock(c))
-               return !nr_to_scan ? 0 : -1;
+               return SHRINK_STOP;
 
-       if (nr_to_scan)
-               __scan(c, nr_to_scan, sc);
+       freed  = __scan(c, sc->nr_to_scan, sc->gfp_mask);
+       dm_bufio_unlock(c);
+       return freed;
+}
 
-       r = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
-       if (r > INT_MAX)
-               r = INT_MAX;
+static unsigned long
+dm_bufio_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+       struct dm_bufio_client *c;
+       unsigned long count;
 
-       dm_bufio_unlock(c);
+       c = container_of(shrink, struct dm_bufio_client, shrinker);
+       if (sc->gfp_mask & __GFP_IO)
+               dm_bufio_lock(c);
+       else if (!dm_bufio_trylock(c))
+               return 0;
 
-       return r;
+       count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
+       dm_bufio_unlock(c);
+       return count;
 }
 
 /*
@@ -1582,7 +1595,8 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
        __cache_size_refresh();
        mutex_unlock(&dm_bufio_clients_lock);
 
-       c->shrinker.shrink = shrink;
+       c->shrinker.count_objects = dm_bufio_shrink_count;
+       c->shrinker.scan_objects = dm_bufio_shrink_scan;
        c->shrinker.seeks = 1;
        c->shrinker.batch = 0;
        register_shrinker(&c->shrinker);
@@ -1669,7 +1683,7 @@ static void cleanup_old_buffers(void)
                        struct dm_buffer *b;
                        b = list_entry(c->lru[LIST_CLEAN].prev,
                                       struct dm_buffer, lru_list);
-                       if (__cleanup_old_buffer(b, 0, max_age * HZ))
+                       if (!__cleanup_old_buffer(b, 0, max_age * HZ))
                                break;
                        dm_bufio_cond_resched();
                }
index 0df3ec085ebb49705c4db91815eb8df90808703a..29569768ffbf97259e327ee09b5ce50349ae203e 100644 (file)
@@ -67,9 +67,11 @@ static void free_bitset(unsigned long *bits)
 #define MIGRATION_COUNT_WINDOW 10
 
 /*
- * The block size of the device holding cache data must be >= 32KB
+ * The block size of the device holding cache data must be
+ * between 32KB and 1GB.
  */
 #define DATA_DEV_BLOCK_SIZE_MIN_SECTORS (32 * 1024 >> SECTOR_SHIFT)
+#define DATA_DEV_BLOCK_SIZE_MAX_SECTORS (1024 * 1024 * 1024 >> SECTOR_SHIFT)
 
 /*
  * FIXME: the cache is read/write for the time being.
@@ -101,6 +103,8 @@ struct cache {
        struct dm_target *ti;
        struct dm_target_callbacks callbacks;
 
+       struct dm_cache_metadata *cmd;
+
        /*
         * Metadata is written to this device.
         */
@@ -116,11 +120,6 @@ struct cache {
         */
        struct dm_dev *cache_dev;
 
-       /*
-        * Cache features such as write-through.
-        */
-       struct cache_features features;
-
        /*
         * Size of the origin device in _complete_ blocks and native sectors.
         */
@@ -138,8 +137,6 @@ struct cache {
        uint32_t sectors_per_block;
        int sectors_per_block_shift;
 
-       struct dm_cache_metadata *cmd;
-
        spinlock_t lock;
        struct bio_list deferred_bios;
        struct bio_list deferred_flush_bios;
@@ -148,8 +145,8 @@ struct cache {
        struct list_head completed_migrations;
        struct list_head need_commit_migrations;
        sector_t migration_threshold;
-       atomic_t nr_migrations;
        wait_queue_head_t migration_wait;
+       atomic_t nr_migrations;
 
        /*
         * cache_size entries, dirty if set
@@ -160,9 +157,16 @@ struct cache {
        /*
         * origin_blocks entries, discarded if set.
         */
-       uint32_t discard_block_size; /* a power of 2 times sectors per block */
        dm_dblock_t discard_nr_blocks;
        unsigned long *discard_bitset;
+       uint32_t discard_block_size; /* a power of 2 times sectors per block */
+
+       /*
+        * Rather than reconstructing the table line for the status we just
+        * save it and regurgitate.
+        */
+       unsigned nr_ctr_args;
+       const char **ctr_args;
 
        struct dm_kcopyd_client *copier;
        struct workqueue_struct *wq;
@@ -187,14 +191,12 @@ struct cache {
        bool loaded_mappings:1;
        bool loaded_discards:1;
 
-       struct cache_stats stats;
-
        /*
-        * Rather than reconstructing the table line for the status we just
-        * save it and regurgitate.
+        * Cache features such as write-through.
         */
-       unsigned nr_ctr_args;
-       const char **ctr_args;
+       struct cache_features features;
+
+       struct cache_stats stats;
 };
 
 struct per_bio_data {
@@ -1687,24 +1689,25 @@ static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
 static int parse_block_size(struct cache_args *ca, struct dm_arg_set *as,
                            char **error)
 {
-       unsigned long tmp;
+       unsigned long block_size;
 
        if (!at_least_one_arg(as, error))
                return -EINVAL;
 
-       if (kstrtoul(dm_shift_arg(as), 10, &tmp) || !tmp ||
-           tmp < DATA_DEV_BLOCK_SIZE_MIN_SECTORS ||
-           tmp & (DATA_DEV_BLOCK_SIZE_MIN_SECTORS - 1)) {
+       if (kstrtoul(dm_shift_arg(as), 10, &block_size) || !block_size ||
+           block_size < DATA_DEV_BLOCK_SIZE_MIN_SECTORS ||
+           block_size > DATA_DEV_BLOCK_SIZE_MAX_SECTORS ||
+           block_size & (DATA_DEV_BLOCK_SIZE_MIN_SECTORS - 1)) {
                *error = "Invalid data block size";
                return -EINVAL;
        }
 
-       if (tmp > ca->cache_sectors) {
+       if (block_size > ca->cache_sectors) {
                *error = "Data block size is larger than the cache device";
                return -EINVAL;
        }
 
-       ca->block_size = tmp;
+       ca->block_size = block_size;
 
        return 0;
 }
@@ -2609,9 +2612,17 @@ static void set_discard_limits(struct cache *cache, struct queue_limits *limits)
 static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        struct cache *cache = ti->private;
+       uint64_t io_opt_sectors = limits->io_opt >> SECTOR_SHIFT;
 
-       blk_limits_io_min(limits, 0);
-       blk_limits_io_opt(limits, cache->sectors_per_block << SECTOR_SHIFT);
+       /*
+        * If the system-determined stacked limits are compatible with the
+        * cache's blocksize (io_opt is a factor) do not override them.
+        */
+       if (io_opt_sectors < cache->sectors_per_block ||
+           do_div(io_opt_sectors, cache->sectors_per_block)) {
+               blk_limits_io_min(limits, 0);
+               blk_limits_io_opt(limits, cache->sectors_per_block << SECTOR_SHIFT);
+       }
        set_discard_limits(cache, limits);
 }
 
index 6d2d41ae9e322dbd53e787e5294f2d55551296eb..0fce0bc1a9572f70167cc66d0524186e9e5abece 100644 (file)
@@ -1645,20 +1645,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ret = -ENOMEM;
-       cc->io_queue = alloc_workqueue("kcryptd_io",
-                                      WQ_NON_REENTRANT|
-                                      WQ_MEM_RECLAIM,
-                                      1);
+       cc->io_queue = alloc_workqueue("kcryptd_io", WQ_MEM_RECLAIM, 1);
        if (!cc->io_queue) {
                ti->error = "Couldn't create kcryptd io queue";
                goto bad;
        }
 
        cc->crypt_queue = alloc_workqueue("kcryptd",
-                                         WQ_NON_REENTRANT|
-                                         WQ_CPU_INTENSIVE|
-                                         WQ_MEM_RECLAIM,
-                                         1);
+                                         WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
        if (!cc->crypt_queue) {
                ti->error = "Couldn't create kcryptd queue";
                goto bad;
index f1b758675ec77e2e2c0d16246e2ba772fff01476..afe08146f73ef2baa418ff4ea5734e8a017bf4dc 100644 (file)
@@ -877,7 +877,7 @@ static int dev_rename(struct dm_ioctl *param, size_t param_size)
        unsigned change_uuid = (param->flags & DM_UUID_FLAG) ? 1 : 0;
 
        if (new_data < param->data ||
-           invalid_str(new_data, (void *) param + param_size) ||
+           invalid_str(new_data, (void *) param + param_size) || !*new_data ||
            strlen(new_data) > (change_uuid ? DM_UUID_LEN - 1 : DM_NAME_LEN - 1)) {
                DMWARN("Invalid new mapped device name or uuid string supplied.");
                return -EINVAL;
@@ -1262,44 +1262,37 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
 
        r = dm_table_create(&t, get_mode(param), param->target_count, md);
        if (r)
-               goto out;
+               goto err;
 
+       /* Protect md->type and md->queue against concurrent table loads. */
+       dm_lock_md_type(md);
        r = populate_table(t, param, param_size);
-       if (r) {
-               dm_table_destroy(t);
-               goto out;
-       }
+       if (r)
+               goto err_unlock_md_type;
 
        immutable_target_type = dm_get_immutable_target_type(md);
        if (immutable_target_type &&
            (immutable_target_type != dm_table_get_immutable_target_type(t))) {
                DMWARN("can't replace immutable target type %s",
                       immutable_target_type->name);
-               dm_table_destroy(t);
                r = -EINVAL;
-               goto out;
+               goto err_unlock_md_type;
        }
 
-       /* Protect md->type and md->queue against concurrent table loads. */
-       dm_lock_md_type(md);
        if (dm_get_md_type(md) == DM_TYPE_NONE)
                /* Initial table load: acquire type of table. */
                dm_set_md_type(md, dm_table_get_type(t));
        else if (dm_get_md_type(md) != dm_table_get_type(t)) {
                DMWARN("can't change device type after initial table load.");
-               dm_table_destroy(t);
-               dm_unlock_md_type(md);
                r = -EINVAL;
-               goto out;
+               goto err_unlock_md_type;
        }
 
        /* setup md->queue to reflect md's type (may block) */
        r = dm_setup_md_queue(md);
        if (r) {
                DMWARN("unable to set up device queue for new table.");
-               dm_table_destroy(t);
-               dm_unlock_md_type(md);
-               goto out;
+               goto err_unlock_md_type;
        }
        dm_unlock_md_type(md);
 
@@ -1309,9 +1302,8 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
        if (!hc || hc->md != md) {
                DMWARN("device has been removed from the dev hash table.");
                up_write(&_hash_lock);
-               dm_table_destroy(t);
                r = -ENXIO;
-               goto out;
+               goto err_destroy_table;
        }
 
        if (hc->new_map)
@@ -1322,7 +1314,6 @@ static int table_load(struct dm_ioctl *param, size_t param_size)
        param->flags |= DM_INACTIVE_PRESENT_FLAG;
        __dev_status(md, param);
 
-out:
        if (old_map) {
                dm_sync_table(md);
                dm_table_destroy(old_map);
@@ -1330,6 +1321,15 @@ out:
 
        dm_put(md);
 
+       return 0;
+
+err_unlock_md_type:
+       dm_unlock_md_type(md);
+err_destroy_table:
+       dm_table_destroy(t);
+err:
+       dm_put(md);
+
        return r;
 }
 
@@ -1455,20 +1455,26 @@ static int table_status(struct dm_ioctl *param, size_t param_size)
        return 0;
 }
 
-static bool buffer_test_overflow(char *result, unsigned maxlen)
-{
-       return !maxlen || strlen(result) + 1 >= maxlen;
-}
-
 /*
- * Process device-mapper dependent messages.
+ * Process device-mapper dependent messages.  Messages prefixed with '@'
+ * are processed by the DM core.  All others are delivered to the target.
  * Returns a number <= 1 if message was processed by device mapper.
  * Returns 2 if message should be delivered to the target.
  */
 static int message_for_md(struct mapped_device *md, unsigned argc, char **argv,
                          char *result, unsigned maxlen)
 {
-       return 2;
+       int r;
+
+       if (**argv != '@')
+               return 2; /* no '@' prefix, deliver to target */
+
+       r = dm_stats_message(md, argc, argv, result, maxlen);
+       if (r < 2)
+               return r;
+
+       DMERR("Unsupported message sent to DM core: %s", argv[0]);
+       return -EINVAL;
 }
 
 /*
@@ -1542,7 +1548,7 @@ static int target_message(struct dm_ioctl *param, size_t param_size)
 
        if (r == 1) {
                param->flags |= DM_DATA_OUT_FLAG;
-               if (buffer_test_overflow(result, maxlen))
+               if (dm_message_test_buffer_overflow(result, maxlen))
                        param->flags |= DM_BUFFER_FULL_FLAG;
                else
                        param->data_size = param->data_start + strlen(result) + 1;
index d581fe5d2faf1df83f1fce5725926c8619d7e7aa..3a7cade5e27d828ffa2df3b9254f9064ec078c84 100644 (file)
@@ -833,8 +833,7 @@ struct dm_kcopyd_client *dm_kcopyd_client_create(struct dm_kcopyd_throttle *thro
                goto bad_slab;
 
        INIT_WORK(&kc->kcopyd_work, do_work);
-       kc->kcopyd_wq = alloc_workqueue("kcopyd",
-                                       WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+       kc->kcopyd_wq = alloc_workqueue("kcopyd", WQ_MEM_RECLAIM, 0);
        if (!kc->kcopyd_wq)
                goto bad_workqueue;
 
index 699b5be68d319263cce75e8d932deb0be25c7d00..9584443c56148608d159ceab1d436fd6bacfda3b 100644 (file)
@@ -1080,8 +1080,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        ti->per_bio_data_size = sizeof(struct dm_raid1_bio_record);
        ti->discard_zeroes_data_unsupported = true;
 
-       ms->kmirrord_wq = alloc_workqueue("kmirrord",
-                                         WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+       ms->kmirrord_wq = alloc_workqueue("kmirrord", WQ_MEM_RECLAIM, 0);
        if (!ms->kmirrord_wq) {
                DMERR("couldn't start kmirrord");
                r = -ENOMEM;
diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
new file mode 100644 (file)
index 0000000..8ae31e8
--- /dev/null
@@ -0,0 +1,969 @@
+#include <linux/errno.h>
+#include <linux/numa.h>
+#include <linux/slab.h>
+#include <linux/rculist.h>
+#include <linux/threads.h>
+#include <linux/preempt.h>
+#include <linux/irqflags.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/device-mapper.h>
+
+#include "dm.h"
+#include "dm-stats.h"
+
+#define DM_MSG_PREFIX "stats"
+
+static int dm_stat_need_rcu_barrier;
+
+/*
+ * Using 64-bit values to avoid overflow (which is a
+ * problem that block/genhd.c's IO accounting has).
+ */
+struct dm_stat_percpu {
+       unsigned long long sectors[2];
+       unsigned long long ios[2];
+       unsigned long long merges[2];
+       unsigned long long ticks[2];
+       unsigned long long io_ticks[2];
+       unsigned long long io_ticks_total;
+       unsigned long long time_in_queue;
+};
+
+struct dm_stat_shared {
+       atomic_t in_flight[2];
+       unsigned long stamp;
+       struct dm_stat_percpu tmp;
+};
+
+struct dm_stat {
+       struct list_head list_entry;
+       int id;
+       size_t n_entries;
+       sector_t start;
+       sector_t end;
+       sector_t step;
+       const char *program_id;
+       const char *aux_data;
+       struct rcu_head rcu_head;
+       size_t shared_alloc_size;
+       size_t percpu_alloc_size;
+       struct dm_stat_percpu *stat_percpu[NR_CPUS];
+       struct dm_stat_shared stat_shared[0];
+};
+
+struct dm_stats_last_position {
+       sector_t last_sector;
+       unsigned last_rw;
+};
+
+/*
+ * A typo on the command line could possibly make the kernel run out of memory
+ * and crash. To prevent the crash we account all used memory. We fail if we
+ * exhaust 1/4 of all memory or 1/2 of vmalloc space.
+ */
+#define DM_STATS_MEMORY_FACTOR         4
+#define DM_STATS_VMALLOC_FACTOR                2
+
+static DEFINE_SPINLOCK(shared_memory_lock);
+
+static unsigned long shared_memory_amount;
+
+static bool __check_shared_memory(size_t alloc_size)
+{
+       size_t a;
+
+       a = shared_memory_amount + alloc_size;
+       if (a < shared_memory_amount)
+               return false;
+       if (a >> PAGE_SHIFT > totalram_pages / DM_STATS_MEMORY_FACTOR)
+               return false;
+#ifdef CONFIG_MMU
+       if (a > (VMALLOC_END - VMALLOC_START) / DM_STATS_VMALLOC_FACTOR)
+               return false;
+#endif
+       return true;
+}
+
+static bool check_shared_memory(size_t alloc_size)
+{
+       bool ret;
+
+       spin_lock_irq(&shared_memory_lock);
+
+       ret = __check_shared_memory(alloc_size);
+
+       spin_unlock_irq(&shared_memory_lock);
+
+       return ret;
+}
+
+static bool claim_shared_memory(size_t alloc_size)
+{
+       spin_lock_irq(&shared_memory_lock);
+
+       if (!__check_shared_memory(alloc_size)) {
+               spin_unlock_irq(&shared_memory_lock);
+               return false;
+       }
+
+       shared_memory_amount += alloc_size;
+
+       spin_unlock_irq(&shared_memory_lock);
+
+       return true;
+}
+
+static void free_shared_memory(size_t alloc_size)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&shared_memory_lock, flags);
+
+       if (WARN_ON_ONCE(shared_memory_amount < alloc_size)) {
+               spin_unlock_irqrestore(&shared_memory_lock, flags);
+               DMCRIT("Memory usage accounting bug.");
+               return;
+       }
+
+       shared_memory_amount -= alloc_size;
+
+       spin_unlock_irqrestore(&shared_memory_lock, flags);
+}
+
+static void *dm_kvzalloc(size_t alloc_size, int node)
+{
+       void *p;
+
+       if (!claim_shared_memory(alloc_size))
+               return NULL;
+
+       if (alloc_size <= KMALLOC_MAX_SIZE) {
+               p = kzalloc_node(alloc_size, GFP_KERNEL | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN, node);
+               if (p)
+                       return p;
+       }
+       p = vzalloc_node(alloc_size, node);
+       if (p)
+               return p;
+
+       free_shared_memory(alloc_size);
+
+       return NULL;
+}
+
+static void dm_kvfree(void *ptr, size_t alloc_size)
+{
+       if (!ptr)
+               return;
+
+       free_shared_memory(alloc_size);
+
+       if (is_vmalloc_addr(ptr))
+               vfree(ptr);
+       else
+               kfree(ptr);
+}
+
+static void dm_stat_free(struct rcu_head *head)
+{
+       int cpu;
+       struct dm_stat *s = container_of(head, struct dm_stat, rcu_head);
+
+       kfree(s->program_id);
+       kfree(s->aux_data);
+       for_each_possible_cpu(cpu)
+               dm_kvfree(s->stat_percpu[cpu], s->percpu_alloc_size);
+       dm_kvfree(s, s->shared_alloc_size);
+}
+
+static int dm_stat_in_flight(struct dm_stat_shared *shared)
+{
+       return atomic_read(&shared->in_flight[READ]) +
+              atomic_read(&shared->in_flight[WRITE]);
+}
+
+void dm_stats_init(struct dm_stats *stats)
+{
+       int cpu;
+       struct dm_stats_last_position *last;
+
+       mutex_init(&stats->mutex);
+       INIT_LIST_HEAD(&stats->list);
+       stats->last = alloc_percpu(struct dm_stats_last_position);
+       for_each_possible_cpu(cpu) {
+               last = per_cpu_ptr(stats->last, cpu);
+               last->last_sector = (sector_t)ULLONG_MAX;
+               last->last_rw = UINT_MAX;
+       }
+}
+
+void dm_stats_cleanup(struct dm_stats *stats)
+{
+       size_t ni;
+       struct dm_stat *s;
+       struct dm_stat_shared *shared;
+
+       while (!list_empty(&stats->list)) {
+               s = container_of(stats->list.next, struct dm_stat, list_entry);
+               list_del(&s->list_entry);
+               for (ni = 0; ni < s->n_entries; ni++) {
+                       shared = &s->stat_shared[ni];
+                       if (WARN_ON(dm_stat_in_flight(shared))) {
+                               DMCRIT("leaked in-flight counter at index %lu "
+                                      "(start %llu, end %llu, step %llu): reads %d, writes %d",
+                                      (unsigned long)ni,
+                                      (unsigned long long)s->start,
+                                      (unsigned long long)s->end,
+                                      (unsigned long long)s->step,
+                                      atomic_read(&shared->in_flight[READ]),
+                                      atomic_read(&shared->in_flight[WRITE]));
+                       }
+               }
+               dm_stat_free(&s->rcu_head);
+       }
+       free_percpu(stats->last);
+}
+
+static int dm_stats_create(struct dm_stats *stats, sector_t start, sector_t end,
+                          sector_t step, const char *program_id, const char *aux_data,
+                          void (*suspend_callback)(struct mapped_device *),
+                          void (*resume_callback)(struct mapped_device *),
+                          struct mapped_device *md)
+{
+       struct list_head *l;
+       struct dm_stat *s, *tmp_s;
+       sector_t n_entries;
+       size_t ni;
+       size_t shared_alloc_size;
+       size_t percpu_alloc_size;
+       struct dm_stat_percpu *p;
+       int cpu;
+       int ret_id;
+       int r;
+
+       if (end < start || !step)
+               return -EINVAL;
+
+       n_entries = end - start;
+       if (dm_sector_div64(n_entries, step))
+               n_entries++;
+
+       if (n_entries != (size_t)n_entries || !(size_t)(n_entries + 1))
+               return -EOVERFLOW;
+
+       shared_alloc_size = sizeof(struct dm_stat) + (size_t)n_entries * sizeof(struct dm_stat_shared);
+       if ((shared_alloc_size - sizeof(struct dm_stat)) / sizeof(struct dm_stat_shared) != n_entries)
+               return -EOVERFLOW;
+
+       percpu_alloc_size = (size_t)n_entries * sizeof(struct dm_stat_percpu);
+       if (percpu_alloc_size / sizeof(struct dm_stat_percpu) != n_entries)
+               return -EOVERFLOW;
+
+       if (!check_shared_memory(shared_alloc_size + num_possible_cpus() * percpu_alloc_size))
+               return -ENOMEM;
+
+       s = dm_kvzalloc(shared_alloc_size, NUMA_NO_NODE);
+       if (!s)
+               return -ENOMEM;
+
+       s->n_entries = n_entries;
+       s->start = start;
+       s->end = end;
+       s->step = step;
+       s->shared_alloc_size = shared_alloc_size;
+       s->percpu_alloc_size = percpu_alloc_size;
+
+       s->program_id = kstrdup(program_id, GFP_KERNEL);
+       if (!s->program_id) {
+               r = -ENOMEM;
+               goto out;
+       }
+       s->aux_data = kstrdup(aux_data, GFP_KERNEL);
+       if (!s->aux_data) {
+               r = -ENOMEM;
+               goto out;
+       }
+
+       for (ni = 0; ni < n_entries; ni++) {
+               atomic_set(&s->stat_shared[ni].in_flight[READ], 0);
+               atomic_set(&s->stat_shared[ni].in_flight[WRITE], 0);
+       }
+
+       for_each_possible_cpu(cpu) {
+               p = dm_kvzalloc(percpu_alloc_size, cpu_to_node(cpu));
+               if (!p) {
+                       r = -ENOMEM;
+                       goto out;
+               }
+               s->stat_percpu[cpu] = p;
+       }
+
+       /*
+        * Suspend/resume to make sure there is no i/o in flight,
+        * so that newly created statistics will be exact.
+        *
+        * (note: we couldn't suspend earlier because we must not
+        * allocate memory while suspended)
+        */
+       suspend_callback(md);
+
+       mutex_lock(&stats->mutex);
+       s->id = 0;
+       list_for_each(l, &stats->list) {
+               tmp_s = container_of(l, struct dm_stat, list_entry);
+               if (WARN_ON(tmp_s->id < s->id)) {
+                       r = -EINVAL;
+                       goto out_unlock_resume;
+               }
+               if (tmp_s->id > s->id)
+                       break;
+               if (unlikely(s->id == INT_MAX)) {
+                       r = -ENFILE;
+                       goto out_unlock_resume;
+               }
+               s->id++;
+       }
+       ret_id = s->id;
+       list_add_tail_rcu(&s->list_entry, l);
+       mutex_unlock(&stats->mutex);
+
+       resume_callback(md);
+
+       return ret_id;
+
+out_unlock_resume:
+       mutex_unlock(&stats->mutex);
+       resume_callback(md);
+out:
+       dm_stat_free(&s->rcu_head);
+       return r;
+}
+
+static struct dm_stat *__dm_stats_find(struct dm_stats *stats, int id)
+{
+       struct dm_stat *s;
+
+       list_for_each_entry(s, &stats->list, list_entry) {
+               if (s->id > id)
+                       break;
+               if (s->id == id)
+                       return s;
+       }
+
+       return NULL;
+}
+
+static int dm_stats_delete(struct dm_stats *stats, int id)
+{
+       struct dm_stat *s;
+       int cpu;
+
+       mutex_lock(&stats->mutex);
+
+       s = __dm_stats_find(stats, id);
+       if (!s) {
+               mutex_unlock(&stats->mutex);
+               return -ENOENT;
+       }
+
+       list_del_rcu(&s->list_entry);
+       mutex_unlock(&stats->mutex);
+
+       /*
+        * vfree can't be called from RCU callback
+        */
+       for_each_possible_cpu(cpu)
+               if (is_vmalloc_addr(s->stat_percpu))
+                       goto do_sync_free;
+       if (is_vmalloc_addr(s)) {
+do_sync_free:
+               synchronize_rcu_expedited();
+               dm_stat_free(&s->rcu_head);
+       } else {
+               ACCESS_ONCE(dm_stat_need_rcu_barrier) = 1;
+               call_rcu(&s->rcu_head, dm_stat_free);
+       }
+       return 0;
+}
+
+static int dm_stats_list(struct dm_stats *stats, const char *program,
+                        char *result, unsigned maxlen)
+{
+       struct dm_stat *s;
+       sector_t len;
+       unsigned sz = 0;
+
+       /*
+        * Output format:
+        *   <region_id>: <start_sector>+<length> <step> <program_id> <aux_data>
+        */
+
+       mutex_lock(&stats->mutex);
+       list_for_each_entry(s, &stats->list, list_entry) {
+               if (!program || !strcmp(program, s->program_id)) {
+                       len = s->end - s->start;
+                       DMEMIT("%d: %llu+%llu %llu %s %s\n", s->id,
+                               (unsigned long long)s->start,
+                               (unsigned long long)len,
+                               (unsigned long long)s->step,
+                               s->program_id,
+                               s->aux_data);
+               }
+       }
+       mutex_unlock(&stats->mutex);
+
+       return 1;
+}
+
+static void dm_stat_round(struct dm_stat_shared *shared, struct dm_stat_percpu *p)
+{
+       /*
+        * This is racy, but so is part_round_stats_single.
+        */
+       unsigned long now = jiffies;
+       unsigned in_flight_read;
+       unsigned in_flight_write;
+       unsigned long difference = now - shared->stamp;
+
+       if (!difference)
+               return;
+       in_flight_read = (unsigned)atomic_read(&shared->in_flight[READ]);
+       in_flight_write = (unsigned)atomic_read(&shared->in_flight[WRITE]);
+       if (in_flight_read)
+               p->io_ticks[READ] += difference;
+       if (in_flight_write)
+               p->io_ticks[WRITE] += difference;
+       if (in_flight_read + in_flight_write) {
+               p->io_ticks_total += difference;
+               p->time_in_queue += (in_flight_read + in_flight_write) * difference;
+       }
+       shared->stamp = now;
+}
+
+static void dm_stat_for_entry(struct dm_stat *s, size_t entry,
+                             unsigned long bi_rw, sector_t len, bool merged,
+                             bool end, unsigned long duration)
+{
+       unsigned long idx = bi_rw & REQ_WRITE;
+       struct dm_stat_shared *shared = &s->stat_shared[entry];
+       struct dm_stat_percpu *p;
+
+       /*
+        * For strict correctness we should use local_irq_disable/enable
+        * instead of preempt_disable/enable.
+        *
+        * This is racy if the driver finishes bios from non-interrupt
+        * context as well as from interrupt context or from more different
+        * interrupts.
+        *
+        * However, the race only results in not counting some events,
+        * so it is acceptable.
+        *
+        * part_stat_lock()/part_stat_unlock() have this race too.
+        */
+       preempt_disable();
+       p = &s->stat_percpu[smp_processor_id()][entry];
+
+       if (!end) {
+               dm_stat_round(shared, p);
+               atomic_inc(&shared->in_flight[idx]);
+       } else {
+               dm_stat_round(shared, p);
+               atomic_dec(&shared->in_flight[idx]);
+               p->sectors[idx] += len;
+               p->ios[idx] += 1;
+               p->merges[idx] += merged;
+               p->ticks[idx] += duration;
+       }
+
+       preempt_enable();
+}
+
+static void __dm_stat_bio(struct dm_stat *s, unsigned long bi_rw,
+                         sector_t bi_sector, sector_t end_sector,
+                         bool end, unsigned long duration,
+                         struct dm_stats_aux *stats_aux)
+{
+       sector_t rel_sector, offset, todo, fragment_len;
+       size_t entry;
+
+       if (end_sector <= s->start || bi_sector >= s->end)
+               return;
+       if (unlikely(bi_sector < s->start)) {
+               rel_sector = 0;
+               todo = end_sector - s->start;
+       } else {
+               rel_sector = bi_sector - s->start;
+               todo = end_sector - bi_sector;
+       }
+       if (unlikely(end_sector > s->end))
+               todo -= (end_sector - s->end);
+
+       offset = dm_sector_div64(rel_sector, s->step);
+       entry = rel_sector;
+       do {
+               if (WARN_ON_ONCE(entry >= s->n_entries)) {
+                       DMCRIT("Invalid area access in region id %d", s->id);
+                       return;
+               }
+               fragment_len = todo;
+               if (fragment_len > s->step - offset)
+                       fragment_len = s->step - offset;
+               dm_stat_for_entry(s, entry, bi_rw, fragment_len,
+                                 stats_aux->merged, end, duration);
+               todo -= fragment_len;
+               entry++;
+               offset = 0;
+       } while (unlikely(todo != 0));
+}
+
+void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw,
+                        sector_t bi_sector, unsigned bi_sectors, bool end,
+                        unsigned long duration, struct dm_stats_aux *stats_aux)
+{
+       struct dm_stat *s;
+       sector_t end_sector;
+       struct dm_stats_last_position *last;
+
+       if (unlikely(!bi_sectors))
+               return;
+
+       end_sector = bi_sector + bi_sectors;
+
+       if (!end) {
+               /*
+                * A race condition can at worst result in the merged flag being
+                * misrepresented, so we don't have to disable preemption here.
+                */
+               last = __this_cpu_ptr(stats->last);
+               stats_aux->merged =
+                       (bi_sector == (ACCESS_ONCE(last->last_sector) &&
+                                      ((bi_rw & (REQ_WRITE | REQ_DISCARD)) ==
+                                       (ACCESS_ONCE(last->last_rw) & (REQ_WRITE | REQ_DISCARD)))
+                                      ));
+               ACCESS_ONCE(last->last_sector) = end_sector;
+               ACCESS_ONCE(last->last_rw) = bi_rw;
+       }
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(s, &stats->list, list_entry)
+               __dm_stat_bio(s, bi_rw, bi_sector, end_sector, end, duration, stats_aux);
+
+       rcu_read_unlock();
+}
+
+static void __dm_stat_init_temporary_percpu_totals(struct dm_stat_shared *shared,
+                                                  struct dm_stat *s, size_t x)
+{
+       int cpu;
+       struct dm_stat_percpu *p;
+
+       local_irq_disable();
+       p = &s->stat_percpu[smp_processor_id()][x];
+       dm_stat_round(shared, p);
+       local_irq_enable();
+
+       memset(&shared->tmp, 0, sizeof(shared->tmp));
+       for_each_possible_cpu(cpu) {
+               p = &s->stat_percpu[cpu][x];
+               shared->tmp.sectors[READ] += ACCESS_ONCE(p->sectors[READ]);
+               shared->tmp.sectors[WRITE] += ACCESS_ONCE(p->sectors[WRITE]);
+               shared->tmp.ios[READ] += ACCESS_ONCE(p->ios[READ]);
+               shared->tmp.ios[WRITE] += ACCESS_ONCE(p->ios[WRITE]);
+               shared->tmp.merges[READ] += ACCESS_ONCE(p->merges[READ]);
+               shared->tmp.merges[WRITE] += ACCESS_ONCE(p->merges[WRITE]);
+               shared->tmp.ticks[READ] += ACCESS_ONCE(p->ticks[READ]);
+               shared->tmp.ticks[WRITE] += ACCESS_ONCE(p->ticks[WRITE]);
+               shared->tmp.io_ticks[READ] += ACCESS_ONCE(p->io_ticks[READ]);
+               shared->tmp.io_ticks[WRITE] += ACCESS_ONCE(p->io_ticks[WRITE]);
+               shared->tmp.io_ticks_total += ACCESS_ONCE(p->io_ticks_total);
+               shared->tmp.time_in_queue += ACCESS_ONCE(p->time_in_queue);
+       }
+}
+
+static void __dm_stat_clear(struct dm_stat *s, size_t idx_start, size_t idx_end,
+                           bool init_tmp_percpu_totals)
+{
+       size_t x;
+       struct dm_stat_shared *shared;
+       struct dm_stat_percpu *p;
+
+       for (x = idx_start; x < idx_end; x++) {
+               shared = &s->stat_shared[x];
+               if (init_tmp_percpu_totals)
+                       __dm_stat_init_temporary_percpu_totals(shared, s, x);
+               local_irq_disable();
+               p = &s->stat_percpu[smp_processor_id()][x];
+               p->sectors[READ] -= shared->tmp.sectors[READ];
+               p->sectors[WRITE] -= shared->tmp.sectors[WRITE];
+               p->ios[READ] -= shared->tmp.ios[READ];
+               p->ios[WRITE] -= shared->tmp.ios[WRITE];
+               p->merges[READ] -= shared->tmp.merges[READ];
+               p->merges[WRITE] -= shared->tmp.merges[WRITE];
+               p->ticks[READ] -= shared->tmp.ticks[READ];
+               p->ticks[WRITE] -= shared->tmp.ticks[WRITE];
+               p->io_ticks[READ] -= shared->tmp.io_ticks[READ];
+               p->io_ticks[WRITE] -= shared->tmp.io_ticks[WRITE];
+               p->io_ticks_total -= shared->tmp.io_ticks_total;
+               p->time_in_queue -= shared->tmp.time_in_queue;
+               local_irq_enable();
+       }
+}
+
+static int dm_stats_clear(struct dm_stats *stats, int id)
+{
+       struct dm_stat *s;
+
+       mutex_lock(&stats->mutex);
+
+       s = __dm_stats_find(stats, id);
+       if (!s) {
+               mutex_unlock(&stats->mutex);
+               return -ENOENT;
+       }
+
+       __dm_stat_clear(s, 0, s->n_entries, true);
+
+       mutex_unlock(&stats->mutex);
+
+       return 1;
+}
+
+/*
+ * This is like jiffies_to_msec, but works for 64-bit values.
+ */
+static unsigned long long dm_jiffies_to_msec64(unsigned long long j)
+{
+       unsigned long long result = 0;
+       unsigned mult;
+
+       if (j)
+               result = jiffies_to_msecs(j & 0x3fffff);
+       if (j >= 1 << 22) {
+               mult = jiffies_to_msecs(1 << 22);
+               result += (unsigned long long)mult * (unsigned long long)jiffies_to_msecs((j >> 22) & 0x3fffff);
+       }
+       if (j >= 1ULL << 44)
+               result += (unsigned long long)mult * (unsigned long long)mult * (unsigned long long)jiffies_to_msecs(j >> 44);
+
+       return result;
+}
+
+static int dm_stats_print(struct dm_stats *stats, int id,
+                         size_t idx_start, size_t idx_len,
+                         bool clear, char *result, unsigned maxlen)
+{
+       unsigned sz = 0;
+       struct dm_stat *s;
+       size_t x;
+       sector_t start, end, step;
+       size_t idx_end;
+       struct dm_stat_shared *shared;
+
+       /*
+        * Output format:
+        *   <start_sector>+<length> counters
+        */
+
+       mutex_lock(&stats->mutex);
+
+       s = __dm_stats_find(stats, id);
+       if (!s) {
+               mutex_unlock(&stats->mutex);
+               return -ENOENT;
+       }
+
+       idx_end = idx_start + idx_len;
+       if (idx_end < idx_start ||
+           idx_end > s->n_entries)
+               idx_end = s->n_entries;
+
+       if (idx_start > idx_end)
+               idx_start = idx_end;
+
+       step = s->step;
+       start = s->start + (step * idx_start);
+
+       for (x = idx_start; x < idx_end; x++, start = end) {
+               shared = &s->stat_shared[x];
+               end = start + step;
+               if (unlikely(end > s->end))
+                       end = s->end;
+
+               __dm_stat_init_temporary_percpu_totals(shared, s, x);
+
+               DMEMIT("%llu+%llu %llu %llu %llu %llu %llu %llu %llu %llu %d %llu %llu %llu %llu\n",
+                      (unsigned long long)start,
+                      (unsigned long long)step,
+                      shared->tmp.ios[READ],
+                      shared->tmp.merges[READ],
+                      shared->tmp.sectors[READ],
+                      dm_jiffies_to_msec64(shared->tmp.ticks[READ]),
+                      shared->tmp.ios[WRITE],
+                      shared->tmp.merges[WRITE],
+                      shared->tmp.sectors[WRITE],
+                      dm_jiffies_to_msec64(shared->tmp.ticks[WRITE]),
+                      dm_stat_in_flight(shared),
+                      dm_jiffies_to_msec64(shared->tmp.io_ticks_total),
+                      dm_jiffies_to_msec64(shared->tmp.time_in_queue),
+                      dm_jiffies_to_msec64(shared->tmp.io_ticks[READ]),
+                      dm_jiffies_to_msec64(shared->tmp.io_ticks[WRITE]));
+
+               if (unlikely(sz + 1 >= maxlen))
+                       goto buffer_overflow;
+       }
+
+       if (clear)
+               __dm_stat_clear(s, idx_start, idx_end, false);
+
+buffer_overflow:
+       mutex_unlock(&stats->mutex);
+
+       return 1;
+}
+
+static int dm_stats_set_aux(struct dm_stats *stats, int id, const char *aux_data)
+{
+       struct dm_stat *s;
+       const char *new_aux_data;
+
+       mutex_lock(&stats->mutex);
+
+       s = __dm_stats_find(stats, id);
+       if (!s) {
+               mutex_unlock(&stats->mutex);
+               return -ENOENT;
+       }
+
+       new_aux_data = kstrdup(aux_data, GFP_KERNEL);
+       if (!new_aux_data) {
+               mutex_unlock(&stats->mutex);
+               return -ENOMEM;
+       }
+
+       kfree(s->aux_data);
+       s->aux_data = new_aux_data;
+
+       mutex_unlock(&stats->mutex);
+
+       return 0;
+}
+
+static int message_stats_create(struct mapped_device *md,
+                               unsigned argc, char **argv,
+                               char *result, unsigned maxlen)
+{
+       int id;
+       char dummy;
+       unsigned long long start, end, len, step;
+       unsigned divisor;
+       const char *program_id, *aux_data;
+
+       /*
+        * Input format:
+        *   <range> <step> [<program_id> [<aux_data>]]
+        */
+
+       if (argc < 3 || argc > 5)
+               return -EINVAL;
+
+       if (!strcmp(argv[1], "-")) {
+               start = 0;
+               len = dm_get_size(md);
+               if (!len)
+                       len = 1;
+       } else if (sscanf(argv[1], "%llu+%llu%c", &start, &len, &dummy) != 2 ||
+                  start != (sector_t)start || len != (sector_t)len)
+               return -EINVAL;
+
+       end = start + len;
+       if (start >= end)
+               return -EINVAL;
+
+       if (sscanf(argv[2], "/%u%c", &divisor, &dummy) == 1) {
+               step = end - start;
+               if (do_div(step, divisor))
+                       step++;
+               if (!step)
+                       step = 1;
+       } else if (sscanf(argv[2], "%llu%c", &step, &dummy) != 1 ||
+                  step != (sector_t)step || !step)
+               return -EINVAL;
+
+       program_id = "-";
+       aux_data = "-";
+
+       if (argc > 3)
+               program_id = argv[3];
+
+       if (argc > 4)
+               aux_data = argv[4];
+
+       /*
+        * If a buffer overflow happens after we created the region,
+        * it's too late (the userspace would retry with a larger
+        * buffer, but the region id that caused the overflow is already
+        * leaked).  So we must detect buffer overflow in advance.
+        */
+       snprintf(result, maxlen, "%d", INT_MAX);
+       if (dm_message_test_buffer_overflow(result, maxlen))
+               return 1;
+
+       id = dm_stats_create(dm_get_stats(md), start, end, step, program_id, aux_data,
+                            dm_internal_suspend, dm_internal_resume, md);
+       if (id < 0)
+               return id;
+
+       snprintf(result, maxlen, "%d", id);
+
+       return 1;
+}
+
+static int message_stats_delete(struct mapped_device *md,
+                               unsigned argc, char **argv)
+{
+       int id;
+       char dummy;
+
+       if (argc != 2)
+               return -EINVAL;
+
+       if (sscanf(argv[1], "%d%c", &id, &dummy) != 1 || id < 0)
+               return -EINVAL;
+
+       return dm_stats_delete(dm_get_stats(md), id);
+}
+
+static int message_stats_clear(struct mapped_device *md,
+                              unsigned argc, char **argv)
+{
+       int id;
+       char dummy;
+
+       if (argc != 2)
+               return -EINVAL;
+
+       if (sscanf(argv[1], "%d%c", &id, &dummy) != 1 || id < 0)
+               return -EINVAL;
+
+       return dm_stats_clear(dm_get_stats(md), id);
+}
+
+static int message_stats_list(struct mapped_device *md,
+                             unsigned argc, char **argv,
+                             char *result, unsigned maxlen)
+{
+       int r;
+       const char *program = NULL;
+
+       if (argc < 1 || argc > 2)
+               return -EINVAL;
+
+       if (argc > 1) {
+               program = kstrdup(argv[1], GFP_KERNEL);
+               if (!program)
+                       return -ENOMEM;
+       }
+
+       r = dm_stats_list(dm_get_stats(md), program, result, maxlen);
+
+       kfree(program);
+
+       return r;
+}
+
+static int message_stats_print(struct mapped_device *md,
+                              unsigned argc, char **argv, bool clear,
+                              char *result, unsigned maxlen)
+{
+       int id;
+       char dummy;
+       unsigned long idx_start = 0, idx_len = ULONG_MAX;
+
+       if (argc != 2 && argc != 4)
+               return -EINVAL;
+
+       if (sscanf(argv[1], "%d%c", &id, &dummy) != 1 || id < 0)
+               return -EINVAL;
+
+       if (argc > 3) {
+               if (strcmp(argv[2], "-") &&
+                   sscanf(argv[2], "%lu%c", &idx_start, &dummy) != 1)
+                       return -EINVAL;
+               if (strcmp(argv[3], "-") &&
+                   sscanf(argv[3], "%lu%c", &idx_len, &dummy) != 1)
+                       return -EINVAL;
+       }
+
+       return dm_stats_print(dm_get_stats(md), id, idx_start, idx_len, clear,
+                             result, maxlen);
+}
+
+static int message_stats_set_aux(struct mapped_device *md,
+                                unsigned argc, char **argv)
+{
+       int id;
+       char dummy;
+
+       if (argc != 3)
+               return -EINVAL;
+
+       if (sscanf(argv[1], "%d%c", &id, &dummy) != 1 || id < 0)
+               return -EINVAL;
+
+       return dm_stats_set_aux(dm_get_stats(md), id, argv[2]);
+}
+
+int dm_stats_message(struct mapped_device *md, unsigned argc, char **argv,
+                    char *result, unsigned maxlen)
+{
+       int r;
+
+       if (dm_request_based(md)) {
+               DMWARN("Statistics are only supported for bio-based devices");
+               return -EOPNOTSUPP;
+       }
+
+       /* All messages here must start with '@' */
+       if (!strcasecmp(argv[0], "@stats_create"))
+               r = message_stats_create(md, argc, argv, result, maxlen);
+       else if (!strcasecmp(argv[0], "@stats_delete"))
+               r = message_stats_delete(md, argc, argv);
+       else if (!strcasecmp(argv[0], "@stats_clear"))
+               r = message_stats_clear(md, argc, argv);
+       else if (!strcasecmp(argv[0], "@stats_list"))
+               r = message_stats_list(md, argc, argv, result, maxlen);
+       else if (!strcasecmp(argv[0], "@stats_print"))
+               r = message_stats_print(md, argc, argv, false, result, maxlen);
+       else if (!strcasecmp(argv[0], "@stats_print_clear"))
+               r = message_stats_print(md, argc, argv, true, result, maxlen);
+       else if (!strcasecmp(argv[0], "@stats_set_aux"))
+               r = message_stats_set_aux(md, argc, argv);
+       else
+               return 2; /* this wasn't a stats message */
+
+       if (r == -EINVAL)
+               DMWARN("Invalid parameters for message %s", argv[0]);
+
+       return r;
+}
+
+int __init dm_statistics_init(void)
+{
+       dm_stat_need_rcu_barrier = 0;
+       return 0;
+}
+
+void dm_statistics_exit(void)
+{
+       if (dm_stat_need_rcu_barrier)
+               rcu_barrier();
+       if (WARN_ON(shared_memory_amount))
+               DMCRIT("shared_memory_amount leaked: %lu", shared_memory_amount);
+}
+
+module_param_named(stats_current_allocated_bytes, shared_memory_amount, ulong, S_IRUGO);
+MODULE_PARM_DESC(stats_current_allocated_bytes, "Memory currently used by statistics");
diff --git a/drivers/md/dm-stats.h b/drivers/md/dm-stats.h
new file mode 100644 (file)
index 0000000..e7c4984
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DM_STATS_H
+#define DM_STATS_H
+
+#include <linux/types.h>
+#include <linux/mutex.h>
+#include <linux/list.h>
+
+int dm_statistics_init(void);
+void dm_statistics_exit(void);
+
+struct dm_stats {
+       struct mutex mutex;
+       struct list_head list;  /* list of struct dm_stat */
+       struct dm_stats_last_position __percpu *last;
+       sector_t last_sector;
+       unsigned last_rw;
+};
+
+struct dm_stats_aux {
+       bool merged;
+};
+
+void dm_stats_init(struct dm_stats *st);
+void dm_stats_cleanup(struct dm_stats *st);
+
+struct mapped_device;
+
+int dm_stats_message(struct mapped_device *md, unsigned argc, char **argv,
+                    char *result, unsigned maxlen);
+
+void dm_stats_account_io(struct dm_stats *stats, unsigned long bi_rw,
+                        sector_t bi_sector, unsigned bi_sectors, bool end,
+                        unsigned long duration, struct dm_stats_aux *aux);
+
+static inline bool dm_stats_used(struct dm_stats *st)
+{
+       return !list_empty(&st->list);
+}
+
+#endif
index d907ca6227cec3519e46ac95e146656b342125c2..73c1712dad96d09f2760416852dd0cacd22cbd33 100644 (file)
@@ -4,6 +4,7 @@
  * This file is released under the GPL.
  */
 
+#include "dm.h"
 #include <linux/device-mapper.h>
 
 #include <linux/module.h>
index f221812b7dbcf0d3bae7c5171fe9e184c781d7d7..8f8783533ac7e13383aed49eff8a40ba3a0218bf 100644 (file)
@@ -860,14 +860,17 @@ EXPORT_SYMBOL(dm_consume_args);
 static int dm_table_set_type(struct dm_table *t)
 {
        unsigned i;
-       unsigned bio_based = 0, request_based = 0;
+       unsigned bio_based = 0, request_based = 0, hybrid = 0;
        struct dm_target *tgt;
        struct dm_dev_internal *dd;
        struct list_head *devices;
+       unsigned live_md_type;
 
        for (i = 0; i < t->num_targets; i++) {
                tgt = t->targets + i;
-               if (dm_target_request_based(tgt))
+               if (dm_target_hybrid(tgt))
+                       hybrid = 1;
+               else if (dm_target_request_based(tgt))
                        request_based = 1;
                else
                        bio_based = 1;
@@ -879,6 +882,19 @@ static int dm_table_set_type(struct dm_table *t)
                }
        }
 
+       if (hybrid && !bio_based && !request_based) {
+               /*
+                * The targets can work either way.
+                * Determine the type from the live device.
+                * Default to bio-based if device is new.
+                */
+               live_md_type = dm_get_md_type(t->md);
+               if (live_md_type == DM_TYPE_REQUEST_BASED)
+                       request_based = 1;
+               else
+                       bio_based = 1;
+       }
+
        if (bio_based) {
                /* We must use this table as bio-based */
                t->type = DM_TYPE_BIO_BASED;
index 37ba5db71cd9b2f3c16c0e64e67b109401c5903d..242e3cec397a5c87a1963b31aa0d65a9bec7527a 100644 (file)
@@ -131,12 +131,19 @@ static int io_err_map(struct dm_target *tt, struct bio *bio)
        return -EIO;
 }
 
+static int io_err_map_rq(struct dm_target *ti, struct request *clone,
+                        union map_info *map_context)
+{
+       return -EIO;
+}
+
 static struct target_type error_target = {
        .name = "error",
-       .version = {1, 1, 0},
+       .version = {1, 2, 0},
        .ctr  = io_err_ctr,
        .dtr  = io_err_dtr,
        .map  = io_err_map,
+       .map_rq = io_err_map_rq,
 };
 
 int __init dm_target_init(void)
index 88f2f802d528be23b8e64c26085913677082be03..ed063427d676f64b53f3d9569449fc0daaf174b0 100644 (file)
@@ -887,7 +887,8 @@ static int commit(struct pool *pool)
 
        r = dm_pool_commit_metadata(pool->pmd);
        if (r)
-               DMERR_LIMIT("commit failed: error = %d", r);
+               DMERR_LIMIT("%s: commit failed: error = %d",
+                           dm_device_name(pool->pool_md), r);
 
        return r;
 }
@@ -917,6 +918,13 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
        unsigned long flags;
        struct pool *pool = tc->pool;
 
+       /*
+        * Once no_free_space is set we must not allow allocation to succeed.
+        * Otherwise it is difficult to explain, debug, test and support.
+        */
+       if (pool->no_free_space)
+               return -ENOSPC;
+
        r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
        if (r)
                return r;
@@ -931,31 +939,30 @@ static int alloc_data_block(struct thin_c *tc, dm_block_t *result)
        }
 
        if (!free_blocks) {
-               if (pool->no_free_space)
-                       return -ENOSPC;
-               else {
-                       /*
-                        * Try to commit to see if that will free up some
-                        * more space.
-                        */
-                       (void) commit_or_fallback(pool);
+               /*
+                * Try to commit to see if that will free up some
+                * more space.
+                */
+               (void) commit_or_fallback(pool);
 
-                       r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
-                       if (r)
-                               return r;
+               r = dm_pool_get_free_block_count(pool->pmd, &free_blocks);
+               if (r)
+                       return r;
 
-                       /*
-                        * If we still have no space we set a flag to avoid
-                        * doing all this checking and return -ENOSPC.
-                        */
-                       if (!free_blocks) {
-                               DMWARN("%s: no free space available.",
-                                      dm_device_name(pool->pool_md));
-                               spin_lock_irqsave(&pool->lock, flags);
-                               pool->no_free_space = 1;
-                               spin_unlock_irqrestore(&pool->lock, flags);
-                               return -ENOSPC;
-                       }
+               /*
+                * If we still have no space we set a flag to avoid
+                * doing all this checking and return -ENOSPC.  This
+                * flag serves as a latch that disallows allocations from
+                * this pool until the admin takes action (e.g. resize or
+                * table reload).
+                */
+               if (!free_blocks) {
+                       DMWARN("%s: no free space available.",
+                              dm_device_name(pool->pool_md));
+                       spin_lock_irqsave(&pool->lock, flags);
+                       pool->no_free_space = 1;
+                       spin_unlock_irqrestore(&pool->lock, flags);
+                       return -ENOSPC;
                }
        }
 
@@ -1085,6 +1092,7 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
 {
        int r;
        dm_block_t data_block;
+       struct pool *pool = tc->pool;
 
        r = alloc_data_block(tc, &data_block);
        switch (r) {
@@ -1094,13 +1102,14 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
                break;
 
        case -ENOSPC:
-               no_space(tc->pool, cell);
+               no_space(pool, cell);
                break;
 
        default:
                DMERR_LIMIT("%s: alloc_data_block() failed: error = %d",
                            __func__, r);
-               cell_error(tc->pool, cell);
+               set_pool_mode(pool, PM_READ_ONLY);
+               cell_error(pool, cell);
                break;
        }
 }
@@ -1386,7 +1395,8 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode)
 
        switch (mode) {
        case PM_FAIL:
-               DMERR("switching pool to failure mode");
+               DMERR("%s: switching pool to failure mode",
+                     dm_device_name(pool->pool_md));
                pool->process_bio = process_bio_fail;
                pool->process_discard = process_bio_fail;
                pool->process_prepared_mapping = process_prepared_mapping_fail;
@@ -1394,10 +1404,12 @@ static void set_pool_mode(struct pool *pool, enum pool_mode mode)
                break;
 
        case PM_READ_ONLY:
-               DMERR("switching pool to read-only mode");
+               DMERR("%s: switching pool to read-only mode",
+                     dm_device_name(pool->pool_md));
                r = dm_pool_abort_metadata(pool->pmd);
                if (r) {
-                       DMERR("aborting transaction failed");
+                       DMERR("%s: aborting transaction failed",
+                             dm_device_name(pool->pool_md));
                        set_pool_mode(pool, PM_FAIL);
                } else {
                        dm_pool_metadata_read_only(pool->pmd);
@@ -2156,19 +2168,22 @@ static int maybe_resize_data_dev(struct dm_target *ti, bool *need_commit)
 
        r = dm_pool_get_data_dev_size(pool->pmd, &sb_data_size);
        if (r) {
-               DMERR("failed to retrieve data device size");
+               DMERR("%s: failed to retrieve data device size",
+                     dm_device_name(pool->pool_md));
                return r;
        }
 
        if (data_size < sb_data_size) {
-               DMERR("pool target (%llu blocks) too small: expected %llu",
+               DMERR("%s: pool target (%llu blocks) too small: expected %llu",
+                     dm_device_name(pool->pool_md),
                      (unsigned long long)data_size, sb_data_size);
                return -EINVAL;
 
        } else if (data_size > sb_data_size) {
                r = dm_pool_resize_data_dev(pool->pmd, data_size);
                if (r) {
-                       DMERR("failed to resize data device");
+                       DMERR("%s: failed to resize data device",
+                             dm_device_name(pool->pool_md));
                        set_pool_mode(pool, PM_READ_ONLY);
                        return r;
                }
@@ -2192,19 +2207,22 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit)
 
        r = dm_pool_get_metadata_dev_size(pool->pmd, &sb_metadata_dev_size);
        if (r) {
-               DMERR("failed to retrieve data device size");
+               DMERR("%s: failed to retrieve metadata device size",
+                     dm_device_name(pool->pool_md));
                return r;
        }
 
        if (metadata_dev_size < sb_metadata_dev_size) {
-               DMERR("metadata device (%llu blocks) too small: expected %llu",
+               DMERR("%s: metadata device (%llu blocks) too small: expected %llu",
+                     dm_device_name(pool->pool_md),
                      metadata_dev_size, sb_metadata_dev_size);
                return -EINVAL;
 
        } else if (metadata_dev_size > sb_metadata_dev_size) {
                r = dm_pool_resize_metadata_dev(pool->pmd, metadata_dev_size);
                if (r) {
-                       DMERR("failed to resize metadata device");
+                       DMERR("%s: failed to resize metadata device",
+                             dm_device_name(pool->pool_md));
                        return r;
                }
 
@@ -2530,37 +2548,43 @@ static void pool_status(struct dm_target *ti, status_type_t type,
 
                r = dm_pool_get_metadata_transaction_id(pool->pmd, &transaction_id);
                if (r) {
-                       DMERR("dm_pool_get_metadata_transaction_id returned %d", r);
+                       DMERR("%s: dm_pool_get_metadata_transaction_id returned %d",
+                             dm_device_name(pool->pool_md), r);
                        goto err;
                }
 
                r = dm_pool_get_free_metadata_block_count(pool->pmd, &nr_free_blocks_metadata);
                if (r) {
-                       DMERR("dm_pool_get_free_metadata_block_count returned %d", r);
+                       DMERR("%s: dm_pool_get_free_metadata_block_count returned %d",
+                             dm_device_name(pool->pool_md), r);
                        goto err;
                }
 
                r = dm_pool_get_metadata_dev_size(pool->pmd, &nr_blocks_metadata);
                if (r) {
-                       DMERR("dm_pool_get_metadata_dev_size returned %d", r);
+                       DMERR("%s: dm_pool_get_metadata_dev_size returned %d",
+                             dm_device_name(pool->pool_md), r);
                        goto err;
                }
 
                r = dm_pool_get_free_block_count(pool->pmd, &nr_free_blocks_data);
                if (r) {
-                       DMERR("dm_pool_get_free_block_count returned %d", r);
+                       DMERR("%s: dm_pool_get_free_block_count returned %d",
+                             dm_device_name(pool->pool_md), r);
                        goto err;
                }
 
                r = dm_pool_get_data_dev_size(pool->pmd, &nr_blocks_data);
                if (r) {
-                       DMERR("dm_pool_get_data_dev_size returned %d", r);
+                       DMERR("%s: dm_pool_get_data_dev_size returned %d",
+                             dm_device_name(pool->pool_md), r);
                        goto err;
                }
 
                r = dm_pool_get_metadata_snap(pool->pmd, &held_root);
                if (r) {
-                       DMERR("dm_pool_get_metadata_snap returned %d", r);
+                       DMERR("%s: dm_pool_get_metadata_snap returned %d",
+                             dm_device_name(pool->pool_md), r);
                        goto err;
                }
 
@@ -2648,9 +2672,17 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
 {
        struct pool_c *pt = ti->private;
        struct pool *pool = pt->pool;
+       uint64_t io_opt_sectors = limits->io_opt >> SECTOR_SHIFT;
 
-       blk_limits_io_min(limits, 0);
-       blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+       /*
+        * If the system-determined stacked limits are compatible with the
+        * pool's blocksize (io_opt is a factor) do not override them.
+        */
+       if (io_opt_sectors < pool->sectors_per_block ||
+           do_div(io_opt_sectors, pool->sectors_per_block)) {
+               blk_limits_io_min(limits, 0);
+               blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
+       }
 
        /*
         * pt->adjusted_pf is a staging area for the actual features to use.
@@ -2669,7 +2701,7 @@ static struct target_type pool_target = {
        .name = "thin-pool",
        .features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
                    DM_TARGET_IMMUTABLE,
-       .version = {1, 8, 0},
+       .version = {1, 9, 0},
        .module = THIS_MODULE,
        .ctr = pool_ctr,
        .dtr = pool_dtr,
@@ -2956,7 +2988,7 @@ static int thin_iterate_devices(struct dm_target *ti,
 
 static struct target_type thin_target = {
        .name = "thin",
-       .version = {1, 8, 0},
+       .version = {1, 9, 0},
        .module = THIS_MODULE,
        .ctr = thin_ctr,
        .dtr = thin_dtr,
index 9e39d2b64bf8f3cc4a864e300ff61f5020b67dda..6a5e9ed2fcc3eb775268e2e5fc401efa55d6da3d 100644 (file)
@@ -60,6 +60,7 @@ struct dm_io {
        struct bio *bio;
        unsigned long start_time;
        spinlock_t endio_lock;
+       struct dm_stats_aux stats_aux;
 };
 
 /*
@@ -198,6 +199,8 @@ struct mapped_device {
 
        /* zero-length flush that will be cloned and submitted to targets */
        struct bio flush_bio;
+
+       struct dm_stats stats;
 };
 
 /*
@@ -269,6 +272,7 @@ static int (*_inits[])(void) __initdata = {
        dm_io_init,
        dm_kcopyd_init,
        dm_interface_init,
+       dm_statistics_init,
 };
 
 static void (*_exits[])(void) = {
@@ -279,6 +283,7 @@ static void (*_exits[])(void) = {
        dm_io_exit,
        dm_kcopyd_exit,
        dm_interface_exit,
+       dm_statistics_exit,
 };
 
 static int __init dm_init(void)
@@ -384,6 +389,16 @@ int dm_lock_for_deletion(struct mapped_device *md)
        return r;
 }
 
+sector_t dm_get_size(struct mapped_device *md)
+{
+       return get_capacity(md->disk);
+}
+
+struct dm_stats *dm_get_stats(struct mapped_device *md)
+{
+       return &md->stats;
+}
+
 static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
        struct mapped_device *md = bdev->bd_disk->private_data;
@@ -466,8 +481,9 @@ static int md_in_flight(struct mapped_device *md)
 static void start_io_acct(struct dm_io *io)
 {
        struct mapped_device *md = io->md;
+       struct bio *bio = io->bio;
        int cpu;
-       int rw = bio_data_dir(io->bio);
+       int rw = bio_data_dir(bio);
 
        io->start_time = jiffies;
 
@@ -476,6 +492,10 @@ static void start_io_acct(struct dm_io *io)
        part_stat_unlock();
        atomic_set(&dm_disk(md)->part0.in_flight[rw],
                atomic_inc_return(&md->pending[rw]));
+
+       if (unlikely(dm_stats_used(&md->stats)))
+               dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector,
+                                   bio_sectors(bio), false, 0, &io->stats_aux);
 }
 
 static void end_io_acct(struct dm_io *io)
@@ -491,6 +511,10 @@ static void end_io_acct(struct dm_io *io)
        part_stat_add(cpu, &dm_disk(md)->part0, ticks[rw], duration);
        part_stat_unlock();
 
+       if (unlikely(dm_stats_used(&md->stats)))
+               dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector,
+                                   bio_sectors(bio), true, duration, &io->stats_aux);
+
        /*
         * After this is decremented the bio must not be touched if it is
         * a flush.
@@ -1519,7 +1543,7 @@ static void _dm_request(struct request_queue *q, struct bio *bio)
        return;
 }
 
-static int dm_request_based(struct mapped_device *md)
+int dm_request_based(struct mapped_device *md)
 {
        return blk_queue_stackable(md->queue);
 }
@@ -1946,8 +1970,7 @@ static struct mapped_device *alloc_dev(int minor)
        add_disk(md->disk);
        format_dev_t(md->name, MKDEV(_major, minor));
 
-       md->wq = alloc_workqueue("kdmflush",
-                                WQ_NON_REENTRANT | WQ_MEM_RECLAIM, 0);
+       md->wq = alloc_workqueue("kdmflush", WQ_MEM_RECLAIM, 0);
        if (!md->wq)
                goto bad_thread;
 
@@ -1959,6 +1982,8 @@ static struct mapped_device *alloc_dev(int minor)
        md->flush_bio.bi_bdev = md->bdev;
        md->flush_bio.bi_rw = WRITE_FLUSH;
 
+       dm_stats_init(&md->stats);
+
        /* Populate the mapping, nobody knows we exist yet */
        spin_lock(&_minor_lock);
        old_md = idr_replace(&_minor_idr, md, minor);
@@ -2010,6 +2035,7 @@ static void free_dev(struct mapped_device *md)
 
        put_disk(md->disk);
        blk_cleanup_queue(md->queue);
+       dm_stats_cleanup(&md->stats);
        module_put(THIS_MODULE);
        kfree(md);
 }
@@ -2151,7 +2177,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
        /*
         * Wipe any geometry if the size of the table changed.
         */
-       if (size != get_capacity(md->disk))
+       if (size != dm_get_size(md))
                memset(&md->geometry, 0, sizeof(md->geometry));
 
        __set_size(md, size);
@@ -2236,11 +2262,13 @@ void dm_unlock_md_type(struct mapped_device *md)
 
 void dm_set_md_type(struct mapped_device *md, unsigned type)
 {
+       BUG_ON(!mutex_is_locked(&md->type_lock));
        md->type = type;
 }
 
 unsigned dm_get_md_type(struct mapped_device *md)
 {
+       BUG_ON(!mutex_is_locked(&md->type_lock));
        return md->type;
 }
 
@@ -2695,6 +2723,38 @@ out:
        return r;
 }
 
+/*
+ * Internal suspend/resume works like userspace-driven suspend. It waits
+ * until all bios finish and prevents issuing new bios to the target drivers.
+ * It may be used only from the kernel.
+ *
+ * Internal suspend holds md->suspend_lock, which prevents interaction with
+ * userspace-driven suspend.
+ */
+
+void dm_internal_suspend(struct mapped_device *md)
+{
+       mutex_lock(&md->suspend_lock);
+       if (dm_suspended_md(md))
+               return;
+
+       set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
+       synchronize_srcu(&md->io_barrier);
+       flush_workqueue(md->wq);
+       dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
+}
+
+void dm_internal_resume(struct mapped_device *md)
+{
+       if (dm_suspended_md(md))
+               goto done;
+
+       dm_queue_flush(md);
+
+done:
+       mutex_unlock(&md->suspend_lock);
+}
+
 /*-----------------------------------------------------------------
  * Event notification.
  *---------------------------------------------------------------*/
index 45b97da1bd061f02a32e0e7523fdf5125ffb1089..5e604cc7b4aa26c41db96c84c1fa0f306bcb698e 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/blkdev.h>
 #include <linux/hdreg.h>
 
+#include "dm-stats.h"
+
 /*
  * Suspend feature flags
  */
@@ -88,11 +90,22 @@ int dm_setup_md_queue(struct mapped_device *md);
  */
 #define dm_target_is_valid(t) ((t)->table)
 
+/*
+ * To check whether the target type is bio-based or not (request-based).
+ */
+#define dm_target_bio_based(t) ((t)->type->map != NULL)
+
 /*
  * To check whether the target type is request-based or not (bio-based).
  */
 #define dm_target_request_based(t) ((t)->type->map_rq != NULL)
 
+/*
+ * To check whether the target type is a hybrid (capable of being
+ * either request-based or bio-based).
+ */
+#define dm_target_hybrid(t) (dm_target_bio_based(t) && dm_target_request_based(t))
+
 /*-----------------------------------------------------------------
  * A registry of target types.
  *---------------------------------------------------------------*/
@@ -146,10 +159,16 @@ void dm_destroy(struct mapped_device *md);
 void dm_destroy_immediate(struct mapped_device *md);
 int dm_open_count(struct mapped_device *md);
 int dm_lock_for_deletion(struct mapped_device *md);
+int dm_request_based(struct mapped_device *md);
+sector_t dm_get_size(struct mapped_device *md);
+struct dm_stats *dm_get_stats(struct mapped_device *md);
 
 int dm_kobject_uevent(struct mapped_device *md, enum kobject_action action,
                      unsigned cookie);
 
+void dm_internal_suspend(struct mapped_device *md);
+void dm_internal_resume(struct mapped_device *md);
+
 int dm_io_init(void);
 void dm_io_exit(void);
 
@@ -162,4 +181,12 @@ void dm_kcopyd_exit(void);
 struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, unsigned per_bio_data_size);
 void dm_free_md_mempools(struct dm_md_mempools *pools);
 
+/*
+ * Helpers that are used by DM core
+ */
+static inline bool dm_message_test_buffer_overflow(char *result, unsigned maxlen)
+{
+       return !maxlen || strlen(result) + 1 >= maxlen;
+}
+
 #endif
index 9f13e13506efbb3859786879ed6a5ff42eb72e8f..adf4d7e1d5e15233a67e7108dc24b8a7bb6efeb1 100644 (file)
@@ -1180,7 +1180,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
                        mddev->bitmap_info.offset =
                                mddev->bitmap_info.default_offset;
                        mddev->bitmap_info.space =
-                               mddev->bitmap_info.space;
+                               mddev->bitmap_info.default_space;
                }
 
        } else if (mddev->pers == NULL) {
@@ -3429,7 +3429,7 @@ safe_delay_store(struct mddev *mddev, const char *cbuf, size_t len)
                mddev->safemode_delay = (msec*HZ)/1000;
                if (mddev->safemode_delay == 0)
                        mddev->safemode_delay = 1;
-               if (mddev->safemode_delay < old_delay)
+               if (mddev->safemode_delay < old_delay || old_delay == 0)
                        md_safemode_timeout((unsigned long)mddev);
        }
        return len;
@@ -5144,7 +5144,7 @@ int md_run(struct mddev *mddev)
        
        set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
        
-       if (mddev->flags)
+       if (mddev->flags & MD_UPDATE_SB_FLAGS)
                md_update_sb(mddev, 0);
 
        md_new_event(mddev);
@@ -5289,7 +5289,7 @@ static void __md_stop_writes(struct mddev *mddev)
        md_super_wait(mddev);
 
        if (mddev->ro == 0 &&
-           (!mddev->in_sync || mddev->flags)) {
+           (!mddev->in_sync || (mddev->flags & MD_UPDATE_SB_FLAGS))) {
                /* mark array as shutdown cleanly */
                mddev->in_sync = 1;
                md_update_sb(mddev, 1);
@@ -5337,8 +5337,14 @@ static int md_set_readonly(struct mddev *mddev, struct block_device *bdev)
                err = -EBUSY;
                goto out;
        }
-       if (bdev)
-               sync_blockdev(bdev);
+       if (bdev && !test_bit(MD_STILL_CLOSED, &mddev->flags)) {
+               /* Someone opened the device since we flushed it
+                * so page cache could be dirty and it is too late
+                * to flush.  So abort
+                */
+               mutex_unlock(&mddev->open_mutex);
+               return -EBUSY;
+       }
        if (mddev->pers) {
                __md_stop_writes(mddev);
 
@@ -5373,14 +5379,14 @@ static int do_md_stop(struct mddev * mddev, int mode,
                mutex_unlock(&mddev->open_mutex);
                return -EBUSY;
        }
-       if (bdev)
-               /* It is possible IO was issued on some other
-                * open file which was closed before we took ->open_mutex.
-                * As that was not the last close __blkdev_put will not
-                * have called sync_blockdev, so we must.
+       if (bdev && !test_bit(MD_STILL_CLOSED, &mddev->flags)) {
+               /* Someone opened the device since we flushed it
+                * so page cache could be dirty and it is too late
+                * to flush.  So abort
                 */
-               sync_blockdev(bdev);
-
+               mutex_unlock(&mddev->open_mutex);
+               return -EBUSY;
+       }
        if (mddev->pers) {
                if (mddev->ro)
                        set_disk_ro(disk, 0);
@@ -5628,10 +5634,7 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
        char *ptr, *buf = NULL;
        int err = -ENOMEM;
 
-       if (md_allow_write(mddev))
-               file = kmalloc(sizeof(*file), GFP_NOIO);
-       else
-               file = kmalloc(sizeof(*file), GFP_KERNEL);
+       file = kmalloc(sizeof(*file), GFP_NOIO);
 
        if (!file)
                goto out;
@@ -6420,6 +6423,20 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
                                                 !test_bit(MD_RECOVERY_NEEDED,
                                                           &mddev->flags),
                                                 msecs_to_jiffies(5000));
+       if (cmd == STOP_ARRAY || cmd == STOP_ARRAY_RO) {
+               /* Need to flush page cache, and ensure no-one else opens
+                * and writes
+                */
+               mutex_lock(&mddev->open_mutex);
+               if (atomic_read(&mddev->openers) > 1) {
+                       mutex_unlock(&mddev->open_mutex);
+                       err = -EBUSY;
+                       goto abort;
+               }
+               set_bit(MD_STILL_CLOSED, &mddev->flags);
+               mutex_unlock(&mddev->open_mutex);
+               sync_blockdev(bdev);
+       }
        err = mddev_lock(mddev);
        if (err) {
                printk(KERN_INFO 
@@ -6673,6 +6690,7 @@ static int md_open(struct block_device *bdev, fmode_t mode)
 
        err = 0;
        atomic_inc(&mddev->openers);
+       clear_bit(MD_STILL_CLOSED, &mddev->flags);
        mutex_unlock(&mddev->open_mutex);
 
        check_disk_change(bdev);
@@ -7817,7 +7835,7 @@ void md_check_recovery(struct mddev *mddev)
                                sysfs_notify_dirent_safe(mddev->sysfs_state);
                }
 
-               if (mddev->flags)
+               if (mddev->flags & MD_UPDATE_SB_FLAGS)
                        md_update_sb(mddev, 0);
 
                if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
index 20f02c0b5f2d6d99ac69a36067135f0b8196d9a7..608050c43f17e9d7688a9b3d1b749b7971d47c33 100644 (file)
@@ -204,12 +204,16 @@ struct mddev {
        struct md_personality           *pers;
        dev_t                           unit;
        int                             md_minor;
-       struct list_head                disks;
+       struct list_head                disks;
        unsigned long                   flags;
 #define MD_CHANGE_DEVS 0       /* Some device status has changed */
 #define MD_CHANGE_CLEAN 1      /* transition to or from 'clean' */
 #define MD_CHANGE_PENDING 2    /* switch from 'clean' to 'active' in progress */
+#define MD_UPDATE_SB_FLAGS (1 | 2 | 4) /* If these are set, md_update_sb needed */
 #define MD_ARRAY_FIRST_USE 3    /* First use of array, needs initialization */
+#define MD_STILL_CLOSED        4       /* If set, then array has not been opened since
+                                * md_ioctl checked on it.
+                                */
 
        int                             suspended;
        atomic_t                        active_io;
@@ -218,7 +222,7 @@ struct mddev {
                                                       * are happening, so run/
                                                       * takeover/stop are not safe
                                                       */
-       int                             ready; /* See when safe to pass 
+       int                             ready; /* See when safe to pass
                                                * IO requests down */
        struct gendisk                  *gendisk;
 
index 81b513890e2bfd8d41b1c48f986c9c9a187f336c..a7e8bf2963886dfa349a03644cf33ff1ded748c5 100644 (file)
@@ -615,6 +615,11 @@ int dm_bm_flush_and_unlock(struct dm_block_manager *bm,
 }
 EXPORT_SYMBOL_GPL(dm_bm_flush_and_unlock);
 
+void dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b)
+{
+       dm_bufio_prefetch(bm->bufio, b, 1);
+}
+
 void dm_bm_set_read_only(struct dm_block_manager *bm)
 {
        bm->read_only = true;
index be5bff61be280562932906b1b182ef1d3775ea55..9a82083a66b6a86833bccc1d2b6d4d43c9de6500 100644 (file)
@@ -108,6 +108,11 @@ int dm_bm_unlock(struct dm_block *b);
 int dm_bm_flush_and_unlock(struct dm_block_manager *bm,
                           struct dm_block *superblock);
 
+ /*
+  * Request data be prefetched into the cache.
+  */
+void dm_bm_prefetch(struct dm_block_manager *bm, dm_block_t b);
+
 /*
  * Switches the bm to a read only mode.  Once read-only mode
  * has been entered the following functions will return -EPERM.
index 35865425e4b4443e925014fd918655ef51c07d57..468e371ee9b22d036fc6e5cca36ca0f46acb4f6a 100644 (file)
@@ -161,6 +161,7 @@ struct frame {
 };
 
 struct del_stack {
+       struct dm_btree_info *info;
        struct dm_transaction_manager *tm;
        int top;
        struct frame spine[MAX_SPINE_DEPTH];
@@ -183,6 +184,20 @@ static int unprocessed_frames(struct del_stack *s)
        return s->top >= 0;
 }
 
+static void prefetch_children(struct del_stack *s, struct frame *f)
+{
+       unsigned i;
+       struct dm_block_manager *bm = dm_tm_get_bm(s->tm);
+
+       for (i = 0; i < f->nr_children; i++)
+               dm_bm_prefetch(bm, value64(f->n, i));
+}
+
+static bool is_internal_level(struct dm_btree_info *info, struct frame *f)
+{
+       return f->level < (info->levels - 1);
+}
+
 static int push_frame(struct del_stack *s, dm_block_t b, unsigned level)
 {
        int r;
@@ -205,6 +220,7 @@ static int push_frame(struct del_stack *s, dm_block_t b, unsigned level)
                dm_tm_dec(s->tm, b);
 
        else {
+               uint32_t flags;
                struct frame *f = s->spine + ++s->top;
 
                r = dm_tm_read_lock(s->tm, b, &btree_node_validator, &f->b);
@@ -217,6 +233,10 @@ static int push_frame(struct del_stack *s, dm_block_t b, unsigned level)
                f->level = level;
                f->nr_children = le32_to_cpu(f->n->header.nr_entries);
                f->current_child = 0;
+
+               flags = le32_to_cpu(f->n->header.flags);
+               if (flags & INTERNAL_NODE || is_internal_level(s->info, f))
+                       prefetch_children(s, f);
        }
 
        return 0;
@@ -230,11 +250,6 @@ static void pop_frame(struct del_stack *s)
        dm_tm_unlock(s->tm, f->b);
 }
 
-static bool is_internal_level(struct dm_btree_info *info, struct frame *f)
-{
-       return f->level < (info->levels - 1);
-}
-
 int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
 {
        int r;
@@ -243,6 +258,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
        s = kmalloc(sizeof(*s), GFP_KERNEL);
        if (!s)
                return -ENOMEM;
+       s->info = info;
        s->tm = info->tm;
        s->top = -1;
 
@@ -287,7 +303,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
                                        info->value_type.dec(info->value_type.context,
                                                             value_ptr(f->n, i));
                        }
-                       f->current_child = f->nr_children;
+                       pop_frame(s);
                }
        }
 
index 3e7a88d99eb0260ce4e9128f94349713b28170c5..6058569fe86c3dcf862ddc933e234e721dbdc3e6 100644 (file)
@@ -292,16 +292,11 @@ int sm_ll_lookup_bitmap(struct ll_disk *ll, dm_block_t b, uint32_t *result)
        return dm_tm_unlock(ll->tm, blk);
 }
 
-int sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result)
+static int sm_ll_lookup_big_ref_count(struct ll_disk *ll, dm_block_t b,
+                                     uint32_t *result)
 {
        __le32 le_rc;
-       int r = sm_ll_lookup_bitmap(ll, b, result);
-
-       if (r)
-               return r;
-
-       if (*result != 3)
-               return r;
+       int r;
 
        r = dm_btree_lookup(&ll->ref_count_info, ll->ref_count_root, &b, &le_rc);
        if (r < 0)
@@ -312,6 +307,19 @@ int sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result)
        return r;
 }
 
+int sm_ll_lookup(struct ll_disk *ll, dm_block_t b, uint32_t *result)
+{
+       int r = sm_ll_lookup_bitmap(ll, b, result);
+
+       if (r)
+               return r;
+
+       if (*result != 3)
+               return r;
+
+       return sm_ll_lookup_big_ref_count(ll, b, result);
+}
+
 int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
                          dm_block_t end, dm_block_t *result)
 {
@@ -372,11 +380,12 @@ int sm_ll_find_free_block(struct ll_disk *ll, dm_block_t begin,
        return -ENOSPC;
 }
 
-int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
-                uint32_t ref_count, enum allocation_event *ev)
+static int sm_ll_mutate(struct ll_disk *ll, dm_block_t b,
+                       uint32_t (*mutator)(void *context, uint32_t old),
+                       void *context, enum allocation_event *ev)
 {
        int r;
-       uint32_t bit, old;
+       uint32_t bit, old, ref_count;
        struct dm_block *nb;
        dm_block_t index = b;
        struct disk_index_entry ie_disk;
@@ -399,6 +408,14 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
        bm_le = dm_bitmap_data(nb);
        old = sm_lookup_bitmap(bm_le, bit);
 
+       if (old > 2) {
+               r = sm_ll_lookup_big_ref_count(ll, b, &old);
+               if (r < 0)
+                       return r;
+       }
+
+       ref_count = mutator(context, old);
+
        if (ref_count <= 2) {
                sm_set_bitmap(bm_le, bit, ref_count);
 
@@ -448,31 +465,35 @@ int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
        return ll->save_ie(ll, index, &ie_disk);
 }
 
-int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
+static uint32_t set_ref_count(void *context, uint32_t old)
 {
-       int r;
-       uint32_t rc;
-
-       r = sm_ll_lookup(ll, b, &rc);
-       if (r)
-               return r;
+       return *((uint32_t *) context);
+}
 
-       return sm_ll_insert(ll, b, rc + 1, ev);
+int sm_ll_insert(struct ll_disk *ll, dm_block_t b,
+                uint32_t ref_count, enum allocation_event *ev)
+{
+       return sm_ll_mutate(ll, b, set_ref_count, &ref_count, ev);
 }
 
-int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
+static uint32_t inc_ref_count(void *context, uint32_t old)
 {
-       int r;
-       uint32_t rc;
+       return old + 1;
+}
 
-       r = sm_ll_lookup(ll, b, &rc);
-       if (r)
-               return r;
+int sm_ll_inc(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
+{
+       return sm_ll_mutate(ll, b, inc_ref_count, NULL, ev);
+}
 
-       if (!rc)
-               return -EINVAL;
+static uint32_t dec_ref_count(void *context, uint32_t old)
+{
+       return old - 1;
+}
 
-       return sm_ll_insert(ll, b, rc - 1, ev);
+int sm_ll_dec(struct ll_disk *ll, dm_block_t b, enum allocation_event *ev)
+{
+       return sm_ll_mutate(ll, b, dec_ref_count, NULL, ev);
 }
 
 int sm_ll_commit(struct ll_disk *ll)
index 78ea44336e75e06d5769b4a6158f2a1e506214e0..7ff4f252ca1a42943252a9e19b975da5b2f8ce9b 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/cpu.h>
 #include <linux/slab.h>
 #include <linux/ratelimit.h>
+#include <linux/nodemask.h>
 #include <trace/events/block.h>
 
 #include "md.h"
 #include "raid0.h"
 #include "bitmap.h"
 
+#define cpu_to_group(cpu) cpu_to_node(cpu)
+#define ANY_GROUP NUMA_NO_NODE
+
+static struct workqueue_struct *raid5_wq;
 /*
  * Stripe cache
  */
@@ -72,6 +77,7 @@
 #define BYPASS_THRESHOLD       1
 #define NR_HASH                        (PAGE_SIZE / sizeof(struct hlist_head))
 #define HASH_MASK              (NR_HASH - 1)
+#define MAX_STRIPE_BATCH       8
 
 static inline struct hlist_head *stripe_hash(struct r5conf *conf, sector_t sect)
 {
@@ -200,6 +206,49 @@ static int stripe_operations_active(struct stripe_head *sh)
               test_bit(STRIPE_COMPUTE_RUN, &sh->state);
 }
 
+static void raid5_wakeup_stripe_thread(struct stripe_head *sh)
+{
+       struct r5conf *conf = sh->raid_conf;
+       struct r5worker_group *group;
+       int thread_cnt;
+       int i, cpu = sh->cpu;
+
+       if (!cpu_online(cpu)) {
+               cpu = cpumask_any(cpu_online_mask);
+               sh->cpu = cpu;
+       }
+
+       if (list_empty(&sh->lru)) {
+               struct r5worker_group *group;
+               group = conf->worker_groups + cpu_to_group(cpu);
+               list_add_tail(&sh->lru, &group->handle_list);
+               group->stripes_cnt++;
+               sh->group = group;
+       }
+
+       if (conf->worker_cnt_per_group == 0) {
+               md_wakeup_thread(conf->mddev->thread);
+               return;
+       }
+
+       group = conf->worker_groups + cpu_to_group(sh->cpu);
+
+       group->workers[0].working = true;
+       /* at least one worker should run to avoid race */
+       queue_work_on(sh->cpu, raid5_wq, &group->workers[0].work);
+
+       thread_cnt = group->stripes_cnt / MAX_STRIPE_BATCH - 1;
+       /* wakeup more workers */
+       for (i = 1; i < conf->worker_cnt_per_group && thread_cnt > 0; i++) {
+               if (group->workers[i].working == false) {
+                       group->workers[i].working = true;
+                       queue_work_on(sh->cpu, raid5_wq,
+                                     &group->workers[i].work);
+                       thread_cnt--;
+               }
+       }
+}
+
 static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
 {
        BUG_ON(!list_empty(&sh->lru));
@@ -214,7 +263,12 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh)
                else {
                        clear_bit(STRIPE_DELAYED, &sh->state);
                        clear_bit(STRIPE_BIT_DELAY, &sh->state);
-                       list_add_tail(&sh->lru, &conf->handle_list);
+                       if (conf->worker_cnt_per_group == 0) {
+                               list_add_tail(&sh->lru, &conf->handle_list);
+                       } else {
+                               raid5_wakeup_stripe_thread(sh);
+                               return;
+                       }
                }
                md_wakeup_thread(conf->mddev->thread);
        } else {
@@ -239,12 +293,62 @@ static void __release_stripe(struct r5conf *conf, struct stripe_head *sh)
                do_release_stripe(conf, sh);
 }
 
+static struct llist_node *llist_reverse_order(struct llist_node *head)
+{
+       struct llist_node *new_head = NULL;
+
+       while (head) {
+               struct llist_node *tmp = head;
+               head = head->next;
+               tmp->next = new_head;
+               new_head = tmp;
+       }
+
+       return new_head;
+}
+
+/* should hold conf->device_lock already */
+static int release_stripe_list(struct r5conf *conf)
+{
+       struct stripe_head *sh;
+       int count = 0;
+       struct llist_node *head;
+
+       head = llist_del_all(&conf->released_stripes);
+       head = llist_reverse_order(head);
+       while (head) {
+               sh = llist_entry(head, struct stripe_head, release_list);
+               head = llist_next(head);
+               /* sh could be readded after STRIPE_ON_RELEASE_LIST is cleard */
+               smp_mb();
+               clear_bit(STRIPE_ON_RELEASE_LIST, &sh->state);
+               /*
+                * Don't worry the bit is set here, because if the bit is set
+                * again, the count is always > 1. This is true for
+                * STRIPE_ON_UNPLUG_LIST bit too.
+                */
+               __release_stripe(conf, sh);
+               count++;
+       }
+
+       return count;
+}
+
 static void release_stripe(struct stripe_head *sh)
 {
        struct r5conf *conf = sh->raid_conf;
        unsigned long flags;
+       bool wakeup;
 
+       if (test_and_set_bit(STRIPE_ON_RELEASE_LIST, &sh->state))
+               goto slow_path;
+       wakeup = llist_add(&sh->release_list, &conf->released_stripes);
+       if (wakeup)
+               md_wakeup_thread(conf->mddev->thread);
+       return;
+slow_path:
        local_irq_save(flags);
+       /* we are ok here if STRIPE_ON_RELEASE_LIST is set or not */
        if (atomic_dec_and_lock(&sh->count, &conf->device_lock)) {
                do_release_stripe(conf, sh);
                spin_unlock(&conf->device_lock);
@@ -359,6 +463,7 @@ static void init_stripe(struct stripe_head *sh, sector_t sector, int previous)
                raid5_build_block(sh, i, previous);
        }
        insert_hash(conf, sh);
+       sh->cpu = smp_processor_id();
 }
 
 static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector,
@@ -491,7 +596,8 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
                        if (atomic_read(&sh->count)) {
                                BUG_ON(!list_empty(&sh->lru)
                                    && !test_bit(STRIPE_EXPANDING, &sh->state)
-                                   && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state));
+                                   && !test_bit(STRIPE_ON_UNPLUG_LIST, &sh->state)
+                                   && !test_bit(STRIPE_ON_RELEASE_LIST, &sh->state));
                        } else {
                                if (!test_bit(STRIPE_HANDLE, &sh->state))
                                        atomic_inc(&conf->active_stripes);
@@ -499,6 +605,10 @@ get_active_stripe(struct r5conf *conf, sector_t sector,
                                    !test_bit(STRIPE_EXPANDING, &sh->state))
                                        BUG();
                                list_del_init(&sh->lru);
+                               if (sh->group) {
+                                       sh->group->stripes_cnt--;
+                                       sh->group = NULL;
+                               }
                        }
                }
        } while (sh == NULL);
@@ -3779,6 +3889,7 @@ static void raid5_activate_delayed(struct r5conf *conf)
                        if (!test_and_set_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
                                atomic_inc(&conf->preread_active_stripes);
                        list_add_tail(&sh->lru, &conf->hold_list);
+                       raid5_wakeup_stripe_thread(sh);
                }
        }
 }
@@ -4058,18 +4169,35 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
  * head of the hold_list has changed, i.e. the head was promoted to the
  * handle_list.
  */
-static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
+static struct stripe_head *__get_priority_stripe(struct r5conf *conf, int group)
 {
-       struct stripe_head *sh;
+       struct stripe_head *sh = NULL, *tmp;
+       struct list_head *handle_list = NULL;
+       struct r5worker_group *wg = NULL;
+
+       if (conf->worker_cnt_per_group == 0) {
+               handle_list = &conf->handle_list;
+       } else if (group != ANY_GROUP) {
+               handle_list = &conf->worker_groups[group].handle_list;
+               wg = &conf->worker_groups[group];
+       } else {
+               int i;
+               for (i = 0; i < conf->group_cnt; i++) {
+                       handle_list = &conf->worker_groups[i].handle_list;
+                       wg = &conf->worker_groups[i];
+                       if (!list_empty(handle_list))
+                               break;
+               }
+       }
 
        pr_debug("%s: handle: %s hold: %s full_writes: %d bypass_count: %d\n",
                  __func__,
-                 list_empty(&conf->handle_list) ? "empty" : "busy",
+                 list_empty(handle_list) ? "empty" : "busy",
                  list_empty(&conf->hold_list) ? "empty" : "busy",
                  atomic_read(&conf->pending_full_writes), conf->bypass_count);
 
-       if (!list_empty(&conf->handle_list)) {
-               sh = list_entry(conf->handle_list.next, typeof(*sh), lru);
+       if (!list_empty(handle_list)) {
+               sh = list_entry(handle_list->next, typeof(*sh), lru);
 
                if (list_empty(&conf->hold_list))
                        conf->bypass_count = 0;
@@ -4087,14 +4215,32 @@ static struct stripe_head *__get_priority_stripe(struct r5conf *conf)
                   ((conf->bypass_threshold &&
                     conf->bypass_count > conf->bypass_threshold) ||
                    atomic_read(&conf->pending_full_writes) == 0)) {
-               sh = list_entry(conf->hold_list.next,
-                               typeof(*sh), lru);
-               conf->bypass_count -= conf->bypass_threshold;
-               if (conf->bypass_count < 0)
-                       conf->bypass_count = 0;
-       } else
+
+               list_for_each_entry(tmp, &conf->hold_list,  lru) {
+                       if (conf->worker_cnt_per_group == 0 ||
+                           group == ANY_GROUP ||
+                           !cpu_online(tmp->cpu) ||
+                           cpu_to_group(tmp->cpu) == group) {
+                               sh = tmp;
+                               break;
+                       }
+               }
+
+               if (sh) {
+                       conf->bypass_count -= conf->bypass_threshold;
+                       if (conf->bypass_count < 0)
+                               conf->bypass_count = 0;
+               }
+               wg = NULL;
+       }
+
+       if (!sh)
                return NULL;
 
+       if (wg) {
+               wg->stripes_cnt--;
+               sh->group = NULL;
+       }
        list_del_init(&sh->lru);
        atomic_inc(&sh->count);
        BUG_ON(atomic_read(&sh->count) != 1);
@@ -4127,6 +4273,10 @@ static void raid5_unplug(struct blk_plug_cb *blk_cb, bool from_schedule)
                         */
                        smp_mb__before_clear_bit();
                        clear_bit(STRIPE_ON_UNPLUG_LIST, &sh->state);
+                       /*
+                        * STRIPE_ON_RELEASE_LIST could be set here. In that
+                        * case, the count is always > 1 here
+                        */
                        __release_stripe(conf, sh);
                        cnt++;
                }
@@ -4286,8 +4436,10 @@ static void make_request(struct mddev *mddev, struct bio * bi)
        for (;logical_sector < last_sector; logical_sector += STRIPE_SECTORS) {
                DEFINE_WAIT(w);
                int previous;
+               int seq;
 
        retry:
+               seq = read_seqcount_begin(&conf->gen_lock);
                previous = 0;
                prepare_to_wait(&conf->wait_for_overlap, &w, TASK_UNINTERRUPTIBLE);
                if (unlikely(conf->reshape_progress != MaxSector)) {
@@ -4320,7 +4472,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                                  previous,
                                                  &dd_idx, NULL);
                pr_debug("raid456: make_request, sector %llu logical %llu\n",
-                       (unsigned long long)new_sector, 
+                       (unsigned long long)new_sector,
                        (unsigned long long)logical_sector);
 
                sh = get_active_stripe(conf, new_sector, previous,
@@ -4349,6 +4501,13 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                                        goto retry;
                                }
                        }
+                       if (read_seqcount_retry(&conf->gen_lock, seq)) {
+                               /* Might have got the wrong stripe_head
+                                * by accident
+                                */
+                               release_stripe(sh);
+                               goto retry;
+                       }
 
                        if (rw == WRITE &&
                            logical_sector >= mddev->suspend_lo &&
@@ -4788,14 +4947,14 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
        return handled;
 }
 
-#define MAX_STRIPE_BATCH 8
-static int handle_active_stripes(struct r5conf *conf)
+static int handle_active_stripes(struct r5conf *conf, int group,
+                                struct r5worker *worker)
 {
        struct stripe_head *batch[MAX_STRIPE_BATCH], *sh;
        int i, batch_size = 0;
 
        while (batch_size < MAX_STRIPE_BATCH &&
-                       (sh = __get_priority_stripe(conf)) != NULL)
+                       (sh = __get_priority_stripe(conf, group)) != NULL)
                batch[batch_size++] = sh;
 
        if (batch_size == 0)
@@ -4813,6 +4972,39 @@ static int handle_active_stripes(struct r5conf *conf)
        return batch_size;
 }
 
+static void raid5_do_work(struct work_struct *work)
+{
+       struct r5worker *worker = container_of(work, struct r5worker, work);
+       struct r5worker_group *group = worker->group;
+       struct r5conf *conf = group->conf;
+       int group_id = group - conf->worker_groups;
+       int handled;
+       struct blk_plug plug;
+
+       pr_debug("+++ raid5worker active\n");
+
+       blk_start_plug(&plug);
+       handled = 0;
+       spin_lock_irq(&conf->device_lock);
+       while (1) {
+               int batch_size, released;
+
+               released = release_stripe_list(conf);
+
+               batch_size = handle_active_stripes(conf, group_id, worker);
+               worker->working = false;
+               if (!batch_size && !released)
+                       break;
+               handled += batch_size;
+       }
+       pr_debug("%d stripes handled\n", handled);
+
+       spin_unlock_irq(&conf->device_lock);
+       blk_finish_plug(&plug);
+
+       pr_debug("--- raid5worker inactive\n");
+}
+
 /*
  * This is our raid5 kernel thread.
  *
@@ -4836,7 +5028,9 @@ static void raid5d(struct md_thread *thread)
        spin_lock_irq(&conf->device_lock);
        while (1) {
                struct bio *bio;
-               int batch_size;
+               int batch_size, released;
+
+               released = release_stripe_list(conf);
 
                if (
                    !list_empty(&conf->bitmap_list)) {
@@ -4860,8 +5054,8 @@ static void raid5d(struct md_thread *thread)
                        handled++;
                }
 
-               batch_size = handle_active_stripes(conf);
-               if (!batch_size)
+               batch_size = handle_active_stripes(conf, ANY_GROUP, NULL);
+               if (!batch_size && !released)
                        break;
                handled += batch_size;
 
@@ -4989,10 +5183,70 @@ stripe_cache_active_show(struct mddev *mddev, char *page)
 static struct md_sysfs_entry
 raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
 
+static ssize_t
+raid5_show_group_thread_cnt(struct mddev *mddev, char *page)
+{
+       struct r5conf *conf = mddev->private;
+       if (conf)
+               return sprintf(page, "%d\n", conf->worker_cnt_per_group);
+       else
+               return 0;
+}
+
+static int alloc_thread_groups(struct r5conf *conf, int cnt);
+static ssize_t
+raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
+{
+       struct r5conf *conf = mddev->private;
+       unsigned long new;
+       int err;
+       struct r5worker_group *old_groups;
+       int old_group_cnt;
+
+       if (len >= PAGE_SIZE)
+               return -EINVAL;
+       if (!conf)
+               return -ENODEV;
+
+       if (kstrtoul(page, 10, &new))
+               return -EINVAL;
+
+       if (new == conf->worker_cnt_per_group)
+               return len;
+
+       mddev_suspend(mddev);
+
+       old_groups = conf->worker_groups;
+       old_group_cnt = conf->worker_cnt_per_group;
+
+       conf->worker_groups = NULL;
+       err = alloc_thread_groups(conf, new);
+       if (err) {
+               conf->worker_groups = old_groups;
+               conf->worker_cnt_per_group = old_group_cnt;
+       } else {
+               if (old_groups)
+                       kfree(old_groups[0].workers);
+               kfree(old_groups);
+       }
+
+       mddev_resume(mddev);
+
+       if (err)
+               return err;
+       return len;
+}
+
+static struct md_sysfs_entry
+raid5_group_thread_cnt = __ATTR(group_thread_cnt, S_IRUGO | S_IWUSR,
+                               raid5_show_group_thread_cnt,
+                               raid5_store_group_thread_cnt);
+
 static struct attribute *raid5_attrs[] =  {
        &raid5_stripecache_size.attr,
        &raid5_stripecache_active.attr,
        &raid5_preread_bypass_threshold.attr,
+       &raid5_group_thread_cnt.attr,
        NULL,
 };
 static struct attribute_group raid5_attrs_group = {
@@ -5000,6 +5254,54 @@ static struct attribute_group raid5_attrs_group = {
        .attrs = raid5_attrs,
 };
 
+static int alloc_thread_groups(struct r5conf *conf, int cnt)
+{
+       int i, j;
+       ssize_t size;
+       struct r5worker *workers;
+
+       conf->worker_cnt_per_group = cnt;
+       if (cnt == 0) {
+               conf->worker_groups = NULL;
+               return 0;
+       }
+       conf->group_cnt = num_possible_nodes();
+       size = sizeof(struct r5worker) * cnt;
+       workers = kzalloc(size * conf->group_cnt, GFP_NOIO);
+       conf->worker_groups = kzalloc(sizeof(struct r5worker_group) *
+                               conf->group_cnt, GFP_NOIO);
+       if (!conf->worker_groups || !workers) {
+               kfree(workers);
+               kfree(conf->worker_groups);
+               conf->worker_groups = NULL;
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < conf->group_cnt; i++) {
+               struct r5worker_group *group;
+
+               group = &conf->worker_groups[i];
+               INIT_LIST_HEAD(&group->handle_list);
+               group->conf = conf;
+               group->workers = workers + i * cnt;
+
+               for (j = 0; j < cnt; j++) {
+                       group->workers[j].group = group;
+                       INIT_WORK(&group->workers[j].work, raid5_do_work);
+               }
+       }
+
+       return 0;
+}
+
+static void free_thread_groups(struct r5conf *conf)
+{
+       if (conf->worker_groups)
+               kfree(conf->worker_groups[0].workers);
+       kfree(conf->worker_groups);
+       conf->worker_groups = NULL;
+}
+
 static sector_t
 raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks)
 {
@@ -5040,6 +5342,7 @@ static void raid5_free_percpu(struct r5conf *conf)
 
 static void free_conf(struct r5conf *conf)
 {
+       free_thread_groups(conf);
        shrink_stripes(conf);
        raid5_free_percpu(conf);
        kfree(conf->disks);
@@ -5168,7 +5471,11 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        conf = kzalloc(sizeof(struct r5conf), GFP_KERNEL);
        if (conf == NULL)
                goto abort;
+       /* Don't enable multi-threading by default*/
+       if (alloc_thread_groups(conf, 0))
+               goto abort;
        spin_lock_init(&conf->device_lock);
+       seqcount_init(&conf->gen_lock);
        init_waitqueue_head(&conf->wait_for_stripe);
        init_waitqueue_head(&conf->wait_for_overlap);
        INIT_LIST_HEAD(&conf->handle_list);
@@ -5176,6 +5483,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
        INIT_LIST_HEAD(&conf->delayed_list);
        INIT_LIST_HEAD(&conf->bitmap_list);
        INIT_LIST_HEAD(&conf->inactive_list);
+       init_llist_head(&conf->released_stripes);
        atomic_set(&conf->active_stripes, 0);
        atomic_set(&conf->preread_active_stripes, 0);
        atomic_set(&conf->active_aligned_reads, 0);
@@ -5980,6 +6288,7 @@ static int raid5_start_reshape(struct mddev *mddev)
 
        atomic_set(&conf->reshape_stripes, 0);
        spin_lock_irq(&conf->device_lock);
+       write_seqcount_begin(&conf->gen_lock);
        conf->previous_raid_disks = conf->raid_disks;
        conf->raid_disks += mddev->delta_disks;
        conf->prev_chunk_sectors = conf->chunk_sectors;
@@ -5996,8 +6305,16 @@ static int raid5_start_reshape(struct mddev *mddev)
        else
                conf->reshape_progress = 0;
        conf->reshape_safe = conf->reshape_progress;
+       write_seqcount_end(&conf->gen_lock);
        spin_unlock_irq(&conf->device_lock);
 
+       /* Now make sure any requests that proceeded on the assumption
+        * the reshape wasn't running - like Discard or Read - have
+        * completed.
+        */
+       mddev_suspend(mddev);
+       mddev_resume(mddev);
+
        /* Add some new drives, as many as will fit.
         * We know there are enough to make the newly sized array work.
         * Don't add devices if we are reducing the number of
@@ -6472,6 +6789,10 @@ static struct md_personality raid4_personality =
 
 static int __init raid5_init(void)
 {
+       raid5_wq = alloc_workqueue("raid5wq",
+               WQ_UNBOUND|WQ_MEM_RECLAIM|WQ_CPU_INTENSIVE|WQ_SYSFS, 0);
+       if (!raid5_wq)
+               return -ENOMEM;
        register_md_personality(&raid6_personality);
        register_md_personality(&raid5_personality);
        register_md_personality(&raid4_personality);
@@ -6483,6 +6804,7 @@ static void raid5_exit(void)
        unregister_md_personality(&raid6_personality);
        unregister_md_personality(&raid5_personality);
        unregister_md_personality(&raid4_personality);
+       destroy_workqueue(raid5_wq);
 }
 
 module_init(raid5_init);
index 70c49329ca9a23fbbad73061477ac0a0cfe80e6e..2113ffa82c7a2506d21ce36076c3f6bd057d922b 100644 (file)
@@ -197,6 +197,7 @@ enum reconstruct_states {
 struct stripe_head {
        struct hlist_node       hash;
        struct list_head        lru;          /* inactive_list or handle_list */
+       struct llist_node       release_list;
        struct r5conf           *raid_conf;
        short                   generation;     /* increments with every
                                                 * reshape */
@@ -211,6 +212,8 @@ struct stripe_head {
        enum check_states       check_state;
        enum reconstruct_states reconstruct_state;
        spinlock_t              stripe_lock;
+       int                     cpu;
+       struct r5worker_group   *group;
        /**
         * struct stripe_operations
         * @target - STRIPE_OP_COMPUTE_BLK target
@@ -321,6 +324,7 @@ enum {
        STRIPE_OPS_REQ_PENDING,
        STRIPE_ON_UNPLUG_LIST,
        STRIPE_DISCARD,
+       STRIPE_ON_RELEASE_LIST,
 };
 
 /*
@@ -363,6 +367,19 @@ struct disk_info {
        struct md_rdev  *rdev, *replacement;
 };
 
+struct r5worker {
+       struct work_struct work;
+       struct r5worker_group *group;
+       bool working;
+};
+
+struct r5worker_group {
+       struct list_head handle_list;
+       struct r5conf *conf;
+       struct r5worker *workers;
+       int stripes_cnt;
+};
+
 struct r5conf {
        struct hlist_head       *stripe_hashtbl;
        struct mddev            *mddev;
@@ -386,6 +403,7 @@ struct r5conf {
        int                     prev_chunk_sectors;
        int                     prev_algo;
        short                   generation; /* increments with every reshape */
+       seqcount_t              gen_lock;       /* lock against generation changes */
        unsigned long           reshape_checkpoint; /* Time we last updated
                                                     * metadata */
        long long               min_offset_diff; /* minimum difference between
@@ -445,6 +463,7 @@ struct r5conf {
         */
        atomic_t                active_stripes;
        struct list_head        inactive_list;
+       struct llist_head       released_stripes;
        wait_queue_head_t       wait_for_stripe;
        wait_queue_head_t       wait_for_overlap;
        int                     inactive_blocked;       /* release of inactive stripes blocked,
@@ -458,6 +477,9 @@ struct r5conf {
         * the new thread here until we fully activate the array.
         */
        struct md_thread        *thread;
+       struct r5worker_group   *worker_groups;
+       int                     group_cnt;
+       int                     worker_cnt_per_group;
 };
 
 /*
index 8068d7b6415532183839f1281d3e6dbef5949098..c7caf94621b418b351f19c040267c98754e4a924 100644 (file)
@@ -203,7 +203,7 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
 
 config VIDEO_SH_VEU
        tristate "SuperH VEU mem2mem video processing driver"
-       depends on VIDEO_DEV && VIDEO_V4L2 && GENERIC_HARDIRQS && HAS_DMA
+       depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
        select VIDEOBUF2_DMA_CONTIG
        select V4L2_MEM2MEM_DEV
        help
index 39882ddd2594ffe5b3792f0f0b0a14ec1a2f10ec..6ecdc39bb366c66cdc5998ef37eca73092edb569 100644 (file)
@@ -214,7 +214,7 @@ config RADIO_TIMBERDALE
 
 config RADIO_WL1273
        tristate "Texas Instruments WL1273 I2C FM Radio"
-       depends on I2C && VIDEO_V4L2 && GENERIC_HARDIRQS
+       depends on I2C && VIDEO_V4L2
        select MFD_CORE
        select MFD_WL1273_CORE
        select FW_LOADER
index 95f1814b5368c55bd05e7f2eef1c5759b476c41f..1d389491d5fdfcd1d31e3f77b4b4f07107105ff5 100644 (file)
@@ -24,3 +24,15 @@ config MSPRO_BLOCK
          support. This provides a block device driver, which you can use
          to mount the filesystem. Almost everyone wishing MemoryStick
          support should say Y or M here.
+
+config MS_BLOCK
+       tristate "MemoryStick Standard device driver"
+       depends on BLOCK
+       help
+         Say Y here to enable the MemoryStick Standard device driver
+         support. This provides a block device driver, which you can use
+         to mount the filesystem.
+         This driver works with old (bulky) MemoryStick and MemoryStick Duo
+         but not PRO. Say Y if you have such card.
+         Driver is new and not yet well tested, thus it can damage your card
+         (even permanently)
index ecd0299377386fee7e062a87c9209a5ad36f22f1..0d7f90c0ff25d6a03ef85d0a6c950af465565321 100644 (file)
@@ -3,5 +3,5 @@
 #
 
 obj-$(CONFIG_MEMSTICK)         += memstick.o
-
+obj-$(CONFIG_MS_BLOCK)         += ms_block.o
 obj-$(CONFIG_MSPRO_BLOCK)      += mspro_block.o
diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c
new file mode 100644 (file)
index 0000000..08e7023
--- /dev/null
@@ -0,0 +1,2385 @@
+/*
+ *  ms_block.c - Sony MemoryStick (legacy) storage support
+
+ *  Copyright (C) 2013 Maxim Levitsky <maximlevitsky@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.
+ *
+ * Minor portions of the driver were copied from mspro_block.c which is
+ * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
+ *
+ */
+#define DRIVER_NAME "ms_block"
+#define pr_fmt(fmt) DRIVER_NAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/memstick.h>
+#include <linux/idr.h>
+#include <linux/hdreg.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/bitmap.h>
+#include <linux/scatterlist.h>
+#include <linux/jiffies.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+#include "ms_block.h"
+
+static int debug;
+static int cache_flush_timeout = 1000;
+static bool verify_writes;
+
+/*
+ * Copies section of 'sg_from' starting from offset 'offset' and with length
+ * 'len' To another scatterlist of to_nents enties
+ */
+static size_t msb_sg_copy(struct scatterlist *sg_from,
+       struct scatterlist *sg_to, int to_nents, size_t offset, size_t len)
+{
+       size_t copied = 0;
+
+       while (offset > 0) {
+               if (offset >= sg_from->length) {
+                       if (sg_is_last(sg_from))
+                               return 0;
+
+                       offset -= sg_from->length;
+                       sg_from = sg_next(sg_from);
+                       continue;
+               }
+
+               copied = min(len, sg_from->length - offset);
+               sg_set_page(sg_to, sg_page(sg_from),
+                       copied, sg_from->offset + offset);
+
+               len -= copied;
+               offset = 0;
+
+               if (sg_is_last(sg_from) || !len)
+                       goto out;
+
+               sg_to = sg_next(sg_to);
+               to_nents--;
+               sg_from = sg_next(sg_from);
+       }
+
+       while (len > sg_from->length && to_nents--) {
+               len -= sg_from->length;
+               copied += sg_from->length;
+
+               sg_set_page(sg_to, sg_page(sg_from),
+                               sg_from->length, sg_from->offset);
+
+               if (sg_is_last(sg_from) || !len)
+                       goto out;
+
+               sg_from = sg_next(sg_from);
+               sg_to = sg_next(sg_to);
+       }
+
+       if (len && to_nents) {
+               sg_set_page(sg_to, sg_page(sg_from), len, sg_from->offset);
+               copied += len;
+       }
+out:
+       sg_mark_end(sg_to);
+       return copied;
+}
+
+/*
+ * Compares section of 'sg' starting from offset 'offset' and with length 'len'
+ * to linear buffer of length 'len' at address 'buffer'
+ * Returns 0 if equal and  -1 otherwice
+ */
+static int msb_sg_compare_to_buffer(struct scatterlist *sg,
+                                       size_t offset, u8 *buffer, size_t len)
+{
+       int retval = 0, cmplen;
+       struct sg_mapping_iter miter;
+
+       sg_miter_start(&miter, sg, sg_nents(sg),
+                                       SG_MITER_ATOMIC | SG_MITER_FROM_SG);
+
+       while (sg_miter_next(&miter) && len > 0) {
+               if (offset >= miter.length) {
+                       offset -= miter.length;
+                       continue;
+               }
+
+               cmplen = min(miter.length - offset, len);
+               retval = memcmp(miter.addr + offset, buffer, cmplen) ? -1 : 0;
+               if (retval)
+                       break;
+
+               buffer += cmplen;
+               len -= cmplen;
+               offset = 0;
+       }
+
+       if (!retval && len)
+               retval = -1;
+
+       sg_miter_stop(&miter);
+       return retval;
+}
+
+
+/* Get zone at which block with logical address 'lba' lives
+ * Flash is broken into zones.
+ * Each zone consists of 512 eraseblocks, out of which in first
+ * zone 494 are used and 496 are for all following zones.
+ * Therefore zone #0 hosts blocks 0-493, zone #1 blocks 494-988, etc...
+*/
+static int msb_get_zone_from_lba(int lba)
+{
+       if (lba < 494)
+               return 0;
+       return ((lba - 494) / 496) + 1;
+}
+
+/* Get zone of physical block. Trivial */
+static int msb_get_zone_from_pba(int pba)
+{
+       return pba / MS_BLOCKS_IN_ZONE;
+}
+
+/* Debug test to validate free block counts */
+static int msb_validate_used_block_bitmap(struct msb_data *msb)
+{
+       int total_free_blocks = 0;
+       int i;
+
+       if (!debug)
+               return 0;
+
+       for (i = 0; i < msb->zone_count; i++)
+               total_free_blocks += msb->free_block_count[i];
+
+       if (msb->block_count - bitmap_weight(msb->used_blocks_bitmap,
+                                       msb->block_count) == total_free_blocks)
+               return 0;
+
+       pr_err("BUG: free block counts don't match the bitmap");
+       msb->read_only = true;
+       return -EINVAL;
+}
+
+/* Mark physical block as used */
+static void msb_mark_block_used(struct msb_data *msb, int pba)
+{
+       int zone = msb_get_zone_from_pba(pba);
+
+       if (test_bit(pba, msb->used_blocks_bitmap)) {
+               pr_err(
+               "BUG: attempt to mark already used pba %d as used", pba);
+               msb->read_only = true;
+               return;
+       }
+
+       if (msb_validate_used_block_bitmap(msb))
+               return;
+
+       /* No races because all IO is single threaded */
+       __set_bit(pba, msb->used_blocks_bitmap);
+       msb->free_block_count[zone]--;
+}
+
+/* Mark physical block as free */
+static void msb_mark_block_unused(struct msb_data *msb, int pba)
+{
+       int zone = msb_get_zone_from_pba(pba);
+
+       if (!test_bit(pba, msb->used_blocks_bitmap)) {
+               pr_err("BUG: attempt to mark already unused pba %d as unused" , pba);
+               msb->read_only = true;
+               return;
+       }
+
+       if (msb_validate_used_block_bitmap(msb))
+               return;
+
+       /* No races because all IO is single threaded */
+       __clear_bit(pba, msb->used_blocks_bitmap);
+       msb->free_block_count[zone]++;
+}
+
+/* Invalidate current register window */
+static void msb_invalidate_reg_window(struct msb_data *msb)
+{
+       msb->reg_addr.w_offset = offsetof(struct ms_register, id);
+       msb->reg_addr.w_length = sizeof(struct ms_id_register);
+       msb->reg_addr.r_offset = offsetof(struct ms_register, id);
+       msb->reg_addr.r_length = sizeof(struct ms_id_register);
+       msb->addr_valid = false;
+}
+
+/* Start a state machine */
+static int msb_run_state_machine(struct msb_data *msb, int   (*state_func)
+               (struct memstick_dev *card, struct memstick_request **req))
+{
+       struct memstick_dev *card = msb->card;
+
+       WARN_ON(msb->state != -1);
+       msb->int_polling = false;
+       msb->state = 0;
+       msb->exit_error = 0;
+
+       memset(&card->current_mrq, 0, sizeof(card->current_mrq));
+
+       card->next_request = state_func;
+       memstick_new_req(card->host);
+       wait_for_completion(&card->mrq_complete);
+
+       WARN_ON(msb->state != -1);
+       return msb->exit_error;
+}
+
+/* State machines call that to exit */
+static int msb_exit_state_machine(struct msb_data *msb, int error)
+{
+       WARN_ON(msb->state == -1);
+
+       msb->state = -1;
+       msb->exit_error = error;
+       msb->card->next_request = h_msb_default_bad;
+
+       /* Invalidate reg window on errors */
+       if (error)
+               msb_invalidate_reg_window(msb);
+
+       complete(&msb->card->mrq_complete);
+       return -ENXIO;
+}
+
+/* read INT register */
+static int msb_read_int_reg(struct msb_data *msb, long timeout)
+{
+       struct memstick_request *mrq = &msb->card->current_mrq;
+
+       WARN_ON(msb->state == -1);
+
+       if (!msb->int_polling) {
+               msb->int_timeout = jiffies +
+                       msecs_to_jiffies(timeout == -1 ? 500 : timeout);
+               msb->int_polling = true;
+       } else if (time_after(jiffies, msb->int_timeout)) {
+               mrq->data[0] = MEMSTICK_INT_CMDNAK;
+               return 0;
+       }
+
+       if ((msb->caps & MEMSTICK_CAP_AUTO_GET_INT) &&
+                               mrq->need_card_int && !mrq->error) {
+               mrq->data[0] = mrq->int_reg;
+               mrq->need_card_int = false;
+               return 0;
+       } else {
+               memstick_init_req(mrq, MS_TPC_GET_INT, NULL, 1);
+               return 1;
+       }
+}
+
+/* Read a register */
+static int msb_read_regs(struct msb_data *msb, int offset, int len)
+{
+       struct memstick_request *req = &msb->card->current_mrq;
+
+       if (msb->reg_addr.r_offset != offset ||
+           msb->reg_addr.r_length != len || !msb->addr_valid) {
+
+               msb->reg_addr.r_offset = offset;
+               msb->reg_addr.r_length = len;
+               msb->addr_valid = true;
+
+               memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS,
+                       &msb->reg_addr, sizeof(msb->reg_addr));
+               return 0;
+       }
+
+       memstick_init_req(req, MS_TPC_READ_REG, NULL, len);
+       return 1;
+}
+
+/* Write a card register */
+static int msb_write_regs(struct msb_data *msb, int offset, int len, void *buf)
+{
+       struct memstick_request *req = &msb->card->current_mrq;
+
+       if (msb->reg_addr.w_offset != offset ||
+               msb->reg_addr.w_length != len  || !msb->addr_valid) {
+
+               msb->reg_addr.w_offset = offset;
+               msb->reg_addr.w_length = len;
+               msb->addr_valid = true;
+
+               memstick_init_req(req, MS_TPC_SET_RW_REG_ADRS,
+                       &msb->reg_addr, sizeof(msb->reg_addr));
+               return 0;
+       }
+
+       memstick_init_req(req, MS_TPC_WRITE_REG, buf, len);
+       return 1;
+}
+
+/* Handler for absence of IO */
+static int h_msb_default_bad(struct memstick_dev *card,
+                                               struct memstick_request **mrq)
+{
+       return -ENXIO;
+}
+
+/*
+ * This function is a handler for reads of one page from device.
+ * Writes output to msb->current_sg, takes sector address from msb->reg.param
+ * Can also be used to read extra data only. Set params accordintly.
+ */
+static int h_msb_read_page(struct memstick_dev *card,
+                                       struct memstick_request **out_mrq)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_request *mrq = *out_mrq = &card->current_mrq;
+       struct scatterlist sg[2];
+       u8 command, intreg;
+
+       if (mrq->error) {
+               dbg("read_page, unknown error");
+               return msb_exit_state_machine(msb, mrq->error);
+       }
+again:
+       switch (msb->state) {
+       case MSB_RP_SEND_BLOCK_ADDRESS:
+               /* msb_write_regs sometimes "fails" because it needs to update
+                       the reg window, and thus it returns request for that.
+                       Then we stay in this state and retry */
+               if (!msb_write_regs(msb,
+                       offsetof(struct ms_register, param),
+                       sizeof(struct ms_param_register),
+                       (unsigned char *)&msb->regs.param))
+                       return 0;
+
+               msb->state = MSB_RP_SEND_READ_COMMAND;
+               return 0;
+
+       case MSB_RP_SEND_READ_COMMAND:
+               command = MS_CMD_BLOCK_READ;
+               memstick_init_req(mrq, MS_TPC_SET_CMD, &command, 1);
+               msb->state = MSB_RP_SEND_INT_REQ;
+               return 0;
+
+       case MSB_RP_SEND_INT_REQ:
+               msb->state = MSB_RP_RECEIVE_INT_REQ_RESULT;
+               /* If dont actually need to send the int read request (only in
+                       serial mode), then just fall through */
+               if (msb_read_int_reg(msb, -1))
+                       return 0;
+               /* fallthrough */
+
+       case MSB_RP_RECEIVE_INT_REQ_RESULT:
+               intreg = mrq->data[0];
+               msb->regs.status.interrupt = intreg;
+
+               if (intreg & MEMSTICK_INT_CMDNAK)
+                       return msb_exit_state_machine(msb, -EIO);
+
+               if (!(intreg & MEMSTICK_INT_CED)) {
+                       msb->state = MSB_RP_SEND_INT_REQ;
+                       goto again;
+               }
+
+               msb->int_polling = false;
+               msb->state = (intreg & MEMSTICK_INT_ERR) ?
+                       MSB_RP_SEND_READ_STATUS_REG : MSB_RP_SEND_OOB_READ;
+               goto again;
+
+       case MSB_RP_SEND_READ_STATUS_REG:
+                /* read the status register to understand source of the INT_ERR */
+               if (!msb_read_regs(msb,
+                       offsetof(struct ms_register, status),
+                       sizeof(struct ms_status_register)))
+                       return 0;
+
+               msb->state = MSB_RP_RECEIVE_OOB_READ;
+               return 0;
+
+       case MSB_RP_RECIVE_STATUS_REG:
+               msb->regs.status = *(struct ms_status_register *)mrq->data;
+               msb->state = MSB_RP_SEND_OOB_READ;
+               /* fallthrough */
+
+       case MSB_RP_SEND_OOB_READ:
+               if (!msb_read_regs(msb,
+                       offsetof(struct ms_register, extra_data),
+                       sizeof(struct ms_extra_data_register)))
+                       return 0;
+
+               msb->state = MSB_RP_RECEIVE_OOB_READ;
+               return 0;
+
+       case MSB_RP_RECEIVE_OOB_READ:
+               msb->regs.extra_data =
+                       *(struct ms_extra_data_register *) mrq->data;
+               msb->state = MSB_RP_SEND_READ_DATA;
+               /* fallthrough */
+
+       case MSB_RP_SEND_READ_DATA:
+               /* Skip that state if we only read the oob */
+               if (msb->regs.param.cp == MEMSTICK_CP_EXTRA) {
+                       msb->state = MSB_RP_RECEIVE_READ_DATA;
+                       goto again;
+               }
+
+               sg_init_table(sg, ARRAY_SIZE(sg));
+               msb_sg_copy(msb->current_sg, sg, ARRAY_SIZE(sg),
+                       msb->current_sg_offset,
+                       msb->page_size);
+
+               memstick_init_req_sg(mrq, MS_TPC_READ_LONG_DATA, sg);
+               msb->state = MSB_RP_RECEIVE_READ_DATA;
+               return 0;
+
+       case MSB_RP_RECEIVE_READ_DATA:
+               if (!(msb->regs.status.interrupt & MEMSTICK_INT_ERR)) {
+                       msb->current_sg_offset += msb->page_size;
+                       return msb_exit_state_machine(msb, 0);
+               }
+
+               if (msb->regs.status.status1 & MEMSTICK_UNCORR_ERROR) {
+                       dbg("read_page: uncorrectable error");
+                       return msb_exit_state_machine(msb, -EBADMSG);
+               }
+
+               if (msb->regs.status.status1 & MEMSTICK_CORR_ERROR) {
+                       dbg("read_page: correctable error");
+                       msb->current_sg_offset += msb->page_size;
+                       return msb_exit_state_machine(msb, -EUCLEAN);
+               } else {
+                       dbg("read_page: INT error, but no status error bits");
+                       return msb_exit_state_machine(msb, -EIO);
+               }
+       }
+
+       BUG();
+}
+
+/*
+ * Handler of writes of exactly one block.
+ * Takes address from msb->regs.param.
+ * Writes same extra data to blocks, also taken
+ * from msb->regs.extra
+ * Returns -EBADMSG if write fails due to uncorrectable error, or -EIO if
+ * device refuses to take the command or something else
+ */
+static int h_msb_write_block(struct memstick_dev *card,
+                                       struct memstick_request **out_mrq)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_request *mrq = *out_mrq = &card->current_mrq;
+       struct scatterlist sg[2];
+       u8 intreg, command;
+
+       if (mrq->error)
+               return msb_exit_state_machine(msb, mrq->error);
+
+again:
+       switch (msb->state) {
+
+       /* HACK: Jmicon handling of TPCs between 8 and
+        *      sizeof(memstick_request.data) is broken due to hardware
+        *      bug in PIO mode that is used for these TPCs
+        *      Therefore split the write
+        */
+
+       case MSB_WB_SEND_WRITE_PARAMS:
+               if (!msb_write_regs(msb,
+                       offsetof(struct ms_register, param),
+                       sizeof(struct ms_param_register),
+                       &msb->regs.param))
+                       return 0;
+
+               msb->state = MSB_WB_SEND_WRITE_OOB;
+               return 0;
+
+       case MSB_WB_SEND_WRITE_OOB:
+               if (!msb_write_regs(msb,
+                       offsetof(struct ms_register, extra_data),
+                       sizeof(struct ms_extra_data_register),
+                       &msb->regs.extra_data))
+                       return 0;
+               msb->state = MSB_WB_SEND_WRITE_COMMAND;
+               return 0;
+
+
+       case MSB_WB_SEND_WRITE_COMMAND:
+               command = MS_CMD_BLOCK_WRITE;
+               memstick_init_req(mrq, MS_TPC_SET_CMD, &command, 1);
+               msb->state = MSB_WB_SEND_INT_REQ;
+               return 0;
+
+       case MSB_WB_SEND_INT_REQ:
+               msb->state = MSB_WB_RECEIVE_INT_REQ;
+               if (msb_read_int_reg(msb, -1))
+                       return 0;
+               /* fallthrough */
+
+       case MSB_WB_RECEIVE_INT_REQ:
+               intreg = mrq->data[0];
+               msb->regs.status.interrupt = intreg;
+
+               /* errors mean out of here, and fast... */
+               if (intreg & (MEMSTICK_INT_CMDNAK))
+                       return msb_exit_state_machine(msb, -EIO);
+
+               if (intreg & MEMSTICK_INT_ERR)
+                       return msb_exit_state_machine(msb, -EBADMSG);
+
+
+               /* for last page we need to poll CED */
+               if (msb->current_page == msb->pages_in_block) {
+                       if (intreg & MEMSTICK_INT_CED)
+                               return msb_exit_state_machine(msb, 0);
+                       msb->state = MSB_WB_SEND_INT_REQ;
+                       goto again;
+
+               }
+
+               /* for non-last page we need BREQ before writing next chunk */
+               if (!(intreg & MEMSTICK_INT_BREQ)) {
+                       msb->state = MSB_WB_SEND_INT_REQ;
+                       goto again;
+               }
+
+               msb->int_polling = false;
+               msb->state = MSB_WB_SEND_WRITE_DATA;
+               /* fallthrough */
+
+       case MSB_WB_SEND_WRITE_DATA:
+               sg_init_table(sg, ARRAY_SIZE(sg));
+
+               if (msb_sg_copy(msb->current_sg, sg, ARRAY_SIZE(sg),
+                       msb->current_sg_offset,
+                       msb->page_size) < msb->page_size)
+                       return msb_exit_state_machine(msb, -EIO);
+
+               memstick_init_req_sg(mrq, MS_TPC_WRITE_LONG_DATA, sg);
+               mrq->need_card_int = 1;
+               msb->state = MSB_WB_RECEIVE_WRITE_CONFIRMATION;
+               return 0;
+
+       case MSB_WB_RECEIVE_WRITE_CONFIRMATION:
+               msb->current_page++;
+               msb->current_sg_offset += msb->page_size;
+               msb->state = MSB_WB_SEND_INT_REQ;
+               goto again;
+       default:
+               BUG();
+       }
+
+       return 0;
+}
+
+/*
+ * This function is used to send simple IO requests to device that consist
+ * of register write + command
+ */
+static int h_msb_send_command(struct memstick_dev *card,
+                                       struct memstick_request **out_mrq)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_request *mrq = *out_mrq = &card->current_mrq;
+       u8 intreg;
+
+       if (mrq->error) {
+               dbg("send_command: unknown error");
+               return msb_exit_state_machine(msb, mrq->error);
+       }
+again:
+       switch (msb->state) {
+
+       /* HACK: see h_msb_write_block */
+       case MSB_SC_SEND_WRITE_PARAMS: /* write param register*/
+               if (!msb_write_regs(msb,
+                       offsetof(struct ms_register, param),
+                       sizeof(struct ms_param_register),
+                       &msb->regs.param))
+                       return 0;
+               msb->state = MSB_SC_SEND_WRITE_OOB;
+               return 0;
+
+       case MSB_SC_SEND_WRITE_OOB:
+               if (!msb->command_need_oob) {
+                       msb->state = MSB_SC_SEND_COMMAND;
+                       goto again;
+               }
+
+               if (!msb_write_regs(msb,
+                       offsetof(struct ms_register, extra_data),
+                       sizeof(struct ms_extra_data_register),
+                       &msb->regs.extra_data))
+                       return 0;
+
+               msb->state = MSB_SC_SEND_COMMAND;
+               return 0;
+
+       case MSB_SC_SEND_COMMAND:
+               memstick_init_req(mrq, MS_TPC_SET_CMD, &msb->command_value, 1);
+               msb->state = MSB_SC_SEND_INT_REQ;
+               return 0;
+
+       case MSB_SC_SEND_INT_REQ:
+               msb->state = MSB_SC_RECEIVE_INT_REQ;
+               if (msb_read_int_reg(msb, -1))
+                       return 0;
+               /* fallthrough */
+
+       case MSB_SC_RECEIVE_INT_REQ:
+               intreg = mrq->data[0];
+
+               if (intreg & MEMSTICK_INT_CMDNAK)
+                       return msb_exit_state_machine(msb, -EIO);
+               if (intreg & MEMSTICK_INT_ERR)
+                       return msb_exit_state_machine(msb, -EBADMSG);
+
+               if (!(intreg & MEMSTICK_INT_CED)) {
+                       msb->state = MSB_SC_SEND_INT_REQ;
+                       goto again;
+               }
+
+               return msb_exit_state_machine(msb, 0);
+       }
+
+       BUG();
+}
+
+/* Small handler for card reset */
+static int h_msb_reset(struct memstick_dev *card,
+                                       struct memstick_request **out_mrq)
+{
+       u8 command = MS_CMD_RESET;
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_request *mrq = *out_mrq = &card->current_mrq;
+
+       if (mrq->error)
+               return msb_exit_state_machine(msb, mrq->error);
+
+       switch (msb->state) {
+       case MSB_RS_SEND:
+               memstick_init_req(mrq, MS_TPC_SET_CMD, &command, 1);
+               mrq->need_card_int = 0;
+               msb->state = MSB_RS_CONFIRM;
+               return 0;
+       case MSB_RS_CONFIRM:
+               return msb_exit_state_machine(msb, 0);
+       }
+       BUG();
+}
+
+/* This handler is used to do serial->parallel switch */
+static int h_msb_parallel_switch(struct memstick_dev *card,
+                                       struct memstick_request **out_mrq)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_request *mrq = *out_mrq = &card->current_mrq;
+       struct memstick_host *host = card->host;
+
+       if (mrq->error) {
+               dbg("parallel_switch: error");
+               msb->regs.param.system &= ~MEMSTICK_SYS_PAM;
+               return msb_exit_state_machine(msb, mrq->error);
+       }
+
+       switch (msb->state) {
+       case MSB_PS_SEND_SWITCH_COMMAND:
+               /* Set the parallel interface on memstick side */
+               msb->regs.param.system |= MEMSTICK_SYS_PAM;
+
+               if (!msb_write_regs(msb,
+                       offsetof(struct ms_register, param),
+                       1,
+                       (unsigned char *)&msb->regs.param))
+                       return 0;
+
+               msb->state = MSB_PS_SWICH_HOST;
+               return 0;
+
+       case MSB_PS_SWICH_HOST:
+                /* Set parallel interface on our side + send a dummy request
+                       to see if card responds */
+               host->set_param(host, MEMSTICK_INTERFACE, MEMSTICK_PAR4);
+               memstick_init_req(mrq, MS_TPC_GET_INT, NULL, 1);
+               msb->state = MSB_PS_CONFIRM;
+               return 0;
+
+       case MSB_PS_CONFIRM:
+               return msb_exit_state_machine(msb, 0);
+       }
+
+       BUG();
+}
+
+static int msb_switch_to_parallel(struct msb_data *msb);
+
+/* Reset the card, to guard against hw errors beeing treated as bad blocks */
+static int msb_reset(struct msb_data *msb, bool full)
+{
+
+       bool was_parallel = msb->regs.param.system & MEMSTICK_SYS_PAM;
+       struct memstick_dev *card = msb->card;
+       struct memstick_host *host = card->host;
+       int error;
+
+       /* Reset the card */
+       msb->regs.param.system = MEMSTICK_SYS_BAMD;
+
+       if (full) {
+               error =  host->set_param(host,
+                                       MEMSTICK_POWER, MEMSTICK_POWER_OFF);
+               if (error)
+                       goto out_error;
+
+               msb_invalidate_reg_window(msb);
+
+               error = host->set_param(host,
+                                       MEMSTICK_POWER, MEMSTICK_POWER_ON);
+               if (error)
+                       goto out_error;
+
+               error = host->set_param(host,
+                                       MEMSTICK_INTERFACE, MEMSTICK_SERIAL);
+               if (error) {
+out_error:
+                       dbg("Failed to reset the host controller");
+                       msb->read_only = true;
+                       return -EFAULT;
+               }
+       }
+
+       error = msb_run_state_machine(msb, h_msb_reset);
+       if (error) {
+               dbg("Failed to reset the card");
+               msb->read_only = true;
+               return -ENODEV;
+       }
+
+       /* Set parallel mode */
+       if (was_parallel)
+               msb_switch_to_parallel(msb);
+       return 0;
+}
+
+/* Attempts to switch interface to parallel mode */
+static int msb_switch_to_parallel(struct msb_data *msb)
+{
+       int error;
+
+       error = msb_run_state_machine(msb, h_msb_parallel_switch);
+       if (error) {
+               pr_err("Switch to parallel failed");
+               msb->regs.param.system &= ~MEMSTICK_SYS_PAM;
+               msb_reset(msb, true);
+               return -EFAULT;
+       }
+
+       msb->caps |= MEMSTICK_CAP_AUTO_GET_INT;
+       return 0;
+}
+
+/* Changes overwrite flag on a page */
+static int msb_set_overwrite_flag(struct msb_data *msb,
+                                               u16 pba, u8 page, u8 flag)
+{
+       if (msb->read_only)
+               return -EROFS;
+
+       msb->regs.param.block_address = cpu_to_be16(pba);
+       msb->regs.param.page_address = page;
+       msb->regs.param.cp = MEMSTICK_CP_OVERWRITE;
+       msb->regs.extra_data.overwrite_flag = flag;
+       msb->command_value = MS_CMD_BLOCK_WRITE;
+       msb->command_need_oob = true;
+
+       dbg_verbose("changing overwrite flag to %02x for sector %d, page %d",
+                                                       flag, pba, page);
+       return msb_run_state_machine(msb, h_msb_send_command);
+}
+
+static int msb_mark_bad(struct msb_data *msb, int pba)
+{
+       pr_notice("marking pba %d as bad", pba);
+       msb_reset(msb, true);
+       return msb_set_overwrite_flag(
+                       msb, pba, 0, 0xFF & ~MEMSTICK_OVERWRITE_BKST);
+}
+
+static int msb_mark_page_bad(struct msb_data *msb, int pba, int page)
+{
+       dbg("marking page %d of pba %d as bad", page, pba);
+       msb_reset(msb, true);
+       return msb_set_overwrite_flag(msb,
+               pba, page, ~MEMSTICK_OVERWRITE_PGST0);
+}
+
+/* Erases one physical block */
+static int msb_erase_block(struct msb_data *msb, u16 pba)
+{
+       int error, try;
+       if (msb->read_only)
+               return -EROFS;
+
+       dbg_verbose("erasing pba %d", pba);
+
+       for (try = 1; try < 3; try++) {
+               msb->regs.param.block_address = cpu_to_be16(pba);
+               msb->regs.param.page_address = 0;
+               msb->regs.param.cp = MEMSTICK_CP_BLOCK;
+               msb->command_value = MS_CMD_BLOCK_ERASE;
+               msb->command_need_oob = false;
+
+
+               error = msb_run_state_machine(msb, h_msb_send_command);
+               if (!error || msb_reset(msb, true))
+                       break;
+       }
+
+       if (error) {
+               pr_err("erase failed, marking pba %d as bad", pba);
+               msb_mark_bad(msb, pba);
+       }
+
+       dbg_verbose("erase success, marking pba %d as unused", pba);
+       msb_mark_block_unused(msb, pba);
+       __set_bit(pba, msb->erased_blocks_bitmap);
+       return error;
+}
+
+/* Reads one page from device */
+static int msb_read_page(struct msb_data *msb,
+       u16 pba, u8 page, struct ms_extra_data_register *extra,
+                                       struct scatterlist *sg,  int offset)
+{
+       int try, error;
+
+       if (pba == MS_BLOCK_INVALID) {
+               unsigned long flags;
+               struct sg_mapping_iter miter;
+               size_t len = msb->page_size;
+
+               dbg_verbose("read unmapped sector. returning 0xFF");
+
+               local_irq_save(flags);
+               sg_miter_start(&miter, sg, sg_nents(sg),
+                               SG_MITER_ATOMIC | SG_MITER_TO_SG);
+
+               while (sg_miter_next(&miter) && len > 0) {
+
+                       int chunklen;
+
+                       if (offset && offset >= miter.length) {
+                               offset -= miter.length;
+                               continue;
+                       }
+
+                       chunklen = min(miter.length - offset, len);
+                       memset(miter.addr + offset, 0xFF, chunklen);
+                       len -= chunklen;
+                       offset = 0;
+               }
+
+               sg_miter_stop(&miter);
+               local_irq_restore(flags);
+
+               if (offset)
+                       return -EFAULT;
+
+               if (extra)
+                       memset(extra, 0xFF, sizeof(*extra));
+               return 0;
+       }
+
+       if (pba >= msb->block_count) {
+               pr_err("BUG: attempt to read beyond the end of the card at pba %d", pba);
+               return -EINVAL;
+       }
+
+       for (try = 1; try < 3; try++) {
+               msb->regs.param.block_address = cpu_to_be16(pba);
+               msb->regs.param.page_address = page;
+               msb->regs.param.cp = MEMSTICK_CP_PAGE;
+
+               msb->current_sg = sg;
+               msb->current_sg_offset = offset;
+               error = msb_run_state_machine(msb, h_msb_read_page);
+
+
+               if (error == -EUCLEAN) {
+                       pr_notice("correctable error on pba %d, page %d",
+                               pba, page);
+                       error = 0;
+               }
+
+               if (!error && extra)
+                       *extra = msb->regs.extra_data;
+
+               if (!error || msb_reset(msb, true))
+                       break;
+
+       }
+
+       /* Mark bad pages */
+       if (error == -EBADMSG) {
+               pr_err("uncorrectable error on read of pba %d, page %d",
+                       pba, page);
+
+               if (msb->regs.extra_data.overwrite_flag &
+                                       MEMSTICK_OVERWRITE_PGST0)
+                       msb_mark_page_bad(msb, pba, page);
+               return -EBADMSG;
+       }
+
+       if (error)
+               pr_err("read of pba %d, page %d failed with error %d",
+                       pba, page, error);
+       return error;
+}
+
+/* Reads oob of page only */
+static int msb_read_oob(struct msb_data *msb, u16 pba, u16 page,
+       struct ms_extra_data_register *extra)
+{
+       int error;
+
+       BUG_ON(!extra);
+       msb->regs.param.block_address = cpu_to_be16(pba);
+       msb->regs.param.page_address = page;
+       msb->regs.param.cp = MEMSTICK_CP_EXTRA;
+
+       if (pba > msb->block_count) {
+               pr_err("BUG: attempt to read beyond the end of card at pba %d", pba);
+               return -EINVAL;
+       }
+
+       error = msb_run_state_machine(msb, h_msb_read_page);
+       *extra = msb->regs.extra_data;
+
+       if (error == -EUCLEAN) {
+               pr_notice("correctable error on pba %d, page %d",
+                       pba, page);
+               return 0;
+       }
+
+       return error;
+}
+
+/* Reads a block and compares it with data contained in scatterlist orig_sg */
+static int msb_verify_block(struct msb_data *msb, u16 pba,
+                               struct scatterlist *orig_sg,  int offset)
+{
+       struct scatterlist sg;
+       int page = 0, error;
+
+       sg_init_one(&sg, msb->block_buffer, msb->block_size);
+
+       while (page < msb->pages_in_block) {
+
+               error = msb_read_page(msb, pba, page,
+                               NULL, &sg, page * msb->page_size);
+               if (error)
+                       return error;
+               page++;
+       }
+
+       if (msb_sg_compare_to_buffer(orig_sg, offset,
+                               msb->block_buffer, msb->block_size))
+               return -EIO;
+       return 0;
+}
+
+/* Writes exectly one block + oob */
+static int msb_write_block(struct msb_data *msb,
+                       u16 pba, u32 lba, struct scatterlist *sg, int offset)
+{
+       int error, current_try = 1;
+       BUG_ON(sg->length < msb->page_size);
+
+       if (msb->read_only)
+               return -EROFS;
+
+       if (pba == MS_BLOCK_INVALID) {
+               pr_err(
+                       "BUG: write: attempt to write MS_BLOCK_INVALID block");
+               return -EINVAL;
+       }
+
+       if (pba >= msb->block_count || lba >= msb->logical_block_count) {
+               pr_err(
+               "BUG: write: attempt to write beyond the end of device");
+               return -EINVAL;
+       }
+
+       if (msb_get_zone_from_lba(lba) != msb_get_zone_from_pba(pba)) {
+               pr_err("BUG: write: lba zone mismatch");
+               return -EINVAL;
+       }
+
+       if (pba == msb->boot_block_locations[0] ||
+               pba == msb->boot_block_locations[1]) {
+               pr_err("BUG: write: attempt to write to boot blocks!");
+               return -EINVAL;
+       }
+
+       while (1) {
+
+               if (msb->read_only)
+                       return -EROFS;
+
+               msb->regs.param.cp = MEMSTICK_CP_BLOCK;
+               msb->regs.param.page_address = 0;
+               msb->regs.param.block_address = cpu_to_be16(pba);
+
+               msb->regs.extra_data.management_flag = 0xFF;
+               msb->regs.extra_data.overwrite_flag = 0xF8;
+               msb->regs.extra_data.logical_address = cpu_to_be16(lba);
+
+               msb->current_sg = sg;
+               msb->current_sg_offset = offset;
+               msb->current_page = 0;
+
+               error = msb_run_state_machine(msb, h_msb_write_block);
+
+               /* Sector we just wrote to is assumed erased since its pba
+                       was erased. If it wasn't erased, write will succeed
+                       and will just clear the bits that were set in the block
+                       thus test that what we have written,
+                       matches what we expect.
+                       We do trust the blocks that we erased */
+               if (!error && (verify_writes ||
+                               !test_bit(pba, msb->erased_blocks_bitmap)))
+                       error = msb_verify_block(msb, pba, sg, offset);
+
+               if (!error)
+                       break;
+
+               if (current_try > 1 || msb_reset(msb, true))
+                       break;
+
+               pr_err("write failed, trying to erase the pba %d", pba);
+               error = msb_erase_block(msb, pba);
+               if (error)
+                       break;
+
+               current_try++;
+       }
+       return error;
+}
+
+/* Finds a free block for write replacement */
+static u16 msb_get_free_block(struct msb_data *msb, int zone)
+{
+       u16 pos;
+       int pba = zone * MS_BLOCKS_IN_ZONE;
+       int i;
+
+       get_random_bytes(&pos, sizeof(pos));
+
+       if (!msb->free_block_count[zone]) {
+               pr_err("NO free blocks in the zone %d, to use for a write, (media is WORN out) switching to RO mode", zone);
+               msb->read_only = true;
+               return MS_BLOCK_INVALID;
+       }
+
+       pos %= msb->free_block_count[zone];
+
+       dbg_verbose("have %d choices for a free block, selected randomally: %d",
+               msb->free_block_count[zone], pos);
+
+       pba = find_next_zero_bit(msb->used_blocks_bitmap,
+                                                       msb->block_count, pba);
+       for (i = 0; i < pos; ++i)
+               pba = find_next_zero_bit(msb->used_blocks_bitmap,
+                                               msb->block_count, pba + 1);
+
+       dbg_verbose("result of the free blocks scan: pba %d", pba);
+
+       if (pba == msb->block_count || (msb_get_zone_from_pba(pba)) != zone) {
+               pr_err("BUG: cant get a free block");
+               msb->read_only = true;
+               return MS_BLOCK_INVALID;
+       }
+
+       msb_mark_block_used(msb, pba);
+       return pba;
+}
+
+static int msb_update_block(struct msb_data *msb, u16 lba,
+       struct scatterlist *sg, int offset)
+{
+       u16 pba, new_pba;
+       int error, try;
+
+       pba = msb->lba_to_pba_table[lba];
+       dbg_verbose("start of a block update at lba  %d, pba %d", lba, pba);
+
+       if (pba != MS_BLOCK_INVALID) {
+               dbg_verbose("setting the update flag on the block");
+               msb_set_overwrite_flag(msb, pba, 0,
+                               0xFF & ~MEMSTICK_OVERWRITE_UDST);
+       }
+
+       for (try = 0; try < 3; try++) {
+               new_pba = msb_get_free_block(msb,
+                       msb_get_zone_from_lba(lba));
+
+               if (new_pba == MS_BLOCK_INVALID) {
+                       error = -EIO;
+                       goto out;
+               }
+
+               dbg_verbose("block update: writing updated block to the pba %d",
+                                                               new_pba);
+               error = msb_write_block(msb, new_pba, lba, sg, offset);
+               if (error == -EBADMSG) {
+                       msb_mark_bad(msb, new_pba);
+                       continue;
+               }
+
+               if (error)
+                       goto out;
+
+               dbg_verbose("block update: erasing the old block");
+               msb_erase_block(msb, pba);
+               msb->lba_to_pba_table[lba] = new_pba;
+               return 0;
+       }
+out:
+       if (error) {
+               pr_err("block update error after %d tries,  switching to r/o mode", try);
+               msb->read_only = true;
+       }
+       return error;
+}
+
+/* Converts endiannes in the boot block for easy use */
+static void msb_fix_boot_page_endianness(struct ms_boot_page *p)
+{
+       p->header.block_id = be16_to_cpu(p->header.block_id);
+       p->header.format_reserved = be16_to_cpu(p->header.format_reserved);
+       p->entry.disabled_block.start_addr
+               = be32_to_cpu(p->entry.disabled_block.start_addr);
+       p->entry.disabled_block.data_size
+               = be32_to_cpu(p->entry.disabled_block.data_size);
+       p->entry.cis_idi.start_addr
+               = be32_to_cpu(p->entry.cis_idi.start_addr);
+       p->entry.cis_idi.data_size
+               = be32_to_cpu(p->entry.cis_idi.data_size);
+       p->attr.block_size = be16_to_cpu(p->attr.block_size);
+       p->attr.number_of_blocks = be16_to_cpu(p->attr.number_of_blocks);
+       p->attr.number_of_effective_blocks
+               = be16_to_cpu(p->attr.number_of_effective_blocks);
+       p->attr.page_size = be16_to_cpu(p->attr.page_size);
+       p->attr.memory_manufacturer_code
+               = be16_to_cpu(p->attr.memory_manufacturer_code);
+       p->attr.memory_device_code = be16_to_cpu(p->attr.memory_device_code);
+       p->attr.implemented_capacity
+               = be16_to_cpu(p->attr.implemented_capacity);
+       p->attr.controller_number = be16_to_cpu(p->attr.controller_number);
+       p->attr.controller_function = be16_to_cpu(p->attr.controller_function);
+}
+
+static int msb_read_boot_blocks(struct msb_data *msb)
+{
+       int pba = 0;
+       struct scatterlist sg;
+       struct ms_extra_data_register extra;
+       struct ms_boot_page *page;
+
+       msb->boot_block_locations[0] = MS_BLOCK_INVALID;
+       msb->boot_block_locations[1] = MS_BLOCK_INVALID;
+       msb->boot_block_count = 0;
+
+       dbg_verbose("Start of a scan for the boot blocks");
+
+       if (!msb->boot_page) {
+               page = kmalloc(sizeof(struct ms_boot_page)*2, GFP_KERNEL);
+               if (!page)
+                       return -ENOMEM;
+
+               msb->boot_page = page;
+       } else
+               page = msb->boot_page;
+
+       msb->block_count = MS_BLOCK_MAX_BOOT_ADDR;
+
+       for (pba = 0; pba < MS_BLOCK_MAX_BOOT_ADDR; pba++) {
+
+               sg_init_one(&sg, page, sizeof(*page));
+               if (msb_read_page(msb, pba, 0, &extra, &sg, 0)) {
+                       dbg("boot scan: can't read pba %d", pba);
+                       continue;
+               }
+
+               if (extra.management_flag & MEMSTICK_MANAGEMENT_SYSFLG) {
+                       dbg("managment flag doesn't indicate boot block %d",
+                                                                       pba);
+                       continue;
+               }
+
+               if (be16_to_cpu(page->header.block_id) != MS_BLOCK_BOOT_ID) {
+                       dbg("the pba at %d doesn' contain boot block ID", pba);
+                       continue;
+               }
+
+               msb_fix_boot_page_endianness(page);
+               msb->boot_block_locations[msb->boot_block_count] = pba;
+
+               page++;
+               msb->boot_block_count++;
+
+               if (msb->boot_block_count == 2)
+                       break;
+       }
+
+       if (!msb->boot_block_count) {
+               pr_err("media doesn't contain master page, aborting");
+               return -EIO;
+       }
+
+       dbg_verbose("End of scan for boot blocks");
+       return 0;
+}
+
+static int msb_read_bad_block_table(struct msb_data *msb, int block_nr)
+{
+       struct ms_boot_page *boot_block;
+       struct scatterlist sg;
+       u16 *buffer = NULL;
+       int offset = 0;
+       int i, error = 0;
+       int data_size, data_offset, page, page_offset, size_to_read;
+       u16 pba;
+
+       BUG_ON(block_nr > 1);
+       boot_block = &msb->boot_page[block_nr];
+       pba = msb->boot_block_locations[block_nr];
+
+       if (msb->boot_block_locations[block_nr] == MS_BLOCK_INVALID)
+               return -EINVAL;
+
+       data_size = boot_block->entry.disabled_block.data_size;
+       data_offset = sizeof(struct ms_boot_page) +
+                       boot_block->entry.disabled_block.start_addr;
+       if (!data_size)
+               return 0;
+
+       page = data_offset / msb->page_size;
+       page_offset = data_offset % msb->page_size;
+       size_to_read =
+               DIV_ROUND_UP(data_size + page_offset, msb->page_size) *
+                       msb->page_size;
+
+       dbg("reading bad block of boot block at pba %d, offset %d len %d",
+               pba, data_offset, data_size);
+
+       buffer = kzalloc(size_to_read, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       /* Read the buffer */
+       sg_init_one(&sg, buffer, size_to_read);
+
+       while (offset < size_to_read) {
+               error = msb_read_page(msb, pba, page, NULL, &sg, offset);
+               if (error)
+                       goto out;
+
+               page++;
+               offset += msb->page_size;
+
+               if (page == msb->pages_in_block) {
+                       pr_err(
+                       "bad block table extends beyond the boot block");
+                       break;
+               }
+       }
+
+       /* Process the bad block table */
+       for (i = page_offset; i < data_size / sizeof(u16); i++) {
+
+               u16 bad_block = be16_to_cpu(buffer[i]);
+
+               if (bad_block >= msb->block_count) {
+                       dbg("bad block table contains invalid block %d",
+                                                               bad_block);
+                       continue;
+               }
+
+               if (test_bit(bad_block, msb->used_blocks_bitmap))  {
+                       dbg("duplicate bad block %d in the table",
+                               bad_block);
+                       continue;
+               }
+
+               dbg("block %d is marked as factory bad", bad_block);
+               msb_mark_block_used(msb, bad_block);
+       }
+out:
+       kfree(buffer);
+       return error;
+}
+
+static int msb_ftl_initialize(struct msb_data *msb)
+{
+       int i;
+
+       if (msb->ftl_initialized)
+               return 0;
+
+       msb->zone_count = msb->block_count / MS_BLOCKS_IN_ZONE;
+       msb->logical_block_count = msb->zone_count * 496 - 2;
+
+       msb->used_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
+       msb->erased_blocks_bitmap = kzalloc(msb->block_count / 8, GFP_KERNEL);
+       msb->lba_to_pba_table =
+               kmalloc(msb->logical_block_count * sizeof(u16), GFP_KERNEL);
+
+       if (!msb->used_blocks_bitmap || !msb->lba_to_pba_table ||
+                                               !msb->erased_blocks_bitmap) {
+               kfree(msb->used_blocks_bitmap);
+               kfree(msb->lba_to_pba_table);
+               kfree(msb->erased_blocks_bitmap);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < msb->zone_count; i++)
+               msb->free_block_count[i] = MS_BLOCKS_IN_ZONE;
+
+       memset(msb->lba_to_pba_table, MS_BLOCK_INVALID,
+                       msb->logical_block_count * sizeof(u16));
+
+       dbg("initial FTL tables created. Zone count = %d, Logical block count = %d",
+               msb->zone_count, msb->logical_block_count);
+
+       msb->ftl_initialized = true;
+       return 0;
+}
+
+static int msb_ftl_scan(struct msb_data *msb)
+{
+       u16 pba, lba, other_block;
+       u8 overwrite_flag, managment_flag, other_overwrite_flag;
+       int error;
+       struct ms_extra_data_register extra;
+       u8 *overwrite_flags = kzalloc(msb->block_count, GFP_KERNEL);
+
+       if (!overwrite_flags)
+               return -ENOMEM;
+
+       dbg("Start of media scanning");
+       for (pba = 0; pba < msb->block_count; pba++) {
+
+               if (pba == msb->boot_block_locations[0] ||
+                       pba == msb->boot_block_locations[1]) {
+                       dbg_verbose("pba %05d -> [boot block]", pba);
+                       msb_mark_block_used(msb, pba);
+                       continue;
+               }
+
+               if (test_bit(pba, msb->used_blocks_bitmap)) {
+                       dbg_verbose("pba %05d -> [factory bad]", pba);
+                       continue;
+               }
+
+               memset(&extra, 0, sizeof(extra));
+               error = msb_read_oob(msb, pba, 0, &extra);
+
+               /* can't trust the page if we can't read the oob */
+               if (error == -EBADMSG) {
+                       pr_notice(
+                       "oob of pba %d damaged, will try to erase it", pba);
+                       msb_mark_block_used(msb, pba);
+                       msb_erase_block(msb, pba);
+                       continue;
+               } else if (error) {
+                       pr_err("unknown error %d on read of oob of pba %d - aborting",
+                               error, pba);
+
+                       kfree(overwrite_flags);
+                       return error;
+               }
+
+               lba = be16_to_cpu(extra.logical_address);
+               managment_flag = extra.management_flag;
+               overwrite_flag = extra.overwrite_flag;
+               overwrite_flags[pba] = overwrite_flag;
+
+               /* Skip bad blocks */
+               if (!(overwrite_flag & MEMSTICK_OVERWRITE_BKST)) {
+                       dbg("pba %05d -> [BAD]", pba);
+                       msb_mark_block_used(msb, pba);
+                       continue;
+               }
+
+               /* Skip system/drm blocks */
+               if ((managment_flag & MEMSTICK_MANAGMENT_FLAG_NORMAL) !=
+                       MEMSTICK_MANAGMENT_FLAG_NORMAL) {
+                       dbg("pba %05d -> [reserved managment flag %02x]",
+                                                       pba, managment_flag);
+                       msb_mark_block_used(msb, pba);
+                       continue;
+               }
+
+               /* Erase temporary tables */
+               if (!(managment_flag & MEMSTICK_MANAGEMENT_ATFLG)) {
+                       dbg("pba %05d -> [temp table] - will erase", pba);
+
+                       msb_mark_block_used(msb, pba);
+                       msb_erase_block(msb, pba);
+                       continue;
+               }
+
+               if (lba == MS_BLOCK_INVALID) {
+                       dbg_verbose("pba %05d -> [free]", pba);
+                       continue;
+               }
+
+               msb_mark_block_used(msb, pba);
+
+               /* Block has LBA not according to zoning*/
+               if (msb_get_zone_from_lba(lba) != msb_get_zone_from_pba(pba)) {
+                       pr_notice("pba %05d -> [bad lba %05d] - will erase",
+                                                               pba, lba);
+                       msb_erase_block(msb, pba);
+                       continue;
+               }
+
+               /* No collisions - great */
+               if (msb->lba_to_pba_table[lba] == MS_BLOCK_INVALID) {
+                       dbg_verbose("pba %05d -> [lba %05d]", pba, lba);
+                       msb->lba_to_pba_table[lba] = pba;
+                       continue;
+               }
+
+               other_block = msb->lba_to_pba_table[lba];
+               other_overwrite_flag = overwrite_flags[other_block];
+
+               pr_notice("Collision between pba %d and pba %d",
+                       pba, other_block);
+
+               if (!(overwrite_flag & MEMSTICK_OVERWRITE_UDST)) {
+                       pr_notice("pba %d is marked as stable, use it", pba);
+                       msb_erase_block(msb, other_block);
+                       msb->lba_to_pba_table[lba] = pba;
+                       continue;
+               }
+
+               if (!(other_overwrite_flag & MEMSTICK_OVERWRITE_UDST)) {
+                       pr_notice("pba %d is marked as stable, use it",
+                                                               other_block);
+                       msb_erase_block(msb, pba);
+                       continue;
+               }
+
+               pr_notice("collision between blocks %d and %d, without stable flag set on both, erasing pba %d",
+                               pba, other_block, other_block);
+
+               msb_erase_block(msb, other_block);
+               msb->lba_to_pba_table[lba] = pba;
+       }
+
+       dbg("End of media scanning");
+       kfree(overwrite_flags);
+       return 0;
+}
+
+static void msb_cache_flush_timer(unsigned long data)
+{
+       struct msb_data *msb = (struct msb_data *)data;
+       msb->need_flush_cache = true;
+       queue_work(msb->io_queue, &msb->io_work);
+}
+
+
+static void msb_cache_discard(struct msb_data *msb)
+{
+       if (msb->cache_block_lba == MS_BLOCK_INVALID)
+               return;
+
+       del_timer_sync(&msb->cache_flush_timer);
+
+       dbg_verbose("Discarding the write cache");
+       msb->cache_block_lba = MS_BLOCK_INVALID;
+       bitmap_zero(&msb->valid_cache_bitmap, msb->pages_in_block);
+}
+
+static int msb_cache_init(struct msb_data *msb)
+{
+       setup_timer(&msb->cache_flush_timer, msb_cache_flush_timer,
+               (unsigned long)msb);
+
+       if (!msb->cache)
+               msb->cache = kzalloc(msb->block_size, GFP_KERNEL);
+       if (!msb->cache)
+               return -ENOMEM;
+
+       msb_cache_discard(msb);
+       return 0;
+}
+
+static int msb_cache_flush(struct msb_data *msb)
+{
+       struct scatterlist sg;
+       struct ms_extra_data_register extra;
+       int page, offset, error;
+       u16 pba, lba;
+
+       if (msb->read_only)
+               return -EROFS;
+
+       if (msb->cache_block_lba == MS_BLOCK_INVALID)
+               return 0;
+
+       lba = msb->cache_block_lba;
+       pba = msb->lba_to_pba_table[lba];
+
+       dbg_verbose("Flushing the write cache of pba %d (LBA %d)",
+                                               pba, msb->cache_block_lba);
+
+       sg_init_one(&sg, msb->cache , msb->block_size);
+
+       /* Read all missing pages in cache */
+       for (page = 0; page < msb->pages_in_block; page++) {
+
+               if (test_bit(page, &msb->valid_cache_bitmap))
+                       continue;
+
+               offset = page * msb->page_size;
+
+               dbg_verbose("reading non-present sector %d of cache block %d",
+                       page, lba);
+               error = msb_read_page(msb, pba, page, &extra, &sg, offset);
+
+               /* Bad pages are copied with 00 page status */
+               if (error == -EBADMSG) {
+                       pr_err("read error on sector %d, contents probably damaged", page);
+                       continue;
+               }
+
+               if (error)
+                       return error;
+
+               if ((extra.overwrite_flag & MEMSTICK_OV_PG_NORMAL) !=
+                                                       MEMSTICK_OV_PG_NORMAL) {
+                       dbg("page %d is marked as bad", page);
+                       continue;
+               }
+
+               set_bit(page, &msb->valid_cache_bitmap);
+       }
+
+       /* Write the cache now */
+       error = msb_update_block(msb, msb->cache_block_lba, &sg, 0);
+       pba = msb->lba_to_pba_table[msb->cache_block_lba];
+
+       /* Mark invalid pages */
+       if (!error) {
+               for (page = 0; page < msb->pages_in_block; page++) {
+
+                       if (test_bit(page, &msb->valid_cache_bitmap))
+                               continue;
+
+                       dbg("marking page %d as containing damaged data",
+                               page);
+                       msb_set_overwrite_flag(msb,
+                               pba , page, 0xFF & ~MEMSTICK_OV_PG_NORMAL);
+               }
+       }
+
+       msb_cache_discard(msb);
+       return error;
+}
+
+static int msb_cache_write(struct msb_data *msb, int lba,
+       int page, bool add_to_cache_only, struct scatterlist *sg, int offset)
+{
+       int error;
+       struct scatterlist sg_tmp[10];
+
+       if (msb->read_only)
+               return -EROFS;
+
+       if (msb->cache_block_lba == MS_BLOCK_INVALID ||
+                                               lba != msb->cache_block_lba)
+               if (add_to_cache_only)
+                       return 0;
+
+       /* If we need to write different block */
+       if (msb->cache_block_lba != MS_BLOCK_INVALID &&
+                                               lba != msb->cache_block_lba) {
+               dbg_verbose("first flush the cache");
+               error = msb_cache_flush(msb);
+               if (error)
+                       return error;
+       }
+
+       if (msb->cache_block_lba  == MS_BLOCK_INVALID) {
+               msb->cache_block_lba  = lba;
+               mod_timer(&msb->cache_flush_timer,
+                       jiffies + msecs_to_jiffies(cache_flush_timeout));
+       }
+
+       dbg_verbose("Write of LBA %d page %d to cache ", lba, page);
+
+       sg_init_table(sg_tmp, ARRAY_SIZE(sg_tmp));
+       msb_sg_copy(sg, sg_tmp, ARRAY_SIZE(sg_tmp), offset, msb->page_size);
+
+       sg_copy_to_buffer(sg_tmp, sg_nents(sg_tmp),
+               msb->cache + page * msb->page_size, msb->page_size);
+
+       set_bit(page, &msb->valid_cache_bitmap);
+       return 0;
+}
+
+static int msb_cache_read(struct msb_data *msb, int lba,
+                               int page, struct scatterlist *sg, int offset)
+{
+       int pba = msb->lba_to_pba_table[lba];
+       struct scatterlist sg_tmp[10];
+       int error = 0;
+
+       if (lba == msb->cache_block_lba &&
+                       test_bit(page, &msb->valid_cache_bitmap)) {
+
+               dbg_verbose("Read of LBA %d (pba %d) sector %d from cache",
+                                                       lba, pba, page);
+
+               sg_init_table(sg_tmp, ARRAY_SIZE(sg_tmp));
+               msb_sg_copy(sg, sg_tmp, ARRAY_SIZE(sg_tmp),
+                       offset, msb->page_size);
+               sg_copy_from_buffer(sg_tmp, sg_nents(sg_tmp),
+                       msb->cache + msb->page_size * page,
+                                                       msb->page_size);
+       } else {
+               dbg_verbose("Read of LBA %d (pba %d) sector %d from device",
+                                                       lba, pba, page);
+
+               error = msb_read_page(msb, pba, page, NULL, sg, offset);
+               if (error)
+                       return error;
+
+               msb_cache_write(msb, lba, page, true, sg, offset);
+       }
+       return error;
+}
+
+/* Emulated geometry table
+ * This table content isn't that importaint,
+ * One could put here different values, providing that they still
+ * cover whole disk.
+ * 64 MB entry is what windows reports for my 64M memstick */
+
+static const struct chs_entry chs_table[] = {
+/*        size sectors cylynders  heads */
+       { 4,    16,    247,       2  },
+       { 8,    16,    495,       2  },
+       { 16,   16,    495,       4  },
+       { 32,   16,    991,       4  },
+       { 64,   16,    991,       8  },
+       {128,   16,    991,       16 },
+       { 0 }
+};
+
+/* Load information about the card */
+static int msb_init_card(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_host *host = card->host;
+       struct ms_boot_page *boot_block;
+       int error = 0, i, raw_size_in_megs;
+
+       msb->caps = 0;
+
+       if (card->id.class >= MEMSTICK_CLASS_ROM &&
+                               card->id.class <= MEMSTICK_CLASS_ROM)
+               msb->read_only = true;
+
+       msb->state = -1;
+       error = msb_reset(msb, false);
+       if (error)
+               return error;
+
+       /* Due to a bug in Jmicron driver written by Alex Dubov,
+        its serial mode barely works,
+        so we switch to parallel mode right away */
+       if (host->caps & MEMSTICK_CAP_PAR4)
+               msb_switch_to_parallel(msb);
+
+       msb->page_size = sizeof(struct ms_boot_page);
+
+       /* Read the boot page */
+       error = msb_read_boot_blocks(msb);
+       if (error)
+               return -EIO;
+
+       boot_block = &msb->boot_page[0];
+
+       /* Save intersting attributes from boot page */
+       msb->block_count = boot_block->attr.number_of_blocks;
+       msb->page_size = boot_block->attr.page_size;
+
+       msb->pages_in_block = boot_block->attr.block_size * 2;
+       msb->block_size = msb->page_size * msb->pages_in_block;
+
+       if (msb->page_size > PAGE_SIZE) {
+               /* this isn't supported by linux at all, anyway*/
+               dbg("device page %d size isn't supported", msb->page_size);
+               return -EINVAL;
+       }
+
+       msb->block_buffer = kzalloc(msb->block_size, GFP_KERNEL);
+       if (!msb->block_buffer)
+               return -ENOMEM;
+
+       raw_size_in_megs = (msb->block_size * msb->block_count) >> 20;
+
+       for (i = 0; chs_table[i].size; i++) {
+
+               if (chs_table[i].size != raw_size_in_megs)
+                       continue;
+
+               msb->geometry.cylinders = chs_table[i].cyl;
+               msb->geometry.heads = chs_table[i].head;
+               msb->geometry.sectors = chs_table[i].sec;
+               break;
+       }
+
+       if (boot_block->attr.transfer_supporting == 1)
+               msb->caps |= MEMSTICK_CAP_PAR4;
+
+       if (boot_block->attr.device_type & 0x03)
+               msb->read_only = true;
+
+       dbg("Total block count = %d", msb->block_count);
+       dbg("Each block consists of %d pages", msb->pages_in_block);
+       dbg("Page size = %d bytes", msb->page_size);
+       dbg("Parallel mode supported: %d", !!(msb->caps & MEMSTICK_CAP_PAR4));
+       dbg("Read only: %d", msb->read_only);
+
+#if 0
+       /* Now we can switch the interface */
+       if (host->caps & msb->caps & MEMSTICK_CAP_PAR4)
+               msb_switch_to_parallel(msb);
+#endif
+
+       error = msb_cache_init(msb);
+       if (error)
+               return error;
+
+       error = msb_ftl_initialize(msb);
+       if (error)
+               return error;
+
+
+       /* Read the bad block table */
+       error = msb_read_bad_block_table(msb, 0);
+
+       if (error && error != -ENOMEM) {
+               dbg("failed to read bad block table from primary boot block, trying from backup");
+               error = msb_read_bad_block_table(msb, 1);
+       }
+
+       if (error)
+               return error;
+
+       /* *drum roll* Scan the media */
+       error = msb_ftl_scan(msb);
+       if (error) {
+               pr_err("Scan of media failed");
+               return error;
+       }
+
+       return 0;
+
+}
+
+static int msb_do_write_request(struct msb_data *msb, int lba,
+       int page, struct scatterlist *sg, size_t len, int *sucessfuly_written)
+{
+       int error = 0;
+       off_t offset = 0;
+       *sucessfuly_written = 0;
+
+       while (offset < len) {
+               if (page == 0 && len - offset >= msb->block_size) {
+
+                       if (msb->cache_block_lba == lba)
+                               msb_cache_discard(msb);
+
+                       dbg_verbose("Writing whole lba %d", lba);
+                       error = msb_update_block(msb, lba, sg, offset);
+                       if (error)
+                               return error;
+
+                       offset += msb->block_size;
+                       *sucessfuly_written += msb->block_size;
+                       lba++;
+                       continue;
+               }
+
+               error = msb_cache_write(msb, lba, page, false, sg, offset);
+               if (error)
+                       return error;
+
+               offset += msb->page_size;
+               *sucessfuly_written += msb->page_size;
+
+               page++;
+               if (page == msb->pages_in_block) {
+                       page = 0;
+                       lba++;
+               }
+       }
+       return 0;
+}
+
+static int msb_do_read_request(struct msb_data *msb, int lba,
+               int page, struct scatterlist *sg, int len, int *sucessfuly_read)
+{
+       int error = 0;
+       int offset = 0;
+       *sucessfuly_read = 0;
+
+       while (offset < len) {
+
+               error = msb_cache_read(msb, lba, page, sg, offset);
+               if (error)
+                       return error;
+
+               offset += msb->page_size;
+               *sucessfuly_read += msb->page_size;
+
+               page++;
+               if (page == msb->pages_in_block) {
+                       page = 0;
+                       lba++;
+               }
+       }
+       return 0;
+}
+
+static void msb_io_work(struct work_struct *work)
+{
+       struct msb_data *msb = container_of(work, struct msb_data, io_work);
+       int page, error, len;
+       sector_t lba;
+       unsigned long flags;
+       struct scatterlist *sg = msb->prealloc_sg;
+
+       dbg_verbose("IO: work started");
+
+       while (1) {
+               spin_lock_irqsave(&msb->q_lock, flags);
+
+               if (msb->need_flush_cache) {
+                       msb->need_flush_cache = false;
+                       spin_unlock_irqrestore(&msb->q_lock, flags);
+                       msb_cache_flush(msb);
+                       continue;
+               }
+
+               if (!msb->req) {
+                       msb->req = blk_fetch_request(msb->queue);
+                       if (!msb->req) {
+                               dbg_verbose("IO: no more requests exiting");
+                               spin_unlock_irqrestore(&msb->q_lock, flags);
+                               return;
+                       }
+               }
+
+               spin_unlock_irqrestore(&msb->q_lock, flags);
+
+               /* If card was removed meanwhile */
+               if (!msb->req)
+                       return;
+
+               /* process the request */
+               dbg_verbose("IO: processing new request");
+               blk_rq_map_sg(msb->queue, msb->req, sg);
+
+               lba = blk_rq_pos(msb->req);
+
+               sector_div(lba, msb->page_size / 512);
+               page = do_div(lba, msb->pages_in_block);
+
+               if (rq_data_dir(msb->req) == READ)
+                       error = msb_do_read_request(msb, lba, page, sg,
+                               blk_rq_bytes(msb->req), &len);
+               else
+                       error = msb_do_write_request(msb, lba, page, sg,
+                               blk_rq_bytes(msb->req), &len);
+
+               spin_lock_irqsave(&msb->q_lock, flags);
+
+               if (len)
+                       if (!__blk_end_request(msb->req, 0, len))
+                               msb->req = NULL;
+
+               if (error && msb->req) {
+                       dbg_verbose("IO: ending one sector of the request with error");
+                       if (!__blk_end_request(msb->req, error, msb->page_size))
+                               msb->req = NULL;
+               }
+
+               if (msb->req)
+                       dbg_verbose("IO: request still pending");
+
+               spin_unlock_irqrestore(&msb->q_lock, flags);
+       }
+}
+
+static DEFINE_IDR(msb_disk_idr); /*set of used disk numbers */
+static DEFINE_MUTEX(msb_disk_lock); /* protects against races in open/release */
+
+static int msb_bd_open(struct block_device *bdev, fmode_t mode)
+{
+       struct gendisk *disk = bdev->bd_disk;
+       struct msb_data *msb = disk->private_data;
+
+       dbg_verbose("block device open");
+
+       mutex_lock(&msb_disk_lock);
+
+       if (msb && msb->card)
+               msb->usage_count++;
+
+       mutex_unlock(&msb_disk_lock);
+       return 0;
+}
+
+static void msb_data_clear(struct msb_data *msb)
+{
+       kfree(msb->boot_page);
+       kfree(msb->used_blocks_bitmap);
+       kfree(msb->lba_to_pba_table);
+       kfree(msb->cache);
+       msb->card = NULL;
+}
+
+static int msb_disk_release(struct gendisk *disk)
+{
+       struct msb_data *msb = disk->private_data;
+
+       dbg_verbose("block device release");
+       mutex_lock(&msb_disk_lock);
+
+       if (msb) {
+               if (msb->usage_count)
+                       msb->usage_count--;
+
+               if (!msb->usage_count) {
+                       disk->private_data = NULL;
+                       idr_remove(&msb_disk_idr, msb->disk_id);
+                       put_disk(disk);
+                       kfree(msb);
+               }
+       }
+       mutex_unlock(&msb_disk_lock);
+       return 0;
+}
+
+static void msb_bd_release(struct gendisk *disk, fmode_t mode)
+{
+       msb_disk_release(disk);
+}
+
+static int msb_bd_getgeo(struct block_device *bdev,
+                                struct hd_geometry *geo)
+{
+       struct msb_data *msb = bdev->bd_disk->private_data;
+       *geo = msb->geometry;
+       return 0;
+}
+
+static int msb_prepare_req(struct request_queue *q, struct request *req)
+{
+       if (req->cmd_type != REQ_TYPE_FS &&
+                               req->cmd_type != REQ_TYPE_BLOCK_PC) {
+               blk_dump_rq_flags(req, "MS unsupported request");
+               return BLKPREP_KILL;
+       }
+       req->cmd_flags |= REQ_DONTPREP;
+       return BLKPREP_OK;
+}
+
+static void msb_submit_req(struct request_queue *q)
+{
+       struct memstick_dev *card = q->queuedata;
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct request *req = NULL;
+
+       dbg_verbose("Submit request");
+
+       if (msb->card_dead) {
+               dbg("Refusing requests on removed card");
+
+               WARN_ON(!msb->io_queue_stopped);
+
+               while ((req = blk_fetch_request(q)) != NULL)
+                       __blk_end_request_all(req, -ENODEV);
+               return;
+       }
+
+       if (msb->req)
+               return;
+
+       if (!msb->io_queue_stopped)
+               queue_work(msb->io_queue, &msb->io_work);
+}
+
+static int msb_check_card(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       return (msb->card_dead == 0);
+}
+
+static void msb_stop(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       unsigned long flags;
+
+       dbg("Stopping all msblock IO");
+
+       spin_lock_irqsave(&msb->q_lock, flags);
+       blk_stop_queue(msb->queue);
+       msb->io_queue_stopped = true;
+       spin_unlock_irqrestore(&msb->q_lock, flags);
+
+       del_timer_sync(&msb->cache_flush_timer);
+       flush_workqueue(msb->io_queue);
+
+       if (msb->req) {
+               spin_lock_irqsave(&msb->q_lock, flags);
+               blk_requeue_request(msb->queue, msb->req);
+               msb->req = NULL;
+               spin_unlock_irqrestore(&msb->q_lock, flags);
+       }
+
+}
+
+static void msb_start(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       unsigned long flags;
+
+       dbg("Resuming IO from msblock");
+
+       msb_invalidate_reg_window(msb);
+
+       spin_lock_irqsave(&msb->q_lock, flags);
+       if (!msb->io_queue_stopped || msb->card_dead) {
+               spin_unlock_irqrestore(&msb->q_lock, flags);
+               return;
+       }
+       spin_unlock_irqrestore(&msb->q_lock, flags);
+
+       /* Kick cache flush anyway, its harmless */
+       msb->need_flush_cache = true;
+       msb->io_queue_stopped = false;
+
+       spin_lock_irqsave(&msb->q_lock, flags);
+       blk_start_queue(msb->queue);
+       spin_unlock_irqrestore(&msb->q_lock, flags);
+
+       queue_work(msb->io_queue, &msb->io_work);
+
+}
+
+static const struct block_device_operations msb_bdops = {
+       .open    = msb_bd_open,
+       .release = msb_bd_release,
+       .getgeo  = msb_bd_getgeo,
+       .owner   = THIS_MODULE
+};
+
+/* Registers the block device */
+static int msb_init_disk(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct memstick_host *host = card->host;
+       int rc;
+       u64 limit = BLK_BOUNCE_HIGH;
+       unsigned long capacity;
+
+       if (host->dev.dma_mask && *(host->dev.dma_mask))
+               limit = *(host->dev.dma_mask);
+
+       mutex_lock(&msb_disk_lock);
+       msb->disk_id = idr_alloc(&msb_disk_idr, card, 0, 256, GFP_KERNEL);
+       mutex_unlock(&msb_disk_lock);
+
+       if (msb->disk_id  < 0)
+               return msb->disk_id;
+
+       msb->disk = alloc_disk(0);
+       if (!msb->disk) {
+               rc = -ENOMEM;
+               goto out_release_id;
+       }
+
+       msb->queue = blk_init_queue(msb_submit_req, &msb->q_lock);
+       if (!msb->queue) {
+               rc = -ENOMEM;
+               goto out_put_disk;
+       }
+
+       msb->queue->queuedata = card;
+       blk_queue_prep_rq(msb->queue, msb_prepare_req);
+
+       blk_queue_bounce_limit(msb->queue, limit);
+       blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES);
+       blk_queue_max_segments(msb->queue, MS_BLOCK_MAX_SEGS);
+       blk_queue_max_segment_size(msb->queue,
+                                  MS_BLOCK_MAX_PAGES * msb->page_size);
+       blk_queue_logical_block_size(msb->queue, msb->page_size);
+
+       sprintf(msb->disk->disk_name, "msblk%d", msb->disk_id);
+       msb->disk->fops = &msb_bdops;
+       msb->disk->private_data = msb;
+       msb->disk->queue = msb->queue;
+       msb->disk->driverfs_dev = &card->dev;
+       msb->disk->flags |= GENHD_FL_EXT_DEVT;
+
+       capacity = msb->pages_in_block * msb->logical_block_count;
+       capacity *= (msb->page_size / 512);
+       set_capacity(msb->disk, capacity);
+       dbg("Set total disk size to %lu sectors", capacity);
+
+       msb->usage_count = 1;
+       msb->io_queue = alloc_ordered_workqueue("ms_block", WQ_MEM_RECLAIM);
+       INIT_WORK(&msb->io_work, msb_io_work);
+       sg_init_table(msb->prealloc_sg, MS_BLOCK_MAX_SEGS+1);
+
+       if (msb->read_only)
+               set_disk_ro(msb->disk, 1);
+
+       msb_start(card);
+       add_disk(msb->disk);
+       dbg("Disk added");
+       return 0;
+
+out_put_disk:
+       put_disk(msb->disk);
+out_release_id:
+       mutex_lock(&msb_disk_lock);
+       idr_remove(&msb_disk_idr, msb->disk_id);
+       mutex_unlock(&msb_disk_lock);
+       return rc;
+}
+
+static int msb_probe(struct memstick_dev *card)
+{
+       struct msb_data *msb;
+       int rc = 0;
+
+       msb = kzalloc(sizeof(struct msb_data), GFP_KERNEL);
+       if (!msb)
+               return -ENOMEM;
+       memstick_set_drvdata(card, msb);
+       msb->card = card;
+       spin_lock_init(&msb->q_lock);
+
+       rc = msb_init_card(card);
+       if (rc)
+               goto out_free;
+
+       rc = msb_init_disk(card);
+       if (!rc) {
+               card->check = msb_check_card;
+               card->stop = msb_stop;
+               card->start = msb_start;
+               return 0;
+       }
+out_free:
+       memstick_set_drvdata(card, NULL);
+       msb_data_clear(msb);
+       kfree(msb);
+       return rc;
+}
+
+static void msb_remove(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       unsigned long flags;
+
+       if (!msb->io_queue_stopped)
+               msb_stop(card);
+
+       dbg("Removing the disk device");
+
+       /* Take care of unhandled + new requests from now on */
+       spin_lock_irqsave(&msb->q_lock, flags);
+       msb->card_dead = true;
+       blk_start_queue(msb->queue);
+       spin_unlock_irqrestore(&msb->q_lock, flags);
+
+       /* Remove the disk */
+       del_gendisk(msb->disk);
+       blk_cleanup_queue(msb->queue);
+       msb->queue = NULL;
+
+       mutex_lock(&msb_disk_lock);
+       msb_data_clear(msb);
+       mutex_unlock(&msb_disk_lock);
+
+       msb_disk_release(msb->disk);
+       memstick_set_drvdata(card, NULL);
+}
+
+#ifdef CONFIG_PM
+
+static int msb_suspend(struct memstick_dev *card, pm_message_t state)
+{
+       msb_stop(card);
+       return 0;
+}
+
+static int msb_resume(struct memstick_dev *card)
+{
+       struct msb_data *msb = memstick_get_drvdata(card);
+       struct msb_data *new_msb = NULL;
+       bool card_dead = true;
+
+#ifndef CONFIG_MEMSTICK_UNSAFE_RESUME
+       msb->card_dead = true;
+       return 0;
+#endif
+       mutex_lock(&card->host->lock);
+
+       new_msb = kzalloc(sizeof(struct msb_data), GFP_KERNEL);
+       if (!new_msb)
+               goto out;
+
+       new_msb->card = card;
+       memstick_set_drvdata(card, new_msb);
+       spin_lock_init(&new_msb->q_lock);
+       sg_init_table(msb->prealloc_sg, MS_BLOCK_MAX_SEGS+1);
+
+       if (msb_init_card(card))
+               goto out;
+
+       if (msb->block_size != new_msb->block_size)
+               goto out;
+
+       if (memcmp(msb->boot_page, new_msb->boot_page,
+                                       sizeof(struct ms_boot_page)))
+               goto out;
+
+       if (msb->logical_block_count != new_msb->logical_block_count ||
+               memcmp(msb->lba_to_pba_table, new_msb->lba_to_pba_table,
+                                               msb->logical_block_count))
+               goto out;
+
+       if (msb->block_count != new_msb->block_count ||
+               memcmp(msb->used_blocks_bitmap, new_msb->used_blocks_bitmap,
+                                                       msb->block_count / 8))
+               goto out;
+
+       card_dead = false;
+out:
+       if (card_dead)
+               dbg("Card was removed/replaced during suspend");
+
+       msb->card_dead = card_dead;
+       memstick_set_drvdata(card, msb);
+
+       if (new_msb) {
+               msb_data_clear(new_msb);
+               kfree(new_msb);
+       }
+
+       msb_start(card);
+       mutex_unlock(&card->host->lock);
+       return 0;
+}
+#else
+
+#define msb_suspend NULL
+#define msb_resume NULL
+
+#endif /* CONFIG_PM */
+
+static struct memstick_device_id msb_id_tbl[] = {
+       {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+        MEMSTICK_CLASS_FLASH},
+
+       {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+        MEMSTICK_CLASS_ROM},
+
+       {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+        MEMSTICK_CLASS_RO},
+
+       {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_LEGACY, MEMSTICK_CATEGORY_STORAGE,
+        MEMSTICK_CLASS_WP},
+
+       {MEMSTICK_MATCH_ALL, MEMSTICK_TYPE_DUO, MEMSTICK_CATEGORY_STORAGE_DUO,
+        MEMSTICK_CLASS_DUO},
+       {}
+};
+MODULE_DEVICE_TABLE(memstick, msb_id_tbl);
+
+
+static struct memstick_driver msb_driver = {
+       .driver = {
+               .name  = DRIVER_NAME,
+               .owner = THIS_MODULE
+       },
+       .id_table = msb_id_tbl,
+       .probe    = msb_probe,
+       .remove   = msb_remove,
+       .suspend  = msb_suspend,
+       .resume   = msb_resume
+};
+
+static int major;
+
+static int __init msb_init(void)
+{
+       int rc = register_blkdev(0, DRIVER_NAME);
+
+       if (rc < 0) {
+               pr_err("failed to register major (error %d)\n", rc);
+               return rc;
+       }
+
+       major = rc;
+       rc = memstick_register_driver(&msb_driver);
+       if (rc) {
+               unregister_blkdev(major, DRIVER_NAME);
+               pr_err("failed to register memstick driver (error %d)\n", rc);
+       }
+
+       return rc;
+}
+
+static void __exit msb_exit(void)
+{
+       memstick_unregister_driver(&msb_driver);
+       unregister_blkdev(major, DRIVER_NAME);
+       idr_destroy(&msb_disk_idr);
+}
+
+module_init(msb_init);
+module_exit(msb_exit);
+
+module_param(cache_flush_timeout, int, S_IRUGO);
+MODULE_PARM_DESC(cache_flush_timeout,
+                               "Cache flush timeout in msec (1000 default)");
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level (0-2)");
+
+module_param(verify_writes, bool, S_IRUGO);
+MODULE_PARM_DESC(verify_writes, "Read back and check all data that is written");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Maxim Levitsky");
+MODULE_DESCRIPTION("Sony MemoryStick block device driver");
diff --git a/drivers/memstick/core/ms_block.h b/drivers/memstick/core/ms_block.h
new file mode 100644 (file)
index 0000000..96e6375
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ *  ms_block.h - Sony MemoryStick (legacy) storage support
+
+ *  Copyright (C) 2013 Maxim Levitsky <maximlevitsky@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.
+ *
+ * Minor portions of the driver are copied from mspro_block.c which is
+ * Copyright (C) 2007 Alex Dubov <oakad@yahoo.com>
+ *
+ * Also ms structures were copied from old broken driver by same author
+ * These probably come from MS spec
+ *
+ */
+
+#ifndef MS_BLOCK_NEW_H
+#define MS_BLOCK_NEW_H
+
+#define MS_BLOCK_MAX_SEGS      32
+#define MS_BLOCK_MAX_PAGES     ((2 << 16) - 1)
+
+#define MS_BLOCK_MAX_BOOT_ADDR 0x000c
+#define MS_BLOCK_BOOT_ID       0x0001
+#define MS_BLOCK_INVALID       0xffff
+#define MS_MAX_ZONES           16
+#define MS_BLOCKS_IN_ZONE      512
+
+#define MS_BLOCK_MAP_LINE_SZ   16
+#define MS_BLOCK_PART_SHIFT    3
+
+
+#define MEMSTICK_UNCORR_ERROR (MEMSTICK_STATUS1_UCFG | \
+               MEMSTICK_STATUS1_UCEX | MEMSTICK_STATUS1_UCDT)
+
+#define MEMSTICK_CORR_ERROR (MEMSTICK_STATUS1_FGER | MEMSTICK_STATUS1_EXER | \
+       MEMSTICK_STATUS1_DTER)
+
+#define MEMSTICK_INT_ERROR (MEMSTICK_INT_CMDNAK | MEMSTICK_INT_ERR)
+
+#define MEMSTICK_OVERWRITE_FLAG_NORMAL \
+       (MEMSTICK_OVERWRITE_PGST1 | \
+       MEMSTICK_OVERWRITE_PGST0  | \
+       MEMSTICK_OVERWRITE_BKST)
+
+#define MEMSTICK_OV_PG_NORMAL \
+       (MEMSTICK_OVERWRITE_PGST1 | MEMSTICK_OVERWRITE_PGST0)
+
+#define MEMSTICK_MANAGMENT_FLAG_NORMAL \
+       (MEMSTICK_MANAGEMENT_SYSFLG |  \
+       MEMSTICK_MANAGEMENT_SCMS1   |  \
+       MEMSTICK_MANAGEMENT_SCMS0)     \
+
+struct ms_boot_header {
+       unsigned short block_id;
+       unsigned short format_reserved;
+       unsigned char  reserved0[184];
+       unsigned char  data_entry;
+       unsigned char  reserved1[179];
+} __packed;
+
+
+struct ms_system_item {
+       unsigned int  start_addr;
+       unsigned int  data_size;
+       unsigned char data_type_id;
+       unsigned char reserved[3];
+} __packed;
+
+struct ms_system_entry {
+       struct ms_system_item disabled_block;
+       struct ms_system_item cis_idi;
+       unsigned char         reserved[24];
+} __packed;
+
+struct ms_boot_attr_info {
+       unsigned char      memorystick_class;
+       unsigned char      format_unique_value1;
+       unsigned short     block_size;
+       unsigned short     number_of_blocks;
+       unsigned short     number_of_effective_blocks;
+       unsigned short     page_size;
+       unsigned char      extra_data_size;
+       unsigned char      format_unique_value2;
+       unsigned char      assembly_time[8];
+       unsigned char      format_unique_value3;
+       unsigned char      serial_number[3];
+       unsigned char      assembly_manufacturer_code;
+       unsigned char      assembly_model_code[3];
+       unsigned short     memory_manufacturer_code;
+       unsigned short     memory_device_code;
+       unsigned short     implemented_capacity;
+       unsigned char      format_unique_value4[2];
+       unsigned char      vcc;
+       unsigned char      vpp;
+       unsigned short     controller_number;
+       unsigned short     controller_function;
+       unsigned char      reserved0[9];
+       unsigned char      transfer_supporting;
+       unsigned short     format_unique_value5;
+       unsigned char      format_type;
+       unsigned char      memorystick_application;
+       unsigned char      device_type;
+       unsigned char      reserved1[22];
+       unsigned char      format_uniqure_value6[2];
+       unsigned char      reserved2[15];
+} __packed;
+
+struct ms_cis_idi {
+       unsigned short general_config;
+       unsigned short logical_cylinders;
+       unsigned short reserved0;
+       unsigned short logical_heads;
+       unsigned short track_size;
+       unsigned short page_size;
+       unsigned short pages_per_track;
+       unsigned short msw;
+       unsigned short lsw;
+       unsigned short reserved1;
+       unsigned char  serial_number[20];
+       unsigned short buffer_type;
+       unsigned short buffer_size_increments;
+       unsigned short long_command_ecc;
+       unsigned char  firmware_version[28];
+       unsigned char  model_name[18];
+       unsigned short reserved2[5];
+       unsigned short pio_mode_number;
+       unsigned short dma_mode_number;
+       unsigned short field_validity;
+       unsigned short current_logical_cylinders;
+       unsigned short current_logical_heads;
+       unsigned short current_pages_per_track;
+       unsigned int   current_page_capacity;
+       unsigned short mutiple_page_setting;
+       unsigned int   addressable_pages;
+       unsigned short single_word_dma;
+       unsigned short multi_word_dma;
+       unsigned char  reserved3[128];
+} __packed;
+
+
+struct ms_boot_page {
+       struct ms_boot_header    header;
+       struct ms_system_entry   entry;
+       struct ms_boot_attr_info attr;
+} __packed;
+
+struct msb_data {
+       unsigned int                    usage_count;
+       struct memstick_dev             *card;
+       struct gendisk                  *disk;
+       struct request_queue            *queue;
+       spinlock_t                      q_lock;
+       struct hd_geometry              geometry;
+       struct attribute_group          attr_group;
+       struct request                  *req;
+       int                             caps;
+       int                             disk_id;
+
+       /* IO */
+       struct workqueue_struct         *io_queue;
+       bool                            io_queue_stopped;
+       struct work_struct              io_work;
+       bool                            card_dead;
+
+       /* Media properties */
+       struct ms_boot_page             *boot_page;
+       u16                             boot_block_locations[2];
+       int                             boot_block_count;
+
+       bool                            read_only;
+       unsigned short                  page_size;
+       int                             block_size;
+       int                             pages_in_block;
+       int                             zone_count;
+       int                             block_count;
+       int                             logical_block_count;
+
+       /* FTL tables */
+       unsigned long                   *used_blocks_bitmap;
+       unsigned long                   *erased_blocks_bitmap;
+       u16                             *lba_to_pba_table;
+       int                             free_block_count[MS_MAX_ZONES];
+       bool                            ftl_initialized;
+
+       /* Cache */
+       unsigned char                   *cache;
+       unsigned long                   valid_cache_bitmap;
+       int                             cache_block_lba;
+       bool                            need_flush_cache;
+       struct timer_list               cache_flush_timer;
+
+       /* Preallocated buffers */
+       unsigned char                   *block_buffer;
+       struct scatterlist              prealloc_sg[MS_BLOCK_MAX_SEGS+1];
+
+
+       /* handler's local data */
+       struct ms_register_addr         reg_addr;
+       bool                            addr_valid;
+
+       u8                              command_value;
+       bool                            command_need_oob;
+       struct scatterlist              *current_sg;
+       int                             current_sg_offset;
+
+       struct ms_register              regs;
+       int                             current_page;
+
+       int                             state;
+       int                             exit_error;
+       bool                            int_polling;
+       unsigned long                   int_timeout;
+
+};
+
+enum msb_readpage_states {
+       MSB_RP_SEND_BLOCK_ADDRESS = 0,
+       MSB_RP_SEND_READ_COMMAND,
+
+       MSB_RP_SEND_INT_REQ,
+       MSB_RP_RECEIVE_INT_REQ_RESULT,
+
+       MSB_RP_SEND_READ_STATUS_REG,
+       MSB_RP_RECIVE_STATUS_REG,
+
+       MSB_RP_SEND_OOB_READ,
+       MSB_RP_RECEIVE_OOB_READ,
+
+       MSB_RP_SEND_READ_DATA,
+       MSB_RP_RECEIVE_READ_DATA,
+};
+
+enum msb_write_block_states {
+       MSB_WB_SEND_WRITE_PARAMS = 0,
+       MSB_WB_SEND_WRITE_OOB,
+       MSB_WB_SEND_WRITE_COMMAND,
+
+       MSB_WB_SEND_INT_REQ,
+       MSB_WB_RECEIVE_INT_REQ,
+
+       MSB_WB_SEND_WRITE_DATA,
+       MSB_WB_RECEIVE_WRITE_CONFIRMATION,
+};
+
+enum msb_send_command_states {
+       MSB_SC_SEND_WRITE_PARAMS,
+       MSB_SC_SEND_WRITE_OOB,
+       MSB_SC_SEND_COMMAND,
+
+       MSB_SC_SEND_INT_REQ,
+       MSB_SC_RECEIVE_INT_REQ,
+
+};
+
+enum msb_reset_states {
+       MSB_RS_SEND,
+       MSB_RS_CONFIRM,
+};
+
+enum msb_par_switch_states {
+       MSB_PS_SEND_SWITCH_COMMAND,
+       MSB_PS_SWICH_HOST,
+       MSB_PS_CONFIRM,
+};
+
+struct chs_entry {
+       unsigned long size;
+       unsigned char sec;
+       unsigned short cyl;
+       unsigned char head;
+};
+
+static int msb_reset(struct msb_data *msb, bool full);
+
+static int h_msb_default_bad(struct memstick_dev *card,
+                                               struct memstick_request **mrq);
+
+#define __dbg(level, format, ...) \
+       do { \
+               if (debug >= level) \
+                       pr_err(format "\n", ## __VA_ARGS__); \
+       } while (0)
+
+
+#define dbg(format, ...)               __dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...)       __dbg(2, format, ## __VA_ARGS__)
+
+#endif
index 64a779c58a74fd9346444c62663817010f5331d3..25f8f93decb6e0c97267ed00609b35f881634519 100644 (file)
@@ -1,6 +1,6 @@
 /* Realtek PCI-Express Memstick Card Interface driver
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/module.h>
@@ -613,8 +612,6 @@ static int rtsx_pci_ms_drv_remove(struct platform_device *pdev)
        memstick_remove_host(msh);
        memstick_free_host(msh);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_dbg(&(pdev->dev),
                ": Realtek PCI-E Memstick controller has been removed\n");
 
index 6c954835d61ecb04dd0801ccae801033869f2b74..a65447d65605fe7d7539082322a70cceae9c18c7 100644 (file)
@@ -333,9 +333,11 @@ static int device_rtc_init(struct pm80x_chip *chip,
 {
        int ret;
 
-       rtc_devs[0].platform_data = pdata->rtc;
-       rtc_devs[0].pdata_size =
-                       pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0;
+       if (pdata) {
+               rtc_devs[0].platform_data = pdata->rtc;
+               rtc_devs[0].pdata_size =
+                               pdata->rtc ? sizeof(struct pm80x_rtc_pdata) : 0;
+       }
        ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
                              ARRAY_SIZE(rtc_devs), NULL, 0, NULL);
        if (ret) {
@@ -541,7 +543,7 @@ static int pm800_probe(struct i2c_client *client,
 {
        int ret = 0;
        struct pm80x_chip *chip;
-       struct pm80x_platform_data *pdata = client->dev.platform_data;
+       struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct pm80x_subchip *subchip;
 
        ret = pm80x_init(client);
@@ -578,7 +580,7 @@ static int pm800_probe(struct i2c_client *client,
                goto err_device_init;
        }
 
-       if (pdata->plat_config)
+       if (pdata && pdata->plat_config)
                pdata->plat_config(chip, pdata);
 
        return 0;
index 521602231c7bc43c8ec007f078ae5c4d38bcaa7d..8a5b6ffb5afb6fbedbd8a1364a879890a6ebfba5 100644 (file)
@@ -227,7 +227,7 @@ static int pm805_probe(struct i2c_client *client,
 {
        int ret = 0;
        struct pm80x_chip *chip;
-       struct pm80x_platform_data *pdata = client->dev.platform_data;
+       struct pm80x_platform_data *pdata = dev_get_platdata(&client->dev);
 
        ret = pm80x_init(client);
        if (ret) {
@@ -243,7 +243,7 @@ static int pm805_probe(struct i2c_client *client,
                goto err_805_init;
        }
 
-       if (pdata->plat_config)
+       if (pdata && pdata->plat_config)
                pdata->plat_config(chip, pdata);
 
 err_805_init:
index eeb481d426b5df159264cc28e4bd56210c1ae1e0..7ebe9ef1eba663006399ec1b52f327e3fd3d0e47 100644 (file)
@@ -1130,7 +1130,7 @@ static int pm860x_dt_init(struct device_node *np,
 static int pm860x_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct pm860x_platform_data *pdata = client->dev.platform_data;
+       struct pm860x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct device_node *node = client->dev.of_node;
        struct pm860x_chip *chip;
        int ret;
index aecd6ddcbbbf75699f1ddab73241ee21eb888687..914c3d142f789f0a517d32e59f53b457b61c2089 100644 (file)
@@ -23,7 +23,7 @@ config MFD_AS3711
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          Support for the AS3711 PMIC from AMS
 
@@ -40,7 +40,7 @@ config PMIC_ADP5520
 config MFD_AAT2870_CORE
        bool "AnalogicTech AAT2870"
        select MFD_CORE
-       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+       depends on I2C=y && GPIOLIB
        help
          If you say yes here you get support for the AAT2870.
          This driver provides common support for accessing the device,
@@ -78,7 +78,7 @@ config MFD_CROS_EC_SPI
 
 config MFD_ASIC3
        bool "Compaq ASIC3"
-       depends on GENERIC_HARDIRQS && GPIOLIB && ARM
+       depends on GPIOLIB && ARM
        select MFD_CORE
         ---help---
          This driver supports the ASIC3 multifunction chip found on many
@@ -104,7 +104,7 @@ config MFD_DA9052_SPI
        select REGMAP_SPI
        select REGMAP_IRQ
        select PMIC_DA9052
-       depends on SPI_MASTER=y && GENERIC_HARDIRQS
+       depends on SPI_MASTER=y
        help
          Support for the Dialog Semiconductor DA9052 PMIC
          when controlled using SPI. This driver provides common support
@@ -116,7 +116,7 @@ config MFD_DA9052_I2C
        select REGMAP_I2C
        select REGMAP_IRQ
        select PMIC_DA9052
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          Support for the Dialog Semiconductor DA9052 PMIC
          when controlled using I2C. This driver provides common support
@@ -128,7 +128,7 @@ config MFD_DA9055
        select REGMAP_I2C
        select REGMAP_IRQ
        select MFD_CORE
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          Say yes here for support of Dialog Semiconductor DA9055. This is
          a Power Management IC. This driver provides common support for
@@ -139,12 +139,24 @@ config MFD_DA9055
          This driver can be built as a module. If built as a module it will be
          called "da9055"
 
+config MFD_DA9063
+       bool "Dialog Semiconductor DA9063 PMIC Support"
+       select MFD_CORE
+       select REGMAP_I2C
+       select REGMAP_IRQ
+       depends on I2C=y
+       help
+         Say yes here for support for the Dialog Semiconductor DA9063 PMIC.
+         This includes the I2C driver and core APIs.
+         Additional drivers must be enabled in order to use the functionality
+         of the device.
+
 config MFD_MC13783
        tristate
 
 config MFD_MC13XXX
        tristate
-       depends on (SPI_MASTER || I2C) && GENERIC_HARDIRQS
+       depends on (SPI_MASTER || I2C)
        select MFD_CORE
        select MFD_MC13783
        help
@@ -155,7 +167,7 @@ config MFD_MC13XXX
 
 config MFD_MC13XXX_SPI
        tristate "Freescale MC13783 and MC13892 SPI interface"
-       depends on SPI_MASTER && GENERIC_HARDIRQS
+       depends on SPI_MASTER
        select REGMAP_SPI
        select MFD_MC13XXX
        help
@@ -163,7 +175,7 @@ config MFD_MC13XXX_SPI
 
 config MFD_MC13XXX_I2C
        tristate "Freescale MC13892 I2C interface"
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        select REGMAP_I2C
        select MFD_MC13XXX
        help
@@ -171,7 +183,7 @@ config MFD_MC13XXX_I2C
 
 config HTC_EGPIO
        bool "HTC EGPIO support"
-       depends on GENERIC_HARDIRQS && GPIOLIB && ARM
+       depends on GPIOLIB && ARM
        help
            This driver supports the CPLD egpio chip present on
            several HTC phones.  It provides basic support for input
@@ -180,7 +192,6 @@ config HTC_EGPIO
 config HTC_PASIC3
        tristate "HTC PASIC3 LED/DS1WM chip support"
        select MFD_CORE
-       depends on GENERIC_HARDIRQS
        help
          This core driver provides register access for the LED/DS1WM
          chips labeled "AIC2" and "AIC3", found on HTC Blueangel and
@@ -198,7 +209,7 @@ config HTC_I2CPLD
 
 config LPC_ICH
        tristate "Intel ICH LPC"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select MFD_CORE
        help
          The LPC bridge function of the Intel ICH provides support for
@@ -208,7 +219,7 @@ config LPC_ICH
 
 config LPC_SCH
        tristate "Intel SCH LPC"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select MFD_CORE
        help
          LPC bridge function of the Intel SCH provides support for
@@ -226,7 +237,7 @@ config MFD_INTEL_MSIC
 config MFD_JANZ_CMODIO
        tristate "Janz CMOD-IO PCI MODULbus Carrier Board"
        select MFD_CORE
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        help
          This is the core driver for the Janz CMOD-IO PCI MODULbus
          carrier board. This device is a PCI to MODULbus bridge which may
@@ -265,7 +276,7 @@ config MFD_KEMPLD
 
 config MFD_88PM800
        tristate "Marvell 88PM800"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select REGMAP_I2C
        select REGMAP_IRQ
        select MFD_CORE
@@ -277,7 +288,7 @@ config MFD_88PM800
 
 config MFD_88PM805
        tristate "Marvell 88PM805"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select REGMAP_I2C
        select REGMAP_IRQ
        select MFD_CORE
@@ -289,7 +300,7 @@ config MFD_88PM805
 
 config MFD_88PM860X
        bool "Marvell 88PM8606/88PM8607"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select REGMAP_I2C
        select MFD_CORE
        help
@@ -300,7 +311,7 @@ config MFD_88PM860X
 
 config MFD_MAX77686
        bool "Maxim Semiconductor MAX77686 PMIC Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select IRQ_DOMAIN
@@ -313,7 +324,7 @@ config MFD_MAX77686
 
 config MFD_MAX77693
        bool "Maxim Semiconductor MAX77693 PMIC Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -327,7 +338,7 @@ config MFD_MAX77693
 config MFD_MAX8907
        tristate "Maxim Semiconductor MAX8907 PMIC Support"
        select MFD_CORE
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select REGMAP_I2C
        select REGMAP_IRQ
        help
@@ -338,7 +349,7 @@ config MFD_MAX8907
 
 config MFD_MAX8925
        bool "Maxim Semiconductor MAX8925 PMIC Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        help
          Say yes here to support for Maxim Semiconductor MAX8925. This is
@@ -348,7 +359,7 @@ config MFD_MAX8925
 
 config MFD_MAX8997
        bool "Maxim Semiconductor MAX8997/8966 PMIC Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select IRQ_DOMAIN
        help
@@ -361,7 +372,7 @@ config MFD_MAX8997
 
 config MFD_MAX8998
        bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select IRQ_DOMAIN
        help
@@ -373,7 +384,7 @@ config MFD_MAX8998
 
 config EZX_PCAP
        bool "Motorola EZXPCAP Support"
-       depends on GENERIC_HARDIRQS && SPI_MASTER
+       depends on SPI_MASTER
        help
          This enables the PCAP ASIC present on EZX Phones. This is
          needed for MMC, TouchScreen, Sound, USB, etc..
@@ -381,7 +392,7 @@ config EZX_PCAP
 config MFD_VIPERBOARD
         tristate "Nano River Technologies Viperboard"
        select MFD_CORE
-       depends on USB && GENERIC_HARDIRQS
+       depends on USB
        default n
        help
          Say yes here if you want support for Nano River Technologies
@@ -395,7 +406,7 @@ config MFD_VIPERBOARD
 config MFD_RETU
        tristate "Nokia Retu and Tahvo multi-function device"
        select MFD_CORE
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        select REGMAP_IRQ
        help
          Retu and Tahvo are a multi-function devices found on Nokia
@@ -468,7 +479,7 @@ config MFD_PM8XXX_IRQ
 config MFD_RDC321X
        tristate "RDC R-321x southbridge"
        select MFD_CORE
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        help
          Say yes here if you want to have support for the RDC R-321x SoC
          southbridge which provides access to GPIOs and Watchdog using the
@@ -476,7 +487,7 @@ config MFD_RDC321X
 
 config MFD_RTSX_PCI
        tristate "Realtek PCI-E card reader"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select MFD_CORE
        help
          This supports for Realtek PCI-Express card reader including rts5209,
@@ -486,7 +497,7 @@ config MFD_RTSX_PCI
 
 config MFD_RC5T583
        bool "Ricoh RC5T583 Power Management system device"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -500,7 +511,7 @@ config MFD_RC5T583
 
 config MFD_SEC_CORE
        bool "SAMSUNG Electronics PMIC Series Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -543,7 +554,7 @@ config MFD_SM501_GPIO
 
 config MFD_SMSC
        bool "SMSC ECE1099 series chips"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -565,7 +576,7 @@ config ABX500_CORE
 
 config AB3100_CORE
        bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions"
-       depends on I2C=y && ABX500_CORE && GENERIC_HARDIRQS
+       depends on I2C=y && ABX500_CORE
        select MFD_CORE
        default y if ARCH_U300
        help
@@ -589,7 +600,7 @@ config AB3100_OTP
 
 config AB8500_CORE
        bool "ST-Ericsson AB8500 Mixed Signal Power Management chip"
-       depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU
+       depends on ABX500_CORE && MFD_DB8500_PRCMU
        select POWER_SUPPLY
        select MFD_CORE
        select IRQ_DOMAIN
@@ -627,7 +638,7 @@ config MFD_DB8500_PRCMU
 
 config MFD_STMPE
        bool "STMicroelectronics STMPE"
-       depends on (I2C=y || SPI_MASTER=y) && GENERIC_HARDIRQS
+       depends on (I2C=y || SPI_MASTER=y)
        select MFD_CORE
        help
          Support for the STMPE family of I/O Expanders from
@@ -668,7 +679,7 @@ endmenu
 
 config MFD_STA2X11
        bool "STMicroelectronics STA2X11"
-       depends on STA2X11 && GENERIC_HARDIRQS
+       depends on STA2X11
        select MFD_CORE
        select REGMAP_MMIO
 
@@ -688,7 +699,6 @@ config MFD_TI_AM335X_TSCADC
        select MFD_CORE
        select REGMAP
        select REGMAP_MMIO
-       depends on GENERIC_HARDIRQS
        help
          If you say yes here you get support for Texas Instruments series
          of Touch Screen /ADC chips.
@@ -705,7 +715,7 @@ config MFD_DM355EVM_MSP
 
 config MFD_LP8788
        bool "TI LP8788 Power Management Unit Driver"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select IRQ_DOMAIN
@@ -727,14 +737,14 @@ config MFD_PALMAS
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          If you say yes here you get support for the Palmas
          series of PMIC chips from Texas Instruments.
 
 config MFD_TI_SSP
        tristate "TI Sequencer Serial Port support"
-       depends on ARCH_DAVINCI_TNETV107X && GENERIC_HARDIRQS
+       depends on ARCH_DAVINCI_TNETV107X
        select MFD_CORE
        ---help---
          Say Y here if you want support for the Sequencer Serial Port
@@ -749,7 +759,6 @@ config TPS6105X
        select REGULATOR
        select MFD_CORE
        select REGULATOR_FIXED_VOLTAGE
-       depends on GENERIC_HARDIRQS
        help
          This option enables a driver for the TP61050/TPS61052
          high-power "white LED driver". This boost converter is
@@ -772,7 +781,7 @@ config TPS65010
 config TPS6507X
        tristate "TI TPS6507x Power Management / Touch Screen chips"
        select MFD_CORE
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        help
          If you say yes here you get support for the TPS6507x series of
          Power Management / Touch Screen chips.  These include voltage
@@ -786,7 +795,7 @@ config TPS65911_COMPARATOR
 
 config MFD_TPS65090
        bool "TI TPS65090 Power Management chips"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -799,7 +808,7 @@ config MFD_TPS65090
 
 config MFD_TPS65217
        tristate "TI TPS65217 Power Management / White LED chips"
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -814,7 +823,7 @@ config MFD_TPS65217
 
 config MFD_TPS6586X
        bool "TI TPS6586x Power Management chips"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        help
@@ -829,7 +838,7 @@ config MFD_TPS6586X
 
 config MFD_TPS65910
        bool "TI TPS65910 Power Management chip"
-       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+       depends on I2C=y && GPIOLIB
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -850,7 +859,7 @@ config MFD_TPS65912_I2C
        bool "TI TPS65912 Power Management chip with I2C"
        select MFD_CORE
        select MFD_TPS65912
-       depends on I2C=y && GPIOLIB && GENERIC_HARDIRQS
+       depends on I2C=y && GPIOLIB
        help
          If you say yes here you get support for the TPS65912 series of
          PM chips with I2C interface.
@@ -859,14 +868,14 @@ config MFD_TPS65912_SPI
        bool "TI TPS65912 Power Management chip with SPI"
        select MFD_CORE
        select MFD_TPS65912
-       depends on SPI_MASTER && GPIOLIB && GENERIC_HARDIRQS
+       depends on SPI_MASTER && GPIOLIB
        help
          If you say yes here you get support for the TPS65912 series of
          PM chips with SPI interface.
 
 config MFD_TPS80031
        bool "TI TPS80031/TPS80032 Power Management chips"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -880,7 +889,7 @@ config MFD_TPS80031
 
 config TWL4030_CORE
        bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select IRQ_DOMAIN
        select REGMAP_I2C
        help
@@ -919,13 +928,13 @@ config TWL4030_POWER
 
 config MFD_TWL4030_AUDIO
        bool "TI TWL4030 Audio"
-       depends on TWL4030_CORE && GENERIC_HARDIRQS
+       depends on TWL4030_CORE
        select MFD_CORE
        default n
 
 config TWL6040_CORE
        bool "TI TWL6040 audio codec"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
@@ -949,7 +958,7 @@ config MENELAUS
 
 config MFD_WL1273_CORE
        tristate "TI WL1273 FM radio"
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        select MFD_CORE
        default n
        help
@@ -962,7 +971,6 @@ config MFD_LM3533
        depends on I2C
        select MFD_CORE
        select REGMAP_I2C
-       depends on GENERIC_HARDIRQS
        help
          Say yes here to enable support for National Semiconductor / TI
          LM3533 Lighting Power chips.
@@ -984,7 +992,7 @@ config MFD_TIMBERDALE
 
 config MFD_TC3589X
        bool "Toshiba TC35892 and variants"
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_CORE
        help
          Support for the Toshiba TC35892 and variants I/O Expander.
@@ -999,7 +1007,7 @@ config MFD_TMIO
 
 config MFD_T7L66XB
        bool "Toshiba T7L66XB"
-       depends on ARM && HAVE_CLK && GENERIC_HARDIRQS
+       depends on ARM && HAVE_CLK
        select MFD_CORE
        select MFD_TMIO
        help
@@ -1024,7 +1032,7 @@ config MFD_TC6393XB
 
 config MFD_VX855
        tristate "VIA VX855/VX875 integrated south bridge"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select MFD_CORE
        help
          Say yes here to enable support for various functions of the
@@ -1042,7 +1050,7 @@ config MFD_ARIZONA_I2C
        select MFD_ARIZONA
        select MFD_CORE
        select REGMAP_I2C
-       depends on I2C && GENERIC_HARDIRQS
+       depends on I2C
        help
          Support for the Wolfson Microelectronics Arizona platform audio SoC
          core functionality controlled via I2C.
@@ -1052,7 +1060,7 @@ config MFD_ARIZONA_SPI
        select MFD_ARIZONA
        select MFD_CORE
        select REGMAP_SPI
-       depends on SPI_MASTER && GENERIC_HARDIRQS
+       depends on SPI_MASTER
        help
          Support for the Wolfson Microelectronics Arizona platform audio SoC
          core functionality controlled via I2C.
@@ -1070,7 +1078,7 @@ config MFD_WM5110
          Support for Wolfson Microelectronics WM5110 low power audio SoC
 
 config MFD_WM8997
-       bool "Support Wolfson Microelectronics WM8997"
+       bool "Wolfson Microelectronics WM8997"
        depends on MFD_ARIZONA
        help
          Support for Wolfson Microelectronics WM8997 low power audio SoC
@@ -1078,7 +1086,7 @@ config MFD_WM8997
 config MFD_WM8400
        bool "Wolfson Microelectronics WM8400"
        select MFD_CORE
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select REGMAP_I2C
        help
          Support for the Wolfson Microelecronics WM8400 PMIC and audio
@@ -1088,7 +1096,6 @@ config MFD_WM8400
 
 config MFD_WM831X
        bool
-       depends on GENERIC_HARDIRQS
 
 config MFD_WM831X_I2C
        bool "Wolfson Microelectronics WM831x/2x PMICs with I2C"
@@ -1096,7 +1103,7 @@ config MFD_WM831X_I2C
        select MFD_WM831X
        select REGMAP_I2C
        select IRQ_DOMAIN
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          Support for the Wolfson Microelecronics WM831x and WM832x PMICs
          when controlled using I2C.  This driver provides common support
@@ -1109,7 +1116,7 @@ config MFD_WM831X_SPI
        select MFD_WM831X
        select REGMAP_SPI
        select IRQ_DOMAIN
-       depends on SPI_MASTER && GENERIC_HARDIRQS
+       depends on SPI_MASTER
        help
          Support for the Wolfson Microelecronics WM831x and WM832x PMICs
          when controlled using SPI.  This driver provides common support
@@ -1118,12 +1125,11 @@ config MFD_WM831X_SPI
 
 config MFD_WM8350
        bool
-       depends on GENERIC_HARDIRQS
 
 config MFD_WM8350_I2C
        bool "Wolfson Microelectronics WM8350 with I2C"
        select MFD_WM8350
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          The WM8350 is an integrated audio and power management
          subsystem with watchdog and RTC functionality for embedded
@@ -1136,7 +1142,7 @@ config MFD_WM8994
        select MFD_CORE
        select REGMAP_I2C
        select REGMAP_IRQ
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        help
          The WM8994 is a highly integrated hi-fi CODEC designed for
          smartphone applicatiosn.  As well as audio functionality it
index 3c90051ffa5a390972a4d3cffb34f4b055ed3d8f..15b905c6553c07e7953b7cc4b57c63fcd5ad06a1 100644 (file)
@@ -107,6 +107,9 @@ obj-$(CONFIG_MFD_LP8788)    += lp8788.o lp8788-irq.o
 da9055-objs                    := da9055-core.o da9055-i2c.o
 obj-$(CONFIG_MFD_DA9055)       += da9055.o
 
+da9063-objs                    := da9063-core.o da9063-irq.o da9063-i2c.o
+obj-$(CONFIG_MFD_DA9063)       += da9063.o
+
 obj-$(CONFIG_MFD_MAX77686)     += max77686.o max77686-irq.o
 obj-$(CONFIG_MFD_MAX77693)     += max77693.o max77693-irq.o
 obj-$(CONFIG_MFD_MAX8907)      += max8907.o
index d4f594517521b30e5bc3344208b21d03801ef14d..6f68472e0ca633e9b0ec5f08db4f1389af93336e 100644 (file)
@@ -363,7 +363,7 @@ static inline void aat2870_uninit_debugfs(struct aat2870_data *aat2870)
 static int aat2870_i2c_probe(struct i2c_client *client,
                             const struct i2c_device_id *id)
 {
-       struct aat2870_platform_data *pdata = client->dev.platform_data;
+       struct aat2870_platform_data *pdata = dev_get_platdata(&client->dev);
        struct aat2870_data *aat2870;
        int i, j;
        int ret = 0;
index ddc669d19530ee7a171547b78983adab6b4b7e0d..b348ae5206297eb554e70decb2e21d216fd8a2f6 100644 (file)
@@ -854,7 +854,7 @@ static int ab3100_probe(struct i2c_client *client,
 {
        struct ab3100 *ab3100;
        struct ab3100_platform_data *ab3100_plf_data =
-               client->dev.platform_data;
+               dev_get_platdata(&client->dev);
        int err;
        int i;
 
index 7d1f1b08fc4be76c20310879b34b0a2394c3034f..e33e385af0a29e7930e4277984c640a1cf1db975 100644 (file)
@@ -159,7 +159,7 @@ static struct hwreg_cfg hwreg_cfg = {
 
 static struct ab8500_prcmu_ranges *debug_ranges;
 
-struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
+static struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
        [0x0] = {
                .num_ranges = 0,
                .range = NULL,
@@ -488,7 +488,7 @@ struct ab8500_prcmu_ranges ab8500_debug_ranges[AB8500_NUM_BANKS] = {
        },
 };
 
-struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
+static struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
        [0x0] = {
                .num_ranges = 0,
                .range = NULL,
@@ -847,7 +847,7 @@ struct ab8500_prcmu_ranges ab8505_debug_ranges[AB8500_NUM_BANKS] = {
        },
 };
 
-struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = {
+static struct ab8500_prcmu_ranges ab8540_debug_ranges[AB8500_NUM_BANKS] = {
        [AB8500_M_FSM_RANK] = {
                .num_ranges = 1,
                .range = (struct ab8500_reg_range[]) {
@@ -1377,7 +1377,7 @@ void ab8500_dump_all_banks(struct device *dev)
 
 /* Space for 500 registers. */
 #define DUMP_MAX_REGS 700
-struct ab8500_register_dump
+static struct ab8500_register_dump
 {
        u8 bank;
        u8 reg;
@@ -2800,7 +2800,13 @@ static ssize_t ab8500_subscribe_write(struct file *file,
         */
        dev_attr[irq_index] = kmalloc(sizeof(struct device_attribute),
                GFP_KERNEL);
+       if (!dev_attr[irq_index])
+               return -ENOMEM;
+
        event_name[irq_index] = kmalloc(count, GFP_KERNEL);
+       if (!event_name[irq_index])
+               return -ENOMEM;
+
        sprintf(event_name[irq_index], "%lu", user_val);
        dev_attr[irq_index]->show = show_irq;
        dev_attr[irq_index]->store = NULL;
index 7623e91238287b4d04f6b5d28e994fd0e478117b..36000f920981b055195c1cd4b1dfd88954050655 100644 (file)
@@ -867,6 +867,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
                gpadc->cal_data[ADC_INPUT_VBAT].offset);
 }
 
+#ifdef CONFIG_PM_RUNTIME
 static int ab8500_gpadc_runtime_suspend(struct device *dev)
 {
        struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
@@ -885,7 +886,9 @@ static int ab8500_gpadc_runtime_resume(struct device *dev)
                dev_err(dev, "Failed to enable vtvout LDO: %d\n", ret);
        return ret;
 }
+#endif
 
+#ifdef CONFIG_PM_SLEEP
 static int ab8500_gpadc_suspend(struct device *dev)
 {
        struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
@@ -913,6 +916,7 @@ static int ab8500_gpadc_resume(struct device *dev)
        mutex_unlock(&gpadc->ab8500_gpadc_lock);
        return ret;
 }
+#endif
 
 static int ab8500_gpadc_probe(struct platform_device *pdev)
 {
index 28346ad0b4a6da0eee7e5e6f09e025769d11b024..62501553d63c4f7c2b49da5c73d79141d964179e 100644 (file)
@@ -207,7 +207,7 @@ static int adp5520_remove_subdevs(struct adp5520_chip *chip)
 static int adp5520_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
-       struct adp5520_platform_data *pdata = client->dev.platform_data;
+       struct adp5520_platform_data *pdata = dev_get_platdata(&client->dev);
        struct platform_device *pdev;
        struct adp5520_chip *chip;
        int ret;
index 89a115301a0cbea26adb9e4b1ffec8ef1cebe7f1..5ac3aa48473be0364d70eeae84a7a423b1a3be4d 100644 (file)
@@ -438,9 +438,9 @@ static int arizona_runtime_suspend(struct device *dev)
                }
        }
 
-       regulator_disable(arizona->dcvdd);
        regcache_cache_only(arizona->regmap, true);
        regcache_mark_dirty(arizona->regmap);
+       regulator_disable(arizona->dcvdd);
 
        return 0;
 }
index 01e414162702bcd1ccfcc8e73f099e8a95cf14b3..abd3ab7c0908ab6232f0e7d82a35361ca33c46c7 100644 (file)
@@ -129,7 +129,7 @@ static int as3711_i2c_probe(struct i2c_client *client,
        int ret;
 
        if (!client->dev.of_node) {
-               pdata = client->dev.platform_data;
+               pdata = dev_get_platdata(&client->dev);
                if (!pdata)
                        dev_dbg(&client->dev, "Platform data not found\n");
        } else {
index 9532f749412f6442f190d3ec34fff0c286b36e9d..fa22154c84e49cfb6be58930339ea180b8be77b6 100644 (file)
@@ -952,7 +952,7 @@ static void asic3_mfd_remove(struct platform_device *pdev)
 /* Core */
 static int __init asic3_probe(struct platform_device *pdev)
 {
-       struct asic3_platform_data *pdata = pdev->dev.platform_data;
+       struct asic3_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct asic3 *asic;
        struct resource *mem;
        unsigned long clksel;
index f1a316e0d6a68850e367d0455937be635148fa89..e0a2e0ee603be73a6d808efa2ce1673f9c32e7ae 100644 (file)
@@ -494,7 +494,7 @@ failed:
 static int da903x_probe(struct i2c_client *client,
                                  const struct i2c_device_id *id)
 {
-       struct da903x_platform_data *pdata = client->dev.platform_data;
+       struct da903x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct da903x_chip *chip;
        unsigned int tmp;
        int ret;
index a3c9613f91664e87ae03f4496c3360df74c755ef..ea28a33576e45cd3c3df406a09264bd69a5c3298 100644 (file)
@@ -534,7 +534,7 @@ EXPORT_SYMBOL_GPL(da9052_regmap_config);
 
 int da9052_device_init(struct da9052 *da9052, u8 chip_id)
 {
-       struct da9052_pdata *pdata = da9052->dev->platform_data;
+       struct da9052_pdata *pdata = dev_get_platdata(da9052->dev);
        int ret;
 
        mutex_init(&da9052->auxadc_lock);
index 49cb23d37469153980f5b78ceb0126f1d46aa852..d3670cd3c3c6c0e025c80ec940851ee5599037b1 100644 (file)
@@ -379,8 +379,9 @@ static struct regmap_irq_chip da9055_regmap_irq_chip = {
 
 int da9055_device_init(struct da9055 *da9055)
 {
-       struct da9055_pdata *pdata = da9055->dev->platform_data;
+       struct da9055_pdata *pdata = dev_get_platdata(da9055->dev);
        int ret;
+       uint8_t clear_events[3] = {0xFF, 0xFF, 0xFF};
 
        if (pdata && pdata->init != NULL)
                pdata->init(da9055);
@@ -390,6 +391,10 @@ int da9055_device_init(struct da9055 *da9055)
        else
                da9055->irq_base = pdata->irq_base;
 
+       ret = da9055_group_write(da9055, DA9055_REG_EVENT_A, 3, clear_events);
+       if (ret < 0)
+               return ret;
+
        ret = regmap_add_irq_chip(da9055->regmap, da9055->chip_irq,
                                  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
                                  da9055->irq_base, &da9055_regmap_irq_chip,
index 607387ffe8caa85e6d0396facd62a094dc4523a7..13af7e50021eedd5767aa296cfe46118f55f49ac 100644 (file)
@@ -54,7 +54,7 @@ static int da9055_i2c_remove(struct i2c_client *i2c)
 }
 
 static struct i2c_device_id da9055_i2c_id[] = {
-       {"da9055-pmic", 0},
+       {"da9055", 0},
        { }
 };
 
diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c
new file mode 100644 (file)
index 0000000..c9cf8d9
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * da9063-core.c: Device access for Dialog DA9063 modules
+ *
+ * Copyright 2012 Dialog Semiconductors Ltd.
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.com>,
+ *         Michal Hajduk <michal.hajduk@diasemi.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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/mfd/core.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+#include <linux/mfd/da9063/registers.h>
+
+#include <linux/proc_fs.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+
+
+static struct resource da9063_regulators_resources[] = {
+       {
+               .name   = "LDO_LIM",
+               .start  = DA9063_IRQ_LDO_LIM,
+               .end    = DA9063_IRQ_LDO_LIM,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource da9063_rtc_resources[] = {
+       {
+               .name   = "ALARM",
+               .start  = DA9063_IRQ_ALARM,
+               .end    = DA9063_IRQ_ALARM,
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "TICK",
+               .start  = DA9063_IRQ_TICK,
+               .end    = DA9063_IRQ_TICK,
+               .flags  = IORESOURCE_IRQ,
+       }
+};
+
+static struct resource da9063_onkey_resources[] = {
+       {
+               .start  = DA9063_IRQ_ONKEY,
+               .end    = DA9063_IRQ_ONKEY,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource da9063_hwmon_resources[] = {
+       {
+               .start  = DA9063_IRQ_ADC_RDY,
+               .end    = DA9063_IRQ_ADC_RDY,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+
+static struct mfd_cell da9063_devs[] = {
+       {
+               .name           = DA9063_DRVNAME_REGULATORS,
+               .num_resources  = ARRAY_SIZE(da9063_regulators_resources),
+               .resources      = da9063_regulators_resources,
+       },
+       {
+               .name           = DA9063_DRVNAME_LEDS,
+       },
+       {
+               .name           = DA9063_DRVNAME_WATCHDOG,
+       },
+       {
+               .name           = DA9063_DRVNAME_HWMON,
+               .num_resources  = ARRAY_SIZE(da9063_hwmon_resources),
+               .resources      = da9063_hwmon_resources,
+       },
+       {
+               .name           = DA9063_DRVNAME_ONKEY,
+               .num_resources  = ARRAY_SIZE(da9063_onkey_resources),
+               .resources      = da9063_onkey_resources,
+       },
+       {
+               .name           = DA9063_DRVNAME_RTC,
+               .num_resources  = ARRAY_SIZE(da9063_rtc_resources),
+               .resources      = da9063_rtc_resources,
+       },
+       {
+               .name           = DA9063_DRVNAME_VIBRATION,
+       },
+};
+
+int da9063_device_init(struct da9063 *da9063, unsigned int irq)
+{
+       struct da9063_pdata *pdata = da9063->dev->platform_data;
+       int model, revision;
+       int ret;
+
+       if (pdata) {
+               da9063->flags = pdata->flags;
+               da9063->irq_base = pdata->irq_base;
+       } else {
+               da9063->flags = 0;
+               da9063->irq_base = 0;
+       }
+       da9063->chip_irq = irq;
+
+       if (pdata && pdata->init != NULL) {
+               ret = pdata->init(da9063);
+               if (ret != 0) {
+                       dev_err(da9063->dev,
+                               "Platform initialization failed.\n");
+                       return ret;
+               }
+       }
+
+       ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_ID, &model);
+       if (ret < 0) {
+               dev_err(da9063->dev, "Cannot read chip model id.\n");
+               return -EIO;
+       }
+       if (model != PMIC_DA9063) {
+               dev_err(da9063->dev, "Invalid chip model id: 0x%02x\n", model);
+               return -ENODEV;
+       }
+
+       ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &revision);
+       if (ret < 0) {
+               dev_err(da9063->dev, "Cannot read chip revision id.\n");
+               return -EIO;
+       }
+       revision >>= DA9063_CHIP_VARIANT_SHIFT;
+       if (revision != 3) {
+               dev_err(da9063->dev, "Unknown chip revision: %d\n", revision);
+               return -ENODEV;
+       }
+
+       da9063->model = model;
+       da9063->revision = revision;
+
+       dev_info(da9063->dev,
+                "Device detected (model-ID: 0x%02X  rev-ID: 0x%02X)\n",
+                model, revision);
+
+       ret = da9063_irq_init(da9063);
+       if (ret) {
+               dev_err(da9063->dev, "Cannot initialize interrupts.\n");
+               return ret;
+       }
+
+       ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
+                             ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
+                             NULL);
+       if (ret)
+               dev_err(da9063->dev, "Cannot add MFD cells\n");
+
+       return ret;
+}
+
+void da9063_device_exit(struct da9063 *da9063)
+{
+       mfd_remove_devices(da9063->dev);
+       da9063_irq_exit(da9063);
+}
+
+MODULE_DESCRIPTION("PMIC driver for Dialog DA9063");
+MODULE_AUTHOR("Krystian Garbaciak <krystian.garbaciak@diasemi.com>, Michal Hajduk <michal.hajduk@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c
new file mode 100644 (file)
index 0000000..8db5c80
--- /dev/null
@@ -0,0 +1,182 @@
+/* da9063-i2c.c: Interrupt support for Dialog DA9063
+ *
+ * Copyright 2012 Dialog Semiconductor Ltd.
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.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/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+#include <linux/mfd/da9063/registers.h>
+
+static const struct regmap_range da9063_readable_ranges[] = {
+       {
+               .range_min = DA9063_REG_PAGE_CON,
+               .range_max = DA9063_REG_SECOND_D,
+       }, {
+               .range_min = DA9063_REG_SEQ,
+               .range_max = DA9063_REG_ID_32_31,
+       }, {
+               .range_min = DA9063_REG_SEQ_A,
+               .range_max = DA9063_REG_AUTO3_LOW,
+       }, {
+               .range_min = DA9063_REG_T_OFFSET,
+               .range_max = DA9063_REG_GP_ID_19,
+       }, {
+               .range_min = DA9063_REG_CHIP_ID,
+               .range_max = DA9063_REG_CHIP_VARIANT,
+       },
+};
+
+static const struct regmap_range da9063_writeable_ranges[] = {
+       {
+               .range_min = DA9063_REG_PAGE_CON,
+               .range_max = DA9063_REG_PAGE_CON,
+       }, {
+               .range_min = DA9063_REG_FAULT_LOG,
+               .range_max = DA9063_REG_VSYS_MON,
+       }, {
+               .range_min = DA9063_REG_COUNT_S,
+               .range_max = DA9063_REG_ALARM_Y,
+       }, {
+               .range_min = DA9063_REG_SEQ,
+               .range_max = DA9063_REG_ID_32_31,
+       }, {
+               .range_min = DA9063_REG_SEQ_A,
+               .range_max = DA9063_REG_AUTO3_LOW,
+       }, {
+               .range_min = DA9063_REG_CONFIG_I,
+               .range_max = DA9063_REG_MON_REG_4,
+       }, {
+               .range_min = DA9063_REG_GP_ID_0,
+               .range_max = DA9063_REG_GP_ID_19,
+       },
+};
+
+static const struct regmap_range da9063_volatile_ranges[] = {
+       {
+               .range_min = DA9063_REG_STATUS_A,
+               .range_max = DA9063_REG_EVENT_D,
+       }, {
+               .range_min = DA9063_REG_CONTROL_F,
+               .range_max = DA9063_REG_CONTROL_F,
+       }, {
+               .range_min = DA9063_REG_ADC_MAN,
+               .range_max = DA9063_REG_ADC_MAN,
+       }, {
+               .range_min = DA9063_REG_ADC_RES_L,
+               .range_max = DA9063_REG_SECOND_D,
+       }, {
+               .range_min = DA9063_REG_MON_REG_5,
+               .range_max = DA9063_REG_MON_REG_6,
+       },
+};
+
+static const struct regmap_access_table da9063_readable_table = {
+       .yes_ranges = da9063_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(da9063_readable_ranges),
+};
+
+static const struct regmap_access_table da9063_writeable_table = {
+       .yes_ranges = da9063_writeable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(da9063_writeable_ranges),
+};
+
+static const struct regmap_access_table da9063_volatile_table = {
+       .yes_ranges = da9063_volatile_ranges,
+       .n_yes_ranges = ARRAY_SIZE(da9063_volatile_ranges),
+};
+
+static const struct regmap_range_cfg da9063_range_cfg[] = {
+       {
+               .range_min = DA9063_REG_PAGE_CON,
+               .range_max = DA9063_REG_CHIP_VARIANT,
+               .selector_reg = DA9063_REG_PAGE_CON,
+               .selector_mask = 1 << DA9063_I2C_PAGE_SEL_SHIFT,
+               .selector_shift = DA9063_I2C_PAGE_SEL_SHIFT,
+               .window_start = 0,
+               .window_len = 256,
+       }
+};
+
+static struct regmap_config da9063_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .ranges = da9063_range_cfg,
+       .num_ranges = ARRAY_SIZE(da9063_range_cfg),
+       .max_register = DA9063_REG_CHIP_VARIANT,
+
+       .cache_type = REGCACHE_RBTREE,
+
+       .rd_table = &da9063_readable_table,
+       .wr_table = &da9063_writeable_table,
+       .volatile_table = &da9063_volatile_table,
+};
+
+static int da9063_i2c_probe(struct i2c_client *i2c,
+       const struct i2c_device_id *id)
+{
+       struct da9063 *da9063;
+       int ret;
+
+       da9063 = devm_kzalloc(&i2c->dev, sizeof(struct da9063), GFP_KERNEL);
+       if (da9063 == NULL)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, da9063);
+       da9063->dev = &i2c->dev;
+       da9063->chip_irq = i2c->irq;
+
+       da9063->regmap = devm_regmap_init_i2c(i2c, &da9063_regmap_config);
+       if (IS_ERR(da9063->regmap)) {
+               ret = PTR_ERR(da9063->regmap);
+               dev_err(da9063->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       return da9063_device_init(da9063, i2c->irq);
+}
+
+static int da9063_i2c_remove(struct i2c_client *i2c)
+{
+       struct da9063 *da9063 = i2c_get_clientdata(i2c);
+
+       da9063_device_exit(da9063);
+
+       return 0;
+}
+
+static const struct i2c_device_id da9063_i2c_id[] = {
+       {"da9063", PMIC_DA9063},
+       {},
+};
+MODULE_DEVICE_TABLE(i2c, da9063_i2c_id);
+
+static struct i2c_driver da9063_i2c_driver = {
+       .driver = {
+               .name = "da9063",
+               .owner = THIS_MODULE,
+       },
+       .probe    = da9063_i2c_probe,
+       .remove   = da9063_i2c_remove,
+       .id_table = da9063_i2c_id,
+};
+
+module_i2c_driver(da9063_i2c_driver);
diff --git a/drivers/mfd/da9063-irq.c b/drivers/mfd/da9063-irq.c
new file mode 100644 (file)
index 0000000..8229226
--- /dev/null
@@ -0,0 +1,193 @@
+/* da9063-irq.c: Interrupts support for Dialog DA9063
+ *
+ * Copyright 2012 Dialog Semiconductor Ltd.
+ * Copyright 2013 Philipp Zabel, Pengutronix
+ *
+ * Author: Michal Hajduk <michal.hajduk@diasemi.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/kernel.h>
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/mfd/core.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/mfd/da9063/core.h>
+#include <linux/mfd/da9063/pdata.h>
+
+#define        DA9063_REG_EVENT_A_OFFSET       0
+#define        DA9063_REG_EVENT_B_OFFSET       1
+#define        DA9063_REG_EVENT_C_OFFSET       2
+#define        DA9063_REG_EVENT_D_OFFSET       3
+#define EVENTS_BUF_LEN                 4
+
+static const u8 mask_events_buf[] = { [0 ... (EVENTS_BUF_LEN - 1)] = ~0 };
+
+struct da9063_irq_data {
+       u16 reg;
+       u8 mask;
+};
+
+static struct regmap_irq da9063_irqs[] = {
+       /* DA9063 event A register */
+       [DA9063_IRQ_ONKEY] = {
+               .reg_offset = DA9063_REG_EVENT_A_OFFSET,
+               .mask = DA9063_M_ONKEY,
+       },
+       [DA9063_IRQ_ALARM] = {
+               .reg_offset = DA9063_REG_EVENT_A_OFFSET,
+               .mask = DA9063_M_ALARM,
+       },
+       [DA9063_IRQ_TICK] = {
+               .reg_offset = DA9063_REG_EVENT_A_OFFSET,
+               .mask = DA9063_M_TICK,
+       },
+       [DA9063_IRQ_ADC_RDY] = {
+               .reg_offset = DA9063_REG_EVENT_A_OFFSET,
+               .mask = DA9063_M_ADC_RDY,
+       },
+       [DA9063_IRQ_SEQ_RDY] = {
+               .reg_offset = DA9063_REG_EVENT_A_OFFSET,
+               .mask = DA9063_M_SEQ_RDY,
+       },
+       /* DA9063 event B register */
+       [DA9063_IRQ_WAKE] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_WAKE,
+       },
+       [DA9063_IRQ_TEMP] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_TEMP,
+       },
+       [DA9063_IRQ_COMP_1V2] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_COMP_1V2,
+       },
+       [DA9063_IRQ_LDO_LIM] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_LDO_LIM,
+       },
+       [DA9063_IRQ_REG_UVOV] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_UVOV,
+       },
+       [DA9063_IRQ_VDD_MON] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_VDD_MON,
+       },
+       [DA9063_IRQ_WARN] = {
+               .reg_offset = DA9063_REG_EVENT_B_OFFSET,
+               .mask = DA9063_M_VDD_WARN,
+       },
+       /* DA9063 event C register */
+       [DA9063_IRQ_GPI0] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI0,
+       },
+       [DA9063_IRQ_GPI1] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI1,
+       },
+       [DA9063_IRQ_GPI2] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI2,
+       },
+       [DA9063_IRQ_GPI3] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI3,
+       },
+       [DA9063_IRQ_GPI4] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI4,
+       },
+       [DA9063_IRQ_GPI5] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI5,
+       },
+       [DA9063_IRQ_GPI6] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI6,
+       },
+       [DA9063_IRQ_GPI7] = {
+               .reg_offset = DA9063_REG_EVENT_C_OFFSET,
+               .mask = DA9063_M_GPI7,
+       },
+       /* DA9063 event D register */
+       [DA9063_IRQ_GPI8] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI8,
+       },
+       [DA9063_IRQ_GPI9] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI9,
+       },
+       [DA9063_IRQ_GPI10] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI10,
+       },
+       [DA9063_IRQ_GPI11] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI11,
+       },
+       [DA9063_IRQ_GPI12] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI12,
+       },
+       [DA9063_IRQ_GPI13] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI13,
+       },
+       [DA9063_IRQ_GPI14] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI14,
+       },
+       [DA9063_IRQ_GPI15] = {
+               .reg_offset = DA9063_REG_EVENT_D_OFFSET,
+               .mask = DA9063_M_GPI15,
+       },
+};
+
+static struct regmap_irq_chip da9063_irq_chip = {
+       .name = "da9063-irq",
+       .irqs = da9063_irqs,
+       .num_irqs = DA9063_NUM_IRQ,
+
+       .num_regs = 4,
+       .status_base = DA9063_REG_EVENT_A,
+       .mask_base = DA9063_REG_IRQ_MASK_A,
+       .ack_base = DA9063_REG_EVENT_A,
+       .init_ack_masked = true,
+};
+
+int da9063_irq_init(struct da9063 *da9063)
+{
+       int ret;
+
+       if (!da9063->chip_irq) {
+               dev_err(da9063->dev, "No IRQ configured\n");
+               return -EINVAL;
+       }
+
+       ret = regmap_add_irq_chip(da9063->regmap, da9063->chip_irq,
+                       IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
+                       da9063->irq_base, &da9063_irq_chip,
+                       &da9063->regmap_irq);
+       if (ret) {
+               dev_err(da9063->dev, "Failed to reguest IRQ %d: %d\n",
+                               da9063->chip_irq, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+void da9063_irq_exit(struct da9063 *da9063)
+{
+       regmap_del_irq_chip(da9063->chip_irq, da9063->regmap_irq);
+}
index fb64398506e9934725bba33d9b3dabe0e9b591fc..013ba8159dcda339a8f71729976afeffd9516873 100644 (file)
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/clk.h>
+#include <linux/regmap.h>
 
 #include <sound/pcm.h>
 
 #include <linux/mfd/davinci_voicecodec.h>
 
-u32 davinci_vc_read(struct davinci_vc *davinci_vc, int reg)
-{
-       return __raw_readl(davinci_vc->base + reg);
-}
-
-void davinci_vc_write(struct davinci_vc *davinci_vc,
-                                          int reg, u32 val)
-{
-       __raw_writel(val, davinci_vc->base + reg);
-}
+static struct regmap_config davinci_vc_regmap = {
+       .reg_bits = 32,
+       .val_bits = 32,
+};
 
 static int __init davinci_vc_probe(struct platform_device *pdev)
 {
@@ -74,6 +69,14 @@ static int __init davinci_vc_probe(struct platform_device *pdev)
                goto fail;
        }
 
+       davinci_vc->regmap = devm_regmap_init_mmio(&pdev->dev,
+                                                  davinci_vc->base,
+                                                  &davinci_vc_regmap);
+       if (IS_ERR(davinci_vc->regmap)) {
+               ret = PTR_ERR(davinci_vc->regmap);
+               goto fail;
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
        if (!res) {
                dev_err(&pdev->dev, "no DMA resource\n");
index 0d68eb1a5ec528924695959646a29a31d87ca1a8..53f371dcbb6e96550537b108fffbba1c00af3015 100644 (file)
@@ -465,7 +465,7 @@ static DEFINE_SPINLOCK(clk_mgt_lock);
 
 #define CLK_MGT_ENTRY(_name, _branch, _clk38div)[PRCMU_##_name] = \
        { (PRCM_##_name##_MGT), 0 , _branch, _clk38div}
-struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
+static struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
        CLK_MGT_ENTRY(SGACLK, PLL_DIV, false),
        CLK_MGT_ENTRY(UARTCLK, PLL_FIX, true),
        CLK_MGT_ENTRY(MSP02CLK, PLL_FIX, true),
@@ -2319,7 +2319,7 @@ unlock_and_return:
 /**
  * prcmu_ac_sleep_req - called when ARM no longer needs to talk to modem
  */
-void prcmu_ac_sleep_req()
+void prcmu_ac_sleep_req(void)
 {
        u32 val;
 
index 7710227d284e82f3ea98bd6dcf307abd177f71e9..7a55c0071fa8e9840b47420277673120547df191 100644 (file)
@@ -315,8 +315,8 @@ static int add_children(struct i2c_client *client)
        }
 
        /* MMC/SD inputs -- right after the last config input */
-       if (client->dev.platform_data) {
-               void (*mmcsd_setup)(unsigned) = client->dev.platform_data;
+       if (dev_get_platdata(&client->dev)) {
+               void (*mmcsd_setup)(unsigned) = dev_get_platdata(&client->dev);
 
                mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5);
        }
index 5502106ad5157dcf8c3a2648c29e949c1b60b7b2..7245b0c5b794be489d1c5d250c196c92e028a48f 100644 (file)
@@ -177,7 +177,7 @@ static void pcap_msr_work(struct work_struct *work)
 static void pcap_isr_work(struct work_struct *work)
 {
        struct pcap_chip *pcap = container_of(work, struct pcap_chip, isr_work);
-       struct pcap_platform_data *pdata = pcap->spi->dev.platform_data;
+       struct pcap_platform_data *pdata = dev_get_platdata(&pcap->spi->dev);
        u32 msr, isr, int_sel, service;
        int irq;
 
@@ -394,7 +394,7 @@ static int pcap_add_subdev(struct pcap_chip *pcap,
 static int ezx_pcap_remove(struct spi_device *spi)
 {
        struct pcap_chip *pcap = spi_get_drvdata(spi);
-       struct pcap_platform_data *pdata = spi->dev.platform_data;
+       struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev);
        int i, adc_irq;
 
        /* remove all registered subdevs */
@@ -420,7 +420,7 @@ static int ezx_pcap_remove(struct spi_device *spi)
 
 static int ezx_pcap_probe(struct spi_device *spi)
 {
-       struct pcap_platform_data *pdata = spi->dev.platform_data;
+       struct pcap_platform_data *pdata = dev_get_platdata(&spi->dev);
        struct pcap_chip *pcap;
        int i, adc_irq;
        int ret = -ENODEV;
index 26aca545084b38bc6373b85998410bd28392b1f6..49f39feca7843e73bce9e906953ed5620936a193 100644 (file)
@@ -261,7 +261,7 @@ static void egpio_write_cache(struct egpio_info *ei)
 
 static int __init egpio_probe(struct platform_device *pdev)
 {
-       struct htc_egpio_platform_data *pdata = pdev->dev.platform_data;
+       struct htc_egpio_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct resource   *res;
        struct egpio_info *ei;
        struct gpio_chip  *chip;
index c9dfce6ae0c289229bf895adb92d7a27e440ec8e..d7b2a75aca3e5fcd9b38de98ceb4f5c3b16f013e 100644 (file)
@@ -340,7 +340,7 @@ static int htcpld_setup_chip_irq(
        int ret = 0;
 
        /* Get the platform and driver data */
-       pdata = dev->platform_data;
+       pdata = dev_get_platdata(dev);
        htcpld = platform_get_drvdata(pdev);
        chip = &htcpld->chip[chip_index];
        plat_chip_data = &pdata->chip[chip_index];
@@ -375,7 +375,7 @@ static int htcpld_register_chip_i2c(
        struct i2c_board_info info;
 
        /* Get the platform and driver data */
-       pdata = dev->platform_data;
+       pdata = dev_get_platdata(dev);
        htcpld = platform_get_drvdata(pdev);
        chip = &htcpld->chip[chip_index];
        plat_chip_data = &pdata->chip[chip_index];
@@ -447,7 +447,7 @@ static int htcpld_register_chip_gpio(
        int ret = 0;
 
        /* Get the platform and driver data */
-       pdata = dev->platform_data;
+       pdata = dev_get_platdata(dev);
        htcpld = platform_get_drvdata(pdev);
        chip = &htcpld->chip[chip_index];
        plat_chip_data = &pdata->chip[chip_index];
@@ -509,7 +509,7 @@ static int htcpld_setup_chips(struct platform_device *pdev)
        int i;
 
        /* Get the platform and driver data */
-       pdata = dev->platform_data;
+       pdata = dev_get_platdata(dev);
        htcpld = platform_get_drvdata(pdev);
 
        /* Setup each chip's output GPIOs */
@@ -574,7 +574,7 @@ static int htcpld_core_probe(struct platform_device *pdev)
        if (!dev)
                return -ENODEV;
 
-       pdata = dev->platform_data;
+       pdata = dev_get_platdata(dev);
        if (!pdata) {
                dev_warn(dev, "Platform data not found for htcpld core!\n");
                return -ENXIO;
index 0a5e85fd8517c145a952183349ee7fbc310ad85b..6bf92a507b9546b911e258037c2dba3ac391851b 100644 (file)
@@ -126,7 +126,7 @@ static struct mfd_cell ds1wm_cell __initdata = {
 
 static int __init pasic3_probe(struct platform_device *pdev)
 {
-       struct pasic3_platform_data *pdata = pdev->dev.platform_data;
+       struct pasic3_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        struct pasic3_data *asic;
        struct resource *r;
index 4f2462f0963e6fac016f6cacbf917a012870eb46..9203d47cdbb1b4106e87ba91e4571cea54c55543 100644 (file)
@@ -310,7 +310,7 @@ EXPORT_SYMBOL_GPL(intel_msic_irq_read);
 static int intel_msic_init_devices(struct intel_msic *msic)
 {
        struct platform_device *pdev = msic->pdev;
-       struct intel_msic_platform_data *pdata = pdev->dev.platform_data;
+       struct intel_msic_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret, i;
 
        if (pdata->gpio) {
@@ -372,7 +372,7 @@ static void intel_msic_remove_devices(struct intel_msic *msic)
 
 static int intel_msic_probe(struct platform_device *pdev)
 {
-       struct intel_msic_platform_data *pdata = pdev->dev.platform_data;
+       struct intel_msic_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct intel_msic *msic;
        struct resource *res;
        u8 id0, id1;
index 686a4565acb6a6c3b5b3620cb96720014cb6e089..d3e23278d299021f34bab4aacbb361d117f5a40b 100644 (file)
@@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(kempld_write32);
  */
 void kempld_get_mutex(struct kempld_device_data *pld)
 {
-       struct kempld_platform_data *pdata = pld->dev->platform_data;
+       struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
        mutex_lock(&pld->lock);
        pdata->get_hardware_mutex(pld);
@@ -271,7 +271,7 @@ EXPORT_SYMBOL_GPL(kempld_get_mutex);
  */
 void kempld_release_mutex(struct kempld_device_data *pld)
 {
-       struct kempld_platform_data *pdata = pld->dev->platform_data;
+       struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
        pdata->release_hardware_mutex(pld);
        mutex_unlock(&pld->lock);
@@ -288,7 +288,7 @@ EXPORT_SYMBOL_GPL(kempld_release_mutex);
  */
 static int kempld_get_info(struct kempld_device_data *pld)
 {
-       struct kempld_platform_data *pdata = pld->dev->platform_data;
+       struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
        return pdata->get_info(pld);
 }
@@ -302,7 +302,7 @@ static int kempld_get_info(struct kempld_device_data *pld)
  */
 static int kempld_register_cells(struct kempld_device_data *pld)
 {
-       struct kempld_platform_data *pdata = pld->dev->platform_data;
+       struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
        return pdata->register_cells(pld);
 }
@@ -357,7 +357,7 @@ static int kempld_detect_device(struct kempld_device_data *pld)
 
 static int kempld_probe(struct platform_device *pdev)
 {
-       struct kempld_platform_data *pdata = pdev->dev.platform_data;
+       struct kempld_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct device *dev = &pdev->dev;
        struct kempld_device_data *pld;
        struct resource *ioport;
@@ -394,7 +394,7 @@ static int kempld_probe(struct platform_device *pdev)
 static int kempld_remove(struct platform_device *pdev)
 {
        struct kempld_device_data *pld = platform_get_drvdata(pdev);
-       struct kempld_platform_data *pdata = pld->dev->platform_data;
+       struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
 
        mfd_remove_devices(&pdev->dev);
        pdata->release_hardware_mutex(pld);
@@ -412,6 +412,15 @@ static struct platform_driver kempld_driver = {
 };
 
 static struct dmi_system_id __initdata kempld_dmi_table[] = {
+       {
+               .ident = "BHL6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       },
        {
                .ident = "CCR2",
                .matches = {
@@ -596,6 +605,15 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
                .driver_data = (void *)&kempld_platform_data_generic,
                .callback = kempld_create_platform_device,
        },
+       {
+               .ident = "UTH6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
index 4b7e6dac1de80ea22b556902d1f7896dbd7a6225..8c29f7b27324f4980e1b73f98b7186c10107120a 100644 (file)
@@ -384,7 +384,7 @@ static struct attribute_group lm3533_attribute_group = {
 
 static int lm3533_device_als_init(struct lm3533 *lm3533)
 {
-       struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
+       struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
        int ret;
 
        if (!pdata->als)
@@ -407,7 +407,7 @@ static int lm3533_device_als_init(struct lm3533 *lm3533)
 
 static int lm3533_device_bl_init(struct lm3533 *lm3533)
 {
-       struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
+       struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
        int i;
        int ret;
 
@@ -436,7 +436,7 @@ static int lm3533_device_bl_init(struct lm3533 *lm3533)
 
 static int lm3533_device_led_init(struct lm3533 *lm3533)
 {
-       struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
+       struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
        int i;
        int ret;
 
@@ -481,7 +481,7 @@ static int lm3533_device_setup(struct lm3533 *lm3533,
 
 static int lm3533_device_init(struct lm3533 *lm3533)
 {
-       struct lm3533_platform_data *pdata = lm3533->dev->platform_data;
+       struct lm3533_platform_data *pdata = dev_get_platdata(lm3533->dev);
        int ret;
 
        dev_dbg(lm3533->dev, "%s\n", __func__);
index c3d3c9b4d3addedc53bc5b7450cd45a2e4707a72..0f1221911018b6d4fd4e558ff0df4996a4b70a10 100644 (file)
@@ -173,7 +173,7 @@ static const struct regmap_config lp8788_regmap_config = {
 static int lp8788_probe(struct i2c_client *cl, const struct i2c_device_id *id)
 {
        struct lp8788 *lp;
-       struct lp8788_platform_data *pdata = cl->dev.platform_data;
+       struct lp8788_platform_data *pdata = dev_get_platdata(&cl->dev);
        int ret;
 
        lp = devm_kzalloc(&cl->dev, sizeof(struct lp8788), GFP_KERNEL);
index 24033324c17a08437d3e62e3b1fa705c53f5de53..9483bc8472a51acbbc45a3f08b6072104a81e027 100644 (file)
@@ -213,7 +213,7 @@ enum lpc_chipsets {
        LPC_COLETO,     /* Coleto Creek */
 };
 
-struct lpc_ich_info lpc_chipset_info[] = {
+static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_ICH] = {
                .name = "ICH",
                .iTCO_version = 1,
index f27a21831583b2e94e06424384deee76f916e03a..522be67b2e682d743c36534005fb09737cfcf590 100644 (file)
@@ -77,7 +77,7 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
        struct max77686_dev *max77686 = NULL;
-       struct max77686_platform_data *pdata = i2c->dev.platform_data;
+       struct max77686_platform_data *pdata = dev_get_platdata(&i2c->dev);
        unsigned int data;
        int ret = 0;
 
index 9e60fed5ff82a81dbf774c7d8af7547f12861516..c04723efc70709d4dd81db288be1fa11fc6deccb 100644 (file)
@@ -110,7 +110,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
        struct max77693_dev *max77693;
-       struct max77693_platform_data *pdata = i2c->dev.platform_data;
+       struct max77693_platform_data *pdata = dev_get_platdata(&i2c->dev);
        u8 reg_data;
        int ret = 0;
 
index 8042b3205eaaf450b3a46b2e657bd5445350c8b1..de7fb80a60528e8f3bcbc2c45e934dcfa5a65181 100644 (file)
@@ -151,7 +151,7 @@ static int max8925_dt_init(struct device_node *np, struct device *dev,
 static int max8925_probe(struct i2c_client *client,
                                   const struct i2c_device_id *id)
 {
-       struct max8925_platform_data *pdata = client->dev.platform_data;
+       struct max8925_platform_data *pdata = dev_get_platdata(&client->dev);
        static struct max8925_chip *chip;
        struct device_node *node = client->dev.of_node;
 
index 14714058f2d2a673e5b678d950e6184454a189bf..cee098c0dae36ef4ef9baf9d3fb07ec11e24913f 100644 (file)
@@ -51,7 +51,7 @@ static struct mfd_cell max8997_devs[] = {
 
 #ifdef CONFIG_OF
 static struct of_device_id max8997_pmic_dt_match[] = {
-       { .compatible = "maxim,max8997-pmic", .data = TYPE_MAX8997 },
+       { .compatible = "maxim,max8997-pmic", .data = (void *)TYPE_MAX8997 },
        {},
 };
 #endif
@@ -188,10 +188,11 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct max8997_dev *max8997;
-       struct max8997_platform_data *pdata = i2c->dev.platform_data;
+       struct max8997_platform_data *pdata = dev_get_platdata(&i2c->dev);
        int ret = 0;
 
-       max8997 = kzalloc(sizeof(struct max8997_dev), GFP_KERNEL);
+       max8997 = devm_kzalloc(&i2c->dev, sizeof(struct max8997_dev),
+                               GFP_KERNEL);
        if (max8997 == NULL)
                return -ENOMEM;
 
@@ -203,14 +204,12 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
 
        if (max8997->dev->of_node) {
                pdata = max8997_i2c_parse_dt_pdata(max8997->dev);
-               if (IS_ERR(pdata)) {
-                       ret = PTR_ERR(pdata);
-                       goto err;
-               }
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
        }
 
        if (!pdata)
-               goto err;
+               return ret;
 
        max8997->pdata = pdata;
        max8997->ono = pdata->ono;
@@ -250,8 +249,6 @@ err_mfd:
        i2c_unregister_device(max8997->muic);
        i2c_unregister_device(max8997->haptic);
        i2c_unregister_device(max8997->rtc);
-err:
-       kfree(max8997);
        return ret;
 }
 
@@ -263,7 +260,6 @@ static int max8997_i2c_remove(struct i2c_client *i2c)
        i2c_unregister_device(max8997->muic);
        i2c_unregister_device(max8997->haptic);
        i2c_unregister_device(max8997->rtc);
-       kfree(max8997);
 
        return 0;
 }
index 21af51a499f4af42f657a25a4f134437b4892b4e..fe6332dcabee891a27daed80e3ed2525e3b1caa8 100644 (file)
@@ -184,11 +184,12 @@ static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c,
 static int max8998_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct max8998_platform_data *pdata = i2c->dev.platform_data;
+       struct max8998_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct max8998_dev *max8998;
        int ret = 0;
 
-       max8998 = kzalloc(sizeof(struct max8998_dev), GFP_KERNEL);
+       max8998 = devm_kzalloc(&i2c->dev, sizeof(struct max8998_dev),
+                               GFP_KERNEL);
        if (max8998 == NULL)
                return -ENOMEM;
 
@@ -246,7 +247,6 @@ err:
        mfd_remove_devices(max8998->dev);
        max8998_irq_exit(max8998);
        i2c_unregister_device(max8998->rtc);
-       kfree(max8998);
        return ret;
 }
 
@@ -257,7 +257,6 @@ static int max8998_i2c_remove(struct i2c_client *i2c)
        mfd_remove_devices(max8998->dev);
        max8998_irq_exit(max8998);
        i2c_unregister_device(max8998->rtc);
-       kfree(max8998);
 
        return 0;
 }
index 13198d937e3657ae63717c30ffe602519a92f2c5..41c31b3ac94059e4dacf21565d3d411cd37da371 100644 (file)
@@ -156,7 +156,7 @@ static struct mcp_ops mcp_sa11x0 = {
 
 static int mcp_sa11x0_probe(struct platform_device *dev)
 {
-       struct mcp_plat_data *data = dev->dev.platform_data;
+       struct mcp_plat_data *data = dev_get_platdata(&dev->dev);
        struct resource *mem0, *mem1;
        struct mcp_sa11x0 *m;
        struct mcp *mcp;
index 998ce8cb3065a5a68dc2c09289e13e68826c341b..ad25bfa3fb02cf76ee6c1afcbe3cd8fcecbd49e5 100644 (file)
@@ -442,7 +442,7 @@ void menelaus_unregister_mmc_callback(void)
        menelaus_remove_irq_work(MENELAUS_MMC_S2D1_IRQ);
 
        the_menelaus->mmc_callback = NULL;
-       the_menelaus->mmc_callback_data = 0;
+       the_menelaus->mmc_callback_data = NULL;
 }
 EXPORT_SYMBOL(menelaus_unregister_mmc_callback);
 
@@ -466,7 +466,7 @@ static int menelaus_set_voltage(const struct menelaus_vtg *vtg, int mV,
        struct i2c_client *c = the_menelaus->client;
 
        mutex_lock(&the_menelaus->lock);
-       if (vtg == 0)
+       if (!vtg)
                goto set_voltage;
 
        ret = menelaus_read_reg(vtg->vtg_reg);
@@ -1189,7 +1189,7 @@ static int menelaus_probe(struct i2c_client *client,
        int                     rev = 0, val;
        int                     err = 0;
        struct menelaus_platform_data *menelaus_pdata =
-                                       client->dev.platform_data;
+                                       dev_get_platdata(&client->dev);
 
        if (the_menelaus) {
                dev_dbg(&client->dev, "only one %s for now\n",
@@ -1197,7 +1197,7 @@ static int menelaus_probe(struct i2c_client *client,
                return -ENODEV;
        }
 
-       menelaus = kzalloc(sizeof *menelaus, GFP_KERNEL);
+       menelaus = devm_kzalloc(&client->dev, sizeof(*menelaus), GFP_KERNEL);
        if (!menelaus)
                return -ENOMEM;
 
@@ -1210,8 +1210,7 @@ static int menelaus_probe(struct i2c_client *client,
        rev = menelaus_read_reg(MENELAUS_REV);
        if (rev < 0) {
                pr_err(DRIVER_NAME ": device not found");
-               err = -ENODEV;
-               goto fail1;
+               return -ENODEV;
        }
 
        /* Ack and disable all Menelaus interrupts */
@@ -1231,7 +1230,7 @@ static int menelaus_probe(struct i2c_client *client,
                if (err) {
                        dev_dbg(&client->dev,  "can't get IRQ %d, err %d\n",
                                        client->irq, err);
-                       goto fail1;
+                       return err;
                }
        }
 
@@ -1242,7 +1241,7 @@ static int menelaus_probe(struct i2c_client *client,
 
        val = menelaus_read_reg(MENELAUS_VCORE_CTRL1);
        if (val < 0)
-               goto fail2;
+               goto fail;
        if (val & (1 << 7))
                menelaus->vcore_hw_mode = 1;
        else
@@ -1251,17 +1250,15 @@ static int menelaus_probe(struct i2c_client *client,
        if (menelaus_pdata != NULL && menelaus_pdata->late_init != NULL) {
                err = menelaus_pdata->late_init(&client->dev);
                if (err < 0)
-                       goto fail2;
+                       goto fail;
        }
 
        menelaus_rtc_init(menelaus);
 
        return 0;
-fail2:
+fail:
        free_irq(client->irq, menelaus);
        flush_work(&menelaus->work);
-fail1:
-       kfree(menelaus);
        return err;
 }
 
@@ -1271,7 +1268,6 @@ static int __exit menelaus_remove(struct i2c_client *client)
 
        free_irq(client->irq, menelaus);
        flush_work(&menelaus->work);
-       kfree(menelaus);
        the_menelaus = NULL;
        return 0;
 }
index 7604f4e5df40a10e03693407da38cb82ea3de14b..f421586f29fb09b02644ee8b05aa6777fb353835 100644 (file)
@@ -96,6 +96,8 @@ static int mfd_add_device(struct device *parent, int id,
 
        pdev->dev.parent = parent;
        pdev->dev.type = &mfd_dev_type;
+       pdev->dev.dma_mask = parent->dma_mask;
+       pdev->dev.dma_parms = parent->dma_parms;
 
        if (parent->of_node && cell->of_compatible) {
                for_each_child_of_node(parent->of_node, np) {
index 759fae3ca7fb0dba592ab808d036f889bf96f922..29ee54d68512e3ce38dad4b5d6897f192b8295f8 100644 (file)
@@ -114,7 +114,7 @@ struct usbhs_hcd_omap {
 };
 /*-------------------------------------------------------------------------*/
 
-const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
+static const char usbhs_driver_name[] = USBHS_DRIVER_NAME;
 static u64 usbhs_dmamask = DMA_BIT_MASK(32);
 
 /*-------------------------------------------------------------------------*/
@@ -232,7 +232,7 @@ err_end:
 static int omap_usbhs_alloc_children(struct platform_device *pdev)
 {
        struct device                           *dev = &pdev->dev;
-       struct usbhs_omap_platform_data         *pdata = dev->platform_data;
+       struct usbhs_omap_platform_data         *pdata = dev_get_platdata(dev);
        struct platform_device                  *ehci;
        struct platform_device                  *ohci;
        struct resource                         *res;
@@ -571,7 +571,7 @@ static struct of_device_id usbhs_child_match_table[] = {
 static int usbhs_omap_probe(struct platform_device *pdev)
 {
        struct device                   *dev =  &pdev->dev;
-       struct usbhs_omap_platform_data *pdata = dev->platform_data;
+       struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev);
        struct usbhs_hcd_omap           *omap;
        struct resource                 *res;
        int                             ret = 0;
index e4d1c706df8b9d1cf6a5f9f2f835cc652097789b..135afabe4ae2ae850a6897ddad06dc1969dba301 100644 (file)
 #include <linux/mfd/palmas.h>
 #include <linux/of_device.h>
 
+#define PALMAS_EXT_REQ (PALMAS_EXT_CONTROL_ENABLE1 |   \
+                       PALMAS_EXT_CONTROL_ENABLE2 |    \
+                       PALMAS_EXT_CONTROL_NSLEEP)
+
+struct palmas_sleep_requestor_info {
+       int id;
+       int reg_offset;
+       int bit_pos;
+};
+
+#define EXTERNAL_REQUESTOR(_id, _offset, _pos)         \
+       [PALMAS_EXTERNAL_REQSTR_ID_##_id] = {           \
+               .id = PALMAS_EXTERNAL_REQSTR_ID_##_id,  \
+               .reg_offset = _offset,                  \
+               .bit_pos = _pos,                        \
+       }
+
+static struct palmas_sleep_requestor_info sleep_req_info[] = {
+       EXTERNAL_REQUESTOR(REGEN1, 0, 0),
+       EXTERNAL_REQUESTOR(REGEN2, 0, 1),
+       EXTERNAL_REQUESTOR(SYSEN1, 0, 2),
+       EXTERNAL_REQUESTOR(SYSEN2, 0, 3),
+       EXTERNAL_REQUESTOR(CLK32KG, 0, 4),
+       EXTERNAL_REQUESTOR(CLK32KGAUDIO, 0, 5),
+       EXTERNAL_REQUESTOR(REGEN3, 0, 6),
+       EXTERNAL_REQUESTOR(SMPS12, 1, 0),
+       EXTERNAL_REQUESTOR(SMPS3, 1, 1),
+       EXTERNAL_REQUESTOR(SMPS45, 1, 2),
+       EXTERNAL_REQUESTOR(SMPS6, 1, 3),
+       EXTERNAL_REQUESTOR(SMPS7, 1, 4),
+       EXTERNAL_REQUESTOR(SMPS8, 1, 5),
+       EXTERNAL_REQUESTOR(SMPS9, 1, 6),
+       EXTERNAL_REQUESTOR(SMPS10, 1, 7),
+       EXTERNAL_REQUESTOR(LDO1, 2, 0),
+       EXTERNAL_REQUESTOR(LDO2, 2, 1),
+       EXTERNAL_REQUESTOR(LDO3, 2, 2),
+       EXTERNAL_REQUESTOR(LDO4, 2, 3),
+       EXTERNAL_REQUESTOR(LDO5, 2, 4),
+       EXTERNAL_REQUESTOR(LDO6, 2, 5),
+       EXTERNAL_REQUESTOR(LDO7, 2, 6),
+       EXTERNAL_REQUESTOR(LDO8, 2, 7),
+       EXTERNAL_REQUESTOR(LDO9, 3, 0),
+       EXTERNAL_REQUESTOR(LDOLN, 3, 1),
+       EXTERNAL_REQUESTOR(LDOUSB, 3, 2),
+};
+
 static const struct regmap_config palmas_regmap_config[PALMAS_NUM_CLIENTS] = {
        {
                .reg_bits = 8,
@@ -186,6 +232,57 @@ static struct regmap_irq_chip palmas_irq_chip = {
                        PALMAS_INT1_MASK),
 };
 
+int palmas_ext_control_req_config(struct palmas *palmas,
+       enum palmas_external_requestor_id id,  int ext_ctrl, bool enable)
+{
+       int preq_mask_bit = 0;
+       int reg_add = 0;
+       int bit_pos;
+       int ret;
+
+       if (!(ext_ctrl & PALMAS_EXT_REQ))
+               return 0;
+
+       if (id >= PALMAS_EXTERNAL_REQSTR_ID_MAX)
+               return 0;
+
+       if (ext_ctrl & PALMAS_EXT_CONTROL_NSLEEP) {
+               reg_add = PALMAS_NSLEEP_RES_ASSIGN;
+               preq_mask_bit = 0;
+       } else if (ext_ctrl & PALMAS_EXT_CONTROL_ENABLE1) {
+               reg_add = PALMAS_ENABLE1_RES_ASSIGN;
+               preq_mask_bit = 1;
+       } else if (ext_ctrl & PALMAS_EXT_CONTROL_ENABLE2) {
+               reg_add = PALMAS_ENABLE2_RES_ASSIGN;
+               preq_mask_bit = 2;
+       }
+
+       bit_pos = sleep_req_info[id].bit_pos;
+       reg_add += sleep_req_info[id].reg_offset;
+       if (enable)
+               ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
+                               reg_add, BIT(bit_pos), BIT(bit_pos));
+       else
+               ret = palmas_update_bits(palmas, PALMAS_RESOURCE_BASE,
+                               reg_add, BIT(bit_pos), 0);
+       if (ret < 0) {
+               dev_err(palmas->dev, "Resource reg 0x%02x update failed %d\n",
+                       reg_add, ret);
+               return ret;
+       }
+
+       /* Unmask the PREQ */
+       ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
+                       PALMAS_POWER_CTRL, BIT(preq_mask_bit), 0);
+       if (ret < 0) {
+               dev_err(palmas->dev, "POWER_CTRL register update failed %d\n",
+                       ret);
+               return ret;
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(palmas_ext_control_req_config);
+
 static int palmas_set_pdata_irq_flag(struct i2c_client *i2c,
                struct palmas_platform_data *pdata)
 {
@@ -229,6 +326,32 @@ static void palmas_dt_to_pdata(struct i2c_client *i2c,
                                        PALMAS_POWER_CTRL_ENABLE2_MASK;
        if (i2c->irq)
                palmas_set_pdata_irq_flag(i2c, pdata);
+
+       pdata->pm_off = of_property_read_bool(node,
+                       "ti,system-power-controller");
+}
+
+static struct palmas *palmas_dev;
+static void palmas_power_off(void)
+{
+       unsigned int addr;
+       int ret, slave;
+
+       if (!palmas_dev)
+               return;
+
+       slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE);
+       addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL);
+
+       ret = regmap_update_bits(
+                       palmas_dev->regmap[slave],
+                       addr,
+                       PALMAS_DEV_CTRL_DEV_ON,
+                       0);
+
+       if (ret)
+               pr_err("%s: Unable to write to DEV_CTRL_DEV_ON: %d\n",
+                               __func__, ret);
 }
 
 static unsigned int palmas_features = PALMAS_PMIC_FEATURE_SMPS10_BOOST;
@@ -423,10 +546,13 @@ no_irq:
         */
        if (node) {
                ret = of_platform_populate(node, NULL, NULL, &i2c->dev);
-               if (ret < 0)
+               if (ret < 0) {
                        goto err_irq;
-               else
+               } else if (pdata->pm_off && !pm_power_off) {
+                       palmas_dev = palmas;
+                       pm_power_off = palmas_power_off;
                        return ret;
+               }
        }
 
        return ret;
index 18b53cb72feae4984b44b6cea94c2f6d68fc3e40..b8941a556d7195e884e1f85d3e7017e89275a3f5 100644 (file)
@@ -203,7 +203,7 @@ static int pcf50633_adc_probe(struct platform_device *pdev)
 {
        struct pcf50633_adc *adc;
 
-       adc = kzalloc(sizeof(*adc), GFP_KERNEL);
+       adc = devm_kzalloc(&pdev->dev, sizeof(*adc), GFP_KERNEL);
        if (!adc)
                return -ENOMEM;
 
@@ -236,7 +236,6 @@ static int pcf50633_adc_remove(struct platform_device *pdev)
                kfree(adc->queue[i]);
 
        mutex_unlock(&adc->queue_mutex);
-       kfree(adc);
 
        return 0;
 }
index d11567307fbed6c930f955abf198de1157dfb237..6841d6805fd64a6aaab032ce121d4e3c63b36443 100644 (file)
@@ -195,7 +195,7 @@ static int pcf50633_probe(struct i2c_client *client,
                                const struct i2c_device_id *ids)
 {
        struct pcf50633 *pcf;
-       struct pcf50633_platform_data *pdata = client->dev.platform_data;
+       struct pcf50633_platform_data *pdata = dev_get_platdata(&client->dev);
        int i, ret;
        int version, variant;
 
index ecc137ffa8c3c6369592a5cea5ecd987f9deeed4..a6841f77aa5e709d472b120336e25e5572646cf8 100644 (file)
@@ -14,6 +14,7 @@
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/err.h>
@@ -106,7 +107,7 @@ static int pm8921_add_subdevices(const struct pm8921_platform_data
 
 static int pm8921_probe(struct platform_device *pdev)
 {
-       const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
+       const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct pm8921 *pmic;
        int rc;
        u8 val;
@@ -117,7 +118,7 @@ static int pm8921_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       pmic = kzalloc(sizeof(struct pm8921), GFP_KERNEL);
+       pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL);
        if (!pmic) {
                pr_err("Cannot alloc pm8921 struct\n");
                return -ENOMEM;
@@ -127,7 +128,7 @@ static int pm8921_probe(struct platform_device *pdev)
        rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
        if (rc) {
                pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
-               goto err_read_rev;
+               return rc;
        }
        pr_info("PMIC revision 1: %02X\n", val);
        rev = val;
@@ -137,7 +138,7 @@ static int pm8921_probe(struct platform_device *pdev)
        if (rc) {
                pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
                        REG_HWREV_2, rc);
-               goto err_read_rev;
+               return rc;
        }
        pr_info("PMIC revision 2: %02X\n", val);
        rev |= val << BITS_PER_BYTE;
@@ -159,9 +160,6 @@ static int pm8921_probe(struct platform_device *pdev)
 
 err:
        mfd_remove_devices(pmic->dev);
-       platform_set_drvdata(pdev, NULL);
-err_read_rev:
-       kfree(pmic);
        return rc;
 }
 
@@ -179,8 +177,6 @@ static int pm8921_remove(struct platform_device *pdev)
                pm8xxx_irq_exit(pmic->irq_chip);
                pmic->irq_chip = NULL;
        }
-       platform_set_drvdata(pdev, NULL);
-       kfree(pmic);
 
        return 0;
 }
index 14bdaccefbeca4da3099ab804e807da6f190843f..346330176afcd81ba9f6a294420db761e60ab908 100644 (file)
@@ -250,7 +250,7 @@ static int rc5t583_i2c_probe(struct i2c_client *i2c,
                              const struct i2c_device_id *id)
 {
        struct rc5t583 *rc5t583;
-       struct rc5t583_platform_data *pdata = i2c->dev.platform_data;
+       struct rc5t583_platform_data *pdata = dev_get_platdata(&i2c->dev);
        int ret;
        bool irq_init_success = false;
 
index c436bf27e78d232340825ad12bf9d493d9ae26a2..52801351864d684e094ec59b60ec797cf4ffcc27 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,7 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
+ *   Roger Tseng <rogerable@realtek.com>
  */
 
 #include <linux/module.h>
@@ -47,19 +47,77 @@ static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
                return 0;
 }
 
+static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+       u32 reg1;
+       u8 reg3;
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg1);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1);
+
+       if (!rtsx_vendor_setting_valid(reg1))
+               return;
+
+       pcr->aspm_en = rtsx_reg_to_aspm(reg1);
+       pcr->sd30_drive_sel_1v8 =
+               map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg1));
+       pcr->card_drive_sel &= 0x3F;
+       pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1);
+
+       rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, &reg3);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3);
+       pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3);
+}
+
+static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+       u32 reg;
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+       if (!rtsx_vendor_setting_valid(reg))
+               return;
+
+       pcr->aspm_en = rtsx_reg_to_aspm(reg);
+       pcr->sd30_drive_sel_1v8 =
+               map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
+       pcr->sd30_drive_sel_3v3 =
+               map_sd_drive(rtl8411b_reg_to_sd30_drive_sel_3v3(reg));
+}
+
+static void rtl8411_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
+}
+
 static int rtl8411_extra_init_hw(struct rtsx_pcr *pcr)
 {
-       return rtsx_pci_write_register(pcr, CD_PAD_CTL,
+       rtsx_pci_init_cmd(pcr);
+
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+                       0xFF, pcr->sd30_drive_sel_3v3);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL,
                        CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
+
+       return rtsx_pci_send_cmd(pcr, 100);
 }
 
 static int rtl8411b_extra_init_hw(struct rtsx_pcr *pcr)
 {
-       if (rtl8411b_is_qfn48(pcr))
-               rtsx_pci_write_register(pcr, CARD_PULL_CTL3, 0xFF, 0xF5);
+       rtsx_pci_init_cmd(pcr);
 
-       return rtsx_pci_write_register(pcr, CD_PAD_CTL,
+       if (rtl8411b_is_qfn48(pcr))
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               CARD_PULL_CTL3, 0xFF, 0xF5);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+                       0xFF, pcr->sd30_drive_sel_3v3);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CD_PAD_CTL,
                        CD_DISABLE_MASK | CD_AUTO_DISABLE, CD_ENABLE);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, FUNC_FORCE_CTL,
+                       0x06, 0x00);
+
+       return rtsx_pci_send_cmd(pcr, 100);
 }
 
 static int rtl8411_turn_on_led(struct rtsx_pcr *pcr)
@@ -141,13 +199,13 @@ static int rtl8411_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
        mask = (BPP_REG_TUNED18 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_MASK;
        if (voltage == OUTPUT_3V3) {
                err = rtsx_pci_write_register(pcr,
-                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+                               SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
                if (err < 0)
                        return err;
                val = (BPP_ASIC_3V3 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_3V3;
        } else if (voltage == OUTPUT_1V8) {
                err = rtsx_pci_write_register(pcr,
-                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+                               SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
                if (err < 0)
                        return err;
                val = (BPP_ASIC_1V8 << BPP_TUNED18_SHIFT_8411) | BPP_PAD_1V8;
@@ -222,6 +280,7 @@ static int rtl8411_conv_clk_and_div_n(int input, int dir)
 }
 
 static const struct pcr_ops rtl8411_pcr_ops = {
+       .fetch_vendor_settings = rtl8411_fetch_vendor_settings,
        .extra_init_hw = rtl8411_extra_init_hw,
        .optimize_phy = NULL,
        .turn_on_led = rtl8411_turn_on_led,
@@ -233,9 +292,11 @@ static const struct pcr_ops rtl8411_pcr_ops = {
        .switch_output_voltage = rtl8411_switch_output_voltage,
        .cd_deglitch = rtl8411_cd_deglitch,
        .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+       .force_power_down = rtl8411_force_power_down,
 };
 
 static const struct pcr_ops rtl8411b_pcr_ops = {
+       .fetch_vendor_settings = rtl8411b_fetch_vendor_settings,
        .extra_init_hw = rtl8411b_extra_init_hw,
        .optimize_phy = NULL,
        .turn_on_led = rtl8411_turn_on_led,
@@ -247,6 +308,7 @@ static const struct pcr_ops rtl8411b_pcr_ops = {
        .switch_output_voltage = rtl8411_switch_output_voltage,
        .cd_deglitch = rtl8411_cd_deglitch,
        .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n,
+       .force_power_down = rtl8411_force_power_down,
 };
 
 /* SD Pull Control Enable:
@@ -385,6 +447,14 @@ void rtl8411_init_params(struct rtsx_pcr *pcr)
        pcr->num_slots = 2;
        pcr->ops = &rtl8411_pcr_ops;
 
+       pcr->flags = 0;
+       pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT;
+       pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+       pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+       pcr->aspm_en = ASPM_L1_EN;
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14);
+       pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10);
+
        pcr->ic_version = rtl8411_get_ic_version(pcr);
        pcr->sd_pull_ctl_enable_tbl = rtl8411_sd_pull_ctl_enable_tbl;
        pcr->sd_pull_ctl_disable_tbl = rtl8411_sd_pull_ctl_disable_tbl;
@@ -398,6 +468,14 @@ void rtl8411b_init_params(struct rtsx_pcr *pcr)
        pcr->num_slots = 2;
        pcr->ops = &rtl8411b_pcr_ops;
 
+       pcr->flags = 0;
+       pcr->card_drive_sel = RTL8411_CARD_DRIVE_DEFAULT;
+       pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+       pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+       pcr->aspm_en = ASPM_L1_EN;
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(23, 7, 14);
+       pcr->rx_initial_phase = SET_CLOCK_PHASE(4, 3, 10);
+
        pcr->ic_version = rtl8411_get_ic_version(pcr);
 
        if (rtl8411b_is_qfn48(pcr)) {
index ec78d9fb08791a9975a825411b6d7a8049f5d801..cb04174a8924b0279fccb697706f9227b6869e15 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/module.h>
@@ -34,19 +33,34 @@ static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr)
        return val & 0x0F;
 }
 
-static void rts5209_init_vendor_cfg(struct rtsx_pcr *pcr)
+static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
 {
-       u32 val;
+       u32 reg;
 
-       rtsx_pci_read_config_dword(pcr, 0x724, &val);
-       dev_dbg(&(pcr->pci->dev), "Cfg 0x724: 0x%x\n", val);
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
 
-       if (!(val & 0x80)) {
-               if (val & 0x08)
-                       pcr->ms_pmos = false;
-               else
-                       pcr->ms_pmos = true;
+       if (rts5209_vendor_setting1_valid(reg)) {
+               if (rts5209_reg_check_ms_pmos(reg))
+                       pcr->flags |= PCR_MS_PMOS;
+               pcr->aspm_en = rts5209_reg_to_aspm(reg);
        }
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+
+       if (rts5209_vendor_setting2_valid(reg)) {
+               pcr->sd30_drive_sel_1v8 =
+                       rts5209_reg_to_sd30_drive_sel_1v8(reg);
+               pcr->sd30_drive_sel_3v3 =
+                       rts5209_reg_to_sd30_drive_sel_3v3(reg);
+               pcr->card_drive_sel = rts5209_reg_to_card_drive_sel(reg);
+       }
+}
+
+static void rts5209_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       rtsx_pci_write_register(pcr, FPDCTL, 0x07, 0x07);
 }
 
 static int rts5209_extra_init_hw(struct rtsx_pcr *pcr)
@@ -55,8 +69,15 @@ static int rts5209_extra_init_hw(struct rtsx_pcr *pcr)
 
        /* Turn off LED */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO, 0xFF, 0x03);
+       /* Reset ASPM state to default value */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
+       /* Force CLKREQ# PIN to drive 0 to request clock */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
        /* Configure GPIO as output */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_GPIO_DIR, 0xFF, 0x03);
+       /* Configure driving */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+                       0xFF, pcr->sd30_drive_sel_3v3);
 
        return rtsx_pci_send_cmd(pcr, 100);
 }
@@ -95,7 +116,7 @@ static int rts5209_card_power_on(struct rtsx_pcr *pcr, int card)
        partial_pwr_on = SD_PARTIAL_POWER_ON;
        pwr_on = SD_POWER_ON;
 
-       if (pcr->ms_pmos && (card == RTSX_MS_CARD)) {
+       if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
                pwr_mask = MS_POWER_MASK;
                partial_pwr_on = MS_PARTIAL_POWER_ON;
                pwr_on = MS_POWER_ON;
@@ -131,7 +152,7 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card)
        pwr_mask = SD_POWER_MASK;
        pwr_off = SD_POWER_OFF;
 
-       if (pcr->ms_pmos && (card == RTSX_MS_CARD)) {
+       if ((pcr->flags & PCR_MS_PMOS) && (card == RTSX_MS_CARD)) {
                pwr_mask = MS_POWER_MASK;
                pwr_off = MS_POWER_OFF;
        }
@@ -140,7 +161,7 @@ static int rts5209_card_power_off(struct rtsx_pcr *pcr, int card)
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_PWR_CTL,
                        pwr_mask | PMOS_STRG_MASK, pwr_off | PMOS_STRG_400mA);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-                       LDO3318_PWR_MASK, 0X06);
+                       LDO3318_PWR_MASK, 0x06);
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
@@ -150,7 +171,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 
        if (voltage == OUTPUT_3V3) {
                err = rtsx_pci_write_register(pcr,
-                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+                               SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
                if (err < 0)
                        return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
@@ -158,7 +179,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
                        return err;
        } else if (voltage == OUTPUT_1V8) {
                err = rtsx_pci_write_register(pcr,
-                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+                               SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
                if (err < 0)
                        return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
@@ -172,6 +193,7 @@ static int rts5209_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 }
 
 static const struct pcr_ops rts5209_pcr_ops = {
+       .fetch_vendor_settings = rts5209_fetch_vendor_settings,
        .extra_init_hw = rts5209_extra_init_hw,
        .optimize_phy = rts5209_optimize_phy,
        .turn_on_led = rts5209_turn_on_led,
@@ -183,6 +205,7 @@ static const struct pcr_ops rts5209_pcr_ops = {
        .switch_output_voltage = rts5209_switch_output_voltage,
        .cd_deglitch = NULL,
        .conv_clk_and_div_n = NULL,
+       .force_power_down = rts5209_force_power_down,
 };
 
 /* SD Pull Control Enable:
@@ -242,7 +265,13 @@ void rts5209_init_params(struct rtsx_pcr *pcr)
        pcr->num_slots = 2;
        pcr->ops = &rts5209_pcr_ops;
 
-       rts5209_init_vendor_cfg(pcr);
+       pcr->flags = 0;
+       pcr->card_drive_sel = RTS5209_CARD_DRIVE_DEFAULT;
+       pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+       pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+       pcr->aspm_en = ASPM_L1_EN;
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 16);
+       pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
 
        pcr->ic_version = rts5209_get_ic_version(pcr);
        pcr->sd_pull_ctl_enable_tbl = rts5209_sd_pull_ctl_enable_tbl;
index 164b7faa70c9daf3f3cb69d1cf810d071b6ce8ee..9c8eec80ceed53bef339da4c9778ea224c1b9c99 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
- *
  *   Roger Tseng <rogerable@realtek.com>
- *   No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
  */
 
 #include <linux/module.h>
 
 #include "rtsx_pcr.h"
 
+static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
+{
+       u8 driving_3v3[4][3] = {
+               {0x13, 0x13, 0x13},
+               {0x96, 0x96, 0x96},
+               {0x7F, 0x7F, 0x7F},
+               {0x96, 0x96, 0x96},
+       };
+       u8 driving_1v8[4][3] = {
+               {0x99, 0x99, 0x99},
+               {0xAA, 0xAA, 0xAA},
+               {0xFE, 0xFE, 0xFE},
+               {0xB3, 0xB3, 0xB3},
+       };
+       u8 (*driving)[3], drive_sel;
+
+       if (voltage == OUTPUT_3V3) {
+               driving = driving_3v3;
+               drive_sel = pcr->sd30_drive_sel_3v3;
+       } else {
+               driving = driving_1v8;
+               drive_sel = pcr->sd30_drive_sel_1v8;
+       }
+
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
+                       0xFF, driving[drive_sel][0]);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
+                       0xFF, driving[drive_sel][1]);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
+                       0xFF, driving[drive_sel][2]);
+}
+
+static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+       u32 reg;
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+       if (!rtsx_vendor_setting_valid(reg))
+               return;
+
+       pcr->aspm_en = rtsx_reg_to_aspm(reg);
+       pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
+       pcr->card_drive_sel &= 0x3F;
+       pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+       pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
+       if (rtsx_reg_check_reverse_socket(reg))
+               pcr->flags |= PCR_REVERSE_SOCKET;
+}
+
+static void rts5227_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       /* Set relink_time to 0 */
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
+
+       if (pm_state == HOST_ENTER_S3)
+               rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10);
+
+       rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
+}
+
 static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
 {
        u16 cap;
@@ -37,6 +101,8 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
 
        /* Configure GPIO as output */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+       /* Reset ASPM state to default value */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
        /* Switch LDO3318 source from DV33 to card_3v3 */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
@@ -48,17 +114,16 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LTR_CTL, 0xFF, 0xA3);
        /* Configure OBFF */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OBFF_CFG, 0x03, 0x03);
-       /* Configure force_clock_req
-        * Maybe We should define 0xFF03 as some name
-        */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, 0xFF03, 0x08, 0x08);
-       /* Correct driving */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                       SD30_CLK_DRIVE_SEL, 0xFF, 0x96);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                       SD30_CMD_DRIVE_SEL, 0xFF, 0x96);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                       SD30_DAT_DRIVE_SEL, 0xFF, 0x96);
+       /* Configure driving */
+       rts5227_fill_driving(pcr, OUTPUT_3V3);
+       /* Configure force_clock_req */
+       if (pcr->flags & PCR_REVERSE_SOCKET)
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               AUTOLOAD_CFG_BASE + 3, 0xB8, 0xB8);
+       else
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               AUTOLOAD_CFG_BASE + 3, 0xB8, 0x88);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00);
 
        return rtsx_pci_send_cmd(pcr, 100);
 }
@@ -131,13 +196,11 @@ static int rts5227_card_power_off(struct rtsx_pcr *pcr, int card)
 static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 {
        int err;
-       u8 drive_sel;
 
        if (voltage == OUTPUT_3V3) {
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
                if (err < 0)
                        return err;
-               drive_sel = 0x96;
        } else if (voltage == OUTPUT_1V8) {
                err = rtsx_pci_write_phy_register(pcr, 0x11, 0x3C02);
                if (err < 0)
@@ -145,23 +208,18 @@ static int rts5227_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C80 | 0x24);
                if (err < 0)
                        return err;
-               drive_sel = 0xB3;
        } else {
                return -EINVAL;
        }
 
        /* set pad drive */
        rtsx_pci_init_cmd(pcr);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
-                       0xFF, drive_sel);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
-                       0xFF, drive_sel);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
-                       0xFF, drive_sel);
+       rts5227_fill_driving(pcr, voltage);
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
 static const struct pcr_ops rts5227_pcr_ops = {
+       .fetch_vendor_settings = rts5227_fetch_vendor_settings,
        .extra_init_hw = rts5227_extra_init_hw,
        .optimize_phy = rts5227_optimize_phy,
        .turn_on_led = rts5227_turn_on_led,
@@ -173,6 +231,7 @@ static const struct pcr_ops rts5227_pcr_ops = {
        .switch_output_voltage = rts5227_switch_output_voltage,
        .cd_deglitch = NULL,
        .conv_clk_and_div_n = NULL,
+       .force_power_down = rts5227_force_power_down,
 };
 
 /* SD Pull Control Enable:
@@ -227,6 +286,14 @@ void rts5227_init_params(struct rtsx_pcr *pcr)
        pcr->num_slots = 2;
        pcr->ops = &rts5227_pcr_ops;
 
+       pcr->flags = 0;
+       pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+       pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
+       pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
+       pcr->aspm_en = ASPM_L1_EN;
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
+       pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 7, 7);
+
        pcr->sd_pull_ctl_enable_tbl = rts5227_sd_pull_ctl_enable_tbl;
        pcr->sd_pull_ctl_disable_tbl = rts5227_sd_pull_ctl_disable_tbl;
        pcr->ms_pull_ctl_enable_tbl = rts5227_ms_pull_ctl_enable_tbl;
index 58af4dbe358623d2c45385ee5a5e6f31cb04344e..6353f5df087aa41bb11653b69593ea3eb56abd8b 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/module.h>
@@ -34,17 +33,51 @@ static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr)
        return val & 0x0F;
 }
 
+static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+       u32 reg;
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+       if (!rtsx_vendor_setting_valid(reg))
+               return;
+
+       pcr->aspm_en = rtsx_reg_to_aspm(reg);
+       pcr->sd30_drive_sel_1v8 =
+               map_sd_drive(rtsx_reg_to_sd30_drive_sel_1v8(reg));
+       pcr->card_drive_sel &= 0x3F;
+       pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+       pcr->sd30_drive_sel_3v3 =
+               map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));
+}
+
+static void rts5229_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
+}
+
 static int rts5229_extra_init_hw(struct rtsx_pcr *pcr)
 {
        rtsx_pci_init_cmd(pcr);
 
        /* Configure GPIO as output */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+       /* Reset ASPM state to default value */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
+       /* Force CLKREQ# PIN to drive 0 to request clock */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
        /* Switch LDO3318 source from DV33 to card_3v3 */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
        /* LED shine disabled, set initial shine cycle period */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
+       /* Configure driving */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+                       0xFF, pcr->sd30_drive_sel_3v3);
 
        return rtsx_pci_send_cmd(pcr, 100);
 }
@@ -110,7 +143,7 @@ static int rts5229_card_power_off(struct rtsx_pcr *pcr, int card)
                        SD_POWER_MASK | PMOS_STRG_MASK,
                        SD_POWER_OFF | PMOS_STRG_400mA);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PWR_GATE_CTRL,
-                       LDO3318_PWR_MASK, 0X00);
+                       LDO3318_PWR_MASK, 0x00);
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
@@ -120,7 +153,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 
        if (voltage == OUTPUT_3V3) {
                err = rtsx_pci_write_register(pcr,
-                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_D);
+                               SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_3v3);
                if (err < 0)
                        return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4FC0 | 0x24);
@@ -128,7 +161,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
                        return err;
        } else if (voltage == OUTPUT_1V8) {
                err = rtsx_pci_write_register(pcr,
-                               SD30_DRIVE_SEL, 0x07, DRIVER_TYPE_B);
+                               SD30_DRIVE_SEL, 0x07, pcr->sd30_drive_sel_1v8);
                if (err < 0)
                        return err;
                err = rtsx_pci_write_phy_register(pcr, 0x08, 0x4C40 | 0x24);
@@ -142,6 +175,7 @@ static int rts5229_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 }
 
 static const struct pcr_ops rts5229_pcr_ops = {
+       .fetch_vendor_settings = rts5229_fetch_vendor_settings,
        .extra_init_hw = rts5229_extra_init_hw,
        .optimize_phy = rts5229_optimize_phy,
        .turn_on_led = rts5229_turn_on_led,
@@ -153,6 +187,7 @@ static const struct pcr_ops rts5229_pcr_ops = {
        .switch_output_voltage = rts5229_switch_output_voltage,
        .cd_deglitch = NULL,
        .conv_clk_and_div_n = NULL,
+       .force_power_down = rts5229_force_power_down,
 };
 
 /* SD Pull Control Enable:
@@ -221,6 +256,14 @@ void rts5229_init_params(struct rtsx_pcr *pcr)
        pcr->num_slots = 2;
        pcr->ops = &rts5229_pcr_ops;
 
+       pcr->flags = 0;
+       pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+       pcr->sd30_drive_sel_1v8 = DRIVER_TYPE_B;
+       pcr->sd30_drive_sel_3v3 = DRIVER_TYPE_D;
+       pcr->aspm_en = ASPM_L1_EN;
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(27, 27, 15);
+       pcr->rx_initial_phase = SET_CLOCK_PHASE(30, 6, 6);
+
        pcr->ic_version = rts5229_get_ic_version(pcr);
        if (pcr->ic_version == IC_VER_C) {
                pcr->sd_pull_ctl_enable_tbl = rts5229_sd_pull_ctl_enable_tbl2;
index 15dc848bc0817bd6aafab9fa341e362e375f7944..3b835f593e35294a4666c25872eb911e9726b131 100644 (file)
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 128, West Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/module.h>
@@ -34,24 +33,95 @@ static u8 rts5249_get_ic_version(struct rtsx_pcr *pcr)
        return val & 0x0F;
 }
 
+static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
+{
+       u8 driving_3v3[4][3] = {
+               {0x11, 0x11, 0x11},
+               {0x55, 0x55, 0x5C},
+               {0x99, 0x99, 0x92},
+               {0x99, 0x99, 0x92},
+       };
+       u8 driving_1v8[4][3] = {
+               {0x3C, 0x3C, 0x3C},
+               {0xB3, 0xB3, 0xB3},
+               {0xFE, 0xFE, 0xFE},
+               {0xC4, 0xC4, 0xC4},
+       };
+       u8 (*driving)[3], drive_sel;
+
+       if (voltage == OUTPUT_3V3) {
+               driving = driving_3v3;
+               drive_sel = pcr->sd30_drive_sel_3v3;
+       } else {
+               driving = driving_1v8;
+               drive_sel = pcr->sd30_drive_sel_1v8;
+       }
+
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
+                       0xFF, driving[drive_sel][0]);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
+                       0xFF, driving[drive_sel][1]);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
+                       0xFF, driving[drive_sel][2]);
+}
+
+static void rts5249_fetch_vendor_settings(struct rtsx_pcr *pcr)
+{
+       u32 reg;
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
+
+       if (!rtsx_vendor_setting_valid(reg))
+               return;
+
+       pcr->aspm_en = rtsx_reg_to_aspm(reg);
+       pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
+       pcr->card_drive_sel &= 0x3F;
+       pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
+
+       rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
+       dev_dbg(&(pcr->pci->dev), "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
+       pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
+       if (rtsx_reg_check_reverse_socket(reg))
+               pcr->flags |= PCR_REVERSE_SOCKET;
+}
+
+static void rts5249_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       /* Set relink_time to 0 */
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, 0xFF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, 0xFF, 0);
+       rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3, 0x01, 0);
+
+       if (pm_state == HOST_ENTER_S3)
+               rtsx_pci_write_register(pcr, PM_CTRL3, 0x10, 0x10);
+
+       rtsx_pci_write_register(pcr, FPDCTL, 0x03, 0x03);
+}
+
 static int rts5249_extra_init_hw(struct rtsx_pcr *pcr)
 {
        rtsx_pci_init_cmd(pcr);
 
        /* Configure GPIO as output */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, GPIO_CTL, 0x02, 0x02);
+       /* Reset ASPM state to default value */
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
        /* Switch LDO3318 source from DV33 to card_3v3 */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x00);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, LDO_PWR_SEL, 0x03, 0x01);
        /* LED shine disabled, set initial shine cycle period */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, OLT_LED_CTL, 0x0F, 0x02);
-       /* Correct driving */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                       SD30_CLK_DRIVE_SEL, 0xFF, 0x99);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                       SD30_CMD_DRIVE_SEL, 0xFF, 0x99);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
-                       SD30_DAT_DRIVE_SEL, 0xFF, 0x92);
+       /* Configure driving */
+       rts5249_fill_driving(pcr, OUTPUT_3V3);
+       if (pcr->flags & PCR_REVERSE_SOCKET)
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               AUTOLOAD_CFG_BASE + 3, 0xB0, 0xB0);
+       else
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               AUTOLOAD_CFG_BASE + 3, 0xB0, 0x80);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PM_CTRL3, 0x10, 0x00);
 
        return rtsx_pci_send_cmd(pcr, 100);
 }
@@ -129,15 +199,11 @@ static int rts5249_card_power_off(struct rtsx_pcr *pcr, int card)
 static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
 {
        int err;
-       u8 clk_drive, cmd_drive, dat_drive;
 
        if (voltage == OUTPUT_3V3) {
                err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4FC0 | 0x24);
                if (err < 0)
                        return err;
-               clk_drive = 0x99;
-               cmd_drive = 0x99;
-               dat_drive = 0x92;
        } else if (voltage == OUTPUT_1V8) {
                err = rtsx_pci_write_phy_register(pcr, PHY_BACR, 0x3C02);
                if (err < 0)
@@ -145,25 +211,18 @@ static int rts5249_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
                err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, 0x4C40 | 0x24);
                if (err < 0)
                        return err;
-               clk_drive = 0xb3;
-               cmd_drive = 0xb3;
-               dat_drive = 0xb3;
        } else {
                return -EINVAL;
        }
 
        /* set pad drive */
        rtsx_pci_init_cmd(pcr);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CLK_DRIVE_SEL,
-                       0xFF, clk_drive);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_CMD_DRIVE_SEL,
-                       0xFF, cmd_drive);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DAT_DRIVE_SEL,
-                       0xFF, dat_drive);
+       rts5249_fill_driving(pcr, voltage);
        return rtsx_pci_send_cmd(pcr, 100);
 }
 
 static const struct pcr_ops rts5249_pcr_ops = {
+       .fetch_vendor_settings = rts5249_fetch_vendor_settings,
        .extra_init_hw = rts5249_extra_init_hw,
        .optimize_phy = rts5249_optimize_phy,
        .turn_on_led = rts5249_turn_on_led,
@@ -173,6 +232,7 @@ static const struct pcr_ops rts5249_pcr_ops = {
        .card_power_on = rts5249_card_power_on,
        .card_power_off = rts5249_card_power_off,
        .switch_output_voltage = rts5249_switch_output_voltage,
+       .force_power_down = rts5249_force_power_down,
 };
 
 /* SD Pull Control Enable:
@@ -233,6 +293,14 @@ void rts5249_init_params(struct rtsx_pcr *pcr)
        pcr->num_slots = 2;
        pcr->ops = &rts5249_pcr_ops;
 
+       pcr->flags = 0;
+       pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
+       pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_C;
+       pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
+       pcr->aspm_en = ASPM_L1_EN;
+       pcr->tx_initial_phase = SET_CLOCK_PHASE(1, 29, 16);
+       pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
+
        pcr->ic_version = rts5249_get_ic_version(pcr);
        pcr->sd_pull_ctl_enable_tbl = rts5249_sd_pull_ctl_enable_tbl;
        pcr->sd_pull_ctl_disable_tbl = rts5249_sd_pull_ctl_disable_tbl;
index dd186c4103c1e4f6ad9dc690879fa161489a8b2c..e6ae7720f9e15bd546362509bca185c7a64eb86f 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/pci.h>
@@ -73,6 +72,9 @@ void rtsx_pci_start_run(struct rtsx_pcr *pcr)
                pcr->state = PDEV_STAT_RUN;
                if (pcr->ops->enable_auto_blink)
                        pcr->ops->enable_auto_blink(pcr);
+
+               if (pcr->aspm_en)
+                       rtsx_pci_write_config_byte(pcr, LCTLR, 0);
        }
 
        mod_delayed_work(system_wq, &pcr->idle_work, msecs_to_jiffies(200));
@@ -717,7 +719,7 @@ int rtsx_pci_card_exclusive_check(struct rtsx_pcr *pcr, int card)
                [RTSX_MS_CARD] = MS_EXIST
        };
 
-       if (!pcr->ms_pmos) {
+       if (!(pcr->flags & PCR_MS_PMOS)) {
                /* When using single PMOS, accessing card is not permitted
                 * if the existing card is not the designated one.
                 */
@@ -918,9 +920,27 @@ static void rtsx_pci_idle_work(struct work_struct *work)
        if (pcr->ops->turn_off_led)
                pcr->ops->turn_off_led(pcr);
 
+       if (pcr->aspm_en)
+               rtsx_pci_write_config_byte(pcr, LCTLR, pcr->aspm_en);
+
        mutex_unlock(&pcr->pcr_mutex);
 }
 
+static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
+{
+       if (pcr->ops->turn_off_led)
+               pcr->ops->turn_off_led(pcr);
+
+       rtsx_pci_writel(pcr, RTSX_BIER, 0);
+       pcr->bier = 0;
+
+       rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08);
+       rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, pm_state);
+
+       if (pcr->ops->force_power_down)
+               pcr->ops->force_power_down(pcr, pm_state);
+}
+
 static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
 {
        int err;
@@ -951,13 +971,11 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, HOST_SLEEP_STATE, 0x03, 0x00);
        /* Disable card clock */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_CLK_EN, 0x1E, 0);
-       /* Reset ASPM state to default value */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, ASPM_FORCE_CTL, 0x3F, 0);
        /* Reset delink mode */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CHANGE_LINK_STATE, 0x0A, 0);
        /* Card driving select */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD30_DRIVE_SEL,
-                       0x07, DRIVER_TYPE_D);
+       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DRIVE_SEL,
+                       0xFF, pcr->card_drive_sel);
        /* Enable SSC Clock */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1,
                        0xFF, SSC_8X_EN | SSC_SEL_4M);
@@ -982,13 +1000,13 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
         *      0: ELBI interrupt flag[31:22] & [7:0] only can be write clear
         */
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, NFTS_TX_CTRL, 0x02, 0);
-       /* Force CLKREQ# PIN to drive 0 to request clock */
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, 0x08, 0x08);
 
        err = rtsx_pci_send_cmd(pcr, 100);
        if (err < 0)
                return err;
 
+       rtsx_pci_write_config_byte(pcr, LCTLR, 0);
+
        /* Enable clk_request_n to enable clock power management */
        rtsx_pci_write_config_byte(pcr, 0x81, 1);
        /* Enter L1 when host tx idle */
@@ -1053,6 +1071,18 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
        if (!pcr->slots)
                return -ENOMEM;
 
+       if (pcr->ops->fetch_vendor_settings)
+               pcr->ops->fetch_vendor_settings(pcr);
+
+       dev_dbg(&(pcr->pci->dev), "pcr->aspm_en = 0x%x\n", pcr->aspm_en);
+       dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_1v8 = 0x%x\n",
+                       pcr->sd30_drive_sel_1v8);
+       dev_dbg(&(pcr->pci->dev), "pcr->sd30_drive_sel_3v3 = 0x%x\n",
+                       pcr->sd30_drive_sel_3v3);
+       dev_dbg(&(pcr->pci->dev), "pcr->card_drive_sel = 0x%x\n",
+                       pcr->card_drive_sel);
+       dev_dbg(&(pcr->pci->dev), "pcr->flags = 0x%x\n", pcr->flags);
+
        pcr->state = PDEV_STAT_IDLE;
        err = rtsx_pci_init_hw(pcr);
        if (err < 0) {
@@ -1235,7 +1265,6 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
 {
        struct pcr_handle *handle;
        struct rtsx_pcr *pcr;
-       int ret = 0;
 
        dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
 
@@ -1247,14 +1276,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
 
        mutex_lock(&pcr->pcr_mutex);
 
-       if (pcr->ops->turn_off_led)
-               pcr->ops->turn_off_led(pcr);
-
-       rtsx_pci_writel(pcr, RTSX_BIER, 0);
-       pcr->bier = 0;
-
-       rtsx_pci_write_register(pcr, PETXCFG, 0x08, 0x08);
-       rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x02);
+       rtsx_pci_power_off(pcr, HOST_ENTER_S3);
 
        pci_save_state(pcidev);
        pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
@@ -1262,7 +1284,7 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
        pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
 
        mutex_unlock(&pcr->pcr_mutex);
-       return ret;
+       return 0;
 }
 
 static int rtsx_pci_resume(struct pci_dev *pcidev)
@@ -1300,10 +1322,25 @@ out:
        return ret;
 }
 
+static void rtsx_pci_shutdown(struct pci_dev *pcidev)
+{
+       struct pcr_handle *handle;
+       struct rtsx_pcr *pcr;
+
+       dev_dbg(&(pcidev->dev), "--> %s\n", __func__);
+
+       handle = pci_get_drvdata(pcidev);
+       pcr = handle->pcr;
+       rtsx_pci_power_off(pcr, HOST_ENTER_S1);
+
+       pci_disable_device(pcidev);
+}
+
 #else /* CONFIG_PM */
 
 #define rtsx_pci_suspend NULL
 #define rtsx_pci_resume NULL
+#define rtsx_pci_shutdown NULL
 
 #endif /* CONFIG_PM */
 
@@ -1314,6 +1351,7 @@ static struct pci_driver rtsx_pci_driver = {
        .remove = rtsx_pci_remove,
        .suspend = rtsx_pci_suspend,
        .resume = rtsx_pci_resume,
+       .shutdown = rtsx_pci_shutdown,
 };
 module_pci_driver(rtsx_pci_driver);
 
index c0cac7e8972f6327571e9558eb3026aab4b6fa8a..947e79b05cebfd211590c93a53cec7f58182f907 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #ifndef __RTSX_PCR_H
@@ -35,4 +34,33 @@ void rts5227_init_params(struct rtsx_pcr *pcr);
 void rts5249_init_params(struct rtsx_pcr *pcr);
 void rtl8411b_init_params(struct rtsx_pcr *pcr);
 
+static inline u8 map_sd_drive(int idx)
+{
+       u8 sd_drive[4] = {
+               0x01,   /* Type D */
+               0x02,   /* Type C */
+               0x05,   /* Type A */
+               0x03    /* Type B */
+       };
+
+       return sd_drive[idx];
+}
+
+#define rtsx_vendor_setting_valid(reg)         (!((reg) & 0x1000000))
+#define rts5209_vendor_setting1_valid(reg)     (!((reg) & 0x80))
+#define rts5209_vendor_setting2_valid(reg)     ((reg) & 0x80)
+
+#define rtsx_reg_to_aspm(reg)                  (((reg) >> 28) & 0x03)
+#define rtsx_reg_to_sd30_drive_sel_1v8(reg)    (((reg) >> 26) & 0x03)
+#define rtsx_reg_to_sd30_drive_sel_3v3(reg)    (((reg) >> 5) & 0x03)
+#define rtsx_reg_to_card_drive_sel(reg)                ((((reg) >> 25) & 0x01) << 6)
+#define rtsx_reg_check_reverse_socket(reg)     ((reg) & 0x4000)
+#define rts5209_reg_to_aspm(reg)               (((reg) >> 5) & 0x03)
+#define rts5209_reg_check_ms_pmos(reg)         (!((reg) & 0x08))
+#define rts5209_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 3) & 0x07)
+#define rts5209_reg_to_sd30_drive_sel_3v3(reg) ((reg) & 0x07)
+#define rts5209_reg_to_card_drive_sel(reg)     ((reg) >> 8)
+#define rtl8411_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x07)
+#define rtl8411b_reg_to_sd30_drive_sel_3v3(reg)        ((reg) & 0x03)
+
 #endif
index 79767681483a65b78804e44263bfbba4ef135d2e..f530e4b73f19abd63fe42ba7f18230dba79c088f 100644 (file)
@@ -61,7 +61,9 @@ static struct mfd_cell s5m8767_devs[] = {
 static struct mfd_cell s2mps11_devs[] = {
        {
                .name = "s2mps11-pmic",
-       },
+       }, {
+               .name = "s2mps11-clk",
+       }
 };
 
 #ifdef CONFIG_OF
@@ -69,6 +71,9 @@ static struct of_device_id sec_dt_match[] = {
        {       .compatible = "samsung,s5m8767-pmic",
                .data = (void *)S5M8767X,
        },
+       {       .compatible = "samsung,s2mps11-pmic",
+               .data = (void *)S2MPS11X,
+       },
        {},
 };
 #endif
@@ -103,6 +108,31 @@ int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask)
 }
 EXPORT_SYMBOL_GPL(sec_reg_update);
 
+static bool s2mps11_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case S2MPS11_REG_INT1M:
+       case S2MPS11_REG_INT2M:
+       case S2MPS11_REG_INT3M:
+               return false;
+       default:
+               return true;
+       }
+}
+
+static bool s5m8763_volatile(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case S5M8763_REG_IRQM1:
+       case S5M8763_REG_IRQM2:
+       case S5M8763_REG_IRQM3:
+       case S5M8763_REG_IRQM4:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static struct regmap_config sec_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
@@ -113,6 +143,8 @@ static struct regmap_config s2mps11_regmap_config = {
        .val_bits = 8,
 
        .max_register = S2MPS11_REG_L38CTRL,
+       .volatile_reg = s2mps11_volatile,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static struct regmap_config s5m8763_regmap_config = {
@@ -120,6 +152,8 @@ static struct regmap_config s5m8763_regmap_config = {
        .val_bits = 8,
 
        .max_register = S5M8763_REG_LBCNFG2,
+       .volatile_reg = s5m8763_volatile,
+       .cache_type = REGCACHE_FLAT,
 };
 
 static struct regmap_config s5m8767_regmap_config = {
@@ -127,6 +161,8 @@ static struct regmap_config s5m8767_regmap_config = {
        .val_bits = 8,
 
        .max_register = S5M8767_REG_LDO28CTRL,
+       .volatile_reg = s2mps11_volatile,
+       .cache_type = REGCACHE_FLAT,
 };
 
 #ifdef CONFIG_OF
@@ -182,7 +218,7 @@ static inline int sec_i2c_get_driver_data(struct i2c_client *i2c,
 static int sec_pmic_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
-       struct sec_platform_data *pdata = i2c->dev.platform_data;
+       struct sec_platform_data *pdata = dev_get_platdata(&i2c->dev);
        const struct regmap_config *regmap;
        struct sec_pmic_dev *sec_pmic;
        int ret;
index f5bc8e4bd4bf631b3266091a3af6212be07138cf..0e4a76daf18789b37e84163f2a83bb45afb642ea 100644 (file)
@@ -718,7 +718,7 @@ static int si476x_core_probe(struct i2c_client *client,
        atomic_set(&core->is_alive, 0);
        core->power_state = SI476X_POWER_DOWN;
 
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        if (pdata) {
                memcpy(&core->power_up_parameters,
                       &pdata->power_up_parameters,
index 9816c232e58331c202f8622e87657c90ccb1f972..33f040c558d090aca5887356bdd1cd2bbb11f461 100644 (file)
@@ -840,7 +840,7 @@ static int sm501_register_uart(struct sm501_devdata *sm, int devices)
        if (!pdev)
                return -ENOMEM;
 
-       uart_data = pdev->dev.platform_data;
+       uart_data = dev_get_platdata(&pdev->dev);
 
        if (devices & SM501_USE_UART0) {
                sm501_setup_uart_data(sm, uart_data++, 0x30000);
@@ -1167,7 +1167,7 @@ static int sm501_register_gpio_i2c_instance(struct sm501_devdata *sm,
        if (!pdev)
                return -ENOMEM;
 
-       icd = pdev->dev.platform_data;
+       icd = dev_get_platdata(&pdev->dev);
 
        /* We keep the pin_sda and pin_scl fields relative in case the
         * same platform data is passed to >1 SM501.
@@ -1403,7 +1403,7 @@ static int sm501_plat_probe(struct platform_device *dev)
 
        sm->dev = &dev->dev;
        sm->pdev_id = dev->id;
-       sm->platdata = dev->dev.platform_data;
+       sm->platdata = dev_get_platdata(&dev->dev);
 
        ret = platform_get_irq(dev, 0);
        if (ret < 0) {
index d70a343078fd5934ab1fff9732caed67a32b095c..65c6fa671acb27a67496b3b9277aa4919942dc89 100644 (file)
@@ -133,7 +133,7 @@ int sta2x11_mfd_get_regs_data(struct platform_device *dev,
                              void __iomem **regs,
                              spinlock_t **lock)
 {
-       struct pci_dev *pdev = *(struct pci_dev **)(dev->dev.platform_data);
+       struct pci_dev *pdev = *(struct pci_dev **)dev_get_platdata(&dev->dev);
        struct sta2x11_mfd *mfd;
 
        if (!pdev)
@@ -312,7 +312,7 @@ static int sta2x11_mfd_platform_probe(struct platform_device *dev,
        const char *name = sta2x11_mfd_names[index];
        struct regmap_config *regmap_config = sta2x11_mfd_regmap_configs[index];
 
-       pdev = dev->dev.platform_data;
+       pdev = dev_get_platdata(&dev->dev);
        mfd = sta2x11_mfd_find(*pdev);
        if (!mfd)
                return -ENODEV;
index 5d5e6f90424aa981653e0e3a609845d4de5a935f..fff63a41862cf6bbb4acfac38496447a4137ad0a 100644 (file)
@@ -1106,7 +1106,8 @@ static int stmpe_devices_init(struct stmpe *stmpe)
        return ret;
 }
 
-void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np)
+static void stmpe_of_probe(struct stmpe_platform_data *pdata,
+                          struct device_node *np)
 {
        struct device_node *child;
 
index 962a6e17a01a1f75a3e783a94f4eb0d126273b60..71841f9181bd19f4ae6b832898353bc442999c2e 100644 (file)
@@ -25,7 +25,6 @@
 static struct platform_driver syscon_driver;
 
 struct syscon {
-       void __iomem *base;
        struct regmap *regmap;
 };
 
@@ -129,6 +128,7 @@ static int syscon_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct syscon *syscon;
        struct resource *res;
+       void __iomem *base;
 
        syscon = devm_kzalloc(dev, sizeof(*syscon), GFP_KERNEL);
        if (!syscon)
@@ -138,12 +138,12 @@ static int syscon_probe(struct platform_device *pdev)
        if (!res)
                return -ENOENT;
 
-       syscon->base = devm_ioremap(dev, res->start, resource_size(res));
-       if (!syscon->base)
+       base = devm_ioremap(dev, res->start, resource_size(res));
+       if (!base)
                return -ENOMEM;
 
        syscon_regmap_config.max_register = res->end - res->start - 3;
-       syscon->regmap = devm_regmap_init_mmio(dev, syscon->base,
+       syscon->regmap = devm_regmap_init_mmio(dev, base,
                                        &syscon_regmap_config);
        if (IS_ERR(syscon->regmap)) {
                dev_err(dev, "regmap init failed\n");
index a21bff283a98fa7d5637e2f9ebc9ba6e94a602c7..9e04a74859818bd0016dfd6a60bbcd94669a4248 100644 (file)
@@ -281,7 +281,7 @@ static void t7l66xb_detach_irq(struct platform_device *dev)
 static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
-       struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
+       struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
 
        if (pdata && pdata->suspend)
                pdata->suspend(dev);
@@ -293,7 +293,7 @@ static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
 static int t7l66xb_resume(struct platform_device *dev)
 {
        struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
-       struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
+       struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
 
        clk_enable(t7l66xb->clk48m);
        if (pdata && pdata->resume)
@@ -313,7 +313,7 @@ static int t7l66xb_resume(struct platform_device *dev)
 
 static int t7l66xb_probe(struct platform_device *dev)
 {
-       struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
+       struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
        struct t7l66xb *t7l66xb;
        struct resource *iomem, *rscr;
        int ret;
@@ -409,7 +409,7 @@ err_noirq:
 
 static int t7l66xb_remove(struct platform_device *dev)
 {
-       struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
+       struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
        struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
        int ret;
 
index 4cb92bb2aea2f27ad2a1cf4177890b7488ae7dc9..70f4909fee13b8d30a632029a9639b41b81cb051 100644 (file)
@@ -325,7 +325,7 @@ static int tc3589x_of_probe(struct device_node *np,
 static int tc3589x_probe(struct i2c_client *i2c,
                                   const struct i2c_device_id *id)
 {
-       struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
+       struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct device_node *np = i2c->dev.of_node;
        struct tc3589x *tc3589x;
        int ret;
index 65c425a517c50ec94836a7edb1e7cdf496e04481..acd0f3a41044a5171cc0cfde9d03ad693fa9f48c 100644 (file)
@@ -48,7 +48,7 @@ static struct resource tc6387xb_mmc_resources[] = {
 static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
 {
        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
-       struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
+       struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
 
        if (pdata && pdata->suspend)
                pdata->suspend(dev);
@@ -60,7 +60,7 @@ static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
 static int tc6387xb_resume(struct platform_device *dev)
 {
        struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
-       struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
+       struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
 
        clk_enable(tc6387xb->clk32k);
        if (pdata && pdata->resume)
@@ -140,7 +140,7 @@ static struct mfd_cell tc6387xb_cells[] = {
 
 static int tc6387xb_probe(struct platform_device *dev)
 {
-       struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
+       struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
        struct resource *iomem, *rscr;
        struct clk *clk32k;
        struct tc6387xb *tc6387xb;
index a563dfa3cf87434706ab8f464d1538329fa5b4f0..11c19e5385510ccf8d8272e709e7b95264b66afc 100644 (file)
@@ -604,7 +604,7 @@ static void tc6393xb_detach_irq(struct platform_device *dev)
 
 static int tc6393xb_probe(struct platform_device *dev)
 {
-       struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
+       struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
        struct tc6393xb *tc6393xb;
        struct resource *iomem, *rscr;
        int ret, temp;
@@ -733,7 +733,7 @@ err_kzalloc:
 
 static int tc6393xb_remove(struct platform_device *dev)
 {
-       struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
+       struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
        struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
        int ret;
 
@@ -765,7 +765,7 @@ static int tc6393xb_remove(struct platform_device *dev)
 #ifdef CONFIG_PM
 static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
+       struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
        struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
        int i, ret;
 
@@ -788,7 +788,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
 
 static int tc6393xb_resume(struct platform_device *dev)
 {
-       struct tc6393xb_platform_data *tcpd = dev->dev.platform_data;
+       struct tc6393xb_platform_data *tcpd = dev_get_platdata(&dev->dev);
        struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
        int ret;
        int i;
index 09a14cec351ba4b0d3c606fcf8ad112684ee1a2b..1c2b994e1f6c0b0ce1e4bd346a4ff6e1e1c77e3d 100644 (file)
@@ -318,7 +318,7 @@ static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
 static int ti_ssp_probe(struct platform_device *pdev)
 {
        static struct ti_ssp *ssp;
-       const struct ti_ssp_data *pdata = pdev->dev.platform_data;
+       const struct ti_ssp_data *pdata = dev_get_platdata(&pdev->dev);
        int error = 0, prediv = 0xff, id;
        unsigned long sysclk;
        struct device *dev = &pdev->dev;
index b003a16ba227384d8deddb861d89515a0f29b525..baaf5a8123bb8eba1aadffda901238acce2a9a98 100644 (file)
@@ -57,20 +57,20 @@ EXPORT_SYMBOL_GPL(am335x_tsc_se_update);
 void am335x_tsc_se_set(struct ti_tscadc_dev *tsadc, u32 val)
 {
        spin_lock(&tsadc->reg_lock);
+       tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE);
        tsadc->reg_se_cache |= val;
-       spin_unlock(&tsadc->reg_lock);
-
        am335x_tsc_se_update(tsadc);
+       spin_unlock(&tsadc->reg_lock);
 }
 EXPORT_SYMBOL_GPL(am335x_tsc_se_set);
 
 void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val)
 {
        spin_lock(&tsadc->reg_lock);
+       tsadc->reg_se_cache = tscadc_readl(tsadc, REG_SE);
        tsadc->reg_se_cache &= ~val;
-       spin_unlock(&tsadc->reg_lock);
-
        am335x_tsc_se_update(tsadc);
+       spin_unlock(&tsadc->reg_lock);
 }
 EXPORT_SYMBOL_GPL(am335x_tsc_se_clr);
 
@@ -197,24 +197,21 @@ static    int ti_tscadc_probe(struct platform_device *pdev)
        clock_rate = clk_get_rate(clk);
        clk_put(clk);
        clk_value = clock_rate / ADC_CLK;
-       if (clk_value < MAX_CLK_DIV) {
-               dev_err(&pdev->dev, "clock input less than min clock requirement\n");
-               err = -EINVAL;
-               goto err_disable_clk;
-       }
+
        /* TSCADC_CLKDIV needs to be configured to the value minus 1 */
        clk_value = clk_value - 1;
        tscadc_writel(tscadc, REG_CLKDIV, clk_value);
 
        /* Set the control register bits */
        ctrl = CNTRLREG_STEPCONFIGWRT |
-                       CNTRLREG_TSCENB |
-                       CNTRLREG_STEPID |
-                       CNTRLREG_4WIRE;
+                       CNTRLREG_STEPID;
+       if (tsc_wires > 0)
+               ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB;
        tscadc_writel(tscadc, REG_CTRL, ctrl);
 
        /* Set register bits for Idle Config Mode */
-       tscadc_idle_config(tscadc);
+       if (tsc_wires > 0)
+               tscadc_idle_config(tscadc);
 
        /* Enable the TSC module enable bit */
        ctrl = tscadc_readl(tscadc, REG_CTRL);
@@ -294,10 +291,13 @@ static int tscadc_resume(struct device *dev)
        pm_runtime_get_sync(dev);
 
        /* context restore */
-       ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_TSCENB |
-                       CNTRLREG_STEPID | CNTRLREG_4WIRE;
+       ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID;
+       if (tscadc_dev->tsc_cell != -1)
+               ctrl |= CNTRLREG_TSCENB | CNTRLREG_4WIRE;
        tscadc_writel(tscadc_dev, REG_CTRL, ctrl);
-       tscadc_idle_config(tscadc_dev);
+
+       if (tscadc_dev->tsc_cell != -1)
+               tscadc_idle_config(tscadc_dev);
        am335x_tsc_se_update(tscadc_dev);
        restore = tscadc_readl(tscadc_dev, REG_CTRL);
        tscadc_writel(tscadc_dev, REG_CTRL,
index 0c1fcbc23d045652ba224a0871a05f1769d2114a..a6755ec7bd6ac55a1a8675a2d0382330f6863f54 100644 (file)
@@ -115,11 +115,11 @@ static const struct resource timberdale_ocores_resources[] = {
        },
 };
 
-const struct max7301_platform_data timberdale_max7301_platform_data = {
+static const struct max7301_platform_data timberdale_max7301_platform_data = {
        .base = 200
 };
 
-const struct mc33880_platform_data timberdale_mc33880_platform_data = {
+static const struct mc33880_platform_data timberdale_mc33880_platform_data = {
        .base = 100
 };
 
@@ -781,7 +781,6 @@ static int timb_probe(struct pci_dev *dev,
                        priv->fw.major, priv->fw.minor, ip_setup);
                err = -ENODEV;
                goto err_mfd;
-               break;
        }
 
        if (err) {
@@ -869,34 +868,7 @@ static struct pci_driver timberdale_pci_driver = {
        .remove = timb_remove,
 };
 
-static int __init timberdale_init(void)
-{
-       int err;
-
-       err = pci_register_driver(&timberdale_pci_driver);
-       if (err < 0) {
-               printk(KERN_ERR
-                       "Failed to register PCI driver for %s device.\n",
-                       timberdale_pci_driver.name);
-               return -ENODEV;
-       }
-
-       printk(KERN_INFO "Driver for %s has been successfully registered.\n",
-               timberdale_pci_driver.name);
-
-       return 0;
-}
-
-static void __exit timberdale_exit(void)
-{
-       pci_unregister_driver(&timberdale_pci_driver);
-
-       printk(KERN_INFO "Driver for %s has been successfully unregistered.\n",
-               timberdale_pci_driver.name);
-}
-
-module_init(timberdale_init);
-module_exit(timberdale_exit);
+module_pci_driver(timberdale_pci_driver);
 
 MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
 MODULE_VERSION(DRV_VERSION);
index 1d302f583adf2c3b2633164daa4c9fe253563476..b5dfa6e4e692968f80bc31f85be7757db4c80e69 100644 (file)
@@ -147,7 +147,7 @@ static int tps6105x_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, tps6105x);
        tps6105x->client = client;
-       pdata = client->dev.platform_data;
+       pdata = dev_get_platdata(&client->dev);
        tps6105x->pdata = pdata;
        mutex_init(&tps6105x->lock);
 
index da2691f22e114390f3f40817473f24a12c302f8f..743fb524fc8ae96f58cfaa6ea635317b621878cb 100644 (file)
@@ -242,8 +242,8 @@ static int dbg_show(struct seq_file *s, void *_)
        seq_printf(s, "mask2     %s\n", buf);
        /* ignore ackint2 */
 
-       schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
-
+       queue_delayed_work(system_power_efficient_wq, &tps->work,
+                          POWER_POLL_DELAY);
 
        /* VMAIN voltage, enable lowpower, etc */
        value = i2c_smbus_read_byte_data(tps->client, TPS_VDCDC1);
@@ -400,7 +400,8 @@ static void tps65010_interrupt(struct tps65010 *tps)
                        && (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)))
                poll = 1;
        if (poll)
-               schedule_delayed_work(&tps->work, POWER_POLL_DELAY);
+               queue_delayed_work(system_power_efficient_wq, &tps->work,
+                                  POWER_POLL_DELAY);
 
        /* also potentially gpio-in rise or fall */
 }
@@ -448,7 +449,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
 
        disable_irq_nosync(irq);
        set_bit(FLAG_IRQ_ENABLE, &tps->flags);
-       schedule_delayed_work(&tps->work, 0);
+       queue_delayed_work(system_power_efficient_wq, &tps->work, 0);
        return IRQ_HANDLED;
 }
 
@@ -517,7 +518,7 @@ static struct tps65010 *the_tps;
 static int __exit tps65010_remove(struct i2c_client *client)
 {
        struct tps65010         *tps = i2c_get_clientdata(client);
-       struct tps65010_board   *board = client->dev.platform_data;
+       struct tps65010_board   *board = dev_get_platdata(&client->dev);
 
        if (board && board->teardown) {
                int status = board->teardown(client, board->context);
@@ -529,7 +530,6 @@ static int __exit tps65010_remove(struct i2c_client *client)
                free_irq(client->irq, tps);
        cancel_delayed_work_sync(&tps->work);
        debugfs_remove(tps->file);
-       kfree(tps);
        the_tps = NULL;
        return 0;
 }
@@ -539,7 +539,7 @@ static int tps65010_probe(struct i2c_client *client,
 {
        struct tps65010         *tps;
        int                     status;
-       struct tps65010_board   *board = client->dev.platform_data;
+       struct tps65010_board   *board = dev_get_platdata(&client->dev);
 
        if (the_tps) {
                dev_dbg(&client->dev, "only one tps6501x chip allowed\n");
@@ -549,7 +549,7 @@ static int tps65010_probe(struct i2c_client *client,
        if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
                return -EINVAL;
 
-       tps = kzalloc(sizeof *tps, GFP_KERNEL);
+       tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
        if (!tps)
                return -ENOMEM;
 
@@ -567,7 +567,7 @@ static int tps65010_probe(struct i2c_client *client,
                if (status < 0) {
                        dev_dbg(&client->dev, "can't get IRQ %d, err %d\n",
                                        client->irq, status);
-                       goto fail1;
+                       return status;
                }
                /* annoying race here, ideally we'd have an option
                 * to claim the irq now and enable it later.
@@ -667,9 +667,6 @@ static int tps65010_probe(struct i2c_client *client,
        }
 
        return 0;
-fail1:
-       kfree(tps);
-       return status;
 }
 
 static const struct i2c_device_id tps65010_id[] = {
@@ -718,7 +715,8 @@ int tps65010_set_vbus_draw(unsigned mA)
                        && test_and_set_bit(
                                FLAG_VBUS_CHANGED, &the_tps->flags)) {
                /* gadget drivers call this in_irq() */
-               schedule_delayed_work(&the_tps->work, 0);
+               queue_delayed_work(system_power_efficient_wq, &the_tps->work,
+                                  0);
        }
        local_irq_restore(flags);
 
index fbd6ee67b5a511317c02fe45d5d039b881987d8d..e6f03a733879b063d670ecc2bd074ea28063ec18 100644 (file)
@@ -172,7 +172,7 @@ MODULE_DEVICE_TABLE(of, tps65090_of_match);
 static int tps65090_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
-       struct tps65090_platform_data *pdata = client->dev.platform_data;
+       struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
        int irq_base = 0;
        struct tps65090 *tps65090;
        int ret;
index 4b93ed4d5cd6a3649efdaa2c0eedc191792ab7c0..f54fe4d4f77b34a7ecbcef449635dbdbccf036d8 100644 (file)
@@ -462,7 +462,7 @@ static void tps6586x_power_off(void)
 static int tps6586x_i2c_probe(struct i2c_client *client,
                                        const struct i2c_device_id *id)
 {
-       struct tps6586x_platform_data *pdata = client->dev.platform_data;
+       struct tps6586x_platform_data *pdata = dev_get_platdata(&client->dev);
        struct tps6586x *tps6586x;
        int ret;
 
index 479886a4cf8054b60750303cc092c88128331c9d..925a044cbdf61740e3c54e0a481a9774587c652b 100644 (file)
@@ -123,7 +123,7 @@ EXPORT_SYMBOL_GPL(tps65912_reg_write);
 
 int tps65912_device_init(struct tps65912 *tps65912)
 {
-       struct tps65912_board *pmic_plat_data = tps65912->dev->platform_data;
+       struct tps65912_board *pmic_plat_data = dev_get_platdata(tps65912->dev);
        struct tps65912_platform_data *init_data;
        int ret, dcdc_avs, value;
 
index c90a2c450f5113c44536eac3b82315be92e9e89d..f15ee6d5cfbf96fb97ef6f169528c624b09a2aba 100644 (file)
@@ -418,7 +418,7 @@ static const struct regmap_config tps80031_regmap_configs[] = {
 static int tps80031_probe(struct i2c_client *client,
                          const struct i2c_device_id *id)
 {
-       struct tps80031_platform_data *pdata = client->dev.platform_data;
+       struct tps80031_platform_data *pdata = dev_get_platdata(&client->dev);
        struct tps80031 *tps80031;
        int ret;
        uint8_t es_version;
index 7f150d94d295146fc58b9c07481d06eb950b8604..29473c2c95ae0d92aa75184199486f70bdf5fc53 100644 (file)
@@ -1137,7 +1137,7 @@ static int twl_remove(struct i2c_client *client)
 static int
 twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
-       struct twl4030_platform_data    *pdata = client->dev.platform_data;
+       struct twl4030_platform_data    *pdata = dev_get_platdata(&client->dev);
        struct device_node              *node = client->dev.of_node;
        struct platform_device          *pdev;
        struct regmap_config            *twl_regmap_config;
index a31fba96ef438f745d0966d1c0e7828a8e0c930b..07fe542e6fc008a48995dc6191b73b758a20dcf6 100644 (file)
@@ -187,7 +187,7 @@ static bool twl4030_audio_has_vibra(struct twl4030_audio_data *pdata,
 static int twl4030_audio_probe(struct platform_device *pdev)
 {
        struct twl4030_audio *audio;
-       struct twl4030_audio_data *pdata = pdev->dev.platform_data;
+       struct twl4030_audio_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *node = pdev->dev.of_node;
        struct mfd_cell *cell = NULL;
        int ret, childs = 0;
index 1ea54d4d003aeb84c87c7af509dc13052a4bfc3f..4c583e47133993b59dd512f1e3ec7316fb68c7fb 100644 (file)
@@ -701,7 +701,7 @@ static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
 static int twl4030_madc_probe(struct platform_device *pdev)
 {
        struct twl4030_madc_data *madc;
-       struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
+       struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret;
        u8 regval;
 
index a5fd3c7382110d7298ea4ddf72ab644dcf1c6ed5..96162b62f3c0897df3f923ee0d4befcebfcb9048 100644 (file)
@@ -493,7 +493,7 @@ int twl4030_remove_script(u8 flags)
        return err;
 }
 
-int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
+static int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
 {
        int err;
        int i;
@@ -509,7 +509,7 @@ int twl4030_power_configure_scripts(struct twl4030_power_data *pdata)
        return 0;
 }
 
-int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
+static int twl4030_power_configure_resources(struct twl4030_power_data *pdata)
 {
        struct twl4030_resconfig *resconfig = pdata->resource_config;
        int err;
@@ -553,9 +553,9 @@ static bool twl4030_power_use_poweroff(struct twl4030_power_data *pdata,
        return false;
 }
 
-int twl4030_power_probe(struct platform_device *pdev)
+static int twl4030_power_probe(struct platform_device *pdev)
 {
-       struct twl4030_power_data *pdata = pdev->dev.platform_data;
+       struct twl4030_power_data *pdata = dev_get_platdata(&pdev->dev);
        struct device_node *node = pdev->dev.of_node;
        int err = 0;
        int err2 = 0;
index 277a8dba42d5742903863e1bfc325297e0f671aa..517eda832f79978ac772c94b3bcf111643ec8835 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/suspend.h>
 #include <linux/of.h>
 #include <linux/irqdomain.h>
+#include <linux/of_device.h>
 
 #include "twl-core.h"
 
@@ -84,39 +85,77 @@ static int twl6030_interrupt_mapping[24] = {
        CHARGERFAULT_INTR_OFFSET,       /* Bit 22       INT_CHRG        */
        RSV_INTR_OFFSET,        /* Bit 23       Reserved                */
 };
+
+static int twl6032_interrupt_mapping[24] = {
+       PWR_INTR_OFFSET,        /* Bit 0        PWRON                   */
+       PWR_INTR_OFFSET,        /* Bit 1        RPWRON                  */
+       PWR_INTR_OFFSET,        /* Bit 2        SYS_VLOW                */
+       RTC_INTR_OFFSET,        /* Bit 3        RTC_ALARM               */
+       RTC_INTR_OFFSET,        /* Bit 4        RTC_PERIOD              */
+       HOTDIE_INTR_OFFSET,     /* Bit 5        HOT_DIE                 */
+       SMPSLDO_INTR_OFFSET,    /* Bit 6        VXXX_SHORT              */
+       PWR_INTR_OFFSET,        /* Bit 7        SPDURATION              */
+
+       PWR_INTR_OFFSET,        /* Bit 8        WATCHDOG                */
+       BATDETECT_INTR_OFFSET,  /* Bit 9        BAT                     */
+       SIMDETECT_INTR_OFFSET,  /* Bit 10       SIM                     */
+       MMCDETECT_INTR_OFFSET,  /* Bit 11       MMC                     */
+       MADC_INTR_OFFSET,       /* Bit 12       GPADC_RT_EOC            */
+       MADC_INTR_OFFSET,       /* Bit 13       GPADC_SW_EOC            */
+       GASGAUGE_INTR_OFFSET,   /* Bit 14       CC_EOC                  */
+       GASGAUGE_INTR_OFFSET,   /* Bit 15       CC_AUTOCAL              */
+
+       USBOTG_INTR_OFFSET,     /* Bit 16       ID_WKUP                 */
+       USBOTG_INTR_OFFSET,     /* Bit 17       VBUS_WKUP               */
+       USBOTG_INTR_OFFSET,     /* Bit 18       ID                      */
+       USB_PRES_INTR_OFFSET,   /* Bit 19       VBUS                    */
+       CHARGER_INTR_OFFSET,    /* Bit 20       CHRG_CTRL               */
+       CHARGERFAULT_INTR_OFFSET,       /* Bit 21       EXT_CHRG        */
+       CHARGERFAULT_INTR_OFFSET,       /* Bit 22       INT_CHRG        */
+       RSV_INTR_OFFSET,        /* Bit 23       Reserved                */
+};
+
 /*----------------------------------------------------------------------*/
 
-static unsigned twl6030_irq_base;
-static int twl_irq;
-static bool twl_irq_wake_enabled;
+struct twl6030_irq {
+       unsigned int            irq_base;
+       int                     twl_irq;
+       bool                    irq_wake_enabled;
+       atomic_t                wakeirqs;
+       struct notifier_block   pm_nb;
+       struct irq_chip         irq_chip;
+       struct irq_domain       *irq_domain;
+       const int               *irq_mapping_tbl;
+};
 
-static struct completion irq_event;
-static atomic_t twl6030_wakeirqs = ATOMIC_INIT(0);
+static struct twl6030_irq *twl6030_irq;
 
 static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
                                   unsigned long pm_event, void *unused)
 {
        int chained_wakeups;
+       struct twl6030_irq *pdata = container_of(notifier, struct twl6030_irq,
+                                                 pm_nb);
 
        switch (pm_event) {
        case PM_SUSPEND_PREPARE:
-               chained_wakeups = atomic_read(&twl6030_wakeirqs);
+               chained_wakeups = atomic_read(&pdata->wakeirqs);
 
-               if (chained_wakeups && !twl_irq_wake_enabled) {
-                       if (enable_irq_wake(twl_irq))
+               if (chained_wakeups && !pdata->irq_wake_enabled) {
+                       if (enable_irq_wake(pdata->twl_irq))
                                pr_err("twl6030 IRQ wake enable failed\n");
                        else
-                               twl_irq_wake_enabled = true;
-               } else if (!chained_wakeups && twl_irq_wake_enabled) {
-                       disable_irq_wake(twl_irq);
-                       twl_irq_wake_enabled = false;
+                               pdata->irq_wake_enabled = true;
+               } else if (!chained_wakeups && pdata->irq_wake_enabled) {
+                       disable_irq_wake(pdata->twl_irq);
+                       pdata->irq_wake_enabled = false;
                }
 
-               disable_irq(twl_irq);
+               disable_irq(pdata->twl_irq);
                break;
 
        case PM_POST_SUSPEND:
-               enable_irq(twl_irq);
+               enable_irq(pdata->twl_irq);
                break;
 
        default:
@@ -126,124 +165,77 @@ static int twl6030_irq_pm_notifier(struct notifier_block *notifier,
        return NOTIFY_DONE;
 }
 
-static struct notifier_block twl6030_irq_pm_notifier_block = {
-       .notifier_call = twl6030_irq_pm_notifier,
-};
-
 /*
- * This thread processes interrupts reported by the Primary Interrupt Handler.
- */
-static int twl6030_irq_thread(void *data)
+* Threaded irq handler for the twl6030 interrupt.
+* We query the interrupt controller in the twl6030 to determine
+* which module is generating the interrupt request and call
+* handle_nested_irq for that module.
+*/
+static irqreturn_t twl6030_irq_thread(int irq, void *data)
 {
-       long irq = (long)data;
-       static unsigned i2c_errors;
-       static const unsigned max_i2c_errors = 100;
-       int ret;
-
-       while (!kthread_should_stop()) {
-               int i;
-               union {
+       int i, ret;
+       union {
                u8 bytes[4];
                u32 int_sts;
-               } sts;
-
-               /* Wait for IRQ, then read PIH irq status (also blocking) */
-               wait_for_completion_interruptible(&irq_event);
-
-               /* read INT_STS_A, B and C in one shot using a burst read */
-               ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes,
-                               REG_INT_STS_A, 3);
-               if (ret) {
-                       pr_warning("twl6030: I2C error %d reading PIH ISR\n",
-                                       ret);
-                       if (++i2c_errors >= max_i2c_errors) {
-                               printk(KERN_ERR "Maximum I2C error count"
-                                               " exceeded.  Terminating %s.\n",
-                                               __func__);
-                               break;
-                       }
-                       complete(&irq_event);
-                       continue;
-               }
-
-
+       } sts;
+       struct twl6030_irq *pdata = data;
+
+       /* read INT_STS_A, B and C in one shot using a burst read */
+       ret = twl_i2c_read(TWL_MODULE_PIH, sts.bytes, REG_INT_STS_A, 3);
+       if (ret) {
+               pr_warn("twl6030_irq: I2C error %d reading PIH ISR\n", ret);
+               return IRQ_HANDLED;
+       }
 
-               sts.bytes[3] = 0; /* Only 24 bits are valid*/
+       sts.bytes[3] = 0; /* Only 24 bits are valid*/
 
-               /*
-                * Since VBUS status bit is not reliable for VBUS disconnect
-                * use CHARGER VBUS detection status bit instead.
-                */
-               if (sts.bytes[2] & 0x10)
-                       sts.bytes[2] |= 0x08;
-
-               for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++) {
-                       local_irq_disable();
-                       if (sts.int_sts & 0x1) {
-                               int module_irq = twl6030_irq_base +
-                                       twl6030_interrupt_mapping[i];
-                               generic_handle_irq(module_irq);
-
-                       }
-               local_irq_enable();
+       /*
+        * Since VBUS status bit is not reliable for VBUS disconnect
+        * use CHARGER VBUS detection status bit instead.
+        */
+       if (sts.bytes[2] & 0x10)
+               sts.bytes[2] |= 0x08;
+
+       for (i = 0; sts.int_sts; sts.int_sts >>= 1, i++)
+               if (sts.int_sts & 0x1) {
+                       int module_irq =
+                               irq_find_mapping(pdata->irq_domain,
+                                                pdata->irq_mapping_tbl[i]);
+                       if (module_irq)
+                               handle_nested_irq(module_irq);
+                       else
+                               pr_err("twl6030_irq: Unmapped PIH ISR %u detected\n",
+                                      i);
+                       pr_debug("twl6030_irq: PIH ISR %u, virq%u\n",
+                                i, module_irq);
                }
 
-               /*
-                * NOTE:
-                * Simulation confirms that documentation is wrong w.r.t the
-                * interrupt status clear operation. A single *byte* write to
-                * any one of STS_A to STS_C register results in all three
-                * STS registers being reset. Since it does not matter which
-                * value is written, all three registers are cleared on a
-                * single byte write, so we just use 0x0 to clear.
-                */
-               ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
-               if (ret)
-                       pr_warning("twl6030: I2C error in clearing PIH ISR\n");
-
-               enable_irq(irq);
-       }
-
-       return 0;
-}
+       /*
+        * NOTE:
+        * Simulation confirms that documentation is wrong w.r.t the
+        * interrupt status clear operation. A single *byte* write to
+        * any one of STS_A to STS_C register results in all three
+        * STS registers being reset. Since it does not matter which
+        * value is written, all three registers are cleared on a
+        * single byte write, so we just use 0x0 to clear.
+        */
+       ret = twl_i2c_write_u8(TWL_MODULE_PIH, 0x00, REG_INT_STS_A);
+       if (ret)
+               pr_warn("twl6030_irq: I2C error in clearing PIH ISR\n");
 
-/*
- * handle_twl6030_int() is the desc->handle method for the twl6030 interrupt.
- * This is a chained interrupt, so there is no desc->action method for it.
- * Now we need to query the interrupt controller in the twl6030 to determine
- * which module is generating the interrupt request.  However, we can't do i2c
- * transactions in interrupt context, so we must defer that work to a kernel
- * thread.  All we do here is acknowledge and mask the interrupt and wakeup
- * the kernel thread.
- */
-static irqreturn_t handle_twl6030_pih(int irq, void *devid)
-{
-       disable_irq_nosync(irq);
-       complete(devid);
        return IRQ_HANDLED;
 }
 
 /*----------------------------------------------------------------------*/
 
-static inline void activate_irq(int irq)
-{
-#ifdef CONFIG_ARM
-       /* ARM requires an extra step to clear IRQ_NOREQUEST, which it
-        * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
-        */
-       set_irq_flags(irq, IRQF_VALID);
-#else
-       /* same effect on other architectures */
-       irq_set_noprobe(irq);
-#endif
-}
-
 static int twl6030_irq_set_wake(struct irq_data *d, unsigned int on)
 {
+       struct twl6030_irq *pdata = irq_get_chip_data(d->irq);
+
        if (on)
-               atomic_inc(&twl6030_wakeirqs);
+               atomic_inc(&pdata->wakeirqs);
        else
-               atomic_dec(&twl6030_wakeirqs);
+               atomic_dec(&pdata->wakeirqs);
 
        return 0;
 }
@@ -318,7 +310,8 @@ int twl6030_mmc_card_detect_config(void)
                return ret;
        }
 
-       return twl6030_irq_base + MMCDETECT_INTR_OFFSET;
+       return irq_find_mapping(twl6030_irq->irq_domain,
+                                MMCDETECT_INTR_OFFSET);
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect_config);
 
@@ -347,99 +340,143 @@ int twl6030_mmc_card_detect(struct device *dev, int slot)
 }
 EXPORT_SYMBOL(twl6030_mmc_card_detect);
 
+static int twl6030_irq_map(struct irq_domain *d, unsigned int virq,
+                             irq_hw_number_t hwirq)
+{
+       struct twl6030_irq *pdata = d->host_data;
+
+       irq_set_chip_data(virq, pdata);
+       irq_set_chip_and_handler(virq,  &pdata->irq_chip, handle_simple_irq);
+       irq_set_nested_thread(virq, true);
+       irq_set_parent(virq, pdata->twl_irq);
+
+#ifdef CONFIG_ARM
+       /*
+        * ARM requires an extra step to clear IRQ_NOREQUEST, which it
+        * sets on behalf of every irq_chip.  Also sets IRQ_NOPROBE.
+        */
+       set_irq_flags(virq, IRQF_VALID);
+#else
+       /* same effect on other architectures */
+       irq_set_noprobe(virq);
+#endif
+
+       return 0;
+}
+
+static void twl6030_irq_unmap(struct irq_domain *d, unsigned int virq)
+{
+#ifdef CONFIG_ARM
+       set_irq_flags(virq, 0);
+#endif
+       irq_set_chip_and_handler(virq, NULL, NULL);
+       irq_set_chip_data(virq, NULL);
+}
+
+static struct irq_domain_ops twl6030_irq_domain_ops = {
+       .map    = twl6030_irq_map,
+       .unmap  = twl6030_irq_unmap,
+       .xlate  = irq_domain_xlate_onetwocell,
+};
+
+static const struct of_device_id twl6030_of_match[] = {
+       {.compatible = "ti,twl6030", &twl6030_interrupt_mapping},
+       {.compatible = "ti,twl6032", &twl6032_interrupt_mapping},
+       { },
+};
+
 int twl6030_init_irq(struct device *dev, int irq_num)
 {
        struct                  device_node *node = dev->of_node;
-       int                     nr_irqs, irq_base, irq_end;
-       struct task_struct      *task;
-       static struct irq_chip  twl6030_irq_chip;
-       int                     status = 0;
-       int                     i;
+       int                     nr_irqs;
+       int                     status;
        u8                      mask[3];
+       const struct of_device_id *of_id;
 
-       nr_irqs = TWL6030_NR_IRQS;
-
-       irq_base = irq_alloc_descs(-1, 0, nr_irqs, 0);
-       if (IS_ERR_VALUE(irq_base)) {
-               dev_err(dev, "Fail to allocate IRQ descs\n");
-               return irq_base;
+       of_id = of_match_device(twl6030_of_match, dev);
+       if (!of_id || !of_id->data) {
+               dev_err(dev, "Unknown TWL device model\n");
+               return -EINVAL;
        }
 
-       irq_domain_add_legacy(node, nr_irqs, irq_base, 0,
-                             &irq_domain_simple_ops, NULL);
+       nr_irqs = TWL6030_NR_IRQS;
 
-       irq_end = irq_base + nr_irqs;
+       twl6030_irq = devm_kzalloc(dev, sizeof(*twl6030_irq), GFP_KERNEL);
+       if (!twl6030_irq) {
+               dev_err(dev, "twl6030_irq: Memory allocation failed\n");
+               return -ENOMEM;
+       }
 
        mask[0] = 0xFF;
        mask[1] = 0xFF;
        mask[2] = 0xFF;
 
        /* mask all int lines */
-       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
+       status = twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_LINE_A, 3);
        /* mask all int sts */
-       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
+       status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_MSK_STS_A, 3);
        /* clear INT_STS_A,B,C */
-       twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
+       status |= twl_i2c_write(TWL_MODULE_PIH, &mask[0], REG_INT_STS_A, 3);
 
-       twl6030_irq_base = irq_base;
+       if (status < 0) {
+               dev_err(dev, "I2C err writing TWL_MODULE_PIH: %d\n", status);
+               return status;
+       }
 
        /*
         * install an irq handler for each of the modules;
         * clone dummy irq_chip since PIH can't *do* anything
         */
-       twl6030_irq_chip = dummy_irq_chip;
-       twl6030_irq_chip.name = "twl6030";
-       twl6030_irq_chip.irq_set_type = NULL;
-       twl6030_irq_chip.irq_set_wake = twl6030_irq_set_wake;
-
-       for (i = irq_base; i < irq_end; i++) {
-               irq_set_chip_and_handler(i, &twl6030_irq_chip,
-                                        handle_simple_irq);
-               irq_set_chip_data(i, (void *)irq_num);
-               activate_irq(i);
+       twl6030_irq->irq_chip = dummy_irq_chip;
+       twl6030_irq->irq_chip.name = "twl6030";
+       twl6030_irq->irq_chip.irq_set_type = NULL;
+       twl6030_irq->irq_chip.irq_set_wake = twl6030_irq_set_wake;
+
+       twl6030_irq->pm_nb.notifier_call = twl6030_irq_pm_notifier;
+       atomic_set(&twl6030_irq->wakeirqs, 0);
+       twl6030_irq->irq_mapping_tbl = of_id->data;
+
+       twl6030_irq->irq_domain =
+               irq_domain_add_linear(node, nr_irqs,
+                                     &twl6030_irq_domain_ops, twl6030_irq);
+       if (!twl6030_irq->irq_domain) {
+               dev_err(dev, "Can't add irq_domain\n");
+               return -ENOMEM;
        }
 
-       dev_info(dev, "PIH (irq %d) chaining IRQs %d..%d\n",
-                       irq_num, irq_base, irq_end);
+       dev_info(dev, "PIH (irq %d) nested IRQs\n", irq_num);
 
        /* install an irq handler to demultiplex the TWL6030 interrupt */
-       init_completion(&irq_event);
-
-       status = request_irq(irq_num, handle_twl6030_pih, 0, "TWL6030-PIH",
-                            &irq_event);
+       status = request_threaded_irq(irq_num, NULL, twl6030_irq_thread,
+                                     IRQF_ONESHOT, "TWL6030-PIH", twl6030_irq);
        if (status < 0) {
                dev_err(dev, "could not claim irq %d: %d\n", irq_num, status);
                goto fail_irq;
        }
 
-       task = kthread_run(twl6030_irq_thread, (void *)irq_num, "twl6030-irq");
-       if (IS_ERR(task)) {
-               dev_err(dev, "could not create irq %d thread!\n", irq_num);
-               status = PTR_ERR(task);
-               goto fail_kthread;
-       }
-
-       twl_irq = irq_num;
-       register_pm_notifier(&twl6030_irq_pm_notifier_block);
-       return irq_base;
-
-fail_kthread:
-       free_irq(irq_num, &irq_event);
+       twl6030_irq->twl_irq = irq_num;
+       register_pm_notifier(&twl6030_irq->pm_nb);
+       return 0;
 
 fail_irq:
-       for (i = irq_base; i < irq_end; i++)
-               irq_set_chip_and_handler(i, NULL, NULL);
-
+       irq_domain_remove(twl6030_irq->irq_domain);
        return status;
 }
 
 int twl6030_exit_irq(void)
 {
-       unregister_pm_notifier(&twl6030_irq_pm_notifier_block);
-
-       if (twl6030_irq_base) {
-               pr_err("twl6030: can't yet clean up IRQs?\n");
-               return -ENOSYS;
+       if (twl6030_irq && twl6030_irq->twl_irq) {
+               unregister_pm_notifier(&twl6030_irq->pm_nb);
+               free_irq(twl6030_irq->twl_irq, NULL);
+               /*
+                * TODO: IRQ domain and allocated nested IRQ descriptors
+                * should be freed somehow here. Now It can't be done, because
+                * child devices will not be deleted during removing of
+                * TWL Core driver and they will still contain allocated
+                * virt IRQs in their Resources tables.
+                * The same prevents us from using devm_request_threaded_irq()
+                * in this module.
+                */
        }
        return 0;
 }
index 492ee2cd3400cf7b24863900137b740fbea6a72e..daf66942071c9084779497f6b40ac7bc2c8c916d 100644 (file)
 #define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
 #define TWL6040_NUM_SUPPLIES   (2)
 
-static bool twl6040_has_vibra(struct twl6040_platform_data *pdata,
-                             struct device_node *node)
+static bool twl6040_has_vibra(struct device_node *node)
 {
-       if (pdata && pdata->vibra)
-               return true;
-
 #ifdef CONFIG_OF
        if (of_find_node_by_name(node, "vibra"))
                return true;
 #endif
-
        return false;
 }
 
@@ -63,15 +58,9 @@ int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
        int ret;
        unsigned int val;
 
-       /* Vibra control registers from cache */
-       if (unlikely(reg == TWL6040_REG_VIBCTLL ||
-                    reg == TWL6040_REG_VIBCTLR)) {
-               val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)];
-       } else {
-               ret = regmap_read(twl6040->regmap, reg, &val);
-               if (ret < 0)
-                       return ret;
-       }
+       ret = regmap_read(twl6040->regmap, reg, &val);
+       if (ret < 0)
+               return ret;
 
        return val;
 }
@@ -82,9 +71,6 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val)
        int ret;
 
        ret = regmap_write(twl6040->regmap, reg, val);
-       /* Cache the vibra control registers */
-       if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR)
-               twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val;
 
        return ret;
 }
@@ -461,9 +447,20 @@ EXPORT_SYMBOL(twl6040_get_sysclk);
 /* Get the combined status of the vibra control register */
 int twl6040_get_vibralr_status(struct twl6040 *twl6040)
 {
+       unsigned int reg;
+       int ret;
        u8 status;
 
-       status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1];
+       ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLL, &reg);
+       if (ret != 0)
+               return ret;
+       status = reg;
+
+       ret = regmap_read(twl6040->regmap, TWL6040_REG_VIBCTLR, &reg);
+       if (ret != 0)
+               return ret;
+       status |= reg;
+
        status &= (TWL6040_VIBENA | TWL6040_VIBSEL);
 
        return status;
@@ -490,12 +487,27 @@ static bool twl6040_readable_reg(struct device *dev, unsigned int reg)
        return true;
 }
 
+static bool twl6040_volatile_reg(struct device *dev, unsigned int reg)
+{
+       switch (reg) {
+       case TWL6040_REG_VIBCTLL:
+       case TWL6040_REG_VIBCTLR:
+       case TWL6040_REG_INTMR:
+               return false;
+       default:
+               return true;
+       }
+}
+
 static struct regmap_config twl6040_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
        .max_register = TWL6040_REG_STATUS, /* 0x2e */
 
        .readable_reg = twl6040_readable_reg,
+       .volatile_reg = twl6040_volatile_reg,
+
+       .cache_type = REGCACHE_RBTREE,
 };
 
 static const struct regmap_irq twl6040_irqs[] = {
@@ -520,14 +532,13 @@ static struct regmap_irq_chip twl6040_irq_chip = {
 static int twl6040_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
-       struct twl6040_platform_data *pdata = client->dev.platform_data;
        struct device_node *node = client->dev.of_node;
        struct twl6040 *twl6040;
        struct mfd_cell *cell = NULL;
        int irq, ret, children = 0;
 
-       if (!pdata && !node) {
-               dev_err(&client->dev, "Platform data is missing\n");
+       if (!node) {
+               dev_err(&client->dev, "of node is missing\n");
                return -EINVAL;
        }
 
@@ -539,23 +550,19 @@ static int twl6040_probe(struct i2c_client *client,
 
        twl6040 = devm_kzalloc(&client->dev, sizeof(struct twl6040),
                               GFP_KERNEL);
-       if (!twl6040) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!twl6040)
+               return -ENOMEM;
 
        twl6040->regmap = devm_regmap_init_i2c(client, &twl6040_regmap_config);
-       if (IS_ERR(twl6040->regmap)) {
-               ret = PTR_ERR(twl6040->regmap);
-               goto err;
-       }
+       if (IS_ERR(twl6040->regmap))
+               return PTR_ERR(twl6040->regmap);
 
        i2c_set_clientdata(client, twl6040);
 
        twl6040->supplies[0].supply = "vio";
        twl6040->supplies[1].supply = "v2v1";
        ret = devm_regulator_bulk_get(&client->dev, TWL6040_NUM_SUPPLIES,
-                                twl6040->supplies);
+                                     twl6040->supplies);
        if (ret != 0) {
                dev_err(&client->dev, "Failed to get supplies: %d\n", ret);
                goto regulator_get_err;
@@ -576,44 +583,40 @@ static int twl6040_probe(struct i2c_client *client,
        twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
 
        /* ERRATA: Automatic power-up is not possible in ES1.0 */
-       if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0) {
-               if (pdata)
-                       twl6040->audpwron = pdata->audpwron_gpio;
-               else
-                       twl6040->audpwron = of_get_named_gpio(node,
-                                               "ti,audpwron-gpio", 0);
-       } else
+       if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
+               twl6040->audpwron = of_get_named_gpio(node,
+                                                     "ti,audpwron-gpio", 0);
+       else
                twl6040->audpwron = -EINVAL;
 
        if (gpio_is_valid(twl6040->audpwron)) {
                ret = devm_gpio_request_one(&client->dev, twl6040->audpwron,
-                                       GPIOF_OUT_INIT_LOW, "audpwron");
+                                           GPIOF_OUT_INIT_LOW, "audpwron");
                if (ret)
                        goto gpio_err;
        }
 
-       ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq,
-                       IRQF_ONESHOT, 0, &twl6040_irq_chip,
-                       &twl6040->irq_data);
+       ret = regmap_add_irq_chip(twl6040->regmap, twl6040->irq, IRQF_ONESHOT,
+                                 0, &twl6040_irq_chip,&twl6040->irq_data);
        if (ret < 0)
                goto gpio_err;
 
        twl6040->irq_ready = regmap_irq_get_virq(twl6040->irq_data,
-                                              TWL6040_IRQ_READY);
+                                                TWL6040_IRQ_READY);
        twl6040->irq_th = regmap_irq_get_virq(twl6040->irq_data,
-                                              TWL6040_IRQ_TH);
+                                             TWL6040_IRQ_TH);
 
        ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_ready, NULL,
-                                  twl6040_readyint_handler, IRQF_ONESHOT,
-                                  "twl6040_irq_ready", twl6040);
+                                       twl6040_readyint_handler, IRQF_ONESHOT,
+                                       "twl6040_irq_ready", twl6040);
        if (ret) {
                dev_err(twl6040->dev, "READY IRQ request failed: %d\n", ret);
                goto readyirq_err;
        }
 
        ret = devm_request_threaded_irq(twl6040->dev, twl6040->irq_th, NULL,
-                                  twl6040_thint_handler, IRQF_ONESHOT,
-                                  "twl6040_irq_th", twl6040);
+                                       twl6040_thint_handler, IRQF_ONESHOT,
+                                       "twl6040_irq_th", twl6040);
        if (ret) {
                dev_err(twl6040->dev, "Thermal IRQ request failed: %d\n", ret);
                goto thirq_err;
@@ -625,8 +628,6 @@ static int twl6040_probe(struct i2c_client *client,
        /*
         * The main functionality of twl6040 to provide audio on OMAP4+ systems.
         * We can add the ASoC codec child whenever this driver has been loaded.
-        * The ASoC codec can work without pdata, pass the platform_data only if
-        * it has been provided.
         */
        irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_PLUG);
        cell = &twl6040->cells[children];
@@ -635,13 +636,10 @@ static int twl6040_probe(struct i2c_client *client,
        twl6040_codec_rsrc[0].end = irq;
        cell->resources = twl6040_codec_rsrc;
        cell->num_resources = ARRAY_SIZE(twl6040_codec_rsrc);
-       if (pdata && pdata->codec) {
-               cell->platform_data = pdata->codec;
-               cell->pdata_size = sizeof(*pdata->codec);
-       }
        children++;
 
-       if (twl6040_has_vibra(pdata, node)) {
+       /* Vibra input driver support */
+       if (twl6040_has_vibra(node)) {
                irq = regmap_irq_get_virq(twl6040->irq_data, TWL6040_IRQ_VIB);
 
                cell = &twl6040->cells[children];
@@ -650,28 +648,13 @@ static int twl6040_probe(struct i2c_client *client,
                twl6040_vibra_rsrc[0].end = irq;
                cell->resources = twl6040_vibra_rsrc;
                cell->num_resources = ARRAY_SIZE(twl6040_vibra_rsrc);
-
-               if (pdata && pdata->vibra) {
-                       cell->platform_data = pdata->vibra;
-                       cell->pdata_size = sizeof(*pdata->vibra);
-               }
                children++;
        }
 
-       /*
-        * Enable the GPO driver in the following cases:
-        * DT booted kernel or legacy boot with valid gpo platform_data
-        */
-       if (!pdata || (pdata && pdata->gpo)) {
-               cell = &twl6040->cells[children];
-               cell->name = "twl6040-gpo";
-
-               if (pdata) {
-                       cell->platform_data = pdata->gpo;
-                       cell->pdata_size = sizeof(*pdata->gpo);
-               }
-               children++;
-       }
+       /* GPO support */
+       cell = &twl6040->cells[children];
+       cell->name = "twl6040-gpo";
+       children++;
 
        ret = mfd_add_devices(&client->dev, -1, twl6040->cells, children,
                              NULL, 0, NULL);
@@ -690,7 +673,7 @@ gpio_err:
        regulator_bulk_disable(TWL6040_NUM_SUPPLIES, twl6040->supplies);
 regulator_get_err:
        i2c_set_clientdata(client, NULL);
-err:
+
        return ret;
 }
 
index e9031fa9d53d1983e0dfe5ee5307bf8d24f79857..ebb20edf9c1758a7d6e58ddce9f856dd89bbd860 100644 (file)
@@ -52,7 +52,7 @@ static int ucb1400_core_probe(struct device *dev)
        struct ucb1400_ts ucb_ts;
        struct ucb1400_gpio ucb_gpio;
        struct snd_ac97 *ac97;
-       struct ucb1400_pdata *pdata = dev->platform_data;
+       struct ucb1400_pdata *pdata = dev_get_platdata(dev);
 
        memset(&ucb_ts, 0, sizeof(ucb_ts));
        memset(&ucb_gpio, 0, sizeof(ucb_gpio));
index 70f02daeb22a884da64297f26bc3f43e4e365aa8..d5966e6b5a7d8058a9ff37f15a86204ffe6ffe6c 100644 (file)
@@ -393,22 +393,24 @@ static struct irq_chip ucb1x00_irqchip = {
 static int ucb1x00_add_dev(struct ucb1x00 *ucb, struct ucb1x00_driver *drv)
 {
        struct ucb1x00_dev *dev;
-       int ret = -ENOMEM;
+       int ret;
 
        dev = kmalloc(sizeof(struct ucb1x00_dev), GFP_KERNEL);
-       if (dev) {
-               dev->ucb = ucb;
-               dev->drv = drv;
-
-               ret = drv->add(dev);
-
-               if (ret == 0) {
-                       list_add_tail(&dev->dev_node, &ucb->devs);
-                       list_add_tail(&dev->drv_node, &drv->devs);
-               } else {
-                       kfree(dev);
-               }
+       if (!dev)
+               return -ENOMEM;
+
+       dev->ucb = ucb;
+       dev->drv = drv;
+
+       ret = drv->add(dev);
+       if (ret) {
+               kfree(dev);
+               return ret;
        }
+
+       list_add_tail(&dev->dev_node, &ucb->devs);
+       list_add_tail(&dev->drv_node, &drv->devs);
+
        return ret;
 }
 
@@ -669,9 +671,10 @@ void ucb1x00_unregister_driver(struct ucb1x00_driver *drv)
        mutex_unlock(&ucb1x00_mutex);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int ucb1x00_suspend(struct device *dev)
 {
-       struct ucb1x00_plat_data *pdata = dev->platform_data;
+       struct ucb1x00_plat_data *pdata = dev_get_platdata(dev);
        struct ucb1x00 *ucb = dev_get_drvdata(dev);
        struct ucb1x00_dev *udev;
 
@@ -703,7 +706,7 @@ static int ucb1x00_suspend(struct device *dev)
 
 static int ucb1x00_resume(struct device *dev)
 {
-       struct ucb1x00_plat_data *pdata = dev->platform_data;
+       struct ucb1x00_plat_data *pdata = dev_get_platdata(dev);
        struct ucb1x00 *ucb = dev_get_drvdata(dev);
        struct ucb1x00_dev *udev;
 
@@ -736,6 +739,7 @@ static int ucb1x00_resume(struct device *dev)
        mutex_unlock(&ucb1x00_mutex);
        return 0;
 }
+#endif
 
 static const struct dev_pm_ops ucb1x00_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
index edbe6c1b755a75a467c933a10323860089a33595..f7c52d901040cc5b14f00ebb86a8678ee7918e6d 100644 (file)
@@ -172,12 +172,9 @@ static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
 
 static int wl1273_core_remove(struct i2c_client *client)
 {
-       struct wl1273_core *core = i2c_get_clientdata(client);
-
        dev_dbg(&client->dev, "%s\n", __func__);
 
        mfd_remove_devices(&client->dev);
-       kfree(core);
 
        return 0;
 }
@@ -185,7 +182,7 @@ static int wl1273_core_remove(struct i2c_client *client)
 static int wl1273_core_probe(struct i2c_client *client,
                                       const struct i2c_device_id *id)
 {
-       struct wl1273_fm_platform_data *pdata = client->dev.platform_data;
+       struct wl1273_fm_platform_data *pdata = dev_get_platdata(&client->dev);
        struct wl1273_core *core;
        struct mfd_cell *cell;
        int children = 0;
@@ -203,7 +200,7 @@ static int wl1273_core_probe(struct i2c_client *client,
                return -EINVAL;
        }
 
-       core = kzalloc(sizeof(*core), GFP_KERNEL);
+       core = devm_kzalloc(&client->dev, sizeof(*core), GFP_KERNEL);
        if (!core)
                return -ENOMEM;
 
@@ -249,7 +246,6 @@ static int wl1273_core_probe(struct i2c_client *client,
 
 err:
        pdata->free_resources();
-       kfree(core);
 
        dev_dbg(&client->dev, "%s\n", __func__);
 
index 2a7972349159fb91f27e802addf7790be81c341a..3113e39b318e27a7aa2e74b7433e601edae2da72 100644 (file)
@@ -468,12 +468,14 @@ static const struct reg_default wm5110_reg_default[] = {
        { 0x00000176, 0x0000 },    /* R374   - FLL1 Control 6 */
        { 0x00000177, 0x0281 },    /* R375   - FLL1 Loop Filter Test 1 */
        { 0x00000178, 0x0000 },    /* R376   - FLL1 NCO Test 0 */
+       { 0x00000179, 0x0000 },    /* R376   - FLL1 Control 7 */
        { 0x00000181, 0x0000 },    /* R385   - FLL1 Synchroniser 1 */
        { 0x00000182, 0x0000 },    /* R386   - FLL1 Synchroniser 2 */
        { 0x00000183, 0x0000 },    /* R387   - FLL1 Synchroniser 3 */
        { 0x00000184, 0x0000 },    /* R388   - FLL1 Synchroniser 4 */
        { 0x00000185, 0x0000 },    /* R389   - FLL1 Synchroniser 5 */
        { 0x00000186, 0x0000 },    /* R390   - FLL1 Synchroniser 6 */
+       { 0x00000187, 0x0001 },    /* R390   - FLL1 Synchroniser 7 */
        { 0x00000189, 0x0000 },    /* R393   - FLL1 Spread Spectrum */
        { 0x0000018A, 0x0004 },    /* R394   - FLL1 GPIO Clock */
        { 0x00000191, 0x0000 },    /* R401   - FLL2 Control 1 */
@@ -484,12 +486,14 @@ static const struct reg_default wm5110_reg_default[] = {
        { 0x00000196, 0x0000 },    /* R406   - FLL2 Control 6 */
        { 0x00000197, 0x0000 },    /* R407   - FLL2 Loop Filter Test 1 */
        { 0x00000198, 0x0000 },    /* R408   - FLL2 NCO Test 0 */
+       { 0x00000199, 0x0000 },    /* R408   - FLL2 Control 7 */
        { 0x000001A1, 0x0000 },    /* R417   - FLL2 Synchroniser 1 */
        { 0x000001A2, 0x0000 },    /* R418   - FLL2 Synchroniser 2 */
        { 0x000001A3, 0x0000 },    /* R419   - FLL2 Synchroniser 3 */
        { 0x000001A4, 0x0000 },    /* R420   - FLL2 Synchroniser 4 */
        { 0x000001A5, 0x0000 },    /* R421   - FLL2 Synchroniser 5 */
        { 0x000001A6, 0x0000 },    /* R422   - FLL2 Synchroniser 6 */
+       { 0x000001A7, 0x0001 },    /* R422   - FLL2 Synchroniser 7 */
        { 0x000001A9, 0x0000 },    /* R425   - FLL2 Spread Spectrum */
        { 0x000001AA, 0x0004 },    /* R426   - FLL2 GPIO Clock */
        { 0x00000200, 0x0006 },    /* R512   - Mic Charge Pump 1 */
@@ -503,6 +507,11 @@ static const struct reg_default wm5110_reg_default[] = {
        { 0x0000029C, 0x0000 },    /* R668   - Headphone Detect 2 */
        { 0x000002A3, 0x1102 },    /* R675   - Mic Detect 1 */
        { 0x000002A4, 0x009F },    /* R676   - Mic Detect 2 */
+       { 0x000002A5, 0x0000 },    /* R677   - Mic Detect 3 */
+       { 0x000002A6, 0x3737 },    /* R678   - Mic Detect Level 1 */
+       { 0x000002A7, 0x372C },    /* R679   - Mic Detect Level 2 */
+       { 0x000002A8, 0x1422 },    /* R680   - Mic Detect Level 3 */
+       { 0x000002A9, 0x300A },    /* R681   - Mic Detect Level 4 */
        { 0x000002C3, 0x0000 },    /* R707   - Mic noise mix control 1 */
        { 0x000002D3, 0x0000 },    /* R723   - Jack detect analogue */
        { 0x00000300, 0x0000 },    /* R768   - Input Enables */
@@ -1392,6 +1401,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL1_CONTROL_4:
        case ARIZONA_FLL1_CONTROL_5:
        case ARIZONA_FLL1_CONTROL_6:
+       case ARIZONA_FLL1_CONTROL_7:
        case ARIZONA_FLL1_LOOP_FILTER_TEST_1:
        case ARIZONA_FLL1_NCO_TEST_0:
        case ARIZONA_FLL1_SYNCHRONISER_1:
@@ -1400,6 +1410,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL1_SYNCHRONISER_4:
        case ARIZONA_FLL1_SYNCHRONISER_5:
        case ARIZONA_FLL1_SYNCHRONISER_6:
+       case ARIZONA_FLL1_SYNCHRONISER_7:
        case ARIZONA_FLL1_SPREAD_SPECTRUM:
        case ARIZONA_FLL1_GPIO_CLOCK:
        case ARIZONA_FLL2_CONTROL_1:
@@ -1408,6 +1419,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL2_CONTROL_4:
        case ARIZONA_FLL2_CONTROL_5:
        case ARIZONA_FLL2_CONTROL_6:
+       case ARIZONA_FLL2_CONTROL_7:
        case ARIZONA_FLL2_LOOP_FILTER_TEST_1:
        case ARIZONA_FLL2_NCO_TEST_0:
        case ARIZONA_FLL2_SYNCHRONISER_1:
@@ -1416,6 +1428,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_FLL2_SYNCHRONISER_4:
        case ARIZONA_FLL2_SYNCHRONISER_5:
        case ARIZONA_FLL2_SYNCHRONISER_6:
+       case ARIZONA_FLL2_SYNCHRONISER_7:
        case ARIZONA_FLL2_SPREAD_SPECTRUM:
        case ARIZONA_FLL2_GPIO_CLOCK:
        case ARIZONA_MIC_CHARGE_PUMP_1:
@@ -1430,6 +1443,10 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_MIC_DETECT_1:
        case ARIZONA_MIC_DETECT_2:
        case ARIZONA_MIC_DETECT_3:
+       case ARIZONA_MIC_DETECT_LEVEL_1:
+       case ARIZONA_MIC_DETECT_LEVEL_2:
+       case ARIZONA_MIC_DETECT_LEVEL_3:
+       case ARIZONA_MIC_DETECT_LEVEL_4:
        case ARIZONA_MIC_NOISE_MIX_CONTROL_1:
        case ARIZONA_JACK_DETECT_ANALOGUE:
        case ARIZONA_INPUT_ENABLES:
@@ -2332,6 +2349,7 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
        case ARIZONA_IRQ_PIN_STATUS:
        case ARIZONA_AOD_IRQ1:
        case ARIZONA_AOD_IRQ2:
+       case ARIZONA_FX_CTRL2:
        case ARIZONA_ASRC_STATUS:
        case ARIZONA_DSP_STATUS:
        case ARIZONA_DSP1_CONTROL_1:
index 521340a708d3a76d9ae6ef8241f085bcd623439a..5c459f469224a61719d3258e948c0f0f3ecef856 100644 (file)
@@ -1618,7 +1618,7 @@ EXPORT_SYMBOL_GPL(wm831x_regmap_config);
  */
 int wm831x_device_init(struct wm831x *wm831x, unsigned long id, int irq)
 {
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        int rev, wm831x_num;
        enum wm831x_parent parent;
        int ret, i;
index 804e56ec99eb284f4c32e1f44f8b7a143d4f340c..64e512eadf1718de932218ba2c3f60b7c216e257 100644 (file)
@@ -571,7 +571,7 @@ static struct irq_domain_ops wm831x_irq_domain_ops = {
 
 int wm831x_irq_init(struct wm831x *wm831x, int irq)
 {
-       struct wm831x_pdata *pdata = wm831x->dev->platform_data;
+       struct wm831x_pdata *pdata = dev_get_platdata(wm831x->dev);
        struct irq_domain *domain;
        int i, ret, irq_base;
 
index e7ed14f661d8eb1360d7974ae0bf64ec90ea0401..07de3cc5a0d91db385a8ef755e8bf89d3817477b 100644 (file)
@@ -34,7 +34,6 @@ static int wm831x_spi_probe(struct spi_device *spi)
        if (wm831x == NULL)
                return -ENOMEM;
 
-       spi->bits_per_word = 16;
        spi->mode = SPI_MODE_0;
 
        spi_set_drvdata(spi, wm831x);
index 2e57101c8d3dabfc395f2bf764bddc23a411bbe5..f919def05e24778e53678385075b6fef440e1cf7 100644 (file)
@@ -27,6 +27,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8350 *wm8350;
+       struct wm8350_platform_data *pdata = dev_get_platdata(&i2c->dev);
        int ret = 0;
 
        wm8350 = devm_kzalloc(&i2c->dev, sizeof(struct wm8350), GFP_KERNEL);
@@ -44,7 +45,7 @@ static int wm8350_i2c_probe(struct i2c_client *i2c,
        i2c_set_clientdata(i2c, wm8350);
        wm8350->dev = &i2c->dev;
 
-       return wm8350_device_init(wm8350, i2c->irq, i2c->dev.platform_data);
+       return wm8350_device_init(wm8350, i2c->irq, pdata);
 }
 
 static int wm8350_i2c_remove(struct i2c_client *i2c)
index 639ca359242f849cebfe407333e6107c0bca4bbb..d66d256551fb77768fc9d458d5493c976ec25f30 100644 (file)
@@ -178,7 +178,7 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
        wm8400->dev = &i2c->dev;
        i2c_set_clientdata(i2c, wm8400);
 
-       ret = wm8400_init(wm8400, i2c->dev.platform_data);
+       ret = wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
        if (ret != 0)
                goto err;
 
index 781115e8dca90823bbae297ab4eadc9ff63fa791..e1c283e6d4e54eca7e88e1404ed9d1ec72497cf9 100644 (file)
@@ -201,35 +201,7 @@ static int wm8994_suspend(struct device *dev)
        int ret;
 
        /* Don't actually go through with the suspend if the CODEC is
-        * still active (eg, for audio passthrough from CP. */
-       ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_1);
-       if (ret < 0) {
-               dev_err(dev, "Failed to read power status: %d\n", ret);
-       } else if (ret & WM8994_VMID_SEL_MASK) {
-               dev_dbg(dev, "CODEC still active, ignoring suspend\n");
-               return 0;
-       }
-
-       ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_4);
-       if (ret < 0) {
-               dev_err(dev, "Failed to read power status: %d\n", ret);
-       } else if (ret & (WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA |
-                         WM8994_AIF1ADC2L_ENA | WM8994_AIF1ADC2R_ENA |
-                         WM8994_AIF1ADC1L_ENA | WM8994_AIF1ADC1R_ENA)) {
-               dev_dbg(dev, "CODEC still active, ignoring suspend\n");
-               return 0;
-       }
-
-       ret = wm8994_reg_read(wm8994, WM8994_POWER_MANAGEMENT_5);
-       if (ret < 0) {
-               dev_err(dev, "Failed to read power status: %d\n", ret);
-       } else if (ret & (WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
-                         WM8994_AIF1DAC2L_ENA | WM8994_AIF1DAC2R_ENA |
-                         WM8994_AIF1DAC1L_ENA | WM8994_AIF1DAC1R_ENA)) {
-               dev_dbg(dev, "CODEC still active, ignoring suspend\n");
-               return 0;
-       }
-
+        * still active for accessory detect. */
        switch (wm8994->type) {
        case WM8958:
        case WM1811:
@@ -245,20 +217,6 @@ static int wm8994_suspend(struct device *dev)
                break;
        }
 
-       switch (wm8994->type) {
-       case WM1811:
-               ret = wm8994_reg_read(wm8994, WM8994_ANTIPOP_2);
-               if (ret < 0) {
-                       dev_err(dev, "Failed to read jackdet: %d\n", ret);
-               } else if (ret & WM1811_JACKDET_MODE_MASK) {
-                       dev_dbg(dev, "CODEC still active, ignoring suspend\n");
-                       return 0;
-               }
-               break;
-       default:
-               break;
-       }
-
        /* Disable LDO pulldowns while the device is suspended if we
         * don't know that something will be driving them. */
        if (!wm8994->ldo_ena_always_driven)
index d3a184a240f5e0a7cb683bb330b82d01c15eaeaf..e74dedda5b557caabedf38b045414e7ec7830bd6 100644 (file)
@@ -193,7 +193,7 @@ int wm8994_irq_init(struct wm8994 *wm8994)
 {
        int ret;
        unsigned long irqflags;
-       struct wm8994_pdata *pdata = wm8994->dev->platform_data;
+       struct wm8994_pdata *pdata = dev_get_platdata(wm8994->dev);
 
        if (!wm8994->irq) {
                dev_warn(wm8994->dev,
index 5acb9c5b49c44e16ce57588ccc7fcd45af2cabe1..22429b8b1068e334e3640513f90ea2869ecdc068 100644 (file)
@@ -1,6 +1,6 @@
 config CB710_CORE
        tristate "ENE CB710/720 Flash memory card reader support"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        help
          This option enables support for PCI ENE CB710/720 Flash memory card
          reader found in some laptops (ie. some versions of HP Compaq nx9500).
index cd0b7f4a1ff2dbd58419d92dcb077379c68e3a20..1a3163f1407e2093a43a6a1c61db5a9538f6a329 100644 (file)
@@ -812,7 +812,7 @@ static int mmc_blk_cmd_error(struct request *req, const char *name, int error,
  * Otherwise we don't understand what happened, so abort.
  */
 static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
-       struct mmc_blk_request *brq, int *ecc_err)
+       struct mmc_blk_request *brq, int *ecc_err, int *gen_err)
 {
        bool prev_cmd_status_valid = true;
        u32 status, stop_status = 0;
@@ -850,6 +850,16 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
            (brq->cmd.resp[0] & R1_CARD_ECC_FAILED))
                *ecc_err = 1;
 
+       /* Flag General errors */
+       if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
+               if ((status & R1_ERROR) ||
+                       (brq->stop.resp[0] & R1_ERROR)) {
+                       pr_err("%s: %s: general error sending stop or status command, stop cmd response %#x, card status %#x\n",
+                              req->rq_disk->disk_name, __func__,
+                              brq->stop.resp[0], status);
+                       *gen_err = 1;
+               }
+
        /*
         * Check the current card state.  If it is in some data transfer
         * mode, tell it to stop (and hopefully transition back to TRAN.)
@@ -869,6 +879,13 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
                        return ERR_ABORT;
                if (stop_status & R1_CARD_ECC_FAILED)
                        *ecc_err = 1;
+               if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
+                       if (stop_status & R1_ERROR) {
+                               pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
+                                      req->rq_disk->disk_name, __func__,
+                                      stop_status);
+                               *gen_err = 1;
+                       }
        }
 
        /* Check for set block count errors */
@@ -1097,7 +1114,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
                                                    mmc_active);
        struct mmc_blk_request *brq = &mq_mrq->brq;
        struct request *req = mq_mrq->req;
-       int ecc_err = 0;
+       int ecc_err = 0, gen_err = 0;
 
        /*
         * sbc.error indicates a problem with the set block count
@@ -1111,7 +1128,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
         */
        if (brq->sbc.error || brq->cmd.error || brq->stop.error ||
            brq->data.error) {
-               switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err)) {
+               switch (mmc_blk_cmd_recovery(card, req, brq, &ecc_err, &gen_err)) {
                case ERR_RETRY:
                        return MMC_BLK_RETRY;
                case ERR_ABORT:
@@ -1143,6 +1160,14 @@ static int mmc_blk_err_check(struct mmc_card *card,
                u32 status;
                unsigned long timeout;
 
+               /* Check stop command response */
+               if (brq->stop.resp[0] & R1_ERROR) {
+                       pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
+                              req->rq_disk->disk_name, __func__,
+                              brq->stop.resp[0]);
+                       gen_err = 1;
+               }
+
                timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
                do {
                        int err = get_card_status(card, &status, 5);
@@ -1152,6 +1177,13 @@ static int mmc_blk_err_check(struct mmc_card *card,
                                return MMC_BLK_CMD_ERR;
                        }
 
+                       if (status & R1_ERROR) {
+                               pr_err("%s: %s: general error sending status command, card status %#x\n",
+                                      req->rq_disk->disk_name, __func__,
+                                      status);
+                               gen_err = 1;
+                       }
+
                        /* Timeout if the device never becomes ready for data
                         * and never leaves the program state.
                         */
@@ -1171,6 +1203,13 @@ static int mmc_blk_err_check(struct mmc_card *card,
                         (R1_CURRENT_STATE(status) == R1_STATE_PRG));
        }
 
+       /* if general error occurs, retry the write operation. */
+       if (gen_err) {
+               pr_warn("%s: retrying write for general error\n",
+                               req->rq_disk->disk_name);
+               return MMC_BLK_RETRY;
+       }
+
        if (brq->data.error) {
                pr_err("%s: error %d transferring data, sector %u, nr %u, cmd response %#x, card status %#x\n",
                       req->rq_disk->disk_name, brq->data.error,
@@ -2191,10 +2230,10 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
                 * is freeing the queue that stops new requests
                 * from being accepted.
                 */
+               card = md->queue.card;
                mmc_cleanup_queue(&md->queue);
                if (md->flags & MMC_BLK_PACKED_CMD)
                        mmc_packed_clean(&md->queue);
-               card = md->queue.card;
                if (md->disk->flags & GENHD_FL_UP) {
                        device_remove_file(disk_to_dev(md->disk), &md->force_ro);
                        if ((md->area_type & MMC_BLK_DATA_AREA_BOOT) &&
index a69df5216274d8f017f6f8cc0e96f1419cce784e..0c0fc52d42c538bd3b6e543d050d40c61533551b 100644 (file)
@@ -2849,18 +2849,12 @@ static ssize_t mtf_test_write(struct file *file, const char __user *buf,
        struct seq_file *sf = (struct seq_file *)file->private_data;
        struct mmc_card *card = (struct mmc_card *)sf->private;
        struct mmc_test_card *test;
-       char lbuf[12];
        long testcase;
+       int ret;
 
-       if (count >= sizeof(lbuf))
-               return -EINVAL;
-
-       if (copy_from_user(lbuf, buf, count))
-               return -EFAULT;
-       lbuf[count] = '\0';
-
-       if (strict_strtol(lbuf, 10, &testcase))
-               return -EINVAL;
+       ret = kstrtol_from_user(buf, count, 10, &testcase);
+       if (ret)
+               return ret;
 
        test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL);
        if (!test)
index 5d088551196b6d9eb61f5443817bbbe9a20492c4..bf18b6bfce487b2dd6a77917344c1514dc1aa7a8 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/fault-inject.h>
 #include <linux/random.h>
 #include <linux/slab.h>
+#include <linux/of.h>
 
 #include <linux/mmc/card.h>
 #include <linux/mmc/host.h>
@@ -1196,6 +1197,49 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
 }
 EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
 
+#ifdef CONFIG_OF
+
+/**
+ * mmc_of_parse_voltage - return mask of supported voltages
+ * @np: The device node need to be parsed.
+ * @mask: mask of voltages available for MMC/SD/SDIO
+ *
+ * 1. Return zero on success.
+ * 2. Return negative errno: voltage-range is invalid.
+ */
+int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
+{
+       const u32 *voltage_ranges;
+       int num_ranges, i;
+
+       voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
+       num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
+       if (!voltage_ranges || !num_ranges) {
+               pr_info("%s: voltage-ranges unspecified\n", np->full_name);
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num_ranges; i++) {
+               const int j = i * 2;
+               u32 ocr_mask;
+
+               ocr_mask = mmc_vddrange_to_ocrmask(
+                               be32_to_cpu(voltage_ranges[j]),
+                               be32_to_cpu(voltage_ranges[j + 1]));
+               if (!ocr_mask) {
+                       pr_err("%s: voltage-range #%d is invalid\n",
+                               np->full_name, i);
+                       return -EINVAL;
+               }
+               *mask |= ocr_mask;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(mmc_of_parse_voltage);
+
+#endif /* CONFIG_OF */
+
 #ifdef CONFIG_REGULATOR
 
 /**
index 6fb6f77450cba2237cd2d07a18fc951b5b1397cc..49bc403e31f02f7f10358d33c49030f9fddcf0d1 100644 (file)
@@ -374,7 +374,7 @@ int mmc_of_parse(struct mmc_host *host)
                        if (!(flags & OF_GPIO_ACTIVE_LOW))
                                gpio_inv_cd = true;
 
-                       ret = mmc_gpio_request_cd(host, gpio);
+                       ret = mmc_gpio_request_cd(host, gpio, 0);
                        if (ret < 0) {
                                dev_err(host->parent,
                                        "Failed to request CD GPIO #%d: %d!\n",
index 837fc7386e237e620f408fd740ec702ad43c2c8b..ef183483d5b67934440cd8dc1a8d6910467e6a61 100644 (file)
@@ -531,6 +531,7 @@ mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
 
        data.sg = &sg;
        data.sg_len = 1;
+       mmc_set_data_timeout(&data, card);
        sg_init_one(&sg, data_buf, len);
        mmc_wait_for_req(host, &mrq);
        err = 0;
index 176d125f5b577c697f90396b0243258977239548..5e8823dc3ef613b70e24ff3d6e16c143da2976a2 100644 (file)
@@ -215,7 +215,7 @@ static int mmc_decode_scr(struct mmc_card *card)
 static int mmc_read_ssr(struct mmc_card *card)
 {
        unsigned int au, es, et, eo;
-       int err, i;
+       int err, i, max_au;
        u32 *ssr;
 
        if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
@@ -239,12 +239,15 @@ static int mmc_read_ssr(struct mmc_card *card)
        for (i = 0; i < 16; i++)
                ssr[i] = be32_to_cpu(ssr[i]);
 
+       /* SD3.0 increases max AU size to 64MB (0xF) from 4MB (0x9) */
+       max_au = card->scr.sda_spec3 ? 0xF : 0x9;
+
        /*
         * UNSTUFF_BITS only works with four u32s so we have to offset the
         * bitfield positions accordingly.
         */
        au = UNSTUFF_BITS(ssr, 428 - 384, 4);
-       if (au > 0 && au <= 9) {
+       if (au > 0 && au <= max_au) {
                card->ssr.au = 1 << (au + 4);
                es = UNSTUFF_BITS(ssr, 408 - 384, 16);
                et = UNSTUFF_BITS(ssr, 402 - 384, 6);
@@ -942,13 +945,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        if (!mmc_host_is_spi(host)) {
                err = mmc_send_relative_addr(host, &card->rca);
                if (err)
-                       return err;
+                       goto free_card;
        }
 
        if (!oldcard) {
                err = mmc_sd_get_csd(host, card);
                if (err)
-                       return err;
+                       goto free_card;
 
                mmc_decode_cid(card);
        }
@@ -959,7 +962,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
        if (!mmc_host_is_spi(host)) {
                err = mmc_select_card(card);
                if (err)
-                       return err;
+                       goto free_card;
        }
 
        err = mmc_sd_setup_card(host, card, oldcard != NULL);
index 324235105519ec0045f2f54c6a833bc6fa639b6e..46596b71a32f49d5934c62d3f5323b26cf6c1658 100644 (file)
@@ -135,6 +135,7 @@ EXPORT_SYMBOL(mmc_gpio_request_ro);
  * mmc_gpio_request_cd - request a gpio for card-detection
  * @host: mmc host
  * @gpio: gpio number requested
+ * @debounce: debounce time in microseconds
  *
  * As devm_* managed functions are used in mmc_gpio_request_cd(), client
  * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up,
@@ -143,9 +144,14 @@ EXPORT_SYMBOL(mmc_gpio_request_ro);
  * switching for card-detection, they are responsible for calling
  * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own.
  *
+ * If GPIO debouncing is desired, set the debounce parameter to a non-zero
+ * value. The caller is responsible for ensuring that the GPIO driver associated
+ * with the GPIO supports debouncing, otherwise an error will be returned.
+ *
  * Returns zero on success, else an error.
  */
-int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
+int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
+                       unsigned int debounce)
 {
        struct mmc_gpio *ctx;
        int irq = gpio_to_irq(gpio);
@@ -167,6 +173,12 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio)
                 */
                return ret;
 
+       if (debounce) {
+               ret = gpio_set_debounce(gpio, debounce);
+               if (ret < 0)
+                       return ret;
+       }
+
        /*
         * Even if gpio_to_irq() returns a valid IRQ number, the platform might
         * still prefer to poll, e.g., because that IRQ number is already used
index 8a4c066787d7ca3acd4d38cb6be87c4588e19a05..7fc5099e44b2ccf6c4b4164f37d1343d177e7d5e 100644 (file)
@@ -284,11 +284,11 @@ config MMC_OMAP
 
 config MMC_OMAP_HS
        tristate "TI OMAP High Speed Multimedia Card Interface support"
-       depends on SOC_OMAP2430 || ARCH_OMAP3 || ARCH_OMAP4
+       depends on ARCH_OMAP2PLUS || COMPILE_TEST
        help
          This selects the TI OMAP High Speed Multimedia card Interface.
-         If you have an OMAP2430 or OMAP3 board or OMAP4 board with a
-         Multimedia Card slot, say Y or M here.
+         If you have an omap2plus board with a Multimedia Card slot,
+         say Y or M here.
 
          If unsure, say N.
 
@@ -487,7 +487,7 @@ config MMC_SDHI
 
 config MMC_CB710
        tristate "ENE CB710 MMC/SD Interface support"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        select CB710_CORE
        help
          This option enables support for MMC/SD part of ENE CB710/720 Flash
@@ -530,7 +530,7 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
 
 config MMC_DW
        tristate "Synopsys DesignWare Memory Card Interface"
-       depends on ARM
+       depends on ARC || ARM
        help
          This selects support for the Synopsys DesignWare Mobile Storage IP
          block, this provides host support for SD and MMC interfaces, in both
@@ -569,7 +569,7 @@ config MMC_DW_EXYNOS
 
 config MMC_DW_SOCFPGA
        tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
-       depends on MMC_DW
+       depends on MMC_DW && MFD_SYSCON
        select MMC_DW_PLTFM
        help
          This selects support for Altera SoCFPGA specific extensions to the
index d422e2167e19cc99b5a258c23daa1c22a86b5fa1..c41d0c36450958840242959e7d911576d4f5102d 100644 (file)
@@ -52,8 +52,6 @@ obj-$(CONFIG_MMC_WMT)         += wmt-sdmmc.o
 
 obj-$(CONFIG_MMC_REALTEK_PCI)  += rtsx_pci_sdmmc.o
 
-obj-$(CONFIG_MMC_REALTEK_PCI)  += rtsx_pci_sdmmc.o
-
 obj-$(CONFIG_MMC_SDHCI_PLTFM)          += sdhci-pltfm.o
 obj-$(CONFIG_MMC_SDHCI_CNS3XXX)                += sdhci-cns3xxx.o
 obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX)      += sdhci-esdhc-imx.o
index bdb84da74952b97c8a2e59a9364477e1e9a4bf9b..69e438ee043e6f8a9c151d3447f6a9e418544231 100644 (file)
@@ -378,6 +378,8 @@ static int atmci_regs_show(struct seq_file *s, void *v)
 {
        struct atmel_mci        *host = s->private;
        u32                     *buf;
+       int                     ret = 0;
+
 
        buf = kmalloc(ATMCI_REGS_SIZE, GFP_KERNEL);
        if (!buf)
@@ -388,12 +390,16 @@ static int atmci_regs_show(struct seq_file *s, void *v)
         * not disabling interrupts, so IMR and SR may not be
         * consistent.
         */
+       ret = clk_prepare_enable(host->mck);
+       if (ret)
+               goto out;
+
        spin_lock_bh(&host->lock);
-       clk_enable(host->mck);
        memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
-       clk_disable(host->mck);
        spin_unlock_bh(&host->lock);
 
+       clk_disable_unprepare(host->mck);
+
        seq_printf(s, "MR:\t0x%08x%s%s ",
                        buf[ATMCI_MR / 4],
                        buf[ATMCI_MR / 4] & ATMCI_MR_RDPROOF ? " RDPROOF" : "",
@@ -442,9 +448,10 @@ static int atmci_regs_show(struct seq_file *s, void *v)
                                val & ATMCI_CFG_LSYNC ? " LSYNC" : "");
        }
 
+out:
        kfree(buf);
 
-       return 0;
+       return ret;
 }
 
 static int atmci_regs_open(struct inode *inode, struct file *file)
@@ -1262,6 +1269,7 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        struct atmel_mci_slot   *slot = mmc_priv(mmc);
        struct atmel_mci        *host = slot->host;
        unsigned int            i;
+       bool                    unprepare_clk;
 
        slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
        switch (ios->bus_width) {
@@ -1277,9 +1285,13 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                unsigned int clock_min = ~0U;
                u32 clkdiv;
 
+               clk_prepare(host->mck);
+               unprepare_clk = true;
+
                spin_lock_bh(&host->lock);
                if (!host->mode_reg) {
                        clk_enable(host->mck);
+                       unprepare_clk = false;
                        atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
                        atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
                        if (host->caps.has_cfg_reg)
@@ -1347,6 +1359,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        } else {
                bool any_slot_active = false;
 
+               unprepare_clk = false;
+
                spin_lock_bh(&host->lock);
                slot->clock = 0;
                for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
@@ -1360,12 +1374,16 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                        if (host->mode_reg) {
                                atmci_readl(host, ATMCI_MR);
                                clk_disable(host->mck);
+                               unprepare_clk = true;
                        }
                        host->mode_reg = 0;
                }
                spin_unlock_bh(&host->lock);
        }
 
+       if (unprepare_clk)
+               clk_unprepare(host->mck);
+
        switch (ios->power_mode) {
        case MMC_POWER_UP:
                set_bit(ATMCI_CARD_NEED_INIT, &slot->flags);
@@ -2376,10 +2394,12 @@ static int __init atmci_probe(struct platform_device *pdev)
        if (!host->regs)
                goto err_ioremap;
 
-       clk_enable(host->mck);
+       ret = clk_prepare_enable(host->mck);
+       if (ret)
+               goto err_request_irq;
        atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
        host->bus_hz = clk_get_rate(host->mck);
-       clk_disable(host->mck);
+       clk_disable_unprepare(host->mck);
 
        host->mapbase = regs->start;
 
@@ -2482,11 +2502,11 @@ static int __exit atmci_remove(struct platform_device *pdev)
                        atmci_cleanup_slot(host->slot[i], i);
        }
 
-       clk_enable(host->mck);
+       clk_prepare_enable(host->mck);
        atmci_writel(host, ATMCI_IDR, ~0UL);
        atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
        atmci_readl(host, ATMCI_SR);
-       clk_disable(host->mck);
+       clk_disable_unprepare(host->mck);
 
        if (host->dma.chan)
                dma_release_channel(host->dma.chan);
index 866edef2e820885d94ba47a5c679a0c411fadc48..6a1fa2110a057b42d2a79cfb3407bb0f8fb8f3b8 100644 (file)
@@ -39,6 +39,7 @@ enum dw_mci_exynos_type {
        DW_MCI_TYPE_EXYNOS4210,
        DW_MCI_TYPE_EXYNOS4412,
        DW_MCI_TYPE_EXYNOS5250,
+       DW_MCI_TYPE_EXYNOS5420,
 };
 
 /* Exynos implementation specific driver private data */
@@ -62,6 +63,9 @@ static struct dw_mci_exynos_compatible {
        }, {
                .compatible     = "samsung,exynos5250-dw-mshc",
                .ctrl_type      = DW_MCI_TYPE_EXYNOS5250,
+       }, {
+               .compatible     = "samsung,exynos5420-dw-mshc",
+               .ctrl_type      = DW_MCI_TYPE_EXYNOS5420,
        },
 };
 
@@ -90,7 +94,8 @@ static int dw_mci_exynos_setup_clock(struct dw_mci *host)
 {
        struct dw_mci_exynos_priv_data *priv = host->priv;
 
-       if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250)
+       if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250 ||
+               priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420)
                host->bus_hz /= (priv->ciu_div + 1);
        else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
                host->bus_hz /= EXYNOS4412_FIXED_CIU_CLK_DIV;
@@ -173,6 +178,8 @@ static const struct of_device_id dw_mci_exynos_match[] = {
                        .data = &exynos_drv_data, },
        { .compatible = "samsung,exynos5250-dw-mshc",
                        .data = &exynos_drv_data, },
+       { .compatible = "samsung,exynos5420-dw-mshc",
+                       .data = &exynos_drv_data, },
        {},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
index b456b0c3523140d9763b0e84e9ca55eccf385a62..f70546a3a7ccd33ac893d4b7734db90abbcbe3dc 100644 (file)
@@ -59,7 +59,9 @@ static int dw_mci_pci_probe(struct pci_dev *pdev,
        if (ret)
                return ret;
 
-       host->regs = pcim_iomap_table(pdev)[0];
+       host->regs = pcim_iomap_table(pdev)[PCI_BAR_NO];
+
+       pci_set_master(pdev);
 
        ret = dw_mci_probe(host);
        if (ret)
index ee525565aa77bc03ff08a5a258bedbcb454094e7..20897529ea5e10185a3d39864755ccdbeb8fea6b 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/of.h>
 
 #include "dw_mmc.h"
+#include "dw_mmc-pltfm.h"
 
 static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
index 542407363dd2012992831208cadfc8df592e3163..018f365e5ae46c71a6e8a0f2327e9fb8775c900d 100644 (file)
@@ -1601,18 +1601,17 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
 
        pending = mci_readl(host, MINTSTS); /* read-only mask reg */
 
-       if (pending) {
-
-               /*
-                * DTO fix - version 2.10a and below, and only if internal DMA
-                * is configured.
-                */
-               if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
-                       if (!pending &&
-                           ((mci_readl(host, STATUS) >> 17) & 0x1fff))
-                               pending |= SDMMC_INT_DATA_OVER;
-               }
+       /*
+        * DTO fix - version 2.10a and below, and only if internal DMA
+        * is configured.
+        */
+       if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
+               if (!pending &&
+                   ((mci_readl(host, STATUS) >> 17) & 0x1fff))
+                       pending |= SDMMC_INT_DATA_OVER;
+       }
 
+       if (pending) {
                if (pending & DW_MCI_CMD_ERROR_FLAGS) {
                        mci_writel(host, RINTSTS, DW_MCI_CMD_ERROR_FLAGS);
                        host->cmd_status = pending;
index 0308c9f1cf52793a43c68602c7287be78f5659fa..66516339e3a0fe474533f62fae475283180d701b 100644 (file)
@@ -713,7 +713,7 @@ static int jz4740_mmc_request_gpios(struct mmc_host *mmc,
                mmc->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
 
        if (gpio_is_valid(pdata->gpio_card_detect)) {
-               ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect);
+               ret = mmc_gpio_request_cd(mmc, pdata->gpio_card_detect, 0);
                if (ret)
                        return ret;
        }
@@ -783,9 +783,8 @@ static int jz4740_mmc_probe(struct platform_device* pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->base = devm_ioremap_resource(&pdev->dev, res);
-       if (!host->base) {
-               ret = -EBUSY;
-               dev_err(&pdev->dev, "Failed to ioremap base memory\n");
+       if (IS_ERR(host->base)) {
+               ret = PTR_ERR(host->base);
                goto err_free_host;
        }
 
index 74145d1d51f5d9df1cfd9f287366ce25893b4d15..0a87e56913411a9abab46c99b13053abee3d96af 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>             /* for R1_SPI_* bit values */
+#include <linux/mmc/slot-gpio.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/mmc_spi.h>
@@ -1272,33 +1273,11 @@ static void mmc_spi_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 }
 
-static int mmc_spi_get_ro(struct mmc_host *mmc)
-{
-       struct mmc_spi_host *host = mmc_priv(mmc);
-
-       if (host->pdata && host->pdata->get_ro)
-               return !!host->pdata->get_ro(mmc->parent);
-       /*
-        * Board doesn't support read only detection; let the mmc core
-        * decide what to do.
-        */
-       return -ENOSYS;
-}
-
-static int mmc_spi_get_cd(struct mmc_host *mmc)
-{
-       struct mmc_spi_host *host = mmc_priv(mmc);
-
-       if (host->pdata && host->pdata->get_cd)
-               return !!host->pdata->get_cd(mmc->parent);
-       return -ENOSYS;
-}
-
 static const struct mmc_host_ops mmc_spi_ops = {
        .request        = mmc_spi_request,
        .set_ios        = mmc_spi_set_ios,
-       .get_ro         = mmc_spi_get_ro,
-       .get_cd         = mmc_spi_get_cd,
+       .get_ro         = mmc_gpio_get_ro,
+       .get_cd         = mmc_gpio_get_cd,
 };
 
 
@@ -1324,6 +1303,7 @@ static int mmc_spi_probe(struct spi_device *spi)
        struct mmc_host         *mmc;
        struct mmc_spi_host     *host;
        int                     status;
+       bool                    has_ro = false;
 
        /* We rely on full duplex transfers, mostly to reduce
         * per-transfer overheads (by making fewer transfers).
@@ -1448,18 +1428,33 @@ static int mmc_spi_probe(struct spi_device *spi)
        }
 
        /* pass platform capabilities, if any */
-       if (host->pdata)
+       if (host->pdata) {
                mmc->caps |= host->pdata->caps;
+               mmc->caps2 |= host->pdata->caps2;
+       }
 
        status = mmc_add_host(mmc);
        if (status != 0)
                goto fail_add_host;
 
+       if (host->pdata && host->pdata->flags & MMC_SPI_USE_CD_GPIO) {
+               status = mmc_gpio_request_cd(mmc, host->pdata->cd_gpio,
+                                            host->pdata->cd_debounce);
+               if (status != 0)
+                       goto fail_add_host;
+       }
+
+       if (host->pdata && host->pdata->flags & MMC_SPI_USE_RO_GPIO) {
+               has_ro = true;
+               status = mmc_gpio_request_ro(mmc, host->pdata->ro_gpio);
+               if (status != 0)
+                       goto fail_add_host;
+       }
+
        dev_info(&spi->dev, "SD/MMC host %s%s%s%s%s\n",
                        dev_name(&mmc->class_dev),
                        host->dma_dev ? "" : ", no DMA",
-                       (host->pdata && host->pdata->get_ro)
-                               ? "" : ", no WP",
+                       has_ro ? "" : ", no WP",
                        (host->pdata && host->pdata->setpower)
                                ? "" : ", no poweroff",
                        (mmc->caps & MMC_CAP_NEEDS_POLL)
index 4ddd83f9865852445602623d53c5e273da63cdab..06c5b0b28ebc99f547b88fb9be47a43196872ff8 100644 (file)
@@ -757,7 +757,8 @@ static int __init mvsd_probe(struct platform_device *pdev)
                if (mvsd_data->gpio_card_detect &&
                    gpio_is_valid(mvsd_data->gpio_card_detect)) {
                        ret = mmc_gpio_request_cd(mmc,
-                                                 mvsd_data->gpio_card_detect);
+                                                 mvsd_data->gpio_card_detect,
+                                                 0);
                        if (ret)
                                goto out;
                } else {
index f38d75f46f7806a5633fe91860a68e645dca0201..e1fa3ef735e097e1c3c8e533fedec63d30786f43 100644 (file)
@@ -102,12 +102,15 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc)
                  BM_SSP_STATUS_CARD_DETECT) ^ host->cd_inverted;
 }
 
-static void mxs_mmc_reset(struct mxs_mmc_host *host)
+static int mxs_mmc_reset(struct mxs_mmc_host *host)
 {
        struct mxs_ssp *ssp = &host->ssp;
        u32 ctrl0, ctrl1;
+       int ret;
 
-       stmp_reset_block(ssp->base);
+       ret = stmp_reset_block(ssp->base);
+       if (ret)
+               return ret;
 
        ctrl0 = BM_SSP_CTRL0_IGNORE_CRC;
        ctrl1 = BF_SSP(0x3, CTRL1_SSP_MODE) |
@@ -132,6 +135,7 @@ static void mxs_mmc_reset(struct mxs_mmc_host *host)
 
        writel(ctrl0, ssp->base + HW_SSP_CTRL0);
        writel(ctrl1, ssp->base + HW_SSP_CTRL1(ssp));
+       return 0;
 }
 
 static void mxs_mmc_start_cmd(struct mxs_mmc_host *host,
@@ -618,21 +622,25 @@ static int mxs_mmc_probe(struct platform_device *pdev)
                }
        }
 
-       ssp->clk = clk_get(&pdev->dev, NULL);
+       ssp->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(ssp->clk)) {
                ret = PTR_ERR(ssp->clk);
                goto out_mmc_free;
        }
        clk_prepare_enable(ssp->clk);
 
-       mxs_mmc_reset(host);
+       ret = mxs_mmc_reset(host);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to reset mmc: %d\n", ret);
+               goto out_clk_disable;
+       }
 
        ssp->dmach = dma_request_slave_channel(&pdev->dev, "rx-tx");
        if (!ssp->dmach) {
                dev_err(mmc_dev(host->mmc),
                        "%s: failed to request dma\n", __func__);
                ret = -ENODEV;
-               goto out_clk_put;
+               goto out_clk_disable;
        }
 
        /* set mmc core parameters */
@@ -685,9 +693,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
 out_free_dma:
        if (ssp->dmach)
                dma_release_channel(ssp->dmach);
-out_clk_put:
+out_clk_disable:
        clk_disable_unprepare(ssp->clk);
-       clk_put(ssp->clk);
 out_mmc_free:
        mmc_free_host(mmc);
        return ret;
@@ -705,7 +712,6 @@ static int mxs_mmc_remove(struct platform_device *pdev)
                dma_release_channel(ssp->dmach);
 
        clk_disable_unprepare(ssp->clk);
-       clk_put(ssp->clk);
 
        mmc_free_host(mmc);
 
index d720b5e05b9cb5510125787bacf2025af5f839a5..6e218fb1a669428ea6d2b5ddc2728f7d2f080e33 100644 (file)
@@ -50,25 +50,6 @@ static struct of_mmc_spi *to_of_mmc_spi(struct device *dev)
        return container_of(dev->platform_data, struct of_mmc_spi, pdata);
 }
 
-static int of_mmc_spi_read_gpio(struct device *dev, int gpio_num)
-{
-       struct of_mmc_spi *oms = to_of_mmc_spi(dev);
-       bool active_low = oms->alow_gpios[gpio_num];
-       bool value = gpio_get_value(oms->gpios[gpio_num]);
-
-       return active_low ^ value;
-}
-
-static int of_mmc_spi_get_cd(struct device *dev)
-{
-       return of_mmc_spi_read_gpio(dev, CD_GPIO);
-}
-
-static int of_mmc_spi_get_ro(struct device *dev)
-{
-       return of_mmc_spi_read_gpio(dev, WP_GPIO);
-}
-
 static int of_mmc_spi_init(struct device *dev,
                           irqreturn_t (*irqhandler)(int, void *), void *mmc)
 {
@@ -130,20 +111,22 @@ struct mmc_spi_platform_data *mmc_spi_get_pdata(struct spi_device *spi)
                if (!gpio_is_valid(oms->gpios[i]))
                        continue;
 
-               ret = gpio_request(oms->gpios[i], dev_name(dev));
-               if (ret < 0) {
-                       oms->gpios[i] = -EINVAL;
-                       continue;
-               }
-
                if (gpio_flags & OF_GPIO_ACTIVE_LOW)
                        oms->alow_gpios[i] = true;
        }
 
-       if (gpio_is_valid(oms->gpios[CD_GPIO]))
-               oms->pdata.get_cd = of_mmc_spi_get_cd;
-       if (gpio_is_valid(oms->gpios[WP_GPIO]))
-               oms->pdata.get_ro = of_mmc_spi_get_ro;
+       if (gpio_is_valid(oms->gpios[CD_GPIO])) {
+               oms->pdata.cd_gpio = oms->gpios[CD_GPIO];
+               oms->pdata.flags |= MMC_SPI_USE_CD_GPIO;
+               if (!oms->alow_gpios[CD_GPIO])
+                       oms->pdata.caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
+       }
+       if (gpio_is_valid(oms->gpios[WP_GPIO])) {
+               oms->pdata.ro_gpio = oms->gpios[WP_GPIO];
+               oms->pdata.flags |= MMC_SPI_USE_RO_GPIO;
+               if (!oms->alow_gpios[WP_GPIO])
+                       oms->pdata.caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
+       }
 
        oms->detect_irq = irq_of_parse_and_map(np, 0);
        if (oms->detect_irq != 0) {
@@ -166,15 +149,10 @@ void mmc_spi_put_pdata(struct spi_device *spi)
        struct device *dev = &spi->dev;
        struct device_node *np = dev->of_node;
        struct of_mmc_spi *oms = to_of_mmc_spi(dev);
-       int i;
 
        if (!dev->platform_data || !np)
                return;
 
-       for (i = 0; i < ARRAY_SIZE(oms->gpios); i++) {
-               if (gpio_is_valid(oms->gpios[i]))
-                       gpio_free(oms->gpios[i]);
-       }
        kfree(oms);
        dev->platform_data = NULL;
 }
index 1865321465c40471751f16c6a50ba417cd07171c..6ac63df645c405b0bd6586c7f8d993d940f8c1af 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/debugfs.h>
 #include <linux/dmaengine.h>
 #include <linux/seq_file.h>
+#include <linux/sizes.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
@@ -1041,6 +1042,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
                }
        }
 
+       OMAP_HSMMC_WRITE(host->base, STAT, status);
        if (end_cmd || ((status & CC_EN) && host->cmd))
                omap_hsmmc_cmd_done(host, host->cmd);
        if ((end_trans || (status & TC_EN)) && host->mrq)
@@ -1060,7 +1062,6 @@ static irqreturn_t omap_hsmmc_irq(int irq, void *dev_id)
                omap_hsmmc_do_irq(host, status);
 
                /* Flush posted write */
-               OMAP_HSMMC_WRITE(host->base, STAT, status);
                status = OMAP_HSMMC_READ(host->base, STAT);
        }
 
index 82a35b91cdbc874da2fb9227f30a056be2de233a..375a880e0c5fb899efa5a2de9b77543fcf66d12d 100644 (file)
@@ -1,6 +1,6 @@
 /* Realtek PCI-Express SD/MMC Card Interface driver
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #include <linux/module.h>
@@ -56,7 +55,6 @@ struct realtek_pci_sdmmc {
        bool                    double_clk;
        bool                    eject;
        bool                    initial_mode;
-       bool                    ddr_mode;
        int                     power_state;
 #define SDMMC_POWER_ON         1
 #define SDMMC_POWER_OFF                0
@@ -228,6 +226,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
        int stat_idx = 0;
        u8 rsp_type;
        int rsp_len = 5;
+       bool clock_toggled = false;
 
        dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
                        __func__, cmd_idx, arg);
@@ -271,6 +270,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                                0xFF, SD_CLK_TOGGLE_EN);
                if (err < 0)
                        goto out;
+
+               clock_toggled = true;
        }
 
        rtsx_pci_init_cmd(pcr);
@@ -351,6 +352,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
 
 out:
        cmd->error = err;
+
+       if (err && clock_toggled)
+               rtsx_pci_write_register(pcr, SD_BUS_STAT,
+                               SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
 }
 
 static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
@@ -475,18 +480,24 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host,
        kfree(buf);
 }
 
-static int sd_change_phase(struct realtek_pci_sdmmc *host, u8 sample_point)
+static int sd_change_phase(struct realtek_pci_sdmmc *host,
+               u8 sample_point, bool rx)
 {
        struct rtsx_pcr *pcr = host->pcr;
        int err;
 
-       dev_dbg(sdmmc_dev(host), "%s: sample_point = %d\n",
-                       __func__, sample_point);
+       dev_dbg(sdmmc_dev(host), "%s(%s): sample_point = %d\n",
+                       __func__, rx ? "RX" : "TX", sample_point);
 
        rtsx_pci_init_cmd(pcr);
 
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CHANGE_CLK, CHANGE_CLK);
-       rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPRX_CTL, 0x1F, sample_point);
+       if (rx)
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               SD_VPRX_CTL, 0x1F, sample_point);
+       else
+               rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+                               SD_VPTX_CTL, 0x1F, sample_point);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL, PHASE_NOT_RESET, 0);
        rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
                        PHASE_NOT_RESET, PHASE_NOT_RESET);
@@ -602,7 +613,7 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
        int err;
        u8 cmd[5] = {0};
 
-       err = sd_change_phase(host, sample_point);
+       err = sd_change_phase(host, sample_point, true);
        if (err < 0)
                return err;
 
@@ -664,7 +675,7 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
                if (final_phase == 0xFF)
                        return -EINVAL;
 
-               err = sd_change_phase(host, final_phase);
+               err = sd_change_phase(host, final_phase, true);
                if (err < 0)
                        return err;
        } else {
@@ -833,14 +844,11 @@ static int sd_set_power_mode(struct realtek_pci_sdmmc *host,
        return err;
 }
 
-static int sd_set_timing(struct realtek_pci_sdmmc *host,
-               unsigned char timing, bool *ddr_mode)
+static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
 {
        struct rtsx_pcr *pcr = host->pcr;
        int err = 0;
 
-       *ddr_mode = false;
-
        rtsx_pci_init_cmd(pcr);
 
        switch (timing) {
@@ -857,8 +865,6 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host,
                break;
 
        case MMC_TIMING_UHS_DDR50:
-               *ddr_mode = true;
-
                rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
                                0x0C | SD_ASYNC_FIFO_NOT_RST,
                                SD_DDR_MODE | SD_ASYNC_FIFO_NOT_RST);
@@ -926,7 +932,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 
        sd_set_bus_width(host, ios->bus_width);
        sd_set_power_mode(host, ios->power_mode);
-       sd_set_timing(host, ios->timing, &host->ddr_mode);
+       sd_set_timing(host, ios->timing);
 
        host->vpclk = false;
        host->double_clk = true;
@@ -1121,11 +1127,11 @@ static int sdmmc_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
                        goto out;
        }
 
+out:
        /* Stop toggle SD clock in idle */
        err = rtsx_pci_write_register(pcr, SD_BUS_STAT,
                        SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
 
-out:
        mutex_unlock(&pcr->pcr_mutex);
 
        return err;
@@ -1148,9 +1154,35 @@ static int sdmmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 
        rtsx_pci_start_run(pcr);
 
-       if (!host->ddr_mode)
-               err = sd_tuning_rx(host, MMC_SEND_TUNING_BLOCK);
+       /* Set initial TX phase */
+       switch (mmc->ios.timing) {
+       case MMC_TIMING_UHS_SDR104:
+               err = sd_change_phase(host, SDR104_TX_PHASE(pcr), false);
+               break;
+
+       case MMC_TIMING_UHS_SDR50:
+               err = sd_change_phase(host, SDR50_TX_PHASE(pcr), false);
+               break;
+
+       case MMC_TIMING_UHS_DDR50:
+               err = sd_change_phase(host, DDR50_TX_PHASE(pcr), false);
+               break;
+
+       default:
+               err = 0;
+       }
 
+       if (err)
+               goto out;
+
+       /* Tuning RX phase */
+       if ((mmc->ios.timing == MMC_TIMING_UHS_SDR104) ||
+                       (mmc->ios.timing == MMC_TIMING_UHS_SDR50))
+               err = sd_tuning_rx(host, opcode);
+       else if (mmc->ios.timing == MMC_TIMING_UHS_DDR50)
+               err = sd_change_phase(host, DDR50_RX_PHASE(pcr), true);
+
+out:
        mutex_unlock(&pcr->pcr_mutex);
 
        return err;
index 0584a1c788b8f93326a79ec5f332ef6958f2f52e..36fa2df0466007f7b618aa9986ca9aa098199b32 100644 (file)
@@ -119,7 +119,7 @@ static u8 bcm2835_sdhci_readb(struct sdhci_host *host, int reg)
        return byte;
 }
 
-unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host)
+static unsigned int bcm2835_sdhci_get_min_clock(struct sdhci_host *host)
 {
        return MIN_FREQ;
 }
index 1dd5ba858754320126a67e08469755429a1a2d1c..abc8cf01e6e3317ecc3e95d32aa66236def768e9 100644 (file)
@@ -616,7 +616,7 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
        /* card_detect */
        switch (boarddata->cd_type) {
        case ESDHC_CD_GPIO:
-               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio);
+               err = mmc_gpio_request_cd(host->mmc, boarddata->cd_gpio, 0);
                if (err) {
                        dev_err(mmc_dev(host->mmc),
                                "failed to request card-detect gpio!\n");
index 15039e2d1c122e30a48cb62a8e00a2a5d99d2916..e328252ebf2a7f684d0756dbfe1c1b20935d05ab 100644 (file)
@@ -316,6 +316,7 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
 
        /* call to generic mmc_of_parse to support additional capabilities */
        mmc_of_parse(host->mmc);
+       mmc_of_parse_voltage(np, &host->ocr_mask);
 
        ret = sdhci_add_host(host);
        if (ret)
index bf99359a3a90cbcc647c2433288243846a0f5eb1..793dacd3b8413c5cd4eae8fc39c420c4f3ffdb5c 100644 (file)
@@ -278,7 +278,8 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                        host->mmc->pm_caps |= pdata->pm_caps;
 
                if (gpio_is_valid(pdata->ext_cd_gpio)) {
-                       ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio);
+                       ret = mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio,
+                                                 0);
                        if (ret) {
                                dev_err(mmc_dev(host->mmc),
                                        "failed to allocate card detect gpio\n");
index 926aaf6acc678d43e7abc28e96890c18886d6563..6debda9521556c530d141cb3fa898af4175a6286 100644 (file)
@@ -296,9 +296,12 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
        unsigned long timeout;
        u16 clk = 0;
 
-       /* don't bother if the clock is going off */
-       if (clock == 0)
+       /* If the clock is going off, set to 0 at clock control register */
+       if (clock == 0) {
+               sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
+               host->clock = clock;
                return;
+       }
 
        sdhci_s3c_set_clock(host, clock);
 
@@ -608,6 +611,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        host->hw_name = "samsung-hsmmc";
        host->ops = &sdhci_s3c_ops;
        host->quirks = 0;
+       host->quirks2 = 0;
        host->irq = irq;
 
        /* Setup quirks for the controller */
index 62a4a835acc67d11a1e7985d7c8f6484c6264f80..696122c1b468b315968128fb5a414fee21c740bd 100644 (file)
@@ -84,7 +84,7 @@ static int sdhci_sirf_probe(struct platform_device *pdev)
         * gets setup in sdhci_add_host() and we oops.
         */
        if (gpio_is_valid(priv->gpio_cd)) {
-               ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd);
+               ret = mmc_gpio_request_cd(host->mmc, priv->gpio_cd, 0);
                if (ret) {
                        dev_err(&pdev->dev, "card detect irq request failed: %d\n",
                                ret);
index dd2c083c434da3f075c6b3566085f2555683315e..7a7fb4f0d5a43a4829fa1e258afbf112f4dd9b82 100644 (file)
@@ -3119,6 +3119,9 @@ int sdhci_add_host(struct sdhci_host *host)
                                   SDHCI_MAX_CURRENT_MULTIPLIER;
        }
 
+       if (host->ocr_mask)
+               ocr_avail = host->ocr_mask;
+
        mmc->ocr_avail = ocr_avail;
        mmc->ocr_avail_sdio = ocr_avail;
        if (host->ocr_avail_sdio)
@@ -3213,6 +3216,8 @@ int sdhci_add_host(struct sdhci_host *host)
                host->tuning_timer.function = sdhci_tuning_timer;
        }
 
+       sdhci_init(host, 0);
+
        ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
                mmc_hostname(mmc), host);
        if (ret) {
@@ -3221,8 +3226,6 @@ int sdhci_add_host(struct sdhci_host *host)
                goto untasklet;
        }
 
-       sdhci_init(host, 0);
-
 #ifdef CONFIG_MMC_DEBUG
        sdhci_dumpregs(host);
 #endif
index 6706b5e3b9747ae78bf47f1c9f7267ac3123f772..36629a024aa1350e6278237f42a6d92e97b33807 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_qos.h>
 #include <linux/pm_runtime.h>
+#include <linux/sh_dma.h>
 #include <linux/spinlock.h>
 #include <linux/module.h>
 
                                 INT_BUFWEN | INT_CMD12DRE | INT_BUFRE | \
                                 INT_DTRANE | INT_CMD12RBE | INT_CMD12CRE)
 
+#define INT_CCS                        (INT_CCSTO | INT_CCSRCV | INT_CCSDE)
+
 /* CE_INT_MASK */
 #define MASK_ALL               0x00000000
 #define MASK_MCCSDE            (1 << 29)
 
 #define MASK_START_CMD         (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \
                                 MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \
-                                MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | \
+                                MASK_MCRCSTO | MASK_MWDATTO | \
                                 MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO)
 
 #define MASK_CLEAN             (INT_ERR_STS | MASK_MRBSYE | MASK_MCRSPE |      \
@@ -243,6 +246,8 @@ struct sh_mmcif_host {
        int sg_blkidx;
        bool power;
        bool card_present;
+       bool ccs_enable;                /* Command Completion Signal support */
+       bool clk_ctrl2_enable;
        struct mutex thread_lock;
 
        /* DMA support */
@@ -386,25 +391,29 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
 
        host->dma_active = false;
 
-       if (!pdata)
-               return;
-
-       if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
+       if (pdata) {
+               if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
+                       return;
+       } else if (!host->pd->dev.of_node) {
                return;
+       }
 
        /* We can only either use DMA for both Tx and Rx or not use it at all */
        dma_cap_zero(mask);
        dma_cap_set(DMA_SLAVE, mask);
 
-       host->chan_tx = dma_request_channel(mask, shdma_chan_filter,
-                                           (void *)pdata->slave_id_tx);
+       host->chan_tx = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+                               pdata ? (void *)pdata->slave_id_tx : NULL,
+                               &host->pd->dev, "tx");
        dev_dbg(&host->pd->dev, "%s: TX: got channel %p\n", __func__,
                host->chan_tx);
 
        if (!host->chan_tx)
                return;
 
-       cfg.slave_id = pdata->slave_id_tx;
+       /* In the OF case the driver will get the slave ID from the DT */
+       if (pdata)
+               cfg.slave_id = pdata->slave_id_tx;
        cfg.direction = DMA_MEM_TO_DEV;
        cfg.dst_addr = res->start + MMCIF_CE_DATA;
        cfg.src_addr = 0;
@@ -412,15 +421,17 @@ static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
        if (ret < 0)
                goto ecfgtx;
 
-       host->chan_rx = dma_request_channel(mask, shdma_chan_filter,
-                                           (void *)pdata->slave_id_rx);
+       host->chan_rx = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+                               pdata ? (void *)pdata->slave_id_rx : NULL,
+                               &host->pd->dev, "rx");
        dev_dbg(&host->pd->dev, "%s: RX: got channel %p\n", __func__,
                host->chan_rx);
 
        if (!host->chan_rx)
                goto erqrx;
 
-       cfg.slave_id = pdata->slave_id_rx;
+       if (pdata)
+               cfg.slave_id = pdata->slave_id_rx;
        cfg.direction = DMA_DEV_TO_MEM;
        cfg.dst_addr = 0;
        cfg.src_addr = res->start + MMCIF_CE_DATA;
@@ -485,8 +496,12 @@ static void sh_mmcif_sync_reset(struct sh_mmcif_host *host)
 
        sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON);
        sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF);
+       if (host->ccs_enable)
+               tmp |= SCCSTO_29;
+       if (host->clk_ctrl2_enable)
+               sh_mmcif_writel(host->addr, MMCIF_CE_CLK_CTRL2, 0x0F0F0000);
        sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp |
-               SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29);
+               SRSPTO_256 | SRBSYTO_29 | SRWDTO_29);
        /* byte swap on */
        sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP);
 }
@@ -866,6 +881,9 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
                break;
        }
 
+       if (host->ccs_enable)
+               mask |= MASK_MCCSTO;
+
        if (mrq->data) {
                sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0);
                sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET,
@@ -873,7 +891,10 @@ static void sh_mmcif_start_cmd(struct sh_mmcif_host *host,
        }
        opc = sh_mmcif_set_cmd(host, mrq);
 
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
+       if (host->ccs_enable)
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0);
+       else
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0 | INT_CCS);
        sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask);
        /* set arg */
        sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg);
@@ -956,11 +977,8 @@ static int sh_mmcif_clk_update(struct sh_mmcif_host *host)
 
 static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)
 {
-       struct sh_mmcif_plat_data *pd = host->pd->dev.platform_data;
        struct mmc_host *mmc = host->mmc;
 
-       if (pd && pd->set_pwr)
-               pd->set_pwr(host->pd, ios->power_mode != MMC_POWER_OFF);
        if (!IS_ERR(mmc->supply.vmmc))
                /* Errors ignored... */
                mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
@@ -1241,11 +1259,14 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
 static irqreturn_t sh_mmcif_intr(int irq, void *dev_id)
 {
        struct sh_mmcif_host *host = dev_id;
-       u32 state;
+       u32 state, mask;
 
        state = sh_mmcif_readl(host->addr, MMCIF_CE_INT);
-       sh_mmcif_writel(host->addr, MMCIF_CE_INT,
-                       ~(state & sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK)));
+       mask = sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK);
+       if (host->ccs_enable)
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(state & mask));
+       else
+               sh_mmcif_writel(host->addr, MMCIF_CE_INT, INT_CCS | ~(state & mask));
        sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state & MASK_CLEAN);
 
        if (state & ~MASK_CLEAN)
@@ -1379,6 +1400,8 @@ static int sh_mmcif_probe(struct platform_device *pdev)
        host->mmc       = mmc;
        host->addr      = reg;
        host->timeout   = msecs_to_jiffies(1000);
+       host->ccs_enable = !pd || !pd->ccs_unsupported;
+       host->clk_ctrl2_enable = pd && pd->clk_ctrl2_present;
 
        host->pd = pdev;
 
@@ -1436,7 +1459,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
        }
 
        if (pd && pd->use_cd_gpio) {
-               ret = mmc_gpio_request_cd(mmc, pd->cd_gpio);
+               ret = mmc_gpio_request_cd(mmc, pd->cd_gpio, 0);
                if (ret < 0)
                        goto erqcd;
        }
index ebea749297c2040f63ea65a24220da57a2f02a55..87ed3fb5149ace85aef3338526741e5010ee1d9d 100644 (file)
@@ -70,20 +70,6 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
        clk_disable(priv->clk);
 }
 
-static void sh_mobile_sdhi_set_pwr(struct platform_device *pdev, int state)
-{
-       struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-
-       p->set_pwr(pdev, state);
-}
-
-static int sh_mobile_sdhi_get_cd(struct platform_device *pdev)
-{
-       struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
-
-       return p->get_cd(pdev);
-}
-
 static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
 {
        int timeout = 1000;
@@ -129,7 +115,12 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = {
 static const struct of_device_id sh_mobile_sdhi_of_match[] = {
        { .compatible = "renesas,shmobile-sdhi" },
        { .compatible = "renesas,sh7372-sdhi" },
+       { .compatible = "renesas,sh73a0-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,r8a73a4-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
        { .compatible = "renesas,r8a7740-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,r8a7778-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,r8a7779-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,r8a7790-sdhi", .data = &sh_mobile_sdhi_of_cfg[0], },
        {},
 };
 MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
@@ -180,10 +171,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
                mmc_data->capabilities |= p->tmio_caps;
                mmc_data->capabilities2 |= p->tmio_caps2;
                mmc_data->cd_gpio = p->cd_gpio;
-               if (p->set_pwr)
-                       mmc_data->set_pwr = sh_mobile_sdhi_set_pwr;
-               if (p->get_cd)
-                       mmc_data->get_cd = sh_mobile_sdhi_get_cd;
 
                if (p->dma_slave_tx > 0 && p->dma_slave_rx > 0) {
                        /*
index 47bdb8fa341bf7f7428bec7180a26aa66bfa8d64..65edb4a62452dc09dfb5318f0adaef6b6f3b2e17 100644 (file)
@@ -104,6 +104,7 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
 pio:
        if (!desc) {
                /* DMA failed, fall back to PIO */
+               tmio_mmc_enable_dma(host, false);
                if (ret >= 0)
                        ret = -EIO;
                host->chan_rx = NULL;
@@ -116,7 +117,6 @@ pio:
                }
                dev_warn(&host->pdev->dev,
                         "DMA failed: %d, falling back to PIO\n", ret);
-               tmio_mmc_enable_dma(host, false);
        }
 
        dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__,
@@ -185,6 +185,7 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
 pio:
        if (!desc) {
                /* DMA failed, fall back to PIO */
+               tmio_mmc_enable_dma(host, false);
                if (ret >= 0)
                        ret = -EIO;
                host->chan_tx = NULL;
@@ -197,7 +198,6 @@ pio:
                }
                dev_warn(&host->pdev->dev,
                         "DMA failed: %d, falling back to PIO\n", ret);
-               tmio_mmc_enable_dma(host, false);
        }
 
        dev_dbg(&host->pdev->dev, "%s(): desc %p, cookie %d\n", __func__,
index b72edb72f7d269ccbeb75ff3c9193974e3d11a3e..b3802256f954b24d7da9f2b3dae35eed4091cae1 100644 (file)
@@ -795,9 +795,13 @@ static void tmio_mmc_power_on(struct tmio_mmc_host *host, unsigned short vdd)
         * omap_hsmmc.c driver does.
         */
        if (!IS_ERR(mmc->supply.vqmmc) && !ret) {
-               regulator_enable(mmc->supply.vqmmc);
+               ret = regulator_enable(mmc->supply.vqmmc);
                udelay(200);
        }
+
+       if (ret < 0)
+               dev_dbg(&host->pdev->dev, "Regulators failed to power up: %d\n",
+                       ret);
 }
 
 static void tmio_mmc_power_off(struct tmio_mmc_host *host)
@@ -932,25 +936,11 @@ static int tmio_mmc_get_ro(struct mmc_host *mmc)
                 (sd_ctrl_read32(host, CTL_STATUS) & TMIO_STAT_WRPROTECT));
 }
 
-static int tmio_mmc_get_cd(struct mmc_host *mmc)
-{
-       struct tmio_mmc_host *host = mmc_priv(mmc);
-       struct tmio_mmc_data *pdata = host->pdata;
-       int ret = mmc_gpio_get_cd(mmc);
-       if (ret >= 0)
-               return ret;
-
-       if (!pdata->get_cd)
-               return -ENOSYS;
-       else
-               return pdata->get_cd(host->pdev);
-}
-
 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,
-       .get_cd         = tmio_mmc_get_cd,
+       .get_cd         = mmc_gpio_get_cd,
        .enable_sdio_irq = tmio_mmc_enable_sdio_irq,
 };
 
@@ -1106,7 +1096,7 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
        dev_pm_qos_expose_latency_limit(&pdev->dev, 100);
 
        if (pdata->flags & TMIO_MMC_USE_GPIO_CD) {
-               ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio);
+               ret = mmc_gpio_request_cd(mmc, pdata->cd_gpio, 0);
                if (ret < 0) {
                        tmio_mmc_host_remove(_host);
                        return ret;
index cb9f361c03ab2d6f45edcb261b3907bb5bcdb7ec..e9028ad05ffbe3fe070e91ff9f7dda4a6a71bdd3 100644 (file)
@@ -2079,7 +2079,7 @@ static void vub300_enable_sdio_irq(struct mmc_host *mmc, int enable)
        kref_put(&vub300->kref, vub300_delete);
 }
 
-void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
+static void vub300_init_card(struct mmc_host *mmc, struct mmc_card *card)
 {                              /* NOT irq */
        struct vub300_mmc_host *vub300 = mmc_priv(mmc);
        dev_info(&vub300->udev->dev, "NO host QUIRKS for this card\n");
index 6eeb84c81bc2ceb16a451fae1bc4194505b2dc7f..5c813907661c3415c979b1176bf937f7c086f2c8 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright Â© 2006-2008  Florian Fainelli <florian@openwrt.org>
  *                       Mike Albon <malbon@openwrt.org>
  * Copyright Â© 2009-2010  Daniel Dickinson <openwrt@cshore.neomailbox.net>
- * Copyright Â© 2011-2012  Jonas Gorski <jonas.gorski@gmail.com>
+ * Copyright Â© 2011-2013  Jonas Gorski <jonas.gorski@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/crc32.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/sizes.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 
+#include <asm/mach-bcm63xx/bcm63xx_nvram.h>
 #include <asm/mach-bcm63xx/bcm963xx_tag.h>
 #include <asm/mach-bcm63xx/board_bcm963xx.h>
 
 #define BCM63XX_EXTENDED_SIZE  0xBFC00000      /* Extended flash address */
 
-#define BCM63XX_CFE_BLOCK_SIZE 0x10000         /* always at least 64KiB */
+#define BCM63XX_CFE_BLOCK_SIZE SZ_64K          /* always at least 64KiB */
 
 #define BCM63XX_CFE_MAGIC_OFFSET 0x4e0
 
@@ -90,7 +92,8 @@ static int bcm63xx_parse_cfe_partitions(struct mtd_info *master,
                              BCM63XX_CFE_BLOCK_SIZE);
 
        cfelen = cfe_erasesize;
-       nvramlen = cfe_erasesize;
+       nvramlen = bcm63xx_nvram_get_psi_size() * SZ_1K;
+       nvramlen = roundup(nvramlen, cfe_erasesize);
 
        /* Allocate memory for buffer */
        buf = vmalloc(sizeof(struct bcm_tag));
index fff665d59a0dba759f63854bb95e25bbb998b64f..89b9d689153298f3b7a3965adf811a3d9963de7c 100644 (file)
@@ -1571,8 +1571,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
        xip_enable(map, chip, adr);
        /* FIXME - should have reset delay before continuing */
 
-       printk(KERN_WARNING "MTD %s(): software timeout\n",
-              __func__ );
+       printk(KERN_WARNING "MTD %s(): software timeout, address:0x%.8lx.\n",
+              __func__, adr);
 
        ret = -EIO;
  op_done:
index 74dbb6bcf4883a8a0461685ea0f180de7ad3da0d..ffb36ba8a6e050e0d8da73a7661cd7734905707d 100644 (file)
@@ -211,9 +211,7 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map,
 
        probe_function = __symbol_get(probename);
        if (!probe_function) {
-               char modname[sizeof("cfi_cmdset_%4.4X")];
-               sprintf(modname, "cfi_cmdset_%4.4X", type);
-               request_module(modname);
+               request_module("cfi_cmdset_%4.4X", type);
                probe_function = __symbol_get(probename);
        }
 
index c443f527a53a5d9dae069701c9b1e0c497e63999..7c0b27d132b1bca8aa546cedac726cf5e92c6613 100644 (file)
 #define PM49FL008      0x006A
 
 /* Sharp */
-#define LH28F640BF     0x00b0
+#define LH28F640BF     0x00B0
 
 /* ST - www.st.com */
 #define M29F800AB      0x0058
@@ -1299,13 +1299,14 @@ static const struct amd_flash_info jedec_table[] = {
                .mfr_id         = CFI_MFR_SHARP,
                .dev_id         = LH28F640BF,
                .name           = "LH28F640BF",
-               .devtypes       = CFI_DEVICETYPE_X8,
+               .devtypes       = CFI_DEVICETYPE_X16,
                .uaddr          = MTD_UADDR_UNNECESSARY,
-               .dev_size       = SIZE_4MiB,
-               .cmd_set        = P_ID_INTEL_STD,
-               .nr_regions     = 1,
+               .dev_size       = SIZE_8MiB,
+               .cmd_set        = P_ID_INTEL_EXT,
+               .nr_regions     = 2,
                .regions        = {
-                       ERASEINFO(0x40000,16),
+                       ERASEINFO(0x10000, 127),
+                       ERASEINFO(0x02000, 8),
                }
        }, {
                .mfr_id         = CFI_MFR_SST,
index 2a4d55e4b3628b7437fb82d7d51a929c92cf79e2..74ab4b7e523eb821c0ee6ceedf85a3ac23b7c473 100644 (file)
@@ -224,59 +224,4 @@ config BCH_CONST_T
        default 4
 endif
 
-config MTD_DOCPROBE
-       tristate
-       select MTD_DOCECC
-
-config MTD_DOCECC
-       tristate
-
-config MTD_DOCPROBE_ADVANCED
-       bool "Advanced detection options for DiskOnChip"
-       depends on MTD_DOCPROBE
-       help
-         This option allows you to specify nonstandard address at which to
-         probe for a DiskOnChip, or to change the detection options.  You
-         are unlikely to need any of this unless you are using LinuxBIOS.
-         Say 'N'.
-
-config MTD_DOCPROBE_ADDRESS
-       hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED
-       depends on MTD_DOCPROBE
-       default "0x0"
-       ---help---
-         By default, the probe for DiskOnChip devices will look for a
-         DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-         This option allows you to specify a single address at which to probe
-         for the device, which is useful if you have other devices in that
-         range which get upset when they are probed.
-
-         (Note that on PowerPC, the normal probe will only check at
-         0xE4000000.)
-
-         Normally, you should leave this set to zero, to allow the probe at
-         the normal addresses.
-
-config MTD_DOCPROBE_HIGH
-       bool "Probe high addresses"
-       depends on MTD_DOCPROBE_ADVANCED
-       help
-         By default, the probe for DiskOnChip devices will look for a
-         DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000.
-         This option changes to make it probe between 0xFFFC8000 and
-         0xFFFEE000.  Unless you are using LinuxBIOS, this is unlikely to be
-         useful to you.  Say 'N'.
-
-config MTD_DOCPROBE_55AA
-       bool "Probe for 0x55 0xAA BIOS Extension Signature"
-       depends on MTD_DOCPROBE_ADVANCED
-       help
-         Check for the 0x55 0xAA signature of a DiskOnChip, and do not
-         continue with probing if it is absent.  The signature will always be
-         present for a DiskOnChip 2000 or a normal DiskOnChip Millennium.
-         Only if you have overwritten the first block of a DiskOnChip
-         Millennium will it be absent.  Enable this option if you are using
-         LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
-         you have managed to wipe the first block.
-
 endmenu
index 18e7761137a33037a21aa61585e20d98f47b172e..77de29bc02ba03069609d6aeff8afa9691cf8d4c 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
@@ -12,6 +13,93 @@ MODULE_DESCRIPTION("Serial flash driver for BCMA bus");
 
 static const char * const probes[] = { "bcm47xxpart", NULL };
 
+/**************************************************
+ * Various helpers
+ **************************************************/
+
+static void bcm47xxsflash_cmd(struct bcm47xxsflash *b47s, u32 opcode)
+{
+       int i;
+
+       b47s->cc_write(b47s, BCMA_CC_FLASHCTL, BCMA_CC_FLASHCTL_START | opcode);
+       for (i = 0; i < 1000; i++) {
+               if (!(b47s->cc_read(b47s, BCMA_CC_FLASHCTL) &
+                     BCMA_CC_FLASHCTL_BUSY))
+                       return;
+               cpu_relax();
+       }
+       pr_err("Control command failed (timeout)!\n");
+}
+
+static int bcm47xxsflash_poll(struct bcm47xxsflash *b47s, int timeout)
+{
+       unsigned long deadline = jiffies + timeout;
+
+       do {
+               switch (b47s->type) {
+               case BCM47XXSFLASH_TYPE_ST:
+                       bcm47xxsflash_cmd(b47s, OPCODE_ST_RDSR);
+                       if (!(b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
+                             SR_ST_WIP))
+                               return 0;
+                       break;
+               case BCM47XXSFLASH_TYPE_ATMEL:
+                       bcm47xxsflash_cmd(b47s, OPCODE_AT_STATUS);
+                       if (b47s->cc_read(b47s, BCMA_CC_FLASHDATA) &
+                           SR_AT_READY)
+                               return 0;
+                       break;
+               }
+
+               cpu_relax();
+               udelay(1);
+       } while (!time_after_eq(jiffies, deadline));
+
+       pr_err("Timeout waiting for flash to be ready!\n");
+
+       return -EBUSY;
+}
+
+/**************************************************
+ * MTD ops
+ **************************************************/
+
+static int bcm47xxsflash_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+       struct bcm47xxsflash *b47s = mtd->priv;
+       int err;
+
+       switch (b47s->type) {
+       case BCM47XXSFLASH_TYPE_ST:
+               bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
+               b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr);
+               /* Newer flashes have "sub-sectors" which can be erased
+                * independently with a new command: ST_SSE. The ST_SE command
+                * erases 64KB just as before.
+                */
+               if (b47s->blocksize < (64 * 1024))
+                       bcm47xxsflash_cmd(b47s, OPCODE_ST_SSE);
+               else
+                       bcm47xxsflash_cmd(b47s, OPCODE_ST_SE);
+               break;
+       case BCM47XXSFLASH_TYPE_ATMEL:
+               b47s->cc_write(b47s, BCMA_CC_FLASHADDR, erase->addr << 1);
+               bcm47xxsflash_cmd(b47s, OPCODE_AT_PAGE_ERASE);
+               break;
+       }
+
+       err = bcm47xxsflash_poll(b47s, HZ);
+       if (err)
+               erase->state = MTD_ERASE_FAILED;
+       else
+               erase->state = MTD_ERASE_DONE;
+
+       if (erase->callback)
+               erase->callback(erase);
+
+       return err;
+}
+
 static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
                              size_t *retlen, u_char *buf)
 {
@@ -28,6 +116,127 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len,
        return len;
 }
 
+static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len,
+                                 const u_char *buf)
+{
+       struct bcm47xxsflash *b47s = mtd->priv;
+       int written = 0;
+
+       /* Enable writes */
+       bcm47xxsflash_cmd(b47s, OPCODE_ST_WREN);
+
+       /* Write first byte */
+       b47s->cc_write(b47s, BCMA_CC_FLASHADDR, offset);
+       b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
+
+       /* Program page */
+       if (b47s->bcma_cc->core->id.rev < 20) {
+               bcm47xxsflash_cmd(b47s, OPCODE_ST_PP);
+               return 1; /* 1B written */
+       }
+
+       /* Program page and set CSA (on newer chips we can continue writing) */
+       bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | OPCODE_ST_PP);
+       offset++;
+       len--;
+       written++;
+
+       while (len > 0) {
+               /* Page boundary, another function call is needed */
+               if ((offset & 0xFF) == 0)
+                       break;
+
+               bcm47xxsflash_cmd(b47s, OPCODE_ST_CSA | *buf++);
+               offset++;
+               len--;
+               written++;
+       }
+
+       /* All done, drop CSA & poll */
+       b47s->cc_write(b47s, BCMA_CC_FLASHCTL, 0);
+       udelay(1);
+       if (bcm47xxsflash_poll(b47s, HZ / 10))
+               pr_err("Flash rejected dropping CSA\n");
+
+       return written;
+}
+
+static int bcm47xxsflash_write_at(struct mtd_info *mtd, u32 offset, size_t len,
+                                 const u_char *buf)
+{
+       struct bcm47xxsflash *b47s = mtd->priv;
+       u32 mask = b47s->blocksize - 1;
+       u32 page = (offset & ~mask) << 1;
+       u32 byte = offset & mask;
+       int written = 0;
+
+       /* If we don't overwrite whole page, read it to the buffer first */
+       if (byte || (len < b47s->blocksize)) {
+               int err;
+
+               b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
+               bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_LOAD);
+               /* 250 us for AT45DB321B */
+               err = bcm47xxsflash_poll(b47s, HZ / 1000);
+               if (err) {
+                       pr_err("Timeout reading page 0x%X info buffer\n", page);
+                       return err;
+               }
+       }
+
+       /* Change buffer content with our data */
+       while (len > 0) {
+               /* Page boundary, another function call is needed */
+               if (byte == b47s->blocksize)
+                       break;
+
+               b47s->cc_write(b47s, BCMA_CC_FLASHADDR, byte++);
+               b47s->cc_write(b47s, BCMA_CC_FLASHDATA, *buf++);
+               bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_WRITE);
+               len--;
+               written++;
+       }
+
+       /* Program page with the buffer content */
+       b47s->cc_write(b47s, BCMA_CC_FLASHADDR, page);
+       bcm47xxsflash_cmd(b47s, OPCODE_AT_BUF1_PROGRAM);
+
+       return written;
+}
+
+static int bcm47xxsflash_write(struct mtd_info *mtd, loff_t to, size_t len,
+                              size_t *retlen, const u_char *buf)
+{
+       struct bcm47xxsflash *b47s = mtd->priv;
+       int written;
+
+       /* Writing functions can return without writing all passed data, for
+        * example when the hardware is too old or when we git page boundary.
+        */
+       while (len > 0) {
+               switch (b47s->type) {
+               case BCM47XXSFLASH_TYPE_ST:
+                       written = bcm47xxsflash_write_st(mtd, to, len, buf);
+                       break;
+               case BCM47XXSFLASH_TYPE_ATMEL:
+                       written = bcm47xxsflash_write_at(mtd, to, len, buf);
+                       break;
+               default:
+                       BUG_ON(1);
+               }
+               if (written < 0) {
+                       pr_err("Error writing at offset 0x%llX\n", to);
+                       return written;
+               }
+               to += (loff_t)written;
+               len -= written;
+               *retlen += written;
+               buf += written;
+       }
+
+       return 0;
+}
+
 static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
 {
        struct mtd_info *mtd = &b47s->mtd;
@@ -35,33 +244,48 @@ static void bcm47xxsflash_fill_mtd(struct bcm47xxsflash *b47s)
        mtd->priv = b47s;
        mtd->name = "bcm47xxsflash";
        mtd->owner = THIS_MODULE;
-       mtd->type = MTD_ROM;
+
+       mtd->type = MTD_NORFLASH;
+       mtd->flags = MTD_CAP_NORFLASH;
        mtd->size = b47s->size;
-       mtd->_read = bcm47xxsflash_read;
+       mtd->erasesize = b47s->blocksize;
+       mtd->writesize = 1;
+       mtd->writebufsize = 1;
 
-       /* TODO: implement writing support and verify/change following code */
-       mtd->flags = MTD_CAP_ROM;
-       mtd->writebufsize = mtd->writesize = 1;
+       mtd->_erase = bcm47xxsflash_erase;
+       mtd->_read = bcm47xxsflash_read;
+       mtd->_write = bcm47xxsflash_write;
 }
 
 /**************************************************
  * BCMA
  **************************************************/
 
+static int bcm47xxsflash_bcma_cc_read(struct bcm47xxsflash *b47s, u16 offset)
+{
+       return bcma_cc_read32(b47s->bcma_cc, offset);
+}
+
+static void bcm47xxsflash_bcma_cc_write(struct bcm47xxsflash *b47s, u16 offset,
+                                       u32 value)
+{
+       bcma_cc_write32(b47s->bcma_cc, offset, value);
+}
+
 static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
 {
        struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev);
        struct bcm47xxsflash *b47s;
        int err;
 
-       b47s = kzalloc(sizeof(*b47s), GFP_KERNEL);
-       if (!b47s) {
-               err = -ENOMEM;
-               goto out;
-       }
+       b47s = devm_kzalloc(&pdev->dev, sizeof(*b47s), GFP_KERNEL);
+       if (!b47s)
+               return -ENOMEM;
        sflash->priv = b47s;
 
        b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash);
+       b47s->cc_read = bcm47xxsflash_bcma_cc_read;
+       b47s->cc_write = bcm47xxsflash_bcma_cc_write;
 
        switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) {
        case BCMA_CC_FLASHT_STSER:
@@ -81,15 +305,13 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev)
        err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0);
        if (err) {
                pr_err("Failed to register MTD device: %d\n", err);
-               goto err_dev_reg;
+               return err;
        }
 
-       return 0;
+       if (bcm47xxsflash_poll(b47s, HZ / 10))
+               pr_warn("Serial flash busy\n");
 
-err_dev_reg:
-       kfree(&b47s->mtd);
-out:
-       return err;
+       return 0;
 }
 
 static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
@@ -98,7 +320,6 @@ static int bcm47xxsflash_bcma_remove(struct platform_device *pdev)
        struct bcm47xxsflash *b47s = sflash->priv;
 
        mtd_device_unregister(&b47s->mtd);
-       kfree(b47s);
 
        return 0;
 }
@@ -116,22 +337,4 @@ static struct platform_driver bcma_sflash_driver = {
  * Init
  **************************************************/
 
-static int __init bcm47xxsflash_init(void)
-{
-       int err;
-
-       err = platform_driver_register(&bcma_sflash_driver);
-       if (err)
-               pr_err("Failed to register BCMA serial flash driver: %d\n",
-                      err);
-
-       return err;
-}
-
-static void __exit bcm47xxsflash_exit(void)
-{
-       platform_driver_unregister(&bcma_sflash_driver);
-}
-
-module_init(bcm47xxsflash_init);
-module_exit(bcm47xxsflash_exit);
+module_platform_driver(bcma_sflash_driver);
index f22f8c46dfc059566ae8cd4fcf4c90f810a7fd2a..fe93daf4f4894a35f2d7b8a65363d1d163d09ffc 100644 (file)
@@ -60,6 +60,8 @@ enum bcm47xxsflash_type {
 
 struct bcm47xxsflash {
        struct bcma_drv_cc *bcma_cc;
+       int (*cc_read)(struct bcm47xxsflash *b47s, u16 offset);
+       void (*cc_write)(struct bcm47xxsflash *b47s, u16 offset, u32 value);
 
        enum bcm47xxsflash_type type;
 
index e081bfeaaf7da1941c9dc243856c3ab2ba9abde2..5cb4c04726b2e0eb58dd6452b293602f82fa1945 100644 (file)
@@ -6,6 +6,9 @@
  *
  * Licence: GPL
  */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/mount.h>
 #include <linux/slab.h>
 
-#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
-#define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args)
-
-
 /* Info for the block device */
 struct block2mtd_dev {
        struct list_head list;
@@ -84,7 +83,7 @@ static int block2mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
        err = _block2mtd_erase(dev, from, len);
        mutex_unlock(&dev->write_mutex);
        if (err) {
-               ERROR("erase failed err = %d", err);
+               pr_err("erase failed err = %d\n", err);
                instr->state = MTD_ERASE_FAILED;
        } else
                instr->state = MTD_ERASE_DONE;
@@ -239,13 +238,13 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 #endif
 
        if (IS_ERR(bdev)) {
-               ERROR("error: cannot open device %s", devname);
+               pr_err("error: cannot open device %s\n", devname);
                goto devinit_err;
        }
        dev->blkdev = bdev;
 
        if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
-               ERROR("attempting to use an MTD device as a block device");
+               pr_err("attempting to use an MTD device as a block device\n");
                goto devinit_err;
        }
 
@@ -277,9 +276,10 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
                goto devinit_err;
        }
        list_add(&dev->list, &blkmtd_device_list);
-       INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
-                       dev->mtd.name + strlen("block2mtd: "),
-                       dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+       pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
+               dev->mtd.index,
+               dev->mtd.name + strlen("block2mtd: "),
+               dev->mtd.erasesize >> 10, dev->mtd.erasesize);
        return dev;
 
 devinit_err:
@@ -339,17 +339,11 @@ static inline void kill_final_newline(char *str)
 }
 
 
-#define parse_err(fmt, args...) do {   \
-       ERROR(fmt, ## args);            \
-       return 0;                       \
-} while (0)
-
 #ifndef MODULE
 static int block2mtd_init_called = 0;
 static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
 #endif
 
-
 static int block2mtd_setup2(const char *val)
 {
        char buf[80 + 12]; /* 80 for device, 12 for erase size */
@@ -359,8 +353,10 @@ static int block2mtd_setup2(const char *val)
        size_t erase_size = PAGE_SIZE;
        int i, ret;
 
-       if (strnlen(val, sizeof(buf)) >= sizeof(buf))
-               parse_err("parameter too long");
+       if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
+               pr_err("parameter too long\n");
+               return 0;
+       }
 
        strcpy(str, val);
        kill_final_newline(str);
@@ -368,20 +364,27 @@ static int block2mtd_setup2(const char *val)
        for (i = 0; i < 2; i++)
                token[i] = strsep(&str, ",");
 
-       if (str)
-               parse_err("too many arguments");
+       if (str) {
+               pr_err("too many arguments\n");
+               return 0;
+       }
 
-       if (!token[0])
-               parse_err("no argument");
+       if (!token[0]) {
+               pr_err("no argument\n");
+               return 0;
+       }
 
        name = token[0];
-       if (strlen(name) + 1 > 80)
-               parse_err("device name too long");
+       if (strlen(name) + 1 > 80) {
+               pr_err("device name too long\n");
+               return 0;
+       }
 
        if (token[1]) {
                ret = parse_num(&erase_size, token[1]);
                if (ret) {
-                       parse_err("illegal erase size");
+                       pr_err("illegal erase size\n");
+                       return 0;
                }
        }
 
@@ -444,8 +447,9 @@ static void block2mtd_exit(void)
                struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
                block2mtd_sync(&dev->mtd);
                mtd_device_unregister(&dev->mtd);
-               INFO("mtd%d: [%s] removed", dev->mtd.index,
-                               dev->mtd.name + strlen("block2mtd: "));
+               pr_info("mtd%d: [%s] removed\n",
+                       dev->mtd.index,
+                       dev->mtd.name + strlen("block2mtd: "));
                list_del(&dev->list);
                block2mtd_free_device(dev);
        }
index dccef9fdc1f276269566bcc4ba03ae6e7a87111d..d1dd6a33a0500831f78012f9be91afa0161e4574 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/sched.h>
 #include <linux/pm_runtime.h>
 #include <linux/platform_data/elm.h>
 
+#define ELM_SYSCONFIG                  0x010
 #define ELM_IRQSTATUS                  0x018
 #define ELM_IRQENABLE                  0x01c
 #define ELM_LOCATION_CONFIG            0x020
 #define ELM_PAGE_CTRL                  0x080
 #define ELM_SYNDROME_FRAGMENT_0                0x400
+#define ELM_SYNDROME_FRAGMENT_1                0x404
+#define ELM_SYNDROME_FRAGMENT_2                0x408
+#define ELM_SYNDROME_FRAGMENT_3                0x40c
+#define ELM_SYNDROME_FRAGMENT_4                0x410
+#define ELM_SYNDROME_FRAGMENT_5                0x414
 #define ELM_SYNDROME_FRAGMENT_6                0x418
 #define ELM_LOCATION_STATUS            0x800
 #define ELM_ERROR_LOCATION_0           0x880
 #define SYNDROME_FRAGMENT_REG_SIZE     0x40
 #define ERROR_LOCATION_SIZE            0x100
 
+struct elm_registers {
+       u32 elm_irqenable;
+       u32 elm_sysconfig;
+       u32 elm_location_config;
+       u32 elm_page_ctrl;
+       u32 elm_syndrome_fragment_6[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_5[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_4[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_3[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_2[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_1[ERROR_VECTOR_MAX];
+       u32 elm_syndrome_fragment_0[ERROR_VECTOR_MAX];
+};
+
 struct elm_info {
        struct device *dev;
        void __iomem *elm_base;
        struct completion elm_completion;
        struct list_head list;
        enum bch_ecc bch_type;
+       struct elm_registers elm_regs;
 };
 
 static LIST_HEAD(elm_devices);
@@ -346,14 +368,9 @@ static int elm_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no memory resource defined\n");
-               return -ENODEV;
-       }
-
-       info->elm_base = devm_request_and_ioremap(&pdev->dev, res);
-       if (!info->elm_base)
-               return -EADDRNOTAVAIL;
+       info->elm_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->elm_base))
+               return PTR_ERR(info->elm_base);
 
        ret = devm_request_irq(&pdev->dev, irq->start, elm_isr, 0,
                        pdev->name, info);
@@ -381,10 +398,103 @@ static int elm_remove(struct platform_device *pdev)
 {
        pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
-       platform_set_drvdata(pdev, NULL);
        return 0;
 }
 
+/**
+ * elm_context_save
+ * saves ELM configurations to preserve them across Hardware powered-down
+ */
+static int elm_context_save(struct elm_info *info)
+{
+       struct elm_registers *regs = &info->elm_regs;
+       enum bch_ecc bch_type = info->bch_type;
+       u32 offset = 0, i;
+
+       regs->elm_irqenable       = elm_read_reg(info, ELM_IRQENABLE);
+       regs->elm_sysconfig       = elm_read_reg(info, ELM_SYSCONFIG);
+       regs->elm_location_config = elm_read_reg(info, ELM_LOCATION_CONFIG);
+       regs->elm_page_ctrl       = elm_read_reg(info, ELM_PAGE_CTRL);
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+               offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+               switch (bch_type) {
+               case BCH8_ECC:
+                       regs->elm_syndrome_fragment_3[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_3 + offset);
+                       regs->elm_syndrome_fragment_2[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_2 + offset);
+               case BCH4_ECC:
+                       regs->elm_syndrome_fragment_1[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_1 + offset);
+                       regs->elm_syndrome_fragment_0[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_0 + offset);
+               default:
+                       return -EINVAL;
+               }
+               /* ELM SYNDROME_VALID bit in SYNDROME_FRAGMENT_6[] needs
+                * to be saved for all BCH schemes*/
+               regs->elm_syndrome_fragment_6[i] = elm_read_reg(info,
+                                       ELM_SYNDROME_FRAGMENT_6 + offset);
+       }
+       return 0;
+}
+
+/**
+ * elm_context_restore
+ * writes configurations saved duing power-down back into ELM registers
+ */
+static int elm_context_restore(struct elm_info *info)
+{
+       struct elm_registers *regs = &info->elm_regs;
+       enum bch_ecc bch_type = info->bch_type;
+       u32 offset = 0, i;
+
+       elm_write_reg(info, ELM_IRQENABLE,       regs->elm_irqenable);
+       elm_write_reg(info, ELM_SYSCONFIG,       regs->elm_sysconfig);
+       elm_write_reg(info, ELM_LOCATION_CONFIG, regs->elm_location_config);
+       elm_write_reg(info, ELM_PAGE_CTRL,       regs->elm_page_ctrl);
+       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+               offset = i * SYNDROME_FRAGMENT_REG_SIZE;
+               switch (bch_type) {
+               case BCH8_ECC:
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_3 + offset,
+                                       regs->elm_syndrome_fragment_3[i]);
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_2 + offset,
+                                       regs->elm_syndrome_fragment_2[i]);
+               case BCH4_ECC:
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_1 + offset,
+                                       regs->elm_syndrome_fragment_1[i]);
+                       elm_write_reg(info, ELM_SYNDROME_FRAGMENT_0 + offset,
+                                       regs->elm_syndrome_fragment_0[i]);
+               default:
+                       return -EINVAL;
+               }
+               /* ELM_SYNDROME_VALID bit to be set in last to trigger FSM */
+               elm_write_reg(info, ELM_SYNDROME_FRAGMENT_6 + offset,
+                                       regs->elm_syndrome_fragment_6[i] &
+                                                        ELM_SYNDROME_VALID);
+       }
+       return 0;
+}
+
+static int elm_suspend(struct device *dev)
+{
+       struct elm_info *info = dev_get_drvdata(dev);
+       elm_context_save(info);
+       pm_runtime_put_sync(dev);
+       return 0;
+}
+
+static int elm_resume(struct device *dev)
+{
+       struct elm_info *info = dev_get_drvdata(dev);
+       pm_runtime_get_sync(dev);
+       elm_context_restore(info);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(elm_pm_ops, elm_suspend, elm_resume);
+
 #ifdef CONFIG_OF
 static const struct of_device_id elm_of_match[] = {
        { .compatible = "ti,am3352-elm" },
@@ -398,6 +508,7 @@ static struct platform_driver elm_driver = {
                .name   = "elm",
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(elm_of_match),
+               .pm     = &elm_pm_ops,
        },
        .probe  = elm_probe,
        .remove = elm_remove,
index 2f3d2a5ff349a174dc0f473f07c67f477f0139c4..26b14f9fcac6d129c3a2bc5c7a9fa7baea234691 100644 (file)
 #define        OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
 #define        OPCODE_PP               0x02    /* Page program (up to 256 bytes) */
 #define        OPCODE_BE_4K            0x20    /* Erase 4KiB block */
+#define        OPCODE_BE_4K_PMC        0xd7    /* Erase 4KiB block on PMC chips */
 #define        OPCODE_BE_32K           0x52    /* Erase 32KiB block */
 #define        OPCODE_CHIP_ERASE       0xc7    /* Erase whole flash chip */
 #define        OPCODE_SE               0xd8    /* Sector erase (usually 64KiB) */
 #define        OPCODE_RDID             0x9f    /* Read JEDEC ID */
 
+/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
+#define        OPCODE_NORM_READ_4B     0x13    /* Read data bytes (low frequency) */
+#define        OPCODE_FAST_READ_4B     0x0c    /* Read data bytes (high frequency) */
+#define        OPCODE_PP_4B            0x12    /* Page program (up to 256 bytes) */
+#define        OPCODE_SE_4B            0xdc    /* Sector erase (usually 64KiB) */
+
 /* Used for SST flashes only. */
 #define        OPCODE_BP               0x02    /* Byte program */
 #define        OPCODE_WRDI             0x04    /* Write disable */
 #define        OPCODE_AAI_WP           0xad    /* Auto address increment word program */
 
-/* Used for Macronix flashes only. */
+/* Used for Macronix and Winbond flashes. */
 #define        OPCODE_EN4B             0xb7    /* Enter 4-byte mode */
 #define        OPCODE_EX4B             0xe9    /* Exit 4-byte mode */
 
@@ -84,6 +91,8 @@ struct m25p {
        u16                     page_size;
        u16                     addr_width;
        u8                      erase_opcode;
+       u8                      read_opcode;
+       u8                      program_opcode;
        u8                      *command;
        bool                    fast_read;
 };
@@ -161,6 +170,7 @@ static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
 {
        switch (JEDEC_MFR(jedec_id)) {
        case CFI_MFR_MACRONIX:
+       case CFI_MFR_ST: /* Micron, actually */
        case 0xEF /* winbond */:
                flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
                return spi_write(flash->spi, flash->command, 1);
@@ -371,7 +381,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
         */
 
        /* Set up the write data buffer. */
-       opcode = flash->fast_read ? OPCODE_FAST_READ : OPCODE_NORM_READ;
+       opcode = flash->read_opcode;
        flash->command[0] = opcode;
        m25p_addr2cmd(flash, from, flash->command);
 
@@ -422,7 +432,7 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
        write_enable(flash);
 
        /* Set up the opcode in the write buffer. */
-       flash->command[0] = OPCODE_PP;
+       flash->command[0] = flash->program_opcode;
        m25p_addr2cmd(flash, to, flash->command);
 
        page_offset = to & (flash->page_size - 1);
@@ -682,6 +692,8 @@ struct flash_info {
 #define        SECT_4K         0x01            /* OPCODE_BE_4K works uniformly */
 #define        M25P_NO_ERASE   0x02            /* No erase command needed */
 #define        SST_WRITE       0x04            /* use SST byte programming */
+#define        M25P_NO_FR      0x08            /* Can't do fastread */
+#define        SECT_4K_PMC     0x10            /* OPCODE_BE_4K_PMC works uniformly */
 };
 
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
@@ -694,13 +706,13 @@ struct flash_info {
                .flags = (_flags),                                      \
        })
 
-#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width)  \
+#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)  \
        ((kernel_ulong_t)&(struct flash_info) {                         \
                .sector_size = (_sector_size),                          \
                .n_sectors = (_n_sectors),                              \
                .page_size = (_page_size),                              \
                .addr_width = (_addr_width),                            \
-               .flags = M25P_NO_ERASE,                                 \
+               .flags = (_flags),                                      \
        })
 
 /* NOTE: double check command sets and memory organization when you add
@@ -732,7 +744,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
 
        /* Everspin */
-       { "mr25h256", CAT25_INFO(  32 * 1024, 1, 256, 2) },
+       { "mr25h256", CAT25_INFO(  32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
+       { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
 
        /* GigaDevice */
        { "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
@@ -762,6 +775,11 @@ static const struct spi_device_id m25p_ids[] = {
        { "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
        { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
 
+       /* PMC */
+       { "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
+       { "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
+       { "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024,  64, SECT_4K) },
+
        /* Spansion -- single (large) sector size only, at least
         * for the chips listed here (without boot sectors).
         */
@@ -840,17 +858,18 @@ static const struct spi_device_id m25p_ids[] = {
        { "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
        { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
        { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
+       { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
        { "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
        { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
        { "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
 
        /* Catalyst / On Semiconductor -- non-JEDEC */
-       { "cat25c11", CAT25_INFO(  16, 8, 16, 1) },
-       { "cat25c03", CAT25_INFO(  32, 8, 16, 2) },
-       { "cat25c09", CAT25_INFO( 128, 8, 32, 2) },
-       { "cat25c17", CAT25_INFO( 256, 8, 32, 2) },
-       { "cat25128", CAT25_INFO(2048, 8, 64, 2) },
+       { "cat25c11", CAT25_INFO(  16, 8, 16, 1, M25P_NO_ERASE | M25P_NO_FR) },
+       { "cat25c03", CAT25_INFO(  32, 8, 16, 2, M25P_NO_ERASE | M25P_NO_FR) },
+       { "cat25c09", CAT25_INFO( 128, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
+       { "cat25c17", CAT25_INFO( 256, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
+       { "cat25128", CAT25_INFO(2048, 8, 64, 2, M25P_NO_ERASE | M25P_NO_FR) },
        { },
 };
 MODULE_DEVICE_TABLE(spi, m25p_ids);
@@ -920,7 +939,7 @@ static int m25p_probe(struct spi_device *spi)
         * a chip ID, try the JEDEC id commands; they'll work for most
         * newer chips, even if we don't recognize the particular chip.
         */
-       data = spi->dev.platform_data;
+       data = dev_get_platdata(&spi->dev);
        if (data && data->type) {
                const struct spi_device_id *plat_id;
 
@@ -972,7 +991,7 @@ static int m25p_probe(struct spi_device *spi)
 
        flash->spi = spi;
        mutex_init(&flash->lock);
-       dev_set_drvdata(&spi->dev, flash);
+       spi_set_drvdata(spi, flash);
 
        /*
         * Atmel, SST and Intel/Numonyx serial flash tend to power
@@ -1014,6 +1033,9 @@ static int m25p_probe(struct spi_device *spi)
        if (info->flags & SECT_4K) {
                flash->erase_opcode = OPCODE_BE_4K;
                flash->mtd.erasesize = 4096;
+       } else if (info->flags & SECT_4K_PMC) {
+               flash->erase_opcode = OPCODE_BE_4K_PMC;
+               flash->mtd.erasesize = 4096;
        } else {
                flash->erase_opcode = OPCODE_SE;
                flash->mtd.erasesize = info->sector_size;
@@ -1028,24 +1050,41 @@ static int m25p_probe(struct spi_device *spi)
        flash->mtd.writebufsize = flash->page_size;
 
        flash->fast_read = false;
-#ifdef CONFIG_OF
        if (np && of_property_read_bool(np, "m25p,fast-read"))
                flash->fast_read = true;
-#endif
 
 #ifdef CONFIG_M25PXX_USE_FAST_READ
        flash->fast_read = true;
 #endif
+       if (info->flags & M25P_NO_FR)
+               flash->fast_read = false;
+
+       /* Default commands */
+       if (flash->fast_read)
+               flash->read_opcode = OPCODE_FAST_READ;
+       else
+               flash->read_opcode = OPCODE_NORM_READ;
+
+       flash->program_opcode = OPCODE_PP;
 
        if (info->addr_width)
                flash->addr_width = info->addr_width;
-       else {
+       else if (flash->mtd.size > 0x1000000) {
                /* enable 4-byte addressing if the device exceeds 16MiB */
-               if (flash->mtd.size > 0x1000000) {
-                       flash->addr_width = 4;
-                       set_4byte(flash, info->jedec_id, 1);
+               flash->addr_width = 4;
+               if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
+                       /* Dedicated 4-byte command set */
+                       flash->read_opcode = flash->fast_read ?
+                               OPCODE_FAST_READ_4B :
+                               OPCODE_NORM_READ_4B;
+                       flash->program_opcode = OPCODE_PP_4B;
+                       /* No small sector erase for 4-byte command set */
+                       flash->erase_opcode = OPCODE_SE_4B;
+                       flash->mtd.erasesize = info->sector_size;
                } else
-                       flash->addr_width = 3;
+                       set_4byte(flash, info->jedec_id, 1);
+       } else {
+               flash->addr_width = 3;
        }
 
        dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
@@ -1080,7 +1119,7 @@ static int m25p_probe(struct spi_device *spi)
 
 static int m25p_remove(struct spi_device *spi)
 {
-       struct m25p     *flash = dev_get_drvdata(&spi->dev);
+       struct m25p     *flash = spi_get_drvdata(spi);
        int             status;
 
        /* Clean up MTD stuff. */
index 28779b6dfcd98fc6c8b2ed5b49800d898fee7e81..0e8cbfeba11e42a85da4a843cd7f212263eb9448 100644 (file)
@@ -622,7 +622,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        struct dataflash                *priv;
        struct mtd_info                 *device;
        struct mtd_part_parser_data     ppdata;
-       struct flash_platform_data      *pdata = spi->dev.platform_data;
+       struct flash_platform_data      *pdata = dev_get_platdata(&spi->dev);
        char                            *otp_tag = "";
        int                             err = 0;
 
@@ -661,7 +661,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n",
                        name, (long long)((device->size + 1023) >> 10),
                        pagesize, otp_tag);
-       dev_set_drvdata(&spi->dev, priv);
+       spi_set_drvdata(spi, priv);
 
        ppdata.of_node = spi->dev.of_node;
        err = mtd_device_parse_register(device, NULL, &ppdata,
@@ -671,7 +671,7 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        if (!err)
                return 0;
 
-       dev_set_drvdata(&spi->dev, NULL);
+       spi_set_drvdata(spi, NULL);
        kfree(priv);
        return err;
 }
@@ -895,14 +895,14 @@ static int dataflash_probe(struct spi_device *spi)
 
 static int dataflash_remove(struct spi_device *spi)
 {
-       struct dataflash        *flash = dev_get_drvdata(&spi->dev);
+       struct dataflash        *flash = spi_get_drvdata(spi);
        int                     status;
 
        pr_debug("%s: remove\n", dev_name(&spi->dev));
 
        status = mtd_device_unregister(&flash->mtd);
        if (status == 0) {
-               dev_set_drvdata(&spi->dev, NULL);
+               spi_set_drvdata(spi, NULL);
                kfree(flash);
        }
        return status;
index 8a82b8bc21e185d7f62ca331d93f532470bb4399..42382141206222152d948ecd19f73338e1a30a3f 100644 (file)
@@ -550,7 +550,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
 {
        struct spear_snor_flash *flash = get_flash_data(mtd);
        struct spear_smi *dev = mtd->priv;
-       void *src;
+       void __iomem *src;
        u32 ctrlreg1, val;
        int ret;
 
@@ -583,7 +583,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
 
        writel(val, dev->io_base + SMI_CR1);
 
-       memcpy_fromio(buf, (u8 *)src, len);
+       memcpy_fromio(buf, src, len);
 
        /* restore ctrl reg1 */
        writel(ctrlreg1, dev->io_base + SMI_CR1);
@@ -596,7 +596,7 @@ static int spear_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
 }
 
 static inline int spear_smi_cpy_toio(struct spear_smi *dev, u32 bank,
-               void *dest, const void *src, size_t len)
+               void __iomem *dest, const void *src, size_t len)
 {
        int ret;
        u32 ctrlreg1;
@@ -643,7 +643,7 @@ static int spear_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
 {
        struct spear_snor_flash *flash = get_flash_data(mtd);
        struct spear_smi *dev = mtd->priv;
-       void *dest;
+       void __iomem *dest;
        u32 page_offset, page_size;
        int ret;
 
@@ -995,14 +995,12 @@ static int spear_smi_probe(struct platform_device *pdev)
                ret = spear_smi_setup_banks(pdev, i, pdata->np[i]);
                if (ret) {
                        dev_err(&dev->pdev->dev, "bank setup failed\n");
-                       goto err_bank_setup;
+                       goto err_irq;
                }
        }
 
        return 0;
 
-err_bank_setup:
-       platform_set_drvdata(pdev, NULL);
 err_irq:
        clk_disable_unprepare(dev->clk);
 err:
@@ -1040,12 +1038,11 @@ static int spear_smi_remove(struct platform_device *pdev)
        }
 
        clk_disable_unprepare(dev->clk);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int spear_smi_suspend(struct device *dev)
 {
        struct spear_smi *sdev = dev_get_drvdata(dev);
@@ -1068,9 +1065,9 @@ static int spear_smi_resume(struct device *dev)
                spear_smi_hw_init(sdev);
        return ret;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(spear_smi_pm_ops, spear_smi_suspend, spear_smi_resume);
-#endif
 
 #ifdef CONFIG_OF
 static const struct of_device_id spear_smi_id_table[] = {
@@ -1086,9 +1083,7 @@ static struct platform_driver spear_smi_driver = {
                .bus = &platform_bus_type,
                .owner = THIS_MODULE,
                .of_match_table = of_match_ptr(spear_smi_id_table),
-#ifdef CONFIG_PM
                .pm = &spear_smi_pm_ops,
-#endif
        },
        .probe = spear_smi_probe,
        .remove = spear_smi_remove,
index 8091b016369430c0975835be79d3a6c381363846..a42f1f0e7281417398f4de453845ff8edf79b60c 100644 (file)
@@ -370,9 +370,9 @@ static int sst25l_probe(struct spi_device *spi)
 
        flash->spi = spi;
        mutex_init(&flash->lock);
-       dev_set_drvdata(&spi->dev, flash);
+       spi_set_drvdata(spi, flash);
 
-       data = spi->dev.platform_data;
+       data = dev_get_platdata(&spi->dev);
        if (data && data->name)
                flash->mtd.name = data->name;
        else
@@ -404,7 +404,7 @@ static int sst25l_probe(struct spi_device *spi)
                                        data ? data->nr_parts : 0);
        if (ret) {
                kfree(flash);
-               dev_set_drvdata(&spi->dev, NULL);
+               spi_set_drvdata(spi, NULL);
                return -ENODEV;
        }
 
@@ -413,7 +413,7 @@ static int sst25l_probe(struct spi_device *spi)
 
 static int sst25l_remove(struct spi_device *spi)
 {
-       struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
+       struct sst25l_flash *flash = spi_get_drvdata(spi);
        int ret;
 
        ret = mtd_device_unregister(&flash->mtd);
index 8b27ca054c59ba1d4e2ee5bd20cfd600dce79afa..310dc7c93425587095941d76afcc8dacbdb1fc29 100644 (file)
@@ -157,24 +157,6 @@ config MTD_PXA2XX
        help
          This provides a driver for the NOR flash attached to a PXA2xx chip.
 
-config MTD_OCTAGON
-       tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
-       depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
-       help
-         This provides a 'mapping' driver which supports the way in which
-         the flash chips are connected in the Octagon-5066 Single Board
-         Computer. More information on the board is available at
-         <http://www.octagonsystems.com/products/5066.aspx>.
-
-config MTD_VMAX
-       tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301"
-       depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
-       help
-         This provides a 'mapping' driver which supports the way in which
-         the flash chips are connected in the Tempustech VMAX SBC301 Single
-         Board Computer. More information on the board is available at
-         <http://www.tempustech.com/>.
-
 config MTD_SCx200_DOCFLASH
        tristate "Flash device mapped with DOCCS on NatSemi SCx200"
        depends on SCx200 && MTD_CFI
index 9fdbd4ba64419f45576e0833470680f0d4194003..141c91a5b24cc044c063b064d600f59a0182d48d 100644 (file)
@@ -16,7 +16,6 @@ obj-$(CONFIG_MTD_ICHXROM)     += ichxrom.o
 obj-$(CONFIG_MTD_CK804XROM)    += ck804xrom.o
 obj-$(CONFIG_MTD_TSUNAMI)      += tsunami_flash.o
 obj-$(CONFIG_MTD_PXA2XX)       += pxa2xx-flash.o
-obj-$(CONFIG_MTD_OCTAGON)      += octagon-5066.o
 obj-$(CONFIG_MTD_PHYSMAP)      += physmap.o
 obj-$(CONFIG_MTD_PHYSMAP_OF)   += physmap_of.o
 obj-$(CONFIG_MTD_PISMO)                += pismo.o
@@ -28,7 +27,6 @@ obj-$(CONFIG_MTD_SC520CDP)    += sc520cdp.o
 obj-$(CONFIG_MTD_NETSC520)     += netsc520.o
 obj-$(CONFIG_MTD_TS5500)       += ts5500_flash.o
 obj-$(CONFIG_MTD_SUN_UFLASH)   += sun_uflash.o
-obj-$(CONFIG_MTD_VMAX)         += vmax301.o
 obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
 obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
 obj-$(CONFIG_MTD_PCI)          += pci.o
index 319b04a6c9d1f6a0ccc5c565c977740d63babaa9..5434d8ded015dfca0e8a19199883ce26122fc421 100644 (file)
@@ -128,7 +128,7 @@ static const char * const part_probe_types[] = {
 static int bfin_flash_probe(struct platform_device *pdev)
 {
        int ret;
-       struct physmap_flash_data *pdata = pdev->dev.platform_data;
+       struct physmap_flash_data *pdata = dev_get_platdata(&pdev->dev);
        struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        struct async_state *state;
index d16fc9d3b8cd5bd58dae35c7f5e579e289ac9083..d504b3d1791da8ef70076d2b936c6afba7cc863c 100644 (file)
 #define FLASH_PARTITION3_SIZE 0x001C0000
 
 
-struct map_info flagadm_map = {
+static struct map_info flagadm_map = {
                .name =         "FlagaDM flash device",
                .size =         FLASH_SIZE,
                .bankwidth =    2,
 };
 
-struct mtd_partition flagadm_parts[] = {
+static struct mtd_partition flagadm_parts[] = {
        {
                .name =         "Bootloader",
                .offset =       FLASH_PARTITION0_ADDR,
@@ -112,7 +112,7 @@ static int __init init_flagadm(void)
                return 0;
        }
 
-       iounmap((void *)flagadm_map.virt);
+       iounmap((void __iomem *)flagadm_map.virt);
        return -ENXIO;
 }
 
@@ -123,8 +123,8 @@ static void __exit cleanup_flagadm(void)
                map_destroy(mymtd);
        }
        if (flagadm_map.virt) {
-               iounmap((void *)flagadm_map.virt);
-               flagadm_map.virt = 0;
+               iounmap((void __iomem *)flagadm_map.virt);
+               flagadm_map.virt = NULL;
        }
 }
 
index 5ede28294f9e49765a9a24ed12867b94cc9e3208..1adba86474a52f7a4fed630bd08f300cf45e3398 100644 (file)
@@ -196,7 +196,7 @@ static int gpio_flash_probe(struct platform_device *pdev)
        struct resource *gpios;
        struct async_state *state;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        memory = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 
index 49686744d93cac9d2dae0758fd1b70618237c9c1..15bbda03be6542cd860759a79a914387c842301d 100644 (file)
@@ -79,7 +79,7 @@ static int __init init_impa7(void)
                }
                simple_map_init(&impa7_map[i]);
 
-               impa7_mtd[i] = 0;
+               impa7_mtd[i] = NULL;
                type = rom_probe_types;
                for(; !impa7_mtd[i] && *type; type++) {
                        impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
@@ -91,9 +91,9 @@ static int __init init_impa7(void)
                        mtd_device_parse_register(impa7_mtd[i], NULL, NULL,
                                                  partitions,
                                                  ARRAY_SIZE(partitions));
+               } else {
+                       iounmap((void __iomem *)impa7_map[i].virt);
                }
-               else
-                       iounmap((void *)impa7_map[i].virt);
        }
        return devicesfound == 0 ? -ENXIO : 0;
 }
@@ -105,8 +105,8 @@ static void __exit cleanup_impa7(void)
                if (impa7_mtd[i]) {
                        mtd_device_unregister(impa7_mtd[i]);
                        map_destroy(impa7_mtd[i]);
-                       iounmap((void *)impa7_map[i].virt);
-                       impa7_map[i].virt = 0;
+                       iounmap((void __iomem *)impa7_map[i].virt);
+                       impa7_map[i].virt = NULL;
                }
        }
 }
index 52b3410a105c943d47ce3b9ea873781948d028a4..10debfea81e7147c25fa00e4913bd2d336c24b6a 100644 (file)
@@ -152,11 +152,9 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 static int ixp4xx_flash_remove(struct platform_device *dev)
 {
-       struct flash_platform_data *plat = dev->dev.platform_data;
+       struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
        struct ixp4xx_flash_info *info = platform_get_drvdata(dev);
 
-       platform_set_drvdata(dev, NULL);
-
        if(!info)
                return 0;
 
@@ -180,7 +178,7 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
 
 static int ixp4xx_flash_probe(struct platform_device *dev)
 {
-       struct flash_platform_data *plat = dev->dev.platform_data;
+       struct flash_platform_data *plat = dev_get_platdata(&dev->dev);
        struct ixp4xx_flash_info *info;
        struct mtd_part_parser_data ppdata = {
                .origin = dev->resource->start,
index ab0fead56b8383f1a57579c0f9f3dfe0a5211d32..98bb5d5375d741e8159497e30b704c0520533f79 100644 (file)
@@ -102,9 +102,8 @@ static int latch_addr_flash_remove(struct platform_device *dev)
        info = platform_get_drvdata(dev);
        if (info == NULL)
                return 0;
-       platform_set_drvdata(dev, NULL);
 
-       latch_addr_data = dev->dev.platform_data;
+       latch_addr_data = dev_get_platdata(&dev->dev);
 
        if (info->mtd != NULL) {
                mtd_device_unregister(info->mtd);
@@ -135,7 +134,7 @@ static int latch_addr_flash_probe(struct platform_device *dev)
        int chipsel;
        int err;
 
-       latch_addr_data = dev->dev.platform_data;
+       latch_addr_data = dev_get_platdata(&dev->dev);
        if (latch_addr_data == NULL)
                return -ENODEV;
 
diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c
deleted file mode 100644 (file)
index 807ac2a..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/* ######################################################################
-
-   Octagon 5066 MTD Driver.
-
-   The Octagon 5066 is a SBC based on AMD's 586-WB running at 133 MHZ. It
-   comes with a builtin AMD 29F016 flash chip and a socketed EEPROM that
-   is replacable by flash. Both units are mapped through a multiplexer
-   into a 32k memory window at 0xe8000. The control register for the
-   multiplexing unit is located at IO 0x208 with a bit map of
-     0-5 Page Selection in 32k increments
-     6-7 Device selection:
-        00 SSD off
-        01 SSD 0 (Socket)
-        10 SSD 1 (Flash chip)
-        11 undefined
-
-   On each SSD, the first 128k is reserved for use by the bios
-   (actually it IS the bios..) This only matters if you are booting off the
-   flash, you must not put a file system starting there.
-
-   The driver tries to do a detection algorithm to guess what sort of devices
-   are plugged into the sockets.
-
-   ##################################################################### */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-
-#define WINDOW_START 0xe8000
-#define WINDOW_LENGTH 0x8000
-#define WINDOW_SHIFT 27
-#define WINDOW_MASK 0x7FFF
-#define PAGE_IO 0x208
-
-static volatile char page_n_dev = 0;
-static unsigned long iomapadr;
-static DEFINE_SPINLOCK(oct5066_spin);
-
-/*
- * We use map_priv_1 to identify which device we are.
- */
-
-static void __oct5066_page(struct map_info *map, __u8 byte)
-{
-       outb(byte,PAGE_IO);
-       page_n_dev = byte;
-}
-
-static inline void oct5066_page(struct map_info *map, unsigned long ofs)
-{
-       __u8 byte = map->map_priv_1 | (ofs >> WINDOW_SHIFT);
-
-       if (page_n_dev != byte)
-               __oct5066_page(map, byte);
-}
-
-
-static map_word oct5066_read8(struct map_info *map, unsigned long ofs)
-{
-       map_word ret;
-       spin_lock(&oct5066_spin);
-       oct5066_page(map, ofs);
-       ret.x[0] = readb(iomapadr + (ofs & WINDOW_MASK));
-       spin_unlock(&oct5066_spin);
-       return ret;
-}
-
-static void oct5066_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-       while(len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-
-               spin_lock(&oct5066_spin);
-               oct5066_page(map, from);
-               memcpy_fromio(to, iomapadr + from, thislen);
-               spin_unlock(&oct5066_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static void oct5066_write8(struct map_info *map, map_word d, unsigned long adr)
-{
-       spin_lock(&oct5066_spin);
-       oct5066_page(map, adr);
-       writeb(d.x[0], iomapadr + (adr & WINDOW_MASK));
-       spin_unlock(&oct5066_spin);
-}
-
-static void oct5066_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-       while(len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
-               spin_lock(&oct5066_spin);
-               oct5066_page(map, to);
-               memcpy_toio(iomapadr + to, from, thislen);
-               spin_unlock(&oct5066_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static struct map_info oct5066_map[2] = {
-       {
-               .name = "Octagon 5066 Socket",
-               .phys = NO_XIP,
-               .size = 512 * 1024,
-               .bankwidth = 1,
-               .read = oct5066_read8,
-               .copy_from = oct5066_copy_from,
-               .write = oct5066_write8,
-               .copy_to = oct5066_copy_to,
-               .map_priv_1 = 1<<6
-       },
-       {
-               .name = "Octagon 5066 Internal Flash",
-               .phys = NO_XIP,
-               .size = 2 * 1024 * 1024,
-               .bankwidth = 1,
-               .read = oct5066_read8,
-               .copy_from = oct5066_copy_from,
-               .write = oct5066_write8,
-               .copy_to = oct5066_copy_to,
-               .map_priv_1 = 2<<6
-       }
-};
-
-static struct mtd_info *oct5066_mtd[2] = {NULL, NULL};
-
-// OctProbe - Sense if this is an octagon card
-// ---------------------------------------------------------------------
-/* Perform a simple validity test, we map the window select SSD0 and
-   change pages while monitoring the window. A change in the window,
-   controlled by the PAGE_IO port is a functioning 5066 board. This will
-   fail if the thing in the socket is set to a uniform value. */
-static int __init OctProbe(void)
-{
-   unsigned int Base = (1 << 6);
-   unsigned long I;
-   unsigned long Values[10];
-   for (I = 0; I != 20; I++)
-   {
-      outb(Base + (I%10),PAGE_IO);
-      if (I < 10)
-      {
-        // Record the value and check for uniqueness
-        Values[I%10] = readl(iomapadr);
-        if (I > 0 && Values[I%10] == Values[0])
-           return -EAGAIN;
-      }
-      else
-      {
-        // Make sure we get the same values on the second pass
-        if (Values[I%10] != readl(iomapadr))
-           return -EAGAIN;
-      }
-   }
-   return 0;
-}
-
-void cleanup_oct5066(void)
-{
-       int i;
-       for (i=0; i<2; i++) {
-               if (oct5066_mtd[i]) {
-                       mtd_device_unregister(oct5066_mtd[i]);
-                       map_destroy(oct5066_mtd[i]);
-               }
-       }
-       iounmap((void *)iomapadr);
-       release_region(PAGE_IO, 1);
-}
-
-static int __init init_oct5066(void)
-{
-       int i;
-       int ret = 0;
-
-       // Do an autoprobe sequence
-       if (!request_region(PAGE_IO,1,"Octagon SSD")) {
-               printk(KERN_NOTICE "5066: Page Register in Use\n");
-               return -EAGAIN;
-       }
-       iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH);
-       if (!iomapadr) {
-               printk(KERN_NOTICE "Failed to ioremap memory region\n");
-               ret = -EIO;
-               goto out_rel;
-       }
-       if (OctProbe() != 0) {
-               printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n");
-               iounmap((void *)iomapadr);
-               ret = -EAGAIN;
-               goto out_unmap;
-       }
-
-       // Print out our little header..
-       printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START,
-              WINDOW_START+WINDOW_LENGTH);
-
-       for (i=0; i<2; i++) {
-               oct5066_mtd[i] = do_map_probe("cfi_probe", &oct5066_map[i]);
-               if (!oct5066_mtd[i])
-                       oct5066_mtd[i] = do_map_probe("jedec", &oct5066_map[i]);
-               if (!oct5066_mtd[i])
-                       oct5066_mtd[i] = do_map_probe("map_ram", &oct5066_map[i]);
-               if (!oct5066_mtd[i])
-                       oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]);
-               if (oct5066_mtd[i]) {
-                       oct5066_mtd[i]->owner = THIS_MODULE;
-                       mtd_device_register(oct5066_mtd[i], NULL, 0);
-               }
-       }
-
-       if (!oct5066_mtd[0] && !oct5066_mtd[1]) {
-               cleanup_oct5066();
-               return -ENXIO;
-       }
-
-       return 0;
-
- out_unmap:
-       iounmap((void *)iomapadr);
- out_rel:
-       release_region(PAGE_IO, 1);
-       return ret;
-}
-
-module_init(init_oct5066);
-module_exit(cleanup_oct5066);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jason Gunthorpe <jgg@deltatee.com>, David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("MTD map driver for Octagon 5066 Single Board Computer");
index e7a592c8c76591e02257e5c39b891aefbf43d9d3..f73cd461257c852af9da775f839c3ec190527256 100644 (file)
@@ -40,9 +40,8 @@ static int physmap_flash_remove(struct platform_device *dev)
        info = platform_get_drvdata(dev);
        if (info == NULL)
                return 0;
-       platform_set_drvdata(dev, NULL);
 
-       physmap_data = dev->dev.platform_data;
+       physmap_data = dev_get_platdata(&dev->dev);
 
        if (info->cmtd) {
                mtd_device_unregister(info->cmtd);
@@ -69,7 +68,7 @@ static void physmap_set_vpp(struct map_info *map, int state)
        unsigned long flags;
 
        pdev = (struct platform_device *)map->map_priv_1;
-       physmap_data = pdev->dev.platform_data;
+       physmap_data = dev_get_platdata(&pdev->dev);
 
        if (!physmap_data->set_vpp)
                return;
@@ -103,7 +102,7 @@ static int physmap_flash_probe(struct platform_device *dev)
        int i;
        int devices_found = 0;
 
-       physmap_data = dev->dev.platform_data;
+       physmap_data = dev_get_platdata(&dev->dev);
        if (physmap_data == NULL)
                return -ENODEV;
 
index 71fdda29594b7c3595d786c1572012d09b4df8af..676271659b37442a85d4d545fca05f80c48bdb54 100644 (file)
@@ -84,8 +84,6 @@ static int platram_remove(struct platform_device *pdev)
 {
        struct platram_info *info = to_platram_info(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        dev_dbg(&pdev->dev, "removing device\n");
 
        if (info == NULL)
@@ -130,13 +128,13 @@ static int platram_probe(struct platform_device *pdev)
 
        dev_dbg(&pdev->dev, "probe entered\n");
 
-       if (pdev->dev.platform_data == NULL) {
+       if (dev_get_platdata(&pdev->dev) == NULL) {
                dev_err(&pdev->dev, "no platform data supplied\n");
                err = -ENOENT;
                goto exit_error;
        }
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
index acb1dbcf7ce58a438ed7ff9a1df9aecb2b57478f..d210d131fef255da97e7d277574ac80f01a66341 100644 (file)
@@ -49,7 +49,7 @@ static const char * const probes[] = { "RedBoot", "cmdlinepart", NULL };
 
 static int pxa2xx_flash_probe(struct platform_device *pdev)
 {
-       struct flash_platform_data *flash = pdev->dev.platform_data;
+       struct flash_platform_data *flash = dev_get_platdata(&pdev->dev);
        struct pxa2xx_flash_info *info;
        struct resource *res;
 
@@ -107,8 +107,6 @@ static int pxa2xx_flash_remove(struct platform_device *dev)
 {
        struct pxa2xx_flash_info *info = platform_get_drvdata(dev);
 
-       platform_set_drvdata(dev, NULL);
-
        mtd_device_unregister(info->mtd);
 
        map_destroy(info->mtd);
index ac02fbffd6df940f70e3802895811f5916843541..93525121d69dc17876f70f8341e6f69faa251b12 100644 (file)
@@ -34,10 +34,9 @@ static int rbtx4939_flash_remove(struct platform_device *dev)
        info = platform_get_drvdata(dev);
        if (!info)
                return 0;
-       platform_set_drvdata(dev, NULL);
 
        if (info->mtd) {
-               struct rbtx4939_flash_data *pdata = dev->dev.platform_data;
+               struct rbtx4939_flash_data *pdata = dev_get_platdata(&dev->dev);
 
                mtd_device_unregister(info->mtd);
                map_destroy(info->mtd);
@@ -57,7 +56,7 @@ static int rbtx4939_flash_probe(struct platform_device *dev)
        int err = 0;
        unsigned long size;
 
-       pdata = dev->dev.platform_data;
+       pdata = dev_get_platdata(&dev->dev);
        if (!pdata)
                return -ENODEV;
 
index 29e3dcaa1d90413b15df9e30c04373d897c2f6c6..8fc06bf111c4685c0376a48f2f39df486cdda268 100644 (file)
@@ -248,7 +248,7 @@ static const char * const part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
 static int sa1100_mtd_probe(struct platform_device *pdev)
 {
-       struct flash_platform_data *plat = pdev->dev.platform_data;
+       struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
        struct sa_info *info;
        int err;
 
@@ -277,9 +277,8 @@ static int sa1100_mtd_probe(struct platform_device *pdev)
 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
 {
        struct sa_info *info = platform_get_drvdata(pdev);
-       struct flash_platform_data *plat = pdev->dev.platform_data;
+       struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
 
-       platform_set_drvdata(pdev, NULL);
        sa1100_destroy(info, plat);
 
        return 0;
diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c
deleted file mode 100644 (file)
index 5e68de7..0000000
+++ /dev/null
@@ -1,196 +0,0 @@
-/* ######################################################################
-
-   Tempustech VMAX SBC301 MTD Driver.
-
-   The VMAx 301 is a SBC based on . It
-   comes with three builtin AMD 29F016B flash chips and a socket for SRAM or
-   more flash. Each unit has it's own 8k mapping into a settable region
-   (0xD8000). There are two 8k mappings for each MTD, the first is always set
-   to the lower 8k of the device the second is paged. Writing a 16 bit page
-   value to anywhere in the first 8k will cause the second 8k to page around.
-
-   To boot the device a bios extension must be installed into the first 8k
-   of flash that is smart enough to copy itself down, page in the rest of
-   itself and begin executing.
-
-   ##################################################################### */
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-
-
-#define WINDOW_START 0xd8000
-#define WINDOW_LENGTH 0x2000
-#define WINDOW_SHIFT 25
-#define WINDOW_MASK 0x1FFF
-
-/* Actually we could use two spinlocks, but we'd have to have
-   more private space in the struct map_info. We lose a little
-   performance like this, but we'd probably lose more by having
-   the extra indirection from having one of the map->map_priv
-   fields pointing to yet another private struct.
-*/
-static DEFINE_SPINLOCK(vmax301_spin);
-
-static void __vmax301_page(struct map_info *map, unsigned long page)
-{
-       writew(page, map->map_priv_2 - WINDOW_LENGTH);
-       map->map_priv_1 = page;
-}
-
-static inline void vmax301_page(struct map_info *map,
-                                 unsigned long ofs)
-{
-       unsigned long page = (ofs >> WINDOW_SHIFT);
-       if (map->map_priv_1 != page)
-               __vmax301_page(map, page);
-}
-
-static map_word vmax301_read8(struct map_info *map, unsigned long ofs)
-{
-       map_word ret;
-       spin_lock(&vmax301_spin);
-       vmax301_page(map, ofs);
-       ret.x[0] = readb(map->map_priv_2 + (ofs & WINDOW_MASK));
-       spin_unlock(&vmax301_spin);
-       return ret;
-}
-
-static void vmax301_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
-       while(len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-               spin_lock(&vmax301_spin);
-               vmax301_page(map, from);
-               memcpy_fromio(to, map->map_priv_2 + from, thislen);
-               spin_unlock(&vmax301_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static void vmax301_write8(struct map_info *map, map_word d, unsigned long adr)
-{
-       spin_lock(&vmax301_spin);
-       vmax301_page(map, adr);
-       writeb(d.x[0], map->map_priv_2 + (adr & WINDOW_MASK));
-       spin_unlock(&vmax301_spin);
-}
-
-static void vmax301_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
-       while(len) {
-               unsigned long thislen = len;
-               if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
-                       thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
-               spin_lock(&vmax301_spin);
-               vmax301_page(map, to);
-               memcpy_toio(map->map_priv_2 + to, from, thislen);
-               spin_unlock(&vmax301_spin);
-               to += thislen;
-               from += thislen;
-               len -= thislen;
-       }
-}
-
-static struct map_info vmax_map[2] = {
-       {
-               .name = "VMAX301 Internal Flash",
-               .phys = NO_XIP,
-               .size = 3*2*1024*1024,
-               .bankwidth = 1,
-               .read = vmax301_read8,
-               .copy_from = vmax301_copy_from,
-               .write = vmax301_write8,
-               .copy_to = vmax301_copy_to,
-               .map_priv_1 = WINDOW_START + WINDOW_LENGTH,
-               .map_priv_2 = 0xFFFFFFFF
-       },
-       {
-               .name = "VMAX301 Socket",
-               .phys = NO_XIP,
-               .size = 0,
-               .bankwidth = 1,
-               .read = vmax301_read8,
-               .copy_from = vmax301_copy_from,
-               .write = vmax301_write8,
-               .copy_to = vmax301_copy_to,
-               .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH),
-               .map_priv_2 = 0xFFFFFFFF
-       }
-};
-
-static struct mtd_info *vmax_mtd[2] = {NULL, NULL};
-
-static void __exit cleanup_vmax301(void)
-{
-       int i;
-
-       for (i=0; i<2; i++) {
-               if (vmax_mtd[i]) {
-                       mtd_device_unregister(vmax_mtd[i]);
-                       map_destroy(vmax_mtd[i]);
-               }
-       }
-       iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START);
-}
-
-static int __init init_vmax301(void)
-{
-       int i;
-       unsigned long iomapadr;
-       // Print out our little header..
-       printk("Tempustech VMAX 301 MEM:0x%x-0x%x\n",WINDOW_START,
-              WINDOW_START+4*WINDOW_LENGTH);
-
-       iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH*4);
-       if (!iomapadr) {
-               printk("Failed to ioremap memory region\n");
-               return -EIO;
-       }
-       /* Put the address in the map's private data area.
-          We store the actual MTD IO address rather than the
-          address of the first half, because it's used more
-          often.
-       */
-       vmax_map[0].map_priv_2 = iomapadr + WINDOW_START;
-       vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START);
-
-       for (i=0; i<2; i++) {
-               vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]);
-               if (!vmax_mtd[i])
-                       vmax_mtd[i] = do_map_probe("jedec", &vmax_map[i]);
-               if (!vmax_mtd[i])
-                       vmax_mtd[i] = do_map_probe("map_ram", &vmax_map[i]);
-               if (!vmax_mtd[i])
-                       vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]);
-               if (vmax_mtd[i]) {
-                       vmax_mtd[i]->owner = THIS_MODULE;
-                       mtd_device_register(vmax_mtd[i], NULL, 0);
-               }
-       }
-
-       if (!vmax_mtd[0] && !vmax_mtd[1]) {
-               iounmap((void *)iomapadr);
-               return -ENXIO;
-       }
-
-       return 0;
-}
-
-module_init(init_vmax301);
-module_exit(cleanup_vmax301);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("MTD map driver for Tempustech VMAX SBC301 board");
index 048c823f5c51397df8c5e6ef023ba287ab65b02f..5e14d540ba2f623abb6438c4b6c204b991ed260b 100644 (file)
@@ -285,6 +285,16 @@ static DEVICE_ATTR(bitflip_threshold, S_IRUGO | S_IWUSR,
                   mtd_bitflip_threshold_show,
                   mtd_bitflip_threshold_store);
 
+static ssize_t mtd_ecc_step_size_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct mtd_info *mtd = dev_get_drvdata(dev);
+
+       return snprintf(buf, PAGE_SIZE, "%u\n", mtd->ecc_step_size);
+
+}
+static DEVICE_ATTR(ecc_step_size, S_IRUGO, mtd_ecc_step_size_show, NULL);
+
 static struct attribute *mtd_attrs[] = {
        &dev_attr_type.attr,
        &dev_attr_flags.attr,
@@ -296,6 +306,7 @@ static struct attribute *mtd_attrs[] = {
        &dev_attr_numeraseregions.attr,
        &dev_attr_name.attr,
        &dev_attr_ecc_strength.attr,
+       &dev_attr_ecc_step_size.attr,
        &dev_attr_bitflip_threshold.attr,
        NULL,
 };
index 301493382cd0a27a0df3fe0b5285fdb6a8cbb5f0..6e732c3820c14bf9d07b693a0c1de9bfff0088f0 100644 (file)
@@ -516,6 +516,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
        }
 
        slave->mtd.ecclayout = master->ecclayout;
+       slave->mtd.ecc_step_size = master->ecc_step_size;
        slave->mtd.ecc_strength = master->ecc_strength;
        slave->mtd.bitflip_threshold = master->bitflip_threshold;
 
index c92f0f6bc130e12380a53eab2a53239be33916f1..8b33b26eb12b25a1dccc1f4b42a7f8992b2229de 100644 (file)
@@ -1425,7 +1425,7 @@ static void mtdswap_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
                return;
 
        while ((this_opt = strsep(&parts, ",")) != NULL) {
-               if (strict_strtoul(this_opt, 0, &part) < 0)
+               if (kstrtoul(this_opt, 0, &part) < 0)
                        return;
 
                if (mtd->index == part)
index 50543f1662150ade806e9967190c60426a9ab029..d88529841d3f191dce0f8233a56f1cce63c0e0ba 100644 (file)
@@ -43,6 +43,7 @@ config MTD_SM_COMMON
 
 config MTD_NAND_DENALI
         tristate "Support Denali NAND controller"
+        depends on HAS_DMA
         help
          Enable support for the Denali NAND controller.  This should be
          combined with either the PCI or platform drivers to provide device
@@ -75,7 +76,7 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR
 
 config MTD_NAND_GPIO
        tristate "GPIO NAND Flash driver"
-       depends on GPIOLIB && ARM
+       depends on GPIOLIB
        help
          This enables a GPIO based NAND flash driver.
 
@@ -354,7 +355,7 @@ config MTD_NAND_ATMEL
 
 config MTD_NAND_PXA3xx
        tristate "Support for NAND flash devices on PXA3xx"
-       depends on PXA3xx || ARCH_MMP
+       depends on PXA3xx || ARCH_MMP || PLAT_ORION
        help
          This enables the driver for the NAND flash device found on
          PXA3xx processors
@@ -432,13 +433,6 @@ config MTD_NAND_PLATFORM
          devices. You will need to provide platform-specific functions
          via platform_data.
 
-config MTD_ALAUDA
-       tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
-       depends on USB
-       help
-         These two (and possibly other) Alauda-based cardreaders for
-         SmartMedia and xD allow raw flash access.
-
 config MTD_NAND_ORION
        tristate "NAND Flash support for Marvell Orion SoC"
        depends on PLAT_ORION
index bb8189172f62f49871573bb6119555fce1697654..542b5689eb636b0abad6501500872d376efad77a 100644 (file)
@@ -31,7 +31,6 @@ obj-$(CONFIG_MTD_NAND_CM_X270)                += cmx270_nand.o
 obj-$(CONFIG_MTD_NAND_PXA3xx)          += pxa3xx_nand.o
 obj-$(CONFIG_MTD_NAND_TMIO)            += tmio_nand.o
 obj-$(CONFIG_MTD_NAND_PLATFORM)                += plat_nand.o
-obj-$(CONFIG_MTD_ALAUDA)               += alauda.o
 obj-$(CONFIG_MTD_NAND_PASEMI)          += pasemi_nand.o
 obj-$(CONFIG_MTD_NAND_ORION)           += orion_nand.o
 obj-$(CONFIG_MTD_NAND_FSL_ELBC)                += fsl_elbc_nand.o
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
deleted file mode 100644 (file)
index 60a0dfd..0000000
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * MTD driver for Alauda chips
- *
- * Copyright (C) 2007 Joern Engel <joern@logfs.org>
- *
- * Based on drivers/usb/usb-skeleton.c which is:
- * Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
- * and on drivers/usb/storage/alauda.c, which is:
- *   (c) 2005 Daniel Drake <dsd@gentoo.org>
- *
- * Idea and initial work by Arnd Bergmann <arnd@arndb.de>
- */
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand_ecc.h>
-
-/* Control commands */
-#define ALAUDA_GET_XD_MEDIA_STATUS     0x08
-#define ALAUDA_ACK_XD_MEDIA_CHANGE     0x0a
-#define ALAUDA_GET_XD_MEDIA_SIG                0x86
-
-/* Common prefix */
-#define ALAUDA_BULK_CMD                        0x40
-
-/* The two ports */
-#define ALAUDA_PORT_XD                 0x00
-#define ALAUDA_PORT_SM                 0x01
-
-/* Bulk commands */
-#define ALAUDA_BULK_READ_PAGE          0x84
-#define ALAUDA_BULK_READ_OOB           0x85 /* don't use, there's a chip bug */
-#define ALAUDA_BULK_READ_BLOCK         0x94
-#define ALAUDA_BULK_ERASE_BLOCK                0xa3
-#define ALAUDA_BULK_WRITE_PAGE         0xa4
-#define ALAUDA_BULK_WRITE_BLOCK                0xb4
-#define ALAUDA_BULK_RESET_MEDIA                0xe0
-
-/* Address shifting */
-#define PBA_LO(pba) ((pba & 0xF) << 5)
-#define PBA_HI(pba) (pba >> 3)
-#define PBA_ZONE(pba) (pba >> 11)
-
-#define TIMEOUT HZ
-
-static const struct usb_device_id alauda_table[] = {
-       { USB_DEVICE(0x0584, 0x0008) }, /* Fujifilm DPC-R1 */
-       { USB_DEVICE(0x07b4, 0x010a) }, /* Olympus MAUSB-10 */
-       { }
-};
-MODULE_DEVICE_TABLE(usb, alauda_table);
-
-struct alauda_card {
-       u8      id;             /* id byte */
-       u8      chipshift;      /* 1<<chipshift total size */
-       u8      pageshift;      /* 1<<pageshift page size */
-       u8      blockshift;     /* 1<<blockshift block size */
-};
-
-struct alauda {
-       struct usb_device       *dev;
-       struct usb_interface    *interface;
-       struct mtd_info         *mtd;
-       struct alauda_card      *card;
-       struct mutex            card_mutex;
-       u32                     pagemask;
-       u32                     bytemask;
-       u32                     blockmask;
-       unsigned int            write_out;
-       unsigned int            bulk_in;
-       unsigned int            bulk_out;
-       u8                      port;
-       struct kref             kref;
-};
-
-static struct alauda_card alauda_card_ids[] = {
-       /* NAND flash */
-       { 0x6e, 20, 8, 12},     /* 1 MB */
-       { 0xe8, 20, 8, 12},     /* 1 MB */
-       { 0xec, 20, 8, 12},     /* 1 MB */
-       { 0x64, 21, 8, 12},     /* 2 MB */
-       { 0xea, 21, 8, 12},     /* 2 MB */
-       { 0x6b, 22, 9, 13},     /* 4 MB */
-       { 0xe3, 22, 9, 13},     /* 4 MB */
-       { 0xe5, 22, 9, 13},     /* 4 MB */
-       { 0xe6, 23, 9, 13},     /* 8 MB */
-       { 0x73, 24, 9, 14},     /* 16 MB */
-       { 0x75, 25, 9, 14},     /* 32 MB */
-       { 0x76, 26, 9, 14},     /* 64 MB */
-       { 0x79, 27, 9, 14},     /* 128 MB */
-       { 0x71, 28, 9, 14},     /* 256 MB */
-
-       /* MASK ROM */
-       { 0x5d, 21, 9, 13},     /* 2 MB */
-       { 0xd5, 22, 9, 13},     /* 4 MB */
-       { 0xd6, 23, 9, 13},     /* 8 MB */
-       { 0x57, 24, 9, 13},     /* 16 MB */
-       { 0x58, 25, 9, 13},     /* 32 MB */
-       { }
-};
-
-static struct alauda_card *get_card(u8 id)
-{
-       struct alauda_card *card;
-
-       for (card = alauda_card_ids; card->id; card++)
-               if (card->id == id)
-                       return card;
-       return NULL;
-}
-
-static void alauda_delete(struct kref *kref)
-{
-       struct alauda *al = container_of(kref, struct alauda, kref);
-
-       if (al->mtd) {
-               mtd_device_unregister(al->mtd);
-               kfree(al->mtd);
-       }
-       usb_put_dev(al->dev);
-       kfree(al);
-}
-
-static int alauda_get_media_status(struct alauda *al, void *buf)
-{
-       int ret;
-
-       mutex_lock(&al->card_mutex);
-       ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
-                       ALAUDA_GET_XD_MEDIA_STATUS, 0xc0, 0, 1, buf, 2, HZ);
-       mutex_unlock(&al->card_mutex);
-       return ret;
-}
-
-static int alauda_ack_media(struct alauda *al)
-{
-       int ret;
-
-       mutex_lock(&al->card_mutex);
-       ret = usb_control_msg(al->dev, usb_sndctrlpipe(al->dev, 0),
-                       ALAUDA_ACK_XD_MEDIA_CHANGE, 0x40, 0, 1, NULL, 0, HZ);
-       mutex_unlock(&al->card_mutex);
-       return ret;
-}
-
-static int alauda_get_media_signatures(struct alauda *al, void *buf)
-{
-       int ret;
-
-       mutex_lock(&al->card_mutex);
-       ret = usb_control_msg(al->dev, usb_rcvctrlpipe(al->dev, 0),
-                       ALAUDA_GET_XD_MEDIA_SIG, 0xc0, 0, 0, buf, 4, HZ);
-       mutex_unlock(&al->card_mutex);
-       return ret;
-}
-
-static void alauda_reset(struct alauda *al)
-{
-       u8 command[] = {
-               ALAUDA_BULK_CMD, ALAUDA_BULK_RESET_MEDIA, 0, 0,
-               0, 0, 0, 0, al->port
-       };
-       mutex_lock(&al->card_mutex);
-       usb_bulk_msg(al->dev, al->bulk_out, command, 9, NULL, HZ);
-       mutex_unlock(&al->card_mutex);
-}
-
-static void correct_data(void *buf, void *read_ecc,
-               int *corrected, int *uncorrected)
-{
-       u8 calc_ecc[3];
-       int err;
-
-       nand_calculate_ecc(NULL, buf, calc_ecc);
-       err = nand_correct_data(NULL, buf, read_ecc, calc_ecc);
-       if (err) {
-               if (err > 0)
-                       (*corrected)++;
-               else
-                       (*uncorrected)++;
-       }
-}
-
-struct alauda_sg_request {
-       struct urb *urb[3];
-       struct completion comp;
-};
-
-static void alauda_complete(struct urb *urb)
-{
-       struct completion *comp = urb->context;
-
-       if (comp)
-               complete(comp);
-}
-
-static int __alauda_read_page(struct mtd_info *mtd, loff_t from, void *buf,
-               void *oob)
-{
-       struct alauda_sg_request sg;
-       struct alauda *al = mtd->priv;
-       u32 pba = from >> al->card->blockshift;
-       u32 page = (from >> al->card->pageshift) & al->pagemask;
-       u8 command[] = {
-               ALAUDA_BULK_CMD, ALAUDA_BULK_READ_PAGE, PBA_HI(pba),
-               PBA_ZONE(pba), 0, PBA_LO(pba) + page, 1, 0, al->port
-       };
-       int i, err;
-
-       for (i=0; i<3; i++)
-               sg.urb[i] = NULL;
-
-       err = -ENOMEM;
-       for (i=0; i<3; i++) {
-               sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
-               if (!sg.urb[i])
-                       goto out;
-       }
-       init_completion(&sg.comp);
-       usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
-                       alauda_complete, NULL);
-       usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, mtd->writesize,
-                       alauda_complete, NULL);
-       usb_fill_bulk_urb(sg.urb[2], al->dev, al->bulk_in, oob, 16,
-                       alauda_complete, &sg.comp);
-
-       mutex_lock(&al->card_mutex);
-       for (i=0; i<3; i++) {
-               err = usb_submit_urb(sg.urb[i], GFP_NOIO);
-               if (err)
-                       goto cancel;
-       }
-       if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
-               err = -ETIMEDOUT;
-cancel:
-               for (i=0; i<3; i++) {
-                       usb_kill_urb(sg.urb[i]);
-               }
-       }
-       mutex_unlock(&al->card_mutex);
-
-out:
-       usb_free_urb(sg.urb[0]);
-       usb_free_urb(sg.urb[1]);
-       usb_free_urb(sg.urb[2]);
-       return err;
-}
-
-static int alauda_read_page(struct mtd_info *mtd, loff_t from,
-               void *buf, u8 *oob, int *corrected, int *uncorrected)
-{
-       int err;
-
-       err = __alauda_read_page(mtd, from, buf, oob);
-       if (err)
-               return err;
-       correct_data(buf, oob+13, corrected, uncorrected);
-       correct_data(buf+256, oob+8, corrected, uncorrected);
-       return 0;
-}
-
-static int alauda_write_page(struct mtd_info *mtd, loff_t to, void *buf,
-               void *oob)
-{
-       struct alauda_sg_request sg;
-       struct alauda *al = mtd->priv;
-       u32 pba = to >> al->card->blockshift;
-       u32 page = (to >> al->card->pageshift) & al->pagemask;
-       u8 command[] = {
-               ALAUDA_BULK_CMD, ALAUDA_BULK_WRITE_PAGE, PBA_HI(pba),
-               PBA_ZONE(pba), 0, PBA_LO(pba) + page, 32, 0, al->port
-       };
-       int i, err;
-
-       for (i=0; i<3; i++)
-               sg.urb[i] = NULL;
-
-       err = -ENOMEM;
-       for (i=0; i<3; i++) {
-               sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
-               if (!sg.urb[i])
-                       goto out;
-       }
-       init_completion(&sg.comp);
-       usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
-                       alauda_complete, NULL);
-       usb_fill_bulk_urb(sg.urb[1], al->dev, al->write_out, buf,mtd->writesize,
-                       alauda_complete, NULL);
-       usb_fill_bulk_urb(sg.urb[2], al->dev, al->write_out, oob, 16,
-                       alauda_complete, &sg.comp);
-
-       mutex_lock(&al->card_mutex);
-       for (i=0; i<3; i++) {
-               err = usb_submit_urb(sg.urb[i], GFP_NOIO);
-               if (err)
-                       goto cancel;
-       }
-       if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
-               err = -ETIMEDOUT;
-cancel:
-               for (i=0; i<3; i++) {
-                       usb_kill_urb(sg.urb[i]);
-               }
-       }
-       mutex_unlock(&al->card_mutex);
-
-out:
-       usb_free_urb(sg.urb[0]);
-       usb_free_urb(sg.urb[1]);
-       usb_free_urb(sg.urb[2]);
-       return err;
-}
-
-static int alauda_erase_block(struct mtd_info *mtd, loff_t ofs)
-{
-       struct alauda_sg_request sg;
-       struct alauda *al = mtd->priv;
-       u32 pba = ofs >> al->card->blockshift;
-       u8 command[] = {
-               ALAUDA_BULK_CMD, ALAUDA_BULK_ERASE_BLOCK, PBA_HI(pba),
-               PBA_ZONE(pba), 0, PBA_LO(pba), 0x02, 0, al->port
-       };
-       u8 buf[2];
-       int i, err;
-
-       for (i=0; i<2; i++)
-               sg.urb[i] = NULL;
-
-       err = -ENOMEM;
-       for (i=0; i<2; i++) {
-               sg.urb[i] = usb_alloc_urb(0, GFP_NOIO);
-               if (!sg.urb[i])
-                       goto out;
-       }
-       init_completion(&sg.comp);
-       usb_fill_bulk_urb(sg.urb[0], al->dev, al->bulk_out, command, 9,
-                       alauda_complete, NULL);
-       usb_fill_bulk_urb(sg.urb[1], al->dev, al->bulk_in, buf, 2,
-                       alauda_complete, &sg.comp);
-
-       mutex_lock(&al->card_mutex);
-       for (i=0; i<2; i++) {
-               err = usb_submit_urb(sg.urb[i], GFP_NOIO);
-               if (err)
-                       goto cancel;
-       }
-       if (!wait_for_completion_timeout(&sg.comp, TIMEOUT)) {
-               err = -ETIMEDOUT;
-cancel:
-               for (i=0; i<2; i++) {
-                       usb_kill_urb(sg.urb[i]);
-               }
-       }
-       mutex_unlock(&al->card_mutex);
-
-out:
-       usb_free_urb(sg.urb[0]);
-       usb_free_urb(sg.urb[1]);
-       return err;
-}
-
-static int alauda_read_oob(struct mtd_info *mtd, loff_t from, void *oob)
-{
-       static u8 ignore_buf[512]; /* write only */
-
-       return __alauda_read_page(mtd, from, ignore_buf, oob);
-}
-
-static int alauda_isbad(struct mtd_info *mtd, loff_t ofs)
-{
-       u8 oob[16];
-       int err;
-
-       err = alauda_read_oob(mtd, ofs, oob);
-       if (err)
-               return err;
-
-       /* A block is marked bad if two or more bits are zero */
-       return hweight8(oob[5]) >= 7 ? 0 : 1;
-}
-
-static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
-               size_t *retlen, u_char *buf)
-{
-       struct alauda *al = mtd->priv;
-       void *bounce_buf;
-       int err, corrected=0, uncorrected=0;
-
-       bounce_buf = kmalloc(mtd->writesize, GFP_KERNEL);
-       if (!bounce_buf)
-               return -ENOMEM;
-
-       *retlen = len;
-       while (len) {
-               u8 oob[16];
-               size_t byte = from & al->bytemask;
-               size_t cplen = min(len, mtd->writesize - byte);
-
-               err = alauda_read_page(mtd, from, bounce_buf, oob,
-                               &corrected, &uncorrected);
-               if (err)
-                       goto out;
-
-               memcpy(buf, bounce_buf + byte, cplen);
-               buf += cplen;
-               from += cplen;
-               len -= cplen;
-       }
-       err = 0;
-       if (corrected)
-               err = 1;        /* return max_bitflips per ecc step */
-       if (uncorrected)
-               err = -EBADMSG;
-out:
-       kfree(bounce_buf);
-       return err;
-}
-
-static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
-               size_t *retlen, u_char *buf)
-{
-       struct alauda *al = mtd->priv;
-       int err, corrected=0, uncorrected=0;
-
-       if ((from & al->bytemask) || (len & al->bytemask))
-               return alauda_bounce_read(mtd, from, len, retlen, buf);
-
-       *retlen = len;
-       while (len) {
-               u8 oob[16];
-
-               err = alauda_read_page(mtd, from, buf, oob,
-                               &corrected, &uncorrected);
-               if (err)
-                       return err;
-
-               buf += mtd->writesize;
-               from += mtd->writesize;
-               len -= mtd->writesize;
-       }
-       err = 0;
-       if (corrected)
-               err = 1;        /* return max_bitflips per ecc step */
-       if (uncorrected)
-               err = -EBADMSG;
-       return err;
-}
-
-static int alauda_write(struct mtd_info *mtd, loff_t to, size_t len,
-               size_t *retlen, const u_char *buf)
-{
-       struct alauda *al = mtd->priv;
-       int err;
-
-       if ((to & al->bytemask) || (len & al->bytemask))
-               return -EINVAL;
-
-       *retlen = len;
-       while (len) {
-               u32 page = (to >> al->card->pageshift) & al->pagemask;
-               u8 oob[16] = {  'h', 'e', 'l', 'l', 'o', 0xff, 0xff, 0xff,
-                               0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-
-               /* don't write to bad blocks */
-               if (page == 0) {
-                       err = alauda_isbad(mtd, to);
-                       if (err) {
-                               return -EIO;
-                       }
-               }
-               nand_calculate_ecc(mtd, buf, &oob[13]);
-               nand_calculate_ecc(mtd, buf+256, &oob[8]);
-
-               err = alauda_write_page(mtd, to, (void*)buf, oob);
-               if (err)
-                       return err;
-
-               buf += mtd->writesize;
-               to += mtd->writesize;
-               len -= mtd->writesize;
-       }
-       return 0;
-}
-
-static int __alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-       struct alauda *al = mtd->priv;
-       u32 ofs = instr->addr;
-       u32 len = instr->len;
-       int err;
-
-       if ((ofs & al->blockmask) || (len & al->blockmask))
-               return -EINVAL;
-
-       while (len) {
-               /* don't erase bad blocks */
-               err = alauda_isbad(mtd, ofs);
-               if (err > 0)
-                       err = -EIO;
-               if (err < 0)
-                       return err;
-
-               err = alauda_erase_block(mtd, ofs);
-               if (err < 0)
-                       return err;
-
-               ofs += mtd->erasesize;
-               len -= mtd->erasesize;
-       }
-       return 0;
-}
-
-static int alauda_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
-       int err;
-
-       err = __alauda_erase(mtd, instr);
-       instr->state = err ? MTD_ERASE_FAILED : MTD_ERASE_DONE;
-       mtd_erase_callback(instr);
-       return err;
-}
-
-static int alauda_init_media(struct alauda *al)
-{
-       u8 buf[4], *b0=buf, *b1=buf+1;
-       struct alauda_card *card;
-       struct mtd_info *mtd;
-       int err;
-
-       mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd)
-               return -ENOMEM;
-
-       for (;;) {
-               err = alauda_get_media_status(al, buf);
-               if (err < 0)
-                       goto error;
-               if (*b0 & 0x10)
-                       break;
-               msleep(20);
-       }
-
-       err = alauda_ack_media(al);
-       if (err)
-               goto error;
-
-       msleep(10);
-
-       err = alauda_get_media_status(al, buf);
-       if (err < 0)
-               goto error;
-
-       if (*b0 != 0x14) {
-               /* media not ready */
-               err = -EIO;
-               goto error;
-       }
-       err = alauda_get_media_signatures(al, buf);
-       if (err < 0)
-               goto error;
-
-       card = get_card(*b1);
-       if (!card) {
-               printk(KERN_ERR"Alauda: unknown card id %02x\n", *b1);
-               err = -EIO;
-               goto error;
-       }
-       printk(KERN_INFO"pagesize=%x\nerasesize=%x\nsize=%xMiB\n",
-                       1<<card->pageshift, 1<<card->blockshift,
-                       1<<(card->chipshift-20));
-       al->card = card;
-       al->pagemask = (1 << (card->blockshift - card->pageshift)) - 1;
-       al->bytemask = (1 << card->pageshift) - 1;
-       al->blockmask = (1 << card->blockshift) - 1;
-
-       mtd->name = "alauda";
-       mtd->size = 1<<card->chipshift;
-       mtd->erasesize = 1<<card->blockshift;
-       mtd->writesize = 1<<card->pageshift;
-       mtd->type = MTD_NANDFLASH;
-       mtd->flags = MTD_CAP_NANDFLASH;
-       mtd->_read = alauda_read;
-       mtd->_write = alauda_write;
-       mtd->_erase = alauda_erase;
-       mtd->_block_isbad = alauda_isbad;
-       mtd->priv = al;
-       mtd->owner = THIS_MODULE;
-       mtd->ecc_strength = 1;
-
-       err = mtd_device_register(mtd, NULL, 0);
-       if (err) {
-               err = -ENFILE;
-               goto error;
-       }
-
-       al->mtd = mtd;
-       alauda_reset(al); /* no clue whether this is necessary */
-       return 0;
-error:
-       kfree(mtd);
-       return err;
-}
-
-static int alauda_check_media(struct alauda *al)
-{
-       u8 buf[2], *b0 = buf, *b1 = buf+1;
-       int err;
-
-       err = alauda_get_media_status(al, buf);
-       if (err < 0)
-               return err;
-
-       if ((*b1 & 0x01) == 0) {
-               /* door open */
-               return -EIO;
-       }
-       if ((*b0 & 0x80) || ((*b0 & 0x1F) == 0x10)) {
-               /* no media ? */
-               return -EIO;
-       }
-       if (*b0 & 0x08) {
-               /* media change ? */
-               return alauda_init_media(al);
-       }
-       return 0;
-}
-
-static int alauda_probe(struct usb_interface *interface,
-               const struct usb_device_id *id)
-{
-       struct alauda *al;
-       struct usb_host_interface *iface;
-       struct usb_endpoint_descriptor *ep,
-                       *ep_in=NULL, *ep_out=NULL, *ep_wr=NULL;
-       int i, err = -ENOMEM;
-
-       al = kzalloc(2*sizeof(*al), GFP_KERNEL);
-       if (!al)
-               goto error;
-
-       kref_init(&al->kref);
-       usb_set_intfdata(interface, al);
-
-       al->dev = usb_get_dev(interface_to_usbdev(interface));
-       al->interface = interface;
-
-       iface = interface->cur_altsetting;
-       for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
-               ep = &iface->endpoint[i].desc;
-
-               if (usb_endpoint_is_bulk_in(ep)) {
-                       ep_in = ep;
-               } else if (usb_endpoint_is_bulk_out(ep)) {
-                       if (i==0)
-                               ep_wr = ep;
-                       else
-                               ep_out = ep;
-               }
-       }
-       err = -EIO;
-       if (!ep_wr || !ep_in || !ep_out)
-               goto error;
-
-       al->write_out = usb_sndbulkpipe(al->dev,
-                       usb_endpoint_num(ep_wr));
-       al->bulk_in = usb_rcvbulkpipe(al->dev,
-                       usb_endpoint_num(ep_in));
-       al->bulk_out = usb_sndbulkpipe(al->dev,
-                       usb_endpoint_num(ep_out));
-
-       /* second device is identical up to now */
-       memcpy(al+1, al, sizeof(*al));
-
-       mutex_init(&al[0].card_mutex);
-       mutex_init(&al[1].card_mutex);
-
-       al[0].port = ALAUDA_PORT_XD;
-       al[1].port = ALAUDA_PORT_SM;
-
-       dev_info(&interface->dev, "alauda probed\n");
-       alauda_check_media(al);
-       alauda_check_media(al+1);
-
-       return 0;
-
-error:
-       if (al)
-               kref_put(&al->kref, alauda_delete);
-       return err;
-}
-
-static void alauda_disconnect(struct usb_interface *interface)
-{
-       struct alauda *al;
-
-       al = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
-
-       /* FIXME: prevent more I/O from starting */
-
-       /* decrement our usage count */
-       if (al)
-               kref_put(&al->kref, alauda_delete);
-
-       dev_info(&interface->dev, "alauda gone");
-}
-
-static struct usb_driver alauda_driver = {
-       .name =         "alauda",
-       .probe =        alauda_probe,
-       .disconnect =   alauda_disconnect,
-       .id_table =     alauda_table,
-};
-
-module_usb_driver(alauda_driver);
-
-MODULE_LICENSE("GPL");
index f1d71cdc8aac97f827f7fac7d9a136342f0a6a22..8611eb4b45fca90e73d84db280b55301640fcd93 100644 (file)
@@ -258,7 +258,6 @@ static int ams_delta_init(struct platform_device *pdev)
  out_mtd:
        gpio_free_array(_mandatory_gpio, ARRAY_SIZE(_mandatory_gpio));
 out_gpio:
-       platform_set_drvdata(pdev, NULL);
        gpio_free(AMS_DELTA_GPIO_PIN_NAND_RB);
        iounmap(io_base);
 out_free:
index 2d23d2929438053a255ccad183e111ac7fe633ba..060feeaf6b3e5554328904a1ac870a97cbc5685b 100644 (file)
@@ -18,6 +18,9 @@
  *  Add Programmable Multibit ECC support for various AT91 SoC
  *     Â© Copyright 2012 ATMEL, Hong Xu
  *
+ *  Add Nand Flash Controller support for SAMA5 SoC
+ *     Â© Copyright 2013 ATMEL, Josh Wu (josh.wu@atmel.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/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
+#include <linux/delay.h>
 #include <linux/dmaengine.h>
 #include <linux/gpio.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/platform_data/atmel.h>
-#include <linux/pinctrl/consumer.h>
-
-#include <mach/cpu.h>
 
 static int use_dma = 1;
 module_param(use_dma, int, 0);
@@ -58,6 +60,7 @@ module_param(on_flash_bbt, int, 0);
        __raw_writel((value), add + ATMEL_ECC_##reg)
 
 #include "atmel_nand_ecc.h"    /* Hardware ECC registers */
+#include "atmel_nand_nfc.h"    /* Nand Flash Controller definition */
 
 /* oob layout for large page size
  * bad block info is on bytes 0 and 1
@@ -85,6 +88,23 @@ static struct nand_ecclayout atmel_oobinfo_small = {
        },
 };
 
+struct atmel_nfc {
+       void __iomem            *base_cmd_regs;
+       void __iomem            *hsmc_regs;
+       void __iomem            *sram_bank0;
+       dma_addr_t              sram_bank0_phys;
+       bool                    use_nfc_sram;
+       bool                    write_by_sram;
+
+       bool                    is_initialized;
+       struct completion       comp_nfc;
+
+       /* Point to the sram bank which include readed data via NFC */
+       void __iomem            *data_in_sram;
+       bool                    will_write_sram;
+};
+static struct atmel_nfc        nand_nfc;
+
 struct atmel_nand_host {
        struct nand_chip        nand_chip;
        struct mtd_info         mtd;
@@ -97,6 +117,8 @@ struct atmel_nand_host {
        struct completion       comp;
        struct dma_chan         *dma_chan;
 
+       struct atmel_nfc        *nfc;
+
        bool                    has_pmecc;
        u8                      pmecc_corr_cap;
        u16                     pmecc_sector_size;
@@ -128,11 +150,6 @@ struct atmel_nand_host {
 
 static struct nand_ecclayout atmel_pmecc_oobinfo;
 
-static int cpu_has_dma(void)
-{
-       return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
-}
-
 /*
  * Enable NAND.
  */
@@ -186,21 +203,103 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
                 !!host->board.rdy_pin_active_low;
 }
 
+/* Set up for hardware ready pin and enable pin. */
+static int atmel_nand_set_enable_ready_pins(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct atmel_nand_host *host = chip->priv;
+       int res = 0;
+
+       if (gpio_is_valid(host->board.rdy_pin)) {
+               res = devm_gpio_request(host->dev,
+                               host->board.rdy_pin, "nand_rdy");
+               if (res < 0) {
+                       dev_err(host->dev,
+                               "can't request rdy gpio %d\n",
+                               host->board.rdy_pin);
+                       return res;
+               }
+
+               res = gpio_direction_input(host->board.rdy_pin);
+               if (res < 0) {
+                       dev_err(host->dev,
+                               "can't request input direction rdy gpio %d\n",
+                               host->board.rdy_pin);
+                       return res;
+               }
+
+               chip->dev_ready = atmel_nand_device_ready;
+       }
+
+       if (gpio_is_valid(host->board.enable_pin)) {
+               res = devm_gpio_request(host->dev,
+                               host->board.enable_pin, "nand_enable");
+               if (res < 0) {
+                       dev_err(host->dev,
+                               "can't request enable gpio %d\n",
+                               host->board.enable_pin);
+                       return res;
+               }
+
+               res = gpio_direction_output(host->board.enable_pin, 1);
+               if (res < 0) {
+                       dev_err(host->dev,
+                               "can't request output direction enable gpio %d\n",
+                               host->board.enable_pin);
+                       return res;
+               }
+       }
+
+       return res;
+}
+
+static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
+{
+       int i;
+       u32 *t = trg;
+       const __iomem u32 *s = src;
+
+       for (i = 0; i < (size >> 2); i++)
+               *t++ = readl_relaxed(s++);
+}
+
+static void memcpy32_toio(void __iomem *trg, const void *src, int size)
+{
+       int i;
+       u32 __iomem *t = trg;
+       const u32 *s = src;
+
+       for (i = 0; i < (size >> 2); i++)
+               writel_relaxed(*s++, t++);
+}
+
 /*
  * Minimal-overhead PIO for data access.
  */
 static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
 {
        struct nand_chip        *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
 
-       __raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+       if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+               memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+               host->nfc->data_in_sram += len;
+       } else {
+               __raw_readsb(nand_chip->IO_ADDR_R, buf, len);
+       }
 }
 
 static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
 {
        struct nand_chip        *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
 
-       __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+       if (host->nfc && host->nfc->use_nfc_sram && host->nfc->data_in_sram) {
+               memcpy32_fromio(buf, host->nfc->data_in_sram, len);
+               host->nfc->data_in_sram += len;
+       } else {
+               __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
+       }
 }
 
 static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
@@ -222,6 +321,40 @@ static void dma_complete_func(void *completion)
        complete(completion);
 }
 
+static int nfc_set_sram_bank(struct atmel_nand_host *host, unsigned int bank)
+{
+       /* NFC only has two banks. Must be 0 or 1 */
+       if (bank > 1)
+               return -EINVAL;
+
+       if (bank) {
+               /* Only for a 2k-page or lower flash, NFC can handle 2 banks */
+               if (host->mtd.writesize > 2048)
+                       return -EINVAL;
+               nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK1);
+       } else {
+               nfc_writel(host->nfc->hsmc_regs, BANK, ATMEL_HSMC_NFC_BANK0);
+       }
+
+       return 0;
+}
+
+static uint nfc_get_sram_off(struct atmel_nand_host *host)
+{
+       if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+               return NFC_SRAM_BANK1_OFFSET;
+       else
+               return 0;
+}
+
+static dma_addr_t nfc_sram_phys(struct atmel_nand_host *host)
+{
+       if (nfc_readl(host->nfc->hsmc_regs, BANK) & ATMEL_HSMC_NFC_BANK1)
+               return host->nfc->sram_bank0_phys + NFC_SRAM_BANK1_OFFSET;
+       else
+               return host->nfc->sram_bank0_phys;
+}
+
 static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
                               int is_read)
 {
@@ -235,6 +368,7 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
        void *p = buf;
        int err = -EIO;
        enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+       struct atmel_nfc *nfc = host->nfc;
 
        if (buf >= high_memory)
                goto err_buf;
@@ -251,11 +385,20 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
        }
 
        if (is_read) {
-               dma_src_addr = host->io_phys;
+               if (nfc && nfc->data_in_sram)
+                       dma_src_addr = nfc_sram_phys(host) + (nfc->data_in_sram
+                               - (nfc->sram_bank0 + nfc_get_sram_off(host)));
+               else
+                       dma_src_addr = host->io_phys;
+
                dma_dst_addr = phys_addr;
        } else {
                dma_src_addr = phys_addr;
-               dma_dst_addr = host->io_phys;
+
+               if (nfc && nfc->write_by_sram)
+                       dma_dst_addr = nfc_sram_phys(host);
+               else
+                       dma_dst_addr = host->io_phys;
        }
 
        tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
@@ -278,6 +421,10 @@ static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
        dma_async_issue_pending(host->dma_chan);
        wait_for_completion(&host->comp);
 
+       if (is_read && nfc && nfc->data_in_sram)
+               /* After read data from SRAM, need to increase the position */
+               nfc->data_in_sram += len;
+
        err = 0;
 
 err_dma:
@@ -366,43 +513,34 @@ static void __iomem *pmecc_get_alpha_to(struct atmel_nand_host *host)
                        table_size * sizeof(int16_t);
 }
 
-static void pmecc_data_free(struct atmel_nand_host *host)
-{
-       kfree(host->pmecc_partial_syn);
-       kfree(host->pmecc_si);
-       kfree(host->pmecc_lmu);
-       kfree(host->pmecc_smu);
-       kfree(host->pmecc_mu);
-       kfree(host->pmecc_dmu);
-       kfree(host->pmecc_delta);
-}
-
 static int pmecc_data_alloc(struct atmel_nand_host *host)
 {
        const int cap = host->pmecc_corr_cap;
+       int size;
+
+       size = (2 * cap + 1) * sizeof(int16_t);
+       host->pmecc_partial_syn = devm_kzalloc(host->dev, size, GFP_KERNEL);
+       host->pmecc_si = devm_kzalloc(host->dev, size, GFP_KERNEL);
+       host->pmecc_lmu = devm_kzalloc(host->dev,
+                       (cap + 1) * sizeof(int16_t), GFP_KERNEL);
+       host->pmecc_smu = devm_kzalloc(host->dev,
+                       (cap + 2) * size, GFP_KERNEL);
+
+       size = (cap + 1) * sizeof(int);
+       host->pmecc_mu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+       host->pmecc_dmu = devm_kzalloc(host->dev, size, GFP_KERNEL);
+       host->pmecc_delta = devm_kzalloc(host->dev, size, GFP_KERNEL);
+
+       if (!host->pmecc_partial_syn ||
+               !host->pmecc_si ||
+               !host->pmecc_lmu ||
+               !host->pmecc_smu ||
+               !host->pmecc_mu ||
+               !host->pmecc_dmu ||
+               !host->pmecc_delta)
+               return -ENOMEM;
 
-       host->pmecc_partial_syn = kzalloc((2 * cap + 1) * sizeof(int16_t),
-                                       GFP_KERNEL);
-       host->pmecc_si = kzalloc((2 * cap + 1) * sizeof(int16_t), GFP_KERNEL);
-       host->pmecc_lmu = kzalloc((cap + 1) * sizeof(int16_t), GFP_KERNEL);
-       host->pmecc_smu = kzalloc((cap + 2) * (2 * cap + 1) * sizeof(int16_t),
-                                       GFP_KERNEL);
-       host->pmecc_mu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-       host->pmecc_dmu = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-       host->pmecc_delta = kzalloc((cap + 1) * sizeof(int), GFP_KERNEL);
-
-       if (host->pmecc_partial_syn &&
-                       host->pmecc_si &&
-                       host->pmecc_lmu &&
-                       host->pmecc_smu &&
-                       host->pmecc_mu &&
-                       host->pmecc_dmu &&
-                       host->pmecc_delta)
-               return 0;
-
-       /* error happened */
-       pmecc_data_free(host);
-       return -ENOMEM;
+       return 0;
 }
 
 static void pmecc_gen_syndrome(struct mtd_info *mtd, int sector)
@@ -763,6 +901,30 @@ normal_check:
        return total_err;
 }
 
+static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
+{
+       u32 val;
+
+       if (ecc_op != NAND_ECC_READ && ecc_op != NAND_ECC_WRITE) {
+               dev_err(host->dev, "atmel_nand: wrong pmecc operation type!");
+               return;
+       }
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
+       val = pmecc_readl_relaxed(host->ecc, CFG);
+
+       if (ecc_op == NAND_ECC_READ)
+               pmecc_writel(host->ecc, CFG, (val & ~PMECC_CFG_WRITE_OP)
+                       | PMECC_CFG_AUTO_ENABLE);
+       else
+               pmecc_writel(host->ecc, CFG, (val | PMECC_CFG_WRITE_OP)
+                       & ~PMECC_CFG_AUTO_ENABLE);
+
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
+       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+}
+
 static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
 {
@@ -774,13 +936,8 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd,
        unsigned long end_time;
        int bitflips = 0;
 
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-       pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG)
-               & ~PMECC_CFG_WRITE_OP) | PMECC_CFG_AUTO_ENABLE);
-
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
+       if (!host->nfc || !host->nfc->use_nfc_sram)
+               pmecc_enable(host, NAND_ECC_READ);
 
        chip->read_buf(mtd, buf, eccsize);
        chip->read_buf(mtd, oob, mtd->oobsize);
@@ -813,16 +970,10 @@ static int atmel_nand_pmecc_write_page(struct mtd_info *mtd,
        int i, j;
        unsigned long end_time;
 
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_RST);
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-
-       pmecc_writel(host->ecc, CFG, (pmecc_readl_relaxed(host->ecc, CFG) |
-               PMECC_CFG_WRITE_OP) & ~PMECC_CFG_AUTO_ENABLE);
-
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_ENABLE);
-       pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DATA);
-
-       chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+       if (!host->nfc || !host->nfc->write_by_sram) {
+               pmecc_enable(host, NAND_ECC_WRITE);
+               chip->write_buf(mtd, (u8 *)buf, mtd->writesize);
+       }
 
        end_time = jiffies + msecs_to_jiffies(PMECC_MAX_TIMEOUT_MS);
        while ((pmecc_readl_relaxed(host->ecc, SR) & PMECC_SR_BUSY)) {
@@ -967,11 +1118,11 @@ static int pmecc_choose_ecc(struct atmel_nand_host *host,
                        host->pmecc_corr_cap = 2;
                else if (*cap <= 4)
                        host->pmecc_corr_cap = 4;
-               else if (*cap < 8)
+               else if (*cap <= 8)
                        host->pmecc_corr_cap = 8;
-               else if (*cap < 12)
+               else if (*cap <= 12)
                        host->pmecc_corr_cap = 12;
-               else if (*cap < 24)
+               else if (*cap <= 24)
                        host->pmecc_corr_cap = 24;
                else
                        return -EINVAL;
@@ -1002,7 +1153,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
                return err_no;
        }
 
-       if (cap != host->pmecc_corr_cap ||
+       if (cap > host->pmecc_corr_cap ||
                        sector_size != host->pmecc_sector_size)
                dev_info(host->dev, "WARNING: Be Caution! Using different PMECC parameters from Nand ONFI ECC reqirement.\n");
 
@@ -1023,27 +1174,28 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
                return 0;
        }
 
-       host->ecc = ioremap(regs->start, resource_size(regs));
-       if (host->ecc == NULL) {
+       host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(host->ecc)) {
                dev_err(host->dev, "ioremap failed\n");
-               err_no = -EIO;
-               goto err_pmecc_ioremap;
+               err_no = PTR_ERR(host->ecc);
+               goto err;
        }
 
        regs_pmerr = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-       regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
-       if (regs_pmerr && regs_rom) {
-               host->pmerrloc_base = ioremap(regs_pmerr->start,
-                       resource_size(regs_pmerr));
-               host->pmecc_rom_base = ioremap(regs_rom->start,
-                       resource_size(regs_rom));
+       host->pmerrloc_base = devm_ioremap_resource(&pdev->dev, regs_pmerr);
+       if (IS_ERR(host->pmerrloc_base)) {
+               dev_err(host->dev,
+                       "Can not get I/O resource for PMECC ERRLOC controller!\n");
+               err_no = PTR_ERR(host->pmerrloc_base);
+               goto err;
        }
 
-       if (!host->pmerrloc_base || !host->pmecc_rom_base) {
-               dev_err(host->dev,
-                       "Can not get I/O resource for PMECC ERRLOC controller or ROM!\n");
-               err_no = -EIO;
-               goto err_pmloc_ioremap;
+       regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+       host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
+       if (IS_ERR(host->pmecc_rom_base)) {
+               dev_err(host->dev, "Can not get I/O resource for ROM!\n");
+               err_no = PTR_ERR(host->pmecc_rom_base);
+               goto err;
        }
 
        /* ECC is calculated for the whole page (1 step) */
@@ -1052,7 +1204,8 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
        /* set ECC page size and oob layout */
        switch (mtd->writesize) {
        case 2048:
-               host->pmecc_degree = PMECC_GF_DIMENSION_13;
+               host->pmecc_degree = (sector_size == 512) ?
+                       PMECC_GF_DIMENSION_13 : PMECC_GF_DIMENSION_14;
                host->pmecc_cw_len = (1 << host->pmecc_degree) - 1;
                host->pmecc_sector_number = mtd->writesize / sector_size;
                host->pmecc_bytes_per_sector = pmecc_get_ecc_bytes(
@@ -1068,7 +1221,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
                if (nand_chip->ecc.bytes > mtd->oobsize - 2) {
                        dev_err(host->dev, "No room for ECC bytes\n");
                        err_no = -EINVAL;
-                       goto err_no_ecc_room;
+                       goto err;
                }
                pmecc_config_ecc_layout(&atmel_pmecc_oobinfo,
                                        mtd->oobsize,
@@ -1093,7 +1246,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
        if (err_no) {
                dev_err(host->dev,
                                "Cannot allocate memory for PMECC computation!\n");
-               goto err_pmecc_data_alloc;
+               goto err;
        }
 
        nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
@@ -1103,15 +1256,7 @@ static int __init atmel_pmecc_nand_init_params(struct platform_device *pdev,
 
        return 0;
 
-err_pmecc_data_alloc:
-err_no_ecc_room:
-err_pmloc_ioremap:
-       iounmap(host->ecc);
-       if (host->pmerrloc_base)
-               iounmap(host->pmerrloc_base);
-       if (host->pmecc_rom_base)
-               iounmap(host->pmecc_rom_base);
-err_pmecc_ioremap:
+err:
        return err_no;
 }
 
@@ -1174,10 +1319,9 @@ static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
         * Workaround: Reset the parity registers before reading the
         * actual data.
         */
-       if (cpu_is_at32ap7000()) {
-               struct atmel_nand_host *host = chip->priv;
+       struct atmel_nand_host *host = chip->priv;
+       if (host->board.need_reset_workaround)
                ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
-       }
 
        /* read the page */
        chip->read_buf(mtd, p, eccsize);
@@ -1298,11 +1442,11 @@ static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat,
  */
 static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
 {
-       if (cpu_is_at32ap7000()) {
-               struct nand_chip *nand_chip = mtd->priv;
-               struct atmel_nand_host *host = nand_chip->priv;
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+
+       if (host->board.need_reset_workaround)
                ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
-       }
 }
 
 #if defined(CONFIG_OF)
@@ -1337,6 +1481,8 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
        board->on_flash_bbt = of_get_nand_on_flash_bbt(np);
 
+       board->has_dma = of_property_read_bool(np, "atmel,nand-has-dma");
+
        if (of_get_nand_bus_width(np) == 16)
                board->bus_width_16 = 1;
 
@@ -1348,6 +1494,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
 
        host->has_pmecc = of_property_read_bool(np, "atmel,has-pmecc");
 
+       /* load the nfc driver if there is */
+       of_platform_populate(np, NULL, NULL, host->dev);
+
        if (!(board->ecc_mode == NAND_ECC_HW) || !host->has_pmecc)
                return 0;       /* Not using PMECC */
 
@@ -1414,10 +1563,10 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
                return 0;
        }
 
-       host->ecc = ioremap(regs->start, resource_size(regs));
-       if (host->ecc == NULL) {
+       host->ecc = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(host->ecc)) {
                dev_err(host->dev, "ioremap failed\n");
-               return -EIO;
+               return PTR_ERR(host->ecc);
        }
 
        /* ECC is calculated for the whole page (1 step) */
@@ -1459,6 +1608,382 @@ static int __init atmel_hw_nand_init_params(struct platform_device *pdev,
        return 0;
 }
 
+/* SMC interrupt service routine */
+static irqreturn_t hsmc_interrupt(int irq, void *dev_id)
+{
+       struct atmel_nand_host *host = dev_id;
+       u32 status, mask, pending;
+       irqreturn_t ret = IRQ_HANDLED;
+
+       status = nfc_readl(host->nfc->hsmc_regs, SR);
+       mask = nfc_readl(host->nfc->hsmc_regs, IMR);
+       pending = status & mask;
+
+       if (pending & NFC_SR_XFR_DONE) {
+               complete(&host->nfc->comp_nfc);
+               nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_XFR_DONE);
+       } else if (pending & NFC_SR_RB_EDGE) {
+               complete(&host->nfc->comp_nfc);
+               nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_RB_EDGE);
+       } else if (pending & NFC_SR_CMD_DONE) {
+               complete(&host->nfc->comp_nfc);
+               nfc_writel(host->nfc->hsmc_regs, IDR, NFC_SR_CMD_DONE);
+       } else {
+               ret = IRQ_NONE;
+       }
+
+       return ret;
+}
+
+/* NFC(Nand Flash Controller) related functions */
+static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
+{
+       unsigned long timeout;
+       init_completion(&host->nfc->comp_nfc);
+
+       /* Enable interrupt that need to wait for */
+       nfc_writel(host->nfc->hsmc_regs, IER, flag);
+
+       timeout = wait_for_completion_timeout(&host->nfc->comp_nfc,
+                       msecs_to_jiffies(NFC_TIME_OUT_MS));
+       if (timeout)
+               return 0;
+
+       /* Time out to wait for the interrupt */
+       dev_err(host->dev, "Time out to wait for interrupt: 0x%08x\n", flag);
+       return -ETIMEDOUT;
+}
+
+static int nfc_send_command(struct atmel_nand_host *host,
+       unsigned int cmd, unsigned int addr, unsigned char cycle0)
+{
+       unsigned long timeout;
+       dev_dbg(host->dev,
+               "nfc_cmd: 0x%08x, addr1234: 0x%08x, cycle0: 0x%02x\n",
+               cmd, addr, cycle0);
+
+       timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+       while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
+                       & NFCADDR_CMD_NFCBUSY) {
+               if (time_after(jiffies, timeout)) {
+                       dev_err(host->dev,
+                               "Time out to wait CMD_NFCBUSY ready!\n");
+                       return -ETIMEDOUT;
+               }
+       }
+       nfc_writel(host->nfc->hsmc_regs, CYCLE0, cycle0);
+       nfc_cmd_addr1234_writel(cmd, addr, host->nfc->base_cmd_regs);
+       return nfc_wait_interrupt(host, NFC_SR_CMD_DONE);
+}
+
+static int nfc_device_ready(struct mtd_info *mtd)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+       if (!nfc_wait_interrupt(host, NFC_SR_RB_EDGE))
+               return 1;
+       return 0;
+}
+
+static void nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+       struct nand_chip *nand_chip = mtd->priv;
+       struct atmel_nand_host *host = nand_chip->priv;
+
+       if (chip == -1)
+               nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_DISABLE);
+       else
+               nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
+}
+
+static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
+               unsigned int *addr1234, unsigned int *cycle0)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       int acycle = 0;
+       unsigned char addr_bytes[8];
+       int index = 0, bit_shift;
+
+       BUG_ON(addr1234 == NULL || cycle0 == NULL);
+
+       *cycle0 = 0;
+       *addr1234 = 0;
+
+       if (column != -1) {
+               if (chip->options & NAND_BUSWIDTH_16)
+                       column >>= 1;
+               addr_bytes[acycle++] = column & 0xff;
+               if (mtd->writesize > 512)
+                       addr_bytes[acycle++] = (column >> 8) & 0xff;
+       }
+
+       if (page_addr != -1) {
+               addr_bytes[acycle++] = page_addr & 0xff;
+               addr_bytes[acycle++] = (page_addr >> 8) & 0xff;
+               if (chip->chipsize > (128 << 20))
+                       addr_bytes[acycle++] = (page_addr >> 16) & 0xff;
+       }
+
+       if (acycle > 4)
+               *cycle0 = addr_bytes[index++];
+
+       for (bit_shift = 0; index < acycle; bit_shift += 8)
+               *addr1234 += addr_bytes[index++] << bit_shift;
+
+       /* return acycle in cmd register */
+       return acycle << NFCADDR_CMD_ACYCLE_BIT_POS;
+}
+
+static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
+                               int column, int page_addr)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct atmel_nand_host *host = chip->priv;
+       unsigned long timeout;
+       unsigned int nfc_addr_cmd = 0;
+
+       unsigned int cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
+
+       /* Set default settings: no cmd2, no addr cycle. read from nand */
+       unsigned int cmd2 = 0;
+       unsigned int vcmd2 = 0;
+       int acycle = NFCADDR_CMD_ACYCLE_NONE;
+       int csid = NFCADDR_CMD_CSID_3;
+       int dataen = NFCADDR_CMD_DATADIS;
+       int nfcwr = NFCADDR_CMD_NFCRD;
+       unsigned int addr1234 = 0;
+       unsigned int cycle0 = 0;
+       bool do_addr = true;
+       host->nfc->data_in_sram = NULL;
+
+       dev_dbg(host->dev, "%s: cmd = 0x%02x, col = 0x%08x, page = 0x%08x\n",
+            __func__, command, column, page_addr);
+
+       switch (command) {
+       case NAND_CMD_RESET:
+               nfc_addr_cmd = cmd1 | acycle | csid | dataen | nfcwr;
+               nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+               udelay(chip->chip_delay);
+
+               nfc_nand_command(mtd, NAND_CMD_STATUS, -1, -1);
+               timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
+               while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) {
+                       if (time_after(jiffies, timeout)) {
+                               dev_err(host->dev,
+                                       "Time out to wait status ready!\n");
+                               break;
+                       }
+               }
+               return;
+       case NAND_CMD_STATUS:
+               do_addr = false;
+               break;
+       case NAND_CMD_PARAM:
+       case NAND_CMD_READID:
+               do_addr = false;
+               acycle = NFCADDR_CMD_ACYCLE_1;
+               if (column != -1)
+                       addr1234 = column;
+               break;
+       case NAND_CMD_RNDOUT:
+               cmd2 = NAND_CMD_RNDOUTSTART << NFCADDR_CMD_CMD2_BIT_POS;
+               vcmd2 = NFCADDR_CMD_VCMD2;
+               break;
+       case NAND_CMD_READ0:
+       case NAND_CMD_READOOB:
+               if (command == NAND_CMD_READOOB) {
+                       column += mtd->writesize;
+                       command = NAND_CMD_READ0; /* only READ0 is valid */
+                       cmd1 = command << NFCADDR_CMD_CMD1_BIT_POS;
+               }
+               if (host->nfc->use_nfc_sram) {
+                       /* Enable Data transfer to sram */
+                       dataen = NFCADDR_CMD_DATAEN;
+
+                       /* Need enable PMECC now, since NFC will transfer
+                        * data in bus after sending nfc read command.
+                        */
+                       if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+                               pmecc_enable(host, NAND_ECC_READ);
+               }
+
+               cmd2 = NAND_CMD_READSTART << NFCADDR_CMD_CMD2_BIT_POS;
+               vcmd2 = NFCADDR_CMD_VCMD2;
+               break;
+       /* For prgramming command, the cmd need set to write enable */
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_RNDIN:
+               nfcwr = NFCADDR_CMD_NFCWR;
+               if (host->nfc->will_write_sram && command == NAND_CMD_SEQIN)
+                       dataen = NFCADDR_CMD_DATAEN;
+               break;
+       default:
+               break;
+       }
+
+       if (do_addr)
+               acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
+                               &cycle0);
+
+       nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
+       nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
+
+       if (dataen == NFCADDR_CMD_DATAEN)
+               if (nfc_wait_interrupt(host, NFC_SR_XFR_DONE))
+                       dev_err(host->dev, "something wrong, No XFR_DONE interrupt comes.\n");
+
+       /*
+        * Program and erase have their own busy handlers status, sequential
+        * in, and deplete1 need no delay.
+        */
+       switch (command) {
+       case NAND_CMD_CACHEDPROG:
+       case NAND_CMD_PAGEPROG:
+       case NAND_CMD_ERASE1:
+       case NAND_CMD_ERASE2:
+       case NAND_CMD_RNDIN:
+       case NAND_CMD_STATUS:
+       case NAND_CMD_RNDOUT:
+       case NAND_CMD_SEQIN:
+       case NAND_CMD_READID:
+               return;
+
+       case NAND_CMD_READ0:
+               if (dataen == NFCADDR_CMD_DATAEN) {
+                       host->nfc->data_in_sram = host->nfc->sram_bank0 +
+                               nfc_get_sram_off(host);
+                       return;
+               }
+               /* fall through */
+       default:
+               nfc_wait_interrupt(host, NFC_SR_RB_EDGE);
+       }
+}
+
+static int nfc_sram_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+                       uint32_t offset, int data_len, const uint8_t *buf,
+                       int oob_required, int page, int cached, int raw)
+{
+       int cfg, len;
+       int status = 0;
+       struct atmel_nand_host *host = chip->priv;
+       void __iomem *sram = host->nfc->sram_bank0 + nfc_get_sram_off(host);
+
+       /* Subpage write is not supported */
+       if (offset || (data_len < mtd->writesize))
+               return -EINVAL;
+
+       cfg = nfc_readl(host->nfc->hsmc_regs, CFG);
+       len = mtd->writesize;
+
+       if (unlikely(raw)) {
+               len += mtd->oobsize;
+               nfc_writel(host->nfc->hsmc_regs, CFG, cfg | NFC_CFG_WSPARE);
+       } else
+               nfc_writel(host->nfc->hsmc_regs, CFG, cfg & ~NFC_CFG_WSPARE);
+
+       /* Copy page data to sram that will write to nand via NFC */
+       if (use_dma) {
+               if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) != 0)
+                       /* Fall back to use cpu copy */
+                       memcpy32_toio(sram, buf, len);
+       } else {
+               memcpy32_toio(sram, buf, len);
+       }
+
+       if (chip->ecc.mode == NAND_ECC_HW && host->has_pmecc)
+               /*
+                * When use NFC sram, need set up PMECC before send
+                * NAND_CMD_SEQIN command. Since when the nand command
+                * is sent, nfc will do transfer from sram and nand.
+                */
+               pmecc_enable(host, NAND_ECC_WRITE);
+
+       host->nfc->will_write_sram = true;
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+       host->nfc->will_write_sram = false;
+
+       if (likely(!raw))
+               /* Need to write ecc into oob */
+               status = chip->ecc.write_page(mtd, chip, buf, oob_required);
+
+       if (status < 0)
+               return status;
+
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       status = chip->waitfunc(mtd, chip);
+
+       if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+               status = chip->errstat(mtd, chip, FL_WRITING, status, page);
+
+       if (status & NAND_STATUS_FAIL)
+               return -EIO;
+
+       return 0;
+}
+
+static int nfc_sram_init(struct mtd_info *mtd)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct atmel_nand_host *host = chip->priv;
+       int res = 0;
+
+       /* Initialize the NFC CFG register */
+       unsigned int cfg_nfc = 0;
+
+       /* set page size and oob layout */
+       switch (mtd->writesize) {
+       case 512:
+               cfg_nfc = NFC_CFG_PAGESIZE_512;
+               break;
+       case 1024:
+               cfg_nfc = NFC_CFG_PAGESIZE_1024;
+               break;
+       case 2048:
+               cfg_nfc = NFC_CFG_PAGESIZE_2048;
+               break;
+       case 4096:
+               cfg_nfc = NFC_CFG_PAGESIZE_4096;
+               break;
+       case 8192:
+               cfg_nfc = NFC_CFG_PAGESIZE_8192;
+               break;
+       default:
+               dev_err(host->dev, "Unsupported page size for NFC.\n");
+               res = -ENXIO;
+               return res;
+       }
+
+       /* oob bytes size = (NFCSPARESIZE + 1) * 4
+        * Max support spare size is 512 bytes. */
+       cfg_nfc |= (((mtd->oobsize / 4) - 1) << NFC_CFG_NFC_SPARESIZE_BIT_POS
+               & NFC_CFG_NFC_SPARESIZE);
+       /* default set a max timeout */
+       cfg_nfc |= NFC_CFG_RSPARE |
+                       NFC_CFG_NFC_DTOCYC | NFC_CFG_NFC_DTOMUL;
+
+       nfc_writel(host->nfc->hsmc_regs, CFG, cfg_nfc);
+
+       host->nfc->will_write_sram = false;
+       nfc_set_sram_bank(host, 0);
+
+       /* Use Write page with NFC SRAM only for PMECC or ECC NONE. */
+       if (host->nfc->write_by_sram) {
+               if ((chip->ecc.mode == NAND_ECC_HW && host->has_pmecc) ||
+                               chip->ecc.mode == NAND_ECC_NONE)
+                       chip->write_page = nfc_sram_write_page;
+               else
+                       host->nfc->write_by_sram = false;
+       }
+
+       dev_info(host->dev, "Using NFC Sram read %s\n",
+                       host->nfc->write_by_sram ? "and write" : "");
+       return 0;
+}
+
+static struct platform_driver atmel_nand_nfc_driver;
 /*
  * Probe for the NAND device.
  */
@@ -1469,30 +1994,27 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        struct nand_chip *nand_chip;
        struct resource *mem;
        struct mtd_part_parser_data ppdata = {};
-       int res;
-       struct pinctrl *pinctrl;
-
-       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               printk(KERN_ERR "atmel_nand: can't get I/O resource mem\n");
-               return -ENXIO;
-       }
+       int res, irq;
 
        /* Allocate memory for the device structure (and zero it) */
-       host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL);
+       host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
        if (!host) {
                printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
                return -ENOMEM;
        }
 
-       host->io_phys = (dma_addr_t)mem->start;
+       res = platform_driver_register(&atmel_nand_nfc_driver);
+       if (res)
+               dev_err(&pdev->dev, "atmel_nand: can't register NFC driver\n");
 
-       host->io_base = ioremap(mem->start, resource_size(mem));
-       if (host->io_base == NULL) {
-               printk(KERN_ERR "atmel_nand: ioremap failed\n");
-               res = -EIO;
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->io_base = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(host->io_base)) {
+               dev_err(&pdev->dev, "atmel_nand: ioremap resource failed\n");
+               res = PTR_ERR(host->io_base);
                goto err_nand_ioremap;
        }
+       host->io_phys = (dma_addr_t)mem->start;
 
        mtd = &host->mtd;
        nand_chip = &host->nand_chip;
@@ -1500,9 +2022,9 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        if (pdev->dev.of_node) {
                res = atmel_of_init_port(host, pdev->dev.of_node);
                if (res)
-                       goto err_ecc_ioremap;
+                       goto err_nand_ioremap;
        } else {
-               memcpy(&host->board, pdev->dev.platform_data,
+               memcpy(&host->board, dev_get_platdata(&pdev->dev),
                       sizeof(struct atmel_nand_data));
        }
 
@@ -1513,51 +2035,36 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        /* Set address of NAND IO lines */
        nand_chip->IO_ADDR_R = host->io_base;
        nand_chip->IO_ADDR_W = host->io_base;
-       nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
 
-       pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               dev_err(host->dev, "Failed to request pinctrl\n");
-               res = PTR_ERR(pinctrl);
-               goto err_ecc_ioremap;
-       }
+       if (nand_nfc.is_initialized) {
+               /* NFC driver is probed and initialized */
+               host->nfc = &nand_nfc;
 
-       if (gpio_is_valid(host->board.rdy_pin)) {
-               res = gpio_request(host->board.rdy_pin, "nand_rdy");
-               if (res < 0) {
-                       dev_err(&pdev->dev,
-                               "can't request rdy gpio %d\n",
-                               host->board.rdy_pin);
-                       goto err_ecc_ioremap;
-               }
+               nand_chip->select_chip = nfc_select_chip;
+               nand_chip->dev_ready = nfc_device_ready;
+               nand_chip->cmdfunc = nfc_nand_command;
 
-               res = gpio_direction_input(host->board.rdy_pin);
-               if (res < 0) {
-                       dev_err(&pdev->dev,
-                               "can't request input direction rdy gpio %d\n",
-                               host->board.rdy_pin);
-                       goto err_ecc_ioremap;
+               /* Initialize the interrupt for NFC */
+               irq = platform_get_irq(pdev, 0);
+               if (irq < 0) {
+                       dev_err(host->dev, "Cannot get HSMC irq!\n");
+                       res = irq;
+                       goto err_nand_ioremap;
                }
 
-               nand_chip->dev_ready = atmel_nand_device_ready;
-       }
-
-       if (gpio_is_valid(host->board.enable_pin)) {
-               res = gpio_request(host->board.enable_pin, "nand_enable");
-               if (res < 0) {
-                       dev_err(&pdev->dev,
-                               "can't request enable gpio %d\n",
-                               host->board.enable_pin);
-                       goto err_ecc_ioremap;
+               res = devm_request_irq(&pdev->dev, irq, hsmc_interrupt,
+                               0, "hsmc", host);
+               if (res) {
+                       dev_err(&pdev->dev, "Unable to request HSMC irq %d\n",
+                               irq);
+                       goto err_nand_ioremap;
                }
+       } else {
+               res = atmel_nand_set_enable_ready_pins(mtd);
+               if (res)
+                       goto err_nand_ioremap;
 
-               res = gpio_direction_output(host->board.enable_pin, 1);
-               if (res < 0) {
-                       dev_err(&pdev->dev,
-                               "can't request output direction enable gpio %d\n",
-                               host->board.enable_pin);
-                       goto err_ecc_ioremap;
-               }
+               nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl;
        }
 
        nand_chip->ecc.mode = host->board.ecc_mode;
@@ -1573,7 +2080,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
        atmel_nand_enable(host);
 
        if (gpio_is_valid(host->board.det_pin)) {
-               res = gpio_request(host->board.det_pin, "nand_det");
+               res = devm_gpio_request(&pdev->dev,
+                               host->board.det_pin, "nand_det");
                if (res < 0) {
                        dev_err(&pdev->dev,
                                "can't request det gpio %d\n",
@@ -1601,7 +2109,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
        }
 
-       if (!cpu_has_dma())
+       if (!host->board.has_dma)
                use_dma = 0;
 
        if (use_dma) {
@@ -1637,6 +2145,15 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                        goto err_hw_ecc;
        }
 
+       /* initialize the nfc configuration register */
+       if (host->nfc && host->nfc->use_nfc_sram) {
+               res = nfc_sram_init(mtd);
+               if (res) {
+                       host->nfc->use_nfc_sram = false;
+                       dev_err(host->dev, "Disable use nfc sram for data transfer.\n");
+               }
+       }
+
        /* second phase scan */
        if (nand_scan_tail(mtd)) {
                res = -ENXIO;
@@ -1651,27 +2168,16 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
                return res;
 
 err_scan_tail:
-       if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW) {
+       if (host->has_pmecc && host->nand_chip.ecc.mode == NAND_ECC_HW)
                pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
-               pmecc_data_free(host);
-       }
-       if (host->ecc)
-               iounmap(host->ecc);
-       if (host->pmerrloc_base)
-               iounmap(host->pmerrloc_base);
-       if (host->pmecc_rom_base)
-               iounmap(host->pmecc_rom_base);
 err_hw_ecc:
 err_scan_ident:
 err_no_card:
        atmel_nand_disable(host);
-       platform_set_drvdata(pdev, NULL);
        if (host->dma_chan)
                dma_release_channel(host->dma_chan);
-err_ecc_ioremap:
-       iounmap(host->io_base);
 err_nand_ioremap:
-       kfree(host);
+       platform_driver_unregister(&atmel_nand_nfc_driver);
        return res;
 }
 
@@ -1691,30 +2197,12 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
                pmecc_writel(host->ecc, CTRL, PMECC_CTRL_DISABLE);
                pmerrloc_writel(host->pmerrloc_base, ELDIS,
                                PMERRLOC_DISABLE);
-               pmecc_data_free(host);
        }
 
-       if (gpio_is_valid(host->board.det_pin))
-               gpio_free(host->board.det_pin);
-
-       if (gpio_is_valid(host->board.enable_pin))
-               gpio_free(host->board.enable_pin);
-
-       if (gpio_is_valid(host->board.rdy_pin))
-               gpio_free(host->board.rdy_pin);
-
-       if (host->ecc)
-               iounmap(host->ecc);
-       if (host->pmecc_rom_base)
-               iounmap(host->pmecc_rom_base);
-       if (host->pmerrloc_base)
-               iounmap(host->pmerrloc_base);
-
        if (host->dma_chan)
                dma_release_channel(host->dma_chan);
 
-       iounmap(host->io_base);
-       kfree(host);
+       platform_driver_unregister(&atmel_nand_nfc_driver);
 
        return 0;
 }
@@ -1728,6 +2216,59 @@ static const struct of_device_id atmel_nand_dt_ids[] = {
 MODULE_DEVICE_TABLE(of, atmel_nand_dt_ids);
 #endif
 
+static int atmel_nand_nfc_probe(struct platform_device *pdev)
+{
+       struct atmel_nfc *nfc = &nand_nfc;
+       struct resource *nfc_cmd_regs, *nfc_hsmc_regs, *nfc_sram;
+
+       nfc_cmd_regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       nfc->base_cmd_regs = devm_ioremap_resource(&pdev->dev, nfc_cmd_regs);
+       if (IS_ERR(nfc->base_cmd_regs))
+               return PTR_ERR(nfc->base_cmd_regs);
+
+       nfc_hsmc_regs = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       nfc->hsmc_regs = devm_ioremap_resource(&pdev->dev, nfc_hsmc_regs);
+       if (IS_ERR(nfc->hsmc_regs))
+               return PTR_ERR(nfc->hsmc_regs);
+
+       nfc_sram = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+       if (nfc_sram) {
+               nfc->sram_bank0 = devm_ioremap_resource(&pdev->dev, nfc_sram);
+               if (IS_ERR(nfc->sram_bank0)) {
+                       dev_warn(&pdev->dev, "Fail to ioremap the NFC sram with error: %ld. So disable NFC sram.\n",
+                                       PTR_ERR(nfc->sram_bank0));
+               } else {
+                       nfc->use_nfc_sram = true;
+                       nfc->sram_bank0_phys = (dma_addr_t)nfc_sram->start;
+
+                       if (pdev->dev.of_node)
+                               nfc->write_by_sram = of_property_read_bool(
+                                               pdev->dev.of_node,
+                                               "atmel,write-by-sram");
+               }
+       }
+
+       nfc->is_initialized = true;
+       dev_info(&pdev->dev, "NFC is probed.\n");
+       return 0;
+}
+
+#if defined(CONFIG_OF)
+static struct of_device_id atmel_nand_nfc_match[] = {
+       { .compatible = "atmel,sama5d3-nfc" },
+       { /* sentinel */ }
+};
+#endif
+
+static struct platform_driver atmel_nand_nfc_driver = {
+       .driver = {
+               .name = "atmel_nand_nfc",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(atmel_nand_nfc_match),
+       },
+       .probe = atmel_nand_nfc_probe,
+};
+
 static struct platform_driver atmel_nand_driver = {
        .remove         = __exit_p(atmel_nand_remove),
        .driver         = {
diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h
new file mode 100644 (file)
index 0000000..4efd117
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Atmel Nand Flash Controller (NFC) - System peripherals regsters.
+ * Based on SAMA5D3 datasheet.
+ *
+ * Â© Copyright 2013 Atmel Corporation.
+ *
+ * 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 ATMEL_NAND_NFC_H
+#define ATMEL_NAND_NFC_H
+
+/*
+ * HSMC NFC registers
+ */
+#define ATMEL_HSMC_NFC_CFG     0x00            /* NFC Configuration Register */
+#define                NFC_CFG_PAGESIZE        (7 << 0)
+#define                        NFC_CFG_PAGESIZE_512    (0 << 0)
+#define                        NFC_CFG_PAGESIZE_1024   (1 << 0)
+#define                        NFC_CFG_PAGESIZE_2048   (2 << 0)
+#define                        NFC_CFG_PAGESIZE_4096   (3 << 0)
+#define                        NFC_CFG_PAGESIZE_8192   (4 << 0)
+#define                NFC_CFG_WSPARE          (1 << 8)
+#define                NFC_CFG_RSPARE          (1 << 9)
+#define                NFC_CFG_NFC_DTOCYC      (0xf << 16)
+#define                NFC_CFG_NFC_DTOMUL      (0x7 << 20)
+#define                NFC_CFG_NFC_SPARESIZE   (0x7f << 24)
+#define                NFC_CFG_NFC_SPARESIZE_BIT_POS   24
+
+#define ATMEL_HSMC_NFC_CTRL    0x04            /* NFC Control Register */
+#define                NFC_CTRL_ENABLE         (1 << 0)
+#define                NFC_CTRL_DISABLE        (1 << 1)
+
+#define ATMEL_HSMC_NFC_SR      0x08            /* NFC Status Register */
+#define                NFC_SR_XFR_DONE         (1 << 16)
+#define                NFC_SR_CMD_DONE         (1 << 17)
+#define                NFC_SR_RB_EDGE          (1 << 24)
+
+#define ATMEL_HSMC_NFC_IER     0x0c
+#define ATMEL_HSMC_NFC_IDR     0x10
+#define ATMEL_HSMC_NFC_IMR     0x14
+#define ATMEL_HSMC_NFC_CYCLE0  0x18            /* NFC Address Cycle Zero */
+#define                ATMEL_HSMC_NFC_ADDR_CYCLE0      (0xff)
+
+#define ATMEL_HSMC_NFC_BANK    0x1c            /* NFC Bank Register */
+#define                ATMEL_HSMC_NFC_BANK0            (0 << 0)
+#define                ATMEL_HSMC_NFC_BANK1            (1 << 0)
+
+#define nfc_writel(addr, reg, value) \
+       writel((value), (addr) + ATMEL_HSMC_NFC_##reg)
+
+#define nfc_readl(addr, reg) \
+       readl_relaxed((addr) + ATMEL_HSMC_NFC_##reg)
+
+/*
+ * NFC Address Command definitions
+ */
+#define NFCADDR_CMD_CMD1       (0xff << 2)     /* Command for Cycle 1 */
+#define NFCADDR_CMD_CMD1_BIT_POS       2
+#define NFCADDR_CMD_CMD2       (0xff << 10)    /* Command for Cycle 2 */
+#define NFCADDR_CMD_CMD2_BIT_POS       10
+#define NFCADDR_CMD_VCMD2      (0x1 << 18)     /* Valid Cycle 2 Command */
+#define NFCADDR_CMD_ACYCLE     (0x7 << 19)     /* Number of Address required */
+#define                NFCADDR_CMD_ACYCLE_NONE         (0x0 << 19)
+#define                NFCADDR_CMD_ACYCLE_1            (0x1 << 19)
+#define                NFCADDR_CMD_ACYCLE_2            (0x2 << 19)
+#define                NFCADDR_CMD_ACYCLE_3            (0x3 << 19)
+#define                NFCADDR_CMD_ACYCLE_4            (0x4 << 19)
+#define                NFCADDR_CMD_ACYCLE_5            (0x5 << 19)
+#define NFCADDR_CMD_ACYCLE_BIT_POS     19
+#define NFCADDR_CMD_CSID       (0x7 << 22)     /* Chip Select Identifier */
+#define                NFCADDR_CMD_CSID_0              (0x0 << 22)
+#define                NFCADDR_CMD_CSID_1              (0x1 << 22)
+#define                NFCADDR_CMD_CSID_2              (0x2 << 22)
+#define                NFCADDR_CMD_CSID_3              (0x3 << 22)
+#define                NFCADDR_CMD_CSID_4              (0x4 << 22)
+#define                NFCADDR_CMD_CSID_5              (0x5 << 22)
+#define                NFCADDR_CMD_CSID_6              (0x6 << 22)
+#define                NFCADDR_CMD_CSID_7              (0x7 << 22)
+#define NFCADDR_CMD_DATAEN     (0x1 << 25)     /* Data Transfer Enable */
+#define NFCADDR_CMD_DATADIS    (0x0 << 25)     /* Data Transfer Disable */
+#define NFCADDR_CMD_NFCRD      (0x0 << 26)     /* NFC Read Enable */
+#define NFCADDR_CMD_NFCWR      (0x1 << 26)     /* NFC Write Enable */
+#define NFCADDR_CMD_NFCBUSY    (0x1 << 27)     /* NFC Busy */
+
+#define nfc_cmd_addr1234_writel(cmd, addr1234, nfc_base) \
+       writel((addr1234), (cmd) + nfc_base)
+
+#define nfc_cmd_readl(bitstatus, nfc_base) \
+       readl_relaxed((bitstatus) + nfc_base)
+
+#define NFC_TIME_OUT_MS                100
+#define        NFC_SRAM_BANK1_OFFSET   0x1200
+
+#endif
index 217459d02b2f85b6d5730e1c0d77e4fac7a108eb..ae8dd7c4103922fc760786be079b7576ad648893 100644 (file)
@@ -411,7 +411,7 @@ static int au1550nd_probe(struct platform_device *pdev)
        struct resource *r;
        int ret, cs;
 
-       pd = pdev->dev.platform_data;
+       pd = dev_get_platdata(&pdev->dev);
        if (!pd) {
                dev_err(&pdev->dev, "missing platform data\n");
                return -ENODEV;
index 776df3694f755865f88b7e0a499cac533dd04142..2c42e125720f2141258e064e1fc024fef092057b 100644 (file)
@@ -171,7 +171,7 @@ static struct bf5xx_nand_info *to_nand_info(struct platform_device *pdev)
 
 static struct bf5xx_nand_platform *to_nand_plat(struct platform_device *pdev)
 {
-       return pdev->dev.platform_data;
+       return dev_get_platdata(&pdev->dev);
 }
 
 /*
@@ -671,8 +671,6 @@ static int bf5xx_nand_remove(struct platform_device *pdev)
 {
        struct bf5xx_nand_info *info = to_nand_info(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        /* first thing we need to do is release all our mtds
         * and their partitions, then go through freeing the
         * resources used
@@ -832,7 +830,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 out_err_nand_scan:
        bf5xx_nand_dma_remove(info);
 out_err_hw_init:
-       platform_set_drvdata(pdev, NULL);
        kfree(info);
 out_err_kzalloc:
        peripheral_free_list(bfin_nfc_pin_req);
index 2cdeab8bebc434a68c486031e96d8dcbcce93bd2..d469a9a1dea0de7ea5f31172995c6e79411e7822 100644 (file)
@@ -197,7 +197,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        }
 
        /* Allocate memory for MTD device structure and private data */
-       new_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
+       new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
        if (!new_mtd) {
                printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
                err = -ENOMEM;
@@ -207,10 +207,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        /* Get pointer to private data */
        this = (struct nand_chip *)(&new_mtd[1]);
 
-       /* Initialize structures */
-       memset(new_mtd, 0, sizeof(struct mtd_info));
-       memset(this, 0, sizeof(struct nand_chip));
-
        /* Link the private data with the MTD structure */
        new_mtd->priv = this;
        new_mtd->owner = THIS_MODULE;
index c3e15a55817349eb4ed2e1c86009b042c38e2405..b77a01efb4837ea325988ee6e58e82bd128d7892 100644 (file)
@@ -530,7 +530,7 @@ MODULE_DEVICE_TABLE(of, davinci_nand_of_match);
 static struct davinci_nand_pdata
        *nand_davinci_get_pdata(struct platform_device *pdev)
 {
-       if (!pdev->dev.platform_data && pdev->dev.of_node) {
+       if (!dev_get_platdata(&pdev->dev) && pdev->dev.of_node) {
                struct davinci_nand_pdata *pdata;
                const char *mode;
                u32 prop;
@@ -575,13 +575,13 @@ static struct davinci_nand_pdata
                        pdata->bbt_options = NAND_BBT_USE_FLASH;
        }
 
-       return pdev->dev.platform_data;
+       return dev_get_platdata(&pdev->dev);
 }
 #else
 static struct davinci_nand_pdata
        *nand_davinci_get_pdata(struct platform_device *pdev)
 {
-       return pdev->dev.platform_data;
+       return dev_get_platdata(&pdev->dev);
 }
 #endif
 
@@ -623,11 +623,14 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                goto err_nomem;
        }
 
-       vaddr = devm_request_and_ioremap(&pdev->dev, res1);
-       base = devm_request_and_ioremap(&pdev->dev, res2);
-       if (!vaddr || !base) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               ret = -EADDRNOTAVAIL;
+       vaddr = devm_ioremap_resource(&pdev->dev, res1);
+       if (IS_ERR(vaddr)) {
+               ret = PTR_ERR(vaddr);
+               goto err_ioremap;
+       }
+       base = devm_ioremap_resource(&pdev->dev, res2);
+       if (IS_ERR(base)) {
+               ret = PTR_ERR(base);
                goto err_ioremap;
        }
 
index 0c8bb6bf8424732b068f17f4793c3a957e86031a..2ed2bb33a6e773f6a81835b2787db2ef9b6bf774 100644 (file)
@@ -1520,7 +1520,7 @@ int denali_init(struct denali_nand_info *denali)
         * so just let controller do 15bit ECC for MLC and 8bit ECC for
         * SLC if possible.
         * */
-       if (denali->nand.cellinfo & 0xc &&
+       if (denali->nand.cellinfo & NAND_CI_CELLTYPE_MSK &&
                        (denali->mtd.oobsize > (denali->bbtskipbytes +
                        ECC_15BITS * (denali->mtd.writesize /
                        ECC_SECTOR_SIZE)))) {
index 81fa5784f98b390fb28ee81a23e720db56c2cc8b..eaa3c29ad860eb7c84a5e1309ef879d9d2044ed1 100644 (file)
@@ -46,13 +46,13 @@ static unsigned long __initdata doc_locations[] = {
        0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
        0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000,
        0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000,
-#else /*  CONFIG_MTD_DOCPROBE_HIGH */
+#else
        0xc8000, 0xca000, 0xcc000, 0xce000,
        0xd0000, 0xd2000, 0xd4000, 0xd6000,
        0xd8000, 0xda000, 0xdc000, 0xde000,
        0xe0000, 0xe2000, 0xe4000, 0xe6000,
        0xe8000, 0xea000, 0xec000, 0xee000,
-#endif /*  CONFIG_MTD_DOCPROBE_HIGH */
+#endif
 #endif
        0xffffffff };
 
index fa25e7a08134d1cc6bf3d0a68eb15da42a44524b..548db2389fab8b63e41f2f61731606c32643084a 100644 (file)
@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
        struct nand_chip *nand = mtd->priv;
        struct docg4_priv *doc = nand->priv;
        struct nand_bbt_descr *bbtd = nand->badblock_pattern;
-       int block = (int)(ofs >> nand->bbt_erase_shift);
        int page = (int)(ofs >> nand->page_shift);
        uint32_t g4_addr = mtd_to_docg4_address(page, 0);
 
@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
        if (buf == NULL)
                return -ENOMEM;
 
-       /* update bbt in memory */
-       nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
-
        /* write bit-wise negation of pattern to oob buffer */
        memset(nand->oob_poi, 0xff, mtd->oobsize);
        for (i = 0; i < bbtd->len; i++)
@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
        write_page_prologue(mtd, g4_addr);
        docg4_write_page(mtd, nand, buf, 1);
        ret = pageprog(mtd);
-       if (!ret)
-               mtd->ecc_stats.badblocks++;
 
        kfree(buf);
 
@@ -1368,7 +1362,6 @@ static int __init probe_docg4(struct platform_device *pdev)
                struct nand_chip *nand = mtd->priv;
                struct docg4_priv *doc = nand->priv;
                nand_release(mtd); /* deletes partitions and mtd devices */
-               platform_set_drvdata(pdev, NULL);
                free_bch(doc->bch);
                kfree(mtd);
        }
@@ -1380,7 +1373,6 @@ static int __exit cleanup_docg4(struct platform_device *pdev)
 {
        struct docg4_priv *doc = platform_get_drvdata(pdev);
        nand_release(doc->mtd);
-       platform_set_drvdata(pdev, NULL);
        free_bch(doc->bch);
        kfree(doc->mtd);
        iounmap(doc->virtadr);
index f1f7f12ab50184b3bc233e360a899b998ea8c724..317a771f1587c94f3fd57c45c8e140deeb08b982 100644 (file)
@@ -823,7 +823,7 @@ static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv)
 
        /* set up nand options */
        chip->bbt_options = NAND_BBT_USE_FLASH;
-
+       chip->options = NAND_NO_SUBPAGE_WRITE;
 
        if (ioread32be(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) {
                chip->read_byte = fsl_ifc_read_byte16;
@@ -908,7 +908,6 @@ static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv)
 
        ifc_nand_ctrl->chips[priv->bank] = NULL;
        dev_set_drvdata(priv->dev, NULL);
-       kfree(priv);
 
        return 0;
 }
index 911e2433fe304b107f1ad8b585621d653578e302..3dc1a7564d8725d62085b16cb7c0544e138858b2 100644 (file)
@@ -889,6 +889,24 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
        if (of_get_property(np, "nand-skip-bbtscan", NULL))
                pdata->options = NAND_SKIP_BBTSCAN;
 
+       pdata->nand_timings = devm_kzalloc(&pdev->dev,
+                               sizeof(*pdata->nand_timings), GFP_KERNEL);
+       if (!pdata->nand_timings) {
+               dev_err(&pdev->dev, "no memory for nand_timing\n");
+               return -ENOMEM;
+       }
+       of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
+                                               sizeof(*pdata->nand_timings));
+
+       /* Set default NAND bank to 0 */
+       pdata->bank = 0;
+       if (!of_property_read_u32(np, "bank", &val)) {
+               if (val > 3) {
+                       dev_err(&pdev->dev, "invalid bank %u\n", val);
+                       return -EINVAL;
+               }
+               pdata->bank = val;
+       }
        return 0;
 }
 #else
@@ -940,9 +958,6 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
-       if (!res)
-               return -EINVAL;
-
        host->data_va = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->data_va))
                return PTR_ERR(host->data_va);
@@ -950,25 +965,16 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
        host->data_pa = (dma_addr_t)res->start;
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_addr");
-       if (!res)
-               return -EINVAL;
-
        host->addr_va = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->addr_va))
                return PTR_ERR(host->addr_va);
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_cmd");
-       if (!res)
-               return -EINVAL;
-
        host->cmd_va = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->cmd_va))
                return PTR_ERR(host->cmd_va);
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fsmc_regs");
-       if (!res)
-               return -EINVAL;
-
        host->regs_va = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->regs_va))
                return PTR_ERR(host->regs_va);
@@ -1174,8 +1180,6 @@ static int fsmc_nand_remove(struct platform_device *pdev)
 {
        struct fsmc_nand_data *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (host) {
                nand_release(&host->mtd);
 
@@ -1190,7 +1194,7 @@ static int fsmc_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int fsmc_nand_suspend(struct device *dev)
 {
        struct fsmc_nand_data *host = dev_get_drvdata(dev);
@@ -1210,9 +1214,9 @@ static int fsmc_nand_resume(struct device *dev)
        }
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(fsmc_nand_pm_ops, fsmc_nand_suspend, fsmc_nand_resume);
-#endif
 
 #ifdef CONFIG_OF
 static const struct of_device_id fsmc_nand_id_table[] = {
@@ -1229,9 +1233,7 @@ static struct platform_driver fsmc_nand_driver = {
                .owner = THIS_MODULE,
                .name = "fsmc-nand",
                .of_match_table = of_match_ptr(fsmc_nand_id_table),
-#ifdef CONFIG_PM
                .pm = &fsmc_nand_pm_ops,
-#endif
        },
 };
 
index 89065dd83d64d7ad64a6d83ca318f36ae65ec6cf..e826f898241f92b24704ba7103fc0cdd970a63d1 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/err.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
@@ -86,59 +87,11 @@ static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
        gpio_nand_dosync(gpiomtd);
 }
 
-static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       iowrite8_rep(this->IO_ADDR_W, buf, len);
-}
-
-static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       ioread8_rep(this->IO_ADDR_R, buf, len);
-}
-
-static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf,
-                                int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       if (IS_ALIGNED((unsigned long)buf, 2)) {
-               iowrite16_rep(this->IO_ADDR_W, buf, len>>1);
-       } else {
-               int i;
-               unsigned short *ptr = (unsigned short *)buf;
-
-               for (i = 0; i < len; i += 2, ptr++)
-                       writew(*ptr, this->IO_ADDR_W);
-       }
-}
-
-static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len)
-{
-       struct nand_chip *this = mtd->priv;
-
-       if (IS_ALIGNED((unsigned long)buf, 2)) {
-               ioread16_rep(this->IO_ADDR_R, buf, len>>1);
-       } else {
-               int i;
-               unsigned short *ptr = (unsigned short *)buf;
-
-               for (i = 0; i < len; i += 2, ptr++)
-                       *ptr = readw(this->IO_ADDR_R);
-       }
-}
-
 static int gpio_nand_devready(struct mtd_info *mtd)
 {
        struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd);
 
-       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-               return gpio_get_value(gpiomtd->plat.gpio_rdy);
-
-       return 1;
+       return gpio_get_value(gpiomtd->plat.gpio_rdy);
 }
 
 #ifdef CONFIG_OF
@@ -153,6 +106,9 @@ static int gpio_nand_get_config_of(const struct device *dev,
 {
        u32 val;
 
+       if (!dev->of_node)
+               return -ENODEV;
+
        if (!of_property_read_u32(dev->of_node, "bank-width", &val)) {
                if (val == 2) {
                        plat->options |= NAND_BUSWIDTH_16;
@@ -211,8 +167,8 @@ static inline int gpio_nand_get_config(const struct device *dev,
        if (!ret)
                return ret;
 
-       if (dev->platform_data) {
-               memcpy(plat, dev->platform_data, sizeof(*plat));
+       if (dev_get_platdata(dev)) {
+               memcpy(plat, dev_get_platdata(dev), sizeof(*plat));
                return 0;
        }
 
@@ -230,145 +186,100 @@ gpio_nand_get_io_sync(struct platform_device *pdev)
        return platform_get_resource(pdev, IORESOURCE_MEM, 1);
 }
 
-static int gpio_nand_remove(struct platform_device *dev)
+static int gpio_nand_remove(struct platform_device *pdev)
 {
-       struct gpiomtd *gpiomtd = platform_get_drvdata(dev);
-       struct resource *res;
+       struct gpiomtd *gpiomtd = platform_get_drvdata(pdev);
 
        nand_release(&gpiomtd->mtd_info);
 
-       res = gpio_nand_get_io_sync(dev);
-       iounmap(gpiomtd->io_sync);
-       if (res)
-               release_mem_region(res->start, resource_size(res));
-
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       iounmap(gpiomtd->nand_chip.IO_ADDR_R);
-       release_mem_region(res->start, resource_size(res));
-
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
        gpio_set_value(gpiomtd->plat.gpio_nce, 1);
 
-       gpio_free(gpiomtd->plat.gpio_cle);
-       gpio_free(gpiomtd->plat.gpio_ale);
-       gpio_free(gpiomtd->plat.gpio_nce);
-       if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
-               gpio_free(gpiomtd->plat.gpio_nwp);
-       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-               gpio_free(gpiomtd->plat.gpio_rdy);
-
        return 0;
 }
 
-static void __iomem *request_and_remap(struct resource *res, size_t size,
-                                       const char *name, int *err)
-{
-       void __iomem *ptr;
-
-       if (!request_mem_region(res->start, resource_size(res), name)) {
-               *err = -EBUSY;
-               return NULL;
-       }
-
-       ptr = ioremap(res->start, size);
-       if (!ptr) {
-               release_mem_region(res->start, resource_size(res));
-               *err = -ENOMEM;
-       }
-       return ptr;
-}
-
-static int gpio_nand_probe(struct platform_device *dev)
+static int gpio_nand_probe(struct platform_device *pdev)
 {
        struct gpiomtd *gpiomtd;
-       struct nand_chip *this;
-       struct resource *res0, *res1;
+       struct nand_chip *chip;
+       struct resource *res;
        struct mtd_part_parser_data ppdata = {};
        int ret = 0;
 
-       if (!dev->dev.of_node && !dev->dev.platform_data)
-               return -EINVAL;
-
-       res0 = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res0)
+       if (!pdev->dev.of_node && !dev_get_platdata(&pdev->dev))
                return -EINVAL;
 
-       gpiomtd = devm_kzalloc(&dev->dev, sizeof(*gpiomtd), GFP_KERNEL);
-       if (gpiomtd == NULL) {
-               dev_err(&dev->dev, "failed to create NAND MTD\n");
+       gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
+       if (!gpiomtd) {
+               dev_err(&pdev->dev, "failed to create NAND MTD\n");
                return -ENOMEM;
        }
 
-       this = &gpiomtd->nand_chip;
-       this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret);
-       if (!this->IO_ADDR_R) {
-               dev_err(&dev->dev, "unable to map NAND\n");
-               goto err_map;
-       }
+       chip = &gpiomtd->nand_chip;
 
-       res1 = gpio_nand_get_io_sync(dev);
-       if (res1) {
-               gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret);
-               if (!gpiomtd->io_sync) {
-                       dev_err(&dev->dev, "unable to map sync NAND\n");
-                       goto err_sync;
-               }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(chip->IO_ADDR_R))
+               return PTR_ERR(chip->IO_ADDR_R);
+
+       res = gpio_nand_get_io_sync(pdev);
+       if (res) {
+               gpiomtd->io_sync = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(gpiomtd->io_sync))
+                       return PTR_ERR(gpiomtd->io_sync);
        }
 
-       ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat);
+       ret = gpio_nand_get_config(&pdev->dev, &gpiomtd->plat);
        if (ret)
-               goto err_nce;
+               return ret;
 
-       ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE");
+       ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nce, "NAND NCE");
        if (ret)
-               goto err_nce;
+               return ret;
        gpio_direction_output(gpiomtd->plat.gpio_nce, 1);
+
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) {
-               ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP");
+               ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_nwp,
+                                       "NAND NWP");
                if (ret)
-                       goto err_nwp;
-               gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
+                       return ret;
        }
-       ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE");
+
+       ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_ale, "NAND ALE");
        if (ret)
-               goto err_ale;
+               return ret;
        gpio_direction_output(gpiomtd->plat.gpio_ale, 0);
-       ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE");
+
+       ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_cle, "NAND CLE");
        if (ret)
-               goto err_cle;
+               return ret;
        gpio_direction_output(gpiomtd->plat.gpio_cle, 0);
+
        if (gpio_is_valid(gpiomtd->plat.gpio_rdy)) {
-               ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY");
+               ret = devm_gpio_request(&pdev->dev, gpiomtd->plat.gpio_rdy,
+                                       "NAND RDY");
                if (ret)
-                       goto err_rdy;
+                       return ret;
                gpio_direction_input(gpiomtd->plat.gpio_rdy);
+               chip->dev_ready = gpio_nand_devready;
        }
 
+       chip->IO_ADDR_W         = chip->IO_ADDR_R;
+       chip->ecc.mode          = NAND_ECC_SOFT;
+       chip->options           = gpiomtd->plat.options;
+       chip->chip_delay        = gpiomtd->plat.chip_delay;
+       chip->cmd_ctrl          = gpio_nand_cmd_ctrl;
 
-       this->IO_ADDR_W  = this->IO_ADDR_R;
-       this->ecc.mode   = NAND_ECC_SOFT;
-       this->options    = gpiomtd->plat.options;
-       this->chip_delay = gpiomtd->plat.chip_delay;
-
-       /* install our routines */
-       this->cmd_ctrl   = gpio_nand_cmd_ctrl;
-       this->dev_ready  = gpio_nand_devready;
+       gpiomtd->mtd_info.priv  = chip;
+       gpiomtd->mtd_info.owner = THIS_MODULE;
 
-       if (this->options & NAND_BUSWIDTH_16) {
-               this->read_buf   = gpio_nand_readbuf16;
-               this->write_buf  = gpio_nand_writebuf16;
-       } else {
-               this->read_buf   = gpio_nand_readbuf;
-               this->write_buf  = gpio_nand_writebuf;
-       }
+       platform_set_drvdata(pdev, gpiomtd);
 
-       /* set the mtd private data for the nand driver */
-       gpiomtd->mtd_info.priv = this;
-       gpiomtd->mtd_info.owner = THIS_MODULE;
+       if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
+               gpio_direction_output(gpiomtd->plat.gpio_nwp, 1);
 
        if (nand_scan(&gpiomtd->mtd_info, 1)) {
-               dev_err(&dev->dev, "no nand chips found?\n");
                ret = -ENXIO;
                goto err_wp;
        }
@@ -377,38 +288,17 @@ static int gpio_nand_probe(struct platform_device *dev)
                gpiomtd->plat.adjust_parts(&gpiomtd->plat,
                                           gpiomtd->mtd_info.size);
 
-       ppdata.of_node = dev->dev.of_node;
+       ppdata.of_node = pdev->dev.of_node;
        ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata,
                                        gpiomtd->plat.parts,
                                        gpiomtd->plat.num_parts);
-       if (ret)
-               goto err_wp;
-       platform_set_drvdata(dev, gpiomtd);
-
-       return 0;
+       if (!ret)
+               return 0;
 
 err_wp:
        if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
                gpio_set_value(gpiomtd->plat.gpio_nwp, 0);
-       if (gpio_is_valid(gpiomtd->plat.gpio_rdy))
-               gpio_free(gpiomtd->plat.gpio_rdy);
-err_rdy:
-       gpio_free(gpiomtd->plat.gpio_cle);
-err_cle:
-       gpio_free(gpiomtd->plat.gpio_ale);
-err_ale:
-       if (gpio_is_valid(gpiomtd->plat.gpio_nwp))
-               gpio_free(gpiomtd->plat.gpio_nwp);
-err_nwp:
-       gpio_free(gpiomtd->plat.gpio_nce);
-err_nce:
-       iounmap(gpiomtd->io_sync);
-       if (res1)
-               release_mem_region(res1->start, resource_size(res1));
-err_sync:
-       iounmap(gpiomtd->nand_chip.IO_ADDR_R);
-       release_mem_region(res0->start, resource_size(res0));
-err_map:
+
        return ret;
 }
 
@@ -417,6 +307,7 @@ static struct platform_driver gpio_nand_driver = {
        .remove         = gpio_nand_remove,
        .driver         = {
                .name   = "gpio-nand",
+               .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(gpio_nand_id_table),
        },
 };
index 25ecfa1822a8fc75cf485b41c51602ad04a0489b..59ab0692f0b97f58fef750b6f5e29c11b6fa0367 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/mtd/partitions.h>
-#include <linux/pinctrl/consumer.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
 #include <linux/of_mtd.h>
@@ -112,7 +111,131 @@ static inline bool gpmi_check_ecc(struct gpmi_nand_data *this)
        return true;
 }
 
-int common_nfc_set_geometry(struct gpmi_nand_data *this)
+/*
+ * If we can get the ECC information from the nand chip, we do not
+ * need to calculate them ourselves.
+ *
+ * We may have available oob space in this case.
+ */
+static bool set_geometry_by_ecc_info(struct gpmi_nand_data *this)
+{
+       struct bch_geometry *geo = &this->bch_geometry;
+       struct mtd_info *mtd = &this->mtd;
+       struct nand_chip *chip = mtd->priv;
+       struct nand_oobfree *of = gpmi_hw_ecclayout.oobfree;
+       unsigned int block_mark_bit_offset;
+
+       if (!(chip->ecc_strength_ds > 0 && chip->ecc_step_ds > 0))
+               return false;
+
+       switch (chip->ecc_step_ds) {
+       case SZ_512:
+               geo->gf_len = 13;
+               break;
+       case SZ_1K:
+               geo->gf_len = 14;
+               break;
+       default:
+               dev_err(this->dev,
+                       "unsupported nand chip. ecc bits : %d, ecc size : %d\n",
+                       chip->ecc_strength_ds, chip->ecc_step_ds);
+               return false;
+       }
+       geo->ecc_chunk_size = chip->ecc_step_ds;
+       geo->ecc_strength = round_up(chip->ecc_strength_ds, 2);
+       if (!gpmi_check_ecc(this))
+               return false;
+
+       /* Keep the C >= O */
+       if (geo->ecc_chunk_size < mtd->oobsize) {
+               dev_err(this->dev,
+                       "unsupported nand chip. ecc size: %d, oob size : %d\n",
+                       chip->ecc_step_ds, mtd->oobsize);
+               return false;
+       }
+
+       /* The default value, see comment in the legacy_set_geometry(). */
+       geo->metadata_size = 10;
+
+       geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size;
+
+       /*
+        * Now, the NAND chip with 2K page(data chunk is 512byte) shows below:
+        *
+        *    |                          P                            |
+        *    |<----------------------------------------------------->|
+        *    |                                                       |
+        *    |                                        (Block Mark)   |
+        *    |                      P'                      |      | |     |
+        *    |<-------------------------------------------->|  D   | |  O' |
+        *    |                                              |<---->| |<--->|
+        *    V                                              V      V V     V
+        *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+        *    | M |   data   |E|   data   |E|   data   |E|   data   |E|     |
+        *    +---+----------+-+----------+-+----------+-+----------+-+-----+
+        *                                                   ^              ^
+        *                                                   |      O       |
+        *                                                   |<------------>|
+        *                                                   |              |
+        *
+        *      P : the page size for BCH module.
+        *      E : The ECC strength.
+        *      G : the length of Galois Field.
+        *      N : The chunk count of per page.
+        *      M : the metasize of per page.
+        *      C : the ecc chunk size, aka the "data" above.
+        *      P': the nand chip's page size.
+        *      O : the nand chip's oob size.
+        *      O': the free oob.
+        *
+        *      The formula for P is :
+        *
+        *                  E * G * N
+        *             P = ------------ + P' + M
+        *                      8
+        *
+        * The position of block mark moves forward in the ECC-based view
+        * of page, and the delta is:
+        *
+        *                   E * G * (N - 1)
+        *             D = (---------------- + M)
+        *                          8
+        *
+        * Please see the comment in legacy_set_geometry().
+        * With the condition C >= O , we still can get same result.
+        * So the bit position of the physical block mark within the ECC-based
+        * view of the page is :
+        *             (P' - D) * 8
+        */
+       geo->page_size = mtd->writesize + geo->metadata_size +
+               (geo->gf_len * geo->ecc_strength * geo->ecc_chunk_count) / 8;
+
+       /* The available oob size we have. */
+       if (geo->page_size < mtd->writesize + mtd->oobsize) {
+               of->offset = geo->page_size - mtd->writesize;
+               of->length = mtd->oobsize - of->offset;
+       }
+
+       geo->payload_size = mtd->writesize;
+
+       geo->auxiliary_status_offset = ALIGN(geo->metadata_size, 4);
+       geo->auxiliary_size = ALIGN(geo->metadata_size, 4)
+                               + ALIGN(geo->ecc_chunk_count, 4);
+
+       if (!this->swap_block_mark)
+               return true;
+
+       /* For bit swap. */
+       block_mark_bit_offset = mtd->writesize * 8 -
+               (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1)
+                               + geo->metadata_size * 8);
+
+       geo->block_mark_byte_offset = block_mark_bit_offset / 8;
+       geo->block_mark_bit_offset  = block_mark_bit_offset % 8;
+       return true;
+}
+
+static int legacy_set_geometry(struct gpmi_nand_data *this)
 {
        struct bch_geometry *geo = &this->bch_geometry;
        struct mtd_info *mtd = &this->mtd;
@@ -224,6 +347,11 @@ int common_nfc_set_geometry(struct gpmi_nand_data *this)
        return 0;
 }
 
+int common_nfc_set_geometry(struct gpmi_nand_data *this)
+{
+       return set_geometry_by_ecc_info(this) ? 0 : legacy_set_geometry(this);
+}
+
 struct dma_chan *get_dma_chan(struct gpmi_nand_data *this)
 {
        int chipnr = this->current_chip;
@@ -355,7 +483,7 @@ static int acquire_register_block(struct gpmi_nand_data *this,
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
        if (!r) {
                pr_err("Can't get resource for %s\n", res_name);
-               return -ENXIO;
+               return -ENODEV;
        }
 
        p = ioremap(r->start, resource_size(r));
@@ -396,7 +524,7 @@ static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
        r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
        if (!r) {
                pr_err("Can't get resource for %s\n", res_name);
-               return -ENXIO;
+               return -ENODEV;
        }
 
        err = request_irq(r->start, irq_h, 0, res_name, this);
@@ -473,12 +601,14 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
        struct resources *r = &this->resources;
        char **extra_clks = NULL;
        struct clk *clk;
-       int i;
+       int err, i;
 
        /* The main clock is stored in the first. */
        r->clock[0] = clk_get(this->dev, "gpmi_io");
-       if (IS_ERR(r->clock[0]))
+       if (IS_ERR(r->clock[0])) {
+               err = PTR_ERR(r->clock[0]);
                goto err_clock;
+       }
 
        /* Get extra clocks */
        if (GPMI_IS_MX6Q(this))
@@ -491,8 +621,10 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
                        break;
 
                clk = clk_get(this->dev, extra_clks[i - 1]);
-               if (IS_ERR(clk))
+               if (IS_ERR(clk)) {
+                       err = PTR_ERR(clk);
                        goto err_clock;
+               }
 
                r->clock[i] = clk;
        }
@@ -511,12 +643,11 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
 err_clock:
        dev_dbg(this->dev, "failed in finding the clocks.\n");
        gpmi_put_clks(this);
-       return -ENOMEM;
+       return err;
 }
 
 static int acquire_resources(struct gpmi_nand_data *this)
 {
-       struct pinctrl *pinctrl;
        int ret;
 
        ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME);
@@ -535,19 +666,12 @@ static int acquire_resources(struct gpmi_nand_data *this)
        if (ret)
                goto exit_dma_channels;
 
-       pinctrl = devm_pinctrl_get_select_default(&this->pdev->dev);
-       if (IS_ERR(pinctrl)) {
-               ret = PTR_ERR(pinctrl);
-               goto exit_pin;
-       }
-
        ret = gpmi_get_clks(this);
        if (ret)
                goto exit_clock;
        return 0;
 
 exit_clock:
-exit_pin:
        release_dma_channels(this);
 exit_dma_channels:
        release_bch_irq(this);
@@ -1153,43 +1277,31 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
        struct nand_chip *chip = mtd->priv;
        struct gpmi_nand_data *this = chip->priv;
-       int block, ret = 0;
+       int ret = 0;
        uint8_t *block_mark;
        int column, page, status, chipnr;
 
-       /* Get block number */
-       block = (int)(ofs >> chip->bbt_erase_shift);
-       if (chip->bbt)
-               chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+       chipnr = (int)(ofs >> chip->chip_shift);
+       chip->select_chip(mtd, chipnr);
 
-       /* Do we have a flash based bad block table ? */
-       if (chip->bbt_options & NAND_BBT_USE_FLASH)
-               ret = nand_update_bbt(mtd, ofs);
-       else {
-               chipnr = (int)(ofs >> chip->chip_shift);
-               chip->select_chip(mtd, chipnr);
+       column = this->swap_block_mark ? mtd->writesize : 0;
 
-               column = this->swap_block_mark ? mtd->writesize : 0;
+       /* Write the block mark. */
+       block_mark = this->data_buffer_dma;
+       block_mark[0] = 0; /* bad block marker */
 
-               /* Write the block mark. */
-               block_mark = this->data_buffer_dma;
-               block_mark[0] = 0; /* bad block marker */
+       /* Shift to get page */
+       page = (int)(ofs >> chip->page_shift);
 
-               /* Shift to get page */
-               page = (int)(ofs >> chip->page_shift);
+       chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
+       chip->write_buf(mtd, block_mark, 1);
+       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 
-               chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
-               chip->write_buf(mtd, block_mark, 1);
-               chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+       status = chip->waitfunc(mtd, chip);
+       if (status & NAND_STATUS_FAIL)
+               ret = -EIO;
 
-               status = chip->waitfunc(mtd, chip);
-               if (status & NAND_STATUS_FAIL)
-                       ret = -EIO;
-
-               chip->select_chip(mtd, -1);
-       }
-       if (!ret)
-               mtd->ecc_stats.badblocks++;
+       chip->select_chip(mtd, -1);
 
        return ret;
 }
@@ -1469,19 +1581,22 @@ static int gpmi_pre_bbt_scan(struct gpmi_nand_data  *this)
        if (ret)
                return ret;
 
-       /* Adjust the ECC strength according to the chip. */
-       this->nand.ecc.strength = this->bch_geometry.ecc_strength;
-       this->mtd.ecc_strength = this->bch_geometry.ecc_strength;
-       this->mtd.bitflip_threshold = this->bch_geometry.ecc_strength;
-
        /* NAND boot init, depends on the gpmi_set_geometry(). */
        return nand_boot_init(this);
 }
 
-static int gpmi_scan_bbt(struct mtd_info *mtd)
+static void gpmi_nfc_exit(struct gpmi_nand_data *this)
 {
+       nand_release(&this->mtd);
+       gpmi_free_dma_buffer(this);
+}
+
+static int gpmi_init_last(struct gpmi_nand_data *this)
+{
+       struct mtd_info *mtd = &this->mtd;
        struct nand_chip *chip = mtd->priv;
-       struct gpmi_nand_data *this = chip->priv;
+       struct nand_ecc_ctrl *ecc = &chip->ecc;
+       struct bch_geometry *bch_geo = &this->bch_geometry;
        int ret;
 
        /* Prepare for the BBT scan. */
@@ -1489,6 +1604,16 @@ static int gpmi_scan_bbt(struct mtd_info *mtd)
        if (ret)
                return ret;
 
+       /* Init the nand_ecc_ctrl{} */
+       ecc->read_page  = gpmi_ecc_read_page;
+       ecc->write_page = gpmi_ecc_write_page;
+       ecc->read_oob   = gpmi_ecc_read_oob;
+       ecc->write_oob  = gpmi_ecc_write_oob;
+       ecc->mode       = NAND_ECC_HW;
+       ecc->size       = bch_geo->ecc_chunk_size;
+       ecc->strength   = bch_geo->ecc_strength;
+       ecc->layout     = &gpmi_hw_ecclayout;
+
        /*
         * Can we enable the extra features? such as EDO or Sync mode.
         *
@@ -1497,14 +1622,7 @@ static int gpmi_scan_bbt(struct mtd_info *mtd)
         */
        gpmi_extra_init(this);
 
-       /* use the default BBT implementation */
-       return nand_default_bbt(mtd);
-}
-
-static void gpmi_nfc_exit(struct gpmi_nand_data *this)
-{
-       nand_release(&this->mtd);
-       gpmi_free_dma_buffer(this);
+       return 0;
 }
 
 static int gpmi_nfc_init(struct gpmi_nand_data *this)
@@ -1530,33 +1648,33 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
        chip->read_byte         = gpmi_read_byte;
        chip->read_buf          = gpmi_read_buf;
        chip->write_buf         = gpmi_write_buf;
-       chip->ecc.read_page     = gpmi_ecc_read_page;
-       chip->ecc.write_page    = gpmi_ecc_write_page;
-       chip->ecc.read_oob      = gpmi_ecc_read_oob;
-       chip->ecc.write_oob     = gpmi_ecc_write_oob;
-       chip->scan_bbt          = gpmi_scan_bbt;
        chip->badblock_pattern  = &gpmi_bbt_descr;
        chip->block_markbad     = gpmi_block_markbad;
        chip->options           |= NAND_NO_SUBPAGE_WRITE;
-       chip->ecc.mode          = NAND_ECC_HW;
-       chip->ecc.size          = 1;
-       chip->ecc.strength      = 8;
-       chip->ecc.layout        = &gpmi_hw_ecclayout;
        if (of_get_nand_on_flash_bbt(this->dev->of_node))
                chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
 
-       /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */
+       /*
+        * Allocate a temporary DMA buffer for reading ID in the
+        * nand_scan_ident().
+        */
        this->bch_geometry.payload_size = 1024;
        this->bch_geometry.auxiliary_size = 128;
        ret = gpmi_alloc_dma_buffer(this);
        if (ret)
                goto err_out;
 
-       ret = nand_scan(mtd, 1);
-       if (ret) {
-               pr_err("Chip scan failed\n");
+       ret = nand_scan_ident(mtd, 1, NULL);
+       if (ret)
+               goto err_out;
+
+       ret = gpmi_init_last(this);
+       if (ret)
+               goto err_out;
+
+       ret = nand_scan_tail(mtd);
+       if (ret)
                goto err_out;
-       }
 
        ppdata.of_node = this->pdev->dev.of_node;
        ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
@@ -1601,7 +1719,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
                pdev->id_entry = of_id->data;
        } else {
                pr_err("Failed to find the right device id.\n");
-               return -ENOMEM;
+               return -ENODEV;
        }
 
        this = kzalloc(sizeof(*this), GFP_KERNEL);
@@ -1633,7 +1751,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
 exit_nfc_init:
        release_resources(this);
 exit_acquire_resources:
-       platform_set_drvdata(pdev, NULL);
        dev_err(this->dev, "driver registration failed: %d\n", ret);
        kfree(this);
 
@@ -1646,7 +1763,6 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 
        gpmi_nfc_exit(this);
        release_resources(this);
-       platform_set_drvdata(pdev, NULL);
        kfree(this);
        return 0;
 }
index b76460eeaf2253f7db3e69404ff4afb51298f84b..a264b888c66cc9153e0f160af0c50e4675826a93 100644 (file)
@@ -411,7 +411,7 @@ static int jz_nand_probe(struct platform_device *pdev)
        struct jz_nand *nand;
        struct nand_chip *chip;
        struct mtd_info *mtd;
-       struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+       struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        size_t chipnr, bank_idx;
        uint8_t nand_maf_id = 0, nand_dev_id = 0;
 
@@ -538,7 +538,6 @@ err_unclaim_banks:
 err_gpio_busy:
        if (pdata && gpio_is_valid(pdata->busy_gpio))
                gpio_free(pdata->busy_gpio);
-       platform_set_drvdata(pdev, NULL);
 err_iounmap_mmio:
        jz_nand_iounmap_resource(nand->mem, nand->base);
 err_free:
@@ -549,7 +548,7 @@ err_free:
 static int jz_nand_remove(struct platform_device *pdev)
 {
        struct jz_nand *nand = platform_get_drvdata(pdev);
-       struct jz_nand_platform_data *pdata = pdev->dev.platform_data;
+       struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        size_t i;
 
        nand_release(&nand->mtd);
@@ -570,7 +569,6 @@ static int jz_nand_remove(struct platform_device *pdev)
 
        jz_nand_iounmap_resource(nand->mem, nand->base);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(nand);
 
        return 0;
index fd1df5e13ae44d77207d19fb492064166bf46525..f4dd2a887ea5da15b0b64c743f9ecb2603035b97 100644 (file)
@@ -696,7 +696,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
        lpc32xx_wp_disable(host);
 
-       host->pdata = pdev->dev.platform_data;
+       host->pdata = dev_get_platdata(&pdev->dev);
 
        nand_chip->priv = host;         /* link the private data structures */
        mtd->priv = nand_chip;
@@ -828,7 +828,6 @@ err_exit3:
 err_exit2:
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
 err_exit1:
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
@@ -851,7 +850,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
 
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
index be94ed5abefb74aebde118529cf5eca82abe876e..add75709d41550d893f9dc0ef144a8b2edc281f7 100644 (file)
@@ -798,7 +798,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
        lpc32xx_wp_disable(host);
 
-       host->pdata = pdev->dev.platform_data;
+       host->pdata = dev_get_platdata(&pdev->dev);
 
        mtd = &host->mtd;
        chip = &host->nand_chip;
@@ -936,7 +936,6 @@ err_exit3:
 err_exit2:
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
 err_exit1:
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
@@ -963,7 +962,6 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
 
        clk_disable(host->clk);
        clk_put(host->clk);
-       platform_set_drvdata(pdev, NULL);
        lpc32xx_wp_enable(host);
        gpio_free(host->ncfg->wp_gpio);
 
index 07e5784e5cd3f365e459a651368afdd6b2ab6f1b..ce8242b6c3e7fd9147cd4a481d024eec32bf1853 100644 (file)
@@ -266,7 +266,7 @@ static struct nand_ecclayout nandv2_hw_eccoob_4k = {
        }
 };
 
-static const char const *part_probes[] = {
+static const char * const part_probes[] = {
        "cmdlinepart", "RedBoot", "ofpart", NULL };
 
 static void memcpy32_fromio(void *trg, const void __iomem  *src, size_t size)
@@ -1432,7 +1432,8 @@ static int mxcnd_probe(struct platform_device *pdev)
 
        err = mxcnd_probe_dt(host);
        if (err > 0) {
-               struct mxc_nand_platform_data *pdata = pdev->dev.platform_data;
+               struct mxc_nand_platform_data *pdata =
+                                       dev_get_platdata(&pdev->dev);
                if (pdata) {
                        host->pdata = *pdata;
                        host->devtype_data = (struct mxc_nand_devtype_data *)
@@ -1446,8 +1447,6 @@ static int mxcnd_probe(struct platform_device *pdev)
 
        if (host->devtype_data->needs_ip) {
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-               if (!res)
-                       return -ENODEV;
                host->regs_ip = devm_ioremap_resource(&pdev->dev, res);
                if (IS_ERR(host->regs_ip))
                        return PTR_ERR(host->regs_ip);
@@ -1457,9 +1456,6 @@ static int mxcnd_probe(struct platform_device *pdev)
                res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        }
 
-       if (!res)
-               return -ENODEV;
-
        host->base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->base))
                return PTR_ERR(host->base);
@@ -1578,8 +1574,6 @@ static int mxcnd_remove(struct platform_device *pdev)
 {
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        nand_release(&host->mtd);
 
        return 0;
index dfcd0a565c5b3e8f66d9b24077ae3701f132ee36..7ed4841327f2d7668e51c75645628f2127589f82 100644 (file)
@@ -108,13 +108,13 @@ static int check_offs_len(struct mtd_info *mtd,
        int ret = 0;
 
        /* Start address must align on block boundary */
-       if (ofs & ((1 << chip->phys_erase_shift) - 1)) {
+       if (ofs & ((1ULL << chip->phys_erase_shift) - 1)) {
                pr_debug("%s: unaligned address\n", __func__);
                ret = -EINVAL;
        }
 
        /* Length must align on block boundary */
-       if (len & ((1 << chip->phys_erase_shift) - 1)) {
+       if (len & ((1ULL << chip->phys_erase_shift) - 1)) {
                pr_debug("%s: length not block aligned\n", __func__);
                ret = -EINVAL;
        }
@@ -211,11 +211,9 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
  */
 static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
 
-       for (i = 0; i < len; i++)
-               writeb(buf[i], chip->IO_ADDR_W);
+       iowrite8_rep(chip->IO_ADDR_W, buf, len);
 }
 
 /**
@@ -228,11 +226,9 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
 
-       for (i = 0; i < len; i++)
-               buf[i] = readb(chip->IO_ADDR_R);
+       ioread8_rep(chip->IO_ADDR_R, buf, len);
 }
 
 /**
@@ -245,14 +241,10 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
  */
 static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
        u16 *p = (u16 *) buf;
-       len >>= 1;
-
-       for (i = 0; i < len; i++)
-               writew(p[i], chip->IO_ADDR_W);
 
+       iowrite16_rep(chip->IO_ADDR_W, p, len >> 1);
 }
 
 /**
@@ -265,13 +257,10 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
  */
 static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len)
 {
-       int i;
        struct nand_chip *chip = mtd->priv;
        u16 *p = (u16 *) buf;
-       len >>= 1;
 
-       for (i = 0; i < len; i++)
-               p[i] = readw(chip->IO_ADDR_R);
+       ioread16_rep(chip->IO_ADDR_R, p, len >> 1);
 }
 
 /**
@@ -335,80 +324,88 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 }
 
 /**
- * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
  * @mtd: MTD device structure
  * @ofs: offset from device start
  *
  * This is the default implementation, which can be overridden by a hardware
- * specific driver. We try operations in the following order, according to our
- * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
+ * specific driver. It provides the details for writing a bad block marker to a
+ * block.
+ */
+static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+       struct nand_chip *chip = mtd->priv;
+       struct mtd_oob_ops ops;
+       uint8_t buf[2] = { 0, 0 };
+       int ret = 0, res, i = 0;
+
+       ops.datbuf = NULL;
+       ops.oobbuf = buf;
+       ops.ooboffs = chip->badblockpos;
+       if (chip->options & NAND_BUSWIDTH_16) {
+               ops.ooboffs &= ~0x01;
+               ops.len = ops.ooblen = 2;
+       } else {
+               ops.len = ops.ooblen = 1;
+       }
+       ops.mode = MTD_OPS_PLACE_OOB;
+
+       /* Write to first/last page(s) if necessary */
+       if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
+               ofs += mtd->erasesize - mtd->writesize;
+       do {
+               res = nand_do_write_oob(mtd, ofs, &ops);
+               if (!ret)
+                       ret = res;
+
+               i++;
+               ofs += mtd->writesize;
+       } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
+
+       return ret;
+}
+
+/**
+ * nand_block_markbad_lowlevel - mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This function performs the generic NAND bad block marking steps (i.e., bad
+ * block table(s) and/or marker(s)). We only allow the hardware driver to
+ * specify how to write bad block markers to OOB (chip->block_markbad).
+ *
+ * We try operations in the following order:
  *  (1) erase the affected block, to allow OOB marker to be written cleanly
- *  (2) update in-memory BBT
- *  (3) write bad block marker to OOB area of affected block
- *  (4) update flash-based BBT
- * Note that we retain the first error encountered in (3) or (4), finish the
+ *  (2) write bad block marker to OOB area of affected block (unless flag
+ *      NAND_BBT_NO_OOB_BBM is present)
+ *  (3) update the BBT
+ * Note that we retain the first error encountered in (2) or (3), finish the
  * procedures, and dump the error in the end.
 */
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
 {
        struct nand_chip *chip = mtd->priv;
-       uint8_t buf[2] = { 0, 0 };
-       int block, res, ret = 0, i = 0;
-       int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
+       int res, ret = 0;
 
-       if (write_oob) {
+       if (!(chip->bbt_options & NAND_BBT_NO_OOB_BBM)) {
                struct erase_info einfo;
 
                /* Attempt erase before marking OOB */
                memset(&einfo, 0, sizeof(einfo));
                einfo.mtd = mtd;
                einfo.addr = ofs;
-               einfo.len = 1 << chip->phys_erase_shift;
+               einfo.len = 1ULL << chip->phys_erase_shift;
                nand_erase_nand(mtd, &einfo, 0);
-       }
-
-       /* Get block number */
-       block = (int)(ofs >> chip->bbt_erase_shift);
-       /* Mark block bad in memory-based BBT */
-       if (chip->bbt)
-               chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
-
-       /* Write bad block marker to OOB */
-       if (write_oob) {
-               struct mtd_oob_ops ops;
-               loff_t wr_ofs = ofs;
 
+               /* Write bad block marker to OOB */
                nand_get_device(mtd, FL_WRITING);
-
-               ops.datbuf = NULL;
-               ops.oobbuf = buf;
-               ops.ooboffs = chip->badblockpos;
-               if (chip->options & NAND_BUSWIDTH_16) {
-                       ops.ooboffs &= ~0x01;
-                       ops.len = ops.ooblen = 2;
-               } else {
-                       ops.len = ops.ooblen = 1;
-               }
-               ops.mode = MTD_OPS_PLACE_OOB;
-
-               /* Write to first/last page(s) if necessary */
-               if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
-                       wr_ofs += mtd->erasesize - mtd->writesize;
-               do {
-                       res = nand_do_write_oob(mtd, wr_ofs, &ops);
-                       if (!ret)
-                               ret = res;
-
-                       i++;
-                       wr_ofs += mtd->writesize;
-               } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
-
+               ret = chip->block_markbad(mtd, ofs);
                nand_release_device(mtd);
        }
 
-       /* Update flash-based bad block table */
-       if (chip->bbt_options & NAND_BBT_USE_FLASH) {
-               res = nand_update_bbt(mtd, ofs);
+       /* Mark block bad in BBT */
+       if (chip->bbt) {
+               res = nand_markbad_bbt(mtd, ofs);
                if (!ret)
                        ret = res;
        }
@@ -1983,13 +1980,14 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
  * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
  * @mtd:       mtd info structure
  * @chip:      nand chip info structure
- * @column:    column address of subpage within the page
+ * @offset:    column address of subpage within the page
  * @data_len:  data length
+ * @buf:       data buffer
  * @oob_required: must write chip->oob_poi to OOB
  */
 static int nand_write_subpage_hwecc(struct mtd_info *mtd,
                                struct nand_chip *chip, uint32_t offset,
-                               uint32_t data_len, const uint8_t *data_buf,
+                               uint32_t data_len, const uint8_t *buf,
                                int oob_required)
 {
        uint8_t *oob_buf  = chip->oob_poi;
@@ -2008,20 +2006,20 @@ static int nand_write_subpage_hwecc(struct mtd_info *mtd,
                chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
 
                /* write data (untouched subpages already masked by 0xFF) */
-               chip->write_buf(mtd, data_buf, ecc_size);
+               chip->write_buf(mtd, buf, ecc_size);
 
                /* mask ECC of un-touched subpages by padding 0xFF */
                if ((step < start_step) || (step > end_step))
                        memset(ecc_calc, 0xff, ecc_bytes);
                else
-                       chip->ecc.calculate(mtd, data_buf, ecc_calc);
+                       chip->ecc.calculate(mtd, buf, ecc_calc);
 
                /* mask OOB of un-touched subpages by padding 0xFF */
                /* if oob_required, preserve OOB metadata of written subpage */
                if (!oob_required || (step < start_step) || (step > end_step))
                        memset(oob_buf, 0xff, oob_bytes);
 
-               data_buf += ecc_size;
+               buf += ecc_size;
                ecc_calc += ecc_bytes;
                oob_buf  += oob_bytes;
        }
@@ -2633,7 +2631,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                }
 
                /* Increment page address and decrement length */
-               len -= (1 << chip->phys_erase_shift);
+               len -= (1ULL << chip->phys_erase_shift);
                page += pages_per_block;
 
                /* Check, if we cross a chip boundary */
@@ -2694,7 +2692,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
  */
 static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
-       struct nand_chip *chip = mtd->priv;
        int ret;
 
        ret = nand_block_isbad(mtd, ofs);
@@ -2705,7 +2702,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
                return ret;
        }
 
-       return chip->block_markbad(mtd, ofs);
+       return nand_block_markbad_lowlevel(mtd, ofs);
 }
 
 /**
@@ -2720,7 +2717,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 {
        int status;
 
-       if (!chip->onfi_version)
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
        chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
@@ -2741,7 +2740,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
                        int addr, uint8_t *subfeature_param)
 {
-       if (!chip->onfi_version)
+       if (!chip->onfi_version ||
+           !(le16_to_cpu(chip->onfi_params.opt_cmd)
+             & ONFI_OPT_CMD_SET_GET_FEATURES))
                return -EINVAL;
 
        /* clear the sub feature parameters */
@@ -2793,7 +2794,15 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
 
        if (!chip->select_chip)
                chip->select_chip = nand_select_chip;
-       if (!chip->read_byte)
+
+       /* set for ONFI nand */
+       if (!chip->onfi_set_features)
+               chip->onfi_set_features = nand_onfi_set_features;
+       if (!chip->onfi_get_features)
+               chip->onfi_get_features = nand_onfi_get_features;
+
+       /* If called twice, pointers that depend on busw may need to be reset */
+       if (!chip->read_byte || chip->read_byte == nand_read_byte)
                chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
        if (!chip->read_word)
                chip->read_word = nand_read_word;
@@ -2801,9 +2810,9 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
                chip->block_bad = nand_block_bad;
        if (!chip->block_markbad)
                chip->block_markbad = nand_default_block_markbad;
-       if (!chip->write_buf)
+       if (!chip->write_buf || chip->write_buf == nand_write_buf)
                chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
-       if (!chip->read_buf)
+       if (!chip->read_buf || chip->read_buf == nand_read_buf)
                chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
        if (!chip->scan_bbt)
                chip->scan_bbt = nand_default_bbt;
@@ -2846,6 +2855,78 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
        return crc;
 }
 
+/* Parse the Extended Parameter Page. */
+static int nand_flash_detect_ext_param_page(struct mtd_info *mtd,
+               struct nand_chip *chip, struct nand_onfi_params *p)
+{
+       struct onfi_ext_param_page *ep;
+       struct onfi_ext_section *s;
+       struct onfi_ext_ecc_info *ecc;
+       uint8_t *cursor;
+       int ret = -EINVAL;
+       int len;
+       int i;
+
+       len = le16_to_cpu(p->ext_param_page_length) * 16;
+       ep = kmalloc(len, GFP_KERNEL);
+       if (!ep) {
+               ret = -ENOMEM;
+               goto ext_out;
+       }
+
+       /* Send our own NAND_CMD_PARAM. */
+       chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
+
+       /* Use the Change Read Column command to skip the ONFI param pages. */
+       chip->cmdfunc(mtd, NAND_CMD_RNDOUT,
+                       sizeof(*p) * p->num_of_param_pages , -1);
+
+       /* Read out the Extended Parameter Page. */
+       chip->read_buf(mtd, (uint8_t *)ep, len);
+       if ((onfi_crc16(ONFI_CRC_BASE, ((uint8_t *)ep) + 2, len - 2)
+               != le16_to_cpu(ep->crc))) {
+               pr_debug("fail in the CRC.\n");
+               goto ext_out;
+       }
+
+       /*
+        * Check the signature.
+        * Do not strictly follow the ONFI spec, maybe changed in future.
+        */
+       if (strncmp(ep->sig, "EPPS", 4)) {
+               pr_debug("The signature is invalid.\n");
+               goto ext_out;
+       }
+
+       /* find the ECC section. */
+       cursor = (uint8_t *)(ep + 1);
+       for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) {
+               s = ep->sections + i;
+               if (s->type == ONFI_SECTION_TYPE_2)
+                       break;
+               cursor += s->length * 16;
+       }
+       if (i == ONFI_EXT_SECTION_MAX) {
+               pr_debug("We can not find the ECC section.\n");
+               goto ext_out;
+       }
+
+       /* get the info we want. */
+       ecc = (struct onfi_ext_ecc_info *)cursor;
+
+       if (ecc->codeword_size) {
+               chip->ecc_strength_ds = ecc->ecc_bits;
+               chip->ecc_step_ds = 1 << ecc->codeword_size;
+       }
+
+       pr_info("ONFI extended param page detected.\n");
+       return 0;
+
+ext_out:
+       kfree(ep);
+       return ret;
+}
+
 /*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
@@ -2907,9 +2988,31 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
        chip->chipsize = le32_to_cpu(p->blocks_per_lun);
        chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
-       *busw = 0;
-       if (le16_to_cpu(p->features) & 1)
+
+       if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS)
                *busw = NAND_BUSWIDTH_16;
+       else
+               *busw = 0;
+
+       if (p->ecc_bits != 0xff) {
+               chip->ecc_strength_ds = p->ecc_bits;
+               chip->ecc_step_ds = 512;
+       } else if (chip->onfi_version >= 21 &&
+               (onfi_feature(chip) & ONFI_FEATURE_EXT_PARAM_PAGE)) {
+
+               /*
+                * The nand_flash_detect_ext_param_page() uses the
+                * Change Read Column command which maybe not supported
+                * by the chip->cmdfunc. So try to update the chip->cmdfunc
+                * now. We do not replace user supplied command function.
+                */
+               if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
+                       chip->cmdfunc = nand_command_lp;
+
+               /* The Extended Parameter Page is supported since ONFI 2.1. */
+               if (nand_flash_detect_ext_param_page(mtd, chip, p))
+                       pr_info("Failed to detect the extended param page.\n");
+       }
 
        pr_info("ONFI flash detected\n");
        return 1;
@@ -3086,6 +3189,22 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
                extid >>= 2;
                /* Get buswidth information */
                *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0;
+
+               /*
+                * Toshiba 24nm raw SLC (i.e., not BENAND) have 32B OOB per
+                * 512B page. For Toshiba SLC, we decode the 5th/6th byte as
+                * follows:
+                * - ID byte 6, bits[2:0]: 100b -> 43nm, 101b -> 32nm,
+                *                         110b -> 24nm
+                * - ID byte 5, bit[7]:    1 -> BENAND, 0 -> raw SLC
+                */
+               if (id_len >= 6 && id_data[0] == NAND_MFR_TOSHIBA &&
+                               !(chip->cellinfo & NAND_CI_CELLTYPE_MSK) &&
+                               (id_data[5] & 0x7) == 0x6 /* 24nm */ &&
+                               !(id_data[4] & 0x80) /* !BENAND */) {
+                       mtd->oobsize = 32 * mtd->writesize >> 9;
+               }
+
        }
 }
 
@@ -3172,6 +3291,8 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
                chip->cellinfo = id_data[2];
                chip->chipsize = (uint64_t)type->chipsize << 20;
                chip->options |= type->options;
+               chip->ecc_strength_ds = NAND_ECC_STRENGTH(type);
+               chip->ecc_step_ds = NAND_ECC_STEP(type);
 
                *busw = type->options & NAND_BUSWIDTH_16;
 
@@ -3446,12 +3567,6 @@ int nand_scan_tail(struct mtd_info *mtd)
        if (!chip->write_page)
                chip->write_page = nand_write_page;
 
-       /* set for ONFI nand */
-       if (!chip->onfi_set_features)
-               chip->onfi_set_features = nand_onfi_set_features;
-       if (!chip->onfi_get_features)
-               chip->onfi_get_features = nand_onfi_get_features;
-
        /*
         * Check ECC mode, default to software if 3byte/512byte hardware ECC is
         * selected and we have 256 byte pagesize fallback to software ECC
@@ -3674,6 +3789,7 @@ int nand_scan_tail(struct mtd_info *mtd)
        /* propagate ecc info to mtd_info */
        mtd->ecclayout = chip->ecc.layout;
        mtd->ecc_strength = chip->ecc.strength;
+       mtd->ecc_step_size = chip->ecc.size;
        /*
         * Initialize bitflip_threshold to its default prior scan_bbt() call.
         * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be
index 267264320e06587cbee58ad5e036a38b90f07fe9..bc06196d57395c5c0a9ec8dba4ea5fcd8832e8b2 100644 (file)
 #include <linux/export.h>
 #include <linux/string.h>
 
+#define BBT_BLOCK_GOOD         0x00
+#define BBT_BLOCK_WORN         0x01
+#define BBT_BLOCK_RESERVED     0x02
+#define BBT_BLOCK_FACTORY_BAD  0x03
+
+#define BBT_ENTRY_MASK         0x03
+#define BBT_ENTRY_SHIFT                2
+
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
+
+static inline uint8_t bbt_get_entry(struct nand_chip *chip, int block)
+{
+       uint8_t entry = chip->bbt[block >> BBT_ENTRY_SHIFT];
+       entry >>= (block & BBT_ENTRY_MASK) * 2;
+       return entry & BBT_ENTRY_MASK;
+}
+
+static inline void bbt_mark_entry(struct nand_chip *chip, int block,
+               uint8_t mark)
+{
+       uint8_t msk = (mark & BBT_ENTRY_MASK) << ((block & BBT_ENTRY_MASK) * 2);
+       chip->bbt[block >> BBT_ENTRY_SHIFT] |= msk;
+}
+
 static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
 {
        if (memcmp(buf, td->pattern, td->len))
@@ -86,33 +110,17 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td)
  * @td: search pattern descriptor
  *
  * Check for a pattern at the given place. Used to search bad block tables and
- * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if
- * all bytes except the pattern area contain 0xff.
+ * good / bad block identifiers.
  */
 static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
 {
-       int end = 0;
-       uint8_t *p = buf;
-
        if (td->options & NAND_BBT_NO_OOB)
                return check_pattern_no_oob(buf, td);
 
-       end = paglen + td->offs;
-       if (td->options & NAND_BBT_SCANEMPTY)
-               if (memchr_inv(p, 0xff, end))
-                       return -1;
-       p += end;
-
        /* Compare the pattern */
-       if (memcmp(p, td->pattern, td->len))
+       if (memcmp(buf + paglen + td->offs, td->pattern, td->len))
                return -1;
 
-       if (td->options & NAND_BBT_SCANEMPTY) {
-               p += td->len;
-               end += td->len;
-               if (memchr_inv(p, 0xff, len - end))
-                       return -1;
-       }
        return 0;
 }
 
@@ -159,7 +167,7 @@ static u32 add_marker_len(struct nand_bbt_descr *td)
  * @page: the starting page
  * @num: the number of bbt descriptors to read
  * @td: the bbt describtion table
- * @offs: offset in the memory table
+ * @offs: block number offset in the table
  *
  * Read the bad block table starting from page.
  */
@@ -209,14 +217,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                /* Analyse data */
                for (i = 0; i < len; i++) {
                        uint8_t dat = buf[i];
-                       for (j = 0; j < 8; j += bits, act += 2) {
+                       for (j = 0; j < 8; j += bits, act++) {
                                uint8_t tmp = (dat >> j) & msk;
                                if (tmp == msk)
                                        continue;
                                if (reserved_block_code && (tmp == reserved_block_code)) {
                                        pr_info("nand_read_bbt: reserved block at 0x%012llx\n",
-                                                (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
-                                       this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);
+                                                (loff_t)(offs + act) <<
+                                                this->bbt_erase_shift);
+                                       bbt_mark_entry(this, offs + act,
+                                                       BBT_BLOCK_RESERVED);
                                        mtd->ecc_stats.bbtblocks++;
                                        continue;
                                }
@@ -225,12 +235,15 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,
                                 * move this message to pr_debug.
                                 */
                                pr_info("nand_read_bbt: bad block at 0x%012llx\n",
-                                        (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);
+                                        (loff_t)(offs + act) <<
+                                        this->bbt_erase_shift);
                                /* Factory marked bad or worn out? */
                                if (tmp == 0)
-                                       this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);
+                                       bbt_mark_entry(this, offs + act,
+                                                       BBT_BLOCK_FACTORY_BAD);
                                else
-                                       this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);
+                                       bbt_mark_entry(this, offs + act,
+                                                       BBT_BLOCK_WORN);
                                mtd->ecc_stats.badblocks++;
                        }
                }
@@ -265,7 +278,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
                                        td, offs);
                        if (res)
                                return res;
-                       offs += this->chipsize >> (this->bbt_erase_shift + 2);
+                       offs += this->chipsize >> this->bbt_erase_shift;
                }
        } else {
                res = read_bbt(mtd, buf, td->pages[0],
@@ -478,22 +491,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
        else
                numpages = 1;
 
-       if (!(bd->options & NAND_BBT_SCANEMPTY)) {
-               /* We need only read few bytes from the OOB area */
-               scanlen = 0;
-               readlen = bd->len;
-       } else {
-               /* Full page content should be read */
-               scanlen = mtd->writesize + mtd->oobsize;
-               readlen = numpages * mtd->writesize;
-       }
+       /* We need only read few bytes from the OOB area */
+       scanlen = 0;
+       readlen = bd->len;
 
        if (chip == -1) {
-               /*
-                * Note that numblocks is 2 * (real numblocks) here, see i+=2
-                * below as it makes shifting and masking less painful
-                */
-               numblocks = mtd->size >> (this->bbt_erase_shift - 1);
+               numblocks = mtd->size >> this->bbt_erase_shift;
                startblock = 0;
                from = 0;
        } else {
@@ -502,16 +505,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
                               chip + 1, this->numchips);
                        return -EINVAL;
                }
-               numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
+               numblocks = this->chipsize >> this->bbt_erase_shift;
                startblock = chip * numblocks;
                numblocks += startblock;
-               from = (loff_t)startblock << (this->bbt_erase_shift - 1);
+               from = (loff_t)startblock << this->bbt_erase_shift;
        }
 
        if (this->bbt_options & NAND_BBT_SCANLASTPAGE)
                from += mtd->erasesize - (mtd->writesize * numpages);
 
-       for (i = startblock; i < numblocks;) {
+       for (i = startblock; i < numblocks; i++) {
                int ret;
 
                BUG_ON(bd->options & NAND_BBT_NO_OOB);
@@ -526,13 +529,12 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,
                        return ret;
 
                if (ret) {
-                       this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+                       bbt_mark_entry(this, i, BBT_BLOCK_FACTORY_BAD);
                        pr_warn("Bad eraseblock %d at 0x%012llx\n",
-                               i >> 1, (unsigned long long)from);
+                               i, (unsigned long long)from);
                        mtd->ecc_stats.badblocks++;
                }
 
-               i += 2;
                from += (1 << this->bbt_erase_shift);
        }
        return 0;
@@ -655,9 +657,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
 {
        struct nand_chip *this = mtd->priv;
        struct erase_info einfo;
-       int i, j, res, chip = 0;
+       int i, res, chip = 0;
        int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
-       int nrchips, bbtoffs, pageoffs, ooboffs;
+       int nrchips, pageoffs, ooboffs;
        uint8_t msk[4];
        uint8_t rcode = td->reserved_block_code;
        size_t retlen, len = 0;
@@ -713,10 +715,9 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                for (i = 0; i < td->maxblocks; i++) {
                        int block = startblock + dir * i;
                        /* Check, if the block is bad */
-                       switch ((this->bbt[block >> 2] >>
-                                (2 * (block & 0x03))) & 0x03) {
-                       case 0x01:
-                       case 0x03:
+                       switch (bbt_get_entry(this, block)) {
+                       case BBT_BLOCK_WORN:
+                       case BBT_BLOCK_FACTORY_BAD:
                                continue;
                        }
                        page = block <<
@@ -748,8 +749,6 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                default: return -EINVAL;
                }
 
-               bbtoffs = chip * (numblocks >> 2);
-
                to = ((loff_t)page) << this->page_shift;
 
                /* Must we save the block contents? */
@@ -814,16 +813,12 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
                        buf[ooboffs + td->veroffs] = td->version[chip];
 
                /* Walk through the memory table */
-               for (i = 0; i < numblocks;) {
+               for (i = 0; i < numblocks; i++) {
                        uint8_t dat;
-                       dat = this->bbt[bbtoffs + (i >> 2)];
-                       for (j = 0; j < 4; j++, i++) {
-                               int sftcnt = (i << (3 - sft)) & sftmsk;
-                               /* Do not store the reserved bbt blocks! */
-                               buf[offs + (i >> sft)] &=
-                                       ~(msk[dat & 0x03] << sftcnt);
-                               dat >>= 2;
-                       }
+                       int sftcnt = (i << (3 - sft)) & sftmsk;
+                       dat = bbt_get_entry(this, chip * numblocks + i);
+                       /* Do not store the reserved bbt blocks! */
+                       buf[offs + (i >> sft)] &= ~(msk[dat] << sftcnt);
                }
 
                memset(&einfo, 0, sizeof(einfo));
@@ -865,7 +860,6 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
 {
        struct nand_chip *this = mtd->priv;
 
-       bd->options &= ~NAND_BBT_SCANEMPTY;
        return create_bbt(mtd, this->buffers->databuf, bd, -1);
 }
 
@@ -1009,7 +1003,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
 {
        struct nand_chip *this = mtd->priv;
        int i, j, chips, block, nrblocks, update;
-       uint8_t oldval, newval;
+       uint8_t oldval;
 
        /* Do we have a bbt per chip? */
        if (td->options & NAND_BBT_PERCHIP) {
@@ -1026,12 +1020,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                        if (td->pages[i] == -1)
                                continue;
                        block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
-                       block <<= 1;
-                       oldval = this->bbt[(block >> 3)];
-                       newval = oldval | (0x2 << (block & 0x06));
-                       this->bbt[(block >> 3)] = newval;
-                       if ((oldval != newval) && td->reserved_block_code)
-                               nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));
+                       oldval = bbt_get_entry(this, block);
+                       bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+                       if ((oldval != BBT_BLOCK_RESERVED) &&
+                                       td->reserved_block_code)
+                               nand_update_bbt(mtd, (loff_t)block <<
+                                               this->bbt_erase_shift);
                        continue;
                }
                update = 0;
@@ -1039,14 +1033,12 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                        block = ((i + 1) * nrblocks) - td->maxblocks;
                else
                        block = i * nrblocks;
-               block <<= 1;
                for (j = 0; j < td->maxblocks; j++) {
-                       oldval = this->bbt[(block >> 3)];
-                       newval = oldval | (0x2 << (block & 0x06));
-                       this->bbt[(block >> 3)] = newval;
-                       if (oldval != newval)
+                       oldval = bbt_get_entry(this, block);
+                       bbt_mark_entry(this, block, BBT_BLOCK_RESERVED);
+                       if (oldval != BBT_BLOCK_RESERVED)
                                update = 1;
-                       block += 2;
+                       block++;
                }
                /*
                 * If we want reserved blocks to be recorded to flash, and some
@@ -1054,7 +1046,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
                 * bbts.  This should only happen once.
                 */
                if (update && td->reserved_block_code)
-                       nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1));
+                       nand_update_bbt(mtd, (loff_t)(block - 1) <<
+                                       this->bbt_erase_shift);
        }
 }
 
@@ -1180,13 +1173,13 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
 }
 
 /**
- * nand_update_bbt - [NAND Interface] update bad block table(s)
+ * nand_update_bbt - update bad block table(s)
  * @mtd: MTD device structure
  * @offs: the offset of the newly marked block
  *
  * The function updates the bad block table(s).
  */
-int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
+static int nand_update_bbt(struct mtd_info *mtd, loff_t offs)
 {
        struct nand_chip *this = mtd->priv;
        int len, res = 0;
@@ -1356,28 +1349,47 @@ int nand_default_bbt(struct mtd_info *mtd)
 int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
 {
        struct nand_chip *this = mtd->priv;
-       int block;
-       uint8_t res;
+       int block, res;
 
-       /* Get block number * 2 */
-       block = (int)(offs >> (this->bbt_erase_shift - 1));
-       res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
+       block = (int)(offs >> this->bbt_erase_shift);
+       res = bbt_get_entry(this, block);
 
        pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: "
                        "(block %d) 0x%02x\n",
-                       (unsigned int)offs, block >> 1, res);
+                       (unsigned int)offs, block, res);
 
-       switch ((int)res) {
-       case 0x00:
+       switch (res) {
+       case BBT_BLOCK_GOOD:
                return 0;
-       case 0x01:
+       case BBT_BLOCK_WORN:
                return 1;
-       case 0x02:
+       case BBT_BLOCK_RESERVED:
                return allowbbt ? 0 : 1;
        }
        return 1;
 }
 
+/**
+ * nand_markbad_bbt - [NAND Interface] Mark a block bad in the BBT
+ * @mtd: MTD device structure
+ * @offs: offset of the bad block
+ */
+int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs)
+{
+       struct nand_chip *this = mtd->priv;
+       int block, ret = 0;
+
+       block = (int)(offs >> this->bbt_erase_shift);
+
+       /* Mark bad block in memory */
+       bbt_mark_entry(this, block, BBT_BLOCK_WORN);
+
+       /* Update flash-based bad block table */
+       if (this->bbt_options & NAND_BBT_USE_FLASH)
+               ret = nand_update_bbt(mtd, offs);
+
+       return ret;
+}
+
 EXPORT_SYMBOL(nand_scan_bbt);
 EXPORT_SYMBOL(nand_default_bbt);
-EXPORT_SYMBOL_GPL(nand_update_bbt);
index 683813a46a905f489feabaced468efd88abc136d..a87b0a3afa351a1b8f8991836cb99af930d858da 100644 (file)
@@ -33,16 +33,16 @@ struct nand_flash_dev nand_flash_ids[] = {
         */
        {"TC58NVG2S0F 4G 3.3V 8-bit",
                { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} },
-                 SZ_4K, SZ_512, SZ_256K, 0, 8, 224},
+                 SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) },
        {"TC58NVG3S0F 8G 3.3V 8-bit",
                { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} },
-                 SZ_4K, SZ_1K, SZ_256K, 0, 8, 232},
+                 SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) },
        {"TC58NVG5D2 32G 3.3V 8-bit",
                { .id = {0x98, 0xd7, 0x94, 0x32, 0x76, 0x56, 0x09, 0x00} },
-                 SZ_8K, SZ_4K, SZ_1M, 0, 8, 640},
+                 SZ_8K, SZ_4K, SZ_1M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
        {"TC58NVG6D2 64G 3.3V 8-bit",
                { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
-                 SZ_8K, SZ_8K, SZ_2M, 0, 8, 640},
+                 SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
 
        LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
        LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
index cb38f3d94218b2c977437062f8f402d07941fd6c..bdc1d15369f844bfce700a9794b4f8eb558fa921 100644 (file)
@@ -205,7 +205,7 @@ MODULE_PARM_DESC(bch,                "Enable BCH ecc and set how many bits should "
 
 /* Calculate the page offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET(ns) \
-       (((ns)->regs.row << (ns)->geom.pgshift) + ((ns)->regs.row * (ns)->geom.oobsz) + (ns)->regs.column)
+       (((ns)->regs.row * (ns)->geom.pgszoob) + (ns)->regs.column)
 
 /* Calculate the OOB offset in flash RAM image by (row, column) address */
 #define NS_RAW_OFFSET_OOB(ns) (NS_RAW_OFFSET(ns) + ns->geom.pgsz)
@@ -336,7 +336,6 @@ struct nandsim {
                uint pgsec;         /* number of pages per sector */
                uint secshift;      /* bits number in sector size */
                uint pgshift;       /* bits number in page size */
-               uint oobshift;      /* bits number in OOB size */
                uint pgaddrbytes;   /* bytes per page address */
                uint secaddrbytes;  /* bytes per sector address */
                uint idbytes;       /* the number ID bytes that this chip outputs */
@@ -363,7 +362,7 @@ struct nandsim {
 
        /* Fields needed when using a cache file */
        struct file *cfile; /* Open file */
-       unsigned char *pages_written; /* Which pages have been written */
+       unsigned long *pages_written; /* Which pages have been written */
        void *file_buf;
        struct page *held_pages[NS_MAX_HELD_PAGES];
        int held_cnt;
@@ -586,7 +585,8 @@ static int alloc_device(struct nandsim *ns)
                        err = -EINVAL;
                        goto err_close;
                }
-               ns->pages_written = vzalloc(ns->geom.pgnum);
+               ns->pages_written = vzalloc(BITS_TO_LONGS(ns->geom.pgnum) *
+                                           sizeof(unsigned long));
                if (!ns->pages_written) {
                        NS_ERR("alloc_device: unable to allocate pages written array\n");
                        err = -ENOMEM;
@@ -653,9 +653,7 @@ static void free_device(struct nandsim *ns)
 
 static char *get_partition_name(int i)
 {
-       char buf[64];
-       sprintf(buf, "NAND simulator partition %d", i);
-       return kstrdup(buf, GFP_KERNEL);
+       return kasprintf(GFP_KERNEL, "NAND simulator partition %d", i);
 }
 
 /*
@@ -690,7 +688,6 @@ static int init_nandsim(struct mtd_info *mtd)
        ns->geom.totszoob = ns->geom.totsz + (uint64_t)ns->geom.pgnum * ns->geom.oobsz;
        ns->geom.secshift = ffs(ns->geom.secsz) - 1;
        ns->geom.pgshift  = chip->page_shift;
-       ns->geom.oobshift = ffs(ns->geom.oobsz) - 1;
        ns->geom.pgsec    = ns->geom.secsz / ns->geom.pgsz;
        ns->geom.secszoob = ns->geom.secsz + ns->geom.oobsz * ns->geom.pgsec;
        ns->options = 0;
@@ -761,12 +758,6 @@ static int init_nandsim(struct mtd_info *mtd)
                ns->nbparts += 1;
        }
 
-       /* Detect how many ID bytes the NAND chip outputs */
-       for (i = 0; nand_flash_ids[i].name != NULL; i++) {
-               if (second_id_byte != nand_flash_ids[i].dev_id)
-                       continue;
-       }
-
        if (ns->busw == 16)
                NS_WARN("16-bit flashes support wasn't tested\n");
 
@@ -780,7 +771,7 @@ static int init_nandsim(struct mtd_info *mtd)
        printk("bus width: %u\n",               ns->busw);
        printk("bits in sector size: %u\n",     ns->geom.secshift);
        printk("bits in page size: %u\n",       ns->geom.pgshift);
-       printk("bits in OOB size: %u\n",        ns->geom.oobshift);
+       printk("bits in OOB size: %u\n",        ffs(ns->geom.oobsz) - 1);
        printk("flash size with OOB: %llu KiB\n",
                        (unsigned long long)ns->geom.totszoob >> 10);
        printk("page address bytes: %u\n",      ns->geom.pgaddrbytes);
@@ -1442,7 +1433,7 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
        return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
 }
 
-int do_read_error(struct nandsim *ns, int num)
+static int do_read_error(struct nandsim *ns, int num)
 {
        unsigned int page_no = ns->regs.row;
 
@@ -1454,7 +1445,7 @@ int do_read_error(struct nandsim *ns, int num)
        return 0;
 }
 
-void do_bit_flips(struct nandsim *ns, int num)
+static void do_bit_flips(struct nandsim *ns, int num)
 {
        if (bitflips && prandom_u32() < (1 << 22)) {
                int flips = 1;
@@ -1479,7 +1470,7 @@ static void read_page(struct nandsim *ns, int num)
        union ns_mem *mypage;
 
        if (ns->cfile) {
-               if (!ns->pages_written[ns->regs.row]) {
+               if (!test_bit(ns->regs.row, ns->pages_written)) {
                        NS_DBG("read_page: page %d not written\n", ns->regs.row);
                        memset(ns->buf.byte, 0xFF, num);
                } else {
@@ -1490,7 +1481,7 @@ static void read_page(struct nandsim *ns, int num)
                                ns->regs.row, ns->regs.column + ns->regs.off);
                        if (do_read_error(ns, num))
                                return;
-                       pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
+                       pos = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
                        tx = read_file(ns, ns->cfile, ns->buf.byte, num, pos);
                        if (tx != num) {
                                NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx);
@@ -1525,9 +1516,9 @@ static void erase_sector(struct nandsim *ns)
 
        if (ns->cfile) {
                for (i = 0; i < ns->geom.pgsec; i++)
-                       if (ns->pages_written[ns->regs.row + i]) {
+                       if (__test_and_clear_bit(ns->regs.row + i,
+                                                ns->pages_written)) {
                                NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i);
-                               ns->pages_written[ns->regs.row + i] = 0;
                        }
                return;
        }
@@ -1559,8 +1550,8 @@ static int prog_page(struct nandsim *ns, int num)
 
                NS_DBG("prog_page: writing page %d\n", ns->regs.row);
                pg_off = ns->file_buf + ns->regs.column + ns->regs.off;
-               off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off;
-               if (!ns->pages_written[ns->regs.row]) {
+               off = (loff_t)NS_RAW_OFFSET(ns) + ns->regs.off;
+               if (!test_bit(ns->regs.row, ns->pages_written)) {
                        all = 1;
                        memset(ns->file_buf, 0xff, ns->geom.pgszoob);
                } else {
@@ -1580,7 +1571,7 @@ static int prog_page(struct nandsim *ns, int num)
                                NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx);
                                return -1;
                        }
-                       ns->pages_written[ns->regs.row] = 1;
+                       __set_bit(ns->regs.row, ns->pages_written);
                } else {
                        tx = write_file(ns, ns->cfile, pg_off, num, off);
                        if (tx != num) {
index cd6be2ed53a86a86a1baca65440adb73183d10a8..52115151e4a7f325491a3dbf6f16ccd87221b37a 100644 (file)
@@ -324,8 +324,6 @@ static int nuc900_nand_remove(struct platform_device *pdev)
 
        kfree(nuc900_nand);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 81b80af55872a4f2481dd6d3d0c61b762e02ff51..4ecf0e5fd4844d0432d68b0c9981bc9a79531b37 100644 (file)
@@ -154,7 +154,7 @@ static struct nand_ecclayout omap_oobinfo;
  */
 static uint8_t scan_ff_pattern[] = { 0xff };
 static struct nand_bbt_descr bb_descrip_flashbased = {
-       .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+       .options = NAND_BBT_SCANALLPAGES,
        .offs = 0,
        .len = 1,
        .pattern = scan_ff_pattern,
@@ -1831,7 +1831,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        struct resource                 *res;
        struct mtd_part_parser_data     ppdata = {};
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (pdata == NULL) {
                dev_err(&pdev->dev, "platform data missing\n");
                return -ENODEV;
@@ -2087,7 +2087,6 @@ static int omap_nand_remove(struct platform_device *pdev)
                                                        mtd);
        omap3_free_bch(&info->mtd);
 
-       platform_set_drvdata(pdev, NULL);
        if (info->dma)
                dma_release_channel(info->dma);
 
index 8fbd002086107f1fff96d26307e9b670b1ca7d95..a393a5b6ce1e5028155a415ae33db88067a7bfff 100644 (file)
@@ -130,8 +130,9 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                if (!of_property_read_u32(pdev->dev.of_node,
                                                "chip-delay", &val))
                        board->chip_delay = (u8)val;
-       } else
-               board = pdev->dev.platform_data;
+       } else {
+               board = dev_get_platdata(&pdev->dev);
+       }
 
        mtd->priv = nc;
        mtd->owner = THIS_MODULE;
@@ -186,7 +187,6 @@ no_dev:
                clk_disable_unprepare(clk);
                clk_put(clk);
        }
-       platform_set_drvdata(pdev, NULL);
        iounmap(io_base);
 no_res:
        kfree(nc);
index c004566a9ad2ae383a311ea31587411e0a98aaa7..cad4cdc9df399a70c77640be5a634b837996790d 100644 (file)
@@ -30,7 +30,7 @@ static const char *part_probe_types[] = { "cmdlinepart", NULL };
  */
 static int plat_nand_probe(struct platform_device *pdev)
 {
-       struct platform_nand_data *pdata = pdev->dev.platform_data;
+       struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
        struct mtd_part_parser_data ppdata;
        struct plat_nand_data *data;
        struct resource *res;
@@ -122,7 +122,6 @@ static int plat_nand_probe(struct platform_device *pdev)
 out:
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
-       platform_set_drvdata(pdev, NULL);
        iounmap(data->io_base);
 out_release_io:
        release_mem_region(res->start, resource_size(res));
@@ -137,7 +136,7 @@ out_free:
 static int plat_nand_remove(struct platform_device *pdev)
 {
        struct plat_nand_data *data = platform_get_drvdata(pdev);
-       struct platform_nand_data *pdata = pdev->dev.platform_data;
+       struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
        struct resource *res;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
index dec80ca6a5ce58dbd187690ea42fc706c9dc9325..5db900d917f92434f5941a393bcb9045ee99bd6c 100644 (file)
 #include <linux/of.h>
 #include <linux/of_device.h>
 
+#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
+#define ARCH_HAS_DMA
+#endif
+
+#ifdef ARCH_HAS_DMA
 #include <mach/dma.h>
+#endif
+
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
 #define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
@@ -80,6 +87,7 @@
 #define NDSR_RDDREQ            (0x1 << 1)
 #define NDSR_WRCMDREQ          (0x1)
 
+#define NDCB0_LEN_OVRD         (0x1 << 28)
 #define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_AUTO_RS          (0x1 << 25)
 #define NDCB0_CSEL             (0x1 << 24)
@@ -123,9 +131,13 @@ enum {
        STATE_READY,
 };
 
+enum pxa3xx_nand_variant {
+       PXA3XX_NAND_VARIANT_PXA,
+       PXA3XX_NAND_VARIANT_ARMADA370,
+};
+
 struct pxa3xx_nand_host {
        struct nand_chip        chip;
-       struct pxa3xx_nand_cmdset *cmdset;
        struct mtd_info         *mtd;
        void                    *info_data;
 
@@ -139,10 +151,6 @@ struct pxa3xx_nand_host {
        unsigned int            row_addr_cycles;
        size_t                  read_id_bytes;
 
-       /* cached register value */
-       uint32_t                reg_ndcr;
-       uint32_t                ndtr0cs0;
-       uint32_t                ndtr1cs0;
 };
 
 struct pxa3xx_nand_info {
@@ -171,9 +179,16 @@ struct pxa3xx_nand_info {
        struct pxa3xx_nand_host *host[NUM_CHIP_SELECT];
        unsigned int            state;
 
+       /*
+        * This driver supports NFCv1 (as found in PXA SoC)
+        * and NFCv2 (as found in Armada 370/XP SoC).
+        */
+       enum pxa3xx_nand_variant variant;
+
        int                     cs;
        int                     use_ecc;        /* use HW ECC ? */
        int                     use_dma;        /* use DMA ? */
+       int                     use_spare;      /* use spare ? */
        int                     is_ready;
 
        unsigned int            page_size;      /* page size of attached chip */
@@ -181,33 +196,22 @@ struct pxa3xx_nand_info {
        unsigned int            oob_size;
        int                     retcode;
 
+       /* cached register value */
+       uint32_t                reg_ndcr;
+       uint32_t                ndtr0cs0;
+       uint32_t                ndtr1cs0;
+
        /* generated NDCBx register values */
        uint32_t                ndcb0;
        uint32_t                ndcb1;
        uint32_t                ndcb2;
+       uint32_t                ndcb3;
 };
 
 static bool use_dma = 1;
 module_param(use_dma, bool, 0444);
 MODULE_PARM_DESC(use_dma, "enable DMA for data transferring to/from NAND HW");
 
-/*
- * Default NAND flash controller configuration setup by the
- * bootloader. This configuration is used only when pdata->keep_config is set
- */
-static struct pxa3xx_nand_cmdset default_cmdset = {
-       .read1          = 0x3000,
-       .read2          = 0x0050,
-       .program        = 0x1080,
-       .read_status    = 0x0070,
-       .read_id        = 0x0090,
-       .erase          = 0xD060,
-       .reset          = 0x00FF,
-       .lock           = 0x002A,
-       .unlock         = 0x2423,
-       .lock_status    = 0x007A,
-};
-
 static struct pxa3xx_nand_timing timing[] = {
        { 40, 80, 60, 100, 80, 100, 90000, 400, 40, },
        { 10,  0, 20,  40, 30,  40, 11123, 110, 10, },
@@ -230,8 +234,6 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
 /* Define a default flash type setting serve as flash detecting only */
 #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
 
-const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL};
-
 #define NDTR0_tCH(c)   (min((c), 7) << 19)
 #define NDTR0_tCS(c)   (min((c), 7) << 16)
 #define NDTR0_tWH(c)   (min((c), 7) << 11)
@@ -264,8 +266,8 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
                NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) |
                NDTR1_tAR(ns2cycle(t->tAR, nand_clk));
 
-       host->ndtr0cs0 = ndtr0;
-       host->ndtr1cs0 = ndtr1;
+       info->ndtr0cs0 = ndtr0;
+       info->ndtr1cs0 = ndtr1;
        nand_writel(info, NDTR0CS0, ndtr0);
        nand_writel(info, NDTR1CS0, ndtr1);
 }
@@ -273,7 +275,7 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
 static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
 {
        struct pxa3xx_nand_host *host = info->host[info->cs];
-       int oob_enable = host->reg_ndcr & NDCR_SPARE_EN;
+       int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
 
        info->data_size = host->page_size;
        if (!oob_enable) {
@@ -299,12 +301,25 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
  */
 static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
 {
-       struct pxa3xx_nand_host *host = info->host[info->cs];
        uint32_t ndcr;
 
-       ndcr = host->reg_ndcr;
-       ndcr |= info->use_ecc ? NDCR_ECC_EN : 0;
-       ndcr |= info->use_dma ? NDCR_DMA_EN : 0;
+       ndcr = info->reg_ndcr;
+
+       if (info->use_ecc)
+               ndcr |= NDCR_ECC_EN;
+       else
+               ndcr &= ~NDCR_ECC_EN;
+
+       if (info->use_dma)
+               ndcr |= NDCR_DMA_EN;
+       else
+               ndcr &= ~NDCR_DMA_EN;
+
+       if (info->use_spare)
+               ndcr |= NDCR_SPARE_EN;
+       else
+               ndcr &= ~NDCR_SPARE_EN;
+
        ndcr |= NDCR_ND_RUN;
 
        /* clear status bits and run */
@@ -333,7 +348,8 @@ static void pxa3xx_nand_stop(struct pxa3xx_nand_info *info)
        nand_writel(info, NDSR, NDSR_MASK);
 }
 
-static void enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
+static void __maybe_unused
+enable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
 {
        uint32_t ndcr;
 
@@ -373,6 +389,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info)
        }
 }
 
+#ifdef ARCH_HAS_DMA
 static void start_data_dma(struct pxa3xx_nand_info *info)
 {
        struct pxa_dma_desc *desc = info->data_desc;
@@ -419,6 +436,10 @@ static void pxa3xx_nand_data_dma_irq(int channel, void *data)
        enable_int(info, NDCR_INT_MASK);
        nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
 }
+#else
+static void start_data_dma(struct pxa3xx_nand_info *info)
+{}
+#endif
 
 static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 {
@@ -467,9 +488,22 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
                nand_writel(info, NDSR, NDSR_WRCMDREQ);
                status &= ~NDSR_WRCMDREQ;
                info->state = STATE_CMD_HANDLE;
+
+               /*
+                * Command buffer registers NDCB{0-2} (and optionally NDCB3)
+                * must be loaded by writing directly either 12 or 16
+                * bytes directly to NDCB0, four bytes at a time.
+                *
+                * Direct write access to NDCB1, NDCB2 and NDCB3 is ignored
+                * but each NDCBx register can be read.
+                */
                nand_writel(info, NDCB0, info->ndcb0);
                nand_writel(info, NDCB0, info->ndcb1);
                nand_writel(info, NDCB0, info->ndcb2);
+
+               /* NDCB3 register is available in NFCv2 (Armada 370/XP SoC) */
+               if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
+                       nand_writel(info, NDCB0, info->ndcb3);
        }
 
        /* clear NDSR to let the controller exit the IRQ */
@@ -491,7 +525,6 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
 static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
                uint16_t column, int page_addr)
 {
-       uint16_t cmd;
        int addr_cycle, exec_cmd;
        struct pxa3xx_nand_host *host;
        struct mtd_info *mtd;
@@ -506,6 +539,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
        info->buf_count         = 0;
        info->oob_size          = 0;
        info->use_ecc           = 0;
+       info->use_spare         = 1;
+       info->use_dma           = (use_dma) ? 1 : 0;
        info->is_ready          = 0;
        info->retcode           = ERR_NONE;
        if (info->cs != 0)
@@ -520,12 +555,16 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
        case NAND_CMD_READOOB:
                pxa3xx_set_datasize(info);
                break;
+       case NAND_CMD_PARAM:
+               info->use_spare = 0;
+               break;
        case NAND_CMD_SEQIN:
                exec_cmd = 0;
                break;
        default:
                info->ndcb1 = 0;
                info->ndcb2 = 0;
+               info->ndcb3 = 0;
                break;
        }
 
@@ -535,21 +574,17 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
        switch (command) {
        case NAND_CMD_READOOB:
        case NAND_CMD_READ0:
-               cmd = host->cmdset->read1;
+               info->buf_start = column;
+               info->ndcb0 |= NDCB0_CMD_TYPE(0)
+                               | addr_cycle
+                               | NAND_CMD_READ0;
+
                if (command == NAND_CMD_READOOB)
-                       info->buf_start = mtd->writesize + column;
-               else
-                       info->buf_start = column;
+                       info->buf_start += mtd->writesize;
 
-               if (unlikely(host->page_size < PAGE_CHUNK_SIZE))
-                       info->ndcb0 |= NDCB0_CMD_TYPE(0)
-                                       | addr_cycle
-                                       | (cmd & NDCB0_CMD1_MASK);
-               else
-                       info->ndcb0 |= NDCB0_CMD_TYPE(0)
-                                       | NDCB0_DBC
-                                       | addr_cycle
-                                       | cmd;
+               /* Second command setting for large pages */
+               if (host->page_size >= PAGE_CHUNK_SIZE)
+                       info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
 
        case NAND_CMD_SEQIN:
                /* small page addr setting */
@@ -580,49 +615,58 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
                        break;
                }
 
-               cmd = host->cmdset->program;
                info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
                                | NDCB0_AUTO_RS
                                | NDCB0_ST_ROW_EN
                                | NDCB0_DBC
-                               | cmd
+                               | (NAND_CMD_PAGEPROG << 8)
+                               | NAND_CMD_SEQIN
                                | addr_cycle;
                break;
 
+       case NAND_CMD_PARAM:
+               info->buf_count = 256;
+               info->ndcb0 |= NDCB0_CMD_TYPE(0)
+                               | NDCB0_ADDR_CYC(1)
+                               | NDCB0_LEN_OVRD
+                               | command;
+               info->ndcb1 = (column & 0xFF);
+               info->ndcb3 = 256;
+               info->data_size = 256;
+               break;
+
        case NAND_CMD_READID:
-               cmd = host->cmdset->read_id;
                info->buf_count = host->read_id_bytes;
                info->ndcb0 |= NDCB0_CMD_TYPE(3)
                                | NDCB0_ADDR_CYC(1)
-                               | cmd;
+                               | command;
+               info->ndcb1 = (column & 0xFF);
 
                info->data_size = 8;
                break;
        case NAND_CMD_STATUS:
-               cmd = host->cmdset->read_status;
                info->buf_count = 1;
                info->ndcb0 |= NDCB0_CMD_TYPE(4)
                                | NDCB0_ADDR_CYC(1)
-                               | cmd;
+                               | command;
 
                info->data_size = 8;
                break;
 
        case NAND_CMD_ERASE1:
-               cmd = host->cmdset->erase;
                info->ndcb0 |= NDCB0_CMD_TYPE(2)
                                | NDCB0_AUTO_RS
                                | NDCB0_ADDR_CYC(3)
                                | NDCB0_DBC
-                               | cmd;
+                               | (NAND_CMD_ERASE2 << 8)
+                               | NAND_CMD_ERASE1;
                info->ndcb1 = page_addr;
                info->ndcb2 = 0;
 
                break;
        case NAND_CMD_RESET:
-               cmd = host->cmdset->reset;
                info->ndcb0 |= NDCB0_CMD_TYPE(5)
-                               | cmd;
+                               | command;
 
                break;
 
@@ -652,7 +696,7 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
         * "byte" address into a "word" address appropriate
         * for indexing a word-oriented device
         */
-       if (host->reg_ndcr & NDCR_DWIDTH_M)
+       if (info->reg_ndcr & NDCR_DWIDTH_M)
                column /= 2;
 
        /*
@@ -662,8 +706,8 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
         */
        if (info->cs != host->cs) {
                info->cs = host->cs;
-               nand_writel(info, NDTR0CS0, host->ndtr0cs0);
-               nand_writel(info, NDTR1CS0, host->ndtr1cs0);
+               nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+               nand_writel(info, NDTR1CS0, info->ndtr1cs0);
        }
 
        info->state = STATE_PREPARED;
@@ -803,7 +847,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
                                    const struct pxa3xx_nand_flash *f)
 {
        struct platform_device *pdev = info->pdev;
-       struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
+       struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct pxa3xx_nand_host *host = info->host[info->cs];
        uint32_t ndcr = 0x0; /* enable all interrupts */
 
@@ -818,7 +862,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
        }
 
        /* calculate flash information */
-       host->cmdset = &default_cmdset;
        host->page_size = f->page_size;
        host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
 
@@ -840,7 +883,7 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
        ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes);
        ndcr |= NDCR_SPARE_EN; /* enable spare by default */
 
-       host->reg_ndcr = ndcr;
+       info->reg_ndcr = ndcr;
 
        pxa3xx_nand_set_timing(host, f->timing);
        return 0;
@@ -863,12 +906,9 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
                host->read_id_bytes = 2;
        }
 
-       host->reg_ndcr = ndcr & ~NDCR_INT_MASK;
-       host->cmdset = &default_cmdset;
-
-       host->ndtr0cs0 = nand_readl(info, NDTR0CS0);
-       host->ndtr1cs0 = nand_readl(info, NDTR1CS0);
-
+       info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
+       info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
+       info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
        return 0;
 }
 
@@ -878,6 +918,7 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
  */
 #define MAX_BUFF_SIZE  PAGE_SIZE
 
+#ifdef ARCH_HAS_DMA
 static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
 {
        struct platform_device *pdev = info->pdev;
@@ -912,6 +953,32 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
        return 0;
 }
 
+static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+{
+       struct platform_device *pdev = info->pdev;
+       if (use_dma) {
+               pxa_free_dma(info->data_dma_ch);
+               dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
+                                 info->data_buff, info->data_buff_phys);
+       } else {
+               kfree(info->data_buff);
+       }
+}
+#else
+static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info)
+{
+       info->data_buff = kmalloc(MAX_BUFF_SIZE, GFP_KERNEL);
+       if (info->data_buff == NULL)
+               return -ENOMEM;
+       return 0;
+}
+
+static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
+{
+       kfree(info->data_buff);
+}
+#endif
+
 static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
 {
        struct mtd_info *mtd;
@@ -934,7 +1001,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        struct pxa3xx_nand_host *host = mtd->priv;
        struct pxa3xx_nand_info *info = host->info_data;
        struct platform_device *pdev = info->pdev;
-       struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data;
+       struct pxa3xx_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL;
        const struct pxa3xx_nand_flash *f = NULL;
        struct nand_chip *chip = mtd->priv;
@@ -1003,7 +1070,7 @@ KEEP_CONFIG:
        chip->ecc.size = host->page_size;
        chip->ecc.strength = 1;
 
-       if (host->reg_ndcr & NDCR_DWIDTH_M)
+       if (info->reg_ndcr & NDCR_DWIDTH_M)
                chip->options |= NAND_BUSWIDTH_16;
 
        if (nand_scan_ident(mtd, 1, def))
@@ -1019,8 +1086,6 @@ KEEP_CONFIG:
                host->row_addr_cycles = 3;
        else
                host->row_addr_cycles = 2;
-
-       mtd->name = mtd_names[0];
        return nand_scan_tail(mtd);
 }
 
@@ -1034,13 +1099,11 @@ static int alloc_nand_resource(struct platform_device *pdev)
        struct resource *r;
        int ret, irq, cs;
 
-       pdata = pdev->dev.platform_data;
-       info = kzalloc(sizeof(*info) + (sizeof(*mtd) +
-                      sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
-       if (!info) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       pdata = dev_get_platdata(&pdev->dev);
+       info = devm_kzalloc(&pdev->dev, sizeof(*info) + (sizeof(*mtd) +
+                           sizeof(*host)) * pdata->num_cs, GFP_KERNEL);
+       if (!info)
                return -ENOMEM;
-       }
 
        info->pdev = pdev;
        for (cs = 0; cs < pdata->num_cs; cs++) {
@@ -1069,72 +1132,64 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
        spin_lock_init(&chip->controller->lock);
        init_waitqueue_head(&chip->controller->wq);
-       info->clk = clk_get(&pdev->dev, NULL);
+       info->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(info->clk)) {
                dev_err(&pdev->dev, "failed to get nand clock\n");
-               ret = PTR_ERR(info->clk);
-               goto fail_free_mtd;
+               return PTR_ERR(info->clk);
        }
-       clk_enable(info->clk);
-
-       /*
-        * This is a dirty hack to make this driver work from devicetree
-        * bindings. It can be removed once we have a prober DMA controller
-        * framework for DT.
-        */
-       if (pdev->dev.of_node && cpu_is_pxa3xx()) {
-               info->drcmr_dat = 97;
-               info->drcmr_cmd = 99;
-       } else {
-               r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
-               if (r == NULL) {
-                       dev_err(&pdev->dev, "no resource defined for data DMA\n");
-                       ret = -ENXIO;
-                       goto fail_put_clk;
-               }
-               info->drcmr_dat = r->start;
+       ret = clk_prepare_enable(info->clk);
+       if (ret < 0)
+               return ret;
 
-               r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
-               if (r == NULL) {
-                       dev_err(&pdev->dev, "no resource defined for command DMA\n");
-                       ret = -ENXIO;
-                       goto fail_put_clk;
+       if (use_dma) {
+               /*
+                * This is a dirty hack to make this driver work from
+                * devicetree bindings. It can be removed once we have
+                * a prober DMA controller framework for DT.
+                */
+               if (pdev->dev.of_node &&
+                   of_machine_is_compatible("marvell,pxa3xx")) {
+                       info->drcmr_dat = 97;
+                       info->drcmr_cmd = 99;
+               } else {
+                       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+                       if (r == NULL) {
+                               dev_err(&pdev->dev,
+                                       "no resource defined for data DMA\n");
+                               ret = -ENXIO;
+                               goto fail_disable_clk;
+                       }
+                       info->drcmr_dat = r->start;
+
+                       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+                       if (r == NULL) {
+                               dev_err(&pdev->dev,
+                                       "no resource defined for cmd DMA\n");
+                               ret = -ENXIO;
+                               goto fail_disable_clk;
+                       }
+                       info->drcmr_cmd = r->start;
                }
-               info->drcmr_cmd = r->start;
        }
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "no IRQ resource defined\n");
                ret = -ENXIO;
-               goto fail_put_clk;
+               goto fail_disable_clk;
        }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "no IO memory resource defined\n");
-               ret = -ENODEV;
-               goto fail_put_clk;
-       }
-
-       r = request_mem_region(r->start, resource_size(r), pdev->name);
-       if (r == NULL) {
-               dev_err(&pdev->dev, "failed to request memory resource\n");
-               ret = -EBUSY;
-               goto fail_put_clk;
-       }
-
-       info->mmio_base = ioremap(r->start, resource_size(r));
-       if (info->mmio_base == NULL) {
-               dev_err(&pdev->dev, "ioremap() failed\n");
-               ret = -ENODEV;
-               goto fail_free_res;
+       info->mmio_base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(info->mmio_base)) {
+               ret = PTR_ERR(info->mmio_base);
+               goto fail_disable_clk;
        }
        info->mmio_phys = r->start;
 
        ret = pxa3xx_nand_init_buff(info);
        if (ret)
-               goto fail_free_io;
+               goto fail_disable_clk;
 
        /* initialize all interrupts to be disabled */
        disable_int(info, NDSR_MASK);
@@ -1152,21 +1207,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
 
 fail_free_buf:
        free_irq(irq, info);
-       if (use_dma) {
-               pxa_free_dma(info->data_dma_ch);
-               dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE,
-                       info->data_buff, info->data_buff_phys);
-       } else
-               kfree(info->data_buff);
-fail_free_io:
-       iounmap(info->mmio_base);
-fail_free_res:
-       release_mem_region(r->start, resource_size(r));
-fail_put_clk:
-       clk_disable(info->clk);
-       clk_put(info->clk);
-fail_free_mtd:
-       kfree(info);
+       pxa3xx_nand_free_buff(info);
+fail_disable_clk:
+       clk_disable_unprepare(info->clk);
        return ret;
 }
 
@@ -1174,44 +1217,48 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
 {
        struct pxa3xx_nand_info *info = platform_get_drvdata(pdev);
        struct pxa3xx_nand_platform_data *pdata;
-       struct resource *r;
        int irq, cs;
 
        if (!info)
                return 0;
 
-       pdata = pdev->dev.platform_data;
-       platform_set_drvdata(pdev, NULL);
+       pdata = dev_get_platdata(&pdev->dev);
 
        irq = platform_get_irq(pdev, 0);
        if (irq >= 0)
                free_irq(irq, info);
-       if (use_dma) {
-               pxa_free_dma(info->data_dma_ch);
-               dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE,
-                               info->data_buff, info->data_buff_phys);
-       } else
-               kfree(info->data_buff);
-
-       iounmap(info->mmio_base);
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(r->start, resource_size(r));
+       pxa3xx_nand_free_buff(info);
 
-       clk_disable(info->clk);
-       clk_put(info->clk);
+       clk_disable_unprepare(info->clk);
 
        for (cs = 0; cs < pdata->num_cs; cs++)
                nand_release(info->host[cs]->mtd);
-       kfree(info);
        return 0;
 }
 
 #ifdef CONFIG_OF
 static struct of_device_id pxa3xx_nand_dt_ids[] = {
-       { .compatible = "marvell,pxa3xx-nand" },
+       {
+               .compatible = "marvell,pxa3xx-nand",
+               .data       = (void *)PXA3XX_NAND_VARIANT_PXA,
+       },
+       {
+               .compatible = "marvell,armada370-nand",
+               .data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
+       },
        {}
 };
-MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
+MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
+
+static enum pxa3xx_nand_variant
+pxa3xx_nand_get_variant(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id =
+                       of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+       if (!of_id)
+               return PXA3XX_NAND_VARIANT_PXA;
+       return (enum pxa3xx_nand_variant)of_id->data;
+}
 
 static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
 {
@@ -1251,11 +1298,18 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        struct pxa3xx_nand_info *info;
        int ret, cs, probe_success;
 
+#ifndef ARCH_HAS_DMA
+       if (use_dma) {
+               use_dma = 0;
+               dev_warn(&pdev->dev,
+                        "This platform can't do DMA on this device\n");
+       }
+#endif
        ret = pxa3xx_nand_probe_dt(pdev);
        if (ret)
                return ret;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data defined\n");
                return -ENODEV;
@@ -1268,10 +1322,14 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        }
 
        info = platform_get_drvdata(pdev);
+       info->variant = pxa3xx_nand_get_variant(pdev);
        probe_success = 0;
        for (cs = 0; cs < pdata->num_cs; cs++) {
+               struct mtd_info *mtd = info->host[cs]->mtd;
+
+               mtd->name = pdev->name;
                info->cs = cs;
-               ret = pxa3xx_nand_scan(info->host[cs]->mtd);
+               ret = pxa3xx_nand_scan(mtd);
                if (ret) {
                        dev_warn(&pdev->dev, "failed to scan nand at cs %d\n",
                                cs);
@@ -1279,7 +1337,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
                }
 
                ppdata.of_node = pdev->dev.of_node;
-               ret = mtd_device_parse_register(info->host[cs]->mtd, NULL,
+               ret = mtd_device_parse_register(mtd, NULL,
                                                &ppdata, pdata->parts[cs],
                                                pdata->nr_parts[cs]);
                if (!ret)
@@ -1302,7 +1360,7 @@ static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state)
        struct mtd_info *mtd;
        int cs;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (info->state) {
                dev_err(&pdev->dev, "driver busy, state = %d\n", info->state);
                return -EAGAIN;
@@ -1323,7 +1381,7 @@ static int pxa3xx_nand_resume(struct platform_device *pdev)
        struct mtd_info *mtd;
        int cs;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        /* We don't want to handle interrupt without calling mtd routine */
        disable_int(info, NDCR_INT_MASK);
 
index 4495f8551fa093fc6f30117475d624691e918430..9dcf02d22aa8fed1a8e4006952f9d7ee27739c9e 100644 (file)
@@ -229,7 +229,7 @@ static void r852_do_dma(struct r852_device *dev, uint8_t *buf, int do_read)
 /*
  * Program data lines of the nand chip to send data to it
  */
-void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+static void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 {
        struct r852_device *dev = r852_get_dev(mtd);
        uint32_t reg;
@@ -261,7 +261,7 @@ void r852_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 /*
  * Read data lines of the nand chip to retrieve data
  */
-void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+static void r852_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 {
        struct r852_device *dev = r852_get_dev(mtd);
        uint32_t reg;
@@ -312,7 +312,7 @@ static uint8_t r852_read_byte(struct mtd_info *mtd)
 /*
  * Control several chip lines & send commands
  */
-void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
+static void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
 {
        struct r852_device *dev = r852_get_dev(mtd);
 
@@ -357,7 +357,7 @@ void r852_cmdctl(struct mtd_info *mtd, int dat, unsigned int ctrl)
  * Wait till card is ready.
  * based on nand_wait, but returns errors on DMA error
  */
-int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
+static int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
 {
        struct r852_device *dev = chip->priv;
 
@@ -386,7 +386,7 @@ int r852_wait(struct mtd_info *mtd, struct nand_chip *chip)
  * Check if card is ready
  */
 
-int r852_ready(struct mtd_info *mtd)
+static int r852_ready(struct mtd_info *mtd)
 {
        struct r852_device *dev = r852_get_dev(mtd);
        return !(r852_read_reg(dev, R852_CARD_STA) & R852_CARD_STA_BUSY);
@@ -397,7 +397,7 @@ int r852_ready(struct mtd_info *mtd)
  * Set ECC engine mode
 */
 
-void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
+static void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
 {
        struct r852_device *dev = r852_get_dev(mtd);
 
@@ -429,7 +429,7 @@ void r852_ecc_hwctl(struct mtd_info *mtd, int mode)
  * Calculate ECC, only used for writes
  */
 
-int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
+static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
                                                        uint8_t *ecc_code)
 {
        struct r852_device *dev = r852_get_dev(mtd);
@@ -461,7 +461,7 @@ int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
  * Correct the data using ECC, hw did almost everything for us
  */
 
-int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
+static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
                                uint8_t *read_ecc, uint8_t *calc_ecc)
 {
        uint16_t ecc_reg;
@@ -529,7 +529,7 @@ static int r852_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
  * Start the nand engine
  */
 
-void r852_engine_enable(struct r852_device *dev)
+static void r852_engine_enable(struct r852_device *dev)
 {
        if (r852_read_reg_dword(dev, R852_HW) & R852_HW_UNKNOWN) {
                r852_write_reg(dev, R852_CTL, R852_CTL_RESET | R852_CTL_ON);
@@ -547,7 +547,7 @@ void r852_engine_enable(struct r852_device *dev)
  * Stop the nand engine
  */
 
-void r852_engine_disable(struct r852_device *dev)
+static void r852_engine_disable(struct r852_device *dev)
 {
        r852_write_reg_dword(dev, R852_HW, 0);
        r852_write_reg(dev, R852_CTL, R852_CTL_RESET);
@@ -557,7 +557,7 @@ void r852_engine_disable(struct r852_device *dev)
  * Test if card is present
  */
 
-void r852_card_update_present(struct r852_device *dev)
+static void r852_card_update_present(struct r852_device *dev)
 {
        unsigned long flags;
        uint8_t reg;
@@ -572,7 +572,7 @@ void r852_card_update_present(struct r852_device *dev)
  * Update card detection IRQ state according to current card state
  * which is read in r852_card_update_present
  */
-void r852_update_card_detect(struct r852_device *dev)
+static void r852_update_card_detect(struct r852_device *dev)
 {
        int card_detect_reg = r852_read_reg(dev, R852_CARD_IRQ_ENABLE);
        dev->card_unstable = 0;
@@ -586,8 +586,8 @@ void r852_update_card_detect(struct r852_device *dev)
        r852_write_reg(dev, R852_CARD_IRQ_ENABLE, card_detect_reg);
 }
 
-ssize_t r852_media_type_show(struct device *sys_dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t r852_media_type_show(struct device *sys_dev,
+                       struct device_attribute *attr, char *buf)
 {
        struct mtd_info *mtd = container_of(sys_dev, struct mtd_info, dev);
        struct r852_device *dev = r852_get_dev(mtd);
@@ -597,11 +597,11 @@ ssize_t r852_media_type_show(struct device *sys_dev,
        return strlen(data);
 }
 
-DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
+static DEVICE_ATTR(media_type, S_IRUGO, r852_media_type_show, NULL);
 
 
 /* Detect properties of card in slot */
-void r852_update_media_status(struct r852_device *dev)
+static void r852_update_media_status(struct r852_device *dev)
 {
        uint8_t reg;
        unsigned long flags;
@@ -630,7 +630,7 @@ void r852_update_media_status(struct r852_device *dev)
  * Register the nand device
  * Called when the card is detected
  */
-int r852_register_nand_device(struct r852_device *dev)
+static int r852_register_nand_device(struct r852_device *dev)
 {
        dev->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
 
@@ -668,7 +668,7 @@ error1:
  * Unregister the card
  */
 
-void r852_unregister_nand_device(struct r852_device *dev)
+static void r852_unregister_nand_device(struct r852_device *dev)
 {
        if (!dev->card_registred)
                return;
@@ -682,7 +682,7 @@ void r852_unregister_nand_device(struct r852_device *dev)
 }
 
 /* Card state updater */
-void r852_card_detect_work(struct work_struct *work)
+static void r852_card_detect_work(struct work_struct *work)
 {
        struct r852_device *dev =
                container_of(work, struct r852_device, card_detect_work.work);
@@ -821,7 +821,7 @@ out:
        return ret;
 }
 
-int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
+static int  r852_probe(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
        int error;
        struct nand_chip *chip;
@@ -961,7 +961,7 @@ error1:
        return error;
 }
 
-void r852_remove(struct pci_dev *pci_dev)
+static void r852_remove(struct pci_dev *pci_dev)
 {
        struct r852_device *dev = pci_get_drvdata(pci_dev);
 
@@ -992,7 +992,7 @@ void r852_remove(struct pci_dev *pci_dev)
        pci_disable_device(pci_dev);
 }
 
-void r852_shutdown(struct pci_dev *pci_dev)
+static void r852_shutdown(struct pci_dev *pci_dev)
 {
        struct r852_device *dev = pci_get_drvdata(pci_dev);
 
@@ -1002,7 +1002,7 @@ void r852_shutdown(struct pci_dev *pci_dev)
        pci_disable_device(pci_dev);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int r852_suspend(struct device *device)
 {
        struct r852_device *dev = pci_get_drvdata(to_pci_dev(device));
@@ -1055,9 +1055,6 @@ static int r852_resume(struct device *device)
        r852_update_card_detect(dev);
        return 0;
 }
-#else
-#define r852_suspend   NULL
-#define r852_resume    NULL
 #endif
 
 static const struct pci_device_id r852_pci_id_tbl[] = {
index d65afd23e171c16587dffd4fd0044121eb43313a..d65cbe903d4015e37076f0505db987ee4383e0d5 100644 (file)
@@ -150,7 +150,7 @@ static struct s3c2410_nand_info *to_nand_info(struct platform_device *dev)
 
 static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev)
 {
-       return dev->dev.platform_data;
+       return dev_get_platdata(&dev->dev);
 }
 
 static inline int allow_clk_suspend(struct s3c2410_nand_info *info)
@@ -697,8 +697,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev)
 {
        struct s3c2410_nand_info *info = to_nand_info(pdev);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (info == NULL)
                return 0;
 
index e57e18e8c2893ab8077693e13385bb06ddaad9af..a3c84ebbe39227dac06bae3d0f9014849cf48b17 100644 (file)
@@ -137,7 +137,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
        dma_cap_mask_t mask;
        struct dma_slave_config cfg;
        struct platform_device *pdev = flctl->pdev;
-       struct sh_flctl_platform_data *pdata = pdev->dev.platform_data;
+       struct sh_flctl_platform_data *pdata = dev_get_platdata(&pdev->dev);
        int ret;
 
        if (!pdata)
@@ -1131,7 +1131,7 @@ static int flctl_probe(struct platform_device *pdev)
        if (pdev->dev.of_node)
                pdata = flctl_parse_dt(&pdev->dev);
        else
-               pdata = pdev->dev.platform_data;
+               pdata = dev_get_platdata(&pdev->dev);
 
        if (!pdata) {
                dev_err(&pdev->dev, "no setup data defined\n");
index 127bc42718217a68c4c83fa89cf64b3cbed7d95c..87908d760feb067c3cb179b35bfa5a3c462ab737 100644 (file)
@@ -112,7 +112,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
        struct resource *r;
        int err = 0;
        struct sharpsl_nand *sharpsl;
-       struct sharpsl_nand_platform_data *data = pdev->dev.platform_data;
+       struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
 
        if (!data) {
                dev_err(&pdev->dev, "no platform data!\n");
@@ -194,7 +194,6 @@ err_add:
        nand_release(&sharpsl->mtd);
 
 err_scan:
-       platform_set_drvdata(pdev, NULL);
        iounmap(sharpsl->io);
 err_ioremap:
 err_get_res:
@@ -212,8 +211,6 @@ static int sharpsl_nand_remove(struct platform_device *pdev)
        /* Release resources, unregister device */
        nand_release(&sharpsl->mtd);
 
-       platform_set_drvdata(pdev, NULL);
-
        iounmap(sharpsl->io);
 
        /* Free the MTD device structure */
index e8181edebddd10923904c4db4be17adf79d29316..e06b5e5d3287dbaceaeed98941a77dcb595a5b4c 100644 (file)
@@ -42,7 +42,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
 {
        struct mtd_oob_ops ops;
        struct sm_oob oob;
-       int ret, error = 0;
+       int ret;
 
        memset(&oob, -1, SM_OOB_SIZE);
        oob.block_status = 0x0F;
@@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
                printk(KERN_NOTICE
                        "sm_common: can't mark sector at %i as bad\n",
                                                                (int)ofs);
-               error = -EIO;
-       } else
-               mtd->ecc_stats.badblocks++;
+               return -EIO;
+       }
 
-       return error;
+       return 0;
 }
 
 static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
index 508e9e04b0926a5b16c4620dc1f2a821e945680d..396530d87ecfb824f5e7a4ede7a92e6c8f0d3a82 100644 (file)
@@ -357,7 +357,7 @@ static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
 
 static int tmio_probe(struct platform_device *dev)
 {
-       struct tmio_nand_data *data = dev->dev.platform_data;
+       struct tmio_nand_data *data = dev_get_platdata(&dev->dev);
        struct resource *fcr = platform_get_resource(dev,
                        IORESOURCE_MEM, 0);
        struct resource *ccr = platform_get_resource(dev,
index 7ed654c68b0867af79c82da6f65cc210fb827498..235714a421dd6770851f2f5026522123f46dbefc 100644 (file)
@@ -87,7 +87,7 @@ static struct platform_device *mtd_to_platdev(struct mtd_info *mtd)
 static void __iomem *ndregaddr(struct platform_device *dev, unsigned int reg)
 {
        struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
-       struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+       struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
 
        return drvdata->base + (reg << plat->shift);
 }
@@ -138,7 +138,7 @@ static void txx9ndfmc_cmd_ctrl(struct mtd_info *mtd, int cmd,
        struct nand_chip *chip = mtd->priv;
        struct txx9ndfmc_priv *txx9_priv = chip->priv;
        struct platform_device *dev = txx9_priv->dev;
-       struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+       struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
 
        if (ctrl & NAND_CTRL_CHANGE) {
                u32 mcr = txx9ndfmc_read(dev, TXX9_NDFMCR);
@@ -225,7 +225,7 @@ static void txx9ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
 
 static void txx9ndfmc_initialize(struct platform_device *dev)
 {
-       struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+       struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
        struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
        int tmout = 100;
 
@@ -274,19 +274,17 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd)
 
 static int __init txx9ndfmc_probe(struct platform_device *dev)
 {
-       struct txx9ndfmc_platform_data *plat = dev->dev.platform_data;
+       struct txx9ndfmc_platform_data *plat = dev_get_platdata(&dev->dev);
        int hold, spw;
        int i;
        struct txx9ndfmc_drvdata *drvdata;
        unsigned long gbusclk = plat->gbus_clock;
        struct resource *res;
 
-       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
        drvdata = devm_kzalloc(&dev->dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        drvdata->base = devm_ioremap_resource(&dev->dev, res);
        if (IS_ERR(drvdata->base))
                return PTR_ERR(drvdata->base);
@@ -387,7 +385,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev)
        struct txx9ndfmc_drvdata *drvdata = platform_get_drvdata(dev);
        int i;
 
-       platform_set_drvdata(dev, NULL);
        if (!drvdata)
                return 0;
        for (i = 0; i < MAX_TXX9NDFMC_DEV; i++) {
index 553d6d6d560322c4bcafa44a184e6c09e864b621..d64f8c30945fbcd8e2d09a5b8342e75c081cd343 100644 (file)
 #include <linux/slab.h>
 #include <linux/mtd/partitions.h>
 
+static bool node_has_compatible(struct device_node *pp)
+{
+       return of_get_property(pp, "compatible", NULL);
+}
+
 static int parse_ofpart_partitions(struct mtd_info *master,
                                   struct mtd_partition **pparts,
                                   struct mtd_part_parser_data *data)
@@ -38,10 +43,13 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                return 0;
 
        /* First count the subnodes */
-       pp = NULL;
        nr_parts = 0;
-       while ((pp = of_get_next_child(node, pp)))
+       for_each_child_of_node(node,  pp) {
+               if (node_has_compatible(pp))
+                       continue;
+
                nr_parts++;
+       }
 
        if (nr_parts == 0)
                return 0;
@@ -50,13 +58,15 @@ static int parse_ofpart_partitions(struct mtd_info *master,
        if (!*pparts)
                return -ENOMEM;
 
-       pp = NULL;
        i = 0;
-       while ((pp = of_get_next_child(node, pp))) {
+       for_each_child_of_node(node,  pp) {
                const __be32 *reg;
                int len;
                int a_cells, s_cells;
 
+               if (node_has_compatible(pp))
+                       continue;
+
                reg = of_get_property(pp, "reg", &len);
                if (!reg) {
                        nr_parts--;
index 9f11562f849dbb0f7f5a4836cc31ce9c9a7e3cb5..63699fffc96de24b3098f629ea495184103386c8 100644 (file)
@@ -38,7 +38,7 @@ struct onenand_info {
 static int generic_onenand_probe(struct platform_device *pdev)
 {
        struct onenand_info *info;
-       struct onenand_platform_data *pdata = pdev->dev.platform_data;
+       struct onenand_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct resource *res = pdev->resource;
        unsigned long size = resource_size(res);
        int err;
@@ -94,8 +94,6 @@ static int generic_onenand_remove(struct platform_device *pdev)
        struct resource *res = pdev->resource;
        unsigned long size = resource_size(res);
 
-       platform_set_drvdata(pdev, NULL);
-
        if (info) {
                onenand_release(&info->mtd);
                release_mem_region(res->start, size);
index d98b198edd53a27139c1eaa0ffad5ae5f0fac9f2..558071bf92de0ed607355067b08ebea7fe3833b4 100644 (file)
@@ -639,7 +639,7 @@ static int omap2_onenand_probe(struct platform_device *pdev)
        struct resource *res;
        struct mtd_part_parser_data ppdata = {};
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (pdata == NULL) {
                dev_err(&pdev->dev, "platform data missing\n");
                return -ENODEV;
@@ -810,7 +810,6 @@ static int omap2_onenand_remove(struct platform_device *pdev)
        if (c->dma_channel != -1)
                omap_free_dma(c->dma_channel);
        omap2_onenand_shutdown(pdev);
-       platform_set_drvdata(pdev, NULL);
        if (c->gpio_irq) {
                free_irq(gpio_to_irq(c->gpio_irq), c);
                gpio_free(c->gpio_irq);
index 66fe3b7e78515679bae0f8ae75ab9bfb5b509958..08d0085f3e939fb277cc9c21b3b3004eab662206 100644 (file)
@@ -133,7 +133,6 @@ static inline int onenand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_desc
 {
        struct onenand_chip *this = mtd->priv;
 
-        bd->options &= ~NAND_BBT_SCANEMPTY;
        return create_bbt(mtd, this->page_buf, bd, -1);
 }
 
index 2cf74085f93524c784f9adc3c3920713da570f5a..df7400dd4df847b321bb1fdedbb5ac522e9c5b83 100644 (file)
@@ -867,7 +867,7 @@ static int s3c_onenand_probe(struct platform_device *pdev)
        struct resource *r;
        int size, err;
 
-       pdata = pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        /* No need to check pdata. the platform data is optional */
 
        size = sizeof(struct mtd_info) + sizeof(struct onenand_chip);
@@ -1073,7 +1073,6 @@ static int s3c_onenand_remove(struct platform_device *pdev)
        release_mem_region(onenand->base_res->start,
                           resource_size(onenand->base_res));
 
-       platform_set_drvdata(pdev, NULL);
        kfree(onenand->oob_buf);
        kfree(onenand->page_buf);
        kfree(onenand);
index f9d5615c572747ee6137a89327aa974322fd949f..4b8e89583f2a5d83f366515f4ed0fa5c4239361d 100644 (file)
@@ -22,7 +22,7 @@
 
 
 
-struct workqueue_struct *cache_flush_workqueue;
+static struct workqueue_struct *cache_flush_workqueue;
 
 static int cache_timeout = 1000;
 module_param(cache_timeout, int, S_IRUGO);
@@ -41,7 +41,7 @@ struct sm_sysfs_attribute {
        int len;
 };
 
-ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,
+static ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,
                     char *buf)
 {
        struct sm_sysfs_attribute *sm_attr =
@@ -54,7 +54,7 @@ ssize_t sm_attr_show(struct device *dev, struct device_attribute *attr,
 
 #define NUM_ATTRIBUTES 1
 #define SM_CIS_VENDOR_OFFSET 0x59
-struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
+static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
 {
        struct attribute_group *attr_group;
        struct attribute **attributes;
@@ -107,7 +107,7 @@ error1:
        return NULL;
 }
 
-void sm_delete_sysfs_attributes(struct sm_ftl *ftl)
+static void sm_delete_sysfs_attributes(struct sm_ftl *ftl)
 {
        struct attribute **attributes = ftl->disk_attributes->attrs;
        int i;
@@ -571,7 +571,7 @@ static const uint8_t cis_signature[] = {
 };
 /* Find out media parameters.
  * This ideally has to be based on nand id, but for now device size is enough */
-int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)
+static int sm_get_media_info(struct sm_ftl *ftl, struct mtd_info *mtd)
 {
        int i;
        int size_in_megs = mtd->size / (1024 * 1024);
@@ -878,7 +878,7 @@ static int sm_init_zone(struct sm_ftl *ftl, int zone_num)
 }
 
 /* Get and automatically initialize an FTL mapping for one zone */
-struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)
+static struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)
 {
        struct ftl_zone *zone;
        int error;
@@ -899,7 +899,7 @@ struct ftl_zone *sm_get_zone(struct sm_ftl *ftl, int zone_num)
 /* ----------------- cache handling ------------------------------------------*/
 
 /* Initialize the one block cache */
-void sm_cache_init(struct sm_ftl *ftl)
+static void sm_cache_init(struct sm_ftl *ftl)
 {
        ftl->cache_data_invalid_bitmap = 0xFFFFFFFF;
        ftl->cache_clean = 1;
@@ -909,7 +909,7 @@ void sm_cache_init(struct sm_ftl *ftl)
 }
 
 /* Put sector in one block cache */
-void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)
+static void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)
 {
        memcpy(ftl->cache_data + boffset, buffer, SM_SECTOR_SIZE);
        clear_bit(boffset / SM_SECTOR_SIZE, &ftl->cache_data_invalid_bitmap);
@@ -917,7 +917,7 @@ void sm_cache_put(struct sm_ftl *ftl, char *buffer, int boffset)
 }
 
 /* Read a sector from the cache */
-int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)
+static int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)
 {
        if (test_bit(boffset / SM_SECTOR_SIZE,
                &ftl->cache_data_invalid_bitmap))
@@ -928,7 +928,7 @@ int sm_cache_get(struct sm_ftl *ftl, char *buffer, int boffset)
 }
 
 /* Write the cache to hardware */
-int sm_cache_flush(struct sm_ftl *ftl)
+static int sm_cache_flush(struct sm_ftl *ftl)
 {
        struct ftl_zone *zone;
 
@@ -1274,10 +1274,10 @@ static struct mtd_blktrans_ops sm_ftl_ops = {
 static __init int sm_module_init(void)
 {
        int error = 0;
-       cache_flush_workqueue = create_freezable_workqueue("smflush");
 
-       if (IS_ERR(cache_flush_workqueue))
-               return PTR_ERR(cache_flush_workqueue);
+       cache_flush_workqueue = create_freezable_workqueue("smflush");
+       if (!cache_flush_workqueue)
+               return -ENOMEM;
 
        error = register_mtd_blktrans(&sm_ftl_ops);
        if (error)
index bd0065c0d359f7e207523ca06f2aa0221dc78fad..937a829bb70111c4e44ad110b9d9dc029f0b8d94 100644 (file)
@@ -7,3 +7,12 @@ obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_nandecctest.o
 obj-$(CONFIG_MTD_TESTS) += mtd_nandbiterrs.o
+
+mtd_oobtest-objs := oobtest.o mtd_test.o
+mtd_pagetest-objs := pagetest.o mtd_test.o
+mtd_readtest-objs := readtest.o mtd_test.o
+mtd_speedtest-objs := speedtest.o mtd_test.o
+mtd_stresstest-objs := stresstest.o mtd_test.o
+mtd_subpagetest-objs := subpagetest.o mtd_test.o
+mtd_torturetest-objs := torturetest.o mtd_test.o
+mtd_nandbiterrs-objs := nandbiterrs.o mtd_test.o
diff --git a/drivers/mtd/tests/mtd_nandbiterrs.c b/drivers/mtd/tests/mtd_nandbiterrs.c
deleted file mode 100644 (file)
index 207bf9a..0000000
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright Â© 2012 NetCommWireless
- * Iwo Mergler <Iwo.Mergler@netcommwireless.com.au>
- *
- * Test for multi-bit error recovery on a NAND page This mostly tests the
- * ECC controller / driver.
- *
- * There are two test modes:
- *
- *     0 - artificially inserting bit errors until the ECC fails
- *         This is the default method and fairly quick. It should
- *         be independent of the quality of the FLASH.
- *
- *     1 - re-writing the same pattern repeatedly until the ECC fails.
- *         This method relies on the physics of NAND FLASH to eventually
- *         generate '0' bits if '1' has been written sufficient times.
- *         Depending on the NAND, the first bit errors will appear after
- *         1000 or more writes and then will usually snowball, reaching the
- *         limits of the ECC quickly.
- *
- *         The test stops after 10000 cycles, should your FLASH be
- *         exceptionally good and not generate bit errors before that. Try
- *         a different page in that case.
- *
- * Please note that neither of these tests will significantly 'use up' any
- * FLASH endurance. Only a maximum of two erase operations will be performed.
- *
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/mtd/mtd.h>
-#include <linux/err.h>
-#include <linux/mtd/nand.h>
-#include <linux/slab.h>
-
-static int dev;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static unsigned page_offset;
-module_param(page_offset, uint, S_IRUGO);
-MODULE_PARM_DESC(page_offset, "Page number relative to dev start");
-
-static unsigned seed;
-module_param(seed, uint, S_IRUGO);
-MODULE_PARM_DESC(seed, "Random seed");
-
-static int mode;
-module_param(mode, int, S_IRUGO);
-MODULE_PARM_DESC(mode, "0=incremental errors, 1=overwrite test");
-
-static unsigned max_overwrite = 10000;
-
-static loff_t   offset;     /* Offset of the page we're using. */
-static unsigned eraseblock; /* Eraseblock number for our page. */
-
-/* We assume that the ECC can correct up to a certain number
- * of biterrors per subpage. */
-static unsigned subsize;  /* Size of subpages */
-static unsigned subcount; /* Number of subpages per page */
-
-static struct mtd_info *mtd;   /* MTD device */
-
-static uint8_t *wbuffer; /* One page write / compare buffer */
-static uint8_t *rbuffer; /* One page read buffer */
-
-/* 'random' bytes from known offsets */
-static uint8_t hash(unsigned offset)
-{
-       unsigned v = offset;
-       unsigned char c;
-       v ^= 0x7f7edfd3;
-       v = v ^ (v >> 3);
-       v = v ^ (v >> 5);
-       v = v ^ (v >> 13);
-       c = v & 0xFF;
-       /* Reverse bits of result. */
-       c = (c & 0x0F) << 4 | (c & 0xF0) >> 4;
-       c = (c & 0x33) << 2 | (c & 0xCC) >> 2;
-       c = (c & 0x55) << 1 | (c & 0xAA) >> 1;
-       return c;
-}
-
-static int erase_block(void)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = eraseblock * mtd->erasesize;
-
-       pr_info("erase_block\n");
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (err || ei.state == MTD_ERASE_FAILED) {
-               pr_err("error %d while erasing\n", err);
-               if (!err)
-                       err = -EIO;
-               return err;
-       }
-
-       return 0;
-}
-
-/* Writes wbuffer to page */
-static int write_page(int log)
-{
-       int err = 0;
-       size_t written;
-
-       if (log)
-               pr_info("write_page\n");
-
-       err = mtd_write(mtd, offset, mtd->writesize, &written, wbuffer);
-       if (err || written != mtd->writesize) {
-               pr_err("error: write failed at %#llx\n", (long long)offset);
-               if (!err)
-                       err = -EIO;
-       }
-
-       return err;
-}
-
-/* Re-writes the data area while leaving the OOB alone. */
-static int rewrite_page(int log)
-{
-       int err = 0;
-       struct mtd_oob_ops ops;
-
-       if (log)
-               pr_info("rewrite page\n");
-
-       ops.mode      = MTD_OPS_RAW; /* No ECC */
-       ops.len       = mtd->writesize;
-       ops.retlen    = 0;
-       ops.ooblen    = 0;
-       ops.oobretlen = 0;
-       ops.ooboffs   = 0;
-       ops.datbuf    = wbuffer;
-       ops.oobbuf    = NULL;
-
-       err = mtd_write_oob(mtd, offset, &ops);
-       if (err || ops.retlen != mtd->writesize) {
-               pr_err("error: write_oob failed (%d)\n", err);
-               if (!err)
-                       err = -EIO;
-       }
-
-       return err;
-}
-
-/* Reads page into rbuffer. Returns number of corrected bit errors (>=0)
- * or error (<0) */
-static int read_page(int log)
-{
-       int err = 0;
-       size_t read;
-       struct mtd_ecc_stats oldstats;
-
-       if (log)
-               pr_info("read_page\n");
-
-       /* Saving last mtd stats */
-       memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats));
-
-       err = mtd_read(mtd, offset, mtd->writesize, &read, rbuffer);
-       if (err == -EUCLEAN)
-               err = mtd->ecc_stats.corrected - oldstats.corrected;
-
-       if (err < 0 || read != mtd->writesize) {
-               pr_err("error: read failed at %#llx\n", (long long)offset);
-               if (err >= 0)
-                       err = -EIO;
-       }
-
-       return err;
-}
-
-/* Verifies rbuffer against random sequence */
-static int verify_page(int log)
-{
-       unsigned i, errs = 0;
-
-       if (log)
-               pr_info("verify_page\n");
-
-       for (i = 0; i < mtd->writesize; i++) {
-               if (rbuffer[i] != hash(i+seed)) {
-                       pr_err("Error: page offset %u, expected %02x, got %02x\n",
-                               i, hash(i+seed), rbuffer[i]);
-                       errs++;
-               }
-       }
-
-       if (errs)
-               return -EIO;
-       else
-               return 0;
-}
-
-#define CBIT(v, n) ((v) & (1 << (n)))
-#define BCLR(v, n) ((v) = (v) & ~(1 << (n)))
-
-/* Finds the first '1' bit in wbuffer starting at offset 'byte'
- * and sets it to '0'. */
-static int insert_biterror(unsigned byte)
-{
-       int bit;
-
-       while (byte < mtd->writesize) {
-               for (bit = 7; bit >= 0; bit--) {
-                       if (CBIT(wbuffer[byte], bit)) {
-                               BCLR(wbuffer[byte], bit);
-                               pr_info("Inserted biterror @ %u/%u\n", byte, bit);
-                               return 0;
-                       }
-               }
-               byte++;
-       }
-       pr_err("biterror: Failed to find a '1' bit\n");
-       return -EIO;
-}
-
-/* Writes 'random' data to page and then introduces deliberate bit
- * errors into the page, while verifying each step. */
-static int incremental_errors_test(void)
-{
-       int err = 0;
-       unsigned i;
-       unsigned errs_per_subpage = 0;
-
-       pr_info("incremental biterrors test\n");
-
-       for (i = 0; i < mtd->writesize; i++)
-               wbuffer[i] = hash(i+seed);
-
-       err = write_page(1);
-       if (err)
-               goto exit;
-
-       while (1) {
-
-               err = rewrite_page(1);
-               if (err)
-                       goto exit;
-
-               err = read_page(1);
-               if (err > 0)
-                       pr_info("Read reported %d corrected bit errors\n", err);
-               if (err < 0) {
-                       pr_err("After %d biterrors per subpage, read reported error %d\n",
-                               errs_per_subpage, err);
-                       err = 0;
-                       goto exit;
-               }
-
-               err = verify_page(1);
-               if (err) {
-                       pr_err("ECC failure, read data is incorrect despite read success\n");
-                       goto exit;
-               }
-
-               pr_info("Successfully corrected %d bit errors per subpage\n",
-                       errs_per_subpage);
-
-               for (i = 0; i < subcount; i++) {
-                       err = insert_biterror(i * subsize);
-                       if (err < 0)
-                               goto exit;
-               }
-               errs_per_subpage++;
-       }
-
-exit:
-       return err;
-}
-
-
-/* Writes 'random' data to page and then re-writes that same data repeatedly.
-   This eventually develops bit errors (bits written as '1' will slowly become
-   '0'), which are corrected as far as the ECC is capable of. */
-static int overwrite_test(void)
-{
-       int err = 0;
-       unsigned i;
-       unsigned max_corrected = 0;
-       unsigned opno = 0;
-       /* We don't expect more than this many correctable bit errors per
-        * page. */
-       #define MAXBITS 512
-       static unsigned bitstats[MAXBITS]; /* bit error histogram. */
-
-       memset(bitstats, 0, sizeof(bitstats));
-
-       pr_info("overwrite biterrors test\n");
-
-       for (i = 0; i < mtd->writesize; i++)
-               wbuffer[i] = hash(i+seed);
-
-       err = write_page(1);
-       if (err)
-               goto exit;
-
-       while (opno < max_overwrite) {
-
-               err = rewrite_page(0);
-               if (err)
-                       break;
-
-               err = read_page(0);
-               if (err >= 0) {
-                       if (err >= MAXBITS) {
-                               pr_info("Implausible number of bit errors corrected\n");
-                               err = -EIO;
-                               break;
-                       }
-                       bitstats[err]++;
-                       if (err > max_corrected) {
-                               max_corrected = err;
-                               pr_info("Read reported %d corrected bit errors\n",
-                                       err);
-                       }
-               } else { /* err < 0 */
-                       pr_info("Read reported error %d\n", err);
-                       err = 0;
-                       break;
-               }
-
-               err = verify_page(0);
-               if (err) {
-                       bitstats[max_corrected] = opno;
-                       pr_info("ECC failure, read data is incorrect despite read success\n");
-                       break;
-               }
-
-               opno++;
-       }
-
-       /* At this point bitstats[0] contains the number of ops with no bit
-        * errors, bitstats[1] the number of ops with 1 bit error, etc. */
-       pr_info("Bit error histogram (%d operations total):\n", opno);
-       for (i = 0; i < max_corrected; i++)
-               pr_info("Page reads with %3d corrected bit errors: %d\n",
-                       i, bitstats[i]);
-
-exit:
-       return err;
-}
-
-static int __init mtd_nandbiterrs_init(void)
-{
-       int err = 0;
-
-       printk("\n");
-       printk(KERN_INFO "==================================================\n");
-       pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               goto exit_mtddev;
-       }
-
-       if (mtd->type != MTD_NANDFLASH) {
-               pr_info("this test requires NAND flash\n");
-               err = -ENODEV;
-               goto exit_nand;
-       }
-
-       pr_info("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
-               (unsigned long long)mtd->size, mtd->erasesize,
-               mtd->writesize, mtd->oobsize);
-
-       subsize  = mtd->writesize >> mtd->subpage_sft;
-       subcount = mtd->writesize / subsize;
-
-       pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize);
-
-       offset     = page_offset * mtd->writesize;
-       eraseblock = mtd_div_by_eb(offset, mtd);
-
-       pr_info("Using page=%u, offset=%llu, eraseblock=%u\n",
-               page_offset, offset, eraseblock);
-
-       wbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
-       if (!wbuffer) {
-               err = -ENOMEM;
-               goto exit_wbuffer;
-       }
-
-       rbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
-       if (!rbuffer) {
-               err = -ENOMEM;
-               goto exit_rbuffer;
-       }
-
-       err = erase_block();
-       if (err)
-               goto exit_error;
-
-       if (mode == 0)
-               err = incremental_errors_test();
-       else
-               err = overwrite_test();
-
-       if (err)
-               goto exit_error;
-
-       /* We leave the block un-erased in case of test failure. */
-       err = erase_block();
-       if (err)
-               goto exit_error;
-
-       err = -EIO;
-       pr_info("finished successfully.\n");
-       printk(KERN_INFO "==================================================\n");
-
-exit_error:
-       kfree(rbuffer);
-exit_rbuffer:
-       kfree(wbuffer);
-exit_wbuffer:
-       /* Nothing */
-exit_nand:
-       put_mtd_device(mtd);
-exit_mtddev:
-       return err;
-}
-
-static void __exit mtd_nandbiterrs_exit(void)
-{
-       return;
-}
-
-module_init(mtd_nandbiterrs_init);
-module_exit(mtd_nandbiterrs_exit);
-
-MODULE_DESCRIPTION("NAND bit error recovery test");
-MODULE_AUTHOR("Iwo Mergler");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c
deleted file mode 100644 (file)
index 3e24b37..0000000
+++ /dev/null
@@ -1,720 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Nokia Corporation
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Test OOB read and write on MTD device.
- *
- * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <asm/div64.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static struct mtd_info *mtd;
-static unsigned char *readbuf;
-static unsigned char *writebuf;
-static unsigned char *bbt;
-
-static int ebcnt;
-static int pgcnt;
-static int errcnt;
-static int use_offset;
-static int use_len;
-static int use_len_max;
-static int vary_offset;
-static struct rnd_state rnd_state;
-
-static int erase_eraseblock(int ebnum)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (err) {
-               pr_err("error %d while erasing EB %d\n", err, ebnum);
-               return err;
-       }
-
-       if (ei.state == MTD_ERASE_FAILED) {
-               pr_err("some erase error occurred at EB %d\n", ebnum);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int erase_whole_device(void)
-{
-       int err;
-       unsigned int i;
-
-       pr_info("erasing whole device\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = erase_eraseblock(i);
-               if (err)
-                       return err;
-               cond_resched();
-       }
-       pr_info("erased %u eraseblocks\n", i);
-       return 0;
-}
-
-static void do_vary_offset(void)
-{
-       use_len -= 1;
-       if (use_len < 1) {
-               use_offset += 1;
-               if (use_offset >= use_len_max)
-                       use_offset = 0;
-               use_len = use_len_max - use_offset;
-       }
-}
-
-static int write_eraseblock(int ebnum)
-{
-       int i;
-       struct mtd_oob_ops ops;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
-               prandom_bytes_state(&rnd_state, writebuf, use_len);
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = use_len;
-               ops.oobretlen = 0;
-               ops.ooboffs   = use_offset;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = writebuf;
-               err = mtd_write_oob(mtd, addr, &ops);
-               if (err || ops.oobretlen != use_len) {
-                       pr_err("error: writeoob failed at %#llx\n",
-                              (long long)addr);
-                       pr_err("error: use_len %d, use_offset %d\n",
-                              use_len, use_offset);
-                       errcnt += 1;
-                       return err ? err : -1;
-               }
-               if (vary_offset)
-                       do_vary_offset();
-       }
-
-       return err;
-}
-
-static int write_whole_device(void)
-{
-       int err;
-       unsigned int i;
-
-       pr_info("writing OOBs of whole device\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock(i);
-               if (err)
-                       return err;
-               if (i % 256 == 0)
-                       pr_info("written up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("written %u eraseblocks\n", i);
-       return 0;
-}
-
-static int verify_eraseblock(int ebnum)
-{
-       int i;
-       struct mtd_oob_ops ops;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
-               prandom_bytes_state(&rnd_state, writebuf, use_len);
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = use_len;
-               ops.oobretlen = 0;
-               ops.ooboffs   = use_offset;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = readbuf;
-               err = mtd_read_oob(mtd, addr, &ops);
-               if (err || ops.oobretlen != use_len) {
-                       pr_err("error: readoob failed at %#llx\n",
-                              (long long)addr);
-                       errcnt += 1;
-                       return err ? err : -1;
-               }
-               if (memcmp(readbuf, writebuf, use_len)) {
-                       pr_err("error: verify failed at %#llx\n",
-                              (long long)addr);
-                       errcnt += 1;
-                       if (errcnt > 1000) {
-                               pr_err("error: too many errors\n");
-                               return -1;
-                       }
-               }
-               if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
-                       int k;
-
-                       ops.mode      = MTD_OPS_AUTO_OOB;
-                       ops.len       = 0;
-                       ops.retlen    = 0;
-                       ops.ooblen    = mtd->ecclayout->oobavail;
-                       ops.oobretlen = 0;
-                       ops.ooboffs   = 0;
-                       ops.datbuf    = NULL;
-                       ops.oobbuf    = readbuf;
-                       err = mtd_read_oob(mtd, addr, &ops);
-                       if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
-                               pr_err("error: readoob failed at %#llx\n",
-                                               (long long)addr);
-                               errcnt += 1;
-                               return err ? err : -1;
-                       }
-                       if (memcmp(readbuf + use_offset, writebuf, use_len)) {
-                               pr_err("error: verify failed at %#llx\n",
-                                               (long long)addr);
-                               errcnt += 1;
-                               if (errcnt > 1000) {
-                                       pr_err("error: too many errors\n");
-                                       return -1;
-                               }
-                       }
-                       for (k = 0; k < use_offset; ++k)
-                               if (readbuf[k] != 0xff) {
-                                       pr_err("error: verify 0xff "
-                                              "failed at %#llx\n",
-                                              (long long)addr);
-                                       errcnt += 1;
-                                       if (errcnt > 1000) {
-                                               pr_err("error: too "
-                                                      "many errors\n");
-                                               return -1;
-                                       }
-                               }
-                       for (k = use_offset + use_len;
-                            k < mtd->ecclayout->oobavail; ++k)
-                               if (readbuf[k] != 0xff) {
-                                       pr_err("error: verify 0xff "
-                                              "failed at %#llx\n",
-                                              (long long)addr);
-                                       errcnt += 1;
-                                       if (errcnt > 1000) {
-                                               pr_err("error: too "
-                                                      "many errors\n");
-                                               return -1;
-                                       }
-                               }
-               }
-               if (vary_offset)
-                       do_vary_offset();
-       }
-       return err;
-}
-
-static int verify_eraseblock_in_one_go(int ebnum)
-{
-       struct mtd_oob_ops ops;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-       size_t len = mtd->ecclayout->oobavail * pgcnt;
-
-       prandom_bytes_state(&rnd_state, writebuf, len);
-       ops.mode      = MTD_OPS_AUTO_OOB;
-       ops.len       = 0;
-       ops.retlen    = 0;
-       ops.ooblen    = len;
-       ops.oobretlen = 0;
-       ops.ooboffs   = 0;
-       ops.datbuf    = NULL;
-       ops.oobbuf    = readbuf;
-       err = mtd_read_oob(mtd, addr, &ops);
-       if (err || ops.oobretlen != len) {
-               pr_err("error: readoob failed at %#llx\n",
-                      (long long)addr);
-               errcnt += 1;
-               return err ? err : -1;
-       }
-       if (memcmp(readbuf, writebuf, len)) {
-               pr_err("error: verify failed at %#llx\n",
-                      (long long)addr);
-               errcnt += 1;
-               if (errcnt > 1000) {
-                       pr_err("error: too many errors\n");
-                       return -1;
-               }
-       }
-
-       return err;
-}
-
-static int verify_all_eraseblocks(void)
-{
-       int err;
-       unsigned int i;
-
-       pr_info("verifying all eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = verify_eraseblock(i);
-               if (err)
-                       return err;
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-       return 0;
-}
-
-static int is_block_bad(int ebnum)
-{
-       int ret;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       ret = mtd_block_isbad(mtd, addr);
-       if (ret)
-               pr_info("block %d is bad\n", ebnum);
-       return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-       int i, bad = 0;
-
-       bbt = kmalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       pr_info("scanning for bad eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               bbt[i] = is_block_bad(i) ? 1 : 0;
-               if (bbt[i])
-                       bad += 1;
-               cond_resched();
-       }
-       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-       return 0;
-}
-
-static int __init mtd_oobtest_init(void)
-{
-       int err = 0;
-       unsigned int i;
-       uint64_t tmp;
-       struct mtd_oob_ops ops;
-       loff_t addr = 0, addr0;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
-               return -EINVAL;
-       }
-
-       pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->type != MTD_NANDFLASH) {
-               pr_info("this test requires NAND flash\n");
-               goto out;
-       }
-
-       tmp = mtd->size;
-       do_div(tmp, mtd->erasesize);
-       ebcnt = tmp;
-       pgcnt = mtd->erasesize / mtd->writesize;
-
-       pr_info("MTD device size %llu, eraseblock size %u, "
-              "page size %u, count of eraseblocks %u, pages per "
-              "eraseblock %u, OOB size %u\n",
-              (unsigned long long)mtd->size, mtd->erasesize,
-              mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
-
-       err = -ENOMEM;
-       readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!readbuf) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-       writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-
-       err = scan_for_bad_eraseblocks();
-       if (err)
-               goto out;
-
-       use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
-       vary_offset = 0;
-
-       /* First test: write all OOB, read it back and verify */
-       pr_info("test 1 of 5\n");
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       prandom_seed_state(&rnd_state, 1);
-       err = write_whole_device();
-       if (err)
-               goto out;
-
-       prandom_seed_state(&rnd_state, 1);
-       err = verify_all_eraseblocks();
-       if (err)
-               goto out;
-
-       /*
-        * Second test: write all OOB, a block at a time, read it back and
-        * verify.
-        */
-       pr_info("test 2 of 5\n");
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       prandom_seed_state(&rnd_state, 3);
-       err = write_whole_device();
-       if (err)
-               goto out;
-
-       /* Check all eraseblocks */
-       prandom_seed_state(&rnd_state, 3);
-       pr_info("verifying all eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = verify_eraseblock_in_one_go(i);
-               if (err)
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-
-       /*
-        * Third test: write OOB at varying offsets and lengths, read it back
-        * and verify.
-        */
-       pr_info("test 3 of 5\n");
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       /* Write all eraseblocks */
-       use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
-       vary_offset = 1;
-       prandom_seed_state(&rnd_state, 5);
-
-       err = write_whole_device();
-       if (err)
-               goto out;
-
-       /* Check all eraseblocks */
-       use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
-       vary_offset = 1;
-       prandom_seed_state(&rnd_state, 5);
-       err = verify_all_eraseblocks();
-       if (err)
-               goto out;
-
-       use_offset = 0;
-       use_len = mtd->ecclayout->oobavail;
-       use_len_max = mtd->ecclayout->oobavail;
-       vary_offset = 0;
-
-       /* Fourth test: try to write off end of device */
-       pr_info("test 4 of 5\n");
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       addr0 = 0;
-       for (i = 0; i < ebcnt && bbt[i]; ++i)
-               addr0 += mtd->erasesize;
-
-       /* Attempt to write off end of OOB */
-       ops.mode      = MTD_OPS_AUTO_OOB;
-       ops.len       = 0;
-       ops.retlen    = 0;
-       ops.ooblen    = 1;
-       ops.oobretlen = 0;
-       ops.ooboffs   = mtd->ecclayout->oobavail;
-       ops.datbuf    = NULL;
-       ops.oobbuf    = writebuf;
-       pr_info("attempting to start write past end of OOB\n");
-       pr_info("an error is expected...\n");
-       err = mtd_write_oob(mtd, addr0, &ops);
-       if (err) {
-               pr_info("error occurred as expected\n");
-               err = 0;
-       } else {
-               pr_err("error: can write past end of OOB\n");
-               errcnt += 1;
-       }
-
-       /* Attempt to read off end of OOB */
-       ops.mode      = MTD_OPS_AUTO_OOB;
-       ops.len       = 0;
-       ops.retlen    = 0;
-       ops.ooblen    = 1;
-       ops.oobretlen = 0;
-       ops.ooboffs   = mtd->ecclayout->oobavail;
-       ops.datbuf    = NULL;
-       ops.oobbuf    = readbuf;
-       pr_info("attempting to start read past end of OOB\n");
-       pr_info("an error is expected...\n");
-       err = mtd_read_oob(mtd, addr0, &ops);
-       if (err) {
-               pr_info("error occurred as expected\n");
-               err = 0;
-       } else {
-               pr_err("error: can read past end of OOB\n");
-               errcnt += 1;
-       }
-
-       if (bbt[ebcnt - 1])
-               pr_info("skipping end of device tests because last "
-                      "block is bad\n");
-       else {
-               /* Attempt to write off end of device */
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail + 1;
-               ops.oobretlen = 0;
-               ops.ooboffs   = 0;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = writebuf;
-               pr_info("attempting to write past end of device\n");
-               pr_info("an error is expected...\n");
-               err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
-               if (err) {
-                       pr_info("error occurred as expected\n");
-                       err = 0;
-               } else {
-                       pr_err("error: wrote past end of device\n");
-                       errcnt += 1;
-               }
-
-               /* Attempt to read off end of device */
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail + 1;
-               ops.oobretlen = 0;
-               ops.ooboffs   = 0;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = readbuf;
-               pr_info("attempting to read past end of device\n");
-               pr_info("an error is expected...\n");
-               err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
-               if (err) {
-                       pr_info("error occurred as expected\n");
-                       err = 0;
-               } else {
-                       pr_err("error: read past end of device\n");
-                       errcnt += 1;
-               }
-
-               err = erase_eraseblock(ebcnt - 1);
-               if (err)
-                       goto out;
-
-               /* Attempt to write off end of device */
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail;
-               ops.oobretlen = 0;
-               ops.ooboffs   = 1;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = writebuf;
-               pr_info("attempting to write past end of device\n");
-               pr_info("an error is expected...\n");
-               err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
-               if (err) {
-                       pr_info("error occurred as expected\n");
-                       err = 0;
-               } else {
-                       pr_err("error: wrote past end of device\n");
-                       errcnt += 1;
-               }
-
-               /* Attempt to read off end of device */
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail;
-               ops.oobretlen = 0;
-               ops.ooboffs   = 1;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = readbuf;
-               pr_info("attempting to read past end of device\n");
-               pr_info("an error is expected...\n");
-               err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
-               if (err) {
-                       pr_info("error occurred as expected\n");
-                       err = 0;
-               } else {
-                       pr_err("error: read past end of device\n");
-                       errcnt += 1;
-               }
-       }
-
-       /* Fifth test: write / read across block boundaries */
-       pr_info("test 5 of 5\n");
-
-       /* Erase all eraseblocks */
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       /* Write all eraseblocks */
-       prandom_seed_state(&rnd_state, 11);
-       pr_info("writing OOBs of whole device\n");
-       for (i = 0; i < ebcnt - 1; ++i) {
-               int cnt = 2;
-               int pg;
-               size_t sz = mtd->ecclayout->oobavail;
-               if (bbt[i] || bbt[i + 1])
-                       continue;
-               addr = (i + 1) * mtd->erasesize - mtd->writesize;
-               for (pg = 0; pg < cnt; ++pg) {
-                       prandom_bytes_state(&rnd_state, writebuf, sz);
-                       ops.mode      = MTD_OPS_AUTO_OOB;
-                       ops.len       = 0;
-                       ops.retlen    = 0;
-                       ops.ooblen    = sz;
-                       ops.oobretlen = 0;
-                       ops.ooboffs   = 0;
-                       ops.datbuf    = NULL;
-                       ops.oobbuf    = writebuf;
-                       err = mtd_write_oob(mtd, addr, &ops);
-                       if (err)
-                               goto out;
-                       if (i % 256 == 0)
-                               pr_info("written up to eraseblock %u\n", i);
-                       cond_resched();
-                       addr += mtd->writesize;
-               }
-       }
-       pr_info("written %u eraseblocks\n", i);
-
-       /* Check all eraseblocks */
-       prandom_seed_state(&rnd_state, 11);
-       pr_info("verifying all eraseblocks\n");
-       for (i = 0; i < ebcnt - 1; ++i) {
-               if (bbt[i] || bbt[i + 1])
-                       continue;
-               prandom_bytes_state(&rnd_state, writebuf,
-                                       mtd->ecclayout->oobavail * 2);
-               addr = (i + 1) * mtd->erasesize - mtd->writesize;
-               ops.mode      = MTD_OPS_AUTO_OOB;
-               ops.len       = 0;
-               ops.retlen    = 0;
-               ops.ooblen    = mtd->ecclayout->oobavail * 2;
-               ops.oobretlen = 0;
-               ops.ooboffs   = 0;
-               ops.datbuf    = NULL;
-               ops.oobbuf    = readbuf;
-               err = mtd_read_oob(mtd, addr, &ops);
-               if (err)
-                       goto out;
-               if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
-                       pr_err("error: verify failed at %#llx\n",
-                              (long long)addr);
-                       errcnt += 1;
-                       if (errcnt > 1000) {
-                               pr_err("error: too many errors\n");
-                               goto out;
-                       }
-               }
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-
-       pr_info("finished with %d errors\n", errcnt);
-out:
-       kfree(bbt);
-       kfree(writebuf);
-       kfree(readbuf);
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(mtd_oobtest_init);
-
-static void __exit mtd_oobtest_exit(void)
-{
-       return;
-}
-module_exit(mtd_oobtest_exit);
-
-MODULE_DESCRIPTION("Out-of-band test module");
-MODULE_AUTHOR("Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c
deleted file mode 100644 (file)
index 0c1140b..0000000
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Nokia Corporation
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Test page read and write on MTD device.
- *
- * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <asm/div64.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static struct mtd_info *mtd;
-static unsigned char *twopages;
-static unsigned char *writebuf;
-static unsigned char *boundary;
-static unsigned char *bbt;
-
-static int pgsize;
-static int bufsize;
-static int ebcnt;
-static int pgcnt;
-static int errcnt;
-static struct rnd_state rnd_state;
-
-static int erase_eraseblock(int ebnum)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (err) {
-               pr_err("error %d while erasing EB %d\n", err, ebnum);
-               return err;
-       }
-
-       if (ei.state == MTD_ERASE_FAILED) {
-               pr_err("some erase error occurred at EB %d\n",
-                      ebnum);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int write_eraseblock(int ebnum)
-{
-       int err = 0;
-       size_t written;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
-       cond_resched();
-       err = mtd_write(mtd, addr, mtd->erasesize, &written, writebuf);
-       if (err || written != mtd->erasesize)
-               pr_err("error: write failed at %#llx\n",
-                      (long long)addr);
-
-       return err;
-}
-
-static int verify_eraseblock(int ebnum)
-{
-       uint32_t j;
-       size_t read;
-       int err = 0, i;
-       loff_t addr0, addrn;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       addr0 = 0;
-       for (i = 0; i < ebcnt && bbt[i]; ++i)
-               addr0 += mtd->erasesize;
-
-       addrn = mtd->size;
-       for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
-               addrn -= mtd->erasesize;
-
-       prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
-       for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
-               /* Do a read to set the internal dataRAMs to different data */
-               err = mtd_read(mtd, addr0, bufsize, &read, twopages);
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != bufsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr0);
-                       return err;
-               }
-               err = mtd_read(mtd, addrn - bufsize, bufsize, &read, twopages);
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != bufsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)(addrn - bufsize));
-                       return err;
-               }
-               memset(twopages, 0, bufsize);
-               err = mtd_read(mtd, addr, bufsize, &read, twopages);
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != bufsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr);
-                       break;
-               }
-               if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
-                       pr_err("error: verify failed at %#llx\n",
-                              (long long)addr);
-                       errcnt += 1;
-               }
-       }
-       /* Check boundary between eraseblocks */
-       if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
-               struct rnd_state old_state = rnd_state;
-
-               /* Do a read to set the internal dataRAMs to different data */
-               err = mtd_read(mtd, addr0, bufsize, &read, twopages);
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != bufsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr0);
-                       return err;
-               }
-               err = mtd_read(mtd, addrn - bufsize, bufsize, &read, twopages);
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != bufsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)(addrn - bufsize));
-                       return err;
-               }
-               memset(twopages, 0, bufsize);
-               err = mtd_read(mtd, addr, bufsize, &read, twopages);
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != bufsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr);
-                       return err;
-               }
-               memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
-               prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
-               if (memcmp(twopages, boundary, bufsize)) {
-                       pr_err("error: verify failed at %#llx\n",
-                              (long long)addr);
-                       errcnt += 1;
-               }
-               rnd_state = old_state;
-       }
-       return err;
-}
-
-static int crosstest(void)
-{
-       size_t read;
-       int err = 0, i;
-       loff_t addr, addr0, addrn;
-       unsigned char *pp1, *pp2, *pp3, *pp4;
-
-       pr_info("crosstest\n");
-       pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
-       if (!pp1) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-       pp2 = pp1 + pgsize;
-       pp3 = pp2 + pgsize;
-       pp4 = pp3 + pgsize;
-       memset(pp1, 0, pgsize * 4);
-
-       addr0 = 0;
-       for (i = 0; i < ebcnt && bbt[i]; ++i)
-               addr0 += mtd->erasesize;
-
-       addrn = mtd->size;
-       for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
-               addrn -= mtd->erasesize;
-
-       /* Read 2nd-to-last page to pp1 */
-       addr = addrn - pgsize - pgsize;
-       err = mtd_read(mtd, addr, pgsize, &read, pp1);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr);
-               kfree(pp1);
-               return err;
-       }
-
-       /* Read 3rd-to-last page to pp1 */
-       addr = addrn - pgsize - pgsize - pgsize;
-       err = mtd_read(mtd, addr, pgsize, &read, pp1);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr);
-               kfree(pp1);
-               return err;
-       }
-
-       /* Read first page to pp2 */
-       addr = addr0;
-       pr_info("reading page at %#llx\n", (long long)addr);
-       err = mtd_read(mtd, addr, pgsize, &read, pp2);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr);
-               kfree(pp1);
-               return err;
-       }
-
-       /* Read last page to pp3 */
-       addr = addrn - pgsize;
-       pr_info("reading page at %#llx\n", (long long)addr);
-       err = mtd_read(mtd, addr, pgsize, &read, pp3);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr);
-               kfree(pp1);
-               return err;
-       }
-
-       /* Read first page again to pp4 */
-       addr = addr0;
-       pr_info("reading page at %#llx\n", (long long)addr);
-       err = mtd_read(mtd, addr, pgsize, &read, pp4);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr);
-               kfree(pp1);
-               return err;
-       }
-
-       /* pp2 and pp4 should be the same */
-       pr_info("verifying pages read at %#llx match\n",
-              (long long)addr0);
-       if (memcmp(pp2, pp4, pgsize)) {
-               pr_err("verify failed!\n");
-               errcnt += 1;
-       } else if (!err)
-               pr_info("crosstest ok\n");
-       kfree(pp1);
-       return err;
-}
-
-static int erasecrosstest(void)
-{
-       size_t read, written;
-       int err = 0, i, ebnum, ebnum2;
-       loff_t addr0;
-       char *readbuf = twopages;
-
-       pr_info("erasecrosstest\n");
-
-       ebnum = 0;
-       addr0 = 0;
-       for (i = 0; i < ebcnt && bbt[i]; ++i) {
-               addr0 += mtd->erasesize;
-               ebnum += 1;
-       }
-
-       ebnum2 = ebcnt - 1;
-       while (ebnum2 && bbt[ebnum2])
-               ebnum2 -= 1;
-
-       pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(ebnum);
-       if (err)
-               return err;
-
-       pr_info("writing 1st page of block %d\n", ebnum);
-       prandom_bytes_state(&rnd_state, writebuf, pgsize);
-       strcpy(writebuf, "There is no data like this!");
-       err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
-       if (err || written != pgsize) {
-               pr_info("error: write failed at %#llx\n",
-                      (long long)addr0);
-               return err ? err : -1;
-       }
-
-       pr_info("reading 1st page of block %d\n", ebnum);
-       memset(readbuf, 0, pgsize);
-       err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr0);
-               return err ? err : -1;
-       }
-
-       pr_info("verifying 1st page of block %d\n", ebnum);
-       if (memcmp(writebuf, readbuf, pgsize)) {
-               pr_err("verify failed!\n");
-               errcnt += 1;
-               return -1;
-       }
-
-       pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(ebnum);
-       if (err)
-               return err;
-
-       pr_info("writing 1st page of block %d\n", ebnum);
-       prandom_bytes_state(&rnd_state, writebuf, pgsize);
-       strcpy(writebuf, "There is no data like this!");
-       err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
-       if (err || written != pgsize) {
-               pr_err("error: write failed at %#llx\n",
-                      (long long)addr0);
-               return err ? err : -1;
-       }
-
-       pr_info("erasing block %d\n", ebnum2);
-       err = erase_eraseblock(ebnum2);
-       if (err)
-               return err;
-
-       pr_info("reading 1st page of block %d\n", ebnum);
-       memset(readbuf, 0, pgsize);
-       err = mtd_read(mtd, addr0, pgsize, &read, readbuf);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr0);
-               return err ? err : -1;
-       }
-
-       pr_info("verifying 1st page of block %d\n", ebnum);
-       if (memcmp(writebuf, readbuf, pgsize)) {
-               pr_err("verify failed!\n");
-               errcnt += 1;
-               return -1;
-       }
-
-       if (!err)
-               pr_info("erasecrosstest ok\n");
-       return err;
-}
-
-static int erasetest(void)
-{
-       size_t read, written;
-       int err = 0, i, ebnum, ok = 1;
-       loff_t addr0;
-
-       pr_info("erasetest\n");
-
-       ebnum = 0;
-       addr0 = 0;
-       for (i = 0; i < ebcnt && bbt[i]; ++i) {
-               addr0 += mtd->erasesize;
-               ebnum += 1;
-       }
-
-       pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(ebnum);
-       if (err)
-               return err;
-
-       pr_info("writing 1st page of block %d\n", ebnum);
-       prandom_bytes_state(&rnd_state, writebuf, pgsize);
-       err = mtd_write(mtd, addr0, pgsize, &written, writebuf);
-       if (err || written != pgsize) {
-               pr_err("error: write failed at %#llx\n",
-                      (long long)addr0);
-               return err ? err : -1;
-       }
-
-       pr_info("erasing block %d\n", ebnum);
-       err = erase_eraseblock(ebnum);
-       if (err)
-               return err;
-
-       pr_info("reading 1st page of block %d\n", ebnum);
-       err = mtd_read(mtd, addr0, pgsize, &read, twopages);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != pgsize) {
-               pr_err("error: read failed at %#llx\n",
-                      (long long)addr0);
-               return err ? err : -1;
-       }
-
-       pr_info("verifying 1st page of block %d is all 0xff\n",
-              ebnum);
-       for (i = 0; i < pgsize; ++i)
-               if (twopages[i] != 0xff) {
-                       pr_err("verifying all 0xff failed at %d\n",
-                              i);
-                       errcnt += 1;
-                       ok = 0;
-                       break;
-               }
-
-       if (ok && !err)
-               pr_info("erasetest ok\n");
-
-       return err;
-}
-
-static int is_block_bad(int ebnum)
-{
-       loff_t addr = ebnum * mtd->erasesize;
-       int ret;
-
-       ret = mtd_block_isbad(mtd, addr);
-       if (ret)
-               pr_info("block %d is bad\n", ebnum);
-       return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-       int i, bad = 0;
-
-       bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       pr_info("scanning for bad eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               bbt[i] = is_block_bad(i) ? 1 : 0;
-               if (bbt[i])
-                       bad += 1;
-               cond_resched();
-       }
-       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-       return 0;
-}
-
-static int __init mtd_pagetest_init(void)
-{
-       int err = 0;
-       uint64_t tmp;
-       uint32_t i;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
-               return -EINVAL;
-       }
-
-       pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->type != MTD_NANDFLASH) {
-               pr_info("this test requires NAND flash\n");
-               goto out;
-       }
-
-       tmp = mtd->size;
-       do_div(tmp, mtd->erasesize);
-       ebcnt = tmp;
-       pgcnt = mtd->erasesize / mtd->writesize;
-       pgsize = mtd->writesize;
-
-       pr_info("MTD device size %llu, eraseblock size %u, "
-              "page size %u, count of eraseblocks %u, pages per "
-              "eraseblock %u, OOB size %u\n",
-              (unsigned long long)mtd->size, mtd->erasesize,
-              pgsize, ebcnt, pgcnt, mtd->oobsize);
-
-       err = -ENOMEM;
-       bufsize = pgsize * 2;
-       writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-       twopages = kmalloc(bufsize, GFP_KERNEL);
-       if (!twopages) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-       boundary = kmalloc(bufsize, GFP_KERNEL);
-       if (!boundary) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-
-       err = scan_for_bad_eraseblocks();
-       if (err)
-               goto out;
-
-       /* Erase all eraseblocks */
-       pr_info("erasing whole device\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = erase_eraseblock(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       pr_info("erased %u eraseblocks\n", i);
-
-       /* Write all eraseblocks */
-       prandom_seed_state(&rnd_state, 1);
-       pr_info("writing whole device\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock(i);
-               if (err)
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("written up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("written %u eraseblocks\n", i);
-
-       /* Check all eraseblocks */
-       prandom_seed_state(&rnd_state, 1);
-       pr_info("verifying all eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = verify_eraseblock(i);
-               if (err)
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-
-       err = crosstest();
-       if (err)
-               goto out;
-
-       err = erasecrosstest();
-       if (err)
-               goto out;
-
-       err = erasetest();
-       if (err)
-               goto out;
-
-       pr_info("finished with %d errors\n", errcnt);
-out:
-
-       kfree(bbt);
-       kfree(boundary);
-       kfree(twopages);
-       kfree(writebuf);
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(mtd_pagetest_init);
-
-static void __exit mtd_pagetest_exit(void)
-{
-       return;
-}
-module_exit(mtd_pagetest_exit);
-
-MODULE_DESCRIPTION("NAND page test");
-MODULE_AUTHOR("Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c
deleted file mode 100644 (file)
index 266de04..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Nokia Corporation
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Check MTD device read.
- *
- * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static struct mtd_info *mtd;
-static unsigned char *iobuf;
-static unsigned char *iobuf1;
-static unsigned char *bbt;
-
-static int pgsize;
-static int ebcnt;
-static int pgcnt;
-
-static int read_eraseblock_by_page(int ebnum)
-{
-       size_t read;
-       int i, ret, err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-       void *buf = iobuf;
-       void *oobbuf = iobuf1;
-
-       for (i = 0; i < pgcnt; i++) {
-               memset(buf, 0 , pgsize);
-               ret = mtd_read(mtd, addr, pgsize, &read, buf);
-               if (ret == -EUCLEAN)
-                       ret = 0;
-               if (ret || read != pgsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr);
-                       if (!err)
-                               err = ret;
-                       if (!err)
-                               err = -EINVAL;
-               }
-               if (mtd->oobsize) {
-                       struct mtd_oob_ops ops;
-
-                       ops.mode      = MTD_OPS_PLACE_OOB;
-                       ops.len       = 0;
-                       ops.retlen    = 0;
-                       ops.ooblen    = mtd->oobsize;
-                       ops.oobretlen = 0;
-                       ops.ooboffs   = 0;
-                       ops.datbuf    = NULL;
-                       ops.oobbuf    = oobbuf;
-                       ret = mtd_read_oob(mtd, addr, &ops);
-                       if ((ret && !mtd_is_bitflip(ret)) ||
-                                       ops.oobretlen != mtd->oobsize) {
-                               pr_err("error: read oob failed at "
-                                                 "%#llx\n", (long long)addr);
-                               if (!err)
-                                       err = ret;
-                               if (!err)
-                                       err = -EINVAL;
-                       }
-                       oobbuf += mtd->oobsize;
-               }
-               addr += pgsize;
-               buf += pgsize;
-       }
-
-       return err;
-}
-
-static void dump_eraseblock(int ebnum)
-{
-       int i, j, n;
-       char line[128];
-       int pg, oob;
-
-       pr_info("dumping eraseblock %d\n", ebnum);
-       n = mtd->erasesize;
-       for (i = 0; i < n;) {
-               char *p = line;
-
-               p += sprintf(p, "%05x: ", i);
-               for (j = 0; j < 32 && i < n; j++, i++)
-                       p += sprintf(p, "%02x", (unsigned int)iobuf[i]);
-               printk(KERN_CRIT "%s\n", line);
-               cond_resched();
-       }
-       if (!mtd->oobsize)
-               return;
-       pr_info("dumping oob from eraseblock %d\n", ebnum);
-       n = mtd->oobsize;
-       for (pg = 0, i = 0; pg < pgcnt; pg++)
-               for (oob = 0; oob < n;) {
-                       char *p = line;
-
-                       p += sprintf(p, "%05x: ", i);
-                       for (j = 0; j < 32 && oob < n; j++, oob++, i++)
-                               p += sprintf(p, "%02x",
-                                            (unsigned int)iobuf1[i]);
-                       printk(KERN_CRIT "%s\n", line);
-                       cond_resched();
-               }
-}
-
-static int is_block_bad(int ebnum)
-{
-       loff_t addr = ebnum * mtd->erasesize;
-       int ret;
-
-       ret = mtd_block_isbad(mtd, addr);
-       if (ret)
-               pr_info("block %d is bad\n", ebnum);
-       return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-       int i, bad = 0;
-
-       bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       if (!mtd_can_have_bb(mtd))
-               return 0;
-
-       pr_info("scanning for bad eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               bbt[i] = is_block_bad(i) ? 1 : 0;
-               if (bbt[i])
-                       bad += 1;
-               cond_resched();
-       }
-       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-       return 0;
-}
-
-static int __init mtd_readtest_init(void)
-{
-       uint64_t tmp;
-       int err, i;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               return -EINVAL;
-       }
-
-       pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: Cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->writesize == 1) {
-               pr_info("not NAND flash, assume page size is 512 "
-                      "bytes.\n");
-               pgsize = 512;
-       } else
-               pgsize = mtd->writesize;
-
-       tmp = mtd->size;
-       do_div(tmp, mtd->erasesize);
-       ebcnt = tmp;
-       pgcnt = mtd->erasesize / pgsize;
-
-       pr_info("MTD device size %llu, eraseblock size %u, "
-              "page size %u, count of eraseblocks %u, pages per "
-              "eraseblock %u, OOB size %u\n",
-              (unsigned long long)mtd->size, mtd->erasesize,
-              pgsize, ebcnt, pgcnt, mtd->oobsize);
-
-       err = -ENOMEM;
-       iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-       iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf1) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-
-       err = scan_for_bad_eraseblocks();
-       if (err)
-               goto out;
-
-       /* Read all eraseblocks 1 page at a time */
-       pr_info("testing page read\n");
-       for (i = 0; i < ebcnt; ++i) {
-               int ret;
-
-               if (bbt[i])
-                       continue;
-               ret = read_eraseblock_by_page(i);
-               if (ret) {
-                       dump_eraseblock(i);
-                       if (!err)
-                               err = ret;
-               }
-               cond_resched();
-       }
-
-       if (err)
-               pr_info("finished with errors\n");
-       else
-               pr_info("finished\n");
-
-out:
-
-       kfree(iobuf);
-       kfree(iobuf1);
-       kfree(bbt);
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(mtd_readtest_init);
-
-static void __exit mtd_readtest_exit(void)
-{
-       return;
-}
-module_exit(mtd_readtest_exit);
-
-MODULE_DESCRIPTION("Read test module");
-MODULE_AUTHOR("Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c
deleted file mode 100644 (file)
index a6ce9c1..0000000
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright (C) 2007 Nokia Corporation
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Test read and write speed of a MTD device.
- *
- * Author: Adrian Hunter <adrian.hunter@nokia.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static int count;
-module_param(count, int, S_IRUGO);
-MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
-                       "(0 means use all)");
-
-static struct mtd_info *mtd;
-static unsigned char *iobuf;
-static unsigned char *bbt;
-
-static int pgsize;
-static int ebcnt;
-static int pgcnt;
-static int goodebcnt;
-static struct timeval start, finish;
-
-
-static int erase_eraseblock(int ebnum)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (err) {
-               pr_err("error %d while erasing EB %d\n", err, ebnum);
-               return err;
-       }
-
-       if (ei.state == MTD_ERASE_FAILED) {
-               pr_err("some erase error occurred at EB %d\n",
-                      ebnum);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int multiblock_erase(int ebnum, int blocks)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize * blocks;
-
-       err = mtd_erase(mtd, &ei);
-       if (err) {
-               pr_err("error %d while erasing EB %d, blocks %d\n",
-                      err, ebnum, blocks);
-               return err;
-       }
-
-       if (ei.state == MTD_ERASE_FAILED) {
-               pr_err("some erase error occurred at EB %d,"
-                      "blocks %d\n", ebnum, blocks);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int erase_whole_device(void)
-{
-       int err;
-       unsigned int i;
-
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = erase_eraseblock(i);
-               if (err)
-                       return err;
-               cond_resched();
-       }
-       return 0;
-}
-
-static int write_eraseblock(int ebnum)
-{
-       size_t written;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       err = mtd_write(mtd, addr, mtd->erasesize, &written, iobuf);
-       if (err || written != mtd->erasesize) {
-               pr_err("error: write failed at %#llx\n", addr);
-               if (!err)
-                       err = -EINVAL;
-       }
-
-       return err;
-}
-
-static int write_eraseblock_by_page(int ebnum)
-{
-       size_t written;
-       int i, err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-       void *buf = iobuf;
-
-       for (i = 0; i < pgcnt; i++) {
-               err = mtd_write(mtd, addr, pgsize, &written, buf);
-               if (err || written != pgsize) {
-                       pr_err("error: write failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
-                       break;
-               }
-               addr += pgsize;
-               buf += pgsize;
-       }
-
-       return err;
-}
-
-static int write_eraseblock_by_2pages(int ebnum)
-{
-       size_t written, sz = pgsize * 2;
-       int i, n = pgcnt / 2, err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-       void *buf = iobuf;
-
-       for (i = 0; i < n; i++) {
-               err = mtd_write(mtd, addr, sz, &written, buf);
-               if (err || written != sz) {
-                       pr_err("error: write failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
-                       return err;
-               }
-               addr += sz;
-               buf += sz;
-       }
-       if (pgcnt % 2) {
-               err = mtd_write(mtd, addr, pgsize, &written, buf);
-               if (err || written != pgsize) {
-                       pr_err("error: write failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
-               }
-       }
-
-       return err;
-}
-
-static int read_eraseblock(int ebnum)
-{
-       size_t read;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       err = mtd_read(mtd, addr, mtd->erasesize, &read, iobuf);
-       /* Ignore corrected ECC errors */
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (err || read != mtd->erasesize) {
-               pr_err("error: read failed at %#llx\n", addr);
-               if (!err)
-                       err = -EINVAL;
-       }
-
-       return err;
-}
-
-static int read_eraseblock_by_page(int ebnum)
-{
-       size_t read;
-       int i, err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-       void *buf = iobuf;
-
-       for (i = 0; i < pgcnt; i++) {
-               err = mtd_read(mtd, addr, pgsize, &read, buf);
-               /* Ignore corrected ECC errors */
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != pgsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
-                       break;
-               }
-               addr += pgsize;
-               buf += pgsize;
-       }
-
-       return err;
-}
-
-static int read_eraseblock_by_2pages(int ebnum)
-{
-       size_t read, sz = pgsize * 2;
-       int i, n = pgcnt / 2, err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-       void *buf = iobuf;
-
-       for (i = 0; i < n; i++) {
-               err = mtd_read(mtd, addr, sz, &read, buf);
-               /* Ignore corrected ECC errors */
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != sz) {
-                       pr_err("error: read failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
-                       return err;
-               }
-               addr += sz;
-               buf += sz;
-       }
-       if (pgcnt % 2) {
-               err = mtd_read(mtd, addr, pgsize, &read, buf);
-               /* Ignore corrected ECC errors */
-               if (mtd_is_bitflip(err))
-                       err = 0;
-               if (err || read != pgsize) {
-                       pr_err("error: read failed at %#llx\n",
-                              addr);
-                       if (!err)
-                               err = -EINVAL;
-               }
-       }
-
-       return err;
-}
-
-static int is_block_bad(int ebnum)
-{
-       loff_t addr = ebnum * mtd->erasesize;
-       int ret;
-
-       ret = mtd_block_isbad(mtd, addr);
-       if (ret)
-               pr_info("block %d is bad\n", ebnum);
-       return ret;
-}
-
-static inline void start_timing(void)
-{
-       do_gettimeofday(&start);
-}
-
-static inline void stop_timing(void)
-{
-       do_gettimeofday(&finish);
-}
-
-static long calc_speed(void)
-{
-       uint64_t k;
-       long ms;
-
-       ms = (finish.tv_sec - start.tv_sec) * 1000 +
-            (finish.tv_usec - start.tv_usec) / 1000;
-       if (ms == 0)
-               return 0;
-       k = goodebcnt * (mtd->erasesize / 1024) * 1000;
-       do_div(k, ms);
-       return k;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-       int i, bad = 0;
-
-       bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       if (!mtd_can_have_bb(mtd))
-               goto out;
-
-       pr_info("scanning for bad eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               bbt[i] = is_block_bad(i) ? 1 : 0;
-               if (bbt[i])
-                       bad += 1;
-               cond_resched();
-       }
-       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-out:
-       goodebcnt = ebcnt - bad;
-       return 0;
-}
-
-static int __init mtd_speedtest_init(void)
-{
-       int err, i, blocks, j, k;
-       long speed;
-       uint64_t tmp;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
-               return -EINVAL;
-       }
-
-       if (count)
-               pr_info("MTD device: %d    count: %d\n", dev, count);
-       else
-               pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->writesize == 1) {
-               pr_info("not NAND flash, assume page size is 512 "
-                      "bytes.\n");
-               pgsize = 512;
-       } else
-               pgsize = mtd->writesize;
-
-       tmp = mtd->size;
-       do_div(tmp, mtd->erasesize);
-       ebcnt = tmp;
-       pgcnt = mtd->erasesize / pgsize;
-
-       pr_info("MTD device size %llu, eraseblock size %u, "
-              "page size %u, count of eraseblocks %u, pages per "
-              "eraseblock %u, OOB size %u\n",
-              (unsigned long long)mtd->size, mtd->erasesize,
-              pgsize, ebcnt, pgcnt, mtd->oobsize);
-
-       if (count > 0 && count < ebcnt)
-               ebcnt = count;
-
-       err = -ENOMEM;
-       iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!iobuf) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-
-       prandom_bytes(iobuf, mtd->erasesize);
-
-       err = scan_for_bad_eraseblocks();
-       if (err)
-               goto out;
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       /* Write all eraseblocks, 1 eraseblock at a time */
-       pr_info("testing eraseblock write speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("eraseblock write speed is %ld KiB/s\n", speed);
-
-       /* Read all eraseblocks, 1 eraseblock at a time */
-       pr_info("testing eraseblock read speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = read_eraseblock(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("eraseblock read speed is %ld KiB/s\n", speed);
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       /* Write all eraseblocks, 1 page at a time */
-       pr_info("testing page write speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock_by_page(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("page write speed is %ld KiB/s\n", speed);
-
-       /* Read all eraseblocks, 1 page at a time */
-       pr_info("testing page read speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = read_eraseblock_by_page(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("page read speed is %ld KiB/s\n", speed);
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       /* Write all eraseblocks, 2 pages at a time */
-       pr_info("testing 2 page write speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock_by_2pages(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("2 page write speed is %ld KiB/s\n", speed);
-
-       /* Read all eraseblocks, 2 pages at a time */
-       pr_info("testing 2 page read speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = read_eraseblock_by_2pages(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("2 page read speed is %ld KiB/s\n", speed);
-
-       /* Erase all eraseblocks */
-       pr_info("Testing erase speed\n");
-       start_timing();
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = erase_eraseblock(i);
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       stop_timing();
-       speed = calc_speed();
-       pr_info("erase speed is %ld KiB/s\n", speed);
-
-       /* Multi-block erase all eraseblocks */
-       for (k = 1; k < 7; k++) {
-               blocks = 1 << k;
-               pr_info("Testing %dx multi-block erase speed\n",
-                      blocks);
-               start_timing();
-               for (i = 0; i < ebcnt; ) {
-                       for (j = 0; j < blocks && (i + j) < ebcnt; j++)
-                               if (bbt[i + j])
-                                       break;
-                       if (j < 1) {
-                               i++;
-                               continue;
-                       }
-                       err = multiblock_erase(i, j);
-                       if (err)
-                               goto out;
-                       cond_resched();
-                       i += j;
-               }
-               stop_timing();
-               speed = calc_speed();
-               pr_info("%dx multi-block erase speed is %ld KiB/s\n",
-                      blocks, speed);
-       }
-       pr_info("finished\n");
-out:
-       kfree(iobuf);
-       kfree(bbt);
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(mtd_speedtest_init);
-
-static void __exit mtd_speedtest_exit(void)
-{
-       return;
-}
-module_exit(mtd_speedtest_exit);
-
-MODULE_DESCRIPTION("Speed test module");
-MODULE_AUTHOR("Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c
deleted file mode 100644 (file)
index 787f539..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Nokia Corporation
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Test random reads, writes and erases on MTD device.
- *
- * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/vmalloc.h>
-#include <linux/random.h>
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static int count = 10000;
-module_param(count, int, S_IRUGO);
-MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");
-
-static struct mtd_info *mtd;
-static unsigned char *writebuf;
-static unsigned char *readbuf;
-static unsigned char *bbt;
-static int *offsets;
-
-static int pgsize;
-static int bufsize;
-static int ebcnt;
-static int pgcnt;
-
-static int rand_eb(void)
-{
-       unsigned int eb;
-
-again:
-       eb = prandom_u32();
-       /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
-       eb %= (ebcnt - 1);
-       if (bbt[eb])
-               goto again;
-       return eb;
-}
-
-static int rand_offs(void)
-{
-       unsigned int offs;
-
-       offs = prandom_u32();
-       offs %= bufsize;
-       return offs;
-}
-
-static int rand_len(int offs)
-{
-       unsigned int len;
-
-       len = prandom_u32();
-       len %= (bufsize - offs);
-       return len;
-}
-
-static int erase_eraseblock(int ebnum)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (unlikely(err)) {
-               pr_err("error %d while erasing EB %d\n", err, ebnum);
-               return err;
-       }
-
-       if (unlikely(ei.state == MTD_ERASE_FAILED)) {
-               pr_err("some erase error occurred at EB %d\n",
-                      ebnum);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int is_block_bad(int ebnum)
-{
-       loff_t addr = ebnum * mtd->erasesize;
-       int ret;
-
-       ret = mtd_block_isbad(mtd, addr);
-       if (ret)
-               pr_info("block %d is bad\n", ebnum);
-       return ret;
-}
-
-static int do_read(void)
-{
-       size_t read;
-       int eb = rand_eb();
-       int offs = rand_offs();
-       int len = rand_len(offs), err;
-       loff_t addr;
-
-       if (bbt[eb + 1]) {
-               if (offs >= mtd->erasesize)
-                       offs -= mtd->erasesize;
-               if (offs + len > mtd->erasesize)
-                       len = mtd->erasesize - offs;
-       }
-       addr = eb * mtd->erasesize + offs;
-       err = mtd_read(mtd, addr, len, &read, readbuf);
-       if (mtd_is_bitflip(err))
-               err = 0;
-       if (unlikely(err || read != len)) {
-               pr_err("error: read failed at 0x%llx\n",
-                      (long long)addr);
-               if (!err)
-                       err = -EINVAL;
-               return err;
-       }
-       return 0;
-}
-
-static int do_write(void)
-{
-       int eb = rand_eb(), offs, err, len;
-       size_t written;
-       loff_t addr;
-
-       offs = offsets[eb];
-       if (offs >= mtd->erasesize) {
-               err = erase_eraseblock(eb);
-               if (err)
-                       return err;
-               offs = offsets[eb] = 0;
-       }
-       len = rand_len(offs);
-       len = ((len + pgsize - 1) / pgsize) * pgsize;
-       if (offs + len > mtd->erasesize) {
-               if (bbt[eb + 1])
-                       len = mtd->erasesize - offs;
-               else {
-                       err = erase_eraseblock(eb + 1);
-                       if (err)
-                               return err;
-                       offsets[eb + 1] = 0;
-               }
-       }
-       addr = eb * mtd->erasesize + offs;
-       err = mtd_write(mtd, addr, len, &written, writebuf);
-       if (unlikely(err || written != len)) {
-               pr_err("error: write failed at 0x%llx\n",
-                      (long long)addr);
-               if (!err)
-                       err = -EINVAL;
-               return err;
-       }
-       offs += len;
-       while (offs > mtd->erasesize) {
-               offsets[eb++] = mtd->erasesize;
-               offs -= mtd->erasesize;
-       }
-       offsets[eb] = offs;
-       return 0;
-}
-
-static int do_operation(void)
-{
-       if (prandom_u32() & 1)
-               return do_read();
-       else
-               return do_write();
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-       int i, bad = 0;
-
-       bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       if (!mtd_can_have_bb(mtd))
-               return 0;
-
-       pr_info("scanning for bad eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               bbt[i] = is_block_bad(i) ? 1 : 0;
-               if (bbt[i])
-                       bad += 1;
-               cond_resched();
-       }
-       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-       return 0;
-}
-
-static int __init mtd_stresstest_init(void)
-{
-       int err;
-       int i, op;
-       uint64_t tmp;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
-               return -EINVAL;
-       }
-
-       pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->writesize == 1) {
-               pr_info("not NAND flash, assume page size is 512 "
-                      "bytes.\n");
-               pgsize = 512;
-       } else
-               pgsize = mtd->writesize;
-
-       tmp = mtd->size;
-       do_div(tmp, mtd->erasesize);
-       ebcnt = tmp;
-       pgcnt = mtd->erasesize / pgsize;
-
-       pr_info("MTD device size %llu, eraseblock size %u, "
-              "page size %u, count of eraseblocks %u, pages per "
-              "eraseblock %u, OOB size %u\n",
-              (unsigned long long)mtd->size, mtd->erasesize,
-              pgsize, ebcnt, pgcnt, mtd->oobsize);
-
-       if (ebcnt < 2) {
-               pr_err("error: need at least 2 eraseblocks\n");
-               err = -ENOSPC;
-               goto out_put_mtd;
-       }
-
-       /* Read or write up 2 eraseblocks at a time */
-       bufsize = mtd->erasesize * 2;
-
-       err = -ENOMEM;
-       readbuf = vmalloc(bufsize);
-       writebuf = vmalloc(bufsize);
-       offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
-       if (!readbuf || !writebuf || !offsets) {
-               pr_err("error: cannot allocate memory\n");
-               goto out;
-       }
-       for (i = 0; i < ebcnt; i++)
-               offsets[i] = mtd->erasesize;
-       prandom_bytes(writebuf, bufsize);
-
-       err = scan_for_bad_eraseblocks();
-       if (err)
-               goto out;
-
-       /* Do operations */
-       pr_info("doing operations\n");
-       for (op = 0; op < count; op++) {
-               if ((op & 1023) == 0)
-                       pr_info("%d operations done\n", op);
-               err = do_operation();
-               if (err)
-                       goto out;
-               cond_resched();
-       }
-       pr_info("finished, %d operations done\n", op);
-
-out:
-       kfree(offsets);
-       kfree(bbt);
-       vfree(writebuf);
-       vfree(readbuf);
-out_put_mtd:
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(mtd_stresstest_init);
-
-static void __exit mtd_stresstest_exit(void)
-{
-       return;
-}
-module_exit(mtd_stresstest_exit);
-
-MODULE_DESCRIPTION("Stress test module");
-MODULE_AUTHOR("Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c
deleted file mode 100644 (file)
index aade56f..0000000
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2006-2007 Nokia Corporation
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Test sub-page read and write on MTD device.
- * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/random.h>
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static struct mtd_info *mtd;
-static unsigned char *writebuf;
-static unsigned char *readbuf;
-static unsigned char *bbt;
-
-static int subpgsize;
-static int bufsize;
-static int ebcnt;
-static int pgcnt;
-static int errcnt;
-static struct rnd_state rnd_state;
-
-static inline void clear_data(unsigned char *buf, size_t len)
-{
-       memset(buf, 0, len);
-}
-
-static int erase_eraseblock(int ebnum)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (err) {
-               pr_err("error %d while erasing EB %d\n", err, ebnum);
-               return err;
-       }
-
-       if (ei.state == MTD_ERASE_FAILED) {
-               pr_err("some erase error occurred at EB %d\n",
-                      ebnum);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int erase_whole_device(void)
-{
-       int err;
-       unsigned int i;
-
-       pr_info("erasing whole device\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = erase_eraseblock(i);
-               if (err)
-                       return err;
-               cond_resched();
-       }
-       pr_info("erased %u eraseblocks\n", i);
-       return 0;
-}
-
-static int write_eraseblock(int ebnum)
-{
-       size_t written;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
-       err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
-       if (unlikely(err || written != subpgsize)) {
-               pr_err("error: write failed at %#llx\n",
-                      (long long)addr);
-               if (written != subpgsize) {
-                       pr_err("  write size: %#x\n", subpgsize);
-                       pr_err("  written: %#zx\n", written);
-               }
-               return err ? err : -1;
-       }
-
-       addr += subpgsize;
-
-       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
-       err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
-       if (unlikely(err || written != subpgsize)) {
-               pr_err("error: write failed at %#llx\n",
-                      (long long)addr);
-               if (written != subpgsize) {
-                       pr_err("  write size: %#x\n", subpgsize);
-                       pr_err("  written: %#zx\n", written);
-               }
-               return err ? err : -1;
-       }
-
-       return err;
-}
-
-static int write_eraseblock2(int ebnum)
-{
-       size_t written;
-       int err = 0, k;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       for (k = 1; k < 33; ++k) {
-               if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
-                       break;
-               prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
-               err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
-               if (unlikely(err || written != subpgsize * k)) {
-                       pr_err("error: write failed at %#llx\n",
-                              (long long)addr);
-                       if (written != subpgsize) {
-                               pr_err("  write size: %#x\n",
-                                      subpgsize * k);
-                               pr_err("  written: %#08zx\n",
-                                      written);
-                       }
-                       return err ? err : -1;
-               }
-               addr += subpgsize * k;
-       }
-
-       return err;
-}
-
-static void print_subpage(unsigned char *p)
-{
-       int i, j;
-
-       for (i = 0; i < subpgsize; ) {
-               for (j = 0; i < subpgsize && j < 32; ++i, ++j)
-                       printk("%02x", *p++);
-               printk("\n");
-       }
-}
-
-static int verify_eraseblock(int ebnum)
-{
-       size_t read;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
-       clear_data(readbuf, subpgsize);
-       err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
-       if (unlikely(err || read != subpgsize)) {
-               if (mtd_is_bitflip(err) && read == subpgsize) {
-                       pr_info("ECC correction at %#llx\n",
-                              (long long)addr);
-                       err = 0;
-               } else {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr);
-                       return err ? err : -1;
-               }
-       }
-       if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-               pr_err("error: verify failed at %#llx\n",
-                      (long long)addr);
-               pr_info("------------- written----------------\n");
-               print_subpage(writebuf);
-               pr_info("------------- read ------------------\n");
-               print_subpage(readbuf);
-               pr_info("-------------------------------------\n");
-               errcnt += 1;
-       }
-
-       addr += subpgsize;
-
-       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
-       clear_data(readbuf, subpgsize);
-       err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
-       if (unlikely(err || read != subpgsize)) {
-               if (mtd_is_bitflip(err) && read == subpgsize) {
-                       pr_info("ECC correction at %#llx\n",
-                              (long long)addr);
-                       err = 0;
-               } else {
-                       pr_err("error: read failed at %#llx\n",
-                              (long long)addr);
-                       return err ? err : -1;
-               }
-       }
-       if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-               pr_info("error: verify failed at %#llx\n",
-                      (long long)addr);
-               pr_info("------------- written----------------\n");
-               print_subpage(writebuf);
-               pr_info("------------- read ------------------\n");
-               print_subpage(readbuf);
-               pr_info("-------------------------------------\n");
-               errcnt += 1;
-       }
-
-       return err;
-}
-
-static int verify_eraseblock2(int ebnum)
-{
-       size_t read;
-       int err = 0, k;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       for (k = 1; k < 33; ++k) {
-               if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
-                       break;
-               prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
-               clear_data(readbuf, subpgsize * k);
-               err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
-               if (unlikely(err || read != subpgsize * k)) {
-                       if (mtd_is_bitflip(err) && read == subpgsize * k) {
-                               pr_info("ECC correction at %#llx\n",
-                                      (long long)addr);
-                               err = 0;
-                       } else {
-                               pr_err("error: read failed at "
-                                      "%#llx\n", (long long)addr);
-                               return err ? err : -1;
-                       }
-               }
-               if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
-                       pr_err("error: verify failed at %#llx\n",
-                              (long long)addr);
-                       errcnt += 1;
-               }
-               addr += subpgsize * k;
-       }
-
-       return err;
-}
-
-static int verify_eraseblock_ff(int ebnum)
-{
-       uint32_t j;
-       size_t read;
-       int err = 0;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(writebuf, 0xff, subpgsize);
-       for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
-               clear_data(readbuf, subpgsize);
-               err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
-               if (unlikely(err || read != subpgsize)) {
-                       if (mtd_is_bitflip(err) && read == subpgsize) {
-                               pr_info("ECC correction at %#llx\n",
-                                      (long long)addr);
-                               err = 0;
-                       } else {
-                               pr_err("error: read failed at "
-                                      "%#llx\n", (long long)addr);
-                               return err ? err : -1;
-                       }
-               }
-               if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
-                       pr_err("error: verify 0xff failed at "
-                              "%#llx\n", (long long)addr);
-                       errcnt += 1;
-               }
-               addr += subpgsize;
-       }
-
-       return err;
-}
-
-static int verify_all_eraseblocks_ff(void)
-{
-       int err;
-       unsigned int i;
-
-       pr_info("verifying all eraseblocks for 0xff\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = verify_eraseblock_ff(i);
-               if (err)
-                       return err;
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-       return 0;
-}
-
-static int is_block_bad(int ebnum)
-{
-       loff_t addr = ebnum * mtd->erasesize;
-       int ret;
-
-       ret = mtd_block_isbad(mtd, addr);
-       if (ret)
-               pr_info("block %d is bad\n", ebnum);
-       return ret;
-}
-
-static int scan_for_bad_eraseblocks(void)
-{
-       int i, bad = 0;
-
-       bbt = kzalloc(ebcnt, GFP_KERNEL);
-       if (!bbt) {
-               pr_err("error: cannot allocate memory\n");
-               return -ENOMEM;
-       }
-
-       pr_info("scanning for bad eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               bbt[i] = is_block_bad(i) ? 1 : 0;
-               if (bbt[i])
-                       bad += 1;
-               cond_resched();
-       }
-       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
-       return 0;
-}
-
-static int __init mtd_subpagetest_init(void)
-{
-       int err = 0;
-       uint32_t i;
-       uint64_t tmp;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
-               return -EINVAL;
-       }
-
-       pr_info("MTD device: %d\n", dev);
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->type != MTD_NANDFLASH) {
-               pr_info("this test requires NAND flash\n");
-               goto out;
-       }
-
-       subpgsize = mtd->writesize >> mtd->subpage_sft;
-       tmp = mtd->size;
-       do_div(tmp, mtd->erasesize);
-       ebcnt = tmp;
-       pgcnt = mtd->erasesize / mtd->writesize;
-
-       pr_info("MTD device size %llu, eraseblock size %u, "
-              "page size %u, subpage size %u, count of eraseblocks %u, "
-              "pages per eraseblock %u, OOB size %u\n",
-              (unsigned long long)mtd->size, mtd->erasesize,
-              mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
-
-       err = -ENOMEM;
-       bufsize = subpgsize * 32;
-       writebuf = kmalloc(bufsize, GFP_KERNEL);
-       if (!writebuf) {
-               pr_info("error: cannot allocate memory\n");
-               goto out;
-       }
-       readbuf = kmalloc(bufsize, GFP_KERNEL);
-       if (!readbuf) {
-               pr_info("error: cannot allocate memory\n");
-               goto out;
-       }
-
-       err = scan_for_bad_eraseblocks();
-       if (err)
-               goto out;
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       pr_info("writing whole device\n");
-       prandom_seed_state(&rnd_state, 1);
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock(i);
-               if (unlikely(err))
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("written up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("written %u eraseblocks\n", i);
-
-       prandom_seed_state(&rnd_state, 1);
-       pr_info("verifying all eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = verify_eraseblock(i);
-               if (unlikely(err))
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       err = verify_all_eraseblocks_ff();
-       if (err)
-               goto out;
-
-       /* Write all eraseblocks */
-       prandom_seed_state(&rnd_state, 3);
-       pr_info("writing whole device\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = write_eraseblock2(i);
-               if (unlikely(err))
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("written up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("written %u eraseblocks\n", i);
-
-       /* Check all eraseblocks */
-       prandom_seed_state(&rnd_state, 3);
-       pr_info("verifying all eraseblocks\n");
-       for (i = 0; i < ebcnt; ++i) {
-               if (bbt[i])
-                       continue;
-               err = verify_eraseblock2(i);
-               if (unlikely(err))
-                       goto out;
-               if (i % 256 == 0)
-                       pr_info("verified up to eraseblock %u\n", i);
-               cond_resched();
-       }
-       pr_info("verified %u eraseblocks\n", i);
-
-       err = erase_whole_device();
-       if (err)
-               goto out;
-
-       err = verify_all_eraseblocks_ff();
-       if (err)
-               goto out;
-
-       pr_info("finished with %d errors\n", errcnt);
-
-out:
-       kfree(bbt);
-       kfree(readbuf);
-       kfree(writebuf);
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(mtd_subpagetest_init);
-
-static void __exit mtd_subpagetest_exit(void)
-{
-       return;
-}
-module_exit(mtd_subpagetest_exit);
-
-MODULE_DESCRIPTION("Subpage test module");
-MODULE_AUTHOR("Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/mtd_test.c b/drivers/mtd/tests/mtd_test.c
new file mode 100644 (file)
index 0000000..c818a63
--- /dev/null
@@ -0,0 +1,114 @@
+#define pr_fmt(fmt) "mtd_test: " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/printk.h>
+
+#include "mtd_test.h"
+
+int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum)
+{
+       int err;
+       struct erase_info ei;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       memset(&ei, 0, sizeof(struct erase_info));
+       ei.mtd  = mtd;
+       ei.addr = addr;
+       ei.len  = mtd->erasesize;
+
+       err = mtd_erase(mtd, &ei);
+       if (err) {
+               pr_info("error %d while erasing EB %d\n", err, ebnum);
+               return err;
+       }
+
+       if (ei.state == MTD_ERASE_FAILED) {
+               pr_info("some erase error occurred at EB %d\n", ebnum);
+               return -EIO;
+       }
+       return 0;
+}
+
+static int is_block_bad(struct mtd_info *mtd, unsigned int ebnum)
+{
+       int ret;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       ret = mtd_block_isbad(mtd, addr);
+       if (ret)
+               pr_info("block %d is bad\n", ebnum);
+
+       return ret;
+}
+
+int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+                                       unsigned int eb, int ebcnt)
+{
+       int i, bad = 0;
+
+       if (!mtd_can_have_bb(mtd))
+               return 0;
+
+       pr_info("scanning for bad eraseblocks\n");
+       for (i = 0; i < ebcnt; ++i) {
+               bbt[i] = is_block_bad(mtd, eb + i) ? 1 : 0;
+               if (bbt[i])
+                       bad += 1;
+               cond_resched();
+       }
+       pr_info("scanned %d eraseblocks, %d are bad\n", i, bad);
+
+       return 0;
+}
+
+int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+                               unsigned int eb, int ebcnt)
+{
+       int err;
+       unsigned int i;
+
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = mtdtest_erase_eraseblock(mtd, eb + i);
+               if (err)
+                       return err;
+               cond_resched();
+       }
+
+       return 0;
+}
+
+int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf)
+{
+       size_t read;
+       int err;
+
+       err = mtd_read(mtd, addr, size, &read, buf);
+       /* Ignore corrected ECC errors */
+       if (mtd_is_bitflip(err))
+               err = 0;
+       if (!err && read != size)
+               err = -EIO;
+       if (err)
+               pr_err("error: read failed at %#llx\n", addr);
+
+       return err;
+}
+
+int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
+               const void *buf)
+{
+       size_t written;
+       int err;
+
+       err = mtd_write(mtd, addr, size, &written, buf);
+       if (!err && written != size)
+               err = -EIO;
+       if (err)
+               pr_err("error: write failed at %#llx\n", addr);
+
+       return err;
+}
diff --git a/drivers/mtd/tests/mtd_test.h b/drivers/mtd/tests/mtd_test.h
new file mode 100644 (file)
index 0000000..f437c77
--- /dev/null
@@ -0,0 +1,11 @@
+#include <linux/mtd/mtd.h>
+
+int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum);
+int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+                                       unsigned int eb, int ebcnt);
+int mtdtest_erase_good_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,
+                               unsigned int eb, int ebcnt);
+
+int mtdtest_read(struct mtd_info *mtd, loff_t addr, size_t size, void *buf);
+int mtdtest_write(struct mtd_info *mtd, loff_t addr, size_t size,
+               const void *buf);
diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c
deleted file mode 100644 (file)
index 3a9f6a6..0000000
+++ /dev/null
@@ -1,535 +0,0 @@
-/*
- * Copyright (C) 2006-2008 Artem Bityutskiy
- * Copyright (C) 2006-2008 Jarkko Lavinen
- * Copyright (C) 2006-2008 Adrian Hunter
- *
- * 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; see the file COPYING. If not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter
- *
- * WARNING: this test program may kill your flash and your device. Do not
- * use it unless you know what you do. Authors are not responsible for any
- * damage caused by this program.
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/err.h>
-#include <linux/mtd/mtd.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-
-#define RETRIES 3
-
-static int eb = 8;
-module_param(eb, int, S_IRUGO);
-MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");
-
-static int ebcnt = 32;
-module_param(ebcnt, int, S_IRUGO);
-MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");
-
-static int pgcnt;
-module_param(pgcnt, int, S_IRUGO);
-MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");
-
-static int dev = -EINVAL;
-module_param(dev, int, S_IRUGO);
-MODULE_PARM_DESC(dev, "MTD device number to use");
-
-static int gran = 512;
-module_param(gran, int, S_IRUGO);
-MODULE_PARM_DESC(gran, "how often the status information should be printed");
-
-static int check = 1;
-module_param(check, int, S_IRUGO);
-MODULE_PARM_DESC(check, "if the written data should be checked");
-
-static unsigned int cycles_count;
-module_param(cycles_count, uint, S_IRUGO);
-MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
-                              "(infinite by default)");
-
-static struct mtd_info *mtd;
-
-/* This buffer contains 0x555555...0xAAAAAA... pattern */
-static unsigned char *patt_5A5;
-/* This buffer contains 0xAAAAAA...0x555555... pattern */
-static unsigned char *patt_A5A;
-/* This buffer contains all 0xFF bytes */
-static unsigned char *patt_FF;
-/* This a temporary buffer is use when checking data */
-static unsigned char *check_buf;
-/* How many erase cycles were done */
-static unsigned int erase_cycles;
-
-static int pgsize;
-static struct timeval start, finish;
-
-static void report_corrupt(unsigned char *read, unsigned char *written);
-
-static inline void start_timing(void)
-{
-       do_gettimeofday(&start);
-}
-
-static inline void stop_timing(void)
-{
-       do_gettimeofday(&finish);
-}
-
-/*
- * Erase eraseblock number @ebnum.
- */
-static inline int erase_eraseblock(int ebnum)
-{
-       int err;
-       struct erase_info ei;
-       loff_t addr = ebnum * mtd->erasesize;
-
-       memset(&ei, 0, sizeof(struct erase_info));
-       ei.mtd  = mtd;
-       ei.addr = addr;
-       ei.len  = mtd->erasesize;
-
-       err = mtd_erase(mtd, &ei);
-       if (err) {
-               pr_err("error %d while erasing EB %d\n", err, ebnum);
-               return err;
-       }
-
-       if (ei.state == MTD_ERASE_FAILED) {
-               pr_err("some erase error occurred at EB %d\n",
-                      ebnum);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*
- * Check that the contents of eraseblock number @enbum is equivalent to the
- * @buf buffer.
- */
-static inline int check_eraseblock(int ebnum, unsigned char *buf)
-{
-       int err, retries = 0;
-       size_t read;
-       loff_t addr = ebnum * mtd->erasesize;
-       size_t len = mtd->erasesize;
-
-       if (pgcnt) {
-               addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
-               len = pgcnt * pgsize;
-       }
-
-retry:
-       err = mtd_read(mtd, addr, len, &read, check_buf);
-       if (mtd_is_bitflip(err))
-               pr_err("single bit flip occurred at EB %d "
-                      "MTD reported that it was fixed.\n", ebnum);
-       else if (err) {
-               pr_err("error %d while reading EB %d, "
-                      "read %zd\n", err, ebnum, read);
-               return err;
-       }
-
-       if (read != len) {
-               pr_err("failed to read %zd bytes from EB %d, "
-                      "read only %zd, but no error reported\n",
-                      len, ebnum, read);
-               return -EIO;
-       }
-
-       if (memcmp(buf, check_buf, len)) {
-               pr_err("read wrong data from EB %d\n", ebnum);
-               report_corrupt(check_buf, buf);
-
-               if (retries++ < RETRIES) {
-                       /* Try read again */
-                       yield();
-                       pr_info("re-try reading data from EB %d\n",
-                              ebnum);
-                       goto retry;
-               } else {
-                       pr_info("retried %d times, still errors, "
-                              "give-up\n", RETRIES);
-                       return -EINVAL;
-               }
-       }
-
-       if (retries != 0)
-               pr_info("only attempt number %d was OK (!!!)\n",
-                      retries);
-
-       return 0;
-}
-
-static inline int write_pattern(int ebnum, void *buf)
-{
-       int err;
-       size_t written;
-       loff_t addr = ebnum * mtd->erasesize;
-       size_t len = mtd->erasesize;
-
-       if (pgcnt) {
-               addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
-               len = pgcnt * pgsize;
-       }
-       err = mtd_write(mtd, addr, len, &written, buf);
-       if (err) {
-               pr_err("error %d while writing EB %d, written %zd"
-                     " bytes\n", err, ebnum, written);
-               return err;
-       }
-       if (written != len) {
-               pr_info("written only %zd bytes of %zd, but no error"
-                      " reported\n", written, len);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int __init tort_init(void)
-{
-       int err = 0, i, infinite = !cycles_count;
-       int *bad_ebs;
-
-       printk(KERN_INFO "\n");
-       printk(KERN_INFO "=================================================\n");
-       pr_info("Warning: this program is trying to wear out your "
-              "flash, stop it if this is not wanted.\n");
-
-       if (dev < 0) {
-               pr_info("Please specify a valid mtd-device via module parameter\n");
-               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
-               return -EINVAL;
-       }
-
-       pr_info("MTD device: %d\n", dev);
-       pr_info("torture %d eraseblocks (%d-%d) of mtd%d\n",
-              ebcnt, eb, eb + ebcnt - 1, dev);
-       if (pgcnt)
-               pr_info("torturing just %d pages per eraseblock\n",
-                       pgcnt);
-       pr_info("write verify %s\n", check ? "enabled" : "disabled");
-
-       mtd = get_mtd_device(NULL, dev);
-       if (IS_ERR(mtd)) {
-               err = PTR_ERR(mtd);
-               pr_err("error: cannot get MTD device\n");
-               return err;
-       }
-
-       if (mtd->writesize == 1) {
-               pr_info("not NAND flash, assume page size is 512 "
-                      "bytes.\n");
-               pgsize = 512;
-       } else
-               pgsize = mtd->writesize;
-
-       if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
-               pr_err("error: invalid pgcnt value %d\n", pgcnt);
-               goto out_mtd;
-       }
-
-       err = -ENOMEM;
-       patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!patt_5A5)
-               goto out_mtd;
-
-       patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!patt_A5A)
-               goto out_patt_5A5;
-
-       patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!patt_FF)
-               goto out_patt_A5A;
-
-       check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
-       if (!check_buf)
-               goto out_patt_FF;
-
-       bad_ebs = kcalloc(ebcnt, sizeof(*bad_ebs), GFP_KERNEL);
-       if (!bad_ebs)
-               goto out_check_buf;
-
-       err = 0;
-
-       /* Initialize patterns */
-       memset(patt_FF, 0xFF, mtd->erasesize);
-       for (i = 0; i < mtd->erasesize / pgsize; i++) {
-               if (!(i & 1)) {
-                       memset(patt_5A5 + i * pgsize, 0x55, pgsize);
-                       memset(patt_A5A + i * pgsize, 0xAA, pgsize);
-               } else {
-                       memset(patt_5A5 + i * pgsize, 0xAA, pgsize);
-                       memset(patt_A5A + i * pgsize, 0x55, pgsize);
-               }
-       }
-
-       /*
-        * Check if there is a bad eraseblock among those we are going to test.
-        */
-       if (mtd_can_have_bb(mtd)) {
-               for (i = eb; i < eb + ebcnt; i++) {
-                       err = mtd_block_isbad(mtd, (loff_t)i * mtd->erasesize);
-
-                       if (err < 0) {
-                               pr_info("block_isbad() returned %d "
-                                      "for EB %d\n", err, i);
-                               goto out;
-                       }
-
-                       if (err) {
-                               pr_err("EB %d is bad. Skip it.\n", i);
-                               bad_ebs[i - eb] = 1;
-                       }
-               }
-       }
-
-       start_timing();
-       while (1) {
-               int i;
-               void *patt;
-
-               /* Erase all eraseblocks */
-               for (i = eb; i < eb + ebcnt; i++) {
-                       if (bad_ebs[i - eb])
-                               continue;
-                       err = erase_eraseblock(i);
-                       if (err)
-                               goto out;
-                       cond_resched();
-               }
-
-               /* Check if the eraseblocks contain only 0xFF bytes */
-               if (check) {
-                       for (i = eb; i < eb + ebcnt; i++) {
-                               if (bad_ebs[i - eb])
-                                       continue;
-                               err = check_eraseblock(i, patt_FF);
-                               if (err) {
-                                       pr_info("verify failed"
-                                              " for 0xFF... pattern\n");
-                                       goto out;
-                               }
-                               cond_resched();
-                       }
-               }
-
-               /* Write the pattern */
-               for (i = eb; i < eb + ebcnt; i++) {
-                       if (bad_ebs[i - eb])
-                               continue;
-                       if ((eb + erase_cycles) & 1)
-                               patt = patt_5A5;
-                       else
-                               patt = patt_A5A;
-                       err = write_pattern(i, patt);
-                       if (err)
-                               goto out;
-                       cond_resched();
-               }
-
-               /* Verify what we wrote */
-               if (check) {
-                       for (i = eb; i < eb + ebcnt; i++) {
-                               if (bad_ebs[i - eb])
-                                       continue;
-                               if ((eb + erase_cycles) & 1)
-                                       patt = patt_5A5;
-                               else
-                                       patt = patt_A5A;
-                               err = check_eraseblock(i, patt);
-                               if (err) {
-                                       pr_info("verify failed for %s"
-                                              " pattern\n",
-                                              ((eb + erase_cycles) & 1) ?
-                                              "0x55AA55..." : "0xAA55AA...");
-                                       goto out;
-                               }
-                               cond_resched();
-                       }
-               }
-
-               erase_cycles += 1;
-
-               if (erase_cycles % gran == 0) {
-                       long ms;
-
-                       stop_timing();
-                       ms = (finish.tv_sec - start.tv_sec) * 1000 +
-                            (finish.tv_usec - start.tv_usec) / 1000;
-                       pr_info("%08u erase cycles done, took %lu "
-                              "milliseconds (%lu seconds)\n",
-                              erase_cycles, ms, ms / 1000);
-                       start_timing();
-               }
-
-               if (!infinite && --cycles_count == 0)
-                       break;
-       }
-out:
-
-       pr_info("finished after %u erase cycles\n",
-              erase_cycles);
-       kfree(bad_ebs);
-out_check_buf:
-       kfree(check_buf);
-out_patt_FF:
-       kfree(patt_FF);
-out_patt_A5A:
-       kfree(patt_A5A);
-out_patt_5A5:
-       kfree(patt_5A5);
-out_mtd:
-       put_mtd_device(mtd);
-       if (err)
-               pr_info("error %d occurred during torturing\n", err);
-       printk(KERN_INFO "=================================================\n");
-       return err;
-}
-module_init(tort_init);
-
-static void __exit tort_exit(void)
-{
-       return;
-}
-module_exit(tort_exit);
-
-static int countdiffs(unsigned char *buf, unsigned char *check_buf,
-                     unsigned offset, unsigned len, unsigned *bytesp,
-                     unsigned *bitsp);
-static void print_bufs(unsigned char *read, unsigned char *written, int start,
-                      int len);
-
-/*
- * Report the detailed information about how the read EB differs from what was
- * written.
- */
-static void report_corrupt(unsigned char *read, unsigned char *written)
-{
-       int i;
-       int bytes, bits, pages, first;
-       int offset, len;
-       size_t check_len = mtd->erasesize;
-
-       if (pgcnt)
-               check_len = pgcnt * pgsize;
-
-       bytes = bits = pages = 0;
-       for (i = 0; i < check_len; i += pgsize)
-               if (countdiffs(written, read, i, pgsize, &bytes,
-                              &bits) >= 0)
-                       pages++;
-
-       pr_info("verify fails on %d pages, %d bytes/%d bits\n",
-              pages, bytes, bits);
-       pr_info("The following is a list of all differences between"
-              " what was read from flash and what was expected\n");
-
-       for (i = 0; i < check_len; i += pgsize) {
-               cond_resched();
-               bytes = bits = 0;
-               first = countdiffs(written, read, i, pgsize, &bytes,
-                                  &bits);
-               if (first < 0)
-                       continue;
-
-               printk("-------------------------------------------------------"
-                      "----------------------------------\n");
-
-               pr_info("Page %zd has %d bytes/%d bits failing verify,"
-                      " starting at offset 0x%x\n",
-                      (mtd->erasesize - check_len + i) / pgsize,
-                      bytes, bits, first);
-
-               offset = first & ~0x7;
-               len = ((first + bytes) | 0x7) + 1 - offset;
-
-               print_bufs(read, written, offset, len);
-       }
-}
-
-static void print_bufs(unsigned char *read, unsigned char *written, int start,
-                      int len)
-{
-       int i = 0, j1, j2;
-       char *diff;
-
-       printk("Offset       Read                          Written\n");
-       while (i < len) {
-               printk("0x%08x: ", start + i);
-               diff = "   ";
-               for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {
-                       printk(" %02x", read[start + i + j1]);
-                       if (read[start + i + j1] != written[start + i + j1])
-                               diff = "***";
-               }
-
-               while (j1 < 8) {
-                       printk(" ");
-                       j1 += 1;
-               }
-
-               printk("  %s ", diff);
-
-               for (j2 = 0; j2 < 8 && i + j2 < len; j2++)
-                       printk(" %02x", written[start + i + j2]);
-               printk("\n");
-               i += 8;
-       }
-}
-
-/*
- * Count the number of differing bytes and bits and return the first differing
- * offset.
- */
-static int countdiffs(unsigned char *buf, unsigned char *check_buf,
-                     unsigned offset, unsigned len, unsigned *bytesp,
-                     unsigned *bitsp)
-{
-       unsigned i, bit;
-       int first = -1;
-
-       for (i = offset; i < offset + len; i++)
-               if (buf[i] != check_buf[i]) {
-                       first = i;
-                       break;
-               }
-
-       while (i < offset + len) {
-               if (buf[i] != check_buf[i]) {
-                       (*bytesp)++;
-                       bit = 1;
-                       while (bit < 256) {
-                               if ((buf[i] & bit) != (check_buf[i] & bit))
-                                       (*bitsp)++;
-                               bit <<= 1;
-                       }
-               }
-               i++;
-       }
-
-       return first;
-}
-
-MODULE_DESCRIPTION("Eraseblock torturing module");
-MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c
new file mode 100644 (file)
index 0000000..3cd3aab
--- /dev/null
@@ -0,0 +1,428 @@
+/*
+ * Copyright Â© 2012 NetCommWireless
+ * Iwo Mergler <Iwo.Mergler@netcommwireless.com.au>
+ *
+ * Test for multi-bit error recovery on a NAND page This mostly tests the
+ * ECC controller / driver.
+ *
+ * There are two test modes:
+ *
+ *     0 - artificially inserting bit errors until the ECC fails
+ *         This is the default method and fairly quick. It should
+ *         be independent of the quality of the FLASH.
+ *
+ *     1 - re-writing the same pattern repeatedly until the ECC fails.
+ *         This method relies on the physics of NAND FLASH to eventually
+ *         generate '0' bits if '1' has been written sufficient times.
+ *         Depending on the NAND, the first bit errors will appear after
+ *         1000 or more writes and then will usually snowball, reaching the
+ *         limits of the ECC quickly.
+ *
+ *         The test stops after 10000 cycles, should your FLASH be
+ *         exceptionally good and not generate bit errors before that. Try
+ *         a different page in that case.
+ *
+ * Please note that neither of these tests will significantly 'use up' any
+ * FLASH endurance. Only a maximum of two erase operations will be performed.
+ *
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mtd/mtd.h>
+#include <linux/err.h>
+#include <linux/mtd/nand.h>
+#include <linux/slab.h>
+#include "mtd_test.h"
+
+static int dev;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static unsigned page_offset;
+module_param(page_offset, uint, S_IRUGO);
+MODULE_PARM_DESC(page_offset, "Page number relative to dev start");
+
+static unsigned seed;
+module_param(seed, uint, S_IRUGO);
+MODULE_PARM_DESC(seed, "Random seed");
+
+static int mode;
+module_param(mode, int, S_IRUGO);
+MODULE_PARM_DESC(mode, "0=incremental errors, 1=overwrite test");
+
+static unsigned max_overwrite = 10000;
+
+static loff_t   offset;     /* Offset of the page we're using. */
+static unsigned eraseblock; /* Eraseblock number for our page. */
+
+/* We assume that the ECC can correct up to a certain number
+ * of biterrors per subpage. */
+static unsigned subsize;  /* Size of subpages */
+static unsigned subcount; /* Number of subpages per page */
+
+static struct mtd_info *mtd;   /* MTD device */
+
+static uint8_t *wbuffer; /* One page write / compare buffer */
+static uint8_t *rbuffer; /* One page read buffer */
+
+/* 'random' bytes from known offsets */
+static uint8_t hash(unsigned offset)
+{
+       unsigned v = offset;
+       unsigned char c;
+       v ^= 0x7f7edfd3;
+       v = v ^ (v >> 3);
+       v = v ^ (v >> 5);
+       v = v ^ (v >> 13);
+       c = v & 0xFF;
+       /* Reverse bits of result. */
+       c = (c & 0x0F) << 4 | (c & 0xF0) >> 4;
+       c = (c & 0x33) << 2 | (c & 0xCC) >> 2;
+       c = (c & 0x55) << 1 | (c & 0xAA) >> 1;
+       return c;
+}
+
+/* Writes wbuffer to page */
+static int write_page(int log)
+{
+       if (log)
+               pr_info("write_page\n");
+
+       return mtdtest_write(mtd, offset, mtd->writesize, wbuffer);
+}
+
+/* Re-writes the data area while leaving the OOB alone. */
+static int rewrite_page(int log)
+{
+       int err = 0;
+       struct mtd_oob_ops ops;
+
+       if (log)
+               pr_info("rewrite page\n");
+
+       ops.mode      = MTD_OPS_RAW; /* No ECC */
+       ops.len       = mtd->writesize;
+       ops.retlen    = 0;
+       ops.ooblen    = 0;
+       ops.oobretlen = 0;
+       ops.ooboffs   = 0;
+       ops.datbuf    = wbuffer;
+       ops.oobbuf    = NULL;
+
+       err = mtd_write_oob(mtd, offset, &ops);
+       if (err || ops.retlen != mtd->writesize) {
+               pr_err("error: write_oob failed (%d)\n", err);
+               if (!err)
+                       err = -EIO;
+       }
+
+       return err;
+}
+
+/* Reads page into rbuffer. Returns number of corrected bit errors (>=0)
+ * or error (<0) */
+static int read_page(int log)
+{
+       int err = 0;
+       size_t read;
+       struct mtd_ecc_stats oldstats;
+
+       if (log)
+               pr_info("read_page\n");
+
+       /* Saving last mtd stats */
+       memcpy(&oldstats, &mtd->ecc_stats, sizeof(oldstats));
+
+       err = mtd_read(mtd, offset, mtd->writesize, &read, rbuffer);
+       if (err == -EUCLEAN)
+               err = mtd->ecc_stats.corrected - oldstats.corrected;
+
+       if (err < 0 || read != mtd->writesize) {
+               pr_err("error: read failed at %#llx\n", (long long)offset);
+               if (err >= 0)
+                       err = -EIO;
+       }
+
+       return err;
+}
+
+/* Verifies rbuffer against random sequence */
+static int verify_page(int log)
+{
+       unsigned i, errs = 0;
+
+       if (log)
+               pr_info("verify_page\n");
+
+       for (i = 0; i < mtd->writesize; i++) {
+               if (rbuffer[i] != hash(i+seed)) {
+                       pr_err("Error: page offset %u, expected %02x, got %02x\n",
+                               i, hash(i+seed), rbuffer[i]);
+                       errs++;
+               }
+       }
+
+       if (errs)
+               return -EIO;
+       else
+               return 0;
+}
+
+#define CBIT(v, n) ((v) & (1 << (n)))
+#define BCLR(v, n) ((v) = (v) & ~(1 << (n)))
+
+/* Finds the first '1' bit in wbuffer starting at offset 'byte'
+ * and sets it to '0'. */
+static int insert_biterror(unsigned byte)
+{
+       int bit;
+
+       while (byte < mtd->writesize) {
+               for (bit = 7; bit >= 0; bit--) {
+                       if (CBIT(wbuffer[byte], bit)) {
+                               BCLR(wbuffer[byte], bit);
+                               pr_info("Inserted biterror @ %u/%u\n", byte, bit);
+                               return 0;
+                       }
+               }
+               byte++;
+       }
+       pr_err("biterror: Failed to find a '1' bit\n");
+       return -EIO;
+}
+
+/* Writes 'random' data to page and then introduces deliberate bit
+ * errors into the page, while verifying each step. */
+static int incremental_errors_test(void)
+{
+       int err = 0;
+       unsigned i;
+       unsigned errs_per_subpage = 0;
+
+       pr_info("incremental biterrors test\n");
+
+       for (i = 0; i < mtd->writesize; i++)
+               wbuffer[i] = hash(i+seed);
+
+       err = write_page(1);
+       if (err)
+               goto exit;
+
+       while (1) {
+
+               err = rewrite_page(1);
+               if (err)
+                       goto exit;
+
+               err = read_page(1);
+               if (err > 0)
+                       pr_info("Read reported %d corrected bit errors\n", err);
+               if (err < 0) {
+                       pr_err("After %d biterrors per subpage, read reported error %d\n",
+                               errs_per_subpage, err);
+                       err = 0;
+                       goto exit;
+               }
+
+               err = verify_page(1);
+               if (err) {
+                       pr_err("ECC failure, read data is incorrect despite read success\n");
+                       goto exit;
+               }
+
+               pr_info("Successfully corrected %d bit errors per subpage\n",
+                       errs_per_subpage);
+
+               for (i = 0; i < subcount; i++) {
+                       err = insert_biterror(i * subsize);
+                       if (err < 0)
+                               goto exit;
+               }
+               errs_per_subpage++;
+       }
+
+exit:
+       return err;
+}
+
+
+/* Writes 'random' data to page and then re-writes that same data repeatedly.
+   This eventually develops bit errors (bits written as '1' will slowly become
+   '0'), which are corrected as far as the ECC is capable of. */
+static int overwrite_test(void)
+{
+       int err = 0;
+       unsigned i;
+       unsigned max_corrected = 0;
+       unsigned opno = 0;
+       /* We don't expect more than this many correctable bit errors per
+        * page. */
+       #define MAXBITS 512
+       static unsigned bitstats[MAXBITS]; /* bit error histogram. */
+
+       memset(bitstats, 0, sizeof(bitstats));
+
+       pr_info("overwrite biterrors test\n");
+
+       for (i = 0; i < mtd->writesize; i++)
+               wbuffer[i] = hash(i+seed);
+
+       err = write_page(1);
+       if (err)
+               goto exit;
+
+       while (opno < max_overwrite) {
+
+               err = rewrite_page(0);
+               if (err)
+                       break;
+
+               err = read_page(0);
+               if (err >= 0) {
+                       if (err >= MAXBITS) {
+                               pr_info("Implausible number of bit errors corrected\n");
+                               err = -EIO;
+                               break;
+                       }
+                       bitstats[err]++;
+                       if (err > max_corrected) {
+                               max_corrected = err;
+                               pr_info("Read reported %d corrected bit errors\n",
+                                       err);
+                       }
+               } else { /* err < 0 */
+                       pr_info("Read reported error %d\n", err);
+                       err = 0;
+                       break;
+               }
+
+               err = verify_page(0);
+               if (err) {
+                       bitstats[max_corrected] = opno;
+                       pr_info("ECC failure, read data is incorrect despite read success\n");
+                       break;
+               }
+
+               opno++;
+       }
+
+       /* At this point bitstats[0] contains the number of ops with no bit
+        * errors, bitstats[1] the number of ops with 1 bit error, etc. */
+       pr_info("Bit error histogram (%d operations total):\n", opno);
+       for (i = 0; i < max_corrected; i++)
+               pr_info("Page reads with %3d corrected bit errors: %d\n",
+                       i, bitstats[i]);
+
+exit:
+       return err;
+}
+
+static int __init mtd_nandbiterrs_init(void)
+{
+       int err = 0;
+
+       printk("\n");
+       printk(KERN_INFO "==================================================\n");
+       pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               goto exit_mtddev;
+       }
+
+       if (mtd->type != MTD_NANDFLASH) {
+               pr_info("this test requires NAND flash\n");
+               err = -ENODEV;
+               goto exit_nand;
+       }
+
+       pr_info("MTD device size %llu, eraseblock=%u, page=%u, oob=%u\n",
+               (unsigned long long)mtd->size, mtd->erasesize,
+               mtd->writesize, mtd->oobsize);
+
+       subsize  = mtd->writesize >> mtd->subpage_sft;
+       subcount = mtd->writesize / subsize;
+
+       pr_info("Device uses %d subpages of %d bytes\n", subcount, subsize);
+
+       offset     = page_offset * mtd->writesize;
+       eraseblock = mtd_div_by_eb(offset, mtd);
+
+       pr_info("Using page=%u, offset=%llu, eraseblock=%u\n",
+               page_offset, offset, eraseblock);
+
+       wbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
+       if (!wbuffer) {
+               err = -ENOMEM;
+               goto exit_wbuffer;
+       }
+
+       rbuffer = kmalloc(mtd->writesize, GFP_KERNEL);
+       if (!rbuffer) {
+               err = -ENOMEM;
+               goto exit_rbuffer;
+       }
+
+       err = mtdtest_erase_eraseblock(mtd, eraseblock);
+       if (err)
+               goto exit_error;
+
+       if (mode == 0)
+               err = incremental_errors_test();
+       else
+               err = overwrite_test();
+
+       if (err)
+               goto exit_error;
+
+       /* We leave the block un-erased in case of test failure. */
+       err = mtdtest_erase_eraseblock(mtd, eraseblock);
+       if (err)
+               goto exit_error;
+
+       err = -EIO;
+       pr_info("finished successfully.\n");
+       printk(KERN_INFO "==================================================\n");
+
+exit_error:
+       kfree(rbuffer);
+exit_rbuffer:
+       kfree(wbuffer);
+exit_wbuffer:
+       /* Nothing */
+exit_nand:
+       put_mtd_device(mtd);
+exit_mtddev:
+       return err;
+}
+
+static void __exit mtd_nandbiterrs_exit(void)
+{
+       return;
+}
+
+module_init(mtd_nandbiterrs_init);
+module_exit(mtd_nandbiterrs_exit);
+
+MODULE_DESCRIPTION("NAND bit error recovery test");
+MODULE_AUTHOR("Iwo Mergler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c
new file mode 100644 (file)
index 0000000..ff35c46
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test OOB read and write on MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <asm/div64.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+
+#include "mtd_test.h"
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *readbuf;
+static unsigned char *writebuf;
+static unsigned char *bbt;
+
+static int ebcnt;
+static int pgcnt;
+static int errcnt;
+static int use_offset;
+static int use_len;
+static int use_len_max;
+static int vary_offset;
+static struct rnd_state rnd_state;
+
+static void do_vary_offset(void)
+{
+       use_len -= 1;
+       if (use_len < 1) {
+               use_offset += 1;
+               if (use_offset >= use_len_max)
+                       use_offset = 0;
+               use_len = use_len_max - use_offset;
+       }
+}
+
+static int write_eraseblock(int ebnum)
+{
+       int i;
+       struct mtd_oob_ops ops;
+       int err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
+               prandom_bytes_state(&rnd_state, writebuf, use_len);
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = use_len;
+               ops.oobretlen = 0;
+               ops.ooboffs   = use_offset;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = writebuf;
+               err = mtd_write_oob(mtd, addr, &ops);
+               if (err || ops.oobretlen != use_len) {
+                       pr_err("error: writeoob failed at %#llx\n",
+                              (long long)addr);
+                       pr_err("error: use_len %d, use_offset %d\n",
+                              use_len, use_offset);
+                       errcnt += 1;
+                       return err ? err : -1;
+               }
+               if (vary_offset)
+                       do_vary_offset();
+       }
+
+       return err;
+}
+
+static int write_whole_device(void)
+{
+       int err;
+       unsigned int i;
+
+       pr_info("writing OOBs of whole device\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock(i);
+               if (err)
+                       return err;
+               if (i % 256 == 0)
+                       pr_info("written up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("written %u eraseblocks\n", i);
+       return 0;
+}
+
+static int verify_eraseblock(int ebnum)
+{
+       int i;
+       struct mtd_oob_ops ops;
+       int err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
+               prandom_bytes_state(&rnd_state, writebuf, use_len);
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = use_len;
+               ops.oobretlen = 0;
+               ops.ooboffs   = use_offset;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = readbuf;
+               err = mtd_read_oob(mtd, addr, &ops);
+               if (err || ops.oobretlen != use_len) {
+                       pr_err("error: readoob failed at %#llx\n",
+                              (long long)addr);
+                       errcnt += 1;
+                       return err ? err : -1;
+               }
+               if (memcmp(readbuf, writebuf, use_len)) {
+                       pr_err("error: verify failed at %#llx\n",
+                              (long long)addr);
+                       errcnt += 1;
+                       if (errcnt > 1000) {
+                               pr_err("error: too many errors\n");
+                               return -1;
+                       }
+               }
+               if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) {
+                       int k;
+
+                       ops.mode      = MTD_OPS_AUTO_OOB;
+                       ops.len       = 0;
+                       ops.retlen    = 0;
+                       ops.ooblen    = mtd->ecclayout->oobavail;
+                       ops.oobretlen = 0;
+                       ops.ooboffs   = 0;
+                       ops.datbuf    = NULL;
+                       ops.oobbuf    = readbuf;
+                       err = mtd_read_oob(mtd, addr, &ops);
+                       if (err || ops.oobretlen != mtd->ecclayout->oobavail) {
+                               pr_err("error: readoob failed at %#llx\n",
+                                               (long long)addr);
+                               errcnt += 1;
+                               return err ? err : -1;
+                       }
+                       if (memcmp(readbuf + use_offset, writebuf, use_len)) {
+                               pr_err("error: verify failed at %#llx\n",
+                                               (long long)addr);
+                               errcnt += 1;
+                               if (errcnt > 1000) {
+                                       pr_err("error: too many errors\n");
+                                       return -1;
+                               }
+                       }
+                       for (k = 0; k < use_offset; ++k)
+                               if (readbuf[k] != 0xff) {
+                                       pr_err("error: verify 0xff "
+                                              "failed at %#llx\n",
+                                              (long long)addr);
+                                       errcnt += 1;
+                                       if (errcnt > 1000) {
+                                               pr_err("error: too "
+                                                      "many errors\n");
+                                               return -1;
+                                       }
+                               }
+                       for (k = use_offset + use_len;
+                            k < mtd->ecclayout->oobavail; ++k)
+                               if (readbuf[k] != 0xff) {
+                                       pr_err("error: verify 0xff "
+                                              "failed at %#llx\n",
+                                              (long long)addr);
+                                       errcnt += 1;
+                                       if (errcnt > 1000) {
+                                               pr_err("error: too "
+                                                      "many errors\n");
+                                               return -1;
+                                       }
+                               }
+               }
+               if (vary_offset)
+                       do_vary_offset();
+       }
+       return err;
+}
+
+static int verify_eraseblock_in_one_go(int ebnum)
+{
+       struct mtd_oob_ops ops;
+       int err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+       size_t len = mtd->ecclayout->oobavail * pgcnt;
+
+       prandom_bytes_state(&rnd_state, writebuf, len);
+       ops.mode      = MTD_OPS_AUTO_OOB;
+       ops.len       = 0;
+       ops.retlen    = 0;
+       ops.ooblen    = len;
+       ops.oobretlen = 0;
+       ops.ooboffs   = 0;
+       ops.datbuf    = NULL;
+       ops.oobbuf    = readbuf;
+       err = mtd_read_oob(mtd, addr, &ops);
+       if (err || ops.oobretlen != len) {
+               pr_err("error: readoob failed at %#llx\n",
+                      (long long)addr);
+               errcnt += 1;
+               return err ? err : -1;
+       }
+       if (memcmp(readbuf, writebuf, len)) {
+               pr_err("error: verify failed at %#llx\n",
+                      (long long)addr);
+               errcnt += 1;
+               if (errcnt > 1000) {
+                       pr_err("error: too many errors\n");
+                       return -1;
+               }
+       }
+
+       return err;
+}
+
+static int verify_all_eraseblocks(void)
+{
+       int err;
+       unsigned int i;
+
+       pr_info("verifying all eraseblocks\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = verify_eraseblock(i);
+               if (err)
+                       return err;
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+       return 0;
+}
+
+static int __init mtd_oobtest_init(void)
+{
+       int err = 0;
+       unsigned int i;
+       uint64_t tmp;
+       struct mtd_oob_ops ops;
+       loff_t addr = 0, addr0;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
+               return -EINVAL;
+       }
+
+       pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->type != MTD_NANDFLASH) {
+               pr_info("this test requires NAND flash\n");
+               goto out;
+       }
+
+       tmp = mtd->size;
+       do_div(tmp, mtd->erasesize);
+       ebcnt = tmp;
+       pgcnt = mtd->erasesize / mtd->writesize;
+
+       pr_info("MTD device size %llu, eraseblock size %u, "
+              "page size %u, count of eraseblocks %u, pages per "
+              "eraseblock %u, OOB size %u\n",
+              (unsigned long long)mtd->size, mtd->erasesize,
+              mtd->writesize, ebcnt, pgcnt, mtd->oobsize);
+
+       err = -ENOMEM;
+       readbuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!readbuf)
+               goto out;
+       writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!writebuf)
+               goto out;
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       use_offset = 0;
+       use_len = mtd->ecclayout->oobavail;
+       use_len_max = mtd->ecclayout->oobavail;
+       vary_offset = 0;
+
+       /* First test: write all OOB, read it back and verify */
+       pr_info("test 1 of 5\n");
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       prandom_seed_state(&rnd_state, 1);
+       err = write_whole_device();
+       if (err)
+               goto out;
+
+       prandom_seed_state(&rnd_state, 1);
+       err = verify_all_eraseblocks();
+       if (err)
+               goto out;
+
+       /*
+        * Second test: write all OOB, a block at a time, read it back and
+        * verify.
+        */
+       pr_info("test 2 of 5\n");
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       prandom_seed_state(&rnd_state, 3);
+       err = write_whole_device();
+       if (err)
+               goto out;
+
+       /* Check all eraseblocks */
+       prandom_seed_state(&rnd_state, 3);
+       pr_info("verifying all eraseblocks\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = verify_eraseblock_in_one_go(i);
+               if (err)
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+
+       /*
+        * Third test: write OOB at varying offsets and lengths, read it back
+        * and verify.
+        */
+       pr_info("test 3 of 5\n");
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Write all eraseblocks */
+       use_offset = 0;
+       use_len = mtd->ecclayout->oobavail;
+       use_len_max = mtd->ecclayout->oobavail;
+       vary_offset = 1;
+       prandom_seed_state(&rnd_state, 5);
+
+       err = write_whole_device();
+       if (err)
+               goto out;
+
+       /* Check all eraseblocks */
+       use_offset = 0;
+       use_len = mtd->ecclayout->oobavail;
+       use_len_max = mtd->ecclayout->oobavail;
+       vary_offset = 1;
+       prandom_seed_state(&rnd_state, 5);
+       err = verify_all_eraseblocks();
+       if (err)
+               goto out;
+
+       use_offset = 0;
+       use_len = mtd->ecclayout->oobavail;
+       use_len_max = mtd->ecclayout->oobavail;
+       vary_offset = 0;
+
+       /* Fourth test: try to write off end of device */
+       pr_info("test 4 of 5\n");
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       addr0 = 0;
+       for (i = 0; i < ebcnt && bbt[i]; ++i)
+               addr0 += mtd->erasesize;
+
+       /* Attempt to write off end of OOB */
+       ops.mode      = MTD_OPS_AUTO_OOB;
+       ops.len       = 0;
+       ops.retlen    = 0;
+       ops.ooblen    = 1;
+       ops.oobretlen = 0;
+       ops.ooboffs   = mtd->ecclayout->oobavail;
+       ops.datbuf    = NULL;
+       ops.oobbuf    = writebuf;
+       pr_info("attempting to start write past end of OOB\n");
+       pr_info("an error is expected...\n");
+       err = mtd_write_oob(mtd, addr0, &ops);
+       if (err) {
+               pr_info("error occurred as expected\n");
+               err = 0;
+       } else {
+               pr_err("error: can write past end of OOB\n");
+               errcnt += 1;
+       }
+
+       /* Attempt to read off end of OOB */
+       ops.mode      = MTD_OPS_AUTO_OOB;
+       ops.len       = 0;
+       ops.retlen    = 0;
+       ops.ooblen    = 1;
+       ops.oobretlen = 0;
+       ops.ooboffs   = mtd->ecclayout->oobavail;
+       ops.datbuf    = NULL;
+       ops.oobbuf    = readbuf;
+       pr_info("attempting to start read past end of OOB\n");
+       pr_info("an error is expected...\n");
+       err = mtd_read_oob(mtd, addr0, &ops);
+       if (err) {
+               pr_info("error occurred as expected\n");
+               err = 0;
+       } else {
+               pr_err("error: can read past end of OOB\n");
+               errcnt += 1;
+       }
+
+       if (bbt[ebcnt - 1])
+               pr_info("skipping end of device tests because last "
+                      "block is bad\n");
+       else {
+               /* Attempt to write off end of device */
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = mtd->ecclayout->oobavail + 1;
+               ops.oobretlen = 0;
+               ops.ooboffs   = 0;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = writebuf;
+               pr_info("attempting to write past end of device\n");
+               pr_info("an error is expected...\n");
+               err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
+               if (err) {
+                       pr_info("error occurred as expected\n");
+                       err = 0;
+               } else {
+                       pr_err("error: wrote past end of device\n");
+                       errcnt += 1;
+               }
+
+               /* Attempt to read off end of device */
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = mtd->ecclayout->oobavail + 1;
+               ops.oobretlen = 0;
+               ops.ooboffs   = 0;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = readbuf;
+               pr_info("attempting to read past end of device\n");
+               pr_info("an error is expected...\n");
+               err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
+               if (err) {
+                       pr_info("error occurred as expected\n");
+                       err = 0;
+               } else {
+                       pr_err("error: read past end of device\n");
+                       errcnt += 1;
+               }
+
+               err = mtdtest_erase_eraseblock(mtd, ebcnt - 1);
+               if (err)
+                       goto out;
+
+               /* Attempt to write off end of device */
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = mtd->ecclayout->oobavail;
+               ops.oobretlen = 0;
+               ops.ooboffs   = 1;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = writebuf;
+               pr_info("attempting to write past end of device\n");
+               pr_info("an error is expected...\n");
+               err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops);
+               if (err) {
+                       pr_info("error occurred as expected\n");
+                       err = 0;
+               } else {
+                       pr_err("error: wrote past end of device\n");
+                       errcnt += 1;
+               }
+
+               /* Attempt to read off end of device */
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = mtd->ecclayout->oobavail;
+               ops.oobretlen = 0;
+               ops.ooboffs   = 1;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = readbuf;
+               pr_info("attempting to read past end of device\n");
+               pr_info("an error is expected...\n");
+               err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops);
+               if (err) {
+                       pr_info("error occurred as expected\n");
+                       err = 0;
+               } else {
+                       pr_err("error: read past end of device\n");
+                       errcnt += 1;
+               }
+       }
+
+       /* Fifth test: write / read across block boundaries */
+       pr_info("test 5 of 5\n");
+
+       /* Erase all eraseblocks */
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Write all eraseblocks */
+       prandom_seed_state(&rnd_state, 11);
+       pr_info("writing OOBs of whole device\n");
+       for (i = 0; i < ebcnt - 1; ++i) {
+               int cnt = 2;
+               int pg;
+               size_t sz = mtd->ecclayout->oobavail;
+               if (bbt[i] || bbt[i + 1])
+                       continue;
+               addr = (i + 1) * mtd->erasesize - mtd->writesize;
+               for (pg = 0; pg < cnt; ++pg) {
+                       prandom_bytes_state(&rnd_state, writebuf, sz);
+                       ops.mode      = MTD_OPS_AUTO_OOB;
+                       ops.len       = 0;
+                       ops.retlen    = 0;
+                       ops.ooblen    = sz;
+                       ops.oobretlen = 0;
+                       ops.ooboffs   = 0;
+                       ops.datbuf    = NULL;
+                       ops.oobbuf    = writebuf;
+                       err = mtd_write_oob(mtd, addr, &ops);
+                       if (err)
+                               goto out;
+                       if (i % 256 == 0)
+                               pr_info("written up to eraseblock %u\n", i);
+                       cond_resched();
+                       addr += mtd->writesize;
+               }
+       }
+       pr_info("written %u eraseblocks\n", i);
+
+       /* Check all eraseblocks */
+       prandom_seed_state(&rnd_state, 11);
+       pr_info("verifying all eraseblocks\n");
+       for (i = 0; i < ebcnt - 1; ++i) {
+               if (bbt[i] || bbt[i + 1])
+                       continue;
+               prandom_bytes_state(&rnd_state, writebuf,
+                                       mtd->ecclayout->oobavail * 2);
+               addr = (i + 1) * mtd->erasesize - mtd->writesize;
+               ops.mode      = MTD_OPS_AUTO_OOB;
+               ops.len       = 0;
+               ops.retlen    = 0;
+               ops.ooblen    = mtd->ecclayout->oobavail * 2;
+               ops.oobretlen = 0;
+               ops.ooboffs   = 0;
+               ops.datbuf    = NULL;
+               ops.oobbuf    = readbuf;
+               err = mtd_read_oob(mtd, addr, &ops);
+               if (err)
+                       goto out;
+               if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) {
+                       pr_err("error: verify failed at %#llx\n",
+                              (long long)addr);
+                       errcnt += 1;
+                       if (errcnt > 1000) {
+                               pr_err("error: too many errors\n");
+                               goto out;
+                       }
+               }
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+
+       pr_info("finished with %d errors\n", errcnt);
+out:
+       kfree(bbt);
+       kfree(writebuf);
+       kfree(readbuf);
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(mtd_oobtest_init);
+
+static void __exit mtd_oobtest_exit(void)
+{
+       return;
+}
+module_exit(mtd_oobtest_exit);
+
+MODULE_DESCRIPTION("Out-of-band test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c
new file mode 100644 (file)
index 0000000..44b96e9
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test page read and write on MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <asm/div64.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+
+#include "mtd_test.h"
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *twopages;
+static unsigned char *writebuf;
+static unsigned char *boundary;
+static unsigned char *bbt;
+
+static int pgsize;
+static int bufsize;
+static int ebcnt;
+static int pgcnt;
+static int errcnt;
+static struct rnd_state rnd_state;
+
+static int write_eraseblock(int ebnum)
+{
+       loff_t addr = ebnum * mtd->erasesize;
+
+       prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
+       cond_resched();
+       return mtdtest_write(mtd, addr, mtd->erasesize, writebuf);
+}
+
+static int verify_eraseblock(int ebnum)
+{
+       uint32_t j;
+       int err = 0, i;
+       loff_t addr0, addrn;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       addr0 = 0;
+       for (i = 0; i < ebcnt && bbt[i]; ++i)
+               addr0 += mtd->erasesize;
+
+       addrn = mtd->size;
+       for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
+               addrn -= mtd->erasesize;
+
+       prandom_bytes_state(&rnd_state, writebuf, mtd->erasesize);
+       for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) {
+               /* Do a read to set the internal dataRAMs to different data */
+               err = mtdtest_read(mtd, addr0, bufsize, twopages);
+               if (err)
+                       return err;
+               err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
+               if (err)
+                       return err;
+               memset(twopages, 0, bufsize);
+               err = mtdtest_read(mtd, addr, bufsize, twopages);
+               if (err)
+                       break;
+               if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) {
+                       pr_err("error: verify failed at %#llx\n",
+                              (long long)addr);
+                       errcnt += 1;
+               }
+       }
+       /* Check boundary between eraseblocks */
+       if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) {
+               struct rnd_state old_state = rnd_state;
+
+               /* Do a read to set the internal dataRAMs to different data */
+               err = mtdtest_read(mtd, addr0, bufsize, twopages);
+               if (err)
+                       return err;
+               err = mtdtest_read(mtd, addrn - bufsize, bufsize, twopages);
+               if (err)
+                       return err;
+               memset(twopages, 0, bufsize);
+               err = mtdtest_read(mtd, addr, bufsize, twopages);
+               if (err)
+                       return err;
+               memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize);
+               prandom_bytes_state(&rnd_state, boundary + pgsize, pgsize);
+               if (memcmp(twopages, boundary, bufsize)) {
+                       pr_err("error: verify failed at %#llx\n",
+                              (long long)addr);
+                       errcnt += 1;
+               }
+               rnd_state = old_state;
+       }
+       return err;
+}
+
+static int crosstest(void)
+{
+       int err = 0, i;
+       loff_t addr, addr0, addrn;
+       unsigned char *pp1, *pp2, *pp3, *pp4;
+
+       pr_info("crosstest\n");
+       pp1 = kmalloc(pgsize * 4, GFP_KERNEL);
+       if (!pp1)
+               return -ENOMEM;
+       pp2 = pp1 + pgsize;
+       pp3 = pp2 + pgsize;
+       pp4 = pp3 + pgsize;
+       memset(pp1, 0, pgsize * 4);
+
+       addr0 = 0;
+       for (i = 0; i < ebcnt && bbt[i]; ++i)
+               addr0 += mtd->erasesize;
+
+       addrn = mtd->size;
+       for (i = 0; i < ebcnt && bbt[ebcnt - i - 1]; ++i)
+               addrn -= mtd->erasesize;
+
+       /* Read 2nd-to-last page to pp1 */
+       addr = addrn - pgsize - pgsize;
+       err = mtdtest_read(mtd, addr, pgsize, pp1);
+       if (err) {
+               kfree(pp1);
+               return err;
+       }
+
+       /* Read 3rd-to-last page to pp1 */
+       addr = addrn - pgsize - pgsize - pgsize;
+       err = mtdtest_read(mtd, addr, pgsize, pp1);
+       if (err) {
+               kfree(pp1);
+               return err;
+       }
+
+       /* Read first page to pp2 */
+       addr = addr0;
+       pr_info("reading page at %#llx\n", (long long)addr);
+       err = mtdtest_read(mtd, addr, pgsize, pp2);
+       if (err) {
+               kfree(pp1);
+               return err;
+       }
+
+       /* Read last page to pp3 */
+       addr = addrn - pgsize;
+       pr_info("reading page at %#llx\n", (long long)addr);
+       err = mtdtest_read(mtd, addr, pgsize, pp3);
+       if (err) {
+               kfree(pp1);
+               return err;
+       }
+
+       /* Read first page again to pp4 */
+       addr = addr0;
+       pr_info("reading page at %#llx\n", (long long)addr);
+       err = mtdtest_read(mtd, addr, pgsize, pp4);
+       if (err) {
+               kfree(pp1);
+               return err;
+       }
+
+       /* pp2 and pp4 should be the same */
+       pr_info("verifying pages read at %#llx match\n",
+              (long long)addr0);
+       if (memcmp(pp2, pp4, pgsize)) {
+               pr_err("verify failed!\n");
+               errcnt += 1;
+       } else if (!err)
+               pr_info("crosstest ok\n");
+       kfree(pp1);
+       return err;
+}
+
+static int erasecrosstest(void)
+{
+       int err = 0, i, ebnum, ebnum2;
+       loff_t addr0;
+       char *readbuf = twopages;
+
+       pr_info("erasecrosstest\n");
+
+       ebnum = 0;
+       addr0 = 0;
+       for (i = 0; i < ebcnt && bbt[i]; ++i) {
+               addr0 += mtd->erasesize;
+               ebnum += 1;
+       }
+
+       ebnum2 = ebcnt - 1;
+       while (ebnum2 && bbt[ebnum2])
+               ebnum2 -= 1;
+
+       pr_info("erasing block %d\n", ebnum);
+       err = mtdtest_erase_eraseblock(mtd, ebnum);
+       if (err)
+               return err;
+
+       pr_info("writing 1st page of block %d\n", ebnum);
+       prandom_bytes_state(&rnd_state, writebuf, pgsize);
+       strcpy(writebuf, "There is no data like this!");
+       err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+       if (err)
+               return err;
+
+       pr_info("reading 1st page of block %d\n", ebnum);
+       memset(readbuf, 0, pgsize);
+       err = mtdtest_read(mtd, addr0, pgsize, readbuf);
+       if (err)
+               return err;
+
+       pr_info("verifying 1st page of block %d\n", ebnum);
+       if (memcmp(writebuf, readbuf, pgsize)) {
+               pr_err("verify failed!\n");
+               errcnt += 1;
+               return -1;
+       }
+
+       pr_info("erasing block %d\n", ebnum);
+       err = mtdtest_erase_eraseblock(mtd, ebnum);
+       if (err)
+               return err;
+
+       pr_info("writing 1st page of block %d\n", ebnum);
+       prandom_bytes_state(&rnd_state, writebuf, pgsize);
+       strcpy(writebuf, "There is no data like this!");
+       err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+       if (err)
+               return err;
+
+       pr_info("erasing block %d\n", ebnum2);
+       err = mtdtest_erase_eraseblock(mtd, ebnum2);
+       if (err)
+               return err;
+
+       pr_info("reading 1st page of block %d\n", ebnum);
+       memset(readbuf, 0, pgsize);
+       err = mtdtest_read(mtd, addr0, pgsize, readbuf);
+       if (err)
+               return err;
+
+       pr_info("verifying 1st page of block %d\n", ebnum);
+       if (memcmp(writebuf, readbuf, pgsize)) {
+               pr_err("verify failed!\n");
+               errcnt += 1;
+               return -1;
+       }
+
+       if (!err)
+               pr_info("erasecrosstest ok\n");
+       return err;
+}
+
+static int erasetest(void)
+{
+       int err = 0, i, ebnum, ok = 1;
+       loff_t addr0;
+
+       pr_info("erasetest\n");
+
+       ebnum = 0;
+       addr0 = 0;
+       for (i = 0; i < ebcnt && bbt[i]; ++i) {
+               addr0 += mtd->erasesize;
+               ebnum += 1;
+       }
+
+       pr_info("erasing block %d\n", ebnum);
+       err = mtdtest_erase_eraseblock(mtd, ebnum);
+       if (err)
+               return err;
+
+       pr_info("writing 1st page of block %d\n", ebnum);
+       prandom_bytes_state(&rnd_state, writebuf, pgsize);
+       err = mtdtest_write(mtd, addr0, pgsize, writebuf);
+       if (err)
+               return err;
+
+       pr_info("erasing block %d\n", ebnum);
+       err = mtdtest_erase_eraseblock(mtd, ebnum);
+       if (err)
+               return err;
+
+       pr_info("reading 1st page of block %d\n", ebnum);
+       err = mtdtest_read(mtd, addr0, pgsize, twopages);
+       if (err)
+               return err;
+
+       pr_info("verifying 1st page of block %d is all 0xff\n",
+              ebnum);
+       for (i = 0; i < pgsize; ++i)
+               if (twopages[i] != 0xff) {
+                       pr_err("verifying all 0xff failed at %d\n",
+                              i);
+                       errcnt += 1;
+                       ok = 0;
+                       break;
+               }
+
+       if (ok && !err)
+               pr_info("erasetest ok\n");
+
+       return err;
+}
+
+static int __init mtd_pagetest_init(void)
+{
+       int err = 0;
+       uint64_t tmp;
+       uint32_t i;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
+               return -EINVAL;
+       }
+
+       pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->type != MTD_NANDFLASH) {
+               pr_info("this test requires NAND flash\n");
+               goto out;
+       }
+
+       tmp = mtd->size;
+       do_div(tmp, mtd->erasesize);
+       ebcnt = tmp;
+       pgcnt = mtd->erasesize / mtd->writesize;
+       pgsize = mtd->writesize;
+
+       pr_info("MTD device size %llu, eraseblock size %u, "
+              "page size %u, count of eraseblocks %u, pages per "
+              "eraseblock %u, OOB size %u\n",
+              (unsigned long long)mtd->size, mtd->erasesize,
+              pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+       err = -ENOMEM;
+       bufsize = pgsize * 2;
+       writebuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!writebuf)
+               goto out;
+       twopages = kmalloc(bufsize, GFP_KERNEL);
+       if (!twopages)
+               goto out;
+       boundary = kmalloc(bufsize, GFP_KERNEL);
+       if (!boundary)
+               goto out;
+
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Erase all eraseblocks */
+       pr_info("erasing whole device\n");
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+       pr_info("erased %u eraseblocks\n", ebcnt);
+
+       /* Write all eraseblocks */
+       prandom_seed_state(&rnd_state, 1);
+       pr_info("writing whole device\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock(i);
+               if (err)
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("written up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("written %u eraseblocks\n", i);
+
+       /* Check all eraseblocks */
+       prandom_seed_state(&rnd_state, 1);
+       pr_info("verifying all eraseblocks\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = verify_eraseblock(i);
+               if (err)
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+
+       err = crosstest();
+       if (err)
+               goto out;
+
+       err = erasecrosstest();
+       if (err)
+               goto out;
+
+       err = erasetest();
+       if (err)
+               goto out;
+
+       pr_info("finished with %d errors\n", errcnt);
+out:
+
+       kfree(bbt);
+       kfree(boundary);
+       kfree(twopages);
+       kfree(writebuf);
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(mtd_pagetest_init);
+
+static void __exit mtd_pagetest_exit(void)
+{
+       return;
+}
+module_exit(mtd_pagetest_exit);
+
+MODULE_DESCRIPTION("NAND page test");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c
new file mode 100644 (file)
index 0000000..626e66d
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Check MTD device read.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+
+#include "mtd_test.h"
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *iobuf;
+static unsigned char *iobuf1;
+static unsigned char *bbt;
+
+static int pgsize;
+static int ebcnt;
+static int pgcnt;
+
+static int read_eraseblock_by_page(int ebnum)
+{
+       int i, ret, err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+       void *buf = iobuf;
+       void *oobbuf = iobuf1;
+
+       for (i = 0; i < pgcnt; i++) {
+               memset(buf, 0 , pgsize);
+               ret = mtdtest_read(mtd, addr, pgsize, buf);
+               if (ret) {
+                       if (!err)
+                               err = ret;
+               }
+               if (mtd->oobsize) {
+                       struct mtd_oob_ops ops;
+
+                       ops.mode      = MTD_OPS_PLACE_OOB;
+                       ops.len       = 0;
+                       ops.retlen    = 0;
+                       ops.ooblen    = mtd->oobsize;
+                       ops.oobretlen = 0;
+                       ops.ooboffs   = 0;
+                       ops.datbuf    = NULL;
+                       ops.oobbuf    = oobbuf;
+                       ret = mtd_read_oob(mtd, addr, &ops);
+                       if ((ret && !mtd_is_bitflip(ret)) ||
+                                       ops.oobretlen != mtd->oobsize) {
+                               pr_err("error: read oob failed at "
+                                                 "%#llx\n", (long long)addr);
+                               if (!err)
+                                       err = ret;
+                               if (!err)
+                                       err = -EINVAL;
+                       }
+                       oobbuf += mtd->oobsize;
+               }
+               addr += pgsize;
+               buf += pgsize;
+       }
+
+       return err;
+}
+
+static void dump_eraseblock(int ebnum)
+{
+       int i, j, n;
+       char line[128];
+       int pg, oob;
+
+       pr_info("dumping eraseblock %d\n", ebnum);
+       n = mtd->erasesize;
+       for (i = 0; i < n;) {
+               char *p = line;
+
+               p += sprintf(p, "%05x: ", i);
+               for (j = 0; j < 32 && i < n; j++, i++)
+                       p += sprintf(p, "%02x", (unsigned int)iobuf[i]);
+               printk(KERN_CRIT "%s\n", line);
+               cond_resched();
+       }
+       if (!mtd->oobsize)
+               return;
+       pr_info("dumping oob from eraseblock %d\n", ebnum);
+       n = mtd->oobsize;
+       for (pg = 0, i = 0; pg < pgcnt; pg++)
+               for (oob = 0; oob < n;) {
+                       char *p = line;
+
+                       p += sprintf(p, "%05x: ", i);
+                       for (j = 0; j < 32 && oob < n; j++, oob++, i++)
+                               p += sprintf(p, "%02x",
+                                            (unsigned int)iobuf1[i]);
+                       printk(KERN_CRIT "%s\n", line);
+                       cond_resched();
+               }
+}
+
+static int __init mtd_readtest_init(void)
+{
+       uint64_t tmp;
+       int err, i;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               return -EINVAL;
+       }
+
+       pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: Cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->writesize == 1) {
+               pr_info("not NAND flash, assume page size is 512 "
+                      "bytes.\n");
+               pgsize = 512;
+       } else
+               pgsize = mtd->writesize;
+
+       tmp = mtd->size;
+       do_div(tmp, mtd->erasesize);
+       ebcnt = tmp;
+       pgcnt = mtd->erasesize / pgsize;
+
+       pr_info("MTD device size %llu, eraseblock size %u, "
+              "page size %u, count of eraseblocks %u, pages per "
+              "eraseblock %u, OOB size %u\n",
+              (unsigned long long)mtd->size, mtd->erasesize,
+              pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+       err = -ENOMEM;
+       iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!iobuf)
+               goto out;
+       iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!iobuf1)
+               goto out;
+
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Read all eraseblocks 1 page at a time */
+       pr_info("testing page read\n");
+       for (i = 0; i < ebcnt; ++i) {
+               int ret;
+
+               if (bbt[i])
+                       continue;
+               ret = read_eraseblock_by_page(i);
+               if (ret) {
+                       dump_eraseblock(i);
+                       if (!err)
+                               err = ret;
+               }
+               cond_resched();
+       }
+
+       if (err)
+               pr_info("finished with errors\n");
+       else
+               pr_info("finished\n");
+
+out:
+
+       kfree(iobuf);
+       kfree(iobuf1);
+       kfree(bbt);
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(mtd_readtest_init);
+
+static void __exit mtd_readtest_exit(void)
+{
+       return;
+}
+module_exit(mtd_readtest_exit);
+
+MODULE_DESCRIPTION("Read test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c
new file mode 100644 (file)
index 0000000..87ff6a2
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2007 Nokia Corporation
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test read and write speed of a MTD device.
+ *
+ * Author: Adrian Hunter <adrian.hunter@nokia.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+
+#include "mtd_test.h"
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static int count;
+module_param(count, int, S_IRUGO);
+MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
+                       "(0 means use all)");
+
+static struct mtd_info *mtd;
+static unsigned char *iobuf;
+static unsigned char *bbt;
+
+static int pgsize;
+static int ebcnt;
+static int pgcnt;
+static int goodebcnt;
+static struct timeval start, finish;
+
+static int multiblock_erase(int ebnum, int blocks)
+{
+       int err;
+       struct erase_info ei;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       memset(&ei, 0, sizeof(struct erase_info));
+       ei.mtd  = mtd;
+       ei.addr = addr;
+       ei.len  = mtd->erasesize * blocks;
+
+       err = mtd_erase(mtd, &ei);
+       if (err) {
+               pr_err("error %d while erasing EB %d, blocks %d\n",
+                      err, ebnum, blocks);
+               return err;
+       }
+
+       if (ei.state == MTD_ERASE_FAILED) {
+               pr_err("some erase error occurred at EB %d,"
+                      "blocks %d\n", ebnum, blocks);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int write_eraseblock(int ebnum)
+{
+       loff_t addr = ebnum * mtd->erasesize;
+
+       return mtdtest_write(mtd, addr, mtd->erasesize, iobuf);
+}
+
+static int write_eraseblock_by_page(int ebnum)
+{
+       int i, err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+       void *buf = iobuf;
+
+       for (i = 0; i < pgcnt; i++) {
+               err = mtdtest_write(mtd, addr, pgsize, buf);
+               if (err)
+                       break;
+               addr += pgsize;
+               buf += pgsize;
+       }
+
+       return err;
+}
+
+static int write_eraseblock_by_2pages(int ebnum)
+{
+       size_t sz = pgsize * 2;
+       int i, n = pgcnt / 2, err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+       void *buf = iobuf;
+
+       for (i = 0; i < n; i++) {
+               err = mtdtest_write(mtd, addr, sz, buf);
+               if (err)
+                       return err;
+               addr += sz;
+               buf += sz;
+       }
+       if (pgcnt % 2)
+               err = mtdtest_write(mtd, addr, pgsize, buf);
+
+       return err;
+}
+
+static int read_eraseblock(int ebnum)
+{
+       loff_t addr = ebnum * mtd->erasesize;
+
+       return mtdtest_read(mtd, addr, mtd->erasesize, iobuf);
+}
+
+static int read_eraseblock_by_page(int ebnum)
+{
+       int i, err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+       void *buf = iobuf;
+
+       for (i = 0; i < pgcnt; i++) {
+               err = mtdtest_read(mtd, addr, pgsize, buf);
+               if (err)
+                       break;
+               addr += pgsize;
+               buf += pgsize;
+       }
+
+       return err;
+}
+
+static int read_eraseblock_by_2pages(int ebnum)
+{
+       size_t sz = pgsize * 2;
+       int i, n = pgcnt / 2, err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+       void *buf = iobuf;
+
+       for (i = 0; i < n; i++) {
+               err = mtdtest_read(mtd, addr, sz, buf);
+               if (err)
+                       return err;
+               addr += sz;
+               buf += sz;
+       }
+       if (pgcnt % 2)
+               err = mtdtest_read(mtd, addr, pgsize, buf);
+
+       return err;
+}
+
+static inline void start_timing(void)
+{
+       do_gettimeofday(&start);
+}
+
+static inline void stop_timing(void)
+{
+       do_gettimeofday(&finish);
+}
+
+static long calc_speed(void)
+{
+       uint64_t k;
+       long ms;
+
+       ms = (finish.tv_sec - start.tv_sec) * 1000 +
+            (finish.tv_usec - start.tv_usec) / 1000;
+       if (ms == 0)
+               return 0;
+       k = goodebcnt * (mtd->erasesize / 1024) * 1000;
+       do_div(k, ms);
+       return k;
+}
+
+static int __init mtd_speedtest_init(void)
+{
+       int err, i, blocks, j, k;
+       long speed;
+       uint64_t tmp;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
+               return -EINVAL;
+       }
+
+       if (count)
+               pr_info("MTD device: %d    count: %d\n", dev, count);
+       else
+               pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->writesize == 1) {
+               pr_info("not NAND flash, assume page size is 512 "
+                      "bytes.\n");
+               pgsize = 512;
+       } else
+               pgsize = mtd->writesize;
+
+       tmp = mtd->size;
+       do_div(tmp, mtd->erasesize);
+       ebcnt = tmp;
+       pgcnt = mtd->erasesize / pgsize;
+
+       pr_info("MTD device size %llu, eraseblock size %u, "
+              "page size %u, count of eraseblocks %u, pages per "
+              "eraseblock %u, OOB size %u\n",
+              (unsigned long long)mtd->size, mtd->erasesize,
+              pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+       if (count > 0 && count < ebcnt)
+               ebcnt = count;
+
+       err = -ENOMEM;
+       iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!iobuf)
+               goto out;
+
+       prandom_bytes(iobuf, mtd->erasesize);
+
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+       for (i = 0; i < ebcnt; i++) {
+               if (!bbt[i])
+                       goodebcnt++;
+       }
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Write all eraseblocks, 1 eraseblock at a time */
+       pr_info("testing eraseblock write speed\n");
+       start_timing();
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock(i);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       stop_timing();
+       speed = calc_speed();
+       pr_info("eraseblock write speed is %ld KiB/s\n", speed);
+
+       /* Read all eraseblocks, 1 eraseblock at a time */
+       pr_info("testing eraseblock read speed\n");
+       start_timing();
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = read_eraseblock(i);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       stop_timing();
+       speed = calc_speed();
+       pr_info("eraseblock read speed is %ld KiB/s\n", speed);
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Write all eraseblocks, 1 page at a time */
+       pr_info("testing page write speed\n");
+       start_timing();
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock_by_page(i);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       stop_timing();
+       speed = calc_speed();
+       pr_info("page write speed is %ld KiB/s\n", speed);
+
+       /* Read all eraseblocks, 1 page at a time */
+       pr_info("testing page read speed\n");
+       start_timing();
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = read_eraseblock_by_page(i);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       stop_timing();
+       speed = calc_speed();
+       pr_info("page read speed is %ld KiB/s\n", speed);
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Write all eraseblocks, 2 pages at a time */
+       pr_info("testing 2 page write speed\n");
+       start_timing();
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock_by_2pages(i);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       stop_timing();
+       speed = calc_speed();
+       pr_info("2 page write speed is %ld KiB/s\n", speed);
+
+       /* Read all eraseblocks, 2 pages at a time */
+       pr_info("testing 2 page read speed\n");
+       start_timing();
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = read_eraseblock_by_2pages(i);
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       stop_timing();
+       speed = calc_speed();
+       pr_info("2 page read speed is %ld KiB/s\n", speed);
+
+       /* Erase all eraseblocks */
+       pr_info("Testing erase speed\n");
+       start_timing();
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+       stop_timing();
+       speed = calc_speed();
+       pr_info("erase speed is %ld KiB/s\n", speed);
+
+       /* Multi-block erase all eraseblocks */
+       for (k = 1; k < 7; k++) {
+               blocks = 1 << k;
+               pr_info("Testing %dx multi-block erase speed\n",
+                      blocks);
+               start_timing();
+               for (i = 0; i < ebcnt; ) {
+                       for (j = 0; j < blocks && (i + j) < ebcnt; j++)
+                               if (bbt[i + j])
+                                       break;
+                       if (j < 1) {
+                               i++;
+                               continue;
+                       }
+                       err = multiblock_erase(i, j);
+                       if (err)
+                               goto out;
+                       cond_resched();
+                       i += j;
+               }
+               stop_timing();
+               speed = calc_speed();
+               pr_info("%dx multi-block erase speed is %ld KiB/s\n",
+                      blocks, speed);
+       }
+       pr_info("finished\n");
+out:
+       kfree(iobuf);
+       kfree(bbt);
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(mtd_speedtest_init);
+
+static void __exit mtd_speedtest_exit(void)
+{
+       return;
+}
+module_exit(mtd_speedtest_exit);
+
+MODULE_DESCRIPTION("Speed test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c
new file mode 100644 (file)
index 0000000..c9d42cc
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2006-2008 Nokia Corporation
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test random reads, writes and erases on MTD device.
+ *
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/random.h>
+
+#include "mtd_test.h"
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static int count = 10000;
+module_param(count, int, S_IRUGO);
+MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)");
+
+static struct mtd_info *mtd;
+static unsigned char *writebuf;
+static unsigned char *readbuf;
+static unsigned char *bbt;
+static int *offsets;
+
+static int pgsize;
+static int bufsize;
+static int ebcnt;
+static int pgcnt;
+
+static int rand_eb(void)
+{
+       unsigned int eb;
+
+again:
+       eb = prandom_u32();
+       /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */
+       eb %= (ebcnt - 1);
+       if (bbt[eb])
+               goto again;
+       return eb;
+}
+
+static int rand_offs(void)
+{
+       unsigned int offs;
+
+       offs = prandom_u32();
+       offs %= bufsize;
+       return offs;
+}
+
+static int rand_len(int offs)
+{
+       unsigned int len;
+
+       len = prandom_u32();
+       len %= (bufsize - offs);
+       return len;
+}
+
+static int do_read(void)
+{
+       int eb = rand_eb();
+       int offs = rand_offs();
+       int len = rand_len(offs);
+       loff_t addr;
+
+       if (bbt[eb + 1]) {
+               if (offs >= mtd->erasesize)
+                       offs -= mtd->erasesize;
+               if (offs + len > mtd->erasesize)
+                       len = mtd->erasesize - offs;
+       }
+       addr = eb * mtd->erasesize + offs;
+       return mtdtest_read(mtd, addr, len, readbuf);
+}
+
+static int do_write(void)
+{
+       int eb = rand_eb(), offs, err, len;
+       loff_t addr;
+
+       offs = offsets[eb];
+       if (offs >= mtd->erasesize) {
+               err = mtdtest_erase_eraseblock(mtd, eb);
+               if (err)
+                       return err;
+               offs = offsets[eb] = 0;
+       }
+       len = rand_len(offs);
+       len = ((len + pgsize - 1) / pgsize) * pgsize;
+       if (offs + len > mtd->erasesize) {
+               if (bbt[eb + 1])
+                       len = mtd->erasesize - offs;
+               else {
+                       err = mtdtest_erase_eraseblock(mtd, eb + 1);
+                       if (err)
+                               return err;
+                       offsets[eb + 1] = 0;
+               }
+       }
+       addr = eb * mtd->erasesize + offs;
+       err = mtdtest_write(mtd, addr, len, writebuf);
+       if (unlikely(err))
+               return err;
+       offs += len;
+       while (offs > mtd->erasesize) {
+               offsets[eb++] = mtd->erasesize;
+               offs -= mtd->erasesize;
+       }
+       offsets[eb] = offs;
+       return 0;
+}
+
+static int do_operation(void)
+{
+       if (prandom_u32() & 1)
+               return do_read();
+       else
+               return do_write();
+}
+
+static int __init mtd_stresstest_init(void)
+{
+       int err;
+       int i, op;
+       uint64_t tmp;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
+               return -EINVAL;
+       }
+
+       pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->writesize == 1) {
+               pr_info("not NAND flash, assume page size is 512 "
+                      "bytes.\n");
+               pgsize = 512;
+       } else
+               pgsize = mtd->writesize;
+
+       tmp = mtd->size;
+       do_div(tmp, mtd->erasesize);
+       ebcnt = tmp;
+       pgcnt = mtd->erasesize / pgsize;
+
+       pr_info("MTD device size %llu, eraseblock size %u, "
+              "page size %u, count of eraseblocks %u, pages per "
+              "eraseblock %u, OOB size %u\n",
+              (unsigned long long)mtd->size, mtd->erasesize,
+              pgsize, ebcnt, pgcnt, mtd->oobsize);
+
+       if (ebcnt < 2) {
+               pr_err("error: need at least 2 eraseblocks\n");
+               err = -ENOSPC;
+               goto out_put_mtd;
+       }
+
+       /* Read or write up 2 eraseblocks at a time */
+       bufsize = mtd->erasesize * 2;
+
+       err = -ENOMEM;
+       readbuf = vmalloc(bufsize);
+       writebuf = vmalloc(bufsize);
+       offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL);
+       if (!readbuf || !writebuf || !offsets)
+               goto out;
+       for (i = 0; i < ebcnt; i++)
+               offsets[i] = mtd->erasesize;
+       prandom_bytes(writebuf, bufsize);
+
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       /* Do operations */
+       pr_info("doing operations\n");
+       for (op = 0; op < count; op++) {
+               if ((op & 1023) == 0)
+                       pr_info("%d operations done\n", op);
+               err = do_operation();
+               if (err)
+                       goto out;
+               cond_resched();
+       }
+       pr_info("finished, %d operations done\n", op);
+
+out:
+       kfree(offsets);
+       kfree(bbt);
+       vfree(writebuf);
+       vfree(readbuf);
+out_put_mtd:
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(mtd_stresstest_init);
+
+static void __exit mtd_stresstest_exit(void)
+{
+       return;
+}
+module_exit(mtd_stresstest_exit);
+
+MODULE_DESCRIPTION("Stress test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c
new file mode 100644 (file)
index 0000000..e2c0adf
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2006-2007 Nokia Corporation
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Test sub-page read and write on MTD device.
+ * Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
+ *
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/random.h>
+
+#include "mtd_test.h"
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static struct mtd_info *mtd;
+static unsigned char *writebuf;
+static unsigned char *readbuf;
+static unsigned char *bbt;
+
+static int subpgsize;
+static int bufsize;
+static int ebcnt;
+static int pgcnt;
+static int errcnt;
+static struct rnd_state rnd_state;
+
+static inline void clear_data(unsigned char *buf, size_t len)
+{
+       memset(buf, 0, len);
+}
+
+static int write_eraseblock(int ebnum)
+{
+       size_t written;
+       int err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
+       err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
+       if (unlikely(err || written != subpgsize)) {
+               pr_err("error: write failed at %#llx\n",
+                      (long long)addr);
+               if (written != subpgsize) {
+                       pr_err("  write size: %#x\n", subpgsize);
+                       pr_err("  written: %#zx\n", written);
+               }
+               return err ? err : -1;
+       }
+
+       addr += subpgsize;
+
+       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
+       err = mtd_write(mtd, addr, subpgsize, &written, writebuf);
+       if (unlikely(err || written != subpgsize)) {
+               pr_err("error: write failed at %#llx\n",
+                      (long long)addr);
+               if (written != subpgsize) {
+                       pr_err("  write size: %#x\n", subpgsize);
+                       pr_err("  written: %#zx\n", written);
+               }
+               return err ? err : -1;
+       }
+
+       return err;
+}
+
+static int write_eraseblock2(int ebnum)
+{
+       size_t written;
+       int err = 0, k;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       for (k = 1; k < 33; ++k) {
+               if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
+                       break;
+               prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
+               err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
+               if (unlikely(err || written != subpgsize * k)) {
+                       pr_err("error: write failed at %#llx\n",
+                              (long long)addr);
+                       if (written != subpgsize) {
+                               pr_err("  write size: %#x\n",
+                                      subpgsize * k);
+                               pr_err("  written: %#08zx\n",
+                                      written);
+                       }
+                       return err ? err : -1;
+               }
+               addr += subpgsize * k;
+       }
+
+       return err;
+}
+
+static void print_subpage(unsigned char *p)
+{
+       int i, j;
+
+       for (i = 0; i < subpgsize; ) {
+               for (j = 0; i < subpgsize && j < 32; ++i, ++j)
+                       printk("%02x", *p++);
+               printk("\n");
+       }
+}
+
+static int verify_eraseblock(int ebnum)
+{
+       size_t read;
+       int err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
+       clear_data(readbuf, subpgsize);
+       err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
+       if (unlikely(err || read != subpgsize)) {
+               if (mtd_is_bitflip(err) && read == subpgsize) {
+                       pr_info("ECC correction at %#llx\n",
+                              (long long)addr);
+                       err = 0;
+               } else {
+                       pr_err("error: read failed at %#llx\n",
+                              (long long)addr);
+                       return err ? err : -1;
+               }
+       }
+       if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
+               pr_err("error: verify failed at %#llx\n",
+                      (long long)addr);
+               pr_info("------------- written----------------\n");
+               print_subpage(writebuf);
+               pr_info("------------- read ------------------\n");
+               print_subpage(readbuf);
+               pr_info("-------------------------------------\n");
+               errcnt += 1;
+       }
+
+       addr += subpgsize;
+
+       prandom_bytes_state(&rnd_state, writebuf, subpgsize);
+       clear_data(readbuf, subpgsize);
+       err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
+       if (unlikely(err || read != subpgsize)) {
+               if (mtd_is_bitflip(err) && read == subpgsize) {
+                       pr_info("ECC correction at %#llx\n",
+                              (long long)addr);
+                       err = 0;
+               } else {
+                       pr_err("error: read failed at %#llx\n",
+                              (long long)addr);
+                       return err ? err : -1;
+               }
+       }
+       if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
+               pr_info("error: verify failed at %#llx\n",
+                      (long long)addr);
+               pr_info("------------- written----------------\n");
+               print_subpage(writebuf);
+               pr_info("------------- read ------------------\n");
+               print_subpage(readbuf);
+               pr_info("-------------------------------------\n");
+               errcnt += 1;
+       }
+
+       return err;
+}
+
+static int verify_eraseblock2(int ebnum)
+{
+       size_t read;
+       int err = 0, k;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       for (k = 1; k < 33; ++k) {
+               if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
+                       break;
+               prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
+               clear_data(readbuf, subpgsize * k);
+               err = mtd_read(mtd, addr, subpgsize * k, &read, readbuf);
+               if (unlikely(err || read != subpgsize * k)) {
+                       if (mtd_is_bitflip(err) && read == subpgsize * k) {
+                               pr_info("ECC correction at %#llx\n",
+                                      (long long)addr);
+                               err = 0;
+                       } else {
+                               pr_err("error: read failed at "
+                                      "%#llx\n", (long long)addr);
+                               return err ? err : -1;
+                       }
+               }
+               if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) {
+                       pr_err("error: verify failed at %#llx\n",
+                              (long long)addr);
+                       errcnt += 1;
+               }
+               addr += subpgsize * k;
+       }
+
+       return err;
+}
+
+static int verify_eraseblock_ff(int ebnum)
+{
+       uint32_t j;
+       size_t read;
+       int err = 0;
+       loff_t addr = ebnum * mtd->erasesize;
+
+       memset(writebuf, 0xff, subpgsize);
+       for (j = 0; j < mtd->erasesize / subpgsize; ++j) {
+               clear_data(readbuf, subpgsize);
+               err = mtd_read(mtd, addr, subpgsize, &read, readbuf);
+               if (unlikely(err || read != subpgsize)) {
+                       if (mtd_is_bitflip(err) && read == subpgsize) {
+                               pr_info("ECC correction at %#llx\n",
+                                      (long long)addr);
+                               err = 0;
+                       } else {
+                               pr_err("error: read failed at "
+                                      "%#llx\n", (long long)addr);
+                               return err ? err : -1;
+                       }
+               }
+               if (unlikely(memcmp(readbuf, writebuf, subpgsize))) {
+                       pr_err("error: verify 0xff failed at "
+                              "%#llx\n", (long long)addr);
+                       errcnt += 1;
+               }
+               addr += subpgsize;
+       }
+
+       return err;
+}
+
+static int verify_all_eraseblocks_ff(void)
+{
+       int err;
+       unsigned int i;
+
+       pr_info("verifying all eraseblocks for 0xff\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = verify_eraseblock_ff(i);
+               if (err)
+                       return err;
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+       return 0;
+}
+
+static int __init mtd_subpagetest_init(void)
+{
+       int err = 0;
+       uint32_t i;
+       uint64_t tmp;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
+               return -EINVAL;
+       }
+
+       pr_info("MTD device: %d\n", dev);
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->type != MTD_NANDFLASH) {
+               pr_info("this test requires NAND flash\n");
+               goto out;
+       }
+
+       subpgsize = mtd->writesize >> mtd->subpage_sft;
+       tmp = mtd->size;
+       do_div(tmp, mtd->erasesize);
+       ebcnt = tmp;
+       pgcnt = mtd->erasesize / mtd->writesize;
+
+       pr_info("MTD device size %llu, eraseblock size %u, "
+              "page size %u, subpage size %u, count of eraseblocks %u, "
+              "pages per eraseblock %u, OOB size %u\n",
+              (unsigned long long)mtd->size, mtd->erasesize,
+              mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize);
+
+       err = -ENOMEM;
+       bufsize = subpgsize * 32;
+       writebuf = kmalloc(bufsize, GFP_KERNEL);
+       if (!writebuf)
+               goto out;
+       readbuf = kmalloc(bufsize, GFP_KERNEL);
+       if (!readbuf)
+               goto out;
+       bbt = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bbt)
+               goto out;
+
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       pr_info("writing whole device\n");
+       prandom_seed_state(&rnd_state, 1);
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock(i);
+               if (unlikely(err))
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("written up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("written %u eraseblocks\n", i);
+
+       prandom_seed_state(&rnd_state, 1);
+       pr_info("verifying all eraseblocks\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = verify_eraseblock(i);
+               if (unlikely(err))
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       err = verify_all_eraseblocks_ff();
+       if (err)
+               goto out;
+
+       /* Write all eraseblocks */
+       prandom_seed_state(&rnd_state, 3);
+       pr_info("writing whole device\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = write_eraseblock2(i);
+               if (unlikely(err))
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("written up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("written %u eraseblocks\n", i);
+
+       /* Check all eraseblocks */
+       prandom_seed_state(&rnd_state, 3);
+       pr_info("verifying all eraseblocks\n");
+       for (i = 0; i < ebcnt; ++i) {
+               if (bbt[i])
+                       continue;
+               err = verify_eraseblock2(i);
+               if (unlikely(err))
+                       goto out;
+               if (i % 256 == 0)
+                       pr_info("verified up to eraseblock %u\n", i);
+               cond_resched();
+       }
+       pr_info("verified %u eraseblocks\n", i);
+
+       err = mtdtest_erase_good_eraseblocks(mtd, bbt, 0, ebcnt);
+       if (err)
+               goto out;
+
+       err = verify_all_eraseblocks_ff();
+       if (err)
+               goto out;
+
+       pr_info("finished with %d errors\n", errcnt);
+
+out:
+       kfree(bbt);
+       kfree(readbuf);
+       kfree(writebuf);
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(mtd_subpagetest_init);
+
+static void __exit mtd_subpagetest_exit(void)
+{
+       return;
+}
+module_exit(mtd_subpagetest_exit);
+
+MODULE_DESCRIPTION("Subpage test module");
+MODULE_AUTHOR("Adrian Hunter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/tests/torturetest.c b/drivers/mtd/tests/torturetest.c
new file mode 100644 (file)
index 0000000..eeab969
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2006-2008 Artem Bityutskiy
+ * Copyright (C) 2006-2008 Jarkko Lavinen
+ * Copyright (C) 2006-2008 Adrian Hunter
+ *
+ * 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; see the file COPYING. If not, write to the Free Software
+ * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter
+ *
+ * WARNING: this test program may kill your flash and your device. Do not
+ * use it unless you know what you do. Authors are not responsible for any
+ * damage caused by this program.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include "mtd_test.h"
+
+#define RETRIES 3
+
+static int eb = 8;
+module_param(eb, int, S_IRUGO);
+MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device");
+
+static int ebcnt = 32;
+module_param(ebcnt, int, S_IRUGO);
+MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture");
+
+static int pgcnt;
+module_param(pgcnt, int, S_IRUGO);
+MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)");
+
+static int dev = -EINVAL;
+module_param(dev, int, S_IRUGO);
+MODULE_PARM_DESC(dev, "MTD device number to use");
+
+static int gran = 512;
+module_param(gran, int, S_IRUGO);
+MODULE_PARM_DESC(gran, "how often the status information should be printed");
+
+static int check = 1;
+module_param(check, int, S_IRUGO);
+MODULE_PARM_DESC(check, "if the written data should be checked");
+
+static unsigned int cycles_count;
+module_param(cycles_count, uint, S_IRUGO);
+MODULE_PARM_DESC(cycles_count, "how many erase cycles to do "
+                              "(infinite by default)");
+
+static struct mtd_info *mtd;
+
+/* This buffer contains 0x555555...0xAAAAAA... pattern */
+static unsigned char *patt_5A5;
+/* This buffer contains 0xAAAAAA...0x555555... pattern */
+static unsigned char *patt_A5A;
+/* This buffer contains all 0xFF bytes */
+static unsigned char *patt_FF;
+/* This a temporary buffer is use when checking data */
+static unsigned char *check_buf;
+/* How many erase cycles were done */
+static unsigned int erase_cycles;
+
+static int pgsize;
+static struct timeval start, finish;
+
+static void report_corrupt(unsigned char *read, unsigned char *written);
+
+static inline void start_timing(void)
+{
+       do_gettimeofday(&start);
+}
+
+static inline void stop_timing(void)
+{
+       do_gettimeofday(&finish);
+}
+
+/*
+ * Check that the contents of eraseblock number @enbum is equivalent to the
+ * @buf buffer.
+ */
+static inline int check_eraseblock(int ebnum, unsigned char *buf)
+{
+       int err, retries = 0;
+       size_t read;
+       loff_t addr = ebnum * mtd->erasesize;
+       size_t len = mtd->erasesize;
+
+       if (pgcnt) {
+               addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
+               len = pgcnt * pgsize;
+       }
+
+retry:
+       err = mtd_read(mtd, addr, len, &read, check_buf);
+       if (mtd_is_bitflip(err))
+               pr_err("single bit flip occurred at EB %d "
+                      "MTD reported that it was fixed.\n", ebnum);
+       else if (err) {
+               pr_err("error %d while reading EB %d, "
+                      "read %zd\n", err, ebnum, read);
+               return err;
+       }
+
+       if (read != len) {
+               pr_err("failed to read %zd bytes from EB %d, "
+                      "read only %zd, but no error reported\n",
+                      len, ebnum, read);
+               return -EIO;
+       }
+
+       if (memcmp(buf, check_buf, len)) {
+               pr_err("read wrong data from EB %d\n", ebnum);
+               report_corrupt(check_buf, buf);
+
+               if (retries++ < RETRIES) {
+                       /* Try read again */
+                       yield();
+                       pr_info("re-try reading data from EB %d\n",
+                              ebnum);
+                       goto retry;
+               } else {
+                       pr_info("retried %d times, still errors, "
+                              "give-up\n", RETRIES);
+                       return -EINVAL;
+               }
+       }
+
+       if (retries != 0)
+               pr_info("only attempt number %d was OK (!!!)\n",
+                      retries);
+
+       return 0;
+}
+
+static inline int write_pattern(int ebnum, void *buf)
+{
+       int err;
+       size_t written;
+       loff_t addr = ebnum * mtd->erasesize;
+       size_t len = mtd->erasesize;
+
+       if (pgcnt) {
+               addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
+               len = pgcnt * pgsize;
+       }
+       err = mtd_write(mtd, addr, len, &written, buf);
+       if (err) {
+               pr_err("error %d while writing EB %d, written %zd"
+                     " bytes\n", err, ebnum, written);
+               return err;
+       }
+       if (written != len) {
+               pr_info("written only %zd bytes of %zd, but no error"
+                      " reported\n", written, len);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int __init tort_init(void)
+{
+       int err = 0, i, infinite = !cycles_count;
+       unsigned char *bad_ebs;
+
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "=================================================\n");
+       pr_info("Warning: this program is trying to wear out your "
+              "flash, stop it if this is not wanted.\n");
+
+       if (dev < 0) {
+               pr_info("Please specify a valid mtd-device via module parameter\n");
+               pr_crit("CAREFUL: This test wipes all data on the specified MTD device!\n");
+               return -EINVAL;
+       }
+
+       pr_info("MTD device: %d\n", dev);
+       pr_info("torture %d eraseblocks (%d-%d) of mtd%d\n",
+              ebcnt, eb, eb + ebcnt - 1, dev);
+       if (pgcnt)
+               pr_info("torturing just %d pages per eraseblock\n",
+                       pgcnt);
+       pr_info("write verify %s\n", check ? "enabled" : "disabled");
+
+       mtd = get_mtd_device(NULL, dev);
+       if (IS_ERR(mtd)) {
+               err = PTR_ERR(mtd);
+               pr_err("error: cannot get MTD device\n");
+               return err;
+       }
+
+       if (mtd->writesize == 1) {
+               pr_info("not NAND flash, assume page size is 512 "
+                      "bytes.\n");
+               pgsize = 512;
+       } else
+               pgsize = mtd->writesize;
+
+       if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) {
+               pr_err("error: invalid pgcnt value %d\n", pgcnt);
+               goto out_mtd;
+       }
+
+       err = -ENOMEM;
+       patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!patt_5A5)
+               goto out_mtd;
+
+       patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!patt_A5A)
+               goto out_patt_5A5;
+
+       patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!patt_FF)
+               goto out_patt_A5A;
+
+       check_buf = kmalloc(mtd->erasesize, GFP_KERNEL);
+       if (!check_buf)
+               goto out_patt_FF;
+
+       bad_ebs = kzalloc(ebcnt, GFP_KERNEL);
+       if (!bad_ebs)
+               goto out_check_buf;
+
+       err = 0;
+
+       /* Initialize patterns */
+       memset(patt_FF, 0xFF, mtd->erasesize);
+       for (i = 0; i < mtd->erasesize / pgsize; i++) {
+               if (!(i & 1)) {
+                       memset(patt_5A5 + i * pgsize, 0x55, pgsize);
+                       memset(patt_A5A + i * pgsize, 0xAA, pgsize);
+               } else {
+                       memset(patt_5A5 + i * pgsize, 0xAA, pgsize);
+                       memset(patt_A5A + i * pgsize, 0x55, pgsize);
+               }
+       }
+
+       err = mtdtest_scan_for_bad_eraseblocks(mtd, bad_ebs, eb, ebcnt);
+       if (err)
+               goto out;
+
+       start_timing();
+       while (1) {
+               int i;
+               void *patt;
+
+               mtdtest_erase_good_eraseblocks(mtd, bad_ebs, eb, ebcnt);
+
+               /* Check if the eraseblocks contain only 0xFF bytes */
+               if (check) {
+                       for (i = eb; i < eb + ebcnt; i++) {
+                               if (bad_ebs[i - eb])
+                                       continue;
+                               err = check_eraseblock(i, patt_FF);
+                               if (err) {
+                                       pr_info("verify failed"
+                                              " for 0xFF... pattern\n");
+                                       goto out;
+                               }
+                               cond_resched();
+                       }
+               }
+
+               /* Write the pattern */
+               for (i = eb; i < eb + ebcnt; i++) {
+                       if (bad_ebs[i - eb])
+                               continue;
+                       if ((eb + erase_cycles) & 1)
+                               patt = patt_5A5;
+                       else
+                               patt = patt_A5A;
+                       err = write_pattern(i, patt);
+                       if (err)
+                               goto out;
+                       cond_resched();
+               }
+
+               /* Verify what we wrote */
+               if (check) {
+                       for (i = eb; i < eb + ebcnt; i++) {
+                               if (bad_ebs[i - eb])
+                                       continue;
+                               if ((eb + erase_cycles) & 1)
+                                       patt = patt_5A5;
+                               else
+                                       patt = patt_A5A;
+                               err = check_eraseblock(i, patt);
+                               if (err) {
+                                       pr_info("verify failed for %s"
+                                              " pattern\n",
+                                              ((eb + erase_cycles) & 1) ?
+                                              "0x55AA55..." : "0xAA55AA...");
+                                       goto out;
+                               }
+                               cond_resched();
+                       }
+               }
+
+               erase_cycles += 1;
+
+               if (erase_cycles % gran == 0) {
+                       long ms;
+
+                       stop_timing();
+                       ms = (finish.tv_sec - start.tv_sec) * 1000 +
+                            (finish.tv_usec - start.tv_usec) / 1000;
+                       pr_info("%08u erase cycles done, took %lu "
+                              "milliseconds (%lu seconds)\n",
+                              erase_cycles, ms, ms / 1000);
+                       start_timing();
+               }
+
+               if (!infinite && --cycles_count == 0)
+                       break;
+       }
+out:
+
+       pr_info("finished after %u erase cycles\n",
+              erase_cycles);
+       kfree(bad_ebs);
+out_check_buf:
+       kfree(check_buf);
+out_patt_FF:
+       kfree(patt_FF);
+out_patt_A5A:
+       kfree(patt_A5A);
+out_patt_5A5:
+       kfree(patt_5A5);
+out_mtd:
+       put_mtd_device(mtd);
+       if (err)
+               pr_info("error %d occurred during torturing\n", err);
+       printk(KERN_INFO "=================================================\n");
+       return err;
+}
+module_init(tort_init);
+
+static void __exit tort_exit(void)
+{
+       return;
+}
+module_exit(tort_exit);
+
+static int countdiffs(unsigned char *buf, unsigned char *check_buf,
+                     unsigned offset, unsigned len, unsigned *bytesp,
+                     unsigned *bitsp);
+static void print_bufs(unsigned char *read, unsigned char *written, int start,
+                      int len);
+
+/*
+ * Report the detailed information about how the read EB differs from what was
+ * written.
+ */
+static void report_corrupt(unsigned char *read, unsigned char *written)
+{
+       int i;
+       int bytes, bits, pages, first;
+       int offset, len;
+       size_t check_len = mtd->erasesize;
+
+       if (pgcnt)
+               check_len = pgcnt * pgsize;
+
+       bytes = bits = pages = 0;
+       for (i = 0; i < check_len; i += pgsize)
+               if (countdiffs(written, read, i, pgsize, &bytes,
+                              &bits) >= 0)
+                       pages++;
+
+       pr_info("verify fails on %d pages, %d bytes/%d bits\n",
+              pages, bytes, bits);
+       pr_info("The following is a list of all differences between"
+              " what was read from flash and what was expected\n");
+
+       for (i = 0; i < check_len; i += pgsize) {
+               cond_resched();
+               bytes = bits = 0;
+               first = countdiffs(written, read, i, pgsize, &bytes,
+                                  &bits);
+               if (first < 0)
+                       continue;
+
+               printk("-------------------------------------------------------"
+                      "----------------------------------\n");
+
+               pr_info("Page %zd has %d bytes/%d bits failing verify,"
+                      " starting at offset 0x%x\n",
+                      (mtd->erasesize - check_len + i) / pgsize,
+                      bytes, bits, first);
+
+               offset = first & ~0x7;
+               len = ((first + bytes) | 0x7) + 1 - offset;
+
+               print_bufs(read, written, offset, len);
+       }
+}
+
+static void print_bufs(unsigned char *read, unsigned char *written, int start,
+                      int len)
+{
+       int i = 0, j1, j2;
+       char *diff;
+
+       printk("Offset       Read                          Written\n");
+       while (i < len) {
+               printk("0x%08x: ", start + i);
+               diff = "   ";
+               for (j1 = 0; j1 < 8 && i + j1 < len; j1++) {
+                       printk(" %02x", read[start + i + j1]);
+                       if (read[start + i + j1] != written[start + i + j1])
+                               diff = "***";
+               }
+
+               while (j1 < 8) {
+                       printk(" ");
+                       j1 += 1;
+               }
+
+               printk("  %s ", diff);
+
+               for (j2 = 0; j2 < 8 && i + j2 < len; j2++)
+                       printk(" %02x", written[start + i + j2]);
+               printk("\n");
+               i += 8;
+       }
+}
+
+/*
+ * Count the number of differing bytes and bits and return the first differing
+ * offset.
+ */
+static int countdiffs(unsigned char *buf, unsigned char *check_buf,
+                     unsigned offset, unsigned len, unsigned *bytesp,
+                     unsigned *bitsp)
+{
+       unsigned i, bit;
+       int first = -1;
+
+       for (i = offset; i < offset + len; i++)
+               if (buf[i] != check_buf[i]) {
+                       first = i;
+                       break;
+               }
+
+       while (i < offset + len) {
+               if (buf[i] != check_buf[i]) {
+                       (*bytesp)++;
+                       bit = 1;
+                       while (bit < 256) {
+                               if ((buf[i] & bit) != (check_buf[i] & bit))
+                                       (*bitsp)++;
+                               bit <<= 1;
+                       }
+               }
+               i++;
+       }
+
+       return first;
+}
+
+MODULE_DESCRIPTION("Eraseblock torturing module");
+MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter");
+MODULE_LICENSE("GPL");
index 154275182b4b22d8943e4be1ba6d5eb119694e3a..f5aa4b02cfa676f3270dc9b9a87bd87ef031893d 100644 (file)
@@ -1343,7 +1343,7 @@ out:
 static int invalidate_fastmap(struct ubi_device *ubi,
                              struct ubi_fastmap_layout *fm)
 {
-       int ret, i;
+       int ret;
        struct ubi_vid_hdr *vh;
 
        ret = erase_block(ubi, fm->e[0]->pnum);
@@ -1360,9 +1360,6 @@ static int invalidate_fastmap(struct ubi_device *ubi,
        vh->sqnum = cpu_to_be64(ubi_next_sqnum(ubi));
        ret = ubi_io_write_vid_hdr(ubi, fm->e[0]->pnum, vh);
 
-       for (i = 0; i < fm->used_blocks; i++)
-               ubi_wl_put_fm_peb(ubi, fm->e[i], i, fm->to_be_tortured[i]);
-
        return ret;
 }
 
index 5df49d3cb5c7c05e7644bd9e534950b070336d5b..c95bfb183c62b185f2f6cc17b5d84245bdd2d13d 100644 (file)
@@ -1069,6 +1069,9 @@ static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk,
                if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) {
                        dbg_wl("no WL needed: min used EC %d, max free EC %d",
                               e1->ec, e2->ec);
+
+                       /* Give the unused PEB back */
+                       wl_tree_add(e2, &ubi->free);
                        goto out_cancel;
                }
                self_check_in_wl_tree(ubi, e1, &ubi->used);
index 91f179d5135c7542f7bbf4dfb36ea75e23dac4e7..f428ef57437279ec4bbf15e1c7e8e9b6a9da7a2c 100644 (file)
@@ -1472,7 +1472,7 @@ void bond_alb_monitor(struct work_struct *work)
        bond_info->lp_counter++;
 
        /* send learning packets */
-       if (bond_info->lp_counter >= BOND_ALB_LP_TICKS) {
+       if (bond_info->lp_counter >= BOND_ALB_LP_TICKS(bond)) {
                /* change of curr_active_slave involves swapping of mac addresses.
                 * in order to avoid this swapping from happening while
                 * sending the learning packets, the curr_slave_lock must be held for
index 28d8e4c7dc06d07e2aa396943adf6b391c7d7a61..c5eff5dafdfeab12ee4849fe75d9117d70c4859f 100644 (file)
@@ -36,14 +36,15 @@ struct slave;
                                         * Used for division - never set
                                         * to zero !!!
                                         */
-#define BOND_ALB_LP_INTERVAL       1   /* In seconds, periodic send of
-                                        * learning packets to the switch
-                                        */
+#define BOND_ALB_DEFAULT_LP_INTERVAL 1
+#define BOND_ALB_LP_INTERVAL(bond) (bond->params.lp_interval)  /* In seconds, periodic send of
+                                                                * learning packets to the switch
+                                                                */
 
 #define BOND_TLB_REBALANCE_TICKS (BOND_TLB_REBALANCE_INTERVAL \
                                  * ALB_TIMER_TICKS_PER_SEC)
 
-#define BOND_ALB_LP_TICKS (BOND_ALB_LP_INTERVAL \
+#define BOND_ALB_LP_TICKS(bond) (BOND_ALB_LP_INTERVAL(bond) \
                           * ALB_TIMER_TICKS_PER_SEC)
 
 #define TLB_HASH_TABLE_SIZE 256        /* The size of the clients hash table.
index 39e5b1c7ffe21e09273ea3d7ddb17dff9ec02d27..55bbb8b8200c5bbd6949ab255015b3a23a174fc3 100644 (file)
@@ -2404,8 +2404,8 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32
        slave->target_last_arp_rx[i] = jiffies;
 }
 
-static int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
-                       struct slave *slave)
+int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond,
+                struct slave *slave)
 {
        struct arphdr *arp = (struct arphdr *)skb->data;
        unsigned char *arp_ptr;
@@ -4416,6 +4416,7 @@ static int bond_check_params(struct bond_params *params)
        params->all_slaves_active = all_slaves_active;
        params->resend_igmp = resend_igmp;
        params->min_links = min_links;
+       params->lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL;
 
        if (primary) {
                strncpy(params->primary, primary, IFNAMSIZ);
index ce4677668e2c1a025813bc2da681ea049a74064c..c29b836749b6323fe86c35e7762b25a3c8596978 100644 (file)
@@ -349,6 +349,8 @@ static ssize_t bonding_store_mode(struct device *d,
                goto out;
        }
 
+       /* don't cache arp_validate between modes */
+       bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
        bond->params.mode = new_value;
        bond_set_mode_ops(bond, bond->params.mode);
        pr_info("%s: setting mode to %s (%d).\n",
@@ -419,27 +421,39 @@ static ssize_t bonding_store_arp_validate(struct device *d,
                                          struct device_attribute *attr,
                                          const char *buf, size_t count)
 {
-       int new_value;
        struct bonding *bond = to_bond(d);
+       int new_value, ret = count;
 
+       if (!rtnl_trylock())
+               return restart_syscall();
        new_value = bond_parse_parm(buf, arp_validate_tbl);
        if (new_value < 0) {
                pr_err("%s: Ignoring invalid arp_validate value %s\n",
                       bond->dev->name, buf);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
-       if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
+       if (bond->params.mode != BOND_MODE_ACTIVEBACKUP) {
                pr_err("%s: arp_validate only supported in active-backup mode.\n",
                       bond->dev->name);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
        pr_info("%s: setting arp_validate to %s (%d).\n",
                bond->dev->name, arp_validate_tbl[new_value].modename,
                new_value);
 
+       if (bond->dev->flags & IFF_UP) {
+               if (!new_value)
+                       bond->recv_probe = NULL;
+               else if (bond->params.arp_interval)
+                       bond->recv_probe = bond_arp_rcv;
+       }
        bond->params.arp_validate = new_value;
+out:
+       rtnl_unlock();
 
-       return count;
+       return ret;
 }
 
 static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate,
@@ -555,8 +569,8 @@ static ssize_t bonding_store_arp_interval(struct device *d,
                                          struct device_attribute *attr,
                                          const char *buf, size_t count)
 {
-       int new_value, ret = count;
        struct bonding *bond = to_bond(d);
+       int new_value, ret = count;
 
        if (!rtnl_trylock())
                return restart_syscall();
@@ -599,8 +613,13 @@ static ssize_t bonding_store_arp_interval(struct device *d,
                 * is called.
                 */
                if (!new_value) {
+                       if (bond->params.arp_validate)
+                               bond->recv_probe = NULL;
                        cancel_delayed_work_sync(&bond->arp_work);
                } else {
+                       /* arp_validate can be set only in active-backup mode */
+                       if (bond->params.arp_validate)
+                               bond->recv_probe = bond_arp_rcv;
                        cancel_delayed_work_sync(&bond->mii_work);
                        queue_delayed_work(bond->wq, &bond->arp_work, 0);
                }
@@ -1680,6 +1699,44 @@ out:
 static DEVICE_ATTR(resend_igmp, S_IRUGO | S_IWUSR,
                   bonding_show_resend_igmp, bonding_store_resend_igmp);
 
+
+static ssize_t bonding_show_lp_interval(struct device *d,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct bonding *bond = to_bond(d);
+       return sprintf(buf, "%d\n", bond->params.lp_interval);
+}
+
+static ssize_t bonding_store_lp_interval(struct device *d,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
+{
+       struct bonding *bond = to_bond(d);
+       int new_value, ret = count;
+
+       if (sscanf(buf, "%d", &new_value) != 1) {
+               pr_err("%s: no lp interval value specified.\n",
+                       bond->dev->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (new_value <= 0) {
+               pr_err ("%s: lp_interval must be between 1 and %d\n",
+                       bond->dev->name, INT_MAX);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       bond->params.lp_interval = new_value;
+out:
+       return ret;
+}
+
+static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR,
+                  bonding_show_lp_interval, bonding_store_lp_interval);
+
 static struct attribute *per_bond_attrs[] = {
        &dev_attr_slaves.attr,
        &dev_attr_mode.attr,
@@ -1710,6 +1767,7 @@ static struct attribute *per_bond_attrs[] = {
        &dev_attr_all_slaves_active.attr,
        &dev_attr_resend_igmp.attr,
        &dev_attr_min_links.attr,
+       &dev_attr_lp_interval.attr,
        NULL,
 };
 
index f7ab16185f68ef94c5e7103e8842aff1bd871fae..03cf3fd14490c4e4dcf8cd2d61f8bca99c9d55db 100644 (file)
@@ -176,6 +176,7 @@ struct bond_params {
        int tx_queues;
        int all_slaves_active;
        int resend_igmp;
+       int lp_interval;
 };
 
 struct bond_parm_tbl {
@@ -430,6 +431,7 @@ static inline bool slave_can_tx(struct slave *slave)
 
 struct bond_net;
 
+int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave);
 struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr);
 int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_device *slave_dev);
 void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int slave_id);
index e66684a438f52cf3f4fdde9e1effcec0577ceb8f..75fb1d20d6fd8ebff82f34da2b99271c1894fb4a 100644 (file)
@@ -530,7 +530,7 @@ static int bfin_mac_ethtool_setwol(struct net_device *dev,
        if (lp->wol && !lp->irq_wake_requested) {
                /* register wake irq handler */
                rc = request_irq(IRQ_MAC_WAKEDET, bfin_mac_wake_interrupt,
-                                IRQF_DISABLED, "EMAC_WAKE", dev);
+                                0, "EMAC_WAKE", dev);
                if (rc)
                        return rc;
                lp->irq_wake_requested = true;
@@ -1686,7 +1686,7 @@ static int bfin_mac_probe(struct platform_device *pdev)
        /* now, enable interrupts */
        /* register irq handler */
        rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
-                       IRQF_DISABLED, "EMAC_RX", ndev);
+                       0, "EMAC_RX", ndev);
        if (rc) {
                dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
                rc = -EBUSY;
index 3d86ffeb4e15919b0b3efb21205b4195127ba79d..94edc9c6fbbf317765d41d8d4ba9cfc6b817ec20 100644 (file)
@@ -725,6 +725,7 @@ static irqreturn_t lance_dma_merr_int(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
 
+       clear_ioasic_dma_irq(irq);
        printk(KERN_ERR "%s: DMA error\n", dev->name);
        return IRQ_HANDLED;
 }
index d6b20296b8e46a7273f0f15296129fbe75d0e02a..3d8c6b2cdea4ca5906e0abb09a0523a5aa03b74c 100644 (file)
@@ -358,7 +358,7 @@ static int __init lance_probe( struct net_device *dev)
 
        REGA(CSR0) = CSR0_STOP;
 
-       if (request_irq(LANCE_IRQ, lance_interrupt, IRQF_DISABLED, "SUN3 Lance", dev) < 0) {
+       if (request_irq(LANCE_IRQ, lance_interrupt, 0, "SUN3 Lance", dev) < 0) {
 #ifdef CONFIG_SUN3
                iounmap((void __iomem *)ioaddr);
 #endif
index 027398ebbba6aae4bfe946bd6d74bc002f671cab..fc95b235e210d058545efd889537c2a8dea08a45 100644 (file)
@@ -1188,7 +1188,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct alx_priv *alx;
        struct alx_hw *hw;
        bool phy_configured;
-       int bars, pm_cap, err;
+       int bars, err;
 
        err = pci_enable_device_mem(pdev);
        if (err)
@@ -1225,18 +1225,13 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_enable_pcie_error_reporting(pdev);
        pci_set_master(pdev);
 
-       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pm_cap == 0) {
+       if (!pdev->pm_cap) {
                dev_err(&pdev->dev,
                        "Can't find power management capability, aborting\n");
                err = -EIO;
                goto out_pci_release;
        }
 
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err)
-               goto out_pci_release;
-
        netdev = alloc_etherdev(sizeof(*alx));
        if (!netdev) {
                err = -ENOMEM;
index 8ac48fbf8a66bf9fbda6171cf791cb26063ea516..b9a5fb6400d3cf1917511dec27c92486a46f12fc 100644 (file)
@@ -926,13 +926,13 @@ static int bcm_enet_open(struct net_device *dev)
        if (ret)
                goto out_phy_disconnect;
 
-       ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, IRQF_DISABLED,
+       ret = request_irq(priv->irq_rx, bcm_enet_isr_dma, 0,
                          dev->name, dev);
        if (ret)
                goto out_freeirq;
 
        ret = request_irq(priv->irq_tx, bcm_enet_isr_dma,
-                         IRQF_DISABLED, dev->name, dev);
+                         0, dev->name, dev);
        if (ret)
                goto out_freeirq_rx;
 
@@ -2156,13 +2156,13 @@ static int bcm_enetsw_open(struct net_device *dev)
        enet_dmac_writel(priv, 0, ENETDMAC_IRMASK, priv->tx_chan);
 
        ret = request_irq(priv->irq_rx, bcm_enet_isr_dma,
-                         IRQF_DISABLED, dev->name, dev);
+                         0, dev->name, dev);
        if (ret)
                goto out_freeirq;
 
        if (priv->irq_tx != -1) {
                ret = request_irq(priv->irq_tx, bcm_enet_isr_dma,
-                                 IRQF_DISABLED, dev->name, dev);
+                                 0, dev->name, dev);
                if (ret)
                        goto out_freeirq_rx;
        }
index eec0af45b85996b2cdb02a2509563e944f93a742..249468f953651480a5e0b897d582dd09743c6c3b 100644 (file)
@@ -157,6 +157,7 @@ static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
        if (++ring->end >= BGMAC_TX_RING_SLOTS)
                ring->end = 0;
        bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
+                   ring->index_base +
                    ring->end * sizeof(struct bgmac_dma_desc));
 
        /* Always keep one slot free to allow detecting bugged calls. */
@@ -181,6 +182,8 @@ static void bgmac_dma_tx_free(struct bgmac *bgmac, struct bgmac_dma_ring *ring)
        /* The last slot that hardware didn't consume yet */
        empty_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_TX_STATUS);
        empty_slot &= BGMAC_DMA_TX_STATDPTR;
+       empty_slot -= ring->index_base;
+       empty_slot &= BGMAC_DMA_TX_STATDPTR;
        empty_slot /= sizeof(struct bgmac_dma_desc);
 
        while (ring->start != empty_slot) {
@@ -274,6 +277,8 @@ static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
 
        end_slot = bgmac_read(bgmac, ring->mmio_base + BGMAC_DMA_RX_STATUS);
        end_slot &= BGMAC_DMA_RX_STATDPTR;
+       end_slot -= ring->index_base;
+       end_slot &= BGMAC_DMA_RX_STATDPTR;
        end_slot /= sizeof(struct bgmac_dma_desc);
 
        ring->end = end_slot;
@@ -418,9 +423,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                ring = &bgmac->tx_ring[i];
                ring->num_slots = BGMAC_TX_RING_SLOTS;
                ring->mmio_base = ring_base[i];
-               if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_TX))
-                       bgmac_warn(bgmac, "TX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
-                                  ring->mmio_base);
 
                /* Alloc ring of descriptors */
                size = ring->num_slots * sizeof(struct bgmac_dma_desc);
@@ -435,6 +437,13 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                if (ring->dma_base & 0xC0000000)
                        bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
+               ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
+                                                     BGMAC_DMA_RING_TX);
+               if (ring->unaligned)
+                       ring->index_base = lower_32_bits(ring->dma_base);
+               else
+                       ring->index_base = 0;
+
                /* No need to alloc TX slots yet */
        }
 
@@ -444,9 +453,6 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                ring = &bgmac->rx_ring[i];
                ring->num_slots = BGMAC_RX_RING_SLOTS;
                ring->mmio_base = ring_base[i];
-               if (bgmac_dma_unaligned(bgmac, ring, BGMAC_DMA_RING_RX))
-                       bgmac_warn(bgmac, "RX on ring 0x%X supports unaligned addressing but this feature is not implemented\n",
-                                  ring->mmio_base);
 
                /* Alloc ring of descriptors */
                size = ring->num_slots * sizeof(struct bgmac_dma_desc);
@@ -462,6 +468,13 @@ static int bgmac_dma_alloc(struct bgmac *bgmac)
                if (ring->dma_base & 0xC0000000)
                        bgmac_warn(bgmac, "DMA address using 0xC0000000 bit(s), it may need translation trick\n");
 
+               ring->unaligned = bgmac_dma_unaligned(bgmac, ring,
+                                                     BGMAC_DMA_RING_RX);
+               if (ring->unaligned)
+                       ring->index_base = lower_32_bits(ring->dma_base);
+               else
+                       ring->index_base = 0;
+
                /* Alloc RX slots */
                for (j = 0; j < ring->num_slots; j++) {
                        err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
@@ -489,12 +502,14 @@ static void bgmac_dma_init(struct bgmac *bgmac)
        for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
                ring = &bgmac->tx_ring[i];
 
-               /* We don't implement unaligned addressing, so enable first */
-               bgmac_dma_tx_enable(bgmac, ring);
+               if (!ring->unaligned)
+                       bgmac_dma_tx_enable(bgmac, ring);
                bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGLO,
                            lower_32_bits(ring->dma_base));
                bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_RINGHI,
                            upper_32_bits(ring->dma_base));
+               if (ring->unaligned)
+                       bgmac_dma_tx_enable(bgmac, ring);
 
                ring->start = 0;
                ring->end = 0;  /* Points the slot that should *not* be read */
@@ -505,12 +520,14 @@ static void bgmac_dma_init(struct bgmac *bgmac)
 
                ring = &bgmac->rx_ring[i];
 
-               /* We don't implement unaligned addressing, so enable first */
-               bgmac_dma_rx_enable(bgmac, ring);
+               if (!ring->unaligned)
+                       bgmac_dma_rx_enable(bgmac, ring);
                bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGLO,
                            lower_32_bits(ring->dma_base));
                bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_RINGHI,
                            upper_32_bits(ring->dma_base));
+               if (ring->unaligned)
+                       bgmac_dma_rx_enable(bgmac, ring);
 
                for (j = 0, dma_desc = ring->cpu_base; j < ring->num_slots;
                     j++, dma_desc++) {
@@ -531,6 +548,7 @@ static void bgmac_dma_init(struct bgmac *bgmac)
                }
 
                bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
+                           ring->index_base +
                            ring->num_slots * sizeof(struct bgmac_dma_desc));
 
                ring->start = 0;
@@ -908,10 +926,10 @@ static void bgmac_chip_reset(struct bgmac *bgmac)
                struct bcma_drv_cc *cc = &bgmac->core->bus->drv_cc;
                u8 et_swtype = 0;
                u8 sw_type = BGMAC_CHIPCTL_1_SW_TYPE_EPHY |
-                            BGMAC_CHIPCTL_1_IF_TYPE_RMII;
-               char buf[2];
+                            BGMAC_CHIPCTL_1_IF_TYPE_MII;
+               char buf[4];
 
-               if (bcm47xx_nvram_getenv("et_swtype", buf, 1) > 0) {
+               if (bcm47xx_nvram_getenv("et_swtype", buf, sizeof(buf)) > 0) {
                        if (kstrtou8(buf, 0, &et_swtype))
                                bgmac_err(bgmac, "Failed to parse et_swtype (%s)\n",
                                          buf);
index 98d4b5fcc070b4c0d10fbf09d9510dd6570492d3..66c8afbdc8c7fd863337da4795df8df9443ae120 100644 (file)
 
 #define BGMAC_CHIPCTL_1_IF_TYPE_MASK           0x00000030
 #define BGMAC_CHIPCTL_1_IF_TYPE_RMII           0x00000000
-#define BGMAC_CHIPCTL_1_IF_TYPE_MI             0x00000010
+#define BGMAC_CHIPCTL_1_IF_TYPE_MII            0x00000010
 #define BGMAC_CHIPCTL_1_IF_TYPE_RGMII          0x00000020
 #define BGMAC_CHIPCTL_1_SW_TYPE_MASK           0x000000C0
 #define BGMAC_CHIPCTL_1_SW_TYPE_EPHY           0x00000000
@@ -384,6 +384,8 @@ struct bgmac_dma_ring {
        u16 mmio_base;
        struct bgmac_dma_desc *cpu_base;
        dma_addr_t dma_base;
+       u32 index_base; /* Used for unaligned rings only, otherwise 0 */
+       bool unaligned;
 
        struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
 };
index 0c338026ce01e4473c2f28fc4f288fc122185670..97b3d32a98bd010ab1a1327ef7382e5bd64139b8 100644 (file)
@@ -246,8 +246,37 @@ enum {
        BNX2X_MAX_CNIC_ETH_CL_ID_IDX,
 };
 
-#define BNX2X_CNIC_START_ETH_CID(bp)   (BNX2X_NUM_NON_CNIC_QUEUES(bp) *\
+/* use a value high enough to be above all the PFs, which has least significant
+ * nibble as 8, so when cnic needs to come up with a CID for UIO to use to
+ * calculate doorbell address according to old doorbell configuration scheme
+ * (db_msg_sz 1 << 7 * cid + 0x40 DPM offset) it can come up with a valid number
+ * We must avoid coming up with cid 8 for iscsi since according to this method
+ * the designated UIO cid will come out 0 and it has a special handling for that
+ * case which doesn't suit us. Therefore will will cieling to closes cid which
+ * has least signigifcant nibble 8 and if it is 8 we will move forward to 0x18.
+ */
+
+#define BNX2X_1st_NON_L2_ETH_CID(bp)   (BNX2X_NUM_NON_CNIC_QUEUES(bp) * \
                                         (bp)->max_cos)
+/* amount of cids traversed by UIO's DPM addition to doorbell */
+#define UIO_DPM                                8
+/* roundup to DPM offset */
+#define UIO_ROUNDUP(bp)                        (roundup(BNX2X_1st_NON_L2_ETH_CID(bp), \
+                                        UIO_DPM))
+/* offset to nearest value which has lsb nibble matching DPM */
+#define UIO_CID_OFFSET(bp)             ((UIO_ROUNDUP(bp) + UIO_DPM) % \
+                                        (UIO_DPM * 2))
+/* add offset to rounded-up cid to get a value which could be used with UIO */
+#define UIO_DPM_ALIGN(bp)              (UIO_ROUNDUP(bp) + UIO_CID_OFFSET(bp))
+/* but wait - avoid UIO special case for cid 0 */
+#define UIO_DPM_CID0_OFFSET(bp)                ((UIO_DPM * 2) * \
+                                        (UIO_DPM_ALIGN(bp) == UIO_DPM))
+/* Properly DPM aligned CID dajusted to cid 0 secal case */
+#define BNX2X_CNIC_START_ETH_CID(bp)   (UIO_DPM_ALIGN(bp) + \
+                                        (UIO_DPM_CID0_OFFSET(bp)))
+/* how many cids were wasted  - need this value for cid allocation */
+#define UIO_CID_PAD(bp)                        (BNX2X_CNIC_START_ETH_CID(bp) - \
+                                        BNX2X_1st_NON_L2_ETH_CID(bp))
        /* iSCSI L2 */
 #define        BNX2X_ISCSI_ETH_CID(bp)         (BNX2X_CNIC_START_ETH_CID(bp))
        /* FCoE L2 */
@@ -1542,7 +1571,6 @@ struct bnx2x {
         */
        bool                    fcoe_init;
 
-       int                     pm_cap;
        int                     mrrs;
 
        struct delayed_work     sp_task;
@@ -1681,10 +1709,11 @@ struct bnx2x {
  * Maximum CID count that might be required by the bnx2x:
  * Max RSS * Max_Tx_Multi_Cos + FCoE + iSCSI
  */
+
 #define BNX2X_L2_CID_COUNT(bp) (BNX2X_NUM_ETH_QUEUES(bp) * BNX2X_MULTI_TX_COS \
-                               + 2 * CNIC_SUPPORT(bp))
+                               + CNIC_SUPPORT(bp) * (2 + UIO_CID_PAD(bp)))
 #define BNX2X_L2_MAX_CID(bp)   (BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS \
-                               + 2 * CNIC_SUPPORT(bp))
+                               + CNIC_SUPPORT(bp) * (2 + UIO_CID_PAD(bp)))
 #define L2_ILT_LINES(bp)       (DIV_ROUND_UP(BNX2X_L2_CID_COUNT(bp),\
                                        ILT_PAGE_CIDS))
 
index 2361bf236ce302f112bd333014212d60d344dc28..61726af1de6ede3c111d07040e5dec8f4440884a 100644 (file)
@@ -490,10 +490,10 @@ static void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags,
        NAPI_GRO_CB(skb)->count = num_of_coalesced_segs;
 }
 
-static int bnx2x_alloc_rx_sge(struct bnx2x *bp,
-                             struct bnx2x_fastpath *fp, u16 index)
+static int bnx2x_alloc_rx_sge(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+                             u16 index, gfp_t gfp_mask)
 {
-       struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT);
+       struct page *page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT);
        struct sw_rx_page *sw_buf = &fp->rx_page_ring[index];
        struct eth_rx_sge *sge = &fp->rx_sge_ring[index];
        dma_addr_t mapping;
@@ -572,7 +572,7 @@ static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp,
 
                /* If we fail to allocate a substitute page, we simply stop
                   where we are and drop the whole packet */
-               err = bnx2x_alloc_rx_sge(bp, fp, sge_idx);
+               err = bnx2x_alloc_rx_sge(bp, fp, sge_idx, GFP_ATOMIC);
                if (unlikely(err)) {
                        bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++;
                        return err;
@@ -616,12 +616,17 @@ static void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data)
                kfree(data);
 }
 
-static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp)
+static void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp, gfp_t gfp_mask)
 {
-       if (fp->rx_frag_size)
+       if (fp->rx_frag_size) {
+               /* GFP_KERNEL allocations are used only during initialization */
+               if (unlikely(gfp_mask & __GFP_WAIT))
+                       return (void *)__get_free_page(gfp_mask);
+
                return netdev_alloc_frag(fp->rx_frag_size);
+       }
 
-       return kmalloc(fp->rx_buf_size + NET_SKB_PAD, GFP_ATOMIC);
+       return kmalloc(fp->rx_buf_size + NET_SKB_PAD, gfp_mask);
 }
 
 #ifdef CONFIG_INET
@@ -701,7 +706,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp,
                goto drop;
 
        /* Try to allocate the new data */
-       new_data = bnx2x_frag_alloc(fp);
+       new_data = bnx2x_frag_alloc(fp, GFP_ATOMIC);
        /* Unmap skb in the pool anyway, as we are going to change
           pool entry status to BNX2X_TPA_STOP even if new skb allocation
           fails. */
@@ -752,15 +757,15 @@ drop:
        bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed++;
 }
 
-static int bnx2x_alloc_rx_data(struct bnx2x *bp,
-                              struct bnx2x_fastpath *fp, u16 index)
+static int bnx2x_alloc_rx_data(struct bnx2x *bp, struct bnx2x_fastpath *fp,
+                              u16 index, gfp_t gfp_mask)
 {
        u8 *data;
        struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index];
        struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index];
        dma_addr_t mapping;
 
-       data = bnx2x_frag_alloc(fp);
+       data = bnx2x_frag_alloc(fp, gfp_mask);
        if (unlikely(data == NULL))
                return -ENOMEM;
 
@@ -953,7 +958,8 @@ int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget)
                        memcpy(skb->data, data + pad, len);
                        bnx2x_reuse_rx_data(fp, bd_cons, bd_prod);
                } else {
-                       if (likely(bnx2x_alloc_rx_data(bp, fp, bd_prod) == 0)) {
+                       if (likely(bnx2x_alloc_rx_data(bp, fp, bd_prod,
+                                                      GFP_ATOMIC) == 0)) {
                                dma_unmap_single(&bp->pdev->dev,
                                                 dma_unmap_addr(rx_buf, mapping),
                                                 fp->rx_buf_size,
@@ -1313,7 +1319,8 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                                struct sw_rx_bd *first_buf =
                                        &tpa_info->first_buf;
 
-                               first_buf->data = bnx2x_frag_alloc(fp);
+                               first_buf->data =
+                                       bnx2x_frag_alloc(fp, GFP_KERNEL);
                                if (!first_buf->data) {
                                        BNX2X_ERR("Failed to allocate TPA skb pool for queue[%d] - disabling TPA on this queue!\n",
                                                  j);
@@ -1335,7 +1342,8 @@ void bnx2x_init_rx_rings(struct bnx2x *bp)
                        for (i = 0, ring_prod = 0;
                             i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) {
 
-                               if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) {
+                               if (bnx2x_alloc_rx_sge(bp, fp, ring_prod,
+                                                      GFP_KERNEL) < 0) {
                                        BNX2X_ERR("was only able to allocate %d rx sges\n",
                                                  i);
                                        BNX2X_ERR("disabling TPA for queue[%d]\n",
@@ -3000,16 +3008,16 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
        u16 pmcsr;
 
        /* If there is no power capability, silently succeed */
-       if (!bp->pm_cap) {
+       if (!bp->pdev->pm_cap) {
                BNX2X_DEV_INFO("No power capability. Breaking.\n");
                return 0;
        }
 
-       pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
+       pci_read_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL, &pmcsr);
 
        switch (state) {
        case PCI_D0:
-               pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+               pci_write_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL,
                                      ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
                                       PCI_PM_CTRL_PME_STATUS));
 
@@ -3033,7 +3041,7 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state)
                if (bp->wol)
                        pmcsr |= PCI_PM_CTRL_PME_ENABLE;
 
-               pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
+               pci_write_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL,
                                      pmcsr);
 
                /* No more memory access after this point until
@@ -4221,7 +4229,7 @@ static int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp,
         * fp->eth_q_stats.rx_skb_alloc_failed = 0
         */
        for (i = 0; i < rx_ring_size; i++) {
-               if (bnx2x_alloc_rx_data(bp, fp, ring_prod) < 0) {
+               if (bnx2x_alloc_rx_data(bp, fp, ring_prod, GFP_KERNEL) < 0) {
                        failure_cnt++;
                        continue;
                }
index 2612e3c715d4c0f198d458a69dcfba5d686c3300..324de5f05332e78aa6c108d23891105880ee5bd8 100644 (file)
@@ -1387,9 +1387,9 @@ static bool bnx2x_is_nvm_accessible(struct bnx2x *bp)
        u16 pm = 0;
        struct net_device *dev = pci_get_drvdata(bp->pdev);
 
-       if (bp->pm_cap)
+       if (bp->pdev->pm_cap)
                rc = pci_read_config_word(bp->pdev,
-                                         bp->pm_cap + PCI_PM_CTRL, &pm);
+                                         bp->pdev->pm_cap + PCI_PM_CTRL, &pm);
 
        if ((rc && !netif_running(dev)) ||
            (!rc && ((pm & PCI_PM_CTRL_STATE_MASK) != (__force u16)PCI_D0)))
index 634a793c1c462ab429261a7388867db81bfaaeb8..a6704b555042dfd26eab956f64082578bcf51a09 100644 (file)
@@ -7645,6 +7645,7 @@ static int bnx2x_init_hw_func(struct bnx2x *bp)
 
        bnx2x_init_block(bp, BLOCK_TM, init_phase);
        bnx2x_init_block(bp, BLOCK_DORQ, init_phase);
+       REG_WR(bp, DORQ_REG_MODE_ACT, 1); /* no dpm */
 
        bnx2x_iov_init_dq(bp);
 
@@ -8651,6 +8652,7 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
        else if (bp->wol) {
                u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
                u8 *mac_addr = bp->dev->dev_addr;
+               struct pci_dev *pdev = bp->pdev;
                u32 val;
                u16 pmc;
 
@@ -8667,9 +8669,9 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode)
                EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val);
 
                /* Enable the PME and clear the status */
-               pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmc);
+               pci_read_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, &pmc);
                pmc |= PCI_PM_CTRL_PME_ENABLE | PCI_PM_CTRL_PME_STATUS;
-               pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, pmc);
+               pci_write_config_word(pdev, pdev->pm_cap + PCI_PM_CTRL, pmc);
 
                reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN;
 
@@ -10398,7 +10400,7 @@ static void bnx2x_get_common_hwinfo(struct bnx2x *bp)
                break;
        }
 
-       pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc);
+       pci_read_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_PMC, &pmc);
        bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG;
 
        BNX2X_DEV_INFO("%sWoL capable\n",
@@ -12140,8 +12142,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
        }
 
        if (IS_PF(bp)) {
-               bp->pm_cap = pdev->pm_cap;
-               if (bp->pm_cap == 0) {
+               if (!pdev->pm_cap) {
                        dev_err(&bp->pdev->dev,
                                "Cannot find power management capability, aborting\n");
                        rc = -EIO;
@@ -13631,6 +13632,10 @@ void bnx2x_setup_cnic_info(struct bnx2x *bp)
        cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID(bp);
        cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID(bp);
 
+       DP(NETIF_MSG_IFUP, "BNX2X_1st_NON_L2_ETH_CID(bp) %x, cp->starting_cid %x, cp->fcoe_init_cid %x, cp->iscsi_l2_cid %x\n",
+          BNX2X_1st_NON_L2_ETH_CID(bp), cp->starting_cid, cp->fcoe_init_cid,
+          cp->iscsi_l2_cid);
+
        if (NO_ISCSI_OOO(bp))
                cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO;
 }
index b26eb83069b6b45c608f25a037386a151a73a2b9..2604b6204abe03965cf0f89dd48b5a25bf00e7e1 100644 (file)
@@ -1756,9 +1756,6 @@ void bnx2x_iov_init_dq(struct bnx2x *bp)
        REG_WR(bp, DORQ_REG_VF_TYPE_MIN_MCID_0, 0);
        REG_WR(bp, DORQ_REG_VF_TYPE_MAX_MCID_0, 0x1ffff);
 
-       /* set the number of VF allowed doorbells to the full DQ range */
-       REG_WR(bp, DORQ_REG_VF_NORM_MAX_CID_COUNT, 0x20000);
-
        /* set the VF doorbell threshold */
        REG_WR(bp, DORQ_REG_VF_USAGE_CT_LIMIT, 4);
 }
index 8142480d9770ff5f3aa19e4d24eaae615e4e75c4..99394bd49a139414776df9ff776c02b2fe6f3c26 100644 (file)
@@ -3135,6 +3135,7 @@ static void cnic_service_bnx2x_bh(unsigned long data)
 {
        struct cnic_dev *dev = (struct cnic_dev *) data;
        struct cnic_local *cp = dev->cnic_priv;
+       struct bnx2x *bp = netdev_priv(dev->netdev);
        u32 status_idx, new_status_idx;
 
        if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
@@ -3146,7 +3147,7 @@ static void cnic_service_bnx2x_bh(unsigned long data)
                CNIC_WR16(dev, cp->kcq1.io_addr,
                          cp->kcq1.sw_prod_idx + MAX_KCQ_IDX);
 
-               if (cp->ethdev->drv_state & CNIC_DRV_STATE_NO_FCOE) {
+               if (!CNIC_SUPPORTS_FCOE(bp)) {
                        cp->arm_int(dev, status_idx);
                        break;
                }
@@ -5217,7 +5218,8 @@ static void cnic_init_rings(struct cnic_dev *dev)
                                "iSCSI CLIENT_SETUP did not complete\n");
                cnic_spq_completion(dev, DRV_CTL_RET_L2_SPQ_CREDIT_CMD, 1);
                cnic_ring_ctl(dev, cid, cli, 1);
-               *cid_ptr = cid;
+               *cid_ptr = cid >> 4;
+               *(cid_ptr + 1) = cid * bp->db_size;
        }
 }
 
index 5701f3d1a169a207440c3ec92da789d6ea948536..12d961c4ebcaf704e36b83c8624633c2fbd48dda 100644 (file)
@@ -3034,6 +3034,7 @@ static bool tg3_phy_led_bug(struct tg3 *tp)
 {
        switch (tg3_asic_rev(tp)) {
        case ASIC_REV_5719:
+       case ASIC_REV_5720:
                if ((tp->phy_flags & TG3_PHYFLG_MII_SERDES) &&
                    !tp->pci_fn)
                        return true;
@@ -16192,12 +16193,12 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent)
                         * So explicitly force the chip into D0 here.
                         */
                        pci_read_config_dword(tp->pdev,
-                                             tp->pm_cap + PCI_PM_CTRL,
+                                             tp->pdev->pm_cap + PCI_PM_CTRL,
                                              &pm_reg);
                        pm_reg &= ~PCI_PM_CTRL_STATE_MASK;
                        pm_reg |= PCI_PM_CTRL_PME_ENABLE | 0 /* D0 */;
                        pci_write_config_dword(tp->pdev,
-                                              tp->pm_cap + PCI_PM_CTRL,
+                                              tp->pdev->pm_cap + PCI_PM_CTRL,
                                               pm_reg);
 
                        /* Also, force SERR#/PERR# in PCI command. */
@@ -17346,7 +17347,6 @@ static int tg3_init_one(struct pci_dev *pdev,
        tp = netdev_priv(dev);
        tp->pdev = pdev;
        tp->dev = dev;
-       tp->pm_cap = pdev->pm_cap;
        tp->rx_mode = TG3_DEF_RX_MODE;
        tp->tx_mode = TG3_DEF_TX_MODE;
        tp->irq_sync = 1;
index ddb8be1298eab2b66eac319a4abce91a72da8896..70257808aa37deb3c2ff0511a16a6966a8d5f9c0 100644 (file)
@@ -3234,7 +3234,6 @@ struct tg3 {
        u8                              pci_lat_timer;
 
        int                             pci_fn;
-       int                             pm_cap;
        int                             msi_cap;
        int                             pcix_cap;
        int                             pcie_readrq;
index 8030cc0396fd22f1568fb0ded2eb3823b5bdd700..751d5c7b312dc39c32aba0636a0cc668ff946a44 100644 (file)
@@ -22,7 +22,7 @@ if NET_CADENCE
 
 config ARM_AT91_ETHER
        tristate "AT91RM9200 Ethernet support"
-       depends on GENERIC_HARDIRQS && HAS_DMA
+       depends on HAS_DMA
        select MACB
        ---help---
          If you wish to compile a kernel for the AT91RM9200 and enable
index 0d0665ca6f1914f77fa3aa23b68254d42fcd0c86..c73cabdbd4c08a22fd506eef8a219f02833fb4b3 100644 (file)
@@ -6149,8 +6149,10 @@ static int __init cxgb4_init_module(void)
                pr_warn("could not create debugfs entry, continuing\n");
 
        ret = pci_register_driver(&cxgb4_driver);
-       if (ret < 0)
+       if (ret < 0) {
                debugfs_remove(cxgb4_debugfs_root);
+               destroy_workqueue(workq);
+       }
 
        register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
 
index 2db6c573cec7744c49d6cc205fce25476f0cc0ea..263b92c00cbfb34dbc3b1904cd2ddacafdeb48cc 100644 (file)
@@ -1321,7 +1321,7 @@ de4x5_open(struct net_device *dev)
     if (request_irq(dev->irq, de4x5_interrupt, IRQF_SHARED,
                                                     lp->adapter_name, dev)) {
        printk("de4x5_open(): Requested IRQ%d is busy - attemping FAST/SHARE...", dev->irq);
-       if (request_irq(dev->irq, de4x5_interrupt, IRQF_DISABLED | IRQF_SHARED,
+       if (request_irq(dev->irq, de4x5_interrupt, IRQF_SHARED,
                                                     lp->adapter_name, dev)) {
            printk("\n              Cannot get IRQ- reconfigure your hardware.\n");
            disable_ast(dev);
index 3224d28cdad4384d4322bd5765d503ef9ace1ca1..100b528b9bd0f85bf26b778b0d928966d11d419a 100644 (file)
@@ -2802,7 +2802,7 @@ static int be_vfs_if_create(struct be_adapter *adapter)
        struct be_resources res = {0};
        struct be_vf_cfg *vf_cfg;
        u32 cap_flags, en_flags, vf;
-       int status;
+       int status = 0;
 
        cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
                    BE_IF_FLAGS_MULTICAST;
index f9aacf5d85230c67fadaa9b892f9765da30171a7..b2793b91cc553e41e80170ac791d10b83f0e776d 100644 (file)
@@ -2199,7 +2199,7 @@ fec_probe(struct platform_device *pdev)
                        goto failed_irq;
                }
                ret = devm_request_irq(&pdev->dev, irq, fec_enet_interrupt,
-                                      IRQF_DISABLED, pdev->name, ndev);
+                                      0, pdev->name, ndev);
                if (ret)
                        goto failed_irq;
        }
index e3c7c697fc45c2e1c5670cdc6a04b6d93083a40c..91227d03274e02685d5e96fe6096e56e6af999eb 100644 (file)
@@ -1097,7 +1097,7 @@ static int hp100_open(struct net_device *dev)
        /* New: if bus is PCI or EISA, interrupts might be shared interrupts */
        if (request_irq(dev->irq, hp100_interrupt,
                        lp->bus == HP100_BUS_PCI || lp->bus ==
-                       HP100_BUS_EISA ? IRQF_SHARED : IRQF_DISABLED,
+                       HP100_BUS_EISA ? IRQF_SHARED : 0,
                        "hp100", dev)) {
                printk("hp100: %s: unable to get IRQ %d\n", dev->name, dev->irq);
                return -EAGAIN;
index 35853b43d66e860bd24e5bad2265b6dae9c9f7cc..2d1c6bdd36189f9f595ada15599301ce992330a9 100644 (file)
@@ -102,6 +102,19 @@ static int ehea_probe_adapter(struct platform_device *dev);
 
 static int ehea_remove(struct platform_device *dev);
 
+static struct of_device_id ehea_module_device_table[] = {
+       {
+               .name = "lhea",
+               .compatible = "IBM,lhea",
+       },
+       {
+               .type = "network",
+               .compatible = "IBM,lhea-ethernet",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ehea_module_device_table);
+
 static struct of_device_id ehea_device_table[] = {
        {
                .name = "lhea",
@@ -109,7 +122,6 @@ static struct of_device_id ehea_device_table[] = {
        },
        {},
 };
-MODULE_DEVICE_TABLE(of, ehea_device_table);
 
 static struct platform_driver ehea_driver = {
        .driver = {
@@ -1285,7 +1297,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
 
        ret = ibmebus_request_irq(port->qp_eq->attr.ist1,
                                  ehea_qp_aff_irq_handler,
-                                 IRQF_DISABLED, port->int_aff_name, port);
+                                 0, port->int_aff_name, port);
        if (ret) {
                netdev_err(dev, "failed registering irq for qp_aff_irq_handler:ist=%X\n",
                           port->qp_eq->attr.ist1);
@@ -1303,8 +1315,7 @@ static int ehea_reg_interrupts(struct net_device *dev)
                         "%s-queue%d", dev->name, i);
                ret = ibmebus_request_irq(pr->eq->attr.ist1,
                                          ehea_recv_irq_handler,
-                                         IRQF_DISABLED, pr->int_send_name,
-                                         pr);
+                                         0, pr->int_send_name, pr);
                if (ret) {
                        netdev_err(dev, "failed registering irq for ehea_queue port_res_nr:%d, ist=%X\n",
                                   i, pr->eq->attr.ist1);
@@ -3320,7 +3331,7 @@ static int ehea_probe_adapter(struct platform_device *dev)
        }
 
        ret = ibmebus_request_irq(adapter->neq->attr.ist1,
-                                 ehea_interrupt_neq, IRQF_DISABLED,
+                                 ehea_interrupt_neq, 0,
                                  "ehea_neq", adapter);
        if (ret) {
                dev_err(&dev->dev, "requesting NEQ IRQ failed\n");
index f0e7ed20a750b56d1bc77e6bc9151847ac09ac5b..149ac85b5f9e328d584aaa2a40d899527739edc5 100644 (file)
@@ -241,4 +241,22 @@ config IXGBEVF
          will be called ixgbevf.  MSI-X interrupt support is required
          for this driver to work correctly.
 
+config I40E
+       tristate "Intel(R) Ethernet Controller XL710 Family support"
+       depends on PCI
+       ---help---
+         This driver supports Intel(R) Ethernet Controller XL710 Family of
+         devices.  For more information on how to identify your adapter, go
+         to the Adapter & Driver ID Guide at:
+
+         <http://support.intel.com/support/network/adapter/pro100/21397.htm>
+
+         For general information and support, go to the Intel support
+         website at:
+
+         <http://support.intel.com>
+
+         To compile this driver as a module, choose M here. The module
+         will be called i40e.
+
 endif # NET_VENDOR_INTEL
index c8210e688669647bb4bcc3253efc3ee38502e5c9..5bae933efc7c95dab0c97cd22a6c479c6497d941 100644 (file)
@@ -9,4 +9,5 @@ obj-$(CONFIG_IGB) += igb/
 obj-$(CONFIG_IGBVF) += igbvf/
 obj-$(CONFIG_IXGBE) += ixgbe/
 obj-$(CONFIG_IXGBEVF) += ixgbevf/
+obj-$(CONFIG_I40E) += i40e/
 obj-$(CONFIG_IXGB) += ixgb/
index a8633b8f0ac5aaff57b2be97d8e0ac5dfe3ff36a..d14c8f53384cd415c3933015c02bf9d2a369ba11 100644 (file)
@@ -922,6 +922,14 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                        else
                                mask &= ~(1 << 30);
                }
+               if (mac->type == e1000_pch2lan) {
+                       /* SHRAH[0,1,2] different than previous */
+                       if (i == 7)
+                               mask &= 0xFFF4FFFF;
+                       /* SHRAH[3] different than SHRAH[0,1,2] */
+                       if (i == 10)
+                               mask |= (1 << 30);
+               }
 
                REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask,
                                       0xFFFFFFFF);
index af08188d7e624471ed3e8b87df7d39fd24ba3815..42f0f6717511c21bb0f16edbeee050cc4878db96 100644 (file)
@@ -1371,7 +1371,10 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index)
                return;
        }
 
-       if (index < hw->mac.rar_entry_count) {
+       /* RAR[1-6] are owned by manageability.  Skip those and program the
+        * next address into the SHRA register array.
+        */
+       if (index < (u32)(hw->mac.rar_entry_count - 6)) {
                s32 ret_val;
 
                ret_val = e1000_acquire_swflag_ich8lan(hw);
@@ -1962,8 +1965,8 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw)
        if (ret_val)
                goto release;
 
-       /* Copy both RAL/H (rar_entry_count) and SHRAL/H (+4) to PHY */
-       for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+       /* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */
+       for (i = 0; i < (hw->mac.rar_entry_count); i++) {
                mac_reg = er32(RAL(i));
                hw->phy.ops.write_reg_page(hw, BM_RAR_L(i),
                                           (u16)(mac_reg & 0xFFFF));
@@ -2007,10 +2010,10 @@ s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable)
                return ret_val;
 
        if (enable) {
-               /* Write Rx addresses (rar_entry_count for RAL/H, +4 for
+               /* Write Rx addresses (rar_entry_count for RAL/H, and
                 * SHRAL/H) and initial CRC values to the MAC
                 */
-               for (i = 0; i < (hw->mac.rar_entry_count + 4); i++) {
+               for (i = 0; i < hw->mac.rar_entry_count; i++) {
                        u8 mac_addr[ETH_ALEN] = { 0 };
                        u32 addr_high, addr_low;
 
index 59865695b2826a388b721b2313253e25d86a7c94..217090df33e788d46603f1c0369a2cf4e8041719 100644 (file)
@@ -98,7 +98,7 @@
 #define PCIE_ICH8_SNOOP_ALL    PCIE_NO_SNOOP_ALL
 
 #define E1000_ICH_RAR_ENTRIES  7
-#define E1000_PCH2_RAR_ENTRIES 5       /* RAR[0], SHRA[0-3] */
+#define E1000_PCH2_RAR_ENTRIES 11      /* RAR[0-6], SHRA[0-3] */
 #define E1000_PCH_LPT_RAR_ENTRIES      12      /* RAR[0], SHRA[0-10] */
 
 #define PHY_PAGE_SHIFT         5
index e87e9b01f404446dfca553146fa4734c2af45f79..4ef786775acb7ca6665873cae61f520a6fbc8b45 100644 (file)
@@ -4868,7 +4868,7 @@ static void e1000_watchdog_task(struct work_struct *work)
                         */
                        if ((hw->phy.type == e1000_phy_igp_3 ||
                             hw->phy.type == e1000_phy_bm) &&
-                           (hw->mac.autoneg == true) &&
+                           hw->mac.autoneg &&
                            (adapter->link_speed == SPEED_10 ||
                             adapter->link_speed == SPEED_100) &&
                            (adapter->link_duplex == HALF_DUPLEX)) {
diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile
new file mode 100644 (file)
index 0000000..479b2c4
--- /dev/null
@@ -0,0 +1,44 @@
+################################################################################
+#
+# Intel Ethernet Controller XL710 Family Linux Driver
+# Copyright(c) 2013 Intel Corporation.
+#
+# 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.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Contact Information:
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) Ethernet Connection XL710 (i40e.ko) driver
+#
+
+obj-$(CONFIG_I40E) += i40e.o
+
+i40e-objs := i40e_main.o \
+       i40e_ethtool.o  \
+       i40e_adminq.o   \
+       i40e_common.o   \
+       i40e_hmc.o      \
+       i40e_lan_hmc.o  \
+       i40e_nvm.o      \
+       i40e_debugfs.o  \
+       i40e_diag.o     \
+       i40e_txrx.o     \
+       i40e_virtchnl_pf.o
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
new file mode 100644 (file)
index 0000000..b5252eb
--- /dev/null
@@ -0,0 +1,558 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_H_
+#define _I40E_H_
+
+#include <net/tcp.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/aer.h>
+#include <linux/netdevice.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/sctp.h>
+#include <linux/pkt_sched.h>
+#include <linux/ipv6.h>
+#include <linux/version.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include "i40e_type.h"
+#include "i40e_prototype.h"
+#include "i40e_virtchnl.h"
+#include "i40e_virtchnl_pf.h"
+#include "i40e_txrx.h"
+
+/* Useful i40e defaults */
+#define I40E_BASE_PF_SEID     16
+#define I40E_BASE_VSI_SEID    512
+#define I40E_BASE_VEB_SEID    288
+#define I40E_MAX_VEB          16
+
+#define I40E_MAX_NUM_DESCRIPTORS      4096
+#define I40E_MAX_REGISTER     0x0038FFFF
+#define I40E_DEFAULT_NUM_DESCRIPTORS  512
+#define I40E_REQ_DESCRIPTOR_MULTIPLE  32
+#define I40E_MIN_NUM_DESCRIPTORS      64
+#define I40E_MIN_MSIX                 2
+#define I40E_DEFAULT_NUM_VMDQ_VSI     8 /* max 256 VSIs */
+#define I40E_DEFAULT_QUEUES_PER_VMDQ  2 /* max 16 qps */
+#define I40E_DEFAULT_QUEUES_PER_VF    4
+#define I40E_DEFAULT_QUEUES_PER_TC    1 /* should be a power of 2 */
+#define I40E_FDIR_RING                0
+#define I40E_FDIR_RING_COUNT          32
+#define I40E_MAX_AQ_BUF_SIZE          4096
+#define I40E_AQ_LEN                   32
+#define I40E_AQ_WORK_LIMIT            16
+#define I40E_MAX_USER_PRIORITY        8
+#define I40E_DEFAULT_MSG_ENABLE       4
+
+#define I40E_NVM_VERSION_LO_SHIFT  0
+#define I40E_NVM_VERSION_LO_MASK   (0xf << I40E_NVM_VERSION_LO_SHIFT)
+#define I40E_NVM_VERSION_MID_SHIFT 4
+#define I40E_NVM_VERSION_MID_MASK  (0xff << I40E_NVM_VERSION_MID_SHIFT)
+#define I40E_NVM_VERSION_HI_SHIFT  12
+#define I40E_NVM_VERSION_HI_MASK   (0xf << I40E_NVM_VERSION_HI_SHIFT)
+
+/* magic for getting defines into strings */
+#define STRINGIFY(foo)  #foo
+#define XSTRINGIFY(bar) STRINGIFY(bar)
+
+#ifndef ARCH_HAS_PREFETCH
+#define prefetch(X)
+#endif
+
+#define I40E_RX_DESC(R, i)                     \
+       ((ring_is_16byte_desc_enabled(R))       \
+               ? (union i40e_32byte_rx_desc *) \
+                       (&(((union i40e_16byte_rx_desc *)((R)->desc))[i])) \
+               : (&(((union i40e_32byte_rx_desc *)((R)->desc))[i])))
+#define I40E_TX_DESC(R, i)                     \
+       (&(((struct i40e_tx_desc *)((R)->desc))[i]))
+#define I40E_TX_CTXTDESC(R, i)                 \
+       (&(((struct i40e_tx_context_desc *)((R)->desc))[i]))
+#define I40E_TX_FDIRDESC(R, i)                 \
+       (&(((struct i40e_filter_program_desc *)((R)->desc))[i]))
+
+/* default to trying for four seconds */
+#define I40E_TRY_LINK_TIMEOUT (4 * HZ)
+
+/* driver state flags */
+enum i40e_state_t {
+       __I40E_TESTING,
+       __I40E_CONFIG_BUSY,
+       __I40E_CONFIG_DONE,
+       __I40E_DOWN,
+       __I40E_NEEDS_RESTART,
+       __I40E_SERVICE_SCHED,
+       __I40E_ADMINQ_EVENT_PENDING,
+       __I40E_MDD_EVENT_PENDING,
+       __I40E_VFLR_EVENT_PENDING,
+       __I40E_RESET_RECOVERY_PENDING,
+       __I40E_RESET_INTR_RECEIVED,
+       __I40E_REINIT_REQUESTED,
+       __I40E_PF_RESET_REQUESTED,
+       __I40E_CORE_RESET_REQUESTED,
+       __I40E_GLOBAL_RESET_REQUESTED,
+       __I40E_FILTER_OVERFLOW_PROMISC,
+};
+
+enum i40e_interrupt_policy {
+       I40E_INTERRUPT_BEST_CASE,
+       I40E_INTERRUPT_MEDIUM,
+       I40E_INTERRUPT_LOWEST
+};
+
+struct i40e_lump_tracking {
+       u16 num_entries;
+       u16 search_hint;
+       u16 list[0];
+#define I40E_PILE_VALID_BIT  0x8000
+};
+
+#define I40E_DEFAULT_ATR_SAMPLE_RATE   20
+#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512
+struct i40e_fdir_data {
+       u16 q_index;
+       u8  flex_off;
+       u8  pctype;
+       u16 dest_vsi;
+       u8  dest_ctl;
+       u8  fd_status;
+       u16 cnt_index;
+       u32 fd_id;
+       u8  *raw_packet;
+};
+
+#define I40E_DCB_PRIO_TYPE_STRICT      0
+#define I40E_DCB_PRIO_TYPE_ETS         1
+#define I40E_DCB_STRICT_PRIO_CREDITS   127
+#define I40E_MAX_USER_PRIORITY 8
+/* DCB per TC information data structure */
+struct i40e_tc_info {
+       u16     qoffset;        /* Queue offset from base queue */
+       u16     qcount;         /* Total Queues */
+       u8      netdev_tc;      /* Netdev TC index if netdev associated */
+};
+
+/* TC configuration data structure */
+struct i40e_tc_configuration {
+       u8      numtc;          /* Total number of enabled TCs */
+       u8      enabled_tc;     /* TC map */
+       struct i40e_tc_info tc_info[I40E_MAX_TRAFFIC_CLASS];
+};
+
+/* struct that defines the Ethernet device */
+struct i40e_pf {
+       struct pci_dev *pdev;
+       struct i40e_hw hw;
+       unsigned long state;
+       unsigned long link_check_timeout;
+       struct msix_entry *msix_entries;
+       u16 num_msix_entries;
+       bool fc_autoneg_status;
+
+       u16 eeprom_version;
+       u16 num_vmdq_vsis;         /* num vmdq pools this pf has set up */
+       u16 num_vmdq_qps;          /* num queue pairs per vmdq pool */
+       u16 num_vmdq_msix;         /* num queue vectors per vmdq pool */
+       u16 num_req_vfs;           /* num vfs requested for this vf */
+       u16 num_vf_qps;            /* num queue pairs per vf */
+       u16 num_tc_qps;            /* num queue pairs per TC */
+       u16 num_lan_qps;           /* num lan queues this pf has set up */
+       u16 num_lan_msix;          /* num queue vectors for the base pf vsi */
+       u16 rss_size;              /* num queues in the RSS array */
+       u16 rss_size_max;          /* HW defined max RSS queues */
+       u16 fdir_pf_filter_count;  /* num of guaranteed filters for this PF */
+       u8 atr_sample_rate;
+
+       enum i40e_interrupt_policy int_policy;
+       u16 rx_itr_default;
+       u16 tx_itr_default;
+       u16 msg_enable;
+       char misc_int_name[IFNAMSIZ + 9];
+       u16 adminq_work_limit; /* num of admin receive queue desc to process */
+       int service_timer_period;
+       struct timer_list service_timer;
+       struct work_struct service_task;
+
+       u64 flags;
+#define I40E_FLAG_RX_CSUM_ENABLED              (u64)(1 << 1)
+#define I40E_FLAG_MSI_ENABLED                  (u64)(1 << 2)
+#define I40E_FLAG_MSIX_ENABLED                 (u64)(1 << 3)
+#define I40E_FLAG_RX_1BUF_ENABLED              (u64)(1 << 4)
+#define I40E_FLAG_RX_PS_ENABLED                (u64)(1 << 5)
+#define I40E_FLAG_RSS_ENABLED                  (u64)(1 << 6)
+#define I40E_FLAG_MQ_ENABLED                   (u64)(1 << 7)
+#define I40E_FLAG_VMDQ_ENABLED                 (u64)(1 << 8)
+#define I40E_FLAG_FDIR_REQUIRES_REINIT         (u64)(1 << 9)
+#define I40E_FLAG_NEED_LINK_UPDATE             (u64)(1 << 10)
+#define I40E_FLAG_IN_NETPOLL                   (u64)(1 << 13)
+#define I40E_FLAG_16BYTE_RX_DESC_ENABLED       (u64)(1 << 14)
+#define I40E_FLAG_CLEAN_ADMINQ                 (u64)(1 << 15)
+#define I40E_FLAG_FILTER_SYNC                  (u64)(1 << 16)
+#define I40E_FLAG_PROCESS_MDD_EVENT            (u64)(1 << 18)
+#define I40E_FLAG_PROCESS_VFLR_EVENT           (u64)(1 << 19)
+#define I40E_FLAG_SRIOV_ENABLED                (u64)(1 << 20)
+#define I40E_FLAG_DCB_ENABLED                  (u64)(1 << 21)
+#define I40E_FLAG_FDIR_ENABLED                 (u64)(1 << 22)
+#define I40E_FLAG_FDIR_ATR_ENABLED             (u64)(1 << 23)
+#define I40E_FLAG_MFP_ENABLED                  (u64)(1 << 27)
+
+       u16 num_tx_queues;
+       u16 num_rx_queues;
+
+       bool stat_offsets_loaded;
+       struct i40e_hw_port_stats stats;
+       struct i40e_hw_port_stats stats_offsets;
+       u32 tx_timeout_count;
+       u32 tx_timeout_recovery_level;
+       unsigned long tx_timeout_last_recovery;
+       u32 hw_csum_rx_error;
+       u32 led_status;
+       u16 corer_count; /* Core reset count */
+       u16 globr_count; /* Global reset count */
+       u16 empr_count; /* EMP reset count */
+       u16 pfr_count; /* PF reset count */
+
+       struct mutex switch_mutex;
+       u16 lan_vsi;       /* our default LAN VSI */
+       u16 lan_veb;       /* initial relay, if exists */
+#define I40E_NO_VEB   0xffff
+#define I40E_NO_VSI   0xffff
+       u16 next_vsi;      /* Next unallocated VSI - 0-based! */
+       struct i40e_vsi **vsi;
+       struct i40e_veb *veb[I40E_MAX_VEB];
+
+       struct i40e_lump_tracking *qp_pile;
+       struct i40e_lump_tracking *irq_pile;
+
+       /* switch config info */
+       u16 pf_seid;
+       u16 main_vsi_seid;
+       u16 mac_seid;
+       struct i40e_aqc_get_switch_config_data *sw_config;
+       struct kobject *switch_kobj;
+#ifdef CONFIG_DEBUG_FS
+       struct dentry *i40e_dbg_pf;
+#endif /* CONFIG_DEBUG_FS */
+
+       /* sr-iov config info */
+       struct i40e_vf *vf;
+       int num_alloc_vfs;      /* actual number of VFs allocated */
+       u32 vf_aq_requests;
+
+       /* DCBx/DCBNL capability for PF that indicates
+        * whether DCBx is managed by firmware or host
+        * based agent (LLDPAD). Also, indicates what
+        * flavor of DCBx protocol (IEEE/CEE) is supported
+        * by the device. For now we're supporting IEEE
+        * mode only.
+        */
+       u16 dcbx_cap;
+
+       u32     fcoe_hmc_filt_num;
+       u32     fcoe_hmc_cntx_num;
+       struct i40e_filter_control_settings filter_settings;
+};
+
+struct i40e_mac_filter {
+       struct list_head list;
+       u8 macaddr[ETH_ALEN];
+#define I40E_VLAN_ANY -1
+       s16 vlan;
+       u8 counter;             /* number of instances of this filter */
+       bool is_vf;             /* filter belongs to a VF */
+       bool is_netdev;         /* filter belongs to a netdev */
+       bool changed;           /* filter needs to be sync'd to the HW */
+};
+
+struct i40e_veb {
+       struct i40e_pf *pf;
+       u16 idx;
+       u16 veb_idx;           /* index of VEB parent */
+       u16 seid;
+       u16 uplink_seid;
+       u16 stats_idx;           /* index of VEB parent */
+       u8  enabled_tc;
+       u16 flags;
+       u16 bw_limit;
+       u8  bw_max_quanta;
+       bool is_abs_credits;
+       u8  bw_tc_share_credits[I40E_MAX_TRAFFIC_CLASS];
+       u16 bw_tc_limit_credits[I40E_MAX_TRAFFIC_CLASS];
+       u8  bw_tc_max_quanta[I40E_MAX_TRAFFIC_CLASS];
+       struct kobject *kobj;
+       bool stat_offsets_loaded;
+       struct i40e_eth_stats stats;
+       struct i40e_eth_stats stats_offsets;
+};
+
+/* struct that defines a VSI, associated with a dev */
+struct i40e_vsi {
+       struct net_device *netdev;
+       unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+       bool netdev_registered;
+       bool stat_offsets_loaded;
+
+       u32 current_netdev_flags;
+       unsigned long state;
+#define I40E_VSI_FLAG_FILTER_CHANGED  (1<<0)
+#define I40E_VSI_FLAG_VEB_OWNER       (1<<1)
+       unsigned long flags;
+
+       struct list_head mac_filter_list;
+
+       /* VSI stats */
+       struct rtnl_link_stats64 net_stats;
+       struct rtnl_link_stats64 net_stats_offsets;
+       struct i40e_eth_stats eth_stats;
+       struct i40e_eth_stats eth_stats_offsets;
+       u32 tx_restart;
+       u32 tx_busy;
+       u32 rx_buf_failed;
+       u32 rx_page_failed;
+
+       /* These are arrays of rings, allocated at run-time */
+       struct i40e_ring *rx_rings;
+       struct i40e_ring *tx_rings;
+
+       u16 work_limit;
+       /* high bit set means dynamic, use accessor routines to read/write.
+        * hardware only supports 2us resolution for the ITR registers.
+        * these values always store the USER setting, and must be converted
+        * before programming to a register.
+        */
+       u16 rx_itr_setting;
+       u16 tx_itr_setting;
+
+       u16 max_frame;
+       u16 rx_hdr_len;
+       u16 rx_buf_len;
+       u8  dtype;
+
+       /* List of q_vectors allocated to this VSI */
+       struct i40e_q_vector *q_vectors;
+       int num_q_vectors;
+       int base_vector;
+
+       u16 seid;            /* HW index of this VSI (absolute index) */
+       u16 id;              /* VSI number */
+       u16 uplink_seid;
+
+       u16 base_queue;      /* vsi's first queue in hw array */
+       u16 alloc_queue_pairs; /* Allocated Tx/Rx queues */
+       u16 num_queue_pairs; /* Used tx and rx pairs */
+       u16 num_desc;
+       enum i40e_vsi_type type;  /* VSI type, e.g., LAN, FCoE, etc */
+       u16 vf_id;              /* Virtual function ID for SRIOV VSIs */
+
+       struct i40e_tc_configuration tc_config;
+       struct i40e_aqc_vsi_properties_data info;
+
+       /* VSI BW limit (absolute across all TCs) */
+       u16 bw_limit;           /* VSI BW Limit (0 = disabled) */
+       u8  bw_max_quanta;      /* Max Quanta when BW limit is enabled */
+
+       /* Relative TC credits across VSIs */
+       u8  bw_ets_share_credits[I40E_MAX_TRAFFIC_CLASS];
+       /* TC BW limit credits within VSI */
+       u16  bw_ets_limit_credits[I40E_MAX_TRAFFIC_CLASS];
+       /* TC BW limit max quanta within VSI */
+       u8  bw_ets_max_quanta[I40E_MAX_TRAFFIC_CLASS];
+
+       struct i40e_pf *back;  /* Backreference to associated PF */
+       u16 idx;               /* index in pf->vsi[] */
+       u16 veb_idx;           /* index of VEB parent */
+       struct kobject *kobj;  /* sysfs object */
+
+       /* VSI specific handlers */
+       irqreturn_t (*irq_handler)(int irq, void *data);
+} ____cacheline_internodealigned_in_smp;
+
+struct i40e_netdev_priv {
+       struct i40e_vsi *vsi;
+};
+
+/* struct that defines an interrupt vector */
+struct i40e_q_vector {
+       struct i40e_vsi *vsi;
+
+       u16 v_idx;              /* index in the vsi->q_vector array. */
+       u16 reg_idx;            /* register index of the interrupt */
+
+       struct napi_struct napi;
+
+       struct i40e_ring_container rx;
+       struct i40e_ring_container tx;
+
+       u8 num_ringpairs;       /* total number of ring pairs in vector */
+
+       char name[IFNAMSIZ + 9];
+       cpumask_t affinity_mask;
+} ____cacheline_internodealigned_in_smp;
+
+/* lan device */
+struct i40e_device {
+       struct list_head list;
+       struct i40e_pf *pf;
+};
+
+/**
+ * i40e_fw_version_str - format the FW and NVM version strings
+ * @hw: ptr to the hardware info
+ **/
+static inline char *i40e_fw_version_str(struct i40e_hw *hw)
+{
+       static char buf[32];
+
+       snprintf(buf, sizeof(buf),
+                "f%d.%d a%d.%d n%02d.%02d.%02d e%08x",
+                hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
+                hw->aq.api_maj_ver, hw->aq.api_min_ver,
+                (hw->nvm.version & I40E_NVM_VERSION_HI_MASK)
+                                               >> I40E_NVM_VERSION_HI_SHIFT,
+                (hw->nvm.version & I40E_NVM_VERSION_MID_MASK)
+                                               >> I40E_NVM_VERSION_MID_SHIFT,
+                (hw->nvm.version & I40E_NVM_VERSION_LO_MASK)
+                                               >> I40E_NVM_VERSION_LO_SHIFT,
+                hw->nvm.eetrack);
+
+       return buf;
+}
+
+/**
+ * i40e_netdev_to_pf: Retrieve the PF struct for given netdev
+ * @netdev: the corresponding netdev
+ *
+ * Return the PF struct for the given netdev
+ **/
+static inline struct i40e_pf *i40e_netdev_to_pf(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       return vsi->back;
+}
+
+static inline void i40e_vsi_setup_irqhandler(struct i40e_vsi *vsi,
+                               irqreturn_t (*irq_handler)(int, void *))
+{
+       vsi->irq_handler = irq_handler;
+}
+
+/**
+ * i40e_rx_is_programming_status - check for programming status descriptor
+ * @qw: the first quad word of the program status descriptor
+ *
+ * The value of in the descriptor length field indicate if this
+ * is a programming status descriptor for flow director or FCoE
+ * by the value of I40E_RX_PROG_STATUS_DESC_LENGTH, otherwise
+ * it is a packet descriptor.
+ **/
+static inline bool i40e_rx_is_programming_status(u64 qw)
+{
+       return I40E_RX_PROG_STATUS_DESC_LENGTH ==
+               (qw >> I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT);
+}
+
+/* needed by i40e_ethtool.c */
+int i40e_up(struct i40e_vsi *vsi);
+void i40e_down(struct i40e_vsi *vsi);
+extern const char i40e_driver_name[];
+extern const char i40e_driver_version_str[];
+void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags);
+void i40e_update_stats(struct i40e_vsi *vsi);
+void i40e_update_eth_stats(struct i40e_vsi *vsi);
+struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi);
+int i40e_fetch_switch_configuration(struct i40e_pf *pf,
+                                   bool printconfig);
+
+/* needed by i40e_main.c */
+void i40e_add_fdir_filter(struct i40e_fdir_data fdir_data,
+                         struct i40e_ring *tx_ring);
+void i40e_add_remove_filter(struct i40e_fdir_data fdir_data,
+                           struct i40e_ring *tx_ring);
+void i40e_update_fdir_filter(struct i40e_fdir_data fdir_data,
+                            struct i40e_ring *tx_ring);
+int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+                            struct i40e_pf *pf, bool add);
+
+void i40e_set_ethtool_ops(struct net_device *netdev);
+struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
+                                       u8 *macaddr, s16 vlan,
+                                       bool is_vf, bool is_netdev);
+void i40e_del_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan,
+                    bool is_vf, bool is_netdev);
+int i40e_sync_vsi_filters(struct i40e_vsi *vsi);
+struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+                               u16 uplink, u32 param1);
+int i40e_vsi_release(struct i40e_vsi *vsi);
+struct i40e_vsi *i40e_vsi_lookup(struct i40e_pf *pf, enum i40e_vsi_type type,
+                                struct i40e_vsi *start_vsi);
+struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags, u16 uplink_seid,
+                               u16 downlink_seid, u8 enabled_tc);
+void i40e_veb_release(struct i40e_veb *veb);
+
+i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid);
+void i40e_vsi_remove_pvid(struct i40e_vsi *vsi);
+void i40e_vsi_reset_stats(struct i40e_vsi *vsi);
+void i40e_pf_reset_stats(struct i40e_pf *pf);
+#ifdef CONFIG_DEBUG_FS
+void i40e_dbg_pf_init(struct i40e_pf *pf);
+void i40e_dbg_pf_exit(struct i40e_pf *pf);
+void i40e_dbg_init(void);
+void i40e_dbg_exit(void);
+#else
+static inline void i40e_dbg_pf_init(struct i40e_pf *pf) {}
+static inline void i40e_dbg_pf_exit(struct i40e_pf *pf) {}
+static inline void i40e_dbg_init(void) {}
+static inline void i40e_dbg_exit(void) {}
+#endif /* CONFIG_DEBUG_FS*/
+void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector);
+int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+void i40e_vlan_stripping_disable(struct i40e_vsi *vsi);
+int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid);
+int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid);
+struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
+                                            bool is_vf, bool is_netdev);
+bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi);
+struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
+                                     bool is_vf, bool is_netdev);
+void i40e_vlan_stripping_enable(struct i40e_vsi *vsi);
+
+#endif /* _I40E_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
new file mode 100644 (file)
index 0000000..0c524fa
--- /dev/null
@@ -0,0 +1,983 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e_status.h"
+#include "i40e_type.h"
+#include "i40e_register.h"
+#include "i40e_adminq.h"
+#include "i40e_prototype.h"
+
+/**
+ *  i40e_adminq_init_regs - Initialize AdminQ registers
+ *  @hw: pointer to the hardware structure
+ *
+ *  This assumes the alloc_asq and alloc_arq functions have already been called
+ **/
+static void i40e_adminq_init_regs(struct i40e_hw *hw)
+{
+       /* set head and tail registers in our local struct */
+       if (hw->mac.type == I40E_MAC_VF) {
+               hw->aq.asq.tail = I40E_VF_ATQT1;
+               hw->aq.asq.head = I40E_VF_ATQH1;
+               hw->aq.arq.tail = I40E_VF_ARQT1;
+               hw->aq.arq.head = I40E_VF_ARQH1;
+       } else {
+               hw->aq.asq.tail = I40E_PF_ATQT;
+               hw->aq.asq.head = I40E_PF_ATQH;
+               hw->aq.arq.tail = I40E_PF_ARQT;
+               hw->aq.arq.head = I40E_PF_ARQH;
+       }
+}
+
+/**
+ *  i40e_alloc_adminq_asq_ring - Allocate Admin Queue send rings
+ *  @hw: pointer to the hardware structure
+ **/
+static i40e_status i40e_alloc_adminq_asq_ring(struct i40e_hw *hw)
+{
+       i40e_status ret_code;
+       struct i40e_virt_mem mem;
+
+       ret_code = i40e_allocate_dma_mem(hw, &hw->aq.asq_mem,
+                                        i40e_mem_atq_ring,
+                                        (hw->aq.num_asq_entries *
+                                        sizeof(struct i40e_aq_desc)),
+                                        I40E_ADMINQ_DESC_ALIGNMENT);
+       if (ret_code)
+               return ret_code;
+
+       hw->aq.asq.desc = hw->aq.asq_mem.va;
+       hw->aq.asq.dma_addr = hw->aq.asq_mem.pa;
+
+       ret_code = i40e_allocate_virt_mem(hw, &mem,
+                                         (hw->aq.num_asq_entries *
+                                         sizeof(struct i40e_asq_cmd_details)));
+       if (ret_code) {
+               i40e_free_dma_mem(hw, &hw->aq.asq_mem);
+               hw->aq.asq_mem.va = NULL;
+               hw->aq.asq_mem.pa = 0;
+               return ret_code;
+       }
+
+       hw->aq.asq.details = mem.va;
+
+       return ret_code;
+}
+
+/**
+ *  i40e_alloc_adminq_arq_ring - Allocate Admin Queue receive rings
+ *  @hw: pointer to the hardware structure
+ **/
+static i40e_status i40e_alloc_adminq_arq_ring(struct i40e_hw *hw)
+{
+       i40e_status ret_code;
+
+       ret_code = i40e_allocate_dma_mem(hw, &hw->aq.arq_mem,
+                                        i40e_mem_arq_ring,
+                                        (hw->aq.num_arq_entries *
+                                        sizeof(struct i40e_aq_desc)),
+                                        I40E_ADMINQ_DESC_ALIGNMENT);
+       if (ret_code)
+               return ret_code;
+
+       hw->aq.arq.desc = hw->aq.arq_mem.va;
+       hw->aq.arq.dma_addr = hw->aq.arq_mem.pa;
+
+       return ret_code;
+}
+
+/**
+ *  i40e_free_adminq_asq - Free Admin Queue send rings
+ *  @hw: pointer to the hardware structure
+ *
+ *  This assumes the posted send buffers have already been cleaned
+ *  and de-allocated
+ **/
+static void i40e_free_adminq_asq(struct i40e_hw *hw)
+{
+       struct i40e_virt_mem mem;
+
+       i40e_free_dma_mem(hw, &hw->aq.asq_mem);
+       hw->aq.asq_mem.va = NULL;
+       hw->aq.asq_mem.pa = 0;
+       mem.va = hw->aq.asq.details;
+       i40e_free_virt_mem(hw, &mem);
+       hw->aq.asq.details = NULL;
+}
+
+/**
+ *  i40e_free_adminq_arq - Free Admin Queue receive rings
+ *  @hw: pointer to the hardware structure
+ *
+ *  This assumes the posted receive buffers have already been cleaned
+ *  and de-allocated
+ **/
+static void i40e_free_adminq_arq(struct i40e_hw *hw)
+{
+       i40e_free_dma_mem(hw, &hw->aq.arq_mem);
+       hw->aq.arq_mem.va = NULL;
+       hw->aq.arq_mem.pa = 0;
+}
+
+/**
+ *  i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue
+ *  @hw:     pointer to the hardware structure
+ **/
+static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw)
+{
+       i40e_status ret_code;
+       struct i40e_aq_desc *desc;
+       struct i40e_virt_mem mem;
+       struct i40e_dma_mem *bi;
+       int i;
+
+       /* We'll be allocating the buffer info memory first, then we can
+        * allocate the mapped buffers for the event processing
+        */
+
+       /* buffer_info structures do not need alignment */
+       ret_code = i40e_allocate_virt_mem(hw, &mem, (hw->aq.num_arq_entries *
+                                         sizeof(struct i40e_dma_mem)));
+       if (ret_code)
+               goto alloc_arq_bufs;
+       hw->aq.arq.r.arq_bi = (struct i40e_dma_mem *)mem.va;
+
+       /* allocate the mapped buffers */
+       for (i = 0; i < hw->aq.num_arq_entries; i++) {
+               bi = &hw->aq.arq.r.arq_bi[i];
+               ret_code = i40e_allocate_dma_mem(hw, bi,
+                                                i40e_mem_arq_buf,
+                                                hw->aq.arq_buf_size,
+                                                I40E_ADMINQ_DESC_ALIGNMENT);
+               if (ret_code)
+                       goto unwind_alloc_arq_bufs;
+
+               /* now configure the descriptors for use */
+               desc = I40E_ADMINQ_DESC(hw->aq.arq, i);
+
+               desc->flags = cpu_to_le16(I40E_AQ_FLAG_BUF);
+               if (hw->aq.arq_buf_size > I40E_AQ_LARGE_BUF)
+                       desc->flags |= cpu_to_le16(I40E_AQ_FLAG_LB);
+               desc->opcode = 0;
+               /* This is in accordance with Admin queue design, there is no
+                * register for buffer size configuration
+                */
+               desc->datalen = cpu_to_le16((u16)bi->size);
+               desc->retval = 0;
+               desc->cookie_high = 0;
+               desc->cookie_low = 0;
+               desc->params.external.addr_high =
+                       cpu_to_le32(upper_32_bits(bi->pa));
+               desc->params.external.addr_low =
+                       cpu_to_le32(lower_32_bits(bi->pa));
+               desc->params.external.param0 = 0;
+               desc->params.external.param1 = 0;
+       }
+
+alloc_arq_bufs:
+       return ret_code;
+
+unwind_alloc_arq_bufs:
+       /* don't try to free the one that failed... */
+       i--;
+       for (; i >= 0; i--)
+               i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
+       mem.va = hw->aq.arq.r.arq_bi;
+       i40e_free_virt_mem(hw, &mem);
+
+       return ret_code;
+}
+
+/**
+ *  i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue
+ *  @hw:     pointer to the hardware structure
+ **/
+static i40e_status i40e_alloc_asq_bufs(struct i40e_hw *hw)
+{
+       i40e_status ret_code;
+       struct i40e_virt_mem mem;
+       struct i40e_dma_mem *bi;
+       int i;
+
+       /* No mapped memory needed yet, just the buffer info structures */
+       ret_code = i40e_allocate_virt_mem(hw, &mem, (hw->aq.num_asq_entries *
+                                         sizeof(struct i40e_dma_mem)));
+       if (ret_code)
+               goto alloc_asq_bufs;
+       hw->aq.asq.r.asq_bi = (struct i40e_dma_mem *)mem.va;
+
+       /* allocate the mapped buffers */
+       for (i = 0; i < hw->aq.num_asq_entries; i++) {
+               bi = &hw->aq.asq.r.asq_bi[i];
+               ret_code = i40e_allocate_dma_mem(hw, bi,
+                                                i40e_mem_asq_buf,
+                                                hw->aq.asq_buf_size,
+                                                I40E_ADMINQ_DESC_ALIGNMENT);
+               if (ret_code)
+                       goto unwind_alloc_asq_bufs;
+       }
+alloc_asq_bufs:
+       return ret_code;
+
+unwind_alloc_asq_bufs:
+       /* don't try to free the one that failed... */
+       i--;
+       for (; i >= 0; i--)
+               i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
+       mem.va = hw->aq.asq.r.asq_bi;
+       i40e_free_virt_mem(hw, &mem);
+
+       return ret_code;
+}
+
+/**
+ *  i40e_free_arq_bufs - Free receive queue buffer info elements
+ *  @hw:     pointer to the hardware structure
+ **/
+static void i40e_free_arq_bufs(struct i40e_hw *hw)
+{
+       struct i40e_virt_mem mem;
+       int i;
+
+       for (i = 0; i < hw->aq.num_arq_entries; i++)
+               i40e_free_dma_mem(hw, &hw->aq.arq.r.arq_bi[i]);
+
+       mem.va = hw->aq.arq.r.arq_bi;
+       i40e_free_virt_mem(hw, &mem);
+}
+
+/**
+ *  i40e_free_asq_bufs - Free send queue buffer info elements
+ *  @hw:     pointer to the hardware structure
+ **/
+static void i40e_free_asq_bufs(struct i40e_hw *hw)
+{
+       struct i40e_virt_mem mem;
+       int i;
+
+       /* only unmap if the address is non-NULL */
+       for (i = 0; i < hw->aq.num_asq_entries; i++)
+               if (hw->aq.asq.r.asq_bi[i].pa)
+                       i40e_free_dma_mem(hw, &hw->aq.asq.r.asq_bi[i]);
+
+       /* now free the buffer info list */
+       mem.va = hw->aq.asq.r.asq_bi;
+       i40e_free_virt_mem(hw, &mem);
+}
+
+/**
+ *  i40e_config_asq_regs - configure ASQ registers
+ *  @hw:     pointer to the hardware structure
+ *
+ *  Configure base address and length registers for the transmit queue
+ **/
+static void i40e_config_asq_regs(struct i40e_hw *hw)
+{
+       if (hw->mac.type == I40E_MAC_VF) {
+               /* configure the transmit queue */
+               wr32(hw, I40E_VF_ATQBAH1, upper_32_bits(hw->aq.asq.dma_addr));
+               wr32(hw, I40E_VF_ATQBAL1, lower_32_bits(hw->aq.asq.dma_addr));
+               wr32(hw, I40E_VF_ATQLEN1, (hw->aq.num_asq_entries |
+                                         I40E_VF_ATQLEN1_ATQENABLE_MASK));
+       } else {
+               /* configure the transmit queue */
+               wr32(hw, I40E_PF_ATQBAH, upper_32_bits(hw->aq.asq.dma_addr));
+               wr32(hw, I40E_PF_ATQBAL, lower_32_bits(hw->aq.asq.dma_addr));
+               wr32(hw, I40E_PF_ATQLEN, (hw->aq.num_asq_entries |
+                                         I40E_PF_ATQLEN_ATQENABLE_MASK));
+       }
+}
+
+/**
+ *  i40e_config_arq_regs - ARQ register configuration
+ *  @hw:     pointer to the hardware structure
+ *
+ * Configure base address and length registers for the receive (event queue)
+ **/
+static void i40e_config_arq_regs(struct i40e_hw *hw)
+{
+       if (hw->mac.type == I40E_MAC_VF) {
+               /* configure the receive queue */
+               wr32(hw, I40E_VF_ARQBAH1, upper_32_bits(hw->aq.arq.dma_addr));
+               wr32(hw, I40E_VF_ARQBAL1, lower_32_bits(hw->aq.arq.dma_addr));
+               wr32(hw, I40E_VF_ARQLEN1, (hw->aq.num_arq_entries |
+                                         I40E_VF_ARQLEN1_ARQENABLE_MASK));
+       } else {
+               /* configure the receive queue */
+               wr32(hw, I40E_PF_ARQBAH, upper_32_bits(hw->aq.arq.dma_addr));
+               wr32(hw, I40E_PF_ARQBAL, lower_32_bits(hw->aq.arq.dma_addr));
+               wr32(hw, I40E_PF_ARQLEN, (hw->aq.num_arq_entries |
+                                         I40E_PF_ARQLEN_ARQENABLE_MASK));
+       }
+
+       /* Update tail in the HW to post pre-allocated buffers */
+       wr32(hw, hw->aq.arq.tail, hw->aq.num_arq_entries - 1);
+}
+
+/**
+ *  i40e_init_asq - main initialization routine for ASQ
+ *  @hw:     pointer to the hardware structure
+ *
+ *  This is the main initialization routine for the Admin Send Queue
+ *  Prior to calling this function, drivers *MUST* set the following fields
+ *  in the hw->aq structure:
+ *     - hw->aq.num_asq_entries
+ *     - hw->aq.arq_buf_size
+ *
+ *  Do *NOT* hold the lock when calling this as the memory allocation routines
+ *  called are not going to be atomic context safe
+ **/
+static i40e_status i40e_init_asq(struct i40e_hw *hw)
+{
+       i40e_status ret_code = 0;
+
+       if (hw->aq.asq.count > 0) {
+               /* queue already initialized */
+               ret_code = I40E_ERR_NOT_READY;
+               goto init_adminq_exit;
+       }
+
+       /* verify input for valid configuration */
+       if ((hw->aq.num_asq_entries == 0) ||
+           (hw->aq.asq_buf_size == 0)) {
+               ret_code = I40E_ERR_CONFIG;
+               goto init_adminq_exit;
+       }
+
+       hw->aq.asq.next_to_use = 0;
+       hw->aq.asq.next_to_clean = 0;
+       hw->aq.asq.count = hw->aq.num_asq_entries;
+
+       /* allocate the ring memory */
+       ret_code = i40e_alloc_adminq_asq_ring(hw);
+       if (ret_code)
+               goto init_adminq_exit;
+
+       /* allocate buffers in the rings */
+       ret_code = i40e_alloc_asq_bufs(hw);
+       if (ret_code)
+               goto init_adminq_free_rings;
+
+       /* initialize base registers */
+       i40e_config_asq_regs(hw);
+
+       /* success! */
+       goto init_adminq_exit;
+
+init_adminq_free_rings:
+       i40e_free_adminq_asq(hw);
+
+init_adminq_exit:
+       return ret_code;
+}
+
+/**
+ *  i40e_init_arq - initialize ARQ
+ *  @hw:     pointer to the hardware structure
+ *
+ *  The main initialization routine for the Admin Receive (Event) Queue.
+ *  Prior to calling this function, drivers *MUST* set the following fields
+ *  in the hw->aq structure:
+ *     - hw->aq.num_asq_entries
+ *     - hw->aq.arq_buf_size
+ *
+ *  Do *NOT* hold the lock when calling this as the memory allocation routines
+ *  called are not going to be atomic context safe
+ **/
+static i40e_status i40e_init_arq(struct i40e_hw *hw)
+{
+       i40e_status ret_code = 0;
+
+       if (hw->aq.arq.count > 0) {
+               /* queue already initialized */
+               ret_code = I40E_ERR_NOT_READY;
+               goto init_adminq_exit;
+       }
+
+       /* verify input for valid configuration */
+       if ((hw->aq.num_arq_entries == 0) ||
+           (hw->aq.arq_buf_size == 0)) {
+               ret_code = I40E_ERR_CONFIG;
+               goto init_adminq_exit;
+       }
+
+       hw->aq.arq.next_to_use = 0;
+       hw->aq.arq.next_to_clean = 0;
+       hw->aq.arq.count = hw->aq.num_arq_entries;
+
+       /* allocate the ring memory */
+       ret_code = i40e_alloc_adminq_arq_ring(hw);
+       if (ret_code)
+               goto init_adminq_exit;
+
+       /* allocate buffers in the rings */
+       ret_code = i40e_alloc_arq_bufs(hw);
+       if (ret_code)
+               goto init_adminq_free_rings;
+
+       /* initialize base registers */
+       i40e_config_arq_regs(hw);
+
+       /* success! */
+       goto init_adminq_exit;
+
+init_adminq_free_rings:
+       i40e_free_adminq_arq(hw);
+
+init_adminq_exit:
+       return ret_code;
+}
+
+/**
+ *  i40e_shutdown_asq - shutdown the ASQ
+ *  @hw:     pointer to the hardware structure
+ *
+ *  The main shutdown routine for the Admin Send Queue
+ **/
+static i40e_status i40e_shutdown_asq(struct i40e_hw *hw)
+{
+       i40e_status ret_code = 0;
+
+       if (hw->aq.asq.count == 0)
+               return I40E_ERR_NOT_READY;
+
+       /* Stop firmware AdminQ processing */
+       if (hw->mac.type == I40E_MAC_VF)
+               wr32(hw, I40E_VF_ATQLEN1, 0);
+       else
+               wr32(hw, I40E_PF_ATQLEN, 0);
+
+       /* make sure lock is available */
+       mutex_lock(&hw->aq.asq_mutex);
+
+       hw->aq.asq.count = 0; /* to indicate uninitialized queue */
+
+       /* free ring buffers */
+       i40e_free_asq_bufs(hw);
+       /* free the ring descriptors */
+       i40e_free_adminq_asq(hw);
+
+       mutex_unlock(&hw->aq.asq_mutex);
+
+       return ret_code;
+}
+
+/**
+ *  i40e_shutdown_arq - shutdown ARQ
+ *  @hw:     pointer to the hardware structure
+ *
+ *  The main shutdown routine for the Admin Receive Queue
+ **/
+static i40e_status i40e_shutdown_arq(struct i40e_hw *hw)
+{
+       i40e_status ret_code = 0;
+
+       if (hw->aq.arq.count == 0)
+               return I40E_ERR_NOT_READY;
+
+       /* Stop firmware AdminQ processing */
+       if (hw->mac.type == I40E_MAC_VF)
+               wr32(hw, I40E_VF_ARQLEN1, 0);
+       else
+               wr32(hw, I40E_PF_ARQLEN, 0);
+
+       /* make sure lock is available */
+       mutex_lock(&hw->aq.arq_mutex);
+
+       hw->aq.arq.count = 0; /* to indicate uninitialized queue */
+
+       /* free ring buffers */
+       i40e_free_arq_bufs(hw);
+       /* free the ring descriptors */
+       i40e_free_adminq_arq(hw);
+
+       mutex_unlock(&hw->aq.arq_mutex);
+
+       return ret_code;
+}
+
+/**
+ *  i40e_init_adminq - main initialization routine for Admin Queue
+ *  @hw:     pointer to the hardware structure
+ *
+ *  Prior to calling this function, drivers *MUST* set the following fields
+ *  in the hw->aq structure:
+ *     - hw->aq.num_asq_entries
+ *     - hw->aq.num_arq_entries
+ *     - hw->aq.arq_buf_size
+ *     - hw->aq.asq_buf_size
+ **/
+i40e_status i40e_init_adminq(struct i40e_hw *hw)
+{
+       u16 eetrack_lo, eetrack_hi;
+       i40e_status ret_code;
+
+       /* verify input for valid configuration */
+       if ((hw->aq.num_arq_entries == 0) ||
+           (hw->aq.num_asq_entries == 0) ||
+           (hw->aq.arq_buf_size == 0) ||
+           (hw->aq.asq_buf_size == 0)) {
+               ret_code = I40E_ERR_CONFIG;
+               goto init_adminq_exit;
+       }
+
+       /* initialize locks */
+       mutex_init(&hw->aq.asq_mutex);
+       mutex_init(&hw->aq.arq_mutex);
+
+       /* Set up register offsets */
+       i40e_adminq_init_regs(hw);
+
+       /* allocate the ASQ */
+       ret_code = i40e_init_asq(hw);
+       if (ret_code)
+               goto init_adminq_destroy_locks;
+
+       /* allocate the ARQ */
+       ret_code = i40e_init_arq(hw);
+       if (ret_code)
+               goto init_adminq_free_asq;
+
+       ret_code = i40e_aq_get_firmware_version(hw,
+                                    &hw->aq.fw_maj_ver, &hw->aq.fw_min_ver,
+                                    &hw->aq.api_maj_ver, &hw->aq.api_min_ver,
+                                    NULL);
+       if (ret_code)
+               goto init_adminq_free_arq;
+
+       if (hw->aq.api_maj_ver != I40E_FW_API_VERSION_MAJOR ||
+           hw->aq.api_min_ver != I40E_FW_API_VERSION_MINOR) {
+               ret_code = I40E_ERR_FIRMWARE_API_VERSION;
+               goto init_adminq_free_arq;
+       }
+       i40e_read_nvm_word(hw, I40E_SR_NVM_IMAGE_VERSION, &hw->nvm.version);
+       i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_LO, &eetrack_lo);
+       i40e_read_nvm_word(hw, I40E_SR_NVM_EETRACK_HI, &eetrack_hi);
+       hw->nvm.eetrack = (eetrack_hi << 16) | eetrack_lo;
+
+       ret_code = i40e_aq_set_hmc_resource_profile(hw,
+                                                   I40E_HMC_PROFILE_DEFAULT,
+                                                   0,
+                                                   NULL);
+       ret_code = 0;
+
+       /* success! */
+       goto init_adminq_exit;
+
+init_adminq_free_arq:
+       i40e_shutdown_arq(hw);
+init_adminq_free_asq:
+       i40e_shutdown_asq(hw);
+init_adminq_destroy_locks:
+
+init_adminq_exit:
+       return ret_code;
+}
+
+/**
+ *  i40e_shutdown_adminq - shutdown routine for the Admin Queue
+ *  @hw:     pointer to the hardware structure
+ **/
+i40e_status i40e_shutdown_adminq(struct i40e_hw *hw)
+{
+       i40e_status ret_code = 0;
+
+       i40e_shutdown_asq(hw);
+       i40e_shutdown_arq(hw);
+
+       /* destroy the locks */
+
+       return ret_code;
+}
+
+/**
+ *  i40e_clean_asq - cleans Admin send queue
+ *  @asq: pointer to the adminq send ring
+ *
+ *  returns the number of free desc
+ **/
+static u16 i40e_clean_asq(struct i40e_hw *hw)
+{
+       struct i40e_adminq_ring *asq = &(hw->aq.asq);
+       struct i40e_asq_cmd_details *details;
+       u16 ntc = asq->next_to_clean;
+       struct i40e_aq_desc desc_cb;
+       struct i40e_aq_desc *desc;
+
+       desc = I40E_ADMINQ_DESC(*asq, ntc);
+       details = I40E_ADMINQ_DETAILS(*asq, ntc);
+       while (rd32(hw, hw->aq.asq.head) != ntc) {
+               if (details->callback) {
+                       I40E_ADMINQ_CALLBACK cb_func =
+                                       (I40E_ADMINQ_CALLBACK)details->callback;
+                       desc_cb = *desc;
+                       cb_func(hw, &desc_cb);
+               }
+               memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
+               memset((void *)details, 0,
+                      sizeof(struct i40e_asq_cmd_details));
+               ntc++;
+               if (ntc == asq->count)
+                       ntc = 0;
+               desc = I40E_ADMINQ_DESC(*asq, ntc);
+               details = I40E_ADMINQ_DETAILS(*asq, ntc);
+       }
+
+       asq->next_to_clean = ntc;
+
+       return I40E_DESC_UNUSED(asq);
+}
+
+/**
+ *  i40e_asq_done - check if FW has processed the Admin Send Queue
+ *  @hw: pointer to the hw struct
+ *
+ *  Returns true if the firmware has processed all descriptors on the
+ *  admin send queue. Returns false if there are still requests pending.
+ **/
+bool i40e_asq_done(struct i40e_hw *hw)
+{
+       /* AQ designers suggest use of head for better
+        * timing reliability than DD bit
+        */
+       return (rd32(hw, hw->aq.asq.head) == hw->aq.asq.next_to_use);
+
+}
+
+/**
+ *  i40e_asq_send_command - send command to Admin Queue
+ *  @hw: pointer to the hw struct
+ *  @desc: prefilled descriptor describing the command (non DMA mem)
+ *  @buff: buffer to use for indirect commands
+ *  @buff_size: size of buffer for indirect commands
+ *  @opaque: pointer to info to be used in async cleanup
+ *
+ *  This is the main send command driver routine for the Admin Queue send
+ *  queue.  It runs the queue, cleans the queue, etc
+ **/
+i40e_status i40e_asq_send_command(struct i40e_hw *hw,
+                               struct i40e_aq_desc *desc,
+                               void *buff, /* can be NULL */
+                               u16  buff_size,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       i40e_status status = 0;
+       struct i40e_dma_mem *dma_buff = NULL;
+       struct i40e_asq_cmd_details *details;
+       struct i40e_aq_desc *desc_on_ring;
+       bool cmd_completed = false;
+       u16  retval = 0;
+
+       if (hw->aq.asq.count == 0) {
+               i40e_debug(hw, I40E_DEBUG_AQ_MESSAGE,
+                          "AQTX: Admin queue not initialized.\n");
+               status = I40E_ERR_QUEUE_EMPTY;
+               goto asq_send_command_exit;
+       }
+
+       details = I40E_ADMINQ_DETAILS(hw->aq.asq, hw->aq.asq.next_to_use);
+       if (cmd_details) {
+               memcpy(details, cmd_details,
+                      sizeof(struct i40e_asq_cmd_details));
+
+               /* If the cmd_details are defined copy the cookie.  The
+                * cpu_to_le32 is not needed here because the data is ignored
+                * by the FW, only used by the driver
+                */
+               if (details->cookie) {
+                       desc->cookie_high =
+                               cpu_to_le32(upper_32_bits(details->cookie));
+                       desc->cookie_low =
+                               cpu_to_le32(lower_32_bits(details->cookie));
+               }
+       } else {
+               memset(details, 0, sizeof(struct i40e_asq_cmd_details));
+       }
+
+       /* clear requested flags and then set additional flags if defined */
+       desc->flags &= ~cpu_to_le16(details->flags_dis);
+       desc->flags |= cpu_to_le16(details->flags_ena);
+
+       mutex_lock(&hw->aq.asq_mutex);
+
+       if (buff_size > hw->aq.asq_buf_size) {
+               i40e_debug(hw,
+                          I40E_DEBUG_AQ_MESSAGE,
+                          "AQTX: Invalid buffer size: %d.\n",
+                          buff_size);
+               status = I40E_ERR_INVALID_SIZE;
+               goto asq_send_command_error;
+       }
+
+       if (details->postpone && !details->async) {
+               i40e_debug(hw,
+                          I40E_DEBUG_AQ_MESSAGE,
+                          "AQTX: Async flag not set along with postpone flag");
+               status = I40E_ERR_PARAM;
+               goto asq_send_command_error;
+       }
+
+       /* call clean and check queue available function to reclaim the
+        * descriptors that were processed by FW, the function returns the
+        * number of desc available
+        */
+       /* the clean function called here could be called in a separate thread
+        * in case of asynchronous completions
+        */
+       if (i40e_clean_asq(hw) == 0) {
+               i40e_debug(hw,
+                          I40E_DEBUG_AQ_MESSAGE,
+                          "AQTX: Error queue is full.\n");
+               status = I40E_ERR_ADMIN_QUEUE_FULL;
+               goto asq_send_command_error;
+       }
+
+       /* initialize the temp desc pointer with the right desc */
+       desc_on_ring = I40E_ADMINQ_DESC(hw->aq.asq, hw->aq.asq.next_to_use);
+
+       /* if the desc is available copy the temp desc to the right place */
+       memcpy(desc_on_ring, desc, sizeof(struct i40e_aq_desc));
+
+       /* if buff is not NULL assume indirect command */
+       if (buff != NULL) {
+               dma_buff = &(hw->aq.asq.r.asq_bi[hw->aq.asq.next_to_use]);
+               /* copy the user buff into the respective DMA buff */
+               memcpy(dma_buff->va, buff, buff_size);
+               desc_on_ring->datalen = cpu_to_le16(buff_size);
+
+               /* Update the address values in the desc with the pa value
+                * for respective buffer
+                */
+               desc_on_ring->params.external.addr_high =
+                               cpu_to_le32(upper_32_bits(dma_buff->pa));
+               desc_on_ring->params.external.addr_low =
+                               cpu_to_le32(lower_32_bits(dma_buff->pa));
+       }
+
+       /* bump the tail */
+       i40e_debug_aq(hw, I40E_DEBUG_AQ_COMMAND, (void *)desc_on_ring, buff);
+       (hw->aq.asq.next_to_use)++;
+       if (hw->aq.asq.next_to_use == hw->aq.asq.count)
+               hw->aq.asq.next_to_use = 0;
+       if (!details->postpone)
+               wr32(hw, hw->aq.asq.tail, hw->aq.asq.next_to_use);
+
+       /* if cmd_details are not defined or async flag is not set,
+        * we need to wait for desc write back
+        */
+       if (!details->async && !details->postpone) {
+               u32 total_delay = 0;
+               u32 delay_len = 10;
+
+               do {
+                       /* AQ designers suggest use of head for better
+                        * timing reliability than DD bit
+                        */
+                       if (i40e_asq_done(hw))
+                               break;
+                       /* ugh! delay while spin_lock */
+                       udelay(delay_len);
+                       total_delay += delay_len;
+               } while (total_delay <  I40E_ASQ_CMD_TIMEOUT);
+       }
+
+       /* if ready, copy the desc back to temp */
+       if (i40e_asq_done(hw)) {
+               memcpy(desc, desc_on_ring, sizeof(struct i40e_aq_desc));
+               if (buff != NULL)
+                       memcpy(buff, dma_buff->va, buff_size);
+               retval = le16_to_cpu(desc->retval);
+               if (retval != 0) {
+                       i40e_debug(hw,
+                                  I40E_DEBUG_AQ_MESSAGE,
+                                  "AQTX: Command completed with error 0x%X.\n",
+                                  retval);
+                       /* strip off FW internal code */
+                       retval &= 0xff;
+               }
+               cmd_completed = true;
+               if ((enum i40e_admin_queue_err)retval == I40E_AQ_RC_OK)
+                       status = 0;
+               else
+                       status = I40E_ERR_ADMIN_QUEUE_ERROR;
+               hw->aq.asq_last_status = (enum i40e_admin_queue_err)retval;
+       }
+
+       /* update the error if time out occurred */
+       if ((!cmd_completed) &&
+           (!details->async && !details->postpone)) {
+               i40e_debug(hw,
+                          I40E_DEBUG_AQ_MESSAGE,
+                          "AQTX: Writeback timeout.\n");
+               status = I40E_ERR_ADMIN_QUEUE_TIMEOUT;
+       }
+
+asq_send_command_error:
+       mutex_unlock(&hw->aq.asq_mutex);
+asq_send_command_exit:
+       return status;
+}
+
+/**
+ *  i40e_fill_default_direct_cmd_desc - AQ descriptor helper function
+ *  @desc:     pointer to the temp descriptor (non DMA mem)
+ *  @opcode:   the opcode can be used to decide which flags to turn off or on
+ *
+ *  Fill the desc with default values
+ **/
+void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
+                                      u16 opcode)
+{
+       /* zero out the desc */
+       memset((void *)desc, 0, sizeof(struct i40e_aq_desc));
+       desc->opcode = cpu_to_le16(opcode);
+       desc->flags = cpu_to_le16(I40E_AQ_FLAG_EI | I40E_AQ_FLAG_SI);
+}
+
+/**
+ *  i40e_clean_arq_element
+ *  @hw: pointer to the hw struct
+ *  @e: event info from the receive descriptor, includes any buffers
+ *  @pending: number of events that could be left to process
+ *
+ *  This function cleans one Admin Receive Queue element and returns
+ *  the contents through e.  It can also return how many events are
+ *  left to process through 'pending'
+ **/
+i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
+                                            struct i40e_arq_event_info *e,
+                                            u16 *pending)
+{
+       i40e_status ret_code = 0;
+       u16 ntc = hw->aq.arq.next_to_clean;
+       struct i40e_aq_desc *desc;
+       struct i40e_dma_mem *bi;
+       u16 desc_idx;
+       u16 datalen;
+       u16 flags;
+       u16 ntu;
+
+       /* take the lock before we start messing with the ring */
+       mutex_lock(&hw->aq.arq_mutex);
+
+       /* set next_to_use to head */
+       ntu = (rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK);
+       if (ntu == ntc) {
+               /* nothing to do - shouldn't need to update ring's values */
+               i40e_debug(hw,
+                          I40E_DEBUG_AQ_MESSAGE,
+                          "AQRX: Queue is empty.\n");
+               ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK;
+               goto clean_arq_element_out;
+       }
+
+       /* now clean the next descriptor */
+       desc = I40E_ADMINQ_DESC(hw->aq.arq, ntc);
+       desc_idx = ntc;
+       i40e_debug_aq(hw,
+                     I40E_DEBUG_AQ_COMMAND,
+                     (void *)desc,
+                     hw->aq.arq.r.arq_bi[desc_idx].va);
+
+       flags = le16_to_cpu(desc->flags);
+       if (flags & I40E_AQ_FLAG_ERR) {
+               ret_code = I40E_ERR_ADMIN_QUEUE_ERROR;
+               hw->aq.arq_last_status =
+                       (enum i40e_admin_queue_err)le16_to_cpu(desc->retval);
+               i40e_debug(hw,
+                          I40E_DEBUG_AQ_MESSAGE,
+                          "AQRX: Event received with error 0x%X.\n",
+                          hw->aq.arq_last_status);
+       } else {
+               memcpy(&e->desc, desc, sizeof(struct i40e_aq_desc));
+               datalen = le16_to_cpu(desc->datalen);
+               e->msg_size = min(datalen, e->msg_size);
+               if (e->msg_buf != NULL && (e->msg_size != 0))
+                       memcpy(e->msg_buf, hw->aq.arq.r.arq_bi[desc_idx].va,
+                              e->msg_size);
+       }
+
+       /* Restore the original datalen and buffer address in the desc,
+        * FW updates datalen to indicate the event message
+        * size
+        */
+       bi = &hw->aq.arq.r.arq_bi[ntc];
+       desc->datalen = cpu_to_le16((u16)bi->size);
+       desc->params.external.addr_high = cpu_to_le32(upper_32_bits(bi->pa));
+       desc->params.external.addr_low = cpu_to_le32(lower_32_bits(bi->pa));
+
+       /* set tail = the last cleaned desc index. */
+       wr32(hw, hw->aq.arq.tail, ntc);
+       /* ntc is updated to tail + 1 */
+       ntc++;
+       if (ntc == hw->aq.num_arq_entries)
+               ntc = 0;
+       hw->aq.arq.next_to_clean = ntc;
+       hw->aq.arq.next_to_use = ntu;
+
+clean_arq_element_out:
+       /* Set pending if needed, unlock and return */
+       if (pending != NULL)
+               *pending = (ntc > ntu ? hw->aq.arq.count : 0) + (ntu - ntc);
+       mutex_unlock(&hw->aq.arq_mutex);
+
+       return ret_code;
+}
+
+void i40e_resume_aq(struct i40e_hw *hw)
+{
+       u32 reg = 0;
+
+       /* Registers are reset after PF reset */
+       hw->aq.asq.next_to_use = 0;
+       hw->aq.asq.next_to_clean = 0;
+
+       i40e_config_asq_regs(hw);
+       reg = hw->aq.num_asq_entries;
+
+       if (hw->mac.type == I40E_MAC_VF) {
+               reg |= I40E_VF_ATQLEN_ATQENABLE_MASK;
+               wr32(hw, I40E_VF_ATQLEN1, reg);
+       } else {
+               reg |= I40E_PF_ATQLEN_ATQENABLE_MASK;
+               wr32(hw, I40E_PF_ATQLEN, reg);
+       }
+
+       hw->aq.arq.next_to_use = 0;
+       hw->aq.arq.next_to_clean = 0;
+
+       i40e_config_arq_regs(hw);
+       reg = hw->aq.num_arq_entries;
+
+       if (hw->mac.type == I40E_MAC_VF) {
+               reg |= I40E_VF_ATQLEN_ATQENABLE_MASK;
+               wr32(hw, I40E_VF_ARQLEN1, reg);
+       } else {
+               reg |= I40E_PF_ATQLEN_ATQENABLE_MASK;
+               wr32(hw, I40E_PF_ARQLEN, reg);
+       }
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
new file mode 100644 (file)
index 0000000..22e5ed6
--- /dev/null
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_ADMINQ_H_
+#define _I40E_ADMINQ_H_
+
+#include "i40e_osdep.h"
+#include "i40e_adminq_cmd.h"
+
+#define I40E_ADMINQ_DESC(R, i)   \
+       (&(((struct i40e_aq_desc *)((R).desc))[i]))
+
+#define I40E_ADMINQ_DESC_ALIGNMENT 4096
+
+struct i40e_adminq_ring {
+       void *desc;             /* Descriptor ring memory */
+       void *details;          /* ASQ details */
+
+       union {
+               struct i40e_dma_mem *asq_bi;
+               struct i40e_dma_mem *arq_bi;
+       } r;
+
+       u64 dma_addr;           /* Physical address of the ring */
+       u16 count;              /* Number of descriptors */
+       u16 rx_buf_len;         /* Admin Receive Queue buffer length */
+
+       /* used for interrupt processing */
+       u16 next_to_use;
+       u16 next_to_clean;
+
+       /* used for queue tracking */
+       u32 head;
+       u32 tail;
+};
+
+/* ASQ transaction details */
+struct i40e_asq_cmd_details {
+       void *callback; /* cast from type I40E_ADMINQ_CALLBACK */
+       u64 cookie;
+       u16 flags_ena;
+       u16 flags_dis;
+       bool async;
+       bool postpone;
+};
+
+#define I40E_ADMINQ_DETAILS(R, i)   \
+       (&(((struct i40e_asq_cmd_details *)((R).details))[i]))
+
+/* ARQ event information */
+struct i40e_arq_event_info {
+       struct i40e_aq_desc desc;
+       u16 msg_size;
+       u8 *msg_buf;
+};
+
+/* Admin Queue information */
+struct i40e_adminq_info {
+       struct i40e_adminq_ring arq;    /* receive queue */
+       struct i40e_adminq_ring asq;    /* send queue */
+       u16 num_arq_entries;            /* receive queue depth */
+       u16 num_asq_entries;            /* send queue depth */
+       u16 arq_buf_size;               /* receive queue buffer size */
+       u16 asq_buf_size;               /* send queue buffer size */
+       u16 fw_maj_ver;                 /* firmware major version */
+       u16 fw_min_ver;                 /* firmware minor version */
+       u16 api_maj_ver;                /* api major version */
+       u16 api_min_ver;                /* api minor version */
+
+       struct mutex asq_mutex; /* Send queue lock */
+       struct mutex arq_mutex; /* Receive queue lock */
+
+       struct i40e_dma_mem asq_mem;    /* send queue dynamic memory */
+       struct i40e_dma_mem arq_mem;    /* receive queue dynamic memory */
+
+       /* last status values on send and receive queues */
+       enum i40e_admin_queue_err asq_last_status;
+       enum i40e_admin_queue_err arq_last_status;
+};
+
+/* general information */
+#define I40E_AQ_LARGE_BUF      512
+#define I40E_ASQ_CMD_TIMEOUT   100000  /* usecs */
+
+void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
+                                      u16 opcode);
+
+#endif /* _I40E_ADMINQ_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
new file mode 100644 (file)
index 0000000..e61ebdd
--- /dev/null
@@ -0,0 +1,2076 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_ADMINQ_CMD_H_
+#define _I40E_ADMINQ_CMD_H_
+
+/* This header file defines the i40e Admin Queue commands and is shared between
+ * i40e Firmware and Software.
+ *
+ * This file needs to comply with the Linux Kernel coding style.
+ */
+
+#define I40E_FW_API_VERSION_MAJOR  0x0001
+#define I40E_FW_API_VERSION_MINOR  0x0000
+
+struct i40e_aq_desc {
+       __le16 flags;
+       __le16 opcode;
+       __le16 datalen;
+       __le16 retval;
+       __le32 cookie_high;
+       __le32 cookie_low;
+       union {
+               struct {
+                       __le32 param0;
+                       __le32 param1;
+                       __le32 param2;
+                       __le32 param3;
+               } internal;
+               struct {
+                       __le32 param0;
+                       __le32 param1;
+                       __le32 addr_high;
+                       __le32 addr_low;
+               } external;
+               u8 raw[16];
+       } params;
+};
+
+/* Flags sub-structure
+ * |0  |1  |2  |3  |4  |5  |6  |7  |8  |9  |10 |11 |12 |13 |14 |15 |
+ * |DD |CMP|ERR|VFE| * *  RESERVED * * |LB |RD |VFC|BUF|SI |EI |FE |
+ */
+
+/* command flags and offsets*/
+#define I40E_AQ_FLAG_DD_SHIFT  0
+#define I40E_AQ_FLAG_CMP_SHIFT 1
+#define I40E_AQ_FLAG_ERR_SHIFT 2
+#define I40E_AQ_FLAG_VFE_SHIFT 3
+#define I40E_AQ_FLAG_LB_SHIFT  9
+#define I40E_AQ_FLAG_RD_SHIFT  10
+#define I40E_AQ_FLAG_VFC_SHIFT 11
+#define I40E_AQ_FLAG_BUF_SHIFT 12
+#define I40E_AQ_FLAG_SI_SHIFT  13
+#define I40E_AQ_FLAG_EI_SHIFT  14
+#define I40E_AQ_FLAG_FE_SHIFT  15
+
+#define I40E_AQ_FLAG_DD  (1 << I40E_AQ_FLAG_DD_SHIFT)  /* 0x1    */
+#define I40E_AQ_FLAG_CMP (1 << I40E_AQ_FLAG_CMP_SHIFT) /* 0x2    */
+#define I40E_AQ_FLAG_ERR (1 << I40E_AQ_FLAG_ERR_SHIFT) /* 0x4    */
+#define I40E_AQ_FLAG_VFE (1 << I40E_AQ_FLAG_VFE_SHIFT) /* 0x8    */
+#define I40E_AQ_FLAG_LB  (1 << I40E_AQ_FLAG_LB_SHIFT)  /* 0x200  */
+#define I40E_AQ_FLAG_RD  (1 << I40E_AQ_FLAG_RD_SHIFT)  /* 0x400  */
+#define I40E_AQ_FLAG_VFC (1 << I40E_AQ_FLAG_VFC_SHIFT) /* 0x800  */
+#define I40E_AQ_FLAG_BUF (1 << I40E_AQ_FLAG_BUF_SHIFT) /* 0x1000 */
+#define I40E_AQ_FLAG_SI  (1 << I40E_AQ_FLAG_SI_SHIFT)  /* 0x2000 */
+#define I40E_AQ_FLAG_EI  (1 << I40E_AQ_FLAG_EI_SHIFT)  /* 0x4000 */
+#define I40E_AQ_FLAG_FE  (1 << I40E_AQ_FLAG_FE_SHIFT)  /* 0x8000 */
+
+/* error codes */
+enum i40e_admin_queue_err {
+       I40E_AQ_RC_OK       = 0,    /* success */
+       I40E_AQ_RC_EPERM    = 1,    /* Operation not permitted */
+       I40E_AQ_RC_ENOENT   = 2,    /* No such element */
+       I40E_AQ_RC_ESRCH    = 3,    /* Bad opcode */
+       I40E_AQ_RC_EINTR    = 4,    /* operation interrupted */
+       I40E_AQ_RC_EIO      = 5,    /* I/O error */
+       I40E_AQ_RC_ENXIO    = 6,    /* No such resource */
+       I40E_AQ_RC_E2BIG    = 7,    /* Arg too long */
+       I40E_AQ_RC_EAGAIN   = 8,    /* Try again */
+       I40E_AQ_RC_ENOMEM   = 9,    /* Out of memory */
+       I40E_AQ_RC_EACCES   = 10,   /* Permission denied */
+       I40E_AQ_RC_EFAULT   = 11,   /* Bad address */
+       I40E_AQ_RC_EBUSY    = 12,   /* Device or resource busy */
+       I40E_AQ_RC_EEXIST   = 13,   /* object already exists */
+       I40E_AQ_RC_EINVAL   = 14,   /* Invalid argument */
+       I40E_AQ_RC_ENOTTY   = 15,   /* Not a typewriter */
+       I40E_AQ_RC_ENOSPC   = 16,   /* No space left or alloc failure */
+       I40E_AQ_RC_ENOSYS   = 17,   /* Function not implemented */
+       I40E_AQ_RC_ERANGE   = 18,   /* Parameter out of range */
+       I40E_AQ_RC_EFLUSHED = 19,   /* Cmd flushed because of prev cmd error */
+       I40E_AQ_RC_BAD_ADDR = 20,   /* Descriptor contains a bad pointer */
+       I40E_AQ_RC_EMODE    = 21,   /* Op not allowed in current dev mode */
+       I40E_AQ_RC_EFBIG    = 22,   /* File too large */
+};
+
+/* Admin Queue command opcodes */
+enum i40e_admin_queue_opc {
+       /* aq commands */
+       i40e_aqc_opc_get_version      = 0x0001,
+       i40e_aqc_opc_driver_version   = 0x0002,
+       i40e_aqc_opc_queue_shutdown   = 0x0003,
+
+       /* resource ownership */
+       i40e_aqc_opc_request_resource = 0x0008,
+       i40e_aqc_opc_release_resource = 0x0009,
+
+       i40e_aqc_opc_list_func_capabilities = 0x000A,
+       i40e_aqc_opc_list_dev_capabilities  = 0x000B,
+
+       i40e_aqc_opc_set_cppm_configuration = 0x0103,
+       i40e_aqc_opc_set_arp_proxy_entry    = 0x0104,
+       i40e_aqc_opc_set_ns_proxy_entry     = 0x0105,
+
+       /* LAA */
+       i40e_aqc_opc_mng_laa                = 0x0106,
+       i40e_aqc_opc_mac_address_read       = 0x0107,
+       i40e_aqc_opc_mac_address_write      = 0x0108,
+
+       /* internal switch commands */
+       i40e_aqc_opc_get_switch_config         = 0x0200,
+       i40e_aqc_opc_add_statistics            = 0x0201,
+       i40e_aqc_opc_remove_statistics         = 0x0202,
+       i40e_aqc_opc_set_port_parameters       = 0x0203,
+       i40e_aqc_opc_get_switch_resource_alloc = 0x0204,
+
+       i40e_aqc_opc_add_vsi                = 0x0210,
+       i40e_aqc_opc_update_vsi_parameters  = 0x0211,
+       i40e_aqc_opc_get_vsi_parameters     = 0x0212,
+
+       i40e_aqc_opc_add_pv                = 0x0220,
+       i40e_aqc_opc_update_pv_parameters  = 0x0221,
+       i40e_aqc_opc_get_pv_parameters     = 0x0222,
+
+       i40e_aqc_opc_add_veb               = 0x0230,
+       i40e_aqc_opc_update_veb_parameters = 0x0231,
+       i40e_aqc_opc_get_veb_parameters    = 0x0232,
+
+       i40e_aqc_opc_delete_element  = 0x0243,
+
+       i40e_aqc_opc_add_macvlan                  = 0x0250,
+       i40e_aqc_opc_remove_macvlan               = 0x0251,
+       i40e_aqc_opc_add_vlan                     = 0x0252,
+       i40e_aqc_opc_remove_vlan                  = 0x0253,
+       i40e_aqc_opc_set_vsi_promiscuous_modes    = 0x0254,
+       i40e_aqc_opc_add_tag                      = 0x0255,
+       i40e_aqc_opc_remove_tag                   = 0x0256,
+       i40e_aqc_opc_add_multicast_etag           = 0x0257,
+       i40e_aqc_opc_remove_multicast_etag        = 0x0258,
+       i40e_aqc_opc_update_tag                   = 0x0259,
+       i40e_aqc_opc_add_control_packet_filter    = 0x025A,
+       i40e_aqc_opc_remove_control_packet_filter = 0x025B,
+       i40e_aqc_opc_add_cloud_filters            = 0x025C,
+       i40e_aqc_opc_remove_cloud_filters         = 0x025D,
+
+       i40e_aqc_opc_add_mirror_rule    = 0x0260,
+       i40e_aqc_opc_delete_mirror_rule = 0x0261,
+
+       i40e_aqc_opc_set_storm_control_config = 0x0280,
+       i40e_aqc_opc_get_storm_control_config = 0x0281,
+
+       /* DCB commands */
+       i40e_aqc_opc_dcb_ignore_pfc = 0x0301,
+       i40e_aqc_opc_dcb_updated    = 0x0302,
+
+       /* TX scheduler */
+       i40e_aqc_opc_configure_vsi_bw_limit            = 0x0400,
+       i40e_aqc_opc_configure_vsi_ets_sla_bw_limit    = 0x0406,
+       i40e_aqc_opc_configure_vsi_tc_bw               = 0x0407,
+       i40e_aqc_opc_query_vsi_bw_config               = 0x0408,
+       i40e_aqc_opc_query_vsi_ets_sla_config          = 0x040A,
+       i40e_aqc_opc_configure_switching_comp_bw_limit = 0x0410,
+
+       i40e_aqc_opc_enable_switching_comp_ets             = 0x0413,
+       i40e_aqc_opc_modify_switching_comp_ets             = 0x0414,
+       i40e_aqc_opc_disable_switching_comp_ets            = 0x0415,
+       i40e_aqc_opc_configure_switching_comp_ets_bw_limit = 0x0416,
+       i40e_aqc_opc_configure_switching_comp_bw_config    = 0x0417,
+       i40e_aqc_opc_query_switching_comp_ets_config       = 0x0418,
+       i40e_aqc_opc_query_port_ets_config                 = 0x0419,
+       i40e_aqc_opc_query_switching_comp_bw_config        = 0x041A,
+       i40e_aqc_opc_suspend_port_tx                       = 0x041B,
+       i40e_aqc_opc_resume_port_tx                        = 0x041C,
+
+       /* hmc */
+       i40e_aqc_opc_query_hmc_resource_profile = 0x0500,
+       i40e_aqc_opc_set_hmc_resource_profile   = 0x0501,
+
+       /* phy commands*/
+       i40e_aqc_opc_get_phy_abilities   = 0x0600,
+       i40e_aqc_opc_set_phy_config      = 0x0601,
+       i40e_aqc_opc_set_mac_config      = 0x0603,
+       i40e_aqc_opc_set_link_restart_an = 0x0605,
+       i40e_aqc_opc_get_link_status     = 0x0607,
+       i40e_aqc_opc_set_phy_int_mask    = 0x0613,
+       i40e_aqc_opc_get_local_advt_reg  = 0x0614,
+       i40e_aqc_opc_set_local_advt_reg  = 0x0615,
+       i40e_aqc_opc_get_partner_advt    = 0x0616,
+       i40e_aqc_opc_set_lb_modes        = 0x0618,
+       i40e_aqc_opc_get_phy_wol_caps    = 0x0621,
+       i40e_aqc_opc_set_phy_reset       = 0x0622,
+       i40e_aqc_opc_upload_ext_phy_fm   = 0x0625,
+
+       /* NVM commands */
+       i40e_aqc_opc_nvm_read   = 0x0701,
+       i40e_aqc_opc_nvm_erase  = 0x0702,
+       i40e_aqc_opc_nvm_update = 0x0703,
+
+       /* virtualization commands */
+       i40e_aqc_opc_send_msg_to_pf   = 0x0801,
+       i40e_aqc_opc_send_msg_to_vf   = 0x0802,
+       i40e_aqc_opc_send_msg_to_peer = 0x0803,
+
+       /* alternate structure */
+       i40e_aqc_opc_alternate_write          = 0x0900,
+       i40e_aqc_opc_alternate_write_indirect = 0x0901,
+       i40e_aqc_opc_alternate_read           = 0x0902,
+       i40e_aqc_opc_alternate_read_indirect  = 0x0903,
+       i40e_aqc_opc_alternate_write_done     = 0x0904,
+       i40e_aqc_opc_alternate_set_mode       = 0x0905,
+       i40e_aqc_opc_alternate_clear_port     = 0x0906,
+
+       /* LLDP commands */
+       i40e_aqc_opc_lldp_get_mib    = 0x0A00,
+       i40e_aqc_opc_lldp_update_mib = 0x0A01,
+       i40e_aqc_opc_lldp_add_tlv    = 0x0A02,
+       i40e_aqc_opc_lldp_update_tlv = 0x0A03,
+       i40e_aqc_opc_lldp_delete_tlv = 0x0A04,
+       i40e_aqc_opc_lldp_stop       = 0x0A05,
+       i40e_aqc_opc_lldp_start      = 0x0A06,
+
+       /* Tunnel commands */
+       i40e_aqc_opc_add_udp_tunnel       = 0x0B00,
+       i40e_aqc_opc_del_udp_tunnel       = 0x0B01,
+       i40e_aqc_opc_tunnel_key_structure = 0x0B10,
+
+       /* Async Events */
+       i40e_aqc_opc_event_lan_overflow = 0x1001,
+
+       /* OEM commands */
+       i40e_aqc_opc_oem_parameter_change     = 0xFE00,
+       i40e_aqc_opc_oem_device_status_change = 0xFE01,
+
+       /* debug commands */
+       i40e_aqc_opc_debug_get_deviceid     = 0xFF00,
+       i40e_aqc_opc_debug_set_mode         = 0xFF01,
+       i40e_aqc_opc_debug_read_reg         = 0xFF03,
+       i40e_aqc_opc_debug_write_reg        = 0xFF04,
+       i40e_aqc_opc_debug_read_reg_sg      = 0xFF05,
+       i40e_aqc_opc_debug_write_reg_sg     = 0xFF06,
+       i40e_aqc_opc_debug_modify_reg       = 0xFF07,
+       i40e_aqc_opc_debug_dump_internals   = 0xFF08,
+       i40e_aqc_opc_debug_modify_internals = 0xFF09,
+};
+
+/* command structures and indirect data structures */
+
+/* Structure naming conventions:
+ * - no suffix for direct command descriptor structures
+ * - _data for indirect sent data
+ * - _resp for indirect return data (data which is both will use _data)
+ * - _completion for direct return data
+ * - _element_ for repeated elements (may also be _data or _resp)
+ *
+ * Command structures are expected to overlay the params.raw member of the basic
+ * descriptor, and as such cannot exceed 16 bytes in length.
+ */
+
+/* This macro is used to generate a compilation error if a structure
+ * is not exactly the correct length. It gives a divide by zero error if the
+ * structure is not of the correct size, otherwise it creates an enum that is
+ * never used.
+ */
+#define I40E_CHECK_STRUCT_LEN(n, X) enum i40e_static_assert_enum_##X \
+       { i40e_static_assert_##X = (n)/((sizeof(struct X) == (n)) ? 1 : 0) }
+
+/* This macro is used extensively to ensure that command structures are 16
+ * bytes in length as they have to map to the raw array of that size.
+ */
+#define I40E_CHECK_CMD_LENGTH(X) I40E_CHECK_STRUCT_LEN(16, X)
+
+/* internal (0x00XX) commands */
+
+/* Get version (direct 0x0001) */
+struct i40e_aqc_get_version {
+       __le32 rom_ver;
+       __le32 fw_build;
+       __le16 fw_major;
+       __le16 fw_minor;
+       __le16 api_major;
+       __le16 api_minor;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_version);
+
+/* Send driver version (direct 0x0002) */
+struct i40e_aqc_driver_version {
+       u8     driver_major_ver;
+       u8     driver_minor_ver;
+       u8     driver_build_ver;
+       u8     driver_subbuild_ver;
+       u8     reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_driver_version);
+
+/* Queue Shutdown (direct 0x0003) */
+struct i40e_aqc_queue_shutdown {
+       __le32     driver_unloading;
+#define I40E_AQ_DRIVER_UNLOADING    0x1
+       u8     reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_queue_shutdown);
+
+/* Request resource ownership (direct 0x0008)
+ * Release resource ownership (direct 0x0009)
+ */
+#define I40E_AQ_RESOURCE_NVM               1
+#define I40E_AQ_RESOURCE_SDP               2
+#define I40E_AQ_RESOURCE_ACCESS_READ       1
+#define I40E_AQ_RESOURCE_ACCESS_WRITE      2
+#define I40E_AQ_RESOURCE_NVM_READ_TIMEOUT  3000
+#define I40E_AQ_RESOURCE_NVM_WRITE_TIMEOUT 180000
+
+struct i40e_aqc_request_resource {
+       __le16 resource_id;
+       __le16 access_type;
+       __le32 timeout;
+       __le32 resource_number;
+       u8     reserved[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_request_resource);
+
+/* Get function capabilities (indirect 0x000A)
+ * Get device capabilities (indirect 0x000B)
+ */
+struct i40e_aqc_list_capabilites {
+       u8 command_flags;
+#define I40E_AQ_LIST_CAP_PF_INDEX_EN     1
+       u8 pf_index;
+       u8 reserved[2];
+       __le32 count;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_list_capabilites);
+
+struct i40e_aqc_list_capabilities_element_resp {
+       __le16 id;
+       u8     major_rev;
+       u8     minor_rev;
+       __le32 number;
+       __le32 logical_id;
+       __le32 phys_id;
+       u8     reserved[16];
+};
+
+/* list of caps */
+
+#define I40E_AQ_CAP_ID_SWITCH_MODE      0x0001
+#define I40E_AQ_CAP_ID_MNG_MODE         0x0002
+#define I40E_AQ_CAP_ID_NPAR_ACTIVE      0x0003
+#define I40E_AQ_CAP_ID_OS2BMC_CAP       0x0004
+#define I40E_AQ_CAP_ID_FUNCTIONS_VALID  0x0005
+#define I40E_AQ_CAP_ID_ALTERNATE_RAM    0x0006
+#define I40E_AQ_CAP_ID_SRIOV            0x0012
+#define I40E_AQ_CAP_ID_VF               0x0013
+#define I40E_AQ_CAP_ID_VMDQ             0x0014
+#define I40E_AQ_CAP_ID_8021QBG          0x0015
+#define I40E_AQ_CAP_ID_8021QBR          0x0016
+#define I40E_AQ_CAP_ID_VSI              0x0017
+#define I40E_AQ_CAP_ID_DCB              0x0018
+#define I40E_AQ_CAP_ID_FCOE             0x0021
+#define I40E_AQ_CAP_ID_RSS              0x0040
+#define I40E_AQ_CAP_ID_RXQ              0x0041
+#define I40E_AQ_CAP_ID_TXQ              0x0042
+#define I40E_AQ_CAP_ID_MSIX             0x0043
+#define I40E_AQ_CAP_ID_VF_MSIX          0x0044
+#define I40E_AQ_CAP_ID_FLOW_DIRECTOR    0x0045
+#define I40E_AQ_CAP_ID_1588             0x0046
+#define I40E_AQ_CAP_ID_IWARP            0x0051
+#define I40E_AQ_CAP_ID_LED              0x0061
+#define I40E_AQ_CAP_ID_SDP              0x0062
+#define I40E_AQ_CAP_ID_MDIO             0x0063
+#define I40E_AQ_CAP_ID_FLEX10           0x00F1
+#define I40E_AQ_CAP_ID_CEM              0x00F2
+
+/* Set CPPM Configuration (direct 0x0103) */
+struct i40e_aqc_cppm_configuration {
+       __le16 command_flags;
+#define I40E_AQ_CPPM_EN_LTRC    0x0800
+#define I40E_AQ_CPPM_EN_DMCTH   0x1000
+#define I40E_AQ_CPPM_EN_DMCTLX  0x2000
+#define I40E_AQ_CPPM_EN_HPTC    0x4000
+#define I40E_AQ_CPPM_EN_DMARC   0x8000
+       __le16 ttlx;
+       __le32 dmacr;
+       __le16 dmcth;
+       u8     hptc;
+       u8     reserved;
+       __le32 pfltrc;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_cppm_configuration);
+
+/* Set ARP Proxy command / response (indirect 0x0104) */
+struct i40e_aqc_arp_proxy_data {
+       __le16 command_flags;
+#define I40E_AQ_ARP_INIT_IPV4           0x0008
+#define I40E_AQ_ARP_UNSUP_CTL           0x0010
+#define I40E_AQ_ARP_ENA                 0x0020
+#define I40E_AQ_ARP_ADD_IPV4            0x0040
+#define I40E_AQ_ARP_DEL_IPV4            0x0080
+       __le16 table_id;
+       __le32 pfpm_proxyfc;
+       __le32 ip_addr;
+       u8     mac_addr[6];
+};
+
+/* Set NS Proxy Table Entry Command (indirect 0x0105) */
+struct i40e_aqc_ns_proxy_data {
+       __le16 table_idx_mac_addr_0;
+       __le16 table_idx_mac_addr_1;
+       __le16 table_idx_ipv6_0;
+       __le16 table_idx_ipv6_1;
+       __le16 control;
+#define I40E_AQ_NS_PROXY_ADD_0             0x0100
+#define I40E_AQ_NS_PROXY_DEL_0             0x0200
+#define I40E_AQ_NS_PROXY_ADD_1             0x0400
+#define I40E_AQ_NS_PROXY_DEL_1             0x0800
+#define I40E_AQ_NS_PROXY_ADD_IPV6_0        0x1000
+#define I40E_AQ_NS_PROXY_DEL_IPV6_0        0x2000
+#define I40E_AQ_NS_PROXY_ADD_IPV6_1        0x4000
+#define I40E_AQ_NS_PROXY_DEL_IPV6_1        0x8000
+#define I40E_AQ_NS_PROXY_COMMAND_SEQ       0x0001
+#define I40E_AQ_NS_PROXY_INIT_IPV6_TBL     0x0002
+#define I40E_AQ_NS_PROXY_INIT_MAC_TBL      0x0004
+       u8     mac_addr_0[6];
+       u8     mac_addr_1[6];
+       u8     local_mac_addr[6];
+       u8     ipv6_addr_0[16]; /* Warning! spec specifies BE byte order */
+       u8     ipv6_addr_1[16];
+};
+
+/* Manage LAA Command (0x0106) - obsolete */
+struct i40e_aqc_mng_laa {
+       __le16  command_flags;
+#define I40E_AQ_LAA_FLAG_WR   0x8000
+       u8     reserved[2];
+       __le32 sal;
+       __le16 sah;
+       u8     reserved2[6];
+};
+
+/* Manage MAC Address Read Command (0x0107) */
+struct i40e_aqc_mac_address_read {
+       __le16  command_flags;
+#define I40E_AQC_LAN_ADDR_VALID   0x10
+#define I40E_AQC_SAN_ADDR_VALID   0x20
+#define I40E_AQC_PORT_ADDR_VALID  0x40
+#define I40E_AQC_WOL_ADDR_VALID   0x80
+#define I40E_AQC_ADDR_VALID_MASK  0xf0
+       u8     reserved[6];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_read);
+
+struct i40e_aqc_mac_address_read_data {
+       u8 pf_lan_mac[6];
+       u8 pf_san_mac[6];
+       u8 port_mac[6];
+       u8 pf_wol_mac[6];
+};
+
+I40E_CHECK_STRUCT_LEN(24, i40e_aqc_mac_address_read_data);
+
+/* Manage MAC Address Write Command (0x0108) */
+struct i40e_aqc_mac_address_write {
+       __le16 command_flags;
+#define I40E_AQC_WRITE_TYPE_LAA_ONLY    0x0000
+#define I40E_AQC_WRITE_TYPE_LAA_WOL     0x4000
+#define I40E_AQC_WRITE_TYPE_PORT        0x8000
+#define I40E_AQC_WRITE_TYPE_MASK        0xc000
+       __le16 mac_sah;
+       __le32 mac_sal;
+       u8     reserved[8];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_mac_address_write);
+
+/* Switch configuration commands (0x02xx) */
+
+/* Used by many indirect commands that only pass an seid and a buffer in the
+ * command
+ */
+struct i40e_aqc_switch_seid {
+       __le16 seid;
+       u8     reserved[6];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_switch_seid);
+
+/* Get Switch Configuration command (indirect 0x0200)
+ * uses i40e_aqc_switch_seid for the descriptor
+ */
+struct i40e_aqc_get_switch_config_header_resp {
+       __le16 num_reported;
+       __le16 num_total;
+       u8     reserved[12];
+};
+
+struct i40e_aqc_switch_config_element_resp {
+       u8     element_type;
+#define I40E_AQ_SW_ELEM_TYPE_MAC        1
+#define I40E_AQ_SW_ELEM_TYPE_PF         2
+#define I40E_AQ_SW_ELEM_TYPE_VF         3
+#define I40E_AQ_SW_ELEM_TYPE_EMP        4
+#define I40E_AQ_SW_ELEM_TYPE_BMC        5
+#define I40E_AQ_SW_ELEM_TYPE_PV         16
+#define I40E_AQ_SW_ELEM_TYPE_VEB        17
+#define I40E_AQ_SW_ELEM_TYPE_PA         18
+#define I40E_AQ_SW_ELEM_TYPE_VSI        19
+       u8     revision;
+#define I40E_AQ_SW_ELEM_REV_1           1
+       __le16 seid;
+       __le16 uplink_seid;
+       __le16 downlink_seid;
+       u8     reserved[3];
+       u8     connection_type;
+#define I40E_AQ_CONN_TYPE_REGULAR       0x1
+#define I40E_AQ_CONN_TYPE_DEFAULT       0x2
+#define I40E_AQ_CONN_TYPE_CASCADED      0x3
+       __le16 scheduler_id;
+       __le16 element_info;
+};
+
+/* Get Switch Configuration (indirect 0x0200)
+ *    an array of elements are returned in the response buffer
+ *    the first in the array is the header, remainder are elements
+ */
+struct i40e_aqc_get_switch_config_resp {
+       struct i40e_aqc_get_switch_config_header_resp header;
+       struct i40e_aqc_switch_config_element_resp    element[1];
+};
+
+/* Add Statistics (direct 0x0201)
+ * Remove Statistics (direct 0x0202)
+ */
+struct i40e_aqc_add_remove_statistics {
+       __le16 seid;
+       __le16 vlan;
+       __le16 stat_index;
+       u8     reserved[10];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_statistics);
+
+/* Set Port Parameters command (direct 0x0203) */
+struct i40e_aqc_set_port_parameters {
+       __le16 command_flags;
+#define I40E_AQ_SET_P_PARAMS_SAVE_BAD_PACKETS   1
+#define I40E_AQ_SET_P_PARAMS_PAD_SHORT_PACKETS  2 /* must set! */
+#define I40E_AQ_SET_P_PARAMS_DOUBLE_VLAN_ENA    4
+       __le16 bad_frame_vsi;
+       __le16 default_seid;        /* reserved for command */
+       u8     reserved[10];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_port_parameters);
+
+/* Get Switch Resource Allocation (indirect 0x0204) */
+struct i40e_aqc_get_switch_resource_alloc {
+       u8     num_entries;         /* reserved for command */
+       u8     reserved[7];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_resource_alloc);
+
+/* expect an array of these structs in the response buffer */
+struct i40e_aqc_switch_resource_alloc_element_resp {
+       u8     resource_type;
+#define I40E_AQ_RESOURCE_TYPE_VEB                 0x0
+#define I40E_AQ_RESOURCE_TYPE_VSI                 0x1
+#define I40E_AQ_RESOURCE_TYPE_MACADDR             0x2
+#define I40E_AQ_RESOURCE_TYPE_STAG                0x3
+#define I40E_AQ_RESOURCE_TYPE_ETAG                0x4
+#define I40E_AQ_RESOURCE_TYPE_MULTICAST_HASH      0x5
+#define I40E_AQ_RESOURCE_TYPE_UNICAST_HASH        0x6
+#define I40E_AQ_RESOURCE_TYPE_VLAN                0x7
+#define I40E_AQ_RESOURCE_TYPE_VSI_LIST_ENTRY      0x8
+#define I40E_AQ_RESOURCE_TYPE_ETAG_LIST_ENTRY     0x9
+#define I40E_AQ_RESOURCE_TYPE_VLAN_STAT_POOL      0xA
+#define I40E_AQ_RESOURCE_TYPE_MIRROR_RULE         0xB
+#define I40E_AQ_RESOURCE_TYPE_QUEUE_SETS          0xC
+#define I40E_AQ_RESOURCE_TYPE_VLAN_FILTERS        0xD
+#define I40E_AQ_RESOURCE_TYPE_INNER_MAC_FILTERS   0xF
+#define I40E_AQ_RESOURCE_TYPE_IP_FILTERS          0x10
+#define I40E_AQ_RESOURCE_TYPE_GRE_VN_KEYS         0x11
+#define I40E_AQ_RESOURCE_TYPE_VN2_KEYS            0x12
+#define I40E_AQ_RESOURCE_TYPE_TUNNEL_PORTS        0x13
+       u8     reserved1;
+       __le16 guaranteed;
+       __le16 total;
+       __le16 used;
+       __le16 total_unalloced;
+       u8     reserved2[6];
+};
+
+/* Add VSI (indirect 0x210)
+ *    this indirect command uses struct i40e_aqc_vsi_properties_data
+ *    as the indirect buffer (128 bytes)
+ *
+ * Update VSI (indirect 0x211) Get VSI (indirect 0x0212)
+ *    use the generic i40e_aqc_switch_seid descriptor format
+ *    use the same completion and data structure as Add VSI
+ */
+struct i40e_aqc_add_get_update_vsi {
+       __le16 uplink_seid;
+       u8     connection_type;
+#define I40E_AQ_VSI_CONN_TYPE_NORMAL            0x1
+#define I40E_AQ_VSI_CONN_TYPE_DEFAULT           0x2
+#define I40E_AQ_VSI_CONN_TYPE_CASCADED          0x3
+       u8     reserved1;
+       u8     vf_id;
+       u8     reserved2;
+       __le16 vsi_flags;
+#define I40E_AQ_VSI_TYPE_SHIFT          0x0
+#define I40E_AQ_VSI_TYPE_MASK           (0x3 << I40E_AQ_VSI_TYPE_SHIFT)
+#define I40E_AQ_VSI_TYPE_VF             0x0
+#define I40E_AQ_VSI_TYPE_VMDQ2          0x1
+#define I40E_AQ_VSI_TYPE_PF             0x2
+#define I40E_AQ_VSI_TYPE_EMP_MNG        0x3
+#define I40E_AQ_VSI_FLAG_CASCADED_PV    0x4
+#define I40E_AQ_VSI_FLAG_CLOUD_VSI      0x8
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi);
+
+struct i40e_aqc_add_get_update_vsi_completion {
+       __le16 seid;
+       __le16 vsi_number;
+       __le16 vsi_used;
+       __le16 vsi_free;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_get_update_vsi_completion);
+
+struct i40e_aqc_vsi_properties_data {
+       /* first 96 byte are written by SW */
+       __le16 valid_sections;
+#define I40E_AQ_VSI_PROP_SWITCH_VALID       0x0001
+#define I40E_AQ_VSI_PROP_SECURITY_VALID     0x0002
+#define I40E_AQ_VSI_PROP_VLAN_VALID         0x0004
+#define I40E_AQ_VSI_PROP_CAS_PV_VALID       0x0008
+#define I40E_AQ_VSI_PROP_INGRESS_UP_VALID   0x0010
+#define I40E_AQ_VSI_PROP_EGRESS_UP_VALID    0x0020
+#define I40E_AQ_VSI_PROP_QUEUE_MAP_VALID    0x0040
+#define I40E_AQ_VSI_PROP_QUEUE_OPT_VALID    0x0080
+#define I40E_AQ_VSI_PROP_OUTER_UP_VALID     0x0100
+#define I40E_AQ_VSI_PROP_SCHED_VALID        0x0200
+       /* switch section */
+       __le16 switch_id; /* 12bit id combined with flags below */
+#define I40E_AQ_VSI_SW_ID_SHIFT             0x0000
+#define I40E_AQ_VSI_SW_ID_MASK              (0xFFF << I40E_AQ_VSI_SW_ID_SHIFT)
+#define I40E_AQ_VSI_SW_ID_FLAG_NOT_STAG     0x1000
+#define I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB     0x2000
+#define I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB     0x4000
+       u8     sw_reserved[2];
+       /* security section */
+       u8     sec_flags;
+#define I40E_AQ_VSI_SEC_FLAG_ALLOW_DEST_OVRD    0x01
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_VLAN_CHK    0x02
+#define I40E_AQ_VSI_SEC_FLAG_ENABLE_MAC_CHK     0x04
+       u8     sec_reserved;
+       /* VLAN section */
+       __le16 pvid; /* VLANS include priority bits */
+       __le16 fcoe_pvid;
+       u8     port_vlan_flags;
+#define I40E_AQ_VSI_PVLAN_MODE_SHIFT        0x00
+#define I40E_AQ_VSI_PVLAN_MODE_MASK         (0x03 << \
+                                               I40E_AQ_VSI_PVLAN_MODE_SHIFT)
+#define I40E_AQ_VSI_PVLAN_MODE_TAGGED       0x01
+#define I40E_AQ_VSI_PVLAN_MODE_UNTAGGED     0x02
+#define I40E_AQ_VSI_PVLAN_MODE_ALL          0x03
+#define I40E_AQ_VSI_PVLAN_INSERT_PVID       0x04
+#define I40E_AQ_VSI_PVLAN_EMOD_SHIFT        0x03
+#define I40E_AQ_VSI_PVLAN_EMOD_MASK         (0x3 << \
+                                       I40E_AQ_VSI_PVLAN_EMOD_SHIFT)
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH     0x0
+#define I40E_AQ_VSI_PVLAN_EMOD_STR_UP       0x08
+#define I40E_AQ_VSI_PVLAN_EMOD_STR          0x10
+#define I40E_AQ_VSI_PVLAN_EMOD_NOTHING      0x18
+       u8     pvlan_reserved[3];
+       /* ingress egress up sections */
+       __le32 ingress_table; /* bitmap, 3 bits per up */
+#define I40E_AQ_VSI_UP_TABLE_UP0_SHIFT      0
+#define I40E_AQ_VSI_UP_TABLE_UP0_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP0_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP1_SHIFT      3
+#define I40E_AQ_VSI_UP_TABLE_UP1_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP1_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP2_SHIFT      6
+#define I40E_AQ_VSI_UP_TABLE_UP2_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP2_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP3_SHIFT      9
+#define I40E_AQ_VSI_UP_TABLE_UP3_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP3_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP4_SHIFT      12
+#define I40E_AQ_VSI_UP_TABLE_UP4_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP4_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP5_SHIFT      15
+#define I40E_AQ_VSI_UP_TABLE_UP5_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP5_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP6_SHIFT      18
+#define I40E_AQ_VSI_UP_TABLE_UP6_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP6_SHIFT)
+#define I40E_AQ_VSI_UP_TABLE_UP7_SHIFT      21
+#define I40E_AQ_VSI_UP_TABLE_UP7_MASK       (0x7 << \
+                                       I40E_AQ_VSI_UP_TABLE_UP7_SHIFT)
+       __le32 egress_table;   /* same defines as for ingress table */
+       /* cascaded PV section */
+       __le16 cas_pv_tag;
+       u8     cas_pv_flags;
+#define I40E_AQ_VSI_CAS_PV_TAGX_SHIFT      0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_MASK       (0x03 << \
+                                               I40E_AQ_VSI_CAS_PV_TAGX_SHIFT)
+#define I40E_AQ_VSI_CAS_PV_TAGX_LEAVE      0x00
+#define I40E_AQ_VSI_CAS_PV_TAGX_REMOVE     0x01
+#define I40E_AQ_VSI_CAS_PV_TAGX_COPY       0x02
+#define I40E_AQ_VSI_CAS_PV_INSERT_TAG      0x10
+#define I40E_AQ_VSI_CAS_PV_ETAG_PRUNE      0x20
+#define I40E_AQ_VSI_CAS_PV_ACCEPT_HOST_TAG 0x40
+       u8     cas_pv_reserved;
+       /* queue mapping section */
+       __le16 mapping_flags;
+#define I40E_AQ_VSI_QUE_MAP_CONTIG          0x0
+#define I40E_AQ_VSI_QUE_MAP_NONCONTIG       0x1
+       __le16 queue_mapping[16];
+#define I40E_AQ_VSI_QUEUE_SHIFT             0x0
+#define I40E_AQ_VSI_QUEUE_MASK              (0x7FF << I40E_AQ_VSI_QUEUE_SHIFT)
+       __le16 tc_mapping[8];
+#define I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT     0
+#define I40E_AQ_VSI_TC_QUE_OFFSET_MASK      (0x1FF << \
+                                               I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT)
+#define I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT     9
+#define I40E_AQ_VSI_TC_QUE_NUMBER_MASK      (0x7 << \
+                                               I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT)
+       /* queueing option section */
+       u8     queueing_opt_flags;
+#define I40E_AQ_VSI_QUE_OPT_TCP_ENA         0x10
+#define I40E_AQ_VSI_QUE_OPT_FCOE_ENA        0x20
+       u8     queueing_opt_reserved[3];
+       /* scheduler section */
+       u8     up_enable_bits;
+       u8     sched_reserved;
+       /* outer up section */
+       __le32 outer_up_table; /* same structure and defines as ingress table */
+       u8     cmd_reserved[8];
+       /* last 32 bytes are written by FW */
+       __le16 qs_handle[8];
+#define I40E_AQ_VSI_QS_HANDLE_INVALID  0xFFFF
+       __le16 stat_counter_idx;
+       __le16 sched_id;
+       u8     resp_reserved[12];
+};
+
+I40E_CHECK_STRUCT_LEN(128, i40e_aqc_vsi_properties_data);
+
+/* Add Port Virtualizer (direct 0x0220)
+ * also used for update PV (direct 0x0221) but only flags are used
+ * (IS_CTRL_PORT only works on add PV)
+ */
+struct i40e_aqc_add_update_pv {
+       __le16 command_flags;
+#define I40E_AQC_PV_FLAG_PV_TYPE                0x1
+#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_STAG_EN    0x2
+#define I40E_AQC_PV_FLAG_FWD_UNKNOWN_ETAG_EN    0x4
+#define I40E_AQC_PV_FLAG_IS_CTRL_PORT           0x8
+       __le16 uplink_seid;
+       __le16 connected_seid;
+       u8     reserved[10];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv);
+
+struct i40e_aqc_add_update_pv_completion {
+       /* reserved for update; for add also encodes error if rc == ENOSPC */
+       __le16 pv_seid;
+#define I40E_AQC_PV_ERR_FLAG_NO_PV               0x1
+#define I40E_AQC_PV_ERR_FLAG_NO_SCHED            0x2
+#define I40E_AQC_PV_ERR_FLAG_NO_COUNTER          0x4
+#define I40E_AQC_PV_ERR_FLAG_NO_ENTRY            0x8
+       u8     reserved[14];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_update_pv_completion);
+
+/* Get PV Params (direct 0x0222)
+ * uses i40e_aqc_switch_seid for the descriptor
+ */
+
+struct i40e_aqc_get_pv_params_completion {
+       __le16 seid;
+       __le16 default_stag;
+       __le16 pv_flags; /* same flags as add_pv */
+#define I40E_AQC_GET_PV_PV_TYPE            0x1
+#define I40E_AQC_GET_PV_FRWD_UNKNOWN_STAG  0x2
+#define I40E_AQC_GET_PV_FRWD_UNKNOWN_ETAG  0x4
+       u8     reserved[8];
+       __le16 default_port_seid;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_pv_params_completion);
+
+/* Add VEB (direct 0x0230) */
+struct i40e_aqc_add_veb {
+       __le16 uplink_seid;
+       __le16 downlink_seid;
+       __le16 veb_flags;
+#define I40E_AQC_ADD_VEB_FLOATING           0x1
+#define I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT    1
+#define I40E_AQC_ADD_VEB_PORT_TYPE_MASK     (0x3 << \
+                                       I40E_AQC_ADD_VEB_PORT_TYPE_SHIFT)
+#define I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT  0x2
+#define I40E_AQC_ADD_VEB_PORT_TYPE_DATA     0x4
+#define I40E_AQC_ADD_VEB_ENABLE_L2_FILTER   0x8
+       u8     enable_tcs;
+       u8     reserved[9];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb);
+
+struct i40e_aqc_add_veb_completion {
+       u8     reserved[6];
+       __le16 switch_seid;
+       /* also encodes error if rc == ENOSPC; codes are the same as add_pv */
+       __le16 veb_seid;
+#define I40E_AQC_VEB_ERR_FLAG_NO_VEB              0x1
+#define I40E_AQC_VEB_ERR_FLAG_NO_SCHED            0x2
+#define I40E_AQC_VEB_ERR_FLAG_NO_COUNTER          0x4
+#define I40E_AQC_VEB_ERR_FLAG_NO_ENTRY            0x8
+       __le16 statistic_index;
+       __le16 vebs_used;
+       __le16 vebs_free;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_veb_completion);
+
+/* Get VEB Parameters (direct 0x0232)
+ * uses i40e_aqc_switch_seid for the descriptor
+ */
+struct i40e_aqc_get_veb_parameters_completion {
+       __le16 seid;
+       __le16 switch_id;
+       __le16 veb_flags; /* only the first/last flags from 0x0230 is valid */
+       __le16 statistic_index;
+       __le16 vebs_used;
+       __le16 vebs_free;
+       u8     reserved[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_veb_parameters_completion);
+
+/* Delete Element (direct 0x0243)
+ * uses the generic i40e_aqc_switch_seid
+ */
+
+/* Add MAC-VLAN (indirect 0x0250) */
+
+/* used for the command for most vlan commands */
+struct i40e_aqc_macvlan {
+       __le16 num_addresses;
+       __le16 seid[3];
+#define I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT  0
+#define I40E_AQC_MACVLAN_CMD_SEID_NUM_MASK   (0x3FF << \
+                                       I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
+#define I40E_AQC_MACVLAN_CMD_SEID_VALID      0x8000
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_macvlan);
+
+/* indirect data for command and response */
+struct i40e_aqc_add_macvlan_element_data {
+       u8     mac_addr[6];
+       __le16 vlan_tag;
+       __le16 flags;
+#define I40E_AQC_MACVLAN_ADD_PERFECT_MATCH     0x0001
+#define I40E_AQC_MACVLAN_ADD_HASH_MATCH        0x0002
+#define I40E_AQC_MACVLAN_ADD_IGNORE_VLAN       0x0004
+#define I40E_AQC_MACVLAN_ADD_TO_QUEUE          0x0008
+       __le16 queue_number;
+#define I40E_AQC_MACVLAN_CMD_QUEUE_SHIFT  0
+#define I40E_AQC_MACVLAN_CMD_QUEUE_MASK   (0x7FF << \
+                                       I40E_AQC_MACVLAN_CMD_SEID_NUM_SHIFT)
+       /* response section */
+       u8     match_method;
+#define I40E_AQC_MM_PERFECT_MATCH             0x01
+#define I40E_AQC_MM_HASH_MATCH                0x02
+#define I40E_AQC_MM_ERR_NO_RES                0xFF
+       u8     reserved1[3];
+};
+
+struct i40e_aqc_add_remove_macvlan_completion {
+       __le16 perfect_mac_used;
+       __le16 perfect_mac_free;
+       __le16 unicast_hash_free;
+       __le16 multicast_hash_free;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_macvlan_completion);
+
+/* Remove MAC-VLAN (indirect 0x0251)
+ * uses i40e_aqc_macvlan for the descriptor
+ * data points to an array of num_addresses of elements
+ */
+
+struct i40e_aqc_remove_macvlan_element_data {
+       u8     mac_addr[6];
+       __le16 vlan_tag;
+       u8     flags;
+#define I40E_AQC_MACVLAN_DEL_PERFECT_MATCH      0x01
+#define I40E_AQC_MACVLAN_DEL_HASH_MATCH         0x02
+#define I40E_AQC_MACVLAN_DEL_IGNORE_VLAN        0x08
+#define I40E_AQC_MACVLAN_DEL_ALL_VSIS           0x10
+       u8     reserved[3];
+       /* reply section */
+       u8     error_code;
+#define I40E_AQC_REMOVE_MACVLAN_SUCCESS         0x0
+#define I40E_AQC_REMOVE_MACVLAN_FAIL            0xFF
+       u8     reply_reserved[3];
+};
+
+/* Add VLAN (indirect 0x0252)
+ * Remove VLAN (indirect 0x0253)
+ * use the generic i40e_aqc_macvlan for the command
+ */
+struct i40e_aqc_add_remove_vlan_element_data {
+       __le16 vlan_tag;
+       u8     vlan_flags;
+/* flags for add VLAN */
+#define I40E_AQC_ADD_VLAN_LOCAL             0x1
+#define I40E_AQC_ADD_PVLAN_TYPE_SHIFT       1
+#define I40E_AQC_ADD_PVLAN_TYPE_MASK        (0x3 << \
+                                               I40E_AQC_ADD_PVLAN_TYPE_SHIFT)
+#define I40E_AQC_ADD_PVLAN_TYPE_REGULAR     0x0
+#define I40E_AQC_ADD_PVLAN_TYPE_PRIMARY     0x2
+#define I40E_AQC_ADD_PVLAN_TYPE_SECONDARY   0x4
+#define I40E_AQC_VLAN_PTYPE_SHIFT           3
+#define I40E_AQC_VLAN_PTYPE_MASK            (0x3 << I40E_AQC_VLAN_PTYPE_SHIFT)
+#define I40E_AQC_VLAN_PTYPE_REGULAR_VSI     0x0
+#define I40E_AQC_VLAN_PTYPE_PROMISC_VSI     0x8
+#define I40E_AQC_VLAN_PTYPE_COMMUNITY_VSI   0x10
+#define I40E_AQC_VLAN_PTYPE_ISOLATED_VSI    0x18
+/* flags for remove VLAN */
+#define I40E_AQC_REMOVE_VLAN_ALL            0x1
+       u8     reserved;
+       u8     result;
+/* flags for add VLAN */
+#define I40E_AQC_ADD_VLAN_SUCCESS       0x0
+#define I40E_AQC_ADD_VLAN_FAIL_REQUEST  0xFE
+#define I40E_AQC_ADD_VLAN_FAIL_RESOURCE 0xFF
+/* flags for remove VLAN */
+#define I40E_AQC_REMOVE_VLAN_SUCCESS    0x0
+#define I40E_AQC_REMOVE_VLAN_FAIL       0xFF
+       u8     reserved1[3];
+};
+
+struct i40e_aqc_add_remove_vlan_completion {
+       u8     reserved[4];
+       __le16 vlans_used;
+       __le16 vlans_free;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+/* Set VSI Promiscuous Modes (direct 0x0254) */
+struct i40e_aqc_set_vsi_promiscuous_modes {
+       __le16 promiscuous_flags;
+       __le16 valid_flags;
+/* flags used for both fields above */
+#define I40E_AQC_SET_VSI_PROMISC_UNICAST     0x01
+#define I40E_AQC_SET_VSI_PROMISC_MULTICAST   0x02
+#define I40E_AQC_SET_VSI_PROMISC_BROADCAST   0x04
+#define I40E_AQC_SET_VSI_DEFAULT             0x08
+#define I40E_AQC_SET_VSI_PROMISC_VLAN        0x10
+       __le16 seid;
+#define I40E_AQC_VSI_PROM_CMD_SEID_MASK      0x3FF
+       u8     reserved[10];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_vsi_promiscuous_modes);
+
+/* Add S/E-tag command (direct 0x0255)
+ * Uses generic i40e_aqc_add_remove_tag_completion for completion
+ */
+struct i40e_aqc_add_tag {
+       __le16 flags;
+#define I40E_AQC_ADD_TAG_FLAG_TO_QUEUE     0x0001
+       __le16 seid;
+#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT  0
+#define I40E_AQC_ADD_TAG_CMD_SEID_NUM_MASK   (0x3FF << \
+                                       I40E_AQC_ADD_TAG_CMD_SEID_NUM_SHIFT)
+       __le16 tag;
+       __le16 queue_number;
+       u8     reserved[8];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_tag);
+
+struct i40e_aqc_add_remove_tag_completion {
+       u8     reserved[12];
+       __le16 tags_used;
+       __le16 tags_free;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_tag_completion);
+
+/* Remove S/E-tag command (direct 0x0256)
+ * Uses generic i40e_aqc_add_remove_tag_completion for completion
+ */
+struct i40e_aqc_remove_tag {
+       __le16 seid;
+#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT  0
+#define I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_MASK   (0x3FF << \
+                                       I40E_AQC_REMOVE_TAG_CMD_SEID_NUM_SHIFT)
+       __le16 tag;
+       u8     reserved[12];
+};
+
+/* Add multicast E-Tag (direct 0x0257)
+ * del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields
+ * and no external data
+ */
+struct i40e_aqc_add_remove_mcast_etag {
+       __le16 pv_seid;
+       __le16 etag;
+       u8     num_unicast_etags;
+       u8     reserved[3];
+       __le32 addr_high;          /* address of array of 2-byte s-tags */
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag);
+
+struct i40e_aqc_add_remove_mcast_etag_completion {
+       u8     reserved[4];
+       __le16 mcast_etags_used;
+       __le16 mcast_etags_free;
+       __le32 addr_high;
+       __le32 addr_low;
+
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_mcast_etag_completion);
+
+/* Update S/E-Tag (direct 0x0259) */
+struct i40e_aqc_update_tag {
+       __le16 seid;
+#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT  0
+#define I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_MASK   (0x3FF << \
+                                       I40E_AQC_UPDATE_TAG_CMD_SEID_NUM_SHIFT)
+       __le16 old_tag;
+       __le16 new_tag;
+       u8     reserved[10];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag);
+
+struct i40e_aqc_update_tag_completion {
+       u8     reserved[12];
+       __le16 tags_used;
+       __le16 tags_free;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_update_tag_completion);
+
+/* Add Control Packet filter (direct 0x025A)
+ * Remove Control Packet filter (direct 0x025B)
+ * uses the i40e_aqc_add_oveb_cloud,
+ * and the generic direct completion structure
+ */
+struct i40e_aqc_add_remove_control_packet_filter {
+       u8     mac[6];
+       __le16 etype;
+       __le16 flags;
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC    0x0001
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP          0x0002
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE      0x0004
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TX            0x0008
+#define I40E_AQC_ADD_CONTROL_PACKET_FLAGS_RX            0x0000
+       __le16 seid;
+#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT  0
+#define I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_MASK   (0x3FF << \
+                               I40E_AQC_ADD_CONTROL_PACKET_CMD_SEID_NUM_SHIFT)
+       __le16 queue;
+       u8     reserved[2];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter);
+
+struct i40e_aqc_add_remove_control_packet_filter_completion {
+       __le16 mac_etype_used;
+       __le16 etype_used;
+       __le16 mac_etype_free;
+       __le16 etype_free;
+       u8     reserved[8];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_control_packet_filter_completion);
+
+/* Add Cloud filters (indirect 0x025C)
+ * Remove Cloud filters (indirect 0x025D)
+ * uses the i40e_aqc_add_remove_cloud_filters,
+ * and the generic indirect completion structure
+ */
+struct i40e_aqc_add_remove_cloud_filters {
+       u8     num_filters;
+       u8     reserved;
+       __le16 seid;
+#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT  0
+#define I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_MASK   (0x3FF << \
+                                       I40E_AQC_ADD_CLOUD_CMD_SEID_NUM_SHIFT)
+       u8     reserved2[4];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_remove_cloud_filters);
+
+struct i40e_aqc_add_remove_cloud_filters_element_data {
+       u8     outer_mac[6];
+       u8     inner_mac[6];
+       __le16 inner_vlan;
+       union {
+               struct {
+                       u8 reserved[12];
+                       u8 data[4];
+               } v4;
+               struct {
+                       u8 data[16];
+                       } v6;
+               } ipaddr;
+       __le16 flags;
+#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT                 0
+#define I40E_AQC_ADD_CLOUD_FILTER_MASK                  (0x3F << \
+                                       I40E_AQC_ADD_CLOUD_FILTER_SHIFT)
+#define I40E_AQC_ADD_CLOUD_FILTER_OIP                   0x0001
+#define I40E_AQC_ADD_CLOUD_FILTER_OIP_GRE               0x0002
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN            0x0003
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_GRE        0x0004
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID           0x0006
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_VNL        0x0007
+/* 0x0008 reserved */
+#define I40E_AQC_ADD_CLOUD_FILTER_OMAC                  0x0009
+#define I40E_AQC_ADD_CLOUD_FILTER_IMAC                  0x000A
+#define I40E_AQC_ADD_CLOUD_FLAGS_TO_QUEUE               0x0080
+#define I40E_AQC_ADD_CLOUD_VNK_SHIFT                    6
+#define I40E_AQC_ADD_CLOUD_VNK_MASK                     0x00C0
+#define I40E_AQC_ADD_CLOUD_FLAGS_IPV4                   0
+#define I40E_AQC_ADD_CLOUD_FLAGS_IPV6                   0x0100
+       __le32 key_low;
+       __le32 key_high;
+       __le16 queue_number;
+#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT                  0
+#define I40E_AQC_ADD_CLOUD_QUEUE_MASK                   (0x3F << \
+                                       I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
+       u8     reserved[14];
+       /* response section */
+       u8     allocation_result;
+#define I40E_AQC_ADD_CLOUD_FILTER_SUCCESS         0x0
+#define I40E_AQC_ADD_CLOUD_FILTER_FAIL            0xFF
+       u8     response_reserved[7];
+};
+
+struct i40e_aqc_remove_cloud_filters_completion {
+       __le16 perfect_ovlan_used;
+       __le16 perfect_ovlan_free;
+       __le16 vlan_used;
+       __le16 vlan_free;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_cloud_filters_completion);
+
+/* Add Mirror Rule (indirect or direct 0x0260)
+ * Delete Mirror Rule (indirect or direct 0x0261)
+ * note: some rule types (4,5) do not use an external buffer.
+ *       take care to set the flags correctly.
+ */
+struct i40e_aqc_add_delete_mirror_rule {
+       __le16 seid;
+       __le16 rule_type;
+#define I40E_AQC_MIRROR_RULE_TYPE_SHIFT            0
+#define I40E_AQC_MIRROR_RULE_TYPE_MASK             (0x7 << \
+                                               I40E_AQC_MIRROR_RULE_TYPE_SHIFT)
+#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_INGRESS    1
+#define I40E_AQC_MIRROR_RULE_TYPE_VPORT_EGRESS     2
+#define I40E_AQC_MIRROR_RULE_TYPE_VLAN             3
+#define I40E_AQC_MIRROR_RULE_TYPE_ALL_INGRESS      4
+#define I40E_AQC_MIRROR_RULE_TYPE_ALL_EGRESS       5
+       __le16 num_entries;
+       __le16 destination;  /* VSI for add, rule id for delete */
+       __le32 addr_high;    /* address of array of 2-byte VSI or VLAN ids */
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule);
+
+struct i40e_aqc_add_delete_mirror_rule_completion {
+       u8     reserved[2];
+       __le16 rule_id;  /* only used on add */
+       __le16 mirror_rules_used;
+       __le16 mirror_rules_free;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_delete_mirror_rule_completion);
+
+/* Set Storm Control Configuration (direct 0x0280)
+ * Get Storm Control Configuration (direct 0x0281)
+ *    the command and response use the same descriptor structure
+ */
+struct i40e_aqc_set_get_storm_control_config {
+       __le32 broadcast_threshold;
+       __le32 multicast_threshold;
+       __le32 control_flags;
+#define I40E_AQC_STORM_CONTROL_MDIPW            0x01
+#define I40E_AQC_STORM_CONTROL_MDICW            0x02
+#define I40E_AQC_STORM_CONTROL_BDIPW            0x04
+#define I40E_AQC_STORM_CONTROL_BDICW            0x08
+#define I40E_AQC_STORM_CONTROL_BIDU             0x10
+#define I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT   8
+#define I40E_AQC_STORM_CONTROL_INTERVAL_MASK    (0x3FF << \
+                                       I40E_AQC_STORM_CONTROL_INTERVAL_SHIFT)
+       u8     reserved[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_get_storm_control_config);
+
+/* DCB 0x03xx*/
+
+/* PFC Ignore (direct 0x0301)
+ *    the command and response use the same descriptor structure
+ */
+struct i40e_aqc_pfc_ignore {
+       u8     tc_bitmap;
+       u8     command_flags; /* unused on response */
+#define I40E_AQC_PFC_IGNORE_SET    0x80
+#define I40E_AQC_PFC_IGNORE_CLEAR  0x0
+       u8     reserved[14];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_pfc_ignore);
+
+/* DCB Update (direct 0x0302) uses the i40e_aq_desc structure
+ * with no parameters
+ */
+
+/* TX scheduler 0x04xx */
+
+/* Almost all the indirect commands use
+ * this generic struct to pass the SEID in param0
+ */
+struct i40e_aqc_tx_sched_ind {
+       __le16 vsi_seid;
+       u8     reserved[6];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_tx_sched_ind);
+
+/* Several commands respond with a set of queue set handles */
+struct i40e_aqc_qs_handles_resp {
+       __le16 qs_handles[8];
+};
+
+/* Configure VSI BW limits (direct 0x0400) */
+struct i40e_aqc_configure_vsi_bw_limit {
+       __le16 vsi_seid;
+       u8     reserved[2];
+       __le16 credit;
+       u8     reserved1[2];
+       u8     max_credit; /* 0-3, limit = 2^max */
+       u8     reserved2[7];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_vsi_bw_limit);
+
+/* Configure VSI Bandwidth Limit per Traffic Type (indirect 0x0406)
+ *    responds with i40e_aqc_qs_handles_resp
+ */
+struct i40e_aqc_configure_vsi_ets_sla_bw_data {
+       u8     tc_valid_bits;
+       u8     reserved[15];
+       __le16 tc_bw_credits[8]; /* FW writesback QS handles here */
+
+       /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
+       __le16 tc_bw_max[2];
+       u8     reserved1[28];
+};
+
+/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407)
+ *    responds with i40e_aqc_qs_handles_resp
+ */
+struct i40e_aqc_configure_vsi_tc_bw_data {
+       u8     tc_valid_bits;
+       u8     reserved[3];
+       u8     tc_bw_credits[8];
+       u8     reserved1[4];
+       __le16 qs_handles[8];
+};
+
+/* Query vsi bw configuration (indirect 0x0408) */
+struct i40e_aqc_query_vsi_bw_config_resp {
+       u8     tc_valid_bits;
+       u8     tc_suspended_bits;
+       u8     reserved[14];
+       __le16 qs_handles[8];
+       u8     reserved1[4];
+       __le16 port_bw_limit;
+       u8     reserved2[2];
+       u8     max_bw; /* 0-3, limit = 2^max */
+       u8     reserved3[23];
+};
+
+/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */
+struct i40e_aqc_query_vsi_ets_sla_config_resp {
+       u8     tc_valid_bits;
+       u8     reserved[3];
+       u8     share_credits[8];
+       __le16 credits[8];
+
+       /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
+       __le16 tc_bw_max[2];
+};
+
+/* Configure Switching Component Bandwidth Limit (direct 0x0410) */
+struct i40e_aqc_configure_switching_comp_bw_limit {
+       __le16 seid;
+       u8     reserved[2];
+       __le16 credit;
+       u8     reserved1[2];
+       u8     max_bw; /* 0-3, limit = 2^max */
+       u8     reserved2[7];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_configure_switching_comp_bw_limit);
+
+/* Enable  Physical Port ETS (indirect 0x0413)
+ * Modify  Physical Port ETS (indirect 0x0414)
+ * Disable Physical Port ETS (indirect 0x0415)
+ */
+struct i40e_aqc_configure_switching_comp_ets_data {
+       u8     reserved[4];
+       u8     tc_valid_bits;
+       u8     reserved1;
+       u8     tc_strict_priority_flags;
+       u8     reserved2[17];
+       u8     tc_bw_share_credits[8];
+       u8     reserved3[96];
+};
+
+/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */
+struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
+       u8     tc_valid_bits;
+       u8     reserved[15];
+       __le16 tc_bw_credit[8];
+
+       /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
+       __le16 tc_bw_max[2];
+       u8     reserved1[28];
+};
+
+/* Configure Switching Component Bandwidth Allocation per Tc
+ * (indirect 0x0417)
+ */
+struct i40e_aqc_configure_switching_comp_bw_config_data {
+       u8     tc_valid_bits;
+       u8     reserved[2];
+       u8     absolute_credits; /* bool */
+       u8     tc_bw_share_credits[8];
+       u8     reserved1[20];
+};
+
+/* Query Switching Component Configuration (indirect 0x0418) */
+struct i40e_aqc_query_switching_comp_ets_config_resp {
+       u8     tc_valid_bits;
+       u8     reserved[35];
+       __le16 port_bw_limit;
+       u8     reserved1[2];
+       u8     tc_bw_max; /* 0-3, limit = 2^max */
+       u8     reserved2[23];
+};
+
+/* Query PhysicalPort ETS Configuration (indirect 0x0419) */
+struct i40e_aqc_query_port_ets_config_resp {
+       u8     reserved[4];
+       u8     tc_valid_bits;
+       u8     reserved1;
+       u8     tc_strict_priority_bits;
+       u8     reserved2;
+       u8     tc_bw_share_credits[8];
+       __le16 tc_bw_limits[8];
+
+       /* 4 bits per tc 0-7, 4th bit reserved, limit = 2^max */
+       __le16 tc_bw_max[2];
+       u8     reserved3[32];
+};
+
+/* Query Switching Component Bandwidth Allocation per Traffic Type
+ * (indirect 0x041A)
+ */
+struct i40e_aqc_query_switching_comp_bw_config_resp {
+       u8     tc_valid_bits;
+       u8     reserved[2];
+       u8     absolute_credits_enable; /* bool */
+       u8     tc_bw_share_credits[8];
+       __le16 tc_bw_limits[8];
+
+       /* 4 bits per tc 0-7, 4th bit is reserved, limit = 2^max */
+       __le16 tc_bw_max[2];
+};
+
+/* Suspend/resume port TX traffic
+ * (direct 0x041B and 0x041C) uses the generic SEID struct
+ */
+
+/* Get and set the active HMC resource profile and status.
+ * (direct 0x0500) and (direct 0x0501)
+ */
+struct i40e_aq_get_set_hmc_resource_profile {
+       u8     pm_profile;
+       u8     pe_vf_enabled;
+       u8     reserved[14];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aq_get_set_hmc_resource_profile);
+
+enum i40e_aq_hmc_profile {
+       /* I40E_HMC_PROFILE_NO_CHANGE    = 0, reserved */
+       I40E_HMC_PROFILE_DEFAULT     = 1,
+       I40E_HMC_PROFILE_FAVOR_VF    = 2,
+       I40E_HMC_PROFILE_EQUAL       = 3,
+};
+
+#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_PM_MASK       0xF
+#define I40E_AQ_GET_HMC_RESOURCE_PROFILE_COUNT_MASK    0x3F
+
+/* Get PHY Abilities (indirect 0x0600) uses the generic indirect struct */
+
+/* set in param0 for get phy abilities to report qualified modules */
+#define I40E_AQ_PHY_REPORT_QUALIFIED_MODULES  0x0001
+#define I40E_AQ_PHY_REPORT_INITIAL_VALUES     0x0002
+
+enum i40e_aq_phy_type {
+       I40E_PHY_TYPE_SGMII                     = 0x0,
+       I40E_PHY_TYPE_1000BASE_KX               = 0x1,
+       I40E_PHY_TYPE_10GBASE_KX4               = 0x2,
+       I40E_PHY_TYPE_10GBASE_KR                = 0x3,
+       I40E_PHY_TYPE_40GBASE_KR4               = 0x4,
+       I40E_PHY_TYPE_XAUI                      = 0x5,
+       I40E_PHY_TYPE_XFI                       = 0x6,
+       I40E_PHY_TYPE_SFI                       = 0x7,
+       I40E_PHY_TYPE_XLAUI                     = 0x8,
+       I40E_PHY_TYPE_XLPPI                     = 0x9,
+       I40E_PHY_TYPE_40GBASE_CR4_CU            = 0xA,
+       I40E_PHY_TYPE_10GBASE_CR1_CU            = 0xB,
+       I40E_PHY_TYPE_100BASE_TX                = 0x11,
+       I40E_PHY_TYPE_1000BASE_T                = 0x12,
+       I40E_PHY_TYPE_10GBASE_T                 = 0x13,
+       I40E_PHY_TYPE_10GBASE_SR                = 0x14,
+       I40E_PHY_TYPE_10GBASE_LR                = 0x15,
+       I40E_PHY_TYPE_10GBASE_SFPP_CU           = 0x16,
+       I40E_PHY_TYPE_10GBASE_CR1               = 0x17,
+       I40E_PHY_TYPE_40GBASE_CR4               = 0x18,
+       I40E_PHY_TYPE_40GBASE_SR4               = 0x19,
+       I40E_PHY_TYPE_40GBASE_LR4               = 0x1A,
+       I40E_PHY_TYPE_20GBASE_KR2               = 0x1B,
+       I40E_PHY_TYPE_MAX
+};
+
+#define I40E_LINK_SPEED_100MB_SHIFT    0x1
+#define I40E_LINK_SPEED_1000MB_SHIFT   0x2
+#define I40E_LINK_SPEED_10GB_SHIFT     0x3
+#define I40E_LINK_SPEED_40GB_SHIFT     0x4
+#define I40E_LINK_SPEED_20GB_SHIFT     0x5
+
+enum i40e_aq_link_speed {
+       I40E_LINK_SPEED_UNKNOWN = 0,
+       I40E_LINK_SPEED_100MB   = (1 << I40E_LINK_SPEED_100MB_SHIFT),
+       I40E_LINK_SPEED_1GB     = (1 << I40E_LINK_SPEED_1000MB_SHIFT),
+       I40E_LINK_SPEED_10GB    = (1 << I40E_LINK_SPEED_10GB_SHIFT),
+       I40E_LINK_SPEED_40GB    = (1 << I40E_LINK_SPEED_40GB_SHIFT),
+       I40E_LINK_SPEED_20GB    = (1 << I40E_LINK_SPEED_20GB_SHIFT)
+};
+
+struct i40e_aqc_module_desc {
+       u8 oui[3];
+       u8 reserved1;
+       u8 part_number[16];
+       u8 revision[4];
+       u8 reserved2[8];
+};
+
+struct i40e_aq_get_phy_abilities_resp {
+       __le32 phy_type;       /* bitmap using the above enum for offsets */
+       u8     link_speed;     /* bitmap using the above enum */
+       u8     abilities;
+#define I40E_AQ_PHY_FLAG_PAUSE_TX         0x01
+#define I40E_AQ_PHY_FLAG_PAUSE_RX         0x02
+#define I40E_AQ_PHY_FLAG_LOW_POWER        0x04
+#define I40E_AQ_PHY_FLAG_AN_SHIFT         3
+#define I40E_AQ_PHY_FLAG_AN_MASK          (0x3 << I40E_AQ_PHY_FLAG_AN_SHIFT)
+#define I40E_AQ_PHY_FLAG_AN_OFF           0x00 /* link forced on */
+#define I40E_AQ_PHY_FLAG_AN_OFF_LINK_DOWN 0x01
+#define I40E_AQ_PHY_FLAG_AN_ON            0x02
+#define I40E_AQ_PHY_FLAG_MODULE_QUAL      0x20
+       __le16 eee_capability;
+#define I40E_AQ_EEE_100BASE_TX       0x0002
+#define I40E_AQ_EEE_1000BASE_T       0x0004
+#define I40E_AQ_EEE_10GBASE_T        0x0008
+#define I40E_AQ_EEE_1000BASE_KX      0x0010
+#define I40E_AQ_EEE_10GBASE_KX4      0x0020
+#define I40E_AQ_EEE_10GBASE_KR       0x0040
+       __le32 eeer_val;
+       u8     d3_lpan;
+#define I40E_AQ_SET_PHY_D3_LPAN_ENA  0x01
+       u8     reserved[3];
+       u8     phy_id[4];
+       u8     module_type[3];
+       u8     qualified_module_count;
+#define I40E_AQ_PHY_MAX_QMS          16
+       struct i40e_aqc_module_desc  qualified_module[I40E_AQ_PHY_MAX_QMS];
+};
+
+/* Set PHY Config (direct 0x0601) */
+struct i40e_aq_set_phy_config { /* same bits as above in all */
+       __le32 phy_type;
+       u8     link_speed;
+       u8     abilities;
+       __le16 eee_capability;
+       __le32 eeer;
+       u8     low_power_ctrl;
+       u8     reserved[3];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aq_set_phy_config);
+
+/* Set MAC Config command data structure (direct 0x0603) */
+struct i40e_aq_set_mac_config {
+       __le16 max_frame_size;
+       u8     params;
+#define I40E_AQ_SET_MAC_CONFIG_CRC_EN           0x04
+#define I40E_AQ_SET_MAC_CONFIG_PACING_MASK      0x78
+#define I40E_AQ_SET_MAC_CONFIG_PACING_SHIFT     3
+#define I40E_AQ_SET_MAC_CONFIG_PACING_NONE      0x0
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1B_13TX   0xF
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_9TX   0x9
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_4TX   0x8
+#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_7TX   0x7
+#define I40E_AQ_SET_MAC_CONFIG_PACING_2DW_3TX   0x6
+#define I40E_AQ_SET_MAC_CONFIG_PACING_1DW_1TX   0x5
+#define I40E_AQ_SET_MAC_CONFIG_PACING_3DW_2TX   0x4
+#define I40E_AQ_SET_MAC_CONFIG_PACING_7DW_3TX   0x3
+#define I40E_AQ_SET_MAC_CONFIG_PACING_4DW_1TX   0x2
+#define I40E_AQ_SET_MAC_CONFIG_PACING_9DW_1TX   0x1
+       u8     tx_timer_priority; /* bitmap */
+       __le16 tx_timer_value;
+       __le16 fc_refresh_threshold;
+       u8     reserved[8];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aq_set_mac_config);
+
+/* Restart Auto-Negotiation (direct 0x605) */
+struct i40e_aqc_set_link_restart_an {
+       u8     command;
+#define I40E_AQ_PHY_RESTART_AN  0x02
+#define I40E_AQ_PHY_LINK_ENABLE 0x04
+       u8     reserved[15];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_link_restart_an);
+
+/* Get Link Status cmd & response data structure (direct 0x0607) */
+struct i40e_aqc_get_link_status {
+       __le16 command_flags; /* only field set on command */
+#define I40E_AQ_LSE_MASK             0x3
+#define I40E_AQ_LSE_NOP              0x0
+#define I40E_AQ_LSE_DISABLE          0x2
+#define I40E_AQ_LSE_ENABLE           0x3
+/* only response uses this flag */
+#define I40E_AQ_LSE_IS_ENABLED       0x1
+       u8     phy_type;    /* i40e_aq_phy_type   */
+       u8     link_speed;  /* i40e_aq_link_speed */
+       u8     link_info;
+#define I40E_AQ_LINK_UP              0x01
+#define I40E_AQ_LINK_FAULT           0x02
+#define I40E_AQ_LINK_FAULT_TX        0x04
+#define I40E_AQ_LINK_FAULT_RX        0x08
+#define I40E_AQ_LINK_FAULT_REMOTE    0x10
+#define I40E_AQ_MEDIA_AVAILABLE      0x40
+#define I40E_AQ_SIGNAL_DETECT        0x80
+       u8     an_info;
+#define I40E_AQ_AN_COMPLETED         0x01
+#define I40E_AQ_LP_AN_ABILITY        0x02
+#define I40E_AQ_PD_FAULT             0x04
+#define I40E_AQ_FEC_EN               0x08
+#define I40E_AQ_PHY_LOW_POWER        0x10
+#define I40E_AQ_LINK_PAUSE_TX        0x20
+#define I40E_AQ_LINK_PAUSE_RX        0x40
+#define I40E_AQ_QUALIFIED_MODULE     0x80
+       u8     ext_info;
+#define I40E_AQ_LINK_PHY_TEMP_ALARM  0x01
+#define I40E_AQ_LINK_XCESSIVE_ERRORS 0x02
+#define I40E_AQ_LINK_TX_SHIFT        0x02
+#define I40E_AQ_LINK_TX_MASK         (0x03 << I40E_AQ_LINK_TX_SHIFT)
+#define I40E_AQ_LINK_TX_ACTIVE       0x00
+#define I40E_AQ_LINK_TX_DRAINED      0x01
+#define I40E_AQ_LINK_TX_FLUSHED      0x03
+       u8     loopback;         /* use defines from i40e_aqc_set_lb_mode */
+       __le16 max_frame_size;
+       u8     config;
+#define I40E_AQ_CONFIG_CRC_ENA       0x04
+#define I40E_AQ_CONFIG_PACING_MASK   0x78
+       u8     reserved[5];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_link_status);
+
+/* Set event mask command (direct 0x613) */
+struct i40e_aqc_set_phy_int_mask {
+       u8     reserved[8];
+       __le16 event_mask;
+#define I40E_AQ_EVENT_LINK_UPDOWN       0x0002
+#define I40E_AQ_EVENT_MEDIA_NA          0x0004
+#define I40E_AQ_EVENT_LINK_FAULT        0x0008
+#define I40E_AQ_EVENT_PHY_TEMP_ALARM    0x0010
+#define I40E_AQ_EVENT_EXCESSIVE_ERRORS  0x0020
+#define I40E_AQ_EVENT_SIGNAL_DETECT     0x0040
+#define I40E_AQ_EVENT_AN_COMPLETED      0x0080
+#define I40E_AQ_EVENT_MODULE_QUAL_FAIL  0x0100
+#define I40E_AQ_EVENT_PORT_TX_SUSPENDED 0x0200
+       u8     reserved1[6];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_int_mask);
+
+/* Get Local AN advt register (direct 0x0614)
+ * Set Local AN advt register (direct 0x0615)
+ * Get Link Partner AN advt register (direct 0x0616)
+ */
+struct i40e_aqc_an_advt_reg {
+       __le32 local_an_reg0;
+       __le16 local_an_reg1;
+       u8     reserved[10];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_an_advt_reg);
+
+/* Set Loopback mode (0x0618) */
+struct i40e_aqc_set_lb_mode {
+       __le16 lb_mode;
+#define I40E_AQ_LB_PHY_LOCAL   0x01
+#define I40E_AQ_LB_PHY_REMOTE  0x02
+#define I40E_AQ_LB_MAC_LOCAL   0x04
+       u8     reserved[14];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_lb_mode);
+
+/* Set PHY Reset command (0x0622) */
+struct i40e_aqc_set_phy_reset {
+       u8     reset_flags;
+#define I40E_AQ_PHY_RESET_REQUEST  0x02
+       u8     reserved[15];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_set_phy_reset);
+
+enum i40e_aq_phy_reg_type {
+       I40E_AQC_PHY_REG_INTERNAL         = 0x1,
+       I40E_AQC_PHY_REG_EXERNAL_BASET    = 0x2,
+       I40E_AQC_PHY_REG_EXERNAL_MODULE   = 0x3
+};
+
+/* NVM Read command (indirect 0x0701)
+ * NVM Erase commands (direct 0x0702)
+ * NVM Update commands (indirect 0x0703)
+ */
+struct i40e_aqc_nvm_update {
+       u8     command_flags;
+#define I40E_AQ_NVM_LAST_CMD    0x01
+#define I40E_AQ_NVM_FLASH_ONLY  0x80
+       u8     module_pointer;
+       __le16 length;
+       __le32 offset;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update);
+
+/* Send to PF command (indirect 0x0801) id is only used by PF
+ * Send to VF command (indirect 0x0802) id is only used by PF
+ * Send to Peer PF command (indirect 0x0803)
+ */
+struct i40e_aqc_pf_vf_message {
+       __le32 id;
+       u8     reserved[4];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_pf_vf_message);
+
+/* Alternate structure */
+
+/* Direct write (direct 0x0900)
+ * Direct read (direct 0x0902)
+ */
+struct i40e_aqc_alternate_write {
+       __le32 address0;
+       __le32 data0;
+       __le32 address1;
+       __le32 data1;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write);
+
+/* Indirect write (indirect 0x0901)
+ * Indirect read (indirect 0x0903)
+ */
+
+struct i40e_aqc_alternate_ind_write {
+       __le32 address;
+       __le32 length;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_ind_write);
+
+/* Done alternate write (direct 0x0904)
+ * uses i40e_aq_desc
+ */
+struct i40e_aqc_alternate_write_done {
+       __le16 cmd_flags;
+#define I40E_AQ_ALTERNATE_MODE_BIOS_MASK       1
+#define I40E_AQ_ALTERNATE_MODE_BIOS_LEGACY     0
+#define I40E_AQ_ALTERNATE_MODE_BIOS_UEFI       1
+#define I40E_AQ_ALTERNATE_RESET_NEEDED         2
+       u8     reserved[14];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_write_done);
+
+/* Set OEM mode (direct 0x0905) */
+struct i40e_aqc_alternate_set_mode {
+       __le32 mode;
+#define I40E_AQ_ALTERNATE_MODE_NONE    0
+#define I40E_AQ_ALTERNATE_MODE_OEM     1
+       u8     reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_alternate_set_mode);
+
+/* Clear port Alternate RAM (direct 0x0906) uses i40e_aq_desc */
+
+/* async events 0x10xx */
+
+/* Lan Queue Overflow Event (direct, 0x1001) */
+struct i40e_aqc_lan_overflow {
+       __le32 prtdcb_rupto;
+       __le32 otx_ctl;
+       u8     reserved[8];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lan_overflow);
+
+/* Get LLDP MIB (indirect 0x0A00) */
+struct i40e_aqc_lldp_get_mib {
+       u8     type;
+       u8     reserved1;
+#define I40E_AQ_LLDP_MIB_TYPE_MASK                      0x3
+#define I40E_AQ_LLDP_MIB_LOCAL                          0x0
+#define I40E_AQ_LLDP_MIB_REMOTE                         0x1
+#define I40E_AQ_LLDP_MIB_LOCAL_AND_REMOTE               0x2
+#define I40E_AQ_LLDP_BRIDGE_TYPE_MASK                   0xC
+#define I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT                  0x2
+#define I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE         0x0
+#define I40E_AQ_LLDP_BRIDGE_TYPE_NON_TPMR               0x1
+#define I40E_AQ_LLDP_TX_SHIFT              0x4
+#define I40E_AQ_LLDP_TX_MASK               (0x03 << I40E_AQ_LLDP_TX_SHIFT)
+/* TX pause flags use I40E_AQ_LINK_TX_* above */
+       __le16 local_len;
+       __le16 remote_len;
+       u8     reserved2[2];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_get_mib);
+
+/* Configure LLDP MIB Change Event (direct 0x0A01)
+ * also used for the event (with type in the command field)
+ */
+struct i40e_aqc_lldp_update_mib {
+       u8     command;
+#define I40E_AQ_LLDP_MIB_UPDATE_ENABLE          0x0
+#define I40E_AQ_LLDP_MIB_UPDATE_DISABLE         0x1
+       u8     reserved[7];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_mib);
+
+/* Add LLDP TLV (indirect 0x0A02)
+ * Delete LLDP TLV (indirect 0x0A04)
+ */
+struct i40e_aqc_lldp_add_tlv {
+       u8     type; /* only nearest bridge and non-TPMR from 0x0A00 */
+       u8     reserved1[1];
+       __le16 len;
+       u8     reserved2[4];
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_add_tlv);
+
+/* Update LLDP TLV (indirect 0x0A03) */
+struct i40e_aqc_lldp_update_tlv {
+       u8     type; /* only nearest bridge and non-TPMR from 0x0A00 */
+       u8     reserved;
+       __le16 old_len;
+       __le16 new_offset;
+       __le16 new_len;
+       __le32 addr_high;
+       __le32 addr_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_update_tlv);
+
+/* Stop LLDP (direct 0x0A05) */
+struct i40e_aqc_lldp_stop {
+       u8     command;
+#define I40E_AQ_LLDP_AGENT_STOP                 0x0
+#define I40E_AQ_LLDP_AGENT_SHUTDOWN             0x1
+       u8     reserved[15];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop);
+
+/* Start LLDP (direct 0x0A06) */
+
+struct i40e_aqc_lldp_start {
+       u8     command;
+#define I40E_AQ_LLDP_AGENT_START                0x1
+       u8     reserved[15];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start);
+
+/* Apply MIB changes (0x0A07)
+ * uses the generic struc as it contains no data
+ */
+
+/* Add Udp Tunnel command and completion (direct 0x0B00) */
+struct i40e_aqc_add_udp_tunnel {
+       __le16 udp_port;
+       u8     header_len; /* in DWords, 1 to 15 */
+       u8     protocol_index;
+#define I40E_AQC_TUNNEL_TYPE_MAC    0x0
+#define I40E_AQC_TUNNEL_TYPE_UDP    0x1
+       u8     reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_add_udp_tunnel);
+
+/* remove UDP Tunnel command (0x0B01) */
+struct i40e_aqc_remove_udp_tunnel {
+       u8     reserved[2];
+       u8     index; /* 0 to 15 */
+       u8     pf_filters;
+       u8     total_filters;
+       u8     reserved2[11];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_udp_tunnel);
+
+struct i40e_aqc_del_udp_tunnel_completion {
+       __le16 udp_port;
+       u8     index; /* 0 to 15 */
+       u8     multiple_entries;
+       u8     tunnels_used;
+       u8     reserved;
+       u8     tunnels_free;
+       u8     reserved1[9];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_del_udp_tunnel_completion);
+
+/* tunnel key structure 0x0B10 */
+struct i40e_aqc_tunnel_key_structure {
+       __le16     key1_off;
+       __le16     key1_len;
+       __le16     key2_off;
+       __le16     key2_len;
+       __le16     flags;
+#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDE 0x01
+/* response flags */
+#define I40E_AQC_TUNNEL_KEY_STRUCT_SUCCESS    0x01
+#define I40E_AQC_TUNNEL_KEY_STRUCT_MODIFIED   0x02
+#define I40E_AQC_TUNNEL_KEY_STRUCT_OVERRIDDEN 0x03
+       u8         resreved[6];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_tunnel_key_structure);
+
+/* OEM mode commands (direct 0xFE0x) */
+struct i40e_aqc_oem_param_change {
+       __le32 param_type;
+#define I40E_AQ_OEM_PARAM_TYPE_PF_CTL   0
+#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL   1
+#define I40E_AQ_OEM_PARAM_MAC           2
+       __le32 param_value1;
+       u8     param_value2[8];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change);
+
+struct i40e_aqc_oem_state_change {
+       __le32 state;
+#define I40E_AQ_OEM_STATE_LINK_DOWN  0x0
+#define I40E_AQ_OEM_STATE_LINK_UP    0x1
+       u8     reserved[12];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change);
+
+/* debug commands */
+
+/* get device id (0xFF00) uses the generic structure */
+
+/* set test more (0xFF01, internal) */
+
+struct i40e_acq_set_test_mode {
+       u8     mode;
+#define I40E_AQ_TEST_PARTIAL    0
+#define I40E_AQ_TEST_FULL       1
+#define I40E_AQ_TEST_NVM        2
+       u8     reserved[3];
+       u8     command;
+#define I40E_AQ_TEST_OPEN        0
+#define I40E_AQ_TEST_CLOSE       1
+#define I40E_AQ_TEST_INC         2
+       u8     reserved2[3];
+       __le32 address_high;
+       __le32 address_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_acq_set_test_mode);
+
+/* Debug Read Register command (0xFF03)
+ * Debug Write Register command (0xFF04)
+ */
+struct i40e_aqc_debug_reg_read_write {
+       __le32 reserved;
+       __le32 address;
+       __le32 value_high;
+       __le32 value_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_reg_read_write);
+
+/* Scatter/gather Reg Read  (indirect 0xFF05)
+ * Scatter/gather Reg Write (indirect 0xFF06)
+ */
+
+/* i40e_aq_desc is used for the command */
+struct i40e_aqc_debug_reg_sg_element_data {
+       __le32 address;
+       __le32 value;
+};
+
+/* Debug Modify register (direct 0xFF07) */
+struct i40e_aqc_debug_modify_reg {
+       __le32 address;
+       __le32 value;
+       __le32 clear_mask;
+       __le32 set_mask;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_reg);
+
+/* dump internal data (0xFF08, indirect) */
+
+#define I40E_AQ_CLUSTER_ID_AUX         0
+#define I40E_AQ_CLUSTER_ID_SWITCH_FLU  1
+#define I40E_AQ_CLUSTER_ID_TXSCHED     2
+#define I40E_AQ_CLUSTER_ID_HMC         3
+#define I40E_AQ_CLUSTER_ID_MAC0                4
+#define I40E_AQ_CLUSTER_ID_MAC1                5
+#define I40E_AQ_CLUSTER_ID_MAC2                6
+#define I40E_AQ_CLUSTER_ID_MAC3                7
+#define I40E_AQ_CLUSTER_ID_DCB         8
+#define I40E_AQ_CLUSTER_ID_EMP_MEM     9
+#define I40E_AQ_CLUSTER_ID_PKT_BUF     10
+
+struct i40e_aqc_debug_dump_internals {
+       u8     cluster_id;
+       u8     table_id;
+       __le16 data_size;
+       __le32 idx;
+       __le32 address_high;
+       __le32 address_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_dump_internals);
+
+struct i40e_aqc_debug_modify_internals {
+       u8     cluster_id;
+       u8     cluster_specific_params[7];
+       __le32 address_high;
+       __le32 address_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_debug_modify_internals);
+
+#endif
diff --git a/drivers/net/ethernet/intel/i40e/i40e_alloc.h b/drivers/net/ethernet/intel/i40e/i40e_alloc.h
new file mode 100644 (file)
index 0000000..3b1cc21
--- /dev/null
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_ALLOC_H_
+#define _I40E_ALLOC_H_
+
+struct i40e_hw;
+
+/* Memory allocation types */
+enum i40e_memory_type {
+       i40e_mem_arq_buf = 0,           /* ARQ indirect command buffer */
+       i40e_mem_asq_buf = 1,
+       i40e_mem_atq_buf = 2,           /* ATQ indirect command buffer */
+       i40e_mem_arq_ring = 3,          /* ARQ descriptor ring */
+       i40e_mem_atq_ring = 4,          /* ATQ descriptor ring */
+       i40e_mem_pd = 5,                /* Page Descriptor */
+       i40e_mem_bp = 6,                /* Backing Page - 4KB */
+       i40e_mem_bp_jumbo = 7,          /* Backing Page - > 4KB */
+       i40e_mem_reserved
+};
+
+/* prototype for functions used for dynamic memory allocation */
+i40e_status i40e_allocate_dma_mem(struct i40e_hw *hw,
+                                           struct i40e_dma_mem *mem,
+                                           enum i40e_memory_type type,
+                                           u64 size, u32 alignment);
+i40e_status i40e_free_dma_mem(struct i40e_hw *hw,
+                                       struct i40e_dma_mem *mem);
+i40e_status i40e_allocate_virt_mem(struct i40e_hw *hw,
+                                            struct i40e_virt_mem *mem,
+                                            u32 size);
+i40e_status i40e_free_virt_mem(struct i40e_hw *hw,
+                                        struct i40e_virt_mem *mem);
+
+#endif /* _I40E_ALLOC_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
new file mode 100644 (file)
index 0000000..c21df7b
--- /dev/null
@@ -0,0 +1,2041 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e_type.h"
+#include "i40e_adminq.h"
+#include "i40e_prototype.h"
+#include "i40e_virtchnl.h"
+
+/**
+ * i40e_set_mac_type - Sets MAC type
+ * @hw: pointer to the HW structure
+ *
+ * This function sets the mac type of the adapter based on the
+ * vendor ID and device ID stored in the hw structure.
+ **/
+static i40e_status i40e_set_mac_type(struct i40e_hw *hw)
+{
+       i40e_status status = 0;
+
+       if (hw->vendor_id == PCI_VENDOR_ID_INTEL) {
+               switch (hw->device_id) {
+               case I40E_SFP_XL710_DEVICE_ID:
+               case I40E_SFP_X710_DEVICE_ID:
+               case I40E_QEMU_DEVICE_ID:
+               case I40E_KX_A_DEVICE_ID:
+               case I40E_KX_B_DEVICE_ID:
+               case I40E_KX_C_DEVICE_ID:
+               case I40E_KX_D_DEVICE_ID:
+               case I40E_QSFP_A_DEVICE_ID:
+               case I40E_QSFP_B_DEVICE_ID:
+               case I40E_QSFP_C_DEVICE_ID:
+                       hw->mac.type = I40E_MAC_XL710;
+                       break;
+               case I40E_VF_DEVICE_ID:
+               case I40E_VF_HV_DEVICE_ID:
+                       hw->mac.type = I40E_MAC_VF;
+                       break;
+               default:
+                       hw->mac.type = I40E_MAC_GENERIC;
+                       break;
+               }
+       } else {
+               status = I40E_ERR_DEVICE_NOT_SUPPORTED;
+       }
+
+       hw_dbg(hw, "i40e_set_mac_type found mac: %d, returns: %d\n",
+                 hw->mac.type, status);
+       return status;
+}
+
+/**
+ * i40e_debug_aq
+ * @hw: debug mask related to admin queue
+ * @cap: pointer to adminq command descriptor
+ * @buffer: pointer to command buffer
+ *
+ * Dumps debug log about adminq command with descriptor contents.
+ **/
+void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void *desc,
+                  void *buffer)
+{
+       struct i40e_aq_desc *aq_desc = (struct i40e_aq_desc *)desc;
+       u8 *aq_buffer = (u8 *)buffer;
+       u32 data[4];
+       u32 i = 0;
+
+       if ((!(mask & hw->debug_mask)) || (desc == NULL))
+               return;
+
+       i40e_debug(hw, mask,
+                  "AQ CMD: opcode 0x%04X, flags 0x%04X, datalen 0x%04X, retval 0x%04X\n",
+                  aq_desc->opcode, aq_desc->flags, aq_desc->datalen,
+                  aq_desc->retval);
+       i40e_debug(hw, mask, "\tcookie (h,l) 0x%08X 0x%08X\n",
+                  aq_desc->cookie_high, aq_desc->cookie_low);
+       i40e_debug(hw, mask, "\tparam (0,1)  0x%08X 0x%08X\n",
+                  aq_desc->params.internal.param0,
+                  aq_desc->params.internal.param1);
+       i40e_debug(hw, mask, "\taddr (h,l)   0x%08X 0x%08X\n",
+                  aq_desc->params.external.addr_high,
+                  aq_desc->params.external.addr_low);
+
+       if ((buffer != NULL) && (aq_desc->datalen != 0)) {
+               memset(data, 0, sizeof(data));
+               i40e_debug(hw, mask, "AQ CMD Buffer:\n");
+               for (i = 0; i < le16_to_cpu(aq_desc->datalen); i++) {
+                       data[((i % 16) / 4)] |=
+                               ((u32)aq_buffer[i]) << (8 * (i % 4));
+                       if ((i % 16) == 15) {
+                               i40e_debug(hw, mask,
+                                          "\t0x%04X  %08X %08X %08X %08X\n",
+                                          i - 15, data[0], data[1], data[2],
+                                          data[3]);
+                               memset(data, 0, sizeof(data));
+                       }
+               }
+               if ((i % 16) != 0)
+                       i40e_debug(hw, mask, "\t0x%04X  %08X %08X %08X %08X\n",
+                                  i - (i % 16), data[0], data[1], data[2],
+                                  data[3]);
+       }
+}
+
+/**
+ * i40e_init_shared_code - Initialize the shared code
+ * @hw: pointer to hardware structure
+ *
+ * This assigns the MAC type and PHY code and inits the NVM.
+ * Does not touch the hardware. This function must be called prior to any
+ * other function in the shared code. The i40e_hw structure should be
+ * memset to 0 prior to calling this function.  The following fields in
+ * hw structure should be filled in prior to calling this function:
+ * hw_addr, back, device_id, vendor_id, subsystem_device_id,
+ * subsystem_vendor_id, and revision_id
+ **/
+i40e_status i40e_init_shared_code(struct i40e_hw *hw)
+{
+       i40e_status status = 0;
+       u32 reg;
+
+       hw->phy.get_link_info = true;
+
+       /* Determine port number */
+       reg = rd32(hw, I40E_PFGEN_PORTNUM);
+       reg = ((reg & I40E_PFGEN_PORTNUM_PORT_NUM_MASK) >>
+              I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT);
+       hw->port = (u8)reg;
+
+       i40e_set_mac_type(hw);
+
+       switch (hw->mac.type) {
+       case I40E_MAC_XL710:
+               break;
+       default:
+               return I40E_ERR_DEVICE_NOT_SUPPORTED;
+               break;
+       }
+
+       status = i40e_init_nvm(hw);
+       return status;
+}
+
+/**
+ * i40e_aq_mac_address_read - Retrieve the MAC addresses
+ * @hw: pointer to the hw struct
+ * @flags: a return indicator of what addresses were added to the addr store
+ * @addrs: the requestor's mac addr store
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+static i40e_status i40e_aq_mac_address_read(struct i40e_hw *hw,
+                                  u16 *flags,
+                                  struct i40e_aqc_mac_address_read_data *addrs,
+                                  struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_mac_address_read *cmd_data =
+               (struct i40e_aqc_mac_address_read *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_mac_address_read);
+       desc.flags |= cpu_to_le16(I40E_AQ_FLAG_BUF);
+
+       status = i40e_asq_send_command(hw, &desc, addrs,
+                                      sizeof(*addrs), cmd_details);
+       *flags = le16_to_cpu(cmd_data->command_flags);
+
+       return status;
+}
+
+/**
+ * i40e_aq_mac_address_write - Change the MAC addresses
+ * @hw: pointer to the hw struct
+ * @flags: indicates which MAC to be written
+ * @mac_addr: address to write
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_mac_address_write(struct i40e_hw *hw,
+                                   u16 flags, u8 *mac_addr,
+                                   struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_mac_address_write *cmd_data =
+               (struct i40e_aqc_mac_address_write *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_mac_address_write);
+       cmd_data->command_flags = cpu_to_le16(flags);
+       memcpy(&cmd_data->mac_sal, &mac_addr[0], 4);
+       memcpy(&cmd_data->mac_sah, &mac_addr[4], 2);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_get_mac_addr - get MAC address
+ * @hw: pointer to the HW structure
+ * @mac_addr: pointer to MAC address
+ *
+ * Reads the adapter's MAC address from register
+ **/
+i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr)
+{
+       struct i40e_aqc_mac_address_read_data addrs;
+       i40e_status status;
+       u16 flags = 0;
+
+       status = i40e_aq_mac_address_read(hw, &flags, &addrs, NULL);
+
+       if (flags & I40E_AQC_LAN_ADDR_VALID)
+               memcpy(mac_addr, &addrs.pf_lan_mac, sizeof(addrs.pf_lan_mac));
+
+       return status;
+}
+
+/**
+ * i40e_validate_mac_addr - Validate MAC address
+ * @mac_addr: pointer to MAC address
+ *
+ * Tests a MAC address to ensure it is a valid Individual Address
+ **/
+i40e_status i40e_validate_mac_addr(u8 *mac_addr)
+{
+       i40e_status status = 0;
+
+       /* Make sure it is not a multicast address */
+       if (I40E_IS_MULTICAST(mac_addr)) {
+               hw_dbg(hw, "MAC address is multicast\n");
+               status = I40E_ERR_INVALID_MAC_ADDR;
+       /* Not a broadcast address */
+       } else if (I40E_IS_BROADCAST(mac_addr)) {
+               hw_dbg(hw, "MAC address is broadcast\n");
+               status = I40E_ERR_INVALID_MAC_ADDR;
+       /* Reject the zero address */
+       } else if (mac_addr[0] == 0 && mac_addr[1] == 0 && mac_addr[2] == 0 &&
+                  mac_addr[3] == 0 && mac_addr[4] == 0 && mac_addr[5] == 0) {
+               hw_dbg(hw, "MAC address is all zeros\n");
+               status = I40E_ERR_INVALID_MAC_ADDR;
+       }
+       return status;
+}
+
+/**
+ * i40e_pf_reset - Reset the PF
+ * @hw: pointer to the hardware structure
+ *
+ * Assuming someone else has triggered a global reset,
+ * assure the global reset is complete and then reset the PF
+ **/
+i40e_status i40e_pf_reset(struct i40e_hw *hw)
+{
+       u32 wait_cnt = 0;
+       u32 reg = 0;
+       u32 grst_del;
+
+       /* Poll for Global Reset steady state in case of recent GRST.
+        * The grst delay value is in 100ms units, and we'll wait a
+        * couple counts longer to be sure we don't just miss the end.
+        */
+       grst_del = rd32(hw, I40E_GLGEN_RSTCTL) & I40E_GLGEN_RSTCTL_GRSTDEL_MASK
+                       >> I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT;
+       for (wait_cnt = 0; wait_cnt < grst_del + 2; wait_cnt++) {
+               reg = rd32(hw, I40E_GLGEN_RSTAT);
+               if (!(reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK))
+                       break;
+               msleep(100);
+       }
+       if (reg & I40E_GLGEN_RSTAT_DEVSTATE_MASK) {
+               hw_dbg(hw, "Global reset polling failed to complete.\n");
+               return I40E_ERR_RESET_FAILED;
+       }
+
+       /* Determine the PF number based on the PCI fn */
+       hw->pf_id = (u8)hw->bus.func;
+
+       /* If there was a Global Reset in progress when we got here,
+        * we don't need to do the PF Reset
+        */
+       if (!wait_cnt) {
+               reg = rd32(hw, I40E_PFGEN_CTRL);
+               wr32(hw, I40E_PFGEN_CTRL,
+                    (reg | I40E_PFGEN_CTRL_PFSWR_MASK));
+               for (wait_cnt = 0; wait_cnt < 10; wait_cnt++) {
+                       reg = rd32(hw, I40E_PFGEN_CTRL);
+                       if (!(reg & I40E_PFGEN_CTRL_PFSWR_MASK))
+                               break;
+                       usleep_range(1000, 2000);
+               }
+               if (reg & I40E_PFGEN_CTRL_PFSWR_MASK) {
+                       hw_dbg(hw, "PF reset polling failed to complete.\n");
+                       return I40E_ERR_RESET_FAILED;
+               }
+       }
+
+       i40e_clear_pxe_mode(hw);
+       return 0;
+}
+
+/**
+ * i40e_clear_pxe_mode - clear pxe operations mode
+ * @hw: pointer to the hw struct
+ *
+ * Make sure all PXE mode settings are cleared, including things
+ * like descriptor fetch/write-back mode.
+ **/
+void i40e_clear_pxe_mode(struct i40e_hw *hw)
+{
+       u32 reg;
+
+       /* Clear single descriptor fetch/write-back mode */
+       reg = rd32(hw, I40E_GLLAN_RCTL_0);
+       wr32(hw, I40E_GLLAN_RCTL_0, (reg | I40E_GLLAN_RCTL_0_PXE_MODE_MASK));
+}
+
+/**
+ * i40e_led_get - return current on/off mode
+ * @hw: pointer to the hw struct
+ *
+ * The value returned is the 'mode' field as defined in the
+ * GPIO register definitions: 0x0 = off, 0xf = on, and other
+ * values are variations of possible behaviors relating to
+ * blink, link, and wire.
+ **/
+u32 i40e_led_get(struct i40e_hw *hw)
+{
+       u32 gpio_val = 0;
+       u32 mode = 0;
+       u32 port;
+       int i;
+
+       for (i = 0; i < I40E_HW_CAP_MAX_GPIO; i++) {
+               if (!hw->func_caps.led[i])
+                       continue;
+
+               gpio_val = rd32(hw, I40E_GLGEN_GPIO_CTL(i));
+               port = (gpio_val & I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK)
+                       >> I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT;
+
+               if (port != hw->port)
+                       continue;
+
+               mode = (gpio_val & I40E_GLGEN_GPIO_CTL_LED_MODE_MASK)
+                               >> I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT;
+               break;
+       }
+
+       return mode;
+}
+
+/**
+ * i40e_led_set - set new on/off mode
+ * @hw: pointer to the hw struct
+ * @mode: 0=off, else on (see EAS for mode details)
+ **/
+void i40e_led_set(struct i40e_hw *hw, u32 mode)
+{
+       u32 gpio_val = 0;
+       u32 led_mode = 0;
+       u32 port;
+       int i;
+
+       for (i = 0; i < I40E_HW_CAP_MAX_GPIO; i++) {
+               if (!hw->func_caps.led[i])
+                       continue;
+
+               gpio_val = rd32(hw, I40E_GLGEN_GPIO_CTL(i));
+               port = (gpio_val & I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK)
+                       >> I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT;
+
+               if (port != hw->port)
+                       continue;
+
+               led_mode = (mode << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) &
+                           I40E_GLGEN_GPIO_CTL_LED_MODE_MASK;
+               gpio_val &= ~I40E_GLGEN_GPIO_CTL_LED_MODE_MASK;
+               gpio_val |= led_mode;
+               wr32(hw, I40E_GLGEN_GPIO_CTL(i), gpio_val);
+       }
+}
+
+/* Admin command wrappers */
+/**
+ * i40e_aq_queue_shutdown
+ * @hw: pointer to the hw struct
+ * @unloading: is the driver unloading itself
+ *
+ * Tell the Firmware that we're shutting down the AdminQ and whether
+ * or not the driver is unloading as well.
+ **/
+i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw,
+                                            bool unloading)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_queue_shutdown *cmd =
+               (struct i40e_aqc_queue_shutdown *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_queue_shutdown);
+
+       if (unloading)
+               cmd->driver_unloading = cpu_to_le32(I40E_AQ_DRIVER_UNLOADING);
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, NULL);
+
+       return status;
+}
+
+/**
+ * i40e_aq_set_link_restart_an
+ * @hw: pointer to the hw struct
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Sets up the link and restarts the Auto-Negotiation over the link.
+ **/
+i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_set_link_restart_an *cmd =
+               (struct i40e_aqc_set_link_restart_an *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_set_link_restart_an);
+
+       cmd->command = I40E_AQ_PHY_RESTART_AN;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_get_link_info
+ * @hw: pointer to the hw struct
+ * @enable_lse: enable/disable LinkStatusEvent reporting
+ * @link: pointer to link status structure - optional
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Returns the link status of the adapter.
+ **/
+i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
+                               bool enable_lse, struct i40e_link_status *link,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_get_link_status *resp =
+               (struct i40e_aqc_get_link_status *)&desc.params.raw;
+       struct i40e_link_status *hw_link_info = &hw->phy.link_info;
+       i40e_status status;
+       u16 command_flags;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_link_status);
+
+       if (enable_lse)
+               command_flags = I40E_AQ_LSE_ENABLE;
+       else
+               command_flags = I40E_AQ_LSE_DISABLE;
+       resp->command_flags = cpu_to_le16(command_flags);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       if (status)
+               goto aq_get_link_info_exit;
+
+       /* save off old link status information */
+       memcpy(&hw->phy.link_info_old, hw_link_info,
+              sizeof(struct i40e_link_status));
+
+       /* update link status */
+       hw_link_info->phy_type = (enum i40e_aq_phy_type)resp->phy_type;
+       hw_link_info->link_speed = (enum i40e_aq_link_speed)resp->link_speed;
+       hw_link_info->link_info = resp->link_info;
+       hw_link_info->an_info = resp->an_info;
+       hw_link_info->ext_info = resp->ext_info;
+
+       if (resp->command_flags & cpu_to_le16(I40E_AQ_LSE_ENABLE))
+               hw_link_info->lse_enable = true;
+       else
+               hw_link_info->lse_enable = false;
+
+       /* save link status information */
+       if (link)
+               memcpy(link, hw_link_info, sizeof(struct i40e_link_status));
+
+       /* flag cleared so helper functions don't call AQ again */
+       hw->phy.get_link_info = false;
+
+aq_get_link_info_exit:
+       return status;
+}
+
+/**
+ * i40e_aq_add_vsi
+ * @hw: pointer to the hw struct
+ * @vsi: pointer to a vsi context struct
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Add a VSI context to the hardware.
+**/
+i40e_status i40e_aq_add_vsi(struct i40e_hw *hw,
+                               struct i40e_vsi_context *vsi_ctx,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_add_get_update_vsi *cmd =
+               (struct i40e_aqc_add_get_update_vsi *)&desc.params.raw;
+       struct i40e_aqc_add_get_update_vsi_completion *resp =
+               (struct i40e_aqc_add_get_update_vsi_completion *)
+               &desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_add_vsi);
+
+       cmd->uplink_seid = cpu_to_le16(vsi_ctx->uplink_seid);
+       cmd->connection_type = vsi_ctx->connection_type;
+       cmd->vf_id = vsi_ctx->vf_num;
+       cmd->vsi_flags = cpu_to_le16(vsi_ctx->flags);
+
+       desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (sizeof(vsi_ctx->info) > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, &vsi_ctx->info,
+                                   sizeof(vsi_ctx->info), cmd_details);
+
+       if (status)
+               goto aq_add_vsi_exit;
+
+       vsi_ctx->seid = le16_to_cpu(resp->seid);
+       vsi_ctx->vsi_number = le16_to_cpu(resp->vsi_number);
+       vsi_ctx->vsis_allocated = le16_to_cpu(resp->vsi_used);
+       vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
+
+aq_add_vsi_exit:
+       return status;
+}
+
+/**
+ * i40e_aq_set_vsi_unicast_promiscuous
+ * @hw: pointer to the hw struct
+ * @seid: vsi number
+ * @set: set unicast promiscuous enable/disable
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
+                               u16 seid, bool set, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
+               (struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw;
+       i40e_status status;
+       u16 flags = 0;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                       i40e_aqc_opc_set_vsi_promiscuous_modes);
+
+       if (set)
+               flags |= I40E_AQC_SET_VSI_PROMISC_UNICAST;
+
+       cmd->promiscuous_flags = cpu_to_le16(flags);
+
+       cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_UNICAST);
+
+       cmd->seid = cpu_to_le16(seid);
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_set_vsi_multicast_promiscuous
+ * @hw: pointer to the hw struct
+ * @seid: vsi number
+ * @set: set multicast promiscuous enable/disable
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
+                               u16 seid, bool set, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
+               (struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw;
+       i40e_status status;
+       u16 flags = 0;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                       i40e_aqc_opc_set_vsi_promiscuous_modes);
+
+       if (set)
+               flags |= I40E_AQC_SET_VSI_PROMISC_MULTICAST;
+
+       cmd->promiscuous_flags = cpu_to_le16(flags);
+
+       cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_MULTICAST);
+
+       cmd->seid = cpu_to_le16(seid);
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_set_vsi_broadcast
+ * @hw: pointer to the hw struct
+ * @seid: vsi number
+ * @set_filter: true to set filter, false to clear filter
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Set or clear the broadcast promiscuous flag (filter) for a given VSI.
+ **/
+i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
+                               u16 seid, bool set_filter,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_set_vsi_promiscuous_modes *cmd =
+               (struct i40e_aqc_set_vsi_promiscuous_modes *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                       i40e_aqc_opc_set_vsi_promiscuous_modes);
+
+       if (set_filter)
+               cmd->promiscuous_flags
+                           |= cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_BROADCAST);
+       else
+               cmd->promiscuous_flags
+                           &= cpu_to_le16(~I40E_AQC_SET_VSI_PROMISC_BROADCAST);
+
+       cmd->valid_flags = cpu_to_le16(I40E_AQC_SET_VSI_PROMISC_BROADCAST);
+       cmd->seid = cpu_to_le16(seid);
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_get_vsi_params - get VSI configuration info
+ * @hw: pointer to the hw struct
+ * @vsi: pointer to a vsi context struct
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
+                               struct i40e_vsi_context *vsi_ctx,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_switch_seid *cmd =
+               (struct i40e_aqc_switch_seid *)&desc.params.raw;
+       struct i40e_aqc_add_get_update_vsi_completion *resp =
+               (struct i40e_aqc_add_get_update_vsi_completion *)
+               &desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_get_vsi_parameters);
+
+       cmd->seid = cpu_to_le16(vsi_ctx->seid);
+
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+       if (sizeof(vsi_ctx->info) > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, &vsi_ctx->info,
+                                   sizeof(vsi_ctx->info), NULL);
+
+       if (status)
+               goto aq_get_vsi_params_exit;
+
+       vsi_ctx->seid = le16_to_cpu(resp->seid);
+       vsi_ctx->vsi_number = le16_to_cpu(resp->vsi_number);
+       vsi_ctx->vsis_allocated = le16_to_cpu(resp->vsi_used);
+       vsi_ctx->vsis_unallocated = le16_to_cpu(resp->vsi_free);
+
+aq_get_vsi_params_exit:
+       return status;
+}
+
+/**
+ * i40e_aq_update_vsi_params
+ * @hw: pointer to the hw struct
+ * @vsi: pointer to a vsi context struct
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Update a VSI context.
+ **/
+i40e_status i40e_aq_update_vsi_params(struct i40e_hw *hw,
+                               struct i40e_vsi_context *vsi_ctx,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_switch_seid *cmd =
+               (struct i40e_aqc_switch_seid *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_update_vsi_parameters);
+       cmd->seid = cpu_to_le16(vsi_ctx->seid);
+
+       desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (sizeof(vsi_ctx->info) > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, &vsi_ctx->info,
+                                   sizeof(vsi_ctx->info), cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_get_switch_config
+ * @hw: pointer to the hardware structure
+ * @buf: pointer to the result buffer
+ * @buf_size: length of input buffer
+ * @start_seid: seid to start for the report, 0 == beginning
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Fill the buf with switch configuration returned from AdminQ command
+ **/
+i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
+                               struct i40e_aqc_get_switch_config_resp *buf,
+                               u16 buf_size, u16 *start_seid,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_switch_seid *scfg =
+               (struct i40e_aqc_switch_seid *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_get_switch_config);
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+       if (buf_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+       scfg->seid = cpu_to_le16(*start_seid);
+
+       status = i40e_asq_send_command(hw, &desc, buf, buf_size, cmd_details);
+       *start_seid = le16_to_cpu(scfg->seid);
+
+       return status;
+}
+
+/**
+ * i40e_aq_get_firmware_version
+ * @hw: pointer to the hw struct
+ * @fw_major_version: firmware major version
+ * @fw_minor_version: firmware minor version
+ * @api_major_version: major queue version
+ * @api_minor_version: minor queue version
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Get the firmware version from the admin queue commands
+ **/
+i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw,
+                               u16 *fw_major_version, u16 *fw_minor_version,
+                               u16 *api_major_version, u16 *api_minor_version,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_get_version *resp =
+               (struct i40e_aqc_get_version *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_get_version);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       if (!status) {
+               if (fw_major_version != NULL)
+                       *fw_major_version = le16_to_cpu(resp->fw_major);
+               if (fw_minor_version != NULL)
+                       *fw_minor_version = le16_to_cpu(resp->fw_minor);
+               if (api_major_version != NULL)
+                       *api_major_version = le16_to_cpu(resp->api_major);
+               if (api_minor_version != NULL)
+                       *api_minor_version = le16_to_cpu(resp->api_minor);
+       }
+
+       return status;
+}
+
+/**
+ * i40e_aq_send_driver_version
+ * @hw: pointer to the hw struct
+ * @event: driver event: driver ok, start or stop
+ * @dv: driver's major, minor version
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Send the driver version to the firmware
+ **/
+i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
+                               struct i40e_driver_version *dv,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_driver_version *cmd =
+               (struct i40e_aqc_driver_version *)&desc.params.raw;
+       i40e_status status;
+
+       if (dv == NULL)
+               return I40E_ERR_PARAM;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_driver_version);
+
+       desc.flags |= cpu_to_le16(I40E_AQ_FLAG_SI);
+       cmd->driver_major_ver = dv->major_version;
+       cmd->driver_minor_ver = dv->minor_version;
+       cmd->driver_build_ver = dv->build_version;
+       cmd->driver_subbuild_ver = dv->subbuild_version;
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_get_link_status - get status of the HW network link
+ * @hw: pointer to the hw struct
+ *
+ * Returns true if link is up, false if link is down.
+ *
+ * Side effect: LinkStatusEvent reporting becomes enabled
+ **/
+bool i40e_get_link_status(struct i40e_hw *hw)
+{
+       i40e_status status = 0;
+       bool link_status = false;
+
+       if (hw->phy.get_link_info) {
+               status = i40e_aq_get_link_info(hw, true, NULL, NULL);
+
+               if (status)
+                       goto i40e_get_link_status_exit;
+       }
+
+       link_status = hw->phy.link_info.link_info & I40E_AQ_LINK_UP;
+
+i40e_get_link_status_exit:
+       return link_status;
+}
+
+/**
+ * i40e_aq_add_veb - Insert a VEB between the VSI and the MAC
+ * @hw: pointer to the hw struct
+ * @uplink_seid: the MAC or other gizmo SEID
+ * @downlink_seid: the VSI SEID
+ * @enabled_tc: bitmap of TCs to be enabled
+ * @default_port: true for default port VSI, false for control port
+ * @veb_seid: pointer to where to put the resulting VEB SEID
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * This asks the FW to add a VEB between the uplink and downlink
+ * elements.  If the uplink SEID is 0, this will be a floating VEB.
+ **/
+i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
+                               u16 downlink_seid, u8 enabled_tc,
+                               bool default_port, u16 *veb_seid,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_add_veb *cmd =
+               (struct i40e_aqc_add_veb *)&desc.params.raw;
+       struct i40e_aqc_add_veb_completion *resp =
+               (struct i40e_aqc_add_veb_completion *)&desc.params.raw;
+       i40e_status status;
+       u16 veb_flags = 0;
+
+       /* SEIDs need to either both be set or both be 0 for floating VEB */
+       if (!!uplink_seid != !!downlink_seid)
+               return I40E_ERR_PARAM;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_add_veb);
+
+       cmd->uplink_seid = cpu_to_le16(uplink_seid);
+       cmd->downlink_seid = cpu_to_le16(downlink_seid);
+       cmd->enable_tcs = enabled_tc;
+       if (!uplink_seid)
+               veb_flags |= I40E_AQC_ADD_VEB_FLOATING;
+       if (default_port)
+               veb_flags |= I40E_AQC_ADD_VEB_PORT_TYPE_DEFAULT;
+       else
+               veb_flags |= I40E_AQC_ADD_VEB_PORT_TYPE_DATA;
+       cmd->veb_flags = cpu_to_le16(veb_flags);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       if (!status && veb_seid)
+               *veb_seid = le16_to_cpu(resp->veb_seid);
+
+       return status;
+}
+
+/**
+ * i40e_aq_get_veb_parameters - Retrieve VEB parameters
+ * @hw: pointer to the hw struct
+ * @veb_seid: the SEID of the VEB to query
+ * @switch_id: the uplink switch id
+ * @floating_veb: set to true if the VEB is floating
+ * @statistic_index: index of the stats counter block for this VEB
+ * @vebs_used: number of VEB's used by function
+ * @vebs_unallocated: total VEB's not reserved by any function
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * This retrieves the parameters for a particular VEB, specified by
+ * uplink_seid, and returns them to the caller.
+ **/
+i40e_status i40e_aq_get_veb_parameters(struct i40e_hw *hw,
+                               u16 veb_seid, u16 *switch_id,
+                               bool *floating, u16 *statistic_index,
+                               u16 *vebs_used, u16 *vebs_free,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_get_veb_parameters_completion *cmd_resp =
+               (struct i40e_aqc_get_veb_parameters_completion *)
+               &desc.params.raw;
+       i40e_status status;
+
+       if (veb_seid == 0)
+               return I40E_ERR_PARAM;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                         i40e_aqc_opc_get_veb_parameters);
+       cmd_resp->seid = cpu_to_le16(veb_seid);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+       if (status)
+               goto get_veb_exit;
+
+       if (switch_id)
+               *switch_id = le16_to_cpu(cmd_resp->switch_id);
+       if (statistic_index)
+               *statistic_index = le16_to_cpu(cmd_resp->statistic_index);
+       if (vebs_used)
+               *vebs_used = le16_to_cpu(cmd_resp->vebs_used);
+       if (vebs_free)
+               *vebs_free = le16_to_cpu(cmd_resp->vebs_free);
+       if (floating) {
+               u16 flags = le16_to_cpu(cmd_resp->veb_flags);
+               if (flags & I40E_AQC_ADD_VEB_FLOATING)
+                       *floating = true;
+               else
+                       *floating = false;
+       }
+
+get_veb_exit:
+       return status;
+}
+
+/**
+ * i40e_aq_add_macvlan
+ * @hw: pointer to the hw struct
+ * @seid: VSI for the mac address
+ * @mv_list: list of macvlans to be added
+ * @count: length of the list
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Add MAC/VLAN addresses to the HW filtering
+ **/
+i40e_status i40e_aq_add_macvlan(struct i40e_hw *hw, u16 seid,
+                       struct i40e_aqc_add_macvlan_element_data *mv_list,
+                       u16 count, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_macvlan *cmd =
+               (struct i40e_aqc_macvlan *)&desc.params.raw;
+       i40e_status status;
+       u16 buf_size;
+
+       if (count == 0 || !mv_list || !hw)
+               return I40E_ERR_PARAM;
+
+       buf_size = count * sizeof(struct i40e_aqc_add_macvlan_element_data);
+
+       /* prep the rest of the request */
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_add_macvlan);
+       cmd->num_addresses = cpu_to_le16(count);
+       cmd->seid[0] = cpu_to_le16(I40E_AQC_MACVLAN_CMD_SEID_VALID | seid);
+       cmd->seid[1] = 0;
+       cmd->seid[2] = 0;
+
+       desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (buf_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, mv_list, buf_size,
+                                   cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_remove_macvlan
+ * @hw: pointer to the hw struct
+ * @seid: VSI for the mac address
+ * @mv_list: list of macvlans to be removed
+ * @count: length of the list
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Remove MAC/VLAN addresses from the HW filtering
+ **/
+i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid,
+                       struct i40e_aqc_remove_macvlan_element_data *mv_list,
+                       u16 count, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_macvlan *cmd =
+               (struct i40e_aqc_macvlan *)&desc.params.raw;
+       i40e_status status;
+       u16 buf_size;
+
+       if (count == 0 || !mv_list || !hw)
+               return I40E_ERR_PARAM;
+
+       buf_size = count * sizeof(struct i40e_aqc_remove_macvlan_element_data);
+
+       /* prep the rest of the request */
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_remove_macvlan);
+       cmd->num_addresses = cpu_to_le16(count);
+       cmd->seid[0] = cpu_to_le16(I40E_AQC_MACVLAN_CMD_SEID_VALID | seid);
+       cmd->seid[1] = 0;
+       cmd->seid[2] = 0;
+
+       desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (buf_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, mv_list, buf_size,
+                                      cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_add_vlan - Add VLAN ids to the HW filtering
+ * @hw: pointer to the hw struct
+ * @seid: VSI for the vlan filters
+ * @v_list: list of vlan filters to be added
+ * @count: length of the list
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_add_vlan(struct i40e_hw *hw, u16 seid,
+                       struct i40e_aqc_add_remove_vlan_element_data *v_list,
+                       u8 count, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_macvlan *cmd =
+               (struct i40e_aqc_macvlan *)&desc.params.raw;
+       i40e_status status;
+       u16 buf_size;
+
+       if (count == 0 || !v_list || !hw)
+               return I40E_ERR_PARAM;
+
+       buf_size = count * sizeof(struct i40e_aqc_add_remove_vlan_element_data);
+
+       /* prep the rest of the request */
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_add_vlan);
+       cmd->num_addresses = cpu_to_le16(count);
+       cmd->seid[0] = cpu_to_le16(seid | I40E_AQC_MACVLAN_CMD_SEID_VALID);
+       cmd->seid[1] = 0;
+       cmd->seid[2] = 0;
+
+       desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (buf_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, v_list, buf_size,
+                                      cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_remove_vlan - Remove VLANs from the HW filtering
+ * @hw: pointer to the hw struct
+ * @seid: VSI for the vlan filters
+ * @v_list: list of macvlans to be removed
+ * @count: length of the list
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_remove_vlan(struct i40e_hw *hw, u16 seid,
+                       struct i40e_aqc_add_remove_vlan_element_data *v_list,
+                       u8 count, struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_macvlan *cmd =
+               (struct i40e_aqc_macvlan *)&desc.params.raw;
+       i40e_status status;
+       u16 buf_size;
+
+       if (count == 0 || !v_list || !hw)
+               return I40E_ERR_PARAM;
+
+       buf_size = count * sizeof(struct i40e_aqc_add_remove_vlan_element_data);
+
+       /* prep the rest of the request */
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_remove_vlan);
+       cmd->num_addresses = cpu_to_le16(count);
+       cmd->seid[0] = cpu_to_le16(seid | I40E_AQC_MACVLAN_CMD_SEID_VALID);
+       cmd->seid[1] = 0;
+       cmd->seid[2] = 0;
+
+       desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
+       if (buf_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, v_list, buf_size,
+                                      cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_send_msg_to_vf
+ * @hw: pointer to the hardware structure
+ * @vfid: vf id to send msg
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cmd_details: pointer to command details
+ *
+ * send msg to vf
+ **/
+i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid,
+                               u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_pf_vf_message *cmd =
+               (struct i40e_aqc_pf_vf_message *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_send_msg_to_vf);
+       cmd->id = cpu_to_le32(vfid);
+       desc.cookie_high = cpu_to_le32(v_opcode);
+       desc.cookie_low = cpu_to_le32(v_retval);
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_SI);
+       if (msglen) {
+               desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF |
+                                               I40E_AQ_FLAG_RD));
+               if (msglen > I40E_AQ_LARGE_BUF)
+                       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+               desc.datalen = cpu_to_le16(msglen);
+       }
+       status = i40e_asq_send_command(hw, &desc, msg, msglen, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_set_hmc_resource_profile
+ * @hw: pointer to the hw struct
+ * @profile: type of profile the HMC is to be set as
+ * @pe_vf_enabled_count: the number of PE enabled VFs the system has
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * set the HMC profile of the device.
+ **/
+i40e_status i40e_aq_set_hmc_resource_profile(struct i40e_hw *hw,
+                               enum i40e_aq_hmc_profile profile,
+                               u8 pe_vf_enabled_count,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aq_get_set_hmc_resource_profile *cmd =
+               (struct i40e_aq_get_set_hmc_resource_profile *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc,
+                                       i40e_aqc_opc_set_hmc_resource_profile);
+
+       cmd->pm_profile = (u8)profile;
+       cmd->pe_vf_enabled = pe_vf_enabled_count;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_request_resource
+ * @hw: pointer to the hw struct
+ * @resource: resource id
+ * @access: access type
+ * @sdp_number: resource number
+ * @timeout: the maximum time in ms that the driver may hold the resource
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * requests common resource using the admin queue commands
+ **/
+i40e_status i40e_aq_request_resource(struct i40e_hw *hw,
+                               enum i40e_aq_resources_ids resource,
+                               enum i40e_aq_resource_access_type access,
+                               u8 sdp_number, u64 *timeout,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_request_resource *cmd_resp =
+               (struct i40e_aqc_request_resource *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_request_resource);
+
+       cmd_resp->resource_id = cpu_to_le16(resource);
+       cmd_resp->access_type = cpu_to_le16(access);
+       cmd_resp->resource_number = cpu_to_le32(sdp_number);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+       /* The completion specifies the maximum time in ms that the driver
+        * may hold the resource in the Timeout field.
+        * If the resource is held by someone else, the command completes with
+        * busy return value and the timeout field indicates the maximum time
+        * the current owner of the resource has to free it.
+        */
+       if (!status || hw->aq.asq_last_status == I40E_AQ_RC_EBUSY)
+               *timeout = le32_to_cpu(cmd_resp->timeout);
+
+       return status;
+}
+
+/**
+ * i40e_aq_release_resource
+ * @hw: pointer to the hw struct
+ * @resource: resource id
+ * @sdp_number: resource number
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * release common resource using the admin queue commands
+ **/
+i40e_status i40e_aq_release_resource(struct i40e_hw *hw,
+                               enum i40e_aq_resources_ids resource,
+                               u8 sdp_number,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_request_resource *cmd =
+               (struct i40e_aqc_request_resource *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_release_resource);
+
+       cmd->resource_id = cpu_to_le16(resource);
+       cmd->resource_number = cpu_to_le32(sdp_number);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_read_nvm
+ * @hw: pointer to the hw struct
+ * @module_pointer: module pointer location in words from the NVM beginning
+ * @offset: byte offset from the module beginning
+ * @length: length of the section to be read (in bytes from the offset)
+ * @data: command buffer (size [bytes] = length)
+ * @last_command: tells if this is the last command in a series
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Read the NVM using the admin queue commands
+ **/
+i40e_status i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer,
+                               u32 offset, u16 length, void *data,
+                               bool last_command,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_nvm_update *cmd =
+               (struct i40e_aqc_nvm_update *)&desc.params.raw;
+       i40e_status status;
+
+       /* In offset the highest byte must be zeroed. */
+       if (offset & 0xFF000000) {
+               status = I40E_ERR_PARAM;
+               goto i40e_aq_read_nvm_exit;
+       }
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_nvm_read);
+
+       /* If this is the last command in a series, set the proper flag. */
+       if (last_command)
+               cmd->command_flags |= I40E_AQ_NVM_LAST_CMD;
+       cmd->module_pointer = module_pointer;
+       cmd->offset = cpu_to_le32(offset);
+       cmd->length = cpu_to_le16(length);
+
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+       if (length > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, data, length, cmd_details);
+
+i40e_aq_read_nvm_exit:
+       return status;
+}
+
+#define I40E_DEV_FUNC_CAP_SWITCH_MODE  0x01
+#define I40E_DEV_FUNC_CAP_MGMT_MODE    0x02
+#define I40E_DEV_FUNC_CAP_NPAR         0x03
+#define I40E_DEV_FUNC_CAP_OS2BMC       0x04
+#define I40E_DEV_FUNC_CAP_VALID_FUNC   0x05
+#define I40E_DEV_FUNC_CAP_SRIOV_1_1    0x12
+#define I40E_DEV_FUNC_CAP_VF           0x13
+#define I40E_DEV_FUNC_CAP_VMDQ         0x14
+#define I40E_DEV_FUNC_CAP_802_1_QBG    0x15
+#define I40E_DEV_FUNC_CAP_802_1_QBH    0x16
+#define I40E_DEV_FUNC_CAP_VSI          0x17
+#define I40E_DEV_FUNC_CAP_DCB          0x18
+#define I40E_DEV_FUNC_CAP_FCOE         0x21
+#define I40E_DEV_FUNC_CAP_RSS          0x40
+#define I40E_DEV_FUNC_CAP_RX_QUEUES    0x41
+#define I40E_DEV_FUNC_CAP_TX_QUEUES    0x42
+#define I40E_DEV_FUNC_CAP_MSIX         0x43
+#define I40E_DEV_FUNC_CAP_MSIX_VF      0x44
+#define I40E_DEV_FUNC_CAP_FLOW_DIRECTOR        0x45
+#define I40E_DEV_FUNC_CAP_IEEE_1588    0x46
+#define I40E_DEV_FUNC_CAP_MFP_MODE_1   0xF1
+#define I40E_DEV_FUNC_CAP_CEM          0xF2
+#define I40E_DEV_FUNC_CAP_IWARP                0x51
+#define I40E_DEV_FUNC_CAP_LED          0x61
+#define I40E_DEV_FUNC_CAP_SDP          0x62
+#define I40E_DEV_FUNC_CAP_MDIO         0x63
+
+/**
+ * i40e_parse_discover_capabilities
+ * @hw: pointer to the hw struct
+ * @buff: pointer to a buffer containing device/function capability records
+ * @cap_count: number of capability records in the list
+ * @list_type_opc: type of capabilities list to parse
+ *
+ * Parse the device/function capabilities list.
+ **/
+static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
+                                    u32 cap_count,
+                                    enum i40e_admin_queue_opc list_type_opc)
+{
+       struct i40e_aqc_list_capabilities_element_resp *cap;
+       u32 number, logical_id, phys_id;
+       struct i40e_hw_capabilities *p;
+       u32 reg_val;
+       u32 i = 0;
+       u16 id;
+
+       cap = (struct i40e_aqc_list_capabilities_element_resp *) buff;
+
+       if (list_type_opc == i40e_aqc_opc_list_dev_capabilities)
+               p = (struct i40e_hw_capabilities *)&hw->dev_caps;
+       else if (list_type_opc == i40e_aqc_opc_list_func_capabilities)
+               p = (struct i40e_hw_capabilities *)&hw->func_caps;
+       else
+               return;
+
+       for (i = 0; i < cap_count; i++, cap++) {
+               id = le16_to_cpu(cap->id);
+               number = le32_to_cpu(cap->number);
+               logical_id = le32_to_cpu(cap->logical_id);
+               phys_id = le32_to_cpu(cap->phys_id);
+
+               switch (id) {
+               case I40E_DEV_FUNC_CAP_SWITCH_MODE:
+                       p->switch_mode = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_MGMT_MODE:
+                       p->management_mode = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_NPAR:
+                       p->npar_enable = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_OS2BMC:
+                       p->os2bmc = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_VALID_FUNC:
+                       p->valid_functions = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_SRIOV_1_1:
+                       if (number == 1)
+                               p->sr_iov_1_1 = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_VF:
+                       p->num_vfs = number;
+                       p->vf_base_id = logical_id;
+                       break;
+               case I40E_DEV_FUNC_CAP_VMDQ:
+                       if (number == 1)
+                               p->vmdq = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_802_1_QBG:
+                       if (number == 1)
+                               p->evb_802_1_qbg = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_802_1_QBH:
+                       if (number == 1)
+                               p->evb_802_1_qbh = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_VSI:
+                       p->num_vsis = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_DCB:
+                       if (number == 1) {
+                               p->dcb = true;
+                               p->enabled_tcmap = logical_id;
+                               p->maxtc = phys_id;
+                       }
+                       break;
+               case I40E_DEV_FUNC_CAP_FCOE:
+                       if (number == 1)
+                               p->fcoe = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_RSS:
+                       p->rss = true;
+                       reg_val = rd32(hw, I40E_PFQF_CTL_0);
+                       if (reg_val & I40E_PFQF_CTL_0_HASHLUTSIZE_MASK)
+                               p->rss_table_size = number;
+                       else
+                               p->rss_table_size = 128;
+                       p->rss_table_entry_width = logical_id;
+                       break;
+               case I40E_DEV_FUNC_CAP_RX_QUEUES:
+                       p->num_rx_qp = number;
+                       p->base_queue = phys_id;
+                       break;
+               case I40E_DEV_FUNC_CAP_TX_QUEUES:
+                       p->num_tx_qp = number;
+                       p->base_queue = phys_id;
+                       break;
+               case I40E_DEV_FUNC_CAP_MSIX:
+                       p->num_msix_vectors = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_MSIX_VF:
+                       p->num_msix_vectors_vf = number;
+                       break;
+               case I40E_DEV_FUNC_CAP_MFP_MODE_1:
+                       if (number == 1)
+                               p->mfp_mode_1 = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_CEM:
+                       if (number == 1)
+                               p->mgmt_cem = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_IWARP:
+                       if (number == 1)
+                               p->iwarp = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_LED:
+                       if (phys_id < I40E_HW_CAP_MAX_GPIO)
+                               p->led[phys_id] = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_SDP:
+                       if (phys_id < I40E_HW_CAP_MAX_GPIO)
+                               p->sdp[phys_id] = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_MDIO:
+                       if (number == 1) {
+                               p->mdio_port_num = phys_id;
+                               p->mdio_port_mode = logical_id;
+                       }
+                       break;
+               case I40E_DEV_FUNC_CAP_IEEE_1588:
+                       if (number == 1)
+                               p->ieee_1588 = true;
+                       break;
+               case I40E_DEV_FUNC_CAP_FLOW_DIRECTOR:
+                       p->fd = true;
+                       p->fd_filters_guaranteed = number;
+                       p->fd_filters_best_effort = logical_id;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       /* additional HW specific goodies that might
+        * someday be HW version specific
+        */
+       p->rx_buf_chain_len = I40E_MAX_CHAINED_RX_BUFFERS;
+}
+
+/**
+ * i40e_aq_discover_capabilities
+ * @hw: pointer to the hw struct
+ * @buff: a virtual buffer to hold the capabilities
+ * @buff_size: Size of the virtual buffer
+ * @data_size: Size of the returned data, or buff size needed if AQ err==ENOMEM
+ * @list_type_opc: capabilities type to discover - pass in the command opcode
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Get the device capabilities descriptions from the firmware
+ **/
+i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw,
+                               void *buff, u16 buff_size, u16 *data_size,
+                               enum i40e_admin_queue_opc list_type_opc,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aqc_list_capabilites *cmd;
+       i40e_status status = 0;
+       struct i40e_aq_desc desc;
+
+       cmd = (struct i40e_aqc_list_capabilites *)&desc.params.raw;
+
+       if (list_type_opc != i40e_aqc_opc_list_func_capabilities &&
+               list_type_opc != i40e_aqc_opc_list_dev_capabilities) {
+               status = I40E_ERR_PARAM;
+               goto exit;
+       }
+
+       i40e_fill_default_direct_cmd_desc(&desc, list_type_opc);
+
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+       if (buff_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+       *data_size = le16_to_cpu(desc.datalen);
+
+       if (status)
+               goto exit;
+
+       i40e_parse_discover_capabilities(hw, buff, le32_to_cpu(cmd->count),
+                                        list_type_opc);
+
+exit:
+       return status;
+}
+
+/**
+ * i40e_aq_get_lldp_mib
+ * @hw: pointer to the hw struct
+ * @bridge_type: type of bridge requested
+ * @mib_type: Local, Remote or both Local and Remote MIBs
+ * @buff: pointer to a user supplied buffer to store the MIB block
+ * @buff_size: size of the buffer (in bytes)
+ * @local_len : length of the returned Local LLDP MIB
+ * @remote_len: length of the returned Remote LLDP MIB
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Requests the complete LLDP MIB (entire packet).
+ **/
+i40e_status i40e_aq_get_lldp_mib(struct i40e_hw *hw, u8 bridge_type,
+                               u8 mib_type, void *buff, u16 buff_size,
+                               u16 *local_len, u16 *remote_len,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_lldp_get_mib *cmd =
+               (struct i40e_aqc_lldp_get_mib *)&desc.params.raw;
+       struct i40e_aqc_lldp_get_mib *resp =
+               (struct i40e_aqc_lldp_get_mib *)&desc.params.raw;
+       i40e_status status;
+
+       if (buff_size == 0 || !buff)
+               return I40E_ERR_PARAM;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_get_mib);
+       /* Indirect Command */
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+
+       cmd->type = mib_type & I40E_AQ_LLDP_MIB_TYPE_MASK;
+       cmd->type |= ((bridge_type << I40E_AQ_LLDP_BRIDGE_TYPE_SHIFT) &
+                      I40E_AQ_LLDP_BRIDGE_TYPE_MASK);
+
+       desc.datalen = cpu_to_le16(buff_size);
+
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+       if (buff_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+       if (!status) {
+               if (local_len != NULL)
+                       *local_len = le16_to_cpu(resp->local_len);
+               if (remote_len != NULL)
+                       *remote_len = le16_to_cpu(resp->remote_len);
+       }
+
+       return status;
+}
+
+/**
+ * i40e_aq_cfg_lldp_mib_change_event
+ * @hw: pointer to the hw struct
+ * @enable_update: Enable or Disable event posting
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Enable or Disable posting of an event on ARQ when LLDP MIB
+ * associated with the interface changes
+ **/
+i40e_status i40e_aq_cfg_lldp_mib_change_event(struct i40e_hw *hw,
+                               bool enable_update,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_lldp_update_mib *cmd =
+               (struct i40e_aqc_lldp_update_mib *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_update_mib);
+
+       if (!enable_update)
+               cmd->command |= I40E_AQ_LLDP_MIB_UPDATE_DISABLE;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_stop_lldp
+ * @hw: pointer to the hw struct
+ * @shutdown_agent: True if LLDP Agent needs to be Shutdown
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Stop or Shutdown the embedded LLDP Agent
+ **/
+i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_lldp_stop *cmd =
+               (struct i40e_aqc_lldp_stop *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_stop);
+
+       if (shutdown_agent)
+               cmd->command |= I40E_AQ_LLDP_AGENT_SHUTDOWN;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_start_lldp
+ * @hw: pointer to the hw struct
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Start the embedded LLDP Agent on all ports.
+ **/
+i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_lldp_start *cmd =
+               (struct i40e_aqc_lldp_start *)&desc.params.raw;
+       i40e_status status;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_lldp_start);
+
+       cmd->command = I40E_AQ_LLDP_AGENT_START;
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_delete_element - Delete switch element
+ * @hw: pointer to the hw struct
+ * @seid: the SEID to delete from the switch
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * This deletes a switch element from the switch.
+ **/
+i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_switch_seid *cmd =
+               (struct i40e_aqc_switch_seid *)&desc.params.raw;
+       i40e_status status;
+
+       if (seid == 0)
+               return I40E_ERR_PARAM;
+
+       i40e_fill_default_direct_cmd_desc(&desc, i40e_aqc_opc_delete_element);
+
+       cmd->seid = cpu_to_le16(seid);
+
+       status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_tx_sched_cmd - generic Tx scheduler AQ command handler
+ * @hw: pointer to the hw struct
+ * @seid: seid for the physical port/switching component/vsi
+ * @buff: Indirect buffer to hold data parameters and response
+ * @buff_size: Indirect buffer size
+ * @opcode: Tx scheduler AQ command opcode
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Generic command handler for Tx scheduler AQ commands
+ **/
+static i40e_status i40e_aq_tx_sched_cmd(struct i40e_hw *hw, u16 seid,
+                               void *buff, u16 buff_size,
+                                enum i40e_admin_queue_opc opcode,
+                               struct i40e_asq_cmd_details *cmd_details)
+{
+       struct i40e_aq_desc desc;
+       struct i40e_aqc_tx_sched_ind *cmd =
+               (struct i40e_aqc_tx_sched_ind *)&desc.params.raw;
+       i40e_status status;
+       bool cmd_param_flag = false;
+
+       switch (opcode) {
+       case i40e_aqc_opc_configure_vsi_ets_sla_bw_limit:
+       case i40e_aqc_opc_configure_vsi_tc_bw:
+       case i40e_aqc_opc_enable_switching_comp_ets:
+       case i40e_aqc_opc_modify_switching_comp_ets:
+       case i40e_aqc_opc_disable_switching_comp_ets:
+       case i40e_aqc_opc_configure_switching_comp_ets_bw_limit:
+       case i40e_aqc_opc_configure_switching_comp_bw_config:
+               cmd_param_flag = true;
+               break;
+       case i40e_aqc_opc_query_vsi_bw_config:
+       case i40e_aqc_opc_query_vsi_ets_sla_config:
+       case i40e_aqc_opc_query_switching_comp_ets_config:
+       case i40e_aqc_opc_query_port_ets_config:
+       case i40e_aqc_opc_query_switching_comp_bw_config:
+               cmd_param_flag = false;
+               break;
+       default:
+               return I40E_ERR_PARAM;
+       }
+
+       i40e_fill_default_direct_cmd_desc(&desc, opcode);
+
+       /* Indirect command */
+       desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_BUF);
+       if (cmd_param_flag)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_RD);
+       if (buff_size > I40E_AQ_LARGE_BUF)
+               desc.flags |= cpu_to_le16((u16)I40E_AQ_FLAG_LB);
+
+       desc.datalen = cpu_to_le16(buff_size);
+
+       cmd->vsi_seid = cpu_to_le16(seid);
+
+       status = i40e_asq_send_command(hw, &desc, buff, buff_size, cmd_details);
+
+       return status;
+}
+
+/**
+ * i40e_aq_config_vsi_tc_bw - Config VSI BW Allocation per TC
+ * @hw: pointer to the hw struct
+ * @seid: VSI seid
+ * @bw_data: Buffer holding enabled TCs, relative TC BW limit/credits
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_config_vsi_tc_bw(struct i40e_hw *hw,
+                       u16 seid,
+                       struct i40e_aqc_configure_vsi_tc_bw_data *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details)
+{
+       return i40e_aq_tx_sched_cmd(hw, seid, (void *)bw_data, sizeof(*bw_data),
+                                   i40e_aqc_opc_configure_vsi_tc_bw,
+                                   cmd_details);
+}
+
+/**
+ * i40e_aq_query_vsi_bw_config - Query VSI BW configuration
+ * @hw: pointer to the hw struct
+ * @seid: seid of the VSI
+ * @bw_data: Buffer to hold VSI BW configuration
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_query_vsi_bw_config(struct i40e_hw *hw,
+                       u16 seid,
+                       struct i40e_aqc_query_vsi_bw_config_resp *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details)
+{
+       return i40e_aq_tx_sched_cmd(hw, seid, (void *)bw_data, sizeof(*bw_data),
+                                   i40e_aqc_opc_query_vsi_bw_config,
+                                   cmd_details);
+}
+
+/**
+ * i40e_aq_query_vsi_ets_sla_config - Query VSI BW configuration per TC
+ * @hw: pointer to the hw struct
+ * @seid: seid of the VSI
+ * @bw_data: Buffer to hold VSI BW configuration per TC
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_query_vsi_ets_sla_config(struct i40e_hw *hw,
+                       u16 seid,
+                       struct i40e_aqc_query_vsi_ets_sla_config_resp *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details)
+{
+       return i40e_aq_tx_sched_cmd(hw, seid, (void *)bw_data, sizeof(*bw_data),
+                                   i40e_aqc_opc_query_vsi_ets_sla_config,
+                                   cmd_details);
+}
+
+/**
+ * i40e_aq_query_switch_comp_ets_config - Query Switch comp BW config per TC
+ * @hw: pointer to the hw struct
+ * @seid: seid of the switching component
+ * @bw_data: Buffer to hold switching component's per TC BW config
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_query_switch_comp_ets_config(struct i40e_hw *hw,
+               u16 seid,
+               struct i40e_aqc_query_switching_comp_ets_config_resp *bw_data,
+               struct i40e_asq_cmd_details *cmd_details)
+{
+       return i40e_aq_tx_sched_cmd(hw, seid, (void *)bw_data, sizeof(*bw_data),
+                                  i40e_aqc_opc_query_switching_comp_ets_config,
+                                  cmd_details);
+}
+
+/**
+ * i40e_aq_query_port_ets_config - Query Physical Port ETS configuration
+ * @hw: pointer to the hw struct
+ * @seid: seid of the VSI or switching component connected to Physical Port
+ * @bw_data: Buffer to hold current ETS configuration for the Physical Port
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_query_port_ets_config(struct i40e_hw *hw,
+                       u16 seid,
+                       struct i40e_aqc_query_port_ets_config_resp *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details)
+{
+       return i40e_aq_tx_sched_cmd(hw, seid, (void *)bw_data, sizeof(*bw_data),
+                                   i40e_aqc_opc_query_port_ets_config,
+                                   cmd_details);
+}
+
+/**
+ * i40e_aq_query_switch_comp_bw_config - Query Switch comp BW configuration
+ * @hw: pointer to the hw struct
+ * @seid: seid of the switching component
+ * @bw_data: Buffer to hold switching component's BW configuration
+ * @cmd_details: pointer to command details structure or NULL
+ **/
+i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
+               u16 seid,
+               struct i40e_aqc_query_switching_comp_bw_config_resp *bw_data,
+               struct i40e_asq_cmd_details *cmd_details)
+{
+       return i40e_aq_tx_sched_cmd(hw, seid, (void *)bw_data, sizeof(*bw_data),
+                                   i40e_aqc_opc_query_switching_comp_bw_config,
+                                   cmd_details);
+}
+
+/**
+ * i40e_validate_filter_settings
+ * @hw: pointer to the hardware structure
+ * @settings: Filter control settings
+ *
+ * Check and validate the filter control settings passed.
+ * The function checks for the valid filter/context sizes being
+ * passed for FCoE and PE.
+ *
+ * Returns 0 if the values passed are valid and within
+ * range else returns an error.
+ **/
+static i40e_status i40e_validate_filter_settings(struct i40e_hw *hw,
+                               struct i40e_filter_control_settings *settings)
+{
+       u32 fcoe_cntx_size, fcoe_filt_size;
+       u32 pe_cntx_size, pe_filt_size;
+       u32 fcoe_fmax, pe_fmax;
+       u32 val;
+
+       /* Validate FCoE settings passed */
+       switch (settings->fcoe_filt_num) {
+       case I40E_HASH_FILTER_SIZE_1K:
+       case I40E_HASH_FILTER_SIZE_2K:
+       case I40E_HASH_FILTER_SIZE_4K:
+       case I40E_HASH_FILTER_SIZE_8K:
+       case I40E_HASH_FILTER_SIZE_16K:
+       case I40E_HASH_FILTER_SIZE_32K:
+               fcoe_filt_size = I40E_HASH_FILTER_BASE_SIZE;
+               fcoe_filt_size <<= (u32)settings->fcoe_filt_num;
+               break;
+       default:
+               return I40E_ERR_PARAM;
+       }
+
+       switch (settings->fcoe_cntx_num) {
+       case I40E_DMA_CNTX_SIZE_512:
+       case I40E_DMA_CNTX_SIZE_1K:
+       case I40E_DMA_CNTX_SIZE_2K:
+       case I40E_DMA_CNTX_SIZE_4K:
+               fcoe_cntx_size = I40E_DMA_CNTX_BASE_SIZE;
+               fcoe_cntx_size <<= (u32)settings->fcoe_cntx_num;
+               break;
+       default:
+               return I40E_ERR_PARAM;
+       }
+
+       /* Validate PE settings passed */
+       switch (settings->pe_filt_num) {
+       case I40E_HASH_FILTER_SIZE_1K:
+       case I40E_HASH_FILTER_SIZE_2K:
+       case I40E_HASH_FILTER_SIZE_4K:
+       case I40E_HASH_FILTER_SIZE_8K:
+       case I40E_HASH_FILTER_SIZE_16K:
+       case I40E_HASH_FILTER_SIZE_32K:
+       case I40E_HASH_FILTER_SIZE_64K:
+       case I40E_HASH_FILTER_SIZE_128K:
+       case I40E_HASH_FILTER_SIZE_256K:
+       case I40E_HASH_FILTER_SIZE_512K:
+       case I40E_HASH_FILTER_SIZE_1M:
+               pe_filt_size = I40E_HASH_FILTER_BASE_SIZE;
+               pe_filt_size <<= (u32)settings->pe_filt_num;
+               break;
+       default:
+               return I40E_ERR_PARAM;
+       }
+
+       switch (settings->pe_cntx_num) {
+       case I40E_DMA_CNTX_SIZE_512:
+       case I40E_DMA_CNTX_SIZE_1K:
+       case I40E_DMA_CNTX_SIZE_2K:
+       case I40E_DMA_CNTX_SIZE_4K:
+       case I40E_DMA_CNTX_SIZE_8K:
+       case I40E_DMA_CNTX_SIZE_16K:
+       case I40E_DMA_CNTX_SIZE_32K:
+       case I40E_DMA_CNTX_SIZE_64K:
+       case I40E_DMA_CNTX_SIZE_128K:
+       case I40E_DMA_CNTX_SIZE_256K:
+               pe_cntx_size = I40E_DMA_CNTX_BASE_SIZE;
+               pe_cntx_size <<= (u32)settings->pe_cntx_num;
+               break;
+       default:
+               return I40E_ERR_PARAM;
+       }
+
+       /* FCHSIZE + FCDSIZE should not be greater than PMFCOEFMAX */
+       val = rd32(hw, I40E_GLHMC_FCOEFMAX);
+       fcoe_fmax = (val & I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK)
+                    >> I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT;
+       if (fcoe_filt_size + fcoe_cntx_size >  fcoe_fmax)
+               return I40E_ERR_INVALID_SIZE;
+
+       /* PEHSIZE + PEDSIZE should not be greater than PMPEXFMAX */
+       val = rd32(hw, I40E_GLHMC_PEXFMAX);
+       pe_fmax = (val & I40E_GLHMC_PEXFMAX_PMPEXFMAX_MASK)
+                  >> I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT;
+       if (pe_filt_size + pe_cntx_size >  pe_fmax)
+               return I40E_ERR_INVALID_SIZE;
+
+       return 0;
+}
+
+/**
+ * i40e_set_filter_control
+ * @hw: pointer to the hardware structure
+ * @settings: Filter control settings
+ *
+ * Set the Queue Filters for PE/FCoE and enable filters required
+ * for a single PF. It is expected that these settings are programmed
+ * at the driver initialization time.
+ **/
+i40e_status i40e_set_filter_control(struct i40e_hw *hw,
+                               struct i40e_filter_control_settings *settings)
+{
+       i40e_status ret = 0;
+       u32 hash_lut_size = 0;
+       u32 val;
+
+       if (!settings)
+               return I40E_ERR_PARAM;
+
+       /* Validate the input settings */
+       ret = i40e_validate_filter_settings(hw, settings);
+       if (ret)
+               return ret;
+
+       /* Read the PF Queue Filter control register */
+       val = rd32(hw, I40E_PFQF_CTL_0);
+
+       /* Program required PE hash buckets for the PF */
+       val &= ~I40E_PFQF_CTL_0_PEHSIZE_MASK;
+       val |= ((u32)settings->pe_filt_num << I40E_PFQF_CTL_0_PEHSIZE_SHIFT) &
+               I40E_PFQF_CTL_0_PEHSIZE_MASK;
+       /* Program required PE contexts for the PF */
+       val &= ~I40E_PFQF_CTL_0_PEDSIZE_MASK;
+       val |= ((u32)settings->pe_cntx_num << I40E_PFQF_CTL_0_PEDSIZE_SHIFT) &
+               I40E_PFQF_CTL_0_PEDSIZE_MASK;
+
+       /* Program required FCoE hash buckets for the PF */
+       val &= ~I40E_PFQF_CTL_0_PFFCHSIZE_MASK;
+       val |= ((u32)settings->fcoe_filt_num <<
+                       I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) &
+               I40E_PFQF_CTL_0_PFFCHSIZE_MASK;
+       /* Program required FCoE DDP contexts for the PF */
+       val &= ~I40E_PFQF_CTL_0_PFFCDSIZE_MASK;
+       val |= ((u32)settings->fcoe_cntx_num <<
+                       I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) &
+               I40E_PFQF_CTL_0_PFFCDSIZE_MASK;
+
+       /* Program Hash LUT size for the PF */
+       val &= ~I40E_PFQF_CTL_0_HASHLUTSIZE_MASK;
+       if (settings->hash_lut_size == I40E_HASH_LUT_SIZE_512)
+               hash_lut_size = 1;
+       val |= (hash_lut_size << I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) &
+               I40E_PFQF_CTL_0_HASHLUTSIZE_MASK;
+
+       /* Enable FDIR, Ethertype and MACVLAN filters for PF and VFs */
+       if (settings->enable_fdir)
+               val |= I40E_PFQF_CTL_0_FD_ENA_MASK;
+       if (settings->enable_ethtype)
+               val |= I40E_PFQF_CTL_0_ETYPE_ENA_MASK;
+       if (settings->enable_macvlan)
+               val |= I40E_PFQF_CTL_0_MACVLAN_ENA_MASK;
+
+       wr32(hw, I40E_PFQF_CTL_0, val);
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
new file mode 100644 (file)
index 0000000..8dbd91f
--- /dev/null
@@ -0,0 +1,2076 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+
+#include "i40e.h"
+
+static struct dentry *i40e_dbg_root;
+
+/**
+ * i40e_dbg_find_vsi - searches for the vsi with the given seid
+ * @pf - the pf structure to search for the vsi
+ * @seid - seid of the vsi it is searching for
+ **/
+static struct i40e_vsi *i40e_dbg_find_vsi(struct i40e_pf *pf, int seid)
+{
+       int i;
+
+       if (seid < 0)
+               dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
+       else
+               for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+                       if (pf->vsi[i] && (pf->vsi[i]->seid == seid))
+                               return pf->vsi[i];
+
+       return NULL;
+}
+
+/**
+ * i40e_dbg_find_veb - searches for the veb with the given seid
+ * @pf - the pf structure to search for the veb
+ * @seid - seid of the veb it is searching for
+ **/
+static struct i40e_veb *i40e_dbg_find_veb(struct i40e_pf *pf, int seid)
+{
+       int i;
+
+       if ((seid < I40E_BASE_VEB_SEID) ||
+           (seid > (I40E_BASE_VEB_SEID + I40E_MAX_VEB)))
+               dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
+       else
+               for (i = 0; i < I40E_MAX_VEB; i++)
+                       if (pf->veb[i] && pf->veb[i]->seid == seid)
+                               return pf->veb[i];
+       return NULL;
+}
+
+/**************************************************************
+ * dump
+ * The dump entry in debugfs is for getting a data snapshow of
+ * the driver's current configuration and runtime details.
+ * When the filesystem entry is written, a snapshot is taken.
+ * When the entry is read, the most recent snapshot data is dumped.
+ **************************************************************/
+static char *i40e_dbg_dump_buf;
+static ssize_t i40e_dbg_dump_data_len;
+static ssize_t i40e_dbg_dump_buffer_len;
+
+/**
+ * i40e_dbg_dump_read - read the dump data
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ **/
+static ssize_t i40e_dbg_dump_read(struct file *filp, char __user *buffer,
+                                 size_t count, loff_t *ppos)
+{
+       int bytes_not_copied;
+       int len;
+
+       /* is *ppos bigger than the available data? */
+       if (*ppos >= i40e_dbg_dump_data_len || !i40e_dbg_dump_buf)
+               return 0;
+
+       /* be sure to not read beyond the end of available data */
+       len = min_t(int, count, (i40e_dbg_dump_data_len - *ppos));
+
+       bytes_not_copied = copy_to_user(buffer, &i40e_dbg_dump_buf[*ppos], len);
+       if (bytes_not_copied < 0)
+               return bytes_not_copied;
+
+       *ppos += len;
+       return len;
+}
+
+/**
+ * i40e_dbg_prep_dump_buf
+ * @pf: the pf we're working with
+ * @buflen: the desired buffer length
+ *
+ * Return positive if success, 0 if failed
+ **/
+static int i40e_dbg_prep_dump_buf(struct i40e_pf *pf, int buflen)
+{
+       /* if not already big enough, prep for re alloc */
+       if (i40e_dbg_dump_buffer_len && i40e_dbg_dump_buffer_len < buflen) {
+               kfree(i40e_dbg_dump_buf);
+               i40e_dbg_dump_buffer_len = 0;
+               i40e_dbg_dump_buf = NULL;
+       }
+
+       /* get a new buffer if needed */
+       if (!i40e_dbg_dump_buf) {
+               i40e_dbg_dump_buf = kzalloc(buflen, GFP_KERNEL);
+               if (i40e_dbg_dump_buf != NULL)
+                       i40e_dbg_dump_buffer_len = buflen;
+       }
+
+       return i40e_dbg_dump_buffer_len;
+}
+
+/**
+ * i40e_dbg_dump_write - trigger a datadump snapshot
+ * @filp: the opened file
+ * @buffer: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ *
+ * Any write clears the stats
+ **/
+static ssize_t i40e_dbg_dump_write(struct file *filp,
+                                  const char __user *buffer,
+                                  size_t count, loff_t *ppos)
+{
+       struct i40e_pf *pf = filp->private_data;
+       char dump_request_buf[16];
+       bool seid_found = false;
+       int bytes_not_copied;
+       long seid = -1;
+       int buflen = 0;
+       int i, ret;
+       int len;
+       u8 *p;
+
+       /* don't allow partial writes */
+       if (*ppos != 0)
+               return 0;
+       if (count >= sizeof(dump_request_buf))
+               return -ENOSPC;
+
+       bytes_not_copied = copy_from_user(dump_request_buf, buffer, count);
+       if (bytes_not_copied < 0)
+               return bytes_not_copied;
+       if (bytes_not_copied > 0)
+               count -= bytes_not_copied;
+       dump_request_buf[count] = '\0';
+
+       /* decode the SEID given to be dumped */
+       ret = kstrtol(dump_request_buf, 0, &seid);
+       if (ret < 0) {
+               dev_info(&pf->pdev->dev, "bad seid value '%s'\n",
+                        dump_request_buf);
+       } else if (seid == 0) {
+               seid_found = true;
+
+               kfree(i40e_dbg_dump_buf);
+               i40e_dbg_dump_buffer_len = 0;
+               i40e_dbg_dump_data_len = 0;
+               i40e_dbg_dump_buf = NULL;
+               dev_info(&pf->pdev->dev, "debug buffer freed\n");
+
+       } else if (seid == pf->pf_seid || seid == 1) {
+               seid_found = true;
+
+               buflen = sizeof(struct i40e_pf);
+               buflen += (sizeof(struct i40e_aq_desc)
+                    * (pf->hw.aq.num_arq_entries + pf->hw.aq.num_asq_entries));
+
+               if (i40e_dbg_prep_dump_buf(pf, buflen)) {
+                       p = i40e_dbg_dump_buf;
+
+                       len = sizeof(struct i40e_pf);
+                       memcpy(p, pf, len);
+                       p += len;
+
+                       len = (sizeof(struct i40e_aq_desc)
+                                       * pf->hw.aq.num_asq_entries);
+                       memcpy(p, pf->hw.aq.asq.desc, len);
+                       p += len;
+
+                       len = (sizeof(struct i40e_aq_desc)
+                                       * pf->hw.aq.num_arq_entries);
+                       memcpy(p, pf->hw.aq.arq.desc, len);
+                       p += len;
+
+                       i40e_dbg_dump_data_len = buflen;
+                       dev_info(&pf->pdev->dev,
+                                "PF seid %ld dumped %d bytes\n",
+                                seid, (int)i40e_dbg_dump_data_len);
+               }
+       } else if (seid >= I40E_BASE_VSI_SEID) {
+               struct i40e_vsi *vsi = NULL;
+               struct i40e_mac_filter *f;
+               int filter_count = 0;
+
+               mutex_lock(&pf->switch_mutex);
+               vsi = i40e_dbg_find_vsi(pf, seid);
+               if (!vsi) {
+                       mutex_unlock(&pf->switch_mutex);
+                       goto write_exit;
+               }
+
+               buflen = sizeof(struct i40e_vsi);
+               buflen += sizeof(struct i40e_q_vector) * vsi->num_q_vectors;
+               buflen += sizeof(struct i40e_ring) * 2 * vsi->num_queue_pairs;
+               buflen += sizeof(struct i40e_tx_buffer) * vsi->num_queue_pairs;
+               buflen += sizeof(struct i40e_rx_buffer) * vsi->num_queue_pairs;
+               list_for_each_entry(f, &vsi->mac_filter_list, list)
+                       filter_count++;
+               buflen += sizeof(struct i40e_mac_filter) * filter_count;
+
+               if (i40e_dbg_prep_dump_buf(pf, buflen)) {
+                       p = i40e_dbg_dump_buf;
+                       seid_found = true;
+
+                       len = sizeof(struct i40e_vsi);
+                       memcpy(p, vsi, len);
+                       p += len;
+
+                       len = (sizeof(struct i40e_q_vector)
+                               * vsi->num_q_vectors);
+                       memcpy(p, vsi->q_vectors, len);
+                       p += len;
+
+                       len = (sizeof(struct i40e_ring) * vsi->num_queue_pairs);
+                       memcpy(p, vsi->tx_rings, len);
+                       p += len;
+                       memcpy(p, vsi->rx_rings, len);
+                       p += len;
+
+                       for (i = 0; i < vsi->num_queue_pairs; i++) {
+                               len = sizeof(struct i40e_tx_buffer);
+                               memcpy(p, vsi->tx_rings[i].tx_bi, len);
+                               p += len;
+                       }
+                       for (i = 0; i < vsi->num_queue_pairs; i++) {
+                               len = sizeof(struct i40e_rx_buffer);
+                               memcpy(p, vsi->rx_rings[i].rx_bi, len);
+                               p += len;
+                       }
+
+                       /* macvlan filter list */
+                       len = sizeof(struct i40e_mac_filter);
+                       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+                               memcpy(p, f, len);
+                               p += len;
+                       }
+
+                       i40e_dbg_dump_data_len = buflen;
+                       dev_info(&pf->pdev->dev,
+                                "VSI seid %ld dumped %d bytes\n",
+                                seid, (int)i40e_dbg_dump_data_len);
+               }
+               mutex_unlock(&pf->switch_mutex);
+       } else if (seid >= I40E_BASE_VEB_SEID) {
+               struct i40e_veb *veb = NULL;
+
+               mutex_lock(&pf->switch_mutex);
+               veb = i40e_dbg_find_veb(pf, seid);
+               if (!veb) {
+                       mutex_unlock(&pf->switch_mutex);
+                       goto write_exit;
+               }
+
+               buflen = sizeof(struct i40e_veb);
+               if (i40e_dbg_prep_dump_buf(pf, buflen)) {
+                       seid_found = true;
+                       memcpy(i40e_dbg_dump_buf, veb, buflen);
+                       i40e_dbg_dump_data_len = buflen;
+                       dev_info(&pf->pdev->dev,
+                                "VEB seid %ld dumped %d bytes\n",
+                                seid, (int)i40e_dbg_dump_data_len);
+               }
+               mutex_unlock(&pf->switch_mutex);
+       }
+
+write_exit:
+       if (!seid_found)
+               dev_info(&pf->pdev->dev, "unknown seid %ld\n", seid);
+
+       return count;
+}
+
+static const struct file_operations i40e_dbg_dump_fops = {
+       .owner = THIS_MODULE,
+       .open =  simple_open,
+       .read =  i40e_dbg_dump_read,
+       .write = i40e_dbg_dump_write,
+};
+
+/**************************************************************
+ * command
+ * The command entry in debugfs is for giving the driver commands
+ * to be executed - these may be for changing the internal switch
+ * setup, adding or removing filters, or other things.  Many of
+ * these will be useful for some forms of unit testing.
+ **************************************************************/
+static char i40e_dbg_command_buf[256] = "hello world";
+
+/**
+ * i40e_dbg_command_read - read for command datum
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ **/
+static ssize_t i40e_dbg_command_read(struct file *filp, char __user *buffer,
+                                    size_t count, loff_t *ppos)
+{
+       struct i40e_pf *pf = filp->private_data;
+       int bytes_not_copied;
+       int buf_size = 256;
+       char *buf;
+       int len;
+
+       /* don't allow partial reads */
+       if (*ppos != 0)
+               return 0;
+       if (count < buf_size)
+               return -ENOSPC;
+
+       buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOSPC;
+
+       len = snprintf(buf, buf_size, "%s: %s\n",
+                      pf->vsi[pf->lan_vsi]->netdev->name,
+                      i40e_dbg_command_buf);
+
+       bytes_not_copied = copy_to_user(buffer, buf, len);
+       kfree(buf);
+
+       if (bytes_not_copied < 0)
+               return bytes_not_copied;
+
+       *ppos = len;
+       return len;
+}
+
+/**
+ * i40e_dbg_dump_vsi_seid - handles dump vsi seid write into pokem datum
+ * @pf: the i40e_pf created in command write
+ * @seid: the seid the user put in
+ **/
+static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
+{
+       struct rtnl_link_stats64 *nstat;
+       struct i40e_mac_filter *f;
+       struct i40e_vsi *vsi;
+       int i;
+
+       vsi = i40e_dbg_find_vsi(pf, seid);
+       if (!vsi) {
+               dev_info(&pf->pdev->dev,
+                        "dump %d: seid not found\n", seid);
+               return;
+       }
+       dev_info(&pf->pdev->dev, "vsi seid %d\n", seid);
+       if (vsi->netdev)
+               dev_info(&pf->pdev->dev,
+                        "    netdev: name = %s\n",
+                        vsi->netdev->name);
+       if (vsi->active_vlans)
+               dev_info(&pf->pdev->dev,
+                        "    vlgrp: & = %p\n", vsi->active_vlans);
+       dev_info(&pf->pdev->dev,
+                "    netdev_registered = %i, current_netdev_flags = 0x%04x, state = %li flags = 0x%08lx\n",
+                vsi->netdev_registered,
+                vsi->current_netdev_flags, vsi->state, vsi->flags);
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               dev_info(&pf->pdev->dev,
+                        "    mac_filter_list: %pM vid=%d, is_netdev=%d is_vf=%d counter=%d\n",
+                        f->macaddr, f->vlan, f->is_netdev, f->is_vf,
+                        f->counter);
+       }
+       nstat = i40e_get_vsi_stats_struct(vsi);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: rx_packets = %lu, rx_bytes = %lu, rx_errors = %lu, rx_dropped = %lu\n",
+                (long unsigned int)nstat->rx_packets,
+                (long unsigned int)nstat->rx_bytes,
+                (long unsigned int)nstat->rx_errors,
+                (long unsigned int)nstat->rx_dropped);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: tx_packets = %lu, tx_bytes = %lu, tx_errors = %lu, tx_dropped = %lu\n",
+                (long unsigned int)nstat->tx_packets,
+                (long unsigned int)nstat->tx_bytes,
+                (long unsigned int)nstat->tx_errors,
+                (long unsigned int)nstat->tx_dropped);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: multicast = %lu, collisions = %lu\n",
+                (long unsigned int)nstat->multicast,
+                (long unsigned int)nstat->collisions);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: rx_length_errors = %lu, rx_over_errors = %lu, rx_crc_errors = %lu\n",
+                (long unsigned int)nstat->rx_length_errors,
+                (long unsigned int)nstat->rx_over_errors,
+                (long unsigned int)nstat->rx_crc_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: rx_frame_errors = %lu, rx_fifo_errors = %lu, rx_missed_errors = %lu\n",
+                (long unsigned int)nstat->rx_frame_errors,
+                (long unsigned int)nstat->rx_fifo_errors,
+                (long unsigned int)nstat->rx_missed_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: tx_aborted_errors = %lu, tx_carrier_errors = %lu, tx_fifo_errors = %lu\n",
+                (long unsigned int)nstat->tx_aborted_errors,
+                (long unsigned int)nstat->tx_carrier_errors,
+                (long unsigned int)nstat->tx_fifo_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: tx_heartbeat_errors = %lu, tx_window_errors = %lu\n",
+                (long unsigned int)nstat->tx_heartbeat_errors,
+                (long unsigned int)nstat->tx_window_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats: rx_compressed = %lu, tx_compressed = %lu\n",
+                (long unsigned int)nstat->rx_compressed,
+                (long unsigned int)nstat->tx_compressed);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: rx_packets = %lu, rx_bytes = %lu, rx_errors = %lu, rx_dropped = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.rx_packets,
+                (long unsigned int)vsi->net_stats_offsets.rx_bytes,
+                (long unsigned int)vsi->net_stats_offsets.rx_errors,
+                (long unsigned int)vsi->net_stats_offsets.rx_dropped);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: tx_packets = %lu, tx_bytes = %lu, tx_errors = %lu, tx_dropped = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.tx_packets,
+                (long unsigned int)vsi->net_stats_offsets.tx_bytes,
+                (long unsigned int)vsi->net_stats_offsets.tx_errors,
+                (long unsigned int)vsi->net_stats_offsets.tx_dropped);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: multicast = %lu, collisions = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.multicast,
+                (long unsigned int)vsi->net_stats_offsets.collisions);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: rx_length_errors = %lu, rx_over_errors = %lu, rx_crc_errors = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.rx_length_errors,
+                (long unsigned int)vsi->net_stats_offsets.rx_over_errors,
+                (long unsigned int)vsi->net_stats_offsets.rx_crc_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: rx_frame_errors = %lu, rx_fifo_errors = %lu, rx_missed_errors = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.rx_frame_errors,
+                (long unsigned int)vsi->net_stats_offsets.rx_fifo_errors,
+                (long unsigned int)vsi->net_stats_offsets.rx_missed_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: tx_aborted_errors = %lu, tx_carrier_errors = %lu, tx_fifo_errors = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.tx_aborted_errors,
+                (long unsigned int)vsi->net_stats_offsets.tx_carrier_errors,
+                (long unsigned int)vsi->net_stats_offsets.tx_fifo_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: tx_heartbeat_errors = %lu, tx_window_errors = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.tx_heartbeat_errors,
+                (long unsigned int)vsi->net_stats_offsets.tx_window_errors);
+       dev_info(&pf->pdev->dev,
+                "    net_stats_offsets: rx_compressed = %lu, tx_compressed = %lu\n",
+                (long unsigned int)vsi->net_stats_offsets.rx_compressed,
+                (long unsigned int)vsi->net_stats_offsets.tx_compressed);
+       dev_info(&pf->pdev->dev,
+                "    tx_restart = %d, tx_busy = %d, rx_buf_failed = %d, rx_page_failed = %d\n",
+                vsi->tx_restart, vsi->tx_busy,
+                vsi->rx_buf_failed, vsi->rx_page_failed);
+       if (vsi->rx_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: desc = %p\n",
+                                i, vsi->rx_rings[i].desc);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: dev = %p, netdev = %p, rx_bi = %p\n",
+                                i, vsi->rx_rings[i].dev,
+                                vsi->rx_rings[i].netdev,
+                                vsi->rx_rings[i].rx_bi);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: state = %li, queue_index = %d, reg_idx = %d\n",
+                                i, vsi->rx_rings[i].state,
+                                vsi->rx_rings[i].queue_index,
+                                vsi->rx_rings[i].reg_idx);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: rx_hdr_len = %d, rx_buf_len = %d, dtype = %d\n",
+                                i, vsi->rx_rings[i].rx_hdr_len,
+                                vsi->rx_rings[i].rx_buf_len,
+                                vsi->rx_rings[i].dtype);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: hsplit = %d, next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
+                                i, vsi->rx_rings[i].hsplit,
+                                vsi->rx_rings[i].next_to_use,
+                                vsi->rx_rings[i].next_to_clean,
+                                vsi->rx_rings[i].ring_active);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: rx_stats: packets = %lld, bytes = %lld, non_eop_descs = %lld\n",
+                                i, vsi->rx_rings[i].rx_stats.packets,
+                                vsi->rx_rings[i].rx_stats.bytes,
+                                vsi->rx_rings[i].rx_stats.non_eop_descs);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: rx_stats: alloc_rx_page_failed = %lld, alloc_rx_buff_failed = %lld\n",
+                                i,
+                                vsi->rx_rings[i].rx_stats.alloc_rx_page_failed,
+                               vsi->rx_rings[i].rx_stats.alloc_rx_buff_failed);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: size = %i, dma = 0x%08lx\n",
+                                i, vsi->rx_rings[i].size,
+                                (long unsigned int)vsi->rx_rings[i].dma);
+                       dev_info(&pf->pdev->dev,
+                                "    rx_rings[%i]: vsi = %p, q_vector = %p\n",
+                                i, vsi->rx_rings[i].vsi,
+                                vsi->rx_rings[i].q_vector);
+               }
+       }
+       if (vsi->tx_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: desc = %p\n",
+                                i, vsi->tx_rings[i].desc);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: dev = %p, netdev = %p, tx_bi = %p\n",
+                                i, vsi->tx_rings[i].dev,
+                                vsi->tx_rings[i].netdev,
+                                vsi->tx_rings[i].tx_bi);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: state = %li, queue_index = %d, reg_idx = %d\n",
+                                i, vsi->tx_rings[i].state,
+                                vsi->tx_rings[i].queue_index,
+                                vsi->tx_rings[i].reg_idx);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: dtype = %d\n",
+                                i, vsi->tx_rings[i].dtype);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: hsplit = %d, next_to_use = %d, next_to_clean = %d, ring_active = %i\n",
+                                i, vsi->tx_rings[i].hsplit,
+                                vsi->tx_rings[i].next_to_use,
+                                vsi->tx_rings[i].next_to_clean,
+                                vsi->tx_rings[i].ring_active);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: tx_stats: packets = %lld, bytes = %lld, restart_queue = %lld\n",
+                                i, vsi->tx_rings[i].tx_stats.packets,
+                                vsi->tx_rings[i].tx_stats.bytes,
+                                vsi->tx_rings[i].tx_stats.restart_queue);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: tx_stats: tx_busy = %lld, completed = %lld, tx_done_old = %lld\n",
+                                i,
+                                vsi->tx_rings[i].tx_stats.tx_busy,
+                                vsi->tx_rings[i].tx_stats.completed,
+                                vsi->tx_rings[i].tx_stats.tx_done_old);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: size = %i, dma = 0x%08lx\n",
+                                i, vsi->tx_rings[i].size,
+                                (long unsigned int)vsi->tx_rings[i].dma);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: vsi = %p, q_vector = %p\n",
+                                i, vsi->tx_rings[i].vsi,
+                                vsi->tx_rings[i].q_vector);
+                       dev_info(&pf->pdev->dev,
+                                "    tx_rings[%i]: DCB tc = %d\n",
+                                i, vsi->tx_rings[i].dcb_tc);
+               }
+       }
+       dev_info(&pf->pdev->dev,
+                "    work_limit = %d, rx_itr_setting = %d (%s), tx_itr_setting = %d (%s)\n",
+                vsi->work_limit, vsi->rx_itr_setting,
+                ITR_IS_DYNAMIC(vsi->rx_itr_setting) ? "dynamic" : "fixed",
+                vsi->tx_itr_setting,
+                ITR_IS_DYNAMIC(vsi->tx_itr_setting) ? "dynamic" : "fixed");
+       dev_info(&pf->pdev->dev,
+                "    max_frame = %d, rx_hdr_len = %d, rx_buf_len = %d dtype = %d\n",
+                vsi->max_frame, vsi->rx_hdr_len, vsi->rx_buf_len, vsi->dtype);
+       if (vsi->q_vectors) {
+               for (i = 0; i < vsi->num_q_vectors; i++) {
+                       dev_info(&pf->pdev->dev,
+                                "    q_vectors[%i]: base index = %ld\n",
+                                i, ((long int)*vsi->q_vectors[i].rx.ring-
+                                       (long int)*vsi->q_vectors[0].rx.ring)/
+                                       sizeof(struct i40e_ring));
+               }
+       }
+       dev_info(&pf->pdev->dev,
+                "    num_q_vectors = %i, base_vector = %i\n",
+                vsi->num_q_vectors, vsi->base_vector);
+       dev_info(&pf->pdev->dev,
+                "    seid = %d, id = %d, uplink_seid = %d\n",
+                vsi->seid, vsi->id, vsi->uplink_seid);
+       dev_info(&pf->pdev->dev,
+                "    base_queue = %d, num_queue_pairs = %d, num_desc = %d\n",
+                vsi->base_queue, vsi->num_queue_pairs, vsi->num_desc);
+       dev_info(&pf->pdev->dev, "    type = %i\n", vsi->type);
+       dev_info(&pf->pdev->dev,
+                "    info: valid_sections = 0x%04x, switch_id = 0x%04x\n",
+                vsi->info.valid_sections, vsi->info.switch_id);
+       dev_info(&pf->pdev->dev,
+                "    info: sw_reserved[] = 0x%02x 0x%02x\n",
+                vsi->info.sw_reserved[0], vsi->info.sw_reserved[1]);
+       dev_info(&pf->pdev->dev,
+                "    info: sec_flags = 0x%02x, sec_reserved = 0x%02x\n",
+                vsi->info.sec_flags, vsi->info.sec_reserved);
+       dev_info(&pf->pdev->dev,
+                "    info: pvid = 0x%04x, fcoe_pvid = 0x%04x, port_vlan_flags = 0x%02x\n",
+                vsi->info.pvid, vsi->info.fcoe_pvid,
+                vsi->info.port_vlan_flags);
+       dev_info(&pf->pdev->dev,
+                "    info: pvlan_reserved[] = 0x%02x 0x%02x 0x%02x\n",
+                vsi->info.pvlan_reserved[0], vsi->info.pvlan_reserved[1],
+                vsi->info.pvlan_reserved[2]);
+       dev_info(&pf->pdev->dev,
+                "    info: ingress_table = 0x%08x, egress_table = 0x%08x\n",
+                vsi->info.ingress_table, vsi->info.egress_table);
+       dev_info(&pf->pdev->dev,
+                "    info: cas_pv_stag = 0x%04x, cas_pv_flags= 0x%02x, cas_pv_reserved = 0x%02x\n",
+                vsi->info.cas_pv_tag, vsi->info.cas_pv_flags,
+                vsi->info.cas_pv_reserved);
+       dev_info(&pf->pdev->dev,
+                "    info: queue_mapping[0..7 ] = 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
+                vsi->info.queue_mapping[0], vsi->info.queue_mapping[1],
+                vsi->info.queue_mapping[2], vsi->info.queue_mapping[3],
+                vsi->info.queue_mapping[4], vsi->info.queue_mapping[5],
+                vsi->info.queue_mapping[6], vsi->info.queue_mapping[7]);
+       dev_info(&pf->pdev->dev,
+                "    info: queue_mapping[8..15] = 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
+                vsi->info.queue_mapping[8], vsi->info.queue_mapping[9],
+                vsi->info.queue_mapping[10], vsi->info.queue_mapping[11],
+                vsi->info.queue_mapping[12], vsi->info.queue_mapping[13],
+                vsi->info.queue_mapping[14], vsi->info.queue_mapping[15]);
+       dev_info(&pf->pdev->dev,
+                "    info: tc_mapping[] = 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
+                vsi->info.tc_mapping[0], vsi->info.tc_mapping[1],
+                vsi->info.tc_mapping[2], vsi->info.tc_mapping[3],
+                vsi->info.tc_mapping[4], vsi->info.tc_mapping[5],
+                vsi->info.tc_mapping[6], vsi->info.tc_mapping[7]);
+       dev_info(&pf->pdev->dev,
+                "    info: queueing_opt_flags = 0x%02x  queueing_opt_reserved[0..2] = 0x%02x 0x%02x 0x%02x\n",
+                vsi->info.queueing_opt_flags,
+                vsi->info.queueing_opt_reserved[0],
+                vsi->info.queueing_opt_reserved[1],
+                vsi->info.queueing_opt_reserved[2]);
+       dev_info(&pf->pdev->dev,
+                "    info: up_enable_bits = 0x%02x\n",
+                vsi->info.up_enable_bits);
+       dev_info(&pf->pdev->dev,
+                "    info: sched_reserved = 0x%02x, outer_up_table = 0x%04x\n",
+                vsi->info.sched_reserved, vsi->info.outer_up_table);
+       dev_info(&pf->pdev->dev,
+                "    info: cmd_reserved[] = 0x%02x 0x%02x 0x%02x 0x0%02x 0x%02x 0x%02x 0x%02x 0x0%02x\n",
+                vsi->info.cmd_reserved[0], vsi->info.cmd_reserved[1],
+                vsi->info.cmd_reserved[2], vsi->info.cmd_reserved[3],
+                vsi->info.cmd_reserved[4], vsi->info.cmd_reserved[5],
+                vsi->info.cmd_reserved[6], vsi->info.cmd_reserved[7]);
+       dev_info(&pf->pdev->dev,
+                "    info: qs_handle[] = 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n",
+                vsi->info.qs_handle[0], vsi->info.qs_handle[1],
+                vsi->info.qs_handle[2], vsi->info.qs_handle[3],
+                vsi->info.qs_handle[4], vsi->info.qs_handle[5],
+                vsi->info.qs_handle[6], vsi->info.qs_handle[7]);
+       dev_info(&pf->pdev->dev,
+                "    info: stat_counter_idx = 0x%04x, sched_id = 0x%04x\n",
+                vsi->info.stat_counter_idx, vsi->info.sched_id);
+       dev_info(&pf->pdev->dev,
+                "    info: resp_reserved[] = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
+                vsi->info.resp_reserved[0], vsi->info.resp_reserved[1],
+                vsi->info.resp_reserved[2], vsi->info.resp_reserved[3],
+                vsi->info.resp_reserved[4], vsi->info.resp_reserved[5],
+                vsi->info.resp_reserved[6], vsi->info.resp_reserved[7],
+                vsi->info.resp_reserved[8], vsi->info.resp_reserved[9],
+                vsi->info.resp_reserved[10], vsi->info.resp_reserved[11]);
+       if (vsi->back)
+               dev_info(&pf->pdev->dev, "    pf = %p\n", vsi->back);
+       dev_info(&pf->pdev->dev, "    idx = %d\n", vsi->idx);
+       dev_info(&pf->pdev->dev,
+                "    tc_config: numtc = %d, enabled_tc = 0x%x\n",
+                vsi->tc_config.numtc, vsi->tc_config.enabled_tc);
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               dev_info(&pf->pdev->dev,
+                        "    tc_config: tc = %d, qoffset = %d, qcount = %d, netdev_tc = %d\n",
+                        i, vsi->tc_config.tc_info[i].qoffset,
+                        vsi->tc_config.tc_info[i].qcount,
+                        vsi->tc_config.tc_info[i].netdev_tc);
+       }
+       dev_info(&pf->pdev->dev,
+                "    bw: bw_limit = %d, bw_max_quanta = %d\n",
+                vsi->bw_limit, vsi->bw_max_quanta);
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               dev_info(&pf->pdev->dev,
+                        "    bw[%d]: ets_share_credits = %d, ets_limit_credits = %d, max_quanta = %d\n",
+                        i, vsi->bw_ets_share_credits[i],
+                        vsi->bw_ets_limit_credits[i],
+                        vsi->bw_ets_max_quanta[i]);
+       }
+}
+
+/**
+ * i40e_dbg_dump_aq_desc - handles dump aq_desc write into command datum
+ * @pf: the i40e_pf created in command write
+ **/
+static void i40e_dbg_dump_aq_desc(struct i40e_pf *pf)
+{
+       struct i40e_adminq_ring *ring;
+       struct i40e_hw *hw = &pf->hw;
+       int i;
+
+       /* first the send (command) ring, then the receive (event) ring */
+       dev_info(&pf->pdev->dev, "AdminQ Tx Ring\n");
+       ring = &(hw->aq.asq);
+       for (i = 0; i < ring->count; i++) {
+               struct i40e_aq_desc *d = I40E_ADMINQ_DESC(*ring, i);
+               dev_info(&pf->pdev->dev,
+                        "   at[%02d] flags=0x%04x op=0x%04x dlen=0x%04x ret=0x%04x cookie_h=0x%08x cookie_l=0x%08x\n",
+                        i, d->flags, d->opcode, d->datalen, d->retval,
+                        d->cookie_high, d->cookie_low);
+               dev_info(&pf->pdev->dev,
+                        "            %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                        d->params.raw[0], d->params.raw[1], d->params.raw[2],
+                        d->params.raw[3], d->params.raw[4], d->params.raw[5],
+                        d->params.raw[6], d->params.raw[7], d->params.raw[8],
+                        d->params.raw[9], d->params.raw[10], d->params.raw[11],
+                        d->params.raw[12], d->params.raw[13],
+                        d->params.raw[14], d->params.raw[15]);
+       }
+
+       dev_info(&pf->pdev->dev, "AdminQ Rx Ring\n");
+       ring = &(hw->aq.arq);
+       for (i = 0; i < ring->count; i++) {
+               struct i40e_aq_desc *d = I40E_ADMINQ_DESC(*ring, i);
+               dev_info(&pf->pdev->dev,
+                        "   ar[%02d] flags=0x%04x op=0x%04x dlen=0x%04x ret=0x%04x cookie_h=0x%08x cookie_l=0x%08x\n",
+                        i, d->flags, d->opcode, d->datalen, d->retval,
+                        d->cookie_high, d->cookie_low);
+               dev_info(&pf->pdev->dev,
+                        "            %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+                        d->params.raw[0], d->params.raw[1], d->params.raw[2],
+                        d->params.raw[3], d->params.raw[4], d->params.raw[5],
+                        d->params.raw[6], d->params.raw[7], d->params.raw[8],
+                        d->params.raw[9], d->params.raw[10], d->params.raw[11],
+                        d->params.raw[12], d->params.raw[13],
+                        d->params.raw[14], d->params.raw[15]);
+       }
+}
+
+/**
+ * i40e_dbg_dump_desc - handles dump desc write into command datum
+ * @cnt: number of arguments that the user supplied
+ * @vsi_seid: vsi id entered by user
+ * @ring_id: ring id entered by user
+ * @desc_n: descriptor number entered by user
+ * @pf: the i40e_pf created in command write
+ * @is_rx_ring: true if rx, false if tx
+ **/
+static void i40e_dbg_dump_desc(int cnt, int vsi_seid, int ring_id, int desc_n,
+                              struct i40e_pf *pf, bool is_rx_ring)
+{
+       union i40e_rx_desc *ds;
+       struct i40e_ring ring;
+       struct i40e_vsi *vsi;
+       int i;
+
+       vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+       if (!vsi) {
+               dev_info(&pf->pdev->dev,
+                        "vsi %d not found\n", vsi_seid);
+               if (is_rx_ring)
+                       dev_info(&pf->pdev->dev, "dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
+               else
+                       dev_info(&pf->pdev->dev, "dump desc tx <vsi_seid> <ring_id> [<desc_n>]\n");
+               return;
+       }
+       if (ring_id >= vsi->num_queue_pairs || ring_id < 0) {
+               dev_info(&pf->pdev->dev, "ring %d not found\n", ring_id);
+               if (is_rx_ring)
+                       dev_info(&pf->pdev->dev, "dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
+               else
+                       dev_info(&pf->pdev->dev, "dump desc tx <vsi_seid> <ring_id> [<desc_n>]\n");
+               return;
+       }
+       if (is_rx_ring)
+               ring = vsi->rx_rings[ring_id];
+       else
+               ring = vsi->tx_rings[ring_id];
+       if (cnt == 2) {
+               dev_info(&pf->pdev->dev, "vsi = %02i %s ring = %02i\n",
+                        vsi_seid, is_rx_ring ? "rx" : "tx", ring_id);
+               for (i = 0; i < ring.count; i++) {
+                       if (is_rx_ring)
+                               ds = I40E_RX_DESC(&ring, i);
+                       else
+                               ds = (union i40e_rx_desc *)
+                                       I40E_TX_DESC(&ring, i);
+                       if ((sizeof(union i40e_rx_desc) ==
+                           sizeof(union i40e_16byte_rx_desc)) || (!is_rx_ring))
+                               dev_info(&pf->pdev->dev,
+                                        "   d[%03i] = 0x%016llx 0x%016llx\n", i,
+                                        ds->read.pkt_addr, ds->read.hdr_addr);
+                       else
+                               dev_info(&pf->pdev->dev,
+                                        "   d[%03i] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
+                                        i, ds->read.pkt_addr,
+                                        ds->read.hdr_addr,
+                                        ds->read.rsvd1, ds->read.rsvd2);
+               }
+       } else if (cnt == 3) {
+               if (desc_n >= ring.count || desc_n < 0) {
+                       dev_info(&pf->pdev->dev,
+                                "descriptor %d not found\n", desc_n);
+                       return;
+               }
+               if (is_rx_ring)
+                       ds = I40E_RX_DESC(&ring, desc_n);
+               else
+                       ds = (union i40e_rx_desc *)I40E_TX_DESC(&ring, desc_n);
+               if ((sizeof(union i40e_rx_desc) ==
+                   sizeof(union i40e_16byte_rx_desc)) || (!is_rx_ring))
+                       dev_info(&pf->pdev->dev,
+                                "vsi = %02i %s ring = %02i d[%03i] = 0x%016llx 0x%016llx\n",
+                                vsi_seid, is_rx_ring ? "rx" : "tx", ring_id,
+                                desc_n, ds->read.pkt_addr, ds->read.hdr_addr);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "vsi = %02i rx ring = %02i d[%03i] = 0x%016llx 0x%016llx 0x%016llx 0x%016llx\n",
+                                vsi_seid, ring_id,
+                                desc_n, ds->read.pkt_addr, ds->read.hdr_addr,
+                                ds->read.rsvd1, ds->read.rsvd2);
+       } else {
+               if (is_rx_ring)
+                       dev_info(&pf->pdev->dev, "dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
+               else
+                       dev_info(&pf->pdev->dev, "dump desc tx <vsi_seid> <ring_id> [<desc_n>]\n");
+       }
+}
+
+/**
+ * i40e_dbg_dump_vsi_no_seid - handles dump vsi write into command datum
+ * @pf: the i40e_pf created in command write
+ **/
+static void i40e_dbg_dump_vsi_no_seid(struct i40e_pf *pf)
+{
+       int i;
+
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+               if (pf->vsi[i])
+                       dev_info(&pf->pdev->dev, "dump vsi[%d]: %d\n",
+                                i, pf->vsi[i]->seid);
+}
+
+/**
+ * i40e_dbg_dump_stats - handles dump stats write into command datum
+ * @pf: the i40e_pf created in command write
+ * @estats: the eth stats structure to be dumped
+ **/
+static void i40e_dbg_dump_eth_stats(struct i40e_pf *pf,
+                                   struct i40e_eth_stats *estats)
+{
+       dev_info(&pf->pdev->dev, "  ethstats:\n");
+       dev_info(&pf->pdev->dev,
+                "    rx_bytes = \t%lld \trx_unicast = \t\t%lld \trx_multicast = \t%lld\n",
+               estats->rx_bytes, estats->rx_unicast, estats->rx_multicast);
+       dev_info(&pf->pdev->dev,
+                "    rx_broadcast = \t%lld \trx_discards = \t\t%lld \trx_errors = \t%lld\n",
+                estats->rx_broadcast, estats->rx_discards, estats->rx_errors);
+       dev_info(&pf->pdev->dev,
+                "    rx_missed = \t%lld \trx_unknown_protocol = \t%lld \ttx_bytes = \t%lld\n",
+                estats->rx_missed, estats->rx_unknown_protocol,
+                estats->tx_bytes);
+       dev_info(&pf->pdev->dev,
+                "    tx_unicast = \t%lld \ttx_multicast = \t\t%lld \ttx_broadcast = \t%lld\n",
+                estats->tx_unicast, estats->tx_multicast, estats->tx_broadcast);
+       dev_info(&pf->pdev->dev,
+                "    tx_discards = \t%lld \ttx_errors = \t\t%lld\n",
+                estats->tx_discards, estats->tx_errors);
+}
+
+/**
+ * i40e_dbg_dump_stats - handles dump stats write into command datum
+ * @pf: the i40e_pf created in command write
+ * @stats: the stats structure to be dumped
+ **/
+static void i40e_dbg_dump_stats(struct i40e_pf *pf,
+                               struct i40e_hw_port_stats *stats)
+{
+       int i;
+
+       dev_info(&pf->pdev->dev, "  stats:\n");
+       dev_info(&pf->pdev->dev,
+                "    crc_errors = \t\t%lld \tillegal_bytes = \t%lld \terror_bytes = \t\t%lld\n",
+                stats->crc_errors, stats->illegal_bytes, stats->error_bytes);
+       dev_info(&pf->pdev->dev,
+                "    mac_local_faults = \t%lld \tmac_remote_faults = \t%lld \trx_length_errors = \t%lld\n",
+                stats->mac_local_faults, stats->mac_remote_faults,
+                stats->rx_length_errors);
+       dev_info(&pf->pdev->dev,
+                "    link_xon_rx = \t\t%lld \tlink_xoff_rx = \t\t%lld \tlink_xon_tx = \t\t%lld\n",
+                stats->link_xon_rx, stats->link_xoff_rx, stats->link_xon_tx);
+       dev_info(&pf->pdev->dev,
+                "    link_xoff_tx = \t\t%lld \trx_size_64 = \t\t%lld \trx_size_127 = \t\t%lld\n",
+                stats->link_xoff_tx, stats->rx_size_64, stats->rx_size_127);
+       dev_info(&pf->pdev->dev,
+                "    rx_size_255 = \t\t%lld \trx_size_511 = \t\t%lld \trx_size_1023 = \t\t%lld\n",
+                stats->rx_size_255, stats->rx_size_511, stats->rx_size_1023);
+       dev_info(&pf->pdev->dev,
+                "    rx_size_big = \t\t%lld \trx_undersize = \t\t%lld \trx_jabber = \t\t%lld\n",
+                stats->rx_size_big, stats->rx_undersize, stats->rx_jabber);
+       dev_info(&pf->pdev->dev,
+                "    rx_fragments = \t\t%lld \trx_oversize = \t\t%lld \ttx_size_64 = \t\t%lld\n",
+                stats->rx_fragments, stats->rx_oversize, stats->tx_size_64);
+       dev_info(&pf->pdev->dev,
+                "    tx_size_127 = \t\t%lld \ttx_size_255 = \t\t%lld \ttx_size_511 = \t\t%lld\n",
+                stats->tx_size_127, stats->tx_size_255, stats->tx_size_511);
+       dev_info(&pf->pdev->dev,
+                "    tx_size_1023 = \t\t%lld \ttx_size_big = \t\t%lld \tmac_short_packet_dropped = \t%lld\n",
+                stats->tx_size_1023, stats->tx_size_big,
+                stats->mac_short_packet_dropped);
+       for (i = 0; i < 8; i += 4) {
+               dev_info(&pf->pdev->dev,
+                        "    priority_xon_rx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
+                        i, stats->priority_xon_rx[i],
+                        i+1, stats->priority_xon_rx[i+1],
+                        i+2, stats->priority_xon_rx[i+2],
+                        i+3, stats->priority_xon_rx[i+3]);
+       }
+       for (i = 0; i < 8; i += 4) {
+               dev_info(&pf->pdev->dev,
+                        "    priority_xoff_rx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
+                        i, stats->priority_xoff_rx[i],
+                        i+1, stats->priority_xoff_rx[i+1],
+                        i+2, stats->priority_xoff_rx[i+2],
+                        i+3, stats->priority_xoff_rx[i+3]);
+       }
+       for (i = 0; i < 8; i += 4) {
+               dev_info(&pf->pdev->dev,
+                        "    priority_xon_tx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
+                        i, stats->priority_xon_tx[i],
+                        i+1, stats->priority_xon_tx[i+1],
+                        i+2, stats->priority_xon_tx[i+2],
+                        i+3, stats->priority_xon_rx[i+3]);
+       }
+       for (i = 0; i < 8; i += 4) {
+               dev_info(&pf->pdev->dev,
+                        "    priority_xoff_tx[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
+                        i, stats->priority_xoff_tx[i],
+                        i+1, stats->priority_xoff_tx[i+1],
+                        i+2, stats->priority_xoff_tx[i+2],
+                        i+3, stats->priority_xoff_tx[i+3]);
+       }
+       for (i = 0; i < 8; i += 4) {
+               dev_info(&pf->pdev->dev,
+                        "    priority_xon_2_xoff[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld \t[%d] = \t%lld\n",
+                        i, stats->priority_xon_2_xoff[i],
+                        i+1, stats->priority_xon_2_xoff[i+1],
+                        i+2, stats->priority_xon_2_xoff[i+2],
+                        i+3, stats->priority_xon_2_xoff[i+3]);
+       }
+
+       i40e_dbg_dump_eth_stats(pf, &stats->eth);
+}
+
+/**
+ * i40e_dbg_dump_veb_seid - handles dump stats of a single given veb
+ * @pf: the i40e_pf created in command write
+ * @seid: the seid the user put in
+ **/
+static void i40e_dbg_dump_veb_seid(struct i40e_pf *pf, int seid)
+{
+       struct i40e_veb *veb;
+
+       if ((seid < I40E_BASE_VEB_SEID) ||
+           (seid >= (I40E_MAX_VEB + I40E_BASE_VEB_SEID))) {
+               dev_info(&pf->pdev->dev, "%d: bad seid\n", seid);
+               return;
+       }
+
+       veb = i40e_dbg_find_veb(pf, seid);
+       if (!veb) {
+               dev_info(&pf->pdev->dev,
+                        "%d: can't find veb\n", seid);
+               return;
+       }
+       dev_info(&pf->pdev->dev,
+                "veb idx=%d,%d stats_ic=%d  seid=%d uplink=%d\n",
+                veb->idx, veb->veb_idx, veb->stats_idx, veb->seid,
+                veb->uplink_seid);
+       i40e_dbg_dump_eth_stats(pf, &veb->stats);
+}
+
+/**
+ * i40e_dbg_dump_veb_all - dumps all known veb's stats
+ * @pf: the i40e_pf created in command write
+ **/
+static void i40e_dbg_dump_veb_all(struct i40e_pf *pf)
+{
+       struct i40e_veb *veb;
+       int i;
+
+       for (i = 0; i < I40E_MAX_VEB; i++) {
+               veb = pf->veb[i];
+               if (veb)
+                       i40e_dbg_dump_veb_seid(pf, veb->seid);
+       }
+}
+
+#define I40E_MAX_DEBUG_OUT_BUFFER (4096*4)
+/**
+ * i40e_dbg_command_write - write into command datum
+ * @filp: the opened file
+ * @buffer: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ **/
+static ssize_t i40e_dbg_command_write(struct file *filp,
+                                     const char __user *buffer,
+                                     size_t count, loff_t *ppos)
+{
+       struct i40e_pf *pf = filp->private_data;
+       int bytes_not_copied;
+       struct i40e_vsi *vsi;
+       u8 *print_buf_start;
+       u8 *print_buf;
+       char *cmd_buf;
+       int vsi_seid;
+       int veb_seid;
+       int cnt;
+
+       /* don't allow partial writes */
+       if (*ppos != 0)
+               return 0;
+
+       cmd_buf = kzalloc(count + 1, GFP_KERNEL);
+       if (!cmd_buf)
+               return count;
+       bytes_not_copied = copy_from_user(cmd_buf, buffer, count);
+       if (bytes_not_copied < 0)
+               return bytes_not_copied;
+       if (bytes_not_copied > 0)
+               count -= bytes_not_copied;
+       cmd_buf[count] = '\0';
+
+       print_buf_start = kzalloc(I40E_MAX_DEBUG_OUT_BUFFER, GFP_KERNEL);
+       if (!print_buf_start)
+               goto command_write_done;
+       print_buf = print_buf_start;
+
+       if (strncmp(cmd_buf, "add vsi", 7) == 0) {
+               vsi_seid = -1;
+               cnt = sscanf(&cmd_buf[7], "%i", &vsi_seid);
+               if (cnt == 0) {
+                       /* default to PF VSI */
+                       vsi_seid = pf->vsi[pf->lan_vsi]->seid;
+               } else if (vsi_seid < 0) {
+                       dev_info(&pf->pdev->dev, "add VSI %d: bad vsi seid\n",
+                                vsi_seid);
+                       goto command_write_done;
+               }
+
+               vsi = i40e_vsi_setup(pf, I40E_VSI_VMDQ2, vsi_seid, 0);
+               if (vsi)
+                       dev_info(&pf->pdev->dev, "added VSI %d to relay %d\n",
+                                vsi->seid, vsi->uplink_seid);
+               else
+                       dev_info(&pf->pdev->dev, "'%s' failed\n", cmd_buf);
+
+       } else if (strncmp(cmd_buf, "del vsi", 7) == 0) {
+               sscanf(&cmd_buf[7], "%i", &vsi_seid);
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev, "del VSI %d: seid not found\n",
+                                vsi_seid);
+                       goto command_write_done;
+               }
+
+               dev_info(&pf->pdev->dev, "deleting VSI %d\n", vsi_seid);
+               i40e_vsi_release(vsi);
+
+       } else if (strncmp(cmd_buf, "add relay", 9) == 0) {
+               struct i40e_veb *veb;
+               int uplink_seid, i;
+
+               cnt = sscanf(&cmd_buf[9], "%i %i", &uplink_seid, &vsi_seid);
+               if (cnt != 2) {
+                       dev_info(&pf->pdev->dev,
+                                "add relay: bad command string, cnt=%d\n",
+                                cnt);
+                       goto command_write_done;
+               } else if (uplink_seid < 0) {
+                       dev_info(&pf->pdev->dev,
+                                "add relay %d: bad uplink seid\n",
+                                uplink_seid);
+                       goto command_write_done;
+               }
+
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "add relay: vsi VSI %d not found\n", vsi_seid);
+                       goto command_write_done;
+               }
+
+               for (i = 0; i < I40E_MAX_VEB; i++)
+                       if (pf->veb[i] && pf->veb[i]->seid == uplink_seid)
+                               break;
+               if (i >= I40E_MAX_VEB && uplink_seid != 0 &&
+                   uplink_seid != pf->mac_seid) {
+                       dev_info(&pf->pdev->dev,
+                                "add relay: relay uplink %d not found\n",
+                                uplink_seid);
+                       goto command_write_done;
+               }
+
+               veb = i40e_veb_setup(pf, 0, uplink_seid, vsi_seid,
+                                    vsi->tc_config.enabled_tc);
+               if (veb)
+                       dev_info(&pf->pdev->dev, "added relay %d\n", veb->seid);
+               else
+                       dev_info(&pf->pdev->dev, "add relay failed\n");
+
+       } else if (strncmp(cmd_buf, "del relay", 9) == 0) {
+               int i;
+               cnt = sscanf(&cmd_buf[9], "%i", &veb_seid);
+               if (cnt != 1) {
+                       dev_info(&pf->pdev->dev,
+                                "del relay: bad command string, cnt=%d\n",
+                                cnt);
+                       goto command_write_done;
+               } else if (veb_seid < 0) {
+                       dev_info(&pf->pdev->dev,
+                                "del relay %d: bad relay seid\n", veb_seid);
+                       goto command_write_done;
+               }
+
+               /* find the veb */
+               for (i = 0; i < I40E_MAX_VEB; i++)
+                       if (pf->veb[i] && pf->veb[i]->seid == veb_seid)
+                               break;
+               if (i >= I40E_MAX_VEB) {
+                       dev_info(&pf->pdev->dev,
+                                "del relay: relay %d not found\n", veb_seid);
+                       goto command_write_done;
+               }
+
+               dev_info(&pf->pdev->dev, "deleting relay %d\n", veb_seid);
+               i40e_veb_release(pf->veb[i]);
+
+       } else if (strncmp(cmd_buf, "add macaddr", 11) == 0) {
+               u8 ma[6];
+               int vlan = 0;
+               struct i40e_mac_filter *f;
+               int ret;
+
+               cnt = sscanf(&cmd_buf[11],
+                            "%i %hhx:%hhx:%hhx:%hhx:%hhx:%hhx %i",
+                            &vsi_seid,
+                            &ma[0], &ma[1], &ma[2], &ma[3], &ma[4], &ma[5],
+                            &vlan);
+               if (cnt == 7) {
+                       vlan = 0;
+               } else if (cnt != 8) {
+                       dev_info(&pf->pdev->dev,
+                                "add macaddr: bad command string, cnt=%d\n",
+                                cnt);
+                       goto command_write_done;
+               }
+
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "add macaddr: VSI %d not found\n", vsi_seid);
+                       goto command_write_done;
+               }
+
+               f = i40e_add_filter(vsi, ma, vlan, false, false);
+               ret = i40e_sync_vsi_filters(vsi);
+               if (f && !ret)
+                       dev_info(&pf->pdev->dev,
+                                "add macaddr: %pM vlan=%d added to VSI %d\n",
+                                ma, vlan, vsi_seid);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "add macaddr: %pM vlan=%d to VSI %d failed, f=%p ret=%d\n",
+                                ma, vlan, vsi_seid, f, ret);
+
+       } else if (strncmp(cmd_buf, "del macaddr", 11) == 0) {
+               u8 ma[6];
+               int vlan = 0;
+               int ret;
+
+               cnt = sscanf(&cmd_buf[11],
+                            "%i %hhx:%hhx:%hhx:%hhx:%hhx:%hhx %i",
+                            &vsi_seid,
+                            &ma[0], &ma[1], &ma[2], &ma[3], &ma[4], &ma[5],
+                            &vlan);
+               if (cnt == 7) {
+                       vlan = 0;
+               } else if (cnt != 8) {
+                       dev_info(&pf->pdev->dev,
+                                "del macaddr: bad command string, cnt=%d\n",
+                                cnt);
+                       goto command_write_done;
+               }
+
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "del macaddr: VSI %d not found\n", vsi_seid);
+                       goto command_write_done;
+               }
+
+               i40e_del_filter(vsi, ma, vlan, false, false);
+               ret = i40e_sync_vsi_filters(vsi);
+               if (!ret)
+                       dev_info(&pf->pdev->dev,
+                                "del macaddr: %pM vlan=%d removed from VSI %d\n",
+                                ma, vlan, vsi_seid);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "del macaddr: %pM vlan=%d from VSI %d failed, ret=%d\n",
+                                ma, vlan, vsi_seid, ret);
+
+       } else if (strncmp(cmd_buf, "add pvid", 8) == 0) {
+               int v;
+               u16 vid;
+               i40e_status ret;
+
+               cnt = sscanf(&cmd_buf[8], "%i %u", &vsi_seid, &v);
+               if (cnt != 2) {
+                       dev_info(&pf->pdev->dev,
+                                "add pvid: bad command string, cnt=%d\n", cnt);
+                       goto command_write_done;
+               }
+
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev, "add pvid: VSI %d not found\n",
+                                vsi_seid);
+                       goto command_write_done;
+               }
+
+               vid = (unsigned)v;
+               ret = i40e_vsi_add_pvid(vsi, vid);
+               if (!ret)
+                       dev_info(&pf->pdev->dev,
+                                "add pvid: %d added to VSI %d\n",
+                                vid, vsi_seid);
+               else
+                       dev_info(&pf->pdev->dev,
+                                "add pvid: %d to VSI %d failed, ret=%d\n",
+                                vid, vsi_seid, ret);
+
+       } else if (strncmp(cmd_buf, "del pvid", 8) == 0) {
+
+               cnt = sscanf(&cmd_buf[8], "%i", &vsi_seid);
+               if (cnt != 1) {
+                       dev_info(&pf->pdev->dev,
+                                "del pvid: bad command string, cnt=%d\n",
+                                cnt);
+                       goto command_write_done;
+               }
+
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "del pvid: VSI %d not found\n", vsi_seid);
+                       goto command_write_done;
+               }
+
+               i40e_vsi_remove_pvid(vsi);
+               dev_info(&pf->pdev->dev,
+                        "del pvid: removed from VSI %d\n", vsi_seid);
+
+       } else if (strncmp(cmd_buf, "dump", 4) == 0) {
+               if (strncmp(&cmd_buf[5], "switch", 6) == 0) {
+                       i40e_fetch_switch_configuration(pf, true);
+               } else if (strncmp(&cmd_buf[5], "vsi", 3) == 0) {
+                       cnt = sscanf(&cmd_buf[8], "%i", &vsi_seid);
+                       if (cnt > 0)
+                               i40e_dbg_dump_vsi_seid(pf, vsi_seid);
+                       else
+                               i40e_dbg_dump_vsi_no_seid(pf);
+               } else if (strncmp(&cmd_buf[5], "veb", 3) == 0) {
+                       cnt = sscanf(&cmd_buf[8], "%i", &vsi_seid);
+                       if (cnt > 0)
+                               i40e_dbg_dump_veb_seid(pf, vsi_seid);
+                       else
+                               i40e_dbg_dump_veb_all(pf);
+               } else if (strncmp(&cmd_buf[5], "desc", 4) == 0) {
+                       int ring_id, desc_n;
+                       if (strncmp(&cmd_buf[10], "rx", 2) == 0) {
+                               cnt = sscanf(&cmd_buf[12], "%i %i %i",
+                                            &vsi_seid, &ring_id, &desc_n);
+                               i40e_dbg_dump_desc(cnt, vsi_seid, ring_id,
+                                                  desc_n, pf, true);
+                       } else if (strncmp(&cmd_buf[10], "tx", 2)
+                                       == 0) {
+                               cnt = sscanf(&cmd_buf[12], "%i %i %i",
+                                            &vsi_seid, &ring_id, &desc_n);
+                               i40e_dbg_dump_desc(cnt, vsi_seid, ring_id,
+                                                  desc_n, pf, false);
+                       } else if (strncmp(&cmd_buf[10], "aq", 2) == 0) {
+                               i40e_dbg_dump_aq_desc(pf);
+                       } else {
+                               dev_info(&pf->pdev->dev,
+                                        "dump desc tx <vsi_seid> <ring_id> [<desc_n>]\n");
+                               dev_info(&pf->pdev->dev,
+                                        "dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
+                               dev_info(&pf->pdev->dev, "dump desc aq\n");
+                       }
+               } else if (strncmp(&cmd_buf[5], "stats", 5) == 0) {
+                       dev_info(&pf->pdev->dev, "pf stats:\n");
+                       i40e_dbg_dump_stats(pf, &pf->stats);
+                       dev_info(&pf->pdev->dev, "pf stats_offsets:\n");
+                       i40e_dbg_dump_stats(pf, &pf->stats_offsets);
+               } else if (strncmp(&cmd_buf[5], "reset stats", 11) == 0) {
+                       dev_info(&pf->pdev->dev,
+                                "core reset count: %d\n", pf->corer_count);
+                       dev_info(&pf->pdev->dev,
+                                "global reset count: %d\n", pf->globr_count);
+                       dev_info(&pf->pdev->dev,
+                                "emp reset count: %d\n", pf->empr_count);
+                       dev_info(&pf->pdev->dev,
+                                "pf reset count: %d\n", pf->pfr_count);
+               } else if (strncmp(&cmd_buf[5], "port", 4) == 0) {
+                       struct i40e_aqc_query_port_ets_config_resp *bw_data;
+                       struct i40e_dcbx_config *cfg =
+                                               &pf->hw.local_dcbx_config;
+                       struct i40e_dcbx_config *r_cfg =
+                                               &pf->hw.remote_dcbx_config;
+                       int i, ret;
+
+                       bw_data = kzalloc(sizeof(
+                                   struct i40e_aqc_query_port_ets_config_resp),
+                                         GFP_KERNEL);
+                       if (!bw_data) {
+                               ret = -ENOMEM;
+                               goto command_write_done;
+                       }
+
+                       ret = i40e_aq_query_port_ets_config(&pf->hw,
+                                                           pf->mac_seid,
+                                                           bw_data, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Query Port ETS Config AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               kfree(bw_data);
+                               bw_data = NULL;
+                               goto command_write_done;
+                       }
+                       dev_info(&pf->pdev->dev,
+                                "port bw: tc_valid=0x%x tc_strict_prio=0x%x, tc_bw_max=0x%04x,0x%04x\n",
+                                bw_data->tc_valid_bits,
+                                bw_data->tc_strict_priority_bits,
+                                le16_to_cpu(bw_data->tc_bw_max[0]),
+                                le16_to_cpu(bw_data->tc_bw_max[1]));
+                       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                               dev_info(&pf->pdev->dev, "port bw: tc_bw_share=%d tc_bw_limit=%d\n",
+                                        bw_data->tc_bw_share_credits[i],
+                                        le16_to_cpu(bw_data->tc_bw_limits[i]));
+                       }
+
+                       kfree(bw_data);
+                       bw_data = NULL;
+
+                       dev_info(&pf->pdev->dev,
+                                "port ets_cfg: willing=%d cbs=%d, maxtcs=%d\n",
+                                cfg->etscfg.willing, cfg->etscfg.cbs,
+                                cfg->etscfg.maxtcs);
+                       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                               dev_info(&pf->pdev->dev, "port ets_cfg: %d prio_tc=%d tcbw=%d tctsa=%d\n",
+                                        i, cfg->etscfg.prioritytable[i],
+                                        cfg->etscfg.tcbwtable[i],
+                                        cfg->etscfg.tsatable[i]);
+                       }
+                       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                               dev_info(&pf->pdev->dev, "port ets_rec: %d prio_tc=%d tcbw=%d tctsa=%d\n",
+                                        i, cfg->etsrec.prioritytable[i],
+                                        cfg->etsrec.tcbwtable[i],
+                                        cfg->etsrec.tsatable[i]);
+                       }
+                       dev_info(&pf->pdev->dev,
+                                "port pfc_cfg: willing=%d mbc=%d, pfccap=%d pfcenable=0x%x\n",
+                                cfg->pfc.willing, cfg->pfc.mbc,
+                                cfg->pfc.pfccap, cfg->pfc.pfcenable);
+                       dev_info(&pf->pdev->dev,
+                                "port app_table: num_apps=%d\n", cfg->numapps);
+                       for (i = 0; i < cfg->numapps; i++) {
+                               dev_info(&pf->pdev->dev, "port app_table: %d prio=%d selector=%d protocol=0x%x\n",
+                                        i, cfg->app[i].priority,
+                                        cfg->app[i].selector,
+                                        cfg->app[i].protocolid);
+                       }
+                       /* Peer TLV DCBX data */
+                       dev_info(&pf->pdev->dev,
+                                "remote port ets_cfg: willing=%d cbs=%d, maxtcs=%d\n",
+                                r_cfg->etscfg.willing,
+                                r_cfg->etscfg.cbs, r_cfg->etscfg.maxtcs);
+                       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                               dev_info(&pf->pdev->dev, "remote port ets_cfg: %d prio_tc=%d tcbw=%d tctsa=%d\n",
+                                        i, r_cfg->etscfg.prioritytable[i],
+                                        r_cfg->etscfg.tcbwtable[i],
+                                        r_cfg->etscfg.tsatable[i]);
+                       }
+                       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                               dev_info(&pf->pdev->dev, "remote port ets_rec: %d prio_tc=%d tcbw=%d tctsa=%d\n",
+                                        i, r_cfg->etsrec.prioritytable[i],
+                                        r_cfg->etsrec.tcbwtable[i],
+                                        r_cfg->etsrec.tsatable[i]);
+                       }
+                       dev_info(&pf->pdev->dev,
+                                "remote port pfc_cfg: willing=%d mbc=%d, pfccap=%d pfcenable=0x%x\n",
+                                r_cfg->pfc.willing,
+                                r_cfg->pfc.mbc,
+                                r_cfg->pfc.pfccap,
+                                r_cfg->pfc.pfcenable);
+                       dev_info(&pf->pdev->dev,
+                                "remote port app_table: num_apps=%d\n",
+                                r_cfg->numapps);
+                       for (i = 0; i < r_cfg->numapps; i++) {
+                               dev_info(&pf->pdev->dev, "remote port app_table: %d prio=%d selector=%d protocol=0x%x\n",
+                                        i, r_cfg->app[i].priority,
+                                        r_cfg->app[i].selector,
+                                        r_cfg->app[i].protocolid);
+                       }
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "dump desc tx <vsi_seid> <ring_id> [<desc_n>], dump desc rx <vsi_seid> <ring_id> [<desc_n>],\n");
+                       dev_info(&pf->pdev->dev, "dump switch, dump vsi [seid] or\n");
+                       dev_info(&pf->pdev->dev, "dump stats\n");
+                       dev_info(&pf->pdev->dev, "dump reset stats\n");
+                       dev_info(&pf->pdev->dev, "dump port\n");
+                       dev_info(&pf->pdev->dev,
+                                "dump debug fwdata <cluster_id> <table_id> <index>\n");
+               }
+
+       } else if (strncmp(cmd_buf, "msg_enable", 10) == 0) {
+               u32 level;
+               cnt = sscanf(&cmd_buf[10], "%i", &level);
+               if (cnt) {
+                       if (I40E_DEBUG_USER & level) {
+                               pf->hw.debug_mask = level;
+                               dev_info(&pf->pdev->dev,
+                                        "set hw.debug_mask = 0x%08x\n",
+                                        pf->hw.debug_mask);
+                       }
+                       pf->msg_enable = level;
+                       dev_info(&pf->pdev->dev, "set msg_enable = 0x%08x\n",
+                                pf->msg_enable);
+               } else {
+                       dev_info(&pf->pdev->dev, "msg_enable = 0x%08x\n",
+                                pf->msg_enable);
+               }
+       } else if (strncmp(cmd_buf, "pfr", 3) == 0) {
+               dev_info(&pf->pdev->dev, "forcing PFR\n");
+               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+
+       } else if (strncmp(cmd_buf, "corer", 5) == 0) {
+               dev_info(&pf->pdev->dev, "forcing CoreR\n");
+               i40e_do_reset(pf, (1 << __I40E_CORE_RESET_REQUESTED));
+
+       } else if (strncmp(cmd_buf, "globr", 5) == 0) {
+               dev_info(&pf->pdev->dev, "forcing GlobR\n");
+               i40e_do_reset(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED));
+
+       } else if (strncmp(cmd_buf, "read", 4) == 0) {
+               u32 address;
+               u32 value;
+               cnt = sscanf(&cmd_buf[4], "%x", &address);
+               if (cnt != 1) {
+                       dev_info(&pf->pdev->dev, "read <reg>\n");
+                       goto command_write_done;
+               }
+
+               /* check the range on address */
+               if (address >= I40E_MAX_REGISTER) {
+                       dev_info(&pf->pdev->dev, "read reg address 0x%08x too large\n",
+                                address);
+                       goto command_write_done;
+               }
+
+               value = rd32(&pf->hw, address);
+               dev_info(&pf->pdev->dev, "read: 0x%08x = 0x%08x\n",
+                        address, value);
+
+       } else if (strncmp(cmd_buf, "write", 5) == 0) {
+               u32 address, value;
+               cnt = sscanf(&cmd_buf[5], "%x %x", &address, &value);
+               if (cnt != 2) {
+                       dev_info(&pf->pdev->dev, "write <reg> <value>\n");
+                       goto command_write_done;
+               }
+
+               /* check the range on address */
+               if (address >= I40E_MAX_REGISTER) {
+                       dev_info(&pf->pdev->dev, "write reg address 0x%08x too large\n",
+                                address);
+                       goto command_write_done;
+               }
+               wr32(&pf->hw, address, value);
+               value = rd32(&pf->hw, address);
+               dev_info(&pf->pdev->dev, "write: 0x%08x = 0x%08x\n",
+                        address, value);
+       } else if (strncmp(cmd_buf, "clear_stats", 11) == 0) {
+               if (strncmp(&cmd_buf[12], "vsi", 3) == 0) {
+                       cnt = sscanf(&cmd_buf[15], "%d", &vsi_seid);
+                       if (cnt == 0) {
+                               int i;
+                               for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+                                       i40e_vsi_reset_stats(pf->vsi[i]);
+                               dev_info(&pf->pdev->dev, "vsi clear stats called for all vsi's\n");
+                       } else if (cnt == 1) {
+                               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+                               if (!vsi) {
+                                       dev_info(&pf->pdev->dev,
+                                                "clear_stats vsi: bad vsi %d\n",
+                                                vsi_seid);
+                                       goto command_write_done;
+                               }
+                               i40e_vsi_reset_stats(vsi);
+                               dev_info(&pf->pdev->dev,
+                                        "vsi clear stats called for vsi %d\n",
+                                        vsi_seid);
+                       } else {
+                               dev_info(&pf->pdev->dev, "clear_stats vsi [seid]\n");
+                       }
+               } else if (strncmp(&cmd_buf[12], "pf", 2) == 0) {
+                       i40e_pf_reset_stats(pf);
+                       dev_info(&pf->pdev->dev, "pf clear stats called\n");
+               } else {
+                       dev_info(&pf->pdev->dev, "clear_stats vsi [seid] or clear_stats pf\n");
+               }
+       } else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) ||
+                  (strncmp(cmd_buf, "rem fd_filter", 13) == 0)) {
+               struct i40e_fdir_data fd_data;
+               int ret;
+               u16 packet_len, i, j = 0;
+               char *asc_packet;
+               bool add = false;
+
+               asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+                                    GFP_KERNEL);
+               if (!asc_packet)
+                       goto command_write_done;
+
+               fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+                                            GFP_KERNEL);
+
+               if (!fd_data.raw_packet) {
+                       kfree(asc_packet);
+                       asc_packet = NULL;
+                       goto command_write_done;
+               }
+
+               if (strncmp(cmd_buf, "add", 3) == 0)
+                       add = true;
+               cnt = sscanf(&cmd_buf[13],
+                            "%hx %2hhx %2hhx %hx %2hhx %2hhx %hx %x %hd %512s",
+                            &fd_data.q_index,
+                            &fd_data.flex_off, &fd_data.pctype,
+                            &fd_data.dest_vsi, &fd_data.dest_ctl,
+                            &fd_data.fd_status, &fd_data.cnt_index,
+                            &fd_data.fd_id, &packet_len, asc_packet);
+               if (cnt != 10) {
+                       dev_info(&pf->pdev->dev,
+                                "program fd_filter: bad command string, cnt=%d\n",
+                                cnt);
+                       kfree(asc_packet);
+                       asc_packet = NULL;
+                       kfree(fd_data.raw_packet);
+                       goto command_write_done;
+               }
+
+               /* fix packet length if user entered 0 */
+               if (packet_len == 0)
+                       packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP;
+
+               /* make sure to check the max as well */
+               packet_len = min_t(u16,
+                                  packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP);
+
+               dev_info(&pf->pdev->dev, "FD raw packet:\n");
+               for (i = 0; i < packet_len; i++) {
+                       sscanf(&asc_packet[j], "%2hhx ",
+                              &fd_data.raw_packet[i]);
+                       j += 3;
+                       snprintf(print_buf, 3, "%02x ", fd_data.raw_packet[i]);
+                       print_buf += 3;
+                       if ((i % 16) == 15) {
+                               snprintf(print_buf, 1, "\n");
+                               print_buf++;
+                       }
+               }
+               dev_info(&pf->pdev->dev, "%s\n", print_buf_start);
+               ret = i40e_program_fdir_filter(&fd_data, pf, add);
+               if (!ret) {
+                       dev_info(&pf->pdev->dev, "Filter command send Status : Success\n");
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed %d\n", ret);
+               }
+               kfree(fd_data.raw_packet);
+               fd_data.raw_packet = NULL;
+               kfree(asc_packet);
+               asc_packet = NULL;
+       } else if (strncmp(cmd_buf, "lldp", 4) == 0) {
+               if (strncmp(&cmd_buf[5], "stop", 4) == 0) {
+                       int ret;
+                       ret = i40e_aq_stop_lldp(&pf->hw, false, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Stop LLDP AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               goto command_write_done;
+                       }
+               } else if (strncmp(&cmd_buf[5], "start", 5) == 0) {
+                       int ret;
+                       ret = i40e_aq_start_lldp(&pf->hw, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Start LLDP AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               goto command_write_done;
+                       }
+               } else if (strncmp(&cmd_buf[5],
+                          "get local", 9) == 0) {
+                       int ret, i;
+                       u8 *buff;
+                       u16 llen, rlen;
+                       buff = kzalloc(I40E_LLDPDU_SIZE, GFP_KERNEL);
+                       if (!buff)
+                               goto command_write_done;
+
+                       ret = i40e_aq_get_lldp_mib(&pf->hw, 0,
+                                                  I40E_AQ_LLDP_MIB_LOCAL,
+                                                  buff, I40E_LLDPDU_SIZE,
+                                                  &llen, &rlen, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Get LLDP MIB (local) AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               kfree(buff);
+                               buff = NULL;
+                               goto command_write_done;
+                       }
+                       dev_info(&pf->pdev->dev,
+                                "Get LLDP MIB (local) AQ buffer written back:\n");
+                       for (i = 0; i < I40E_LLDPDU_SIZE; i++) {
+                               snprintf(print_buf, 3, "%02x ", buff[i]);
+                               print_buf += 3;
+                               if ((i % 16) == 15) {
+                                       snprintf(print_buf, 1, "\n");
+                                       print_buf++;
+                               }
+                       }
+                       dev_info(&pf->pdev->dev, "%s\n", print_buf_start);
+                       kfree(buff);
+                       buff = NULL;
+               } else if (strncmp(&cmd_buf[5], "get remote", 10) == 0) {
+                       int ret, i;
+                       u8 *buff;
+                       u16 llen, rlen;
+                       buff = kzalloc(I40E_LLDPDU_SIZE, GFP_KERNEL);
+                       if (!buff)
+                               goto command_write_done;
+
+                       ret = i40e_aq_get_lldp_mib(&pf->hw,
+                                       I40E_AQ_LLDP_BRIDGE_TYPE_NEAREST_BRIDGE,
+                                       I40E_AQ_LLDP_MIB_LOCAL,
+                                       buff, I40E_LLDPDU_SIZE,
+                                       &llen, &rlen, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Get LLDP MIB (remote) AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               kfree(buff);
+                               buff = NULL;
+                               goto command_write_done;
+                       }
+                       dev_info(&pf->pdev->dev,
+                                "Get LLDP MIB (remote) AQ buffer written back:\n");
+                       for (i = 0; i < I40E_LLDPDU_SIZE; i++) {
+                               snprintf(print_buf, 3, "%02x ", buff[i]);
+                               print_buf += 3;
+                               if ((i % 16) == 15) {
+                                       snprintf(print_buf, 1, "\n");
+                                       print_buf++;
+                               }
+                       }
+                       dev_info(&pf->pdev->dev, "%s\n", print_buf_start);
+                       kfree(buff);
+                       buff = NULL;
+               } else if (strncmp(&cmd_buf[5], "event on", 8) == 0) {
+                       int ret;
+                       ret = i40e_aq_cfg_lldp_mib_change_event(&pf->hw,
+                                                               true, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Config LLDP MIB Change Event (on) AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               goto command_write_done;
+                       }
+               } else if (strncmp(&cmd_buf[5], "event off", 9) == 0) {
+                       int ret;
+                       ret = i40e_aq_cfg_lldp_mib_change_event(&pf->hw,
+                                                               false, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "Config LLDP MIB Change Event (off) AQ command failed =0x%x\n",
+                                        pf->hw.aq.asq_last_status);
+                               goto command_write_done;
+                       }
+               }
+       } else if (strncmp(cmd_buf, "nvm read", 8) == 0) {
+               u16 buffer_len, i, bytes;
+               u16 module;
+               u32 offset;
+               u16 *buff;
+               int ret;
+
+               cnt = sscanf(&cmd_buf[8], "%hx %x %hx",
+                            &module, &offset, &buffer_len);
+               if (cnt == 0) {
+                       module = 0;
+                       offset = 0;
+                       buffer_len = 0;
+               } else if (cnt == 1) {
+                       offset = 0;
+                       buffer_len = 0;
+               } else if (cnt == 2) {
+                       buffer_len = 0;
+               } else if (cnt > 3) {
+                       dev_info(&pf->pdev->dev,
+                                "nvm read: bad command string, cnt=%d\n", cnt);
+                       goto command_write_done;
+               }
+
+               /* Read at least 512 words */
+               if (buffer_len == 0)
+                       buffer_len = 512;
+
+               bytes = 2 * buffer_len;
+               buff = kzalloc(bytes, GFP_KERNEL);
+               if (!buff)
+                       goto command_write_done;
+
+               ret = i40e_acquire_nvm(&pf->hw, I40E_RESOURCE_READ);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Failed Acquiring NVM resource for read err=%d status=0x%x\n",
+                                ret, pf->hw.aq.asq_last_status);
+                       kfree(buff);
+                       goto command_write_done;
+               }
+
+               ret = i40e_aq_read_nvm(&pf->hw, module, (2 * offset),
+                                      bytes, (u8 *)buff, true, NULL);
+               i40e_release_nvm(&pf->hw);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Read NVM AQ failed err=%d status=0x%x\n",
+                                ret, pf->hw.aq.asq_last_status);
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Read NVM module=0x%x offset=0x%x words=%d\n",
+                                module, offset, buffer_len);
+                       for (i = 0; i < buffer_len; i++) {
+                               if ((i % 16) == 0) {
+                                       snprintf(print_buf, 11, "\n0x%08x: ",
+                                                offset + i);
+                                       print_buf += 11;
+                               }
+                               snprintf(print_buf, 5, "%04x ", buff[i]);
+                               print_buf += 5;
+                       }
+                       dev_info(&pf->pdev->dev, "%s\n", print_buf_start);
+               }
+               kfree(buff);
+               buff = NULL;
+       } else {
+               dev_info(&pf->pdev->dev, "unknown command '%s'\n", cmd_buf);
+               dev_info(&pf->pdev->dev, "available commands\n");
+               dev_info(&pf->pdev->dev, "  add vsi [relay_seid]\n");
+               dev_info(&pf->pdev->dev, "  del vsi [vsi_seid]\n");
+               dev_info(&pf->pdev->dev, "  add relay <uplink_seid> <vsi_seid>\n");
+               dev_info(&pf->pdev->dev, "  del relay <relay_seid>\n");
+               dev_info(&pf->pdev->dev, "  add macaddr <vsi_seid> <aa:bb:cc:dd:ee:ff> [vlan]\n");
+               dev_info(&pf->pdev->dev, "  del macaddr <vsi_seid> <aa:bb:cc:dd:ee:ff> [vlan]\n");
+               dev_info(&pf->pdev->dev, "  add pvid <vsi_seid> <vid>\n");
+               dev_info(&pf->pdev->dev, "  del pvid <vsi_seid>\n");
+               dev_info(&pf->pdev->dev, "  dump switch\n");
+               dev_info(&pf->pdev->dev, "  dump vsi [seid]\n");
+               dev_info(&pf->pdev->dev, "  dump desc tx <vsi_seid> <ring_id> [<desc_n>]\n");
+               dev_info(&pf->pdev->dev, "  dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
+               dev_info(&pf->pdev->dev, "  dump desc aq\n");
+               dev_info(&pf->pdev->dev, "  dump stats\n");
+               dev_info(&pf->pdev->dev, "  dump reset stats\n");
+               dev_info(&pf->pdev->dev, "  msg_enable [level]\n");
+               dev_info(&pf->pdev->dev, "  read <reg>\n");
+               dev_info(&pf->pdev->dev, "  write <reg> <value>\n");
+               dev_info(&pf->pdev->dev, "  clear_stats vsi [seid]\n");
+               dev_info(&pf->pdev->dev, "  clear_stats pf\n");
+               dev_info(&pf->pdev->dev, "  pfr\n");
+               dev_info(&pf->pdev->dev, "  corer\n");
+               dev_info(&pf->pdev->dev, "  globr\n");
+               dev_info(&pf->pdev->dev, "  add fd_filter <dest q_index> <flex_off> <pctype> <dest_vsi> <dest_ctl> <fd_status> <cnt_index> <fd_id> <packet_len> <packet>\n");
+               dev_info(&pf->pdev->dev, "  rem fd_filter <dest q_index> <flex_off> <pctype> <dest_vsi> <dest_ctl> <fd_status> <cnt_index> <fd_id> <packet_len> <packet>\n");
+               dev_info(&pf->pdev->dev, "  lldp start\n");
+               dev_info(&pf->pdev->dev, "  lldp stop\n");
+               dev_info(&pf->pdev->dev, "  lldp get local\n");
+               dev_info(&pf->pdev->dev, "  lldp get remote\n");
+               dev_info(&pf->pdev->dev, "  lldp event on\n");
+               dev_info(&pf->pdev->dev, "  lldp event off\n");
+               dev_info(&pf->pdev->dev, "  nvm read [module] [word_offset] [word_count]\n");
+       }
+
+command_write_done:
+       kfree(cmd_buf);
+       cmd_buf = NULL;
+       kfree(print_buf_start);
+       print_buf = NULL;
+       print_buf_start = NULL;
+       return count;
+}
+
+static const struct file_operations i40e_dbg_command_fops = {
+       .owner = THIS_MODULE,
+       .open =  simple_open,
+       .read =  i40e_dbg_command_read,
+       .write = i40e_dbg_command_write,
+};
+
+/**************************************************************
+ * netdev_ops
+ * The netdev_ops entry in debugfs is for giving the driver commands
+ * to be executed from the netdev operations.
+ **************************************************************/
+static char i40e_dbg_netdev_ops_buf[256] = "hello world";
+
+/**
+ * i40e_dbg_netdev_ops - read for netdev_ops datum
+ * @filp: the opened file
+ * @buffer: where to write the data for the user to read
+ * @count: the size of the user's buffer
+ * @ppos: file position offset
+ **/
+static ssize_t i40e_dbg_netdev_ops_read(struct file *filp, char __user *buffer,
+                                       size_t count, loff_t *ppos)
+{
+       struct i40e_pf *pf = filp->private_data;
+       int bytes_not_copied;
+       int buf_size = 256;
+       char *buf;
+       int len;
+
+       /* don't allow partal reads */
+       if (*ppos != 0)
+               return 0;
+       if (count < buf_size)
+               return -ENOSPC;
+
+       buf = kzalloc(buf_size, GFP_KERNEL);
+       if (!buf)
+               return -ENOSPC;
+
+       len = snprintf(buf, buf_size, "%s: %s\n",
+                      pf->vsi[pf->lan_vsi]->netdev->name,
+                      i40e_dbg_netdev_ops_buf);
+
+       bytes_not_copied = copy_to_user(buffer, buf, len);
+       kfree(buf);
+
+       if (bytes_not_copied < 0)
+               return bytes_not_copied;
+
+       *ppos = len;
+       return len;
+}
+
+/**
+ * i40e_dbg_netdev_ops_write - write into netdev_ops datum
+ * @filp: the opened file
+ * @buffer: where to find the user's data
+ * @count: the length of the user's data
+ * @ppos: file position offset
+ **/
+static ssize_t i40e_dbg_netdev_ops_write(struct file *filp,
+                                        const char __user *buffer,
+                                        size_t count, loff_t *ppos)
+{
+       struct i40e_pf *pf = filp->private_data;
+       int bytes_not_copied;
+       struct i40e_vsi *vsi;
+       int vsi_seid;
+       int i, cnt;
+
+       /* don't allow partial writes */
+       if (*ppos != 0)
+               return 0;
+       if (count >= sizeof(i40e_dbg_netdev_ops_buf))
+               return -ENOSPC;
+
+       memset(i40e_dbg_netdev_ops_buf, 0, sizeof(i40e_dbg_netdev_ops_buf));
+       bytes_not_copied = copy_from_user(i40e_dbg_netdev_ops_buf,
+                                         buffer, count);
+       if (bytes_not_copied < 0)
+               return bytes_not_copied;
+       else if (bytes_not_copied > 0)
+               count -= bytes_not_copied;
+       i40e_dbg_netdev_ops_buf[count] = '\0';
+
+       if (strncmp(i40e_dbg_netdev_ops_buf, "tx_timeout", 10) == 0) {
+               cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i", &vsi_seid);
+               if (cnt != 1) {
+                       dev_info(&pf->pdev->dev, "tx_timeout <vsi_seid>\n");
+                       goto netdev_ops_write_done;
+               }
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "tx_timeout: VSI %d not found\n", vsi_seid);
+                       goto netdev_ops_write_done;
+               }
+               if (rtnl_trylock()) {
+                       vsi->netdev->netdev_ops->ndo_tx_timeout(vsi->netdev);
+                       rtnl_unlock();
+                       dev_info(&pf->pdev->dev, "tx_timeout called\n");
+               } else {
+                       dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+               }
+       } else if (strncmp(i40e_dbg_netdev_ops_buf, "change_mtu", 10) == 0) {
+               int mtu;
+               cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i %i",
+                            &vsi_seid, &mtu);
+               if (cnt != 2) {
+                       dev_info(&pf->pdev->dev, "change_mtu <vsi_seid> <mtu>\n");
+                       goto netdev_ops_write_done;
+               }
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "change_mtu: VSI %d not found\n", vsi_seid);
+                       goto netdev_ops_write_done;
+               }
+               if (rtnl_trylock()) {
+                       vsi->netdev->netdev_ops->ndo_change_mtu(vsi->netdev,
+                                                               mtu);
+                       rtnl_unlock();
+                       dev_info(&pf->pdev->dev, "change_mtu called\n");
+               } else {
+                       dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+               }
+
+       } else if (strncmp(i40e_dbg_netdev_ops_buf, "set_rx_mode", 11) == 0) {
+               cnt = sscanf(&i40e_dbg_netdev_ops_buf[11], "%i", &vsi_seid);
+               if (cnt != 1) {
+                       dev_info(&pf->pdev->dev, "set_rx_mode <vsi_seid>\n");
+                       goto netdev_ops_write_done;
+               }
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev,
+                                "set_rx_mode: VSI %d not found\n", vsi_seid);
+                       goto netdev_ops_write_done;
+               }
+               if (rtnl_trylock()) {
+                       vsi->netdev->netdev_ops->ndo_set_rx_mode(vsi->netdev);
+                       rtnl_unlock();
+                       dev_info(&pf->pdev->dev, "set_rx_mode called\n");
+               } else {
+                       dev_info(&pf->pdev->dev, "Could not acquire RTNL - please try again\n");
+               }
+
+       } else if (strncmp(i40e_dbg_netdev_ops_buf, "napi", 4) == 0) {
+               cnt = sscanf(&i40e_dbg_netdev_ops_buf[4], "%i", &vsi_seid);
+               if (cnt != 1) {
+                       dev_info(&pf->pdev->dev, "napi <vsi_seid>\n");
+                       goto netdev_ops_write_done;
+               }
+               vsi = i40e_dbg_find_vsi(pf, vsi_seid);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev, "napi: VSI %d not found\n",
+                                vsi_seid);
+                       goto netdev_ops_write_done;
+               }
+               for (i = 0; i < vsi->num_q_vectors; i++)
+                       napi_schedule(&vsi->q_vectors[i].napi);
+               dev_info(&pf->pdev->dev, "napi called\n");
+       } else {
+               dev_info(&pf->pdev->dev, "unknown command '%s'\n",
+                        i40e_dbg_netdev_ops_buf);
+               dev_info(&pf->pdev->dev, "available commands\n");
+               dev_info(&pf->pdev->dev, "  tx_timeout <vsi_seid>\n");
+               dev_info(&pf->pdev->dev, "  change_mtu <vsi_seid> <mtu>\n");
+               dev_info(&pf->pdev->dev, "  set_rx_mode <vsi_seid>\n");
+               dev_info(&pf->pdev->dev, "  napi <vsi_seid>\n");
+       }
+netdev_ops_write_done:
+       return count;
+}
+
+static const struct file_operations i40e_dbg_netdev_ops_fops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = i40e_dbg_netdev_ops_read,
+       .write = i40e_dbg_netdev_ops_write,
+};
+
+/**
+ * i40e_dbg_pf_init - setup the debugfs directory for the pf
+ * @pf: the pf that is starting up
+ **/
+void i40e_dbg_pf_init(struct i40e_pf *pf)
+{
+       struct dentry *pfile __attribute__((unused));
+       const char *name = pci_name(pf->pdev);
+
+       pf->i40e_dbg_pf = debugfs_create_dir(name, i40e_dbg_root);
+       if (pf->i40e_dbg_pf) {
+               pfile = debugfs_create_file("command", 0600, pf->i40e_dbg_pf,
+                                           pf, &i40e_dbg_command_fops);
+               pfile = debugfs_create_file("dump", 0600, pf->i40e_dbg_pf, pf,
+                                           &i40e_dbg_dump_fops);
+               pfile = debugfs_create_file("netdev_ops", 0600, pf->i40e_dbg_pf,
+                                           pf, &i40e_dbg_netdev_ops_fops);
+       } else {
+               dev_info(&pf->pdev->dev,
+                        "debugfs entry for %s failed\n", name);
+       }
+}
+
+/**
+ * i40e_dbg_pf_exit - clear out the pf's debugfs entries
+ * @pf: the pf that is stopping
+ **/
+void i40e_dbg_pf_exit(struct i40e_pf *pf)
+{
+       debugfs_remove_recursive(pf->i40e_dbg_pf);
+       pf->i40e_dbg_pf = NULL;
+
+       kfree(i40e_dbg_dump_buf);
+       i40e_dbg_dump_buf = NULL;
+}
+
+/**
+ * i40e_dbg_init - start up debugfs for the driver
+ **/
+void i40e_dbg_init(void)
+{
+       i40e_dbg_root = debugfs_create_dir(i40e_driver_name, NULL);
+       if (!i40e_dbg_root)
+               pr_info("init of debugfs failed\n");
+}
+
+/**
+ * i40e_dbg_exit - clean out the driver's debugfs entries
+ **/
+void i40e_dbg_exit(void)
+{
+       debugfs_remove_recursive(i40e_dbg_root);
+       i40e_dbg_root = NULL;
+}
+
+#endif /* CONFIG_DEBUG_FS */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c
new file mode 100644 (file)
index 0000000..de25514
--- /dev/null
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e_diag.h"
+#include "i40e_prototype.h"
+
+/**
+ * i40e_diag_reg_pattern_test
+ * @hw: pointer to the hw struct
+ * @reg: reg to be tested
+ * @mask: bits to be touched
+ **/
+static i40e_status i40e_diag_reg_pattern_test(struct i40e_hw *hw,
+                                                       u32 reg, u32 mask)
+{
+       const u32 patterns[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF};
+       u32 pat, val, orig_val;
+       int i;
+
+       orig_val = rd32(hw, reg);
+       for (i = 0; i < ARRAY_SIZE(patterns); i++) {
+               pat = patterns[i];
+               wr32(hw, reg, (pat & mask));
+               val = rd32(hw, reg);
+               if ((val & mask) != (pat & mask)) {
+                       i40e_debug(hw, I40E_DEBUG_DIAG,
+                                  "%s: reg pattern test failed - reg 0x%08x pat 0x%08x val 0x%08x\n",
+                                  __func__, reg, pat, val);
+                       return I40E_ERR_DIAG_TEST_FAILED;
+               }
+       }
+
+       wr32(hw, reg, orig_val);
+       val = rd32(hw, reg);
+       if (val != orig_val) {
+               i40e_debug(hw, I40E_DEBUG_DIAG,
+                          "%s: reg restore test failed - reg 0x%08x orig_val 0x%08x val 0x%08x\n",
+                          __func__, reg, orig_val, val);
+               return I40E_ERR_DIAG_TEST_FAILED;
+       }
+
+       return 0;
+}
+
+struct i40e_diag_reg_test_info i40e_reg_list[] = {
+       /* offset               mask         elements   stride */
+       {I40E_QTX_CTL(0),       0x0000FFBF,  64, I40E_QTX_CTL(1) - I40E_QTX_CTL(0)},
+       {I40E_PFINT_ITR0(0),    0x00000FFF,   3, I40E_PFINT_ITR0(1) - I40E_PFINT_ITR0(0)},
+       {I40E_PFINT_ITRN(0, 0), 0x00000FFF,  64, I40E_PFINT_ITRN(0, 1) - I40E_PFINT_ITRN(0, 0)},
+       {I40E_PFINT_ITRN(1, 0), 0x00000FFF,  64, I40E_PFINT_ITRN(1, 1) - I40E_PFINT_ITRN(1, 0)},
+       {I40E_PFINT_ITRN(2, 0), 0x00000FFF,  64, I40E_PFINT_ITRN(2, 1) - I40E_PFINT_ITRN(2, 0)},
+       {I40E_PFINT_STAT_CTL0,  0x0000000C,   1, 0},
+       {I40E_PFINT_LNKLST0,    0x00001FFF,   1, 0},
+       {I40E_PFINT_LNKLSTN(0), 0x000007FF, 511, I40E_PFINT_LNKLSTN(1) - I40E_PFINT_LNKLSTN(0)},
+       {I40E_QINT_TQCTL(0),    0x000000FF, I40E_QINT_TQCTL_MAX_INDEX + 1, I40E_QINT_TQCTL(1) - I40E_QINT_TQCTL(0)},
+       {I40E_QINT_RQCTL(0),    0x000000FF, I40E_QINT_RQCTL_MAX_INDEX + 1, I40E_QINT_RQCTL(1) - I40E_QINT_RQCTL(0)},
+       {I40E_PFINT_ICR0_ENA,   0xF7F20000,   1, 0},
+       { 0 }
+};
+
+/**
+ * i40e_diag_reg_test
+ * @hw: pointer to the hw struct
+ *
+ * Perform registers diagnostic test
+ **/
+i40e_status i40e_diag_reg_test(struct i40e_hw *hw)
+{
+       i40e_status ret_code = 0;
+       u32 reg, mask;
+       u32 i, j;
+
+       for (i = 0; (i40e_reg_list[i].offset != 0) && !ret_code; i++) {
+               mask = i40e_reg_list[i].mask;
+               for (j = 0; (j < i40e_reg_list[i].elements) && !ret_code; j++) {
+                       reg = i40e_reg_list[i].offset +
+                             (j * i40e_reg_list[i].stride);
+                       ret_code = i40e_diag_reg_pattern_test(hw, reg, mask);
+               }
+       }
+
+       return ret_code;
+}
+
+/**
+ * i40e_diag_eeprom_test
+ * @hw: pointer to the hw struct
+ *
+ * Perform EEPROM diagnostic test
+ **/
+i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw)
+{
+       i40e_status ret_code;
+       u16 reg_val;
+
+       /* read NVM control word and if NVM valid, validate EEPROM checksum*/
+       ret_code = i40e_read_nvm_word(hw, I40E_SR_NVM_CONTROL_WORD, &reg_val);
+       if ((!ret_code) &&
+           ((reg_val & I40E_SR_CONTROL_WORD_1_MASK) ==
+            (0x01 << I40E_SR_CONTROL_WORD_1_SHIFT))) {
+               ret_code = i40e_validate_nvm_checksum(hw, NULL);
+       } else {
+               ret_code = I40E_ERR_DIAG_TEST_FAILED;
+       }
+
+       return ret_code;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.h b/drivers/net/ethernet/intel/i40e/i40e_diag.h
new file mode 100644 (file)
index 0000000..3d98277
--- /dev/null
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_DIAG_H_
+#define _I40E_DIAG_H_
+
+#include "i40e_type.h"
+
+enum i40e_lb_mode {
+       I40E_LB_MODE_NONE = 0,
+       I40E_LB_MODE_PHY_LOCAL,
+       I40E_LB_MODE_PHY_REMOTE,
+       I40E_LB_MODE_MAC_LOCAL,
+};
+
+struct i40e_diag_reg_test_info {
+       u32 offset;     /* the base register */
+       u32 mask;       /* bits that can be tested */
+       u32 elements;   /* number of elements if array */
+       u32 stride;     /* bytes between each element */
+};
+
+extern struct i40e_diag_reg_test_info i40e_reg_list[];
+
+i40e_status i40e_diag_reg_test(struct i40e_hw *hw);
+i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw);
+
+#endif /* _I40E_DIAG_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
new file mode 100644 (file)
index 0000000..9a76b8c
--- /dev/null
@@ -0,0 +1,1449 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+/* ethtool support for i40e */
+
+#include "i40e.h"
+#include "i40e_diag.h"
+
+struct i40e_stats {
+       char stat_string[ETH_GSTRING_LEN];
+       int sizeof_stat;
+       int stat_offset;
+};
+
+#define I40E_STAT(_type, _name, _stat) { \
+       .stat_string = _name, \
+       .sizeof_stat = FIELD_SIZEOF(_type, _stat), \
+       .stat_offset = offsetof(_type, _stat) \
+}
+#define I40E_NETDEV_STAT(_net_stat) \
+               I40E_STAT(struct net_device_stats, #_net_stat, _net_stat)
+#define I40E_PF_STAT(_name, _stat) \
+               I40E_STAT(struct i40e_pf, _name, _stat)
+#define I40E_VSI_STAT(_name, _stat) \
+               I40E_STAT(struct i40e_vsi, _name, _stat)
+
+static const struct i40e_stats i40e_gstrings_net_stats[] = {
+       I40E_NETDEV_STAT(rx_packets),
+       I40E_NETDEV_STAT(tx_packets),
+       I40E_NETDEV_STAT(rx_bytes),
+       I40E_NETDEV_STAT(tx_bytes),
+       I40E_NETDEV_STAT(rx_errors),
+       I40E_NETDEV_STAT(tx_errors),
+       I40E_NETDEV_STAT(rx_dropped),
+       I40E_NETDEV_STAT(tx_dropped),
+       I40E_NETDEV_STAT(multicast),
+       I40E_NETDEV_STAT(collisions),
+       I40E_NETDEV_STAT(rx_length_errors),
+       I40E_NETDEV_STAT(rx_crc_errors),
+};
+
+/* These PF_STATs might look like duplicates of some NETDEV_STATs,
+ * but they are separate.  This device supports Virtualization, and
+ * as such might have several netdevs supporting VMDq and FCoE going
+ * through a single port.  The NETDEV_STATs are for individual netdevs
+ * seen at the top of the stack, and the PF_STATs are for the physical
+ * function at the bottom of the stack hosting those netdevs.
+ *
+ * The PF_STATs are appended to the netdev stats only when ethtool -S
+ * is queried on the base PF netdev, not on the VMDq or FCoE netdev.
+ */
+static struct i40e_stats i40e_gstrings_stats[] = {
+       I40E_PF_STAT("rx_bytes", stats.eth.rx_bytes),
+       I40E_PF_STAT("tx_bytes", stats.eth.tx_bytes),
+       I40E_PF_STAT("rx_errors", stats.eth.rx_errors),
+       I40E_PF_STAT("tx_errors", stats.eth.tx_errors),
+       I40E_PF_STAT("rx_dropped", stats.eth.rx_discards),
+       I40E_PF_STAT("tx_dropped", stats.eth.tx_discards),
+       I40E_PF_STAT("tx_dropped_link_down", stats.tx_dropped_link_down),
+       I40E_PF_STAT("crc_errors", stats.crc_errors),
+       I40E_PF_STAT("illegal_bytes", stats.illegal_bytes),
+       I40E_PF_STAT("mac_local_faults", stats.mac_local_faults),
+       I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults),
+       I40E_PF_STAT("rx_length_errors", stats.rx_length_errors),
+       I40E_PF_STAT("link_xon_rx", stats.link_xon_rx),
+       I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx),
+       I40E_PF_STAT("link_xon_tx", stats.link_xon_tx),
+       I40E_PF_STAT("link_xoff_tx", stats.link_xoff_tx),
+       I40E_PF_STAT("rx_size_64", stats.rx_size_64),
+       I40E_PF_STAT("rx_size_127", stats.rx_size_127),
+       I40E_PF_STAT("rx_size_255", stats.rx_size_255),
+       I40E_PF_STAT("rx_size_511", stats.rx_size_511),
+       I40E_PF_STAT("rx_size_1023", stats.rx_size_1023),
+       I40E_PF_STAT("rx_size_1522", stats.rx_size_1522),
+       I40E_PF_STAT("rx_size_big", stats.rx_size_big),
+       I40E_PF_STAT("tx_size_64", stats.tx_size_64),
+       I40E_PF_STAT("tx_size_127", stats.tx_size_127),
+       I40E_PF_STAT("tx_size_255", stats.tx_size_255),
+       I40E_PF_STAT("tx_size_511", stats.tx_size_511),
+       I40E_PF_STAT("tx_size_1023", stats.tx_size_1023),
+       I40E_PF_STAT("tx_size_1522", stats.tx_size_1522),
+       I40E_PF_STAT("tx_size_big", stats.tx_size_big),
+       I40E_PF_STAT("rx_undersize", stats.rx_undersize),
+       I40E_PF_STAT("rx_fragments", stats.rx_fragments),
+       I40E_PF_STAT("rx_oversize", stats.rx_oversize),
+       I40E_PF_STAT("rx_jabber", stats.rx_jabber),
+       I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests),
+};
+
+#define I40E_QUEUE_STATS_LEN(n) \
+  ((((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs + \
+    ((struct i40e_netdev_priv *)netdev_priv((n)))->vsi->num_queue_pairs) * 2)
+#define I40E_GLOBAL_STATS_LEN  ARRAY_SIZE(i40e_gstrings_stats)
+#define I40E_NETDEV_STATS_LEN   ARRAY_SIZE(i40e_gstrings_net_stats)
+#define I40E_VSI_STATS_LEN(n)   (I40E_NETDEV_STATS_LEN + \
+                                I40E_QUEUE_STATS_LEN((n)))
+#define I40E_PFC_STATS_LEN ( \
+               (FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_rx) + \
+                FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_rx) + \
+                FIELD_SIZEOF(struct i40e_pf, stats.priority_xoff_tx) + \
+                FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_tx) + \
+                FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_2_xoff)) \
+                / sizeof(u64))
+#define I40E_PF_STATS_LEN(n)   (I40E_GLOBAL_STATS_LEN + \
+                                I40E_PFC_STATS_LEN + \
+                                I40E_VSI_STATS_LEN((n)))
+
+enum i40e_ethtool_test_id {
+       I40E_ETH_TEST_REG = 0,
+       I40E_ETH_TEST_EEPROM,
+       I40E_ETH_TEST_INTR,
+       I40E_ETH_TEST_LOOPBACK,
+       I40E_ETH_TEST_LINK,
+};
+
+static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = {
+       "Register test  (offline)",
+       "Eeprom test    (offline)",
+       "Interrupt test (offline)",
+       "Loopback test  (offline)",
+       "Link test   (on/offline)"
+};
+
+#define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN)
+
+/**
+ * i40e_get_settings - Get Link Speed and Duplex settings
+ * @netdev: network interface device structure
+ * @ecmd: ethtool command
+ *
+ * Reports speed/duplex settings based on media_type
+ **/
+static int i40e_get_settings(struct net_device *netdev,
+                            struct ethtool_cmd *ecmd)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_link_status *hw_link_info = &hw->phy.link_info;
+       bool link_up = hw_link_info->link_info & I40E_AQ_LINK_UP;
+       u32 link_speed = hw_link_info->link_speed;
+
+       /* hardware is either in 40G mode or 10G mode
+        * NOTE: this section initializes supported and advertising
+        */
+       switch (hw_link_info->phy_type) {
+       case I40E_PHY_TYPE_40GBASE_CR4:
+       case I40E_PHY_TYPE_40GBASE_CR4_CU:
+               ecmd->supported = SUPPORTED_40000baseCR4_Full;
+               ecmd->advertising = ADVERTISED_40000baseCR4_Full;
+               break;
+       case I40E_PHY_TYPE_40GBASE_KR4:
+               ecmd->supported = SUPPORTED_40000baseKR4_Full;
+               ecmd->advertising = ADVERTISED_40000baseKR4_Full;
+               break;
+       case I40E_PHY_TYPE_40GBASE_SR4:
+               ecmd->supported = SUPPORTED_40000baseSR4_Full;
+               ecmd->advertising = ADVERTISED_40000baseSR4_Full;
+               break;
+       case I40E_PHY_TYPE_40GBASE_LR4:
+               ecmd->supported = SUPPORTED_40000baseLR4_Full;
+               ecmd->advertising = ADVERTISED_40000baseLR4_Full;
+               break;
+       case I40E_PHY_TYPE_10GBASE_KX4:
+               ecmd->supported = SUPPORTED_10000baseKX4_Full;
+               ecmd->advertising = ADVERTISED_10000baseKX4_Full;
+               break;
+       case I40E_PHY_TYPE_10GBASE_KR:
+               ecmd->supported = SUPPORTED_10000baseKR_Full;
+               ecmd->advertising = ADVERTISED_10000baseKR_Full;
+               break;
+       case I40E_PHY_TYPE_10GBASE_T:
+       default:
+               ecmd->supported = SUPPORTED_10000baseT_Full;
+               ecmd->advertising = ADVERTISED_10000baseT_Full;
+               break;
+       }
+
+       /* for now just say autoneg all the time */
+       ecmd->supported |= SUPPORTED_Autoneg;
+
+       if (hw->phy.media_type == I40E_MEDIA_TYPE_BACKPLANE) {
+               ecmd->supported |= SUPPORTED_Backplane;
+               ecmd->advertising |= ADVERTISED_Backplane;
+               ecmd->port = PORT_NONE;
+       } else if (hw->phy.media_type == I40E_MEDIA_TYPE_BASET) {
+               ecmd->supported |= SUPPORTED_TP;
+               ecmd->advertising |= ADVERTISED_TP;
+               ecmd->port = PORT_TP;
+       } else {
+               ecmd->supported |= SUPPORTED_FIBRE;
+               ecmd->advertising |= ADVERTISED_FIBRE;
+               ecmd->port = PORT_FIBRE;
+       }
+
+       ecmd->transceiver = XCVR_EXTERNAL;
+
+       if (link_up) {
+               switch (link_speed) {
+               case I40E_LINK_SPEED_40GB:
+                       /* need a SPEED_40000 in ethtool.h */
+                       ethtool_cmd_speed_set(ecmd, 40000);
+                       break;
+               case I40E_LINK_SPEED_10GB:
+                       ethtool_cmd_speed_set(ecmd, SPEED_10000);
+                       break;
+               default:
+                       break;
+               }
+               ecmd->duplex = DUPLEX_FULL;
+       } else {
+               ethtool_cmd_speed_set(ecmd, SPEED_UNKNOWN);
+               ecmd->duplex = DUPLEX_UNKNOWN;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_get_pauseparam -  Get Flow Control status
+ * Return tx/rx-pause status
+ **/
+static void i40e_get_pauseparam(struct net_device *netdev,
+                               struct ethtool_pauseparam *pause)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_link_status *hw_link_info = &hw->phy.link_info;
+
+       pause->autoneg =
+               ((hw_link_info->an_info & I40E_AQ_AN_COMPLETED) ?
+                 AUTONEG_ENABLE : AUTONEG_DISABLE);
+
+       pause->rx_pause = 0;
+       pause->tx_pause = 0;
+       if (hw_link_info->an_info & I40E_AQ_LINK_PAUSE_RX)
+               pause->rx_pause = 1;
+       if (hw_link_info->an_info & I40E_AQ_LINK_PAUSE_TX)
+               pause->tx_pause = 1;
+}
+
+static u32 i40e_get_msglevel(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+
+       return pf->msg_enable;
+}
+
+static void i40e_set_msglevel(struct net_device *netdev, u32 data)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+
+       if (I40E_DEBUG_USER & data)
+               pf->hw.debug_mask = data;
+       pf->msg_enable = data;
+}
+
+static int i40e_get_regs_len(struct net_device *netdev)
+{
+       int reg_count = 0;
+       int i;
+
+       for (i = 0; i40e_reg_list[i].offset != 0; i++)
+               reg_count += i40e_reg_list[i].elements;
+
+       return reg_count * sizeof(u32);
+}
+
+static void i40e_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
+                         void *p)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u32 *reg_buf = p;
+       int i, j, ri;
+       u32 reg;
+
+       /* Tell ethtool which driver-version-specific regs output we have.
+        *
+        * At some point, if we have ethtool doing special formatting of
+        * this data, it will rely on this version number to know how to
+        * interpret things.  Hence, this needs to be updated if/when the
+        * diags register table is changed.
+        */
+       regs->version = 1;
+
+       /* loop through the diags reg table for what to print */
+       ri = 0;
+       for (i = 0; i40e_reg_list[i].offset != 0; i++) {
+               for (j = 0; j < i40e_reg_list[i].elements; j++) {
+                       reg = i40e_reg_list[i].offset
+                               + (j * i40e_reg_list[i].stride);
+                       reg_buf[ri++] = rd32(hw, reg);
+               }
+       }
+
+}
+
+static int i40e_get_eeprom(struct net_device *netdev,
+                          struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_hw *hw = &np->vsi->back->hw;
+       int first_word, last_word;
+       u16 i, eeprom_len;
+       u16 *eeprom_buff;
+       int ret_val = 0;
+
+       if (eeprom->len == 0)
+               return -EINVAL;
+
+       eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+       eeprom_len = last_word - first_word + 1;
+
+       eeprom_buff = kmalloc(sizeof(u16) * eeprom_len, GFP_KERNEL);
+       if (!eeprom_buff)
+               return -ENOMEM;
+
+       ret_val = i40e_read_nvm_buffer(hw, first_word, &eeprom_len,
+                                          eeprom_buff);
+       if (eeprom_len == 0) {
+               kfree(eeprom_buff);
+               return -EACCES;
+       }
+
+       /* Device's eeprom is always little-endian, word addressable */
+       for (i = 0; i < eeprom_len; i++)
+               le16_to_cpus(&eeprom_buff[i]);
+
+       memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
+       kfree(eeprom_buff);
+
+       return ret_val;
+}
+
+static int i40e_get_eeprom_len(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_hw *hw = &np->vsi->back->hw;
+
+       return hw->nvm.sr_size * 2;
+}
+
+static void i40e_get_drvinfo(struct net_device *netdev,
+                            struct ethtool_drvinfo *drvinfo)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+
+       strlcpy(drvinfo->driver, i40e_driver_name, sizeof(drvinfo->driver));
+       strlcpy(drvinfo->version, i40e_driver_version_str,
+               sizeof(drvinfo->version));
+       strlcpy(drvinfo->fw_version, i40e_fw_version_str(&pf->hw),
+               sizeof(drvinfo->fw_version));
+       strlcpy(drvinfo->bus_info, pci_name(pf->pdev),
+               sizeof(drvinfo->bus_info));
+}
+
+static void i40e_get_ringparam(struct net_device *netdev,
+                              struct ethtool_ringparam *ring)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+
+       ring->rx_max_pending = I40E_MAX_NUM_DESCRIPTORS;
+       ring->tx_max_pending = I40E_MAX_NUM_DESCRIPTORS;
+       ring->rx_mini_max_pending = 0;
+       ring->rx_jumbo_max_pending = 0;
+       ring->rx_pending = vsi->rx_rings[0].count;
+       ring->tx_pending = vsi->tx_rings[0].count;
+       ring->rx_mini_pending = 0;
+       ring->rx_jumbo_pending = 0;
+}
+
+static int i40e_set_ringparam(struct net_device *netdev,
+                             struct ethtool_ringparam *ring)
+{
+       struct i40e_ring *tx_rings = NULL, *rx_rings = NULL;
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       u32 new_rx_count, new_tx_count;
+       int i, err = 0;
+
+       if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
+               return -EINVAL;
+
+       new_tx_count = clamp_t(u32, ring->tx_pending,
+                              I40E_MIN_NUM_DESCRIPTORS,
+                              I40E_MAX_NUM_DESCRIPTORS);
+       new_tx_count = ALIGN(new_tx_count, I40E_REQ_DESCRIPTOR_MULTIPLE);
+
+       new_rx_count = clamp_t(u32, ring->rx_pending,
+                              I40E_MIN_NUM_DESCRIPTORS,
+                              I40E_MAX_NUM_DESCRIPTORS);
+       new_rx_count = ALIGN(new_rx_count, I40E_REQ_DESCRIPTOR_MULTIPLE);
+
+       /* if nothing to do return success */
+       if ((new_tx_count == vsi->tx_rings[0].count) &&
+           (new_rx_count == vsi->rx_rings[0].count))
+               return 0;
+
+       while (test_and_set_bit(__I40E_CONFIG_BUSY, &pf->state))
+               usleep_range(1000, 2000);
+
+       if (!netif_running(vsi->netdev)) {
+               /* simple case - set for the next time the netdev is started */
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       vsi->tx_rings[i].count = new_tx_count;
+                       vsi->rx_rings[i].count = new_rx_count;
+               }
+               goto done;
+       }
+
+       /* We can't just free everything and then setup again,
+        * because the ISRs in MSI-X mode get passed pointers
+        * to the Tx and Rx ring structs.
+        */
+
+       /* alloc updated Tx resources */
+       if (new_tx_count != vsi->tx_rings[0].count) {
+               netdev_info(netdev,
+                           "Changing Tx descriptor count from %d to %d.\n",
+                           vsi->tx_rings[0].count, new_tx_count);
+               tx_rings = kcalloc(vsi->alloc_queue_pairs,
+                                  sizeof(struct i40e_ring), GFP_KERNEL);
+               if (!tx_rings) {
+                       err = -ENOMEM;
+                       goto done;
+               }
+
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       /* clone ring and setup updated count */
+                       tx_rings[i] = vsi->tx_rings[i];
+                       tx_rings[i].count = new_tx_count;
+                       err = i40e_setup_tx_descriptors(&tx_rings[i]);
+                       if (err) {
+                               while (i) {
+                                       i--;
+                                       i40e_free_tx_resources(&tx_rings[i]);
+                               }
+                               kfree(tx_rings);
+                               tx_rings = NULL;
+
+                               goto done;
+                       }
+               }
+       }
+
+       /* alloc updated Rx resources */
+       if (new_rx_count != vsi->rx_rings[0].count) {
+               netdev_info(netdev,
+                           "Changing Rx descriptor count from %d to %d\n",
+                           vsi->rx_rings[0].count, new_rx_count);
+               rx_rings = kcalloc(vsi->alloc_queue_pairs,
+                                  sizeof(struct i40e_ring), GFP_KERNEL);
+               if (!rx_rings) {
+                       err = -ENOMEM;
+                       goto free_tx;
+               }
+
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       /* clone ring and setup updated count */
+                       rx_rings[i] = vsi->rx_rings[i];
+                       rx_rings[i].count = new_rx_count;
+                       err = i40e_setup_rx_descriptors(&rx_rings[i]);
+                       if (err) {
+                               while (i) {
+                                       i--;
+                                       i40e_free_rx_resources(&rx_rings[i]);
+                               }
+                               kfree(rx_rings);
+                               rx_rings = NULL;
+
+                               goto free_tx;
+                       }
+               }
+       }
+
+       /* Bring interface down, copy in the new ring info,
+        * then restore the interface
+        */
+       i40e_down(vsi);
+
+       if (tx_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       i40e_free_tx_resources(&vsi->tx_rings[i]);
+                       vsi->tx_rings[i] = tx_rings[i];
+               }
+               kfree(tx_rings);
+               tx_rings = NULL;
+       }
+
+       if (rx_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       i40e_free_rx_resources(&vsi->rx_rings[i]);
+                       vsi->rx_rings[i] = rx_rings[i];
+               }
+               kfree(rx_rings);
+               rx_rings = NULL;
+       }
+
+       i40e_up(vsi);
+
+free_tx:
+       /* error cleanup if the Rx allocations failed after getting Tx */
+       if (tx_rings) {
+               for (i = 0; i < vsi->num_queue_pairs; i++)
+                       i40e_free_tx_resources(&tx_rings[i]);
+               kfree(tx_rings);
+               tx_rings = NULL;
+       }
+
+done:
+       clear_bit(__I40E_CONFIG_BUSY, &pf->state);
+
+       return err;
+}
+
+static int i40e_get_sset_count(struct net_device *netdev, int sset)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+
+       switch (sset) {
+       case ETH_SS_TEST:
+               return I40E_TEST_LEN;
+       case ETH_SS_STATS:
+               if (vsi == pf->vsi[pf->lan_vsi])
+                       return I40E_PF_STATS_LEN(netdev);
+               else
+                       return I40E_VSI_STATS_LEN(netdev);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static void i40e_get_ethtool_stats(struct net_device *netdev,
+                                  struct ethtool_stats *stats, u64 *data)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       int i = 0;
+       char *p;
+       int j;
+       struct rtnl_link_stats64 *net_stats = i40e_get_vsi_stats_struct(vsi);
+
+       i40e_update_stats(vsi);
+
+       for (j = 0; j < I40E_NETDEV_STATS_LEN; j++) {
+               p = (char *)net_stats + i40e_gstrings_net_stats[j].stat_offset;
+               data[i++] = (i40e_gstrings_net_stats[j].sizeof_stat ==
+                       sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+       }
+       for (j = 0; j < vsi->num_queue_pairs; j++) {
+               data[i++] = vsi->tx_rings[j].tx_stats.packets;
+               data[i++] = vsi->tx_rings[j].tx_stats.bytes;
+       }
+       for (j = 0; j < vsi->num_queue_pairs; j++) {
+               data[i++] = vsi->rx_rings[j].rx_stats.packets;
+               data[i++] = vsi->rx_rings[j].rx_stats.bytes;
+       }
+       if (vsi == pf->vsi[pf->lan_vsi]) {
+               for (j = 0; j < I40E_GLOBAL_STATS_LEN; j++) {
+                       p = (char *)pf + i40e_gstrings_stats[j].stat_offset;
+                       data[i++] = (i40e_gstrings_stats[j].sizeof_stat ==
+                                  sizeof(u64)) ? *(u64 *)p : *(u32 *)p;
+               }
+               for (j = 0; j < I40E_MAX_USER_PRIORITY; j++) {
+                       data[i++] = pf->stats.priority_xon_tx[j];
+                       data[i++] = pf->stats.priority_xoff_tx[j];
+               }
+               for (j = 0; j < I40E_MAX_USER_PRIORITY; j++) {
+                       data[i++] = pf->stats.priority_xon_rx[j];
+                       data[i++] = pf->stats.priority_xoff_rx[j];
+               }
+               for (j = 0; j < I40E_MAX_USER_PRIORITY; j++)
+                       data[i++] = pf->stats.priority_xon_2_xoff[j];
+       }
+}
+
+static void i40e_get_strings(struct net_device *netdev, u32 stringset,
+                            u8 *data)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       char *p = (char *)data;
+       int i;
+
+       switch (stringset) {
+       case ETH_SS_TEST:
+               for (i = 0; i < I40E_TEST_LEN; i++) {
+                       memcpy(data, i40e_gstrings_test[i], ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               break;
+       case ETH_SS_STATS:
+               for (i = 0; i < I40E_NETDEV_STATS_LEN; i++) {
+                       snprintf(p, ETH_GSTRING_LEN, "%s",
+                                i40e_gstrings_net_stats[i].stat_string);
+                       p += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_packets", i);
+                       p += ETH_GSTRING_LEN;
+                       snprintf(p, ETH_GSTRING_LEN, "tx-%u.tx_bytes", i);
+                       p += ETH_GSTRING_LEN;
+               }
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       snprintf(p, ETH_GSTRING_LEN, "rx-%u.rx_packets", i);
+                       p += ETH_GSTRING_LEN;
+                       snprintf(p, ETH_GSTRING_LEN, "rx-%u.rx_bytes", i);
+                       p += ETH_GSTRING_LEN;
+               }
+               if (vsi == pf->vsi[pf->lan_vsi]) {
+                       for (i = 0; i < I40E_GLOBAL_STATS_LEN; i++) {
+                               snprintf(p, ETH_GSTRING_LEN, "port.%s",
+                                        i40e_gstrings_stats[i].stat_string);
+                               p += ETH_GSTRING_LEN;
+                       }
+                       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+                               snprintf(p, ETH_GSTRING_LEN,
+                                        "port.tx_priority_%u_xon", i);
+                               p += ETH_GSTRING_LEN;
+                               snprintf(p, ETH_GSTRING_LEN,
+                                        "port.tx_priority_%u_xoff", i);
+                               p += ETH_GSTRING_LEN;
+                       }
+                       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+                               snprintf(p, ETH_GSTRING_LEN,
+                                        "port.rx_priority_%u_xon", i);
+                               p += ETH_GSTRING_LEN;
+                               snprintf(p, ETH_GSTRING_LEN,
+                                        "port.rx_priority_%u_xoff", i);
+                               p += ETH_GSTRING_LEN;
+                       }
+                       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+                               snprintf(p, ETH_GSTRING_LEN,
+                                        "port.rx_priority_%u_xon_2_xoff", i);
+                               p += ETH_GSTRING_LEN;
+                       }
+               }
+               /* BUG_ON(p - data != I40E_STATS_LEN * ETH_GSTRING_LEN); */
+               break;
+       }
+}
+
+static int i40e_get_ts_info(struct net_device *dev,
+                           struct ethtool_ts_info *info)
+{
+       return ethtool_op_get_ts_info(dev, info);
+}
+
+static int i40e_link_test(struct i40e_pf *pf, u64 *data)
+{
+       if (i40e_get_link_status(&pf->hw))
+               *data = 0;
+       else
+               *data = 1;
+
+       return *data;
+}
+
+static int i40e_reg_test(struct i40e_pf *pf, u64 *data)
+{
+       i40e_status ret;
+
+       ret = i40e_diag_reg_test(&pf->hw);
+       *data = ret;
+
+       return ret;
+}
+
+static int i40e_eeprom_test(struct i40e_pf *pf, u64 *data)
+{
+       i40e_status ret;
+
+       ret = i40e_diag_eeprom_test(&pf->hw);
+       *data = ret;
+
+       return ret;
+}
+
+static int i40e_intr_test(struct i40e_pf *pf, u64 *data)
+{
+       *data = -ENOSYS;
+
+       return *data;
+}
+
+static int i40e_loopback_test(struct i40e_pf *pf, u64 *data)
+{
+       *data = -ENOSYS;
+
+       return *data;
+}
+
+static void i40e_diag_test(struct net_device *netdev,
+                          struct ethtool_test *eth_test, u64 *data)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+
+       set_bit(__I40E_TESTING, &pf->state);
+       if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
+               /* Offline tests */
+
+               netdev_info(netdev, "offline testing starting\n");
+
+               /* Link test performed before hardware reset
+                * so autoneg doesn't interfere with test result
+                */
+               netdev_info(netdev, "link test starting\n");
+               if (i40e_link_test(pf, &data[I40E_ETH_TEST_LINK]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               netdev_info(netdev, "register test starting\n");
+               if (i40e_reg_test(pf, &data[I40E_ETH_TEST_REG]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+               netdev_info(netdev, "eeprom test starting\n");
+               if (i40e_eeprom_test(pf, &data[I40E_ETH_TEST_EEPROM]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+               netdev_info(netdev, "interrupt test starting\n");
+               if (i40e_intr_test(pf, &data[I40E_ETH_TEST_INTR]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+               netdev_info(netdev, "loopback test starting\n");
+               if (i40e_loopback_test(pf, &data[I40E_ETH_TEST_LOOPBACK]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+       } else {
+               netdev_info(netdev, "online test starting\n");
+               /* Online tests */
+               if (i40e_link_test(pf, &data[I40E_ETH_TEST_LINK]))
+                       eth_test->flags |= ETH_TEST_FL_FAILED;
+
+               /* Offline only tests, not run in online; pass by default */
+               data[I40E_ETH_TEST_REG] = 0;
+               data[I40E_ETH_TEST_EEPROM] = 0;
+               data[I40E_ETH_TEST_INTR] = 0;
+               data[I40E_ETH_TEST_LOOPBACK] = 0;
+
+               clear_bit(__I40E_TESTING, &pf->state);
+       }
+}
+
+static void i40e_get_wol(struct net_device *netdev,
+                        struct ethtool_wolinfo *wol)
+{
+       wol->supported = 0;
+       wol->wolopts = 0;
+}
+
+static int i40e_nway_reset(struct net_device *netdev)
+{
+       /* restart autonegotiation */
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status ret = 0;
+
+       ret = i40e_aq_set_link_restart_an(hw, NULL);
+       if (ret) {
+               netdev_info(netdev, "link restart failed, aq_err=%d\n",
+                           pf->hw.aq.asq_last_status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static int i40e_set_phys_id(struct net_device *netdev,
+                           enum ethtool_phys_id_state state)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int blink_freq = 2;
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               pf->led_status = i40e_led_get(hw);
+               return blink_freq;
+       case ETHTOOL_ID_ON:
+               i40e_led_set(hw, 0xF);
+               break;
+       case ETHTOOL_ID_OFF:
+               i40e_led_set(hw, 0x0);
+               break;
+       case ETHTOOL_ID_INACTIVE:
+               i40e_led_set(hw, pf->led_status);
+               break;
+       }
+
+       return 0;
+}
+
+/* NOTE: i40e hardware uses a conversion factor of 2 for Interrupt
+ * Throttle Rate (ITR) ie. ITR(1) = 2us ITR(10) = 20 us, and also
+ * 125us (8000 interrupts per second) == ITR(62)
+ */
+
+static int i40e_get_coalesce(struct net_device *netdev,
+                            struct ethtool_coalesce *ec)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       ec->tx_max_coalesced_frames_irq = vsi->work_limit;
+       ec->rx_max_coalesced_frames_irq = vsi->work_limit;
+
+       if (ITR_IS_DYNAMIC(vsi->rx_itr_setting))
+               ec->rx_coalesce_usecs = 1;
+       else
+               ec->rx_coalesce_usecs = vsi->rx_itr_setting;
+
+       if (ITR_IS_DYNAMIC(vsi->tx_itr_setting))
+               ec->tx_coalesce_usecs = 1;
+       else
+               ec->tx_coalesce_usecs = vsi->tx_itr_setting;
+
+       return 0;
+}
+
+static int i40e_set_coalesce(struct net_device *netdev,
+                            struct ethtool_coalesce *ec)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_q_vector *q_vector;
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u16 vector;
+       int i;
+
+       if (ec->tx_max_coalesced_frames_irq || ec->rx_max_coalesced_frames_irq)
+               vsi->work_limit = ec->tx_max_coalesced_frames_irq;
+
+       switch (ec->rx_coalesce_usecs) {
+       case 0:
+               vsi->rx_itr_setting = 0;
+               break;
+       case 1:
+               vsi->rx_itr_setting = (I40E_ITR_DYNAMIC |
+                                      ITR_REG_TO_USEC(I40E_ITR_RX_DEF));
+               break;
+       default:
+               if ((ec->rx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+                   (ec->rx_coalesce_usecs > (I40E_MAX_ITR << 1)))
+                       return -EINVAL;
+               vsi->rx_itr_setting = ec->rx_coalesce_usecs;
+               break;
+       }
+
+       switch (ec->tx_coalesce_usecs) {
+       case 0:
+               vsi->tx_itr_setting = 0;
+               break;
+       case 1:
+               vsi->tx_itr_setting = (I40E_ITR_DYNAMIC |
+                                      ITR_REG_TO_USEC(I40E_ITR_TX_DEF));
+               break;
+       default:
+               if ((ec->tx_coalesce_usecs < (I40E_MIN_ITR << 1)) ||
+                   (ec->tx_coalesce_usecs > (I40E_MAX_ITR << 1)))
+                       return -EINVAL;
+               vsi->tx_itr_setting = ec->tx_coalesce_usecs;
+               break;
+       }
+
+       vector = vsi->base_vector;
+       q_vector = vsi->q_vectors;
+       for (i = 0; i < vsi->num_q_vectors; i++, vector++, q_vector++) {
+               q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+               wr32(hw, I40E_PFINT_ITRN(0, vector - 1), q_vector->rx.itr);
+               q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+               wr32(hw, I40E_PFINT_ITRN(1, vector - 1), q_vector->tx.itr);
+               i40e_flush(hw);
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_get_rss_hash_opts - Get RSS hash Input Set for each flow type
+ * @pf: pointer to the physical function struct
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the flow is supported, else Invalid Input.
+ **/
+static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd)
+{
+       cmd->data = 0;
+
+       /* Report default options for RSS on i40e */
+       switch (cmd->flow_type) {
+       case TCP_V4_FLOW:
+       case UDP_V4_FLOW:
+               cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+       /* fall through to add IP fields */
+       case SCTP_V4_FLOW:
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case IPV4_FLOW:
+               cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+               break;
+       case TCP_V6_FLOW:
+       case UDP_V6_FLOW:
+               cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
+       /* fall through to add IP fields */
+       case SCTP_V6_FLOW:
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case IPV6_FLOW:
+               cmd->data |= RXH_IP_SRC | RXH_IP_DST;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_get_rxnfc - command to get RX flow classification rules
+ * @netdev: network interface device structure
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the command is supported.
+ **/
+static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
+                         u32 *rule_locs)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       int ret = -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_GRXRINGS:
+               cmd->data = vsi->alloc_queue_pairs;
+               ret = 0;
+               break;
+       case ETHTOOL_GRXFH:
+               ret = i40e_get_rss_hash_opts(pf, cmd);
+               break;
+       case ETHTOOL_GRXCLSRLCNT:
+               ret = 0;
+               break;
+       case ETHTOOL_GRXCLSRULE:
+               ret = 0;
+               break;
+       case ETHTOOL_GRXCLSRLALL:
+               cmd->data = 500;
+               ret = 0;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_set_rss_hash_opt - Enable/Disable flow types for RSS hash
+ * @pf: pointer to the physical function struct
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the flow input set is supported.
+ **/
+static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u64 hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
+                  ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+
+       /* RSS does not support anything other than hashing
+        * to queues on src and dst IPs and ports
+        */
+       if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
+                         RXH_L4_B_0_1 | RXH_L4_B_2_3))
+               return -EINVAL;
+
+       /* We need at least the IP SRC and DEST fields for hashing */
+       if (!(nfc->data & RXH_IP_SRC) ||
+           !(nfc->data & RXH_IP_DST))
+               return -EINVAL;
+
+       switch (nfc->flow_type) {
+       case TCP_V4_FLOW:
+               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+               case 0:
+                       hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case TCP_V6_FLOW:
+               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+               case 0:
+                       hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case UDP_V4_FLOW:
+               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+               case 0:
+                       hena &=
+                       ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4));
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       hena |=
+                       (((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP)  |
+                       ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case UDP_V6_FLOW:
+               switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) {
+               case 0:
+                       hena &=
+                       ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6));
+                       break;
+               case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
+                       hena |=
+                       (((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP)  |
+                       ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6));
+                       break;
+               default:
+                       return -EINVAL;
+               }
+               break;
+       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+       case SCTP_V4_FLOW:
+               if ((nfc->data & RXH_L4_B_0_1) ||
+                   (nfc->data & RXH_L4_B_2_3))
+                       return -EINVAL;
+               hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER);
+               break;
+       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+       case SCTP_V6_FLOW:
+               if ((nfc->data & RXH_L4_B_0_1) ||
+                   (nfc->data & RXH_L4_B_2_3))
+                       return -EINVAL;
+               hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER);
+               break;
+       case IPV4_FLOW:
+               hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4);
+               break;
+       case IPV6_FLOW:
+               hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) |
+                       ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
+       wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
+       i40e_flush(hw);
+
+       return 0;
+}
+
+#define IP_HEADER_OFFSET 14
+/**
+ * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required from the FDir descriptor
+ * @ethtool_rx_flow_spec: the flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi,
+                                  struct i40e_fdir_data *fd_data,
+                                  struct ethtool_rx_flow_spec *fsp, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct udphdr *udp;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       int i;
+
+       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+       udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
+             + sizeof(struct iphdr));
+
+       ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
+       ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
+       udp->source = fsp->h_u.tcp_ip4_spec.psrc;
+       udp->dest = fsp->h_u.tcp_ip4_spec.pdst;
+
+       for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+            i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) {
+               fd_data->pctype = i;
+               ret = i40e_program_fdir_filter(fd_data, pf, add);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+                       err = true;
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+               }
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required from the FDir descriptor
+ * @ethtool_rx_flow_spec: the flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi,
+                                  struct i40e_fdir_data *fd_data,
+                                  struct ethtool_rx_flow_spec *fsp, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct tcphdr *tcp;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+
+       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+       tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET
+             + sizeof(struct iphdr));
+
+       ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst;
+       tcp->dest = fsp->h_u.tcp_ip4_spec.pdst;
+
+       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN;
+       ret = i40e_program_fdir_filter(fd_data, pf, add);
+
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+               err = true;
+       } else {
+               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+       }
+
+       ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src;
+       tcp->source = fsp->h_u.tcp_ip4_spec.psrc;
+
+       fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+
+       ret = i40e_program_fdir_filter(fd_data, pf, add);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                        fd_data->pctype, ret);
+               err = true;
+       } else {
+               dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n",
+                         fd_data->pctype, ret);
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required from the FDir descriptor
+ * @ethtool_rx_flow_spec: the flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi,
+                                   struct i40e_fdir_data *fd_data,
+                                   struct ethtool_rx_flow_spec *fsp, bool add)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for
+ * a specific flow spec
+ * @vsi: pointer to the targeted VSI
+ * @fd_data: the flow director data required for the FDir descriptor
+ * @fsp: the ethtool flow spec
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi,
+                                 struct i40e_fdir_data *fd_data,
+                                 struct ethtool_rx_flow_spec *fsp, bool add)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct iphdr *ip;
+       bool err = false;
+       int ret;
+       int i;
+
+       ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET);
+
+       ip->saddr = fsp->h_u.usr_ip4_spec.ip4src;
+       ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst;
+       ip->protocol = fsp->h_u.usr_ip4_spec.proto;
+
+       for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER;
+            i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) {
+               fd_data->pctype = i;
+               ret = i40e_program_fdir_filter(fd_data, pf, add);
+
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Filter command send failed for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+                       err = true;
+               } else {
+                       dev_info(&pf->pdev->dev,
+                                "Filter OK for PCTYPE %d (ret = %d)\n",
+                                fd_data->pctype, ret);
+               }
+       }
+
+       return err ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for
+ * a specific flow spec based on their protocol
+ * @vsi: pointer to the targeted VSI
+ * @cmd: command to get or set RX flow classification rules
+ * @add: true adds a filter, false removes it
+ *
+ * Returns 0 if the filters were successfully added or removed
+ **/
+static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi,
+                       struct ethtool_rxnfc *cmd, bool add)
+{
+       struct i40e_fdir_data fd_data;
+       int ret = -EINVAL;
+       struct i40e_pf *pf;
+       struct ethtool_rx_flow_spec *fsp =
+               (struct ethtool_rx_flow_spec *)&cmd->fs;
+
+       if (!vsi)
+               return -EINVAL;
+
+       pf = vsi->back;
+
+       if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) &&
+           (fsp->ring_cookie >= vsi->num_queue_pairs))
+               return -EINVAL;
+
+       /* Populate the Flow Director that we have at the moment
+        * and allocate the raw packet buffer for the calling functions
+        */
+       fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP,
+                                    GFP_KERNEL);
+
+       if (!fd_data.raw_packet) {
+               dev_info(&pf->pdev->dev, "Could not allocate memory\n");
+               return -ENOMEM;
+       }
+
+       fd_data.q_index = fsp->ring_cookie;
+       fd_data.flex_off = 0;
+       fd_data.pctype = 0;
+       fd_data.dest_vsi = vsi->id;
+       fd_data.dest_ctl = 0;
+       fd_data.fd_status = 0;
+       fd_data.cnt_index = 0;
+       fd_data.fd_id = 0;
+
+       switch (fsp->flow_type & ~FLOW_EXT) {
+       case TCP_V4_FLOW:
+               ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
+               break;
+       case UDP_V4_FLOW:
+               ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
+               break;
+       case SCTP_V4_FLOW:
+               ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
+               break;
+       case IPV4_FLOW:
+               ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
+               break;
+       case IP_USER_FLOW:
+               switch (fsp->h_u.usr_ip4_spec.proto) {
+               case IPPROTO_TCP:
+                       ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add);
+                       break;
+               case IPPROTO_UDP:
+                       ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add);
+                       break;
+               case IPPROTO_SCTP:
+                       ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add);
+                       break;
+               default:
+                       ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add);
+                       break;
+               }
+               break;
+       default:
+               dev_info(&pf->pdev->dev, "Could not specify spec type\n");
+               ret = -EINVAL;
+       }
+
+       kfree(fd_data.raw_packet);
+       fd_data.raw_packet = NULL;
+
+       return ret;
+}
+/**
+ * i40e_set_rxnfc - command to set RX flow classification rules
+ * @netdev: network interface device structure
+ * @cmd: ethtool rxnfc command
+ *
+ * Returns Success if the command is supported.
+ **/
+static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       int ret = -EOPNOTSUPP;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_SRXFH:
+               ret = i40e_set_rss_hash_opt(pf, cmd);
+               break;
+       case ETHTOOL_SRXCLSRLINS:
+               ret = i40e_add_del_fdir_ethtool(vsi, cmd, true);
+               break;
+       case ETHTOOL_SRXCLSRLDEL:
+               ret = i40e_add_del_fdir_ethtool(vsi, cmd, false);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static const struct ethtool_ops i40e_ethtool_ops = {
+       .get_settings           = i40e_get_settings,
+       .get_drvinfo            = i40e_get_drvinfo,
+       .get_regs_len           = i40e_get_regs_len,
+       .get_regs               = i40e_get_regs,
+       .nway_reset             = i40e_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_wol                = i40e_get_wol,
+       .get_eeprom_len         = i40e_get_eeprom_len,
+       .get_eeprom             = i40e_get_eeprom,
+       .get_ringparam          = i40e_get_ringparam,
+       .set_ringparam          = i40e_set_ringparam,
+       .get_pauseparam         = i40e_get_pauseparam,
+       .get_msglevel           = i40e_get_msglevel,
+       .set_msglevel           = i40e_set_msglevel,
+       .get_rxnfc              = i40e_get_rxnfc,
+       .set_rxnfc              = i40e_set_rxnfc,
+       .self_test              = i40e_diag_test,
+       .get_strings            = i40e_get_strings,
+       .set_phys_id            = i40e_set_phys_id,
+       .get_sset_count         = i40e_get_sset_count,
+       .get_ethtool_stats      = i40e_get_ethtool_stats,
+       .get_coalesce           = i40e_get_coalesce,
+       .set_coalesce           = i40e_set_coalesce,
+       .get_ts_info            = i40e_get_ts_info,
+};
+
+void i40e_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &i40e_ethtool_ops);
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c
new file mode 100644 (file)
index 0000000..901804a
--- /dev/null
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e_osdep.h"
+#include "i40e_register.h"
+#include "i40e_status.h"
+#include "i40e_alloc.h"
+#include "i40e_hmc.h"
+#include "i40e_type.h"
+
+/**
+ * i40e_add_sd_table_entry - Adds a segment descriptor to the table
+ * @hw: pointer to our hw struct
+ * @hmc_info: pointer to the HMC configuration information struct
+ * @sd_index: segment descriptor index to manipulate
+ * @type: what type of segment descriptor we're manipulating
+ * @direct_mode_sz: size to alloc in direct mode
+ **/
+i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw,
+                                             struct i40e_hmc_info *hmc_info,
+                                             u32 sd_index,
+                                             enum i40e_sd_entry_type type,
+                                             u64 direct_mode_sz)
+{
+       enum i40e_memory_type mem_type __attribute__((unused));
+       i40e_status ret_code = 0;
+       struct i40e_hmc_sd_entry *sd_entry;
+       bool dma_mem_alloc_done = false;
+       struct i40e_dma_mem mem;
+       u64 alloc_len;
+
+       if (NULL == hmc_info->sd_table.sd_entry) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_entry\n");
+               goto exit;
+       }
+
+       if (sd_index >= hmc_info->sd_table.sd_cnt) {
+               ret_code = I40E_ERR_INVALID_SD_INDEX;
+               hw_dbg(hw, "i40e_add_sd_table_entry: bad sd_index\n");
+               goto exit;
+       }
+
+       sd_entry = &hmc_info->sd_table.sd_entry[sd_index];
+       if (!sd_entry->valid) {
+               if (I40E_SD_TYPE_PAGED == type) {
+                       mem_type = i40e_mem_pd;
+                       alloc_len = I40E_HMC_PAGED_BP_SIZE;
+               } else {
+                       mem_type = i40e_mem_bp_jumbo;
+                       alloc_len = direct_mode_sz;
+               }
+
+               /* allocate a 4K pd page or 2M backing page */
+               ret_code = i40e_allocate_dma_mem(hw, &mem, mem_type, alloc_len,
+                                                I40E_HMC_PD_BP_BUF_ALIGNMENT);
+               if (ret_code)
+                       goto exit;
+               dma_mem_alloc_done = true;
+               if (I40E_SD_TYPE_PAGED == type) {
+                       ret_code = i40e_allocate_virt_mem(hw,
+                                       &sd_entry->u.pd_table.pd_entry_virt_mem,
+                                       sizeof(struct i40e_hmc_pd_entry) * 512);
+                       if (ret_code)
+                               goto exit;
+                       sd_entry->u.pd_table.pd_entry =
+                               (struct i40e_hmc_pd_entry *)
+                               sd_entry->u.pd_table.pd_entry_virt_mem.va;
+                       memcpy(&sd_entry->u.pd_table.pd_page_addr, &mem,
+                              sizeof(struct i40e_dma_mem));
+               } else {
+                       memcpy(&sd_entry->u.bp.addr, &mem,
+                              sizeof(struct i40e_dma_mem));
+                       sd_entry->u.bp.sd_pd_index = sd_index;
+               }
+               /* initialize the sd entry */
+               hmc_info->sd_table.sd_entry[sd_index].entry_type = type;
+
+               /* increment the ref count */
+               I40E_INC_SD_REFCNT(&hmc_info->sd_table);
+       }
+       /* Increment backing page reference count */
+       if (I40E_SD_TYPE_DIRECT == sd_entry->entry_type)
+               I40E_INC_BP_REFCNT(&sd_entry->u.bp);
+exit:
+       if (ret_code)
+               if (dma_mem_alloc_done)
+                       i40e_free_dma_mem(hw, &mem);
+
+       return ret_code;
+}
+
+/**
+ * i40e_add_pd_table_entry - Adds page descriptor to the specified table
+ * @hw: pointer to our HW structure
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @pd_index: which page descriptor index to manipulate
+ *
+ * This function:
+ *     1. Initializes the pd entry
+ *     2. Adds pd_entry in the pd_table
+ *     3. Mark the entry valid in i40e_hmc_pd_entry structure
+ *     4. Initializes the pd_entry's ref count to 1
+ * assumptions:
+ *     1. The memory for pd should be pinned down, physically contiguous and
+ *        aligned on 4K boundary and zeroed memory.
+ *     2. It should be 4K in size.
+ **/
+i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw,
+                                             struct i40e_hmc_info *hmc_info,
+                                             u32 pd_index)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_pd_table *pd_table;
+       struct i40e_hmc_pd_entry *pd_entry;
+       struct i40e_dma_mem mem;
+       u32 sd_idx, rel_pd_idx;
+       u64 *pd_addr;
+       u64 page_desc;
+
+       if (pd_index / I40E_HMC_PD_CNT_IN_SD >= hmc_info->sd_table.sd_cnt) {
+               ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
+               hw_dbg(hw, "i40e_add_pd_table_entry: bad pd_index\n");
+               goto exit;
+       }
+
+       /* find corresponding sd */
+       sd_idx = (pd_index / I40E_HMC_PD_CNT_IN_SD);
+       if (I40E_SD_TYPE_PAGED !=
+           hmc_info->sd_table.sd_entry[sd_idx].entry_type)
+               goto exit;
+
+       rel_pd_idx = (pd_index % I40E_HMC_PD_CNT_IN_SD);
+       pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
+       pd_entry = &pd_table->pd_entry[rel_pd_idx];
+       if (!pd_entry->valid) {
+               /* allocate a 4K backing page */
+               ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp,
+                                                I40E_HMC_PAGED_BP_SIZE,
+                                                I40E_HMC_PD_BP_BUF_ALIGNMENT);
+               if (ret_code)
+                       goto exit;
+
+               memcpy(&pd_entry->bp.addr, &mem, sizeof(struct i40e_dma_mem));
+               pd_entry->bp.sd_pd_index = pd_index;
+               pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED;
+               /* Set page address and valid bit */
+               page_desc = mem.pa | 0x1;
+
+               pd_addr = (u64 *)pd_table->pd_page_addr.va;
+               pd_addr += rel_pd_idx;
+
+               /* Add the backing page physical address in the pd entry */
+               memcpy(pd_addr, &page_desc, sizeof(u64));
+
+               pd_entry->sd_index = sd_idx;
+               pd_entry->valid = true;
+               I40E_INC_PD_REFCNT(pd_table);
+       }
+       I40E_INC_BP_REFCNT(&pd_entry->bp);
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_remove_pd_bp - remove a backing page from a page descriptor
+ * @hw: pointer to our HW structure
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: the page index
+ * @is_pf: distinguishes a VF from a PF
+ *
+ * This function:
+ *     1. Marks the entry in pd tabe (for paged address mode) or in sd table
+ *        (for direct address mode) invalid.
+ *     2. Write to register PMPDINV to invalidate the backing page in FV cache
+ *     3. Decrement the ref count for the pd _entry
+ * assumptions:
+ *     1. Caller can deallocate the memory used by backing storage after this
+ *        function returns.
+ **/
+i40e_status i40e_remove_pd_bp(struct i40e_hw *hw,
+                                       struct i40e_hmc_info *hmc_info,
+                                       u32 idx, bool is_pf)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_pd_entry *pd_entry;
+       struct i40e_hmc_pd_table *pd_table;
+       struct i40e_hmc_sd_entry *sd_entry;
+       u32 sd_idx, rel_pd_idx;
+       u64 *pd_addr;
+
+       /* calculate index */
+       sd_idx = idx / I40E_HMC_PD_CNT_IN_SD;
+       rel_pd_idx = idx % I40E_HMC_PD_CNT_IN_SD;
+       if (sd_idx >= hmc_info->sd_table.sd_cnt) {
+               ret_code = I40E_ERR_INVALID_PAGE_DESC_INDEX;
+               hw_dbg(hw, "i40e_remove_pd_bp: bad idx\n");
+               goto exit;
+       }
+       sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
+       if (I40E_SD_TYPE_PAGED != sd_entry->entry_type) {
+               ret_code = I40E_ERR_INVALID_SD_TYPE;
+               hw_dbg(hw, "i40e_remove_pd_bp: wrong sd_entry type\n");
+               goto exit;
+       }
+       /* get the entry and decrease its ref counter */
+       pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
+       pd_entry = &pd_table->pd_entry[rel_pd_idx];
+       I40E_DEC_BP_REFCNT(&pd_entry->bp);
+       if (pd_entry->bp.ref_cnt)
+               goto exit;
+
+       /* mark the entry invalid */
+       pd_entry->valid = false;
+       I40E_DEC_PD_REFCNT(pd_table);
+       pd_addr = (u64 *)pd_table->pd_page_addr.va;
+       pd_addr += rel_pd_idx;
+       memset(pd_addr, 0, sizeof(u64));
+       if (is_pf)
+               I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx);
+       else
+               I40E_INVALIDATE_VF_HMC_PD(hw, sd_idx, idx, hmc_info->hmc_fn_id);
+
+       /* free memory here */
+       ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr));
+       if (ret_code)
+               goto exit;
+       if (!pd_table->ref_cnt)
+               i40e_free_virt_mem(hw, &pd_table->pd_entry_virt_mem);
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_prep_remove_sd_bp - Prepares to remove a backing page from a sd entry
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: the page index
+ **/
+i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
+                                            u32 idx)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_sd_entry *sd_entry;
+
+       /* get the entry and decrease its ref counter */
+       sd_entry = &hmc_info->sd_table.sd_entry[idx];
+       I40E_DEC_BP_REFCNT(&sd_entry->u.bp);
+       if (sd_entry->u.bp.ref_cnt) {
+               ret_code = I40E_ERR_NOT_READY;
+               goto exit;
+       }
+       I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
+
+       /* mark the entry invalid */
+       sd_entry->valid = false;
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_remove_sd_bp_new - Removes a backing page from a segment descriptor
+ * @hw: pointer to our hw struct
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: the page index
+ * @is_pf: used to distinguish between VF and PF
+ **/
+i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw,
+                                           struct i40e_hmc_info *hmc_info,
+                                           u32 idx, bool is_pf)
+{
+       struct i40e_hmc_sd_entry *sd_entry;
+       i40e_status ret_code = 0;
+
+       /* get the entry and decrease its ref counter */
+       sd_entry = &hmc_info->sd_table.sd_entry[idx];
+       if (is_pf) {
+               I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT);
+       } else {
+               ret_code = I40E_NOT_SUPPORTED;
+               goto exit;
+       }
+       ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr));
+       if (ret_code)
+               goto exit;
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_prep_remove_pd_page - Prepares to remove a PD page from sd entry.
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: segment descriptor index to find the relevant page descriptor
+ **/
+i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
+                                              u32 idx)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_sd_entry *sd_entry;
+
+       sd_entry = &hmc_info->sd_table.sd_entry[idx];
+
+       if (sd_entry->u.pd_table.ref_cnt) {
+               ret_code = I40E_ERR_NOT_READY;
+               goto exit;
+       }
+
+       /* mark the entry invalid */
+       sd_entry->valid = false;
+
+       I40E_DEC_SD_REFCNT(&hmc_info->sd_table);
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_remove_pd_page_new - Removes a PD page from sd entry.
+ * @hw: pointer to our hw struct
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: segment descriptor index to find the relevant page descriptor
+ * @is_pf: used to distinguish between VF and PF
+ **/
+i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw,
+                                             struct i40e_hmc_info *hmc_info,
+                                             u32 idx, bool is_pf)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_sd_entry *sd_entry;
+
+       sd_entry = &hmc_info->sd_table.sd_entry[idx];
+       if (is_pf) {
+               I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED);
+       } else {
+               ret_code = I40E_NOT_SUPPORTED;
+               goto exit;
+       }
+       /* free memory here */
+       ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr));
+       if (ret_code)
+               goto exit;
+exit:
+       return ret_code;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h
new file mode 100644 (file)
index 0000000..aacd42a
--- /dev/null
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_HMC_H_
+#define _I40E_HMC_H_
+
+#define I40E_HMC_MAX_BP_COUNT 512
+
+/* forward-declare the HW struct for the compiler */
+struct i40e_hw;
+
+#define I40E_HMC_INFO_SIGNATURE                0x484D5347 /* HMSG */
+#define I40E_HMC_PD_CNT_IN_SD          512
+#define I40E_HMC_DIRECT_BP_SIZE                0x200000 /* 2M */
+#define I40E_HMC_PAGED_BP_SIZE         4096
+#define I40E_HMC_PD_BP_BUF_ALIGNMENT   4096
+#define I40E_FIRST_VF_FPM_ID           16
+
+struct i40e_hmc_obj_info {
+       u64 base;       /* base addr in FPM */
+       u32 max_cnt;    /* max count available for this hmc func */
+       u32 cnt;        /* count of objects driver actually wants to create */
+       u64 size;       /* size in bytes of one object */
+};
+
+enum i40e_sd_entry_type {
+       I40E_SD_TYPE_INVALID = 0,
+       I40E_SD_TYPE_PAGED   = 1,
+       I40E_SD_TYPE_DIRECT  = 2
+};
+
+struct i40e_hmc_bp {
+       enum i40e_sd_entry_type entry_type;
+       struct i40e_dma_mem addr; /* populate to be used by hw */
+       u32 sd_pd_index;
+       u32 ref_cnt;
+};
+
+struct i40e_hmc_pd_entry {
+       struct i40e_hmc_bp bp;
+       u32 sd_index;
+       bool valid;
+};
+
+struct i40e_hmc_pd_table {
+       struct i40e_dma_mem pd_page_addr; /* populate to be used by hw */
+       struct i40e_hmc_pd_entry  *pd_entry; /* [512] for sw book keeping */
+       struct i40e_virt_mem pd_entry_virt_mem; /* virt mem for pd_entry */
+
+       u32 ref_cnt;
+       u32 sd_index;
+};
+
+struct i40e_hmc_sd_entry {
+       enum i40e_sd_entry_type entry_type;
+       bool valid;
+
+       union {
+               struct i40e_hmc_pd_table pd_table;
+               struct i40e_hmc_bp bp;
+       } u;
+};
+
+struct i40e_hmc_sd_table {
+       struct i40e_virt_mem addr; /* used to track sd_entry allocations */
+       u32 sd_cnt;
+       u32 ref_cnt;
+       struct i40e_hmc_sd_entry *sd_entry; /* (sd_cnt*512) entries max */
+};
+
+struct i40e_hmc_info {
+       u32 signature;
+       /* equals to pci func num for PF and dynamically allocated for VFs */
+       u8 hmc_fn_id;
+       u16 first_sd_index; /* index of the first available SD */
+
+       /* hmc objects */
+       struct i40e_hmc_obj_info *hmc_obj;
+       struct i40e_virt_mem hmc_obj_virt_mem;
+       struct i40e_hmc_sd_table sd_table;
+};
+
+#define I40E_INC_SD_REFCNT(sd_table)   ((sd_table)->ref_cnt++)
+#define I40E_INC_PD_REFCNT(pd_table)   ((pd_table)->ref_cnt++)
+#define I40E_INC_BP_REFCNT(bp)         ((bp)->ref_cnt++)
+
+#define I40E_DEC_SD_REFCNT(sd_table)   ((sd_table)->ref_cnt--)
+#define I40E_DEC_PD_REFCNT(pd_table)   ((pd_table)->ref_cnt--)
+#define I40E_DEC_BP_REFCNT(bp)         ((bp)->ref_cnt--)
+
+/**
+ * I40E_SET_PF_SD_ENTRY - marks the sd entry as valid in the hardware
+ * @hw: pointer to our hw struct
+ * @pa: pointer to physical address
+ * @sd_index: segment descriptor index
+ * @hmc_fn_id: hmc function id
+ * @type: if sd entry is direct or paged
+ **/
+#define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type)                   \
+{                                                                      \
+       u32 val1, val2, val3;                                           \
+       val1 = (u32)(upper_32_bits(pa));                                \
+       val2 = (u32)(pa) | (I40E_HMC_MAX_BP_COUNT <<                    \
+                I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |              \
+               ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) <<            \
+               I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) |                  \
+               (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT);            \
+       val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);       \
+       wr32((hw), I40E_PFHMC_SDDATAHIGH, val1);                        \
+       wr32((hw), I40E_PFHMC_SDDATALOW, val2);                         \
+       wr32((hw), I40E_PFHMC_SDCMD, val3);                             \
+}
+
+/**
+ * I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware
+ * @hw: pointer to our hw struct
+ * @sd_index: segment descriptor index
+ * @hmc_fn_id: hmc function id
+ * @type: if sd entry is direct or paged
+ **/
+#define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type)                     \
+{                                                                      \
+       u32 val2, val3;                                                 \
+       val2 = (I40E_HMC_MAX_BP_COUNT <<                                \
+               I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) |               \
+               ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) <<            \
+               I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT);                   \
+       val3 = (sd_index) | (1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT);       \
+       wr32((hw), I40E_PFHMC_SDDATAHIGH, 0);                           \
+       wr32((hw), I40E_PFHMC_SDDATALOW, val2);                         \
+       wr32((hw), I40E_PFHMC_SDCMD, val3);                             \
+}
+
+/**
+ * I40E_INVALIDATE_PF_HMC_PD - Invalidates the pd cache in the hardware
+ * @hw: pointer to our hw struct
+ * @sd_idx: segment descriptor index
+ * @pd_idx: page descriptor index
+ * @hmc_fn_id: hmc function id
+ **/
+#define I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx)                  \
+       wr32((hw), I40E_PFHMC_PDINV,                                    \
+           (((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) |             \
+            ((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)))
+
+#define I40E_INVALIDATE_VF_HMC_PD(hw, sd_idx, pd_idx, hmc_fn_id)          \
+       wr32((hw), I40E_GLHMC_VFPDINV((hmc_fn_id) - I40E_FIRST_VF_FPM_ID), \
+            (((sd_idx) << I40E_PFHMC_PDINV_PMSDIDX_SHIFT) |               \
+             ((pd_idx) << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)))
+
+/**
+ * I40E_FIND_SD_INDEX_LIMIT - finds segment descriptor index limit
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @type: type of HMC resources we're searching
+ * @index: starting index for the object
+ * @cnt: number of objects we're trying to create
+ * @sd_idx: pointer to return index of the segment descriptor in question
+ * @sd_limit: pointer to return the maximum number of segment descriptors
+ *
+ * This function calculates the segment descriptor index and index limit
+ * for the resource defined by i40e_hmc_rsrc_type.
+ **/
+#define I40E_FIND_SD_INDEX_LIMIT(hmc_info, type, index, cnt, sd_idx, sd_limit)\
+{                                                                      \
+       u64 fpm_addr, fpm_limit;                                        \
+       fpm_addr = (hmc_info)->hmc_obj[(type)].base +                   \
+                  (hmc_info)->hmc_obj[(type)].size * (index);          \
+       fpm_limit = fpm_addr + (hmc_info)->hmc_obj[(type)].size * (cnt);\
+       *(sd_idx) = (u32)(fpm_addr / I40E_HMC_DIRECT_BP_SIZE);          \
+       *(sd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_DIRECT_BP_SIZE); \
+       /* add one more to the limit to correct our range */            \
+       *(sd_limit) += 1;                                               \
+}
+
+/**
+ * I40E_FIND_PD_INDEX_LIMIT - finds page descriptor index limit
+ * @hmc_info: pointer to the HMC configuration information struct
+ * @type: HMC resource type we're examining
+ * @idx: starting index for the object
+ * @cnt: number of objects we're trying to create
+ * @pd_index: pointer to return page descriptor index
+ * @pd_limit: pointer to return page descriptor index limit
+ *
+ * Calculates the page descriptor index and index limit for the resource
+ * defined by i40e_hmc_rsrc_type.
+ **/
+#define I40E_FIND_PD_INDEX_LIMIT(hmc_info, type, idx, cnt, pd_index, pd_limit)\
+{                                                                      \
+       u64 fpm_adr, fpm_limit;                                         \
+       fpm_adr = (hmc_info)->hmc_obj[(type)].base +                    \
+                 (hmc_info)->hmc_obj[(type)].size * (idx);             \
+       fpm_limit = fpm_adr + (hmc_info)->hmc_obj[(type)].size * (cnt); \
+       *(pd_index) = (u32)(fpm_adr / I40E_HMC_PAGED_BP_SIZE);          \
+       *(pd_limit) = (u32)((fpm_limit - 1) / I40E_HMC_PAGED_BP_SIZE);  \
+       /* add one more to the limit to correct our range */            \
+       *(pd_limit) += 1;                                               \
+}
+i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw,
+                                             struct i40e_hmc_info *hmc_info,
+                                             u32 sd_index,
+                                             enum i40e_sd_entry_type type,
+                                             u64 direct_mode_sz);
+
+i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw,
+                                             struct i40e_hmc_info *hmc_info,
+                                             u32 pd_index);
+i40e_status i40e_remove_pd_bp(struct i40e_hw *hw,
+                                       struct i40e_hmc_info *hmc_info,
+                                       u32 idx, bool is_pf);
+i40e_status i40e_prep_remove_sd_bp(struct i40e_hmc_info *hmc_info,
+                                            u32 idx);
+i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw,
+                                           struct i40e_hmc_info *hmc_info,
+                                           u32 idx, bool is_pf);
+i40e_status i40e_prep_remove_pd_page(struct i40e_hmc_info *hmc_info,
+                                              u32 idx);
+i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw,
+                                             struct i40e_hmc_info *hmc_info,
+                                             u32 idx, bool is_pf);
+
+#endif /* _I40E_HMC_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c
new file mode 100644 (file)
index 0000000..a695b91
--- /dev/null
@@ -0,0 +1,1006 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e_osdep.h"
+#include "i40e_register.h"
+#include "i40e_type.h"
+#include "i40e_hmc.h"
+#include "i40e_lan_hmc.h"
+#include "i40e_prototype.h"
+
+/* lan specific interface functions */
+
+/**
+ * i40e_align_l2obj_base - aligns base object pointer to 512 bytes
+ * @offset: base address offset needing alignment
+ *
+ * Aligns the layer 2 function private memory so it's 512-byte aligned.
+ **/
+static u64 i40e_align_l2obj_base(u64 offset)
+{
+       u64 aligned_offset = offset;
+
+       if ((offset % I40E_HMC_L2OBJ_BASE_ALIGNMENT) > 0)
+               aligned_offset += (I40E_HMC_L2OBJ_BASE_ALIGNMENT -
+                                  (offset % I40E_HMC_L2OBJ_BASE_ALIGNMENT));
+
+       return aligned_offset;
+}
+
+/**
+ * i40e_calculate_l2fpm_size - calculates layer 2 FPM memory size
+ * @txq_num: number of Tx queues needing backing context
+ * @rxq_num: number of Rx queues needing backing context
+ * @fcoe_cntx_num: amount of FCoE statefull contexts needing backing context
+ * @fcoe_filt_num: number of FCoE filters needing backing context
+ *
+ * Calculates the maximum amount of memory for the function required, based
+ * on the number of resources it must provide context for.
+ **/
+static u64 i40e_calculate_l2fpm_size(u32 txq_num, u32 rxq_num,
+                             u32 fcoe_cntx_num, u32 fcoe_filt_num)
+{
+       u64 fpm_size = 0;
+
+       fpm_size = txq_num * I40E_HMC_OBJ_SIZE_TXQ;
+       fpm_size = i40e_align_l2obj_base(fpm_size);
+
+       fpm_size += (rxq_num * I40E_HMC_OBJ_SIZE_RXQ);
+       fpm_size = i40e_align_l2obj_base(fpm_size);
+
+       fpm_size += (fcoe_cntx_num * I40E_HMC_OBJ_SIZE_FCOE_CNTX);
+       fpm_size = i40e_align_l2obj_base(fpm_size);
+
+       fpm_size += (fcoe_filt_num * I40E_HMC_OBJ_SIZE_FCOE_FILT);
+       fpm_size = i40e_align_l2obj_base(fpm_size);
+
+       return fpm_size;
+}
+
+/**
+ * i40e_init_lan_hmc - initialize i40e_hmc_info struct
+ * @hw: pointer to the HW structure
+ * @txq_num: number of Tx queues needing backing context
+ * @rxq_num: number of Rx queues needing backing context
+ * @fcoe_cntx_num: amount of FCoE statefull contexts needing backing context
+ * @fcoe_filt_num: number of FCoE filters needing backing context
+ *
+ * This function will be called once per physical function initialization.
+ * It will fill out the i40e_hmc_obj_info structure for LAN objects based on
+ * the driver's provided input, as well as information from the HMC itself
+ * loaded from NVRAM.
+ *
+ * Assumptions:
+ *   - HMC Resource Profile has been selected before calling this function.
+ **/
+i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
+                                       u32 rxq_num, u32 fcoe_cntx_num,
+                                       u32 fcoe_filt_num)
+{
+       struct i40e_hmc_obj_info *obj, *full_obj;
+       i40e_status ret_code = 0;
+       u64 l2fpm_size;
+       u32 size_exp;
+
+       hw->hmc.signature = I40E_HMC_INFO_SIGNATURE;
+       hw->hmc.hmc_fn_id = hw->pf_id;
+
+       /* allocate memory for hmc_obj */
+       ret_code = i40e_allocate_virt_mem(hw, &hw->hmc.hmc_obj_virt_mem,
+                       sizeof(struct i40e_hmc_obj_info) * I40E_HMC_LAN_MAX);
+       if (ret_code)
+               goto init_lan_hmc_out;
+       hw->hmc.hmc_obj = (struct i40e_hmc_obj_info *)
+                         hw->hmc.hmc_obj_virt_mem.va;
+
+       /* The full object will be used to create the LAN HMC SD */
+       full_obj = &hw->hmc.hmc_obj[I40E_HMC_LAN_FULL];
+       full_obj->max_cnt = 0;
+       full_obj->cnt = 0;
+       full_obj->base = 0;
+       full_obj->size = 0;
+
+       /* Tx queue context information */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_LAN_TX];
+       obj->max_cnt = rd32(hw, I40E_GLHMC_LANQMAX);
+       obj->cnt = txq_num;
+       obj->base = 0;
+       size_exp = rd32(hw, I40E_GLHMC_LANTXOBJSZ);
+       obj->size = (u64)1 << size_exp;
+
+       /* validate values requested by driver don't exceed HMC capacity */
+       if (txq_num > obj->max_cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+               hw_dbg(hw, "i40e_init_lan_hmc: Tx context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
+                         txq_num, obj->max_cnt, ret_code);
+               goto init_lan_hmc_out;
+       }
+
+       /* aggregate values into the full LAN object for later */
+       full_obj->max_cnt += obj->max_cnt;
+       full_obj->cnt += obj->cnt;
+
+       /* Rx queue context information */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_LAN_RX];
+       obj->max_cnt = rd32(hw, I40E_GLHMC_LANQMAX);
+       obj->cnt = rxq_num;
+       obj->base = hw->hmc.hmc_obj[I40E_HMC_LAN_TX].base +
+                   (hw->hmc.hmc_obj[I40E_HMC_LAN_TX].cnt *
+                    hw->hmc.hmc_obj[I40E_HMC_LAN_TX].size);
+       obj->base = i40e_align_l2obj_base(obj->base);
+       size_exp = rd32(hw, I40E_GLHMC_LANRXOBJSZ);
+       obj->size = (u64)1 << size_exp;
+
+       /* validate values requested by driver don't exceed HMC capacity */
+       if (rxq_num > obj->max_cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+               hw_dbg(hw, "i40e_init_lan_hmc: Rx context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
+                         rxq_num, obj->max_cnt, ret_code);
+               goto init_lan_hmc_out;
+       }
+
+       /* aggregate values into the full LAN object for later */
+       full_obj->max_cnt += obj->max_cnt;
+       full_obj->cnt += obj->cnt;
+
+       /* FCoE context information */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX];
+       obj->max_cnt = rd32(hw, I40E_GLHMC_FCOEMAX);
+       obj->cnt = fcoe_cntx_num;
+       obj->base = hw->hmc.hmc_obj[I40E_HMC_LAN_RX].base +
+                   (hw->hmc.hmc_obj[I40E_HMC_LAN_RX].cnt *
+                    hw->hmc.hmc_obj[I40E_HMC_LAN_RX].size);
+       obj->base = i40e_align_l2obj_base(obj->base);
+       size_exp = rd32(hw, I40E_GLHMC_FCOEDDPOBJSZ);
+       obj->size = (u64)1 << size_exp;
+
+       /* validate values requested by driver don't exceed HMC capacity */
+       if (fcoe_cntx_num > obj->max_cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+               hw_dbg(hw, "i40e_init_lan_hmc: FCoE context: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
+                         fcoe_cntx_num, obj->max_cnt, ret_code);
+               goto init_lan_hmc_out;
+       }
+
+       /* aggregate values into the full LAN object for later */
+       full_obj->max_cnt += obj->max_cnt;
+       full_obj->cnt += obj->cnt;
+
+       /* FCoE filter information */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_FCOE_FILT];
+       obj->max_cnt = rd32(hw, I40E_GLHMC_FCOEFMAX);
+       obj->cnt = fcoe_filt_num;
+       obj->base = hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX].base +
+                   (hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX].cnt *
+                    hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX].size);
+       obj->base = i40e_align_l2obj_base(obj->base);
+       size_exp = rd32(hw, I40E_GLHMC_FCOEFOBJSZ);
+       obj->size = (u64)1 << size_exp;
+
+       /* validate values requested by driver don't exceed HMC capacity */
+       if (fcoe_filt_num > obj->max_cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+               hw_dbg(hw, "i40e_init_lan_hmc: FCoE filter: asks for 0x%x but max allowed is 0x%x, returns error %d\n",
+                         fcoe_filt_num, obj->max_cnt, ret_code);
+               goto init_lan_hmc_out;
+       }
+
+       /* aggregate values into the full LAN object for later */
+       full_obj->max_cnt += obj->max_cnt;
+       full_obj->cnt += obj->cnt;
+
+       hw->hmc.first_sd_index = 0;
+       hw->hmc.sd_table.ref_cnt = 0;
+       l2fpm_size = i40e_calculate_l2fpm_size(txq_num, rxq_num, fcoe_cntx_num,
+                                              fcoe_filt_num);
+       if (NULL == hw->hmc.sd_table.sd_entry) {
+               hw->hmc.sd_table.sd_cnt = (u32)
+                                  (l2fpm_size + I40E_HMC_DIRECT_BP_SIZE - 1) /
+                                  I40E_HMC_DIRECT_BP_SIZE;
+
+               /* allocate the sd_entry members in the sd_table */
+               ret_code = i40e_allocate_virt_mem(hw, &hw->hmc.sd_table.addr,
+                                         (sizeof(struct i40e_hmc_sd_entry) *
+                                         hw->hmc.sd_table.sd_cnt));
+               if (ret_code)
+                       goto init_lan_hmc_out;
+               hw->hmc.sd_table.sd_entry =
+                       (struct i40e_hmc_sd_entry *)hw->hmc.sd_table.addr.va;
+       }
+       /* store in the LAN full object for later */
+       full_obj->size = l2fpm_size;
+
+init_lan_hmc_out:
+       return ret_code;
+}
+
+/**
+ * i40e_remove_pd_page - Remove a page from the page descriptor table
+ * @hw: pointer to the HW structure
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: segment descriptor index to find the relevant page descriptor
+ *
+ * This function:
+ *     1. Marks the entry in pd table (for paged address mode) invalid
+ *     2. write to register PMPDINV to invalidate the backing page in FV cache
+ *     3. Decrement the ref count for  pd_entry
+ * assumptions:
+ *     1. caller can deallocate the memory used by pd after this function
+ *        returns.
+ **/
+static i40e_status i40e_remove_pd_page(struct i40e_hw *hw,
+                                                struct i40e_hmc_info *hmc_info,
+                                                u32 idx)
+{
+       i40e_status ret_code = 0;
+
+       if (!i40e_prep_remove_pd_page(hmc_info, idx))
+               ret_code = i40e_remove_pd_page_new(hw, hmc_info, idx, true);
+
+       return ret_code;
+}
+
+/**
+ * i40e_remove_sd_bp - remove a backing page from a segment descriptor
+ * @hw: pointer to our HW structure
+ * @hmc_info: pointer to the HMC configuration information structure
+ * @idx: the page index
+ *
+ * This function:
+ *     1. Marks the entry in sd table (for direct address mode) invalid
+ *     2. write to register PMSDCMD, PMSDDATALOW(PMSDDATALOW.PMSDVALID set
+ *        to 0) and PMSDDATAHIGH to invalidate the sd page
+ *     3. Decrement the ref count for the sd_entry
+ * assumptions:
+ *     1. caller can deallocate the memory used by backing storage after this
+ *        function returns.
+ **/
+static i40e_status i40e_remove_sd_bp(struct i40e_hw *hw,
+                                              struct i40e_hmc_info *hmc_info,
+                                              u32 idx)
+{
+       i40e_status ret_code = 0;
+
+       if (!i40e_prep_remove_sd_bp(hmc_info, idx))
+               ret_code = i40e_remove_sd_bp_new(hw, hmc_info, idx, true);
+
+       return ret_code;
+}
+
+/**
+ * i40e_create_lan_hmc_object - allocate backing store for hmc objects
+ * @hw: pointer to the HW structure
+ * @info: pointer to i40e_hmc_create_obj_info struct
+ *
+ * This will allocate memory for PDs and backing pages and populate
+ * the sd and pd entries.
+ **/
+static i40e_status i40e_create_lan_hmc_object(struct i40e_hw *hw,
+                               struct i40e_hmc_lan_create_obj_info *info)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_sd_entry *sd_entry;
+       u32 pd_idx1 = 0, pd_lmt1 = 0;
+       u32 pd_idx = 0, pd_lmt = 0;
+       bool pd_error = false;
+       u32 sd_idx, sd_lmt;
+       u64 sd_size;
+       u32 i, j;
+
+       if (NULL == info) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_create_lan_hmc_object: bad info ptr\n");
+               goto exit;
+       }
+       if (NULL == info->hmc_info) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_create_lan_hmc_object: bad hmc_info ptr\n");
+               goto exit;
+       }
+       if (I40E_HMC_INFO_SIGNATURE != info->hmc_info->signature) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_create_lan_hmc_object: bad signature\n");
+               goto exit;
+       }
+
+       if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_INDEX;
+               hw_dbg(hw, "i40e_create_lan_hmc_object: returns error %d\n",
+                         ret_code);
+               goto exit;
+       }
+       if ((info->start_idx + info->count) >
+           info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+               hw_dbg(hw, "i40e_create_lan_hmc_object: returns error %d\n",
+                         ret_code);
+               goto exit;
+       }
+
+       /* find sd index and limit */
+       I40E_FIND_SD_INDEX_LIMIT(info->hmc_info, info->rsrc_type,
+                                info->start_idx, info->count,
+                                &sd_idx, &sd_lmt);
+       if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
+           sd_lmt > info->hmc_info->sd_table.sd_cnt) {
+                       ret_code = I40E_ERR_INVALID_SD_INDEX;
+                       goto exit;
+       }
+       /* find pd index */
+       I40E_FIND_PD_INDEX_LIMIT(info->hmc_info, info->rsrc_type,
+                                info->start_idx, info->count, &pd_idx,
+                                &pd_lmt);
+
+       /* This is to cover for cases where you may not want to have an SD with
+        * the full 2M memory but something smaller. By not filling out any
+        * size, the function will default the SD size to be 2M.
+        */
+       if (info->direct_mode_sz == 0)
+               sd_size = I40E_HMC_DIRECT_BP_SIZE;
+       else
+               sd_size = info->direct_mode_sz;
+
+       /* check if all the sds are valid. If not, allocate a page and
+        * initialize it.
+        */
+       for (j = sd_idx; j < sd_lmt; j++) {
+               /* update the sd table entry */
+               ret_code = i40e_add_sd_table_entry(hw, info->hmc_info, j,
+                                                  info->entry_type,
+                                                  sd_size);
+               if (ret_code)
+                       goto exit_sd_error;
+               sd_entry = &info->hmc_info->sd_table.sd_entry[j];
+               if (I40E_SD_TYPE_PAGED == sd_entry->entry_type) {
+                       /* check if all the pds in this sd are valid. If not,
+                        * allocate a page and initialize it.
+                        */
+
+                       /* find pd_idx and pd_lmt in this sd */
+                       pd_idx1 = max(pd_idx, (j * I40E_HMC_MAX_BP_COUNT));
+                       pd_lmt1 = min(pd_lmt,
+                                     ((j + 1) * I40E_HMC_MAX_BP_COUNT));
+                       for (i = pd_idx1; i < pd_lmt1; i++) {
+                               /* update the pd table entry */
+                               ret_code = i40e_add_pd_table_entry(hw,
+                                                               info->hmc_info,
+                                                               i);
+                               if (ret_code) {
+                                       pd_error = true;
+                                       break;
+                               }
+                       }
+                       if (pd_error) {
+                               /* remove the backing pages from pd_idx1 to i */
+                               while (i && (i > pd_idx1)) {
+                                       i40e_remove_pd_bp(hw, info->hmc_info,
+                                                         (i - 1), true);
+                                       i--;
+                               }
+                       }
+               }
+               if (!sd_entry->valid) {
+                       sd_entry->valid = true;
+                       switch (sd_entry->entry_type) {
+                       case I40E_SD_TYPE_PAGED:
+                               I40E_SET_PF_SD_ENTRY(hw,
+                                       sd_entry->u.pd_table.pd_page_addr.pa,
+                                       j, sd_entry->entry_type);
+                               break;
+                       case I40E_SD_TYPE_DIRECT:
+                               I40E_SET_PF_SD_ENTRY(hw, sd_entry->u.bp.addr.pa,
+                                                    j, sd_entry->entry_type);
+                               break;
+                       default:
+                               ret_code = I40E_ERR_INVALID_SD_TYPE;
+                               goto exit;
+                               break;
+                       }
+               }
+       }
+       goto exit;
+
+exit_sd_error:
+       /* cleanup for sd entries from j to sd_idx */
+       while (j && (j > sd_idx)) {
+               sd_entry = &info->hmc_info->sd_table.sd_entry[j - 1];
+               switch (sd_entry->entry_type) {
+               case I40E_SD_TYPE_PAGED:
+                       pd_idx1 = max(pd_idx,
+                                     ((j - 1) * I40E_HMC_MAX_BP_COUNT));
+                       pd_lmt1 = min(pd_lmt, (j * I40E_HMC_MAX_BP_COUNT));
+                       for (i = pd_idx1; i < pd_lmt1; i++) {
+                               i40e_remove_pd_bp(
+                                       hw,
+                                       info->hmc_info,
+                                       i,
+                                       true);
+                       }
+                       i40e_remove_pd_page(hw, info->hmc_info, (j - 1));
+                       break;
+               case I40E_SD_TYPE_DIRECT:
+                       i40e_remove_sd_bp(hw, info->hmc_info, (j - 1));
+                       break;
+               default:
+                       ret_code = I40E_ERR_INVALID_SD_TYPE;
+                       break;
+               }
+               j--;
+       }
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_configure_lan_hmc - prepare the HMC backing store
+ * @hw: pointer to the hw structure
+ * @model: the model for the layout of the SD/PD tables
+ *
+ * - This function will be called once per physical function initialization.
+ * - This function will be called after i40e_init_lan_hmc() and before
+ *   any LAN/FCoE HMC objects can be created.
+ **/
+i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw,
+                                            enum i40e_hmc_model model)
+{
+       struct i40e_hmc_lan_create_obj_info info;
+       i40e_status ret_code = 0;
+       u8 hmc_fn_id = hw->hmc.hmc_fn_id;
+       struct i40e_hmc_obj_info *obj;
+
+       /* Initialize part of the create object info struct */
+       info.hmc_info = &hw->hmc;
+       info.rsrc_type = I40E_HMC_LAN_FULL;
+       info.start_idx = 0;
+       info.direct_mode_sz = hw->hmc.hmc_obj[I40E_HMC_LAN_FULL].size;
+
+       /* Build the SD entry for the LAN objects */
+       switch (model) {
+       case I40E_HMC_MODEL_DIRECT_PREFERRED:
+       case I40E_HMC_MODEL_DIRECT_ONLY:
+               info.entry_type = I40E_SD_TYPE_DIRECT;
+               /* Make one big object, a single SD */
+               info.count = 1;
+               ret_code = i40e_create_lan_hmc_object(hw, &info);
+               if ((ret_code) &&
+                   (model == I40E_HMC_MODEL_DIRECT_PREFERRED))
+                       goto try_type_paged;
+               else if (ret_code)
+                       goto configure_lan_hmc_out;
+               /* else clause falls through the break */
+               break;
+       case I40E_HMC_MODEL_PAGED_ONLY:
+try_type_paged:
+               info.entry_type = I40E_SD_TYPE_PAGED;
+               /* Make one big object in the PD table */
+               info.count = 1;
+               ret_code = i40e_create_lan_hmc_object(hw, &info);
+               if (ret_code)
+                       goto configure_lan_hmc_out;
+               break;
+       default:
+               /* unsupported type */
+               ret_code = I40E_ERR_INVALID_SD_TYPE;
+               hw_dbg(hw, "i40e_configure_lan_hmc: Unknown SD type: %d\n",
+                         ret_code);
+               goto configure_lan_hmc_out;
+               break;
+       }
+
+       /* Configure and program the FPM registers so objects can be created */
+
+       /* Tx contexts */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_LAN_TX];
+       wr32(hw, I40E_GLHMC_LANTXBASE(hmc_fn_id),
+            (u32)((obj->base & I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK) / 512));
+       wr32(hw, I40E_GLHMC_LANTXCNT(hmc_fn_id), obj->cnt);
+
+       /* Rx contexts */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_LAN_RX];
+       wr32(hw, I40E_GLHMC_LANRXBASE(hmc_fn_id),
+            (u32)((obj->base & I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK) / 512));
+       wr32(hw, I40E_GLHMC_LANRXCNT(hmc_fn_id), obj->cnt);
+
+       /* FCoE contexts */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX];
+       wr32(hw, I40E_GLHMC_FCOEDDPBASE(hmc_fn_id),
+        (u32)((obj->base & I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK) / 512));
+       wr32(hw, I40E_GLHMC_FCOEDDPCNT(hmc_fn_id), obj->cnt);
+
+       /* FCoE filters */
+       obj = &hw->hmc.hmc_obj[I40E_HMC_FCOE_FILT];
+       wr32(hw, I40E_GLHMC_FCOEFBASE(hmc_fn_id),
+            (u32)((obj->base & I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK) / 512));
+       wr32(hw, I40E_GLHMC_FCOEFCNT(hmc_fn_id), obj->cnt);
+
+configure_lan_hmc_out:
+       return ret_code;
+}
+
+/**
+ * i40e_delete_hmc_object - remove hmc objects
+ * @hw: pointer to the HW structure
+ * @info: pointer to i40e_hmc_delete_obj_info struct
+ *
+ * This will de-populate the SDs and PDs.  It frees
+ * the memory for PDS and backing storage.  After this function is returned,
+ * caller should deallocate memory allocated previously for
+ * book-keeping information about PDs and backing storage.
+ **/
+static i40e_status i40e_delete_lan_hmc_object(struct i40e_hw *hw,
+                               struct i40e_hmc_lan_delete_obj_info *info)
+{
+       i40e_status ret_code = 0;
+       struct i40e_hmc_pd_table *pd_table;
+       u32 pd_idx, pd_lmt, rel_pd_idx;
+       u32 sd_idx, sd_lmt;
+       u32 i, j;
+
+       if (NULL == info) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_delete_hmc_object: bad info ptr\n");
+               goto exit;
+       }
+       if (NULL == info->hmc_info) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_delete_hmc_object: bad info->hmc_info ptr\n");
+               goto exit;
+       }
+       if (I40E_HMC_INFO_SIGNATURE != info->hmc_info->signature) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_delete_hmc_object: bad hmc_info->signature\n");
+               goto exit;
+       }
+
+       if (NULL == info->hmc_info->sd_table.sd_entry) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_delete_hmc_object: bad sd_entry\n");
+               goto exit;
+       }
+
+       if (NULL == info->hmc_info->hmc_obj) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_delete_hmc_object: bad hmc_info->hmc_obj\n");
+               goto exit;
+       }
+       if (info->start_idx >= info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_INDEX;
+               hw_dbg(hw, "i40e_delete_hmc_object: returns error %d\n",
+                         ret_code);
+               goto exit;
+       }
+
+       if ((info->start_idx + info->count) >
+           info->hmc_info->hmc_obj[info->rsrc_type].cnt) {
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_COUNT;
+               hw_dbg(hw, "i40e_delete_hmc_object: returns error %d\n",
+                         ret_code);
+               goto exit;
+       }
+
+       I40E_FIND_PD_INDEX_LIMIT(info->hmc_info, info->rsrc_type,
+                                info->start_idx, info->count, &pd_idx,
+                                &pd_lmt);
+
+       for (j = pd_idx; j < pd_lmt; j++) {
+               sd_idx = j / I40E_HMC_PD_CNT_IN_SD;
+
+               if (I40E_SD_TYPE_PAGED !=
+                   info->hmc_info->sd_table.sd_entry[sd_idx].entry_type)
+                       continue;
+
+               rel_pd_idx = j % I40E_HMC_PD_CNT_IN_SD;
+
+               pd_table =
+                       &info->hmc_info->sd_table.sd_entry[sd_idx].u.pd_table;
+               if (pd_table->pd_entry[rel_pd_idx].valid) {
+                       ret_code = i40e_remove_pd_bp(hw, info->hmc_info,
+                                                    j, true);
+                       if (ret_code)
+                               goto exit;
+               }
+       }
+
+       /* find sd index and limit */
+       I40E_FIND_SD_INDEX_LIMIT(info->hmc_info, info->rsrc_type,
+                                info->start_idx, info->count,
+                                &sd_idx, &sd_lmt);
+       if (sd_idx >= info->hmc_info->sd_table.sd_cnt ||
+           sd_lmt > info->hmc_info->sd_table.sd_cnt) {
+               ret_code = I40E_ERR_INVALID_SD_INDEX;
+               goto exit;
+       }
+
+       for (i = sd_idx; i < sd_lmt; i++) {
+               if (!info->hmc_info->sd_table.sd_entry[i].valid)
+                       continue;
+               switch (info->hmc_info->sd_table.sd_entry[i].entry_type) {
+               case I40E_SD_TYPE_DIRECT:
+                       ret_code = i40e_remove_sd_bp(hw, info->hmc_info, i);
+                       if (ret_code)
+                               goto exit;
+                       break;
+               case I40E_SD_TYPE_PAGED:
+                       ret_code = i40e_remove_pd_page(hw, info->hmc_info, i);
+                       if (ret_code)
+                               goto exit;
+                       break;
+               default:
+                       break;
+               }
+       }
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_shutdown_lan_hmc - Remove HMC backing store, free allocated memory
+ * @hw: pointer to the hw structure
+ *
+ * This must be called by drivers as they are shutting down and being
+ * removed from the OS.
+ **/
+i40e_status i40e_shutdown_lan_hmc(struct i40e_hw *hw)
+{
+       struct i40e_hmc_lan_delete_obj_info info;
+       i40e_status ret_code;
+
+       info.hmc_info = &hw->hmc;
+       info.rsrc_type = I40E_HMC_LAN_FULL;
+       info.start_idx = 0;
+       info.count = 1;
+
+       /* delete the object */
+       ret_code = i40e_delete_lan_hmc_object(hw, &info);
+
+       /* free the SD table entry for LAN */
+       i40e_free_virt_mem(hw, &hw->hmc.sd_table.addr);
+       hw->hmc.sd_table.sd_cnt = 0;
+       hw->hmc.sd_table.sd_entry = NULL;
+
+       /* free memory used for hmc_obj */
+       i40e_free_virt_mem(hw, &hw->hmc.hmc_obj_virt_mem);
+       hw->hmc.hmc_obj = NULL;
+
+       return ret_code;
+}
+
+#define I40E_HMC_STORE(_struct, _ele)          \
+       offsetof(struct _struct, _ele),         \
+       FIELD_SIZEOF(struct _struct, _ele)
+
+struct i40e_context_ele {
+       u16 offset;
+       u16 size_of;
+       u16 width;
+       u16 lsb;
+};
+
+/* LAN Tx Queue Context */
+static struct i40e_context_ele i40e_hmc_txq_ce_info[] = {
+                                            /* Field      Width    LSB */
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, head),           13,      0 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, new_context),     1,     30 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, base),           57,     32 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, fc_ena),          1,     89 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, timesync_ena),    1,     90 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, fd_ena),          1,     91 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, alt_vlan_ena),    1,     92 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, cpuid),           8,     96 },
+/* line 1 */
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, thead_wb),       13,  0 + 128 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, head_wb_ena),     1, 32 + 128 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, qlen),           13, 33 + 128 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, tphrdesc_ena),    1, 46 + 128 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, tphrpacket_ena),  1, 47 + 128 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, tphwdesc_ena),    1, 48 + 128 },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, head_wb_addr),   64, 64 + 128 },
+/* line 7 */
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, crc),            32,  0 + (7 * 128) },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, rdylist),        10, 84 + (7 * 128) },
+       {I40E_HMC_STORE(i40e_hmc_obj_txq, rdylist_act),     1, 94 + (7 * 128) },
+       { 0 }
+};
+
+/* LAN Rx Queue Context */
+static struct i40e_context_ele i40e_hmc_rxq_ce_info[] = {
+                                        /* Field      Width    LSB */
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, head),        13,    0   },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, cpuid),        8,    13  },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, base),        57,    32  },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, qlen),        13,    89  },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, dbuff),        7,    102 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, hbuff),        5,    109 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, dtype),        2,    114 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, dsize),        1,    116 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, crcstrip),     1,    117 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, fc_ena),       1,    118 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, l2tsel),       1,    119 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, hsplit_0),     4,    120 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, hsplit_1),     2,    124 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, showiv),       1,    127 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, rxmax),       14,    174 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphrdesc_ena), 1,    193 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphwdesc_ena), 1,    194 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphdata_ena),  1,    195 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, tphhead_ena),  1,    196 },
+       { I40E_HMC_STORE(i40e_hmc_obj_rxq, lrxqthresh),   3,    198 },
+       { 0 }
+};
+
+/**
+ * i40e_clear_hmc_context - zero out the HMC context bits
+ * @hw:       the hardware struct
+ * @context_bytes: pointer to the context bit array (DMA memory)
+ * @hmc_type: the type of HMC resource
+ **/
+static i40e_status i40e_clear_hmc_context(struct i40e_hw *hw,
+                                       u8 *context_bytes,
+                                       enum i40e_hmc_lan_rsrc_type hmc_type)
+{
+       /* clean the bit array */
+       memset(context_bytes, 0, (u32)hw->hmc.hmc_obj[hmc_type].size);
+
+       return 0;
+}
+
+/**
+ * i40e_set_hmc_context - replace HMC context bits
+ * @context_bytes: pointer to the context bit array
+ * @ce_info:  a description of the struct to be filled
+ * @dest:     the struct to be filled
+ **/
+static i40e_status i40e_set_hmc_context(u8 *context_bytes,
+                                       struct i40e_context_ele *ce_info,
+                                       u8 *dest)
+{
+       u16 shift_width;
+       u64 bitfield;
+       u8 hi_byte;
+       u8 hi_mask;
+       u64 t_bits;
+       u64 mask;
+       u8 *p;
+       int f;
+
+       for (f = 0; ce_info[f].width != 0; f++) {
+               /* clear out the field */
+               bitfield = 0;
+
+               /* copy from the next struct field */
+               p = dest + ce_info[f].offset;
+               switch (ce_info[f].size_of) {
+               case 1:
+                       bitfield = *p;
+                       break;
+               case 2:
+                       bitfield = cpu_to_le16(*(u16 *)p);
+                       break;
+               case 4:
+                       bitfield = cpu_to_le32(*(u32 *)p);
+                       break;
+               case 8:
+                       bitfield = cpu_to_le64(*(u64 *)p);
+                       break;
+               }
+
+               /* prepare the bits and mask */
+               shift_width = ce_info[f].lsb % 8;
+               mask = ((u64)1 << ce_info[f].width) - 1;
+
+               /* save upper bytes for special case */
+               hi_mask = (u8)((mask >> 56) & 0xff);
+               hi_byte = (u8)((bitfield >> 56) & 0xff);
+
+               /* shift to correct alignment */
+               mask <<= shift_width;
+               bitfield <<= shift_width;
+
+               /* get the current bits from the target bit string */
+               p = context_bytes + (ce_info[f].lsb / 8);
+               memcpy(&t_bits, p, sizeof(u64));
+
+               t_bits &= ~mask;          /* get the bits not changing */
+               t_bits |= bitfield;       /* add in the new bits */
+
+               /* put it all back */
+               memcpy(p, &t_bits, sizeof(u64));
+
+               /* deal with the special case if needed
+                * example: 62 bit field that starts in bit 5 of first byte
+                *          will overlap 3 bits into byte 9
+                */
+               if ((shift_width + ce_info[f].width) > 64) {
+                       u8 byte;
+
+                       hi_mask >>= (8 - shift_width);
+                       hi_byte >>= (8 - shift_width);
+                       byte = p[8] & ~hi_mask;  /* get the bits not changing */
+                       byte |= hi_byte;         /* add in the new bits */
+                       p[8] = byte;             /* put it back */
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_hmc_get_object_va - retrieves an object's virtual address
+ * @hmc_info: pointer to i40e_hmc_info struct
+ * @object_base: pointer to u64 to get the va
+ * @rsrc_type: the hmc resource type
+ * @obj_idx: hmc object index
+ *
+ * This function retrieves the object's virtual address from the object
+ * base pointer.  This function is used for LAN Queue contexts.
+ **/
+static
+i40e_status i40e_hmc_get_object_va(struct i40e_hmc_info *hmc_info,
+                                       u8 **object_base,
+                                       enum i40e_hmc_lan_rsrc_type rsrc_type,
+                                       u32 obj_idx)
+{
+       u32 obj_offset_in_sd, obj_offset_in_pd;
+       i40e_status ret_code = 0;
+       struct i40e_hmc_sd_entry *sd_entry;
+       struct i40e_hmc_pd_entry *pd_entry;
+       u32 pd_idx, pd_lmt, rel_pd_idx;
+       u64 obj_offset_in_fpm;
+       u32 sd_idx, sd_lmt;
+
+       if (NULL == hmc_info) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_hmc_get_object_va: bad hmc_info ptr\n");
+               goto exit;
+       }
+       if (NULL == hmc_info->hmc_obj) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_hmc_get_object_va: bad hmc_info->hmc_obj ptr\n");
+               goto exit;
+       }
+       if (NULL == object_base) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_hmc_get_object_va: bad object_base ptr\n");
+               goto exit;
+       }
+       if (I40E_HMC_INFO_SIGNATURE != hmc_info->signature) {
+               ret_code = I40E_ERR_BAD_PTR;
+               hw_dbg(hw, "i40e_hmc_get_object_va: bad hmc_info->signature\n");
+               goto exit;
+       }
+       if (obj_idx >= hmc_info->hmc_obj[rsrc_type].cnt) {
+               hw_dbg(hw, "i40e_hmc_get_object_va: returns error %d\n",
+                         ret_code);
+               ret_code = I40E_ERR_INVALID_HMC_OBJ_INDEX;
+               goto exit;
+       }
+       /* find sd index and limit */
+       I40E_FIND_SD_INDEX_LIMIT(hmc_info, rsrc_type, obj_idx, 1,
+                                &sd_idx, &sd_lmt);
+
+       sd_entry = &hmc_info->sd_table.sd_entry[sd_idx];
+       obj_offset_in_fpm = hmc_info->hmc_obj[rsrc_type].base +
+                           hmc_info->hmc_obj[rsrc_type].size * obj_idx;
+
+       if (I40E_SD_TYPE_PAGED == sd_entry->entry_type) {
+               I40E_FIND_PD_INDEX_LIMIT(hmc_info, rsrc_type, obj_idx, 1,
+                                        &pd_idx, &pd_lmt);
+               rel_pd_idx = pd_idx % I40E_HMC_PD_CNT_IN_SD;
+               pd_entry = &sd_entry->u.pd_table.pd_entry[rel_pd_idx];
+               obj_offset_in_pd = (u32)(obj_offset_in_fpm %
+                                        I40E_HMC_PAGED_BP_SIZE);
+               *object_base = (u8 *)pd_entry->bp.addr.va + obj_offset_in_pd;
+       } else {
+               obj_offset_in_sd = (u32)(obj_offset_in_fpm %
+                                        I40E_HMC_DIRECT_BP_SIZE);
+               *object_base = (u8 *)sd_entry->u.bp.addr.va + obj_offset_in_sd;
+       }
+exit:
+       return ret_code;
+}
+
+/**
+ * i40e_clear_lan_tx_queue_context - clear the HMC context for the queue
+ * @hw:    the hardware struct
+ * @queue: the queue we care about
+ **/
+i40e_status i40e_clear_lan_tx_queue_context(struct i40e_hw *hw,
+                                                     u16 queue)
+{
+       i40e_status err;
+       u8 *context_bytes;
+
+       err = i40e_hmc_get_object_va(&hw->hmc, &context_bytes,
+                                    I40E_HMC_LAN_TX, queue);
+       if (err < 0)
+               return err;
+
+       return i40e_clear_hmc_context(hw, context_bytes, I40E_HMC_LAN_TX);
+}
+
+/**
+ * i40e_set_lan_tx_queue_context - set the HMC context for the queue
+ * @hw:    the hardware struct
+ * @queue: the queue we care about
+ * @s:     the struct to be filled
+ **/
+i40e_status i40e_set_lan_tx_queue_context(struct i40e_hw *hw,
+                                                   u16 queue,
+                                                   struct i40e_hmc_obj_txq *s)
+{
+       i40e_status err;
+       u8 *context_bytes;
+
+       err = i40e_hmc_get_object_va(&hw->hmc, &context_bytes,
+                                    I40E_HMC_LAN_TX, queue);
+       if (err < 0)
+               return err;
+
+       return i40e_set_hmc_context(context_bytes,
+                                   i40e_hmc_txq_ce_info, (u8 *)s);
+}
+
+/**
+ * i40e_clear_lan_rx_queue_context - clear the HMC context for the queue
+ * @hw:    the hardware struct
+ * @queue: the queue we care about
+ **/
+i40e_status i40e_clear_lan_rx_queue_context(struct i40e_hw *hw,
+                                                     u16 queue)
+{
+       i40e_status err;
+       u8 *context_bytes;
+
+       err = i40e_hmc_get_object_va(&hw->hmc, &context_bytes,
+                                    I40E_HMC_LAN_RX, queue);
+       if (err < 0)
+               return err;
+
+       return i40e_clear_hmc_context(hw, context_bytes, I40E_HMC_LAN_RX);
+}
+
+/**
+ * i40e_set_lan_rx_queue_context - set the HMC context for the queue
+ * @hw:    the hardware struct
+ * @queue: the queue we care about
+ * @s:     the struct to be filled
+ **/
+i40e_status i40e_set_lan_rx_queue_context(struct i40e_hw *hw,
+                                                   u16 queue,
+                                                   struct i40e_hmc_obj_rxq *s)
+{
+       i40e_status err;
+       u8 *context_bytes;
+
+       err = i40e_hmc_get_object_va(&hw->hmc, &context_bytes,
+                                    I40E_HMC_LAN_RX, queue);
+       if (err < 0)
+               return err;
+
+       return i40e_set_hmc_context(context_bytes,
+                                   i40e_hmc_rxq_ce_info, (u8 *)s);
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.h
new file mode 100644 (file)
index 0000000..00ff350
--- /dev/null
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_LAN_HMC_H_
+#define _I40E_LAN_HMC_H_
+
+/* forward-declare the HW struct for the compiler */
+struct i40e_hw;
+
+/* HMC element context information */
+
+/* Rx queue context data */
+struct i40e_hmc_obj_rxq {
+       u16 head;
+       u8  cpuid;
+       u64 base;
+       u16 qlen;
+#define I40E_RXQ_CTX_DBUFF_SHIFT 7
+       u8  dbuff;
+#define I40E_RXQ_CTX_HBUFF_SHIFT 6
+       u8  hbuff;
+       u8  dtype;
+       u8  dsize;
+       u8  crcstrip;
+       u8  fc_ena;
+       u8  l2tsel;
+       u8  hsplit_0;
+       u8  hsplit_1;
+       u8  showiv;
+       u16 rxmax;
+       u8  tphrdesc_ena;
+       u8  tphwdesc_ena;
+       u8  tphdata_ena;
+       u8  tphhead_ena;
+       u8  lrxqthresh;
+};
+
+/* Tx queue context data */
+struct i40e_hmc_obj_txq {
+       u16 head;
+       u8  new_context;
+       u64 base;
+       u8  fc_ena;
+       u8  timesync_ena;
+       u8  fd_ena;
+       u8  alt_vlan_ena;
+       u16 thead_wb;
+       u16 cpuid;
+       u8  head_wb_ena;
+       u16 qlen;
+       u8  tphrdesc_ena;
+       u8  tphrpacket_ena;
+       u8  tphwdesc_ena;
+       u64 head_wb_addr;
+       u32 crc;
+       u16 rdylist;
+       u8  rdylist_act;
+};
+
+/* for hsplit_0 field of Rx HMC context */
+enum i40e_hmc_obj_rx_hsplit_0 {
+       I40E_HMC_OBJ_RX_HSPLIT_0_NO_SPLIT      = 0,
+       I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_L2      = 1,
+       I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_IP      = 2,
+       I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_TCP_UDP = 4,
+       I40E_HMC_OBJ_RX_HSPLIT_0_SPLIT_SCTP    = 8,
+};
+
+/* fcoe_cntx and fcoe_filt are for debugging purpose only */
+struct i40e_hmc_obj_fcoe_cntx {
+       u32 rsv[32];
+};
+
+struct i40e_hmc_obj_fcoe_filt {
+       u32 rsv[8];
+};
+
+/* Context sizes for LAN objects */
+enum i40e_hmc_lan_object_size {
+       I40E_HMC_LAN_OBJ_SZ_8   = 0x3,
+       I40E_HMC_LAN_OBJ_SZ_16  = 0x4,
+       I40E_HMC_LAN_OBJ_SZ_32  = 0x5,
+       I40E_HMC_LAN_OBJ_SZ_64  = 0x6,
+       I40E_HMC_LAN_OBJ_SZ_128 = 0x7,
+       I40E_HMC_LAN_OBJ_SZ_256 = 0x8,
+       I40E_HMC_LAN_OBJ_SZ_512 = 0x9,
+};
+
+#define I40E_HMC_L2OBJ_BASE_ALIGNMENT 512
+#define I40E_HMC_OBJ_SIZE_TXQ         128
+#define I40E_HMC_OBJ_SIZE_RXQ         32
+#define I40E_HMC_OBJ_SIZE_FCOE_CNTX   128
+#define I40E_HMC_OBJ_SIZE_FCOE_FILT   32
+
+enum i40e_hmc_lan_rsrc_type {
+       I40E_HMC_LAN_FULL  = 0,
+       I40E_HMC_LAN_TX    = 1,
+       I40E_HMC_LAN_RX    = 2,
+       I40E_HMC_FCOE_CTX  = 3,
+       I40E_HMC_FCOE_FILT = 4,
+       I40E_HMC_LAN_MAX   = 5
+};
+
+enum i40e_hmc_model {
+       I40E_HMC_MODEL_DIRECT_PREFERRED = 0,
+       I40E_HMC_MODEL_DIRECT_ONLY      = 1,
+       I40E_HMC_MODEL_PAGED_ONLY       = 2,
+       I40E_HMC_MODEL_UNKNOWN,
+};
+
+struct i40e_hmc_lan_create_obj_info {
+       struct i40e_hmc_info *hmc_info;
+       u32 rsrc_type;
+       u32 start_idx;
+       u32 count;
+       enum i40e_sd_entry_type entry_type;
+       u64 direct_mode_sz;
+};
+
+struct i40e_hmc_lan_delete_obj_info {
+       struct i40e_hmc_info *hmc_info;
+       u32 rsrc_type;
+       u32 start_idx;
+       u32 count;
+};
+
+i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num,
+                                       u32 rxq_num, u32 fcoe_cntx_num,
+                                       u32 fcoe_filt_num);
+i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw,
+                                            enum i40e_hmc_model model);
+i40e_status i40e_shutdown_lan_hmc(struct i40e_hw *hw);
+
+i40e_status i40e_clear_lan_tx_queue_context(struct i40e_hw *hw,
+                                                     u16 queue);
+i40e_status i40e_set_lan_tx_queue_context(struct i40e_hw *hw,
+                                                   u16 queue,
+                                                   struct i40e_hmc_obj_txq *s);
+i40e_status i40e_clear_lan_rx_queue_context(struct i40e_hw *hw,
+                                                     u16 queue);
+i40e_status i40e_set_lan_rx_queue_context(struct i40e_hw *hw,
+                                                   u16 queue,
+                                                   struct i40e_hmc_obj_rxq *s);
+
+#endif /* _I40E_LAN_HMC_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
new file mode 100644 (file)
index 0000000..601d482
--- /dev/null
@@ -0,0 +1,7375 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+/* Local includes */
+#include "i40e.h"
+
+const char i40e_driver_name[] = "i40e";
+static const char i40e_driver_string[] =
+                       "Intel(R) Ethernet Connection XL710 Network Driver";
+
+#define DRV_KERN "-k"
+
+#define DRV_VERSION_MAJOR 0
+#define DRV_VERSION_MINOR 3
+#define DRV_VERSION_BUILD 9
+#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
+            __stringify(DRV_VERSION_MINOR) "." \
+            __stringify(DRV_VERSION_BUILD)    DRV_KERN
+const char i40e_driver_version_str[] = DRV_VERSION;
+static const char i40e_copyright[] = "Copyright (c) 2013 Intel Corporation.";
+
+/* a bit of forward declarations */
+static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi);
+static void i40e_handle_reset_warning(struct i40e_pf *pf);
+static int i40e_add_vsi(struct i40e_vsi *vsi);
+static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi);
+static int i40e_setup_pf_switch(struct i40e_pf *pf);
+static int i40e_setup_misc_vector(struct i40e_pf *pf);
+static void i40e_determine_queue_usage(struct i40e_pf *pf);
+static int i40e_setup_pf_filter_control(struct i40e_pf *pf);
+
+/* i40e_pci_tbl - PCI Device ID Table
+ *
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static DEFINE_PCI_DEVICE_TABLE(i40e_pci_tbl) = {
+       {PCI_VDEVICE(INTEL, I40E_SFP_XL710_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_SFP_X710_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_QEMU_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_KX_A_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_KX_B_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_KX_C_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_KX_D_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_QSFP_A_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_QSFP_B_DEVICE_ID), 0},
+       {PCI_VDEVICE(INTEL, I40E_QSFP_C_DEVICE_ID), 0},
+       /* required last entry */
+       {0, }
+};
+MODULE_DEVICE_TABLE(pci, i40e_pci_tbl);
+
+#define I40E_MAX_VF_COUNT 128
+static int debug = -1;
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+
+MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
+MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ * i40e_allocate_dma_mem_d - OS specific memory alloc for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  ptr to mem struct to fill out
+ * @size: size of memory requested
+ * @alignment: what to align the allocation to
+ **/
+int i40e_allocate_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem,
+                           u64 size, u32 alignment)
+{
+       struct i40e_pf *pf = (struct i40e_pf *)hw->back;
+
+       mem->size = ALIGN(size, alignment);
+       mem->va = dma_zalloc_coherent(&pf->pdev->dev, mem->size,
+                                     &mem->pa, GFP_KERNEL);
+       if (mem->va)
+               return 0;
+
+       return -ENOMEM;
+}
+
+/**
+ * i40e_free_dma_mem_d - OS specific memory free for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  ptr to mem struct to free
+ **/
+int i40e_free_dma_mem_d(struct i40e_hw *hw, struct i40e_dma_mem *mem)
+{
+       struct i40e_pf *pf = (struct i40e_pf *)hw->back;
+
+       dma_free_coherent(&pf->pdev->dev, mem->size, mem->va, mem->pa);
+       mem->va = NULL;
+       mem->pa = 0;
+       mem->size = 0;
+
+       return 0;
+}
+
+/**
+ * i40e_allocate_virt_mem_d - OS specific memory alloc for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  ptr to mem struct to fill out
+ * @size: size of memory requested
+ **/
+int i40e_allocate_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem,
+                            u32 size)
+{
+       mem->size = size;
+       mem->va = kzalloc(size, GFP_KERNEL);
+
+       if (mem->va)
+               return 0;
+
+       return -ENOMEM;
+}
+
+/**
+ * i40e_free_virt_mem_d - OS specific memory free for shared code
+ * @hw:   pointer to the HW structure
+ * @mem:  ptr to mem struct to free
+ **/
+int i40e_free_virt_mem_d(struct i40e_hw *hw, struct i40e_virt_mem *mem)
+{
+       /* it's ok to kfree a NULL pointer */
+       kfree(mem->va);
+       mem->va = NULL;
+       mem->size = 0;
+
+       return 0;
+}
+
+/**
+ * i40e_get_lump - find a lump of free generic resource
+ * @pf: board private structure
+ * @pile: the pile of resource to search
+ * @needed: the number of items needed
+ * @id: an owner id to stick on the items assigned
+ *
+ * Returns the base item index of the lump, or negative for error
+ *
+ * The search_hint trick and lack of advanced fit-finding only work
+ * because we're highly likely to have all the same size lump requests.
+ * Linear search time and any fragmentation should be minimal.
+ **/
+static int i40e_get_lump(struct i40e_pf *pf, struct i40e_lump_tracking *pile,
+                        u16 needed, u16 id)
+{
+       int ret = -ENOMEM;
+       int i = 0;
+       int j = 0;
+
+       if (!pile || needed == 0 || id >= I40E_PILE_VALID_BIT) {
+               dev_info(&pf->pdev->dev,
+                        "param err: pile=%p needed=%d id=0x%04x\n",
+                        pile, needed, id);
+               return -EINVAL;
+       }
+
+       /* start the linear search with an imperfect hint */
+       i = pile->search_hint;
+       while (i < pile->num_entries && ret < 0) {
+               /* skip already allocated entries */
+               if (pile->list[i] & I40E_PILE_VALID_BIT) {
+                       i++;
+                       continue;
+               }
+
+               /* do we have enough in this lump? */
+               for (j = 0; (j < needed) && ((i+j) < pile->num_entries); j++) {
+                       if (pile->list[i+j] & I40E_PILE_VALID_BIT)
+                               break;
+               }
+
+               if (j == needed) {
+                       /* there was enough, so assign it to the requestor */
+                       for (j = 0; j < needed; j++)
+                               pile->list[i+j] = id | I40E_PILE_VALID_BIT;
+                       ret = i;
+                       pile->search_hint = i + j;
+               } else {
+                       /* not enough, so skip over it and continue looking */
+                       i += j;
+               }
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_put_lump - return a lump of generic resource
+ * @pile: the pile of resource to search
+ * @index: the base item index
+ * @id: the owner id of the items assigned
+ *
+ * Returns the count of items in the lump
+ **/
+static int i40e_put_lump(struct i40e_lump_tracking *pile, u16 index, u16 id)
+{
+       int valid_id = (id | I40E_PILE_VALID_BIT);
+       int count = 0;
+       int i;
+
+       if (!pile || index >= pile->num_entries)
+               return -EINVAL;
+
+       for (i = index;
+            i < pile->num_entries && pile->list[i] == valid_id;
+            i++) {
+               pile->list[i] = 0;
+               count++;
+       }
+
+       if (count && index < pile->search_hint)
+               pile->search_hint = index;
+
+       return count;
+}
+
+/**
+ * i40e_service_event_schedule - Schedule the service task to wake up
+ * @pf: board private structure
+ *
+ * If not already scheduled, this puts the task into the work queue
+ **/
+static void i40e_service_event_schedule(struct i40e_pf *pf)
+{
+       if (!test_bit(__I40E_DOWN, &pf->state) &&
+           !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) &&
+           !test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state))
+               schedule_work(&pf->service_task);
+}
+
+/**
+ * i40e_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ *
+ * If any port has noticed a Tx timeout, it is likely that the whole
+ * device is munged, not just the one netdev port, so go for the full
+ * reset.
+ **/
+static void i40e_tx_timeout(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+
+       pf->tx_timeout_count++;
+
+       if (time_after(jiffies, (pf->tx_timeout_last_recovery + HZ*20)))
+               pf->tx_timeout_recovery_level = 0;
+       pf->tx_timeout_last_recovery = jiffies;
+       netdev_info(netdev, "tx_timeout recovery level %d\n",
+                   pf->tx_timeout_recovery_level);
+
+       switch (pf->tx_timeout_recovery_level) {
+       case 0:
+               /* disable and re-enable queues for the VSI */
+               if (in_interrupt()) {
+                       set_bit(__I40E_REINIT_REQUESTED, &pf->state);
+                       set_bit(__I40E_REINIT_REQUESTED, &vsi->state);
+               } else {
+                       i40e_vsi_reinit_locked(vsi);
+               }
+               break;
+       case 1:
+               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
+               break;
+       case 2:
+               set_bit(__I40E_CORE_RESET_REQUESTED, &pf->state);
+               break;
+       case 3:
+               set_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state);
+               break;
+       default:
+               netdev_err(netdev, "tx_timeout recovery unsuccessful\n");
+               i40e_down(vsi);
+               break;
+       }
+       i40e_service_event_schedule(pf);
+       pf->tx_timeout_recovery_level++;
+}
+
+/**
+ * i40e_release_rx_desc - Store the new tail and head values
+ * @rx_ring: ring to bump
+ * @val: new head index
+ **/
+static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
+{
+       rx_ring->next_to_use = val;
+
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+       writel(val, rx_ring->tail);
+}
+
+/**
+ * i40e_get_vsi_stats_struct - Get System Network Statistics
+ * @vsi: the VSI we care about
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the service task.
+ **/
+struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi)
+{
+       return &vsi->net_stats;
+}
+
+/**
+ * i40e_get_netdev_stats_struct - Get statistics for netdev interface
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the service task.
+ **/
+static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
+                                            struct net_device *netdev,
+                                            struct rtnl_link_stats64 *storage)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       *storage = *i40e_get_vsi_stats_struct(vsi);
+
+       return storage;
+}
+
+/**
+ * i40e_vsi_reset_stats - Resets all stats of the given vsi
+ * @vsi: the VSI to have its stats reset
+ **/
+void i40e_vsi_reset_stats(struct i40e_vsi *vsi)
+{
+       struct rtnl_link_stats64 *ns;
+       int i;
+
+       if (!vsi)
+               return;
+
+       ns = i40e_get_vsi_stats_struct(vsi);
+       memset(ns, 0, sizeof(*ns));
+       memset(&vsi->net_stats_offsets, 0, sizeof(vsi->net_stats_offsets));
+       memset(&vsi->eth_stats, 0, sizeof(vsi->eth_stats));
+       memset(&vsi->eth_stats_offsets, 0, sizeof(vsi->eth_stats_offsets));
+       if (vsi->rx_rings)
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       memset(&vsi->rx_rings[i].rx_stats, 0 ,
+                              sizeof(vsi->rx_rings[i].rx_stats));
+                       memset(&vsi->tx_rings[i].tx_stats, 0,
+                              sizeof(vsi->tx_rings[i].tx_stats));
+               }
+       vsi->stat_offsets_loaded = false;
+}
+
+/**
+ * i40e_pf_reset_stats - Reset all of the stats for the given pf
+ * @pf: the PF to be reset
+ **/
+void i40e_pf_reset_stats(struct i40e_pf *pf)
+{
+       memset(&pf->stats, 0, sizeof(pf->stats));
+       memset(&pf->stats_offsets, 0, sizeof(pf->stats_offsets));
+       pf->stat_offsets_loaded = false;
+}
+
+/**
+ * i40e_stat_update48 - read and update a 48 bit stat from the chip
+ * @hw: ptr to the hardware info
+ * @hireg: the high 32 bit reg to read
+ * @loreg: the low 32 bit reg to read
+ * @offset_loaded: has the initial offset been loaded yet
+ * @offset: ptr to current offset value
+ * @stat: ptr to the stat
+ *
+ * Since the device stats are not reset at PFReset, they likely will not
+ * be zeroed when the driver starts.  We'll save the first values read
+ * and use them as offsets to be subtracted from the raw values in order
+ * to report stats that count from zero.  In the process, we also manage
+ * the potential roll-over.
+ **/
+static void i40e_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg,
+                              bool offset_loaded, u64 *offset, u64 *stat)
+{
+       u64 new_data;
+
+       if (hw->device_id == I40E_QEMU_DEVICE_ID) {
+               new_data = rd32(hw, loreg);
+               new_data |= ((u64)(rd32(hw, hireg) & 0xFFFF)) << 32;
+       } else {
+               new_data = rd64(hw, loreg);
+       }
+       if (!offset_loaded)
+               *offset = new_data;
+       if (likely(new_data >= *offset))
+               *stat = new_data - *offset;
+       else
+               *stat = (new_data + ((u64)1 << 48)) - *offset;
+       *stat &= 0xFFFFFFFFFFFFULL;
+}
+
+/**
+ * i40e_stat_update32 - read and update a 32 bit stat from the chip
+ * @hw: ptr to the hardware info
+ * @reg: the hw reg to read
+ * @offset_loaded: has the initial offset been loaded yet
+ * @offset: ptr to current offset value
+ * @stat: ptr to the stat
+ **/
+static void i40e_stat_update32(struct i40e_hw *hw, u32 reg,
+                              bool offset_loaded, u64 *offset, u64 *stat)
+{
+       u32 new_data;
+
+       new_data = rd32(hw, reg);
+       if (!offset_loaded)
+               *offset = new_data;
+       if (likely(new_data >= *offset))
+               *stat = (u32)(new_data - *offset);
+       else
+               *stat = (u32)((new_data + ((u64)1 << 32)) - *offset);
+}
+
+/**
+ * i40e_update_eth_stats - Update VSI-specific ethernet statistics counters.
+ * @vsi: the VSI to be updated
+ **/
+void i40e_update_eth_stats(struct i40e_vsi *vsi)
+{
+       int stat_idx = le16_to_cpu(vsi->info.stat_counter_idx);
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_eth_stats *oes;
+       struct i40e_eth_stats *es;     /* device's eth stats */
+
+       es = &vsi->eth_stats;
+       oes = &vsi->eth_stats_offsets;
+
+       /* Gather up the stats that the hw collects */
+       i40e_stat_update32(hw, I40E_GLV_TEPC(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->tx_errors, &es->tx_errors);
+       i40e_stat_update32(hw, I40E_GLV_RDPC(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->rx_discards, &es->rx_discards);
+
+       i40e_stat_update48(hw, I40E_GLV_GORCH(stat_idx),
+                          I40E_GLV_GORCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->rx_bytes, &es->rx_bytes);
+       i40e_stat_update48(hw, I40E_GLV_UPRCH(stat_idx),
+                          I40E_GLV_UPRCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->rx_unicast, &es->rx_unicast);
+       i40e_stat_update48(hw, I40E_GLV_MPRCH(stat_idx),
+                          I40E_GLV_MPRCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->rx_multicast, &es->rx_multicast);
+       i40e_stat_update48(hw, I40E_GLV_BPRCH(stat_idx),
+                          I40E_GLV_BPRCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->rx_broadcast, &es->rx_broadcast);
+
+       i40e_stat_update48(hw, I40E_GLV_GOTCH(stat_idx),
+                          I40E_GLV_GOTCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->tx_bytes, &es->tx_bytes);
+       i40e_stat_update48(hw, I40E_GLV_UPTCH(stat_idx),
+                          I40E_GLV_UPTCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->tx_unicast, &es->tx_unicast);
+       i40e_stat_update48(hw, I40E_GLV_MPTCH(stat_idx),
+                          I40E_GLV_MPTCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->tx_multicast, &es->tx_multicast);
+       i40e_stat_update48(hw, I40E_GLV_BPTCH(stat_idx),
+                          I40E_GLV_BPTCL(stat_idx),
+                          vsi->stat_offsets_loaded,
+                          &oes->tx_broadcast, &es->tx_broadcast);
+       vsi->stat_offsets_loaded = true;
+}
+
+/**
+ * i40e_update_veb_stats - Update Switch component statistics
+ * @veb: the VEB being updated
+ **/
+static void i40e_update_veb_stats(struct i40e_veb *veb)
+{
+       struct i40e_pf *pf = veb->pf;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_eth_stats *oes;
+       struct i40e_eth_stats *es;     /* device's eth stats */
+       int idx = 0;
+
+       idx = veb->stats_idx;
+       es = &veb->stats;
+       oes = &veb->stats_offsets;
+
+       /* Gather up the stats that the hw collects */
+       i40e_stat_update32(hw, I40E_GLSW_TDPC(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->tx_discards, &es->tx_discards);
+       i40e_stat_update32(hw, I40E_GLSW_RUPP(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->rx_unknown_protocol, &es->rx_unknown_protocol);
+
+       i40e_stat_update48(hw, I40E_GLSW_GORCH(idx), I40E_GLSW_GORCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->rx_bytes, &es->rx_bytes);
+       i40e_stat_update48(hw, I40E_GLSW_UPRCH(idx), I40E_GLSW_UPRCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->rx_unicast, &es->rx_unicast);
+       i40e_stat_update48(hw, I40E_GLSW_MPRCH(idx), I40E_GLSW_MPRCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->rx_multicast, &es->rx_multicast);
+       i40e_stat_update48(hw, I40E_GLSW_BPRCH(idx), I40E_GLSW_BPRCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->rx_broadcast, &es->rx_broadcast);
+
+       i40e_stat_update48(hw, I40E_GLSW_GOTCH(idx), I40E_GLSW_GOTCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->tx_bytes, &es->tx_bytes);
+       i40e_stat_update48(hw, I40E_GLSW_UPTCH(idx), I40E_GLSW_UPTCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->tx_unicast, &es->tx_unicast);
+       i40e_stat_update48(hw, I40E_GLSW_MPTCH(idx), I40E_GLSW_MPTCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->tx_multicast, &es->tx_multicast);
+       i40e_stat_update48(hw, I40E_GLSW_BPTCH(idx), I40E_GLSW_BPTCL(idx),
+                          veb->stat_offsets_loaded,
+                          &oes->tx_broadcast, &es->tx_broadcast);
+       veb->stat_offsets_loaded = true;
+}
+
+/**
+ * i40e_update_link_xoff_rx - Update XOFF received in link flow control mode
+ * @pf: the corresponding PF
+ *
+ * Update the Rx XOFF counter (PAUSE frames) in link flow control mode
+ **/
+static void i40e_update_link_xoff_rx(struct i40e_pf *pf)
+{
+       struct i40e_hw_port_stats *osd = &pf->stats_offsets;
+       struct i40e_hw_port_stats *nsd = &pf->stats;
+       struct i40e_hw *hw = &pf->hw;
+       u64 xoff = 0;
+       u16 i, v;
+
+       if ((hw->fc.current_mode != I40E_FC_FULL) &&
+           (hw->fc.current_mode != I40E_FC_RX_PAUSE))
+               return;
+
+       xoff = nsd->link_xoff_rx;
+       i40e_stat_update32(hw, I40E_GLPRT_LXOFFRXC(hw->port),
+                          pf->stat_offsets_loaded,
+                          &osd->link_xoff_rx, &nsd->link_xoff_rx);
+
+       /* No new LFC xoff rx */
+       if (!(nsd->link_xoff_rx - xoff))
+               return;
+
+       /* Clear the __I40E_HANG_CHECK_ARMED bit for all Tx rings */
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               struct i40e_vsi *vsi = pf->vsi[v];
+
+               if (!vsi)
+                       continue;
+
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       struct i40e_ring *ring = &vsi->tx_rings[i];
+                       clear_bit(__I40E_HANG_CHECK_ARMED, &ring->state);
+               }
+       }
+}
+
+/**
+ * i40e_update_prio_xoff_rx - Update XOFF received in PFC mode
+ * @pf: the corresponding PF
+ *
+ * Update the Rx XOFF counter (PAUSE frames) in PFC mode
+ **/
+static void i40e_update_prio_xoff_rx(struct i40e_pf *pf)
+{
+       struct i40e_hw_port_stats *osd = &pf->stats_offsets;
+       struct i40e_hw_port_stats *nsd = &pf->stats;
+       bool xoff[I40E_MAX_TRAFFIC_CLASS] = {false};
+       struct i40e_dcbx_config *dcb_cfg;
+       struct i40e_hw *hw = &pf->hw;
+       u16 i, v;
+       u8 tc;
+
+       dcb_cfg = &hw->local_dcbx_config;
+
+       /* See if DCB enabled with PFC TC */
+       if (!(pf->flags & I40E_FLAG_DCB_ENABLED) ||
+           !(dcb_cfg->pfc.pfcenable)) {
+               i40e_update_link_xoff_rx(pf);
+               return;
+       }
+
+       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+               u64 prio_xoff = nsd->priority_xoff_rx[i];
+               i40e_stat_update32(hw, I40E_GLPRT_PXOFFRXC(hw->port, i),
+                                  pf->stat_offsets_loaded,
+                                  &osd->priority_xoff_rx[i],
+                                  &nsd->priority_xoff_rx[i]);
+
+               /* No new PFC xoff rx */
+               if (!(nsd->priority_xoff_rx[i] - prio_xoff))
+                       continue;
+               /* Get the TC for given priority */
+               tc = dcb_cfg->etscfg.prioritytable[i];
+               xoff[tc] = true;
+       }
+
+       /* Clear the __I40E_HANG_CHECK_ARMED bit for Tx rings */
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               struct i40e_vsi *vsi = pf->vsi[v];
+
+               if (!vsi)
+                       continue;
+
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       struct i40e_ring *ring = &vsi->tx_rings[i];
+
+                       tc = ring->dcb_tc;
+                       if (xoff[tc])
+                               clear_bit(__I40E_HANG_CHECK_ARMED,
+                                         &ring->state);
+               }
+       }
+}
+
+/**
+ * i40e_update_stats - Update the board statistics counters.
+ * @vsi: the VSI to be updated
+ *
+ * There are a few instances where we store the same stat in a
+ * couple of different structs.  This is partly because we have
+ * the netdev stats that need to be filled out, which is slightly
+ * different from the "eth_stats" defined by the chip and used in
+ * VF communications.  We sort it all out here in a central place.
+ **/
+void i40e_update_stats(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct rtnl_link_stats64 *ons;
+       struct rtnl_link_stats64 *ns;   /* netdev stats */
+       struct i40e_eth_stats *oes;
+       struct i40e_eth_stats *es;     /* device's eth stats */
+       u32 tx_restart, tx_busy;
+       u32 rx_page, rx_buf;
+       u64 rx_p, rx_b;
+       u64 tx_p, tx_b;
+       int i;
+       u16 q;
+
+       if (test_bit(__I40E_DOWN, &vsi->state) ||
+           test_bit(__I40E_CONFIG_BUSY, &pf->state))
+               return;
+
+       ns = i40e_get_vsi_stats_struct(vsi);
+       ons = &vsi->net_stats_offsets;
+       es = &vsi->eth_stats;
+       oes = &vsi->eth_stats_offsets;
+
+       /* Gather up the netdev and vsi stats that the driver collects
+        * on the fly during packet processing
+        */
+       rx_b = rx_p = 0;
+       tx_b = tx_p = 0;
+       tx_restart = tx_busy = 0;
+       rx_page = 0;
+       rx_buf = 0;
+       for (q = 0; q < vsi->num_queue_pairs; q++) {
+               struct i40e_ring *p;
+
+               p = &vsi->rx_rings[q];
+               rx_b += p->rx_stats.bytes;
+               rx_p += p->rx_stats.packets;
+               rx_buf += p->rx_stats.alloc_rx_buff_failed;
+               rx_page += p->rx_stats.alloc_rx_page_failed;
+
+               p = &vsi->tx_rings[q];
+               tx_b += p->tx_stats.bytes;
+               tx_p += p->tx_stats.packets;
+               tx_restart += p->tx_stats.restart_queue;
+               tx_busy += p->tx_stats.tx_busy;
+       }
+       vsi->tx_restart = tx_restart;
+       vsi->tx_busy = tx_busy;
+       vsi->rx_page_failed = rx_page;
+       vsi->rx_buf_failed = rx_buf;
+
+       ns->rx_packets = rx_p;
+       ns->rx_bytes = rx_b;
+       ns->tx_packets = tx_p;
+       ns->tx_bytes = tx_b;
+
+       i40e_update_eth_stats(vsi);
+       /* update netdev stats from eth stats */
+       ons->rx_errors = oes->rx_errors;
+       ns->rx_errors = es->rx_errors;
+       ons->tx_errors = oes->tx_errors;
+       ns->tx_errors = es->tx_errors;
+       ons->multicast = oes->rx_multicast;
+       ns->multicast = es->rx_multicast;
+       ons->tx_dropped = oes->tx_discards;
+       ns->tx_dropped = es->tx_discards;
+
+       /* Get the port data only if this is the main PF VSI */
+       if (vsi == pf->vsi[pf->lan_vsi]) {
+               struct i40e_hw_port_stats *nsd = &pf->stats;
+               struct i40e_hw_port_stats *osd = &pf->stats_offsets;
+
+               i40e_stat_update48(hw, I40E_GLPRT_GORCH(hw->port),
+                                  I40E_GLPRT_GORCL(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->eth.rx_bytes, &nsd->eth.rx_bytes);
+               i40e_stat_update48(hw, I40E_GLPRT_GOTCH(hw->port),
+                                  I40E_GLPRT_GOTCL(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->eth.tx_bytes, &nsd->eth.tx_bytes);
+               i40e_stat_update32(hw, I40E_GLPRT_RDPC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->eth.rx_discards,
+                                  &nsd->eth.rx_discards);
+               i40e_stat_update32(hw, I40E_GLPRT_TDPC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->eth.tx_discards,
+                                  &nsd->eth.tx_discards);
+               i40e_stat_update48(hw, I40E_GLPRT_MPRCH(hw->port),
+                                  I40E_GLPRT_MPRCL(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->eth.rx_multicast,
+                                  &nsd->eth.rx_multicast);
+
+               i40e_stat_update32(hw, I40E_GLPRT_TDOLD(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_dropped_link_down,
+                                  &nsd->tx_dropped_link_down);
+
+               i40e_stat_update32(hw, I40E_GLPRT_CRCERRS(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->crc_errors, &nsd->crc_errors);
+               ns->rx_crc_errors = nsd->crc_errors;
+
+               i40e_stat_update32(hw, I40E_GLPRT_ILLERRC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->illegal_bytes, &nsd->illegal_bytes);
+               ns->rx_errors = nsd->crc_errors
+                               + nsd->illegal_bytes;
+
+               i40e_stat_update32(hw, I40E_GLPRT_MLFC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->mac_local_faults,
+                                  &nsd->mac_local_faults);
+               i40e_stat_update32(hw, I40E_GLPRT_MRFC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->mac_remote_faults,
+                                  &nsd->mac_remote_faults);
+
+               i40e_stat_update32(hw, I40E_GLPRT_RLEC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_length_errors,
+                                  &nsd->rx_length_errors);
+               ns->rx_length_errors = nsd->rx_length_errors;
+
+               i40e_stat_update32(hw, I40E_GLPRT_LXONRXC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->link_xon_rx, &nsd->link_xon_rx);
+               i40e_stat_update32(hw, I40E_GLPRT_LXONTXC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->link_xon_tx, &nsd->link_xon_tx);
+               i40e_update_prio_xoff_rx(pf);  /* handles I40E_GLPRT_LXOFFRXC */
+               i40e_stat_update32(hw, I40E_GLPRT_LXOFFTXC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->link_xoff_tx, &nsd->link_xoff_tx);
+
+               for (i = 0; i < 8; i++) {
+                       i40e_stat_update32(hw, I40E_GLPRT_PXONRXC(hw->port, i),
+                                          pf->stat_offsets_loaded,
+                                          &osd->priority_xon_rx[i],
+                                          &nsd->priority_xon_rx[i]);
+                       i40e_stat_update32(hw, I40E_GLPRT_PXONTXC(hw->port, i),
+                                          pf->stat_offsets_loaded,
+                                          &osd->priority_xon_tx[i],
+                                          &nsd->priority_xon_tx[i]);
+                       i40e_stat_update32(hw, I40E_GLPRT_PXOFFTXC(hw->port, i),
+                                          pf->stat_offsets_loaded,
+                                          &osd->priority_xoff_tx[i],
+                                          &nsd->priority_xoff_tx[i]);
+                       i40e_stat_update32(hw,
+                                          I40E_GLPRT_RXON2OFFCNT(hw->port, i),
+                                          pf->stat_offsets_loaded,
+                                          &osd->priority_xon_2_xoff[i],
+                                          &nsd->priority_xon_2_xoff[i]);
+               }
+
+               i40e_stat_update48(hw, I40E_GLPRT_PRC64H(hw->port),
+                                  I40E_GLPRT_PRC64L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_64, &nsd->rx_size_64);
+               i40e_stat_update48(hw, I40E_GLPRT_PRC127H(hw->port),
+                                  I40E_GLPRT_PRC127L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_127, &nsd->rx_size_127);
+               i40e_stat_update48(hw, I40E_GLPRT_PRC255H(hw->port),
+                                  I40E_GLPRT_PRC255L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_255, &nsd->rx_size_255);
+               i40e_stat_update48(hw, I40E_GLPRT_PRC511H(hw->port),
+                                  I40E_GLPRT_PRC511L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_511, &nsd->rx_size_511);
+               i40e_stat_update48(hw, I40E_GLPRT_PRC1023H(hw->port),
+                                  I40E_GLPRT_PRC1023L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_1023, &nsd->rx_size_1023);
+               i40e_stat_update48(hw, I40E_GLPRT_PRC1522H(hw->port),
+                                  I40E_GLPRT_PRC1522L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_1522, &nsd->rx_size_1522);
+               i40e_stat_update48(hw, I40E_GLPRT_PRC9522H(hw->port),
+                                  I40E_GLPRT_PRC9522L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_size_big, &nsd->rx_size_big);
+
+               i40e_stat_update48(hw, I40E_GLPRT_PTC64H(hw->port),
+                                  I40E_GLPRT_PTC64L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_64, &nsd->tx_size_64);
+               i40e_stat_update48(hw, I40E_GLPRT_PTC127H(hw->port),
+                                  I40E_GLPRT_PTC127L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_127, &nsd->tx_size_127);
+               i40e_stat_update48(hw, I40E_GLPRT_PTC255H(hw->port),
+                                  I40E_GLPRT_PTC255L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_255, &nsd->tx_size_255);
+               i40e_stat_update48(hw, I40E_GLPRT_PTC511H(hw->port),
+                                  I40E_GLPRT_PTC511L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_511, &nsd->tx_size_511);
+               i40e_stat_update48(hw, I40E_GLPRT_PTC1023H(hw->port),
+                                  I40E_GLPRT_PTC1023L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_1023, &nsd->tx_size_1023);
+               i40e_stat_update48(hw, I40E_GLPRT_PTC1522H(hw->port),
+                                  I40E_GLPRT_PTC1522L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_1522, &nsd->tx_size_1522);
+               i40e_stat_update48(hw, I40E_GLPRT_PTC9522H(hw->port),
+                                  I40E_GLPRT_PTC9522L(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->tx_size_big, &nsd->tx_size_big);
+
+               i40e_stat_update32(hw, I40E_GLPRT_RUC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_undersize, &nsd->rx_undersize);
+               i40e_stat_update32(hw, I40E_GLPRT_RFC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_fragments, &nsd->rx_fragments);
+               i40e_stat_update32(hw, I40E_GLPRT_ROC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_oversize, &nsd->rx_oversize);
+               i40e_stat_update32(hw, I40E_GLPRT_RJC(hw->port),
+                                  pf->stat_offsets_loaded,
+                                  &osd->rx_jabber, &nsd->rx_jabber);
+       }
+
+       pf->stat_offsets_loaded = true;
+}
+
+/**
+ * i40e_find_filter - Search VSI filter list for specific mac/vlan filter
+ * @vsi: the VSI to be searched
+ * @macaddr: the MAC address
+ * @vlan: the vlan
+ * @is_vf: make sure its a vf filter, else doesn't matter
+ * @is_netdev: make sure its a netdev filter, else doesn't matter
+ *
+ * Returns ptr to the filter object or NULL
+ **/
+static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi,
+                                               u8 *macaddr, s16 vlan,
+                                               bool is_vf, bool is_netdev)
+{
+       struct i40e_mac_filter *f;
+
+       if (!vsi || !macaddr)
+               return NULL;
+
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               if ((ether_addr_equal(macaddr, f->macaddr)) &&
+                   (vlan == f->vlan)    &&
+                   (!is_vf || f->is_vf) &&
+                   (!is_netdev || f->is_netdev))
+                       return f;
+       }
+       return NULL;
+}
+
+/**
+ * i40e_find_mac - Find a mac addr in the macvlan filters list
+ * @vsi: the VSI to be searched
+ * @macaddr: the MAC address we are searching for
+ * @is_vf: make sure its a vf filter, else doesn't matter
+ * @is_netdev: make sure its a netdev filter, else doesn't matter
+ *
+ * Returns the first filter with the provided MAC address or NULL if
+ * MAC address was not found
+ **/
+struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
+                                     bool is_vf, bool is_netdev)
+{
+       struct i40e_mac_filter *f;
+
+       if (!vsi || !macaddr)
+               return NULL;
+
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               if ((ether_addr_equal(macaddr, f->macaddr)) &&
+                   (!is_vf || f->is_vf) &&
+                   (!is_netdev || f->is_netdev))
+                       return f;
+       }
+       return NULL;
+}
+
+/**
+ * i40e_is_vsi_in_vlan - Check if VSI is in vlan mode
+ * @vsi: the VSI to be searched
+ *
+ * Returns true if VSI is in vlan mode or false otherwise
+ **/
+bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi)
+{
+       struct i40e_mac_filter *f;
+
+       /* Only -1 for all the filters denotes not in vlan mode
+        * so we have to go through all the list in order to make sure
+        */
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               if (f->vlan >= 0)
+                       return true;
+       }
+
+       return false;
+}
+
+/**
+ * i40e_put_mac_in_vlan - Make macvlan filters from macaddrs and vlans
+ * @vsi: the VSI to be searched
+ * @macaddr: the mac address to be filtered
+ * @is_vf: true if it is a vf
+ * @is_netdev: true if it is a netdev
+ *
+ * Goes through all the macvlan filters and adds a
+ * macvlan filter for each unique vlan that already exists
+ *
+ * Returns first filter found on success, else NULL
+ **/
+struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
+                                            bool is_vf, bool is_netdev)
+{
+       struct i40e_mac_filter *f;
+
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               if (!i40e_find_filter(vsi, macaddr, f->vlan,
+                                     is_vf, is_netdev)) {
+                       if (!i40e_add_filter(vsi, macaddr, f->vlan,
+                                               is_vf, is_netdev))
+                               return NULL;
+               }
+       }
+
+       return list_first_entry_or_null(&vsi->mac_filter_list,
+                                       struct i40e_mac_filter, list);
+}
+
+/**
+ * i40e_add_filter - Add a mac/vlan filter to the VSI
+ * @vsi: the VSI to be searched
+ * @macaddr: the MAC address
+ * @vlan: the vlan
+ * @is_vf: make sure its a vf filter, else doesn't matter
+ * @is_netdev: make sure its a netdev filter, else doesn't matter
+ *
+ * Returns ptr to the filter object or NULL when no memory available.
+ **/
+struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
+                                       u8 *macaddr, s16 vlan,
+                                       bool is_vf, bool is_netdev)
+{
+       struct i40e_mac_filter *f;
+
+       if (!vsi || !macaddr)
+               return NULL;
+
+       f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev);
+       if (!f) {
+               f = kzalloc(sizeof(*f), GFP_ATOMIC);
+               if (!f)
+                       goto add_filter_out;
+
+               memcpy(f->macaddr, macaddr, ETH_ALEN);
+               f->vlan = vlan;
+               f->changed = true;
+
+               INIT_LIST_HEAD(&f->list);
+               list_add(&f->list, &vsi->mac_filter_list);
+       }
+
+       /* increment counter and add a new flag if needed */
+       if (is_vf) {
+               if (!f->is_vf) {
+                       f->is_vf = true;
+                       f->counter++;
+               }
+       } else if (is_netdev) {
+               if (!f->is_netdev) {
+                       f->is_netdev = true;
+                       f->counter++;
+               }
+       } else {
+               f->counter++;
+       }
+
+       /* changed tells sync_filters_subtask to
+        * push the filter down to the firmware
+        */
+       if (f->changed) {
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+       }
+
+add_filter_out:
+       return f;
+}
+
+/**
+ * i40e_del_filter - Remove a mac/vlan filter from the VSI
+ * @vsi: the VSI to be searched
+ * @macaddr: the MAC address
+ * @vlan: the vlan
+ * @is_vf: make sure it's a vf filter, else doesn't matter
+ * @is_netdev: make sure it's a netdev filter, else doesn't matter
+ **/
+void i40e_del_filter(struct i40e_vsi *vsi,
+                    u8 *macaddr, s16 vlan,
+                    bool is_vf, bool is_netdev)
+{
+       struct i40e_mac_filter *f;
+
+       if (!vsi || !macaddr)
+               return;
+
+       f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev);
+       if (!f || f->counter == 0)
+               return;
+
+       if (is_vf) {
+               if (f->is_vf) {
+                       f->is_vf = false;
+                       f->counter--;
+               }
+       } else if (is_netdev) {
+               if (f->is_netdev) {
+                       f->is_netdev = false;
+                       f->counter--;
+               }
+       } else {
+               /* make sure we don't remove a filter in use by vf or netdev */
+               int min_f = 0;
+               min_f += (f->is_vf ? 1 : 0);
+               min_f += (f->is_netdev ? 1 : 0);
+
+               if (f->counter > min_f)
+                       f->counter--;
+       }
+
+       /* counter == 0 tells sync_filters_subtask to
+        * remove the filter from the firmware's list
+        */
+       if (f->counter == 0) {
+               f->changed = true;
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+       }
+}
+
+/**
+ * i40e_set_mac - NDO callback to set mac address
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_set_mac(struct net_device *netdev, void *p)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct sockaddr *addr = p;
+       struct i40e_mac_filter *f;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       netdev_info(netdev, "set mac address=%pM\n", addr->sa_data);
+
+       if (ether_addr_equal(netdev->dev_addr, addr->sa_data))
+               return 0;
+
+       if (vsi->type == I40E_VSI_MAIN) {
+               i40e_status ret;
+               ret = i40e_aq_mac_address_write(&vsi->back->hw,
+                                               I40E_AQC_WRITE_TYPE_LAA_ONLY,
+                                               addr->sa_data, NULL);
+               if (ret) {
+                       netdev_info(netdev,
+                                   "Addr change for Main VSI failed: %d\n",
+                                   ret);
+                       return -EADDRNOTAVAIL;
+               }
+
+               memcpy(vsi->back->hw.mac.addr, addr->sa_data, netdev->addr_len);
+       }
+
+       /* In order to be sure to not drop any packets, add the new address
+        * then delete the old one.
+        */
+       f = i40e_add_filter(vsi, addr->sa_data, I40E_VLAN_ANY, false, false);
+       if (!f)
+               return -ENOMEM;
+
+       i40e_sync_vsi_filters(vsi);
+       i40e_del_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY, false, false);
+       i40e_sync_vsi_filters(vsi);
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_setup_queue_map - Setup a VSI queue map based on enabled_tc
+ * @vsi: the VSI being setup
+ * @ctxt: VSI context structure
+ * @enabled_tc: Enabled TCs bitmap
+ * @is_add: True if called before Add VSI
+ *
+ * Setup VSI queue mapping for enabled traffic classes.
+ **/
+static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
+                                    struct i40e_vsi_context *ctxt,
+                                    u8 enabled_tc,
+                                    bool is_add)
+{
+       struct i40e_pf *pf = vsi->back;
+       u16 sections = 0;
+       u8 netdev_tc = 0;
+       u16 numtc = 0;
+       u16 qcount;
+       u8 offset;
+       u16 qmap;
+       int i;
+
+       sections = I40E_AQ_VSI_PROP_QUEUE_MAP_VALID;
+       offset = 0;
+
+       if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) {
+               /* Find numtc from enabled TC bitmap */
+               for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                       if (enabled_tc & (1 << i)) /* TC is enabled */
+                               numtc++;
+               }
+               if (!numtc) {
+                       dev_warn(&pf->pdev->dev, "DCB is enabled but no TC enabled, forcing TC0\n");
+                       numtc = 1;
+               }
+       } else {
+               /* At least TC0 is enabled in case of non-DCB case */
+               numtc = 1;
+       }
+
+       vsi->tc_config.numtc = numtc;
+       vsi->tc_config.enabled_tc = enabled_tc ? enabled_tc : 1;
+
+       /* Setup queue offset/count for all TCs for given VSI */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               /* See if the given TC is enabled for the given VSI */
+               if (vsi->tc_config.enabled_tc & (1 << i)) { /* TC is enabled */
+                       int pow, num_qps;
+
+                       vsi->tc_config.tc_info[i].qoffset = offset;
+                       switch (vsi->type) {
+                       case I40E_VSI_MAIN:
+                               if (i == 0)
+                                       qcount = pf->rss_size;
+                               else
+                                       qcount = pf->num_tc_qps;
+                               vsi->tc_config.tc_info[i].qcount = qcount;
+                               break;
+                       case I40E_VSI_FDIR:
+                       case I40E_VSI_SRIOV:
+                       case I40E_VSI_VMDQ2:
+                       default:
+                               qcount = vsi->alloc_queue_pairs;
+                               vsi->tc_config.tc_info[i].qcount = qcount;
+                               WARN_ON(i != 0);
+                               break;
+                       }
+
+                       /* find the power-of-2 of the number of queue pairs */
+                       num_qps = vsi->tc_config.tc_info[i].qcount;
+                       pow = 0;
+                       while (num_qps &&
+                             ((1 << pow) < vsi->tc_config.tc_info[i].qcount)) {
+                               pow++;
+                               num_qps >>= 1;
+                       }
+
+                       vsi->tc_config.tc_info[i].netdev_tc = netdev_tc++;
+                       qmap =
+                           (offset << I40E_AQ_VSI_TC_QUE_OFFSET_SHIFT) |
+                           (pow << I40E_AQ_VSI_TC_QUE_NUMBER_SHIFT);
+
+                       offset += vsi->tc_config.tc_info[i].qcount;
+               } else {
+                       /* TC is not enabled so set the offset to
+                        * default queue and allocate one queue
+                        * for the given TC.
+                        */
+                       vsi->tc_config.tc_info[i].qoffset = 0;
+                       vsi->tc_config.tc_info[i].qcount = 1;
+                       vsi->tc_config.tc_info[i].netdev_tc = 0;
+
+                       qmap = 0;
+               }
+               ctxt->info.tc_mapping[i] = cpu_to_le16(qmap);
+       }
+
+       /* Set actual Tx/Rx queue pairs */
+       vsi->num_queue_pairs = offset;
+
+       /* Scheduler section valid can only be set for ADD VSI */
+       if (is_add) {
+               sections |= I40E_AQ_VSI_PROP_SCHED_VALID;
+
+               ctxt->info.up_enable_bits = enabled_tc;
+       }
+       if (vsi->type == I40E_VSI_SRIOV) {
+               ctxt->info.mapping_flags |=
+                                    cpu_to_le16(I40E_AQ_VSI_QUE_MAP_NONCONTIG);
+               for (i = 0; i < vsi->num_queue_pairs; i++)
+                       ctxt->info.queue_mapping[i] =
+                                              cpu_to_le16(vsi->base_queue + i);
+       } else {
+               ctxt->info.mapping_flags |=
+                                       cpu_to_le16(I40E_AQ_VSI_QUE_MAP_CONTIG);
+               ctxt->info.queue_mapping[0] = cpu_to_le16(vsi->base_queue);
+       }
+       ctxt->info.valid_sections |= cpu_to_le16(sections);
+}
+
+/**
+ * i40e_set_rx_mode - NDO callback to set the netdev filters
+ * @netdev: network interface device structure
+ **/
+static void i40e_set_rx_mode(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_mac_filter *f, *ftmp;
+       struct i40e_vsi *vsi = np->vsi;
+       struct netdev_hw_addr *uca;
+       struct netdev_hw_addr *mca;
+       struct netdev_hw_addr *ha;
+
+       /* add addr if not already in the filter list */
+       netdev_for_each_uc_addr(uca, netdev) {
+               if (!i40e_find_mac(vsi, uca->addr, false, true)) {
+                       if (i40e_is_vsi_in_vlan(vsi))
+                               i40e_put_mac_in_vlan(vsi, uca->addr,
+                                                    false, true);
+                       else
+                               i40e_add_filter(vsi, uca->addr, I40E_VLAN_ANY,
+                                               false, true);
+               }
+       }
+
+       netdev_for_each_mc_addr(mca, netdev) {
+               if (!i40e_find_mac(vsi, mca->addr, false, true)) {
+                       if (i40e_is_vsi_in_vlan(vsi))
+                               i40e_put_mac_in_vlan(vsi, mca->addr,
+                                                    false, true);
+                       else
+                               i40e_add_filter(vsi, mca->addr, I40E_VLAN_ANY,
+                                               false, true);
+               }
+       }
+
+       /* remove filter if not in netdev list */
+       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
+               bool found = false;
+
+               if (!f->is_netdev)
+                       continue;
+
+               if (is_multicast_ether_addr(f->macaddr)) {
+                       netdev_for_each_mc_addr(mca, netdev) {
+                               if (ether_addr_equal(mca->addr, f->macaddr)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+               } else {
+                       netdev_for_each_uc_addr(uca, netdev) {
+                               if (ether_addr_equal(uca->addr, f->macaddr)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+
+                       for_each_dev_addr(netdev, ha) {
+                               if (ether_addr_equal(ha->addr, f->macaddr)) {
+                                       found = true;
+                                       break;
+                               }
+                       }
+               }
+               if (!found)
+                       i40e_del_filter(
+                          vsi, f->macaddr, I40E_VLAN_ANY, false, true);
+       }
+
+       /* check for other flag changes */
+       if (vsi->current_netdev_flags != vsi->netdev->flags) {
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+       }
+}
+
+/**
+ * i40e_sync_vsi_filters - Update the VSI filter list to the HW
+ * @vsi: ptr to the VSI
+ *
+ * Push any outstanding VSI filter changes through the AdminQ.
+ *
+ * Returns 0 or error value
+ **/
+int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
+{
+       struct i40e_mac_filter *f, *ftmp;
+       bool promisc_forced_on = false;
+       bool add_happened = false;
+       int filter_list_len = 0;
+       u32 changed_flags = 0;
+       i40e_status ret = 0;
+       struct i40e_pf *pf;
+       int num_add = 0;
+       int num_del = 0;
+       u16 cmd_flags;
+
+       /* empty array typed pointers, kcalloc later */
+       struct i40e_aqc_add_macvlan_element_data *add_list;
+       struct i40e_aqc_remove_macvlan_element_data *del_list;
+
+       while (test_and_set_bit(__I40E_CONFIG_BUSY, &vsi->state))
+               usleep_range(1000, 2000);
+       pf = vsi->back;
+
+       if (vsi->netdev) {
+               changed_flags = vsi->current_netdev_flags ^ vsi->netdev->flags;
+               vsi->current_netdev_flags = vsi->netdev->flags;
+       }
+
+       if (vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) {
+               vsi->flags &= ~I40E_VSI_FLAG_FILTER_CHANGED;
+
+               filter_list_len = pf->hw.aq.asq_buf_size /
+                           sizeof(struct i40e_aqc_remove_macvlan_element_data);
+               del_list = kcalloc(filter_list_len,
+                           sizeof(struct i40e_aqc_remove_macvlan_element_data),
+                           GFP_KERNEL);
+               if (!del_list)
+                       return -ENOMEM;
+
+               list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
+                       if (!f->changed)
+                               continue;
+
+                       if (f->counter != 0)
+                               continue;
+                       f->changed = false;
+                       cmd_flags = 0;
+
+                       /* add to delete list */
+                       memcpy(del_list[num_del].mac_addr,
+                              f->macaddr, ETH_ALEN);
+                       del_list[num_del].vlan_tag =
+                               cpu_to_le16((u16)(f->vlan ==
+                                           I40E_VLAN_ANY ? 0 : f->vlan));
+
+                       /* vlan0 as wild card to allow packets from all vlans */
+                       if (f->vlan == I40E_VLAN_ANY ||
+                           (vsi->netdev && !(vsi->netdev->features &
+                                             NETIF_F_HW_VLAN_CTAG_FILTER)))
+                               cmd_flags |= I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
+                       cmd_flags |= I40E_AQC_MACVLAN_DEL_PERFECT_MATCH;
+                       del_list[num_del].flags = cmd_flags;
+                       num_del++;
+
+                       /* unlink from filter list */
+                       list_del(&f->list);
+                       kfree(f);
+
+                       /* flush a full buffer */
+                       if (num_del == filter_list_len) {
+                               ret = i40e_aq_remove_macvlan(&pf->hw,
+                                           vsi->seid, del_list, num_del,
+                                           NULL);
+                               num_del = 0;
+                               memset(del_list, 0, sizeof(*del_list));
+
+                               if (ret)
+                                       dev_info(&pf->pdev->dev,
+                                                "ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n",
+                                                ret,
+                                                pf->hw.aq.asq_last_status);
+                       }
+               }
+               if (num_del) {
+                       ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid,
+                                                    del_list, num_del, NULL);
+                       num_del = 0;
+
+                       if (ret)
+                               dev_info(&pf->pdev->dev,
+                                        "ignoring delete macvlan error, err %d, aq_err %d\n",
+                                        ret, pf->hw.aq.asq_last_status);
+               }
+
+               kfree(del_list);
+               del_list = NULL;
+
+               /* do all the adds now */
+               filter_list_len = pf->hw.aq.asq_buf_size /
+                              sizeof(struct i40e_aqc_add_macvlan_element_data),
+               add_list = kcalloc(filter_list_len,
+                              sizeof(struct i40e_aqc_add_macvlan_element_data),
+                              GFP_KERNEL);
+               if (!add_list)
+                       return -ENOMEM;
+
+               list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
+                       if (!f->changed)
+                               continue;
+
+                       if (f->counter == 0)
+                               continue;
+                       f->changed = false;
+                       add_happened = true;
+                       cmd_flags = 0;
+
+                       /* add to add array */
+                       memcpy(add_list[num_add].mac_addr,
+                              f->macaddr, ETH_ALEN);
+                       add_list[num_add].vlan_tag =
+                               cpu_to_le16(
+                                (u16)(f->vlan == I40E_VLAN_ANY ? 0 : f->vlan));
+                       add_list[num_add].queue_number = 0;
+
+                       cmd_flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
+
+                       /* vlan0 as wild card to allow packets from all vlans */
+                       if (f->vlan == I40E_VLAN_ANY || (vsi->netdev &&
+                           !(vsi->netdev->features &
+                                                NETIF_F_HW_VLAN_CTAG_FILTER)))
+                               cmd_flags |= I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
+                       add_list[num_add].flags = cpu_to_le16(cmd_flags);
+                       num_add++;
+
+                       /* flush a full buffer */
+                       if (num_add == filter_list_len) {
+                               ret = i40e_aq_add_macvlan(&pf->hw,
+                                                         vsi->seid,
+                                                         add_list,
+                                                         num_add,
+                                                         NULL);
+                               num_add = 0;
+
+                               if (ret)
+                                       break;
+                               memset(add_list, 0, sizeof(*add_list));
+                       }
+               }
+               if (num_add) {
+                       ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid,
+                                                 add_list, num_add, NULL);
+                       num_add = 0;
+               }
+               kfree(add_list);
+               add_list = NULL;
+
+               if (add_happened && (!ret)) {
+                       /* do nothing */;
+               } else if (add_happened && (ret)) {
+                       dev_info(&pf->pdev->dev,
+                                "add filter failed, err %d, aq_err %d\n",
+                                ret, pf->hw.aq.asq_last_status);
+                       if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) &&
+                           !test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
+                                     &vsi->state)) {
+                               promisc_forced_on = true;
+                               set_bit(__I40E_FILTER_OVERFLOW_PROMISC,
+                                       &vsi->state);
+                               dev_info(&pf->pdev->dev, "promiscuous mode forced on\n");
+                       }
+               }
+       }
+
+       /* check for changes in promiscuous modes */
+       if (changed_flags & IFF_ALLMULTI) {
+               bool cur_multipromisc;
+               cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI);
+               ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw,
+                                                           vsi->seid,
+                                                           cur_multipromisc,
+                                                           NULL);
+               if (ret)
+                       dev_info(&pf->pdev->dev,
+                                "set multi promisc failed, err %d, aq_err %d\n",
+                                ret, pf->hw.aq.asq_last_status);
+       }
+       if ((changed_flags & IFF_PROMISC) || promisc_forced_on) {
+               bool cur_promisc;
+               cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) ||
+                              test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
+                                       &vsi->state));
+               ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw,
+                                                         vsi->seid,
+                                                         cur_promisc,
+                                                         NULL);
+               if (ret)
+                       dev_info(&pf->pdev->dev,
+                                "set uni promisc failed, err %d, aq_err %d\n",
+                                ret, pf->hw.aq.asq_last_status);
+       }
+
+       clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
+       return 0;
+}
+
+/**
+ * i40e_sync_filters_subtask - Sync the VSI filter list with HW
+ * @pf: board private structure
+ **/
+static void i40e_sync_filters_subtask(struct i40e_pf *pf)
+{
+       int v;
+
+       if (!pf || !(pf->flags & I40E_FLAG_FILTER_SYNC))
+               return;
+       pf->flags &= ~I40E_FLAG_FILTER_SYNC;
+
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               if (pf->vsi[v] &&
+                   (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED))
+                       i40e_sync_vsi_filters(pf->vsi[v]);
+       }
+}
+
+/**
+ * i40e_change_mtu - NDO callback to change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+       struct i40e_vsi *vsi = np->vsi;
+
+       /* MTU < 68 is an error and causes problems on some kernels */
+       if ((new_mtu < 68) || (max_frame > I40E_MAX_RXBUFFER))
+               return -EINVAL;
+
+       netdev_info(netdev, "changing MTU from %d to %d\n",
+                   netdev->mtu, new_mtu);
+       netdev->mtu = new_mtu;
+       if (netif_running(netdev))
+               i40e_vsi_reinit_locked(vsi);
+
+       return 0;
+}
+
+/**
+ * i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI
+ * @vsi: the vsi being adjusted
+ **/
+void i40e_vlan_stripping_enable(struct i40e_vsi *vsi)
+{
+       struct i40e_vsi_context ctxt;
+       i40e_status ret;
+
+       if ((vsi->info.valid_sections &
+            cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID)) &&
+           ((vsi->info.port_vlan_flags & I40E_AQ_VSI_PVLAN_MODE_MASK) == 0))
+               return;  /* already enabled */
+
+       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
+       vsi->info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
+                                   I40E_AQ_VSI_PVLAN_EMOD_STR_BOTH;
+
+       ctxt.seid = vsi->seid;
+       memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+       ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "%s: update vsi failed, aq_err=%d\n",
+                        __func__, vsi->back->hw.aq.asq_last_status);
+       }
+}
+
+/**
+ * i40e_vlan_stripping_disable - Turn off vlan stripping for the VSI
+ * @vsi: the vsi being adjusted
+ **/
+void i40e_vlan_stripping_disable(struct i40e_vsi *vsi)
+{
+       struct i40e_vsi_context ctxt;
+       i40e_status ret;
+
+       if ((vsi->info.valid_sections &
+            cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID)) &&
+           ((vsi->info.port_vlan_flags & I40E_AQ_VSI_PVLAN_EMOD_MASK) ==
+            I40E_AQ_VSI_PVLAN_EMOD_MASK))
+               return;  /* already disabled */
+
+       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
+       vsi->info.port_vlan_flags = I40E_AQ_VSI_PVLAN_MODE_ALL |
+                                   I40E_AQ_VSI_PVLAN_EMOD_NOTHING;
+
+       ctxt.seid = vsi->seid;
+       memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+       ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "%s: update vsi failed, aq_err=%d\n",
+                        __func__, vsi->back->hw.aq.asq_last_status);
+       }
+}
+
+/**
+ * i40e_vlan_rx_register - Setup or shutdown vlan offload
+ * @netdev: network interface to be adjusted
+ * @features: netdev features to test if VLAN offload is enabled or not
+ **/
+static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (features & NETIF_F_HW_VLAN_CTAG_RX)
+               i40e_vlan_stripping_enable(vsi);
+       else
+               i40e_vlan_stripping_disable(vsi);
+}
+
+/**
+ * i40e_vsi_add_vlan - Add vsi membership for given vlan
+ * @vsi: the vsi being configured
+ * @vid: vlan id to be added (0 = untagged only , -1 = any)
+ **/
+int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
+{
+       struct i40e_mac_filter *f, *add_f;
+       bool is_netdev, is_vf;
+       int ret;
+
+       is_vf = (vsi->type == I40E_VSI_SRIOV);
+       is_netdev = !!(vsi->netdev);
+
+       if (is_netdev) {
+               add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, vid,
+                                       is_vf, is_netdev);
+               if (!add_f) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "Could not add vlan filter %d for %pM\n",
+                                vid, vsi->netdev->dev_addr);
+                       return -ENOMEM;
+               }
+       }
+
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               add_f = i40e_add_filter(vsi, f->macaddr, vid, is_vf, is_netdev);
+               if (!add_f) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "Could not add vlan filter %d for %pM\n",
+                                vid, f->macaddr);
+                       return -ENOMEM;
+               }
+       }
+
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Could not sync filters for vid %d\n", vid);
+               return ret;
+       }
+
+       /* Now if we add a vlan tag, make sure to check if it is the first
+        * tag (i.e. a "tag" -1 does exist) and if so replace the -1 "tag"
+        * with 0, so we now accept untagged and specified tagged traffic
+        * (and not any taged and untagged)
+        */
+       if (vid > 0) {
+               if (is_netdev && i40e_find_filter(vsi, vsi->netdev->dev_addr,
+                                                 I40E_VLAN_ANY,
+                                                 is_vf, is_netdev)) {
+                       i40e_del_filter(vsi, vsi->netdev->dev_addr,
+                                       I40E_VLAN_ANY, is_vf, is_netdev);
+                       add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, 0,
+                                               is_vf, is_netdev);
+                       if (!add_f) {
+                               dev_info(&vsi->back->pdev->dev,
+                                        "Could not add filter 0 for %pM\n",
+                                        vsi->netdev->dev_addr);
+                               return -ENOMEM;
+                       }
+               }
+
+               list_for_each_entry(f, &vsi->mac_filter_list, list) {
+                       if (i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY,
+                                            is_vf, is_netdev)) {
+                               i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY,
+                                               is_vf, is_netdev);
+                               add_f = i40e_add_filter(vsi, f->macaddr,
+                                                       0, is_vf, is_netdev);
+                               if (!add_f) {
+                                       dev_info(&vsi->back->pdev->dev,
+                                                "Could not add filter 0 for %pM\n",
+                                                f->macaddr);
+                                       return -ENOMEM;
+                               }
+                       }
+               }
+               ret = i40e_sync_vsi_filters(vsi);
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_vsi_kill_vlan - Remove vsi membership for given vlan
+ * @vsi: the vsi being configured
+ * @vid: vlan id to be removed (0 = untagged only , -1 = any)
+ **/
+int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
+{
+       struct net_device *netdev = vsi->netdev;
+       struct i40e_mac_filter *f, *add_f;
+       bool is_vf, is_netdev;
+       int filter_count = 0;
+       int ret;
+
+       is_vf = (vsi->type == I40E_VSI_SRIOV);
+       is_netdev = !!(netdev);
+
+       if (is_netdev)
+               i40e_del_filter(vsi, netdev->dev_addr, vid, is_vf, is_netdev);
+
+       list_for_each_entry(f, &vsi->mac_filter_list, list)
+               i40e_del_filter(vsi, f->macaddr, vid, is_vf, is_netdev);
+
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev, "Could not sync filters\n");
+               return ret;
+       }
+
+       /* go through all the filters for this VSI and if there is only
+        * vid == 0 it means there are no other filters, so vid 0 must
+        * be replaced with -1. This signifies that we should from now
+        * on accept any traffic (with any tag present, or untagged)
+        */
+       list_for_each_entry(f, &vsi->mac_filter_list, list) {
+               if (is_netdev) {
+                       if (f->vlan &&
+                           ether_addr_equal(netdev->dev_addr, f->macaddr))
+                               filter_count++;
+               }
+
+               if (f->vlan)
+                       filter_count++;
+       }
+
+       if (!filter_count && is_netdev) {
+               i40e_del_filter(vsi, netdev->dev_addr, 0, is_vf, is_netdev);
+               f = i40e_add_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY,
+                                   is_vf, is_netdev);
+               if (!f) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "Could not add filter %d for %pM\n",
+                                I40E_VLAN_ANY, netdev->dev_addr);
+                       return -ENOMEM;
+               }
+       }
+
+       if (!filter_count) {
+               list_for_each_entry(f, &vsi->mac_filter_list, list) {
+                       i40e_del_filter(vsi, f->macaddr, 0, is_vf, is_netdev);
+                       add_f = i40e_add_filter(vsi, f->macaddr, I40E_VLAN_ANY,
+                                           is_vf, is_netdev);
+                       if (!add_f) {
+                               dev_info(&vsi->back->pdev->dev,
+                                        "Could not add filter %d for %pM\n",
+                                        I40E_VLAN_ANY, f->macaddr);
+                               return -ENOMEM;
+                       }
+               }
+       }
+
+       return i40e_sync_vsi_filters(vsi);
+}
+
+/**
+ * i40e_vlan_rx_add_vid - Add a vlan id filter to HW offload
+ * @netdev: network interface to be adjusted
+ * @vid: vlan id to be added
+ **/
+static int i40e_vlan_rx_add_vid(struct net_device *netdev,
+                               __always_unused __be16 proto, u16 vid)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       int ret;
+
+       if (vid > 4095)
+               return 0;
+
+       netdev_info(vsi->netdev, "adding %pM vid=%d\n",
+                   netdev->dev_addr, vid);
+       /* If the network stack called us with vid = 0, we should
+        * indicate to i40e_vsi_add_vlan() that we want to receive
+        * any traffic (i.e. with any vlan tag, or untagged)
+        */
+       ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY);
+
+       if (!ret) {
+               if (vid < VLAN_N_VID)
+                       set_bit(vid, vsi->active_vlans);
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vlan_rx_kill_vid - Remove a vlan id filter from HW offload
+ * @netdev: network interface to be adjusted
+ * @vid: vlan id to be removed
+ **/
+static int i40e_vlan_rx_kill_vid(struct net_device *netdev,
+                                __always_unused __be16 proto, u16 vid)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       netdev_info(vsi->netdev, "removing %pM vid=%d\n",
+                   netdev->dev_addr, vid);
+       /* return code is ignored as there is nothing a user
+        * can do about failure to remove and a log message was
+        * already printed from another function
+        */
+       i40e_vsi_kill_vlan(vsi, vid);
+
+       clear_bit(vid, vsi->active_vlans);
+       return 0;
+}
+
+/**
+ * i40e_restore_vlan - Reinstate vlans when vsi/netdev comes back up
+ * @vsi: the vsi being brought back up
+ **/
+static void i40e_restore_vlan(struct i40e_vsi *vsi)
+{
+       u16 vid;
+
+       if (!vsi->netdev)
+               return;
+
+       i40e_vlan_rx_register(vsi->netdev, vsi->netdev->features);
+
+       for_each_set_bit(vid, vsi->active_vlans, VLAN_N_VID)
+               i40e_vlan_rx_add_vid(vsi->netdev, htons(ETH_P_8021Q),
+                                    vid);
+}
+
+/**
+ * i40e_vsi_add_pvid - Add pvid for the VSI
+ * @vsi: the vsi being adjusted
+ * @vid: the vlan id to set as a PVID
+ **/
+i40e_status i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid)
+{
+       struct i40e_vsi_context ctxt;
+       i40e_status ret;
+
+       vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
+       vsi->info.pvid = cpu_to_le16(vid);
+       vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_INSERT_PVID;
+       vsi->info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_UNTAGGED;
+
+       ctxt.seid = vsi->seid;
+       memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+       ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "%s: update vsi failed, aq_err=%d\n",
+                        __func__, vsi->back->hw.aq.asq_last_status);
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_vsi_remove_pvid - Remove the pvid from the VSI
+ * @vsi: the vsi being adjusted
+ *
+ * Just use the vlan_rx_register() service to put it back to normal
+ **/
+void i40e_vsi_remove_pvid(struct i40e_vsi *vsi)
+{
+       vsi->info.pvid = 0;
+       i40e_vlan_rx_register(vsi->netdev, vsi->netdev->features);
+}
+
+/**
+ * i40e_vsi_setup_tx_resources - Allocate VSI Tx queue resources
+ * @vsi: ptr to the VSI
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int i40e_vsi_setup_tx_resources(struct i40e_vsi *vsi)
+{
+       int i, err = 0;
+
+       for (i = 0; i < vsi->num_queue_pairs && !err; i++)
+               err = i40e_setup_tx_descriptors(&vsi->tx_rings[i]);
+
+       return err;
+}
+
+/**
+ * i40e_vsi_free_tx_resources - Free Tx resources for VSI queues
+ * @vsi: ptr to the VSI
+ *
+ * Free VSI's transmit software resources
+ **/
+static void i40e_vsi_free_tx_resources(struct i40e_vsi *vsi)
+{
+       int i;
+
+       for (i = 0; i < vsi->num_queue_pairs; i++)
+               if (vsi->tx_rings[i].desc)
+                       i40e_free_tx_resources(&vsi->tx_rings[i]);
+}
+
+/**
+ * i40e_vsi_setup_rx_resources - Allocate VSI queues Rx resources
+ * @vsi: ptr to the VSI
+ *
+ * If this function returns with an error, then it's possible one or
+ * more of the rings is populated (while the rest are not).  It is the
+ * callers duty to clean those orphaned rings.
+ *
+ * Return 0 on success, negative on failure
+ **/
+static int i40e_vsi_setup_rx_resources(struct i40e_vsi *vsi)
+{
+       int i, err = 0;
+
+       for (i = 0; i < vsi->num_queue_pairs && !err; i++)
+               err = i40e_setup_rx_descriptors(&vsi->rx_rings[i]);
+       return err;
+}
+
+/**
+ * i40e_vsi_free_rx_resources - Free Rx Resources for VSI queues
+ * @vsi: ptr to the VSI
+ *
+ * Free all receive software resources
+ **/
+static void i40e_vsi_free_rx_resources(struct i40e_vsi *vsi)
+{
+       int i;
+
+       for (i = 0; i < vsi->num_queue_pairs; i++)
+               if (vsi->rx_rings[i].desc)
+                       i40e_free_rx_resources(&vsi->rx_rings[i]);
+}
+
+/**
+ * i40e_configure_tx_ring - Configure a transmit ring context and rest
+ * @ring: The Tx ring to configure
+ *
+ * Configure the Tx descriptor ring in the HMC context.
+ **/
+static int i40e_configure_tx_ring(struct i40e_ring *ring)
+{
+       struct i40e_vsi *vsi = ring->vsi;
+       u16 pf_q = vsi->base_queue + ring->queue_index;
+       struct i40e_hw *hw = &vsi->back->hw;
+       struct i40e_hmc_obj_txq tx_ctx;
+       i40e_status err = 0;
+       u32 qtx_ctl = 0;
+
+       /* some ATR related tx ring init */
+       if (vsi->back->flags & I40E_FLAG_FDIR_ATR_ENABLED) {
+               ring->atr_sample_rate = vsi->back->atr_sample_rate;
+               ring->atr_count = 0;
+       } else {
+               ring->atr_sample_rate = 0;
+       }
+
+       /* initialize XPS */
+       if (ring->q_vector && ring->netdev &&
+           !test_and_set_bit(__I40E_TX_XPS_INIT_DONE, &ring->state))
+               netif_set_xps_queue(ring->netdev,
+                                   &ring->q_vector->affinity_mask,
+                                   ring->queue_index);
+
+       /* clear the context structure first */
+       memset(&tx_ctx, 0, sizeof(tx_ctx));
+
+       tx_ctx.new_context = 1;
+       tx_ctx.base = (ring->dma / 128);
+       tx_ctx.qlen = ring->count;
+       tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED |
+                       I40E_FLAG_FDIR_ATR_ENABLED));
+
+       /* As part of VSI creation/update, FW allocates certain
+        * Tx arbitration queue sets for each TC enabled for
+        * the VSI. The FW returns the handles to these queue
+        * sets as part of the response buffer to Add VSI,
+        * Update VSI, etc. AQ commands. It is expected that
+        * these queue set handles be associated with the Tx
+        * queues by the driver as part of the TX queue context
+        * initialization. This has to be done regardless of
+        * DCB as by default everything is mapped to TC0.
+        */
+       tx_ctx.rdylist = le16_to_cpu(vsi->info.qs_handle[ring->dcb_tc]);
+       tx_ctx.rdylist_act = 0;
+
+       /* clear the context in the HMC */
+       err = i40e_clear_lan_tx_queue_context(hw, pf_q);
+       if (err) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed to clear LAN Tx queue context on Tx ring %d (pf_q %d), error: %d\n",
+                        ring->queue_index, pf_q, err);
+               return -ENOMEM;
+       }
+
+       /* set the context in the HMC */
+       err = i40e_set_lan_tx_queue_context(hw, pf_q, &tx_ctx);
+       if (err) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed to set LAN Tx queue context on Tx ring %d (pf_q %d, error: %d\n",
+                        ring->queue_index, pf_q, err);
+               return -ENOMEM;
+       }
+
+       /* Now associate this queue with this PCI function */
+       qtx_ctl = I40E_QTX_CTL_PF_QUEUE;
+       qtx_ctl |= ((hw->hmc.hmc_fn_id << I40E_QTX_CTL_PF_INDX_SHIFT)
+                                               & I40E_QTX_CTL_PF_INDX_MASK);
+       wr32(hw, I40E_QTX_CTL(pf_q), qtx_ctl);
+       i40e_flush(hw);
+
+       clear_bit(__I40E_HANG_CHECK_ARMED, &ring->state);
+
+       /* cache tail off for easier writes later */
+       ring->tail = hw->hw_addr + I40E_QTX_TAIL(pf_q);
+
+       return 0;
+}
+
+/**
+ * i40e_configure_rx_ring - Configure a receive ring context
+ * @ring: The Rx ring to configure
+ *
+ * Configure the Rx descriptor ring in the HMC context.
+ **/
+static int i40e_configure_rx_ring(struct i40e_ring *ring)
+{
+       struct i40e_vsi *vsi = ring->vsi;
+       u32 chain_len = vsi->back->hw.func_caps.rx_buf_chain_len;
+       u16 pf_q = vsi->base_queue + ring->queue_index;
+       struct i40e_hw *hw = &vsi->back->hw;
+       struct i40e_hmc_obj_rxq rx_ctx;
+       i40e_status err = 0;
+
+       ring->state = 0;
+
+       /* clear the context structure first */
+       memset(&rx_ctx, 0, sizeof(rx_ctx));
+
+       ring->rx_buf_len = vsi->rx_buf_len;
+       ring->rx_hdr_len = vsi->rx_hdr_len;
+
+       rx_ctx.dbuff = ring->rx_buf_len >> I40E_RXQ_CTX_DBUFF_SHIFT;
+       rx_ctx.hbuff = ring->rx_hdr_len >> I40E_RXQ_CTX_HBUFF_SHIFT;
+
+       rx_ctx.base = (ring->dma / 128);
+       rx_ctx.qlen = ring->count;
+
+       if (vsi->back->flags & I40E_FLAG_16BYTE_RX_DESC_ENABLED) {
+               set_ring_16byte_desc_enabled(ring);
+               rx_ctx.dsize = 0;
+       } else {
+               rx_ctx.dsize = 1;
+       }
+
+       rx_ctx.dtype = vsi->dtype;
+       if (vsi->dtype) {
+               set_ring_ps_enabled(ring);
+               rx_ctx.hsplit_0 = I40E_RX_SPLIT_L2      |
+                                 I40E_RX_SPLIT_IP      |
+                                 I40E_RX_SPLIT_TCP_UDP |
+                                 I40E_RX_SPLIT_SCTP;
+       } else {
+               rx_ctx.hsplit_0 = 0;
+       }
+
+       rx_ctx.rxmax = min_t(u16, vsi->max_frame,
+                                 (chain_len * ring->rx_buf_len));
+       rx_ctx.tphrdesc_ena = 1;
+       rx_ctx.tphwdesc_ena = 1;
+       rx_ctx.tphdata_ena = 1;
+       rx_ctx.tphhead_ena = 1;
+       rx_ctx.lrxqthresh = 2;
+       rx_ctx.crcstrip = 1;
+       rx_ctx.l2tsel = 1;
+       rx_ctx.showiv = 1;
+
+       /* clear the context in the HMC */
+       err = i40e_clear_lan_rx_queue_context(hw, pf_q);
+       if (err) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed to clear LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
+                        ring->queue_index, pf_q, err);
+               return -ENOMEM;
+       }
+
+       /* set the context in the HMC */
+       err = i40e_set_lan_rx_queue_context(hw, pf_q, &rx_ctx);
+       if (err) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed to set LAN Rx queue context on Rx ring %d (pf_q %d), error: %d\n",
+                        ring->queue_index, pf_q, err);
+               return -ENOMEM;
+       }
+
+       /* cache tail for quicker writes, and clear the reg before use */
+       ring->tail = hw->hw_addr + I40E_QRX_TAIL(pf_q);
+       writel(0, ring->tail);
+
+       i40e_alloc_rx_buffers(ring, I40E_DESC_UNUSED(ring));
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_configure_tx - Configure the VSI for Tx
+ * @vsi: VSI structure describing this set of rings and resources
+ *
+ * Configure the Tx VSI for operation.
+ **/
+static int i40e_vsi_configure_tx(struct i40e_vsi *vsi)
+{
+       int err = 0;
+       u16 i;
+
+       for (i = 0; (i < vsi->num_queue_pairs) && (!err); i++)
+               err = i40e_configure_tx_ring(&vsi->tx_rings[i]);
+
+       return err;
+}
+
+/**
+ * i40e_vsi_configure_rx - Configure the VSI for Rx
+ * @vsi: the VSI being configured
+ *
+ * Configure the Rx VSI for operation.
+ **/
+static int i40e_vsi_configure_rx(struct i40e_vsi *vsi)
+{
+       int err = 0;
+       u16 i;
+
+       if (vsi->netdev && (vsi->netdev->mtu > ETH_DATA_LEN))
+               vsi->max_frame = vsi->netdev->mtu + ETH_HLEN
+                              + ETH_FCS_LEN + VLAN_HLEN;
+       else
+               vsi->max_frame = I40E_RXBUFFER_2048;
+
+       /* figure out correct receive buffer length */
+       switch (vsi->back->flags & (I40E_FLAG_RX_1BUF_ENABLED |
+                                   I40E_FLAG_RX_PS_ENABLED)) {
+       case I40E_FLAG_RX_1BUF_ENABLED:
+               vsi->rx_hdr_len = 0;
+               vsi->rx_buf_len = vsi->max_frame;
+               vsi->dtype = I40E_RX_DTYPE_NO_SPLIT;
+               break;
+       case I40E_FLAG_RX_PS_ENABLED:
+               vsi->rx_hdr_len = I40E_RX_HDR_SIZE;
+               vsi->rx_buf_len = I40E_RXBUFFER_2048;
+               vsi->dtype = I40E_RX_DTYPE_HEADER_SPLIT;
+               break;
+       default:
+               vsi->rx_hdr_len = I40E_RX_HDR_SIZE;
+               vsi->rx_buf_len = I40E_RXBUFFER_2048;
+               vsi->dtype = I40E_RX_DTYPE_SPLIT_ALWAYS;
+               break;
+       }
+
+       /* round up for the chip's needs */
+       vsi->rx_hdr_len = ALIGN(vsi->rx_hdr_len,
+                               (1 << I40E_RXQ_CTX_HBUFF_SHIFT));
+       vsi->rx_buf_len = ALIGN(vsi->rx_buf_len,
+                               (1 << I40E_RXQ_CTX_DBUFF_SHIFT));
+
+       /* set up individual rings */
+       for (i = 0; i < vsi->num_queue_pairs && !err; i++)
+               err = i40e_configure_rx_ring(&vsi->rx_rings[i]);
+
+       return err;
+}
+
+/**
+ * i40e_vsi_config_dcb_rings - Update rings to reflect DCB TC
+ * @vsi: ptr to the VSI
+ **/
+static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi)
+{
+       u16 qoffset, qcount;
+       int i, n;
+
+       if (!(vsi->back->flags & I40E_FLAG_DCB_ENABLED))
+               return;
+
+       for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) {
+               if (!(vsi->tc_config.enabled_tc & (1 << n)))
+                       continue;
+
+               qoffset = vsi->tc_config.tc_info[n].qoffset;
+               qcount = vsi->tc_config.tc_info[n].qcount;
+               for (i = qoffset; i < (qoffset + qcount); i++) {
+                       struct i40e_ring *rx_ring = &vsi->rx_rings[i];
+                       struct i40e_ring *tx_ring = &vsi->tx_rings[i];
+                       rx_ring->dcb_tc = n;
+                       tx_ring->dcb_tc = n;
+               }
+       }
+}
+
+/**
+ * i40e_set_vsi_rx_mode - Call set_rx_mode on a VSI
+ * @vsi: ptr to the VSI
+ **/
+static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi)
+{
+       if (vsi->netdev)
+               i40e_set_rx_mode(vsi->netdev);
+}
+
+/**
+ * i40e_vsi_configure - Set up the VSI for action
+ * @vsi: the VSI being configured
+ **/
+static int i40e_vsi_configure(struct i40e_vsi *vsi)
+{
+       int err;
+
+       i40e_set_vsi_rx_mode(vsi);
+       i40e_restore_vlan(vsi);
+       i40e_vsi_config_dcb_rings(vsi);
+       err = i40e_vsi_configure_tx(vsi);
+       if (!err)
+               err = i40e_vsi_configure_rx(vsi);
+
+       return err;
+}
+
+/**
+ * i40e_vsi_configure_msix - MSIX mode Interrupt Config in the HW
+ * @vsi: the VSI being configured
+ **/
+static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_q_vector *q_vector;
+       struct i40e_hw *hw = &pf->hw;
+       u16 vector;
+       int i, q;
+       u32 val;
+       u32 qp;
+
+       /* The interrupt indexing is offset by 1 in the PFINT_ITRn
+        * and PFINT_LNKLSTn registers, e.g.:
+        *   PFINT_ITRn[0..n-1] gets msix-1..msix-n  (qpair interrupts)
+        */
+       qp = vsi->base_queue;
+       vector = vsi->base_vector;
+       q_vector = vsi->q_vectors;
+       for (i = 0; i < vsi->num_q_vectors; i++, q_vector++, vector++) {
+               q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+               q_vector->rx.latency_range = I40E_LOW_LATENCY;
+               wr32(hw, I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1),
+                    q_vector->rx.itr);
+               q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+               q_vector->tx.latency_range = I40E_LOW_LATENCY;
+               wr32(hw, I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1),
+                    q_vector->tx.itr);
+
+               /* Linked list for the queuepairs assigned to this vector */
+               wr32(hw, I40E_PFINT_LNKLSTN(vector - 1), qp);
+               for (q = 0; q < q_vector->num_ringpairs; q++) {
+                       val = I40E_QINT_RQCTL_CAUSE_ENA_MASK |
+                             (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT)  |
+                             (vector      << I40E_QINT_RQCTL_MSIX_INDX_SHIFT) |
+                             (qp          << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT)|
+                             (I40E_QUEUE_TYPE_TX
+                                     << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT);
+
+                       wr32(hw, I40E_QINT_RQCTL(qp), val);
+
+                       val = I40E_QINT_TQCTL_CAUSE_ENA_MASK |
+                             (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT)  |
+                             (vector      << I40E_QINT_TQCTL_MSIX_INDX_SHIFT) |
+                             ((qp+1)      << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT)|
+                             (I40E_QUEUE_TYPE_RX
+                                     << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
+
+                       /* Terminate the linked list */
+                       if (q == (q_vector->num_ringpairs - 1))
+                               val |= (I40E_QUEUE_END_OF_LIST
+                                          << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
+
+                       wr32(hw, I40E_QINT_TQCTL(qp), val);
+                       qp++;
+               }
+       }
+
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_enable_misc_int_causes - enable the non-queue interrupts
+ * @hw: ptr to the hardware info
+ **/
+static void i40e_enable_misc_int_causes(struct i40e_hw *hw)
+{
+       u32 val;
+
+       /* clear things first */
+       wr32(hw, I40E_PFINT_ICR0_ENA, 0);  /* disable all */
+       rd32(hw, I40E_PFINT_ICR0);         /* read to clear */
+
+       val = I40E_PFINT_ICR0_ENA_ECC_ERR_MASK       |
+             I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK    |
+             I40E_PFINT_ICR0_ENA_GRST_MASK          |
+             I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK |
+             I40E_PFINT_ICR0_ENA_GPIO_MASK          |
+             I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK  |
+             I40E_PFINT_ICR0_ENA_HMC_ERR_MASK       |
+             I40E_PFINT_ICR0_ENA_VFLR_MASK          |
+             I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
+
+       wr32(hw, I40E_PFINT_ICR0_ENA, val);
+
+       /* SW_ITR_IDX = 0, but don't change INTENA */
+       wr32(hw, I40E_PFINT_DYN_CTL0, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK |
+                                       I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK);
+
+       /* OTHER_ITR_IDX = 0 */
+       wr32(hw, I40E_PFINT_STAT_CTL0, 0);
+}
+
+/**
+ * i40e_configure_msi_and_legacy - Legacy mode interrupt config in the HW
+ * @vsi: the VSI being configured
+ **/
+static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
+{
+       struct i40e_q_vector *q_vector = vsi->q_vectors;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u32 val;
+
+       /* set the ITR configuration */
+       q_vector->rx.itr = ITR_TO_REG(vsi->rx_itr_setting);
+       q_vector->rx.latency_range = I40E_LOW_LATENCY;
+       wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), q_vector->rx.itr);
+       q_vector->tx.itr = ITR_TO_REG(vsi->tx_itr_setting);
+       q_vector->tx.latency_range = I40E_LOW_LATENCY;
+       wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr);
+
+       i40e_enable_misc_int_causes(hw);
+
+       /* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
+       wr32(hw, I40E_PFINT_LNKLST0, 0);
+
+       /* Associate the queue pair to the vector and enable the q int */
+       val = I40E_QINT_RQCTL_CAUSE_ENA_MASK                  |
+             (I40E_RX_ITR << I40E_QINT_RQCTL_ITR_INDX_SHIFT) |
+             (I40E_QUEUE_TYPE_TX << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT);
+
+       wr32(hw, I40E_QINT_RQCTL(0), val);
+
+       val = I40E_QINT_TQCTL_CAUSE_ENA_MASK                  |
+             (I40E_TX_ITR << I40E_QINT_TQCTL_ITR_INDX_SHIFT) |
+             (I40E_QUEUE_END_OF_LIST << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT);
+
+       wr32(hw, I40E_QINT_TQCTL(0), val);
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_irq_dynamic_enable_icr0 - Enable default interrupt generation for icr0
+ * @pf: board private structure
+ **/
+static void i40e_irq_dynamic_enable_icr0(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u32 val;
+
+       val = I40E_PFINT_DYN_CTL0_INTENA_MASK   |
+             I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+             (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT);
+
+       wr32(hw, I40E_PFINT_DYN_CTL0, val);
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_irq_dynamic_enable - Enable default interrupt generation settings
+ * @vsi: pointer to a vsi
+ * @vector: enable a particular Hw Interrupt vector
+ **/
+void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u32 val;
+
+       val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
+             I40E_PFINT_DYN_CTLN_CLEARPBA_MASK |
+             (I40E_ITR_NONE << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT);
+       wr32(hw, I40E_PFINT_DYN_CTLN(vector - 1), val);
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_msix_clean_rings - MSIX mode Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ **/
+static irqreturn_t i40e_msix_clean_rings(int irq, void *data)
+{
+       struct i40e_q_vector *q_vector = data;
+
+       if (!q_vector->tx.ring[0] && !q_vector->rx.ring[0])
+               return IRQ_HANDLED;
+
+       napi_schedule(&q_vector->napi);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * i40e_fdir_clean_rings - Interrupt Handler for FDIR rings
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ **/
+static irqreturn_t i40e_fdir_clean_rings(int irq, void *data)
+{
+       struct i40e_q_vector *q_vector = data;
+
+       if (!q_vector->tx.ring[0] && !q_vector->rx.ring[0])
+               return IRQ_HANDLED;
+
+       pr_info("fdir ring cleaning needed\n");
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * i40e_vsi_request_irq_msix - Initialize MSI-X interrupts
+ * @vsi: the VSI being configured
+ * @basename: name for the vector
+ *
+ * Allocates MSI-X vectors and requests interrupts from the kernel.
+ **/
+static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
+{
+       int q_vectors = vsi->num_q_vectors;
+       struct i40e_pf *pf = vsi->back;
+       int base = vsi->base_vector;
+       int rx_int_idx = 0;
+       int tx_int_idx = 0;
+       int vector, err;
+
+       for (vector = 0; vector < q_vectors; vector++) {
+               struct i40e_q_vector *q_vector = &(vsi->q_vectors[vector]);
+
+               if (q_vector->tx.ring[0] && q_vector->rx.ring[0]) {
+                       snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+                                "%s-%s-%d", basename, "TxRx", rx_int_idx++);
+                       tx_int_idx++;
+               } else if (q_vector->rx.ring[0]) {
+                       snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+                                "%s-%s-%d", basename, "rx", rx_int_idx++);
+               } else if (q_vector->tx.ring[0]) {
+                       snprintf(q_vector->name, sizeof(q_vector->name) - 1,
+                                "%s-%s-%d", basename, "tx", tx_int_idx++);
+               } else {
+                       /* skip this unused q_vector */
+                       continue;
+               }
+               err = request_irq(pf->msix_entries[base + vector].vector,
+                                 vsi->irq_handler,
+                                 0,
+                                 q_vector->name,
+                                 q_vector);
+               if (err) {
+                       dev_info(&pf->pdev->dev,
+                                "%s: request_irq failed, error: %d\n",
+                                __func__, err);
+                       goto free_queue_irqs;
+               }
+               /* assign the mask for this irq */
+               irq_set_affinity_hint(pf->msix_entries[base + vector].vector,
+                                     &q_vector->affinity_mask);
+       }
+
+       return 0;
+
+free_queue_irqs:
+       while (vector) {
+               vector--;
+               irq_set_affinity_hint(pf->msix_entries[base + vector].vector,
+                                     NULL);
+               free_irq(pf->msix_entries[base + vector].vector,
+                        &(vsi->q_vectors[vector]));
+       }
+       return err;
+}
+
+/**
+ * i40e_vsi_disable_irq - Mask off queue interrupt generation on the VSI
+ * @vsi: the VSI being un-configured
+ **/
+static void i40e_vsi_disable_irq(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int base = vsi->base_vector;
+       int i;
+
+       for (i = 0; i < vsi->num_queue_pairs; i++) {
+               wr32(hw, I40E_QINT_TQCTL(vsi->tx_rings[i].reg_idx), 0);
+               wr32(hw, I40E_QINT_RQCTL(vsi->rx_rings[i].reg_idx), 0);
+       }
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               for (i = vsi->base_vector;
+                    i < (vsi->num_q_vectors + vsi->base_vector); i++)
+                       wr32(hw, I40E_PFINT_DYN_CTLN(i - 1), 0);
+
+               i40e_flush(hw);
+               for (i = 0; i < vsi->num_q_vectors; i++)
+                       synchronize_irq(pf->msix_entries[i + base].vector);
+       } else {
+               /* Legacy and MSI mode - this stops all interrupt handling */
+               wr32(hw, I40E_PFINT_ICR0_ENA, 0);
+               wr32(hw, I40E_PFINT_DYN_CTL0, 0);
+               i40e_flush(hw);
+               synchronize_irq(pf->pdev->irq);
+       }
+}
+
+/**
+ * i40e_vsi_enable_irq - Enable IRQ for the given VSI
+ * @vsi: the VSI being configured
+ **/
+static int i40e_vsi_enable_irq(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       int i;
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               for (i = vsi->base_vector;
+                    i < (vsi->num_q_vectors + vsi->base_vector); i++)
+                       i40e_irq_dynamic_enable(vsi, i);
+       } else {
+               i40e_irq_dynamic_enable_icr0(pf);
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_stop_misc_vector - Stop the vector that handles non-queue events
+ * @pf: board private structure
+ **/
+static void i40e_stop_misc_vector(struct i40e_pf *pf)
+{
+       /* Disable ICR 0 */
+       wr32(&pf->hw, I40E_PFINT_ICR0_ENA, 0);
+       i40e_flush(&pf->hw);
+}
+
+/**
+ * i40e_intr - MSI/Legacy and non-queue interrupt handler
+ * @irq: interrupt number
+ * @data: pointer to a q_vector
+ *
+ * This is the handler used for all MSI/Legacy interrupts, and deals
+ * with both queue and non-queue interrupts.  This is also used in
+ * MSIX mode to handle the non-queue interrupts.
+ **/
+static irqreturn_t i40e_intr(int irq, void *data)
+{
+       struct i40e_pf *pf = (struct i40e_pf *)data;
+       struct i40e_hw *hw = &pf->hw;
+       u32 icr0, icr0_remaining;
+       u32 val, ena_mask;
+
+       icr0 = rd32(hw, I40E_PFINT_ICR0);
+
+       /* if sharing a legacy IRQ, we might get called w/o an intr pending */
+       if ((icr0 & I40E_PFINT_ICR0_INTEVENT_MASK) == 0)
+               return IRQ_NONE;
+
+       val = rd32(hw, I40E_PFINT_DYN_CTL0);
+       val = val | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
+       wr32(hw, I40E_PFINT_DYN_CTL0, val);
+
+       ena_mask = rd32(hw, I40E_PFINT_ICR0_ENA);
+
+       /* only q0 is used in MSI/Legacy mode, and none are used in MSIX */
+       if (icr0 & I40E_PFINT_ICR0_QUEUE_0_MASK) {
+
+               /* temporarily disable queue cause for NAPI processing */
+               u32 qval = rd32(hw, I40E_QINT_RQCTL(0));
+               qval &= ~I40E_QINT_RQCTL_CAUSE_ENA_MASK;
+               wr32(hw, I40E_QINT_RQCTL(0), qval);
+
+               qval = rd32(hw, I40E_QINT_TQCTL(0));
+               qval &= ~I40E_QINT_TQCTL_CAUSE_ENA_MASK;
+               wr32(hw, I40E_QINT_TQCTL(0), qval);
+               i40e_flush(hw);
+
+               if (!test_bit(__I40E_DOWN, &pf->state))
+                       napi_schedule(&pf->vsi[pf->lan_vsi]->q_vectors[0].napi);
+       }
+
+       if (icr0 & I40E_PFINT_ICR0_ADMINQ_MASK) {
+               ena_mask &= ~I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
+               set_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state);
+       }
+
+       if (icr0 & I40E_PFINT_ICR0_MAL_DETECT_MASK) {
+               ena_mask &= ~I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
+               set_bit(__I40E_MDD_EVENT_PENDING, &pf->state);
+       }
+
+       if (icr0 & I40E_PFINT_ICR0_VFLR_MASK) {
+               ena_mask &= ~I40E_PFINT_ICR0_ENA_VFLR_MASK;
+               set_bit(__I40E_VFLR_EVENT_PENDING, &pf->state);
+       }
+
+       if (icr0 & I40E_PFINT_ICR0_GRST_MASK) {
+               if (!test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
+                       set_bit(__I40E_RESET_INTR_RECEIVED, &pf->state);
+               ena_mask &= ~I40E_PFINT_ICR0_ENA_GRST_MASK;
+               val = rd32(hw, I40E_GLGEN_RSTAT);
+               val = (val & I40E_GLGEN_RSTAT_RESET_TYPE_MASK)
+                      >> I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT;
+               if (val & I40E_RESET_CORER)
+                       pf->corer_count++;
+               else if (val & I40E_RESET_GLOBR)
+                       pf->globr_count++;
+               else if (val & I40E_RESET_EMPR)
+                       pf->empr_count++;
+       }
+
+       /* If a critical error is pending we have no choice but to reset the
+        * device.
+        * Report and mask out any remaining unexpected interrupts.
+        */
+       icr0_remaining = icr0 & ena_mask;
+       if (icr0_remaining) {
+               dev_info(&pf->pdev->dev, "unhandled interrupt icr0=0x%08x\n",
+                        icr0_remaining);
+               if ((icr0_remaining & I40E_PFINT_ICR0_HMC_ERR_MASK) ||
+                   (icr0_remaining & I40E_PFINT_ICR0_PE_CRITERR_MASK) ||
+                   (icr0_remaining & I40E_PFINT_ICR0_PCI_EXCEPTION_MASK) ||
+                   (icr0_remaining & I40E_PFINT_ICR0_ECC_ERR_MASK) ||
+                   (icr0_remaining & I40E_PFINT_ICR0_MAL_DETECT_MASK)) {
+                       if (icr0 & I40E_PFINT_ICR0_HMC_ERR_MASK) {
+                               dev_info(&pf->pdev->dev, "HMC error interrupt\n");
+                       } else {
+                               dev_info(&pf->pdev->dev, "device will be reset\n");
+                               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
+                               i40e_service_event_schedule(pf);
+                       }
+               }
+               ena_mask &= ~icr0_remaining;
+       }
+
+       /* re-enable interrupt causes */
+       wr32(hw, I40E_PFINT_ICR0_ENA, ena_mask);
+       i40e_flush(hw);
+       if (!test_bit(__I40E_DOWN, &pf->state)) {
+               i40e_service_event_schedule(pf);
+               i40e_irq_dynamic_enable_icr0(pf);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * i40e_map_vector_to_rxq - Assigns the Rx queue to the vector
+ * @vsi: the VSI being configured
+ * @v_idx: vector index
+ * @r_idx: rx queue index
+ **/
+static void map_vector_to_rxq(struct i40e_vsi *vsi, int v_idx, int r_idx)
+{
+       struct i40e_q_vector *q_vector = &(vsi->q_vectors[v_idx]);
+       struct i40e_ring *rx_ring = &(vsi->rx_rings[r_idx]);
+
+       rx_ring->q_vector = q_vector;
+       q_vector->rx.ring[q_vector->rx.count] = rx_ring;
+       q_vector->rx.count++;
+       q_vector->rx.latency_range = I40E_LOW_LATENCY;
+       q_vector->vsi = vsi;
+}
+
+/**
+ * i40e_map_vector_to_txq - Assigns the Tx queue to the vector
+ * @vsi: the VSI being configured
+ * @v_idx: vector index
+ * @t_idx: tx queue index
+ **/
+static void map_vector_to_txq(struct i40e_vsi *vsi, int v_idx, int t_idx)
+{
+       struct i40e_q_vector *q_vector = &(vsi->q_vectors[v_idx]);
+       struct i40e_ring *tx_ring = &(vsi->tx_rings[t_idx]);
+
+       tx_ring->q_vector = q_vector;
+       q_vector->tx.ring[q_vector->tx.count] = tx_ring;
+       q_vector->tx.count++;
+       q_vector->tx.latency_range = I40E_LOW_LATENCY;
+       q_vector->num_ringpairs++;
+       q_vector->vsi = vsi;
+}
+
+/**
+ * i40e_vsi_map_rings_to_vectors - Maps descriptor rings to vectors
+ * @vsi: the VSI being configured
+ *
+ * This function maps descriptor rings to the queue-specific vectors
+ * we were allotted through the MSI-X enabling code.  Ideally, we'd have
+ * one vector per queue pair, but on a constrained vector budget, we
+ * group the queue pairs as "efficiently" as possible.
+ **/
+static void i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi)
+{
+       int qp_remaining = vsi->num_queue_pairs;
+       int q_vectors = vsi->num_q_vectors;
+       int qp_per_vector;
+       int v_start = 0;
+       int qp_idx = 0;
+
+       /* If we don't have enough vectors for a 1-to-1 mapping, we'll have to
+        * group them so there are multiple queues per vector.
+        */
+       for (; v_start < q_vectors && qp_remaining; v_start++) {
+               qp_per_vector = DIV_ROUND_UP(qp_remaining, q_vectors - v_start);
+               for (; qp_per_vector;
+                    qp_per_vector--, qp_idx++, qp_remaining--) {
+                       map_vector_to_rxq(vsi, v_start, qp_idx);
+                       map_vector_to_txq(vsi, v_start, qp_idx);
+               }
+       }
+}
+
+/**
+ * i40e_vsi_request_irq - Request IRQ from the OS
+ * @vsi: the VSI being configured
+ * @basename: name for the vector
+ **/
+static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename)
+{
+       struct i40e_pf *pf = vsi->back;
+       int err;
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+               err = i40e_vsi_request_irq_msix(vsi, basename);
+       else if (pf->flags & I40E_FLAG_MSI_ENABLED)
+               err = request_irq(pf->pdev->irq, i40e_intr, 0,
+                                 pf->misc_int_name, pf);
+       else
+               err = request_irq(pf->pdev->irq, i40e_intr, IRQF_SHARED,
+                                 pf->misc_int_name, pf);
+
+       if (err)
+               dev_info(&pf->pdev->dev, "request_irq failed, Error %d\n", err);
+
+       return err;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/**
+ * i40e_netpoll - A Polling 'interrupt'handler
+ * @netdev: network interface device structure
+ *
+ * This is used by netconsole to send skbs without having to re-enable
+ * interrupts.  It's not called while the normal interrupt routine is executing.
+ **/
+static void i40e_netpoll(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       int i;
+
+       /* if interface is down do nothing */
+       if (test_bit(__I40E_DOWN, &vsi->state))
+               return;
+
+       pf->flags |= I40E_FLAG_IN_NETPOLL;
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               for (i = 0; i < vsi->num_q_vectors; i++)
+                       i40e_msix_clean_rings(0, &vsi->q_vectors[i]);
+       } else {
+               i40e_intr(pf->pdev->irq, netdev);
+       }
+       pf->flags &= ~I40E_FLAG_IN_NETPOLL;
+}
+#endif
+
+/**
+ * i40e_vsi_control_tx - Start or stop a VSI's rings
+ * @vsi: the VSI being configured
+ * @enable: start or stop the rings
+ **/
+static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int i, j, pf_q;
+       u32 tx_reg;
+
+       pf_q = vsi->base_queue;
+       for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
+               j = 1000;
+               do {
+                       usleep_range(1000, 2000);
+                       tx_reg = rd32(hw, I40E_QTX_ENA(pf_q));
+               } while (j-- && ((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT)
+                              ^ (tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT)) & 1);
+
+               if (enable) {
+                       /* is STAT set ? */
+                       if ((tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) {
+                               dev_info(&pf->pdev->dev,
+                                        "Tx %d already enabled\n", i);
+                               continue;
+                       }
+               } else {
+                       /* is !STAT set ? */
+                       if (!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) {
+                               dev_info(&pf->pdev->dev,
+                                        "Tx %d already disabled\n", i);
+                               continue;
+                       }
+               }
+
+               /* turn on/off the queue */
+               if (enable)
+                       tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK |
+                                 I40E_QTX_ENA_QENA_STAT_MASK;
+               else
+                       tx_reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
+
+               wr32(hw, I40E_QTX_ENA(pf_q), tx_reg);
+
+               /* wait for the change to finish */
+               for (j = 0; j < 10; j++) {
+                       tx_reg = rd32(hw, I40E_QTX_ENA(pf_q));
+                       if (enable) {
+                               if ((tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
+                                       break;
+                       } else {
+                               if (!(tx_reg & I40E_QTX_ENA_QENA_STAT_MASK))
+                                       break;
+                       }
+
+                       udelay(10);
+               }
+               if (j >= 10) {
+                       dev_info(&pf->pdev->dev, "Tx ring %d %sable timeout\n",
+                                pf_q, (enable ? "en" : "dis"));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_control_rx - Start or stop a VSI's rings
+ * @vsi: the VSI being configured
+ * @enable: start or stop the rings
+ **/
+static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int i, j, pf_q;
+       u32 rx_reg;
+
+       pf_q = vsi->base_queue;
+       for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) {
+               j = 1000;
+               do {
+                       usleep_range(1000, 2000);
+                       rx_reg = rd32(hw, I40E_QRX_ENA(pf_q));
+               } while (j-- && ((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT)
+                              ^ (rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT)) & 1);
+
+               if (enable) {
+                       /* is STAT set ? */
+                       if ((rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
+                               continue;
+               } else {
+                       /* is !STAT set ? */
+                       if (!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
+                               continue;
+               }
+
+               /* turn on/off the queue */
+               if (enable)
+                       rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK |
+                                 I40E_QRX_ENA_QENA_STAT_MASK;
+               else
+                       rx_reg &= ~(I40E_QRX_ENA_QENA_REQ_MASK |
+                                 I40E_QRX_ENA_QENA_STAT_MASK);
+               wr32(hw, I40E_QRX_ENA(pf_q), rx_reg);
+
+               /* wait for the change to finish */
+               for (j = 0; j < 10; j++) {
+                       rx_reg = rd32(hw, I40E_QRX_ENA(pf_q));
+
+                       if (enable) {
+                               if ((rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
+                                       break;
+                       } else {
+                               if (!(rx_reg & I40E_QRX_ENA_QENA_STAT_MASK))
+                                       break;
+                       }
+
+                       udelay(10);
+               }
+               if (j >= 10) {
+                       dev_info(&pf->pdev->dev, "Rx ring %d %sable timeout\n",
+                                pf_q, (enable ? "en" : "dis"));
+                       return -ETIMEDOUT;
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_control_rings - Start or stop a VSI's rings
+ * @vsi: the VSI being configured
+ * @enable: start or stop the rings
+ **/
+static int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request)
+{
+       int ret;
+
+       /* do rx first for enable and last for disable */
+       if (request) {
+               ret = i40e_vsi_control_rx(vsi, request);
+               if (ret)
+                       return ret;
+               ret = i40e_vsi_control_tx(vsi, request);
+       } else {
+               ret = i40e_vsi_control_tx(vsi, request);
+               if (ret)
+                       return ret;
+               ret = i40e_vsi_control_rx(vsi, request);
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_vsi_free_irq - Free the irq association with the OS
+ * @vsi: the VSI being configured
+ **/
+static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       int base = vsi->base_vector;
+       u32 val, qp;
+       int i;
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               if (!vsi->q_vectors)
+                       return;
+
+               for (i = 0; i < vsi->num_q_vectors; i++) {
+                       u16 vector = i + base;
+
+                       /* free only the irqs that were actually requested */
+                       if (vsi->q_vectors[i].num_ringpairs == 0)
+                               continue;
+
+                       /* clear the affinity_mask in the IRQ descriptor */
+                       irq_set_affinity_hint(pf->msix_entries[vector].vector,
+                                             NULL);
+                       free_irq(pf->msix_entries[vector].vector,
+                                &vsi->q_vectors[i]);
+
+                       /* Tear down the interrupt queue link list
+                        *
+                        * We know that they come in pairs and always
+                        * the Rx first, then the Tx.  To clear the
+                        * link list, stick the EOL value into the
+                        * next_q field of the registers.
+                        */
+                       val = rd32(hw, I40E_PFINT_LNKLSTN(vector - 1));
+                       qp = (val & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK)
+                               >> I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT;
+                       val |= I40E_QUEUE_END_OF_LIST
+                               << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT;
+                       wr32(hw, I40E_PFINT_LNKLSTN(vector - 1), val);
+
+                       while (qp != I40E_QUEUE_END_OF_LIST) {
+                               u32 next;
+
+                               val = rd32(hw, I40E_QINT_RQCTL(qp));
+
+                               val &= ~(I40E_QINT_RQCTL_MSIX_INDX_MASK  |
+                                        I40E_QINT_RQCTL_MSIX0_INDX_MASK |
+                                        I40E_QINT_RQCTL_CAUSE_ENA_MASK  |
+                                        I40E_QINT_RQCTL_INTEVENT_MASK);
+
+                               val |= (I40E_QINT_RQCTL_ITR_INDX_MASK |
+                                        I40E_QINT_RQCTL_NEXTQ_INDX_MASK);
+
+                               wr32(hw, I40E_QINT_RQCTL(qp), val);
+
+                               val = rd32(hw, I40E_QINT_TQCTL(qp));
+
+                               next = (val & I40E_QINT_TQCTL_NEXTQ_INDX_MASK)
+                                       >> I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT;
+
+                               val &= ~(I40E_QINT_TQCTL_MSIX_INDX_MASK  |
+                                        I40E_QINT_TQCTL_MSIX0_INDX_MASK |
+                                        I40E_QINT_TQCTL_CAUSE_ENA_MASK  |
+                                        I40E_QINT_TQCTL_INTEVENT_MASK);
+
+                               val |= (I40E_QINT_TQCTL_ITR_INDX_MASK |
+                                        I40E_QINT_TQCTL_NEXTQ_INDX_MASK);
+
+                               wr32(hw, I40E_QINT_TQCTL(qp), val);
+                               qp = next;
+                       }
+               }
+       } else {
+               free_irq(pf->pdev->irq, pf);
+
+               val = rd32(hw, I40E_PFINT_LNKLST0);
+               qp = (val & I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK)
+                       >> I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT;
+               val |= I40E_QUEUE_END_OF_LIST
+                       << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT;
+               wr32(hw, I40E_PFINT_LNKLST0, val);
+
+               val = rd32(hw, I40E_QINT_RQCTL(qp));
+               val &= ~(I40E_QINT_RQCTL_MSIX_INDX_MASK  |
+                        I40E_QINT_RQCTL_MSIX0_INDX_MASK |
+                        I40E_QINT_RQCTL_CAUSE_ENA_MASK  |
+                        I40E_QINT_RQCTL_INTEVENT_MASK);
+
+               val |= (I40E_QINT_RQCTL_ITR_INDX_MASK |
+                       I40E_QINT_RQCTL_NEXTQ_INDX_MASK);
+
+               wr32(hw, I40E_QINT_RQCTL(qp), val);
+
+               val = rd32(hw, I40E_QINT_TQCTL(qp));
+
+               val &= ~(I40E_QINT_TQCTL_MSIX_INDX_MASK  |
+                        I40E_QINT_TQCTL_MSIX0_INDX_MASK |
+                        I40E_QINT_TQCTL_CAUSE_ENA_MASK  |
+                        I40E_QINT_TQCTL_INTEVENT_MASK);
+
+               val |= (I40E_QINT_TQCTL_ITR_INDX_MASK |
+                       I40E_QINT_TQCTL_NEXTQ_INDX_MASK);
+
+               wr32(hw, I40E_QINT_TQCTL(qp), val);
+       }
+}
+
+/**
+ * i40e_vsi_free_q_vectors - Free memory allocated for interrupt vectors
+ * @vsi: the VSI being un-configured
+ *
+ * This frees the memory allocated to the q_vectors and
+ * deletes references to the NAPI struct.
+ **/
+static void i40e_vsi_free_q_vectors(struct i40e_vsi *vsi)
+{
+       int v_idx;
+
+       for (v_idx = 0; v_idx < vsi->num_q_vectors; v_idx++) {
+               struct i40e_q_vector *q_vector = &vsi->q_vectors[v_idx];
+               int r_idx;
+
+               if (!q_vector)
+                       continue;
+
+               /* disassociate q_vector from rings */
+               for (r_idx = 0; r_idx < q_vector->tx.count; r_idx++)
+                       q_vector->tx.ring[r_idx]->q_vector = NULL;
+               for (r_idx = 0; r_idx < q_vector->rx.count; r_idx++)
+                       q_vector->rx.ring[r_idx]->q_vector = NULL;
+
+               /* only VSI w/ an associated netdev is set up w/ NAPI */
+               if (vsi->netdev)
+                       netif_napi_del(&q_vector->napi);
+       }
+       kfree(vsi->q_vectors);
+}
+
+/**
+ * i40e_reset_interrupt_capability - Disable interrupt setup in OS
+ * @pf: board private structure
+ **/
+static void i40e_reset_interrupt_capability(struct i40e_pf *pf)
+{
+       /* If we're in Legacy mode, the interrupt was cleaned in vsi_close */
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               pci_disable_msix(pf->pdev);
+               kfree(pf->msix_entries);
+               pf->msix_entries = NULL;
+       } else if (pf->flags & I40E_FLAG_MSI_ENABLED) {
+               pci_disable_msi(pf->pdev);
+       }
+       pf->flags &= ~(I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED);
+}
+
+/**
+ * i40e_clear_interrupt_scheme - Clear the current interrupt scheme settings
+ * @pf: board private structure
+ *
+ * We go through and clear interrupt specific resources and reset the structure
+ * to pre-load conditions
+ **/
+static void i40e_clear_interrupt_scheme(struct i40e_pf *pf)
+{
+       int i;
+
+       i40e_put_lump(pf->irq_pile, 0, I40E_PILE_VALID_BIT-1);
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+               if (pf->vsi[i])
+                       i40e_vsi_free_q_vectors(pf->vsi[i]);
+       i40e_reset_interrupt_capability(pf);
+}
+
+/**
+ * i40e_napi_enable_all - Enable NAPI for all q_vectors in the VSI
+ * @vsi: the VSI being configured
+ **/
+static void i40e_napi_enable_all(struct i40e_vsi *vsi)
+{
+       int q_idx;
+
+       if (!vsi->netdev)
+               return;
+
+       for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++)
+               napi_enable(&vsi->q_vectors[q_idx].napi);
+}
+
+/**
+ * i40e_napi_disable_all - Disable NAPI for all q_vectors in the VSI
+ * @vsi: the VSI being configured
+ **/
+static void i40e_napi_disable_all(struct i40e_vsi *vsi)
+{
+       int q_idx;
+
+       if (!vsi->netdev)
+               return;
+
+       for (q_idx = 0; q_idx < vsi->num_q_vectors; q_idx++)
+               napi_disable(&vsi->q_vectors[q_idx].napi);
+}
+
+/**
+ * i40e_quiesce_vsi - Pause a given VSI
+ * @vsi: the VSI being paused
+ **/
+static void i40e_quiesce_vsi(struct i40e_vsi *vsi)
+{
+       if (test_bit(__I40E_DOWN, &vsi->state))
+               return;
+
+       set_bit(__I40E_NEEDS_RESTART, &vsi->state);
+       if (vsi->netdev && netif_running(vsi->netdev)) {
+               vsi->netdev->netdev_ops->ndo_stop(vsi->netdev);
+       } else {
+               set_bit(__I40E_DOWN, &vsi->state);
+               i40e_down(vsi);
+       }
+}
+
+/**
+ * i40e_unquiesce_vsi - Resume a given VSI
+ * @vsi: the VSI being resumed
+ **/
+static void i40e_unquiesce_vsi(struct i40e_vsi *vsi)
+{
+       if (!test_bit(__I40E_NEEDS_RESTART, &vsi->state))
+               return;
+
+       clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
+       if (vsi->netdev && netif_running(vsi->netdev))
+               vsi->netdev->netdev_ops->ndo_open(vsi->netdev);
+       else
+               i40e_up(vsi);   /* this clears the DOWN bit */
+}
+
+/**
+ * i40e_pf_quiesce_all_vsi - Pause all VSIs on a PF
+ * @pf: the PF
+ **/
+static void i40e_pf_quiesce_all_vsi(struct i40e_pf *pf)
+{
+       int v;
+
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               if (pf->vsi[v])
+                       i40e_quiesce_vsi(pf->vsi[v]);
+       }
+}
+
+/**
+ * i40e_pf_unquiesce_all_vsi - Resume all VSIs on a PF
+ * @pf: the PF
+ **/
+static void i40e_pf_unquiesce_all_vsi(struct i40e_pf *pf)
+{
+       int v;
+
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               if (pf->vsi[v])
+                       i40e_unquiesce_vsi(pf->vsi[v]);
+       }
+}
+
+/**
+ * i40e_dcb_get_num_tc -  Get the number of TCs from DCBx config
+ * @dcbcfg: the corresponding DCBx configuration structure
+ *
+ * Return the number of TCs from given DCBx configuration
+ **/
+static u8 i40e_dcb_get_num_tc(struct i40e_dcbx_config *dcbcfg)
+{
+       int num_tc = 0, i;
+
+       /* Scan the ETS Config Priority Table to find
+        * traffic class enabled for a given priority
+        * and use the traffic class index to get the
+        * number of traffic classes enabled
+        */
+       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+               if (dcbcfg->etscfg.prioritytable[i] > num_tc)
+                       num_tc = dcbcfg->etscfg.prioritytable[i];
+       }
+
+       /* Traffic class index starts from zero so
+        * increment to return the actual count
+        */
+       num_tc++;
+
+       return num_tc;
+}
+
+/**
+ * i40e_dcb_get_enabled_tc - Get enabled traffic classes
+ * @dcbcfg: the corresponding DCBx configuration structure
+ *
+ * Query the current DCB configuration and return the number of
+ * traffic classes enabled from the given DCBX config
+ **/
+static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg)
+{
+       u8 num_tc = i40e_dcb_get_num_tc(dcbcfg);
+       u8 enabled_tc = 1;
+       u8 i;
+
+       for (i = 0; i < num_tc; i++)
+               enabled_tc |= 1 << i;
+
+       return enabled_tc;
+}
+
+/**
+ * i40e_pf_get_num_tc - Get enabled traffic classes for PF
+ * @pf: PF being queried
+ *
+ * Return number of traffic classes enabled for the given PF
+ **/
+static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u8 i, enabled_tc;
+       u8 num_tc = 0;
+       struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
+
+       /* If DCB is not enabled then always in single TC */
+       if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+               return 1;
+
+       /* MFP mode return count of enabled TCs for this PF */
+       if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+               enabled_tc = pf->hw.func_caps.enabled_tcmap;
+               for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+                       if (enabled_tc & (1 << i))
+                               num_tc++;
+               }
+               return num_tc;
+       }
+
+       /* SFP mode will be enabled for all TCs on port */
+       return i40e_dcb_get_num_tc(dcbcfg);
+}
+
+/**
+ * i40e_pf_get_default_tc - Get bitmap for first enabled TC
+ * @pf: PF being queried
+ *
+ * Return a bitmap for first enabled traffic class for this PF.
+ **/
+static u8 i40e_pf_get_default_tc(struct i40e_pf *pf)
+{
+       u8 enabled_tc = pf->hw.func_caps.enabled_tcmap;
+       u8 i = 0;
+
+       if (!enabled_tc)
+               return 0x1; /* TC0 */
+
+       /* Find the first enabled TC */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               if (enabled_tc & (1 << i))
+                       break;
+       }
+
+       return 1 << i;
+}
+
+/**
+ * i40e_pf_get_pf_tc_map - Get bitmap for enabled traffic classes
+ * @pf: PF being queried
+ *
+ * Return a bitmap for enabled traffic classes for this PF.
+ **/
+static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
+{
+       /* If DCB is not enabled for this PF then just return default TC */
+       if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+               return i40e_pf_get_default_tc(pf);
+
+       /* MFP mode will have enabled TCs set by FW */
+       if (pf->flags & I40E_FLAG_MFP_ENABLED)
+               return pf->hw.func_caps.enabled_tcmap;
+
+       /* SFP mode we want PF to be enabled for all TCs */
+       return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config);
+}
+
+/**
+ * i40e_vsi_get_bw_info - Query VSI BW Information
+ * @vsi: the VSI being queried
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi)
+{
+       struct i40e_aqc_query_vsi_ets_sla_config_resp bw_ets_config = {0};
+       struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0};
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u32 tc_bw_max;
+       int ret;
+       int i;
+
+       /* Get the VSI level BW configuration */
+       ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "couldn't get pf vsi bw config, err %d, aq_err %d\n",
+                        ret, pf->hw.aq.asq_last_status);
+               return ret;
+       }
+
+       /* Get the VSI level BW configuration per TC */
+       ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid,
+                                              &bw_ets_config,
+                                              NULL);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "couldn't get pf vsi ets bw config, err %d, aq_err %d\n",
+                        ret, pf->hw.aq.asq_last_status);
+               return ret;
+       }
+
+       if (bw_config.tc_valid_bits != bw_ets_config.tc_valid_bits) {
+               dev_info(&pf->pdev->dev,
+                        "Enabled TCs mismatch from querying VSI BW info 0x%08x 0x%08x\n",
+                        bw_config.tc_valid_bits,
+                        bw_ets_config.tc_valid_bits);
+               /* Still continuing */
+       }
+
+       vsi->bw_limit = le16_to_cpu(bw_config.port_bw_limit);
+       vsi->bw_max_quanta = bw_config.max_bw;
+       tc_bw_max = le16_to_cpu(bw_ets_config.tc_bw_max[0]) |
+                   (le16_to_cpu(bw_ets_config.tc_bw_max[1]) << 16);
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               vsi->bw_ets_share_credits[i] = bw_ets_config.share_credits[i];
+               vsi->bw_ets_limit_credits[i] =
+                                       le16_to_cpu(bw_ets_config.credits[i]);
+               /* 3 bits out of 4 for each TC */
+               vsi->bw_ets_max_quanta[i] = (u8)((tc_bw_max >> (i*4)) & 0x7);
+       }
+       return ret;
+}
+
+/**
+ * i40e_vsi_configure_bw_alloc - Configure VSI BW allocation per TC
+ * @vsi: the VSI being configured
+ * @enabled_tc: TC bitmap
+ * @bw_credits: BW shared credits per TC
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi,
+                                      u8 enabled_tc,
+                                      u8 *bw_share)
+{
+       struct i40e_aqc_configure_vsi_tc_bw_data bw_data;
+       int i, ret = 0;
+
+       bw_data.tc_valid_bits = enabled_tc;
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               bw_data.tc_bw_credits[i] = bw_share[i];
+
+       ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid,
+                                      &bw_data, NULL);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "%s: AQ command Config VSI BW allocation per TC failed = %d\n",
+                        __func__, vsi->back->hw.aq.asq_last_status);
+               return ret;
+       }
+
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
+               vsi->info.qs_handle[i] = bw_data.qs_handles[i];
+
+       return ret;
+}
+
+/**
+ * i40e_vsi_config_netdev_tc - Setup the netdev TC configuration
+ * @vsi: the VSI being configured
+ * @enabled_tc: TC map to be enabled
+ *
+ **/
+static void i40e_vsi_config_netdev_tc(struct i40e_vsi *vsi, u8 enabled_tc)
+{
+       struct net_device *netdev = vsi->netdev;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u8 netdev_tc = 0;
+       int i;
+       struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
+
+       if (!netdev)
+               return;
+
+       if (!enabled_tc) {
+               netdev_reset_tc(netdev);
+               return;
+       }
+
+       /* Set up actual enabled TCs on the VSI */
+       if (netdev_set_num_tc(netdev, vsi->tc_config.numtc))
+               return;
+
+       /* set per TC queues for the VSI */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               /* Only set TC queues for enabled tcs
+                *
+                * e.g. For a VSI that has TC0 and TC3 enabled the
+                * enabled_tc bitmap would be 0x00001001; the driver
+                * will set the numtc for netdev as 2 that will be
+                * referenced by the netdev layer as TC 0 and 1.
+                */
+               if (vsi->tc_config.enabled_tc & (1 << i))
+                       netdev_set_tc_queue(netdev,
+                                       vsi->tc_config.tc_info[i].netdev_tc,
+                                       vsi->tc_config.tc_info[i].qcount,
+                                       vsi->tc_config.tc_info[i].qoffset);
+       }
+
+       /* Assign UP2TC map for the VSI */
+       for (i = 0; i < I40E_MAX_USER_PRIORITY; i++) {
+               /* Get the actual TC# for the UP */
+               u8 ets_tc = dcbcfg->etscfg.prioritytable[i];
+               /* Get the mapped netdev TC# for the UP */
+               netdev_tc =  vsi->tc_config.tc_info[ets_tc].netdev_tc;
+               netdev_set_prio_tc_map(netdev, i, netdev_tc);
+       }
+}
+
+/**
+ * i40e_vsi_update_queue_map - Update our copy of VSi info with new queue map
+ * @vsi: the VSI being configured
+ * @ctxt: the ctxt buffer returned from AQ VSI update param command
+ **/
+static void i40e_vsi_update_queue_map(struct i40e_vsi *vsi,
+                                     struct i40e_vsi_context *ctxt)
+{
+       /* copy just the sections touched not the entire info
+        * since not all sections are valid as returned by
+        * update vsi params
+        */
+       vsi->info.mapping_flags = ctxt->info.mapping_flags;
+       memcpy(&vsi->info.queue_mapping,
+              &ctxt->info.queue_mapping, sizeof(vsi->info.queue_mapping));
+       memcpy(&vsi->info.tc_mapping, ctxt->info.tc_mapping,
+              sizeof(vsi->info.tc_mapping));
+}
+
+/**
+ * i40e_vsi_config_tc - Configure VSI Tx Scheduler for given TC map
+ * @vsi: VSI to be configured
+ * @enabled_tc: TC bitmap
+ *
+ * This configures a particular VSI for TCs that are mapped to the
+ * given TC bitmap. It uses default bandwidth share for TCs across
+ * VSIs to configure TC for a particular VSI.
+ *
+ * NOTE:
+ * It is expected that the VSI queues have been quisced before calling
+ * this function.
+ **/
+static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc)
+{
+       u8 bw_share[I40E_MAX_TRAFFIC_CLASS] = {0};
+       struct i40e_vsi_context ctxt;
+       int ret = 0;
+       int i;
+
+       /* Check if enabled_tc is same as existing or new TCs */
+       if (vsi->tc_config.enabled_tc == enabled_tc)
+               return ret;
+
+       /* Enable ETS TCs with equal BW Share for now across all VSIs */
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               if (enabled_tc & (1 << i))
+                       bw_share[i] = 1;
+       }
+
+       ret = i40e_vsi_configure_bw_alloc(vsi, enabled_tc, bw_share);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed configuring TC map %d for VSI %d\n",
+                        enabled_tc, vsi->seid);
+               goto out;
+       }
+
+       /* Update Queue Pairs Mapping for currently enabled UPs */
+       ctxt.seid = vsi->seid;
+       ctxt.pf_num = vsi->back->hw.pf_id;
+       ctxt.vf_num = 0;
+       ctxt.uplink_seid = vsi->uplink_seid;
+       memcpy(&ctxt.info, &vsi->info, sizeof(vsi->info));
+       i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
+
+       /* Update the VSI after updating the VSI queue-mapping information */
+       ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "update vsi failed, aq_err=%d\n",
+                        vsi->back->hw.aq.asq_last_status);
+               goto out;
+       }
+       /* update the local VSI info with updated queue map */
+       i40e_vsi_update_queue_map(vsi, &ctxt);
+       vsi->info.valid_sections = 0;
+
+       /* Update current VSI BW information */
+       ret = i40e_vsi_get_bw_info(vsi);
+       if (ret) {
+               dev_info(&vsi->back->pdev->dev,
+                        "Failed updating vsi bw info, aq_err=%d\n",
+                        vsi->back->hw.aq.asq_last_status);
+               goto out;
+       }
+
+       /* Update the netdev TC setup */
+       i40e_vsi_config_netdev_tc(vsi, enabled_tc);
+out:
+       return ret;
+}
+
+/**
+ * i40e_up_complete - Finish the last steps of bringing up a connection
+ * @vsi: the VSI being configured
+ **/
+static int i40e_up_complete(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       int err;
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+               i40e_vsi_configure_msix(vsi);
+       else
+               i40e_configure_msi_and_legacy(vsi);
+
+       /* start rings */
+       err = i40e_vsi_control_rings(vsi, true);
+       if (err)
+               return err;
+
+       clear_bit(__I40E_DOWN, &vsi->state);
+       i40e_napi_enable_all(vsi);
+       i40e_vsi_enable_irq(vsi);
+
+       if ((pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP) &&
+           (vsi->netdev)) {
+               netif_tx_start_all_queues(vsi->netdev);
+               netif_carrier_on(vsi->netdev);
+       }
+       i40e_service_event_schedule(pf);
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_reinit_locked - Reset the VSI
+ * @vsi: the VSI being configured
+ *
+ * Rebuild the ring structs after some configuration
+ * has changed, e.g. MTU size.
+ **/
+static void i40e_vsi_reinit_locked(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+
+       WARN_ON(in_interrupt());
+       while (test_and_set_bit(__I40E_CONFIG_BUSY, &pf->state))
+               usleep_range(1000, 2000);
+       i40e_down(vsi);
+
+       /* Give a VF some time to respond to the reset.  The
+        * two second wait is based upon the watchdog cycle in
+        * the VF driver.
+        */
+       if (vsi->type == I40E_VSI_SRIOV)
+               msleep(2000);
+       i40e_up(vsi);
+       clear_bit(__I40E_CONFIG_BUSY, &pf->state);
+}
+
+/**
+ * i40e_up - Bring the connection back up after being down
+ * @vsi: the VSI being configured
+ **/
+int i40e_up(struct i40e_vsi *vsi)
+{
+       int err;
+
+       err = i40e_vsi_configure(vsi);
+       if (!err)
+               err = i40e_up_complete(vsi);
+
+       return err;
+}
+
+/**
+ * i40e_down - Shutdown the connection processing
+ * @vsi: the VSI being stopped
+ **/
+void i40e_down(struct i40e_vsi *vsi)
+{
+       int i;
+
+       /* It is assumed that the caller of this function
+        * sets the vsi->state __I40E_DOWN bit.
+        */
+       if (vsi->netdev) {
+               netif_carrier_off(vsi->netdev);
+               netif_tx_disable(vsi->netdev);
+       }
+       i40e_vsi_disable_irq(vsi);
+       i40e_vsi_control_rings(vsi, false);
+       i40e_napi_disable_all(vsi);
+
+       for (i = 0; i < vsi->num_queue_pairs; i++) {
+               i40e_clean_tx_ring(&vsi->tx_rings[i]);
+               i40e_clean_rx_ring(&vsi->rx_rings[i]);
+       }
+}
+
+/**
+ * i40e_setup_tc - configure multiple traffic classes
+ * @netdev: net device to configure
+ * @tc: number of traffic classes to enable
+ **/
+static int i40e_setup_tc(struct net_device *netdev, u8 tc)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       u8 enabled_tc = 0;
+       int ret = -EINVAL;
+       int i;
+
+       /* Check if DCB enabled to continue */
+       if (!(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+               netdev_info(netdev, "DCB is not enabled for adapter\n");
+               goto exit;
+       }
+
+       /* Check if MFP enabled */
+       if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+               netdev_info(netdev, "Configuring TC not supported in MFP mode\n");
+               goto exit;
+       }
+
+       /* Check whether tc count is within enabled limit */
+       if (tc > i40e_pf_get_num_tc(pf)) {
+               netdev_info(netdev, "TC count greater than enabled on link for adapter\n");
+               goto exit;
+       }
+
+       /* Generate TC map for number of tc requested */
+       for (i = 0; i < tc; i++)
+               enabled_tc |= (1 << i);
+
+       /* Requesting same TC configuration as already enabled */
+       if (enabled_tc == vsi->tc_config.enabled_tc)
+               return 0;
+
+       /* Quiesce VSI queues */
+       i40e_quiesce_vsi(vsi);
+
+       /* Configure VSI for enabled TCs */
+       ret = i40e_vsi_config_tc(vsi, enabled_tc);
+       if (ret) {
+               netdev_info(netdev, "Failed configuring TC for VSI seid=%d\n",
+                           vsi->seid);
+               goto exit;
+       }
+
+       /* Unquiesce VSI */
+       i40e_unquiesce_vsi(vsi);
+
+exit:
+       return ret;
+}
+
+/**
+ * i40e_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the netdev watchdog subtask is
+ * enabled, and the stack is notified that the interface is ready.
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+static int i40e_open(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       char int_name[IFNAMSIZ];
+       int err;
+
+       /* disallow open during test */
+       if (test_bit(__I40E_TESTING, &pf->state))
+               return -EBUSY;
+
+       netif_carrier_off(netdev);
+
+       /* allocate descriptors */
+       err = i40e_vsi_setup_tx_resources(vsi);
+       if (err)
+               goto err_setup_tx;
+       err = i40e_vsi_setup_rx_resources(vsi);
+       if (err)
+               goto err_setup_rx;
+
+       err = i40e_vsi_configure(vsi);
+       if (err)
+               goto err_setup_rx;
+
+       snprintf(int_name, sizeof(int_name) - 1, "%s-%s",
+                dev_driver_string(&pf->pdev->dev), netdev->name);
+       err = i40e_vsi_request_irq(vsi, int_name);
+       if (err)
+               goto err_setup_rx;
+
+       err = i40e_up_complete(vsi);
+       if (err)
+               goto err_up_complete;
+
+       if ((vsi->type == I40E_VSI_MAIN) || (vsi->type == I40E_VSI_VMDQ2)) {
+               err = i40e_aq_set_vsi_broadcast(&pf->hw, vsi->seid, true, NULL);
+               if (err)
+                       netdev_info(netdev,
+                                   "couldn't set broadcast err %d aq_err %d\n",
+                                   err, pf->hw.aq.asq_last_status);
+       }
+
+       return 0;
+
+err_up_complete:
+       i40e_down(vsi);
+       i40e_vsi_free_irq(vsi);
+err_setup_rx:
+       i40e_vsi_free_rx_resources(vsi);
+err_setup_tx:
+       i40e_vsi_free_tx_resources(vsi);
+       if (vsi == pf->vsi[pf->lan_vsi])
+               i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED));
+
+       return err;
+}
+
+/**
+ * i40e_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the driver's control, but
+ * this netdev interface is disabled.
+ *
+ * Returns 0, this is not allowed to fail
+ **/
+static int i40e_close(struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (test_and_set_bit(__I40E_DOWN, &vsi->state))
+               return 0;
+
+       i40e_down(vsi);
+       i40e_vsi_free_irq(vsi);
+
+       i40e_vsi_free_tx_resources(vsi);
+       i40e_vsi_free_rx_resources(vsi);
+
+       return 0;
+}
+
+/**
+ * i40e_do_reset - Start a PF or Core Reset sequence
+ * @pf: board private structure
+ * @reset_flags: which reset is requested
+ *
+ * The essential difference in resets is that the PF Reset
+ * doesn't clear the packet buffers, doesn't reset the PE
+ * firmware, and doesn't bother the other PFs on the chip.
+ **/
+void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags)
+{
+       u32 val;
+
+       WARN_ON(in_interrupt());
+
+       /* do the biggest reset indicated */
+       if (reset_flags & (1 << __I40E_GLOBAL_RESET_REQUESTED)) {
+
+               /* Request a Global Reset
+                *
+                * This will start the chip's countdown to the actual full
+                * chip reset event, and a warning interrupt to be sent
+                * to all PFs, including the requestor.  Our handler
+                * for the warning interrupt will deal with the shutdown
+                * and recovery of the switch setup.
+                */
+               dev_info(&pf->pdev->dev, "GlobalR requested\n");
+               val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
+               val |= I40E_GLGEN_RTRIG_GLOBR_MASK;
+               wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
+
+       } else if (reset_flags & (1 << __I40E_CORE_RESET_REQUESTED)) {
+
+               /* Request a Core Reset
+                *
+                * Same as Global Reset, except does *not* include the MAC/PHY
+                */
+               dev_info(&pf->pdev->dev, "CoreR requested\n");
+               val = rd32(&pf->hw, I40E_GLGEN_RTRIG);
+               val |= I40E_GLGEN_RTRIG_CORER_MASK;
+               wr32(&pf->hw, I40E_GLGEN_RTRIG, val);
+               i40e_flush(&pf->hw);
+
+       } else if (reset_flags & (1 << __I40E_PF_RESET_REQUESTED)) {
+
+               /* Request a PF Reset
+                *
+                * Resets only the PF-specific registers
+                *
+                * This goes directly to the tear-down and rebuild of
+                * the switch, since we need to do all the recovery as
+                * for the Core Reset.
+                */
+               dev_info(&pf->pdev->dev, "PFR requested\n");
+               i40e_handle_reset_warning(pf);
+
+       } else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) {
+               int v;
+
+               /* Find the VSI(s) that requested a re-init */
+               dev_info(&pf->pdev->dev,
+                        "VSI reinit requested\n");
+               for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+                       struct i40e_vsi *vsi = pf->vsi[v];
+                       if (vsi != NULL &&
+                           test_bit(__I40E_REINIT_REQUESTED, &vsi->state)) {
+                               i40e_vsi_reinit_locked(pf->vsi[v]);
+                               clear_bit(__I40E_REINIT_REQUESTED, &vsi->state);
+                       }
+               }
+
+               /* no further action needed, so return now */
+               return;
+       } else {
+               dev_info(&pf->pdev->dev,
+                        "bad reset request 0x%08x\n", reset_flags);
+               return;
+       }
+}
+
+/**
+ * i40e_handle_lan_overflow_event - Handler for LAN queue overflow event
+ * @pf: board private structure
+ * @e: event info posted on ARQ
+ *
+ * Handler for LAN Queue Overflow Event generated by the firmware for PF
+ * and VF queues
+ **/
+static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
+                                          struct i40e_arq_event_info *e)
+{
+       struct i40e_aqc_lan_overflow *data =
+               (struct i40e_aqc_lan_overflow *)&e->desc.params.raw;
+       u32 queue = le32_to_cpu(data->prtdcb_rupto);
+       u32 qtx_ctl = le32_to_cpu(data->otx_ctl);
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf;
+       u16 vf_id;
+
+       dev_info(&pf->pdev->dev, "%s: Rx Queue Number = %d QTX_CTL=0x%08x\n",
+                __func__, queue, qtx_ctl);
+
+       /* Queue belongs to VF, find the VF and issue VF reset */
+       if (((qtx_ctl & I40E_QTX_CTL_PFVF_Q_MASK)
+           >> I40E_QTX_CTL_PFVF_Q_SHIFT) == I40E_QTX_CTL_VF_QUEUE) {
+               vf_id = (u16)((qtx_ctl & I40E_QTX_CTL_VFVM_INDX_MASK)
+                        >> I40E_QTX_CTL_VFVM_INDX_SHIFT);
+               vf_id -= hw->func_caps.vf_base_id;
+               vf = &pf->vf[vf_id];
+               i40e_vc_notify_vf_reset(vf);
+               /* Allow VF to process pending reset notification */
+               msleep(20);
+               i40e_reset_vf(vf, false);
+       }
+}
+
+/**
+ * i40e_service_event_complete - Finish up the service event
+ * @pf: board private structure
+ **/
+static void i40e_service_event_complete(struct i40e_pf *pf)
+{
+       BUG_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
+
+       /* flush memory to make sure state is correct before next watchog */
+       smp_mb__before_clear_bit();
+       clear_bit(__I40E_SERVICE_SCHED, &pf->state);
+}
+
+/**
+ * i40e_fdir_reinit_subtask - Worker thread to reinit FDIR filter table
+ * @pf: board private structure
+ **/
+static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
+{
+       if (!(pf->flags & I40E_FLAG_FDIR_REQUIRES_REINIT))
+               return;
+
+       pf->flags &= ~I40E_FLAG_FDIR_REQUIRES_REINIT;
+
+       /* if interface is down do nothing */
+       if (test_bit(__I40E_DOWN, &pf->state))
+               return;
+}
+
+/**
+ * i40e_vsi_link_event - notify VSI of a link event
+ * @vsi: vsi to be notified
+ * @link_up: link up or down
+ **/
+static void i40e_vsi_link_event(struct i40e_vsi *vsi, bool link_up)
+{
+       if (!vsi)
+               return;
+
+       switch (vsi->type) {
+       case I40E_VSI_MAIN:
+               if (!vsi->netdev || !vsi->netdev_registered)
+                       break;
+
+               if (link_up) {
+                       netif_carrier_on(vsi->netdev);
+                       netif_tx_wake_all_queues(vsi->netdev);
+               } else {
+                       netif_carrier_off(vsi->netdev);
+                       netif_tx_stop_all_queues(vsi->netdev);
+               }
+               break;
+
+       case I40E_VSI_SRIOV:
+               break;
+
+       case I40E_VSI_VMDQ2:
+       case I40E_VSI_CTRL:
+       case I40E_VSI_MIRROR:
+       default:
+               /* there is no notification for other VSIs */
+               break;
+       }
+}
+
+/**
+ * i40e_veb_link_event - notify elements on the veb of a link event
+ * @veb: veb to be notified
+ * @link_up: link up or down
+ **/
+static void i40e_veb_link_event(struct i40e_veb *veb, bool link_up)
+{
+       struct i40e_pf *pf;
+       int i;
+
+       if (!veb || !veb->pf)
+               return;
+       pf = veb->pf;
+
+       /* depth first... */
+       for (i = 0; i < I40E_MAX_VEB; i++)
+               if (pf->veb[i] && (pf->veb[i]->uplink_seid == veb->seid))
+                       i40e_veb_link_event(pf->veb[i], link_up);
+
+       /* ... now the local VSIs */
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+               if (pf->vsi[i] && (pf->vsi[i]->uplink_seid == veb->seid))
+                       i40e_vsi_link_event(pf->vsi[i], link_up);
+}
+
+/**
+ * i40e_link_event - Update netif_carrier status
+ * @pf: board private structure
+ **/
+static void i40e_link_event(struct i40e_pf *pf)
+{
+       bool new_link, old_link;
+
+       new_link = (pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP);
+       old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
+
+       if (new_link == old_link)
+               return;
+
+       netdev_info(pf->vsi[pf->lan_vsi]->netdev,
+                   "NIC Link is %s\n", (new_link ? "Up" : "Down"));
+
+       /* Notify the base of the switch tree connected to
+        * the link.  Floating VEBs are not notified.
+        */
+       if (pf->lan_veb != I40E_NO_VEB && pf->veb[pf->lan_veb])
+               i40e_veb_link_event(pf->veb[pf->lan_veb], new_link);
+       else
+               i40e_vsi_link_event(pf->vsi[pf->lan_vsi], new_link);
+
+       if (pf->vf)
+               i40e_vc_notify_link_state(pf);
+}
+
+/**
+ * i40e_check_hang_subtask - Check for hung queues and dropped interrupts
+ * @pf: board private structure
+ *
+ * Set the per-queue flags to request a check for stuck queues in the irq
+ * clean functions, then force interrupts to be sure the irq clean is called.
+ **/
+static void i40e_check_hang_subtask(struct i40e_pf *pf)
+{
+       int i, v;
+
+       /* If we're down or resetting, just bail */
+       if (test_bit(__I40E_CONFIG_BUSY, &pf->state))
+               return;
+
+       /* for each VSI/netdev
+        *     for each Tx queue
+        *         set the check flag
+        *     for each q_vector
+        *         force an interrupt
+        */
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               struct i40e_vsi *vsi = pf->vsi[v];
+               int armed = 0;
+
+               if (!pf->vsi[v] ||
+                   test_bit(__I40E_DOWN, &vsi->state) ||
+                   (vsi->netdev && !netif_carrier_ok(vsi->netdev)))
+                       continue;
+
+               for (i = 0; i < vsi->num_queue_pairs; i++) {
+                       set_check_for_tx_hang(&vsi->tx_rings[i]);
+                       if (test_bit(__I40E_HANG_CHECK_ARMED,
+                                    &vsi->tx_rings[i].state))
+                               armed++;
+               }
+
+               if (armed) {
+                       if (!(pf->flags & I40E_FLAG_MSIX_ENABLED)) {
+                               wr32(&vsi->back->hw, I40E_PFINT_DYN_CTL0,
+                                    (I40E_PFINT_DYN_CTL0_INTENA_MASK |
+                                     I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK));
+                       } else {
+                               u16 vec = vsi->base_vector - 1;
+                               u32 val = (I40E_PFINT_DYN_CTLN_INTENA_MASK |
+                                          I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK);
+                               for (i = 0; i < vsi->num_q_vectors; i++, vec++)
+                                       wr32(&vsi->back->hw,
+                                            I40E_PFINT_DYN_CTLN(vec), val);
+                       }
+                       i40e_flush(&vsi->back->hw);
+               }
+       }
+}
+
+/**
+ * i40e_watchdog_subtask - Check and bring link up
+ * @pf: board private structure
+ **/
+static void i40e_watchdog_subtask(struct i40e_pf *pf)
+{
+       int i;
+
+       /* if interface is down do nothing */
+       if (test_bit(__I40E_DOWN, &pf->state) ||
+           test_bit(__I40E_CONFIG_BUSY, &pf->state))
+               return;
+
+       /* Update the stats for active netdevs so the network stack
+        * can look at updated numbers whenever it cares to
+        */
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+               if (pf->vsi[i] && pf->vsi[i]->netdev)
+                       i40e_update_stats(pf->vsi[i]);
+
+       /* Update the stats for the active switching components */
+       for (i = 0; i < I40E_MAX_VEB; i++)
+               if (pf->veb[i])
+                       i40e_update_veb_stats(pf->veb[i]);
+}
+
+/**
+ * i40e_reset_subtask - Set up for resetting the device and driver
+ * @pf: board private structure
+ **/
+static void i40e_reset_subtask(struct i40e_pf *pf)
+{
+       u32 reset_flags = 0;
+
+       if (test_bit(__I40E_REINIT_REQUESTED, &pf->state)) {
+               reset_flags |= (1 << __I40E_REINIT_REQUESTED);
+               clear_bit(__I40E_REINIT_REQUESTED, &pf->state);
+       }
+       if (test_bit(__I40E_PF_RESET_REQUESTED, &pf->state)) {
+               reset_flags |= (1 << __I40E_PF_RESET_REQUESTED);
+               clear_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
+       }
+       if (test_bit(__I40E_CORE_RESET_REQUESTED, &pf->state)) {
+               reset_flags |= (1 << __I40E_CORE_RESET_REQUESTED);
+               clear_bit(__I40E_CORE_RESET_REQUESTED, &pf->state);
+       }
+       if (test_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state)) {
+               reset_flags |= (1 << __I40E_GLOBAL_RESET_REQUESTED);
+               clear_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state);
+       }
+
+       /* If there's a recovery already waiting, it takes
+        * precedence before starting a new reset sequence.
+        */
+       if (test_bit(__I40E_RESET_INTR_RECEIVED, &pf->state)) {
+               i40e_handle_reset_warning(pf);
+               return;
+       }
+
+       /* If we're already down or resetting, just bail */
+       if (reset_flags &&
+           !test_bit(__I40E_DOWN, &pf->state) &&
+           !test_bit(__I40E_CONFIG_BUSY, &pf->state))
+               i40e_do_reset(pf, reset_flags);
+}
+
+/**
+ * i40e_handle_link_event - Handle link event
+ * @pf: board private structure
+ * @e: event info posted on ARQ
+ **/
+static void i40e_handle_link_event(struct i40e_pf *pf,
+                                  struct i40e_arq_event_info *e)
+{
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_aqc_get_link_status *status =
+               (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
+       struct i40e_link_status *hw_link_info = &hw->phy.link_info;
+
+       /* save off old link status information */
+       memcpy(&pf->hw.phy.link_info_old, hw_link_info,
+              sizeof(pf->hw.phy.link_info_old));
+
+       /* update link status */
+       hw_link_info->phy_type = (enum i40e_aq_phy_type)status->phy_type;
+       hw_link_info->link_speed = (enum i40e_aq_link_speed)status->link_speed;
+       hw_link_info->link_info = status->link_info;
+       hw_link_info->an_info = status->an_info;
+       hw_link_info->ext_info = status->ext_info;
+       hw_link_info->lse_enable =
+               le16_to_cpu(status->command_flags) &
+                           I40E_AQ_LSE_ENABLE;
+
+       /* process the event */
+       i40e_link_event(pf);
+
+       /* Do a new status request to re-enable LSE reporting
+        * and load new status information into the hw struct,
+        * then see if the status changed while processing the
+        * initial event.
+        */
+       i40e_aq_get_link_info(&pf->hw, true, NULL, NULL);
+       i40e_link_event(pf);
+}
+
+/**
+ * i40e_clean_adminq_subtask - Clean the AdminQ rings
+ * @pf: board private structure
+ **/
+static void i40e_clean_adminq_subtask(struct i40e_pf *pf)
+{
+       struct i40e_arq_event_info event;
+       struct i40e_hw *hw = &pf->hw;
+       u16 pending, i = 0;
+       i40e_status ret;
+       u16 opcode;
+       u32 val;
+
+       if (!test_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state))
+               return;
+
+       event.msg_size = I40E_MAX_AQ_BUF_SIZE;
+       event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL);
+       if (!event.msg_buf)
+               return;
+
+       do {
+               ret = i40e_clean_arq_element(hw, &event, &pending);
+               if (ret == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
+                       dev_info(&pf->pdev->dev, "No ARQ event found\n");
+                       break;
+               } else if (ret) {
+                       dev_info(&pf->pdev->dev, "ARQ event error %d\n", ret);
+                       break;
+               }
+
+               opcode = le16_to_cpu(event.desc.opcode);
+               switch (opcode) {
+
+               case i40e_aqc_opc_get_link_status:
+                       i40e_handle_link_event(pf, &event);
+                       break;
+               case i40e_aqc_opc_send_msg_to_pf:
+                       ret = i40e_vc_process_vf_msg(pf,
+                                       le16_to_cpu(event.desc.retval),
+                                       le32_to_cpu(event.desc.cookie_high),
+                                       le32_to_cpu(event.desc.cookie_low),
+                                       event.msg_buf,
+                                       event.msg_size);
+                       break;
+               case i40e_aqc_opc_lldp_update_mib:
+                       dev_info(&pf->pdev->dev, "ARQ: Update LLDP MIB event received\n");
+                       break;
+               case i40e_aqc_opc_event_lan_overflow:
+                       dev_info(&pf->pdev->dev, "ARQ LAN queue overflow event received\n");
+                       i40e_handle_lan_overflow_event(pf, &event);
+                       break;
+               default:
+                       dev_info(&pf->pdev->dev,
+                                "ARQ Error: Unknown event %d received\n",
+                                event.desc.opcode);
+                       break;
+               }
+       } while (pending && (i++ < pf->adminq_work_limit));
+
+       clear_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state);
+       /* re-enable Admin queue interrupt cause */
+       val = rd32(hw, I40E_PFINT_ICR0_ENA);
+       val |=  I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
+       wr32(hw, I40E_PFINT_ICR0_ENA, val);
+       i40e_flush(hw);
+
+       kfree(event.msg_buf);
+}
+
+/**
+ * i40e_reconstitute_veb - rebuild the VEB and anything connected to it
+ * @veb: pointer to the VEB instance
+ *
+ * This is a recursive function that first builds the attached VSIs then
+ * recurses in to build the next layer of VEB.  We track the connections
+ * through our own index numbers because the seid's from the HW could
+ * change across the reset.
+ **/
+static int i40e_reconstitute_veb(struct i40e_veb *veb)
+{
+       struct i40e_vsi *ctl_vsi = NULL;
+       struct i40e_pf *pf = veb->pf;
+       int v, veb_idx;
+       int ret;
+
+       /* build VSI that owns this VEB, temporarily attached to base VEB */
+       for (v = 0; v < pf->hw.func_caps.num_vsis && !ctl_vsi; v++) {
+               if (pf->vsi[v] &&
+                   pf->vsi[v]->veb_idx == veb->idx &&
+                   pf->vsi[v]->flags & I40E_VSI_FLAG_VEB_OWNER) {
+                       ctl_vsi = pf->vsi[v];
+                       break;
+               }
+       }
+       if (!ctl_vsi) {
+               dev_info(&pf->pdev->dev,
+                        "missing owner VSI for veb_idx %d\n", veb->idx);
+               ret = -ENOENT;
+               goto end_reconstitute;
+       }
+       if (ctl_vsi != pf->vsi[pf->lan_vsi])
+               ctl_vsi->uplink_seid = pf->vsi[pf->lan_vsi]->uplink_seid;
+       ret = i40e_add_vsi(ctl_vsi);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "rebuild of owner VSI failed: %d\n", ret);
+               goto end_reconstitute;
+       }
+       i40e_vsi_reset_stats(ctl_vsi);
+
+       /* create the VEB in the switch and move the VSI onto the VEB */
+       ret = i40e_add_veb(veb, ctl_vsi);
+       if (ret)
+               goto end_reconstitute;
+
+       /* create the remaining VSIs attached to this VEB */
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               if (!pf->vsi[v] || pf->vsi[v] == ctl_vsi)
+                       continue;
+
+               if (pf->vsi[v]->veb_idx == veb->idx) {
+                       struct i40e_vsi *vsi = pf->vsi[v];
+                       vsi->uplink_seid = veb->seid;
+                       ret = i40e_add_vsi(vsi);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "rebuild of vsi_idx %d failed: %d\n",
+                                        v, ret);
+                               goto end_reconstitute;
+                       }
+                       i40e_vsi_reset_stats(vsi);
+               }
+       }
+
+       /* create any VEBs attached to this VEB - RECURSION */
+       for (veb_idx = 0; veb_idx < I40E_MAX_VEB; veb_idx++) {
+               if (pf->veb[veb_idx] && pf->veb[veb_idx]->veb_idx == veb->idx) {
+                       pf->veb[veb_idx]->uplink_seid = veb->seid;
+                       ret = i40e_reconstitute_veb(pf->veb[veb_idx]);
+                       if (ret)
+                               break;
+               }
+       }
+
+end_reconstitute:
+       return ret;
+}
+
+/**
+ * i40e_get_capabilities - get info about the HW
+ * @pf: the PF struct
+ **/
+static int i40e_get_capabilities(struct i40e_pf *pf)
+{
+       struct i40e_aqc_list_capabilities_element_resp *cap_buf;
+       u16 data_size;
+       int buf_len;
+       int err;
+
+       buf_len = 40 * sizeof(struct i40e_aqc_list_capabilities_element_resp);
+       do {
+               cap_buf = kzalloc(buf_len, GFP_KERNEL);
+               if (!cap_buf)
+                       return -ENOMEM;
+
+               /* this loads the data into the hw struct for us */
+               err = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,
+                                           &data_size,
+                                           i40e_aqc_opc_list_func_capabilities,
+                                           NULL);
+               /* data loaded, buffer no longer needed */
+               kfree(cap_buf);
+
+               if (pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOMEM) {
+                       /* retry with a larger buffer */
+                       buf_len = data_size;
+               } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) {
+                       dev_info(&pf->pdev->dev,
+                                "capability discovery failed: aq=%d\n",
+                                pf->hw.aq.asq_last_status);
+                       return -ENODEV;
+               }
+       } while (err);
+
+       if (pf->hw.debug_mask & I40E_DEBUG_USER)
+               dev_info(&pf->pdev->dev,
+                        "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n",
+                        pf->hw.pf_id, pf->hw.func_caps.num_vfs,
+                        pf->hw.func_caps.num_msix_vectors,
+                        pf->hw.func_caps.num_msix_vectors_vf,
+                        pf->hw.func_caps.fd_filters_guaranteed,
+                        pf->hw.func_caps.fd_filters_best_effort,
+                        pf->hw.func_caps.num_tx_qp,
+                        pf->hw.func_caps.num_vsis);
+
+       return 0;
+}
+
+/**
+ * i40e_fdir_setup - initialize the Flow Director resources
+ * @pf: board private structure
+ **/
+static void i40e_fdir_setup(struct i40e_pf *pf)
+{
+       struct i40e_vsi *vsi;
+       bool new_vsi = false;
+       int err, i;
+
+       if (!(pf->flags & (I40E_FLAG_FDIR_ENABLED|I40E_FLAG_FDIR_ATR_ENABLED)))
+               return;
+
+       pf->atr_sample_rate = I40E_DEFAULT_ATR_SAMPLE_RATE;
+
+       /* find existing or make new FDIR VSI */
+       vsi = NULL;
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+               if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR)
+                       vsi = pf->vsi[i];
+       if (!vsi) {
+               vsi = i40e_vsi_setup(pf, I40E_VSI_FDIR, pf->mac_seid, 0);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n");
+                       pf->flags &= ~I40E_FLAG_FDIR_ENABLED;
+                       return;
+               }
+               new_vsi = true;
+       }
+       WARN_ON(vsi->base_queue != I40E_FDIR_RING);
+       i40e_vsi_setup_irqhandler(vsi, i40e_fdir_clean_rings);
+
+       err = i40e_vsi_setup_tx_resources(vsi);
+       if (!err)
+               err = i40e_vsi_setup_rx_resources(vsi);
+       if (!err)
+               err = i40e_vsi_configure(vsi);
+       if (!err && new_vsi) {
+               char int_name[IFNAMSIZ + 9];
+               snprintf(int_name, sizeof(int_name) - 1, "%s-fdir",
+                        dev_driver_string(&pf->pdev->dev));
+               err = i40e_vsi_request_irq(vsi, int_name);
+       }
+       if (!err)
+               err = i40e_up_complete(vsi);
+
+       clear_bit(__I40E_NEEDS_RESTART, &vsi->state);
+}
+
+/**
+ * i40e_fdir_teardown - release the Flow Director resources
+ * @pf: board private structure
+ **/
+static void i40e_fdir_teardown(struct i40e_pf *pf)
+{
+       int i;
+
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+               if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
+                       i40e_vsi_release(pf->vsi[i]);
+                       break;
+               }
+       }
+}
+
+/**
+ * i40e_handle_reset_warning - prep for the core to reset
+ * @pf: board private structure
+ *
+ * Close up the VFs and other things in prep for a Core Reset,
+ * then get ready to rebuild the world.
+ **/
+static void i40e_handle_reset_warning(struct i40e_pf *pf)
+{
+       struct i40e_driver_version dv;
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status ret;
+       u32 v;
+
+       clear_bit(__I40E_RESET_INTR_RECEIVED, &pf->state);
+       if (test_and_set_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
+               return;
+
+       dev_info(&pf->pdev->dev, "Tearing down internal switch for reset\n");
+
+       i40e_vc_notify_reset(pf);
+
+       /* quiesce the VSIs and their queues that are not already DOWN */
+       i40e_pf_quiesce_all_vsi(pf);
+
+       for (v = 0; v < pf->hw.func_caps.num_vsis; v++) {
+               if (pf->vsi[v])
+                       pf->vsi[v]->seid = 0;
+       }
+
+       i40e_shutdown_adminq(&pf->hw);
+
+       /* Now we wait for GRST to settle out.
+        * We don't have to delete the VEBs or VSIs from the hw switch
+        * because the reset will make them disappear.
+        */
+       ret = i40e_pf_reset(hw);
+       if (ret)
+               dev_info(&pf->pdev->dev, "PF reset failed, %d\n", ret);
+       pf->pfr_count++;
+
+       if (test_bit(__I40E_DOWN, &pf->state))
+               goto end_core_reset;
+       dev_info(&pf->pdev->dev, "Rebuilding internal switch\n");
+
+       /* rebuild the basics for the AdminQ, HMC, and initial HW switch */
+       ret = i40e_init_adminq(&pf->hw);
+       if (ret) {
+               dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, %d\n", ret);
+               goto end_core_reset;
+       }
+
+       ret = i40e_get_capabilities(pf);
+       if (ret) {
+               dev_info(&pf->pdev->dev, "i40e_get_capabilities failed, %d\n",
+                        ret);
+               goto end_core_reset;
+       }
+
+       /* call shutdown HMC */
+       ret = i40e_shutdown_lan_hmc(hw);
+       if (ret) {
+               dev_info(&pf->pdev->dev, "shutdown_lan_hmc failed: %d\n", ret);
+               goto end_core_reset;
+       }
+
+       ret = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
+                               hw->func_caps.num_rx_qp,
+                               pf->fcoe_hmc_cntx_num, pf->fcoe_hmc_filt_num);
+       if (ret) {
+               dev_info(&pf->pdev->dev, "init_lan_hmc failed: %d\n", ret);
+               goto end_core_reset;
+       }
+       ret = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
+       if (ret) {
+               dev_info(&pf->pdev->dev, "configure_lan_hmc failed: %d\n", ret);
+               goto end_core_reset;
+       }
+
+       /* do basic switch setup */
+       ret = i40e_setup_pf_switch(pf);
+       if (ret)
+               goto end_core_reset;
+
+       /* Rebuild the VSIs and VEBs that existed before reset.
+        * They are still in our local switch element arrays, so only
+        * need to rebuild the switch model in the HW.
+        *
+        * If there were VEBs but the reconstitution failed, we'll try
+        * try to recover minimal use by getting the basic PF VSI working.
+        */
+       if (pf->vsi[pf->lan_vsi]->uplink_seid != pf->mac_seid) {
+               dev_info(&pf->pdev->dev, "attempting to rebuild switch\n");
+               /* find the one VEB connected to the MAC, and find orphans */
+               for (v = 0; v < I40E_MAX_VEB; v++) {
+                       if (!pf->veb[v])
+                               continue;
+
+                       if (pf->veb[v]->uplink_seid == pf->mac_seid ||
+                           pf->veb[v]->uplink_seid == 0) {
+                               ret = i40e_reconstitute_veb(pf->veb[v]);
+
+                               if (!ret)
+                                       continue;
+
+                               /* If Main VEB failed, we're in deep doodoo,
+                                * so give up rebuilding the switch and set up
+                                * for minimal rebuild of PF VSI.
+                                * If orphan failed, we'll report the error
+                                * but try to keep going.
+                                */
+                               if (pf->veb[v]->uplink_seid == pf->mac_seid) {
+                                       dev_info(&pf->pdev->dev,
+                                                "rebuild of switch failed: %d, will try to set up simple PF connection\n",
+                                                ret);
+                                       pf->vsi[pf->lan_vsi]->uplink_seid
+                                                               = pf->mac_seid;
+                                       break;
+                               } else if (pf->veb[v]->uplink_seid == 0) {
+                                       dev_info(&pf->pdev->dev,
+                                                "rebuild of orphan VEB failed: %d\n",
+                                                ret);
+                               }
+                       }
+               }
+       }
+
+       if (pf->vsi[pf->lan_vsi]->uplink_seid == pf->mac_seid) {
+               dev_info(&pf->pdev->dev, "attempting to rebuild PF VSI\n");
+               /* no VEB, so rebuild only the Main VSI */
+               ret = i40e_add_vsi(pf->vsi[pf->lan_vsi]);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "rebuild of Main VSI failed: %d\n", ret);
+                       goto end_core_reset;
+               }
+       }
+
+       /* reinit the misc interrupt */
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+               ret = i40e_setup_misc_vector(pf);
+
+       /* restart the VSIs that were rebuilt and running before the reset */
+       i40e_pf_unquiesce_all_vsi(pf);
+
+       /* tell the firmware that we're starting */
+       dv.major_version = DRV_VERSION_MAJOR;
+       dv.minor_version = DRV_VERSION_MINOR;
+       dv.build_version = DRV_VERSION_BUILD;
+       dv.subbuild_version = 0;
+       i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
+
+       dev_info(&pf->pdev->dev, "PF reset done\n");
+
+end_core_reset:
+       clear_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state);
+}
+
+/**
+ * i40e_handle_mdd_event
+ * @pf: pointer to the pf structure
+ *
+ * Called from the MDD irq handler to identify possibly malicious vfs
+ **/
+static void i40e_handle_mdd_event(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       bool mdd_detected = false;
+       struct i40e_vf *vf;
+       u32 reg;
+       int i;
+
+       if (!test_bit(__I40E_MDD_EVENT_PENDING, &pf->state))
+               return;
+
+       /* find what triggered the MDD event */
+       reg = rd32(hw, I40E_GL_MDET_TX);
+       if (reg & I40E_GL_MDET_TX_VALID_MASK) {
+               u8 func = (reg & I40E_GL_MDET_TX_FUNCTION_MASK)
+                               >> I40E_GL_MDET_TX_FUNCTION_SHIFT;
+               u8 event = (reg & I40E_GL_MDET_TX_EVENT_SHIFT)
+                               >> I40E_GL_MDET_TX_EVENT_SHIFT;
+               u8 queue = (reg & I40E_GL_MDET_TX_QUEUE_MASK)
+                               >> I40E_GL_MDET_TX_QUEUE_SHIFT;
+               dev_info(&pf->pdev->dev,
+                        "Malicious Driver Detection TX event 0x%02x on q %d of function 0x%02x\n",
+                        event, queue, func);
+               wr32(hw, I40E_GL_MDET_TX, 0xffffffff);
+               mdd_detected = true;
+       }
+       reg = rd32(hw, I40E_GL_MDET_RX);
+       if (reg & I40E_GL_MDET_RX_VALID_MASK) {
+               u8 func = (reg & I40E_GL_MDET_RX_FUNCTION_MASK)
+                               >> I40E_GL_MDET_RX_FUNCTION_SHIFT;
+               u8 event = (reg & I40E_GL_MDET_RX_EVENT_SHIFT)
+                               >> I40E_GL_MDET_RX_EVENT_SHIFT;
+               u8 queue = (reg & I40E_GL_MDET_RX_QUEUE_MASK)
+                               >> I40E_GL_MDET_RX_QUEUE_SHIFT;
+               dev_info(&pf->pdev->dev,
+                        "Malicious Driver Detection RX event 0x%02x on q %d of function 0x%02x\n",
+                        event, queue, func);
+               wr32(hw, I40E_GL_MDET_RX, 0xffffffff);
+               mdd_detected = true;
+       }
+
+       /* see if one of the VFs needs its hand slapped */
+       for (i = 0; i < pf->num_alloc_vfs && mdd_detected; i++) {
+               vf = &(pf->vf[i]);
+               reg = rd32(hw, I40E_VP_MDET_TX(i));
+               if (reg & I40E_VP_MDET_TX_VALID_MASK) {
+                       wr32(hw, I40E_VP_MDET_TX(i), 0xFFFF);
+                       vf->num_mdd_events++;
+                       dev_info(&pf->pdev->dev, "MDD TX event on VF %d\n", i);
+               }
+
+               reg = rd32(hw, I40E_VP_MDET_RX(i));
+               if (reg & I40E_VP_MDET_RX_VALID_MASK) {
+                       wr32(hw, I40E_VP_MDET_RX(i), 0xFFFF);
+                       vf->num_mdd_events++;
+                       dev_info(&pf->pdev->dev, "MDD RX event on VF %d\n", i);
+               }
+
+               if (vf->num_mdd_events > I40E_DEFAULT_NUM_MDD_EVENTS_ALLOWED) {
+                       dev_info(&pf->pdev->dev,
+                                "Too many MDD events on VF %d, disabled\n", i);
+                       dev_info(&pf->pdev->dev,
+                                "Use PF Control I/F to re-enable the VF\n");
+                       set_bit(I40E_VF_STAT_DISABLED, &vf->vf_states);
+               }
+       }
+
+       /* re-enable mdd interrupt cause */
+       clear_bit(__I40E_MDD_EVENT_PENDING, &pf->state);
+       reg = rd32(hw, I40E_PFINT_ICR0_ENA);
+       reg |=  I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK;
+       wr32(hw, I40E_PFINT_ICR0_ENA, reg);
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_service_task - Run the driver's async subtasks
+ * @work: pointer to work_struct containing our data
+ **/
+static void i40e_service_task(struct work_struct *work)
+{
+       struct i40e_pf *pf = container_of(work,
+                                         struct i40e_pf,
+                                         service_task);
+       unsigned long start_time = jiffies;
+
+       i40e_reset_subtask(pf);
+       i40e_handle_mdd_event(pf);
+       i40e_vc_process_vflr_event(pf);
+       i40e_watchdog_subtask(pf);
+       i40e_fdir_reinit_subtask(pf);
+       i40e_check_hang_subtask(pf);
+       i40e_sync_filters_subtask(pf);
+       i40e_clean_adminq_subtask(pf);
+
+       i40e_service_event_complete(pf);
+
+       /* If the tasks have taken longer than one timer cycle or there
+        * is more work to be done, reschedule the service task now
+        * rather than wait for the timer to tick again.
+        */
+       if (time_after(jiffies, (start_time + pf->service_timer_period)) ||
+           test_bit(__I40E_ADMINQ_EVENT_PENDING, &pf->state)            ||
+           test_bit(__I40E_MDD_EVENT_PENDING, &pf->state)               ||
+           test_bit(__I40E_VFLR_EVENT_PENDING, &pf->state))
+               i40e_service_event_schedule(pf);
+}
+
+/**
+ * i40e_service_timer - timer callback
+ * @data: pointer to PF struct
+ **/
+static void i40e_service_timer(unsigned long data)
+{
+       struct i40e_pf *pf = (struct i40e_pf *)data;
+
+       mod_timer(&pf->service_timer,
+                 round_jiffies(jiffies + pf->service_timer_period));
+       i40e_service_event_schedule(pf);
+}
+
+/**
+ * i40e_set_num_rings_in_vsi - Determine number of rings in the VSI
+ * @vsi: the VSI being configured
+ **/
+static int i40e_set_num_rings_in_vsi(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+
+       switch (vsi->type) {
+       case I40E_VSI_MAIN:
+               vsi->alloc_queue_pairs = pf->num_lan_qps;
+               vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+                                     I40E_REQ_DESCRIPTOR_MULTIPLE);
+               if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+                       vsi->num_q_vectors = pf->num_lan_msix;
+               else
+                       vsi->num_q_vectors = 1;
+
+               break;
+
+       case I40E_VSI_FDIR:
+               vsi->alloc_queue_pairs = 1;
+               vsi->num_desc = ALIGN(I40E_FDIR_RING_COUNT,
+                                     I40E_REQ_DESCRIPTOR_MULTIPLE);
+               vsi->num_q_vectors = 1;
+               break;
+
+       case I40E_VSI_VMDQ2:
+               vsi->alloc_queue_pairs = pf->num_vmdq_qps;
+               vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+                                     I40E_REQ_DESCRIPTOR_MULTIPLE);
+               vsi->num_q_vectors = pf->num_vmdq_msix;
+               break;
+
+       case I40E_VSI_SRIOV:
+               vsi->alloc_queue_pairs = pf->num_vf_qps;
+               vsi->num_desc = ALIGN(I40E_DEFAULT_NUM_DESCRIPTORS,
+                                     I40E_REQ_DESCRIPTOR_MULTIPLE);
+               break;
+
+       default:
+               WARN_ON(1);
+               return -ENODATA;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_mem_alloc - Allocates the next available struct vsi in the PF
+ * @pf: board private structure
+ * @type: type of VSI
+ *
+ * On error: returns error code (negative)
+ * On success: returns vsi index in PF (positive)
+ **/
+static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
+{
+       int ret = -ENODEV;
+       struct i40e_vsi *vsi;
+       int vsi_idx;
+       int i;
+
+       /* Need to protect the allocation of the VSIs at the PF level */
+       mutex_lock(&pf->switch_mutex);
+
+       /* VSI list may be fragmented if VSI creation/destruction has
+        * been happening.  We can afford to do a quick scan to look
+        * for any free VSIs in the list.
+        *
+        * find next empty vsi slot, looping back around if necessary
+        */
+       i = pf->next_vsi;
+       while (i < pf->hw.func_caps.num_vsis && pf->vsi[i])
+               i++;
+       if (i >= pf->hw.func_caps.num_vsis) {
+               i = 0;
+               while (i < pf->next_vsi && pf->vsi[i])
+                       i++;
+       }
+
+       if (i < pf->hw.func_caps.num_vsis && !pf->vsi[i]) {
+               vsi_idx = i;             /* Found one! */
+       } else {
+               ret = -ENODEV;
+               goto err_alloc_vsi;  /* out of VSI slots! */
+       }
+       pf->next_vsi = ++i;
+
+       vsi = kzalloc(sizeof(*vsi), GFP_KERNEL);
+       if (!vsi) {
+               ret = -ENOMEM;
+               goto err_alloc_vsi;
+       }
+       vsi->type = type;
+       vsi->back = pf;
+       set_bit(__I40E_DOWN, &vsi->state);
+       vsi->flags = 0;
+       vsi->idx = vsi_idx;
+       vsi->rx_itr_setting = pf->rx_itr_default;
+       vsi->tx_itr_setting = pf->tx_itr_default;
+       vsi->netdev_registered = false;
+       vsi->work_limit = I40E_DEFAULT_IRQ_WORK;
+       INIT_LIST_HEAD(&vsi->mac_filter_list);
+
+       i40e_set_num_rings_in_vsi(vsi);
+
+       /* Setup default MSIX irq handler for VSI */
+       i40e_vsi_setup_irqhandler(vsi, i40e_msix_clean_rings);
+
+       pf->vsi[vsi_idx] = vsi;
+       ret = vsi_idx;
+err_alloc_vsi:
+       mutex_unlock(&pf->switch_mutex);
+       return ret;
+}
+
+/**
+ * i40e_vsi_clear - Deallocate the VSI provided
+ * @vsi: the VSI being un-configured
+ **/
+static int i40e_vsi_clear(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf;
+
+       if (!vsi)
+               return 0;
+
+       if (!vsi->back)
+               goto free_vsi;
+       pf = vsi->back;
+
+       mutex_lock(&pf->switch_mutex);
+       if (!pf->vsi[vsi->idx]) {
+               dev_err(&pf->pdev->dev, "pf->vsi[%d] is NULL, just free vsi[%d](%p,type %d)\n",
+                       vsi->idx, vsi->idx, vsi, vsi->type);
+               goto unlock_vsi;
+       }
+
+       if (pf->vsi[vsi->idx] != vsi) {
+               dev_err(&pf->pdev->dev,
+                       "pf->vsi[%d](%p, type %d) != vsi[%d](%p,type %d): no free!\n",
+                       pf->vsi[vsi->idx]->idx,
+                       pf->vsi[vsi->idx],
+                       pf->vsi[vsi->idx]->type,
+                       vsi->idx, vsi, vsi->type);
+               goto unlock_vsi;
+       }
+
+       /* updates the pf for this cleared vsi */
+       i40e_put_lump(pf->qp_pile, vsi->base_queue, vsi->idx);
+       i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx);
+
+       pf->vsi[vsi->idx] = NULL;
+       if (vsi->idx < pf->next_vsi)
+               pf->next_vsi = vsi->idx;
+
+unlock_vsi:
+       mutex_unlock(&pf->switch_mutex);
+free_vsi:
+       kfree(vsi);
+
+       return 0;
+}
+
+/**
+ * i40e_alloc_rings - Allocates the Rx and Tx rings for the provided VSI
+ * @vsi: the VSI being configured
+ **/
+static int i40e_alloc_rings(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       int ret = 0;
+       int i;
+
+       vsi->rx_rings = kcalloc(vsi->alloc_queue_pairs,
+                               sizeof(struct i40e_ring), GFP_KERNEL);
+       if (!vsi->rx_rings) {
+               ret = -ENOMEM;
+               goto err_alloc_rings;
+       }
+
+       vsi->tx_rings = kcalloc(vsi->alloc_queue_pairs,
+                               sizeof(struct i40e_ring), GFP_KERNEL);
+       if (!vsi->tx_rings) {
+               ret = -ENOMEM;
+               kfree(vsi->rx_rings);
+               goto err_alloc_rings;
+       }
+
+       /* Set basic values in the rings to be used later during open() */
+       for (i = 0; i < vsi->alloc_queue_pairs; i++) {
+               struct i40e_ring *rx_ring = &vsi->rx_rings[i];
+               struct i40e_ring *tx_ring = &vsi->tx_rings[i];
+
+               tx_ring->queue_index = i;
+               tx_ring->reg_idx = vsi->base_queue + i;
+               tx_ring->ring_active = false;
+               tx_ring->vsi = vsi;
+               tx_ring->netdev = vsi->netdev;
+               tx_ring->dev = &pf->pdev->dev;
+               tx_ring->count = vsi->num_desc;
+               tx_ring->size = 0;
+               tx_ring->dcb_tc = 0;
+
+               rx_ring->queue_index = i;
+               rx_ring->reg_idx = vsi->base_queue + i;
+               rx_ring->ring_active = false;
+               rx_ring->vsi = vsi;
+               rx_ring->netdev = vsi->netdev;
+               rx_ring->dev = &pf->pdev->dev;
+               rx_ring->count = vsi->num_desc;
+               rx_ring->size = 0;
+               rx_ring->dcb_tc = 0;
+               if (pf->flags & I40E_FLAG_16BYTE_RX_DESC_ENABLED)
+                       set_ring_16byte_desc_enabled(rx_ring);
+               else
+                       clear_ring_16byte_desc_enabled(rx_ring);
+       }
+
+err_alloc_rings:
+       return ret;
+}
+
+/**
+ * i40e_vsi_clear_rings - Deallocates the Rx and Tx rings for the provided VSI
+ * @vsi: the VSI being cleaned
+ **/
+static int i40e_vsi_clear_rings(struct i40e_vsi *vsi)
+{
+       if (vsi) {
+               kfree(vsi->rx_rings);
+               kfree(vsi->tx_rings);
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_reserve_msix_vectors - Reserve MSI-X vectors in the kernel
+ * @pf: board private structure
+ * @vectors: the number of MSI-X vectors to request
+ *
+ * Returns the number of vectors reserved, or error
+ **/
+static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors)
+{
+       int err = 0;
+
+       pf->num_msix_entries = 0;
+       while (vectors >= I40E_MIN_MSIX) {
+               err = pci_enable_msix(pf->pdev, pf->msix_entries, vectors);
+               if (err == 0) {
+                       /* good to go */
+                       pf->num_msix_entries = vectors;
+                       break;
+               } else if (err < 0) {
+                       /* total failure */
+                       dev_info(&pf->pdev->dev,
+                                "MSI-X vector reservation failed: %d\n", err);
+                       vectors = 0;
+                       break;
+               } else {
+                       /* err > 0 is the hint for retry */
+                       dev_info(&pf->pdev->dev,
+                                "MSI-X vectors wanted %d, retrying with %d\n",
+                                vectors, err);
+                       vectors = err;
+               }
+       }
+
+       if (vectors > 0 && vectors < I40E_MIN_MSIX) {
+               dev_info(&pf->pdev->dev,
+                        "Couldn't get enough vectors, only %d available\n",
+                        vectors);
+               vectors = 0;
+       }
+
+       return vectors;
+}
+
+/**
+ * i40e_init_msix - Setup the MSIX capability
+ * @pf: board private structure
+ *
+ * Work with the OS to set up the MSIX vectors needed.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_init_msix(struct i40e_pf *pf)
+{
+       i40e_status err = 0;
+       struct i40e_hw *hw = &pf->hw;
+       int v_budget, i;
+       int vec;
+
+       if (!(pf->flags & I40E_FLAG_MSIX_ENABLED))
+               return -ENODEV;
+
+       /* The number of vectors we'll request will be comprised of:
+        *   - Add 1 for "other" cause for Admin Queue events, etc.
+        *   - The number of LAN queue pairs
+        *        already adjusted for the NUMA node
+        *        assumes symmetric Tx/Rx pairing
+        *   - The number of VMDq pairs
+        * Once we count this up, try the request.
+        *
+        * If we can't get what we want, we'll simplify to nearly nothing
+        * and try again.  If that still fails, we punt.
+        */
+       pf->num_lan_msix = pf->num_lan_qps;
+       pf->num_vmdq_msix = pf->num_vmdq_qps;
+       v_budget = 1 + pf->num_lan_msix;
+       v_budget += (pf->num_vmdq_vsis * pf->num_vmdq_msix);
+       if (pf->flags & I40E_FLAG_FDIR_ENABLED)
+               v_budget++;
+
+       /* Scale down if necessary, and the rings will share vectors */
+       v_budget = min_t(int, v_budget, hw->func_caps.num_msix_vectors);
+
+       pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
+                                  GFP_KERNEL);
+       if (!pf->msix_entries)
+               return -ENOMEM;
+
+       for (i = 0; i < v_budget; i++)
+               pf->msix_entries[i].entry = i;
+       vec = i40e_reserve_msix_vectors(pf, v_budget);
+       if (vec < I40E_MIN_MSIX) {
+               pf->flags &= ~I40E_FLAG_MSIX_ENABLED;
+               kfree(pf->msix_entries);
+               pf->msix_entries = NULL;
+               return -ENODEV;
+
+       } else if (vec == I40E_MIN_MSIX) {
+               /* Adjust for minimal MSIX use */
+               dev_info(&pf->pdev->dev, "Features disabled, not enough MSIX vectors\n");
+               pf->flags &= ~I40E_FLAG_VMDQ_ENABLED;
+               pf->num_vmdq_vsis = 0;
+               pf->num_vmdq_qps = 0;
+               pf->num_vmdq_msix = 0;
+               pf->num_lan_qps = 1;
+               pf->num_lan_msix = 1;
+
+       } else if (vec != v_budget) {
+               /* Scale vector usage down */
+               pf->num_vmdq_msix = 1;    /* force VMDqs to only one vector */
+               vec--;                    /* reserve the misc vector */
+
+               /* partition out the remaining vectors */
+               switch (vec) {
+               case 2:
+                       pf->num_vmdq_vsis = 1;
+                       pf->num_lan_msix = 1;
+                       break;
+               case 3:
+                       pf->num_vmdq_vsis = 1;
+                       pf->num_lan_msix = 2;
+                       break;
+               default:
+                       pf->num_lan_msix = min_t(int, (vec / 2),
+                                                pf->num_lan_qps);
+                       pf->num_vmdq_vsis = min_t(int, (vec - pf->num_lan_msix),
+                                                 I40E_DEFAULT_NUM_VMDQ_VSI);
+                       break;
+               }
+       }
+
+       return err;
+}
+
+/**
+ * i40e_alloc_q_vectors - Allocate memory for interrupt vectors
+ * @vsi: the VSI being configured
+ *
+ * We allocate one q_vector per queue interrupt.  If allocation fails we
+ * return -ENOMEM.
+ **/
+static int i40e_alloc_q_vectors(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       int v_idx, num_q_vectors;
+
+       /* if not MSIX, give the one vector only to the LAN VSI */
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED)
+               num_q_vectors = vsi->num_q_vectors;
+       else if (vsi == pf->vsi[pf->lan_vsi])
+               num_q_vectors = 1;
+       else
+               return -EINVAL;
+
+       vsi->q_vectors = kcalloc(num_q_vectors,
+                                sizeof(struct i40e_q_vector),
+                                GFP_KERNEL);
+       if (!vsi->q_vectors)
+               return -ENOMEM;
+
+       for (v_idx = 0; v_idx < num_q_vectors; v_idx++) {
+               vsi->q_vectors[v_idx].vsi = vsi;
+               vsi->q_vectors[v_idx].v_idx = v_idx;
+               cpumask_set_cpu(v_idx, &vsi->q_vectors[v_idx].affinity_mask);
+               if (vsi->netdev)
+                       netif_napi_add(vsi->netdev, &vsi->q_vectors[v_idx].napi,
+                                      i40e_napi_poll, vsi->work_limit);
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_init_interrupt_scheme - Determine proper interrupt scheme
+ * @pf: board private structure to initialize
+ **/
+static void i40e_init_interrupt_scheme(struct i40e_pf *pf)
+{
+       int err = 0;
+
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               err = i40e_init_msix(pf);
+               if (err) {
+                       pf->flags &= ~(I40E_FLAG_RSS_ENABLED       |
+                                       I40E_FLAG_MQ_ENABLED       |
+                                       I40E_FLAG_DCB_ENABLED      |
+                                       I40E_FLAG_SRIOV_ENABLED    |
+                                       I40E_FLAG_FDIR_ENABLED     |
+                                       I40E_FLAG_FDIR_ATR_ENABLED |
+                                       I40E_FLAG_VMDQ_ENABLED);
+
+                       /* rework the queue expectations without MSIX */
+                       i40e_determine_queue_usage(pf);
+               }
+       }
+
+       if (!(pf->flags & I40E_FLAG_MSIX_ENABLED) &&
+           (pf->flags & I40E_FLAG_MSI_ENABLED)) {
+               err = pci_enable_msi(pf->pdev);
+               if (err) {
+                       dev_info(&pf->pdev->dev,
+                                "MSI init failed (%d), trying legacy.\n", err);
+                       pf->flags &= ~I40E_FLAG_MSI_ENABLED;
+               }
+       }
+
+       /* track first vector for misc interrupts */
+       err = i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT-1);
+}
+
+/**
+ * i40e_setup_misc_vector - Setup the misc vector to handle non queue events
+ * @pf: board private structure
+ *
+ * This sets up the handler for MSIX 0, which is used to manage the
+ * non-queue interrupts, e.g. AdminQ and errors.  This is not used
+ * when in MSI or Legacy interrupt mode.
+ **/
+static int i40e_setup_misc_vector(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       int err = 0;
+
+       /* Only request the irq if this is the first time through, and
+        * not when we're rebuilding after a Reset
+        */
+       if (!test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) {
+               err = request_irq(pf->msix_entries[0].vector,
+                                 i40e_intr, 0, pf->misc_int_name, pf);
+               if (err) {
+                       dev_info(&pf->pdev->dev,
+                                "request_irq for msix_misc failed: %d\n", err);
+                       return -EFAULT;
+               }
+       }
+
+       i40e_enable_misc_int_causes(hw);
+
+       /* associate no queues to the misc vector */
+       wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST);
+       wr32(hw, I40E_PFINT_ITR0(I40E_RX_ITR), I40E_ITR_8K);
+
+       i40e_flush(hw);
+
+       i40e_irq_dynamic_enable_icr0(pf);
+
+       return err;
+}
+
+/**
+ * i40e_config_rss - Prepare for RSS if used
+ * @pf: board private structure
+ **/
+static int i40e_config_rss(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       u32 lut = 0;
+       int i, j;
+       u64 hena;
+       /* Set of random keys generated using kernel random number generator */
+       static const u32 seed[I40E_PFQF_HKEY_MAX_INDEX + 1] = {0x41b01687,
+                               0x183cfd8c, 0xce880440, 0x580cbc3c, 0x35897377,
+                               0x328b25e1, 0x4fa98922, 0xb7d90c14, 0xd5bad70d,
+                               0xcd15a2c1, 0xe8580225, 0x4a1e9d11, 0xfe5731be};
+
+       /* Fill out hash function seed */
+       for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+               wr32(hw, I40E_PFQF_HKEY(i), seed[i]);
+
+       /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */
+       hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
+               ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
+       hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP) |
+               ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)|
+               ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6);
+       wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
+       wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
+
+       /* Populate the LUT with max no. of queues in round robin fashion */
+       for (i = 0, j = 0; i < pf->hw.func_caps.rss_table_size; i++, j++) {
+
+               /* The assumption is that lan qp count will be the highest
+                * qp count for any PF VSI that needs RSS.
+                * If multiple VSIs need RSS support, all the qp counts
+                * for those VSIs should be a power of 2 for RSS to work.
+                * If LAN VSI is the only consumer for RSS then this requirement
+                * is not necessary.
+                */
+               if (j == pf->rss_size)
+                       j = 0;
+               /* lut = 4-byte sliding window of 4 lut entries */
+               lut = (lut << 8) | (j &
+                        ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1));
+               /* On i = 3, we have 4 entries in lut; write to the register */
+               if ((i & 3) == 3)
+                       wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
+       }
+       i40e_flush(hw);
+
+       return 0;
+}
+
+/**
+ * i40e_sw_init - Initialize general software structures (struct i40e_pf)
+ * @pf: board private structure to initialize
+ *
+ * i40e_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+static int i40e_sw_init(struct i40e_pf *pf)
+{
+       int err = 0;
+       int size;
+
+       pf->msg_enable = netif_msg_init(I40E_DEFAULT_MSG_ENABLE,
+                               (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK));
+       if (debug != -1 && debug != I40E_DEFAULT_MSG_ENABLE) {
+               if (I40E_DEBUG_USER & debug)
+                       pf->hw.debug_mask = debug;
+               pf->msg_enable = netif_msg_init((debug & ~I40E_DEBUG_USER),
+                                               I40E_DEFAULT_MSG_ENABLE);
+       }
+
+       /* Set default capability flags */
+       pf->flags = I40E_FLAG_RX_CSUM_ENABLED |
+                   I40E_FLAG_MSI_ENABLED     |
+                   I40E_FLAG_MSIX_ENABLED    |
+                   I40E_FLAG_RX_PS_ENABLED   |
+                   I40E_FLAG_MQ_ENABLED      |
+                   I40E_FLAG_RX_1BUF_ENABLED;
+
+       pf->rss_size_max = 0x1 << pf->hw.func_caps.rss_table_entry_width;
+       if (pf->hw.func_caps.rss) {
+               pf->flags |= I40E_FLAG_RSS_ENABLED;
+               pf->rss_size = min_t(int, pf->rss_size_max,
+                                    nr_cpus_node(numa_node_id()));
+       } else {
+               pf->rss_size = 1;
+       }
+
+       if (pf->hw.func_caps.dcb)
+               pf->num_tc_qps = I40E_DEFAULT_QUEUES_PER_TC;
+       else
+               pf->num_tc_qps = 0;
+
+       if (pf->hw.func_caps.fd) {
+               /* FW/NVM is not yet fixed in this regard */
+               if ((pf->hw.func_caps.fd_filters_guaranteed > 0) ||
+                   (pf->hw.func_caps.fd_filters_best_effort > 0)) {
+                       pf->flags |= I40E_FLAG_FDIR_ATR_ENABLED;
+                       dev_info(&pf->pdev->dev,
+                                "Flow Director ATR mode Enabled\n");
+                       pf->flags |= I40E_FLAG_FDIR_ENABLED;
+                       dev_info(&pf->pdev->dev,
+                                "Flow Director Side Band mode Enabled\n");
+                       pf->fdir_pf_filter_count =
+                                        pf->hw.func_caps.fd_filters_guaranteed;
+               }
+       } else {
+               pf->fdir_pf_filter_count = 0;
+       }
+
+       if (pf->hw.func_caps.vmdq) {
+               pf->flags |= I40E_FLAG_VMDQ_ENABLED;
+               pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
+               pf->num_vmdq_qps = I40E_DEFAULT_QUEUES_PER_VMDQ;
+       }
+
+       /* MFP mode enabled */
+       if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.mfp_mode_1) {
+               pf->flags |= I40E_FLAG_MFP_ENABLED;
+               dev_info(&pf->pdev->dev, "MFP mode Enabled\n");
+       }
+
+#ifdef CONFIG_PCI_IOV
+       if (pf->hw.func_caps.num_vfs) {
+               pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;
+               pf->flags |= I40E_FLAG_SRIOV_ENABLED;
+               pf->num_req_vfs = min_t(int,
+                                       pf->hw.func_caps.num_vfs,
+                                       I40E_MAX_VF_COUNT);
+       }
+#endif /* CONFIG_PCI_IOV */
+       pf->eeprom_version = 0xDEAD;
+       pf->lan_veb = I40E_NO_VEB;
+       pf->lan_vsi = I40E_NO_VSI;
+
+       /* set up queue assignment tracking */
+       size = sizeof(struct i40e_lump_tracking)
+               + (sizeof(u16) * pf->hw.func_caps.num_tx_qp);
+       pf->qp_pile = kzalloc(size, GFP_KERNEL);
+       if (!pf->qp_pile) {
+               err = -ENOMEM;
+               goto sw_init_done;
+       }
+       pf->qp_pile->num_entries = pf->hw.func_caps.num_tx_qp;
+       pf->qp_pile->search_hint = 0;
+
+       /* set up vector assignment tracking */
+       size = sizeof(struct i40e_lump_tracking)
+               + (sizeof(u16) * pf->hw.func_caps.num_msix_vectors);
+       pf->irq_pile = kzalloc(size, GFP_KERNEL);
+       if (!pf->irq_pile) {
+               kfree(pf->qp_pile);
+               err = -ENOMEM;
+               goto sw_init_done;
+       }
+       pf->irq_pile->num_entries = pf->hw.func_caps.num_msix_vectors;
+       pf->irq_pile->search_hint = 0;
+
+       mutex_init(&pf->switch_mutex);
+
+sw_init_done:
+       return err;
+}
+
+/**
+ * i40e_set_features - set the netdev feature flags
+ * @netdev: ptr to the netdev being adjusted
+ * @features: the feature set that the stack is suggesting
+ **/
+static int i40e_set_features(struct net_device *netdev,
+                            netdev_features_t features)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (features & NETIF_F_HW_VLAN_CTAG_RX)
+               i40e_vlan_stripping_enable(vsi);
+       else
+               i40e_vlan_stripping_disable(vsi);
+
+       return 0;
+}
+
+static const struct net_device_ops i40e_netdev_ops = {
+       .ndo_open               = i40e_open,
+       .ndo_stop               = i40e_close,
+       .ndo_start_xmit         = i40e_lan_xmit_frame,
+       .ndo_get_stats64        = i40e_get_netdev_stats_struct,
+       .ndo_set_rx_mode        = i40e_set_rx_mode,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = i40e_set_mac,
+       .ndo_change_mtu         = i40e_change_mtu,
+       .ndo_tx_timeout         = i40e_tx_timeout,
+       .ndo_vlan_rx_add_vid    = i40e_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = i40e_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = i40e_netpoll,
+#endif
+       .ndo_setup_tc           = i40e_setup_tc,
+       .ndo_set_features       = i40e_set_features,
+       .ndo_set_vf_mac         = i40e_ndo_set_vf_mac,
+       .ndo_set_vf_vlan        = i40e_ndo_set_vf_port_vlan,
+       .ndo_set_vf_tx_rate     = i40e_ndo_set_vf_bw,
+       .ndo_get_vf_config      = i40e_ndo_get_vf_config,
+};
+
+/**
+ * i40e_config_netdev - Setup the netdev flags
+ * @vsi: the VSI being configured
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+static int i40e_config_netdev(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_netdev_priv *np;
+       struct net_device *netdev;
+       u8 mac_addr[ETH_ALEN];
+       int etherdev_size;
+
+       etherdev_size = sizeof(struct i40e_netdev_priv);
+       netdev = alloc_etherdev_mq(etherdev_size, vsi->alloc_queue_pairs);
+       if (!netdev)
+               return -ENOMEM;
+
+       vsi->netdev = netdev;
+       np = netdev_priv(netdev);
+       np->vsi = vsi;
+
+       netdev->hw_enc_features = NETIF_F_IP_CSUM        |
+                                 NETIF_F_GSO_UDP_TUNNEL |
+                                 NETIF_F_TSO            |
+                                 NETIF_F_SG;
+
+       netdev->features = NETIF_F_SG                  |
+                          NETIF_F_IP_CSUM             |
+                          NETIF_F_SCTP_CSUM           |
+                          NETIF_F_HIGHDMA             |
+                          NETIF_F_GSO_UDP_TUNNEL      |
+                          NETIF_F_HW_VLAN_CTAG_TX     |
+                          NETIF_F_HW_VLAN_CTAG_RX     |
+                          NETIF_F_HW_VLAN_CTAG_FILTER |
+                          NETIF_F_IPV6_CSUM           |
+                          NETIF_F_TSO                 |
+                          NETIF_F_TSO6                |
+                          NETIF_F_RXCSUM              |
+                          NETIF_F_RXHASH              |
+                          0;
+
+       /* copy netdev features into list of user selectable features */
+       netdev->hw_features |= netdev->features;
+
+       if (vsi->type == I40E_VSI_MAIN) {
+               SET_NETDEV_DEV(netdev, &pf->pdev->dev);
+               memcpy(mac_addr, hw->mac.perm_addr, ETH_ALEN);
+       } else {
+               /* relate the VSI_VMDQ name to the VSI_MAIN name */
+               snprintf(netdev->name, IFNAMSIZ, "%sv%%d",
+                        pf->vsi[pf->lan_vsi]->netdev->name);
+               random_ether_addr(mac_addr);
+               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, false);
+       }
+
+       memcpy(netdev->dev_addr, mac_addr, ETH_ALEN);
+       memcpy(netdev->perm_addr, mac_addr, ETH_ALEN);
+       /* vlan gets same features (except vlan offload)
+        * after any tweaks for specific VSI types
+        */
+       netdev->vlan_features = netdev->features & ~(NETIF_F_HW_VLAN_CTAG_TX |
+                                                    NETIF_F_HW_VLAN_CTAG_RX |
+                                                  NETIF_F_HW_VLAN_CTAG_FILTER);
+       netdev->priv_flags |= IFF_UNICAST_FLT;
+       netdev->priv_flags |= IFF_SUPP_NOFCS;
+       /* Setup netdev TC information */
+       i40e_vsi_config_netdev_tc(vsi, vsi->tc_config.enabled_tc);
+
+       netdev->netdev_ops = &i40e_netdev_ops;
+       netdev->watchdog_timeo = 5 * HZ;
+       i40e_set_ethtool_ops(netdev);
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_delete - Delete a VSI from the switch
+ * @vsi: the VSI being removed
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+static void i40e_vsi_delete(struct i40e_vsi *vsi)
+{
+       /* remove default VSI is not allowed */
+       if (vsi == vsi->back->vsi[vsi->back->lan_vsi])
+               return;
+
+       /* there is no HW VSI for FDIR */
+       if (vsi->type == I40E_VSI_FDIR)
+               return;
+
+       i40e_aq_delete_element(&vsi->back->hw, vsi->seid, NULL);
+       return;
+}
+
+/**
+ * i40e_add_vsi - Add a VSI to the switch
+ * @vsi: the VSI being configured
+ *
+ * This initializes a VSI context depending on the VSI type to be added and
+ * passes it down to the add_vsi aq command.
+ **/
+static int i40e_add_vsi(struct i40e_vsi *vsi)
+{
+       int ret = -ENODEV;
+       struct i40e_mac_filter *f, *ftmp;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vsi_context ctxt;
+       u8 enabled_tc = 0x1; /* TC0 enabled */
+       int f_count = 0;
+
+       memset(&ctxt, 0, sizeof(ctxt));
+       switch (vsi->type) {
+       case I40E_VSI_MAIN:
+               /* The PF's main VSI is already setup as part of the
+                * device initialization, so we'll not bother with
+                * the add_vsi call, but we will retrieve the current
+                * VSI context.
+                */
+               ctxt.seid = pf->main_vsi_seid;
+               ctxt.pf_num = pf->hw.pf_id;
+               ctxt.vf_num = 0;
+               ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL);
+               ctxt.flags = I40E_AQ_VSI_TYPE_PF;
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "couldn't get pf vsi config, err %d, aq_err %d\n",
+                                ret, pf->hw.aq.asq_last_status);
+                       return -ENOENT;
+               }
+               memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
+               vsi->info.valid_sections = 0;
+
+               vsi->seid = ctxt.seid;
+               vsi->id = ctxt.vsi_number;
+
+               enabled_tc = i40e_pf_get_tc_map(pf);
+
+               /* MFP mode setup queue map and update VSI */
+               if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+                       memset(&ctxt, 0, sizeof(ctxt));
+                       ctxt.seid = pf->main_vsi_seid;
+                       ctxt.pf_num = pf->hw.pf_id;
+                       ctxt.vf_num = 0;
+                       i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, false);
+                       ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "update vsi failed, aq_err=%d\n",
+                                        pf->hw.aq.asq_last_status);
+                               ret = -ENOENT;
+                               goto err;
+                       }
+                       /* update the local VSI info queue map */
+                       i40e_vsi_update_queue_map(vsi, &ctxt);
+                       vsi->info.valid_sections = 0;
+               } else {
+                       /* Default/Main VSI is only enabled for TC0
+                        * reconfigure it to enable all TCs that are
+                        * available on the port in SFP mode.
+                        */
+                       ret = i40e_vsi_config_tc(vsi, enabled_tc);
+                       if (ret) {
+                               dev_info(&pf->pdev->dev,
+                                        "failed to configure TCs for main VSI tc_map 0x%08x, err %d, aq_err %d\n",
+                                        enabled_tc, ret,
+                                        pf->hw.aq.asq_last_status);
+                               ret = -ENOENT;
+                       }
+               }
+               break;
+
+       case I40E_VSI_FDIR:
+               /* no queue mapping or actual HW VSI needed */
+               vsi->info.valid_sections = 0;
+               vsi->seid = 0;
+               vsi->id = 0;
+               i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true);
+               return 0;
+               break;
+
+       case I40E_VSI_VMDQ2:
+               ctxt.pf_num = hw->pf_id;
+               ctxt.vf_num = 0;
+               ctxt.uplink_seid = vsi->uplink_seid;
+               ctxt.connection_type = 0x1;     /* regular data port */
+               ctxt.flags = I40E_AQ_VSI_TYPE_VMDQ2;
+
+               ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+
+               /* This VSI is connected to VEB so the switch_id
+                * should be set to zero by default.
+                */
+               ctxt.info.switch_id = 0;
+               ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_LOCAL_LB);
+               ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+
+               /* Setup the VSI tx/rx queue map for TC0 only for now */
+               i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true);
+               break;
+
+       case I40E_VSI_SRIOV:
+               ctxt.pf_num = hw->pf_id;
+               ctxt.vf_num = vsi->vf_id + hw->func_caps.vf_base_id;
+               ctxt.uplink_seid = vsi->uplink_seid;
+               ctxt.connection_type = 0x1;     /* regular data port */
+               ctxt.flags = I40E_AQ_VSI_TYPE_VF;
+
+               ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID);
+
+               /* This VSI is connected to VEB so the switch_id
+                * should be set to zero by default.
+                */
+               ctxt.info.switch_id = cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
+
+               ctxt.info.valid_sections |= cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID);
+               ctxt.info.port_vlan_flags |= I40E_AQ_VSI_PVLAN_MODE_ALL;
+               /* Setup the VSI tx/rx queue map for TC0 only for now */
+               i40e_vsi_setup_queue_map(vsi, &ctxt, enabled_tc, true);
+               break;
+
+       default:
+               return -ENODEV;
+       }
+
+       if (vsi->type != I40E_VSI_MAIN) {
+               ret = i40e_aq_add_vsi(hw, &ctxt, NULL);
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "add vsi failed, aq_err=%d\n",
+                                vsi->back->hw.aq.asq_last_status);
+                       ret = -ENOENT;
+                       goto err;
+               }
+               memcpy(&vsi->info, &ctxt.info, sizeof(ctxt.info));
+               vsi->info.valid_sections = 0;
+               vsi->seid = ctxt.seid;
+               vsi->id = ctxt.vsi_number;
+       }
+
+       /* If macvlan filters already exist, force them to get loaded */
+       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
+               f->changed = true;
+               f_count++;
+       }
+       if (f_count) {
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+               pf->flags |= I40E_FLAG_FILTER_SYNC;
+       }
+
+       /* Update VSI BW information */
+       ret = i40e_vsi_get_bw_info(vsi);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "couldn't get vsi bw info, err %d, aq_err %d\n",
+                        ret, pf->hw.aq.asq_last_status);
+               /* VSI is already added so not tearing that up */
+               ret = 0;
+       }
+
+err:
+       return ret;
+}
+
+/**
+ * i40e_vsi_release - Delete a VSI and free its resources
+ * @vsi: the VSI being removed
+ *
+ * Returns 0 on success or < 0 on error
+ **/
+int i40e_vsi_release(struct i40e_vsi *vsi)
+{
+       struct i40e_mac_filter *f, *ftmp;
+       struct i40e_veb *veb = NULL;
+       struct i40e_pf *pf;
+       u16 uplink_seid;
+       int i, n;
+
+       pf = vsi->back;
+
+       /* release of a VEB-owner or last VSI is not allowed */
+       if (vsi->flags & I40E_VSI_FLAG_VEB_OWNER) {
+               dev_info(&pf->pdev->dev, "VSI %d has existing VEB %d\n",
+                        vsi->seid, vsi->uplink_seid);
+               return -ENODEV;
+       }
+       if (vsi == pf->vsi[pf->lan_vsi] &&
+           !test_bit(__I40E_DOWN, &pf->state)) {
+               dev_info(&pf->pdev->dev, "Can't remove PF VSI\n");
+               return -ENODEV;
+       }
+
+       uplink_seid = vsi->uplink_seid;
+       if (vsi->type != I40E_VSI_SRIOV) {
+               if (vsi->netdev_registered) {
+                       vsi->netdev_registered = false;
+                       if (vsi->netdev) {
+                               /* results in a call to i40e_close() */
+                               unregister_netdev(vsi->netdev);
+                               free_netdev(vsi->netdev);
+                               vsi->netdev = NULL;
+                       }
+               } else {
+                       if (!test_and_set_bit(__I40E_DOWN, &vsi->state))
+                               i40e_down(vsi);
+                       i40e_vsi_free_irq(vsi);
+                       i40e_vsi_free_tx_resources(vsi);
+                       i40e_vsi_free_rx_resources(vsi);
+               }
+               i40e_vsi_disable_irq(vsi);
+       }
+
+       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list)
+               i40e_del_filter(vsi, f->macaddr, f->vlan,
+                               f->is_vf, f->is_netdev);
+       i40e_sync_vsi_filters(vsi);
+
+       i40e_vsi_delete(vsi);
+       i40e_vsi_free_q_vectors(vsi);
+       i40e_vsi_clear_rings(vsi);
+       i40e_vsi_clear(vsi);
+
+       /* If this was the last thing on the VEB, except for the
+        * controlling VSI, remove the VEB, which puts the controlling
+        * VSI onto the next level down in the switch.
+        *
+        * Well, okay, there's one more exception here: don't remove
+        * the orphan VEBs yet.  We'll wait for an explicit remove request
+        * from up the network stack.
+        */
+       for (n = 0, i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+               if (pf->vsi[i] &&
+                   pf->vsi[i]->uplink_seid == uplink_seid &&
+                   (pf->vsi[i]->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) {
+                       n++;      /* count the VSIs */
+               }
+       }
+       for (i = 0; i < I40E_MAX_VEB; i++) {
+               if (!pf->veb[i])
+                       continue;
+               if (pf->veb[i]->uplink_seid == uplink_seid)
+                       n++;     /* count the VEBs */
+               if (pf->veb[i]->seid == uplink_seid)
+                       veb = pf->veb[i];
+       }
+       if (n == 0 && veb && veb->uplink_seid != 0)
+               i40e_veb_release(veb);
+
+       return 0;
+}
+
+/**
+ * i40e_vsi_setup_vectors - Set up the q_vectors for the given VSI
+ * @vsi: ptr to the VSI
+ *
+ * This should only be called after i40e_vsi_mem_alloc() which allocates the
+ * corresponding SW VSI structure and initializes num_queue_pairs for the
+ * newly allocated VSI.
+ *
+ * Returns 0 on success or negative on failure
+ **/
+static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi)
+{
+       int ret = -ENOENT;
+       struct i40e_pf *pf = vsi->back;
+
+       if (vsi->q_vectors) {
+               dev_info(&pf->pdev->dev, "VSI %d has existing q_vectors\n",
+                        vsi->seid);
+               return -EEXIST;
+       }
+
+       if (vsi->base_vector) {
+               dev_info(&pf->pdev->dev,
+                        "VSI %d has non-zero base vector %d\n",
+                        vsi->seid, vsi->base_vector);
+               return -EEXIST;
+       }
+
+       ret = i40e_alloc_q_vectors(vsi);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "failed to allocate %d q_vector for VSI %d, ret=%d\n",
+                        vsi->num_q_vectors, vsi->seid, ret);
+               vsi->num_q_vectors = 0;
+               goto vector_setup_out;
+       }
+
+       vsi->base_vector = i40e_get_lump(pf, pf->irq_pile,
+                                        vsi->num_q_vectors, vsi->idx);
+       if (vsi->base_vector < 0) {
+               dev_info(&pf->pdev->dev,
+                        "failed to get q tracking for VSI %d, err=%d\n",
+                        vsi->seid, vsi->base_vector);
+               i40e_vsi_free_q_vectors(vsi);
+               ret = -ENOENT;
+               goto vector_setup_out;
+       }
+
+vector_setup_out:
+       return ret;
+}
+
+/**
+ * i40e_vsi_setup - Set up a VSI by a given type
+ * @pf: board private structure
+ * @type: VSI type
+ * @uplink_seid: the switch element to link to
+ * @param1: usage depends upon VSI type. For VF types, indicates VF id
+ *
+ * This allocates the sw VSI structure and its queue resources, then add a VSI
+ * to the identified VEB.
+ *
+ * Returns pointer to the successfully allocated and configure VSI sw struct on
+ * success, otherwise returns NULL on failure.
+ **/
+struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
+                               u16 uplink_seid, u32 param1)
+{
+       struct i40e_vsi *vsi = NULL;
+       struct i40e_veb *veb = NULL;
+       int ret, i;
+       int v_idx;
+
+       /* The requested uplink_seid must be either
+        *     - the PF's port seid
+        *              no VEB is needed because this is the PF
+        *              or this is a Flow Director special case VSI
+        *     - seid of an existing VEB
+        *     - seid of a VSI that owns an existing VEB
+        *     - seid of a VSI that doesn't own a VEB
+        *              a new VEB is created and the VSI becomes the owner
+        *     - seid of the PF VSI, which is what creates the first VEB
+        *              this is a special case of the previous
+        *
+        * Find which uplink_seid we were given and create a new VEB if needed
+        */
+       for (i = 0; i < I40E_MAX_VEB; i++) {
+               if (pf->veb[i] && pf->veb[i]->seid == uplink_seid) {
+                       veb = pf->veb[i];
+                       break;
+               }
+       }
+
+       if (!veb && uplink_seid != pf->mac_seid) {
+
+               for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+                       if (pf->vsi[i] && pf->vsi[i]->seid == uplink_seid) {
+                               vsi = pf->vsi[i];
+                               break;
+                       }
+               }
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev, "no such uplink_seid %d\n",
+                                uplink_seid);
+                       return NULL;
+               }
+
+               if (vsi->uplink_seid == pf->mac_seid)
+                       veb = i40e_veb_setup(pf, 0, pf->mac_seid, vsi->seid,
+                                            vsi->tc_config.enabled_tc);
+               else if ((vsi->flags & I40E_VSI_FLAG_VEB_OWNER) == 0)
+                       veb = i40e_veb_setup(pf, 0, vsi->uplink_seid, vsi->seid,
+                                            vsi->tc_config.enabled_tc);
+
+               for (i = 0; i < I40E_MAX_VEB && !veb; i++) {
+                       if (pf->veb[i] && pf->veb[i]->seid == vsi->uplink_seid)
+                               veb = pf->veb[i];
+               }
+               if (!veb) {
+                       dev_info(&pf->pdev->dev, "couldn't add VEB\n");
+                       return NULL;
+               }
+
+               vsi->flags |= I40E_VSI_FLAG_VEB_OWNER;
+               uplink_seid = veb->seid;
+       }
+
+       /* get vsi sw struct */
+       v_idx = i40e_vsi_mem_alloc(pf, type);
+       if (v_idx < 0)
+               goto err_alloc;
+       vsi = pf->vsi[v_idx];
+       vsi->type = type;
+       vsi->veb_idx = (veb ? veb->idx : I40E_NO_VEB);
+
+       if (type == I40E_VSI_MAIN)
+               pf->lan_vsi = v_idx;
+       else if (type == I40E_VSI_SRIOV)
+               vsi->vf_id = param1;
+       /* assign it some queues */
+       ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx);
+       if (ret < 0) {
+               dev_info(&pf->pdev->dev, "VSI %d get_lump failed %d\n",
+                        vsi->seid, ret);
+               goto err_vsi;
+       }
+       vsi->base_queue = ret;
+
+       /* get a VSI from the hardware */
+       vsi->uplink_seid = uplink_seid;
+       ret = i40e_add_vsi(vsi);
+       if (ret)
+               goto err_vsi;
+
+       switch (vsi->type) {
+       /* setup the netdev if needed */
+       case I40E_VSI_MAIN:
+       case I40E_VSI_VMDQ2:
+               ret = i40e_config_netdev(vsi);
+               if (ret)
+                       goto err_netdev;
+               ret = register_netdev(vsi->netdev);
+               if (ret)
+                       goto err_netdev;
+               vsi->netdev_registered = true;
+               netif_carrier_off(vsi->netdev);
+               /* fall through */
+
+       case I40E_VSI_FDIR:
+               /* set up vectors and rings if needed */
+               ret = i40e_vsi_setup_vectors(vsi);
+               if (ret)
+                       goto err_msix;
+
+               ret = i40e_alloc_rings(vsi);
+               if (ret)
+                       goto err_rings;
+
+               /* map all of the rings to the q_vectors */
+               i40e_vsi_map_rings_to_vectors(vsi);
+
+               i40e_vsi_reset_stats(vsi);
+               break;
+
+       default:
+               /* no netdev or rings for the other VSI types */
+               break;
+       }
+
+       return vsi;
+
+err_rings:
+       i40e_vsi_free_q_vectors(vsi);
+err_msix:
+       if (vsi->netdev_registered) {
+               vsi->netdev_registered = false;
+               unregister_netdev(vsi->netdev);
+               free_netdev(vsi->netdev);
+               vsi->netdev = NULL;
+       }
+err_netdev:
+       i40e_aq_delete_element(&pf->hw, vsi->seid, NULL);
+err_vsi:
+       i40e_vsi_clear(vsi);
+err_alloc:
+       return NULL;
+}
+
+/**
+ * i40e_veb_get_bw_info - Query VEB BW information
+ * @veb: the veb to query
+ *
+ * Query the Tx scheduler BW configuration data for given VEB
+ **/
+static int i40e_veb_get_bw_info(struct i40e_veb *veb)
+{
+       struct i40e_aqc_query_switching_comp_ets_config_resp ets_data;
+       struct i40e_aqc_query_switching_comp_bw_config_resp bw_data;
+       struct i40e_pf *pf = veb->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 tc_bw_max;
+       int ret = 0;
+       int i;
+
+       ret = i40e_aq_query_switch_comp_bw_config(hw, veb->seid,
+                                                 &bw_data, NULL);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "query veb bw config failed, aq_err=%d\n",
+                        hw->aq.asq_last_status);
+               goto out;
+       }
+
+       ret = i40e_aq_query_switch_comp_ets_config(hw, veb->seid,
+                                                  &ets_data, NULL);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "query veb bw ets config failed, aq_err=%d\n",
+                        hw->aq.asq_last_status);
+               goto out;
+       }
+
+       veb->bw_limit = le16_to_cpu(ets_data.port_bw_limit);
+       veb->bw_max_quanta = ets_data.tc_bw_max;
+       veb->is_abs_credits = bw_data.absolute_credits_enable;
+       tc_bw_max = le16_to_cpu(bw_data.tc_bw_max[0]) |
+                   (le16_to_cpu(bw_data.tc_bw_max[1]) << 16);
+       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+               veb->bw_tc_share_credits[i] = bw_data.tc_bw_share_credits[i];
+               veb->bw_tc_limit_credits[i] =
+                                       le16_to_cpu(bw_data.tc_bw_limits[i]);
+               veb->bw_tc_max_quanta[i] = ((tc_bw_max >> (i*4)) & 0x7);
+       }
+
+out:
+       return ret;
+}
+
+/**
+ * i40e_veb_mem_alloc - Allocates the next available struct veb in the PF
+ * @pf: board private structure
+ *
+ * On error: returns error code (negative)
+ * On success: returns vsi index in PF (positive)
+ **/
+static int i40e_veb_mem_alloc(struct i40e_pf *pf)
+{
+       int ret = -ENOENT;
+       struct i40e_veb *veb;
+       int i;
+
+       /* Need to protect the allocation of switch elements at the PF level */
+       mutex_lock(&pf->switch_mutex);
+
+       /* VEB list may be fragmented if VEB creation/destruction has
+        * been happening.  We can afford to do a quick scan to look
+        * for any free slots in the list.
+        *
+        * find next empty veb slot, looping back around if necessary
+        */
+       i = 0;
+       while ((i < I40E_MAX_VEB) && (pf->veb[i] != NULL))
+               i++;
+       if (i >= I40E_MAX_VEB) {
+               ret = -ENOMEM;
+               goto err_alloc_veb;  /* out of VEB slots! */
+       }
+
+       veb = kzalloc(sizeof(*veb), GFP_KERNEL);
+       if (!veb) {
+               ret = -ENOMEM;
+               goto err_alloc_veb;
+       }
+       veb->pf = pf;
+       veb->idx = i;
+       veb->enabled_tc = 1;
+
+       pf->veb[i] = veb;
+       ret = i;
+err_alloc_veb:
+       mutex_unlock(&pf->switch_mutex);
+       return ret;
+}
+
+/**
+ * i40e_switch_branch_release - Delete a branch of the switch tree
+ * @branch: where to start deleting
+ *
+ * This uses recursion to find the tips of the branch to be
+ * removed, deleting until we get back to and can delete this VEB.
+ **/
+static void i40e_switch_branch_release(struct i40e_veb *branch)
+{
+       struct i40e_pf *pf = branch->pf;
+       u16 branch_seid = branch->seid;
+       u16 veb_idx = branch->idx;
+       int i;
+
+       /* release any VEBs on this VEB - RECURSION */
+       for (i = 0; i < I40E_MAX_VEB; i++) {
+               if (!pf->veb[i])
+                       continue;
+               if (pf->veb[i]->uplink_seid == branch->seid)
+                       i40e_switch_branch_release(pf->veb[i]);
+       }
+
+       /* Release the VSIs on this VEB, but not the owner VSI.
+        *
+        * NOTE: Removing the last VSI on a VEB has the SIDE EFFECT of removing
+        *       the VEB itself, so don't use (*branch) after this loop.
+        */
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+               if (!pf->vsi[i])
+                       continue;
+               if (pf->vsi[i]->uplink_seid == branch_seid &&
+                  (pf->vsi[i]->flags & I40E_VSI_FLAG_VEB_OWNER) == 0) {
+                       i40e_vsi_release(pf->vsi[i]);
+               }
+       }
+
+       /* There's one corner case where the VEB might not have been
+        * removed, so double check it here and remove it if needed.
+        * This case happens if the veb was created from the debugfs
+        * commands and no VSIs were added to it.
+        */
+       if (pf->veb[veb_idx])
+               i40e_veb_release(pf->veb[veb_idx]);
+}
+
+/**
+ * i40e_veb_clear - remove veb struct
+ * @veb: the veb to remove
+ **/
+static void i40e_veb_clear(struct i40e_veb *veb)
+{
+       if (!veb)
+               return;
+
+       if (veb->pf) {
+               struct i40e_pf *pf = veb->pf;
+
+               mutex_lock(&pf->switch_mutex);
+               if (pf->veb[veb->idx] == veb)
+                       pf->veb[veb->idx] = NULL;
+               mutex_unlock(&pf->switch_mutex);
+       }
+
+       kfree(veb);
+}
+
+/**
+ * i40e_veb_release - Delete a VEB and free its resources
+ * @veb: the VEB being removed
+ **/
+void i40e_veb_release(struct i40e_veb *veb)
+{
+       struct i40e_vsi *vsi = NULL;
+       struct i40e_pf *pf;
+       int i, n = 0;
+
+       pf = veb->pf;
+
+       /* find the remaining VSI and check for extras */
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+               if (pf->vsi[i] && pf->vsi[i]->uplink_seid == veb->seid) {
+                       n++;
+                       vsi = pf->vsi[i];
+               }
+       }
+       if (n != 1) {
+               dev_info(&pf->pdev->dev,
+                        "can't remove VEB %d with %d VSIs left\n",
+                        veb->seid, n);
+               return;
+       }
+
+       /* move the remaining VSI to uplink veb */
+       vsi->flags &= ~I40E_VSI_FLAG_VEB_OWNER;
+       if (veb->uplink_seid) {
+               vsi->uplink_seid = veb->uplink_seid;
+               if (veb->uplink_seid == pf->mac_seid)
+                       vsi->veb_idx = I40E_NO_VEB;
+               else
+                       vsi->veb_idx = veb->veb_idx;
+       } else {
+               /* floating VEB */
+               vsi->uplink_seid = pf->vsi[pf->lan_vsi]->uplink_seid;
+               vsi->veb_idx = pf->vsi[pf->lan_vsi]->veb_idx;
+       }
+
+       i40e_aq_delete_element(&pf->hw, veb->seid, NULL);
+       i40e_veb_clear(veb);
+
+       return;
+}
+
+/**
+ * i40e_add_veb - create the VEB in the switch
+ * @veb: the VEB to be instantiated
+ * @vsi: the controlling VSI
+ **/
+static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi)
+{
+       bool is_default = (vsi->idx == vsi->back->lan_vsi);
+       int ret;
+
+       /* get a VEB from the hardware */
+       ret = i40e_aq_add_veb(&veb->pf->hw, veb->uplink_seid, vsi->seid,
+                             veb->enabled_tc, is_default, &veb->seid, NULL);
+       if (ret) {
+               dev_info(&veb->pf->pdev->dev,
+                        "couldn't add VEB, err %d, aq_err %d\n",
+                        ret, veb->pf->hw.aq.asq_last_status);
+               return -EPERM;
+       }
+
+       /* get statistics counter */
+       ret = i40e_aq_get_veb_parameters(&veb->pf->hw, veb->seid, NULL, NULL,
+                                        &veb->stats_idx, NULL, NULL, NULL);
+       if (ret) {
+               dev_info(&veb->pf->pdev->dev,
+                        "couldn't get VEB statistics idx, err %d, aq_err %d\n",
+                        ret, veb->pf->hw.aq.asq_last_status);
+               return -EPERM;
+       }
+       ret = i40e_veb_get_bw_info(veb);
+       if (ret) {
+               dev_info(&veb->pf->pdev->dev,
+                        "couldn't get VEB bw info, err %d, aq_err %d\n",
+                        ret, veb->pf->hw.aq.asq_last_status);
+               i40e_aq_delete_element(&veb->pf->hw, veb->seid, NULL);
+               return -ENOENT;
+       }
+
+       vsi->uplink_seid = veb->seid;
+       vsi->veb_idx = veb->idx;
+       vsi->flags |= I40E_VSI_FLAG_VEB_OWNER;
+
+       return 0;
+}
+
+/**
+ * i40e_veb_setup - Set up a VEB
+ * @pf: board private structure
+ * @flags: VEB setup flags
+ * @uplink_seid: the switch element to link to
+ * @vsi_seid: the initial VSI seid
+ * @enabled_tc: Enabled TC bit-map
+ *
+ * This allocates the sw VEB structure and links it into the switch
+ * It is possible and legal for this to be a duplicate of an already
+ * existing VEB.  It is also possible for both uplink and vsi seids
+ * to be zero, in order to create a floating VEB.
+ *
+ * Returns pointer to the successfully allocated VEB sw struct on
+ * success, otherwise returns NULL on failure.
+ **/
+struct i40e_veb *i40e_veb_setup(struct i40e_pf *pf, u16 flags,
+                               u16 uplink_seid, u16 vsi_seid,
+                               u8 enabled_tc)
+{
+       struct i40e_veb *veb, *uplink_veb = NULL;
+       int vsi_idx, veb_idx;
+       int ret;
+
+       /* if one seid is 0, the other must be 0 to create a floating relay */
+       if ((uplink_seid == 0 || vsi_seid == 0) &&
+           (uplink_seid + vsi_seid != 0)) {
+               dev_info(&pf->pdev->dev,
+                        "one, not both seid's are 0: uplink=%d vsi=%d\n",
+                        uplink_seid, vsi_seid);
+               return NULL;
+       }
+
+       /* make sure there is such a vsi and uplink */
+       for (vsi_idx = 0; vsi_idx < pf->hw.func_caps.num_vsis; vsi_idx++)
+               if (pf->vsi[vsi_idx] && pf->vsi[vsi_idx]->seid == vsi_seid)
+                       break;
+       if (vsi_idx >= pf->hw.func_caps.num_vsis && vsi_seid != 0) {
+               dev_info(&pf->pdev->dev, "vsi seid %d not found\n",
+                        vsi_seid);
+               return NULL;
+       }
+
+       if (uplink_seid && uplink_seid != pf->mac_seid) {
+               for (veb_idx = 0; veb_idx < I40E_MAX_VEB; veb_idx++) {
+                       if (pf->veb[veb_idx] &&
+                           pf->veb[veb_idx]->seid == uplink_seid) {
+                               uplink_veb = pf->veb[veb_idx];
+                               break;
+                       }
+               }
+               if (!uplink_veb) {
+                       dev_info(&pf->pdev->dev,
+                                "uplink seid %d not found\n", uplink_seid);
+                       return NULL;
+               }
+       }
+
+       /* get veb sw struct */
+       veb_idx = i40e_veb_mem_alloc(pf);
+       if (veb_idx < 0)
+               goto err_alloc;
+       veb = pf->veb[veb_idx];
+       veb->flags = flags;
+       veb->uplink_seid = uplink_seid;
+       veb->veb_idx = (uplink_veb ? uplink_veb->idx : I40E_NO_VEB);
+       veb->enabled_tc = (enabled_tc ? enabled_tc : 0x1);
+
+       /* create the VEB in the switch */
+       ret = i40e_add_veb(veb, pf->vsi[vsi_idx]);
+       if (ret)
+               goto err_veb;
+
+       return veb;
+
+err_veb:
+       i40e_veb_clear(veb);
+err_alloc:
+       return NULL;
+}
+
+/**
+ * i40e_setup_pf_switch_element - set pf vars based on switch type
+ * @pf: board private structure
+ * @ele: element we are building info from
+ * @num_reported: total number of elements
+ * @printconfig: should we print the contents
+ *
+ * helper function to assist in extracting a few useful SEID values.
+ **/
+static void i40e_setup_pf_switch_element(struct i40e_pf *pf,
+                               struct i40e_aqc_switch_config_element_resp *ele,
+                               u16 num_reported, bool printconfig)
+{
+       u16 downlink_seid = le16_to_cpu(ele->downlink_seid);
+       u16 uplink_seid = le16_to_cpu(ele->uplink_seid);
+       u8 element_type = ele->element_type;
+       u16 seid = le16_to_cpu(ele->seid);
+
+       if (printconfig)
+               dev_info(&pf->pdev->dev,
+                        "type=%d seid=%d uplink=%d downlink=%d\n",
+                        element_type, seid, uplink_seid, downlink_seid);
+
+       switch (element_type) {
+       case I40E_SWITCH_ELEMENT_TYPE_MAC:
+               pf->mac_seid = seid;
+               break;
+       case I40E_SWITCH_ELEMENT_TYPE_VEB:
+               /* Main VEB? */
+               if (uplink_seid != pf->mac_seid)
+                       break;
+               if (pf->lan_veb == I40E_NO_VEB) {
+                       int v;
+
+                       /* find existing or else empty VEB */
+                       for (v = 0; v < I40E_MAX_VEB; v++) {
+                               if (pf->veb[v] && (pf->veb[v]->seid == seid)) {
+                                       pf->lan_veb = v;
+                                       break;
+                               }
+                       }
+                       if (pf->lan_veb == I40E_NO_VEB) {
+                               v = i40e_veb_mem_alloc(pf);
+                               if (v < 0)
+                                       break;
+                               pf->lan_veb = v;
+                       }
+               }
+
+               pf->veb[pf->lan_veb]->seid = seid;
+               pf->veb[pf->lan_veb]->uplink_seid = pf->mac_seid;
+               pf->veb[pf->lan_veb]->pf = pf;
+               pf->veb[pf->lan_veb]->veb_idx = I40E_NO_VEB;
+               break;
+       case I40E_SWITCH_ELEMENT_TYPE_VSI:
+               if (num_reported != 1)
+                       break;
+               /* This is immediately after a reset so we can assume this is
+                * the PF's VSI
+                */
+               pf->mac_seid = uplink_seid;
+               pf->pf_seid = downlink_seid;
+               pf->main_vsi_seid = seid;
+               if (printconfig)
+                       dev_info(&pf->pdev->dev,
+                                "pf_seid=%d main_vsi_seid=%d\n",
+                                pf->pf_seid, pf->main_vsi_seid);
+               break;
+       case I40E_SWITCH_ELEMENT_TYPE_PF:
+       case I40E_SWITCH_ELEMENT_TYPE_VF:
+       case I40E_SWITCH_ELEMENT_TYPE_EMP:
+       case I40E_SWITCH_ELEMENT_TYPE_BMC:
+       case I40E_SWITCH_ELEMENT_TYPE_PE:
+       case I40E_SWITCH_ELEMENT_TYPE_PA:
+               /* ignore these for now */
+               break;
+       default:
+               dev_info(&pf->pdev->dev, "unknown element type=%d seid=%d\n",
+                        element_type, seid);
+               break;
+       }
+}
+
+/**
+ * i40e_fetch_switch_configuration - Get switch config from firmware
+ * @pf: board private structure
+ * @printconfig: should we print the contents
+ *
+ * Get the current switch configuration from the device and
+ * extract a few useful SEID values.
+ **/
+int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig)
+{
+       struct i40e_aqc_get_switch_config_resp *sw_config;
+       u16 next_seid = 0;
+       int ret = 0;
+       u8 *aq_buf;
+       int i;
+
+       aq_buf = kzalloc(I40E_AQ_LARGE_BUF, GFP_KERNEL);
+       if (!aq_buf)
+               return -ENOMEM;
+
+       sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
+       do {
+               u16 num_reported, num_total;
+
+               ret = i40e_aq_get_switch_config(&pf->hw, sw_config,
+                                               I40E_AQ_LARGE_BUF,
+                                               &next_seid, NULL);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "get switch config failed %d aq_err=%x\n",
+                                ret, pf->hw.aq.asq_last_status);
+                       kfree(aq_buf);
+                       return -ENOENT;
+               }
+
+               num_reported = le16_to_cpu(sw_config->header.num_reported);
+               num_total = le16_to_cpu(sw_config->header.num_total);
+
+               if (printconfig)
+                       dev_info(&pf->pdev->dev,
+                                "header: %d reported %d total\n",
+                                num_reported, num_total);
+
+               if (num_reported) {
+                       int sz = sizeof(*sw_config) * num_reported;
+
+                       kfree(pf->sw_config);
+                       pf->sw_config = kzalloc(sz, GFP_KERNEL);
+                       if (pf->sw_config)
+                               memcpy(pf->sw_config, sw_config, sz);
+               }
+
+               for (i = 0; i < num_reported; i++) {
+                       struct i40e_aqc_switch_config_element_resp *ele =
+                               &sw_config->element[i];
+
+                       i40e_setup_pf_switch_element(pf, ele, num_reported,
+                                                    printconfig);
+               }
+       } while (next_seid != 0);
+
+       kfree(aq_buf);
+       return ret;
+}
+
+/**
+ * i40e_setup_pf_switch - Setup the HW switch on startup or after reset
+ * @pf: board private structure
+ *
+ * Returns 0 on success, negative value on failure
+ **/
+static int i40e_setup_pf_switch(struct i40e_pf *pf)
+{
+       int ret;
+
+       /* find out what's out there already */
+       ret = i40e_fetch_switch_configuration(pf, false);
+       if (ret) {
+               dev_info(&pf->pdev->dev,
+                        "couldn't fetch switch config, err %d, aq_err %d\n",
+                        ret, pf->hw.aq.asq_last_status);
+               return ret;
+       }
+       i40e_pf_reset_stats(pf);
+
+       /* fdir VSI must happen first to be sure it gets queue 0, but only
+        * if there is enough room for the fdir VSI
+        */
+       if (pf->num_lan_qps > 1)
+               i40e_fdir_setup(pf);
+
+       /* first time setup */
+       if (pf->lan_vsi == I40E_NO_VSI) {
+               struct i40e_vsi *vsi = NULL;
+               u16 uplink_seid;
+
+               /* Set up the PF VSI associated with the PF's main VSI
+                * that is already in the HW switch
+                */
+               if (pf->lan_veb != I40E_NO_VEB && pf->veb[pf->lan_veb])
+                       uplink_seid = pf->veb[pf->lan_veb]->seid;
+               else
+                       uplink_seid = pf->mac_seid;
+
+               vsi = i40e_vsi_setup(pf, I40E_VSI_MAIN, uplink_seid, 0);
+               if (!vsi) {
+                       dev_info(&pf->pdev->dev, "setup of MAIN VSI failed\n");
+                       i40e_fdir_teardown(pf);
+                       return -EAGAIN;
+               }
+               /* accommodate kcompat by copying the main VSI queue count
+                * into the pf, since this newer code pushes the pf queue
+                * info down a level into a VSI
+                */
+               pf->num_rx_queues = vsi->alloc_queue_pairs;
+               pf->num_tx_queues = vsi->alloc_queue_pairs;
+       } else {
+               /* force a reset of TC and queue layout configurations */
+               u8 enabled_tc = pf->vsi[pf->lan_vsi]->tc_config.enabled_tc;
+               pf->vsi[pf->lan_vsi]->tc_config.enabled_tc = 0;
+               pf->vsi[pf->lan_vsi]->seid = pf->main_vsi_seid;
+               i40e_vsi_config_tc(pf->vsi[pf->lan_vsi], enabled_tc);
+       }
+       i40e_vlan_stripping_disable(pf->vsi[pf->lan_vsi]);
+
+       /* Setup static PF queue filter control settings */
+       ret = i40e_setup_pf_filter_control(pf);
+       if (ret) {
+               dev_info(&pf->pdev->dev, "setup_pf_filter_control failed: %d\n",
+                        ret);
+               /* Failure here should not stop continuing other steps */
+       }
+
+       /* enable RSS in the HW, even for only one queue, as the stack can use
+        * the hash
+        */
+       if ((pf->flags & I40E_FLAG_RSS_ENABLED))
+               i40e_config_rss(pf);
+
+       /* fill in link information and enable LSE reporting */
+       i40e_aq_get_link_info(&pf->hw, true, NULL, NULL);
+       i40e_link_event(pf);
+
+       /* Initialize user-specifics link properties */
+       pf->fc_autoneg_status = ((pf->hw.phy.link_info.an_info &
+                                 I40E_AQ_AN_COMPLETED) ? true : false);
+       pf->hw.fc.requested_mode = I40E_FC_DEFAULT;
+       if (pf->hw.phy.link_info.an_info &
+          (I40E_AQ_LINK_PAUSE_TX | I40E_AQ_LINK_PAUSE_RX))
+               pf->hw.fc.current_mode = I40E_FC_FULL;
+       else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_TX)
+               pf->hw.fc.current_mode = I40E_FC_TX_PAUSE;
+       else if (pf->hw.phy.link_info.an_info & I40E_AQ_LINK_PAUSE_RX)
+               pf->hw.fc.current_mode = I40E_FC_RX_PAUSE;
+       else
+               pf->hw.fc.current_mode = I40E_FC_DEFAULT;
+
+       return ret;
+}
+
+/**
+ * i40e_set_rss_size - helper to set rss_size
+ * @pf: board private structure
+ * @queues_left: how many queues
+ */
+static u16 i40e_set_rss_size(struct i40e_pf *pf, int queues_left)
+{
+       int num_tc0;
+
+       num_tc0 = min_t(int, queues_left, pf->rss_size_max);
+       num_tc0 = min_t(int, num_tc0, nr_cpus_node(numa_node_id()));
+       num_tc0 = rounddown_pow_of_two(num_tc0);
+
+       return num_tc0;
+}
+
+/**
+ * i40e_determine_queue_usage - Work out queue distribution
+ * @pf: board private structure
+ **/
+static void i40e_determine_queue_usage(struct i40e_pf *pf)
+{
+       int accum_tc_size;
+       int queues_left;
+
+       pf->num_lan_qps = 0;
+       pf->num_tc_qps = rounddown_pow_of_two(pf->num_tc_qps);
+       accum_tc_size = (I40E_MAX_TRAFFIC_CLASS - 1) * pf->num_tc_qps;
+
+       /* Find the max queues to be put into basic use.  We'll always be
+        * using TC0, whether or not DCB is running, and TC0 will get the
+        * big RSS set.
+        */
+       queues_left = pf->hw.func_caps.num_tx_qp;
+
+       if   (!((pf->flags & I40E_FLAG_MSIX_ENABLED)             &&
+               (pf->flags & I40E_FLAG_MQ_ENABLED))              ||
+               !(pf->flags & (I40E_FLAG_RSS_ENABLED |
+               I40E_FLAG_FDIR_ENABLED | I40E_FLAG_DCB_ENABLED)) ||
+               (queues_left == 1)) {
+
+               /* one qp for PF, no queues for anything else */
+               queues_left = 0;
+               pf->rss_size = pf->num_lan_qps = 1;
+
+               /* make sure all the fancies are disabled */
+               pf->flags &= ~(I40E_FLAG_RSS_ENABLED       |
+                               I40E_FLAG_MQ_ENABLED       |
+                               I40E_FLAG_FDIR_ENABLED     |
+                               I40E_FLAG_FDIR_ATR_ENABLED |
+                               I40E_FLAG_DCB_ENABLED      |
+                               I40E_FLAG_SRIOV_ENABLED    |
+                               I40E_FLAG_VMDQ_ENABLED);
+
+       } else if (pf->flags & I40E_FLAG_RSS_ENABLED      &&
+                  !(pf->flags & I40E_FLAG_FDIR_ENABLED)  &&
+                  !(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+
+               pf->rss_size = i40e_set_rss_size(pf, queues_left);
+
+               queues_left -= pf->rss_size;
+               pf->num_lan_qps = pf->rss_size;
+
+       } else if (pf->flags & I40E_FLAG_RSS_ENABLED      &&
+                  !(pf->flags & I40E_FLAG_FDIR_ENABLED)  &&
+                  (pf->flags & I40E_FLAG_DCB_ENABLED)) {
+
+               /* save num_tc_qps queues for TCs 1 thru 7 and the rest
+                * are set up for RSS in TC0
+                */
+               queues_left -= accum_tc_size;
+
+               pf->rss_size = i40e_set_rss_size(pf, queues_left);
+
+               queues_left -= pf->rss_size;
+               if (queues_left < 0) {
+                       dev_info(&pf->pdev->dev, "not enough queues for DCB\n");
+                       return;
+               }
+
+               pf->num_lan_qps = pf->rss_size + accum_tc_size;
+
+       } else if (pf->flags & I40E_FLAG_RSS_ENABLED   &&
+                 (pf->flags & I40E_FLAG_FDIR_ENABLED) &&
+                 !(pf->flags & I40E_FLAG_DCB_ENABLED)) {
+
+               queues_left -= 1; /* save 1 queue for FD */
+
+               pf->rss_size = i40e_set_rss_size(pf, queues_left);
+
+               queues_left -= pf->rss_size;
+               if (queues_left < 0) {
+                       dev_info(&pf->pdev->dev, "not enough queues for Flow Director\n");
+                       return;
+               }
+
+               pf->num_lan_qps = pf->rss_size;
+
+       } else if (pf->flags & I40E_FLAG_RSS_ENABLED   &&
+                 (pf->flags & I40E_FLAG_FDIR_ENABLED) &&
+                 (pf->flags & I40E_FLAG_DCB_ENABLED)) {
+
+               /* save 1 queue for TCs 1 thru 7,
+                * 1 queue for flow director,
+                * and the rest are set up for RSS in TC0
+                */
+               queues_left -= 1;
+               queues_left -= accum_tc_size;
+
+               pf->rss_size = i40e_set_rss_size(pf, queues_left);
+               queues_left -= pf->rss_size;
+               if (queues_left < 0) {
+                       dev_info(&pf->pdev->dev, "not enough queues for DCB and Flow Director\n");
+                       return;
+               }
+
+               pf->num_lan_qps = pf->rss_size + accum_tc_size;
+
+       } else {
+               dev_info(&pf->pdev->dev,
+                        "Invalid configuration, flags=0x%08llx\n", pf->flags);
+               return;
+       }
+
+       if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
+           pf->num_vf_qps && pf->num_req_vfs && queues_left) {
+               pf->num_req_vfs = min_t(int, pf->num_req_vfs, (queues_left /
+                                                              pf->num_vf_qps));
+               queues_left -= (pf->num_req_vfs * pf->num_vf_qps);
+       }
+
+       if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
+           pf->num_vmdq_vsis && pf->num_vmdq_qps && queues_left) {
+               pf->num_vmdq_vsis = min_t(int, pf->num_vmdq_vsis,
+                                         (queues_left / pf->num_vmdq_qps));
+               queues_left -= (pf->num_vmdq_vsis * pf->num_vmdq_qps);
+       }
+
+       return;
+}
+
+/**
+ * i40e_setup_pf_filter_control - Setup PF static filter control
+ * @pf: PF to be setup
+ *
+ * i40e_setup_pf_filter_control sets up a pf's initial filter control
+ * settings. If PE/FCoE are enabled then it will also set the per PF
+ * based filter sizes required for them. It also enables Flow director,
+ * ethertype and macvlan type filter settings for the pf.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_setup_pf_filter_control(struct i40e_pf *pf)
+{
+       struct i40e_filter_control_settings *settings = &pf->filter_settings;
+
+       settings->hash_lut_size = I40E_HASH_LUT_SIZE_128;
+
+       /* Flow Director is enabled */
+       if (pf->flags & (I40E_FLAG_FDIR_ENABLED | I40E_FLAG_FDIR_ATR_ENABLED))
+               settings->enable_fdir = true;
+
+       /* Ethtype and MACVLAN filters enabled for PF */
+       settings->enable_ethtype = true;
+       settings->enable_macvlan = true;
+
+       if (i40e_set_filter_control(&pf->hw, settings))
+               return -ENOENT;
+
+       return 0;
+}
+
+/**
+ * i40e_probe - Device initialization routine
+ * @pdev: PCI device information struct
+ * @ent: entry in i40e_pci_tbl
+ *
+ * i40e_probe initializes a pf identified by a pci_dev structure.
+ * The OS initialization, configuring of the pf private structure,
+ * and a hardware reset occur.
+ *
+ * Returns 0 on success, negative on failure
+ **/
+static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct i40e_driver_version dv;
+       struct i40e_pf *pf;
+       struct i40e_hw *hw;
+       int err = 0;
+       u32 len;
+
+       err = pci_enable_device_mem(pdev);
+       if (err)
+               return err;
+
+       /* set up for high or low dma */
+       if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) {
+               /* coherent mask for the same size will always succeed if
+                * dma_set_mask does
+                */
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64));
+       } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) {
+               dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+       } else {
+               dev_err(&pdev->dev, "DMA configuration failed: %d\n", err);
+               err = -EIO;
+               goto err_dma;
+       }
+
+       /* set up pci connections */
+       err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
+                                          IORESOURCE_MEM), i40e_driver_name);
+       if (err) {
+               dev_info(&pdev->dev,
+                        "pci_request_selected_regions failed %d\n", err);
+               goto err_pci_reg;
+       }
+
+       pci_enable_pcie_error_reporting(pdev);
+       pci_set_master(pdev);
+
+       /* Now that we have a PCI connection, we need to do the
+        * low level device setup.  This is primarily setting up
+        * the Admin Queue structures and then querying for the
+        * device's current profile information.
+        */
+       pf = kzalloc(sizeof(*pf), GFP_KERNEL);
+       if (!pf) {
+               err = -ENOMEM;
+               goto err_pf_alloc;
+       }
+       pf->next_vsi = 0;
+       pf->pdev = pdev;
+       set_bit(__I40E_DOWN, &pf->state);
+
+       hw = &pf->hw;
+       hw->back = pf;
+       hw->hw_addr = ioremap(pci_resource_start(pdev, 0),
+                             pci_resource_len(pdev, 0));
+       if (!hw->hw_addr) {
+               err = -EIO;
+               dev_info(&pdev->dev, "ioremap(0x%04x, 0x%04x) failed: 0x%x\n",
+                        (unsigned int)pci_resource_start(pdev, 0),
+                        (unsigned int)pci_resource_len(pdev, 0), err);
+               goto err_ioremap;
+       }
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+       hw->subsystem_vendor_id = pdev->subsystem_vendor;
+       hw->subsystem_device_id = pdev->subsystem_device;
+       hw->bus.device = PCI_SLOT(pdev->devfn);
+       hw->bus.func = PCI_FUNC(pdev->devfn);
+
+       /* Reset here to make sure all is clean and to define PF 'n' */
+       err = i40e_pf_reset(hw);
+       if (err) {
+               dev_info(&pdev->dev, "Initial pf_reset failed: %d\n", err);
+               goto err_pf_reset;
+       }
+       pf->pfr_count++;
+
+       hw->aq.num_arq_entries = I40E_AQ_LEN;
+       hw->aq.num_asq_entries = I40E_AQ_LEN;
+       hw->aq.arq_buf_size = I40E_MAX_AQ_BUF_SIZE;
+       hw->aq.asq_buf_size = I40E_MAX_AQ_BUF_SIZE;
+       pf->adminq_work_limit = I40E_AQ_WORK_LIMIT;
+       snprintf(pf->misc_int_name, sizeof(pf->misc_int_name) - 1,
+                "%s-pf%d:misc",
+                dev_driver_string(&pf->pdev->dev), pf->hw.pf_id);
+
+       err = i40e_init_shared_code(hw);
+       if (err) {
+               dev_info(&pdev->dev, "init_shared_code failed: %d\n", err);
+               goto err_pf_reset;
+       }
+
+       err = i40e_init_adminq(hw);
+       dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw));
+       if (err) {
+               dev_info(&pdev->dev,
+                        "init_adminq failed: %d expecting API %02x.%02x\n",
+                        err,
+                        I40E_FW_API_VERSION_MAJOR, I40E_FW_API_VERSION_MINOR);
+               goto err_pf_reset;
+       }
+
+       err = i40e_get_capabilities(pf);
+       if (err)
+               goto err_adminq_setup;
+
+       err = i40e_sw_init(pf);
+       if (err) {
+               dev_info(&pdev->dev, "sw_init failed: %d\n", err);
+               goto err_sw_init;
+       }
+
+       err = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp,
+                               hw->func_caps.num_rx_qp,
+                               pf->fcoe_hmc_cntx_num, pf->fcoe_hmc_filt_num);
+       if (err) {
+               dev_info(&pdev->dev, "init_lan_hmc failed: %d\n", err);
+               goto err_init_lan_hmc;
+       }
+
+       err = i40e_configure_lan_hmc(hw, I40E_HMC_MODEL_DIRECT_ONLY);
+       if (err) {
+               dev_info(&pdev->dev, "configure_lan_hmc failed: %d\n", err);
+               err = -ENOENT;
+               goto err_configure_lan_hmc;
+       }
+
+       i40e_get_mac_addr(hw, hw->mac.addr);
+       if (i40e_validate_mac_addr(hw->mac.addr)) {
+               dev_info(&pdev->dev, "invalid MAC address %pM\n", hw->mac.addr);
+               err = -EIO;
+               goto err_mac_addr;
+       }
+       dev_info(&pdev->dev, "MAC address: %pM\n", hw->mac.addr);
+       memcpy(hw->mac.perm_addr, hw->mac.addr, ETH_ALEN);
+
+       pci_set_drvdata(pdev, pf);
+       pci_save_state(pdev);
+
+       /* set up periodic task facility */
+       setup_timer(&pf->service_timer, i40e_service_timer, (unsigned long)pf);
+       pf->service_timer_period = HZ;
+
+       INIT_WORK(&pf->service_task, i40e_service_task);
+       clear_bit(__I40E_SERVICE_SCHED, &pf->state);
+       pf->flags |= I40E_FLAG_NEED_LINK_UPDATE;
+       pf->link_check_timeout = jiffies;
+
+       /* set up the main switch operations */
+       i40e_determine_queue_usage(pf);
+       i40e_init_interrupt_scheme(pf);
+
+       /* Set up the *vsi struct based on the number of VSIs in the HW,
+        * and set up our local tracking of the MAIN PF vsi.
+        */
+       len = sizeof(struct i40e_vsi *) * pf->hw.func_caps.num_vsis;
+       pf->vsi = kzalloc(len, GFP_KERNEL);
+       if (!pf->vsi)
+               goto err_switch_setup;
+
+       err = i40e_setup_pf_switch(pf);
+       if (err) {
+               dev_info(&pdev->dev, "setup_pf_switch failed: %d\n", err);
+               goto err_vsis;
+       }
+
+       /* The main driver is (mostly) up and happy. We need to set this state
+        * before setting up the misc vector or we get a race and the vector
+        * ends up disabled forever.
+        */
+       clear_bit(__I40E_DOWN, &pf->state);
+
+       /* In case of MSIX we are going to setup the misc vector right here
+        * to handle admin queue events etc. In case of legacy and MSI
+        * the misc functionality and queue processing is combined in
+        * the same vector and that gets setup at open.
+        */
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               err = i40e_setup_misc_vector(pf);
+               if (err) {
+                       dev_info(&pdev->dev,
+                                "setup of misc vector failed: %d\n", err);
+                       goto err_vsis;
+               }
+       }
+
+       /* prep for VF support */
+       if ((pf->flags & I40E_FLAG_SRIOV_ENABLED) &&
+           (pf->flags & I40E_FLAG_MSIX_ENABLED)) {
+               u32 val;
+
+               /* disable link interrupts for VFs */
+               val = rd32(hw, I40E_PFGEN_PORTMDIO_NUM);
+               val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK;
+               wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val);
+               i40e_flush(hw);
+       }
+
+       i40e_dbg_pf_init(pf);
+
+       /* tell the firmware that we're starting */
+       dv.major_version = DRV_VERSION_MAJOR;
+       dv.minor_version = DRV_VERSION_MINOR;
+       dv.build_version = DRV_VERSION_BUILD;
+       dv.subbuild_version = 0;
+       i40e_aq_send_driver_version(&pf->hw, &dv, NULL);
+
+       /* since everything's happy, start the service_task timer */
+       mod_timer(&pf->service_timer,
+                 round_jiffies(jiffies + pf->service_timer_period));
+
+       return 0;
+
+       /* Unwind what we've done if something failed in the setup */
+err_vsis:
+       set_bit(__I40E_DOWN, &pf->state);
+err_switch_setup:
+       i40e_clear_interrupt_scheme(pf);
+       kfree(pf->vsi);
+       del_timer_sync(&pf->service_timer);
+err_mac_addr:
+err_configure_lan_hmc:
+       (void)i40e_shutdown_lan_hmc(hw);
+err_init_lan_hmc:
+       kfree(pf->qp_pile);
+       kfree(pf->irq_pile);
+err_sw_init:
+err_adminq_setup:
+       (void)i40e_shutdown_adminq(hw);
+err_pf_reset:
+       iounmap(hw->hw_addr);
+err_ioremap:
+       kfree(pf);
+err_pf_alloc:
+       pci_disable_pcie_error_reporting(pdev);
+       pci_release_selected_regions(pdev,
+                                    pci_select_bars(pdev, IORESOURCE_MEM));
+err_pci_reg:
+err_dma:
+       pci_disable_device(pdev);
+       return err;
+}
+
+/**
+ * i40e_remove - Device removal routine
+ * @pdev: PCI device information struct
+ *
+ * i40e_remove is called by the PCI subsystem to alert the driver
+ * that is should release a PCI device.  This could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+static void i40e_remove(struct pci_dev *pdev)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       i40e_status ret_code;
+       u32 reg;
+       int i;
+
+       i40e_dbg_pf_exit(pf);
+
+       if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
+               i40e_free_vfs(pf);
+               pf->flags &= ~I40E_FLAG_SRIOV_ENABLED;
+       }
+
+       /* no more scheduling of any task */
+       set_bit(__I40E_DOWN, &pf->state);
+       del_timer_sync(&pf->service_timer);
+       cancel_work_sync(&pf->service_task);
+
+       i40e_fdir_teardown(pf);
+
+       /* If there is a switch structure or any orphans, remove them.
+        * This will leave only the PF's VSI remaining.
+        */
+       for (i = 0; i < I40E_MAX_VEB; i++) {
+               if (!pf->veb[i])
+                       continue;
+
+               if (pf->veb[i]->uplink_seid == pf->mac_seid ||
+                   pf->veb[i]->uplink_seid == 0)
+                       i40e_switch_branch_release(pf->veb[i]);
+       }
+
+       /* Now we can shutdown the PF's VSI, just before we kill
+        * adminq and hmc.
+        */
+       if (pf->vsi[pf->lan_vsi])
+               i40e_vsi_release(pf->vsi[pf->lan_vsi]);
+
+       i40e_stop_misc_vector(pf);
+       if (pf->flags & I40E_FLAG_MSIX_ENABLED) {
+               synchronize_irq(pf->msix_entries[0].vector);
+               free_irq(pf->msix_entries[0].vector, pf);
+       }
+
+       /* shutdown and destroy the HMC */
+       ret_code = i40e_shutdown_lan_hmc(&pf->hw);
+       if (ret_code)
+               dev_warn(&pdev->dev,
+                        "Failed to destroy the HMC resources: %d\n", ret_code);
+
+       /* shutdown the adminq */
+       i40e_aq_queue_shutdown(&pf->hw, true);
+       ret_code = i40e_shutdown_adminq(&pf->hw);
+       if (ret_code)
+               dev_warn(&pdev->dev,
+                        "Failed to destroy the Admin Queue resources: %d\n",
+                        ret_code);
+
+       /* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
+       i40e_clear_interrupt_scheme(pf);
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++) {
+               if (pf->vsi[i]) {
+                       i40e_vsi_clear_rings(pf->vsi[i]);
+                       i40e_vsi_clear(pf->vsi[i]);
+                       pf->vsi[i] = NULL;
+               }
+       }
+
+       for (i = 0; i < I40E_MAX_VEB; i++) {
+               kfree(pf->veb[i]);
+               pf->veb[i] = NULL;
+       }
+
+       kfree(pf->qp_pile);
+       kfree(pf->irq_pile);
+       kfree(pf->sw_config);
+       kfree(pf->vsi);
+
+       /* force a PF reset to clean anything leftover */
+       reg = rd32(&pf->hw, I40E_PFGEN_CTRL);
+       wr32(&pf->hw, I40E_PFGEN_CTRL, (reg | I40E_PFGEN_CTRL_PFSWR_MASK));
+       i40e_flush(&pf->hw);
+
+       iounmap(pf->hw.hw_addr);
+       kfree(pf);
+       pci_release_selected_regions(pdev,
+                                    pci_select_bars(pdev, IORESOURCE_MEM));
+
+       pci_disable_pcie_error_reporting(pdev);
+       pci_disable_device(pdev);
+}
+
+/**
+ * i40e_pci_error_detected - warning that something funky happened in PCI land
+ * @pdev: PCI device information struct
+ *
+ * Called to warn that something happened and the error handling steps
+ * are in progress.  Allows the driver to quiesce things, be ready for
+ * remediation.
+ **/
+static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev,
+                                               enum pci_channel_state error)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+
+       dev_info(&pdev->dev, "%s: error %d\n", __func__, error);
+
+       /* shutdown all operations */
+       i40e_pf_quiesce_all_vsi(pf);
+
+       /* Request a slot reset */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * i40e_pci_error_slot_reset - a PCI slot reset just happened
+ * @pdev: PCI device information struct
+ *
+ * Called to find if the driver can work with the device now that
+ * the pci slot has been reset.  If a basic connection seems good
+ * (registers are readable and have sane content) then return a
+ * happy little PCI_ERS_RESULT_xxx.
+ **/
+static pci_ers_result_t i40e_pci_error_slot_reset(struct pci_dev *pdev)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       pci_ers_result_t result;
+       int err;
+       u32 reg;
+
+       dev_info(&pdev->dev, "%s\n", __func__);
+       if (pci_enable_device_mem(pdev)) {
+               dev_info(&pdev->dev,
+                        "Cannot re-enable PCI device after reset.\n");
+               result = PCI_ERS_RESULT_DISCONNECT;
+       } else {
+               pci_set_master(pdev);
+               pci_restore_state(pdev);
+               pci_save_state(pdev);
+               pci_wake_from_d3(pdev, false);
+
+               reg = rd32(&pf->hw, I40E_GLGEN_RTRIG);
+               if (reg == 0)
+                       result = PCI_ERS_RESULT_RECOVERED;
+               else
+                       result = PCI_ERS_RESULT_DISCONNECT;
+       }
+
+       err = pci_cleanup_aer_uncorrect_error_status(pdev);
+       if (err) {
+               dev_info(&pdev->dev,
+                        "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n",
+                        err);
+               /* non-fatal, continue */
+       }
+
+       return result;
+}
+
+/**
+ * i40e_pci_error_resume - restart operations after PCI error recovery
+ * @pdev: PCI device information struct
+ *
+ * Called to allow the driver to bring things back up after PCI error
+ * and/or reset recovery has finished.
+ **/
+static void i40e_pci_error_resume(struct pci_dev *pdev)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+
+       dev_info(&pdev->dev, "%s\n", __func__);
+       i40e_handle_reset_warning(pf);
+}
+
+static const struct pci_error_handlers i40e_err_handler = {
+       .error_detected = i40e_pci_error_detected,
+       .slot_reset = i40e_pci_error_slot_reset,
+       .resume = i40e_pci_error_resume,
+};
+
+static struct pci_driver i40e_driver = {
+       .name     = i40e_driver_name,
+       .id_table = i40e_pci_tbl,
+       .probe    = i40e_probe,
+       .remove   = i40e_remove,
+       .err_handler = &i40e_err_handler,
+       .sriov_configure = i40e_pci_sriov_configure,
+};
+
+/**
+ * i40e_init_module - Driver registration routine
+ *
+ * i40e_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+static int __init i40e_init_module(void)
+{
+       pr_info("%s: %s - version %s\n", i40e_driver_name,
+               i40e_driver_string, i40e_driver_version_str);
+       pr_info("%s: %s\n", i40e_driver_name, i40e_copyright);
+       i40e_dbg_init();
+       return pci_register_driver(&i40e_driver);
+}
+module_init(i40e_init_module);
+
+/**
+ * i40e_exit_module - Driver exit cleanup routine
+ *
+ * i40e_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+static void __exit i40e_exit_module(void)
+{
+       pci_unregister_driver(&i40e_driver);
+       i40e_dbg_exit();
+}
+module_exit(i40e_exit_module);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c
new file mode 100644 (file)
index 0000000..97e1bb3
--- /dev/null
@@ -0,0 +1,391 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e_prototype.h"
+
+/**
+ *  i40e_init_nvm_ops - Initialize NVM function pointers.
+ *  @hw: pointer to the HW structure.
+ *
+ *  Setups the function pointers and the NVM info structure. Should be called
+ *  once per NVM initialization, e.g. inside the i40e_init_shared_code().
+ *  Please notice that the NVM term is used here (& in all methods covered
+ *  in this file) as an equivalent of the FLASH part mapped into the SR.
+ *  We are accessing FLASH always thru the Shadow RAM.
+ **/
+i40e_status i40e_init_nvm(struct i40e_hw *hw)
+{
+       struct i40e_nvm_info *nvm = &hw->nvm;
+       i40e_status ret_code = 0;
+       u32 fla, gens;
+       u8 sr_size;
+
+       /* The SR size is stored regardless of the nvm programming mode
+        * as the blank mode may be used in the factory line.
+        */
+       gens = rd32(hw, I40E_GLNVM_GENS);
+       sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >>
+                          I40E_GLNVM_GENS_SR_SIZE_SHIFT);
+       /* Switching to words (sr_size contains power of 2KB). */
+       nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB;
+
+       /* Check if we are in the normal or blank NVM programming mode. */
+       fla = rd32(hw, I40E_GLNVM_FLA);
+       if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode. */
+               /* Max NVM timeout. */
+               nvm->timeout = I40E_MAX_NVM_TIMEOUT;
+               nvm->blank_nvm_mode = false;
+       } else { /* Blank programming mode. */
+               nvm->blank_nvm_mode = true;
+               ret_code = I40E_ERR_NVM_BLANK_MODE;
+               hw_dbg(hw, "NVM init error: unsupported blank mode.\n");
+       }
+
+       return ret_code;
+}
+
+/**
+ *  i40e_acquire_nvm - Generic request for acquiring the NVM ownership.
+ *  @hw: pointer to the HW structure.
+ *  @access: NVM access type (read or write).
+ *
+ *  This function will request NVM ownership for reading
+ *  via the proper Admin Command.
+ **/
+i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
+                                      enum i40e_aq_resource_access_type access)
+{
+       i40e_status ret_code = 0;
+       u64 gtime, timeout;
+       u64 time = 0;
+
+       if (hw->nvm.blank_nvm_mode)
+               goto i40e_i40e_acquire_nvm_exit;
+
+       ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access,
+                                           0, &time, NULL);
+       /* Reading the Global Device Timer. */
+       gtime = rd32(hw, I40E_GLVFGEN_TIMER);
+
+       /* Store the timeout. */
+       hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime;
+
+       if (ret_code) {
+               /* Set the polling timeout. */
+               if (time > I40E_MAX_NVM_TIMEOUT)
+                       timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT)
+                                 + gtime;
+               else
+                       timeout = hw->nvm.hw_semaphore_timeout;
+               /* Poll until the current NVM owner timeouts. */
+               while (gtime < timeout) {
+                       usleep_range(10000, 20000);
+                       ret_code = i40e_aq_request_resource(hw,
+                                                       I40E_NVM_RESOURCE_ID,
+                                                       access, 0, &time,
+                                                       NULL);
+                       if (!ret_code) {
+                               hw->nvm.hw_semaphore_timeout =
+                                               I40E_MS_TO_GTIME(time) + gtime;
+                               break;
+                       }
+                       gtime = rd32(hw, I40E_GLVFGEN_TIMER);
+               }
+               if (ret_code) {
+                       hw->nvm.hw_semaphore_timeout = 0;
+                       hw->nvm.hw_semaphore_wait =
+                                               I40E_MS_TO_GTIME(time) + gtime;
+                       hw_dbg(hw, "NVM acquire timed out, wait %llu ms before trying again.\n",
+                                 time);
+               }
+       }
+
+i40e_i40e_acquire_nvm_exit:
+       return ret_code;
+}
+
+/**
+ *  i40e_release_nvm - Generic request for releasing the NVM ownership.
+ *  @hw: pointer to the HW structure.
+ *
+ *  This function will release NVM resource via the proper Admin Command.
+ **/
+void i40e_release_nvm(struct i40e_hw *hw)
+{
+       if (!hw->nvm.blank_nvm_mode)
+               i40e_aq_release_resource(hw, I40E_NVM_RESOURCE_ID, 0, NULL);
+}
+
+/**
+ *  i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit.
+ *  @hw: pointer to the HW structure.
+ *
+ *  Polls the SRCTL Shadow RAM register done bit.
+ **/
+static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw)
+{
+       i40e_status ret_code = I40E_ERR_TIMEOUT;
+       u32 srctl, wait_cnt;
+
+       /* Poll the I40E_GLNVM_SRCTL until the done bit is set. */
+       for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) {
+               srctl = rd32(hw, I40E_GLNVM_SRCTL);
+               if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) {
+                       ret_code = 0;
+                       break;
+               }
+               udelay(5);
+       }
+       if (ret_code == I40E_ERR_TIMEOUT)
+               hw_dbg(hw, "Done bit in GLNVM_SRCTL not set");
+       return ret_code;
+}
+
+/**
+ *  i40e_read_nvm_srctl - Reads Shadow RAM.
+ *  @hw: pointer to the HW structure.
+ *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ *  @data: word read from the Shadow RAM.
+ *
+ *  Reads 16 bit word from the Shadow RAM using the GLNVM_SRCTL register.
+ **/
+static i40e_status i40e_read_nvm_srctl(struct i40e_hw *hw, u16 offset,
+                                                u16 *data)
+{
+       i40e_status ret_code = I40E_ERR_TIMEOUT;
+       u32 sr_reg;
+
+       if (offset >= hw->nvm.sr_size) {
+               hw_dbg(hw, "NVM read error: Offset beyond Shadow RAM limit.\n");
+               ret_code = I40E_ERR_PARAM;
+               goto read_nvm_exit;
+       }
+
+       /* Poll the done bit first. */
+       ret_code = i40e_poll_sr_srctl_done_bit(hw);
+       if (!ret_code) {
+               /* Write the address and start reading. */
+               sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) |
+                        (1 << I40E_GLNVM_SRCTL_START_SHIFT);
+               wr32(hw, I40E_GLNVM_SRCTL, sr_reg);
+
+               /* Poll I40E_GLNVM_SRCTL until the done bit is set. */
+               ret_code = i40e_poll_sr_srctl_done_bit(hw);
+               if (!ret_code) {
+                       sr_reg = rd32(hw, I40E_GLNVM_SRDATA);
+                       *data = (u16)((sr_reg &
+                                      I40E_GLNVM_SRDATA_RDDATA_MASK)
+                                   >> I40E_GLNVM_SRDATA_RDDATA_SHIFT);
+               }
+       }
+       if (ret_code)
+               hw_dbg(hw, "NVM read error: Couldn't access Shadow RAM address: 0x%x\n",
+                         offset);
+
+read_nvm_exit:
+       return ret_code;
+}
+
+/**
+ *  i40e_read_nvm_word - Reads Shadow RAM word.
+ *  @hw: pointer to the HW structure.
+ *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ *  @data: word read from the Shadow RAM.
+ *
+ *  Reads 16 bit word from the Shadow RAM. Each read is preceded
+ *  with the NVM ownership taking and followed by the release.
+ **/
+i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
+                                        u16 *data)
+{
+       i40e_status ret_code = 0;
+
+       ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (!ret_code) {
+               ret_code = i40e_read_nvm_srctl(hw, offset, data);
+               i40e_release_nvm(hw);
+       }
+
+       return ret_code;
+}
+
+/**
+ *  i40e_read_nvm_buffer - Reads Shadow RAM buffer.
+ *  @hw: pointer to the HW structure.
+ *  @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF).
+ *  @words: number of words to read (in) &
+ *          number of words read before the NVM ownership timeout (out).
+ *  @data: words read from the Shadow RAM.
+ *
+ *  Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd()
+ *  method. The buffer read is preceded by the NVM ownership take
+ *  and followed by the release.
+ **/
+i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
+                                          u16 *words, u16 *data)
+{
+       i40e_status ret_code = 0;
+       u16 index, word;
+       u32 time;
+
+       ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (!ret_code) {
+               /* Loop thru the selected region. */
+               for (word = 0; word < *words; word++) {
+                       index = offset + word;
+                       ret_code = i40e_read_nvm_srctl(hw, index, &data[word]);
+                       if (ret_code)
+                               break;
+                       /* Check if we didn't exceeded the semaphore timeout. */
+                       time = rd32(hw, I40E_GLVFGEN_TIMER);
+                       if (time >= hw->nvm.hw_semaphore_timeout) {
+                               ret_code = I40E_ERR_TIMEOUT;
+                               hw_dbg(hw, "NVM read error: timeout.\n");
+                               break;
+                       }
+               }
+               /* Update the number of words read from the Shadow RAM. */
+               *words = word;
+               /* Release the NVM ownership. */
+               i40e_release_nvm(hw);
+       }
+
+       return ret_code;
+}
+
+/**
+ *  i40e_calc_nvm_checksum - Calculates and returns the checksum
+ *  @hw: pointer to hardware structure
+ *
+ *  This function calculate SW Checksum that covers the whole 64kB shadow RAM
+ *  except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD
+ *  is customer specific and unknown. Therefore, this function skips all maximum
+ *  possible size of VPD (1kB).
+ **/
+static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw,
+                                                   u16 *checksum)
+{
+       i40e_status ret_code = 0;
+       u16 pcie_alt_module = 0;
+       u16 checksum_local = 0;
+       u16 vpd_module = 0;
+       u16 word = 0;
+       u32 i = 0;
+
+       /* read pointer to VPD area */
+       ret_code = i40e_read_nvm_srctl(hw, I40E_SR_VPD_PTR, &vpd_module);
+       if (ret_code) {
+               ret_code = I40E_ERR_NVM_CHECKSUM;
+               goto i40e_calc_nvm_checksum_exit;
+       }
+
+       /* read pointer to PCIe Alt Auto-load module */
+       ret_code = i40e_read_nvm_srctl(hw, I40E_SR_PCIE_ALT_AUTO_LOAD_PTR,
+                                      &pcie_alt_module);
+       if (ret_code) {
+               ret_code = I40E_ERR_NVM_CHECKSUM;
+               goto i40e_calc_nvm_checksum_exit;
+       }
+
+       /* Calculate SW checksum that covers the whole 64kB shadow RAM
+        * except the VPD and PCIe ALT Auto-load modules
+        */
+       for (i = 0; i < hw->nvm.sr_size; i++) {
+               /* Skip Checksum word */
+               if (i == I40E_SR_SW_CHECKSUM_WORD)
+                       i++;
+               /* Skip VPD module (convert byte size to word count) */
+               if (i == (u32)vpd_module) {
+                       i += (I40E_SR_VPD_MODULE_MAX_SIZE / 2);
+                       if (i >= hw->nvm.sr_size)
+                               break;
+               }
+               /* Skip PCIe ALT module (convert byte size to word count) */
+               if (i == (u32)pcie_alt_module) {
+                       i += (I40E_SR_PCIE_ALT_MODULE_MAX_SIZE / 2);
+                       if (i >= hw->nvm.sr_size)
+                               break;
+               }
+
+               ret_code = i40e_read_nvm_srctl(hw, (u16)i, &word);
+               if (ret_code) {
+                       ret_code = I40E_ERR_NVM_CHECKSUM;
+                       goto i40e_calc_nvm_checksum_exit;
+               }
+               checksum_local += word;
+       }
+
+       *checksum = (u16)I40E_SR_SW_CHECKSUM_BASE - checksum_local;
+
+i40e_calc_nvm_checksum_exit:
+       return ret_code;
+}
+
+/**
+ *  i40e_validate_nvm_checksum - Validate EEPROM checksum
+ *  @hw: pointer to hardware structure
+ *  @checksum: calculated checksum
+ *
+ *  Performs checksum calculation and validates the NVM SW checksum. If the
+ *  caller does not need checksum, the value can be NULL.
+ **/
+i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
+                                                u16 *checksum)
+{
+       i40e_status ret_code = 0;
+       u16 checksum_sr = 0;
+       u16 checksum_local;
+
+       ret_code = i40e_acquire_nvm(hw, I40E_RESOURCE_READ);
+       if (ret_code)
+               goto i40e_validate_nvm_checksum_exit;
+
+       ret_code = i40e_calc_nvm_checksum(hw, &checksum_local);
+       if (ret_code)
+               goto i40e_validate_nvm_checksum_free;
+
+       /* Do not use i40e_read_nvm_word() because we do not want to take
+        * the synchronization semaphores twice here.
+        */
+       i40e_read_nvm_srctl(hw, I40E_SR_SW_CHECKSUM_WORD, &checksum_sr);
+
+       /* Verify read checksum from EEPROM is the same as
+        * calculated checksum
+        */
+       if (checksum_local != checksum_sr)
+               ret_code = I40E_ERR_NVM_CHECKSUM;
+
+       /* If the user cares, return the calculated checksum */
+       if (checksum)
+               *checksum = checksum_local;
+
+i40e_validate_nvm_checksum_free:
+       i40e_release_nvm(hw);
+
+i40e_validate_nvm_checksum_exit:
+       return ret_code;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_osdep.h b/drivers/net/ethernet/intel/i40e/i40e_osdep.h
new file mode 100644 (file)
index 0000000..702c81b
--- /dev/null
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_OSDEP_H_
+#define _I40E_OSDEP_H_
+
+#include <linux/types.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
+#include <linux/tcp.h>
+#include <linux/pci.h>
+#include <linux/highuid.h>
+
+/* get readq/writeq support for 32 bit kernels, use the low-first version */
+#include <asm-generic/io-64-nonatomic-lo-hi.h>
+
+/* File to be the magic between shared code and
+ * actual OS primitives
+ */
+
+#define hw_dbg(hw, S, A...)    do {} while (0)
+
+#define wr32(a, reg, value)    writel((value), ((a)->hw_addr + (reg)))
+#define rd32(a, reg)           readl((a)->hw_addr + (reg))
+
+#define wr64(a, reg, value)    writeq((value), ((a)->hw_addr + (reg)))
+#define rd64(a, reg)           readq((a)->hw_addr + (reg))
+#define i40e_flush(a)          readl((a)->hw_addr + I40E_GLGEN_STAT)
+
+/* memory allocation tracking */
+struct i40e_dma_mem {
+       void *va;
+       dma_addr_t pa;
+       u32 size;
+} __packed;
+
+#define i40e_allocate_dma_mem(h, m, unused, s, a) \
+                       i40e_allocate_dma_mem_d(h, m, s, a)
+#define i40e_free_dma_mem(h, m) i40e_free_dma_mem_d(h, m)
+
+struct i40e_virt_mem {
+       void *va;
+       u32 size;
+} __packed;
+
+#define i40e_allocate_virt_mem(h, m, s) i40e_allocate_virt_mem_d(h, m, s)
+#define i40e_free_virt_mem(h, m) i40e_free_virt_mem_d(h, m)
+
+#define i40e_debug(h, m, s, ...)                                \
+do {                                                            \
+       if (((m) & (h)->debug_mask))                            \
+               pr_info("i40e %02x.%x " s,                      \
+                       (h)->bus.device, (h)->bus.func,         \
+                       ##__VA_ARGS__);                         \
+} while (0)
+
+typedef enum i40e_status_code i40e_status;
+#endif /* _I40E_OSDEP_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
new file mode 100644 (file)
index 0000000..f75bb9c
--- /dev/null
@@ -0,0 +1,239 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_PROTOTYPE_H_
+#define _I40E_PROTOTYPE_H_
+
+#include "i40e_type.h"
+#include "i40e_alloc.h"
+#include "i40e_virtchnl.h"
+
+/* Prototypes for shared code functions that are not in
+ * the standard function pointer structures.  These are
+ * mostly because they are needed even before the init
+ * has happened and will assist in the early SW and FW
+ * setup.
+ */
+
+/* adminq functions */
+i40e_status i40e_init_adminq(struct i40e_hw *hw);
+i40e_status i40e_shutdown_adminq(struct i40e_hw *hw);
+void i40e_adminq_init_ring_data(struct i40e_hw *hw);
+i40e_status i40e_clean_arq_element(struct i40e_hw *hw,
+                                            struct i40e_arq_event_info *e,
+                                            u16 *events_pending);
+i40e_status i40e_asq_send_command(struct i40e_hw *hw,
+                               struct i40e_aq_desc *desc,
+                               void *buff, /* can be NULL */
+                               u16  buff_size,
+                               struct i40e_asq_cmd_details *cmd_details);
+bool i40e_asq_done(struct i40e_hw *hw);
+
+/* debug function for adminq */
+void i40e_debug_aq(struct i40e_hw *hw,
+                  enum i40e_debug_mask mask,
+                  void *desc,
+                  void *buffer);
+
+void i40e_idle_aq(struct i40e_hw *hw);
+void i40e_resume_aq(struct i40e_hw *hw);
+
+u32 i40e_led_get(struct i40e_hw *hw);
+void i40e_led_set(struct i40e_hw *hw, u32 mode);
+
+/* admin send queue commands */
+
+i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw,
+                               u16 *fw_major_version, u16 *fw_minor_version,
+                               u16 *api_major_version, u16 *api_minor_version,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw,
+                                            bool unloading);
+i40e_status i40e_aq_set_phy_reset(struct i40e_hw *hw,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_link_restart_an(struct i40e_hw *hw,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_link_info(struct i40e_hw *hw,
+                               bool enable_lse, struct i40e_link_status *link,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_local_advt_reg(struct i40e_hw *hw,
+                               u64 advt_reg,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_send_driver_version(struct i40e_hw *hw,
+                               struct i40e_driver_version *dv,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_add_vsi(struct i40e_hw *hw,
+                               struct i40e_vsi_context *vsi_ctx,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw,
+                               u16 vsi_id, bool set_filter,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw,
+                               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw,
+                               u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw,
+                               struct i40e_vsi_context *vsi_ctx,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_update_vsi_params(struct i40e_hw *hw,
+                               struct i40e_vsi_context *vsi_ctx,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid,
+                               u16 downlink_seid, u8 enabled_tc,
+                               bool default_port, u16 *pveb_seid,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_veb_parameters(struct i40e_hw *hw,
+                               u16 veb_seid, u16 *switch_id, bool *floating,
+                               u16 *statistic_index, u16 *vebs_used,
+                               u16 *vebs_free,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_add_macvlan(struct i40e_hw *hw, u16 vsi_id,
+                       struct i40e_aqc_add_macvlan_element_data *mv_list,
+                       u16 count, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 vsi_id,
+                       struct i40e_aqc_remove_macvlan_element_data *mv_list,
+                       u16 count, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_add_vlan(struct i40e_hw *hw, u16 vsi_id,
+                       struct i40e_aqc_add_remove_vlan_element_data *v_list,
+                       u8 count, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_remove_vlan(struct i40e_hw *hw, u16 vsi_id,
+                       struct i40e_aqc_add_remove_vlan_element_data *v_list,
+                       u8 count, struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid,
+                               u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_switch_config(struct i40e_hw *hw,
+                               struct i40e_aqc_get_switch_config_resp *buf,
+                               u16 buf_size, u16 *start_seid,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_request_resource(struct i40e_hw *hw,
+                               enum i40e_aq_resources_ids resource,
+                               enum i40e_aq_resource_access_type access,
+                               u8 sdp_number, u64 *timeout,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_release_resource(struct i40e_hw *hw,
+                               enum i40e_aq_resources_ids resource,
+                               u8 sdp_number,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_read_nvm(struct i40e_hw *hw, u8 module_pointer,
+                               u32 offset, u16 length, void *data,
+                               bool last_command,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_discover_capabilities(struct i40e_hw *hw,
+                               void *buff, u16 buff_size, u16 *data_size,
+                               enum i40e_admin_queue_opc list_type_opc,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_update_nvm(struct i40e_hw *hw, u8 module_pointer,
+                               u32 offset, u16 length, void *data,
+                               bool last_command,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_get_lldp_mib(struct i40e_hw *hw, u8 bridge_type,
+                               u8 mib_type, void *buff, u16 buff_size,
+                               u16 *local_len, u16 *remote_len,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_cfg_lldp_mib_change_event(struct i40e_hw *hw,
+                               bool enable_update,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_stop_lldp(struct i40e_hw *hw, bool shutdown_agent,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_start_lldp(struct i40e_hw *hw,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_delete_element(struct i40e_hw *hw, u16 seid,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_mac_address_write(struct i40e_hw *hw,
+                                   u16 flags, u8 *mac_addr,
+                                   struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_set_hmc_resource_profile(struct i40e_hw *hw,
+                               enum i40e_aq_hmc_profile profile,
+                               u8 pe_vf_enabled_count,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_config_switch_comp_bw_limit(struct i40e_hw *hw,
+                               u16 seid, u16 credit, u8 max_bw,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_config_vsi_tc_bw(struct i40e_hw *hw, u16 seid,
+                       struct i40e_aqc_configure_vsi_tc_bw_data *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_query_vsi_bw_config(struct i40e_hw *hw,
+                       u16 seid,
+                       struct i40e_aqc_query_vsi_bw_config_resp *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_query_vsi_ets_sla_config(struct i40e_hw *hw,
+                       u16 seid,
+                       struct i40e_aqc_query_vsi_ets_sla_config_resp *bw_data,
+                       struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_query_switch_comp_ets_config(struct i40e_hw *hw,
+               u16 seid,
+               struct i40e_aqc_query_switching_comp_ets_config_resp *bw_data,
+               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_query_port_ets_config(struct i40e_hw *hw,
+               u16 seid,
+               struct i40e_aqc_query_port_ets_config_resp *bw_data,
+               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
+               u16 seid,
+               struct i40e_aqc_query_switching_comp_bw_config_resp *bw_data,
+               struct i40e_asq_cmd_details *cmd_details);
+/* i40e_common */
+i40e_status i40e_init_shared_code(struct i40e_hw *hw);
+i40e_status i40e_pf_reset(struct i40e_hw *hw);
+void i40e_clear_pxe_mode(struct i40e_hw *hw);
+bool i40e_get_link_status(struct i40e_hw *hw);
+i40e_status i40e_get_mac_addr(struct i40e_hw *hw,
+                                               u8 *mac_addr);
+i40e_status i40e_validate_mac_addr(u8 *mac_addr);
+i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
+                                       struct i40e_lldp_variables *lldp_cfg);
+/* prototype for functions used for NVM access */
+i40e_status i40e_init_nvm(struct i40e_hw *hw);
+i40e_status i40e_acquire_nvm(struct i40e_hw *hw,
+                                     enum i40e_aq_resource_access_type access);
+void i40e_release_nvm(struct i40e_hw *hw);
+i40e_status i40e_read_nvm_srrd(struct i40e_hw *hw, u16 offset,
+                                        u16 *data);
+i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset,
+                                        u16 *data);
+i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset,
+                                          u16 *words, u16 *data);
+i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw,
+                                                u16 *checksum);
+
+/* prototype for functions used for SW locks */
+
+/* i40e_common for VF drivers*/
+void i40e_vf_parse_hw_config(struct i40e_hw *hw,
+                            struct i40e_virtchnl_vf_resource *msg);
+i40e_status i40e_vf_reset(struct i40e_hw *hw);
+i40e_status i40e_aq_send_msg_to_pf(struct i40e_hw *hw,
+                               enum i40e_virtchnl_ops v_opcode,
+                               i40e_status v_retval,
+                               u8 *msg, u16 msglen,
+                               struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_set_filter_control(struct i40e_hw *hw,
+                               struct i40e_filter_control_settings *settings);
+#endif /* _I40E_PROTOTYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h
new file mode 100644 (file)
index 0000000..6bd333c
--- /dev/null
@@ -0,0 +1,4688 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_REGISTER_H_
+#define _I40E_REGISTER_H_
+
+#define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4
+#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0
+#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT)
+#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT 16
+#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT)
+#define I40E_GLPCI_PM_MUX_PFB 0x0009C4F0
+#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT 0
+#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK (0x1F << I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT)
+#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16
+#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK (0x7 << I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT)
+#define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8
+#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0
+#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT)
+#define I40E_GLPCI_SPARE_BITS_1 0x0009C4FC
+#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT 0
+#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_MASK (0xFFFFFFFF << I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT)
+#define I40E_PFPCI_PF_FLUSH_DONE 0x0009C800
+#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT 0
+#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT)
+#define I40E_PFPCI_VF_FLUSH_DONE 0x0009C600
+#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0
+#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT)
+#define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880
+#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0
+#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK (0x1 << I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT)
+#define I40E_PF_ARQBAH 0x00080180
+#define I40E_PF_ARQBAH_ARQBAH_SHIFT 0
+#define I40E_PF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_PF_ARQBAH_ARQBAH_SHIFT)
+#define I40E_PF_ARQBAL 0x00080080
+#define I40E_PF_ARQBAL_ARQBAL_SHIFT 0
+#define I40E_PF_ARQBAL_ARQBAL_MASK (0xFFFFFFFF << I40E_PF_ARQBAL_ARQBAL_SHIFT)
+#define I40E_PF_ARQH 0x00080380
+#define I40E_PF_ARQH_ARQH_SHIFT 0
+#define I40E_PF_ARQH_ARQH_MASK (0x3FF << I40E_PF_ARQH_ARQH_SHIFT)
+#define I40E_PF_ARQLEN 0x00080280
+#define I40E_PF_ARQLEN_ARQLEN_SHIFT 0
+#define I40E_PF_ARQLEN_ARQLEN_MASK (0x3FF << I40E_PF_ARQLEN_ARQLEN_SHIFT)
+#define I40E_PF_ARQLEN_ARQVFE_SHIFT 28
+#define I40E_PF_ARQLEN_ARQVFE_MASK (0x1 << I40E_PF_ARQLEN_ARQVFE_SHIFT)
+#define I40E_PF_ARQLEN_ARQOVFL_SHIFT 29
+#define I40E_PF_ARQLEN_ARQOVFL_MASK (0x1 << I40E_PF_ARQLEN_ARQOVFL_SHIFT)
+#define I40E_PF_ARQLEN_ARQCRIT_SHIFT 30
+#define I40E_PF_ARQLEN_ARQCRIT_MASK (0x1 << I40E_PF_ARQLEN_ARQCRIT_SHIFT)
+#define I40E_PF_ARQLEN_ARQENABLE_SHIFT 31
+#define I40E_PF_ARQLEN_ARQENABLE_MASK (0x1 << I40E_PF_ARQLEN_ARQENABLE_SHIFT)
+#define I40E_PF_ARQT 0x00080480
+#define I40E_PF_ARQT_ARQT_SHIFT 0
+#define I40E_PF_ARQT_ARQT_MASK (0x3FF << I40E_PF_ARQT_ARQT_SHIFT)
+#define I40E_PF_ATQBAH 0x00080100
+#define I40E_PF_ATQBAH_ATQBAH_SHIFT 0
+#define I40E_PF_ATQBAH_ATQBAH_MASK (0xFFFFFFFF << I40E_PF_ATQBAH_ATQBAH_SHIFT)
+#define I40E_PF_ATQBAL 0x00080000
+#define I40E_PF_ATQBAL_ATQBAL_SHIFT 0
+#define I40E_PF_ATQBAL_ATQBAL_MASK (0xFFFFFFFF << I40E_PF_ATQBAL_ATQBAL_SHIFT)
+#define I40E_PF_ATQH 0x00080300
+#define I40E_PF_ATQH_ATQH_SHIFT 0
+#define I40E_PF_ATQH_ATQH_MASK (0x3FF << I40E_PF_ATQH_ATQH_SHIFT)
+#define I40E_PF_ATQLEN 0x00080200
+#define I40E_PF_ATQLEN_ATQLEN_SHIFT 0
+#define I40E_PF_ATQLEN_ATQLEN_MASK (0x3FF << I40E_PF_ATQLEN_ATQLEN_SHIFT)
+#define I40E_PF_ATQLEN_ATQVFE_SHIFT 28
+#define I40E_PF_ATQLEN_ATQVFE_MASK (0x1 << I40E_PF_ATQLEN_ATQVFE_SHIFT)
+#define I40E_PF_ATQLEN_ATQOVFL_SHIFT 29
+#define I40E_PF_ATQLEN_ATQOVFL_MASK (0x1 << I40E_PF_ATQLEN_ATQOVFL_SHIFT)
+#define I40E_PF_ATQLEN_ATQCRIT_SHIFT 30
+#define I40E_PF_ATQLEN_ATQCRIT_MASK (0x1 << I40E_PF_ATQLEN_ATQCRIT_SHIFT)
+#define I40E_PF_ATQLEN_ATQENABLE_SHIFT 31
+#define I40E_PF_ATQLEN_ATQENABLE_MASK (0x1 << I40E_PF_ATQLEN_ATQENABLE_SHIFT)
+#define I40E_PF_ATQT 0x00080400
+#define I40E_PF_ATQT_ATQT_SHIFT 0
+#define I40E_PF_ATQT_ATQT_MASK (0x3FF << I40E_PF_ATQT_ATQT_SHIFT)
+#define I40E_VF_ARQBAH(_VF) (0x00081400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ARQBAH_MAX_INDEX 127
+#define I40E_VF_ARQBAH_ARQBAH_SHIFT 0
+#define I40E_VF_ARQBAH_ARQBAH_MASK (0xFFFFFFFF << I40E_VF_ARQBAH_ARQBAH_SHIFT)
+#define I40E_VF_ARQBAL(_VF) (0x00080C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ARQBAL_MAX_INDEX 127
+#define I40E_VF_ARQBAL_ARQBAL_SHIFT 0
+#define I40E_VF_ARQBAL_ARQBAL_MASK (0xFFFFFFFF << I40E_VF_ARQBAL_ARQBAL_SHIFT)
+#define I40E_VF_ARQH(_VF) (0x00082400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ARQH_MAX_INDEX 127
+#define I40E_VF_ARQH_ARQH_SHIFT 0
+#define I40E_VF_ARQH_ARQH_MASK (0x3FF << I40E_VF_ARQH_ARQH_SHIFT)
+#define I40E_VF_ARQLEN(_VF) (0x00081C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ARQLEN_MAX_INDEX 127
+#define I40E_VF_ARQLEN_ARQLEN_SHIFT 0
+#define I40E_VF_ARQLEN_ARQLEN_MASK (0x3FF << I40E_VF_ARQLEN_ARQLEN_SHIFT)
+#define I40E_VF_ARQLEN_ARQVFE_SHIFT 28
+#define I40E_VF_ARQLEN_ARQVFE_MASK (0x1 << I40E_VF_ARQLEN_ARQVFE_SHIFT)
+#define I40E_VF_ARQLEN_ARQOVFL_SHIFT 29
+#define I40E_VF_ARQLEN_ARQOVFL_MASK (0x1 << I40E_VF_ARQLEN_ARQOVFL_SHIFT)
+#define I40E_VF_ARQLEN_ARQCRIT_SHIFT 30
+#define I40E_VF_ARQLEN_ARQCRIT_MASK (0x1 << I40E_VF_ARQLEN_ARQCRIT_SHIFT)
+#define I40E_VF_ARQLEN_ARQENABLE_SHIFT 31
+#define I40E_VF_ARQLEN_ARQENABLE_MASK (0x1 << I40E_VF_ARQLEN_ARQENABLE_SHIFT)
+#define I40E_VF_ARQT(_VF) (0x00082C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ARQT_MAX_INDEX 127
+#define I40E_VF_ARQT_ARQT_SHIFT 0
+#define I40E_VF_ARQT_ARQT_MASK (0x3FF << I40E_VF_ARQT_ARQT_SHIFT)
+#define I40E_VF_ATQBAH(_VF) (0x00081000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ATQBAH_MAX_INDEX 127
+#define I40E_VF_ATQBAH_ATQBAH_SHIFT 0
+#define I40E_VF_ATQBAH_ATQBAH_MASK (0xFFFFFFFF << I40E_VF_ATQBAH_ATQBAH_SHIFT)
+#define I40E_VF_ATQBAL(_VF) (0x00080800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ATQBAL_MAX_INDEX 127
+#define I40E_VF_ATQBAL_ATQBAL_SHIFT 0
+#define I40E_VF_ATQBAL_ATQBAL_MASK (0xFFFFFFFF << I40E_VF_ATQBAL_ATQBAL_SHIFT)
+#define I40E_VF_ATQH(_VF) (0x00082000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ATQH_MAX_INDEX 127
+#define I40E_VF_ATQH_ATQH_SHIFT 0
+#define I40E_VF_ATQH_ATQH_MASK (0x3FF << I40E_VF_ATQH_ATQH_SHIFT)
+#define I40E_VF_ATQLEN(_VF) (0x00081800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ATQLEN_MAX_INDEX 127
+#define I40E_VF_ATQLEN_ATQLEN_SHIFT 0
+#define I40E_VF_ATQLEN_ATQLEN_MASK (0x3FF << I40E_VF_ATQLEN_ATQLEN_SHIFT)
+#define I40E_VF_ATQLEN_ATQVFE_SHIFT 28
+#define I40E_VF_ATQLEN_ATQVFE_MASK (0x1 << I40E_VF_ATQLEN_ATQVFE_SHIFT)
+#define I40E_VF_ATQLEN_ATQOVFL_SHIFT 29
+#define I40E_VF_ATQLEN_ATQOVFL_MASK (0x1 << I40E_VF_ATQLEN_ATQOVFL_SHIFT)
+#define I40E_VF_ATQLEN_ATQCRIT_SHIFT 30
+#define I40E_VF_ATQLEN_ATQCRIT_MASK (0x1 << I40E_VF_ATQLEN_ATQCRIT_SHIFT)
+#define I40E_VF_ATQLEN_ATQENABLE_SHIFT 31
+#define I40E_VF_ATQLEN_ATQENABLE_MASK (0x1 << I40E_VF_ATQLEN_ATQENABLE_SHIFT)
+#define I40E_VF_ATQT(_VF) (0x00082800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VF_ATQT_MAX_INDEX 127
+#define I40E_VF_ATQT_ATQT_SHIFT 0
+#define I40E_VF_ATQT_ATQT_MASK (0x3FF << I40E_VF_ATQT_ATQT_SHIFT)
+#define I40E_PRT_L2TAGSEN 0x001C0B20
+#define I40E_PRT_L2TAGSEN_ENABLE_SHIFT 0
+#define I40E_PRT_L2TAGSEN_ENABLE_MASK (0xFF << I40E_PRT_L2TAGSEN_ENABLE_SHIFT)
+#define I40E_PFCM_LAN_ERRDATA 0x0010C080
+#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT 0
+#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_MASK (0xF << I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT)
+#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT 4
+#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_MASK (0x7 << I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT)
+#define I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT 8
+#define I40E_PFCM_LAN_ERRDATA_Q_NUM_MASK (0xFFF << I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT)
+#define I40E_PFCM_LAN_ERRINFO 0x0010C000
+#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT 0
+#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT)
+#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT 4
+#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_MASK (0x7 << I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT)
+#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT 8
+#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT)
+#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT 16
+#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT)
+#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT 24
+#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT)
+#define I40E_PFCM_LANCTXCTL 0x0010C300
+#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT 0
+#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_MASK (0xFFF << I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT)
+#define I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT 12
+#define I40E_PFCM_LANCTXCTL_SUB_LINE_MASK (0x7 << I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT)
+#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT 15
+#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_MASK (0x3 << I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT)
+#define I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT 17
+#define I40E_PFCM_LANCTXCTL_OP_CODE_MASK (0x3 << I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT)
+#define I40E_PFCM_LANCTXDATA(_i) (0x0010C100 + ((_i) * 128)) /* _i=0...3 */
+#define I40E_PFCM_LANCTXDATA_MAX_INDEX 3
+#define I40E_PFCM_LANCTXDATA_DATA_SHIFT 0
+#define I40E_PFCM_LANCTXDATA_DATA_MASK (0xFFFFFFFF << I40E_PFCM_LANCTXDATA_DATA_SHIFT)
+#define I40E_PFCM_LANCTXSTAT 0x0010C380
+#define I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT 0
+#define I40E_PFCM_LANCTXSTAT_CTX_DONE_MASK (0x1 << I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT)
+#define I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT 1
+#define I40E_PFCM_LANCTXSTAT_CTX_MISS_MASK (0x1 << I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT)
+#define I40E_PFCM_PE_ERRDATA 0x00138D00
+#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0
+#define I40E_PFCM_PE_ERRDATA_ERROR_CODE_MASK (0xF << I40E_PFCM_PE_ERRDATA_ERROR_CODE_SHIFT)
+#define I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT 4
+#define I40E_PFCM_PE_ERRDATA_Q_TYPE_MASK (0x7 << I40E_PFCM_PE_ERRDATA_Q_TYPE_SHIFT)
+#define I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT 8
+#define I40E_PFCM_PE_ERRDATA_Q_NUM_MASK (0x3FFFF << I40E_PFCM_PE_ERRDATA_Q_NUM_SHIFT)
+#define I40E_PFCM_PE_ERRINFO 0x00138C80
+#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0
+#define I40E_PFCM_PE_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_PFCM_PE_ERRINFO_ERROR_VALID_SHIFT)
+#define I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT 4
+#define I40E_PFCM_PE_ERRINFO_ERROR_INST_MASK (0x7 << I40E_PFCM_PE_ERRINFO_ERROR_INST_SHIFT)
+#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8
+#define I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT)
+#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16
+#define I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT)
+#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24
+#define I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_PFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT)
+#define I40E_VFCM_PE_ERRDATA1(_VF) (0x00138800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFCM_PE_ERRDATA1_MAX_INDEX 127
+#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT 0
+#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_MASK (0xF << I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT)
+#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT 4
+#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_MASK (0x7 << I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT)
+#define I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT 8
+#define I40E_VFCM_PE_ERRDATA1_Q_NUM_MASK (0x3FFFF << I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT)
+#define I40E_VFCM_PE_ERRINFO1(_VF) (0x00138400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFCM_PE_ERRINFO1_MAX_INDEX 127
+#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT 0
+#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_MASK (0x1 << I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT)
+#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT 4
+#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_MASK (0x7 << I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT)
+#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT 8
+#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT)
+#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT 16
+#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT)
+#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT 24
+#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT)
+#define I40E_GLDCB_GENC 0x00083044
+#define I40E_GLDCB_GENC_PCIRTT_SHIFT 0
+#define I40E_GLDCB_GENC_PCIRTT_MASK (0xFFFF << I40E_GLDCB_GENC_PCIRTT_SHIFT)
+#define I40E_GLDCB_RUPTI 0x00122618
+#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT 0
+#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_MASK (0xFFFFFFFF << I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT)
+#define I40E_PRTDCB_FCCFG 0x001E4640
+#define I40E_PRTDCB_FCCFG_TFCE_SHIFT 3
+#define I40E_PRTDCB_FCCFG_TFCE_MASK (0x3 << I40E_PRTDCB_FCCFG_TFCE_SHIFT)
+#define I40E_PRTDCB_FCRTV 0x001E4600
+#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT 0
+#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK (0xFFFF << I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT)
+#define I40E_PRTDCB_FCTTVN(_i) (0x001E4580 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRTDCB_FCTTVN_MAX_INDEX 3
+#define I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT 0
+#define I40E_PRTDCB_FCTTVN_TTV_2N_MASK (0xFFFF << I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT)
+#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT 16
+#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_MASK (0xFFFF << I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT)
+#define I40E_PRTDCB_GENC 0x00083000
+#define I40E_PRTDCB_GENC_RESERVED_1_SHIFT 0
+#define I40E_PRTDCB_GENC_RESERVED_1_MASK (0x3 << I40E_PRTDCB_GENC_RESERVED_1_SHIFT)
+#define I40E_PRTDCB_GENC_NUMTC_SHIFT 2
+#define I40E_PRTDCB_GENC_NUMTC_MASK (0xF << I40E_PRTDCB_GENC_NUMTC_SHIFT)
+#define I40E_PRTDCB_GENC_FCOEUP_SHIFT 6
+#define I40E_PRTDCB_GENC_FCOEUP_MASK (0x7 << I40E_PRTDCB_GENC_FCOEUP_SHIFT)
+#define I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT 9
+#define I40E_PRTDCB_GENC_FCOEUP_VALID_MASK (0x1 << I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT)
+#define I40E_PRTDCB_GENC_PFCLDA_SHIFT 16
+#define I40E_PRTDCB_GENC_PFCLDA_MASK (0xFFFF << I40E_PRTDCB_GENC_PFCLDA_SHIFT)
+#define I40E_PRTDCB_GENS 0x00083020
+#define I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT 0
+#define I40E_PRTDCB_GENS_DCBX_STATUS_MASK (0x7 << I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT)
+#define I40E_PRTDCB_MFLCN 0x001E2400
+#define I40E_PRTDCB_MFLCN_PMCF_SHIFT 0
+#define I40E_PRTDCB_MFLCN_PMCF_MASK (0x1 << I40E_PRTDCB_MFLCN_PMCF_SHIFT)
+#define I40E_PRTDCB_MFLCN_DPF_SHIFT 1
+#define I40E_PRTDCB_MFLCN_DPF_MASK (0x1 << I40E_PRTDCB_MFLCN_DPF_SHIFT)
+#define I40E_PRTDCB_MFLCN_RPFCM_SHIFT 2
+#define I40E_PRTDCB_MFLCN_RPFCM_MASK (0x1 << I40E_PRTDCB_MFLCN_RPFCM_SHIFT)
+#define I40E_PRTDCB_MFLCN_RFCE_SHIFT 3
+#define I40E_PRTDCB_MFLCN_RFCE_MASK (0x1 << I40E_PRTDCB_MFLCN_RFCE_SHIFT)
+#define I40E_PRTDCB_MFLCN_RPFCE_SHIFT 4
+#define I40E_PRTDCB_MFLCN_RPFCE_MASK (0xFF << I40E_PRTDCB_MFLCN_RPFCE_SHIFT)
+#define I40E_PRTDCB_RETSC 0x001223E0
+#define I40E_PRTDCB_RETSC_ETS_MODE_SHIFT 0
+#define I40E_PRTDCB_RETSC_ETS_MODE_MASK (0x1 << I40E_PRTDCB_RETSC_ETS_MODE_SHIFT)
+#define I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT 1
+#define I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK (0x1 << I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT)
+#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT 2
+#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK (0xF << I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT)
+#define I40E_PRTDCB_RETSC_LLTC_SHIFT 8
+#define I40E_PRTDCB_RETSC_LLTC_MASK (0xFF << I40E_PRTDCB_RETSC_LLTC_SHIFT)
+#define I40E_PRTDCB_RETSTCC(_i) (0x00122180 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTDCB_RETSTCC_MAX_INDEX 7
+#define I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT 0
+#define I40E_PRTDCB_RETSTCC_BWSHARE_MASK (0x7F << I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT)
+#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT 30
+#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK (0x1 << I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT)
+#define I40E_PRTDCB_RETSTCC_ETSTC_SHIFT 31
+#define I40E_PRTDCB_RETSTCC_ETSTC_MASK (0x1 << I40E_PRTDCB_RETSTCC_ETSTC_SHIFT)
+#define I40E_PRTDCB_RPPMC 0x001223A0
+#define I40E_PRTDCB_RPPMC_LANRPPM_SHIFT 0
+#define I40E_PRTDCB_RPPMC_LANRPPM_MASK (0xFF << I40E_PRTDCB_RPPMC_LANRPPM_SHIFT)
+#define I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT 8
+#define I40E_PRTDCB_RPPMC_RDMARPPM_MASK (0xFF << I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT)
+#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT 16
+#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK (0xFF << I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT)
+#define I40E_PRTDCB_RUP 0x001C0B00
+#define I40E_PRTDCB_RUP_NOVLANUP_SHIFT 0
+#define I40E_PRTDCB_RUP_NOVLANUP_MASK (0x7 << I40E_PRTDCB_RUP_NOVLANUP_SHIFT)
+#define I40E_PRTDCB_RUP2TC 0x001C09A0
+#define I40E_PRTDCB_RUP2TC_UP0TC_SHIFT 0
+#define I40E_PRTDCB_RUP2TC_UP0TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP0TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP1TC_SHIFT 3
+#define I40E_PRTDCB_RUP2TC_UP1TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP1TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP2TC_SHIFT 6
+#define I40E_PRTDCB_RUP2TC_UP2TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP2TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP3TC_SHIFT 9
+#define I40E_PRTDCB_RUP2TC_UP3TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP3TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP4TC_SHIFT 12
+#define I40E_PRTDCB_RUP2TC_UP4TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP4TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP5TC_SHIFT 15
+#define I40E_PRTDCB_RUP2TC_UP5TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP5TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP6TC_SHIFT 18
+#define I40E_PRTDCB_RUP2TC_UP6TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP6TC_SHIFT)
+#define I40E_PRTDCB_RUP2TC_UP7TC_SHIFT 21
+#define I40E_PRTDCB_RUP2TC_UP7TC_MASK (0x7 << I40E_PRTDCB_RUP2TC_UP7TC_SHIFT)
+#define I40E_PRTDCB_TC2PFC 0x001C0980
+#define I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT 0
+#define I40E_PRTDCB_TC2PFC_TC2PFC_MASK (0xFF << I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT)
+#define I40E_PRTDCB_TCPMC 0x000A21A0
+#define I40E_PRTDCB_TCPMC_CPM_SHIFT 0
+#define I40E_PRTDCB_TCPMC_CPM_MASK (0x1FFF << I40E_PRTDCB_TCPMC_CPM_SHIFT)
+#define I40E_PRTDCB_TCPMC_LLTC_SHIFT 13
+#define I40E_PRTDCB_TCPMC_LLTC_MASK (0xFF << I40E_PRTDCB_TCPMC_LLTC_SHIFT)
+#define I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT 30
+#define I40E_PRTDCB_TCPMC_TCPM_MODE_MASK (0x1 << I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT)
+#define I40E_PRTDCB_TCWSTC(_i) (0x000A2040 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTDCB_TCWSTC_MAX_INDEX 7
+#define I40E_PRTDCB_TCWSTC_MSTC_SHIFT 0
+#define I40E_PRTDCB_TCWSTC_MSTC_MASK (0xFFFFF << I40E_PRTDCB_TCWSTC_MSTC_SHIFT)
+#define I40E_PRTDCB_TDPMC 0x000A0180
+#define I40E_PRTDCB_TDPMC_DPM_SHIFT 0
+#define I40E_PRTDCB_TDPMC_DPM_MASK (0xFF << I40E_PRTDCB_TDPMC_DPM_SHIFT)
+#define I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT 30
+#define I40E_PRTDCB_TDPMC_TCPM_MODE_MASK (0x1 << I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT)
+#define I40E_PRTDCB_TDPUC 0x00044100
+#define I40E_PRTDCB_TDPUC_MAX_TXFRAME_SHIFT 0
+#define I40E_PRTDCB_TDPUC_MAX_TXFRAME_MASK (0xFFFF << I40E_PRTDCB_TDPUC_MAX_TXFRAME_SHIFT)
+#define I40E_PRTDCB_TETSC_TCB 0x000AE060
+#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT 0
+#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_MASK (0x1 << I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT)
+#define I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT 8
+#define I40E_PRTDCB_TETSC_TCB_LLTC_MASK (0xFF << I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT)
+#define I40E_PRTDCB_TETSC_TPB 0x00098060
+#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT 0
+#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_MASK (0x1 << I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT)
+#define I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT 8
+#define I40E_PRTDCB_TETSC_TPB_LLTC_MASK (0xFF << I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT)
+#define I40E_PRTDCB_TFCS 0x001E4560
+#define I40E_PRTDCB_TFCS_TXOFF_SHIFT 0
+#define I40E_PRTDCB_TFCS_TXOFF_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF0_SHIFT 8
+#define I40E_PRTDCB_TFCS_TXOFF0_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF0_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF1_SHIFT 9
+#define I40E_PRTDCB_TFCS_TXOFF1_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF1_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF2_SHIFT 10
+#define I40E_PRTDCB_TFCS_TXOFF2_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF2_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF3_SHIFT 11
+#define I40E_PRTDCB_TFCS_TXOFF3_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF3_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF4_SHIFT 12
+#define I40E_PRTDCB_TFCS_TXOFF4_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF4_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF5_SHIFT 13
+#define I40E_PRTDCB_TFCS_TXOFF5_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF5_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF6_SHIFT 14
+#define I40E_PRTDCB_TFCS_TXOFF6_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF6_SHIFT)
+#define I40E_PRTDCB_TFCS_TXOFF7_SHIFT 15
+#define I40E_PRTDCB_TFCS_TXOFF7_MASK (0x1 << I40E_PRTDCB_TFCS_TXOFF7_SHIFT)
+#define I40E_PRTDCB_TFWSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTDCB_TFWSTC_MAX_INDEX 7
+#define I40E_PRTDCB_TFWSTC_MSTC_SHIFT 0
+#define I40E_PRTDCB_TFWSTC_MSTC_MASK (0xFFFFF << I40E_PRTDCB_TFWSTC_MSTC_SHIFT)
+#define I40E_PRTDCB_TPFCTS(_i) (0x001E4660 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTDCB_TPFCTS_MAX_INDEX 7
+#define I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT 0
+#define I40E_PRTDCB_TPFCTS_PFCTIMER_MASK (0x3FFF << I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT)
+#define I40E_GLFCOE_RCTL 0x00269B94
+#define I40E_GLFCOE_RCTL_FCOEVER_SHIFT 0
+#define I40E_GLFCOE_RCTL_FCOEVER_MASK (0xF << I40E_GLFCOE_RCTL_FCOEVER_SHIFT)
+#define I40E_GLFCOE_RCTL_SAVBAD_SHIFT 4
+#define I40E_GLFCOE_RCTL_SAVBAD_MASK (0x1 << I40E_GLFCOE_RCTL_SAVBAD_SHIFT)
+#define I40E_GLFCOE_RCTL_ICRC_SHIFT 5
+#define I40E_GLFCOE_RCTL_ICRC_MASK (0x1 << I40E_GLFCOE_RCTL_ICRC_SHIFT)
+#define I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT 16
+#define I40E_GLFCOE_RCTL_MAX_SIZE_MASK (0x3FFF << I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT)
+#define I40E_GL_FWSTS 0x00083048
+#define I40E_GL_FWSTS_FWS0B_SHIFT 0
+#define I40E_GL_FWSTS_FWS0B_MASK (0xFF << I40E_GL_FWSTS_FWS0B_SHIFT)
+#define I40E_GL_FWSTS_FWRI_SHIFT 9
+#define I40E_GL_FWSTS_FWRI_MASK (0x1 << I40E_GL_FWSTS_FWRI_SHIFT)
+#define I40E_GL_FWSTS_FWS1B_SHIFT 16
+#define I40E_GL_FWSTS_FWS1B_MASK (0xFF << I40E_GL_FWSTS_FWS1B_SHIFT)
+#define I40E_GLGEN_CLKSTAT 0x000B8184
+#define I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT 0
+#define I40E_GLGEN_CLKSTAT_CLKMODE_MASK (0x1 << I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT)
+#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT 4
+#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_MASK (0x3 << I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT)
+#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT 8
+#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT)
+#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT 12
+#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT)
+#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT 16
+#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT)
+#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT 20
+#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_MASK (0x7 << I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT)
+#define I40E_GLGEN_GPIO_CTL(_i) (0x00088100 + ((_i) * 4)) /* _i=0...29 */
+#define I40E_GLGEN_GPIO_CTL_MAX_INDEX 29
+#define I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT 0
+#define I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK (0x3 << I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT 3
+#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_MASK (0x1 << I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT 4
+#define I40E_GLGEN_GPIO_CTL_PIN_DIR_MASK (0x1 << I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT 5
+#define I40E_GLGEN_GPIO_CTL_TRI_CTL_MASK (0x1 << I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT 6
+#define I40E_GLGEN_GPIO_CTL_OUT_CTL_MASK (0x1 << I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT 7
+#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK (0x7 << I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT 10
+#define I40E_GLGEN_GPIO_CTL_LED_INVRT_MASK (0x1 << I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT 11
+#define I40E_GLGEN_GPIO_CTL_LED_BLINK_MASK (0x1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT 12
+#define I40E_GLGEN_GPIO_CTL_LED_MODE_MASK (0xF << I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT 17
+#define I40E_GLGEN_GPIO_CTL_INT_MODE_MASK (0x3 << I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT 19
+#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_MASK (0x1 << I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT)
+#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT 20
+#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_MASK (0x3F << I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT)
+#define I40E_GLGEN_GPIO_SET 0x00088184
+#define I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT 0
+#define I40E_GLGEN_GPIO_SET_GPIO_INDX_MASK (0x1F << I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT)
+#define I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT 5
+#define I40E_GLGEN_GPIO_SET_SDP_DATA_MASK (0x1 << I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT)
+#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT 6
+#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_MASK (0x1 << I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT)
+#define I40E_GLGEN_GPIO_STAT 0x0008817C
+#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT 0
+#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_MASK (0x3FFFFFFF << I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT)
+#define I40E_GLGEN_GPIO_TRANSIT 0x00088180
+#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT 0
+#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_MASK (0x3FFFFFFF << I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT)
+#define I40E_GLGEN_I2CCMD(_i) (0x000881E0 + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_I2CCMD_MAX_INDEX 3
+#define I40E_GLGEN_I2CCMD_DATA_SHIFT 0
+#define I40E_GLGEN_I2CCMD_DATA_MASK (0xFFFF << I40E_GLGEN_I2CCMD_DATA_SHIFT)
+#define I40E_GLGEN_I2CCMD_REGADD_SHIFT 16
+#define I40E_GLGEN_I2CCMD_REGADD_MASK (0xFF << I40E_GLGEN_I2CCMD_REGADD_SHIFT)
+#define I40E_GLGEN_I2CCMD_PHYADD_SHIFT 24
+#define I40E_GLGEN_I2CCMD_PHYADD_MASK (0x7 << I40E_GLGEN_I2CCMD_PHYADD_SHIFT)
+#define I40E_GLGEN_I2CCMD_OP_SHIFT 27
+#define I40E_GLGEN_I2CCMD_OP_MASK (0x1 << I40E_GLGEN_I2CCMD_OP_SHIFT)
+#define I40E_GLGEN_I2CCMD_RESET_SHIFT 28
+#define I40E_GLGEN_I2CCMD_RESET_MASK (0x1 << I40E_GLGEN_I2CCMD_RESET_SHIFT)
+#define I40E_GLGEN_I2CCMD_R_SHIFT 29
+#define I40E_GLGEN_I2CCMD_R_MASK (0x1 << I40E_GLGEN_I2CCMD_R_SHIFT)
+#define I40E_GLGEN_I2CCMD_E_SHIFT 31
+#define I40E_GLGEN_I2CCMD_E_MASK (0x1 << I40E_GLGEN_I2CCMD_E_SHIFT)
+#define I40E_GLGEN_I2CPARAMS(_i) (0x000881AC + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_I2CPARAMS_MAX_INDEX 3
+#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT 0
+#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_MASK (0x1F << I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT 5
+#define I40E_GLGEN_I2CPARAMS_READ_TIME_MASK (0x7 << I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT 8
+#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_CLK_SHIFT 9
+#define I40E_GLGEN_I2CPARAMS_CLK_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT 10
+#define I40E_GLGEN_I2CPARAMS_DATA_OUT_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT 11
+#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT 12
+#define I40E_GLGEN_I2CPARAMS_DATA_IN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT 13
+#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT 14
+#define I40E_GLGEN_I2CPARAMS_CLK_IN_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT 15
+#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_MASK (0x1 << I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT)
+#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT 31
+#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_MASK (0x1 << I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT)
+#define I40E_GLGEN_LED_CTL 0x00088178
+#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT 0
+#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_MASK (0x1 << I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT)
+#define I40E_GLGEN_MDIO_CTRL(_i) (0x000881D0 + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_MDIO_CTRL_MAX_INDEX 3
+#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT 0
+#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_MASK (0x1FFFF << I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT)
+#define I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT 17
+#define I40E_GLGEN_MDIO_CTRL_CONTMDC_MASK (0x1 << I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT)
+#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT 18
+#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_MASK (0x3FFF << I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL(_i) (0x000881C0 + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_MDIO_I2C_SEL_MAX_INDEX 3
+#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT 0
+#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK (0x1 << I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT 1
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK (0xF << I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT 5
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT 10
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT 15
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT 20
+#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_MASK (0x1F << I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT 25
+#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_MASK (0xF << I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT)
+#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT 31
+#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_MASK (0x1 << I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT)
+#define I40E_GLGEN_MSCA(_i) (0x0008818C + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_MSCA_MAX_INDEX 3
+#define I40E_GLGEN_MSCA_MDIADD_SHIFT 0
+#define I40E_GLGEN_MSCA_MDIADD_MASK (0xFFFF << I40E_GLGEN_MSCA_MDIADD_SHIFT)
+#define I40E_GLGEN_MSCA_DEVADD_SHIFT 16
+#define I40E_GLGEN_MSCA_DEVADD_MASK (0x1F << I40E_GLGEN_MSCA_DEVADD_SHIFT)
+#define I40E_GLGEN_MSCA_PHYADD_SHIFT 21
+#define I40E_GLGEN_MSCA_PHYADD_MASK (0x1F << I40E_GLGEN_MSCA_PHYADD_SHIFT)
+#define I40E_GLGEN_MSCA_OPCODE_SHIFT 26
+#define I40E_GLGEN_MSCA_OPCODE_MASK (0x3 << I40E_GLGEN_MSCA_OPCODE_SHIFT)
+#define I40E_GLGEN_MSCA_STCODE_SHIFT 28
+#define I40E_GLGEN_MSCA_STCODE_MASK (0x3 << I40E_GLGEN_MSCA_STCODE_SHIFT)
+#define I40E_GLGEN_MSCA_MDICMD_SHIFT 30
+#define I40E_GLGEN_MSCA_MDICMD_MASK (0x1 << I40E_GLGEN_MSCA_MDICMD_SHIFT)
+#define I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT 31
+#define I40E_GLGEN_MSCA_MDIINPROGEN_MASK (0x1 << I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT)
+#define I40E_GLGEN_MSRWD(_i) (0x0008819C + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_MSRWD_MAX_INDEX 3
+#define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0
+#define I40E_GLGEN_MSRWD_MDIWRDATA_MASK (0xFFFF << I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT)
+#define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16
+#define I40E_GLGEN_MSRWD_MDIRDDATA_MASK (0xFFFF << I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0
+#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK (0x1F << I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT)
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16
+#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK (0xFF << I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT)
+#define I40E_GLGEN_PE_ENA 0x000B81A0
+#define I40E_GLGEN_PE_ENA_PE_ENA_SHIFT 0
+#define I40E_GLGEN_PE_ENA_PE_ENA_MASK (0x1 << I40E_GLGEN_PE_ENA_PE_ENA_SHIFT)
+#define I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_SHIFT 1
+#define I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_MASK (0x3 << I40E_GLGEN_PE_ENA_PE_CLK_SRC_SEL_SHIFT)
+#define I40E_GLGEN_RSTAT 0x000B8188
+#define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0
+#define I40E_GLGEN_RSTAT_DEVSTATE_MASK (0x3 << I40E_GLGEN_RSTAT_DEVSTATE_SHIFT)
+#define I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT 2
+#define I40E_GLGEN_RSTAT_RESET_TYPE_MASK (0x3 << I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT)
+#define I40E_GLGEN_RSTAT_CORERCNT_SHIFT 4
+#define I40E_GLGEN_RSTAT_CORERCNT_MASK (0x3 << I40E_GLGEN_RSTAT_CORERCNT_SHIFT)
+#define I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT 6
+#define I40E_GLGEN_RSTAT_GLOBRCNT_MASK (0x3 << I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT)
+#define I40E_GLGEN_RSTAT_EMPRCNT_SHIFT 8
+#define I40E_GLGEN_RSTAT_EMPRCNT_MASK (0x3 << I40E_GLGEN_RSTAT_EMPRCNT_SHIFT)
+#define I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT 10
+#define I40E_GLGEN_RSTAT_TIME_TO_RST_MASK (0x3F << I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT)
+#define I40E_GLGEN_RSTCTL 0x000B8180
+#define I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT 0
+#define I40E_GLGEN_RSTCTL_GRSTDEL_MASK (0x3F << I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT)
+#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT 8
+#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_MASK (0x1 << I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT)
+#define I40E_GLGEN_RSTENA_EMP 0x000B818C
+#define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT 0
+#define I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_MASK (0x1 << I40E_GLGEN_RSTENA_EMP_EMP_RST_ENA_SHIFT)
+#define I40E_GLGEN_RTRIG 0x000B8190
+#define I40E_GLGEN_RTRIG_CORER_SHIFT 0
+#define I40E_GLGEN_RTRIG_CORER_MASK (0x1 << I40E_GLGEN_RTRIG_CORER_SHIFT)
+#define I40E_GLGEN_RTRIG_GLOBR_SHIFT 1
+#define I40E_GLGEN_RTRIG_GLOBR_MASK (0x1 << I40E_GLGEN_RTRIG_GLOBR_SHIFT)
+#define I40E_GLGEN_RTRIG_EMPFWR_SHIFT 2
+#define I40E_GLGEN_RTRIG_EMPFWR_MASK (0x1 << I40E_GLGEN_RTRIG_EMPFWR_SHIFT)
+#define I40E_GLGEN_STAT 0x000B612C
+#define I40E_GLGEN_STAT_HWRSVD0_SHIFT 0
+#define I40E_GLGEN_STAT_HWRSVD0_MASK (0x3 << I40E_GLGEN_STAT_HWRSVD0_SHIFT)
+#define I40E_GLGEN_STAT_DCBEN_SHIFT 2
+#define I40E_GLGEN_STAT_DCBEN_MASK (0x1 << I40E_GLGEN_STAT_DCBEN_SHIFT)
+#define I40E_GLGEN_STAT_VTEN_SHIFT 3
+#define I40E_GLGEN_STAT_VTEN_MASK (0x1 << I40E_GLGEN_STAT_VTEN_SHIFT)
+#define I40E_GLGEN_STAT_FCOEN_SHIFT 4
+#define I40E_GLGEN_STAT_FCOEN_MASK (0x1 << I40E_GLGEN_STAT_FCOEN_SHIFT)
+#define I40E_GLGEN_STAT_EVBEN_SHIFT 5
+#define I40E_GLGEN_STAT_EVBEN_MASK (0x1 << I40E_GLGEN_STAT_EVBEN_SHIFT)
+#define I40E_GLGEN_STAT_HWRSVD1_SHIFT 6
+#define I40E_GLGEN_STAT_HWRSVD1_MASK (0x3 << I40E_GLGEN_STAT_HWRSVD1_SHIFT)
+#define I40E_GLGEN_VFLRSTAT(_i) (0x00092600 + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLGEN_VFLRSTAT_MAX_INDEX 3
+#define I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT 0
+#define I40E_GLGEN_VFLRSTAT_VFLRE_MASK (0xFFFFFFFF << I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT)
+#define I40E_GLVFGEN_TIMER 0x000881BC
+#define I40E_GLVFGEN_TIMER_GTIME_SHIFT 0
+#define I40E_GLVFGEN_TIMER_GTIME_MASK (0xFFFFFFFF << I40E_GLVFGEN_TIMER_GTIME_SHIFT)
+#define I40E_PFGEN_CTRL 0x00092400
+#define I40E_PFGEN_CTRL_PFSWR_SHIFT 0
+#define I40E_PFGEN_CTRL_PFSWR_MASK (0x1 << I40E_PFGEN_CTRL_PFSWR_SHIFT)
+#define I40E_PFGEN_DRUN 0x00092500
+#define I40E_PFGEN_DRUN_DRVUNLD_SHIFT 0
+#define I40E_PFGEN_DRUN_DRVUNLD_MASK (0x1 << I40E_PFGEN_DRUN_DRVUNLD_SHIFT)
+#define I40E_PFGEN_PORTNUM 0x001C0480
+#define I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT 0
+#define I40E_PFGEN_PORTNUM_PORT_NUM_MASK (0x3 << I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT)
+#define I40E_PFGEN_STATE 0x00088000
+#define I40E_PFGEN_STATE_PFPEEN_SHIFT 0
+#define I40E_PFGEN_STATE_PFPEEN_MASK (0x1 << I40E_PFGEN_STATE_PFPEEN_SHIFT)
+#define I40E_PFGEN_STATE_PFFCEN_SHIFT 1
+#define I40E_PFGEN_STATE_PFFCEN_MASK (0x1 << I40E_PFGEN_STATE_PFFCEN_SHIFT)
+#define I40E_PFGEN_STATE_PFLINKEN_SHIFT 2
+#define I40E_PFGEN_STATE_PFLINKEN_MASK (0x1 << I40E_PFGEN_STATE_PFLINKEN_SHIFT)
+#define I40E_PFGEN_STATE_PFSCEN_SHIFT 3
+#define I40E_PFGEN_STATE_PFSCEN_MASK (0x1 << I40E_PFGEN_STATE_PFSCEN_SHIFT)
+#define I40E_PRTGEN_CNF 0x000B8120
+#define I40E_PRTGEN_CNF_PORT_DIS_SHIFT 0
+#define I40E_PRTGEN_CNF_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_PORT_DIS_SHIFT)
+#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT 1
+#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT)
+#define I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT 2
+#define I40E_PRTGEN_CNF_EMP_PORT_DIS_MASK (0x1 << I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT)
+#define I40E_PRTGEN_CNF2 0x000B8160
+#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT 0
+#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_MASK (0x1 << I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT)
+#define I40E_PRTGEN_STATUS 0x000B8100
+#define I40E_PRTGEN_STATUS_PORT_VALID_SHIFT 0
+#define I40E_PRTGEN_STATUS_PORT_VALID_MASK (0x1 << I40E_PRTGEN_STATUS_PORT_VALID_SHIFT)
+#define I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT 1
+#define I40E_PRTGEN_STATUS_PORT_ACTIVE_MASK (0x1 << I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT)
+#define I40E_VFGEN_RSTAT1(_VF) (0x00074400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFGEN_RSTAT1_MAX_INDEX 127
+#define I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT 0
+#define I40E_VFGEN_RSTAT1_VFR_STATE_MASK (0x3 << I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT)
+#define I40E_VPGEN_VFRSTAT(_VF) (0x00091C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPGEN_VFRSTAT_MAX_INDEX 127
+#define I40E_VPGEN_VFRSTAT_VFRD_SHIFT 0
+#define I40E_VPGEN_VFRSTAT_VFRD_MASK (0x1 << I40E_VPGEN_VFRSTAT_VFRD_SHIFT)
+#define I40E_VPGEN_VFRTRIG(_VF) (0x00091800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPGEN_VFRTRIG_MAX_INDEX 127
+#define I40E_VPGEN_VFRTRIG_VFSWR_SHIFT 0
+#define I40E_VPGEN_VFRTRIG_VFSWR_MASK (0x1 << I40E_VPGEN_VFRTRIG_VFSWR_SHIFT)
+#define I40E_VSIGEN_RSTAT(_VSI) (0x00090800 + ((_VSI) * 4)) /* _i=0...383 */
+#define I40E_VSIGEN_RSTAT_MAX_INDEX 383
+#define I40E_VSIGEN_RSTAT_VMRD_SHIFT 0
+#define I40E_VSIGEN_RSTAT_VMRD_MASK (0x1 << I40E_VSIGEN_RSTAT_VMRD_SHIFT)
+#define I40E_VSIGEN_RTRIG(_VSI) (0x00090000 + ((_VSI) * 4)) /* _i=0...383 */
+#define I40E_VSIGEN_RTRIG_MAX_INDEX 383
+#define I40E_VSIGEN_RTRIG_VMSWR_SHIFT 0
+#define I40E_VSIGEN_RTRIG_VMSWR_MASK (0x1 << I40E_VSIGEN_RTRIG_VMSWR_SHIFT)
+#define I40E_GLHMC_APBVTINUSEBASE(_i) (0x000C4a00 + ((_i) * 4))
+#define I40E_GLHMC_APBVTINUSEBASE_MAX_INDEX 15
+#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0
+#define I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_MASK (0xFFFFFF << I40E_GLHMC_APBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT)
+#define I40E_GLHMC_CEQPART(_i) (0x001312C0 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_CEQPART_MAX_INDEX 15
+#define I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT 0
+#define I40E_GLHMC_CEQPART_PMCEQBASE_MASK (0xFF << I40E_GLHMC_CEQPART_PMCEQBASE_SHIFT)
+#define I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT 16
+#define I40E_GLHMC_CEQPART_PMCEQSIZE_MASK (0x1FF << I40E_GLHMC_CEQPART_PMCEQSIZE_SHIFT)
+#define I40E_GLHMC_DBCQPART(_i) (0x00131240 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_DBCQPART_MAX_INDEX 15
+#define I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT 0
+#define I40E_GLHMC_DBCQPART_PMDBCQBASE_MASK (0x3FFF << I40E_GLHMC_DBCQPART_PMDBCQBASE_SHIFT)
+#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT 16
+#define I40E_GLHMC_DBCQPART_PMDBCQSIZE_MASK (0x7FFF << I40E_GLHMC_DBCQPART_PMDBCQSIZE_SHIFT)
+#define I40E_GLHMC_DBQPPART(_i) (0x00138D80 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_DBQPPART_MAX_INDEX 15
+#define I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT 0
+#define I40E_GLHMC_DBQPPART_PMDBQPBASE_MASK (0x3FFF << I40E_GLHMC_DBQPPART_PMDBQPBASE_SHIFT)
+#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT 16
+#define I40E_GLHMC_DBQPPART_PMDBQPSIZE_MASK (0x7FFF << I40E_GLHMC_DBQPPART_PMDBQPSIZE_SHIFT)
+#define I40E_GLHMC_FCOEDDPBASE(_i) (0x000C6600 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FCOEDDPBASE_MAX_INDEX 15
+#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT 0
+#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK (0xFFFFFF << I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT)
+#define I40E_GLHMC_FCOEDDPCNT(_i) (0x000C6700 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FCOEDDPCNT_MAX_INDEX 15
+#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT 0
+#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_MASK (0xFFFFF << I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT)
+#define I40E_GLHMC_FCOEDDPOBJSZ 0x000C2010
+#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT 0
+#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_MASK (0xF << I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT)
+#define I40E_GLHMC_FCOEFBASE(_i) (0x000C6800 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FCOEFBASE_MAX_INDEX 15
+#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT 0
+#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK (0xFFFFFF << I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT)
+#define I40E_GLHMC_FCOEFCNT(_i) (0x000C6900 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FCOEFCNT_MAX_INDEX 15
+#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT 0
+#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_MASK (0x7FFFFF << I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT)
+#define I40E_GLHMC_FCOEFMAX 0x000C20D0
+#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT 0
+#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK (0xFFFF << I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT)
+#define I40E_GLHMC_FCOEFOBJSZ 0x000C2018
+#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT 0
+#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_MASK (0xF << I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT)
+#define I40E_GLHMC_FCOEMAX 0x000C2014
+#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT 0
+#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_MASK (0x1FFF << I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT)
+#define I40E_GLHMC_FSIAVBASE(_i) (0x000C5600 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FSIAVBASE_MAX_INDEX 15
+#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT 0
+#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_MASK (0xFFFFFF << I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT)
+#define I40E_GLHMC_FSIAVCNT(_i) (0x000C5700 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FSIAVCNT_MAX_INDEX 15
+#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT 0
+#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_MASK (0x1FFFFFFF << I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT)
+#define I40E_GLHMC_FSIAVCNT_RSVD_SHIFT 29
+#define I40E_GLHMC_FSIAVCNT_RSVD_MASK (0x7 << I40E_GLHMC_FSIAVCNT_RSVD_SHIFT)
+#define I40E_GLHMC_FSIAVMAX 0x000C2068
+#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT 0
+#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_MASK (0x1FFFF << I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT)
+#define I40E_GLHMC_FSIAVOBJSZ 0x000C2064
+#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT 0
+#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_MASK (0xF << I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT)
+#define I40E_GLHMC_FSIMCBASE(_i) (0x000C6000 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FSIMCBASE_MAX_INDEX 15
+#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT 0
+#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_MASK (0xFFFFFF << I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT)
+#define I40E_GLHMC_FSIMCCNT(_i) (0x000C6100 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_FSIMCCNT_MAX_INDEX 15
+#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT 0
+#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_MASK (0x1FFFFFFF << I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT)
+#define I40E_GLHMC_FSIMCMAX 0x000C2060
+#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT 0
+#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_MASK (0x3FFF << I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT)
+#define I40E_GLHMC_FSIMCOBJSZ 0x000C205c
+#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT 0
+#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_MASK (0xF << I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT)
+#define I40E_GLHMC_LANQMAX 0x000C2008
+#define I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT 0
+#define I40E_GLHMC_LANQMAX_PMLANQMAX_MASK (0x7FF << I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT)
+#define I40E_GLHMC_LANRXBASE(_i) (0x000C6400 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_LANRXBASE_MAX_INDEX 15
+#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT 0
+#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK (0xFFFFFF << I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT)
+#define I40E_GLHMC_LANRXCNT(_i) (0x000C6500 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_LANRXCNT_MAX_INDEX 15
+#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT 0
+#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_MASK (0x7FF << I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT)
+#define I40E_GLHMC_LANRXOBJSZ 0x000C200c
+#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT 0
+#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_MASK (0xF << I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT)
+#define I40E_GLHMC_LANTXBASE(_i) (0x000C6200 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_LANTXBASE_MAX_INDEX 15
+#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT 0
+#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK (0xFFFFFF << I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT)
+#define I40E_GLHMC_LANTXBASE_RSVD_SHIFT 24
+#define I40E_GLHMC_LANTXBASE_RSVD_MASK (0xFF << I40E_GLHMC_LANTXBASE_RSVD_SHIFT)
+#define I40E_GLHMC_LANTXCNT(_i) (0x000C6300 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_LANTXCNT_MAX_INDEX 15
+#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT 0
+#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_MASK (0x7FF << I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT)
+#define I40E_GLHMC_LANTXOBJSZ 0x000C2004
+#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT 0
+#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_MASK (0xF << I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT)
+#define I40E_GLHMC_PEARPBASE(_i) (0x000C4800 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEARPBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT 0
+#define I40E_GLHMC_PEARPBASE_FPMPEARPBASE_MASK (0xFFFFFF << I40E_GLHMC_PEARPBASE_FPMPEARPBASE_SHIFT)
+#define I40E_GLHMC_PEARPCNT(_i) (0x000C4900 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEARPCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT 0
+#define I40E_GLHMC_PEARPCNT_FPMPEARPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEARPCNT_FPMPEARPCNT_SHIFT)
+#define I40E_GLHMC_PEARPMAX 0x000C2038
+#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT 0
+#define I40E_GLHMC_PEARPMAX_PMPEARPMAX_MASK (0x1FFFF << I40E_GLHMC_PEARPMAX_PMPEARPMAX_SHIFT)
+#define I40E_GLHMC_PEARPOBJSZ 0x000C2034
+#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT 0
+#define I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_MASK (0x7 << I40E_GLHMC_PEARPOBJSZ_PMPEARPOBJSZ_SHIFT)
+#define I40E_GLHMC_PECQBASE(_i) (0x000C4200 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PECQBASE_MAX_INDEX 15
+#define I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT 0
+#define I40E_GLHMC_PECQBASE_FPMPECQBASE_MASK (0xFFFFFF << I40E_GLHMC_PECQBASE_FPMPECQBASE_SHIFT)
+#define I40E_GLHMC_PECQCNT(_i) (0x000C4300 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PECQCNT_MAX_INDEX 15
+#define I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT 0
+#define I40E_GLHMC_PECQCNT_FPMPECQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PECQCNT_FPMPECQCNT_SHIFT)
+#define I40E_GLHMC_PECQOBJSZ 0x000C2020
+#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT 0
+#define I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_MASK (0xF << I40E_GLHMC_PECQOBJSZ_PMPECQOBJSZ_SHIFT)
+#define I40E_GLHMC_PEHTCNT(_i) (0x000C4700 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEHTCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT 0
+#define I40E_GLHMC_PEHTCNT_FPMPEHTCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEHTCNT_FPMPEHTCNT_SHIFT)
+#define I40E_GLHMC_PEHTEBASE(_i) (0x000C4600 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEHTEBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT 0
+#define I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_MASK (0xFFFFFF << I40E_GLHMC_PEHTEBASE_FPMPEHTEBASE_SHIFT)
+#define I40E_GLHMC_PEHTEOBJSZ 0x000C202c
+#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT 0
+#define I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_MASK (0xF << I40E_GLHMC_PEHTEOBJSZ_PMPEHTEOBJSZ_SHIFT)
+#define I40E_GLHMC_PEHTMAX 0x000C2030
+#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT 0
+#define I40E_GLHMC_PEHTMAX_PMPEHTMAX_MASK (0x1FFFFF << I40E_GLHMC_PEHTMAX_PMPEHTMAX_SHIFT)
+#define I40E_GLHMC_PEMRBASE(_i) (0x000C4c00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEMRBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT 0
+#define I40E_GLHMC_PEMRBASE_FPMPEMRBASE_MASK (0xFFFFFF << I40E_GLHMC_PEMRBASE_FPMPEMRBASE_SHIFT)
+#define I40E_GLHMC_PEMRCNT(_i) (0x000C4d00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEMRCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT 0
+#define I40E_GLHMC_PEMRCNT_FPMPEMRSZ_MASK (0x1FFFFFFF << I40E_GLHMC_PEMRCNT_FPMPEMRSZ_SHIFT)
+#define I40E_GLHMC_PEMRMAX 0x000C2040
+#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT 0
+#define I40E_GLHMC_PEMRMAX_PMPEMRMAX_MASK (0x7FFFFF << I40E_GLHMC_PEMRMAX_PMPEMRMAX_SHIFT)
+#define I40E_GLHMC_PEMROBJSZ 0x000C203c
+#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT 0
+#define I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_MASK (0xF << I40E_GLHMC_PEMROBJSZ_PMPEMROBJSZ_SHIFT)
+#define I40E_GLHMC_PEPBLBASE(_i) (0x000C5800 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEPBLBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT 0
+#define I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEPBLBASE_FPMPEPBLBASE_SHIFT)
+#define I40E_GLHMC_PEPBLCNT(_i) (0x000C5900 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEPBLCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT 0
+#define I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEPBLCNT_FPMPEPBLCNT_SHIFT)
+#define I40E_GLHMC_PEPBLMAX 0x000C206c
+#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT 0
+#define I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_MASK (0x1FFFFFFF << I40E_GLHMC_PEPBLMAX_PMPEPBLMAX_SHIFT)
+#define I40E_GLHMC_PEQ1BASE(_i) (0x000C5200 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEQ1BASE_MAX_INDEX 15
+#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT 0
+#define I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_MASK (0xFFFFFF << I40E_GLHMC_PEQ1BASE_FPMPEQ1BASE_SHIFT)
+#define I40E_GLHMC_PEQ1CNT(_i) (0x000C5300 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEQ1CNT_MAX_INDEX 15
+#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT 0
+#define I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1CNT_FPMPEQ1CNT_SHIFT)
+#define I40E_GLHMC_PEQ1FLBASE(_i) (0x000C5400 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEQ1FLBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0
+#define I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEQ1FLBASE_FPMPEQ1FLBASE_SHIFT)
+#define I40E_GLHMC_PEQ1FLCNT(_i) (0x000C5500 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEQ1FLCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT 0
+#define I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQ1FLCNT_FPMPEQ1FLCNT_SHIFT)
+#define I40E_GLHMC_PEQ1FLMAX 0x000C2058
+#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT 0
+#define I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_MASK (0x3FFFFF << I40E_GLHMC_PEQ1FLMAX_PMPEQ1FLMAX_SHIFT)
+#define I40E_GLHMC_PEQ1MAX 0x000C2054
+#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT 0
+#define I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_MASK (0x3FFFFFF << I40E_GLHMC_PEQ1MAX_PMPEQ1MAX_SHIFT)
+#define I40E_GLHMC_PEQ1OBJSZ 0x000C2050
+#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT 0
+#define I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_MASK (0xF << I40E_GLHMC_PEQ1OBJSZ_PMPEQ1OBJSZ_SHIFT)
+#define I40E_GLHMC_PEQPBASE(_i) (0x000C4000 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEQPBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT 0
+#define I40E_GLHMC_PEQPBASE_FPMPEQPBASE_MASK (0xFFFFFF << I40E_GLHMC_PEQPBASE_FPMPEQPBASE_SHIFT)
+#define I40E_GLHMC_PEQPCNT(_i) (0x000C4100 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEQPCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT 0
+#define I40E_GLHMC_PEQPCNT_FPMPEQPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEQPCNT_FPMPEQPCNT_SHIFT)
+#define I40E_GLHMC_PEQPOBJSZ 0x000C201c
+#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT 0
+#define I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_MASK (0xF << I40E_GLHMC_PEQPOBJSZ_PMPEQPOBJSZ_SHIFT)
+#define I40E_GLHMC_PESRQBASE(_i) (0x000C4400 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PESRQBASE_MAX_INDEX 15
+#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT 0
+#define I40E_GLHMC_PESRQBASE_FPMPESRQBASE_MASK (0xFFFFFF << I40E_GLHMC_PESRQBASE_FPMPESRQBASE_SHIFT)
+#define I40E_GLHMC_PESRQCNT(_i) (0x000C4500 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PESRQCNT_MAX_INDEX 15
+#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT 0
+#define I40E_GLHMC_PESRQCNT_FPMPESRQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PESRQCNT_FPMPESRQCNT_SHIFT)
+#define I40E_GLHMC_PESRQMAX 0x000C2028
+#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT 0
+#define I40E_GLHMC_PESRQMAX_PMPESRQMAX_MASK (0xFFFF << I40E_GLHMC_PESRQMAX_PMPESRQMAX_SHIFT)
+#define I40E_GLHMC_PESRQOBJSZ 0x000C2024
+#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT 0
+#define I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_MASK (0xF << I40E_GLHMC_PESRQOBJSZ_PMPESRQOBJSZ_SHIFT)
+#define I40E_GLHMC_PESRQOBJSZ_RSVD_SHIFT 4
+#define I40E_GLHMC_PESRQOBJSZ_RSVD_MASK (0xFFFFFFF << I40E_GLHMC_PESRQOBJSZ_RSVD_SHIFT)
+#define I40E_GLHMC_PETIMERBASE(_i) (0x000C5A00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PETIMERBASE_MAX_INDEX 15
+#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT 0
+#define I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_MASK (0xFFFFFF << I40E_GLHMC_PETIMERBASE_FPMPETIMERBASE_SHIFT)
+#define I40E_GLHMC_PETIMERCNT(_i) (0x000C5B00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PETIMERCNT_MAX_INDEX 15
+#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT 0
+#define I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PETIMERCNT_FPMPETIMERCNT_SHIFT)
+#define I40E_GLHMC_PETIMERMAX 0x000C2084
+#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT 0
+#define I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_MASK (0x1FFFFFFF << I40E_GLHMC_PETIMERMAX_PMPETIMERMAX_SHIFT)
+#define I40E_GLHMC_PETIMEROBJSZ 0x000C2080
+#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT 0
+#define I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_MASK (0xF << I40E_GLHMC_PETIMEROBJSZ_PMPETIMEROBJSZ_SHIFT)
+#define I40E_GLHMC_PEXFBASE(_i) (0x000C4e00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEXFBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT 0
+#define I40E_GLHMC_PEXFBASE_FPMPEXFBASE_MASK (0xFFFFFF << I40E_GLHMC_PEXFBASE_FPMPEXFBASE_SHIFT)
+#define I40E_GLHMC_PEXFCNT(_i) (0x000C4f00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEXFCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT 0
+#define I40E_GLHMC_PEXFCNT_FPMPEXFCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFCNT_FPMPEXFCNT_SHIFT)
+#define I40E_GLHMC_PEXFFLBASE(_i) (0x000C5000 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEXFFLBASE_MAX_INDEX 15
+#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT 0
+#define I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_MASK (0xFFFFFF << I40E_GLHMC_PEXFFLBASE_FPMPEXFFLBASE_SHIFT)
+#define I40E_GLHMC_PEXFFLCNT(_i) (0x000C5100 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PEXFFLCNT_MAX_INDEX 15
+#define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT 0
+#define I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_PEXFFLCNT_FPMPEXFFLCNT_SHIFT)
+#define I40E_GLHMC_PEXFFLMAX 0x000C204c
+#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT 0
+#define I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_MASK (0x3FFFFF << I40E_GLHMC_PEXFFLMAX_PMPEXFFLMAX_SHIFT)
+#define I40E_GLHMC_PEXFMAX 0x000C2048
+#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT 0
+#define I40E_GLHMC_PEXFMAX_PMPEXFMAX_MASK (0x3FFFFFF << I40E_GLHMC_PEXFMAX_PMPEXFMAX_SHIFT)
+#define I40E_GLHMC_PEXFOBJSZ 0x000C2044
+#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT 0
+#define I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_MASK (0xF << I40E_GLHMC_PEXFOBJSZ_PMPEXFOBJSZ_SHIFT)
+#define I40E_GLHMC_PEXFOBJSZ_RSVD_SHIFT 4
+#define I40E_GLHMC_PEXFOBJSZ_RSVD_MASK (0xFFFFFFF << I40E_GLHMC_PEXFOBJSZ_RSVD_SHIFT)
+#define I40E_GLHMC_PFASSIGN(_i) (0x000C0c00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_PFASSIGN_MAX_INDEX 15
+#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT 0
+#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_MASK (0xF << I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT)
+#define I40E_GLHMC_SDPART(_i) (0x000C0800 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLHMC_SDPART_MAX_INDEX 15
+#define I40E_GLHMC_SDPART_PMSDBASE_SHIFT 0
+#define I40E_GLHMC_SDPART_PMSDBASE_MASK (0xFFF << I40E_GLHMC_SDPART_PMSDBASE_SHIFT)
+#define I40E_GLHMC_SDPART_PMSDSIZE_SHIFT 16
+#define I40E_GLHMC_SDPART_PMSDSIZE_MASK (0x1FFF << I40E_GLHMC_SDPART_PMSDSIZE_SHIFT)
+#define I40E_GLHMC_VFAPBVTINUSEBASE(_i) (0x000Cca00 + ((_i) * 4))
+#define I40E_GLHMC_VFAPBVTINUSEBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT 0
+#define I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_MASK (0xFFFFFF << I40E_GLHMC_VFAPBVTINUSEBASE_FPMAPBINUSEBASE_SHIFT)
+#define I40E_GLHMC_VFCEQPART(_i) (0x00132240 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFCEQPART_MAX_INDEX 31
+#define I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT 0
+#define I40E_GLHMC_VFCEQPART_PMCEQBASE_MASK (0xFF << I40E_GLHMC_VFCEQPART_PMCEQBASE_SHIFT)
+#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT 16
+#define I40E_GLHMC_VFCEQPART_PMCEQSIZE_MASK (0x1FF << I40E_GLHMC_VFCEQPART_PMCEQSIZE_SHIFT)
+#define I40E_GLHMC_VFDBCQPART(_i) (0x00132140 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFDBCQPART_MAX_INDEX 31
+#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT 0
+#define I40E_GLHMC_VFDBCQPART_PMDBCQBASE_MASK (0x3FFF << I40E_GLHMC_VFDBCQPART_PMDBCQBASE_SHIFT)
+#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT 16
+#define I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_MASK (0x7FFF << I40E_GLHMC_VFDBCQPART_PMDBCQSIZE_SHIFT)
+#define I40E_GLHMC_VFDBQPPART(_i) (0x00138E00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFDBQPPART_MAX_INDEX 31
+#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT 0
+#define I40E_GLHMC_VFDBQPPART_PMDBQPBASE_MASK (0x3FFF << I40E_GLHMC_VFDBQPPART_PMDBQPBASE_SHIFT)
+#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT 16
+#define I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_MASK (0x7FFF << I40E_GLHMC_VFDBQPPART_PMDBQPSIZE_SHIFT)
+#define I40E_GLHMC_VFFSIAVBASE(_i) (0x000Cd600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFFSIAVBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT 0
+#define I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_MASK (0xFFFFFF << I40E_GLHMC_VFFSIAVBASE_FPMFSIAVBASE_SHIFT)
+#define I40E_GLHMC_VFFSIAVCNT(_i) (0x000Cd700 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFFSIAVCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT 0
+#define I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFFSIAVCNT_FPMFSIAVCNT_SHIFT)
+#define I40E_GLHMC_VFFSIAVCNT_RSVD_SHIFT 29
+#define I40E_GLHMC_VFFSIAVCNT_RSVD_MASK (0x7 << I40E_GLHMC_VFFSIAVCNT_RSVD_SHIFT)
+#define I40E_GLHMC_VFPDINV(_i) (0x000C8300 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPDINV_MAX_INDEX 31
+#define I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT 0
+#define I40E_GLHMC_VFPDINV_PMSDIDX_MASK (0xFFF << I40E_GLHMC_VFPDINV_PMSDIDX_SHIFT)
+#define I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT 16
+#define I40E_GLHMC_VFPDINV_PMPDIDX_MASK (0x1FF << I40E_GLHMC_VFPDINV_PMPDIDX_SHIFT)
+#define I40E_GLHMC_VFPEARPBASE(_i) (0x000Cc800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEARPBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT 0
+#define I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEARPBASE_FPMPEARPBASE_SHIFT)
+#define I40E_GLHMC_VFPEARPCNT(_i) (0x000Cc900 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEARPCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT 0
+#define I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEARPCNT_FPMPEARPCNT_SHIFT)
+#define I40E_GLHMC_VFPECQBASE(_i) (0x000Cc200 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPECQBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT 0
+#define I40E_GLHMC_VFPECQBASE_FPMPECQBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPECQBASE_FPMPECQBASE_SHIFT)
+#define I40E_GLHMC_VFPECQCNT(_i) (0x000Cc300 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPECQCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT 0
+#define I40E_GLHMC_VFPECQCNT_FPMPECQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPECQCNT_FPMPECQCNT_SHIFT)
+#define I40E_GLHMC_VFPEHTCNT(_i) (0x000Cc700 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEHTCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT 0
+#define I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEHTCNT_FPMPEHTCNT_SHIFT)
+#define I40E_GLHMC_VFPEHTEBASE(_i) (0x000Cc600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEHTEBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT 0
+#define I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEHTEBASE_FPMPEHTEBASE_SHIFT)
+#define I40E_GLHMC_VFPEMRBASE(_i) (0x000Ccc00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEMRBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT 0
+#define I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEMRBASE_FPMPEMRBASE_SHIFT)
+#define I40E_GLHMC_VFPEMRCNT(_i) (0x000Ccd00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEMRCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT 0
+#define I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEMRCNT_FPMPEMRSZ_SHIFT)
+#define I40E_GLHMC_VFPEPBLBASE(_i) (0x000Cd800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEPBLBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT 0
+#define I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEPBLBASE_FPMPEPBLBASE_SHIFT)
+#define I40E_GLHMC_VFPEPBLCNT(_i) (0x000Cd900 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEPBLCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT 0
+#define I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEPBLCNT_FPMPEPBLCNT_SHIFT)
+#define I40E_GLHMC_VFPEQ1BASE(_i) (0x000Cd200 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEQ1BASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT 0
+#define I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQ1BASE_FPMPEQ1BASE_SHIFT)
+#define I40E_GLHMC_VFPEQ1CNT(_i) (0x000Cd300 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEQ1CNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT 0
+#define I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQ1CNT_FPMPEQ1CNT_SHIFT)
+#define I40E_GLHMC_VFPEQ1FLBASE(_i) (0x000Cd400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEQ1FLBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT 0
+#define I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQ1FLBASE_FPMPEQ1FLBASE_SHIFT)
+#define I40E_GLHMC_VFPEQ1FLCNT(_i) (0x000Cd500 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEQ1FLCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_SHIFT 0
+#define I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQ1FLCNT_FPMPEQ1FLCNT_SHIFT)
+#define I40E_GLHMC_VFPEQPBASE(_i) (0x000Cc000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEQPBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT 0
+#define I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEQPBASE_FPMPEQPBASE_SHIFT)
+#define I40E_GLHMC_VFPEQPCNT(_i) (0x000Cc100 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEQPCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT 0
+#define I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEQPCNT_FPMPEQPCNT_SHIFT)
+#define I40E_GLHMC_VFPESRQBASE(_i) (0x000Cc400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPESRQBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT 0
+#define I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPESRQBASE_FPMPESRQBASE_SHIFT)
+#define I40E_GLHMC_VFPESRQCNT(_i) (0x000Cc500 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPESRQCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT 0
+#define I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPESRQCNT_FPMPESRQCNT_SHIFT)
+#define I40E_GLHMC_VFPETIMERBASE(_i) (0x000CDA00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPETIMERBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT 0
+#define I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPETIMERBASE_FPMPETIMERBASE_SHIFT)
+#define I40E_GLHMC_VFPETIMERCNT(_i) (0x000CDB00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPETIMERCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT 0
+#define I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPETIMERCNT_FPMPETIMERCNT_SHIFT)
+#define I40E_GLHMC_VFPEXFBASE(_i) (0x000Cce00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEXFBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT 0
+#define I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEXFBASE_FPMPEXFBASE_SHIFT)
+#define I40E_GLHMC_VFPEXFCNT(_i) (0x000Ccf00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEXFCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT 0
+#define I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEXFCNT_FPMPEXFCNT_SHIFT)
+#define I40E_GLHMC_VFPEXFFLBASE(_i) (0x000Cd000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEXFFLBASE_MAX_INDEX 31
+#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT 0
+#define I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_MASK (0xFFFFFF << I40E_GLHMC_VFPEXFFLBASE_FPMPEXFFLBASE_SHIFT)
+#define I40E_GLHMC_VFPEXFFLCNT(_i) (0x000Cd100 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFPEXFFLCNT_MAX_INDEX 31
+#define I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_SHIFT 0
+#define I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_MASK (0x1FFFFFFF << I40E_GLHMC_VFPEXFFLCNT_FPMPEXFFLCNT_SHIFT)
+#define I40E_GLHMC_VFSDPART(_i) (0x000C8800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLHMC_VFSDPART_MAX_INDEX 31
+#define I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT 0
+#define I40E_GLHMC_VFSDPART_PMSDBASE_MASK (0xFFF << I40E_GLHMC_VFSDPART_PMSDBASE_SHIFT)
+#define I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT 16
+#define I40E_GLHMC_VFSDPART_PMSDSIZE_MASK (0x1FFF << I40E_GLHMC_VFSDPART_PMSDSIZE_SHIFT)
+#define I40E_PFHMC_ERRORDATA 0x000C0500
+#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT 0
+#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_MASK (0x3FFFFFFF << I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT)
+#define I40E_PFHMC_ERRORINFO 0x000C0400
+#define I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT 0
+#define I40E_PFHMC_ERRORINFO_PMF_INDEX_MASK (0x1F << I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT)
+#define I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT 7
+#define I40E_PFHMC_ERRORINFO_PMF_ISVF_MASK (0x1 << I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT)
+#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT 8
+#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_MASK (0xF << I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT)
+#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT 16
+#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_MASK (0x1F << I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT)
+#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT 31
+#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK (0x1 << I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT)
+#define I40E_PFHMC_PDINV 0x000C0300
+#define I40E_PFHMC_PDINV_PMSDIDX_SHIFT 0
+#define I40E_PFHMC_PDINV_PMSDIDX_MASK (0xFFF << I40E_PFHMC_PDINV_PMSDIDX_SHIFT)
+#define I40E_PFHMC_PDINV_PMPDIDX_SHIFT 16
+#define I40E_PFHMC_PDINV_PMPDIDX_MASK (0x1FF << I40E_PFHMC_PDINV_PMPDIDX_SHIFT)
+#define I40E_PFHMC_SDCMD 0x000C0000
+#define I40E_PFHMC_SDCMD_PMSDIDX_SHIFT 0
+#define I40E_PFHMC_SDCMD_PMSDIDX_MASK (0xFFF << I40E_PFHMC_SDCMD_PMSDIDX_SHIFT)
+#define I40E_PFHMC_SDCMD_PMSDWR_SHIFT 31
+#define I40E_PFHMC_SDCMD_PMSDWR_MASK (0x1 << I40E_PFHMC_SDCMD_PMSDWR_SHIFT)
+#define I40E_PFHMC_SDDATAHIGH 0x000C0200
+#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT 0
+#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_MASK (0xFFFFFFFF << I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT)
+#define I40E_PFHMC_SDDATALOW 0x000C0100
+#define I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT 0
+#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT)
+#define I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT 1
+#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK (0x1 << I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT)
+#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT 2
+#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK (0x3FF << I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT)
+#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT 12
+#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_MASK (0xFFFFF << I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT)
+#define I40E_GL_UFUSE 0x00094008
+#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT 1
+#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_MASK (0x1 << I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT)
+#define I40E_GL_UFUSE_NIC_ID_SHIFT 2
+#define I40E_GL_UFUSE_NIC_ID_MASK (0x1 << I40E_GL_UFUSE_NIC_ID_SHIFT)
+#define I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT 10
+#define I40E_GL_UFUSE_ULT_LOCKOUT_MASK (0x1 << I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT)
+#define I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT 11
+#define I40E_GL_UFUSE_CLS_LOCKOUT_MASK (0x1 << I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT)
+#define I40E_EMPINT_GPIO_ENA 0x00088188
+#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT 0
+#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT 1
+#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT 2
+#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT 3
+#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT 4
+#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT 5
+#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT 6
+#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT 7
+#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT 8
+#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT 9
+#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT 10
+#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT 11
+#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT 12
+#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT 13
+#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT 14
+#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT 15
+#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT 16
+#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT 17
+#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT 18
+#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT 19
+#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT 20
+#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT 21
+#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT 22
+#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT 23
+#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT 24
+#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT 25
+#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT 26
+#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT 27
+#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT 28
+#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT)
+#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT 29
+#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_MASK (0x1 << I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT)
+#define I40E_PFGEN_PORTMDIO_NUM 0x0003F100
+#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT 0
+#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_MASK (0x3 << I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT)
+#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT 4
+#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK (0x1 << I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT)
+#define I40E_PFINT_AEQCTL 0x00038700
+#define I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT 0
+#define I40E_PFINT_AEQCTL_MSIX_INDX_MASK (0xFF << I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT)
+#define I40E_PFINT_AEQCTL_ITR_INDX_SHIFT 11
+#define I40E_PFINT_AEQCTL_ITR_INDX_MASK (0x3 << I40E_PFINT_AEQCTL_ITR_INDX_SHIFT)
+#define I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT 13
+#define I40E_PFINT_AEQCTL_MSIX0_INDX_MASK (0x7 << I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT)
+#define I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT 30
+#define I40E_PFINT_AEQCTL_CAUSE_ENA_MASK (0x1 << I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT)
+#define I40E_PFINT_AEQCTL_INTEVENT_SHIFT 31
+#define I40E_PFINT_AEQCTL_INTEVENT_MASK (0x1 << I40E_PFINT_AEQCTL_INTEVENT_SHIFT)
+#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */
+#define I40E_PFINT_CEQCTL_MAX_INDEX 511
+#define I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT 0
+#define I40E_PFINT_CEQCTL_MSIX_INDX_MASK (0xFF << I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT)
+#define I40E_PFINT_CEQCTL_ITR_INDX_SHIFT 11
+#define I40E_PFINT_CEQCTL_ITR_INDX_MASK (0x3 << I40E_PFINT_CEQCTL_ITR_INDX_SHIFT)
+#define I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT 13
+#define I40E_PFINT_CEQCTL_MSIX0_INDX_MASK (0x7 << I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT)
+#define I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT 16
+#define I40E_PFINT_CEQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT)
+#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT 27
+#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT)
+#define I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT 30
+#define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK (0x1 << I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT)
+#define I40E_PFINT_CEQCTL_INTEVENT_SHIFT 31
+#define I40E_PFINT_CEQCTL_INTEVENT_MASK (0x1 << I40E_PFINT_CEQCTL_INTEVENT_SHIFT)
+#define I40E_PFINT_DYN_CTL0 0x00038480
+#define I40E_PFINT_DYN_CTL0_INTENA_SHIFT 0
+#define I40E_PFINT_DYN_CTL0_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTL0_INTENA_SHIFT)
+#define I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT 1
+#define I40E_PFINT_DYN_CTL0_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT)
+#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2
+#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK (0x1 << I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT)
+#define I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT 3
+#define I40E_PFINT_DYN_CTL0_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT)
+#define I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT 5
+#define I40E_PFINT_DYN_CTL0_INTERVAL_MASK (0xFFF << I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT)
+#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24
+#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK (0x1 << I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT)
+#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25
+#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT)
+#define I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT 31
+#define I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK (0x1 << I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT)
+#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */
+#define I40E_PFINT_DYN_CTLN_MAX_INDEX 511
+#define I40E_PFINT_DYN_CTLN_INTENA_SHIFT 0
+#define I40E_PFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_SHIFT)
+#define I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT 1
+#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT)
+#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2
+#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK (0x1 << I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT)
+#define I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT 3
+#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT)
+#define I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT 5
+#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK (0xFFF << I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT)
+#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24
+#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK (0x1 << I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT)
+#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25
+#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK (0x3 << I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT)
+#define I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT 31
+#define I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK (0x1 << I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT)
+#define I40E_PFINT_GPIO_ENA 0x00088080
+#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT 0
+#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT 1
+#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT 2
+#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT 3
+#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT 4
+#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT 5
+#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT 6
+#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT 7
+#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT 8
+#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT 9
+#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT 10
+#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT 11
+#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT 12
+#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT 13
+#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT 14
+#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT 15
+#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT 16
+#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT 17
+#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT 18
+#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT 19
+#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT 20
+#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT 21
+#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT 22
+#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT 23
+#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT 24
+#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT 25
+#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT 26
+#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT 27
+#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT 28
+#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT)
+#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT 29
+#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_MASK (0x1 << I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT)
+#define I40E_PFINT_ICR0 0x00038780
+#define I40E_PFINT_ICR0_INTEVENT_SHIFT 0
+#define I40E_PFINT_ICR0_INTEVENT_MASK (0x1 << I40E_PFINT_ICR0_INTEVENT_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_0_SHIFT 1
+#define I40E_PFINT_ICR0_QUEUE_0_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_0_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_1_SHIFT 2
+#define I40E_PFINT_ICR0_QUEUE_1_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_1_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_2_SHIFT 3
+#define I40E_PFINT_ICR0_QUEUE_2_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_2_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_3_SHIFT 4
+#define I40E_PFINT_ICR0_QUEUE_3_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_3_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_4_SHIFT 5
+#define I40E_PFINT_ICR0_QUEUE_4_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_4_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_5_SHIFT 6
+#define I40E_PFINT_ICR0_QUEUE_5_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_5_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_6_SHIFT 7
+#define I40E_PFINT_ICR0_QUEUE_6_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_6_SHIFT)
+#define I40E_PFINT_ICR0_QUEUE_7_SHIFT 8
+#define I40E_PFINT_ICR0_QUEUE_7_MASK (0x1 << I40E_PFINT_ICR0_QUEUE_7_SHIFT)
+#define I40E_PFINT_ICR0_ECC_ERR_SHIFT 16
+#define I40E_PFINT_ICR0_ECC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ECC_ERR_SHIFT)
+#define I40E_PFINT_ICR0_MAL_DETECT_SHIFT 19
+#define I40E_PFINT_ICR0_MAL_DETECT_MASK (0x1 << I40E_PFINT_ICR0_MAL_DETECT_SHIFT)
+#define I40E_PFINT_ICR0_GRST_SHIFT 20
+#define I40E_PFINT_ICR0_GRST_MASK (0x1 << I40E_PFINT_ICR0_GRST_SHIFT)
+#define I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT 21
+#define I40E_PFINT_ICR0_PCI_EXCEPTION_MASK (0x1 << I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT)
+#define I40E_PFINT_ICR0_GPIO_SHIFT 22
+#define I40E_PFINT_ICR0_GPIO_MASK (0x1 << I40E_PFINT_ICR0_GPIO_SHIFT)
+#define I40E_PFINT_ICR0_TIMESYNC_SHIFT 23
+#define I40E_PFINT_ICR0_TIMESYNC_MASK (0x1 << I40E_PFINT_ICR0_TIMESYNC_SHIFT)
+#define I40E_PFINT_ICR0_STORM_DETECT_SHIFT 24
+#define I40E_PFINT_ICR0_STORM_DETECT_MASK (0x1 << I40E_PFINT_ICR0_STORM_DETECT_SHIFT)
+#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25
+#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK (0x1 << I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT)
+#define I40E_PFINT_ICR0_HMC_ERR_SHIFT 26
+#define I40E_PFINT_ICR0_HMC_ERR_MASK (0x1 << I40E_PFINT_ICR0_HMC_ERR_SHIFT)
+#define I40E_PFINT_ICR0_PE_CRITERR_SHIFT 28
+#define I40E_PFINT_ICR0_PE_CRITERR_MASK (0x1 << I40E_PFINT_ICR0_PE_CRITERR_SHIFT)
+#define I40E_PFINT_ICR0_VFLR_SHIFT 29
+#define I40E_PFINT_ICR0_VFLR_MASK (0x1 << I40E_PFINT_ICR0_VFLR_SHIFT)
+#define I40E_PFINT_ICR0_ADMINQ_SHIFT 30
+#define I40E_PFINT_ICR0_ADMINQ_MASK (0x1 << I40E_PFINT_ICR0_ADMINQ_SHIFT)
+#define I40E_PFINT_ICR0_SWINT_SHIFT 31
+#define I40E_PFINT_ICR0_SWINT_MASK (0x1 << I40E_PFINT_ICR0_SWINT_SHIFT)
+#define I40E_PFINT_ICR0_ENA 0x00038800
+#define I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT 16
+#define I40E_PFINT_ICR0_ENA_ECC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT)
+#define I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT 19
+#define I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK (0x1 << I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT)
+#define I40E_PFINT_ICR0_ENA_GRST_SHIFT 20
+#define I40E_PFINT_ICR0_ENA_GRST_MASK (0x1 << I40E_PFINT_ICR0_ENA_GRST_SHIFT)
+#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT 21
+#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK (0x1 << I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT)
+#define I40E_PFINT_ICR0_ENA_GPIO_SHIFT 22
+#define I40E_PFINT_ICR0_ENA_GPIO_MASK (0x1 << I40E_PFINT_ICR0_ENA_GPIO_SHIFT)
+#define I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT 23
+#define I40E_PFINT_ICR0_ENA_TIMESYNC_MASK (0x1 << I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT)
+#define I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT 24
+#define I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK (0x1 << I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT)
+#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25
+#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK (0x1 << I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT)
+#define I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT 26
+#define I40E_PFINT_ICR0_ENA_HMC_ERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT)
+#define I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT 28
+#define I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK (0x1 << I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT)
+#define I40E_PFINT_ICR0_ENA_VFLR_SHIFT 29
+#define I40E_PFINT_ICR0_ENA_VFLR_MASK (0x1 << I40E_PFINT_ICR0_ENA_VFLR_SHIFT)
+#define I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT 30
+#define I40E_PFINT_ICR0_ENA_ADMINQ_MASK (0x1 << I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT)
+#define I40E_PFINT_ICR0_ENA_RSVD_SHIFT 31
+#define I40E_PFINT_ICR0_ENA_RSVD_MASK (0x1 << I40E_PFINT_ICR0_ENA_RSVD_SHIFT)
+#define I40E_PFINT_ITR0(_i) (0x00038000 + ((_i) * 128)) /* _i=0...2 */
+#define I40E_PFINT_ITR0_MAX_INDEX 2
+#define I40E_PFINT_ITR0_INTERVAL_SHIFT 0
+#define I40E_PFINT_ITR0_INTERVAL_MASK (0xFFF << I40E_PFINT_ITR0_INTERVAL_SHIFT)
+#define I40E_PFINT_ITRN(_i, _INTPF) (0x00030000 + ((_i) * 2048 + (_INTPF) * 4))
+#define I40E_PFINT_ITRN_MAX_INDEX 2
+#define I40E_PFINT_ITRN_INTERVAL_SHIFT 0
+#define I40E_PFINT_ITRN_INTERVAL_MASK (0xFFF << I40E_PFINT_ITRN_INTERVAL_SHIFT)
+#define I40E_PFINT_LNKLST0 0x00038500
+#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT 0
+#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK (0x7FF << I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT)
+#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11
+#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_MASK (0x3 << I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT)
+#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */
+#define I40E_PFINT_LNKLSTN_MAX_INDEX 511
+#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0
+#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK (0x7FF << I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT)
+#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11
+#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK (0x3 << I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT)
+#define I40E_PFINT_RATE0 0x00038580
+#define I40E_PFINT_RATE0_INTERVAL_SHIFT 0
+#define I40E_PFINT_RATE0_INTERVAL_MASK (0x3F << I40E_PFINT_RATE0_INTERVAL_SHIFT)
+#define I40E_PFINT_RATE0_INTRL_ENA_SHIFT 6
+#define I40E_PFINT_RATE0_INTRL_ENA_MASK (0x1 << I40E_PFINT_RATE0_INTRL_ENA_SHIFT)
+#define I40E_PFINT_RATEN(_INTPF) (0x00035800 + ((_INTPF) * 4)) /* _i=0...511 */
+#define I40E_PFINT_RATEN_MAX_INDEX 511
+#define I40E_PFINT_RATEN_INTERVAL_SHIFT 0
+#define I40E_PFINT_RATEN_INTERVAL_MASK (0x3F << I40E_PFINT_RATEN_INTERVAL_SHIFT)
+#define I40E_PFINT_RATEN_INTRL_ENA_SHIFT 6
+#define I40E_PFINT_RATEN_INTRL_ENA_MASK (0x1 << I40E_PFINT_RATEN_INTRL_ENA_SHIFT)
+#define I40E_PFINT_STAT_CTL0 0x00038400
+#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2
+#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK (0x3 << I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT)
+#define I40E_QINT_RQCTL(_Q) (0x0003A000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QINT_RQCTL_MAX_INDEX 1535
+#define I40E_QINT_RQCTL_MSIX_INDX_SHIFT 0
+#define I40E_QINT_RQCTL_MSIX_INDX_MASK (0xFF << I40E_QINT_RQCTL_MSIX_INDX_SHIFT)
+#define I40E_QINT_RQCTL_ITR_INDX_SHIFT 11
+#define I40E_QINT_RQCTL_ITR_INDX_MASK (0x3 << I40E_QINT_RQCTL_ITR_INDX_SHIFT)
+#define I40E_QINT_RQCTL_MSIX0_INDX_SHIFT 13
+#define I40E_QINT_RQCTL_MSIX0_INDX_MASK (0x7 << I40E_QINT_RQCTL_MSIX0_INDX_SHIFT)
+#define I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT 16
+#define I40E_QINT_RQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT)
+#define I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT 27
+#define I40E_QINT_RQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT)
+#define I40E_QINT_RQCTL_CAUSE_ENA_SHIFT 30
+#define I40E_QINT_RQCTL_CAUSE_ENA_MASK (0x1 << I40E_QINT_RQCTL_CAUSE_ENA_SHIFT)
+#define I40E_QINT_RQCTL_INTEVENT_SHIFT 31
+#define I40E_QINT_RQCTL_INTEVENT_MASK (0x1 << I40E_QINT_RQCTL_INTEVENT_SHIFT)
+#define I40E_QINT_TQCTL(_Q) (0x0003C000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QINT_TQCTL_MAX_INDEX 1535
+#define I40E_QINT_TQCTL_MSIX_INDX_SHIFT 0
+#define I40E_QINT_TQCTL_MSIX_INDX_MASK (0xFF << I40E_QINT_TQCTL_MSIX_INDX_SHIFT)
+#define I40E_QINT_TQCTL_ITR_INDX_SHIFT 11
+#define I40E_QINT_TQCTL_ITR_INDX_MASK (0x3 << I40E_QINT_TQCTL_ITR_INDX_SHIFT)
+#define I40E_QINT_TQCTL_MSIX0_INDX_SHIFT 13
+#define I40E_QINT_TQCTL_MSIX0_INDX_MASK (0x7 << I40E_QINT_TQCTL_MSIX0_INDX_SHIFT)
+#define I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT 16
+#define I40E_QINT_TQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT)
+#define I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT 27
+#define I40E_QINT_TQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT)
+#define I40E_QINT_TQCTL_CAUSE_ENA_SHIFT 30
+#define I40E_QINT_TQCTL_CAUSE_ENA_MASK (0x1 << I40E_QINT_TQCTL_CAUSE_ENA_SHIFT)
+#define I40E_QINT_TQCTL_INTEVENT_SHIFT 31
+#define I40E_QINT_TQCTL_INTEVENT_MASK (0x1 << I40E_QINT_TQCTL_INTEVENT_SHIFT)
+#define I40E_VFINT_DYN_CTL0(_VF) (0x0002A400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFINT_DYN_CTL0_MAX_INDEX 127
+#define I40E_VFINT_DYN_CTL0_INTENA_SHIFT 0
+#define I40E_VFINT_DYN_CTL0_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTL0_INTENA_SHIFT)
+#define I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT 1
+#define I40E_VFINT_DYN_CTL0_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT)
+#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2
+#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT)
+#define I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT 3
+#define I40E_VFINT_DYN_CTL0_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT 5
+#define I40E_VFINT_DYN_CTL0_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT)
+#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24
+#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT)
+#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25
+#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT 31
+#define I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT)
+#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */
+#define I40E_VFINT_DYN_CTLN_MAX_INDEX 511
+#define I40E_VFINT_DYN_CTLN_INTENA_SHIFT 0
+#define I40E_VFINT_DYN_CTLN_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTLN_INTENA_SHIFT)
+#define I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT 1
+#define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT)
+#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2
+#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT)
+#define I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT 3
+#define I40E_VFINT_DYN_CTLN_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT 5
+#define I40E_VFINT_DYN_CTLN_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT)
+#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24
+#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT)
+#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25
+#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT 31
+#define I40E_VFINT_DYN_CTLN_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT)
+#define I40E_VFINT_ICR0(_VF) (0x0002BC00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFINT_ICR0_MAX_INDEX 127
+#define I40E_VFINT_ICR0_INTEVENT_SHIFT 0
+#define I40E_VFINT_ICR0_INTEVENT_MASK (0x1 << I40E_VFINT_ICR0_INTEVENT_SHIFT)
+#define I40E_VFINT_ICR0_QUEUE_0_SHIFT 1
+#define I40E_VFINT_ICR0_QUEUE_0_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_0_SHIFT)
+#define I40E_VFINT_ICR0_QUEUE_1_SHIFT 2
+#define I40E_VFINT_ICR0_QUEUE_1_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_1_SHIFT)
+#define I40E_VFINT_ICR0_QUEUE_2_SHIFT 3
+#define I40E_VFINT_ICR0_QUEUE_2_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_2_SHIFT)
+#define I40E_VFINT_ICR0_QUEUE_3_SHIFT 4
+#define I40E_VFINT_ICR0_QUEUE_3_MASK (0x1 << I40E_VFINT_ICR0_QUEUE_3_SHIFT)
+#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25
+#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT)
+#define I40E_VFINT_ICR0_ADMINQ_SHIFT 30
+#define I40E_VFINT_ICR0_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ADMINQ_SHIFT)
+#define I40E_VFINT_ICR0_SWINT_SHIFT 31
+#define I40E_VFINT_ICR0_SWINT_MASK (0x1 << I40E_VFINT_ICR0_SWINT_SHIFT)
+#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFINT_ICR0_ENA_MAX_INDEX 127
+#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25
+#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT)
+#define I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT 30
+#define I40E_VFINT_ICR0_ENA_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT)
+#define I40E_VFINT_ICR0_ENA_RSVD_SHIFT 31
+#define I40E_VFINT_ICR0_ENA_RSVD_MASK (0x1 << I40E_VFINT_ICR0_ENA_RSVD_SHIFT)
+#define I40E_VFINT_ITR0(_i, _VF) (0x00028000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...2, _VF=0...127 */
+#define I40E_VFINT_ITR0_MAX_INDEX 2
+#define I40E_VFINT_ITR0_INTERVAL_SHIFT 0
+#define I40E_VFINT_ITR0_INTERVAL_MASK (0xFFF << I40E_VFINT_ITR0_INTERVAL_SHIFT)
+#define I40E_VFINT_ITRN(_i, _INTVF) (0x00020000 + ((_i) * 2048 + (_INTVF) * 4))
+#define I40E_VFINT_ITRN_MAX_INDEX 2
+#define I40E_VFINT_ITRN_INTERVAL_SHIFT 0
+#define I40E_VFINT_ITRN_INTERVAL_MASK (0xFFF << I40E_VFINT_ITRN_INTERVAL_SHIFT)
+#define I40E_VFINT_STAT_CTL0(_VF) (0x0002A000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFINT_STAT_CTL0_MAX_INDEX 127
+#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2
+#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_MASK (0x3 << I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT)
+#define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPINT_AEQCTL_MAX_INDEX 127
+#define I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT 0
+#define I40E_VPINT_AEQCTL_MSIX_INDX_MASK (0xFF << I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT)
+#define I40E_VPINT_AEQCTL_ITR_INDX_SHIFT 11
+#define I40E_VPINT_AEQCTL_ITR_INDX_MASK (0x3 << I40E_VPINT_AEQCTL_ITR_INDX_SHIFT)
+#define I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT 13
+#define I40E_VPINT_AEQCTL_MSIX0_INDX_MASK (0x7 << I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT)
+#define I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT 30
+#define I40E_VPINT_AEQCTL_CAUSE_ENA_MASK (0x1 << I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT)
+#define I40E_VPINT_AEQCTL_INTEVENT_SHIFT 31
+#define I40E_VPINT_AEQCTL_INTEVENT_MASK (0x1 << I40E_VPINT_AEQCTL_INTEVENT_SHIFT)
+#define I40E_VPINT_CEQCTL(_INTVF) (0x00026800 + ((_INTVF) * 4)) /* _i=0...511 */
+#define I40E_VPINT_CEQCTL_MAX_INDEX 511
+#define I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT 0
+#define I40E_VPINT_CEQCTL_MSIX_INDX_MASK (0xFF << I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT)
+#define I40E_VPINT_CEQCTL_ITR_INDX_SHIFT 11
+#define I40E_VPINT_CEQCTL_ITR_INDX_MASK (0x3 << I40E_VPINT_CEQCTL_ITR_INDX_SHIFT)
+#define I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT 13
+#define I40E_VPINT_CEQCTL_MSIX0_INDX_MASK (0x7 << I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT)
+#define I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT 16
+#define I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK (0x7FF << I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT)
+#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT 27
+#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK (0x3 << I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT)
+#define I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT 30
+#define I40E_VPINT_CEQCTL_CAUSE_ENA_MASK (0x1 << I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT)
+#define I40E_VPINT_CEQCTL_INTEVENT_SHIFT 31
+#define I40E_VPINT_CEQCTL_INTEVENT_MASK (0x1 << I40E_VPINT_CEQCTL_INTEVENT_SHIFT)
+#define I40E_VPINT_LNKLST0(_VF) (0x0002A800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPINT_LNKLST0_MAX_INDEX 127
+#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT 0
+#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK (0x7FF << I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT)
+#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11
+#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_MASK (0x3 << I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT)
+#define I40E_VPINT_LNKLSTN(_INTVF) (0x00025000 + ((_INTVF) * 4)) /* _i=0...511 */
+#define I40E_VPINT_LNKLSTN_MAX_INDEX 511
+#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0
+#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK (0x7FF << I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT)
+#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11
+#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK (0x3 << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT)
+#define I40E_VPINT_RATE0(_VF) (0x0002AC00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPINT_RATE0_MAX_INDEX 127
+#define I40E_VPINT_RATE0_INTERVAL_SHIFT 0
+#define I40E_VPINT_RATE0_INTERVAL_MASK (0x3F << I40E_VPINT_RATE0_INTERVAL_SHIFT)
+#define I40E_VPINT_RATE0_INTRL_ENA_SHIFT 6
+#define I40E_VPINT_RATE0_INTRL_ENA_MASK (0x1 << I40E_VPINT_RATE0_INTRL_ENA_SHIFT)
+#define I40E_VPINT_RATEN(_INTVF) (0x00025800 + ((_INTVF) * 4)) /* _i=0...511 */
+#define I40E_VPINT_RATEN_MAX_INDEX 511
+#define I40E_VPINT_RATEN_INTERVAL_SHIFT 0
+#define I40E_VPINT_RATEN_INTERVAL_MASK (0x3F << I40E_VPINT_RATEN_INTERVAL_SHIFT)
+#define I40E_VPINT_RATEN_INTRL_ENA_SHIFT 6
+#define I40E_VPINT_RATEN_INTRL_ENA_MASK (0x1 << I40E_VPINT_RATEN_INTRL_ENA_SHIFT)
+#define I40E_GL_RDPU_CNTRL 0x00051060
+#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT 0
+#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_MASK (0x1 << I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT)
+#define I40E_GL_RDPU_CNTRL_ECO_SHIFT 1
+#define I40E_GL_RDPU_CNTRL_ECO_MASK (0x7FFFFFFF << I40E_GL_RDPU_CNTRL_ECO_SHIFT)
+#define I40E_GLLAN_RCTL_0 0x0012A500
+#define I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT 0
+#define I40E_GLLAN_RCTL_0_PXE_MODE_MASK (0x1 << I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT)
+#define I40E_GLLAN_TSOMSK_F 0x000442D8
+#define I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT 0
+#define I40E_GLLAN_TSOMSK_F_TCPMSKF_MASK (0xFFF << I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT)
+#define I40E_GLLAN_TSOMSK_L 0x000442E0
+#define I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT 0
+#define I40E_GLLAN_TSOMSK_L_TCPMSKL_MASK (0xFFF << I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT)
+#define I40E_GLLAN_TSOMSK_M 0x000442DC
+#define I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT 0
+#define I40E_GLLAN_TSOMSK_M_TCPMSKM_MASK (0xFFF << I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT)
+#define I40E_PFLAN_QALLOC 0x001C0400
+#define I40E_PFLAN_QALLOC_FIRSTQ_SHIFT 0
+#define I40E_PFLAN_QALLOC_FIRSTQ_MASK (0x7FF << I40E_PFLAN_QALLOC_FIRSTQ_SHIFT)
+#define I40E_PFLAN_QALLOC_LASTQ_SHIFT 16
+#define I40E_PFLAN_QALLOC_LASTQ_MASK (0x7FF << I40E_PFLAN_QALLOC_LASTQ_SHIFT)
+#define I40E_PFLAN_QALLOC_VALID_SHIFT 31
+#define I40E_PFLAN_QALLOC_VALID_MASK (0x1 << I40E_PFLAN_QALLOC_VALID_SHIFT)
+#define I40E_QRX_ENA(_Q) (0x00120000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QRX_ENA_MAX_INDEX 1535
+#define I40E_QRX_ENA_QENA_REQ_SHIFT 0
+#define I40E_QRX_ENA_QENA_REQ_MASK (0x1 << I40E_QRX_ENA_QENA_REQ_SHIFT)
+#define I40E_QRX_ENA_FAST_QDIS_SHIFT 1
+#define I40E_QRX_ENA_FAST_QDIS_MASK (0x1 << I40E_QRX_ENA_FAST_QDIS_SHIFT)
+#define I40E_QRX_ENA_QENA_STAT_SHIFT 2
+#define I40E_QRX_ENA_QENA_STAT_MASK (0x1 << I40E_QRX_ENA_QENA_STAT_SHIFT)
+#define I40E_QRX_TAIL(_Q) (0x00128000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QRX_TAIL_MAX_INDEX 1535
+#define I40E_QRX_TAIL_TAIL_SHIFT 0
+#define I40E_QRX_TAIL_TAIL_MASK (0x1FFF << I40E_QRX_TAIL_TAIL_SHIFT)
+#define I40E_QTX_CTL(_Q) (0x00104000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QTX_CTL_MAX_INDEX 1535
+#define I40E_QTX_CTL_PFVF_Q_SHIFT 0
+#define I40E_QTX_CTL_PFVF_Q_MASK (0x3 << I40E_QTX_CTL_PFVF_Q_SHIFT)
+#define I40E_QTX_CTL_PF_INDX_SHIFT 2
+#define I40E_QTX_CTL_PF_INDX_MASK (0xF << I40E_QTX_CTL_PF_INDX_SHIFT)
+#define I40E_QTX_CTL_VFVM_INDX_SHIFT 7
+#define I40E_QTX_CTL_VFVM_INDX_MASK (0x1FF << I40E_QTX_CTL_VFVM_INDX_SHIFT)
+#define I40E_QTX_ENA(_Q) (0x00100000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QTX_ENA_MAX_INDEX 1535
+#define I40E_QTX_ENA_QENA_REQ_SHIFT 0
+#define I40E_QTX_ENA_QENA_REQ_MASK (0x1 << I40E_QTX_ENA_QENA_REQ_SHIFT)
+#define I40E_QTX_ENA_FAST_QDIS_SHIFT 1
+#define I40E_QTX_ENA_FAST_QDIS_MASK (0x1 << I40E_QTX_ENA_FAST_QDIS_SHIFT)
+#define I40E_QTX_ENA_QENA_STAT_SHIFT 2
+#define I40E_QTX_ENA_QENA_STAT_MASK (0x1 << I40E_QTX_ENA_QENA_STAT_SHIFT)
+#define I40E_QTX_HEAD(_Q) (0x000E4000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QTX_HEAD_MAX_INDEX 1535
+#define I40E_QTX_HEAD_HEAD_SHIFT 0
+#define I40E_QTX_HEAD_HEAD_MASK (0x1FFF << I40E_QTX_HEAD_HEAD_SHIFT)
+#define I40E_QTX_HEAD_RS_PENDING_SHIFT 16
+#define I40E_QTX_HEAD_RS_PENDING_MASK (0x1 << I40E_QTX_HEAD_RS_PENDING_SHIFT)
+#define I40E_QTX_TAIL(_Q) (0x00108000 + ((_Q) * 4)) /* _i=0...1535 */
+#define I40E_QTX_TAIL_MAX_INDEX 1535
+#define I40E_QTX_TAIL_TAIL_SHIFT 0
+#define I40E_QTX_TAIL_TAIL_MASK (0x1FFF << I40E_QTX_TAIL_TAIL_SHIFT)
+#define I40E_VPLAN_MAPENA(_VF) (0x00074000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPLAN_MAPENA_MAX_INDEX 127
+#define I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT 0
+#define I40E_VPLAN_MAPENA_TXRX_ENA_MASK (0x1 << I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT)
+#define I40E_VPLAN_QTABLE(_i, _VF) (0x00070000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */
+#define I40E_VPLAN_QTABLE_MAX_INDEX 15
+#define I40E_VPLAN_QTABLE_QINDEX_SHIFT 0
+#define I40E_VPLAN_QTABLE_QINDEX_MASK (0x7FF << I40E_VPLAN_QTABLE_QINDEX_SHIFT)
+#define I40E_VSILAN_QBASE(_VSI) (0x0020C800 + ((_VSI) * 4)) /* _i=0...383 */
+#define I40E_VSILAN_QBASE_MAX_INDEX 383
+#define I40E_VSILAN_QBASE_VSIBASE_SHIFT 0
+#define I40E_VSILAN_QBASE_VSIBASE_MASK (0x7FF << I40E_VSILAN_QBASE_VSIBASE_SHIFT)
+#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT 11
+#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK (0x1 << I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT)
+#define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4))
+#define I40E_VSILAN_QTABLE_MAX_INDEX 15
+#define I40E_VSILAN_QTABLE_QINDEX_0_SHIFT 0
+#define I40E_VSILAN_QTABLE_QINDEX_0_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_0_SHIFT)
+#define I40E_VSILAN_QTABLE_QINDEX_1_SHIFT 16
+#define I40E_VSILAN_QTABLE_QINDEX_1_MASK (0x7FF << I40E_VSILAN_QTABLE_QINDEX_1_SHIFT)
+#define I40E_PRTGL_SAH 0x001E2140
+#define I40E_PRTGL_SAH_FC_SAH_SHIFT 0
+#define I40E_PRTGL_SAH_FC_SAH_MASK (0xFFFF << I40E_PRTGL_SAH_FC_SAH_SHIFT)
+#define I40E_PRTGL_SAH_MFS_SHIFT 16
+#define I40E_PRTGL_SAH_MFS_MASK (0xFFFF << I40E_PRTGL_SAH_MFS_SHIFT)
+#define I40E_PRTGL_SAL 0x001E2120
+#define I40E_PRTGL_SAL_FC_SAL_SHIFT 0
+#define I40E_PRTGL_SAL_FC_SAL_MASK (0xFFFFFFFF << I40E_PRTGL_SAL_FC_SAL_SHIFT)
+#define I40E_PRTMAC_HLCTLA 0x001E4760
+#define I40E_PRTMAC_HLCTLA_DROP_US_PKTS_SHIFT 0
+#define I40E_PRTMAC_HLCTLA_DROP_US_PKTS_MASK (0x1 << I40E_PRTMAC_HLCTLA_DROP_US_PKTS_SHIFT)
+#define I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_SHIFT 1
+#define I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_MASK (0x1 << I40E_PRTMAC_HLCTLA_RX_FWRD_CTRL_SHIFT)
+#define I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_SHIFT 2
+#define I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_MASK (0x1 << I40E_PRTMAC_HLCTLA_CHOP_OS_PKT_SHIFT)
+#define I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_SHIFT 4
+#define I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_MASK (0x7 << I40E_PRTMAC_HLCTLA_TX_HYSTERESIS_SHIFT)
+#define I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_SHIFT 7
+#define I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_MASK (0x1 << I40E_PRTMAC_HLCTLA_HYS_FLUSH_PKT_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP 0x001E3130
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GCP_HSEC_CTL_RX_CHECK_SA_GCP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP 0x001E3290
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_GPP_HSEC_CTL_RX_CHECK_SA_GPP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP 0x001E3310
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_SA_PPP_HSEC_CTL_RX_CHECK_SA_PPP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP 0x001E3100
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GCP_HSEC_CTL_RX_CHECK_UCAST_GCP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP 0x001E3280
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_GPP_HSEC_CTL_RX_CHECK_UCAST_GPP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP 0x001E3300
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_CHECK_UCAST_PPP_HSEC_CTL_RX_CHECK_UCAST_PPP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP 0x001E30E0
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP 0x001E3260
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP 0x001E32E0
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL 0x001E3360
+#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1 0x001E3110
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2 0x001E3120
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE 0x001E30C0
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK (0x1FF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1 0x001E3140
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2 0x001E3150
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE 0x001E3000
+#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_MASK (0x1 << I40E_PRTMAC_HSEC_CTL_TX_ENABLE_HSEC_CTL_TX_ENABLE_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE 0x001E30D0
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK (0x1FF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(_i) (0x001E3370 + ((_i) * 16))
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX 8
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(_i) (0x001E3400 + ((_i) * 16))
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MAX_INDEX 8
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1 0x001E34B0
+#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_MASK (0xFFFFFFFF << I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT)
+#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2 0x001E34C0
+#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT 0
+#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_MASK (0xFFFF << I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT)
+#define I40E_PRTMAC_HSECTL1 0x001E3560
+#define I40E_PRTMAC_HSECTL1_DROP_US_PKTS_SHIFT 0
+#define I40E_PRTMAC_HSECTL1_DROP_US_PKTS_MASK (0x1 << I40E_PRTMAC_HSECTL1_DROP_US_PKTS_SHIFT)
+#define I40E_PRTMAC_HSECTL1_PAD_US_PKT_SHIFT 3
+#define I40E_PRTMAC_HSECTL1_PAD_US_PKT_MASK (0x1 << I40E_PRTMAC_HSECTL1_PAD_US_PKT_SHIFT)
+#define I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_SHIFT 4
+#define I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_MASK (0x7 << I40E_PRTMAC_HSECTL1_TX_HYSTERESIS_SHIFT)
+#define I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_SHIFT 7
+#define I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_MASK (0x1 << I40E_PRTMAC_HSECTL1_HYS_FLUSH_PKT_SHIFT)
+#define I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_SHIFT 30
+#define I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_MASK (0x1 << I40E_PRTMAC_HSECTL1_EN_SFD_CHECK_SHIFT)
+#define I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_SHIFT 31
+#define I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_MASK (0x1 << I40E_PRTMAC_HSECTL1_EN_PREAMBLE_CHECK_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A 0x0008C480
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT 0
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT 2
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT 4
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT 6
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT 8
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT 10
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT 12
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT 14
+#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B 0x0008C484
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT 0
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT 2
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT 4
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT 6
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT 8
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT 10
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT 12
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT)
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT 14
+#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK (0x3 << I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT)
+#define I40E_GL_MNG_FWSM 0x000B6134
+#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 0
+#define I40E_GL_MNG_FWSM_FW_MODES_MASK (0x3FF << I40E_GL_MNG_FWSM_FW_MODES_SHIFT)
+#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 10
+#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK (0x1 << I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT)
+#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT 11
+#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK (0xF << I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT)
+#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT 15
+#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK (0x1 << I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT)
+#define I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT 19
+#define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK (0x3F << I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT)
+#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT 26
+#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT)
+#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT 27
+#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT)
+#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT 28
+#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT)
+#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT 29
+#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_MASK (0x1 << I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT)
+#define I40E_GL_MNG_HWARB_CTRL 0x000B6130
+#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT 0
+#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_MASK (0x1 << I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT)
+#define I40E_PRT_MNG_FTFT_DATA(_i) (0x000852A0 + ((_i) * 32)) /* _i=0...31 */
+#define I40E_PRT_MNG_FTFT_DATA_MAX_INDEX 31
+#define I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT 0
+#define I40E_PRT_MNG_FTFT_DATA_DWORD_MASK (0xFFFFFFFF << I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT)
+#define I40E_PRT_MNG_FTFT_LENGTH 0x00085260
+#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT 0
+#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_MASK (0xFF << I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT)
+#define I40E_PRT_MNG_FTFT_MASK(_i) (0x00085160 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRT_MNG_FTFT_MASK_MAX_INDEX 7
+#define I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT 0
+#define I40E_PRT_MNG_FTFT_MASK_MASK_MASK (0xFFFF << I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT)
+#define I40E_PRT_MNG_MANC 0x00256A20
+#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT 0
+#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_MASK (0x1 << I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT)
+#define I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT 1
+#define I40E_PRT_MNG_MANC_NCSI_DISCARD_MASK (0x1 << I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT)
+#define I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT 17
+#define I40E_PRT_MNG_MANC_RCV_TCO_EN_MASK (0x1 << I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT)
+#define I40E_PRT_MNG_MANC_RCV_ALL_SHIFT 19
+#define I40E_PRT_MNG_MANC_RCV_ALL_MASK (0x1 << I40E_PRT_MNG_MANC_RCV_ALL_SHIFT)
+#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT 25
+#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_MASK (0x1 << I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT)
+#define I40E_PRT_MNG_MANC_NET_TYPE_SHIFT 26
+#define I40E_PRT_MNG_MANC_NET_TYPE_MASK (0x1 << I40E_PRT_MNG_MANC_NET_TYPE_SHIFT)
+#define I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT 28
+#define I40E_PRT_MNG_MANC_EN_BMC2OS_MASK (0x1 << I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT)
+#define I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT 29
+#define I40E_PRT_MNG_MANC_EN_BMC2NET_MASK (0x1 << I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT)
+#define I40E_PRT_MNG_MAVTV(_i) (0x00255900 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRT_MNG_MAVTV_MAX_INDEX 7
+#define I40E_PRT_MNG_MAVTV_VID_SHIFT 0
+#define I40E_PRT_MNG_MAVTV_VID_MASK (0xFFF << I40E_PRT_MNG_MAVTV_VID_SHIFT)
+#define I40E_PRT_MNG_MDEF(_i) (0x00255D00 + ((_i) * 32))
+#define I40E_PRT_MNG_MDEF_MAX_INDEX 7
+#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT 0
+#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_MASK (0xF << I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT 4
+#define I40E_PRT_MNG_MDEF_BROADCAST_AND_MASK (0x1 << I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT 5
+#define I40E_PRT_MNG_MDEF_VLAN_AND_MASK (0xFF << I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT 13
+#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_MASK (0xF << I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT 17
+#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_MASK (0xF << I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT 21
+#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_MASK (0xF << I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT 25
+#define I40E_PRT_MNG_MDEF_BROADCAST_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT 26
+#define I40E_PRT_MNG_MDEF_MULTICAST_AND_MASK (0x1 << I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT 27
+#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT 28
+#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT 29
+#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT 30
+#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT 31
+#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT(_i) (0x00255F00 + ((_i) * 32))
+#define I40E_PRT_MNG_MDEF_EXT_MAX_INDEX 7
+#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT 0
+#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_MASK (0xF << I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT 4
+#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_MASK (0xF << I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT 8
+#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_MASK (0xFFFF << I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT 24
+#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT 25
+#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT 26
+#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT 27
+#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT 28
+#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT 29
+#define I40E_PRT_MNG_MDEF_EXT_MLD_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT 30
+#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT)
+#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT 31
+#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_MASK (0x1 << I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT)
+#define I40E_PRT_MNG_MDEFVSI(_i) (0x00256580 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRT_MNG_MDEFVSI_MAX_INDEX 3
+#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT 0
+#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_MASK (0xFFFF << I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT)
+#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT 16
+#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_MASK (0xFFFF << I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT)
+#define I40E_PRT_MNG_METF(_i) (0x00256780 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRT_MNG_METF_MAX_INDEX 3
+#define I40E_PRT_MNG_METF_ETYPE_SHIFT 0
+#define I40E_PRT_MNG_METF_ETYPE_MASK (0xFFFF << I40E_PRT_MNG_METF_ETYPE_SHIFT)
+#define I40E_PRT_MNG_METF_POLARITY_SHIFT 30
+#define I40E_PRT_MNG_METF_POLARITY_MASK (0x1 << I40E_PRT_MNG_METF_POLARITY_SHIFT)
+#define I40E_PRT_MNG_MFUTP(_i) (0x00254E00 + ((_i) * 32)) /* _i=0...15 */
+#define I40E_PRT_MNG_MFUTP_MAX_INDEX 15
+#define I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT 0
+#define I40E_PRT_MNG_MFUTP_MFUTP_N_MASK (0xFFFF << I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT)
+#define I40E_PRT_MNG_MFUTP_UDP_SHIFT 16
+#define I40E_PRT_MNG_MFUTP_UDP_MASK (0x1 << I40E_PRT_MNG_MFUTP_UDP_SHIFT)
+#define I40E_PRT_MNG_MFUTP_TCP_SHIFT 17
+#define I40E_PRT_MNG_MFUTP_TCP_MASK (0x1 << I40E_PRT_MNG_MFUTP_TCP_SHIFT)
+#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT 18
+#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_MASK (0x1 << I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT)
+#define I40E_PRT_MNG_MIPAF4(_i) (0x00256280 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRT_MNG_MIPAF4_MAX_INDEX 3
+#define I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT 0
+#define I40E_PRT_MNG_MIPAF4_MIPAF_MASK (0xFFFFFFFF << I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT)
+#define I40E_PRT_MNG_MIPAF6(_i) (0x00254200 + ((_i) * 32)) /* _i=0...15 */
+#define I40E_PRT_MNG_MIPAF6_MAX_INDEX 15
+#define I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT 0
+#define I40E_PRT_MNG_MIPAF6_MIPAF_MASK (0xFFFFFFFF << I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT)
+#define I40E_PRT_MNG_MMAH(_i) (0x00256380 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRT_MNG_MMAH_MAX_INDEX 3
+#define I40E_PRT_MNG_MMAH_MMAH_SHIFT 0
+#define I40E_PRT_MNG_MMAH_MMAH_MASK (0xFFFF << I40E_PRT_MNG_MMAH_MMAH_SHIFT)
+#define I40E_PRT_MNG_MMAL(_i) (0x00256480 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRT_MNG_MMAL_MAX_INDEX 3
+#define I40E_PRT_MNG_MMAL_MMAL_SHIFT 0
+#define I40E_PRT_MNG_MMAL_MMAL_MASK (0xFFFFFFFF << I40E_PRT_MNG_MMAL_MMAL_SHIFT)
+#define I40E_PRT_MNG_MNGONLY 0x00256A60
+#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT 0
+#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_MASK (0xFF << I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT)
+#define I40E_PRT_MNG_MSFM 0x00256AA0
+#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT 0
+#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT)
+#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT 1
+#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT)
+#define I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT 2
+#define I40E_PRT_MNG_MSFM_PORT_298_UDP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT)
+#define I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT 3
+#define I40E_PRT_MNG_MSFM_PORT_298_TCP_MASK (0x1 << I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT)
+#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT 4
+#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT)
+#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT 5
+#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT)
+#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT 6
+#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT)
+#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT 7
+#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_MASK (0x1 << I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT)
+#define I40E_MSIX_PBA(_i) (0x00004900 + ((_i) * 4)) /* _i=0...5 */
+#define I40E_MSIX_PBA_MAX_INDEX 5
+#define I40E_MSIX_PBA_PENBIT_SHIFT 0
+#define I40E_MSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_MSIX_PBA_PENBIT_SHIFT)
+#define I40E_MSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...128 */
+#define I40E_MSIX_TADD_MAX_INDEX 128
+#define I40E_MSIX_TADD_MSIXTADD10_SHIFT 0
+#define I40E_MSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_MSIX_TADD_MSIXTADD10_SHIFT)
+#define I40E_MSIX_TADD_MSIXTADD_SHIFT 2
+#define I40E_MSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_MSIX_TADD_MSIXTADD_SHIFT)
+#define I40E_MSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...128 */
+#define I40E_MSIX_TMSG_MAX_INDEX 128
+#define I40E_MSIX_TMSG_MSIXTMSG_SHIFT 0
+#define I40E_MSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_MSIX_TMSG_MSIXTMSG_SHIFT)
+#define I40E_MSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...128 */
+#define I40E_MSIX_TUADD_MAX_INDEX 128
+#define I40E_MSIX_TUADD_MSIXTUADD_SHIFT 0
+#define I40E_MSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_MSIX_TUADD_MSIXTUADD_SHIFT)
+#define I40E_MSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...128 */
+#define I40E_MSIX_TVCTRL_MAX_INDEX 128
+#define I40E_MSIX_TVCTRL_MASK_SHIFT 0
+#define I40E_MSIX_TVCTRL_MASK_MASK (0x1 << I40E_MSIX_TVCTRL_MASK_SHIFT)
+#define I40E_VFMSIX_PBA1(_i) (0x00004944 + ((_i) * 4)) /* _i=0...19 */
+#define I40E_VFMSIX_PBA1_MAX_INDEX 19
+#define I40E_VFMSIX_PBA1_PENBIT_SHIFT 0
+#define I40E_VFMSIX_PBA1_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA1_PENBIT_SHIFT)
+#define I40E_VFMSIX_TADD1(_i) (0x00002100 + ((_i) * 16)) /* _i=0...639 */
+#define I40E_VFMSIX_TADD1_MAX_INDEX 639
+#define I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT 0
+#define I40E_VFMSIX_TADD1_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD1_MSIXTADD10_SHIFT)
+#define I40E_VFMSIX_TADD1_MSIXTADD_SHIFT 2
+#define I40E_VFMSIX_TADD1_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD1_MSIXTADD_SHIFT)
+#define I40E_VFMSIX_TMSG1(_i) (0x00002108 + ((_i) * 16)) /* _i=0...639 */
+#define I40E_VFMSIX_TMSG1_MAX_INDEX 639
+#define I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT 0
+#define I40E_VFMSIX_TMSG1_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG1_MSIXTMSG_SHIFT)
+#define I40E_VFMSIX_TUADD1(_i) (0x00002104 + ((_i) * 16)) /* _i=0...639 */
+#define I40E_VFMSIX_TUADD1_MAX_INDEX 639
+#define I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT 0
+#define I40E_VFMSIX_TUADD1_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD1_MSIXTUADD_SHIFT)
+#define I40E_VFMSIX_TVCTRL1(_i) (0x0000210C + ((_i) * 16)) /* _i=0...639 */
+#define I40E_VFMSIX_TVCTRL1_MAX_INDEX 639
+#define I40E_VFMSIX_TVCTRL1_MASK_SHIFT 0
+#define I40E_VFMSIX_TVCTRL1_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL1_MASK_SHIFT)
+#define I40E_GLNVM_FLA 0x000B6108
+#define I40E_GLNVM_FLA_FL_SCK_SHIFT 0
+#define I40E_GLNVM_FLA_FL_SCK_MASK (0x1 << I40E_GLNVM_FLA_FL_SCK_SHIFT)
+#define I40E_GLNVM_FLA_FL_CE_SHIFT 1
+#define I40E_GLNVM_FLA_FL_CE_MASK (0x1 << I40E_GLNVM_FLA_FL_CE_SHIFT)
+#define I40E_GLNVM_FLA_FL_SI_SHIFT 2
+#define I40E_GLNVM_FLA_FL_SI_MASK (0x1 << I40E_GLNVM_FLA_FL_SI_SHIFT)
+#define I40E_GLNVM_FLA_FL_SO_SHIFT 3
+#define I40E_GLNVM_FLA_FL_SO_MASK (0x1 << I40E_GLNVM_FLA_FL_SO_SHIFT)
+#define I40E_GLNVM_FLA_FL_REQ_SHIFT 4
+#define I40E_GLNVM_FLA_FL_REQ_MASK (0x1 << I40E_GLNVM_FLA_FL_REQ_SHIFT)
+#define I40E_GLNVM_FLA_FL_GNT_SHIFT 5
+#define I40E_GLNVM_FLA_FL_GNT_MASK (0x1 << I40E_GLNVM_FLA_FL_GNT_SHIFT)
+#define I40E_GLNVM_FLA_LOCKED_SHIFT 6
+#define I40E_GLNVM_FLA_LOCKED_MASK (0x1 << I40E_GLNVM_FLA_LOCKED_SHIFT)
+#define I40E_GLNVM_FLA_FL_SADDR_SHIFT 18
+#define I40E_GLNVM_FLA_FL_SADDR_MASK (0x7FF << I40E_GLNVM_FLA_FL_SADDR_SHIFT)
+#define I40E_GLNVM_FLA_FL_BUSY_SHIFT 30
+#define I40E_GLNVM_FLA_FL_BUSY_MASK (0x1 << I40E_GLNVM_FLA_FL_BUSY_SHIFT)
+#define I40E_GLNVM_FLA_FL_DER_SHIFT 31
+#define I40E_GLNVM_FLA_FL_DER_MASK (0x1 << I40E_GLNVM_FLA_FL_DER_SHIFT)
+#define I40E_GLNVM_FLASHID 0x000B6104
+#define I40E_GLNVM_FLASHID_FLASHID_SHIFT 0
+#define I40E_GLNVM_FLASHID_FLASHID_MASK (0xFFFFFF << I40E_GLNVM_FLASHID_FLASHID_SHIFT)
+#define I40E_GLNVM_GENS 0x000B6100
+#define I40E_GLNVM_GENS_NVM_PRES_SHIFT 0
+#define I40E_GLNVM_GENS_NVM_PRES_MASK (0x1 << I40E_GLNVM_GENS_NVM_PRES_SHIFT)
+#define I40E_GLNVM_GENS_SR_SIZE_SHIFT 5
+#define I40E_GLNVM_GENS_SR_SIZE_MASK (0x7 << I40E_GLNVM_GENS_SR_SIZE_SHIFT)
+#define I40E_GLNVM_GENS_BANK1VAL_SHIFT 8
+#define I40E_GLNVM_GENS_BANK1VAL_MASK (0x1 << I40E_GLNVM_GENS_BANK1VAL_SHIFT)
+#define I40E_GLNVM_GENS_ALT_PRST_SHIFT 23
+#define I40E_GLNVM_GENS_ALT_PRST_MASK (0x1 << I40E_GLNVM_GENS_ALT_PRST_SHIFT)
+#define I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT 25
+#define I40E_GLNVM_GENS_FL_AUTO_RD_MASK (0x1 << I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT)
+#define I40E_GLNVM_PROTCSR(_i) (0x000B6010 + ((_i) * 4)) /* _i=0...59 */
+#define I40E_GLNVM_PROTCSR_MAX_INDEX 59
+#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT 0
+#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_MASK (0xFFFFFF << I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT)
+#define I40E_GLNVM_SRCTL 0x000B6110
+#define I40E_GLNVM_SRCTL_SRBUSY_SHIFT 0
+#define I40E_GLNVM_SRCTL_SRBUSY_MASK (0x1 << I40E_GLNVM_SRCTL_SRBUSY_SHIFT)
+#define I40E_GLNVM_SRCTL_ADDR_SHIFT 14
+#define I40E_GLNVM_SRCTL_ADDR_MASK (0x7FFF << I40E_GLNVM_SRCTL_ADDR_SHIFT)
+#define I40E_GLNVM_SRCTL_WRITE_SHIFT 29
+#define I40E_GLNVM_SRCTL_WRITE_MASK (0x1 << I40E_GLNVM_SRCTL_WRITE_SHIFT)
+#define I40E_GLNVM_SRCTL_START_SHIFT 30
+#define I40E_GLNVM_SRCTL_START_MASK (0x1 << I40E_GLNVM_SRCTL_START_SHIFT)
+#define I40E_GLNVM_SRCTL_DONE_SHIFT 31
+#define I40E_GLNVM_SRCTL_DONE_MASK (0x1 << I40E_GLNVM_SRCTL_DONE_SHIFT)
+#define I40E_GLNVM_SRDATA 0x000B6114
+#define I40E_GLNVM_SRDATA_WRDATA_SHIFT 0
+#define I40E_GLNVM_SRDATA_WRDATA_MASK (0xFFFF << I40E_GLNVM_SRDATA_WRDATA_SHIFT)
+#define I40E_GLNVM_SRDATA_RDDATA_SHIFT 16
+#define I40E_GLNVM_SRDATA_RDDATA_MASK (0xFFFF << I40E_GLNVM_SRDATA_RDDATA_SHIFT)
+#define I40E_GLPCI_BYTCTH 0x0009C484
+#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT 0
+#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_MASK (0xFFFFFFFF << I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT)
+#define I40E_GLPCI_BYTCTL 0x0009C488
+#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT 0
+#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_MASK (0xFFFFFFFF << I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT)
+#define I40E_GLPCI_CAPCTRL 0x000BE4A4
+#define I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT 0
+#define I40E_GLPCI_CAPCTRL_VPD_EN_MASK (0x1 << I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP 0x000BE4A8
+#define I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT 0
+#define I40E_GLPCI_CAPSUP_PCIE_VER_MASK (0x1 << I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT)
+#define I40E_GLPCI_CAPSUP_LTR_EN_SHIFT 2
+#define I40E_GLPCI_CAPSUP_LTR_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_LTR_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_TPH_EN_SHIFT 3
+#define I40E_GLPCI_CAPSUP_TPH_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_TPH_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_ARI_EN_SHIFT 4
+#define I40E_GLPCI_CAPSUP_ARI_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ARI_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_IOV_EN_SHIFT 5
+#define I40E_GLPCI_CAPSUP_IOV_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_IOV_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_ACS_EN_SHIFT 6
+#define I40E_GLPCI_CAPSUP_ACS_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ACS_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_SEC_EN_SHIFT 7
+#define I40E_GLPCI_CAPSUP_SEC_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_SEC_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT 16
+#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT 17
+#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_IDO_EN_SHIFT 18
+#define I40E_GLPCI_CAPSUP_IDO_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_IDO_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT 19
+#define I40E_GLPCI_CAPSUP_MSI_MASK_MASK (0x1 << I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT)
+#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT 20
+#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_MASK (0x1 << I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT)
+#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT 30
+#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_MASK (0x1 << I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT)
+#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT 31
+#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_MASK (0x1 << I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT)
+#define I40E_GLPCI_CNF 0x000BE4C0
+#define I40E_GLPCI_CNF_FLEX10_SHIFT 1
+#define I40E_GLPCI_CNF_FLEX10_MASK (0x1 << I40E_GLPCI_CNF_FLEX10_SHIFT)
+#define I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT 2
+#define I40E_GLPCI_CNF_WAKE_PIN_EN_MASK (0x1 << I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT)
+#define I40E_GLPCI_CNF2 0x000BE494
+#define I40E_GLPCI_CNF2_RO_DIS_SHIFT 0
+#define I40E_GLPCI_CNF2_RO_DIS_MASK (0x1 << I40E_GLPCI_CNF2_RO_DIS_SHIFT)
+#define I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT 1
+#define I40E_GLPCI_CNF2_CACHELINE_SIZE_MASK (0x1 << I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT)
+#define I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT 2
+#define I40E_GLPCI_CNF2_MSI_X_PF_N_MASK (0x7FF << I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT)
+#define I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT 13
+#define I40E_GLPCI_CNF2_MSI_X_VF_N_MASK (0x7FF << I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT)
+#define I40E_GLPCI_DREVID 0x0009C480
+#define I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT 0
+#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK (0xFF << I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT)
+#define I40E_GLPCI_GSCL_1 0x0009C48C
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT 0
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT 1
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT 2
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT 3
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT)
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT 4
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT)
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT 5
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT)
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT 6
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT)
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT 7
+#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_MASK (0x1 << I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT)
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT 8
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT)
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT 9
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_MASK (0x1F << I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT)
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT 14
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT)
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT 15
+#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_MASK (0x1F << I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT 28
+#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT 29
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT 30
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT)
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT 31
+#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_MASK (0x1 << I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT)
+#define I40E_GLPCI_GSCL_2 0x0009C490
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT 0
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT)
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT 8
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT)
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT 16
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT)
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT 24
+#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_MASK (0xFF << I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT)
+#define I40E_GLPCI_GSCL_5_8(_i) (0x0009C494 + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLPCI_GSCL_5_8_MAX_INDEX 3
+#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT 0
+#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_MASK (0xFFFF << I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT)
+#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT 16
+#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_MASK (0xFFFF << I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT)
+#define I40E_GLPCI_GSCN_0_3(_i) (0x0009C4A4 + ((_i) * 4)) /* _i=0...3 */
+#define I40E_GLPCI_GSCN_0_3_MAX_INDEX 3
+#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT 0
+#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_MASK (0xFFFFFFFF << I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT)
+#define I40E_GLPCI_LATCT 0x0009C4B4
+#define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT 0
+#define I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_MASK (0xFFFFFFFF << I40E_GLPCI_LATCT_PCI_COUNT_LAT_CT_SHIFT)
+#define I40E_GLPCI_LBARCTRL 0x000BE484
+#define I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT 0
+#define I40E_GLPCI_LBARCTRL_PREFBAR_MASK (0x1 << I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT)
+#define I40E_GLPCI_LBARCTRL_BAR32_SHIFT 1
+#define I40E_GLPCI_LBARCTRL_BAR32_MASK (0x1 << I40E_GLPCI_LBARCTRL_BAR32_SHIFT)
+#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT 3
+#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_MASK (0x1 << I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT)
+#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT 4
+#define I40E_GLPCI_LBARCTRL_PE_DB_SIZE_MASK (0x3 << I40E_GLPCI_LBARCTRL_PE_DB_SIZE_SHIFT)
+#define I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT 6
+#define I40E_GLPCI_LBARCTRL_FL_SIZE_MASK (0x7 << I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT)
+#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT 10
+#define I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_MASK (0x1 << I40E_GLPCI_LBARCTRL_VF_PE_DB_SIZE_SHIFT)
+#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT 11
+#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_MASK (0x7 << I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT)
+#define I40E_GLPCI_LINKCAP 0x000BE4AC
+#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT 0
+#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_MASK (0x3F << I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT)
+#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT 6
+#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_MASK (0x7 << I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT)
+#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT 9
+#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_MASK (0xF << I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT)
+#define I40E_GLPCI_PCIERR 0x000BE4FC
+#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT 0
+#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK (0xFFFFFFFF << I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT)
+#define I40E_GLPCI_PKTCT 0x0009C4BC
+#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT 0
+#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK (0xFFFFFFFF << I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT)
+#define I40E_GLPCI_PMSUP 0x000BE4B0
+#define I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT 0
+#define I40E_GLPCI_PMSUP_ASPM_SUP_MASK (0x3 << I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT)
+#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT 2
+#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT)
+#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT 5
+#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT)
+#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT 8
+#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT)
+#define I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT 11
+#define I40E_GLPCI_PMSUP_L1_ACC_LAT_MASK (0x7 << I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT)
+#define I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT 14
+#define I40E_GLPCI_PMSUP_SLOT_CLK_MASK (0x1 << I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT)
+#define I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT 15
+#define I40E_GLPCI_PMSUP_OBFF_SUP_MASK (0x3 << I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT)
+#define I40E_GLPCI_PWRDATA 0x000BE490
+#define I40E_GLPCI_PWRDATA_D0_POWER_SHIFT 0
+#define I40E_GLPCI_PWRDATA_D0_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_D0_POWER_SHIFT)
+#define I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT 8
+#define I40E_GLPCI_PWRDATA_COMM_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT)
+#define I40E_GLPCI_PWRDATA_D3_POWER_SHIFT 16
+#define I40E_GLPCI_PWRDATA_D3_POWER_MASK (0xFF << I40E_GLPCI_PWRDATA_D3_POWER_SHIFT)
+#define I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT 24
+#define I40E_GLPCI_PWRDATA_DATA_SCALE_MASK (0x3 << I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT)
+#define I40E_GLPCI_REVID 0x000BE4B4
+#define I40E_GLPCI_REVID_NVM_REVID_SHIFT 0
+#define I40E_GLPCI_REVID_NVM_REVID_MASK (0xFF << I40E_GLPCI_REVID_NVM_REVID_SHIFT)
+#define I40E_GLPCI_SERH 0x000BE49C
+#define I40E_GLPCI_SERH_SER_NUM_H_SHIFT 0
+#define I40E_GLPCI_SERH_SER_NUM_H_MASK (0xFFFF << I40E_GLPCI_SERH_SER_NUM_H_SHIFT)
+#define I40E_GLPCI_SERL 0x000BE498
+#define I40E_GLPCI_SERL_SER_NUM_L_SHIFT 0
+#define I40E_GLPCI_SERL_SER_NUM_L_MASK (0xFFFFFFFF << I40E_GLPCI_SERL_SER_NUM_L_SHIFT)
+#define I40E_GLPCI_SUBSYSID 0x000BE48C
+#define I40E_GLPCI_SUBSYSID_SUB_VEN_ID_SHIFT 0
+#define I40E_GLPCI_SUBSYSID_SUB_VEN_ID_MASK (0xFFFF << I40E_GLPCI_SUBSYSID_SUB_VEN_ID_SHIFT)
+#define I40E_GLPCI_SUBSYSID_SUB_ID_SHIFT 16
+#define I40E_GLPCI_SUBSYSID_SUB_ID_MASK (0xFFFF << I40E_GLPCI_SUBSYSID_SUB_ID_SHIFT)
+#define I40E_GLPCI_UPADD 0x000BE4F8
+#define I40E_GLPCI_UPADD_ADDRESS_SHIFT 1
+#define I40E_GLPCI_UPADD_ADDRESS_MASK (0x7FFFFFFF << I40E_GLPCI_UPADD_ADDRESS_SHIFT)
+#define I40E_GLPCI_VFSUP 0x000BE4B8
+#define I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT 0
+#define I40E_GLPCI_VFSUP_VF_PREFETCH_MASK (0x1 << I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT)
+#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT 1
+#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_MASK (0x1 << I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT)
+#define I40E_PF_FUNC_RID 0x0009C000
+#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT 0
+#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_MASK (0x7 << I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT)
+#define I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT 3
+#define I40E_PF_FUNC_RID_DEVICE_NUMBER_MASK (0x1F << I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT)
+#define I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT 8
+#define I40E_PF_FUNC_RID_BUS_NUMBER_MASK (0xFF << I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT)
+#define I40E_PF_PCI_CIAA 0x0009C080
+#define I40E_PF_PCI_CIAA_ADDRESS_SHIFT 0
+#define I40E_PF_PCI_CIAA_ADDRESS_MASK (0xFFF << I40E_PF_PCI_CIAA_ADDRESS_SHIFT)
+#define I40E_PF_PCI_CIAA_VF_NUM_SHIFT 12
+#define I40E_PF_PCI_CIAA_VF_NUM_MASK (0x7F << I40E_PF_PCI_CIAA_VF_NUM_SHIFT)
+#define I40E_PF_PCI_CIAD 0x0009C100
+#define I40E_PF_PCI_CIAD_DATA_SHIFT 0
+#define I40E_PF_PCI_CIAD_DATA_MASK (0xFFFFFFFF << I40E_PF_PCI_CIAD_DATA_SHIFT)
+#define I40E_PFPCI_CLASS 0x000BE400
+#define I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT 0
+#define I40E_PFPCI_CLASS_STORAGE_CLASS_MASK (0x1 << I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT)
+#define I40E_PFPCI_CNF 0x000BE000
+#define I40E_PFPCI_CNF_MSI_EN_SHIFT 2
+#define I40E_PFPCI_CNF_MSI_EN_MASK (0x1 << I40E_PFPCI_CNF_MSI_EN_SHIFT)
+#define I40E_PFPCI_CNF_EXROM_DIS_SHIFT 3
+#define I40E_PFPCI_CNF_EXROM_DIS_MASK (0x1 << I40E_PFPCI_CNF_EXROM_DIS_SHIFT)
+#define I40E_PFPCI_CNF_IO_BAR_SHIFT 4
+#define I40E_PFPCI_CNF_IO_BAR_MASK (0x1 << I40E_PFPCI_CNF_IO_BAR_SHIFT)
+#define I40E_PFPCI_CNF_INT_PIN_SHIFT 5
+#define I40E_PFPCI_CNF_INT_PIN_MASK (0x3 << I40E_PFPCI_CNF_INT_PIN_SHIFT)
+#define I40E_PFPCI_FACTPS 0x0009C180
+#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT 0
+#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_MASK (0x3 << I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT)
+#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT 3
+#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_MASK (0x1 << I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT)
+#define I40E_PFPCI_FUNC 0x000BE200
+#define I40E_PFPCI_FUNC_FUNC_DIS_SHIFT 0
+#define I40E_PFPCI_FUNC_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC_FUNC_DIS_SHIFT)
+#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT 1
+#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT)
+#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT 2
+#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_MASK (0x1 << I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT)
+#define I40E_PFPCI_FUNC2 0x000BE180
+#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT 0
+#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_MASK (0x1 << I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT)
+#define I40E_PFPCI_ICAUSE 0x0009C200
+#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT 0
+#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_MASK (0xFFFFFFFF << I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT)
+#define I40E_PFPCI_IENA 0x0009C280
+#define I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT 0
+#define I40E_PFPCI_IENA_PCIE_ERR_EN_MASK (0xFFFFFFFF << I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT)
+#define I40E_PFPCI_PFDEVID 0x000BE080
+#define I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_SHIFT 0
+#define I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_MASK (0xFFFF << I40E_PFPCI_PFDEVID_PF_DEV_ID_LAN_SHIFT)
+#define I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_SHIFT 16
+#define I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_MASK (0xFFFF << I40E_PFPCI_PFDEVID_PF_DEV_ID_SAN_SHIFT)
+#define I40E_PFPCI_PM 0x000BE300
+#define I40E_PFPCI_PM_PME_EN_SHIFT 0
+#define I40E_PFPCI_PM_PME_EN_MASK (0x1 << I40E_PFPCI_PM_PME_EN_SHIFT)
+#define I40E_PFPCI_STATUS1 0x000BE280
+#define I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT 0
+#define I40E_PFPCI_STATUS1_FUNC_VALID_MASK (0x1 << I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT)
+#define I40E_PFPCI_VFDEVID 0x000BE100
+#define I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_SHIFT 0
+#define I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_MASK (0xFFFF << I40E_PFPCI_VFDEVID_VF_DEV_ID_LAN_SHIFT)
+#define I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_SHIFT 16
+#define I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_MASK (0xFFFF << I40E_PFPCI_VFDEVID_VF_DEV_ID_SAN_SHIFT)
+#define I40E_PFPCI_VMINDEX 0x0009C300
+#define I40E_PFPCI_VMINDEX_VMINDEX_SHIFT 0
+#define I40E_PFPCI_VMINDEX_VMINDEX_MASK (0x1FF << I40E_PFPCI_VMINDEX_VMINDEX_SHIFT)
+#define I40E_PFPCI_VMPEND 0x0009C380
+#define I40E_PFPCI_VMPEND_PENDING_SHIFT 0
+#define I40E_PFPCI_VMPEND_PENDING_MASK (0x1 << I40E_PFPCI_VMPEND_PENDING_SHIFT)
+#define I40E_GLPE_CPUSTATUS0 0x0000D040
+#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT 0
+#define I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS0_PECPUSTATUS0_SHIFT)
+#define I40E_GLPE_CPUSTATUS1 0x0000D044
+#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT 0
+#define I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS1_PECPUSTATUS1_SHIFT)
+#define I40E_GLPE_CPUSTATUS2 0x0000D048
+#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT 0
+#define I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_MASK (0xFFFFFFFF << I40E_GLPE_CPUSTATUS2_PECPUSTATUS2_SHIFT)
+#define I40E_GLPE_PFFLMOBJCTRL(_i) (0x0000D480 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPE_PFFLMOBJCTRL_MAX_INDEX 15
+#define I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0
+#define I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_PFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT)
+#define I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8
+#define I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_PFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT)
+#define I40E_GLPE_VFFLMOBJCTRL(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPE_VFFLMOBJCTRL_MAX_INDEX 31
+#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT 0
+#define I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_XMIT_BLOCKSIZE_SHIFT)
+#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT 8
+#define I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_MASK (0x7 << I40E_GLPE_VFFLMOBJCTRL_Q1_BLOCKSIZE_SHIFT)
+#define I40E_GLPE_VFFLMQ1ALLOCERR(_i) (0x0000C700 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPE_VFFLMQ1ALLOCERR_MAX_INDEX 31
+#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0
+#define I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMQ1ALLOCERR_ERROR_COUNT_SHIFT)
+#define I40E_GLPE_VFFLMXMITALLOCERR(_i) (0x0000C600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPE_VFFLMXMITALLOCERR_MAX_INDEX 31
+#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT 0
+#define I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_GLPE_VFFLMXMITALLOCERR_ERROR_COUNT_SHIFT)
+#define I40E_GLPE_VFUDACTRL(_i) (0x0000C000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPE_VFUDACTRL_MAX_INDEX 31
+#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT 0
+#define I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4MCFRAGRESBP_SHIFT)
+#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT 1
+#define I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV4UCFRAGRESBP_SHIFT)
+#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT 2
+#define I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6MCFRAGRESBP_SHIFT)
+#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT 3
+#define I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_GLPE_VFUDACTRL_IPV6UCFRAGRESBP_SHIFT)
+#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT 4
+#define I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_GLPE_VFUDACTRL_UDPMCFRAGRESFAIL_SHIFT)
+#define I40E_GLPE_VFUDAUCFBQPN(_i) (0x0000C100 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPE_VFUDAUCFBQPN_MAX_INDEX 31
+#define I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT 0
+#define I40E_GLPE_VFUDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_GLPE_VFUDAUCFBQPN_QPN_SHIFT)
+#define I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT 31
+#define I40E_GLPE_VFUDAUCFBQPN_VALID_MASK (0x1 << I40E_GLPE_VFUDAUCFBQPN_VALID_SHIFT)
+#define I40E_PFPE_AEQALLOC 0x00131180
+#define I40E_PFPE_AEQALLOC_AECOUNT_SHIFT 0
+#define I40E_PFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_PFPE_AEQALLOC_AECOUNT_SHIFT)
+#define I40E_PFPE_CCQPHIGH 0x00008200
+#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0
+#define I40E_PFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_PFPE_CCQPHIGH_PECCQPHIGH_SHIFT)
+#define I40E_PFPE_CCQPLOW 0x00008180
+#define I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT 0
+#define I40E_PFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_PFPE_CCQPLOW_PECCQPLOW_SHIFT)
+#define I40E_PFPE_CCQPSTATUS 0x00008100
+#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0
+#define I40E_PFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_DONE_SHIFT)
+#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31
+#define I40E_PFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_PFPE_CCQPSTATUS_CCQP_ERR_SHIFT)
+#define I40E_PFPE_CQACK 0x00131100
+#define I40E_PFPE_CQACK_PECQID_SHIFT 0
+#define I40E_PFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_PFPE_CQACK_PECQID_SHIFT)
+#define I40E_PFPE_CQARM 0x00131080
+#define I40E_PFPE_CQARM_PECQID_SHIFT 0
+#define I40E_PFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_PFPE_CQARM_PECQID_SHIFT)
+#define I40E_PFPE_CQPDB 0x00008000
+#define I40E_PFPE_CQPDB_WQHEAD_SHIFT 0
+#define I40E_PFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_PFPE_CQPDB_WQHEAD_SHIFT)
+#define I40E_PFPE_CQPERRCODES 0x00008880
+#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0
+#define I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT)
+#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16
+#define I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_PFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT)
+#define I40E_PFPE_CQPTAIL 0x00008080
+#define I40E_PFPE_CQPTAIL_WQTAIL_SHIFT 0
+#define I40E_PFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_PFPE_CQPTAIL_WQTAIL_SHIFT)
+#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31
+#define I40E_PFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_PFPE_CQPTAIL_CQP_OP_ERR_SHIFT)
+#define I40E_PFPE_FLMQ1ALLOCERR 0x00008980
+#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT 0
+#define I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMQ1ALLOCERR_ERROR_COUNT_SHIFT)
+#define I40E_PFPE_FLMXMITALLOCERR 0x00008900
+#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT 0
+#define I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_MASK (0xFFFF << I40E_PFPE_FLMXMITALLOCERR_ERROR_COUNT_SHIFT)
+#define I40E_PFPE_IPCONFIG0 0x00008280
+#define I40E_PFPE_IPCONFIG0_PEIPID_SHIFT 0
+#define I40E_PFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_PFPE_IPCONFIG0_PEIPID_SHIFT)
+#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16
+#define I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT)
+#define I40E_PFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT 17
+#define I40E_PFPE_IPCONFIG0_USEUPPERIDRANGE_MASK (0x1 << I40E_PFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT)
+#define I40E_PFPE_MRTEIDXMASK 0x00008600
+#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0
+#define I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_PFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT)
+#define I40E_PFPE_RCVUNEXPECTEDERROR 0x00008680
+#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0
+#define I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_PFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT)
+#define I40E_PFPE_TCPNOWTIMER 0x00008580
+#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0
+#define I40E_PFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_PFPE_TCPNOWTIMER_TCP_NOW_SHIFT)
+#define I40E_PFPE_UDACTRL 0x00008700
+#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT 0
+#define I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV4MCFRAGRESBP_SHIFT)
+#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT 1
+#define I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV4UCFRAGRESBP_SHIFT)
+#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT 2
+#define I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV6MCFRAGRESBP_SHIFT)
+#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT 3
+#define I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_MASK (0x1 << I40E_PFPE_UDACTRL_IPV6UCFRAGRESBP_SHIFT)
+#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT 4
+#define I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_MASK (0x1 << I40E_PFPE_UDACTRL_UDPMCFRAGRESFAIL_SHIFT)
+#define I40E_PFPE_UDAUCFBQPN 0x00008780
+#define I40E_PFPE_UDAUCFBQPN_QPN_SHIFT 0
+#define I40E_PFPE_UDAUCFBQPN_QPN_MASK (0x3FFFF << I40E_PFPE_UDAUCFBQPN_QPN_SHIFT)
+#define I40E_PFPE_UDAUCFBQPN_VALID_SHIFT 31
+#define I40E_PFPE_UDAUCFBQPN_VALID_MASK (0x1 << I40E_PFPE_UDAUCFBQPN_VALID_SHIFT)
+#define I40E_PFPE_WQEALLOC 0x00138C00
+#define I40E_PFPE_WQEALLOC_PEQPID_SHIFT 0
+#define I40E_PFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_PFPE_WQEALLOC_PEQPID_SHIFT)
+#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20
+#define I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_PFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT)
+#define I40E_VFPE_AEQALLOC(_VF) (0x00130C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_AEQALLOC_MAX_INDEX 127
+#define I40E_VFPE_AEQALLOC_AECOUNT_SHIFT 0
+#define I40E_VFPE_AEQALLOC_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC_AECOUNT_SHIFT)
+#define I40E_VFPE_CCQPHIGH(_VF) (0x00001000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CCQPHIGH_MAX_INDEX 127
+#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT 0
+#define I40E_VFPE_CCQPHIGH_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH_PECCQPHIGH_SHIFT)
+#define I40E_VFPE_CCQPLOW(_VF) (0x00000C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CCQPLOW_MAX_INDEX 127
+#define I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT 0
+#define I40E_VFPE_CCQPLOW_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW_PECCQPLOW_SHIFT)
+#define I40E_VFPE_CCQPSTATUS(_VF) (0x00000800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CCQPSTATUS_MAX_INDEX 127
+#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT 0
+#define I40E_VFPE_CCQPSTATUS_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_DONE_SHIFT)
+#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT 31
+#define I40E_VFPE_CCQPSTATUS_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS_CCQP_ERR_SHIFT)
+#define I40E_VFPE_CQACK(_VF) (0x00130800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CQACK_MAX_INDEX 127
+#define I40E_VFPE_CQACK_PECQID_SHIFT 0
+#define I40E_VFPE_CQACK_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK_PECQID_SHIFT)
+#define I40E_VFPE_CQARM(_VF) (0x00130400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CQARM_MAX_INDEX 127
+#define I40E_VFPE_CQARM_PECQID_SHIFT 0
+#define I40E_VFPE_CQARM_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM_PECQID_SHIFT)
+#define I40E_VFPE_CQPDB(_VF) (0x00000000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CQPDB_MAX_INDEX 127
+#define I40E_VFPE_CQPDB_WQHEAD_SHIFT 0
+#define I40E_VFPE_CQPDB_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB_WQHEAD_SHIFT)
+#define I40E_VFPE_CQPERRCODES(_VF) (0x00001800 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CQPERRCODES_MAX_INDEX 127
+#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT 0
+#define I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MINOR_CODE_SHIFT)
+#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT 16
+#define I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES_CQP_MAJOR_CODE_SHIFT)
+#define I40E_VFPE_CQPTAIL(_VF) (0x00000400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_CQPTAIL_MAX_INDEX 127
+#define I40E_VFPE_CQPTAIL_WQTAIL_SHIFT 0
+#define I40E_VFPE_CQPTAIL_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL_WQTAIL_SHIFT)
+#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT 31
+#define I40E_VFPE_CQPTAIL_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL_CQP_OP_ERR_SHIFT)
+#define I40E_VFPE_IPCONFIG0(_VF) (0x00001400 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_IPCONFIG0_MAX_INDEX 127
+#define I40E_VFPE_IPCONFIG0_PEIPID_SHIFT 0
+#define I40E_VFPE_IPCONFIG0_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG0_PEIPID_SHIFT)
+#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT 16
+#define I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEENTIREIDRANGE_SHIFT)
+#define I40E_VFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT 17
+#define I40E_VFPE_IPCONFIG0_USEUPPERIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG0_USEUPPERIDRANGE_SHIFT)
+#define I40E_VFPE_MRTEIDXMASK(_VF) (0x00003000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_MRTEIDXMASK_MAX_INDEX 127
+#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT 0
+#define I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK_MRTEIDXMASKBITS_SHIFT)
+#define I40E_VFPE_RCVUNEXPECTEDERROR(_VF) (0x00003400 + ((_VF) * 4))
+#define I40E_VFPE_RCVUNEXPECTEDERROR_MAX_INDEX 127
+#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT 0
+#define I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR_TCP_RX_UNEXP_ERR_SHIFT)
+#define I40E_VFPE_TCPNOWTIMER(_VF) (0x00002C00 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_TCPNOWTIMER_MAX_INDEX 127
+#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT 0
+#define I40E_VFPE_TCPNOWTIMER_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER_TCP_NOW_SHIFT)
+#define I40E_VFPE_WQEALLOC(_VF) (0x00138000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VFPE_WQEALLOC_MAX_INDEX 127
+#define I40E_VFPE_WQEALLOC_PEQPID_SHIFT 0
+#define I40E_VFPE_WQEALLOC_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC_PEQPID_SHIFT)
+#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT 20
+#define I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC_WQE_DESC_INDEX_SHIFT)
+#define I40E_GLPES_PFIP4RXDISCARD(_i) (0x00010600 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXDISCARD_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0
+#define I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXDISCARD_IP4RXDISCARD_SHIFT)
+#define I40E_GLPES_PFIP4RXFRAGSHI(_i) (0x00010804 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXFRAGSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0
+#define I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT)
+#define I40E_GLPES_PFIP4RXFRAGSLO(_i) (0x00010800 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXFRAGSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0
+#define I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT)
+#define I40E_GLPES_PFIP4RXMCOCTSHI(_i) (0x00010A04 + ((_i) * 8))
+#define I40E_GLPES_PFIP4RXMCOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP4RXMCOCTSLO(_i) (0x00010A00 + ((_i) * 8))
+#define I40E_GLPES_PFIP4RXMCOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP4RXMCPKTSHI(_i) (0x00010C04 + ((_i) * 8))
+#define I40E_GLPES_PFIP4RXMCPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP4RXMCPKTSLO(_i) (0x00010C00 + ((_i) * 8))
+#define I40E_GLPES_PFIP4RXMCPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP4RXOCTSHI(_i) (0x00010204 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP4RXOCTSLO(_i) (0x00010200 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP4RXPKTSHI(_i) (0x00010404 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP4RXPKTSLO(_i) (0x00010400 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP4RXTRUNC(_i) (0x00010700 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4RXTRUNC_MAX_INDEX 15
+#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0
+#define I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4RXTRUNC_IP4RXTRUNC_SHIFT)
+#define I40E_GLPES_PFIP4TXFRAGSHI(_i) (0x00011E04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXFRAGSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0
+#define I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT)
+#define I40E_GLPES_PFIP4TXFRAGSLO(_i) (0x00011E00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXFRAGSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0
+#define I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT)
+#define I40E_GLPES_PFIP4TXMCOCTSHI(_i) (0x00012004 + ((_i) * 8))
+#define I40E_GLPES_PFIP4TXMCOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP4TXMCOCTSLO(_i) (0x00012000 + ((_i) * 8))
+#define I40E_GLPES_PFIP4TXMCOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP4TXMCPKTSHI(_i) (0x00012204 + ((_i) * 8))
+#define I40E_GLPES_PFIP4TXMCPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP4TXMCPKTSLO(_i) (0x00012200 + ((_i) * 8))
+#define I40E_GLPES_PFIP4TXMCPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP4TXNOROUTE(_i) (0x00012E00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXNOROUTE_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0
+#define I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT)
+#define I40E_GLPES_PFIP4TXOCTSHI(_i) (0x00011A04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP4TXOCTSLO(_i) (0x00011A00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP4TXPKTSHI(_i) (0x00011C04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP4TXPKTSLO(_i) (0x00011C00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP4TXPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP6RXDISCARD(_i) (0x00011200 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXDISCARD_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0
+#define I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXDISCARD_IP6RXDISCARD_SHIFT)
+#define I40E_GLPES_PFIP6RXFRAGSHI(_i) (0x00011404 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXFRAGSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0
+#define I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT)
+#define I40E_GLPES_PFIP6RXFRAGSLO(_i) (0x00011400 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXFRAGSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0
+#define I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT)
+#define I40E_GLPES_PFIP6RXMCOCTSHI(_i) (0x00011604 + ((_i) * 8))
+#define I40E_GLPES_PFIP6RXMCOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP6RXMCOCTSLO(_i) (0x00011600 + ((_i) * 8))
+#define I40E_GLPES_PFIP6RXMCOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP6RXMCPKTSHI(_i) (0x00011804 + ((_i) * 8))
+#define I40E_GLPES_PFIP6RXMCPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP6RXMCPKTSLO(_i) (0x00011800 + ((_i) * 8))
+#define I40E_GLPES_PFIP6RXMCPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP6RXOCTSHI(_i) (0x00010E04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP6RXOCTSLO(_i) (0x00010E00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP6RXPKTSHI(_i) (0x00011004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP6RXPKTSLO(_i) (0x00011000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP6RXTRUNC(_i) (0x00011300 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6RXTRUNC_MAX_INDEX 15
+#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0
+#define I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6RXTRUNC_IP6RXTRUNC_SHIFT)
+#define I40E_GLPES_PFIP6TXFRAGSHI(_i) (0x00012804 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXFRAGSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0
+#define I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT)
+#define I40E_GLPES_PFIP6TXFRAGSLO(_i) (0x00012800 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXFRAGSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0
+#define I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT)
+#define I40E_GLPES_PFIP6TXMCOCTSHI(_i) (0x00012A04 + ((_i) * 8))
+#define I40E_GLPES_PFIP6TXMCOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP6TXMCOCTSLO(_i) (0x00012A00 + ((_i) * 8))
+#define I40E_GLPES_PFIP6TXMCOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP6TXMCPKTSHI(_i) (0x00012C04 + ((_i) * 8))
+#define I40E_GLPES_PFIP6TXMCPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP6TXMCPKTSLO(_i) (0x00012C00 + ((_i) * 8))
+#define I40E_GLPES_PFIP6TXMCPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT)
+#define I40E_GLPES_PFIP6TXNOROUTE(_i) (0x00012F00 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXNOROUTE_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0
+#define I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_PFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT)
+#define I40E_GLPES_PFIP6TXOCTSHI(_i) (0x00012404 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXOCTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT)
+#define I40E_GLPES_PFIP6TXOCTSLO(_i) (0x00012400 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXOCTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT)
+#define I40E_GLPES_PFIP6TXPKTSHI(_i) (0x00012604 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0
+#define I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT)
+#define I40E_GLPES_PFIP6TXPKTSLO(_i) (0x00012600 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFIP6TXPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0
+#define I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT)
+#define I40E_GLPES_PFRDMARXRDSHI(_i) (0x00013E04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMARXRDSHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0
+#define I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXRDSHI_RDMARXRDSHI_SHIFT)
+#define I40E_GLPES_PFRDMARXRDSLO(_i) (0x00013E00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMARXRDSLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0
+#define I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXRDSLO_RDMARXRDSLO_SHIFT)
+#define I40E_GLPES_PFRDMARXSNDSHI(_i) (0x00014004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMARXSNDSHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0
+#define I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT)
+#define I40E_GLPES_PFRDMARXSNDSLO(_i) (0x00014000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMARXSNDSLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0
+#define I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT)
+#define I40E_GLPES_PFRDMARXWRSHI(_i) (0x00013C04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMARXWRSHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0
+#define I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMARXWRSHI_RDMARXWRSHI_SHIFT)
+#define I40E_GLPES_PFRDMARXWRSLO(_i) (0x00013C00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMARXWRSLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0
+#define I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMARXWRSLO_RDMARXWRSLO_SHIFT)
+#define I40E_GLPES_PFRDMATXRDSHI(_i) (0x00014404 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMATXRDSHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0
+#define I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXRDSHI_RDMARXRDSHI_SHIFT)
+#define I40E_GLPES_PFRDMATXRDSLO(_i) (0x00014400 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMATXRDSLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0
+#define I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXRDSLO_RDMARXRDSLO_SHIFT)
+#define I40E_GLPES_PFRDMATXSNDSHI(_i) (0x00014604 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMATXSNDSHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0
+#define I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT)
+#define I40E_GLPES_PFRDMATXSNDSLO(_i) (0x00014600 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMATXSNDSLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0
+#define I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT)
+#define I40E_GLPES_PFRDMATXWRSHI(_i) (0x00014204 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMATXWRSHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0
+#define I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_PFRDMATXWRSHI_RDMARXWRSHI_SHIFT)
+#define I40E_GLPES_PFRDMATXWRSLO(_i) (0x00014200 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMATXWRSLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0
+#define I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMATXWRSLO_RDMARXWRSLO_SHIFT)
+#define I40E_GLPES_PFRDMAVBNDHI(_i) (0x00014804 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMAVBNDHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0
+#define I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDHI_RDMAVBNDHI_SHIFT)
+#define I40E_GLPES_PFRDMAVBNDLO(_i) (0x00014800 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMAVBNDLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0
+#define I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVBNDLO_RDMAVBNDLO_SHIFT)
+#define I40E_GLPES_PFRDMAVINVHI(_i) (0x00014A04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMAVINVHI_MAX_INDEX 15
+#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT 0
+#define I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVHI_RDMAVINVHI_SHIFT)
+#define I40E_GLPES_PFRDMAVINVLO(_i) (0x00014A00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFRDMAVINVLO_MAX_INDEX 15
+#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT 0
+#define I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_PFRDMAVINVLO_RDMAVINVLO_SHIFT)
+#define I40E_GLPES_PFRXVLANERR(_i) (0x00010000 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFRXVLANERR_MAX_INDEX 15
+#define I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT 0
+#define I40E_GLPES_PFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_PFRXVLANERR_RXVLANERR_SHIFT)
+#define I40E_GLPES_PFTCPRTXSEG(_i) (0x00013600 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFTCPRTXSEG_MAX_INDEX 15
+#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT 0
+#define I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRTXSEG_TCPRTXSEG_SHIFT)
+#define I40E_GLPES_PFTCPRXOPTERR(_i) (0x00013200 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_GLPES_PFTCPRXOPTERR_MAX_INDEX 15
+#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0
+#define I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXOPTERR_TCPRXOPTERR_SHIFT)
+#define I40E_GLPES_PFTCPRXPROTOERR(_i) (0x00013300 + ((_i) * 4))
+#define I40E_GLPES_PFTCPRXPROTOERR_MAX_INDEX 15
+#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0
+#define I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_PFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT)
+#define I40E_GLPES_PFTCPRXSEGSHI(_i) (0x00013004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFTCPRXSEGSHI_MAX_INDEX 15
+#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0
+#define I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_PFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT)
+#define I40E_GLPES_PFTCPRXSEGSLO(_i) (0x00013000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFTCPRXSEGSLO_MAX_INDEX 15
+#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0
+#define I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT)
+#define I40E_GLPES_PFTCPTXSEGHI(_i) (0x00013404 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFTCPTXSEGHI_MAX_INDEX 15
+#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0
+#define I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_PFTCPTXSEGHI_TCPTXSEGHI_SHIFT)
+#define I40E_GLPES_PFTCPTXSEGLO(_i) (0x00013400 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFTCPTXSEGLO_MAX_INDEX 15
+#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0
+#define I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_PFTCPTXSEGLO_TCPTXSEGLO_SHIFT)
+#define I40E_GLPES_PFUDPRXPKTSHI(_i) (0x00013804 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFUDPRXPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0
+#define I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT)
+#define I40E_GLPES_PFUDPRXPKTSLO(_i) (0x00013800 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFUDPRXPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0
+#define I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT)
+#define I40E_GLPES_PFUDPTXPKTSHI(_i) (0x00013A04 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFUDPTXPKTSHI_MAX_INDEX 15
+#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0
+#define I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_PFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT)
+#define I40E_GLPES_PFUDPTXPKTSLO(_i) (0x00013A00 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLPES_PFUDPTXPKTSLO_MAX_INDEX 15
+#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0
+#define I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_PFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT)
+#define I40E_GLPES_RDMARXMULTFPDUSHI 0x0001E014
+#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT 0
+#define I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXMULTFPDUSHI_RDMARXMULTFPDUSHI_SHIFT)
+#define I40E_GLPES_RDMARXMULTFPDUSLO 0x0001E010
+#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT 0
+#define I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXMULTFPDUSLO_RDMARXMULTFPDUSLO_SHIFT)
+#define I40E_GLPES_RDMARXOOODDPHI 0x0001E01C
+#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT 0
+#define I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_MASK (0xFFFFFF << I40E_GLPES_RDMARXOOODDPHI_RDMARXOOODDPHI_SHIFT)
+#define I40E_GLPES_RDMARXOOODDPLO 0x0001E018
+#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT 0
+#define I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOODDPLO_RDMARXOOODDPLO_SHIFT)
+#define I40E_GLPES_RDMARXOOONOMARK 0x0001E004
+#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT 0
+#define I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXOOONOMARK_RDMAOOONOMARK_SHIFT)
+#define I40E_GLPES_RDMARXUNALIGN 0x0001E000
+#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT 0
+#define I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_MASK (0xFFFFFFFF << I40E_GLPES_RDMARXUNALIGN_RDMRXAUNALIGN_SHIFT)
+#define I40E_GLPES_TCPRXFOURHOLEHI 0x0001E044
+#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT 0
+#define I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXFOURHOLEHI_TCPRXFOURHOLEHI_SHIFT)
+#define I40E_GLPES_TCPRXFOURHOLELO 0x0001E040
+#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT 0
+#define I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXFOURHOLELO_TCPRXFOURHOLELO_SHIFT)
+#define I40E_GLPES_TCPRXONEHOLEHI 0x0001E02C
+#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT 0
+#define I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXONEHOLEHI_TCPRXONEHOLEHI_SHIFT)
+#define I40E_GLPES_TCPRXONEHOLELO 0x0001E028
+#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT 0
+#define I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXONEHOLELO_TCPRXONEHOLELO_SHIFT)
+#define I40E_GLPES_TCPRXPUREACKHI 0x0001E024
+#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT 0
+#define I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXPUREACKHI_TCPRXPUREACKSHI_SHIFT)
+#define I40E_GLPES_TCPRXPUREACKSLO 0x0001E020
+#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT 0
+#define I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXPUREACKSLO_TCPRXPUREACKLO_SHIFT)
+#define I40E_GLPES_TCPRXTHREEHOLEHI 0x0001E03C
+#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT 0
+#define I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTHREEHOLEHI_TCPRXTHREEHOLEHI_SHIFT)
+#define I40E_GLPES_TCPRXTHREEHOLELO 0x0001E038
+#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT 0
+#define I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTHREEHOLELO_TCPRXTHREEHOLELO_SHIFT)
+#define I40E_GLPES_TCPRXTWOHOLEHI 0x0001E034
+#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT 0
+#define I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_MASK (0xFFFFFF << I40E_GLPES_TCPRXTWOHOLEHI_TCPRXTWOHOLEHI_SHIFT)
+#define I40E_GLPES_TCPRXTWOHOLELO 0x0001E030
+#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT 0
+#define I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_MASK (0xFFFFFFFF << I40E_GLPES_TCPRXTWOHOLELO_TCPRXTWOHOLELO_SHIFT)
+#define I40E_GLPES_TCPRXUNEXPERR 0x0001E008
+#define I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_SHIFT 0
+#define I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_MASK (0xFFFFFF << I40E_GLPES_TCPRXUNEXPERR_TCPRXUNEXPERR_SHIFT)
+#define I40E_GLPES_TCPTXRETRANSFASTHI 0x0001E04C
+#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT 0
+#define I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXRETRANSFASTHI_TCPTXRETRANSFASTHI_SHIFT)
+#define I40E_GLPES_TCPTXRETRANSFASTLO 0x0001E048
+#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT 0
+#define I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXRETRANSFASTLO_TCPTXRETRANSFASTLO_SHIFT)
+#define I40E_GLPES_TCPTXTOUTSFASTHI 0x0001E054
+#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT 0
+#define I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSFASTHI_TCPTXTOUTSFASTHI_SHIFT)
+#define I40E_GLPES_TCPTXTOUTSFASTLO 0x0001E050
+#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT 0
+#define I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSFASTLO_TCPTXTOUTSFASTLO_SHIFT)
+#define I40E_GLPES_TCPTXTOUTSHI 0x0001E05C
+#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT 0
+#define I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_MASK (0xFFFFFF << I40E_GLPES_TCPTXTOUTSHI_TCPTXTOUTSHI_SHIFT)
+#define I40E_GLPES_TCPTXTOUTSLO 0x0001E058
+#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT 0
+#define I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_MASK (0xFFFFFFFF << I40E_GLPES_TCPTXTOUTSLO_TCPTXTOUTSLO_SHIFT)
+#define I40E_GLPES_VFIP4RXDISCARD(_i) (0x00018600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXDISCARD_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT 0
+#define I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXDISCARD_IP4RXDISCARD_SHIFT)
+#define I40E_GLPES_VFIP4RXFRAGSHI(_i) (0x00018804 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXFRAGSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT 0
+#define I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXFRAGSHI_IP4RXFRAGSHI_SHIFT)
+#define I40E_GLPES_VFIP4RXFRAGSLO(_i) (0x00018800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXFRAGSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT 0
+#define I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXFRAGSLO_IP4RXFRAGSLO_SHIFT)
+#define I40E_GLPES_VFIP4RXMCOCTSHI(_i) (0x00018A04 + ((_i) * 4))
+#define I40E_GLPES_VFIP4RXMCOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCOCTSHI_IP4RXMCOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP4RXMCOCTSLO(_i) (0x00018A00 + ((_i) * 4))
+#define I40E_GLPES_VFIP4RXMCOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCOCTSLO_IP4RXMCOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP4RXMCPKTSHI(_i) (0x00018C04 + ((_i) * 4))
+#define I40E_GLPES_VFIP4RXMCPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXMCPKTSHI_IP4RXMCPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP4RXMCPKTSLO(_i) (0x00018C00 + ((_i) * 4))
+#define I40E_GLPES_VFIP4RXMCPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXMCPKTSLO_IP4RXMCPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP4RXOCTSHI(_i) (0x00018204 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXOCTSHI_IP4RXOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP4RXOCTSLO(_i) (0x00018200 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXOCTSLO_IP4RXOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP4RXPKTSHI(_i) (0x00018404 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4RXPKTSHI_IP4RXPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP4RXPKTSLO(_i) (0x00018400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXPKTSLO_IP4RXPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP4RXTRUNC(_i) (0x00018700 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4RXTRUNC_MAX_INDEX 31
+#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT 0
+#define I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4RXTRUNC_IP4RXTRUNC_SHIFT)
+#define I40E_GLPES_VFIP4TXFRAGSHI(_i) (0x00019E04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXFRAGSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT 0
+#define I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXFRAGSHI_IP4TXFRAGSHI_SHIFT)
+#define I40E_GLPES_VFIP4TXFRAGSLO(_i) (0x00019E00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXFRAGSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT 0
+#define I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXFRAGSLO_IP4TXFRAGSLO_SHIFT)
+#define I40E_GLPES_VFIP4TXMCOCTSHI(_i) (0x0001A004 + ((_i) * 4))
+#define I40E_GLPES_VFIP4TXMCOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCOCTSHI_IP4TXMCOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP4TXMCOCTSLO(_i) (0x0001A000 + ((_i) * 4))
+#define I40E_GLPES_VFIP4TXMCOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCOCTSLO_IP4TXMCOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP4TXMCPKTSHI(_i) (0x0001A204 + ((_i) * 4))
+#define I40E_GLPES_VFIP4TXMCPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXMCPKTSHI_IP4TXMCPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP4TXMCPKTSLO(_i) (0x0001A200 + ((_i) * 4))
+#define I40E_GLPES_VFIP4TXMCPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXMCPKTSLO_IP4TXMCPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP4TXNOROUTE(_i) (0x0001AE00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXNOROUTE_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT 0
+#define I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP4TXNOROUTE_IP4TXNOROUTE_SHIFT)
+#define I40E_GLPES_VFIP4TXOCTSHI(_i) (0x00019A04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXOCTSHI_IP4TXOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP4TXOCTSLO(_i) (0x00019A00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXOCTSLO_IP4TXOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP4TXPKTSHI(_i) (0x00019C04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP4TXPKTSHI_IP4TXPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP4TXPKTSLO(_i) (0x00019C00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP4TXPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP4TXPKTSLO_IP4TXPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP6RXDISCARD(_i) (0x00019200 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXDISCARD_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT 0
+#define I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXDISCARD_IP6RXDISCARD_SHIFT)
+#define I40E_GLPES_VFIP6RXFRAGSHI(_i) (0x00019404 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXFRAGSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT 0
+#define I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXFRAGSHI_IP6RXFRAGSHI_SHIFT)
+#define I40E_GLPES_VFIP6RXFRAGSLO(_i) (0x00019400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXFRAGSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT 0
+#define I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXFRAGSLO_IP6RXFRAGSLO_SHIFT)
+#define I40E_GLPES_VFIP6RXMCOCTSHI(_i) (0x00019604 + ((_i) * 4))
+#define I40E_GLPES_VFIP6RXMCOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCOCTSHI_IP6RXMCOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP6RXMCOCTSLO(_i) (0x00019600 + ((_i) * 4))
+#define I40E_GLPES_VFIP6RXMCOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCOCTSLO_IP6RXMCOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP6RXMCPKTSHI(_i) (0x00019804 + ((_i) * 4))
+#define I40E_GLPES_VFIP6RXMCPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXMCPKTSHI_IP6RXMCPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP6RXMCPKTSLO(_i) (0x00019800 + ((_i) * 4))
+#define I40E_GLPES_VFIP6RXMCPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXMCPKTSLO_IP6RXMCPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP6RXOCTSHI(_i) (0x00018E04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXOCTSHI_IP6RXOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP6RXOCTSLO(_i) (0x00018E00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXOCTSLO_IP6RXOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP6RXPKTSHI(_i) (0x00019004 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6RXPKTSHI_IP6RXPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP6RXPKTSLO(_i) (0x00019000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXPKTSLO_IP6RXPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP6RXTRUNC(_i) (0x00019300 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6RXTRUNC_MAX_INDEX 31
+#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT 0
+#define I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6RXTRUNC_IP6RXTRUNC_SHIFT)
+#define I40E_GLPES_VFIP6TXFRAGSHI(_i) (0x0001A804 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXFRAGSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT 0
+#define I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXFRAGSHI_IP6TXFRAGSHI_SHIFT)
+#define I40E_GLPES_VFIP6TXFRAGSLO(_i) (0x0001A800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXFRAGSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT 0
+#define I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXFRAGSLO_IP6TXFRAGSLO_SHIFT)
+#define I40E_GLPES_VFIP6TXMCOCTSHI(_i) (0x0001AA04 + ((_i) * 4))
+#define I40E_GLPES_VFIP6TXMCOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCOCTSHI_IP6TXMCOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP6TXMCOCTSLO(_i) (0x0001AA00 + ((_i) * 4))
+#define I40E_GLPES_VFIP6TXMCOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCOCTSLO_IP6TXMCOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP6TXMCPKTSHI(_i) (0x0001AC04 + ((_i) * 4))
+#define I40E_GLPES_VFIP6TXMCPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXMCPKTSHI_IP6TXMCPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP6TXMCPKTSLO(_i) (0x0001AC00 + ((_i) * 4))
+#define I40E_GLPES_VFIP6TXMCPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXMCPKTSLO_IP6TXMCPKTSLO_SHIFT)
+#define I40E_GLPES_VFIP6TXNOROUTE(_i) (0x0001AF00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXNOROUTE_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT 0
+#define I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_MASK (0xFFFFFF << I40E_GLPES_VFIP6TXNOROUTE_IP6TXNOROUTE_SHIFT)
+#define I40E_GLPES_VFIP6TXOCTSHI(_i) (0x0001A404 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXOCTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXOCTSHI_IP6TXOCTSHI_SHIFT)
+#define I40E_GLPES_VFIP6TXOCTSLO(_i) (0x0001A400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXOCTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXOCTSLO_IP6TXOCTSLO_SHIFT)
+#define I40E_GLPES_VFIP6TXPKTSHI(_i) (0x0001A604 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT 0
+#define I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFIP6TXPKTSHI_IP6TXPKTSHI_SHIFT)
+#define I40E_GLPES_VFIP6TXPKTSLO(_i) (0x0001A600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFIP6TXPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT 0
+#define I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFIP6TXPKTSLO_IP6TXPKTSLO_SHIFT)
+#define I40E_GLPES_VFRDMARXRDSHI(_i) (0x0001BE04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMARXRDSHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT 0
+#define I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXRDSHI_RDMARXRDSHI_SHIFT)
+#define I40E_GLPES_VFRDMARXRDSLO(_i) (0x0001BE00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMARXRDSLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT 0
+#define I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXRDSLO_RDMARXRDSLO_SHIFT)
+#define I40E_GLPES_VFRDMARXSNDSHI(_i) (0x0001C004 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMARXSNDSHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT 0
+#define I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXSNDSHI_RDMARXSNDSHI_SHIFT)
+#define I40E_GLPES_VFRDMARXSNDSLO(_i) (0x0001C000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMARXSNDSLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT 0
+#define I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXSNDSLO_RDMARXSNDSLO_SHIFT)
+#define I40E_GLPES_VFRDMARXWRSHI(_i) (0x0001BC04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMARXWRSHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT 0
+#define I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMARXWRSHI_RDMARXWRSHI_SHIFT)
+#define I40E_GLPES_VFRDMARXWRSLO(_i) (0x0001BC00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMARXWRSLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT 0
+#define I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMARXWRSLO_RDMARXWRSLO_SHIFT)
+#define I40E_GLPES_VFRDMATXRDSHI(_i) (0x0001C404 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMATXRDSHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT 0
+#define I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXRDSHI_RDMARXRDSHI_SHIFT)
+#define I40E_GLPES_VFRDMATXRDSLO(_i) (0x0001C400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMATXRDSLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT 0
+#define I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXRDSLO_RDMARXRDSLO_SHIFT)
+#define I40E_GLPES_VFRDMATXSNDSHI(_i) (0x0001C604 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMATXSNDSHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT 0
+#define I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXSNDSHI_RDMARXSNDSHI_SHIFT)
+#define I40E_GLPES_VFRDMATXSNDSLO(_i) (0x0001C600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMATXSNDSLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT 0
+#define I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXSNDSLO_RDMARXSNDSLO_SHIFT)
+#define I40E_GLPES_VFRDMATXWRSHI(_i) (0x0001C204 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMATXWRSHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT 0
+#define I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_MASK (0xFFFF << I40E_GLPES_VFRDMATXWRSHI_RDMARXWRSHI_SHIFT)
+#define I40E_GLPES_VFRDMATXWRSLO(_i) (0x0001C200 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMATXWRSLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT 0
+#define I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMATXWRSLO_RDMARXWRSLO_SHIFT)
+#define I40E_GLPES_VFRDMAVBNDHI(_i) (0x0001C804 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMAVBNDHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT 0
+#define I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDHI_RDMAVBNDHI_SHIFT)
+#define I40E_GLPES_VFRDMAVBNDLO(_i) (0x0001C800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMAVBNDLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT 0
+#define I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVBNDLO_RDMAVBNDLO_SHIFT)
+#define I40E_GLPES_VFRDMAVINVHI(_i) (0x0001CA04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMAVINVHI_MAX_INDEX 31
+#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT 0
+#define I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVHI_RDMAVINVHI_SHIFT)
+#define I40E_GLPES_VFRDMAVINVLO(_i) (0x0001CA00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRDMAVINVLO_MAX_INDEX 31
+#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT 0
+#define I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_MASK (0xFFFFFFFF << I40E_GLPES_VFRDMAVINVLO_RDMAVINVLO_SHIFT)
+#define I40E_GLPES_VFRXVLANERR(_i) (0x00018000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFRXVLANERR_MAX_INDEX 31
+#define I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT 0
+#define I40E_GLPES_VFRXVLANERR_RXVLANERR_MASK (0xFFFFFF << I40E_GLPES_VFRXVLANERR_RXVLANERR_SHIFT)
+#define I40E_GLPES_VFTCPRTXSEG(_i) (0x0001B600 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFTCPRTXSEG_MAX_INDEX 31
+#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT 0
+#define I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRTXSEG_TCPRTXSEG_SHIFT)
+#define I40E_GLPES_VFTCPRXOPTERR(_i) (0x0001B200 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFTCPRXOPTERR_MAX_INDEX 31
+#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT 0
+#define I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXOPTERR_TCPRXOPTERR_SHIFT)
+#define I40E_GLPES_VFTCPRXPROTOERR(_i) (0x0001B300 + ((_i) * 4))
+#define I40E_GLPES_VFTCPRXPROTOERR_MAX_INDEX 31
+#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT 0
+#define I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_MASK (0xFFFFFF << I40E_GLPES_VFTCPRXPROTOERR_TCPRXPROTOERR_SHIFT)
+#define I40E_GLPES_VFTCPRXSEGSHI(_i) (0x0001B004 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFTCPRXSEGSHI_MAX_INDEX 31
+#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT 0
+#define I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_MASK (0xFFFF << I40E_GLPES_VFTCPRXSEGSHI_TCPRXSEGSHI_SHIFT)
+#define I40E_GLPES_VFTCPRXSEGSLO(_i) (0x0001B000 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFTCPRXSEGSLO_MAX_INDEX 31
+#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT 0
+#define I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPRXSEGSLO_TCPRXSEGSLO_SHIFT)
+#define I40E_GLPES_VFTCPTXSEGHI(_i) (0x0001B404 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFTCPTXSEGHI_MAX_INDEX 31
+#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT 0
+#define I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_MASK (0xFFFF << I40E_GLPES_VFTCPTXSEGHI_TCPTXSEGHI_SHIFT)
+#define I40E_GLPES_VFTCPTXSEGLO(_i) (0x0001B400 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFTCPTXSEGLO_MAX_INDEX 31
+#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT 0
+#define I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_MASK (0xFFFFFFFF << I40E_GLPES_VFTCPTXSEGLO_TCPTXSEGLO_SHIFT)
+#define I40E_GLPES_VFUDPRXPKTSHI(_i) (0x0001B804 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFUDPRXPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT 0
+#define I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPRXPKTSHI_UDPRXPKTSHI_SHIFT)
+#define I40E_GLPES_VFUDPRXPKTSLO(_i) (0x0001B800 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFUDPRXPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT 0
+#define I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPRXPKTSLO_UDPRXPKTSLO_SHIFT)
+#define I40E_GLPES_VFUDPTXPKTSHI(_i) (0x0001BA04 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFUDPTXPKTSHI_MAX_INDEX 31
+#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT 0
+#define I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_MASK (0xFFFF << I40E_GLPES_VFUDPTXPKTSHI_UDPTXPKTSHI_SHIFT)
+#define I40E_GLPES_VFUDPTXPKTSLO(_i) (0x0001BA00 + ((_i) * 4)) /* _i=0...31 */
+#define I40E_GLPES_VFUDPTXPKTSLO_MAX_INDEX 31
+#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT 0
+#define I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_MASK (0xFFFFFFFF << I40E_GLPES_VFUDPTXPKTSLO_UDPTXPKTSLO_SHIFT)
+#define I40E_GLPM_DMACR 0x000881F4
+#define I40E_GLPM_DMACR_DMACWT_SHIFT 0
+#define I40E_GLPM_DMACR_DMACWT_MASK (0xFFFF << I40E_GLPM_DMACR_DMACWT_SHIFT)
+#define I40E_GLPM_DMACR_EXIT_DC_SHIFT 29
+#define I40E_GLPM_DMACR_EXIT_DC_MASK (0x1 << I40E_GLPM_DMACR_EXIT_DC_SHIFT)
+#define I40E_GLPM_DMACR_LX_COALESCING_INDICATION_SHIFT 30
+#define I40E_GLPM_DMACR_LX_COALESCING_INDICATION_MASK (0x1 << I40E_GLPM_DMACR_LX_COALESCING_INDICATION_SHIFT)
+#define I40E_GLPM_DMACR_DMAC_EN_SHIFT 31
+#define I40E_GLPM_DMACR_DMAC_EN_MASK (0x1 << I40E_GLPM_DMACR_DMAC_EN_SHIFT)
+#define I40E_GLPM_LTRC 0x000BE500
+#define I40E_GLPM_LTRC_SLTRV_SHIFT 0
+#define I40E_GLPM_LTRC_SLTRV_MASK (0x3FF << I40E_GLPM_LTRC_SLTRV_SHIFT)
+#define I40E_GLPM_LTRC_SSCALE_SHIFT 10
+#define I40E_GLPM_LTRC_SSCALE_MASK (0x7 << I40E_GLPM_LTRC_SSCALE_SHIFT)
+#define I40E_GLPM_LTRC_LTRS_REQUIREMENT_SHIFT 15
+#define I40E_GLPM_LTRC_LTRS_REQUIREMENT_MASK (0x1 << I40E_GLPM_LTRC_LTRS_REQUIREMENT_SHIFT)
+#define I40E_GLPM_LTRC_NSLTRV_SHIFT 16
+#define I40E_GLPM_LTRC_NSLTRV_MASK (0x3FF << I40E_GLPM_LTRC_NSLTRV_SHIFT)
+#define I40E_GLPM_LTRC_NSSCALE_SHIFT 26
+#define I40E_GLPM_LTRC_NSSCALE_MASK (0x7 << I40E_GLPM_LTRC_NSSCALE_SHIFT)
+#define I40E_GLPM_LTRC_LTR_SEND_SHIFT 30
+#define I40E_GLPM_LTRC_LTR_SEND_MASK (0x1 << I40E_GLPM_LTRC_LTR_SEND_SHIFT)
+#define I40E_GLPM_LTRC_LTRNS_REQUIREMENT_SHIFT 31
+#define I40E_GLPM_LTRC_LTRNS_REQUIREMENT_MASK (0x1 << I40E_GLPM_LTRC_LTRNS_REQUIREMENT_SHIFT)
+#define I40E_PRTPM_EEE_STAT 0x001E4320
+#define I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT 29
+#define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK (0x1 << I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT)
+#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT 30
+#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK (0x1 << I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT)
+#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT 31
+#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK (0x1 << I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT)
+#define I40E_PRTPM_EEEC 0x001E4380
+#define I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT 16
+#define I40E_PRTPM_EEEC_TW_WAKE_MIN_MASK (0x3F << I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT)
+#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT 24
+#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_MASK (0x3 << I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT)
+#define I40E_PRTPM_EEEC_TEEE_DLY_SHIFT 26
+#define I40E_PRTPM_EEEC_TEEE_DLY_MASK (0x3F << I40E_PRTPM_EEEC_TEEE_DLY_SHIFT)
+#define I40E_PRTPM_EEEFWD 0x001E4400
+#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT 31
+#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_MASK (0x1 << I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT)
+#define I40E_PRTPM_EEER 0x001E4360
+#define I40E_PRTPM_EEER_TW_SYSTEM_SHIFT 0
+#define I40E_PRTPM_EEER_TW_SYSTEM_MASK (0xFFFF << I40E_PRTPM_EEER_TW_SYSTEM_SHIFT)
+#define I40E_PRTPM_EEER_TX_LPI_EN_SHIFT 16
+#define I40E_PRTPM_EEER_TX_LPI_EN_MASK (0x1 << I40E_PRTPM_EEER_TX_LPI_EN_SHIFT)
+#define I40E_PRTPM_EEETXC 0x001E43E0
+#define I40E_PRTPM_EEETXC_TW_PHY_SHIFT 0
+#define I40E_PRTPM_EEETXC_TW_PHY_MASK (0xFFFF << I40E_PRTPM_EEETXC_TW_PHY_SHIFT)
+#define I40E_PRTPM_GC 0x000B8140
+#define I40E_PRTPM_GC_EMP_LINK_ON_SHIFT 0
+#define I40E_PRTPM_GC_EMP_LINK_ON_MASK (0x1 << I40E_PRTPM_GC_EMP_LINK_ON_SHIFT)
+#define I40E_PRTPM_GC_MNG_VETO_SHIFT 1
+#define I40E_PRTPM_GC_MNG_VETO_MASK (0x1 << I40E_PRTPM_GC_MNG_VETO_SHIFT)
+#define I40E_PRTPM_GC_RATD_SHIFT 2
+#define I40E_PRTPM_GC_RATD_MASK (0x1 << I40E_PRTPM_GC_RATD_SHIFT)
+#define I40E_PRTPM_GC_LCDMP_SHIFT 3
+#define I40E_PRTPM_GC_LCDMP_MASK (0x1 << I40E_PRTPM_GC_LCDMP_SHIFT)
+#define I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT 31
+#define I40E_PRTPM_GC_LPLU_ASSERTED_MASK (0x1 << I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT)
+#define I40E_PRTPM_HPTC 0x000AC800
+#define I40E_PRTPM_HPTC_HIGH_PRI_TC_SHIFT 0
+#define I40E_PRTPM_HPTC_HIGH_PRI_TC_MASK (0xFF << I40E_PRTPM_HPTC_HIGH_PRI_TC_SHIFT)
+#define I40E_PRTPM_RLPIC 0x001E43A0
+#define I40E_PRTPM_RLPIC_ERLPIC_SHIFT 0
+#define I40E_PRTPM_RLPIC_ERLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_RLPIC_ERLPIC_SHIFT)
+#define I40E_PRTPM_TLPIC 0x001E43C0
+#define I40E_PRTPM_TLPIC_ETLPIC_SHIFT 0
+#define I40E_PRTPM_TLPIC_ETLPIC_MASK (0xFFFFFFFF << I40E_PRTPM_TLPIC_ETLPIC_SHIFT)
+#define I40E_GLRPB_DPSS 0x000AC828
+#define I40E_GLRPB_DPSS_DPS_TCN_SHIFT 0
+#define I40E_GLRPB_DPSS_DPS_TCN_MASK (0xFFFFF << I40E_GLRPB_DPSS_DPS_TCN_SHIFT)
+#define I40E_GLRPB_GHW 0x000AC830
+#define I40E_GLRPB_GHW_GHW_SHIFT 0
+#define I40E_GLRPB_GHW_GHW_MASK (0xFFFFF << I40E_GLRPB_GHW_GHW_SHIFT)
+#define I40E_GLRPB_GLW 0x000AC834
+#define I40E_GLRPB_GLW_GLW_SHIFT 0
+#define I40E_GLRPB_GLW_GLW_MASK (0xFFFFF << I40E_GLRPB_GLW_GLW_SHIFT)
+#define I40E_GLRPB_PHW 0x000AC844
+#define I40E_GLRPB_PHW_PHW_SHIFT 0
+#define I40E_GLRPB_PHW_PHW_MASK (0xFFFFF << I40E_GLRPB_PHW_PHW_SHIFT)
+#define I40E_GLRPB_PLW 0x000AC848
+#define I40E_GLRPB_PLW_PLW_SHIFT 0
+#define I40E_GLRPB_PLW_PLW_MASK (0xFFFFF << I40E_GLRPB_PLW_PLW_SHIFT)
+#define I40E_PRTRPB_DHW(_i) (0x000AC100 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTRPB_DHW_MAX_INDEX 7
+#define I40E_PRTRPB_DHW_DHW_TCN_SHIFT 0
+#define I40E_PRTRPB_DHW_DHW_TCN_MASK (0xFFFFF << I40E_PRTRPB_DHW_DHW_TCN_SHIFT)
+#define I40E_PRTRPB_DLW(_i) (0x000AC220 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTRPB_DLW_MAX_INDEX 7
+#define I40E_PRTRPB_DLW_DLW_TCN_SHIFT 0
+#define I40E_PRTRPB_DLW_DLW_TCN_MASK (0xFFFFF << I40E_PRTRPB_DLW_DLW_TCN_SHIFT)
+#define I40E_PRTRPB_DPS(_i) (0x000AC320 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTRPB_DPS_MAX_INDEX 7
+#define I40E_PRTRPB_DPS_DPS_TCN_SHIFT 0
+#define I40E_PRTRPB_DPS_DPS_TCN_MASK (0xFFFFF << I40E_PRTRPB_DPS_DPS_TCN_SHIFT)
+#define I40E_PRTRPB_SHT(_i) (0x000AC480 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTRPB_SHT_MAX_INDEX 7
+#define I40E_PRTRPB_SHT_SHT_TCN_SHIFT 0
+#define I40E_PRTRPB_SHT_SHT_TCN_MASK (0xFFFFF << I40E_PRTRPB_SHT_SHT_TCN_SHIFT)
+#define I40E_PRTRPB_SHW 0x000AC580
+#define I40E_PRTRPB_SHW_SHW_SHIFT 0
+#define I40E_PRTRPB_SHW_SHW_MASK (0xFFFFF << I40E_PRTRPB_SHW_SHW_SHIFT)
+#define I40E_PRTRPB_SLT(_i) (0x000AC5A0 + ((_i) * 32)) /* _i=0...7 */
+#define I40E_PRTRPB_SLT_MAX_INDEX 7
+#define I40E_PRTRPB_SLT_SLT_TCN_SHIFT 0
+#define I40E_PRTRPB_SLT_SLT_TCN_MASK (0xFFFFF << I40E_PRTRPB_SLT_SLT_TCN_SHIFT)
+#define I40E_PRTRPB_SLW 0x000AC6A0
+#define I40E_PRTRPB_SLW_SLW_SHIFT 0
+#define I40E_PRTRPB_SLW_SLW_MASK (0xFFFFF << I40E_PRTRPB_SLW_SLW_SHIFT)
+#define I40E_PRTRPB_SPS 0x000AC7C0
+#define I40E_PRTRPB_SPS_SPS_SHIFT 0
+#define I40E_PRTRPB_SPS_SPS_MASK (0xFFFFF << I40E_PRTRPB_SPS_SPS_SHIFT)
+#define I40E_GLQF_APBVT(_i) (0x00260000 + ((_i) * 4)) /* _i=0...2047 */
+#define I40E_GLQF_APBVT_MAX_INDEX 2047
+#define I40E_GLQF_APBVT_APBVT_SHIFT 0
+#define I40E_GLQF_APBVT_APBVT_MASK (0xFFFFFFFF << I40E_GLQF_APBVT_APBVT_SHIFT)
+#define I40E_GLQF_CTL 0x00269BA4
+#define I40E_GLQF_CTL_HTOEP_SHIFT 1
+#define I40E_GLQF_CTL_HTOEP_MASK (0x1 << I40E_GLQF_CTL_HTOEP_SHIFT)
+#define I40E_GLQF_CTL_HTOEP_FCOE_SHIFT 2
+#define I40E_GLQF_CTL_HTOEP_FCOE_MASK (0x1 << I40E_GLQF_CTL_HTOEP_FCOE_SHIFT)
+#define I40E_GLQF_CTL_PCNT_ALLOC_SHIFT 3
+#define I40E_GLQF_CTL_PCNT_ALLOC_MASK (0x7 << I40E_GLQF_CTL_PCNT_ALLOC_SHIFT)
+#define I40E_GLQF_CTL_DDPLPEN_SHIFT 7
+#define I40E_GLQF_CTL_DDPLPEN_MASK (0x1 << I40E_GLQF_CTL_DDPLPEN_SHIFT)
+#define I40E_GLQF_CTL_MAXPEBLEN_SHIFT 8
+#define I40E_GLQF_CTL_MAXPEBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXPEBLEN_SHIFT)
+#define I40E_GLQF_CTL_MAXFCBLEN_SHIFT 11
+#define I40E_GLQF_CTL_MAXFCBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXFCBLEN_SHIFT)
+#define I40E_GLQF_CTL_MAXFDBLEN_SHIFT 14
+#define I40E_GLQF_CTL_MAXFDBLEN_MASK (0x7 << I40E_GLQF_CTL_MAXFDBLEN_SHIFT)
+#define I40E_GLQF_CTL_FDBEST_SHIFT 17
+#define I40E_GLQF_CTL_FDBEST_MASK (0xFF << I40E_GLQF_CTL_FDBEST_SHIFT)
+#define I40E_GLQF_CTL_PROGPRIO_SHIFT 25
+#define I40E_GLQF_CTL_PROGPRIO_MASK (0x1 << I40E_GLQF_CTL_PROGPRIO_SHIFT)
+#define I40E_GLQF_CTL_INVALPRIO_SHIFT 26
+#define I40E_GLQF_CTL_INVALPRIO_MASK (0x1 << I40E_GLQF_CTL_INVALPRIO_SHIFT)
+#define I40E_GLQF_CTL_IGNORE_IP_SHIFT 27
+#define I40E_GLQF_CTL_IGNORE_IP_MASK (0x1 << I40E_GLQF_CTL_IGNORE_IP_SHIFT)
+#define I40E_GLQF_FDCNT_0 0x00269BAC
+#define I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT 0
+#define I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK (0x1FFF << I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT)
+#define I40E_GLQF_FDCNT_0_BESTCNT_SHIFT 13
+#define I40E_GLQF_FDCNT_0_BESTCNT_MASK (0x1FFF << I40E_GLQF_FDCNT_0_BESTCNT_SHIFT)
+#define I40E_GLQF_HSYM(_i) (0x00269D00 + ((_i) * 4)) /* _i=0...63 */
+#define I40E_GLQF_HSYM_MAX_INDEX 63
+#define I40E_GLQF_HSYM_SYMH_ENA_SHIFT 0
+#define I40E_GLQF_HSYM_SYMH_ENA_MASK (0x1 << I40E_GLQF_HSYM_SYMH_ENA_SHIFT)
+#define I40E_GLQF_PCNT(_i) (0x00266800 + ((_i) * 4)) /* _i=0...511 */
+#define I40E_GLQF_PCNT_MAX_INDEX 511
+#define I40E_GLQF_PCNT_PCNT_SHIFT 0
+#define I40E_GLQF_PCNT_PCNT_MASK (0xFFFFFFFF << I40E_GLQF_PCNT_PCNT_SHIFT)
+#define I40E_GLQF_SWAP(_i, _j) (0x00267E00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */
+#define I40E_GLQF_SWAP_MAX_INDEX 1
+#define I40E_GLQF_SWAP_OFF0_SRC0_SHIFT 0
+#define I40E_GLQF_SWAP_OFF0_SRC0_MASK (0x3F << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT)
+#define I40E_GLQF_SWAP_OFF0_SRC1_SHIFT 6
+#define I40E_GLQF_SWAP_OFF0_SRC1_MASK (0x3F << I40E_GLQF_SWAP_OFF0_SRC1_SHIFT)
+#define I40E_GLQF_SWAP_FLEN0_SHIFT 12
+#define I40E_GLQF_SWAP_FLEN0_MASK (0xF << I40E_GLQF_SWAP_FLEN0_SHIFT)
+#define I40E_GLQF_SWAP_OFF1_SRC0_SHIFT 16
+#define I40E_GLQF_SWAP_OFF1_SRC0_MASK (0x3F << I40E_GLQF_SWAP_OFF1_SRC0_SHIFT)
+#define I40E_GLQF_SWAP_OFF1_SRC1_SHIFT 22
+#define I40E_GLQF_SWAP_OFF1_SRC1_MASK (0x3F << I40E_GLQF_SWAP_OFF1_SRC1_SHIFT)
+#define I40E_GLQF_SWAP_FLEN1_SHIFT 28
+#define I40E_GLQF_SWAP_FLEN1_MASK (0xF << I40E_GLQF_SWAP_FLEN1_SHIFT)
+#define I40E_PFQF_CTL_0 0x001C0AC0
+#define I40E_PFQF_CTL_0_PEHSIZE_SHIFT 0
+#define I40E_PFQF_CTL_0_PEHSIZE_MASK (0x1F << I40E_PFQF_CTL_0_PEHSIZE_SHIFT)
+#define I40E_PFQF_CTL_0_PEDSIZE_SHIFT 5
+#define I40E_PFQF_CTL_0_PEDSIZE_MASK (0x1F << I40E_PFQF_CTL_0_PEDSIZE_SHIFT)
+#define I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT 10
+#define I40E_PFQF_CTL_0_PFFCHSIZE_MASK (0xF << I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT)
+#define I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT 14
+#define I40E_PFQF_CTL_0_PFFCDSIZE_MASK (0x3 << I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT)
+#define I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT 16
+#define I40E_PFQF_CTL_0_HASHLUTSIZE_MASK (0x1 << I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT)
+#define I40E_PFQF_CTL_0_FD_ENA_SHIFT 17
+#define I40E_PFQF_CTL_0_FD_ENA_MASK (0x1 << I40E_PFQF_CTL_0_FD_ENA_SHIFT)
+#define I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT 18
+#define I40E_PFQF_CTL_0_ETYPE_ENA_MASK (0x1 << I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT)
+#define I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT 19
+#define I40E_PFQF_CTL_0_MACVLAN_ENA_MASK (0x1 << I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT)
+#define I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT 20
+#define I40E_PFQF_CTL_0_VFFCHSIZE_MASK (0xF << I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT)
+#define I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT 24
+#define I40E_PFQF_CTL_0_VFFCDSIZE_MASK (0x3 << I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT)
+#define I40E_PFQF_CTL_1 0x00245D80
+#define I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT 0
+#define I40E_PFQF_CTL_1_CLEARFDTABLE_MASK (0x1 << I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT)
+#define I40E_PFQF_FDALLOC 0x00246280
+#define I40E_PFQF_FDALLOC_FDALLOC_SHIFT 0
+#define I40E_PFQF_FDALLOC_FDALLOC_MASK (0xFF << I40E_PFQF_FDALLOC_FDALLOC_SHIFT)
+#define I40E_PFQF_FDALLOC_FDBEST_SHIFT 8
+#define I40E_PFQF_FDALLOC_FDBEST_MASK (0xFF << I40E_PFQF_FDALLOC_FDBEST_SHIFT)
+#define I40E_PFQF_FDSTAT 0x00246380
+#define I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT 0
+#define I40E_PFQF_FDSTAT_GUARANT_CNT_MASK (0x1FFF << I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT)
+#define I40E_PFQF_FDSTAT_BEST_CNT_SHIFT 16
+#define I40E_PFQF_FDSTAT_BEST_CNT_MASK (0x1FFF << I40E_PFQF_FDSTAT_BEST_CNT_SHIFT)
+#define I40E_PFQF_HENA(_i) (0x00245900 + ((_i) * 128)) /* _i=0...1 */
+#define I40E_PFQF_HENA_MAX_INDEX 1
+#define I40E_PFQF_HENA_PTYPE_ENA_SHIFT 0
+#define I40E_PFQF_HENA_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_PFQF_HENA_PTYPE_ENA_SHIFT)
+#define I40E_PFQF_HKEY(_i) (0x00244800 + ((_i) * 128)) /* _i=0...12 */
+#define I40E_PFQF_HKEY_MAX_INDEX 12
+#define I40E_PFQF_HKEY_KEY_0_SHIFT 0
+#define I40E_PFQF_HKEY_KEY_0_MASK (0xFF << I40E_PFQF_HKEY_KEY_0_SHIFT)
+#define I40E_PFQF_HKEY_KEY_1_SHIFT 8
+#define I40E_PFQF_HKEY_KEY_1_MASK (0xFF << I40E_PFQF_HKEY_KEY_1_SHIFT)
+#define I40E_PFQF_HKEY_KEY_2_SHIFT 16
+#define I40E_PFQF_HKEY_KEY_2_MASK (0xFF << I40E_PFQF_HKEY_KEY_2_SHIFT)
+#define I40E_PFQF_HKEY_KEY_3_SHIFT 24
+#define I40E_PFQF_HKEY_KEY_3_MASK (0xFF << I40E_PFQF_HKEY_KEY_3_SHIFT)
+#define I40E_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */
+#define I40E_PFQF_HLUT_MAX_INDEX 127
+#define I40E_PFQF_HLUT_LUT0_SHIFT 0
+#define I40E_PFQF_HLUT_LUT0_MASK (0x3F << I40E_PFQF_HLUT_LUT0_SHIFT)
+#define I40E_PFQF_HLUT_LUT1_SHIFT 8
+#define I40E_PFQF_HLUT_LUT1_MASK (0x3F << I40E_PFQF_HLUT_LUT1_SHIFT)
+#define I40E_PFQF_HLUT_LUT2_SHIFT 16
+#define I40E_PFQF_HLUT_LUT2_MASK (0x3F << I40E_PFQF_HLUT_LUT2_SHIFT)
+#define I40E_PFQF_HLUT_LUT3_SHIFT 24
+#define I40E_PFQF_HLUT_LUT3_MASK (0x3F << I40E_PFQF_HLUT_LUT3_SHIFT)
+#define I40E_PFQF_HREGION(_i) (0x00245400 + ((_i) * 128)) /* _i=0...7 */
+#define I40E_PFQF_HREGION_MAX_INDEX 7
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_0_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_0_SHIFT)
+#define I40E_PFQF_HREGION_REGION_0_SHIFT 1
+#define I40E_PFQF_HREGION_REGION_0_MASK (0x7 << I40E_PFQF_HREGION_REGION_0_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_1_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_1_SHIFT)
+#define I40E_PFQF_HREGION_REGION_1_SHIFT 5
+#define I40E_PFQF_HREGION_REGION_1_MASK (0x7 << I40E_PFQF_HREGION_REGION_1_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_2_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_2_SHIFT)
+#define I40E_PFQF_HREGION_REGION_2_SHIFT 9
+#define I40E_PFQF_HREGION_REGION_2_MASK (0x7 << I40E_PFQF_HREGION_REGION_2_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_3_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_3_SHIFT)
+#define I40E_PFQF_HREGION_REGION_3_SHIFT 13
+#define I40E_PFQF_HREGION_REGION_3_MASK (0x7 << I40E_PFQF_HREGION_REGION_3_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_4_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_4_SHIFT)
+#define I40E_PFQF_HREGION_REGION_4_SHIFT 17
+#define I40E_PFQF_HREGION_REGION_4_MASK (0x7 << I40E_PFQF_HREGION_REGION_4_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_5_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_5_SHIFT)
+#define I40E_PFQF_HREGION_REGION_5_SHIFT 21
+#define I40E_PFQF_HREGION_REGION_5_MASK (0x7 << I40E_PFQF_HREGION_REGION_5_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_6_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_6_SHIFT)
+#define I40E_PFQF_HREGION_REGION_6_SHIFT 25
+#define I40E_PFQF_HREGION_REGION_6_MASK (0x7 << I40E_PFQF_HREGION_REGION_6_SHIFT)
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28
+#define I40E_PFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_PFQF_HREGION_OVERRIDE_ENA_7_SHIFT)
+#define I40E_PFQF_HREGION_REGION_7_SHIFT 29
+#define I40E_PFQF_HREGION_REGION_7_MASK (0x7 << I40E_PFQF_HREGION_REGION_7_SHIFT)
+#define I40E_PRTQF_CTL_0 0x00256E60
+#define I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT 0
+#define I40E_PRTQF_CTL_0_HSYM_ENA_MASK (0x1 << I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT)
+#define I40E_PRTQF_FD_FLXINSET(_i) (0x00253800 + ((_i) * 32)) /* _i=0...63 */
+#define I40E_PRTQF_FD_FLXINSET_MAX_INDEX 63
+#define I40E_PRTQF_FD_FLXINSET_INSET_SHIFT 0
+#define I40E_PRTQF_FD_FLXINSET_INSET_MASK (0xFF << I40E_PRTQF_FD_FLXINSET_INSET_SHIFT)
+#define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */
+#define I40E_PRTQF_FD_MSK_MAX_INDEX 63
+#define I40E_PRTQF_FD_MSK_MASK_SHIFT 0
+#define I40E_PRTQF_FD_MSK_MASK_MASK (0xFFFF << I40E_PRTQF_FD_MSK_MASK_SHIFT)
+#define I40E_PRTQF_FD_MSK_OFFSET_SHIFT 16
+#define I40E_PRTQF_FD_MSK_OFFSET_MASK (0x3F << I40E_PRTQF_FD_MSK_OFFSET_SHIFT)
+#define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */
+#define I40E_PRTQF_FLX_PIT_MAX_INDEX 8
+#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT 0
+#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK (0x3F << I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT)
+#define I40E_PRTQF_FLX_PIT_FSIZE_SHIFT 6
+#define I40E_PRTQF_FLX_PIT_FSIZE_MASK (0xF << I40E_PRTQF_FLX_PIT_FSIZE_SHIFT)
+#define I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT 10
+#define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK (0x3F << I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT)
+#define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4))
+#define I40E_VFQF_HENA1_MAX_INDEX 1
+#define I40E_VFQF_HENA1_PTYPE_ENA_SHIFT 0
+#define I40E_VFQF_HENA1_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_VFQF_HENA1_PTYPE_ENA_SHIFT)
+#define I40E_VFQF_HKEY1(_i, _VF) (0x00228000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...12, _VF=0...127 */
+#define I40E_VFQF_HKEY1_MAX_INDEX 12
+#define I40E_VFQF_HKEY1_KEY_0_SHIFT 0
+#define I40E_VFQF_HKEY1_KEY_0_MASK (0xFF << I40E_VFQF_HKEY1_KEY_0_SHIFT)
+#define I40E_VFQF_HKEY1_KEY_1_SHIFT 8
+#define I40E_VFQF_HKEY1_KEY_1_MASK (0xFF << I40E_VFQF_HKEY1_KEY_1_SHIFT)
+#define I40E_VFQF_HKEY1_KEY_2_SHIFT 16
+#define I40E_VFQF_HKEY1_KEY_2_MASK (0xFF << I40E_VFQF_HKEY1_KEY_2_SHIFT)
+#define I40E_VFQF_HKEY1_KEY_3_SHIFT 24
+#define I40E_VFQF_HKEY1_KEY_3_MASK (0xFF << I40E_VFQF_HKEY1_KEY_3_SHIFT)
+#define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */
+#define I40E_VFQF_HLUT1_MAX_INDEX 15
+#define I40E_VFQF_HLUT1_LUT0_SHIFT 0
+#define I40E_VFQF_HLUT1_LUT0_MASK (0xF << I40E_VFQF_HLUT1_LUT0_SHIFT)
+#define I40E_VFQF_HLUT1_LUT1_SHIFT 8
+#define I40E_VFQF_HLUT1_LUT1_MASK (0xF << I40E_VFQF_HLUT1_LUT1_SHIFT)
+#define I40E_VFQF_HLUT1_LUT2_SHIFT 16
+#define I40E_VFQF_HLUT1_LUT2_MASK (0xF << I40E_VFQF_HLUT1_LUT2_SHIFT)
+#define I40E_VFQF_HLUT1_LUT3_SHIFT 24
+#define I40E_VFQF_HLUT1_LUT3_MASK (0xF << I40E_VFQF_HLUT1_LUT3_SHIFT)
+#define I40E_VFQF_HREGION1(_i, _VF) (0x0022E000 + ((_i) * 1024 + (_VF) * 4))
+#define I40E_VFQF_HREGION1_MAX_INDEX 7
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT 0
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_0_SHIFT 1
+#define I40E_VFQF_HREGION1_REGION_0_MASK (0x7 << I40E_VFQF_HREGION1_REGION_0_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT 4
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_1_SHIFT 5
+#define I40E_VFQF_HREGION1_REGION_1_MASK (0x7 << I40E_VFQF_HREGION1_REGION_1_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT 8
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_2_SHIFT 9
+#define I40E_VFQF_HREGION1_REGION_2_MASK (0x7 << I40E_VFQF_HREGION1_REGION_2_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT 12
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_3_SHIFT 13
+#define I40E_VFQF_HREGION1_REGION_3_MASK (0x7 << I40E_VFQF_HREGION1_REGION_3_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT 16
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_4_SHIFT 17
+#define I40E_VFQF_HREGION1_REGION_4_MASK (0x7 << I40E_VFQF_HREGION1_REGION_4_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT 20
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_5_SHIFT 21
+#define I40E_VFQF_HREGION1_REGION_5_MASK (0x7 << I40E_VFQF_HREGION1_REGION_5_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT 24
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_6_SHIFT 25
+#define I40E_VFQF_HREGION1_REGION_6_MASK (0x7 << I40E_VFQF_HREGION1_REGION_6_SHIFT)
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT 28
+#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT)
+#define I40E_VFQF_HREGION1_REGION_7_SHIFT 29
+#define I40E_VFQF_HREGION1_REGION_7_MASK (0x7 << I40E_VFQF_HREGION1_REGION_7_SHIFT)
+#define I40E_VPQF_CTL(_VF) (0x001C0000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VPQF_CTL_MAX_INDEX 127
+#define I40E_VPQF_CTL_PEHSIZE_SHIFT 0
+#define I40E_VPQF_CTL_PEHSIZE_MASK (0x1F << I40E_VPQF_CTL_PEHSIZE_SHIFT)
+#define I40E_VPQF_CTL_PEDSIZE_SHIFT 5
+#define I40E_VPQF_CTL_PEDSIZE_MASK (0x1F << I40E_VPQF_CTL_PEDSIZE_SHIFT)
+#define I40E_VPQF_CTL_FCHSIZE_SHIFT 10
+#define I40E_VPQF_CTL_FCHSIZE_MASK (0xF << I40E_VPQF_CTL_FCHSIZE_SHIFT)
+#define I40E_VPQF_CTL_FCDSIZE_SHIFT 14
+#define I40E_VPQF_CTL_FCDSIZE_MASK (0x3 << I40E_VPQF_CTL_FCDSIZE_SHIFT)
+#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4)) /* _i=0...383 */
+#define I40E_VSIQF_CTL_MAX_INDEX 383
+#define I40E_VSIQF_CTL_FCOE_ENA_SHIFT 0
+#define I40E_VSIQF_CTL_FCOE_ENA_MASK (0x1 << I40E_VSIQF_CTL_FCOE_ENA_SHIFT)
+#define I40E_VSIQF_CTL_PETCP_ENA_SHIFT 1
+#define I40E_VSIQF_CTL_PETCP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PETCP_ENA_SHIFT)
+#define I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT 2
+#define I40E_VSIQF_CTL_PEUUDP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT)
+#define I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT 3
+#define I40E_VSIQF_CTL_PEMUDP_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT)
+#define I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT 4
+#define I40E_VSIQF_CTL_PEUFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT)
+#define I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT 5
+#define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK (0x1 << I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT)
+#define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4))
+#define I40E_VSIQF_TCREGION_MAX_INDEX 7
+#define I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT 0
+#define I40E_VSIQF_TCREGION_TC_OFFSET_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT)
+#define I40E_VSIQF_TCREGION_TC_SIZE_SHIFT 9
+#define I40E_VSIQF_TCREGION_TC_SIZE_MASK (0x7 << I40E_VSIQF_TCREGION_TC_SIZE_SHIFT)
+#define I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT 16
+#define I40E_VSIQF_TCREGION_TC_OFFSET2_MASK (0x1FF << I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT)
+#define I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT 25
+#define I40E_VSIQF_TCREGION_TC_SIZE2_MASK (0x7 << I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT)
+#define I40E_GL_FCOECRC(_i) (0x00314d80 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOECRC_MAX_INDEX 143
+#define I40E_GL_FCOECRC_FCOECRC_SHIFT 0
+#define I40E_GL_FCOECRC_FCOECRC_MASK (0xFFFFFFFF << I40E_GL_FCOECRC_FCOECRC_SHIFT)
+#define I40E_GL_FCOEDDPC(_i) (0x00314480 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDDPC_MAX_INDEX 143
+#define I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT 0
+#define I40E_GL_FCOEDDPC_FCOEDDPC_MASK (0xFFFFFFFF << I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT)
+#define I40E_GL_FCOEDDPEC(_i) (0x00314900 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDDPEC_MAX_INDEX 143
+#define I40E_GL_FCOEDDPEC_CFOEDDPEC_SHIFT 0
+#define I40E_GL_FCOEDDPEC_CFOEDDPEC_MASK (0xFFFFFFFF << I40E_GL_FCOEDDPEC_CFOEDDPEC_SHIFT)
+#define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDIFEC_MAX_INDEX 143
+#define I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT 0
+#define I40E_GL_FCOEDIFEC_FCOEDIFRC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT)
+#define I40E_GL_FCOEDIFRC(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDIFRC_MAX_INDEX 143
+#define I40E_GL_FCOEDIFRC_FCOEDIFRC_SHIFT 0
+#define I40E_GL_FCOEDIFRC_FCOEDIFRC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFRC_FCOEDIFRC_SHIFT)
+#define I40E_GL_FCOEDIFTCL(_i) (0x00354000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDIFTCL_MAX_INDEX 143
+#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT 0
+#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT)
+#define I40E_GL_FCOEDIXAC(_i) (0x0031c000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDIXAC_MAX_INDEX 143
+#define I40E_GL_FCOEDIXAC_FCOEDIXAC_SHIFT 0
+#define I40E_GL_FCOEDIXAC_FCOEDIXAC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXAC_FCOEDIXAC_SHIFT)
+#define I40E_GL_FCOEDIXEC(_i) (0x0034c000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDIXEC_MAX_INDEX 143
+#define I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT 0
+#define I40E_GL_FCOEDIXEC_FCOEDIXEC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT)
+#define I40E_GL_FCOEDIXVC(_i) (0x00350000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDIXVC_MAX_INDEX 143
+#define I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT 0
+#define I40E_GL_FCOEDIXVC_FCOEDIXVC_MASK (0xFFFFFFFF << I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT)
+#define I40E_GL_FCOEDWRCH(_i) (0x00320004 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDWRCH_MAX_INDEX 143
+#define I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT 0
+#define I40E_GL_FCOEDWRCH_FCOEDWRCH_MASK (0xFFFF << I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT)
+#define I40E_GL_FCOEDWRCL(_i) (0x00320000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDWRCL_MAX_INDEX 143
+#define I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT 0
+#define I40E_GL_FCOEDWRCL_FCOEDWRCL_MASK (0xFFFFFFFF << I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT)
+#define I40E_GL_FCOEDWTCH(_i) (0x00348084 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDWTCH_MAX_INDEX 143
+#define I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT 0
+#define I40E_GL_FCOEDWTCH_FCOEDWTCH_MASK (0xFFFF << I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT)
+#define I40E_GL_FCOEDWTCL(_i) (0x00348080 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEDWTCL_MAX_INDEX 143
+#define I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT 0
+#define I40E_GL_FCOEDWTCL_FCOEDWTCL_MASK (0xFFFFFFFF << I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT)
+#define I40E_GL_FCOELAST(_i) (0x00314000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOELAST_MAX_INDEX 143
+#define I40E_GL_FCOELAST_FCOELAST_SHIFT 0
+#define I40E_GL_FCOELAST_FCOELAST_MASK (0xFFFFFFFF << I40E_GL_FCOELAST_FCOELAST_SHIFT)
+#define I40E_GL_FCOEPRC(_i) (0x00315200 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEPRC_MAX_INDEX 143
+#define I40E_GL_FCOEPRC_FCOEPRC_SHIFT 0
+#define I40E_GL_FCOEPRC_FCOEPRC_MASK (0xFFFFFFFF << I40E_GL_FCOEPRC_FCOEPRC_SHIFT)
+#define I40E_GL_FCOEPTC(_i) (0x00344C00 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOEPTC_MAX_INDEX 143
+#define I40E_GL_FCOEPTC_FCOEPTC_SHIFT 0
+#define I40E_GL_FCOEPTC_FCOEPTC_MASK (0xFFFFFFFF << I40E_GL_FCOEPTC_FCOEPTC_SHIFT)
+#define I40E_GL_FCOERPDC(_i) (0x00324000 + ((_i) * 8)) /* _i=0...143 */
+#define I40E_GL_FCOERPDC_MAX_INDEX 143
+#define I40E_GL_FCOERPDC_FCOERPDC_SHIFT 0
+#define I40E_GL_FCOERPDC_FCOERPDC_MASK (0xFFFFFFFF << I40E_GL_FCOERPDC_FCOERPDC_SHIFT)
+#define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_BPRCH_MAX_INDEX 3
+#define I40E_GLPRT_BPRCH_UPRCH_SHIFT 0
+#define I40E_GLPRT_BPRCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_BPRCH_UPRCH_SHIFT)
+#define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_BPRCL_MAX_INDEX 3
+#define I40E_GLPRT_BPRCL_UPRCH_SHIFT 0
+#define I40E_GLPRT_BPRCL_UPRCH_MASK (0xFFFFFFFF << I40E_GLPRT_BPRCL_UPRCH_SHIFT)
+#define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_BPTCH_MAX_INDEX 3
+#define I40E_GLPRT_BPTCH_UPRCH_SHIFT 0
+#define I40E_GLPRT_BPTCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_BPTCH_UPRCH_SHIFT)
+#define I40E_GLPRT_BPTCL(_i) (0x00300A00 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_BPTCL_MAX_INDEX 3
+#define I40E_GLPRT_BPTCL_UPRCH_SHIFT 0
+#define I40E_GLPRT_BPTCL_UPRCH_MASK (0xFFFFFFFF << I40E_GLPRT_BPTCL_UPRCH_SHIFT)
+#define I40E_GLPRT_CRCERRS(_i) (0x00300080 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_CRCERRS_MAX_INDEX 3
+#define I40E_GLPRT_CRCERRS_CRCERRS_SHIFT 0
+#define I40E_GLPRT_CRCERRS_CRCERRS_MASK (0xFFFFFFFF << I40E_GLPRT_CRCERRS_CRCERRS_SHIFT)
+#define I40E_GLPRT_GORCH(_i) (0x00300004 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_GORCH_MAX_INDEX 3
+#define I40E_GLPRT_GORCH_GORCH_SHIFT 0
+#define I40E_GLPRT_GORCH_GORCH_MASK (0xFFFF << I40E_GLPRT_GORCH_GORCH_SHIFT)
+#define I40E_GLPRT_GORCL(_i) (0x00300000 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_GORCL_MAX_INDEX 3
+#define I40E_GLPRT_GORCL_GORCL_SHIFT 0
+#define I40E_GLPRT_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLPRT_GORCL_GORCL_SHIFT)
+#define I40E_GLPRT_GOTCH(_i) (0x00300684 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_GOTCH_MAX_INDEX 3
+#define I40E_GLPRT_GOTCH_GOTCH_SHIFT 0
+#define I40E_GLPRT_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLPRT_GOTCH_GOTCH_SHIFT)
+#define I40E_GLPRT_GOTCL(_i) (0x00300680 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_GOTCL_MAX_INDEX 3
+#define I40E_GLPRT_GOTCL_GOTCL_SHIFT 0
+#define I40E_GLPRT_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLPRT_GOTCL_GOTCL_SHIFT)
+#define I40E_GLPRT_ILLERRC(_i) (0x003000E0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_ILLERRC_MAX_INDEX 3
+#define I40E_GLPRT_ILLERRC_ILLERRC_SHIFT 0
+#define I40E_GLPRT_ILLERRC_ILLERRC_MASK (0xFFFFFFFF << I40E_GLPRT_ILLERRC_ILLERRC_SHIFT)
+#define I40E_GLPRT_LDPC(_i) (0x00300620 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_LDPC_MAX_INDEX 3
+#define I40E_GLPRT_LDPC_LDPC_SHIFT 0
+#define I40E_GLPRT_LDPC_LDPC_MASK (0xFFFFFFFF << I40E_GLPRT_LDPC_LDPC_SHIFT)
+#define I40E_GLPRT_LXOFFRXC(_i) (0x00300160 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_LXOFFRXC_MAX_INDEX 3
+#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT 0
+#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT)
+#define I40E_GLPRT_LXOFFTXC(_i) (0x003009A0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_LXOFFTXC_MAX_INDEX 3
+#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT 0
+#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_MASK (0xFFFFFFFF << I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT)
+#define I40E_GLPRT_LXONRXC(_i) (0x00300140 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_LXONRXC_MAX_INDEX 3
+#define I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT 0
+#define I40E_GLPRT_LXONRXC_LXONRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT)
+#define I40E_GLPRT_LXONTXC(_i) (0x00300980 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_LXONTXC_MAX_INDEX 3
+#define I40E_GLPRT_LXONTXC_LXONTXC_SHIFT 0
+#define I40E_GLPRT_LXONTXC_LXONTXC_MASK (0xFFFFFFFF << I40E_GLPRT_LXONTXC_LXONTXC_SHIFT)
+#define I40E_GLPRT_MLFC(_i) (0x00300020 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_MLFC_MAX_INDEX 3
+#define I40E_GLPRT_MLFC_MLFC_SHIFT 0
+#define I40E_GLPRT_MLFC_MLFC_MASK (0xFFFFFFFF << I40E_GLPRT_MLFC_MLFC_SHIFT)
+#define I40E_GLPRT_MPRCH(_i) (0x003005C4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_MPRCH_MAX_INDEX 3
+#define I40E_GLPRT_MPRCH_MPRCH_SHIFT 0
+#define I40E_GLPRT_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLPRT_MPRCH_MPRCH_SHIFT)
+#define I40E_GLPRT_MPRCL(_i) (0x003005C0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_MPRCL_MAX_INDEX 3
+#define I40E_GLPRT_MPRCL_MPRCL_SHIFT 0
+#define I40E_GLPRT_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLPRT_MPRCL_MPRCL_SHIFT)
+#define I40E_GLPRT_MPTCH(_i) (0x003009E4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_MPTCH_MAX_INDEX 3
+#define I40E_GLPRT_MPTCH_MPTCH_SHIFT 0
+#define I40E_GLPRT_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLPRT_MPTCH_MPTCH_SHIFT)
+#define I40E_GLPRT_MPTCL(_i) (0x003009E0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_MPTCL_MAX_INDEX 3
+#define I40E_GLPRT_MPTCL_MPTCL_SHIFT 0
+#define I40E_GLPRT_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLPRT_MPTCL_MPTCL_SHIFT)
+#define I40E_GLPRT_MRFC(_i) (0x00300040 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_MRFC_MAX_INDEX 3
+#define I40E_GLPRT_MRFC_MRFC_SHIFT 0
+#define I40E_GLPRT_MRFC_MRFC_MASK (0xFFFFFFFF << I40E_GLPRT_MRFC_MRFC_SHIFT)
+#define I40E_GLPRT_PRC1023H(_i) (0x00300504 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC1023H_MAX_INDEX 3
+#define I40E_GLPRT_PRC1023H_PRC1023H_SHIFT 0
+#define I40E_GLPRT_PRC1023H_PRC1023H_MASK (0xFFFF << I40E_GLPRT_PRC1023H_PRC1023H_SHIFT)
+#define I40E_GLPRT_PRC1023L(_i) (0x00300500 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC1023L_MAX_INDEX 3
+#define I40E_GLPRT_PRC1023L_PRC1023L_SHIFT 0
+#define I40E_GLPRT_PRC1023L_PRC1023L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC1023L_PRC1023L_SHIFT)
+#define I40E_GLPRT_PRC127H(_i) (0x003004A4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC127H_MAX_INDEX 3
+#define I40E_GLPRT_PRC127H_PRC127H_SHIFT 0
+#define I40E_GLPRT_PRC127H_PRC127H_MASK (0xFFFF << I40E_GLPRT_PRC127H_PRC127H_SHIFT)
+#define I40E_GLPRT_PRC127L(_i) (0x003004A0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC127L_MAX_INDEX 3
+#define I40E_GLPRT_PRC127L_PRC127L_SHIFT 0
+#define I40E_GLPRT_PRC127L_PRC127L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC127L_PRC127L_SHIFT)
+#define I40E_GLPRT_PRC1522H(_i) (0x00300524 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC1522H_MAX_INDEX 3
+#define I40E_GLPRT_PRC1522H_PRC1522H_SHIFT 0
+#define I40E_GLPRT_PRC1522H_PRC1522H_MASK (0xFFFF << I40E_GLPRT_PRC1522H_PRC1522H_SHIFT)
+#define I40E_GLPRT_PRC1522L(_i) (0x00300520 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC1522L_MAX_INDEX 3
+#define I40E_GLPRT_PRC1522L_PRC1522L_SHIFT 0
+#define I40E_GLPRT_PRC1522L_PRC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC1522L_PRC1522L_SHIFT)
+#define I40E_GLPRT_PRC255H(_i) (0x003004C4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC255H_MAX_INDEX 3
+#define I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT 0
+#define I40E_GLPRT_PRC255H_PRTPRC255H_MASK (0xFFFF << I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT)
+#define I40E_GLPRT_PRC255L(_i) (0x003004C0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC255L_MAX_INDEX 3
+#define I40E_GLPRT_PRC255L_PRC255L_SHIFT 0
+#define I40E_GLPRT_PRC255L_PRC255L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC255L_PRC255L_SHIFT)
+#define I40E_GLPRT_PRC511H(_i) (0x003004E4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC511H_MAX_INDEX 3
+#define I40E_GLPRT_PRC511H_PRC511H_SHIFT 0
+#define I40E_GLPRT_PRC511H_PRC511H_MASK (0xFFFF << I40E_GLPRT_PRC511H_PRC511H_SHIFT)
+#define I40E_GLPRT_PRC511L(_i) (0x003004E0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC511L_MAX_INDEX 3
+#define I40E_GLPRT_PRC511L_PRC511L_SHIFT 0
+#define I40E_GLPRT_PRC511L_PRC511L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC511L_PRC511L_SHIFT)
+#define I40E_GLPRT_PRC64H(_i) (0x00300484 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC64H_MAX_INDEX 3
+#define I40E_GLPRT_PRC64H_PRC64H_SHIFT 0
+#define I40E_GLPRT_PRC64H_PRC64H_MASK (0xFFFF << I40E_GLPRT_PRC64H_PRC64H_SHIFT)
+#define I40E_GLPRT_PRC64L(_i) (0x00300480 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC64L_MAX_INDEX 3
+#define I40E_GLPRT_PRC64L_PRC64L_SHIFT 0
+#define I40E_GLPRT_PRC64L_PRC64L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC64L_PRC64L_SHIFT)
+#define I40E_GLPRT_PRC9522H(_i) (0x00300544 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC9522H_MAX_INDEX 3
+#define I40E_GLPRT_PRC9522H_PRC1522H_SHIFT 0
+#define I40E_GLPRT_PRC9522H_PRC1522H_MASK (0xFFFF << I40E_GLPRT_PRC9522H_PRC1522H_SHIFT)
+#define I40E_GLPRT_PRC9522L(_i) (0x00300540 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PRC9522L_MAX_INDEX 3
+#define I40E_GLPRT_PRC9522L_PRC1522L_SHIFT 0
+#define I40E_GLPRT_PRC9522L_PRC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PRC9522L_PRC1522L_SHIFT)
+#define I40E_GLPRT_PTC1023H(_i) (0x00300724 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC1023H_MAX_INDEX 3
+#define I40E_GLPRT_PTC1023H_PTC1023H_SHIFT 0
+#define I40E_GLPRT_PTC1023H_PTC1023H_MASK (0xFFFF << I40E_GLPRT_PTC1023H_PTC1023H_SHIFT)
+#define I40E_GLPRT_PTC1023L(_i) (0x00300720 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC1023L_MAX_INDEX 3
+#define I40E_GLPRT_PTC1023L_PTC1023L_SHIFT 0
+#define I40E_GLPRT_PTC1023L_PTC1023L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC1023L_PTC1023L_SHIFT)
+#define I40E_GLPRT_PTC127H(_i) (0x003006C4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC127H_MAX_INDEX 3
+#define I40E_GLPRT_PTC127H_PTC127H_SHIFT 0
+#define I40E_GLPRT_PTC127H_PTC127H_MASK (0xFFFF << I40E_GLPRT_PTC127H_PTC127H_SHIFT)
+#define I40E_GLPRT_PTC127L(_i) (0x003006C0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC127L_MAX_INDEX 3
+#define I40E_GLPRT_PTC127L_PTC127L_SHIFT 0
+#define I40E_GLPRT_PTC127L_PTC127L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC127L_PTC127L_SHIFT)
+#define I40E_GLPRT_PTC1522H(_i) (0x00300744 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC1522H_MAX_INDEX 3
+#define I40E_GLPRT_PTC1522H_PTC1522H_SHIFT 0
+#define I40E_GLPRT_PTC1522H_PTC1522H_MASK (0xFFFF << I40E_GLPRT_PTC1522H_PTC1522H_SHIFT)
+#define I40E_GLPRT_PTC1522L(_i) (0x00300740 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC1522L_MAX_INDEX 3
+#define I40E_GLPRT_PTC1522L_PTC1522L_SHIFT 0
+#define I40E_GLPRT_PTC1522L_PTC1522L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC1522L_PTC1522L_SHIFT)
+#define I40E_GLPRT_PTC255H(_i) (0x003006E4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC255H_MAX_INDEX 3
+#define I40E_GLPRT_PTC255H_PTC255H_SHIFT 0
+#define I40E_GLPRT_PTC255H_PTC255H_MASK (0xFFFF << I40E_GLPRT_PTC255H_PTC255H_SHIFT)
+#define I40E_GLPRT_PTC255L(_i) (0x003006E0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC255L_MAX_INDEX 3
+#define I40E_GLPRT_PTC255L_PTC255L_SHIFT 0
+#define I40E_GLPRT_PTC255L_PTC255L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC255L_PTC255L_SHIFT)
+#define I40E_GLPRT_PTC511H(_i) (0x00300704 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC511H_MAX_INDEX 3
+#define I40E_GLPRT_PTC511H_PTC511H_SHIFT 0
+#define I40E_GLPRT_PTC511H_PTC511H_MASK (0xFFFF << I40E_GLPRT_PTC511H_PTC511H_SHIFT)
+#define I40E_GLPRT_PTC511L(_i) (0x00300700 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC511L_MAX_INDEX 3
+#define I40E_GLPRT_PTC511L_PTC511L_SHIFT 0
+#define I40E_GLPRT_PTC511L_PTC511L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC511L_PTC511L_SHIFT)
+#define I40E_GLPRT_PTC64H(_i) (0x003006A4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC64H_MAX_INDEX 3
+#define I40E_GLPRT_PTC64H_PTC64H_SHIFT 0
+#define I40E_GLPRT_PTC64H_PTC64H_MASK (0xFFFF << I40E_GLPRT_PTC64H_PTC64H_SHIFT)
+#define I40E_GLPRT_PTC64L(_i) (0x003006A0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC64L_MAX_INDEX 3
+#define I40E_GLPRT_PTC64L_PTC64L_SHIFT 0
+#define I40E_GLPRT_PTC64L_PTC64L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC64L_PTC64L_SHIFT)
+#define I40E_GLPRT_PTC9522H(_i) (0x00300764 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC9522H_MAX_INDEX 3
+#define I40E_GLPRT_PTC9522H_PTC9522H_SHIFT 0
+#define I40E_GLPRT_PTC9522H_PTC9522H_MASK (0xFFFF << I40E_GLPRT_PTC9522H_PTC9522H_SHIFT)
+#define I40E_GLPRT_PTC9522L(_i) (0x00300760 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_PTC9522L_MAX_INDEX 3
+#define I40E_GLPRT_PTC9522L_PTC9522L_SHIFT 0
+#define I40E_GLPRT_PTC9522L_PTC9522L_MASK (0xFFFFFFFF << I40E_GLPRT_PTC9522L_PTC9522L_SHIFT)
+#define I40E_GLPRT_PXOFFRXC(_i, _j) (0x00300280 + ((_i) * 8 + (_j) * 32))
+#define I40E_GLPRT_PXOFFRXC_MAX_INDEX 3
+#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT 0
+#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT)
+#define I40E_GLPRT_PXOFFTXC(_i, _j) (0x00300880 + ((_i) * 8 + (_j) * 32))
+#define I40E_GLPRT_PXOFFTXC_MAX_INDEX 3
+#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT 0
+#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT)
+#define I40E_GLPRT_PXONRXC(_i, _j) (0x00300180 + ((_i) * 8 + (_j) * 32))
+#define I40E_GLPRT_PXONRXC_MAX_INDEX 3
+#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT 0
+#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_MASK (0xFFFFFFFF << I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT)
+#define I40E_GLPRT_PXONTXC(_i, _j) (0x00300780 + ((_i) * 8 + (_j) * 32))
+#define I40E_GLPRT_PXONTXC_MAX_INDEX 3
+#define I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT 0
+#define I40E_GLPRT_PXONTXC_PRPXONTXC_MASK (0xFFFFFFFF << I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT)
+#define I40E_GLPRT_RDPC(_i) (0x00300600 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_RDPC_MAX_INDEX 3
+#define I40E_GLPRT_RDPC_RDPC_SHIFT 0
+#define I40E_GLPRT_RDPC_RDPC_MASK (0xFFFFFFFF << I40E_GLPRT_RDPC_RDPC_SHIFT)
+#define I40E_GLPRT_RFC(_i) (0x00300560 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_RFC_MAX_INDEX 3
+#define I40E_GLPRT_RFC_RFC_SHIFT 0
+#define I40E_GLPRT_RFC_RFC_MASK (0xFFFFFFFF << I40E_GLPRT_RFC_RFC_SHIFT)
+#define I40E_GLPRT_RJC(_i) (0x00300580 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_RJC_MAX_INDEX 3
+#define I40E_GLPRT_RJC_RJC_SHIFT 0
+#define I40E_GLPRT_RJC_RJC_MASK (0xFFFFFFFF << I40E_GLPRT_RJC_RJC_SHIFT)
+#define I40E_GLPRT_RLEC(_i) (0x003000A0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_RLEC_MAX_INDEX 3
+#define I40E_GLPRT_RLEC_RLEC_SHIFT 0
+#define I40E_GLPRT_RLEC_RLEC_MASK (0xFFFFFFFF << I40E_GLPRT_RLEC_RLEC_SHIFT)
+#define I40E_GLPRT_ROC(_i) (0x00300120 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_ROC_MAX_INDEX 3
+#define I40E_GLPRT_ROC_ROC_SHIFT 0
+#define I40E_GLPRT_ROC_ROC_MASK (0xFFFFFFFF << I40E_GLPRT_ROC_ROC_SHIFT)
+#define I40E_GLPRT_RUC(_i) (0x00300100 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_RUC_MAX_INDEX 3
+#define I40E_GLPRT_RUC_RUC_SHIFT 0
+#define I40E_GLPRT_RUC_RUC_MASK (0xFFFFFFFF << I40E_GLPRT_RUC_RUC_SHIFT)
+#define I40E_GLPRT_RUPP(_i) (0x00300660 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_RUPP_MAX_INDEX 3
+#define I40E_GLPRT_RUPP_RUPP_SHIFT 0
+#define I40E_GLPRT_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLPRT_RUPP_RUPP_SHIFT)
+#define I40E_GLPRT_RXON2OFFCNT(_i, _j) (0x00300380 + ((_i) * 8 + (_j) * 32))
+#define I40E_GLPRT_RXON2OFFCNT_MAX_INDEX 3
+#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT 0
+#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_MASK (0xFFFFFFFF << I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT)
+#define I40E_GLPRT_STDC(_i) (0x00300640 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_STDC_MAX_INDEX 3
+#define I40E_GLPRT_STDC_STDC_SHIFT 0
+#define I40E_GLPRT_STDC_STDC_MASK (0xFFFFFFFF << I40E_GLPRT_STDC_STDC_SHIFT)
+#define I40E_GLPRT_TDOLD(_i) (0x00300A20 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_TDOLD_MAX_INDEX 3
+#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT 0
+#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_MASK (0xFFFFFFFF << I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT)
+#define I40E_GLPRT_TDPC(_i) (0x00375400 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_TDPC_MAX_INDEX 3
+#define I40E_GLPRT_TDPC_TDPC_SHIFT 0
+#define I40E_GLPRT_TDPC_TDPC_MASK (0xFFFFFFFF << I40E_GLPRT_TDPC_TDPC_SHIFT)
+#define I40E_GLPRT_UPRCH(_i) (0x003005A4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_UPRCH_MAX_INDEX 3
+#define I40E_GLPRT_UPRCH_UPRCH_SHIFT 0
+#define I40E_GLPRT_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLPRT_UPRCH_UPRCH_SHIFT)
+#define I40E_GLPRT_UPRCL(_i) (0x003005A0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_UPRCL_MAX_INDEX 3
+#define I40E_GLPRT_UPRCL_UPRCL_SHIFT 0
+#define I40E_GLPRT_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLPRT_UPRCL_UPRCL_SHIFT)
+#define I40E_GLPRT_UPTCH(_i) (0x003009C4 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_UPTCH_MAX_INDEX 3
+#define I40E_GLPRT_UPTCH_UPTCH_SHIFT 0
+#define I40E_GLPRT_UPTCH_UPTCH_MASK (0xFFFF << I40E_GLPRT_UPTCH_UPTCH_SHIFT)
+#define I40E_GLPRT_UPTCL(_i) (0x003009C0 + ((_i) * 8)) /* _i=0...3 */
+#define I40E_GLPRT_UPTCL_MAX_INDEX 3
+#define I40E_GLPRT_UPTCL_VUPTCH_SHIFT 0
+#define I40E_GLPRT_UPTCL_VUPTCH_MASK (0xFFFFFFFF << I40E_GLPRT_UPTCL_VUPTCH_SHIFT)
+#define I40E_GLSW_BPRCH(_i) (0x00370104 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_BPRCH_MAX_INDEX 15
+#define I40E_GLSW_BPRCH_BPRCH_SHIFT 0
+#define I40E_GLSW_BPRCH_BPRCH_MASK (0xFFFF << I40E_GLSW_BPRCH_BPRCH_SHIFT)
+#define I40E_GLSW_BPRCL(_i) (0x00370100 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_BPRCL_MAX_INDEX 15
+#define I40E_GLSW_BPRCL_BPRCL_SHIFT 0
+#define I40E_GLSW_BPRCL_BPRCL_MASK (0xFFFFFFFF << I40E_GLSW_BPRCL_BPRCL_SHIFT)
+#define I40E_GLSW_BPTCH(_i) (0x00340104 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_BPTCH_MAX_INDEX 15
+#define I40E_GLSW_BPTCH_BPTCH_SHIFT 0
+#define I40E_GLSW_BPTCH_BPTCH_MASK (0xFFFF << I40E_GLSW_BPTCH_BPTCH_SHIFT)
+#define I40E_GLSW_BPTCL(_i) (0x00340100 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_BPTCL_MAX_INDEX 15
+#define I40E_GLSW_BPTCL_BPTCL_SHIFT 0
+#define I40E_GLSW_BPTCL_BPTCL_MASK (0xFFFFFFFF << I40E_GLSW_BPTCL_BPTCL_SHIFT)
+#define I40E_GLSW_GORCH(_i) (0x0035C004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_GORCH_MAX_INDEX 15
+#define I40E_GLSW_GORCH_GORCH_SHIFT 0
+#define I40E_GLSW_GORCH_GORCH_MASK (0xFFFF << I40E_GLSW_GORCH_GORCH_SHIFT)
+#define I40E_GLSW_GORCL(_i) (0x0035c000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_GORCL_MAX_INDEX 15
+#define I40E_GLSW_GORCL_GORCL_SHIFT 0
+#define I40E_GLSW_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLSW_GORCL_GORCL_SHIFT)
+#define I40E_GLSW_GOTCH(_i) (0x0032C004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_GOTCH_MAX_INDEX 15
+#define I40E_GLSW_GOTCH_GOTCH_SHIFT 0
+#define I40E_GLSW_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLSW_GOTCH_GOTCH_SHIFT)
+#define I40E_GLSW_GOTCL(_i) (0x0032c000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_GOTCL_MAX_INDEX 15
+#define I40E_GLSW_GOTCL_GOTCL_SHIFT 0
+#define I40E_GLSW_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLSW_GOTCL_GOTCL_SHIFT)
+#define I40E_GLSW_MPRCH(_i) (0x00370084 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_MPRCH_MAX_INDEX 15
+#define I40E_GLSW_MPRCH_MPRCH_SHIFT 0
+#define I40E_GLSW_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLSW_MPRCH_MPRCH_SHIFT)
+#define I40E_GLSW_MPRCL(_i) (0x00370080 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_MPRCL_MAX_INDEX 15
+#define I40E_GLSW_MPRCL_MPRCL_SHIFT 0
+#define I40E_GLSW_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLSW_MPRCL_MPRCL_SHIFT)
+#define I40E_GLSW_MPTCH(_i) (0x00340084 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_MPTCH_MAX_INDEX 15
+#define I40E_GLSW_MPTCH_MPTCH_SHIFT 0
+#define I40E_GLSW_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLSW_MPTCH_MPTCH_SHIFT)
+#define I40E_GLSW_MPTCL(_i) (0x00340080 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_MPTCL_MAX_INDEX 15
+#define I40E_GLSW_MPTCL_MPTCL_SHIFT 0
+#define I40E_GLSW_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLSW_MPTCL_MPTCL_SHIFT)
+#define I40E_GLSW_RUPP(_i) (0x00370180 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_RUPP_MAX_INDEX 15
+#define I40E_GLSW_RUPP_RUPP_SHIFT 0
+#define I40E_GLSW_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLSW_RUPP_RUPP_SHIFT)
+#define I40E_GLSW_TDPC(_i) (0x00348000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_TDPC_MAX_INDEX 15
+#define I40E_GLSW_TDPC_TDPC_SHIFT 0
+#define I40E_GLSW_TDPC_TDPC_MASK (0xFFFFFFFF << I40E_GLSW_TDPC_TDPC_SHIFT)
+#define I40E_GLSW_UPRCH(_i) (0x00370004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_UPRCH_MAX_INDEX 15
+#define I40E_GLSW_UPRCH_UPRCH_SHIFT 0
+#define I40E_GLSW_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLSW_UPRCH_UPRCH_SHIFT)
+#define I40E_GLSW_UPRCL(_i) (0x00370000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_UPRCL_MAX_INDEX 15
+#define I40E_GLSW_UPRCL_UPRCL_SHIFT 0
+#define I40E_GLSW_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLSW_UPRCL_UPRCL_SHIFT)
+#define I40E_GLSW_UPTCH(_i) (0x00340004 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_UPTCH_MAX_INDEX 15
+#define I40E_GLSW_UPTCH_UPTCH_SHIFT 0
+#define I40E_GLSW_UPTCH_UPTCH_MASK (0xFFFF << I40E_GLSW_UPTCH_UPTCH_SHIFT)
+#define I40E_GLSW_UPTCL(_i) (0x00340000 + ((_i) * 8)) /* _i=0...15 */
+#define I40E_GLSW_UPTCL_MAX_INDEX 15
+#define I40E_GLSW_UPTCL_UPTCL_SHIFT 0
+#define I40E_GLSW_UPTCL_UPTCL_MASK (0xFFFFFFFF << I40E_GLSW_UPTCL_UPTCL_SHIFT)
+#define I40E_GLV_BPRCH(_i) (0x0036D804 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_BPRCH_MAX_INDEX 383
+#define I40E_GLV_BPRCH_BPRCH_SHIFT 0
+#define I40E_GLV_BPRCH_BPRCH_MASK (0xFFFF << I40E_GLV_BPRCH_BPRCH_SHIFT)
+#define I40E_GLV_BPRCL(_i) (0x0036d800 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_BPRCL_MAX_INDEX 383
+#define I40E_GLV_BPRCL_BPRCL_SHIFT 0
+#define I40E_GLV_BPRCL_BPRCL_MASK (0xFFFFFFFF << I40E_GLV_BPRCL_BPRCL_SHIFT)
+#define I40E_GLV_BPTCH(_i) (0x0033D804 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_BPTCH_MAX_INDEX 383
+#define I40E_GLV_BPTCH_BPTCH_SHIFT 0
+#define I40E_GLV_BPTCH_BPTCH_MASK (0xFFFF << I40E_GLV_BPTCH_BPTCH_SHIFT)
+#define I40E_GLV_BPTCL(_i) (0x0033d800 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_BPTCL_MAX_INDEX 383
+#define I40E_GLV_BPTCL_BPTCL_SHIFT 0
+#define I40E_GLV_BPTCL_BPTCL_MASK (0xFFFFFFFF << I40E_GLV_BPTCL_BPTCL_SHIFT)
+#define I40E_GLV_GORCH(_i) (0x00358004 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_GORCH_MAX_INDEX 383
+#define I40E_GLV_GORCH_GORCH_SHIFT 0
+#define I40E_GLV_GORCH_GORCH_MASK (0xFFFF << I40E_GLV_GORCH_GORCH_SHIFT)
+#define I40E_GLV_GORCL(_i) (0x00358000 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_GORCL_MAX_INDEX 383
+#define I40E_GLV_GORCL_GORCL_SHIFT 0
+#define I40E_GLV_GORCL_GORCL_MASK (0xFFFFFFFF << I40E_GLV_GORCL_GORCL_SHIFT)
+#define I40E_GLV_GOTCH(_i) (0x00328004 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_GOTCH_MAX_INDEX 383
+#define I40E_GLV_GOTCH_GOTCH_SHIFT 0
+#define I40E_GLV_GOTCH_GOTCH_MASK (0xFFFF << I40E_GLV_GOTCH_GOTCH_SHIFT)
+#define I40E_GLV_GOTCL(_i) (0x00328000 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_GOTCL_MAX_INDEX 383
+#define I40E_GLV_GOTCL_GOTCL_SHIFT 0
+#define I40E_GLV_GOTCL_GOTCL_MASK (0xFFFFFFFF << I40E_GLV_GOTCL_GOTCL_SHIFT)
+#define I40E_GLV_MPRCH(_i) (0x0036CC04 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_MPRCH_MAX_INDEX 383
+#define I40E_GLV_MPRCH_MPRCH_SHIFT 0
+#define I40E_GLV_MPRCH_MPRCH_MASK (0xFFFF << I40E_GLV_MPRCH_MPRCH_SHIFT)
+#define I40E_GLV_MPRCL(_i) (0x0036cc00 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_MPRCL_MAX_INDEX 383
+#define I40E_GLV_MPRCL_MPRCL_SHIFT 0
+#define I40E_GLV_MPRCL_MPRCL_MASK (0xFFFFFFFF << I40E_GLV_MPRCL_MPRCL_SHIFT)
+#define I40E_GLV_MPTCH(_i) (0x0033CC04 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_MPTCH_MAX_INDEX 383
+#define I40E_GLV_MPTCH_MPTCH_SHIFT 0
+#define I40E_GLV_MPTCH_MPTCH_MASK (0xFFFF << I40E_GLV_MPTCH_MPTCH_SHIFT)
+#define I40E_GLV_MPTCL(_i) (0x0033cc00 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_MPTCL_MAX_INDEX 383
+#define I40E_GLV_MPTCL_MPTCL_SHIFT 0
+#define I40E_GLV_MPTCL_MPTCL_MASK (0xFFFFFFFF << I40E_GLV_MPTCL_MPTCL_SHIFT)
+#define I40E_GLV_RDPC(_i) (0x00310000 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_RDPC_MAX_INDEX 383
+#define I40E_GLV_RDPC_RDPC_SHIFT 0
+#define I40E_GLV_RDPC_RDPC_MASK (0xFFFFFFFF << I40E_GLV_RDPC_RDPC_SHIFT)
+#define I40E_GLV_RUPP(_i) (0x0036E400 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_RUPP_MAX_INDEX 383
+#define I40E_GLV_RUPP_RUPP_SHIFT 0
+#define I40E_GLV_RUPP_RUPP_MASK (0xFFFFFFFF << I40E_GLV_RUPP_RUPP_SHIFT)
+#define I40E_GLV_TEPC(_VSI) (0x00344000 + ((_VSI) * 8)) /* _i=0...383 */
+#define I40E_GLV_TEPC_MAX_INDEX 383
+#define I40E_GLV_TEPC_TEPC_SHIFT 0
+#define I40E_GLV_TEPC_TEPC_MASK (0xFFFFFFFF << I40E_GLV_TEPC_TEPC_SHIFT)
+#define I40E_GLV_UPRCH(_i) (0x0036C004 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_UPRCH_MAX_INDEX 383
+#define I40E_GLV_UPRCH_UPRCH_SHIFT 0
+#define I40E_GLV_UPRCH_UPRCH_MASK (0xFFFF << I40E_GLV_UPRCH_UPRCH_SHIFT)
+#define I40E_GLV_UPRCL(_i) (0x0036c000 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_UPRCL_MAX_INDEX 383
+#define I40E_GLV_UPRCL_UPRCL_SHIFT 0
+#define I40E_GLV_UPRCL_UPRCL_MASK (0xFFFFFFFF << I40E_GLV_UPRCL_UPRCL_SHIFT)
+#define I40E_GLV_UPTCH(_i) (0x0033C004 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_UPTCH_MAX_INDEX 383
+#define I40E_GLV_UPTCH_GLVUPTCH_SHIFT 0
+#define I40E_GLV_UPTCH_GLVUPTCH_MASK (0xFFFF << I40E_GLV_UPTCH_GLVUPTCH_SHIFT)
+#define I40E_GLV_UPTCL(_i) (0x0033c000 + ((_i) * 8)) /* _i=0...383 */
+#define I40E_GLV_UPTCL_MAX_INDEX 383
+#define I40E_GLV_UPTCL_UPTCL_SHIFT 0
+#define I40E_GLV_UPTCL_UPTCL_MASK (0xFFFFFFFF << I40E_GLV_UPTCL_UPTCL_SHIFT)
+#define I40E_GLVEBTC_RBCH(_i, _j) (0x00364004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_RBCH_MAX_INDEX 7
+#define I40E_GLVEBTC_RBCH_TCBCH_SHIFT 0
+#define I40E_GLVEBTC_RBCH_TCBCH_MASK (0xFFFF << I40E_GLVEBTC_RBCH_TCBCH_SHIFT)
+#define I40E_GLVEBTC_RBCL(_i, _j) (0x00364000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_RBCL_MAX_INDEX 7
+#define I40E_GLVEBTC_RBCL_TCBCL_SHIFT 0
+#define I40E_GLVEBTC_RBCL_TCBCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_RBCL_TCBCL_SHIFT)
+#define I40E_GLVEBTC_RPCH(_i, _j) (0x00368004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_RPCH_MAX_INDEX 7
+#define I40E_GLVEBTC_RPCH_TCPCH_SHIFT 0
+#define I40E_GLVEBTC_RPCH_TCPCH_MASK (0xFFFF << I40E_GLVEBTC_RPCH_TCPCH_SHIFT)
+#define I40E_GLVEBTC_RPCL(_i, _j) (0x00368000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_RPCL_MAX_INDEX 7
+#define I40E_GLVEBTC_RPCL_TCPCL_SHIFT 0
+#define I40E_GLVEBTC_RPCL_TCPCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_RPCL_TCPCL_SHIFT)
+#define I40E_GLVEBTC_TBCH(_i, _j) (0x00334004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_TBCH_MAX_INDEX 7
+#define I40E_GLVEBTC_TBCH_TCBCH_SHIFT 0
+#define I40E_GLVEBTC_TBCH_TCBCH_MASK (0xFFFF << I40E_GLVEBTC_TBCH_TCBCH_SHIFT)
+#define I40E_GLVEBTC_TBCL(_i, _j) (0x00334000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_TBCL_MAX_INDEX 7
+#define I40E_GLVEBTC_TBCL_TCBCL_SHIFT 0
+#define I40E_GLVEBTC_TBCL_TCBCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_TBCL_TCBCL_SHIFT)
+#define I40E_GLVEBTC_TPCH(_i, _j) (0x00338004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_TPCH_MAX_INDEX 7
+#define I40E_GLVEBTC_TPCH_TCPCH_SHIFT 0
+#define I40E_GLVEBTC_TPCH_TCPCH_MASK (0xFFFF << I40E_GLVEBTC_TPCH_TCPCH_SHIFT)
+#define I40E_GLVEBTC_TPCL(_i, _j) (0x00338000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */
+#define I40E_GLVEBTC_TPCL_MAX_INDEX 7
+#define I40E_GLVEBTC_TPCL_TCPCL_SHIFT 0
+#define I40E_GLVEBTC_TPCL_TCPCL_MASK (0xFFFFFFFF << I40E_GLVEBTC_TPCL_TCPCL_SHIFT)
+#define I40E_GLVEBVL_BPCH(_i) (0x00374804 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_BPCH_MAX_INDEX 127
+#define I40E_GLVEBVL_BPCH_VLBPCH_SHIFT 0
+#define I40E_GLVEBVL_BPCH_VLBPCH_MASK (0xFFFF << I40E_GLVEBVL_BPCH_VLBPCH_SHIFT)
+#define I40E_GLVEBVL_BPCL(_i) (0x00374800 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_BPCL_MAX_INDEX 127
+#define I40E_GLVEBVL_BPCL_VLBPCL_SHIFT 0
+#define I40E_GLVEBVL_BPCL_VLBPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_BPCL_VLBPCL_SHIFT)
+#define I40E_GLVEBVL_GORCH(_i) (0x00360004 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_GORCH_MAX_INDEX 127
+#define I40E_GLVEBVL_GORCH_VLBCH_SHIFT 0
+#define I40E_GLVEBVL_GORCH_VLBCH_MASK (0xFFFF << I40E_GLVEBVL_GORCH_VLBCH_SHIFT)
+#define I40E_GLVEBVL_GORCL(_i) (0x00360000 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_GORCL_MAX_INDEX 127
+#define I40E_GLVEBVL_GORCL_VLBCL_SHIFT 0
+#define I40E_GLVEBVL_GORCL_VLBCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_GORCL_VLBCL_SHIFT)
+#define I40E_GLVEBVL_GOTCH(_i) (0x00330004 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_GOTCH_MAX_INDEX 127
+#define I40E_GLVEBVL_GOTCH_VLBCH_SHIFT 0
+#define I40E_GLVEBVL_GOTCH_VLBCH_MASK (0xFFFF << I40E_GLVEBVL_GOTCH_VLBCH_SHIFT)
+#define I40E_GLVEBVL_GOTCL(_i) (0x00330000 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_GOTCL_MAX_INDEX 127
+#define I40E_GLVEBVL_GOTCL_VLBCL_SHIFT 0
+#define I40E_GLVEBVL_GOTCL_VLBCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_GOTCL_VLBCL_SHIFT)
+#define I40E_GLVEBVL_MPCH(_i) (0x00374404 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_MPCH_MAX_INDEX 127
+#define I40E_GLVEBVL_MPCH_VLMPCH_SHIFT 0
+#define I40E_GLVEBVL_MPCH_VLMPCH_MASK (0xFFFF << I40E_GLVEBVL_MPCH_VLMPCH_SHIFT)
+#define I40E_GLVEBVL_MPCL(_i) (0x00374400 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_MPCL_MAX_INDEX 127
+#define I40E_GLVEBVL_MPCL_VLMPCL_SHIFT 0
+#define I40E_GLVEBVL_MPCL_VLMPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_MPCL_VLMPCL_SHIFT)
+#define I40E_GLVEBVL_UPCH(_i) (0x00374004 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_UPCH_MAX_INDEX 127
+#define I40E_GLVEBVL_UPCH_VLUPCH_SHIFT 0
+#define I40E_GLVEBVL_UPCH_VLUPCH_MASK (0xFFFF << I40E_GLVEBVL_UPCH_VLUPCH_SHIFT)
+#define I40E_GLVEBVL_UPCL(_i) (0x00374000 + ((_i) * 8)) /* _i=0...127 */
+#define I40E_GLVEBVL_UPCL_MAX_INDEX 127
+#define I40E_GLVEBVL_UPCL_VLUPCL_SHIFT 0
+#define I40E_GLVEBVL_UPCL_VLUPCL_MASK (0xFFFFFFFF << I40E_GLVEBVL_UPCL_VLUPCL_SHIFT)
+#define I40E_GL_MTG_FLU_MSK_H 0x00269F4C
+#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT 0
+#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_MASK (0xFFFF << I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT)
+#define I40E_GL_MTG_FLU_MSK_L 0x00269F44
+#define I40E_GL_MTG_FLU_MSK_L_MASK_LOW_SHIFT 0
+#define I40E_GL_MTG_FLU_MSK_L_MASK_LOW_MASK (0xFFFFFFFF << I40E_GL_MTG_FLU_MSK_L_MASK_LOW_SHIFT)
+#define I40E_GL_SWR_DEF_ACT(_i) (0x0026CF00 + ((_i) * 4)) /* _i=0...25 */
+#define I40E_GL_SWR_DEF_ACT_MAX_INDEX 25
+#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT 0
+#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_MASK (0xFFFFFFFF << I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT)
+#define I40E_GL_SWR_DEF_ACT_EN 0x0026CF84
+#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT 0
+#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_MASK (0xFFFFFFFF << I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT)
+#define I40E_PRT_MSCCNT 0x00256BA0
+#define I40E_PRT_MSCCNT_CCOUNT_SHIFT 0
+#define I40E_PRT_MSCCNT_CCOUNT_MASK (0x1FFFFFF << I40E_PRT_MSCCNT_CCOUNT_SHIFT)
+#define I40E_PRT_SCSTS 0x00256C20
+#define I40E_PRT_SCSTS_BSCA_SHIFT 0
+#define I40E_PRT_SCSTS_BSCA_MASK (0x1 << I40E_PRT_SCSTS_BSCA_SHIFT)
+#define I40E_PRT_SCSTS_BSCAP_SHIFT 1
+#define I40E_PRT_SCSTS_BSCAP_MASK (0x1 << I40E_PRT_SCSTS_BSCAP_SHIFT)
+#define I40E_PRT_SCSTS_MSCA_SHIFT 2
+#define I40E_PRT_SCSTS_MSCA_MASK (0x1 << I40E_PRT_SCSTS_MSCA_SHIFT)
+#define I40E_PRT_SCSTS_MSCAP_SHIFT 3
+#define I40E_PRT_SCSTS_MSCAP_MASK (0x1 << I40E_PRT_SCSTS_MSCAP_SHIFT)
+#define I40E_PRT_SWT_BSCCNT 0x00256C60
+#define I40E_PRT_SWT_BSCCNT_CCOUNT_SHIFT 0
+#define I40E_PRT_SWT_BSCCNT_CCOUNT_MASK (0x1FFFFFF << I40E_PRT_SWT_BSCCNT_CCOUNT_SHIFT)
+#define I40E_PRTTSYN_ADJ 0x001E4280
+#define I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT 0
+#define I40E_PRTTSYN_ADJ_TSYNADJ_MASK (0x7FFFFFFF << I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT)
+#define I40E_PRTTSYN_ADJ_SIGN_SHIFT 31
+#define I40E_PRTTSYN_ADJ_SIGN_MASK (0x1 << I40E_PRTTSYN_ADJ_SIGN_SHIFT)
+#define I40E_PRTTSYN_AUX_0(_i) (0x001E42A0 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_AUX_0_MAX_INDEX 1
+#define I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT 0
+#define I40E_PRTTSYN_AUX_0_OUT_ENA_MASK (0x1 << I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT)
+#define I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT 1
+#define I40E_PRTTSYN_AUX_0_OUTMOD_MASK (0x3 << I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT)
+#define I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT 3
+#define I40E_PRTTSYN_AUX_0_OUTLVL_MASK (0x1 << I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT)
+#define I40E_PRTTSYN_AUX_0_PULSEW_SHIFT 8
+#define I40E_PRTTSYN_AUX_0_PULSEW_MASK (0xF << I40E_PRTTSYN_AUX_0_PULSEW_SHIFT)
+#define I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT 16
+#define I40E_PRTTSYN_AUX_0_EVNTLVL_MASK (0x3 << I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT)
+#define I40E_PRTTSYN_AUX_1(_i) (0x001E42E0 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_AUX_1_MAX_INDEX 1
+#define I40E_PRTTSYN_AUX_1_INSTNT_SHIFT 0
+#define I40E_PRTTSYN_AUX_1_INSTNT_MASK (0x1 << I40E_PRTTSYN_AUX_1_INSTNT_SHIFT)
+#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT 1
+#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_MASK (0x1 << I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT)
+#define I40E_PRTTSYN_CLKO(_i) (0x001E4240 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_CLKO_MAX_INDEX 1
+#define I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT 0
+#define I40E_PRTTSYN_CLKO_TSYNCLKO_MASK (0xFFFFFFFF << I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT)
+#define I40E_PRTTSYN_CTL0 0x001E4200
+#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT 0
+#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_MASK (0x1 << I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT)
+#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT 1
+#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT)
+#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT 2
+#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT)
+#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT 3
+#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT)
+#define I40E_PRTTSYN_CTL0_PF_ID_SHIFT 8
+#define I40E_PRTTSYN_CTL0_PF_ID_MASK (0xF << I40E_PRTTSYN_CTL0_PF_ID_SHIFT)
+#define I40E_PRTTSYN_CTL0_TSYNACT_SHIFT 12
+#define I40E_PRTTSYN_CTL0_TSYNACT_MASK (0x3 << I40E_PRTTSYN_CTL0_TSYNACT_SHIFT)
+#define I40E_PRTTSYN_CTL0_TSYNENA_SHIFT 31
+#define I40E_PRTTSYN_CTL0_TSYNENA_MASK (0x1 << I40E_PRTTSYN_CTL0_TSYNENA_SHIFT)
+#define I40E_PRTTSYN_CTL1 0x00085020
+#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT 0
+#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK (0xFF << I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT)
+#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT 8
+#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_MASK (0xFF << I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT)
+#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT 16
+#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK (0xF << I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT)
+#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT 20
+#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_MASK (0xF << I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT)
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT 24
+#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK (0x3 << I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT)
+#define I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT 26
+#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK (0x3 << I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT)
+#define I40E_PRTTSYN_CTL1_TSYNENA_SHIFT 31
+#define I40E_PRTTSYN_CTL1_TSYNENA_MASK (0x1 << I40E_PRTTSYN_CTL1_TSYNENA_SHIFT)
+#define I40E_PRTTSYN_EVNT_H(_i) (0x001E40C0 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_EVNT_H_MAX_INDEX 1
+#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT 0
+#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT)
+#define I40E_PRTTSYN_EVNT_L(_i) (0x001E4080 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_EVNT_L_MAX_INDEX 1
+#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT 0
+#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT)
+#define I40E_PRTTSYN_INC_H 0x001E4060
+#define I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT 0
+#define I40E_PRTTSYN_INC_H_TSYNINC_H_MASK (0x3F << I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT)
+#define I40E_PRTTSYN_INC_L 0x001E4040
+#define I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT 0
+#define I40E_PRTTSYN_INC_L_TSYNINC_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT)
+#define I40E_PRTTSYN_RXTIME_H(_i) (0x00085040 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRTTSYN_RXTIME_H_MAX_INDEX 3
+#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT 0
+#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT)
+#define I40E_PRTTSYN_RXTIME_L(_i) (0x000850C0 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRTTSYN_RXTIME_L_MAX_INDEX 3
+#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT 0
+#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT)
+#define I40E_PRTTSYN_STAT_0 0x001E4220
+#define I40E_PRTTSYN_STAT_0_EVENT0_SHIFT 0
+#define I40E_PRTTSYN_STAT_0_EVENT0_MASK (0x1 << I40E_PRTTSYN_STAT_0_EVENT0_SHIFT)
+#define I40E_PRTTSYN_STAT_0_EVENT1_SHIFT 1
+#define I40E_PRTTSYN_STAT_0_EVENT1_MASK (0x1 << I40E_PRTTSYN_STAT_0_EVENT1_SHIFT)
+#define I40E_PRTTSYN_STAT_0_TGT0_SHIFT 2
+#define I40E_PRTTSYN_STAT_0_TGT0_MASK (0x1 << I40E_PRTTSYN_STAT_0_TGT0_SHIFT)
+#define I40E_PRTTSYN_STAT_0_TGT1_SHIFT 3
+#define I40E_PRTTSYN_STAT_0_TGT1_MASK (0x1 << I40E_PRTTSYN_STAT_0_TGT1_SHIFT)
+#define I40E_PRTTSYN_STAT_0_TXTIME_SHIFT 4
+#define I40E_PRTTSYN_STAT_0_TXTIME_MASK (0x1 << I40E_PRTTSYN_STAT_0_TXTIME_SHIFT)
+#define I40E_PRTTSYN_STAT_1 0x00085140
+#define I40E_PRTTSYN_STAT_1_RXT0_SHIFT 0
+#define I40E_PRTTSYN_STAT_1_RXT0_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT0_SHIFT)
+#define I40E_PRTTSYN_STAT_1_RXT1_SHIFT 1
+#define I40E_PRTTSYN_STAT_1_RXT1_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT1_SHIFT)
+#define I40E_PRTTSYN_STAT_1_RXT2_SHIFT 2
+#define I40E_PRTTSYN_STAT_1_RXT2_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT2_SHIFT)
+#define I40E_PRTTSYN_STAT_1_RXT3_SHIFT 3
+#define I40E_PRTTSYN_STAT_1_RXT3_MASK (0x1 << I40E_PRTTSYN_STAT_1_RXT3_SHIFT)
+#define I40E_PRTTSYN_TGT_H(_i) (0x001E4180 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_TGT_H_MAX_INDEX 1
+#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT 0
+#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT)
+#define I40E_PRTTSYN_TGT_L(_i) (0x001E4140 + ((_i) * 32)) /* _i=0...1 */
+#define I40E_PRTTSYN_TGT_L_MAX_INDEX 1
+#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT 0
+#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT)
+#define I40E_PRTTSYN_TIME_H 0x001E4120
+#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT 0
+#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT)
+#define I40E_PRTTSYN_TIME_L 0x001E4100
+#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT 0
+#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT)
+#define I40E_PRTTSYN_TXTIME_H 0x001E41E0
+#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT 0
+#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_MASK (0xFFFFFFFF << I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT)
+#define I40E_PRTTSYN_TXTIME_L 0x001E41C0
+#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT 0
+#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_MASK (0xFFFFFFFF << I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT)
+#define I40E_GLSCD_QUANTA 0x000B2080
+#define I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT 0
+#define I40E_GLSCD_QUANTA_TSCDQUANTA_MASK (0x7 << I40E_GLSCD_QUANTA_TSCDQUANTA_SHIFT)
+#define I40E_GL_MDET_RX 0x0012A510
+#define I40E_GL_MDET_RX_FUNCTION_SHIFT 0
+#define I40E_GL_MDET_RX_FUNCTION_MASK (0xFF << I40E_GL_MDET_RX_FUNCTION_SHIFT)
+#define I40E_GL_MDET_RX_EVENT_SHIFT 8
+#define I40E_GL_MDET_RX_EVENT_MASK (0x1FF << I40E_GL_MDET_RX_EVENT_SHIFT)
+#define I40E_GL_MDET_RX_QUEUE_SHIFT 17
+#define I40E_GL_MDET_RX_QUEUE_MASK (0x3FFF << I40E_GL_MDET_RX_QUEUE_SHIFT)
+#define I40E_GL_MDET_RX_VALID_SHIFT 31
+#define I40E_GL_MDET_RX_VALID_MASK (0x1 << I40E_GL_MDET_RX_VALID_SHIFT)
+#define I40E_GL_MDET_TX 0x000E6480
+#define I40E_GL_MDET_TX_FUNCTION_SHIFT 0
+#define I40E_GL_MDET_TX_FUNCTION_MASK (0xFF << I40E_GL_MDET_TX_FUNCTION_SHIFT)
+#define I40E_GL_MDET_TX_EVENT_SHIFT 8
+#define I40E_GL_MDET_TX_EVENT_MASK (0x1FF << I40E_GL_MDET_TX_EVENT_SHIFT)
+#define I40E_GL_MDET_TX_QUEUE_SHIFT 17
+#define I40E_GL_MDET_TX_QUEUE_MASK (0x3FFF << I40E_GL_MDET_TX_QUEUE_SHIFT)
+#define I40E_GL_MDET_TX_VALID_SHIFT 31
+#define I40E_GL_MDET_TX_VALID_MASK (0x1 << I40E_GL_MDET_TX_VALID_SHIFT)
+#define I40E_PF_MDET_RX 0x0012A400
+#define I40E_PF_MDET_RX_VALID_SHIFT 0
+#define I40E_PF_MDET_RX_VALID_MASK (0x1 << I40E_PF_MDET_RX_VALID_SHIFT)
+#define I40E_PF_MDET_TX 0x000E6400
+#define I40E_PF_MDET_TX_VALID_SHIFT 0
+#define I40E_PF_MDET_TX_VALID_MASK (0x1 << I40E_PF_MDET_TX_VALID_SHIFT)
+#define I40E_PF_VT_PFALLOC 0x001C0500
+#define I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT 0
+#define I40E_PF_VT_PFALLOC_FIRSTVF_MASK (0xFF << I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT)
+#define I40E_PF_VT_PFALLOC_LASTVF_SHIFT 8
+#define I40E_PF_VT_PFALLOC_LASTVF_MASK (0xFF << I40E_PF_VT_PFALLOC_LASTVF_SHIFT)
+#define I40E_PF_VT_PFALLOC_VALID_SHIFT 31
+#define I40E_PF_VT_PFALLOC_VALID_MASK (0x1 << I40E_PF_VT_PFALLOC_VALID_SHIFT)
+#define I40E_VP_MDET_RX(_VF) (0x0012A000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VP_MDET_RX_MAX_INDEX 127
+#define I40E_VP_MDET_RX_VALID_SHIFT 0
+#define I40E_VP_MDET_RX_VALID_MASK (0x1 << I40E_VP_MDET_RX_VALID_SHIFT)
+#define I40E_VP_MDET_TX(_VF) (0x000E6000 + ((_VF) * 4)) /* _i=0...127 */
+#define I40E_VP_MDET_TX_MAX_INDEX 127
+#define I40E_VP_MDET_TX_VALID_SHIFT 0
+#define I40E_VP_MDET_TX_VALID_MASK (0x1 << I40E_VP_MDET_TX_VALID_SHIFT)
+#define I40E_GLPM_WUMC 0x0006C800
+#define I40E_GLPM_WUMC_NOTCO_SHIFT 0
+#define I40E_GLPM_WUMC_NOTCO_MASK (0x1 << I40E_GLPM_WUMC_NOTCO_SHIFT)
+#define I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT 1
+#define I40E_GLPM_WUMC_SRST_PIN_VAL_MASK (0x1 << I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT)
+#define I40E_GLPM_WUMC_ROL_MODE_SHIFT 2
+#define I40E_GLPM_WUMC_ROL_MODE_MASK (0x1 << I40E_GLPM_WUMC_ROL_MODE_SHIFT)
+#define I40E_GLPM_WUMC_RESERVED_4_SHIFT 3
+#define I40E_GLPM_WUMC_RESERVED_4_MASK (0x1FFF << I40E_GLPM_WUMC_RESERVED_4_SHIFT)
+#define I40E_GLPM_WUMC_MNG_WU_PF_SHIFT 16
+#define I40E_GLPM_WUMC_MNG_WU_PF_MASK (0xFFFF << I40E_GLPM_WUMC_MNG_WU_PF_SHIFT)
+#define I40E_PFPM_APM 0x000B8080
+#define I40E_PFPM_APM_APME_SHIFT 0
+#define I40E_PFPM_APM_APME_MASK (0x1 << I40E_PFPM_APM_APME_SHIFT)
+#define I40E_PFPM_FHFT_DATA(_i, _j) (0x00060000 + ((_i) * 4096 + (_j) * 128))
+#define I40E_PFPM_FHFT_DATA_MAX_INDEX 7
+#define I40E_PFPM_FHFT_DATA_DWORD_SHIFT 0
+#define I40E_PFPM_FHFT_DATA_DWORD_MASK (0xFFFFFFFF << I40E_PFPM_FHFT_DATA_DWORD_SHIFT)
+#define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */
+#define I40E_PFPM_FHFT_LENGTH_MAX_INDEX 7
+#define I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT 0
+#define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK (0xFF << I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT)
+#define I40E_PFPM_FHFT_MASK(_i, _j) (0x00068000 + ((_i) * 1024 + (_j) * 128))
+#define I40E_PFPM_FHFT_MASK_MAX_INDEX 7
+#define I40E_PFPM_FHFT_MASK_MASK_SHIFT 0
+#define I40E_PFPM_FHFT_MASK_MASK_MASK (0xFFFF << I40E_PFPM_FHFT_MASK_MASK_SHIFT)
+#define I40E_PFPM_PROXYFC 0x00245A80
+#define I40E_PFPM_PROXYFC_PPROXYE_SHIFT 0
+#define I40E_PFPM_PROXYFC_PPROXYE_MASK (0x1 << I40E_PFPM_PROXYFC_PPROXYE_SHIFT)
+#define I40E_PFPM_PROXYFC_EX_SHIFT 1
+#define I40E_PFPM_PROXYFC_EX_MASK (0x1 << I40E_PFPM_PROXYFC_EX_SHIFT)
+#define I40E_PFPM_PROXYFC_ARP_SHIFT 4
+#define I40E_PFPM_PROXYFC_ARP_MASK (0x1 << I40E_PFPM_PROXYFC_ARP_SHIFT)
+#define I40E_PFPM_PROXYFC_ARP_DIRECTED_SHIFT 5
+#define I40E_PFPM_PROXYFC_ARP_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYFC_ARP_DIRECTED_SHIFT)
+#define I40E_PFPM_PROXYFC_NS_SHIFT 9
+#define I40E_PFPM_PROXYFC_NS_MASK (0x1 << I40E_PFPM_PROXYFC_NS_SHIFT)
+#define I40E_PFPM_PROXYFC_NS_DIRECTED_SHIFT 10
+#define I40E_PFPM_PROXYFC_NS_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYFC_NS_DIRECTED_SHIFT)
+#define I40E_PFPM_PROXYFC_MLD_SHIFT 12
+#define I40E_PFPM_PROXYFC_MLD_MASK (0x1 << I40E_PFPM_PROXYFC_MLD_SHIFT)
+#define I40E_PFPM_PROXYS 0x00245B80
+#define I40E_PFPM_PROXYS_EX_SHIFT 1
+#define I40E_PFPM_PROXYS_EX_MASK (0x1 << I40E_PFPM_PROXYS_EX_SHIFT)
+#define I40E_PFPM_PROXYS_ARP_SHIFT 4
+#define I40E_PFPM_PROXYS_ARP_MASK (0x1 << I40E_PFPM_PROXYS_ARP_SHIFT)
+#define I40E_PFPM_PROXYS_ARP_DIRECTED_SHIFT 5
+#define I40E_PFPM_PROXYS_ARP_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYS_ARP_DIRECTED_SHIFT)
+#define I40E_PFPM_PROXYS_NS_SHIFT 9
+#define I40E_PFPM_PROXYS_NS_MASK (0x1 << I40E_PFPM_PROXYS_NS_SHIFT)
+#define I40E_PFPM_PROXYS_NS_DIRECTED_SHIFT 10
+#define I40E_PFPM_PROXYS_NS_DIRECTED_MASK (0x1 << I40E_PFPM_PROXYS_NS_DIRECTED_SHIFT)
+#define I40E_PFPM_PROXYS_MLD_SHIFT 12
+#define I40E_PFPM_PROXYS_MLD_MASK (0x1 << I40E_PFPM_PROXYS_MLD_SHIFT)
+#define I40E_PFPM_WUC 0x0006B200
+#define I40E_PFPM_WUC_EN_APM_D0_SHIFT 5
+#define I40E_PFPM_WUC_EN_APM_D0_MASK (0x1 << I40E_PFPM_WUC_EN_APM_D0_SHIFT)
+#define I40E_PFPM_WUFC 0x0006B400
+#define I40E_PFPM_WUFC_LNKC_SHIFT 0
+#define I40E_PFPM_WUFC_LNKC_MASK (0x1 << I40E_PFPM_WUFC_LNKC_SHIFT)
+#define I40E_PFPM_WUFC_MAG_SHIFT 1
+#define I40E_PFPM_WUFC_MAG_MASK (0x1 << I40E_PFPM_WUFC_MAG_SHIFT)
+#define I40E_PFPM_WUFC_MNG_SHIFT 3
+#define I40E_PFPM_WUFC_MNG_MASK (0x1 << I40E_PFPM_WUFC_MNG_SHIFT)
+#define I40E_PFPM_WUFC_FLX0_ACT_SHIFT 4
+#define I40E_PFPM_WUFC_FLX0_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX0_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX1_ACT_SHIFT 5
+#define I40E_PFPM_WUFC_FLX1_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX1_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX2_ACT_SHIFT 6
+#define I40E_PFPM_WUFC_FLX2_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX2_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX3_ACT_SHIFT 7
+#define I40E_PFPM_WUFC_FLX3_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX3_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX4_ACT_SHIFT 8
+#define I40E_PFPM_WUFC_FLX4_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX4_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX5_ACT_SHIFT 9
+#define I40E_PFPM_WUFC_FLX5_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX5_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX6_ACT_SHIFT 10
+#define I40E_PFPM_WUFC_FLX6_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX6_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX7_ACT_SHIFT 11
+#define I40E_PFPM_WUFC_FLX7_ACT_MASK (0x1 << I40E_PFPM_WUFC_FLX7_ACT_SHIFT)
+#define I40E_PFPM_WUFC_FLX0_SHIFT 16
+#define I40E_PFPM_WUFC_FLX0_MASK (0x1 << I40E_PFPM_WUFC_FLX0_SHIFT)
+#define I40E_PFPM_WUFC_FLX1_SHIFT 17
+#define I40E_PFPM_WUFC_FLX1_MASK (0x1 << I40E_PFPM_WUFC_FLX1_SHIFT)
+#define I40E_PFPM_WUFC_FLX2_SHIFT 18
+#define I40E_PFPM_WUFC_FLX2_MASK (0x1 << I40E_PFPM_WUFC_FLX2_SHIFT)
+#define I40E_PFPM_WUFC_FLX3_SHIFT 19
+#define I40E_PFPM_WUFC_FLX3_MASK (0x1 << I40E_PFPM_WUFC_FLX3_SHIFT)
+#define I40E_PFPM_WUFC_FLX4_SHIFT 20
+#define I40E_PFPM_WUFC_FLX4_MASK (0x1 << I40E_PFPM_WUFC_FLX4_SHIFT)
+#define I40E_PFPM_WUFC_FLX5_SHIFT 21
+#define I40E_PFPM_WUFC_FLX5_MASK (0x1 << I40E_PFPM_WUFC_FLX5_SHIFT)
+#define I40E_PFPM_WUFC_FLX6_SHIFT 22
+#define I40E_PFPM_WUFC_FLX6_MASK (0x1 << I40E_PFPM_WUFC_FLX6_SHIFT)
+#define I40E_PFPM_WUFC_FLX7_SHIFT 23
+#define I40E_PFPM_WUFC_FLX7_MASK (0x1 << I40E_PFPM_WUFC_FLX7_SHIFT)
+#define I40E_PFPM_WUFC_FW_RST_WK_SHIFT 31
+#define I40E_PFPM_WUFC_FW_RST_WK_MASK (0x1 << I40E_PFPM_WUFC_FW_RST_WK_SHIFT)
+#define I40E_PFPM_WUS 0x0006B600
+#define I40E_PFPM_WUS_LNKC_SHIFT 0
+#define I40E_PFPM_WUS_LNKC_MASK (0x1 << I40E_PFPM_WUS_LNKC_SHIFT)
+#define I40E_PFPM_WUS_MAG_SHIFT 1
+#define I40E_PFPM_WUS_MAG_MASK (0x1 << I40E_PFPM_WUS_MAG_SHIFT)
+#define I40E_PFPM_WUS_PME_STATUS_SHIFT 2
+#define I40E_PFPM_WUS_PME_STATUS_MASK (0x1 << I40E_PFPM_WUS_PME_STATUS_SHIFT)
+#define I40E_PFPM_WUS_MNG_SHIFT 3
+#define I40E_PFPM_WUS_MNG_MASK (0x1 << I40E_PFPM_WUS_MNG_SHIFT)
+#define I40E_PFPM_WUS_FLX0_SHIFT 16
+#define I40E_PFPM_WUS_FLX0_MASK (0x1 << I40E_PFPM_WUS_FLX0_SHIFT)
+#define I40E_PFPM_WUS_FLX1_SHIFT 17
+#define I40E_PFPM_WUS_FLX1_MASK (0x1 << I40E_PFPM_WUS_FLX1_SHIFT)
+#define I40E_PFPM_WUS_FLX2_SHIFT 18
+#define I40E_PFPM_WUS_FLX2_MASK (0x1 << I40E_PFPM_WUS_FLX2_SHIFT)
+#define I40E_PFPM_WUS_FLX3_SHIFT 19
+#define I40E_PFPM_WUS_FLX3_MASK (0x1 << I40E_PFPM_WUS_FLX3_SHIFT)
+#define I40E_PFPM_WUS_FLX4_SHIFT 20
+#define I40E_PFPM_WUS_FLX4_MASK (0x1 << I40E_PFPM_WUS_FLX4_SHIFT)
+#define I40E_PFPM_WUS_FLX5_SHIFT 21
+#define I40E_PFPM_WUS_FLX5_MASK (0x1 << I40E_PFPM_WUS_FLX5_SHIFT)
+#define I40E_PFPM_WUS_FLX6_SHIFT 22
+#define I40E_PFPM_WUS_FLX6_MASK (0x1 << I40E_PFPM_WUS_FLX6_SHIFT)
+#define I40E_PFPM_WUS_FLX7_SHIFT 23
+#define I40E_PFPM_WUS_FLX7_MASK (0x1 << I40E_PFPM_WUS_FLX7_SHIFT)
+#define I40E_PFPM_WUS_FW_RST_WK_SHIFT 31
+#define I40E_PFPM_WUS_FW_RST_WK_MASK (0x1 << I40E_PFPM_WUS_FW_RST_WK_SHIFT)
+#define I40E_PRTPM_FHFHR 0x0006C000
+#define I40E_PRTPM_FHFHR_UNICAST_SHIFT 0
+#define I40E_PRTPM_FHFHR_UNICAST_MASK (0x1 << I40E_PRTPM_FHFHR_UNICAST_SHIFT)
+#define I40E_PRTPM_FHFHR_MULTICAST_SHIFT 1
+#define I40E_PRTPM_FHFHR_MULTICAST_MASK (0x1 << I40E_PRTPM_FHFHR_MULTICAST_SHIFT)
+#define I40E_PRTPM_SAH(_i) (0x001E44C0 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRTPM_SAH_MAX_INDEX 3
+#define I40E_PRTPM_SAH_PFPM_SAH_SHIFT 0
+#define I40E_PRTPM_SAH_PFPM_SAH_MASK (0xFFFF << I40E_PRTPM_SAH_PFPM_SAH_SHIFT)
+#define I40E_PRTPM_SAH_PF_NUM_SHIFT 26
+#define I40E_PRTPM_SAH_PF_NUM_MASK (0xF << I40E_PRTPM_SAH_PF_NUM_SHIFT)
+#define I40E_PRTPM_SAH_MC_MAG_EN_SHIFT 30
+#define I40E_PRTPM_SAH_MC_MAG_EN_MASK (0x1 << I40E_PRTPM_SAH_MC_MAG_EN_SHIFT)
+#define I40E_PRTPM_SAH_AV_SHIFT 31
+#define I40E_PRTPM_SAH_AV_MASK (0x1 << I40E_PRTPM_SAH_AV_SHIFT)
+#define I40E_PRTPM_SAL(_i) (0x001E4440 + ((_i) * 32)) /* _i=0...3 */
+#define I40E_PRTPM_SAL_MAX_INDEX 3
+#define I40E_PRTPM_SAL_PFPM_SAL_SHIFT 0
+#define I40E_PRTPM_SAL_PFPM_SAL_MASK (0xFFFFFFFF << I40E_PRTPM_SAL_PFPM_SAL_SHIFT)
+#define I40E_VF_ARQBAH1 0x00006000
+#define I40E_VF_ARQBAH1_ARQBAH_SHIFT 0
+#define I40E_VF_ARQBAH1_ARQBAH_MASK (0xFFFFFFFF << I40E_VF_ARQBAH1_ARQBAH_SHIFT)
+#define I40E_VF_ARQBAL1 0x00006C00
+#define I40E_VF_ARQBAL1_ARQBAL_SHIFT 0
+#define I40E_VF_ARQBAL1_ARQBAL_MASK (0xFFFFFFFF << I40E_VF_ARQBAL1_ARQBAL_SHIFT)
+#define I40E_VF_ARQH1 0x00007400
+#define I40E_VF_ARQH1_ARQH_SHIFT 0
+#define I40E_VF_ARQH1_ARQH_MASK (0x3FF << I40E_VF_ARQH1_ARQH_SHIFT)
+#define I40E_VF_ARQLEN1 0x00008000
+#define I40E_VF_ARQLEN1_ARQLEN_SHIFT 0
+#define I40E_VF_ARQLEN1_ARQLEN_MASK (0x3FF << I40E_VF_ARQLEN1_ARQLEN_SHIFT)
+#define I40E_VF_ARQLEN1_ARQVFE_SHIFT 28
+#define I40E_VF_ARQLEN1_ARQVFE_MASK (0x1 << I40E_VF_ARQLEN1_ARQVFE_SHIFT)
+#define I40E_VF_ARQLEN1_ARQOVFL_SHIFT 29
+#define I40E_VF_ARQLEN1_ARQOVFL_MASK (0x1 << I40E_VF_ARQLEN1_ARQOVFL_SHIFT)
+#define I40E_VF_ARQLEN1_ARQCRIT_SHIFT 30
+#define I40E_VF_ARQLEN1_ARQCRIT_MASK (0x1 << I40E_VF_ARQLEN1_ARQCRIT_SHIFT)
+#define I40E_VF_ARQLEN1_ARQENABLE_SHIFT 31
+#define I40E_VF_ARQLEN1_ARQENABLE_MASK (0x1 << I40E_VF_ARQLEN1_ARQENABLE_SHIFT)
+#define I40E_VF_ARQT1 0x00007000
+#define I40E_VF_ARQT1_ARQT_SHIFT 0
+#define I40E_VF_ARQT1_ARQT_MASK (0x3FF << I40E_VF_ARQT1_ARQT_SHIFT)
+#define I40E_VF_ATQBAH1 0x00007800
+#define I40E_VF_ATQBAH1_ATQBAH_SHIFT 0
+#define I40E_VF_ATQBAH1_ATQBAH_MASK (0xFFFFFFFF << I40E_VF_ATQBAH1_ATQBAH_SHIFT)
+#define I40E_VF_ATQBAL1 0x00007C00
+#define I40E_VF_ATQBAL1_ATQBAL_SHIFT 0
+#define I40E_VF_ATQBAL1_ATQBAL_MASK (0xFFFFFFFF << I40E_VF_ATQBAL1_ATQBAL_SHIFT)
+#define I40E_VF_ATQH1 0x00006400
+#define I40E_VF_ATQH1_ATQH_SHIFT 0
+#define I40E_VF_ATQH1_ATQH_MASK (0x3FF << I40E_VF_ATQH1_ATQH_SHIFT)
+#define I40E_VF_ATQLEN1 0x00006800
+#define I40E_VF_ATQLEN1_ATQLEN_SHIFT 0
+#define I40E_VF_ATQLEN1_ATQLEN_MASK (0x3FF << I40E_VF_ATQLEN1_ATQLEN_SHIFT)
+#define I40E_VF_ATQLEN1_ATQVFE_SHIFT 28
+#define I40E_VF_ATQLEN1_ATQVFE_MASK (0x1 << I40E_VF_ATQLEN1_ATQVFE_SHIFT)
+#define I40E_VF_ATQLEN1_ATQOVFL_SHIFT 29
+#define I40E_VF_ATQLEN1_ATQOVFL_MASK (0x1 << I40E_VF_ATQLEN1_ATQOVFL_SHIFT)
+#define I40E_VF_ATQLEN1_ATQCRIT_SHIFT 30
+#define I40E_VF_ATQLEN1_ATQCRIT_MASK (0x1 << I40E_VF_ATQLEN1_ATQCRIT_SHIFT)
+#define I40E_VF_ATQLEN1_ATQENABLE_SHIFT 31
+#define I40E_VF_ATQLEN1_ATQENABLE_MASK (0x1 << I40E_VF_ATQLEN1_ATQENABLE_SHIFT)
+#define I40E_VF_ATQT1 0x00008400
+#define I40E_VF_ATQT1_ATQT_SHIFT 0
+#define I40E_VF_ATQT1_ATQT_MASK (0x3FF << I40E_VF_ATQT1_ATQT_SHIFT)
+#define I40E_VFGEN_RSTAT 0x00008800
+#define I40E_VFGEN_RSTAT_VFR_STATE_SHIFT 0
+#define I40E_VFGEN_RSTAT_VFR_STATE_MASK (0x3 << I40E_VFGEN_RSTAT_VFR_STATE_SHIFT)
+#define I40E_VFINT_DYN_CTL01 0x00005C00
+#define I40E_VFINT_DYN_CTL01_INTENA_SHIFT 0
+#define I40E_VFINT_DYN_CTL01_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTL01_INTENA_SHIFT)
+#define I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT 1
+#define I40E_VFINT_DYN_CTL01_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTL01_CLEARPBA_SHIFT)
+#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT 2
+#define I40E_VFINT_DYN_CTL01_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTL01_SWINT_TRIG_SHIFT)
+#define I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT 3
+#define I40E_VFINT_DYN_CTL01_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL01_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT 5
+#define I40E_VFINT_DYN_CTL01_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTL01_INTERVAL_SHIFT)
+#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT 24
+#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTL01_SW_ITR_INDX_ENA_SHIFT)
+#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT 25
+#define I40E_VFINT_DYN_CTL01_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTL01_SW_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT 31
+#define I40E_VFINT_DYN_CTL01_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTL01_INTENA_MSK_SHIFT)
+#define I40E_VFINT_DYN_CTLN1(_INTVF) (0x00003800 + ((_INTVF) * 4))
+#define I40E_VFINT_DYN_CTLN1_MAX_INDEX 15
+#define I40E_VFINT_DYN_CTLN1_INTENA_SHIFT 0
+#define I40E_VFINT_DYN_CTLN1_INTENA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_INTENA_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT 1
+#define I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_CLEARPBA_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT 2
+#define I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK (0x1 << I40E_VFINT_DYN_CTLN1_SWINT_TRIG_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT 3
+#define I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT 5
+#define I40E_VFINT_DYN_CTLN1_INTERVAL_MASK (0xFFF << I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT 24
+#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_MASK (0x1 << I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_ENA_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT 25
+#define I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_MASK (0x3 << I40E_VFINT_DYN_CTLN1_SW_ITR_INDX_SHIFT)
+#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT 31
+#define I40E_VFINT_DYN_CTLN1_INTENA_MSK_MASK (0x1 << I40E_VFINT_DYN_CTLN1_INTENA_MSK_SHIFT)
+#define I40E_VFINT_ICR0_ENA1 0x00005000
+#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT 25
+#define I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR0_ENA1_LINK_STAT_CHANGE_SHIFT)
+#define I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT 30
+#define I40E_VFINT_ICR0_ENA1_ADMINQ_MASK (0x1 << I40E_VFINT_ICR0_ENA1_ADMINQ_SHIFT)
+#define I40E_VFINT_ICR0_ENA1_RSVD_SHIFT 31
+#define I40E_VFINT_ICR0_ENA1_RSVD_MASK (0x1 << I40E_VFINT_ICR0_ENA1_RSVD_SHIFT)
+#define I40E_VFINT_ICR01 0x00004800
+#define I40E_VFINT_ICR01_INTEVENT_SHIFT 0
+#define I40E_VFINT_ICR01_INTEVENT_MASK (0x1 << I40E_VFINT_ICR01_INTEVENT_SHIFT)
+#define I40E_VFINT_ICR01_QUEUE_0_SHIFT 1
+#define I40E_VFINT_ICR01_QUEUE_0_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_0_SHIFT)
+#define I40E_VFINT_ICR01_QUEUE_1_SHIFT 2
+#define I40E_VFINT_ICR01_QUEUE_1_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_1_SHIFT)
+#define I40E_VFINT_ICR01_QUEUE_2_SHIFT 3
+#define I40E_VFINT_ICR01_QUEUE_2_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_2_SHIFT)
+#define I40E_VFINT_ICR01_QUEUE_3_SHIFT 4
+#define I40E_VFINT_ICR01_QUEUE_3_MASK (0x1 << I40E_VFINT_ICR01_QUEUE_3_SHIFT)
+#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT 25
+#define I40E_VFINT_ICR01_LINK_STAT_CHANGE_MASK (0x1 << I40E_VFINT_ICR01_LINK_STAT_CHANGE_SHIFT)
+#define I40E_VFINT_ICR01_ADMINQ_SHIFT 30
+#define I40E_VFINT_ICR01_ADMINQ_MASK (0x1 << I40E_VFINT_ICR01_ADMINQ_SHIFT)
+#define I40E_VFINT_ICR01_SWINT_SHIFT 31
+#define I40E_VFINT_ICR01_SWINT_MASK (0x1 << I40E_VFINT_ICR01_SWINT_SHIFT)
+#define I40E_VFINT_ITR01(_i) (0x00004C00 + ((_i) * 4)) /* _i=0...2 */
+#define I40E_VFINT_ITR01_MAX_INDEX 2
+#define I40E_VFINT_ITR01_INTERVAL_SHIFT 0
+#define I40E_VFINT_ITR01_INTERVAL_MASK (0xFFF << I40E_VFINT_ITR01_INTERVAL_SHIFT)
+#define I40E_VFINT_ITRN1(_i, _INTVF) (0x00002800 + ((_i) * 64 + (_INTVF) * 4))
+#define I40E_VFINT_ITRN1_MAX_INDEX 2
+#define I40E_VFINT_ITRN1_INTERVAL_SHIFT 0
+#define I40E_VFINT_ITRN1_INTERVAL_MASK (0xFFF << I40E_VFINT_ITRN1_INTERVAL_SHIFT)
+#define I40E_VFINT_STAT_CTL01 0x00005400
+#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT 2
+#define I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_MASK (0x3 << I40E_VFINT_STAT_CTL01_OTHER_ITR_INDX_SHIFT)
+#define I40E_QRX_TAIL1(_Q) (0x00002000 + ((_Q) * 4)) /* _i=0...15 */
+#define I40E_QRX_TAIL1_MAX_INDEX 15
+#define I40E_QRX_TAIL1_TAIL_SHIFT 0
+#define I40E_QRX_TAIL1_TAIL_MASK (0x1FFF << I40E_QRX_TAIL1_TAIL_SHIFT)
+#define I40E_QTX_TAIL1(_Q) (0x00000000 + ((_Q) * 4)) /* _i=0...15 */
+#define I40E_QTX_TAIL1_MAX_INDEX 15
+#define I40E_QTX_TAIL1_TAIL_SHIFT 0
+#define I40E_QTX_TAIL1_TAIL_MASK (0x1FFF << I40E_QTX_TAIL1_TAIL_SHIFT)
+#define I40E_VFMSIX_PBA 0x00002000
+#define I40E_VFMSIX_PBA_PENBIT_SHIFT 0
+#define I40E_VFMSIX_PBA_PENBIT_MASK (0xFFFFFFFF << I40E_VFMSIX_PBA_PENBIT_SHIFT)
+#define I40E_VFMSIX_TADD(_i) (0x00000008 + ((_i) * 16)) /* _i=0...16 */
+#define I40E_VFMSIX_TADD_MAX_INDEX 16
+#define I40E_VFMSIX_TADD_MSIXTADD10_SHIFT 0
+#define I40E_VFMSIX_TADD_MSIXTADD10_MASK (0x3 << I40E_VFMSIX_TADD_MSIXTADD10_SHIFT)
+#define I40E_VFMSIX_TADD_MSIXTADD_SHIFT 2
+#define I40E_VFMSIX_TADD_MSIXTADD_MASK (0x3FFFFFFF << I40E_VFMSIX_TADD_MSIXTADD_SHIFT)
+#define I40E_VFMSIX_TMSG(_i) (0x0000000C + ((_i) * 16)) /* _i=0...16 */
+#define I40E_VFMSIX_TMSG_MAX_INDEX 16
+#define I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT 0
+#define I40E_VFMSIX_TMSG_MSIXTMSG_MASK (0xFFFFFFFF << I40E_VFMSIX_TMSG_MSIXTMSG_SHIFT)
+#define I40E_VFMSIX_TUADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...16 */
+#define I40E_VFMSIX_TUADD_MAX_INDEX 16
+#define I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT 0
+#define I40E_VFMSIX_TUADD_MSIXTUADD_MASK (0xFFFFFFFF << I40E_VFMSIX_TUADD_MSIXTUADD_SHIFT)
+#define I40E_VFMSIX_TVCTRL(_i) (0x00000004 + ((_i) * 16)) /* _i=0...16 */
+#define I40E_VFMSIX_TVCTRL_MAX_INDEX 16
+#define I40E_VFMSIX_TVCTRL_MASK_SHIFT 0
+#define I40E_VFMSIX_TVCTRL_MASK_MASK (0x1 << I40E_VFMSIX_TVCTRL_MASK_SHIFT)
+#define I40E_VFCM_PE_ERRDATA 0x0000DC00
+#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT 0
+#define I40E_VFCM_PE_ERRDATA_ERROR_CODE_MASK (0xF << I40E_VFCM_PE_ERRDATA_ERROR_CODE_SHIFT)
+#define I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT 4
+#define I40E_VFCM_PE_ERRDATA_Q_TYPE_MASK (0x7 << I40E_VFCM_PE_ERRDATA_Q_TYPE_SHIFT)
+#define I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT 8
+#define I40E_VFCM_PE_ERRDATA_Q_NUM_MASK (0x3FFFF << I40E_VFCM_PE_ERRDATA_Q_NUM_SHIFT)
+#define I40E_VFCM_PE_ERRINFO 0x0000D800
+#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT 0
+#define I40E_VFCM_PE_ERRINFO_ERROR_VALID_MASK (0x1 << I40E_VFCM_PE_ERRINFO_ERROR_VALID_SHIFT)
+#define I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT 4
+#define I40E_VFCM_PE_ERRINFO_ERROR_INST_MASK (0x7 << I40E_VFCM_PE_ERRINFO_ERROR_INST_SHIFT)
+#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT 8
+#define I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_DBL_ERROR_CNT_SHIFT)
+#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT 16
+#define I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_RLU_ERROR_CNT_SHIFT)
+#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT 24
+#define I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_MASK (0xFF << I40E_VFCM_PE_ERRINFO_RLS_ERROR_CNT_SHIFT)
+#define I40E_VFPE_AEQALLOC1 0x0000A400
+#define I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT 0
+#define I40E_VFPE_AEQALLOC1_AECOUNT_MASK (0xFFFFFFFF << I40E_VFPE_AEQALLOC1_AECOUNT_SHIFT)
+#define I40E_VFPE_CCQPHIGH1 0x00009800
+#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT 0
+#define I40E_VFPE_CCQPHIGH1_PECCQPHIGH_MASK (0xFFFFFFFF << I40E_VFPE_CCQPHIGH1_PECCQPHIGH_SHIFT)
+#define I40E_VFPE_CCQPLOW1 0x0000AC00
+#define I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT 0
+#define I40E_VFPE_CCQPLOW1_PECCQPLOW_MASK (0xFFFFFFFF << I40E_VFPE_CCQPLOW1_PECCQPLOW_SHIFT)
+#define I40E_VFPE_CCQPSTATUS1 0x0000B800
+#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT 0
+#define I40E_VFPE_CCQPSTATUS1_CCQP_DONE_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_DONE_SHIFT)
+#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT 31
+#define I40E_VFPE_CCQPSTATUS1_CCQP_ERR_MASK (0x1 << I40E_VFPE_CCQPSTATUS1_CCQP_ERR_SHIFT)
+#define I40E_VFPE_CQACK1 0x0000B000
+#define I40E_VFPE_CQACK1_PECQID_SHIFT 0
+#define I40E_VFPE_CQACK1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQACK1_PECQID_SHIFT)
+#define I40E_VFPE_CQARM1 0x0000B400
+#define I40E_VFPE_CQARM1_PECQID_SHIFT 0
+#define I40E_VFPE_CQARM1_PECQID_MASK (0x1FFFF << I40E_VFPE_CQARM1_PECQID_SHIFT)
+#define I40E_VFPE_CQPDB1 0x0000BC00
+#define I40E_VFPE_CQPDB1_WQHEAD_SHIFT 0
+#define I40E_VFPE_CQPDB1_WQHEAD_MASK (0x7FF << I40E_VFPE_CQPDB1_WQHEAD_SHIFT)
+#define I40E_VFPE_CQPERRCODES1 0x00009C00
+#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT 0
+#define I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MINOR_CODE_SHIFT)
+#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT 16
+#define I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_MASK (0xFFFF << I40E_VFPE_CQPERRCODES1_CQP_MAJOR_CODE_SHIFT)
+#define I40E_VFPE_CQPTAIL1 0x0000A000
+#define I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT 0
+#define I40E_VFPE_CQPTAIL1_WQTAIL_MASK (0x7FF << I40E_VFPE_CQPTAIL1_WQTAIL_SHIFT)
+#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT 31
+#define I40E_VFPE_CQPTAIL1_CQP_OP_ERR_MASK (0x1 << I40E_VFPE_CQPTAIL1_CQP_OP_ERR_SHIFT)
+#define I40E_VFPE_IPCONFIG01 0x00008C00
+#define I40E_VFPE_IPCONFIG01_PEIPID_SHIFT 0
+#define I40E_VFPE_IPCONFIG01_PEIPID_MASK (0xFFFF << I40E_VFPE_IPCONFIG01_PEIPID_SHIFT)
+#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT 16
+#define I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEENTIREIDRANGE_SHIFT)
+#define I40E_VFPE_IPCONFIG01_USEUPPERIDRANGE_SHIFT 17
+#define I40E_VFPE_IPCONFIG01_USEUPPERIDRANGE_MASK (0x1 << I40E_VFPE_IPCONFIG01_USEUPPERIDRANGE_SHIFT)
+#define I40E_VFPE_MRTEIDXMASK1 0x00009000
+#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT 0
+#define I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_MASK (0x1F << I40E_VFPE_MRTEIDXMASK1_MRTEIDXMASKBITS_SHIFT)
+#define I40E_VFPE_RCVUNEXPECTEDERROR1 0x00009400
+#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT 0
+#define I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_MASK (0xFFFFFF << I40E_VFPE_RCVUNEXPECTEDERROR1_TCP_RX_UNEXP_ERR_SHIFT)
+#define I40E_VFPE_TCPNOWTIMER1 0x0000A800
+#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT 0
+#define I40E_VFPE_TCPNOWTIMER1_TCP_NOW_MASK (0xFFFFFFFF << I40E_VFPE_TCPNOWTIMER1_TCP_NOW_SHIFT)
+#define I40E_VFPE_WQEALLOC1 0x0000C000
+#define I40E_VFPE_WQEALLOC1_PEQPID_SHIFT 0
+#define I40E_VFPE_WQEALLOC1_PEQPID_MASK (0x3FFFF << I40E_VFPE_WQEALLOC1_PEQPID_SHIFT)
+#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT 20
+#define I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_MASK (0xFFF << I40E_VFPE_WQEALLOC1_WQE_DESC_INDEX_SHIFT)
+#define I40E_VFQF_HENA(_i) (0x0000C400 + ((_i) * 4)) /* _i=0...1 */
+#define I40E_VFQF_HENA_MAX_INDEX 1
+#define I40E_VFQF_HENA_PTYPE_ENA_SHIFT 0
+#define I40E_VFQF_HENA_PTYPE_ENA_MASK (0xFFFFFFFF << I40E_VFQF_HENA_PTYPE_ENA_SHIFT)
+#define I40E_VFQF_HKEY(_i) (0x0000CC00 + ((_i) * 4)) /* _i=0...12 */
+#define I40E_VFQF_HKEY_MAX_INDEX 12
+#define I40E_VFQF_HKEY_KEY_0_SHIFT 0
+#define I40E_VFQF_HKEY_KEY_0_MASK (0xFF << I40E_VFQF_HKEY_KEY_0_SHIFT)
+#define I40E_VFQF_HKEY_KEY_1_SHIFT 8
+#define I40E_VFQF_HKEY_KEY_1_MASK (0xFF << I40E_VFQF_HKEY_KEY_1_SHIFT)
+#define I40E_VFQF_HKEY_KEY_2_SHIFT 16
+#define I40E_VFQF_HKEY_KEY_2_MASK (0xFF << I40E_VFQF_HKEY_KEY_2_SHIFT)
+#define I40E_VFQF_HKEY_KEY_3_SHIFT 24
+#define I40E_VFQF_HKEY_KEY_3_MASK (0xFF << I40E_VFQF_HKEY_KEY_3_SHIFT)
+#define I40E_VFQF_HLUT(_i) (0x0000D000 + ((_i) * 4)) /* _i=0...15 */
+#define I40E_VFQF_HLUT_MAX_INDEX 15
+#define I40E_VFQF_HLUT_LUT0_SHIFT 0
+#define I40E_VFQF_HLUT_LUT0_MASK (0xF << I40E_VFQF_HLUT_LUT0_SHIFT)
+#define I40E_VFQF_HLUT_LUT1_SHIFT 8
+#define I40E_VFQF_HLUT_LUT1_MASK (0xF << I40E_VFQF_HLUT_LUT1_SHIFT)
+#define I40E_VFQF_HLUT_LUT2_SHIFT 16
+#define I40E_VFQF_HLUT_LUT2_MASK (0xF << I40E_VFQF_HLUT_LUT2_SHIFT)
+#define I40E_VFQF_HLUT_LUT3_SHIFT 24
+#define I40E_VFQF_HLUT_LUT3_MASK (0xF << I40E_VFQF_HLUT_LUT3_SHIFT)
+#define I40E_VFQF_HREGION(_i) (0x0000D400 + ((_i) * 4)) /* _i=0...7 */
+#define I40E_VFQF_HREGION_MAX_INDEX 7
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT 0
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_0_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_0_SHIFT)
+#define I40E_VFQF_HREGION_REGION_0_SHIFT 1
+#define I40E_VFQF_HREGION_REGION_0_MASK (0x7 << I40E_VFQF_HREGION_REGION_0_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT 4
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_1_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_1_SHIFT)
+#define I40E_VFQF_HREGION_REGION_1_SHIFT 5
+#define I40E_VFQF_HREGION_REGION_1_MASK (0x7 << I40E_VFQF_HREGION_REGION_1_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT 8
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_2_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_2_SHIFT)
+#define I40E_VFQF_HREGION_REGION_2_SHIFT 9
+#define I40E_VFQF_HREGION_REGION_2_MASK (0x7 << I40E_VFQF_HREGION_REGION_2_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT 12
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_3_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_3_SHIFT)
+#define I40E_VFQF_HREGION_REGION_3_SHIFT 13
+#define I40E_VFQF_HREGION_REGION_3_MASK (0x7 << I40E_VFQF_HREGION_REGION_3_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT 16
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_4_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_4_SHIFT)
+#define I40E_VFQF_HREGION_REGION_4_SHIFT 17
+#define I40E_VFQF_HREGION_REGION_4_MASK (0x7 << I40E_VFQF_HREGION_REGION_4_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT 20
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_5_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_5_SHIFT)
+#define I40E_VFQF_HREGION_REGION_5_SHIFT 21
+#define I40E_VFQF_HREGION_REGION_5_MASK (0x7 << I40E_VFQF_HREGION_REGION_5_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT 24
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_6_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_6_SHIFT)
+#define I40E_VFQF_HREGION_REGION_6_SHIFT 25
+#define I40E_VFQF_HREGION_REGION_6_MASK (0x7 << I40E_VFQF_HREGION_REGION_6_SHIFT)
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT 28
+#define I40E_VFQF_HREGION_OVERRIDE_ENA_7_MASK (0x1 << I40E_VFQF_HREGION_OVERRIDE_ENA_7_SHIFT)
+#define I40E_VFQF_HREGION_REGION_7_SHIFT 29
+#define I40E_VFQF_HREGION_REGION_7_MASK (0x7 << I40E_VFQF_HREGION_REGION_7_SHIFT)
+
+#endif
diff --git a/drivers/net/ethernet/intel/i40e/i40e_status.h b/drivers/net/ethernet/intel/i40e/i40e_status.h
new file mode 100644 (file)
index 0000000..5e5bcdd
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_STATUS_H_
+#define _I40E_STATUS_H_
+
+/* Error Codes */
+enum i40e_status_code {
+       I40E_SUCCESS                            = 0,
+       I40E_ERR_NVM                            = -1,
+       I40E_ERR_NVM_CHECKSUM                   = -2,
+       I40E_ERR_PHY                            = -3,
+       I40E_ERR_CONFIG                         = -4,
+       I40E_ERR_PARAM                          = -5,
+       I40E_ERR_MAC_TYPE                       = -6,
+       I40E_ERR_UNKNOWN_PHY                    = -7,
+       I40E_ERR_LINK_SETUP                     = -8,
+       I40E_ERR_ADAPTER_STOPPED                = -9,
+       I40E_ERR_INVALID_MAC_ADDR               = -10,
+       I40E_ERR_DEVICE_NOT_SUPPORTED           = -11,
+       I40E_ERR_MASTER_REQUESTS_PENDING        = -12,
+       I40E_ERR_INVALID_LINK_SETTINGS          = -13,
+       I40E_ERR_AUTONEG_NOT_COMPLETE           = -14,
+       I40E_ERR_RESET_FAILED                   = -15,
+       I40E_ERR_SWFW_SYNC                      = -16,
+       I40E_ERR_NO_AVAILABLE_VSI               = -17,
+       I40E_ERR_NO_MEMORY                      = -18,
+       I40E_ERR_BAD_PTR                        = -19,
+       I40E_ERR_RING_FULL                      = -20,
+       I40E_ERR_INVALID_PD_ID                  = -21,
+       I40E_ERR_INVALID_QP_ID                  = -22,
+       I40E_ERR_INVALID_CQ_ID                  = -23,
+       I40E_ERR_INVALID_CEQ_ID                 = -24,
+       I40E_ERR_INVALID_AEQ_ID                 = -25,
+       I40E_ERR_INVALID_SIZE                   = -26,
+       I40E_ERR_INVALID_ARP_INDEX              = -27,
+       I40E_ERR_INVALID_FPM_FUNC_ID            = -28,
+       I40E_ERR_QP_INVALID_MSG_SIZE            = -29,
+       I40E_ERR_QP_TOOMANY_WRS_POSTED          = -30,
+       I40E_ERR_INVALID_FRAG_COUNT             = -31,
+       I40E_ERR_QUEUE_EMPTY                    = -32,
+       I40E_ERR_INVALID_ALIGNMENT              = -33,
+       I40E_ERR_FLUSHED_QUEUE                  = -34,
+       I40E_ERR_INVALID_PUSH_PAGE_INDEX        = -35,
+       I40E_ERR_INVALID_IMM_DATA_SIZE          = -36,
+       I40E_ERR_TIMEOUT                        = -37,
+       I40E_ERR_OPCODE_MISMATCH                = -38,
+       I40E_ERR_CQP_COMPL_ERROR                = -39,
+       I40E_ERR_INVALID_VF_ID                  = -40,
+       I40E_ERR_INVALID_HMCFN_ID               = -41,
+       I40E_ERR_BACKING_PAGE_ERROR             = -42,
+       I40E_ERR_NO_PBLCHUNKS_AVAILABLE         = -43,
+       I40E_ERR_INVALID_PBLE_INDEX             = -44,
+       I40E_ERR_INVALID_SD_INDEX               = -45,
+       I40E_ERR_INVALID_PAGE_DESC_INDEX        = -46,
+       I40E_ERR_INVALID_SD_TYPE                = -47,
+       I40E_ERR_MEMCPY_FAILED                  = -48,
+       I40E_ERR_INVALID_HMC_OBJ_INDEX          = -49,
+       I40E_ERR_INVALID_HMC_OBJ_COUNT          = -50,
+       I40E_ERR_INVALID_SRQ_ARM_LIMIT          = -51,
+       I40E_ERR_SRQ_ENABLED                    = -52,
+       I40E_ERR_ADMIN_QUEUE_ERROR              = -53,
+       I40E_ERR_ADMIN_QUEUE_TIMEOUT            = -54,
+       I40E_ERR_BUF_TOO_SHORT                  = -55,
+       I40E_ERR_ADMIN_QUEUE_FULL               = -56,
+       I40E_ERR_ADMIN_QUEUE_NO_WORK            = -57,
+       I40E_ERR_BAD_IWARP_CQE                  = -58,
+       I40E_ERR_NVM_BLANK_MODE                 = -59,
+       I40E_ERR_NOT_IMPLEMENTED                = -60,
+       I40E_ERR_PE_DOORBELL_NOT_ENABLED        = -61,
+       I40E_ERR_DIAG_TEST_FAILED               = -62,
+       I40E_ERR_NOT_READY                      = -63,
+       I40E_NOT_SUPPORTED                      = -64,
+       I40E_ERR_FIRMWARE_API_VERSION           = -65,
+};
+
+#endif /* _I40E_STATUS_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
new file mode 100644 (file)
index 0000000..49d2cfa
--- /dev/null
@@ -0,0 +1,1817 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e.h"
+
+static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size,
+                               u32 td_tag)
+{
+       return cpu_to_le64(I40E_TX_DESC_DTYPE_DATA |
+                          ((u64)td_cmd  << I40E_TXD_QW1_CMD_SHIFT) |
+                          ((u64)td_offset << I40E_TXD_QW1_OFFSET_SHIFT) |
+                          ((u64)size  << I40E_TXD_QW1_TX_BUF_SZ_SHIFT) |
+                          ((u64)td_tag  << I40E_TXD_QW1_L2TAG1_SHIFT));
+}
+
+/**
+ * i40e_program_fdir_filter - Program a Flow Director filter
+ * @fdir_input: Packet data that will be filter parameters
+ * @pf: The pf pointer
+ * @add: True for add/update, False for remove
+ **/
+int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data,
+                            struct i40e_pf *pf, bool add)
+{
+       struct i40e_filter_program_desc *fdir_desc;
+       struct i40e_tx_buffer *tx_buf;
+       struct i40e_tx_desc *tx_desc;
+       struct i40e_ring *tx_ring;
+       struct i40e_vsi *vsi;
+       struct device *dev;
+       dma_addr_t dma;
+       u32 td_cmd = 0;
+       u16 i;
+
+       /* find existing FDIR VSI */
+       vsi = NULL;
+       for (i = 0; i < pf->hw.func_caps.num_vsis; i++)
+               if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR)
+                       vsi = pf->vsi[i];
+       if (!vsi)
+               return -ENOENT;
+
+       tx_ring = &vsi->tx_rings[0];
+       dev = tx_ring->dev;
+
+       dma = dma_map_single(dev, fdir_data->raw_packet,
+                               I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, dma))
+               goto dma_fail;
+
+       /* grab the next descriptor */
+       fdir_desc = I40E_TX_FDIRDESC(tx_ring, tx_ring->next_to_use);
+       tx_buf = &tx_ring->tx_bi[tx_ring->next_to_use];
+       tx_ring->next_to_use++;
+       if (tx_ring->next_to_use == tx_ring->count)
+               tx_ring->next_to_use = 0;
+
+       fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32((fdir_data->q_index
+                                            << I40E_TXD_FLTR_QW0_QINDEX_SHIFT)
+                                            & I40E_TXD_FLTR_QW0_QINDEX_MASK);
+
+       fdir_desc->qindex_flex_ptype_vsi |= cpu_to_le32((fdir_data->flex_off
+                                           << I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT)
+                                           & I40E_TXD_FLTR_QW0_FLEXOFF_MASK);
+
+       fdir_desc->qindex_flex_ptype_vsi |= cpu_to_le32((fdir_data->pctype
+                                            << I40E_TXD_FLTR_QW0_PCTYPE_SHIFT)
+                                            & I40E_TXD_FLTR_QW0_PCTYPE_MASK);
+
+       /* Use LAN VSI Id if not programmed by user */
+       if (fdir_data->dest_vsi == 0)
+               fdir_desc->qindex_flex_ptype_vsi |=
+                                         cpu_to_le32((pf->vsi[pf->lan_vsi]->id)
+                                          << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT);
+       else
+               fdir_desc->qindex_flex_ptype_vsi |=
+                                           cpu_to_le32((fdir_data->dest_vsi
+                                           << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT)
+                                           & I40E_TXD_FLTR_QW0_DEST_VSI_MASK);
+
+       fdir_desc->dtype_cmd_cntindex =
+                                   cpu_to_le32(I40E_TX_DESC_DTYPE_FILTER_PROG);
+
+       if (add)
+               fdir_desc->dtype_cmd_cntindex |= cpu_to_le32(
+                                      I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE
+                                       << I40E_TXD_FLTR_QW1_PCMD_SHIFT);
+       else
+               fdir_desc->dtype_cmd_cntindex |= cpu_to_le32(
+                                          I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE
+                                          << I40E_TXD_FLTR_QW1_PCMD_SHIFT);
+
+       fdir_desc->dtype_cmd_cntindex |= cpu_to_le32((fdir_data->dest_ctl
+                                         << I40E_TXD_FLTR_QW1_DEST_SHIFT)
+                                         & I40E_TXD_FLTR_QW1_DEST_MASK);
+
+       fdir_desc->dtype_cmd_cntindex |= cpu_to_le32(
+                    (fdir_data->fd_status << I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT)
+                     & I40E_TXD_FLTR_QW1_FD_STATUS_MASK);
+
+       if (fdir_data->cnt_index != 0) {
+               fdir_desc->dtype_cmd_cntindex |=
+                                   cpu_to_le32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK);
+               fdir_desc->dtype_cmd_cntindex |=
+                                           cpu_to_le32((fdir_data->cnt_index
+                                           << I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT)
+                                           & I40E_TXD_FLTR_QW1_CNTINDEX_MASK);
+       }
+
+       fdir_desc->fd_id = cpu_to_le32(fdir_data->fd_id);
+
+       /* Now program a dummy descriptor */
+       tx_desc = I40E_TX_DESC(tx_ring, tx_ring->next_to_use);
+       tx_buf = &tx_ring->tx_bi[tx_ring->next_to_use];
+       tx_ring->next_to_use++;
+       if (tx_ring->next_to_use == tx_ring->count)
+               tx_ring->next_to_use = 0;
+
+       tx_desc->buffer_addr = cpu_to_le64(dma);
+       td_cmd = I40E_TX_DESC_CMD_EOP |
+                I40E_TX_DESC_CMD_RS  |
+                I40E_TX_DESC_CMD_DUMMY;
+
+       tx_desc->cmd_type_offset_bsz =
+               build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0);
+
+       /* Mark the data descriptor to be watched */
+       tx_buf->next_to_watch = tx_desc;
+
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+
+       writel(tx_ring->next_to_use, tx_ring->tail);
+       return 0;
+
+dma_fail:
+       return -1;
+}
+
+/**
+ * i40e_fd_handle_status - check the Programming Status for FD
+ * @rx_ring: the Rx ring for this descriptor
+ * @qw: the descriptor data
+ * @prog_id: the id originally used for programming
+ *
+ * This is used to verify if the FD programming or invalidation
+ * requested by SW to the HW is successful or not and take actions accordingly.
+ **/
+static void i40e_fd_handle_status(struct i40e_ring *rx_ring, u32 qw, u8 prog_id)
+{
+       struct pci_dev *pdev = rx_ring->vsi->back->pdev;
+       u32 error;
+
+       error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >>
+               I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT;
+
+       /* for now just print the Status */
+       dev_info(&pdev->dev, "FD programming id %02x, Status %08x\n",
+                prog_id, error);
+}
+
+/**
+ * i40e_unmap_tx_resource - Release a Tx buffer
+ * @ring:      the ring that owns the buffer
+ * @tx_buffer: the buffer to free
+ **/
+static inline void i40e_unmap_tx_resource(struct i40e_ring *ring,
+                                         struct i40e_tx_buffer *tx_buffer)
+{
+       if (tx_buffer->dma) {
+               if (tx_buffer->tx_flags & I40E_TX_FLAGS_MAPPED_AS_PAGE)
+                       dma_unmap_page(ring->dev,
+                                      tx_buffer->dma,
+                                      tx_buffer->length,
+                                      DMA_TO_DEVICE);
+               else
+                       dma_unmap_single(ring->dev,
+                                        tx_buffer->dma,
+                                        tx_buffer->length,
+                                        DMA_TO_DEVICE);
+       }
+       tx_buffer->dma = 0;
+       tx_buffer->time_stamp = 0;
+}
+
+/**
+ * i40e_clean_tx_ring - Free any empty Tx buffers
+ * @tx_ring: ring to be cleaned
+ **/
+void i40e_clean_tx_ring(struct i40e_ring *tx_ring)
+{
+       struct i40e_tx_buffer *tx_buffer;
+       unsigned long bi_size;
+       u16 i;
+
+       /* ring already cleared, nothing to do */
+       if (!tx_ring->tx_bi)
+               return;
+
+       /* Free all the Tx ring sk_buffs */
+       for (i = 0; i < tx_ring->count; i++) {
+               tx_buffer = &tx_ring->tx_bi[i];
+               i40e_unmap_tx_resource(tx_ring, tx_buffer);
+               if (tx_buffer->skb)
+                       dev_kfree_skb_any(tx_buffer->skb);
+               tx_buffer->skb = NULL;
+       }
+
+       bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count;
+       memset(tx_ring->tx_bi, 0, bi_size);
+
+       /* Zero out the descriptor ring */
+       memset(tx_ring->desc, 0, tx_ring->size);
+
+       tx_ring->next_to_use = 0;
+       tx_ring->next_to_clean = 0;
+}
+
+/**
+ * i40e_free_tx_resources - Free Tx resources per queue
+ * @tx_ring: Tx descriptor ring for a specific queue
+ *
+ * Free all transmit software resources
+ **/
+void i40e_free_tx_resources(struct i40e_ring *tx_ring)
+{
+       i40e_clean_tx_ring(tx_ring);
+       kfree(tx_ring->tx_bi);
+       tx_ring->tx_bi = NULL;
+
+       if (tx_ring->desc) {
+               dma_free_coherent(tx_ring->dev, tx_ring->size,
+                                 tx_ring->desc, tx_ring->dma);
+               tx_ring->desc = NULL;
+       }
+}
+
+/**
+ * i40e_get_tx_pending - how many tx descriptors not processed
+ * @tx_ring: the ring of descriptors
+ *
+ * Since there is no access to the ring head register
+ * in XL710, we need to use our local copies
+ **/
+static u32 i40e_get_tx_pending(struct i40e_ring *ring)
+{
+       u32 ntu = ((ring->next_to_clean <= ring->next_to_use)
+                       ? ring->next_to_use
+                       : ring->next_to_use + ring->count);
+       return ntu - ring->next_to_clean;
+}
+
+/**
+ * i40e_check_tx_hang - Is there a hang in the Tx queue
+ * @tx_ring: the ring of descriptors
+ **/
+static bool i40e_check_tx_hang(struct i40e_ring *tx_ring)
+{
+       u32 tx_pending = i40e_get_tx_pending(tx_ring);
+       bool ret = false;
+
+       clear_check_for_tx_hang(tx_ring);
+
+       /* Check for a hung queue, but be thorough. This verifies
+        * that a transmit has been completed since the previous
+        * check AND there is at least one packet pending. The
+        * ARMED bit is set to indicate a potential hang. The
+        * bit is cleared if a pause frame is received to remove
+        * false hang detection due to PFC or 802.3x frames. By
+        * requiring this to fail twice we avoid races with
+        * PFC clearing the ARMED bit and conditions where we
+        * run the check_tx_hang logic with a transmit completion
+        * pending but without time to complete it yet.
+        */
+       if ((tx_ring->tx_stats.tx_done_old == tx_ring->tx_stats.packets) &&
+           tx_pending) {
+               /* make sure it is true for two checks in a row */
+               ret = test_and_set_bit(__I40E_HANG_CHECK_ARMED,
+                                      &tx_ring->state);
+       } else {
+               /* update completed stats and disarm the hang check */
+               tx_ring->tx_stats.tx_done_old = tx_ring->tx_stats.packets;
+               clear_bit(__I40E_HANG_CHECK_ARMED, &tx_ring->state);
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_clean_tx_irq - Reclaim resources after transmit completes
+ * @tx_ring:  tx ring to clean
+ * @budget:   how many cleans we're allowed
+ *
+ * Returns true if there's any budget left (e.g. the clean is finished)
+ **/
+static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
+{
+       u16 i = tx_ring->next_to_clean;
+       struct i40e_tx_buffer *tx_buf;
+       struct i40e_tx_desc *tx_desc;
+       unsigned int total_packets = 0;
+       unsigned int total_bytes = 0;
+
+       tx_buf = &tx_ring->tx_bi[i];
+       tx_desc = I40E_TX_DESC(tx_ring, i);
+
+       for (; budget; budget--) {
+               struct i40e_tx_desc *eop_desc;
+
+               eop_desc = tx_buf->next_to_watch;
+
+               /* if next_to_watch is not set then there is no work pending */
+               if (!eop_desc)
+                       break;
+
+               /* if the descriptor isn't done, no work yet to do */
+               if (!(eop_desc->cmd_type_offset_bsz &
+                     cpu_to_le64(I40E_TX_DESC_DTYPE_DESC_DONE)))
+                       break;
+
+               /* count the packet as being completed */
+               tx_ring->tx_stats.completed++;
+               tx_buf->next_to_watch = NULL;
+               tx_buf->time_stamp = 0;
+
+               /* set memory barrier before eop_desc is verified */
+               rmb();
+
+               do {
+                       i40e_unmap_tx_resource(tx_ring, tx_buf);
+
+                       /* clear dtype status */
+                       tx_desc->cmd_type_offset_bsz &=
+                               ~cpu_to_le64(I40E_TXD_QW1_DTYPE_MASK);
+
+                       if (likely(tx_desc == eop_desc)) {
+                               eop_desc = NULL;
+
+                               dev_kfree_skb_any(tx_buf->skb);
+                               tx_buf->skb = NULL;
+
+                               total_bytes += tx_buf->bytecount;
+                               total_packets += tx_buf->gso_segs;
+                       }
+
+                       tx_buf++;
+                       tx_desc++;
+                       i++;
+                       if (unlikely(i == tx_ring->count)) {
+                               i = 0;
+                               tx_buf = tx_ring->tx_bi;
+                               tx_desc = I40E_TX_DESC(tx_ring, 0);
+                       }
+               } while (eop_desc);
+       }
+
+       tx_ring->next_to_clean = i;
+       tx_ring->tx_stats.bytes += total_bytes;
+       tx_ring->tx_stats.packets += total_packets;
+       tx_ring->q_vector->tx.total_bytes += total_bytes;
+       tx_ring->q_vector->tx.total_packets += total_packets;
+       if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) {
+               /* schedule immediate reset if we believe we hung */
+               dev_info(tx_ring->dev, "Detected Tx Unit Hang\n"
+                        "  VSI                  <%d>\n"
+                        "  Tx Queue             <%d>\n"
+                        "  next_to_use          <%x>\n"
+                        "  next_to_clean        <%x>\n",
+                        tx_ring->vsi->seid,
+                        tx_ring->queue_index,
+                        tx_ring->next_to_use, i);
+               dev_info(tx_ring->dev, "tx_bi[next_to_clean]\n"
+                        "  time_stamp           <%lx>\n"
+                        "  jiffies              <%lx>\n",
+                        tx_ring->tx_bi[i].time_stamp, jiffies);
+
+               netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+               dev_info(tx_ring->dev,
+                        "tx hang detected on queue %d, resetting adapter\n",
+                        tx_ring->queue_index);
+
+               tx_ring->netdev->netdev_ops->ndo_tx_timeout(tx_ring->netdev);
+
+               /* the adapter is about to reset, no point in enabling stuff */
+               return true;
+       }
+
+#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
+       if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
+                    (I40E_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))) {
+               /* Make sure that anybody stopping the queue after this
+                * sees the new next_to_clean.
+                */
+               smp_mb();
+               if (__netif_subqueue_stopped(tx_ring->netdev,
+                                            tx_ring->queue_index) &&
+                  !test_bit(__I40E_DOWN, &tx_ring->vsi->state)) {
+                       netif_wake_subqueue(tx_ring->netdev,
+                                           tx_ring->queue_index);
+                       ++tx_ring->tx_stats.restart_queue;
+               }
+       }
+
+       return budget > 0;
+}
+
+/**
+ * i40e_set_new_dynamic_itr - Find new ITR level
+ * @rc: structure containing ring performance data
+ *
+ * Stores a new ITR value based on packets and byte counts during
+ * the last interrupt.  The advantage of per interrupt computation
+ * is faster updates and more accurate ITR for the current traffic
+ * pattern.  Constants in this function were computed based on
+ * theoretical maximum wire speed and thresholds were set based on
+ * testing data as well as attempting to minimize response time
+ * while increasing bulk throughput.
+ **/
+static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc)
+{
+       enum i40e_latency_range new_latency_range = rc->latency_range;
+       u32 new_itr = rc->itr;
+       int bytes_per_int;
+
+       if (rc->total_packets == 0 || !rc->itr)
+               return;
+
+       /* simple throttlerate management
+        *   0-10MB/s   lowest (100000 ints/s)
+        *  10-20MB/s   low    (20000 ints/s)
+        *  20-1249MB/s bulk   (8000 ints/s)
+        */
+       bytes_per_int = rc->total_bytes / rc->itr;
+       switch (rc->itr) {
+       case I40E_LOWEST_LATENCY:
+               if (bytes_per_int > 10)
+                       new_latency_range = I40E_LOW_LATENCY;
+               break;
+       case I40E_LOW_LATENCY:
+               if (bytes_per_int > 20)
+                       new_latency_range = I40E_BULK_LATENCY;
+               else if (bytes_per_int <= 10)
+                       new_latency_range = I40E_LOWEST_LATENCY;
+               break;
+       case I40E_BULK_LATENCY:
+               if (bytes_per_int <= 20)
+                       rc->latency_range = I40E_LOW_LATENCY;
+               break;
+       }
+
+       switch (new_latency_range) {
+       case I40E_LOWEST_LATENCY:
+               new_itr = I40E_ITR_100K;
+               break;
+       case I40E_LOW_LATENCY:
+               new_itr = I40E_ITR_20K;
+               break;
+       case I40E_BULK_LATENCY:
+               new_itr = I40E_ITR_8K;
+               break;
+       default:
+               break;
+       }
+
+       if (new_itr != rc->itr) {
+               /* do an exponential smoothing */
+               new_itr = (10 * new_itr * rc->itr) /
+                         ((9 * new_itr) + rc->itr);
+               rc->itr = new_itr & I40E_MAX_ITR;
+       }
+
+       rc->total_bytes = 0;
+       rc->total_packets = 0;
+}
+
+/**
+ * i40e_update_dynamic_itr - Adjust ITR based on bytes per int
+ * @q_vector: the vector to adjust
+ **/
+static void i40e_update_dynamic_itr(struct i40e_q_vector *q_vector)
+{
+       u16 vector = q_vector->vsi->base_vector + q_vector->v_idx;
+       struct i40e_hw *hw = &q_vector->vsi->back->hw;
+       u32 reg_addr;
+       u16 old_itr;
+
+       reg_addr = I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1);
+       old_itr = q_vector->rx.itr;
+       i40e_set_new_dynamic_itr(&q_vector->rx);
+       if (old_itr != q_vector->rx.itr)
+               wr32(hw, reg_addr, q_vector->rx.itr);
+
+       reg_addr = I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1);
+       old_itr = q_vector->tx.itr;
+       i40e_set_new_dynamic_itr(&q_vector->tx);
+       if (old_itr != q_vector->tx.itr)
+               wr32(hw, reg_addr, q_vector->tx.itr);
+
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_clean_programming_status - clean the programming status descriptor
+ * @rx_ring: the rx ring that has this descriptor
+ * @rx_desc: the rx descriptor written back by HW
+ *
+ * Flow director should handle FD_FILTER_STATUS to check its filter programming
+ * status being successful or not and take actions accordingly. FCoE should
+ * handle its context/filter programming/invalidation status and take actions.
+ *
+ **/
+static void i40e_clean_programming_status(struct i40e_ring *rx_ring,
+                                         union i40e_rx_desc *rx_desc)
+{
+       u64 qw;
+       u8 id;
+
+       qw = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
+       id = (qw & I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK) >>
+                 I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT;
+
+       if (id == I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS)
+               i40e_fd_handle_status(rx_ring, qw, id);
+}
+
+/**
+ * i40e_setup_tx_descriptors - Allocate the Tx descriptors
+ * @tx_ring: the tx ring to set up
+ *
+ * Return 0 on success, negative on error
+ **/
+int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring)
+{
+       struct device *dev = tx_ring->dev;
+       int bi_size;
+
+       if (!dev)
+               return -ENOMEM;
+
+       bi_size = sizeof(struct i40e_tx_buffer) * tx_ring->count;
+       tx_ring->tx_bi = kzalloc(bi_size, GFP_KERNEL);
+       if (!tx_ring->tx_bi)
+               goto err;
+
+       /* round up to nearest 4K */
+       tx_ring->size = tx_ring->count * sizeof(struct i40e_tx_desc);
+       tx_ring->size = ALIGN(tx_ring->size, 4096);
+       tx_ring->desc = dma_alloc_coherent(dev, tx_ring->size,
+                                          &tx_ring->dma, GFP_KERNEL);
+       if (!tx_ring->desc) {
+               dev_info(dev, "Unable to allocate memory for the Tx descriptor ring, size=%d\n",
+                        tx_ring->size);
+               goto err;
+       }
+
+       tx_ring->next_to_use = 0;
+       tx_ring->next_to_clean = 0;
+       return 0;
+
+err:
+       kfree(tx_ring->tx_bi);
+       tx_ring->tx_bi = NULL;
+       return -ENOMEM;
+}
+
+/**
+ * i40e_clean_rx_ring - Free Rx buffers
+ * @rx_ring: ring to be cleaned
+ **/
+void i40e_clean_rx_ring(struct i40e_ring *rx_ring)
+{
+       struct device *dev = rx_ring->dev;
+       struct i40e_rx_buffer *rx_bi;
+       unsigned long bi_size;
+       u16 i;
+
+       /* ring already cleared, nothing to do */
+       if (!rx_ring->rx_bi)
+               return;
+
+       /* Free all the Rx ring sk_buffs */
+       for (i = 0; i < rx_ring->count; i++) {
+               rx_bi = &rx_ring->rx_bi[i];
+               if (rx_bi->dma) {
+                       dma_unmap_single(dev,
+                                        rx_bi->dma,
+                                        rx_ring->rx_buf_len,
+                                        DMA_FROM_DEVICE);
+                       rx_bi->dma = 0;
+               }
+               if (rx_bi->skb) {
+                       dev_kfree_skb(rx_bi->skb);
+                       rx_bi->skb = NULL;
+               }
+               if (rx_bi->page) {
+                       if (rx_bi->page_dma) {
+                               dma_unmap_page(dev,
+                                              rx_bi->page_dma,
+                                              PAGE_SIZE / 2,
+                                              DMA_FROM_DEVICE);
+                               rx_bi->page_dma = 0;
+                       }
+                       __free_page(rx_bi->page);
+                       rx_bi->page = NULL;
+                       rx_bi->page_offset = 0;
+               }
+       }
+
+       bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count;
+       memset(rx_ring->rx_bi, 0, bi_size);
+
+       /* Zero out the descriptor ring */
+       memset(rx_ring->desc, 0, rx_ring->size);
+
+       rx_ring->next_to_clean = 0;
+       rx_ring->next_to_use = 0;
+}
+
+/**
+ * i40e_free_rx_resources - Free Rx resources
+ * @rx_ring: ring to clean the resources from
+ *
+ * Free all receive software resources
+ **/
+void i40e_free_rx_resources(struct i40e_ring *rx_ring)
+{
+       i40e_clean_rx_ring(rx_ring);
+       kfree(rx_ring->rx_bi);
+       rx_ring->rx_bi = NULL;
+
+       if (rx_ring->desc) {
+               dma_free_coherent(rx_ring->dev, rx_ring->size,
+                                 rx_ring->desc, rx_ring->dma);
+               rx_ring->desc = NULL;
+       }
+}
+
+/**
+ * i40e_setup_rx_descriptors - Allocate Rx descriptors
+ * @rx_ring: Rx descriptor ring (for a specific queue) to setup
+ *
+ * Returns 0 on success, negative on failure
+ **/
+int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
+{
+       struct device *dev = rx_ring->dev;
+       int bi_size;
+
+       bi_size = sizeof(struct i40e_rx_buffer) * rx_ring->count;
+       rx_ring->rx_bi = kzalloc(bi_size, GFP_KERNEL);
+       if (!rx_ring->rx_bi)
+               goto err;
+
+       /* Round up to nearest 4K */
+       rx_ring->size = ring_is_16byte_desc_enabled(rx_ring)
+               ? rx_ring->count * sizeof(union i40e_16byte_rx_desc)
+               : rx_ring->count * sizeof(union i40e_32byte_rx_desc);
+       rx_ring->size = ALIGN(rx_ring->size, 4096);
+       rx_ring->desc = dma_alloc_coherent(dev, rx_ring->size,
+                                          &rx_ring->dma, GFP_KERNEL);
+
+       if (!rx_ring->desc) {
+               dev_info(dev, "Unable to allocate memory for the Rx descriptor ring, size=%d\n",
+                        rx_ring->size);
+               goto err;
+       }
+
+       rx_ring->next_to_clean = 0;
+       rx_ring->next_to_use = 0;
+
+       return 0;
+err:
+       kfree(rx_ring->rx_bi);
+       rx_ring->rx_bi = NULL;
+       return -ENOMEM;
+}
+
+/**
+ * i40e_release_rx_desc - Store the new tail and head values
+ * @rx_ring: ring to bump
+ * @val: new head index
+ **/
+static inline void i40e_release_rx_desc(struct i40e_ring *rx_ring, u32 val)
+{
+       rx_ring->next_to_use = val;
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+       writel(val, rx_ring->tail);
+}
+
+/**
+ * i40e_alloc_rx_buffers - Replace used receive buffers; packet split
+ * @rx_ring: ring to place buffers on
+ * @cleaned_count: number of buffers to replace
+ **/
+void i40e_alloc_rx_buffers(struct i40e_ring *rx_ring, u16 cleaned_count)
+{
+       u16 i = rx_ring->next_to_use;
+       union i40e_rx_desc *rx_desc;
+       struct i40e_rx_buffer *bi;
+       struct sk_buff *skb;
+
+       /* do nothing if no valid netdev defined */
+       if (!rx_ring->netdev || !cleaned_count)
+               return;
+
+       while (cleaned_count--) {
+               rx_desc = I40E_RX_DESC(rx_ring, i);
+               bi = &rx_ring->rx_bi[i];
+               skb = bi->skb;
+
+               if (!skb) {
+                       skb = netdev_alloc_skb_ip_align(rx_ring->netdev,
+                                                       rx_ring->rx_buf_len);
+                       if (!skb) {
+                               rx_ring->rx_stats.alloc_rx_buff_failed++;
+                               goto no_buffers;
+                       }
+                       /* initialize queue mapping */
+                       skb_record_rx_queue(skb, rx_ring->queue_index);
+                       bi->skb = skb;
+               }
+
+               if (!bi->dma) {
+                       bi->dma = dma_map_single(rx_ring->dev,
+                                                skb->data,
+                                                rx_ring->rx_buf_len,
+                                                DMA_FROM_DEVICE);
+                       if (dma_mapping_error(rx_ring->dev, bi->dma)) {
+                               rx_ring->rx_stats.alloc_rx_buff_failed++;
+                               bi->dma = 0;
+                               goto no_buffers;
+                       }
+               }
+
+               if (ring_is_ps_enabled(rx_ring)) {
+                       if (!bi->page) {
+                               bi->page = alloc_page(GFP_ATOMIC);
+                               if (!bi->page) {
+                                       rx_ring->rx_stats.alloc_rx_page_failed++;
+                                       goto no_buffers;
+                               }
+                       }
+
+                       if (!bi->page_dma) {
+                               /* use a half page if we're re-using */
+                               bi->page_offset ^= PAGE_SIZE / 2;
+                               bi->page_dma = dma_map_page(rx_ring->dev,
+                                                           bi->page,
+                                                           bi->page_offset,
+                                                           PAGE_SIZE / 2,
+                                                           DMA_FROM_DEVICE);
+                               if (dma_mapping_error(rx_ring->dev,
+                                                     bi->page_dma)) {
+                                       rx_ring->rx_stats.alloc_rx_page_failed++;
+                                       bi->page_dma = 0;
+                                       goto no_buffers;
+                               }
+                       }
+
+                       /* Refresh the desc even if buffer_addrs didn't change
+                        * because each write-back erases this info.
+                        */
+                       rx_desc->read.pkt_addr = cpu_to_le64(bi->page_dma);
+                       rx_desc->read.hdr_addr = cpu_to_le64(bi->dma);
+               } else {
+                       rx_desc->read.pkt_addr = cpu_to_le64(bi->dma);
+                       rx_desc->read.hdr_addr = 0;
+               }
+               i++;
+               if (i == rx_ring->count)
+                       i = 0;
+       }
+
+no_buffers:
+       if (rx_ring->next_to_use != i)
+               i40e_release_rx_desc(rx_ring, i);
+}
+
+/**
+ * i40e_receive_skb - Send a completed packet up the stack
+ * @rx_ring:  rx ring in play
+ * @skb: packet to send up
+ * @vlan_tag: vlan tag for packet
+ **/
+static void i40e_receive_skb(struct i40e_ring *rx_ring,
+                            struct sk_buff *skb, u16 vlan_tag)
+{
+       struct i40e_q_vector *q_vector = rx_ring->q_vector;
+       struct i40e_vsi *vsi = rx_ring->vsi;
+       u64 flags = vsi->back->flags;
+
+       if (vlan_tag & VLAN_VID_MASK)
+               __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag);
+
+       if (flags & I40E_FLAG_IN_NETPOLL)
+               netif_rx(skb);
+       else
+               napi_gro_receive(&q_vector->napi, skb);
+}
+
+/**
+ * i40e_rx_checksum - Indicate in skb if hw indicated a good cksum
+ * @vsi: the VSI we care about
+ * @skb: skb currently being received and modified
+ * @rx_status: status value of last descriptor in packet
+ * @rx_error: error value of last descriptor in packet
+ **/
+static inline void i40e_rx_checksum(struct i40e_vsi *vsi,
+                                   struct sk_buff *skb,
+                                   u32 rx_status,
+                                   u32 rx_error)
+{
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* Rx csum enabled and ip headers found? */
+       if (!(vsi->netdev->features & NETIF_F_RXCSUM &&
+             rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT)))
+               return;
+
+       /* IP or L4 checksum error */
+       if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) |
+                       (1 << I40E_RX_DESC_ERROR_L4E_SHIFT))) {
+               vsi->back->hw_csum_rx_error++;
+               return;
+       }
+
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+}
+
+/**
+ * i40e_rx_hash - returns the hash value from the Rx descriptor
+ * @ring: descriptor ring
+ * @rx_desc: specific descriptor
+ **/
+static inline u32 i40e_rx_hash(struct i40e_ring *ring,
+                              union i40e_rx_desc *rx_desc)
+{
+       if (ring->netdev->features & NETIF_F_RXHASH) {
+               if ((le64_to_cpu(rx_desc->wb.qword1.status_error_len) >>
+                    I40E_RX_DESC_STATUS_FLTSTAT_SHIFT) &
+                   I40E_RX_DESC_FLTSTAT_RSS_HASH)
+                       return le32_to_cpu(rx_desc->wb.qword0.hi_dword.rss);
+       }
+       return 0;
+}
+
+/**
+ * i40e_clean_rx_irq - Reclaim resources after receive completes
+ * @rx_ring:  rx ring to clean
+ * @budget:   how many cleans we're allowed
+ *
+ * Returns true if there's any budget left (e.g. the clean is finished)
+ **/
+static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget)
+{
+       unsigned int total_rx_bytes = 0, total_rx_packets = 0;
+       u16 rx_packet_len, rx_header_len, rx_sph, rx_hbo;
+       u16 cleaned_count = I40E_DESC_UNUSED(rx_ring);
+       const int current_node = numa_node_id();
+       struct i40e_vsi *vsi = rx_ring->vsi;
+       u16 i = rx_ring->next_to_clean;
+       union i40e_rx_desc *rx_desc;
+       u32 rx_error, rx_status;
+       u64 qword;
+
+       rx_desc = I40E_RX_DESC(rx_ring, i);
+       qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
+       rx_status = (qword & I40E_RXD_QW1_STATUS_MASK)
+                               >> I40E_RXD_QW1_STATUS_SHIFT;
+
+       while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) {
+               union i40e_rx_desc *next_rxd;
+               struct i40e_rx_buffer *rx_bi;
+               struct sk_buff *skb;
+               u16 vlan_tag;
+               if (i40e_rx_is_programming_status(qword)) {
+                       i40e_clean_programming_status(rx_ring, rx_desc);
+                       I40E_RX_NEXT_DESC_PREFETCH(rx_ring, i, next_rxd);
+                       goto next_desc;
+               }
+               rx_bi = &rx_ring->rx_bi[i];
+               skb = rx_bi->skb;
+               prefetch(skb->data);
+
+               rx_packet_len = (qword & I40E_RXD_QW1_LENGTH_PBUF_MASK)
+                                             >> I40E_RXD_QW1_LENGTH_PBUF_SHIFT;
+               rx_header_len = (qword & I40E_RXD_QW1_LENGTH_HBUF_MASK)
+                                             >> I40E_RXD_QW1_LENGTH_HBUF_SHIFT;
+               rx_sph = (qword & I40E_RXD_QW1_LENGTH_SPH_MASK)
+                                             >> I40E_RXD_QW1_LENGTH_SPH_SHIFT;
+
+               rx_error = (qword & I40E_RXD_QW1_ERROR_MASK)
+                                             >> I40E_RXD_QW1_ERROR_SHIFT;
+               rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT);
+               rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT);
+
+               rx_bi->skb = NULL;
+
+               /* This memory barrier is needed to keep us from reading
+                * any other fields out of the rx_desc until we know the
+                * STATUS_DD bit is set
+                */
+               rmb();
+
+               /* Get the header and possibly the whole packet
+                * If this is an skb from previous receive dma will be 0
+                */
+               if (rx_bi->dma) {
+                       u16 len;
+
+                       if (rx_hbo)
+                               len = I40E_RX_HDR_SIZE;
+                       else if (rx_sph)
+                               len = rx_header_len;
+                       else if (rx_packet_len)
+                               len = rx_packet_len;   /* 1buf/no split found */
+                       else
+                               len = rx_header_len;   /* split always mode */
+
+                       skb_put(skb, len);
+                       dma_unmap_single(rx_ring->dev,
+                                        rx_bi->dma,
+                                        rx_ring->rx_buf_len,
+                                        DMA_FROM_DEVICE);
+                       rx_bi->dma = 0;
+               }
+
+               /* Get the rest of the data if this was a header split */
+               if (ring_is_ps_enabled(rx_ring) && rx_packet_len) {
+
+                       skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags,
+                                          rx_bi->page,
+                                          rx_bi->page_offset,
+                                          rx_packet_len);
+
+                       skb->len += rx_packet_len;
+                       skb->data_len += rx_packet_len;
+                       skb->truesize += rx_packet_len;
+
+                       if ((page_count(rx_bi->page) == 1) &&
+                           (page_to_nid(rx_bi->page) == current_node))
+                               get_page(rx_bi->page);
+                       else
+                               rx_bi->page = NULL;
+
+                       dma_unmap_page(rx_ring->dev,
+                                      rx_bi->page_dma,
+                                      PAGE_SIZE / 2,
+                                      DMA_FROM_DEVICE);
+                       rx_bi->page_dma = 0;
+               }
+               I40E_RX_NEXT_DESC_PREFETCH(rx_ring, i, next_rxd);
+
+               if (unlikely(
+                   !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) {
+                       struct i40e_rx_buffer *next_buffer;
+
+                       next_buffer = &rx_ring->rx_bi[i];
+
+                       if (ring_is_ps_enabled(rx_ring)) {
+                               rx_bi->skb = next_buffer->skb;
+                               rx_bi->dma = next_buffer->dma;
+                               next_buffer->skb = skb;
+                               next_buffer->dma = 0;
+                       }
+                       rx_ring->rx_stats.non_eop_descs++;
+                       goto next_desc;
+               }
+
+               /* ERR_MASK will only have valid bits if EOP set */
+               if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) {
+                       dev_kfree_skb_any(skb);
+                       goto next_desc;
+               }
+
+               skb->rxhash = i40e_rx_hash(rx_ring, rx_desc);
+               i40e_rx_checksum(vsi, skb, rx_status, rx_error);
+
+               /* probably a little skewed due to removing CRC */
+               total_rx_bytes += skb->len;
+               total_rx_packets++;
+
+               skb->protocol = eth_type_trans(skb, rx_ring->netdev);
+               vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT)
+                        ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1)
+                        : 0;
+               i40e_receive_skb(rx_ring, skb, vlan_tag);
+
+               rx_ring->netdev->last_rx = jiffies;
+               budget--;
+next_desc:
+               rx_desc->wb.qword1.status_error_len = 0;
+               if (!budget)
+                       break;
+
+               cleaned_count++;
+               /* return some buffers to hardware, one at a time is too slow */
+               if (cleaned_count >= I40E_RX_BUFFER_WRITE) {
+                       i40e_alloc_rx_buffers(rx_ring, cleaned_count);
+                       cleaned_count = 0;
+               }
+
+               /* use prefetched values */
+               rx_desc = next_rxd;
+               qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len);
+               rx_status = (qword & I40E_RXD_QW1_STATUS_MASK)
+                                               >> I40E_RXD_QW1_STATUS_SHIFT;
+       }
+
+       rx_ring->next_to_clean = i;
+       rx_ring->rx_stats.packets += total_rx_packets;
+       rx_ring->rx_stats.bytes += total_rx_bytes;
+       rx_ring->q_vector->rx.total_packets += total_rx_packets;
+       rx_ring->q_vector->rx.total_bytes += total_rx_bytes;
+
+       if (cleaned_count)
+               i40e_alloc_rx_buffers(rx_ring, cleaned_count);
+
+       return budget > 0;
+}
+
+/**
+ * i40e_napi_poll - NAPI polling Rx/Tx cleanup routine
+ * @napi: napi struct with our devices info in it
+ * @budget: amount of work driver is allowed to do this pass, in packets
+ *
+ * This function will clean all queues associated with a q_vector.
+ *
+ * Returns the amount of work done
+ **/
+int i40e_napi_poll(struct napi_struct *napi, int budget)
+{
+       struct i40e_q_vector *q_vector =
+                              container_of(napi, struct i40e_q_vector, napi);
+       struct i40e_vsi *vsi = q_vector->vsi;
+       bool clean_complete = true;
+       int budget_per_ring;
+       int i;
+
+       if (test_bit(__I40E_DOWN, &vsi->state)) {
+               napi_complete(napi);
+               return 0;
+       }
+
+       /* We attempt to distribute budget to each Rx queue fairly, but don't
+        * allow the budget to go below 1 because that would exit polling early.
+        * Since the actual Tx work is minimal, we can give the Tx a larger
+        * budget and be more aggressive about cleaning up the Tx descriptors.
+        */
+       budget_per_ring = max(budget/q_vector->num_ringpairs, 1);
+       for (i = 0; i < q_vector->num_ringpairs; i++) {
+               clean_complete &= i40e_clean_tx_irq(q_vector->tx.ring[i],
+                                                   vsi->work_limit);
+               clean_complete &= i40e_clean_rx_irq(q_vector->rx.ring[i],
+                                                   budget_per_ring);
+       }
+
+       /* If work not completed, return budget and polling will return */
+       if (!clean_complete)
+               return budget;
+
+       /* Work is done so exit the polling mode and re-enable the interrupt */
+       napi_complete(napi);
+       if (ITR_IS_DYNAMIC(vsi->rx_itr_setting) ||
+           ITR_IS_DYNAMIC(vsi->tx_itr_setting))
+               i40e_update_dynamic_itr(q_vector);
+
+       if (!test_bit(__I40E_DOWN, &vsi->state)) {
+               if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) {
+                       i40e_irq_dynamic_enable(vsi,
+                                       q_vector->v_idx + vsi->base_vector);
+               } else {
+                       struct i40e_hw *hw = &vsi->back->hw;
+                       /* We re-enable the queue 0 cause, but
+                        * don't worry about dynamic_enable
+                        * because we left it on for the other
+                        * possible interrupts during napi
+                        */
+                       u32 qval = rd32(hw, I40E_QINT_RQCTL(0));
+                       qval |= I40E_QINT_RQCTL_CAUSE_ENA_MASK;
+                       wr32(hw, I40E_QINT_RQCTL(0), qval);
+
+                       qval = rd32(hw, I40E_QINT_TQCTL(0));
+                       qval |= I40E_QINT_TQCTL_CAUSE_ENA_MASK;
+                       wr32(hw, I40E_QINT_TQCTL(0), qval);
+                       i40e_flush(hw);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_atr - Add a Flow Director ATR filter
+ * @tx_ring:  ring to add programming descriptor to
+ * @skb:      send buffer
+ * @flags:    send flags
+ * @protocol: wire protocol
+ **/
+static void i40e_atr(struct i40e_ring *tx_ring, struct sk_buff *skb,
+                    u32 flags, __be16 protocol)
+{
+       struct i40e_filter_program_desc *fdir_desc;
+       struct i40e_pf *pf = tx_ring->vsi->back;
+       union {
+               unsigned char *network;
+               struct iphdr *ipv4;
+               struct ipv6hdr *ipv6;
+       } hdr;
+       struct tcphdr *th;
+       unsigned int hlen;
+       u32 flex_ptype, dtype_cmd;
+
+       /* make sure ATR is enabled */
+       if (!(pf->flags & I40E_FLAG_FDIR_ATR_ENABLED))
+               return;
+
+       /* if sampling is disabled do nothing */
+       if (!tx_ring->atr_sample_rate)
+               return;
+
+       tx_ring->atr_count++;
+
+       /* snag network header to get L4 type and address */
+       hdr.network = skb_network_header(skb);
+
+       /* Currently only IPv4/IPv6 with TCP is supported */
+       if (protocol == htons(ETH_P_IP)) {
+               if (hdr.ipv4->protocol != IPPROTO_TCP)
+                       return;
+
+               /* access ihl as a u8 to avoid unaligned access on ia64 */
+               hlen = (hdr.network[0] & 0x0F) << 2;
+       } else if (protocol == htons(ETH_P_IPV6)) {
+               if (hdr.ipv6->nexthdr != IPPROTO_TCP)
+                       return;
+
+               hlen = sizeof(struct ipv6hdr);
+       } else {
+               return;
+       }
+
+       th = (struct tcphdr *)(hdr.network + hlen);
+
+       /* sample on all syn/fin packets or once every atr sample rate */
+       if (!th->fin && !th->syn && (tx_ring->atr_count < tx_ring->atr_sample_rate))
+               return;
+
+       tx_ring->atr_count = 0;
+
+       /* grab the next descriptor */
+       fdir_desc = I40E_TX_FDIRDESC(tx_ring, tx_ring->next_to_use);
+       tx_ring->next_to_use++;
+       if (tx_ring->next_to_use == tx_ring->count)
+               tx_ring->next_to_use = 0;
+
+       flex_ptype = (tx_ring->queue_index << I40E_TXD_FLTR_QW0_QINDEX_SHIFT) &
+                     I40E_TXD_FLTR_QW0_QINDEX_MASK;
+       flex_ptype |= (protocol == htons(ETH_P_IP)) ?
+                     (I40E_FILTER_PCTYPE_NONF_IPV4_TCP <<
+                      I40E_TXD_FLTR_QW0_PCTYPE_SHIFT) :
+                     (I40E_FILTER_PCTYPE_NONF_IPV6_TCP <<
+                      I40E_TXD_FLTR_QW0_PCTYPE_SHIFT);
+
+       flex_ptype |= tx_ring->vsi->id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT;
+
+       dtype_cmd = I40E_TX_DESC_DTYPE_FILTER_PROG;
+
+       dtype_cmd |= th->fin ?
+                    (I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE <<
+                     I40E_TXD_FLTR_QW1_PCMD_SHIFT) :
+                    (I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE <<
+                     I40E_TXD_FLTR_QW1_PCMD_SHIFT);
+
+       dtype_cmd |= I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX <<
+                    I40E_TXD_FLTR_QW1_DEST_SHIFT;
+
+       dtype_cmd |= I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID <<
+                    I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT;
+
+       fdir_desc->qindex_flex_ptype_vsi = cpu_to_le32(flex_ptype);
+       fdir_desc->dtype_cmd_cntindex = cpu_to_le32(dtype_cmd);
+}
+
+#define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS)
+/**
+ * i40e_tx_prepare_vlan_flags - prepare generic TX VLAN tagging flags for HW
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ * @flags:   the tx flags to be set
+ *
+ * Checks the skb and set up correspondingly several generic transmit flags
+ * related to VLAN tagging for the HW, such as VLAN, DCB, etc.
+ *
+ * Returns error code indicate the frame should be dropped upon error and the
+ * otherwise  returns 0 to indicate the flags has been set properly.
+ **/
+static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
+                                     struct i40e_ring *tx_ring,
+                                     u32 *flags)
+{
+       __be16 protocol = skb->protocol;
+       u32  tx_flags = 0;
+
+       /* if we have a HW VLAN tag being added, default to the HW one */
+       if (vlan_tx_tag_present(skb)) {
+               tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT;
+               tx_flags |= I40E_TX_FLAGS_HW_VLAN;
+       /* else if it is a SW VLAN, check the next protocol and store the tag */
+       } else if (protocol == __constant_htons(ETH_P_8021Q)) {
+               struct vlan_hdr *vhdr, _vhdr;
+               vhdr = skb_header_pointer(skb, ETH_HLEN, sizeof(_vhdr), &_vhdr);
+               if (!vhdr)
+                       return -EINVAL;
+
+               protocol = vhdr->h_vlan_encapsulated_proto;
+               tx_flags |= ntohs(vhdr->h_vlan_TCI) << I40E_TX_FLAGS_VLAN_SHIFT;
+               tx_flags |= I40E_TX_FLAGS_SW_VLAN;
+       }
+
+       /* Insert 802.1p priority into VLAN header */
+       if ((tx_ring->vsi->back->flags & I40E_FLAG_DCB_ENABLED) &&
+           ((tx_flags & (I40E_TX_FLAGS_HW_VLAN | I40E_TX_FLAGS_SW_VLAN)) ||
+            (skb->priority != TC_PRIO_CONTROL))) {
+               tx_flags &= ~I40E_TX_FLAGS_VLAN_PRIO_MASK;
+               tx_flags |= (skb->priority & 0x7) <<
+                               I40E_TX_FLAGS_VLAN_PRIO_SHIFT;
+               if (tx_flags & I40E_TX_FLAGS_SW_VLAN) {
+                       struct vlan_ethhdr *vhdr;
+                       if (skb_header_cloned(skb) &&
+                           pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
+                               return -ENOMEM;
+                       vhdr = (struct vlan_ethhdr *)skb->data;
+                       vhdr->h_vlan_TCI = htons(tx_flags >>
+                                                I40E_TX_FLAGS_VLAN_SHIFT);
+               } else {
+                       tx_flags |= I40E_TX_FLAGS_HW_VLAN;
+               }
+       }
+       *flags = tx_flags;
+       return 0;
+}
+
+/**
+ * i40e_tx_csum - is checksum offload requested
+ * @tx_ring:  ptr to the ring to send
+ * @skb:      ptr to the skb we're sending
+ * @tx_flags: the collected send information
+ * @protocol: the send protocol
+ *
+ * Returns true if checksum offload is requested
+ **/
+static bool i40e_tx_csum(struct i40e_ring *tx_ring, struct sk_buff *skb,
+                        u32 tx_flags, __be16 protocol)
+{
+       if ((skb->ip_summed != CHECKSUM_PARTIAL) &&
+           !(tx_flags & I40E_TX_FLAGS_TXSW)) {
+               if (!(tx_flags & I40E_TX_FLAGS_HW_VLAN))
+                       return false;
+       }
+
+       return skb->ip_summed == CHECKSUM_PARTIAL;
+}
+
+/**
+ * i40e_tso - set up the tso context descriptor
+ * @tx_ring:  ptr to the ring to send
+ * @skb:      ptr to the skb we're sending
+ * @tx_flags: the collected send information
+ * @protocol: the send protocol
+ * @hdr_len:  ptr to the size of the packet header
+ * @cd_tunneling: ptr to context descriptor bits
+ *
+ * Returns 0 if no TSO can happen, 1 if tso is going, or error
+ **/
+static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb,
+                   u32 tx_flags, __be16 protocol, u8 *hdr_len,
+                   u64 *cd_type_cmd_tso_mss, u32 *cd_tunneling)
+{
+       u32 cd_cmd, cd_tso_len, cd_mss;
+       struct tcphdr *tcph;
+       struct iphdr *iph;
+       u32 l4len;
+       int err;
+       struct ipv6hdr *ipv6h;
+
+       if (!skb_is_gso(skb))
+               return 0;
+
+       if (skb_header_cloned(skb)) {
+               err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+               if (err)
+                       return err;
+       }
+
+       if (protocol == __constant_htons(ETH_P_IP)) {
+               iph = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb);
+               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
+               iph->tot_len = 0;
+               iph->check = 0;
+               tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr,
+                                                0, IPPROTO_TCP, 0);
+       } else if (skb_is_gso_v6(skb)) {
+
+               ipv6h = skb->encapsulation ? inner_ipv6_hdr(skb)
+                                          : ipv6_hdr(skb);
+               tcph = skb->encapsulation ? inner_tcp_hdr(skb) : tcp_hdr(skb);
+               ipv6h->payload_len = 0;
+               tcph->check = ~csum_ipv6_magic(&ipv6h->saddr, &ipv6h->daddr,
+                                              0, IPPROTO_TCP, 0);
+       }
+
+       l4len = skb->encapsulation ? inner_tcp_hdrlen(skb) : tcp_hdrlen(skb);
+       *hdr_len = (skb->encapsulation
+                   ? (skb_inner_transport_header(skb) - skb->data)
+                   : skb_transport_offset(skb)) + l4len;
+
+       /* find the field values */
+       cd_cmd = I40E_TX_CTX_DESC_TSO;
+       cd_tso_len = skb->len - *hdr_len;
+       cd_mss = skb_shinfo(skb)->gso_size;
+       *cd_type_cmd_tso_mss |= ((u64)cd_cmd << I40E_TXD_CTX_QW1_CMD_SHIFT)
+                            | ((u64)cd_tso_len
+                               << I40E_TXD_CTX_QW1_TSO_LEN_SHIFT)
+                            | ((u64)cd_mss << I40E_TXD_CTX_QW1_MSS_SHIFT);
+       return 1;
+}
+
+/**
+ * i40e_tx_enable_csum - Enable Tx checksum offloads
+ * @skb: send buffer
+ * @tx_flags: Tx flags currently set
+ * @td_cmd: Tx descriptor command bits to set
+ * @td_offset: Tx descriptor header offsets to set
+ * @cd_tunneling: ptr to context desc bits
+ **/
+static void i40e_tx_enable_csum(struct sk_buff *skb, u32 tx_flags,
+                               u32 *td_cmd, u32 *td_offset,
+                               struct i40e_ring *tx_ring,
+                               u32 *cd_tunneling)
+{
+       struct ipv6hdr *this_ipv6_hdr;
+       unsigned int this_tcp_hdrlen;
+       struct iphdr *this_ip_hdr;
+       u32 network_hdr_len;
+       u8 l4_hdr = 0;
+
+       if (skb->encapsulation) {
+               network_hdr_len = skb_inner_network_header_len(skb);
+               this_ip_hdr = inner_ip_hdr(skb);
+               this_ipv6_hdr = inner_ipv6_hdr(skb);
+               this_tcp_hdrlen = inner_tcp_hdrlen(skb);
+
+               if (tx_flags & I40E_TX_FLAGS_IPV4) {
+
+                       if (tx_flags & I40E_TX_FLAGS_TSO) {
+                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV4;
+                               ip_hdr(skb)->check = 0;
+                       } else {
+                               *cd_tunneling |=
+                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+                       }
+               } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
+                       if (tx_flags & I40E_TX_FLAGS_TSO) {
+                               *cd_tunneling |= I40E_TX_CTX_EXT_IP_IPV6;
+                               ip_hdr(skb)->check = 0;
+                       } else {
+                               *cd_tunneling |=
+                                        I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM;
+                       }
+               }
+
+               /* Now set the ctx descriptor fields */
+               *cd_tunneling |= (skb_network_header_len(skb) >> 2) <<
+                                       I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT |
+                                  I40E_TXD_CTX_UDP_TUNNELING            |
+                                  ((skb_inner_network_offset(skb) -
+                                       skb_transport_offset(skb)) >> 1) <<
+                                  I40E_TXD_CTX_QW0_NATLEN_SHIFT;
+
+       } else {
+               network_hdr_len = skb_network_header_len(skb);
+               this_ip_hdr = ip_hdr(skb);
+               this_ipv6_hdr = ipv6_hdr(skb);
+               this_tcp_hdrlen = tcp_hdrlen(skb);
+       }
+
+       /* Enable IP checksum offloads */
+       if (tx_flags & I40E_TX_FLAGS_IPV4) {
+               l4_hdr = this_ip_hdr->protocol;
+               /* the stack computes the IP header already, the only time we
+                * need the hardware to recompute it is in the case of TSO.
+                */
+               if (tx_flags & I40E_TX_FLAGS_TSO) {
+                       *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4_CSUM;
+                       this_ip_hdr->check = 0;
+               } else {
+                       *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV4;
+               }
+               /* Now set the td_offset for IP header length */
+               *td_offset = (network_hdr_len >> 2) <<
+                             I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+       } else if (tx_flags & I40E_TX_FLAGS_IPV6) {
+               l4_hdr = this_ipv6_hdr->nexthdr;
+               *td_cmd |= I40E_TX_DESC_CMD_IIPT_IPV6;
+               /* Now set the td_offset for IP header length */
+               *td_offset = (network_hdr_len >> 2) <<
+                             I40E_TX_DESC_LENGTH_IPLEN_SHIFT;
+       }
+       /* words in MACLEN + dwords in IPLEN + dwords in L4Len */
+       *td_offset |= (skb_network_offset(skb) >> 1) <<
+                      I40E_TX_DESC_LENGTH_MACLEN_SHIFT;
+
+       /* Enable L4 checksum offloads */
+       switch (l4_hdr) {
+       case IPPROTO_TCP:
+               /* enable checksum offloads */
+               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_TCP;
+               *td_offset |= (this_tcp_hdrlen >> 2) <<
+                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               break;
+       case IPPROTO_SCTP:
+               /* enable SCTP checksum offload */
+               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_SCTP;
+               *td_offset |= (sizeof(struct sctphdr) >> 2) <<
+                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               break;
+       case IPPROTO_UDP:
+               /* enable UDP checksum offload */
+               *td_cmd |= I40E_TX_DESC_CMD_L4T_EOFT_UDP;
+               *td_offset |= (sizeof(struct udphdr) >> 2) <<
+                              I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT;
+               break;
+       default:
+               break;
+       }
+}
+
+/**
+ * i40e_create_tx_ctx Build the Tx context descriptor
+ * @tx_ring:  ring to create the descriptor on
+ * @cd_type_cmd_tso_mss: Quad Word 1
+ * @cd_tunneling: Quad Word 0 - bits 0-31
+ * @cd_l2tag2: Quad Word 0 - bits 32-63
+ **/
+static void i40e_create_tx_ctx(struct i40e_ring *tx_ring,
+                              const u64 cd_type_cmd_tso_mss,
+                              const u32 cd_tunneling, const u32 cd_l2tag2)
+{
+       struct i40e_tx_context_desc *context_desc;
+
+       if (!cd_type_cmd_tso_mss && !cd_tunneling && !cd_l2tag2)
+               return;
+
+       /* grab the next descriptor */
+       context_desc = I40E_TX_CTXTDESC(tx_ring, tx_ring->next_to_use);
+       tx_ring->next_to_use++;
+       if (tx_ring->next_to_use == tx_ring->count)
+               tx_ring->next_to_use = 0;
+
+       /* cpu_to_le32 and assign to struct fields */
+       context_desc->tunneling_params = cpu_to_le32(cd_tunneling);
+       context_desc->l2tag2 = cpu_to_le16(cd_l2tag2);
+       context_desc->type_cmd_tso_mss = cpu_to_le64(cd_type_cmd_tso_mss);
+}
+
+/**
+ * i40e_tx_map - Build the Tx descriptor
+ * @tx_ring:  ring to send buffer on
+ * @skb:      send buffer
+ * @first:    first buffer info buffer to use
+ * @tx_flags: collected send information
+ * @hdr_len:  size of the packet header
+ * @td_cmd:   the command field in the descriptor
+ * @td_offset: offset for checksum or crc
+ **/
+static void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
+                       struct i40e_tx_buffer *first, u32 tx_flags,
+                       const u8 hdr_len, u32 td_cmd, u32 td_offset)
+{
+       struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
+       unsigned int data_len = skb->data_len;
+       unsigned int size = skb_headlen(skb);
+       struct device *dev = tx_ring->dev;
+       u32 paylen = skb->len - hdr_len;
+       u16 i = tx_ring->next_to_use;
+       struct i40e_tx_buffer *tx_bi;
+       struct i40e_tx_desc *tx_desc;
+       u32 buf_offset = 0;
+       u32 td_tag = 0;
+       dma_addr_t dma;
+       u16 gso_segs;
+
+       dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
+       if (dma_mapping_error(dev, dma))
+               goto dma_error;
+
+       if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
+               td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
+               td_tag = (tx_flags & I40E_TX_FLAGS_VLAN_MASK) >>
+                        I40E_TX_FLAGS_VLAN_SHIFT;
+       }
+
+       tx_desc = I40E_TX_DESC(tx_ring, i);
+       for (;;) {
+               while (size > I40E_MAX_DATA_PER_TXD) {
+                       tx_desc->buffer_addr = cpu_to_le64(dma + buf_offset);
+                       tx_desc->cmd_type_offset_bsz =
+                               build_ctob(td_cmd, td_offset,
+                                          I40E_MAX_DATA_PER_TXD, td_tag);
+
+                       buf_offset += I40E_MAX_DATA_PER_TXD;
+                       size -= I40E_MAX_DATA_PER_TXD;
+
+                       tx_desc++;
+                       i++;
+                       if (i == tx_ring->count) {
+                               tx_desc = I40E_TX_DESC(tx_ring, 0);
+                               i = 0;
+                       }
+               }
+
+               tx_bi = &tx_ring->tx_bi[i];
+               tx_bi->length = buf_offset + size;
+               tx_bi->tx_flags = tx_flags;
+               tx_bi->dma = dma;
+
+               tx_desc->buffer_addr = cpu_to_le64(dma + buf_offset);
+               tx_desc->cmd_type_offset_bsz = build_ctob(td_cmd, td_offset,
+                                                         size, td_tag);
+
+               if (likely(!data_len))
+                       break;
+
+               size = skb_frag_size(frag);
+               data_len -= size;
+               buf_offset = 0;
+               tx_flags |= I40E_TX_FLAGS_MAPPED_AS_PAGE;
+
+               dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
+               if (dma_mapping_error(dev, dma))
+                       goto dma_error;
+
+               tx_desc++;
+               i++;
+               if (i == tx_ring->count) {
+                       tx_desc = I40E_TX_DESC(tx_ring, 0);
+                       i = 0;
+               }
+
+               frag++;
+       }
+
+       tx_desc->cmd_type_offset_bsz |=
+                      cpu_to_le64((u64)I40E_TXD_CMD << I40E_TXD_QW1_CMD_SHIFT);
+
+       i++;
+       if (i == tx_ring->count)
+               i = 0;
+
+       tx_ring->next_to_use = i;
+
+       if (tx_flags & (I40E_TX_FLAGS_TSO | I40E_TX_FLAGS_FSO))
+               gso_segs = skb_shinfo(skb)->gso_segs;
+       else
+               gso_segs = 1;
+
+       /* multiply data chunks by size of headers */
+       tx_bi->bytecount = paylen + (gso_segs * hdr_len);
+       tx_bi->gso_segs = gso_segs;
+       tx_bi->skb = skb;
+
+       /* set the timestamp and next to watch values */
+       first->time_stamp = jiffies;
+       first->next_to_watch = tx_desc;
+
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+
+       writel(i, tx_ring->tail);
+       return;
+
+dma_error:
+       dev_info(dev, "TX DMA map failed\n");
+
+       /* clear dma mappings for failed tx_bi map */
+       for (;;) {
+               tx_bi = &tx_ring->tx_bi[i];
+               i40e_unmap_tx_resource(tx_ring, tx_bi);
+               if (tx_bi == first)
+                       break;
+               if (i == 0)
+                       i = tx_ring->count;
+               i--;
+       }
+
+       dev_kfree_skb_any(skb);
+
+       tx_ring->next_to_use = i;
+}
+
+/**
+ * __i40e_maybe_stop_tx - 2nd level check for tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size:    the size buffer we want to assure is available
+ *
+ * Returns -EBUSY if a stop is needed, else 0
+ **/
+static inline int __i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+       smp_mb();
+
+       /* Check again in a case another CPU has just made room available. */
+       if (likely(I40E_DESC_UNUSED(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+       ++tx_ring->tx_stats.restart_queue;
+       return 0;
+}
+
+/**
+ * i40e_maybe_stop_tx - 1st level check for tx stop conditions
+ * @tx_ring: the ring to be checked
+ * @size:    the size buffer we want to assure is available
+ *
+ * Returns 0 if stop is not needed
+ **/
+static int i40e_maybe_stop_tx(struct i40e_ring *tx_ring, int size)
+{
+       if (likely(I40E_DESC_UNUSED(tx_ring) >= size))
+               return 0;
+       return __i40e_maybe_stop_tx(tx_ring, size);
+}
+
+/**
+ * i40e_xmit_descriptor_count - calculate number of tx descriptors needed
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ *
+ * Returns number of data descriptors needed for this skb. Returns 0 to indicate
+ * there is not enough descriptors available in this ring since we need at least
+ * one descriptor.
+ **/
+static int i40e_xmit_descriptor_count(struct sk_buff *skb,
+                                     struct i40e_ring *tx_ring)
+{
+#if PAGE_SIZE > I40E_MAX_DATA_PER_TXD
+       unsigned int f;
+#endif
+       int count = 0;
+
+       /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD,
+        *       + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD,
+        *       + 2 desc gap to keep tail from touching head,
+        *       + 1 desc for context descriptor,
+        * otherwise try next time
+        */
+#if PAGE_SIZE > I40E_MAX_DATA_PER_TXD
+       for (f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+               count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size);
+#else
+       count += skb_shinfo(skb)->nr_frags;
+#endif
+       count += TXD_USE_COUNT(skb_headlen(skb));
+       if (i40e_maybe_stop_tx(tx_ring, count + 3)) {
+               tx_ring->tx_stats.tx_busy++;
+               return 0;
+       }
+       return count;
+}
+
+/**
+ * i40e_xmit_frame_ring - Sends buffer on Tx ring
+ * @skb:     send buffer
+ * @tx_ring: ring to send buffer on
+ *
+ * Returns NETDEV_TX_OK if sent, else an error code
+ **/
+static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb,
+                                       struct i40e_ring *tx_ring)
+{
+       u64 cd_type_cmd_tso_mss = I40E_TX_DESC_DTYPE_CONTEXT;
+       u32 cd_tunneling = 0, cd_l2tag2 = 0;
+       struct i40e_tx_buffer *first;
+       u32 td_offset = 0;
+       u32 tx_flags = 0;
+       __be16 protocol;
+       u32 td_cmd = 0;
+       u8 hdr_len = 0;
+       int tso;
+       if (0 == i40e_xmit_descriptor_count(skb, tx_ring))
+               return NETDEV_TX_BUSY;
+
+       /* prepare the xmit flags */
+       if (i40e_tx_prepare_vlan_flags(skb, tx_ring, &tx_flags))
+               goto out_drop;
+
+       /* obtain protocol of skb */
+       protocol = skb->protocol;
+
+       /* record the location of the first descriptor for this packet */
+       first = &tx_ring->tx_bi[tx_ring->next_to_use];
+
+       /* setup IPv4/IPv6 offloads */
+       if (protocol == __constant_htons(ETH_P_IP))
+               tx_flags |= I40E_TX_FLAGS_IPV4;
+       else if (protocol == __constant_htons(ETH_P_IPV6))
+               tx_flags |= I40E_TX_FLAGS_IPV6;
+
+       tso = i40e_tso(tx_ring, skb, tx_flags, protocol, &hdr_len,
+                      &cd_type_cmd_tso_mss, &cd_tunneling);
+
+       if (tso < 0)
+               goto out_drop;
+       else if (tso)
+               tx_flags |= I40E_TX_FLAGS_TSO;
+
+       skb_tx_timestamp(skb);
+
+       /* Always offload the checksum, since it's in the data descriptor */
+       if (i40e_tx_csum(tx_ring, skb, tx_flags, protocol))
+               tx_flags |= I40E_TX_FLAGS_CSUM;
+
+       /* always enable offload insertion */
+       td_cmd |= I40E_TX_DESC_CMD_ICRC;
+
+       if (tx_flags & I40E_TX_FLAGS_CSUM)
+               i40e_tx_enable_csum(skb, tx_flags, &td_cmd, &td_offset,
+                                   tx_ring, &cd_tunneling);
+
+       i40e_create_tx_ctx(tx_ring, cd_type_cmd_tso_mss,
+                          cd_tunneling, cd_l2tag2);
+
+       /* Add Flow Director ATR if it's enabled.
+        *
+        * NOTE: this must always be directly before the data descriptor.
+        */
+       i40e_atr(tx_ring, skb, tx_flags, protocol);
+
+       i40e_tx_map(tx_ring, skb, first, tx_flags, hdr_len,
+                   td_cmd, td_offset);
+
+       i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+       return NETDEV_TX_OK;
+
+out_drop:
+       dev_kfree_skb_any(skb);
+       return NETDEV_TX_OK;
+}
+
+/**
+ * i40e_lan_xmit_frame - Selects the correct VSI and Tx queue to send buffer
+ * @skb:    send buffer
+ * @netdev: network interface device structure
+ *
+ * Returns NETDEV_TX_OK if sent, else an error code
+ **/
+netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_ring *tx_ring = &vsi->tx_rings[skb->queue_mapping];
+
+       /* hardware can't handle really short frames, hardware padding works
+        * beyond this point
+        */
+       if (unlikely(skb->len < I40E_MIN_TX_LEN)) {
+               if (skb_pad(skb, I40E_MIN_TX_LEN - skb->len))
+                       return NETDEV_TX_OK;
+               skb->len = I40E_MIN_TX_LEN;
+               skb_set_tail_pointer(skb, I40E_MIN_TX_LEN);
+       }
+
+       return i40e_xmit_frame_ring(skb, tx_ring);
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h
new file mode 100644 (file)
index 0000000..b1d7722
--- /dev/null
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+/* Interrupt Throttling and Rate Limiting (storm control) Goodies */
+
+#define I40E_MAX_ITR               0x07FF
+#define I40E_MIN_ITR               0x0001
+#define I40E_ITR_USEC_RESOLUTION   2
+#define I40E_MAX_IRATE             0x03F
+#define I40E_MIN_IRATE             0x001
+#define I40E_IRATE_USEC_RESOLUTION 4
+#define I40E_ITR_100K              0x0005
+#define I40E_ITR_20K               0x0019
+#define I40E_ITR_8K                0x003E
+#define I40E_ITR_4K                0x007A
+#define I40E_ITR_RX_DEF            I40E_ITR_8K
+#define I40E_ITR_TX_DEF            I40E_ITR_4K
+#define I40E_ITR_DYNAMIC           0x8000  /* use top bit as a flag */
+#define I40E_MIN_INT_RATE          250     /* ~= 1000000 / (I40E_MAX_ITR * 2) */
+#define I40E_MAX_INT_RATE          500000  /* == 1000000 / (I40E_MIN_ITR * 2) */
+#define I40E_DEFAULT_IRQ_WORK      256
+#define ITR_TO_REG(setting) ((setting & ~I40E_ITR_DYNAMIC) >> 1)
+#define ITR_IS_DYNAMIC(setting) (!!(setting & I40E_ITR_DYNAMIC))
+#define ITR_REG_TO_USEC(itr_reg) (itr_reg << 1)
+
+#define I40E_QUEUE_END_OF_LIST 0x7FF
+
+#define I40E_ITR_NONE  3
+#define I40E_RX_ITR    0
+#define I40E_TX_ITR    1
+#define I40E_PE_ITR    2
+/* Supported Rx Buffer Sizes */
+#define I40E_RXBUFFER_512   512    /* Used for packet split */
+#define I40E_RXBUFFER_2048  2048
+#define I40E_RXBUFFER_3072  3072   /* For FCoE MTU of 2158 */
+#define I40E_RXBUFFER_4096  4096
+#define I40E_RXBUFFER_8192  8192
+#define I40E_MAX_RXBUFFER   9728  /* largest size for single descriptor */
+
+/* NOTE: netdev_alloc_skb reserves up to 64 bytes, NET_IP_ALIGN means we
+ * reserve 2 more, and skb_shared_info adds an additional 384 bytes more,
+ * this adds up to 512 bytes of extra data meaning the smallest allocation
+ * we could have is 1K.
+ * i.e. RXBUFFER_512 --> size-1024 slab
+ */
+#define I40E_RX_HDR_SIZE  I40E_RXBUFFER_512
+
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define I40E_RX_BUFFER_WRITE   16      /* Must be power of 2 */
+#define I40E_RX_NEXT_DESC(r, i, n)             \
+       do {                                    \
+               (i)++;                          \
+               if ((i) == (r)->count)          \
+                       i = 0;                  \
+               (n) = I40E_RX_DESC((r), (i));   \
+       } while (0)
+
+#define I40E_RX_NEXT_DESC_PREFETCH(r, i, n)            \
+       do {                                            \
+               I40E_RX_NEXT_DESC((r), (i), (n));       \
+               prefetch((n));                          \
+       } while (0)
+
+#define i40e_rx_desc i40e_32byte_rx_desc
+
+#define I40E_MIN_TX_LEN                17
+#define I40E_MAX_DATA_PER_TXD  16383   /* aka 16kB - 1 */
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), I40E_MAX_DATA_PER_TXD)
+#define DESC_NEEDED ((MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE)) + 4)
+
+#define I40E_TX_FLAGS_CSUM             (u32)(1)
+#define I40E_TX_FLAGS_HW_VLAN          (u32)(1 << 1)
+#define I40E_TX_FLAGS_SW_VLAN          (u32)(1 << 2)
+#define I40E_TX_FLAGS_TSO              (u32)(1 << 3)
+#define I40E_TX_FLAGS_IPV4             (u32)(1 << 4)
+#define I40E_TX_FLAGS_IPV6             (u32)(1 << 5)
+#define I40E_TX_FLAGS_FCCRC            (u32)(1 << 6)
+#define I40E_TX_FLAGS_FSO              (u32)(1 << 7)
+#define I40E_TX_FLAGS_TXSW             (u32)(1 << 8)
+#define I40E_TX_FLAGS_MAPPED_AS_PAGE   (u32)(1 << 9)
+#define I40E_TX_FLAGS_VLAN_MASK                0xffff0000
+#define I40E_TX_FLAGS_VLAN_PRIO_MASK   0xe0000000
+#define I40E_TX_FLAGS_VLAN_PRIO_SHIFT  29
+#define I40E_TX_FLAGS_VLAN_SHIFT       16
+
+struct i40e_tx_buffer {
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       unsigned long time_stamp;
+       u16 length;
+       u32 tx_flags;
+       struct i40e_tx_desc *next_to_watch;
+       unsigned int bytecount;
+       u16 gso_segs;
+       u8 mapped_as_page;
+};
+
+struct i40e_rx_buffer {
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       struct page *page;
+       dma_addr_t page_dma;
+       unsigned int page_offset;
+};
+
+struct i40e_tx_queue_stats {
+       u64 packets;
+       u64 bytes;
+       u64 restart_queue;
+       u64 tx_busy;
+       u64 completed;
+       u64 tx_done_old;
+};
+
+struct i40e_rx_queue_stats {
+       u64 packets;
+       u64 bytes;
+       u64 non_eop_descs;
+       u64 alloc_rx_page_failed;
+       u64 alloc_rx_buff_failed;
+};
+
+enum i40e_ring_state_t {
+       __I40E_TX_FDIR_INIT_DONE,
+       __I40E_TX_XPS_INIT_DONE,
+       __I40E_TX_DETECT_HANG,
+       __I40E_HANG_CHECK_ARMED,
+       __I40E_RX_PS_ENABLED,
+       __I40E_RX_LRO_ENABLED,
+       __I40E_RX_16BYTE_DESC_ENABLED,
+};
+
+#define ring_is_ps_enabled(ring) \
+       test_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
+#define set_ring_ps_enabled(ring) \
+       set_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
+#define clear_ring_ps_enabled(ring) \
+       clear_bit(__I40E_RX_PS_ENABLED, &(ring)->state)
+#define check_for_tx_hang(ring) \
+       test_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
+#define set_check_for_tx_hang(ring) \
+       set_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
+#define clear_check_for_tx_hang(ring) \
+       clear_bit(__I40E_TX_DETECT_HANG, &(ring)->state)
+#define ring_is_lro_enabled(ring) \
+       test_bit(__I40E_RX_LRO_ENABLED, &(ring)->state)
+#define set_ring_lro_enabled(ring) \
+       set_bit(__I40E_RX_LRO_ENABLED, &(ring)->state)
+#define clear_ring_lro_enabled(ring) \
+       clear_bit(__I40E_RX_LRO_ENABLED, &(ring)->state)
+#define ring_is_16byte_desc_enabled(ring) \
+       test_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state)
+#define set_ring_16byte_desc_enabled(ring) \
+       set_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state)
+#define clear_ring_16byte_desc_enabled(ring) \
+       clear_bit(__I40E_RX_16BYTE_DESC_ENABLED, &(ring)->state)
+
+/* struct that defines a descriptor ring, associated with a VSI */
+struct i40e_ring {
+       void *desc;                     /* Descriptor ring memory */
+       struct device *dev;             /* Used for DMA mapping */
+       struct net_device *netdev;      /* netdev ring maps to */
+       union {
+               struct i40e_tx_buffer *tx_bi;
+               struct i40e_rx_buffer *rx_bi;
+       };
+       unsigned long state;
+       u16 queue_index;                /* Queue number of ring */
+       u8 dcb_tc;                      /* Traffic class of ring */
+       u8 __iomem *tail;
+
+       u16 count;                      /* Number of descriptors */
+       u16 reg_idx;                    /* HW register index of the ring */
+       u16 rx_hdr_len;
+       u16 rx_buf_len;
+       u8  dtype;
+#define I40E_RX_DTYPE_NO_SPLIT      0
+#define I40E_RX_DTYPE_SPLIT_ALWAYS  1
+#define I40E_RX_DTYPE_HEADER_SPLIT  2
+       u8  hsplit;
+#define I40E_RX_SPLIT_L2      0x1
+#define I40E_RX_SPLIT_IP      0x2
+#define I40E_RX_SPLIT_TCP_UDP 0x4
+#define I40E_RX_SPLIT_SCTP    0x8
+
+       /* used in interrupt processing */
+       u16 next_to_use;
+       u16 next_to_clean;
+
+       u8 atr_sample_rate;
+       u8 atr_count;
+
+       bool ring_active;               /* is ring online or not */
+
+       /* stats structs */
+       union {
+               struct i40e_tx_queue_stats tx_stats;
+               struct i40e_rx_queue_stats rx_stats;
+       };
+
+       unsigned int size;              /* length of descriptor ring in bytes */
+       dma_addr_t dma;                 /* physical address of ring */
+
+       struct i40e_vsi *vsi;           /* Backreference to associated VSI */
+       struct i40e_q_vector *q_vector; /* Backreference to associated vector */
+} ____cacheline_internodealigned_in_smp;
+
+enum i40e_latency_range {
+       I40E_LOWEST_LATENCY = 0,
+       I40E_LOW_LATENCY = 1,
+       I40E_BULK_LATENCY = 2,
+};
+
+struct i40e_ring_container {
+#define I40E_MAX_RINGPAIR_PER_VECTOR 8
+       /* array of pointers to rings */
+       struct i40e_ring *ring[I40E_MAX_RINGPAIR_PER_VECTOR];
+       unsigned int total_bytes;       /* total bytes processed this int */
+       unsigned int total_packets;     /* total packets processed this int */
+       u16 count;
+       enum i40e_latency_range latency_range;
+       u16 itr;
+};
+
+void i40e_alloc_rx_buffers(struct i40e_ring *rxr, u16 cleaned_count);
+netdev_tx_t i40e_lan_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+void i40e_clean_tx_ring(struct i40e_ring *tx_ring);
+void i40e_clean_rx_ring(struct i40e_ring *rx_ring);
+int i40e_setup_tx_descriptors(struct i40e_ring *tx_ring);
+int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring);
+void i40e_free_tx_resources(struct i40e_ring *tx_ring);
+void i40e_free_rx_resources(struct i40e_ring *rx_ring);
+int i40e_napi_poll(struct napi_struct *napi, int budget);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
new file mode 100644 (file)
index 0000000..f3f22b2
--- /dev/null
@@ -0,0 +1,1154 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_TYPE_H_
+#define _I40E_TYPE_H_
+
+#include "i40e_status.h"
+#include "i40e_osdep.h"
+#include "i40e_register.h"
+#include "i40e_adminq.h"
+#include "i40e_hmc.h"
+#include "i40e_lan_hmc.h"
+
+/* Device IDs */
+#define I40E_SFP_XL710_DEVICE_ID       0x1572
+#define I40E_SFP_X710_DEVICE_ID                0x1573
+#define I40E_QEMU_DEVICE_ID            0x1574
+#define I40E_KX_A_DEVICE_ID            0x157F
+#define I40E_KX_B_DEVICE_ID            0x1580
+#define I40E_KX_C_DEVICE_ID            0x1581
+#define I40E_KX_D_DEVICE_ID            0x1582
+#define I40E_QSFP_A_DEVICE_ID          0x1583
+#define I40E_QSFP_B_DEVICE_ID          0x1584
+#define I40E_QSFP_C_DEVICE_ID          0x1585
+#define I40E_VF_DEVICE_ID              0x154C
+#define I40E_VF_HV_DEVICE_ID           0x1571
+
+#define I40E_FW_API_VERSION_MAJOR  0x0001
+#define I40E_FW_API_VERSION_MINOR  0x0000
+
+#define I40E_MAX_VSI_QP                        16
+#define I40E_MAX_VF_VSI                        3
+#define I40E_MAX_CHAINED_RX_BUFFERS    5
+
+/* Max default timeout in ms, */
+#define I40E_MAX_NVM_TIMEOUT           18000
+
+/* Check whether address is multicast.  This is little-endian specific check.*/
+#define I40E_IS_MULTICAST(address)     \
+       (bool)(((u8 *)(address))[0] & ((u8)0x01))
+
+/* Check whether an address is broadcast. */
+#define I40E_IS_BROADCAST(address)     \
+       ((((u8 *)(address))[0] == ((u8)0xff)) && \
+       (((u8 *)(address))[1] == ((u8)0xff)))
+
+/* Switch from mc to the 2usec global time (this is the GTIME resolution) */
+#define I40E_MS_TO_GTIME(time)         (((time) * 1000) / 2)
+
+/* forward declaration */
+struct i40e_hw;
+typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *);
+
+#define I40E_ETH_LENGTH_OF_ADDRESS     6
+
+/* Data type manipulation macros. */
+
+#define I40E_DESC_UNUSED(R)    \
+       ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
+       (R)->next_to_clean - (R)->next_to_use - 1)
+
+/* bitfields for Tx queue mapping in QTX_CTL */
+#define I40E_QTX_CTL_VF_QUEUE  0x0
+#define I40E_QTX_CTL_PF_QUEUE  0x2
+
+/* debug masks */
+enum i40e_debug_mask {
+       I40E_DEBUG_INIT                 = 0x00000001,
+       I40E_DEBUG_RELEASE              = 0x00000002,
+
+       I40E_DEBUG_LINK                 = 0x00000010,
+       I40E_DEBUG_PHY                  = 0x00000020,
+       I40E_DEBUG_HMC                  = 0x00000040,
+       I40E_DEBUG_NVM                  = 0x00000080,
+       I40E_DEBUG_LAN                  = 0x00000100,
+       I40E_DEBUG_FLOW                 = 0x00000200,
+       I40E_DEBUG_DCB                  = 0x00000400,
+       I40E_DEBUG_DIAG                 = 0x00000800,
+
+       I40E_DEBUG_AQ_MESSAGE           = 0x01000000, /* for i40e_debug() */
+       I40E_DEBUG_AQ_DESCRIPTOR        = 0x02000000,
+       I40E_DEBUG_AQ_DESC_BUFFER       = 0x04000000,
+       I40E_DEBUG_AQ_COMMAND           = 0x06000000, /* for i40e_debug_aq() */
+       I40E_DEBUG_AQ                   = 0x0F000000,
+
+       I40E_DEBUG_USER                 = 0xF0000000,
+
+       I40E_DEBUG_ALL                  = 0xFFFFFFFF
+};
+
+/* These are structs for managing the hardware information and the operations.
+ * The structures of function pointers are filled out at init time when we
+ * know for sure exactly which hardware we're working with.  This gives us the
+ * flexibility of using the same main driver code but adapting to slightly
+ * different hardware needs as new parts are developed.  For this architecture,
+ * the Firmware and AdminQ are intended to insulate the driver from most of the
+ * future changes, but these structures will also do part of the job.
+ */
+enum i40e_mac_type {
+       I40E_MAC_UNKNOWN = 0,
+       I40E_MAC_X710,
+       I40E_MAC_XL710,
+       I40E_MAC_VF,
+       I40E_MAC_GENERIC,
+};
+
+enum i40e_media_type {
+       I40E_MEDIA_TYPE_UNKNOWN = 0,
+       I40E_MEDIA_TYPE_FIBER,
+       I40E_MEDIA_TYPE_BASET,
+       I40E_MEDIA_TYPE_BACKPLANE,
+       I40E_MEDIA_TYPE_CX4,
+       I40E_MEDIA_TYPE_VIRTUAL
+};
+
+enum i40e_fc_mode {
+       I40E_FC_NONE = 0,
+       I40E_FC_RX_PAUSE,
+       I40E_FC_TX_PAUSE,
+       I40E_FC_FULL,
+       I40E_FC_PFC,
+       I40E_FC_DEFAULT
+};
+
+enum i40e_vsi_type {
+       I40E_VSI_MAIN = 0,
+       I40E_VSI_VMDQ1,
+       I40E_VSI_VMDQ2,
+       I40E_VSI_CTRL,
+       I40E_VSI_FCOE,
+       I40E_VSI_MIRROR,
+       I40E_VSI_SRIOV,
+       I40E_VSI_FDIR,
+       I40E_VSI_TYPE_UNKNOWN
+};
+
+enum i40e_queue_type {
+       I40E_QUEUE_TYPE_RX = 0,
+       I40E_QUEUE_TYPE_TX,
+       I40E_QUEUE_TYPE_PE_CEQ,
+       I40E_QUEUE_TYPE_UNKNOWN
+};
+
+struct i40e_link_status {
+       enum i40e_aq_phy_type phy_type;
+       enum i40e_aq_link_speed link_speed;
+       u8 link_info;
+       u8 an_info;
+       u8 ext_info;
+       /* is Link Status Event notification to SW enabled */
+       bool lse_enable;
+};
+
+struct i40e_phy_info {
+       struct i40e_link_status link_info;
+       struct i40e_link_status link_info_old;
+       u32 autoneg_advertised;
+       u32 phy_id;
+       u32 module_type;
+       bool get_link_info;
+       enum i40e_media_type media_type;
+};
+
+#define I40E_HW_CAP_MAX_GPIO                   30
+/* Capabilities of a PF or a VF or the whole device */
+struct i40e_hw_capabilities {
+       u32  switch_mode;
+#define I40E_NVM_IMAGE_TYPE_EVB                0x0
+#define I40E_NVM_IMAGE_TYPE_CLOUD      0x2
+#define I40E_NVM_IMAGE_TYPE_UDP_CLOUD  0x3
+
+       u32  management_mode;
+       u32  npar_enable;
+       u32  os2bmc;
+       u32  valid_functions;
+       bool sr_iov_1_1;
+       bool vmdq;
+       bool evb_802_1_qbg; /* Edge Virtual Bridging */
+       bool evb_802_1_qbh; /* Bridge Port Extension */
+       bool dcb;
+       bool fcoe;
+       bool mfp_mode_1;
+       bool mgmt_cem;
+       bool ieee_1588;
+       bool iwarp;
+       bool fd;
+       u32 fd_filters_guaranteed;
+       u32 fd_filters_best_effort;
+       bool rss;
+       u32 rss_table_size;
+       u32 rss_table_entry_width;
+       bool led[I40E_HW_CAP_MAX_GPIO];
+       bool sdp[I40E_HW_CAP_MAX_GPIO];
+       u32 nvm_image_type;
+       u32 num_flow_director_filters;
+       u32 num_vfs;
+       u32 vf_base_id;
+       u32 num_vsis;
+       u32 num_rx_qp;
+       u32 num_tx_qp;
+       u32 base_queue;
+       u32 num_msix_vectors;
+       u32 num_msix_vectors_vf;
+       u32 led_pin_num;
+       u32 sdp_pin_num;
+       u32 mdio_port_num;
+       u32 mdio_port_mode;
+       u8 rx_buf_chain_len;
+       u32 enabled_tcmap;
+       u32 maxtc;
+};
+
+struct i40e_mac_info {
+       enum i40e_mac_type type;
+       u8 addr[I40E_ETH_LENGTH_OF_ADDRESS];
+       u8 perm_addr[I40E_ETH_LENGTH_OF_ADDRESS];
+       u8 san_addr[I40E_ETH_LENGTH_OF_ADDRESS];
+       u16 max_fcoeq;
+};
+
+enum i40e_aq_resources_ids {
+       I40E_NVM_RESOURCE_ID = 1
+};
+
+enum i40e_aq_resource_access_type {
+       I40E_RESOURCE_READ = 1,
+       I40E_RESOURCE_WRITE
+};
+
+struct i40e_nvm_info {
+       u64 hw_semaphore_timeout; /* 2usec global time (GTIME resolution) */
+       u64 hw_semaphore_wait;    /* - || - */
+       u32 timeout;              /* [ms] */
+       u16 sr_size;              /* Shadow RAM size in words */
+       bool blank_nvm_mode;      /* is NVM empty (no FW present)*/
+       u16 version;              /* NVM package version */
+       u32 eetrack;              /* NVM data version */
+};
+
+/* PCI bus types */
+enum i40e_bus_type {
+       i40e_bus_type_unknown = 0,
+       i40e_bus_type_pci,
+       i40e_bus_type_pcix,
+       i40e_bus_type_pci_express,
+       i40e_bus_type_reserved
+};
+
+/* PCI bus speeds */
+enum i40e_bus_speed {
+       i40e_bus_speed_unknown  = 0,
+       i40e_bus_speed_33       = 33,
+       i40e_bus_speed_66       = 66,
+       i40e_bus_speed_100      = 100,
+       i40e_bus_speed_120      = 120,
+       i40e_bus_speed_133      = 133,
+       i40e_bus_speed_2500     = 2500,
+       i40e_bus_speed_5000     = 5000,
+       i40e_bus_speed_8000     = 8000,
+       i40e_bus_speed_reserved
+};
+
+/* PCI bus widths */
+enum i40e_bus_width {
+       i40e_bus_width_unknown  = 0,
+       i40e_bus_width_pcie_x1  = 1,
+       i40e_bus_width_pcie_x2  = 2,
+       i40e_bus_width_pcie_x4  = 4,
+       i40e_bus_width_pcie_x8  = 8,
+       i40e_bus_width_32       = 32,
+       i40e_bus_width_64       = 64,
+       i40e_bus_width_reserved
+};
+
+/* Bus parameters */
+struct i40e_bus_info {
+       enum i40e_bus_speed speed;
+       enum i40e_bus_width width;
+       enum i40e_bus_type type;
+
+       u16 func;
+       u16 device;
+       u16 lan_id;
+};
+
+/* Flow control (FC) parameters */
+struct i40e_fc_info {
+       enum i40e_fc_mode current_mode; /* FC mode in effect */
+       enum i40e_fc_mode requested_mode; /* FC mode requested by caller */
+};
+
+#define I40E_MAX_TRAFFIC_CLASS         8
+#define I40E_MAX_USER_PRIORITY         8
+#define I40E_DCBX_MAX_APPS             32
+#define I40E_LLDPDU_SIZE               1500
+
+/* IEEE 802.1Qaz ETS Configuration data */
+struct i40e_ieee_ets_config {
+       u8 willing;
+       u8 cbs;
+       u8 maxtcs;
+       u8 prioritytable[I40E_MAX_TRAFFIC_CLASS];
+       u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS];
+       u8 tsatable[I40E_MAX_TRAFFIC_CLASS];
+};
+
+/* IEEE 802.1Qaz ETS Recommendation data */
+struct i40e_ieee_ets_recommend {
+       u8 prioritytable[I40E_MAX_TRAFFIC_CLASS];
+       u8 tcbwtable[I40E_MAX_TRAFFIC_CLASS];
+       u8 tsatable[I40E_MAX_TRAFFIC_CLASS];
+};
+
+/* IEEE 802.1Qaz PFC Configuration data */
+struct i40e_ieee_pfc_config {
+       u8 willing;
+       u8 mbc;
+       u8 pfccap;
+       u8 pfcenable;
+};
+
+/* IEEE 802.1Qaz Application Priority data */
+struct i40e_ieee_app_priority_table {
+       u8  priority;
+       u8  selector;
+       u16 protocolid;
+};
+
+struct i40e_dcbx_config {
+       u32 numapps;
+       struct i40e_ieee_ets_config etscfg;
+       struct i40e_ieee_ets_recommend etsrec;
+       struct i40e_ieee_pfc_config pfc;
+       struct i40e_ieee_app_priority_table app[I40E_DCBX_MAX_APPS];
+};
+
+/* Port hardware description */
+struct i40e_hw {
+       u8 __iomem *hw_addr;
+       void *back;
+
+       /* function pointer structs */
+       struct i40e_phy_info phy;
+       struct i40e_mac_info mac;
+       struct i40e_bus_info bus;
+       struct i40e_nvm_info nvm;
+       struct i40e_fc_info fc;
+
+       /* pci info */
+       u16 device_id;
+       u16 vendor_id;
+       u16 subsystem_device_id;
+       u16 subsystem_vendor_id;
+       u8 revision_id;
+       u8 port;
+       bool adapter_stopped;
+
+       /* capabilities for entire device and PCI func */
+       struct i40e_hw_capabilities dev_caps;
+       struct i40e_hw_capabilities func_caps;
+
+       /* Flow Director shared filter space */
+       u16 fdir_shared_filter_count;
+
+       /* device profile info */
+       u8  pf_id;
+       u16 main_vsi_seid;
+
+       /* Closest numa node to the device */
+       u16 numa_node;
+
+       /* Admin Queue info */
+       struct i40e_adminq_info aq;
+
+       /* HMC info */
+       struct i40e_hmc_info hmc; /* HMC info struct */
+
+       /* LLDP/DCBX Status */
+       u16 dcbx_status;
+
+       /* DCBX info */
+       struct i40e_dcbx_config local_dcbx_config;
+       struct i40e_dcbx_config remote_dcbx_config;
+
+       /* debug mask */
+       u32 debug_mask;
+};
+
+struct i40e_driver_version {
+       u8 major_version;
+       u8 minor_version;
+       u8 build_version;
+       u8 subbuild_version;
+};
+
+/* RX Descriptors */
+union i40e_16byte_rx_desc {
+       struct {
+               __le64 pkt_addr; /* Packet buffer address */
+               __le64 hdr_addr; /* Header buffer address */
+       } read;
+       struct {
+               struct {
+                       struct {
+                               union {
+                                       __le16 mirroring_status;
+                                       __le16 fcoe_ctx_id;
+                               } mirr_fcoe;
+                               __le16 l2tag1;
+                       } lo_dword;
+                       union {
+                               __le32 rss; /* RSS Hash */
+                               __le32 fd_id; /* Flow director filter id */
+                               __le32 fcoe_param; /* FCoE DDP Context id */
+                       } hi_dword;
+               } qword0;
+               struct {
+                       /* ext status/error/pktype/length */
+                       __le64 status_error_len;
+               } qword1;
+       } wb;  /* writeback */
+};
+
+union i40e_32byte_rx_desc {
+       struct {
+               __le64  pkt_addr; /* Packet buffer address */
+               __le64  hdr_addr; /* Header buffer address */
+                       /* bit 0 of hdr_buffer_addr is DD bit */
+               __le64  rsvd1;
+               __le64  rsvd2;
+       } read;
+       struct {
+               struct {
+                       struct {
+                               union {
+                                       __le16 mirroring_status;
+                                       __le16 fcoe_ctx_id;
+                               } mirr_fcoe;
+                               __le16 l2tag1;
+                       } lo_dword;
+                       union {
+                               __le32 rss; /* RSS Hash */
+                               __le32 fcoe_param; /* FCoE DDP Context id */
+                       } hi_dword;
+               } qword0;
+               struct {
+                       /* status/error/pktype/length */
+                       __le64 status_error_len;
+               } qword1;
+               struct {
+                       __le16 ext_status; /* extended status */
+                       __le16 rsvd;
+                       __le16 l2tag2_1;
+                       __le16 l2tag2_2;
+               } qword2;
+               struct {
+                       union {
+                               __le32 flex_bytes_lo;
+                               __le32 pe_status;
+                       } lo_dword;
+                       union {
+                               __le32 flex_bytes_hi;
+                               __le32 fd_id;
+                       } hi_dword;
+               } qword3;
+       } wb;  /* writeback */
+};
+
+#define I40E_RXD_QW1_STATUS_SHIFT      0
+#define I40E_RXD_QW1_STATUS_MASK       (0x7FFFUL << I40E_RXD_QW1_STATUS_SHIFT)
+
+enum i40e_rx_desc_status_bits {
+       /* Note: These are predefined bit offsets */
+       I40E_RX_DESC_STATUS_DD_SHIFT            = 0,
+       I40E_RX_DESC_STATUS_EOF_SHIFT           = 1,
+       I40E_RX_DESC_STATUS_L2TAG1P_SHIFT       = 2,
+       I40E_RX_DESC_STATUS_L3L4P_SHIFT         = 3,
+       I40E_RX_DESC_STATUS_CRCP_SHIFT          = 4,
+       I40E_RX_DESC_STATUS_TSYNINDX_SHIFT      = 5, /* 3 BITS */
+       I40E_RX_DESC_STATUS_PIF_SHIFT           = 8,
+       I40E_RX_DESC_STATUS_UMBCAST_SHIFT       = 9, /* 2 BITS */
+       I40E_RX_DESC_STATUS_FLM_SHIFT           = 11,
+       I40E_RX_DESC_STATUS_FLTSTAT_SHIFT       = 12, /* 2 BITS */
+       I40E_RX_DESC_STATUS_LPBK_SHIFT          = 14
+};
+
+#define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT   I40E_RX_DESC_STATUS_TSYNINDX_SHIFT
+#define I40E_RXD_QW1_STATUS_TSYNINDX_MASK      (0x7UL << \
+                                            I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT)
+
+enum i40e_rx_desc_fltstat_values {
+       I40E_RX_DESC_FLTSTAT_NO_DATA    = 0,
+       I40E_RX_DESC_FLTSTAT_RSV_FD_ID  = 1, /* 16byte desc? FD_ID : RSV */
+       I40E_RX_DESC_FLTSTAT_RSV        = 2,
+       I40E_RX_DESC_FLTSTAT_RSS_HASH   = 3,
+};
+
+#define I40E_RXD_QW1_ERROR_SHIFT       19
+#define I40E_RXD_QW1_ERROR_MASK                (0xFFUL << I40E_RXD_QW1_ERROR_SHIFT)
+
+enum i40e_rx_desc_error_bits {
+       /* Note: These are predefined bit offsets */
+       I40E_RX_DESC_ERROR_RXE_SHIFT            = 0,
+       I40E_RX_DESC_ERROR_RECIPE_SHIFT         = 1,
+       I40E_RX_DESC_ERROR_HBO_SHIFT            = 2,
+       I40E_RX_DESC_ERROR_L3L4E_SHIFT          = 3, /* 3 BITS */
+       I40E_RX_DESC_ERROR_IPE_SHIFT            = 3,
+       I40E_RX_DESC_ERROR_L4E_SHIFT            = 4,
+       I40E_RX_DESC_ERROR_EIPE_SHIFT           = 5,
+       I40E_RX_DESC_ERROR_OVERSIZE_SHIFT       = 6
+};
+
+enum i40e_rx_desc_error_l3l4e_fcoe_masks {
+       I40E_RX_DESC_ERROR_L3L4E_NONE           = 0,
+       I40E_RX_DESC_ERROR_L3L4E_PROT           = 1,
+       I40E_RX_DESC_ERROR_L3L4E_FC             = 2,
+       I40E_RX_DESC_ERROR_L3L4E_DMAC_ERR       = 3,
+       I40E_RX_DESC_ERROR_L3L4E_DMAC_WARN      = 4
+};
+
+#define I40E_RXD_QW1_PTYPE_SHIFT       30
+#define I40E_RXD_QW1_PTYPE_MASK                (0xFFULL << I40E_RXD_QW1_PTYPE_SHIFT)
+
+/* Packet type non-ip values */
+enum i40e_rx_l2_ptype {
+       I40E_RX_PTYPE_L2_RESERVED               = 0,
+       I40E_RX_PTYPE_L2_MAC_PAY2               = 1,
+       I40E_RX_PTYPE_L2_TIMESYNC_PAY2          = 2,
+       I40E_RX_PTYPE_L2_FIP_PAY2               = 3,
+       I40E_RX_PTYPE_L2_OUI_PAY2               = 4,
+       I40E_RX_PTYPE_L2_MACCNTRL_PAY2          = 5,
+       I40E_RX_PTYPE_L2_LLDP_PAY2              = 6,
+       I40E_RX_PTYPE_L2_ECP_PAY2               = 7,
+       I40E_RX_PTYPE_L2_EVB_PAY2               = 8,
+       I40E_RX_PTYPE_L2_QCN_PAY2               = 9,
+       I40E_RX_PTYPE_L2_EAPOL_PAY2             = 10,
+       I40E_RX_PTYPE_L2_ARP                    = 11,
+       I40E_RX_PTYPE_L2_FCOE_PAY3              = 12,
+       I40E_RX_PTYPE_L2_FCOE_FCDATA_PAY3       = 13,
+       I40E_RX_PTYPE_L2_FCOE_FCRDY_PAY3        = 14,
+       I40E_RX_PTYPE_L2_FCOE_FCRSP_PAY3        = 15,
+       I40E_RX_PTYPE_L2_FCOE_FCOTHER_PA        = 16,
+       I40E_RX_PTYPE_L2_FCOE_VFT_PAY3          = 17,
+       I40E_RX_PTYPE_L2_FCOE_VFT_FCDATA        = 18,
+       I40E_RX_PTYPE_L2_FCOE_VFT_FCRDY         = 19,
+       I40E_RX_PTYPE_L2_FCOE_VFT_FCRSP         = 20,
+       I40E_RX_PTYPE_L2_FCOE_VFT_FCOTHER       = 21
+};
+
+struct i40e_rx_ptype_decoded {
+       u32 ptype:8;
+       u32 known:1;
+       u32 outer_ip:1;
+       u32 outer_ip_ver:1;
+       u32 outer_frag:1;
+       u32 tunnel_type:3;
+       u32 tunnel_end_prot:2;
+       u32 tunnel_end_frag:1;
+       u32 inner_prot:4;
+       u32 payload_layer:3;
+};
+
+enum i40e_rx_ptype_outer_ip {
+       I40E_RX_PTYPE_OUTER_L2  = 0,
+       I40E_RX_PTYPE_OUTER_IP  = 1
+};
+
+enum i40e_rx_ptype_outer_ip_ver {
+       I40E_RX_PTYPE_OUTER_NONE        = 0,
+       I40E_RX_PTYPE_OUTER_IPV4        = 0,
+       I40E_RX_PTYPE_OUTER_IPV6        = 1
+};
+
+enum i40e_rx_ptype_outer_fragmented {
+       I40E_RX_PTYPE_NOT_FRAG  = 0,
+       I40E_RX_PTYPE_FRAG      = 1
+};
+
+enum i40e_rx_ptype_tunnel_type {
+       I40E_RX_PTYPE_TUNNEL_NONE               = 0,
+       I40E_RX_PTYPE_TUNNEL_IP_IP              = 1,
+       I40E_RX_PTYPE_TUNNEL_IP_GRENAT          = 2,
+       I40E_RX_PTYPE_TUNNEL_IP_GRENAT_MAC      = 3,
+       I40E_RX_PTYPE_TUNNEL_IP_GRENAT_MAC_VLAN = 4,
+};
+
+enum i40e_rx_ptype_tunnel_end_prot {
+       I40E_RX_PTYPE_TUNNEL_END_NONE   = 0,
+       I40E_RX_PTYPE_TUNNEL_END_IPV4   = 1,
+       I40E_RX_PTYPE_TUNNEL_END_IPV6   = 2,
+};
+
+enum i40e_rx_ptype_inner_prot {
+       I40E_RX_PTYPE_INNER_PROT_NONE           = 0,
+       I40E_RX_PTYPE_INNER_PROT_UDP            = 1,
+       I40E_RX_PTYPE_INNER_PROT_TCP            = 2,
+       I40E_RX_PTYPE_INNER_PROT_SCTP           = 3,
+       I40E_RX_PTYPE_INNER_PROT_ICMP           = 4,
+       I40E_RX_PTYPE_INNER_PROT_TIMESYNC       = 5
+};
+
+enum i40e_rx_ptype_payload_layer {
+       I40E_RX_PTYPE_PAYLOAD_LAYER_NONE        = 0,
+       I40E_RX_PTYPE_PAYLOAD_LAYER_PAY2        = 1,
+       I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3        = 2,
+       I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4        = 3,
+};
+
+#define I40E_RXD_QW1_LENGTH_PBUF_SHIFT 38
+#define I40E_RXD_QW1_LENGTH_PBUF_MASK  (0x3FFFULL << \
+                                        I40E_RXD_QW1_LENGTH_PBUF_SHIFT)
+
+#define I40E_RXD_QW1_LENGTH_HBUF_SHIFT 52
+#define I40E_RXD_QW1_LENGTH_HBUF_MASK  (0x7FFULL << \
+                                        I40E_RXD_QW1_LENGTH_HBUF_SHIFT)
+
+#define I40E_RXD_QW1_LENGTH_SPH_SHIFT  63
+#define I40E_RXD_QW1_LENGTH_SPH_MASK   (0x1ULL << \
+                                        I40E_RXD_QW1_LENGTH_SPH_SHIFT)
+
+enum i40e_rx_desc_ext_status_bits {
+       /* Note: These are predefined bit offsets */
+       I40E_RX_DESC_EXT_STATUS_L2TAG2P_SHIFT   = 0,
+       I40E_RX_DESC_EXT_STATUS_L2TAG3P_SHIFT   = 1,
+       I40E_RX_DESC_EXT_STATUS_FLEXBL_SHIFT    = 2, /* 2 BITS */
+       I40E_RX_DESC_EXT_STATUS_FLEXBH_SHIFT    = 4, /* 2 BITS */
+       I40E_RX_DESC_EXT_STATUS_FTYPE_SHIFT     = 6, /* 3 BITS */
+       I40E_RX_DESC_EXT_STATUS_FDLONGB_SHIFT   = 9,
+       I40E_RX_DESC_EXT_STATUS_FCOELONGB_SHIFT = 10,
+       I40E_RX_DESC_EXT_STATUS_PELONGB_SHIFT   = 11,
+};
+
+enum i40e_rx_desc_pe_status_bits {
+       /* Note: These are predefined bit offsets */
+       I40E_RX_DESC_PE_STATUS_QPID_SHIFT       = 0, /* 18 BITS */
+       I40E_RX_DESC_PE_STATUS_L4PORT_SHIFT     = 0, /* 16 BITS */
+       I40E_RX_DESC_PE_STATUS_IPINDEX_SHIFT    = 16, /* 8 BITS */
+       I40E_RX_DESC_PE_STATUS_QPIDHIT_SHIFT    = 24,
+       I40E_RX_DESC_PE_STATUS_APBVTHIT_SHIFT   = 25,
+       I40E_RX_DESC_PE_STATUS_PORTV_SHIFT      = 26,
+       I40E_RX_DESC_PE_STATUS_URG_SHIFT        = 27,
+       I40E_RX_DESC_PE_STATUS_IPFRAG_SHIFT     = 28,
+       I40E_RX_DESC_PE_STATUS_IPOPT_SHIFT      = 29
+};
+
+#define I40E_RX_PROG_STATUS_DESC_LENGTH_SHIFT          38
+#define I40E_RX_PROG_STATUS_DESC_LENGTH                        0x2000000
+
+#define I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT      2
+#define I40E_RX_PROG_STATUS_DESC_QW1_PROGID_MASK       (0x7UL << \
+                               I40E_RX_PROG_STATUS_DESC_QW1_PROGID_SHIFT)
+
+#define I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT       19
+#define I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK                (0x3FUL << \
+                               I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT)
+
+enum i40e_rx_prog_status_desc_status_bits {
+       /* Note: These are predefined bit offsets */
+       I40E_RX_PROG_STATUS_DESC_DD_SHIFT       = 0,
+       I40E_RX_PROG_STATUS_DESC_PROG_ID_SHIFT  = 2 /* 3 BITS */
+};
+
+enum i40e_rx_prog_status_desc_prog_id_masks {
+       I40E_RX_PROG_STATUS_DESC_FD_FILTER_STATUS       = 1,
+       I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_PROG_STATUS  = 2,
+       I40E_RX_PROG_STATUS_DESC_FCOE_CTXT_INVL_STATUS  = 4,
+};
+
+enum i40e_rx_prog_status_desc_error_bits {
+       /* Note: These are predefined bit offsets */
+       I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT      = 0,
+       I40E_RX_PROG_STATUS_DESC_NO_FD_QUOTA_SHIFT      = 1,
+       I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT    = 2,
+       I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT    = 3
+};
+
+/* TX Descriptor */
+struct i40e_tx_desc {
+       __le64 buffer_addr; /* Address of descriptor's data buf */
+       __le64 cmd_type_offset_bsz;
+};
+
+#define I40E_TXD_QW1_DTYPE_SHIFT       0
+#define I40E_TXD_QW1_DTYPE_MASK                (0xFUL << I40E_TXD_QW1_DTYPE_SHIFT)
+
+enum i40e_tx_desc_dtype_value {
+       I40E_TX_DESC_DTYPE_DATA         = 0x0,
+       I40E_TX_DESC_DTYPE_NOP          = 0x1, /* same as Context desc */
+       I40E_TX_DESC_DTYPE_CONTEXT      = 0x1,
+       I40E_TX_DESC_DTYPE_FCOE_CTX     = 0x2,
+       I40E_TX_DESC_DTYPE_FILTER_PROG  = 0x8,
+       I40E_TX_DESC_DTYPE_DDP_CTX      = 0x9,
+       I40E_TX_DESC_DTYPE_FLEX_DATA    = 0xB,
+       I40E_TX_DESC_DTYPE_FLEX_CTX_1   = 0xC,
+       I40E_TX_DESC_DTYPE_FLEX_CTX_2   = 0xD,
+       I40E_TX_DESC_DTYPE_DESC_DONE    = 0xF
+};
+
+#define I40E_TXD_QW1_CMD_SHIFT 4
+#define I40E_TXD_QW1_CMD_MASK  (0x3FFUL << I40E_TXD_QW1_CMD_SHIFT)
+
+enum i40e_tx_desc_cmd_bits {
+       I40E_TX_DESC_CMD_EOP                    = 0x0001,
+       I40E_TX_DESC_CMD_RS                     = 0x0002,
+       I40E_TX_DESC_CMD_ICRC                   = 0x0004,
+       I40E_TX_DESC_CMD_IL2TAG1                = 0x0008,
+       I40E_TX_DESC_CMD_DUMMY                  = 0x0010,
+       I40E_TX_DESC_CMD_IIPT_NONIP             = 0x0000, /* 2 BITS */
+       I40E_TX_DESC_CMD_IIPT_IPV6              = 0x0020, /* 2 BITS */
+       I40E_TX_DESC_CMD_IIPT_IPV4              = 0x0040, /* 2 BITS */
+       I40E_TX_DESC_CMD_IIPT_IPV4_CSUM         = 0x0060, /* 2 BITS */
+       I40E_TX_DESC_CMD_FCOET                  = 0x0080,
+       I40E_TX_DESC_CMD_L4T_EOFT_UNK           = 0x0000, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_TCP           = 0x0100, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_SCTP          = 0x0200, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_UDP           = 0x0300, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_EOF_N         = 0x0000, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_EOF_T         = 0x0100, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_EOF_NI        = 0x0200, /* 2 BITS */
+       I40E_TX_DESC_CMD_L4T_EOFT_EOF_A         = 0x0300, /* 2 BITS */
+};
+
+#define I40E_TXD_QW1_OFFSET_SHIFT      16
+#define I40E_TXD_QW1_OFFSET_MASK       (0x3FFFFULL << \
+                                        I40E_TXD_QW1_OFFSET_SHIFT)
+
+enum i40e_tx_desc_length_fields {
+       /* Note: These are predefined bit offsets */
+       I40E_TX_DESC_LENGTH_MACLEN_SHIFT        = 0, /* 7 BITS */
+       I40E_TX_DESC_LENGTH_IPLEN_SHIFT         = 7, /* 7 BITS */
+       I40E_TX_DESC_LENGTH_L4_FC_LEN_SHIFT     = 14 /* 4 BITS */
+};
+
+#define I40E_TXD_QW1_TX_BUF_SZ_SHIFT   34
+#define I40E_TXD_QW1_TX_BUF_SZ_MASK    (0x3FFFULL << \
+                                        I40E_TXD_QW1_TX_BUF_SZ_SHIFT)
+
+#define I40E_TXD_QW1_L2TAG1_SHIFT      48
+#define I40E_TXD_QW1_L2TAG1_MASK       (0xFFFFULL << I40E_TXD_QW1_L2TAG1_SHIFT)
+
+/* Context descriptors */
+struct i40e_tx_context_desc {
+       __le32 tunneling_params;
+       __le16 l2tag2;
+       __le16 rsvd;
+       __le64 type_cmd_tso_mss;
+};
+
+#define I40E_TXD_CTX_QW1_DTYPE_SHIFT   0
+#define I40E_TXD_CTX_QW1_DTYPE_MASK    (0xFUL << I40E_TXD_CTX_QW1_DTYPE_SHIFT)
+
+#define I40E_TXD_CTX_QW1_CMD_SHIFT     4
+#define I40E_TXD_CTX_QW1_CMD_MASK      (0xFFFFUL << I40E_TXD_CTX_QW1_CMD_SHIFT)
+
+enum i40e_tx_ctx_desc_cmd_bits {
+       I40E_TX_CTX_DESC_TSO            = 0x01,
+       I40E_TX_CTX_DESC_TSYN           = 0x02,
+       I40E_TX_CTX_DESC_IL2TAG2        = 0x04,
+       I40E_TX_CTX_DESC_IL2TAG2_IL2H   = 0x08,
+       I40E_TX_CTX_DESC_SWTCH_NOTAG    = 0x00,
+       I40E_TX_CTX_DESC_SWTCH_UPLINK   = 0x10,
+       I40E_TX_CTX_DESC_SWTCH_LOCAL    = 0x20,
+       I40E_TX_CTX_DESC_SWTCH_VSI      = 0x30,
+       I40E_TX_CTX_DESC_SWPE           = 0x40
+};
+
+#define I40E_TXD_CTX_QW1_TSO_LEN_SHIFT 30
+#define I40E_TXD_CTX_QW1_TSO_LEN_MASK  (0x3FFFFULL << \
+                                        I40E_TXD_CTX_QW1_TSO_LEN_SHIFT)
+
+#define I40E_TXD_CTX_QW1_MSS_SHIFT     50
+#define I40E_TXD_CTX_QW1_MSS_MASK      (0x3FFFULL << \
+                                        I40E_TXD_CTX_QW1_MSS_SHIFT)
+
+#define I40E_TXD_CTX_QW1_VSI_SHIFT     50
+#define I40E_TXD_CTX_QW1_VSI_MASK      (0x1FFULL << I40E_TXD_CTX_QW1_VSI_SHIFT)
+
+#define I40E_TXD_CTX_QW0_EXT_IP_SHIFT  0
+#define I40E_TXD_CTX_QW0_EXT_IP_MASK   (0x3ULL << \
+                                        I40E_TXD_CTX_QW0_EXT_IP_SHIFT)
+
+enum i40e_tx_ctx_desc_eipt_offload {
+       I40E_TX_CTX_EXT_IP_NONE         = 0x0,
+       I40E_TX_CTX_EXT_IP_IPV6         = 0x1,
+       I40E_TX_CTX_EXT_IP_IPV4_NO_CSUM = 0x2,
+       I40E_TX_CTX_EXT_IP_IPV4         = 0x3
+};
+
+#define I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT       2
+#define I40E_TXD_CTX_QW0_EXT_IPLEN_MASK        (0x3FULL << \
+                                        I40E_TXD_CTX_QW0_EXT_IPLEN_SHIFT)
+
+#define I40E_TXD_CTX_QW0_NATT_SHIFT    9
+#define I40E_TXD_CTX_QW0_NATT_MASK     (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT)
+
+#define I40E_TXD_CTX_UDP_TUNNELING     (0x1ULL << I40E_TXD_CTX_QW0_NATT_SHIFT)
+#define I40E_TXD_CTX_GRE_TUNNELING     (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT)
+
+#define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT       11
+#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK        (0x1ULL << \
+                                        I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT)
+
+#define I40E_TXD_CTX_EIP_NOINC_IPID_CONST      I40E_TXD_CTX_QW0_EIP_NOINC_MASK
+
+#define I40E_TXD_CTX_QW0_NATLEN_SHIFT  12
+#define I40E_TXD_CTX_QW0_NATLEN_MASK   (0X7FULL << \
+                                        I40E_TXD_CTX_QW0_NATLEN_SHIFT)
+
+#define I40E_TXD_CTX_QW0_DECTTL_SHIFT  19
+#define I40E_TXD_CTX_QW0_DECTTL_MASK   (0xFULL << \
+                                        I40E_TXD_CTX_QW0_DECTTL_SHIFT)
+
+struct i40e_filter_program_desc {
+       __le32 qindex_flex_ptype_vsi;
+       __le32 rsvd;
+       __le32 dtype_cmd_cntindex;
+       __le32 fd_id;
+};
+#define I40E_TXD_FLTR_QW0_QINDEX_SHIFT 0
+#define I40E_TXD_FLTR_QW0_QINDEX_MASK  (0x7FFUL << \
+                                        I40E_TXD_FLTR_QW0_QINDEX_SHIFT)
+#define I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT        11
+#define I40E_TXD_FLTR_QW0_FLEXOFF_MASK (0x7UL << \
+                                        I40E_TXD_FLTR_QW0_FLEXOFF_SHIFT)
+#define I40E_TXD_FLTR_QW0_PCTYPE_SHIFT 17
+#define I40E_TXD_FLTR_QW0_PCTYPE_MASK  (0x3FUL << \
+                                        I40E_TXD_FLTR_QW0_PCTYPE_SHIFT)
+
+/* Packet Classifier Types for filters */
+enum i40e_filter_pctype {
+       /* Note: Value 0-25 are reserved for future use */
+       I40E_FILTER_PCTYPE_IPV4_TEREDO_UDP              = 26,
+       I40E_FILTER_PCTYPE_IPV6_TEREDO_UDP              = 27,
+       I40E_FILTER_PCTYPE_NONF_IPV4_1588_UDP           = 28,
+       I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP        = 29,
+       I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP      = 30,
+       I40E_FILTER_PCTYPE_NONF_IPV4_UDP                = 31,
+       I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN            = 32,
+       I40E_FILTER_PCTYPE_NONF_IPV4_TCP                = 33,
+       I40E_FILTER_PCTYPE_NONF_IPV4_SCTP               = 34,
+       I40E_FILTER_PCTYPE_NONF_IPV4_OTHER              = 35,
+       I40E_FILTER_PCTYPE_FRAG_IPV4                    = 36,
+       /* Note: Value 37 is reserved for future use */
+       I40E_FILTER_PCTYPE_NONF_IPV6_1588_UDP           = 38,
+       I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP        = 39,
+       I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP      = 40,
+       I40E_FILTER_PCTYPE_NONF_IPV6_UDP                = 41,
+       I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN            = 42,
+       I40E_FILTER_PCTYPE_NONF_IPV6_TCP                = 43,
+       I40E_FILTER_PCTYPE_NONF_IPV6_SCTP               = 44,
+       I40E_FILTER_PCTYPE_NONF_IPV6_OTHER              = 45,
+       I40E_FILTER_PCTYPE_FRAG_IPV6                    = 46,
+       /* Note: Value 47 is reserved for future use */
+       I40E_FILTER_PCTYPE_FCOE_OX                      = 48,
+       I40E_FILTER_PCTYPE_FCOE_RX                      = 49,
+       /* Note: Value 50-62 are reserved for future use */
+       I40E_FILTER_PCTYPE_L2_PAYLOAD                   = 63,
+};
+
+enum i40e_filter_program_desc_dest {
+       I40E_FILTER_PROGRAM_DESC_DEST_DROP_PACKET               = 0x0,
+       I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX      = 0x1,
+       I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_OTHER       = 0x2,
+};
+
+enum i40e_filter_program_desc_fd_status {
+       I40E_FILTER_PROGRAM_DESC_FD_STATUS_NONE                 = 0x0,
+       I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID                = 0x1,
+       I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID_4FLEX_BYTES    = 0x2,
+       I40E_FILTER_PROGRAM_DESC_FD_STATUS_8FLEX_BYTES          = 0x3,
+};
+
+#define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT       23
+#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK        (0x1FFUL << \
+                                        I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT)
+
+#define I40E_TXD_FLTR_QW1_CMD_SHIFT    4
+#define I40E_TXD_FLTR_QW1_CMD_MASK     (0xFFFFULL << \
+                                        I40E_TXD_FLTR_QW1_CMD_SHIFT)
+
+#define I40E_TXD_FLTR_QW1_PCMD_SHIFT   (0x0ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT)
+#define I40E_TXD_FLTR_QW1_PCMD_MASK    (0x7ULL << I40E_TXD_FLTR_QW1_PCMD_SHIFT)
+
+enum i40e_filter_program_desc_pcmd {
+       I40E_FILTER_PROGRAM_DESC_PCMD_ADD_UPDATE        = 0x1,
+       I40E_FILTER_PROGRAM_DESC_PCMD_REMOVE            = 0x2,
+};
+
+#define I40E_TXD_FLTR_QW1_DEST_SHIFT   (0x3ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT)
+#define I40E_TXD_FLTR_QW1_DEST_MASK    (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT)
+
+#define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT        (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT)
+#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK (0x1ULL << \
+                                        I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT)
+
+#define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT      (0x9ULL + \
+                                                I40E_TXD_FLTR_QW1_CMD_SHIFT)
+#define I40E_TXD_FLTR_QW1_FD_STATUS_MASK (0x3ULL << \
+                                         I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT)
+
+#define I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT 20
+#define I40E_TXD_FLTR_QW1_CNTINDEX_MASK        (0x1FFUL << \
+                                        I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT)
+
+enum i40e_filter_type {
+       I40E_FLOW_DIRECTOR_FLTR = 0,
+       I40E_PE_QUAD_HASH_FLTR = 1,
+       I40E_ETHERTYPE_FLTR,
+       I40E_FCOE_CTX_FLTR,
+       I40E_MAC_VLAN_FLTR,
+       I40E_HASH_FLTR
+};
+
+struct i40e_vsi_context {
+       u16 seid;
+       u16 uplink_seid;
+       u16 vsi_number;
+       u16 vsis_allocated;
+       u16 vsis_unallocated;
+       u16 flags;
+       u8 pf_num;
+       u8 vf_num;
+       u8 connection_type;
+       struct i40e_aqc_vsi_properties_data info;
+};
+
+/* Statistics collected by each port, VSI, VEB, and S-channel */
+struct i40e_eth_stats {
+       u64 rx_bytes;                   /* gorc */
+       u64 rx_unicast;                 /* uprc */
+       u64 rx_multicast;               /* mprc */
+       u64 rx_broadcast;               /* bprc */
+       u64 rx_discards;                /* rdpc */
+       u64 rx_errors;                  /* repc */
+       u64 rx_missed;                  /* rmpc */
+       u64 rx_unknown_protocol;        /* rupp */
+       u64 tx_bytes;                   /* gotc */
+       u64 tx_unicast;                 /* uptc */
+       u64 tx_multicast;               /* mptc */
+       u64 tx_broadcast;               /* bptc */
+       u64 tx_discards;                /* tdpc */
+       u64 tx_errors;                  /* tepc */
+};
+
+/* Statistics collected by the MAC */
+struct i40e_hw_port_stats {
+       /* eth stats collected by the port */
+       struct i40e_eth_stats eth;
+
+       /* additional port specific stats */
+       u64 tx_dropped_link_down;       /* tdold */
+       u64 crc_errors;                 /* crcerrs */
+       u64 illegal_bytes;              /* illerrc */
+       u64 error_bytes;                /* errbc */
+       u64 mac_local_faults;           /* mlfc */
+       u64 mac_remote_faults;          /* mrfc */
+       u64 rx_length_errors;           /* rlec */
+       u64 link_xon_rx;                /* lxonrxc */
+       u64 link_xoff_rx;               /* lxoffrxc */
+       u64 priority_xon_rx[8];         /* pxonrxc[8] */
+       u64 priority_xoff_rx[8];        /* pxoffrxc[8] */
+       u64 link_xon_tx;                /* lxontxc */
+       u64 link_xoff_tx;               /* lxofftxc */
+       u64 priority_xon_tx[8];         /* pxontxc[8] */
+       u64 priority_xoff_tx[8];        /* pxofftxc[8] */
+       u64 priority_xon_2_xoff[8];     /* pxon2offc[8] */
+       u64 rx_size_64;                 /* prc64 */
+       u64 rx_size_127;                /* prc127 */
+       u64 rx_size_255;                /* prc255 */
+       u64 rx_size_511;                /* prc511 */
+       u64 rx_size_1023;               /* prc1023 */
+       u64 rx_size_1522;               /* prc1522 */
+       u64 rx_size_big;                /* prc9522 */
+       u64 rx_undersize;               /* ruc */
+       u64 rx_fragments;               /* rfc */
+       u64 rx_oversize;                /* roc */
+       u64 rx_jabber;                  /* rjc */
+       u64 tx_size_64;                 /* ptc64 */
+       u64 tx_size_127;                /* ptc127 */
+       u64 tx_size_255;                /* ptc255 */
+       u64 tx_size_511;                /* ptc511 */
+       u64 tx_size_1023;               /* ptc1023 */
+       u64 tx_size_1522;               /* ptc1522 */
+       u64 tx_size_big;                /* ptc9522 */
+       u64 mac_short_packet_dropped;   /* mspdc */
+       u64 checksum_error;             /* xec */
+};
+
+/* Checksum and Shadow RAM pointers */
+#define I40E_SR_NVM_CONTROL_WORD               0x00
+#define I40E_SR_EMP_MODULE_PTR                 0x0F
+#define I40E_SR_NVM_IMAGE_VERSION              0x18
+#define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR  0x27
+#define I40E_SR_NVM_EETRACK_LO                 0x2D
+#define I40E_SR_NVM_EETRACK_HI                 0x2E
+#define I40E_SR_VPD_PTR                                0x2F
+#define I40E_SR_PCIE_ALT_AUTO_LOAD_PTR         0x3E
+#define I40E_SR_SW_CHECKSUM_WORD               0x3F
+
+/* Auxiliary field, mask and shift definition for Shadow RAM and NVM Flash */
+#define I40E_SR_VPD_MODULE_MAX_SIZE            1024
+#define I40E_SR_PCIE_ALT_MODULE_MAX_SIZE       1024
+#define I40E_SR_CONTROL_WORD_1_SHIFT           0x06
+#define I40E_SR_CONTROL_WORD_1_MASK    (0x03 << I40E_SR_CONTROL_WORD_1_SHIFT)
+
+/* Shadow RAM related */
+#define I40E_SR_SECTOR_SIZE_IN_WORDS   0x800
+#define I40E_SR_WORDS_IN_1KB           512
+/* Checksum should be calculated such that after adding all the words,
+ * including the checksum word itself, the sum should be 0xBABA.
+ */
+#define I40E_SR_SW_CHECKSUM_BASE       0xBABA
+
+#define I40E_SRRD_SRCTL_ATTEMPTS       100000
+
+enum i40e_switch_element_types {
+       I40E_SWITCH_ELEMENT_TYPE_MAC    = 1,
+       I40E_SWITCH_ELEMENT_TYPE_PF     = 2,
+       I40E_SWITCH_ELEMENT_TYPE_VF     = 3,
+       I40E_SWITCH_ELEMENT_TYPE_EMP    = 4,
+       I40E_SWITCH_ELEMENT_TYPE_BMC    = 6,
+       I40E_SWITCH_ELEMENT_TYPE_PE     = 16,
+       I40E_SWITCH_ELEMENT_TYPE_VEB    = 17,
+       I40E_SWITCH_ELEMENT_TYPE_PA     = 18,
+       I40E_SWITCH_ELEMENT_TYPE_VSI    = 19,
+};
+
+/* Supported EtherType filters */
+enum i40e_ether_type_index {
+       I40E_ETHER_TYPE_1588            = 0,
+       I40E_ETHER_TYPE_FIP             = 1,
+       I40E_ETHER_TYPE_OUI_EXTENDED    = 2,
+       I40E_ETHER_TYPE_MAC_CONTROL     = 3,
+       I40E_ETHER_TYPE_LLDP            = 4,
+       I40E_ETHER_TYPE_EVB_PROTOCOL1   = 5,
+       I40E_ETHER_TYPE_EVB_PROTOCOL2   = 6,
+       I40E_ETHER_TYPE_QCN_CNM         = 7,
+       I40E_ETHER_TYPE_8021X           = 8,
+       I40E_ETHER_TYPE_ARP             = 9,
+       I40E_ETHER_TYPE_RSV1            = 10,
+       I40E_ETHER_TYPE_RSV2            = 11,
+};
+
+/* Filter context base size is 1K */
+#define I40E_HASH_FILTER_BASE_SIZE     1024
+/* Supported Hash filter values */
+enum i40e_hash_filter_size {
+       I40E_HASH_FILTER_SIZE_1K        = 0,
+       I40E_HASH_FILTER_SIZE_2K        = 1,
+       I40E_HASH_FILTER_SIZE_4K        = 2,
+       I40E_HASH_FILTER_SIZE_8K        = 3,
+       I40E_HASH_FILTER_SIZE_16K       = 4,
+       I40E_HASH_FILTER_SIZE_32K       = 5,
+       I40E_HASH_FILTER_SIZE_64K       = 6,
+       I40E_HASH_FILTER_SIZE_128K      = 7,
+       I40E_HASH_FILTER_SIZE_256K      = 8,
+       I40E_HASH_FILTER_SIZE_512K      = 9,
+       I40E_HASH_FILTER_SIZE_1M        = 10,
+};
+
+/* DMA context base size is 0.5K */
+#define I40E_DMA_CNTX_BASE_SIZE                512
+/* Supported DMA context values */
+enum i40e_dma_cntx_size {
+       I40E_DMA_CNTX_SIZE_512          = 0,
+       I40E_DMA_CNTX_SIZE_1K           = 1,
+       I40E_DMA_CNTX_SIZE_2K           = 2,
+       I40E_DMA_CNTX_SIZE_4K           = 3,
+       I40E_DMA_CNTX_SIZE_8K           = 4,
+       I40E_DMA_CNTX_SIZE_16K          = 5,
+       I40E_DMA_CNTX_SIZE_32K          = 6,
+       I40E_DMA_CNTX_SIZE_64K          = 7,
+       I40E_DMA_CNTX_SIZE_128K         = 8,
+       I40E_DMA_CNTX_SIZE_256K         = 9,
+};
+
+/* Supported Hash look up table (LUT) sizes */
+enum i40e_hash_lut_size {
+       I40E_HASH_LUT_SIZE_128          = 0,
+       I40E_HASH_LUT_SIZE_512          = 1,
+};
+
+/* Structure to hold a per PF filter control settings */
+struct i40e_filter_control_settings {
+       /* number of PE Quad Hash filter buckets */
+       enum i40e_hash_filter_size pe_filt_num;
+       /* number of PE Quad Hash contexts */
+       enum i40e_dma_cntx_size pe_cntx_num;
+       /* number of FCoE filter buckets */
+       enum i40e_hash_filter_size fcoe_filt_num;
+       /* number of FCoE DDP contexts */
+       enum i40e_dma_cntx_size fcoe_cntx_num;
+       /* size of the Hash LUT */
+       enum i40e_hash_lut_size hash_lut_size;
+       /* enable FDIR filters for PF and its VFs */
+       bool enable_fdir;
+       /* enable Ethertype filters for PF and its VFs */
+       bool enable_ethtype;
+       /* enable MAC/VLAN filters for PF and its VFs */
+       bool enable_macvlan;
+};
+
+/* Structure to hold device level control filter counts */
+struct i40e_control_filter_stats {
+       u16 mac_etype_used;   /* Used perfect match MAC/EtherType filters */
+       u16 etype_used;       /* Used perfect EtherType filters */
+       u16 mac_etype_free;   /* Un-used perfect match MAC/EtherType filters */
+       u16 etype_free;       /* Un-used perfect EtherType filters */
+};
+
+enum i40e_reset_type {
+       I40E_RESET_POR          = 0,
+       I40E_RESET_CORER        = 1,
+       I40E_RESET_GLOBR        = 2,
+       I40E_RESET_EMPR         = 3,
+};
+
+/* IEEE 802.1AB LLDP Agent Variables from NVM */
+#define I40E_NVM_LLDP_CFG_PTR          0xF
+struct i40e_lldp_variables {
+       u16 length;
+       u16 adminstatus;
+       u16 msgfasttx;
+       u16 msgtxinterval;
+       u16 txparams;
+       u16 timers;
+       u16 crc8;
+};
+
+#endif /* _I40E_TYPE_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h
new file mode 100644 (file)
index 0000000..cc6654f
--- /dev/null
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_VIRTCHNL_H_
+#define _I40E_VIRTCHNL_H_
+
+#include "i40e_type.h"
+
+/* Description:
+ * This header file describes the VF-PF communication protocol used
+ * by the various i40e drivers.
+ *
+ * Admin queue buffer usage:
+ * desc->opcode is always i40e_aqc_opc_send_msg_to_pf
+ * flags, retval, datalen, and data addr are all used normally.
+ * Firmware copies the cookie fields when sending messages between the PF and
+ * VF, but uses all other fields internally. Due to this limitation, we
+ * must send all messages as "indirect", i.e. using an external buffer.
+ *
+ * All the vsi indexes are relative to the VF. Each VF can have maximum of
+ * three VSIs. All the queue indexes are relative to the VSI.  Each VF can
+ * have a maximum of sixteen queues for all of its VSIs.
+ *
+ * The PF is required to return a status code in v_retval for all messages
+ * except RESET_VF, which does not require any response. The return value is of
+ * i40e_status_code type, defined in the i40e_type.h.
+ *
+ * In general, VF driver initialization should roughly follow the order of these
+ * opcodes. The VF driver must first validate the API version of the PF driver,
+ * then request a reset, then get resources, then configure queues and
+ * interrupts. After these operations are complete, the VF driver may start
+ * its queues, optionally add MAC and VLAN filters, and process traffic.
+ */
+
+/* Opcodes for VF-PF communication. These are placed in the v_opcode field
+ * of the virtchnl_msg structure.
+ */
+enum i40e_virtchnl_ops {
+/* VF sends req. to pf for the following
+ * ops.
+ */
+       I40E_VIRTCHNL_OP_UNKNOWN = 0,
+       I40E_VIRTCHNL_OP_VERSION = 1, /* must ALWAYS be 1 */
+       I40E_VIRTCHNL_OP_RESET_VF,
+       I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
+       I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE,
+       I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE,
+       I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+       I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
+       I40E_VIRTCHNL_OP_ENABLE_QUEUES,
+       I40E_VIRTCHNL_OP_DISABLE_QUEUES,
+       I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
+       I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS,
+       I40E_VIRTCHNL_OP_ADD_VLAN,
+       I40E_VIRTCHNL_OP_DEL_VLAN,
+       I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+       I40E_VIRTCHNL_OP_GET_STATS,
+       I40E_VIRTCHNL_OP_FCOE,
+/* PF sends status change events to vfs using
+ * the following op.
+ */
+       I40E_VIRTCHNL_OP_EVENT,
+};
+
+/* Virtual channel message descriptor. This overlays the admin queue
+ * descriptor. All other data is passed in external buffers.
+ */
+
+struct i40e_virtchnl_msg {
+       u8 pad[8];                       /* AQ flags/opcode/len/retval fields */
+       enum i40e_virtchnl_ops v_opcode; /* avoid confusion with desc->opcode */
+       i40e_status v_retval;  /* ditto for desc->retval */
+       u32 vfid;                        /* used by PF when sending to VF */
+};
+
+/* Message descriptions and data structures.*/
+
+/* I40E_VIRTCHNL_OP_VERSION
+ * VF posts its version number to the PF. PF responds with its version number
+ * in the same format, along with a return code.
+ * Reply from PF has its major/minor versions also in param0 and param1.
+ * If there is a major version mismatch, then the VF cannot operate.
+ * If there is a minor version mismatch, then the VF can operate but should
+ * add a warning to the system log.
+ *
+ * This enum element MUST always be specified as == 1, regardless of other
+ * changes in the API. The PF must always respond to this message without
+ * error regardless of version mismatch.
+ */
+#define I40E_VIRTCHNL_VERSION_MAJOR            1
+#define I40E_VIRTCHNL_VERSION_MINOR            0
+struct i40e_virtchnl_version_info {
+       u32 major;
+       u32 minor;
+};
+
+/* I40E_VIRTCHNL_OP_RESET_VF
+ * VF sends this request to PF with no parameters
+ * PF does NOT respond! VF driver must delay then poll VFGEN_RSTAT register
+ * until reset completion is indicated. The admin queue must be reinitialized
+ * after this operation.
+ *
+ * When reset is complete, PF must ensure that all queues in all VSIs associated
+ * with the VF are stopped, all queue configurations in the HMC are set to 0,
+ * and all MAC and VLAN filters (except the default MAC address) on all VSIs
+ * are cleared.
+ */
+
+/* I40E_VIRTCHNL_OP_GET_VF_RESOURCES
+ * VF sends this request to PF with no parameters
+ * PF responds with an indirect message containing
+ * i40e_virtchnl_vf_resource and one or more
+ * i40e_virtchnl_vsi_resource structures.
+ */
+
+struct i40e_virtchnl_vsi_resource {
+       u16 vsi_id;
+       u16 num_queue_pairs;
+       enum i40e_vsi_type vsi_type;
+       u16 qset_handle;
+       u8 default_mac_addr[I40E_ETH_LENGTH_OF_ADDRESS];
+};
+/* VF offload flags */
+#define I40E_VIRTCHNL_VF_OFFLOAD_L2    0x00000001
+#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE  0x00000004
+#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN  0x00010000
+
+struct i40e_virtchnl_vf_resource {
+       u16 num_vsis;
+       u16 num_queue_pairs;
+       u16 max_vectors;
+       u16 max_mtu;
+
+       u32 vf_offload_flags;
+       u32 max_fcoe_contexts;
+       u32 max_fcoe_filters;
+
+       struct i40e_virtchnl_vsi_resource vsi_res[1];
+};
+
+/* I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE
+ * VF sends this message to set up parameters for one TX queue.
+ * External data buffer contains one instance of i40e_virtchnl_txq_info.
+ * PF configures requested queue and returns a status code.
+ */
+
+/* Tx queue config info */
+struct i40e_virtchnl_txq_info {
+       u16 vsi_id;
+       u16 queue_id;
+       u16 ring_len;           /* number of descriptors, multiple of 8 */
+       u16 headwb_enabled;
+       u64 dma_ring_addr;
+       u64 dma_headwb_addr;
+};
+
+/* I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE
+ * VF sends this message to set up parameters for one RX queue.
+ * External data buffer contains one instance of i40e_virtchnl_rxq_info.
+ * PF configures requested queue and returns a status code.
+ */
+
+/* Rx queue config info */
+struct i40e_virtchnl_rxq_info {
+       u16 vsi_id;
+       u16 queue_id;
+       u32 ring_len;           /* number of descriptors, multiple of 32 */
+       u16 hdr_size;
+       u16 splithdr_enabled;
+       u32 databuffer_size;
+       u32 max_pkt_size;
+       u64 dma_ring_addr;
+       enum i40e_hmc_obj_rx_hsplit_0 rx_split_pos;
+};
+
+/* I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES
+ * VF sends this message to set parameters for all active TX and RX queues
+ * associated with the specified VSI.
+ * PF configures queues and returns status.
+ * If the number of queues specified is greater than the number of queues
+ * associated with the VSI, an error is returned and no queues are configured.
+ */
+struct i40e_virtchnl_queue_pair_info {
+       /* NOTE: vsi_id and queue_id should be identical for both queues. */
+       struct i40e_virtchnl_txq_info txq;
+       struct i40e_virtchnl_rxq_info rxq;
+};
+
+struct i40e_virtchnl_vsi_queue_config_info {
+       u16 vsi_id;
+       u16 num_queue_pairs;
+       struct i40e_virtchnl_queue_pair_info qpair[1];
+};
+
+/* I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP
+ * VF uses this message to map vectors to queues.
+ * The rxq_map and txq_map fields are bitmaps used to indicate which queues
+ * are to be associated with the specified vector.
+ * The "other" causes are always mapped to vector 0.
+ * PF configures interrupt mapping and returns status.
+ */
+struct i40e_virtchnl_vector_map {
+       u16 vsi_id;
+       u16 vector_id;
+       u16 rxq_map;
+       u16 txq_map;
+       u16 rxitr_idx;
+       u16 txitr_idx;
+};
+
+struct i40e_virtchnl_irq_map_info {
+       u16 num_vectors;
+       struct i40e_virtchnl_vector_map vecmap[1];
+};
+
+/* I40E_VIRTCHNL_OP_ENABLE_QUEUES
+ * I40E_VIRTCHNL_OP_DISABLE_QUEUES
+ * VF sends these message to enable or disable TX/RX queue pairs.
+ * The queues fields are bitmaps indicating which queues to act upon.
+ * (Currently, we only support 16 queues per VF, but we make the field
+ * u32 to allow for expansion.)
+ * PF performs requested action and returns status.
+ */
+struct i40e_virtchnl_queue_select {
+       u16 vsi_id;
+       u16 pad;
+       u32 rx_queues;
+       u32 tx_queues;
+};
+
+/* I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS
+ * VF sends this message in order to add one or more unicast or multicast
+ * address filters for the specified VSI.
+ * PF adds the filters and returns status.
+ */
+
+/* I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS
+ * VF sends this message in order to remove one or more unicast or multicast
+ * filters for the specified VSI.
+ * PF removes the filters and returns status.
+ */
+
+struct i40e_virtchnl_ether_addr {
+       u8 addr[I40E_ETH_LENGTH_OF_ADDRESS];
+       u8 pad[2];
+};
+
+struct i40e_virtchnl_ether_addr_list {
+       u16 vsi_id;
+       u16 num_elements;
+       struct i40e_virtchnl_ether_addr list[1];
+};
+
+/* I40E_VIRTCHNL_OP_ADD_VLAN
+ * VF sends this message to add one or more VLAN tag filters for receives.
+ * PF adds the filters and returns status.
+ * If a port VLAN is configured by the PF, this operation will return an
+ * error to the VF.
+ */
+
+/* I40E_VIRTCHNL_OP_DEL_VLAN
+ * VF sends this message to remove one or more VLAN tag filters for receives.
+ * PF removes the filters and returns status.
+ * If a port VLAN is configured by the PF, this operation will return an
+ * error to the VF.
+ */
+
+struct i40e_virtchnl_vlan_filter_list {
+       u16 vsi_id;
+       u16 num_elements;
+       u16 vlan_id[1];
+};
+
+/* I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE
+ * VF sends VSI id and flags.
+ * PF returns status code in retval.
+ * Note: we assume that broadcast accept mode is always enabled.
+ */
+struct i40e_virtchnl_promisc_info {
+       u16 vsi_id;
+       u16 flags;
+};
+
+#define I40E_FLAG_VF_UNICAST_PROMISC   0x00000001
+#define I40E_FLAG_VF_MULTICAST_PROMISC 0x00000002
+
+/* I40E_VIRTCHNL_OP_GET_STATS
+ * VF sends this message to request stats for the selected VSI. VF uses
+ * the i40e_virtchnl_queue_select struct to specify the VSI. The queue_id
+ * field is ignored by the PF.
+ *
+ * PF replies with struct i40e_eth_stats in an external buffer.
+ */
+
+/* I40E_VIRTCHNL_OP_EVENT
+ * PF sends this message to inform the VF driver of events that may affect it.
+ * No direct response is expected from the VF, though it may generate other
+ * messages in response to this one.
+ */
+enum i40e_virtchnl_event_codes {
+       I40E_VIRTCHNL_EVENT_UNKNOWN = 0,
+       I40E_VIRTCHNL_EVENT_LINK_CHANGE,
+       I40E_VIRTCHNL_EVENT_RESET_IMPENDING,
+       I40E_VIRTCHNL_EVENT_PF_DRIVER_CLOSE,
+};
+#define I40E_PF_EVENT_SEVERITY_INFO            0
+#define I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM    255
+
+struct i40e_virtchnl_pf_event {
+       enum i40e_virtchnl_event_codes event;
+       union {
+               struct {
+                       enum i40e_aq_link_speed link_speed;
+                       bool link_status;
+               } link_event;
+       } event_data;
+
+       int severity;
+};
+
+/* The following are TBD, not necessary for LAN functionality.
+ * I40E_VIRTCHNL_OP_FCOE
+ */
+
+/* VF reset states - these are written into the RSTAT register:
+ * I40E_VFGEN_RSTAT1 on the PF
+ * I40E_VFGEN_RSTAT on the VF
+ * When the PF initiates a reset, it writes 0
+ * When the reset is complete, it writes 1
+ * When the PF detects that the VF has recovered, it writes 2
+ * VF checks this register periodically to determine if a reset has occurred,
+ * then polls it to know when the reset is complete.
+ * If either the PF or VF reads the register while the hardware
+ * is in a reset state, it will return DEADBEEF, which, when masked
+ * will result in 3.
+ */
+enum i40e_vfr_states {
+       I40E_VFR_INPROGRESS = 0,
+       I40E_VFR_COMPLETED,
+       I40E_VFR_VFACTIVE,
+       I40E_VFR_UNKNOWN,
+};
+
+#endif /* _I40E_VIRTCHNL_H_ */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
new file mode 100644 (file)
index 0000000..8967e58
--- /dev/null
@@ -0,0 +1,2335 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#include "i40e.h"
+
+/***********************misc routines*****************************/
+
+/**
+ * i40e_vc_isvalid_vsi_id
+ * @vf: pointer to the vf info
+ * @vsi_id: vf relative vsi id
+ *
+ * check for the valid vsi id
+ **/
+static inline bool i40e_vc_isvalid_vsi_id(struct i40e_vf *vf, u8 vsi_id)
+{
+       struct i40e_pf *pf = vf->pf;
+
+       return pf->vsi[vsi_id]->vf_id == vf->vf_id;
+}
+
+/**
+ * i40e_vc_isvalid_queue_id
+ * @vf: pointer to the vf info
+ * @vsi_id: vsi id
+ * @qid: vsi relative queue id
+ *
+ * check for the valid queue id
+ **/
+static inline bool i40e_vc_isvalid_queue_id(struct i40e_vf *vf, u8 vsi_id,
+                                           u8 qid)
+{
+       struct i40e_pf *pf = vf->pf;
+
+       return qid < pf->vsi[vsi_id]->num_queue_pairs;
+}
+
+/**
+ * i40e_vc_isvalid_vector_id
+ * @vf: pointer to the vf info
+ * @vector_id: vf relative vector id
+ *
+ * check for the valid vector id
+ **/
+static inline bool i40e_vc_isvalid_vector_id(struct i40e_vf *vf, u8 vector_id)
+{
+       struct i40e_pf *pf = vf->pf;
+
+       return vector_id < pf->hw.func_caps.num_msix_vectors_vf;
+}
+
+/***********************vf resource mgmt routines*****************/
+
+/**
+ * i40e_vc_get_pf_queue_id
+ * @vf: pointer to the vf info
+ * @vsi_idx: index of VSI in PF struct
+ * @vsi_queue_id: vsi relative queue id
+ *
+ * return pf relative queue id
+ **/
+static u16 i40e_vc_get_pf_queue_id(struct i40e_vf *vf, u8 vsi_idx,
+                                  u8 vsi_queue_id)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = pf->vsi[vsi_idx];
+       u16 pf_queue_id = I40E_QUEUE_END_OF_LIST;
+
+       if (le16_to_cpu(vsi->info.mapping_flags) &
+           I40E_AQ_VSI_QUE_MAP_NONCONTIG)
+               pf_queue_id =
+                       le16_to_cpu(vsi->info.queue_mapping[vsi_queue_id]);
+       else
+               pf_queue_id = le16_to_cpu(vsi->info.queue_mapping[0]) +
+                             vsi_queue_id;
+
+       return pf_queue_id;
+}
+
+/**
+ * i40e_ctrl_vsi_tx_queue
+ * @vf: pointer to the vf info
+ * @vsi_idx: index of VSI in PF struct
+ * @vsi_queue_id: vsi relative queue index
+ * @ctrl: control flags
+ *
+ * enable/disable/enable check/disable check
+ **/
+static int i40e_ctrl_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx,
+                                 u16 vsi_queue_id,
+                                 enum i40e_queue_ctrl ctrl)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       bool writeback = false;
+       u16 pf_queue_id;
+       int ret = 0;
+       u32 reg;
+
+       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id);
+       reg = rd32(hw, I40E_QTX_ENA(pf_queue_id));
+
+       switch (ctrl) {
+       case I40E_QUEUE_CTRL_ENABLE:
+               reg |= I40E_QTX_ENA_QENA_REQ_MASK;
+               writeback = true;
+               break;
+       case I40E_QUEUE_CTRL_ENABLECHECK:
+               ret = (reg & I40E_QTX_ENA_QENA_STAT_MASK) ? 0 : -EPERM;
+               break;
+       case I40E_QUEUE_CTRL_DISABLE:
+               reg &= ~I40E_QTX_ENA_QENA_REQ_MASK;
+               writeback = true;
+               break;
+       case I40E_QUEUE_CTRL_DISABLECHECK:
+               ret = (reg & I40E_QTX_ENA_QENA_STAT_MASK) ? -EPERM : 0;
+               break;
+       case I40E_QUEUE_CTRL_FASTDISABLE:
+               reg |= I40E_QTX_ENA_FAST_QDIS_MASK;
+               writeback = true;
+               break;
+       case I40E_QUEUE_CTRL_FASTDISABLECHECK:
+               ret = (reg & I40E_QTX_ENA_QENA_STAT_MASK) ? -EPERM : 0;
+               if (!ret) {
+                       reg &= ~I40E_QTX_ENA_FAST_QDIS_MASK;
+                       writeback = true;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (writeback) {
+               wr32(hw, I40E_QTX_ENA(pf_queue_id), reg);
+               i40e_flush(hw);
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_ctrl_vsi_rx_queue
+ * @vf: pointer to the vf info
+ * @vsi_idx: index of VSI in PF struct
+ * @vsi_queue_id: vsi relative queue index
+ * @ctrl: control flags
+ *
+ * enable/disable/enable check/disable check
+ **/
+static int i40e_ctrl_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx,
+                                 u16 vsi_queue_id,
+                                 enum i40e_queue_ctrl ctrl)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       bool writeback = false;
+       u16 pf_queue_id;
+       int ret = 0;
+       u32 reg;
+
+       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id);
+       reg = rd32(hw, I40E_QRX_ENA(pf_queue_id));
+
+       switch (ctrl) {
+       case I40E_QUEUE_CTRL_ENABLE:
+               reg |= I40E_QRX_ENA_QENA_REQ_MASK;
+               writeback = true;
+               break;
+       case I40E_QUEUE_CTRL_ENABLECHECK:
+               ret = (reg & I40E_QRX_ENA_QENA_STAT_MASK) ? 0 : -EPERM;
+               break;
+       case I40E_QUEUE_CTRL_DISABLE:
+               reg &= ~I40E_QRX_ENA_QENA_REQ_MASK;
+               writeback = true;
+               break;
+       case I40E_QUEUE_CTRL_DISABLECHECK:
+               ret = (reg & I40E_QRX_ENA_QENA_STAT_MASK) ? -EPERM : 0;
+               break;
+       case I40E_QUEUE_CTRL_FASTDISABLE:
+               reg |= I40E_QRX_ENA_FAST_QDIS_MASK;
+               writeback = true;
+               break;
+       case I40E_QUEUE_CTRL_FASTDISABLECHECK:
+               ret = (reg & I40E_QRX_ENA_QENA_STAT_MASK) ? -EPERM : 0;
+               if (!ret) {
+                       reg &= ~I40E_QRX_ENA_FAST_QDIS_MASK;
+                       writeback = true;
+               }
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (writeback) {
+               wr32(hw, I40E_QRX_ENA(pf_queue_id), reg);
+               i40e_flush(hw);
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_config_irq_link_list
+ * @vf: pointer to the vf info
+ * @vsi_idx: index of VSI in PF struct
+ * @vecmap: irq map info
+ *
+ * configure irq link list from the map
+ **/
+static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_idx,
+                                     struct i40e_virtchnl_vector_map *vecmap)
+{
+       unsigned long linklistmap = 0, tempmap;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u16 vsi_queue_id, pf_queue_id;
+       enum i40e_queue_type qtype;
+       u16 next_q, vector_id;
+       u32 reg, reg_idx;
+       u16 itr_idx = 0;
+
+       vector_id = vecmap->vector_id;
+       /* setup the head */
+       if (0 == vector_id)
+               reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
+       else
+               reg_idx = I40E_VPINT_LNKLSTN(
+                           ((pf->hw.func_caps.num_msix_vectors_vf - 1)
+                                             * vf->vf_id) + (vector_id - 1));
+
+       if (vecmap->rxq_map == 0 && vecmap->txq_map == 0) {
+               /* Special case - No queues mapped on this vector */
+               wr32(hw, reg_idx, I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK);
+               goto irq_list_done;
+       }
+       tempmap = vecmap->rxq_map;
+       vsi_queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (vsi_queue_id < I40E_MAX_VSI_QP) {
+               linklistmap |= (1 <<
+                               (I40E_VIRTCHNL_SUPPORTED_QTYPES *
+                                vsi_queue_id));
+               vsi_queue_id =
+                   find_next_bit(&tempmap, I40E_MAX_VSI_QP, vsi_queue_id + 1);
+       }
+
+       tempmap = vecmap->txq_map;
+       vsi_queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (vsi_queue_id < I40E_MAX_VSI_QP) {
+               linklistmap |= (1 <<
+                               (I40E_VIRTCHNL_SUPPORTED_QTYPES * vsi_queue_id
+                                + 1));
+               vsi_queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                            vsi_queue_id + 1);
+       }
+
+       next_q = find_first_bit(&linklistmap,
+                               (I40E_MAX_VSI_QP *
+                                I40E_VIRTCHNL_SUPPORTED_QTYPES));
+       vsi_queue_id = next_q/I40E_VIRTCHNL_SUPPORTED_QTYPES;
+       qtype = next_q%I40E_VIRTCHNL_SUPPORTED_QTYPES;
+       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id);
+       reg = ((qtype << I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) | pf_queue_id);
+
+       wr32(hw, reg_idx, reg);
+
+       while (next_q < (I40E_MAX_VSI_QP * I40E_VIRTCHNL_SUPPORTED_QTYPES)) {
+               switch (qtype) {
+               case I40E_QUEUE_TYPE_RX:
+                       reg_idx = I40E_QINT_RQCTL(pf_queue_id);
+                       itr_idx = vecmap->rxitr_idx;
+                       break;
+               case I40E_QUEUE_TYPE_TX:
+                       reg_idx = I40E_QINT_TQCTL(pf_queue_id);
+                       itr_idx = vecmap->txitr_idx;
+                       break;
+               default:
+                       break;
+               }
+
+               next_q = find_next_bit(&linklistmap,
+                                      (I40E_MAX_VSI_QP *
+                                       I40E_VIRTCHNL_SUPPORTED_QTYPES),
+                                      next_q + 1);
+               if (next_q < (I40E_MAX_VSI_QP * I40E_VIRTCHNL_SUPPORTED_QTYPES)) {
+                       vsi_queue_id = next_q / I40E_VIRTCHNL_SUPPORTED_QTYPES;
+                       qtype = next_q % I40E_VIRTCHNL_SUPPORTED_QTYPES;
+                       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx,
+                                                             vsi_queue_id);
+               } else {
+                       pf_queue_id = I40E_QUEUE_END_OF_LIST;
+                       qtype = 0;
+               }
+
+               /* format for the RQCTL & TQCTL regs is same */
+               reg = (vector_id) |
+                   (qtype << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) |
+                   (pf_queue_id << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) |
+                   (1 << I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) |
+                   (itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT);
+               wr32(hw, reg_idx, reg);
+       }
+
+irq_list_done:
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_config_vsi_tx_queue
+ * @vf: pointer to the vf info
+ * @vsi_idx: index of VSI in PF struct
+ * @vsi_queue_id: vsi relative queue index
+ * @info: config. info
+ *
+ * configure tx queue
+ **/
+static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_idx,
+                                   u16 vsi_queue_id,
+                                   struct i40e_virtchnl_txq_info *info)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_hmc_obj_txq tx_ctx;
+       u16 pf_queue_id;
+       u32 qtx_ctl;
+       int ret = 0;
+
+       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id);
+
+       /* clear the context structure first */
+       memset(&tx_ctx, 0, sizeof(struct i40e_hmc_obj_txq));
+
+       /* only set the required fields */
+       tx_ctx.base = info->dma_ring_addr / 128;
+       tx_ctx.qlen = info->ring_len;
+       tx_ctx.rdylist = le16_to_cpu(pf->vsi[vsi_idx]->info.qs_handle[0]);
+       tx_ctx.rdylist_act = 0;
+
+       /* clear the context in the HMC */
+       ret = i40e_clear_lan_tx_queue_context(hw, pf_queue_id);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to clear VF LAN Tx queue context %d, error: %d\n",
+                       pf_queue_id, ret);
+               ret = -ENOENT;
+               goto error_context;
+       }
+
+       /* set the context in the HMC */
+       ret = i40e_set_lan_tx_queue_context(hw, pf_queue_id, &tx_ctx);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to set VF LAN Tx queue context %d error: %d\n",
+                       pf_queue_id, ret);
+               ret = -ENOENT;
+               goto error_context;
+       }
+
+       /* associate this queue with the PCI VF function */
+       qtx_ctl = I40E_QTX_CTL_VF_QUEUE;
+       qtx_ctl |= ((hw->hmc.hmc_fn_id << I40E_QTX_CTL_PF_INDX_SHIFT)
+                   & I40E_QTX_CTL_PF_INDX_MASK);
+       qtx_ctl |= (((vf->vf_id + hw->func_caps.vf_base_id)
+                    << I40E_QTX_CTL_VFVM_INDX_SHIFT)
+                   & I40E_QTX_CTL_VFVM_INDX_MASK);
+       wr32(hw, I40E_QTX_CTL(pf_queue_id), qtx_ctl);
+       i40e_flush(hw);
+
+error_context:
+       return ret;
+}
+
+/**
+ * i40e_config_vsi_rx_queue
+ * @vf: pointer to the vf info
+ * @vsi_idx: index of VSI in PF struct
+ * @vsi_queue_id: vsi relative queue index
+ * @info: config. info
+ *
+ * configure rx queue
+ **/
+static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_idx,
+                                   u16 vsi_queue_id,
+                                   struct i40e_virtchnl_rxq_info *info)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_hmc_obj_rxq rx_ctx;
+       u16 pf_queue_id;
+       int ret = 0;
+
+       pf_queue_id = i40e_vc_get_pf_queue_id(vf, vsi_idx, vsi_queue_id);
+
+       /* clear the context structure first */
+       memset(&rx_ctx, 0, sizeof(struct i40e_hmc_obj_rxq));
+
+       /* only set the required fields */
+       rx_ctx.base = info->dma_ring_addr / 128;
+       rx_ctx.qlen = info->ring_len;
+
+       if (info->splithdr_enabled) {
+               rx_ctx.hsplit_0 = I40E_RX_SPLIT_L2      |
+                                 I40E_RX_SPLIT_IP      |
+                                 I40E_RX_SPLIT_TCP_UDP |
+                                 I40E_RX_SPLIT_SCTP;
+               /* header length validation */
+               if (info->hdr_size > ((2 * 1024) - 64)) {
+                       ret = -EINVAL;
+                       goto error_param;
+               }
+               rx_ctx.hbuff = info->hdr_size >> I40E_RXQ_CTX_HBUFF_SHIFT;
+
+               /* set splitalways mode 10b */
+               rx_ctx.dtype = 0x2;
+       }
+
+       /* databuffer length validation */
+       if (info->databuffer_size > ((16 * 1024) - 128)) {
+               ret = -EINVAL;
+               goto error_param;
+       }
+       rx_ctx.dbuff = info->databuffer_size >> I40E_RXQ_CTX_DBUFF_SHIFT;
+
+       /* max pkt. length validation */
+       if (info->max_pkt_size >= (16 * 1024) || info->max_pkt_size < 64) {
+               ret = -EINVAL;
+               goto error_param;
+       }
+       rx_ctx.rxmax = info->max_pkt_size;
+
+       /* enable 32bytes desc always */
+       rx_ctx.dsize = 1;
+
+       /* default values */
+       rx_ctx.tphrdesc_ena = 1;
+       rx_ctx.tphwdesc_ena = 1;
+       rx_ctx.tphdata_ena = 1;
+       rx_ctx.tphhead_ena = 1;
+       rx_ctx.lrxqthresh = 2;
+       rx_ctx.crcstrip = 1;
+
+       /* clear the context in the HMC */
+       ret = i40e_clear_lan_rx_queue_context(hw, pf_queue_id);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to clear VF LAN Rx queue context %d, error: %d\n",
+                       pf_queue_id, ret);
+               ret = -ENOENT;
+               goto error_param;
+       }
+
+       /* set the context in the HMC */
+       ret = i40e_set_lan_rx_queue_context(hw, pf_queue_id, &rx_ctx);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "Failed to set VF LAN Rx queue context %d error: %d\n",
+                       pf_queue_id, ret);
+               ret = -ENOENT;
+               goto error_param;
+       }
+
+error_param:
+       return ret;
+}
+
+/**
+ * i40e_alloc_vsi_res
+ * @vf: pointer to the vf info
+ * @type: type of VSI to allocate
+ *
+ * alloc vf vsi context & resources
+ **/
+static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
+{
+       struct i40e_mac_filter *f = NULL;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vsi *vsi;
+       int ret = 0;
+
+       vsi = i40e_vsi_setup(pf, type, pf->vsi[pf->lan_vsi]->seid, vf->vf_id);
+
+       if (!vsi) {
+               dev_err(&pf->pdev->dev,
+                       "add vsi failed for vf %d, aq_err %d\n",
+                       vf->vf_id, pf->hw.aq.asq_last_status);
+               ret = -ENOENT;
+               goto error_alloc_vsi_res;
+       }
+       if (type == I40E_VSI_SRIOV) {
+               vf->lan_vsi_index = vsi->idx;
+               vf->lan_vsi_id = vsi->id;
+               dev_info(&pf->pdev->dev,
+                        "LAN VSI index %d, VSI id %d\n",
+                        vsi->idx, vsi->id);
+               f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
+                                   0, true, false);
+       }
+       if (!f) {
+               dev_err(&pf->pdev->dev, "Unable to add ucast filter\n");
+               ret = -ENOMEM;
+               goto error_alloc_vsi_res;
+       }
+
+       /* program mac filter */
+       ret = i40e_sync_vsi_filters(vsi);
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
+               goto error_alloc_vsi_res;
+       }
+
+       /* accept bcast pkts. by default */
+       ret = i40e_aq_set_vsi_broadcast(hw, vsi->seid, true, NULL);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "set vsi bcast failed for vf %d, vsi %d, aq_err %d\n",
+                       vf->vf_id, vsi->idx, pf->hw.aq.asq_last_status);
+               ret = -EINVAL;
+       }
+
+error_alloc_vsi_res:
+       return ret;
+}
+
+/**
+ * i40e_reset_vf
+ * @vf: pointer to the vf structure
+ * @flr: VFLR was issued or not
+ *
+ * reset the vf
+ **/
+int i40e_reset_vf(struct i40e_vf *vf, bool flr)
+{
+       int ret = -ENOENT;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg, reg_idx, msix_vf;
+       bool rsd = false;
+       u16 pf_queue_id;
+       int i, j;
+
+       /* warn the VF */
+       wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_INPROGRESS);
+
+       clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
+
+       /* PF triggers VFR only when VF requests, in case of
+        * VFLR, HW triggers VFR
+        */
+       if (!flr) {
+               /* reset vf using VPGEN_VFRTRIG reg */
+               reg = I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+               wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
+               i40e_flush(hw);
+       }
+
+       /* poll VPGEN_VFRSTAT reg to make sure
+        * that reset is complete
+        */
+       for (i = 0; i < 4; i++) {
+               /* vf reset requires driver to first reset the
+                * vf & than poll the status register to make sure
+                * that the requested op was completed
+                * successfully
+                */
+               udelay(10);
+               reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
+               if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) {
+                       rsd = true;
+                       break;
+               }
+       }
+
+       if (!rsd)
+               dev_err(&pf->pdev->dev, "VF reset check timeout %d\n",
+                       vf->vf_id);
+
+       /* fast disable qps */
+       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
+               ret = i40e_ctrl_vsi_tx_queue(vf, vf->lan_vsi_index, j,
+                                            I40E_QUEUE_CTRL_FASTDISABLE);
+               ret = i40e_ctrl_vsi_rx_queue(vf, vf->lan_vsi_index, j,
+                                            I40E_QUEUE_CTRL_FASTDISABLE);
+       }
+
+       /* Queue enable/disable requires driver to
+        * first reset the vf & than poll the status register
+        * to make sure that the requested op was completed
+        * successfully
+        */
+       udelay(10);
+       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
+               ret = i40e_ctrl_vsi_tx_queue(vf, vf->lan_vsi_index, j,
+                                            I40E_QUEUE_CTRL_FASTDISABLECHECK);
+               if (ret)
+                       dev_info(&pf->pdev->dev,
+                                "Queue control check failed on Tx queue %d of VSI %d VF %d\n",
+                                vf->lan_vsi_index, j, vf->vf_id);
+               ret = i40e_ctrl_vsi_rx_queue(vf, vf->lan_vsi_index, j,
+                                            I40E_QUEUE_CTRL_FASTDISABLECHECK);
+               if (ret)
+                       dev_info(&pf->pdev->dev,
+                                "Queue control check failed on Rx queue %d of VSI %d VF %d\n",
+                                vf->lan_vsi_index, j, vf->vf_id);
+       }
+
+       /* clear the irq settings */
+       msix_vf = pf->hw.func_caps.num_msix_vectors_vf;
+       for (i = 0; i < msix_vf; i++) {
+               /* format is same for both registers */
+               if (0 == i)
+                       reg_idx = I40E_VPINT_LNKLST0(vf->vf_id);
+               else
+                       reg_idx = I40E_VPINT_LNKLSTN(((msix_vf - 1) *
+                                                     (vf->vf_id))
+                                                    + (i - 1));
+               reg = (I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK |
+                      I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK);
+               wr32(hw, reg_idx, reg);
+               i40e_flush(hw);
+       }
+       /* disable interrupts so the VF starts in a known state */
+       for (i = 0; i < msix_vf; i++) {
+               /* format is same for both registers */
+               if (0 == i)
+                       reg_idx = I40E_VFINT_DYN_CTL0(vf->vf_id);
+               else
+                       reg_idx = I40E_VFINT_DYN_CTLN(((msix_vf - 1) *
+                                                     (vf->vf_id))
+                                                    + (i - 1));
+               wr32(hw, reg_idx, I40E_VFINT_DYN_CTLN_CLEARPBA_MASK);
+               i40e_flush(hw);
+       }
+
+       /* set the defaults for the rqctl & tqctl registers */
+       reg = (I40E_QINT_RQCTL_NEXTQ_INDX_MASK | I40E_QINT_RQCTL_ITR_INDX_MASK |
+              I40E_QINT_RQCTL_NEXTQ_TYPE_MASK);
+       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
+               pf_queue_id = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, j);
+               wr32(hw, I40E_QINT_RQCTL(pf_queue_id), reg);
+               wr32(hw, I40E_QINT_TQCTL(pf_queue_id), reg);
+       }
+
+       /* clear the reset bit in the VPGEN_VFRTRIG reg */
+       reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id));
+       reg &= ~I40E_VPGEN_VFRTRIG_VFSWR_MASK;
+       wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg);
+       /* tell the VF the reset is done */
+       wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_COMPLETED);
+       i40e_flush(hw);
+
+       return ret;
+}
+
+/**
+ * i40e_enable_vf_mappings
+ * @vf: pointer to the vf info
+ *
+ * enable vf mappings
+ **/
+static void i40e_enable_vf_mappings(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg, total_queue_pairs = 0;
+       int j;
+
+       /* Tell the hardware we're using noncontiguous mapping. HW requires
+        * that VF queues be mapped using this method, even when they are
+        * contiguous in real life
+        */
+       wr32(hw, I40E_VSILAN_QBASE(vf->lan_vsi_id),
+            I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK);
+
+       /* enable VF vplan_qtable mappings */
+       reg = I40E_VPLAN_MAPENA_TXRX_ENA_MASK;
+       wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), reg);
+
+       /* map PF queues to VF queues */
+       for (j = 0; j < pf->vsi[vf->lan_vsi_index]->num_queue_pairs; j++) {
+               u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index, j);
+               reg = (qid & I40E_VPLAN_QTABLE_QINDEX_MASK);
+               wr32(hw, I40E_VPLAN_QTABLE(total_queue_pairs, vf->vf_id), reg);
+               total_queue_pairs++;
+       }
+
+       /* map PF queues to VSI */
+       for (j = 0; j < 7; j++) {
+               if (j * 2 >= pf->vsi[vf->lan_vsi_index]->num_queue_pairs) {
+                       reg = 0x07FF07FF;       /* unused */
+               } else {
+                       u16 qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index,
+                                                         j * 2);
+                       reg = qid;
+                       qid = i40e_vc_get_pf_queue_id(vf, vf->lan_vsi_index,
+                                                     (j * 2) + 1);
+                       reg |= qid << 16;
+               }
+               wr32(hw, I40E_VSILAN_QTABLE(j, vf->lan_vsi_id), reg);
+       }
+
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_disable_vf_mappings
+ * @vf: pointer to the vf info
+ *
+ * disable vf mappings
+ **/
+static void i40e_disable_vf_mappings(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       int i;
+
+       /* disable qp mappings */
+       wr32(hw, I40E_VPLAN_MAPENA(vf->vf_id), 0);
+       for (i = 0; i < I40E_MAX_VSI_QP; i++)
+               wr32(hw, I40E_VPLAN_QTABLE(i, vf->vf_id),
+                    I40E_QUEUE_END_OF_LIST);
+       i40e_flush(hw);
+}
+
+/**
+ * i40e_free_vf_res
+ * @vf: pointer to the vf info
+ *
+ * free vf resources
+ **/
+static void i40e_free_vf_res(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+
+       /* free vsi & disconnect it from the parent uplink */
+       if (vf->lan_vsi_index) {
+               i40e_vsi_release(pf->vsi[vf->lan_vsi_index]);
+               vf->lan_vsi_index = 0;
+               vf->lan_vsi_id = 0;
+       }
+       /* reset some of the state varibles keeping
+        * track of the resources
+        */
+       vf->num_queue_pairs = 0;
+       vf->vf_states = 0;
+}
+
+/**
+ * i40e_alloc_vf_res
+ * @vf: pointer to the vf info
+ *
+ * allocate vf resources
+ **/
+static int i40e_alloc_vf_res(struct i40e_vf *vf)
+{
+       struct i40e_pf *pf = vf->pf;
+       int total_queue_pairs = 0;
+       int ret;
+
+       /* allocate hw vsi context & associated resources */
+       ret = i40e_alloc_vsi_res(vf, I40E_VSI_SRIOV);
+       if (ret)
+               goto error_alloc;
+       total_queue_pairs += pf->vsi[vf->lan_vsi_index]->num_queue_pairs;
+       set_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps);
+
+       /* store the total qps number for the runtime
+        * vf req validation
+        */
+       vf->num_queue_pairs = total_queue_pairs;
+
+       /* vf is now completely initialized */
+       set_bit(I40E_VF_STAT_INIT, &vf->vf_states);
+
+error_alloc:
+       if (ret)
+               i40e_free_vf_res(vf);
+
+       return ret;
+}
+
+/**
+ * i40e_vfs_are_assigned
+ * @pf: pointer to the pf structure
+ *
+ * Determine if any VFs are assigned to VMs
+ **/
+static bool i40e_vfs_are_assigned(struct i40e_pf *pf)
+{
+       struct pci_dev *pdev = pf->pdev;
+       struct pci_dev *vfdev;
+
+       /* loop through all the VFs to see if we own any that are assigned */
+       vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, I40E_VF_DEVICE_ID , NULL);
+       while (vfdev) {
+               /* if we don't own it we don't care */
+               if (vfdev->is_virtfn && pci_physfn(vfdev) == pdev) {
+                       /* if it is assigned we cannot release it */
+                       if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
+                               return true;
+               }
+
+               vfdev = pci_get_device(PCI_VENDOR_ID_INTEL,
+                                      I40E_VF_DEVICE_ID,
+                                      vfdev);
+       }
+
+       return false;
+}
+
+/**
+ * i40e_free_vfs
+ * @pf: pointer to the pf structure
+ *
+ * free vf resources
+ **/
+void i40e_free_vfs(struct i40e_pf *pf)
+{
+       struct i40e_hw *hw = &pf->hw;
+       int i;
+
+       if (!pf->vf)
+               return;
+
+       /* Disable interrupt 0 so we don't try to handle the VFLR. */
+       wr32(hw, I40E_PFINT_DYN_CTL0, 0);
+       i40e_flush(hw);
+
+       /* free up vf resources */
+       for (i = 0; i < pf->num_alloc_vfs; i++) {
+               if (test_bit(I40E_VF_STAT_INIT, &pf->vf[i].vf_states))
+                       i40e_free_vf_res(&pf->vf[i]);
+               /* disable qp mappings */
+               i40e_disable_vf_mappings(&pf->vf[i]);
+       }
+
+       kfree(pf->vf);
+       pf->vf = NULL;
+       pf->num_alloc_vfs = 0;
+
+       if (!i40e_vfs_are_assigned(pf))
+               pci_disable_sriov(pf->pdev);
+       else
+               dev_warn(&pf->pdev->dev,
+                        "unable to disable SR-IOV because VFs are assigned.\n");
+
+       /* Re-enable interrupt 0. */
+       wr32(hw, I40E_PFINT_DYN_CTL0,
+            I40E_PFINT_DYN_CTL0_INTENA_MASK |
+            I40E_PFINT_DYN_CTL0_CLEARPBA_MASK |
+            (I40E_ITR_NONE << I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT));
+       i40e_flush(hw);
+}
+
+#ifdef CONFIG_PCI_IOV
+/**
+ * i40e_alloc_vfs
+ * @pf: pointer to the pf structure
+ * @num_alloc_vfs: number of vfs to allocate
+ *
+ * allocate vf resources
+ **/
+static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs)
+{
+       struct i40e_vf *vfs;
+       int i, ret = 0;
+
+       ret = pci_enable_sriov(pf->pdev, num_alloc_vfs);
+       if (ret) {
+               dev_err(&pf->pdev->dev,
+                       "pci_enable_sriov failed with error %d!\n", ret);
+               pf->num_alloc_vfs = 0;
+               goto err_iov;
+       }
+
+       /* allocate memory */
+       vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL);
+       if (!vfs) {
+               ret = -ENOMEM;
+               goto err_alloc;
+       }
+
+       /* apply default profile */
+       for (i = 0; i < num_alloc_vfs; i++) {
+               vfs[i].pf = pf;
+               vfs[i].parent_type = I40E_SWITCH_ELEMENT_TYPE_VEB;
+               vfs[i].vf_id = i;
+
+               /* assign default capabilities */
+               set_bit(I40E_VIRTCHNL_VF_CAP_L2, &vfs[i].vf_caps);
+
+               ret = i40e_alloc_vf_res(&vfs[i]);
+               i40e_reset_vf(&vfs[i], true);
+               if (ret)
+                       break;
+
+               /* enable vf vplan_qtable mappings */
+               i40e_enable_vf_mappings(&vfs[i]);
+       }
+       pf->vf = vfs;
+       pf->num_alloc_vfs = num_alloc_vfs;
+
+err_alloc:
+       if (ret)
+               i40e_free_vfs(pf);
+err_iov:
+       return ret;
+}
+
+#endif
+/**
+ * i40e_pci_sriov_enable
+ * @pdev: pointer to a pci_dev structure
+ * @num_vfs: number of vfs to allocate
+ *
+ * Enable or change the number of VFs
+ **/
+static int i40e_pci_sriov_enable(struct pci_dev *pdev, int num_vfs)
+{
+#ifdef CONFIG_PCI_IOV
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+       int pre_existing_vfs = pci_num_vf(pdev);
+       int err = 0;
+
+       dev_info(&pdev->dev, "Allocating %d VFs.\n", num_vfs);
+       if (pre_existing_vfs && pre_existing_vfs != num_vfs)
+               i40e_free_vfs(pf);
+       else if (pre_existing_vfs && pre_existing_vfs == num_vfs)
+               goto out;
+
+       if (num_vfs > pf->num_req_vfs) {
+               err = -EPERM;
+               goto err_out;
+       }
+
+       err = i40e_alloc_vfs(pf, num_vfs);
+       if (err) {
+               dev_warn(&pdev->dev, "Failed to enable SR-IOV: %d\n", err);
+               goto err_out;
+       }
+
+out:
+       return num_vfs;
+
+err_out:
+       return err;
+#endif
+       return 0;
+}
+
+/**
+ * i40e_pci_sriov_configure
+ * @pdev: pointer to a pci_dev structure
+ * @num_vfs: number of vfs to allocate
+ *
+ * Enable or change the number of VFs. Called when the user updates the number
+ * of VFs in sysfs.
+ **/
+int i40e_pci_sriov_configure(struct pci_dev *pdev, int num_vfs)
+{
+       struct i40e_pf *pf = pci_get_drvdata(pdev);
+
+       if (num_vfs)
+               return i40e_pci_sriov_enable(pdev, num_vfs);
+
+       i40e_free_vfs(pf);
+       return 0;
+}
+
+/***********************virtual channel routines******************/
+
+/**
+ * i40e_vc_send_msg_to_vf
+ * @vf: pointer to the vf info
+ * @v_opcode: virtual channel opcode
+ * @v_retval: virtual channel return value
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * send msg to vf
+ **/
+static int i40e_vc_send_msg_to_vf(struct i40e_vf *vf, u32 v_opcode,
+                                 u32 v_retval, u8 *msg, u16 msglen)
+{
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       i40e_status aq_ret;
+
+       /* single place to detect unsuccessful return values */
+       if (v_retval) {
+               vf->num_invalid_msgs++;
+               dev_err(&pf->pdev->dev, "Failed opcode %d Error: %d\n",
+                       v_opcode, v_retval);
+               if (vf->num_invalid_msgs >
+                   I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED) {
+                       dev_err(&pf->pdev->dev,
+                               "Number of invalid messages exceeded for VF %d\n",
+                               vf->vf_id);
+                       dev_err(&pf->pdev->dev, "Use PF Control I/F to enable the VF\n");
+                       set_bit(I40E_VF_STAT_DISABLED, &vf->vf_states);
+               }
+       } else {
+               vf->num_valid_msgs++;
+       }
+
+       aq_ret = i40e_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval,
+                                    msg, msglen, NULL);
+       if (aq_ret) {
+               dev_err(&pf->pdev->dev,
+                       "Unable to send the message to VF %d aq_err %d\n",
+                       vf->vf_id, pf->hw.aq.asq_last_status);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_vc_send_resp_to_vf
+ * @vf: pointer to the vf info
+ * @opcode: operation code
+ * @retval: return value
+ *
+ * send resp msg to vf
+ **/
+static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf,
+                                  enum i40e_virtchnl_ops opcode,
+                                  i40e_status retval)
+{
+       return i40e_vc_send_msg_to_vf(vf, opcode, retval, NULL, 0);
+}
+
+/**
+ * i40e_vc_get_version_msg
+ * @vf: pointer to the vf info
+ *
+ * called from the vf to request the API version used by the PF
+ **/
+static int i40e_vc_get_version_msg(struct i40e_vf *vf)
+{
+       struct i40e_virtchnl_version_info info = {
+               I40E_VIRTCHNL_VERSION_MAJOR, I40E_VIRTCHNL_VERSION_MINOR
+       };
+
+       return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION,
+                                     I40E_SUCCESS, (u8 *)&info,
+                                     sizeof(struct
+                                            i40e_virtchnl_version_info));
+}
+
+/**
+ * i40e_vc_get_vf_resources_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to request its resources
+ **/
+static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf)
+{
+       struct i40e_virtchnl_vf_resource *vfres = NULL;
+       struct i40e_pf *pf = vf->pf;
+       i40e_status aq_ret = 0;
+       struct i40e_vsi *vsi;
+       int i = 0, len = 0;
+       int num_vsis = 1;
+       int ret;
+
+       if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto err;
+       }
+
+       len = (sizeof(struct i40e_virtchnl_vf_resource) +
+              sizeof(struct i40e_virtchnl_vsi_resource) * num_vsis);
+
+       vfres = kzalloc(len, GFP_KERNEL);
+       if (!vfres) {
+               aq_ret = I40E_ERR_NO_MEMORY;
+               len = 0;
+               goto err;
+       }
+
+       vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2;
+       vsi = pf->vsi[vf->lan_vsi_index];
+       if (!vsi->info.pvid)
+               vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
+
+       vfres->num_vsis = num_vsis;
+       vfres->num_queue_pairs = vf->num_queue_pairs;
+       vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
+       if (vf->lan_vsi_index) {
+               vfres->vsi_res[i].vsi_id = vf->lan_vsi_index;
+               vfres->vsi_res[i].vsi_type = I40E_VSI_SRIOV;
+               vfres->vsi_res[i].num_queue_pairs =
+                   pf->vsi[vf->lan_vsi_index]->num_queue_pairs;
+               memcpy(vfres->vsi_res[i].default_mac_addr,
+                      vf->default_lan_addr.addr, ETH_ALEN);
+               i++;
+       }
+       set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
+
+err:
+       /* send the response back to the vf */
+       ret = i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_VF_RESOURCES,
+                                    aq_ret, (u8 *)vfres, len);
+
+       kfree(vfres);
+       return ret;
+}
+
+/**
+ * i40e_vc_reset_vf_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to reset itself,
+ * unlike other virtchnl messages, pf driver
+ * doesn't send the response back to the vf
+ **/
+static int i40e_vc_reset_vf_msg(struct i40e_vf *vf)
+{
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states))
+               return -ENOENT;
+
+       return i40e_reset_vf(vf, false);
+}
+
+/**
+ * i40e_vc_config_promiscuous_mode_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to configure the promiscuous mode of
+ * vf vsis
+ **/
+static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
+                                              u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_promisc_info *info =
+           (struct i40e_virtchnl_promisc_info *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_hw *hw = &pf->hw;
+       bool allmulti = false;
+       bool promisc = false;
+       i40e_status aq_ret;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
+           !i40e_vc_isvalid_vsi_id(vf, info->vsi_id) ||
+           (pf->vsi[info->vsi_id]->type != I40E_VSI_FCOE)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (info->flags & I40E_FLAG_VF_UNICAST_PROMISC)
+               promisc = true;
+       aq_ret = i40e_aq_set_vsi_unicast_promiscuous(hw, info->vsi_id,
+                                                    promisc, NULL);
+       if (aq_ret)
+               goto error_param;
+
+       if (info->flags & I40E_FLAG_VF_MULTICAST_PROMISC)
+               allmulti = true;
+       aq_ret = i40e_aq_set_vsi_multicast_promiscuous(hw, info->vsi_id,
+                                                      allmulti, NULL);
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf,
+                                      I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_config_queues_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to configure the rx/tx
+ * queues
+ **/
+static int i40e_vc_config_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_vsi_queue_config_info *qci =
+           (struct i40e_virtchnl_vsi_queue_config_info *)msg;
+       struct i40e_virtchnl_queue_pair_info *qpi;
+       u16 vsi_id, vsi_queue_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       vsi_id = qci->vsi_id;
+       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+       for (i = 0; i < qci->num_queue_pairs; i++) {
+               qpi = &qci->qpair[i];
+               vsi_queue_id = qpi->txq.queue_id;
+               if ((qpi->txq.vsi_id != vsi_id) ||
+                   (qpi->rxq.vsi_id != vsi_id) ||
+                   (qpi->rxq.queue_id != vsi_queue_id) ||
+                   !i40e_vc_isvalid_queue_id(vf, vsi_id, vsi_queue_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               if (i40e_config_vsi_rx_queue(vf, vsi_id, vsi_queue_id,
+                                            &qpi->rxq) ||
+                   i40e_config_vsi_tx_queue(vf, vsi_id, vsi_queue_id,
+                                            &qpi->txq)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+       }
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_config_irq_map_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to configure the irq to
+ * queue map
+ **/
+static int i40e_vc_config_irq_map_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_irq_map_info *irqmap_info =
+           (struct i40e_virtchnl_irq_map_info *)msg;
+       struct i40e_virtchnl_vector_map *map;
+       u16 vsi_id, vsi_queue_id, vector_id;
+       i40e_status aq_ret = 0;
+       unsigned long tempmap;
+       int i;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < irqmap_info->num_vectors; i++) {
+               map = &irqmap_info->vecmap[i];
+
+               vector_id = map->vector_id;
+               vsi_id = map->vsi_id;
+               /* validate msg params */
+               if (!i40e_vc_isvalid_vector_id(vf, vector_id) ||
+                   !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+
+               /* lookout for the invalid queue index */
+               tempmap = map->rxq_map;
+               vsi_queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+               while (vsi_queue_id < I40E_MAX_VSI_QP) {
+                       if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
+                                                     vsi_queue_id)) {
+                               aq_ret = I40E_ERR_PARAM;
+                               goto error_param;
+                       }
+                       vsi_queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                                    vsi_queue_id + 1);
+               }
+
+               tempmap = map->txq_map;
+               vsi_queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+               while (vsi_queue_id < I40E_MAX_VSI_QP) {
+                       if (!i40e_vc_isvalid_queue_id(vf, vsi_id,
+                                                     vsi_queue_id)) {
+                               aq_ret = I40E_ERR_PARAM;
+                               goto error_param;
+                       }
+                       vsi_queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                                    vsi_queue_id + 1);
+               }
+
+               i40e_config_irq_link_list(vf, vsi_id, map);
+       }
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_enable_queues_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to enable all or specific queue(s)
+ **/
+static int i40e_vc_enable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_queue_select *vqs =
+           (struct i40e_virtchnl_queue_select *)msg;
+       struct i40e_pf *pf = vf->pf;
+       u16 vsi_id = vqs->vsi_id;
+       i40e_status aq_ret = 0;
+       unsigned long tempmap;
+       u16 queue_id;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       tempmap = vqs->rx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+               i40e_ctrl_vsi_rx_queue(vf, vsi_id, queue_id,
+                                      I40E_QUEUE_CTRL_ENABLE);
+
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+       tempmap = vqs->tx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+               i40e_ctrl_vsi_tx_queue(vf, vsi_id, queue_id,
+                                      I40E_QUEUE_CTRL_ENABLE);
+
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+       /* Poll the status register to make sure that the
+        * requested op was completed successfully
+        */
+       udelay(10);
+
+       tempmap = vqs->rx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (i40e_ctrl_vsi_rx_queue(vf, vsi_id, queue_id,
+                                          I40E_QUEUE_CTRL_ENABLECHECK)) {
+                       dev_err(&pf->pdev->dev,
+                               "Queue control check failed on RX queue %d of VSI %d VF %d\n",
+                               queue_id, vsi_id, vf->vf_id);
+               }
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+       tempmap = vqs->tx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (i40e_ctrl_vsi_tx_queue(vf, vsi_id, queue_id,
+                                          I40E_QUEUE_CTRL_ENABLECHECK)) {
+                       dev_err(&pf->pdev->dev,
+                               "Queue control check failed on TX queue %d of VSI %d VF %d\n",
+                               queue_id, vsi_id, vf->vf_id);
+               }
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_disable_queues_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to disable all or specific
+ * queue(s)
+ **/
+static int i40e_vc_disable_queues_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_queue_select *vqs =
+           (struct i40e_virtchnl_queue_select *)msg;
+       struct i40e_pf *pf = vf->pf;
+       u16 vsi_id = vqs->vsi_id;
+       i40e_status aq_ret = 0;
+       unsigned long tempmap;
+       u16 queue_id;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if ((0 == vqs->rx_queues) && (0 == vqs->tx_queues)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       tempmap = vqs->rx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+               i40e_ctrl_vsi_rx_queue(vf, vsi_id, queue_id,
+                                      I40E_QUEUE_CTRL_DISABLE);
+
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+       tempmap = vqs->tx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (!i40e_vc_isvalid_queue_id(vf, vsi_id, queue_id)) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+               i40e_ctrl_vsi_tx_queue(vf, vsi_id, queue_id,
+                                      I40E_QUEUE_CTRL_DISABLE);
+
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+       /* Poll the status register to make sure that the
+        * requested op was completed successfully
+        */
+       udelay(10);
+
+       tempmap = vqs->rx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (i40e_ctrl_vsi_rx_queue(vf, vsi_id, queue_id,
+                                          I40E_QUEUE_CTRL_DISABLECHECK)) {
+                       dev_err(&pf->pdev->dev,
+                               "Queue control check failed on RX queue %d of VSI %d VF %d\n",
+                               queue_id, vsi_id, vf->vf_id);
+               }
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+       tempmap = vqs->tx_queues;
+       queue_id = find_first_bit(&tempmap, I40E_MAX_VSI_QP);
+       while (queue_id < I40E_MAX_VSI_QP) {
+               if (i40e_ctrl_vsi_tx_queue(vf, vsi_id, queue_id,
+                                          I40E_QUEUE_CTRL_DISABLECHECK)) {
+                       dev_err(&pf->pdev->dev,
+                               "Queue control check failed on TX queue %d of VSI %d VF %d\n",
+                               queue_id, vsi_id, vf->vf_id);
+               }
+               queue_id = find_next_bit(&tempmap, I40E_MAX_VSI_QP,
+                                        queue_id + 1);
+       }
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_get_stats_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf to get vsi stats
+ **/
+static int i40e_vc_get_stats_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_queue_select *vqs =
+           (struct i40e_virtchnl_queue_select *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_eth_stats stats;
+       i40e_status aq_ret = 0;
+       struct i40e_vsi *vsi;
+
+       memset(&stats, 0, sizeof(struct i40e_eth_stats));
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       if (!i40e_vc_isvalid_vsi_id(vf, vqs->vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       vsi = pf->vsi[vqs->vsi_id];
+       if (!vsi) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+       i40e_update_eth_stats(vsi);
+       memcpy(&stats, &vsi->eth_stats, sizeof(struct i40e_eth_stats));
+
+error_param:
+       /* send the response back to the vf */
+       return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_GET_STATS, aq_ret,
+                                     (u8 *)&stats, sizeof(stats));
+}
+
+/**
+ * i40e_vc_add_mac_addr_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * add guest mac address filter
+ **/
+static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_ether_addr_list *al =
+           (struct i40e_virtchnl_ether_addr_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = al->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < al->num_elements; i++) {
+               if (is_broadcast_ether_addr(al->list[i].addr) ||
+                   is_zero_ether_addr(al->list[i].addr)) {
+                       dev_err(&pf->pdev->dev, "invalid VF MAC addr %pMAC\n",
+                               al->list[i].addr);
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+       }
+       vsi = pf->vsi[vsi_id];
+
+       /* add new addresses to the list */
+       for (i = 0; i < al->num_elements; i++) {
+               struct i40e_mac_filter *f;
+
+               f = i40e_find_mac(vsi, al->list[i].addr, true, false);
+               if (f) {
+                       if (i40e_is_vsi_in_vlan(vsi))
+                               f = i40e_put_mac_in_vlan(vsi, al->list[i].addr,
+                                                        true, false);
+                       else
+                               f = i40e_add_filter(vsi, al->list[i].addr, -1,
+                                                   true, false);
+               }
+
+               if (!f) {
+                       dev_err(&pf->pdev->dev,
+                               "Unable to add VF MAC filter\n");
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+       }
+
+       /* program the updated filter list */
+       if (i40e_sync_vsi_filters(vsi))
+               dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n");
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_del_mac_addr_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * remove guest mac address filter
+ **/
+static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_ether_addr_list *al =
+           (struct i40e_virtchnl_ether_addr_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = al->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+       vsi = pf->vsi[vsi_id];
+
+       /* delete addresses from the list */
+       for (i = 0; i < al->num_elements; i++)
+               i40e_del_filter(vsi, al->list[i].addr,
+                               I40E_VLAN_ANY, true, false);
+
+       /* program the updated filter list */
+       if (i40e_sync_vsi_filters(vsi))
+               dev_err(&pf->pdev->dev, "Unable to program VF MAC filters\n");
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS,
+                                      aq_ret);
+}
+
+/**
+ * i40e_vc_add_vlan_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * program guest vlan id
+ **/
+static int i40e_vc_add_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_vlan_filter_list *vfl =
+           (struct i40e_virtchnl_vlan_filter_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = vfl->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < vfl->num_elements; i++) {
+               if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
+                       aq_ret = I40E_ERR_PARAM;
+                       dev_err(&pf->pdev->dev,
+                               "invalid VF VLAN id %d\n", vfl->vlan_id[i]);
+                       goto error_param;
+               }
+       }
+       vsi = pf->vsi[vsi_id];
+       if (vsi->info.pvid) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       i40e_vlan_stripping_enable(vsi);
+       for (i = 0; i < vfl->num_elements; i++) {
+               /* add new VLAN filter */
+               int ret = i40e_vsi_add_vlan(vsi, vfl->vlan_id[i]);
+               if (ret)
+                       dev_err(&pf->pdev->dev,
+                               "Unable to add VF vlan filter %d, error %d\n",
+                               vfl->vlan_id[i], ret);
+       }
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_ADD_VLAN, aq_ret);
+}
+
+/**
+ * i40e_vc_remove_vlan_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * remove programmed guest vlan id
+ **/
+static int i40e_vc_remove_vlan_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       struct i40e_virtchnl_vlan_filter_list *vfl =
+           (struct i40e_virtchnl_vlan_filter_list *)msg;
+       struct i40e_pf *pf = vf->pf;
+       struct i40e_vsi *vsi = NULL;
+       u16 vsi_id = vfl->vsi_id;
+       i40e_status aq_ret = 0;
+       int i;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VIRTCHNL_VF_CAP_PRIVILEGE, &vf->vf_caps) ||
+           !i40e_vc_isvalid_vsi_id(vf, vsi_id)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < vfl->num_elements; i++) {
+               if (vfl->vlan_id[i] > I40E_MAX_VLANID) {
+                       aq_ret = I40E_ERR_PARAM;
+                       goto error_param;
+               }
+       }
+
+       vsi = pf->vsi[vsi_id];
+       if (vsi->info.pvid) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+
+       for (i = 0; i < vfl->num_elements; i++) {
+               int ret = i40e_vsi_kill_vlan(vsi, vfl->vlan_id[i]);
+               if (ret)
+                       dev_err(&pf->pdev->dev,
+                               "Unable to delete VF vlan filter %d, error %d\n",
+                               vfl->vlan_id[i], ret);
+       }
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_DEL_VLAN, aq_ret);
+}
+
+/**
+ * i40e_vc_fcoe_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * called from the vf for the fcoe msgs
+ **/
+static int i40e_vc_fcoe_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
+{
+       i40e_status aq_ret = 0;
+
+       if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
+           !test_bit(I40E_VF_STAT_FCOEENA, &vf->vf_states)) {
+               aq_ret = I40E_ERR_PARAM;
+               goto error_param;
+       }
+       aq_ret = I40E_ERR_NOT_IMPLEMENTED;
+
+error_param:
+       /* send the response to the vf */
+       return i40e_vc_send_resp_to_vf(vf, I40E_VIRTCHNL_OP_FCOE, aq_ret);
+}
+
+/**
+ * i40e_vc_validate_vf_msg
+ * @vf: pointer to the vf info
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @msghndl: msg handle
+ *
+ * validate msg
+ **/
+static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode,
+                                  u32 v_retval, u8 *msg, u16 msglen)
+{
+       bool err_msg_format = false;
+       int valid_len;
+
+       /* Check if VF is disabled. */
+       if (test_bit(I40E_VF_STAT_DISABLED, &vf->vf_states))
+               return I40E_ERR_PARAM;
+
+       /* Validate message length. */
+       switch (v_opcode) {
+       case I40E_VIRTCHNL_OP_VERSION:
+               valid_len = sizeof(struct i40e_virtchnl_version_info);
+               break;
+       case I40E_VIRTCHNL_OP_RESET_VF:
+       case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
+               valid_len = 0;
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE:
+               valid_len = sizeof(struct i40e_virtchnl_txq_info);
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_RX_QUEUE:
+               valid_len = sizeof(struct i40e_virtchnl_rxq_info);
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+               valid_len = sizeof(struct i40e_virtchnl_vsi_queue_config_info);
+               if (msglen >= valid_len) {
+                       struct i40e_virtchnl_vsi_queue_config_info *vqc =
+                           (struct i40e_virtchnl_vsi_queue_config_info *)msg;
+                       valid_len += (vqc->num_queue_pairs *
+                                     sizeof(struct
+                                            i40e_virtchnl_queue_pair_info));
+                       if (vqc->num_queue_pairs == 0)
+                               err_msg_format = true;
+               }
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
+               valid_len = sizeof(struct i40e_virtchnl_irq_map_info);
+               if (msglen >= valid_len) {
+                       struct i40e_virtchnl_irq_map_info *vimi =
+                           (struct i40e_virtchnl_irq_map_info *)msg;
+                       valid_len += (vimi->num_vectors *
+                                     sizeof(struct i40e_virtchnl_vector_map));
+                       if (vimi->num_vectors == 0)
+                               err_msg_format = true;
+               }
+               break;
+       case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
+       case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
+               valid_len = sizeof(struct i40e_virtchnl_queue_select);
+               break;
+       case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
+       case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
+               valid_len = sizeof(struct i40e_virtchnl_ether_addr_list);
+               if (msglen >= valid_len) {
+                       struct i40e_virtchnl_ether_addr_list *veal =
+                           (struct i40e_virtchnl_ether_addr_list *)msg;
+                       valid_len += veal->num_elements *
+                           sizeof(struct i40e_virtchnl_ether_addr);
+                       if (veal->num_elements == 0)
+                               err_msg_format = true;
+               }
+               break;
+       case I40E_VIRTCHNL_OP_ADD_VLAN:
+       case I40E_VIRTCHNL_OP_DEL_VLAN:
+               valid_len = sizeof(struct i40e_virtchnl_vlan_filter_list);
+               if (msglen >= valid_len) {
+                       struct i40e_virtchnl_vlan_filter_list *vfl =
+                           (struct i40e_virtchnl_vlan_filter_list *)msg;
+                       valid_len += vfl->num_elements * sizeof(u16);
+                       if (vfl->num_elements == 0)
+                               err_msg_format = true;
+               }
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+               valid_len = sizeof(struct i40e_virtchnl_promisc_info);
+               break;
+       case I40E_VIRTCHNL_OP_GET_STATS:
+               valid_len = sizeof(struct i40e_virtchnl_queue_select);
+               break;
+       /* These are always errors coming from the VF. */
+       case I40E_VIRTCHNL_OP_EVENT:
+       case I40E_VIRTCHNL_OP_UNKNOWN:
+       default:
+               return -EPERM;
+               break;
+       }
+       /* few more checks */
+       if ((valid_len != msglen) || (err_msg_format)) {
+               i40e_vc_send_resp_to_vf(vf, v_opcode, I40E_ERR_PARAM);
+               return -EINVAL;
+       } else {
+               return 0;
+       }
+}
+
+/**
+ * i40e_vc_process_vf_msg
+ * @pf: pointer to the pf structure
+ * @vf_id: source vf id
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @msghndl: msg handle
+ *
+ * called from the common aeq/arq handler to
+ * process request from vf
+ **/
+int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
+                          u32 v_retval, u8 *msg, u16 msglen)
+{
+       struct i40e_vf *vf = &(pf->vf[vf_id]);
+       struct i40e_hw *hw = &pf->hw;
+       int ret;
+
+       pf->vf_aq_requests++;
+       /* perform basic checks on the msg */
+       ret = i40e_vc_validate_vf_msg(vf, v_opcode, v_retval, msg, msglen);
+
+       if (ret) {
+               dev_err(&pf->pdev->dev, "invalid message from vf %d\n", vf_id);
+               return ret;
+       }
+       wr32(hw, I40E_VFGEN_RSTAT1(vf_id), I40E_VFR_VFACTIVE);
+       switch (v_opcode) {
+       case I40E_VIRTCHNL_OP_VERSION:
+               ret = i40e_vc_get_version_msg(vf);
+               break;
+       case I40E_VIRTCHNL_OP_GET_VF_RESOURCES:
+               ret = i40e_vc_get_vf_resources_msg(vf);
+               break;
+       case I40E_VIRTCHNL_OP_RESET_VF:
+               ret = i40e_vc_reset_vf_msg(vf);
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+               ret = i40e_vc_config_promiscuous_mode_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+               ret = i40e_vc_config_queues_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
+               ret = i40e_vc_config_irq_map_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
+               ret = i40e_vc_enable_queues_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
+               ret = i40e_vc_disable_queues_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
+               ret = i40e_vc_add_mac_addr_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
+               ret = i40e_vc_del_mac_addr_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_ADD_VLAN:
+               ret = i40e_vc_add_vlan_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_DEL_VLAN:
+               ret = i40e_vc_remove_vlan_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_GET_STATS:
+               ret = i40e_vc_get_stats_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_FCOE:
+               ret = i40e_vc_fcoe_msg(vf, msg, msglen);
+               break;
+       case I40E_VIRTCHNL_OP_UNKNOWN:
+       default:
+               dev_err(&pf->pdev->dev,
+                       "Unsupported opcode %d from vf %d\n", v_opcode, vf_id);
+               ret = i40e_vc_send_resp_to_vf(vf, v_opcode,
+                                             I40E_ERR_NOT_IMPLEMENTED);
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * i40e_vc_process_vflr_event
+ * @pf: pointer to the pf structure
+ *
+ * called from the vlfr irq handler to
+ * free up vf resources and state variables
+ **/
+int i40e_vc_process_vflr_event(struct i40e_pf *pf)
+{
+       u32 reg, reg_idx, bit_idx, vf_id;
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf;
+
+       if (!test_bit(__I40E_VFLR_EVENT_PENDING, &pf->state))
+               return 0;
+
+       clear_bit(__I40E_VFLR_EVENT_PENDING, &pf->state);
+       for (vf_id = 0; vf_id < pf->num_alloc_vfs; vf_id++) {
+               reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32;
+               bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32;
+               /* read GLGEN_VFLRSTAT register to find out the flr vfs */
+               vf = &pf->vf[vf_id];
+               reg = rd32(hw, I40E_GLGEN_VFLRSTAT(reg_idx));
+               if (reg & (1 << bit_idx)) {
+                       /* clear the bit in GLGEN_VFLRSTAT */
+                       wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx));
+
+                       if (i40e_reset_vf(vf, true))
+                               dev_err(&pf->pdev->dev,
+                                       "Unable to reset the VF %d\n", vf_id);
+                       /* free up vf resources to destroy vsi state */
+                       i40e_free_vf_res(vf);
+
+                       /* allocate new vf resources with the default state */
+                       if (i40e_alloc_vf_res(vf))
+                               dev_err(&pf->pdev->dev,
+                                       "Unable to allocate VF resources %d\n",
+                                       vf_id);
+
+                       i40e_enable_vf_mappings(vf);
+               }
+       }
+
+       /* re-enable vflr interrupt cause */
+       reg = rd32(hw, I40E_PFINT_ICR0_ENA);
+       reg |= I40E_PFINT_ICR0_ENA_VFLR_MASK;
+       wr32(hw, I40E_PFINT_ICR0_ENA, reg);
+       i40e_flush(hw);
+
+       return 0;
+}
+
+/**
+ * i40e_vc_vf_broadcast
+ * @pf: pointer to the pf structure
+ * @opcode: operation code
+ * @retval: return value
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ *
+ * send a message to all VFs on a given PF
+ **/
+static void i40e_vc_vf_broadcast(struct i40e_pf *pf,
+                                enum i40e_virtchnl_ops v_opcode,
+                                i40e_status v_retval, u8 *msg,
+                                u16 msglen)
+{
+       struct i40e_hw *hw = &pf->hw;
+       struct i40e_vf *vf = pf->vf;
+       int i;
+
+       for (i = 0; i < pf->num_alloc_vfs; i++) {
+               /* Ignore return value on purpose - a given VF may fail, but
+                * we need to keep going and send to all of them
+                */
+               i40e_aq_send_msg_to_vf(hw, vf->vf_id, v_opcode, v_retval,
+                                      msg, msglen, NULL);
+               vf++;
+       }
+}
+
+/**
+ * i40e_vc_notify_link_state
+ * @pf: pointer to the pf structure
+ *
+ * send a link status message to all VFs on a given PF
+ **/
+void i40e_vc_notify_link_state(struct i40e_pf *pf)
+{
+       struct i40e_virtchnl_pf_event pfe;
+
+       pfe.event = I40E_VIRTCHNL_EVENT_LINK_CHANGE;
+       pfe.severity = I40E_PF_EVENT_SEVERITY_INFO;
+       pfe.event_data.link_event.link_status =
+           pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP;
+       pfe.event_data.link_event.link_speed = pf->hw.phy.link_info.link_speed;
+
+       i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, I40E_SUCCESS,
+                            (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event));
+}
+
+/**
+ * i40e_vc_notify_reset
+ * @pf: pointer to the pf structure
+ *
+ * indicate a pending reset to all VFs on a given PF
+ **/
+void i40e_vc_notify_reset(struct i40e_pf *pf)
+{
+       struct i40e_virtchnl_pf_event pfe;
+
+       pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING;
+       pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM;
+       i40e_vc_vf_broadcast(pf, I40E_VIRTCHNL_OP_EVENT, I40E_SUCCESS,
+                            (u8 *)&pfe, sizeof(struct i40e_virtchnl_pf_event));
+}
+
+/**
+ * i40e_vc_notify_vf_reset
+ * @vf: pointer to the vf structure
+ *
+ * indicate a pending reset to the given VF
+ **/
+void i40e_vc_notify_vf_reset(struct i40e_vf *vf)
+{
+       struct i40e_virtchnl_pf_event pfe;
+
+       pfe.event = I40E_VIRTCHNL_EVENT_RESET_IMPENDING;
+       pfe.severity = I40E_PF_EVENT_SEVERITY_CERTAIN_DOOM;
+       i40e_aq_send_msg_to_vf(&vf->pf->hw, vf->vf_id, I40E_VIRTCHNL_OP_EVENT,
+                              I40E_SUCCESS, (u8 *)&pfe,
+                              sizeof(struct i40e_virtchnl_pf_event), NULL);
+}
+
+/**
+ * i40e_ndo_set_vf_mac
+ * @netdev: network interface device structure
+ * @vf_id: vf identifier
+ * @mac: mac address
+ *
+ * program vf mac address
+ **/
+int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_mac_filter *f;
+       struct i40e_vf *vf;
+       int ret = 0;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev,
+                       "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_param;
+       }
+
+       vf = &(pf->vf[vf_id]);
+       vsi = pf->vsi[vf->lan_vsi_index];
+       if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev,
+                       "Uninitialized VF %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_param;
+       }
+
+       if (!is_valid_ether_addr(mac)) {
+               dev_err(&pf->pdev->dev,
+                       "Invalid VF ethernet address\n");
+               ret = -EINVAL;
+               goto error_param;
+       }
+
+       /* delete the temporary mac address */
+       i40e_del_filter(vsi, vf->default_lan_addr.addr, 0, true, false);
+
+       /* add the new mac address */
+       f = i40e_add_filter(vsi, mac, 0, true, false);
+       if (!f) {
+               dev_err(&pf->pdev->dev,
+                       "Unable to add VF ucast filter\n");
+               ret = -ENOMEM;
+               goto error_param;
+       }
+
+       dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
+       /* program mac filter */
+       if (i40e_sync_vsi_filters(vsi)) {
+               dev_err(&pf->pdev->dev, "Unable to program ucast filters\n");
+               ret = -EIO;
+               goto error_param;
+       }
+       memcpy(vf->default_lan_addr.addr, mac, ETH_ALEN);
+       dev_info(&pf->pdev->dev, "Reload the VF driver to make this change effective.\n");
+       ret = 0;
+
+error_param:
+       return ret;
+}
+
+/**
+ * i40e_ndo_set_vf_port_vlan
+ * @netdev: network interface device structure
+ * @vf_id: vf identifier
+ * @vlan_id: mac address
+ * @qos: priority setting
+ *
+ * program vf vlan id and/or qos
+ **/
+int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
+                             int vf_id, u16 vlan_id, u8 qos)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_pf *pf = np->vsi->back;
+       struct i40e_vsi *vsi;
+       struct i40e_vf *vf;
+       int ret = 0;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_pvid;
+       }
+
+       if ((vlan_id > I40E_MAX_VLANID) || (qos > 7)) {
+               dev_err(&pf->pdev->dev, "Invalid VF Parameters\n");
+               ret = -EINVAL;
+               goto error_pvid;
+       }
+
+       vf = &(pf->vf[vf_id]);
+       vsi = pf->vsi[vf->lan_vsi_index];
+       if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_pvid;
+       }
+
+       if (vsi->info.pvid) {
+               /* kill old VLAN */
+               ret = i40e_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) &
+                                              VLAN_VID_MASK));
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "remove VLAN failed, ret=%d, aq_err=%d\n",
+                                ret, pf->hw.aq.asq_last_status);
+               }
+       }
+       if (vlan_id || qos)
+               ret = i40e_vsi_add_pvid(vsi,
+                               vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT));
+       else
+               i40e_vlan_stripping_disable(vsi);
+
+       if (vlan_id) {
+               dev_info(&pf->pdev->dev, "Setting VLAN %d, QOS 0x%x on VF %d\n",
+                        vlan_id, qos, vf_id);
+
+               /* add new VLAN filter */
+               ret = i40e_vsi_add_vlan(vsi, vlan_id);
+               if (ret) {
+                       dev_info(&vsi->back->pdev->dev,
+                                "add VF VLAN failed, ret=%d aq_err=%d\n", ret,
+                                vsi->back->hw.aq.asq_last_status);
+                       goto error_pvid;
+               }
+       }
+
+       if (ret) {
+               dev_err(&pf->pdev->dev, "Unable to update VF vsi context\n");
+               goto error_pvid;
+       }
+       ret = 0;
+
+error_pvid:
+       return ret;
+}
+
+/**
+ * i40e_ndo_set_vf_bw
+ * @netdev: network interface device structure
+ * @vf_id: vf identifier
+ * @tx_rate: tx rate
+ *
+ * configure vf tx rate
+ **/
+int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate)
+{
+       return -EOPNOTSUPP;
+}
+
+/**
+ * i40e_ndo_get_vf_config
+ * @netdev: network interface device structure
+ * @vf_id: vf identifier
+ * @ivi: vf configuration structure
+ *
+ * return vf configuration
+ **/
+int i40e_ndo_get_vf_config(struct net_device *netdev,
+                          int vf_id, struct ifla_vf_info *ivi)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_mac_filter *f, *ftmp;
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_vf *vf;
+       int ret = 0;
+
+       /* validate the request */
+       if (vf_id >= pf->num_alloc_vfs) {
+               dev_err(&pf->pdev->dev, "Invalid VF Identifier %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_param;
+       }
+
+       vf = &(pf->vf[vf_id]);
+       /* first vsi is always the LAN vsi */
+       vsi = pf->vsi[vf->lan_vsi_index];
+       if (!test_bit(I40E_VF_STAT_INIT, &vf->vf_states)) {
+               dev_err(&pf->pdev->dev, "Uninitialized VF %d\n", vf_id);
+               ret = -EINVAL;
+               goto error_param;
+       }
+
+       ivi->vf = vf_id;
+
+       /* first entry of the list is the default ethernet address */
+       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
+               memcpy(&ivi->mac, f->macaddr, I40E_ETH_LENGTH_OF_ADDRESS);
+               break;
+       }
+
+       ivi->tx_rate = 0;
+       ivi->vlan = le16_to_cpu(vsi->info.pvid) & I40E_VLAN_MASK;
+       ivi->qos = (le16_to_cpu(vsi->info.pvid) & I40E_PRIORITY_MASK) >>
+                  I40E_VLAN_PRIORITY_SHIFT;
+       ret = 0;
+
+error_param:
+       return ret;
+}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h
new file mode 100644 (file)
index 0000000..360382c
--- /dev/null
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ *
+ * Intel Ethernet Controller XL710 Family Linux Driver
+ * Copyright(c) 2013 Intel Corporation.
+ *
+ * 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.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Contact Information:
+ * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ ******************************************************************************/
+
+#ifndef _I40E_VIRTCHNL_PF_H_
+#define _I40E_VIRTCHNL_PF_H_
+
+#include "i40e.h"
+
+#define I40E_MAX_MACVLAN_FILTERS 256
+#define I40E_MAX_VLAN_FILTERS 256
+#define I40E_MAX_VLANID 4095
+
+#define I40E_VIRTCHNL_SUPPORTED_QTYPES 2
+
+#define I40E_DEFAULT_NUM_MDD_EVENTS_ALLOWED    3
+#define I40E_DEFAULT_NUM_INVALID_MSGS_ALLOWED  10
+
+#define I40E_VLAN_PRIORITY_SHIFT       12
+#define I40E_VLAN_MASK                 0xFFF
+#define I40E_PRIORITY_MASK             0x7000
+
+/* Various queue ctrls */
+enum i40e_queue_ctrl {
+       I40E_QUEUE_CTRL_UNKNOWN = 0,
+       I40E_QUEUE_CTRL_ENABLE,
+       I40E_QUEUE_CTRL_ENABLECHECK,
+       I40E_QUEUE_CTRL_DISABLE,
+       I40E_QUEUE_CTRL_DISABLECHECK,
+       I40E_QUEUE_CTRL_FASTDISABLE,
+       I40E_QUEUE_CTRL_FASTDISABLECHECK,
+};
+
+/* VF states */
+enum i40e_vf_states {
+       I40E_VF_STAT_INIT = 0,
+       I40E_VF_STAT_ACTIVE,
+       I40E_VF_STAT_FCOEENA,
+       I40E_VF_STAT_DISABLED,
+};
+
+/* VF capabilities */
+enum i40e_vf_capabilities {
+       I40E_VIRTCHNL_VF_CAP_PRIVILEGE = 0,
+       I40E_VIRTCHNL_VF_CAP_L2,
+};
+
+/* VF information structure */
+struct i40e_vf {
+       struct i40e_pf *pf;
+
+       /* vf id in the pf space */
+       u16 vf_id;
+       /* all vf vsis connect to the same parent */
+       enum i40e_switch_element_types parent_type;
+
+       /* vf Port Extender (PE) stag if used */
+       u16 stag;
+
+       struct i40e_virtchnl_ether_addr default_lan_addr;
+       struct i40e_virtchnl_ether_addr default_fcoe_addr;
+
+       /* VSI indices - actual VSI pointers are maintained in the PF structure
+        * When assigned, these will be non-zero, because VSI 0 is always
+        * the main LAN VSI for the PF.
+        */
+       u8 lan_vsi_index;       /* index into PF struct */
+       u8 lan_vsi_id;          /* ID as used by firmware */
+
+       u8 num_queue_pairs;     /* num of qps assigned to vf vsis */
+       u64 num_mdd_events;     /* num of mdd events detected */
+       u64 num_invalid_msgs;   /* num of malformed or invalid msgs detected */
+       u64 num_valid_msgs;     /* num of valid msgs detected */
+
+       unsigned long vf_caps;  /* vf's adv. capabilities */
+       unsigned long vf_states;        /* vf's runtime states */
+};
+
+void i40e_free_vfs(struct i40e_pf *pf);
+int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs);
+int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode,
+                          u32 v_retval, u8 *msg, u16 msglen);
+int i40e_vc_process_vflr_event(struct i40e_pf *pf);
+int i40e_reset_vf(struct i40e_vf *vf, bool flr);
+void i40e_vc_notify_vf_reset(struct i40e_vf *vf);
+
+/* vf configuration related iplink handlers */
+int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac);
+int i40e_ndo_set_vf_port_vlan(struct net_device *netdev,
+                             int vf_id, u16 vlan_id, u8 qos);
+int i40e_ndo_set_vf_bw(struct net_device *netdev, int vf_id, int tx_rate);
+int i40e_ndo_get_vf_config(struct net_device *netdev,
+                          int vf_id, struct ifla_vf_info *ivi);
+void i40e_vc_notify_link_state(struct i40e_pf *pf);
+void i40e_vc_notify_reset(struct i40e_pf *pf);
+
+#endif /* _I40E_VIRTCHNL_PF_H_ */
index 79b58353d849177219f4e84e05bfabd64819d44a..47c2d10df8263422d8e23169939adc84a5f3012b 100644 (file)
@@ -719,6 +719,10 @@ static s32 igb_get_phy_id_82575(struct e1000_hw *hw)
        u32 ctrl_ext;
        u32 mdic;
 
+       /* Extra read required for some PHY's on i354 */
+       if (hw->mac.type == e1000_i354)
+               igb_get_phy_id(hw);
+
        /* For SGMII PHYs, we try the list of possible addresses until
         * we find one that works.  For non-SGMII PHYs
         * (e.g. integrated copper PHYs), an address of 1 should
index f0dfd41dd4bdfff5aefff40c449fb4877f6797db..298f0ed50670c0388a53e82d3509beca6aaf351e 100644 (file)
@@ -712,6 +712,7 @@ static s32 igb_set_fc_watermarks(struct e1000_hw *hw)
 static s32 igb_set_default_fc(struct e1000_hw *hw)
 {
        s32 ret_val = 0;
+       u16 lan_offset;
        u16 nvm_data;
 
        /* Read and store word 0x0F of the EEPROM. This word contains bits
@@ -722,7 +723,14 @@ static s32 igb_set_default_fc(struct e1000_hw *hw)
         * control setting, then the variable hw->fc will
         * be initialized based on a value in the EEPROM.
         */
-       ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG, 1, &nvm_data);
+       if (hw->mac.type == e1000_i350) {
+               lan_offset = NVM_82580_LAN_FUNC_OFFSET(hw->bus.func);
+               ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG
+                                          + lan_offset, 1, &nvm_data);
+        } else {
+               ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL2_REG,
+                                          1, &nvm_data);
+        }
 
        if (ret_val) {
                hw_dbg("NVM Read Error\n");
index 0e1b973659b0a006377fc2f4e84526266cdaecff..e8649abf97c0dd93152d7037bae870eaf3532954 100644 (file)
@@ -160,6 +160,13 @@ static int ixgbe_get_settings(struct net_device *netdev,
        bool autoneg = false;
        bool link_up;
 
+       /* SFP type is needed for get_link_capabilities */
+       if (hw->phy.media_type & (ixgbe_media_type_fiber |
+                                 ixgbe_media_type_fiber_qsfp)) {
+               if (hw->phy.sfp_type == ixgbe_sfp_type_not_present)
+                               hw->phy.ops.identify_sfp(hw);
+       }
+
        hw->mac.ops.get_link_capabilities(hw, &supported_link, &autoneg);
 
        /* set the supported link speeds */
@@ -186,6 +193,11 @@ static int ixgbe_get_settings(struct net_device *netdev,
                        ecmd->advertising |= ADVERTISED_1000baseT_Full;
                if (supported_link & IXGBE_LINK_SPEED_100_FULL)
                        ecmd->advertising |= ADVERTISED_100baseT_Full;
+
+               if (hw->phy.multispeed_fiber && !autoneg) {
+                       if (supported_link & IXGBE_LINK_SPEED_10GB_FULL)
+                               ecmd->advertising = ADVERTISED_10000baseT_Full;
+               }
        }
 
        if (autoneg) {
@@ -314,6 +326,14 @@ static int ixgbe_set_settings(struct net_device *netdev,
                if (ecmd->advertising & ~ecmd->supported)
                        return -EINVAL;
 
+               /* only allow one speed at a time if no autoneg */
+               if (!ecmd->autoneg && hw->phy.multispeed_fiber) {
+                       if (ecmd->advertising ==
+                           (ADVERTISED_10000baseT_Full |
+                            ADVERTISED_1000baseT_Full))
+                               return -EINVAL;
+               }
+
                old = hw->phy.autoneg_advertised;
                advertised = 0;
                if (ecmd->advertising & ADVERTISED_10000baseT_Full)
@@ -1805,6 +1825,10 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
        unsigned int size = 1024;
        netdev_tx_t tx_ret_val;
        struct sk_buff *skb;
+       u32 flags_orig = adapter->flags;
+
+       /* DCB can modify the frames on Tx */
+       adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
 
        /* allocate test skb */
        skb = alloc_skb(size, GFP_KERNEL);
@@ -1857,6 +1881,7 @@ static int ixgbe_run_loopback_test(struct ixgbe_adapter *adapter)
 
        /* free the original skb */
        kfree_skb(skb);
+       adapter->flags = flags_orig;
 
        return ret_val;
 }
index 7aba452833e5ef94ea1137f24729d36ddcf7d029..0ade0cd5ef53ffab28b3fd34136374bfe9f4b51e 100644 (file)
@@ -3571,7 +3571,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
        int i;
-       u32 rxctrl;
+       u32 rxctrl, rfctl;
 
        /* disable receives while setting up the descriptors */
        rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
@@ -3580,6 +3580,13 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        ixgbe_setup_psrtype(adapter);
        ixgbe_setup_rdrxctl(adapter);
 
+       /* RSC Setup */
+       rfctl = IXGBE_READ_REG(hw, IXGBE_RFCTL);
+       rfctl &= ~IXGBE_RFCTL_RSC_DIS;
+       if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED))
+               rfctl |= IXGBE_RFCTL_RSC_DIS;
+       IXGBE_WRITE_REG(hw, IXGBE_RFCTL, rfctl);
+
        /* Program registers for the distribution of queues */
        ixgbe_setup_mrqc(adapter);
 
@@ -5993,8 +6000,16 @@ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter)
        adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG;
 
        speed = hw->phy.autoneg_advertised;
-       if ((!speed) && (hw->mac.ops.get_link_capabilities))
+       if ((!speed) && (hw->mac.ops.get_link_capabilities)) {
                hw->mac.ops.get_link_capabilities(hw, &speed, &autoneg);
+
+               /* setup the highest link when no autoneg */
+               if (!autoneg) {
+                       if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+                               speed = IXGBE_LINK_SPEED_10GB_FULL;
+               }
+       }
+
        if (hw->mac.ops.setup_link)
                hw->mac.ops.setup_link(hw, speed, true);
 
index 6442cf8f9dceb4fc40d25aa5bcd0b3a97631e741..10775cb9b6d84c066263c51881257bf8995e037a 100644 (file)
@@ -1861,6 +1861,7 @@ enum {
 #define IXGBE_RFCTL_ISCSI_DIS       0x00000001
 #define IXGBE_RFCTL_ISCSI_DWC_MASK  0x0000003E
 #define IXGBE_RFCTL_ISCSI_DWC_SHIFT 1
+#define IXGBE_RFCTL_RSC_DIS            0x00000020
 #define IXGBE_RFCTL_NFSW_DIS        0x00000040
 #define IXGBE_RFCTL_NFSR_DIS        0x00000080
 #define IXGBE_RFCTL_NFS_VER_MASK    0x00000300
index 270e65f21102415d554d115956644c862e02725e..a36fa80968eb1a0a42e9051b8ca2ea91ece4840c 100644 (file)
@@ -996,14 +996,14 @@ static int korina_open(struct net_device *dev)
         * that handles the Done Finished
         * Ovr and Und Events */
        ret = request_irq(lp->rx_irq, korina_rx_dma_interrupt,
-                       IRQF_DISABLED, "Korina ethernet Rx", dev);
+                       0, "Korina ethernet Rx", dev);
        if (ret < 0) {
                printk(KERN_ERR "%s: unable to get Rx DMA IRQ %d\n",
                    dev->name, lp->rx_irq);
                goto err_release;
        }
        ret = request_irq(lp->tx_irq, korina_tx_dma_interrupt,
-                       IRQF_DISABLED, "Korina ethernet Tx", dev);
+                       0, "Korina ethernet Tx", dev);
        if (ret < 0) {
                printk(KERN_ERR "%s: unable to get Tx DMA IRQ %d\n",
                    dev->name, lp->tx_irq);
@@ -1012,7 +1012,7 @@ static int korina_open(struct net_device *dev)
 
        /* Install handler for overrun error. */
        ret = request_irq(lp->ovr_irq, korina_ovr_interrupt,
-                       IRQF_DISABLED, "Ethernet Overflow", dev);
+                       0, "Ethernet Overflow", dev);
        if (ret < 0) {
                printk(KERN_ERR "%s: unable to get OVR IRQ %d\n",
                    dev->name, lp->ovr_irq);
@@ -1021,7 +1021,7 @@ static int korina_open(struct net_device *dev)
 
        /* Install handler for underflow error. */
        ret = request_irq(lp->und_irq, korina_und_interrupt,
-                       IRQF_DISABLED, "Ethernet Underflow", dev);
+                       0, "Ethernet Underflow", dev);
        if (ret < 0) {
                printk(KERN_ERR "%s: unable to get UND IRQ %d\n",
                    dev->name, lp->und_irq);
index bfdb06860397e720a848d6e8cab7b324ded6ea1c..6a6c1f76d8e04406b1c6de12820a48a7d27337fd 100644 (file)
@@ -282,8 +282,7 @@ ltq_etop_hw_init(struct net_device *dev)
 
                if (IS_TX(i)) {
                        ltq_dma_alloc_tx(&ch->dma);
-                       request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
-                               "etop_tx", priv);
+                       request_irq(irq, ltq_etop_dma_irq, 0, "etop_tx", priv);
                } else if (IS_RX(i)) {
                        ltq_dma_alloc_rx(&ch->dma);
                        for (ch->dma.desc = 0; ch->dma.desc < LTQ_DESC_NUM;
@@ -291,8 +290,7 @@ ltq_etop_hw_init(struct net_device *dev)
                                if (ltq_etop_alloc_skb(ch))
                                        return -ENOMEM;
                        ch->dma.desc = 0;
-                       request_irq(irq, ltq_etop_dma_irq, IRQF_DISABLED,
-                               "etop_rx", priv);
+                       request_irq(irq, ltq_etop_dma_irq, 0, "etop_rx", priv);
                }
                ch->dma.irq = irq;
        }
index 4ae0c74260103fb65ffe58536d58ee3a3af9e6a2..fff62460185c3ea26572a4cf7c9aa2bfe28bfb72 100644 (file)
@@ -1123,8 +1123,7 @@ static int pxa168_eth_open(struct net_device *dev)
        struct pxa168_eth_private *pep = netdev_priv(dev);
        int err;
 
-       err = request_irq(dev->irq, pxa168_eth_int_handler,
-                         IRQF_DISABLED, dev->name, dev);
+       err = request_irq(dev->irq, pxa168_eth_int_handler, 0, dev->name, dev);
        if (err) {
                dev_err(&dev->dev, "can't assign irq\n");
                return -EAGAIN;
index ef94a591f9e550ed31d654c2cc1fa2ba7bc1bef9..1a9c4f6269ea8a3422781bc14f2f7164b57ff7bf 100644 (file)
@@ -3092,6 +3092,9 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                if (!nskb)
                        goto resubmit;
 
+               skb = e->skb;
+               prefetch(skb->data);
+
                if (skge_rx_setup(skge, e, nskb, skge->rx_buf_size) < 0) {
                        dev_kfree_skb(nskb);
                        goto resubmit;
@@ -3101,8 +3104,6 @@ static struct sk_buff *skge_rx_get(struct net_device *dev,
                                 dma_unmap_addr(e, mapaddr),
                                 dma_unmap_len(e, maplen),
                                 PCI_DMA_FROMDEVICE);
-               skb = e->skb;
-               prefetch(skb->data);
        }
 
        skb_put(skb, len);
index a28cd801a236e5a674de67009a5b872ed29e9e71..0c750985f47e61f06bd402e390978800206b27f4 100644 (file)
@@ -53,9 +53,11 @@ static int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
        for (i = 0; i < priv->tx_ring_num; i++) {
                priv->tx_cq[i].moder_cnt = priv->tx_frames;
                priv->tx_cq[i].moder_time = priv->tx_usecs;
-               err = mlx4_en_set_cq_moder(priv, &priv->tx_cq[i]);
-               if (err)
-                       return err;
+               if (priv->port_up) {
+                       err = mlx4_en_set_cq_moder(priv, &priv->tx_cq[i]);
+                       if (err)
+                               return err;
+               }
        }
 
        if (priv->adaptive_rx_coal)
@@ -65,9 +67,11 @@ static int mlx4_en_moderation_update(struct mlx4_en_priv *priv)
                priv->rx_cq[i].moder_cnt = priv->rx_frames;
                priv->rx_cq[i].moder_time = priv->rx_usecs;
                priv->last_moder_time[i] = MLX4_EN_AUTO_CONF;
-               err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]);
-               if (err)
-                       return err;
+               if (priv->port_up) {
+                       err = mlx4_en_set_cq_moder(priv, &priv->rx_cq[i]);
+                       if (err)
+                               return err;
+               }
        }
 
        return err;
index 0fba1532d32646de3757896b101eec8ddba9889c..075f4e21d33df6f4f2b749dcd4aeb9fee1405077 100644 (file)
@@ -915,7 +915,7 @@ static int ks_net_open(struct net_device *netdev)
        struct ks_net *ks = netdev_priv(netdev);
        int err;
 
-#define        KS_INT_FLAGS    (IRQF_DISABLED|IRQF_TRIGGER_LOW)
+#define        KS_INT_FLAGS    IRQF_TRIGGER_LOW
        /* lock the card, even if we may not actually do anything
         * else at the moment.
         */
index c20766c2f65b91c57de2ba68ccb4d98058544059..79257f71c5d95e9daac062f111dd1ac3792885d8 100644 (file)
@@ -83,8 +83,7 @@ static int jazzsonic_open(struct net_device* dev)
 {
        int retval;
 
-       retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
-                               "sonic", dev);
+       retval = request_irq(dev->irq, sonic_interrupt, 0, "sonic", dev);
        if (retval) {
                printk(KERN_ERR "%s: unable to get IRQ %d.\n",
                                dev->name, dev->irq);
index c2e0256fe3dfb423d1ba9011d7035379e1dd3f47..4da172ac55991bd69b50037501c3fc886728dc08 100644 (file)
@@ -95,8 +95,7 @@ static int xtsonic_open(struct net_device *dev)
 {
        int retval;
 
-       retval = request_irq(dev->irq, sonic_interrupt, IRQF_DISABLED,
-                               "sonic", dev);
+       retval = request_irq(dev->irq, sonic_interrupt, 0, "sonic", dev);
        if (retval) {
                printk(KERN_ERR "%s: unable to get IRQ %d.\n",
                       dev->name, dev->irq);
index c498181a9aa823e18e9e120821254c3721bbdad3..5b65356e7568b28e0d2030c7436863db10a44b32 100644 (file)
@@ -1219,7 +1219,7 @@ static int pasemi_mac_open(struct net_device *dev)
        snprintf(mac->tx_irq_name, sizeof(mac->tx_irq_name), "%s tx",
                 dev->name);
 
-       ret = request_irq(mac->tx->chan.irq, pasemi_mac_tx_intr, IRQF_DISABLED,
+       ret = request_irq(mac->tx->chan.irq, pasemi_mac_tx_intr, 0,
                          mac->tx_irq_name, mac->tx);
        if (ret) {
                dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
@@ -1230,7 +1230,7 @@ static int pasemi_mac_open(struct net_device *dev)
        snprintf(mac->rx_irq_name, sizeof(mac->rx_irq_name), "%s rx",
                 dev->name);
 
-       ret = request_irq(mac->rx->chan.irq, pasemi_mac_rx_intr, IRQF_DISABLED,
+       ret = request_irq(mac->rx->chan.irq, pasemi_mac_rx_intr, 0,
                          mac->rx_irq_name, mac->rx);
        if (ret) {
                dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
index 88349b8fa39ad822372f6e9e2f92caceb6094643..81bf83604c4fb1c04aa0a5dfe361d1ffaefd160d 100644 (file)
@@ -430,7 +430,7 @@ struct qlcnic_hardware_context {
        u8 diag_test;
        u8 num_msix;
        u8 nic_mode;
-       char diag_cnt;
+       int diag_cnt;
 
        u16 max_uc_count;
        u16 port_type;
index 652cc13c5023ccfca09bed0978b166914e97a9a8..392b9bd12b4fb67585501f817defd1fb0194b9ca 100644 (file)
@@ -1561,6 +1561,7 @@ static int qlcnic_sriov_vf_reinit_driver(struct qlcnic_adapter *adapter)
 {
        int err;
 
+       adapter->need_fw_reset = 0;
        qlcnic_83xx_reinit_mbx_work(adapter->ahw->mailbox);
        qlcnic_83xx_enable_mbx_interrupt(adapter);
 
index 6f87f2cde647fba98bed02cc599afff911125ded..3397cee89777ba4be6c888fe9711e928ef209e06 100644 (file)
@@ -4231,6 +4231,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
        case RTL_GIGA_MAC_VER_23:
        case RTL_GIGA_MAC_VER_24:
        case RTL_GIGA_MAC_VER_34:
+       case RTL_GIGA_MAC_VER_35:
                RTL_W32(RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST);
                break;
        case RTL_GIGA_MAC_VER_40:
index 8b7152565c5e27bed528dc7ea5b2e104efd3abb1..0889212944486f9978c2c9f404bd3c87b4b5777f 100644 (file)
@@ -7,7 +7,7 @@ config SFC
        select I2C_ALGOBIT
        select PTP_1588_CLOCK
        ---help---
-         This driver supports 10-gigabit Ethernet cards based on
+         This driver supports 10/40-gigabit Ethernet cards based on
          the Solarflare SFC4000, SFC9000-family and SFC9100-family
          controllers.
 
index 5f42313b4965a3013f5e28c907895783aa5206cb..9f18ae984f9ed38386b16e5284d4d10864687c4b 100644 (file)
@@ -94,7 +94,7 @@ static unsigned int efx_ef10_mem_map_size(struct efx_nic *efx)
        return resource_size(&efx->pci_dev->resource[EFX_MEM_BAR]);
 }
 
-static int efx_ef10_init_capabilities(struct efx_nic *efx)
+static int efx_ef10_init_datapath_caps(struct efx_nic *efx)
 {
        MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_CAPABILITIES_OUT_LEN);
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
@@ -107,16 +107,27 @@ static int efx_ef10_init_capabilities(struct efx_nic *efx)
                          outbuf, sizeof(outbuf), &outlen);
        if (rc)
                return rc;
+       if (outlen < sizeof(outbuf)) {
+               netif_err(efx, drv, efx->net_dev,
+                         "unable to read datapath firmware capabilities\n");
+               return -EIO;
+       }
 
-       if (outlen >= sizeof(outbuf)) {
-               nic_data->datapath_caps =
-                       MCDI_DWORD(outbuf, GET_CAPABILITIES_OUT_FLAGS1);
-               if (!(nic_data->datapath_caps &
-                    (1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN))) {
-                       netif_err(efx, drv, efx->net_dev,
-                                 "Capabilities don't indicate TSO support.\n");
-                       return -ENODEV;
-               }
+       nic_data->datapath_caps =
+               MCDI_DWORD(outbuf, GET_CAPABILITIES_OUT_FLAGS1);
+
+       if (!(nic_data->datapath_caps &
+             (1 << MC_CMD_GET_CAPABILITIES_OUT_TX_TSO_LBN))) {
+               netif_err(efx, drv, efx->net_dev,
+                         "current firmware does not support TSO\n");
+               return -ENODEV;
+       }
+
+       if (!(nic_data->datapath_caps &
+             (1 << MC_CMD_GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14_LBN))) {
+               netif_err(efx, probe, efx->net_dev,
+                         "current firmware does not support an RX prefix\n");
+               return -ENODEV;
        }
 
        return 0;
@@ -217,21 +228,13 @@ static int efx_ef10_probe(struct efx_nic *efx)
        if (rc)
                goto fail3;
 
-       rc = efx_ef10_init_capabilities(efx);
+       rc = efx_ef10_init_datapath_caps(efx);
        if (rc < 0)
                goto fail3;
 
        efx->rx_packet_len_offset =
                ES_DZ_RX_PREFIX_PKTLEN_OFST - ES_DZ_RX_PREFIX_SIZE;
 
-       if (!(nic_data->datapath_caps &
-             (1 << MC_CMD_GET_CAPABILITIES_OUT_RX_PREFIX_LEN_14_LBN))) {
-               netif_err(efx, probe, efx->net_dev,
-                         "current firmware does not support an RX prefix\n");
-               rc = -ENODEV;
-               goto fail3;
-       }
-
        rc = efx_mcdi_port_get_number(efx);
        if (rc < 0)
                goto fail3;
@@ -260,8 +263,6 @@ static int efx_ef10_probe(struct efx_nic *efx)
        if (rc)
                goto fail3;
 
-       efx_ptp_probe(efx);
-
        return 0;
 
 fail3:
@@ -342,6 +343,13 @@ static int efx_ef10_init_nic(struct efx_nic *efx)
        struct efx_ef10_nic_data *nic_data = efx->nic_data;
        int rc;
 
+       if (nic_data->must_check_datapath_caps) {
+               rc = efx_ef10_init_datapath_caps(efx);
+               if (rc)
+                       return rc;
+               nic_data->must_check_datapath_caps = false;
+       }
+
        if (nic_data->must_realloc_vis) {
                /* We cannot let the number of VIs change now */
                rc = efx_ef10_alloc_vis(efx, nic_data->n_allocated_vis,
@@ -710,6 +718,14 @@ static int efx_ef10_mcdi_poll_reboot(struct efx_nic *efx)
        nic_data->must_restore_filters = true;
        nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID;
 
+       /* The datapath firmware might have been changed */
+       nic_data->must_check_datapath_caps = true;
+
+       /* MAC statistics have been cleared on the NIC; clear the local
+        * statistic that we update with efx_update_diff_stat().
+        */
+       nic_data->stats[EF10_STAT_rx_bad_bytes] = 0;
+
        return -EIO;
 }
 
index 8d33da6697fbef6fefa40955d8fb01231b3c9c79..7b6be61d549fd57f81d1d7a31b6ef374d0f5acfb 100644 (file)
@@ -556,6 +556,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec
                case 100:   caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN;   break;
                case 1000:  caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN;  break;
                case 10000: caps = 1 << MC_CMD_PHY_CAP_10000FDX_LBN; break;
+               case 40000: caps = 1 << MC_CMD_PHY_CAP_40000FDX_LBN; break;
                default:    return -EINVAL;
                }
        } else {
@@ -841,6 +842,7 @@ static unsigned int efx_mcdi_event_link_speed[] = {
        [MCDI_EVENT_LINKCHANGE_SPEED_100M] = 100,
        [MCDI_EVENT_LINKCHANGE_SPEED_1G] = 1000,
        [MCDI_EVENT_LINKCHANGE_SPEED_10G] = 10000,
+       [MCDI_EVENT_LINKCHANGE_SPEED_40G] = 40000,
 };
 
 void efx_mcdi_process_link_change(struct efx_nic *efx, efx_qword_t *ev)
index 4b1e188f7a2fc51a640bc03f79752428867ad33b..fda29d39032f422d2c395a4fe68a4c5091654006 100644 (file)
@@ -400,6 +400,8 @@ enum {
  * @rx_rss_context: Firmware handle for our RSS context
  * @stats: Hardware statistics
  * @workaround_35388: Flag: firmware supports workaround for bug 35388
+ * @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated
+ *     after MC reboot
  * @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of
  *     %MC_CMD_GET_CAPABILITIES response)
  */
@@ -413,6 +415,7 @@ struct efx_ef10_nic_data {
        u32 rx_rss_context;
        u64 stats[EF10_STAT_COUNT];
        bool workaround_35388;
+       bool must_check_datapath_caps;
        u32 datapath_caps;
 };
 
index 370e13dde115a31a1bd4feba15d1c264b8fcdbef..5730fe2445a6c1acf5dfa5cd8767d1b1bb749734 100644 (file)
@@ -271,7 +271,7 @@ static inline void mcf_outsw(void *a, unsigned char *p, int l)
 #define SMC_insw(a, r, p, l)   mcf_insw(a + r, p, l)
 #define SMC_outsw(a, r, p, l)  mcf_outsw(a + r, p, l)
 
-#define SMC_IRQ_FLAGS          (IRQF_DISABLED)
+#define SMC_IRQ_FLAGS          0
 
 #else
 
index ffa5c4ad12105a2050d264d4deac90080f7e4c9d..5f9e79f7f2df52f8b6a3c1955bd7e99ba4bbb122 100644 (file)
@@ -1356,8 +1356,7 @@ static int smsc9420_open(struct net_device *dev)
        smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF);
        smsc9420_pci_flush_write(pd);
 
-       result = request_irq(irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED,
-                            DRV_NAME, pd);
+       result = request_irq(irq, smsc9420_isr, IRQF_SHARED, DRV_NAME, pd);
        if (result) {
                smsc_warn(IFUP, "Unable to use IRQ = %d", irq);
                result = -ENODEV;
index 949076f4e6ae180ae78f83b68973b8486b4087bd..13e6fff8ca23af28e4b1e2229846522082dd60c4 100644 (file)
@@ -1734,7 +1734,8 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
        unsigned int data_len = skb->len - sh_len;
        unsigned char *data = skb->data;
        unsigned int ih_off, th_off, p_len;
-       unsigned int isum_seed, tsum_seed, id, seq;
+       unsigned int isum_seed, tsum_seed, seq;
+       unsigned int uninitialized_var(id);
        int is_ipv6;
        long f_id = -1;    /* id of the current fragment */
        long f_size = skb_headlen(skb) - sh_len;  /* current fragment size */
@@ -1781,7 +1782,7 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
                } else {
                        ih = (struct iphdr *)(buf + ih_off);
                        ih->tot_len = htons(sh_len + p_len - ih_off);
-                       ih->id = htons(id);
+                       ih->id = htons(id++);
                        ih->check = csum_long(isum_seed + ih->tot_len +
                                              ih->id) ^ 0xffff;
                }
@@ -1818,7 +1819,6 @@ static void tso_headers_prepare(struct sk_buff *skb, unsigned char *headers,
                        slot++;
                }
 
-               id++;
                seq += p_len;
 
                /* The last segment may be less than gso_size. */
index 9c805e0c0cae87bd81bb305a6c51cb3c58b479e1..f7f2ef49c0c1cbbe4756c805797bedb71cc6495f 100644 (file)
@@ -1726,7 +1726,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev)
                goto fail_alloc_irq;
        }
        result = request_irq(card->irq, gelic_card_interrupt,
-                            IRQF_DISABLED, netdev->name, card);
+                            0, netdev->name, card);
 
        if (result) {
                dev_info(ctodev(card), "%s:request_irq failed (%d)\n",
index 510b9c8d23a9ea57066edc14e7ab307b0c9dce22..31bcb98ef35609b9f0be24cfc63bcd4fd43ae852 100644 (file)
@@ -1488,7 +1488,7 @@ static void
 toshoboe_close (struct pci_dev *pci_dev)
 {
   int i;
-  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
 
   IRDA_DEBUG (4, "%s()\n", __func__);
 
@@ -1696,7 +1696,7 @@ freeself:
 static int
 toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap)
 {
-  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
   unsigned long flags;
   int i = 10;
 
@@ -1725,7 +1725,7 @@ toshoboe_gotosleep (struct pci_dev *pci_dev, pm_message_t crap)
 static int
 toshoboe_wakeup (struct pci_dev *pci_dev)
 {
-  struct toshoboe_cb *self = (struct toshoboe_cb*)pci_get_drvdata(pci_dev);
+  struct toshoboe_cb *self = pci_get_drvdata(pci_dev);
   unsigned long flags;
 
   IRDA_DEBUG (4, "%s()\n", __func__);
index f07c340990da570303a25a0e44cbf7ca4b21efa8..3f138ca88670ce608731cdcd4d636bc87d3a2cac 100644 (file)
@@ -191,8 +191,8 @@ static inline int mcs_setup_transceiver_vishay(struct mcs_cb *mcs)
                goto error;
 
        ret = 0;
-       error:
-               return ret;
+error:
+       return ret;
 }
 
 /* Setup a communication between mcs7780 and agilent chip. */
@@ -501,8 +501,11 @@ static inline int mcs_setup_urbs(struct mcs_cb *mcs)
                return 0;
 
        mcs->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!mcs->rx_urb)
+       if (!mcs->rx_urb) {
+               usb_free_urb(mcs->tx_urb);
+               mcs->tx_urb = NULL;
                return 0;
+       }
 
        return 1;
 }
@@ -643,9 +646,9 @@ static int mcs_speed_change(struct mcs_cb *mcs)
        ret = mcs_set_reg(mcs, MCS_MODE_REG, rval);
 
        mcs->speed = mcs->new_speed;
-       error:
-               mcs->new_speed = 0;
-               return ret;
+error:
+       mcs->new_speed = 0;
+       return ret;
 }
 
 /* Ioctl calls not supported at this time.  Can be an area of future work. */
@@ -738,17 +741,20 @@ static int mcs_net_open(struct net_device *netdev)
 
        ret = mcs_receive_start(mcs);
        if (ret)
-               goto error3;
+               goto error4;
 
        netif_start_queue(netdev);
        return 0;
 
-       error3:
-               irlap_close(mcs->irlap);
-       error2:
-               kfree_skb(mcs->rx_buff.skb);
-       error1:
-               return ret;
+error4:
+       usb_free_urb(mcs->rx_urb);
+       usb_free_urb(mcs->tx_urb);
+error3:
+       irlap_close(mcs->irlap);
+error2:
+       kfree_skb(mcs->rx_buff.skb);
+error1:
+       return ret;
 }
 
 /* Receive callback function.  */
@@ -946,11 +952,11 @@ static int mcs_probe(struct usb_interface *intf,
        usb_set_intfdata(intf, mcs);
        return 0;
 
-       error2:
-               free_netdev(ndev);
+error2:
+       free_netdev(ndev);
 
-       error1:
-               return ret;
+error1:
+       return ret;
 }
 
 /* The current device is removed, the USB layer tells us to shut down. */
index 5f4758492e4c0ca1efb1b7e4c4ab063ba98bf7aa..c5bd58b4d8a82a61ad2a87a3f854f7d6b033e803 100644 (file)
@@ -543,7 +543,7 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd)
        int             crclen, len = 0;
        struct sk_buff  *skb;
        int             ret = 0;
-       struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev);
+       struct net_device *ndev = pci_get_drvdata(r->pdev);
        vlsi_irda_dev_t *idev = netdev_priv(ndev);
 
        pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir);
index fcbf680c3e62f73af4933896641045de34f1f68c..a17d85a331f1ade54f9ec1834f1e8ee1c67d9b9d 100644 (file)
@@ -146,6 +146,7 @@ static int loopback_dev_init(struct net_device *dev)
 
 static void loopback_dev_free(struct net_device *dev)
 {
+       dev_net(dev)->loopback_dev = NULL;
        free_percpu(dev->lstats);
        free_netdev(dev);
 }
index 64dfaa303dcc943f34286604b080cd657895cbc7..9bf46bd19b87bf947fd79e547bdde626c8a12097 100644 (file)
@@ -118,8 +118,6 @@ static int macvlan_broadcast_one(struct sk_buff *skb,
                                 const struct ethhdr *eth, bool local)
 {
        struct net_device *dev = vlan->dev;
-       if (!skb)
-               return NET_RX_DROP;
 
        if (local)
                return vlan->forward(dev, skb);
@@ -171,9 +169,13 @@ static void macvlan_broadcast(struct sk_buff *skb,
                        hash = mc_hash(vlan, eth->h_dest);
                        if (!test_bit(hash, vlan->mc_filter))
                                continue;
+
+                       err = NET_RX_DROP;
                        nskb = skb_clone(skb, GFP_ATOMIC);
-                       err = macvlan_broadcast_one(nskb, vlan, eth,
-                                        mode == MACVLAN_MODE_BRIDGE);
+                       if (likely(nskb))
+                               err = macvlan_broadcast_one(
+                                       nskb, vlan, eth,
+                                       mode == MACVLAN_MODE_BRIDGE);
                        macvlan_count_rx(vlan, skb->len + ETH_HLEN,
                                         err == NET_RX_SUCCESS, 1);
                }
index dcb21347c67044da535903f2f88ba36f2529f347..adeee615dd19f4e0d7c6288466798781a1f8bda7 100644 (file)
@@ -684,15 +684,12 @@ restart:
                        case NETDEV_RELEASE:
                        case NETDEV_JOIN:
                        case NETDEV_UNREGISTER:
-                               /*
-                                * rtnl_lock already held
+                               /* rtnl_lock already held
                                 * we might sleep in __netpoll_cleanup()
                                 */
                                spin_unlock_irqrestore(&target_list_lock, flags);
 
-                               mutex_lock(&nt->mutex);
                                __netpoll_cleanup(&nt->np);
-                               mutex_unlock(&nt->mutex);
 
                                spin_lock_irqsave(&target_list_lock, flags);
                                dev_put(nt->np.dev);
index db472ffb6e89ed269f11e09fc032c8b9a714f03c..313a0377f68fc98f244ab145c7823ce3bf9ddaed 100644 (file)
@@ -30,9 +30,9 @@
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/irq.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 /* Cicada Extended Control Register 1 */
 #define MII_CIS8201_EXT_CON1           0x17
index 6fa5ae00039fd65b2c634d0d22241d9c7a9d13e2..01805319e1e0335a70f86109e058cac44d669ee0 100644 (file)
@@ -281,7 +281,7 @@ static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
        nf_reset(skb);
 
        skb->ip_summed = CHECKSUM_NONE;
-       ip_select_ident(iph, &rt->dst, NULL);
+       ip_select_ident(skb, &rt->dst, NULL);
        ip_send_check(iph);
 
        ip_local_out(skb);
index a639de8401f8741ce7325b5261fe9c42ee377be7..807815fc996839d14efd18625fb300a2f48d2577 100644 (file)
@@ -1641,11 +1641,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
                INIT_LIST_HEAD(&tun->disabled);
                err = tun_attach(tun, file, false);
                if (err < 0)
-                       goto err_free_dev;
+                       goto err_free_flow;
 
                err = register_netdevice(tun->dev);
                if (err < 0)
-                       goto err_free_dev;
+                       goto err_detach;
 
                if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) ||
                    device_create_file(&tun->dev->dev, &dev_attr_owner) ||
@@ -1689,7 +1689,12 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
        strcpy(ifr->ifr_name, tun->dev->name);
        return 0;
 
- err_free_dev:
+err_detach:
+       tun_detach_all(dev);
+err_free_flow:
+       tun_flow_uninit(tun);
+       security_tun_dev_free_security(tun->security);
+err_free_dev:
        free_netdev(dev);
        return err;
 }
index 03ad4dc293aa2a468f8a93f0a0d045623507a9a0..2023f3ea891e6bf75f0c62d3d78213e30d1a11f4 100644 (file)
@@ -33,7 +33,7 @@
 #include <linux/usb/usbnet.h>
 
 
-#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+#if IS_ENABLED(CONFIG_USB_NET_RNDIS_HOST)
 
 static int is_rndis(struct usb_interface_descriptor *desc)
 {
@@ -69,8 +69,7 @@ static const u8 mbm_guid[16] = {
        0xa6, 0x07, 0xc0, 0xff, 0xcb, 0x7e, 0x39, 0x2a,
 };
 
-/*
- * probes control interface, claims data interface, collects the bulk
+/* probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
  * all pure cdc, except for certain firmware workarounds, and knowing
  * that rndis uses one different rule.
@@ -88,7 +87,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
        struct usb_cdc_mdlm_desc        *desc = NULL;
        struct usb_cdc_mdlm_detail_desc *detail = NULL;
 
-       if (sizeof dev->data < sizeof *info)
+       if (sizeof(dev->data) < sizeof(*info))
                return -EDOM;
 
        /* expect strict spec conformance for the descriptors, but
@@ -126,10 +125,10 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                 is_activesync(&intf->cur_altsetting->desc) ||
                 is_wireless_rndis(&intf->cur_altsetting->desc));
 
-       memset(info, 0, sizeof *info);
+       memset(info, 0, sizeof(*info));
        info->control = intf;
        while (len > 3) {
-               if (buf [1] != USB_DT_CS_INTERFACE)
+               if (buf[1] != USB_DT_CS_INTERFACE)
                        goto next_desc;
 
                /* use bDescriptorSubType to identify the CDC descriptors.
@@ -139,14 +138,14 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                 * in favor of a complicated OID-based RPC scheme doing what
                 * CDC Ethernet achieves with a simple descriptor.
                 */
-               switch (buf [2]) {
+               switch (buf[2]) {
                case USB_CDC_HEADER_TYPE:
                        if (info->header) {
                                dev_dbg(&intf->dev, "extra CDC header\n");
                                goto bad_desc;
                        }
                        info->header = (void *) buf;
-                       if (info->header->bLength != sizeof *info->header) {
+                       if (info->header->bLength != sizeof(*info->header)) {
                                dev_dbg(&intf->dev, "CDC header len %u\n",
                                        info->header->bLength);
                                goto bad_desc;
@@ -175,7 +174,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                goto bad_desc;
                        }
                        info->u = (void *) buf;
-                       if (info->u->bLength != sizeof *info->u) {
+                       if (info->u->bLength != sizeof(*info->u)) {
                                dev_dbg(&intf->dev, "CDC union len %u\n",
                                        info->u->bLength);
                                goto bad_desc;
@@ -233,7 +232,7 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                goto bad_desc;
                        }
                        info->ether = (void *) buf;
-                       if (info->ether->bLength != sizeof *info->ether) {
+                       if (info->ether->bLength != sizeof(*info->ether)) {
                                dev_dbg(&intf->dev, "CDC ether len %u\n",
                                        info->ether->bLength);
                                goto bad_desc;
@@ -274,8 +273,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                        break;
                }
 next_desc:
-               len -= buf [0]; /* bLength */
-               buf += buf [0];
+               len -= buf[0];  /* bLength */
+               buf += buf[0];
        }
 
        /* Microsoft ActiveSync based and some regular RNDIS devices lack the
@@ -379,9 +378,7 @@ void usbnet_cdc_unbind(struct usbnet *dev, struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
 
-/*-------------------------------------------------------------------------
- *
- * Communications Device Class, Ethernet Control model
+/* Communications Device Class, Ethernet Control model
  *
  * Takes two interfaces.  The DATA interface is inactive till an altsetting
  * is selected.  Configuration data includes class descriptors.  There's
@@ -389,8 +386,7 @@ EXPORT_SYMBOL_GPL(usbnet_cdc_unbind);
  *
  * This should interop with whatever the 2.4 "CDCEther.c" driver
  * (by Brad Hards) talked with, with more functionality.
- *
- *-------------------------------------------------------------------------*/
+ */
 
 static void dumpspeed(struct usbnet *dev, __le32 *speeds)
 {
@@ -404,7 +400,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
 {
        struct usb_cdc_notification     *event;
 
-       if (urb->actual_length < sizeof *event)
+       if (urb->actual_length < sizeof(*event))
                return;
 
        /* SPEED_CHANGE can get split into two 8-byte packets */
@@ -423,7 +419,7 @@ void usbnet_cdc_status(struct usbnet *dev, struct urb *urb)
        case USB_CDC_NOTIFY_SPEED_CHANGE:       /* tx/rx rates */
                netif_dbg(dev, timer, dev->net, "CDC: speed change (len %d)\n",
                          urb->actual_length);
-               if (urb->actual_length != (sizeof *event + 8))
+               if (urb->actual_length != (sizeof(*event) + 8))
                        set_bit(EVENT_STS_SPLIT, &dev->flags);
                else
                        dumpspeed(dev, (__le32 *) &event[1]);
@@ -469,7 +465,6 @@ EXPORT_SYMBOL_GPL(usbnet_cdc_bind);
 static const struct driver_info        cdc_info = {
        .description =  "CDC Ethernet Device",
        .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
-       // .check_connect = cdc_check_connect,
        .bind =         usbnet_cdc_bind,
        .unbind =       usbnet_cdc_unbind,
        .status =       usbnet_cdc_status,
@@ -493,9 +488,8 @@ static const struct driver_info wwan_info = {
 #define DELL_VENDOR_ID         0x413C
 #define REALTEK_VENDOR_ID      0x0bda
 
-static const struct usb_device_id      products [] = {
-/*
- * BLACKLIST !!
+static const struct usb_device_id      products[] = {
+/* BLACKLIST !!
  *
  * First blacklist any products that are egregiously nonconformant
  * with the CDC Ethernet specs.  Minor braindamage we cope with; when
@@ -542,7 +536,7 @@ static const struct usb_device_id   products [] = {
        .driver_info            = 0,
 }, {
        .match_flags    =   USB_DEVICE_ID_MATCH_INT_INFO
-                 | USB_DEVICE_ID_MATCH_DEVICE,
+                         | USB_DEVICE_ID_MATCH_DEVICE,
        .idVendor               = 0x04DD,
        .idProduct              = 0x8007,       /* C-700 */
        ZAURUS_MASTER_INTERFACE,
@@ -659,8 +653,7 @@ static const struct usb_device_id   products [] = {
        .driver_info = 0,
 },
 
-/*
- * WHITELIST!!!
+/* WHITELIST!!!
  *
  * CDC Ether uses two interfaces, not necessarily consecutive.
  * We match the main interface, ignoring the optional device
@@ -672,59 +665,39 @@ static const struct usb_device_id products [] = {
  */
 {
        /* ZTE (Vodafone) K3805-Z */
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = ZTE_VENDOR_ID,
-       .idProduct              = 0x1003,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1003, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
 }, {
        /* ZTE (Vodafone) K3806-Z */
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = ZTE_VENDOR_ID,
-       .idProduct              = 0x1015,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1015, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
 }, {
        /* ZTE (Vodafone) K4510-Z */
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = ZTE_VENDOR_ID,
-       .idProduct              = 0x1173,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1173, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
 }, {
        /* ZTE (Vodafone) K3770-Z */
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = ZTE_VENDOR_ID,
-       .idProduct              = 0x1177,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1177, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
 }, {
        /* ZTE (Vodafone) K3772-Z */
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_PRODUCT
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = ZTE_VENDOR_ID,
-       .idProduct              = 0x1181,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = USB_CDC_PROTO_NONE,
+       USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1181, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET,
+                                     USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long)&wwan_info,
+}, {
+       /* Telit modules */
+       USB_VENDOR_AND_INTERFACE_INFO(0x1bc7, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+       .driver_info = (kernel_ulong_t) &wwan_info,
 }, {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
                        USB_CDC_PROTO_NONE),
@@ -736,15 +709,11 @@ static const struct usb_device_id products [] = {
 
 }, {
        /* Various Huawei modems with a network port like the UMG1831 */
-       .match_flags    =   USB_DEVICE_ID_MATCH_VENDOR
-                | USB_DEVICE_ID_MATCH_INT_INFO,
-       .idVendor               = HUAWEI_VENDOR_ID,
-       .bInterfaceClass        = USB_CLASS_COMM,
-       .bInterfaceSubClass     = USB_CDC_SUBCLASS_ETHERNET,
-       .bInterfaceProtocol     = 255,
+       USB_VENDOR_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, USB_CLASS_COMM,
+                                     USB_CDC_SUBCLASS_ETHERNET, 255),
        .driver_info = (unsigned long)&wwan_info,
 },
-       { },            // END
+       { },            /* END */
 };
 MODULE_DEVICE_TABLE(usb, products);
 
index 3a8131582e753074c5fa0e3b9df2cab76f0face6..6312332afeba283f192cfbf0b9ca07dfbb1e52ec 100644 (file)
@@ -518,6 +518,135 @@ static const struct usb_device_id products[] = {
 
        /* 3. Combined interface devices matching on interface number */
        {QMI_FIXED_INTF(0x0408, 0xea42, 4)},    /* Yota / Megafon M100-1 */
+       {QMI_FIXED_INTF(0x05c6, 0x7000, 0)},
+       {QMI_FIXED_INTF(0x05c6, 0x7001, 1)},
+       {QMI_FIXED_INTF(0x05c6, 0x7002, 1)},
+       {QMI_FIXED_INTF(0x05c6, 0x7101, 1)},
+       {QMI_FIXED_INTF(0x05c6, 0x7101, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x7101, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x7102, 1)},
+       {QMI_FIXED_INTF(0x05c6, 0x7102, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x7102, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x8000, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x8001, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9000, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9003, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9005, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x900a, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x900b, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x900c, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x900c, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x900c, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x900d, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x900f, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x900f, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x900f, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9010, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9010, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9011, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9011, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9021, 1)},
+       {QMI_FIXED_INTF(0x05c6, 0x9022, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x9025, 4)},    /* Alcatel-sbell ASB TL131 TDD LTE  (China Mobile) */
+       {QMI_FIXED_INTF(0x05c6, 0x9026, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x902e, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9031, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9032, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9033, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9033, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9033, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9033, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9034, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9034, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9034, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9034, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9034, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9035, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9036, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9037, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9038, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x903b, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x903c, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x903d, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x903e, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9043, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9046, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9046, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9046, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9047, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x9047, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9047, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9048, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9048, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9048, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9048, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9048, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x904c, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x904c, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x904c, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x904c, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x9050, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9052, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9053, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9053, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9054, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9054, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9055, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9055, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9055, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9055, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9055, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9056, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x9062, 9)},
+       {QMI_FIXED_INTF(0x05c6, 0x9064, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9065, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9065, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9066, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9066, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9067, 1)},
+       {QMI_FIXED_INTF(0x05c6, 0x9068, 2)},
+       {QMI_FIXED_INTF(0x05c6, 0x9068, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9068, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9068, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9068, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9068, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9069, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9069, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9069, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9069, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x9070, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9070, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9075, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9076, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9076, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9076, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9076, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9076, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x9077, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9077, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9077, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9077, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9078, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9079, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x9079, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9079, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9079, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9079, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x9080, 5)},
+       {QMI_FIXED_INTF(0x05c6, 0x9080, 6)},
+       {QMI_FIXED_INTF(0x05c6, 0x9080, 7)},
+       {QMI_FIXED_INTF(0x05c6, 0x9080, 8)},
+       {QMI_FIXED_INTF(0x05c6, 0x9083, 3)},
+       {QMI_FIXED_INTF(0x05c6, 0x9084, 4)},
+       {QMI_FIXED_INTF(0x05c6, 0x920d, 0)},
+       {QMI_FIXED_INTF(0x05c6, 0x920d, 5)},
        {QMI_FIXED_INTF(0x12d1, 0x140c, 1)},    /* Huawei E173 */
        {QMI_FIXED_INTF(0x12d1, 0x14ac, 1)},    /* Huawei E1820 */
        {QMI_FIXED_INTF(0x19d2, 0x0002, 1)},
@@ -612,7 +741,6 @@ static const struct usb_device_id products[] = {
        {QMI_GOBI_DEVICE(0x413c, 0x8186)},      /* Dell Gobi 2000 Modem device (N0218, VU936) */
        {QMI_GOBI_DEVICE(0x413c, 0x8194)},      /* Dell Gobi 3000 Composite */
        {QMI_GOBI_DEVICE(0x05c6, 0x920b)},      /* Generic Gobi 2000 Modem device */
-       {QMI_GOBI_DEVICE(0x05c6, 0x920d)},      /* Gobi 3000 Composite */
        {QMI_GOBI_DEVICE(0x05c6, 0x9225)},      /* Sony Gobi 2000 Modem device (N0279, VU730) */
        {QMI_GOBI_DEVICE(0x05c6, 0x9245)},      /* Samsung Gobi 2000 Modem device (VL176) */
        {QMI_GOBI_DEVICE(0x03f0, 0x251d)},      /* HP Gobi 2000 Modem device (VP412) */
index bf64b4191dcc379f8d0c3d9ec287bb998efa6a69..d1292fe746bc2eb3962a57df299e49f7f9bc2d50 100644 (file)
@@ -564,7 +564,7 @@ static void vxlan_notify_add_rx_port(struct sock *sk)
        struct net_device *dev;
        struct net *net = sock_net(sk);
        sa_family_t sa_family = sk->sk_family;
-       u16 port = htons(inet_sk(sk)->inet_sport);
+       __be16 port = inet_sk(sk)->inet_sport;
 
        rcu_read_lock();
        for_each_netdev_rcu(net, dev) {
@@ -581,7 +581,7 @@ static void vxlan_notify_del_rx_port(struct sock *sk)
        struct net_device *dev;
        struct net *net = sock_net(sk);
        sa_family_t sa_family = sk->sk_family;
-       u16 port = htons(inet_sk(sk)->inet_sport);
+       __be16 port = inet_sk(sk)->inet_sport;
 
        rcu_read_lock();
        for_each_netdev_rcu(net, dev) {
@@ -2021,7 +2021,8 @@ static struct device_type vxlan_type = {
 };
 
 /* Calls the ndo_add_vxlan_port of the caller in order to
- * supply the listening VXLAN udp ports.
+ * supply the listening VXLAN udp ports. Callers are expected
+ * to implement the ndo_add_vxlan_port.
  */
 void vxlan_get_rx_port(struct net_device *dev)
 {
@@ -2029,16 +2030,13 @@ void vxlan_get_rx_port(struct net_device *dev)
        struct net *net = dev_net(dev);
        struct vxlan_net *vn = net_generic(net, vxlan_net_id);
        sa_family_t sa_family;
-       u16 port;
-       int i;
-
-       if (!dev || !dev->netdev_ops || !dev->netdev_ops->ndo_add_vxlan_port)
-               return;
+       __be16 port;
+       unsigned int i;
 
        spin_lock(&vn->sock_lock);
        for (i = 0; i < PORT_HASH_SIZE; ++i) {
-               hlist_for_each_entry_rcu(vs, vs_head(net, i), hlist) {
-                       port = htons(inet_sk(vs->sock->sk)->inet_sport);
+               hlist_for_each_entry_rcu(vs, &vn->sock_list[i], hlist) {
+                       port = inet_sk(vs->sock->sk)->inet_sport;
                        sa_family = vs->sock->sk->sk_family;
                        dev->netdev_ops->ndo_add_vxlan_port(dev, sa_family,
                                                            port);
@@ -2492,15 +2490,19 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
 
        SET_ETHTOOL_OPS(dev, &vxlan_ethtool_ops);
 
-       /* create an fdb entry for default destination */
-       err = vxlan_fdb_create(vxlan, all_zeros_mac,
-                              &vxlan->default_dst.remote_ip,
-                              NUD_REACHABLE|NUD_PERMANENT,
-                              NLM_F_EXCL|NLM_F_CREATE,
-                              vxlan->dst_port, vxlan->default_dst.remote_vni,
-                              vxlan->default_dst.remote_ifindex, NTF_SELF);
-       if (err)
-               return err;
+       /* create an fdb entry for a valid default destination */
+       if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) {
+               err = vxlan_fdb_create(vxlan, all_zeros_mac,
+                                      &vxlan->default_dst.remote_ip,
+                                      NUD_REACHABLE|NUD_PERMANENT,
+                                      NLM_F_EXCL|NLM_F_CREATE,
+                                      vxlan->dst_port,
+                                      vxlan->default_dst.remote_vni,
+                                      vxlan->default_dst.remote_ifindex,
+                                      NTF_SELF);
+               if (err)
+                       return err;
+       }
 
        err = register_netdevice(dev);
        if (err) {
index f9a24e599dee4c7acf9b8a5bf0a0caa2306d01e5..cfce83e1f273f0259ee07d072fd8c8f59df8e99a 100644 (file)
@@ -1924,7 +1924,6 @@ static int adm8211_probe(struct pci_dev *pdev,
        pci_iounmap(pdev, priv->map);
 
  err_free_dev:
-       pci_set_drvdata(pdev, NULL);
        ieee80211_free_hw(dev);
 
  err_free_reg:
index 7fe19648f10e8f1e966b857c12077f34025dc8b5..edf4b57c4aaa306ebbf12beea5100d6f6a7f5e2e 100644 (file)
@@ -5570,7 +5570,6 @@ static void airo_pci_remove(struct pci_dev *pdev)
        airo_print_info(dev->name, "Unregistering...");
        stop_airo_card(dev, 1);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
 }
 
 static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
index 1abf1d421173085e72a4bfa549fd147f83a87ca5..ba81d6292eebd9bd0d34033125349ca90d83bef6 100644 (file)
@@ -32,5 +32,6 @@ source "drivers/net/wireless/ath/ath6kl/Kconfig"
 source "drivers/net/wireless/ath/ar5523/Kconfig"
 source "drivers/net/wireless/ath/wil6210/Kconfig"
 source "drivers/net/wireless/ath/ath10k/Kconfig"
+source "drivers/net/wireless/ath/wcn36xx/Kconfig"
 
 endif
index fb05cfd193616ea65cecbfc489653409b173e617..363b05653c7e92682046df548819d72092845e16 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_ATH6KL)            += ath6kl/
 obj-$(CONFIG_AR5523)           += ar5523/
 obj-$(CONFIG_WIL6210)          += wil6210/
 obj-$(CONFIG_ATH10K)           += ath10k/
+obj-$(CONFIG_WCN36XX)          += wcn36xx/
 
 obj-$(CONFIG_ATH_COMMON)       += ath.o
 
index 17d7fece35d2c203eedef5fed0725074a0067cf7..280fc3d53a36466ca8a3f4ff7fd73074efc86b75 100644 (file)
@@ -1762,6 +1762,7 @@ static struct usb_device_id ar5523_id_table[] = {
        AR5523_DEVICE_UX(0x2001, 0x3a00),       /* Dlink / DWLAG132 */
        AR5523_DEVICE_UG(0x2001, 0x3a02),       /* Dlink / DWLG132 */
        AR5523_DEVICE_UX(0x2001, 0x3a04),       /* Dlink / DWLAG122 */
+       AR5523_DEVICE_UG(0x07d1, 0x3a07),       /* D-Link / WUA-2340 rev A1 */
        AR5523_DEVICE_UG(0x1690, 0x0712),       /* Gigaset / AR5523 */
        AR5523_DEVICE_UG(0x1690, 0x0710),       /* Gigaset / SMCWUSBTG */
        AR5523_DEVICE_UG(0x129b, 0x160c),       /* Gigaset / USB stick 108
index 744da6d1c405d91a645428d0f686c3c9cb4f00f0..a1f0996288508e3cad8ecd8e03f33153980e593e 100644 (file)
@@ -22,7 +22,8 @@
 
 void ath10k_bmi_start(struct ath10k *ar)
 {
-       ath10k_dbg(ATH10K_DBG_CORE, "BMI started\n");
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi start\n");
+
        ar->bmi.done_sent = false;
 }
 
@@ -32,8 +33,10 @@ int ath10k_bmi_done(struct ath10k *ar)
        u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi done\n");
+
        if (ar->bmi.done_sent) {
-               ath10k_dbg(ATH10K_DBG_CORE, "%s skipped\n", __func__);
+               ath10k_dbg(ATH10K_DBG_BMI, "bmi skipped\n");
                return 0;
        }
 
@@ -46,7 +49,6 @@ int ath10k_bmi_done(struct ath10k *ar)
                return ret;
        }
 
-       ath10k_dbg(ATH10K_DBG_CORE, "BMI done\n");
        return 0;
 }
 
@@ -59,6 +61,8 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
        u32 resplen = sizeof(resp.get_target_info);
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi get target info\n");
+
        if (ar->bmi.done_sent) {
                ath10k_warn("BMI Get Target Info Command disallowed\n");
                return -EBUSY;
@@ -80,6 +84,7 @@ int ath10k_bmi_get_target_info(struct ath10k *ar,
 
        target_info->version = __le32_to_cpu(resp.get_target_info.version);
        target_info->type    = __le32_to_cpu(resp.get_target_info.type);
+
        return 0;
 }
 
@@ -92,15 +97,14 @@ int ath10k_bmi_read_memory(struct ath10k *ar,
        u32 rxlen;
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
+                  address, length);
+
        if (ar->bmi.done_sent) {
                ath10k_warn("command disallowed\n");
                return -EBUSY;
        }
 
-       ath10k_dbg(ATH10K_DBG_CORE,
-                  "%s: (device: 0x%p, address: 0x%x, length: %d)\n",
-                  __func__, ar, address, length);
-
        while (length) {
                rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
 
@@ -133,15 +137,14 @@ int ath10k_bmi_write_memory(struct ath10k *ar,
        u32 txlen;
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
+                  address, length);
+
        if (ar->bmi.done_sent) {
                ath10k_warn("command disallowed\n");
                return -EBUSY;
        }
 
-       ath10k_dbg(ATH10K_DBG_CORE,
-                  "%s: (device: 0x%p, address: 0x%x, length: %d)\n",
-                  __func__, ar, address, length);
-
        while (length) {
                txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
 
@@ -180,15 +183,14 @@ int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 *param)
        u32 resplen = sizeof(resp.execute);
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
+                  address, *param);
+
        if (ar->bmi.done_sent) {
                ath10k_warn("command disallowed\n");
                return -EBUSY;
        }
 
-       ath10k_dbg(ATH10K_DBG_CORE,
-                  "%s: (device: 0x%p, address: 0x%x, param: %d)\n",
-                  __func__, ar, address, *param);
-
        cmd.id            = __cpu_to_le32(BMI_EXECUTE);
        cmd.execute.addr  = __cpu_to_le32(address);
        cmd.execute.param = __cpu_to_le32(*param);
@@ -216,6 +218,9 @@ int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
        u32 txlen;
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi lz data buffer 0x%p length %d\n",
+                  buffer, length);
+
        if (ar->bmi.done_sent) {
                ath10k_warn("command disallowed\n");
                return -EBUSY;
@@ -250,6 +255,9 @@ int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
        u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
+                  address);
+
        if (ar->bmi.done_sent) {
                ath10k_warn("command disallowed\n");
                return -EBUSY;
@@ -275,6 +283,10 @@ int ath10k_bmi_fast_download(struct ath10k *ar,
        u32 trailer_len = length - head_len;
        int ret;
 
+       ath10k_dbg(ATH10K_DBG_BMI,
+                  "bmi fast download address 0x%x buffer 0x%p length %d\n",
+                  address, buffer, length);
+
        ret = ath10k_bmi_lz_stream_start(ar, address);
        if (ret)
                return ret;
index f8b969f518f84ecee55c4e38f5d5f8247d501cf0..834e29ea236c5a9c78f195ff589801d15f998950 100644 (file)
@@ -76,36 +76,7 @@ static inline void ath10k_ce_src_ring_write_index_set(struct ath10k *ar,
                                                      u32 ce_ctrl_addr,
                                                      unsigned int n)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       void __iomem *indicator_addr;
-
-       if (!test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
-               ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);
-               return;
-       }
-
-       /* workaround for QCA988x_1.0 HW CE */
-       indicator_addr = ar_pci->mem + ce_ctrl_addr + DST_WATERMARK_ADDRESS;
-
-       if (ce_ctrl_addr == ath10k_ce_base_address(CDC_WAR_DATA_CE)) {
-               iowrite32((CDC_WAR_MAGIC_STR | n), indicator_addr);
-       } else {
-               unsigned long irq_flags;
-               local_irq_save(irq_flags);
-               iowrite32(1, indicator_addr);
-
-               /*
-                * PCIE write waits for ACK in IPQ8K, there is no
-                * need to read back value.
-                */
-               (void)ioread32(indicator_addr);
-               (void)ioread32(indicator_addr); /* conservative */
-
-               ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);
-
-               iowrite32(0, indicator_addr);
-               local_irq_restore(irq_flags);
-       }
+       ath10k_pci_write32(ar, ce_ctrl_addr + SR_WR_INDEX_ADDRESS, n);
 }
 
 static inline u32 ath10k_ce_src_ring_write_index_get(struct ath10k *ar,
@@ -285,7 +256,7 @@ static inline void ath10k_ce_engine_int_status_clear(struct ath10k *ar,
  * ath10k_ce_sendlist_send.
  * The caller takes responsibility for any needed locking.
  */
-static int ath10k_ce_send_nolock(struct ce_state *ce_state,
+static int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
                                 void *per_transfer_context,
                                 u32 buffer,
                                 unsigned int nbytes,
@@ -293,7 +264,7 @@ static int ath10k_ce_send_nolock(struct ce_state *ce_state,
                                 unsigned int flags)
 {
        struct ath10k *ar = ce_state->ar;
-       struct ce_ring_state *src_ring = ce_state->src_ring;
+       struct ath10k_ce_ring *src_ring = ce_state->src_ring;
        struct ce_desc *desc, *sdesc;
        unsigned int nentries_mask = src_ring->nentries_mask;
        unsigned int sw_index = src_ring->sw_index;
@@ -306,7 +277,9 @@ static int ath10k_ce_send_nolock(struct ce_state *ce_state,
                ath10k_warn("%s: send more we can (nbytes: %d, max: %d)\n",
                            __func__, nbytes, ce_state->src_sz_max);
 
-       ath10k_pci_wake(ar);
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return ret;
 
        if (unlikely(CE_RING_DELTA(nentries_mask,
                                   write_index, sw_index - 1) <= 0)) {
@@ -346,7 +319,7 @@ exit:
        return ret;
 }
 
-int ath10k_ce_send(struct ce_state *ce_state,
+int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
                   void *per_transfer_context,
                   u32 buffer,
                   unsigned int nbytes,
@@ -365,33 +338,19 @@ int ath10k_ce_send(struct ce_state *ce_state,
        return ret;
 }
 
-void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist, u32 buffer,
-                               unsigned int nbytes, u32 flags)
-{
-       unsigned int num_items = sendlist->num_items;
-       struct ce_sendlist_item *item;
-
-       item = &sendlist->item[num_items];
-       item->data = buffer;
-       item->u.nbytes = nbytes;
-       item->flags = flags;
-       sendlist->num_items++;
-}
-
-int ath10k_ce_sendlist_send(struct ce_state *ce_state,
+int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
                            void *per_transfer_context,
-                           struct ce_sendlist *sendlist,
-                           unsigned int transfer_id)
+                           unsigned int transfer_id,
+                           u32 paddr, unsigned int nbytes,
+                           u32 flags)
 {
-       struct ce_ring_state *src_ring = ce_state->src_ring;
-       struct ce_sendlist_item *item;
+       struct ath10k_ce_ring *src_ring = ce_state->src_ring;
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        unsigned int nentries_mask = src_ring->nentries_mask;
-       unsigned int num_items = sendlist->num_items;
        unsigned int sw_index;
        unsigned int write_index;
-       int i, delta, ret = -ENOMEM;
+       int delta, ret = -ENOMEM;
 
        spin_lock_bh(&ar_pci->ce_lock);
 
@@ -400,30 +359,12 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,
 
        delta = CE_RING_DELTA(nentries_mask, write_index, sw_index - 1);
 
-       if (delta >= num_items) {
-               /*
-                * Handle all but the last item uniformly.
-                */
-               for (i = 0; i < num_items - 1; i++) {
-                       item = &sendlist->item[i];
-                       ret = ath10k_ce_send_nolock(ce_state,
-                                                   CE_SENDLIST_ITEM_CTXT,
-                                                   (u32) item->data,
-                                                   item->u.nbytes, transfer_id,
-                                                   item->flags |
-                                                   CE_SEND_FLAG_GATHER);
-                       if (ret)
-                               ath10k_warn("CE send failed for item: %d\n", i);
-               }
-               /*
-                * Provide valid context pointer for final item.
-                */
-               item = &sendlist->item[i];
+       if (delta >= 1) {
                ret = ath10k_ce_send_nolock(ce_state, per_transfer_context,
-                                           (u32) item->data, item->u.nbytes,
-                                           transfer_id, item->flags);
+                                           paddr, nbytes,
+                                           transfer_id, flags);
                if (ret)
-                       ath10k_warn("CE send failed for last item: %d\n", i);
+                       ath10k_warn("CE send failed: %d\n", ret);
        }
 
        spin_unlock_bh(&ar_pci->ce_lock);
@@ -431,11 +372,11 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,
        return ret;
 }
 
-int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
+int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
                               void *per_recv_context,
                               u32 buffer)
 {
-       struct ce_ring_state *dest_ring = ce_state->dest_ring;
+       struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
        u32 ctrl_addr = ce_state->ctrl_addr;
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -448,7 +389,9 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
        write_index = dest_ring->write_index;
        sw_index = dest_ring->sw_index;
 
-       ath10k_pci_wake(ar);
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               goto out;
 
        if (CE_RING_DELTA(nentries_mask, write_index, sw_index - 1) > 0) {
                struct ce_desc *base = dest_ring->base_addr_owner_space;
@@ -470,6 +413,8 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
                ret = -EIO;
        }
        ath10k_pci_sleep(ar);
+
+out:
        spin_unlock_bh(&ar_pci->ce_lock);
 
        return ret;
@@ -479,14 +424,14 @@ int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
  * Guts of ath10k_ce_completed_recv_next.
  * The caller takes responsibility for any necessary locking.
  */
-static int ath10k_ce_completed_recv_next_nolock(struct ce_state *ce_state,
+static int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
                                                void **per_transfer_contextp,
                                                u32 *bufferp,
                                                unsigned int *nbytesp,
                                                unsigned int *transfer_idp,
                                                unsigned int *flagsp)
 {
-       struct ce_ring_state *dest_ring = ce_state->dest_ring;
+       struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
        unsigned int nentries_mask = dest_ring->nentries_mask;
        unsigned int sw_index = dest_ring->sw_index;
 
@@ -535,7 +480,7 @@ static int ath10k_ce_completed_recv_next_nolock(struct ce_state *ce_state,
        return 0;
 }
 
-int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
+int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
                                  void **per_transfer_contextp,
                                  u32 *bufferp,
                                  unsigned int *nbytesp,
@@ -556,11 +501,11 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
        return ret;
 }
 
-int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
+int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
                               void **per_transfer_contextp,
                               u32 *bufferp)
 {
-       struct ce_ring_state *dest_ring;
+       struct ath10k_ce_ring *dest_ring;
        unsigned int nentries_mask;
        unsigned int sw_index;
        unsigned int write_index;
@@ -612,19 +557,20 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
  * Guts of ath10k_ce_completed_send_next.
  * The caller takes responsibility for any necessary locking.
  */
-static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,
+static int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
                                                void **per_transfer_contextp,
                                                u32 *bufferp,
                                                unsigned int *nbytesp,
                                                unsigned int *transfer_idp)
 {
-       struct ce_ring_state *src_ring = ce_state->src_ring;
+       struct ath10k_ce_ring *src_ring = ce_state->src_ring;
        u32 ctrl_addr = ce_state->ctrl_addr;
        struct ath10k *ar = ce_state->ar;
        unsigned int nentries_mask = src_ring->nentries_mask;
        unsigned int sw_index = src_ring->sw_index;
+       struct ce_desc *sdesc, *sbase;
        unsigned int read_index;
-       int ret = -EIO;
+       int ret;
 
        if (src_ring->hw_index == sw_index) {
                /*
@@ -634,48 +580,54 @@ static int ath10k_ce_completed_send_next_nolock(struct ce_state *ce_state,
                 * the SW has really caught up to the HW, or if the cached
                 * value of the HW index has become stale.
                 */
-               ath10k_pci_wake(ar);
+
+               ret = ath10k_pci_wake(ar);
+               if (ret)
+                       return ret;
+
                src_ring->hw_index =
                        ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
                src_ring->hw_index &= nentries_mask;
+
                ath10k_pci_sleep(ar);
        }
+
        read_index = src_ring->hw_index;
 
-       if ((read_index != sw_index) && (read_index != 0xffffffff)) {
-               struct ce_desc *sbase = src_ring->shadow_base;
-               struct ce_desc *sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index);
+       if ((read_index == sw_index) || (read_index == 0xffffffff))
+               return -EIO;
 
-               /* Return data from completed source descriptor */
-               *bufferp = __le32_to_cpu(sdesc->addr);
-               *nbytesp = __le16_to_cpu(sdesc->nbytes);
-               *transfer_idp = MS(__le16_to_cpu(sdesc->flags),
-                                               CE_DESC_FLAGS_META_DATA);
+       sbase = src_ring->shadow_base;
+       sdesc = CE_SRC_RING_TO_DESC(sbase, sw_index);
 
-               if (per_transfer_contextp)
-                       *per_transfer_contextp =
-                               src_ring->per_transfer_context[sw_index];
+       /* Return data from completed source descriptor */
+       *bufferp = __le32_to_cpu(sdesc->addr);
+       *nbytesp = __le16_to_cpu(sdesc->nbytes);
+       *transfer_idp = MS(__le16_to_cpu(sdesc->flags),
+                          CE_DESC_FLAGS_META_DATA);
 
-               /* sanity */
-               src_ring->per_transfer_context[sw_index] = NULL;
+       if (per_transfer_contextp)
+               *per_transfer_contextp =
+                       src_ring->per_transfer_context[sw_index];
 
-               /* Update sw_index */
-               sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
-               src_ring->sw_index = sw_index;
-               ret = 0;
-       }
+       /* sanity */
+       src_ring->per_transfer_context[sw_index] = NULL;
 
-       return ret;
+       /* Update sw_index */
+       sw_index = CE_RING_IDX_INCR(nentries_mask, sw_index);
+       src_ring->sw_index = sw_index;
+
+       return 0;
 }
 
 /* NB: Modeled after ath10k_ce_completed_send_next */
-int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
+int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
                               void **per_transfer_contextp,
                               u32 *bufferp,
                               unsigned int *nbytesp,
                               unsigned int *transfer_idp)
 {
-       struct ce_ring_state *src_ring;
+       struct ath10k_ce_ring *src_ring;
        unsigned int nentries_mask;
        unsigned int sw_index;
        unsigned int write_index;
@@ -727,7 +679,7 @@ int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
        return ret;
 }
 
-int ath10k_ce_completed_send_next(struct ce_state *ce_state,
+int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
                                  void **per_transfer_contextp,
                                  u32 *bufferp,
                                  unsigned int *nbytesp,
@@ -756,53 +708,29 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,
 void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_state *ce_state = ar_pci->ce_id_to_state[ce_id];
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
        u32 ctrl_addr = ce_state->ctrl_addr;
-       void *transfer_context;
-       u32 buf;
-       unsigned int nbytes;
-       unsigned int id;
-       unsigned int flags;
+       int ret;
+
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return;
 
-       ath10k_pci_wake(ar);
        spin_lock_bh(&ar_pci->ce_lock);
 
        /* Clear the copy-complete interrupts that will be handled here. */
        ath10k_ce_engine_int_status_clear(ar, ctrl_addr,
                                          HOST_IS_COPY_COMPLETE_MASK);
 
-       if (ce_state->recv_cb) {
-               /*
-                * Pop completed recv buffers and call the registered
-                * recv callback for each
-                */
-               while (ath10k_ce_completed_recv_next_nolock(ce_state,
-                                                           &transfer_context,
-                                                           &buf, &nbytes,
-                                                           &id, &flags) == 0) {
-                       spin_unlock_bh(&ar_pci->ce_lock);
-                       ce_state->recv_cb(ce_state, transfer_context, buf,
-                                         nbytes, id, flags);
-                       spin_lock_bh(&ar_pci->ce_lock);
-               }
-       }
+       spin_unlock_bh(&ar_pci->ce_lock);
 
-       if (ce_state->send_cb) {
-               /*
-                * Pop completed send buffers and call the registered
-                * send callback for each
-                */
-               while (ath10k_ce_completed_send_next_nolock(ce_state,
-                                                           &transfer_context,
-                                                           &buf,
-                                                           &nbytes,
-                                                           &id) == 0) {
-                       spin_unlock_bh(&ar_pci->ce_lock);
-                       ce_state->send_cb(ce_state, transfer_context,
-                                         buf, nbytes, id);
-                       spin_lock_bh(&ar_pci->ce_lock);
-               }
-       }
+       if (ce_state->recv_cb)
+               ce_state->recv_cb(ce_state);
+
+       if (ce_state->send_cb)
+               ce_state->send_cb(ce_state);
+
+       spin_lock_bh(&ar_pci->ce_lock);
 
        /*
         * Misc CE interrupts are not being handled, but still need
@@ -823,10 +751,13 @@ void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id)
 void ath10k_ce_per_engine_service_any(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int ce_id;
+       int ce_id, ret;
        u32 intr_summary;
 
-       ath10k_pci_wake(ar);
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return;
+
        intr_summary = CE_INTERRUPT_SUMMARY(ar);
 
        for (ce_id = 0; intr_summary && (ce_id < ar_pci->ce_count); ce_id++) {
@@ -849,13 +780,16 @@ void ath10k_ce_per_engine_service_any(struct ath10k *ar)
  *
  * Called with ce_lock held.
  */
-static void ath10k_ce_per_engine_handler_adjust(struct ce_state *ce_state,
+static void ath10k_ce_per_engine_handler_adjust(struct ath10k_ce_pipe *ce_state,
                                                int disable_copy_compl_intr)
 {
        u32 ctrl_addr = ce_state->ctrl_addr;
        struct ath10k *ar = ce_state->ar;
+       int ret;
 
-       ath10k_pci_wake(ar);
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return;
 
        if ((!disable_copy_compl_intr) &&
            (ce_state->send_cb || ce_state->recv_cb))
@@ -871,11 +805,14 @@ static void ath10k_ce_per_engine_handler_adjust(struct ce_state *ce_state,
 void ath10k_ce_disable_interrupts(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int ce_id;
+       int ce_id, ret;
+
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return;
 
-       ath10k_pci_wake(ar);
        for (ce_id = 0; ce_id < ar_pci->ce_count; ce_id++) {
-               struct ce_state *ce_state = ar_pci->ce_id_to_state[ce_id];
+               struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
                u32 ctrl_addr = ce_state->ctrl_addr;
 
                ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
@@ -883,12 +820,8 @@ void ath10k_ce_disable_interrupts(struct ath10k *ar)
        ath10k_pci_sleep(ar);
 }
 
-void ath10k_ce_send_cb_register(struct ce_state *ce_state,
-                               void (*send_cb) (struct ce_state *ce_state,
-                                                void *transfer_context,
-                                                u32 buffer,
-                                                unsigned int nbytes,
-                                                unsigned int transfer_id),
+void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
+                               void (*send_cb)(struct ath10k_ce_pipe *),
                                int disable_interrupts)
 {
        struct ath10k *ar = ce_state->ar;
@@ -900,13 +833,8 @@ void ath10k_ce_send_cb_register(struct ce_state *ce_state,
        spin_unlock_bh(&ar_pci->ce_lock);
 }
 
-void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
-                               void (*recv_cb) (struct ce_state *ce_state,
-                                                void *transfer_context,
-                                                u32 buffer,
-                                                unsigned int nbytes,
-                                                unsigned int transfer_id,
-                                                unsigned int flags))
+void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
+                               void (*recv_cb)(struct ath10k_ce_pipe *))
 {
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -919,11 +847,11 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
 
 static int ath10k_ce_init_src_ring(struct ath10k *ar,
                                   unsigned int ce_id,
-                                  struct ce_state *ce_state,
+                                  struct ath10k_ce_pipe *ce_state,
                                   const struct ce_attr *attr)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_ring_state *src_ring;
+       struct ath10k_ce_ring *src_ring;
        unsigned int nentries = attr->src_nentries;
        unsigned int ce_nbytes;
        u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -937,19 +865,18 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
                return 0;
        }
 
-       ce_nbytes = sizeof(struct ce_ring_state) + (nentries * sizeof(void *));
+       ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *));
        ptr = kzalloc(ce_nbytes, GFP_KERNEL);
        if (ptr == NULL)
                return -ENOMEM;
 
-       ce_state->src_ring = (struct ce_ring_state *)ptr;
+       ce_state->src_ring = (struct ath10k_ce_ring *)ptr;
        src_ring = ce_state->src_ring;
 
-       ptr += sizeof(struct ce_ring_state);
+       ptr += sizeof(struct ath10k_ce_ring);
        src_ring->nentries = nentries;
        src_ring->nentries_mask = nentries - 1;
 
-       ath10k_pci_wake(ar);
        src_ring->sw_index = ath10k_ce_src_ring_read_index_get(ar, ctrl_addr);
        src_ring->sw_index &= src_ring->nentries_mask;
        src_ring->hw_index = src_ring->sw_index;
@@ -957,7 +884,6 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
        src_ring->write_index =
                ath10k_ce_src_ring_write_index_get(ar, ctrl_addr);
        src_ring->write_index &= src_ring->nentries_mask;
-       ath10k_pci_sleep(ar);
 
        src_ring->per_transfer_context = (void **)ptr;
 
@@ -970,6 +896,12 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
                                     (nentries * sizeof(struct ce_desc) +
                                      CE_DESC_RING_ALIGN),
                                     &base_addr);
+       if (!src_ring->base_addr_owner_space_unaligned) {
+               kfree(ce_state->src_ring);
+               ce_state->src_ring = NULL;
+               return -ENOMEM;
+       }
+
        src_ring->base_addr_ce_space_unaligned = base_addr;
 
        src_ring->base_addr_owner_space = PTR_ALIGN(
@@ -986,12 +918,21 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
        src_ring->shadow_base_unaligned =
                kmalloc((nentries * sizeof(struct ce_desc) +
                         CE_DESC_RING_ALIGN), GFP_KERNEL);
+       if (!src_ring->shadow_base_unaligned) {
+               pci_free_consistent(ar_pci->pdev,
+                                   (nentries * sizeof(struct ce_desc) +
+                                    CE_DESC_RING_ALIGN),
+                                   src_ring->base_addr_owner_space,
+                                   src_ring->base_addr_ce_space);
+               kfree(ce_state->src_ring);
+               ce_state->src_ring = NULL;
+               return -ENOMEM;
+       }
 
        src_ring->shadow_base = PTR_ALIGN(
                        src_ring->shadow_base_unaligned,
                        CE_DESC_RING_ALIGN);
 
-       ath10k_pci_wake(ar);
        ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr,
                                         src_ring->base_addr_ce_space);
        ath10k_ce_src_ring_size_set(ar, ctrl_addr, nentries);
@@ -999,18 +940,21 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
        ath10k_ce_src_ring_byte_swap_set(ar, ctrl_addr, 0);
        ath10k_ce_src_ring_lowmark_set(ar, ctrl_addr, 0);
        ath10k_ce_src_ring_highmark_set(ar, ctrl_addr, nentries);
-       ath10k_pci_sleep(ar);
+
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot ce src ring id %d entries %d base_addr %p\n",
+                  ce_id, nentries, src_ring->base_addr_owner_space);
 
        return 0;
 }
 
 static int ath10k_ce_init_dest_ring(struct ath10k *ar,
                                    unsigned int ce_id,
-                                   struct ce_state *ce_state,
+                                   struct ath10k_ce_pipe *ce_state,
                                    const struct ce_attr *attr)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_ring_state *dest_ring;
+       struct ath10k_ce_ring *dest_ring;
        unsigned int nentries = attr->dest_nentries;
        unsigned int ce_nbytes;
        u32 ctrl_addr = ath10k_ce_base_address(ce_id);
@@ -1024,25 +968,23 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
                return 0;
        }
 
-       ce_nbytes = sizeof(struct ce_ring_state) + (nentries * sizeof(void *));
+       ce_nbytes = sizeof(struct ath10k_ce_ring) + (nentries * sizeof(void *));
        ptr = kzalloc(ce_nbytes, GFP_KERNEL);
        if (ptr == NULL)
                return -ENOMEM;
 
-       ce_state->dest_ring = (struct ce_ring_state *)ptr;
+       ce_state->dest_ring = (struct ath10k_ce_ring *)ptr;
        dest_ring = ce_state->dest_ring;
 
-       ptr += sizeof(struct ce_ring_state);
+       ptr += sizeof(struct ath10k_ce_ring);
        dest_ring->nentries = nentries;
        dest_ring->nentries_mask = nentries - 1;
 
-       ath10k_pci_wake(ar);
        dest_ring->sw_index = ath10k_ce_dest_ring_read_index_get(ar, ctrl_addr);
        dest_ring->sw_index &= dest_ring->nentries_mask;
        dest_ring->write_index =
                ath10k_ce_dest_ring_write_index_get(ar, ctrl_addr);
        dest_ring->write_index &= dest_ring->nentries_mask;
-       ath10k_pci_sleep(ar);
 
        dest_ring->per_transfer_context = (void **)ptr;
 
@@ -1055,6 +997,12 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
                                     (nentries * sizeof(struct ce_desc) +
                                      CE_DESC_RING_ALIGN),
                                     &base_addr);
+       if (!dest_ring->base_addr_owner_space_unaligned) {
+               kfree(ce_state->dest_ring);
+               ce_state->dest_ring = NULL;
+               return -ENOMEM;
+       }
+
        dest_ring->base_addr_ce_space_unaligned = base_addr;
 
        /*
@@ -1071,44 +1019,35 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
                        dest_ring->base_addr_ce_space_unaligned,
                        CE_DESC_RING_ALIGN);
 
-       ath10k_pci_wake(ar);
        ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr,
                                          dest_ring->base_addr_ce_space);
        ath10k_ce_dest_ring_size_set(ar, ctrl_addr, nentries);
        ath10k_ce_dest_ring_byte_swap_set(ar, ctrl_addr, 0);
        ath10k_ce_dest_ring_lowmark_set(ar, ctrl_addr, 0);
        ath10k_ce_dest_ring_highmark_set(ar, ctrl_addr, nentries);
-       ath10k_pci_sleep(ar);
+
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot ce dest ring id %d entries %d base_addr %p\n",
+                  ce_id, nentries, dest_ring->base_addr_owner_space);
 
        return 0;
 }
 
-static struct ce_state *ath10k_ce_init_state(struct ath10k *ar,
+static struct ath10k_ce_pipe *ath10k_ce_init_state(struct ath10k *ar,
                                             unsigned int ce_id,
                                             const struct ce_attr *attr)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_state *ce_state = NULL;
+       struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
        u32 ctrl_addr = ath10k_ce_base_address(ce_id);
 
        spin_lock_bh(&ar_pci->ce_lock);
 
-       if (!ar_pci->ce_id_to_state[ce_id]) {
-               ce_state = kzalloc(sizeof(*ce_state), GFP_ATOMIC);
-               if (ce_state == NULL) {
-                       spin_unlock_bh(&ar_pci->ce_lock);
-                       return NULL;
-               }
-
-               ar_pci->ce_id_to_state[ce_id] = ce_state;
-               ce_state->ar = ar;
-               ce_state->id = ce_id;
-               ce_state->ctrl_addr = ctrl_addr;
-               ce_state->state = CE_RUNNING;
-               /* Save attribute flags */
-               ce_state->attr_flags = attr->flags;
-               ce_state->src_sz_max = attr->src_sz_max;
-       }
+       ce_state->ar = ar;
+       ce_state->id = ce_id;
+       ce_state->ctrl_addr = ctrl_addr;
+       ce_state->attr_flags = attr->flags;
+       ce_state->src_sz_max = attr->src_sz_max;
 
        spin_unlock_bh(&ar_pci->ce_lock);
 
@@ -1122,12 +1061,17 @@ static struct ce_state *ath10k_ce_init_state(struct ath10k *ar,
  * initialization. It may be that only one side or the other is
  * initialized by software/firmware.
  */
-struct ce_state *ath10k_ce_init(struct ath10k *ar,
+struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
                                unsigned int ce_id,
                                const struct ce_attr *attr)
 {
-       struct ce_state *ce_state;
+       struct ath10k_ce_pipe *ce_state;
        u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+       int ret;
+
+       ret = ath10k_pci_wake(ar);
+       if (ret)
+               return NULL;
 
        ce_state = ath10k_ce_init_state(ar, ce_id, attr);
        if (!ce_state) {
@@ -1136,40 +1080,38 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar,
        }
 
        if (attr->src_nentries) {
-               if (ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr)) {
-                       ath10k_err("Failed to initialize CE src ring for ID: %d\n",
-                                  ce_id);
+               ret = ath10k_ce_init_src_ring(ar, ce_id, ce_state, attr);
+               if (ret) {
+                       ath10k_err("Failed to initialize CE src ring for ID: %d (%d)\n",
+                                  ce_id, ret);
                        ath10k_ce_deinit(ce_state);
                        return NULL;
                }
        }
 
        if (attr->dest_nentries) {
-               if (ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr)) {
-                       ath10k_err("Failed to initialize CE dest ring for ID: %d\n",
-                                  ce_id);
+               ret = ath10k_ce_init_dest_ring(ar, ce_id, ce_state, attr);
+               if (ret) {
+                       ath10k_err("Failed to initialize CE dest ring for ID: %d (%d)\n",
+                                  ce_id, ret);
                        ath10k_ce_deinit(ce_state);
                        return NULL;
                }
        }
 
        /* Enable CE error interrupts */
-       ath10k_pci_wake(ar);
        ath10k_ce_error_intr_enable(ar, ctrl_addr);
+
        ath10k_pci_sleep(ar);
 
        return ce_state;
 }
 
-void ath10k_ce_deinit(struct ce_state *ce_state)
+void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state)
 {
-       unsigned int ce_id = ce_state->id;
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       ce_state->state = CE_UNUSED;
-       ar_pci->ce_id_to_state[ce_id] = NULL;
-
        if (ce_state->src_ring) {
                kfree(ce_state->src_ring->shadow_base_unaligned);
                pci_free_consistent(ar_pci->pdev,
@@ -1190,5 +1132,7 @@ void ath10k_ce_deinit(struct ce_state *ce_state)
                                    ce_state->dest_ring->base_addr_ce_space);
                kfree(ce_state->dest_ring);
        }
-       kfree(ce_state);
+
+       ce_state->src_ring = NULL;
+       ce_state->dest_ring = NULL;
 }
index c17f07c026f48f585fc8699de1d850e2f1440a9d..aec802868341b42fe86411258640086d7fd585e7 100644 (file)
@@ -27,7 +27,6 @@
 
 /* Descriptor rings must be aligned to this boundary */
 #define CE_DESC_RING_ALIGN     8
-#define CE_SENDLIST_ITEMS_MAX  12
 #define CE_SEND_FLAG_GATHER    0x00010000
 
 /*
  * how to use copy engines.
  */
 
-struct ce_state;
+struct ath10k_ce_pipe;
 
 
-/* Copy Engine operational state */
-enum ce_op_state {
-       CE_UNUSED,
-       CE_PAUSED,
-       CE_RUNNING,
-};
-
 #define CE_DESC_FLAGS_GATHER         (1 << 0)
 #define CE_DESC_FLAGS_BYTE_SWAP      (1 << 1)
 #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
@@ -57,8 +49,7 @@ struct ce_desc {
        __le16 flags; /* %CE_DESC_FLAGS_ */
 };
 
-/* Copy Engine Ring internal state */
-struct ce_ring_state {
+struct ath10k_ce_ring {
        /* Number of entries in this ring; must be power of 2 */
        unsigned int nentries;
        unsigned int nentries_mask;
@@ -116,49 +107,20 @@ struct ce_ring_state {
        void **per_transfer_context;
 };
 
-/* Copy Engine internal state */
-struct ce_state {
+struct ath10k_ce_pipe {
        struct ath10k *ar;
        unsigned int id;
 
        unsigned int attr_flags;
 
        u32 ctrl_addr;
-       enum ce_op_state state;
-
-       void (*send_cb) (struct ce_state *ce_state,
-                        void *per_transfer_send_context,
-                        u32 buffer,
-                        unsigned int nbytes,
-                        unsigned int transfer_id);
-       void (*recv_cb) (struct ce_state *ce_state,
-                        void *per_transfer_recv_context,
-                        u32 buffer,
-                        unsigned int nbytes,
-                        unsigned int transfer_id,
-                        unsigned int flags);
 
-       unsigned int src_sz_max;
-       struct ce_ring_state *src_ring;
-       struct ce_ring_state *dest_ring;
-};
+       void (*send_cb)(struct ath10k_ce_pipe *);
+       void (*recv_cb)(struct ath10k_ce_pipe *);
 
-struct ce_sendlist_item {
-       /* e.g. buffer or desc list */
-       dma_addr_t data;
-       union {
-               /* simple buffer */
-               unsigned int nbytes;
-               /* Rx descriptor list */
-               unsigned int ndesc;
-       } u;
-       /* externally-specified flags; OR-ed with internal flags */
-       u32 flags;
-};
-
-struct ce_sendlist {
-       unsigned int num_items;
-       struct ce_sendlist_item item[CE_SENDLIST_ITEMS_MAX];
+       unsigned int src_sz_max;
+       struct ath10k_ce_ring *src_ring;
+       struct ath10k_ce_ring *dest_ring;
 };
 
 /* Copy Engine settable attributes */
@@ -182,7 +144,7 @@ struct ce_attr;
  *
  * Implementation note: pushes 1 buffer to Source ring
  */
-int ath10k_ce_send(struct ce_state *ce_state,
+int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
                   void *per_transfer_send_context,
                   u32 buffer,
                   unsigned int nbytes,
@@ -190,21 +152,10 @@ int ath10k_ce_send(struct ce_state *ce_state,
                   unsigned int transfer_id,
                   unsigned int flags);
 
-void ath10k_ce_send_cb_register(struct ce_state *ce_state,
-                               void (*send_cb) (struct ce_state *ce_state,
-                                                void *transfer_context,
-                                                u32 buffer,
-                                                unsigned int nbytes,
-                                                unsigned int transfer_id),
+void ath10k_ce_send_cb_register(struct ath10k_ce_pipe *ce_state,
+                               void (*send_cb)(struct ath10k_ce_pipe *),
                                int disable_interrupts);
 
-/* Append a simple buffer (address/length) to a sendlist. */
-void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist,
-                               u32 buffer,
-                               unsigned int nbytes,
-                               /* OR-ed with internal flags */
-                               u32 flags);
-
 /*
  * Queue a "sendlist" of buffers to be sent using gather to a single
  * anonymous destination buffer
@@ -215,11 +166,11 @@ void ath10k_ce_sendlist_buf_add(struct ce_sendlist *sendlist,
  *
  * Implemenation note: Pushes multiple buffers with Gather to Source ring.
  */
-int ath10k_ce_sendlist_send(struct ce_state *ce_state,
-                           void *per_transfer_send_context,
-                           struct ce_sendlist *sendlist,
-                           /* 14 bits */
-                           unsigned int transfer_id);
+int ath10k_ce_sendlist_send(struct ath10k_ce_pipe *ce_state,
+                           void *per_transfer_context,
+                           unsigned int transfer_id,
+                           u32 paddr, unsigned int nbytes,
+                           u32 flags);
 
 /*==================Recv=======================*/
 
@@ -233,17 +184,12 @@ int ath10k_ce_sendlist_send(struct ce_state *ce_state,
  *
  * Implemenation note: Pushes a buffer to Dest ring.
  */
-int ath10k_ce_recv_buf_enqueue(struct ce_state *ce_state,
+int ath10k_ce_recv_buf_enqueue(struct ath10k_ce_pipe *ce_state,
                               void *per_transfer_recv_context,
                               u32 buffer);
 
-void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
-                               void (*recv_cb) (struct ce_state *ce_state,
-                                                void *transfer_context,
-                                                u32 buffer,
-                                                unsigned int nbytes,
-                                                unsigned int transfer_id,
-                                                unsigned int flags));
+void ath10k_ce_recv_cb_register(struct ath10k_ce_pipe *ce_state,
+                               void (*recv_cb)(struct ath10k_ce_pipe *));
 
 /* recv flags */
 /* Data is byte-swapped */
@@ -253,7 +199,7 @@ void ath10k_ce_recv_cb_register(struct ce_state *ce_state,
  * Supply data for the next completed unprocessed receive descriptor.
  * Pops buffer from Dest ring.
  */
-int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
+int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
                                  void **per_transfer_contextp,
                                  u32 *bufferp,
                                  unsigned int *nbytesp,
@@ -263,7 +209,7 @@ int ath10k_ce_completed_recv_next(struct ce_state *ce_state,
  * Supply data for the next completed unprocessed send descriptor.
  * Pops 1 completed send buffer from Source ring.
  */
-int ath10k_ce_completed_send_next(struct ce_state *ce_state,
+int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
                           void **per_transfer_contextp,
                           u32 *bufferp,
                           unsigned int *nbytesp,
@@ -272,7 +218,7 @@ int ath10k_ce_completed_send_next(struct ce_state *ce_state,
 /*==================CE Engine Initialization=======================*/
 
 /* Initialize an instance of a CE */
-struct ce_state *ath10k_ce_init(struct ath10k *ar,
+struct ath10k_ce_pipe *ath10k_ce_init(struct ath10k *ar,
                                unsigned int ce_id,
                                const struct ce_attr *attr);
 
@@ -282,7 +228,7 @@ struct ce_state *ath10k_ce_init(struct ath10k *ar,
  * receive buffers.  Target DMA must be stopped before using
  * this API.
  */
-int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
+int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
                               void **per_transfer_contextp,
                               u32 *bufferp);
 
@@ -291,13 +237,13 @@ int ath10k_ce_revoke_recv_next(struct ce_state *ce_state,
  * pending sends.  Target DMA must be stopped before using
  * this API.
  */
-int ath10k_ce_cancel_send_next(struct ce_state *ce_state,
+int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
                               void **per_transfer_contextp,
                               u32 *bufferp,
                               unsigned int *nbytesp,
                               unsigned int *transfer_idp);
 
-void ath10k_ce_deinit(struct ce_state *ce_state);
+void ath10k_ce_deinit(struct ath10k_ce_pipe *ce_state);
 
 /*==================CE Interrupt Handlers====================*/
 void ath10k_ce_per_engine_service_any(struct ath10k *ar);
@@ -322,9 +268,6 @@ struct ce_attr {
        /* CE_ATTR_* values */
        unsigned int flags;
 
-       /* currently not in use */
-       unsigned int priority;
-
        /* #entries in source ring - Must be a power of 2 */
        unsigned int src_nentries;
 
@@ -336,21 +279,8 @@ struct ce_attr {
 
        /* #entries in destination ring - Must be a power of 2 */
        unsigned int dest_nentries;
-
-       /* Future use */
-       void *reserved;
 };
 
-/*
- * When using sendlist_send to transfer multiple buffer fragments, the
- * transfer context of each fragment, except last one, will be filled
- * with CE_SENDLIST_ITEM_CTXT. ce_completed_send will return success for
- * each fragment done with send and the transfer context would be
- * CE_SENDLIST_ITEM_CTXT. Upper layer could use this to identify the
- * status of a send completion.
- */
-#define CE_SENDLIST_ITEM_CTXT  ((void *)0xcecebeef)
-
 #define SR_BA_ADDRESS          0x0000
 #define SR_SIZE_ADDRESS                0x0004
 #define DR_BA_ADDRESS          0x0008
index 7226c23b956991165f5f1f7c5e7253d951400387..76906d5a082e00e9ebbb4fe967b430668646fe54 100644 (file)
@@ -38,17 +38,6 @@ MODULE_PARM_DESC(uart_print, "Uart target debugging");
 MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
 
 static const struct ath10k_hw_params ath10k_hw_params_list[] = {
-       {
-               .id = QCA988X_HW_1_0_VERSION,
-               .name = "qca988x hw1.0",
-               .patch_load_addr = QCA988X_HW_1_0_PATCH_LOAD_ADDR,
-               .fw = {
-                       .dir = QCA988X_HW_1_0_FW_DIR,
-                       .fw = QCA988X_HW_1_0_FW_FILE,
-                       .otp = QCA988X_HW_1_0_OTP_FILE,
-                       .board = QCA988X_HW_1_0_BOARD_DATA_FILE,
-               },
-       },
        {
                .id = QCA988X_HW_2_0_VERSION,
                .name = "qca988x hw2.0",
@@ -64,7 +53,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
 
 static void ath10k_send_suspend_complete(struct ath10k *ar)
 {
-       ath10k_dbg(ATH10K_DBG_CORE, "%s\n", __func__);
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot suspend complete\n");
 
        ar->is_target_paused = true;
        wake_up(&ar->event_queue);
@@ -112,7 +101,7 @@ static int ath10k_init_connect_htc(struct ath10k *ar)
                goto timeout;
        }
 
-       ath10k_dbg(ATH10K_DBG_CORE, "core wmi ready\n");
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot wmi ready\n");
        return 0;
 
 timeout:
@@ -214,8 +203,8 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
                return ret;
        }
 
-       ath10k_dbg(ATH10K_DBG_CORE,
-                  "ath10k: Board extended Data download addr: 0x%x\n",
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot push board extended data addr 0x%x\n",
                   board_ext_data_addr);
 
        if (board_ext_data_addr == 0)
@@ -446,6 +435,13 @@ static int ath10k_init_uart(struct ath10k *ar)
                return ret;
        }
 
+       /* Set the UART baud rate to 19200. */
+       ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);
+       if (ret) {
+               ath10k_warn("could not set the baud rate (%d)\n", ret);
+               return ret;
+       }
+
        ath10k_info("UART prints enabled\n");
        return 0;
 }
@@ -641,6 +637,10 @@ int ath10k_core_start(struct ath10k *ar)
        if (status)
                goto err_disconnect_htc;
 
+       status = ath10k_debug_start(ar);
+       if (status)
+               goto err_disconnect_htc;
+
        ar->free_vdev_map = (1 << TARGET_NUM_VDEVS) - 1;
 
        return 0;
@@ -658,6 +658,7 @@ EXPORT_SYMBOL(ath10k_core_start);
 
 void ath10k_core_stop(struct ath10k *ar)
 {
+       ath10k_debug_stop(ar);
        ath10k_htc_stop(&ar->htc);
        ath10k_htt_detach(&ar->htt);
        ath10k_wmi_detach(ar);
@@ -717,10 +718,46 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
        return 0;
 }
 
-int ath10k_core_register(struct ath10k *ar)
+static int ath10k_core_check_chip_id(struct ath10k *ar)
+{
+       u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
+                  ar->chip_id, hw_revision);
+
+       /* Check that we are not using hw1.0 (some of them have same pci id
+        * as hw2.0) before doing anything else as ath10k crashes horribly
+        * due to missing hw1.0 workarounds. */
+       switch (hw_revision) {
+       case QCA988X_HW_1_0_CHIP_ID_REV:
+               ath10k_err("ERROR: qca988x hw1.0 is not supported\n");
+               return -EOPNOTSUPP;
+
+       case QCA988X_HW_2_0_CHIP_ID_REV:
+               /* known hardware revision, continue normally */
+               return 0;
+
+       default:
+               ath10k_warn("Warning: hardware revision unknown (0x%x), expect problems\n",
+                           ar->chip_id);
+               return 0;
+       }
+
+       return 0;
+}
+
+int ath10k_core_register(struct ath10k *ar, u32 chip_id)
 {
        int status;
 
+       ar->chip_id = chip_id;
+
+       status = ath10k_core_check_chip_id(ar);
+       if (status) {
+               ath10k_err("Unsupported chip id 0x%08x\n", ar->chip_id);
+               return status;
+       }
+
        status = ath10k_core_probe_fw(ar);
        if (status) {
                ath10k_err("could not probe fw (%d)\n", status);
@@ -755,6 +792,7 @@ void ath10k_core_unregister(struct ath10k *ar)
         * Otherwise we will fail to submit commands to FW and mac80211 will be
         * unhappy about callback failures. */
        ath10k_mac_unregister(ar);
+
        ath10k_core_free_firmware_files(ar);
 }
 EXPORT_SYMBOL(ath10k_core_unregister);
index e4bba563ed4273613e58332e45c4146c04818516..292ad4577c986aa3efc9c4c377307005fcdddecf 100644 (file)
@@ -52,18 +52,12 @@ struct ath10k_skb_cb {
 
        struct {
                u8 vdev_id;
-               u16 msdu_id;
                u8 tid;
                bool is_offchan;
-               bool is_conf;
-               bool discard;
-               bool no_ack;
-               u8 refcount;
-               struct sk_buff *txfrag;
-               struct sk_buff *msdu;
-       } __packed htt;
 
-       /* 4 bytes left on 64bit arch */
+               u8 frag_len;
+               u8 pad_len;
+       } __packed htt;
 } __packed;
 
 static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
@@ -112,11 +106,7 @@ struct ath10k_wmi {
        enum ath10k_htc_ep_id eid;
        struct completion service_ready;
        struct completion unified_ready;
-       atomic_t pending_tx_count;
-       wait_queue_head_t wq;
-
-       struct sk_buff_head wmi_event_list;
-       struct work_struct wmi_event_work;
+       wait_queue_head_t tx_credits_wq;
 };
 
 struct ath10k_peer_stat {
@@ -203,6 +193,7 @@ struct ath10k_vif {
        enum wmi_vdev_subtype vdev_subtype;
        u32 beacon_interval;
        u32 dtim_period;
+       struct sk_buff *beacon;
 
        struct ath10k *ar;
        struct ieee80211_vif *vif;
@@ -246,6 +237,9 @@ struct ath10k_debug {
        u32 wmi_service_bitmap[WMI_SERVICE_BM_SIZE];
 
        struct completion event_stats_compl;
+
+       unsigned long htt_stats_mask;
+       struct delayed_work htt_stats_dwork;
 };
 
 enum ath10k_state {
@@ -270,12 +264,21 @@ enum ath10k_state {
        ATH10K_STATE_WEDGED,
 };
 
+enum ath10k_fw_features {
+       /* wmi_mgmt_rx_hdr contains extra RSSI information */
+       ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
+
+       /* keep last */
+       ATH10K_FW_FEATURE_COUNT,
+};
+
 struct ath10k {
        struct ath_common ath_common;
        struct ieee80211_hw *hw;
        struct device *dev;
        u8 mac_addr[ETH_ALEN];
 
+       u32 chip_id;
        u32 target_version;
        u8 fw_version_major;
        u32 fw_version_minor;
@@ -288,6 +291,8 @@ struct ath10k {
        u32 vht_cap_info;
        u32 num_rf_chains;
 
+       DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
+
        struct targetdef *targetdef;
        struct hostdef *hostdef;
 
@@ -393,7 +398,7 @@ void ath10k_core_destroy(struct ath10k *ar);
 
 int ath10k_core_start(struct ath10k *ar);
 void ath10k_core_stop(struct ath10k *ar);
-int ath10k_core_register(struct ath10k *ar);
+int ath10k_core_register(struct ath10k *ar, u32 chip_id);
 void ath10k_core_unregister(struct ath10k *ar);
 
 #endif /* _CORE_H_ */
index 3d65594fa098a40f638f73499d423e80d2a64a7e..59615c7f217e408ee48669f6d5d949ae8fef1ada 100644 (file)
@@ -21,6 +21,9 @@
 #include "core.h"
 #include "debug.h"
 
+/* ms */
+#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
+
 static int ath10k_printk(const char *level, const char *fmt, ...)
 {
        struct va_format vaf;
@@ -260,7 +263,6 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
        }
 
        spin_unlock_bh(&ar->data_lock);
-       mutex_unlock(&ar->conf_mutex);
        complete(&ar->debug.event_stats_compl);
 }
 
@@ -499,6 +501,136 @@ static const struct file_operations fops_simulate_fw_crash = {
        .llseek = default_llseek,
 };
 
+static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       unsigned int len;
+       char buf[50];
+
+       len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static const struct file_operations fops_chip_id = {
+       .read = ath10k_read_chip_id,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+static int ath10k_debug_htt_stats_req(struct ath10k *ar)
+{
+       u64 cookie;
+       int ret;
+
+       lockdep_assert_held(&ar->conf_mutex);
+
+       if (ar->debug.htt_stats_mask == 0)
+               /* htt stats are disabled */
+               return 0;
+
+       if (ar->state != ATH10K_STATE_ON)
+               return 0;
+
+       cookie = get_jiffies_64();
+
+       ret = ath10k_htt_h2t_stats_req(&ar->htt, ar->debug.htt_stats_mask,
+                                      cookie);
+       if (ret) {
+               ath10k_warn("failed to send htt stats request: %d\n", ret);
+               return ret;
+       }
+
+       queue_delayed_work(ar->workqueue, &ar->debug.htt_stats_dwork,
+                          msecs_to_jiffies(ATH10K_DEBUG_HTT_STATS_INTERVAL));
+
+       return 0;
+}
+
+static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
+{
+       struct ath10k *ar = container_of(work, struct ath10k,
+                                        debug.htt_stats_dwork.work);
+
+       mutex_lock(&ar->conf_mutex);
+
+       ath10k_debug_htt_stats_req(ar);
+
+       mutex_unlock(&ar->conf_mutex);
+}
+
+static ssize_t ath10k_read_htt_stats_mask(struct file *file,
+                                           char __user *user_buf,
+                                           size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       char buf[32];
+       unsigned int len;
+
+       len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_write_htt_stats_mask(struct file *file,
+                                            const char __user *user_buf,
+                                            size_t count, loff_t *ppos)
+{
+       struct ath10k *ar = file->private_data;
+       unsigned long mask;
+       int ret;
+
+       ret = kstrtoul_from_user(user_buf, count, 0, &mask);
+       if (ret)
+               return ret;
+
+       /* max 8 bit masks (for now) */
+       if (mask > 0xff)
+               return -E2BIG;
+
+       mutex_lock(&ar->conf_mutex);
+
+       ar->debug.htt_stats_mask = mask;
+
+       ret = ath10k_debug_htt_stats_req(ar);
+       if (ret)
+               goto out;
+
+       ret = count;
+
+out:
+       mutex_unlock(&ar->conf_mutex);
+
+       return ret;
+}
+
+static const struct file_operations fops_htt_stats_mask = {
+       .read = ath10k_read_htt_stats_mask,
+       .write = ath10k_write_htt_stats_mask,
+       .open = simple_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
+
+int ath10k_debug_start(struct ath10k *ar)
+{
+       int ret;
+
+       ret = ath10k_debug_htt_stats_req(ar);
+       if (ret)
+               /* continue normally anyway, this isn't serious */
+               ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
+
+       return 0;
+}
+
+void ath10k_debug_stop(struct ath10k *ar)
+{
+       cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
+}
+
 int ath10k_debug_create(struct ath10k *ar)
 {
        ar->debug.debugfs_phy = debugfs_create_dir("ath10k",
@@ -507,6 +639,9 @@ int ath10k_debug_create(struct ath10k *ar)
        if (!ar->debug.debugfs_phy)
                return -ENOMEM;
 
+       INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
+                         ath10k_debug_htt_stats_dwork);
+
        init_completion(&ar->debug.event_stats_compl);
 
        debugfs_create_file("fw_stats", S_IRUSR, ar->debug.debugfs_phy, ar,
@@ -518,8 +653,15 @@ int ath10k_debug_create(struct ath10k *ar)
        debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
                            ar, &fops_simulate_fw_crash);
 
+       debugfs_create_file("chip_id", S_IRUSR, ar->debug.debugfs_phy,
+                           ar, &fops_chip_id);
+
+       debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
+                           ar, &fops_htt_stats_mask);
+
        return 0;
 }
+
 #endif /* CONFIG_ATH10K_DEBUGFS */
 
 #ifdef CONFIG_ATH10K_DEBUG
index 168140c54028eb16d7482ecbb7a6a835d4807736..fa581486626f7e6d8a320b6f9daa8cab87c42b23 100644 (file)
@@ -27,11 +27,12 @@ enum ath10k_debug_mask {
        ATH10K_DBG_HTC          = 0x00000004,
        ATH10K_DBG_HTT          = 0x00000008,
        ATH10K_DBG_MAC          = 0x00000010,
-       ATH10K_DBG_CORE         = 0x00000020,
+       ATH10K_DBG_BOOT         = 0x00000020,
        ATH10K_DBG_PCI_DUMP     = 0x00000040,
        ATH10K_DBG_HTT_DUMP     = 0x00000080,
        ATH10K_DBG_MGMT         = 0x00000100,
        ATH10K_DBG_DATA         = 0x00000200,
+       ATH10K_DBG_BMI          = 0x00000400,
        ATH10K_DBG_ANY          = 0xffffffff,
 };
 
@@ -42,6 +43,8 @@ extern __printf(1, 2) int ath10k_err(const char *fmt, ...);
 extern __printf(1, 2) int ath10k_warn(const char *fmt, ...);
 
 #ifdef CONFIG_ATH10K_DEBUGFS
+int ath10k_debug_start(struct ath10k *ar);
+void ath10k_debug_stop(struct ath10k *ar);
 int ath10k_debug_create(struct ath10k *ar);
 void ath10k_debug_read_service_map(struct ath10k *ar,
                                   void *service_map,
@@ -50,6 +53,15 @@ void ath10k_debug_read_target_stats(struct ath10k *ar,
                                    struct wmi_stats_event *ev);
 
 #else
+static inline int ath10k_debug_start(struct ath10k *ar)
+{
+       return 0;
+}
+
+static inline void ath10k_debug_stop(struct ath10k *ar)
+{
+}
+
 static inline int ath10k_debug_create(struct ath10k *ar)
 {
        return 0;
index ef3329ef52f369f0b65a7fd2e830ab07d99c573b..3118d7506734267c8fcca7e80ad9eeba9269fce1 100644 (file)
@@ -103,10 +103,10 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
        struct ath10k_htc_hdr *hdr;
 
        hdr = (struct ath10k_htc_hdr *)skb->data;
-       memset(hdr, 0, sizeof(*hdr));
 
        hdr->eid = ep->eid;
        hdr->len = __cpu_to_le16(skb->len - sizeof(*hdr));
+       hdr->flags = 0;
 
        spin_lock_bh(&ep->htc->tx_lock);
        hdr->seq_no = ep->seq_no++;
@@ -117,134 +117,13 @@ static void ath10k_htc_prepare_tx_skb(struct ath10k_htc_ep *ep,
        spin_unlock_bh(&ep->htc->tx_lock);
 }
 
-static int ath10k_htc_issue_skb(struct ath10k_htc *htc,
-                               struct ath10k_htc_ep *ep,
-                               struct sk_buff *skb,
-                               u8 credits)
-{
-       struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
-       int ret;
-
-       ath10k_dbg(ATH10K_DBG_HTC, "%s: ep %d skb %p\n", __func__,
-                  ep->eid, skb);
-
-       ath10k_htc_prepare_tx_skb(ep, skb);
-
-       ret = ath10k_skb_map(htc->ar->dev, skb);
-       if (ret)
-               goto err;
-
-       ret = ath10k_hif_send_head(htc->ar,
-                                  ep->ul_pipe_id,
-                                  ep->eid,
-                                  skb->len,
-                                  skb);
-       if (unlikely(ret))
-               goto err;
-
-       return 0;
-err:
-       ath10k_warn("HTC issue failed: %d\n", ret);
-
-       spin_lock_bh(&htc->tx_lock);
-       ep->tx_credits += credits;
-       spin_unlock_bh(&htc->tx_lock);
-
-       /* this is the simplest way to handle out-of-resources for non-credit
-        * based endpoints. credit based endpoints can still get -ENOSR, but
-        * this is highly unlikely as credit reservation should prevent that */
-       if (ret == -ENOSR) {
-               spin_lock_bh(&htc->tx_lock);
-               __skb_queue_head(&ep->tx_queue, skb);
-               spin_unlock_bh(&htc->tx_lock);
-
-               return ret;
-       }
-
-       skb_cb->is_aborted = true;
-       ath10k_htc_notify_tx_completion(ep, skb);
-
-       return ret;
-}
-
-static struct sk_buff *ath10k_htc_get_skb_credit_based(struct ath10k_htc *htc,
-                                                      struct ath10k_htc_ep *ep,
-                                                      u8 *credits)
-{
-       struct sk_buff *skb;
-       struct ath10k_skb_cb *skb_cb;
-       int credits_required;
-       int remainder;
-       unsigned int transfer_len;
-
-       lockdep_assert_held(&htc->tx_lock);
-
-       skb = __skb_dequeue(&ep->tx_queue);
-       if (!skb)
-               return NULL;
-
-       skb_cb = ATH10K_SKB_CB(skb);
-       transfer_len = skb->len;
-
-       if (likely(transfer_len <= htc->target_credit_size)) {
-               credits_required = 1;
-       } else {
-               /* figure out how many credits this message requires */
-               credits_required = transfer_len / htc->target_credit_size;
-               remainder = transfer_len % htc->target_credit_size;
-
-               if (remainder)
-                       credits_required++;
-       }
-
-       ath10k_dbg(ATH10K_DBG_HTC, "Credits required %d got %d\n",
-                  credits_required, ep->tx_credits);
-
-       if (ep->tx_credits < credits_required) {
-               __skb_queue_head(&ep->tx_queue, skb);
-               return NULL;
-       }
-
-       ep->tx_credits -= credits_required;
-       *credits = credits_required;
-       return skb;
-}
-
-static void ath10k_htc_send_work(struct work_struct *work)
-{
-       struct ath10k_htc_ep *ep = container_of(work,
-                                       struct ath10k_htc_ep, send_work);
-       struct ath10k_htc *htc = ep->htc;
-       struct sk_buff *skb;
-       u8 credits = 0;
-       int ret;
-
-       while (true) {
-               if (ep->ul_is_polled)
-                       ath10k_htc_send_complete_check(ep, 0);
-
-               spin_lock_bh(&htc->tx_lock);
-               if (ep->tx_credit_flow_enabled)
-                       skb = ath10k_htc_get_skb_credit_based(htc, ep,
-                                                             &credits);
-               else
-                       skb = __skb_dequeue(&ep->tx_queue);
-               spin_unlock_bh(&htc->tx_lock);
-
-               if (!skb)
-                       break;
-
-               ret = ath10k_htc_issue_skb(htc, ep, skb, credits);
-               if (ret == -ENOSR)
-                       break;
-       }
-}
-
 int ath10k_htc_send(struct ath10k_htc *htc,
                    enum ath10k_htc_ep_id eid,
                    struct sk_buff *skb)
 {
        struct ath10k_htc_ep *ep = &htc->endpoint[eid];
+       int credits = 0;
+       int ret;
 
        if (htc->ar->state == ATH10K_STATE_WEDGED)
                return -ECOMM;
@@ -254,18 +133,55 @@ int ath10k_htc_send(struct ath10k_htc *htc,
                return -ENOENT;
        }
 
+       /* FIXME: This looks ugly, can we fix it? */
        spin_lock_bh(&htc->tx_lock);
        if (htc->stopped) {
                spin_unlock_bh(&htc->tx_lock);
                return -ESHUTDOWN;
        }
+       spin_unlock_bh(&htc->tx_lock);
 
-       __skb_queue_tail(&ep->tx_queue, skb);
        skb_push(skb, sizeof(struct ath10k_htc_hdr));
-       spin_unlock_bh(&htc->tx_lock);
 
-       queue_work(htc->ar->workqueue, &ep->send_work);
+       if (ep->tx_credit_flow_enabled) {
+               credits = DIV_ROUND_UP(skb->len, htc->target_credit_size);
+               spin_lock_bh(&htc->tx_lock);
+               if (ep->tx_credits < credits) {
+                       spin_unlock_bh(&htc->tx_lock);
+                       ret = -EAGAIN;
+                       goto err_pull;
+               }
+               ep->tx_credits -= credits;
+               spin_unlock_bh(&htc->tx_lock);
+       }
+
+       ath10k_htc_prepare_tx_skb(ep, skb);
+
+       ret = ath10k_skb_map(htc->ar->dev, skb);
+       if (ret)
+               goto err_credits;
+
+       ret = ath10k_hif_send_head(htc->ar, ep->ul_pipe_id, ep->eid,
+                                  skb->len, skb);
+       if (ret)
+               goto err_unmap;
+
        return 0;
+
+err_unmap:
+       ath10k_skb_unmap(htc->ar->dev, skb);
+err_credits:
+       if (ep->tx_credit_flow_enabled) {
+               spin_lock_bh(&htc->tx_lock);
+               ep->tx_credits += credits;
+               spin_unlock_bh(&htc->tx_lock);
+
+               if (ep->ep_ops.ep_tx_credits)
+                       ep->ep_ops.ep_tx_credits(htc->ar);
+       }
+err_pull:
+       skb_pull(skb, sizeof(struct ath10k_htc_hdr));
+       return ret;
 }
 
 static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
@@ -278,39 +194,9 @@ static int ath10k_htc_tx_completion_handler(struct ath10k *ar,
        ath10k_htc_notify_tx_completion(ep, skb);
        /* the skb now belongs to the completion handler */
 
-       /* note: when using TX credit flow, the re-checking of queues happens
-        * when credits flow back from the target.  in the non-TX credit case,
-        * we recheck after the packet completes */
-       spin_lock_bh(&htc->tx_lock);
-       if (!ep->tx_credit_flow_enabled && !htc->stopped)
-               queue_work(ar->workqueue, &ep->send_work);
-       spin_unlock_bh(&htc->tx_lock);
-
        return 0;
 }
 
-/* flush endpoint TX queue */
-static void ath10k_htc_flush_endpoint_tx(struct ath10k_htc *htc,
-                                        struct ath10k_htc_ep *ep)
-{
-       struct sk_buff *skb;
-       struct ath10k_skb_cb *skb_cb;
-
-       spin_lock_bh(&htc->tx_lock);
-       for (;;) {
-               skb = __skb_dequeue(&ep->tx_queue);
-               if (!skb)
-                       break;
-
-               skb_cb = ATH10K_SKB_CB(skb);
-               skb_cb->is_aborted = true;
-               ath10k_htc_notify_tx_completion(ep, skb);
-       }
-       spin_unlock_bh(&htc->tx_lock);
-
-       cancel_work_sync(&ep->send_work);
-}
-
 /***********/
 /* Receive */
 /***********/
@@ -340,8 +226,11 @@ ath10k_htc_process_credit_report(struct ath10k_htc *htc,
                ep = &htc->endpoint[report->eid];
                ep->tx_credits += report->credits;
 
-               if (ep->tx_credits && !skb_queue_empty(&ep->tx_queue))
-                       queue_work(htc->ar->workqueue, &ep->send_work);
+               if (ep->ep_ops.ep_tx_credits) {
+                       spin_unlock_bh(&htc->tx_lock);
+                       ep->ep_ops.ep_tx_credits(htc->ar);
+                       spin_lock_bh(&htc->tx_lock);
+               }
        }
        spin_unlock_bh(&htc->tx_lock);
 }
@@ -599,10 +488,8 @@ static void ath10k_htc_reset_endpoint_states(struct ath10k_htc *htc)
                ep->max_ep_message_len = 0;
                ep->max_tx_queue_depth = 0;
                ep->eid = i;
-               skb_queue_head_init(&ep->tx_queue);
                ep->htc = htc;
                ep->tx_credit_flow_enabled = true;
-               INIT_WORK(&ep->send_work, ath10k_htc_send_work);
        }
 }
 
@@ -752,8 +639,8 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
        tx_alloc = ath10k_htc_get_credit_allocation(htc,
                                                    conn_req->service_id);
        if (!tx_alloc)
-               ath10k_dbg(ATH10K_DBG_HTC,
-                          "HTC Service %s does not allocate target credits\n",
+               ath10k_dbg(ATH10K_DBG_BOOT,
+                          "boot htc service %s does not allocate target credits\n",
                           htc_service_name(conn_req->service_id));
 
        skb = ath10k_htc_build_tx_ctrl_skb(htc->ar);
@@ -772,16 +659,16 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
 
        flags |= SM(tx_alloc, ATH10K_HTC_CONN_FLAGS_RECV_ALLOC);
 
-       req_msg = &msg->connect_service;
-       req_msg->flags = __cpu_to_le16(flags);
-       req_msg->service_id = __cpu_to_le16(conn_req->service_id);
-
        /* Only enable credit flow control for WMI ctrl service */
        if (conn_req->service_id != ATH10K_HTC_SVC_ID_WMI_CONTROL) {
                flags |= ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
                disable_credit_flow_ctrl = true;
        }
 
+       req_msg = &msg->connect_service;
+       req_msg->flags = __cpu_to_le16(flags);
+       req_msg->service_id = __cpu_to_le16(conn_req->service_id);
+
        INIT_COMPLETION(htc->ctl_resp);
 
        status = ath10k_htc_send(htc, ATH10K_HTC_EP_0, skb);
@@ -873,19 +760,19 @@ setup:
        if (status)
                return status;
 
-       ath10k_dbg(ATH10K_DBG_HTC,
-                  "HTC service: %s UL pipe: %d DL pipe: %d eid: %d ready\n",
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot htc service '%s' ul pipe %d dl pipe %d eid %d ready\n",
                   htc_service_name(ep->service_id), ep->ul_pipe_id,
                   ep->dl_pipe_id, ep->eid);
 
-       ath10k_dbg(ATH10K_DBG_HTC,
-                  "EP %d UL polled: %d, DL polled: %d\n",
+       ath10k_dbg(ATH10K_DBG_BOOT,
+                  "boot htc ep %d ul polled %d dl polled %d\n",
                   ep->eid, ep->ul_is_polled, ep->dl_is_polled);
 
        if (disable_credit_flow_ctrl && ep->tx_credit_flow_enabled) {
                ep->tx_credit_flow_enabled = false;
-               ath10k_dbg(ATH10K_DBG_HTC,
-                          "HTC service: %s eid: %d TX flow control disabled\n",
+               ath10k_dbg(ATH10K_DBG_BOOT,
+                          "boot htc service '%s' eid %d TX flow control disabled\n",
                           htc_service_name(ep->service_id), assigned_eid);
        }
 
@@ -945,18 +832,10 @@ int ath10k_htc_start(struct ath10k_htc *htc)
  */
 void ath10k_htc_stop(struct ath10k_htc *htc)
 {
-       int i;
-       struct ath10k_htc_ep *ep;
-
        spin_lock_bh(&htc->tx_lock);
        htc->stopped = true;
        spin_unlock_bh(&htc->tx_lock);
 
-       for (i = ATH10K_HTC_EP_0; i < ATH10K_HTC_EP_COUNT; i++) {
-               ep = &htc->endpoint[i];
-               ath10k_htc_flush_endpoint_tx(htc, ep);
-       }
-
        ath10k_hif_stop(htc->ar);
 }
 
index e1dd8c761853d7d3197c173aeacb9499d4bd274a..4716d331e6b6504d712c858345545a410cbcbab1 100644 (file)
@@ -276,6 +276,7 @@ struct ath10k_htc_ops {
 struct ath10k_htc_ep_ops {
        void (*ep_tx_complete)(struct ath10k *, struct sk_buff *);
        void (*ep_rx_complete)(struct ath10k *, struct sk_buff *);
+       void (*ep_tx_credits)(struct ath10k *);
 };
 
 /* service connection information */
@@ -315,15 +316,11 @@ struct ath10k_htc_ep {
        int ul_is_polled; /* call HIF to get tx completions */
        int dl_is_polled; /* call HIF to fetch rx (not implemented) */
 
-       struct sk_buff_head tx_queue;
-
        u8 seq_no; /* for debugging */
        int tx_credits;
        int tx_credit_size;
        int tx_credits_per_max_message;
        bool tx_credit_flow_enabled;
-
-       struct work_struct send_work;
 };
 
 struct ath10k_htc_svc_tx_credits {
index 39342c5cfcb270d8ded3d53fb8b0aaba011cc789..5f7eeebc54327736cbfc2b6fb77bc030029bf7c3 100644 (file)
@@ -104,21 +104,16 @@ err_htc_attach:
 
 static int ath10k_htt_verify_version(struct ath10k_htt *htt)
 {
-       ath10k_dbg(ATH10K_DBG_HTT,
-                  "htt target version %d.%d; host version %d.%d\n",
-                   htt->target_version_major,
-                   htt->target_version_minor,
-                   HTT_CURRENT_VERSION_MAJOR,
-                   HTT_CURRENT_VERSION_MINOR);
-
-       if (htt->target_version_major != HTT_CURRENT_VERSION_MAJOR) {
-               ath10k_err("htt major versions are incompatible!\n");
+       ath10k_info("htt target version %d.%d\n",
+                   htt->target_version_major, htt->target_version_minor);
+
+       if (htt->target_version_major != 2 &&
+           htt->target_version_major != 3) {
+               ath10k_err("unsupported htt major version %d. supported versions are 2 and 3\n",
+                          htt->target_version_major);
                return -ENOTSUPP;
        }
 
-       if (htt->target_version_minor != HTT_CURRENT_VERSION_MINOR)
-               ath10k_warn("htt minor version differ but still compatible\n");
-
        return 0;
 }
 
index 318be4629cded3b19248fe13c17d6def30253b92..1a337e93b7e95e9ef70ab9053696dce7cf4e4c95 100644 (file)
 #define _HTT_H_
 
 #include <linux/bug.h>
+#include <linux/interrupt.h>
 
 #include "htc.h"
 #include "rx_desc.h"
 
-#define HTT_CURRENT_VERSION_MAJOR      2
-#define HTT_CURRENT_VERSION_MINOR      1
-
 enum htt_dbg_stats_type {
        HTT_DBG_STATS_WAL_PDEV_TXRX = 1 << 0,
        HTT_DBG_STATS_RX_REORDER    = 1 << 1,
@@ -45,6 +43,9 @@ enum htt_h2t_msg_type { /* host-to-target */
        HTT_H2T_MSG_TYPE_SYNC               = 4,
        HTT_H2T_MSG_TYPE_AGGR_CFG           = 5,
        HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG = 6,
+
+       /* This command is used for sending management frames in HTT < 3.0.
+        * HTT >= 3.0 uses TX_FRM for everything. */
        HTT_H2T_MSG_TYPE_MGMT_TX            = 7,
 
        HTT_H2T_NUM_MSGS /* keep this last */
@@ -1268,6 +1269,7 @@ struct ath10k_htt {
        /* set if host-fw communication goes haywire
         * used to avoid further failures */
        bool rx_confused;
+       struct tasklet_struct rx_replenish_task;
 };
 
 #define RX_HTT_HDR_STATUS_LEN 64
@@ -1308,6 +1310,10 @@ struct htt_rx_desc {
 #define HTT_RX_BUF_SIZE 1920
 #define HTT_RX_MSDU_SIZE (HTT_RX_BUF_SIZE - (int)sizeof(struct htt_rx_desc))
 
+/* Refill a bunch of RX buffers for each refill round so that FW/HW can handle
+ * aggregated traffic more nicely. */
+#define ATH10K_HTT_MAX_NUM_REFILL 16
+
 /*
  * DMA_MAP expects the buffer to be an integral number of cache lines.
  * Rather than checking the actual cache line size, this code makes a
@@ -1327,6 +1333,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt);
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
 void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb);
 int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt);
+int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie);
 int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt);
 
 void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
index e784c40b904b55165a112df250c61351c606979b..90d4f74c28d7deaa4c087bfdbc47ca83ac1a9716 100644 (file)
@@ -20,6 +20,7 @@
 #include "htt.h"
 #include "txrx.h"
 #include "debug.h"
+#include "trace.h"
 
 #include <linux/log2.h>
 
 /* when under memory pressure rx ring refill may fail and needs a retry */
 #define HTT_RX_RING_REFILL_RETRY_MS 50
 
+
+static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
+
+
 static int ath10k_htt_rx_ring_size(struct ath10k_htt *htt)
 {
        int size;
@@ -177,10 +182,27 @@ static int ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
 
 static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
 {
-       int ret, num_to_fill;
+       int ret, num_deficit, num_to_fill;
 
+       /* Refilling the whole RX ring buffer proves to be a bad idea. The
+        * reason is RX may take up significant amount of CPU cycles and starve
+        * other tasks, e.g. TX on an ethernet device while acting as a bridge
+        * with ath10k wlan interface. This ended up with very poor performance
+        * once CPU the host system was overwhelmed with RX on ath10k.
+        *
+        * By limiting the number of refills the replenishing occurs
+        * progressively. This in turns makes use of the fact tasklets are
+        * processed in FIFO order. This means actual RX processing can starve
+        * out refilling. If there's not enough buffers on RX ring FW will not
+        * report RX until it is refilled with enough buffers. This
+        * automatically balances load wrt to CPU power.
+        *
+        * This probably comes at a cost of lower maximum throughput but
+        * improves the avarage and stability. */
        spin_lock_bh(&htt->rx_ring.lock);
-       num_to_fill = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
+       num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
+       num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit);
+       num_deficit -= num_to_fill;
        ret = ath10k_htt_rx_ring_fill_n(htt, num_to_fill);
        if (ret == -ENOMEM) {
                /*
@@ -191,6 +213,8 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
                 */
                mod_timer(&htt->rx_ring.refill_retry_timer, jiffies +
                          msecs_to_jiffies(HTT_RX_RING_REFILL_RETRY_MS));
+       } else if (num_deficit > 0) {
+               tasklet_schedule(&htt->rx_replenish_task);
        }
        spin_unlock_bh(&htt->rx_ring.lock);
 }
@@ -212,6 +236,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt)
        int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
 
        del_timer_sync(&htt->rx_ring.refill_retry_timer);
+       tasklet_kill(&htt->rx_replenish_task);
 
        while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
                struct sk_buff *skb =
@@ -441,6 +466,12 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
        return msdu_chaining;
 }
 
+static void ath10k_htt_rx_replenish_task(unsigned long ptr)
+{
+       struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
+       ath10k_htt_rx_msdu_buff_replenish(htt);
+}
+
 int ath10k_htt_rx_attach(struct ath10k_htt *htt)
 {
        dma_addr_t paddr;
@@ -501,7 +532,10 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
        if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))
                goto err_fill_ring;
 
-       ath10k_dbg(ATH10K_DBG_HTT, "HTT RX ring size: %d, fill_level: %d\n",
+       tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
+                    (unsigned long)htt);
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
                   htt->rx_ring.size, htt->rx_ring.fill_level);
        return 0;
 
@@ -590,134 +624,144 @@ static bool ath10k_htt_rx_hdr_is_amsdu(struct ieee80211_hdr *hdr)
        return false;
 }
 
-static int ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
-                       struct htt_rx_info *info)
+struct rfc1042_hdr {
+       u8 llc_dsap;
+       u8 llc_ssap;
+       u8 llc_ctrl;
+       u8 snap_oui[3];
+       __be16 snap_type;
+} __packed;
+
+struct amsdu_subframe_hdr {
+       u8 dst[ETH_ALEN];
+       u8 src[ETH_ALEN];
+       __be16 len;
+} __packed;
+
+static void ath10k_htt_rx_amsdu(struct ath10k_htt *htt,
+                               struct htt_rx_info *info)
 {
        struct htt_rx_desc *rxd;
-       struct sk_buff *amsdu;
        struct sk_buff *first;
-       struct ieee80211_hdr *hdr;
        struct sk_buff *skb = info->skb;
        enum rx_msdu_decap_format fmt;
        enum htt_rx_mpdu_encrypt_type enctype;
+       struct ieee80211_hdr *hdr;
+       u8 hdr_buf[64], addr[ETH_ALEN], *qos;
        unsigned int hdr_len;
-       int crypto_len;
 
        rxd = (void *)skb->data - sizeof(*rxd);
-       fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-                       RX_MSDU_START_INFO1_DECAP_FORMAT);
        enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
                        RX_MPDU_START_INFO0_ENCRYPT_TYPE);
 
-       /* FIXME: No idea what assumptions are safe here. Need logs */
-       if ((fmt == RX_MSDU_DECAP_RAW && skb->next) ||
-           (fmt == RX_MSDU_DECAP_8023_SNAP_LLC)) {
-               ath10k_htt_rx_free_msdu_chain(skb->next);
-               skb->next = NULL;
-               return -ENOTSUPP;
-       }
+       hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
+       hdr_len = ieee80211_hdrlen(hdr->frame_control);
+       memcpy(hdr_buf, hdr, hdr_len);
+       hdr = (struct ieee80211_hdr *)hdr_buf;
 
-       /* A-MSDU max is a little less than 8K */
-       amsdu = dev_alloc_skb(8*1024);
-       if (!amsdu) {
-               ath10k_warn("A-MSDU allocation failed\n");
-               ath10k_htt_rx_free_msdu_chain(skb->next);
-               skb->next = NULL;
-               return -ENOMEM;
-       }
-
-       if (fmt >= RX_MSDU_DECAP_NATIVE_WIFI) {
-               int hdrlen;
-
-               hdr = (void *)rxd->rx_hdr_status;
-               hdrlen = ieee80211_hdrlen(hdr->frame_control);
-               memcpy(skb_put(amsdu, hdrlen), hdr, hdrlen);
-       }
+       /* FIXME: Hopefully this is a temporary measure.
+        *
+        * Reporting individual A-MSDU subframes means each reported frame
+        * shares the same sequence number.
+        *
+        * mac80211 drops frames it recognizes as duplicates, i.e.
+        * retransmission flag is set and sequence number matches sequence
+        * number from a previous frame (as per IEEE 802.11-2012: 9.3.2.10
+        * "Duplicate detection and recovery")
+        *
+        * To avoid frames being dropped clear retransmission flag for all
+        * received A-MSDUs.
+        *
+        * Worst case: actual duplicate frames will be reported but this should
+        * still be handled gracefully by other OSI/ISO layers. */
+       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_RETRY);
 
        first = skb;
        while (skb) {
                void *decap_hdr;
-               int decap_len = 0;
+               int len;
 
                rxd = (void *)skb->data - sizeof(*rxd);
                fmt = MS(__le32_to_cpu(rxd->msdu_start.info1),
-                               RX_MSDU_START_INFO1_DECAP_FORMAT);
+                        RX_MSDU_START_INFO1_DECAP_FORMAT);
                decap_hdr = (void *)rxd->rx_hdr_status;
 
-               if (skb == first) {
-                       /* We receive linked A-MSDU subframe skbuffs. The
-                        * first one contains the original 802.11 header (and
-                        * possible crypto param) in the RX descriptor. The
-                        * A-MSDU subframe header follows that. Each part is
-                        * aligned to 4 byte boundary. */
-
-                       hdr = (void *)amsdu->data;
-                       hdr_len = ieee80211_hdrlen(hdr->frame_control);
-                       crypto_len = ath10k_htt_rx_crypto_param_len(enctype);
-
-                       decap_hdr += roundup(hdr_len, 4);
-                       decap_hdr += roundup(crypto_len, 4);
-               }
+               skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);
 
-               if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) {
-                       /* Ethernet2 decap inserts ethernet header in place of
-                        * A-MSDU subframe header. */
-                       skb_pull(skb, 6 + 6 + 2);
-
-                       /* A-MSDU subframe header length */
-                       decap_len += 6 + 6 + 2;
-
-                       /* Ethernet2 decap also strips the LLC/SNAP so we need
-                        * to re-insert it. The LLC/SNAP follows A-MSDU
-                        * subframe header. */
-                       /* FIXME: Not all LLCs are 8 bytes long */
-                       decap_len += 8;
-
-                       memcpy(skb_put(amsdu, decap_len), decap_hdr, decap_len);
+               /* First frame in an A-MSDU chain has more decapped data. */
+               if (skb == first) {
+                       len = round_up(ieee80211_hdrlen(hdr->frame_control), 4);
+                       len += round_up(ath10k_htt_rx_crypto_param_len(enctype),
+                                       4);
+                       decap_hdr += len;
                }
 
-               if (fmt == RX_MSDU_DECAP_NATIVE_WIFI) {
-                       /* Native Wifi decap inserts regular 802.11 header
-                        * in place of A-MSDU subframe header. */
+               switch (fmt) {
+               case RX_MSDU_DECAP_RAW:
+                       /* remove trailing FCS */
+                       skb_trim(skb, skb->len - FCS_LEN);
+                       break;
+               case RX_MSDU_DECAP_NATIVE_WIFI:
+                       /* pull decapped header and copy DA */
                        hdr = (struct ieee80211_hdr *)skb->data;
-                       skb_pull(skb, ieee80211_hdrlen(hdr->frame_control));
+                       hdr_len = ieee80211_hdrlen(hdr->frame_control);
+                       memcpy(addr, ieee80211_get_DA(hdr), ETH_ALEN);
+                       skb_pull(skb, hdr_len);
 
-                       /* A-MSDU subframe header length */
-                       decap_len += 6 + 6 + 2;
+                       /* push original 802.11 header */
+                       hdr = (struct ieee80211_hdr *)hdr_buf;
+                       hdr_len = ieee80211_hdrlen(hdr->frame_control);
+                       memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
 
-                       memcpy(skb_put(amsdu, decap_len), decap_hdr, decap_len);
-               }
+                       /* original A-MSDU header has the bit set but we're
+                        * not including A-MSDU subframe header */
+                       hdr = (struct ieee80211_hdr *)skb->data;
+                       qos = ieee80211_get_qos_ctl(hdr);
+                       qos[0] &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
 
-               if (fmt == RX_MSDU_DECAP_RAW)
-                       skb_trim(skb, skb->len - 4); /* remove FCS */
+                       /* original 802.11 header has a different DA */
+                       memcpy(ieee80211_get_DA(hdr), addr, ETH_ALEN);
+                       break;
+               case RX_MSDU_DECAP_ETHERNET2_DIX:
+                       /* strip ethernet header and insert decapped 802.11
+                        * header, amsdu subframe header and rfc1042 header */
 
-               memcpy(skb_put(amsdu, skb->len), skb->data, skb->len);
+                       len = 0;
+                       len += sizeof(struct rfc1042_hdr);
+                       len += sizeof(struct amsdu_subframe_hdr);
 
-               /* A-MSDU subframes are padded to 4bytes
-                * but relative to first subframe, not the whole MPDU */
-               if (skb->next && ((decap_len + skb->len) & 3)) {
-                       int padlen = 4 - ((decap_len + skb->len) & 3);
-                       memset(skb_put(amsdu, padlen), 0, padlen);
+                       skb_pull(skb, sizeof(struct ethhdr));
+                       memcpy(skb_push(skb, len), decap_hdr, len);
+                       memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+                       break;
+               case RX_MSDU_DECAP_8023_SNAP_LLC:
+                       /* insert decapped 802.11 header making a singly
+                        * A-MSDU */
+                       memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+                       break;
                }
 
+               info->skb = skb;
+               info->encrypt_type = enctype;
                skb = skb->next;
-       }
+               info->skb->next = NULL;
 
-       info->skb = amsdu;
-       info->encrypt_type = enctype;
-
-       ath10k_htt_rx_free_msdu_chain(first);
+               ath10k_process_rx(htt->ar, info);
+       }
 
-       return 0;
+       /* FIXME: It might be nice to re-assemble the A-MSDU when there's a
+        * monitor interface active for sniffing purposes. */
 }
 
-static int ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
+static void ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
 {
        struct sk_buff *skb = info->skb;
        struct htt_rx_desc *rxd;
        struct ieee80211_hdr *hdr;
        enum rx_msdu_decap_format fmt;
        enum htt_rx_mpdu_encrypt_type enctype;
+       int hdr_len;
+       void *rfc1042;
 
        /* This shouldn't happen. If it does than it may be a FW bug. */
        if (skb->next) {
@@ -731,49 +775,53 @@ static int ath10k_htt_rx_msdu(struct ath10k_htt *htt, struct htt_rx_info *info)
                        RX_MSDU_START_INFO1_DECAP_FORMAT);
        enctype = MS(__le32_to_cpu(rxd->mpdu_start.info0),
                        RX_MPDU_START_INFO0_ENCRYPT_TYPE);
-       hdr = (void *)skb->data - RX_HTT_HDR_STATUS_LEN;
+       hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
+       hdr_len = ieee80211_hdrlen(hdr->frame_control);
+
+       skb->ip_summed = ath10k_htt_rx_get_csum_state(skb);
 
        switch (fmt) {
        case RX_MSDU_DECAP_RAW:
                /* remove trailing FCS */
-               skb_trim(skb, skb->len - 4);
+               skb_trim(skb, skb->len - FCS_LEN);
                break;
        case RX_MSDU_DECAP_NATIVE_WIFI:
-               /* nothing to do here */
+               /* Pull decapped header */
+               hdr = (struct ieee80211_hdr *)skb->data;
+               hdr_len = ieee80211_hdrlen(hdr->frame_control);
+               skb_pull(skb, hdr_len);
+
+               /* Push original header */
+               hdr = (struct ieee80211_hdr *)rxd->rx_hdr_status;
+               hdr_len = ieee80211_hdrlen(hdr->frame_control);
+               memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
                break;
        case RX_MSDU_DECAP_ETHERNET2_DIX:
-               /* macaddr[6] + macaddr[6] + ethertype[2] */
-               skb_pull(skb, 6 + 6 + 2);
-               break;
-       case RX_MSDU_DECAP_8023_SNAP_LLC:
-               /* macaddr[6] + macaddr[6] + len[2] */
-               /* we don't need this for non-A-MSDU */
-               skb_pull(skb, 6 + 6 + 2);
-               break;
-       }
+               /* strip ethernet header and insert decapped 802.11 header and
+                * rfc1042 header */
 
-       if (fmt == RX_MSDU_DECAP_ETHERNET2_DIX) {
-               void *llc;
-               int llclen;
+               rfc1042 = hdr;
+               rfc1042 += roundup(hdr_len, 4);
+               rfc1042 += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
 
-               llclen = 8;
-               llc  = hdr;
-               llc += roundup(ieee80211_hdrlen(hdr->frame_control), 4);
-               llc += roundup(ath10k_htt_rx_crypto_param_len(enctype), 4);
-
-               skb_push(skb, llclen);
-               memcpy(skb->data, llc, llclen);
-       }
+               skb_pull(skb, sizeof(struct ethhdr));
+               memcpy(skb_push(skb, sizeof(struct rfc1042_hdr)),
+                      rfc1042, sizeof(struct rfc1042_hdr));
+               memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+               break;
+       case RX_MSDU_DECAP_8023_SNAP_LLC:
+               /* remove A-MSDU subframe header and insert
+                * decapped 802.11 header. rfc1042 header is already there */
 
-       if (fmt >= RX_MSDU_DECAP_ETHERNET2_DIX) {
-               int len = ieee80211_hdrlen(hdr->frame_control);
-               skb_push(skb, len);
-               memcpy(skb->data, hdr, len);
+               skb_pull(skb, sizeof(struct amsdu_subframe_hdr));
+               memcpy(skb_push(skb, hdr_len), hdr, hdr_len);
+               break;
        }
 
        info->skb = skb;
        info->encrypt_type = enctype;
-       return 0;
+
+       ath10k_process_rx(htt->ar, info);
 }
 
 static bool ath10k_htt_rx_has_decrypt_err(struct sk_buff *skb)
@@ -845,8 +893,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
        int fw_desc_len;
        u8 *fw_desc;
        int i, j;
-       int ret;
-       int ip_summed;
 
        memset(&info, 0, sizeof(info));
 
@@ -921,11 +967,6 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                                continue;
                        }
 
-                       /* The skb is not yet processed and it may be
-                        * reallocated. Since the offload is in the original
-                        * skb extract the checksum now and assign it later */
-                       ip_summed = ath10k_htt_rx_get_csum_state(msdu_head);
-
                        info.skb     = msdu_head;
                        info.fcs_err = ath10k_htt_rx_has_fcs_err(msdu_head);
                        info.signal  = ATH10K_DEFAULT_NOISE_FLOOR;
@@ -938,28 +979,13 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
                        hdr = ath10k_htt_rx_skb_get_hdr(msdu_head);
 
                        if (ath10k_htt_rx_hdr_is_amsdu(hdr))
-                               ret = ath10k_htt_rx_amsdu(htt, &info);
+                               ath10k_htt_rx_amsdu(htt, &info);
                        else
-                               ret = ath10k_htt_rx_msdu(htt, &info);
-
-                       if (ret && !info.fcs_err) {
-                               ath10k_warn("error processing msdus %d\n", ret);
-                               dev_kfree_skb_any(info.skb);
-                               continue;
-                       }
-
-                       if (ath10k_htt_rx_hdr_is_amsdu((void *)info.skb->data))
-                               ath10k_dbg(ATH10K_DBG_HTT, "htt mpdu is amsdu\n");
-
-                       info.skb->ip_summed = ip_summed;
-
-                       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "htt mpdu: ",
-                                       info.skb->data, info.skb->len);
-                       ath10k_process_rx(htt->ar, &info);
+                               ath10k_htt_rx_msdu(htt, &info);
                }
        }
 
-       ath10k_htt_rx_msdu_buff_replenish(htt);
+       tasklet_schedule(&htt->rx_replenish_task);
 }
 
 static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,
@@ -1131,7 +1157,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                        break;
                }
 
-               ath10k_txrx_tx_completed(htt, &tx_done);
+               ath10k_txrx_tx_unref(htt, &tx_done);
                break;
        }
        case HTT_T2H_MSG_TYPE_TX_COMPL_IND: {
@@ -1165,7 +1191,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
                        msdu_id = resp->data_tx_completion.msdus[i];
                        tx_done.msdu_id = __le16_to_cpu(msdu_id);
-                       ath10k_txrx_tx_completed(htt, &tx_done);
+                       ath10k_txrx_tx_unref(htt, &tx_done);
                }
                break;
        }
@@ -1190,8 +1216,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
        case HTT_T2H_MSG_TYPE_TEST:
                /* FIX THIS */
                break;
-       case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
        case HTT_T2H_MSG_TYPE_STATS_CONF:
+               trace_ath10k_htt_stats(skb->data, skb->len);
+               break;
+       case HTT_T2H_MSG_TYPE_TX_INSPECT_IND:
        case HTT_T2H_MSG_TYPE_RX_ADDBA:
        case HTT_T2H_MSG_TYPE_RX_DELBA:
        case HTT_T2H_MSG_TYPE_RX_FLUSH:
index 656c2546b2949825a38b1b9b05d266e5af8bc5f0..3b93c6a01c6c618a7e2ae4a194a226be769984aa 100644 (file)
@@ -96,7 +96,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
        htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar,
                                                                   pipe);
 
-       ath10k_dbg(ATH10K_DBG_HTT, "htt tx max num pending tx %d\n",
+       ath10k_dbg(ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
                   htt->max_num_pending_tx);
 
        htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
@@ -117,7 +117,7 @@ int ath10k_htt_tx_attach(struct ath10k_htt *htt)
 
 static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
 {
-       struct sk_buff *txdesc;
+       struct htt_tx_done tx_done = {0};
        int msdu_id;
 
        /* No locks needed. Called after communication with the device has
@@ -127,18 +127,13 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
                if (!test_bit(msdu_id, htt->used_msdu_ids))
                        continue;
 
-               txdesc = htt->pending_tx[msdu_id];
-               if (!txdesc)
-                       continue;
-
                ath10k_dbg(ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
                           msdu_id);
 
-               if (ATH10K_SKB_CB(txdesc)->htt.refcount > 0)
-                       ATH10K_SKB_CB(txdesc)->htt.refcount = 1;
+               tx_done.discard = 1;
+               tx_done.msdu_id = msdu_id;
 
-               ATH10K_SKB_CB(txdesc)->htt.discard = true;
-               ath10k_txrx_tx_unref(htt, txdesc);
+               ath10k_txrx_tx_unref(htt, &tx_done);
        }
 }
 
@@ -152,26 +147,7 @@ void ath10k_htt_tx_detach(struct ath10k_htt *htt)
 
 void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 {
-       struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
-       struct ath10k_htt *htt = &ar->htt;
-
-       if (skb_cb->htt.is_conf) {
-               dev_kfree_skb_any(skb);
-               return;
-       }
-
-       if (skb_cb->is_aborted) {
-               skb_cb->htt.discard = true;
-
-               /* if the skbuff is aborted we need to make sure we'll free up
-                * the tx resources, we can't simply run tx_unref() 2 times
-                * because if htt tx completion came in earlier we'd access
-                * unallocated memory */
-               if (skb_cb->htt.refcount > 1)
-                       skb_cb->htt.refcount = 1;
-       }
-
-       ath10k_txrx_tx_unref(htt, skb);
+       dev_kfree_skb_any(skb);
 }
 
 int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
@@ -192,10 +168,48 @@ int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt)
        cmd = (struct htt_cmd *)skb->data;
        cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_VERSION_REQ;
 
-       ATH10K_SKB_CB(skb)->htt.is_conf = true;
+       ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
+       if (ret) {
+               dev_kfree_skb_any(skb);
+               return ret;
+       }
+
+       return 0;
+}
+
+int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie)
+{
+       struct htt_stats_req *req;
+       struct sk_buff *skb;
+       struct htt_cmd *cmd;
+       int len = 0, ret;
+
+       len += sizeof(cmd->hdr);
+       len += sizeof(cmd->stats_req);
+
+       skb = ath10k_htc_alloc_skb(len);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, len);
+       cmd = (struct htt_cmd *)skb->data;
+       cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_STATS_REQ;
+
+       req = &cmd->stats_req;
+
+       memset(req, 0, sizeof(*req));
+
+       /* currently we support only max 8 bit masks so no need to worry
+        * about endian support */
+       req->upload_types[0] = mask;
+       req->reset_types[0] = mask;
+       req->stat_type = HTT_STATS_REQ_CFG_STAT_TYPE_INVALID;
+       req->cookie_lsb = cpu_to_le32(cookie & 0xffffffff);
+       req->cookie_msb = cpu_to_le32((cookie & 0xffffffff00000000ULL) >> 32);
 
        ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
        if (ret) {
+               ath10k_warn("failed to send htt type stats request: %d", ret);
                dev_kfree_skb_any(skb);
                return ret;
        }
@@ -279,8 +293,6 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 
 #undef desc_offset
 
-       ATH10K_SKB_CB(skb)->htt.is_conf = true;
-
        ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
        if (ret) {
                dev_kfree_skb_any(skb);
@@ -293,10 +305,10 @@ int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt)
 int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 {
        struct device *dev = htt->ar->dev;
-       struct ath10k_skb_cb *skb_cb;
        struct sk_buff *txdesc = NULL;
        struct htt_cmd *cmd;
-       u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
+       struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
+       u8 vdev_id = skb_cb->htt.vdev_id;
        int len = 0;
        int msdu_id = -1;
        int res;
@@ -304,30 +316,30 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
        res = ath10k_htt_tx_inc_pending(htt);
        if (res)
-               return res;
+               goto err;
 
        len += sizeof(cmd->hdr);
        len += sizeof(cmd->mgmt_tx);
 
-       txdesc = ath10k_htc_alloc_skb(len);
-       if (!txdesc) {
-               res = -ENOMEM;
-               goto err;
-       }
-
        spin_lock_bh(&htt->tx_lock);
-       msdu_id = ath10k_htt_tx_alloc_msdu_id(htt);
-       if (msdu_id < 0) {
+       res = ath10k_htt_tx_alloc_msdu_id(htt);
+       if (res < 0) {
                spin_unlock_bh(&htt->tx_lock);
-               res = msdu_id;
-               goto err;
+               goto err_tx_dec;
        }
-       htt->pending_tx[msdu_id] = txdesc;
+       msdu_id = res;
+       htt->pending_tx[msdu_id] = msdu;
        spin_unlock_bh(&htt->tx_lock);
 
+       txdesc = ath10k_htc_alloc_skb(len);
+       if (!txdesc) {
+               res = -ENOMEM;
+               goto err_free_msdu_id;
+       }
+
        res = ath10k_skb_map(dev, msdu);
        if (res)
-               goto err;
+               goto err_free_txdesc;
 
        skb_put(txdesc, len);
        cmd = (struct htt_cmd *)txdesc->data;
@@ -339,31 +351,27 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        memcpy(cmd->mgmt_tx.hdr, msdu->data,
               min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN));
 
-       /* refcount is decremented by HTC and HTT completions until it reaches
-        * zero and is freed */
-       skb_cb = ATH10K_SKB_CB(txdesc);
-       skb_cb->htt.msdu_id = msdu_id;
-       skb_cb->htt.refcount = 2;
-       skb_cb->htt.msdu = msdu;
+       skb_cb->htt.frag_len = 0;
+       skb_cb->htt.pad_len = 0;
 
        res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
        if (res)
-               goto err;
+               goto err_unmap_msdu;
 
        return 0;
 
-err:
+err_unmap_msdu:
        ath10k_skb_unmap(dev, msdu);
-
-       if (txdesc)
-               dev_kfree_skb_any(txdesc);
-       if (msdu_id >= 0) {
-               spin_lock_bh(&htt->tx_lock);
-               htt->pending_tx[msdu_id] = NULL;
-               ath10k_htt_tx_free_msdu_id(htt, msdu_id);
-               spin_unlock_bh(&htt->tx_lock);
-       }
+err_free_txdesc:
+       dev_kfree_skb_any(txdesc);
+err_free_msdu_id:
+       spin_lock_bh(&htt->tx_lock);
+       htt->pending_tx[msdu_id] = NULL;
+       ath10k_htt_tx_free_msdu_id(htt, msdu_id);
+       spin_unlock_bh(&htt->tx_lock);
+err_tx_dec:
        ath10k_htt_tx_dec_pending(htt);
+err:
        return res;
 }
 
@@ -373,13 +381,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        struct htt_cmd *cmd;
        struct htt_data_tx_desc_frag *tx_frags;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
-       struct ath10k_skb_cb *skb_cb;
+       struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
        struct sk_buff *txdesc = NULL;
-       struct sk_buff *txfrag = NULL;
+       bool use_frags;
        u8 vdev_id = ATH10K_SKB_CB(msdu)->htt.vdev_id;
        u8 tid;
-       int prefetch_len, desc_len, frag_len;
-       dma_addr_t frags_paddr;
+       int prefetch_len, desc_len;
        int msdu_id = -1;
        int res;
        u8 flags0;
@@ -387,69 +394,82 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
        res = ath10k_htt_tx_inc_pending(htt);
        if (res)
-               return res;
+               goto err;
+
+       spin_lock_bh(&htt->tx_lock);
+       res = ath10k_htt_tx_alloc_msdu_id(htt);
+       if (res < 0) {
+               spin_unlock_bh(&htt->tx_lock);
+               goto err_tx_dec;
+       }
+       msdu_id = res;
+       htt->pending_tx[msdu_id] = msdu;
+       spin_unlock_bh(&htt->tx_lock);
 
        prefetch_len = min(htt->prefetch_len, msdu->len);
        prefetch_len = roundup(prefetch_len, 4);
 
        desc_len = sizeof(cmd->hdr) + sizeof(cmd->data_tx) + prefetch_len;
-       frag_len = sizeof(*tx_frags) * 2;
 
        txdesc = ath10k_htc_alloc_skb(desc_len);
        if (!txdesc) {
                res = -ENOMEM;
-               goto err;
+               goto err_free_msdu_id;
        }
 
-       txfrag = dev_alloc_skb(frag_len);
-       if (!txfrag) {
-               res = -ENOMEM;
-               goto err;
-       }
+       /* Since HTT 3.0 there is no separate mgmt tx command. However in case
+        * of mgmt tx using TX_FRM there is not tx fragment list. Instead of tx
+        * fragment list host driver specifies directly frame pointer. */
+       use_frags = htt->target_version_major < 3 ||
+                   !ieee80211_is_mgmt(hdr->frame_control);
 
        if (!IS_ALIGNED((unsigned long)txdesc->data, 4)) {
                ath10k_warn("htt alignment check failed. dropping packet.\n");
                res = -EIO;
-               goto err;
+               goto err_free_txdesc;
        }
 
-       spin_lock_bh(&htt->tx_lock);
-       msdu_id = ath10k_htt_tx_alloc_msdu_id(htt);
-       if (msdu_id < 0) {
-               spin_unlock_bh(&htt->tx_lock);
-               res = msdu_id;
-               goto err;
+       if (use_frags) {
+               skb_cb->htt.frag_len = sizeof(*tx_frags) * 2;
+               skb_cb->htt.pad_len = (unsigned long)msdu->data -
+                                     round_down((unsigned long)msdu->data, 4);
+
+               skb_push(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
+       } else {
+               skb_cb->htt.frag_len = 0;
+               skb_cb->htt.pad_len = 0;
        }
-       htt->pending_tx[msdu_id] = txdesc;
-       spin_unlock_bh(&htt->tx_lock);
 
        res = ath10k_skb_map(dev, msdu);
        if (res)
-               goto err;
-
-       /* tx fragment list must be terminated with zero-entry */
-       skb_put(txfrag, frag_len);
-       tx_frags = (struct htt_data_tx_desc_frag *)txfrag->data;
-       tx_frags[0].paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr);
-       tx_frags[0].len   = __cpu_to_le32(msdu->len);
-       tx_frags[1].paddr = __cpu_to_le32(0);
-       tx_frags[1].len   = __cpu_to_le32(0);
-
-       res = ath10k_skb_map(dev, txfrag);
-       if (res)
-               goto err;
+               goto err_pull_txfrag;
+
+       if (use_frags) {
+               dma_sync_single_for_cpu(dev, skb_cb->paddr, msdu->len,
+                                       DMA_TO_DEVICE);
+
+               /* tx fragment list must be terminated with zero-entry */
+               tx_frags = (struct htt_data_tx_desc_frag *)msdu->data;
+               tx_frags[0].paddr = __cpu_to_le32(skb_cb->paddr +
+                                                 skb_cb->htt.frag_len +
+                                                 skb_cb->htt.pad_len);
+               tx_frags[0].len   = __cpu_to_le32(msdu->len -
+                                                 skb_cb->htt.frag_len -
+                                                 skb_cb->htt.pad_len);
+               tx_frags[1].paddr = __cpu_to_le32(0);
+               tx_frags[1].len   = __cpu_to_le32(0);
+
+               dma_sync_single_for_device(dev, skb_cb->paddr, msdu->len,
+                                          DMA_TO_DEVICE);
+       }
 
-       ath10k_dbg(ATH10K_DBG_HTT, "txfrag 0x%llx msdu 0x%llx\n",
-                  (unsigned long long) ATH10K_SKB_CB(txfrag)->paddr,
+       ath10k_dbg(ATH10K_DBG_HTT, "msdu 0x%llx\n",
                   (unsigned long long) ATH10K_SKB_CB(msdu)->paddr);
-       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "txfrag: ",
-                       txfrag->data, frag_len);
        ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "msdu: ",
                        msdu->data, msdu->len);
 
        skb_put(txdesc, desc_len);
        cmd = (struct htt_cmd *)txdesc->data;
-       memset(cmd, 0, desc_len);
 
        tid = ATH10K_SKB_CB(msdu)->htt.tid;
 
@@ -459,8 +479,13 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        if (!ieee80211_has_protected(hdr->frame_control))
                flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT;
        flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT;
-       flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
-                    HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+
+       if (use_frags)
+               flags0 |= SM(ATH10K_HW_TXRX_NATIVE_WIFI,
+                            HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
+       else
+               flags0 |= SM(ATH10K_HW_TXRX_MGMT,
+                            HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE);
 
        flags1  = 0;
        flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
@@ -468,45 +493,37 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
        flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
        flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
 
-       frags_paddr = ATH10K_SKB_CB(txfrag)->paddr;
-
        cmd->hdr.msg_type        = HTT_H2T_MSG_TYPE_TX_FRM;
        cmd->data_tx.flags0      = flags0;
        cmd->data_tx.flags1      = __cpu_to_le16(flags1);
-       cmd->data_tx.len         = __cpu_to_le16(msdu->len);
+       cmd->data_tx.len         = __cpu_to_le16(msdu->len -
+                                                skb_cb->htt.frag_len -
+                                                skb_cb->htt.pad_len);
        cmd->data_tx.id          = __cpu_to_le16(msdu_id);
-       cmd->data_tx.frags_paddr = __cpu_to_le32(frags_paddr);
+       cmd->data_tx.frags_paddr = __cpu_to_le32(skb_cb->paddr);
        cmd->data_tx.peerid      = __cpu_to_le32(HTT_INVALID_PEERID);
 
-       memcpy(cmd->data_tx.prefetch, msdu->data, prefetch_len);
-
-       /* refcount is decremented by HTC and HTT completions until it reaches
-        * zero and is freed */
-       skb_cb = ATH10K_SKB_CB(txdesc);
-       skb_cb->htt.msdu_id = msdu_id;
-       skb_cb->htt.refcount = 2;
-       skb_cb->htt.txfrag = txfrag;
-       skb_cb->htt.msdu = msdu;
+       memcpy(cmd->data_tx.prefetch, hdr, prefetch_len);
 
        res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc);
        if (res)
-               goto err;
+               goto err_unmap_msdu;
 
        return 0;
-err:
-       if (txfrag)
-               ath10k_skb_unmap(dev, txfrag);
-       if (txdesc)
-               dev_kfree_skb_any(txdesc);
-       if (txfrag)
-               dev_kfree_skb_any(txfrag);
-       if (msdu_id >= 0) {
-               spin_lock_bh(&htt->tx_lock);
-               htt->pending_tx[msdu_id] = NULL;
-               ath10k_htt_tx_free_msdu_id(htt, msdu_id);
-               spin_unlock_bh(&htt->tx_lock);
-       }
-       ath10k_htt_tx_dec_pending(htt);
+
+err_unmap_msdu:
        ath10k_skb_unmap(dev, msdu);
+err_pull_txfrag:
+       skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
+err_free_txdesc:
+       dev_kfree_skb_any(txdesc);
+err_free_msdu_id:
+       spin_lock_bh(&htt->tx_lock);
+       htt->pending_tx[msdu_id] = NULL;
+       ath10k_htt_tx_free_msdu_id(htt, msdu_id);
+       spin_unlock_bh(&htt->tx_lock);
+err_tx_dec:
+       ath10k_htt_tx_dec_pending(htt);
+err:
        return res;
 }
index 44ed5af0a2043f19122685a2f0ff548bbc89feea..8c1be76859220fa1b57d2c9965bbdbb2fc749222 100644 (file)
 #define SUPPORTED_FW_MAJOR     1
 #define SUPPORTED_FW_MINOR     0
 #define SUPPORTED_FW_RELEASE   0
-#define SUPPORTED_FW_BUILD     629
+#define SUPPORTED_FW_BUILD     636
 
-/* QCA988X 1.0 definitions */
-#define QCA988X_HW_1_0_VERSION         0x4000002c
-#define QCA988X_HW_1_0_FW_DIR          "ath10k/QCA988X/hw1.0"
-#define QCA988X_HW_1_0_FW_FILE         "firmware.bin"
-#define QCA988X_HW_1_0_OTP_FILE                "otp.bin"
-#define QCA988X_HW_1_0_BOARD_DATA_FILE "board.bin"
-#define QCA988X_HW_1_0_PATCH_LOAD_ADDR 0x1234
+/* QCA988X 1.0 definitions (unsupported) */
+#define QCA988X_HW_1_0_CHIP_ID_REV     0x0
 
 /* QCA988X 2.0 definitions */
 #define QCA988X_HW_2_0_VERSION         0x4100016c
+#define QCA988X_HW_2_0_CHIP_ID_REV     0x2
 #define QCA988X_HW_2_0_FW_DIR          "ath10k/QCA988X/hw2.0"
 #define QCA988X_HW_2_0_FW_FILE         "firmware.bin"
 #define QCA988X_HW_2_0_OTP_FILE                "otp.bin"
@@ -53,6 +49,9 @@ enum ath10k_hw_txrx_mode {
        ATH10K_HW_TXRX_RAW = 0,
        ATH10K_HW_TXRX_NATIVE_WIFI = 1,
        ATH10K_HW_TXRX_ETHERNET = 2,
+
+       /* Valid for HTT >= 3.0. Used for management frames in TX_FRM. */
+       ATH10K_HW_TXRX_MGMT = 3,
 };
 
 enum ath10k_mcast2ucast_mode {
@@ -75,7 +74,11 @@ enum ath10k_mcast2ucast_mode {
 #define TARGET_RX_CHAIN_MASK                   (BIT(0) | BIT(1) | BIT(2))
 #define TARGET_RX_TIMEOUT_LO_PRI               100
 #define TARGET_RX_TIMEOUT_HI_PRI               40
-#define TARGET_RX_DECAP_MODE                   ATH10K_HW_TXRX_ETHERNET
+
+/* Native Wifi decap mode is used to align IP frames to 4-byte boundaries and
+ * avoid a very expensive re-alignment in mac80211. */
+#define TARGET_RX_DECAP_MODE                   ATH10K_HW_TXRX_NATIVE_WIFI
+
 #define TARGET_SCAN_MAX_PENDING_REQS           4
 #define TARGET_BMISS_OFFLOAD_MAX_VDEV          3
 #define TARGET_ROAM_OFFLOAD_MAX_VDEV           3
@@ -169,6 +172,10 @@ enum ath10k_mcast2ucast_mode {
 #define SOC_LPO_CAL_ENABLE_LSB                 20
 #define SOC_LPO_CAL_ENABLE_MASK                        0x00100000
 
+#define SOC_CHIP_ID_ADDRESS                    0x000000ec
+#define SOC_CHIP_ID_REV_LSB                    8
+#define SOC_CHIP_ID_REV_MASK                   0x00000f00
+
 #define WLAN_RESET_CONTROL_COLD_RST_MASK       0x00000008
 #define WLAN_RESET_CONTROL_WARM_RST_MASK       0x00000004
 #define WLAN_SYSTEM_SLEEP_DISABLE_LSB          0
index cf2ba4d850c9bf0cedb8d123c0e05cccb821e6a2..99a9bad3f398cc87238b1d1c37868b7585a795b3 100644 (file)
@@ -460,6 +460,11 @@ static int ath10k_vdev_start(struct ath10k_vif *arvif)
                arg.ssid_len = arvif->vif->bss_conf.ssid_len;
        }
 
+       ath10k_dbg(ATH10K_DBG_MAC,
+                  "mac vdev %d start center_freq %d phymode %s\n",
+                  arg.vdev_id, arg.channel.freq,
+                  ath10k_wmi_phymode_str(arg.channel.mode));
+
        ret = ath10k_wmi_vdev_start(ar, &arg);
        if (ret) {
                ath10k_warn("WMI vdev start failed: ret %d\n", ret);
@@ -503,13 +508,10 @@ static int ath10k_monitor_start(struct ath10k *ar, int vdev_id)
 {
        struct ieee80211_channel *channel = ar->hw->conf.chandef.chan;
        struct wmi_vdev_start_request_arg arg = {};
-       enum nl80211_channel_type type;
        int ret = 0;
 
        lockdep_assert_held(&ar->conf_mutex);
 
-       type = cfg80211_get_chandef_type(&ar->hw->conf.chandef);
-
        arg.vdev_id = vdev_id;
        arg.channel.freq = channel->center_freq;
        arg.channel.band_center_freq1 = ar->hw->conf.chandef.center_freq1;
@@ -607,7 +609,7 @@ static int ath10k_monitor_create(struct ath10k *ar)
                goto vdev_fail;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "Monitor interface created, vdev id: %d\n",
+       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d created\n",
                   ar->monitor_vdev_id);
 
        ar->monitor_present = true;
@@ -639,7 +641,7 @@ static int ath10k_monitor_destroy(struct ath10k *ar)
        ar->free_vdev_map |= 1 << (ar->monitor_vdev_id);
        ar->monitor_present = false;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "Monitor interface destroyed, vdev id: %d\n",
+       ath10k_dbg(ATH10K_DBG_MAC, "mac monitor vdev %d deleted\n",
                   ar->monitor_vdev_id);
        return ret;
 }
@@ -668,7 +670,7 @@ static void ath10k_control_beaconing(struct ath10k_vif *arvif,
                            arvif->vdev_id);
                return;
        }
-       ath10k_dbg(ATH10K_DBG_MAC, "VDEV: %d up\n", arvif->vdev_id);
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d up\n", arvif->vdev_id);
 }
 
 static void ath10k_control_ibss(struct ath10k_vif *arvif,
@@ -752,14 +754,14 @@ static void ath10k_ps_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
                psmode = WMI_STA_PS_MODE_DISABLED;
        }
 
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d psmode %s\n",
+                  arvif->vdev_id, psmode ? "enable" : "disable");
+
        ar_iter->ret = ath10k_wmi_set_psmode(ar_iter->ar, arvif->vdev_id,
                                             psmode);
        if (ar_iter->ret)
                ath10k_warn("Failed to set PS Mode: %d for VDEV: %d\n",
                            psmode, arvif->vdev_id);
-       else
-               ath10k_dbg(ATH10K_DBG_MAC, "Set PS Mode: %d for VDEV: %d\n",
-                          psmode, arvif->vdev_id);
 }
 
 /**********************/
@@ -949,7 +951,8 @@ static void ath10k_peer_assoc_h_ht(struct ath10k *ar,
        arg->peer_ht_rates.num_rates = n;
        arg->peer_num_spatial_streams = max((n+7) / 8, 1);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mcs cnt %d nss %d\n",
+       ath10k_dbg(ATH10K_DBG_MAC, "mac ht peer %pM mcs cnt %d nss %d\n",
+                  arg->addr,
                   arg->peer_ht_rates.num_rates,
                   arg->peer_num_spatial_streams);
 }
@@ -969,11 +972,11 @@ static void ath10k_peer_assoc_h_qos_ap(struct ath10k *ar,
                arg->peer_flags |= WMI_PEER_QOS;
 
        if (sta->wme && sta->uapsd_queues) {
-               ath10k_dbg(ATH10K_DBG_MAC, "uapsd_queues: 0x%X, max_sp: %d\n",
+               ath10k_dbg(ATH10K_DBG_MAC, "mac uapsd_queues 0x%x max_sp %d\n",
                           sta->uapsd_queues, sta->max_sp);
 
                arg->peer_flags |= WMI_PEER_APSD;
-               arg->peer_flags |= WMI_RC_UAPSD_FLAG;
+               arg->peer_rate_caps |= WMI_RC_UAPSD_FLAG;
 
                if (sta->uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
                        uapsd |= WMI_AP_PS_UAPSD_AC3_DELIVERY_EN |
@@ -1048,7 +1051,8 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
        arg->peer_vht_rates.tx_mcs_set =
                __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer\n");
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
+                  sta->addr, arg->peer_max_mpdu, arg->peer_flags);
 }
 
 static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
@@ -1076,8 +1080,6 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
 {
        enum wmi_phy_mode phymode = MODE_UNKNOWN;
 
-       /* FIXME: add VHT */
-
        switch (ar->hw->conf.chandef.chan->band) {
        case IEEE80211_BAND_2GHZ:
                if (sta->ht_cap.ht_supported) {
@@ -1091,7 +1093,17 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
 
                break;
        case IEEE80211_BAND_5GHZ:
-               if (sta->ht_cap.ht_supported) {
+               /*
+                * Check VHT first.
+                */
+               if (sta->vht_cap.vht_supported) {
+                       if (sta->bandwidth == IEEE80211_STA_RX_BW_80)
+                               phymode = MODE_11AC_VHT80;
+                       else if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+                               phymode = MODE_11AC_VHT40;
+                       else if (sta->bandwidth == IEEE80211_STA_RX_BW_20)
+                               phymode = MODE_11AC_VHT20;
+               } else if (sta->ht_cap.ht_supported) {
                        if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
                                phymode = MODE_11NA_HT40;
                        else
@@ -1105,6 +1117,9 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
                break;
        }
 
+       ath10k_dbg(ATH10K_DBG_MAC, "mac peer %pM phymode %s\n",
+                  sta->addr, ath10k_wmi_phymode_str(phymode));
+
        arg->peer_phymode = phymode;
        WARN_ON(phymode == MODE_UNKNOWN);
 }
@@ -1162,15 +1177,15 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
 
        rcu_read_unlock();
 
+       ath10k_dbg(ATH10K_DBG_MAC,
+                  "mac vdev %d up (associated) bssid %pM aid %d\n",
+                  arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
+
        ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, bss_conf->aid,
                                 bss_conf->bssid);
        if (ret)
                ath10k_warn("VDEV: %d up failed: ret %d\n",
                            arvif->vdev_id, ret);
-       else
-               ath10k_dbg(ATH10K_DBG_MAC,
-                          "VDEV: %d associated, BSSID: %pM, AID: %d\n",
-                          arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
 }
 
 /*
@@ -1191,10 +1206,11 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
         * No idea why this happens, even though VDEV-DOWN is supposed
         * to be analogous to link down, so just stop the VDEV.
         */
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d stop (disassociated\n",
+                  arvif->vdev_id);
+
+       /* FIXME: check return value */
        ret = ath10k_vdev_stop(arvif);
-       if (!ret)
-               ath10k_dbg(ATH10K_DBG_MAC, "VDEV: %d stopped\n",
-                          arvif->vdev_id);
 
        /*
         * If we don't call VDEV-DOWN after VDEV-STOP FW will remain active and
@@ -1203,12 +1219,10 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
         * interfaces as it expects there is no rx when no interface is
         * running.
         */
-       ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
-       if (ret)
-               ath10k_dbg(ATH10K_DBG_MAC, "VDEV: %d ath10k_wmi_vdev_down failed (%d)\n",
-                          arvif->vdev_id, ret);
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d down\n", arvif->vdev_id);
 
-       ath10k_wmi_flush_tx(ar);
+       /* FIXME: why don't we print error if wmi call fails? */
+       ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
 
        arvif->def_wep_key_index = 0;
 }
@@ -1333,8 +1347,8 @@ static int ath10k_update_channel_list(struct ath10k *ar)
                                continue;
 
                        ath10k_dbg(ATH10K_DBG_WMI,
-                                  "%s: [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
-                                  __func__, ch - arg.channels, arg.n_channels,
+                                  "mac channel [%zd/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
+                                   ch - arg.channels, arg.n_channels,
                                   ch->freq, ch->max_power, ch->max_reg_power,
                                   ch->max_antenna_gain, ch->mode);
 
@@ -1421,10 +1435,6 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
        struct ieee80211_key_conf *key = info->control.hw_key;
        int ret;
 
-       /* TODO AP mode should be implemented */
-       if (vif->type != NL80211_IFTYPE_STATION)
-               return;
-
        if (!ieee80211_has_protected(hdr->frame_control))
                return;
 
@@ -1438,7 +1448,8 @@ static void ath10k_tx_h_update_wep_key(struct sk_buff *skb)
        if (key->keyidx == arvif->def_wep_key_index)
                return;
 
-       ath10k_dbg(ATH10K_DBG_MAC, "new wep keyidx will be %d\n", key->keyidx);
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d keyidx %d\n",
+                  arvif->vdev_id, key->keyidx);
 
        ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                        WMI_VDEV_PARAM_DEF_KEYID,
@@ -1480,6 +1491,12 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        int ret;
 
+       if (ar->htt.target_version_major >= 3) {
+               /* Since HTT 3.0 there is no separate mgmt tx command */
+               ret = ath10k_htt_tx(&ar->htt, skb);
+               goto exit;
+       }
+
        if (ieee80211_is_mgmt(hdr->frame_control))
                ret = ath10k_htt_mgmt_tx(&ar->htt, skb);
        else if (ieee80211_is_nullfunc(hdr->frame_control))
@@ -1491,6 +1508,7 @@ static void ath10k_tx_htt(struct ath10k *ar, struct sk_buff *skb)
        else
                ret = ath10k_htt_tx(&ar->htt, skb);
 
+exit:
        if (ret) {
                ath10k_warn("tx failed (%d). dropping packet.\n", ret);
                ieee80211_free_txskb(ar->hw, skb);
@@ -1534,7 +1552,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
 
                mutex_lock(&ar->conf_mutex);
 
-               ath10k_dbg(ATH10K_DBG_MAC, "processing offchannel skb %p\n",
+               ath10k_dbg(ATH10K_DBG_MAC, "mac offchannel skb %p\n",
                           skb);
 
                hdr = (struct ieee80211_hdr *)skb->data;
@@ -1546,6 +1564,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
                spin_unlock_bh(&ar->data_lock);
 
                if (peer)
+                       /* FIXME: should this use ath10k_warn()? */
                        ath10k_dbg(ATH10K_DBG_MAC, "peer %pM on vdev %d already present\n",
                                   peer_addr, vdev_id);
 
@@ -1643,8 +1662,6 @@ static int ath10k_abort_scan(struct ath10k *ar)
                return -EIO;
        }
 
-       ath10k_wmi_flush_tx(ar);
-
        ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
        if (ret == 0)
                ath10k_warn("timed out while waiting for scan to stop\n");
@@ -1678,10 +1695,6 @@ static int ath10k_start_scan(struct ath10k *ar,
        if (ret)
                return ret;
 
-       /* make sure we submit the command so the completion
-       * timeout makes sense */
-       ath10k_wmi_flush_tx(ar);
-
        ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
        if (ret == 0) {
                ath10k_abort_scan(ar);
@@ -1727,8 +1740,10 @@ static void ath10k_tx(struct ieee80211_hw *hw,
        /* we must calculate tid before we apply qos workaround
         * as we'd lose the qos control field */
        tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
-       if (ieee80211_is_data_qos(hdr->frame_control) &&
-           is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
+       if (ieee80211_is_mgmt(hdr->frame_control)) {
+               tid = HTT_DATA_TX_EXT_TID_MGMT;
+       } else if (ieee80211_is_data_qos(hdr->frame_control) &&
+                  is_unicast_ether_addr(ieee80211_get_DA(hdr))) {
                u8 *qc = ieee80211_get_qos_ctl(hdr);
                tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
        }
@@ -1742,7 +1757,7 @@ static void ath10k_tx(struct ieee80211_hw *hw,
                ath10k_tx_h_seq_no(skb);
        }
 
-       memset(ATH10K_SKB_CB(skb), 0, sizeof(*ATH10K_SKB_CB(skb)));
+       ATH10K_SKB_CB(skb)->htt.is_offchan = false;
        ATH10K_SKB_CB(skb)->htt.vdev_id = vdev_id;
        ATH10K_SKB_CB(skb)->htt.tid = tid;
 
@@ -1884,7 +1899,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
        mutex_lock(&ar->conf_mutex);
 
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
-               ath10k_dbg(ATH10K_DBG_MAC, "Config channel %d mhz\n",
+               ath10k_dbg(ATH10K_DBG_MAC, "mac config channel %d mhz\n",
                           conf->chandef.chan->center_freq);
                spin_lock_bh(&ar->data_lock);
                ar->rx_channel = conf->chandef.chan;
@@ -1901,7 +1916,6 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
                        ret = ath10k_monitor_destroy(ar);
        }
 
-       ath10k_wmi_flush_tx(ar);
        mutex_unlock(&ar->conf_mutex);
        return ret;
 }
@@ -1973,7 +1987,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
                break;
        }
 
-       ath10k_dbg(ATH10K_DBG_MAC, "Add interface: id %d type %d subtype %d\n",
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev create %d (add interface) type %d subtype %d\n",
                   arvif->vdev_id, arvif->vdev_type, arvif->vdev_subtype);
 
        ret = ath10k_wmi_vdev_create(ar, arvif->vdev_id, arvif->vdev_type,
@@ -2052,7 +2066,12 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&ar->conf_mutex);
 
-       ath10k_dbg(ATH10K_DBG_MAC, "Remove interface: id %d\n", arvif->vdev_id);
+       spin_lock_bh(&ar->data_lock);
+       if (arvif->beacon) {
+               dev_kfree_skb_any(arvif->beacon);
+               arvif->beacon = NULL;
+       }
+       spin_unlock_bh(&ar->data_lock);
 
        ar->free_vdev_map |= 1 << (arvif->vdev_id);
 
@@ -2064,6 +2083,9 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
                kfree(arvif->u.ap.noa_data);
        }
 
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev delete %d (remove interface)\n",
+                  arvif->vdev_id);
+
        ret = ath10k_wmi_vdev_delete(ar, arvif->vdev_id);
        if (ret)
                ath10k_warn("WMI vdev delete failed: %d\n", ret);
@@ -2105,18 +2127,20 @@ static void ath10k_configure_filter(struct ieee80211_hw *hw,
 
        if ((ar->filter_flags & FIF_PROMISC_IN_BSS) &&
            !ar->monitor_enabled) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d start\n",
+                          ar->monitor_vdev_id);
+
                ret = ath10k_monitor_start(ar, ar->monitor_vdev_id);
                if (ret)
                        ath10k_warn("Unable to start monitor mode\n");
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC, "Monitor mode started\n");
        } else if (!(ar->filter_flags & FIF_PROMISC_IN_BSS) &&
                   ar->monitor_enabled) {
+               ath10k_dbg(ATH10K_DBG_MAC, "mac monitor %d stop\n",
+                          ar->monitor_vdev_id);
+
                ret = ath10k_monitor_stop(ar);
                if (ret)
                        ath10k_warn("Unable to stop monitor mode\n");
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC, "Monitor mode stopped\n");
        }
 
        mutex_unlock(&ar->conf_mutex);
@@ -2141,41 +2165,41 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                                WMI_VDEV_PARAM_BEACON_INTERVAL,
                                                arvif->beacon_interval);
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac vdev %d beacon_interval %d\n",
+                          arvif->vdev_id, arvif->beacon_interval);
+
                if (ret)
                        ath10k_warn("Failed to set beacon interval for VDEV: %d\n",
                                    arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Beacon interval: %d set for VDEV: %d\n",
-                                  arvif->beacon_interval, arvif->vdev_id);
        }
 
        if (changed & BSS_CHANGED_BEACON) {
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "vdev %d set beacon tx mode to staggered\n",
+                          arvif->vdev_id);
+
                ret = ath10k_wmi_pdev_set_param(ar,
                                                WMI_PDEV_PARAM_BEACON_TX_MODE,
                                                WMI_BEACON_STAGGERED_MODE);
                if (ret)
                        ath10k_warn("Failed to set beacon mode for VDEV: %d\n",
                                    arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Set staggered beacon mode for VDEV: %d\n",
-                                  arvif->vdev_id);
        }
 
        if (changed & BSS_CHANGED_BEACON_INFO) {
                arvif->dtim_period = info->dtim_period;
 
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac vdev %d dtim_period %d\n",
+                          arvif->vdev_id, arvif->dtim_period);
+
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                                WMI_VDEV_PARAM_DTIM_PERIOD,
                                                arvif->dtim_period);
                if (ret)
                        ath10k_warn("Failed to set dtim period for VDEV: %d\n",
                                    arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Set dtim period: %d for VDEV: %d\n",
-                                  arvif->dtim_period, arvif->vdev_id);
        }
 
        if (changed & BSS_CHANGED_SSID &&
@@ -2188,16 +2212,15 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
 
        if (changed & BSS_CHANGED_BSSID) {
                if (!is_zero_ether_addr(info->bssid)) {
+                       ath10k_dbg(ATH10K_DBG_MAC,
+                                  "mac vdev %d create peer %pM\n",
+                                  arvif->vdev_id, info->bssid);
+
                        ret = ath10k_peer_create(ar, arvif->vdev_id,
                                                 info->bssid);
                        if (ret)
                                ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
                                            info->bssid, arvif->vdev_id);
-                       else
-                               ath10k_dbg(ATH10K_DBG_MAC,
-                                          "Added peer: %pM for VDEV: %d\n",
-                                          info->bssid, arvif->vdev_id);
-
 
                        if (vif->type == NL80211_IFTYPE_STATION) {
                                /*
@@ -2207,11 +2230,12 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                                memcpy(arvif->u.sta.bssid, info->bssid,
                                       ETH_ALEN);
 
+                               ath10k_dbg(ATH10K_DBG_MAC,
+                                          "mac vdev %d start %pM\n",
+                                          arvif->vdev_id, info->bssid);
+
+                               /* FIXME: check return value */
                                ret = ath10k_vdev_start(arvif);
-                               if (!ret)
-                                       ath10k_dbg(ATH10K_DBG_MAC,
-                                                  "VDEV: %d started with BSSID: %pM\n",
-                                                  arvif->vdev_id, info->bssid);
                        }
 
                        /*
@@ -2235,16 +2259,15 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                else
                        cts_prot = 0;
 
+               ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d cts_prot %d\n",
+                          arvif->vdev_id, cts_prot);
+
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                                WMI_VDEV_PARAM_ENABLE_RTSCTS,
                                                cts_prot);
                if (ret)
                        ath10k_warn("Failed to set CTS prot for VDEV: %d\n",
                                    arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Set CTS prot: %d for VDEV: %d\n",
-                                  cts_prot, arvif->vdev_id);
        }
 
        if (changed & BSS_CHANGED_ERP_SLOT) {
@@ -2255,16 +2278,15 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                else
                        slottime = WMI_VDEV_SLOT_TIME_LONG; /* 20us */
 
+               ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d slot_time %d\n",
+                          arvif->vdev_id, slottime);
+
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                                WMI_VDEV_PARAM_SLOT_TIME,
                                                slottime);
                if (ret)
                        ath10k_warn("Failed to set erp slot for VDEV: %d\n",
                                    arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Set slottime: %d for VDEV: %d\n",
-                                  slottime, arvif->vdev_id);
        }
 
        if (changed & BSS_CHANGED_ERP_PREAMBLE) {
@@ -2274,16 +2296,16 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
                else
                        preamble = WMI_VDEV_PREAMBLE_LONG;
 
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac vdev %d preamble %dn",
+                          arvif->vdev_id, preamble);
+
                ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
                                                WMI_VDEV_PARAM_PREAMBLE,
                                                preamble);
                if (ret)
                        ath10k_warn("Failed to set preamble for VDEV: %d\n",
                                    arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Set preamble: %d for VDEV: %d\n",
-                                  preamble, arvif->vdev_id);
        }
 
        if (changed & BSS_CHANGED_ASSOC) {
@@ -2474,27 +2496,26 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                /*
                 * New station addition.
                 */
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac vdev %d peer create %pM (new sta)\n",
+                          arvif->vdev_id, sta->addr);
+
                ret = ath10k_peer_create(ar, arvif->vdev_id, sta->addr);
                if (ret)
                        ath10k_warn("Failed to add peer: %pM for VDEV: %d\n",
                                    sta->addr, arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Added peer: %pM for VDEV: %d\n",
-                                  sta->addr, arvif->vdev_id);
        } else if ((old_state == IEEE80211_STA_NONE &&
                    new_state == IEEE80211_STA_NOTEXIST)) {
                /*
                 * Existing station deletion.
                 */
+               ath10k_dbg(ATH10K_DBG_MAC,
+                          "mac vdev %d peer delete %pM (sta gone)\n",
+                          arvif->vdev_id, sta->addr);
                ret = ath10k_peer_delete(ar, arvif->vdev_id, sta->addr);
                if (ret)
                        ath10k_warn("Failed to delete peer: %pM for VDEV: %d\n",
                                    sta->addr, arvif->vdev_id);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Removed peer: %pM for VDEV: %d\n",
-                                  sta->addr, arvif->vdev_id);
 
                if (vif->type == NL80211_IFTYPE_STATION)
                        ath10k_bss_disassoc(hw, vif);
@@ -2505,14 +2526,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                /*
                 * New association.
                 */
+               ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM associated\n",
+                          sta->addr);
+
                ret = ath10k_station_assoc(ar, arvif, sta);
                if (ret)
                        ath10k_warn("Failed to associate station: %pM\n",
                                    sta->addr);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Station %pM moved to assoc state\n",
-                                  sta->addr);
        } else if (old_state == IEEE80211_STA_ASSOC &&
                   new_state == IEEE80211_STA_AUTH &&
                   (vif->type == NL80211_IFTYPE_AP ||
@@ -2520,14 +2540,13 @@ static int ath10k_sta_state(struct ieee80211_hw *hw,
                /*
                 * Disassociation.
                 */
+               ath10k_dbg(ATH10K_DBG_MAC, "mac sta %pM disassociated\n",
+                          sta->addr);
+
                ret = ath10k_station_disassoc(ar, arvif, sta);
                if (ret)
                        ath10k_warn("Failed to disassociate station: %pM\n",
                                    sta->addr);
-               else
-                       ath10k_dbg(ATH10K_DBG_MAC,
-                                  "Station %pM moved to disassociated state\n",
-                                  sta->addr);
        }
 
        mutex_unlock(&ar->conf_mutex);
@@ -2747,14 +2766,13 @@ static void ath10k_set_rts_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
                return;
 
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d rts_threshold %d\n",
+                  arvif->vdev_id, rts);
+
        ar_iter->ret = ath10k_mac_set_rts(arvif, rts);
        if (ar_iter->ret)
                ath10k_warn("Failed to set RTS threshold for VDEV: %d\n",
                            arvif->vdev_id);
-       else
-               ath10k_dbg(ATH10K_DBG_MAC,
-                          "Set RTS threshold: %d for VDEV: %d\n",
-                          rts, arvif->vdev_id);
 }
 
 static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
@@ -2789,14 +2807,13 @@ static void ath10k_set_frag_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        if (ar_iter->ar->state == ATH10K_STATE_RESTARTED)
                return;
 
+       ath10k_dbg(ATH10K_DBG_MAC, "mac vdev %d fragmentation_threshold %d\n",
+                  arvif->vdev_id, frag);
+
        ar_iter->ret = ath10k_mac_set_frag(arvif, frag);
        if (ar_iter->ret)
                ath10k_warn("Failed to set frag threshold for VDEV: %d\n",
                            arvif->vdev_id);
-       else
-               ath10k_dbg(ATH10K_DBG_MAC,
-                          "Set frag threshold: %d for VDEV: %d\n",
-                          frag, arvif->vdev_id);
 }
 
 static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
@@ -2836,8 +2853,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
                        bool empty;
 
                        spin_lock_bh(&ar->htt.tx_lock);
-                       empty = bitmap_empty(ar->htt.used_msdu_ids,
-                                            ar->htt.max_num_pending_tx);
+                       empty = (ar->htt.num_pending_tx == 0);
                        spin_unlock_bh(&ar->htt.tx_lock);
 
                        skip = (ar->state == ATH10K_STATE_WEDGED);
@@ -3326,6 +3342,10 @@ int ath10k_mac_register(struct ath10k *ar)
                        IEEE80211_HW_WANT_MONITOR_VIF |
                        IEEE80211_HW_AP_LINK_PS;
 
+       /* MSDU can have HTT TX fragment pushed in front. The additional 4
+        * bytes is used for padding/alignment if necessary. */
+       ar->hw->extra_tx_headroom += sizeof(struct htt_data_tx_desc_frag)*2 + 4;
+
        if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
                ar->hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS;
 
index e2f9ef50b1bd3999f6b7cc2989c24e407e9bd72a..dff23d97bed065d984efac3c481ce2b06fa6e675 100644 (file)
@@ -36,11 +36,9 @@ static unsigned int ath10k_target_ps;
 module_param(ath10k_target_ps, uint, 0644);
 MODULE_PARM_DESC(ath10k_target_ps, "Enable ath10k Target (SoC) PS option");
 
-#define QCA988X_1_0_DEVICE_ID  (0xabcd)
 #define QCA988X_2_0_DEVICE_ID  (0x003c)
 
 static DEFINE_PCI_DEVICE_TABLE(ath10k_pci_id_table) = {
-       { PCI_VDEVICE(ATHEROS, QCA988X_1_0_DEVICE_ID) }, /* PCI-E QCA988X V1 */
        { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
        {0}
 };
@@ -50,9 +48,9 @@ static int ath10k_pci_diag_read_access(struct ath10k *ar, u32 address,
 
 static void ath10k_pci_process_ce(struct ath10k *ar);
 static int ath10k_pci_post_rx(struct ath10k *ar);
-static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
+static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
                                             int num);
-static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info);
+static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info);
 static void ath10k_pci_stop_ce(struct ath10k *ar);
 static void ath10k_pci_device_reset(struct ath10k *ar);
 static int ath10k_pci_reset_target(struct ath10k *ar);
@@ -60,43 +58,145 @@ static int ath10k_pci_start_intr(struct ath10k *ar);
 static void ath10k_pci_stop_intr(struct ath10k *ar);
 
 static const struct ce_attr host_ce_config_wlan[] = {
-       /* host->target HTC control and raw streams */
-       { /* CE0 */ CE_ATTR_FLAGS, 0, 16, 256, 0, NULL,},
-       /* could be moved to share CE3 */
-       /* target->host HTT + HTC control */
-       { /* CE1 */ CE_ATTR_FLAGS, 0, 0, 512, 512, NULL,},
-       /* target->host WMI */
-       { /* CE2 */ CE_ATTR_FLAGS, 0, 0, 2048, 32, NULL,},
-       /* host->target WMI */
-       { /* CE3 */ CE_ATTR_FLAGS, 0, 32, 2048, 0, NULL,},
-       /* host->target HTT */
-       { /* CE4 */ CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 0,
-                   CE_HTT_H2T_MSG_SRC_NENTRIES, 256, 0, NULL,},
-       /* unused */
-       { /* CE5 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
-       /* Target autonomous hif_memcpy */
-       { /* CE6 */ CE_ATTR_FLAGS, 0, 0, 0, 0, NULL,},
-       /* ce_diag, the Diagnostic Window */
-       { /* CE7 */ CE_ATTR_FLAGS, 0, 2, DIAG_TRANSFER_LIMIT, 2, NULL,},
+       /* CE0: host->target HTC control and raw streams */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 16,
+               .src_sz_max = 256,
+               .dest_nentries = 0,
+       },
+
+       /* CE1: target->host HTT + HTC control */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 512,
+               .dest_nentries = 512,
+       },
+
+       /* CE2: target->host WMI */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 2048,
+               .dest_nentries = 32,
+       },
+
+       /* CE3: host->target WMI */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 32,
+               .src_sz_max = 2048,
+               .dest_nentries = 0,
+       },
+
+       /* CE4: host->target HTT */
+       {
+               .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
+               .src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES,
+               .src_sz_max = 256,
+               .dest_nentries = 0,
+       },
+
+       /* CE5: unused */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+
+       /* CE6: target autonomous hif_memcpy */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 0,
+               .src_sz_max = 0,
+               .dest_nentries = 0,
+       },
+
+       /* CE7: ce_diag, the Diagnostic Window */
+       {
+               .flags = CE_ATTR_FLAGS,
+               .src_nentries = 2,
+               .src_sz_max = DIAG_TRANSFER_LIMIT,
+               .dest_nentries = 2,
+       },
 };
 
 /* Target firmware's Copy Engine configuration. */
 static const struct ce_pipe_config target_ce_config_wlan[] = {
-       /* host->target HTC control and raw streams */
-       { /* CE0 */ 0, PIPEDIR_OUT, 32, 256, CE_ATTR_FLAGS, 0,},
-       /* target->host HTT + HTC control */
-       { /* CE1 */ 1, PIPEDIR_IN, 32, 512, CE_ATTR_FLAGS, 0,},
-       /* target->host WMI */
-       { /* CE2 */ 2, PIPEDIR_IN, 32, 2048, CE_ATTR_FLAGS, 0,},
-       /* host->target WMI */
-       { /* CE3 */ 3, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
-       /* host->target HTT */
-       { /* CE4 */ 4, PIPEDIR_OUT, 256, 256, CE_ATTR_FLAGS, 0,},
+       /* CE0: host->target HTC control and raw streams */
+       {
+               .pipenum = 0,
+               .pipedir = PIPEDIR_OUT,
+               .nentries = 32,
+               .nbytes_max = 256,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
+       /* CE1: target->host HTT + HTC control */
+       {
+               .pipenum = 1,
+               .pipedir = PIPEDIR_IN,
+               .nentries = 32,
+               .nbytes_max = 512,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
+       /* CE2: target->host WMI */
+       {
+               .pipenum = 2,
+               .pipedir = PIPEDIR_IN,
+               .nentries = 32,
+               .nbytes_max = 2048,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
+       /* CE3: host->target WMI */
+       {
+               .pipenum = 3,
+               .pipedir = PIPEDIR_OUT,
+               .nentries = 32,
+               .nbytes_max = 2048,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
+       /* CE4: host->target HTT */
+       {
+               .pipenum = 4,
+               .pipedir = PIPEDIR_OUT,
+               .nentries = 256,
+               .nbytes_max = 256,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
        /* NB: 50% of src nentries, since tx has 2 frags */
-       /* unused */
-       { /* CE5 */ 5, PIPEDIR_OUT, 32, 2048, CE_ATTR_FLAGS, 0,},
-       /* Reserved for target autonomous hif_memcpy */
-       { /* CE6 */ 6, PIPEDIR_INOUT, 32, 4096, CE_ATTR_FLAGS, 0,},
+
+       /* CE5: unused */
+       {
+               .pipenum = 5,
+               .pipedir = PIPEDIR_OUT,
+               .nentries = 32,
+               .nbytes_max = 2048,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
+       /* CE6: Reserved for target autonomous hif_memcpy */
+       {
+               .pipenum = 6,
+               .pipedir = PIPEDIR_INOUT,
+               .nentries = 32,
+               .nbytes_max = 4096,
+               .flags = CE_ATTR_FLAGS,
+               .reserved = 0,
+       },
+
        /* CE7 used only by Host */
 };
 
@@ -114,7 +214,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data,
        unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
        unsigned int id;
        unsigned int flags;
-       struct ce_state *ce_diag;
+       struct ath10k_ce_pipe *ce_diag;
        /* Host buffer address in CE space */
        u32 ce_data;
        dma_addr_t ce_data_base = 0;
@@ -278,7 +378,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
        unsigned int completed_nbytes, orig_nbytes, remaining_bytes;
        unsigned int id;
        unsigned int flags;
-       struct ce_state *ce_diag;
+       struct ath10k_ce_pipe *ce_diag;
        void *data_buf = NULL;
        u32 ce_data;    /* Host buffer address in CE space */
        dma_addr_t ce_data_base = 0;
@@ -437,7 +537,7 @@ static void ath10k_pci_wait(struct ath10k *ar)
                ath10k_warn("Unable to wakeup target\n");
 }
 
-void ath10k_do_pci_wake(struct ath10k *ar)
+int ath10k_do_pci_wake(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        void __iomem *pci_addr = ar_pci->mem;
@@ -453,18 +553,19 @@ void ath10k_do_pci_wake(struct ath10k *ar)
        atomic_inc(&ar_pci->keep_awake_count);
 
        if (ar_pci->verified_awake)
-               return;
+               return 0;
 
        for (;;) {
                if (ath10k_pci_target_is_awake(ar)) {
                        ar_pci->verified_awake = true;
-                       break;
+                       return 0;
                }
 
                if (tot_delay > PCIE_WAKE_TIMEOUT) {
-                       ath10k_warn("target takes too long to wake up (awake count %d)\n",
+                       ath10k_warn("target took longer %d us to wake up (awake count %d)\n",
+                                   PCIE_WAKE_TIMEOUT,
                                    atomic_read(&ar_pci->keep_awake_count));
-                       break;
+                       return -ETIMEDOUT;
                }
 
                udelay(curr_delay);
@@ -493,7 +594,7 @@ void ath10k_do_pci_sleep(struct ath10k *ar)
  * FIXME: Handle OOM properly.
  */
 static inline
-struct ath10k_pci_compl *get_free_compl(struct hif_ce_pipe_info *pipe_info)
+struct ath10k_pci_compl *get_free_compl(struct ath10k_pci_pipe *pipe_info)
 {
        struct ath10k_pci_compl *compl = NULL;
 
@@ -511,39 +612,28 @@ exit:
 }
 
 /* Called by lower (CE) layer when a send to Target completes. */
-static void ath10k_pci_ce_send_done(struct ce_state *ce_state,
-                                   void *transfer_context,
-                                   u32 ce_data,
-                                   unsigned int nbytes,
-                                   unsigned int transfer_id)
+static void ath10k_pci_ce_send_done(struct ath10k_ce_pipe *ce_state)
 {
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info =  &ar_pci->pipe_info[ce_state->id];
+       struct ath10k_pci_pipe *pipe_info =  &ar_pci->pipe_info[ce_state->id];
        struct ath10k_pci_compl *compl;
-       bool process = false;
-
-       do {
-               /*
-                * For the send completion of an item in sendlist, just
-                * increment num_sends_allowed. The upper layer callback will
-                * be triggered when last fragment is done with send.
-                */
-               if (transfer_context == CE_SENDLIST_ITEM_CTXT) {
-                       spin_lock_bh(&pipe_info->pipe_lock);
-                       pipe_info->num_sends_allowed++;
-                       spin_unlock_bh(&pipe_info->pipe_lock);
-                       continue;
-               }
+       void *transfer_context;
+       u32 ce_data;
+       unsigned int nbytes;
+       unsigned int transfer_id;
 
+       while (ath10k_ce_completed_send_next(ce_state, &transfer_context,
+                                            &ce_data, &nbytes,
+                                            &transfer_id) == 0) {
                compl = get_free_compl(pipe_info);
                if (!compl)
                        break;
 
-               compl->send_or_recv = HIF_CE_COMPLETE_SEND;
+               compl->state = ATH10K_PCI_COMPL_SEND;
                compl->ce_state = ce_state;
                compl->pipe_info = pipe_info;
-               compl->transfer_context = transfer_context;
+               compl->skb = transfer_context;
                compl->nbytes = nbytes;
                compl->transfer_id = transfer_id;
                compl->flags = 0;
@@ -554,46 +644,36 @@ static void ath10k_pci_ce_send_done(struct ce_state *ce_state,
                spin_lock_bh(&ar_pci->compl_lock);
                list_add_tail(&compl->list, &ar_pci->compl_process);
                spin_unlock_bh(&ar_pci->compl_lock);
-
-               process = true;
-       } while (ath10k_ce_completed_send_next(ce_state,
-                                                          &transfer_context,
-                                                          &ce_data, &nbytes,
-                                                          &transfer_id) == 0);
-
-       /*
-        * If only some of the items within a sendlist have completed,
-        * don't invoke completion processing until the entire sendlist
-        * has been sent.
-        */
-       if (!process)
-               return;
+       }
 
        ath10k_pci_process_ce(ar);
 }
 
 /* Called by lower (CE) layer when data is received from the Target. */
-static void ath10k_pci_ce_recv_data(struct ce_state *ce_state,
-                                   void *transfer_context, u32 ce_data,
-                                   unsigned int nbytes,
-                                   unsigned int transfer_id,
-                                   unsigned int flags)
+static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
 {
        struct ath10k *ar = ce_state->ar;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info =  &ar_pci->pipe_info[ce_state->id];
+       struct ath10k_pci_pipe *pipe_info =  &ar_pci->pipe_info[ce_state->id];
        struct ath10k_pci_compl *compl;
        struct sk_buff *skb;
+       void *transfer_context;
+       u32 ce_data;
+       unsigned int nbytes;
+       unsigned int transfer_id;
+       unsigned int flags;
 
-       do {
+       while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,
+                                            &ce_data, &nbytes, &transfer_id,
+                                            &flags) == 0) {
                compl = get_free_compl(pipe_info);
                if (!compl)
                        break;
 
-               compl->send_or_recv = HIF_CE_COMPLETE_RECV;
+               compl->state = ATH10K_PCI_COMPL_RECV;
                compl->ce_state = ce_state;
                compl->pipe_info = pipe_info;
-               compl->transfer_context = transfer_context;
+               compl->skb = transfer_context;
                compl->nbytes = nbytes;
                compl->transfer_id = transfer_id;
                compl->flags = flags;
@@ -608,12 +688,7 @@ static void ath10k_pci_ce_recv_data(struct ce_state *ce_state,
                spin_lock_bh(&ar_pci->compl_lock);
                list_add_tail(&compl->list, &ar_pci->compl_process);
                spin_unlock_bh(&ar_pci->compl_lock);
-
-       } while (ath10k_ce_completed_recv_next(ce_state,
-                                                          &transfer_context,
-                                                          &ce_data, &nbytes,
-                                                          &transfer_id,
-                                                          &flags) == 0);
+       }
 
        ath10k_pci_process_ce(ar);
 }
@@ -625,15 +700,12 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
 {
        struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(nbuf);
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info = &(ar_pci->pipe_info[pipe_id]);
-       struct ce_state *ce_hdl = pipe_info->ce_hdl;
-       struct ce_sendlist sendlist;
+       struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe_id]);
+       struct ath10k_ce_pipe *ce_hdl = pipe_info->ce_hdl;
        unsigned int len;
        u32 flags = 0;
        int ret;
 
-       memset(&sendlist, 0, sizeof(struct ce_sendlist));
-
        len = min(bytes, nbuf->len);
        bytes -= len;
 
@@ -648,8 +720,6 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
                        "ath10k tx: data: ",
                        nbuf->data, nbuf->len);
 
-       ath10k_ce_sendlist_buf_add(&sendlist, skb_cb->paddr, len, flags);
-
        /* Make sure we have resources to handle this request */
        spin_lock_bh(&pipe_info->pipe_lock);
        if (!pipe_info->num_sends_allowed) {
@@ -660,7 +730,8 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
        pipe_info->num_sends_allowed--;
        spin_unlock_bh(&pipe_info->pipe_lock);
 
-       ret = ath10k_ce_sendlist_send(ce_hdl, nbuf, &sendlist, transfer_id);
+       ret = ath10k_ce_sendlist_send(ce_hdl, nbuf, transfer_id,
+                                     skb_cb->paddr, len, flags);
        if (ret)
                ath10k_warn("CE send failed: %p\n", nbuf);
 
@@ -670,7 +741,7 @@ static int ath10k_pci_hif_send_head(struct ath10k *ar, u8 pipe_id,
 static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info = &(ar_pci->pipe_info[pipe]);
+       struct ath10k_pci_pipe *pipe_info = &(ar_pci->pipe_info[pipe]);
        int ret;
 
        spin_lock_bh(&pipe_info->pipe_lock);
@@ -764,9 +835,9 @@ static void ath10k_pci_hif_set_callbacks(struct ath10k *ar,
 static int ath10k_pci_start_ce(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_state *ce_diag = ar_pci->ce_diag;
+       struct ath10k_ce_pipe *ce_diag = ar_pci->ce_diag;
        const struct ce_attr *attr;
-       struct hif_ce_pipe_info *pipe_info;
+       struct ath10k_pci_pipe *pipe_info;
        struct ath10k_pci_compl *compl;
        int i, pipe_num, completions, disable_interrupts;
 
@@ -805,15 +876,14 @@ static int ath10k_pci_start_ce(struct ath10k *ar)
                        continue;
 
                for (i = 0; i < completions; i++) {
-                       compl = kmalloc(sizeof(struct ath10k_pci_compl),
-                                       GFP_KERNEL);
+                       compl = kmalloc(sizeof(*compl), GFP_KERNEL);
                        if (!compl) {
                                ath10k_warn("No memory for completion state\n");
                                ath10k_pci_stop_ce(ar);
                                return -ENOMEM;
                        }
 
-                       compl->send_or_recv = HIF_CE_COMPLETE_FREE;
+                       compl->state = ATH10K_PCI_COMPL_FREE;
                        list_add_tail(&compl->list, &pipe_info->compl_free);
                }
        }
@@ -840,7 +910,7 @@ static void ath10k_pci_stop_ce(struct ath10k *ar)
         * their associated resources */
        spin_lock_bh(&ar_pci->compl_lock);
        list_for_each_entry(compl, &ar_pci->compl_process, list) {
-               skb = (struct sk_buff *)compl->transfer_context;
+               skb = compl->skb;
                ATH10K_SKB_CB(skb)->is_aborted = true;
        }
        spin_unlock_bh(&ar_pci->compl_lock);
@@ -850,7 +920,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
        struct ath10k_pci_compl *compl, *tmp;
-       struct hif_ce_pipe_info *pipe_info;
+       struct ath10k_pci_pipe *pipe_info;
        struct sk_buff *netbuf;
        int pipe_num;
 
@@ -861,7 +931,7 @@ static void ath10k_pci_cleanup_ce(struct ath10k *ar)
 
        list_for_each_entry_safe(compl, tmp, &ar_pci->compl_process, list) {
                list_del(&compl->list);
-               netbuf = (struct sk_buff *)compl->transfer_context;
+               netbuf = compl->skb;
                dev_kfree_skb_any(netbuf);
                kfree(compl);
        }
@@ -912,12 +982,14 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
                list_del(&compl->list);
                spin_unlock_bh(&ar_pci->compl_lock);
 
-               if (compl->send_or_recv == HIF_CE_COMPLETE_SEND) {
+               switch (compl->state) {
+               case ATH10K_PCI_COMPL_SEND:
                        cb->tx_completion(ar,
-                                         compl->transfer_context,
+                                         compl->skb,
                                          compl->transfer_id);
                        send_done = 1;
-               } else {
+                       break;
+               case ATH10K_PCI_COMPL_RECV:
                        ret = ath10k_pci_post_rx_pipe(compl->pipe_info, 1);
                        if (ret) {
                                ath10k_warn("Unable to post recv buffer for pipe: %d\n",
@@ -925,7 +997,7 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
                                break;
                        }
 
-                       skb = (struct sk_buff *)compl->transfer_context;
+                       skb = compl->skb;
                        nbytes = compl->nbytes;
 
                        ath10k_dbg(ATH10K_DBG_PCI,
@@ -944,9 +1016,17 @@ static void ath10k_pci_process_ce(struct ath10k *ar)
                                            nbytes,
                                            skb->len + skb_tailroom(skb));
                        }
+                       break;
+               case ATH10K_PCI_COMPL_FREE:
+                       ath10k_warn("free completion cannot be processed\n");
+                       break;
+               default:
+                       ath10k_warn("invalid completion state (%d)\n",
+                                   compl->state);
+                       break;
                }
 
-               compl->send_or_recv = HIF_CE_COMPLETE_FREE;
+               compl->state = ATH10K_PCI_COMPL_FREE;
 
                /*
                 * Add completion back to the pipe's free list.
@@ -1037,12 +1117,12 @@ static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
                                                 &dl_is_polled);
 }
 
-static int ath10k_pci_post_rx_pipe(struct hif_ce_pipe_info *pipe_info,
+static int ath10k_pci_post_rx_pipe(struct ath10k_pci_pipe *pipe_info,
                                   int num)
 {
        struct ath10k *ar = pipe_info->hif_ce_state;
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_state *ce_state = pipe_info->ce_hdl;
+       struct ath10k_ce_pipe *ce_state = pipe_info->ce_hdl;
        struct sk_buff *skb;
        dma_addr_t ce_data;
        int i, ret = 0;
@@ -1097,7 +1177,7 @@ err:
 static int ath10k_pci_post_rx(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info;
+       struct ath10k_pci_pipe *pipe_info;
        const struct ce_attr *attr;
        int pipe_num, ret = 0;
 
@@ -1147,11 +1227,11 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
        return 0;
 }
 
-static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
+static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
 {
        struct ath10k *ar;
        struct ath10k_pci *ar_pci;
-       struct ce_state *ce_hdl;
+       struct ath10k_ce_pipe *ce_hdl;
        u32 buf_sz;
        struct sk_buff *netbuf;
        u32 ce_data;
@@ -1179,11 +1259,11 @@ static void ath10k_pci_rx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
        }
 }
 
-static void ath10k_pci_tx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
+static void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pipe_info)
 {
        struct ath10k *ar;
        struct ath10k_pci *ar_pci;
-       struct ce_state *ce_hdl;
+       struct ath10k_ce_pipe *ce_hdl;
        struct sk_buff *netbuf;
        u32 ce_data;
        unsigned int nbytes;
@@ -1206,15 +1286,14 @@ static void ath10k_pci_tx_pipe_cleanup(struct hif_ce_pipe_info *pipe_info)
 
        while (ath10k_ce_cancel_send_next(ce_hdl, (void **)&netbuf,
                                          &ce_data, &nbytes, &id) == 0) {
-               if (netbuf != CE_SENDLIST_ITEM_CTXT)
-                       /*
-                        * Indicate the completion to higer layer to free
-                        * the buffer
-                        */
-                       ATH10K_SKB_CB(netbuf)->is_aborted = true;
-                       ar_pci->msg_callbacks_current.tx_completion(ar,
-                                                                   netbuf,
-                                                                   id);
+               /*
+                * Indicate the completion to higer layer to free
+                * the buffer
+                */
+               ATH10K_SKB_CB(netbuf)->is_aborted = true;
+               ar_pci->msg_callbacks_current.tx_completion(ar,
+                                                           netbuf,
+                                                           id);
        }
 }
 
@@ -1232,7 +1311,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
        int pipe_num;
 
        for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
-               struct hif_ce_pipe_info *pipe_info;
+               struct ath10k_pci_pipe *pipe_info;
 
                pipe_info = &ar_pci->pipe_info[pipe_num];
                ath10k_pci_rx_pipe_cleanup(pipe_info);
@@ -1243,7 +1322,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
 static void ath10k_pci_ce_deinit(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info;
+       struct ath10k_pci_pipe *pipe_info;
        int pipe_num;
 
        for (pipe_num = 0; pipe_num < ar_pci->ce_count; pipe_num++) {
@@ -1293,8 +1372,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
                                           void *resp, u32 *resp_len)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct ce_state *ce_tx = ar_pci->pipe_info[BMI_CE_NUM_TO_TARG].ce_hdl;
-       struct ce_state *ce_rx = ar_pci->pipe_info[BMI_CE_NUM_TO_HOST].ce_hdl;
+       struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
+       struct ath10k_pci_pipe *pci_rx = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST];
+       struct ath10k_ce_pipe *ce_tx = pci_tx->ce_hdl;
+       struct ath10k_ce_pipe *ce_rx = pci_rx->ce_hdl;
        dma_addr_t req_paddr = 0;
        dma_addr_t resp_paddr = 0;
        struct bmi_xfer xfer = {};
@@ -1378,13 +1459,16 @@ err_dma:
        return ret;
 }
 
-static void ath10k_pci_bmi_send_done(struct ce_state *ce_state,
-                                    void *transfer_context,
-                                    u32 data,
-                                    unsigned int nbytes,
-                                    unsigned int transfer_id)
+static void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state)
 {
-       struct bmi_xfer *xfer = transfer_context;
+       struct bmi_xfer *xfer;
+       u32 ce_data;
+       unsigned int nbytes;
+       unsigned int transfer_id;
+
+       if (ath10k_ce_completed_send_next(ce_state, (void **)&xfer, &ce_data,
+                                         &nbytes, &transfer_id))
+               return;
 
        if (xfer->wait_for_resp)
                return;
@@ -1392,14 +1476,17 @@ static void ath10k_pci_bmi_send_done(struct ce_state *ce_state,
        complete(&xfer->done);
 }
 
-static void ath10k_pci_bmi_recv_data(struct ce_state *ce_state,
-                                    void *transfer_context,
-                                    u32 data,
-                                    unsigned int nbytes,
-                                    unsigned int transfer_id,
-                                    unsigned int flags)
+static void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state)
 {
-       struct bmi_xfer *xfer = transfer_context;
+       struct bmi_xfer *xfer;
+       u32 ce_data;
+       unsigned int nbytes;
+       unsigned int transfer_id;
+       unsigned int flags;
+
+       if (ath10k_ce_completed_recv_next(ce_state, (void **)&xfer, &ce_data,
+                                         &nbytes, &transfer_id, &flags))
+               return;
 
        if (!xfer->wait_for_resp) {
                ath10k_warn("unexpected: BMI data received; ignoring\n");
@@ -1679,7 +1766,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
 static int ath10k_pci_ce_init(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       struct hif_ce_pipe_info *pipe_info;
+       struct ath10k_pci_pipe *pipe_info;
        const struct ce_attr *attr;
        int pipe_num;
 
@@ -1895,7 +1982,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 
 static void ath10k_pci_ce_tasklet(unsigned long ptr)
 {
-       struct hif_ce_pipe_info *pipe = (struct hif_ce_pipe_info *)ptr;
+       struct ath10k_pci_pipe *pipe = (struct ath10k_pci_pipe *)ptr;
        struct ath10k_pci *ar_pci = pipe->ar_pci;
 
        ath10k_ce_per_engine_service(ar_pci->ar, pipe->pipe_num);
@@ -2212,18 +2299,13 @@ static int ath10k_pci_reset_target(struct ath10k *ar)
 
 static void ath10k_pci_device_reset(struct ath10k *ar)
 {
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       void __iomem *mem = ar_pci->mem;
        int i;
        u32 val;
 
        if (!SOC_GLOBAL_RESET_ADDRESS)
                return;
 
-       if (!mem)
-               return;
-
-       ath10k_pci_reg_write32(mem, PCIE_SOC_WAKE_ADDRESS,
+       ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS,
                               PCIE_SOC_WAKE_V_MASK);
        for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
                if (ath10k_pci_target_is_awake(ar))
@@ -2232,12 +2314,12 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
        }
 
        /* Put Target, including PCIe, into RESET. */
-       val = ath10k_pci_reg_read32(mem, SOC_GLOBAL_RESET_ADDRESS);
+       val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS);
        val |= 1;
-       ath10k_pci_reg_write32(mem, SOC_GLOBAL_RESET_ADDRESS, val);
+       ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
 
        for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-               if (ath10k_pci_reg_read32(mem, RTC_STATE_ADDRESS) &
+               if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
                                          RTC_STATE_COLD_RESET_MASK)
                        break;
                msleep(1);
@@ -2245,16 +2327,16 @@ static void ath10k_pci_device_reset(struct ath10k *ar)
 
        /* Pull Target, including PCIe, out of RESET. */
        val &= ~1;
-       ath10k_pci_reg_write32(mem, SOC_GLOBAL_RESET_ADDRESS, val);
+       ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val);
 
        for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) {
-               if (!(ath10k_pci_reg_read32(mem, RTC_STATE_ADDRESS) &
+               if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) &
                                            RTC_STATE_COLD_RESET_MASK))
                        break;
                msleep(1);
        }
 
-       ath10k_pci_reg_write32(mem, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET);
+       ath10k_pci_reg_write32(ar, PCIE_SOC_WAKE_ADDRESS, PCIE_SOC_WAKE_RESET);
 }
 
 static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
@@ -2267,13 +2349,10 @@ static void ath10k_pci_dump_features(struct ath10k_pci *ar_pci)
 
                switch (i) {
                case ATH10K_PCI_FEATURE_MSI_X:
-                       ath10k_dbg(ATH10K_DBG_PCI, "device supports MSI-X\n");
-                       break;
-               case ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND:
-                       ath10k_dbg(ATH10K_DBG_PCI, "QCA988X_1.0 workaround enabled\n");
+                       ath10k_dbg(ATH10K_DBG_BOOT, "device supports MSI-X\n");
                        break;
                case ATH10K_PCI_FEATURE_SOC_POWER_SAVE:
-                       ath10k_dbg(ATH10K_DBG_PCI, "QCA98XX SoC power save enabled\n");
+                       ath10k_dbg(ATH10K_DBG_BOOT, "QCA98XX SoC power save enabled\n");
                        break;
                }
        }
@@ -2286,7 +2365,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        int ret = 0;
        struct ath10k *ar;
        struct ath10k_pci *ar_pci;
-       u32 lcr_val;
+       u32 lcr_val, chip_id;
 
        ath10k_dbg(ATH10K_DBG_PCI, "%s\n", __func__);
 
@@ -2298,9 +2377,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
        ar_pci->dev = &pdev->dev;
 
        switch (pci_dev->device) {
-       case QCA988X_1_0_DEVICE_ID:
-               set_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features);
-               break;
        case QCA988X_2_0_DEVICE_ID:
                set_bit(ATH10K_PCI_FEATURE_MSI_X, ar_pci->features);
                break;
@@ -2322,10 +2398,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_ar_pci;
        }
 
-       /* Enable QCA988X_1.0 HW workarounds */
-       if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features))
-               spin_lock_init(&ar_pci->hw_v1_workaround_lock);
-
        ar_pci->ar = ar;
        ar_pci->fw_indicator_address = FW_INDICATOR_ADDRESS;
        atomic_set(&ar_pci->keep_awake_count, 0);
@@ -2395,9 +2467,20 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
 
        spin_lock_init(&ar_pci->ce_lock);
 
-       ar_pci->cacheline_sz = dma_get_cache_alignment();
+       ret = ath10k_do_pci_wake(ar);
+       if (ret) {
+               ath10k_err("Failed to get chip id: %d\n", ret);
+               return ret;
+       }
+
+       chip_id = ath10k_pci_read32(ar,
+                                   RTC_SOC_BASE_ADDRESS + SOC_CHIP_ID_ADDRESS);
+
+       ath10k_do_pci_sleep(ar);
+
+       ath10k_dbg(ATH10K_DBG_BOOT, "boot pci_mem 0x%p\n", ar_pci->mem);
 
-       ret = ath10k_core_register(ar);
+       ret = ath10k_core_register(ar, chip_id);
        if (ret) {
                ath10k_err("could not register driver core (%d)\n", ret);
                goto err_iomap;
@@ -2414,7 +2497,6 @@ err_region:
 err_device:
        pci_disable_device(pdev);
 err_ar:
-       pci_set_drvdata(pdev, NULL);
        ath10k_core_destroy(ar);
 err_ar_pci:
        /* call HIF PCI free here */
@@ -2442,7 +2524,6 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
 
        ath10k_core_unregister(ar);
 
-       pci_set_drvdata(pdev, NULL);
        pci_iounmap(pdev, ar_pci->mem);
        pci_release_region(pdev, BAR_NUM);
        pci_clear_master(pdev);
@@ -2483,9 +2564,6 @@ module_exit(ath10k_pci_exit);
 MODULE_AUTHOR("Qualcomm Atheros");
 MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
 MODULE_LICENSE("Dual BSD/GPL");
-MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_FW_FILE);
-MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_OTP_FILE);
-MODULE_FIRMWARE(QCA988X_HW_1_0_FW_DIR "/" QCA988X_HW_1_0_BOARD_DATA_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_OTP_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE);
index 871bb339d56dc3fbb19d475ed50ea938c59fefa2..7c49f6f96f703993b45188171b82200a5792d7a4 100644 (file)
@@ -43,22 +43,23 @@ struct bmi_xfer {
        u32 resp_len;
 };
 
+enum ath10k_pci_compl_state {
+       ATH10K_PCI_COMPL_FREE = 0,
+       ATH10K_PCI_COMPL_SEND,
+       ATH10K_PCI_COMPL_RECV,
+};
+
 struct ath10k_pci_compl {
        struct list_head list;
-       int send_or_recv;
-       struct ce_state *ce_state;
-       struct hif_ce_pipe_info *pipe_info;
-       void *transfer_context;
+       enum ath10k_pci_compl_state state;
+       struct ath10k_ce_pipe *ce_state;
+       struct ath10k_pci_pipe *pipe_info;
+       struct sk_buff *skb;
        unsigned int nbytes;
        unsigned int transfer_id;
        unsigned int flags;
 };
 
-/* compl_state.send_or_recv */
-#define HIF_CE_COMPLETE_FREE 0
-#define HIF_CE_COMPLETE_SEND 1
-#define HIF_CE_COMPLETE_RECV 2
-
 /*
  * PCI-specific Target state
  *
@@ -152,17 +153,16 @@ struct service_to_pipe {
 
 enum ath10k_pci_features {
        ATH10K_PCI_FEATURE_MSI_X                = 0,
-       ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND    = 1,
-       ATH10K_PCI_FEATURE_SOC_POWER_SAVE       = 2,
+       ATH10K_PCI_FEATURE_SOC_POWER_SAVE       = 1,
 
        /* keep last */
        ATH10K_PCI_FEATURE_COUNT
 };
 
 /* Per-pipe state. */
-struct hif_ce_pipe_info {
+struct ath10k_pci_pipe {
        /* Handle of underlying Copy Engine */
-       struct ce_state *ce_hdl;
+       struct ath10k_ce_pipe *ce_hdl;
 
        /* Our pipe number; facilitiates use of pipe_info ptrs. */
        u8 pipe_num;
@@ -190,7 +190,6 @@ struct ath10k_pci {
        struct device *dev;
        struct ath10k *ar;
        void __iomem *mem;
-       int cacheline_sz;
 
        DECLARE_BITMAP(features, ATH10K_PCI_FEATURE_COUNT);
 
@@ -219,7 +218,7 @@ struct ath10k_pci {
 
        bool compl_processing;
 
-       struct hif_ce_pipe_info pipe_info[CE_COUNT_MAX];
+       struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
 
        struct ath10k_hif_cb msg_callbacks_current;
 
@@ -227,16 +226,13 @@ struct ath10k_pci {
        u32 fw_indicator_address;
 
        /* Copy Engine used for Diagnostic Accesses */
-       struct ce_state *ce_diag;
+       struct ath10k_ce_pipe *ce_diag;
 
        /* FIXME: document what this really protects */
        spinlock_t ce_lock;
 
        /* Map CE id to ce_state */
-       struct ce_state *ce_id_to_state[CE_COUNT_MAX];
-
-       /* makes sure that dummy reads are atomic */
-       spinlock_t hw_v1_workaround_lock;
+       struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
 };
 
 static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
@@ -244,14 +240,18 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
        return ar->hif.priv;
 }
 
-static inline u32 ath10k_pci_reg_read32(void __iomem *mem, u32 addr)
+static inline u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr)
 {
-       return ioread32(mem + PCIE_LOCAL_BASE_ADDRESS + addr);
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       return ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
 }
 
-static inline void ath10k_pci_reg_write32(void __iomem *mem, u32 addr, u32 val)
+static inline void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
 {
-       iowrite32(val, mem + PCIE_LOCAL_BASE_ADDRESS + addr);
+       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+       iowrite32(val, ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + addr);
 }
 
 #define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
@@ -310,23 +310,8 @@ static inline void ath10k_pci_write32(struct ath10k *ar, u32 offset,
                                      u32 value)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       void __iomem *addr = ar_pci->mem;
-
-       if (test_bit(ATH10K_PCI_FEATURE_HW_1_0_WORKAROUND, ar_pci->features)) {
-               unsigned long irq_flags;
 
-               spin_lock_irqsave(&ar_pci->hw_v1_workaround_lock, irq_flags);
-
-               ioread32(addr+offset+4); /* 3rd read prior to write */
-               ioread32(addr+offset+4); /* 2nd read prior to write */
-               ioread32(addr+offset+4); /* 1st read prior to write */
-               iowrite32(value, addr+offset);
-
-               spin_unlock_irqrestore(&ar_pci->hw_v1_workaround_lock,
-                                      irq_flags);
-       } else {
-               iowrite32(value, addr+offset);
-       }
+       iowrite32(value, ar_pci->mem + offset);
 }
 
 static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
@@ -336,15 +321,17 @@ static inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
        return ioread32(ar_pci->mem + offset);
 }
 
-void ath10k_do_pci_wake(struct ath10k *ar);
+int ath10k_do_pci_wake(struct ath10k *ar);
 void ath10k_do_pci_sleep(struct ath10k *ar);
 
-static inline void ath10k_pci_wake(struct ath10k *ar)
+static inline int ath10k_pci_wake(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
        if (test_bit(ATH10K_PCI_FEATURE_SOC_POWER_SAVE, ar_pci->features))
-               ath10k_do_pci_wake(ar);
+               return ath10k_do_pci_wake(ar);
+
+       return 0;
 }
 
 static inline void ath10k_pci_sleep(struct ath10k *ar)
index bfec6c8f2ecb5aed3946ae23c6a93f81ef28f117..1c584c4b019cb7362bd611688fe57e01b3d38b02 100644 (file)
@@ -422,10 +422,30 @@ struct rx_mpdu_end {
 #define RX_MSDU_START_INFO1_IP_FRAG             (1 << 14)
 #define RX_MSDU_START_INFO1_TCP_ONLY_ACK        (1 << 15)
 
+/* The decapped header (rx_hdr_status) contains the following:
+ *  a) 802.11 header
+ *  [padding to 4 bytes]
+ *  b) HW crypto parameter
+ *     - 0 bytes for no security
+ *     - 4 bytes for WEP
+ *     - 8 bytes for TKIP, AES
+ *  [padding to 4 bytes]
+ *  c) A-MSDU subframe header (14 bytes) if appliable
+ *  d) LLC/SNAP (RFC1042, 8 bytes)
+ *
+ * In case of A-MSDU only first frame in sequence contains (a) and (b). */
 enum rx_msdu_decap_format {
-       RX_MSDU_DECAP_RAW           = 0,
-       RX_MSDU_DECAP_NATIVE_WIFI   = 1,
+       RX_MSDU_DECAP_RAW = 0,
+
+       /* Note: QoS frames are reported as non-QoS. The rx_hdr_status in
+        * htt_rx_desc contains the original decapped 802.11 header. */
+       RX_MSDU_DECAP_NATIVE_WIFI = 1,
+
+       /* Payload contains an ethernet header (struct ethhdr). */
        RX_MSDU_DECAP_ETHERNET2_DIX = 2,
+
+       /* Payload contains two 48-bit addresses and 2-byte length (14 bytes
+        * total), followed by an RFC1042 header (8 bytes). */
        RX_MSDU_DECAP_8023_SNAP_LLC = 3
 };
 
index 85e806bf7257ca231e21ace94a1abf8f9d83290a..90817ddc92ba70857ed9d3075c1e663ec75c59ce 100644 (file)
@@ -111,26 +111,29 @@ TRACE_EVENT(ath10k_log_dbg_dump,
 );
 
 TRACE_EVENT(ath10k_wmi_cmd,
-       TP_PROTO(int id, void *buf, size_t buf_len),
+       TP_PROTO(int id, void *buf, size_t buf_len, int ret),
 
-       TP_ARGS(id, buf, buf_len),
+       TP_ARGS(id, buf, buf_len, ret),
 
        TP_STRUCT__entry(
                __field(unsigned int, id)
                __field(size_t, buf_len)
                __dynamic_array(u8, buf, buf_len)
+               __field(int, ret)
        ),
 
        TP_fast_assign(
                __entry->id = id;
                __entry->buf_len = buf_len;
+               __entry->ret = ret;
                memcpy(__get_dynamic_array(buf), buf, buf_len);
        ),
 
        TP_printk(
-               "id %d len %zu",
+               "id %d len %zu ret %d",
                __entry->id,
-               __entry->buf_len
+               __entry->buf_len,
+               __entry->ret
        )
 );
 
@@ -158,6 +161,27 @@ TRACE_EVENT(ath10k_wmi_event,
        )
 );
 
+TRACE_EVENT(ath10k_htt_stats,
+       TP_PROTO(void *buf, size_t buf_len),
+
+       TP_ARGS(buf, buf_len),
+
+       TP_STRUCT__entry(
+               __field(size_t, buf_len)
+               __dynamic_array(u8, buf, buf_len)
+       ),
+
+       TP_fast_assign(
+               __entry->buf_len = buf_len;
+               memcpy(__get_dynamic_array(buf), buf, buf_len);
+       ),
+
+       TP_printk(
+               "len %zu",
+               __entry->buf_len
+       )
+);
+
 #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
 
 /* we don't want to use include/trace/events */
index 68b6faefd1d883f89642775c03390b67a9f929ac..5ae373a1e2942fbcb3d185533d41eaf9dd8e24bd 100644 (file)
@@ -44,40 +44,39 @@ out:
        spin_unlock_bh(&ar->data_lock);
 }
 
-void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
+void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+                         const struct htt_tx_done *tx_done)
 {
        struct device *dev = htt->ar->dev;
        struct ieee80211_tx_info *info;
-       struct sk_buff *txfrag = ATH10K_SKB_CB(txdesc)->htt.txfrag;
-       struct sk_buff *msdu = ATH10K_SKB_CB(txdesc)->htt.msdu;
+       struct ath10k_skb_cb *skb_cb;
+       struct sk_buff *msdu;
        int ret;
 
-       if (ATH10K_SKB_CB(txdesc)->htt.refcount == 0)
-               return;
-
-       ATH10K_SKB_CB(txdesc)->htt.refcount--;
+       ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
+                  tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
 
-       if (ATH10K_SKB_CB(txdesc)->htt.refcount > 0)
+       if (tx_done->msdu_id >= htt->max_num_pending_tx) {
+               ath10k_warn("warning: msdu_id %d too big, ignoring\n",
+                           tx_done->msdu_id);
                return;
-
-       if (txfrag) {
-               ret = ath10k_skb_unmap(dev, txfrag);
-               if (ret)
-                       ath10k_warn("txfrag unmap failed (%d)\n", ret);
-
-               dev_kfree_skb_any(txfrag);
        }
 
+       msdu = htt->pending_tx[tx_done->msdu_id];
+       skb_cb = ATH10K_SKB_CB(msdu);
+
        ret = ath10k_skb_unmap(dev, msdu);
        if (ret)
                ath10k_warn("data skb unmap failed (%d)\n", ret);
 
+       if (skb_cb->htt.frag_len)
+               skb_pull(msdu, skb_cb->htt.frag_len + skb_cb->htt.pad_len);
+
        ath10k_report_offchan_tx(htt->ar, msdu);
 
        info = IEEE80211_SKB_CB(msdu);
-       memset(&info->status, 0, sizeof(info->status));
 
-       if (ATH10K_SKB_CB(txdesc)->htt.discard) {
+       if (tx_done->discard) {
                ieee80211_free_txskb(htt->ar->hw, msdu);
                goto exit;
        }
@@ -85,7 +84,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
                info->flags |= IEEE80211_TX_STAT_ACK;
 
-       if (ATH10K_SKB_CB(txdesc)->htt.no_ack)
+       if (tx_done->no_ack)
                info->flags &= ~IEEE80211_TX_STAT_ACK;
 
        ieee80211_tx_status(htt->ar->hw, msdu);
@@ -93,36 +92,12 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc)
 
 exit:
        spin_lock_bh(&htt->tx_lock);
-       htt->pending_tx[ATH10K_SKB_CB(txdesc)->htt.msdu_id] = NULL;
-       ath10k_htt_tx_free_msdu_id(htt, ATH10K_SKB_CB(txdesc)->htt.msdu_id);
+       htt->pending_tx[tx_done->msdu_id] = NULL;
+       ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
        __ath10k_htt_tx_dec_pending(htt);
-       if (bitmap_empty(htt->used_msdu_ids, htt->max_num_pending_tx))
+       if (htt->num_pending_tx == 0)
                wake_up(&htt->empty_tx_wq);
        spin_unlock_bh(&htt->tx_lock);
-
-       dev_kfree_skb_any(txdesc);
-}
-
-void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
-                             const struct htt_tx_done *tx_done)
-{
-       struct sk_buff *txdesc;
-
-       ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d no_ack %d\n",
-                  tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
-
-       if (tx_done->msdu_id >= htt->max_num_pending_tx) {
-               ath10k_warn("warning: msdu_id %d too big, ignoring\n",
-                           tx_done->msdu_id);
-               return;
-       }
-
-       txdesc = htt->pending_tx[tx_done->msdu_id];
-
-       ATH10K_SKB_CB(txdesc)->htt.discard = tx_done->discard;
-       ATH10K_SKB_CB(txdesc)->htt.no_ack = tx_done->no_ack;
-
-       ath10k_txrx_tx_unref(htt, txdesc);
 }
 
 static const u8 rx_legacy_rate_idx[] = {
@@ -293,6 +268,8 @@ void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info)
                   status->vht_nss,
                   status->freq,
                   status->band);
+       ath10k_dbg_dump(ATH10K_DBG_HTT_DUMP, NULL, "rx skb: ",
+                       info->skb->data, info->skb->len);
 
        ieee80211_rx(ar->hw, info->skb);
 }
index e78632a76df7bd4451cadaada87740bd4bc79991..356dc9c04c9e3981feaeb04d8df4e8f45fc36f7f 100644 (file)
@@ -19,9 +19,8 @@
 
 #include "htt.h"
 
-void ath10k_txrx_tx_unref(struct ath10k_htt *htt, struct sk_buff *txdesc);
-void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
-                             const struct htt_tx_done *tx_done);
+void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+                         const struct htt_tx_done *tx_done);
 void ath10k_process_rx(struct ath10k *ar, struct htt_rx_info *info);
 
 struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
index 55f90c761868ddd9fa228510efb27465d360c00b..6803ead9b9cfd0c6f0be623e025e11f869394a4b 100644 (file)
 #include "wmi.h"
 #include "mac.h"
 
-void ath10k_wmi_flush_tx(struct ath10k *ar)
-{
-       int ret;
-
-       lockdep_assert_held(&ar->conf_mutex);
-
-       if (ar->state == ATH10K_STATE_WEDGED) {
-               ath10k_warn("wmi flush skipped - device is wedged anyway\n");
-               return;
-       }
-
-       ret = wait_event_timeout(ar->wmi.wq,
-                                atomic_read(&ar->wmi.pending_tx_count) == 0,
-                                5*HZ);
-       if (atomic_read(&ar->wmi.pending_tx_count) == 0)
-               return;
-
-       if (ret == 0)
-               ret = -ETIMEDOUT;
-
-       if (ret < 0)
-               ath10k_warn("wmi flush failed (%d)\n", ret);
-}
-
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar)
 {
        int ret;
@@ -85,18 +61,14 @@ static struct sk_buff *ath10k_wmi_alloc_skb(u32 len)
 static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
 {
        dev_kfree_skb(skb);
-
-       if (atomic_sub_return(1, &ar->wmi.pending_tx_count) == 0)
-               wake_up(&ar->wmi.wq);
 }
 
-/* WMI command API */
-static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
-                              enum wmi_cmd_id cmd_id)
+static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
+                                     enum wmi_cmd_id cmd_id)
 {
        struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
        struct wmi_cmd_hdr *cmd_hdr;
-       int status;
+       int ret;
        u32 cmd = 0;
 
        if (skb_push(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
@@ -107,25 +79,87 @@ static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
        cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
        cmd_hdr->cmd_id = __cpu_to_le32(cmd);
 
-       if (atomic_add_return(1, &ar->wmi.pending_tx_count) >
-           WMI_MAX_PENDING_TX_COUNT) {
-               /* avoid using up memory when FW hangs */
-               atomic_dec(&ar->wmi.pending_tx_count);
-               return -EBUSY;
-       }
-
        memset(skb_cb, 0, sizeof(*skb_cb));
+       ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
+       trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len, ret);
 
-       trace_ath10k_wmi_cmd(cmd_id, skb->data, skb->len);
+       if (ret)
+               goto err_pull;
 
-       status = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
-       if (status) {
+       return 0;
+
+err_pull:
+       skb_pull(skb, sizeof(struct wmi_cmd_hdr));
+       return ret;
+}
+
+static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
+{
+       struct wmi_bcn_tx_arg arg = {0};
+       int ret;
+
+       lockdep_assert_held(&arvif->ar->data_lock);
+
+       if (arvif->beacon == NULL)
+               return;
+
+       arg.vdev_id = arvif->vdev_id;
+       arg.tx_rate = 0;
+       arg.tx_power = 0;
+       arg.bcn = arvif->beacon->data;
+       arg.bcn_len = arvif->beacon->len;
+
+       ret = ath10k_wmi_beacon_send_nowait(arvif->ar, &arg);
+       if (ret)
+               return;
+
+       dev_kfree_skb_any(arvif->beacon);
+       arvif->beacon = NULL;
+}
+
+static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
+                                      struct ieee80211_vif *vif)
+{
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+
+       ath10k_wmi_tx_beacon_nowait(arvif);
+}
+
+static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar)
+{
+       spin_lock_bh(&ar->data_lock);
+       ieee80211_iterate_active_interfaces_atomic(ar->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
+                                                  ath10k_wmi_tx_beacons_iter,
+                                                  NULL);
+       spin_unlock_bh(&ar->data_lock);
+}
+
+static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar)
+{
+       /* try to send pending beacons first. they take priority */
+       ath10k_wmi_tx_beacons_nowait(ar);
+
+       wake_up(&ar->wmi.tx_credits_wq);
+}
+
+static int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb,
+                              enum wmi_cmd_id cmd_id)
+{
+       int ret = -EINVAL;
+
+       wait_event_timeout(ar->wmi.tx_credits_wq, ({
+               /* try to send pending beacons first. they take priority */
+               ath10k_wmi_tx_beacons_nowait(ar);
+
+               ret = ath10k_wmi_cmd_send_nowait(ar, skb, cmd_id);
+               (ret != -EAGAIN);
+       }), 3*HZ);
+
+       if (ret)
                dev_kfree_skb_any(skb);
-               atomic_dec(&ar->wmi.pending_tx_count);
-               return status;
-       }
 
-       return 0;
+       return ret;
 }
 
 static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
@@ -315,7 +349,9 @@ static inline u8 get_rate_idx(u32 rate, enum ieee80211_band band)
 
 static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
 {
-       struct wmi_mgmt_rx_event *event = (struct wmi_mgmt_rx_event *)skb->data;
+       struct wmi_mgmt_rx_event_v1 *ev_v1;
+       struct wmi_mgmt_rx_event_v2 *ev_v2;
+       struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr;
        u32 rx_status;
@@ -325,13 +361,24 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
        u32 rate;
        u32 buf_len;
        u16 fc;
+       int pull_len;
+
+       if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
+               ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
+               ev_hdr = &ev_v2->hdr.v1;
+               pull_len = sizeof(*ev_v2);
+       } else {
+               ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
+               ev_hdr = &ev_v1->hdr;
+               pull_len = sizeof(*ev_v1);
+       }
 
-       channel   = __le32_to_cpu(event->hdr.channel);
-       buf_len   = __le32_to_cpu(event->hdr.buf_len);
-       rx_status = __le32_to_cpu(event->hdr.status);
-       snr       = __le32_to_cpu(event->hdr.snr);
-       phy_mode  = __le32_to_cpu(event->hdr.phy_mode);
-       rate      = __le32_to_cpu(event->hdr.rate);
+       channel   = __le32_to_cpu(ev_hdr->channel);
+       buf_len   = __le32_to_cpu(ev_hdr->buf_len);
+       rx_status = __le32_to_cpu(ev_hdr->status);
+       snr       = __le32_to_cpu(ev_hdr->snr);
+       phy_mode  = __le32_to_cpu(ev_hdr->phy_mode);
+       rate      = __le32_to_cpu(ev_hdr->rate);
 
        memset(status, 0, sizeof(*status));
 
@@ -358,7 +405,7 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
        status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
        status->rate_idx = get_rate_idx(rate, status->band);
 
-       skb_pull(skb, sizeof(event->hdr));
+       skb_pull(skb, pull_len);
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = le16_to_cpu(hdr->frame_control);
@@ -734,10 +781,8 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
        int i = -1;
        struct wmi_bcn_info *bcn_info;
        struct ath10k_vif *arvif;
-       struct wmi_bcn_tx_arg arg;
        struct sk_buff *bcn;
        int vdev_id = 0;
-       int ret;
 
        ath10k_dbg(ATH10K_DBG_MGMT, "WMI_HOST_SWBA_EVENTID\n");
 
@@ -794,17 +839,17 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
                ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info);
                ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
 
-               arg.vdev_id = arvif->vdev_id;
-               arg.tx_rate = 0;
-               arg.tx_power = 0;
-               arg.bcn = bcn->data;
-               arg.bcn_len = bcn->len;
+               spin_lock_bh(&ar->data_lock);
+               if (arvif->beacon) {
+                       ath10k_warn("SWBA overrun on vdev %d\n",
+                                   arvif->vdev_id);
+                       dev_kfree_skb_any(arvif->beacon);
+               }
 
-               ret = ath10k_wmi_beacon_send(ar, &arg);
-               if (ret)
-                       ath10k_warn("could not send beacon (%d)\n", ret);
+               arvif->beacon = bcn;
 
-               dev_kfree_skb_any(bcn);
+               ath10k_wmi_tx_beacon_nowait(arvif);
+               spin_unlock_bh(&ar->data_lock);
        }
 }
 
@@ -943,6 +988,9 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
        ar->phy_capability = __le32_to_cpu(ev->phy_capability);
        ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);
 
+       if (ar->fw_version_build > 636)
+               set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
+
        if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {
                ath10k_warn("hardware advertises support for more spatial streams than it should (%d > %d)\n",
                            ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM);
@@ -1007,7 +1055,7 @@ static int ath10k_wmi_ready_event_rx(struct ath10k *ar, struct sk_buff *skb)
        return 0;
 }
 
-static void ath10k_wmi_event_process(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
 {
        struct wmi_cmd_hdr *cmd_hdr;
        enum wmi_event_id id;
@@ -1126,64 +1174,18 @@ static void ath10k_wmi_event_process(struct ath10k *ar, struct sk_buff *skb)
        dev_kfree_skb(skb);
 }
 
-static void ath10k_wmi_event_work(struct work_struct *work)
-{
-       struct ath10k *ar = container_of(work, struct ath10k,
-                                        wmi.wmi_event_work);
-       struct sk_buff *skb;
-
-       for (;;) {
-               skb = skb_dequeue(&ar->wmi.wmi_event_list);
-               if (!skb)
-                       break;
-
-               ath10k_wmi_event_process(ar, skb);
-       }
-}
-
-static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
-{
-       struct wmi_cmd_hdr *cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
-       enum wmi_event_id event_id;
-
-       event_id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
-
-       /* some events require to be handled ASAP
-        * thus can't be defered to a worker thread */
-       switch (event_id) {
-       case WMI_HOST_SWBA_EVENTID:
-       case WMI_MGMT_RX_EVENTID:
-               ath10k_wmi_event_process(ar, skb);
-               return;
-       default:
-               break;
-       }
-
-       skb_queue_tail(&ar->wmi.wmi_event_list, skb);
-       queue_work(ar->workqueue, &ar->wmi.wmi_event_work);
-}
-
 /* WMI Initialization functions */
 int ath10k_wmi_attach(struct ath10k *ar)
 {
        init_completion(&ar->wmi.service_ready);
        init_completion(&ar->wmi.unified_ready);
-       init_waitqueue_head(&ar->wmi.wq);
-
-       skb_queue_head_init(&ar->wmi.wmi_event_list);
-       INIT_WORK(&ar->wmi.wmi_event_work, ath10k_wmi_event_work);
+       init_waitqueue_head(&ar->wmi.tx_credits_wq);
 
        return 0;
 }
 
 void ath10k_wmi_detach(struct ath10k *ar)
 {
-       /* HTC should've drained the packets already */
-       if (WARN_ON(atomic_read(&ar->wmi.pending_tx_count) > 0))
-               ath10k_warn("there are still pending packets\n");
-
-       cancel_work_sync(&ar->wmi.wmi_event_work);
-       skb_queue_purge(&ar->wmi.wmi_event_list);
 }
 
 int ath10k_wmi_connect_htc_service(struct ath10k *ar)
@@ -1198,6 +1200,7 @@ int ath10k_wmi_connect_htc_service(struct ath10k *ar)
        /* these fields are the same for all service endpoints */
        conn_req.ep_ops.ep_tx_complete = ath10k_wmi_htc_tx_complete;
        conn_req.ep_ops.ep_rx_complete = ath10k_wmi_process_rx;
+       conn_req.ep_ops.ep_tx_credits = ath10k_wmi_op_ep_tx_credits;
 
        /* connect to control service */
        conn_req.service_id = ATH10K_HTC_SVC_ID_WMI_CONTROL;
@@ -2108,7 +2111,8 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
        return ath10k_wmi_cmd_send(ar, skb, WMI_PEER_ASSOC_CMDID);
 }
 
-int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg)
+int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
+                                 const struct wmi_bcn_tx_arg *arg)
 {
        struct wmi_bcn_tx_cmd *cmd;
        struct sk_buff *skb;
@@ -2124,7 +2128,7 @@ int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg)
        cmd->hdr.bcn_len  = __cpu_to_le32(arg->bcn_len);
        memcpy(cmd->bcn, arg->bcn, arg->bcn_len);
 
-       return ath10k_wmi_cmd_send(ar, skb, WMI_BCN_TX_CMDID);
+       return ath10k_wmi_cmd_send_nowait(ar, skb, WMI_BCN_TX_CMDID);
 }
 
 static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
index 2c5a4f8daf2ee4b80e9a9e84391586e638389271..2c52c23107dde732b8285791e249cd6bb9a7f74d 100644 (file)
@@ -508,6 +508,48 @@ enum wmi_phy_mode {
        MODE_MAX        = 14
 };
 
+static inline const char *ath10k_wmi_phymode_str(enum wmi_phy_mode mode)
+{
+       switch (mode) {
+       case MODE_11A:
+               return "11a";
+       case MODE_11G:
+               return "11g";
+       case MODE_11B:
+               return "11b";
+       case MODE_11GONLY:
+               return "11gonly";
+       case MODE_11NA_HT20:
+               return "11na-ht20";
+       case MODE_11NG_HT20:
+               return "11ng-ht20";
+       case MODE_11NA_HT40:
+               return "11na-ht40";
+       case MODE_11NG_HT40:
+               return "11ng-ht40";
+       case MODE_11AC_VHT20:
+               return "11ac-vht20";
+       case MODE_11AC_VHT40:
+               return "11ac-vht40";
+       case MODE_11AC_VHT80:
+               return "11ac-vht80";
+       case MODE_11AC_VHT20_2G:
+               return "11ac-vht20-2g";
+       case MODE_11AC_VHT40_2G:
+               return "11ac-vht40-2g";
+       case MODE_11AC_VHT80_2G:
+               return "11ac-vht80-2g";
+       case MODE_UNKNOWN:
+               /* skip */
+               break;
+
+               /* no default handler to allow compiler to check that the
+                * enum is fully handled */
+       };
+
+       return "<unknown>";
+}
+
 #define WMI_CHAN_LIST_TAG      0x1
 #define WMI_SSID_LIST_TAG      0x2
 #define WMI_BSSID_LIST_TAG     0x3
@@ -763,14 +805,6 @@ struct wmi_service_ready_event {
        struct wlan_host_mem_req mem_reqs[1];
 } __packed;
 
-/*
- * status consists of  upper 16 bits fo int status and lower 16 bits of
- * module ID that retuned status
- */
-#define WLAN_INIT_STATUS_SUCCESS   0x0
-#define WLAN_GET_INIT_STATUS_REASON(status)    ((status) & 0xffff)
-#define WLAN_GET_INIT_STATUS_MODULE_ID(status) (((status) >> 16) & 0xffff)
-
 #define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
 #define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ)
 
@@ -1268,7 +1302,7 @@ struct wmi_scan_event {
  * good idea to pass all the fields in the RX status
  * descriptor up to the host.
  */
-struct wmi_mgmt_rx_hdr {
+struct wmi_mgmt_rx_hdr_v1 {
        __le32 channel;
        __le32 snr;
        __le32 rate;
@@ -1277,8 +1311,18 @@ struct wmi_mgmt_rx_hdr {
        __le32 status; /* %WMI_RX_STATUS_ */
 } __packed;
 
-struct wmi_mgmt_rx_event {
-       struct wmi_mgmt_rx_hdr hdr;
+struct wmi_mgmt_rx_hdr_v2 {
+       struct wmi_mgmt_rx_hdr_v1 v1;
+       __le32 rssi_ctl[4];
+} __packed;
+
+struct wmi_mgmt_rx_event_v1 {
+       struct wmi_mgmt_rx_hdr_v1 hdr;
+       u8 buf[0];
+} __packed;
+
+struct wmi_mgmt_rx_event_v2 {
+       struct wmi_mgmt_rx_hdr_v2 hdr;
        u8 buf[0];
 } __packed;
 
@@ -3000,7 +3044,6 @@ struct wmi_force_fw_hang_cmd {
 
 #define WMI_MAX_EVENT 0x1000
 /* Maximum number of pending TXed WMI packets */
-#define WMI_MAX_PENDING_TX_COUNT 128
 #define WMI_SKB_HEADROOM sizeof(struct wmi_cmd_hdr)
 
 /* By default disable power save for IBSS */
@@ -3013,7 +3056,6 @@ int ath10k_wmi_attach(struct ath10k *ar);
 void ath10k_wmi_detach(struct ath10k *ar);
 int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
 int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
-void ath10k_wmi_flush_tx(struct ath10k *ar);
 
 int ath10k_wmi_connect_htc_service(struct ath10k *ar);
 int ath10k_wmi_pdev_set_channel(struct ath10k *ar,
@@ -3066,7 +3108,8 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
                               enum wmi_ap_ps_peer_param param_id, u32 value);
 int ath10k_wmi_scan_chan_list(struct ath10k *ar,
                              const struct wmi_scan_chan_list_arg *arg);
-int ath10k_wmi_beacon_send(struct ath10k *ar, const struct wmi_bcn_tx_arg *arg);
+int ath10k_wmi_beacon_send_nowait(struct ath10k *ar,
+                                 const struct wmi_bcn_tx_arg *arg);
 int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
                        const struct wmi_pdev_set_wmm_params_arg *arg);
 int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
index e9bc9e616b69c94e4c6758ae2c2327768778b942..79bffe165caba6e1f963b9fa81deed4844cb42d1 100644 (file)
@@ -37,12 +37,9 @@ ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 {
        struct ath5k_hw *ah = common->priv;
        struct platform_device *pdev = to_platform_device(ah->dev);
-       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
        u16 *eeprom, *eeprom_end;
 
-
-
-       bcfg = pdev->dev.platform_data;
        eeprom = (u16 *) bcfg->radio;
        eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
 
@@ -57,7 +54,7 @@ ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
 int ath5k_hw_read_srev(struct ath5k_hw *ah)
 {
        struct platform_device *pdev = to_platform_device(ah->dev);
-       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
        ah->ah_mac_srev = bcfg->devid;
        return 0;
 }
@@ -65,7 +62,7 @@ int ath5k_hw_read_srev(struct ath5k_hw *ah)
 static int ath5k_ahb_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
 {
        struct platform_device *pdev = to_platform_device(ah->dev);
-       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
        u8 *cfg_mac;
 
        if (to_platform_device(ah->dev)->id == 0)
@@ -87,7 +84,7 @@ static const struct ath_bus_ops ath_ahb_bus_ops = {
 /*Initialization*/
 static int ath_ahb_probe(struct platform_device *pdev)
 {
-       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
        struct ath5k_hw *ah;
        struct ieee80211_hw *hw;
        struct resource *res;
@@ -96,7 +93,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
        int ret = 0;
        u32 reg;
 
-       if (!pdev->dev.platform_data) {
+       if (!dev_get_platdata(&pdev->dev)) {
                dev_err(&pdev->dev, "no platform data specified\n");
                ret = -EINVAL;
                goto err_out;
@@ -193,7 +190,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
 
 static int ath_ahb_remove(struct platform_device *pdev)
 {
-       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ar231x_board_config *bcfg = dev_get_platdata(&pdev->dev);
        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
        struct ath5k_hw *ah;
        u32 reg;
index 072e4b53106765ce8e0d6c833652501a7abde62d..2dff2765769bb339eea79b05877414b6b9bdc0f9 100644 (file)
@@ -54,7 +54,7 @@ static bool ath_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
        struct platform_device *pdev = to_platform_device(sc->dev);
        struct ath9k_platform_data *pdata;
 
-       pdata = (struct ath9k_platform_data *) pdev->dev.platform_data;
+       pdata = dev_get_platdata(&pdev->dev);
        if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
                ath_err(common,
                        "%s: flash read failed, offset %08x is out of range\n",
@@ -84,7 +84,7 @@ static int ath_ahb_probe(struct platform_device *pdev)
        struct ath_hw *ah;
        char hw_name[64];
 
-       if (!pdev->dev.platform_data) {
+       if (!dev_get_platdata(&pdev->dev)) {
                dev_err(&pdev->dev, "no platform data specified\n");
                return -EINVAL;
        }
index be466b0ef7a7725c736114ee439596ca45a4a380..d28923b7435b257f13a91e3f8896115c30adb1c9 100644 (file)
@@ -338,10 +338,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
                    aniState->cckNoiseImmunityLevel !=
                    ATH9K_ANI_CCK_DEF_LEVEL) {
                        ath_dbg(common, ANI,
-                               "Restore defaults: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
+                               "Restore defaults: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n",
                                ah->opmode,
                                chan->channel,
-                               chan->channelFlags,
                                is_scanning,
                                aniState->ofdmNoiseImmunityLevel,
                                aniState->cckNoiseImmunityLevel);
@@ -354,10 +353,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
                 * restore historical levels for this channel
                 */
                ath_dbg(common, ANI,
-                       "Restore history: opmode %u chan %d Mhz/0x%x is_scanning=%d ofdm:%d cck:%d\n",
+                       "Restore history: opmode %u chan %d Mhz is_scanning=%d ofdm:%d cck:%d\n",
                        ah->opmode,
                        chan->channel,
-                       chan->channelFlags,
                        is_scanning,
                        aniState->ofdmNoiseImmunityLevel,
                        aniState->cckNoiseImmunityLevel);
index dd1cc73d7946104d2353a777586c6da4bf3c6f67..bd048cc69a334d6234b6967ecff5e1aec8b75fbe 100644 (file)
@@ -332,7 +332,7 @@ static void ath_select_ant_div_from_quick_scan(struct ath_ant_comb *antcomb,
                }
 
                if (antcomb->rssi_lna2 > antcomb->rssi_lna1 +
-                   ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)
+                   div_ant_conf->lna1_lna2_switch_delta)
                        div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA2;
                else
                        div_ant_conf->main_lna_conf = ATH_ANT_DIV_COMB_LNA1;
@@ -554,42 +554,22 @@ static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
                        ant_conf->fast_div_bias = 0x1;
                        break;
                case 0x10: /* LNA2 A-B */
-                       if ((antcomb->scan == 0) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
-                               ant_conf->fast_div_bias = 0x3f;
-                       } else {
-                               ant_conf->fast_div_bias = 0x1;
-                       }
+                       ant_conf->fast_div_bias = 0x2;
                        break;
                case 0x12: /* LNA2 LNA1 */
-                       ant_conf->fast_div_bias = 0x39;
+                       ant_conf->fast_div_bias = 0x3f;
                        break;
                case 0x13: /* LNA2 A+B */
-                       if ((antcomb->scan == 0) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
-                               ant_conf->fast_div_bias = 0x3f;
-                       } else {
-                               ant_conf->fast_div_bias = 0x1;
-                       }
+                       ant_conf->fast_div_bias = 0x2;
                        break;
                case 0x20: /* LNA1 A-B */
-                       if ((antcomb->scan == 0) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
-                               ant_conf->fast_div_bias = 0x3f;
-                       } else {
-                               ant_conf->fast_div_bias = 0x4;
-                       }
+                       ant_conf->fast_div_bias = 0x3;
                        break;
                case 0x21: /* LNA1 LNA2 */
-                       ant_conf->fast_div_bias = 0x6;
+                       ant_conf->fast_div_bias = 0x3;
                        break;
                case 0x23: /* LNA1 A+B */
-                       if ((antcomb->scan == 0) &&
-                           (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)) {
-                               ant_conf->fast_div_bias = 0x3f;
-                       } else {
-                               ant_conf->fast_div_bias = 0x6;
-                       }
+                       ant_conf->fast_div_bias = 0x3;
                        break;
                case 0x30: /* A+B A-B */
                        ant_conf->fast_div_bias = 0x1;
@@ -638,7 +618,7 @@ static void ath_ant_try_scan(struct ath_ant_comb *antcomb,
                antcomb->rssi_sub = alt_rssi_avg;
                antcomb->scan = false;
                if (antcomb->rssi_lna2 >
-                   (antcomb->rssi_lna1 + ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA)) {
+                   (antcomb->rssi_lna1 + conf->lna1_lna2_switch_delta)) {
                        /* use LNA2 as main LNA */
                        if ((antcomb->rssi_add > antcomb->rssi_lna1) &&
                            (antcomb->rssi_add > antcomb->rssi_sub)) {
index 08656473c63e5a796b37bcd25f087504d85433fb..ff415e863ee9cc5140879ca008df366b8f1ad967 100644 (file)
@@ -626,12 +626,11 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
                if (AR_SREV_9287_11_OR_LATER(ah))
                        val = val & (~AR_PCU_MISC_MODE2_HWWAR2);
 
+               val |= AR_PCU_MISC_MODE2_CFP_IGNORE;
+
                REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
        }
 
-       REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
-                   AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
-
        if (AR_SREV_9280_20_OR_LATER(ah))
                return;
        /*
@@ -667,14 +666,13 @@ static void ar5008_hw_set_channel_regs(struct ath_hw *ah,
        if (IS_CHAN_HT40(chan)) {
                phymode |= AR_PHY_FC_DYN2040_EN;
 
-               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-                   (chan->chanmode == CHANNEL_G_HT40PLUS))
+               if (IS_CHAN_HT40PLUS(chan))
                        phymode |= AR_PHY_FC_DYN2040_PRI_CH;
 
        }
        REG_WRITE(ah, AR_PHY_TURBO, phymode);
 
-       ath9k_hw_set11nmac2040(ah);
+       ath9k_hw_set11nmac2040(ah, chan);
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -692,31 +690,12 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
        int i, regWrites = 0;
        u32 modesIndex, freqIndex;
 
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-               modesIndex = 1;
-               freqIndex = 1;
-               break;
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               modesIndex = 2;
+       if (IS_CHAN_5GHZ(chan)) {
                freqIndex = 1;
-               break;
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_B:
-               modesIndex = 4;
-               freqIndex = 2;
-               break;
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               modesIndex = 3;
+               modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
+       } else {
                freqIndex = 2;
-               break;
-
-       default:
-               return -EINVAL;
+               modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
        }
 
        /*
@@ -815,8 +794,10 @@ static void ar5008_hw_set_rfmode(struct ath_hw *ah, struct ath9k_channel *chan)
        if (chan == NULL)
                return;
 
-       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
-               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+       if (IS_CHAN_2GHZ(chan))
+               rfMode |= AR_PHY_MODE_DYNAMIC;
+       else
+               rfMode |= AR_PHY_MODE_OFDM;
 
        if (!AR_SREV_9280_20_OR_LATER(ah))
                rfMode |= (IS_CHAN_5GHZ(chan)) ?
@@ -1219,12 +1200,11 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah)
 
        iniDef = &aniState->iniDef;
 
-       ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+       ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz\n",
                ah->hw_version.macVersion,
                ah->hw_version.macRev,
                ah->opmode,
-               chan->channel,
-               chan->channelFlags);
+               chan->channel);
 
        val = REG_READ(ah, AR_PHY_SFCORR);
        iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
index 9f589744a9f945b285ca1c2988d795488cbf7a47..cdc74005650ce9848147ee0e051c64f9df989ffd 100644 (file)
@@ -33,15 +33,12 @@ static bool ar9002_hw_is_cal_supported(struct ath_hw *ah,
        bool supported = false;
        switch (ah->supp_cals & cal_type) {
        case IQ_MISMATCH_CAL:
-               /* Run IQ Mismatch for non-CCK only */
-               if (!IS_CHAN_B(chan))
-                       supported = true;
+               supported = true;
                break;
        case ADC_GAIN_CAL:
        case ADC_DC_CAL:
                /* Run ADC Gain Cal for non-CCK & non 2GHz-HT20 only */
-               if (!IS_CHAN_B(chan) &&
-                   !((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
+               if (!((IS_CHAN_2GHZ(chan) || IS_CHAN_A_FAST_CLOCK(ah, chan)) &&
                      IS_CHAN_HT20(chan)))
                        supported = true;
                break;
@@ -671,7 +668,7 @@ static bool ar9002_hw_calibrate(struct ath_hw *ah,
 
        nfcal = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF);
        if (ah->caldata)
-               nfcal_pending = ah->caldata->nfcal_pending;
+               nfcal_pending = test_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 
        if (currCal && !nfcal &&
            (currCal->calState == CAL_RUNNING ||
@@ -861,7 +858,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
        ar9002_hw_pa_cal(ah, true);
 
        if (ah->caldata)
-               ah->caldata->nfcal_pending = true;
+               set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 
        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
index fb61b081d1721124518f7c4cad85792cedaefac0..5c95fd9e9c9e9c861edb283a2a8cfbf4a9b5e3b9 100644 (file)
@@ -419,28 +419,10 @@ void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan)
        u32 modesIndex;
        int i;
 
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-               modesIndex = 1;
-               break;
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               modesIndex = 2;
-               break;
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_B:
-               modesIndex = 4;
-               break;
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               modesIndex = 3;
-               break;
-
-       default:
-               return;
-       }
+       if (IS_CHAN_5GHZ(chan))
+               modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
+       else
+               modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
 
        ENABLE_REGWRITE_BUFFER(ah);
 
index 1fc1fa955d44fff8ddd60e7f231701f873df5473..17970d49d858e80b37e86097b6c97f73af61e29a 100644 (file)
@@ -485,7 +485,7 @@ static void ar9002_hw_do_getnf(struct ath_hw *ah,
        if (IS_CHAN_HT40(ah->curchan))
                nfarray[3] = sign_extend32(nf, 8);
 
-       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+       if (!(ah->rxchainmask & BIT(1)))
                return;
 
        nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), AR9280_PHY_CH1_MINCCA_PWR);
@@ -532,6 +532,7 @@ static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah,
                                 AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
        antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
                                  AR_PHY_9285_FAST_DIV_BIAS_S;
+       antconf->lna1_lna2_switch_delta = -1;
        antconf->lna1_lna2_delta = -3;
        antconf->div_group = 0;
 }
index 6988e1d081f225c0c0a8efd0dc49fbacb4fc6a1a..22934d3ca54413fa9558a928fdccbc4ab108131a 100644 (file)
@@ -727,8 +727,12 @@ static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
        REG_RMW_FIELD(ah, AR_PHY_RX_IQCAL_CORR_B0,
                      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
 
-       if (caldata)
-               caldata->done_txiqcal_once = is_reusable;
+       if (caldata) {
+               if (is_reusable)
+                       set_bit(TXIQCAL_DONE, &caldata->cal_flags);
+               else
+                       clear_bit(TXIQCAL_DONE, &caldata->cal_flags);
+       }
 
        return;
 }
@@ -961,18 +965,44 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
 }
 
 static void ar9003_hw_do_manual_peak_cal(struct ath_hw *ah,
-                                        struct ath9k_channel *chan)
+                                        struct ath9k_channel *chan,
+                                        bool run_rtt_cal)
 {
+       struct ath9k_hw_cal_data *caldata = ah->caldata;
        int i;
 
        if (!AR_SREV_9462(ah) && !AR_SREV_9565(ah) && !AR_SREV_9485(ah))
                return;
 
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && !run_rtt_cal)
+               return;
+
        for (i = 0; i < AR9300_MAX_CHAINS; i++) {
                if (!(ah->rxchainmask & (1 << i)))
                        continue;
                ar9003_hw_manual_peak_cal(ah, i, IS_CHAN_2GHZ(chan));
        }
+
+       if (caldata)
+               set_bit(SW_PKDET_DONE, &caldata->cal_flags);
+
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_RTT) && caldata) {
+               if (IS_CHAN_2GHZ(chan)){
+                       caldata->caldac[0] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(0),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
+                       caldata->caldac[1] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(1),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR);
+               } else {
+                       caldata->caldac[0] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(0),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
+                       caldata->caldac[1] = REG_READ_FIELD(ah,
+                                                   AR_PHY_65NM_RXRF_AGC(1),
+                                                   AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR);
+               }
+       }
 }
 
 static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
@@ -990,7 +1020,7 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
        txclcal_done = !!(REG_READ(ah, AR_PHY_AGC_CONTROL) &
                          AR_PHY_AGC_CONTROL_CLC_SUCCESS);
 
-       if (caldata->done_txclcal_once) {
+       if (test_bit(TXCLCAL_DONE, &caldata->cal_flags)) {
                for (i = 0; i < AR9300_MAX_CHAINS; i++) {
                        if (!(ah->txchainmask & (1 << i)))
                                continue;
@@ -1006,7 +1036,7 @@ static void ar9003_hw_cl_cal_post_proc(struct ath_hw *ah, bool is_reusable)
                                caldata->tx_clcal[i][j] =
                                        REG_READ(ah, CL_TAB_ENTRY(cl_idx[i]));
                }
-               caldata->done_txclcal_once = true;
+               set_bit(TXCLCAL_DONE, &caldata->cal_flags);
        }
 }
 
@@ -1019,6 +1049,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        bool is_reusable = true, status = true;
        bool run_rtt_cal = false, run_agc_cal, sep_iq_cal = false;
        bool rtt = !!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT);
+       u32 rx_delay = 0;
        u32 agc_ctrl = 0, agc_supp_cals = AR_PHY_AGC_CONTROL_OFFSET_CAL |
                                          AR_PHY_AGC_CONTROL_FLTR_CAL   |
                                          AR_PHY_AGC_CONTROL_PKDET_CAL;
@@ -1042,17 +1073,22 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
                ar9003_hw_rtt_clear_hist(ah);
        }
 
-       if (rtt && !run_rtt_cal) {
-               agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
-               agc_supp_cals &= agc_ctrl;
-               agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
-                            AR_PHY_AGC_CONTROL_FLTR_CAL |
-                            AR_PHY_AGC_CONTROL_PKDET_CAL);
-               REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
+       if (rtt) {
+               if (!run_rtt_cal) {
+                       agc_ctrl = REG_READ(ah, AR_PHY_AGC_CONTROL);
+                       agc_supp_cals &= agc_ctrl;
+                       agc_ctrl &= ~(AR_PHY_AGC_CONTROL_OFFSET_CAL |
+                                     AR_PHY_AGC_CONTROL_FLTR_CAL |
+                                     AR_PHY_AGC_CONTROL_PKDET_CAL);
+                       REG_WRITE(ah, AR_PHY_AGC_CONTROL, agc_ctrl);
+               } else {
+                       if (ah->ah_flags & AH_FASTCC)
+                               run_agc_cal = true;
+               }
        }
 
        if (ah->enabled_cals & TX_CL_CAL) {
-               if (caldata && caldata->done_txclcal_once)
+               if (caldata && test_bit(TXCLCAL_DONE, &caldata->cal_flags))
                        REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
                                    AR_PHY_CL_CAL_ENABLE);
                else {
@@ -1076,14 +1112,14 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
         * AGC calibration
         */
        if (ah->enabled_cals & TX_IQ_ON_AGC_CAL) {
-               if (caldata && !caldata->done_txiqcal_once)
+               if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags))
                        REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
                                    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
                else
                        REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
                                    AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
                txiqcal_done = run_agc_cal = true;
-       } else if (caldata && !caldata->done_txiqcal_once) {
+       } else if (caldata && !test_bit(TXIQCAL_DONE, &caldata->cal_flags)) {
                run_agc_cal = true;
                sep_iq_cal = true;
        }
@@ -1099,6 +1135,15 @@ skip_tx_iqcal:
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
        }
 
+       if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
+               rx_delay = REG_READ(ah, AR_PHY_RX_DELAY);
+               /* Disable BB_active */
+               REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS);
+               udelay(5);
+               REG_WRITE(ah, AR_PHY_RX_DELAY, AR_PHY_RX_DELAY_DELAY);
+               REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+       }
+
        if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
                /* Calibrate the AGC */
                REG_WRITE(ah, AR_PHY_AGC_CONTROL,
@@ -1110,7 +1155,12 @@ skip_tx_iqcal:
                                       AR_PHY_AGC_CONTROL_CAL,
                                       0, AH_WAIT_TIMEOUT);
 
-               ar9003_hw_do_manual_peak_cal(ah, chan);
+               ar9003_hw_do_manual_peak_cal(ah, chan, run_rtt_cal);
+       }
+
+       if (REG_READ(ah, AR_PHY_CL_CAL_CTL) & AR_PHY_CL_CAL_ENABLE) {
+               REG_WRITE(ah, AR_PHY_RX_DELAY, rx_delay);
+               udelay(5);
        }
 
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
@@ -1133,19 +1183,23 @@ skip_tx_iqcal:
 
        if (txiqcal_done)
                ar9003_hw_tx_iq_cal_post_proc(ah, is_reusable);
-       else if (caldata && caldata->done_txiqcal_once)
+       else if (caldata && test_bit(TXIQCAL_DONE, &caldata->cal_flags))
                ar9003_hw_tx_iq_cal_reload(ah);
 
        ar9003_hw_cl_cal_post_proc(ah, is_reusable);
 
        if (run_rtt_cal && caldata) {
                if (is_reusable) {
-                       if (!ath9k_hw_rfbus_req(ah))
+                       if (!ath9k_hw_rfbus_req(ah)) {
                                ath_err(ath9k_hw_common(ah),
                                        "Could not stop baseband\n");
-                       else
+                       } else {
                                ar9003_hw_rtt_fill_hist(ah);
 
+                               if (test_bit(SW_PKDET_DONE, &caldata->cal_flags))
+                                       ar9003_hw_rtt_load_hist(ah);
+                       }
+
                        ath9k_hw_rfbus_done(ah);
                }
 
index f4864807e15bc9fd127c439cb4770d7ff75b1c8a..1ec52356b5a16956dda70a2f7365103497b43c68 100644 (file)
@@ -2991,7 +2991,10 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
        case EEP_CHAIN_MASK_REDUCE:
                return (pBase->miscConfiguration >> 0x3) & 0x1;
        case EEP_ANT_DIV_CTL1:
-               return eep->base_ext1.ant_div_control;
+               if (AR_SREV_9565(ah))
+                       return AR9300_EEP_ANTDIV_CONTROL_DEFAULT_VALUE;
+               else
+                       return eep->base_ext1.ant_div_control;
        case EEP_ANTENNA_GAIN_5G:
                return eep->modalHeader5G.antennaGain;
        case EEP_ANTENNA_GAIN_2G:
@@ -3424,12 +3427,12 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        struct ar9300_base_eep_hdr *pBase;
 
        if (!dump_base_hdr) {
-               len += snprintf(buf + len, size - len,
-                               "%20s :\n", "2GHz modal Header");
+               len += scnprintf(buf + len, size - len,
+                                "%20s :\n", "2GHz modal Header");
                len = ar9003_dump_modal_eeprom(buf, len, size,
                                                &eep->modalHeader2G);
-               len += snprintf(buf + len, size - len,
-                               "%20s :\n", "5GHz modal Header");
+               len += scnprintf(buf + len, size - len,
+                                "%20s :\n", "5GHz modal Header");
                len = ar9003_dump_modal_eeprom(buf, len, size,
                                                &eep->modalHeader5G);
                goto out;
@@ -3479,8 +3482,8 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Rx Gain", pBase->txrxgain & 0xf);
        PR_EEP("SW Reg", le32_to_cpu(pBase->swreg));
 
-       len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
-                       ah->eeprom.ar9300_eep.macAddr);
+       len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+                        ah->eeprom.ar9300_eep.macAddr);
 out:
        if (len > size)
                len = size;
@@ -3656,9 +3659,23 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
                if (AR_SREV_9565(ah)) {
                        if (common->bt_ant_diversity) {
                                regval |= (1 << AR_PHY_ANT_SW_RX_PROT_S);
+
+                               REG_SET_BIT(ah, AR_PHY_RESTART,
+                                           AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
+
+                               /* Force WLAN LNA diversity ON */
+                               REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
+                                           AR_BTCOEX_WL_LNADIV_FORCE_ON);
                        } else {
                                regval &= ~(1 << AR_PHY_ANT_DIV_LNADIV_S);
                                regval &= ~(1 << AR_PHY_ANT_SW_RX_PROT_S);
+
+                               REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
+                                           (1 << AR_PHY_ANT_SW_RX_PROT_S));
+
+                               /* Force WLAN LNA diversity OFF */
+                               REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
+                                           AR_BTCOEX_WL_LNADIV_FORCE_ON);
                        }
                }
 
@@ -3669,7 +3686,8 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
                regval &= (~AR_FAST_DIV_ENABLE);
                regval |= ((value >> 7) & 0x1) << AR_FAST_DIV_ENABLE_S;
 
-               if (AR_SREV_9485(ah) && common->bt_ant_diversity)
+               if ((AR_SREV_9485(ah) || AR_SREV_9565(ah))
+                   && common->bt_ant_diversity)
                        regval |= AR_FAST_DIV_ENABLE;
 
                REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
index 75d4fb41962f312567cd161c900b9d3578007f0d..0e5daa58a4fc14371d360bdc5aa22937902bc824 100644 (file)
@@ -52,6 +52,8 @@
 #define AR9300_PAPRD_SCALE_2           0x70000000
 #define AR9300_PAPRD_SCALE_2_S         28
 
+#define AR9300_EEP_ANTDIV_CONTROL_DEFAULT_VALUE 0xc9
+
 /* Delta from which to start power to pdadc table */
 /* This offset is used in both open loop and closed loop power control
  * schemes. In open loop power control, it is not really needed, but for
index 608bb4824e2a2f800c057ff1e717f9219e8414db..b07f164d65cf582a63c2ddfbfccaced509a6ceca 100644 (file)
@@ -364,6 +364,8 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
 
                INIT_INI_ARRAY(&ah->iniModesFastClock,
                                ar9565_1p0_modes_fast_clock);
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9565_1p0_baseband_core_txfir_coeff_japan_2484);
        } else {
                /* mac */
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -628,6 +630,9 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
        else if (AR_SREV_9462_20(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar9462_common_rx_gain_table_2p0);
+       else if (AR_SREV_9565(ah))
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              ar9565_1p0_Common_rx_gain_table);
        else
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar9300Common_rx_gain_table_2p2);
index 8dd069259e7b7ea7d9dd40212571cab73424f131..7b94a6c7db3d50dd4feb53dd74e1973bd68f2e6d 100644 (file)
@@ -753,9 +753,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                    1 << AR_PHY_TIMING_CONTROL4_DO_GAIN_DC_IQ_CAL_SHIFT);
 
        if (caldata) {
-               caldata->done_txiqcal_once = false;
-               caldata->done_txclcal_once = false;
-               caldata->rtt_done = false;
+               clear_bit(TXIQCAL_DONE, &caldata->cal_flags);
+               clear_bit(TXCLCAL_DONE, &caldata->cal_flags);
+               clear_bit(RTT_DONE, &caldata->cal_flags);
        }
 
        if (!ath9k_hw_init_cal(ah, chan))
index e897648d32335dd1800df489916afa80fca81a2b..f3adafd337042897282bcdf3bca8db1fc5c7cc7f 100644 (file)
@@ -551,8 +551,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
        if (IS_CHAN_HT40(chan)) {
                phymode |= AR_PHY_GC_DYN2040_EN;
                /* Configure control (primary) channel at +-10MHz */
-               if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-                   (chan->chanmode == CHANNEL_G_HT40PLUS))
+               if (IS_CHAN_HT40PLUS(chan))
                        phymode |= AR_PHY_GC_DYN2040_PRI_CH;
 
        }
@@ -565,7 +564,7 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
        REG_WRITE(ah, AR_PHY_GEN_CTRL, phymode);
 
        /* Configure MAC for 20/40 operation */
-       ath9k_hw_set11nmac2040(ah);
+       ath9k_hw_set11nmac2040(ah, chan);
 
        /* global transmit timeout (25 TUs default)*/
        REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S);
@@ -627,11 +626,10 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
         * MAC addr only will fail.
         */
        val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
-       REG_WRITE(ah, AR_PCU_MISC_MODE2,
-                 val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE);
-
-       REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
-                   AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+       val |= AR_AGG_WEP_ENABLE_FIX |
+              AR_AGG_WEP_ENABLE |
+              AR_PCU_MISC_MODE2_CFP_IGNORE;
+       REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
 
        if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
                REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
@@ -683,41 +681,22 @@ static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah,
 {
        int ret;
 
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-               if (chan->channel <= 5350)
-                       ret = 1;
-               else if ((chan->channel > 5350) && (chan->channel <= 5600))
-                       ret = 3;
+       if (IS_CHAN_2GHZ(chan)) {
+               if (IS_CHAN_HT40(chan))
+                       return 7;
                else
-                       ret = 5;
-               break;
-
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               if (chan->channel <= 5350)
-                       ret = 2;
-               else if ((chan->channel > 5350) && (chan->channel <= 5600))
-                       ret = 4;
-               else
-                       ret = 6;
-               break;
-
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_B:
-               ret = 8;
-               break;
+                       return 8;
+       }
 
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               ret = 7;
-               break;
+       if (chan->channel <= 5350)
+               ret = 1;
+       else if ((chan->channel > 5350) && (chan->channel <= 5600))
+               ret = 3;
+       else
+               ret = 5;
 
-       default:
-               ret = -EINVAL;
-       }
+       if (IS_CHAN_HT40(chan))
+               ret++;
 
        return ret;
 }
@@ -728,28 +707,10 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        unsigned int regWrites = 0, i;
        u32 modesIndex;
 
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-               modesIndex = 1;
-               break;
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               modesIndex = 2;
-               break;
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_B:
-               modesIndex = 4;
-               break;
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               modesIndex = 3;
-               break;
-
-       default:
-               return -EINVAL;
-       }
+       if (IS_CHAN_5GHZ(chan))
+               modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
+       else
+               modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
 
        /*
         * SOC, MAC, BB, RADIO initvals.
@@ -847,8 +808,10 @@ static void ar9003_hw_set_rfmode(struct ath_hw *ah,
        if (chan == NULL)
                return;
 
-       rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan))
-               ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM;
+       if (IS_CHAN_2GHZ(chan))
+               rfMode |= AR_PHY_MODE_DYNAMIC;
+       else
+               rfMode |= AR_PHY_MODE_OFDM;
 
        if (IS_CHAN_A_FAST_CLOCK(ah, chan))
                rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE);
@@ -1274,12 +1237,11 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah)
        aniState = &ah->ani;
        iniDef = &aniState->iniDef;
 
-       ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz/0x%x\n",
+       ath_dbg(common, ANI, "ver %d.%d opmode %u chan %d Mhz\n",
                ah->hw_version.macVersion,
                ah->hw_version.macRev,
                ah->opmode,
-               chan->channel,
-               chan->channelFlags);
+               chan->channel);
 
        val = REG_READ(ah, AR_PHY_SFCORR);
        iniDef->m1Thresh = MS(val, AR_PHY_SFCORR_M1_THRESH);
@@ -1375,15 +1337,19 @@ static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah,
                                  AR_PHY_ANT_FAST_DIV_BIAS_S;
 
        if (AR_SREV_9330_11(ah)) {
+               antconf->lna1_lna2_switch_delta = -1;
                antconf->lna1_lna2_delta = -9;
                antconf->div_group = 1;
        } else if (AR_SREV_9485(ah)) {
+               antconf->lna1_lna2_switch_delta = -1;
                antconf->lna1_lna2_delta = -9;
                antconf->div_group = 2;
        } else if (AR_SREV_9565(ah)) {
-               antconf->lna1_lna2_delta = -3;
+               antconf->lna1_lna2_switch_delta = 3;
+               antconf->lna1_lna2_delta = -9;
                antconf->div_group = 3;
        } else {
+               antconf->lna1_lna2_switch_delta = -1;
                antconf->lna1_lna2_delta = -3;
                antconf->div_group = 0;
        }
@@ -1488,18 +1454,25 @@ static void ar9003_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
                }
        } else if (AR_SREV_9565(ah)) {
                if (enable) {
+                       REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
+                                   AR_ANT_DIV_ENABLE);
                        REG_SET_BIT(ah, AR_PHY_MC_GAIN_CTRL,
                                    (1 << AR_PHY_ANT_SW_RX_PROT_S));
-                       if (ah->curchan && IS_CHAN_2GHZ(ah->curchan))
-                               REG_SET_BIT(ah, AR_PHY_RESTART,
-                                           AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
+                       REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
+                                   AR_FAST_DIV_ENABLE);
+                       REG_SET_BIT(ah, AR_PHY_RESTART,
+                                   AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
                        REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV,
                                    AR_BTCOEX_WL_LNADIV_FORCE_ON);
                } else {
-                       REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE);
+                       REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
+                                   AR_ANT_DIV_ENABLE);
                        REG_CLR_BIT(ah, AR_PHY_MC_GAIN_CTRL,
                                    (1 << AR_PHY_ANT_SW_RX_PROT_S));
-                       REG_CLR_BIT(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE);
+                       REG_CLR_BIT(ah, AR_PHY_CCK_DETECT,
+                                   AR_FAST_DIV_ENABLE);
+                       REG_CLR_BIT(ah, AR_PHY_RESTART,
+                                   AR_PHY_RESTART_ENABLE_DIV_M2FLAG);
                        REG_CLR_BIT(ah, AR_BTCOEX_WL_LNADIV,
                                    AR_BTCOEX_WL_LNADIV_FORCE_ON);
 
@@ -1526,28 +1499,10 @@ static int ar9003_hw_fast_chan_change(struct ath_hw *ah,
        unsigned int regWrites = 0;
        u32 modesIndex;
 
-       switch (chan->chanmode) {
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-               modesIndex = 1;
-               break;
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               modesIndex = 2;
-               break;
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_B:
-               modesIndex = 4;
-               break;
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               modesIndex = 3;
-               break;
-
-       default:
-               return -EINVAL;
-       }
+       if (IS_CHAN_5GHZ(chan))
+               modesIndex = IS_CHAN_HT40(chan) ? 2 : 1;
+       else
+               modesIndex = IS_CHAN_HT40(chan) ? 3 : 4;
 
        if (modesIndex == ah->modes_index) {
                *ini_reloaded = false;
index 6fd752321e3616c171c81be16a754b31486de667..fca624322dc8886f991632d7a2d5e78b0bdfa114 100644 (file)
 
 #define AR_PHY_CCA_NOM_VAL_9462_2GHZ          -127
 #define AR_PHY_CCA_MIN_GOOD_VAL_9462_2GHZ     -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9462_2GHZ     -60
+#define AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_2GHZ -95
 #define AR_PHY_CCA_NOM_VAL_9462_5GHZ          -127
 #define AR_PHY_CCA_MIN_GOOD_VAL_9462_5GHZ     -127
+#define AR_PHY_CCA_MAX_GOOD_VAL_9462_5GHZ     -60
+#define AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_5GHZ -100
 
 #define AR_PHY_CCA_NOM_VAL_9330_2GHZ          -118
 
index 74de3539c2c8337680bb273933ea7158b0e946ec..934418872e8e156a641145a512280f3bee6f86bd 100644 (file)
@@ -118,6 +118,27 @@ void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
        }
 }
 
+static void ar9003_hw_patch_rtt(struct ath_hw *ah, int index, int chain)
+{
+       int agc, caldac;
+
+       if (!test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
+               return;
+
+       if ((index != 5) || (chain >= 2))
+               return;
+
+       agc = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                            AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE);
+       if (!agc)
+               return;
+
+       caldac = ah->caldata->caldac[chain];
+       ah->caldata->rtt_table[chain][index] &= 0xFFFF05FF;
+       caldac = (caldac & 0x20) | ((caldac & 0x1F) << 7);
+       ah->caldata->rtt_table[chain][index] |= (caldac << 4);
+}
+
 static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
 {
        u32 val;
@@ -155,13 +176,16 @@ void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
                for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
                        ah->caldata->rtt_table[chain][i] =
                                ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
+
+                       ar9003_hw_patch_rtt(ah, i, chain);
+
                        ath_dbg(ath9k_hw_common(ah), CALIBRATE,
                                "RTT value at idx %d, chain %d is: 0x%x\n",
                                i, chain, ah->caldata->rtt_table[chain][i]);
                }
        }
 
-       ah->caldata->rtt_done = true;
+       set_bit(RTT_DONE, &ah->caldata->cal_flags);
 }
 
 void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
@@ -176,7 +200,7 @@ void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
        }
 
        if (ah->caldata)
-               ah->caldata->rtt_done = false;
+               clear_bit(RTT_DONE, &ah->caldata->cal_flags);
 }
 
 bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
@@ -186,11 +210,37 @@ bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
        if (!ah->caldata)
                return false;
 
-       if (!ah->caldata->rtt_done)
+       if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags)) {
+               if (IS_CHAN_2GHZ(chan)){
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
+                                     AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
+                                     ah->caldata->caldac[0]);
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
+                                     AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
+                                     ah->caldata->caldac[1]);
+               } else {
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
+                                     AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
+                                     ah->caldata->caldac[0]);
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
+                                     AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
+                                     ah->caldata->caldac[1]);
+               }
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(1),
+                             AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(0),
+                             AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
+       }
+
+       if (!test_bit(RTT_DONE, &ah->caldata->cal_flags))
                return false;
 
        ar9003_hw_rtt_enable(ah);
-       ar9003_hw_rtt_set_mask(ah, 0x10);
+
+       if (test_bit(SW_PKDET_DONE, &ah->caldata->cal_flags))
+               ar9003_hw_rtt_set_mask(ah, 0x30);
+       else
+               ar9003_hw_rtt_set_mask(ah, 0x10);
 
        if (!ath9k_hw_rfbus_req(ah)) {
                ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
index 88ff1d7b53ab41c642333d553646e90065c3045b..6f899c6926474ba2f60cd642399e10d61814ec3d 100644 (file)
 
 /* AR9485 1.1 */
 
-#define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble
+static const u32 ar9485_1_1_mac_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160},
+       {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c},
+       {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38},
+       {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00},
+       {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b},
+       {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810},
+       {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a},
+       {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440},
+};
 
 static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
        /* Addr      allmodes  */
@@ -34,6 +44,7 @@ static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
        {0x00009e00, 0x037216a0},
        {0x00009e04, 0x00182020},
        {0x00009e18, 0x00000000},
+       {0x00009e20, 0x000003a8},
        {0x00009e2c, 0x00004121},
        {0x00009e44, 0x02282324},
        {0x0000a000, 0x00060005},
@@ -174,7 +185,7 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
        {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
        {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da},
        {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
        {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
@@ -200,14 +211,14 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
        {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
        {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62001eee, 0x62001eee},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001ff6, 0x66001ff6},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
        {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -263,6 +274,11 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
 static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
        {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
        {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
@@ -297,6 +313,22 @@ static const u32 ar9485Modes_green_ob_db_tx_gain_1_1[][5] = {
        {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
        {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
        {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
+       {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
+       {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
+       {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
        {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
        {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
        {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
@@ -341,6 +373,100 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
        {0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84},
        {0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000},
        {0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050da, 0x000050da},
+       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62001eee, 0x62001eee},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001ff6, 0x66001ff6},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001ff6, 0x66001ff6},
+       {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
+       {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
+       {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
+       {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
+
+static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
        {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
@@ -427,7 +553,7 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
        {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
 };
 
-static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
+static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
        {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
@@ -521,12 +647,15 @@ static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
        {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
 };
 
-#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
-
 static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003},
-       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2dc, 0x00000000, 0x00000000, 0xffad452a, 0xffad452a},
+       {0x0000a2e0, 0x00000000, 0x00000000, 0xffc98634, 0xffc98634},
+       {0x0000a2e4, 0x00000000, 0x00000000, 0xfff60780, 0xfff60780},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0xfffff800, 0xfffff800},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9},
        {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000},
        {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006},
        {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201},
@@ -543,23 +672,39 @@ static const u32 ar9485Modes_green_spur_ob_db_tx_gain_1_1[][5] = {
        {0x0000a530, 0x48023ec6, 0x48023ec6, 0x310006e0, 0x310006e0},
        {0x0000a534, 0x4d023f01, 0x4d023f01, 0x330006e0, 0x330006e0},
        {0x0000a538, 0x53023f4b, 0x53023f4b, 0x3e0008e3, 0x3e0008e3},
-       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x410008e5, 0x410008e5},
-       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x430008e6, 0x430008e6},
-       {0x0000a544, 0x6502feca, 0x6502feca, 0x4a0008ec, 0x4a0008ec},
-       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4e0008f1, 0x4e0008f1},
-       {0x0000a54c, 0x7203feca, 0x7203feca, 0x520008f3, 0x520008f3},
-       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x54000eed, 0x54000eed},
-       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x58000ef1, 0x58000ef1},
-       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5c000ef3, 0x5c000ef3},
-       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x60000ef5, 0x60000ef5},
-       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x62000ef6, 0x62000ef6},
-       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x62000ef6, 0x62000ef6},
-       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
-       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
-       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
-       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
-       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
-       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x430008e6, 0x430008e6},
+       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4a0008ec, 0x4a0008ec},
+       {0x0000a544, 0x6502feca, 0x6502feca, 0x4e0008f1, 0x4e0008f1},
+       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x520008f3, 0x520008f3},
+       {0x0000a54c, 0x7203feca, 0x7203feca, 0x54000eed, 0x54000eed},
+       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x58000ef1, 0x58000ef1},
+       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5c000ef3, 0x5c000ef3},
+       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x62000ef6, 0x62000ef6},
+       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001ff0, 0x66001ff0},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x68001ff6, 0x68001ff6},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x68001ff6, 0x68001ff6},
+       {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a58c, 0x00000000, 0x00000000, 0x01804000, 0x01804000},
+       {0x0000a590, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a594, 0x00000000, 0x00000000, 0x0340ca02, 0x0340ca02},
+       {0x0000a598, 0x00000000, 0x00000000, 0x0340cd03, 0x0340cd03},
+       {0x0000a59c, 0x00000000, 0x00000000, 0x0340cd03, 0x0340cd03},
+       {0x0000a5a0, 0x00000000, 0x00000000, 0x06415304, 0x06415304},
+       {0x0000a5a4, 0x00000000, 0x00000000, 0x04c11905, 0x04c11905},
+       {0x0000a5a8, 0x00000000, 0x00000000, 0x06415905, 0x06415905},
+       {0x0000a5ac, 0x00000000, 0x00000000, 0x06415905, 0x06415905},
+       {0x0000a5b0, 0x00000000, 0x00000000, 0x06415905, 0x06415905},
+       {0x0000a5b4, 0x00000000, 0x00000000, 0x06415905, 0x06415905},
+       {0x0000a5b8, 0x00000000, 0x00000000, 0x06415905, 0x06415905},
+       {0x0000a5bc, 0x00000000, 0x00000000, 0x06415905, 0x06415905},
        {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
        {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
        {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a},
@@ -823,6 +968,7 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
        {0x00009e00, 0x03721b20},
        {0x00009e04, 0x00082020},
        {0x00009e18, 0x0300501e},
+       {0x00009e20, 0x000003ba},
        {0x00009e2c, 0x00002e21},
        {0x00009e44, 0x02182324},
        {0x0000a000, 0x00060005},
@@ -1001,7 +1147,6 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
        {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
        {0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
        {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
        {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -1020,7 +1165,7 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
        {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0},
        {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
-       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
+       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
        {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982},
        {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -1206,6 +1351,11 @@ static const u32 ar9485_1_1_mac_core[][2] = {
        {0x000083d0, 0x000301ff},
 };
 
-#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
+static const u32 ar9485_1_1_baseband_core_txfir_coeff_japan_2484[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a398, 0x00000000},
+       {0x0000a39c, 0x6f7f0301},
+       {0x0000a3a0, 0xca9228ee},
+};
 
 #endif /* INITVALS_9485_H */
index e85a8b076c223e5bd3fbc4549789519c296b7761..a8c757b6124fdac483e21149733c18944f160fd7 100644 (file)
@@ -272,9 +272,9 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
        {0x0000a398, 0x001f0e0f},
        {0x0000a39c, 0x0075393f},
        {0x0000a3a0, 0xb79f6427},
-       {0x0000a3a4, 0x00000000},
-       {0x0000a3a8, 0xaaaaaaaa},
-       {0x0000a3ac, 0x3c466478},
+       {0x0000a3a4, 0x00000011},
+       {0x0000a3a8, 0xaaaaaa6e},
+       {0x0000a3ac, 0x3c466455},
        {0x0000a3c0, 0x20202020},
        {0x0000a3c4, 0x22222220},
        {0x0000a3c8, 0x20200020},
@@ -295,11 +295,11 @@ static const u32 ar9565_1p0_baseband_core[][2] = {
        {0x0000a404, 0x00000000},
        {0x0000a408, 0x0e79e5c6},
        {0x0000a40c, 0x00820820},
-       {0x0000a414, 0x1ce739ce},
+       {0x0000a414, 0x1ce739c5},
        {0x0000a418, 0x2d001dce},
-       {0x0000a41c, 0x1ce739ce},
+       {0x0000a41c, 0x1ce739c5},
        {0x0000a420, 0x000001ce},
-       {0x0000a424, 0x1ce739ce},
+       {0x0000a424, 0x1ce739c5},
        {0x0000a428, 0x000001ce},
        {0x0000a42c, 0x1ce739ce},
        {0x0000a430, 0x1ce739ce},
@@ -351,9 +351,9 @@ static const u32 ar9565_1p0_baseband_postamble[][5] = {
        {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
-       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a4, 0x000003a4},
        {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
-       {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946222, 0xcf946222},
+       {0x00009e3c, 0xcf946222, 0xcf946222, 0xcf946220, 0xcf946220},
        {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
        {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -452,6 +452,7 @@ static const u32 ar9565_1p0_Common_rx_gain_table[][2] = {
        /* Addr      allmodes  */
        {0x00004050, 0x00300300},
        {0x0000406c, 0x00100000},
+       {0x00009e20, 0x000003b6},
        {0x0000a000, 0x00010000},
        {0x0000a004, 0x00030002},
        {0x0000a008, 0x00050004},
@@ -1230,4 +1231,11 @@ static const u32 ar9565_1p0_modes_high_power_tx_gain_table[][5] = {
        {0x00016054, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
 };
 
+static const u32 ar9565_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a398, 0x00000000},
+       {0x0000a39c, 0x6f7f0301},
+       {0x0000a3a0, 0xca9228ee},
+};
+
 #endif /* INITVALS_9565_1P0_H */
index 2ee35f677c0e8843cdc66534fd40cde15755275b..5492a0ce072922dc208874edc3058348683084a3 100644 (file)
@@ -64,7 +64,6 @@ struct ath_node;
 
 struct ath_config {
        u16 txpowlimit;
-       u8 cabqReadytime;
 };
 
 /*************************/
@@ -207,6 +206,14 @@ struct ath_frame_info {
        u8 baw_tracked : 1;
 };
 
+struct ath_rxbuf {
+       struct list_head list;
+       struct sk_buff *bf_mpdu;
+       void *bf_desc;
+       dma_addr_t bf_daddr;
+       dma_addr_t bf_buf_addr;
+};
+
 struct ath_buf_state {
        u8 bf_type;
        u8 bfs_paprd;
@@ -307,7 +314,7 @@ struct ath_rx {
        struct ath_descdma rxdma;
        struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX];
 
-       struct ath_buf *buf_hold;
+       struct ath_rxbuf *buf_hold;
        struct sk_buff *frag;
 
        u32 ampdu_ref;
@@ -459,8 +466,8 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
 
 #define ATH_DUMP_BTCOEX(_s, _val)                              \
        do {                                                    \
-               len += snprintf(buf + len, size - len,          \
-                               "%20s : %10d\n", _s, (_val));   \
+               len += scnprintf(buf + len, size - len,         \
+                                "%20s : %10d\n", _s, (_val));  \
        } while (0)
 
 enum bt_op_flags {
@@ -581,7 +588,6 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO_LOW_RSSI 50
 #define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2_LOW_RSSI 50
 
-#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
 #define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
 #define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
 #define ATH_ANT_DIV_COMB_LNA1_DELTA_LOW 2
@@ -626,12 +632,15 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs);
 /* Main driver core */
 /********************/
 
-#define ATH9K_PCI_CUS198     0x0001
-#define ATH9K_PCI_CUS230     0x0002
-#define ATH9K_PCI_CUS217     0x0004
-#define ATH9K_PCI_WOW        0x0008
-#define ATH9K_PCI_BT_ANT_DIV 0x0010
-#define ATH9K_PCI_D3_L1_WAR  0x0020
+#define ATH9K_PCI_CUS198      0x0001
+#define ATH9K_PCI_CUS230      0x0002
+#define ATH9K_PCI_CUS217      0x0004
+#define ATH9K_PCI_CUS252      0x0008
+#define ATH9K_PCI_WOW         0x0010
+#define ATH9K_PCI_BT_ANT_DIV  0x0020
+#define ATH9K_PCI_D3_L1_WAR   0x0040
+#define ATH9K_PCI_AR9565_1ANT 0x0080
+#define ATH9K_PCI_AR9565_2ANT 0x0100
 
 /*
  * Default cache line size, in bytes.
@@ -924,7 +933,6 @@ void ath9k_deinit_device(struct ath_softc *sc);
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath9k_reload_chainmask_settings(struct ath_softc *sc);
 
-bool ath9k_uses_beacons(int type);
 void ath9k_spectral_scan_trigger(struct ieee80211_hw *hw);
 int ath9k_spectral_scan_config(struct ieee80211_hw *hw,
                               enum spectral_mode spectral_mode);
index b5c16b3a37b953133038d0450616d3c5b2be16e3..17be35392bb4f5134996a6e14b6bdc2547d40de9 100644 (file)
@@ -334,6 +334,8 @@ void ath9k_beacon_tasklet(unsigned long data)
        if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
                sc->beacon.bmisscnt++;
 
+               ath9k_hw_check_nav(ah);
+
                if (!ath9k_hw_check_alive(ah))
                        ieee80211_queue_work(sc->hw, &sc->hw_check_work);
 
index 5e8219a91e252b3d4a9ac2f5fda599caf4ae9ae8..d8db74b0ef6654587fb7bdbc1b23b6db77849b94 100644 (file)
@@ -119,7 +119,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
                        ath_dbg(common, CALIBRATE,
                                "NFmid[%d] (%d) > MAX (%d), %s\n",
                                i, h[i].privNF, limit->max,
-                               (cal->nfcal_interference ?
+                               (test_bit(NFCAL_INTF, &cal->cal_flags) ?
                                 "not corrected (due to interference)" :
                                 "correcting to MAX"));
 
@@ -130,7 +130,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
                         * we bypass this limit here in order to better deal
                         * with our environment.
                         */
-                       if (!cal->nfcal_interference)
+                       if (!test_bit(NFCAL_INTF, &cal->cal_flags))
                                h[i].privNF = limit->max;
                }
        }
@@ -141,7 +141,7 @@ static void ath9k_hw_update_nfcal_hist_buffer(struct ath_hw *ah,
         * Re-enable the enforcement of the NF maximum again.
         */
        if (!high_nf_mid)
-               cal->nfcal_interference = false;
+               clear_bit(NFCAL_INTF, &cal->cal_flags);
 }
 
 static bool ath9k_hw_get_nf_thresh(struct ath_hw *ah,
@@ -186,7 +186,6 @@ void ath9k_hw_reset_calibration(struct ath_hw *ah,
 bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_conf *conf = &common->hw->conf;
        struct ath9k_cal_list *currCal = ah->cal_list_curr;
 
        if (!ah->caldata)
@@ -208,7 +207,7 @@ bool ath9k_hw_reset_calvalid(struct ath_hw *ah)
                return true;
 
        ath_dbg(common, CALIBRATE, "Resetting Cal %d state for channel %u\n",
-               currCal->calData->calType, conf->chandef.chan->center_freq);
+               currCal->calData->calType, ah->curchan->chan->center_freq);
 
        ah->caldata->CalValid &= ~currCal->calData->calType;
        currCal->calState = CAL_WAITING;
@@ -220,7 +219,7 @@ EXPORT_SYMBOL(ath9k_hw_reset_calvalid);
 void ath9k_hw_start_nfcal(struct ath_hw *ah, bool update)
 {
        if (ah->caldata)
-               ah->caldata->nfcal_pending = true;
+               set_bit(NFCAL_PENDING, &ah->caldata->cal_flags);
 
        REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
                    AR_PHY_AGC_CONTROL_ENABLE_NF);
@@ -242,7 +241,6 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
        int32_t val;
        u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_conf *conf = &common->hw->conf;
        s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
 
        if (ah->caldata)
@@ -252,7 +250,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
                if (chainmask & (1 << i)) {
                        s16 nfval;
 
-                       if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
+                       if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
                                continue;
 
                        if (h)
@@ -314,7 +312,7 @@ void ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
        ENABLE_REGWRITE_BUFFER(ah);
        for (i = 0; i < NUM_NF_READINGS; i++) {
                if (chainmask & (1 << i)) {
-                       if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
+                       if ((i >= AR5416_MAX_CHAINS) && !IS_CHAN_HT40(chan))
                                continue;
 
                        val = REG_READ(ah, ah->nf_regs[i]);
@@ -391,7 +389,7 @@ bool ath9k_hw_getnf(struct ath_hw *ah, struct ath9k_channel *chan)
        }
 
        h = caldata->nfCalHist;
-       caldata->nfcal_pending = false;
+       clear_bit(NFCAL_PENDING, &caldata->cal_flags);
        ath9k_hw_update_nfcal_hist_buffer(ah, caldata, nfarray);
        chan->noisefloor = h[0].privNF;
        ah->noise = ath9k_hw_getchan_noise(ah, chan);
@@ -408,7 +406,6 @@ void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
 
        ah->caldata->channel = chan->channel;
        ah->caldata->channelFlags = chan->channelFlags;
-       ah->caldata->chanmode = chan->chanmode;
        h = ah->caldata->nfCalHist;
        default_nf = ath9k_hw_get_default_nf(ah, chan);
        for (i = 0; i < NUM_NF_READINGS; i++) {
@@ -437,12 +434,12 @@ void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
         * the baseband update the internal NF value itself, similar to
         * what is being done after a full reset.
         */
-       if (!caldata->nfcal_pending)
+       if (!test_bit(NFCAL_PENDING, &caldata->cal_flags))
                ath9k_hw_start_nfcal(ah, true);
        else if (!(REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF))
                ath9k_hw_getnf(ah, ah->curchan);
 
-       caldata->nfcal_interference = true;
+       set_bit(NFCAL_INTF, &caldata->cal_flags);
 }
 EXPORT_SYMBOL(ath9k_hw_bstuck_nfcal);
 
index d3063c21e16c7efbd67d073c756de2198e5794e5..a7e5a05b2eff88e8d367cea6403058cc2813ebbc 100644 (file)
@@ -49,103 +49,64 @@ int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb)
 }
 EXPORT_SYMBOL(ath9k_cmn_get_hw_crypto_keytype);
 
-static u32 ath9k_get_extchanmode(struct cfg80211_chan_def *chandef)
-{
-       u32 chanmode = 0;
-
-       switch (chandef->chan->band) {
-       case IEEE80211_BAND_2GHZ:
-               switch (chandef->width) {
-               case NL80211_CHAN_WIDTH_20_NOHT:
-               case NL80211_CHAN_WIDTH_20:
-                       chanmode = CHANNEL_G_HT20;
-                       break;
-               case NL80211_CHAN_WIDTH_40:
-                       if (chandef->center_freq1 > chandef->chan->center_freq)
-                               chanmode = CHANNEL_G_HT40PLUS;
-                       else
-                               chanmode = CHANNEL_G_HT40MINUS;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       case IEEE80211_BAND_5GHZ:
-               switch (chandef->width) {
-               case NL80211_CHAN_WIDTH_20_NOHT:
-               case NL80211_CHAN_WIDTH_20:
-                       chanmode = CHANNEL_A_HT20;
-                       break;
-               case NL80211_CHAN_WIDTH_40:
-                       if (chandef->center_freq1 > chandef->chan->center_freq)
-                               chanmode = CHANNEL_A_HT40PLUS;
-                       else
-                               chanmode = CHANNEL_A_HT40MINUS;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return chanmode;
-}
-
 /*
  * Update internal channel flags.
  */
-void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
-                              struct cfg80211_chan_def *chandef)
+static void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
+                                     struct cfg80211_chan_def *chandef)
 {
-       ichan->channel = chandef->chan->center_freq;
-       ichan->chan = chandef->chan;
-
-       if (chandef->chan->band == IEEE80211_BAND_2GHZ) {
-               ichan->chanmode = CHANNEL_G;
-               ichan->channelFlags = CHANNEL_2GHZ | CHANNEL_OFDM;
-       } else {
-               ichan->chanmode = CHANNEL_A;
-               ichan->channelFlags = CHANNEL_5GHZ | CHANNEL_OFDM;
-       }
+       struct ieee80211_channel *chan = chandef->chan;
+       u16 flags = 0;
+
+       ichan->channel = chan->center_freq;
+       ichan->chan = chan;
+
+       if (chan->band == IEEE80211_BAND_5GHZ)
+               flags |= CHANNEL_5GHZ;
 
        switch (chandef->width) {
        case NL80211_CHAN_WIDTH_5:
-               ichan->channelFlags |= CHANNEL_QUARTER;
+               flags |= CHANNEL_QUARTER;
                break;
        case NL80211_CHAN_WIDTH_10:
-               ichan->channelFlags |= CHANNEL_HALF;
+               flags |= CHANNEL_HALF;
                break;
        case NL80211_CHAN_WIDTH_20_NOHT:
                break;
        case NL80211_CHAN_WIDTH_20:
+               flags |= CHANNEL_HT;
+               break;
        case NL80211_CHAN_WIDTH_40:
-               ichan->chanmode = ath9k_get_extchanmode(chandef);
+               if (chandef->center_freq1 > chandef->chan->center_freq)
+                       flags |= CHANNEL_HT40PLUS | CHANNEL_HT;
+               else
+                       flags |= CHANNEL_HT40MINUS | CHANNEL_HT;
                break;
        default:
                WARN_ON(1);
        }
+
+       ichan->channelFlags = flags;
 }
-EXPORT_SYMBOL(ath9k_cmn_update_ichannel);
 
 /*
  * Get the internal channel reference.
  */
-struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
-                                              struct ath_hw *ah)
+struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
+                                           struct ath_hw *ah,
+                                           struct cfg80211_chan_def *chandef)
 {
-       struct ieee80211_channel *curchan = hw->conf.chandef.chan;
+       struct ieee80211_channel *curchan = chandef->chan;
        struct ath9k_channel *channel;
        u8 chan_idx;
 
        chan_idx = curchan->hw_value;
        channel = &ah->channels[chan_idx];
-       ath9k_cmn_update_ichannel(channel, &hw->conf.chandef);
+       ath9k_cmn_update_ichannel(channel, chandef);
 
        return channel;
 }
-EXPORT_SYMBOL(ath9k_cmn_get_curchannel);
+EXPORT_SYMBOL(ath9k_cmn_get_channel);
 
 int ath9k_cmn_count_streams(unsigned int chainmask, int max)
 {
index e039bcbfbd7923b4f8013f1c4535915a83d4b1fc..eb85e1bdca889a4e43b46261be31e691ff403363 100644 (file)
        (((x) + ((mul)/2)) / (mul))
 
 int ath9k_cmn_get_hw_crypto_keytype(struct sk_buff *skb);
-void ath9k_cmn_update_ichannel(struct ath9k_channel *ichan,
-                              struct cfg80211_chan_def *chandef);
-struct ath9k_channel *ath9k_cmn_get_curchannel(struct ieee80211_hw *hw,
-                                              struct ath_hw *ah);
+struct ath9k_channel *ath9k_cmn_get_channel(struct ieee80211_hw *hw,
+                                           struct ath_hw *ah,
+                                           struct cfg80211_chan_def *chandef);
 int ath9k_cmn_count_streams(unsigned int chainmask, int max);
 void ath9k_cmn_btcoex_bt_stomp(struct ath_common *common,
                                  enum ath_stomp_type stomp_type);
index c088744a6bfb6ea924fb97b07fe47671b53f5e74..1be2c787aac9197609964c4e7adaf68ac1a4d0e2 100644 (file)
@@ -104,37 +104,37 @@ static ssize_t read_file_ani(struct file *file, char __user *user_buf,
                return -ENOMEM;
 
        if (common->disable_ani) {
-               len += snprintf(buf + len, size - len, "%s: %s\n",
-                               "ANI", "DISABLED");
+               len += scnprintf(buf + len, size - len, "%s: %s\n",
+                                "ANI", "DISABLED");
                goto exit;
        }
 
-       len += snprintf(buf + len, size - len, "%15s: %s\n",
-                       "ANI", "ENABLED");
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "ANI RESET", ah->stats.ast_ani_reset);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "SPUR UP", ah->stats.ast_ani_spurup);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "SPUR DOWN", ah->stats.ast_ani_spurup);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "MRC-CCK ON", ah->stats.ast_ani_ccklow);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "FIR-STEP UP", ah->stats.ast_ani_stepup);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
-       len += snprintf(buf + len, size - len, "%15s: %u\n",
-                       "CCK ERRORS", ah->stats.ast_ani_cckerrs);
+       len += scnprintf(buf + len, size - len, "%15s: %s\n",
+                        "ANI", "ENABLED");
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "ANI RESET", ah->stats.ast_ani_reset);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "SPUR UP", ah->stats.ast_ani_spurup);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "SPUR DOWN", ah->stats.ast_ani_spurup);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "OFDM WS-DET ON", ah->stats.ast_ani_ofdmon);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "OFDM WS-DET OFF", ah->stats.ast_ani_ofdmoff);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "MRC-CCK ON", ah->stats.ast_ani_ccklow);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "MRC-CCK OFF", ah->stats.ast_ani_cckhigh);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "FIR-STEP UP", ah->stats.ast_ani_stepup);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "FIR-STEP DOWN", ah->stats.ast_ani_stepdown);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "INV LISTENTIME", ah->stats.ast_ani_lneg_or_lzero);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "OFDM ERRORS", ah->stats.ast_ani_ofdmerrs);
+       len += scnprintf(buf + len, size - len, "%15s: %u\n",
+                        "CCK ERRORS", ah->stats.ast_ani_cckerrs);
 exit:
        if (len > size)
                len = size;
@@ -280,70 +280,70 @@ static ssize_t read_file_antenna_diversity(struct file *file,
                return -ENOMEM;
 
        if (!(pCap->hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB)) {
-               len += snprintf(buf + len, size - len, "%s\n",
-                               "Antenna Diversity Combining is disabled");
+               len += scnprintf(buf + len, size - len, "%s\n",
+                                "Antenna Diversity Combining is disabled");
                goto exit;
        }
 
        ath9k_ps_wakeup(sc);
        ath9k_hw_antdiv_comb_conf_get(ah, &div_ant_conf);
-       len += snprintf(buf + len, size - len, "Current MAIN config : %s\n",
-                       lna_conf_str[div_ant_conf.main_lna_conf]);
-       len += snprintf(buf + len, size - len, "Current ALT config  : %s\n",
-                       lna_conf_str[div_ant_conf.alt_lna_conf]);
-       len += snprintf(buf + len, size - len, "Average MAIN RSSI   : %d\n",
-                       as_main->rssi_avg);
-       len += snprintf(buf + len, size - len, "Average ALT RSSI    : %d\n\n",
-                       as_alt->rssi_avg);
+       len += scnprintf(buf + len, size - len, "Current MAIN config : %s\n",
+                        lna_conf_str[div_ant_conf.main_lna_conf]);
+       len += scnprintf(buf + len, size - len, "Current ALT config  : %s\n",
+                        lna_conf_str[div_ant_conf.alt_lna_conf]);
+       len += scnprintf(buf + len, size - len, "Average MAIN RSSI   : %d\n",
+                        as_main->rssi_avg);
+       len += scnprintf(buf + len, size - len, "Average ALT RSSI    : %d\n\n",
+                        as_alt->rssi_avg);
        ath9k_ps_restore(sc);
 
-       len += snprintf(buf + len, size - len, "Packet Receive Cnt:\n");
-       len += snprintf(buf + len, size - len, "-------------------\n");
-
-       len += snprintf(buf + len, size - len, "%30s%15s\n",
-                       "MAIN", "ALT");
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "TOTAL COUNT",
-                       as_main->recv_cnt,
-                       as_alt->recv_cnt);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA1",
-                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1],
-                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA2",
-                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2],
-                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA1 + LNA2",
-                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
-                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA1 - LNA2",
-                       as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
-                       as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
-
-       len += snprintf(buf + len, size - len, "\nLNA Config Attempts:\n");
-       len += snprintf(buf + len, size - len, "--------------------\n");
-
-       len += snprintf(buf + len, size - len, "%30s%15s\n",
-                       "MAIN", "ALT");
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA1",
-                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1],
-                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA2",
-                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2],
-                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA1 + LNA2",
-                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
-                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
-       len += snprintf(buf + len, size - len, "%-14s:%15d%15d\n",
-                       "LNA1 - LNA2",
-                       as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
-                       as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
+       len += scnprintf(buf + len, size - len, "Packet Receive Cnt:\n");
+       len += scnprintf(buf + len, size - len, "-------------------\n");
+
+       len += scnprintf(buf + len, size - len, "%30s%15s\n",
+                        "MAIN", "ALT");
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "TOTAL COUNT",
+                        as_main->recv_cnt,
+                        as_alt->recv_cnt);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA1",
+                        as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1],
+                        as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1]);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA2",
+                        as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2],
+                        as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA2]);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA1 + LNA2",
+                        as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
+                        as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA1 - LNA2",
+                        as_main->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
+                        as_alt->lna_recv_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
+
+       len += scnprintf(buf + len, size - len, "\nLNA Config Attempts:\n");
+       len += scnprintf(buf + len, size - len, "--------------------\n");
+
+       len += scnprintf(buf + len, size - len, "%30s%15s\n",
+                        "MAIN", "ALT");
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA1",
+                        as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1],
+                        as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1]);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA2",
+                        as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2],
+                        as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA2]);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA1 + LNA2",
+                        as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2],
+                        as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_PLUS_LNA2]);
+       len += scnprintf(buf + len, size - len, "%-14s:%15d%15d\n",
+                        "LNA1 - LNA2",
+                        as_main->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2],
+                        as_alt->lna_attempt_cnt[ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2]);
 
 exit:
        if (len > size)
@@ -385,21 +385,21 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                   (AR_MACMISC_MISC_OBS_BUS_1 <<
                    AR_MACMISC_MISC_OBS_BUS_MSB_S)));
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
-                       "Raw DMA Debug values:\n");
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
+                        "Raw DMA Debug values:\n");
 
        for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) {
                if (i % 4 == 0)
-                       len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
+                       len += scnprintf(buf + len, DMA_BUF_LEN - len, "\n");
 
                val[i] = REG_READ_D(ah, AR_DMADBG_0 + (i * sizeof(u32)));
-               len += snprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ",
-                               i, val[i]);
+               len += scnprintf(buf + len, DMA_BUF_LEN - len, "%d: %08x ",
+                                i, val[i]);
        }
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len, "\n\n");
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
-                       "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
+       len += scnprintf(buf + len, DMA_BUF_LEN - len, "\n\n");
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
+                        "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n");
 
        for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) {
                if (i == 8) {
@@ -412,39 +412,39 @@ static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                        dcuBase++;
                }
 
-               len += snprintf(buf + len, DMA_BUF_LEN - len,
-                       "%2d          %2x      %1x     %2x           %2x\n",
-                       i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
-                       (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
-                       val[2] & (0x7 << (i * 3)) >> (i * 3),
-                       (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
+               len += scnprintf(buf + len, DMA_BUF_LEN - len,
+                        "%2d          %2x      %1x     %2x           %2x\n",
+                        i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset,
+                        (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3),
+                        val[2] & (0x7 << (i * 3)) >> (i * 3),
+                        (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset);
        }
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len, "\n");
+       len += scnprintf(buf + len, DMA_BUF_LEN - len, "\n");
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
                "qcu_stitch state:   %2x    qcu_fetch state:        %2x\n",
                (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22);
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
                "qcu_complete state: %2x    dcu_complete state:     %2x\n",
                (val[3] & 0x1c000000) >> 26, (val[6] & 0x3));
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
                "dcu_arb state:      %2x    dcu_fp state:           %2x\n",
                (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27);
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
                "chan_idle_dur:     %3d    chan_idle_dur_valid:     %1d\n",
                (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10);
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
                "txfifo_valid_0:      %1d    txfifo_valid_1:          %1d\n",
                (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12);
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
                "txfifo_dcu_num_0:   %2d    txfifo_dcu_num_1:       %2d\n",
                (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17);
 
-       len += snprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n",
-                       REG_READ_D(ah, AR_OBS_BUS_1));
-       len += snprintf(buf + len, DMA_BUF_LEN - len,
-                       "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));
+       len += scnprintf(buf + len, DMA_BUF_LEN - len, "pcu observe: 0x%x\n",
+                        REG_READ_D(ah, AR_OBS_BUS_1));
+       len += scnprintf(buf + len, DMA_BUF_LEN - len,
+                        "AR_CR: 0x%x\n", REG_READ_D(ah, AR_CR));
 
        ath9k_ps_restore(sc);
 
@@ -530,9 +530,9 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
 
 #define PR_IS(a, s)                                            \
        do {                                                    \
-               len += snprintf(buf + len, mxlen - len,         \
-                               "%21s: %10u\n", a,              \
-                               sc->debug.stats.istats.s);      \
+               len += scnprintf(buf + len, mxlen - len,        \
+                                "%21s: %10u\n", a,             \
+                                sc->debug.stats.istats.s);     \
        } while (0)
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
@@ -563,8 +563,8 @@ static ssize_t read_file_interrupt(struct file *file, char __user *user_buf,
        PR_IS("GENTIMER", gen_timer);
        PR_IS("TOTAL", total);
 
-       len += snprintf(buf + len, mxlen - len,
-                       "SYNC_CAUSE stats:\n");
+       len += scnprintf(buf + len, mxlen - len,
+                        "SYNC_CAUSE stats:\n");
 
        PR_IS("Sync-All", sync_cause_all);
        PR_IS("RTC-IRQ", sync_rtc_irq);
@@ -655,16 +655,16 @@ static ssize_t print_queue(struct ath_softc *sc, struct ath_txq *txq,
 
        ath_txq_lock(sc, txq);
 
-       len += snprintf(buf + len, size - len, "%s: %d ",
-                       "qnum", txq->axq_qnum);
-       len += snprintf(buf + len, size - len, "%s: %2d ",
-                       "qdepth", txq->axq_depth);
-       len += snprintf(buf + len, size - len, "%s: %2d ",
-                       "ampdu-depth", txq->axq_ampdu_depth);
-       len += snprintf(buf + len, size - len, "%s: %3d ",
-                       "pending", txq->pending_frames);
-       len += snprintf(buf + len, size - len, "%s: %d\n",
-                       "stopped", txq->stopped);
+       len += scnprintf(buf + len, size - len, "%s: %d ",
+                        "qnum", txq->axq_qnum);
+       len += scnprintf(buf + len, size - len, "%s: %2d ",
+                        "qdepth", txq->axq_depth);
+       len += scnprintf(buf + len, size - len, "%s: %2d ",
+                        "ampdu-depth", txq->axq_ampdu_depth);
+       len += scnprintf(buf + len, size - len, "%s: %3d ",
+                        "pending", txq->pending_frames);
+       len += scnprintf(buf + len, size - len, "%s: %d\n",
+                        "stopped", txq->stopped);
 
        ath_txq_unlock(sc, txq);
        return len;
@@ -687,11 +687,11 @@ static ssize_t read_file_queues(struct file *file, char __user *user_buf,
 
        for (i = 0; i < IEEE80211_NUM_ACS; i++) {
                txq = sc->tx.txq_map[i];
-               len += snprintf(buf + len, size - len, "(%s):  ", qname[i]);
+               len += scnprintf(buf + len, size - len, "(%s):  ", qname[i]);
                len += print_queue(sc, txq, buf + len, size - len);
        }
 
-       len += snprintf(buf + len, size - len, "(CAB): ");
+       len += scnprintf(buf + len, size - len, "(CAB): ");
        len += print_queue(sc, sc->beacon.cabq, buf + len, size - len);
 
        if (len > size)
@@ -716,80 +716,82 @@ static ssize_t read_file_misc(struct file *file, char __user *user_buf,
        unsigned int reg;
        u32 rxfilter;
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "BSSID: %pM\n", common->curbssid);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "BSSID-MASK: %pM\n", common->bssidmask);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "OPMODE: %s\n", ath_opmode_to_string(sc->sc_ah->opmode));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "BSSID: %pM\n", common->curbssid);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "BSSID-MASK: %pM\n", common->bssidmask);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "OPMODE: %s\n",
+                        ath_opmode_to_string(sc->sc_ah->opmode));
 
        ath9k_ps_wakeup(sc);
        rxfilter = ath9k_hw_getrxfilter(sc->sc_ah);
        ath9k_ps_restore(sc);
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "RXFILTER: 0x%x", rxfilter);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "RXFILTER: 0x%x", rxfilter);
 
        if (rxfilter & ATH9K_RX_FILTER_UCAST)
-               len += snprintf(buf + len, sizeof(buf) - len, " UCAST");
+               len += scnprintf(buf + len, sizeof(buf) - len, " UCAST");
        if (rxfilter & ATH9K_RX_FILTER_MCAST)
-               len += snprintf(buf + len, sizeof(buf) - len, " MCAST");
+               len += scnprintf(buf + len, sizeof(buf) - len, " MCAST");
        if (rxfilter & ATH9K_RX_FILTER_BCAST)
-               len += snprintf(buf + len, sizeof(buf) - len, " BCAST");
+               len += scnprintf(buf + len, sizeof(buf) - len, " BCAST");
        if (rxfilter & ATH9K_RX_FILTER_CONTROL)
-               len += snprintf(buf + len, sizeof(buf) - len, " CONTROL");
+               len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL");
        if (rxfilter & ATH9K_RX_FILTER_BEACON)
-               len += snprintf(buf + len, sizeof(buf) - len, " BEACON");
+               len += scnprintf(buf + len, sizeof(buf) - len, " BEACON");
        if (rxfilter & ATH9K_RX_FILTER_PROM)
-               len += snprintf(buf + len, sizeof(buf) - len, " PROM");
+               len += scnprintf(buf + len, sizeof(buf) - len, " PROM");
        if (rxfilter & ATH9K_RX_FILTER_PROBEREQ)
-               len += snprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
+               len += scnprintf(buf + len, sizeof(buf) - len, " PROBEREQ");
        if (rxfilter & ATH9K_RX_FILTER_PHYERR)
-               len += snprintf(buf + len, sizeof(buf) - len, " PHYERR");
+               len += scnprintf(buf + len, sizeof(buf) - len, " PHYERR");
        if (rxfilter & ATH9K_RX_FILTER_MYBEACON)
-               len += snprintf(buf + len, sizeof(buf) - len, " MYBEACON");
+               len += scnprintf(buf + len, sizeof(buf) - len, " MYBEACON");
        if (rxfilter & ATH9K_RX_FILTER_COMP_BAR)
-               len += snprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
+               len += scnprintf(buf + len, sizeof(buf) - len, " COMP_BAR");
        if (rxfilter & ATH9K_RX_FILTER_PSPOLL)
-               len += snprintf(buf + len, sizeof(buf) - len, " PSPOLL");
+               len += scnprintf(buf + len, sizeof(buf) - len, " PSPOLL");
        if (rxfilter & ATH9K_RX_FILTER_PHYRADAR)
-               len += snprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
+               len += scnprintf(buf + len, sizeof(buf) - len, " PHYRADAR");
        if (rxfilter & ATH9K_RX_FILTER_MCAST_BCAST_ALL)
-               len += snprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");
+               len += scnprintf(buf + len, sizeof(buf) - len, " MCAST_BCAST_ALL");
        if (rxfilter & ATH9K_RX_FILTER_CONTROL_WRAPPER)
-               len += snprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER");
+               len += scnprintf(buf + len, sizeof(buf) - len, " CONTROL_WRAPPER");
 
-       len += snprintf(buf + len, sizeof(buf) - len, "\n");
+       len += scnprintf(buf + len, sizeof(buf) - len, "\n");
 
        reg = sc->sc_ah->imask;
 
-       len += snprintf(buf + len, sizeof(buf) - len, "INTERRUPT-MASK: 0x%x", reg);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "INTERRUPT-MASK: 0x%x", reg);
 
        if (reg & ATH9K_INT_SWBA)
-               len += snprintf(buf + len, sizeof(buf) - len, " SWBA");
+               len += scnprintf(buf + len, sizeof(buf) - len, " SWBA");
        if (reg & ATH9K_INT_BMISS)
-               len += snprintf(buf + len, sizeof(buf) - len, " BMISS");
+               len += scnprintf(buf + len, sizeof(buf) - len, " BMISS");
        if (reg & ATH9K_INT_CST)
-               len += snprintf(buf + len, sizeof(buf) - len, " CST");
+               len += scnprintf(buf + len, sizeof(buf) - len, " CST");
        if (reg & ATH9K_INT_RX)
-               len += snprintf(buf + len, sizeof(buf) - len, " RX");
+               len += scnprintf(buf + len, sizeof(buf) - len, " RX");
        if (reg & ATH9K_INT_RXHP)
-               len += snprintf(buf + len, sizeof(buf) - len, " RXHP");
+               len += scnprintf(buf + len, sizeof(buf) - len, " RXHP");
        if (reg & ATH9K_INT_RXLP)
-               len += snprintf(buf + len, sizeof(buf) - len, " RXLP");
+               len += scnprintf(buf + len, sizeof(buf) - len, " RXLP");
        if (reg & ATH9K_INT_BB_WATCHDOG)
-               len += snprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG");
+               len += scnprintf(buf + len, sizeof(buf) - len, " BB_WATCHDOG");
 
-       len += snprintf(buf + len, sizeof(buf) - len, "\n");
+       len += scnprintf(buf + len, sizeof(buf) - len, "\n");
 
        ath9k_calculate_iter_data(hw, NULL, &iter_data);
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
-                       " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
-                       iter_data.naps, iter_data.nstations, iter_data.nmeshes,
-                       iter_data.nwds, iter_data.nadhocs,
-                       sc->nvifs, sc->nbcnvifs);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "VIF-COUNTS: AP: %i STA: %i MESH: %i WDS: %i"
+                        " ADHOC: %i TOTAL: %hi BEACON-VIF: %hi\n",
+                        iter_data.naps, iter_data.nstations, iter_data.nmeshes,
+                        iter_data.nwds, iter_data.nadhocs,
+                        sc->nvifs, sc->nbcnvifs);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -805,27 +807,27 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
        char buf[512];
        unsigned int len = 0;
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "Baseband Hang",
-                       sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "Baseband Watchdog",
-                       sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "Fatal HW Error",
-                       sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "TX HW error",
-                       sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "TX Path Hang",
-                       sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "PLL RX Hang",
-                       sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%17s: %2d\n", "MCI Reset",
-                       sc->debug.stats.reset[RESET_TYPE_MCI]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "Baseband Hang",
+                        sc->debug.stats.reset[RESET_TYPE_BB_HANG]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "Baseband Watchdog",
+                        sc->debug.stats.reset[RESET_TYPE_BB_WATCHDOG]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "Fatal HW Error",
+                        sc->debug.stats.reset[RESET_TYPE_FATAL_INT]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "TX HW error",
+                        sc->debug.stats.reset[RESET_TYPE_TX_ERROR]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "TX Path Hang",
+                        sc->debug.stats.reset[RESET_TYPE_TX_HANG]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "PLL RX Hang",
+                        sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%17s: %2d\n", "MCI Reset",
+                        sc->debug.stats.reset[RESET_TYPE_MCI]);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -902,14 +904,14 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
                              size_t count, loff_t *ppos)
 {
 #define PHY_ERR(s, p) \
-       len += snprintf(buf + len, size - len, "%22s : %10u\n", s, \
-                       sc->debug.stats.rxstats.phy_err_stats[p]);
+       len += scnprintf(buf + len, size - len, "%22s : %10u\n", s, \
+                        sc->debug.stats.rxstats.phy_err_stats[p]);
 
 #define RXS_ERR(s, e)                                      \
        do {                                                \
-               len += snprintf(buf + len, size - len,      \
-                               "%22s : %10u\n", s,         \
-                               sc->debug.stats.rxstats.e); \
+               len += scnprintf(buf + len, size - len,     \
+                                "%22s : %10u\n", s,        \
+                                sc->debug.stats.rxstats.e);\
        } while (0)
 
        struct ath_softc *sc = file->private_data;
@@ -1439,22 +1441,22 @@ static ssize_t read_file_dump_nfcal(struct file *file, char __user *user_buf,
        if (!buf)
                return -ENOMEM;
 
-       len += snprintf(buf + len, size - len,
-                       "Channel Noise Floor : %d\n", ah->noise);
-       len += snprintf(buf + len, size - len,
-                       "Chain | privNF | # Readings | NF Readings\n");
+       len += scnprintf(buf + len, size - len,
+                        "Channel Noise Floor : %d\n", ah->noise);
+       len += scnprintf(buf + len, size - len,
+                        "Chain | privNF | # Readings | NF Readings\n");
        for (i = 0; i < NUM_NF_READINGS; i++) {
                if (!(chainmask & (1 << i)) ||
                    ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
                        continue;
 
                nread = AR_PHY_CCA_FILTERWINDOW_LENGTH - h[i].invalidNFcount;
-               len += snprintf(buf + len, size - len, " %d\t %d\t %d\t\t",
-                               i, h[i].privNF, nread);
+               len += scnprintf(buf + len, size - len, " %d\t %d\t %d\t\t",
+                                i, h[i].privNF, nread);
                for (j = 0; j < nread; j++)
-                       len += snprintf(buf + len, size - len,
-                                       " %d", h[i].nfCalBuffer[j]);
-               len += snprintf(buf + len, size - len, "\n");
+                       len += scnprintf(buf + len, size - len,
+                                        " %d", h[i].nfCalBuffer[j]);
+               len += scnprintf(buf + len, size - len, "\n");
        }
 
        if (len > size)
@@ -1543,8 +1545,8 @@ static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,
                return -ENOMEM;
 
        if (!sc->sc_ah->common.btcoex_enabled) {
-               len = snprintf(buf, size, "%s\n",
-                              "BTCOEX is disabled");
+               len = scnprintf(buf, size, "%s\n",
+                               "BTCOEX is disabled");
                goto exit;
        }
 
@@ -1582,43 +1584,43 @@ static ssize_t read_file_node_stat(struct file *file, char __user *user_buf,
                return -ENOMEM;
 
        if (!an->sta->ht_cap.ht_supported) {
-               len = snprintf(buf, size, "%s\n",
-                              "HT not supported");
+               len = scnprintf(buf, size, "%s\n",
+                               "HT not supported");
                goto exit;
        }
 
-       len = snprintf(buf, size, "Max-AMPDU: %d\n",
-                      an->maxampdu);
-       len += snprintf(buf + len, size - len, "MPDU Density: %d\n\n",
-                       an->mpdudensity);
+       len = scnprintf(buf, size, "Max-AMPDU: %d\n",
+                       an->maxampdu);
+       len += scnprintf(buf + len, size - len, "MPDU Density: %d\n\n",
+                        an->mpdudensity);
 
-       len += snprintf(buf + len, size - len,
-                       "%2s%7s\n", "AC", "SCHED");
+       len += scnprintf(buf + len, size - len,
+                        "%2s%7s\n", "AC", "SCHED");
 
        for (acno = 0, ac = &an->ac[acno];
             acno < IEEE80211_NUM_ACS; acno++, ac++) {
                txq = ac->txq;
                ath_txq_lock(sc, txq);
-               len += snprintf(buf + len, size - len,
-                               "%2d%7d\n",
-                               acno, ac->sched);
+               len += scnprintf(buf + len, size - len,
+                                "%2d%7d\n",
+                                acno, ac->sched);
                ath_txq_unlock(sc, txq);
        }
 
-       len += snprintf(buf + len, size - len,
-                       "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n",
-                       "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
-                       "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
+       len += scnprintf(buf + len, size - len,
+                        "\n%3s%11s%10s%10s%10s%10s%9s%6s%8s\n",
+                        "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE",
+                        "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED");
 
        for (tidno = 0, tid = &an->tid[tidno];
             tidno < IEEE80211_NUM_TIDS; tidno++, tid++) {
                txq = tid->ac->txq;
                ath_txq_lock(sc, txq);
-               len += snprintf(buf + len, size - len,
-                               "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n",
-                               tid->tidno, tid->seq_start, tid->seq_next,
-                               tid->baw_size, tid->baw_head, tid->baw_tail,
-                               tid->bar_index, tid->sched, tid->paused);
+               len += scnprintf(buf + len, size - len,
+                                "%3d%11d%10d%10d%10d%10d%9d%6d%8d\n",
+                                tid->tidno, tid->seq_start, tid->seq_next,
+                                tid->baw_size, tid->baw_head, tid->baw_tail,
+                                tid->bar_index, tid->sched, tid->paused);
                ath_txq_unlock(sc, txq);
        }
 exit:
index 6e1556fa2f3e88713fa834cb56d3a4d9f6d87c48..d6e3fa4299a4fa5e4f85e49502a900920d48f718 100644 (file)
@@ -193,12 +193,12 @@ struct ath_tx_stats {
 #define TXSTATS sc->debug.stats.txstats
 #define PR(str, elem)                                                  \
        do {                                                            \
-               len += snprintf(buf + len, size - len,                  \
-                               "%s%13u%11u%10u%10u\n", str,            \
-                               TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \
-                               TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \
-                               TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \
-                               TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \
+               len += scnprintf(buf + len, size - len,                 \
+                                "%s%13u%11u%10u%10u\n", str,           \
+                                TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem,\
+                                TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem,\
+                                TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem,\
+                                TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \
        } while(0)
 
 #define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)
index 3c6e4138a95d13405ed8b2cff14ffbd5a2f52bb5..821599135d8a0f856457ca5108b5c6e162d01247 100644 (file)
 struct ath_dfs_pool_stats global_dfs_pool_stats = { 0 };
 
 #define ATH9K_DFS_STAT(s, p) \
-       len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
-                       sc->debug.stats.dfs_stats.p);
+       len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
+                        sc->debug.stats.dfs_stats.p);
 #define ATH9K_DFS_POOL_STAT(s, p) \
-       len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
-                       global_dfs_pool_stats.p);
+       len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
+                        global_dfs_pool_stats.p);
 
 static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
@@ -44,12 +44,12 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
        if (buf == NULL)
                return -ENOMEM;
 
-       len += snprintf(buf + len, size - len, "DFS support for "
-                       "macVersion = 0x%x, macRev = 0x%x: %s\n",
-                       hw_ver->macVersion, hw_ver->macRev,
-                       (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
+       len += scnprintf(buf + len, size - len, "DFS support for "
+                        "macVersion = 0x%x, macRev = 0x%x: %s\n",
+                        hw_ver->macVersion, hw_ver->macRev,
+                        (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
                                        "enabled" : "disabled");
-       len += snprintf(buf + len, size - len, "Pulse detector statistics:\n");
+       len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
        ATH9K_DFS_STAT("pulse events reported   ", pulses_total);
        ATH9K_DFS_STAT("invalid pulse events    ", pulses_no_dfs);
        ATH9K_DFS_STAT("DFS pulses detected     ", pulses_detected);
@@ -59,11 +59,12 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
        ATH9K_DFS_STAT("Primary channel pulses  ", pri_phy_errors);
        ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors);
        ATH9K_DFS_STAT("Dual channel pulses     ", dc_phy_errors);
-       len += snprintf(buf + len, size - len, "Radar detector statistics "
-                       "(current DFS region: %d)\n", sc->dfs_detector->region);
+       len += scnprintf(buf + len, size - len, "Radar detector statistics "
+                        "(current DFS region: %d)\n",
+                        sc->dfs_detector->region);
        ATH9K_DFS_STAT("Pulse events processed  ", pulses_processed);
        ATH9K_DFS_STAT("Radars detected         ", radar_detected);
-       len += snprintf(buf + len, size - len, "Global Pool statistics:\n");
+       len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
        ATH9K_DFS_POOL_STAT("Pool references         ", pool_reference);
        ATH9K_DFS_POOL_STAT("Pulses allocated        ", pulse_allocated);
        ATH9K_DFS_POOL_STAT("Pulses alloc error      ", pulse_alloc_error);
index 5ba4b6fe37c0aa630692c5291858fea0fcae6b35..c718fc379a10d358dea7fd6ecef339d2d0f06742 100644 (file)
@@ -392,7 +392,7 @@ static struct pri_sequence *pri_detector_add_pulse(struct pri_detector *de,
 
        if (!pseq_handler_create_sequences(de, ts, max_updated_seq)) {
                pri_detector_reset(de, ts);
-               return false;
+               return NULL;
        }
 
        ps = pseq_handler_check_detection(de);
index 9ea8e4b779c97c99b329619616e1ed232a1f5044..b4091716e9b3322881a6ed65fc3996a57e59a8b8 100644 (file)
@@ -129,10 +129,10 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        struct base_eep_header_4k *pBase = &eep->baseEepHeader;
 
        if (!dump_base_hdr) {
-               len += snprintf(buf + len, size - len,
-                               "%20s :\n", "2GHz modal Header");
+               len += scnprintf(buf + len, size - len,
+                                "%20s :\n", "2GHz modal Header");
                len = ath9k_dump_4k_modal_eeprom(buf, len, size,
-                                                 &eep->modalHeader);
+                                                &eep->modalHeader);
                goto out;
        }
 
@@ -160,8 +160,8 @@ static u32 ath9k_hw_4k_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
        PR_EEP("TX Gain type", pBase->txGainType);
 
-       len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
-                       pBase->macAddr);
+       len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+                        pBase->macAddr);
 
 out:
        if (len > size)
index 3ae1f3df063758f000519a5f7d08984e8fb474b2..e1d0c217c104f9ba6c2b0a1e55a941e2ccc63d20 100644 (file)
@@ -125,8 +125,8 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        struct base_eep_ar9287_header *pBase = &eep->baseEepHeader;
 
        if (!dump_base_hdr) {
-               len += snprintf(buf + len, size - len,
-                               "%20s :\n", "2GHz modal Header");
+               len += scnprintf(buf + len, size - len,
+                                "%20s :\n", "2GHz modal Header");
                len = ar9287_dump_modal_eeprom(buf, len, size,
                                                &eep->modalHeader);
                goto out;
@@ -157,8 +157,8 @@ static u32 ath9k_hw_ar9287_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Power Table Offset", pBase->pwrTableOffset);
        PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
 
-       len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
-                       pBase->macAddr);
+       len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+                        pBase->macAddr);
 
 out:
        if (len > size)
index 1c25368b3836f756f39c7f17f884ba43a2fb233c..39107e31e79aaa98fa93453f74db8b4e416ae457 100644 (file)
@@ -205,12 +205,12 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        struct base_eep_header *pBase = &eep->baseEepHeader;
 
        if (!dump_base_hdr) {
-               len += snprintf(buf + len, size - len,
-                               "%20s :\n", "2GHz modal Header");
+               len += scnprintf(buf + len, size - len,
+                                "%20s :\n", "2GHz modal Header");
                len = ath9k_def_dump_modal_eeprom(buf, len, size,
                                                   &eep->modalHeader[0]);
-               len += snprintf(buf + len, size - len,
-                               "%20s :\n", "5GHz modal Header");
+               len += scnprintf(buf + len, size - len,
+                                "%20s :\n", "5GHz modal Header");
                len = ath9k_def_dump_modal_eeprom(buf, len, size,
                                                   &eep->modalHeader[1]);
                goto out;
@@ -240,8 +240,8 @@ static u32 ath9k_hw_def_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Cal Bin Build", (pBase->binBuildNumber >> 8) & 0xFF);
        PR_EEP("OpenLoop Power Ctrl", pBase->openLoopPwrCntl);
 
-       len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
-                       pBase->macAddr);
+       len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+                        pBase->macAddr);
 
 out:
        if (len > size)
index 4b412aaf4f3699e65396598be9f7485f2af0754f..c34f21241da947e5297bc7ad18e6de9cc3430825 100644 (file)
@@ -522,22 +522,22 @@ static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
        ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx);
        ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count);
 
-       len += snprintf(buf + len, size - len, "BT Weights: ");
+       len += scnprintf(buf + len, size - len, "BT Weights: ");
        for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
-               len += snprintf(buf + len, size - len, "%08x ",
-                               btcoex_hw->bt_weight[i]);
-       len += snprintf(buf + len, size - len, "\n");
-       len += snprintf(buf + len, size - len, "WLAN Weights: ");
+               len += scnprintf(buf + len, size - len, "%08x ",
+                                btcoex_hw->bt_weight[i]);
+       len += scnprintf(buf + len, size - len, "\n");
+       len += scnprintf(buf + len, size - len, "WLAN Weights: ");
        for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
-               len += snprintf(buf + len, size - len, "%08x ",
-                               btcoex_hw->wlan_weight[i]);
-       len += snprintf(buf + len, size - len, "\n");
-       len += snprintf(buf + len, size - len, "Tx Priorities: ");
+               len += scnprintf(buf + len, size - len, "%08x ",
+                                btcoex_hw->wlan_weight[i]);
+       len += scnprintf(buf + len, size - len, "\n");
+       len += scnprintf(buf + len, size - len, "Tx Priorities: ");
        for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
-               len += snprintf(buf + len, size - len, "%08x ",
+               len += scnprintf(buf + len, size - len, "%08x ",
                                btcoex_hw->tx_prio[i]);
 
-       len += snprintf(buf + len, size - len, "\n");
+       len += scnprintf(buf + len, size - len, "\n");
 
        return len;
 }
index c1b45e2f848124bdeb0d28a156ed570f4928e635..fb071ee4fcfb3dd5969005a40537908ec92791c6 100644 (file)
@@ -37,29 +37,29 @@ static ssize_t read_file_tgt_int_stats(struct file *file, char __user *user_buf,
 
        ath9k_htc_ps_restore(priv);
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "RX",
-                       be32_to_cpu(cmd_rsp.rx));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "RX",
+                        be32_to_cpu(cmd_rsp.rx));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "RXORN",
-                       be32_to_cpu(cmd_rsp.rxorn));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "RXORN",
+                        be32_to_cpu(cmd_rsp.rxorn));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "RXEOL",
-                       be32_to_cpu(cmd_rsp.rxeol));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "RXEOL",
+                        be32_to_cpu(cmd_rsp.rxeol));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "TXURN",
-                       be32_to_cpu(cmd_rsp.txurn));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "TXURN",
+                        be32_to_cpu(cmd_rsp.txurn));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "TXTO",
-                       be32_to_cpu(cmd_rsp.txto));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "TXTO",
+                        be32_to_cpu(cmd_rsp.txto));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "CST",
-                       be32_to_cpu(cmd_rsp.cst));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "CST",
+                        be32_to_cpu(cmd_rsp.cst));
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -95,41 +95,41 @@ static ssize_t read_file_tgt_tx_stats(struct file *file, char __user *user_buf,
 
        ath9k_htc_ps_restore(priv);
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "Xretries",
-                       be32_to_cpu(cmd_rsp.xretries));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "Xretries",
+                        be32_to_cpu(cmd_rsp.xretries));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "FifoErr",
-                       be32_to_cpu(cmd_rsp.fifoerr));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "FifoErr",
+                        be32_to_cpu(cmd_rsp.fifoerr));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "Filtered",
-                       be32_to_cpu(cmd_rsp.filtered));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "Filtered",
+                        be32_to_cpu(cmd_rsp.filtered));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "TimerExp",
-                       be32_to_cpu(cmd_rsp.timer_exp));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "TimerExp",
+                        be32_to_cpu(cmd_rsp.timer_exp));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "ShortRetries",
-                       be32_to_cpu(cmd_rsp.shortretries));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "ShortRetries",
+                        be32_to_cpu(cmd_rsp.shortretries));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "LongRetries",
-                       be32_to_cpu(cmd_rsp.longretries));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "LongRetries",
+                        be32_to_cpu(cmd_rsp.longretries));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "QueueNull",
-                       be32_to_cpu(cmd_rsp.qnull));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "QueueNull",
+                        be32_to_cpu(cmd_rsp.qnull));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "EncapFail",
-                       be32_to_cpu(cmd_rsp.encap_fail));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "EncapFail",
+                        be32_to_cpu(cmd_rsp.encap_fail));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "NoBuf",
-                       be32_to_cpu(cmd_rsp.nobuf));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "NoBuf",
+                        be32_to_cpu(cmd_rsp.nobuf));
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -165,17 +165,17 @@ static ssize_t read_file_tgt_rx_stats(struct file *file, char __user *user_buf,
 
        ath9k_htc_ps_restore(priv);
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "NoBuf",
-                       be32_to_cpu(cmd_rsp.nobuf));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "NoBuf",
+                        be32_to_cpu(cmd_rsp.nobuf));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "HostSend",
-                       be32_to_cpu(cmd_rsp.host_send));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "HostSend",
+                        be32_to_cpu(cmd_rsp.host_send));
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "HostDone",
-                       be32_to_cpu(cmd_rsp.host_done));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "HostDone",
+                        be32_to_cpu(cmd_rsp.host_done));
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -197,37 +197,37 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
        char buf[512];
        unsigned int len = 0;
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "Buffers queued",
-                       priv->debug.tx_stats.buf_queued);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "Buffers completed",
-                       priv->debug.tx_stats.buf_completed);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "SKBs queued",
-                       priv->debug.tx_stats.skb_queued);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "SKBs success",
-                       priv->debug.tx_stats.skb_success);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "SKBs failed",
-                       priv->debug.tx_stats.skb_failed);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "CAB queued",
-                       priv->debug.tx_stats.cab_queued);
-
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "BE queued",
-                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "BK queued",
-                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "VI queued",
-                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]);
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "%20s : %10u\n", "VO queued",
-                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "Buffers queued",
+                        priv->debug.tx_stats.buf_queued);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "Buffers completed",
+                        priv->debug.tx_stats.buf_completed);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "SKBs queued",
+                        priv->debug.tx_stats.skb_queued);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "SKBs success",
+                        priv->debug.tx_stats.skb_success);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "SKBs failed",
+                        priv->debug.tx_stats.skb_failed);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "CAB queued",
+                        priv->debug.tx_stats.cab_queued);
+
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "BE queued",
+                        priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "BK queued",
+                        priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "VI queued",
+                        priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]);
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "%20s : %10u\n", "VO queued",
+                        priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -273,8 +273,8 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
                              size_t count, loff_t *ppos)
 {
 #define PHY_ERR(s, p)                                                  \
-       len += snprintf(buf + len, size - len, "%20s : %10u\n", s,      \
-                       priv->debug.rx_stats.err_phy_stats[p]);
+       len += scnprintf(buf + len, size - len, "%20s : %10u\n", s,     \
+                        priv->debug.rx_stats.err_phy_stats[p]);
 
        struct ath9k_htc_priv *priv = file->private_data;
        char *buf;
@@ -285,37 +285,37 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
        if (buf == NULL)
                return -ENOMEM;
 
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "SKBs allocated",
-                       priv->debug.rx_stats.skb_allocated);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "SKBs completed",
-                       priv->debug.rx_stats.skb_completed);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "SKBs Dropped",
-                       priv->debug.rx_stats.skb_dropped);
-
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "CRC ERR",
-                       priv->debug.rx_stats.err_crc);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "DECRYPT CRC ERR",
-                       priv->debug.rx_stats.err_decrypt_crc);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "MIC ERR",
-                       priv->debug.rx_stats.err_mic);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "PRE-DELIM CRC ERR",
-                       priv->debug.rx_stats.err_pre_delim);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "POST-DELIM CRC ERR",
-                       priv->debug.rx_stats.err_post_delim);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "DECRYPT BUSY ERR",
-                       priv->debug.rx_stats.err_decrypt_busy);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10u\n", "TOTAL PHY ERR",
-                       priv->debug.rx_stats.err_phy);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "SKBs allocated",
+                        priv->debug.rx_stats.skb_allocated);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "SKBs completed",
+                        priv->debug.rx_stats.skb_completed);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "SKBs Dropped",
+                        priv->debug.rx_stats.skb_dropped);
+
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "CRC ERR",
+                        priv->debug.rx_stats.err_crc);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "DECRYPT CRC ERR",
+                        priv->debug.rx_stats.err_decrypt_crc);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "MIC ERR",
+                        priv->debug.rx_stats.err_mic);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "PRE-DELIM CRC ERR",
+                        priv->debug.rx_stats.err_pre_delim);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "POST-DELIM CRC ERR",
+                        priv->debug.rx_stats.err_post_delim);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "DECRYPT BUSY ERR",
+                        priv->debug.rx_stats.err_decrypt_busy);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10u\n", "TOTAL PHY ERR",
+                        priv->debug.rx_stats.err_phy);
 
 
        PHY_ERR("UNDERRUN", ATH9K_PHYERR_UNDERRUN);
@@ -372,16 +372,16 @@ static ssize_t read_file_slot(struct file *file, char __user *user_buf,
 
        spin_lock_bh(&priv->tx.tx_lock);
 
-       len += snprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
+       len += scnprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
 
        len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
                               priv->tx.tx_slot, MAX_TX_BUF_NUM);
 
-       len += snprintf(buf + len, sizeof(buf) - len, "\n");
+       len += scnprintf(buf + len, sizeof(buf) - len, "\n");
 
-       len += snprintf(buf + len, sizeof(buf) - len,
-                       "Used slots     : %d\n",
-                       bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
+       len += scnprintf(buf + len, sizeof(buf) - len,
+                        "Used slots     : %d\n",
+                        bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
 
        spin_unlock_bh(&priv->tx.tx_lock);
 
@@ -405,30 +405,30 @@ static ssize_t read_file_queue(struct file *file, char __user *user_buf,
        char buf[512];
        unsigned int len = 0;
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Mgmt endpoint", skb_queue_len(&priv->tx.mgmt_ep_queue));
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Cab endpoint", skb_queue_len(&priv->tx.cab_ep_queue));
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Data BE endpoint", skb_queue_len(&priv->tx.data_be_queue));
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Data BK endpoint", skb_queue_len(&priv->tx.data_bk_queue));
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Data VI endpoint", skb_queue_len(&priv->tx.data_vi_queue));
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Data VO endpoint", skb_queue_len(&priv->tx.data_vo_queue));
 
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Failed queue", skb_queue_len(&priv->tx.tx_failed));
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Failed queue", skb_queue_len(&priv->tx.tx_failed));
 
        spin_lock_bh(&priv->tx.tx_lock);
-       len += snprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
-                       "Queued count", priv->tx.queued_cnt);
+       len += scnprintf(buf + len, sizeof(buf) - len, "%20s : %10u\n",
+                        "Queued count", priv->tx.queued_cnt);
        spin_unlock_bh(&priv->tx.tx_lock);
 
        if (len > sizeof(buf))
@@ -507,70 +507,70 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
        if (buf == NULL)
                return -ENOMEM;
 
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n", "Major Version",
-                       pBase->version >> 12);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n", "Minor Version",
-                       pBase->version & 0xFFF);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n", "Checksum",
-                       pBase->checksum);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n", "Length",
-                       pBase->length);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n", "RegDomain1",
-                       pBase->regDmn[0]);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n", "RegDomain2",
-                       pBase->regDmn[1]);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "TX Mask", pBase->txMask);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "RX Mask", pBase->rxMask);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Allow 5GHz",
-                       !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Allow 2GHz",
-                       !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Disable 2GHz HT20",
-                       !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Disable 2GHz HT40",
-                       !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Disable 5Ghz HT20",
-                       !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Disable 5Ghz HT40",
-                       !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Big Endian",
-                       !!(pBase->eepMisc & 0x01));
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Cal Bin Major Ver",
-                       (pBase->binBuildNumber >> 24) & 0xFF);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Cal Bin Minor Ver",
-                       (pBase->binBuildNumber >> 16) & 0xFF);
-       len += snprintf(buf + len, size - len,
-                       "%20s : %10d\n",
-                       "Cal Bin Build",
-                       (pBase->binBuildNumber >> 8) & 0xFF);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n", "Major Version",
+                        pBase->version >> 12);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n", "Minor Version",
+                        pBase->version & 0xFFF);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n", "Checksum",
+                        pBase->checksum);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n", "Length",
+                        pBase->length);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n", "RegDomain1",
+                        pBase->regDmn[0]);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n", "RegDomain2",
+                        pBase->regDmn[1]);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "TX Mask", pBase->txMask);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "RX Mask", pBase->rxMask);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Allow 5GHz",
+                        !!(pBase->opCapFlags & AR5416_OPFLAGS_11A));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Allow 2GHz",
+                        !!(pBase->opCapFlags & AR5416_OPFLAGS_11G));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Disable 2GHz HT20",
+                        !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT20));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Disable 2GHz HT40",
+                        !!(pBase->opCapFlags & AR5416_OPFLAGS_N_2G_HT40));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Disable 5Ghz HT20",
+                        !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT20));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Disable 5Ghz HT40",
+                        !!(pBase->opCapFlags & AR5416_OPFLAGS_N_5G_HT40));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Big Endian",
+                        !!(pBase->eepMisc & 0x01));
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Cal Bin Major Ver",
+                        (pBase->binBuildNumber >> 24) & 0xFF);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Cal Bin Minor Ver",
+                        (pBase->binBuildNumber >> 16) & 0xFF);
+       len += scnprintf(buf + len, size - len,
+                        "%20s : %10d\n",
+                        "Cal Bin Build",
+                        (pBase->binBuildNumber >> 8) & 0xFF);
 
        /*
         * UB91 specific data.
@@ -579,10 +579,10 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
                struct base_eep_header_4k *pBase4k =
                        &priv->ah->eeprom.map4k.baseEepHeader;
 
-               len += snprintf(buf + len, size - len,
-                               "%20s : %10d\n",
-                               "TX Gain type",
-                               pBase4k->txGainType);
+               len += scnprintf(buf + len, size - len,
+                                "%20s : %10d\n",
+                                "TX Gain type",
+                                pBase4k->txGainType);
        }
 
        /*
@@ -592,19 +592,19 @@ static ssize_t read_file_base_eeprom(struct file *file, char __user *user_buf,
                struct base_eep_ar9287_header *pBase9287 =
                        &priv->ah->eeprom.map9287.baseEepHeader;
 
-               len += snprintf(buf + len, size - len,
-                               "%20s : %10ddB\n",
-                               "Power Table Offset",
-                               pBase9287->pwrTableOffset);
+               len += scnprintf(buf + len, size - len,
+                                "%20s : %10ddB\n",
+                                "Power Table Offset",
+                                pBase9287->pwrTableOffset);
 
-               len += snprintf(buf + len, size - len,
-                               "%20s : %10d\n",
-                               "OpenLoop Power Ctrl",
-                               pBase9287->openLoopPwrCntl);
+               len += scnprintf(buf + len, size - len,
+                                "%20s : %10d\n",
+                                "OpenLoop Power Ctrl",
+                                pBase9287->openLoopPwrCntl);
        }
 
-       len += snprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
-                       pBase->macAddr);
+       len += scnprintf(buf + len, size - len, "%20s : %pM\n", "MacAddress",
+                        pBase->macAddr);
        if (len > size)
                len = size;
 
@@ -627,8 +627,8 @@ static ssize_t read_4k_modal_eeprom(struct file *file,
 {
 #define PR_EEP(_s, _val)                                               \
        do {                                                            \
-               len += snprintf(buf + len, size - len, "%20s : %10d\n", \
-                               _s, (_val));                            \
+               len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
+                                _s, (_val));                           \
        } while (0)
 
        struct ath9k_htc_priv *priv = file->private_data;
@@ -708,12 +708,12 @@ static ssize_t read_def_modal_eeprom(struct file *file,
        do {                                                            \
                if (pBase->opCapFlags & AR5416_OPFLAGS_11G) {           \
                        pModal = &priv->ah->eeprom.def.modalHeader[1];  \
-                       len += snprintf(buf + len, size - len, "%20s : %8d%7s", \
-                                       _s, (_val), "|");               \
+                       len += scnprintf(buf + len, size - len, "%20s : %8d%7s", \
+                                        _s, (_val), "|");              \
                }                                                       \
                if (pBase->opCapFlags & AR5416_OPFLAGS_11A) {           \
                        pModal = &priv->ah->eeprom.def.modalHeader[0];  \
-                       len += snprintf(buf + len, size - len, "%9d\n", \
+                       len += scnprintf(buf + len, size - len, "%9d\n",\
                                        (_val));                        \
                }                                                       \
        } while (0)
@@ -729,10 +729,10 @@ static ssize_t read_def_modal_eeprom(struct file *file,
        if (buf == NULL)
                return -ENOMEM;
 
-       len += snprintf(buf + len, size - len,
-                       "%31s %15s\n", "2G", "5G");
-       len += snprintf(buf + len, size - len,
-                       "%32s %16s\n", "====", "====\n");
+       len += scnprintf(buf + len, size - len,
+                        "%31s %15s\n", "2G", "5G");
+       len += scnprintf(buf + len, size - len,
+                        "%32s %16s\n", "====", "====\n");
 
        PR_EEP("Chain0 Ant. Control", pModal->antCtrlChain[0]);
        PR_EEP("Chain1 Ant. Control", pModal->antCtrlChain[1]);
@@ -814,8 +814,8 @@ static ssize_t read_9287_modal_eeprom(struct file *file,
 {
 #define PR_EEP(_s, _val)                                               \
        do {                                                            \
-               len += snprintf(buf + len, size - len, "%20s : %10d\n", \
-                               _s, (_val));                            \
+               len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
+                                _s, (_val));                           \
        } while (0)
 
        struct ath9k_htc_priv *priv = file->private_data;
index d44258172c0f640236719a7e8eb4e8480c9c682b..9a2657fdd9ccd4ec62f96f8a639182e2ded29fec 100644 (file)
 static enum htc_phymode ath9k_htc_get_curmode(struct ath9k_htc_priv *priv,
                                              struct ath9k_channel *ichan)
 {
-       enum htc_phymode mode;
-
-       mode = -EINVAL;
-
-       switch (ichan->chanmode) {
-       case CHANNEL_G:
-       case CHANNEL_G_HT20:
-       case CHANNEL_G_HT40PLUS:
-       case CHANNEL_G_HT40MINUS:
-               mode = HTC_MODE_11NG;
-               break;
-       case CHANNEL_A:
-       case CHANNEL_A_HT20:
-       case CHANNEL_A_HT40PLUS:
-       case CHANNEL_A_HT40MINUS:
-               mode = HTC_MODE_11NA;
-               break;
-       default:
-               break;
-       }
+       if (IS_CHAN_5GHZ(ichan))
+               return HTC_MODE_11NA;
 
-       WARN_ON(mode < 0);
-
-       return mode;
+       return HTC_MODE_11NG;
 }
 
 bool ath9k_htc_setpower(struct ath9k_htc_priv *priv,
@@ -926,7 +906,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw)
        WMI_CMD(WMI_FLUSH_RECV_CMDID);
 
        /* setup initial channel */
-       init_channel = ath9k_cmn_get_curchannel(hw, ah);
+       init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
 
        ret = ath9k_hw_reset(ah, init_channel, ah->caldata, false);
        if (ret) {
@@ -1208,9 +1188,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                ath_dbg(common, CONFIG, "Set channel: %d MHz\n",
                        curchan->center_freq);
 
-               ath9k_cmn_update_ichannel(&priv->ah->channels[pos],
-                                         &hw->conf.chandef);
-
+               ath9k_cmn_get_channel(hw, priv->ah, &hw->conf.chandef);
                if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) {
                        ath_err(common, "Unable to set channel\n");
                        ret = -EINVAL;
index ecc6ec4a1edb39b7f3e4d26da756652fc324971b..dcdbab48709ec7f5c9081caaedf967df65fdb1e5 100644 (file)
@@ -130,29 +130,29 @@ void ath9k_debug_sync_cause(struct ath_common *common, u32 sync_cause)
 
 static void ath9k_hw_set_clockrate(struct ath_hw *ah)
 {
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
        struct ath_common *common = ath9k_hw_common(ah);
+       struct ath9k_channel *chan = ah->curchan;
        unsigned int clockrate;
 
        /* AR9287 v1.3+ uses async FIFO and runs the MAC at 117 MHz */
        if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah))
                clockrate = 117;
-       else if (!ah->curchan) /* should really check for CCK instead */
+       else if (!chan) /* should really check for CCK instead */
                clockrate = ATH9K_CLOCK_RATE_CCK;
-       else if (conf->chandef.chan->band == IEEE80211_BAND_2GHZ)
+       else if (IS_CHAN_2GHZ(chan))
                clockrate = ATH9K_CLOCK_RATE_2GHZ_OFDM;
        else if (ah->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK)
                clockrate = ATH9K_CLOCK_FAST_RATE_5GHZ_OFDM;
        else
                clockrate = ATH9K_CLOCK_RATE_5GHZ_OFDM;
 
-       if (conf_is_ht40(conf))
+       if (IS_CHAN_HT40(chan))
                clockrate *= 2;
 
        if (ah->curchan) {
-               if (IS_CHAN_HALF_RATE(ah->curchan))
+               if (IS_CHAN_HALF_RATE(chan))
                        clockrate /= 2;
-               if (IS_CHAN_QUARTER_RATE(ah->curchan))
+               if (IS_CHAN_QUARTER_RATE(chan))
                        clockrate /= 4;
        }
 
@@ -190,10 +190,7 @@ EXPORT_SYMBOL(ath9k_hw_wait);
 void ath9k_hw_synth_delay(struct ath_hw *ah, struct ath9k_channel *chan,
                          int hw_delay)
 {
-       if (IS_CHAN_B(chan))
-               hw_delay = (4 * hw_delay) / 22;
-       else
-               hw_delay /= 10;
+       hw_delay /= 10;
 
        if (IS_CHAN_HALF_RATE(chan))
                hw_delay *= 2;
@@ -294,8 +291,7 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah,
                return;
        }
 
-       if ((chan->chanmode == CHANNEL_A_HT40PLUS) ||
-           (chan->chanmode == CHANNEL_G_HT40PLUS)) {
+       if (IS_CHAN_HT40PLUS(chan)) {
                centers->synth_center =
                        chan->channel + HT40_CHANNEL_CENTER_SHIFT;
                extoff = 1;
@@ -549,6 +545,18 @@ static int ath9k_hw_post_init(struct ath_hw *ah)
 
        ath9k_hw_ani_init(ah);
 
+       /*
+        * EEPROM needs to be initialized before we do this.
+        * This is required for regulatory compliance.
+        */
+       if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+               u16 regdmn = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
+               if ((regdmn & 0xF0) == CTL_FCC) {
+                       ah->nf_2g.max = AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_2GHZ;
+                       ah->nf_5g.max = AR_PHY_CCA_MAX_GOOD_VAL_9462_FCC_5GHZ;
+               }
+       }
+
        return 0;
 }
 
@@ -1030,7 +1038,6 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hw *ah, u32 tu)
 void ath9k_hw_init_global_settings(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ieee80211_conf *conf = &common->hw->conf;
        const struct ath9k_channel *chan = ah->curchan;
        int acktimeout, ctstimeout, ack_offset = 0;
        int slottime;
@@ -1105,8 +1112,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
         * BA frames in some implementations, but it has been found to fix ACK
         * timeout issues in other cases as well.
         */
-       if (conf->chandef.chan &&
-           conf->chandef.chan->band == IEEE80211_BAND_2GHZ &&
+       if (IS_CHAN_2GHZ(chan) &&
            !IS_CHAN_HALF_RATE(chan) && !IS_CHAN_QUARTER_RATE(chan)) {
                acktimeout += 64 - sifstime - ah->slottime;
                ctstimeout += 48 - sifstime - ah->slottime;
@@ -1148,9 +1154,7 @@ u32 ath9k_regd_get_ctl(struct ath_regulatory *reg, struct ath9k_channel *chan)
 {
        u32 ctl = ath_regd_get_band_ctl(reg, chan->chan->band);
 
-       if (IS_CHAN_B(chan))
-               ctl |= CTL_11B;
-       else if (IS_CHAN_G(chan))
+       if (IS_CHAN_2GHZ(chan))
                ctl |= CTL_11G;
        else
                ctl |= CTL_11A;
@@ -1498,10 +1502,8 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        int r;
 
        if (pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) {
-               u32 cur = ah->curchan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
-               u32 new = chan->channelFlags & (CHANNEL_2GHZ | CHANNEL_5GHZ);
-               band_switch = (cur != new);
-               mode_diff = (chan->chanmode != ah->curchan->chanmode);
+               band_switch = IS_CHAN_5GHZ(ah->curchan) != IS_CHAN_5GHZ(chan);
+               mode_diff = (chan->channelFlags != ah->curchan->channelFlags);
        }
 
        for (qnum = 0; qnum < AR_NUM_QCU; qnum++) {
@@ -1540,9 +1542,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
        ath9k_hw_set_clockrate(ah);
        ath9k_hw_apply_txpower(ah, chan, false);
 
-       if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
-               ath9k_hw_set_delta_slope(ah, chan);
-
+       ath9k_hw_set_delta_slope(ah, chan);
        ath9k_hw_spur_mitigate_freq(ah, chan);
 
        if (band_switch || ini_reloaded)
@@ -1644,6 +1644,19 @@ hang_check_iter:
        return true;
 }
 
+void ath9k_hw_check_nav(struct ath_hw *ah)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       u32 val;
+
+       val = REG_READ(ah, AR_NAV);
+       if (val != 0xdeadbeef && val > 0x7fff) {
+               ath_dbg(common, BSTUCK, "Abnormal NAV: 0x%x\n", val);
+               REG_WRITE(ah, AR_NAV, 0);
+       }
+}
+EXPORT_SYMBOL(ath9k_hw_check_nav);
+
 bool ath9k_hw_check_alive(struct ath_hw *ah)
 {
        int count = 50;
@@ -1799,20 +1812,11 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
                goto fail;
 
        /*
-        * If cross-band fcc is not supoprted, bail out if
-        * either channelFlags or chanmode differ.
-        *
-        * chanmode will be different if the HT operating mode
-        * changes because of CSA.
+        * If cross-band fcc is not supoprted, bail out if channelFlags differ.
         */
-       if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH)) {
-               if ((chan->channelFlags & CHANNEL_ALL) !=
-                   (ah->curchan->channelFlags & CHANNEL_ALL))
-                       goto fail;
-
-               if (chan->chanmode != ah->curchan->chanmode)
-                       goto fail;
-       }
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_FCC_BAND_SWITCH) &&
+           chan->channelFlags != ah->curchan->channelFlags)
+               goto fail;
 
        if (!ath9k_hw_check_alive(ah))
                goto fail;
@@ -1822,9 +1826,9 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
         * re-using are present.
         */
        if (AR_SREV_9462(ah) && (ah->caldata &&
-                                (!ah->caldata->done_txiqcal_once ||
-                                 !ah->caldata->done_txclcal_once ||
-                                 !ah->caldata->rtt_done)))
+                                (!test_bit(TXIQCAL_DONE, &ah->caldata->cal_flags) ||
+                                 !test_bit(TXCLCAL_DONE, &ah->caldata->cal_flags) ||
+                                 !test_bit(RTT_DONE, &ah->caldata->cal_flags))))
                goto fail;
 
        ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n",
@@ -1874,13 +1878,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ah->caldata = caldata;
        if (caldata && (chan->channel != caldata->channel ||
-                       chan->channelFlags != caldata->channelFlags ||
-                       chan->chanmode != caldata->chanmode)) {
+                       chan->channelFlags != caldata->channelFlags)) {
                /* Operating channel changed, reset channel calibration data */
                memset(caldata, 0, sizeof(*caldata));
                ath9k_init_nfcal_hist_buffer(ah, chan);
        } else if (caldata) {
-               caldata->paprd_packet_sent = false;
+               clear_bit(PAPRD_PACKET_SENT, &caldata->cal_flags);
        }
        ah->noise = ath9k_hw_getchan_noise(ah, chan);
 
@@ -1964,9 +1967,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        ath9k_hw_init_mfp(ah);
 
-       if (IS_CHAN_OFDM(chan) || IS_CHAN_HT(chan))
-               ath9k_hw_set_delta_slope(ah, chan);
-
+       ath9k_hw_set_delta_slope(ah, chan);
        ath9k_hw_spur_mitigate_freq(ah, chan);
        ah->eep_ops->set_board_values(ah, chan);
 
@@ -2017,8 +2018,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_init_bb(ah, chan);
 
        if (caldata) {
-               caldata->done_txiqcal_once = false;
-               caldata->done_txclcal_once = false;
+               clear_bit(TXIQCAL_DONE, &caldata->cal_flags);
+               clear_bit(TXCLCAL_DONE, &caldata->cal_flags);
        }
        if (!ath9k_hw_init_cal(ah, chan))
                return -EIO;
@@ -2943,12 +2944,11 @@ void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set)
 }
 EXPORT_SYMBOL(ath9k_hw_set_tsfadjust);
 
-void ath9k_hw_set11nmac2040(struct ath_hw *ah)
+void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan)
 {
-       struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf;
        u32 macmode;
 
-       if (conf_is_ht40(conf) && !ah->config.cwm_ignore_extcca)
+       if (IS_CHAN_HT40(chan) && !ah->config.cwm_ignore_extcca)
                macmode = AR_2040_JOINED_RX_CLEAR;
        else
                macmode = 0;
@@ -3240,19 +3240,19 @@ void ath9k_hw_name(struct ath_hw *ah, char *hw_name, size_t len)
 
        /* chipsets >= AR9280 are single-chip */
        if (AR_SREV_9280_20_OR_LATER(ah)) {
-               used = snprintf(hw_name, len,
-                              "Atheros AR%s Rev:%x",
-                              ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
-                              ah->hw_version.macRev);
+               used = scnprintf(hw_name, len,
+                                "Atheros AR%s Rev:%x",
+                                ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
+                                ah->hw_version.macRev);
        }
        else {
-               used = snprintf(hw_name, len,
-                              "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x",
-                              ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
-                              ah->hw_version.macRev,
-                              ath9k_hw_rf_name((ah->hw_version.analog5GhzRev &
-                                               AR_RADIO_SREV_MAJOR)),
-                              ah->hw_version.phyRev);
+               used = scnprintf(hw_name, len,
+                                "Atheros AR%s MAC/BB Rev:%x AR%s RF Rev:%x",
+                                ath9k_hw_mac_bb_name(ah->hw_version.macVersion),
+                                ah->hw_version.macRev,
+                                ath9k_hw_rf_name((ah->hw_version.analog5GhzRev
+                                                 & AR_RADIO_SREV_MAJOR)),
+                                ah->hw_version.phyRev);
        }
 
        hw_name[used] = '\0';
index 69a907b55a73b129fae1171f2d9859a3303ec3e7..81fcbc75612235601423e38f59d63d9355a3fed7 100644 (file)
@@ -98,8 +98,8 @@
 
 #define PR_EEP(_s, _val)                                               \
        do {                                                            \
-               len += snprintf(buf + len, size - len, "%20s : %10d\n", \
-                               _s, (_val));                            \
+               len += scnprintf(buf + len, size - len, "%20s : %10d\n",\
+                                _s, (_val));                           \
        } while (0)
 
 #define SM(_v, _f)  (((_v) << _f##_S) & _f)
@@ -369,55 +369,30 @@ enum ath9k_int {
        ATH9K_INT_NOCARD = 0xffffffff
 };
 
-#define CHANNEL_CCK       0x00020
-#define CHANNEL_OFDM      0x00040
-#define CHANNEL_2GHZ      0x00080
-#define CHANNEL_5GHZ      0x00100
-#define CHANNEL_PASSIVE   0x00200
-#define CHANNEL_DYN       0x00400
-#define CHANNEL_HALF      0x04000
-#define CHANNEL_QUARTER   0x08000
-#define CHANNEL_HT20      0x10000
-#define CHANNEL_HT40PLUS  0x20000
-#define CHANNEL_HT40MINUS 0x40000
-
-#define CHANNEL_A           (CHANNEL_5GHZ|CHANNEL_OFDM)
-#define CHANNEL_B           (CHANNEL_2GHZ|CHANNEL_CCK)
-#define CHANNEL_G           (CHANNEL_2GHZ|CHANNEL_OFDM)
-#define CHANNEL_G_HT20      (CHANNEL_2GHZ|CHANNEL_HT20)
-#define CHANNEL_A_HT20      (CHANNEL_5GHZ|CHANNEL_HT20)
-#define CHANNEL_G_HT40PLUS  (CHANNEL_2GHZ|CHANNEL_HT40PLUS)
-#define CHANNEL_G_HT40MINUS (CHANNEL_2GHZ|CHANNEL_HT40MINUS)
-#define CHANNEL_A_HT40PLUS  (CHANNEL_5GHZ|CHANNEL_HT40PLUS)
-#define CHANNEL_A_HT40MINUS (CHANNEL_5GHZ|CHANNEL_HT40MINUS)
-#define CHANNEL_ALL                            \
-       (CHANNEL_OFDM|                          \
-        CHANNEL_CCK|                           \
-        CHANNEL_2GHZ |                         \
-        CHANNEL_5GHZ |                         \
-        CHANNEL_HT20 |                         \
-        CHANNEL_HT40PLUS |                     \
-        CHANNEL_HT40MINUS)
-
 #define MAX_RTT_TABLE_ENTRY     6
 #define MAX_IQCAL_MEASUREMENT  8
 #define MAX_CL_TAB_ENTRY       16
 #define CL_TAB_ENTRY(reg_base) (reg_base + (4 * j))
 
+enum ath9k_cal_flags {
+       RTT_DONE,
+       PAPRD_PACKET_SENT,
+       PAPRD_DONE,
+       NFCAL_PENDING,
+       NFCAL_INTF,
+       TXIQCAL_DONE,
+       TXCLCAL_DONE,
+       SW_PKDET_DONE,
+};
+
 struct ath9k_hw_cal_data {
        u16 channel;
-       u32 channelFlags;
-       u32 chanmode;
+       u16 channelFlags;
+       unsigned long cal_flags;
        int32_t CalValid;
        int8_t iCoff;
        int8_t qCoff;
-       bool rtt_done;
-       bool paprd_packet_sent;
-       bool paprd_done;
-       bool nfcal_pending;
-       bool nfcal_interference;
-       bool done_txiqcal_once;
-       bool done_txclcal_once;
+       u8 caldac[2];
        u16 small_signal_gain[AR9300_MAX_CHAINS];
        u32 pa_table[AR9300_MAX_CHAINS][PAPRD_TABLE_SZ];
        u32 num_measures[AR9300_MAX_CHAINS];
@@ -430,33 +405,34 @@ struct ath9k_hw_cal_data {
 struct ath9k_channel {
        struct ieee80211_channel *chan;
        u16 channel;
-       u32 channelFlags;
-       u32 chanmode;
+       u16 channelFlags;
        s16 noisefloor;
 };
 
-#define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \
-       (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \
-       (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \
-       (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0)
-#define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0)
-#define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0)
-#define IS_CHAN_HALF_RATE(_c) (((_c)->channelFlags & CHANNEL_HALF) != 0)
-#define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0)
+#define CHANNEL_5GHZ           BIT(0)
+#define CHANNEL_HALF           BIT(1)
+#define CHANNEL_QUARTER                BIT(2)
+#define CHANNEL_HT             BIT(3)
+#define CHANNEL_HT40PLUS       BIT(4)
+#define CHANNEL_HT40MINUS      BIT(5)
+
+#define IS_CHAN_5GHZ(_c) (!!((_c)->channelFlags & CHANNEL_5GHZ))
+#define IS_CHAN_2GHZ(_c) (!IS_CHAN_5GHZ(_c))
+
+#define IS_CHAN_HALF_RATE(_c) (!!((_c)->channelFlags & CHANNEL_HALF))
+#define IS_CHAN_QUARTER_RATE(_c) (!!((_c)->channelFlags & CHANNEL_QUARTER))
 #define IS_CHAN_A_FAST_CLOCK(_ah, _c)                  \
-       ((((_c)->channelFlags & CHANNEL_5GHZ) != 0) &&  \
-        ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK))
-
-/* These macros check chanmode and not channelFlags */
-#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B)
-#define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) ||        \
-                         ((_c)->chanmode == CHANNEL_G_HT20))
-#define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) ||    \
-                         ((_c)->chanmode == CHANNEL_A_HT40MINUS) ||    \
-                         ((_c)->chanmode == CHANNEL_G_HT40PLUS) ||     \
-                         ((_c)->chanmode == CHANNEL_G_HT40MINUS))
-#define IS_CHAN_HT(_c) (IS_CHAN_HT20((_c)) || IS_CHAN_HT40((_c)))
+       (IS_CHAN_5GHZ(_c) && ((_ah)->caps.hw_caps & ATH9K_HW_CAP_FASTCLOCK))
+
+#define IS_CHAN_HT(_c) ((_c)->channelFlags & CHANNEL_HT)
+
+#define IS_CHAN_HT20(_c) (IS_CHAN_HT(_c) && !IS_CHAN_HT40(_c))
+
+#define IS_CHAN_HT40(_c) \
+       (!!((_c)->channelFlags & (CHANNEL_HT40PLUS | CHANNEL_HT40MINUS)))
+
+#define IS_CHAN_HT40PLUS(_c) ((_c)->channelFlags & CHANNEL_HT40PLUS)
+#define IS_CHAN_HT40MINUS(_c) ((_c)->channelFlags & CHANNEL_HT40MINUS)
 
 enum ath9k_power_mode {
        ATH9K_PM_AWAKE = 0,
@@ -558,6 +534,7 @@ struct ath_hw_antcomb_conf {
        u8 main_gaintb;
        u8 alt_gaintb;
        int lna1_lna2_delta;
+       int lna1_lna2_switch_delta;
        u8 div_group;
 };
 
@@ -1026,10 +1003,11 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah);
 void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set);
 void ath9k_hw_init_global_settings(struct ath_hw *ah);
 u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah);
-void ath9k_hw_set11nmac2040(struct ath_hw *ah);
+void ath9k_hw_set11nmac2040(struct ath_hw *ah, struct ath9k_channel *chan);
 void ath9k_hw_beaconinit(struct ath_hw *ah, u32 next_beacon, u32 beacon_period);
 void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
                                    const struct ath9k_beacon_state *bs);
+void ath9k_hw_check_nav(struct ath_hw *ah);
 bool ath9k_hw_check_alive(struct ath_hw *ah);
 
 bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
index 9a1f349f926001662dee74a796db2c580d21dbb7..7df728f363301d0e477ceb7277cb2f32c86db6d8 100644 (file)
@@ -347,7 +347,6 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        u8 *ds;
-       struct ath_buf *bf;
        int i, bsize, desc_len;
 
        ath_dbg(common, CONFIG, "%s DMA: %u buffers %u desc/buf\n",
@@ -399,33 +398,68 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
                ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len);
 
        /* allocate buffers */
-       bsize = sizeof(struct ath_buf) * nbuf;
-       bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
-       if (!bf)
-               return -ENOMEM;
+       if (is_tx) {
+               struct ath_buf *bf;
+
+               bsize = sizeof(struct ath_buf) * nbuf;
+               bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
+               if (!bf)
+                       return -ENOMEM;
+
+               for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
+                       bf->bf_desc = ds;
+                       bf->bf_daddr = DS2PHYS(dd, ds);
+
+                       if (!(sc->sc_ah->caps.hw_caps &
+                                 ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+                               /*
+                                * Skip descriptor addresses which can cause 4KB
+                                * boundary crossing (addr + length) with a 32 dword
+                                * descriptor fetch.
+                                */
+                               while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+                                       BUG_ON((caddr_t) bf->bf_desc >=
+                                                  ((caddr_t) dd->dd_desc +
+                                               dd->dd_desc_len));
+
+                                       ds += (desc_len * ndesc);
+                                       bf->bf_desc = ds;
+                                       bf->bf_daddr = DS2PHYS(dd, ds);
+                               }
+                       }
+                       list_add_tail(&bf->list, head);
+               }
+       } else {
+               struct ath_rxbuf *bf;
+
+               bsize = sizeof(struct ath_rxbuf) * nbuf;
+               bf = devm_kzalloc(sc->dev, bsize, GFP_KERNEL);
+               if (!bf)
+                       return -ENOMEM;
 
-       for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
-               bf->bf_desc = ds;
-               bf->bf_daddr = DS2PHYS(dd, ds);
-
-               if (!(sc->sc_ah->caps.hw_caps &
-                     ATH9K_HW_CAP_4KB_SPLITTRANS)) {
-                       /*
-                        * Skip descriptor addresses which can cause 4KB
-                        * boundary crossing (addr + length) with a 32 dword
-                        * descriptor fetch.
-                        */
-                       while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
-                               BUG_ON((caddr_t) bf->bf_desc >=
-                                      ((caddr_t) dd->dd_desc +
-                                       dd->dd_desc_len));
-
-                               ds += (desc_len * ndesc);
-                               bf->bf_desc = ds;
-                               bf->bf_daddr = DS2PHYS(dd, ds);
+               for (i = 0; i < nbuf; i++, bf++, ds += (desc_len * ndesc)) {
+                       bf->bf_desc = ds;
+                       bf->bf_daddr = DS2PHYS(dd, ds);
+
+                       if (!(sc->sc_ah->caps.hw_caps &
+                                 ATH9K_HW_CAP_4KB_SPLITTRANS)) {
+                               /*
+                                * Skip descriptor addresses which can cause 4KB
+                                * boundary crossing (addr + length) with a 32 dword
+                                * descriptor fetch.
+                                */
+                               while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) {
+                                       BUG_ON((caddr_t) bf->bf_desc >=
+                                                  ((caddr_t) dd->dd_desc +
+                                               dd->dd_desc_len));
+
+                                       ds += (desc_len * ndesc);
+                                       bf->bf_desc = ds;
+                                       bf->bf_daddr = DS2PHYS(dd, ds);
+                               }
                        }
+                       list_add_tail(&bf->list, head);
                }
-               list_add_tail(&bf->list, head);
        }
        return 0;
 }
@@ -437,7 +471,6 @@ static int ath9k_init_queues(struct ath_softc *sc)
        sc->beacon.beaconq = ath9k_hw_beaconq_setup(sc->sc_ah);
        sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0);
 
-       sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
        ath_cabq_update(sc);
 
        sc->tx.uapsdq = ath_txq_setup(sc, ATH9K_TX_QUEUE_UAPSD, 0);
@@ -547,6 +580,26 @@ static void ath9k_init_platform(struct ath_softc *sc)
        if (sc->driver_data & ATH9K_PCI_CUS217)
                ath_info(common, "CUS217 card detected\n");
 
+       if (sc->driver_data & ATH9K_PCI_CUS252)
+               ath_info(common, "CUS252 card detected\n");
+
+       if (sc->driver_data & ATH9K_PCI_AR9565_1ANT)
+               ath_info(common, "WB335 1-ANT card detected\n");
+
+       if (sc->driver_data & ATH9K_PCI_AR9565_2ANT)
+               ath_info(common, "WB335 2-ANT card detected\n");
+
+       /*
+        * Some WB335 cards do not support antenna diversity. Since
+        * we use a hardcoded value for AR9565 instead of using the
+        * EEPROM/OTP data, remove the combining feature from
+        * the HW capabilities bitmap.
+        */
+       if (sc->driver_data & (ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_AR9565_2ANT)) {
+               if (!(sc->driver_data & ATH9K_PCI_BT_ANT_DIV))
+                       pCap->hw_caps &= ~ATH9K_HW_CAP_ANT_DIV_COMB;
+       }
+
        if (sc->driver_data & ATH9K_PCI_BT_ANT_DIV) {
                pCap->hw_caps |= ATH9K_HW_CAP_BT_ANT_DIV;
                ath_info(common, "Set BT/WLAN RX diversity capability\n");
@@ -748,7 +801,7 @@ static void ath9k_init_band_txpower(struct ath_softc *sc, int band)
                chan = &sband->channels[i];
                ah->curchan = &ah->channels[chan->hw_value];
                cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20);
-               ath9k_cmn_update_ichannel(ah->curchan, &chandef);
+               ath9k_cmn_get_channel(sc->hw, ah, &chandef);
                ath9k_hw_set_txpowerlimit(ah, MAX_RATE_POWER, true);
        }
 }
index 2f831db396ac2fd84c0ca1e3a6e46bc325b1013e..84a60644f93acd05ab8ff5fe08bdc01b48fd814e 100644 (file)
@@ -184,7 +184,7 @@ static void ath_paprd_activate(struct ath_softc *sc)
        struct ath9k_hw_cal_data *caldata = ah->caldata;
        int chain;
 
-       if (!caldata || !caldata->paprd_done) {
+       if (!caldata || !test_bit(PAPRD_DONE, &caldata->cal_flags)) {
                ath_dbg(common, CALIBRATE, "Failed to activate PAPRD\n");
                return;
        }
@@ -256,7 +256,9 @@ void ath_paprd_calibrate(struct work_struct *work)
        int len = 1800;
        int ret;
 
-       if (!caldata || !caldata->paprd_packet_sent || caldata->paprd_done) {
+       if (!caldata ||
+           !test_bit(PAPRD_PACKET_SENT, &caldata->cal_flags) ||
+           test_bit(PAPRD_DONE, &caldata->cal_flags)) {
                ath_dbg(common, CALIBRATE, "Skipping PAPRD calibration\n");
                return;
        }
@@ -316,7 +318,7 @@ void ath_paprd_calibrate(struct work_struct *work)
        kfree_skb(skb);
 
        if (chain_ok) {
-               caldata->paprd_done = true;
+               set_bit(PAPRD_DONE, &caldata->cal_flags);
                ath_paprd_activate(sc);
        }
 
@@ -343,7 +345,7 @@ void ath_ani_calibrate(unsigned long data)
        u32 cal_interval, short_cal_interval, long_cal_interval;
        unsigned long flags;
 
-       if (ah->caldata && ah->caldata->nfcal_interference)
+       if (ah->caldata && test_bit(NFCAL_INTF, &ah->caldata->cal_flags))
                long_cal_interval = ATH_LONG_CALINTERVAL_INT;
        else
                long_cal_interval = ATH_LONG_CALINTERVAL;
@@ -432,7 +434,7 @@ set_timer:
        mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 
        if (ar9003_is_paprd_enabled(ah) && ah->caldata) {
-               if (!ah->caldata->paprd_done) {
+               if (!test_bit(PAPRD_DONE, &ah->caldata->cal_flags)) {
                        ieee80211_queue_work(sc->hw, &sc->paprd_work);
                } else if (!ah->paprd_table_write_done) {
                        ath9k_ps_wakeup(sc);
index a3eff0986a3f95c1ea6b523fc71b02a1ac2b4eba..6a18f9d3e9cc952ef116f9fda1bf56f37526d8bc 100644 (file)
@@ -374,7 +374,6 @@ EXPORT_SYMBOL(ath9k_hw_releasetxqueue);
 bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath9k_channel *chan = ah->curchan;
        struct ath9k_tx_queue_info *qi;
        u32 cwMin, chanCwMin, value;
 
@@ -387,10 +386,7 @@ bool ath9k_hw_resettxqueue(struct ath_hw *ah, u32 q)
        ath_dbg(common, QUEUE, "Reset TX queue: %u\n", q);
 
        if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) {
-               if (chan && IS_CHAN_B(chan))
-                       chanCwMin = INIT_CWMIN_11B;
-               else
-                       chanCwMin = INIT_CWMIN;
+               chanCwMin = INIT_CWMIN;
 
                for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1);
        } else
index bfccaceed44ef82f34c7e9df6562975f4322bf5e..e3eed81f24391c61b1389a749d471cf4ad662056 100644 (file)
@@ -603,8 +603,6 @@ enum ath9k_tx_queue_flags {
 #define ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS 0x00000001
 
 #define ATH9K_DECOMP_MASK_SIZE     128
-#define ATH9K_READY_TIME_LO_BOUND  50
-#define ATH9K_READY_TIME_HI_BOUND  96
 
 enum ath9k_pkt_type {
        ATH9K_PKT_TYPE_NORMAL = 0,
index e4f65900132dedf40a68e2299b2a6177e8dfaf89..c42b55c1face8808f944d00068cce539f22d065a 100644 (file)
@@ -302,17 +302,91 @@ out:
  * by reseting the chip.  To accomplish this we must first cleanup any pending
  * DMA, then restart stuff.
 */
-static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
-                   struct ath9k_channel *hchan)
+static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef)
 {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_hw *hw = sc->hw;
+       struct ath9k_channel *hchan;
+       struct ieee80211_channel *chan = chandef->chan;
+       unsigned long flags;
+       bool offchannel;
+       int pos = chan->hw_value;
+       int old_pos = -1;
        int r;
 
        if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EIO;
 
+       offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
+
+       if (ah->curchan)
+               old_pos = ah->curchan - &ah->channels[0];
+
+       ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
+               chan->center_freq, chandef->width);
+
+       /* update survey stats for the old channel before switching */
+       spin_lock_irqsave(&common->cc_lock, flags);
+       ath_update_survey_stats(sc);
+       spin_unlock_irqrestore(&common->cc_lock, flags);
+
+       ath9k_cmn_get_channel(hw, ah, chandef);
+
+       /*
+        * If the operating channel changes, change the survey in-use flags
+        * along with it.
+        * Reset the survey data for the new channel, unless we're switching
+        * back to the operating channel from an off-channel operation.
+        */
+       if (!offchannel && sc->cur_survey != &sc->survey[pos]) {
+               if (sc->cur_survey)
+                       sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
+
+               sc->cur_survey = &sc->survey[pos];
+
+               memset(sc->cur_survey, 0, sizeof(struct survey_info));
+               sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
+       } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
+               memset(&sc->survey[pos], 0, sizeof(struct survey_info));
+       }
+
+       hchan = &sc->sc_ah->channels[pos];
        r = ath_reset_internal(sc, hchan);
+       if (r)
+               return r;
 
-       return r;
+       /*
+        * The most recent snapshot of channel->noisefloor for the old
+        * channel is only available after the hardware reset. Copy it to
+        * the survey stats now.
+        */
+       if (old_pos >= 0)
+               ath_update_survey_nf(sc, old_pos);
+
+       /*
+        * Enable radar pulse detection if on a DFS channel. Spectral
+        * scanning and radar detection can not be used concurrently.
+        */
+       if (hw->conf.radar_enabled) {
+               u32 rxfilter;
+
+               /* set HW specific DFS configuration */
+               ath9k_hw_set_radar_params(ah);
+               rxfilter = ath9k_hw_getrxfilter(ah);
+               rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
+                               ATH9K_RX_FILTER_PHYERR;
+               ath9k_hw_setrxfilter(ah, rxfilter);
+               ath_dbg(common, DFS, "DFS enabled at freq %d\n",
+                       chan->center_freq);
+       } else {
+               /* perform spectral scan if requested. */
+               if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
+                       sc->spectral_mode == SPECTRAL_CHANSCAN)
+                       ath9k_spectral_scan_trigger(hw);
+       }
+
+       return 0;
 }
 
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -362,6 +436,13 @@ void ath9k_tasklet(unsigned long data)
                        type = RESET_TYPE_BB_WATCHDOG;
 
                ath9k_queue_reset(sc, type);
+
+               /*
+                * Increment the ref. counter here so that
+                * interrupts are enabled in the reset routine.
+                */
+               atomic_inc(&ah->intr_ref_cnt);
+               ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
                goto out;
        }
 
@@ -400,10 +481,9 @@ void ath9k_tasklet(unsigned long data)
 
        ath9k_btcoex_handle_interrupt(sc, status);
 
-out:
        /* re-enable hardware interrupt */
        ath9k_hw_enable_interrupts(ah);
-
+out:
        spin_unlock(&sc->sc_pcu_lock);
        ath9k_ps_restore(sc);
 }
@@ -595,7 +675,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
        ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
-       init_channel = ath9k_cmn_get_curchannel(hw, ah);
+       init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
 
        /* Reset SERDES registers */
        ath9k_hw_configpcipowersave(ah, false);
@@ -798,7 +878,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        }
 
        if (!ah->curchan)
-               ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+               ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
 
        ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        ath9k_hw_phy_disable(ah);
@@ -817,7 +897,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        ath_dbg(common, CONFIG, "Driver halt\n");
 }
 
-bool ath9k_uses_beacons(int type)
+static bool ath9k_uses_beacons(int type)
 {
        switch (type) {
        case NL80211_IFTYPE_AP:
@@ -1202,81 +1282,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        }
 
        if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
-               struct ieee80211_channel *curchan = hw->conf.chandef.chan;
-               int pos = curchan->hw_value;
-               int old_pos = -1;
-               unsigned long flags;
-
-               if (ah->curchan)
-                       old_pos = ah->curchan - &ah->channels[0];
-
-               ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
-                       curchan->center_freq, hw->conf.chandef.width);
-
-               /* update survey stats for the old channel before switching */
-               spin_lock_irqsave(&common->cc_lock, flags);
-               ath_update_survey_stats(sc);
-               spin_unlock_irqrestore(&common->cc_lock, flags);
-
-               ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
-                                         &conf->chandef);
-
-               /*
-                * If the operating channel changes, change the survey in-use flags
-                * along with it.
-                * Reset the survey data for the new channel, unless we're switching
-                * back to the operating channel from an off-channel operation.
-                */
-               if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
-                   sc->cur_survey != &sc->survey[pos]) {
-
-                       if (sc->cur_survey)
-                               sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
-
-                       sc->cur_survey = &sc->survey[pos];
-
-                       memset(sc->cur_survey, 0, sizeof(struct survey_info));
-                       sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
-               } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
-                       memset(&sc->survey[pos], 0, sizeof(struct survey_info));
-               }
-
-               if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
+               if (ath_set_channel(sc, &hw->conf.chandef) < 0) {
                        ath_err(common, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
                        ath9k_ps_restore(sc);
                        return -EINVAL;
                }
-
-               /*
-                * The most recent snapshot of channel->noisefloor for the old
-                * channel is only available after the hardware reset. Copy it to
-                * the survey stats now.
-                */
-               if (old_pos >= 0)
-                       ath_update_survey_nf(sc, old_pos);
-
-               /*
-                * Enable radar pulse detection if on a DFS channel. Spectral
-                * scanning and radar detection can not be used concurrently.
-                */
-               if (hw->conf.radar_enabled) {
-                       u32 rxfilter;
-
-                       /* set HW specific DFS configuration */
-                       ath9k_hw_set_radar_params(ah);
-                       rxfilter = ath9k_hw_getrxfilter(ah);
-                       rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
-                                   ATH9K_RX_FILTER_PHYERR;
-                       ath9k_hw_setrxfilter(ah, rxfilter);
-                       ath_dbg(common, DFS, "DFS enabled at freq %d\n",
-                               curchan->center_freq);
-               } else {
-                       /* perform spectral scan if requested. */
-                       if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
-                           sc->spectral_mode == SPECTRAL_CHANSCAN)
-                               ath9k_spectral_scan_trigger(hw);
-               }
        }
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
index 815bee21c19a0fe1aeb2194fbdba2372be2b279b..0ac1b5f04256517050be277696e9a9eae4f2391c 100644 (file)
@@ -661,9 +661,9 @@ void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all)
        chan_start = wlan_chan - 10;
        chan_end = wlan_chan + 10;
 
-       if (chan->chanmode == CHANNEL_G_HT40PLUS)
+       if (IS_CHAN_HT40PLUS(chan))
                chan_end += 20;
-       else if (chan->chanmode == CHANNEL_G_HT40MINUS)
+       else if (IS_CHAN_HT40MINUS(chan))
                chan_start -= 20;
 
        /* adjust side band */
@@ -707,11 +707,11 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
 
        if (setchannel) {
                struct ath9k_hw_cal_data *caldata = &sc->caldata;
-               if ((caldata->chanmode == CHANNEL_G_HT40PLUS) &&
+               if (IS_CHAN_HT40PLUS(ah->curchan) &&
                    (ah->curchan->channel > caldata->channel) &&
                    (ah->curchan->channel <= caldata->channel + 20))
                        return;
-               if ((caldata->chanmode == CHANNEL_G_HT40MINUS) &&
+               if (IS_CHAN_HT40MINUS(ah->curchan) &&
                    (ah->curchan->channel < caldata->channel) &&
                    (ah->curchan->channel >= caldata->channel - 20))
                        return;
index d089a7cf01c43810e88353d6504a90c238abf721..7e4c2524b63052006650ff76b92b3b839d6c9cd6 100644 (file)
@@ -269,7 +269,200 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
 
        { PCI_VDEVICE(ATHEROS, 0x0034) }, /* PCI-E  AR9462 */
        { PCI_VDEVICE(ATHEROS, 0x0037) }, /* PCI-E  AR1111/AR9485 */
-       { PCI_VDEVICE(ATHEROS, 0x0036) }, /* PCI-E  AR9565 */
+
+       /* CUS252 */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x3028),
+         .driver_data = ATH9K_PCI_CUS252 |
+                        ATH9K_PCI_AR9565_2ANT |
+                        ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x2176),
+         .driver_data = ATH9K_PCI_CUS252 |
+                        ATH9K_PCI_AR9565_2ANT |
+                        ATH9K_PCI_BT_ANT_DIV },
+
+       /* WB335 1-ANT */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE068),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x185F, /* WNC */
+                        0xA119),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0632),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x6671),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x1B9A, /* XAVI */
+                        0x2811),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x1B9A, /* XAVI */
+                        0x2812),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+
+       /* WB335 1-ANT / Antenna Diversity */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x3025),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x3026),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x302B),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE069),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x185F, /* WNC */
+                        0x3028),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0622),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0672),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0662),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x213A),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_LENOVO,
+                        0x3026),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_HP,
+                        0x18E3),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_HP,
+                        0x217F),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_DELL,
+                        0x020E),
+         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+
+       /* WB335 2-ANT */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_SAMSUNG,
+                        0x411A),
+         .driver_data = ATH9K_PCI_AR9565_2ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_SAMSUNG,
+                        0x411B),
+         .driver_data = ATH9K_PCI_AR9565_2ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_SAMSUNG,
+                        0x411C),
+         .driver_data = ATH9K_PCI_AR9565_2ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_SAMSUNG,
+                        0x411D),
+         .driver_data = ATH9K_PCI_AR9565_2ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_SAMSUNG,
+                        0x411E),
+         .driver_data = ATH9K_PCI_AR9565_2ANT },
+
+       /* WB335 2-ANT / Antenna-Diversity */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x3027),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x302C),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0642),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0652),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0612),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x2130),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x144F, /* ASKEY */
+                        0x7202),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x1B9A, /* XAVI */
+                        0x2810),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x185F, /* WNC */
+                        0x3027),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+
+       /* PCI-E AR9565 (WB335) */
+       { PCI_VDEVICE(ATHEROS, 0x0036),
+         .driver_data = ATH9K_PCI_BT_ANT_DIV },
+
        { 0 }
 };
 
index d3d7c51fa6c8bd65d7df5f803c99450aff980d95..d829bb62a3fc6d9e94ae867b2a675530ea4d1d7a 100644 (file)
@@ -1387,31 +1387,31 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
                int used_mcs = 0, used_htmode = 0;
 
                if (WLAN_RC_PHY_HT(rc->rate_table->info[i].phy)) {
-                       used_mcs = snprintf(mcs, 5, "%d",
-                               rc->rate_table->info[i].ratecode);
+                       used_mcs = scnprintf(mcs, 5, "%d",
+                                            rc->rate_table->info[i].ratecode);
 
                        if (WLAN_RC_PHY_40(rc->rate_table->info[i].phy))
-                               used_htmode = snprintf(htmode, 5, "HT40");
+                               used_htmode = scnprintf(htmode, 5, "HT40");
                        else if (WLAN_RC_PHY_20(rc->rate_table->info[i].phy))
-                               used_htmode = snprintf(htmode, 5, "HT20");
+                               used_htmode = scnprintf(htmode, 5, "HT20");
                        else
-                               used_htmode = snprintf(htmode, 5, "????");
+                               used_htmode = scnprintf(htmode, 5, "????");
                }
 
                mcs[used_mcs] = '\0';
                htmode[used_htmode] = '\0';
 
-               len += snprintf(buf + len, max - len,
-                       "%6s %6s %3u.%d: "
-                       "%10u %10u %10u %10u\n",
-                       htmode,
-                       mcs,
-                       ratekbps / 1000,
-                       (ratekbps % 1000) / 100,
-                       stats->success,
-                       stats->retries,
-                       stats->xretries,
-                       stats->per);
+               len += scnprintf(buf + len, max - len,
+                                "%6s %6s %3u.%d: "
+                                "%10u %10u %10u %10u\n",
+                                htmode,
+                                mcs,
+                                ratekbps / 1000,
+                                (ratekbps % 1000) / 100,
+                                stats->success,
+                                stats->retries,
+                                stats->xretries,
+                                stats->per);
        }
 
        if (len > max)
index 4ee472a5a4e4ee6e81b1c0ffc820b6f685fb7ad1..a05164166de8c856b4e755584be375b5e3082cfe 100644 (file)
@@ -19,7 +19,7 @@
 #include "ath9k.h"
 #include "ar9003_mac.h"
 
-#define SKB_CB_ATHBUF(__skb)   (*((struct ath_buf **)__skb->cb))
+#define SKB_CB_ATHBUF(__skb)   (*((struct ath_rxbuf **)__skb->cb))
 
 static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
 {
@@ -35,7 +35,7 @@ static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
  * buffer (or rx fifo). This can incorrectly acknowledge packets
  * to a sender if last desc is self-linked.
  */
-static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
+static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -68,7 +68,7 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf)
        sc->rx.rxlink = &ds->ds_link;
 }
 
-static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf)
+static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf)
 {
        if (sc->rx.buf_hold)
                ath_rx_buf_link(sc, sc->rx.buf_hold);
@@ -112,13 +112,13 @@ static bool ath_rx_edma_buf_link(struct ath_softc *sc,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_rx_edma *rx_edma;
        struct sk_buff *skb;
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
 
        rx_edma = &sc->rx.rx_edma[qtype];
        if (skb_queue_len(&rx_edma->rx_fifo) >= rx_edma->rx_fifo_hwsize)
                return false;
 
-       bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+       bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list);
        list_del_init(&bf->list);
 
        skb = bf->bf_mpdu;
@@ -138,7 +138,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc,
                                  enum ath9k_rx_qtype qtype)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ath_buf *bf, *tbf;
+       struct ath_rxbuf *bf, *tbf;
 
        if (list_empty(&sc->rx.rxbuf)) {
                ath_dbg(common, QUEUE, "No free rx buf available\n");
@@ -154,7 +154,7 @@ static void ath_rx_addbuffer_edma(struct ath_softc *sc,
 static void ath_rx_remove_buffer(struct ath_softc *sc,
                                 enum ath9k_rx_qtype qtype)
 {
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
        struct ath_rx_edma *rx_edma;
        struct sk_buff *skb;
 
@@ -171,7 +171,7 @@ static void ath_rx_edma_cleanup(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
 
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
@@ -199,7 +199,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
        struct sk_buff *skb;
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
        int error = 0, i;
        u32 size;
 
@@ -211,7 +211,7 @@ static int ath_rx_edma_init(struct ath_softc *sc, int nbufs)
        ath_rx_edma_init_queue(&sc->rx.rx_edma[ATH9K_RX_QUEUE_HP],
                               ah->caps.rx_hp_qdepth);
 
-       size = sizeof(struct ath_buf) * nbufs;
+       size = sizeof(struct ath_rxbuf) * nbufs;
        bf = devm_kzalloc(sc->dev, size, GFP_KERNEL);
        if (!bf)
                return -ENOMEM;
@@ -271,7 +271,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct sk_buff *skb;
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
        int error = 0;
 
        spin_lock_init(&sc->sc_pcu_lock);
@@ -332,7 +332,7 @@ void ath_rx_cleanup(struct ath_softc *sc)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct sk_buff *skb;
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
 
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
                ath_rx_edma_cleanup(sc);
@@ -427,7 +427,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
 int ath_startrecv(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
-       struct ath_buf *bf, *tbf;
+       struct ath_rxbuf *bf, *tbf;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
                ath_edma_start_recv(sc);
@@ -447,7 +447,7 @@ int ath_startrecv(struct ath_softc *sc)
        if (list_empty(&sc->rx.rxbuf))
                goto start_recv;
 
-       bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+       bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list);
        ath9k_hw_putrxbuf(ah, bf->bf_daddr);
        ath9k_hw_rxena(ah);
 
@@ -603,13 +603,13 @@ static void ath_rx_ps(struct ath_softc *sc, struct sk_buff *skb, bool mybeacon)
 static bool ath_edma_get_buffers(struct ath_softc *sc,
                                 enum ath9k_rx_qtype qtype,
                                 struct ath_rx_status *rs,
-                                struct ath_buf **dest)
+                                struct ath_rxbuf **dest)
 {
        struct ath_rx_edma *rx_edma = &sc->rx.rx_edma[qtype];
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct sk_buff *skb;
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
        int ret;
 
        skb = skb_peek(&rx_edma->rx_fifo);
@@ -653,11 +653,11 @@ static bool ath_edma_get_buffers(struct ath_softc *sc,
        return true;
 }
 
-static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc,
+static struct ath_rxbuf *ath_edma_get_next_rx_buf(struct ath_softc *sc,
                                                struct ath_rx_status *rs,
                                                enum ath9k_rx_qtype qtype)
 {
-       struct ath_buf *bf = NULL;
+       struct ath_rxbuf *bf = NULL;
 
        while (ath_edma_get_buffers(sc, qtype, rs, &bf)) {
                if (!bf)
@@ -668,13 +668,13 @@ static struct ath_buf *ath_edma_get_next_rx_buf(struct ath_softc *sc,
        return NULL;
 }
 
-static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
+static struct ath_rxbuf *ath_get_next_rx_buf(struct ath_softc *sc,
                                           struct ath_rx_status *rs)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_desc *ds;
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
        int ret;
 
        if (list_empty(&sc->rx.rxbuf)) {
@@ -682,7 +682,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
                return NULL;
        }
 
-       bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list);
+       bf = list_first_entry(&sc->rx.rxbuf, struct ath_rxbuf, list);
        if (bf == sc->rx.buf_hold)
                return NULL;
 
@@ -702,7 +702,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
        ret = ath9k_hw_rxprocdesc(ah, ds, rs);
        if (ret == -EINPROGRESS) {
                struct ath_rx_status trs;
-               struct ath_buf *tbf;
+               struct ath_rxbuf *tbf;
                struct ath_desc *tds;
 
                memset(&trs, 0, sizeof(trs));
@@ -711,7 +711,7 @@ static struct ath_buf *ath_get_next_rx_buf(struct ath_softc *sc,
                        return NULL;
                }
 
-               tbf = list_entry(bf->list.next, struct ath_buf, list);
+               tbf = list_entry(bf->list.next, struct ath_rxbuf, list);
 
                /*
                 * On some hardware the descriptor status words could
@@ -1315,7 +1315,7 @@ static void ath9k_apply_ampdu_details(struct ath_softc *sc,
 
 int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
 {
-       struct ath_buf *bf;
+       struct ath_rxbuf *bf;
        struct sk_buff *skb = NULL, *requeue_skb, *hdr_skb;
        struct ieee80211_rx_status *rxs;
        struct ath_hw *ah = sc->sc_ah;
index fde6da619f30f96e146c00b017e5f37a9df0e80d..0db37f230018ee2692ef4fcbff7cf3f0b3135e8e 100644 (file)
@@ -39,7 +39,7 @@ struct wmi_fw_version {
 struct wmi_event_swba {
        __be64 tsf;
        u8 beacon_pending;
-};
+} __packed;
 
 /*
  * 64 - HTC header - WMI header - 1 / txstatus
index 35b515fe3ffa41e00dc614b6590cc2eabead9de4..fc76052c072114df5154d6200ce9d0f45aac5346 100644 (file)
@@ -1695,16 +1695,9 @@ int ath_cabq_update(struct ath_softc *sc)
        int qnum = sc->beacon.cabq->axq_qnum;
 
        ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
-       /*
-        * Ensure the readytime % is within the bounds.
-        */
-       if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
-               sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
-       else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
-               sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
 
        qi.tqi_readyTime = (cur_conf->beacon_interval *
-                           sc->config.cabqReadytime) / 100;
+                           ATH_CABQ_READY_TIME) / 100;
        ath_txq_update(sc, qnum, &qi);
 
        return 0;
@@ -2023,8 +2016,7 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
        struct ath_hw *ah = sc->sc_ah;
        struct ath9k_channel *curchan = ah->curchan;
 
-       if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) &&
-           (curchan->channelFlags & CHANNEL_5GHZ) &&
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && IS_CHAN_5GHZ(curchan) &&
            (chainmask == 0x7) && (rate < 0x90))
                return 0x3;
        else if (AR_SREV_9462(ah) && ath9k_hw_btcoex_is_enabled(ah) &&
@@ -2315,7 +2307,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
 
        if (sc->sc_ah->caldata)
-               sc->sc_ah->caldata->paprd_packet_sent = true;
+               set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags);
 
        if (!(tx_flags & ATH_TX_ERROR))
                /* Frame was ACKed */
diff --git a/drivers/net/wireless/ath/wcn36xx/Kconfig b/drivers/net/wireless/ath/wcn36xx/Kconfig
new file mode 100644 (file)
index 0000000..591ebae
--- /dev/null
@@ -0,0 +1,16 @@
+config WCN36XX
+       tristate "Qualcomm Atheros WCN3660/3680 support"
+       depends on MAC80211 && HAS_DMA
+       ---help---
+         This module adds support for wireless adapters based on
+         Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets.
+
+         If you choose to build a module, it'll be called wcn36xx.
+
+config WCN36XX_DEBUGFS
+       bool "WCN36XX debugfs support"
+       depends on WCN36XX
+       ---help---
+         Enabled debugfs support
+
+         If unsure, say Y to make it easier to debug problems.
diff --git a/drivers/net/wireless/ath/wcn36xx/Makefile b/drivers/net/wireless/ath/wcn36xx/Makefile
new file mode 100644 (file)
index 0000000..50c43b4
--- /dev/null
@@ -0,0 +1,7 @@
+obj-$(CONFIG_WCN36XX) := wcn36xx.o
+wcn36xx-y +=   main.o \
+               dxe.o \
+               txrx.o \
+               smd.o \
+               pmc.o \
+               debug.o
diff --git a/drivers/net/wireless/ath/wcn36xx/debug.c b/drivers/net/wireless/ath/wcn36xx/debug.c
new file mode 100644 (file)
index 0000000..5b84f7a
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include "wcn36xx.h"
+#include "debug.h"
+#include "pmc.h"
+
+#ifdef CONFIG_WCN36XX_DEBUGFS
+
+static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf,
+                                  size_t count, loff_t *ppos)
+{
+       struct wcn36xx *wcn = file->private_data;
+       struct wcn36xx_vif *vif_priv = NULL;
+       struct ieee80211_vif *vif = NULL;
+       char buf[3];
+
+       list_for_each_entry(vif_priv, &wcn->vif_list, list) {
+                       vif = container_of((void *)vif_priv,
+                                  struct ieee80211_vif,
+                                  drv_priv);
+                       if (NL80211_IFTYPE_STATION == vif->type) {
+                               if (vif_priv->pw_state == WCN36XX_BMPS)
+                                       buf[0] = '1';
+                               else
+                                       buf[0] = '0';
+                               break;
+                       }
+       }
+       buf[1] = '\n';
+       buf[2] = 0x00;
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t write_file_bool_bmps(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wcn36xx *wcn = file->private_data;
+       struct wcn36xx_vif *vif_priv = NULL;
+       struct ieee80211_vif *vif = NULL;
+
+       char buf[32];
+       int buf_size;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       switch (buf[0]) {
+       case 'y':
+       case 'Y':
+       case '1':
+               list_for_each_entry(vif_priv, &wcn->vif_list, list) {
+                       vif = container_of((void *)vif_priv,
+                                  struct ieee80211_vif,
+                                  drv_priv);
+                       if (NL80211_IFTYPE_STATION == vif->type) {
+                               wcn36xx_enable_keep_alive_null_packet(wcn, vif);
+                               wcn36xx_pmc_enter_bmps_state(wcn, vif);
+                       }
+               }
+               break;
+       case 'n':
+       case 'N':
+       case '0':
+               list_for_each_entry(vif_priv, &wcn->vif_list, list) {
+                       vif = container_of((void *)vif_priv,
+                                  struct ieee80211_vif,
+                                  drv_priv);
+                       if (NL80211_IFTYPE_STATION == vif->type)
+                               wcn36xx_pmc_exit_bmps_state(wcn, vif);
+               }
+               break;
+       }
+
+       return count;
+}
+
+static const struct file_operations fops_wcn36xx_bmps = {
+       .open = simple_open,
+       .read  =       read_file_bool_bmps,
+       .write =       write_file_bool_bmps,
+};
+
+static ssize_t write_file_dump(struct file *file,
+                                   const char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct wcn36xx *wcn = file->private_data;
+       char buf[255], *tmp;
+       int buf_size;
+       u32 arg[WCN36xx_MAX_DUMP_ARGS];
+       int i;
+
+       memset(buf, 0, sizeof(buf));
+       memset(arg, 0, sizeof(arg));
+
+       buf_size = min(count, (sizeof(buf) - 1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       tmp = buf;
+
+       for (i = 0; i < WCN36xx_MAX_DUMP_ARGS; i++) {
+               char *begin;
+               begin = strsep(&tmp, " ");
+               if (begin == NULL)
+                       break;
+
+               if (kstrtoul(begin, 0, (unsigned long *)(arg + i)) != 0)
+                       break;
+       }
+
+       wcn36xx_info("DUMP args is %d %d %d %d %d\n", arg[0], arg[1], arg[2],
+                    arg[3], arg[4]);
+       wcn36xx_smd_dump_cmd_req(wcn, arg[0], arg[1], arg[2], arg[3], arg[4]);
+
+       return count;
+}
+
+static const struct file_operations fops_wcn36xx_dump = {
+       .open = simple_open,
+       .write =       write_file_dump,
+};
+
+#define ADD_FILE(name, mode, fop, priv_data)           \
+       do {                                                    \
+               struct dentry *d;                               \
+               d = debugfs_create_file(__stringify(name),      \
+                                       mode, dfs->rootdir,     \
+                                       priv_data, fop);        \
+               dfs->file_##name.dentry = d;                    \
+               if (IS_ERR(d)) {                                \
+                       wcn36xx_warn("Create the debugfs entry failed");\
+                       dfs->file_##name.dentry = NULL;         \
+               }                                               \
+       } while (0)
+
+
+void wcn36xx_debugfs_init(struct wcn36xx *wcn)
+{
+       struct wcn36xx_dfs_entry *dfs = &wcn->dfs;
+
+       dfs->rootdir = debugfs_create_dir(KBUILD_MODNAME,
+                                         wcn->hw->wiphy->debugfsdir);
+       if (IS_ERR(dfs->rootdir)) {
+               wcn36xx_warn("Create the debugfs failed\n");
+               dfs->rootdir = NULL;
+       }
+
+       ADD_FILE(bmps_switcher, S_IRUSR | S_IWUSR,
+                &fops_wcn36xx_bmps, wcn);
+       ADD_FILE(dump, S_IWUSR, &fops_wcn36xx_dump, wcn);
+}
+
+void wcn36xx_debugfs_exit(struct wcn36xx *wcn)
+{
+       struct wcn36xx_dfs_entry *dfs = &wcn->dfs;
+       debugfs_remove_recursive(dfs->rootdir);
+}
+
+#endif /* CONFIG_WCN36XX_DEBUGFS */
diff --git a/drivers/net/wireless/ath/wcn36xx/debug.h b/drivers/net/wireless/ath/wcn36xx/debug.h
new file mode 100644 (file)
index 0000000..46307aa
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WCN36XX_DEBUG_H_
+#define _WCN36XX_DEBUG_H_
+
+#include <linux/kernel.h>
+
+#define WCN36xx_MAX_DUMP_ARGS  5
+
+#ifdef CONFIG_WCN36XX_DEBUGFS
+struct wcn36xx_dfs_file {
+       struct dentry *dentry;
+       u32 value;
+};
+
+struct wcn36xx_dfs_entry {
+       struct dentry *rootdir;
+       struct wcn36xx_dfs_file file_bmps_switcher;
+       struct wcn36xx_dfs_file file_dump;
+};
+
+void wcn36xx_debugfs_init(struct wcn36xx *wcn);
+void wcn36xx_debugfs_exit(struct wcn36xx *wcn);
+
+#else
+static inline void wcn36xx_debugfs_init(struct wcn36xx *wcn)
+{
+}
+static inline void wcn36xx_debugfs_exit(struct wcn36xx *wcn)
+{
+}
+
+#endif /* CONFIG_WCN36XX_DEBUGFS */
+
+#endif /* _WCN36XX_DEBUG_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
new file mode 100644 (file)
index 0000000..ee25786
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* DXE - DMA transfer engine
+ * we have 2 channels(High prio and Low prio) for TX and 2 channels for RX.
+ * through low channels data packets are transfered
+ * through high channels managment packets are transfered
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/interrupt.h>
+#include "wcn36xx.h"
+#include "txrx.h"
+
+void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low)
+{
+       struct wcn36xx_dxe_ch *ch = is_low ?
+               &wcn->dxe_tx_l_ch :
+               &wcn->dxe_tx_h_ch;
+
+       return ch->head_blk_ctl->bd_cpu_addr;
+}
+
+static void wcn36xx_dxe_write_register(struct wcn36xx *wcn, int addr, int data)
+{
+       wcn36xx_dbg(WCN36XX_DBG_DXE,
+                   "wcn36xx_dxe_write_register: addr=%x, data=%x\n",
+                   addr, data);
+
+       writel(data, wcn->mmio + addr);
+}
+
+static void wcn36xx_dxe_read_register(struct wcn36xx *wcn, int addr, int *data)
+{
+       *data = readl(wcn->mmio + addr);
+
+       wcn36xx_dbg(WCN36XX_DBG_DXE,
+                   "wcn36xx_dxe_read_register: addr=%x, data=%x\n",
+                   addr, *data);
+}
+
+static void wcn36xx_dxe_free_ctl_block(struct wcn36xx_dxe_ch *ch)
+{
+       struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl, *next;
+       int i;
+
+       for (i = 0; i < ch->desc_num && ctl; i++) {
+               next = ctl->next;
+               kfree(ctl);
+               ctl = next;
+       }
+}
+
+static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch)
+{
+       struct wcn36xx_dxe_ctl *prev_ctl = NULL;
+       struct wcn36xx_dxe_ctl *cur_ctl = NULL;
+       int i;
+
+       for (i = 0; i < ch->desc_num; i++) {
+               cur_ctl = kzalloc(sizeof(*cur_ctl), GFP_KERNEL);
+               if (!cur_ctl)
+                       goto out_fail;
+
+               cur_ctl->ctl_blk_order = i;
+               if (i == 0) {
+                       ch->head_blk_ctl = cur_ctl;
+                       ch->tail_blk_ctl = cur_ctl;
+               } else if (ch->desc_num - 1 == i) {
+                       prev_ctl->next = cur_ctl;
+                       cur_ctl->next = ch->head_blk_ctl;
+               } else {
+                       prev_ctl->next = cur_ctl;
+               }
+               prev_ctl = cur_ctl;
+       }
+
+       return 0;
+
+out_fail:
+       wcn36xx_dxe_free_ctl_block(ch);
+       return -ENOMEM;
+}
+
+int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn)
+{
+       int ret;
+
+       wcn->dxe_tx_l_ch.ch_type = WCN36XX_DXE_CH_TX_L;
+       wcn->dxe_tx_h_ch.ch_type = WCN36XX_DXE_CH_TX_H;
+       wcn->dxe_rx_l_ch.ch_type = WCN36XX_DXE_CH_RX_L;
+       wcn->dxe_rx_h_ch.ch_type = WCN36XX_DXE_CH_RX_H;
+
+       wcn->dxe_tx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_TX_L;
+       wcn->dxe_tx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_TX_H;
+       wcn->dxe_rx_l_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_L;
+       wcn->dxe_rx_h_ch.desc_num = WCN36XX_DXE_CH_DESC_NUMB_RX_H;
+
+       wcn->dxe_tx_l_ch.dxe_wq =  WCN36XX_DXE_WQ_TX_L;
+       wcn->dxe_tx_h_ch.dxe_wq =  WCN36XX_DXE_WQ_TX_H;
+
+       wcn->dxe_tx_l_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_L_BD;
+       wcn->dxe_tx_h_ch.ctrl_bd = WCN36XX_DXE_CTRL_TX_H_BD;
+
+       wcn->dxe_tx_l_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_L_SKB;
+       wcn->dxe_tx_h_ch.ctrl_skb = WCN36XX_DXE_CTRL_TX_H_SKB;
+
+       wcn->dxe_tx_l_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_L;
+       wcn->dxe_tx_h_ch.reg_ctrl = WCN36XX_DXE_REG_CTL_TX_H;
+
+       wcn->dxe_tx_l_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_L;
+       wcn->dxe_tx_h_ch.def_ctrl = WCN36XX_DXE_CH_DEFAULT_CTL_TX_H;
+
+       /* DXE control block allocation */
+       ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_l_ch);
+       if (ret)
+               goto out_err;
+       ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_tx_h_ch);
+       if (ret)
+               goto out_err;
+       ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_rx_l_ch);
+       if (ret)
+               goto out_err;
+       ret = wcn36xx_dxe_allocate_ctl_block(&wcn->dxe_rx_h_ch);
+       if (ret)
+               goto out_err;
+
+       /* Initialize SMSM state  Clear TX Enable RING EMPTY STATE */
+       ret = wcn->ctrl_ops->smsm_change_state(
+               WCN36XX_SMSM_WLAN_TX_ENABLE,
+               WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY);
+
+       return 0;
+
+out_err:
+       wcn36xx_err("Failed to allocate DXE control blocks\n");
+       wcn36xx_dxe_free_ctl_blks(wcn);
+       return -ENOMEM;
+}
+
+void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn)
+{
+       wcn36xx_dxe_free_ctl_block(&wcn->dxe_tx_l_ch);
+       wcn36xx_dxe_free_ctl_block(&wcn->dxe_tx_h_ch);
+       wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_l_ch);
+       wcn36xx_dxe_free_ctl_block(&wcn->dxe_rx_h_ch);
+}
+
+static int wcn36xx_dxe_init_descs(struct wcn36xx_dxe_ch *wcn_ch)
+{
+       struct wcn36xx_dxe_desc *cur_dxe = NULL;
+       struct wcn36xx_dxe_desc *prev_dxe = NULL;
+       struct wcn36xx_dxe_ctl *cur_ctl = NULL;
+       size_t size;
+       int i;
+
+       size = wcn_ch->desc_num * sizeof(struct wcn36xx_dxe_desc);
+       wcn_ch->cpu_addr = dma_alloc_coherent(NULL, size, &wcn_ch->dma_addr,
+                                             GFP_KERNEL);
+       if (!wcn_ch->cpu_addr)
+               return -ENOMEM;
+
+       memset(wcn_ch->cpu_addr, 0, size);
+
+       cur_dxe = (struct wcn36xx_dxe_desc *)wcn_ch->cpu_addr;
+       cur_ctl = wcn_ch->head_blk_ctl;
+
+       for (i = 0; i < wcn_ch->desc_num; i++) {
+               cur_ctl->desc = cur_dxe;
+               cur_ctl->desc_phy_addr = wcn_ch->dma_addr +
+                       i * sizeof(struct wcn36xx_dxe_desc);
+
+               switch (wcn_ch->ch_type) {
+               case WCN36XX_DXE_CH_TX_L:
+                       cur_dxe->ctrl = WCN36XX_DXE_CTRL_TX_L;
+                       cur_dxe->dst_addr_l = WCN36XX_DXE_WQ_TX_L;
+                       break;
+               case WCN36XX_DXE_CH_TX_H:
+                       cur_dxe->ctrl = WCN36XX_DXE_CTRL_TX_H;
+                       cur_dxe->dst_addr_l = WCN36XX_DXE_WQ_TX_H;
+                       break;
+               case WCN36XX_DXE_CH_RX_L:
+                       cur_dxe->ctrl = WCN36XX_DXE_CTRL_RX_L;
+                       cur_dxe->src_addr_l = WCN36XX_DXE_WQ_RX_L;
+                       break;
+               case WCN36XX_DXE_CH_RX_H:
+                       cur_dxe->ctrl = WCN36XX_DXE_CTRL_RX_H;
+                       cur_dxe->src_addr_l = WCN36XX_DXE_WQ_RX_H;
+                       break;
+               }
+               if (0 == i) {
+                       cur_dxe->phy_next_l = 0;
+               } else if ((0 < i) && (i < wcn_ch->desc_num - 1)) {
+                       prev_dxe->phy_next_l =
+                               cur_ctl->desc_phy_addr;
+               } else if (i == (wcn_ch->desc_num - 1)) {
+                       prev_dxe->phy_next_l =
+                               cur_ctl->desc_phy_addr;
+                       cur_dxe->phy_next_l =
+                               wcn_ch->head_blk_ctl->desc_phy_addr;
+               }
+               cur_ctl = cur_ctl->next;
+               prev_dxe = cur_dxe;
+               cur_dxe++;
+       }
+
+       return 0;
+}
+
+static void wcn36xx_dxe_init_tx_bd(struct wcn36xx_dxe_ch *ch,
+                                  struct wcn36xx_dxe_mem_pool *pool)
+{
+       int i, chunk_size = pool->chunk_size;
+       dma_addr_t bd_phy_addr = pool->phy_addr;
+       void *bd_cpu_addr = pool->virt_addr;
+       struct wcn36xx_dxe_ctl *cur = ch->head_blk_ctl;
+
+       for (i = 0; i < ch->desc_num; i++) {
+               /* Only every second dxe needs a bd pointer,
+                  the other will point to the skb data */
+               if (!(i & 1)) {
+                       cur->bd_phy_addr = bd_phy_addr;
+                       cur->bd_cpu_addr = bd_cpu_addr;
+                       bd_phy_addr += chunk_size;
+                       bd_cpu_addr += chunk_size;
+               } else {
+                       cur->bd_phy_addr = 0;
+                       cur->bd_cpu_addr = NULL;
+               }
+               cur = cur->next;
+       }
+}
+
+static int wcn36xx_dxe_enable_ch_int(struct wcn36xx *wcn, u16 wcn_ch)
+{
+       int reg_data = 0;
+
+       wcn36xx_dxe_read_register(wcn,
+                                 WCN36XX_DXE_INT_MASK_REG,
+                                 &reg_data);
+
+       reg_data |= wcn_ch;
+
+       wcn36xx_dxe_write_register(wcn,
+                                  WCN36XX_DXE_INT_MASK_REG,
+                                  (int)reg_data);
+       return 0;
+}
+
+static int wcn36xx_dxe_fill_skb(struct wcn36xx_dxe_ctl *ctl)
+{
+       struct wcn36xx_dxe_desc *dxe = ctl->desc;
+       struct sk_buff *skb;
+
+       skb = alloc_skb(WCN36XX_PKT_SIZE, GFP_ATOMIC);
+       if (skb == NULL)
+               return -ENOMEM;
+
+       dxe->dst_addr_l = dma_map_single(NULL,
+                                        skb_tail_pointer(skb),
+                                        WCN36XX_PKT_SIZE,
+                                        DMA_FROM_DEVICE);
+       ctl->skb = skb;
+
+       return 0;
+}
+
+static int wcn36xx_dxe_ch_alloc_skb(struct wcn36xx *wcn,
+                                   struct wcn36xx_dxe_ch *wcn_ch)
+{
+       int i;
+       struct wcn36xx_dxe_ctl *cur_ctl = NULL;
+
+       cur_ctl = wcn_ch->head_blk_ctl;
+
+       for (i = 0; i < wcn_ch->desc_num; i++) {
+               wcn36xx_dxe_fill_skb(cur_ctl);
+               cur_ctl = cur_ctl->next;
+       }
+
+       return 0;
+}
+
+static void wcn36xx_dxe_ch_free_skbs(struct wcn36xx *wcn,
+                                    struct wcn36xx_dxe_ch *wcn_ch)
+{
+       struct wcn36xx_dxe_ctl *cur = wcn_ch->head_blk_ctl;
+       int i;
+
+       for (i = 0; i < wcn_ch->desc_num; i++) {
+               kfree_skb(cur->skb);
+               cur = cur->next;
+       }
+}
+
+void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status)
+{
+       struct ieee80211_tx_info *info;
+       struct sk_buff *skb;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wcn->dxe_lock, flags);
+       skb = wcn->tx_ack_skb;
+       wcn->tx_ack_skb = NULL;
+       spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+
+       if (!skb) {
+               wcn36xx_warn("Spurious TX complete indication\n");
+               return;
+       }
+
+       info = IEEE80211_SKB_CB(skb);
+
+       if (status == 1)
+               info->flags |= IEEE80211_TX_STAT_ACK;
+
+       wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ack status: %d\n", status);
+
+       ieee80211_tx_status_irqsafe(wcn->hw, skb);
+       ieee80211_wake_queues(wcn->hw);
+}
+
+static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
+{
+       struct wcn36xx_dxe_ctl *ctl = ch->tail_blk_ctl;
+       struct ieee80211_tx_info *info;
+       unsigned long flags;
+
+       /*
+        * Make at least one loop of do-while because in case ring is
+        * completely full head and tail are pointing to the same element
+        * and while-do will not make any cycles.
+        */
+       do {
+               if (ctl->skb) {
+                       dma_unmap_single(NULL, ctl->desc->src_addr_l,
+                                        ctl->skb->len, DMA_TO_DEVICE);
+                       info = IEEE80211_SKB_CB(ctl->skb);
+                       if (!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) {
+                               /* Keep frame until TX status comes */
+                               ieee80211_free_txskb(wcn->hw, ctl->skb);
+                       }
+                       spin_lock_irqsave(&ctl->skb_lock, flags);
+                       if (wcn->queues_stopped) {
+                               wcn->queues_stopped = false;
+                               ieee80211_wake_queues(wcn->hw);
+                       }
+                       spin_unlock_irqrestore(&ctl->skb_lock, flags);
+
+                       ctl->skb = NULL;
+               }
+               ctl = ctl->next;
+       } while (ctl != ch->head_blk_ctl &&
+              !(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK));
+
+       ch->tail_blk_ctl = ctl;
+}
+
+static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
+{
+       struct wcn36xx *wcn = (struct wcn36xx *)dev;
+       int int_src, int_reason;
+
+       wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src);
+
+       if (int_src & WCN36XX_INT_MASK_CHAN_TX_H) {
+               wcn36xx_dxe_read_register(wcn,
+                                         WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H,
+                                         &int_reason);
+
+               /* TODO: Check int_reason */
+
+               wcn36xx_dxe_write_register(wcn,
+                                          WCN36XX_DXE_0_INT_CLR,
+                                          WCN36XX_INT_MASK_CHAN_TX_H);
+
+               wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
+                                          WCN36XX_INT_MASK_CHAN_TX_H);
+               wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n");
+               reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
+       }
+
+       if (int_src & WCN36XX_INT_MASK_CHAN_TX_L) {
+               wcn36xx_dxe_read_register(wcn,
+                                         WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L,
+                                         &int_reason);
+               /* TODO: Check int_reason */
+
+               wcn36xx_dxe_write_register(wcn,
+                                          WCN36XX_DXE_0_INT_CLR,
+                                          WCN36XX_INT_MASK_CHAN_TX_L);
+
+               wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
+                                          WCN36XX_INT_MASK_CHAN_TX_L);
+               wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n");
+               reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t wcn36xx_irq_rx_ready(int irq, void *dev)
+{
+       struct wcn36xx *wcn = (struct wcn36xx *)dev;
+
+       disable_irq_nosync(wcn->rx_irq);
+       wcn36xx_dxe_rx_frame(wcn);
+       enable_irq(wcn->rx_irq);
+       return IRQ_HANDLED;
+}
+
+static int wcn36xx_dxe_request_irqs(struct wcn36xx *wcn)
+{
+       int ret;
+
+       ret = request_irq(wcn->tx_irq, wcn36xx_irq_tx_complete,
+                         IRQF_TRIGGER_HIGH, "wcn36xx_tx", wcn);
+       if (ret) {
+               wcn36xx_err("failed to alloc tx irq\n");
+               goto out_err;
+       }
+
+       ret = request_irq(wcn->rx_irq, wcn36xx_irq_rx_ready, IRQF_TRIGGER_HIGH,
+                         "wcn36xx_rx", wcn);
+       if (ret) {
+               wcn36xx_err("failed to alloc rx irq\n");
+               goto out_txirq;
+       }
+
+       enable_irq_wake(wcn->rx_irq);
+
+       return 0;
+
+out_txirq:
+       free_irq(wcn->tx_irq, wcn);
+out_err:
+       return ret;
+
+}
+
+static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
+                                    struct wcn36xx_dxe_ch *ch)
+{
+       struct wcn36xx_dxe_ctl *ctl = ch->head_blk_ctl;
+       struct wcn36xx_dxe_desc *dxe = ctl->desc;
+       dma_addr_t  dma_addr;
+       struct sk_buff *skb;
+
+       while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
+               skb = ctl->skb;
+               dma_addr = dxe->dst_addr_l;
+               wcn36xx_dxe_fill_skb(ctl);
+
+               switch (ch->ch_type) {
+               case WCN36XX_DXE_CH_RX_L:
+                       dxe->ctrl = WCN36XX_DXE_CTRL_RX_L;
+                       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR,
+                                                  WCN36XX_DXE_INT_CH1_MASK);
+                       break;
+               case WCN36XX_DXE_CH_RX_H:
+                       dxe->ctrl = WCN36XX_DXE_CTRL_RX_H;
+                       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_ENCH_ADDR,
+                                                  WCN36XX_DXE_INT_CH3_MASK);
+                       break;
+               default:
+                       wcn36xx_warn("Unknown channel\n");
+               }
+
+               dma_unmap_single(NULL, dma_addr, WCN36XX_PKT_SIZE,
+                                DMA_FROM_DEVICE);
+               wcn36xx_rx_skb(wcn, skb);
+               ctl = ctl->next;
+               dxe = ctl->desc;
+       }
+
+       ch->head_blk_ctl = ctl;
+
+       return 0;
+}
+
+void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn)
+{
+       int int_src;
+
+       wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_INT_SRC_RAW_REG, &int_src);
+
+       /* RX_LOW_PRI */
+       if (int_src & WCN36XX_DXE_INT_CH1_MASK) {
+               wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR,
+                                          WCN36XX_DXE_INT_CH1_MASK);
+               wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_l_ch));
+       }
+
+       /* RX_HIGH_PRI */
+       if (int_src & WCN36XX_DXE_INT_CH3_MASK) {
+               /* Clean up all the INT within this channel */
+               wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR,
+                                          WCN36XX_DXE_INT_CH3_MASK);
+               wcn36xx_rx_handle_packets(wcn, &(wcn->dxe_rx_h_ch));
+       }
+
+       if (!int_src)
+               wcn36xx_warn("No DXE interrupt pending\n");
+}
+
+int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn)
+{
+       size_t s;
+       void *cpu_addr;
+
+       /* Allocate BD headers for MGMT frames */
+
+       /* Where this come from ask QC */
+       wcn->mgmt_mem_pool.chunk_size = WCN36XX_BD_CHUNK_SIZE +
+               16 - (WCN36XX_BD_CHUNK_SIZE % 8);
+
+       s = wcn->mgmt_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_H;
+       cpu_addr = dma_alloc_coherent(NULL, s, &wcn->mgmt_mem_pool.phy_addr,
+                                     GFP_KERNEL);
+       if (!cpu_addr)
+               goto out_err;
+
+       wcn->mgmt_mem_pool.virt_addr = cpu_addr;
+       memset(cpu_addr, 0, s);
+
+       /* Allocate BD headers for DATA frames */
+
+       /* Where this come from ask QC */
+       wcn->data_mem_pool.chunk_size = WCN36XX_BD_CHUNK_SIZE +
+               16 - (WCN36XX_BD_CHUNK_SIZE % 8);
+
+       s = wcn->data_mem_pool.chunk_size * WCN36XX_DXE_CH_DESC_NUMB_TX_L;
+       cpu_addr = dma_alloc_coherent(NULL, s, &wcn->data_mem_pool.phy_addr,
+                                     GFP_KERNEL);
+       if (!cpu_addr)
+               goto out_err;
+
+       wcn->data_mem_pool.virt_addr = cpu_addr;
+       memset(cpu_addr, 0, s);
+
+       return 0;
+
+out_err:
+       wcn36xx_dxe_free_mem_pools(wcn);
+       wcn36xx_err("Failed to allocate BD mempool\n");
+       return -ENOMEM;
+}
+
+void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn)
+{
+       if (wcn->mgmt_mem_pool.virt_addr)
+               dma_free_coherent(NULL, wcn->mgmt_mem_pool.chunk_size *
+                                 WCN36XX_DXE_CH_DESC_NUMB_TX_H,
+                                 wcn->mgmt_mem_pool.virt_addr,
+                                 wcn->mgmt_mem_pool.phy_addr);
+
+       if (wcn->data_mem_pool.virt_addr) {
+               dma_free_coherent(NULL, wcn->data_mem_pool.chunk_size *
+                                 WCN36XX_DXE_CH_DESC_NUMB_TX_L,
+                                 wcn->data_mem_pool.virt_addr,
+                                 wcn->data_mem_pool.phy_addr);
+       }
+}
+
+int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
+                        struct wcn36xx_vif *vif_priv,
+                        struct sk_buff *skb,
+                        bool is_low)
+{
+       struct wcn36xx_dxe_ctl *ctl = NULL;
+       struct wcn36xx_dxe_desc *desc = NULL;
+       struct wcn36xx_dxe_ch *ch = NULL;
+       unsigned long flags;
+
+       ch = is_low ? &wcn->dxe_tx_l_ch : &wcn->dxe_tx_h_ch;
+
+       ctl = ch->head_blk_ctl;
+
+       spin_lock_irqsave(&ctl->next->skb_lock, flags);
+
+       /*
+        * If skb is not null that means that we reached the tail of the ring
+        * hence ring is full. Stop queues to let mac80211 back off until ring
+        * has an empty slot again.
+        */
+       if (NULL != ctl->next->skb) {
+               ieee80211_stop_queues(wcn->hw);
+               wcn->queues_stopped = true;
+               spin_unlock_irqrestore(&ctl->next->skb_lock, flags);
+               return -EBUSY;
+       }
+       spin_unlock_irqrestore(&ctl->next->skb_lock, flags);
+
+       ctl->skb = NULL;
+       desc = ctl->desc;
+
+       /* Set source address of the BD we send */
+       desc->src_addr_l = ctl->bd_phy_addr;
+
+       desc->dst_addr_l = ch->dxe_wq;
+       desc->fr_len = sizeof(struct wcn36xx_tx_bd);
+       desc->ctrl = ch->ctrl_bd;
+
+       wcn36xx_dbg(WCN36XX_DBG_DXE, "DXE TX\n");
+
+       wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC1 >>> ",
+                        (char *)desc, sizeof(*desc));
+       wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP,
+                        "BD   >>> ", (char *)ctl->bd_cpu_addr,
+                        sizeof(struct wcn36xx_tx_bd));
+
+       /* Set source address of the SKB we send */
+       ctl = ctl->next;
+       ctl->skb = skb;
+       desc = ctl->desc;
+       if (ctl->bd_cpu_addr) {
+               wcn36xx_err("bd_cpu_addr cannot be NULL for skb DXE\n");
+               return -EINVAL;
+       }
+
+       desc->src_addr_l = dma_map_single(NULL,
+                                         ctl->skb->data,
+                                         ctl->skb->len,
+                                         DMA_TO_DEVICE);
+
+       desc->dst_addr_l = ch->dxe_wq;
+       desc->fr_len = ctl->skb->len;
+
+       /* set dxe descriptor to VALID */
+       desc->ctrl = ch->ctrl_skb;
+
+       wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "DESC2 >>> ",
+                        (char *)desc, sizeof(*desc));
+       wcn36xx_dbg_dump(WCN36XX_DBG_DXE_DUMP, "SKB   >>> ",
+                        (char *)ctl->skb->data, ctl->skb->len);
+
+       /* Move the head of the ring to the next empty descriptor */
+        ch->head_blk_ctl = ctl->next;
+
+       /*
+        * When connected and trying to send data frame chip can be in sleep
+        * mode and writing to the register will not wake up the chip. Instead
+        * notify chip about new frame through SMSM bus.
+        */
+       if (is_low &&  vif_priv->pw_state == WCN36XX_BMPS) {
+               wcn->ctrl_ops->smsm_change_state(
+                                 0,
+                                 WCN36XX_SMSM_WLAN_TX_ENABLE);
+       } else {
+               /* indicate End Of Packet and generate interrupt on descriptor
+                * done.
+                */
+               wcn36xx_dxe_write_register(wcn,
+                       ch->reg_ctrl, ch->def_ctrl);
+       }
+
+       return 0;
+}
+
+int wcn36xx_dxe_init(struct wcn36xx *wcn)
+{
+       int reg_data = 0, ret;
+
+       reg_data = WCN36XX_DXE_REG_RESET;
+       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CSR_RESET, reg_data);
+
+       /* Setting interrupt path */
+       reg_data = WCN36XX_DXE_CCU_INT;
+       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_REG_CCU_INT, reg_data);
+
+       /***************************************/
+       /* Init descriptors for TX LOW channel */
+       /***************************************/
+       wcn36xx_dxe_init_descs(&wcn->dxe_tx_l_ch);
+       wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_l_ch, &wcn->data_mem_pool);
+
+       /* Write channel head to a NEXT register */
+       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_L,
+               wcn->dxe_tx_l_ch.head_blk_ctl->desc_phy_addr);
+
+       /* Program DMA destination addr for TX LOW */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_CH_DEST_ADDR_TX_L,
+               WCN36XX_DXE_WQ_TX_L);
+
+       wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, &reg_data);
+       wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_L);
+
+       /***************************************/
+       /* Init descriptors for TX HIGH channel */
+       /***************************************/
+       wcn36xx_dxe_init_descs(&wcn->dxe_tx_h_ch);
+       wcn36xx_dxe_init_tx_bd(&wcn->dxe_tx_h_ch, &wcn->mgmt_mem_pool);
+
+       /* Write channel head to a NEXT register */
+       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_H,
+               wcn->dxe_tx_h_ch.head_blk_ctl->desc_phy_addr);
+
+       /* Program DMA destination addr for TX HIGH */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_CH_DEST_ADDR_TX_H,
+               WCN36XX_DXE_WQ_TX_H);
+
+       wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_REG_CH_EN, &reg_data);
+
+       /* Enable channel interrupts */
+       wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_TX_H);
+
+       /***************************************/
+       /* Init descriptors for RX LOW channel */
+       /***************************************/
+       wcn36xx_dxe_init_descs(&wcn->dxe_rx_l_ch);
+
+       /* For RX we need to preallocated buffers */
+       wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_l_ch);
+
+       /* Write channel head to a NEXT register */
+       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_L,
+               wcn->dxe_rx_l_ch.head_blk_ctl->desc_phy_addr);
+
+       /* Write DMA source address */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_CH_SRC_ADDR_RX_L,
+               WCN36XX_DXE_WQ_RX_L);
+
+       /* Program preallocated destination address */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_CH_DEST_ADDR_RX_L,
+               wcn->dxe_rx_l_ch.head_blk_ctl->desc->phy_next_l);
+
+       /* Enable default control registers */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_REG_CTL_RX_L,
+               WCN36XX_DXE_CH_DEFAULT_CTL_RX_L);
+
+       /* Enable channel interrupts */
+       wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_L);
+
+       /***************************************/
+       /* Init descriptors for RX HIGH channel */
+       /***************************************/
+       wcn36xx_dxe_init_descs(&wcn->dxe_rx_h_ch);
+
+       /* For RX we need to prealocat buffers */
+       wcn36xx_dxe_ch_alloc_skb(wcn, &wcn->dxe_rx_h_ch);
+
+       /* Write chanel head to a NEXT register */
+       wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_H,
+               wcn->dxe_rx_h_ch.head_blk_ctl->desc_phy_addr);
+
+       /* Write DMA source address */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_CH_SRC_ADDR_RX_H,
+               WCN36XX_DXE_WQ_RX_H);
+
+       /* Program preallocated destination address */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_CH_DEST_ADDR_RX_H,
+                wcn->dxe_rx_h_ch.head_blk_ctl->desc->phy_next_l);
+
+       /* Enable default control registers */
+       wcn36xx_dxe_write_register(wcn,
+               WCN36XX_DXE_REG_CTL_RX_H,
+               WCN36XX_DXE_CH_DEFAULT_CTL_RX_H);
+
+       /* Enable channel interrupts */
+       wcn36xx_dxe_enable_ch_int(wcn, WCN36XX_INT_MASK_CHAN_RX_H);
+
+       ret = wcn36xx_dxe_request_irqs(wcn);
+       if (ret < 0)
+               goto out_err;
+
+       return 0;
+
+out_err:
+       return ret;
+}
+
+void wcn36xx_dxe_deinit(struct wcn36xx *wcn)
+{
+       free_irq(wcn->tx_irq, wcn);
+       free_irq(wcn->rx_irq, wcn);
+
+       if (wcn->tx_ack_skb) {
+               ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb);
+               wcn->tx_ack_skb = NULL;
+       }
+
+       wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_l_ch);
+       wcn36xx_dxe_ch_free_skbs(wcn, &wcn->dxe_rx_h_ch);
+}
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h
new file mode 100644 (file)
index 0000000..c88562f
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DXE_H_
+#define _DXE_H_
+
+#include "wcn36xx.h"
+
+/*
+TX_LOW = DMA0
+TX_HIGH        = DMA4
+RX_LOW = DMA1
+RX_HIGH        = DMA3
+H2H_TEST_RX_TX = DMA2
+*/
+
+/* DXE registers */
+#define WCN36XX_DXE_MEM_BASE                   0x03000000
+#define WCN36XX_DXE_MEM_REG                    0x202000
+
+#define WCN36XX_DXE_CCU_INT                    0xA0011
+#define WCN36XX_DXE_REG_CCU_INT                        0x200b10
+
+/* TODO This must calculated properly but not hardcoded */
+#define WCN36XX_DXE_CTRL_TX_L                  0x328a44
+#define WCN36XX_DXE_CTRL_TX_H                  0x32ce44
+#define WCN36XX_DXE_CTRL_RX_L                  0x12ad2f
+#define WCN36XX_DXE_CTRL_RX_H                  0x12d12f
+#define WCN36XX_DXE_CTRL_TX_H_BD               0x30ce45
+#define WCN36XX_DXE_CTRL_TX_H_SKB              0x32ce4d
+#define WCN36XX_DXE_CTRL_TX_L_BD               0x308a45
+#define WCN36XX_DXE_CTRL_TX_L_SKB              0x328a4d
+
+/* TODO This must calculated properly but not hardcoded */
+#define WCN36XX_DXE_WQ_TX_L                    0x17
+#define WCN36XX_DXE_WQ_TX_H                    0x17
+#define WCN36XX_DXE_WQ_RX_L                    0xB
+#define WCN36XX_DXE_WQ_RX_H                    0x4
+
+/* DXE descriptor control filed */
+#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001)
+
+/* TODO This must calculated properly but not hardcoded */
+/* DXE default control register values */
+#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L                0x847EAD2F
+#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H                0x84FED12F
+#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H                0x853ECF4D
+#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L                0x843e8b4d
+
+/* Common DXE registers */
+#define WCN36XX_DXE_MEM_CSR                    (WCN36XX_DXE_MEM_REG + 0x00)
+#define WCN36XX_DXE_REG_CSR_RESET              (WCN36XX_DXE_MEM_REG + 0x00)
+#define WCN36XX_DXE_ENCH_ADDR                  (WCN36XX_DXE_MEM_REG + 0x04)
+#define WCN36XX_DXE_REG_CH_EN                  (WCN36XX_DXE_MEM_REG + 0x08)
+#define WCN36XX_DXE_REG_CH_DONE                        (WCN36XX_DXE_MEM_REG + 0x0C)
+#define WCN36XX_DXE_REG_CH_ERR                 (WCN36XX_DXE_MEM_REG + 0x10)
+#define WCN36XX_DXE_INT_MASK_REG               (WCN36XX_DXE_MEM_REG + 0x18)
+#define WCN36XX_DXE_INT_SRC_RAW_REG            (WCN36XX_DXE_MEM_REG + 0x20)
+       /* #define WCN36XX_DXE_INT_CH6_MASK     0x00000040 */
+       /* #define WCN36XX_DXE_INT_CH5_MASK     0x00000020 */
+       #define WCN36XX_DXE_INT_CH4_MASK        0x00000010
+       #define WCN36XX_DXE_INT_CH3_MASK        0x00000008
+       /* #define WCN36XX_DXE_INT_CH2_MASK     0x00000004 */
+       #define WCN36XX_DXE_INT_CH1_MASK        0x00000002
+       #define WCN36XX_DXE_INT_CH0_MASK        0x00000001
+#define WCN36XX_DXE_0_INT_CLR                  (WCN36XX_DXE_MEM_REG + 0x30)
+#define WCN36XX_DXE_0_INT_ED_CLR               (WCN36XX_DXE_MEM_REG + 0x34)
+#define WCN36XX_DXE_0_INT_DONE_CLR             (WCN36XX_DXE_MEM_REG + 0x38)
+#define WCN36XX_DXE_0_INT_ERR_CLR              (WCN36XX_DXE_MEM_REG + 0x3C)
+
+#define WCN36XX_DXE_0_CH0_STATUS               (WCN36XX_DXE_MEM_REG + 0x404)
+#define WCN36XX_DXE_0_CH1_STATUS               (WCN36XX_DXE_MEM_REG + 0x444)
+#define WCN36XX_DXE_0_CH2_STATUS               (WCN36XX_DXE_MEM_REG + 0x484)
+#define WCN36XX_DXE_0_CH3_STATUS               (WCN36XX_DXE_MEM_REG + 0x4C4)
+#define WCN36XX_DXE_0_CH4_STATUS               (WCN36XX_DXE_MEM_REG + 0x504)
+
+#define WCN36XX_DXE_REG_RESET                  0x5c89
+
+/* Temporary BMU Workqueue 4 */
+#define WCN36XX_DXE_BMU_WQ_RX_LOW              0xB
+#define WCN36XX_DXE_BMU_WQ_RX_HIGH             0x4
+/* DMA channel offset */
+#define WCN36XX_DXE_TX_LOW_OFFSET              0x400
+#define WCN36XX_DXE_TX_HIGH_OFFSET             0x500
+#define WCN36XX_DXE_RX_LOW_OFFSET              0x440
+#define WCN36XX_DXE_RX_HIGH_OFFSET             0x4C0
+
+/* Address of the next DXE descriptor */
+#define WCN36XX_DXE_CH_NEXT_DESC_ADDR          0x001C
+#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_L     (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_NEXT_DESC_ADDR)
+#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_TX_H     (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_NEXT_DESC_ADDR)
+#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_L     (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_NEXT_DESC_ADDR)
+#define WCN36XX_DXE_CH_NEXT_DESC_ADDR_RX_H     (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_NEXT_DESC_ADDR)
+
+/* DXE Descriptor source address */
+#define WCN36XX_DXE_CH_SRC_ADDR                        0x000C
+#define WCN36XX_DXE_CH_SRC_ADDR_RX_L           (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_SRC_ADDR)
+#define WCN36XX_DXE_CH_SRC_ADDR_RX_H           (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_SRC_ADDR)
+
+/* DXE Descriptor address destination address */
+#define WCN36XX_DXE_CH_DEST_ADDR               0x0014
+#define WCN36XX_DXE_CH_DEST_ADDR_TX_L          (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_DEST_ADDR)
+#define WCN36XX_DXE_CH_DEST_ADDR_TX_H          (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_DEST_ADDR)
+#define WCN36XX_DXE_CH_DEST_ADDR_RX_L          (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_DEST_ADDR)
+#define WCN36XX_DXE_CH_DEST_ADDR_RX_H          (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_DEST_ADDR)
+
+/* Interrupt status */
+#define WCN36XX_DXE_CH_STATUS_REG_ADDR         0x0004
+#define WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L    (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_STATUS_REG_ADDR)
+#define WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H    (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_STATUS_REG_ADDR)
+#define WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_L    (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_LOW_OFFSET + \
+                                                WCN36XX_DXE_CH_STATUS_REG_ADDR)
+#define WCN36XX_DXE_CH_STATUS_REG_ADDR_RX_H    (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_HIGH_OFFSET + \
+                                                WCN36XX_DXE_CH_STATUS_REG_ADDR)
+
+
+/* DXE default control register */
+#define WCN36XX_DXE_REG_CTL_RX_L               (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_LOW_OFFSET)
+#define WCN36XX_DXE_REG_CTL_RX_H               (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_RX_HIGH_OFFSET)
+#define WCN36XX_DXE_REG_CTL_TX_H               (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_HIGH_OFFSET)
+#define WCN36XX_DXE_REG_CTL_TX_L               (WCN36XX_DXE_MEM_REG + \
+                                                WCN36XX_DXE_TX_LOW_OFFSET)
+
+#define WCN36XX_SMSM_WLAN_TX_ENABLE            0x00000400
+#define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY       0x00000200
+
+
+/* Interrupt control channel mask */
+#define WCN36XX_INT_MASK_CHAN_TX_L             0x00000001
+#define WCN36XX_INT_MASK_CHAN_RX_L             0x00000002
+#define WCN36XX_INT_MASK_CHAN_RX_H             0x00000008
+#define WCN36XX_INT_MASK_CHAN_TX_H             0x00000010
+
+#define WCN36XX_BD_CHUNK_SIZE                  128
+
+#define WCN36XX_PKT_SIZE                       0xF20
+enum wcn36xx_dxe_ch_type {
+       WCN36XX_DXE_CH_TX_L,
+       WCN36XX_DXE_CH_TX_H,
+       WCN36XX_DXE_CH_RX_L,
+       WCN36XX_DXE_CH_RX_H
+};
+
+/* amount of descriptors per channel */
+enum wcn36xx_dxe_ch_desc_num {
+       WCN36XX_DXE_CH_DESC_NUMB_TX_L           = 128,
+       WCN36XX_DXE_CH_DESC_NUMB_TX_H           = 10,
+       WCN36XX_DXE_CH_DESC_NUMB_RX_L           = 512,
+       WCN36XX_DXE_CH_DESC_NUMB_RX_H           = 40
+};
+
+/**
+ * struct wcn36xx_dxe_desc - describes descriptor of one DXE buffer
+ *
+ * @ctrl: is a union that consists of following bits:
+ * union {
+ *     u32     valid           :1; //0 = DMA stop, 1 = DMA continue with this
+ *                                 //descriptor
+ *     u32     transfer_type   :2; //0 = Host to Host space
+ *     u32     eop             :1; //End of Packet
+ *     u32     bd_handling     :1; //if transferType = Host to BMU, then 0
+ *                                 // means first 128 bytes contain BD, and 1
+ *                                 // means create new empty BD
+ *     u32     siq             :1; // SIQ
+ *     u32     diq             :1; // DIQ
+ *     u32     pdu_rel         :1; //0 = don't release BD and PDUs when done,
+ *                                 // 1 = release them
+ *     u32     bthld_sel       :4; //BMU Threshold Select
+ *     u32     prio            :3; //Specifies the priority level to use for
+ *                                 // the transfer
+ *     u32     stop_channel    :1; //1 = DMA stops processing further, channel
+ *                                 //requires re-enabling after this
+ *     u32     intr            :1; //Interrupt on Descriptor Done
+ *     u32     rsvd            :1; //reserved
+ *     u32     size            :14;//14 bits used - ignored for BMU transfers,
+ *                                 //only used for host to host transfers?
+ * } ctrl;
+ */
+struct wcn36xx_dxe_desc {
+       u32     ctrl;
+       u32     fr_len;
+
+       u32     src_addr_l;
+       u32     dst_addr_l;
+       u32     phy_next_l;
+       u32     src_addr_h;
+       u32     dst_addr_h;
+       u32     phy_next_h;
+} __packed;
+
+/* DXE Control block */
+struct wcn36xx_dxe_ctl {
+       struct wcn36xx_dxe_ctl  *next;
+       struct wcn36xx_dxe_desc *desc;
+       unsigned int            desc_phy_addr;
+       int                     ctl_blk_order;
+       struct sk_buff          *skb;
+       spinlock_t              skb_lock;
+       void                    *bd_cpu_addr;
+       dma_addr_t              bd_phy_addr;
+};
+
+struct wcn36xx_dxe_ch {
+       enum wcn36xx_dxe_ch_type        ch_type;
+       void                            *cpu_addr;
+       dma_addr_t                      dma_addr;
+       enum wcn36xx_dxe_ch_desc_num    desc_num;
+       /* DXE control block ring */
+       struct wcn36xx_dxe_ctl          *head_blk_ctl;
+       struct wcn36xx_dxe_ctl          *tail_blk_ctl;
+
+       /* DXE channel specific configs */
+       u32                             dxe_wq;
+       u32                             ctrl_bd;
+       u32                             ctrl_skb;
+       u32                             reg_ctrl;
+       u32                             def_ctrl;
+};
+
+/* Memory Pool for BD headers */
+struct wcn36xx_dxe_mem_pool {
+       int             chunk_size;
+       void            *virt_addr;
+       dma_addr_t      phy_addr;
+};
+
+struct wcn36xx_vif;
+int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn);
+void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn);
+void wcn36xx_dxe_rx_frame(struct wcn36xx *wcn);
+int wcn36xx_dxe_alloc_ctl_blks(struct wcn36xx *wcn);
+void wcn36xx_dxe_free_ctl_blks(struct wcn36xx *wcn);
+int wcn36xx_dxe_init(struct wcn36xx *wcn);
+void wcn36xx_dxe_deinit(struct wcn36xx *wcn);
+int wcn36xx_dxe_init_channels(struct wcn36xx *wcn);
+int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
+                        struct wcn36xx_vif *vif_priv,
+                        struct sk_buff *skb,
+                        bool is_low);
+void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status);
+void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low);
+#endif /* _DXE_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/hal.h b/drivers/net/wireless/ath/wcn36xx/hal.h
new file mode 100644 (file)
index 0000000..c02dbc6
--- /dev/null
@@ -0,0 +1,4657 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _HAL_H_
+#define _HAL_H_
+
+/*---------------------------------------------------------------------------
+  API VERSIONING INFORMATION
+
+  The RIVA API is versioned as MAJOR.MINOR.VERSION.REVISION
+  The MAJOR is incremented for major product/architecture changes
+      (and then MINOR/VERSION/REVISION are zeroed)
+  The MINOR is incremented for minor product/architecture changes
+      (and then VERSION/REVISION are zeroed)
+  The VERSION is incremented if a significant API change occurs
+      (and then REVISION is zeroed)
+  The REVISION is incremented if an insignificant API change occurs
+      or if a new API is added
+  All values are in the range 0..255 (ie they are 8-bit values)
+ ---------------------------------------------------------------------------*/
+#define WCN36XX_HAL_VER_MAJOR 1
+#define WCN36XX_HAL_VER_MINOR 4
+#define WCN36XX_HAL_VER_VERSION 1
+#define WCN36XX_HAL_VER_REVISION 2
+
+/* This is to force compiler to use the maximum of an int ( 4 bytes ) */
+#define WCN36XX_HAL_MAX_ENUM_SIZE    0x7FFFFFFF
+#define WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE    0x7FFF
+
+/* Max no. of transmit categories */
+#define STACFG_MAX_TC    8
+
+/* The maximum value of access category */
+#define WCN36XX_HAL_MAX_AC  4
+
+#define WCN36XX_HAL_IPV4_ADDR_LEN       4
+
+#define WALN_HAL_STA_INVALID_IDX 0xFF
+#define WCN36XX_HAL_BSS_INVALID_IDX 0xFF
+
+/* Default Beacon template size */
+#define BEACON_TEMPLATE_SIZE 0x180
+
+/* Param Change Bitmap sent to HAL */
+#define PARAM_BCN_INTERVAL_CHANGED                      (1 << 0)
+#define PARAM_SHORT_PREAMBLE_CHANGED                 (1 << 1)
+#define PARAM_SHORT_SLOT_TIME_CHANGED                 (1 << 2)
+#define PARAM_llACOEXIST_CHANGED                            (1 << 3)
+#define PARAM_llBCOEXIST_CHANGED                            (1 << 4)
+#define PARAM_llGCOEXIST_CHANGED                            (1 << 5)
+#define PARAM_HT20MHZCOEXIST_CHANGED                  (1<<6)
+#define PARAM_NON_GF_DEVICES_PRESENT_CHANGED (1<<7)
+#define PARAM_RIFS_MODE_CHANGED                            (1<<8)
+#define PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED   (1<<9)
+#define PARAM_OBSS_MODE_CHANGED                               (1<<10)
+#define PARAM_BEACON_UPDATE_MASK \
+       (PARAM_BCN_INTERVAL_CHANGED |                                   \
+        PARAM_SHORT_PREAMBLE_CHANGED |                                 \
+        PARAM_SHORT_SLOT_TIME_CHANGED |                                \
+        PARAM_llACOEXIST_CHANGED |                                     \
+        PARAM_llBCOEXIST_CHANGED |                                     \
+        PARAM_llGCOEXIST_CHANGED |                                     \
+        PARAM_HT20MHZCOEXIST_CHANGED |                                 \
+        PARAM_NON_GF_DEVICES_PRESENT_CHANGED |                         \
+        PARAM_RIFS_MODE_CHANGED |                                      \
+        PARAM_LSIG_TXOP_FULL_SUPPORT_CHANGED |                         \
+        PARAM_OBSS_MODE_CHANGED)
+
+/* dump command response Buffer size */
+#define DUMPCMD_RSP_BUFFER 100
+
+/* version string max length (including NULL) */
+#define WCN36XX_HAL_VERSION_LENGTH  64
+
+/* message types for messages exchanged between WDI and HAL */
+enum wcn36xx_hal_host_msg_type {
+       /* Init/De-Init */
+       WCN36XX_HAL_START_REQ = 0,
+       WCN36XX_HAL_START_RSP = 1,
+       WCN36XX_HAL_STOP_REQ = 2,
+       WCN36XX_HAL_STOP_RSP = 3,
+
+       /* Scan */
+       WCN36XX_HAL_INIT_SCAN_REQ = 4,
+       WCN36XX_HAL_INIT_SCAN_RSP = 5,
+       WCN36XX_HAL_START_SCAN_REQ = 6,
+       WCN36XX_HAL_START_SCAN_RSP = 7,
+       WCN36XX_HAL_END_SCAN_REQ = 8,
+       WCN36XX_HAL_END_SCAN_RSP = 9,
+       WCN36XX_HAL_FINISH_SCAN_REQ = 10,
+       WCN36XX_HAL_FINISH_SCAN_RSP = 11,
+
+       /* HW STA configuration/deconfiguration */
+       WCN36XX_HAL_CONFIG_STA_REQ = 12,
+       WCN36XX_HAL_CONFIG_STA_RSP = 13,
+       WCN36XX_HAL_DELETE_STA_REQ = 14,
+       WCN36XX_HAL_DELETE_STA_RSP = 15,
+       WCN36XX_HAL_CONFIG_BSS_REQ = 16,
+       WCN36XX_HAL_CONFIG_BSS_RSP = 17,
+       WCN36XX_HAL_DELETE_BSS_REQ = 18,
+       WCN36XX_HAL_DELETE_BSS_RSP = 19,
+
+       /* Infra STA asscoiation */
+       WCN36XX_HAL_JOIN_REQ = 20,
+       WCN36XX_HAL_JOIN_RSP = 21,
+       WCN36XX_HAL_POST_ASSOC_REQ = 22,
+       WCN36XX_HAL_POST_ASSOC_RSP = 23,
+
+       /* Security */
+       WCN36XX_HAL_SET_BSSKEY_REQ = 24,
+       WCN36XX_HAL_SET_BSSKEY_RSP = 25,
+       WCN36XX_HAL_SET_STAKEY_REQ = 26,
+       WCN36XX_HAL_SET_STAKEY_RSP = 27,
+       WCN36XX_HAL_RMV_BSSKEY_REQ = 28,
+       WCN36XX_HAL_RMV_BSSKEY_RSP = 29,
+       WCN36XX_HAL_RMV_STAKEY_REQ = 30,
+       WCN36XX_HAL_RMV_STAKEY_RSP = 31,
+
+       /* Qos Related */
+       WCN36XX_HAL_ADD_TS_REQ = 32,
+       WCN36XX_HAL_ADD_TS_RSP = 33,
+       WCN36XX_HAL_DEL_TS_REQ = 34,
+       WCN36XX_HAL_DEL_TS_RSP = 35,
+       WCN36XX_HAL_UPD_EDCA_PARAMS_REQ = 36,
+       WCN36XX_HAL_UPD_EDCA_PARAMS_RSP = 37,
+       WCN36XX_HAL_ADD_BA_REQ = 38,
+       WCN36XX_HAL_ADD_BA_RSP = 39,
+       WCN36XX_HAL_DEL_BA_REQ = 40,
+       WCN36XX_HAL_DEL_BA_RSP = 41,
+
+       WCN36XX_HAL_CH_SWITCH_REQ = 42,
+       WCN36XX_HAL_CH_SWITCH_RSP = 43,
+       WCN36XX_HAL_SET_LINK_ST_REQ = 44,
+       WCN36XX_HAL_SET_LINK_ST_RSP = 45,
+       WCN36XX_HAL_GET_STATS_REQ = 46,
+       WCN36XX_HAL_GET_STATS_RSP = 47,
+       WCN36XX_HAL_UPDATE_CFG_REQ = 48,
+       WCN36XX_HAL_UPDATE_CFG_RSP = 49,
+
+       WCN36XX_HAL_MISSED_BEACON_IND = 50,
+       WCN36XX_HAL_UNKNOWN_ADDR2_FRAME_RX_IND = 51,
+       WCN36XX_HAL_MIC_FAILURE_IND = 52,
+       WCN36XX_HAL_FATAL_ERROR_IND = 53,
+       WCN36XX_HAL_SET_KEYDONE_MSG = 54,
+
+       /* NV Interface */
+       WCN36XX_HAL_DOWNLOAD_NV_REQ = 55,
+       WCN36XX_HAL_DOWNLOAD_NV_RSP = 56,
+
+       WCN36XX_HAL_ADD_BA_SESSION_REQ = 57,
+       WCN36XX_HAL_ADD_BA_SESSION_RSP = 58,
+       WCN36XX_HAL_TRIGGER_BA_REQ = 59,
+       WCN36XX_HAL_TRIGGER_BA_RSP = 60,
+       WCN36XX_HAL_UPDATE_BEACON_REQ = 61,
+       WCN36XX_HAL_UPDATE_BEACON_RSP = 62,
+       WCN36XX_HAL_SEND_BEACON_REQ = 63,
+       WCN36XX_HAL_SEND_BEACON_RSP = 64,
+
+       WCN36XX_HAL_SET_BCASTKEY_REQ = 65,
+       WCN36XX_HAL_SET_BCASTKEY_RSP = 66,
+       WCN36XX_HAL_DELETE_STA_CONTEXT_IND = 67,
+       WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ = 68,
+       WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP = 69,
+
+       /* PTT interface support */
+       WCN36XX_HAL_PROCESS_PTT_REQ = 70,
+       WCN36XX_HAL_PROCESS_PTT_RSP = 71,
+
+       /* BTAMP related events */
+       WCN36XX_HAL_SIGNAL_BTAMP_EVENT_REQ = 72,
+       WCN36XX_HAL_SIGNAL_BTAMP_EVENT_RSP = 73,
+       WCN36XX_HAL_TL_HAL_FLUSH_AC_REQ = 74,
+       WCN36XX_HAL_TL_HAL_FLUSH_AC_RSP = 75,
+
+       WCN36XX_HAL_ENTER_IMPS_REQ = 76,
+       WCN36XX_HAL_EXIT_IMPS_REQ = 77,
+       WCN36XX_HAL_ENTER_BMPS_REQ = 78,
+       WCN36XX_HAL_EXIT_BMPS_REQ = 79,
+       WCN36XX_HAL_ENTER_UAPSD_REQ = 80,
+       WCN36XX_HAL_EXIT_UAPSD_REQ = 81,
+       WCN36XX_HAL_UPDATE_UAPSD_PARAM_REQ = 82,
+       WCN36XX_HAL_CONFIGURE_RXP_FILTER_REQ = 83,
+       WCN36XX_HAL_ADD_BCN_FILTER_REQ = 84,
+       WCN36XX_HAL_REM_BCN_FILTER_REQ = 85,
+       WCN36XX_HAL_ADD_WOWL_BCAST_PTRN = 86,
+       WCN36XX_HAL_DEL_WOWL_BCAST_PTRN = 87,
+       WCN36XX_HAL_ENTER_WOWL_REQ = 88,
+       WCN36XX_HAL_EXIT_WOWL_REQ = 89,
+       WCN36XX_HAL_HOST_OFFLOAD_REQ = 90,
+       WCN36XX_HAL_SET_RSSI_THRESH_REQ = 91,
+       WCN36XX_HAL_GET_RSSI_REQ = 92,
+       WCN36XX_HAL_SET_UAPSD_AC_PARAMS_REQ = 93,
+       WCN36XX_HAL_CONFIGURE_APPS_CPU_WAKEUP_STATE_REQ = 94,
+
+       WCN36XX_HAL_ENTER_IMPS_RSP = 95,
+       WCN36XX_HAL_EXIT_IMPS_RSP = 96,
+       WCN36XX_HAL_ENTER_BMPS_RSP = 97,
+       WCN36XX_HAL_EXIT_BMPS_RSP = 98,
+       WCN36XX_HAL_ENTER_UAPSD_RSP = 99,
+       WCN36XX_HAL_EXIT_UAPSD_RSP = 100,
+       WCN36XX_HAL_SET_UAPSD_AC_PARAMS_RSP = 101,
+       WCN36XX_HAL_UPDATE_UAPSD_PARAM_RSP = 102,
+       WCN36XX_HAL_CONFIGURE_RXP_FILTER_RSP = 103,
+       WCN36XX_HAL_ADD_BCN_FILTER_RSP = 104,
+       WCN36XX_HAL_REM_BCN_FILTER_RSP = 105,
+       WCN36XX_HAL_SET_RSSI_THRESH_RSP = 106,
+       WCN36XX_HAL_HOST_OFFLOAD_RSP = 107,
+       WCN36XX_HAL_ADD_WOWL_BCAST_PTRN_RSP = 108,
+       WCN36XX_HAL_DEL_WOWL_BCAST_PTRN_RSP = 109,
+       WCN36XX_HAL_ENTER_WOWL_RSP = 110,
+       WCN36XX_HAL_EXIT_WOWL_RSP = 111,
+       WCN36XX_HAL_RSSI_NOTIFICATION_IND = 112,
+       WCN36XX_HAL_GET_RSSI_RSP = 113,
+       WCN36XX_HAL_CONFIGURE_APPS_CPU_WAKEUP_STATE_RSP = 114,
+
+       /* 11k related events */
+       WCN36XX_HAL_SET_MAX_TX_POWER_REQ = 115,
+       WCN36XX_HAL_SET_MAX_TX_POWER_RSP = 116,
+
+       /* 11R related msgs */
+       WCN36XX_HAL_AGGR_ADD_TS_REQ = 117,
+       WCN36XX_HAL_AGGR_ADD_TS_RSP = 118,
+
+       /* P2P  WLAN_FEATURE_P2P */
+       WCN36XX_HAL_SET_P2P_GONOA_REQ = 119,
+       WCN36XX_HAL_SET_P2P_GONOA_RSP = 120,
+
+       /* WLAN Dump commands */
+       WCN36XX_HAL_DUMP_COMMAND_REQ = 121,
+       WCN36XX_HAL_DUMP_COMMAND_RSP = 122,
+
+       /* OEM_DATA FEATURE SUPPORT */
+       WCN36XX_HAL_START_OEM_DATA_REQ = 123,
+       WCN36XX_HAL_START_OEM_DATA_RSP = 124,
+
+       /* ADD SELF STA REQ and RSP */
+       WCN36XX_HAL_ADD_STA_SELF_REQ = 125,
+       WCN36XX_HAL_ADD_STA_SELF_RSP = 126,
+
+       /* DEL SELF STA SUPPORT */
+       WCN36XX_HAL_DEL_STA_SELF_REQ = 127,
+       WCN36XX_HAL_DEL_STA_SELF_RSP = 128,
+
+       /* Coex Indication */
+       WCN36XX_HAL_COEX_IND = 129,
+
+       /* Tx Complete Indication */
+       WCN36XX_HAL_OTA_TX_COMPL_IND = 130,
+
+       /* Host Suspend/resume messages */
+       WCN36XX_HAL_HOST_SUSPEND_IND = 131,
+       WCN36XX_HAL_HOST_RESUME_REQ = 132,
+       WCN36XX_HAL_HOST_RESUME_RSP = 133,
+
+       WCN36XX_HAL_SET_TX_POWER_REQ = 134,
+       WCN36XX_HAL_SET_TX_POWER_RSP = 135,
+       WCN36XX_HAL_GET_TX_POWER_REQ = 136,
+       WCN36XX_HAL_GET_TX_POWER_RSP = 137,
+
+       WCN36XX_HAL_P2P_NOA_ATTR_IND = 138,
+
+       WCN36XX_HAL_ENABLE_RADAR_DETECT_REQ = 139,
+       WCN36XX_HAL_ENABLE_RADAR_DETECT_RSP = 140,
+       WCN36XX_HAL_GET_TPC_REPORT_REQ = 141,
+       WCN36XX_HAL_GET_TPC_REPORT_RSP = 142,
+       WCN36XX_HAL_RADAR_DETECT_IND = 143,
+       WCN36XX_HAL_RADAR_DETECT_INTR_IND = 144,
+       WCN36XX_HAL_KEEP_ALIVE_REQ = 145,
+       WCN36XX_HAL_KEEP_ALIVE_RSP = 146,
+
+       /* PNO messages */
+       WCN36XX_HAL_SET_PREF_NETWORK_REQ = 147,
+       WCN36XX_HAL_SET_PREF_NETWORK_RSP = 148,
+       WCN36XX_HAL_SET_RSSI_FILTER_REQ = 149,
+       WCN36XX_HAL_SET_RSSI_FILTER_RSP = 150,
+       WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ = 151,
+       WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP = 152,
+       WCN36XX_HAL_PREF_NETW_FOUND_IND = 153,
+
+       WCN36XX_HAL_SET_TX_PER_TRACKING_REQ = 154,
+       WCN36XX_HAL_SET_TX_PER_TRACKING_RSP = 155,
+       WCN36XX_HAL_TX_PER_HIT_IND = 156,
+
+       WCN36XX_HAL_8023_MULTICAST_LIST_REQ = 157,
+       WCN36XX_HAL_8023_MULTICAST_LIST_RSP = 158,
+
+       WCN36XX_HAL_SET_PACKET_FILTER_REQ = 159,
+       WCN36XX_HAL_SET_PACKET_FILTER_RSP = 160,
+       WCN36XX_HAL_PACKET_FILTER_MATCH_COUNT_REQ = 161,
+       WCN36XX_HAL_PACKET_FILTER_MATCH_COUNT_RSP = 162,
+       WCN36XX_HAL_CLEAR_PACKET_FILTER_REQ = 163,
+       WCN36XX_HAL_CLEAR_PACKET_FILTER_RSP = 164,
+
+       /*
+        * This is temp fix. Should be removed once Host and Riva code is
+        * in sync.
+        */
+       WCN36XX_HAL_INIT_SCAN_CON_REQ = 165,
+
+       WCN36XX_HAL_SET_POWER_PARAMS_REQ = 166,
+       WCN36XX_HAL_SET_POWER_PARAMS_RSP = 167,
+
+       WCN36XX_HAL_TSM_STATS_REQ = 168,
+       WCN36XX_HAL_TSM_STATS_RSP = 169,
+
+       /* wake reason indication (WOW) */
+       WCN36XX_HAL_WAKE_REASON_IND = 170,
+
+       /* GTK offload support */
+       WCN36XX_HAL_GTK_OFFLOAD_REQ = 171,
+       WCN36XX_HAL_GTK_OFFLOAD_RSP = 172,
+       WCN36XX_HAL_GTK_OFFLOAD_GETINFO_REQ = 173,
+       WCN36XX_HAL_GTK_OFFLOAD_GETINFO_RSP = 174,
+
+       WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ = 175,
+       WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP = 176,
+       WCN36XX_HAL_EXCLUDE_UNENCRYPTED_IND = 177,
+
+       WCN36XX_HAL_SET_THERMAL_MITIGATION_REQ = 178,
+       WCN36XX_HAL_SET_THERMAL_MITIGATION_RSP = 179,
+
+       WCN36XX_HAL_UPDATE_VHT_OP_MODE_REQ = 182,
+       WCN36XX_HAL_UPDATE_VHT_OP_MODE_RSP = 183,
+
+       WCN36XX_HAL_P2P_NOA_START_IND = 184,
+
+       WCN36XX_HAL_GET_ROAM_RSSI_REQ = 185,
+       WCN36XX_HAL_GET_ROAM_RSSI_RSP = 186,
+
+       WCN36XX_HAL_CLASS_B_STATS_IND = 187,
+       WCN36XX_HAL_DEL_BA_IND = 188,
+       WCN36XX_HAL_DHCP_START_IND = 189,
+       WCN36XX_HAL_DHCP_STOP_IND = 190,
+
+       WCN36XX_HAL_MSG_MAX = WCN36XX_HAL_MSG_TYPE_MAX_ENUM_SIZE
+};
+
+/* Enumeration for Version */
+enum wcn36xx_hal_host_msg_version {
+       WCN36XX_HAL_MSG_VERSION0 = 0,
+       WCN36XX_HAL_MSG_VERSION1 = 1,
+       /* define as 2 bytes data */
+       WCN36XX_HAL_MSG_WCNSS_CTRL_VERSION = 0x7FFF,
+       WCN36XX_HAL_MSG_VERSION_MAX_FIELD = WCN36XX_HAL_MSG_WCNSS_CTRL_VERSION
+};
+
+enum driver_type {
+       DRIVER_TYPE_PRODUCTION = 0,
+       DRIVER_TYPE_MFG = 1,
+       DRIVER_TYPE_DVT = 2,
+       DRIVER_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum wcn36xx_hal_stop_type {
+       HAL_STOP_TYPE_SYS_RESET,
+       HAL_STOP_TYPE_SYS_DEEP_SLEEP,
+       HAL_STOP_TYPE_RF_KILL,
+       HAL_STOP_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum wcn36xx_hal_sys_mode {
+       HAL_SYS_MODE_NORMAL,
+       HAL_SYS_MODE_LEARN,
+       HAL_SYS_MODE_SCAN,
+       HAL_SYS_MODE_PROMISC,
+       HAL_SYS_MODE_SUSPEND_LINK,
+       HAL_SYS_MODE_ROAM_SCAN,
+       HAL_SYS_MODE_ROAM_SUSPEND_LINK,
+       HAL_SYS_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum phy_chan_bond_state {
+       /* 20MHz IF bandwidth centered on IF carrier */
+       PHY_SINGLE_CHANNEL_CENTERED = 0,
+
+       /* 40MHz IF bandwidth with lower 20MHz supporting the primary channel */
+       PHY_DOUBLE_CHANNEL_LOW_PRIMARY = 1,
+
+       /* 40MHz IF bandwidth centered on IF carrier */
+       PHY_DOUBLE_CHANNEL_CENTERED = 2,
+
+       /* 40MHz IF bandwidth with higher 20MHz supporting the primary ch */
+       PHY_DOUBLE_CHANNEL_HIGH_PRIMARY = 3,
+
+       /* 20/40MHZ offset LOW 40/80MHZ offset CENTERED */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_CENTERED = 4,
+
+       /* 20/40MHZ offset CENTERED 40/80MHZ offset CENTERED */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_CENTERED_40MHZ_CENTERED = 5,
+
+       /* 20/40MHZ offset HIGH 40/80MHZ offset CENTERED */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_CENTERED = 6,
+
+       /* 20/40MHZ offset LOW 40/80MHZ offset LOW */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW = 7,
+
+       /* 20/40MHZ offset HIGH 40/80MHZ offset LOW */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW = 8,
+
+       /* 20/40MHZ offset LOW 40/80MHZ offset HIGH */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH = 9,
+
+       /* 20/40MHZ offset-HIGH 40/80MHZ offset HIGH */
+       PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH = 10,
+
+       PHY_CHANNEL_BONDING_STATE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* Spatial Multiplexing(SM) Power Save mode */
+enum wcn36xx_hal_ht_mimo_state {
+       /* Static SM Power Save mode */
+       WCN36XX_HAL_HT_MIMO_PS_STATIC = 0,
+
+       /* Dynamic SM Power Save mode */
+       WCN36XX_HAL_HT_MIMO_PS_DYNAMIC = 1,
+
+       /* reserved */
+       WCN36XX_HAL_HT_MIMO_PS_NA = 2,
+
+       /* SM Power Save disabled */
+       WCN36XX_HAL_HT_MIMO_PS_NO_LIMIT = 3,
+
+       WCN36XX_HAL_HT_MIMO_PS_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* each station added has a rate mode which specifies the sta attributes */
+enum sta_rate_mode {
+       STA_TAURUS = 0,
+       STA_TITAN,
+       STA_POLARIS,
+       STA_11b,
+       STA_11bg,
+       STA_11a,
+       STA_11n,
+       STA_11ac,
+       STA_INVALID_RATE_MODE = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* 1,2,5.5,11 */
+#define WCN36XX_HAL_NUM_DSSS_RATES           4
+
+/* 6,9,12,18,24,36,48,54 */
+#define WCN36XX_HAL_NUM_OFDM_RATES           8
+
+/* 72,96,108 */
+#define WCN36XX_HAL_NUM_POLARIS_RATES       3
+
+#define WCN36XX_HAL_MAC_MAX_SUPPORTED_MCS_SET    16
+
+enum wcn36xx_hal_bss_type {
+       WCN36XX_HAL_INFRASTRUCTURE_MODE,
+
+       /* Added for softAP support */
+       WCN36XX_HAL_INFRA_AP_MODE,
+
+       WCN36XX_HAL_IBSS_MODE,
+
+       /* Added for BT-AMP support */
+       WCN36XX_HAL_BTAMP_STA_MODE,
+
+       /* Added for BT-AMP support */
+       WCN36XX_HAL_BTAMP_AP_MODE,
+
+       WCN36XX_HAL_AUTO_MODE,
+
+       WCN36XX_HAL_DONOT_USE_BSS_TYPE = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum wcn36xx_hal_nw_type {
+       WCN36XX_HAL_11A_NW_TYPE,
+       WCN36XX_HAL_11B_NW_TYPE,
+       WCN36XX_HAL_11G_NW_TYPE,
+       WCN36XX_HAL_11N_NW_TYPE,
+       WCN36XX_HAL_DONOT_USE_NW_TYPE = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+#define WCN36XX_HAL_MAC_RATESET_EID_MAX            12
+
+enum wcn36xx_hal_ht_operating_mode {
+       /* No Protection */
+       WCN36XX_HAL_HT_OP_MODE_PURE,
+
+       /* Overlap Legacy device present, protection is optional */
+       WCN36XX_HAL_HT_OP_MODE_OVERLAP_LEGACY,
+
+       /* No legacy device, but 20 MHz HT present */
+       WCN36XX_HAL_HT_OP_MODE_NO_LEGACY_20MHZ_HT,
+
+       /* Protection is required */
+       WCN36XX_HAL_HT_OP_MODE_MIXED,
+
+       WCN36XX_HAL_HT_OP_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* Encryption type enum used with peer */
+enum ani_ed_type {
+       WCN36XX_HAL_ED_NONE,
+       WCN36XX_HAL_ED_WEP40,
+       WCN36XX_HAL_ED_WEP104,
+       WCN36XX_HAL_ED_TKIP,
+       WCN36XX_HAL_ED_CCMP,
+       WCN36XX_HAL_ED_WPI,
+       WCN36XX_HAL_ED_AES_128_CMAC,
+       WCN36XX_HAL_ED_NOT_IMPLEMENTED = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+#define WLAN_MAX_KEY_RSC_LEN                16
+#define WLAN_WAPI_KEY_RSC_LEN               16
+
+/* MAX key length when ULA is used */
+#define WCN36XX_HAL_MAC_MAX_KEY_LENGTH              32
+#define WCN36XX_HAL_MAC_MAX_NUM_OF_DEFAULT_KEYS     4
+
+/*
+ * Enum to specify whether key is used for TX only, RX only or both.
+ */
+enum ani_key_direction {
+       WCN36XX_HAL_TX_ONLY,
+       WCN36XX_HAL_RX_ONLY,
+       WCN36XX_HAL_TX_RX,
+       WCN36XX_HAL_TX_DEFAULT,
+       WCN36XX_HAL_DONOT_USE_KEY_DIRECTION = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum ani_wep_type {
+       WCN36XX_HAL_WEP_STATIC,
+       WCN36XX_HAL_WEP_DYNAMIC,
+       WCN36XX_HAL_WEP_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum wcn36xx_hal_link_state {
+
+       WCN36XX_HAL_LINK_IDLE_STATE = 0,
+       WCN36XX_HAL_LINK_PREASSOC_STATE = 1,
+       WCN36XX_HAL_LINK_POSTASSOC_STATE = 2,
+       WCN36XX_HAL_LINK_AP_STATE = 3,
+       WCN36XX_HAL_LINK_IBSS_STATE = 4,
+
+       /* BT-AMP Case */
+       WCN36XX_HAL_LINK_BTAMP_PREASSOC_STATE = 5,
+       WCN36XX_HAL_LINK_BTAMP_POSTASSOC_STATE = 6,
+       WCN36XX_HAL_LINK_BTAMP_AP_STATE = 7,
+       WCN36XX_HAL_LINK_BTAMP_STA_STATE = 8,
+
+       /* Reserved for HAL Internal Use */
+       WCN36XX_HAL_LINK_LEARN_STATE = 9,
+       WCN36XX_HAL_LINK_SCAN_STATE = 10,
+       WCN36XX_HAL_LINK_FINISH_SCAN_STATE = 11,
+       WCN36XX_HAL_LINK_INIT_CAL_STATE = 12,
+       WCN36XX_HAL_LINK_FINISH_CAL_STATE = 13,
+       WCN36XX_HAL_LINK_LISTEN_STATE = 14,
+
+       WCN36XX_HAL_LINK_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+enum wcn36xx_hal_stats_mask {
+       HAL_SUMMARY_STATS_INFO = 0x00000001,
+       HAL_GLOBAL_CLASS_A_STATS_INFO = 0x00000002,
+       HAL_GLOBAL_CLASS_B_STATS_INFO = 0x00000004,
+       HAL_GLOBAL_CLASS_C_STATS_INFO = 0x00000008,
+       HAL_GLOBAL_CLASS_D_STATS_INFO = 0x00000010,
+       HAL_PER_STA_STATS_INFO = 0x00000020
+};
+
+/* BT-AMP events type */
+enum bt_amp_event_type {
+       BTAMP_EVENT_CONNECTION_START,
+       BTAMP_EVENT_CONNECTION_STOP,
+       BTAMP_EVENT_CONNECTION_TERMINATED,
+
+       /* This and beyond are invalid values */
+       BTAMP_EVENT_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE,
+};
+
+/* PE Statistics */
+enum pe_stats_mask {
+       PE_SUMMARY_STATS_INFO = 0x00000001,
+       PE_GLOBAL_CLASS_A_STATS_INFO = 0x00000002,
+       PE_GLOBAL_CLASS_B_STATS_INFO = 0x00000004,
+       PE_GLOBAL_CLASS_C_STATS_INFO = 0x00000008,
+       PE_GLOBAL_CLASS_D_STATS_INFO = 0x00000010,
+       PE_PER_STA_STATS_INFO = 0x00000020,
+
+       /* This and beyond are invalid values */
+       PE_STATS_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/*
+ * Configuration Parameter IDs
+ */
+#define WCN36XX_HAL_CFG_STA_ID                         0
+#define WCN36XX_HAL_CFG_CURRENT_TX_ANTENNA             1
+#define WCN36XX_HAL_CFG_CURRENT_RX_ANTENNA             2
+#define WCN36XX_HAL_CFG_LOW_GAIN_OVERRIDE              3
+#define WCN36XX_HAL_CFG_POWER_STATE_PER_CHAIN          4
+#define WCN36XX_HAL_CFG_CAL_PERIOD                     5
+#define WCN36XX_HAL_CFG_CAL_CONTROL                    6
+#define WCN36XX_HAL_CFG_PROXIMITY                      7
+#define WCN36XX_HAL_CFG_NETWORK_DENSITY                        8
+#define WCN36XX_HAL_CFG_MAX_MEDIUM_TIME                        9
+#define WCN36XX_HAL_CFG_MAX_MPDUS_IN_AMPDU             10
+#define WCN36XX_HAL_CFG_RTS_THRESHOLD                  11
+#define WCN36XX_HAL_CFG_SHORT_RETRY_LIMIT              12
+#define WCN36XX_HAL_CFG_LONG_RETRY_LIMIT               13
+#define WCN36XX_HAL_CFG_FRAGMENTATION_THRESHOLD                14
+#define WCN36XX_HAL_CFG_DYNAMIC_THRESHOLD_ZERO         15
+#define WCN36XX_HAL_CFG_DYNAMIC_THRESHOLD_ONE          16
+#define WCN36XX_HAL_CFG_DYNAMIC_THRESHOLD_TWO          17
+#define WCN36XX_HAL_CFG_FIXED_RATE                     18
+#define WCN36XX_HAL_CFG_RETRYRATE_POLICY               19
+#define WCN36XX_HAL_CFG_RETRYRATE_SECONDARY            20
+#define WCN36XX_HAL_CFG_RETRYRATE_TERTIARY             21
+#define WCN36XX_HAL_CFG_FORCE_POLICY_PROTECTION                22
+#define WCN36XX_HAL_CFG_FIXED_RATE_MULTICAST_24GHZ     23
+#define WCN36XX_HAL_CFG_FIXED_RATE_MULTICAST_5GHZ      24
+#define WCN36XX_HAL_CFG_DEFAULT_RATE_INDEX_24GHZ       25
+#define WCN36XX_HAL_CFG_DEFAULT_RATE_INDEX_5GHZ                26
+#define WCN36XX_HAL_CFG_MAX_BA_SESSIONS                        27
+#define WCN36XX_HAL_CFG_PS_DATA_INACTIVITY_TIMEOUT     28
+#define WCN36XX_HAL_CFG_PS_ENABLE_BCN_FILTER           29
+#define WCN36XX_HAL_CFG_PS_ENABLE_RSSI_MONITOR         30
+#define WCN36XX_HAL_CFG_NUM_BEACON_PER_RSSI_AVERAGE    31
+#define WCN36XX_HAL_CFG_STATS_PERIOD                   32
+#define WCN36XX_HAL_CFG_CFP_MAX_DURATION               33
+#define WCN36XX_HAL_CFG_FRAME_TRANS_ENABLED            34
+#define WCN36XX_HAL_CFG_DTIM_PERIOD                    35
+#define WCN36XX_HAL_CFG_EDCA_WMM_ACBK                  36
+#define WCN36XX_HAL_CFG_EDCA_WMM_ACBE                  37
+#define WCN36XX_HAL_CFG_EDCA_WMM_ACVO                  38
+#define WCN36XX_HAL_CFG_EDCA_WMM_ACVI                  39
+#define WCN36XX_HAL_CFG_BA_THRESHOLD_HIGH              40
+#define WCN36XX_HAL_CFG_MAX_BA_BUFFERS                 41
+#define WCN36XX_HAL_CFG_RPE_POLLING_THRESHOLD          42
+#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC0_REG        43
+#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC1_REG        44
+#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC2_REG        45
+#define WCN36XX_HAL_CFG_RPE_AGING_THRESHOLD_FOR_AC3_REG        46
+#define WCN36XX_HAL_CFG_NO_OF_ONCHIP_REORDER_SESSIONS  47
+#define WCN36XX_HAL_CFG_PS_LISTEN_INTERVAL             48
+#define WCN36XX_HAL_CFG_PS_HEART_BEAT_THRESHOLD                49
+#define WCN36XX_HAL_CFG_PS_NTH_BEACON_FILTER           50
+#define WCN36XX_HAL_CFG_PS_MAX_PS_POLL                 51
+#define WCN36XX_HAL_CFG_PS_MIN_RSSI_THRESHOLD          52
+#define WCN36XX_HAL_CFG_PS_RSSI_FILTER_PERIOD          53
+#define WCN36XX_HAL_CFG_PS_BROADCAST_FRAME_FILTER_ENABLE 54
+#define WCN36XX_HAL_CFG_PS_IGNORE_DTIM                 55
+#define WCN36XX_HAL_CFG_PS_ENABLE_BCN_EARLY_TERM       56
+#define WCN36XX_HAL_CFG_DYNAMIC_PS_POLL_VALUE          57
+#define WCN36XX_HAL_CFG_PS_NULLDATA_AP_RESP_TIMEOUT    58
+#define WCN36XX_HAL_CFG_TELE_BCN_WAKEUP_EN             59
+#define WCN36XX_HAL_CFG_TELE_BCN_TRANS_LI              60
+#define WCN36XX_HAL_CFG_TELE_BCN_TRANS_LI_IDLE_BCNS    61
+#define WCN36XX_HAL_CFG_TELE_BCN_MAX_LI                        62
+#define WCN36XX_HAL_CFG_TELE_BCN_MAX_LI_IDLE_BCNS      63
+#define WCN36XX_HAL_CFG_TX_PWR_CTRL_ENABLE             64
+#define WCN36XX_HAL_CFG_VALID_RADAR_CHANNEL_LIST       65
+#define WCN36XX_HAL_CFG_TX_POWER_24_20                 66
+#define WCN36XX_HAL_CFG_TX_POWER_24_40                 67
+#define WCN36XX_HAL_CFG_TX_POWER_50_20                 68
+#define WCN36XX_HAL_CFG_TX_POWER_50_40                 69
+#define WCN36XX_HAL_CFG_MCAST_BCAST_FILTER_SETTING     70
+#define WCN36XX_HAL_CFG_BCN_EARLY_TERM_WAKEUP_INTERVAL 71
+#define WCN36XX_HAL_CFG_MAX_TX_POWER_2_4               72
+#define WCN36XX_HAL_CFG_MAX_TX_POWER_5                 73
+#define WCN36XX_HAL_CFG_INFRA_STA_KEEP_ALIVE_PERIOD    74
+#define WCN36XX_HAL_CFG_ENABLE_CLOSE_LOOP              75
+#define WCN36XX_HAL_CFG_BTC_EXECUTION_MODE             76
+#define WCN36XX_HAL_CFG_BTC_DHCP_BT_SLOTS_TO_BLOCK     77
+#define WCN36XX_HAL_CFG_BTC_A2DP_DHCP_BT_SUB_INTERVALS 78
+#define WCN36XX_HAL_CFG_PS_TX_INACTIVITY_TIMEOUT       79
+#define WCN36XX_HAL_CFG_WCNSS_API_VERSION              80
+#define WCN36XX_HAL_CFG_AP_KEEPALIVE_TIMEOUT           81
+#define WCN36XX_HAL_CFG_GO_KEEPALIVE_TIMEOUT           82
+#define WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST            83
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_INQ_BT          84
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_PAGE_BT         85
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_CONN_BT         86
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_LE_BT           87
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_INQ_WLAN                88
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_PAGE_WLAN       89
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_CONN_WLAN       90
+#define WCN36XX_HAL_CFG_BTC_STATIC_LEN_LE_WLAN         91
+#define WCN36XX_HAL_CFG_BTC_DYN_MAX_LEN_BT             92
+#define WCN36XX_HAL_CFG_BTC_DYN_MAX_LEN_WLAN           93
+#define WCN36XX_HAL_CFG_BTC_MAX_SCO_BLOCK_PERC         94
+#define WCN36XX_HAL_CFG_BTC_DHCP_PROT_ON_A2DP          95
+#define WCN36XX_HAL_CFG_BTC_DHCP_PROT_ON_SCO           96
+#define WCN36XX_HAL_CFG_ENABLE_UNICAST_FILTER          97
+#define WCN36XX_HAL_CFG_MAX_ASSOC_LIMIT                        98
+#define WCN36XX_HAL_CFG_ENABLE_LPWR_IMG_TRANSITION     99
+#define WCN36XX_HAL_CFG_ENABLE_MCC_ADAPTIVE_SCHEDULER  100
+#define WCN36XX_HAL_CFG_ENABLE_DETECT_PS_SUPPORT       101
+#define WCN36XX_HAL_CFG_AP_LINK_MONITOR_TIMEOUT                102
+#define WCN36XX_HAL_CFG_BTC_DWELL_TIME_MULTIPLIER      103
+#define WCN36XX_HAL_CFG_ENABLE_TDLS_OXYGEN_MODE                104
+#define WCN36XX_HAL_CFG_MAX_PARAMS                     105
+
+/* Message definitons - All the messages below need to be packed */
+
+/* Definition for HAL API Version. */
+struct wcnss_wlan_version {
+       u8 revision;
+       u8 version;
+       u8 minor;
+       u8 major;
+} __packed;
+
+/* Definition for Encryption Keys */
+struct wcn36xx_hal_keys {
+       u8 id;
+
+       /* 0 for multicast */
+       u8 unicast;
+
+       enum ani_key_direction direction;
+
+       /* Usage is unknown */
+       u8 rsc[WLAN_MAX_KEY_RSC_LEN];
+
+       /* =1 for authenticator,=0 for supplicant */
+       u8 pae_role;
+
+       u16 length;
+       u8 key[WCN36XX_HAL_MAC_MAX_KEY_LENGTH];
+} __packed;
+
+/*
+ * set_sta_key_params Moving here since it is shared by
+ * configbss/setstakey msgs
+ */
+struct wcn36xx_hal_set_sta_key_params {
+       /* STA Index */
+       u16 sta_index;
+
+       /* Encryption Type used with peer */
+       enum ani_ed_type enc_type;
+
+       /* STATIC/DYNAMIC - valid only for WEP */
+       enum ani_wep_type wep_type;
+
+       /* Default WEP key, valid only for static WEP, must between 0 and 3. */
+       u8 def_wep_idx;
+
+       /* valid only for non-static WEP encyrptions */
+       struct wcn36xx_hal_keys key[WCN36XX_HAL_MAC_MAX_NUM_OF_DEFAULT_KEYS];
+
+       /*
+        * Control for Replay Count, 1= Single TID based replay count on Tx
+        * 0 = Per TID based replay count on TX
+        */
+       u8 single_tid_rc;
+
+} __packed;
+
+/* 4-byte control message header used by HAL*/
+struct wcn36xx_hal_msg_header {
+       enum wcn36xx_hal_host_msg_type msg_type:16;
+       enum wcn36xx_hal_host_msg_version msg_version:16;
+       u32 len;
+} __packed;
+
+/* Config format required by HAL for each CFG item*/
+struct wcn36xx_hal_cfg {
+       /* Cfg Id. The Id required by HAL is exported by HAL
+        * in shared header file between UMAC and HAL.*/
+       u16 id;
+
+       /* Length of the Cfg. This parameter is used to go to next cfg
+        * in the TLV format.*/
+       u16 len;
+
+       /* Padding bytes for unaligned address's */
+       u16 pad_bytes;
+
+       /* Reserve bytes for making cfgVal to align address */
+       u16 reserve;
+
+       /* Following the uCfgLen field there should be a 'uCfgLen' bytes
+        * containing the uCfgValue ; u8 uCfgValue[uCfgLen] */
+} __packed;
+
+struct wcn36xx_hal_mac_start_parameters {
+       /* Drive Type - Production or FTM etc */
+       enum driver_type type;
+
+       /* Length of the config buffer */
+       u32 len;
+
+       /* Following this there is a TLV formatted buffer of length
+        * "len" bytes containing all config values.
+        * The TLV is expected to be formatted like this:
+        * 0           15            31           31+CFG_LEN-1        length-1
+        * |   CFG_ID   |   CFG_LEN   |   CFG_BODY    |  CFG_ID  |......|
+        */
+} __packed;
+
+struct wcn36xx_hal_mac_start_req_msg {
+       /* config buffer must start in TLV format just here */
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_mac_start_parameters params;
+} __packed;
+
+struct wcn36xx_hal_mac_start_rsp_params {
+       /* success or failure */
+       u16 status;
+
+       /* Max number of STA supported by the device */
+       u8 stations;
+
+       /* Max number of BSS supported by the device */
+       u8 bssids;
+
+       /* API Version */
+       struct wcnss_wlan_version version;
+
+       /* CRM build information */
+       u8 crm_version[WCN36XX_HAL_VERSION_LENGTH];
+
+       /* hardware/chipset/misc version information */
+       u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH];
+
+} __packed;
+
+struct wcn36xx_hal_mac_start_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_mac_start_rsp_params start_rsp_params;
+} __packed;
+
+struct wcn36xx_hal_mac_stop_req_params {
+       /* The reason for which the device is being stopped */
+       enum wcn36xx_hal_stop_type reason;
+
+} __packed;
+
+struct wcn36xx_hal_mac_stop_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_mac_stop_req_params stop_req_params;
+} __packed;
+
+struct wcn36xx_hal_mac_stop_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+} __packed;
+
+struct wcn36xx_hal_update_cfg_req_msg {
+       /*
+        * Note: The length specified in tHalUpdateCfgReqMsg messages should be
+        * header.msgLen = sizeof(tHalUpdateCfgReqMsg) + uConfigBufferLen
+        */
+       struct wcn36xx_hal_msg_header header;
+
+       /* Length of the config buffer. Allows UMAC to update multiple CFGs */
+       u32 len;
+
+       /*
+        * Following this there is a TLV formatted buffer of length
+        * "uConfigBufferLen" bytes containing all config values.
+        * The TLV is expected to be formatted like this:
+        * 0           15            31           31+CFG_LEN-1        length-1
+        * |   CFG_ID   |   CFG_LEN   |   CFG_BODY    |  CFG_ID  |......|
+        */
+
+} __packed;
+
+struct wcn36xx_hal_update_cfg_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+} __packed;
+
+/* Frame control field format (2 bytes) */
+struct wcn36xx_hal_mac_frame_ctl {
+
+#ifndef ANI_LITTLE_BIT_ENDIAN
+
+       u8 subType:4;
+       u8 type:2;
+       u8 protVer:2;
+
+       u8 order:1;
+       u8 wep:1;
+       u8 moreData:1;
+       u8 powerMgmt:1;
+       u8 retry:1;
+       u8 moreFrag:1;
+       u8 fromDS:1;
+       u8 toDS:1;
+
+#else
+
+       u8 protVer:2;
+       u8 type:2;
+       u8 subType:4;
+
+       u8 toDS:1;
+       u8 fromDS:1;
+       u8 moreFrag:1;
+       u8 retry:1;
+       u8 powerMgmt:1;
+       u8 moreData:1;
+       u8 wep:1;
+       u8 order:1;
+
+#endif
+
+};
+
+/* Sequence control field */
+struct wcn36xx_hal_mac_seq_ctl {
+       u8 fragNum:4;
+       u8 seqNumLo:4;
+       u8 seqNumHi:8;
+};
+
+/* Management header format */
+struct wcn36xx_hal_mac_mgmt_hdr {
+       struct wcn36xx_hal_mac_frame_ctl fc;
+       u8 durationLo;
+       u8 durationHi;
+       u8 da[6];
+       u8 sa[6];
+       u8 bssId[6];
+       struct wcn36xx_hal_mac_seq_ctl seqControl;
+};
+
+/* FIXME: pronto v1 apparently has 4 */
+#define WCN36XX_HAL_NUM_BSSID               2
+
+/* Scan Entry to hold active BSS idx's */
+struct wcn36xx_hal_scan_entry {
+       u8 bss_index[WCN36XX_HAL_NUM_BSSID];
+       u8 active_bss_count;
+};
+
+struct wcn36xx_hal_init_scan_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* LEARN - AP Role
+          SCAN - STA Role */
+       enum wcn36xx_hal_sys_mode mode;
+
+       /* BSSID of the BSS */
+       u8 bssid[ETH_ALEN];
+
+       /* Whether BSS needs to be notified */
+       u8 notify;
+
+       /* Kind of frame to be used for notifying the BSS (Data Null, QoS
+        * Null, or CTS to Self). Must always be a valid frame type. */
+       u8 frame_type;
+
+       /* UMAC has the option of passing the MAC frame to be used for
+        * notifying the BSS. If non-zero, HAL will use the MAC frame
+        * buffer pointed to by macMgmtHdr. If zero, HAL will generate the
+        * appropriate MAC frame based on frameType. */
+       u8 frame_len;
+
+       /* Following the framelength there is a MAC frame buffer if
+        * frameLength is non-zero. */
+       struct wcn36xx_hal_mac_mgmt_hdr mac_mgmt_hdr;
+
+       /* Entry to hold number of active BSS idx's */
+       struct wcn36xx_hal_scan_entry scan_entry;
+};
+
+struct wcn36xx_hal_init_scan_con_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* LEARN - AP Role
+          SCAN - STA Role */
+       enum wcn36xx_hal_sys_mode mode;
+
+       /* BSSID of the BSS */
+       u8 bssid[ETH_ALEN];
+
+       /* Whether BSS needs to be notified */
+       u8 notify;
+
+       /* Kind of frame to be used for notifying the BSS (Data Null, QoS
+        * Null, or CTS to Self). Must always be a valid frame type. */
+       u8 frame_type;
+
+       /* UMAC has the option of passing the MAC frame to be used for
+        * notifying the BSS. If non-zero, HAL will use the MAC frame
+        * buffer pointed to by macMgmtHdr. If zero, HAL will generate the
+        * appropriate MAC frame based on frameType. */
+       u8 frame_length;
+
+       /* Following the framelength there is a MAC frame buffer if
+        * frameLength is non-zero. */
+       struct wcn36xx_hal_mac_mgmt_hdr mac_mgmt_hdr;
+
+       /* Entry to hold number of active BSS idx's */
+       struct wcn36xx_hal_scan_entry scan_entry;
+
+       /* Single NoA usage in Scanning */
+       u8 use_noa;
+
+       /* Indicates the scan duration (in ms) */
+       u16 scan_duration;
+
+};
+
+struct wcn36xx_hal_init_scan_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+} __packed;
+
+struct wcn36xx_hal_start_scan_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Indicates the channel to scan */
+       u8 scan_channel;
+} __packed;
+
+struct wcn36xx_hal_start_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u32 start_tsf[2];
+       u8 tx_mgmt_power;
+
+} __packed;
+
+struct wcn36xx_hal_end_scan_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Indicates the channel to stop scanning. Not used really. But
+        * retained for symmetry with "start Scan" message. It can also
+        * help in error check if needed. */
+       u8 scan_channel;
+} __packed;
+
+struct wcn36xx_hal_end_scan_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+} __packed;
+
+struct wcn36xx_hal_finish_scan_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Identifies the operational state of the AP/STA
+        * LEARN - AP Role SCAN - STA Role */
+       enum wcn36xx_hal_sys_mode mode;
+
+       /* Operating channel to tune to. */
+       u8 oper_channel;
+
+       /* Channel Bonding state If 20/40 MHz is operational, this will
+        * indicate the 40 MHz extension channel in combination with the
+        * control channel */
+       enum phy_chan_bond_state cb_state;
+
+       /* BSSID of the BSS */
+       u8 bssid[ETH_ALEN];
+
+       /* Whether BSS needs to be notified */
+       u8 notify;
+
+       /* Kind of frame to be used for notifying the BSS (Data Null, QoS
+        * Null, or CTS to Self). Must always be a valid frame type. */
+       u8 frame_type;
+
+       /* UMAC has the option of passing the MAC frame to be used for
+        * notifying the BSS. If non-zero, HAL will use the MAC frame
+        * buffer pointed to by macMgmtHdr. If zero, HAL will generate the
+        * appropriate MAC frame based on frameType. */
+       u8 frame_length;
+
+       /* Following the framelength there is a MAC frame buffer if
+        * frameLength is non-zero. */
+       struct wcn36xx_hal_mac_mgmt_hdr mac_mgmt_hdr;
+
+       /* Entry to hold number of active BSS idx's */
+       struct wcn36xx_hal_scan_entry scan_entry;
+
+} __packed;
+
+struct wcn36xx_hal_finish_scan_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+} __packed;
+
+enum wcn36xx_hal_rate_index {
+       HW_RATE_INDEX_1MBPS     = 0x82,
+       HW_RATE_INDEX_2MBPS     = 0x84,
+       HW_RATE_INDEX_5_5MBPS   = 0x8B,
+       HW_RATE_INDEX_6MBPS     = 0x0C,
+       HW_RATE_INDEX_9MBPS     = 0x12,
+       HW_RATE_INDEX_11MBPS    = 0x96,
+       HW_RATE_INDEX_12MBPS    = 0x18,
+       HW_RATE_INDEX_18MBPS    = 0x24,
+       HW_RATE_INDEX_24MBPS    = 0x30,
+       HW_RATE_INDEX_36MBPS    = 0x48,
+       HW_RATE_INDEX_48MBPS    = 0x60,
+       HW_RATE_INDEX_54MBPS    = 0x6C
+};
+
+struct wcn36xx_hal_supported_rates {
+       /*
+        * For Self STA Entry: this represents Self Mode.
+        * For Peer Stations, this represents the mode of the peer.
+        * On Station:
+        *
+        * --this mode is updated when PE adds the Self Entry.
+        *
+        * -- OR when PE sends 'ADD_BSS' message and station context in BSS
+        *    is used to indicate the mode of the AP.
+        *
+        * ON AP:
+        *
+        * -- this mode is updated when PE sends 'ADD_BSS' and Sta entry
+        *     for that BSS is used to indicate the self mode of the AP.
+        *
+        * -- OR when a station is associated, PE sends 'ADD_STA' message
+        *    with this mode updated.
+        */
+
+       enum sta_rate_mode op_rate_mode;
+
+       /* 11b, 11a and aniLegacyRates are IE rates which gives rate in
+        * unit of 500Kbps */
+       u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES];
+       u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES];
+       u16 legacy_rates[WCN36XX_HAL_NUM_POLARIS_RATES];
+       u16 reserved;
+
+       /* Taurus only supports 26 Titan Rates(no ESF/concat Rates will be
+        * supported) First 26 bits are reserved for those Titan rates and
+        * the last 4 bits(bit28-31) for Taurus, 2(bit26-27) bits are
+        * reserved. */
+       /* Titan and Taurus Rates */
+       u32 enhanced_rate_bitmap;
+
+       /*
+        * 0-76 bits used, remaining reserved
+        * bits 0-15 and 32 should be set.
+        */
+       u8 supported_mcs_set[WCN36XX_HAL_MAC_MAX_SUPPORTED_MCS_SET];
+
+       /*
+        * RX Highest Supported Data Rate defines the highest data
+        * rate that the STA is able to receive, in unites of 1Mbps.
+        * This value is derived from "Supported MCS Set field" inside
+        * the HT capability element.
+        */
+       u16 rx_highest_data_rate;
+
+} __packed;
+
+struct wcn36xx_hal_config_sta_params {
+       /* BSSID of STA */
+       u8 bssid[ETH_ALEN];
+
+       /* ASSOC ID, as assigned by UMAC */
+       u16 aid;
+
+       /* STA entry Type: 0 - Self, 1 - Other/Peer, 2 - BSSID, 3 - BCAST */
+       u8 type;
+
+       /* Short Preamble Supported. */
+       u8 short_preamble_supported;
+
+       /* MAC Address of STA */
+       u8 mac[ETH_ALEN];
+
+       /* Listen interval of the STA */
+       u16 listen_interval;
+
+       /* Support for 11e/WMM */
+       u8 wmm_enabled;
+
+       /* 11n HT capable STA */
+       u8 ht_capable;
+
+       /* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */
+       u8 tx_channel_width_set;
+
+       /* RIFS mode 0 - NA, 1 - Allowed */
+       u8 rifs_mode;
+
+       /* L-SIG TXOP Protection mechanism
+          0 - No Support, 1 - Supported
+          SG - there is global field */
+       u8 lsig_txop_protection;
+
+       /* Max Ampdu Size supported by STA. TPE programming.
+          0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k */
+       u8 max_ampdu_size;
+
+       /* Max Ampdu density. Used by RA.  3 : 0~7 : 2^(11nAMPDUdensity -4) */
+       u8 max_ampdu_density;
+
+       /* Max AMSDU size 1 : 3839 bytes, 0 : 7935 bytes */
+       u8 max_amsdu_size;
+
+       /* Short GI support for 40Mhz packets */
+       u8 sgi_40mhz;
+
+       /* Short GI support for 20Mhz packets */
+       u8 sgi_20Mhz;
+
+       /* TODO move this parameter to the end for 3680 */
+       /* These rates are the intersection of peer and self capabilities. */
+       struct wcn36xx_hal_supported_rates supported_rates;
+
+       /* Robust Management Frame (RMF) enabled/disabled */
+       u8 rmf;
+
+       /* The unicast encryption type in the association */
+       u32 encrypt_type;
+
+       /* HAL should update the existing STA entry, if this flag is set. UMAC
+          will set this flag in case of RE-ASSOC, where we want to reuse the
+          old STA ID. 0 = Add, 1 = Update */
+       u8 action;
+
+       /* U-APSD Flags: 1b per AC.  Encoded as follows:
+          b7 b6 b5 b4 b3 b2 b1 b0 =
+          X  X  X  X  BE BK VI VO */
+       u8 uapsd;
+
+       /* Max SP Length */
+       u8 max_sp_len;
+
+       /* 11n Green Field preamble support
+          0 - Not supported, 1 - Supported */
+       u8 green_field_capable;
+
+       /* MIMO Power Save mode */
+       enum wcn36xx_hal_ht_mimo_state mimo_ps;
+
+       /* Delayed BA Support */
+       u8 delayed_ba_support;
+
+       /* Max AMPDU duration in 32us */
+       u8 max_ampdu_duration;
+
+       /* HT STA should set it to 1 if it is enabled in BSS. HT STA should
+        * set it to 0 if AP does not support it. This indication is sent
+        * to HAL and HAL uses this flag to pickup up appropriate 40Mhz
+        * rates. */
+       u8 dsss_cck_mode_40mhz;
+
+       /* Valid STA Idx when action=Update. Set to 0xFF when invalid!
+        * Retained for backward compalibity with existing HAL code */
+       u8 sta_index;
+
+       /* BSSID of BSS to which station is associated. Set to 0xFF when
+        * invalid. Retained for backward compalibity with existing HAL
+        * code */
+       u8 bssid_index;
+
+       u8 p2p;
+
+       /* TODO add this parameter for 3680. */
+       /* Reserved to align next field on a dword boundary */
+       /* u8 reserved; */
+} __packed;
+
+struct wcn36xx_hal_config_sta_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_config_sta_params sta_params;
+} __packed;
+
+struct wcn36xx_hal_config_sta_params_v1 {
+       /* BSSID of STA */
+       u8 bssid[ETH_ALEN];
+
+       /* ASSOC ID, as assigned by UMAC */
+       u16 aid;
+
+       /* STA entry Type: 0 - Self, 1 - Other/Peer, 2 - BSSID, 3 - BCAST */
+       u8 type;
+
+       /* Short Preamble Supported. */
+       u8 short_preamble_supported;
+
+       /* MAC Address of STA */
+       u8 mac[ETH_ALEN];
+
+       /* Listen interval of the STA */
+       u16 listen_interval;
+
+       /* Support for 11e/WMM */
+       u8 wmm_enabled;
+
+       /* 11n HT capable STA */
+       u8 ht_capable;
+
+       /* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */
+       u8 tx_channel_width_set;
+
+       /* RIFS mode 0 - NA, 1 - Allowed */
+       u8 rifs_mode;
+
+       /* L-SIG TXOP Protection mechanism
+          0 - No Support, 1 - Supported
+          SG - there is global field */
+       u8 lsig_txop_protection;
+
+       /* Max Ampdu Size supported by STA. TPE programming.
+          0 : 8k , 1 : 16k, 2 : 32k, 3 : 64k */
+       u8 max_ampdu_size;
+
+       /* Max Ampdu density. Used by RA.  3 : 0~7 : 2^(11nAMPDUdensity -4) */
+       u8 max_ampdu_density;
+
+       /* Max AMSDU size 1 : 3839 bytes, 0 : 7935 bytes */
+       u8 max_amsdu_size;
+
+       /* Short GI support for 40Mhz packets */
+       u8 sgi_40mhz;
+
+       /* Short GI support for 20Mhz packets */
+       u8 sgi_20Mhz;
+
+       /* Robust Management Frame (RMF) enabled/disabled */
+       u8 rmf;
+
+       /* The unicast encryption type in the association */
+       u32 encrypt_type;
+
+       /* HAL should update the existing STA entry, if this flag is set. UMAC
+          will set this flag in case of RE-ASSOC, where we want to reuse the
+          old STA ID. 0 = Add, 1 = Update */
+       u8 action;
+
+       /* U-APSD Flags: 1b per AC.  Encoded as follows:
+          b7 b6 b5 b4 b3 b2 b1 b0 =
+          X  X  X  X  BE BK VI VO */
+       u8 uapsd;
+
+       /* Max SP Length */
+       u8 max_sp_len;
+
+       /* 11n Green Field preamble support
+          0 - Not supported, 1 - Supported */
+       u8 green_field_capable;
+
+       /* MIMO Power Save mode */
+       enum wcn36xx_hal_ht_mimo_state mimo_ps;
+
+       /* Delayed BA Support */
+       u8 delayed_ba_support;
+
+       /* Max AMPDU duration in 32us */
+       u8 max_ampdu_duration;
+
+       /* HT STA should set it to 1 if it is enabled in BSS. HT STA should
+        * set it to 0 if AP does not support it. This indication is sent
+        * to HAL and HAL uses this flag to pickup up appropriate 40Mhz
+        * rates. */
+       u8 dsss_cck_mode_40mhz;
+
+       /* Valid STA Idx when action=Update. Set to 0xFF when invalid!
+        * Retained for backward compalibity with existing HAL code */
+       u8 sta_index;
+
+       /* BSSID of BSS to which station is associated. Set to 0xFF when
+        * invalid. Retained for backward compalibity with existing HAL
+        * code */
+       u8 bssid_index;
+
+       u8 p2p;
+
+       /* Reserved to align next field on a dword boundary */
+       u8 reserved;
+
+       /* These rates are the intersection of peer and self capabilities. */
+       struct wcn36xx_hal_supported_rates supported_rates;
+} __packed;
+
+struct wcn36xx_hal_config_sta_req_msg_v1 {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_config_sta_params_v1 sta_params;
+} __packed;
+
+struct config_sta_rsp_params {
+       /* success or failure */
+       u32 status;
+
+       /* Station index; valid only when 'status' field value SUCCESS */
+       u8 sta_index;
+
+       /* BSSID Index of BSS to which the station is associated */
+       u8 bssid_index;
+
+       /* DPU Index for PTK */
+       u8 dpu_index;
+
+       /* DPU Index for GTK */
+       u8 bcast_dpu_index;
+
+       /* DPU Index for IGTK  */
+       u8 bcast_mgmt_dpu_idx;
+
+       /* PTK DPU signature */
+       u8 uc_ucast_sig;
+
+       /* GTK DPU isignature */
+       u8 uc_bcast_sig;
+
+       /* IGTK DPU signature */
+       u8 uc_mgmt_sig;
+
+       u8 p2p;
+
+} __packed;
+
+struct wcn36xx_hal_config_sta_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       struct config_sta_rsp_params params;
+} __packed;
+
+/* Delete STA Request message */
+struct wcn36xx_hal_delete_sta_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Index of STA to delete */
+       u8 sta_index;
+
+} __packed;
+
+/* Delete STA Response message */
+struct wcn36xx_hal_delete_sta_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* Index of STA deleted */
+       u8 sta_id;
+} __packed;
+
+/* 12 Bytes long because this structure can be used to represent rate and
+ * extended rate set IEs. The parser assume this to be at least 12 */
+struct wcn36xx_hal_rate_set {
+       u8 num_rates;
+       u8 rate[WCN36XX_HAL_MAC_RATESET_EID_MAX];
+} __packed;
+
+/* access category record */
+struct wcn36xx_hal_aci_aifsn {
+#ifndef ANI_LITTLE_BIT_ENDIAN
+       u8 rsvd:1;
+       u8 aci:2;
+       u8 acm:1;
+       u8 aifsn:4;
+#else
+       u8 aifsn:4;
+       u8 acm:1;
+       u8 aci:2;
+       u8 rsvd:1;
+#endif
+} __packed;
+
+/* contention window size */
+struct wcn36xx_hal_mac_cw {
+#ifndef ANI_LITTLE_BIT_ENDIAN
+       u8 max:4;
+       u8 min:4;
+#else
+       u8 min:4;
+       u8 max:4;
+#endif
+} __packed;
+
+struct wcn36xx_hal_edca_param_record {
+       struct wcn36xx_hal_aci_aifsn aci;
+       struct wcn36xx_hal_mac_cw cw;
+       u16 txop_limit;
+} __packed;
+
+struct wcn36xx_hal_mac_ssid {
+       u8 length;
+       u8 ssid[32];
+} __packed;
+
+/* Concurrency role. These are generic IDs that identify the various roles
+ *  in the software system. */
+enum wcn36xx_hal_con_mode {
+       WCN36XX_HAL_STA_MODE = 0,
+
+       /* to support softAp mode . This is misleading.
+          It means AP MODE only. */
+       WCN36XX_HAL_STA_SAP_MODE = 1,
+
+       WCN36XX_HAL_P2P_CLIENT_MODE,
+       WCN36XX_HAL_P2P_GO_MODE,
+       WCN36XX_HAL_MONITOR_MODE,
+};
+
+/* This is a bit pattern to be set for each mode
+ * bit 0 - sta mode
+ * bit 1 - ap mode
+ * bit 2 - p2p client mode
+ * bit 3 - p2p go mode */
+enum wcn36xx_hal_concurrency_mode {
+       HAL_STA = 1,
+       HAL_SAP = 2,
+
+       /* to support sta, softAp  mode . This means STA+AP mode */
+       HAL_STA_SAP = 3,
+
+       HAL_P2P_CLIENT = 4,
+       HAL_P2P_GO = 8,
+       HAL_MAX_CONCURRENCY_PERSONA = 4
+};
+
+struct wcn36xx_hal_config_bss_params {
+       /* BSSID */
+       u8 bssid[ETH_ALEN];
+
+       /* Self Mac Address */
+       u8 self_mac_addr[ETH_ALEN];
+
+       /* BSS type */
+       enum wcn36xx_hal_bss_type bss_type;
+
+       /* Operational Mode: AP =0, STA = 1 */
+       u8 oper_mode;
+
+       /* Network Type */
+       enum wcn36xx_hal_nw_type nw_type;
+
+       /* Used to classify PURE_11G/11G_MIXED to program MTU */
+       u8 short_slot_time_supported;
+
+       /* Co-exist with 11a STA */
+       u8 lla_coexist;
+
+       /* Co-exist with 11b STA */
+       u8 llb_coexist;
+
+       /* Co-exist with 11g STA */
+       u8 llg_coexist;
+
+       /* Coexistence with 11n STA */
+       u8 ht20_coexist;
+
+       /* Non GF coexist flag */
+       u8 lln_non_gf_coexist;
+
+       /* TXOP protection support */
+       u8 lsig_tx_op_protection_full_support;
+
+       /* RIFS mode */
+       u8 rifs_mode;
+
+       /* Beacon Interval in TU */
+       u16 beacon_interval;
+
+       /* DTIM period */
+       u8 dtim_period;
+
+       /* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */
+       u8 tx_channel_width_set;
+
+       /* Operating channel */
+       u8 oper_channel;
+
+       /* Extension channel for channel bonding */
+       u8 ext_channel;
+
+       /* Reserved to align next field on a dword boundary */
+       u8 reserved;
+
+       /* TODO move sta to the end for 3680 */
+       /* Context of the station being added in HW
+        *  Add a STA entry for "itself" -
+        *
+        *  On AP  - Add the AP itself in an "STA context"
+        *
+        *  On STA - Add the AP to which this STA is joining in an
+        *  "STA context"
+        */
+       struct wcn36xx_hal_config_sta_params sta;
+       /* SSID of the BSS */
+       struct wcn36xx_hal_mac_ssid ssid;
+
+       /* HAL should update the existing BSS entry, if this flag is set.
+        * UMAC will set this flag in case of reassoc, where we want to
+        * resue the the old BSSID and still return success 0 = Add, 1 =
+        * Update */
+       u8 action;
+
+       /* MAC Rate Set */
+       struct wcn36xx_hal_rate_set rateset;
+
+       /* Enable/Disable HT capabilities of the BSS */
+       u8 ht;
+
+       /* Enable/Disable OBSS protection */
+       u8 obss_prot_enabled;
+
+       /* RMF enabled/disabled */
+       u8 rmf;
+
+       /* HT Operating Mode operating mode of the 802.11n STA */
+       enum wcn36xx_hal_ht_operating_mode ht_oper_mode;
+
+       /* Dual CTS Protection: 0 - Unused, 1 - Used */
+       u8 dual_cts_protection;
+
+       /* Probe Response Max retries */
+       u8 max_probe_resp_retry_limit;
+
+       /* To Enable Hidden ssid */
+       u8 hidden_ssid;
+
+       /* To Enable Disable FW Proxy Probe Resp */
+       u8 proxy_probe_resp;
+
+       /* Boolean to indicate if EDCA params are valid. UMAC might not
+        * have valid EDCA params or might not desire to apply EDCA params
+        * during config BSS. 0 implies Not Valid ; Non-Zero implies
+        * valid */
+       u8 edca_params_valid;
+
+       /* EDCA Parameters for Best Effort Access Category */
+       struct wcn36xx_hal_edca_param_record acbe;
+
+       /* EDCA Parameters forBackground Access Category */
+       struct wcn36xx_hal_edca_param_record acbk;
+
+       /* EDCA Parameters for Video Access Category */
+       struct wcn36xx_hal_edca_param_record acvi;
+
+       /* EDCA Parameters for Voice Access Category */
+       struct wcn36xx_hal_edca_param_record acvo;
+
+       /* Ext Bss Config Msg if set */
+       u8 ext_set_sta_key_param_valid;
+
+       /* SetStaKeyParams for ext bss msg */
+       struct wcn36xx_hal_set_sta_key_params ext_set_sta_key_param;
+
+       /* Persona for the BSS can be STA,AP,GO,CLIENT value same as enum
+        * wcn36xx_hal_con_mode */
+       u8 wcn36xx_hal_persona;
+
+       u8 spectrum_mgt_enable;
+
+       /* HAL fills in the tx power used for mgmt frames in txMgmtPower */
+       s8 tx_mgmt_power;
+
+       /* maxTxPower has max power to be used after applying the power
+        * constraint if any */
+       s8 max_tx_power;
+} __packed;
+
+struct wcn36xx_hal_config_bss_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_config_bss_params bss_params;
+} __packed;
+
+struct wcn36xx_hal_config_bss_params_v1 {
+       /* BSSID */
+       u8 bssid[ETH_ALEN];
+
+       /* Self Mac Address */
+       u8 self_mac_addr[ETH_ALEN];
+
+       /* BSS type */
+       enum wcn36xx_hal_bss_type bss_type;
+
+       /* Operational Mode: AP =0, STA = 1 */
+       u8 oper_mode;
+
+       /* Network Type */
+       enum wcn36xx_hal_nw_type nw_type;
+
+       /* Used to classify PURE_11G/11G_MIXED to program MTU */
+       u8 short_slot_time_supported;
+
+       /* Co-exist with 11a STA */
+       u8 lla_coexist;
+
+       /* Co-exist with 11b STA */
+       u8 llb_coexist;
+
+       /* Co-exist with 11g STA */
+       u8 llg_coexist;
+
+       /* Coexistence with 11n STA */
+       u8 ht20_coexist;
+
+       /* Non GF coexist flag */
+       u8 lln_non_gf_coexist;
+
+       /* TXOP protection support */
+       u8 lsig_tx_op_protection_full_support;
+
+       /* RIFS mode */
+       u8 rifs_mode;
+
+       /* Beacon Interval in TU */
+       u16 beacon_interval;
+
+       /* DTIM period */
+       u8 dtim_period;
+
+       /* TX Width Set: 0 - 20 MHz only, 1 - 20/40 MHz */
+       u8 tx_channel_width_set;
+
+       /* Operating channel */
+       u8 oper_channel;
+
+       /* Extension channel for channel bonding */
+       u8 ext_channel;
+
+       /* Reserved to align next field on a dword boundary */
+       u8 reserved;
+
+       /* SSID of the BSS */
+       struct wcn36xx_hal_mac_ssid ssid;
+
+       /* HAL should update the existing BSS entry, if this flag is set.
+        * UMAC will set this flag in case of reassoc, where we want to
+        * resue the the old BSSID and still return success 0 = Add, 1 =
+        * Update */
+       u8 action;
+
+       /* MAC Rate Set */
+       struct wcn36xx_hal_rate_set rateset;
+
+       /* Enable/Disable HT capabilities of the BSS */
+       u8 ht;
+
+       /* Enable/Disable OBSS protection */
+       u8 obss_prot_enabled;
+
+       /* RMF enabled/disabled */
+       u8 rmf;
+
+       /* HT Operating Mode operating mode of the 802.11n STA */
+       enum wcn36xx_hal_ht_operating_mode ht_oper_mode;
+
+       /* Dual CTS Protection: 0 - Unused, 1 - Used */
+       u8 dual_cts_protection;
+
+       /* Probe Response Max retries */
+       u8 max_probe_resp_retry_limit;
+
+       /* To Enable Hidden ssid */
+       u8 hidden_ssid;
+
+       /* To Enable Disable FW Proxy Probe Resp */
+       u8 proxy_probe_resp;
+
+       /* Boolean to indicate if EDCA params are valid. UMAC might not
+        * have valid EDCA params or might not desire to apply EDCA params
+        * during config BSS. 0 implies Not Valid ; Non-Zero implies
+        * valid */
+       u8 edca_params_valid;
+
+       /* EDCA Parameters for Best Effort Access Category */
+       struct wcn36xx_hal_edca_param_record acbe;
+
+       /* EDCA Parameters forBackground Access Category */
+       struct wcn36xx_hal_edca_param_record acbk;
+
+       /* EDCA Parameters for Video Access Category */
+       struct wcn36xx_hal_edca_param_record acvi;
+
+       /* EDCA Parameters for Voice Access Category */
+       struct wcn36xx_hal_edca_param_record acvo;
+
+       /* Ext Bss Config Msg if set */
+       u8 ext_set_sta_key_param_valid;
+
+       /* SetStaKeyParams for ext bss msg */
+       struct wcn36xx_hal_set_sta_key_params ext_set_sta_key_param;
+
+       /* Persona for the BSS can be STA,AP,GO,CLIENT value same as enum
+        * wcn36xx_hal_con_mode */
+       u8 wcn36xx_hal_persona;
+
+       u8 spectrum_mgt_enable;
+
+       /* HAL fills in the tx power used for mgmt frames in txMgmtPower */
+       s8 tx_mgmt_power;
+
+       /* maxTxPower has max power to be used after applying the power
+        * constraint if any */
+       s8 max_tx_power;
+
+       /* Context of the station being added in HW
+        *  Add a STA entry for "itself" -
+        *
+        *  On AP  - Add the AP itself in an "STA context"
+        *
+        *  On STA - Add the AP to which this STA is joining in an
+        *  "STA context"
+        */
+       struct wcn36xx_hal_config_sta_params_v1 sta;
+} __packed;
+
+struct wcn36xx_hal_config_bss_req_msg_v1 {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_config_bss_params_v1 bss_params;
+} __packed;
+
+struct wcn36xx_hal_config_bss_rsp_params {
+       /* Success or Failure */
+       u32 status;
+
+       /* BSS index allocated by HAL */
+       u8 bss_index;
+
+       /* DPU descriptor index for PTK */
+       u8 dpu_desc_index;
+
+       /* PTK DPU signature */
+       u8 ucast_dpu_signature;
+
+       /* DPU descriptor index for GTK */
+       u8 bcast_dpu_desc_indx;
+
+       /* GTK DPU signature */
+       u8 bcast_dpu_signature;
+
+       /* DPU descriptor for IGTK */
+       u8 mgmt_dpu_desc_index;
+
+       /* IGTK DPU signature */
+       u8 mgmt_dpu_signature;
+
+       /* Station Index for BSS entry */
+       u8 bss_sta_index;
+
+       /* Self station index for this BSS */
+       u8 bss_self_sta_index;
+
+       /* Bcast station for buffering bcast frames in AP role */
+       u8 bss_bcast_sta_idx;
+
+       /* MAC Address of STA(PEER/SELF) in staContext of configBSSReq */
+       u8 mac[ETH_ALEN];
+
+       /* HAL fills in the tx power used for mgmt frames in this field. */
+       s8 tx_mgmt_power;
+
+} __packed;
+
+struct wcn36xx_hal_config_bss_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_config_bss_rsp_params bss_rsp_params;
+} __packed;
+
+struct wcn36xx_hal_delete_bss_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* BSS index to be deleted */
+       u8 bss_index;
+
+} __packed;
+
+struct wcn36xx_hal_delete_bss_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Success or Failure */
+       u32 status;
+
+       /* BSS index that has been deleted */
+       u8 bss_index;
+
+} __packed;
+
+struct wcn36xx_hal_join_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Indicates the BSSID to which STA is going to associate */
+       u8 bssid[ETH_ALEN];
+
+       /* Indicates the channel to switch to. */
+       u8 channel;
+
+       /* Self STA MAC */
+       u8 self_sta_mac_addr[ETH_ALEN];
+
+       /* Local power constraint */
+       u8 local_power_constraint;
+
+       /* Secondary channel offset */
+       enum phy_chan_bond_state secondary_channel_offset;
+
+       /* link State */
+       enum wcn36xx_hal_link_state link_state;
+
+       /* Max TX power */
+       s8 max_tx_power;
+} __packed;
+
+struct wcn36xx_hal_join_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* HAL fills in the tx power used for mgmt frames in this field */
+       u8 tx_mgmt_power;
+} __packed;
+
+struct post_assoc_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       struct wcn36xx_hal_config_sta_params sta_params;
+       struct wcn36xx_hal_config_bss_params bss_params;
+};
+
+struct post_assoc_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct config_sta_rsp_params sta_rsp_params;
+       struct wcn36xx_hal_config_bss_rsp_params bss_rsp_params;
+};
+
+/* This is used to create a set of WEP keys for a given BSS. */
+struct wcn36xx_hal_set_bss_key_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* BSS Index of the BSS */
+       u8 bss_idx;
+
+       /* Encryption Type used with peer */
+       enum ani_ed_type enc_type;
+
+       /* Number of keys */
+       u8 num_keys;
+
+       /* Array of keys. */
+       struct wcn36xx_hal_keys keys[WCN36XX_HAL_MAC_MAX_NUM_OF_DEFAULT_KEYS];
+
+       /* Control for Replay Count, 1= Single TID based replay count on Tx
+        * 0 = Per TID based replay count on TX */
+       u8 single_tid_rc;
+} __packed;
+
+/* tagged version of set bss key */
+struct wcn36xx_hal_set_bss_key_req_msg_tagged {
+       struct wcn36xx_hal_set_bss_key_req_msg Msg;
+       u32 tag;
+} __packed;
+
+struct wcn36xx_hal_set_bss_key_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+} __packed;
+
+/*
+ * This is used  configure the key information on a given station.
+ * When the sec_type is WEP40 or WEP104, the def_wep_idx is used to locate
+ * a preconfigured key from a BSS the station assoicated with; otherwise
+ * a new key descriptor is created based on the key field.
+ */
+struct wcn36xx_hal_set_sta_key_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_set_sta_key_params set_sta_key_params;
+} __packed;
+
+struct wcn36xx_hal_set_sta_key_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+} __packed;
+
+struct wcn36xx_hal_remove_bss_key_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* BSS Index of the BSS */
+       u8 bss_idx;
+
+       /* Encryption Type used with peer */
+       enum ani_ed_type enc_type;
+
+       /* Key Id */
+       u8 key_id;
+
+       /* STATIC/DYNAMIC. Used in Nullifying in Key Descriptors for
+        * Static/Dynamic keys */
+       enum ani_wep_type wep_type;
+} __packed;
+
+struct wcn36xx_hal_remove_bss_key_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+} __packed;
+
+/*
+ * This is used by PE to Remove the key information on a given station.
+ */
+struct wcn36xx_hal_remove_sta_key_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* STA Index */
+       u16 sta_idx;
+
+       /* Encryption Type used with peer */
+       enum ani_ed_type enc_type;
+
+       /* Key Id */
+       u8 key_id;
+
+       /* Whether to invalidate the Broadcast key or Unicast key. In case
+        * of WEP, the same key is used for both broadcast and unicast. */
+       u8 unicast;
+
+} __packed;
+
+struct wcn36xx_hal_remove_sta_key_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /*success or failure */
+       u32 status;
+
+} __packed;
+
+#ifdef FEATURE_OEM_DATA_SUPPORT
+
+#ifndef OEM_DATA_REQ_SIZE
+#define OEM_DATA_REQ_SIZE 134
+#endif
+
+#ifndef OEM_DATA_RSP_SIZE
+#define OEM_DATA_RSP_SIZE 1968
+#endif
+
+struct start_oem_data_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u32 status;
+       tSirMacAddr self_mac_addr;
+       u8 oem_data_req[OEM_DATA_REQ_SIZE];
+
+};
+
+struct start_oem_data_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 oem_data_rsp[OEM_DATA_RSP_SIZE];
+};
+
+#endif
+
+struct wcn36xx_hal_switch_channel_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Channel number */
+       u8 channel_number;
+
+       /* Local power constraint */
+       u8 local_power_constraint;
+
+       /* Secondary channel offset */
+       enum phy_chan_bond_state secondary_channel_offset;
+
+       /* HAL fills in the tx power used for mgmt frames in this field. */
+       u8 tx_mgmt_power;
+
+       /* Max TX power */
+       u8 max_tx_power;
+
+       /* Self STA MAC */
+       u8 self_sta_mac_addr[ETH_ALEN];
+
+       /* VO WIFI comment: BSSID needed to identify session. As the
+        * request has power constraints, this should be applied only to
+        * that session Since MTU timing and EDCA are sessionized, this
+        * struct needs to be sessionized and bssid needs to be out of the
+        * VOWifi feature flag V IMP: Keep bssId field at the end of this
+        * msg. It is used to mantain backward compatbility by way of
+        * ignoring if using new host/old FW or old host/new FW since it is
+        * at the end of this struct
+        */
+       u8 bssid[ETH_ALEN];
+} __packed;
+
+struct wcn36xx_hal_switch_channel_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Status */
+       u32 status;
+
+       /* Channel number - same as in request */
+       u8 channel_number;
+
+       /* HAL fills in the tx power used for mgmt frames in this field */
+       u8 tx_mgmt_power;
+
+       /* BSSID needed to identify session - same as in request */
+       u8 bssid[ETH_ALEN];
+
+} __packed;
+
+struct update_edca_params_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /*BSS Index */
+       u16 bss_index;
+
+       /* Best Effort */
+       struct wcn36xx_hal_edca_param_record acbe;
+
+       /* Background */
+       struct wcn36xx_hal_edca_param_record acbk;
+
+       /* Video */
+       struct wcn36xx_hal_edca_param_record acvi;
+
+       /* Voice */
+       struct wcn36xx_hal_edca_param_record acvo;
+};
+
+struct update_edca_params_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct dpu_stats_params {
+       /* Index of STA to which the statistics */
+       u16 sta_index;
+
+       /* Encryption mode */
+       u8 enc_mode;
+
+       /* status */
+       u32 status;
+
+       /* Statistics */
+       u32 send_blocks;
+       u32 recv_blocks;
+       u32 replays;
+       u8 mic_error_cnt;
+       u32 prot_excl_cnt;
+       u16 format_err_cnt;
+       u16 un_decryptable_cnt;
+       u32 decrypt_err_cnt;
+       u32 decrypt_ok_cnt;
+};
+
+struct wcn36xx_hal_stats_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Valid STA Idx for per STA stats request */
+       u32 sta_id;
+
+       /* Categories of stats requested as specified in eHalStatsMask */
+       u32 stats_mask;
+};
+
+struct ani_summary_stats_info {
+       /* Total number of packets(per AC) that were successfully
+        * transmitted with retries */
+       u32 retry_cnt[4];
+
+       /* The number of MSDU packets and MMPDU frames per AC that the
+        * 802.11 station successfully transmitted after more than one
+        * retransmission attempt */
+       u32 multiple_retry_cnt[4];
+
+       /* Total number of packets(per AC) that were successfully
+        * transmitted (with and without retries, including multi-cast,
+        * broadcast) */
+       u32 tx_frm_cnt[4];
+
+       /* Total number of packets that were successfully received (after
+        * appropriate filter rules including multi-cast, broadcast) */
+       u32 rx_frm_cnt;
+
+       /* Total number of duplicate frames received successfully */
+       u32 frm_dup_cnt;
+
+       /* Total number packets(per AC) failed to transmit */
+       u32 fail_cnt[4];
+
+       /* Total number of RTS/CTS sequence failures for transmission of a
+        * packet */
+       u32 rts_fail_cnt;
+
+       /* Total number packets failed transmit because of no ACK from the
+        * remote entity */
+       u32 ack_fail_cnt;
+
+       /* Total number of RTS/CTS sequence success for transmission of a
+        * packet */
+       u32 rts_succ_cnt;
+
+       /* The sum of the receive error count and dropped-receive-buffer
+        * error count. HAL will provide this as a sum of (FCS error) +
+        * (Fail get BD/PDU in HW) */
+       u32 rx_discard_cnt;
+
+       /*
+        * The receive error count. HAL will provide the RxP FCS error
+        * global counter. */
+       u32 rx_error_cnt;
+
+       /* The sum of the transmit-directed byte count, transmit-multicast
+        * byte count and transmit-broadcast byte count. HAL will sum TPE
+        * UC/MC/BCAST global counters to provide this. */
+       u32 tx_byte_cnt;
+};
+
+/* defines tx_rate_flags */
+enum tx_rate_info {
+       /* Legacy rates */
+       HAL_TX_RATE_LEGACY = 0x1,
+
+       /* HT20 rates */
+       HAL_TX_RATE_HT20 = 0x2,
+
+       /* HT40 rates */
+       HAL_TX_RATE_HT40 = 0x4,
+
+       /* Rate with Short guard interval */
+       HAL_TX_RATE_SGI = 0x8,
+
+       /* Rate with Long guard interval */
+       HAL_TX_RATE_LGI = 0x10
+};
+
+struct ani_global_class_a_stats_info {
+       /* The number of MPDU frames received by the 802.11 station for
+        * MSDU packets or MMPDU frames */
+       u32 rx_frag_cnt;
+
+       /* The number of MPDU frames received by the 802.11 station for
+        * MSDU packets or MMPDU frames when a promiscuous packet filter
+        * was enabled */
+       u32 promiscuous_rx_frag_cnt;
+
+       /* The receiver input sensitivity referenced to a FER of 8% at an
+        * MPDU length of 1024 bytes at the antenna connector. Each element
+        * of the array shall correspond to a supported rate and the order
+        * shall be the same as the supporteRates parameter. */
+       u32 rx_input_sensitivity;
+
+       /* The maximum transmit power in dBm upto one decimal. for eg: if
+        * it is 10.5dBm, the value would be 105 */
+       u32 max_pwr;
+
+       /* Number of times the receiver failed to synchronize with the
+        * incoming signal after detecting the sync in the preamble of the
+        * transmitted PLCP protocol data unit. */
+       u32 sync_fail_cnt;
+
+       /* Legacy transmit rate, in units of 500 kbit/sec, for the most
+        * recently transmitted frame */
+       u32 tx_rate;
+
+       /* mcs index for HT20 and HT40 rates */
+       u32 mcs_index;
+
+       /* to differentiate between HT20 and HT40 rates; short and long
+        * guard interval */
+       u32 tx_rate_flags;
+};
+
+struct ani_global_security_stats {
+       /* The number of unencrypted received MPDU frames that the MAC
+        * layer discarded when the IEEE 802.11 dot11ExcludeUnencrypted
+        * management information base (MIB) object is enabled */
+       u32 rx_wep_unencrypted_frm_cnt;
+
+       /* The number of received MSDU packets that that the 802.11 station
+        * discarded because of MIC failures */
+       u32 rx_mic_fail_cnt;
+
+       /* The number of encrypted MPDU frames that the 802.11 station
+        * failed to decrypt because of a TKIP ICV error */
+       u32 tkip_icv_err;
+
+       /* The number of received MPDU frames that the 802.11 discarded
+        * because of an invalid AES-CCMP format */
+       u32 aes_ccmp_format_err;
+
+       /* The number of received MPDU frames that the 802.11 station
+        * discarded because of the AES-CCMP replay protection procedure */
+       u32 aes_ccmp_replay_cnt;
+
+       /* The number of received MPDU frames that the 802.11 station
+        * discarded because of errors detected by the AES-CCMP decryption
+        * algorithm */
+       u32 aes_ccmp_decrpt_err;
+
+       /* The number of encrypted MPDU frames received for which a WEP
+        * decryption key was not available on the 802.11 station */
+       u32 wep_undecryptable_cnt;
+
+       /* The number of encrypted MPDU frames that the 802.11 station
+        * failed to decrypt because of a WEP ICV error */
+       u32 wep_icv_err;
+
+       /* The number of received encrypted packets that the 802.11 station
+        * successfully decrypted */
+       u32 rx_decrypt_succ_cnt;
+
+       /* The number of encrypted packets that the 802.11 station failed
+        * to decrypt */
+       u32 rx_decrypt_fail_cnt;
+};
+
+struct ani_global_class_b_stats_info {
+       struct ani_global_security_stats uc_stats;
+       struct ani_global_security_stats mc_bc_stats;
+};
+
+struct ani_global_class_c_stats_info {
+       /* This counter shall be incremented for a received A-MSDU frame
+        * with the stations MAC address in the address 1 field or an
+        * A-MSDU frame with a group address in the address 1 field */
+       u32 rx_amsdu_cnt;
+
+       /* This counter shall be incremented when the MAC receives an AMPDU
+        * from the PHY */
+       u32 rx_ampdu_cnt;
+
+       /* This counter shall be incremented when a Frame is transmitted
+        * only on the primary channel */
+       u32 tx_20_frm_cnt;
+
+       /* This counter shall be incremented when a Frame is received only
+        * on the primary channel */
+       u32 rx_20_frm_cnt;
+
+       /* This counter shall be incremented by the number of MPDUs
+        * received in the A-MPDU when an A-MPDU is received */
+       u32 rx_mpdu_in_ampdu_cnt;
+
+       /* This counter shall be incremented when an MPDU delimiter has a
+        * CRC error when this is the first CRC error in the received AMPDU
+        * or when the previous delimiter has been decoded correctly */
+       u32 ampdu_delimiter_crc_err;
+};
+
+struct ani_per_sta_stats_info {
+       /* The number of MPDU frames that the 802.11 station transmitted
+        * and acknowledged through a received 802.11 ACK frame */
+       u32 tx_frag_cnt[4];
+
+       /* This counter shall be incremented when an A-MPDU is transmitted */
+       u32 tx_ampdu_cnt;
+
+       /* This counter shall increment by the number of MPDUs in the AMPDU
+        * when an A-MPDU is transmitted */
+       u32 tx_mpdu_in_ampdu_cnt;
+};
+
+struct wcn36xx_hal_stats_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Success or Failure */
+       u32 status;
+
+       /* STA Idx */
+       u32 sta_index;
+
+       /* Categories of STATS being returned as per eHalStatsMask */
+       u32 stats_mask;
+
+       /* message type is same as the request type */
+       u16 msg_type;
+
+       /* length of the entire request, includes the pStatsBuf length too */
+       u16 msg_len;
+};
+
+struct wcn36xx_hal_set_link_state_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bssid[ETH_ALEN];
+       enum wcn36xx_hal_link_state state;
+       u8 self_mac_addr[ETH_ALEN];
+
+} __packed;
+
+struct set_link_state_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+/* TSPEC Params */
+struct wcn36xx_hal_ts_info_tfc {
+#ifndef ANI_LITTLE_BIT_ENDIAN
+       u16 ackPolicy:2;
+       u16 userPrio:3;
+       u16 psb:1;
+       u16 aggregation:1;
+       u16 accessPolicy:2;
+       u16 direction:2;
+       u16 tsid:4;
+       u16 trafficType:1;
+#else
+       u16 trafficType:1;
+       u16 tsid:4;
+       u16 direction:2;
+       u16 accessPolicy:2;
+       u16 aggregation:1;
+       u16 psb:1;
+       u16 userPrio:3;
+       u16 ackPolicy:2;
+#endif
+};
+
+/* Flag to schedule the traffic type */
+struct wcn36xx_hal_ts_info_sch {
+#ifndef ANI_LITTLE_BIT_ENDIAN
+       u8 rsvd:7;
+       u8 schedule:1;
+#else
+       u8 schedule:1;
+       u8 rsvd:7;
+#endif
+};
+
+/* Traffic and scheduling info */
+struct wcn36xx_hal_ts_info {
+       struct wcn36xx_hal_ts_info_tfc traffic;
+       struct wcn36xx_hal_ts_info_sch schedule;
+};
+
+/* Information elements */
+struct wcn36xx_hal_tspec_ie {
+       u8 type;
+       u8 length;
+       struct wcn36xx_hal_ts_info ts_info;
+       u16 nom_msdu_size;
+       u16 max_msdu_size;
+       u32 min_svc_interval;
+       u32 max_svc_interval;
+       u32 inact_interval;
+       u32 suspend_interval;
+       u32 svc_start_time;
+       u32 min_data_rate;
+       u32 mean_data_rate;
+       u32 peak_data_rate;
+       u32 max_burst_sz;
+       u32 delay_bound;
+       u32 min_phy_rate;
+       u16 surplus_bw;
+       u16 medium_time;
+};
+
+struct add_ts_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index */
+       u16 sta_index;
+
+       /* TSPEC handler uniquely identifying a TSPEC for a STA in a BSS */
+       u16 tspec_index;
+
+       /* To program TPE with required parameters */
+       struct wcn36xx_hal_tspec_ie tspec;
+
+       /* U-APSD Flags: 1b per AC.  Encoded as follows:
+          b7 b6 b5 b4 b3 b2 b1 b0 =
+          X  X  X  X  BE BK VI VO */
+       u8 uapsd;
+
+       /* These parameters are for all the access categories */
+
+       /* Service Interval */
+       u32 service_interval[WCN36XX_HAL_MAX_AC];
+
+       /* Suspend Interval */
+       u32 suspend_interval[WCN36XX_HAL_MAX_AC];
+
+       /* Delay Interval */
+       u32 delay_interval[WCN36XX_HAL_MAX_AC];
+};
+
+struct add_rs_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct del_ts_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index */
+       u16 sta_index;
+
+       /* TSPEC identifier uniquely identifying a TSPEC for a STA in a BSS */
+       u16 tspec_index;
+
+       /* To lookup station id using the mac address */
+       u8 bssid[ETH_ALEN];
+};
+
+struct del_ts_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+/* End of TSpec Parameters */
+
+/* Start of BLOCK ACK related Parameters */
+
+struct wcn36xx_hal_add_ba_session_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index */
+       u16 sta_index;
+
+       /* Peer MAC Address */
+       u8 mac_addr[ETH_ALEN];
+
+       /* ADDBA Action Frame dialog token
+          HAL will not interpret this object */
+       u8 dialog_token;
+
+       /* TID for which the BA is being setup
+          This identifies the TC or TS of interest */
+       u8 tid;
+
+       /* 0 - Delayed BA (Not supported)
+          1 - Immediate BA */
+       u8 policy;
+
+       /* Indicates the number of buffers for this TID (baTID)
+          NOTE - This is the requested buffer size. When this
+          is processed by HAL and subsequently by HDD, it is
+          possible that HDD may change this buffer size. Any
+          change in the buffer size should be noted by PE and
+          advertized appropriately in the ADDBA response */
+       u16 buffer_size;
+
+       /* BA timeout in TU's 0 means no timeout will occur */
+       u16 timeout;
+
+       /* b0..b3 - Fragment Number - Always set to 0
+          b4..b15 - Starting Sequence Number of first MSDU
+          for which this BA is setup */
+       u16 ssn;
+
+       /* ADDBA direction
+          1 - Originator
+          0 - Recipient */
+       u8 direction;
+} __packed;
+
+struct wcn36xx_hal_add_ba_session_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* Dialog token */
+       u8 dialog_token;
+
+       /* TID for which the BA session has been setup */
+       u8 ba_tid;
+
+       /* BA Buffer Size allocated for the current BA session */
+       u8 ba_buffer_size;
+
+       u8 ba_session_id;
+
+       /* Reordering Window buffer */
+       u8 win_size;
+
+       /* Station Index to id the sta */
+       u8 sta_index;
+
+       /* Starting Sequence Number */
+       u16 ssn;
+} __packed;
+
+struct wcn36xx_hal_add_ba_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Session Id */
+       u8 session_id;
+
+       /* Reorder Window Size */
+       u8 win_size;
+/* Old FW 1.2.2.4 does not support this*/
+#ifdef FEATURE_ON_CHIP_REORDERING
+       u8 reordering_done_on_chip;
+#endif
+} __packed;
+
+struct wcn36xx_hal_add_ba_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* Dialog token */
+       u8 dialog_token;
+} __packed;
+
+struct add_ba_info {
+       u16 ba_enable:1;
+       u16 starting_seq_num:12;
+       u16 reserved:3;
+};
+
+struct wcn36xx_hal_trigger_ba_rsp_candidate {
+       u8 sta_addr[ETH_ALEN];
+       struct add_ba_info ba_info[STACFG_MAX_TC];
+} __packed;
+
+struct wcn36xx_hal_trigget_ba_req_candidate {
+       u8 sta_index;
+       u8 tid_bitmap;
+} __packed;
+
+struct wcn36xx_hal_trigger_ba_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Session Id */
+       u8 session_id;
+
+       /* baCandidateCnt is followed by trigger BA
+        * Candidate List(tTriggerBaCandidate)
+        */
+       u16 candidate_cnt;
+
+} __packed;
+
+struct wcn36xx_hal_trigger_ba_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* TO SUPPORT BT-AMP */
+       u8 bssid[ETH_ALEN];
+
+       /* success or failure */
+       u32 status;
+
+       /* baCandidateCnt is followed by trigger BA
+        * Rsp Candidate List(tTriggerRspBaCandidate)
+        */
+       u16 candidate_cnt;
+} __packed;
+
+struct wcn36xx_hal_del_ba_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index */
+       u16 sta_index;
+
+       /* TID for which the BA session is being deleted */
+       u8 tid;
+
+       /* DELBA direction
+          1 - Originator
+          0 - Recipient */
+       u8 direction;
+} __packed;
+
+struct wcn36xx_hal_del_ba_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+} __packed;
+
+struct tsm_stats_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Traffic Id */
+       u8 tid;
+
+       u8 bssid[ETH_ALEN];
+};
+
+struct tsm_stats_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /*success or failure */
+       u32 status;
+
+       /* Uplink Packet Queue delay */
+       u16 uplink_pkt_queue_delay;
+
+       /* Uplink Packet Queue delay histogram */
+       u16 uplink_pkt_queue_delay_hist[4];
+
+       /* Uplink Packet Transmit delay */
+       u32 uplink_pkt_tx_delay;
+
+       /* Uplink Packet loss */
+       u16 uplink_pkt_loss;
+
+       /* Uplink Packet count */
+       u16 uplink_pkt_count;
+
+       /* Roaming count */
+       u8 roaming_count;
+
+       /* Roaming Delay */
+       u16 roaming_delay;
+};
+
+struct set_key_done_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /*bssid of the keys */
+       u8 bssidx;
+       u8 enc_type;
+};
+
+struct wcn36xx_hal_nv_img_download_req_msg {
+       /* Note: The length specified in wcn36xx_hal_nv_img_download_req_msg
+        * messages should be
+        * header.len = sizeof(wcn36xx_hal_nv_img_download_req_msg) +
+        * nv_img_buffer_size */
+       struct wcn36xx_hal_msg_header header;
+
+       /* Fragment sequence number of the NV Image. Note that NV Image
+        * might not fit into one message due to size limitation of the SMD
+        * channel FIFO. UMAC can hence choose to chop the NV blob into
+        * multiple fragments starting with seqeunce number 0, 1, 2 etc.
+        * The last fragment MUST be indicated by marking the
+        * isLastFragment field to 1. Note that all the NV blobs would be
+        * concatenated together by HAL without any padding bytes in
+        * between.*/
+       u16 frag_number;
+
+       /* Is this the last fragment? When set to 1 it indicates that no
+        * more fragments will be sent by UMAC and HAL can concatenate all
+        * the NV blobs rcvd & proceed with the parsing. HAL would generate
+        * a WCN36XX_HAL_DOWNLOAD_NV_RSP to the WCN36XX_HAL_DOWNLOAD_NV_REQ
+        * after it receives each fragment */
+       u16 last_fragment;
+
+       /* NV Image size (number of bytes) */
+       u32 nv_img_buffer_size;
+
+       /* Following the 'nv_img_buffer_size', there should be
+        * nv_img_buffer_size bytes of NV Image i.e.
+        * u8[nv_img_buffer_size] */
+} __packed;
+
+struct wcn36xx_hal_nv_img_download_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Success or Failure. HAL would generate a
+        * WCN36XX_HAL_DOWNLOAD_NV_RSP after each fragment */
+       u32 status;
+} __packed;
+
+struct wcn36xx_hal_nv_store_ind {
+       /* Note: The length specified in tHalNvStoreInd messages should be
+        * header.msgLen = sizeof(tHalNvStoreInd) + nvBlobSize */
+       struct wcn36xx_hal_msg_header header;
+
+       /* NV Item */
+       u32 table_id;
+
+       /* Size of NV Blob */
+       u32 nv_blob_size;
+
+       /* Following the 'nvBlobSize', there should be nvBlobSize bytes of
+        * NV blob i.e. u8[nvBlobSize] */
+};
+
+/* End of Block Ack Related Parameters */
+
+#define WCN36XX_HAL_CIPHER_SEQ_CTR_SIZE 6
+
+/* Definition for MIC failure indication MAC reports this each time a MIC
+ * failure occures on Rx TKIP packet
+ */
+struct mic_failure_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bssid[ETH_ALEN];
+
+       /* address used to compute MIC */
+       u8 src_addr[ETH_ALEN];
+
+       /* transmitter address */
+       u8 ta_addr[ETH_ALEN];
+
+       u8 dst_addr[ETH_ALEN];
+
+       u8 multicast;
+
+       /* first byte of IV */
+       u8 iv1;
+
+       /* second byte of IV */
+       u8 key_id;
+
+       /* sequence number */
+       u8 tsc[WCN36XX_HAL_CIPHER_SEQ_CTR_SIZE];
+
+       /* receive address */
+       u8 rx_addr[ETH_ALEN];
+};
+
+struct update_vht_op_mode_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u16 op_mode;
+       u16 sta_id;
+};
+
+struct update_vht_op_mode_params_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u32 status;
+};
+
+struct update_beacon_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bss_index;
+
+       /* shortPreamble mode. HAL should update all the STA rates when it
+        * receives this message */
+       u8 short_preamble;
+
+       /* short Slot time. */
+       u8 short_slot_time;
+
+       /* Beacon Interval */
+       u16 beacon_interval;
+
+       /* Protection related */
+       u8 lla_coexist;
+       u8 llb_coexist;
+       u8 llg_coexist;
+       u8 ht20_coexist;
+       u8 lln_non_gf_coexist;
+       u8 lsig_tx_op_protection_full_support;
+       u8 rifs_mode;
+
+       u16 param_change_bitmap;
+};
+
+struct update_beacon_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       u32 status;
+};
+
+struct wcn36xx_hal_send_beacon_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* length of the template. */
+       u32 beacon_length;
+
+       /* Beacon data. */
+       u8 beacon[BEACON_TEMPLATE_SIZE];
+
+       u8 bssid[ETH_ALEN];
+
+       /* TIM IE offset from the beginning of the template. */
+       u32 tim_ie_offset;
+
+       /* P2P IE offset from the begining of the template */
+       u16 p2p_ie_offset;
+} __packed;
+
+struct send_beacon_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       u32 status;
+} __packed;
+
+struct enable_radar_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bssid[ETH_ALEN];
+       u8 channel;
+};
+
+struct enable_radar_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Link Parameters */
+       u8 bssid[ETH_ALEN];
+
+       /* success or failure */
+       u32 status;
+};
+
+struct radar_detect_intr_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 radar_det_channel;
+};
+
+struct radar_detect_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* channel number in which the RADAR detected */
+       u8 channel_number;
+
+       /* RADAR pulse width in usecond */
+       u16 radar_pulse_width;
+
+       /* Number of RADAR pulses */
+       u16 num_radar_pulse;
+};
+
+struct wcn36xx_hal_get_tpc_report_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 sta[ETH_ALEN];
+       u8 dialog_token;
+       u8 txpower;
+};
+
+struct wcn36xx_hal_get_tpc_report_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_send_probe_resp_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 probe_resp_template[BEACON_TEMPLATE_SIZE];
+       u32 probe_resp_template_len;
+       u32 proxy_probe_req_valid_ie_bmap[8];
+       u8 bssid[ETH_ALEN];
+};
+
+struct send_probe_resp_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct send_unknown_frame_rx_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_delete_sta_context_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u16 aid;
+       u16 sta_id;
+
+       /* TO SUPPORT BT-AMP */
+       u8 bssid[ETH_ALEN];
+
+       /* HAL copies bssid from the sta table. */
+       u8 addr2[ETH_ALEN];
+
+       /* To unify the keepalive / unknown A2 / tim-based disa */
+       u16 reason_code;
+} __packed;
+
+struct indicate_del_sta {
+       struct wcn36xx_hal_msg_header header;
+       u8 aid;
+       u8 sta_index;
+       u8 bss_index;
+       u8 reason_code;
+       u32 status;
+};
+
+struct bt_amp_event_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       enum bt_amp_event_type btAmpEventType;
+};
+
+struct bt_amp_event_rsp {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct tl_hal_flush_ac_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index. originates from HAL */
+       u8 sta_id;
+
+       /* TID for which the transmit queue is being flushed */
+       u8 tid;
+};
+
+struct tl_hal_flush_ac_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index. originates from HAL */
+       u8 sta_id;
+
+       /* TID for which the transmit queue is being flushed */
+       u8 tid;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_enter_imps_req_msg {
+       struct wcn36xx_hal_msg_header header;
+};
+
+struct wcn36xx_hal_exit_imps_req {
+       struct wcn36xx_hal_msg_header header;
+};
+
+struct wcn36xx_hal_enter_bmps_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bss_index;
+
+       /* TBTT value derived from the last beacon */
+#ifndef BUILD_QWPTTSTATIC
+       u64 tbtt;
+#endif
+       u8 dtim_count;
+
+       /* DTIM period given to HAL during association may not be valid, if
+        * association is based on ProbeRsp instead of beacon. */
+       u8 dtim_period;
+
+       /* For CCX and 11R Roaming */
+       u32 rssi_filter_period;
+
+       u32 num_beacon_per_rssi_average;
+       u8 rssi_filter_enable;
+} __packed;
+
+struct wcn36xx_hal_exit_bmps_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 send_data_null;
+       u8 bss_index;
+} __packed;
+
+struct wcn36xx_hal_missed_beacon_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bss_index;
+} __packed;
+
+/* Beacon Filtering data structures */
+
+/* The above structure would be followed by multiple of below mentioned
+ * structure
+ */
+struct beacon_filter_ie {
+       u8 element_id;
+       u8 check_ie_presence;
+       u8 offset;
+       u8 value;
+       u8 bitmask;
+       u8 ref;
+};
+
+struct wcn36xx_hal_add_bcn_filter_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u16 capability_info;
+       u16 capability_mask;
+       u16 beacon_interval;
+       u16 ie_num;
+       u8 bss_index;
+       u8 reserved;
+};
+
+struct wcn36xx_hal_rem_bcn_filter_req {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 ie_Count;
+       u8 rem_ie_id[1];
+};
+
+#define WCN36XX_HAL_IPV4_ARP_REPLY_OFFLOAD                  0
+#define WCN36XX_HAL_IPV6_NEIGHBOR_DISCOVERY_OFFLOAD         1
+#define WCN36XX_HAL_IPV6_NS_OFFLOAD                         2
+#define WCN36XX_HAL_IPV6_ADDR_LEN                           16
+#define WCN36XX_HAL_OFFLOAD_DISABLE                         0
+#define WCN36XX_HAL_OFFLOAD_ENABLE                          1
+#define WCN36XX_HAL_OFFLOAD_BCAST_FILTER_ENABLE             0x2
+#define WCN36XX_HAL_OFFLOAD_ARP_AND_BCAST_FILTER_ENABLE        \
+       (HAL_OFFLOAD_ENABLE|HAL_OFFLOAD_BCAST_FILTER_ENABLE)
+
+struct wcn36xx_hal_ns_offload_params {
+       u8 src_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN];
+       u8 self_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN];
+
+       /* Only support 2 possible Network Advertisement IPv6 address */
+       u8 target_ipv6_addr1[WCN36XX_HAL_IPV6_ADDR_LEN];
+       u8 target_ipv6_addr2[WCN36XX_HAL_IPV6_ADDR_LEN];
+
+       u8 self_addr[ETH_ALEN];
+       u8 src_ipv6_addr_valid:1;
+       u8 target_ipv6_addr1_valid:1;
+       u8 target_ipv6_addr2_valid:1;
+       u8 reserved1:5;
+
+       /* make it DWORD aligned */
+       u8 reserved2;
+
+       /* slot index for this offload */
+       u32 slot_index;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_host_offload_req {
+       u8 offload_Type;
+
+       /* enable or disable */
+       u8 enable;
+
+       union {
+               u8 host_ipv4_addr[4];
+               u8 host_ipv6_addr[WCN36XX_HAL_IPV6_ADDR_LEN];
+       } u;
+};
+
+struct wcn36xx_hal_host_offload_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_host_offload_req host_offload_params;
+       struct wcn36xx_hal_ns_offload_params ns_offload_params;
+};
+
+/* Packet Types. */
+#define WCN36XX_HAL_KEEP_ALIVE_NULL_PKT              1
+#define WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP     2
+
+/* Enable or disable keep alive */
+#define WCN36XX_HAL_KEEP_ALIVE_DISABLE   0
+#define WCN36XX_HAL_KEEP_ALIVE_ENABLE    1
+#define WCN36XX_KEEP_ALIVE_TIME_PERIOD  30 /* unit: s */
+
+/* Keep Alive request. */
+struct wcn36xx_hal_keep_alive_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 packet_type;
+       u32 time_period;
+       u8 host_ipv4_addr[WCN36XX_HAL_IPV4_ADDR_LEN];
+       u8 dest_ipv4_addr[WCN36XX_HAL_IPV4_ADDR_LEN];
+       u8 dest_addr[ETH_ALEN];
+       u8 bss_index;
+} __packed;
+
+struct wcn36xx_hal_rssi_threshold_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       s8 threshold1:8;
+       s8 threshold2:8;
+       s8 threshold3:8;
+       u8 thres1_pos_notify:1;
+       u8 thres1_neg_notify:1;
+       u8 thres2_pos_notify:1;
+       u8 thres2_neg_notify:1;
+       u8 thres3_pos_notify:1;
+       u8 thres3_neg_notify:1;
+       u8 reserved10:2;
+};
+
+struct wcn36xx_hal_enter_uapsd_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bk_delivery:1;
+       u8 be_delivery:1;
+       u8 vi_delivery:1;
+       u8 vo_delivery:1;
+       u8 bk_trigger:1;
+       u8 be_trigger:1;
+       u8 vi_trigger:1;
+       u8 vo_trigger:1;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_exit_uapsd_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       u8 bss_index;
+};
+
+#define WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE 128
+#define WCN36XX_HAL_WOWL_BCAST_MAX_NUM_PATTERNS 16
+
+struct wcn36xx_hal_wowl_add_bcast_ptrn_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Pattern ID */
+       u8 id;
+
+       /* Pattern byte offset from beginning of the 802.11 packet to start
+        * of the wake-up pattern */
+       u8 byte_Offset;
+
+       /* Non-Zero Pattern size */
+       u8 size;
+
+       /* Pattern */
+       u8 pattern[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE];
+
+       /* Non-zero pattern mask size */
+       u8 mask_size;
+
+       /* Pattern mask */
+       u8 mask[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE];
+
+       /* Extra pattern */
+       u8 extra[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE];
+
+       /* Extra pattern mask */
+       u8 mask_extra[WCN36XX_HAL_WOWL_BCAST_PATTERN_MAX_SIZE];
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_wow_del_bcast_ptrn_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Pattern ID of the wakeup pattern to be deleted */
+       u8 id;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_wowl_enter_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Enables/disables magic packet filtering */
+       u8 magic_packet_enable;
+
+       /* Magic pattern */
+       u8 magic_pattern[ETH_ALEN];
+
+       /* Enables/disables packet pattern filtering in firmware. Enabling
+        * this flag enables broadcast pattern matching in Firmware. If
+        * unicast pattern matching is also desired,
+        * ucUcastPatternFilteringEnable flag must be set tot true as well
+        */
+       u8 pattern_filtering_enable;
+
+       /* Enables/disables unicast packet pattern filtering. This flag
+        * specifies whether we want to do pattern match on unicast packets
+        * as well and not just broadcast packets. This flag has no effect
+        * if the ucPatternFilteringEnable (main controlling flag) is set
+        * to false
+        */
+       u8 ucast_pattern_filtering_enable;
+
+       /* This configuration is valid only when magicPktEnable=1. It
+        * requests hardware to wake up when it receives the Channel Switch
+        * Action Frame.
+        */
+       u8 wow_channel_switch_receive;
+
+       /* This configuration is valid only when magicPktEnable=1. It
+        * requests hardware to wake up when it receives the
+        * Deauthentication Frame.
+        */
+       u8 wow_deauth_receive;
+
+       /* This configuration is valid only when magicPktEnable=1. It
+        * requests hardware to wake up when it receives the Disassociation
+        * Frame.
+        */
+       u8 wow_disassoc_receive;
+
+       /* This configuration is valid only when magicPktEnable=1. It
+        * requests hardware to wake up when it has missed consecutive
+        * beacons. This is a hardware register configuration (NOT a
+        * firmware configuration).
+        */
+       u8 wow_max_missed_beacons;
+
+       /* This configuration is valid only when magicPktEnable=1. This is
+        * a timeout value in units of microsec. It requests hardware to
+        * unconditionally wake up after it has stayed in WoWLAN mode for
+        * some time. Set 0 to disable this feature.
+        */
+       u8 wow_max_sleep;
+
+       /* This configuration directs the WoW packet filtering to look for
+        * EAP-ID requests embedded in EAPOL frames and use this as a wake
+        * source.
+        */
+       u8 wow_eap_id_request_enable;
+
+       /* This configuration directs the WoW packet filtering to look for
+        * EAPOL-4WAY requests and use this as a wake source.
+        */
+       u8 wow_eapol_4way_enable;
+
+       /* This configuration allows a host wakeup on an network scan
+        * offload match.
+        */
+       u8 wow_net_scan_offload_match;
+
+       /* This configuration allows a host wakeup on any GTK rekeying
+        * error.
+        */
+       u8 wow_gtk_rekey_error;
+
+       /* This configuration allows a host wakeup on BSS connection loss.
+        */
+       u8 wow_bss_connection_loss;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_wowl_exit_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_get_rssi_req_msg {
+       struct wcn36xx_hal_msg_header header;
+};
+
+struct wcn36xx_hal_get_roam_rssi_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Valid STA Idx for per STA stats request */
+       u32 sta_id;
+};
+
+struct wcn36xx_hal_set_uapsd_ac_params_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* STA index */
+       u8 sta_idx;
+
+       /* Access Category */
+       u8 ac;
+
+       /* User Priority */
+       u8 up;
+
+       /* Service Interval */
+       u32 service_interval;
+
+       /* Suspend Interval */
+       u32 suspend_interval;
+
+       /* Delay Interval */
+       u32 delay_interval;
+};
+
+struct wcn36xx_hal_configure_rxp_filter_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 set_mcst_bcst_filter_setting;
+       u8 set_mcst_bcst_filter;
+};
+
+struct wcn36xx_hal_enter_imps_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_exit_imps_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_enter_bmps_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 bss_index;
+} __packed;
+
+struct wcn36xx_hal_exit_bmps_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 bss_index;
+} __packed;
+
+struct wcn36xx_hal_enter_uapsd_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_exit_uapsd_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_rssi_notification_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u32 rssi_thres1_pos_cross:1;
+       u32 rssi_thres1_neg_cross:1;
+       u32 rssi_thres2_pos_cross:1;
+       u32 rssi_thres2_neg_cross:1;
+       u32 rssi_thres3_pos_cross:1;
+       u32 rssi_thres3_neg_cross:1;
+       u32 avg_rssi:8;
+       u32 reserved:18;
+
+};
+
+struct wcn36xx_hal_get_rssio_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+       s8 rssi;
+
+};
+
+struct wcn36xx_hal_get_roam_rssi_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 sta_id;
+       s8 rssi;
+};
+
+struct wcn36xx_hal_wowl_enter_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_wowl_exit_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_add_bcn_filter_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_rem_bcn_filter_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_add_wowl_bcast_ptrn_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_del_wowl_bcast_ptrn_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_host_offload_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_keep_alive_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_set_rssi_thresh_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_set_uapsd_ac_params_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_configure_rxp_filter_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct set_max_tx_pwr_req {
+       struct wcn36xx_hal_msg_header header;
+
+       /* BSSID is needed to identify which session issued this request.
+        * As the request has power constraints, this should be applied
+        * only to that session */
+       u8 bssid[ETH_ALEN];
+
+       u8 self_addr[ETH_ALEN];
+
+       /* In request, power == MaxTx power to be used. */
+       u8 power;
+};
+
+struct set_max_tx_pwr_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* power == tx power used for management frames */
+       u8 power;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct set_tx_pwr_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* TX Power in milli watts */
+       u32 tx_power;
+
+       u8 bss_index;
+};
+
+struct set_tx_pwr_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct get_tx_pwr_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 sta_id;
+};
+
+struct get_tx_pwr_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* TX Power in milli watts */
+       u32 tx_power;
+};
+
+struct set_p2p_gonoa_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 opp_ps;
+       u32 ct_window;
+       u8 count;
+       u32 duration;
+       u32 interval;
+       u32 single_noa_duration;
+       u8 ps_selection;
+};
+
+struct set_p2p_gonoa_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_add_sta_self_req {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 self_addr[ETH_ALEN];
+       u32 status;
+} __packed;
+
+struct wcn36xx_hal_add_sta_self_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* Self STA Index */
+       u8 self_sta_index;
+
+       /* DPU Index (IGTK, PTK, GTK all same) */
+       u8 dpu_index;
+
+       /* DPU Signature */
+       u8 dpu_signature;
+} __packed;
+
+struct wcn36xx_hal_del_sta_self_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 self_addr[ETH_ALEN];
+} __packed;
+
+struct wcn36xx_hal_del_sta_self_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /*success or failure */
+       u32 status;
+
+       u8 self_addr[ETH_ALEN];
+} __packed;
+
+struct aggr_add_ts_req {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Station Index */
+       u16 sta_idx;
+
+       /* TSPEC handler uniquely identifying a TSPEC for a STA in a BSS.
+        * This will carry the bitmap with the bit positions representing
+        * different AC.s */
+       u16 tspec_index;
+
+       /* Tspec info per AC To program TPE with required parameters */
+       struct wcn36xx_hal_tspec_ie tspec[WCN36XX_HAL_MAX_AC];
+
+       /* U-APSD Flags: 1b per AC.  Encoded as follows:
+          b7 b6 b5 b4 b3 b2 b1 b0 =
+          X  X  X  X  BE BK VI VO */
+       u8 uapsd;
+
+       /* These parameters are for all the access categories */
+
+       /* Service Interval */
+       u32 service_interval[WCN36XX_HAL_MAX_AC];
+
+       /* Suspend Interval */
+       u32 suspend_interval[WCN36XX_HAL_MAX_AC];
+
+       /* Delay Interval */
+       u32 delay_interval[WCN36XX_HAL_MAX_AC];
+};
+
+struct aggr_add_ts_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status0;
+
+       /* FIXME PRIMA for future use for 11R */
+       u32 status1;
+};
+
+struct wcn36xx_hal_configure_apps_cpu_wakeup_state_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 is_apps_cpu_awake;
+};
+
+struct wcn36xx_hal_configure_apps_cpu_wakeup_state_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_dump_cmd_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u32 arg1;
+       u32 arg2;
+       u32 arg3;
+       u32 arg4;
+       u32 arg5;
+} __packed;
+
+struct wcn36xx_hal_dump_cmd_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* Length of the responce message */
+       u32 rsp_length;
+
+       /* FIXME: Currently considering the the responce will be less than
+        * 100bytes */
+       u8 rsp_buffer[DUMPCMD_RSP_BUFFER];
+} __packed;
+
+#define WLAN_COEX_IND_DATA_SIZE (4)
+#define WLAN_COEX_IND_TYPE_DISABLE_HB_MONITOR (0)
+#define WLAN_COEX_IND_TYPE_ENABLE_HB_MONITOR (1)
+
+struct coex_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Coex Indication Type */
+       u32 type;
+
+       /* Coex Indication Data */
+       u32 data[WLAN_COEX_IND_DATA_SIZE];
+};
+
+struct wcn36xx_hal_tx_compl_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Tx Complete Indication Success or Failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_wlan_host_suspend_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u32 configured_mcst_bcst_filter_setting;
+       u32 active_session_count;
+};
+
+struct wcn36xx_hal_wlan_exclude_unencrpted_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 dot11_exclude_unencrypted;
+       u8 bssid[ETH_ALEN];
+};
+
+struct noa_attr_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 index;
+       u8 opp_ps_flag;
+       u16 ctwin;
+
+       u16 noa1_interval_count;
+       u16 bss_index;
+       u32 noa1_duration;
+       u32 noa1_interval;
+       u32 noa1_starttime;
+
+       u16 noa2_interval_count;
+       u16 reserved2;
+       u32 noa2_duration;
+       u32 noa2_interval;
+       u32 noa2_start_time;
+
+       u32 status;
+};
+
+struct noa_start_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u32 status;
+       u32 bss_index;
+};
+
+struct wcn36xx_hal_wlan_host_resume_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 configured_mcst_bcst_filter_setting;
+};
+
+struct wcn36xx_hal_host_resume_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+struct wcn36xx_hal_del_ba_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u16 sta_idx;
+
+       /* Peer MAC Address, whose BA session has timed out */
+       u8 peer_addr[ETH_ALEN];
+
+       /* TID for which a BA session timeout is being triggered */
+       u8 ba_tid;
+
+       /* DELBA direction
+        * 1 - Originator
+        * 0 - Recipient
+        */
+       u8 direction;
+
+       u32 reason_code;
+
+       /* TO SUPPORT BT-AMP */
+       u8 bssid[ETH_ALEN];
+};
+
+/* PNO Messages */
+
+/* Max number of channels that a network can be found on */
+#define WCN36XX_HAL_PNO_MAX_NETW_CHANNELS  26
+
+/* Max number of channels that a network can be found on */
+#define WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX  60
+
+/* Maximum numbers of networks supported by PNO */
+#define WCN36XX_HAL_PNO_MAX_SUPP_NETWORKS  16
+
+/* The number of scan time intervals that can be programmed into PNO */
+#define WCN36XX_HAL_PNO_MAX_SCAN_TIMERS    10
+
+/* Maximum size of the probe template */
+#define WCN36XX_HAL_PNO_MAX_PROBE_SIZE     450
+
+/* Type of PNO enabling:
+ *
+ * Immediate - scanning will start immediately and PNO procedure will be
+ * repeated based on timer
+ *
+ * Suspend - scanning will start at suspend
+ *
+ * Resume - scanning will start on system resume
+ */
+enum pno_mode {
+       PNO_MODE_IMMEDIATE,
+       PNO_MODE_ON_SUSPEND,
+       PNO_MODE_ON_RESUME,
+       PNO_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* Authentication type */
+enum auth_type {
+       AUTH_TYPE_ANY = 0,
+       AUTH_TYPE_OPEN_SYSTEM = 1,
+
+       /* Upper layer authentication types */
+       AUTH_TYPE_WPA = 2,
+       AUTH_TYPE_WPA_PSK = 3,
+
+       AUTH_TYPE_RSN = 4,
+       AUTH_TYPE_RSN_PSK = 5,
+       AUTH_TYPE_FT_RSN = 6,
+       AUTH_TYPE_FT_RSN_PSK = 7,
+       AUTH_TYPE_WAPI_WAI_CERTIFICATE = 8,
+       AUTH_TYPE_WAPI_WAI_PSK = 9,
+
+       AUTH_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* Encryption type */
+enum ed_type {
+       ED_ANY = 0,
+       ED_NONE = 1,
+       ED_WEP = 2,
+       ED_TKIP = 3,
+       ED_CCMP = 4,
+       ED_WPI = 5,
+
+       ED_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* SSID broadcast  type */
+enum ssid_bcast_type {
+       BCAST_UNKNOWN = 0,
+       BCAST_NORMAL = 1,
+       BCAST_HIDDEN = 2,
+
+       BCAST_TYPE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE
+};
+
+/* The network description for which PNO will have to look for */
+struct network_type {
+       /* SSID of the BSS */
+       struct wcn36xx_hal_mac_ssid ssid;
+
+       /* Authentication type for the network */
+       enum auth_type authentication;
+
+       /* Encryption type for the network */
+       enum ed_type encryption;
+
+       /* Indicate the channel on which the Network can be found 0 - if
+        * all channels */
+       u8 channel_count;
+       u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS];
+
+       /* Indicates the RSSI threshold for the network to be considered */
+       u8 rssi_threshold;
+};
+
+struct scan_timer {
+       /* How much it should wait */
+       u32 value;
+
+       /* How many times it should repeat that wait value 0 - keep using
+        * this timer until PNO is disabled */
+       u32 repeat;
+
+       /* e.g: 2 3 4 0 - it will wait 2s between consecutive scans for 3
+        * times - after that it will wait 4s between consecutive scans
+        * until disabled */
+};
+
+/* The network parameters to be sent to the PNO algorithm */
+struct scan_timers_type {
+       /* set to 0 if you wish for PNO to use its default telescopic timer */
+       u8 count;
+
+       /* A set value represents the amount of time that PNO will wait
+        * between two consecutive scan procedures If the desired is for a
+        * uniform timer that fires always at the exact same interval - one
+        * single value is to be set If there is a desire for a more
+        * complex - telescopic like timer multiple values can be set -
+        * once PNO reaches the end of the array it will continue scanning
+        * at intervals presented by the last value */
+       struct scan_timer values[WCN36XX_HAL_PNO_MAX_SCAN_TIMERS];
+};
+
+/* Preferred network list request */
+struct set_pref_netw_list_req {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Enable PNO */
+       u32 enable;
+
+       /* Immediate,  On Suspend,   On Resume */
+       enum pno_mode mode;
+
+       /* Number of networks sent for PNO */
+       u32 networks_count;
+
+       /* The networks that PNO needs to look for */
+       struct network_type networks[WCN36XX_HAL_PNO_MAX_SUPP_NETWORKS];
+
+       /* The scan timers required for PNO */
+       struct scan_timers_type scan_timers;
+
+       /* Probe template for 2.4GHz band */
+       u16 band_24g_probe_size;
+       u8 band_24g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE];
+
+       /* Probe template for 5GHz band */
+       u16 band_5g_probe_size;
+       u8 band_5g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE];
+};
+
+/* The network description for which PNO will have to look for */
+struct network_type_new {
+       /* SSID of the BSS */
+       struct wcn36xx_hal_mac_ssid ssid;
+
+       /* Authentication type for the network */
+       enum auth_type authentication;
+
+       /* Encryption type for the network */
+       enum ed_type encryption;
+
+       /* SSID broadcast type, normal, hidden or unknown */
+       enum ssid_bcast_type bcast_network_type;
+
+       /* Indicate the channel on which the Network can be found 0 - if
+        * all channels */
+       u8 channel_count;
+       u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS];
+
+       /* Indicates the RSSI threshold for the network to be considered */
+       u8 rssi_threshold;
+};
+
+/* Preferred network list request new */
+struct set_pref_netw_list_req_new {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Enable PNO */
+       u32 enable;
+
+       /* Immediate,  On Suspend,   On Resume */
+       enum pno_mode mode;
+
+       /* Number of networks sent for PNO */
+       u32 networks_count;
+
+       /* The networks that PNO needs to look for */
+       struct network_type_new networks[WCN36XX_HAL_PNO_MAX_SUPP_NETWORKS];
+
+       /* The scan timers required for PNO */
+       struct scan_timers_type scan_timers;
+
+       /* Probe template for 2.4GHz band */
+       u16 band_24g_probe_size;
+       u8 band_24g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE];
+
+       /* Probe template for 5GHz band */
+       u16 band_5g_probe_size;
+       u8 band_5g_probe_template[WCN36XX_HAL_PNO_MAX_PROBE_SIZE];
+};
+
+/* Preferred network list response */
+struct set_pref_netw_list_resp {
+       struct wcn36xx_hal_msg_header header;
+
+       /* status of the request - just to indicate that PNO has
+        * acknowledged the request and will start scanning */
+       u32 status;
+};
+
+/* Preferred network found indication */
+struct pref_netw_found_ind {
+
+       struct wcn36xx_hal_msg_header header;
+
+       /* Network that was found with the highest RSSI */
+       struct wcn36xx_hal_mac_ssid ssid;
+
+       /* Indicates the RSSI */
+       u8 rssi;
+};
+
+/* RSSI Filter request */
+struct set_rssi_filter_req {
+       struct wcn36xx_hal_msg_header header;
+
+       /* RSSI Threshold */
+       u8 rssi_threshold;
+};
+
+/* Set RSSI filter resp */
+struct set_rssi_filter_resp {
+       struct wcn36xx_hal_msg_header header;
+
+       /* status of the request */
+       u32 status;
+};
+
+/* Update scan params - sent from host to PNO to be used during PNO
+ * scanningx */
+struct wcn36xx_hal_update_scan_params_req {
+
+       struct wcn36xx_hal_msg_header header;
+
+       /* Host setting for 11d */
+       u8 dot11d_enabled;
+
+       /* Lets PNO know that host has determined the regulatory domain */
+       u8 dot11d_resolved;
+
+       /* Channels on which PNO is allowed to scan */
+       u8 channel_count;
+       u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS];
+
+       /* Minimum channel time */
+       u16 active_min_ch_time;
+
+       /* Maximum channel time */
+       u16 active_max_ch_time;
+
+       /* Minimum channel time */
+       u16 passive_min_ch_time;
+
+       /* Maximum channel time */
+       u16 passive_max_ch_time;
+
+       /* Cb State */
+       enum phy_chan_bond_state state;
+} __packed;
+
+/* Update scan params - sent from host to PNO to be used during PNO
+ * scanningx */
+struct update_scan_params_req_ex {
+
+       struct wcn36xx_hal_msg_header header;
+
+       /* Host setting for 11d */
+       u8 dot11d_enabled;
+
+       /* Lets PNO know that host has determined the regulatory domain */
+       u8 dot11d_resolved;
+
+       /* Channels on which PNO is allowed to scan */
+       u8 channel_count;
+       u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX];
+
+       /* Minimum channel time */
+       u16 active_min_ch_time;
+
+       /* Maximum channel time */
+       u16 active_max_ch_time;
+
+       /* Minimum channel time */
+       u16 passive_min_ch_time;
+
+       /* Maximum channel time */
+       u16 passive_max_ch_time;
+
+       /* Cb State */
+       enum phy_chan_bond_state state;
+};
+
+/* Update scan params - sent from host to PNO to be used during PNO
+ * scanningx */
+struct wcn36xx_hal_update_scan_params_resp {
+
+       struct wcn36xx_hal_msg_header header;
+
+       /* status of the request */
+       u32 status;
+} __packed;
+
+struct wcn36xx_hal_set_tx_per_tracking_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* 0: disable, 1:enable */
+       u8 tx_per_tracking_enable;
+
+       /* Check period, unit is sec. */
+       u8 tx_per_tracking_period;
+
+       /* (Fail TX packet)/(Total TX packet) ratio, the unit is 10%. */
+       u8 tx_per_tracking_ratio;
+
+       /* A watermark of check number, once the tx packet exceed this
+        * number, we do the check, default is 5 */
+       u32 tx_per_tracking_watermark;
+};
+
+struct wcn36xx_hal_set_tx_per_tracking_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+};
+
+struct tx_per_hit_ind_msg {
+       struct wcn36xx_hal_msg_header header;
+};
+
+/* Packet Filtering Definitions Begin */
+#define    WCN36XX_HAL_PROTOCOL_DATA_LEN                  8
+#define    WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS        240
+#define    WCN36XX_HAL_MAX_NUM_FILTERS                   20
+#define    WCN36XX_HAL_MAX_CMP_PER_FILTER                10
+
+enum wcn36xx_hal_receive_packet_filter_type {
+       HAL_RCV_FILTER_TYPE_INVALID,
+       HAL_RCV_FILTER_TYPE_FILTER_PKT,
+       HAL_RCV_FILTER_TYPE_BUFFER_PKT,
+       HAL_RCV_FILTER_TYPE_MAX_ENUM_SIZE
+};
+
+enum wcn36xx_hal_rcv_pkt_flt_protocol_type {
+       HAL_FILTER_PROTO_TYPE_INVALID,
+       HAL_FILTER_PROTO_TYPE_MAC,
+       HAL_FILTER_PROTO_TYPE_ARP,
+       HAL_FILTER_PROTO_TYPE_IPV4,
+       HAL_FILTER_PROTO_TYPE_IPV6,
+       HAL_FILTER_PROTO_TYPE_UDP,
+       HAL_FILTER_PROTO_TYPE_MAX
+};
+
+enum wcn36xx_hal_rcv_pkt_flt_cmp_flag_type {
+       HAL_FILTER_CMP_TYPE_INVALID,
+       HAL_FILTER_CMP_TYPE_EQUAL,
+       HAL_FILTER_CMP_TYPE_MASK_EQUAL,
+       HAL_FILTER_CMP_TYPE_NOT_EQUAL,
+       HAL_FILTER_CMP_TYPE_MAX
+};
+
+struct wcn36xx_hal_rcv_pkt_filter_params {
+       u8 protocol_layer;
+       u8 cmp_flag;
+
+       /* Length of the data to compare */
+       u16 data_length;
+
+       /* from start of the respective frame header */
+       u8 data_offset;
+
+       /* Reserved field */
+       u8 reserved;
+
+       /* Data to compare */
+       u8 compare_data[WCN36XX_HAL_PROTOCOL_DATA_LEN];
+
+       /* Mask to be applied on the received packet data before compare */
+       u8 data_mask[WCN36XX_HAL_PROTOCOL_DATA_LEN];
+};
+
+struct wcn36xx_hal_sessionized_rcv_pkt_filter_cfg_type {
+       u8 id;
+       u8 type;
+       u8 params_count;
+       u32 coleasce_time;
+       u8 bss_index;
+       struct wcn36xx_hal_rcv_pkt_filter_params params[1];
+};
+
+struct wcn36xx_hal_set_rcv_pkt_filter_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 id;
+       u8 type;
+       u8 params_count;
+       u32 coalesce_time;
+       struct wcn36xx_hal_rcv_pkt_filter_params params[1];
+};
+
+struct wcn36xx_hal_rcv_flt_mc_addr_list_type {
+       /* from start of the respective frame header */
+       u8 data_offset;
+
+       u32 mc_addr_count;
+       u8 mc_addr[ETH_ALEN][WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS];
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_set_pkt_filter_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_match_cnt_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_match_cnt {
+       u8 id;
+       u32 match_cnt;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_match_cnt_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Success or Failure */
+       u32 status;
+
+       u32 match_count;
+       struct wcn36xx_hal_rcv_flt_pkt_match_cnt
+               matches[WCN36XX_HAL_MAX_NUM_FILTERS];
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_clear_param {
+       /* only valid for response message */
+       u32 status;
+       u8 id;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_clear_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_rcv_flt_pkt_clear_param param;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_clear_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_rcv_flt_pkt_clear_param param;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       struct wcn36xx_hal_rcv_flt_mc_addr_list_type mc_addr_list;
+};
+
+struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+       u32 status;
+       u8 bss_index;
+};
+
+/* Packet Filtering Definitions End */
+
+struct wcn36xx_hal_set_power_params_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /*  Ignore DTIM */
+       u32 ignore_dtim;
+
+       /* DTIM Period */
+       u32 dtim_period;
+
+       /* Listen Interval */
+       u32 listen_interval;
+
+       /* Broadcast Multicast Filter  */
+       u32 bcast_mcast_filter;
+
+       /* Beacon Early Termination */
+       u32 enable_bet;
+
+       /* Beacon Early Termination Interval */
+       u32 bet_interval;
+} __packed;
+
+struct wcn36xx_hal_set_power_params_resp {
+
+       struct wcn36xx_hal_msg_header header;
+
+       /* status of the request */
+       u32 status;
+} __packed;
+
+/* Capability bitmap exchange definitions and macros starts */
+
+enum place_holder_in_cap_bitmap {
+       MCC = 0,
+       P2P = 1,
+       DOT11AC = 2,
+       SLM_SESSIONIZATION = 3,
+       DOT11AC_OPMODE = 4,
+       SAP32STA = 5,
+       TDLS = 6,
+       P2P_GO_NOA_DECOUPLE_INIT_SCAN = 7,
+       WLANACTIVE_OFFLOAD = 8,
+       BEACON_OFFLOAD = 9,
+       SCAN_OFFLOAD = 10,
+       ROAM_OFFLOAD = 11,
+       BCN_MISS_OFFLOAD = 12,
+       STA_POWERSAVE = 13,
+       STA_ADVANCED_PWRSAVE = 14,
+       AP_UAPSD = 15,
+       AP_DFS = 16,
+       BLOCKACK = 17,
+       PHY_ERR = 18,
+       BCN_FILTER = 19,
+       RTT = 20,
+       RATECTRL = 21,
+       WOW = 22,
+       MAX_FEATURE_SUPPORTED = 128,
+};
+
+struct wcn36xx_hal_feat_caps_msg {
+
+       struct wcn36xx_hal_msg_header header;
+
+       u32 feat_caps[4];
+} __packed;
+
+/* status codes to help debug rekey failures */
+enum gtk_rekey_status {
+       WCN36XX_HAL_GTK_REKEY_STATUS_SUCCESS = 0,
+
+       /* rekey detected, but not handled */
+       WCN36XX_HAL_GTK_REKEY_STATUS_NOT_HANDLED = 1,
+
+       /* MIC check error on M1 */
+       WCN36XX_HAL_GTK_REKEY_STATUS_MIC_ERROR = 2,
+
+       /* decryption error on M1  */
+       WCN36XX_HAL_GTK_REKEY_STATUS_DECRYPT_ERROR = 3,
+
+       /* M1 replay detected */
+       WCN36XX_HAL_GTK_REKEY_STATUS_REPLAY_ERROR = 4,
+
+       /* missing GTK key descriptor in M1 */
+       WCN36XX_HAL_GTK_REKEY_STATUS_MISSING_KDE = 5,
+
+       /* missing iGTK key descriptor in M1 */
+       WCN36XX_HAL_GTK_REKEY_STATUS_MISSING_IGTK_KDE = 6,
+
+       /* key installation error */
+       WCN36XX_HAL_GTK_REKEY_STATUS_INSTALL_ERROR = 7,
+
+       /* iGTK key installation error */
+       WCN36XX_HAL_GTK_REKEY_STATUS_IGTK_INSTALL_ERROR = 8,
+
+       /* GTK rekey M2 response TX error */
+       WCN36XX_HAL_GTK_REKEY_STATUS_RESP_TX_ERROR = 9,
+
+       /* non-specific general error */
+       WCN36XX_HAL_GTK_REKEY_STATUS_GEN_ERROR = 255
+};
+
+/* wake reason types */
+enum wake_reason_type {
+       WCN36XX_HAL_WAKE_REASON_NONE = 0,
+
+       /* magic packet match */
+       WCN36XX_HAL_WAKE_REASON_MAGIC_PACKET = 1,
+
+       /* host defined pattern match */
+       WCN36XX_HAL_WAKE_REASON_PATTERN_MATCH = 2,
+
+       /* EAP-ID frame detected */
+       WCN36XX_HAL_WAKE_REASON_EAPID_PACKET = 3,
+
+       /* start of EAPOL 4-way handshake detected */
+       WCN36XX_HAL_WAKE_REASON_EAPOL4WAY_PACKET = 4,
+
+       /* network scan offload match */
+       WCN36XX_HAL_WAKE_REASON_NETSCAN_OFFL_MATCH = 5,
+
+       /* GTK rekey status wakeup (see status) */
+       WCN36XX_HAL_WAKE_REASON_GTK_REKEY_STATUS = 6,
+
+       /* BSS connection lost */
+       WCN36XX_HAL_WAKE_REASON_BSS_CONN_LOST = 7,
+};
+
+/*
+  Wake Packet which is saved at tWakeReasonParams.DataStart
+  This data is sent for any wake reasons that involve a packet-based wakeup :
+
+  WCN36XX_HAL_WAKE_REASON_TYPE_MAGIC_PACKET
+  WCN36XX_HAL_WAKE_REASON_TYPE_PATTERN_MATCH
+  WCN36XX_HAL_WAKE_REASON_TYPE_EAPID_PACKET
+  WCN36XX_HAL_WAKE_REASON_TYPE_EAPOL4WAY_PACKET
+  WCN36XX_HAL_WAKE_REASON_TYPE_GTK_REKEY_STATUS
+
+  The information is provided to the host for auditing and debug purposes
+
+*/
+
+/* Wake reason indication */
+struct wcn36xx_hal_wake_reason_ind {
+       struct wcn36xx_hal_msg_header header;
+
+       /* see tWakeReasonType */
+       u32 reason;
+
+       /* argument specific to the reason type */
+       u32 reason_arg;
+
+       /* length of optional data stored in this message, in case HAL
+        * truncates the data (i.e. data packets) this length will be less
+        * than the actual length */
+       u32 stored_data_len;
+
+       /* actual length of data */
+       u32 actual_data_len;
+
+       /* variable length start of data (length == storedDataLen) see
+        * specific wake type */
+       u8 data_start[1];
+
+       u32 bss_index:8;
+       u32 reserved:24;
+};
+
+#define WCN36XX_HAL_GTK_KEK_BYTES 16
+#define WCN36XX_HAL_GTK_KCK_BYTES 16
+
+#define WCN36XX_HAL_GTK_OFFLOAD_FLAGS_DISABLE (1 << 0)
+
+#define GTK_SET_BSS_KEY_TAG  0x1234AA55
+
+struct wcn36xx_hal_gtk_offload_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* optional flags */
+       u32 flags;
+
+       /* Key confirmation key */
+       u8 kck[WCN36XX_HAL_GTK_KCK_BYTES];
+
+       /* key encryption key */
+       u8 kek[WCN36XX_HAL_GTK_KEK_BYTES];
+
+       /* replay counter */
+       u64 key_replay_counter;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_gtk_offload_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_gtk_offload_get_info_req_msg {
+       struct wcn36xx_hal_msg_header header;
+       u8 bss_index;
+};
+
+struct wcn36xx_hal_gtk_offload_get_info_rsp_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+
+       /* last rekey status when the rekey was offloaded */
+       u32 last_rekey_status;
+
+       /* current replay counter value */
+       u64 key_replay_counter;
+
+       /* total rekey attempts */
+       u32 total_rekey_count;
+
+       /* successful GTK rekeys */
+       u32 gtk_rekey_count;
+
+       /* successful iGTK rekeys */
+       u32 igtk_rekey_count;
+
+       u8 bss_index;
+};
+
+struct dhcp_info {
+       /* Indicates the device mode which indicates about the DHCP activity */
+       u8 device_mode;
+
+       u8 addr[ETH_ALEN];
+};
+
+struct dhcp_ind_status {
+       struct wcn36xx_hal_msg_header header;
+
+       /* success or failure */
+       u32 status;
+};
+
+/*
+ *   Thermal Mitigation mode of operation.
+ *
+ *  WCN36XX_HAL_THERMAL_MITIGATION_MODE_0 - Based on AMPDU disabling aggregation
+ *
+ *  WCN36XX_HAL_THERMAL_MITIGATION_MODE_1 - Based on AMPDU disabling aggregation
+ *  and reducing transmit power
+ *
+ *  WCN36XX_HAL_THERMAL_MITIGATION_MODE_2 - Not supported */
+enum wcn36xx_hal_thermal_mitigation_mode_type {
+       HAL_THERMAL_MITIGATION_MODE_INVALID = -1,
+       HAL_THERMAL_MITIGATION_MODE_0,
+       HAL_THERMAL_MITIGATION_MODE_1,
+       HAL_THERMAL_MITIGATION_MODE_2,
+       HAL_THERMAL_MITIGATION_MODE_MAX = WCN36XX_HAL_MAX_ENUM_SIZE,
+};
+
+
+/*
+ *   Thermal Mitigation level.
+ * Note the levels are incremental i.e WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_2 =
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_0 +
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_1
+ *
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_0 - lowest level of thermal mitigation.
+ * This level indicates normal mode of operation
+ *
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_1 - 1st level of thermal mitigation
+ *
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_2 - 2nd level of thermal mitigation
+ *
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_3 - 3rd level of thermal mitigation
+ *
+ * WCN36XX_HAL_THERMAL_MITIGATION_LEVEL_4 - 4th level of thermal mitigation
+ */
+enum wcn36xx_hal_thermal_mitigation_level_type {
+       HAL_THERMAL_MITIGATION_LEVEL_INVALID = -1,
+       HAL_THERMAL_MITIGATION_LEVEL_0,
+       HAL_THERMAL_MITIGATION_LEVEL_1,
+       HAL_THERMAL_MITIGATION_LEVEL_2,
+       HAL_THERMAL_MITIGATION_LEVEL_3,
+       HAL_THERMAL_MITIGATION_LEVEL_4,
+       HAL_THERMAL_MITIGATION_LEVEL_MAX = WCN36XX_HAL_MAX_ENUM_SIZE,
+};
+
+
+/* WCN36XX_HAL_SET_THERMAL_MITIGATION_REQ */
+struct set_thermal_mitigation_req_msg {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Thermal Mitigation Operation Mode */
+       enum wcn36xx_hal_thermal_mitigation_mode_type mode;
+
+       /* Thermal Mitigation Level */
+       enum wcn36xx_hal_thermal_mitigation_level_type level;
+};
+
+struct set_thermal_mitigation_resp {
+
+       struct wcn36xx_hal_msg_header header;
+
+       /* status of the request */
+       u32 status;
+};
+
+/* Per STA Class B Statistics. Class B statistics are STA TX/RX stats
+ * provided to FW from Host via periodic messages */
+struct stats_class_b_ind {
+       struct wcn36xx_hal_msg_header header;
+
+       /* Duration over which this stats was collected */
+       u32 duration;
+
+       /* Per STA Stats */
+
+       /* TX stats */
+       u32 tx_bytes_pushed;
+       u32 tx_packets_pushed;
+
+       /* RX stats */
+       u32 rx_bytes_rcvd;
+       u32 rx_packets_rcvd;
+       u32 rx_time_total;
+};
+
+#endif /* _HAL_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
new file mode 100644 (file)
index 0000000..7839b31
--- /dev/null
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "wcn36xx.h"
+
+unsigned int wcn36xx_dbg_mask;
+module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);
+MODULE_PARM_DESC(debug_mask, "Debugging mask");
+
+#define CHAN2G(_freq, _idx) { \
+       .band = IEEE80211_BAND_2GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 25, \
+}
+
+#define CHAN5G(_freq, _idx) { \
+       .band = IEEE80211_BAND_5GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_idx), \
+       .max_power = 25, \
+}
+
+/* The wcn firmware expects channel values to matching
+ * their mnemonic values. So use these for .hw_value. */
+static struct ieee80211_channel wcn_2ghz_channels[] = {
+       CHAN2G(2412, 1), /* Channel 1 */
+       CHAN2G(2417, 2), /* Channel 2 */
+       CHAN2G(2422, 3), /* Channel 3 */
+       CHAN2G(2427, 4), /* Channel 4 */
+       CHAN2G(2432, 5), /* Channel 5 */
+       CHAN2G(2437, 6), /* Channel 6 */
+       CHAN2G(2442, 7), /* Channel 7 */
+       CHAN2G(2447, 8), /* Channel 8 */
+       CHAN2G(2452, 9), /* Channel 9 */
+       CHAN2G(2457, 10), /* Channel 10 */
+       CHAN2G(2462, 11), /* Channel 11 */
+       CHAN2G(2467, 12), /* Channel 12 */
+       CHAN2G(2472, 13), /* Channel 13 */
+       CHAN2G(2484, 14)  /* Channel 14 */
+
+};
+
+static struct ieee80211_channel wcn_5ghz_channels[] = {
+       CHAN5G(5180, 36),
+       CHAN5G(5200, 40),
+       CHAN5G(5220, 44),
+       CHAN5G(5240, 48),
+       CHAN5G(5260, 52),
+       CHAN5G(5280, 56),
+       CHAN5G(5300, 60),
+       CHAN5G(5320, 64),
+       CHAN5G(5500, 100),
+       CHAN5G(5520, 104),
+       CHAN5G(5540, 108),
+       CHAN5G(5560, 112),
+       CHAN5G(5580, 116),
+       CHAN5G(5600, 120),
+       CHAN5G(5620, 124),
+       CHAN5G(5640, 128),
+       CHAN5G(5660, 132),
+       CHAN5G(5700, 140),
+       CHAN5G(5745, 149),
+       CHAN5G(5765, 153),
+       CHAN5G(5785, 157),
+       CHAN5G(5805, 161),
+       CHAN5G(5825, 165)
+};
+
+#define RATE(_bitrate, _hw_rate, _flags) { \
+       .bitrate        = (_bitrate),                   \
+       .flags          = (_flags),                     \
+       .hw_value       = (_hw_rate),                   \
+       .hw_value_short = (_hw_rate)  \
+}
+
+static struct ieee80211_rate wcn_2ghz_rates[] = {
+       RATE(10, HW_RATE_INDEX_1MBPS, 0),
+       RATE(20, HW_RATE_INDEX_2MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(55, HW_RATE_INDEX_5_5MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(110, HW_RATE_INDEX_11MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
+       RATE(60, HW_RATE_INDEX_6MBPS, 0),
+       RATE(90, HW_RATE_INDEX_9MBPS, 0),
+       RATE(120, HW_RATE_INDEX_12MBPS, 0),
+       RATE(180, HW_RATE_INDEX_18MBPS, 0),
+       RATE(240, HW_RATE_INDEX_24MBPS, 0),
+       RATE(360, HW_RATE_INDEX_36MBPS, 0),
+       RATE(480, HW_RATE_INDEX_48MBPS, 0),
+       RATE(540, HW_RATE_INDEX_54MBPS, 0)
+};
+
+static struct ieee80211_rate wcn_5ghz_rates[] = {
+       RATE(60, HW_RATE_INDEX_6MBPS, 0),
+       RATE(90, HW_RATE_INDEX_9MBPS, 0),
+       RATE(120, HW_RATE_INDEX_12MBPS, 0),
+       RATE(180, HW_RATE_INDEX_18MBPS, 0),
+       RATE(240, HW_RATE_INDEX_24MBPS, 0),
+       RATE(360, HW_RATE_INDEX_36MBPS, 0),
+       RATE(480, HW_RATE_INDEX_48MBPS, 0),
+       RATE(540, HW_RATE_INDEX_54MBPS, 0)
+};
+
+static struct ieee80211_supported_band wcn_band_2ghz = {
+       .channels       = wcn_2ghz_channels,
+       .n_channels     = ARRAY_SIZE(wcn_2ghz_channels),
+       .bitrates       = wcn_2ghz_rates,
+       .n_bitrates     = ARRAY_SIZE(wcn_2ghz_rates),
+       .ht_cap         = {
+               .cap =  IEEE80211_HT_CAP_GRN_FLD |
+                       IEEE80211_HT_CAP_SGI_20 |
+                       IEEE80211_HT_CAP_DSSSCCK40 |
+                       IEEE80211_HT_CAP_LSIG_TXOP_PROT,
+               .ht_supported = true,
+               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+               .mcs = {
+                       .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+                       .rx_highest = cpu_to_le16(72),
+                       .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+               }
+       }
+};
+
+static struct ieee80211_supported_band wcn_band_5ghz = {
+       .channels       = wcn_5ghz_channels,
+       .n_channels     = ARRAY_SIZE(wcn_5ghz_channels),
+       .bitrates       = wcn_5ghz_rates,
+       .n_bitrates     = ARRAY_SIZE(wcn_5ghz_rates),
+       .ht_cap         = {
+               .cap =  IEEE80211_HT_CAP_GRN_FLD |
+                       IEEE80211_HT_CAP_SGI_20 |
+                       IEEE80211_HT_CAP_DSSSCCK40 |
+                       IEEE80211_HT_CAP_LSIG_TXOP_PROT |
+                       IEEE80211_HT_CAP_SGI_40 |
+                       IEEE80211_HT_CAP_SUP_WIDTH_20_40,
+               .ht_supported = true,
+               .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
+               .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
+               .mcs = {
+                       .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
+                       .rx_highest = cpu_to_le16(72),
+                       .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
+               }
+       }
+};
+
+#ifdef CONFIG_PM
+
+static const struct wiphy_wowlan_support wowlan_support = {
+       .flags = WIPHY_WOWLAN_ANY
+};
+
+#endif
+
+static inline u8 get_sta_index(struct ieee80211_vif *vif,
+                              struct wcn36xx_sta *sta_priv)
+{
+       return NL80211_IFTYPE_STATION == vif->type ?
+              sta_priv->bss_sta_index :
+              sta_priv->sta_index;
+}
+
+static int wcn36xx_start(struct ieee80211_hw *hw)
+{
+       struct wcn36xx *wcn = hw->priv;
+       int ret;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n");
+
+       /* SMD initialization */
+       ret = wcn36xx_smd_open(wcn);
+       if (ret) {
+               wcn36xx_err("Failed to open smd channel: %d\n", ret);
+               goto out_err;
+       }
+
+       /* Allocate memory pools for Mgmt BD headers and Data BD headers */
+       ret = wcn36xx_dxe_allocate_mem_pools(wcn);
+       if (ret) {
+               wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret);
+               goto out_smd_close;
+       }
+
+       ret = wcn36xx_dxe_alloc_ctl_blks(wcn);
+       if (ret) {
+               wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret);
+               goto out_free_dxe_pool;
+       }
+
+       wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
+       if (!wcn->hal_buf) {
+               wcn36xx_err("Failed to allocate smd buf\n");
+               ret = -ENOMEM;
+               goto out_free_dxe_ctl;
+       }
+
+       ret = wcn36xx_smd_load_nv(wcn);
+       if (ret) {
+               wcn36xx_err("Failed to push NV to chip\n");
+               goto out_free_smd_buf;
+       }
+
+       ret = wcn36xx_smd_start(wcn);
+       if (ret) {
+               wcn36xx_err("Failed to start chip\n");
+               goto out_free_smd_buf;
+       }
+
+       /* DMA channel initialization */
+       ret = wcn36xx_dxe_init(wcn);
+       if (ret) {
+               wcn36xx_err("DXE init failed\n");
+               goto out_smd_stop;
+       }
+
+       wcn36xx_debugfs_init(wcn);
+
+       if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
+               ret = wcn36xx_smd_feature_caps_exchange(wcn);
+               if (ret)
+                       wcn36xx_warn("Exchange feature caps failed\n");
+       }
+       INIT_LIST_HEAD(&wcn->vif_list);
+       return 0;
+
+out_smd_stop:
+       wcn36xx_smd_stop(wcn);
+out_free_smd_buf:
+       kfree(wcn->hal_buf);
+out_free_dxe_pool:
+       wcn36xx_dxe_free_mem_pools(wcn);
+out_free_dxe_ctl:
+       wcn36xx_dxe_free_ctl_blks(wcn);
+out_smd_close:
+       wcn36xx_smd_close(wcn);
+out_err:
+       return ret;
+}
+
+static void wcn36xx_stop(struct ieee80211_hw *hw)
+{
+       struct wcn36xx *wcn = hw->priv;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n");
+
+       wcn36xx_debugfs_exit(wcn);
+       wcn36xx_smd_stop(wcn);
+       wcn36xx_dxe_deinit(wcn);
+       wcn36xx_smd_close(wcn);
+
+       wcn36xx_dxe_free_mem_pools(wcn);
+       wcn36xx_dxe_free_ctl_blks(wcn);
+
+       kfree(wcn->hal_buf);
+}
+
+static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct ieee80211_vif *vif = NULL;
+       struct wcn36xx_vif *tmp;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed);
+
+       if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+               int ch = WCN36XX_HW_CHANNEL(wcn);
+               wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",
+                           ch);
+               list_for_each_entry(tmp, &wcn->vif_list, list) {
+                       vif = container_of((void *)tmp,
+                                          struct ieee80211_vif,
+                                          drv_priv);
+                       wcn36xx_smd_switch_channel(wcn, vif, ch);
+               }
+       }
+
+       return 0;
+}
+
+#define WCN36XX_SUPPORTED_FILTERS (0)
+
+static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
+                                    unsigned int changed,
+                                    unsigned int *total, u64 multicast)
+{
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
+
+       *total &= WCN36XX_SUPPORTED_FILTERS;
+}
+
+static void wcn36xx_tx(struct ieee80211_hw *hw,
+                      struct ieee80211_tx_control *control,
+                      struct sk_buff *skb)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_sta *sta_priv = NULL;
+
+       if (control->sta)
+               sta_priv = (struct wcn36xx_sta *)control->sta->drv_priv;
+
+       if (wcn36xx_start_tx(wcn, sta_priv, skb))
+               ieee80211_free_txskb(wcn->hw, skb);
+}
+
+static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                          struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta,
+                          struct ieee80211_key_conf *key_conf)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_sta *sta_priv = vif_priv->sta;
+       int ret = 0;
+       u8 key[WLAN_MAX_KEY_LEN];
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n");
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",
+                   cmd, key_conf->cipher, key_conf->keyidx,
+                   key_conf->keylen, key_conf->flags);
+       wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ",
+                        key_conf->key,
+                        key_conf->keylen);
+
+       switch (key_conf->cipher) {
+       case WLAN_CIPHER_SUITE_WEP40:
+               vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP;
+               break;
+       default:
+               wcn36xx_err("Unsupported key type 0x%x\n",
+                             key_conf->cipher);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       switch (cmd) {
+       case SET_KEY:
+               if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) {
+                       /*
+                        * Supplicant is sending key in the wrong order:
+                        * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)
+                        * but HW expects it to be in the order as described in
+                        * IEEE 802.11 spec (see chapter 11.7) like this:
+                        * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)
+                        */
+                       memcpy(key, key_conf->key, 16);
+                       memcpy(key + 16, key_conf->key + 24, 8);
+                       memcpy(key + 24, key_conf->key + 16, 8);
+               } else {
+                       memcpy(key, key_conf->key, key_conf->keylen);
+               }
+
+               if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) {
+                       sta_priv->is_data_encrypted = true;
+                       /* Reconfigure bss with encrypt_type */
+                       if (NL80211_IFTYPE_STATION == vif->type)
+                               wcn36xx_smd_config_bss(wcn,
+                                                      vif,
+                                                      sta,
+                                                      sta->addr,
+                                                      true);
+
+                       wcn36xx_smd_set_stakey(wcn,
+                               vif_priv->encrypt_type,
+                               key_conf->keyidx,
+                               key_conf->keylen,
+                               key,
+                               get_sta_index(vif, sta_priv));
+               } else {
+                       wcn36xx_smd_set_bsskey(wcn,
+                               vif_priv->encrypt_type,
+                               key_conf->keyidx,
+                               key_conf->keylen,
+                               key);
+                       if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) ||
+                           (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) {
+                               sta_priv->is_data_encrypted = true;
+                               wcn36xx_smd_set_stakey(wcn,
+                                       vif_priv->encrypt_type,
+                                       key_conf->keyidx,
+                                       key_conf->keylen,
+                                       key,
+                                       get_sta_index(vif, sta_priv));
+                       }
+               }
+               break;
+       case DISABLE_KEY:
+               if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
+                       wcn36xx_smd_remove_bsskey(wcn,
+                               vif_priv->encrypt_type,
+                               key_conf->keyidx);
+               } else {
+                       sta_priv->is_data_encrypted = false;
+                       /* do not remove key if disassociated */
+                       if (sta_priv->aid)
+                               wcn36xx_smd_remove_stakey(wcn,
+                                       vif_priv->encrypt_type,
+                                       key_conf->keyidx,
+                                       get_sta_index(vif, sta_priv));
+               }
+               break;
+       default:
+               wcn36xx_err("Unsupported key cmd 0x%x\n", cmd);
+               ret = -EOPNOTSUPP;
+               goto out;
+               break;
+       }
+
+out:
+       return ret;
+}
+
+static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct wcn36xx *wcn = hw->priv;
+
+       wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
+       wcn36xx_smd_start_scan(wcn);
+}
+
+static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct wcn36xx *wcn = hw->priv;
+
+       wcn36xx_smd_end_scan(wcn);
+       wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
+}
+
+static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
+                                        enum ieee80211_band band)
+{
+       int i, size;
+       u16 *rates_table;
+       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+       u32 rates = sta->supp_rates[band];
+
+       memset(&sta_priv->supported_rates, 0,
+               sizeof(sta_priv->supported_rates));
+       sta_priv->supported_rates.op_rate_mode = STA_11n;
+
+       size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
+       rates_table = sta_priv->supported_rates.dsss_rates;
+       if (band == IEEE80211_BAND_2GHZ) {
+               for (i = 0; i < size; i++) {
+                       if (rates & 0x01) {
+                               rates_table[i] = wcn_2ghz_rates[i].hw_value;
+                               rates = rates >> 1;
+                       }
+               }
+       }
+
+       size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates);
+       rates_table = sta_priv->supported_rates.ofdm_rates;
+       for (i = 0; i < size; i++) {
+               if (rates & 0x01) {
+                       rates_table[i] = wcn_5ghz_rates[i].hw_value;
+                       rates = rates >> 1;
+               }
+       }
+
+       if (sta->ht_cap.ht_supported) {
+               BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) >
+                       sizeof(sta_priv->supported_rates.supported_mcs_set));
+               memcpy(sta_priv->supported_rates.supported_mcs_set,
+                      sta->ht_cap.mcs.rx_mask,
+                      sizeof(sta->ht_cap.mcs.rx_mask));
+       }
+}
+void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)
+{
+       u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = {
+               HW_RATE_INDEX_6MBPS,
+               HW_RATE_INDEX_9MBPS,
+               HW_RATE_INDEX_12MBPS,
+               HW_RATE_INDEX_18MBPS,
+               HW_RATE_INDEX_24MBPS,
+               HW_RATE_INDEX_36MBPS,
+               HW_RATE_INDEX_48MBPS,
+               HW_RATE_INDEX_54MBPS
+       };
+       u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = {
+               HW_RATE_INDEX_1MBPS,
+               HW_RATE_INDEX_2MBPS,
+               HW_RATE_INDEX_5_5MBPS,
+               HW_RATE_INDEX_11MBPS
+       };
+
+       rates->op_rate_mode = STA_11n;
+       memcpy(rates->dsss_rates, dsss_rates,
+               sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES);
+       memcpy(rates->ofdm_rates, ofdm_rates,
+               sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES);
+       rates->supported_mcs_set[0] = 0xFF;
+}
+static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
+                                    struct ieee80211_bss_conf *bss_conf,
+                                    u32 changed)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct sk_buff *skb = NULL;
+       u16 tim_off, tim_len;
+       enum wcn36xx_hal_link_state link_state;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n",
+                   vif, changed);
+
+       if (changed & BSS_CHANGED_BEACON_INFO) {
+               wcn36xx_dbg(WCN36XX_DBG_MAC,
+                           "mac bss changed dtim period %d\n",
+                           bss_conf->dtim_period);
+
+               vif_priv->dtim_period = bss_conf->dtim_period;
+       }
+
+       if (changed & BSS_CHANGED_PS) {
+               wcn36xx_dbg(WCN36XX_DBG_MAC,
+                           "mac bss PS set %d\n",
+                           bss_conf->ps);
+               if (bss_conf->ps) {
+                       wcn36xx_pmc_enter_bmps_state(wcn, vif);
+               } else {
+                       wcn36xx_pmc_exit_bmps_state(wcn, vif);
+               }
+       }
+
+       if (changed & BSS_CHANGED_BSSID) {
+               wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n",
+                           bss_conf->bssid);
+
+               if (!is_zero_ether_addr(bss_conf->bssid)) {
+                       vif_priv->is_joining = true;
+                       vif_priv->bss_index = 0xff;
+                       wcn36xx_smd_join(wcn, bss_conf->bssid,
+                                        vif->addr, WCN36XX_HW_CHANNEL(wcn));
+                       wcn36xx_smd_config_bss(wcn, vif, NULL,
+                                              bss_conf->bssid, false);
+               } else {
+                       vif_priv->is_joining = false;
+                       wcn36xx_smd_delete_bss(wcn, vif);
+               }
+       }
+
+       if (changed & BSS_CHANGED_SSID) {
+               wcn36xx_dbg(WCN36XX_DBG_MAC,
+                           "mac bss changed ssid\n");
+               wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ",
+                                bss_conf->ssid, bss_conf->ssid_len);
+
+               vif_priv->ssid.length = bss_conf->ssid_len;
+               memcpy(&vif_priv->ssid.ssid,
+                      bss_conf->ssid,
+                      bss_conf->ssid_len);
+       }
+
+       if (changed & BSS_CHANGED_ASSOC) {
+               vif_priv->is_joining = false;
+               if (bss_conf->assoc) {
+                       struct ieee80211_sta *sta;
+                       struct wcn36xx_sta *sta_priv;
+
+                       wcn36xx_dbg(WCN36XX_DBG_MAC,
+                                   "mac assoc bss %pM vif %pM AID=%d\n",
+                                    bss_conf->bssid,
+                                    vif->addr,
+                                    bss_conf->aid);
+
+                       rcu_read_lock();
+                       sta = ieee80211_find_sta(vif, bss_conf->bssid);
+                       if (!sta) {
+                               wcn36xx_err("sta %pM is not found\n",
+                                             bss_conf->bssid);
+                               rcu_read_unlock();
+                               goto out;
+                       }
+                       sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+
+                       wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
+
+                       wcn36xx_smd_set_link_st(wcn, bss_conf->bssid,
+                               vif->addr,
+                               WCN36XX_HAL_LINK_POSTASSOC_STATE);
+                       wcn36xx_smd_config_bss(wcn, vif, sta,
+                                              bss_conf->bssid,
+                                              true);
+                       sta_priv->aid = bss_conf->aid;
+                       /*
+                        * config_sta must be called from  because this is the
+                        * place where AID is available.
+                        */
+                       wcn36xx_smd_config_sta(wcn, vif, sta);
+                       rcu_read_unlock();
+               } else {
+                       wcn36xx_dbg(WCN36XX_DBG_MAC,
+                                   "disassociated bss %pM vif %pM AID=%d\n",
+                                   bss_conf->bssid,
+                                   vif->addr,
+                                   bss_conf->aid);
+                       wcn36xx_smd_set_link_st(wcn,
+                                               bss_conf->bssid,
+                                               vif->addr,
+                                               WCN36XX_HAL_LINK_IDLE_STATE);
+               }
+       }
+
+       if (changed & BSS_CHANGED_AP_PROBE_RESP) {
+               wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n");
+               skb = ieee80211_proberesp_get(hw, vif);
+               if (!skb) {
+                       wcn36xx_err("failed to alloc probereq skb\n");
+                       goto out;
+               }
+
+               wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb);
+               dev_kfree_skb(skb);
+       }
+
+       if (changed & BSS_CHANGED_BEACON_ENABLED) {
+               wcn36xx_dbg(WCN36XX_DBG_MAC,
+                           "mac bss changed beacon enabled %d\n",
+                           bss_conf->enable_beacon);
+
+               if (bss_conf->enable_beacon) {
+                       vif_priv->bss_index = 0xff;
+                       wcn36xx_smd_config_bss(wcn, vif, NULL,
+                                              vif->addr, false);
+                       skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,
+                                                      &tim_len);
+                       if (!skb) {
+                               wcn36xx_err("failed to alloc beacon skb\n");
+                               goto out;
+                       }
+                       wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0);
+                       dev_kfree_skb(skb);
+
+                       if (vif->type == NL80211_IFTYPE_ADHOC ||
+                           vif->type == NL80211_IFTYPE_MESH_POINT)
+                               link_state = WCN36XX_HAL_LINK_IBSS_STATE;
+                       else
+                               link_state = WCN36XX_HAL_LINK_AP_STATE;
+
+                       wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
+                                               link_state);
+               } else {
+                       wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
+                                               WCN36XX_HAL_LINK_IDLE_STATE);
+                       wcn36xx_smd_delete_bss(wcn, vif);
+               }
+       }
+out:
+       return;
+}
+
+/* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */
+static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       struct wcn36xx *wcn = hw->priv;
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value);
+
+       wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value);
+       return 0;
+}
+
+static void wcn36xx_remove_interface(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);
+
+       list_del(&vif_priv->list);
+       wcn36xx_smd_delete_sta_self(wcn, vif->addr);
+}
+
+static int wcn36xx_add_interface(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",
+                   vif, vif->type);
+
+       if (!(NL80211_IFTYPE_STATION == vif->type ||
+             NL80211_IFTYPE_AP == vif->type ||
+             NL80211_IFTYPE_ADHOC == vif->type ||
+             NL80211_IFTYPE_MESH_POINT == vif->type)) {
+               wcn36xx_warn("Unsupported interface type requested: %d\n",
+                            vif->type);
+               return -EOPNOTSUPP;
+       }
+
+       list_add(&vif_priv->list, &wcn->vif_list);
+       wcn36xx_smd_add_sta_self(wcn, vif);
+
+       return 0;
+}
+
+static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
+                   vif, sta->addr);
+
+       vif_priv->sta = sta_priv;
+       sta_priv->vif = vif_priv;
+       /*
+        * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
+        * at this stage AID is not available yet.
+        */
+       if (NL80211_IFTYPE_STATION != vif->type) {
+               wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
+               sta_priv->aid = sta->aid;
+               wcn36xx_smd_config_sta(wcn, vif, sta);
+       }
+       return 0;
+}
+
+static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
+                   vif, sta->addr, sta_priv->sta_index);
+
+       wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
+       vif_priv->sta = NULL;
+       sta_priv->vif = NULL;
+       return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
+{
+       struct wcn36xx *wcn = hw->priv;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n");
+
+       flush_workqueue(wcn->hal_ind_wq);
+       wcn36xx_smd_set_power_params(wcn, true);
+       return 0;
+}
+
+static int wcn36xx_resume(struct ieee80211_hw *hw)
+{
+       struct wcn36xx *wcn = hw->priv;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n");
+
+       flush_workqueue(wcn->hal_ind_wq);
+       wcn36xx_smd_set_power_params(wcn, false);
+       return 0;
+}
+
+#endif
+
+static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   enum ieee80211_ampdu_mlme_action action,
+                   struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+                   u8 buf_size)
+{
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_sta *sta_priv = NULL;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
+                   action, tid);
+
+       sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               sta_priv->tid = tid;
+               wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
+                       get_sta_index(vif, sta_priv));
+               wcn36xx_smd_add_ba(wcn);
+               wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
+               ieee80211_start_tx_ba_session(sta, tid, 0);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
+                       get_sta_index(vif, sta_priv));
+               break;
+       case IEEE80211_AMPDU_TX_STOP_FLUSH:
+       case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+       case IEEE80211_AMPDU_TX_STOP_CONT:
+               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+               break;
+       default:
+               wcn36xx_err("Unknown AMPDU action\n");
+       }
+
+       return 0;
+}
+
+static const struct ieee80211_ops wcn36xx_ops = {
+       .start                  = wcn36xx_start,
+       .stop                   = wcn36xx_stop,
+       .add_interface          = wcn36xx_add_interface,
+       .remove_interface       = wcn36xx_remove_interface,
+#ifdef CONFIG_PM
+       .suspend                = wcn36xx_suspend,
+       .resume                 = wcn36xx_resume,
+#endif
+       .config                 = wcn36xx_config,
+       .configure_filter       = wcn36xx_configure_filter,
+       .tx                     = wcn36xx_tx,
+       .set_key                = wcn36xx_set_key,
+       .sw_scan_start          = wcn36xx_sw_scan_start,
+       .sw_scan_complete       = wcn36xx_sw_scan_complete,
+       .bss_info_changed       = wcn36xx_bss_info_changed,
+       .set_rts_threshold      = wcn36xx_set_rts_threshold,
+       .sta_add                = wcn36xx_sta_add,
+       .sta_remove             = wcn36xx_sta_remove,
+       .ampdu_action           = wcn36xx_ampdu_action,
+};
+
+static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
+{
+       int ret = 0;
+
+       static const u32 cipher_suites[] = {
+               WLAN_CIPHER_SUITE_WEP40,
+               WLAN_CIPHER_SUITE_WEP104,
+               WLAN_CIPHER_SUITE_TKIP,
+               WLAN_CIPHER_SUITE_CCMP,
+       };
+
+       wcn->hw->flags = IEEE80211_HW_SIGNAL_DBM |
+               IEEE80211_HW_HAS_RATE_CONTROL |
+               IEEE80211_HW_SUPPORTS_PS |
+               IEEE80211_HW_CONNECTION_MONITOR |
+               IEEE80211_HW_AMPDU_AGGREGATION |
+               IEEE80211_HW_TIMING_BEACON_ONLY;
+
+       wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_ADHOC) |
+               BIT(NL80211_IFTYPE_MESH_POINT);
+
+       wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz;
+       wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz;
+
+       wcn->hw->wiphy->cipher_suites = cipher_suites;
+       wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
+       wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+
+#ifdef CONFIG_PM
+       wcn->hw->wiphy->wowlan = &wowlan_support;
+#endif
+
+       wcn->hw->max_listen_interval = 200;
+
+       wcn->hw->queues = 4;
+
+       SET_IEEE80211_DEV(wcn->hw, wcn->dev);
+
+       wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);
+       wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);
+
+       return ret;
+}
+
+static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
+                                         struct platform_device *pdev)
+{
+       struct resource *res;
+       /* Set TX IRQ */
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+                                          "wcnss_wlantx_irq");
+       if (!res) {
+               wcn36xx_err("failed to get tx_irq\n");
+               return -ENOENT;
+       }
+       wcn->tx_irq = res->start;
+
+       /* Set RX IRQ */
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+                                          "wcnss_wlanrx_irq");
+       if (!res) {
+               wcn36xx_err("failed to get rx_irq\n");
+               return -ENOENT;
+       }
+       wcn->rx_irq = res->start;
+
+       /* Map the memory */
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                                "wcnss_mmio");
+       if (!res) {
+               wcn36xx_err("failed to get mmio\n");
+               return -ENOENT;
+       }
+       wcn->mmio = ioremap(res->start, resource_size(res));
+       if (!wcn->mmio) {
+               wcn36xx_err("failed to map io memory\n");
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+static int wcn36xx_probe(struct platform_device *pdev)
+{
+       struct ieee80211_hw *hw;
+       struct wcn36xx *wcn;
+       int ret;
+       u8 addr[ETH_ALEN];
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
+
+       hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
+       if (!hw) {
+               wcn36xx_err("failed to alloc hw\n");
+               ret = -ENOMEM;
+               goto out_err;
+       }
+       platform_set_drvdata(pdev, hw);
+       wcn = hw->priv;
+       wcn->hw = hw;
+       wcn->dev = &pdev->dev;
+       wcn->ctrl_ops = pdev->dev.platform_data;
+
+       mutex_init(&wcn->hal_mutex);
+
+       if (!wcn->ctrl_ops->get_hw_mac(addr)) {
+               wcn36xx_info("mac address: %pM\n", addr);
+               SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
+       }
+
+       ret = wcn36xx_platform_get_resources(wcn, pdev);
+       if (ret)
+               goto out_wq;
+
+       wcn36xx_init_ieee80211(wcn);
+       ret = ieee80211_register_hw(wcn->hw);
+       if (ret)
+               goto out_unmap;
+
+       return 0;
+
+out_unmap:
+       iounmap(wcn->mmio);
+out_wq:
+       ieee80211_free_hw(hw);
+out_err:
+       return ret;
+}
+static int wcn36xx_remove(struct platform_device *pdev)
+{
+       struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+       struct wcn36xx *wcn = hw->priv;
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
+
+       mutex_destroy(&wcn->hal_mutex);
+
+       ieee80211_unregister_hw(hw);
+       iounmap(wcn->mmio);
+       ieee80211_free_hw(hw);
+
+       return 0;
+}
+static const struct platform_device_id wcn36xx_platform_id_table[] = {
+       {
+               .name = "wcn36xx",
+               .driver_data = 0
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
+
+static struct platform_driver wcn36xx_driver = {
+       .probe      = wcn36xx_probe,
+       .remove     = wcn36xx_remove,
+       .driver         = {
+               .name   = "wcn36xx",
+               .owner  = THIS_MODULE,
+       },
+       .id_table    = wcn36xx_platform_id_table,
+};
+
+static int __init wcn36xx_init(void)
+{
+       platform_driver_register(&wcn36xx_driver);
+       return 0;
+}
+module_init(wcn36xx_init);
+
+static void __exit wcn36xx_exit(void)
+{
+       platform_driver_unregister(&wcn36xx_driver);
+}
+module_exit(wcn36xx_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
+MODULE_FIRMWARE(WLAN_NV_FILE);
diff --git a/drivers/net/wireless/ath/wcn36xx/pmc.c b/drivers/net/wireless/ath/wcn36xx/pmc.c
new file mode 100644 (file)
index 0000000..28b515c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "wcn36xx.h"
+
+int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
+                                struct ieee80211_vif *vif)
+{
+       int ret = 0;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       /* TODO: Make sure the TX chain clean */
+       ret = wcn36xx_smd_enter_bmps(wcn, vif);
+       if (!ret) {
+               wcn36xx_dbg(WCN36XX_DBG_PMC, "Entered BMPS\n");
+               vif_priv->pw_state = WCN36XX_BMPS;
+       } else {
+               /*
+                * One of the reasons why HW will not enter BMPS is because
+                * driver is trying to enter bmps before first beacon was
+                * received just after auth complete
+                */
+               wcn36xx_err("Can not enter BMPS!\n");
+       }
+       return ret;
+}
+
+int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn,
+                               struct ieee80211_vif *vif)
+{
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+
+       if (WCN36XX_BMPS != vif_priv->pw_state) {
+               wcn36xx_err("Not in BMPS mode, no need to exit from BMPS mode!\n");
+               return -EINVAL;
+       }
+       wcn36xx_smd_exit_bmps(wcn, vif);
+       vif_priv->pw_state = WCN36XX_FULL_POWER;
+       return 0;
+}
+
+int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn,
+                                         struct ieee80211_vif *vif)
+{
+       wcn36xx_dbg(WCN36XX_DBG_PMC, "%s\n", __func__);
+       return wcn36xx_smd_keep_alive_req(wcn, vif,
+                                         WCN36XX_HAL_KEEP_ALIVE_NULL_PKT);
+}
diff --git a/drivers/net/wireless/ath/wcn36xx/pmc.h b/drivers/net/wireless/ath/wcn36xx/pmc.h
new file mode 100644 (file)
index 0000000..f72ed68
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WCN36XX_PMC_H_
+#define _WCN36XX_PMC_H_
+
+struct wcn36xx;
+
+enum wcn36xx_power_state {
+       WCN36XX_FULL_POWER,
+       WCN36XX_BMPS
+};
+
+int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
+                                struct ieee80211_vif *vif);
+int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn,
+                               struct ieee80211_vif *vif);
+int wcn36xx_enable_keep_alive_null_packet(struct wcn36xx *wcn,
+                                         struct ieee80211_vif *vif);
+#endif /* _WCN36XX_PMC_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
new file mode 100644 (file)
index 0000000..f8c3a10
--- /dev/null
@@ -0,0 +1,2126 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/etherdevice.h>
+#include <linux/firmware.h>
+#include <linux/bitops.h>
+#include "smd.h"
+
+static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)
+{
+       struct wcn36xx_hal_cfg *entry;
+       u32 *val;
+
+       if (*len + sizeof(*entry) + sizeof(u32) >= WCN36XX_HAL_BUF_SIZE) {
+               wcn36xx_err("Not enough room for TLV entry\n");
+               return -ENOMEM;
+       }
+
+       entry = (struct wcn36xx_hal_cfg *) (wcn->hal_buf + *len);
+       entry->id = id;
+       entry->len = sizeof(u32);
+       entry->pad_bytes = 0;
+       entry->reserve = 0;
+
+       val = (u32 *) (entry + 1);
+       *val = value;
+
+       *len += sizeof(*entry) + sizeof(u32);
+
+       return 0;
+}
+
+static void wcn36xx_smd_set_bss_nw_type(struct wcn36xx *wcn,
+               struct ieee80211_sta *sta,
+               struct wcn36xx_hal_config_bss_params *bss_params)
+{
+       if (IEEE80211_BAND_5GHZ == WCN36XX_BAND(wcn))
+               bss_params->nw_type = WCN36XX_HAL_11A_NW_TYPE;
+       else if (sta && sta->ht_cap.ht_supported)
+               bss_params->nw_type = WCN36XX_HAL_11N_NW_TYPE;
+       else if (sta && (sta->supp_rates[IEEE80211_BAND_2GHZ] & 0x7f))
+               bss_params->nw_type = WCN36XX_HAL_11G_NW_TYPE;
+       else
+               bss_params->nw_type = WCN36XX_HAL_11B_NW_TYPE;
+}
+
+static inline u8 is_cap_supported(unsigned long caps, unsigned long flag)
+{
+       return caps & flag ? 1 : 0;
+}
+static void wcn36xx_smd_set_bss_ht_params(struct ieee80211_vif *vif,
+               struct ieee80211_sta *sta,
+               struct wcn36xx_hal_config_bss_params *bss_params)
+{
+       if (sta && sta->ht_cap.ht_supported) {
+               unsigned long caps = sta->ht_cap.cap;
+               bss_params->ht = sta->ht_cap.ht_supported;
+               bss_params->tx_channel_width_set = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+               bss_params->lsig_tx_op_protection_full_support =
+                       is_cap_supported(caps,
+                                        IEEE80211_HT_CAP_LSIG_TXOP_PROT);
+
+               bss_params->ht_oper_mode = vif->bss_conf.ht_operation_mode;
+               bss_params->lln_non_gf_coexist =
+                       !!(vif->bss_conf.ht_operation_mode &
+                          IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+               /* IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT */
+               bss_params->dual_cts_protection = 0;
+               /* IEEE80211_HT_OP_MODE_PROTECTION_20MHZ */
+               bss_params->ht20_coexist = 0;
+       }
+}
+
+static void wcn36xx_smd_set_sta_ht_params(struct ieee80211_sta *sta,
+               struct wcn36xx_hal_config_sta_params *sta_params)
+{
+       if (sta->ht_cap.ht_supported) {
+               unsigned long caps = sta->ht_cap.cap;
+               sta_params->ht_capable = sta->ht_cap.ht_supported;
+               sta_params->tx_channel_width_set = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_SUP_WIDTH_20_40);
+               sta_params->lsig_txop_protection = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_LSIG_TXOP_PROT);
+
+               sta_params->max_ampdu_size = sta->ht_cap.ampdu_factor;
+               sta_params->max_ampdu_density = sta->ht_cap.ampdu_density;
+               sta_params->max_amsdu_size = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_MAX_AMSDU);
+               sta_params->sgi_20Mhz = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_SGI_20);
+               sta_params->sgi_40mhz = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_SGI_40);
+               sta_params->green_field_capable = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_GRN_FLD);
+               sta_params->delayed_ba_support = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_DELAY_BA);
+               sta_params->dsss_cck_mode_40mhz = is_cap_supported(caps,
+                       IEEE80211_HT_CAP_DSSSCCK40);
+       }
+}
+
+static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
+               struct ieee80211_vif *vif,
+               struct ieee80211_sta *sta,
+               struct wcn36xx_hal_config_sta_params *sta_params)
+{
+       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_sta *priv_sta = NULL;
+       if (vif->type == NL80211_IFTYPE_ADHOC ||
+           vif->type == NL80211_IFTYPE_AP ||
+           vif->type == NL80211_IFTYPE_MESH_POINT) {
+               sta_params->type = 1;
+               sta_params->sta_index = 0xFF;
+       } else {
+               sta_params->type = 0;
+               sta_params->sta_index = 1;
+       }
+
+       sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn);
+
+       /*
+        * In STA mode ieee80211_sta contains bssid and ieee80211_vif
+        * contains our mac address. In  AP mode we are bssid so vif
+        * contains bssid and ieee80211_sta contains mac.
+        */
+       if (NL80211_IFTYPE_STATION == vif->type)
+               memcpy(&sta_params->mac, vif->addr, ETH_ALEN);
+       else
+               memcpy(&sta_params->bssid, vif->addr, ETH_ALEN);
+
+       sta_params->encrypt_type = priv_vif->encrypt_type;
+       sta_params->short_preamble_supported =
+               !(WCN36XX_FLAGS(wcn) &
+                 IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE);
+
+       sta_params->rifs_mode = 0;
+       sta_params->rmf = 0;
+       sta_params->action = 0;
+       sta_params->uapsd = 0;
+       sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC;
+       sta_params->max_ampdu_duration = 0;
+       sta_params->bssid_index = priv_vif->bss_index;
+       sta_params->p2p = 0;
+
+       if (sta) {
+               priv_sta = (struct wcn36xx_sta *)sta->drv_priv;
+               if (NL80211_IFTYPE_STATION == vif->type)
+                       memcpy(&sta_params->bssid, sta->addr, ETH_ALEN);
+               else
+                       memcpy(&sta_params->mac, sta->addr, ETH_ALEN);
+               sta_params->wmm_enabled = sta->wme;
+               sta_params->max_sp_len = sta->max_sp;
+               sta_params->aid = priv_sta->aid;
+               wcn36xx_smd_set_sta_ht_params(sta, sta_params);
+               memcpy(&sta_params->supported_rates, &priv_sta->supported_rates,
+                       sizeof(priv_sta->supported_rates));
+       } else {
+               wcn36xx_set_default_rates(&sta_params->supported_rates);
+       }
+}
+
+static int wcn36xx_smd_send_and_wait(struct wcn36xx *wcn, size_t len)
+{
+       int ret = 0;
+       wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "HAL >>> ", wcn->hal_buf, len);
+
+       init_completion(&wcn->hal_rsp_compl);
+       ret = wcn->ctrl_ops->tx(wcn->hal_buf, len);
+       if (ret) {
+               wcn36xx_err("HAL TX failed\n");
+               goto out;
+       }
+       if (wait_for_completion_timeout(&wcn->hal_rsp_compl,
+               msecs_to_jiffies(HAL_MSG_TIMEOUT)) <= 0) {
+               wcn36xx_err("Timeout while waiting SMD response\n");
+               ret = -ETIME;
+               goto out;
+       }
+out:
+       return ret;
+}
+
+#define INIT_HAL_MSG(msg_body, type) \
+       do {                                                            \
+               memset(&msg_body, 0, sizeof(msg_body));                 \
+               msg_body.header.msg_type = type;                        \
+               msg_body.header.msg_version = WCN36XX_HAL_MSG_VERSION0; \
+               msg_body.header.len = sizeof(msg_body);                 \
+       } while (0)                                                     \
+
+#define PREPARE_HAL_BUF(send_buf, msg_body) \
+       do {                                                    \
+               memset(send_buf, 0, msg_body.header.len);       \
+               memcpy(send_buf, &msg_body, sizeof(msg_body));  \
+       } while (0)                                             \
+
+static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)
+{
+       struct wcn36xx_fw_msg_status_rsp *rsp;
+
+       if (len < sizeof(struct wcn36xx_hal_msg_header) +
+           sizeof(struct wcn36xx_fw_msg_status_rsp))
+               return -EIO;
+
+       rsp = (struct wcn36xx_fw_msg_status_rsp *)
+               (buf + sizeof(struct wcn36xx_hal_msg_header));
+
+       if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status)
+               return rsp->status;
+
+       return 0;
+}
+
+int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
+{
+       const struct firmware *nv;
+       struct nv_data *nv_d;
+       struct wcn36xx_hal_nv_img_download_req_msg msg_body;
+       int fw_bytes_left;
+       int ret;
+       u16 fm_offset = 0;
+
+       ret = request_firmware(&nv, WLAN_NV_FILE, wcn->dev);
+       if (ret) {
+               wcn36xx_err("Failed to load nv file %s: %d\n",
+                             WLAN_NV_FILE, ret);
+               goto out_free_nv;
+       }
+
+       nv_d = (struct nv_data *)nv->data;
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_DOWNLOAD_NV_REQ);
+
+       msg_body.header.len += WCN36XX_NV_FRAGMENT_SIZE;
+
+       msg_body.frag_number = 0;
+       /* hal_buf must be protected with  mutex */
+       mutex_lock(&wcn->hal_mutex);
+
+       do {
+               fw_bytes_left = nv->size - fm_offset - 4;
+               if (fw_bytes_left > WCN36XX_NV_FRAGMENT_SIZE) {
+                       msg_body.last_fragment = 0;
+                       msg_body.nv_img_buffer_size = WCN36XX_NV_FRAGMENT_SIZE;
+               } else {
+                       msg_body.last_fragment = 1;
+                       msg_body.nv_img_buffer_size = fw_bytes_left;
+
+                       /* Do not forget update general message len */
+                       msg_body.header.len = sizeof(msg_body) + fw_bytes_left;
+
+               }
+
+               /* Add load NV request message header */
+               memcpy(wcn->hal_buf, &msg_body, sizeof(msg_body));
+
+               /* Add NV body itself */
+               memcpy(wcn->hal_buf + sizeof(msg_body),
+                      &nv_d->table + fm_offset,
+                      msg_body.nv_img_buffer_size);
+
+               ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+               if (ret)
+                       goto out_unlock;
+               ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf,
+                                                  wcn->hal_rsp_len);
+               if (ret) {
+                       wcn36xx_err("hal_load_nv response failed err=%d\n",
+                                   ret);
+                       goto out_unlock;
+               }
+               msg_body.frag_number++;
+               fm_offset += WCN36XX_NV_FRAGMENT_SIZE;
+
+       } while (msg_body.last_fragment != 1);
+
+out_unlock:
+       mutex_unlock(&wcn->hal_mutex);
+out_free_nv:
+       release_firmware(nv);
+
+       return ret;
+}
+
+static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
+{
+       struct wcn36xx_hal_mac_start_rsp_msg *rsp;
+
+       if (len < sizeof(*rsp))
+               return -EIO;
+
+       rsp = (struct wcn36xx_hal_mac_start_rsp_msg *)buf;
+
+       if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->start_rsp_params.status)
+               return -EIO;
+
+       memcpy(wcn->crm_version, rsp->start_rsp_params.crm_version,
+              WCN36XX_HAL_VERSION_LENGTH);
+       memcpy(wcn->wlan_version, rsp->start_rsp_params.wlan_version,
+              WCN36XX_HAL_VERSION_LENGTH);
+
+       /* null terminate the strings, just in case */
+       wcn->crm_version[WCN36XX_HAL_VERSION_LENGTH] = '\0';
+       wcn->wlan_version[WCN36XX_HAL_VERSION_LENGTH] = '\0';
+
+       wcn->fw_revision = rsp->start_rsp_params.version.revision;
+       wcn->fw_version = rsp->start_rsp_params.version.version;
+       wcn->fw_minor = rsp->start_rsp_params.version.minor;
+       wcn->fw_major = rsp->start_rsp_params.version.major;
+
+       wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
+                    wcn->wlan_version, wcn->crm_version);
+
+       wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",
+                    wcn->fw_major, wcn->fw_minor,
+                    wcn->fw_version, wcn->fw_revision,
+                    rsp->start_rsp_params.stations,
+                    rsp->start_rsp_params.bssids);
+
+       return 0;
+}
+
+int wcn36xx_smd_start(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_mac_start_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ);
+
+       msg_body.params.type = DRIVER_TYPE_PRODUCTION;
+       msg_body.params.len = 0;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n",
+                   msg_body.params.type);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_start failed\n");
+               goto out;
+       }
+
+       ret = wcn36xx_smd_start_rsp(wcn, wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_start response failed err=%d\n", ret);
+               goto out;
+       }
+
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_stop(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_mac_stop_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_STOP_REQ);
+
+       msg_body.stop_req_params.reason = HAL_STOP_TYPE_RF_KILL;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_stop failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_stop response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode)
+{
+       struct wcn36xx_hal_init_scan_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_INIT_SCAN_REQ);
+
+       msg_body.mode = mode;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "hal init scan mode %d\n", msg_body.mode);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_init_scan failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_init_scan response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_start_scan_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_SCAN_REQ);
+
+       msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start scan channel %d\n",
+                   msg_body.scan_channel);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_start_scan failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_start_scan response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_end_scan_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_END_SCAN_REQ);
+
+       msg_body.scan_channel = WCN36XX_HW_CHANNEL(wcn);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "hal end scan channel %d\n",
+                   msg_body.scan_channel);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_end_scan failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_end_scan response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
+                           enum wcn36xx_hal_sys_mode mode)
+{
+       struct wcn36xx_hal_finish_scan_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_FINISH_SCAN_REQ);
+
+       msg_body.mode = mode;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "hal finish scan mode %d\n",
+                   msg_body.mode);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_finish_scan failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_finish_scan response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static int wcn36xx_smd_switch_channel_rsp(void *buf, size_t len)
+{
+       struct wcn36xx_hal_switch_channel_rsp_msg *rsp;
+       int ret = 0;
+
+       ret = wcn36xx_smd_rsp_status_check(buf, len);
+       if (ret)
+               return ret;
+       rsp = (struct wcn36xx_hal_switch_channel_rsp_msg *)buf;
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "channel switched to: %d, status: %d\n",
+                   rsp->channel_number, rsp->status);
+       return ret;
+}
+
+int wcn36xx_smd_switch_channel(struct wcn36xx *wcn,
+                              struct ieee80211_vif *vif, int ch)
+{
+       struct wcn36xx_hal_switch_channel_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_CH_SWITCH_REQ);
+
+       msg_body.channel_number = (u8)ch;
+       msg_body.tx_mgmt_power = 0xbf;
+       msg_body.max_tx_power = 0xbf;
+       memcpy(msg_body.self_sta_mac_addr, vif->addr, ETH_ALEN);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_switch_channel failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_switch_channel_rsp(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_switch_channel response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static int wcn36xx_smd_update_scan_params_rsp(void *buf, size_t len)
+{
+       struct wcn36xx_hal_update_scan_params_resp *rsp;
+
+       rsp = (struct wcn36xx_hal_update_scan_params_resp *)buf;
+
+       /* Remove the PNO version bit */
+       rsp->status &= (~(WCN36XX_FW_MSG_PNO_VERSION_MASK));
+
+       if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status) {
+               wcn36xx_warn("error response from update scan\n");
+               return rsp->status;
+       }
+
+       return 0;
+}
+
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_update_scan_params_req msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_SCAN_PARAM_REQ);
+
+       msg_body.dot11d_enabled = 0;
+       msg_body.dot11d_resolved = 0;
+       msg_body.channel_count = 26;
+       msg_body.active_min_ch_time = 60;
+       msg_body.active_max_ch_time = 120;
+       msg_body.passive_min_ch_time = 60;
+       msg_body.passive_max_ch_time = 110;
+       msg_body.state = 0;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal update scan params channel_count %d\n",
+                   msg_body.channel_count);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_update_scan_params failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_update_scan_params_rsp(wcn->hal_buf,
+                                                wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_update_scan_params response failed err=%d\n",
+                           ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn,
+                                       struct ieee80211_vif *vif,
+                                       void *buf,
+                                       size_t len)
+{
+       struct wcn36xx_hal_add_sta_self_rsp_msg *rsp;
+       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       rsp = (struct wcn36xx_hal_add_sta_self_rsp_msg *)buf;
+
+       if (rsp->status != WCN36XX_FW_MSG_RESULT_SUCCESS) {
+               wcn36xx_warn("hal add sta self failure: %d\n",
+                            rsp->status);
+               return rsp->status;
+       }
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal add sta self status %d self_sta_index %d dpu_index %d\n",
+                   rsp->status, rsp->self_sta_index, rsp->dpu_index);
+
+       priv_vif->self_sta_index = rsp->self_sta_index;
+       priv_vif->self_dpu_desc_index = rsp->dpu_index;
+
+       return 0;
+}
+
+int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif)
+{
+       struct wcn36xx_hal_add_sta_self_req msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_STA_SELF_REQ);
+
+       memcpy(&msg_body.self_addr, vif->addr, ETH_ALEN);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal add sta self self_addr %pM status %d\n",
+                   msg_body.self_addr, msg_body.status);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_add_sta_self failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_add_sta_self_rsp(wcn,
+                                          vif,
+                                          wcn->hal_buf,
+                                          wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_add_sta_self response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr)
+{
+       struct wcn36xx_hal_del_sta_self_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_STA_SELF_REQ);
+
+       memcpy(&msg_body.self_addr, addr, ETH_ALEN);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_delete_sta_self failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_delete_sta_self response failed err=%d\n",
+                           ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index)
+{
+       struct wcn36xx_hal_delete_sta_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_STA_REQ);
+
+       msg_body.sta_index = sta_index;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal delete sta sta_index %d\n",
+                   msg_body.sta_index);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_delete_sta failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_delete_sta response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static int wcn36xx_smd_join_rsp(void *buf, size_t len)
+{
+       struct wcn36xx_hal_join_rsp_msg *rsp;
+
+       if (wcn36xx_smd_rsp_status_check(buf, len))
+               return -EIO;
+
+       rsp = (struct wcn36xx_hal_join_rsp_msg *)buf;
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal rsp join status %d tx_mgmt_power %d\n",
+                   rsp->status, rsp->tx_mgmt_power);
+
+       return 0;
+}
+
+int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch)
+{
+       struct wcn36xx_hal_join_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_JOIN_REQ);
+
+       memcpy(&msg_body.bssid, bssid, ETH_ALEN);
+       memcpy(&msg_body.self_sta_mac_addr, vif, ETH_ALEN);
+       msg_body.channel = ch;
+
+       if (conf_is_ht40_minus(&wcn->hw->conf))
+               msg_body.secondary_channel_offset =
+                       PHY_DOUBLE_CHANNEL_HIGH_PRIMARY;
+       else if (conf_is_ht40_plus(&wcn->hw->conf))
+               msg_body.secondary_channel_offset =
+                       PHY_DOUBLE_CHANNEL_LOW_PRIMARY;
+       else
+               msg_body.secondary_channel_offset =
+                       PHY_SINGLE_CHANNEL_CENTERED;
+
+       msg_body.link_state = WCN36XX_HAL_LINK_PREASSOC_STATE;
+
+       msg_body.max_tx_power = 0xbf;
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal join req bssid %pM self_sta_mac_addr %pM channel %d link_state %d\n",
+                   msg_body.bssid, msg_body.self_sta_mac_addr,
+                   msg_body.channel, msg_body.link_state);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_join failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_join_rsp(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_join response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid,
+                           const u8 *sta_mac,
+                           enum wcn36xx_hal_link_state state)
+{
+       struct wcn36xx_hal_set_link_state_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_LINK_ST_REQ);
+
+       memcpy(&msg_body.bssid, bssid, ETH_ALEN);
+       memcpy(&msg_body.self_mac_addr, sta_mac, ETH_ALEN);
+       msg_body.state = state;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal set link state bssid %pM self_mac_addr %pM state %d\n",
+                   msg_body.bssid, msg_body.self_mac_addr, msg_body.state);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_set_link_st failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_set_link_st response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,
+                       const struct wcn36xx_hal_config_sta_params *orig,
+                       struct wcn36xx_hal_config_sta_params_v1 *v1)
+{
+       /* convert orig to v1 format */
+       memcpy(&v1->bssid, orig->bssid, ETH_ALEN);
+       memcpy(&v1->mac, orig->mac, ETH_ALEN);
+       v1->aid = orig->aid;
+       v1->type = orig->type;
+       v1->listen_interval = orig->listen_interval;
+       v1->ht_capable = orig->ht_capable;
+
+       v1->max_ampdu_size = orig->max_ampdu_size;
+       v1->max_ampdu_density = orig->max_ampdu_density;
+       v1->sgi_40mhz = orig->sgi_40mhz;
+       v1->sgi_20Mhz = orig->sgi_20Mhz;
+
+       memcpy(&v1->supported_rates, &orig->supported_rates,
+              sizeof(orig->supported_rates));
+       v1->sta_index = orig->sta_index;
+}
+
+static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
+                                     struct ieee80211_sta *sta,
+                                     void *buf,
+                                     size_t len)
+{
+       struct wcn36xx_hal_config_sta_rsp_msg *rsp;
+       struct config_sta_rsp_params *params;
+       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       rsp = (struct wcn36xx_hal_config_sta_rsp_msg *)buf;
+       params = &rsp->params;
+
+       if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) {
+               wcn36xx_warn("hal config sta response failure: %d\n",
+                            params->status);
+               return -EIO;
+       }
+
+       sta_priv->sta_index = params->sta_index;
+       sta_priv->dpu_desc_index = params->dpu_index;
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal config sta rsp status %d sta_index %d bssid_index %d p2p %d\n",
+                   params->status, params->sta_index, params->bssid_index,
+                   params->p2p);
+
+       return 0;
+}
+
+static int wcn36xx_smd_config_sta_v1(struct wcn36xx *wcn,
+                    const struct wcn36xx_hal_config_sta_req_msg *orig)
+{
+       struct wcn36xx_hal_config_sta_req_msg_v1 msg_body;
+       struct wcn36xx_hal_config_sta_params_v1 *sta = &msg_body.sta_params;
+
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_STA_REQ);
+
+       wcn36xx_smd_convert_sta_to_v1(wcn, &orig->sta_params,
+                                     &msg_body.sta_params);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal config sta v1 action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",
+                   sta->action, sta->sta_index, sta->bssid_index,
+                   sta->bssid, sta->type, sta->mac, sta->aid);
+
+       return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+}
+
+int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta)
+{
+       struct wcn36xx_hal_config_sta_req_msg msg;
+       struct wcn36xx_hal_config_sta_params *sta_params;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_STA_REQ);
+
+       sta_params = &msg.sta_params;
+
+       wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
+
+       if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
+               ret = wcn36xx_smd_config_sta_v1(wcn, &msg);
+       } else {
+               PREPARE_HAL_BUF(wcn->hal_buf, msg);
+
+               wcn36xx_dbg(WCN36XX_DBG_HAL,
+                           "hal config sta action %d sta_index %d bssid_index %d bssid %pM type %d mac %pM aid %d\n",
+                           sta_params->action, sta_params->sta_index,
+                           sta_params->bssid_index, sta_params->bssid,
+                           sta_params->type, sta_params->mac, sta_params->aid);
+
+               ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len);
+       }
+       if (ret) {
+               wcn36xx_err("Sending hal_config_sta failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_config_sta_rsp(wcn,
+                                        sta,
+                                        wcn->hal_buf,
+                                        wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_config_sta response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
+                       const struct wcn36xx_hal_config_bss_req_msg *orig)
+{
+       struct wcn36xx_hal_config_bss_req_msg_v1 msg_body;
+       struct wcn36xx_hal_config_bss_params_v1 *bss = &msg_body.bss_params;
+       struct wcn36xx_hal_config_sta_params_v1 *sta = &bss->sta;
+
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_CONFIG_BSS_REQ);
+
+       /* convert orig to v1 */
+       memcpy(&msg_body.bss_params.bssid,
+              &orig->bss_params.bssid, ETH_ALEN);
+       memcpy(&msg_body.bss_params.self_mac_addr,
+              &orig->bss_params.self_mac_addr, ETH_ALEN);
+
+       msg_body.bss_params.bss_type = orig->bss_params.bss_type;
+       msg_body.bss_params.oper_mode = orig->bss_params.oper_mode;
+       msg_body.bss_params.nw_type = orig->bss_params.nw_type;
+
+       msg_body.bss_params.short_slot_time_supported =
+               orig->bss_params.short_slot_time_supported;
+       msg_body.bss_params.lla_coexist = orig->bss_params.lla_coexist;
+       msg_body.bss_params.llb_coexist = orig->bss_params.llb_coexist;
+       msg_body.bss_params.llg_coexist = orig->bss_params.llg_coexist;
+       msg_body.bss_params.ht20_coexist = orig->bss_params.ht20_coexist;
+       msg_body.bss_params.lln_non_gf_coexist =
+               orig->bss_params.lln_non_gf_coexist;
+
+       msg_body.bss_params.lsig_tx_op_protection_full_support =
+               orig->bss_params.lsig_tx_op_protection_full_support;
+       msg_body.bss_params.rifs_mode = orig->bss_params.rifs_mode;
+       msg_body.bss_params.beacon_interval = orig->bss_params.beacon_interval;
+       msg_body.bss_params.dtim_period = orig->bss_params.dtim_period;
+       msg_body.bss_params.tx_channel_width_set =
+               orig->bss_params.tx_channel_width_set;
+       msg_body.bss_params.oper_channel = orig->bss_params.oper_channel;
+       msg_body.bss_params.ext_channel = orig->bss_params.ext_channel;
+
+       msg_body.bss_params.reserved = orig->bss_params.reserved;
+
+       memcpy(&msg_body.bss_params.ssid,
+              &orig->bss_params.ssid,
+              sizeof(orig->bss_params.ssid));
+
+       msg_body.bss_params.action = orig->bss_params.action;
+       msg_body.bss_params.rateset = orig->bss_params.rateset;
+       msg_body.bss_params.ht = orig->bss_params.ht;
+       msg_body.bss_params.obss_prot_enabled =
+               orig->bss_params.obss_prot_enabled;
+       msg_body.bss_params.rmf = orig->bss_params.rmf;
+       msg_body.bss_params.ht_oper_mode = orig->bss_params.ht_oper_mode;
+       msg_body.bss_params.dual_cts_protection =
+               orig->bss_params.dual_cts_protection;
+
+       msg_body.bss_params.max_probe_resp_retry_limit =
+               orig->bss_params.max_probe_resp_retry_limit;
+       msg_body.bss_params.hidden_ssid = orig->bss_params.hidden_ssid;
+       msg_body.bss_params.proxy_probe_resp =
+               orig->bss_params.proxy_probe_resp;
+       msg_body.bss_params.edca_params_valid =
+               orig->bss_params.edca_params_valid;
+
+       memcpy(&msg_body.bss_params.acbe,
+              &orig->bss_params.acbe,
+              sizeof(orig->bss_params.acbe));
+       memcpy(&msg_body.bss_params.acbk,
+              &orig->bss_params.acbk,
+              sizeof(orig->bss_params.acbk));
+       memcpy(&msg_body.bss_params.acvi,
+              &orig->bss_params.acvi,
+              sizeof(orig->bss_params.acvi));
+       memcpy(&msg_body.bss_params.acvo,
+              &orig->bss_params.acvo,
+              sizeof(orig->bss_params.acvo));
+
+       msg_body.bss_params.ext_set_sta_key_param_valid =
+               orig->bss_params.ext_set_sta_key_param_valid;
+
+       memcpy(&msg_body.bss_params.ext_set_sta_key_param,
+              &orig->bss_params.ext_set_sta_key_param,
+              sizeof(orig->bss_params.acvo));
+
+       msg_body.bss_params.wcn36xx_hal_persona =
+               orig->bss_params.wcn36xx_hal_persona;
+       msg_body.bss_params.spectrum_mgt_enable =
+               orig->bss_params.spectrum_mgt_enable;
+       msg_body.bss_params.tx_mgmt_power = orig->bss_params.tx_mgmt_power;
+       msg_body.bss_params.max_tx_power = orig->bss_params.max_tx_power;
+
+       wcn36xx_smd_convert_sta_to_v1(wcn, &orig->bss_params.sta,
+                                     &msg_body.bss_params.sta);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal config bss v1 bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",
+                   bss->bssid, bss->self_mac_addr, bss->bss_type,
+                   bss->oper_mode, bss->nw_type);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n",
+                   sta->bssid, sta->action, sta->sta_index,
+                   sta->bssid_index, sta->aid, sta->type, sta->mac);
+
+       return wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+}
+
+
+static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
+                                     struct ieee80211_vif *vif,
+                                     void *buf,
+                                     size_t len)
+{
+       struct wcn36xx_hal_config_bss_rsp_msg *rsp;
+       struct wcn36xx_hal_config_bss_rsp_params *params;
+       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       rsp = (struct wcn36xx_hal_config_bss_rsp_msg *)buf;
+       params = &rsp->bss_rsp_params;
+
+       if (params->status != WCN36XX_FW_MSG_RESULT_SUCCESS) {
+               wcn36xx_warn("hal config bss response failure: %d\n",
+                            params->status);
+               return -EIO;
+       }
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal config bss rsp status %d bss_idx %d dpu_desc_index %d"
+                   " sta_idx %d self_idx %d bcast_idx %d mac %pM"
+                   " power %d ucast_dpu_signature %d\n",
+                   params->status, params->bss_index, params->dpu_desc_index,
+                   params->bss_sta_index, params->bss_self_sta_index,
+                   params->bss_bcast_sta_idx, params->mac,
+                   params->tx_mgmt_power, params->ucast_dpu_signature);
+
+       priv_vif->bss_index = params->bss_index;
+
+       if (priv_vif->sta) {
+               priv_vif->sta->bss_sta_index =  params->bss_sta_index;
+               priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index;
+       }
+
+       priv_vif->ucast_dpu_signature = params->ucast_dpu_signature;
+
+       return 0;
+}
+
+int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta, const u8 *bssid,
+                          bool update)
+{
+       struct wcn36xx_hal_config_bss_req_msg msg;
+       struct wcn36xx_hal_config_bss_params *bss;
+       struct wcn36xx_hal_config_sta_params *sta_params;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg, WCN36XX_HAL_CONFIG_BSS_REQ);
+
+       bss = &msg.bss_params;
+       sta_params = &bss->sta;
+
+       WARN_ON(is_zero_ether_addr(bssid));
+
+       memcpy(&bss->bssid, bssid, ETH_ALEN);
+
+       memcpy(bss->self_mac_addr, vif->addr, ETH_ALEN);
+
+       if (vif->type == NL80211_IFTYPE_STATION) {
+               bss->bss_type = WCN36XX_HAL_INFRASTRUCTURE_MODE;
+
+               /* STA */
+               bss->oper_mode = 1;
+               bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_MODE;
+       } else if (vif->type == NL80211_IFTYPE_AP) {
+               bss->bss_type = WCN36XX_HAL_INFRA_AP_MODE;
+
+               /* AP */
+               bss->oper_mode = 0;
+               bss->wcn36xx_hal_persona = WCN36XX_HAL_STA_SAP_MODE;
+       } else if (vif->type == NL80211_IFTYPE_ADHOC ||
+                  vif->type == NL80211_IFTYPE_MESH_POINT) {
+               bss->bss_type = WCN36XX_HAL_IBSS_MODE;
+
+               /* STA */
+               bss->oper_mode = 1;
+       } else {
+               wcn36xx_warn("Unknown type for bss config: %d\n", vif->type);
+       }
+
+       if (vif->type == NL80211_IFTYPE_STATION)
+               wcn36xx_smd_set_bss_nw_type(wcn, sta, bss);
+       else
+               bss->nw_type = WCN36XX_HAL_11N_NW_TYPE;
+
+       bss->short_slot_time_supported = vif->bss_conf.use_short_slot;
+       bss->lla_coexist = 0;
+       bss->llb_coexist = 0;
+       bss->llg_coexist = 0;
+       bss->rifs_mode = 0;
+       bss->beacon_interval = vif->bss_conf.beacon_int;
+       bss->dtim_period = vif_priv->dtim_period;
+
+       wcn36xx_smd_set_bss_ht_params(vif, sta, bss);
+
+       bss->oper_channel = WCN36XX_HW_CHANNEL(wcn);
+
+       if (conf_is_ht40_minus(&wcn->hw->conf))
+               bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+       else if (conf_is_ht40_plus(&wcn->hw->conf))
+               bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+       else
+               bss->ext_channel = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+
+       bss->reserved = 0;
+       wcn36xx_smd_set_sta_params(wcn, vif, sta, sta_params);
+
+       /* wcn->ssid is only valid in AP and IBSS mode */
+       bss->ssid.length = vif_priv->ssid.length;
+       memcpy(bss->ssid.ssid, vif_priv->ssid.ssid, vif_priv->ssid.length);
+
+       bss->obss_prot_enabled = 0;
+       bss->rmf = 0;
+       bss->max_probe_resp_retry_limit = 0;
+       bss->hidden_ssid = vif->bss_conf.hidden_ssid;
+       bss->proxy_probe_resp = 0;
+       bss->edca_params_valid = 0;
+
+       /* FIXME: set acbe, acbk, acvi and acvo */
+
+       bss->ext_set_sta_key_param_valid = 0;
+
+       /* FIXME: set ext_set_sta_key_param */
+
+       bss->spectrum_mgt_enable = 0;
+       bss->tx_mgmt_power = 0;
+       bss->max_tx_power = WCN36XX_MAX_POWER(wcn);
+
+       bss->action = update;
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal config bss bssid %pM self_mac_addr %pM bss_type %d oper_mode %d nw_type %d\n",
+                   bss->bssid, bss->self_mac_addr, bss->bss_type,
+                   bss->oper_mode, bss->nw_type);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "- sta bssid %pM action %d sta_index %d bssid_index %d aid %d type %d mac %pM\n",
+                   sta_params->bssid, sta_params->action,
+                   sta_params->sta_index, sta_params->bssid_index,
+                   sta_params->aid, sta_params->type,
+                   sta_params->mac);
+
+       if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
+               ret = wcn36xx_smd_config_bss_v1(wcn, &msg);
+       } else {
+               PREPARE_HAL_BUF(wcn->hal_buf, msg);
+
+               ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len);
+       }
+       if (ret) {
+               wcn36xx_err("Sending hal_config_bss failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_config_bss_rsp(wcn,
+                                        vif,
+                                        wcn->hal_buf,
+                                        wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_config_bss response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif)
+{
+       struct wcn36xx_hal_delete_bss_req_msg msg_body;
+       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ);
+
+       msg_body.bss_index = priv_vif->bss_index;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "hal delete bss %d\n", msg_body.bss_index);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_delete_bss failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_delete_bss response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+                           struct sk_buff *skb_beacon, u16 tim_off,
+                           u16 p2p_off)
+{
+       struct wcn36xx_hal_send_beacon_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);
+
+       /* TODO need to find out why this is needed? */
+       msg_body.beacon_length = skb_beacon->len + 6;
+
+       if (BEACON_TEMPLATE_SIZE > msg_body.beacon_length) {
+               memcpy(&msg_body.beacon, &skb_beacon->len, sizeof(u32));
+               memcpy(&(msg_body.beacon[4]), skb_beacon->data,
+                      skb_beacon->len);
+       } else {
+               wcn36xx_err("Beacon is to big: beacon size=%d\n",
+                             msg_body.beacon_length);
+               return -ENOMEM;
+       }
+       memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
+
+       /* TODO need to find out why this is needed? */
+       msg_body.tim_ie_offset = tim_off+4;
+       msg_body.p2p_ie_offset = p2p_off;
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal send beacon beacon_length %d\n",
+                   msg_body.beacon_length);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_send_beacon failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_send_beacon response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn,
+                                     struct ieee80211_vif *vif,
+                                     struct sk_buff *skb)
+{
+       struct wcn36xx_hal_send_probe_resp_req_msg msg;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg, WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_REQ);
+
+       if (skb->len > BEACON_TEMPLATE_SIZE) {
+               wcn36xx_warn("probe response template is too big: %d\n",
+                            skb->len);
+               return -E2BIG;
+       }
+
+       msg.probe_resp_template_len = skb->len;
+       memcpy(&msg.probe_resp_template, skb->data, skb->len);
+
+       memcpy(msg.bssid, vif->addr, ETH_ALEN);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg);
+
+       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                   "hal update probe rsp len %d bssid %pM\n",
+                   msg.probe_resp_template_len, msg.bssid);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_update_proberesp_tmpl failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_update_proberesp_tmpl response failed err=%d\n",
+                           ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_set_stakey(struct wcn36xx *wcn,
+                          enum ani_ed_type enc_type,
+                          u8 keyidx,
+                          u8 keylen,
+                          u8 *key,
+                          u8 sta_index)
+{
+       struct wcn36xx_hal_set_sta_key_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_STAKEY_REQ);
+
+       msg_body.set_sta_key_params.sta_index = sta_index;
+       msg_body.set_sta_key_params.enc_type = enc_type;
+
+       msg_body.set_sta_key_params.key[0].id = keyidx;
+       msg_body.set_sta_key_params.key[0].unicast = 1;
+       msg_body.set_sta_key_params.key[0].direction = WCN36XX_HAL_TX_RX;
+       msg_body.set_sta_key_params.key[0].pae_role = 0;
+       msg_body.set_sta_key_params.key[0].length = keylen;
+       memcpy(msg_body.set_sta_key_params.key[0].key, key, keylen);
+       msg_body.set_sta_key_params.single_tid_rc = 1;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_set_stakey failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_set_stakey response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn,
+                          enum ani_ed_type enc_type,
+                          u8 keyidx,
+                          u8 keylen,
+                          u8 *key)
+{
+       struct wcn36xx_hal_set_bss_key_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_BSSKEY_REQ);
+       msg_body.bss_idx = 0;
+       msg_body.enc_type = enc_type;
+       msg_body.num_keys = 1;
+       msg_body.keys[0].id = keyidx;
+       msg_body.keys[0].unicast = 0;
+       msg_body.keys[0].direction = WCN36XX_HAL_RX_ONLY;
+       msg_body.keys[0].pae_role = 0;
+       msg_body.keys[0].length = keylen;
+       memcpy(msg_body.keys[0].key, key, keylen);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_set_bsskey failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_set_bsskey response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn,
+                             enum ani_ed_type enc_type,
+                             u8 keyidx,
+                             u8 sta_index)
+{
+       struct wcn36xx_hal_remove_sta_key_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_STAKEY_REQ);
+
+       msg_body.sta_idx = sta_index;
+       msg_body.enc_type = enc_type;
+       msg_body.key_id = keyidx;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_remove_stakey failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_remove_stakey response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
+                             enum ani_ed_type enc_type,
+                             u8 keyidx)
+{
+       struct wcn36xx_hal_remove_bss_key_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_RMV_BSSKEY_REQ);
+       msg_body.bss_idx = 0;
+       msg_body.enc_type = enc_type;
+       msg_body.key_id = keyidx;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_remove_bsskey failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
+{
+       struct wcn36xx_hal_enter_bmps_req_msg msg_body;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_ENTER_BMPS_REQ);
+
+       msg_body.bss_index = vif_priv->bss_index;
+       msg_body.tbtt = vif->bss_conf.sync_tsf;
+       msg_body.dtim_period = vif_priv->dtim_period;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_enter_bmps failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_enter_bmps response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
+{
+       struct wcn36xx_hal_enter_bmps_req_msg msg_body;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_EXIT_BMPS_REQ);
+
+       msg_body.bss_index = vif_priv->bss_index;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_exit_bmps failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim)
+{
+       struct wcn36xx_hal_set_power_params_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_SET_POWER_PARAMS_REQ);
+
+       /*
+        * When host is down ignore every second dtim
+        */
+       if (ignore_dtim) {
+               msg_body.ignore_dtim = 1;
+               msg_body.dtim_period = 2;
+       }
+       msg_body.listen_interval = WCN36XX_LISTEN_INTERVAL(wcn);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_set_power_params failed\n");
+               goto out;
+       }
+
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+/* Notice: This function should be called after associated, or else it
+ * will be invalid
+ */
+int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
+                              struct ieee80211_vif *vif,
+                              int packet_type)
+{
+       struct wcn36xx_hal_keep_alive_req_msg msg_body;
+       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_KEEP_ALIVE_REQ);
+
+       if (packet_type == WCN36XX_HAL_KEEP_ALIVE_NULL_PKT) {
+               msg_body.bss_index = vif_priv->bss_index;
+               msg_body.packet_type = WCN36XX_HAL_KEEP_ALIVE_NULL_PKT;
+               msg_body.time_period = WCN36XX_KEEP_ALIVE_TIME_PERIOD;
+       } else if (packet_type == WCN36XX_HAL_KEEP_ALIVE_UNSOLICIT_ARP_RSP) {
+               /* TODO: it also support ARP response type */
+       } else {
+               wcn36xx_warn("unknow keep alive packet type %d\n", packet_type);
+               return -EINVAL;
+       }
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_exit_bmps failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_exit_bmps response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2,
+                            u32 arg3, u32 arg4, u32 arg5)
+{
+       struct wcn36xx_hal_dump_cmd_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_DUMP_COMMAND_REQ);
+
+       msg_body.arg1 = arg1;
+       msg_body.arg2 = arg2;
+       msg_body.arg3 = arg3;
+       msg_body.arg4 = arg4;
+       msg_body.arg5 = arg5;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_dump_cmd failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_dump_cmd response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static inline void set_feat_caps(u32 *bitmap,
+                                enum place_holder_in_cap_bitmap cap)
+{
+       int arr_idx, bit_idx;
+
+       if (cap < 0 || cap > 127) {
+               wcn36xx_warn("error cap idx %d\n", cap);
+               return;
+       }
+
+       arr_idx = cap / 32;
+       bit_idx = cap % 32;
+       bitmap[arr_idx] |= (1 << bit_idx);
+}
+
+static inline int get_feat_caps(u32 *bitmap,
+                               enum place_holder_in_cap_bitmap cap)
+{
+       int arr_idx, bit_idx;
+       int ret = 0;
+
+       if (cap < 0 || cap > 127) {
+               wcn36xx_warn("error cap idx %d\n", cap);
+               return -EINVAL;
+       }
+
+       arr_idx = cap / 32;
+       bit_idx = cap % 32;
+       ret = (bitmap[arr_idx] & (1 << bit_idx)) ? 1 : 0;
+       return ret;
+}
+
+static inline void clear_feat_caps(u32 *bitmap,
+                               enum place_holder_in_cap_bitmap cap)
+{
+       int arr_idx, bit_idx;
+
+       if (cap < 0 || cap > 127) {
+               wcn36xx_warn("error cap idx %d\n", cap);
+               return;
+       }
+
+       arr_idx = cap / 32;
+       bit_idx = cap % 32;
+       bitmap[arr_idx] &= ~(1 << bit_idx);
+}
+
+int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_feat_caps_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_REQ);
+
+       set_feat_caps(msg_body.feat_caps, STA_POWERSAVE);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_feature_caps_exchange failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_feature_caps_exchange response failed err=%d\n",
+                           ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
+               struct ieee80211_sta *sta,
+               u16 tid,
+               u16 *ssn,
+               u8 direction,
+               u8 sta_index)
+{
+       struct wcn36xx_hal_add_ba_session_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_SESSION_REQ);
+
+       msg_body.sta_index = sta_index;
+       memcpy(&msg_body.mac_addr, sta->addr, ETH_ALEN);
+       msg_body.dialog_token = 0x10;
+       msg_body.tid = tid;
+
+       /* Immediate BA because Delayed BA is not supported */
+       msg_body.policy = 1;
+       msg_body.buffer_size = WCN36XX_AGGR_BUFFER_SIZE;
+       msg_body.timeout = 0;
+       if (ssn)
+               msg_body.ssn = *ssn;
+       msg_body.direction = direction;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_add_ba_session failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_add_ba_session response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_add_ba(struct wcn36xx *wcn)
+{
+       struct wcn36xx_hal_add_ba_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_ADD_BA_REQ);
+
+       msg_body.session_id = 0;
+       msg_body.win_size = WCN36XX_AGGR_BUFFER_SIZE;
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_add_ba failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_add_ba response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index)
+{
+       struct wcn36xx_hal_del_ba_req_msg msg_body;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_DEL_BA_REQ);
+
+       msg_body.sta_index = sta_index;
+       msg_body.tid = tid;
+       msg_body.direction = 0;
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_del_ba failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_del_ba response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
+{
+       struct wcn36xx_hal_trigger_ba_req_msg msg_body;
+       struct wcn36xx_hal_trigget_ba_req_candidate *candidate;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_TRIGGER_BA_REQ);
+
+       msg_body.session_id = 0;
+       msg_body.candidate_cnt = 1;
+       msg_body.header.len += sizeof(*candidate);
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       candidate = (struct wcn36xx_hal_trigget_ba_req_candidate *)
+               (wcn->hal_buf + sizeof(msg_body));
+       candidate->sta_index = sta_index;
+       candidate->tid_bitmap = 1;
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_trigger_ba failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
+static int wcn36xx_smd_tx_compl_ind(struct wcn36xx *wcn, void *buf, size_t len)
+{
+       struct wcn36xx_hal_tx_compl_ind_msg *rsp = buf;
+
+       if (len != sizeof(*rsp)) {
+               wcn36xx_warn("Bad TX complete indication\n");
+               return -EIO;
+       }
+
+       wcn36xx_dxe_tx_ack_ind(wcn, rsp->status);
+
+       return 0;
+}
+
+static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
+                                        void *buf,
+                                        size_t len)
+{
+       struct wcn36xx_hal_missed_beacon_ind_msg *rsp = buf;
+       struct ieee80211_vif *vif = NULL;
+       struct wcn36xx_vif *tmp;
+
+       /* Old FW does not have bss index */
+       if (wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
+               list_for_each_entry(tmp, &wcn->vif_list, list) {
+                       wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
+                                   tmp->bss_index);
+                       vif = container_of((void *)tmp,
+                                                struct ieee80211_vif,
+                                                drv_priv);
+                       ieee80211_connection_loss(vif);
+               }
+               return 0;
+       }
+
+       if (len != sizeof(*rsp)) {
+               wcn36xx_warn("Corrupted missed beacon indication\n");
+               return -EIO;
+       }
+
+       list_for_each_entry(tmp, &wcn->vif_list, list) {
+               if (tmp->bss_index == rsp->bss_index) {
+                       wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
+                                   rsp->bss_index);
+                       vif = container_of((void *)tmp,
+                                                struct ieee80211_vif,
+                                                drv_priv);
+                       ieee80211_connection_loss(vif);
+                       return 0;
+               }
+       }
+
+       wcn36xx_warn("BSS index %d not found\n", rsp->bss_index);
+       return -ENOENT;
+}
+
+static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
+                                             void *buf,
+                                             size_t len)
+{
+       struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf;
+       struct wcn36xx_vif *tmp;
+       struct ieee80211_sta *sta = NULL;
+
+       if (len != sizeof(*rsp)) {
+               wcn36xx_warn("Corrupted delete sta indication\n");
+               return -EIO;
+       }
+
+       list_for_each_entry(tmp, &wcn->vif_list, list) {
+               if (sta && (tmp->sta->sta_index == rsp->sta_id)) {
+                       sta = container_of((void *)tmp->sta,
+                                                struct ieee80211_sta,
+                                                drv_priv);
+                       wcn36xx_dbg(WCN36XX_DBG_HAL,
+                                   "delete station indication %pM index %d\n",
+                                   rsp->addr2,
+                                   rsp->sta_id);
+                       ieee80211_report_low_ack(sta, 0);
+                       return 0;
+               }
+       }
+
+       wcn36xx_warn("STA with addr %pM and index %d not found\n",
+                    rsp->addr2,
+                    rsp->sta_id);
+       return -ENOENT;
+}
+
+int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value)
+{
+       struct wcn36xx_hal_update_cfg_req_msg msg_body, *body;
+       size_t len;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+       INIT_HAL_MSG(msg_body, WCN36XX_HAL_UPDATE_CFG_REQ);
+
+       PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+
+       body = (struct wcn36xx_hal_update_cfg_req_msg *) wcn->hal_buf;
+       len = msg_body.header.len;
+
+       put_cfg_tlv_u32(wcn, &len, cfg_id, value);
+       body->header.len = len;
+       body->len = len - sizeof(*body);
+
+       ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);
+       if (ret) {
+               wcn36xx_err("Sending hal_update_cfg failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("hal_update_cfg response failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
+{
+       struct wcn36xx_hal_msg_header *msg_header = buf;
+       struct wcn36xx_hal_ind_msg *msg_ind;
+       wcn36xx_dbg_dump(WCN36XX_DBG_SMD_DUMP, "SMD <<< ", buf, len);
+
+       switch (msg_header->msg_type) {
+       case WCN36XX_HAL_START_RSP:
+       case WCN36XX_HAL_CONFIG_STA_RSP:
+       case WCN36XX_HAL_CONFIG_BSS_RSP:
+       case WCN36XX_HAL_ADD_STA_SELF_RSP:
+       case WCN36XX_HAL_STOP_RSP:
+       case WCN36XX_HAL_DEL_STA_SELF_RSP:
+       case WCN36XX_HAL_DELETE_STA_RSP:
+       case WCN36XX_HAL_INIT_SCAN_RSP:
+       case WCN36XX_HAL_START_SCAN_RSP:
+       case WCN36XX_HAL_END_SCAN_RSP:
+       case WCN36XX_HAL_FINISH_SCAN_RSP:
+       case WCN36XX_HAL_DOWNLOAD_NV_RSP:
+       case WCN36XX_HAL_DELETE_BSS_RSP:
+       case WCN36XX_HAL_SEND_BEACON_RSP:
+       case WCN36XX_HAL_SET_LINK_ST_RSP:
+       case WCN36XX_HAL_UPDATE_PROBE_RSP_TEMPLATE_RSP:
+       case WCN36XX_HAL_SET_BSSKEY_RSP:
+       case WCN36XX_HAL_SET_STAKEY_RSP:
+       case WCN36XX_HAL_RMV_STAKEY_RSP:
+       case WCN36XX_HAL_RMV_BSSKEY_RSP:
+       case WCN36XX_HAL_ENTER_BMPS_RSP:
+       case WCN36XX_HAL_SET_POWER_PARAMS_RSP:
+       case WCN36XX_HAL_EXIT_BMPS_RSP:
+       case WCN36XX_HAL_KEEP_ALIVE_RSP:
+       case WCN36XX_HAL_DUMP_COMMAND_RSP:
+       case WCN36XX_HAL_ADD_BA_SESSION_RSP:
+       case WCN36XX_HAL_ADD_BA_RSP:
+       case WCN36XX_HAL_DEL_BA_RSP:
+       case WCN36XX_HAL_TRIGGER_BA_RSP:
+       case WCN36XX_HAL_UPDATE_CFG_RSP:
+       case WCN36XX_HAL_JOIN_RSP:
+       case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP:
+       case WCN36XX_HAL_CH_SWITCH_RSP:
+       case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
+               memcpy(wcn->hal_buf, buf, len);
+               wcn->hal_rsp_len = len;
+               complete(&wcn->hal_rsp_compl);
+               break;
+
+       case WCN36XX_HAL_OTA_TX_COMPL_IND:
+       case WCN36XX_HAL_MISSED_BEACON_IND:
+       case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
+               mutex_lock(&wcn->hal_ind_mutex);
+               msg_ind = kmalloc(sizeof(*msg_ind), GFP_KERNEL);
+               msg_ind->msg_len = len;
+               msg_ind->msg = kmalloc(len, GFP_KERNEL);
+               memcpy(msg_ind->msg, buf, len);
+               list_add_tail(&msg_ind->list, &wcn->hal_ind_queue);
+               queue_work(wcn->hal_ind_wq, &wcn->hal_ind_work);
+               wcn36xx_dbg(WCN36XX_DBG_HAL, "indication arrived\n");
+               mutex_unlock(&wcn->hal_ind_mutex);
+               break;
+       default:
+               wcn36xx_err("SMD_EVENT (%d) not supported\n",
+                             msg_header->msg_type);
+       }
+}
+static void wcn36xx_ind_smd_work(struct work_struct *work)
+{
+       struct wcn36xx *wcn =
+               container_of(work, struct wcn36xx, hal_ind_work);
+       struct wcn36xx_hal_msg_header *msg_header;
+       struct wcn36xx_hal_ind_msg *hal_ind_msg;
+
+       mutex_lock(&wcn->hal_ind_mutex);
+
+       hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
+                                      struct wcn36xx_hal_ind_msg,
+                                      list);
+
+       msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
+
+       switch (msg_header->msg_type) {
+       case WCN36XX_HAL_OTA_TX_COMPL_IND:
+               wcn36xx_smd_tx_compl_ind(wcn,
+                                        hal_ind_msg->msg,
+                                        hal_ind_msg->msg_len);
+               break;
+       case WCN36XX_HAL_MISSED_BEACON_IND:
+               wcn36xx_smd_missed_beacon_ind(wcn,
+                                             hal_ind_msg->msg,
+                                             hal_ind_msg->msg_len);
+               break;
+       case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
+               wcn36xx_smd_delete_sta_context_ind(wcn,
+                                                  hal_ind_msg->msg,
+                                                  hal_ind_msg->msg_len);
+               break;
+       default:
+               wcn36xx_err("SMD_EVENT (%d) not supported\n",
+                             msg_header->msg_type);
+       }
+       list_del(wcn->hal_ind_queue.next);
+       kfree(hal_ind_msg->msg);
+       kfree(hal_ind_msg);
+       mutex_unlock(&wcn->hal_ind_mutex);
+}
+int wcn36xx_smd_open(struct wcn36xx *wcn)
+{
+       int ret = 0;
+       wcn->hal_ind_wq = create_freezable_workqueue("wcn36xx_smd_ind");
+       if (!wcn->hal_ind_wq) {
+               wcn36xx_err("failed to allocate wq\n");
+               ret = -ENOMEM;
+               goto out;
+       }
+       INIT_WORK(&wcn->hal_ind_work, wcn36xx_ind_smd_work);
+       INIT_LIST_HEAD(&wcn->hal_ind_queue);
+       mutex_init(&wcn->hal_ind_mutex);
+
+       ret = wcn->ctrl_ops->open(wcn, wcn36xx_smd_rsp_process);
+       if (ret) {
+               wcn36xx_err("failed to open control channel\n");
+               goto free_wq;
+       }
+
+       return ret;
+
+free_wq:
+       destroy_workqueue(wcn->hal_ind_wq);
+out:
+       return ret;
+}
+
+void wcn36xx_smd_close(struct wcn36xx *wcn)
+{
+       wcn->ctrl_ops->close();
+       destroy_workqueue(wcn->hal_ind_wq);
+       mutex_destroy(&wcn->hal_ind_mutex);
+}
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.h b/drivers/net/wireless/ath/wcn36xx/smd.h
new file mode 100644 (file)
index 0000000..e7c3901
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SMD_H_
+#define _SMD_H_
+
+#include "wcn36xx.h"
+
+/* Max shared size is 4k but we take less.*/
+#define WCN36XX_NV_FRAGMENT_SIZE                       3072
+
+#define WCN36XX_HAL_BUF_SIZE                           4096
+
+#define HAL_MSG_TIMEOUT 200
+#define WCN36XX_SMSM_WLAN_TX_ENABLE                    0x00000400
+#define WCN36XX_SMSM_WLAN_TX_RINGS_EMPTY               0x00000200
+/* The PNO version info be contained in the rsp msg */
+#define WCN36XX_FW_MSG_PNO_VERSION_MASK                        0x8000
+
+enum wcn36xx_fw_msg_result {
+       WCN36XX_FW_MSG_RESULT_SUCCESS                   = 0,
+       WCN36XX_FW_MSG_RESULT_SUCCESS_SYNC              = 1,
+
+       WCN36XX_FW_MSG_RESULT_MEM_FAIL                  = 5,
+};
+
+/******************************/
+/* SMD requests and responses */
+/******************************/
+struct wcn36xx_fw_msg_status_rsp {
+       u32     status;
+} __packed;
+
+struct wcn36xx_hal_ind_msg {
+       struct list_head list;
+       u8 *msg;
+       size_t msg_len;
+};
+
+struct wcn36xx;
+
+int wcn36xx_smd_open(struct wcn36xx *wcn);
+void wcn36xx_smd_close(struct wcn36xx *wcn);
+
+int wcn36xx_smd_load_nv(struct wcn36xx *wcn);
+int wcn36xx_smd_start(struct wcn36xx *wcn);
+int wcn36xx_smd_stop(struct wcn36xx *wcn);
+int wcn36xx_smd_init_scan(struct wcn36xx *wcn, enum wcn36xx_hal_sys_mode mode);
+int wcn36xx_smd_start_scan(struct wcn36xx *wcn);
+int wcn36xx_smd_end_scan(struct wcn36xx *wcn);
+int wcn36xx_smd_finish_scan(struct wcn36xx *wcn,
+                           enum wcn36xx_hal_sys_mode mode);
+int wcn36xx_smd_update_scan_params(struct wcn36xx *wcn);
+int wcn36xx_smd_add_sta_self(struct wcn36xx *wcn, struct ieee80211_vif *vif);
+int wcn36xx_smd_delete_sta_self(struct wcn36xx *wcn, u8 *addr);
+int wcn36xx_smd_delete_sta(struct wcn36xx *wcn, u8 sta_index);
+int wcn36xx_smd_join(struct wcn36xx *wcn, const u8 *bssid, u8 *vif, u8 ch);
+int wcn36xx_smd_set_link_st(struct wcn36xx *wcn, const u8 *bssid,
+                           const u8 *sta_mac,
+                           enum wcn36xx_hal_link_state state);
+int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta, const u8 *bssid,
+                          bool update);
+int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif);
+int wcn36xx_smd_config_sta(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+                          struct ieee80211_sta *sta);
+int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
+                           struct sk_buff *skb_beacon, u16 tim_off,
+                           u16 p2p_off);
+int wcn36xx_smd_switch_channel(struct wcn36xx *wcn,
+                              struct ieee80211_vif *vif, int ch);
+int wcn36xx_smd_update_proberesp_tmpl(struct wcn36xx *wcn,
+                                     struct ieee80211_vif *vif,
+                                     struct sk_buff *skb);
+int wcn36xx_smd_set_stakey(struct wcn36xx *wcn,
+                          enum ani_ed_type enc_type,
+                          u8 keyidx,
+                          u8 keylen,
+                          u8 *key,
+                          u8 sta_index);
+int wcn36xx_smd_set_bsskey(struct wcn36xx *wcn,
+                          enum ani_ed_type enc_type,
+                          u8 keyidx,
+                          u8 keylen,
+                          u8 *key);
+int wcn36xx_smd_remove_stakey(struct wcn36xx *wcn,
+                             enum ani_ed_type enc_type,
+                             u8 keyidx,
+                             u8 sta_index);
+int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
+                             enum ani_ed_type enc_type,
+                             u8 keyidx);
+int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif);
+int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif);
+int wcn36xx_smd_set_power_params(struct wcn36xx *wcn, bool ignore_dtim);
+int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
+                              struct ieee80211_vif *vif,
+                              int packet_type);
+int wcn36xx_smd_dump_cmd_req(struct wcn36xx *wcn, u32 arg1, u32 arg2,
+                            u32 arg3, u32 arg4, u32 arg5);
+int wcn36xx_smd_feature_caps_exchange(struct wcn36xx *wcn);
+
+int wcn36xx_smd_add_ba_session(struct wcn36xx *wcn,
+               struct ieee80211_sta *sta,
+               u16 tid,
+               u16 *ssn,
+               u8 direction,
+               u8 sta_index);
+int wcn36xx_smd_add_ba(struct wcn36xx *wcn);
+int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
+int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
+
+int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+#endif /* _SMD_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
new file mode 100644 (file)
index 0000000..b2b60e3
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include "txrx.h"
+
+static inline int get_rssi0(struct wcn36xx_rx_bd *bd)
+{
+       return 100 - ((bd->phy_stat0 >> 24) & 0xff);
+}
+
+int wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb)
+{
+       struct ieee80211_rx_status status;
+       struct ieee80211_hdr *hdr;
+       struct wcn36xx_rx_bd *bd;
+       u16 fc, sn;
+
+       /*
+        * All fields must be 0, otherwise it can lead to
+        * unexpected consequences.
+        */
+       memset(&status, 0, sizeof(status));
+
+       bd = (struct wcn36xx_rx_bd *)skb->data;
+       buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
+       wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP,
+                        "BD   <<< ", (char *)bd,
+                        sizeof(struct wcn36xx_rx_bd));
+
+       skb_put(skb, bd->pdu.mpdu_header_off + bd->pdu.mpdu_len);
+       skb_pull(skb, bd->pdu.mpdu_header_off);
+
+       status.mactime = 10;
+       status.freq = WCN36XX_CENTER_FREQ(wcn);
+       status.band = WCN36XX_BAND(wcn);
+       status.signal = -get_rssi0(bd);
+       status.antenna = 1;
+       status.rate_idx = 1;
+       status.flag = 0;
+       status.rx_flags = 0;
+       status.flag |= RX_FLAG_IV_STRIPPED |
+                      RX_FLAG_MMIC_STRIPPED |
+                      RX_FLAG_DECRYPTED;
+
+       wcn36xx_dbg(WCN36XX_DBG_RX, "status.flags=%x status->vendor_radiotap_len=%x\n",
+                   status.flag,  status.vendor_radiotap_len);
+
+       memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = __le16_to_cpu(hdr->frame_control);
+       sn = IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl));
+
+       if (ieee80211_is_beacon(hdr->frame_control)) {
+               wcn36xx_dbg(WCN36XX_DBG_BEACON, "beacon skb %p len %d fc %04x sn %d\n",
+                           skb, skb->len, fc, sn);
+               wcn36xx_dbg_dump(WCN36XX_DBG_BEACON_DUMP, "SKB <<< ",
+                                (char *)skb->data, skb->len);
+       } else {
+               wcn36xx_dbg(WCN36XX_DBG_RX, "rx skb %p len %d fc %04x sn %d\n",
+                           skb, skb->len, fc, sn);
+               wcn36xx_dbg_dump(WCN36XX_DBG_RX_DUMP, "SKB <<< ",
+                                (char *)skb->data, skb->len);
+       }
+
+       ieee80211_rx_irqsafe(wcn->hw, skb);
+
+       return 0;
+}
+
+static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd,
+                              u32 mpdu_header_len,
+                              u32 len,
+                              u16 tid)
+{
+       bd->pdu.mpdu_header_len = mpdu_header_len;
+       bd->pdu.mpdu_header_off = sizeof(*bd);
+       bd->pdu.mpdu_data_off = bd->pdu.mpdu_header_len +
+               bd->pdu.mpdu_header_off;
+       bd->pdu.mpdu_len = len;
+       bd->pdu.tid = tid;
+}
+
+static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
+                                                 u8 *addr)
+{
+       struct wcn36xx_vif *vif_priv = NULL;
+       struct ieee80211_vif *vif = NULL;
+       list_for_each_entry(vif_priv, &wcn->vif_list, list) {
+                       vif = container_of((void *)vif_priv,
+                                  struct ieee80211_vif,
+                                  drv_priv);
+                       if (memcmp(vif->addr, addr, ETH_ALEN) == 0)
+                               return vif_priv;
+       }
+       wcn36xx_warn("vif %pM not found\n", addr);
+       return NULL;
+}
+static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
+                               struct wcn36xx *wcn,
+                               struct wcn36xx_vif **vif_priv,
+                               struct wcn36xx_sta *sta_priv,
+                               struct ieee80211_hdr *hdr,
+                               bool bcast)
+{
+       struct ieee80211_vif *vif = NULL;
+       struct wcn36xx_vif *__vif_priv = NULL;
+       bd->bd_rate = WCN36XX_BD_RATE_DATA;
+
+       /*
+        * For not unicast frames mac80211 will not set sta pointer so use
+        * self_sta_index instead.
+        */
+       if (sta_priv) {
+               __vif_priv = sta_priv->vif;
+               vif = container_of((void *)__vif_priv,
+                                  struct ieee80211_vif,
+                                  drv_priv);
+
+               if (vif->type == NL80211_IFTYPE_STATION) {
+                       bd->sta_index = sta_priv->bss_sta_index;
+                       bd->dpu_desc_idx = sta_priv->bss_dpu_desc_index;
+               } else if (vif->type == NL80211_IFTYPE_AP ||
+                          vif->type == NL80211_IFTYPE_ADHOC ||
+                          vif->type == NL80211_IFTYPE_MESH_POINT) {
+                       bd->sta_index = sta_priv->sta_index;
+                       bd->dpu_desc_idx = sta_priv->dpu_desc_index;
+               }
+       } else {
+               __vif_priv = get_vif_by_addr(wcn, hdr->addr2);
+               bd->sta_index = __vif_priv->self_sta_index;
+               bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index;
+       }
+
+       bd->dpu_sign = __vif_priv->ucast_dpu_signature;
+
+       if (ieee80211_is_nullfunc(hdr->frame_control) ||
+          (sta_priv && !sta_priv->is_data_encrypted))
+               bd->dpu_ne = 1;
+
+       if (bcast) {
+               bd->ub = 1;
+               bd->ack_policy = 1;
+       }
+       *vif_priv = __vif_priv;
+}
+
+static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
+                               struct wcn36xx *wcn,
+                               struct wcn36xx_vif **vif_priv,
+                               struct ieee80211_hdr *hdr,
+                               bool bcast)
+{
+       struct wcn36xx_vif *__vif_priv =
+               get_vif_by_addr(wcn, hdr->addr2);
+       bd->sta_index = __vif_priv->self_sta_index;
+       bd->dpu_desc_idx = __vif_priv->self_dpu_desc_index;
+       bd->dpu_ne = 1;
+
+       /* default rate for unicast */
+       if (ieee80211_is_mgmt(hdr->frame_control))
+               bd->bd_rate = (WCN36XX_BAND(wcn) == IEEE80211_BAND_5GHZ) ?
+                       WCN36XX_BD_RATE_CTRL :
+                       WCN36XX_BD_RATE_MGMT;
+       else if (ieee80211_is_ctl(hdr->frame_control))
+               bd->bd_rate = WCN36XX_BD_RATE_CTRL;
+       else
+               wcn36xx_warn("frame control type unknown\n");
+
+       /*
+        * In joining state trick hardware that probe is sent as
+        * unicast even if address is broadcast.
+        */
+       if (__vif_priv->is_joining &&
+           ieee80211_is_probe_req(hdr->frame_control))
+               bcast = false;
+
+       if (bcast) {
+               /* broadcast */
+               bd->ub = 1;
+               /* No ack needed not unicast */
+               bd->ack_policy = 1;
+               bd->queue_id = WCN36XX_TX_B_WQ_ID;
+       } else
+               bd->queue_id = WCN36XX_TX_U_WQ_ID;
+       *vif_priv = __vif_priv;
+}
+
+int wcn36xx_start_tx(struct wcn36xx *wcn,
+                    struct wcn36xx_sta *sta_priv,
+                    struct sk_buff *skb)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct wcn36xx_vif *vif_priv = NULL;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       unsigned long flags;
+       bool is_low = ieee80211_is_data(hdr->frame_control);
+       bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
+               is_multicast_ether_addr(hdr->addr1);
+       struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low);
+
+       if (!bd) {
+               /*
+                * TX DXE are used in pairs. One for the BD and one for the
+                * actual frame. The BD DXE's has a preallocated buffer while
+                * the skb ones does not. If this isn't true something is really
+                * wierd. TODO: Recover from this situation
+                */
+
+               wcn36xx_err("bd address may not be NULL for BD DXE\n");
+               return -EINVAL;
+       }
+
+       memset(bd, 0, sizeof(*bd));
+
+       wcn36xx_dbg(WCN36XX_DBG_TX,
+                   "tx skb %p len %d fc %04x sn %d %s %s\n",
+                   skb, skb->len, __le16_to_cpu(hdr->frame_control),
+                   IEEE80211_SEQ_TO_SN(__le16_to_cpu(hdr->seq_ctrl)),
+                   is_low ? "low" : "high", bcast ? "bcast" : "ucast");
+
+       wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len);
+
+       bd->dpu_rf = WCN36XX_BMU_WQ_TX;
+
+       bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS;
+       if (bd->tx_comp) {
+               wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
+               spin_lock_irqsave(&wcn->dxe_lock, flags);
+               if (wcn->tx_ack_skb) {
+                       spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+                       wcn36xx_warn("tx_ack_skb already set\n");
+                       return -EINVAL;
+               }
+
+               wcn->tx_ack_skb = skb;
+               spin_unlock_irqrestore(&wcn->dxe_lock, flags);
+
+               /* Only one at a time is supported by fw. Stop the TX queues
+                * until the ack status gets back.
+                *
+                * TODO: Add watchdog in case FW does not answer
+                */
+               ieee80211_stop_queues(wcn->hw);
+       }
+
+       /* Data frames served first*/
+       if (is_low) {
+               wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast);
+               wcn36xx_set_tx_pdu(bd,
+                          ieee80211_is_data_qos(hdr->frame_control) ?
+                          sizeof(struct ieee80211_qos_hdr) :
+                          sizeof(struct ieee80211_hdr_3addr),
+                          skb->len, sta_priv ? sta_priv->tid : 0);
+       } else {
+               /* MGMT and CTRL frames are handeld here*/
+               wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast);
+               wcn36xx_set_tx_pdu(bd,
+                          ieee80211_is_data_qos(hdr->frame_control) ?
+                          sizeof(struct ieee80211_qos_hdr) :
+                          sizeof(struct ieee80211_hdr_3addr),
+                          skb->len, WCN36XX_TID);
+       }
+
+       buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
+       bd->tx_bd_sign = 0xbdbdbdbd;
+
+       return wcn36xx_dxe_tx_frame(wcn, vif_priv, skb, is_low);
+}
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h
new file mode 100644 (file)
index 0000000..bbfbcf8
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TXRX_H_
+#define _TXRX_H_
+
+#include <linux/etherdevice.h>
+#include "wcn36xx.h"
+
+/* TODO describe all properties */
+#define WCN36XX_802_11_HEADER_LEN      24
+#define WCN36XX_BMU_WQ_TX              25
+#define WCN36XX_TID                    7
+/* broadcast wq ID */
+#define WCN36XX_TX_B_WQ_ID             0xA
+#define WCN36XX_TX_U_WQ_ID             0x9
+/* bd_rate */
+#define WCN36XX_BD_RATE_DATA 0
+#define WCN36XX_BD_RATE_MGMT 2
+#define WCN36XX_BD_RATE_CTRL 3
+
+struct wcn36xx_pdu {
+       u32     dpu_fb:8;
+       u32     adu_fb:8;
+       u32     pdu_id:16;
+
+       /* 0x04*/
+       u32     tail_pdu_idx:16;
+       u32     head_pdu_idx:16;
+
+       /* 0x08*/
+       u32     pdu_count:7;
+       u32     mpdu_data_off:9;
+       u32     mpdu_header_off:8;
+       u32     mpdu_header_len:8;
+
+       /* 0x0c*/
+       u32     reserved4:8;
+       u32     tid:4;
+       u32     reserved3:4;
+       u32     mpdu_len:16;
+};
+
+struct wcn36xx_rx_bd {
+       u32     bdt:2;
+       u32     ft:1;
+       u32     dpu_ne:1;
+       u32     rx_key_id:3;
+       u32     ub:1;
+       u32     rmf:1;
+       u32     uma_bypass:1;
+       u32     csr11:1;
+       u32     reserved0:1;
+       u32     scan_learn:1;
+       u32     rx_ch:4;
+       u32     rtsf:1;
+       u32     bsf:1;
+       u32     a2hf:1;
+       u32     st_auf:1;
+       u32     dpu_sign:3;
+       u32     dpu_rf:8;
+
+       struct wcn36xx_pdu pdu;
+
+       /* 0x14*/
+       u32     addr3:8;
+       u32     addr2:8;
+       u32     addr1:8;
+       u32     dpu_desc_idx:8;
+
+       /* 0x18*/
+       u32     rxp_flags:23;
+       u32     rate_id:9;
+
+       u32     phy_stat0;
+       u32     phy_stat1;
+
+       /* 0x24 */
+       u32     rx_times;
+
+       u32     pmi_cmd[6];
+
+       /* 0x40 */
+       u32     reserved7:4;
+       u32     reorder_slot_id:6;
+       u32     reorder_fwd_id:6;
+       u32     reserved6:12;
+       u32     reorder_code:4;
+
+       /* 0x44 */
+       u32     exp_seq_num:12;
+       u32     cur_seq_num:12;
+       u32     fr_type_subtype:8;
+
+       /* 0x48 */
+       u32     msdu_size:16;
+       u32     sub_fr_id:4;
+       u32     proc_order:4;
+       u32     reserved9:4;
+       u32     aef:1;
+       u32     lsf:1;
+       u32     esf:1;
+       u32     asf:1;
+};
+
+struct wcn36xx_tx_bd {
+       u32     bdt:2;
+       u32     ft:1;
+       u32     dpu_ne:1;
+       u32     fw_tx_comp:1;
+       u32     tx_comp:1;
+       u32     reserved1:1;
+       u32     ub:1;
+       u32     rmf:1;
+       u32     reserved0:12;
+       u32     dpu_sign:3;
+       u32     dpu_rf:8;
+
+       struct wcn36xx_pdu pdu;
+
+       /* 0x14*/
+       u32     reserved5:7;
+       u32     queue_id:5;
+       u32     bd_rate:2;
+       u32     ack_policy:2;
+       u32     sta_index:8;
+       u32     dpu_desc_idx:8;
+
+       u32     tx_bd_sign;
+       u32     reserved6;
+       u32     dxe_start_time;
+       u32     dxe_end_time;
+
+       /*u32   tcp_udp_start_off:10;
+       u32     header_cks:16;
+       u32     reserved7:6;*/
+};
+
+struct wcn36xx_sta;
+struct wcn36xx;
+
+int  wcn36xx_rx_skb(struct wcn36xx *wcn, struct sk_buff *skb);
+int wcn36xx_start_tx(struct wcn36xx *wcn,
+                    struct wcn36xx_sta *sta_priv,
+                    struct sk_buff *skb);
+
+#endif /* _TXRX_H_ */
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
new file mode 100644 (file)
index 0000000..58b6383
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WCN36XX_H_
+#define _WCN36XX_H_
+
+#include <linux/completion.h>
+#include <linux/printk.h>
+#include <linux/spinlock.h>
+#include <net/mac80211.h>
+
+#include "hal.h"
+#include "smd.h"
+#include "txrx.h"
+#include "dxe.h"
+#include "pmc.h"
+#include "debug.h"
+
+#define WLAN_NV_FILE               "wlan/prima/WCNSS_qcom_wlan_nv.bin"
+#define WCN36XX_AGGR_BUFFER_SIZE 64
+
+extern unsigned int wcn36xx_dbg_mask;
+
+enum wcn36xx_debug_mask {
+       WCN36XX_DBG_DXE         = 0x00000001,
+       WCN36XX_DBG_DXE_DUMP    = 0x00000002,
+       WCN36XX_DBG_SMD         = 0x00000004,
+       WCN36XX_DBG_SMD_DUMP    = 0x00000008,
+       WCN36XX_DBG_RX          = 0x00000010,
+       WCN36XX_DBG_RX_DUMP     = 0x00000020,
+       WCN36XX_DBG_TX          = 0x00000040,
+       WCN36XX_DBG_TX_DUMP     = 0x00000080,
+       WCN36XX_DBG_HAL         = 0x00000100,
+       WCN36XX_DBG_HAL_DUMP    = 0x00000200,
+       WCN36XX_DBG_MAC         = 0x00000400,
+       WCN36XX_DBG_BEACON      = 0x00000800,
+       WCN36XX_DBG_BEACON_DUMP = 0x00001000,
+       WCN36XX_DBG_PMC         = 0x00002000,
+       WCN36XX_DBG_PMC_DUMP    = 0x00004000,
+       WCN36XX_DBG_ANY         = 0xffffffff,
+};
+
+#define wcn36xx_err(fmt, arg...)                               \
+       printk(KERN_ERR pr_fmt("ERROR " fmt), ##arg);
+
+#define wcn36xx_warn(fmt, arg...)                              \
+       printk(KERN_WARNING pr_fmt("WARNING " fmt), ##arg)
+
+#define wcn36xx_info(fmt, arg...)              \
+       printk(KERN_INFO pr_fmt(fmt), ##arg)
+
+#define wcn36xx_dbg(mask, fmt, arg...) do {                    \
+       if (wcn36xx_dbg_mask & mask)                                    \
+               printk(KERN_DEBUG pr_fmt(fmt), ##arg);  \
+} while (0)
+
+#define wcn36xx_dbg_dump(mask, prefix_str, buf, len) do {      \
+       if (wcn36xx_dbg_mask & mask)                                    \
+               print_hex_dump(KERN_DEBUG, pr_fmt(prefix_str),  \
+                              DUMP_PREFIX_OFFSET, 32, 1,       \
+                              buf, len, false);                \
+} while (0)
+
+#define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value)
+#define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band)
+#define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq)
+#define WCN36XX_LISTEN_INTERVAL(__wcn) (__wcn->hw->conf.listen_interval)
+#define WCN36XX_FLAGS(__wcn) (__wcn->hw->flags)
+#define WCN36XX_MAX_POWER(__wcn) (__wcn->hw->conf.chandef.chan->max_power)
+
+static inline void buff_to_be(u32 *buf, size_t len)
+{
+       int i;
+       for (i = 0; i < len; i++)
+               buf[i] = cpu_to_be32(buf[i]);
+}
+
+struct nv_data {
+       int     is_valid;
+       u8      table;
+};
+
+/* Interface for platform control path
+ *
+ * @open: hook must be called when wcn36xx wants to open control channel.
+ * @tx: sends a buffer.
+ */
+struct wcn36xx_platform_ctrl_ops {
+       int (*open)(void *drv_priv, void *rsp_cb);
+       void (*close)(void);
+       int (*tx)(char *buf, size_t len);
+       int (*get_hw_mac)(u8 *addr);
+       int (*smsm_change_state)(u32 clear_mask, u32 set_mask);
+};
+
+/**
+ * struct wcn36xx_vif - holds VIF related fields
+ *
+ * @bss_index: bss_index is initially set to 0xFF. bss_index is received from
+ * HW after first config_bss call and must be used in delete_bss and
+ * enter/exit_bmps.
+ */
+struct wcn36xx_vif {
+       struct list_head list;
+       struct wcn36xx_sta *sta;
+       u8 dtim_period;
+       enum ani_ed_type encrypt_type;
+       bool is_joining;
+       struct wcn36xx_hal_mac_ssid ssid;
+
+       /* Power management */
+       enum wcn36xx_power_state pw_state;
+
+       u8 bss_index;
+       u8 ucast_dpu_signature;
+       /* Returned from WCN36XX_HAL_ADD_STA_SELF_RSP */
+       u8 self_sta_index;
+       u8 self_dpu_desc_index;
+};
+
+/**
+ * struct wcn36xx_sta - holds STA related fields
+ *
+ * @tid: traffic ID that is used during AMPDU and in TX BD.
+ * @sta_index: STA index is returned from HW after config_sta call and is
+ * used in both SMD channel and TX BD.
+ * @dpu_desc_index: DPU descriptor index is returned from HW after config_sta
+ * call and is used in TX BD.
+ * @bss_sta_index: STA index is returned from HW after config_bss call and is
+ * used in both SMD channel and TX BD. See table bellow when it is used.
+ * @bss_dpu_desc_index: DPU descriptor index is returned from HW after
+ * config_bss call and is used in TX BD.
+ * ______________________________________________
+ * |             |     STA     |       AP      |
+ * |______________|_____________|_______________|
+ * |    TX BD     |bss_sta_index|   sta_index   |
+ * |______________|_____________|_______________|
+ * |all SMD calls |bss_sta_index|   sta_index  |
+ * |______________|_____________|_______________|
+ * |smd_delete_sta|  sta_index  |   sta_index  |
+ * |______________|_____________|_______________|
+ */
+struct wcn36xx_sta {
+       struct wcn36xx_vif *vif;
+       u16 aid;
+       u16 tid;
+       u8 sta_index;
+       u8 dpu_desc_index;
+       u8 bss_sta_index;
+       u8 bss_dpu_desc_index;
+       bool is_data_encrypted;
+       /* Rates */
+       struct wcn36xx_hal_supported_rates supported_rates;
+};
+struct wcn36xx_dxe_ch;
+struct wcn36xx {
+       struct ieee80211_hw     *hw;
+       struct device           *dev;
+       struct list_head        vif_list;
+
+       u8                      fw_revision;
+       u8                      fw_version;
+       u8                      fw_minor;
+       u8                      fw_major;
+
+       /* extra byte for the NULL termination */
+       u8                      crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
+       u8                      wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1];
+
+       /* IRQs */
+       int                     tx_irq;
+       int                     rx_irq;
+       void __iomem            *mmio;
+
+       struct wcn36xx_platform_ctrl_ops *ctrl_ops;
+       /*
+        * smd_buf must be protected with smd_mutex to garantee
+        * that all messages are sent one after another
+        */
+       u8                      *hal_buf;
+       size_t                  hal_rsp_len;
+       struct mutex            hal_mutex;
+       struct completion       hal_rsp_compl;
+       struct workqueue_struct *hal_ind_wq;
+       struct work_struct      hal_ind_work;
+       struct mutex            hal_ind_mutex;
+       struct list_head        hal_ind_queue;
+
+       /* DXE channels */
+       struct wcn36xx_dxe_ch   dxe_tx_l_ch;    /* TX low */
+       struct wcn36xx_dxe_ch   dxe_tx_h_ch;    /* TX high */
+       struct wcn36xx_dxe_ch   dxe_rx_l_ch;    /* RX low */
+       struct wcn36xx_dxe_ch   dxe_rx_h_ch;    /* RX high */
+
+       /* For synchronization of DXE resources from BH, IRQ and WQ contexts */
+       spinlock_t      dxe_lock;
+       bool                    queues_stopped;
+
+       /* Memory pools */
+       struct wcn36xx_dxe_mem_pool mgmt_mem_pool;
+       struct wcn36xx_dxe_mem_pool data_mem_pool;
+
+       struct sk_buff          *tx_ack_skb;
+
+#ifdef CONFIG_WCN36XX_DEBUGFS
+       /* Debug file system entry */
+       struct wcn36xx_dfs_entry    dfs;
+#endif /* CONFIG_WCN36XX_DEBUGFS */
+
+};
+
+static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
+                                        u8 major,
+                                        u8 minor,
+                                        u8 version,
+                                        u8 revision)
+{
+       return (wcn->fw_major == major &&
+               wcn->fw_minor == minor &&
+               wcn->fw_version == version &&
+               wcn->fw_revision == revision);
+}
+void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
+
+#endif /* _WCN36XX_H_ */
index eb1dc7ad80fb367bbb6c56959a8758aa85225ac4..eeceab39cda22aee81e2fcbb86fc0c9520766a5f 100644 (file)
@@ -197,7 +197,6 @@ static void wil_pcie_remove(struct pci_dev *pdev)
        pci_iounmap(pdev, wil->csr);
        pci_release_region(pdev, 0);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(wil6210_pcie_ids) = {
index 64f4a2bc8ddedf6c131d8b8d70408acb3ba17d9b..091c905871ccd100baad84d3c35ab9172709d901 100644 (file)
@@ -34,6 +34,7 @@
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 #include "sdio_host.h"
+#include "sdio_chip.h"
 #include "dhd_dbg.h"
 #include "dhd_bus.h"
 
 
 #define DMA_ALIGN_MASK 0x03
 
-#define SDIO_DEVICE_ID_BROADCOM_43143  43143
-#define SDIO_DEVICE_ID_BROADCOM_43241  0x4324
-#define SDIO_DEVICE_ID_BROADCOM_4329   0x4329
-#define SDIO_DEVICE_ID_BROADCOM_4330   0x4330
-#define SDIO_DEVICE_ID_BROADCOM_4334   0x4334
-#define SDIO_DEVICE_ID_BROADCOM_4335   0x4335
-
 #define SDIO_FUNC1_BLOCKSIZE           64
 #define SDIO_FUNC2_BLOCKSIZE           512
 
@@ -58,7 +52,8 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
-       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4335)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
+                    SDIO_DEVICE_ID_BROADCOM_4335_4339)},
        { /* end: all zeroes */ },
 };
 MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
@@ -468,7 +463,7 @@ static int brcmf_sdio_pd_probe(struct platform_device *pdev)
 
        brcmf_dbg(SDIO, "Enter\n");
 
-       brcmfmac_sdio_pdata = pdev->dev.platform_data;
+       brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
 
        if (brcmfmac_sdio_pdata->power_on)
                brcmfmac_sdio_pdata->power_on();
index 2eb9e642c9bf80d604bea8d201d86a0bb5c1a524..4de9aac6666dd25cacdcde231a49de06d6e794aa 100644 (file)
@@ -97,8 +97,6 @@
 #define        WLC_PHY_TYPE_LCN        8
 #define        WLC_PHY_TYPE_NULL       0xf
 
-#define BRCMF_EVENTING_MASK_LEN        16
-
 #define TOE_TX_CSUM_OL         0x00000001
 #define TOE_RX_CSUM_OL         0x00000002
 
index f7c1985844e44c3ed0464a4e21588d538f693959..200ee9b485bf0e0f31ba2e6b7cee81f095cb97bc 100644 (file)
@@ -136,7 +136,7 @@ extern bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
                         struct sk_buff *pkt, int prec);
 
 /* Receive frame for delivery to OS.  Callee disposes of rxp. */
-extern void brcmf_rx_frames(struct device *dev, struct sk_buff_head *rxlist);
+extern void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
 extern int brcmf_attach(uint bus_hdrlen, struct device *dev);
index e067aec1fbf113220d1a1054ca3dfceb027448a2..42bf19a2eeee3beec051d6184066c34eef2a2dec 100644 (file)
@@ -509,9 +509,8 @@ netif_rx:
        }
 }
 
-void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
 {
-       struct sk_buff *skb, *pnext;
        struct brcmf_if *ifp;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
@@ -519,29 +518,24 @@ void brcmf_rx_frames(struct device *dev, struct sk_buff_head *skb_list)
        u8 ifidx;
        int ret;
 
-       brcmf_dbg(DATA, "Enter: %s: count=%u\n", dev_name(dev),
-                 skb_queue_len(skb_list));
+       brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
 
-       skb_queue_walk_safe(skb_list, skb, pnext) {
-               skb_unlink(skb, skb_list);
-
-               /* process and remove protocol-specific header */
-               ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
-               ifp = drvr->iflist[ifidx];
-
-               if (ret || !ifp || !ifp->ndev) {
-                       if ((ret != -ENODATA) && ifp)
-                               ifp->stats.rx_errors++;
-                       brcmu_pkt_buf_free_skb(skb);
-                       continue;
-               }
+       /* process and remove protocol-specific header */
+       ret = brcmf_proto_hdrpull(drvr, true, &ifidx, skb);
+       ifp = drvr->iflist[ifidx];
 
-               rd = (struct brcmf_skb_reorder_data *)skb->cb;
-               if (rd->reorder)
-                       brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
-               else
-                       brcmf_netif_rx(ifp, skb);
+       if (ret || !ifp || !ifp->ndev) {
+               if ((ret != -ENODATA) && ifp)
+                       ifp->stats.rx_errors++;
+               brcmu_pkt_buf_free_skb(skb);
+               return;
        }
+
+       rd = (struct brcmf_skb_reorder_data *)skb->cb;
+       if (rd->reorder)
+               brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
+       else
+               brcmf_netif_rx(ifp, skb);
 }
 
 void brcmf_txfinalize(struct brcmf_pub *drvr, struct sk_buff *txp,
index 1aa75d5951b82720f21f0ff486e701252837333b..67f05db4b9b8e11918771b087925c12d184821fd 100644 (file)
@@ -275,11 +275,6 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-#define BRCMF_SDIO_FW_NAME     "brcm/brcmfmac-sdio.bin"
-#define BRCMF_SDIO_NV_NAME     "brcm/brcmfmac-sdio.txt"
-MODULE_FIRMWARE(BRCMF_SDIO_FW_NAME);
-MODULE_FIRMWARE(BRCMF_SDIO_NV_NAME);
-
 #define BRCMF_IDLE_IMMEDIATE   (-1)    /* Enter idle immediately */
 #define BRCMF_IDLE_ACTIVE      0       /* Do not request any SD clock change
                                         * when idle
@@ -454,9 +449,6 @@ struct brcmf_sdio {
        struct work_struct datawork;
        atomic_t dpc_tskcnt;
 
-       const struct firmware *firmware;
-       u32 fw_ptr;
-
        bool txoff;             /* Transmit flow-controlled */
        struct brcmf_sdio_count sdcnt;
        bool sr_enabled; /* SaveRestore enabled */
@@ -493,6 +485,100 @@ enum brcmf_sdio_frmtype {
        BRCMF_SDIO_FT_SUB,
 };
 
+#define BCM43143_FIRMWARE_NAME         "brcm/brcmfmac43143-sdio.bin"
+#define BCM43143_NVRAM_NAME            "brcm/brcmfmac43143-sdio.txt"
+#define BCM43241B0_FIRMWARE_NAME       "brcm/brcmfmac43241b0-sdio.bin"
+#define BCM43241B0_NVRAM_NAME          "brcm/brcmfmac43241b0-sdio.txt"
+#define BCM43241B4_FIRMWARE_NAME       "brcm/brcmfmac43241b4-sdio.bin"
+#define BCM43241B4_NVRAM_NAME          "brcm/brcmfmac43241b4-sdio.txt"
+#define BCM4329_FIRMWARE_NAME          "brcm/brcmfmac4329-sdio.bin"
+#define BCM4329_NVRAM_NAME             "brcm/brcmfmac4329-sdio.txt"
+#define BCM4330_FIRMWARE_NAME          "brcm/brcmfmac4330-sdio.bin"
+#define BCM4330_NVRAM_NAME             "brcm/brcmfmac4330-sdio.txt"
+#define BCM4334_FIRMWARE_NAME          "brcm/brcmfmac4334-sdio.bin"
+#define BCM4334_NVRAM_NAME             "brcm/brcmfmac4334-sdio.txt"
+#define BCM4335_FIRMWARE_NAME          "brcm/brcmfmac4335-sdio.bin"
+#define BCM4335_NVRAM_NAME             "brcm/brcmfmac4335-sdio.txt"
+
+MODULE_FIRMWARE(BCM43143_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43143_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43241B0_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43241B0_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43241B4_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43241B4_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4329_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4329_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4330_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
+MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
+
+struct brcmf_firmware_names {
+       u32 chipid;
+       u32 revmsk;
+       const char *bin;
+       const char *nv;
+};
+
+enum brcmf_firmware_type {
+       BRCMF_FIRMWARE_BIN,
+       BRCMF_FIRMWARE_NVRAM
+};
+
+#define BRCMF_FIRMWARE_NVRAM(name) \
+       name ## _FIRMWARE_NAME, name ## _NVRAM_NAME
+
+static const struct brcmf_firmware_names brcmf_fwname_data[] = {
+       { BCM43143_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43143) },
+       { BCM43241_CHIP_ID, 0x0000001F, BRCMF_FIRMWARE_NVRAM(BCM43241B0) },
+       { BCM43241_CHIP_ID, 0xFFFFFFE0, BRCMF_FIRMWARE_NVRAM(BCM43241B4) },
+       { BCM4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
+       { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
+       { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
+       { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }
+};
+
+
+static const struct firmware *brcmf_sdbrcm_get_fw(struct brcmf_sdio *bus,
+                                                 enum brcmf_firmware_type type)
+{
+       const struct firmware *fw;
+       const char *name;
+       int err, i;
+
+       for (i = 0; i < ARRAY_SIZE(brcmf_fwname_data); i++) {
+               if (brcmf_fwname_data[i].chipid == bus->ci->chip &&
+                   brcmf_fwname_data[i].revmsk & BIT(bus->ci->chiprev)) {
+                       switch (type) {
+                       case BRCMF_FIRMWARE_BIN:
+                               name = brcmf_fwname_data[i].bin;
+                               break;
+                       case BRCMF_FIRMWARE_NVRAM:
+                               name = brcmf_fwname_data[i].nv;
+                               break;
+                       default:
+                               brcmf_err("invalid firmware type (%d)\n", type);
+                               return NULL;
+                       }
+                       goto found;
+               }
+       }
+       brcmf_err("Unknown chipid %d [%d]\n",
+                 bus->ci->chip, bus->ci->chiprev);
+       return NULL;
+
+found:
+       err = request_firmware(&fw, name, &bus->sdiodev->func[2]->dev);
+       if ((err) || (!fw)) {
+               brcmf_err("fail to request firmware %s (%d)\n", name, err);
+               return NULL;
+       }
+
+       return fw;
+}
+
 static void pkt_align(struct sk_buff *p, int len, int align)
 {
        uint datalign;
@@ -1406,13 +1492,12 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                           bus->glom.qlen, pfirst, pfirst->data,
                                           pfirst->len, pfirst->next,
                                           pfirst->prev);
+                       skb_unlink(pfirst, &bus->glom);
+                       brcmf_rx_frame(bus->sdiodev->dev, pfirst);
+                       bus->sdcnt.rxglompkts++;
                }
-               /* sent any remaining packets up */
-               if (bus->glom.qlen)
-                       brcmf_rx_frames(bus->sdiodev->dev, &bus->glom);
 
                bus->sdcnt.rxglomframes++;
-               bus->sdcnt.rxglompkts += bus->glom.qlen;
        }
        return num;
 }
@@ -1557,7 +1642,6 @@ static void brcmf_pad(struct brcmf_sdio *bus, u16 *pad, u16 *rdlen)
 static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 {
        struct sk_buff *pkt;            /* Packet for event or data frames */
-       struct sk_buff_head pktlist;    /* needed for bus interface */
        u16 pad;                /* Number of pad bytes to read */
        uint rxleft = 0;        /* Remaining number of frames allowed */
        int ret;                /* Return code from calls */
@@ -1759,9 +1843,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        continue;
                }
 
-               skb_queue_head_init(&pktlist);
-               skb_queue_tail(&pktlist, pkt);
-               brcmf_rx_frames(bus->sdiodev->dev, &pktlist);
+               brcmf_rx_frame(bus->sdiodev->dev, pkt);
        }
 
        rxcount = maxframes - rxleft;
@@ -1786,10 +1868,15 @@ brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
        return;
 }
 
+/**
+ * struct brcmf_skbuff_cb reserves first two bytes in sk_buff::cb for
+ * bus layer usage.
+ */
 /* flag marking a dummy skb added for DMA alignment requirement */
-#define DUMMY_SKB_FLAG         0x10000
+#define ALIGN_SKB_FLAG         0x8000
 /* bit mask of data length chopped from the previous packet */
-#define DUMMY_SKB_CHOP_LEN_MASK        0xffff
+#define ALIGN_SKB_CHOP_LEN_MASK        0x7fff
+
 /**
  * brcmf_sdio_txpkt_prep - packet preparation for transmit
  * @bus: brcmf_sdio structure pointer
@@ -1854,7 +1941,7 @@ brcmf_sdio_txpkt_prep(struct brcmf_sdio *bus, struct sk_buff_head *pktq,
                memcpy(pkt_new->data,
                       pkt_next->data + pkt_next->len - tail_chop,
                       tail_chop);
-               *(u32 *)(pkt_new->cb) = DUMMY_SKB_FLAG + tail_chop;
+               *(u32 *)(pkt_new->cb) = ALIGN_SKB_FLAG + tail_chop;
                skb_trim(pkt_next, pkt_next->len - tail_chop);
                __skb_queue_after(pktq, pkt_next, pkt_new);
        } else {
@@ -1908,8 +1995,8 @@ brcmf_sdio_txpkt_postp(struct brcmf_sdio *bus, struct sk_buff_head *pktq)
 
        skb_queue_walk_safe(pktq, pkt_next, tmp) {
                dummy_flags = *(u32 *)(pkt_next->cb);
-               if (dummy_flags & DUMMY_SKB_FLAG) {
-                       chop_len = dummy_flags & DUMMY_SKB_CHOP_LEN_MASK;
+               if (dummy_flags & ALIGN_SKB_FLAG) {
+                       chop_len = dummy_flags & ALIGN_SKB_CHOP_LEN_MASK;
                        if (chop_len) {
                                pkt_prev = pkt_next->prev;
                                memcpy(pkt_prev->data + pkt_prev->len,
@@ -3037,69 +3124,43 @@ static bool brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
        return true;
 }
 
-static int brcmf_sdbrcm_get_image(char *buf, int len, struct brcmf_sdio *bus)
-{
-       if (bus->firmware->size < bus->fw_ptr + len)
-               len = bus->firmware->size - bus->fw_ptr;
-
-       memcpy(buf, &bus->firmware->data[bus->fw_ptr], len);
-       bus->fw_ptr += len;
-       return len;
-}
-
 static int brcmf_sdbrcm_download_code_file(struct brcmf_sdio *bus)
 {
+       const struct firmware *fw;
+       int err;
        int offset;
-       uint len;
-       u8 *memblock = NULL, *memptr;
-       int ret;
-       u8 idx;
-
-       brcmf_dbg(INFO, "Enter\n");
-
-       ret = request_firmware(&bus->firmware, BRCMF_SDIO_FW_NAME,
-                              &bus->sdiodev->func[2]->dev);
-       if (ret) {
-               brcmf_err("Fail to request firmware %d\n", ret);
-               return ret;
-       }
-       bus->fw_ptr = 0;
-
-       memptr = memblock = kmalloc(MEMBLOCK + BRCMF_SDALIGN, GFP_ATOMIC);
-       if (memblock == NULL) {
-               ret = -ENOMEM;
-               goto err;
-       }
-       if ((u32)(unsigned long)memblock % BRCMF_SDALIGN)
-               memptr += (BRCMF_SDALIGN -
-                          ((u32)(unsigned long)memblock % BRCMF_SDALIGN));
-
-       offset = bus->ci->rambase;
-
-       /* Download image */
-       len = brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus);
-       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_ARM_CR4);
-       if (BRCMF_MAX_CORENUM != idx)
-               memcpy(&bus->ci->rst_vec, memptr, sizeof(bus->ci->rst_vec));
-       while (len) {
-               ret = brcmf_sdio_ramrw(bus->sdiodev, true, offset, memptr, len);
-               if (ret) {
+       int address;
+       int len;
+
+       fw = brcmf_sdbrcm_get_fw(bus, BRCMF_FIRMWARE_BIN);
+       if (fw == NULL)
+               return -ENOENT;
+
+       if (brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_ARM_CR4) !=
+           BRCMF_MAX_CORENUM)
+               memcpy(&bus->ci->rst_vec, fw->data, sizeof(bus->ci->rst_vec));
+
+       err = 0;
+       offset = 0;
+       address = bus->ci->rambase;
+       while (offset < fw->size) {
+               len = ((offset + MEMBLOCK) < fw->size) ? MEMBLOCK :
+                     fw->size - offset;
+               err = brcmf_sdio_ramrw(bus->sdiodev, true, address,
+                                      (u8 *)&fw->data[offset], len);
+               if (err) {
                        brcmf_err("error %d on writing %d membytes at 0x%08x\n",
-                                 ret, MEMBLOCK, offset);
-                       goto err;
+                                 err, len, address);
+                       goto failure;
                }
-
-               offset += MEMBLOCK;
-               len = brcmf_sdbrcm_get_image((char *)memptr, MEMBLOCK, bus);
+               offset += len;
+               address += len;
        }
 
-err:
-       kfree(memblock);
+failure:
+       release_firmware(fw);
 
-       release_firmware(bus->firmware);
-       bus->fw_ptr = 0;
-
-       return ret;
+       return err;
 }
 
 /*
@@ -3111,7 +3172,8 @@ err:
  * by two NULs.
 */
 
-static int brcmf_process_nvram_vars(struct brcmf_sdio *bus)
+static int brcmf_process_nvram_vars(struct brcmf_sdio *bus,
+                                   const struct firmware *nv)
 {
        char *varbuf;
        char *dp;
@@ -3120,12 +3182,12 @@ static int brcmf_process_nvram_vars(struct brcmf_sdio *bus)
        int ret = 0;
        uint buf_len, n, len;
 
-       len = bus->firmware->size;
+       len = nv->size;
        varbuf = vmalloc(len);
        if (!varbuf)
                return -ENOMEM;
 
-       memcpy(varbuf, bus->firmware->data, len);
+       memcpy(varbuf, nv->data, len);
        dp = varbuf;
 
        findNewline = false;
@@ -3177,18 +3239,16 @@ err:
 
 static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus)
 {
+       const struct firmware *nv;
        int ret;
 
-       ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME,
-                              &bus->sdiodev->func[2]->dev);
-       if (ret) {
-               brcmf_err("Fail to request nvram %d\n", ret);
-               return ret;
-       }
+       nv = brcmf_sdbrcm_get_fw(bus, BRCMF_FIRMWARE_NVRAM);
+       if (nv == NULL)
+               return -ENOENT;
 
-       ret = brcmf_process_nvram_vars(bus);
+       ret = brcmf_process_nvram_vars(bus, nv);
 
-       release_firmware(bus->firmware);
+       release_firmware(nv);
 
        return ret;
 }
index e679214b3c98be52662e9f7f09d1e90eb0b62ec7..14bc24dc5baeb1f8272b4da0660d893c4bfc9b48 100644 (file)
@@ -102,7 +102,8 @@ struct brcmf_event;
        BRCMF_ENUM_DEF(DCS_REQUEST, 73) \
        BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \
        BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \
-       BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127)
+       BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \
+       BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128)
 
 #define BRCMF_ENUM_DEF(id, val) \
        BRCMF_E_##id = (val),
@@ -114,6 +115,8 @@ enum brcmf_fweh_event_code {
 };
 #undef BRCMF_ENUM_DEF
 
+#define BRCMF_EVENTING_MASK_LEN                DIV_ROUND_UP(BRCMF_E_LAST, 8)
+
 /* flags field values in struct brcmf_event_msg */
 #define BRCMF_EVENT_MSG_LINK           0x01
 #define BRCMF_EVENT_MSG_FLUSHTXQ       0x02
index 82f9140f3d35481766b317f4a31204fa7b4da6b7..d0cd0bf95c5af4393719a981d008049cde67756d 100644 (file)
@@ -168,6 +168,7 @@ enum brcmf_fws_skb_state {
 /**
  * struct brcmf_skbuff_cb - control buffer associated with skbuff.
  *
+ * @bus_flags: 2 bytes reserved for bus specific parameters
  * @if_flags: holds interface index and packet related flags.
  * @htod: host to device packet identifier (used in PKTTAG tlv).
  * @state: transmit state of the packet.
@@ -177,6 +178,7 @@ enum brcmf_fws_skb_state {
  * provides 48 bytes of storage so this structure should not exceed that.
  */
 struct brcmf_skbuff_cb {
+       u16 bus_flags;
        u16 if_flags;
        u32 htod;
        enum brcmf_fws_skb_state state;
index ca72177388b92726368a6764f86395db6f736b05..2096a14ef1fba5fcaf156140a64b2f52f4b67757 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/netdevice.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/sdio_func.h>
 #include <linux/ssb/ssb_regs.h>
 #include <linux/bcma/bcma.h>
 
@@ -136,6 +137,8 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
        u8 idx;
 
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+       if (idx == BRCMF_MAX_CORENUM)
+               return false;
 
        regdata = brcmf_sdio_regrl(sdiodev,
                                   CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
@@ -154,6 +157,8 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
        bool ret;
 
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+       if (idx == BRCMF_MAX_CORENUM)
+               return false;
 
        regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
                                   NULL);
@@ -261,6 +266,8 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
        u32 regdata;
 
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+       if (idx == BRCMF_MAX_CORENUM)
+               return;
 
        /* if core is already in reset, just return */
        regdata = brcmf_sdio_regrl(sdiodev,
@@ -304,6 +311,8 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
        u8 idx;
 
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+       if (idx == BRCMF_MAX_CORENUM)
+               return;
 
        /*
         * Must do the disable sequence first to work for
@@ -368,6 +377,8 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
        u32 regdata;
 
        idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+       if (idx == BRCMF_MAX_CORENUM)
+               return;
 
        /* must disable first to work for arbitrary current core state */
        brcmf_sdio_ai_coredisable(sdiodev, ci, coreid, core_bits);
@@ -444,6 +455,9 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
                                   NULL);
        ci->chip = regdata & CID_ID_MASK;
        ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+       if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
+           ci->chiprev >= 2)
+               ci->chip = BCM4339_CHIP_ID;
        ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
 
        brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
@@ -541,6 +555,20 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
                ci->ramsize = 0xc0000;
                ci->rambase = 0x180000;
                break;
+       case BCM4339_CHIP_ID:
+               ci->c_inf[0].wrapbase = 0x18100000;
+               ci->c_inf[0].cib = 0x2e084411;
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = 0x18005000;
+               ci->c_inf[1].wrapbase = 0x18105000;
+               ci->c_inf[1].cib = 0x15004211;
+               ci->c_inf[2].id = BCMA_CORE_ARM_CR4;
+               ci->c_inf[2].base = 0x18002000;
+               ci->c_inf[2].wrapbase = 0x18102000;
+               ci->c_inf[2].cib = 0x04084411;
+               ci->ramsize = 0xc0000;
+               ci->rambase = 0x180000;
+               break;
        default:
                brcmf_err("chipid 0x%x is not supported\n", ci->chip);
                return -ENODEV;
index 83c041f1bf4ad154afb0822d734818a7561f9ad6..076b83c7c8964628e778b1247a2c4b7965eb8d46 100644 (file)
 
 #define BRCMF_MAX_CORENUM      6
 
+/* SDIO device ID */
+#define SDIO_DEVICE_ID_BROADCOM_43143          43143
+#define SDIO_DEVICE_ID_BROADCOM_43241          0x4324
+#define SDIO_DEVICE_ID_BROADCOM_4329           0x4329
+#define SDIO_DEVICE_ID_BROADCOM_4330           0x4330
+#define SDIO_DEVICE_ID_BROADCOM_4334           0x4334
+#define SDIO_DEVICE_ID_BROADCOM_4335_4339      0x4335
+
 struct chip_core_info {
        u16 id;
        u16 rev;
index 39e01a7c8556f2ce022bd5b8c545c2e2a615af5d..bf6758d95600bba97bbb43f273d4b2c571fa590f 100644 (file)
@@ -435,7 +435,6 @@ static void brcmf_usb_rx_complete(struct urb *urb)
        struct brcmf_usbreq  *req = (struct brcmf_usbreq *)urb->context;
        struct brcmf_usbdev_info *devinfo = req->devinfo;
        struct sk_buff *skb;
-       struct sk_buff_head skbq;
 
        brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
        brcmf_usb_del_fromq(devinfo, req);
@@ -450,10 +449,8 @@ static void brcmf_usb_rx_complete(struct urb *urb)
        }
 
        if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
-               skb_queue_head_init(&skbq);
-               skb_queue_tail(&skbq, skb);
                skb_put(skb, urb->actual_length);
-               brcmf_rx_frames(devinfo->dev, &skbq);
+               brcmf_rx_frame(devinfo->dev, skb);
                brcmf_usb_rx_refill(devinfo, req);
        } else {
                brcmu_pkt_buf_free_skb(skb);
index 4608e0eb14939d12a73a4af5d3c2408e27bc877c..df6229ed52c8d23289d8ec41eff2e32be24c4146 100644 (file)
@@ -5695,7 +5695,7 @@ static bool brcms_c_chipmatch_pci(struct bcma_device *core)
                return true;
        if ((device == BCM43224_D11N_ID) || (device == BCM43225_D11N2G_ID))
                return true;
-       if (device == BCM4313_D11N2G_ID)
+       if (device == BCM4313_D11N2G_ID || device == BCM4313_CHIP_ID)
                return true;
        if ((device == BCM43236_D11N_ID) || (device == BCM43236_D11N2G_ID))
                return true;
index c1fe245bb07ee18aba557892b274435a3ad40fcb..84113ea16f8434fcd0ee4383aeea18c0dfe9c480 100644 (file)
@@ -41,5 +41,6 @@
 #define BCM4331_CHIP_ID                0x4331
 #define BCM4334_CHIP_ID                0x4334
 #define BCM4335_CHIP_ID                0x4335
+#define BCM4339_CHIP_ID                0x4339
 
 #endif                         /* _BRCM_HW_IDS_H_ */
index f5e6b489ed3277e29cb6b2f4fba2f33bd2abf8fd..e310752f0e33014ade59028b754b2fdd38076cb6 100644 (file)
@@ -375,7 +375,7 @@ static struct hwbus_ops cw1200_spi_hwbus_ops = {
 static int cw1200_spi_probe(struct spi_device *func)
 {
        const struct cw1200_platform_data_spi *plat_data =
-               func->dev.platform_data;
+               dev_get_platdata(&func->dev);
        struct hwbus_priv *self;
        int status;
 
@@ -453,7 +453,7 @@ static int cw1200_spi_disconnect(struct spi_device *func)
                }
                kfree(self);
        }
-       cw1200_spi_off(func->dev.platform_data);
+       cw1200_spi_off(dev_get_platdata(&func->dev));
 
        return 0;
 }
index 6b823a1ab7892fd9c81be07ce56bc45e75a6b8f1..f394af777cf5769057796ce415baf5fe390c85d6 100644 (file)
@@ -11885,7 +11885,6 @@ static int ipw_pci_probe(struct pci_dev *pdev,
        pci_release_regions(pdev);
       out_pci_disable_device:
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
       out_free_libipw:
        free_libipw(priv->net_dev, 0);
       out:
@@ -11966,7 +11965,6 @@ static void ipw_pci_remove(struct pci_dev *pdev)
        iounmap(priv->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
        /* wiphy_unregister needs to be here, before free_libipw */
        wiphy_unregister(priv->ieee->wdev.wiphy);
        kfree(priv->ieee->a_band.channels);
index 9581d07a4242bbdabef6174e60560d42aa4e6b09..dea3b50d68b9c5bcfc1c95794262992bc59d917d 100644 (file)
@@ -3811,7 +3811,6 @@ out_iounmap:
 out_pci_release_regions:
        pci_release_regions(pdev);
 out_pci_disable_device:
-       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 out_ieee80211_free_hw:
        ieee80211_free_hw(il->hw);
@@ -3888,7 +3887,6 @@ il3945_pci_remove(struct pci_dev *pdev)
        iounmap(il->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
 
        il_free_channel_map(il);
        il_free_geos(il);
index 5ab50a5b48b1511708bd67783ccb7518a9a81eb1..3982ab76f3755fdbda4f0cab89aa6cca537a8f43 100644 (file)
@@ -6706,7 +6706,6 @@ out_free_eeprom:
 out_iounmap:
        iounmap(il->hw_base);
 out_pci_release_regions:
-       pci_set_drvdata(pdev, NULL);
        pci_release_regions(pdev);
 out_pci_disable_device:
        pci_disable_device(pdev);
@@ -6787,7 +6786,6 @@ il4965_pci_remove(struct pci_dev *pdev)
        iounmap(il->hw_base);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
 
        il4965_uninit_drv(il);
 
index bad95d28d50da52158ff102de3fc9855e46a662b..c3f904d422b08b1074345fcba99a31390f663945 100644 (file)
@@ -1401,6 +1401,10 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        spin_lock_init(&trans_pcie->reg_lock);
        init_waitqueue_head(&trans_pcie->ucode_write_waitq);
 
+       err = pci_enable_device(pdev);
+       if (err)
+               goto out_no_pci;
+
        if (!cfg->base_params->pcie_l1_allowed) {
                /*
                 * W/A - seems to solve weird behavior. We need to remove this
@@ -1412,10 +1416,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                                       PCIE_LINK_STATE_CLKPM);
        }
 
-       err = pci_enable_device(pdev);
-       if (err)
-               goto out_no_pci;
-
        pci_set_master(pdev);
 
        err = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
index 4bb6574f40737f462f3b7f4ad3d9fea3d705b415..5d39ec880d84350bd270b0115b87574582fa0fed 100644 (file)
@@ -1128,7 +1128,7 @@ static int if_spi_probe(struct spi_device *spi)
 {
        struct if_spi_card *card;
        struct lbs_private *priv = NULL;
-       struct libertas_spi_platform_data *pdata = spi->dev.platform_data;
+       struct libertas_spi_platform_data *pdata = dev_get_platdata(&spi->dev);
        int err = 0;
 
        lbs_deb_enter(LBS_DEB_SPI);
index 2d761477d15e5761ed968200484a6fd55d066f39..fb3fa18390b8fb4bb31fdcdb45e7a54511f3433f 100644 (file)
@@ -1048,7 +1048,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
        struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
        unsigned long cmd_flags;
        unsigned long scan_pending_q_flags;
-       uint16_t cancel_scan_cmd = false;
+       bool cancel_scan_cmd = false;
 
        if ((adapter->curr_cmd) &&
            (adapter->curr_cmd->wait_q_enabled)) {
index 9d7c0e6c4fc7419facd68a3c61f251fbedb86143..717fbe2e0e5aea2b5d86482da86cce7b3ccc393d 100644 (file)
@@ -621,7 +621,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
        int ret = 0;
        struct ieee_types_assoc_rsp *assoc_rsp;
        struct mwifiex_bssdescriptor *bss_desc;
-       u8 enable_data = true;
+       bool enable_data = true;
        u16 cap_info, status_code;
 
        assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
index fd778337deeec4e58b1bddb4d08668aaf51890d9..408f307694aab03c8e471a9704a4ab157406b634 100644 (file)
@@ -880,7 +880,9 @@ mwifiex_add_card(void *card, struct semaphore *sem,
        adapter->cmd_wait_q.status = 0;
        adapter->scan_wait_q_woken = false;
 
-       adapter->workqueue = create_workqueue("MWIFIEX_WORK_QUEUE");
+       adapter->workqueue =
+               alloc_workqueue("MWIFIEX_WORK_QUEUE",
+                               WQ_HIGHPRI | WQ_MEM_RECLAIM | WQ_UNBOUND, 1);
        if (!adapter->workqueue)
                goto err_kmalloc;
 
index 52da8ee7599a041d7922180122c1744d19fe743e..33fa9432b241b353c3ae381ab57c48d5d71f763b 100644 (file)
@@ -93,7 +93,7 @@ static int mwifiex_pcie_suspend(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
 
        if (pdev) {
-               card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+               card = pci_get_drvdata(pdev);
                if (!card || !card->adapter) {
                        pr_err("Card or adapter structure is not valid\n");
                        return 0;
@@ -128,7 +128,7 @@ static int mwifiex_pcie_resume(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
 
        if (pdev) {
-               card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+               card = pci_get_drvdata(pdev);
                if (!card || !card->adapter) {
                        pr_err("Card or adapter structure is not valid\n");
                        return 0;
@@ -2037,7 +2037,7 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
                goto exit;
        }
 
-       card = (struct pcie_service_card *) pci_get_drvdata(pdev);
+       card = pci_get_drvdata(pdev);
        if (!card || !card->adapter) {
                pr_debug("info: %s: card=%p adapter=%p\n", __func__, card,
                         card ? card->adapter : NULL);
index c0268b5977480b384f04f452e3278a9443c93e85..7d66018a2e33060d1bdc1a96b970fd61f6480e4a 100644 (file)
@@ -327,7 +327,7 @@ mwifiex_cmd_802_11_hs_cfg(struct mwifiex_private *priv,
 {
        struct mwifiex_adapter *adapter = priv->adapter;
        struct host_cmd_ds_802_11_hs_cfg_enh *hs_cfg = &cmd->params.opt_hs_cfg;
-       u16 hs_activate = false;
+       bool hs_activate = false;
 
        if (!hscfg_param)
                /* New Activate command */
index 2e8f9cdea54d719cf0f25b4b29d816eb0709ff7a..8f8fea015cb44f4bf926d94f5f78286dd31f7ecc 100644 (file)
@@ -708,7 +708,7 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,
 {
        u8 *curr = (u8 *) &resp->params.get_wmm_status;
        uint16_t resp_len = le16_to_cpu(resp->size), tlv_len;
-       int valid = true;
+       bool valid = true;
 
        struct mwifiex_ie_types_data *tlv_hdr;
        struct mwifiex_ie_types_wmm_queue_status *tlv_wmm_qstatus;
index a3707fd4ef623e5968afc85e5d265cb49024d764..b953ad621e0b90ef23e9fbe009bc0c4cd5f66876 100644 (file)
@@ -6093,7 +6093,6 @@ err_iounmap:
        if (priv->sram != NULL)
                pci_iounmap(pdev, priv->sram);
 
-       pci_set_drvdata(pdev, NULL);
        ieee80211_free_hw(hw);
 
 err_free_reg:
@@ -6147,7 +6146,6 @@ static void mwl8k_remove(struct pci_dev *pdev)
 unmap:
        pci_iounmap(pdev, priv->regs);
        pci_iounmap(pdev, priv->sram);
-       pci_set_drvdata(pdev, NULL);
        ieee80211_free_hw(hw);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
index d73fdf6185a2c7495891544ffe693ed140432f54..ffb2469eb6794c16453022e2b4a0a17a239077d3 100644 (file)
@@ -234,7 +234,6 @@ static int orinoco_nortel_init_one(struct pci_dev *pdev,
        free_irq(pdev->irq, priv);
 
  fail_irq:
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
 
  fail_alloc:
@@ -265,7 +264,6 @@ static void orinoco_nortel_remove_one(struct pci_dev *pdev)
 
        orinoco_if_del(priv);
        free_irq(pdev->irq, priv);
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_iounmap(pdev, card->attr_io);
index 677bf14eca844a1dd7c8cc2dca0724e9c5a5b505..5ae1191d2532545af84df76970140902906bb373 100644 (file)
@@ -184,7 +184,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
        free_irq(pdev->irq, priv);
 
  fail_irq:
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
 
  fail_alloc:
@@ -205,7 +204,6 @@ static void orinoco_pci_remove_one(struct pci_dev *pdev)
 
        orinoco_if_del(priv);
        free_irq(pdev->irq, priv);
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_release_regions(pdev);
index 2559dbd6184b2421b95a2d73630e14a887a9525c..bbd36d1676ff16aff0ff04b70a4e4a761e2ba9ba 100644 (file)
@@ -273,7 +273,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
        free_irq(pdev->irq, priv);
 
  fail_irq:
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
 
  fail_alloc:
@@ -301,7 +300,6 @@ static void orinoco_plx_remove_one(struct pci_dev *pdev)
 
        orinoco_if_del(priv);
        free_irq(pdev->irq, priv);
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_iounmap(pdev, card->attr_io);
index 42afeeea2c405c2403f0075f1aeabacd7af57767..04b08de5fd5db33cc73b89fefe8d2f9cea2adb69 100644 (file)
@@ -170,7 +170,6 @@ static int orinoco_tmd_init_one(struct pci_dev *pdev,
        free_irq(pdev->irq, priv);
 
  fail_irq:
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
 
  fail_alloc:
@@ -195,7 +194,6 @@ static void orinoco_tmd_remove_one(struct pci_dev *pdev)
 
        orinoco_if_del(priv);
        free_irq(pdev->irq, priv);
-       pci_set_drvdata(pdev, NULL);
        free_orinocodev(priv);
        pci_iounmap(pdev, priv->hw.iobase);
        pci_iounmap(pdev, card->bridge_io);
index 15ea36b51a668c6ae50543d0c5304a2bd0c12c45..cdafb8c73e82a74b8f8c0c54fbf7284a37495bd1 100644 (file)
@@ -41,7 +41,7 @@ config P54_PCI
 
 config P54_SPI
        tristate "Prism54 SPI (stlc45xx) support"
-       depends on P54_COMMON && SPI_MASTER && GENERIC_HARDIRQS
+       depends on P54_COMMON && SPI_MASTER
        ---help---
          This driver is for stlc4550 or stlc4560 based wireless chips
          such as Nokia's N800/N810 Portable Internet Tablet.
index 57e3af8ebb4b39622450d1fbee0742b39ab5a0a3..f9a07b0d83acd2f40df4755880fa1551e6276091 100644 (file)
@@ -631,7 +631,6 @@ static int p54p_probe(struct pci_dev *pdev,
        iounmap(priv->map);
 
  err_free_dev:
-       pci_set_drvdata(pdev, NULL);
        p54_free_common(dev);
 
  err_free_reg:
index 7fc46f26cf2be3085f08c56673931a44d538d098..de15171e2cd896f8dfd78c6d5e00966e2161ec12 100644 (file)
@@ -636,7 +636,7 @@ static int p54spi_probe(struct spi_device *spi)
        gpio_direction_input(p54spi_gpio_irq);
 
        ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
-                         p54spi_interrupt, IRQF_DISABLED, "p54spi",
+                         p54spi_interrupt, 0, "p54spi",
                          priv->spi);
        if (ret < 0) {
                dev_err(&priv->spi->dev, "request_irq() failed");
index 68dbbb9c6d1259eb3d83d7c1458126f6fc69a2f2..a18b0051a74551d1d62205ba8452292a3cce45a6 100644 (file)
@@ -219,6 +219,7 @@ config RT2X00_LIB_USB
 
 config RT2X00_LIB
        tristate
+       select AVERAGE
 
 config RT2X00_LIB_FIRMWARE
        boolean
index fa33b5edf931ba688cb40297937e519a67883b76..aab6b5e4f5ddd0fb0a52b7385388f3a07c738add 100644 (file)
@@ -52,6 +52,7 @@
  * RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
  * RF3053 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
  * RF5592 2.4G/5G 2T2R
+ * RF3070 2.4G 1T1R
  * RF5360 2.4G 1T1R
  * RF5370 2.4G 1T1R
  * RF5390 2.4G 1T1R
@@ -70,6 +71,7 @@
 #define RF3322                         0x000c
 #define RF3053                         0x000d
 #define RF5592                         0x000f
+#define RF3070                         0x3070
 #define RF3290                         0x3290
 #define RF5360                         0x5360
 #define RF5370                         0x5370
 /*
  * MAC_CSR0_3290: MAC_CSR0 for RT3290 to identity MAC version number.
  */
-#define MAC_CSR0_3290                          0x0000
+#define MAC_CSR0_3290                  0x0000
 
 /*
  * E2PROM_CSR: PCI EEPROM control register.
 /*
  * COEX_CFG_0
  */
-#define COEX_CFG0                      0x0040
+#define COEX_CFG0              0x0040
 #define COEX_CFG_ANT           FIELD32(0xff000000)
 /*
  * COEX_CFG_1
  */
-#define COEX_CFG1                      0x0044
+#define COEX_CFG1              0x0044
 
 /*
  * COEX_CFG_2
  */
-#define COEX_CFG2                      0x0048
+#define COEX_CFG2              0x0048
 #define BT_COEX_CFG1           FIELD32(0xff000000)
 #define BT_COEX_CFG0           FIELD32(0x00ff0000)
 #define WL_COEX_CFG1           FIELD32(0x0000ff00)
 #define PLL_RESERVED_INPUT2    FIELD32(0x0000ff00)
 #define PLL_CONTROL            FIELD32(0x00070000)
 #define PLL_LPF_R1             FIELD32(0x00080000)
-#define PLL_LPF_C1_CTRL        FIELD32(0x00300000)
-#define PLL_LPF_C2_CTRL        FIELD32(0x00c00000)
+#define PLL_LPF_C1_CTRL                FIELD32(0x00300000)
+#define PLL_LPF_C2_CTRL                FIELD32(0x00c00000)
 #define PLL_CP_CURRENT_CTRL    FIELD32(0x03000000)
 #define PLL_PFD_DELAY_CTRL     FIELD32(0x0c000000)
 #define PLL_LOCK_CTRL          FIELD32(0x70000000)
@@ -2164,7 +2166,7 @@ struct mac_iveiv_entry {
  */
 #define RFCSR6_R1                      FIELD8(0x03)
 #define RFCSR6_R2                      FIELD8(0x40)
-#define RFCSR6_TXDIV           FIELD8(0x0c)
+#define RFCSR6_TXDIV                   FIELD8(0x0c)
 /* bits for RF3053 */
 #define RFCSR6_VCO_IC                  FIELD8(0xc0)
 
@@ -2202,13 +2204,13 @@ struct mac_iveiv_entry {
  * RFCSR 12:
  */
 #define RFCSR12_TX_POWER               FIELD8(0x1f)
-#define RFCSR12_DR0                            FIELD8(0xe0)
+#define RFCSR12_DR0                    FIELD8(0xe0)
 
 /*
  * RFCSR 13:
  */
 #define RFCSR13_TX_POWER               FIELD8(0x1f)
-#define RFCSR13_DR0                            FIELD8(0xe0)
+#define RFCSR13_DR0                    FIELD8(0xe0)
 
 /*
  * RFCSR 15:
@@ -2226,7 +2228,7 @@ struct mac_iveiv_entry {
 #define RFCSR17_TXMIXER_GAIN           FIELD8(0x07)
 #define RFCSR17_TX_LO1_EN              FIELD8(0x08)
 #define RFCSR17_R                      FIELD8(0x20)
-#define RFCSR17_CODE                   FIELD8(0x7f)
+#define RFCSR17_CODE                   FIELD8(0x7f)
 
 /* RFCSR 18 */
 #define RFCSR18_XO_TUNE_BYPASS         FIELD8(0x40)
@@ -2449,7 +2451,7 @@ enum rt2800_eeprom_word {
  */
 #define EEPROM_NIC_CONF0_RXPATH                FIELD16(0x000f)
 #define EEPROM_NIC_CONF0_TXPATH                FIELD16(0x00f0)
-#define EEPROM_NIC_CONF0_RF_TYPE               FIELD16(0x0f00)
+#define EEPROM_NIC_CONF0_RF_TYPE       FIELD16(0x0f00)
 
 /*
  * EEPROM NIC Configuration 1
@@ -2471,18 +2473,18 @@ enum rt2800_eeprom_word {
  * DAC_TEST: 0: disable, 1: enable
  */
 #define EEPROM_NIC_CONF1_HW_RADIO              FIELD16(0x0001)
-#define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC               FIELD16(0x0002)
-#define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G               FIELD16(0x0004)
-#define EEPROM_NIC_CONF1_EXTERNAL_LNA_5G               FIELD16(0x0008)
+#define EEPROM_NIC_CONF1_EXTERNAL_TX_ALC       FIELD16(0x0002)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_2G       FIELD16(0x0004)
+#define EEPROM_NIC_CONF1_EXTERNAL_LNA_5G       FIELD16(0x0008)
 #define EEPROM_NIC_CONF1_CARDBUS_ACCEL         FIELD16(0x0010)
 #define EEPROM_NIC_CONF1_BW40M_SB_2G           FIELD16(0x0020)
 #define EEPROM_NIC_CONF1_BW40M_SB_5G           FIELD16(0x0040)
 #define EEPROM_NIC_CONF1_WPS_PBC               FIELD16(0x0080)
 #define EEPROM_NIC_CONF1_BW40M_2G              FIELD16(0x0100)
 #define EEPROM_NIC_CONF1_BW40M_5G              FIELD16(0x0200)
-#define EEPROM_NIC_CONF1_BROADBAND_EXT_LNA             FIELD16(0x400)
+#define EEPROM_NIC_CONF1_BROADBAND_EXT_LNA     FIELD16(0x400)
 #define EEPROM_NIC_CONF1_ANT_DIVERSITY         FIELD16(0x1800)
-#define EEPROM_NIC_CONF1_INTERNAL_TX_ALC               FIELD16(0x2000)
+#define EEPROM_NIC_CONF1_INTERNAL_TX_ALC       FIELD16(0x2000)
 #define EEPROM_NIC_CONF1_BT_COEXIST            FIELD16(0x4000)
 #define EEPROM_NIC_CONF1_DAC_TEST              FIELD16(0x8000)
 
@@ -2521,9 +2523,9 @@ enum rt2800_eeprom_word {
  * TX_STREAM: 0: Reserved, 1: 1 Stream, 2: 2 Stream
  * CRYSTAL: 00: Reserved, 01: One crystal, 10: Two crystal, 11: Reserved
  */
-#define EEPROM_NIC_CONF2_RX_STREAM             FIELD16(0x000f)
-#define EEPROM_NIC_CONF2_TX_STREAM             FIELD16(0x00f0)
-#define EEPROM_NIC_CONF2_CRYSTAL               FIELD16(0x0600)
+#define EEPROM_NIC_CONF2_RX_STREAM     FIELD16(0x000f)
+#define EEPROM_NIC_CONF2_TX_STREAM     FIELD16(0x00f0)
+#define EEPROM_NIC_CONF2_CRYSTAL       FIELD16(0x0600)
 
 /*
  * EEPROM LNA
@@ -2790,7 +2792,7 @@ enum rt2800_eeprom_word {
 #define MCU_CURRENT                    0x36
 #define MCU_LED                                0x50
 #define MCU_LED_STRENGTH               0x51
-#define MCU_LED_AG_CONF                0x52
+#define MCU_LED_AG_CONF                        0x52
 #define MCU_LED_ACT_CONF               0x53
 #define MCU_LED_LED_POLARITY           0x54
 #define MCU_RADAR                      0x60
@@ -2799,7 +2801,7 @@ enum rt2800_eeprom_word {
 #define MCU_FREQ_OFFSET                        0x74
 #define MCU_BBP_SIGNAL                 0x80
 #define MCU_POWER_SAVE                 0x83
-#define MCU_BAND_SELECT                0x91
+#define MCU_BAND_SELECT                        0x91
 
 /*
  * MCU mailbox tokens
index 88ce656f96cda3d7ea1f7ae5756827538edfc6d2..aa87894239370be67f7c6136723b6cdb35855c0d 100644 (file)
@@ -278,12 +278,9 @@ static const unsigned int rt2800_eeprom_map_ext[EEPROM_WORD_COUNT] = {
        [EEPROM_LNA]                    = 0x0026,
        [EEPROM_EXT_LNA2]               = 0x0027,
        [EEPROM_RSSI_BG]                = 0x0028,
-       [EEPROM_TXPOWER_DELTA]          = 0x0028, /* Overlaps with RSSI_BG */
        [EEPROM_RSSI_BG2]               = 0x0029,
-       [EEPROM_TXMIXER_GAIN_BG]        = 0x0029, /* Overlaps with RSSI_BG2 */
        [EEPROM_RSSI_A]                 = 0x002a,
        [EEPROM_RSSI_A2]                = 0x002b,
-       [EEPROM_TXMIXER_GAIN_A]         = 0x002b, /* Overlaps with RSSI_A2 */
        [EEPROM_TXPOWER_BG1]            = 0x0030,
        [EEPROM_TXPOWER_BG2]            = 0x0037,
        [EEPROM_EXT_TXPOWER_BG3]        = 0x003e,
@@ -1783,7 +1780,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
        rt2800_bbp_read(rt2x00dev, 3, &r3);
 
        if (rt2x00_rt(rt2x00dev, RT3572) &&
-           test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
+           rt2x00_has_cap_bt_coexist(rt2x00dev))
                rt2800_config_3572bt_ant(rt2x00dev);
 
        /*
@@ -1795,7 +1792,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
                break;
        case 2:
                if (rt2x00_rt(rt2x00dev, RT3572) &&
-                   test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
+                   rt2x00_has_cap_bt_coexist(rt2x00dev))
                        rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 1);
                else
                        rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
@@ -1825,7 +1822,7 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
                break;
        case 2:
                if (rt2x00_rt(rt2x00dev, RT3572) &&
-                   test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
+                   rt2x00_has_cap_bt_coexist(rt2x00dev)) {
                        rt2x00_set_field8(&r3, BBP3_RX_ADC, 1);
                        rt2x00_set_field8(&r3, BBP3_RX_ANTENNA,
                                rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
@@ -2029,13 +2026,6 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
                          rt2x00dev->default_ant.tx_chain_num <= 2);
        rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
 
-       rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr);
-       rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1);
-       rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-       msleep(1);
-       rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 0);
-       rt2800_rfcsr_write(rt2x00dev, 30, rfcsr);
-
        rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
        rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
        rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
@@ -2141,7 +2131,7 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
        rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 0);
        rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 0);
-       if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
+       if (rt2x00_has_cap_bt_coexist(rt2x00dev)) {
                if (rf->channel <= 14) {
                        rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
                        rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
@@ -2674,7 +2664,7 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev,
        if (rf->channel <= 14) {
                int idx = rf->channel-1;
 
-               if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
+               if (rt2x00_has_cap_bt_coexist(rt2x00dev)) {
                        if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F)) {
                                /* r55/r59 value array of channel 1~14 */
                                static const char r55_bt_rev[] = {0x83, 0x83,
@@ -3152,6 +3142,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        case RF3322:
                rt2800_config_channel_rf3322(rt2x00dev, conf, rf, info);
                break;
+       case RF3070:
        case RF5360:
        case RF5370:
        case RF5372:
@@ -3166,7 +3157,8 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
        }
 
-       if (rt2x00_rf(rt2x00dev, RF3290) ||
+       if (rt2x00_rf(rt2x00dev, RF3070) ||
+           rt2x00_rf(rt2x00dev, RF3290) ||
            rt2x00_rf(rt2x00dev, RF3322) ||
            rt2x00_rf(rt2x00dev, RF5360) ||
            rt2x00_rf(rt2x00dev, RF5370) ||
@@ -3218,8 +3210,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        if (rf->channel <= 14) {
                if (!rt2x00_rt(rt2x00dev, RT5390) &&
                    !rt2x00_rt(rt2x00dev, RT5392)) {
-                       if (test_bit(CAPABILITY_EXTERNAL_LNA_BG,
-                                    &rt2x00dev->cap_flags)) {
+                       if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
                                rt2800_bbp_write(rt2x00dev, 82, 0x62);
                                rt2800_bbp_write(rt2x00dev, 75, 0x46);
                        } else {
@@ -3244,7 +3235,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                if (rt2x00_rt(rt2x00dev, RT3593))
                        rt2800_bbp_write(rt2x00dev, 83, 0x9a);
 
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
+               if (rt2x00_has_cap_external_lna_a(rt2x00dev))
                        rt2800_bbp_write(rt2x00dev, 75, 0x46);
                else
                        rt2800_bbp_write(rt2x00dev, 75, 0x50);
@@ -3280,7 +3271,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                /* Turn on primary PAs */
                rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN,
                                   rf->channel > 14);
-               if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
+               if (rt2x00_has_cap_bt_coexist(rt2x00dev))
                        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
                else
                        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN,
@@ -3311,33 +3302,50 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
 
        rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
 
-       if (rt2x00_rt(rt2x00dev, RT3572))
+       if (rt2x00_rt(rt2x00dev, RT3572)) {
                rt2800_rfcsr_write(rt2x00dev, 8, 0x80);
 
+               /* AGC init */
+               if (rf->channel <= 14)
+                       reg = 0x1c + (2 * rt2x00dev->lna_gain);
+               else
+                       reg = 0x22 + ((rt2x00dev->lna_gain * 5) / 3);
+
+               rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
+       }
+
        if (rt2x00_rt(rt2x00dev, RT3593)) {
-               if (rt2x00_is_usb(rt2x00dev)) {
-                       rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
+               rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
 
-                       /* Band selection. GPIO #8 controls all paths */
+               /* Band selection */
+               if (rt2x00_is_usb(rt2x00dev) ||
+                   rt2x00_is_pcie(rt2x00dev)) {
+                       /* GPIO #8 controls all paths */
                        rt2x00_set_field32(&reg, GPIO_CTRL_DIR8, 0);
                        if (rf->channel <= 14)
                                rt2x00_set_field32(&reg, GPIO_CTRL_VAL8, 1);
                        else
                                rt2x00_set_field32(&reg, GPIO_CTRL_VAL8, 0);
+               }
 
+               /* LNA PE control. */
+               if (rt2x00_is_usb(rt2x00dev)) {
+                       /* GPIO #4 controls PE0 and PE1,
+                        * GPIO #7 controls PE2
+                        */
                        rt2x00_set_field32(&reg, GPIO_CTRL_DIR4, 0);
                        rt2x00_set_field32(&reg, GPIO_CTRL_DIR7, 0);
 
-                       /* LNA PE control.
-                       * GPIO #4 controls PE0 and PE1,
-                       * GPIO #7 controls PE2
-                       */
                        rt2x00_set_field32(&reg, GPIO_CTRL_VAL4, 1);
                        rt2x00_set_field32(&reg, GPIO_CTRL_VAL7, 1);
-
-                       rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
+               } else if (rt2x00_is_pcie(rt2x00dev)) {
+                       /* GPIO #4 controls PE0, PE1 and PE2 */
+                       rt2x00_set_field32(&reg, GPIO_CTRL_DIR4, 0);
+                       rt2x00_set_field32(&reg, GPIO_CTRL_VAL4, 1);
                }
 
+               rt2800_register_write(rt2x00dev, GPIO_CTRL, reg);
+
                /* AGC init */
                if (rf->channel <= 14)
                        reg = 0x1c + 2 * rt2x00dev->lna_gain;
@@ -3565,7 +3573,7 @@ static int rt2800_get_txpower_reg_delta(struct rt2x00_dev *rt2x00dev,
 {
        int delta;
 
-       if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_power_limit(rt2x00dev))
                return 0;
 
        /*
@@ -3594,7 +3602,7 @@ static u8 rt2800_compensate_txpower(struct rt2x00_dev *rt2x00dev, int is_rate_b,
        if (rt2x00_rt(rt2x00dev, RT3593))
                return min_t(u8, txpower, 0xc);
 
-       if (test_bit(CAPABILITY_POWER_LIMIT, &rt2x00dev->cap_flags)) {
+       if (rt2x00_has_cap_power_limit(rt2x00dev)) {
                /*
                 * Check if eirp txpower exceed txpower_limit.
                 * We use OFDM 6M as criterion and its eirp txpower
@@ -4264,6 +4272,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
                break;
        case RF3053:
+       case RF3070:
        case RF3290:
        case RF5360:
        case RF5370:
@@ -4405,6 +4414,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
                    rt2x00_rt(rt2x00dev, RT3290) ||
                    rt2x00_rt(rt2x00dev, RT3390) ||
                    rt2x00_rt(rt2x00dev, RT3572) ||
+                   rt2x00_rt(rt2x00dev, RT3593) ||
                    rt2x00_rt(rt2x00dev, RT5390) ||
                    rt2x00_rt(rt2x00dev, RT5392) ||
                    rt2x00_rt(rt2x00dev, RT5592))
@@ -4412,8 +4422,8 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev)
                else
                        vgc = 0x2e + rt2x00dev->lna_gain;
        } else { /* 5GHZ band */
-               if (rt2x00_rt(rt2x00dev, RT3572))
-                       vgc = 0x22 + (rt2x00dev->lna_gain * 5) / 3;
+               if (rt2x00_rt(rt2x00dev, RT3593))
+                       vgc = 0x20 + (rt2x00dev->lna_gain * 5) / 3;
                else if (rt2x00_rt(rt2x00dev, RT5592))
                        vgc = 0x24 + (2 * rt2x00dev->lna_gain);
                else {
@@ -4431,11 +4441,17 @@ static inline void rt2800_set_vgc(struct rt2x00_dev *rt2x00dev,
                                  struct link_qual *qual, u8 vgc_level)
 {
        if (qual->vgc_level != vgc_level) {
-               if (rt2x00_rt(rt2x00dev, RT5592)) {
+               if (rt2x00_rt(rt2x00dev, RT3572) ||
+                   rt2x00_rt(rt2x00dev, RT3593)) {
+                       rt2800_bbp_write_with_rx_chain(rt2x00dev, 66,
+                                                      vgc_level);
+               } else if (rt2x00_rt(rt2x00dev, RT5592)) {
                        rt2800_bbp_write(rt2x00dev, 83, qual->rssi > -65 ? 0x4a : 0x7a);
                        rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, vgc_level);
-               } else
+               } else {
                        rt2800_bbp_write(rt2x00dev, 66, vgc_level);
+               }
+
                qual->vgc_level = vgc_level;
                qual->vgc_level_reg = vgc_level;
        }
@@ -4454,17 +4470,35 @@ void rt2800_link_tuner(struct rt2x00_dev *rt2x00dev, struct link_qual *qual,
 
        if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C))
                return;
-       /*
-        * When RSSI is better then -80 increase VGC level with 0x10, except
-        * for rt5592 chip.
+
+       /* When RSSI is better than a certain threshold, increase VGC
+        * with a chip specific value in order to improve the balance
+        * between sensibility and noise isolation.
         */
 
        vgc = rt2800_get_default_vgc(rt2x00dev);
 
-       if (rt2x00_rt(rt2x00dev, RT5592) && qual->rssi > -65)
-               vgc += 0x20;
-       else if (qual->rssi > -80)
-               vgc += 0x10;
+       switch (rt2x00dev->chip.rt) {
+       case RT3572:
+       case RT3593:
+               if (qual->rssi > -65) {
+                       if (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)
+                               vgc += 0x20;
+                       else
+                               vgc += 0x10;
+               }
+               break;
+
+       case RT5592:
+               if (qual->rssi > -65)
+                       vgc += 0x20;
+               break;
+
+       default:
+               if (qual->rssi > -80)
+                       vgc += 0x10;
+               break;
+       }
 
        rt2800_set_vgc(rt2x00dev, qual, vgc);
 }
@@ -5489,7 +5523,7 @@ static void rt2800_init_bbp_53xx(struct rt2x00_dev *rt2x00dev)
        ant = (div_mode == 3) ? 1 : 0;
 
        /* check if this is a Bluetooth combo card */
-       if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
+       if (rt2x00_has_cap_bt_coexist(rt2x00dev)) {
                u32 reg;
 
                rt2800_register_read(rt2x00dev, GPIO_CTRL, &reg);
@@ -5798,7 +5832,7 @@ static void rt2800_normal_mode_setup_3xxx(struct rt2x00_dev *rt2x00dev)
            rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) ||
            rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) ||
            rt2x00_rt_rev_lt(rt2x00dev, RT3390, REV_RT3390E)) {
-               if (!test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
+               if (!rt2x00_has_cap_external_lna_bg(rt2x00dev))
                        rt2x00_set_field8(&rfcsr, RFCSR17_R, 1);
        }
 
@@ -5985,7 +6019,7 @@ static void rt2800_init_rfcsr_30xx(struct rt2x00_dev *rt2x00dev)
        rt2800_rfcsr_write(rt2x00dev, 20, 0xba);
        rt2800_rfcsr_write(rt2x00dev, 21, 0xdb);
        rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
-       rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+       rt2800_rfcsr_write(rt2x00dev, 25, 0x03);
        rt2800_rfcsr_write(rt2x00dev, 29, 0x1f);
 
        if (rt2x00_rt_rev_lt(rt2x00dev, RT3070, REV_RT3070F)) {
@@ -6441,7 +6475,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
        rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
        rt2800_rfcsr_write(rt2x00dev, 29, 0x10);
 
-       rt2800_rfcsr_write(rt2x00dev, 30, 0x00);
+       rt2800_rfcsr_write(rt2x00dev, 30, 0x10);
        rt2800_rfcsr_write(rt2x00dev, 31, 0x80);
        rt2800_rfcsr_write(rt2x00dev, 32, 0x80);
        rt2800_rfcsr_write(rt2x00dev, 33, 0x00);
@@ -6479,7 +6513,7 @@ static void rt2800_init_rfcsr_5390(struct rt2x00_dev *rt2x00dev)
        rt2800_rfcsr_write(rt2x00dev, 56, 0x22);
        rt2800_rfcsr_write(rt2x00dev, 57, 0x80);
        rt2800_rfcsr_write(rt2x00dev, 58, 0x7f);
-       rt2800_rfcsr_write(rt2x00dev, 59, 0x63);
+       rt2800_rfcsr_write(rt2x00dev, 59, 0x8f);
 
        rt2800_rfcsr_write(rt2x00dev, 60, 0x45);
        if (rt2x00_rt_rev_gte(rt2x00dev, RT5390, REV_RT5390F))
@@ -6499,7 +6533,6 @@ static void rt2800_init_rfcsr_5392(struct rt2x00_dev *rt2x00dev)
        rt2800_rf_init_calibration(rt2x00dev, 2);
 
        rt2800_rfcsr_write(rt2x00dev, 1, 0x17);
-       rt2800_rfcsr_write(rt2x00dev, 2, 0x80);
        rt2800_rfcsr_write(rt2x00dev, 3, 0x88);
        rt2800_rfcsr_write(rt2x00dev, 5, 0x10);
        rt2800_rfcsr_write(rt2x00dev, 6, 0xe0);
@@ -6653,17 +6686,20 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
        u16 word;
 
        /*
-        * Initialize all registers.
+        * Initialize MAC registers.
         */
        if (unlikely(rt2800_wait_wpdma_ready(rt2x00dev) ||
                     rt2800_init_registers(rt2x00dev)))
                return -EIO;
 
+       /*
+        * Wait BBP/RF to wake up.
+        */
        if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev)))
                return -EIO;
 
        /*
-        * Send signal to firmware during boot time.
+        * Send signal during boot time to initialize firmware.
         */
        rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
        rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
@@ -6672,9 +6708,15 @@ int rt2800_enable_radio(struct rt2x00_dev *rt2x00dev)
        rt2800_mcu_request(rt2x00dev, MCU_BOOT_SIGNAL, 0, 0, 0);
        msleep(1);
 
+       /*
+        * Make sure BBP is up and running.
+        */
        if (unlikely(rt2800_wait_bbp_ready(rt2x00dev)))
                return -EIO;
 
+       /*
+        * Initialize BBP/RF registers.
+        */
        rt2800_init_bbp(rt2x00dev);
        rt2800_init_rfcsr(rt2x00dev);
 
@@ -7021,6 +7063,7 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev)
        case RF3022:
        case RF3052:
        case RF3053:
+       case RF3070:
        case RF3290:
        case RF3320:
        case RF3322:
@@ -7203,7 +7246,7 @@ static const struct rf_channel rf_vals[] = {
 
 /*
  * RF value list for rt3xxx
- * Supports: 2.4 GHz (all) & 5.2 GHz (RF3052)
+ * Supports: 2.4 GHz (all) & 5.2 GHz (RF3052 & RF3053)
  */
 static const struct rf_channel rf_vals_3x[] = {
        {1,  241, 2, 2 },
@@ -7399,72 +7442,6 @@ static const struct rf_channel rf_vals_5592_xtal40[] = {
        {196, 83, 0, 12, 1},
 };
 
-static const struct rf_channel rf_vals_3053[] = {
-       /* Channel, N, R, K */
-       {1, 241, 2, 2},
-       {2, 241, 2, 7},
-       {3, 242, 2, 2},
-       {4, 242, 2, 7},
-       {5, 243, 2, 2},
-       {6, 243, 2, 7},
-       {7, 244, 2, 2},
-       {8, 244, 2, 7},
-       {9, 245, 2, 2},
-       {10, 245, 2, 7},
-       {11, 246, 2, 2},
-       {12, 246, 2, 7},
-       {13, 247, 2, 2},
-       {14, 248, 2, 4},
-
-       {36, 0x56, 0, 4},
-       {38, 0x56, 0, 6},
-       {40, 0x56, 0, 8},
-       {44, 0x57, 0, 0},
-       {46, 0x57, 0, 2},
-       {48, 0x57, 0, 4},
-       {52, 0x57, 0, 8},
-       {54, 0x57, 0, 10},
-       {56, 0x58, 0, 0},
-       {60, 0x58, 0, 4},
-       {62, 0x58, 0, 6},
-       {64, 0x58, 0, 8},
-
-       {100, 0x5B, 0, 8},
-       {102, 0x5B, 0, 10},
-       {104, 0x5C, 0, 0},
-       {108, 0x5C, 0, 4},
-       {110, 0x5C, 0, 6},
-       {112, 0x5C, 0, 8},
-
-       /* NOTE: Channel 114 has been removed intentionally.
-        * The EEPROM contains no TX power values for that,
-        * and it is disabled in the vendor driver as well.
-        */
-
-       {116, 0x5D, 0, 0},
-       {118, 0x5D, 0, 2},
-       {120, 0x5D, 0, 4},
-       {124, 0x5D, 0, 8},
-       {126, 0x5D, 0, 10},
-       {128, 0x5E, 0, 0},
-       {132, 0x5E, 0, 4},
-       {134, 0x5E, 0, 6},
-       {136, 0x5E, 0, 8},
-       {140, 0x5F, 0, 0},
-
-       {149, 0x5F, 0, 9},
-       {151, 0x5F, 0, 11},
-       {153, 0x60, 0, 1},
-       {157, 0x60, 0, 5},
-       {159, 0x60, 0, 7},
-       {161, 0x60, 0, 9},
-       {165, 0x61, 0, 1},
-       {167, 0x61, 0, 3},
-       {169, 0x61, 0, 5},
-       {171, 0x61, 0, 7},
-       {173, 0x61, 0, 9},
-};
-
 static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
 {
        struct hw_mode_spec *spec = &rt2x00dev->spec;
@@ -7543,6 +7520,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                   rt2x00_rf(rt2x00dev, RF2020) ||
                   rt2x00_rf(rt2x00dev, RF3021) ||
                   rt2x00_rf(rt2x00dev, RF3022) ||
+                  rt2x00_rf(rt2x00dev, RF3070) ||
                   rt2x00_rf(rt2x00dev, RF3290) ||
                   rt2x00_rf(rt2x00dev, RF3320) ||
                   rt2x00_rf(rt2x00dev, RF3322) ||
@@ -7553,14 +7531,11 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
                   rt2x00_rf(rt2x00dev, RF5392)) {
                spec->num_channels = 14;
                spec->channels = rf_vals_3x;
-       } else if (rt2x00_rf(rt2x00dev, RF3052)) {
+       } else if (rt2x00_rf(rt2x00dev, RF3052) ||
+                  rt2x00_rf(rt2x00dev, RF3053)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
                spec->num_channels = ARRAY_SIZE(rf_vals_3x);
                spec->channels = rf_vals_3x;
-       } else if (rt2x00_rf(rt2x00dev, RF3053)) {
-               spec->supported_bands |= SUPPORT_BAND_5GHZ;
-               spec->num_channels = ARRAY_SIZE(rf_vals_3053);
-               spec->channels = rf_vals_3053;
        } else if (rt2x00_rf(rt2x00dev, RF5592)) {
                spec->supported_bands |= SUPPORT_BAND_5GHZ;
 
@@ -7671,6 +7646,7 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        case RF3320:
        case RF3052:
        case RF3053:
+       case RF3070:
        case RF3290:
        case RF5360:
        case RF5370:
index 96961b9a395cf0d2e01c32449c4e9bcc55e7828c..96677ce55da46378136a2555062664133c7af931 100644 (file)
@@ -1176,6 +1176,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Linksys */
        { USB_DEVICE(0x13b1, 0x002f) },
        { USB_DEVICE(0x1737, 0x0079) },
+       /* Logitec */
+       { USB_DEVICE(0x0789, 0x0170) },
        /* Ralink */
        { USB_DEVICE(0x148f, 0x3572) },
        /* Sitecom */
@@ -1199,6 +1201,8 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x050d, 0x1103) },
        /* Cameo */
        { USB_DEVICE(0x148f, 0xf301) },
+       /* D-Link */
+       { USB_DEVICE(0x2001, 0x3c1f) },
        /* Edimax */
        { USB_DEVICE(0x7392, 0x7733) },
        /* Hawking */
@@ -1212,6 +1216,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x0789, 0x016b) },
        /* NETGEAR */
        { USB_DEVICE(0x0846, 0x9012) },
+       { USB_DEVICE(0x0846, 0x9013) },
        { USB_DEVICE(0x0846, 0x9019) },
        /* Planex */
        { USB_DEVICE(0x2019, 0xed19) },
@@ -1220,6 +1225,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        /* Sitecom */
        { USB_DEVICE(0x0df6, 0x0067) },
        { USB_DEVICE(0x0df6, 0x006a) },
+       { USB_DEVICE(0x0df6, 0x006e) },
        /* ZyXEL */
        { USB_DEVICE(0x0586, 0x3421) },
 #endif
@@ -1236,6 +1242,9 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x2001, 0x3c1c) },
        { USB_DEVICE(0x2001, 0x3c1d) },
        { USB_DEVICE(0x2001, 0x3c1e) },
+       { USB_DEVICE(0x2001, 0x3c20) },
+       { USB_DEVICE(0x2001, 0x3c22) },
+       { USB_DEVICE(0x2001, 0x3c23) },
        /* LG innotek */
        { USB_DEVICE(0x043e, 0x7a22) },
        { USB_DEVICE(0x043e, 0x7a42) },
@@ -1258,12 +1267,17 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x043e, 0x7a32) },
        /* AVM GmbH */
        { USB_DEVICE(0x057c, 0x8501) },
-       /* D-Link DWA-160-B2 */
+       /* Buffalo */
+       { USB_DEVICE(0x0411, 0x0241) },
+       /* D-Link */
        { USB_DEVICE(0x2001, 0x3c1a) },
+       { USB_DEVICE(0x2001, 0x3c21) },
        /* Proware */
        { USB_DEVICE(0x043e, 0x7a13) },
        /* Ralink */
        { USB_DEVICE(0x148f, 0x5572) },
+       /* TRENDnet */
+       { USB_DEVICE(0x20f4, 0x724a) },
 #endif
 #ifdef CONFIG_RT2800USB_UNKNOWN
        /*
@@ -1333,6 +1347,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x1d4d, 0x0010) },
        /* Planex */
        { USB_DEVICE(0x2019, 0xab24) },
+       { USB_DEVICE(0x2019, 0xab29) },
        /* Qcom */
        { USB_DEVICE(0x18e8, 0x6259) },
        /* RadioShack */
index fe4c572db52c2749317690b75ad4cc296aec5157..e4ba2ce0f212b955f15db89df45d3b32af9942de 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/input-polldev.h>
 #include <linux/kfifo.h>
 #include <linux/hrtimer.h>
+#include <linux/average.h>
 
 #include <net/mac80211.h>
 
 #define SHORT_EIFS             ( SIFS + SHORT_DIFS + \
                                  GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
 
-/*
- * Structure for average calculation
- * The avg field contains the actual average value,
- * but avg_weight is internally used during calculations
- * to prevent rounding errors.
- */
-struct avg_val {
-       int avg;
-       int avg_weight;
-};
-
 enum rt2x00_chip_intf {
        RT2X00_CHIP_INTF_PCI,
        RT2X00_CHIP_INTF_PCIE,
@@ -297,7 +287,7 @@ struct link_ant {
         * Similar to the avg_rssi in the link_qual structure
         * this value is updated by using the walking average.
         */
-       struct avg_val rssi_ant;
+       struct ewma rssi_ant;
 };
 
 /*
@@ -326,7 +316,7 @@ struct link {
        /*
         * Currently active average RSSI value
         */
-       struct avg_val avg_rssi;
+       struct ewma avg_rssi;
 
        /*
         * Work structure for scheduling periodic link tuning.
@@ -1179,6 +1169,93 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
        return rt2x00_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC);
 }
 
+/* Helpers for capability flags */
+
+static inline bool
+rt2x00_has_cap_flag(struct rt2x00_dev *rt2x00dev,
+                   enum rt2x00_capability_flags cap_flag)
+{
+       return test_bit(cap_flag, &rt2x00dev->cap_flags);
+}
+
+static inline bool
+rt2x00_has_cap_hw_crypto(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_HW_CRYPTO);
+}
+
+static inline bool
+rt2x00_has_cap_power_limit(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_POWER_LIMIT);
+}
+
+static inline bool
+rt2x00_has_cap_control_filters(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_CONTROL_FILTERS);
+}
+
+static inline bool
+rt2x00_has_cap_control_filter_pspoll(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_CONTROL_FILTER_PSPOLL);
+}
+
+static inline bool
+rt2x00_has_cap_pre_tbtt_interrupt(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_PRE_TBTT_INTERRUPT);
+}
+
+static inline bool
+rt2x00_has_cap_link_tuning(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_LINK_TUNING);
+}
+
+static inline bool
+rt2x00_has_cap_frame_type(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_FRAME_TYPE);
+}
+
+static inline bool
+rt2x00_has_cap_rf_sequence(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_RF_SEQUENCE);
+}
+
+static inline bool
+rt2x00_has_cap_external_lna_a(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_EXTERNAL_LNA_A);
+}
+
+static inline bool
+rt2x00_has_cap_external_lna_bg(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_EXTERNAL_LNA_BG);
+}
+
+static inline bool
+rt2x00_has_cap_double_antenna(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_DOUBLE_ANTENNA);
+}
+
+static inline bool
+rt2x00_has_cap_bt_coexist(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_BT_COEXIST);
+}
+
+static inline bool
+rt2x00_has_cap_vco_recalibration(struct rt2x00_dev *rt2x00dev)
+{
+       return rt2x00_has_cap_flag(rt2x00dev, CAPABILITY_VCO_RECALIBRATION);
+}
+
 /**
  * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
  * @entry: Pointer to &struct queue_entry
index 1ca4c7ffc1898c9ce97d87506b0b8e78464e78ad..3db0d99d9da7a9980f63939186f7c2b7971cd533 100644 (file)
@@ -52,7 +52,7 @@ void rt2x00crypto_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
 
-       if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !hw_key)
+       if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !hw_key)
                return;
 
        __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags);
@@ -80,7 +80,7 @@ unsigned int rt2x00crypto_tx_overhead(struct rt2x00_dev *rt2x00dev,
        struct ieee80211_key_conf *key = tx_info->control.hw_key;
        unsigned int overhead = 0;
 
-       if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags) || !key)
+       if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || !key)
                return overhead;
 
        /*
index fe7a7f63a9edc2cf75c0a2caa2f6b8ffe02234aa..7f7baae5ae029e6c252676841682cf8fabf270f4 100644 (file)
@@ -750,7 +750,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
                                intf, &rt2x00debug_fop_queue_stats);
 
 #ifdef CONFIG_RT2X00_LIB_CRYPTO
-       if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_hw_crypto(rt2x00dev))
                intf->crypto_stats_entry =
                    debugfs_create_file("crypto", S_IRUGO, intf->queue_folder,
                                        intf, &rt2x00debug_fop_crypto_stats);
index 712eea9d398ffa747a1c76ebfd0da0ad84ed8854..080b1fcae5fa8f3f2b376d5b77bffab2519ddf57 100644 (file)
@@ -88,7 +88,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev)
        rt2x00queue_start_queues(rt2x00dev);
        rt2x00link_start_tuner(rt2x00dev);
        rt2x00link_start_agc(rt2x00dev);
-       if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_vco_recalibration(rt2x00dev))
                rt2x00link_start_vcocal(rt2x00dev);
 
        /*
@@ -113,7 +113,7 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev)
         * Stop all queues
         */
        rt2x00link_stop_agc(rt2x00dev);
-       if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_vco_recalibration(rt2x00dev))
                rt2x00link_stop_vcocal(rt2x00dev);
        rt2x00link_stop_tuner(rt2x00dev);
        rt2x00queue_stop_queues(rt2x00dev);
@@ -234,7 +234,7 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
         * here as they will fetch the next beacon directly prior to
         * transmission.
         */
-       if (test_bit(CAPABILITY_PRE_TBTT_INTERRUPT, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_pre_tbtt_interrupt(rt2x00dev))
                return;
 
        /* fetch next beacon */
@@ -358,7 +358,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
         * mac80211 will expect the same data to be present it the
         * frame as it was passed to us.
         */
-       if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_hw_crypto(rt2x00dev))
                rt2x00crypto_tx_insert_iv(entry->skb, header_length);
 
        /*
index 8368aab86f286ee6ff5be65b85a73940f3c24cd0..c2b3b66291884e6171b2cd92b78024406ceb7252 100644 (file)
  */
 #define DEFAULT_RSSI           -128
 
-/*
- * Helper struct and macro to work with moving/walking averages.
- * When adding a value to the average value the following calculation
- * is needed:
- *
- *        avg_rssi = ((avg_rssi * 7) + rssi) / 8;
- *
- * The advantage of this approach is that we only need 1 variable
- * to store the average in (No need for a count and a total).
- * But more importantly, normal average values will over time
- * move less and less towards newly added values this results
- * that with link tuning, the device can have a very good RSSI
- * for a few minutes but when the device is moved away from the AP
- * the average will not decrease fast enough to compensate.
- * The walking average compensates this and will move towards
- * the new values correctly allowing a effective link tuning,
- * the speed of the average moving towards other values depends
- * on the value for the number of samples. The higher the number
- * of samples, the slower the average will move.
- * We use two variables to keep track of the average value to
- * compensate for the rounding errors. This can be a significant
- * error (>5dBm) if the factor is too low.
- */
-#define AVG_SAMPLES    8
-#define AVG_FACTOR     1000
-#define MOVING_AVERAGE(__avg, __val) \
-({ \
-       struct avg_val __new; \
-       __new.avg_weight = \
-           (__avg).avg_weight  ? \
-               ((((__avg).avg_weight * ((AVG_SAMPLES) - 1)) + \
-                 ((__val) * (AVG_FACTOR))) / \
-                (AVG_SAMPLES)) : \
-               ((__val) * (AVG_FACTOR)); \
-       __new.avg = __new.avg_weight / (AVG_FACTOR); \
-       __new; \
-})
+/* Constants for EWMA calculations. */
+#define RT2X00_EWMA_FACTOR     1024
+#define RT2X00_EWMA_WEIGHT     8
+
+static inline int rt2x00link_get_avg_rssi(struct ewma *ewma)
+{
+       unsigned long avg;
+
+       avg = ewma_read(ewma);
+       if (avg)
+               return -avg;
+
+       return DEFAULT_RSSI;
+}
 
 static int rt2x00link_antenna_get_link_rssi(struct rt2x00_dev *rt2x00dev)
 {
        struct link_ant *ant = &rt2x00dev->link.ant;
 
-       if (ant->rssi_ant.avg && rt2x00dev->link.qual.rx_success)
-               return ant->rssi_ant.avg;
+       if (rt2x00dev->link.qual.rx_success)
+               return rt2x00link_get_avg_rssi(&ant->rssi_ant);
+
        return DEFAULT_RSSI;
 }
 
@@ -100,8 +78,8 @@ static void rt2x00link_antenna_update_rssi_history(struct rt2x00_dev *rt2x00dev,
 
 static void rt2x00link_antenna_reset(struct rt2x00_dev *rt2x00dev)
 {
-       rt2x00dev->link.ant.rssi_ant.avg = 0;
-       rt2x00dev->link.ant.rssi_ant.avg_weight = 0;
+       ewma_init(&rt2x00dev->link.ant.rssi_ant, RT2X00_EWMA_FACTOR,
+                 RT2X00_EWMA_WEIGHT);
 }
 
 static void rt2x00lib_antenna_diversity_sample(struct rt2x00_dev *rt2x00dev)
@@ -249,12 +227,12 @@ void rt2x00link_update_stats(struct rt2x00_dev *rt2x00dev,
        /*
         * Update global RSSI
         */
-       link->avg_rssi = MOVING_AVERAGE(link->avg_rssi, rxdesc->rssi);
+       ewma_add(&link->avg_rssi, -rxdesc->rssi);
 
        /*
         * Update antenna RSSI
         */
-       ant->rssi_ant = MOVING_AVERAGE(ant->rssi_ant, rxdesc->rssi);
+       ewma_add(&ant->rssi_ant, -rxdesc->rssi);
 }
 
 void rt2x00link_start_tuner(struct rt2x00_dev *rt2x00dev)
@@ -309,6 +287,8 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
         */
        rt2x00dev->link.count = 0;
        memset(qual, 0, sizeof(*qual));
+       ewma_init(&rt2x00dev->link.avg_rssi, RT2X00_EWMA_FACTOR,
+                 RT2X00_EWMA_WEIGHT);
 
        /*
         * Restore the VGC level as stored in the registers,
@@ -363,17 +343,17 @@ static void rt2x00link_tuner(struct work_struct *work)
         * collect the RSSI data we could use this. Otherwise we
         * must fallback to the default RSSI value.
         */
-       if (!link->avg_rssi.avg || !qual->rx_success)
+       if (!qual->rx_success)
                qual->rssi = DEFAULT_RSSI;
        else
-               qual->rssi = link->avg_rssi.avg;
+               qual->rssi = rt2x00link_get_avg_rssi(&link->avg_rssi);
 
        /*
         * Check if link tuning is supported by the hardware, some hardware
         * do not support link tuning at all, while other devices can disable
         * the feature from the EEPROM.
         */
-       if (test_bit(CAPABILITY_LINK_TUNING, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_link_tuning(rt2x00dev))
                rt2x00dev->ops->lib->link_tuner(rt2x00dev, qual, link->count);
 
        /*
@@ -513,7 +493,7 @@ static void rt2x00link_vcocal(struct work_struct *work)
 void rt2x00link_register(struct rt2x00_dev *rt2x00dev)
 {
        INIT_DELAYED_WORK(&rt2x00dev->link.agc_work, rt2x00link_agc);
-       if (test_bit(CAPABILITY_VCO_RECALIBRATION, &rt2x00dev->cap_flags))
+       if (rt2x00_has_cap_vco_recalibration(rt2x00dev))
                INIT_DELAYED_WORK(&rt2x00dev->link.vco_work, rt2x00link_vcocal);
        INIT_DELAYED_WORK(&rt2x00dev->link.watchdog_work, rt2x00link_watchdog);
        INIT_DELAYED_WORK(&rt2x00dev->link.work, rt2x00link_tuner);
index f883802f350585322338ed7683e065bb85349ff3..51f17cfb93f9aa48c255cd4d0ea8c03a359f071b 100644 (file)
@@ -382,11 +382,11 @@ void rt2x00mac_configure_filter(struct ieee80211_hw *hw,
         * of different types, but has no a separate filter for PS Poll frames,
         * FIF_CONTROL flag implies FIF_PSPOLL.
         */
-       if (!test_bit(CAPABILITY_CONTROL_FILTERS, &rt2x00dev->cap_flags)) {
+       if (!rt2x00_has_cap_control_filters(rt2x00dev)) {
                if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL)
                        *total_flags |= FIF_CONTROL | FIF_PSPOLL;
        }
-       if (!test_bit(CAPABILITY_CONTROL_FILTER_PSPOLL, &rt2x00dev->cap_flags)) {
+       if (!rt2x00_has_cap_control_filter_pspoll(rt2x00dev)) {
                if (*total_flags & FIF_CONTROL)
                        *total_flags |= FIF_PSPOLL;
        }
@@ -469,7 +469,7 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
                return 0;
 
-       if (!test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags))
+       if (!rt2x00_has_cap_hw_crypto(rt2x00dev))
                return -EOPNOTSUPP;
 
        /*
index 76d95deb274be56feb9803adb5b8d198f0c35bd0..6c5d667103c4966606940af0976312165a28bc96 100644 (file)
@@ -121,7 +121,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops)
        rt2x00dev->ops = ops;
        rt2x00dev->hw = hw;
        rt2x00dev->irq = pci_dev->irq;
-       rt2x00dev->name = pci_name(pci_dev);
+       rt2x00dev->name = ops->name;
 
        if (pci_is_pcie(pci_dev))
                rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_PCIE);
index 6c8a33b6ee225082d137df7e392306fa0101534a..50590b1420a516863845249c96f689b28e766964 100644 (file)
@@ -61,7 +61,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
         * at least 8 bytes bytes available in headroom for IV/EIV
         * and 8 bytes for ICV data as tailroon.
         */
-       if (test_bit(CAPABILITY_HW_CRYPTO, &rt2x00dev->cap_flags)) {
+       if (rt2x00_has_cap_hw_crypto(rt2x00dev)) {
                head_size += 8;
                tail_size += 8;
        }
@@ -1033,38 +1033,21 @@ EXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
 
 void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
 {
-       bool started;
        bool tx_queue =
                (queue->qid == QID_AC_VO) ||
                (queue->qid == QID_AC_VI) ||
                (queue->qid == QID_AC_BE) ||
                (queue->qid == QID_AC_BK);
 
-       mutex_lock(&queue->status_lock);
 
        /*
-        * If the queue has been started, we must stop it temporarily
-        * to prevent any new frames to be queued on the device. If
-        * we are not dropping the pending frames, the queue must
-        * only be stopped in the software and not the hardware,
-        * otherwise the queue will never become empty on its own.
+        * If we are not supposed to drop any pending
+        * frames, this means we must force a start (=kick)
+        * to the queue to make sure the hardware will
+        * start transmitting.
         */
-       started = test_bit(QUEUE_STARTED, &queue->flags);
-       if (started) {
-               /*
-                * Pause the queue
-                */
-               rt2x00queue_pause_queue(queue);
-
-               /*
-                * If we are not supposed to drop any pending
-                * frames, this means we must force a start (=kick)
-                * to the queue to make sure the hardware will
-                * start transmitting.
-                */
-               if (!drop && tx_queue)
-                       queue->rt2x00dev->ops->lib->kick_queue(queue);
-       }
+       if (!drop && tx_queue)
+               queue->rt2x00dev->ops->lib->kick_queue(queue);
 
        /*
         * Check if driver supports flushing, if that is the case we can
@@ -1080,14 +1063,6 @@ void rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
        if (unlikely(!rt2x00queue_empty(queue)))
                rt2x00_warn(queue->rt2x00dev, "Queue %d failed to flush\n",
                            queue->qid);
-
-       /*
-        * Restore the queue to the previous status
-        */
-       if (started)
-               rt2x00queue_unpause_queue(queue);
-
-       mutex_unlock(&queue->status_lock);
 }
 EXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
 
index 88289873c0cfd754790192e670c6e13bb5736933..4e121627925d91db9de550b635b3fcece71c90e3 100644 (file)
@@ -523,7 +523,9 @@ static void rt2x00usb_watchdog_tx_dma(struct data_queue *queue)
        rt2x00_warn(queue->rt2x00dev, "TX queue %d DMA timed out, invoke forced forced reset\n",
                    queue->qid);
 
+       rt2x00queue_stop_queue(queue);
        rt2x00queue_flush_queue(queue, true);
+       rt2x00queue_start_queue(queue);
 }
 
 static int rt2x00usb_dma_timeout(struct data_queue *queue)
index 54d3ddfc988845cfa844b5c1d76c6a78ec62e4de..a5b69cb49012162580ef78291b696ce15abbeb94 100644 (file)
@@ -685,7 +685,7 @@ static void rt61pci_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, rt2x00_rf(rt2x00dev, RF2529));
        rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
-                         !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags));
+                         !rt2x00_has_cap_frame_type(rt2x00dev));
 
        /*
         * Configure the RX antenna.
@@ -813,10 +813,10 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
 
        if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                sel = antenna_sel_a;
-               lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
+               lna = rt2x00_has_cap_external_lna_a(rt2x00dev);
        } else {
                sel = antenna_sel_bg;
-               lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
+               lna = rt2x00_has_cap_external_lna_bg(rt2x00dev);
        }
 
        for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
@@ -836,7 +836,7 @@ static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev,
        else if (rt2x00_rf(rt2x00dev, RF2527))
                rt61pci_config_antenna_2x(rt2x00dev, ant);
        else if (rt2x00_rf(rt2x00dev, RF2529)) {
-               if (test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags))
+               if (rt2x00_has_cap_double_antenna(rt2x00dev))
                        rt61pci_config_antenna_2x(rt2x00dev, ant);
                else
                        rt61pci_config_antenna_2529(rt2x00dev, ant);
@@ -850,13 +850,13 @@ static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev,
        short lna_gain = 0;
 
        if (libconf->conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
+               if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
                        lna_gain += 14;
 
                rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
                lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1);
        } else {
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
+               if (rt2x00_has_cap_external_lna_a(rt2x00dev))
                        lna_gain += 14;
 
                rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom);
@@ -1054,14 +1054,14 @@ static void rt61pci_link_tuner(struct rt2x00_dev *rt2x00dev,
        if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                low_bound = 0x28;
                up_bound = 0x48;
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
+               if (rt2x00_has_cap_external_lna_a(rt2x00dev)) {
                        low_bound += 0x10;
                        up_bound += 0x10;
                }
        } else {
                low_bound = 0x20;
                up_bound = 0x40;
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) {
+               if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
                        low_bound += 0x10;
                        up_bound += 0x10;
                }
@@ -2578,7 +2578,7 @@ static int rt61pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
         * eeprom word.
         */
        if (rt2x00_rf(rt2x00dev, RF2529) &&
-           !test_bit(CAPABILITY_DOUBLE_ANTENNA, &rt2x00dev->cap_flags)) {
+           !rt2x00_has_cap_double_antenna(rt2x00dev)) {
                rt2x00dev->default_ant.rx =
                    ANTENNA_A + rt2x00_get_field16(eeprom, EEPROM_NIC_RX_FIXED);
                rt2x00dev->default_ant.tx =
@@ -2793,7 +2793,7 @@ static int rt61pci_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        spec->supported_bands = SUPPORT_BAND_2GHZ;
        spec->supported_rates = SUPPORT_RATE_CCK | SUPPORT_RATE_OFDM;
 
-       if (!test_bit(CAPABILITY_RF_SEQUENCE, &rt2x00dev->cap_flags)) {
+       if (!rt2x00_has_cap_rf_sequence(rt2x00dev)) {
                spec->num_channels = 14;
                spec->channels = rf_vals_noseq;
        } else {
index 1d3880e09a13eabb73e93c77b7af948ca12421f8..1baf9c896dcd6477efba878a1c0e407411635206 100644 (file)
@@ -595,8 +595,8 @@ static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev,
        switch (ant->rx) {
        case ANTENNA_HW_DIVERSITY:
                rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA_CONTROL, 2);
-               temp = !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags)
-                      && (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ);
+               temp = !rt2x00_has_cap_frame_type(rt2x00dev) &&
+                      (rt2x00dev->curr_band != IEEE80211_BAND_5GHZ);
                rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END, temp);
                break;
        case ANTENNA_A:
@@ -636,7 +636,7 @@ static void rt73usb_config_antenna_2x(struct rt2x00_dev *rt2x00dev,
 
        rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, 0);
        rt2x00_set_field8(&r4, BBP_R4_RX_FRAME_END,
-                         !test_bit(CAPABILITY_FRAME_TYPE, &rt2x00dev->cap_flags));
+                         !rt2x00_has_cap_frame_type(rt2x00dev));
 
        /*
         * Configure the RX antenna.
@@ -709,10 +709,10 @@ static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev,
 
        if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
                sel = antenna_sel_a;
-               lna = test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags);
+               lna = rt2x00_has_cap_external_lna_a(rt2x00dev);
        } else {
                sel = antenna_sel_bg;
-               lna = test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags);
+               lna = rt2x00_has_cap_external_lna_bg(rt2x00dev);
        }
 
        for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++)
@@ -740,7 +740,7 @@ static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev,
        short lna_gain = 0;
 
        if (libconf->conf->chandef.chan->band == IEEE80211_BAND_2GHZ) {
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags))
+               if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
                        lna_gain += 14;
 
                rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom);
@@ -930,7 +930,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
                low_bound = 0x28;
                up_bound = 0x48;
 
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
+               if (rt2x00_has_cap_external_lna_a(rt2x00dev)) {
                        low_bound += 0x10;
                        up_bound += 0x10;
                }
@@ -946,7 +946,7 @@ static void rt73usb_link_tuner(struct rt2x00_dev *rt2x00dev,
                        up_bound = 0x1c;
                }
 
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_BG, &rt2x00dev->cap_flags)) {
+               if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
                        low_bound += 0x14;
                        up_bound += 0x10;
                }
@@ -1661,7 +1661,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1)
        }
 
        if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
-               if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags)) {
+               if (rt2x00_has_cap_external_lna_a(rt2x00dev)) {
                        if (lna == 3 || lna == 2)
                                offset += 10;
                } else {
index fc207b268e4fd3db1926c494c8b470a6833c8102..a91506b12a627f26a084aef5e6dcb9a4213ac5e4 100644 (file)
@@ -1122,7 +1122,6 @@ static int rtl8180_probe(struct pci_dev *pdev,
        iounmap(priv->map);
 
  err_free_dev:
-       pci_set_drvdata(pdev, NULL);
        ieee80211_free_hw(dev);
 
  err_free_reg:
index 8bb4a9a01a1838e47d0d64b844503726999f3ff9..9a78e3daf74264fa13f446a4779d342ab6341488 100644 (file)
@@ -1613,6 +1613,35 @@ err_free:
 }
 EXPORT_SYMBOL(rtl_send_smps_action);
 
+void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       enum io_type iotype;
+
+       if (!is_hal_stop(rtlhal)) {
+               switch (operation) {
+               case SCAN_OPT_BACKUP:
+                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_IO_CMD,
+                                                     (u8 *)&iotype);
+                       break;
+               case SCAN_OPT_RESTORE:
+                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_IO_CMD,
+                                                     (u8 *)&iotype);
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Unknown Scan Backup operation.\n");
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL(rtl_phy_scan_operation_backup);
+
 /* There seem to be issues in mac80211 regarding when del ba frames can be
  * received. As a work around, we make a fake del_ba if we receive a ba_req;
  * however, rx_agg was opened to let mac80211 release some ba related
index 0e5fe0902daf6eb180a1da431ce54477e49486cb..0cd07420777a702afca02422cab06f16e06a9121 100644 (file)
@@ -114,7 +114,6 @@ void rtl_init_rfkill(struct ieee80211_hw *hw);
 void rtl_deinit_rfkill(struct ieee80211_hw *hw);
 
 void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb);
-void rtl_watch_dog_timer_callback(unsigned long data);
 void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
 
 bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
@@ -153,5 +152,6 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
 bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
 struct sk_buff *rtl_make_del_ba(struct ieee80211_hw *hw,
                                u8 *sa, u8 *bssid, u16 tid);
+void rtl_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation);
 
 #endif
index 838a1ed3f1942b9f3d56a122c2840548b38103c9..ae13fb94b2e8d7b82a259cdc830643cb2e144901 100644 (file)
@@ -1203,20 +1203,18 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 write, u8 pwrstate)
 
 static u16 efuse_get_current_size(struct ieee80211_hw *hw)
 {
-       int continual = true;
        u16 efuse_addr = 0;
        u8 hworden;
        u8 efuse_data, word_cnts;
 
-       while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
-              && (efuse_addr < EFUSE_MAX_SIZE)) {
-               if (efuse_data != 0xFF) {
-                       hworden = efuse_data & 0x0F;
-                       word_cnts = efuse_calculate_word_cnts(hworden);
-                       efuse_addr = efuse_addr + (word_cnts * 2) + 1;
-               } else {
-                       continual = false;
-               }
+       while (efuse_one_byte_read(hw, efuse_addr, &efuse_data) &&
+              efuse_addr < EFUSE_MAX_SIZE) {
+               if (efuse_data == 0xFF)
+                       break;
+
+               hworden = efuse_data & 0x0F;
+               word_cnts = efuse_calculate_word_cnts(hworden);
+               efuse_addr = efuse_addr + (word_cnts * 2) + 1;
        }
 
        return efuse_addr;
index 703f839af6ca0b4abefcfc754dc21eb3d13b2dac..0f494444bcd1d90b457b927d704bf77abe0592ca 100644 (file)
@@ -736,7 +736,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
 
        struct rtl_stats stats = {
                .signal = 0,
-               .noise = -98,
                .rate = 0,
        };
        int index = rtlpci->rx_ring[rx_queue_idx].idx;
@@ -2009,7 +2008,6 @@ fail2:
 fail1:
        if (hw)
                ieee80211_free_hw(hw);
-       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 
        return err;
@@ -2064,8 +2062,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
 
        rtl_pci_disable_aspm(hw);
 
-       pci_set_drvdata(pdev, NULL);
-
        ieee80211_free_hw(hw);
 }
 EXPORT_SYMBOL(rtl_pci_disconnect);
index b68cae3024fc851fec0b58359328a39e14e1e4da..e06971be7df77e047e8d869d046a126d0e987d14 100644 (file)
@@ -143,6 +143,7 @@ static void _rtl88ee_set_fw_clock_on(struct ieee80211_hw *hw,
                } else {
                        rtlhal->fw_clk_change_in_progress = false;
                        spin_unlock_bh(&rtlpriv->locks.fw_ps_lock);
+                       break;
                }
        }
 
index e655c04732251f18ee1121625df732ab8b8d8096..d67f9c731cc4600e57d774e7125d80c945e196b6 100644 (file)
@@ -1136,34 +1136,6 @@ void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
                                           &bw40_pwr[0], channel);
 }
 
-void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       enum io_type iotype;
-
-       if (!is_hal_stop(rtlhal)) {
-               switch (operation) {
-               case SCAN_OPT_BACKUP:
-                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-                       break;
-               case SCAN_OPT_RESTORE:
-                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-                       break;
-               default:
-                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                "Unknown Scan Backup operation.\n");
-                       break;
-               }
-       }
-}
-
 void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
index f1acd6d27e444ca4fac956d14190de873ef15d06..d4545f06e185fb0aea5f4889ce275a98de7d105b 100644 (file)
@@ -217,8 +217,6 @@ extern void rtl88e_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
 extern void rtl88e_phy_get_txpower_level(struct ieee80211_hw *hw,
                                         long *powerlevel);
 extern void rtl88e_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
-extern void rtl88e_phy_scan_operation_backup(struct ieee80211_hw *hw,
-                                            u8 operation);
 extern void rtl88e_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
 extern void rtl88e_phy_set_bw_mode(struct ieee80211_hw *hw,
                                   enum nl80211_channel_type ch_type);
index c254693a1e6ac3b9ce69e6e89947748e5331b48e..347af1e4f438e57cf2c37b8975169a7c92941681 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../core.h"
 #include "../pci.h"
+#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -244,7 +245,7 @@ static struct rtl_hal_ops rtl8188ee_hal_ops = {
        .set_bw_mode = rtl88e_phy_set_bw_mode,
        .switch_channel = rtl88e_phy_sw_chnl,
        .dm_watchdog = rtl88e_dm_watchdog,
-       .scan_operation_backup = rtl88e_phy_scan_operation_backup,
+       .scan_operation_backup = rtl_phy_scan_operation_backup,
        .set_rf_power_state = rtl88e_phy_set_rf_power_state,
        .led_control = rtl88ee_led_control,
        .set_desc = rtl88ee_set_desc,
index 68685a8982574e3e6b88c94379d00e4518a02601..aece6c9cccf1b50febc16049f4fd962c5c834aa7 100644 (file)
@@ -478,7 +478,6 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
 
        /*rx_status->qual = status->signal; */
        rx_status->signal = status->recvsignalpower + 10;
-       /*rx_status->noise = -status->noise; */
        if (status->packet_report_type == TX_REPORT2) {
                status->macid_valid_entry[0] =
                         GET_RX_RPT2_DESC_MACID_VALID_1(pdesc);
index d2d57a27a7c1636538003fc408b36c2bda24ce73..e9caa5d4cff0f910488cd4b22899ad9b5c84665a 100644 (file)
@@ -541,29 +541,6 @@ EXPORT_SYMBOL(rtl92c_dm_write_dig);
 
 static void rtl92c_dm_pwdb_monitor(struct ieee80211_hw *hw)
 {
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       long tmpentry_max_pwdb = 0, tmpentry_min_pwdb = 0xff;
-
-       u8 h2c_parameter[3] = { 0 };
-
-       return;
-
-       if (tmpentry_max_pwdb != 0) {
-               rtlpriv->dm.entry_max_undec_sm_pwdb = tmpentry_max_pwdb;
-       } else {
-               rtlpriv->dm.entry_max_undec_sm_pwdb = 0;
-       }
-
-       if (tmpentry_min_pwdb != 0xff) {
-               rtlpriv->dm.entry_min_undec_sm_pwdb = tmpentry_min_pwdb;
-       } else {
-               rtlpriv->dm.entry_min_undec_sm_pwdb = 0;
-       }
-
-       h2c_parameter[2] = (u8) (rtlpriv->dm.undec_sm_pwdb & 0xFF);
-       h2c_parameter[0] = 0;
-
-       rtl92c_fill_h2c_cmd(hw, H2C_RSSI_REPORT, 3, h2c_parameter);
 }
 
 void rtl92c_dm_init_edca_turbo(struct ieee80211_hw *hw)
@@ -673,7 +650,7 @@ static void rtl92c_dm_txpower_tracking_callback_thermalmeter(struct ieee80211_hw
        s8 cck_index = 0;
        int i;
        bool is2t = IS_92C_SERIAL(rtlhal->version);
-       s8 txpwr_level[2] = {0, 0};
+       s8 txpwr_level[3] = {0, 0, 0};
        u8 ofdm_min_index = 6, rf;
 
        rtlpriv->dm.txpower_trackinginit = true;
index 246e5352f2e15a850dbc7971c08bdbbcffbc7172..0c0e78263a665190aacf3d33d21fa87b99d4dd86 100644 (file)
@@ -592,36 +592,6 @@ long _rtl92c_phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(_rtl92c_phy_txpwr_idx_to_dbm);
 
-void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       enum io_type iotype;
-
-       if (!is_hal_stop(rtlhal)) {
-               switch (operation) {
-               case SCAN_OPT_BACKUP:
-                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-
-                       break;
-               case SCAN_OPT_RESTORE:
-                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-                       break;
-               default:
-                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                "Unknown Scan Backup operation\n");
-                       break;
-               }
-       }
-}
-EXPORT_SYMBOL(rtl92c_phy_scan_operation_backup);
-
 void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
                            enum nl80211_channel_type ch_type)
 {
index cec10d696492ab4055a2982ffadb1202494eea5e..e79dabe9ba1de77c757e91b46c6ba48ca6e9f12f 100644 (file)
@@ -39,9 +39,7 @@
 #define RT_CANNOT_IO(hw)               false
 #define HIGHPOWER_RADIOA_ARRAYLEN      22
 
-#define IQK_ADDA_REG_NUM               16
 #define MAX_TOLERANCE                  5
-#define        IQK_DELAY_TIME                  1
 
 #define        APK_BB_REG_NUM                  5
 #define        APK_AFE_REG_NUM                 16
@@ -205,8 +203,6 @@ void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
 void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
 bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
                                          long power_indbm);
-void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
-                                            u8 operation);
 void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
                                   enum nl80211_channel_type ch_type);
 void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
index 3cfa1bb0f47676853500b237a37aaeb9e49b1bad..fa24de43ce795d4588f002a93390ea8ffb5ee109 100644 (file)
@@ -152,8 +152,6 @@ enum version_8192c {
 #define IS_VENDOR_UMC_A_CUT(version)   ((IS_CHIP_VENDOR_UMC(version)) ? \
        ((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
 #define IS_CHIP_VER_B(version)  ((version & CHIP_VER_B) ? true : false)
-#define IS_VENDOR_UMC_A_CUT(version)   ((IS_CHIP_VENDOR_UMC(version)) ? \
-       ((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
 #define IS_92C_SERIAL(version)  ((version & CHIP_92C_BITMASK) ? true : false)
 #define IS_CHIP_VENDOR_UMC(version)            \
        ((version & CHIP_VENDOR_UMC) ? true : false)
index d5e3b704f9304a596bd943cfcbebd00db6559776..aeb268b190c6aa803618facefa899f455b3f0bad 100644 (file)
@@ -39,9 +39,7 @@
 #define RT_CANNOT_IO(hw)               false
 #define HIGHPOWER_RADIOA_ARRAYLEN      22
 
-#define IQK_ADDA_REG_NUM               16
 #define MAX_TOLERANCE                  5
-#define        IQK_DELAY_TIME                  1
 
 #define        APK_BB_REG_NUM                  5
 #define        APK_AFE_REG_NUM                 16
@@ -209,8 +207,6 @@ void rtl92c_phy_get_txpower_level(struct ieee80211_hw *hw,
 void rtl92c_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
 bool rtl92c_phy_update_txpower_dbm(struct ieee80211_hw *hw,
                                          long power_indbm);
-void rtl92c_phy_scan_operation_backup(struct ieee80211_hw *hw,
-                                            u8 operation);
 void rtl92c_phy_set_bw_mode(struct ieee80211_hw *hw,
                                   enum nl80211_channel_type ch_type);
 void rtl92c_phy_sw_chnl_callback(struct ieee80211_hw *hw);
@@ -226,7 +222,6 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                                          enum radio_path rfpath);
 bool rtl8192_phy_check_is_legal_rfpath(struct ieee80211_hw *hw,
                                              u32 rfpath);
-bool rtl92c_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
 bool rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
                                          enum rf_pwrstate rfpwr_state);
 void rtl92ce_phy_set_rf_on(struct ieee80211_hw *hw);
index bd4aef74c0567929849c24008ead104b5a11b15d..8922ecb47ad245cdb7d1b759f44c558f97e52173 100644 (file)
 #define        EEPROM_DEFAULT_TXPOWERLEVEL             0x22
 #define        EEPROM_DEFAULT_HT40_2SDIFF              0x0
 #define EEPROM_DEFAULT_HT20_DIFF               2
-#define        EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF      0x3
 #define EEPROM_DEFAULT_HT40_PWRMAXOFFSET       0
 #define EEPROM_DEFAULT_HT20_PWRMAXOFFSET       0
 
 
 #define        EEPROM_TXPWR_GROUP                      0x6F
 
-#define EEPROM_TSSI_A                          0x76
-#define EEPROM_TSSI_B                          0x77
-#define EEPROM_THERMAL_METER                   0x78
-
 #define EEPROM_CHANNELPLAN                     0x75
 
-#define RF_OPTION1                             0x79
-#define RF_OPTION2                             0x7A
-#define RF_OPTION3                             0x7B
-#define RF_OPTION4                             0x7C
-
 #define        STOPBECON                               BIT(6)
 #define        STOPHIGHT                               BIT(5)
 #define        STOPMGT                                 BIT(4)
 #define RSV_CTRL                               0x001C
 #define RD_CTRL                                        0x0524
 
-#define REG_USB_INFO                           0xFE17
-#define REG_USB_SPECIAL_OPTION                 0xFE55
-
-#define REG_USB_DMA_AGG_TO                     0xFE5B
-#define REG_USB_AGG_TO                         0xFE5C
-#define REG_USB_AGG_TH                         0xFE5D
-
 #define REG_USB_VID                            0xFE60
 #define REG_USB_PID                            0xFE62
 #define REG_USB_OPTIONAL                       0xFE64
 #define POLLING_LLT_THRESHOLD                  20
 #define POLLING_READY_TIMEOUT_COUNT            1000
 
-#define        MAX_MSS_DENSITY_2T                      0x13
-#define        MAX_MSS_DENSITY_1T                      0x0A
-
 #define EPROM_CMD_OPERATING_MODE_MASK  ((1<<7)|(1<<6))
 #define EPROM_CMD_CONFIG                       0x3
 #define EPROM_CMD_LOAD                         1
index 14203561b6ee5463d04841848a435cc9c51d59cd..b790320d20305427c5ed4fa5fd9f37d944957e31 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../core.h"
 #include "../pci.h"
+#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -219,7 +220,7 @@ static struct rtl_hal_ops rtl8192ce_hal_ops = {
        .set_bw_mode = rtl92c_phy_set_bw_mode,
        .switch_channel = rtl92c_phy_sw_chnl,
        .dm_watchdog = rtl92c_dm_watchdog,
-       .scan_operation_backup = rtl92c_phy_scan_operation_backup,
+       .scan_operation_backup = rtl_phy_scan_operation_backup,
        .set_rf_power_state = rtl92c_phy_set_rf_power_state,
        .led_control = rtl92ce_led_control,
        .set_desc = rtl92ce_set_desc,
index 6ad23b413eb3e6e4251e2242fc4dc912e3b7b6e5..52abf0a862fa70f26ec26ff62d2017f0a11ce5c9 100644 (file)
@@ -420,7 +420,6 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
 
        /*rx_status->qual = stats->signal; */
        rx_status->signal = stats->recvsignalpower + 10;
-       /*rx_status->noise = -stats->noise; */
 
        return true;
 }
index da4f587199ee5537cd20b0f62a326fd8157afb9a..393685390f3ee41f78a903d198eb51484654a55f 100644 (file)
@@ -32,6 +32,7 @@
 #include "../usb.h"
 #include "../ps.h"
 #include "../cam.h"
+#include "../stats.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -738,16 +739,6 @@ static u8 _rtl92c_evm_db_to_percentage(char value)
        return ret_val;
 }
 
-static long _rtl92c_translate_todbm(struct ieee80211_hw *hw,
-                                    u8 signal_strength_index)
-{
-       long signal_power;
-
-       signal_power = (long)((signal_strength_index + 1) >> 1);
-       signal_power -= 95;
-       return signal_power;
-}
-
 static long _rtl92c_signal_scale_mapping(struct ieee80211_hw *hw,
                long currsig)
 {
@@ -913,180 +904,6 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw,
                          (hw, total_rssi /= rf_rx_num));
 }
 
-static void _rtl92c_process_ui_rssi(struct ieee80211_hw *hw,
-               struct rtl_stats *pstats)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_phy *rtlphy = &(rtlpriv->phy);
-       u8 rfpath;
-       u32 last_rssi, tmpval;
-
-       if (pstats->packet_toself || pstats->packet_beacon) {
-               rtlpriv->stats.rssi_calculate_cnt++;
-               if (rtlpriv->stats.ui_rssi.total_num++ >=
-                   PHY_RSSI_SLID_WIN_MAX) {
-                       rtlpriv->stats.ui_rssi.total_num =
-                           PHY_RSSI_SLID_WIN_MAX;
-                       last_rssi =
-                           rtlpriv->stats.ui_rssi.elements[rtlpriv->
-                                                          stats.ui_rssi.index];
-                       rtlpriv->stats.ui_rssi.total_val -= last_rssi;
-               }
-               rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
-               rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.
-                                       index++] = pstats->signalstrength;
-               if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
-                       rtlpriv->stats.ui_rssi.index = 0;
-               tmpval = rtlpriv->stats.ui_rssi.total_val /
-                   rtlpriv->stats.ui_rssi.total_num;
-               rtlpriv->stats.signal_strength =
-                   _rtl92c_translate_todbm(hw, (u8) tmpval);
-               pstats->rssi = rtlpriv->stats.signal_strength;
-       }
-       if (!pstats->is_cck && pstats->packet_toself) {
-               for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
-                    rfpath++) {
-                       if (!rtl8192_phy_check_is_legal_rfpath(hw, rfpath))
-                               continue;
-                       if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
-                               rtlpriv->stats.rx_rssi_percentage[rfpath] =
-                                   pstats->rx_mimo_signalstrength[rfpath];
-                       }
-                       if (pstats->rx_mimo_signalstrength[rfpath] >
-                           rtlpriv->stats.rx_rssi_percentage[rfpath]) {
-                               rtlpriv->stats.rx_rssi_percentage[rfpath] =
-                                   ((rtlpriv->stats.
-                                     rx_rssi_percentage[rfpath] *
-                                     (RX_SMOOTH_FACTOR - 1)) +
-                                    (pstats->rx_mimo_signalstrength[rfpath])) /
-                                   (RX_SMOOTH_FACTOR);
-
-                               rtlpriv->stats.rx_rssi_percentage[rfpath] =
-                                   rtlpriv->stats.rx_rssi_percentage[rfpath] +
-                                   1;
-                       } else {
-                               rtlpriv->stats.rx_rssi_percentage[rfpath] =
-                                   ((rtlpriv->stats.
-                                     rx_rssi_percentage[rfpath] *
-                                     (RX_SMOOTH_FACTOR - 1)) +
-                                    (pstats->rx_mimo_signalstrength[rfpath])) /
-                                   (RX_SMOOTH_FACTOR);
-                       }
-               }
-       }
-}
-
-static void _rtl92c_update_rxsignalstatistics(struct ieee80211_hw *hw,
-                                              struct rtl_stats *pstats)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       int weighting = 0;
-
-       if (rtlpriv->stats.recv_signal_power == 0)
-               rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
-       if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
-               weighting = 5;
-       else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
-               weighting = (-5);
-       rtlpriv->stats.recv_signal_power =
-           (rtlpriv->stats.recv_signal_power * 5 +
-            pstats->recvsignalpower + weighting) / 6;
-}
-
-static void _rtl92c_process_pwdb(struct ieee80211_hw *hw,
-               struct rtl_stats *pstats)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       long undec_sm_pwdb = 0;
-
-       if (mac->opmode == NL80211_IFTYPE_ADHOC) {
-               return;
-       } else {
-               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
-       }
-       if (pstats->packet_toself || pstats->packet_beacon) {
-               if (undec_sm_pwdb < 0)
-                       undec_sm_pwdb = pstats->rx_pwdb_all;
-               if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
-                       undec_sm_pwdb = (((undec_sm_pwdb) *
-                             (RX_SMOOTH_FACTOR - 1)) +
-                            (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-                       undec_sm_pwdb += 1;
-               } else {
-                       undec_sm_pwdb = (((undec_sm_pwdb) *
-                             (RX_SMOOTH_FACTOR - 1)) +
-                            (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
-               }
-               rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
-               _rtl92c_update_rxsignalstatistics(hw, pstats);
-       }
-}
-
-static void _rtl92c_process_LINK_Q(struct ieee80211_hw *hw,
-                                            struct rtl_stats *pstats)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       u32 last_evm = 0, n_stream, tmpval;
-
-       if (pstats->signalquality != 0) {
-               if (pstats->packet_toself || pstats->packet_beacon) {
-                       if (rtlpriv->stats.LINK_Q.total_num++ >=
-                           PHY_LINKQUALITY_SLID_WIN_MAX) {
-                               rtlpriv->stats.LINK_Q.total_num =
-                                   PHY_LINKQUALITY_SLID_WIN_MAX;
-                               last_evm =
-                                   rtlpriv->stats.LINK_Q.elements
-                                   [rtlpriv->stats.LINK_Q.index];
-                               rtlpriv->stats.LINK_Q.total_val -=
-                                   last_evm;
-                       }
-                       rtlpriv->stats.LINK_Q.total_val +=
-                           pstats->signalquality;
-                       rtlpriv->stats.LINK_Q.elements
-                          [rtlpriv->stats.LINK_Q.index++] =
-                           pstats->signalquality;
-                       if (rtlpriv->stats.LINK_Q.index >=
-                           PHY_LINKQUALITY_SLID_WIN_MAX)
-                               rtlpriv->stats.LINK_Q.index = 0;
-                       tmpval = rtlpriv->stats.LINK_Q.total_val /
-                           rtlpriv->stats.LINK_Q.total_num;
-                       rtlpriv->stats.signal_quality = tmpval;
-                       rtlpriv->stats.last_sigstrength_inpercent = tmpval;
-                       for (n_stream = 0; n_stream < 2;
-                            n_stream++) {
-                               if (pstats->RX_SIGQ[n_stream] != -1) {
-                                       if (!rtlpriv->stats.RX_EVM[n_stream]) {
-                                               rtlpriv->stats.RX_EVM[n_stream]
-                                                = pstats->RX_SIGQ[n_stream];
-                                       }
-                                       rtlpriv->stats.RX_EVM[n_stream] =
-                                           ((rtlpriv->stats.RX_EVM
-                                           [n_stream] *
-                                           (RX_SMOOTH_FACTOR - 1)) +
-                                           (pstats->RX_SIGQ
-                                           [n_stream] * 1)) /
-                                           (RX_SMOOTH_FACTOR);
-                               }
-                       }
-               }
-       } else {
-               ;
-       }
-}
-
-static void _rtl92c_process_phyinfo(struct ieee80211_hw *hw,
-                                    u8 *buffer,
-                                    struct rtl_stats *pcurrent_stats)
-{
-       if (!pcurrent_stats->packet_matchbssid &&
-           !pcurrent_stats->packet_beacon)
-               return;
-       _rtl92c_process_ui_rssi(hw, pcurrent_stats);
-       _rtl92c_process_pwdb(hw, pcurrent_stats);
-       _rtl92c_process_LINK_Q(hw, pcurrent_stats);
-}
-
 void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw,
                                               struct sk_buff *skb,
                                               struct rtl_stats *pstats,
@@ -1123,5 +940,5 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        _rtl92c_query_rxphystatus(hw, pstats, pdesc, p_drvinfo,
                                   packet_matchbssid, packet_toself,
                                   packet_beacon);
-       _rtl92c_process_phyinfo(hw, tmp_buf, pstats);
+       rtl_process_phyinfo(hw, tmp_buf, pstats);
 }
index 2bd5985262171bfdfa81de5494a4ef9640d72cc5..9936de716ad58929e50dc0e6f02fca77f5efee68 100644 (file)
@@ -31,6 +31,7 @@
 #include "../core.h"
 #include "../usb.h"
 #include "../efuse.h"
+#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -117,7 +118,7 @@ static struct rtl_hal_ops rtl8192cu_hal_ops = {
        .set_bw_mode = rtl92c_phy_set_bw_mode,
        .switch_channel = rtl92c_phy_sw_chnl,
        .dm_watchdog = rtl92c_dm_watchdog,
-       .scan_operation_backup = rtl92c_phy_scan_operation_backup,
+       .scan_operation_backup = rtl_phy_scan_operation_backup,
        .set_rf_power_state = rtl92cu_phy_set_rf_power_state,
        .led_control = rtl92cu_led_control,
        .enable_hw_sec = rtl92cu_enable_hw_security_config,
index 763cf1defab5b4027b22604c3771e4c8465a4405..04c7e57dbce2f5165626c15344c23b348f58abbf 100644 (file)
@@ -349,7 +349,6 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
        }
        /*rx_status->qual = stats->signal; */
        rx_status->signal = stats->rssi + 10;
-       /*rx_status->noise = -stats->noise; */
        return true;
 }
 
@@ -364,7 +363,6 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
        u8 *rxdesc;
        struct rtl_stats stats = {
                .signal = 0,
-               .noise = -98,
                .rate = 0,
        };
        struct rx_fwinfo_92c *p_drvinfo;
index f700f7a614b264691ce8be3cfb79f219f5edd9ad..7908e1c85819409091abd71ba5b57595947ff909 100644 (file)
@@ -840,9 +840,9 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
        bool internal_pa = false;
        long ele_a = 0, ele_d, temp_cck, val_x, value32;
        long val_y, ele_c = 0;
-       u8 ofdm_index[2];
+       u8 ofdm_index[3];
        s8 cck_index = 0;
-       u8 ofdm_index_old[2] = {0, 0};
+       u8 ofdm_index_old[3] = {0, 0, 0};
        s8 cck_index_old = 0;
        u8 index;
        int i;
@@ -1118,6 +1118,10 @@ static void rtl92d_dm_txpower_tracking_callback_thermalmeter(
                                 val_x, val_y, ele_a, ele_c, ele_d,
                                 val_x, val_y);
 
+                       if (cck_index >= CCK_TABLE_SIZE)
+                               cck_index = CCK_TABLE_SIZE - 1;
+                       if (cck_index < 0)
+                               cck_index = 0;
                        if (rtlhal->current_bandtype == BAND_ON_2_4G) {
                                /* Adjust CCK according to IQK result */
                                if (!rtlpriv->dm.cck_inch14) {
index 7dd8f6de0550f4f03424472f8926577a23b513c9..c4a7db9135d6e3850dcd8490e5e9165807178b64 100644 (file)
@@ -1194,25 +1194,7 @@ void rtl92d_linked_set_reg(struct ieee80211_hw *hw)
  * mac80211 will send pkt when scan */
 void rtl92de_set_qos(struct ieee80211_hw *hw, int aci)
 {
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
        rtl92d_dm_init_edca_turbo(hw);
-       return;
-       switch (aci) {
-       case AC1_BK:
-               rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
-               break;
-       case AC0_BE:
-               break;
-       case AC2_VI:
-               rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
-               break;
-       case AC3_VO:
-               rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
-               break;
-       default:
-               RT_ASSERT(false, "invalid aci: %d !\n", aci);
-               break;
-       }
 }
 
 void rtl92de_enable_interrupt(struct ieee80211_hw *hw)
index 840bac5fa2f80bfa224bd5470b6562585aec0a02..13196cc4b1d380279e7ce3096b5861ba14087b81 100644 (file)
@@ -1022,34 +1022,6 @@ void rtl92d_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
        rtl92d_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel);
 }
 
-void rtl92d_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       enum io_type iotype;
-
-       if (!is_hal_stop(rtlhal)) {
-               switch (operation) {
-               case SCAN_OPT_BACKUP:
-                       rtlhal->current_bandtypebackup =
-                                                rtlhal->current_bandtype;
-                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-                       break;
-               case SCAN_OPT_RESTORE:
-                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-                       break;
-               default:
-                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                "Unknown Scan Backup operation\n");
-                       break;
-               }
-       }
-}
-
 void rtl92d_phy_set_bw_mode(struct ieee80211_hw *hw,
                            enum nl80211_channel_type ch_type)
 {
index f074952bf25c53c3fcd6dbf6ae22f0a1f8de9316..bef3040555dd56f11c075fd896e4a5d5d0e34252 100644 (file)
@@ -39,9 +39,7 @@
 #define RT_CANNOT_IO(hw)                       false
 #define HIGHPOWER_RADIOA_ARRAYLEN              22
 
-#define IQK_ADDA_REG_NUM                       16
 #define MAX_TOLERANCE                          5
-#define        IQK_DELAY_TIME                          1
 
 #define        APK_BB_REG_NUM                          5
 #define        APK_AFE_REG_NUM                         16
@@ -144,8 +142,6 @@ extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
                                                 enum radio_path rfpath);
 extern void rtl92d_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
 extern void rtl92d_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel);
-extern void rtl92d_phy_scan_operation_backup(struct ieee80211_hw *hw,
-                                            u8 operation);
 extern void rtl92d_phy_set_bw_mode(struct ieee80211_hw *hw,
                                   enum nl80211_channel_type ch_type);
 extern u8 rtl92d_phy_sw_chnl(struct ieee80211_hw *hw);
@@ -173,6 +169,5 @@ void rtl92d_acquire_cckandrw_pagea_ctl(struct ieee80211_hw *hw,
                                       unsigned long *flag);
 u8 rtl92d_get_rightchnlplace_for_iqk(u8 chnl);
 void rtl92d_phy_reload_iqk_setting(struct ieee80211_hw *hw, u8 channel);
-void rtl92d_phy_iq_calibrate(struct ieee80211_hw *hw);
 
 #endif
index c18c04bf0c13e4ac98c050f205bf35ddd7d7d14a..edab5a5351b52a814ec10833109666309279e2b1 100644 (file)
@@ -30,6 +30,7 @@
 #include "../wifi.h"
 #include "../core.h"
 #include "../pci.h"
+#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -236,7 +237,7 @@ static struct rtl_hal_ops rtl8192de_hal_ops = {
        .set_bw_mode = rtl92d_phy_set_bw_mode,
        .switch_channel = rtl92d_phy_sw_chnl,
        .dm_watchdog = rtl92d_dm_watchdog,
-       .scan_operation_backup = rtl92d_phy_scan_operation_backup,
+       .scan_operation_backup = rtl_phy_scan_operation_backup,
        .set_rf_power_state = rtl92d_phy_set_rf_power_state,
        .led_control = rtl92de_led_control,
        .set_desc = rtl92de_set_desc,
index b8ec718a0fabbf348df84820fa530f8e28031699..945ddecf90c9a3b6c6bcd916c3c1d293ac51dc15 100644 (file)
@@ -526,7 +526,6 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
        }
        /*rx_status->qual = stats->signal; */
        rx_status->signal = stats->rssi + 10;
-       /*rx_status->noise = -stats->noise; */
        return true;
 }
 
index 84d1181795b8aeba6ff9d3d0d0245f75e596933f..c81c8359194007893412cd3d55f1da054b1bc645 100644 (file)
 #define        EXT_IMEM_CODE_DONE                      BIT(2)
 #define        IMEM_CHK_RPT                            BIT(1)
 #define        IMEM_CODE_DONE                          BIT(0)
-#define        IMEM_CODE_DONE                          BIT(0)
-#define        IMEM_CHK_RPT                            BIT(1)
 #define        EMEM_CODE_DONE                          BIT(2)
 #define        EMEM_CHK_RPT                            BIT(3)
-#define        DMEM_CODE_DONE                          BIT(4)
 #define        IMEM_RDY                                BIT(5)
-#define        BASECHG                                 BIT(6)
-#define        FWRDY                                   BIT(7)
 #define        LOAD_FW_READY                           (IMEM_CODE_DONE | \
                                                IMEM_CHK_RPT | \
                                                EMEM_CODE_DONE | \
index c7095118de6e8c23bbfd0ee5727fc353969db9fd..222d2e792ca6d259885fa6da3a8ad792bbb338ad 100644 (file)
@@ -330,7 +330,6 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
 
        /*rx_status->qual = stats->signal; */
        rx_status->signal = stats->rssi + 10;
-       /*rx_status->noise = -stats->noise; */
 
        return true;
 }
index eafbb18dd48e69a44d67cd60f171b5915662e58c..5d318a85eda4047100eeec7c5297412c15d615fd 100644 (file)
@@ -934,35 +934,6 @@ static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
        return pwrout_dbm;
 }
 
-void rtl8723ae_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       enum io_type iotype;
-
-       if (!is_hal_stop(rtlhal)) {
-               switch (operation) {
-               case SCAN_OPT_BACKUP:
-                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-
-                       break;
-               case SCAN_OPT_RESTORE:
-                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
-                       rtlpriv->cfg->ops->set_hw_reg(hw,
-                                                     HW_VAR_IO_CMD,
-                                                     (u8 *)&iotype);
-                       break;
-               default:
-                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                "Unknown Scan Backup operation.\n");
-                       break;
-               }
-       }
-}
-
 void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
index e7a59eba351adf85cd951f28377517b8347a6807..3d8f9e3aad76ccef40632c44bbb24004cc57c999 100644 (file)
@@ -205,8 +205,6 @@ extern void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw,
                                            u8 channel);
 extern bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw,
                                             long power_indbm);
-extern void rtl8723ae_phy_scan_operation_backup(struct ieee80211_hw *hw,
-                                               u8 operation);
 extern void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
 extern void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw,
                                      enum nl80211_channel_type ch_type);
index d9ee2efffe5ffb1284335352eed2e13ab8e4df96..62b204faf773f74b1137aa2ada315375357268e8 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "../core.h"
 #include "../pci.h"
+#include "../base.h"
 #include "reg.h"
 #include "def.h"
 #include "phy.h"
@@ -220,7 +221,7 @@ static struct rtl_hal_ops rtl8723ae_hal_ops = {
        .set_bw_mode = rtl8723ae_phy_set_bw_mode,
        .switch_channel = rtl8723ae_phy_sw_chnl,
        .dm_watchdog = rtl8723ae_dm_watchdog,
-       .scan_operation_backup = rtl8723ae_phy_scan_operation_backup,
+       .scan_operation_backup = rtl_phy_scan_operation_backup,
        .set_rf_power_state = rtl8723ae_phy_set_rf_power_state,
        .led_control = rtl8723ae_led_control,
        .set_desc = rtl8723ae_set_desc,
index bcd82a1020a5bebd7104467594ffefc47bf28eba..50b7be3f3a605673756e543e456324993c66980d 100644 (file)
@@ -359,7 +359,6 @@ bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
 
        /*rx_status->qual = status->signal; */
        rx_status->signal = status->recvsignalpower + 10;
-       /*rx_status->noise = -status->noise; */
 
        return true;
 }
index e56778cac9bfce39e56d5aa239e34f2fb1135ffb..6e2b5c5c83c8d21234ee013c802d7af317f6db8c 100644 (file)
@@ -455,7 +455,6 @@ static void _rtl_usb_rx_process_agg(struct ieee80211_hw *hw,
        struct ieee80211_rx_status rx_status = {0};
        struct rtl_stats stats = {
                .signal = 0,
-               .noise = -98,
                .rate = 0,
        };
 
@@ -498,7 +497,6 @@ static void _rtl_usb_rx_process_noagg(struct ieee80211_hw *hw,
        struct ieee80211_rx_status rx_status = {0};
        struct rtl_stats stats = {
                .signal = 0,
-               .noise = -98,
                .rate = 0,
        };
 
@@ -582,12 +580,15 @@ static void _rtl_rx_work(unsigned long param)
 static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr,
                                        unsigned int len)
 {
+#if NET_IP_ALIGN != 0
        unsigned int padding = 0;
+#endif
 
        /* make function no-op when possible */
        if (NET_IP_ALIGN == 0 || len < sizeof(*hdr))
                return 0;
 
+#if NET_IP_ALIGN != 0
        /* alignment calculation as in lbtf_rx() / carl9170_rx_copy_data() */
        /* TODO: deduplicate common code, define helper function instead? */
 
@@ -608,6 +609,7 @@ static unsigned int _rtl_rx_get_padding(struct ieee80211_hdr *hdr,
                padding ^= NET_IP_ALIGN;
 
        return padding;
+#endif
 }
 
 #define __RADIO_TAP_SIZE_RSV   32
index cc03e7c87cbe739c9d762a6462b1b0b6f21e1795..96763dcff5ae19283b5962f17efeffdac705e8cf 100644 (file)
@@ -192,8 +192,6 @@ enum hardware_type {
 (IS_HARDWARE_TYPE_8192DE(rtlhal) || IS_HARDWARE_TYPE_8192DU(rtlhal))
 #define        IS_HARDWARE_TYPE_8723(rtlhal)                   \
 (IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal))
-#define IS_HARDWARE_TYPE_8723U(rtlhal)                 \
-       (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U)
 
 #define RX_HAL_IS_CCK_RATE(_pdesc)\
        (_pdesc->rxmcs == DESC92_RATE1M ||              \
index 8fec4ed36ac2ecae7824d00e6e79aa5b5b5880c0..477a206c098ef7157a53fba397d002062d5afbc0 100644 (file)
@@ -1,6 +1,6 @@
 menuconfig WL1251
        tristate "TI wl1251 driver support"
-       depends on MAC80211 && GENERIC_HARDIRQS
+       depends on MAC80211
        select FW_LOADER
        select CRC7
        ---help---
index c7dc6feab2ff38cd2bbbef713ca4b2c0113a4b51..1342f81e683d1498bb16d5904d032009244bed58 100644 (file)
@@ -243,7 +243,7 @@ static int wl1251_spi_probe(struct spi_device *spi)
        struct wl1251 *wl;
        int ret;
 
-       pdata = spi->dev.platform_data;
+       pdata = dev_get_platdata(&spi->dev);
        if (!pdata) {
                wl1251_error("no platform data");
                return -ENODEV;
index fd02060038de6479051accfa7b63c1993193315b..2c3bd1bff3f68e08de48b42101c52606a472fa6a 100644 (file)
@@ -424,8 +424,8 @@ void wl1251_disable_interrupts(struct wl1251 *wl);
 #define CHIP_ID_1271_PG10                 (0x4030101)
 #define CHIP_ID_1271_PG20                 (0x4030111)
 
-#define WL1251_FW_NAME "wl1251-fw.bin"
-#define WL1251_NVS_NAME "wl1251-nvs.bin"
+#define WL1251_FW_NAME "ti-connectivity/wl1251-fw.bin"
+#define WL1251_NVS_NAME "ti-connectivity/wl1251-nvs.bin"
 
 #define WL1251_POWER_ON_SLEEP 10 /* in milliseconds */
 
index 1c627da85083949c9dd9837e09b53b5ca8a9ac74..591526b991547281e4e04f341e071d57c84d58e2 100644 (file)
@@ -1704,7 +1704,7 @@ static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
 static int wl12xx_setup(struct wl1271 *wl)
 {
        struct wl12xx_priv *priv = wl->priv;
-       struct wlcore_platdev_data *pdev_data = wl->pdev->dev.platform_data;
+       struct wlcore_platdev_data *pdev_data = dev_get_platdata(&wl->pdev->dev);
        struct wl12xx_platform_data *pdata = pdev_data->pdata;
 
        wl->rtable = wl12xx_rtable;
index 7aa0eb848c5a2c83cc93f120f96567cd04d5d0fa..d0daca1d23bc55154432d2a031feff4ee51b15e4 100644 (file)
@@ -623,6 +623,18 @@ static const int wl18xx_rtable[REG_TABLE_LEN] = {
        [REG_RAW_FW_STATUS_ADDR]        = WL18XX_FW_STATUS_ADDR,
 };
 
+static const struct wl18xx_clk_cfg wl18xx_clk_table_coex[NUM_CLOCK_CONFIGS] = {
+       [CLOCK_CONFIG_16_2_M]   = { 8,  121, 0, 0, false },
+       [CLOCK_CONFIG_16_368_M] = { 8,  120, 0, 0, false },
+       [CLOCK_CONFIG_16_8_M]   = { 8,  117, 0, 0, false },
+       [CLOCK_CONFIG_19_2_M]   = { 10, 128, 0, 0, false },
+       [CLOCK_CONFIG_26_M]     = { 11, 104, 0, 0, false },
+       [CLOCK_CONFIG_32_736_M] = { 8,  120, 0, 0, false },
+       [CLOCK_CONFIG_33_6_M]   = { 8,  117, 0, 0, false },
+       [CLOCK_CONFIG_38_468_M] = { 10, 128, 0, 0, false },
+       [CLOCK_CONFIG_52_M]     = { 11, 104, 0, 0, false },
+};
+
 static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
        [CLOCK_CONFIG_16_2_M]   = { 7,  104,  801, 4,  true },
        [CLOCK_CONFIG_16_368_M] = { 9,  132, 3751, 4,  true },
@@ -704,6 +716,23 @@ static int wl18xx_set_clk(struct wl1271 *wl)
                     wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q,
                     wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit");
 
+       /* coex PLL configuration */
+       ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_N,
+                                  wl18xx_clk_table_coex[clk_freq].n);
+       if (ret < 0)
+               goto out;
+
+       ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_M,
+                                  wl18xx_clk_table_coex[clk_freq].m);
+       if (ret < 0)
+               goto out;
+
+       /* bypass the swallowing logic */
+       ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
+                                  PLLSH_COEX_PLL_SWALLOW_EN_VAL1);
+       if (ret < 0)
+               goto out;
+
        ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N,
                                   wl18xx_clk_table[clk_freq].n);
        if (ret < 0)
@@ -745,6 +774,30 @@ static int wl18xx_set_clk(struct wl1271 *wl)
                                           PLLSH_WCS_PLL_SWALLOW_EN_VAL2);
        }
 
+       /* choose WCS PLL */
+       ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_SEL,
+                                  PLLSH_WL_PLL_SEL_WCS_PLL);
+       if (ret < 0)
+               goto out;
+
+       /* enable both PLLs */
+       ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL1);
+       if (ret < 0)
+               goto out;
+
+       udelay(1000);
+
+       /* disable coex PLL */
+       ret = wl18xx_top_reg_write(wl, PLLSH_WL_PLL_EN, PLLSH_WL_PLL_EN_VAL2);
+       if (ret < 0)
+               goto out;
+
+       /* reset the swallowing logic */
+       ret = wl18xx_top_reg_write(wl, PLLSH_COEX_PLL_SWALLOW_EN,
+                                  PLLSH_COEX_PLL_SWALLOW_EN_VAL2);
+       if (ret < 0)
+               goto out;
+
 out:
        return ret;
 }
@@ -1175,16 +1228,48 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl,
        }
 }
 
+static const char *wl18xx_rdl_name(enum wl18xx_rdl_num rdl_num)
+{
+       switch (rdl_num) {
+       case RDL_1_HP:
+               return "183xH";
+       case RDL_2_SP:
+               return "183x or 180x";
+       case RDL_3_HP:
+               return "187xH";
+       case RDL_4_SP:
+               return "187x";
+       case RDL_5_SP:
+               return "RDL11 - Not Supported";
+       case RDL_6_SP:
+               return "180xD";
+       case RDL_7_SP:
+               return "RDL13 - Not Supported (1893Q)";
+       case RDL_8_SP:
+               return "18xxQ";
+       case RDL_NONE:
+               return "UNTRIMMED";
+       default:
+               return "UNKNOWN";
+       }
+}
+
 static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
 {
        u32 fuse;
-       s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0;
+       s8 rom = 0, metal = 0, pg_ver = 0, rdl_ver = 0, package_type = 0;
        int ret;
 
        ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]);
        if (ret < 0)
                goto out;
 
+       ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_2_3, &fuse);
+       if (ret < 0)
+               goto out;
+
+       package_type = (fuse >> WL18XX_PACKAGE_TYPE_OFFSET) & 1;
+
        ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse);
        if (ret < 0)
                goto out;
@@ -1192,7 +1277,7 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
        pg_ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET;
        rom = (fuse & WL18XX_ROM_VER_MASK) >> WL18XX_ROM_VER_OFFSET;
 
-       if (rom <= 0xE)
+       if ((rom <= 0xE) && (package_type == WL18XX_PACKAGE_TYPE_WSP))
                metal = (fuse & WL18XX_METAL_VER_MASK) >>
                        WL18XX_METAL_VER_OFFSET;
        else
@@ -1204,11 +1289,9 @@ static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver)
                goto out;
 
        rdl_ver = (fuse & WL18XX_RDL_VER_MASK) >> WL18XX_RDL_VER_OFFSET;
-       if (rdl_ver > RDL_MAX)
-               rdl_ver = RDL_NONE;
 
-       wl1271_info("wl18xx HW: RDL %d, %s, PG %x.%x (ROM %x)",
-                   rdl_ver, rdl_names[rdl_ver], pg_ver, metal, rom);
+       wl1271_info("wl18xx HW: %s, PG %d.%d (ROM 0x%x)",
+                   wl18xx_rdl_name(rdl_ver), pg_ver, metal, rom);
 
        if (ver)
                *ver = pg_ver;
index 05dd8bad27469389e0e5ff3cf713fab083d348d5..a433a75f3cd7c85d51f67cfb8d03830e35c041be 100644 (file)
 #define PLATFORM_DETECTION             0xA0E3E0
 #define OCS_EN                         0xA02080
 #define PRIMARY_CLK_DETECT             0xA020A6
+#define PLLSH_COEX_PLL_N               0xA02384
+#define PLLSH_COEX_PLL_M               0xA02382
+#define PLLSH_COEX_PLL_SWALLOW_EN      0xA0238E
+#define PLLSH_WL_PLL_SEL               0xA02398
+
 #define PLLSH_WCS_PLL_N                        0xA02362
 #define PLLSH_WCS_PLL_M                        0xA02360
 #define PLLSH_WCS_PLL_Q_FACTOR_CFG_1   0xA02364
 #define PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK      0xFFFF
 #define PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK      0x000F
 
+#define PLLSH_WL_PLL_EN_VAL1           0x7
+#define PLLSH_WL_PLL_EN_VAL2           0x2
+#define PLLSH_COEX_PLL_SWALLOW_EN_VAL1 0x2
+#define PLLSH_COEX_PLL_SWALLOW_EN_VAL2 0x11
+
 #define PLLSH_WCS_PLL_SWALLOW_EN_VAL1  0x1
 #define PLLSH_WCS_PLL_SWALLOW_EN_VAL2  0x12
 
+#define PLLSH_WL_PLL_SEL_WCS_PLL       0x0
+#define PLLSH_WL_PLL_SEL_COEX_PLL      0x1
+
 #define WL18XX_REG_FUSE_DATA_1_3       0xA0260C
 #define WL18XX_PG_VER_MASK             0x70
 #define WL18XX_PG_VER_OFFSET           4
-#define WL18XX_ROM_VER_MASK            0x3
-#define WL18XX_ROM_VER_OFFSET          0
+#define WL18XX_ROM_VER_MASK            0x3e00
+#define WL18XX_ROM_VER_OFFSET          9
 #define WL18XX_METAL_VER_MASK          0xC
 #define WL18XX_METAL_VER_OFFSET                2
 #define WL18XX_NEW_METAL_VER_MASK      0x180
 #define WL18XX_NEW_METAL_VER_OFFSET    7
 
+#define WL18XX_PACKAGE_TYPE_OFFSET     13
+#define WL18XX_PACKAGE_TYPE_WSP                0
+
 #define WL18XX_REG_FUSE_DATA_2_3       0xA02614
 #define WL18XX_RDL_VER_MASK            0x1f00
 #define WL18XX_RDL_VER_OFFSET          8
@@ -201,24 +217,21 @@ enum {
        NUM_BOARD_TYPES,
 };
 
-enum {
+enum wl18xx_rdl_num {
        RDL_NONE        = 0,
        RDL_1_HP        = 1,
        RDL_2_SP        = 2,
        RDL_3_HP        = 3,
        RDL_4_SP        = 4,
+       RDL_5_SP        = 0x11,
+       RDL_6_SP        = 0x12,
+       RDL_7_SP        = 0x13,
+       RDL_8_SP        = 0x14,
 
        _RDL_LAST,
        RDL_MAX = _RDL_LAST - 1,
 };
 
-static const char * const rdl_names[] = {
-       [RDL_NONE]      = "",
-       [RDL_1_HP]      = "1853 SISO",
-       [RDL_2_SP]      = "1857 MIMO",
-       [RDL_3_HP]      = "1893 SISO",
-       [RDL_4_SP]      = "1897 MIMO",
-};
 
 /* FPGA_SPARE_1 register - used to change the PHY ATPG clock at boot time */
 #define WL18XX_PHY_FPGA_SPARE_1                0x8093CA40
index 2b832825c3d41130e3ed1c4802dc5c1244275634..7c099542b214796baa995b548f8453f339fde35f 100644 (file)
@@ -1,6 +1,6 @@
 config WLCORE
        tristate "TI wlcore support"
-       depends on WL_TI && GENERIC_HARDIRQS && MAC80211
+       depends on WL_TI && MAC80211
        select FW_LOADER
        ---help---
          This module contains the main code for TI WLAN chips.  It abstracts
index c9e060795d13760befc72a9190b008b65b6f1b41..9e5416f8764d13899cc7de963a71a58bf7b1b0e4 100644 (file)
@@ -1126,6 +1126,8 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        u16 template_id_2_4 = wl->scan_templ_id_2_4;
        u16 template_id_5 = wl->scan_templ_id_5;
 
+       wl1271_debug(DEBUG_SCAN, "build probe request band %d", band);
+
        skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len,
                                     ie_len);
        if (!skb) {
@@ -1135,8 +1137,6 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        if (ie_len)
                memcpy(skb_put(skb, ie_len), ie, ie_len);
 
-       wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
-
        if (sched_scan &&
            (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) {
                template_id_2_4 = wl->sched_scan_templ_id_2_4;
@@ -1172,7 +1172,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
        if (!skb)
                goto out;
 
-       wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
+       wl1271_debug(DEBUG_SCAN, "set ap probe request template");
 
        rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[wlvif->band]);
        if (wlvif->band == IEEE80211_BAND_2GHZ)
@@ -1607,33 +1607,43 @@ out:
 
 static int wlcore_get_reg_conf_ch_idx(enum ieee80211_band band, u16 ch)
 {
-       int idx = -1;
-
+       /*
+        * map the given band/channel to the respective predefined
+        * bit expected by the fw
+        */
        switch (band) {
-       case IEEE80211_BAND_5GHZ:
-               if (ch >= 8 && ch <= 16)
-                       idx = ((ch-8)/4 + 18);
-               else if (ch >= 34 && ch <= 64)
-                       idx = ((ch-34)/2 + 3 + 18);
-               else if (ch >= 100 && ch <= 140)
-                       idx = ((ch-100)/4 + 15 + 18);
-               else if (ch >= 149 && ch <= 165)
-                       idx = ((ch-149)/4 + 26 + 18);
-               else
-                       idx = -1;
-               break;
        case IEEE80211_BAND_2GHZ:
+               /* channels 1..14 are mapped to 0..13 */
                if (ch >= 1 && ch <= 14)
-                       idx = ch - 1;
-               else
-                       idx = -1;
+                       return ch - 1;
+               break;
+       case IEEE80211_BAND_5GHZ:
+               switch (ch) {
+               case 8 ... 16:
+                       /* channels 8,12,16 are mapped to 18,19,20 */
+                       return 18 + (ch-8)/4;
+               case 34 ... 48:
+                       /* channels 34,36..48 are mapped to 21..28 */
+                       return 21 + (ch-34)/2;
+               case 52 ... 64:
+                       /* channels 52,56..64 are mapped to 29..32 */
+                       return 29 + (ch-52)/4;
+               case 100 ... 140:
+                       /* channels 100,104..140 are mapped to 33..43 */
+                       return 33 + (ch-100)/4;
+               case 149 ... 165:
+                       /* channels 149,153..165 are mapped to 44..48 */
+                       return 44 + (ch-149)/4;
+               default:
+                       break;
+               }
                break;
        default:
-               wl1271_error("get reg conf ch idx - unknown band: %d",
-                            (int)band);
+               break;
        }
 
-       return idx;
+       wl1271_error("%s: unknown band/channel: %d/%d", __func__, band, ch);
+       return -1;
 }
 
 void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
@@ -1646,7 +1656,7 @@ void wlcore_set_pending_regdomain_ch(struct wl1271 *wl, u16 channel,
 
        ch_bit_idx = wlcore_get_reg_conf_ch_idx(band, channel);
 
-       if (ch_bit_idx > 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
+       if (ch_bit_idx >= 0 && ch_bit_idx <= WL1271_MAX_CHANNELS)
                set_bit(ch_bit_idx, (long *)wl->reg_ch_conf_pending);
 }
 
index 38995f90040dea19b50d9c46ea2d4c8b7dc1b41b..bbdd10632373d0481ae7dd21b331ce566903c77c 100644 (file)
@@ -1062,7 +1062,8 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
        static const char* const PLT_MODE[] = {
                "PLT_OFF",
                "PLT_ON",
-               "PLT_FEM_DETECT"
+               "PLT_FEM_DETECT",
+               "PLT_CHIP_AWAKE"
        };
 
        int ret;
@@ -1088,9 +1089,11 @@ int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode)
                if (ret < 0)
                        goto power_off;
 
-               ret = wl->ops->plt_init(wl);
-               if (ret < 0)
-                       goto power_off;
+               if (plt_mode != PLT_CHIP_AWAKE) {
+                       ret = wl->ops->plt_init(wl);
+                       if (ret < 0)
+                               goto power_off;
+               }
 
                wl->state = WLCORE_STATE_ON;
                wl1271_notice("firmware booted in PLT mode %s (%s)",
@@ -2008,6 +2011,47 @@ out:
        mutex_unlock(&wl->mutex);
 }
 
+static void wlcore_pending_auth_complete_work(struct work_struct *work)
+{
+       struct delayed_work *dwork;
+       struct wl1271 *wl;
+       struct wl12xx_vif *wlvif;
+       unsigned long time_spare;
+       int ret;
+
+       dwork = container_of(work, struct delayed_work, work);
+       wlvif = container_of(dwork, struct wl12xx_vif,
+                            pending_auth_complete_work);
+       wl = wlvif->wl;
+
+       mutex_lock(&wl->mutex);
+
+       if (unlikely(wl->state != WLCORE_STATE_ON))
+               goto out;
+
+       /*
+        * Make sure a second really passed since the last auth reply. Maybe
+        * a second auth reply arrived while we were stuck on the mutex.
+        * Check for a little less than the timeout to protect from scheduler
+        * irregularities.
+        */
+       time_spare = jiffies +
+                       msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT - 50);
+       if (!time_after(time_spare, wlvif->pending_auth_reply_time))
+               goto out;
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       /* cancel the ROC if active */
+       wlcore_update_inconn_sta(wl, wlvif, NULL, false);
+
+       wl1271_ps_elp_sleep(wl);
+out:
+       mutex_unlock(&wl->mutex);
+}
+
 static int wl12xx_allocate_rate_policy(struct wl1271 *wl, u8 *idx)
 {
        u8 policy = find_first_zero_bit(wl->rate_policies_map,
@@ -2159,6 +2203,8 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
                          wlcore_channel_switch_work);
        INIT_DELAYED_WORK(&wlvif->connection_loss_work,
                          wlcore_connection_loss_work);
+       INIT_DELAYED_WORK(&wlvif->pending_auth_complete_work,
+                         wlcore_pending_auth_complete_work);
        INIT_LIST_HEAD(&wlvif->list);
 
        setup_timer(&wlvif->rx_streaming_timer, wl1271_rx_streaming_timer,
@@ -2376,6 +2422,11 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
        int ret = 0;
        u8 role_type;
 
+       if (wl->plt) {
+               wl1271_error("Adding Interface not allowed while in PLT mode");
+               return -EBUSY;
+       }
+
        vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
                             IEEE80211_VIF_SUPPORTS_CQM_RSSI;
 
@@ -2590,6 +2641,7 @@ unlock:
        cancel_work_sync(&wlvif->rx_streaming_disable_work);
        cancel_delayed_work_sync(&wlvif->connection_loss_work);
        cancel_delayed_work_sync(&wlvif->channel_switch_work);
+       cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);
 
        mutex_lock(&wl->mutex);
 }
@@ -2875,6 +2927,25 @@ static void wl1271_set_band_rate(struct wl1271 *wl, struct wl12xx_vif *wlvif)
        wlvif->rate_set = wlvif->basic_rate_set;
 }
 
+static void wl1271_sta_handle_idle(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                                  bool idle)
+{
+       bool cur_idle = !test_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags);
+
+       if (idle == cur_idle)
+               return;
+
+       if (idle) {
+               clear_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags);
+       } else {
+               /* The current firmware only supports sched_scan in idle */
+               if (wl->sched_vif == wlvif)
+                       wl->ops->sched_scan_stop(wl, wlvif);
+
+               set_bit(WLVIF_FLAG_ACTIVE, &wlvif->flags);
+       }
+}
+
 static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                             struct ieee80211_conf *conf, u32 changed)
 {
@@ -3969,6 +4040,13 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
                        }
                } else {
                        if (test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) {
+                               /*
+                                * AP might be in ROC in case we have just
+                                * sent auth reply. handle it.
+                                */
+                               if (test_bit(wlvif->role_id, wl->roc_map))
+                                       wl12xx_croc(wl, wlvif->role_id);
+
                                ret = wl12xx_cmd_role_stop_ap(wl, wlvif);
                                if (ret < 0)
                                        goto out;
@@ -4120,6 +4198,9 @@ static void wl1271_bss_info_changed_sta(struct wl1271 *wl,
                do_join = true;
        }
 
+       if (changed & BSS_CHANGED_IDLE && !is_ibss)
+               wl1271_sta_handle_idle(wl, wlvif, bss_conf->idle);
+
        if (changed & BSS_CHANGED_CQM) {
                bool enable = false;
                if (bss_conf->cqm_rssi_thold)
@@ -4656,29 +4737,49 @@ static void wlcore_roc_if_possible(struct wl1271 *wl,
        wl12xx_roc(wl, wlvif, wlvif->role_id, wlvif->band, wlvif->channel);
 }
 
-static void wlcore_update_inconn_sta(struct wl1271 *wl,
-                                    struct wl12xx_vif *wlvif,
-                                    struct wl1271_station *wl_sta,
-                                    bool in_connection)
+/*
+ * when wl_sta is NULL, we treat this call as if coming from a
+ * pending auth reply.
+ * wl->mutex must be taken and the FW must be awake when the call
+ * takes place.
+ */
+void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                             struct wl1271_station *wl_sta, bool in_conn)
 {
-       if (in_connection) {
-               if (WARN_ON(wl_sta->in_connection))
+       if (in_conn) {
+               if (WARN_ON(wl_sta && wl_sta->in_connection))
                        return;
-               wl_sta->in_connection = true;
-               if (!wlvif->inconn_count++)
+
+               if (!wlvif->ap_pending_auth_reply &&
+                   !wlvif->inconn_count)
                        wlcore_roc_if_possible(wl, wlvif);
+
+               if (wl_sta) {
+                       wl_sta->in_connection = true;
+                       wlvif->inconn_count++;
+               } else {
+                       wlvif->ap_pending_auth_reply = true;
+               }
        } else {
-               if (!wl_sta->in_connection)
+               if (wl_sta && !wl_sta->in_connection)
+                       return;
+
+               if (WARN_ON(!wl_sta && !wlvif->ap_pending_auth_reply))
                        return;
 
-               wl_sta->in_connection = false;
-               wlvif->inconn_count--;
-               if (WARN_ON(wlvif->inconn_count < 0))
+               if (WARN_ON(wl_sta && !wlvif->inconn_count))
                        return;
 
-               if (!wlvif->inconn_count)
-                       if (test_bit(wlvif->role_id, wl->roc_map))
-                               wl12xx_croc(wl, wlvif->role_id);
+               if (wl_sta) {
+                       wl_sta->in_connection = false;
+                       wlvif->inconn_count--;
+               } else {
+                       wlvif->ap_pending_auth_reply = false;
+               }
+
+               if (!wlvif->inconn_count && !wlvif->ap_pending_auth_reply &&
+                   test_bit(wlvif->role_id, wl->roc_map))
+                       wl12xx_croc(wl, wlvif->role_id);
        }
 }
 
@@ -5313,10 +5414,7 @@ static struct ieee80211_rate wl1271_rates_5ghz[] = {
 
 /* 5 GHz band channels for WL1273 */
 static struct ieee80211_channel wl1271_channels_5ghz[] = {
-       { .hw_value = 7, .center_freq = 5035, .max_power = WLCORE_MAX_TXPWR },
        { .hw_value = 8, .center_freq = 5040, .max_power = WLCORE_MAX_TXPWR },
-       { .hw_value = 9, .center_freq = 5045, .max_power = WLCORE_MAX_TXPWR },
-       { .hw_value = 11, .center_freq = 5055, .max_power = WLCORE_MAX_TXPWR },
        { .hw_value = 12, .center_freq = 5060, .max_power = WLCORE_MAX_TXPWR },
        { .hw_value = 16, .center_freq = 5080, .max_power = WLCORE_MAX_TXPWR },
        { .hw_value = 34, .center_freq = 5170, .max_power = WLCORE_MAX_TXPWR },
@@ -5896,14 +5994,20 @@ static const struct wiphy_wowlan_support wlcore_wowlan_support = {
 };
 #endif
 
+static irqreturn_t wlcore_hardirq(int irq, void *cookie)
+{
+       return IRQ_WAKE_THREAD;
+}
+
 static void wlcore_nvs_cb(const struct firmware *fw, void *context)
 {
        struct wl1271 *wl = context;
        struct platform_device *pdev = wl->pdev;
-       struct wlcore_platdev_data *pdev_data = pdev->dev.platform_data;
+       struct wlcore_platdev_data *pdev_data = dev_get_platdata(&pdev->dev);
        struct wl12xx_platform_data *pdata = pdev_data->pdata;
        unsigned long irqflags;
        int ret;
+       irq_handler_t hardirq_fn = NULL;
 
        if (fw) {
                wl->nvs = kmemdup(fw->data, fw->size, GFP_KERNEL);
@@ -5932,12 +6036,14 @@ static void wlcore_nvs_cb(const struct firmware *fw, void *context)
        wl->platform_quirks = pdata->platform_quirks;
        wl->if_ops = pdev_data->if_ops;
 
-       if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ)
+       if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) {
                irqflags = IRQF_TRIGGER_RISING;
-       else
+               hardirq_fn = wlcore_hardirq;
+       } else {
                irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT;
+       }
 
-       ret = request_threaded_irq(wl->irq, NULL, wlcore_irq,
+       ret = request_threaded_irq(wl->irq, hardirq_fn, wlcore_irq,
                                   irqflags, pdev->name, wl);
        if (ret < 0) {
                wl1271_error("request_irq() failed: %d", ret);
index 98066d40c2ad107943384509abcbc10b82d82019..26bfc365ba70bf03e215ddc0be7df0d01c13512b 100644 (file)
@@ -83,6 +83,10 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
        struct wl12xx_vif *wlvif;
        u32 timeout;
 
+       /* We do not enter elp sleep in PLT mode */
+       if (wl->plt)
+               return;
+
        if (wl->sleep_auth != WL1271_PSM_ELP)
                return;
 
index f407101e525b60a9c4bff3c402865d12f3d6afde..13e743df2e31d45815f8d8fd916e9f5370977841 100644 (file)
@@ -174,17 +174,7 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                    /* if radar is set, we ignore the passive flag */
                    (radar ||
                     !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
-                       wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
-                                    req_channels[i]->band,
-                                    req_channels[i]->center_freq);
-                       wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
-                                    req_channels[i]->hw_value,
-                                    req_channels[i]->flags);
-                       wl1271_debug(DEBUG_SCAN, "max_power %d",
-                                    req_channels[i]->max_power);
-                       wl1271_debug(DEBUG_SCAN, "min_dwell_time %d max dwell time %d",
-                                    min_dwell_time_active,
-                                    max_dwell_time_active);
+
 
                        if (flags & IEEE80211_CHAN_RADAR) {
                                channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
@@ -222,6 +212,17 @@ wlcore_scan_get_channels(struct wl1271 *wl,
                                             *n_pactive_ch);
                        }
 
+                       wl1271_debug(DEBUG_SCAN, "freq %d, ch. %d, flags 0x%x, power %d, min/max_dwell %d/%d%s%s",
+                                    req_channels[i]->center_freq,
+                                    req_channels[i]->hw_value,
+                                    req_channels[i]->flags,
+                                    req_channels[i]->max_power,
+                                    min_dwell_time_active,
+                                    max_dwell_time_active,
+                                    flags & IEEE80211_CHAN_RADAR ?
+                                       ", DFS" : "",
+                                    flags & IEEE80211_CHAN_PASSIVE_SCAN ?
+                                       ", PASSIVE" : "");
                        j++;
                }
        }
@@ -364,7 +365,7 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
        struct cfg80211_ssid *ssids = req->ssids;
        int ret = 0, type, i, j, n_match_ssids = 0;
 
-       wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list");
+       wl1271_debug((DEBUG_CMD | DEBUG_SCAN), "cmd sched scan ssid list");
 
        /* count the match sets that contain SSIDs */
        for (i = 0; i < req->n_match_sets; i++)
@@ -442,8 +443,6 @@ wlcore_scan_sched_scan_ssid_list(struct wl1271 *wl,
                }
        }
 
-       wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd));
-
        ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_SSID_CFG, cmd,
                              sizeof(*cmd), 0);
        if (ret < 0) {
index 1b0cd98e35f187f8be9f0525e152e5960742471d..b2c018dccf1887bb8dbdd5b85d9a88e0d30ff46e 100644 (file)
@@ -335,7 +335,7 @@ static int wl1271_probe(struct spi_device *spi)
        if (!pdev_data)
                goto out;
 
-       pdev_data->pdata = spi->dev.platform_data;
+       pdev_data->pdata = dev_get_platdata(&spi->dev);
        if (!pdev_data->pdata) {
                dev_err(&spi->dev, "no platform data\n");
                ret = -ENODEV;
index 527590f2adfbe66b088a99c48d5ce382ff030efd..a3b7d950d8e9b0f2a989b6624e130ed7cc081d91 100644 (file)
@@ -297,7 +297,8 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[])
                ret = wl1271_plt_stop(wl);
                break;
        case PLT_ON:
-               ret = wl1271_plt_start(wl, PLT_ON);
+       case PLT_CHIP_AWAKE:
+               ret = wl1271_plt_start(wl, val);
                break;
        case PLT_FEM_DETECT:
                ret = wl1271_tm_detect_fem(wl, tb);
@@ -361,6 +362,7 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 {
        struct wl1271 *wl = hw->priv;
        struct nlattr *tb[WL1271_TM_ATTR_MAX + 1];
+       u32 nla_cmd;
        int err;
 
        err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy);
@@ -370,7 +372,14 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        if (!tb[WL1271_TM_ATTR_CMD_ID])
                return -EINVAL;
 
-       switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) {
+       nla_cmd = nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID]);
+
+       /* Only SET_PLT_MODE is allowed in case of mode PLT_CHIP_AWAKE */
+       if (wl->plt_mode == PLT_CHIP_AWAKE &&
+           nla_cmd != WL1271_TM_CMD_SET_PLT_MODE)
+               return -EOPNOTSUPP;
+
+       switch (nla_cmd) {
        case WL1271_TM_CMD_TEST:
                return wl1271_tm_cmd_test(wl, tb);
        case WL1271_TM_CMD_INTERROGATE:
index 7e93fe63a2c74a215b4948a91a95c179a8d78592..87cd707affa240390f6b34ea0d1b28caf23ffb83 100644 (file)
@@ -86,19 +86,34 @@ void wl1271_free_tx_id(struct wl1271 *wl, int id)
 EXPORT_SYMBOL(wl1271_free_tx_id);
 
 static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
+                                                struct wl12xx_vif *wlvif,
                                                 struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
 
+       hdr = (struct ieee80211_hdr *)(skb->data +
+                                      sizeof(struct wl1271_tx_hw_descr));
+       if (!ieee80211_is_auth(hdr->frame_control))
+               return;
+
        /*
         * add the station to the known list before transmitting the
         * authentication response. this way it won't get de-authed by FW
         * when transmitting too soon.
         */
-       hdr = (struct ieee80211_hdr *)(skb->data +
-                                      sizeof(struct wl1271_tx_hw_descr));
-       if (ieee80211_is_auth(hdr->frame_control))
-               wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
+       wl1271_acx_set_inconnection_sta(wl, hdr->addr1);
+
+       /*
+        * ROC for 1 second on the AP channel for completing the connection.
+        * Note the ROC will be continued by the update_sta_state callbacks
+        * once the station reaches the associated state.
+        */
+       wlcore_update_inconn_sta(wl, wlvif, NULL, true);
+       wlvif->pending_auth_reply_time = jiffies;
+       cancel_delayed_work(&wlvif->pending_auth_complete_work);
+       ieee80211_queue_delayed_work(wl->hw,
+                               &wlvif->pending_auth_complete_work,
+                               msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT));
 }
 
 static void wl1271_tx_regulate_link(struct wl1271 *wl,
@@ -386,7 +401,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
                is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
                         (cipher == WLAN_CIPHER_SUITE_WEP104);
 
-               if (WARN_ON(is_wep && wlvif->default_key != idx)) {
+               if (WARN_ON(is_wep && wlvif && wlvif->default_key != idx)) {
                        ret = wl1271_set_default_wep_key(wl, wlvif, idx);
                        if (ret < 0)
                                return ret;
@@ -404,7 +419,7 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
        wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
 
        if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) {
-               wl1271_tx_ap_update_inconnection_sta(wl, skb);
+               wl1271_tx_ap_update_inconnection_sta(wl, wlvif, skb);
                wl1271_tx_regulate_link(wl, wlvif, hlid);
        }
 
index 55aa4acf9105a4e703036b0b12250ae19a9a7f81..35489c300da17bfefe3b35fc7515dc58aeeaa196 100644 (file)
@@ -56,6 +56,9 @@
 /* Used for management frames and dummy packets */
 #define WL1271_TID_MGMT 7
 
+/* stop a ROC for pending authentication reply after this time (ms) */
+#define WLCORE_PEND_AUTH_ROC_TIMEOUT     1000
+
 struct wl127x_tx_mem {
        /*
         * Number of extra memory blocks to allocate for this packet
index 0034979e97cbaa0316dfd2a62db2e5be59b7f058..54ce5d5e84db0be55da713ddcdbcd19818d507f3 100644 (file)
@@ -481,6 +481,8 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd,
                   struct ieee80211_sta *sta,
                   struct ieee80211_key_conf *key_conf);
 void wlcore_regdomain_config(struct wl1271 *wl);
+void wlcore_update_inconn_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+                             struct wl1271_station *wl_sta, bool in_conn);
 
 static inline void
 wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band,
index e5e146435fe77e34bc04ac7bca36a1e8e553a17a..2a50e089b0e755eb9fafa79f1cff00c6e9d2d4a7 100644 (file)
@@ -255,6 +255,7 @@ enum wl12xx_vif_flags {
        WLVIF_FLAG_CS_PROGRESS,
        WLVIF_FLAG_AP_PROBE_RESP_SET,
        WLVIF_FLAG_IN_USE,
+       WLVIF_FLAG_ACTIVE,
 };
 
 struct wl12xx_vif;
@@ -307,6 +308,7 @@ enum plt_mode {
        PLT_OFF = 0,
        PLT_ON = 1,
        PLT_FEM_DETECT = 2,
+       PLT_CHIP_AWAKE = 3
 };
 
 struct wl12xx_rx_filter_field {
@@ -456,6 +458,15 @@ struct wl12xx_vif {
         */
        int hw_queue_base;
 
+       /* do we have a pending auth reply? (and ROC) */
+       bool ap_pending_auth_reply;
+
+       /* time when we sent the pending auth reply */
+       unsigned long pending_auth_reply_time;
+
+       /* work for canceling ROC after pending auth reply */
+       struct delayed_work pending_auth_complete_work;
+
        /*
         * This struct must be last!
         * data that has to be saved acrossed reconfigs (e.g. recovery)
index a1977430ddfb9be616a6e97c7cfb4951da2cdd09..5715318d6bab3b4c7905c7c69ee549e39636c6cc 100644 (file)
@@ -184,6 +184,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
                   unsigned long rx_ring_ref, unsigned int tx_evtchn,
                   unsigned int rx_evtchn);
 void xenvif_disconnect(struct xenvif *vif);
+void xenvif_free(struct xenvif *vif);
 
 int xenvif_xenbus_init(void);
 void xenvif_xenbus_fini(void);
index 625c6f49cfba9923e80dc0834d49a6a6b870f1b3..01bb854c7f62bfc281dfdc0081829237f2f843d6 100644 (file)
@@ -353,6 +353,9 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid,
        }
 
        netdev_dbg(dev, "Successfully created xenvif\n");
+
+       __module_get(THIS_MODULE);
+
        return vif;
 }
 
@@ -366,8 +369,6 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
        if (vif->tx_irq)
                return 0;
 
-       __module_get(THIS_MODULE);
-
        err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref);
        if (err < 0)
                goto err;
@@ -406,7 +407,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref,
 
        init_waitqueue_head(&vif->wq);
        vif->task = kthread_create(xenvif_kthread,
-                                  (void *)vif, vif->dev->name);
+                                  (void *)vif, "%s", vif->dev->name);
        if (IS_ERR(vif->task)) {
                pr_warn("Could not allocate kthread for %s\n", vif->dev->name);
                err = PTR_ERR(vif->task);
@@ -452,12 +453,6 @@ void xenvif_carrier_off(struct xenvif *vif)
 
 void xenvif_disconnect(struct xenvif *vif)
 {
-       /* Disconnect funtion might get called by generic framework
-        * even before vif connects, so we need to check if we really
-        * need to do a module_put.
-        */
-       int need_module_put = 0;
-
        if (netif_carrier_ok(vif->dev))
                xenvif_carrier_off(vif);
 
@@ -468,23 +463,22 @@ void xenvif_disconnect(struct xenvif *vif)
                        unbind_from_irqhandler(vif->tx_irq, vif);
                        unbind_from_irqhandler(vif->rx_irq, vif);
                }
-               /* vif->irq is valid, we had a module_get in
-                * xenvif_connect.
-                */
-               need_module_put = 1;
+               vif->tx_irq = 0;
        }
 
        if (vif->task)
                kthread_stop(vif->task);
 
+       xenvif_unmap_frontend_rings(vif);
+}
+
+void xenvif_free(struct xenvif *vif)
+{
        netif_napi_del(&vif->napi);
 
        unregister_netdev(vif->dev);
 
-       xenvif_unmap_frontend_rings(vif);
-
        free_netdev(vif->dev);
 
-       if (need_module_put)
-               module_put(THIS_MODULE);
+       module_put(THIS_MODULE);
 }
index 956130c70036d2d3d297e8d101bc68017f19c9d6..f3e591c611ded744ec0b6ea2cefe9b7dd3d568c7 100644 (file)
@@ -212,6 +212,49 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
        return false;
 }
 
+struct xenvif_count_slot_state {
+       unsigned long copy_off;
+       bool head;
+};
+
+unsigned int xenvif_count_frag_slots(struct xenvif *vif,
+                                    unsigned long offset, unsigned long size,
+                                    struct xenvif_count_slot_state *state)
+{
+       unsigned count = 0;
+
+       offset &= ~PAGE_MASK;
+
+       while (size > 0) {
+               unsigned long bytes;
+
+               bytes = PAGE_SIZE - offset;
+
+               if (bytes > size)
+                       bytes = size;
+
+               if (start_new_rx_buffer(state->copy_off, bytes, state->head)) {
+                       count++;
+                       state->copy_off = 0;
+               }
+
+               if (state->copy_off + bytes > MAX_BUFFER_OFFSET)
+                       bytes = MAX_BUFFER_OFFSET - state->copy_off;
+
+               state->copy_off += bytes;
+
+               offset += bytes;
+               size -= bytes;
+
+               if (offset == PAGE_SIZE)
+                       offset = 0;
+
+               state->head = false;
+       }
+
+       return count;
+}
+
 /*
  * Figure out how many ring slots we're going to need to send @skb to
  * the guest. This function is essentially a dry run of
@@ -219,48 +262,39 @@ static bool start_new_rx_buffer(int offset, unsigned long size, int head)
  */
 unsigned int xenvif_count_skb_slots(struct xenvif *vif, struct sk_buff *skb)
 {
+       struct xenvif_count_slot_state state;
        unsigned int count;
-       int i, copy_off;
+       unsigned char *data;
+       unsigned i;
 
-       count = DIV_ROUND_UP(skb_headlen(skb), PAGE_SIZE);
+       state.head = true;
+       state.copy_off = 0;
 
-       copy_off = skb_headlen(skb) % PAGE_SIZE;
+       /* Slot for the first (partial) page of data. */
+       count = 1;
 
+       /* Need a slot for the GSO prefix for GSO extra data? */
        if (skb_shinfo(skb)->gso_size)
                count++;
 
-       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-               unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
-               unsigned long offset = skb_shinfo(skb)->frags[i].page_offset;
-               unsigned long bytes;
-
-               offset &= ~PAGE_MASK;
-
-               while (size > 0) {
-                       BUG_ON(offset >= PAGE_SIZE);
-                       BUG_ON(copy_off > MAX_BUFFER_OFFSET);
-
-                       bytes = PAGE_SIZE - offset;
-
-                       if (bytes > size)
-                               bytes = size;
+       data = skb->data;
+       while (data < skb_tail_pointer(skb)) {
+               unsigned long offset = offset_in_page(data);
+               unsigned long size = PAGE_SIZE - offset;
 
-                       if (start_new_rx_buffer(copy_off, bytes, 0)) {
-                               count++;
-                               copy_off = 0;
-                       }
+               if (data + size > skb_tail_pointer(skb))
+                       size = skb_tail_pointer(skb) - data;
 
-                       if (copy_off + bytes > MAX_BUFFER_OFFSET)
-                               bytes = MAX_BUFFER_OFFSET - copy_off;
+               count += xenvif_count_frag_slots(vif, offset, size, &state);
 
-                       copy_off += bytes;
+               data += size;
+       }
 
-                       offset += bytes;
-                       size -= bytes;
+       for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+               unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
+               unsigned long offset = skb_shinfo(skb)->frags[i].page_offset;
 
-                       if (offset == PAGE_SIZE)
-                               offset = 0;
-               }
+               count += xenvif_count_frag_slots(vif, offset, size, &state);
        }
        return count;
 }
index 1fe48fe364ed919a1f011170949c5cd37f4ad905..a53782ef154078717cbcff039a010e93e559fa58 100644 (file)
@@ -42,7 +42,7 @@ static int netback_remove(struct xenbus_device *dev)
        if (be->vif) {
                kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
                xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-               xenvif_disconnect(be->vif);
+               xenvif_free(be->vif);
                be->vif = NULL;
        }
        kfree(be);
@@ -213,9 +213,18 @@ static void disconnect_backend(struct xenbus_device *dev)
 {
        struct backend_info *be = dev_get_drvdata(&dev->dev);
 
+       if (be->vif)
+               xenvif_disconnect(be->vif);
+}
+
+static void destroy_backend(struct xenbus_device *dev)
+{
+       struct backend_info *be = dev_get_drvdata(&dev->dev);
+
        if (be->vif) {
+               kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
                xenbus_rm(XBT_NIL, dev->nodename, "hotplug-status");
-               xenvif_disconnect(be->vif);
+               xenvif_free(be->vif);
                be->vif = NULL;
        }
 }
@@ -246,14 +255,11 @@ static void frontend_changed(struct xenbus_device *dev,
        case XenbusStateConnected:
                if (dev->state == XenbusStateConnected)
                        break;
-               backend_create_xenvif(be);
                if (be->vif)
                        connect(be);
                break;
 
        case XenbusStateClosing:
-               if (be->vif)
-                       kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
                disconnect_backend(dev);
                xenbus_switch_state(dev, XenbusStateClosing);
                break;
@@ -262,6 +268,7 @@ static void frontend_changed(struct xenbus_device *dev,
                xenbus_switch_state(dev, XenbusStateClosed);
                if (xenbus_dev_is_online(dev))
                        break;
+               destroy_backend(dev);
                /* fall through if not online */
        case XenbusStateUnknown:
                device_unregister(&dev->dev);
index 37ee6495acc1e521144bf71396fbdc4ba3b6487b..f69df793dbe2c153e591ddc1180335288288acd5 100644 (file)
@@ -1,7 +1,7 @@
 config NTB
        tristate "Intel Non-Transparent Bridge support"
        depends on PCI
-       depends on X86_64
+       depends on X86
        help
         The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus
         connecting 2 systems.  When configured, writes to the device's PCI
index 2dacd19e1b8a15c5a7c8d66db2eb7cb2793a58ed..1cb6e51e6bda97aadb4ba88bd46123544dcc4140 100644 (file)
  * Jon Mason <jon.mason@intel.com>
  */
 #include <linux/debugfs.h>
+#include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
+#include <linux/random.h>
 #include <linux/slab.h>
 #include "ntb_hw.h"
 #include "ntb_regs.h"
 
 #define NTB_NAME       "Intel(R) PCI-E Non-Transparent Bridge Driver"
-#define NTB_VER                "0.25"
+#define NTB_VER                "1.0"
 
 MODULE_DESCRIPTION(NTB_NAME);
 MODULE_VERSION(NTB_VER);
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Intel Corporation");
 
+static bool xeon_errata_workaround = true;
+module_param(xeon_errata_workaround, bool, 0644);
+MODULE_PARM_DESC(xeon_errata_workaround, "Workaround for the Xeon Errata");
+
 enum {
-       NTB_CONN_CLASSIC = 0,
+       NTB_CONN_TRANSPARENT = 0,
        NTB_CONN_B2B,
        NTB_CONN_RP,
 };
@@ -78,17 +84,27 @@ enum {
        BWD_HW,
 };
 
+static struct dentry *debugfs_dir;
+
+#define BWD_LINK_RECOVERY_TIME 500
+
 /* Translate memory window 0,1 to BAR 2,4 */
-#define MW_TO_BAR(mw)  (mw * 2 + 2)
+#define MW_TO_BAR(mw)  (mw * NTB_MAX_NUM_MW + 2)
 
 static DEFINE_PCI_DEVICE_TABLE(ntb_pci_tbl) = {
        {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
        {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
-       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_CLASSIC_JSF)},
-       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_RP_JSF)},
-       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_RP_SNB)},
        {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
-       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_CLASSIC_SNB)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)},
+       {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)},
        {0}
 };
 MODULE_DEVICE_TABLE(pci, ntb_pci_tbl);
@@ -129,6 +145,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev)
  * ntb_register_db_callback() - register a callback for doorbell interrupt
  * @ndev: pointer to ntb_device instance
  * @idx: doorbell index to register callback, zero based
+ * @data: pointer to be returned to caller with every callback
  * @func: callback function to register
  *
  * This function registers a callback function for the doorbell interrupt
@@ -151,9 +168,9 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
        ndev->db_cb[idx].data = data;
 
        /* unmask interrupt */
-       mask = readw(ndev->reg_ofs.pdb_mask);
+       mask = readw(ndev->reg_ofs.ldb_mask);
        clear_bit(idx * ndev->bits_per_vector, &mask);
-       writew(mask, ndev->reg_ofs.pdb_mask);
+       writew(mask, ndev->reg_ofs.ldb_mask);
 
        return 0;
 }
@@ -173,9 +190,9 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
        if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback)
                return;
 
-       mask = readw(ndev->reg_ofs.pdb_mask);
+       mask = readw(ndev->reg_ofs.ldb_mask);
        set_bit(idx * ndev->bits_per_vector, &mask);
-       writew(mask, ndev->reg_ofs.pdb_mask);
+       writew(mask, ndev->reg_ofs.ldb_mask);
 
        ndev->db_cb[idx].callback = NULL;
 }
@@ -333,6 +350,23 @@ int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
        return 0;
 }
 
+/**
+ * ntb_get_mw_base() - get addr for the NTB memory window
+ * @ndev: pointer to ntb_device instance
+ * @mw: memory window number
+ *
+ * This function provides the base address of the memory window specified.
+ *
+ * RETURNS: address, or NULL on error.
+ */
+resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw)
+{
+       if (mw >= ntb_max_mw(ndev))
+               return 0;
+
+       return pci_resource_start(ndev->pdev, MW_TO_BAR(mw));
+}
+
 /**
  * ntb_get_mw_vbase() - get virtual addr for the NTB memory window
  * @ndev: pointer to ntb_device instance
@@ -345,7 +379,7 @@ int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val)
  */
 void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
 {
-       if (mw >= NTB_NUM_MW)
+       if (mw >= ntb_max_mw(ndev))
                return NULL;
 
        return ndev->mw[mw].vbase;
@@ -360,9 +394,9 @@ void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw)
  *
  * RETURNS: the size of the memory window or zero on error
  */
-resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
+u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
 {
-       if (mw >= NTB_NUM_MW)
+       if (mw >= ntb_max_mw(ndev))
                return 0;
 
        return ndev->mw[mw].bar_sz;
@@ -380,7 +414,7 @@ resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw)
  */
 void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
 {
-       if (mw >= NTB_NUM_MW)
+       if (mw >= ntb_max_mw(ndev))
                return;
 
        dev_dbg(&ndev->pdev->dev, "Writing addr %Lx to BAR %d\n", addr,
@@ -390,16 +424,16 @@ void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
 
        switch (MW_TO_BAR(mw)) {
        case NTB_BAR_23:
-               writeq(addr, ndev->reg_ofs.sbar2_xlat);
+               writeq(addr, ndev->reg_ofs.bar2_xlat);
                break;
        case NTB_BAR_45:
-               writeq(addr, ndev->reg_ofs.sbar4_xlat);
+               writeq(addr, ndev->reg_ofs.bar4_xlat);
                break;
        }
 }
 
 /**
- * ntb_ring_sdb() - Set the doorbell on the secondary/external side
+ * ntb_ring_doorbell() - Set the doorbell on the secondary/external side
  * @ndev: pointer to ntb_device instance
  * @db: doorbell to ring
  *
@@ -408,15 +442,58 @@ void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
  *
  * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
  */
-void ntb_ring_sdb(struct ntb_device *ndev, unsigned int db)
+void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db)
 {
        dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db);
 
        if (ndev->hw_type == BWD_HW)
-               writeq((u64) 1 << db, ndev->reg_ofs.sdb);
+               writeq((u64) 1 << db, ndev->reg_ofs.rdb);
        else
                writew(((1 << ndev->bits_per_vector) - 1) <<
-                      (db * ndev->bits_per_vector), ndev->reg_ofs.sdb);
+                      (db * ndev->bits_per_vector), ndev->reg_ofs.rdb);
+}
+
+static void bwd_recover_link(struct ntb_device *ndev)
+{
+       u32 status;
+
+       /* Driver resets the NTB ModPhy lanes - magic! */
+       writeb(0xe0, ndev->reg_base + BWD_MODPHY_PCSREG6);
+       writeb(0x40, ndev->reg_base + BWD_MODPHY_PCSREG4);
+       writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG4);
+       writeb(0x60, ndev->reg_base + BWD_MODPHY_PCSREG6);
+
+       /* Driver waits 100ms to allow the NTB ModPhy to settle */
+       msleep(100);
+
+       /* Clear AER Errors, write to clear */
+       status = readl(ndev->reg_base + BWD_ERRCORSTS_OFFSET);
+       dev_dbg(&ndev->pdev->dev, "ERRCORSTS = %x\n", status);
+       status &= PCI_ERR_COR_REP_ROLL;
+       writel(status, ndev->reg_base + BWD_ERRCORSTS_OFFSET);
+
+       /* Clear unexpected electrical idle event in LTSSM, write to clear */
+       status = readl(ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
+       dev_dbg(&ndev->pdev->dev, "LTSSMERRSTS0 = %x\n", status);
+       status |= BWD_LTSSMERRSTS0_UNEXPECTEDEI;
+       writel(status, ndev->reg_base + BWD_LTSSMERRSTS0_OFFSET);
+
+       /* Clear DeSkew Buffer error, write to clear */
+       status = readl(ndev->reg_base + BWD_DESKEWSTS_OFFSET);
+       dev_dbg(&ndev->pdev->dev, "DESKEWSTS = %x\n", status);
+       status |= BWD_DESKEWSTS_DBERR;
+       writel(status, ndev->reg_base + BWD_DESKEWSTS_OFFSET);
+
+       status = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+       dev_dbg(&ndev->pdev->dev, "IBSTERRRCRVSTS0 = %x\n", status);
+       status &= BWD_IBIST_ERR_OFLOW;
+       writel(status, ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+
+       /* Releases the NTB state machine to allow the link to retrain */
+       status = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
+       dev_dbg(&ndev->pdev->dev, "LTSSMSTATEJMP = %x\n", status);
+       status &= ~BWD_LTSSMSTATEJMP_FORCEDETECT;
+       writel(status, ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
 }
 
 static void ntb_link_event(struct ntb_device *ndev, int link_state)
@@ -433,7 +510,8 @@ static void ntb_link_event(struct ntb_device *ndev, int link_state)
                ndev->link_status = NTB_LINK_UP;
                event = NTB_EVENT_HW_LINK_UP;
 
-               if (ndev->hw_type == BWD_HW)
+               if (ndev->hw_type == BWD_HW ||
+                   ndev->conn_type == NTB_CONN_TRANSPARENT)
                        status = readw(ndev->reg_ofs.lnk_stat);
                else {
                        int rc = pci_read_config_word(ndev->pdev,
@@ -442,13 +520,16 @@ static void ntb_link_event(struct ntb_device *ndev, int link_state)
                        if (rc)
                                return;
                }
+
+               ndev->link_width = (status & NTB_LINK_WIDTH_MASK) >> 4;
+               ndev->link_speed = (status & NTB_LINK_SPEED_MASK);
                dev_info(&ndev->pdev->dev, "Link Width %d, Link Speed %d\n",
-                        (status & NTB_LINK_WIDTH_MASK) >> 4,
-                        (status & NTB_LINK_SPEED_MASK));
+                        ndev->link_width, ndev->link_speed);
        } else {
                dev_info(&ndev->pdev->dev, "Link Down\n");
                ndev->link_status = NTB_LINK_DOWN;
                event = NTB_EVENT_HW_LINK_DOWN;
+               /* Don't modify link width/speed, we need it in link recovery */
        }
 
        /* notify the upper layer if we have an event change */
@@ -488,6 +569,47 @@ static int ntb_link_status(struct ntb_device *ndev)
        return 0;
 }
 
+static void bwd_link_recovery(struct work_struct *work)
+{
+       struct ntb_device *ndev = container_of(work, struct ntb_device,
+                                              lr_timer.work);
+       u32 status32;
+
+       bwd_recover_link(ndev);
+       /* There is a potential race between the 2 NTB devices recovering at the
+        * same time.  If the times are the same, the link will not recover and
+        * the driver will be stuck in this loop forever.  Add a random interval
+        * to the recovery time to prevent this race.
+        */
+       msleep(BWD_LINK_RECOVERY_TIME + prandom_u32() % BWD_LINK_RECOVERY_TIME);
+
+       status32 = readl(ndev->reg_base + BWD_LTSSMSTATEJMP_OFFSET);
+       if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT)
+               goto retry;
+
+       status32 = readl(ndev->reg_base + BWD_IBSTERRRCRVSTS0_OFFSET);
+       if (status32 & BWD_IBIST_ERR_OFLOW)
+               goto retry;
+
+       status32 = readl(ndev->reg_ofs.lnk_cntl);
+       if (!(status32 & BWD_CNTL_LINK_DOWN)) {
+               unsigned char speed, width;
+               u16 status16;
+
+               status16 = readw(ndev->reg_ofs.lnk_stat);
+               width = (status16 & NTB_LINK_WIDTH_MASK) >> 4;
+               speed = (status16 & NTB_LINK_SPEED_MASK);
+               if (ndev->link_width != width || ndev->link_speed != speed)
+                       goto retry;
+       }
+
+       schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
+       return;
+
+retry:
+       schedule_delayed_work(&ndev->lr_timer, NTB_HB_TIMEOUT);
+}
+
 /* BWD doesn't have link status interrupt, poll on that platform */
 static void bwd_link_poll(struct work_struct *work)
 {
@@ -503,6 +625,16 @@ static void bwd_link_poll(struct work_struct *work)
                if (rc)
                        dev_err(&ndev->pdev->dev,
                                "Error determining link status\n");
+
+               /* Check to see if a link error is the cause of the link down */
+               if (ndev->link_status == NTB_LINK_DOWN) {
+                       u32 status32 = readl(ndev->reg_base +
+                                            BWD_LTSSMSTATEJMP_OFFSET);
+                       if (status32 & BWD_LTSSMSTATEJMP_FORCEDETECT) {
+                               schedule_delayed_work(&ndev->lr_timer, 0);
+                               return;
+                       }
+               }
        }
 
        schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
@@ -519,41 +651,174 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
        if (rc)
                return rc;
 
+       if (val & SNB_PPD_DEV_TYPE)
+               ndev->dev_type = NTB_DEV_USD;
+       else
+               ndev->dev_type = NTB_DEV_DSD;
+
        switch (val & SNB_PPD_CONN_TYPE) {
        case NTB_CONN_B2B:
+               dev_info(&ndev->pdev->dev, "Conn Type = B2B\n");
                ndev->conn_type = NTB_CONN_B2B;
+               ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+               ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
+               ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
+               ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
+               ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
+               ndev->limits.max_spads = SNB_MAX_B2B_SPADS;
+
+               /* There is a Xeon hardware errata related to writes to
+                * SDOORBELL or B2BDOORBELL in conjunction with inbound access
+                * to NTB MMIO Space, which may hang the system.  To workaround
+                * this use the second memory window to access the interrupt and
+                * scratch pad registers on the remote system.
+                */
+               if (xeon_errata_workaround) {
+                       if (!ndev->mw[1].bar_sz)
+                               return -EINVAL;
+
+                       ndev->limits.max_mw = SNB_ERRATA_MAX_MW;
+                       ndev->reg_ofs.spad_write = ndev->mw[1].vbase +
+                                                  SNB_SPAD_OFFSET;
+                       ndev->reg_ofs.rdb = ndev->mw[1].vbase +
+                                           SNB_PDOORBELL_OFFSET;
+
+                       /* Set the Limit register to 4k, the minimum size, to
+                        * prevent an illegal access
+                        */
+                       writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base +
+                              SNB_PBAR4LMT_OFFSET);
+               } else {
+                       ndev->limits.max_mw = SNB_MAX_MW;
+                       ndev->reg_ofs.spad_write = ndev->reg_base +
+                                                  SNB_B2B_SPAD_OFFSET;
+                       ndev->reg_ofs.rdb = ndev->reg_base +
+                                           SNB_B2B_DOORBELL_OFFSET;
+
+                       /* Disable the Limit register, just incase it is set to
+                        * something silly
+                        */
+                       writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET);
+               }
+
+               /* The Xeon errata workaround requires setting SBAR Base
+                * addresses to known values, so that the PBAR XLAT can be
+                * pointed at SBAR0 of the remote system.
+                */
+               if (ndev->dev_type == NTB_DEV_USD) {
+                       writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
+                              SNB_PBAR2XLAT_OFFSET);
+                       if (xeon_errata_workaround)
+                               writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
+                                      SNB_PBAR4XLAT_OFFSET);
+                       else {
+                               writeq(SNB_MBAR45_DSD_ADDR, ndev->reg_base +
+                                      SNB_PBAR4XLAT_OFFSET);
+                               /* B2B_XLAT_OFFSET is a 64bit register, but can
+                                * only take 32bit writes
+                                */
+                               writel(SNB_MBAR01_DSD_ADDR & 0xffffffff,
+                                      ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
+                               writel(SNB_MBAR01_DSD_ADDR >> 32,
+                                      ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
+                       }
+
+                       writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
+                              SNB_SBAR0BASE_OFFSET);
+                       writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
+                              SNB_SBAR2BASE_OFFSET);
+                       writeq(SNB_MBAR45_USD_ADDR, ndev->reg_base +
+                              SNB_SBAR4BASE_OFFSET);
+               } else {
+                       writeq(SNB_MBAR23_USD_ADDR, ndev->reg_base +
+                              SNB_PBAR2XLAT_OFFSET);
+                       if (xeon_errata_workaround)
+                               writeq(SNB_MBAR01_USD_ADDR, ndev->reg_base +
+                                      SNB_PBAR4XLAT_OFFSET);
+                       else {
+                               writeq(SNB_MBAR45_USD_ADDR, ndev->reg_base +
+                                      SNB_PBAR4XLAT_OFFSET);
+                               /* B2B_XLAT_OFFSET is a 64bit register, but can
+                                * only take 32bit writes
+                                */
+                               writel(SNB_MBAR01_DSD_ADDR & 0xffffffff,
+                                      ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
+                               writel(SNB_MBAR01_USD_ADDR >> 32,
+                                      ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
+                       }
+                       writeq(SNB_MBAR01_DSD_ADDR, ndev->reg_base +
+                              SNB_SBAR0BASE_OFFSET);
+                       writeq(SNB_MBAR23_DSD_ADDR, ndev->reg_base +
+                              SNB_SBAR2BASE_OFFSET);
+                       writeq(SNB_MBAR45_DSD_ADDR, ndev->reg_base +
+                              SNB_SBAR4BASE_OFFSET);
+               }
                break;
-       case NTB_CONN_CLASSIC:
        case NTB_CONN_RP:
+               dev_info(&ndev->pdev->dev, "Conn Type = RP\n");
+               ndev->conn_type = NTB_CONN_RP;
+
+               if (xeon_errata_workaround) {
+                       dev_err(&ndev->pdev->dev, 
+                               "NTB-RP disabled due to hardware errata.  To disregard this warning and potentially lock-up the system, add the parameter 'xeon_errata_workaround=0'.\n");
+                       return -EINVAL;
+               }
+
+               /* Scratch pads need to have exclusive access from the primary
+                * or secondary side.  Halve the num spads so that each side can
+                * have an equal amount.
+                */
+               ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
+               /* Note: The SDOORBELL is the cause of the errata.  You REALLY
+                * don't want to touch it.
+                */
+               ndev->reg_ofs.rdb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
+               ndev->reg_ofs.ldb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+               ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
+               /* Offset the start of the spads to correspond to whether it is
+                * primary or secondary
+                */
+               ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET +
+                                          ndev->limits.max_spads * 4;
+               ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
+               ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
+               ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
+               ndev->limits.max_mw = SNB_MAX_MW;
+               break;
+       case NTB_CONN_TRANSPARENT:
+               dev_info(&ndev->pdev->dev, "Conn Type = TRANSPARENT\n");
+               ndev->conn_type = NTB_CONN_TRANSPARENT;
+               /* Scratch pads need to have exclusive access from the primary
+                * or secondary side.  Halve the num spads so that each side can
+                * have an equal amount.
+                */
+               ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2;
+               ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
+               ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
+               ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET;
+               ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET;
+               /* Offset the start of the spads to correspond to whether it is
+                * primary or secondary
+                */
+               ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET +
+                                         ndev->limits.max_spads * 4;
+               ndev->reg_ofs.bar2_xlat = ndev->reg_base + SNB_PBAR2XLAT_OFFSET;
+               ndev->reg_ofs.bar4_xlat = ndev->reg_base + SNB_PBAR4XLAT_OFFSET;
+
+               ndev->limits.max_mw = SNB_MAX_MW;
+               break;
        default:
-               dev_err(&ndev->pdev->dev, "Only B2B supported at this time\n");
+               /* Most likely caused by the remote NTB-RP device not being
+                * configured
+                */
+               dev_err(&ndev->pdev->dev, "Unknown PPD %x\n", val);
                return -EINVAL;
        }
 
-       if (val & SNB_PPD_DEV_TYPE)
-               ndev->dev_type = NTB_DEV_DSD;
-       else
-               ndev->dev_type = NTB_DEV_USD;
-
-       ndev->reg_ofs.pdb = ndev->reg_base + SNB_PDOORBELL_OFFSET;
-       ndev->reg_ofs.pdb_mask = ndev->reg_base + SNB_PDBMSK_OFFSET;
-       ndev->reg_ofs.sbar2_xlat = ndev->reg_base + SNB_SBAR2XLAT_OFFSET;
-       ndev->reg_ofs.sbar4_xlat = ndev->reg_base + SNB_SBAR4XLAT_OFFSET;
        ndev->reg_ofs.lnk_cntl = ndev->reg_base + SNB_NTBCNTL_OFFSET;
-       ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_LINK_STATUS_OFFSET;
-       ndev->reg_ofs.spad_read = ndev->reg_base + SNB_SPAD_OFFSET;
+       ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET;
        ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET;
 
-       if (ndev->conn_type == NTB_CONN_B2B) {
-               ndev->reg_ofs.sdb = ndev->reg_base + SNB_B2B_DOORBELL_OFFSET;
-               ndev->reg_ofs.spad_write = ndev->reg_base + SNB_B2B_SPAD_OFFSET;
-               ndev->limits.max_spads = SNB_MAX_SPADS;
-       } else {
-               ndev->reg_ofs.sdb = ndev->reg_base + SNB_SDOORBELL_OFFSET;
-               ndev->reg_ofs.spad_write = ndev->reg_base + SNB_SPAD_OFFSET;
-               ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS;
-       }
-
        ndev->limits.max_db_bits = SNB_MAX_DB_BITS;
        ndev->limits.msix_cnt = SNB_MSIX_CNT;
        ndev->bits_per_vector = SNB_DB_BITS_PER_VEC;
@@ -578,7 +843,7 @@ static int ntb_bwd_setup(struct ntb_device *ndev)
                break;
        case NTB_CONN_RP:
        default:
-               dev_err(&ndev->pdev->dev, "Only B2B supported at this time\n");
+               dev_err(&ndev->pdev->dev, "Unsupported NTB configuration\n");
                return -EINVAL;
        }
 
@@ -593,31 +858,25 @@ static int ntb_bwd_setup(struct ntb_device *ndev)
        if (rc)
                return rc;
 
-       ndev->reg_ofs.pdb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
-       ndev->reg_ofs.pdb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET;
-       ndev->reg_ofs.sbar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET;
-       ndev->reg_ofs.sbar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET;
+       ndev->reg_ofs.ldb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
+       ndev->reg_ofs.ldb_mask = ndev->reg_base + BWD_PDBMSK_OFFSET;
+       ndev->reg_ofs.rdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET;
+       ndev->reg_ofs.bar2_xlat = ndev->reg_base + BWD_SBAR2XLAT_OFFSET;
+       ndev->reg_ofs.bar4_xlat = ndev->reg_base + BWD_SBAR4XLAT_OFFSET;
        ndev->reg_ofs.lnk_cntl = ndev->reg_base + BWD_NTBCNTL_OFFSET;
        ndev->reg_ofs.lnk_stat = ndev->reg_base + BWD_LINK_STATUS_OFFSET;
        ndev->reg_ofs.spad_read = ndev->reg_base + BWD_SPAD_OFFSET;
+       ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET;
        ndev->reg_ofs.spci_cmd = ndev->reg_base + BWD_PCICMD_OFFSET;
-
-       if (ndev->conn_type == NTB_CONN_B2B) {
-               ndev->reg_ofs.sdb = ndev->reg_base + BWD_B2B_DOORBELL_OFFSET;
-               ndev->reg_ofs.spad_write = ndev->reg_base + BWD_B2B_SPAD_OFFSET;
-               ndev->limits.max_spads = BWD_MAX_SPADS;
-       } else {
-               ndev->reg_ofs.sdb = ndev->reg_base + BWD_PDOORBELL_OFFSET;
-               ndev->reg_ofs.spad_write = ndev->reg_base + BWD_SPAD_OFFSET;
-               ndev->limits.max_spads = BWD_MAX_COMPAT_SPADS;
-       }
-
+       ndev->limits.max_mw = BWD_MAX_MW;
+       ndev->limits.max_spads = BWD_MAX_SPADS;
        ndev->limits.max_db_bits = BWD_MAX_DB_BITS;
        ndev->limits.msix_cnt = BWD_MSIX_CNT;
        ndev->bits_per_vector = BWD_DB_BITS_PER_VEC;
 
        /* Since bwd doesn't have a link interrupt, setup a poll timer */
        INIT_DELAYED_WORK(&ndev->hb_timer, bwd_link_poll);
+       INIT_DELAYED_WORK(&ndev->lr_timer, bwd_link_recovery);
        schedule_delayed_work(&ndev->hb_timer, NTB_HB_TIMEOUT);
 
        return 0;
@@ -628,13 +887,18 @@ static int ntb_device_setup(struct ntb_device *ndev)
        int rc;
 
        switch (ndev->pdev->device) {
-       case PCI_DEVICE_ID_INTEL_NTB_2ND_SNB:
-       case PCI_DEVICE_ID_INTEL_NTB_RP_JSF:
-       case PCI_DEVICE_ID_INTEL_NTB_RP_SNB:
-       case PCI_DEVICE_ID_INTEL_NTB_CLASSIC_JSF:
-       case PCI_DEVICE_ID_INTEL_NTB_CLASSIC_SNB:
+       case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
+       case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
+       case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
+       case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
+       case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
+       case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
+       case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
+       case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
        case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
        case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
+       case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
+       case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
                rc = ntb_xeon_setup(ndev);
                break;
        case PCI_DEVICE_ID_INTEL_NTB_B2B_BWD:
@@ -644,16 +908,26 @@ static int ntb_device_setup(struct ntb_device *ndev)
                rc = -ENODEV;
        }
 
-       /* Enable Bus Master and Memory Space on the secondary side */
-       writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, ndev->reg_ofs.spci_cmd);
+       if (rc)
+               return rc;
+
+       dev_info(&ndev->pdev->dev, "Device Type = %s\n",
+                ndev->dev_type == NTB_DEV_USD ? "USD/DSP" : "DSD/USP");
 
-       return rc;
+       if (ndev->conn_type == NTB_CONN_B2B)
+               /* Enable Bus Master and Memory Space on the secondary side */
+               writew(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER,
+                      ndev->reg_ofs.spci_cmd);
+
+       return 0;
 }
 
 static void ntb_device_free(struct ntb_device *ndev)
 {
-       if (ndev->hw_type == BWD_HW)
+       if (ndev->hw_type == BWD_HW) {
                cancel_delayed_work_sync(&ndev->hb_timer);
+               cancel_delayed_work_sync(&ndev->lr_timer);
+       }
 }
 
 static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
@@ -672,7 +946,7 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data)
         */
        ndev->last_ts = jiffies;
 
-       writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.pdb);
+       writeq((u64) 1 << db_cb->db_num, ndev->reg_ofs.ldb);
 
        return IRQ_HANDLED;
 }
@@ -694,7 +968,7 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
         * interrupts.
         */
        writew(((1 << ndev->bits_per_vector) - 1) <<
-              (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.pdb);
+              (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb);
 
        return IRQ_HANDLED;
 }
@@ -712,7 +986,7 @@ static irqreturn_t xeon_event_msix_irq(int irq, void *dev)
                dev_err(&ndev->pdev->dev, "Error determining link status\n");
 
        /* bit 15 is always the link bit */
-       writew(1 << ndev->limits.max_db_bits, ndev->reg_ofs.pdb);
+       writew(1 << ndev->limits.max_db_bits, ndev->reg_ofs.ldb);
 
        return IRQ_HANDLED;
 }
@@ -723,29 +997,28 @@ static irqreturn_t ntb_interrupt(int irq, void *dev)
        unsigned int i = 0;
 
        if (ndev->hw_type == BWD_HW) {
-               u64 pdb = readq(ndev->reg_ofs.pdb);
+               u64 ldb = readq(ndev->reg_ofs.ldb);
 
-               dev_dbg(&ndev->pdev->dev, "irq %d - pdb = %Lx\n", irq, pdb);
+               dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %Lx\n", irq, ldb);
 
-               while (pdb) {
-                       i = __ffs(pdb);
-                       pdb &= pdb - 1;
+               while (ldb) {
+                       i = __ffs(ldb);
+                       ldb &= ldb - 1;
                        bwd_callback_msix_irq(irq, &ndev->db_cb[i]);
                }
        } else {
-               u16 pdb = readw(ndev->reg_ofs.pdb);
+               u16 ldb = readw(ndev->reg_ofs.ldb);
 
-               dev_dbg(&ndev->pdev->dev, "irq %d - pdb = %x sdb %x\n", irq,
-                       pdb, readw(ndev->reg_ofs.sdb));
+               dev_dbg(&ndev->pdev->dev, "irq %d - ldb = %x\n", irq, ldb);
 
-               if (pdb & SNB_DB_HW_LINK) {
+               if (ldb & SNB_DB_HW_LINK) {
                        xeon_event_msix_irq(irq, dev);
-                       pdb &= ~SNB_DB_HW_LINK;
+                       ldb &= ~SNB_DB_HW_LINK;
                }
 
-               while (pdb) {
-                       i = __ffs(pdb);
-                       pdb &= pdb - 1;
+               while (ldb) {
+                       i = __ffs(ldb);
+                       ldb &= ldb - 1;
                        xeon_callback_msix_irq(irq, &ndev->db_cb[i]);
                }
        }
@@ -758,16 +1031,15 @@ static int ntb_setup_msix(struct ntb_device *ndev)
        struct pci_dev *pdev = ndev->pdev;
        struct msix_entry *msix;
        int msix_entries;
-       int rc, i, pos;
+       int rc, i;
        u16 val;
 
-       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
-       if (!pos) {
+       if (!pdev->msix_cap) {
                rc = -EIO;
                goto err;
        }
 
-       rc = pci_read_config_word(pdev, pos + PCI_MSIX_FLAGS, &val);
+       rc = pci_read_config_word(pdev, pdev->msix_cap + PCI_MSIX_FLAGS, &val);
        if (rc)
                goto err;
 
@@ -903,10 +1175,10 @@ static int ntb_setup_interrupts(struct ntb_device *ndev)
         * Interrupt.  The rest will be unmasked as callbacks are registered.
         */
        if (ndev->hw_type == BWD_HW)
-               writeq(~0, ndev->reg_ofs.pdb_mask);
+               writeq(~0, ndev->reg_ofs.ldb_mask);
        else
                writew(~(1 << ndev->limits.max_db_bits),
-                      ndev->reg_ofs.pdb_mask);
+                      ndev->reg_ofs.ldb_mask);
 
        rc = ntb_setup_msix(ndev);
        if (!rc)
@@ -935,9 +1207,9 @@ static void ntb_free_interrupts(struct ntb_device *ndev)
 
        /* mask interrupts */
        if (ndev->hw_type == BWD_HW)
-               writeq(~0, ndev->reg_ofs.pdb_mask);
+               writeq(~0, ndev->reg_ofs.ldb_mask);
        else
-               writew(~0, ndev->reg_ofs.pdb_mask);
+               writew(~0, ndev->reg_ofs.ldb_mask);
 
        if (ndev->num_msix) {
                struct msix_entry *msix;
@@ -963,9 +1235,9 @@ static int ntb_create_callbacks(struct ntb_device *ndev)
 {
        int i;
 
-       /* Checken-egg issue.  We won't know how many callbacks are necessary
+       /* Chicken-egg issue.  We won't know how many callbacks are necessary
         * until we see how many MSI-X vectors we get, but these pointers need
-        * to be passed into the MSI-X register fucntion.  So, we allocate the
+        * to be passed into the MSI-X register function.  So, we allocate the
         * max, knowing that they might not all be used, to work around this.
         */
        ndev->db_cb = kcalloc(ndev->limits.max_db_bits,
@@ -992,6 +1264,28 @@ static void ntb_free_callbacks(struct ntb_device *ndev)
        kfree(ndev->db_cb);
 }
 
+static void ntb_setup_debugfs(struct ntb_device *ndev)
+{
+       if (!debugfs_initialized())
+               return;
+
+       if (!debugfs_dir)
+               debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
+
+       ndev->debugfs_dir = debugfs_create_dir(pci_name(ndev->pdev),
+                                              debugfs_dir);
+}
+
+static void ntb_free_debugfs(struct ntb_device *ndev)
+{
+       debugfs_remove_recursive(ndev->debugfs_dir);
+
+       if (debugfs_dir && simple_empty(debugfs_dir)) {
+               debugfs_remove_recursive(debugfs_dir);
+               debugfs_dir = NULL;
+       }
+}
+
 static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct ntb_device *ndev;
@@ -1004,6 +1298,7 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        ndev->pdev = pdev;
        ndev->link_status = NTB_LINK_DOWN;
        pci_set_drvdata(pdev, ndev);
+       ntb_setup_debugfs(ndev);
 
        rc = pci_enable_device(pdev);
        if (rc)
@@ -1022,13 +1317,13 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto err2;
        }
 
-       for (i = 0; i < NTB_NUM_MW; i++) {
+       for (i = 0; i < NTB_MAX_NUM_MW; i++) {
                ndev->mw[i].bar_sz = pci_resource_len(pdev, MW_TO_BAR(i));
                ndev->mw[i].vbase =
                    ioremap_wc(pci_resource_start(pdev, MW_TO_BAR(i)),
                               ndev->mw[i].bar_sz);
                dev_info(&pdev->dev, "MW %d size %llu\n", i,
-                        pci_resource_len(pdev, MW_TO_BAR(i)));
+                        (unsigned long long) ndev->mw[i].bar_sz);
                if (!ndev->mw[i].vbase) {
                        dev_warn(&pdev->dev, "Cannot remap BAR %d\n",
                                 MW_TO_BAR(i));
@@ -1100,6 +1395,7 @@ err2:
 err1:
        pci_disable_device(pdev);
 err:
+       ntb_free_debugfs(ndev);
        kfree(ndev);
 
        dev_err(&pdev->dev, "Error loading %s module\n", KBUILD_MODNAME);
@@ -1114,7 +1410,7 @@ static void ntb_pci_remove(struct pci_dev *pdev)
 
        /* Bring NTB link down */
        ntb_cntl = readl(ndev->reg_ofs.lnk_cntl);
-       ntb_cntl |= NTB_LINK_DISABLE;
+       ntb_cntl |= NTB_CNTL_LINK_DISABLE;
        writel(ntb_cntl, ndev->reg_ofs.lnk_cntl);
 
        ntb_transport_free(ndev->ntb_transport);
@@ -1123,12 +1419,13 @@ static void ntb_pci_remove(struct pci_dev *pdev)
        ntb_free_callbacks(ndev);
        ntb_device_free(ndev);
 
-       for (i = 0; i < NTB_NUM_MW; i++)
+       for (i = 0; i < NTB_MAX_NUM_MW; i++)
                iounmap(ndev->mw[i].vbase);
 
        iounmap(ndev->reg_base);
        pci_release_selected_regions(pdev, NTB_BAR_MASK);
        pci_disable_device(pdev);
+       ntb_free_debugfs(ndev);
        kfree(ndev);
 }
 
index 3a3038ca83e6d4451c910bcbc7cdf48a1fd00213..0a31cedae7d42f9227d125bfabe97297b47255d9 100644 (file)
  */
 
 #define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF                0x3725
-#define PCI_DEVICE_ID_INTEL_NTB_CLASSIC_JSF    0x3726
-#define PCI_DEVICE_ID_INTEL_NTB_RP_JSF         0x3727
-#define PCI_DEVICE_ID_INTEL_NTB_RP_SNB         0x3C08
+#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF         0x3726
+#define PCI_DEVICE_ID_INTEL_NTB_SS_JSF         0x3727
 #define PCI_DEVICE_ID_INTEL_NTB_B2B_SNB                0x3C0D
-#define PCI_DEVICE_ID_INTEL_NTB_CLASSIC_SNB    0x3C0E
-#define PCI_DEVICE_ID_INTEL_NTB_2ND_SNB                0x3C0F
+#define PCI_DEVICE_ID_INTEL_NTB_PS_SNB         0x3C0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_SNB         0x3C0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_IVT                0x0E0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_IVT         0x0E0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_IVT         0x0E0F
+#define PCI_DEVICE_ID_INTEL_NTB_B2B_HSX                0x2F0D
+#define PCI_DEVICE_ID_INTEL_NTB_PS_HSX         0x2F0E
+#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX         0x2F0F
 #define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD                0x0C4E
 
 #define msix_table_size(control)       ((control & PCI_MSIX_FLAGS_QSIZE)+1)
 
+#ifndef readq
+static inline u64 readq(void __iomem *addr)
+{
+       return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
+}
+#endif
+
+#ifndef writeq
+static inline void writeq(u64 val, void __iomem *addr)
+{
+       writel(val & 0xffffffff, addr);
+       writel(val >> 32, addr + 4);
+}
+#endif
+
 #define NTB_BAR_MMIO           0
 #define NTB_BAR_23             2
 #define NTB_BAR_45             4
@@ -68,7 +88,7 @@
 
 #define NTB_HB_TIMEOUT         msecs_to_jiffies(1000)
 
-#define NTB_NUM_MW             2
+#define NTB_MAX_NUM_MW         2
 
 enum ntb_hw_event {
        NTB_EVENT_SW_EVENT0 = 0,
@@ -96,18 +116,19 @@ struct ntb_device {
        struct pci_dev *pdev;
        struct msix_entry *msix_entries;
        void __iomem *reg_base;
-       struct ntb_mw mw[NTB_NUM_MW];
+       struct ntb_mw mw[NTB_MAX_NUM_MW];
        struct {
-               unsigned int max_spads;
-               unsigned int max_db_bits;
-               unsigned int msix_cnt;
+               unsigned char max_mw;
+               unsigned char max_spads;
+               unsigned char max_db_bits;
+               unsigned char msix_cnt;
        } limits;
        struct {
-               void __iomem *pdb;
-               void __iomem *pdb_mask;
-               void __iomem *sdb;
-               void __iomem *sbar2_xlat;
-               void __iomem *sbar4_xlat;
+               void __iomem *ldb;
+               void __iomem *ldb_mask;
+               void __iomem *rdb;
+               void __iomem *bar2_xlat;
+               void __iomem *bar4_xlat;
                void __iomem *spad_write;
                void __iomem *spad_read;
                void __iomem *lnk_cntl;
@@ -124,11 +145,44 @@ struct ntb_device {
        unsigned char num_msix;
        unsigned char bits_per_vector;
        unsigned char max_cbs;
+       unsigned char link_width;
+       unsigned char link_speed;
        unsigned char link_status;
+
        struct delayed_work hb_timer;
        unsigned long last_ts;
+
+       struct delayed_work lr_timer;
+
+       struct dentry *debugfs_dir;
 };
 
+/**
+ * ntb_max_cbs() - return the max callbacks
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the maximum number of callbacks
+ *
+ * RETURNS: the maximum number of callbacks
+ */
+static inline unsigned char ntb_max_cbs(struct ntb_device *ndev)
+{
+       return ndev->max_cbs;
+}
+
+/**
+ * ntb_max_mw() - return the max number of memory windows
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the maximum number of memory windows
+ *
+ * RETURNS: the maximum number of memory windows
+ */
+static inline unsigned char ntb_max_mw(struct ntb_device *ndev)
+{
+       return ndev->limits.max_mw;
+}
+
 /**
  * ntb_hw_link_status() - return the hardware link status
  * @ndev: pointer to ntb_device instance
@@ -146,7 +200,7 @@ static inline bool ntb_hw_link_status(struct ntb_device *ndev)
  * ntb_query_pdev() - return the pci_dev pointer
  * @ndev: pointer to ntb_device instance
  *
- * Given the ntb pointer return the pci_dev pointerfor the NTB hardware device
+ * Given the ntb pointer, return the pci_dev pointer for the NTB hardware device
  *
  * RETURNS: a pointer to the ntb pci_dev
  */
@@ -155,6 +209,20 @@ static inline struct pci_dev *ntb_query_pdev(struct ntb_device *ndev)
        return ndev->pdev;
 }
 
+/**
+ * ntb_query_debugfs() - return the debugfs pointer
+ * @ndev: pointer to ntb_device instance
+ *
+ * Given the ntb pointer, return the debugfs directory pointer for the NTB
+ * hardware device
+ *
+ * RETURNS: a pointer to the debugfs directory
+ */
+static inline struct dentry *ntb_query_debugfs(struct ntb_device *ndev)
+{
+       return ndev->debugfs_dir;
+}
+
 struct ntb_device *ntb_register_transport(struct pci_dev *pdev,
                                          void *transport);
 void ntb_unregister_transport(struct ntb_device *ndev);
@@ -172,9 +240,10 @@ int ntb_write_local_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
 int ntb_read_local_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
 int ntb_write_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 val);
 int ntb_read_remote_spad(struct ntb_device *ndev, unsigned int idx, u32 *val);
+resource_size_t ntb_get_mw_base(struct ntb_device *ndev, unsigned int mw);
 void __iomem *ntb_get_mw_vbase(struct ntb_device *ndev, unsigned int mw);
-resource_size_t ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
-void ntb_ring_sdb(struct ntb_device *ndev, unsigned int idx);
+u64 ntb_get_mw_size(struct ntb_device *ndev, unsigned int mw);
+void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int idx);
 void *ntb_find_transport(struct pci_dev *pdev);
 
 int ntb_transport_init(struct pci_dev *pdev);
index 5bfa8c06c059c92eba1e7feb514fa61bfe53eb12..aa4bdd393c58ee2c4cf40105b1644afdcb19913c 100644 (file)
  * Jon Mason <jon.mason@intel.com>
  */
 
-#define NTB_LINK_ENABLE                0x0000
-#define NTB_LINK_DISABLE       0x0002
 #define NTB_LINK_STATUS_ACTIVE 0x2000
 #define NTB_LINK_SPEED_MASK    0x000f
 #define NTB_LINK_WIDTH_MASK    0x03f0
 
 #define SNB_MSIX_CNT           4
-#define SNB_MAX_SPADS          16
-#define SNB_MAX_COMPAT_SPADS   8
+#define SNB_MAX_B2B_SPADS      16
+#define SNB_MAX_COMPAT_SPADS   16
 /* Reserve the uppermost bit for link interrupt */
 #define SNB_MAX_DB_BITS                15
 #define SNB_DB_BITS_PER_VEC    5
+#define SNB_MAX_MW             2
+#define SNB_ERRATA_MAX_MW      1
 
 #define SNB_DB_HW_LINK         0x8000
 
 #define SNB_PCICMD_OFFSET      0x0504
 #define SNB_DEVCTRL_OFFSET     0x0598
+#define SNB_SLINK_STATUS_OFFSET        0x05A2
 #define SNB_LINK_STATUS_OFFSET 0x01A2
 
 #define SNB_PBAR2LMT_OFFSET    0x0000
@@ -74,6 +75,9 @@
 #define SNB_SBAR2XLAT_OFFSET   0x0030
 #define SNB_SBAR4XLAT_OFFSET   0x0038
 #define SNB_SBAR0BASE_OFFSET   0x0040
+#define SNB_SBAR0BASE_OFFSET   0x0040
+#define SNB_SBAR2BASE_OFFSET   0x0048
+#define SNB_SBAR4BASE_OFFSET   0x0050
 #define SNB_SBAR2BASE_OFFSET   0x0048
 #define SNB_SBAR4BASE_OFFSET   0x0050
 #define SNB_NTBCNTL_OFFSET     0x0058
 #define SNB_WCCNTRL_OFFSET     0x00e0
 #define SNB_B2B_SPAD_OFFSET    0x0100
 #define SNB_B2B_DOORBELL_OFFSET        0x0140
-#define SNB_B2B_XLAT_OFFSET    0x0144
+#define SNB_B2B_XLAT_OFFSETL   0x0144
+#define SNB_B2B_XLAT_OFFSETU   0x0148
+
+#define SNB_MBAR01_USD_ADDR    0x000000210000000CULL
+#define SNB_MBAR23_USD_ADDR    0x000000410000000CULL
+#define SNB_MBAR45_USD_ADDR    0x000000810000000CULL
+#define SNB_MBAR01_DSD_ADDR    0x000000200000000CULL
+#define SNB_MBAR23_DSD_ADDR    0x000000400000000CULL
+#define SNB_MBAR45_DSD_ADDR    0x000000800000000CULL
 
 #define BWD_MSIX_CNT           34
 #define BWD_MAX_SPADS          16
-#define BWD_MAX_COMPAT_SPADS   16
 #define BWD_MAX_DB_BITS                34
 #define BWD_DB_BITS_PER_VEC    1
+#define BWD_MAX_MW             2
 
 #define BWD_PCICMD_OFFSET      0xb004
 #define BWD_MBAR23_OFFSET      0xb018
 #define BWD_MBAR45_OFFSET      0xb020
 #define BWD_DEVCTRL_OFFSET     0xb048
 #define BWD_LINK_STATUS_OFFSET 0xb052
+#define BWD_ERRCORSTS_OFFSET   0xb110
 
 #define BWD_SBAR2XLAT_OFFSET   0x0008
 #define BWD_SBAR4XLAT_OFFSET   0x0010
 #define BWD_B2B_SPADSEMA_OFFSET        0x80c0
 #define BWD_B2B_STKYSPAD_OFFSET        0x80c4
 
+#define BWD_MODPHY_PCSREG4     0x1c004
+#define BWD_MODPHY_PCSREG6     0x1c006
+
+#define BWD_IP_BASE            0xC000
+#define BWD_DESKEWSTS_OFFSET   (BWD_IP_BASE + 0x3024)
+#define BWD_LTSSMERRSTS0_OFFSET (BWD_IP_BASE + 0x3180)
+#define BWD_LTSSMSTATEJMP_OFFSET       (BWD_IP_BASE + 0x3040)
+#define BWD_IBSTERRRCRVSTS0_OFFSET     (BWD_IP_BASE + 0x3324)
+
+#define BWD_DESKEWSTS_DBERR    (1 << 15)
+#define BWD_LTSSMERRSTS0_UNEXPECTEDEI  (1 << 20)
+#define BWD_LTSSMSTATEJMP_FORCEDETECT  (1 << 2)
+#define BWD_IBIST_ERR_OFLOW    0x7FFF7FFF
+
+#define NTB_CNTL_CFG_LOCK      (1 << 0)
+#define NTB_CNTL_LINK_DISABLE  (1 << 1)
 #define NTB_CNTL_BAR23_SNOOP   (1 << 2)
 #define NTB_CNTL_BAR45_SNOOP   (1 << 6)
 #define BWD_CNTL_LINK_DOWN     (1 << 16)
 #define BWD_PPD_INIT_LINK      0x0008
 #define BWD_PPD_CONN_TYPE      0x0300
 #define BWD_PPD_DEV_TYPE       0x1000
-
-#define BWD_PBAR2XLAT_USD_ADDR 0x0000004000000000
-#define BWD_PBAR4XLAT_USD_ADDR 0x0000008000000000
-#define BWD_MBAR23_USD_ADDR    0x000000410000000C
-#define BWD_MBAR45_USD_ADDR    0x000000810000000C
-#define BWD_PBAR2XLAT_DSD_ADDR 0x0000004100000000
-#define BWD_PBAR4XLAT_DSD_ADDR 0x0000008100000000
-#define BWD_MBAR23_DSD_ADDR    0x000000400000000C
-#define BWD_MBAR45_DSD_ADDR    0x000000800000000C
index f8d7081ee3014322e90c767fd766456f5410d311..12a9e83c008b402f0f7acde4e80c742c7795348e 100644 (file)
@@ -47,6 +47,7 @@
  */
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/export.h>
@@ -64,10 +65,14 @@ static unsigned int transport_mtu = 0x401E;
 module_param(transport_mtu, uint, 0644);
 MODULE_PARM_DESC(transport_mtu, "Maximum size of NTB transport packets");
 
-static unsigned char max_num_clients = 2;
+static unsigned char max_num_clients;
 module_param(max_num_clients, byte, 0644);
 MODULE_PARM_DESC(max_num_clients, "Maximum number of NTB transport clients");
 
+static unsigned int copy_bytes = 1024;
+module_param(copy_bytes, uint, 0644);
+MODULE_PARM_DESC(copy_bytes, "Threshold under which NTB will use the CPU to copy instead of DMA");
+
 struct ntb_queue_entry {
        /* ntb_queue list reference */
        struct list_head entry;
@@ -76,6 +81,13 @@ struct ntb_queue_entry {
        void *buf;
        unsigned int len;
        unsigned int flags;
+
+       struct ntb_transport_qp *qp;
+       union {
+               struct ntb_payload_header __iomem *tx_hdr;
+               struct ntb_payload_header *rx_hdr;
+       };
+       unsigned int index;
 };
 
 struct ntb_rx_info {
@@ -86,6 +98,7 @@ struct ntb_transport_qp {
        struct ntb_transport *transport;
        struct ntb_device *ndev;
        void *cb_data;
+       struct dma_chan *dma_chan;
 
        bool client_ready;
        bool qp_link;
@@ -99,6 +112,7 @@ struct ntb_transport_qp {
        struct list_head tx_free_q;
        spinlock_t ntb_tx_free_q_lock;
        void __iomem *tx_mw;
+       dma_addr_t tx_mw_phys;
        unsigned int tx_index;
        unsigned int tx_max_entry;
        unsigned int tx_max_frame;
@@ -114,6 +128,7 @@ struct ntb_transport_qp {
        unsigned int rx_index;
        unsigned int rx_max_entry;
        unsigned int rx_max_frame;
+       dma_cookie_t last_cookie;
 
        void (*event_handler) (void *data, int status);
        struct delayed_work link_work;
@@ -129,9 +144,14 @@ struct ntb_transport_qp {
        u64 rx_err_no_buf;
        u64 rx_err_oflow;
        u64 rx_err_ver;
+       u64 rx_memcpy;
+       u64 rx_async;
        u64 tx_bytes;
        u64 tx_pkts;
        u64 tx_ring_full;
+       u64 tx_err_no_buf;
+       u64 tx_memcpy;
+       u64 tx_async;
 };
 
 struct ntb_transport_mw {
@@ -150,14 +170,13 @@ struct ntb_transport {
        struct list_head client_devs;
 
        struct ntb_device *ndev;
-       struct ntb_transport_mw mw[NTB_NUM_MW];
+       struct ntb_transport_mw *mw;
        struct ntb_transport_qp *qps;
        unsigned int max_qps;
        unsigned long qp_bitmap;
        bool transport_link;
        struct delayed_work link_work;
        struct work_struct link_cleanup;
-       struct dentry *debugfs_dir;
 };
 
 enum {
@@ -183,7 +202,7 @@ enum {
        MAX_SPAD,
 };
 
-#define QP_TO_MW(qp)           ((qp) % NTB_NUM_MW)
+#define QP_TO_MW(ndev, qp)     ((qp) % ntb_max_mw(ndev))
 #define NTB_QP_DEF_NUM_ENTRIES 100
 #define NTB_LINK_DOWN_TIMEOUT  10
 
@@ -382,7 +401,7 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
        char *buf;
        ssize_t ret, out_offset, out_count;
 
-       out_count = 600;
+       out_count = 1000;
 
        buf = kmalloc(out_count, GFP_KERNEL);
        if (!buf)
@@ -396,6 +415,10 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
                               "rx_bytes - \t%llu\n", qp->rx_bytes);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "rx_pkts - \t%llu\n", qp->rx_pkts);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "rx_memcpy - \t%llu\n", qp->rx_memcpy);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "rx_async - \t%llu\n", qp->rx_async);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "rx_ring_empty - %llu\n", qp->rx_ring_empty);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
@@ -415,8 +438,14 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count,
                               "tx_bytes - \t%llu\n", qp->tx_bytes);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "tx_pkts - \t%llu\n", qp->tx_pkts);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "tx_memcpy - \t%llu\n", qp->tx_memcpy);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "tx_async - \t%llu\n", qp->tx_async);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "tx_ring_full - \t%llu\n", qp->tx_ring_full);
+       out_offset += snprintf(buf + out_offset, out_count - out_offset,
+                              "tx_err_no_buf - %llu\n", qp->tx_err_no_buf);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
                               "tx_mw - \t%p\n", qp->tx_mw);
        out_offset += snprintf(buf + out_offset, out_count - out_offset,
@@ -475,22 +504,25 @@ static void ntb_transport_setup_qp_mw(struct ntb_transport *nt,
 {
        struct ntb_transport_qp *qp = &nt->qps[qp_num];
        unsigned int rx_size, num_qps_mw;
-       u8 mw_num = QP_TO_MW(qp_num);
+       u8 mw_num, mw_max;
        unsigned int i;
 
+       mw_max = ntb_max_mw(nt->ndev);
+       mw_num = QP_TO_MW(nt->ndev, qp_num);
+
        WARN_ON(nt->mw[mw_num].virt_addr == NULL);
 
-       if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
-               num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+       if (nt->max_qps % mw_max && mw_num < nt->max_qps % mw_max)
+               num_qps_mw = nt->max_qps / mw_max + 1;
        else
-               num_qps_mw = nt->max_qps / NTB_NUM_MW;
+               num_qps_mw = nt->max_qps / mw_max;
 
        rx_size = (unsigned int) nt->mw[mw_num].size / num_qps_mw;
-       qp->remote_rx_info = nt->mw[mw_num].virt_addr +
-                            (qp_num / NTB_NUM_MW * rx_size);
+       qp->rx_buff = nt->mw[mw_num].virt_addr + qp_num / mw_max * rx_size;
        rx_size -= sizeof(struct ntb_rx_info);
 
-       qp->rx_buff = qp->remote_rx_info + 1;
+       qp->remote_rx_info = qp->rx_buff + rx_size;
+
        /* Due to housekeeping, there must be atleast 2 buffs */
        qp->rx_max_frame = min(transport_mtu, rx_size / 2);
        qp->rx_max_entry = rx_size / qp->rx_max_frame;
@@ -631,7 +663,7 @@ static void ntb_transport_link_work(struct work_struct *work)
        int rc, i;
 
        /* send the local info, in the opposite order of the way we read it */
-       for (i = 0; i < NTB_NUM_MW; i++) {
+       for (i = 0; i < ntb_max_mw(ndev); i++) {
                rc = ntb_write_remote_spad(ndev, MW0_SZ_HIGH + (i * 2),
                                           ntb_get_mw_size(ndev, i) >> 32);
                if (rc) {
@@ -651,10 +683,10 @@ static void ntb_transport_link_work(struct work_struct *work)
                }
        }
 
-       rc = ntb_write_remote_spad(ndev, NUM_MWS, NTB_NUM_MW);
+       rc = ntb_write_remote_spad(ndev, NUM_MWS, ntb_max_mw(ndev));
        if (rc) {
                dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
-                       NTB_NUM_MW, NUM_MWS);
+                       ntb_max_mw(ndev), NUM_MWS);
                goto out;
        }
 
@@ -699,11 +731,11 @@ static void ntb_transport_link_work(struct work_struct *work)
                goto out;
        }
 
-       if (val != NTB_NUM_MW)
+       if (val != ntb_max_mw(ndev))
                goto out;
        dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val);
 
-       for (i = 0; i < NTB_NUM_MW; i++) {
+       for (i = 0; i < ntb_max_mw(ndev); i++) {
                u64 val64;
 
                rc = ntb_read_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), &val);
@@ -745,7 +777,7 @@ static void ntb_transport_link_work(struct work_struct *work)
        return;
 
 out1:
-       for (i = 0; i < NTB_NUM_MW; i++)
+       for (i = 0; i < ntb_max_mw(ndev); i++)
                ntb_free_mw(nt, i);
 out:
        if (ntb_hw_link_status(ndev))
@@ -794,12 +826,16 @@ static void ntb_qp_link_work(struct work_struct *work)
                                      msecs_to_jiffies(NTB_LINK_DOWN_TIMEOUT));
 }
 
-static void ntb_transport_init_queue(struct ntb_transport *nt,
+static int ntb_transport_init_queue(struct ntb_transport *nt,
                                     unsigned int qp_num)
 {
        struct ntb_transport_qp *qp;
        unsigned int num_qps_mw, tx_size;
-       u8 mw_num = QP_TO_MW(qp_num);
+       u8 mw_num, mw_max;
+       u64 qp_offset;
+
+       mw_max = ntb_max_mw(nt->ndev);
+       mw_num = QP_TO_MW(nt->ndev, qp_num);
 
        qp = &nt->qps[qp_num];
        qp->qp_num = qp_num;
@@ -809,27 +845,34 @@ static void ntb_transport_init_queue(struct ntb_transport *nt,
        qp->client_ready = NTB_LINK_DOWN;
        qp->event_handler = NULL;
 
-       if (nt->max_qps % NTB_NUM_MW && mw_num < nt->max_qps % NTB_NUM_MW)
-               num_qps_mw = nt->max_qps / NTB_NUM_MW + 1;
+       if (nt->max_qps % mw_max && mw_num < nt->max_qps % mw_max)
+               num_qps_mw = nt->max_qps / mw_max + 1;
        else
-               num_qps_mw = nt->max_qps / NTB_NUM_MW;
+               num_qps_mw = nt->max_qps / mw_max;
 
        tx_size = (unsigned int) ntb_get_mw_size(qp->ndev, mw_num) / num_qps_mw;
-       qp->rx_info = ntb_get_mw_vbase(nt->ndev, mw_num) +
-                     (qp_num / NTB_NUM_MW * tx_size);
+       qp_offset = qp_num / mw_max * tx_size;
+       qp->tx_mw = ntb_get_mw_vbase(nt->ndev, mw_num) + qp_offset;
+       if (!qp->tx_mw)
+               return -EINVAL;
+
+       qp->tx_mw_phys = ntb_get_mw_base(qp->ndev, mw_num) + qp_offset;
+       if (!qp->tx_mw_phys)
+               return -EINVAL;
+
        tx_size -= sizeof(struct ntb_rx_info);
+       qp->rx_info = qp->tx_mw + tx_size;
 
-       qp->tx_mw = qp->rx_info + 1;
        /* Due to housekeeping, there must be atleast 2 buffs */
        qp->tx_max_frame = min(transport_mtu, tx_size / 2);
        qp->tx_max_entry = tx_size / qp->tx_max_frame;
 
-       if (nt->debugfs_dir) {
+       if (ntb_query_debugfs(nt->ndev)) {
                char debugfs_name[4];
 
                snprintf(debugfs_name, 4, "qp%d", qp_num);
                qp->debugfs_dir = debugfs_create_dir(debugfs_name,
-                                                    nt->debugfs_dir);
+                                                ntb_query_debugfs(nt->ndev));
 
                qp->debugfs_stats = debugfs_create_file("stats", S_IRUSR,
                                                        qp->debugfs_dir, qp,
@@ -846,6 +889,8 @@ static void ntb_transport_init_queue(struct ntb_transport *nt,
        INIT_LIST_HEAD(&qp->rx_pend_q);
        INIT_LIST_HEAD(&qp->rx_free_q);
        INIT_LIST_HEAD(&qp->tx_free_q);
+
+       return 0;
 }
 
 int ntb_transport_init(struct pci_dev *pdev)
@@ -857,30 +902,38 @@ int ntb_transport_init(struct pci_dev *pdev)
        if (!nt)
                return -ENOMEM;
 
-       if (debugfs_initialized())
-               nt->debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       else
-               nt->debugfs_dir = NULL;
-
        nt->ndev = ntb_register_transport(pdev, nt);
        if (!nt->ndev) {
                rc = -EIO;
                goto err;
        }
 
-       nt->max_qps = min(nt->ndev->max_cbs, max_num_clients);
+       nt->mw = kcalloc(ntb_max_mw(nt->ndev), sizeof(struct ntb_transport_mw),
+                        GFP_KERNEL);
+       if (!nt->mw) {
+               rc = -ENOMEM;
+               goto err1;
+       }
+
+       if (max_num_clients)
+               nt->max_qps = min(ntb_max_cbs(nt->ndev), max_num_clients);
+       else
+               nt->max_qps = min(ntb_max_cbs(nt->ndev), ntb_max_mw(nt->ndev));
 
        nt->qps = kcalloc(nt->max_qps, sizeof(struct ntb_transport_qp),
                          GFP_KERNEL);
        if (!nt->qps) {
                rc = -ENOMEM;
-               goto err1;
+               goto err2;
        }
 
        nt->qp_bitmap = ((u64) 1 << nt->max_qps) - 1;
 
-       for (i = 0; i < nt->max_qps; i++)
-               ntb_transport_init_queue(nt, i);
+       for (i = 0; i < nt->max_qps; i++) {
+               rc = ntb_transport_init_queue(nt, i);
+               if (rc)
+                       goto err3;
+       }
 
        INIT_DELAYED_WORK(&nt->link_work, ntb_transport_link_work);
        INIT_WORK(&nt->link_cleanup, ntb_transport_link_cleanup);
@@ -888,26 +941,27 @@ int ntb_transport_init(struct pci_dev *pdev)
        rc = ntb_register_event_callback(nt->ndev,
                                         ntb_transport_event_callback);
        if (rc)
-               goto err2;
+               goto err3;
 
        INIT_LIST_HEAD(&nt->client_devs);
        rc = ntb_bus_init(nt);
        if (rc)
-               goto err3;
+               goto err4;
 
        if (ntb_hw_link_status(nt->ndev))
                schedule_delayed_work(&nt->link_work, 0);
 
        return 0;
 
-err3:
+err4:
        ntb_unregister_event_callback(nt->ndev);
-err2:
+err3:
        kfree(nt->qps);
+err2:
+       kfree(nt->mw);
 err1:
        ntb_unregister_transport(nt->ndev);
 err:
-       debugfs_remove_recursive(nt->debugfs_dir);
        kfree(nt);
        return rc;
 }
@@ -915,41 +969,46 @@ err:
 void ntb_transport_free(void *transport)
 {
        struct ntb_transport *nt = transport;
-       struct pci_dev *pdev;
+       struct ntb_device *ndev = nt->ndev;
        int i;
 
        nt->transport_link = NTB_LINK_DOWN;
 
        /* verify that all the qp's are freed */
-       for (i = 0; i < nt->max_qps; i++)
+       for (i = 0; i < nt->max_qps; i++) {
                if (!test_bit(i, &nt->qp_bitmap))
                        ntb_transport_free_queue(&nt->qps[i]);
+               debugfs_remove_recursive(nt->qps[i].debugfs_dir);
+       }
 
        ntb_bus_remove(nt);
 
        cancel_delayed_work_sync(&nt->link_work);
 
-       debugfs_remove_recursive(nt->debugfs_dir);
-
-       ntb_unregister_event_callback(nt->ndev);
-
-       pdev = ntb_query_pdev(nt->ndev);
+       ntb_unregister_event_callback(ndev);
 
-       for (i = 0; i < NTB_NUM_MW; i++)
+       for (i = 0; i < ntb_max_mw(ndev); i++)
                ntb_free_mw(nt, i);
 
        kfree(nt->qps);
-       ntb_unregister_transport(nt->ndev);
+       kfree(nt->mw);
+       ntb_unregister_transport(ndev);
        kfree(nt);
 }
 
-static void ntb_rx_copy_task(struct ntb_transport_qp *qp,
-                            struct ntb_queue_entry *entry, void *offset)
+static void ntb_rx_copy_callback(void *data)
 {
+       struct ntb_queue_entry *entry = data;
+       struct ntb_transport_qp *qp = entry->qp;
        void *cb_data = entry->cb_data;
        unsigned int len = entry->len;
+       struct ntb_payload_header *hdr = entry->rx_hdr;
 
-       memcpy(entry->buf, offset, entry->len);
+       /* Ensure that the data is fully copied out before clearing the flag */
+       wmb();
+       hdr->flags = 0;
+
+       iowrite32(entry->index, &qp->rx_info->entry);
 
        ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry, &qp->rx_free_q);
 
@@ -957,6 +1016,86 @@ static void ntb_rx_copy_task(struct ntb_transport_qp *qp,
                qp->rx_handler(qp, qp->cb_data, cb_data, len);
 }
 
+static void ntb_memcpy_rx(struct ntb_queue_entry *entry, void *offset)
+{
+       void *buf = entry->buf;
+       size_t len = entry->len;
+
+       memcpy(buf, offset, len);
+
+       ntb_rx_copy_callback(entry);
+}
+
+static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset,
+                        size_t len)
+{
+       struct dma_async_tx_descriptor *txd;
+       struct ntb_transport_qp *qp = entry->qp;
+       struct dma_chan *chan = qp->dma_chan;
+       struct dma_device *device;
+       size_t pay_off, buff_off;
+       dma_addr_t src, dest;
+       dma_cookie_t cookie;
+       void *buf = entry->buf;
+       unsigned long flags;
+
+       entry->len = len;
+
+       if (!chan)
+               goto err;
+
+       if (len < copy_bytes) 
+               goto err1;
+
+       device = chan->device;
+       pay_off = (size_t) offset & ~PAGE_MASK;
+       buff_off = (size_t) buf & ~PAGE_MASK;
+
+       if (!is_dma_copy_aligned(device, pay_off, buff_off, len))
+               goto err1;
+
+       dest = dma_map_single(device->dev, buf, len, DMA_FROM_DEVICE);
+       if (dma_mapping_error(device->dev, dest))
+               goto err1;
+
+       src = dma_map_single(device->dev, offset, len, DMA_TO_DEVICE);
+       if (dma_mapping_error(device->dev, src))
+               goto err2;
+
+       flags = DMA_COMPL_DEST_UNMAP_SINGLE | DMA_COMPL_SRC_UNMAP_SINGLE |
+               DMA_PREP_INTERRUPT;
+       txd = device->device_prep_dma_memcpy(chan, dest, src, len, flags);
+       if (!txd)
+               goto err3;
+
+       txd->callback = ntb_rx_copy_callback;
+       txd->callback_param = entry;
+
+       cookie = dmaengine_submit(txd);
+       if (dma_submit_error(cookie))
+               goto err3;
+
+       qp->last_cookie = cookie;
+
+       qp->rx_async++;
+
+       return;
+
+err3:
+       dma_unmap_single(device->dev, src, len, DMA_TO_DEVICE);
+err2:
+       dma_unmap_single(device->dev, dest, len, DMA_FROM_DEVICE);
+err1:
+       /* If the callbacks come out of order, the writing of the index to the
+        * last completed will be out of order.  This may result in the
+        * receive stalling forever.
+        */
+       dma_sync_wait(chan, qp->last_cookie);
+err:
+       ntb_memcpy_rx(entry, offset);
+       qp->rx_memcpy++;
+}
+
 static int ntb_process_rxc(struct ntb_transport_qp *qp)
 {
        struct ntb_payload_header *hdr;
@@ -995,41 +1134,45 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
        if (hdr->flags & LINK_DOWN_FLAG) {
                ntb_qp_link_down(qp);
 
-               ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
-                            &qp->rx_pend_q);
-               goto out;
+               goto err;
        }
 
        dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
                "rx offset %u, ver %u - %d payload received, buf size %d\n",
                qp->rx_index, hdr->ver, hdr->len, entry->len);
 
-       if (hdr->len <= entry->len) {
-               entry->len = hdr->len;
-               ntb_rx_copy_task(qp, entry, offset);
-       } else {
-               ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
-                            &qp->rx_pend_q);
+       qp->rx_bytes += hdr->len;
+       qp->rx_pkts++;
 
+       if (hdr->len > entry->len) {
                qp->rx_err_oflow++;
                dev_dbg(&ntb_query_pdev(qp->ndev)->dev,
                        "RX overflow! Wanted %d got %d\n",
                        hdr->len, entry->len);
+
+               goto err;
        }
 
-       qp->rx_bytes += hdr->len;
-       qp->rx_pkts++;
+       entry->index = qp->rx_index;
+       entry->rx_hdr = hdr;
+
+       ntb_async_rx(entry, offset, hdr->len);
 
 out:
+       qp->rx_index++;
+       qp->rx_index %= qp->rx_max_entry;
+
+       return 0;
+
+err:
+       ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
+                    &qp->rx_pend_q);
        /* Ensure that the data is fully copied out before clearing the flag */
        wmb();
        hdr->flags = 0;
        iowrite32(qp->rx_index, &qp->rx_info->entry);
 
-       qp->rx_index++;
-       qp->rx_index %= qp->rx_max_entry;
-
-       return 0;
+       goto out;
 }
 
 static void ntb_transport_rx(unsigned long data)
@@ -1045,6 +1188,9 @@ static void ntb_transport_rx(unsigned long data)
                if (rc)
                        break;
        }
+
+       if (qp->dma_chan)
+               dma_async_issue_pending(qp->dma_chan);
 }
 
 static void ntb_transport_rxc_db(void *data, int db_num)
@@ -1057,23 +1203,17 @@ static void ntb_transport_rxc_db(void *data, int db_num)
        tasklet_schedule(&qp->rx_work);
 }
 
-static void ntb_tx_copy_task(struct ntb_transport_qp *qp,
-                            struct ntb_queue_entry *entry,
-                            void __iomem *offset)
+static void ntb_tx_copy_callback(void *data)
 {
-       struct ntb_payload_header __iomem *hdr;
+       struct ntb_queue_entry *entry = data;
+       struct ntb_transport_qp *qp = entry->qp;
+       struct ntb_payload_header __iomem *hdr = entry->tx_hdr;
 
-       memcpy_toio(offset, entry->buf, entry->len);
-
-       hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header);
-       iowrite32(entry->len, &hdr->len);
-       iowrite32((u32) qp->tx_pkts, &hdr->ver);
-
-       /* Ensure that the data is fully copied out before setting the flag */
+       /* Ensure that the data is fully copied out before setting the flags */
        wmb();
        iowrite32(entry->flags | DESC_DONE_FLAG, &hdr->flags);
 
-       ntb_ring_sdb(qp->ndev, qp->qp_num);
+       ntb_ring_doorbell(qp->ndev, qp->qp_num);
 
        /* The entry length can only be zero if the packet is intended to be a
         * "link down" or similar.  Since no payload is being sent in these
@@ -1090,15 +1230,81 @@ static void ntb_tx_copy_task(struct ntb_transport_qp *qp,
        ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q);
 }
 
-static int ntb_process_tx(struct ntb_transport_qp *qp,
-                         struct ntb_queue_entry *entry)
+static void ntb_memcpy_tx(struct ntb_queue_entry *entry, void __iomem *offset)
+{
+       memcpy_toio(offset, entry->buf, entry->len);
+
+       ntb_tx_copy_callback(entry);
+}
+
+static void ntb_async_tx(struct ntb_transport_qp *qp,
+                        struct ntb_queue_entry *entry)
 {
+       struct ntb_payload_header __iomem *hdr;
+       struct dma_async_tx_descriptor *txd;
+       struct dma_chan *chan = qp->dma_chan;
+       struct dma_device *device;
+       size_t dest_off, buff_off;
+       dma_addr_t src, dest;
+       dma_cookie_t cookie;
        void __iomem *offset;
+       size_t len = entry->len;
+       void *buf = entry->buf;
+       unsigned long flags;
 
        offset = qp->tx_mw + qp->tx_max_frame * qp->tx_index;
+       hdr = offset + qp->tx_max_frame - sizeof(struct ntb_payload_header);
+       entry->tx_hdr = hdr;
+
+       iowrite32(entry->len, &hdr->len);
+       iowrite32((u32) qp->tx_pkts, &hdr->ver);
+
+       if (!chan)
+               goto err;
+
+       if (len < copy_bytes)
+               goto err;
+
+       device = chan->device;
+       dest = qp->tx_mw_phys + qp->tx_max_frame * qp->tx_index;
+       buff_off = (size_t) buf & ~PAGE_MASK;
+       dest_off = (size_t) dest & ~PAGE_MASK;
+
+       if (!is_dma_copy_aligned(device, buff_off, dest_off, len))
+               goto err;
+
+       src = dma_map_single(device->dev, buf, len, DMA_TO_DEVICE);
+       if (dma_mapping_error(device->dev, src))
+               goto err;
+
+       flags = DMA_COMPL_SRC_UNMAP_SINGLE | DMA_PREP_INTERRUPT;
+       txd = device->device_prep_dma_memcpy(chan, dest, src, len, flags);
+       if (!txd)
+               goto err1;
+
+       txd->callback = ntb_tx_copy_callback;
+       txd->callback_param = entry;
+
+       cookie = dmaengine_submit(txd);
+       if (dma_submit_error(cookie))
+               goto err1;
+
+       dma_async_issue_pending(chan);
+       qp->tx_async++;
 
-       dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%lld - offset %p, tx %u, entry len %d flags %x buff %p\n",
-               qp->tx_pkts, offset, qp->tx_index, entry->len, entry->flags,
+       return;
+err1:
+       dma_unmap_single(device->dev, src, len, DMA_TO_DEVICE);
+err:
+       ntb_memcpy_tx(entry, offset);
+       qp->tx_memcpy++;
+}
+
+static int ntb_process_tx(struct ntb_transport_qp *qp,
+                         struct ntb_queue_entry *entry)
+{
+       dev_dbg(&ntb_query_pdev(qp->ndev)->dev, "%lld - tx %u, entry len %d flags %x buff %p\n",
+               qp->tx_pkts, qp->tx_index, entry->len, entry->flags,
                entry->buf);
        if (qp->tx_index == qp->remote_rx_info->entry) {
                qp->tx_ring_full++;
@@ -1114,7 +1320,7 @@ static int ntb_process_tx(struct ntb_transport_qp *qp,
                return 0;
        }
 
-       ntb_tx_copy_task(qp, entry, offset);
+       ntb_async_tx(qp, entry);
 
        qp->tx_index++;
        qp->tx_index %= qp->tx_max_entry;
@@ -1200,11 +1406,18 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
        qp->tx_handler = handlers->tx_handler;
        qp->event_handler = handlers->event_handler;
 
+       qp->dma_chan = dma_find_channel(DMA_MEMCPY);
+       if (!qp->dma_chan)
+               dev_info(&pdev->dev, "Unable to allocate DMA channel, using CPU instead\n");
+       else
+               dmaengine_get();
+
        for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) {
                entry = kzalloc(sizeof(struct ntb_queue_entry), GFP_ATOMIC);
                if (!entry)
                        goto err1;
 
+               entry->qp = qp;
                ntb_list_add(&qp->ntb_rx_free_q_lock, &entry->entry,
                             &qp->rx_free_q);
        }
@@ -1214,6 +1427,7 @@ ntb_transport_create_queue(void *data, struct pci_dev *pdev,
                if (!entry)
                        goto err2;
 
+               entry->qp = qp;
                ntb_list_add(&qp->ntb_tx_free_q_lock, &entry->entry,
                             &qp->tx_free_q);
        }
@@ -1259,11 +1473,26 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp)
 
        pdev = ntb_query_pdev(qp->ndev);
 
-       cancel_delayed_work_sync(&qp->link_work);
+       if (qp->dma_chan) {
+               struct dma_chan *chan = qp->dma_chan;
+               /* Putting the dma_chan to NULL will force any new traffic to be
+                * processed by the CPU instead of the DAM engine
+                */
+               qp->dma_chan = NULL;
+
+               /* Try to be nice and wait for any queued DMA engine
+                * transactions to process before smashing it with a rock
+                */
+               dma_sync_wait(chan, qp->last_cookie);
+               dmaengine_terminate_all(chan);
+               dmaengine_put();
+       }
 
        ntb_unregister_db_callback(qp->ndev, qp->qp_num);
        tasklet_disable(&qp->rx_work);
 
+       cancel_delayed_work_sync(&qp->link_work);
+
        while ((entry = ntb_list_rm(&qp->ntb_rx_free_q_lock, &qp->rx_free_q)))
                kfree(entry);
 
@@ -1354,7 +1583,7 @@ EXPORT_SYMBOL_GPL(ntb_transport_rx_enqueue);
  * @len: length of the data buffer
  *
  * Enqueue a new transmit buffer onto the transport queue from which a NTB
- * payload will be transmitted.  This assumes that a lock is behing held to
+ * payload will be transmitted.  This assumes that a lock is being held to
  * serialize access to the qp.
  *
  * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
@@ -1369,8 +1598,10 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data,
                return -EINVAL;
 
        entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q);
-       if (!entry)
+       if (!entry) {
+               qp->tx_err_no_buf++;
                return -ENOMEM;
+       }
 
        entry->cb_data = cb;
        entry->buf = data;
@@ -1410,7 +1641,7 @@ EXPORT_SYMBOL_GPL(ntb_transport_link_up);
  *
  * Notify NTB transport layer of client's desire to no longer receive data on
  * transport queue specified.  It is the client's responsibility to ensure all
- * entries on queue are purged or otherwise handled appropraitely.
+ * entries on queue are purged or otherwise handled appropriately.
  */
 void ntb_transport_link_down(struct ntb_transport_qp *qp)
 {
@@ -1486,9 +1717,18 @@ EXPORT_SYMBOL_GPL(ntb_transport_qp_num);
  */
 unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp)
 {
+       unsigned int max;
+
        if (!qp)
                return 0;
 
-       return qp->tx_max_frame - sizeof(struct ntb_payload_header);
+       if (!qp->dma_chan)
+               return qp->tx_max_frame - sizeof(struct ntb_payload_header);
+
+       /* If DMA engine usage is possible, try to find the max size for that */
+       max = qp->tx_max_frame - sizeof(struct ntb_payload_header);
+       max -= max % (1 << qp->dma_chan->device->copy_align);
+
+       return max;
 }
 EXPORT_SYMBOL_GPL(ntb_transport_max_size);
index 78cc76053328c2c8c70bff559f5dc0f903a241df..9d2009a9004d14bc6f80bc9e6192a478fc9362aa 100644 (file)
@@ -74,4 +74,10 @@ config OF_MTD
        depends on MTD
        def_bool y
 
+config OF_RESERVED_MEM
+       depends on OF_FLATTREE && (DMA_CMA || (HAVE_GENERIC_DMA_COHERENT && HAVE_MEMBLOCK))
+       def_bool y
+       help
+         Initialization code for DMA reserved memory
+
 endmenu # OF
index efd05102c40533100794b7d6a7626f583a1f0cdc..ed9660adad7751357b49914fcb046fa64470767c 100644 (file)
@@ -9,3 +9,4 @@ obj-$(CONFIG_OF_MDIO)   += of_mdio.o
 obj-$(CONFIG_OF_PCI)   += of_pci.o
 obj-$(CONFIG_OF_PCI_IRQ)  += of_pci_irq.o
 obj-$(CONFIG_OF_MTD)   += of_mtd.o
+obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
index e486e416d5a08303271e5af402218a26f1f93779..865d3f66c86b2735810e1f6d4d7a219dfd9b350e 100644 (file)
@@ -1176,65 +1176,10 @@ int of_property_count_strings(struct device_node *np, const char *propname)
 }
 EXPORT_SYMBOL_GPL(of_property_count_strings);
 
-/**
- * of_parse_phandle - Resolve a phandle property to a device_node pointer
- * @np: Pointer to device node holding phandle property
- * @phandle_name: Name of property holding a phandle value
- * @index: For properties holding a table of phandles, this is the index into
- *         the table
- *
- * Returns the device_node pointer with refcount incremented.  Use
- * of_node_put() on it when done.
- */
-struct device_node *of_parse_phandle(const struct device_node *np,
-                                    const char *phandle_name, int index)
-{
-       const __be32 *phandle;
-       int size;
-
-       phandle = of_get_property(np, phandle_name, &size);
-       if ((!phandle) || (size < sizeof(*phandle) * (index + 1)))
-               return NULL;
-
-       return of_find_node_by_phandle(be32_to_cpup(phandle + index));
-}
-EXPORT_SYMBOL(of_parse_phandle);
-
-/**
- * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
- * @np:                pointer to a device tree node containing a list
- * @list_name: property name that contains a list
- * @cells_name:        property name that specifies phandles' arguments count
- * @index:     index of a phandle to parse out
- * @out_args:  optional pointer to output arguments structure (will be filled)
- *
- * This function is useful to parse lists of phandles and their arguments.
- * Returns 0 on success and fills out_args, on error returns appropriate
- * errno value.
- *
- * Caller is responsible to call of_node_put() on the returned out_args->node
- * pointer.
- *
- * Example:
- *
- * phandle1: node1 {
- *     #list-cells = <2>;
- * }
- *
- * phandle2: node2 {
- *     #list-cells = <1>;
- * }
- *
- * node3 {
- *     list = <&phandle1 1 2 &phandle2 3>;
- * }
- *
- * To get a device_node of the `node2' node you may call this:
- * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
- */
 static int __of_parse_phandle_with_args(const struct device_node *np,
                                        const char *list_name,
-                                       const char *cells_name, int index,
+                                       const char *cells_name,
+                                       int cell_count, int index,
                                        struct of_phandle_args *out_args)
 {
        const __be32 *list, *list_end;
@@ -1262,19 +1207,32 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
                if (phandle) {
                        /*
                         * Find the provider node and parse the #*-cells
-                        * property to determine the argument length
+                        * property to determine the argument length.
+                        *
+                        * This is not needed if the cell count is hard-coded
+                        * (i.e. cells_name not set, but cell_count is set),
+                        * except when we're going to return the found node
+                        * below.
                         */
-                       node = of_find_node_by_phandle(phandle);
-                       if (!node) {
-                               pr_err("%s: could not find phandle\n",
-                                        np->full_name);
-                               goto err;
+                       if (cells_name || cur_index == index) {
+                               node = of_find_node_by_phandle(phandle);
+                               if (!node) {
+                                       pr_err("%s: could not find phandle\n",
+                                               np->full_name);
+                                       goto err;
+                               }
                        }
-                       if (of_property_read_u32(node, cells_name, &count)) {
-                               pr_err("%s: could not get %s for %s\n",
-                                        np->full_name, cells_name,
-                                        node->full_name);
-                               goto err;
+
+                       if (cells_name) {
+                               if (of_property_read_u32(node, cells_name,
+                                                        &count)) {
+                                       pr_err("%s: could not get %s for %s\n",
+                                               np->full_name, cells_name,
+                                               node->full_name);
+                                       goto err;
+                               }
+                       } else {
+                               count = cell_count;
                        }
 
                        /*
@@ -1334,16 +1292,116 @@ static int __of_parse_phandle_with_args(const struct device_node *np,
        return rc;
 }
 
+/**
+ * of_parse_phandle - Resolve a phandle property to a device_node pointer
+ * @np: Pointer to device node holding phandle property
+ * @phandle_name: Name of property holding a phandle value
+ * @index: For properties holding a table of phandles, this is the index into
+ *         the table
+ *
+ * Returns the device_node pointer with refcount incremented.  Use
+ * of_node_put() on it when done.
+ */
+struct device_node *of_parse_phandle(const struct device_node *np,
+                                    const char *phandle_name, int index)
+{
+       struct of_phandle_args args;
+
+       if (index < 0)
+               return NULL;
+
+       if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0,
+                                        index, &args))
+               return NULL;
+
+       return args.np;
+}
+EXPORT_SYMBOL(of_parse_phandle);
+
+/**
+ * of_parse_phandle_with_args() - Find a node pointed by phandle in a list
+ * @np:                pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name:        property name that specifies phandles' arguments count
+ * @index:     index of a phandle to parse out
+ * @out_args:  optional pointer to output arguments structure (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_args, on error returns appropriate
+ * errno value.
+ *
+ * Caller is responsible to call of_node_put() on the returned out_args->node
+ * pointer.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ *     #list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ *     #list-cells = <1>;
+ * }
+ *
+ * node3 {
+ *     list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
+ */
 int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
                                const char *cells_name, int index,
                                struct of_phandle_args *out_args)
 {
        if (index < 0)
                return -EINVAL;
-       return __of_parse_phandle_with_args(np, list_name, cells_name, index, out_args);
+       return __of_parse_phandle_with_args(np, list_name, cells_name, 0,
+                                           index, out_args);
 }
 EXPORT_SYMBOL(of_parse_phandle_with_args);
 
+/**
+ * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list
+ * @np:                pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cell_count: number of argument cells following the phandle
+ * @index:     index of a phandle to parse out
+ * @out_args:  optional pointer to output arguments structure (will be filled)
+ *
+ * This function is useful to parse lists of phandles and their arguments.
+ * Returns 0 on success and fills out_args, on error returns appropriate
+ * errno value.
+ *
+ * Caller is responsible to call of_node_put() on the returned out_args->node
+ * pointer.
+ *
+ * Example:
+ *
+ * phandle1: node1 {
+ * }
+ *
+ * phandle2: node2 {
+ * }
+ *
+ * node3 {
+ *     list = <&phandle1 0 2 &phandle2 2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args);
+ */
+int of_parse_phandle_with_fixed_args(const struct device_node *np,
+                               const char *list_name, int cell_count,
+                               int index, struct of_phandle_args *out_args)
+{
+       if (index < 0)
+               return -EINVAL;
+       return __of_parse_phandle_with_args(np, list_name, NULL, cell_count,
+                                          index, out_args);
+}
+EXPORT_SYMBOL(of_parse_phandle_with_fixed_args);
+
 /**
  * of_count_phandle_with_args() - Find the number of phandles references in a property
  * @np:                pointer to a device tree node containing a list
@@ -1362,7 +1420,8 @@ EXPORT_SYMBOL(of_parse_phandle_with_args);
 int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
                                const char *cells_name)
 {
-       return __of_parse_phandle_with_args(np, list_name, cells_name, -1, NULL);
+       return __of_parse_phandle_with_args(np, list_name, cells_name, 0, -1,
+                                           NULL);
 }
 EXPORT_SYMBOL(of_count_phandle_with_args);
 
@@ -1734,6 +1793,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
                ap = dt_alloc(sizeof(*ap) + len + 1, 4);
                if (!ap)
                        continue;
+               memset(ap, 0, sizeof(*ap) + len + 1);
                ap->alias = start;
                of_alias_add(ap, np, id, start, len);
        }
index b10ba00cc3e6d00f476fc99e1f35daa26f5ae2e6..229dd9d69e180529cc7e3135d71001421ab9deea 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/initrd.h>
+#include <linux/memblock.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/random.h>
 
 #include <asm/setup.h>  /* for COMMAND_LINE_SIZE */
 #ifdef CONFIG_PPC
@@ -125,13 +127,13 @@ int of_fdt_match(struct boot_param_header *blob, unsigned long node,
        return score;
 }
 
-static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
+static void *unflatten_dt_alloc(void **mem, unsigned long size,
                                       unsigned long align)
 {
        void *res;
 
-       *mem = ALIGN(*mem, align);
-       res = (void *)*mem;
+       *mem = PTR_ALIGN(*mem, align);
+       res = *mem;
        *mem += size;
 
        return res;
@@ -146,9 +148,9 @@ static void *unflatten_dt_alloc(unsigned long *mem, unsigned long size,
  * @allnextpp: pointer to ->allnext from last allocated device_node
  * @fpsize: Size of the node path up at the current depth.
  */
-static unsigned long unflatten_dt_node(struct boot_param_header *blob,
-                               unsigned long mem,
-                               unsigned long *p,
+static void * unflatten_dt_node(struct boot_param_header *blob,
+                               void *mem,
+                               void **p,
                                struct device_node *dad,
                                struct device_node ***allnextpp,
                                unsigned long fpsize)
@@ -161,15 +163,15 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
        int has_name = 0;
        int new_format = 0;
 
-       tag = be32_to_cpup((__be32 *)(*p));
+       tag = be32_to_cpup(*p);
        if (tag != OF_DT_BEGIN_NODE) {
                pr_err("Weird tag at start of node: %x\n", tag);
                return mem;
        }
        *p += 4;
-       pathp = (char *)*p;
+       pathp = *p;
        l = allocl = strlen(pathp) + 1;
-       *p = ALIGN(*p + l, 4);
+       *p = PTR_ALIGN(*p + l, 4);
 
        /* version 0x10 has a more compact unit name here instead of the full
         * path. we accumulate the full path size using "fpsize", we'll rebuild
@@ -201,7 +203,6 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                                __alignof__(struct device_node));
        if (allnextpp) {
                char *fn;
-               memset(np, 0, sizeof(*np));
                np->full_name = fn = ((char *)np) + sizeof(*np);
                if (new_format) {
                        /* rebuild full path for new format */
@@ -239,7 +240,7 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                u32 sz, noff;
                char *pname;
 
-               tag = be32_to_cpup((__be32 *)(*p));
+               tag = be32_to_cpup(*p);
                if (tag == OF_DT_NOP) {
                        *p += 4;
                        continue;
@@ -247,11 +248,11 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                if (tag != OF_DT_PROP)
                        break;
                *p += 4;
-               sz = be32_to_cpup((__be32 *)(*p));
-               noff = be32_to_cpup((__be32 *)((*p) + 4));
+               sz = be32_to_cpup(*p);
+               noff = be32_to_cpup(*p + 4);
                *p += 8;
                if (be32_to_cpu(blob->version) < 0x10)
-                       *p = ALIGN(*p, sz >= 8 ? 8 : 4);
+                       *p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4);
 
                pname = of_fdt_get_string(blob, noff);
                if (pname == NULL) {
@@ -281,11 +282,11 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                                np->phandle = be32_to_cpup((__be32 *)*p);
                        pp->name = pname;
                        pp->length = sz;
-                       pp->value = (void *)*p;
+                       pp->value = *p;
                        *prev_pp = pp;
                        prev_pp = &pp->next;
                }
-               *p = ALIGN((*p) + sz, 4);
+               *p = PTR_ALIGN((*p) + sz, 4);
        }
        /* with version 0x10 we may not have the name property, recreate
         * it here from the unit name if absent
@@ -334,7 +335,7 @@ static unsigned long unflatten_dt_node(struct boot_param_header *blob,
                else
                        mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
                                                fpsize);
-               tag = be32_to_cpup((__be32 *)(*p));
+               tag = be32_to_cpup(*p);
        }
        if (tag != OF_DT_END_NODE) {
                pr_err("Weird tag at end of node: %x\n", tag);
@@ -360,7 +361,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
                             struct device_node **mynodes,
                             void * (*dt_alloc)(u64 size, u64 align))
 {
-       unsigned long start, mem, size;
+       unsigned long size;
+       void *start, *mem;
        struct device_node **allnextp = mynodes;
 
        pr_debug(" -> unflatten_device_tree()\n");
@@ -381,32 +383,28 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
        }
 
        /* First pass, scan for size */
-       start = ((unsigned long)blob) +
-               be32_to_cpu(blob->off_dt_struct);
-       size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
-       size = (size | 3) + 1;
+       start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
+       size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
+       size = ALIGN(size, 4);
 
        pr_debug("  size is %lx, allocating...\n", size);
 
        /* Allocate memory for the expanded device tree */
-       mem = (unsigned long)
-               dt_alloc(size + 4, __alignof__(struct device_node));
+       mem = dt_alloc(size + 4, __alignof__(struct device_node));
+       memset(mem, 0, size);
 
-       memset((void *)mem, 0, size);
+       *(__be32 *)(mem + size) = cpu_to_be32(0xdeadbeef);
 
-       ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
-
-       pr_debug("  unflattening %lx...\n", mem);
+       pr_debug("  unflattening %p...\n", mem);
 
        /* Second pass, do actual unflattening */
-       start = ((unsigned long)blob) +
-               be32_to_cpu(blob->off_dt_struct);
+       start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
        unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
-       if (be32_to_cpup((__be32 *)start) != OF_DT_END)
-               pr_warning("Weird tag at end of tree: %08x\n", *((u32 *)start));
-       if (be32_to_cpu(((__be32 *)mem)[size / 4]) != 0xdeadbeef)
+       if (be32_to_cpup(start) != OF_DT_END)
+               pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start));
+       if (be32_to_cpup(mem + size) != 0xdeadbeef)
                pr_warning("End of tree marker overwritten: %08x\n",
-                          be32_to_cpu(((__be32 *)mem)[size / 4]));
+                          be32_to_cpup(mem + size));
        *allnextp = NULL;
 
        pr_debug(" <- unflatten_device_tree()\n");
@@ -545,6 +543,82 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
        return of_fdt_match(initial_boot_params, node, compat);
 }
 
+struct fdt_scan_status {
+       const char *name;
+       int namelen;
+       int depth;
+       int found;
+       int (*iterator)(unsigned long node, const char *uname, int depth, void *data);
+       void *data;
+};
+
+/**
+ * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
+ */
+static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
+                                       int depth, void *data)
+{
+       struct fdt_scan_status *st = data;
+
+       /*
+        * if scan at the requested fdt node has been completed,
+        * return -ENXIO to abort further scanning
+        */
+       if (depth <= st->depth)
+               return -ENXIO;
+
+       /* requested fdt node has been found, so call iterator function */
+       if (st->found)
+               return st->iterator(node, uname, depth, st->data);
+
+       /* check if scanning automata is entering next level of fdt nodes */
+       if (depth == st->depth + 1 &&
+           strncmp(st->name, uname, st->namelen) == 0 &&
+           uname[st->namelen] == 0) {
+               st->depth += 1;
+               if (st->name[st->namelen] == 0) {
+                       st->found = 1;
+               } else {
+                       const char *next = st->name + st->namelen + 1;
+                       st->name = next;
+                       st->namelen = strcspn(next, "/");
+               }
+               return 0;
+       }
+
+       /* scan next fdt node */
+       return 0;
+}
+
+/**
+ * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
+ *                          child of the given path.
+ * @path: path to start searching for children
+ * @it: callback function
+ * @data: context data pointer
+ *
+ * This function is used to scan the flattened device-tree starting from the
+ * node given by path. It is used to extract information (like reserved
+ * memory), which is required on ealy boot before we can unflatten the tree.
+ */
+int __init of_scan_flat_dt_by_path(const char *path,
+       int (*it)(unsigned long node, const char *name, int depth, void *data),
+       void *data)
+{
+       struct fdt_scan_status st = {path, 0, -1, 0, it, data};
+       int ret = 0;
+
+       if (initial_boot_params)
+                ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
+
+       if (!st.found)
+               return -ENOENT;
+       else if (ret == -ENXIO) /* scan has been completed */
+               return 0;
+       else
+               return ret;
+}
+
 #ifdef CONFIG_BLK_DEV_INITRD
 /**
  * early_init_dt_check_for_initrd - Decode initrd location from flat tree
@@ -552,7 +626,8 @@ int __init of_flat_dt_match(unsigned long node, const char *const *compat)
  */
 void __init early_init_dt_check_for_initrd(unsigned long node)
 {
-       unsigned long start, end, len;
+       u64 start, end;
+       unsigned long len;
        __be32 *prop;
 
        pr_debug("Looking for initrd properties... ");
@@ -560,15 +635,16 @@ void __init early_init_dt_check_for_initrd(unsigned long node)
        prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
        if (!prop)
                return;
-       start = of_read_ulong(prop, len/4);
+       start = of_read_number(prop, len/4);
 
        prop = of_get_flat_dt_prop(node, "linux,initrd-end", &len);
        if (!prop)
                return;
-       end = of_read_ulong(prop, len/4);
+       end = of_read_number(prop, len/4);
 
        early_init_dt_setup_initrd_arch(start, end);
-       pr_debug("initrd_start=0x%lx  initrd_end=0x%lx\n", start, end);
+       pr_debug("initrd_start=0x%llx  initrd_end=0x%llx\n",
+                (unsigned long long)start, (unsigned long long)end);
 }
 #else
 inline void early_init_dt_check_for_initrd(unsigned long node)
@@ -698,6 +774,17 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
        return 1;
 }
 
+#ifdef CONFIG_HAVE_MEMBLOCK
+/*
+ * called from unflatten_device_tree() to bootstrap devicetree itself
+ * Architectures can override this definition if memblock isn't used
+ */
+void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+       return __va(memblock_alloc(size, align));
+}
+#endif
+
 /**
  * unflatten_device_tree - create tree of device_nodes from flat blob
  *
@@ -716,3 +803,14 @@ void __init unflatten_device_tree(void)
 }
 
 #endif /* CONFIG_OF_EARLY_FLATTREE */
+
+/* Feed entire flattened device tree into the random pool */
+static int __init add_fdt_randomness(void)
+{
+       if (initial_boot_params)
+               add_device_randomness(initial_boot_params,
+                               be32_to_cpu(initial_boot_params->totalsize));
+
+       return 0;
+}
+core_initcall(add_fdt_randomness);
index 1264923ade0f2c7973528080d3fa75167b6be0b4..1752988d6aa80224ced68ab6e62744c77e8ab4be 100644 (file)
@@ -28,7 +28,7 @@
 
 /**
  * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
- * @device: Device node of the device whose interrupt is to be mapped
+ * @dev: Device node of the device whose interrupt is to be mapped
  * @index: Index of the interrupt to map
  *
  * This function is a wrapper that chains of_irq_map_one() and
index ea174c8ee34b56502860f78f94ba61df48fe764e..8f9be2e099376981d7a4c39b87dbcc7de715a7ca 100644 (file)
@@ -39,7 +39,7 @@ static const char *phy_modes[] = {
  * The function gets phy interface string from property 'phy-mode',
  * and return its index in phy_modes table, or errno in error case.
  */
-const int of_get_phy_mode(struct device_node *np)
+int of_get_phy_mode(struct device_node *np)
 {
        const char *pm;
        int err, i;
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
new file mode 100644 (file)
index 0000000..0fe40c7
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Device tree based initialization code for reserved memory.
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ * Author: Marek Szyprowski <m.szyprowski@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 optional) any later version of the license.
+ */
+
+#include <linux/memblock.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+#include <linux/mm.h>
+#include <linux/sizes.h>
+#include <linux/mm_types.h>
+#include <linux/dma-contiguous.h>
+#include <linux/dma-mapping.h>
+#include <linux/of_reserved_mem.h>
+
+#define MAX_RESERVED_REGIONS   16
+struct reserved_mem {
+       phys_addr_t             base;
+       unsigned long           size;
+       struct cma              *cma;
+       char                    name[32];
+};
+static struct reserved_mem reserved_mem[MAX_RESERVED_REGIONS];
+static int reserved_mem_count;
+
+static int __init fdt_scan_reserved_mem(unsigned long node, const char *uname,
+                                       int depth, void *data)
+{
+       struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
+       phys_addr_t base, size;
+       int is_cma, is_reserved;
+       unsigned long len;
+       const char *status;
+       __be32 *prop;
+
+       is_cma = IS_ENABLED(CONFIG_DMA_CMA) &&
+              of_flat_dt_is_compatible(node, "linux,contiguous-memory-region");
+       is_reserved = of_flat_dt_is_compatible(node, "reserved-memory-region");
+
+       if (!is_reserved && !is_cma) {
+               /* ignore node and scan next one */
+               return 0;
+       }
+
+       status = of_get_flat_dt_prop(node, "status", &len);
+       if (status && strcmp(status, "okay") != 0) {
+               /* ignore disabled node nad scan next one */
+               return 0;
+       }
+
+       prop = of_get_flat_dt_prop(node, "reg", &len);
+       if (!prop || (len < (dt_root_size_cells + dt_root_addr_cells) *
+                            sizeof(__be32))) {
+               pr_err("Reserved mem: node %s, incorrect \"reg\" property\n",
+                      uname);
+               /* ignore node and scan next one */
+               return 0;
+       }
+       base = dt_mem_next_cell(dt_root_addr_cells, &prop);
+       size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+       if (!size) {
+               /* ignore node and scan next one */
+               return 0;
+       }
+
+       pr_info("Reserved mem: found %s, memory base %lx, size %ld MiB\n",
+               uname, (unsigned long)base, (unsigned long)size / SZ_1M);
+
+       if (reserved_mem_count == ARRAY_SIZE(reserved_mem))
+               return -ENOSPC;
+
+       rmem->base = base;
+       rmem->size = size;
+       strlcpy(rmem->name, uname, sizeof(rmem->name));
+
+       if (is_cma) {
+               struct cma *cma;
+               if (dma_contiguous_reserve_area(size, base, 0, &cma) == 0) {
+                       rmem->cma = cma;
+                       reserved_mem_count++;
+                       if (of_get_flat_dt_prop(node,
+                                               "linux,default-contiguous-region",
+                                               NULL))
+                               dma_contiguous_set_default(cma);
+               }
+       } else if (is_reserved) {
+               if (memblock_remove(base, size) == 0)
+                       reserved_mem_count++;
+               else
+                       pr_err("Failed to reserve memory for %s\n", uname);
+       }
+
+       return 0;
+}
+
+static struct reserved_mem *get_dma_memory_region(struct device *dev)
+{
+       struct device_node *node;
+       const char *name;
+       int i;
+
+       node = of_parse_phandle(dev->of_node, "memory-region", 0);
+       if (!node)
+               return NULL;
+
+       name = kbasename(node->full_name);
+       for (i = 0; i < reserved_mem_count; i++)
+               if (strcmp(name, reserved_mem[i].name) == 0)
+                       return &reserved_mem[i];
+       return NULL;
+}
+
+/**
+ * of_reserved_mem_device_init() - assign reserved memory region to given device
+ *
+ * This function assign memory region pointed by "memory-region" device tree
+ * property to the given device.
+ */
+void of_reserved_mem_device_init(struct device *dev)
+{
+       struct reserved_mem *region = get_dma_memory_region(dev);
+       if (!region)
+               return;
+
+       if (region->cma) {
+               dev_set_cma_area(dev, region->cma);
+               pr_info("Assigned CMA %s to %s device\n", region->name,
+                       dev_name(dev));
+       } else {
+               if (dma_declare_coherent_memory(dev, region->base, region->base,
+                   region->size, DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE) != 0)
+                       pr_info("Declared reserved memory %s to %s device\n",
+                               region->name, dev_name(dev));
+       }
+}
+
+/**
+ * of_reserved_mem_device_release() - release reserved memory device structures
+ *
+ * This function releases structures allocated for memory region handling for
+ * the given device.
+ */
+void of_reserved_mem_device_release(struct device *dev)
+{
+       struct reserved_mem *region = get_dma_memory_region(dev);
+       if (!region && !region->cma)
+               dma_release_declared_memory(dev);
+}
+
+/**
+ * early_init_dt_scan_reserved_mem() - create reserved memory regions
+ *
+ * This function grabs memory from early allocator for device exclusive use
+ * defined in device tree structures. It should be called by arch specific code
+ * once the early allocator (memblock) has been activated and all other
+ * subsystems have already allocated/reserved memory.
+ */
+void __init early_init_dt_scan_reserved_mem(void)
+{
+       of_scan_flat_dt_by_path("/memory/reserved-memory",
+                               fdt_scan_reserved_mem, NULL);
+}
index e0a6514ab46c20eb902453c3b321774d1e787ba0..9b439ac63d8e73eef85aa490d5cab6ec825120b7 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/of_device.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
+#include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
 
 const struct of_device_id of_default_bus_match_table[] = {
@@ -196,7 +197,7 @@ EXPORT_SYMBOL(of_device_alloc);
  * Returns pointer to created platform device, or NULL if a device was not
  * registered.  Unavailable devices will not get registered.
  */
-struct platform_device *of_platform_device_create_pdata(
+static struct platform_device *of_platform_device_create_pdata(
                                        struct device_node *np,
                                        const char *bus_id,
                                        void *platform_data,
@@ -218,6 +219,8 @@ struct platform_device *of_platform_device_create_pdata(
        dev->dev.bus = &platform_bus_type;
        dev->dev.platform_data = platform_data;
 
+       of_reserved_mem_device_init(&dev->dev);
+
        /* We do not fill the DMA ops for platform devices by default.
         * This is currently the responsibility of the platform code
         * to do such, possibly using a device notifier
@@ -225,6 +228,7 @@ struct platform_device *of_platform_device_create_pdata(
 
        if (of_device_add(dev) != 0) {
                platform_device_put(dev);
+               of_reserved_mem_device_release(&dev->dev);
                return NULL;
        }
 
@@ -264,8 +268,11 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
                return NULL;
 
        dev = amba_device_alloc(NULL, 0, 0);
-       if (!dev)
+       if (!dev) {
+               pr_err("%s(): amba_device_alloc() failed for %s\n",
+                      __func__, node->full_name);
                return NULL;
+       }
 
        /* setup generic device info */
        dev->dev.coherent_dma_mask = ~0;
@@ -290,12 +297,18 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
                dev->irq[i] = irq_of_parse_and_map(node, i);
 
        ret = of_address_to_resource(node, 0, &dev->res);
-       if (ret)
+       if (ret) {
+               pr_err("%s(): of_address_to_resource() failed (%d) for %s\n",
+                      __func__, ret, node->full_name);
                goto err_free;
+       }
 
        ret = amba_device_add(dev, &iomem_resource);
-       if (ret)
+       if (ret) {
+               pr_err("%s(): amba_device_add() failed (%d) for %s\n",
+                      __func__, ret, node->full_name);
                goto err_free;
+       }
 
        return dev;
 
@@ -374,6 +387,10 @@ static int of_platform_bus_create(struct device_node *bus,
        }
 
        if (of_device_is_compatible(bus, "arm,primecell")) {
+               /*
+                * Don't return an error here to keep compatibility with older
+                * device tree files.
+                */
                of_amba_device_create(bus, bus_id, platform_data, parent);
                return 0;
        }
index f6488adf3af1c2677510e9f7b96fc7adbe77c8fd..0b7d23b4ad954489b657480d0ee08a3b7b2d81d8 100644 (file)
@@ -487,7 +487,6 @@ static void acpiphp_bus_add(acpi_handle handle)
 {
        struct acpi_device *adev = NULL;
 
-       acpiphp_bus_trim(handle);
        acpi_bus_scan(handle);
        acpi_bus_get_device(handle, &adev);
        if (adev)
@@ -529,6 +528,16 @@ static void check_hotplug_bridge(struct acpiphp_slot *slot, struct pci_dev *dev)
        }
 }
 
+static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
+{
+       struct acpiphp_func *func;
+
+       list_for_each_entry(func, &slot->funcs, sibling)
+               acpiphp_bus_add(func_to_handle(func));
+
+       return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
+}
+
 /**
  * enable_slot - enable, configure a slot
  * @slot: slot to be enabled
@@ -543,12 +552,9 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
        struct acpiphp_func *func;
        int max, pass;
        LIST_HEAD(add_list);
+       int nr_found;
 
-       list_for_each_entry(func, &slot->funcs, sibling)
-               acpiphp_bus_add(func_to_handle(func));
-
-       pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
-
+       nr_found = acpiphp_rescan_slot(slot);
        max = acpiphp_max_busnr(bus);
        for (pass = 0; pass < 2; pass++) {
                list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -567,8 +573,11 @@ static void __ref enable_slot(struct acpiphp_slot *slot)
                        }
                }
        }
-
        __pci_bus_assign_resources(bus, &add_list, NULL);
+       /* Nothing more to do here if there are no new devices on this bus. */
+       if (!nr_found && (slot->flags & SLOT_ENABLED))
+               return;
+
        acpiphp_sanitize_bus(bus);
        acpiphp_set_hpp_values(bus);
        acpiphp_set_acpi_region(slot);
@@ -837,11 +846,22 @@ static void hotplug_event(acpi_handle handle, u32 type, void *data)
        case ACPI_NOTIFY_DEVICE_CHECK:
                /* device check */
                dbg("%s: Device check notify on %s\n", __func__, objname);
-               if (bridge)
+               if (bridge) {
                        acpiphp_check_bridge(bridge);
-               else
-                       acpiphp_check_bridge(func->parent);
+               } else {
+                       struct acpiphp_slot *slot = func->slot;
+                       int ret;
 
+                       /*
+                        * Check if anything has changed in the slot and rescan
+                        * from the parent if that's the case.
+                        */
+                       mutex_lock(&slot->crit_sect);
+                       ret = acpiphp_rescan_slot(slot);
+                       mutex_unlock(&slot->crit_sect);
+                       if (ret)
+                               acpiphp_check_bridge(func->parent);
+               }
                break;
 
        case ACPI_NOTIFY_EJECT_REQUEST:
@@ -867,6 +887,8 @@ static void hotplug_event_work(struct work_struct *work)
        hotplug_event(hp_work->handle, hp_work->type, context);
 
        acpi_scan_lock_release();
+       acpi_evaluate_hotplug_ost(hp_work->handle, hp_work->type,
+                                 ACPI_OST_SC_SUCCESS, NULL);
        kfree(hp_work); /* allocated in handle_hotplug_event() */
        put_bridge(context->func.parent);
 }
@@ -882,11 +904,15 @@ static void hotplug_event_work(struct work_struct *work)
 static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
 {
        struct acpiphp_context *context;
+       u32 ost_code = ACPI_OST_SC_SUCCESS;
 
        switch (type) {
        case ACPI_NOTIFY_BUS_CHECK:
        case ACPI_NOTIFY_DEVICE_CHECK:
+               break;
        case ACPI_NOTIFY_EJECT_REQUEST:
+               ost_code = ACPI_OST_SC_EJECT_IN_PROGRESS;
+               acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
                break;
 
        case ACPI_NOTIFY_DEVICE_WAKE:
@@ -895,20 +921,21 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
        case ACPI_NOTIFY_FREQUENCY_MISMATCH:
                acpi_handle_err(handle, "Device cannot be configured due "
                                "to a frequency mismatch\n");
-               return;
+               goto out;
 
        case ACPI_NOTIFY_BUS_MODE_MISMATCH:
                acpi_handle_err(handle, "Device cannot be configured due "
                                "to a bus mode mismatch\n");
-               return;
+               goto out;
 
        case ACPI_NOTIFY_POWER_FAULT:
                acpi_handle_err(handle, "Device has suffered a power fault\n");
-               return;
+               goto out;
 
        default:
                acpi_handle_warn(handle, "Unsupported event type 0x%x\n", type);
-               return;
+               ost_code = ACPI_OST_SC_UNRECOGNIZED_NOTIFY;
+               goto out;
        }
 
        mutex_lock(&acpiphp_context_lock);
@@ -917,8 +944,14 @@ static void handle_hotplug_event(acpi_handle handle, u32 type, void *data)
                get_bridge(context->func.parent);
                acpiphp_put_context(context);
                alloc_acpi_hp_work(handle, type, context, hotplug_event_work);
+               mutex_unlock(&acpiphp_context_lock);
+               return;
        }
        mutex_unlock(&acpiphp_context_lock);
+       ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+
+ out:
+       acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
 }
 
 /*
index b35f93c232cf5d40390325f587a579aefc51f62b..d5f90d6383bc38660dcaba3786adcbf1e78a936b 100644 (file)
@@ -30,7 +30,6 @@ static int pci_msi_enable = 1;
 
 /* Arch hooks */
 
-#if defined(CONFIG_GENERIC_HARDIRQS)
 int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_chip *chip = dev->bus->msi;
@@ -67,21 +66,6 @@ int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
 
        return chip->check_device(chip, dev, nvec, type);
 }
-#else
-int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
-{
-       return -ENOSYS;
-}
-
-void __weak arch_teardown_msi_irq(unsigned int irq)
-{
-}
-
-int __weak arch_msi_check_device(struct pci_dev *dev, int nvec, int type)
-{
-       return 0;
-}
-#endif /* CONFIG_GENERIC_HARDIRQS */
 
 int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
@@ -245,8 +229,6 @@ static void msix_mask_irq(struct msi_desc *desc, u32 flag)
        desc->masked = __msix_mask_irq(desc, flag);
 }
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-
 static void msi_set_mask_bit(struct irq_data *data, u32 flag)
 {
        struct msi_desc *desc = irq_data_get_msi(data);
@@ -270,8 +252,6 @@ void unmask_msi_irq(struct irq_data *data)
        msi_set_mask_bit(data, 0);
 }
 
-#endif /* CONFIG_GENERIC_HARDIRQS */
-
 void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
 {
        BUG_ON(entry->dev->current_state != PCI_D0);
@@ -382,10 +362,8 @@ static void free_msi_irqs(struct pci_dev *dev)
                        nvec = entry->nvec_used;
                else
                        nvec = 1 << entry->msi_attrib.multiple;
-#ifdef CONFIG_GENERIC_HARDIRQS
                for (i = 0; i < nvec; i++)
                        BUG_ON(irq_has_action(entry->irq + i));
-#endif
        }
 
        arch_teardown_msi_irqs(dev);
index 36a9e602339595de854f561ef725bd3bc3cd8bfa..96d6b2eef4f2a1209f2c9f113e3932b8eb812738 100644 (file)
@@ -732,6 +732,7 @@ config SAMSUNG_LAPTOP
        tristate "Samsung Laptop driver"
        depends on X86
        depends on RFKILL || RFKILL = n
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on BACKLIGHT_CLASS_DEVICE
        select LEDS_CLASS
        select NEW_LEDS
@@ -764,7 +765,7 @@ config INTEL_OAKTRAIL
 
 config SAMSUNG_Q10
        tristate "Samsung Q10 Extras"
-       depends on SERIO_I8042
+       depends on ACPI
        select BACKLIGHT_CLASS_DEVICE
        ---help---
          This driver provides support for backlight control on Samsung Q10
index 6296f078b7bc78eb57e89314e869f10c93a90eef..da36b5e824d467bbfb8b35d0a50e652cd4153a90 100644 (file)
@@ -82,6 +82,13 @@ static const struct dmi_system_id amilo_rfkill_id_table[] = {
                },
                .driver_data = (void *)&amilo_a1655_rfkill_ops
        },
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+                       DMI_MATCH(DMI_BOARD_NAME, "AMILO L1310"),
+               },
+               .driver_data = (void *)&amilo_a1655_rfkill_ops
+       },
        {
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
index f74bfcbb7bad8ce0e329ee9b0fe099451da1486e..8eea2efbbb6dcfc23b692885693ce7f69e55437c 100644 (file)
@@ -393,17 +393,21 @@ static void gmux_notify_handler(acpi_handle device, u32 value, void *context)
                complete(&gmux_data->powerchange_done);
 }
 
-static int gmux_suspend(struct pnp_dev *pnp, pm_message_t state)
+static int gmux_suspend(struct device *dev)
 {
+       struct pnp_dev *pnp = to_pnp_dev(dev);
        struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+
        gmux_data->resume_client_id = gmux_active_client(gmux_data);
        gmux_disable_interrupts(gmux_data);
        return 0;
 }
 
-static int gmux_resume(struct pnp_dev *pnp)
+static int gmux_resume(struct device *dev)
 {
+       struct pnp_dev *pnp = to_pnp_dev(dev);
        struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
+
        gmux_enable_interrupts(gmux_data);
        gmux_switchto(gmux_data->resume_client_id);
        if (gmux_data->power_state == VGA_SWITCHEROO_OFF)
@@ -605,13 +609,19 @@ static const struct pnp_device_id gmux_device_ids[] = {
        {"", 0}
 };
 
+static const struct dev_pm_ops gmux_dev_pm_ops = {
+       .suspend = gmux_suspend,
+       .resume = gmux_resume,
+};
+
 static struct pnp_driver gmux_pnp_driver = {
        .name           = "apple-gmux",
        .probe          = gmux_probe,
        .remove         = gmux_remove,
        .id_table       = gmux_device_ids,
-       .suspend        = gmux_suspend,
-       .resume         = gmux_resume
+       .driver         = {
+                       .pm = &gmux_dev_pm_ops,
+       },
 };
 
 static int __init apple_gmux_init(void)
index 36e5e6c13db4edbdd0aaae00e405eff248619290..6dfa8d3b4eec22dfd826e6d7de7cc811d565340b 100644 (file)
@@ -590,7 +590,7 @@ static ssize_t cmpc_accel_sensitivity_store(struct device *dev,
        inputdev = dev_get_drvdata(&acpi->dev);
        accel = dev_get_drvdata(&inputdev->dev);
 
-       r = strict_strtoul(buf, 0, &sensitivity);
+       r = kstrtoul(buf, 0, &sensitivity);
        if (r)
                return r;
 
index 475cc52425119a1a874347218d2a6cd5de1e4990..eaa78edb1f4ef2b9f5af80bd0f715dfaa9304bd8 100644 (file)
@@ -425,7 +425,8 @@ static ssize_t pwm_enable_store(struct device *dev,
        struct compal_data *data = dev_get_drvdata(dev);
        long val;
        int err;
-       err = strict_strtol(buf, 10, &val);
+
+       err = kstrtol(buf, 10, &val);
        if (err)
                return err;
        if (val < 0)
@@ -463,7 +464,8 @@ static ssize_t pwm_store(struct device *dev, struct device_attribute *attr,
        struct compal_data *data = dev_get_drvdata(dev);
        long val;
        int err;
-       err = strict_strtol(buf, 10, &val);
+
+       err = kstrtol(buf, 10, &val);
        if (err)
                return err;
        if (val < 0 || val > 255)
@@ -1081,7 +1083,6 @@ static int compal_remove(struct platform_device *pdev)
        hwmon_device_unregister(data->hwmon_dev);
        power_supply_unregister(&data->psy);
 
-       platform_set_drvdata(pdev, NULL);
        kfree(data);
 
        sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group);
index d6970f47ae72f639d648c924a27bea8b97cbdfb6..1c86fa0857c8eb73dfb64ec90ee9e7f7e50404c3 100644 (file)
@@ -725,7 +725,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
                                           (void *) HPWMI_WWAN);
                if (!wwan_rfkill) {
                        err = -ENOMEM;
-                       goto register_gps_error;
+                       goto register_bluetooth_error;
                }
                rfkill_init_sw_state(wwan_rfkill,
                                     hp_wmi_get_sw_state(HPWMI_WWAN));
@@ -733,7 +733,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
                                    hp_wmi_get_hw_state(HPWMI_WWAN));
                err = rfkill_register(wwan_rfkill);
                if (err)
-                       goto register_wwan_err;
+                       goto register_wwan_error;
        }
 
        if (wireless & 0x8) {
@@ -743,7 +743,7 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
                                                (void *) HPWMI_GPS);
                if (!gps_rfkill) {
                        err = -ENOMEM;
-                       goto register_bluetooth_error;
+                       goto register_wwan_error;
                }
                rfkill_init_sw_state(gps_rfkill,
                                     hp_wmi_get_sw_state(HPWMI_GPS));
@@ -755,16 +755,16 @@ static int hp_wmi_rfkill_setup(struct platform_device *device)
        }
 
        return 0;
-register_wwan_err:
-       rfkill_destroy(wwan_rfkill);
-       wwan_rfkill = NULL;
-       if (gps_rfkill)
-               rfkill_unregister(gps_rfkill);
 register_gps_error:
        rfkill_destroy(gps_rfkill);
        gps_rfkill = NULL;
        if (bluetooth_rfkill)
                rfkill_unregister(bluetooth_rfkill);
+register_wwan_error:
+       rfkill_destroy(wwan_rfkill);
+       wwan_rfkill = NULL;
+       if (gps_rfkill)
+               rfkill_unregister(gps_rfkill);
 register_bluetooth_error:
        rfkill_destroy(bluetooth_rfkill);
        bluetooth_rfkill = NULL;
index 9385afd9b5582c5042946efc10da1630e25ffa30..41b740cb28bca8743ea282bbf2fb5639a2f4266c 100644 (file)
@@ -193,17 +193,6 @@ static struct acpi_driver irst_driver = {
        },
 };
 
-static int irst_init(void)
-{
-       return acpi_bus_register_driver(&irst_driver);
-}
-
-static void irst_exit(void)
-{
-       acpi_bus_unregister_driver(&irst_driver);
-}
-
-module_init(irst_init);
-module_exit(irst_exit);
+module_acpi_driver(irst_driver);
 
 MODULE_DEVICE_TABLE(acpi, irst_ids);
index f74e93d096bc6b4de29e5079a112f607f0257b00..52259dcabecb8251edad2a0e0dc7eccb9b174500 100644 (file)
@@ -74,17 +74,6 @@ static struct acpi_driver smartconnect_driver = {
        },
 };
 
-static int smartconnect_init(void)
-{
-       return acpi_bus_register_driver(&smartconnect_driver);
-}
-
-static void smartconnect_exit(void)
-{
-       acpi_bus_unregister_driver(&smartconnect_driver);
-}
-
-module_init(smartconnect_init);
-module_exit(smartconnect_exit);
+module_acpi_driver(smartconnect_driver);
 
 MODULE_DEVICE_TABLE(acpi, smartconnect_ids);
index f59683aa13d5d9ce522355ba98eeaa2898f56f01..6b18aba82cfae450bde3cad8fd2b2d01f20b3d03 100644 (file)
@@ -128,7 +128,6 @@ static int mfld_pb_remove(struct platform_device *pdev)
 
        free_irq(irq, input);
        input_unregister_device(input);
-       platform_set_drvdata(pdev, NULL);
 
        return 0;
 }
index 81c491e74b3471e5433a8024df690476489a4fdc..93fab8b70ce17dd5b0b811c88807f9adee3f67e0 100644 (file)
@@ -542,7 +542,6 @@ static int mid_thermal_remove(struct platform_device *pdev)
        }
 
        kfree(pinfo);
-       platform_set_drvdata(pdev, NULL);
 
        /* Stop the ADC */
        return configure_adc(0);
index 984253da365d88426db4e398311e28a2489659e2..10d12b221601ddae853fe3b0e8554d99d0c5ef06 100644 (file)
@@ -643,23 +643,6 @@ out_hotkey:
        return result;
 }
 
-static int __init acpi_pcc_init(void)
-{
-       int result = 0;
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       result = acpi_bus_register_driver(&acpi_pcc_driver);
-       if (result < 0) {
-               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
-                                 "Error registering hotkey driver\n"));
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
 static int acpi_pcc_hotkey_remove(struct acpi_device *device)
 {
        struct pcc_acpi *pcc = acpi_driver_data(device);
@@ -679,10 +662,4 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device)
        return 0;
 }
 
-static void __exit acpi_pcc_exit(void)
-{
-       acpi_bus_unregister_driver(&acpi_pcc_driver);
-}
-
-module_init(acpi_pcc_init);
-module_exit(acpi_pcc_exit);
+module_acpi_driver(acpi_pcc_driver);
index 4430b8c1369d9cd95a5951fe10b0d173e9121b0d..cae7098e9b0d70adf271eb9c31a1e833919a54b1 100644 (file)
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/backlight.h>
-#include <linux/i8042.h>
 #include <linux/dmi.h>
+#include <acpi/acpi_drivers.h>
 
-#define SAMSUNGQ10_BL_MAX_INTENSITY      255
-#define SAMSUNGQ10_BL_DEFAULT_INTENSITY  185
+#define SAMSUNGQ10_BL_MAX_INTENSITY 7
 
-#define SAMSUNGQ10_BL_8042_CMD           0xbe
-#define SAMSUNGQ10_BL_8042_DATA          { 0x89, 0x91 }
-
-static int samsungq10_bl_brightness;
+static acpi_handle ec_handle;
 
 static bool force;
 module_param(force, bool, 0);
@@ -33,21 +29,26 @@ MODULE_PARM_DESC(force,
 static int samsungq10_bl_set_intensity(struct backlight_device *bd)
 {
 
-       int brightness = bd->props.brightness;
-       unsigned char c[3] = SAMSUNGQ10_BL_8042_DATA;
+       acpi_status status;
+       int i;
 
-       c[2] = (unsigned char)brightness;
-       i8042_lock_chip();
-       i8042_command(c, (0x30 << 8) | SAMSUNGQ10_BL_8042_CMD);
-       i8042_unlock_chip();
-       samsungq10_bl_brightness = brightness;
+       for (i = 0; i < SAMSUNGQ10_BL_MAX_INTENSITY; i++) {
+               status = acpi_evaluate_object(ec_handle, "_Q63", NULL, NULL);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+       }
+       for (i = 0; i < bd->props.brightness; i++) {
+               status = acpi_evaluate_object(ec_handle, "_Q64", NULL, NULL);
+               if (ACPI_FAILURE(status))
+                       return -EIO;
+       }
 
        return 0;
 }
 
 static int samsungq10_bl_get_intensity(struct backlight_device *bd)
 {
-       return samsungq10_bl_brightness;
+       return bd->props.brightness;
 }
 
 static const struct backlight_ops samsungq10_bl_ops = {
@@ -55,28 +56,6 @@ static const struct backlight_ops samsungq10_bl_ops = {
        .update_status  = samsungq10_bl_set_intensity,
 };
 
-#ifdef CONFIG_PM_SLEEP
-static int samsungq10_suspend(struct device *dev)
-{
-       return 0;
-}
-
-static int samsungq10_resume(struct device *dev)
-{
-
-       struct backlight_device *bd = dev_get_drvdata(dev);
-
-       samsungq10_bl_set_intensity(bd);
-       return 0;
-}
-#else
-#define samsungq10_suspend NULL
-#define samsungq10_resume  NULL
-#endif
-
-static SIMPLE_DEV_PM_OPS(samsungq10_pm_ops,
-                         samsungq10_suspend, samsungq10_resume);
-
 static int samsungq10_probe(struct platform_device *pdev)
 {
 
@@ -93,9 +72,6 @@ static int samsungq10_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, bd);
 
-       bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY;
-       samsungq10_bl_set_intensity(bd);
-
        return 0;
 }
 
@@ -104,9 +80,6 @@ static int samsungq10_remove(struct platform_device *pdev)
 
        struct backlight_device *bd = platform_get_drvdata(pdev);
 
-       bd->props.brightness = SAMSUNGQ10_BL_DEFAULT_INTENSITY;
-       samsungq10_bl_set_intensity(bd);
-
        backlight_device_unregister(bd);
 
        return 0;
@@ -116,7 +89,6 @@ static struct platform_driver samsungq10_driver = {
        .driver         = {
                .name   = KBUILD_MODNAME,
                .owner  = THIS_MODULE,
-               .pm     = &samsungq10_pm_ops,
        },
        .probe          = samsungq10_probe,
        .remove         = samsungq10_remove,
@@ -172,6 +144,11 @@ static int __init samsungq10_init(void)
        if (!force && !dmi_check_system(samsungq10_dmi_table))
                return -ENODEV;
 
+       ec_handle = ec_get_handle();
+
+       if (!ec_handle)
+               return -ENODEV;
+
        samsungq10_device = platform_create_bundle(&samsungq10_driver,
                                                   samsungq10_probe,
                                                   NULL, 0, NULL, 0);
index be67e5e28d188e07766dd1a1e164c7c76c183693..03ca6c139f1a5c9dd0cc821045bad7b5cb409d51 100644 (file)
@@ -369,7 +369,7 @@ struct tpacpi_led_classdev {
        struct led_classdev led_classdev;
        struct work_struct work;
        enum led_status_t new_state;
-       unsigned int led;
+       int led;
 };
 
 /* brightness level capabilities */
@@ -5296,6 +5296,16 @@ static int __init led_init(struct ibm_init_struct *iibm)
 
        led_supported = led_init_detect_mode();
 
+       if (led_supported != TPACPI_LED_NONE) {
+               useful_leds = tpacpi_check_quirks(led_useful_qtable,
+                               ARRAY_SIZE(led_useful_qtable));
+
+               if (!useful_leds) {
+                       led_handle = NULL;
+                       led_supported = TPACPI_LED_NONE;
+               }
+       }
+
        vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
                str_supported(led_supported), led_supported);
 
@@ -5309,10 +5319,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
                return -ENOMEM;
        }
 
-       useful_leds = tpacpi_check_quirks(led_useful_qtable,
-                                         ARRAY_SIZE(led_useful_qtable));
-
        for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+               tpacpi_leds[i].led = -1;
+
                if (!tpacpi_is_led_restricted(i) &&
                    test_bit(i, &useful_leds)) {
                        rc = tpacpi_init_led(i);
@@ -5370,9 +5379,13 @@ static int led_write(char *buf)
                return -ENODEV;
 
        while ((cmd = next_cmd(&buf))) {
-               if (sscanf(cmd, "%d", &led) != 1 || led < 0 || led > 15)
+               if (sscanf(cmd, "%d", &led) != 1)
                        return -EINVAL;
 
+               if (led < 0 || led > (TPACPI_LED_NUMLEDS - 1) ||
+                               tpacpi_leds[led].led < 0)
+                       return -ENODEV;
+
                if (strstr(cmd, "off")) {
                        s = TPACPI_LED_OFF;
                } else if (strstr(cmd, "on")) {
index 6e02c953d888dd13113ee9f1cd19e40ef01d82ce..601ea951224201a87719f0acc7de5ee7e4635649 100644 (file)
@@ -780,7 +780,7 @@ static bool guid_already_parsed(const char *guid_string)
 /*
  * Parse the _WDG method for the GUID data blocks
  */
-static acpi_status parse_wdg(acpi_handle handle)
+static int parse_wdg(acpi_handle handle)
 {
        struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
        union acpi_object *obj;
@@ -812,7 +812,7 @@ static acpi_status parse_wdg(acpi_handle handle)
 
                wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
                if (!wblock)
-                       return AE_NO_MEMORY;
+                       return -ENOMEM;
 
                wblock->handle = handle;
                wblock->gblock = gblock[i];
index 12adb43a069317da31958ac4913418c385cedb77..a39ee38a9414cece2b0742e05f2cf5260a0fc842 100644 (file)
@@ -163,6 +163,13 @@ static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
        if (!pnp_drv)
                return 0;
 
+       if (pnp_drv->driver.pm && pnp_drv->driver.pm->suspend) {
+               error = pnp_drv->driver.pm->suspend(dev);
+               suspend_report_result(pnp_drv->driver.pm->suspend, error);
+               if (error)
+                       return error;
+       }
+
        if (pnp_drv->suspend) {
                error = pnp_drv->suspend(pnp_dev, state);
                if (error)
@@ -211,6 +218,12 @@ static int pnp_bus_resume(struct device *dev)
                        return error;
        }
 
+       if (pnp_drv->driver.pm && pnp_drv->driver.pm->resume) {
+               error = pnp_drv->driver.pm->resume(dev);
+               if (error)
+                       return error;
+       }
+
        if (pnp_drv->resume) {
                error = pnp_drv->resume(pnp_dev);
                if (error)
index 7b8979c63f4882e6c3e5375b9f9c35c40e5a829c..e6f92b450913e47c490b3481c4c33c537c2526bb 100644 (file)
@@ -216,6 +216,13 @@ config BATTERY_S3C_ADC
        help
          Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
 
+config BATTERY_TWL4030_MADC
+       tristate "TWL4030 MADC battery driver"
+       depends on TWL4030_MADC
+       help
+         Say Y here to enable this dumb driver for batteries managed
+         through the TWL4030 MADC.
+
 config CHARGER_88PM860X
        tristate "Marvell 88PM860x Charger driver"
        depends on MFD_88PM860X && BATTERY_88PM860X
@@ -262,7 +269,6 @@ config CHARGER_ISP1704
 
 config CHARGER_MAX8903
        tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power"
-       depends on GENERIC_HARDIRQS
        help
          Say Y to enable support for the MAX8903 DC-DC charger and sysfs.
          The driver supports controlling charger-enable and current-limit
@@ -334,6 +340,12 @@ config CHARGER_BQ2415X
          You'll need this driver to charge batteries on e.g. Nokia
          RX-51/N900.
 
+config CHARGER_BQ24190
+       tristate "TI BQ24190 battery charger driver"
+       depends on I2C && GPIOLIB
+       help
+         Say Y to enable support for the TI BQ24190 battery charger.
+
 config CHARGER_SMB347
        tristate "Summit Microelectronics SMB347 Battery Charger"
        depends on I2C
@@ -357,7 +369,7 @@ config AB8500_BM
 
 config BATTERY_GOLDFISH
        tristate "Goldfish battery driver"
-       depends on GENERIC_HARDIRQS
+       depends on GOLDFISH || COMPILE_TEST
        help
          Say Y to enable support for the battery and AC power in the
          Goldfish emulator.
index 653bf6ceff30a6c999ec4b1a7bf2932fb8f48359..a4b74177706f24397f327ee4361c7408bf6b0d90 100644 (file)
@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_MAX17040)        += max17040_battery.o
 obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)       += z2_battery.o
 obj-$(CONFIG_BATTERY_S3C_ADC)  += s3c_adc_battery.o
+obj-$(CONFIG_BATTERY_TWL4030_MADC)     += twl4030_madc_battery.o
 obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
 obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)   += jz4740-battery.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
 obj-$(CONFIG_CHARGER_MAX8997)  += max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)  += max8998_charger.o
 obj-$(CONFIG_CHARGER_BQ2415X)  += bq2415x_charger.o
+obj-$(CONFIG_CHARGER_BQ24190)  += bq24190_charger.o
 obj-$(CONFIG_POWER_AVS)                += avs/
 obj-$(CONFIG_CHARGER_SMB347)   += smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
index f098fdafee9fdfc6cfa09e7316a86beec2c70f66..a4c4a10b3a41cd2e2e05d67773097cbfed686f8f 100644 (file)
@@ -774,6 +774,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
                di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
                dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
                                di->max_usb_in_curr.usb_type_max);
+               break;
        case USB_STAT_NOT_VALID_LINK:
                dev_err(di->dev, "USB Type invalid - try charging anyway\n");
                di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c
new file mode 100644 (file)
index 0000000..ad3ff8f
--- /dev/null
@@ -0,0 +1,1549 @@
+/*
+ * Driver for the TI bq24190 battery charger.
+ *
+ * Author: Mark A. Greer <mgreer@animalcreek.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/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/power_supply.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+#include <linux/power/bq24190_charger.h>
+
+
+#define        BQ24190_MANUFACTURER    "Texas Instruments"
+
+#define BQ24190_REG_ISC                0x00 /* Input Source Control */
+#define BQ24190_REG_ISC_EN_HIZ_MASK            BIT(7)
+#define BQ24190_REG_ISC_EN_HIZ_SHIFT           7
+#define BQ24190_REG_ISC_VINDPM_MASK            (BIT(6) | BIT(5) | BIT(4) | \
+                                                BIT(3))
+#define BQ24190_REG_ISC_VINDPM_SHIFT           3
+#define BQ24190_REG_ISC_IINLIM_MASK            (BIT(2) | BIT(1) | BIT(0))
+#define BQ24190_REG_ISC_IINLIM_SHIFT           0
+
+#define BQ24190_REG_POC                0x01 /* Power-On Configuration */
+#define BQ24190_REG_POC_RESET_MASK             BIT(7)
+#define BQ24190_REG_POC_RESET_SHIFT            7
+#define BQ24190_REG_POC_WDT_RESET_MASK         BIT(6)
+#define BQ24190_REG_POC_WDT_RESET_SHIFT                6
+#define BQ24190_REG_POC_CHG_CONFIG_MASK                (BIT(5) | BIT(4))
+#define BQ24190_REG_POC_CHG_CONFIG_SHIFT       4
+#define BQ24190_REG_POC_SYS_MIN_MASK           (BIT(3) | BIT(2) | BIT(1))
+#define BQ24190_REG_POC_SYS_MIN_SHIFT          1
+#define BQ24190_REG_POC_BOOST_LIM_MASK         BIT(0)
+#define BQ24190_REG_POC_BOOST_LIM_SHIFT                0
+
+#define BQ24190_REG_CCC                0x02 /* Charge Current Control */
+#define BQ24190_REG_CCC_ICHG_MASK              (BIT(7) | BIT(6) | BIT(5) | \
+                                                BIT(4) | BIT(3) | BIT(2))
+#define BQ24190_REG_CCC_ICHG_SHIFT             2
+#define BQ24190_REG_CCC_FORCE_20PCT_MASK       BIT(0)
+#define BQ24190_REG_CCC_FORCE_20PCT_SHIFT      0
+
+#define BQ24190_REG_PCTCC      0x03 /* Pre-charge/Termination Current Cntl */
+#define BQ24190_REG_PCTCC_IPRECHG_MASK         (BIT(7) | BIT(6) | BIT(5) | \
+                                                BIT(4))
+#define BQ24190_REG_PCTCC_IPRECHG_SHIFT                4
+#define BQ24190_REG_PCTCC_ITERM_MASK           (BIT(3) | BIT(2) | BIT(1) | \
+                                                BIT(0))
+#define BQ24190_REG_PCTCC_ITERM_SHIFT          0
+
+#define BQ24190_REG_CVC                0x04 /* Charge Voltage Control */
+#define BQ24190_REG_CVC_VREG_MASK              (BIT(7) | BIT(6) | BIT(5) | \
+                                                BIT(4) | BIT(3) | BIT(2))
+#define BQ24190_REG_CVC_VREG_SHIFT             2
+#define BQ24190_REG_CVC_BATLOWV_MASK           BIT(1)
+#define BQ24190_REG_CVC_BATLOWV_SHIFT          1
+#define BQ24190_REG_CVC_VRECHG_MASK            BIT(0)
+#define BQ24190_REG_CVC_VRECHG_SHIFT           0
+
+#define BQ24190_REG_CTTC       0x05 /* Charge Term/Timer Control */
+#define BQ24190_REG_CTTC_EN_TERM_MASK          BIT(7)
+#define BQ24190_REG_CTTC_EN_TERM_SHIFT         7
+#define BQ24190_REG_CTTC_TERM_STAT_MASK                BIT(6)
+#define BQ24190_REG_CTTC_TERM_STAT_SHIFT       6
+#define BQ24190_REG_CTTC_WATCHDOG_MASK         (BIT(5) | BIT(4))
+#define BQ24190_REG_CTTC_WATCHDOG_SHIFT                4
+#define BQ24190_REG_CTTC_EN_TIMER_MASK         BIT(3)
+#define BQ24190_REG_CTTC_EN_TIMER_SHIFT                3
+#define BQ24190_REG_CTTC_CHG_TIMER_MASK                (BIT(2) | BIT(1))
+#define BQ24190_REG_CTTC_CHG_TIMER_SHIFT       1
+#define BQ24190_REG_CTTC_JEITA_ISET_MASK       BIT(0)
+#define BQ24190_REG_CTTC_JEITA_ISET_SHIFT      0
+
+#define BQ24190_REG_ICTRC      0x06 /* IR Comp/Thermal Regulation Control */
+#define BQ24190_REG_ICTRC_BAT_COMP_MASK                (BIT(7) | BIT(6) | BIT(5))
+#define BQ24190_REG_ICTRC_BAT_COMP_SHIFT       5
+#define BQ24190_REG_ICTRC_VCLAMP_MASK          (BIT(4) | BIT(3) | BIT(2))
+#define BQ24190_REG_ICTRC_VCLAMP_SHIFT         2
+#define BQ24190_REG_ICTRC_TREG_MASK            (BIT(1) | BIT(0))
+#define BQ24190_REG_ICTRC_TREG_SHIFT           0
+
+#define BQ24190_REG_MOC                0x07 /* Misc. Operation Control */
+#define BQ24190_REG_MOC_DPDM_EN_MASK           BIT(7)
+#define BQ24190_REG_MOC_DPDM_EN_SHIFT          7
+#define BQ24190_REG_MOC_TMR2X_EN_MASK          BIT(6)
+#define BQ24190_REG_MOC_TMR2X_EN_SHIFT         6
+#define BQ24190_REG_MOC_BATFET_DISABLE_MASK    BIT(5)
+#define BQ24190_REG_MOC_BATFET_DISABLE_SHIFT   5
+#define BQ24190_REG_MOC_JEITA_VSET_MASK                BIT(4)
+#define BQ24190_REG_MOC_JEITA_VSET_SHIFT       4
+#define BQ24190_REG_MOC_INT_MASK_MASK          (BIT(1) | BIT(0))
+#define BQ24190_REG_MOC_INT_MASK_SHIFT         0
+
+#define BQ24190_REG_SS         0x08 /* System Status */
+#define BQ24190_REG_SS_VBUS_STAT_MASK          (BIT(7) | BIT(6))
+#define BQ24190_REG_SS_VBUS_STAT_SHIFT         6
+#define BQ24190_REG_SS_CHRG_STAT_MASK          (BIT(5) | BIT(4))
+#define BQ24190_REG_SS_CHRG_STAT_SHIFT         4
+#define BQ24190_REG_SS_DPM_STAT_MASK           BIT(3)
+#define BQ24190_REG_SS_DPM_STAT_SHIFT          3
+#define BQ24190_REG_SS_PG_STAT_MASK            BIT(2)
+#define BQ24190_REG_SS_PG_STAT_SHIFT           2
+#define BQ24190_REG_SS_THERM_STAT_MASK         BIT(1)
+#define BQ24190_REG_SS_THERM_STAT_SHIFT                1
+#define BQ24190_REG_SS_VSYS_STAT_MASK          BIT(0)
+#define BQ24190_REG_SS_VSYS_STAT_SHIFT         0
+
+#define BQ24190_REG_F          0x09 /* Fault */
+#define BQ24190_REG_F_WATCHDOG_FAULT_MASK      BIT(7)
+#define BQ24190_REG_F_WATCHDOG_FAULT_SHIFT     7
+#define BQ24190_REG_F_BOOST_FAULT_MASK         BIT(6)
+#define BQ24190_REG_F_BOOST_FAULT_SHIFT                6
+#define BQ24190_REG_F_CHRG_FAULT_MASK          (BIT(5) | BIT(4))
+#define BQ24190_REG_F_CHRG_FAULT_SHIFT         4
+#define BQ24190_REG_F_BAT_FAULT_MASK           BIT(3)
+#define BQ24190_REG_F_BAT_FAULT_SHIFT          3
+#define BQ24190_REG_F_NTC_FAULT_MASK           (BIT(2) | BIT(1) | BIT(0))
+#define BQ24190_REG_F_NTC_FAULT_SHIFT          0
+
+#define BQ24190_REG_VPRS       0x0A /* Vendor/Part/Revision Status */
+#define BQ24190_REG_VPRS_PN_MASK               (BIT(5) | BIT(4) | BIT(3))
+#define BQ24190_REG_VPRS_PN_SHIFT              3
+#define BQ24190_REG_VPRS_PN_24190                      0x4
+#define BQ24190_REG_VPRS_PN_24192                      0x5 /* Also 24193 */
+#define BQ24190_REG_VPRS_PN_24192I                     0x3
+#define BQ24190_REG_VPRS_TS_PROFILE_MASK       BIT(2)
+#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT      2
+#define BQ24190_REG_VPRS_DEV_REG_MASK          (BIT(1) | BIT(0))
+#define BQ24190_REG_VPRS_DEV_REG_SHIFT         0
+
+/*
+ * The FAULT register is latched by the bq24190 (except for NTC_FAULT)
+ * so the first read after a fault returns the latched value and subsequent
+ * reads return the current value.  In order to return the fault status
+ * to the user, have the interrupt handler save the reg's value and retrieve
+ * it in the appropriate health/status routine.  Each routine has its own
+ * flag indicating whether it should use the value stored by the last run
+ * of the interrupt handler or do an actual reg read.  That way each routine
+ * can report back whatever fault may have occured.
+ */
+struct bq24190_dev_info {
+       struct i2c_client               *client;
+       struct device                   *dev;
+       struct power_supply             charger;
+       struct power_supply             battery;
+       char                            model_name[I2C_NAME_SIZE];
+       kernel_ulong_t                  model;
+       unsigned int                    gpio_int;
+       unsigned int                    irq;
+       struct mutex                    f_reg_lock;
+       bool                            first_time;
+       bool                            charger_health_valid;
+       bool                            battery_health_valid;
+       bool                            battery_status_valid;
+       u8                              f_reg;
+       u8                              ss_reg;
+       u8                              watchdog;
+};
+
+/*
+ * The tables below provide a 2-way mapping for the value that goes in
+ * the register field and the real-world value that it represents.
+ * The index of the array is the value that goes in the register; the
+ * number at that index in the array is the real-world value that it
+ * represents.
+ */
+/* REG02[7:2] (ICHG) in uAh */
+static const int bq24190_ccc_ichg_values[] = {
+        512000,  576000,  640000,  704000,  768000,  832000,  896000,  960000,
+       1024000, 1088000, 1152000, 1216000, 1280000, 1344000, 1408000, 1472000,
+       1536000, 1600000, 1664000, 1728000, 1792000, 1856000, 1920000, 1984000,
+       2048000, 2112000, 2176000, 2240000, 2304000, 2368000, 2432000, 2496000,
+       2560000, 2624000, 2688000, 2752000, 2816000, 2880000, 2944000, 3008000,
+       3072000, 3136000, 3200000, 3264000, 3328000, 3392000, 3456000, 3520000,
+       3584000, 3648000, 3712000, 3776000, 3840000, 3904000, 3968000, 4032000,
+       4096000, 4160000, 4224000, 4288000, 4352000, 4416000, 4480000, 4544000
+};
+
+/* REG04[7:2] (VREG) in uV */
+static const int bq24190_cvc_vreg_values[] = {
+       3504000, 3520000, 3536000, 3552000, 3568000, 3584000, 3600000, 3616000,
+       3632000, 3648000, 3664000, 3680000, 3696000, 3712000, 3728000, 3744000,
+       3760000, 3776000, 3792000, 3808000, 3824000, 3840000, 3856000, 3872000,
+       3888000, 3904000, 3920000, 3936000, 3952000, 3968000, 3984000, 4000000,
+       4016000, 4032000, 4048000, 4064000, 4080000, 4096000, 4112000, 4128000,
+       4144000, 4160000, 4176000, 4192000, 4208000, 4224000, 4240000, 4256000,
+       4272000, 4288000, 4304000, 4320000, 4336000, 4352000, 4368000, 4384000,
+       4400000
+};
+
+/* REG06[1:0] (TREG) in tenths of degrees Celcius */
+static const int bq24190_ictrc_treg_values[] = {
+       600, 800, 1000, 1200
+};
+
+/*
+ * Return the index in 'tbl' of greatest value that is less than or equal to
+ * 'val'.  The index range returned is 0 to 'tbl_size' - 1.  Assumes that
+ * the values in 'tbl' are sorted from smallest to largest and 'tbl_size'
+ * is less than 2^8.
+ */
+static u8 bq24190_find_idx(const int tbl[], int tbl_size, int v)
+{
+       int i;
+
+       for (i = 1; i < tbl_size; i++)
+               if (v < tbl[i])
+                       break;
+
+       return i - 1;
+}
+
+/* Basic driver I/O routines */
+
+static int bq24190_read(struct bq24190_dev_info *bdi, u8 reg, u8 *data)
+{
+       int ret;
+
+       ret = i2c_smbus_read_byte_data(bdi->client, reg);
+       if (ret < 0)
+               return ret;
+
+       *data = ret;
+       return 0;
+}
+
+static int bq24190_write(struct bq24190_dev_info *bdi, u8 reg, u8 data)
+{
+       return i2c_smbus_write_byte_data(bdi->client, reg, data);
+}
+
+static int bq24190_read_mask(struct bq24190_dev_info *bdi, u8 reg,
+               u8 mask, u8 shift, u8 *data)
+{
+       u8 v;
+       int ret;
+
+       ret = bq24190_read(bdi, reg, &v);
+       if (ret < 0)
+               return ret;
+
+       v &= mask;
+       v >>= shift;
+       *data = v;
+
+       return 0;
+}
+
+static int bq24190_write_mask(struct bq24190_dev_info *bdi, u8 reg,
+               u8 mask, u8 shift, u8 data)
+{
+       u8 v;
+       int ret;
+
+       ret = bq24190_read(bdi, reg, &v);
+       if (ret < 0)
+               return ret;
+
+       v &= ~mask;
+       v |= ((data << shift) & mask);
+
+       return bq24190_write(bdi, reg, v);
+}
+
+static int bq24190_get_field_val(struct bq24190_dev_info *bdi,
+               u8 reg, u8 mask, u8 shift,
+               const int tbl[], int tbl_size,
+               int *val)
+{
+       u8 v;
+       int ret;
+
+       ret = bq24190_read_mask(bdi, reg, mask, shift, &v);
+       if (ret < 0)
+               return ret;
+
+       v = (v >= tbl_size) ? (tbl_size - 1) : v;
+       *val = tbl[v];
+
+       return 0;
+}
+
+static int bq24190_set_field_val(struct bq24190_dev_info *bdi,
+               u8 reg, u8 mask, u8 shift,
+               const int tbl[], int tbl_size,
+               int val)
+{
+       u8 idx;
+
+       idx = bq24190_find_idx(tbl, tbl_size, val);
+
+       return bq24190_write_mask(bdi, reg, mask, shift, idx);
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * There are a numerous options that are configurable on the bq24190
+ * that go well beyond what the power_supply properties provide access to.
+ * Provide sysfs access to them so they can be examined and possibly modified
+ * on the fly.  They will be provided for the charger power_supply object only
+ * and will be prefixed by 'f_' to make them easier to recognize.
+ */
+
+#define BQ24190_SYSFS_FIELD(_name, r, f, m, store)                     \
+{                                                                      \
+       .attr   = __ATTR(f_##_name, m, bq24190_sysfs_show, store),      \
+       .reg    = BQ24190_REG_##r,                                      \
+       .mask   = BQ24190_REG_##r##_##f##_MASK,                         \
+       .shift  = BQ24190_REG_##r##_##f##_SHIFT,                        \
+}
+
+#define BQ24190_SYSFS_FIELD_RW(_name, r, f)                            \
+               BQ24190_SYSFS_FIELD(_name, r, f, S_IWUSR | S_IRUGO,     \
+                               bq24190_sysfs_store)
+
+#define BQ24190_SYSFS_FIELD_RO(_name, r, f)                            \
+               BQ24190_SYSFS_FIELD(_name, r, f, S_IRUGO, NULL)
+
+static ssize_t bq24190_sysfs_show(struct device *dev,
+               struct device_attribute *attr, char *buf);
+static ssize_t bq24190_sysfs_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count);
+
+struct bq24190_sysfs_field_info {
+       struct device_attribute attr;
+       u8      reg;
+       u8      mask;
+       u8      shift;
+};
+
+/* On i386 ptrace-abi.h defines SS that breaks the macro calls below. */
+#undef SS
+
+static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
+                       /*      sysfs name      reg     field in reg */
+       BQ24190_SYSFS_FIELD_RW(en_hiz,          ISC,    EN_HIZ),
+       BQ24190_SYSFS_FIELD_RW(vindpm,          ISC,    VINDPM),
+       BQ24190_SYSFS_FIELD_RW(iinlim,          ISC,    IINLIM),
+       BQ24190_SYSFS_FIELD_RW(chg_config,      POC,    CHG_CONFIG),
+       BQ24190_SYSFS_FIELD_RW(sys_min,         POC,    SYS_MIN),
+       BQ24190_SYSFS_FIELD_RW(boost_lim,       POC,    BOOST_LIM),
+       BQ24190_SYSFS_FIELD_RW(ichg,            CCC,    ICHG),
+       BQ24190_SYSFS_FIELD_RW(force_20_pct,    CCC,    FORCE_20PCT),
+       BQ24190_SYSFS_FIELD_RW(iprechg,         PCTCC,  IPRECHG),
+       BQ24190_SYSFS_FIELD_RW(iterm,           PCTCC,  ITERM),
+       BQ24190_SYSFS_FIELD_RW(vreg,            CVC,    VREG),
+       BQ24190_SYSFS_FIELD_RW(batlowv,         CVC,    BATLOWV),
+       BQ24190_SYSFS_FIELD_RW(vrechg,          CVC,    VRECHG),
+       BQ24190_SYSFS_FIELD_RW(en_term,         CTTC,   EN_TERM),
+       BQ24190_SYSFS_FIELD_RW(term_stat,       CTTC,   TERM_STAT),
+       BQ24190_SYSFS_FIELD_RO(watchdog,        CTTC,   WATCHDOG),
+       BQ24190_SYSFS_FIELD_RW(en_timer,        CTTC,   EN_TIMER),
+       BQ24190_SYSFS_FIELD_RW(chg_timer,       CTTC,   CHG_TIMER),
+       BQ24190_SYSFS_FIELD_RW(jeta_iset,       CTTC,   JEITA_ISET),
+       BQ24190_SYSFS_FIELD_RW(bat_comp,        ICTRC,  BAT_COMP),
+       BQ24190_SYSFS_FIELD_RW(vclamp,          ICTRC,  VCLAMP),
+       BQ24190_SYSFS_FIELD_RW(treg,            ICTRC,  TREG),
+       BQ24190_SYSFS_FIELD_RW(dpdm_en,         MOC,    DPDM_EN),
+       BQ24190_SYSFS_FIELD_RW(tmr2x_en,        MOC,    TMR2X_EN),
+       BQ24190_SYSFS_FIELD_RW(batfet_disable,  MOC,    BATFET_DISABLE),
+       BQ24190_SYSFS_FIELD_RW(jeita_vset,      MOC,    JEITA_VSET),
+       BQ24190_SYSFS_FIELD_RO(int_mask,        MOC,    INT_MASK),
+       BQ24190_SYSFS_FIELD_RO(vbus_stat,       SS,     VBUS_STAT),
+       BQ24190_SYSFS_FIELD_RO(chrg_stat,       SS,     CHRG_STAT),
+       BQ24190_SYSFS_FIELD_RO(dpm_stat,        SS,     DPM_STAT),
+       BQ24190_SYSFS_FIELD_RO(pg_stat,         SS,     PG_STAT),
+       BQ24190_SYSFS_FIELD_RO(therm_stat,      SS,     THERM_STAT),
+       BQ24190_SYSFS_FIELD_RO(vsys_stat,       SS,     VSYS_STAT),
+       BQ24190_SYSFS_FIELD_RO(watchdog_fault,  F,      WATCHDOG_FAULT),
+       BQ24190_SYSFS_FIELD_RO(boost_fault,     F,      BOOST_FAULT),
+       BQ24190_SYSFS_FIELD_RO(chrg_fault,      F,      CHRG_FAULT),
+       BQ24190_SYSFS_FIELD_RO(bat_fault,       F,      BAT_FAULT),
+       BQ24190_SYSFS_FIELD_RO(ntc_fault,       F,      NTC_FAULT),
+       BQ24190_SYSFS_FIELD_RO(pn,              VPRS,   PN),
+       BQ24190_SYSFS_FIELD_RO(ts_profile,      VPRS,   TS_PROFILE),
+       BQ24190_SYSFS_FIELD_RO(dev_reg,         VPRS,   DEV_REG),
+};
+
+static struct attribute *
+       bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
+
+static const struct attribute_group bq24190_sysfs_attr_group = {
+       .attrs = bq24190_sysfs_attrs,
+};
+
+static void bq24190_sysfs_init_attrs(void)
+{
+       int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
+
+       for (i = 0; i < limit; i++)
+               bq24190_sysfs_attrs[i] = &bq24190_sysfs_field_tbl[i].attr.attr;
+
+       bq24190_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
+}
+
+static struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup(
+               const char *name)
+{
+       int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
+
+       for (i = 0; i < limit; i++)
+               if (!strcmp(name, bq24190_sysfs_field_tbl[i].attr.attr.name))
+                       break;
+
+       if (i >= limit)
+               return NULL;
+
+       return &bq24190_sysfs_field_tbl[i];
+}
+
+static ssize_t bq24190_sysfs_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct bq24190_dev_info *bdi =
+                       container_of(psy, struct bq24190_dev_info, charger);
+       struct bq24190_sysfs_field_info *info;
+       int ret;
+       u8 v;
+
+       info = bq24190_sysfs_field_lookup(attr->attr.name);
+       if (!info)
+               return -EINVAL;
+
+       ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
+       if (ret)
+               return ret;
+
+       return scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
+}
+
+static ssize_t bq24190_sysfs_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t count)
+{
+       struct power_supply *psy = dev_get_drvdata(dev);
+       struct bq24190_dev_info *bdi =
+                       container_of(psy, struct bq24190_dev_info, charger);
+       struct bq24190_sysfs_field_info *info;
+       int ret;
+       u8 v;
+
+       info = bq24190_sysfs_field_lookup(attr->attr.name);
+       if (!info)
+               return -EINVAL;
+
+       ret = kstrtou8(buf, 0, &v);
+       if (ret < 0)
+               return ret;
+
+       ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
+{
+       bq24190_sysfs_init_attrs();
+
+       return sysfs_create_group(&bdi->charger.dev->kobj,
+                       &bq24190_sysfs_attr_group);
+}
+
+static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
+{
+       sysfs_remove_group(&bdi->charger.dev->kobj, &bq24190_sysfs_attr_group);
+}
+#else
+static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
+{
+       return 0;
+}
+
+static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
+#endif
+
+/*
+ * According to the "Host Mode and default Mode" section of the
+ * manual, a write to any register causes the bq24190 to switch
+ * from default mode to host mode.  It will switch back to default
+ * mode after a WDT timeout unless the WDT is turned off as well.
+ * So, by simply turning off the WDT, we accomplish both with the
+ * same write.
+ */
+static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
+{
+       int ret;
+       u8 v;
+
+       ret = bq24190_read(bdi, BQ24190_REG_CTTC, &v);
+       if (ret < 0)
+               return ret;
+
+       bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >>
+                                       BQ24190_REG_CTTC_WATCHDOG_SHIFT);
+       v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
+
+       return bq24190_write(bdi, BQ24190_REG_CTTC, v);
+}
+
+static int bq24190_register_reset(struct bq24190_dev_info *bdi)
+{
+       int ret, limit = 100;
+       u8 v;
+
+       /* Reset the registers */
+       ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
+                       BQ24190_REG_POC_RESET_MASK,
+                       BQ24190_REG_POC_RESET_SHIFT,
+                       0x1);
+       if (ret < 0)
+               return ret;
+
+       /* Reset bit will be cleared by hardware so poll until it is */
+       do {
+               ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
+                               BQ24190_REG_POC_RESET_MASK,
+                               BQ24190_REG_POC_RESET_SHIFT,
+                               &v);
+               if (ret < 0)
+                       return ret;
+
+               if (!v)
+                       break;
+
+               udelay(10);
+       } while (--limit);
+
+       if (!limit)
+               return -EIO;
+
+       return 0;
+}
+
+/* Charger power supply property routines */
+
+static int bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 v;
+       int type, ret;
+
+       ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
+                       BQ24190_REG_POC_CHG_CONFIG_MASK,
+                       BQ24190_REG_POC_CHG_CONFIG_SHIFT,
+                       &v);
+       if (ret < 0)
+               return ret;
+
+       /* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */
+       if (!v) {
+               type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+       } else {
+               ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+                               BQ24190_REG_CCC_FORCE_20PCT_MASK,
+                               BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
+                               &v);
+               if (ret < 0)
+                       return ret;
+
+               type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE :
+                            POWER_SUPPLY_CHARGE_TYPE_FAST;
+       }
+
+       val->intval = type;
+
+       return 0;
+}
+
+static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
+               const union power_supply_propval *val)
+{
+       u8 chg_config, force_20pct, en_term;
+       int ret;
+
+       /*
+        * According to the "Termination when REG02[0] = 1" section of
+        * the bq24190 manual, the trickle charge could be less than the
+        * termination current so it recommends turning off the termination
+        * function.
+        *
+        * Note: AFAICT from the datasheet, the user will have to manually
+        * turn off the charging when in 20% mode.  If its not turned off,
+        * there could be battery damage.  So, use this mode at your own risk.
+        */
+       switch (val->intval) {
+       case POWER_SUPPLY_CHARGE_TYPE_NONE:
+               chg_config = 0x0;
+               break;
+       case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+               chg_config = 0x1;
+               force_20pct = 0x1;
+               en_term = 0x0;
+               break;
+       case POWER_SUPPLY_CHARGE_TYPE_FAST:
+               chg_config = 0x1;
+               force_20pct = 0x0;
+               en_term = 0x1;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (chg_config) { /* Enabling the charger */
+               ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
+                               BQ24190_REG_CCC_FORCE_20PCT_MASK,
+                               BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
+                               force_20pct);
+               if (ret < 0)
+                       return ret;
+
+               ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC,
+                               BQ24190_REG_CTTC_EN_TERM_MASK,
+                               BQ24190_REG_CTTC_EN_TERM_SHIFT,
+                               en_term);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return bq24190_write_mask(bdi, BQ24190_REG_POC,
+                       BQ24190_REG_POC_CHG_CONFIG_MASK,
+                       BQ24190_REG_POC_CHG_CONFIG_SHIFT, chg_config);
+}
+
+static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 v;
+       int health, ret;
+
+       mutex_lock(&bdi->f_reg_lock);
+
+       if (bdi->charger_health_valid) {
+               v = bdi->f_reg;
+               bdi->charger_health_valid = false;
+               mutex_unlock(&bdi->f_reg_lock);
+       } else {
+               mutex_unlock(&bdi->f_reg_lock);
+
+               ret = bq24190_read(bdi, BQ24190_REG_F, &v);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
+               /*
+                * This could be over-current or over-voltage but there's
+                * no way to tell which.  Return 'OVERVOLTAGE' since there
+                * isn't an 'OVERCURRENT' value defined that we can return
+                * even if it was over-current.
+                */
+               health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+       } else {
+               v &= BQ24190_REG_F_CHRG_FAULT_MASK;
+               v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
+
+               switch (v) {
+               case 0x0: /* Normal */
+                       health = POWER_SUPPLY_HEALTH_GOOD;
+                       break;
+               case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
+                       /*
+                        * This could be over-voltage or under-voltage
+                        * and there's no way to tell which.  Instead
+                        * of looking foolish and returning 'OVERVOLTAGE'
+                        * when its really under-voltage, just return
+                        * 'UNSPEC_FAILURE'.
+                        */
+                       health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+                       break;
+               case 0x2: /* Thermal Shutdown */
+                       health = POWER_SUPPLY_HEALTH_OVERHEAT;
+                       break;
+               case 0x3: /* Charge Safety Timer Expiration */
+                       health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+                       break;
+               default:
+                       health = POWER_SUPPLY_HEALTH_UNKNOWN;
+               }
+       }
+
+       val->intval = health;
+
+       return 0;
+}
+
+static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 v;
+       int ret;
+
+       ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
+                       BQ24190_REG_SS_PG_STAT_MASK,
+                       BQ24190_REG_SS_PG_STAT_SHIFT, &v);
+       if (ret < 0)
+               return ret;
+
+       val->intval = v;
+       return 0;
+}
+
+static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 v;
+       int curr, ret;
+
+       ret = bq24190_get_field_val(bdi, BQ24190_REG_CCC,
+                       BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
+                       bq24190_ccc_ichg_values,
+                       ARRAY_SIZE(bq24190_ccc_ichg_values), &curr);
+       if (ret < 0)
+               return ret;
+
+       ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+                       BQ24190_REG_CCC_FORCE_20PCT_MASK,
+                       BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
+       if (ret < 0)
+               return ret;
+
+       /* If FORCE_20PCT is enabled, then current is 20% of ICHG value */
+       if (v)
+               curr /= 5;
+
+       val->intval = curr;
+       return 0;
+}
+
+static int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
+
+       val->intval = bq24190_ccc_ichg_values[idx];
+       return 0;
+}
+
+static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
+               const union power_supply_propval *val)
+{
+       u8 v;
+       int ret, curr = val->intval;
+
+       ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+                       BQ24190_REG_CCC_FORCE_20PCT_MASK,
+                       BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
+       if (ret < 0)
+               return ret;
+
+       /* If FORCE_20PCT is enabled, have to multiply value passed in by 5 */
+       if (v)
+               curr *= 5;
+
+       return bq24190_set_field_val(bdi, BQ24190_REG_CCC,
+                       BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
+                       bq24190_ccc_ichg_values,
+                       ARRAY_SIZE(bq24190_ccc_ichg_values), curr);
+}
+
+static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       int voltage, ret;
+
+       ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC,
+                       BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
+                       bq24190_cvc_vreg_values,
+                       ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage);
+       if (ret < 0)
+               return ret;
+
+       val->intval = voltage;
+       return 0;
+}
+
+static int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
+
+       val->intval = bq24190_cvc_vreg_values[idx];
+       return 0;
+}
+
+static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
+               const union power_supply_propval *val)
+{
+       return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
+                       BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
+                       bq24190_cvc_vreg_values,
+                       ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
+}
+
+static int bq24190_charger_get_property(struct power_supply *psy,
+               enum power_supply_property psp, union power_supply_propval *val)
+{
+       struct bq24190_dev_info *bdi =
+                       container_of(psy, struct bq24190_dev_info, charger);
+       int ret;
+
+       dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+       pm_runtime_get_sync(bdi->dev);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               ret = bq24190_charger_get_charge_type(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = bq24190_charger_get_health(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = bq24190_charger_get_online(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               ret = bq24190_charger_get_current(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+               ret = bq24190_charger_get_current_max(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               ret = bq24190_charger_get_voltage(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+               ret = bq24190_charger_get_voltage_max(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
+               ret = 0;
+               break;
+       case POWER_SUPPLY_PROP_MODEL_NAME:
+               val->strval = bdi->model_name;
+               ret = 0;
+               break;
+       case POWER_SUPPLY_PROP_MANUFACTURER:
+               val->strval = BQ24190_MANUFACTURER;
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+       }
+
+       pm_runtime_put_sync(bdi->dev);
+       return ret;
+}
+
+static int bq24190_charger_set_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               const union power_supply_propval *val)
+{
+       struct bq24190_dev_info *bdi =
+                       container_of(psy, struct bq24190_dev_info, charger);
+       int ret;
+
+       dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+       pm_runtime_get_sync(bdi->dev);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+               ret = bq24190_charger_set_charge_type(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+               ret = bq24190_charger_set_current(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               ret = bq24190_charger_set_voltage(bdi, val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       pm_runtime_put_sync(bdi->dev);
+       return ret;
+}
+
+static int bq24190_charger_property_is_writeable(struct power_supply *psy,
+               enum power_supply_property psp)
+{
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_CHARGE_TYPE:
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+       case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+               ret = 1;
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static enum power_supply_property bq24190_charger_properties[] = {
+       POWER_SUPPLY_PROP_TYPE,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+       POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+       POWER_SUPPLY_PROP_SCOPE,
+       POWER_SUPPLY_PROP_MODEL_NAME,
+       POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static char *bq24190_charger_supplied_to[] = {
+       "main-battery",
+};
+
+static void bq24190_charger_init(struct power_supply *charger)
+{
+       charger->name = "bq24190-charger";
+       charger->type = POWER_SUPPLY_TYPE_USB;
+       charger->properties = bq24190_charger_properties;
+       charger->num_properties = ARRAY_SIZE(bq24190_charger_properties);
+       charger->supplied_to = bq24190_charger_supplied_to;
+       charger->num_supplies = ARRAY_SIZE(bq24190_charger_supplied_to);
+       charger->get_property = bq24190_charger_get_property;
+       charger->set_property = bq24190_charger_set_property;
+       charger->property_is_writeable = bq24190_charger_property_is_writeable;
+}
+
+/* Battery power supply property routines */
+
+static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 ss_reg, chrg_fault;
+       int status, ret;
+
+       mutex_lock(&bdi->f_reg_lock);
+
+       if (bdi->battery_status_valid) {
+               chrg_fault = bdi->f_reg;
+               bdi->battery_status_valid = false;
+               mutex_unlock(&bdi->f_reg_lock);
+       } else {
+               mutex_unlock(&bdi->f_reg_lock);
+
+               ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
+               if (ret < 0)
+                       return ret;
+       }
+
+       chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
+       chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
+
+       ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
+       if (ret < 0)
+               return ret;
+
+       /*
+        * The battery must be discharging when any of these are true:
+        * - there is no good power source;
+        * - there is a charge fault.
+        * Could also be discharging when in "supplement mode" but
+        * there is no way to tell when its in that mode.
+        */
+       if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) {
+               status = POWER_SUPPLY_STATUS_DISCHARGING;
+       } else {
+               ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK;
+               ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT;
+
+               switch (ss_reg) {
+               case 0x0: /* Not Charging */
+                       status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+                       break;
+               case 0x1: /* Pre-charge */
+               case 0x2: /* Fast Charging */
+                       status = POWER_SUPPLY_STATUS_CHARGING;
+                       break;
+               case 0x3: /* Charge Termination Done */
+                       status = POWER_SUPPLY_STATUS_FULL;
+                       break;
+               default:
+                       ret = -EIO;
+               }
+       }
+
+       if (!ret)
+               val->intval = status;
+
+       return ret;
+}
+
+static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 v;
+       int health, ret;
+
+       mutex_lock(&bdi->f_reg_lock);
+
+       if (bdi->battery_health_valid) {
+               v = bdi->f_reg;
+               bdi->battery_health_valid = false;
+               mutex_unlock(&bdi->f_reg_lock);
+       } else {
+               mutex_unlock(&bdi->f_reg_lock);
+
+               ret = bq24190_read(bdi, BQ24190_REG_F, &v);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
+               health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+       } else {
+               v &= BQ24190_REG_F_NTC_FAULT_MASK;
+               v >>= BQ24190_REG_F_NTC_FAULT_SHIFT;
+
+               switch (v) {
+               case 0x0: /* Normal */
+                       health = POWER_SUPPLY_HEALTH_GOOD;
+                       break;
+               case 0x1: /* TS1 Cold */
+               case 0x3: /* TS2 Cold */
+               case 0x5: /* Both Cold */
+                       health = POWER_SUPPLY_HEALTH_COLD;
+                       break;
+               case 0x2: /* TS1 Hot */
+               case 0x4: /* TS2 Hot */
+               case 0x6: /* Both Hot */
+                       health = POWER_SUPPLY_HEALTH_OVERHEAT;
+                       break;
+               default:
+                       health = POWER_SUPPLY_HEALTH_UNKNOWN;
+               }
+       }
+
+       val->intval = health;
+       return 0;
+}
+
+static int bq24190_battery_get_online(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       u8 batfet_disable;
+       int ret;
+
+       ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
+                       BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+                       BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
+       if (ret < 0)
+               return ret;
+
+       val->intval = !batfet_disable;
+       return 0;
+}
+
+static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
+               const union power_supply_propval *val)
+{
+       return bq24190_write_mask(bdi, BQ24190_REG_MOC,
+                       BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+                       BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, !val->intval);
+}
+
+static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
+               union power_supply_propval *val)
+{
+       int temp, ret;
+
+       ret = bq24190_get_field_val(bdi, BQ24190_REG_ICTRC,
+                       BQ24190_REG_ICTRC_TREG_MASK,
+                       BQ24190_REG_ICTRC_TREG_SHIFT,
+                       bq24190_ictrc_treg_values,
+                       ARRAY_SIZE(bq24190_ictrc_treg_values), &temp);
+       if (ret < 0)
+               return ret;
+
+       val->intval = temp;
+       return 0;
+}
+
+static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
+               const union power_supply_propval *val)
+{
+       return bq24190_set_field_val(bdi, BQ24190_REG_ICTRC,
+                       BQ24190_REG_ICTRC_TREG_MASK,
+                       BQ24190_REG_ICTRC_TREG_SHIFT,
+                       bq24190_ictrc_treg_values,
+                       ARRAY_SIZE(bq24190_ictrc_treg_values), val->intval);
+}
+
+static int bq24190_battery_get_property(struct power_supply *psy,
+               enum power_supply_property psp, union power_supply_propval *val)
+{
+       struct bq24190_dev_info *bdi =
+                       container_of(psy, struct bq24190_dev_info, battery);
+       int ret;
+
+       dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+       pm_runtime_get_sync(bdi->dev);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               ret = bq24190_battery_get_status(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_HEALTH:
+               ret = bq24190_battery_get_health(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = bq24190_battery_get_online(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               /* Could be Li-on or Li-polymer but no way to tell which */
+               val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+               ret = 0;
+               break;
+       case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+               ret = bq24190_battery_get_temp_alert_max(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_SCOPE:
+               val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
+               ret = 0;
+               break;
+       default:
+               ret = -ENODATA;
+       }
+
+       pm_runtime_put_sync(bdi->dev);
+       return ret;
+}
+
+static int bq24190_battery_set_property(struct power_supply *psy,
+               enum power_supply_property psp,
+               const union power_supply_propval *val)
+{
+       struct bq24190_dev_info *bdi =
+                       container_of(psy, struct bq24190_dev_info, battery);
+       int ret;
+
+       dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+       pm_runtime_put_sync(bdi->dev);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+               ret = bq24190_battery_set_online(bdi, val);
+               break;
+       case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+               ret = bq24190_battery_set_temp_alert_max(bdi, val);
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       pm_runtime_put_sync(bdi->dev);
+       return ret;
+}
+
+static int bq24190_battery_property_is_writeable(struct power_supply *psy,
+               enum power_supply_property psp)
+{
+       int ret;
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_ONLINE:
+       case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+               ret = 1;
+               break;
+       default:
+               ret = 0;
+       }
+
+       return ret;
+}
+
+static enum power_supply_property bq24190_battery_properties[] = {
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_HEALTH,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
+       POWER_SUPPLY_PROP_SCOPE,
+};
+
+static void bq24190_battery_init(struct power_supply *battery)
+{
+       battery->name = "bq24190-battery";
+       battery->type = POWER_SUPPLY_TYPE_BATTERY;
+       battery->properties = bq24190_battery_properties;
+       battery->num_properties = ARRAY_SIZE(bq24190_battery_properties);
+       battery->get_property = bq24190_battery_get_property;
+       battery->set_property = bq24190_battery_set_property;
+       battery->property_is_writeable = bq24190_battery_property_is_writeable;
+}
+
+static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
+{
+       struct bq24190_dev_info *bdi = data;
+       bool alert_userspace = false;
+       u8 ss_reg, f_reg;
+       int ret;
+
+       pm_runtime_get_sync(bdi->dev);
+
+       ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
+       if (ret < 0) {
+               dev_err(bdi->dev, "Can't read SS reg: %d\n", ret);
+               goto out;
+       }
+
+       if (ss_reg != bdi->ss_reg) {
+               /*
+                * The device is in host mode so when PG_STAT goes from 1->0
+                * (i.e., power removed) HIZ needs to be disabled.
+                */
+               if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) &&
+                               !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) {
+                       ret = bq24190_write_mask(bdi, BQ24190_REG_ISC,
+                                       BQ24190_REG_ISC_EN_HIZ_MASK,
+                                       BQ24190_REG_ISC_EN_HIZ_SHIFT,
+                                       0);
+                       if (ret < 0)
+                               dev_err(bdi->dev, "Can't access ISC reg: %d\n",
+                                       ret);
+               }
+
+               bdi->ss_reg = ss_reg;
+               alert_userspace = true;
+       }
+
+       mutex_lock(&bdi->f_reg_lock);
+
+       ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
+       if (ret < 0) {
+               mutex_unlock(&bdi->f_reg_lock);
+               dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
+               goto out;
+       }
+
+       if (f_reg != bdi->f_reg) {
+               bdi->f_reg = f_reg;
+               bdi->charger_health_valid = true;
+               bdi->battery_health_valid = true;
+               bdi->battery_status_valid = true;
+
+               alert_userspace = true;
+       }
+
+       mutex_unlock(&bdi->f_reg_lock);
+
+       /*
+        * Sometimes bq24190 gives a steady trickle of interrupts even
+        * though the watchdog timer is turned off and neither the STATUS
+        * nor FAULT registers have changed.  Weed out these sprurious
+        * interrupts so userspace isn't alerted for no reason.
+        * In addition, the chip always generates an interrupt after
+        * register reset so we should ignore that one (the very first
+        * interrupt received).
+        */
+       if (alert_userspace && !bdi->first_time) {
+               power_supply_changed(&bdi->charger);
+               power_supply_changed(&bdi->battery);
+               bdi->first_time = false;
+       }
+
+out:
+       pm_runtime_put_sync(bdi->dev);
+
+       dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
+
+       return IRQ_HANDLED;
+}
+
+static int bq24190_hw_init(struct bq24190_dev_info *bdi)
+{
+       u8 v;
+       int ret;
+
+       pm_runtime_get_sync(bdi->dev);
+
+       /* First check that the device really is what its supposed to be */
+       ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS,
+                       BQ24190_REG_VPRS_PN_MASK,
+                       BQ24190_REG_VPRS_PN_SHIFT,
+                       &v);
+       if (ret < 0)
+               goto out;
+
+       if (v != bdi->model) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ret = bq24190_register_reset(bdi);
+       if (ret < 0)
+               goto out;
+
+       ret = bq24190_set_mode_host(bdi);
+out:
+       pm_runtime_put_sync(bdi->dev);
+       return ret;
+}
+
+#ifdef CONFIG_OF
+static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
+{
+       bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
+       if (bdi->irq <= 0)
+               return -1;
+
+       return 0;
+}
+#else
+static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
+{
+       return -1;
+}
+#endif
+
+static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
+               struct bq24190_platform_data *pdata)
+{
+       int ret;
+
+       if (!gpio_is_valid(pdata->gpio_int))
+               return -1;
+
+       ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
+       if (ret < 0)
+               return -1;
+
+       ret = gpio_direction_input(pdata->gpio_int);
+       if (ret < 0)
+               goto out;
+
+       bdi->irq = gpio_to_irq(pdata->gpio_int);
+       if (!bdi->irq)
+               goto out;
+
+       bdi->gpio_int = pdata->gpio_int;
+       return 0;
+
+out:
+       gpio_free(pdata->gpio_int);
+       return -1;
+}
+
+static int bq24190_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+       struct device *dev = &client->dev;
+       struct bq24190_platform_data *pdata = client->dev.platform_data;
+       struct bq24190_dev_info *bdi;
+       int ret;
+
+       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+               dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
+               return -ENODEV;
+       }
+
+       bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
+       if (!bdi) {
+               dev_err(dev, "Can't alloc bdi struct\n");
+               return -ENOMEM;
+       }
+
+       bdi->client = client;
+       bdi->dev = dev;
+       bdi->model = id->driver_data;
+       strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
+       mutex_init(&bdi->f_reg_lock);
+       bdi->first_time = true;
+       bdi->charger_health_valid = false;
+       bdi->battery_health_valid = false;
+       bdi->battery_status_valid = false;
+
+       i2c_set_clientdata(client, bdi);
+
+       if (dev->of_node)
+               ret = bq24190_setup_dt(bdi);
+       else
+               ret = bq24190_setup_pdata(bdi, pdata);
+
+       if (ret) {
+               dev_err(dev, "Can't get irq info\n");
+               return -EINVAL;
+       }
+
+       ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
+                       bq24190_irq_handler_thread,
+                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                       "bq24190-charger", bdi);
+       if (ret < 0) {
+               dev_err(dev, "Can't set up irq handler\n");
+               goto out1;
+       }
+
+       pm_runtime_enable(dev);
+       pm_runtime_resume(dev);
+
+       ret = bq24190_hw_init(bdi);
+       if (ret < 0) {
+               dev_err(dev, "Hardware init failed\n");
+               goto out2;
+       }
+
+       bq24190_charger_init(&bdi->charger);
+
+       ret = power_supply_register(dev, &bdi->charger);
+       if (ret) {
+               dev_err(dev, "Can't register charger\n");
+               goto out2;
+       }
+
+       bq24190_battery_init(&bdi->battery);
+
+       ret = power_supply_register(dev, &bdi->battery);
+       if (ret) {
+               dev_err(dev, "Can't register battery\n");
+               goto out3;
+       }
+
+       ret = bq24190_sysfs_create_group(bdi);
+       if (ret) {
+               dev_err(dev, "Can't create sysfs entries\n");
+               goto out4;
+       }
+
+       return 0;
+
+out4:
+       power_supply_unregister(&bdi->battery);
+out3:
+       power_supply_unregister(&bdi->charger);
+out2:
+       pm_runtime_disable(dev);
+out1:
+       if (bdi->gpio_int)
+               gpio_free(bdi->gpio_int);
+
+       return ret;
+}
+
+static int bq24190_remove(struct i2c_client *client)
+{
+       struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+
+       pm_runtime_get_sync(bdi->dev);
+       bq24190_register_reset(bdi);
+       pm_runtime_put_sync(bdi->dev);
+
+       bq24190_sysfs_remove_group(bdi);
+       power_supply_unregister(&bdi->battery);
+       power_supply_unregister(&bdi->charger);
+       pm_runtime_disable(bdi->dev);
+
+       if (bdi->gpio_int)
+               gpio_free(bdi->gpio_int);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bq24190_pm_suspend(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+
+       pm_runtime_get_sync(bdi->dev);
+       bq24190_register_reset(bdi);
+       pm_runtime_put_sync(bdi->dev);
+
+       return 0;
+}
+
+static int bq24190_pm_resume(struct device *dev)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+
+       bdi->charger_health_valid = false;
+       bdi->battery_health_valid = false;
+       bdi->battery_status_valid = false;
+
+       pm_runtime_get_sync(bdi->dev);
+       bq24190_register_reset(bdi);
+       pm_runtime_put_sync(bdi->dev);
+
+       /* Things may have changed while suspended so alert upper layer */
+       power_supply_changed(&bdi->charger);
+       power_supply_changed(&bdi->battery);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume);
+
+/*
+ * Only support the bq24190 right now.  The bq24192, bq24192i, and bq24193
+ * are similar but not identical so the driver needs to be extended to
+ * support them.
+ */
+static const struct i2c_device_id bq24190_i2c_ids[] = {
+       { "bq24190", BQ24190_REG_VPRS_PN_24190 },
+       { },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id bq24190_of_match[] = {
+       { .compatible = "ti,bq24190", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, bq24190_of_match);
+#else
+static const struct of_device_id bq24190_of_match[] = {
+       { },
+};
+#endif
+
+static struct i2c_driver bq24190_driver = {
+       .probe          = bq24190_probe,
+       .remove         = bq24190_remove,
+       .id_table       = bq24190_i2c_ids,
+       .driver = {
+               .name           = "bq24190-charger",
+               .owner          = THIS_MODULE,
+               .pm             = &bq24190_pm_ops,
+               .of_match_table = of_match_ptr(bq24190_of_match),
+       },
+};
+module_i2c_driver(bq24190_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
+MODULE_ALIAS("i2c:bq24190-charger");
+MODULE_DESCRIPTION("TI BQ24190 Charger Driver");
index c58d0e31bdef51918934aac528882513962c3fbb..d02ae02a7590c63f3199c676657d66d19c7af64e 100644 (file)
@@ -287,7 +287,7 @@ static struct gpio collie_batt_gpios[] = {
 };
 
 #ifdef CONFIG_PM
-static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
+static int collie_bat_suspend(struct ucb1x00_dev *dev)
 {
        /* flush all pending status updates */
        flush_work(&bat_work);
index 0ee1e14f76e9a8957f298cb797fb3243958a0af9..b4513f284bbc48385b7de527b16364921a2195e7 100644 (file)
@@ -458,6 +458,7 @@ max8925_power_dt_init(struct platform_device *pdev)
        of_property_read_u32(np, "fast-charge", &fast_charge);
        of_property_read_u32(np, "no-insert-detect", &no_insert_detect);
        of_property_read_u32(np, "no-temp-support", &no_temp_support);
+       of_node_put(np);
 
        pdata->batt_detect = batt_detect;
        pdata->fast_charge = fast_charge;
index 3b2d5df45e7a06d2b54ba4117f40dd7fe27922d5..00e6672963601754262ced9e842f31c27e07c69e 100644 (file)
@@ -67,23 +67,42 @@ static int __power_supply_changed_work(struct device *dev, void *data)
 
 static void power_supply_changed_work(struct work_struct *work)
 {
+       unsigned long flags;
        struct power_supply *psy = container_of(work, struct power_supply,
                                                changed_work);
 
        dev_dbg(psy->dev, "%s\n", __func__);
 
-       class_for_each_device(power_supply_class, NULL, psy,
-                             __power_supply_changed_work);
-
-       power_supply_update_leds(psy);
-
-       kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
+       spin_lock_irqsave(&psy->changed_lock, flags);
+       if (psy->changed) {
+               psy->changed = false;
+               spin_unlock_irqrestore(&psy->changed_lock, flags);
+               class_for_each_device(power_supply_class, NULL, psy,
+                                     __power_supply_changed_work);
+               power_supply_update_leds(psy);
+               kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
+               spin_lock_irqsave(&psy->changed_lock, flags);
+       }
+       /*
+        * Dependent power supplies (e.g. battery) may have changed state
+        * as a result of this event, so poll again and hold the
+        * wakeup_source until all events are processed.
+        */
+       if (!psy->changed)
+               pm_relax(psy->dev);
+       spin_unlock_irqrestore(&psy->changed_lock, flags);
 }
 
 void power_supply_changed(struct power_supply *psy)
 {
+       unsigned long flags;
+
        dev_dbg(psy->dev, "%s\n", __func__);
 
+       spin_lock_irqsave(&psy->changed_lock, flags);
+       psy->changed = true;
+       pm_stay_awake(psy->dev);
+       spin_unlock_irqrestore(&psy->changed_lock, flags);
        schedule_work(&psy->changed_work);
 }
 EXPORT_SYMBOL_GPL(power_supply_changed);
@@ -500,6 +519,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
                goto check_supplies_failed;
        }
 
+       spin_lock_init(&psy->changed_lock);
+       rc = device_init_wakeup(dev, true);
+       if (rc)
+               goto wakeup_init_failed;
+
        rc = kobject_set_name(&dev->kobj, "%s", psy->name);
        if (rc)
                goto kobject_set_name_failed;
@@ -529,6 +553,7 @@ create_triggers_failed:
 register_cooler_failed:
        psy_unregister_thermal(psy);
 register_thermal_failed:
+wakeup_init_failed:
        device_del(dev);
 kobject_set_name_failed:
 device_add_failed:
@@ -546,6 +571,7 @@ void power_supply_unregister(struct power_supply *psy)
        power_supply_remove_triggers(psy);
        psy_unregister_cooler(psy);
        psy_unregister_thermal(psy);
+       device_init_wakeup(psy->dev, false);
        device_unregister(psy->dev);
 }
 EXPORT_SYMBOL_GPL(power_supply_unregister);
index 29178f78d73cfb79868923bfee7ffbe30b393e1b..44420d1e9094cbbc559341b518fe698a7bd0b4fd 100644 (file)
@@ -118,7 +118,7 @@ static ssize_t power_supply_store_property(struct device *dev,
        long long_val;
 
        /* TODO: support other types than int */
-       ret = strict_strtol(buf, 10, &long_val);
+       ret = kstrtol(buf, 10, &long_val);
        if (ret < 0)
                return ret;
 
index ee039dcead04782a5389ff7827f271e2d3aa2192..9b3ea535b472522721ba42efc655375b1943c41c 100644 (file)
@@ -14,6 +14,12 @@ config POWER_RESET_GPIO
          If your board needs a GPIO high/low to power down, say Y and
          create a binding in your devicetree.
 
+config POWER_RESET_MSM
+       bool "Qualcomm MSM power-off driver"
+       depends on POWER_RESET && ARCH_MSM
+       help
+         Power off and restart support for Qualcomm boards.
+
 config POWER_RESET_QNAP
        bool "QNAP power-off driver"
        depends on OF_GPIO && POWER_RESET && PLAT_ORION
@@ -34,7 +40,14 @@ config POWER_RESET_RESTART
 config POWER_RESET_VEXPRESS
        bool "ARM Versatile Express power-off and reset driver"
        depends on ARM || ARM64
-       depends on POWER_RESET
+       depends on POWER_RESET && VEXPRESS_CONFIG
        help
          Power off and reset support for the ARM Ltd. Versatile
          Express boards.
+
+config POWER_RESET_XGENE
+       bool "APM SoC X-Gene reset driver"
+       depends on ARM64
+       depends on POWER_RESET
+       help
+         Reboot support for the APM SoC X-Gene Eval boards.
index 372807fd83f78d32d352e1479721407293c24fce..3e6ed88725ac0889f32326f91c0450dceab13bc3 100644 (file)
@@ -1,4 +1,6 @@
 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
+obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
 obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
+obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
new file mode 100644 (file)
index 0000000..774f9a3
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+#include <asm/system_misc.h>
+
+static void __iomem *msm_ps_hold;
+
+static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
+{
+       writel(0, msm_ps_hold);
+       mdelay(10000);
+}
+
+static void do_msm_poweroff(void)
+{
+       /* TODO: Add poweroff capability */
+       do_msm_restart(REBOOT_HARD, NULL);
+}
+
+static int msm_restart_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct resource *mem;
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       msm_ps_hold = devm_ioremap_resource(dev, mem);
+       if (IS_ERR(msm_ps_hold))
+               return PTR_ERR(msm_ps_hold);
+
+       pm_power_off = do_msm_poweroff;
+       arm_pm_restart = do_msm_restart;
+       return 0;
+}
+
+static const struct of_device_id of_msm_restart_match[] = {
+       { .compatible = "qcom,pshold", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, of_msm_restart_match);
+
+static struct platform_driver msm_restart_driver = {
+       .probe = msm_restart_probe,
+       .driver = {
+               .name = "msm-restart",
+               .of_match_table = of_match_ptr(of_msm_restart_match),
+       },
+};
+
+static int __init msm_restart_init(void)
+{
+       return platform_driver_register(&msm_restart_driver);
+}
+device_initcall(msm_restart_init);
diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c
new file mode 100644 (file)
index 0000000..ecd55f8
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * AppliedMicro X-Gene SoC Reboot Driver
+ *
+ * Copyright (c) 2013, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ * Author: Loc Ho <lho@apm.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * This driver provides system reboot functionality for APM X-Gene SoC.
+ * For system shutdown, this is board specify. If a board designer
+ * implements GPIO shutdown, use the gpio-poweroff.c driver.
+ */
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <asm/system_misc.h>
+
+struct xgene_reboot_context {
+       struct platform_device *pdev;
+       void *csr;
+       u32 mask;
+};
+
+static struct xgene_reboot_context *xgene_restart_ctx;
+
+static void xgene_restart(char str, const char *cmd)
+{
+       struct xgene_reboot_context *ctx = xgene_restart_ctx;
+       unsigned long timeout;
+
+       /* Issue the reboot */
+       if (ctx)
+               writel(ctx->mask, ctx->csr);
+
+       timeout = jiffies + HZ;
+       while (time_before(jiffies, timeout))
+               cpu_relax();
+
+       dev_emerg(&ctx->pdev->dev, "Unable to restart system\n");
+}
+
+static int xgene_reboot_probe(struct platform_device *pdev)
+{
+       struct xgene_reboot_context *ctx;
+
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               dev_err(&pdev->dev, "out of memory for context\n");
+               return -ENODEV;
+       }
+
+       ctx->csr = of_iomap(pdev->dev.of_node, 0);
+       if (!ctx->csr) {
+               devm_kfree(&pdev->dev, ctx);
+               dev_err(&pdev->dev, "can not map resource\n");
+               return -ENODEV;
+       }
+
+       if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask))
+               ctx->mask = 0xFFFFFFFF;
+
+       ctx->pdev = pdev;
+       arm_pm_restart = xgene_restart;
+       xgene_restart_ctx = ctx;
+
+       return 0;
+}
+
+static struct of_device_id xgene_reboot_of_match[] = {
+       { .compatible = "apm,xgene-reboot" },
+       {}
+};
+
+static struct platform_driver xgene_reboot_driver = {
+       .probe = xgene_reboot_probe,
+       .driver = {
+               .name = "xgene-reboot",
+               .of_match_table = xgene_reboot_of_match,
+       },
+};
+
+static int __init xgene_reboot_init(void)
+{
+       return platform_driver_register(&xgene_reboot_driver);
+}
+device_initcall(xgene_reboot_init);
index 8a6288d87056ef40f92538ce30b30eded9763a9a..1bc5857b8bd5103c0f66bb0bdfb6798d2272c933 100644 (file)
 #include <linux/slab.h>
 #include <linux/i2c/twl4030-madc.h>
 
+/* RX51 specific channels */
+#define TWL4030_MADC_BTEMP_RX51        TWL4030_MADC_ADCIN0
+#define TWL4030_MADC_BCI_RX51  TWL4030_MADC_ADCIN4
+
 struct rx51_device_info {
        struct device *dev;
        struct power_supply bat;
@@ -37,7 +41,7 @@ static int rx51_battery_read_adc(int channel)
 {
        struct twl4030_madc_request req;
 
-       req.channels = 1 << channel;
+       req.channels = channel;
        req.do_avg = 1;
        req.method = TWL4030_MADC_SW1;
        req.func_cb = NULL;
@@ -47,7 +51,7 @@ static int rx51_battery_read_adc(int channel)
        if (twl4030_madc_conversion(&req) <= 0)
                return -ENODATA;
 
-       return req.rbuf[channel];
+       return req.rbuf[ffs(channel) - 1];
 }
 
 /*
@@ -56,7 +60,7 @@ static int rx51_battery_read_adc(int channel)
  */
 static int rx51_battery_read_voltage(struct rx51_device_info *di)
 {
-       int voltage = rx51_battery_read_adc(12);
+       int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
 
        if (voltage < 0)
                return voltage;
@@ -108,7 +112,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
 {
        int min = 0;
        int max = ARRAY_SIZE(rx51_temp_table2) - 1;
-       int raw = rx51_battery_read_adc(0);
+       int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
 
        /* Zero and negative values are undefined */
        if (raw <= 0)
@@ -142,7 +146,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
  */
 static int rx51_battery_read_capacity(struct rx51_device_info *di)
 {
-       int capacity = rx51_battery_read_adc(4);
+       int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
 
        if (capacity < 0)
                return capacity;
index 0224de50c54017b0d60a0f9be53d13d21c44ff1d..f4d80df627c7097470a45638bf0392a688d50b93 100644 (file)
@@ -150,7 +150,7 @@ static void tosa_bat_external_power_changed(struct power_supply *psy)
 
 static irqreturn_t tosa_bat_gpio_isr(int irq, void *data)
 {
-       pr_info("tosa_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
+       pr_info("tosa_bat_gpio irq\n");
        schedule_work(&bat_work);
        return IRQ_HANDLED;
 }
index be98e70380f9750a8b256b473e40622091475d53..d98abe911e376cc69f187c53caae17a979d812d8 100644 (file)
@@ -189,7 +189,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
 
                /* Need to keep regulator on */
                if (!bci->usb_enabled) {
-                       regulator_enable(bci->usb_reg);
+                       ret = regulator_enable(bci->usb_reg);
+                       if (ret) {
+                               dev_err(bci->dev,
+                                       "Failed to enable regulator\n");
+                               return ret;
+                       }
                        bci->usb_enabled = 1;
                }
 
diff --git a/drivers/power/twl4030_madc_battery.c b/drivers/power/twl4030_madc_battery.c
new file mode 100644 (file)
index 0000000..7ef445a
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Dumb driver for LiIon batteries using TWL4030 madc.
+ *
+ * Copyright 2013 Golden Delicious Computers
+ * Lukas Märdian <lukas@goldelico.com>
+ *
+ * Based on dumb driver for gta01 battery
+ * Copyright 2009 Openmoko, Inc
+ * Balaji Rao <balajirrao@openmoko.org>
+ */
+
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/power/twl4030_madc_battery.h>
+
+struct twl4030_madc_battery {
+       struct power_supply psy;
+       struct twl4030_madc_bat_platform_data *pdata;
+};
+
+static enum power_supply_property twl4030_madc_bat_props[] = {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_STATUS,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+       POWER_SUPPLY_PROP_CURRENT_NOW,
+       POWER_SUPPLY_PROP_CAPACITY,
+       POWER_SUPPLY_PROP_CHARGE_FULL,
+       POWER_SUPPLY_PROP_CHARGE_NOW,
+       POWER_SUPPLY_PROP_TEMP,
+       POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+};
+
+static int madc_read(int index)
+{
+       struct twl4030_madc_request req;
+       int val;
+
+       req.channels = index;
+       req.method = TWL4030_MADC_SW2;
+       req.type = TWL4030_MADC_WAIT;
+       req.do_avg = 0;
+       req.raw = false;
+       req.func_cb = NULL;
+
+       val = twl4030_madc_conversion(&req);
+       if (val < 0)
+               return val;
+
+       return req.rbuf[ffs(index) - 1];
+}
+
+static int twl4030_madc_bat_get_charging_status(void)
+{
+       return (madc_read(TWL4030_MADC_ICHG) > 0) ? 1 : 0;
+}
+
+static int twl4030_madc_bat_get_voltage(void)
+{
+       return madc_read(TWL4030_MADC_VBAT);
+}
+
+static int twl4030_madc_bat_get_current(void)
+{
+       return madc_read(TWL4030_MADC_ICHG) * 1000;
+}
+
+static int twl4030_madc_bat_get_temp(void)
+{
+       return madc_read(TWL4030_MADC_BTEMP) * 10;
+}
+
+static int twl4030_madc_bat_voltscale(struct twl4030_madc_battery *bat,
+                                       int volt)
+{
+       struct twl4030_madc_bat_calibration *calibration;
+       int i, res = 0;
+
+       /* choose charging curve */
+       if (twl4030_madc_bat_get_charging_status())
+               calibration = bat->pdata->charging;
+       else
+               calibration = bat->pdata->discharging;
+
+       if (volt > calibration[0].voltage) {
+               res = calibration[0].level;
+       } else {
+               for (i = 0; calibration[i+1].voltage >= 0; i++) {
+                       if (volt <= calibration[i].voltage &&
+                                       volt >= calibration[i+1].voltage) {
+                               /* interval found - interpolate within range */
+                               res = calibration[i].level -
+                                       ((calibration[i].voltage - volt) *
+                                       (calibration[i].level -
+                                       calibration[i+1].level)) /
+                                       (calibration[i].voltage -
+                                       calibration[i+1].voltage);
+                               break;
+                       }
+               }
+       }
+       return res;
+}
+
+static int twl4030_madc_bat_get_property(struct power_supply *psy,
+                                       enum power_supply_property psp,
+                                       union power_supply_propval *val)
+{
+       struct twl4030_madc_battery *bat = container_of(psy,
+                                       struct twl4030_madc_battery, psy);
+
+       switch (psp) {
+       case POWER_SUPPLY_PROP_STATUS:
+               if (twl4030_madc_bat_voltscale(bat,
+                               twl4030_madc_bat_get_voltage()) > 95)
+                       val->intval = POWER_SUPPLY_STATUS_FULL;
+               else {
+                       if (twl4030_madc_bat_get_charging_status())
+                               val->intval = POWER_SUPPLY_STATUS_CHARGING;
+                       else
+                               val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+               }
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+               val->intval = twl4030_madc_bat_get_voltage() * 1000;
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+               val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+               break;
+       case POWER_SUPPLY_PROP_CURRENT_NOW:
+               val->intval = twl4030_madc_bat_get_current();
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               /* assume battery is always present */
+               val->intval = 1;
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_NOW: {
+                       int percent = twl4030_madc_bat_voltscale(bat,
+                                       twl4030_madc_bat_get_voltage());
+                       val->intval = (percent * bat->pdata->capacity) / 100;
+                       break;
+               }
+       case POWER_SUPPLY_PROP_CAPACITY:
+               val->intval = twl4030_madc_bat_voltscale(bat,
+                                       twl4030_madc_bat_get_voltage());
+               break;
+       case POWER_SUPPLY_PROP_CHARGE_FULL:
+               val->intval = bat->pdata->capacity;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+               val->intval = twl4030_madc_bat_get_temp();
+               break;
+       case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: {
+                       int percent = twl4030_madc_bat_voltscale(bat,
+                                       twl4030_madc_bat_get_voltage());
+                       /* in mAh */
+                       int chg = (percent * (bat->pdata->capacity/1000))/100;
+
+                       /* assume discharge with 400 mA (ca. 1.5W) */
+                       val->intval = (3600l * chg) / 400;
+                       break;
+               }
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void twl4030_madc_bat_ext_changed(struct power_supply *psy)
+{
+       struct twl4030_madc_battery *bat = container_of(psy,
+                                       struct twl4030_madc_battery, psy);
+
+       power_supply_changed(&bat->psy);
+}
+
+static int twl4030_cmp(const void *a, const void *b)
+{
+       return ((struct twl4030_madc_bat_calibration *)b)->voltage -
+               ((struct twl4030_madc_bat_calibration *)a)->voltage;
+}
+
+static int twl4030_madc_battery_probe(struct platform_device *pdev)
+{
+       struct twl4030_madc_battery *twl4030_madc_bat;
+       struct twl4030_madc_bat_platform_data *pdata = pdev->dev.platform_data;
+
+       twl4030_madc_bat = kzalloc(sizeof(*twl4030_madc_bat), GFP_KERNEL);
+       if (!twl4030_madc_bat)
+               return -ENOMEM;
+
+       twl4030_madc_bat->psy.name = "twl4030_battery";
+       twl4030_madc_bat->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+       twl4030_madc_bat->psy.properties = twl4030_madc_bat_props;
+       twl4030_madc_bat->psy.num_properties =
+                                       ARRAY_SIZE(twl4030_madc_bat_props);
+       twl4030_madc_bat->psy.get_property = twl4030_madc_bat_get_property;
+       twl4030_madc_bat->psy.external_power_changed =
+                                       twl4030_madc_bat_ext_changed;
+
+       /* sort charging and discharging calibration data */
+       sort(pdata->charging, pdata->charging_size,
+               sizeof(struct twl4030_madc_bat_calibration),
+               twl4030_cmp, NULL);
+       sort(pdata->discharging, pdata->discharging_size,
+               sizeof(struct twl4030_madc_bat_calibration),
+               twl4030_cmp, NULL);
+
+       twl4030_madc_bat->pdata = pdata;
+       platform_set_drvdata(pdev, twl4030_madc_bat);
+       power_supply_register(&pdev->dev, &twl4030_madc_bat->psy);
+
+       return 0;
+}
+
+static int twl4030_madc_battery_remove(struct platform_device *pdev)
+{
+       struct twl4030_madc_battery *bat = platform_get_drvdata(pdev);
+
+       power_supply_unregister(&bat->psy);
+       kfree(bat);
+
+       return 0;
+}
+
+static struct platform_driver twl4030_madc_battery_driver = {
+       .driver = {
+               .name = "twl4030_madc_battery",
+       },
+       .probe  = twl4030_madc_battery_probe,
+       .remove = twl4030_madc_battery_remove,
+};
+module_platform_driver(twl4030_madc_battery_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lukas Märdian <lukas@goldelico.com>");
+MODULE_DESCRIPTION("twl4030_madc battery driver");
index 6efd9b60d8ff1aaeb9f2e3563096c070d24ab642..0c9f2805d076ee9633087fc246018c5758b71257 100644 (file)
@@ -31,7 +31,7 @@ config PPS_CLIENT_PARPORT
 
 config PPS_CLIENT_GPIO
        tristate "PPS client using GPIO"
-       depends on PPS && GENERIC_HARDIRQS
+       depends on PPS
        help
          If you say yes here you get support for a PPS source using
          GPIO. To be useful you must also register a platform device
index eae0eda9ff39cc2c933be97b4bc5c349d76da020..9966124ad988510e25200e3196474208a7a40fa9 100644 (file)
@@ -184,7 +184,6 @@ static int pps_gpio_remove(struct platform_device *pdev)
 {
        struct pps_gpio_device_data *data = platform_get_drvdata(pdev);
 
-       platform_set_drvdata(pdev, NULL);
        pps_unregister_source(data->pps);
        dev_info(&pdev->dev, "removed IRQ %d as PPS source\n", data->irq);
        return 0;
index 9e3498bf302b3ba659f4b89d9a5de7a088af1c15..9654aa3c05cbd87c89b7c7ee2a8d8ebf34d5326e 100644 (file)
@@ -1249,6 +1249,15 @@ config RTC_DRV_SIRFSOC
          Say "yes" here to support the real time clock on SiRF SOC chips.
          This driver can also be built as a module called rtc-sirfsoc.
 
+config RTC_DRV_MOXART
+       tristate "MOXA ART RTC"
+       help
+          If you say yes here you get support for the MOXA ART
+          RTC module.
+
+          This driver can also be built as a module. If so, the module
+          will be called rtc-moxart
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
index d3b4488f48f2405541d401f750c5894b559b4781..2dff3d2009b5f5a3cad9e30b0eed0e726e9a51e1 100644 (file)
@@ -130,3 +130,4 @@ obj-$(CONFIG_RTC_DRV_WM831X)        += rtc-wm831x.o
 obj-$(CONFIG_RTC_DRV_WM8350)   += rtc-wm8350.o
 obj-$(CONFIG_RTC_DRV_X1205)    += rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_SIRFSOC)  += rtc-sirfsoc.o
+obj-$(CONFIG_RTC_DRV_MOXART)   += rtc-moxart.o
index be06d7150de5d4b81f6c84e9c5cc874e26360e70..24e733c98f8b69dd13b0b51ef4eab968068a4b85 100644 (file)
@@ -1018,23 +1018,6 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
        cmos_do_remove(&pnp->dev);
 }
 
-#ifdef CONFIG_PM
-
-static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg)
-{
-       return cmos_suspend(&pnp->dev);
-}
-
-static int cmos_pnp_resume(struct pnp_dev *pnp)
-{
-       return cmos_resume(&pnp->dev);
-}
-
-#else
-#define        cmos_pnp_suspend        NULL
-#define        cmos_pnp_resume         NULL
-#endif
-
 static void cmos_pnp_shutdown(struct pnp_dev *pnp)
 {
        if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev))
@@ -1060,8 +1043,11 @@ static struct pnp_driver cmos_pnp_driver = {
 
        /* flag ensures resume() gets called, and stops syslog spam */
        .flags          = PNP_DRIVER_RES_DO_NOT_CHANGE,
-       .suspend        = cmos_pnp_suspend,
-       .resume         = cmos_pnp_resume,
+#ifdef CONFIG_PM_SLEEP
+       .driver         = {
+                       .pm = &cmos_pm_ops,
+       },
+#endif
 };
 
 #endif /* CONFIG_PNP */
index 308a8fefe76f7730b68b0405a46cc1fe50c1ac96..bc7b4fcf603cd741815915d81be8af7789fefaf9 100644 (file)
@@ -89,7 +89,6 @@ enum ds1511reg {
 struct rtc_plat_data {
        struct rtc_device *rtc;
        void __iomem *ioaddr;           /* virtual base address */
-       int size;                               /* amount of memory mapped */
        int irq;
        unsigned int irqen;
        int alrm_sec;
@@ -479,20 +478,14 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
        struct rtc_plat_data *pdata;
        int ret = 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
-       pdata->size = resource_size(res);
-       if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
-                       pdev->name))
-               return -EBUSY;
-       ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size);
-       if (!ds1511_base)
-               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ds1511_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ds1511_base))
+               return PTR_ERR(ds1511_base);
        pdata->ioaddr = ds1511_base;
        pdata->irq = platform_get_irq(pdev, 0);
 
index 8c6c952e90b1c60ab1581c4b073359ed59a1996c..fd31571941f5102260c96fac9e6f28df890eacb6 100644 (file)
@@ -285,19 +285,14 @@ static int ds1553_rtc_probe(struct platform_device *pdev)
        void __iomem *ioaddr;
        int ret = 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
-       if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE,
-                       pdev->name))
-               return -EBUSY;
 
-       ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE);
-       if (!ioaddr)
-               return -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ioaddr))
+               return PTR_ERR(ioaddr);
        pdata->ioaddr = ioaddr;
        pdata->irq = platform_get_irq(pdev, 0);
 
index eccdc62ae1c0fbf470a8440917d6159022ee2af5..17b73fdc3b6e60036c8ba83ad35df7fbf716cb40 100644 (file)
 #define RTC_BATT_FLAG          0x80
 
 struct rtc_plat_data {
-       struct rtc_device *rtc;
        void __iomem *ioaddr_nvram;
        void __iomem *ioaddr_rtc;
        size_t size_nvram;
-       size_t size;
        unsigned long last_jiffies;
        struct bin_attribute nvram_attr;
 };
@@ -117,11 +115,7 @@ static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
        /* year is 1900 + tm->tm_year */
        tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
 
-       if (rtc_valid_tm(tm) < 0) {
-               dev_err(dev, "retrieved date/time is not valid.\n");
-               rtc_time_to_tm(0, tm);
-       }
-       return 0;
+       return rtc_valid_tm(tm);
 }
 
 static const struct rtc_class_ops ds1742_rtc_ops = {
@@ -168,22 +162,17 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
        void __iomem *ioaddr;
        int ret = 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
-       pdata->size = resource_size(res);
-       if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
-               pdev->name))
-               return -EBUSY;
-       ioaddr = devm_ioremap(&pdev->dev, res->start, pdata->size);
-       if (!ioaddr)
-               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ioaddr))
+               return PTR_ERR(ioaddr);
 
        pdata->ioaddr_nvram = ioaddr;
-       pdata->size_nvram = pdata->size - RTC_SIZE;
+       pdata->size_nvram = resource_size(res) - RTC_SIZE;
        pdata->ioaddr_rtc = ioaddr + pdata->size_nvram;
 
        sysfs_bin_attr_init(&pdata->nvram_attr);
@@ -212,7 +201,6 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
                                  &ds1742_rtc_ops, THIS_MODULE);
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
-       pdata->rtc = rtc;
 
        ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
 
index 549b3c3792d203dcb485517916a6b6c55228573d..580e7b56bde87dd22795dceb73d2168bdcd78957 100644 (file)
@@ -138,17 +138,9 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
-
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), pdev->name))
-               return -EBUSY;
-
-       ep93xx_rtc->mmio_base = devm_ioremap(&pdev->dev, res->start,
-                                            resource_size(res));
-       if (!ep93xx_rtc->mmio_base)
-               return -ENXIO;
+       ep93xx_rtc->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ep93xx_rtc->mmio_base))
+               return PTR_ERR(ep93xx_rtc->mmio_base);
 
        pdev->dev.platform_data = ep93xx_rtc;
        platform_set_drvdata(pdev, ep93xx_rtc);
index 7273b0139e5cdbdb72002ee8ab8a28ec85688f6e..4e2a81854f517cac05b775dd57d234e5d871e15e 100644 (file)
 #include <linux/iio/iio.h>
 #include <linux/rtc.h>
 
-/* Format: HID-SENSOR-usage_id_in_hex */
-/* Usage ID from spec for Time: 0x2000A0 */
-#define DRIVER_NAME "HID-SENSOR-2000a0" /* must be lowercase */
-
 enum hid_time_channel {
        CHANNEL_SCAN_INDEX_YEAR,
        CHANNEL_SCAN_INDEX_MONTH,
@@ -283,9 +279,11 @@ static int hid_time_probe(struct platform_device *pdev)
                                        "hid-sensor-time", &hid_time_rtc_ops,
                                        THIS_MODULE);
 
-       if (IS_ERR(time_state->rtc)) {
+       if (IS_ERR_OR_NULL(time_state->rtc)) {
+               ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV;
+               time_state->rtc = NULL;
+               sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME);
                dev_err(&pdev->dev, "rtc device register failed!\n");
-               return PTR_ERR(time_state->rtc);
        }
 
        return ret;
@@ -300,9 +298,19 @@ static int hid_time_remove(struct platform_device *pdev)
        return 0;
 }
 
+static struct platform_device_id hid_time_ids[] = {
+       {
+               /* Format: HID-SENSOR-usage_id_in_hex_lowercase */
+               .name = "HID-SENSOR-2000a0",
+       },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, hid_time_ids);
+
 static struct platform_driver hid_time_platform_driver = {
+       .id_table = hid_time_ids,
        .driver = {
-               .name   = DRIVER_NAME,
+               .name   = KBUILD_MODNAME,
                .owner  = THIS_MODULE,
        },
        .probe          = hid_time_probe,
index d3a8c8e255de9213716d6cca17c56daea2a5b156..abd7f9091f34efdd21a3dec74d0e50599b10a524 100644 (file)
@@ -375,24 +375,16 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
        struct imxdi_dev *imxdi;
        int rc;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL);
        if (!imxdi)
                return -ENOMEM;
 
        imxdi->pdev = pdev;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res),
-                               pdev->name))
-               return -EBUSY;
-
-       imxdi->ioaddr = devm_ioremap(&pdev->dev, res->start,
-                       resource_size(res));
-       if (imxdi->ioaddr == NULL)
-               return -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       imxdi->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(imxdi->ioaddr))
+               return PTR_ERR(imxdi->ioaddr);
 
        spin_lock_init(&imxdi->irq_lock);
 
index 8276ae94a2a933fd62dbde325954c7bb7fc65de6..bfdbcb82d069c223add9e774db0b543a0249d852 100644 (file)
@@ -201,16 +201,9 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct lpc32xx_rtc *rtc;
-       resource_size_t size;
        int rtcirq;
        u32 tmp;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "Can't get memory resource\n");
-               return -ENOENT;
-       }
-
        rtcirq = platform_get_irq(pdev, 0);
        if (rtcirq < 0 || rtcirq >= NR_IRQS) {
                dev_warn(&pdev->dev, "Can't get interrupt resource\n");
@@ -224,19 +217,10 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
        }
        rtc->irq = rtcirq;
 
-       size = resource_size(res);
-
-       if (!devm_request_mem_region(&pdev->dev, res->start, size,
-                                    pdev->name)) {
-               dev_err(&pdev->dev, "RTC registers are not free\n");
-               return -EBUSY;
-       }
-
-       rtc->rtc_base = devm_ioremap(&pdev->dev, res->start, size);
-       if (!rtc->rtc_base) {
-               dev_err(&pdev->dev, "Can't map memory\n");
-               return -ENOMEM;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(rtc->rtc_base))
+               return PTR_ERR(rtc->rtc_base);
 
        spin_lock_init(&rtc->lock);
 
index 9915cb96014bc96df91952bb67a7786cedc1f4d1..9efe118a28bae7bf42a7c6564640fe8967ecf411 100644 (file)
@@ -240,9 +240,9 @@ static int max77686_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        }
 
        alrm->pending = 0;
-       ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS1, &val);
+       ret = regmap_read(info->max77686->regmap, MAX77686_REG_STATUS2, &val);
        if (ret < 0) {
-               dev_err(info->dev, "%s:%d fail to read status1 reg(%d)\n",
+               dev_err(info->dev, "%s:%d fail to read status2 reg(%d)\n",
                                __func__, __LINE__, ret);
                goto out;
        }
diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c
new file mode 100644 (file)
index 0000000..c29dee0
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * MOXA ART RTC driver.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * Based on code from
+ * Moxa Technology Co., Ltd. <www.moxa.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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+
+#define GPIO_RTC_RESERVED                      0x0C
+#define GPIO_RTC_DATA_SET                      0x10
+#define GPIO_RTC_DATA_CLEAR                    0x14
+#define GPIO_RTC_PIN_PULL_ENABLE               0x18
+#define GPIO_RTC_PIN_PULL_TYPE                 0x1C
+#define GPIO_RTC_INT_ENABLE                    0x20
+#define GPIO_RTC_INT_RAW_STATE                 0x24
+#define GPIO_RTC_INT_MASKED_STATE              0x28
+#define GPIO_RTC_INT_MASK                      0x2C
+#define GPIO_RTC_INT_CLEAR                     0x30
+#define GPIO_RTC_INT_TRIGGER                   0x34
+#define GPIO_RTC_INT_BOTH                      0x38
+#define GPIO_RTC_INT_RISE_NEG                  0x3C
+#define GPIO_RTC_BOUNCE_ENABLE                 0x40
+#define GPIO_RTC_BOUNCE_PRE_SCALE              0x44
+#define GPIO_RTC_PROTECT_W                     0x8E
+#define GPIO_RTC_PROTECT_R                     0x8F
+#define GPIO_RTC_YEAR_W                                0x8C
+#define GPIO_RTC_YEAR_R                                0x8D
+#define GPIO_RTC_DAY_W                         0x8A
+#define GPIO_RTC_DAY_R                         0x8B
+#define GPIO_RTC_MONTH_W                       0x88
+#define GPIO_RTC_MONTH_R                       0x89
+#define GPIO_RTC_DATE_W                                0x86
+#define GPIO_RTC_DATE_R                                0x87
+#define GPIO_RTC_HOURS_W                       0x84
+#define GPIO_RTC_HOURS_R                       0x85
+#define GPIO_RTC_MINUTES_W                     0x82
+#define GPIO_RTC_MINUTES_R                     0x83
+#define GPIO_RTC_SECONDS_W                     0x80
+#define GPIO_RTC_SECONDS_R                     0x81
+#define GPIO_RTC_DELAY_TIME                    8
+
+struct moxart_rtc {
+       struct rtc_device *rtc;
+       spinlock_t rtc_lock;
+       int gpio_data, gpio_sclk, gpio_reset;
+};
+
+static int day_of_year[12] =   { 0, 31, 59, 90, 120, 151, 181,
+                                 212, 243, 273, 304, 334 };
+
+static void moxart_rtc_write_byte(struct device *dev, u8 data)
+{
+       struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev);
+       int i;
+
+       for (i = 0; i < 8; i++, data >>= 1) {
+               gpio_set_value(moxart_rtc->gpio_sclk, 0);
+               gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
+               udelay(GPIO_RTC_DELAY_TIME);
+               gpio_set_value(moxart_rtc->gpio_sclk, 1);
+               udelay(GPIO_RTC_DELAY_TIME);
+       }
+}
+
+static u8 moxart_rtc_read_byte(struct device *dev)
+{
+       struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev);
+       int i;
+       u8 data = 0;
+
+       for (i = 0; i < 8; i++) {
+               gpio_set_value(moxart_rtc->gpio_sclk, 0);
+               udelay(GPIO_RTC_DELAY_TIME);
+               gpio_set_value(moxart_rtc->gpio_sclk, 1);
+               udelay(GPIO_RTC_DELAY_TIME);
+               if (gpio_get_value(moxart_rtc->gpio_data))
+                       data |= (1 << i);
+               udelay(GPIO_RTC_DELAY_TIME);
+       }
+       return data;
+}
+
+static u8 moxart_rtc_read_register(struct device *dev, u8 cmd)
+{
+       struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev);
+       u8 data;
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       gpio_direction_output(moxart_rtc->gpio_data, 0);
+       gpio_set_value(moxart_rtc->gpio_reset, 1);
+       udelay(GPIO_RTC_DELAY_TIME);
+       moxart_rtc_write_byte(dev, cmd);
+       gpio_direction_input(moxart_rtc->gpio_data);
+       udelay(GPIO_RTC_DELAY_TIME);
+       data = moxart_rtc_read_byte(dev);
+       gpio_set_value(moxart_rtc->gpio_sclk, 0);
+       gpio_set_value(moxart_rtc->gpio_reset, 0);
+       udelay(GPIO_RTC_DELAY_TIME);
+
+       local_irq_restore(flags);
+
+       return data;
+}
+
+static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data)
+{
+       struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev);
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       gpio_direction_output(moxart_rtc->gpio_data, 0);
+       gpio_set_value(moxart_rtc->gpio_reset, 1);
+       udelay(GPIO_RTC_DELAY_TIME);
+       moxart_rtc_write_byte(dev, cmd);
+       moxart_rtc_write_byte(dev, data);
+       gpio_set_value(moxart_rtc->gpio_sclk, 0);
+       gpio_set_value(moxart_rtc->gpio_reset, 0);
+       udelay(GPIO_RTC_DELAY_TIME);
+
+       local_irq_restore(flags);
+}
+
+static int moxart_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev);
+
+       spin_lock_irq(&moxart_rtc->rtc_lock);
+
+       moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0);
+       moxart_rtc_write_register(dev, GPIO_RTC_YEAR_W,
+                                 (((tm->tm_year - 100) / 10) << 4) |
+                                 ((tm->tm_year - 100) % 10));
+
+       moxart_rtc_write_register(dev, GPIO_RTC_MONTH_W,
+                                 (((tm->tm_mon + 1) / 10) << 4) |
+                                 ((tm->tm_mon + 1) % 10));
+
+       moxart_rtc_write_register(dev, GPIO_RTC_DATE_W,
+                                 ((tm->tm_mday / 10) << 4) |
+                                 (tm->tm_mday % 10));
+
+       moxart_rtc_write_register(dev, GPIO_RTC_HOURS_W,
+                                 ((tm->tm_hour / 10) << 4) |
+                                 (tm->tm_hour % 10));
+
+       moxart_rtc_write_register(dev, GPIO_RTC_MINUTES_W,
+                                 ((tm->tm_min / 10) << 4) |
+                                 (tm->tm_min % 10));
+
+       moxart_rtc_write_register(dev, GPIO_RTC_SECONDS_W,
+                                 ((tm->tm_sec / 10) << 4) |
+                                 (tm->tm_sec % 10));
+
+       moxart_rtc_write_register(dev, GPIO_RTC_PROTECT_W, 0x80);
+
+       spin_unlock_irq(&moxart_rtc->rtc_lock);
+
+       dev_dbg(dev, "%s: success tm_year=%d tm_mon=%d\n"
+               "tm_mday=%d tm_hour=%d tm_min=%d tm_sec=%d\n",
+               __func__, tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+       return 0;
+}
+
+static int moxart_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct moxart_rtc *moxart_rtc = dev_get_drvdata(dev);
+       unsigned char v;
+
+       spin_lock_irq(&moxart_rtc->rtc_lock);
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_SECONDS_R);
+       tm->tm_sec = (((v & 0x70) >> 4) * 10) + (v & 0x0F);
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_MINUTES_R);
+       tm->tm_min = (((v & 0x70) >> 4) * 10) + (v & 0x0F);
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_HOURS_R);
+       if (v & 0x80) { /* 12-hour mode */
+               tm->tm_hour = (((v & 0x10) >> 4) * 10) + (v & 0x0F);
+               if (v & 0x20) { /* PM mode */
+                       tm->tm_hour += 12;
+                       if (tm->tm_hour >= 24)
+                               tm->tm_hour = 0;
+               }
+       } else { /* 24-hour mode */
+               tm->tm_hour = (((v & 0x30) >> 4) * 10) + (v & 0x0F);
+       }
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_DATE_R);
+       tm->tm_mday = (((v & 0x30) >> 4) * 10) + (v & 0x0F);
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_MONTH_R);
+       tm->tm_mon = (((v & 0x10) >> 4) * 10) + (v & 0x0F);
+       tm->tm_mon--;
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_YEAR_R);
+       tm->tm_year = (((v & 0xF0) >> 4) * 10) + (v & 0x0F);
+       tm->tm_year += 100;
+       if (tm->tm_year <= 69)
+               tm->tm_year += 100;
+
+       v = moxart_rtc_read_register(dev, GPIO_RTC_DAY_R);
+       tm->tm_wday = (v & 0x0f) - 1;
+       tm->tm_yday = day_of_year[tm->tm_mon];
+       tm->tm_yday += (tm->tm_mday - 1);
+       if (tm->tm_mon >= 2) {
+               if (!(tm->tm_year % 4) && (tm->tm_year % 100))
+                       tm->tm_yday++;
+       }
+
+       tm->tm_isdst = 0;
+
+       spin_unlock_irq(&moxart_rtc->rtc_lock);
+
+       return 0;
+}
+
+static const struct rtc_class_ops moxart_rtc_ops = {
+       .read_time      = moxart_rtc_read_time,
+       .set_time       = moxart_rtc_set_time,
+};
+
+static int moxart_rtc_probe(struct platform_device *pdev)
+{
+       struct moxart_rtc *moxart_rtc;
+       int ret = 0;
+
+       moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL);
+       if (!moxart_rtc) {
+               dev_err(&pdev->dev, "devm_kzalloc failed\n");
+               return -ENOMEM;
+       }
+
+       moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,
+                                                 "gpio-rtc-data", 0);
+       if (!gpio_is_valid(moxart_rtc->gpio_data)) {
+               dev_err(&pdev->dev, "invalid gpio (data): %d\n",
+                       moxart_rtc->gpio_data);
+               return moxart_rtc->gpio_data;
+       }
+
+       moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node,
+                                                 "gpio-rtc-sclk", 0);
+       if (!gpio_is_valid(moxart_rtc->gpio_sclk)) {
+               dev_err(&pdev->dev, "invalid gpio (sclk): %d\n",
+                       moxart_rtc->gpio_sclk);
+               return moxart_rtc->gpio_sclk;
+       }
+
+       moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node,
+                                                  "gpio-rtc-reset", 0);
+       if (!gpio_is_valid(moxart_rtc->gpio_reset)) {
+               dev_err(&pdev->dev, "invalid gpio (reset): %d\n",
+                       moxart_rtc->gpio_reset);
+               return moxart_rtc->gpio_reset;
+       }
+
+       spin_lock_init(&moxart_rtc->rtc_lock);
+       platform_set_drvdata(pdev, moxart_rtc);
+
+       ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data");
+       if (ret) {
+               dev_err(&pdev->dev, "can't get rtc_data gpio\n");
+               return ret;
+       }
+
+       ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk,
+                                   GPIOF_DIR_OUT, "rtc_sclk");
+       if (ret) {
+               dev_err(&pdev->dev, "can't get rtc_sclk gpio\n");
+               return ret;
+       }
+
+       ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset,
+                                   GPIOF_DIR_OUT, "rtc_reset");
+       if (ret) {
+               dev_err(&pdev->dev, "can't get rtc_reset gpio\n");
+               return ret;
+       }
+
+       moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                                  &moxart_rtc_ops,
+                                                  THIS_MODULE);
+       if (IS_ERR(moxart_rtc->rtc)) {
+               dev_err(&pdev->dev, "devm_rtc_device_register failed\n");
+               return PTR_ERR(moxart_rtc->rtc);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id moxart_rtc_match[] = {
+       { .compatible = "moxa,moxart-rtc" },
+       { },
+};
+
+static struct platform_driver moxart_rtc_driver = {
+       .probe  = moxart_rtc_probe,
+       .driver = {
+               .name           = "moxart-rtc",
+               .owner          = THIS_MODULE,
+               .of_match_table = moxart_rtc_match,
+       },
+};
+module_platform_driver(moxart_rtc_driver);
+
+MODULE_DESCRIPTION("MOXART RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
index baab802f2153c27ee3b1358b79871e4d7f5e2a2f..d536c5962c99f1e6477f63b377e7445c354c5d14 100644 (file)
@@ -221,26 +221,17 @@ static int __init mv_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct rtc_plat_data *pdata;
-       resource_size_t size;
        u32 rtc_time;
        int ret = 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
 
-       size = resource_size(res);
-       if (!devm_request_mem_region(&pdev->dev, res->start, size,
-                                    pdev->name))
-               return -EBUSY;
-
-       pdata->ioaddr = devm_ioremap(&pdev->dev, res->start, size);
-       if (!pdata->ioaddr)
-               return -ENOMEM;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pdata->ioaddr))
+               return PTR_ERR(pdata->ioaddr);
 
        pdata->clk = devm_clk_get(&pdev->dev, NULL);
        /* Not all SoCs require a clock.*/
index ab87bacb8f880b69f01182c44d7d5cf6522c24e6..50c572645546bf20d6a4414d454136f95636d9a3 100644 (file)
@@ -377,22 +377,16 @@ static int mxc_rtc_probe(struct platform_device *pdev)
        unsigned long rate;
        int ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
 
        pdata->devtype = pdev->id_entry->driver_data;
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), pdev->name))
-               return -EBUSY;
-
-       pdata->ioaddr = devm_ioremap(&pdev->dev, res->start,
-                                    resource_size(res));
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pdata->ioaddr))
+               return PTR_ERR(pdata->ioaddr);
 
        pdata->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(pdata->clk)) {
index 22861c5e0c596fff3c87182b1beb1f1c9cdaf109..248653c74b8010e0d942947c4cfddd9549379880 100644 (file)
@@ -99,7 +99,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
        if (!timeout)
                return ERR_PTR(-EPERM);
 
-       return 0;
+       return NULL;
 }
 
 static int nuc900_rtc_bcd2bin(unsigned int timereg,
index c6ffbaec32a4b509609fe03dad3e57b2db16e439..c7d97ee59327a7bec079b7ab452fdbbb45728b56 100644 (file)
@@ -70,6 +70,8 @@
 #define OMAP_RTC_KICK0_REG             0x6c
 #define OMAP_RTC_KICK1_REG             0x70
 
+#define OMAP_RTC_IRQWAKEEN             0x7c
+
 /* OMAP_RTC_CTRL_REG bit fields: */
 #define OMAP_RTC_CTRL_SPLIT            (1<<7)
 #define OMAP_RTC_CTRL_DISABLE          (1<<6)
 #define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)
 #define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2)
 
+/* OMAP_RTC_IRQWAKEEN bit fields: */
+#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN    (1<<1)
+
 /* OMAP_RTC_KICKER values */
 #define        KICK0_VALUE                     0x83e70b13
 #define        KICK1_VALUE                     0x95a4f1e0
 
 #define        OMAP_RTC_HAS_KICKER             0x1
 
+/*
+ * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
+ * generation for event Alarm.
+ */
+#define        OMAP_RTC_HAS_IRQWAKEEN          0x2
+
 static void __iomem    *rtc_base;
 
 #define rtc_read(addr)         readb(rtc_base + (addr))
@@ -299,12 +310,18 @@ static struct rtc_class_ops omap_rtc_ops = {
 static int omap_rtc_alarm;
 static int omap_rtc_timer;
 
-#define        OMAP_RTC_DATA_DA830_IDX 1
+#define        OMAP_RTC_DATA_AM3352_IDX        1
+#define        OMAP_RTC_DATA_DA830_IDX         2
 
 static struct platform_device_id omap_rtc_devtype[] = {
        {
                .name   = DRIVER_NAME,
-       }, {
+       },
+       [OMAP_RTC_DATA_AM3352_IDX] = {
+               .name   = "am3352-rtc",
+               .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN,
+       },
+       [OMAP_RTC_DATA_DA830_IDX] = {
                .name   = "da830-rtc",
                .driver_data = OMAP_RTC_HAS_KICKER,
        },
@@ -316,6 +333,9 @@ static const struct of_device_id omap_rtc_of_match[] = {
        {       .compatible     = "ti,da830-rtc",
                .data           = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX],
        },
+       {       .compatible     = "ti,am3352-rtc",
+               .data           = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX],
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
@@ -464,16 +484,28 @@ static u8 irqstat;
 
 static int omap_rtc_suspend(struct device *dev)
 {
+       u8 irqwake_stat;
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct platform_device_id *id_entry =
+                                       platform_get_device_id(pdev);
+
        irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
 
        /* FIXME the RTC alarm is not currently acting as a wakeup event
-        * source, and in fact this enable() call is just saving a flag
-        * that's never used...
+        * source on some platforms, and in fact this enable() call is just
+        * saving a flag that's never used...
         */
-       if (device_may_wakeup(dev))
+       if (device_may_wakeup(dev)) {
                enable_irq_wake(omap_rtc_alarm);
-       else
+
+               if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) {
+                       irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN);
+                       irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
+                       rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN);
+               }
+       } else {
                rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+       }
 
        /* Disable the clock/module */
        pm_runtime_put_sync(dev);
@@ -483,13 +515,25 @@ static int omap_rtc_suspend(struct device *dev)
 
 static int omap_rtc_resume(struct device *dev)
 {
+       u8 irqwake_stat;
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct platform_device_id *id_entry =
+                               platform_get_device_id(pdev);
+
        /* Enable the clock/module so that we can access the registers */
        pm_runtime_get_sync(dev);
 
-       if (device_may_wakeup(dev))
+       if (device_may_wakeup(dev)) {
                disable_irq_wake(omap_rtc_alarm);
-       else
+
+               if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) {
+                       irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN);
+                       irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
+                       rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN);
+               }
+       } else {
                rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
+       }
        return 0;
 }
 #endif
index a1fecc8d97fc5e0f30f3c06b8e3d00b466289420..fffb7d3449d785e982883921cacf2b3a7dc3a307 100644 (file)
@@ -238,6 +238,15 @@ static int palmas_rtc_probe(struct platform_device *pdev)
        struct palmas *palmas = dev_get_drvdata(pdev->dev.parent);
        struct palmas_rtc *palmas_rtc = NULL;
        int ret;
+       bool enable_bb_charging = false;
+       bool high_bb_charging;
+
+       if (pdev->dev.of_node) {
+               enable_bb_charging = of_property_read_bool(pdev->dev.of_node,
+                                       "ti,backup-battery-chargeable");
+               high_bb_charging = of_property_read_bool(pdev->dev.of_node,
+                                       "ti,backup-battery-charge-high-current");
+       }
 
        palmas_rtc = devm_kzalloc(&pdev->dev, sizeof(struct palmas_rtc),
                        GFP_KERNEL);
@@ -254,6 +263,32 @@ static int palmas_rtc_probe(struct platform_device *pdev)
        palmas_rtc->dev = &pdev->dev;
        platform_set_drvdata(pdev, palmas_rtc);
 
+       if (enable_bb_charging) {
+               unsigned reg = PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG;
+
+               if (high_bb_charging)
+                       reg = 0;
+
+               ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
+                       PALMAS_BACKUP_BATTERY_CTRL,
+                       PALMAS_BACKUP_BATTERY_CTRL_BBS_BBC_LOW_ICHRG, reg);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "BACKUP_BATTERY_CTRL update failed, %d\n", ret);
+                       return ret;
+               }
+
+               ret = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
+                       PALMAS_BACKUP_BATTERY_CTRL,
+                       PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN,
+                       PALMAS_BACKUP_BATTERY_CTRL_BB_CHG_EN);
+               if (ret < 0) {
+                       dev_err(&pdev->dev,
+                               "BACKUP_BATTERY_CTRL update failed, %d\n", ret);
+                       return ret;
+               }
+       }
+
        /* Start RTC */
        ret = palmas_update_bits(palmas, PALMAS_RTC_BASE, PALMAS_RTC_CTRL_REG,
                        PALMAS_RTC_CTRL_REG_STOP_RTC,
index 205b9f7da1b805f48672275b7324343ad2fb202b..1ee514a3972c7d5c91fc8c8dc88d641a0e8c25ee 100644 (file)
@@ -203,11 +203,6 @@ static int pcf2127_probe(struct i2c_client *client,
        return 0;
 }
 
-static int pcf2127_remove(struct i2c_client *client)
-{
-       return 0;
-}
-
 static const struct i2c_device_id pcf2127_id[] = {
        { "pcf2127", 0 },
        { }
@@ -229,7 +224,6 @@ static struct i2c_driver pcf2127_driver = {
                .of_match_table = of_match_ptr(pcf2127_of_match),
        },
        .probe          = pcf2127_probe,
-       .remove         = pcf2127_remove,
        .id_table       = pcf2127_id,
 };
 
index aa7ed4b5f7f06c7e37ab37b69b6f6e94cd177ad1..63460cf80f1b3d6068d915ad9b4707b202b817ef 100644 (file)
@@ -44,6 +44,7 @@ struct sirfsoc_rtc_drv {
        struct rtc_device       *rtc;
        u32                     rtc_base;
        u32                     irq;
+       unsigned                irq_wake;
        /* Overflow for every 8 years extra time */
        u32                     overflow_rtc;
 #ifdef CONFIG_PM
@@ -355,8 +356,8 @@ static int sirfsoc_rtc_suspend(struct device *dev)
        rtcdrv->saved_counter =
                sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
        rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc;
-       if (device_may_wakeup(&pdev->dev))
-               enable_irq_wake(rtcdrv->irq);
+       if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq))
+               rtcdrv->irq_wake = 1;
 
        return 0;
 }
@@ -423,8 +424,10 @@ static int sirfsoc_rtc_resume(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
        sirfsoc_rtc_thaw(dev);
-       if (device_may_wakeup(&pdev->dev))
+       if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
                disable_irq_wake(rtcdrv->irq);
+               rtcdrv->irq_wake = 0;
+       }
 
        return 0;
 }
@@ -434,8 +437,10 @@ static int sirfsoc_rtc_restore(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev);
 
-       if (device_may_wakeup(&pdev->dev))
+       if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) {
                disable_irq_wake(rtcdrv->irq);
+               rtcdrv->irq_wake = 0;
+       }
        return 0;
 }
 
index af5e97e3f2724d0204d3f065f69061e1cf0447bd..a176ba6146837bd7c21ba901ce249e988d85abc2 100644 (file)
@@ -294,19 +294,14 @@ static int stk17ta8_rtc_probe(struct platform_device *pdev)
        void __iomem *ioaddr;
        int ret = 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
        pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
-       if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE,
-                       pdev->name))
-               return -EBUSY;
-       ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE);
-       if (!ioaddr)
-               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       ioaddr = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ioaddr))
+               return PTR_ERR(ioaddr);
        pdata->ioaddr = ioaddr;
        pdata->irq = platform_get_irq(pdev, 0);
 
index f9a0677e4e3b5fb14cfb007d515f0bfc07cf66f2..4f87234e0dee0a6f8daf84e7fd94c6b9d517bfee 100644 (file)
@@ -244,9 +244,6 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
        struct resource *res;
        int irq, ret;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
        irq = platform_get_irq(pdev, 0);
        if (irq < 0)
                return -ENODEV;
@@ -255,13 +252,10 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
        platform_set_drvdata(pdev, pdata);
 
-       if (!devm_request_mem_region(&pdev->dev, res->start,
-                                    resource_size(res), pdev->name))
-               return -EBUSY;
-       pdata->rtcreg = devm_ioremap(&pdev->dev, res->start,
-                                    resource_size(res));
-       if (!pdata->rtcreg)
-               return -EBUSY;
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       pdata->rtcreg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(pdata->rtcreg))
+               return PTR_ERR(pdata->rtcreg);
 
        spin_lock_init(&pdata->lock);
        tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);
index feca317b33debfb78409540fab75b1841c0019a0..92bd22ce676012697be18504d96741b4a3910466 100644 (file)
@@ -645,7 +645,7 @@ dasd_diag_init(void)
        }
        ASCEBC(dasd_diag_discipline.ebcname, 4);
 
-       service_subclass_irq_register();
+       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
        register_external_interrupt(0x2603, dasd_ext_handler);
        dasd_diag_discipline_pointer = &dasd_diag_discipline;
        return 0;
@@ -655,7 +655,7 @@ static void __exit
 dasd_diag_cleanup(void)
 {
        unregister_external_interrupt(0x2603, dasd_ext_handler);
-       service_subclass_irq_unregister();
+       irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
        dasd_diag_discipline_pointer = NULL;
 }
 
index 96e52bf7593020c962fe6f6d1eb8cfcbf6fc942b..f93cc32eb81871b468c3439ecb03de5c19783710 100644 (file)
@@ -524,20 +524,20 @@ static const struct file_operations fs3270_fops = {
        .llseek         = no_llseek,
 };
 
-void fs3270_create_cb(int minor)
+static void fs3270_create_cb(int minor)
 {
        __register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops);
        device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
                      NULL, "3270/tub%d", minor);
 }
 
-void fs3270_destroy_cb(int minor)
+static void fs3270_destroy_cb(int minor)
 {
        device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor));
        __unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
 }
 
-struct raw3270_notifier fs3270_notifier =
+static struct raw3270_notifier fs3270_notifier =
 {
        .create = fs3270_create_cb,
        .destroy = fs3270_destroy_cb,
index 3e4fb4e858da7514eb7a1c5677d23577acba7793..a3aa374799dcf99bd334b6e49c8d7753838fbdc3 100644 (file)
@@ -910,12 +910,12 @@ sclp_check_interface(void)
                spin_unlock_irqrestore(&sclp_lock, flags);
                /* Enable service-signal interruption - needs to happen
                 * with IRQs enabled. */
-               service_subclass_irq_register();
+               irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
                /* Wait for signal from interrupt or timeout */
                sclp_sync_wait();
                /* Disable service-signal interruption - needs to happen
                 * with IRQs enabled. */
-               service_subclass_irq_unregister();
+               irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
                spin_lock_irqsave(&sclp_lock, flags);
                del_timer(&sclp_request_timer);
                if (sclp_init_req.status == SCLP_REQ_DONE &&
@@ -1131,7 +1131,7 @@ sclp_init(void)
        spin_unlock_irqrestore(&sclp_lock, flags);
        /* Enable service-signal external interruption - needs to happen with
         * IRQs enabled. */
-       service_subclass_irq_register();
+       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
        sclp_init_mask(1);
        return 0;
 
index cee69dac3e182b6e2de94300b49ac9ec35658430..a0f47c83fd62f94205a987a728edf207f86c3bc6 100644 (file)
@@ -1845,17 +1845,17 @@ static const struct tty_operations tty3270_ops = {
        .set_termios = tty3270_set_termios
 };
 
-void tty3270_create_cb(int minor)
+static void tty3270_create_cb(int minor)
 {
        tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
 }
 
-void tty3270_destroy_cb(int minor)
+static void tty3270_destroy_cb(int minor)
 {
        tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
 }
 
-struct raw3270_notifier tty3270_notifier =
+static struct raw3270_notifier tty3270_notifier =
 {
        .create = tty3270_create_cb,
        .destroy = tty3270_destroy_cb,
index 9e5e14686e75b6ff37bfbe9faa555470c8263ab7..794820a123d0c83c07b1b2e546efc84c25daa14a 100644 (file)
@@ -30,8 +30,8 @@
 
 #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)
 
-#define TO_USER                0
-#define TO_KERNEL      1
+#define TO_USER                1
+#define TO_KERNEL      0
 #define CHUNK_INFO_SIZE        34 /* 2 16-byte char, each followed by blank */
 
 enum arch_id {
@@ -73,7 +73,7 @@ static struct ipl_parameter_block *ipl_block;
  * @count: Size of buffer, which should be copied
  * @mode:  Either TO_KERNEL or TO_USER
  */
-static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
+int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
 {
        int offs, blk_num;
        static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
index d4174b82a1a953e98277f5215dba5a4e20f36b38..02300dcfac91f87397c030f11eab825d1361f393 100644 (file)
@@ -413,7 +413,7 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
        register unsigned long reg2 asm ("2") = (unsigned long) msg;
        register unsigned long reg3 asm ("3") = (unsigned long) length;
        register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
-       register unsigned long reg5 asm ("5") = (unsigned int) psmid;
+       register unsigned long reg5 asm ("5") = psmid & 0xffffffff;
 
        if (special == 1)
                reg0 |= 0x400000UL;
index 2ea6165366b6f4d8da48f74859aeae3e705f5b7d..af2166fa515953ff8beaf57226182095c67f9654 100644 (file)
@@ -472,7 +472,7 @@ static int __init kvm_devices_init(void)
 
        INIT_WORK(&hotplug_work, hotplug_devices);
 
-       service_subclass_irq_register();
+       irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
        register_external_interrupt(0x2603, kvm_extint_handler);
 
        scan_devices();
index 6917b4f5ac9e02525fd0525ac641b02611dca71d..22d5a949ec83c627a11d0ca45a4ab52d06b42c06 100644 (file)
@@ -692,7 +692,7 @@ ahc_find_pci_device(ahc_dev_softc_t pci)
         * ID as valid.
         */
        if (ahc_get_pci_function(pci) > 0
-        && ahc_9005_subdevinfo_valid(vendor, device, subvendor, subdevice)
+        && ahc_9005_subdevinfo_valid(device, vendor, subdevice, subvendor)
         && SUBID_9005_MFUNCENB(subdevice) == 0)
                return (NULL);
 
index 08b22a901c2590e3aca12ebcfe4484e143c54460..d7ca9305ff457037089e1edba2cc33b28bec1073 100644 (file)
 #define BNX2FC_RQ_WQE_SIZE             (BNX2FC_RQ_BUF_SZ)
 #define BNX2FC_XFERQ_WQE_SIZE          (sizeof(struct fcoe_xfrqe))
 #define BNX2FC_CONFQ_WQE_SIZE          (sizeof(struct fcoe_confqe))
-#define BNX2FC_5771X_DB_PAGE_SIZE      128
+#define BNX2X_DB_SHIFT                 3
 
 #define BNX2FC_TASK_SIZE               128
 #define        BNX2FC_TASKS_PER_PAGE           (PAGE_SIZE/BNX2FC_TASK_SIZE)
index c0d035a8f8f9e79a08a0b313742c2f7b0009ca6f..46a37657307fd9dae74e800709f80f2140da65a5 100644 (file)
@@ -1421,8 +1421,7 @@ int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt)
 
        reg_base = pci_resource_start(hba->pcidev,
                                        BNX2X_DOORBELL_PCI_BAR);
-       reg_off = BNX2FC_5771X_DB_PAGE_SIZE *
-                       (context_id & 0x1FFFF) + DPM_TRIGER_TYPE;
+       reg_off = (1 << BNX2X_DB_SHIFT) * (context_id & 0x1FFFF);
        tgt->ctx_base = ioremap_nocache(reg_base + reg_off, 4);
        if (!tgt->ctx_base)
                return -ENOMEM;
index 6940f0930a848d0523249c2e695345dfe49ecf88..c73bbcb63c02049b1147b98829d8a3e4b4c8ebf5 100644 (file)
@@ -64,7 +64,7 @@
 #define MAX_PAGES_PER_CTRL_STRUCT_POOL 8
 #define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS     4
 
-#define BNX2I_5771X_DBELL_PAGE_SIZE    128
+#define BNX2X_DB_SHIFT                 3
 
 /* 5706/08 hardware has limit on maximum buffer size per BD it can handle */
 #define MAX_BD_LENGTH                  65535
index af3e675d4d48fb51b4f01bdf7acf2f9b6b3c17d6..5be718c241c4f329edb1c23e684daa7b4681a0f1 100644 (file)
@@ -2738,8 +2738,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
        if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) {
                reg_base = pci_resource_start(ep->hba->pcidev,
                                              BNX2X_DOORBELL_PCI_BAR);
-               reg_off = BNX2I_5771X_DBELL_PAGE_SIZE * (cid_num & 0x1FFFF) +
-                         DPM_TRIGER_TYPE;
+               reg_off = (1 << BNX2X_DB_SHIFT) * (cid_num & 0x1FFFF);
                ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4);
                goto arm_cq;
        }
index 8582929b1fef4a7dc1fde4fa01aaca5472cb5583..2ec3c23275b833b63465da412ffff29e20496533 100644 (file)
@@ -860,8 +860,13 @@ bool esas2r_process_fs_ioctl(struct esas2r_adapter *a,
                return false;
        }
 
+       if (fsc->command >= cmdcnt) {
+               fs->status = ATTO_STS_INV_FUNC;
+               return false;
+       }
+
        func = cmd_to_fls_func[fsc->command];
-       if (fsc->command >= cmdcnt || func == 0xFF) {
+       if (func == 0xFF) {
                fs->status = ATTO_STS_INV_FUNC;
                return false;
        }
@@ -1355,7 +1360,7 @@ void esas2r_nvram_set_defaults(struct esas2r_adapter *a)
        u32 time = jiffies_to_msecs(jiffies);
 
        esas2r_lock_clear_flags(&a->flags, AF_NVR_VALID);
-       memcpy(n, &default_sas_nvram, sizeof(struct esas2r_sas_nvram));
+       *n = default_sas_nvram;
        n->sas_addr[3] |= 0x0F;
        n->sas_addr[4] = HIBYTE(LOWORD(time));
        n->sas_addr[5] = LOBYTE(LOWORD(time));
@@ -1373,7 +1378,7 @@ void esas2r_nvram_get_defaults(struct esas2r_adapter *a,
         * address out first.
         */
        memcpy(&sas_addr[0], a->nvram->sas_addr, 8);
-       memcpy(nvram, &default_sas_nvram, sizeof(struct esas2r_sas_nvram));
+       *nvram = default_sas_nvram;
        memcpy(&nvram->sas_addr[0], &sas_addr[0], 8);
 }
 
index 3a798e7d5c5608c3790975183aea380c9538c8e9..da1869df24088a2c2647027033ecd8d3e171c130 100644 (file)
@@ -665,7 +665,7 @@ void esas2r_kill_adapter(int i)
 
 int esas2r_cleanup(struct Scsi_Host *host)
 {
-       struct esas2r_adapter *a = (struct esas2r_adapter *)host->hostdata;
+       struct esas2r_adapter *a;
        int index;
 
        if (host == NULL) {
@@ -678,6 +678,7 @@ int esas2r_cleanup(struct Scsi_Host *host)
        }
 
        esas2r_debug("esas2r_cleanup called for host %p", host);
+       a = (struct esas2r_adapter *)host->hostdata;
        index = a->index;
        esas2r_kill_adapter(index);
        return index;
@@ -808,7 +809,7 @@ static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a)
        int pcie_cap_reg;
 
        pcie_cap_reg = pci_find_capability(a->pcid, PCI_CAP_ID_EXP);
-       if (0xffff && pcie_cap_reg) {
+       if (0xffff & pcie_cap_reg) {
                u16 devcontrol;
 
                pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL,
@@ -1550,8 +1551,7 @@ void esas2r_reset_chip(struct esas2r_adapter *a)
         * to not overwrite a previous crash that was saved.
         */
        if ((a->flags2 & AF2_COREDUMP_AVAIL)
-           && !(a->flags2 & AF2_COREDUMP_SAVED)
-           && a->fw_coredump_buff) {
+           && !(a->flags2 & AF2_COREDUMP_SAVED)) {
                esas2r_read_mem_block(a,
                                      a->fw_coredump_buff,
                                      MW_DATA_ADDR_SRAM + 0x80000,
index f3d0cb8859721335998e81423a58776b85ad4eed..e5b09027e066406daceab374ff299ec2d83f7d38 100644 (file)
@@ -415,7 +415,7 @@ static int csmi_ioctl_callback(struct esas2r_adapter *a,
                lun = tm->lun;
        }
 
-       if (path > 0 || tid > ESAS2R_MAX_ID) {
+       if (path > 0) {
                rq->func_rsp.ioctl_rsp.csmi.csmi_status = cpu_to_le32(
                        CSMI_STS_INV_PARAM);
                return false;
index f8ec6d63684644ab04388036f3f34d241cb9e701..fd1392879647c63f6d2709db2d2033981ea87b5d 100644 (file)
@@ -302,6 +302,7 @@ static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
                if (vi->cmd.cfg.cfg_func == VDA_CFG_GET_INIT) {
                        struct atto_ioctl_vda_cfg_cmd *cfg = &vi->cmd.cfg;
                        struct atto_vda_cfg_rsp *rsp = &rq->func_rsp.cfg_rsp;
+                       char buf[sizeof(cfg->data.init.fw_release) + 1];
 
                        cfg->data_length =
                                cpu_to_le32(sizeof(struct atto_vda_cfg_init));
@@ -309,11 +310,13 @@ static void esas2r_complete_vda_ioctl(struct esas2r_adapter *a,
                                le32_to_cpu(rsp->vda_version);
                        cfg->data.init.fw_build = rsp->fw_build;
 
-                       sprintf((char *)&cfg->data.init.fw_release,
-                               "%1d.%02d",
+                       snprintf(buf, sizeof(buf), "%1d.%02d",
                                (int)LOBYTE(le16_to_cpu(rsp->fw_release)),
                                (int)HIBYTE(le16_to_cpu(rsp->fw_release)));
 
+                       memcpy(&cfg->data.init.fw_release, buf,
+                              sizeof(cfg->data.init.fw_release));
+
                        if (LOWORD(LOBYTE(cfg->data.init.fw_build)) == 'A')
                                cfg->data.init.fw_version =
                                        cfg->data.init.fw_build;
index c18c68150e9f17c8965b80159ecb2c2ddf1b0060..e4dd3d7cd236520a35487e5acabb77559ec78f30 100644 (file)
@@ -43,6 +43,8 @@
 #define DFX                     DRV_NAME "%d: "
 
 #define DESC_CLEAN_LOW_WATERMARK 8
+#define FNIC_UCSM_DFLT_THROTTLE_CNT_BLD        16 /* UCSM default throttle count */
+#define FNIC_MIN_IO_REQ                        256 /* Min IO throttle count */
 #define FNIC_MAX_IO_REQ                2048 /* scsi_cmnd tag map entries */
 #define        FNIC_IO_LOCKS           64 /* IO locks: power of 2 */
 #define FNIC_DFLT_QUEUE_DEPTH  32
@@ -154,6 +156,9 @@ do {                                                                \
        FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING,                    \
                         shost_printk(kern_level, host, fmt, ##args);)
 
+#define FNIC_MAIN_NOTE(kern_level, host, fmt, args...)          \
+       shost_printk(kern_level, host, fmt, ##args)
+
 extern const char *fnic_state_str[];
 
 enum fnic_intx_intr_index {
@@ -215,10 +220,12 @@ struct fnic {
 
        struct vnic_stats *stats;
        unsigned long stats_time;       /* time of stats update */
+       unsigned long stats_reset_time; /* time of stats reset */
        struct vnic_nic_cfg *nic_cfg;
        char name[IFNAMSIZ];
        struct timer_list notify_timer; /* used for MSI interrupts */
 
+       unsigned int fnic_max_tag_id;
        unsigned int err_intr_offset;
        unsigned int link_intr_offset;
 
@@ -359,4 +366,5 @@ fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags)
        return ((fnic->state_flags & st_flags) == st_flags);
 }
 void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long);
+void fnic_dump_fchost_stats(struct Scsi_Host *, struct fc_host_statistics *);
 #endif /* _FNIC_H_ */
index 42e15ee6e1bb73fceac4bd8aaf8ded5ad06ecf1e..bbf81ea3a25273a2e9cfacab90e28723d4471d8e 100644 (file)
@@ -74,6 +74,10 @@ module_param(fnic_trace_max_pages, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(fnic_trace_max_pages, "Total allocated memory pages "
                                        "for fnic trace buffer");
 
+static unsigned int fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH;
+module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN");
+
 static struct libfc_function_template fnic_transport_template = {
        .frame_send = fnic_send,
        .lport_set_port_id = fnic_set_port_id,
@@ -91,7 +95,7 @@ static int fnic_slave_alloc(struct scsi_device *sdev)
        if (!rport || fc_remote_port_chkready(rport))
                return -ENXIO;
 
-       scsi_activate_tcq(sdev, FNIC_DFLT_QUEUE_DEPTH);
+       scsi_activate_tcq(sdev, fnic_max_qdepth);
        return 0;
 }
 
@@ -126,6 +130,7 @@ fnic_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout)
 static void fnic_get_host_speed(struct Scsi_Host *shost);
 static struct scsi_transport_template *fnic_fc_transport;
 static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *);
+static void fnic_reset_host_stats(struct Scsi_Host *);
 
 static struct fc_function_template fnic_fc_functions = {
 
@@ -153,6 +158,7 @@ static struct fc_function_template fnic_fc_functions = {
        .set_rport_dev_loss_tmo = fnic_set_rport_dev_loss_tmo,
        .issue_fc_host_lip = fnic_reset,
        .get_fc_host_stats = fnic_get_stats,
+       .reset_fc_host_stats = fnic_reset_host_stats,
        .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv),
        .terminate_rport_io = fnic_terminate_rport_io,
        .bsg_request = fc_lport_bsg_request,
@@ -206,13 +212,116 @@ static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host)
        stats->error_frames = vs->tx.tx_errors + vs->rx.rx_errors;
        stats->dumped_frames = vs->tx.tx_drops + vs->rx.rx_drop;
        stats->invalid_crc_count = vs->rx.rx_crc_errors;
-       stats->seconds_since_last_reset = (jiffies - lp->boot_time) / HZ;
+       stats->seconds_since_last_reset =
+                       (jiffies - fnic->stats_reset_time) / HZ;
        stats->fcp_input_megabytes = div_u64(fnic->fcp_input_bytes, 1000000);
        stats->fcp_output_megabytes = div_u64(fnic->fcp_output_bytes, 1000000);
 
        return stats;
 }
 
+/*
+ * fnic_dump_fchost_stats
+ * note : dumps fc_statistics into system logs
+ */
+void fnic_dump_fchost_stats(struct Scsi_Host *host,
+                               struct fc_host_statistics *stats)
+{
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: seconds since last reset = %llu\n",
+                       stats->seconds_since_last_reset);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: tx frames                = %llu\n",
+                       stats->tx_frames);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: tx words         = %llu\n",
+                       stats->tx_words);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: rx frames                = %llu\n",
+                       stats->rx_frames);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: rx words         = %llu\n",
+                       stats->rx_words);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: lip count                = %llu\n",
+                       stats->lip_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: nos count                = %llu\n",
+                       stats->nos_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: error frames             = %llu\n",
+                       stats->error_frames);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: dumped frames    = %llu\n",
+                       stats->dumped_frames);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: link failure count       = %llu\n",
+                       stats->link_failure_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: loss of sync count       = %llu\n",
+                       stats->loss_of_sync_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: loss of signal count     = %llu\n",
+                       stats->loss_of_signal_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: prim seq protocol err count = %llu\n",
+                       stats->prim_seq_protocol_err_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: invalid tx word count= %llu\n",
+                       stats->invalid_tx_word_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: invalid crc count        = %llu\n",
+                       stats->invalid_crc_count);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: fcp input requests       = %llu\n",
+                       stats->fcp_input_requests);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: fcp output requests      = %llu\n",
+                       stats->fcp_output_requests);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: fcp control requests     = %llu\n",
+                       stats->fcp_control_requests);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: fcp input megabytes      = %llu\n",
+                       stats->fcp_input_megabytes);
+       FNIC_MAIN_NOTE(KERN_NOTICE, host,
+                       "fnic: fcp output megabytes     = %llu\n",
+                       stats->fcp_output_megabytes);
+       return;
+}
+
+/*
+ * fnic_reset_host_stats : clears host stats
+ * note : called when reset_statistics set under sysfs dir
+ */
+static void fnic_reset_host_stats(struct Scsi_Host *host)
+{
+       int ret;
+       struct fc_lport *lp = shost_priv(host);
+       struct fnic *fnic = lport_priv(lp);
+       struct fc_host_statistics *stats;
+       unsigned long flags;
+
+       /* dump current stats, before clearing them */
+       stats = fnic_get_stats(host);
+       fnic_dump_fchost_stats(host, stats);
+
+       spin_lock_irqsave(&fnic->fnic_lock, flags);
+       ret = vnic_dev_stats_clear(fnic->vdev);
+       spin_unlock_irqrestore(&fnic->fnic_lock, flags);
+
+       if (ret) {
+               FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host,
+                               "fnic: Reset vnic stats failed"
+                               " 0x%x", ret);
+               return;
+       }
+       fnic->stats_reset_time = jiffies;
+       memset(stats, 0, sizeof(*stats));
+
+       return;
+}
+
 void fnic_log_q_error(struct fnic *fnic)
 {
        unsigned int i;
@@ -447,13 +556,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        host->transportt = fnic_fc_transport;
 
-       err = scsi_init_shared_tag_map(host, FNIC_MAX_IO_REQ);
-       if (err) {
-               shost_printk(KERN_ERR, fnic->lport->host,
-                            "Unable to alloc shared tag map\n");
-               goto err_out_free_hba;
-       }
-
        /* Setup PCI resources */
        pci_set_drvdata(pdev, fnic);
 
@@ -476,10 +578,10 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_set_master(pdev);
 
        /* Query PCI controller on system for DMA addressing
-        * limitation for the device.  Try 40-bit first, and
+        * limitation for the device.  Try 64-bit first, and
         * fail to 32-bit.
         */
-       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
+       err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
        if (err) {
                err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (err) {
@@ -496,10 +598,10 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        goto err_out_release_regions;
                }
        } else {
-               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40));
+               err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
                if (err) {
                        shost_printk(KERN_ERR, fnic->lport->host,
-                                    "Unable to obtain 40-bit DMA "
+                                    "Unable to obtain 64-bit DMA "
                                     "for consistent allocations, aborting.\n");
                        goto err_out_release_regions;
                }
@@ -566,6 +668,22 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                             "aborting.\n");
                goto err_out_dev_close;
        }
+
+       /* Configure Maximum Outstanding IO reqs*/
+       if (fnic->config.io_throttle_count != FNIC_UCSM_DFLT_THROTTLE_CNT_BLD) {
+               host->can_queue = min_t(u32, FNIC_MAX_IO_REQ,
+                                       max_t(u32, FNIC_MIN_IO_REQ,
+                                       fnic->config.io_throttle_count));
+       }
+       fnic->fnic_max_tag_id = host->can_queue;
+
+       err = scsi_init_shared_tag_map(host, fnic->fnic_max_tag_id);
+       if (err) {
+               shost_printk(KERN_ERR, fnic->lport->host,
+                         "Unable to alloc shared tag map\n");
+               goto err_out_dev_close;
+       }
+
        host->max_lun = fnic->config.luns_per_tgt;
        host->max_id = FNIC_MAX_FCP_TARGET;
        host->max_cmd_len = FCOE_MAX_CMD_LEN;
@@ -719,6 +837,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
 
        fc_lport_init_stats(lp);
+       fnic->stats_reset_time = jiffies;
 
        fc_lport_config(lp);
 
index a97e6e584f8cfed52b9ef8dd8dd65b006b605558..d014aae19134624824190305040df9ee37fcbf1d 100644 (file)
@@ -111,6 +111,12 @@ static inline spinlock_t *fnic_io_lock_hash(struct fnic *fnic,
        return &fnic->io_req_lock[hash];
 }
 
+static inline spinlock_t *fnic_io_lock_tag(struct fnic *fnic,
+                                           int tag)
+{
+       return &fnic->io_req_lock[tag & (FNIC_IO_LOCKS - 1)];
+}
+
 /*
  * Unmap the data buffer and sense buffer for an io_req,
  * also unmap and free the device-private scatter/gather list.
@@ -730,7 +736,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic,
        fcpio_tag_id_dec(&tag, &id);
        icmnd_cmpl = &desc->u.icmnd_cmpl;
 
-       if (id >= FNIC_MAX_IO_REQ) {
+       if (id >= fnic->fnic_max_tag_id) {
                shost_printk(KERN_ERR, fnic->lport->host,
                        "Tag out of range tag %x hdr status = %s\n",
                             id, fnic_fcpio_status_to_str(hdr_status));
@@ -818,38 +824,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic,
                if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER)
                        xfer_len -= icmnd_cmpl->residual;
 
-               /*
-                * If queue_full, then try to reduce queue depth for all
-                * LUNS on the target. Todo: this should be accompanied
-                * by a periodic queue_depth rampup based on successful
-                * IO completion.
-                */
-               if (icmnd_cmpl->scsi_status == QUEUE_FULL) {
-                       struct scsi_device *t_sdev;
-                       int qd = 0;
-
-                       shost_for_each_device(t_sdev, sc->device->host) {
-                               if (t_sdev->id != sc->device->id)
-                                       continue;
-
-                               if (t_sdev->queue_depth > 1) {
-                                       qd = scsi_track_queue_full
-                                               (t_sdev,
-                                                t_sdev->queue_depth - 1);
-                                       if (qd == -1)
-                                               qd = t_sdev->host->cmd_per_lun;
-                                       shost_printk(KERN_INFO,
-                                                    fnic->lport->host,
-                                                    "scsi[%d:%d:%d:%d"
-                                                    "] queue full detected,"
-                                                    "new depth = %d\n",
-                                                    t_sdev->host->host_no,
-                                                    t_sdev->channel,
-                                                    t_sdev->id, t_sdev->lun,
-                                                    t_sdev->queue_depth);
-                               }
-                       }
-               }
                break;
 
        case FCPIO_TIMEOUT:          /* request was timed out */
@@ -939,7 +913,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
        fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag);
        fcpio_tag_id_dec(&tag, &id);
 
-       if ((id & FNIC_TAG_MASK) >= FNIC_MAX_IO_REQ) {
+       if ((id & FNIC_TAG_MASK) >= fnic->fnic_max_tag_id) {
                shost_printk(KERN_ERR, fnic->lport->host,
                "Tag out of range tag %x hdr status = %s\n",
                id, fnic_fcpio_status_to_str(hdr_status));
@@ -988,9 +962,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic,
                        spin_unlock_irqrestore(io_lock, flags);
                        return;
                }
-               CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE;
                CMD_ABTS_STATUS(sc) = hdr_status;
-
                CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_DONE;
                FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
                              "abts cmpl recd. id %d status %s\n",
@@ -1148,23 +1120,25 @@ int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do)
 
 static void fnic_cleanup_io(struct fnic *fnic, int exclude_id)
 {
-       unsigned int i;
+       int i;
        struct fnic_io_req *io_req;
        unsigned long flags = 0;
        struct scsi_cmnd *sc;
        spinlock_t *io_lock;
        unsigned long start_time = 0;
 
-       for (i = 0; i < FNIC_MAX_IO_REQ; i++) {
+       for (i = 0; i < fnic->fnic_max_tag_id; i++) {
                if (i == exclude_id)
                        continue;
 
+               io_lock = fnic_io_lock_tag(fnic, i);
+               spin_lock_irqsave(io_lock, flags);
                sc = scsi_host_find_tag(fnic->lport->host, i);
-               if (!sc)
+               if (!sc) {
+                       spin_unlock_irqrestore(io_lock, flags);
                        continue;
+               }
 
-               io_lock = fnic_io_lock_hash(fnic, sc);
-               spin_lock_irqsave(io_lock, flags);
                io_req = (struct fnic_io_req *)CMD_SP(sc);
                if ((CMD_FLAGS(sc) & FNIC_DEVICE_RESET) &&
                        !(CMD_FLAGS(sc) & FNIC_DEV_RST_DONE)) {
@@ -1236,7 +1210,7 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq,
        fcpio_tag_id_dec(&desc->hdr.tag, &id);
        id &= FNIC_TAG_MASK;
 
-       if (id >= FNIC_MAX_IO_REQ)
+       if (id >= fnic->fnic_max_tag_id)
                return;
 
        sc = scsi_host_find_tag(fnic->lport->host, id);
@@ -1340,14 +1314,15 @@ static void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id)
        if (fnic->in_remove)
                return;
 
-       for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) {
+       for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) {
                abt_tag = tag;
+               io_lock = fnic_io_lock_tag(fnic, tag);
+               spin_lock_irqsave(io_lock, flags);
                sc = scsi_host_find_tag(fnic->lport->host, tag);
-               if (!sc)
+               if (!sc) {
+                       spin_unlock_irqrestore(io_lock, flags);
                        continue;
-
-               io_lock = fnic_io_lock_hash(fnic, sc);
-               spin_lock_irqsave(io_lock, flags);
+               }
 
                io_req = (struct fnic_io_req *)CMD_SP(sc);
 
@@ -1441,12 +1416,29 @@ void fnic_terminate_rport_io(struct fc_rport *rport)
        unsigned long flags;
        struct scsi_cmnd *sc;
        struct scsi_lun fc_lun;
-       struct fc_rport_libfc_priv *rdata = rport->dd_data;
-       struct fc_lport *lport = rdata->local_port;
-       struct fnic *fnic = lport_priv(lport);
+       struct fc_rport_libfc_priv *rdata;
+       struct fc_lport *lport;
+       struct fnic *fnic;
        struct fc_rport *cmd_rport;
        enum fnic_ioreq_state old_ioreq_state;
 
+       if (!rport) {
+               printk(KERN_ERR "fnic_terminate_rport_io: rport is NULL\n");
+               return;
+       }
+       rdata = rport->dd_data;
+
+       if (!rdata) {
+               printk(KERN_ERR "fnic_terminate_rport_io: rdata is NULL\n");
+               return;
+       }
+       lport = rdata->local_port;
+
+       if (!lport) {
+               printk(KERN_ERR "fnic_terminate_rport_io: lport is NULL\n");
+               return;
+       }
+       fnic = lport_priv(lport);
        FNIC_SCSI_DBG(KERN_DEBUG,
                      fnic->lport->host, "fnic_terminate_rport_io called"
                      " wwpn 0x%llx, wwnn0x%llx, rport 0x%p, portid 0x%06x\n",
@@ -1456,18 +1448,21 @@ void fnic_terminate_rport_io(struct fc_rport *rport)
        if (fnic->in_remove)
                return;
 
-       for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) {
+       for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) {
                abt_tag = tag;
+               io_lock = fnic_io_lock_tag(fnic, tag);
+               spin_lock_irqsave(io_lock, flags);
                sc = scsi_host_find_tag(fnic->lport->host, tag);
-               if (!sc)
+               if (!sc) {
+                       spin_unlock_irqrestore(io_lock, flags);
                        continue;
+               }
 
                cmd_rport = starget_to_rport(scsi_target(sc->device));
-               if (rport != cmd_rport)
+               if (rport != cmd_rport) {
+                       spin_unlock_irqrestore(io_lock, flags);
                        continue;
-
-               io_lock = fnic_io_lock_hash(fnic, sc);
-               spin_lock_irqsave(io_lock, flags);
+               }
 
                io_req = (struct fnic_io_req *)CMD_SP(sc);
 
@@ -1680,13 +1675,15 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
        io_req->abts_done = NULL;
 
        /* fw did not complete abort, timed out */
-       if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) {
+       if (CMD_ABTS_STATUS(sc) == FCPIO_INVALID_CODE) {
                spin_unlock_irqrestore(io_lock, flags);
                CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_TIMED_OUT;
                ret = FAILED;
                goto fnic_abort_cmd_end;
        }
 
+       CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE;
+
        /*
         * firmware completed the abort, check the status,
         * free the io_req irrespective of failure or success
@@ -1784,17 +1781,18 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
        DECLARE_COMPLETION_ONSTACK(tm_done);
        enum fnic_ioreq_state old_ioreq_state;
 
-       for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) {
+       for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) {
+               io_lock = fnic_io_lock_tag(fnic, tag);
+               spin_lock_irqsave(io_lock, flags);
                sc = scsi_host_find_tag(fnic->lport->host, tag);
                /*
                 * ignore this lun reset cmd or cmds that do not belong to
                 * this lun
                 */
-               if (!sc || sc == lr_sc || sc->device != lun_dev)
+               if (!sc || sc == lr_sc || sc->device != lun_dev) {
+                       spin_unlock_irqrestore(io_lock, flags);
                        continue;
-
-               io_lock = fnic_io_lock_hash(fnic, sc);
-               spin_lock_irqsave(io_lock, flags);
+               }
 
                io_req = (struct fnic_io_req *)CMD_SP(sc);
 
@@ -1823,6 +1821,11 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                        spin_unlock_irqrestore(io_lock, flags);
                        continue;
                }
+
+               if (io_req->abts_done)
+                       shost_printk(KERN_ERR, fnic->lport->host,
+                         "%s: io_req->abts_done is set state is %s\n",
+                         __func__, fnic_ioreq_state_to_str(CMD_STATE(sc)));
                old_ioreq_state = CMD_STATE(sc);
                /*
                 * Any pending IO issued prior to reset is expected to be
@@ -1833,11 +1836,6 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                 */
                CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING;
 
-               if (io_req->abts_done)
-                       shost_printk(KERN_ERR, fnic->lport->host,
-                         "%s: io_req->abts_done is set state is %s\n",
-                         __func__, fnic_ioreq_state_to_str(CMD_STATE(sc)));
-
                BUG_ON(io_req->abts_done);
 
                abt_tag = tag;
@@ -1890,12 +1888,13 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
                io_req->abts_done = NULL;
 
                /* if abort is still pending with fw, fail */
-               if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) {
+               if (CMD_ABTS_STATUS(sc) == FCPIO_INVALID_CODE) {
                        spin_unlock_irqrestore(io_lock, flags);
                        CMD_FLAGS(sc) |= FNIC_IO_ABT_TERM_DONE;
                        ret = 1;
                        goto clean_pending_aborts_end;
                }
+               CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE;
                CMD_SP(sc) = NULL;
                spin_unlock_irqrestore(io_lock, flags);
 
@@ -2093,8 +2092,8 @@ int fnic_device_reset(struct scsi_cmnd *sc)
                spin_unlock_irqrestore(io_lock, flags);
                int_to_scsilun(sc->device->lun, &fc_lun);
                /*
-                * Issue abort and terminate on the device reset request.
-                * If q'ing of the abort fails, retry issue it after a delay.
+                * Issue abort and terminate on device reset request.
+                * If q'ing of terminate fails, retry it after a delay.
                 */
                while (1) {
                        spin_lock_irqsave(io_lock, flags);
@@ -2405,7 +2404,7 @@ int fnic_is_abts_pending(struct fnic *fnic, struct scsi_cmnd *lr_sc)
                lun_dev = lr_sc->device;
 
        /* walk again to check, if IOs are still pending in fw */
-       for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) {
+       for (tag = 0; tag < fnic->fnic_max_tag_id; tag++) {
                sc = scsi_host_find_tag(fnic->lport->host, tag);
                /*
                 * ignore this lun reset cmd or cmds that do not belong to
index fbb55364e2723db9d57dd9418ff3a37108d1a32f..e343e1d0f801315398c0b4cdb5cb60e773ba40fa 100644 (file)
@@ -54,8 +54,8 @@
 #define VNIC_FNIC_PLOGI_TIMEOUT_MIN         1000
 #define VNIC_FNIC_PLOGI_TIMEOUT_MAX         255000
 
-#define VNIC_FNIC_IO_THROTTLE_COUNT_MIN     256
-#define VNIC_FNIC_IO_THROTTLE_COUNT_MAX     4096
+#define VNIC_FNIC_IO_THROTTLE_COUNT_MIN     1
+#define VNIC_FNIC_IO_THROTTLE_COUNT_MAX     2048
 
 #define VNIC_FNIC_LINK_DOWN_TIMEOUT_MIN     0
 #define VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX     240000
index fac8cf5832ddce5bf0fe182570f17e8dbdb6899b..891c86b66253b3272dbce9e816cb8bbe72bafab5 100644 (file)
@@ -54,7 +54,7 @@
 #include "hpsa.h"
 
 /* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "2.0.2-1"
+#define HPSA_DRIVER_VERSION "3.4.0-1"
 #define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
 #define HPSA "hpsa"
 
@@ -89,13 +89,14 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3245},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3247},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3249},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324a},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324b},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324A},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x324B},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSE,     0x103C, 0x3233},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3350},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3351},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3352},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3353},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x334D},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3354},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3355},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x3356},
@@ -107,7 +108,19 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1925},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1926},
        {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1928},
-       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSF,     0x103C, 0x334d},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSH,     0x103C, 0x1929},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21BD},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21BE},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21BF},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C0},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C1},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C2},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C3},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C4},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C5},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C7},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C8},
+       {PCI_VENDOR_ID_HP,     PCI_DEVICE_ID_HP_CISSI,     0x103C, 0x21C9},
        {PCI_VENDOR_ID_HP,     PCI_ANY_ID,      PCI_ANY_ID, PCI_ANY_ID,
                PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
        {0,}
@@ -125,24 +138,35 @@ static struct board_type products[] = {
        {0x3245103C, "Smart Array P410i", &SA5_access},
        {0x3247103C, "Smart Array P411", &SA5_access},
        {0x3249103C, "Smart Array P812", &SA5_access},
-       {0x324a103C, "Smart Array P712m", &SA5_access},
-       {0x324b103C, "Smart Array P711m", &SA5_access},
+       {0x324A103C, "Smart Array P712m", &SA5_access},
+       {0x324B103C, "Smart Array P711m", &SA5_access},
        {0x3350103C, "Smart Array P222", &SA5_access},
        {0x3351103C, "Smart Array P420", &SA5_access},
        {0x3352103C, "Smart Array P421", &SA5_access},
        {0x3353103C, "Smart Array P822", &SA5_access},
+       {0x334D103C, "Smart Array P822se", &SA5_access},
        {0x3354103C, "Smart Array P420i", &SA5_access},
        {0x3355103C, "Smart Array P220i", &SA5_access},
        {0x3356103C, "Smart Array P721m", &SA5_access},
-       {0x1920103C, "Smart Array", &SA5_access},
-       {0x1921103C, "Smart Array", &SA5_access},
-       {0x1922103C, "Smart Array", &SA5_access},
-       {0x1923103C, "Smart Array", &SA5_access},
-       {0x1924103C, "Smart Array", &SA5_access},
-       {0x1925103C, "Smart Array", &SA5_access},
-       {0x1926103C, "Smart Array", &SA5_access},
-       {0x1928103C, "Smart Array", &SA5_access},
-       {0x334d103C, "Smart Array P822se", &SA5_access},
+       {0x1921103C, "Smart Array P830i", &SA5_access},
+       {0x1922103C, "Smart Array P430", &SA5_access},
+       {0x1923103C, "Smart Array P431", &SA5_access},
+       {0x1924103C, "Smart Array P830", &SA5_access},
+       {0x1926103C, "Smart Array P731m", &SA5_access},
+       {0x1928103C, "Smart Array P230i", &SA5_access},
+       {0x1929103C, "Smart Array P530", &SA5_access},
+       {0x21BD103C, "Smart Array", &SA5_access},
+       {0x21BE103C, "Smart Array", &SA5_access},
+       {0x21BF103C, "Smart Array", &SA5_access},
+       {0x21C0103C, "Smart Array", &SA5_access},
+       {0x21C1103C, "Smart Array", &SA5_access},
+       {0x21C2103C, "Smart Array", &SA5_access},
+       {0x21C3103C, "Smart Array", &SA5_access},
+       {0x21C4103C, "Smart Array", &SA5_access},
+       {0x21C5103C, "Smart Array", &SA5_access},
+       {0x21C7103C, "Smart Array", &SA5_access},
+       {0x21C8103C, "Smart Array", &SA5_access},
+       {0x21C9103C, "Smart Array", &SA5_access},
        {0xFFFF103C, "Unknown Smart Array", &SA5_access},
 };
 
index 4e31caa21ddfba379036b6a7b4c085a5f916549f..23f5ba5e6472581d4aa69bef39d1ca25992502d4 100644 (file)
@@ -2208,7 +2208,10 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
 
        if (rsp_rc != 0) {
                sdev_printk(KERN_ERR, sdev, "Failed to send cancel event. rc=%d\n", rsp_rc);
-               return -EIO;
+               /* If failure is received, the host adapter is most likely going
+                through reset, return success so the caller will wait for the command
+                being cancelled to get returned */
+               return 0;
        }
 
        sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n");
@@ -2221,7 +2224,15 @@ static int ibmvfc_cancel_all(struct scsi_device *sdev, int type)
 
        if (status != IBMVFC_MAD_SUCCESS) {
                sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status);
-               return -EIO;
+               switch (status) {
+               case IBMVFC_MAD_DRIVER_FAILED:
+               case IBMVFC_MAD_CRQ_ERROR:
+                       /* Host adapter most likely going through reset, return success to
+                        the caller will wait for the command being cancelled to get returned */
+                       return 0;
+               default:
+                       return -EIO;
+               };
        }
 
        sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n");
index d0fa4b6c551fd677bfa14252525717cf4f32469d..fa764406df6872c2daa9fa3d2e75a9e5f2164c8b 100644 (file)
@@ -241,7 +241,7 @@ static void gather_partition_info(void)
        struct device_node *rootdn;
 
        const char *ppartition_name;
-       const unsigned int *p_number_ptr;
+       const __be32 *p_number_ptr;
 
        /* Retrieve information about this partition */
        rootdn = of_find_node_by_path("/");
@@ -255,7 +255,7 @@ static void gather_partition_info(void)
                                sizeof(partition_name));
        p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL);
        if (p_number_ptr)
-               partition_number = *p_number_ptr;
+               partition_number = of_read_number(p_number_ptr, 1);
        of_node_put(rootdn);
 }
 
@@ -270,10 +270,11 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata)
        strncpy(hostdata->madapter_info.partition_name, partition_name,
                        sizeof(hostdata->madapter_info.partition_name));
 
-       hostdata->madapter_info.partition_number = partition_number;
+       hostdata->madapter_info.partition_number =
+                                       cpu_to_be32(partition_number);
 
-       hostdata->madapter_info.mad_version = 1;
-       hostdata->madapter_info.os_type = 2;
+       hostdata->madapter_info.mad_version = cpu_to_be32(1);
+       hostdata->madapter_info.os_type = cpu_to_be32(2);
 }
 
 /**
@@ -464,9 +465,9 @@ static int initialize_event_pool(struct event_pool *pool,
                memset(&evt->crq, 0x00, sizeof(evt->crq));
                atomic_set(&evt->free, 1);
                evt->crq.valid = 0x80;
-               evt->crq.IU_length = sizeof(*evt->xfer_iu);
-               evt->crq.IU_data_ptr = pool->iu_token + 
-                       sizeof(*evt->xfer_iu) * i;
+               evt->crq.IU_length = cpu_to_be16(sizeof(*evt->xfer_iu));
+               evt->crq.IU_data_ptr = cpu_to_be64(pool->iu_token +
+                       sizeof(*evt->xfer_iu) * i);
                evt->xfer_iu = pool->iu_storage + i;
                evt->hostdata = hostdata;
                evt->ext_list = NULL;
@@ -588,7 +589,7 @@ static void init_event_struct(struct srp_event_struct *evt_struct,
        evt_struct->cmnd_done = NULL;
        evt_struct->sync_srp = NULL;
        evt_struct->crq.format = format;
-       evt_struct->crq.timeout = timeout;
+       evt_struct->crq.timeout = cpu_to_be16(timeout);
        evt_struct->done = done;
 }
 
@@ -659,8 +660,8 @@ static int map_sg_list(struct scsi_cmnd *cmd, int nseg,
 
        scsi_for_each_sg(cmd, sg, nseg, i) {
                struct srp_direct_buf *descr = md + i;
-               descr->va = sg_dma_address(sg);
-               descr->len = sg_dma_len(sg);
+               descr->va = cpu_to_be64(sg_dma_address(sg));
+               descr->len = cpu_to_be32(sg_dma_len(sg));
                descr->key = 0;
                total_length += sg_dma_len(sg);
        }
@@ -703,13 +704,14 @@ static int map_sg_data(struct scsi_cmnd *cmd,
        }
 
        indirect->table_desc.va = 0;
-       indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf);
+       indirect->table_desc.len = cpu_to_be32(sg_mapped *
+                                              sizeof(struct srp_direct_buf));
        indirect->table_desc.key = 0;
 
        if (sg_mapped <= MAX_INDIRECT_BUFS) {
                total_length = map_sg_list(cmd, sg_mapped,
                                           &indirect->desc_list[0]);
-               indirect->len = total_length;
+               indirect->len = cpu_to_be32(total_length);
                return 1;
        }
 
@@ -731,9 +733,10 @@ static int map_sg_data(struct scsi_cmnd *cmd,
 
        total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list);
 
-       indirect->len = total_length;
-       indirect->table_desc.va = evt_struct->ext_list_token;
-       indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]);
+       indirect->len = cpu_to_be32(total_length);
+       indirect->table_desc.va = cpu_to_be64(evt_struct->ext_list_token);
+       indirect->table_desc.len = cpu_to_be32(sg_mapped *
+                                              sizeof(indirect->desc_list[0]));
        memcpy(indirect->desc_list, evt_struct->ext_list,
               MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf));
        return 1;
@@ -849,7 +852,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
                                   struct ibmvscsi_host_data *hostdata,
                                   unsigned long timeout)
 {
-       u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
+       __be64 *crq_as_u64 = (__be64 *)&evt_struct->crq;
        int request_status = 0;
        int rc;
        int srp_req = 0;
@@ -920,8 +923,9 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
                add_timer(&evt_struct->timer);
        }
 
-       if ((rc =
-            ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+       rc = ibmvscsi_send_crq(hostdata, be64_to_cpu(crq_as_u64[0]),
+                              be64_to_cpu(crq_as_u64[1]));
+       if (rc != 0) {
                list_del(&evt_struct->list);
                del_timer(&evt_struct->timer);
 
@@ -987,15 +991,16 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
                if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
                        memcpy(cmnd->sense_buffer,
                               rsp->data,
-                              rsp->sense_data_len);
+                              be32_to_cpu(rsp->sense_data_len));
                unmap_cmd_data(&evt_struct->iu.srp.cmd, 
                               evt_struct, 
                               evt_struct->hostdata->dev);
 
                if (rsp->flags & SRP_RSP_FLAG_DOOVER)
-                       scsi_set_resid(cmnd, rsp->data_out_res_cnt);
+                       scsi_set_resid(cmnd,
+                                      be32_to_cpu(rsp->data_out_res_cnt));
                else if (rsp->flags & SRP_RSP_FLAG_DIOVER)
-                       scsi_set_resid(cmnd, rsp->data_in_res_cnt);
+                       scsi_set_resid(cmnd, be32_to_cpu(rsp->data_in_res_cnt));
        }
 
        if (evt_struct->cmnd_done)
@@ -1037,7 +1042,7 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
        memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
        srp_cmd->opcode = SRP_CMD;
        memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
-       srp_cmd->lun = ((u64) lun) << 48;
+       srp_cmd->lun = cpu_to_be64(((u64)lun) << 48);
 
        if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
                if (!firmware_has_feature(FW_FEATURE_CMO))
@@ -1062,9 +1067,10 @@ static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd,
        if ((in_fmt == SRP_DATA_DESC_INDIRECT ||
             out_fmt == SRP_DATA_DESC_INDIRECT) &&
            indirect->table_desc.va == 0) {
-               indirect->table_desc.va = evt_struct->crq.IU_data_ptr +
+               indirect->table_desc.va =
+                       cpu_to_be64(be64_to_cpu(evt_struct->crq.IU_data_ptr) +
                        offsetof(struct srp_cmd, add_data) +
-                       offsetof(struct srp_indirect_buf, desc_list);
+                       offsetof(struct srp_indirect_buf, desc_list));
        }
 
        return ibmvscsi_send_srp_event(evt_struct, hostdata, 0);
@@ -1158,7 +1164,7 @@ static void login_rsp(struct srp_event_struct *evt_struct)
         * request_limit could have been set to -1 by this client.
         */
        atomic_set(&hostdata->request_limit,
-                  evt_struct->xfer_iu->srp.login_rsp.req_lim_delta);
+                  be32_to_cpu(evt_struct->xfer_iu->srp.login_rsp.req_lim_delta));
 
        /* If we had any pending I/Os, kick them */
        scsi_unblock_requests(hostdata->host);
@@ -1184,8 +1190,9 @@ static int send_srp_login(struct ibmvscsi_host_data *hostdata)
        login = &evt_struct->iu.srp.login_req;
        memset(login, 0, sizeof(*login));
        login->opcode = SRP_LOGIN_REQ;
-       login->req_it_iu_len = sizeof(union srp_iu);
-       login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT;
+       login->req_it_iu_len = cpu_to_be32(sizeof(union srp_iu));
+       login->req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
+                                        SRP_BUF_FORMAT_INDIRECT);
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
        /* Start out with a request limit of 0, since this is negotiated in
@@ -1214,12 +1221,13 @@ static void capabilities_rsp(struct srp_event_struct *evt_struct)
                dev_err(hostdata->dev, "error 0x%X getting capabilities info\n",
                        evt_struct->xfer_iu->mad.capabilities.common.status);
        } else {
-               if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP)
+               if (hostdata->caps.migration.common.server_support !=
+                   cpu_to_be16(SERVER_SUPPORTS_CAP))
                        dev_info(hostdata->dev, "Partition migration not supported\n");
 
                if (client_reserve) {
                        if (hostdata->caps.reserve.common.server_support ==
-                           SERVER_SUPPORTS_CAP)
+                           cpu_to_be16(SERVER_SUPPORTS_CAP))
                                dev_info(hostdata->dev, "Client reserve enabled\n");
                        else
                                dev_info(hostdata->dev, "Client reserve not supported\n");
@@ -1251,9 +1259,9 @@ static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
        req = &evt_struct->iu.mad.capabilities;
        memset(req, 0, sizeof(*req));
 
-       hostdata->caps.flags = CAP_LIST_SUPPORTED;
+       hostdata->caps.flags = cpu_to_be32(CAP_LIST_SUPPORTED);
        if (hostdata->client_migrated)
-               hostdata->caps.flags |= CLIENT_MIGRATED;
+               hostdata->caps.flags |= cpu_to_be32(CLIENT_MIGRATED);
 
        strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev),
                sizeof(hostdata->caps.name));
@@ -1264,22 +1272,31 @@ static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
        strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc));
        hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0';
 
-       req->common.type = VIOSRP_CAPABILITIES_TYPE;
-       req->buffer = hostdata->caps_addr;
+       req->common.type = cpu_to_be32(VIOSRP_CAPABILITIES_TYPE);
+       req->buffer = cpu_to_be64(hostdata->caps_addr);
 
-       hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES;
-       hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration);
-       hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP;
-       hostdata->caps.migration.ecl = 1;
+       hostdata->caps.migration.common.cap_type =
+                               cpu_to_be32(MIGRATION_CAPABILITIES);
+       hostdata->caps.migration.common.length =
+                               cpu_to_be16(sizeof(hostdata->caps.migration));
+       hostdata->caps.migration.common.server_support =
+                               cpu_to_be16(SERVER_SUPPORTS_CAP);
+       hostdata->caps.migration.ecl = cpu_to_be32(1);
 
        if (client_reserve) {
-               hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES;
-               hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve);
-               hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP;
-               hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2;
-               req->common.length = sizeof(hostdata->caps);
+               hostdata->caps.reserve.common.cap_type =
+                                       cpu_to_be32(RESERVATION_CAPABILITIES);
+               hostdata->caps.reserve.common.length =
+                               cpu_to_be16(sizeof(hostdata->caps.reserve));
+               hostdata->caps.reserve.common.server_support =
+                               cpu_to_be16(SERVER_SUPPORTS_CAP);
+               hostdata->caps.reserve.type =
+                               cpu_to_be32(CLIENT_RESERVE_SCSI_2);
+               req->common.length =
+                               cpu_to_be16(sizeof(hostdata->caps));
        } else
-               req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve);
+               req->common.length = cpu_to_be16(sizeof(hostdata->caps) -
+                                               sizeof(hostdata->caps.reserve));
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
        if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
@@ -1297,7 +1314,7 @@ static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata)
 static void fast_fail_rsp(struct srp_event_struct *evt_struct)
 {
        struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
-       u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status;
+       u16 status = be16_to_cpu(evt_struct->xfer_iu->mad.fast_fail.common.status);
 
        if (status == VIOSRP_MAD_NOT_SUPPORTED)
                dev_err(hostdata->dev, "fast_fail not supported in server\n");
@@ -1334,8 +1351,8 @@ static int enable_fast_fail(struct ibmvscsi_host_data *hostdata)
 
        fast_fail_mad = &evt_struct->iu.mad.fast_fail;
        memset(fast_fail_mad, 0, sizeof(*fast_fail_mad));
-       fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL;
-       fast_fail_mad->common.length = sizeof(*fast_fail_mad);
+       fast_fail_mad->common.type = cpu_to_be32(VIOSRP_ENABLE_FAST_FAIL);
+       fast_fail_mad->common.length = cpu_to_be16(sizeof(*fast_fail_mad));
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
        rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
@@ -1362,15 +1379,15 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                         "host partition %s (%d), OS %d, max io %u\n",
                         hostdata->madapter_info.srp_version,
                         hostdata->madapter_info.partition_name,
-                        hostdata->madapter_info.partition_number,
-                        hostdata->madapter_info.os_type,
-                        hostdata->madapter_info.port_max_txu[0]);
+                        be32_to_cpu(hostdata->madapter_info.partition_number),
+                        be32_to_cpu(hostdata->madapter_info.os_type),
+                        be32_to_cpu(hostdata->madapter_info.port_max_txu[0]));
                
                if (hostdata->madapter_info.port_max_txu[0]) 
                        hostdata->host->max_sectors = 
-                               hostdata->madapter_info.port_max_txu[0] >> 9;
+                               be32_to_cpu(hostdata->madapter_info.port_max_txu[0]) >> 9;
                
-               if (hostdata->madapter_info.os_type == 3 &&
+               if (be32_to_cpu(hostdata->madapter_info.os_type) == 3 &&
                    strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) {
                        dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n",
                                hostdata->madapter_info.srp_version);
@@ -1379,7 +1396,7 @@ static void adapter_info_rsp(struct srp_event_struct *evt_struct)
                        hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS;
                }
 
-               if (hostdata->madapter_info.os_type == 3) {
+               if (be32_to_cpu(hostdata->madapter_info.os_type) == 3) {
                        enable_fast_fail(hostdata);
                        return;
                }
@@ -1414,9 +1431,9 @@ static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
        req = &evt_struct->iu.mad.adapter_info;
        memset(req, 0x00, sizeof(*req));
        
-       req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
-       req->common.length = sizeof(hostdata->madapter_info);
-       req->buffer = hostdata->adapter_info_addr;
+       req->common.type = cpu_to_be32(VIOSRP_ADAPTER_INFO_TYPE);
+       req->common.length = cpu_to_be16(sizeof(hostdata->madapter_info));
+       req->buffer = cpu_to_be64(hostdata->adapter_info_addr);
 
        spin_lock_irqsave(hostdata->host->host_lock, flags);
        if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2))
@@ -1501,7 +1518,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
                /* Set up an abort SRP command */
                memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
                tsk_mgmt->opcode = SRP_TSK_MGMT;
-               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->lun = cpu_to_be64(((u64) lun) << 48);
                tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK;
                tsk_mgmt->task_tag = (u64) found_evt;
 
@@ -1624,7 +1641,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
                /* Set up a lun reset SRP command */
                memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
                tsk_mgmt->opcode = SRP_TSK_MGMT;
-               tsk_mgmt->lun = ((u64) lun) << 48;
+               tsk_mgmt->lun = cpu_to_be64(((u64) lun) << 48);
                tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET;
 
                evt->sync_srp = &srp_rsp;
@@ -1735,8 +1752,9 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
 {
        long rc;
        unsigned long flags;
+       /* The hypervisor copies our tag value here so no byteswapping */
        struct srp_event_struct *evt_struct =
-           (struct srp_event_struct *)crq->IU_data_ptr;
+                       (__force struct srp_event_struct *)crq->IU_data_ptr;
        switch (crq->valid) {
        case 0xC0:              /* initialization */
                switch (crq->format) {
@@ -1792,18 +1810,18 @@ static void ibmvscsi_handle_crq(struct viosrp_crq *crq,
         */
        if (!valid_event_struct(&hostdata->pool, evt_struct)) {
                dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n",
-                      (void *)crq->IU_data_ptr);
+                      evt_struct);
                return;
        }
 
        if (atomic_read(&evt_struct->free)) {
                dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n",
-                       (void *)crq->IU_data_ptr);
+                       evt_struct);
                return;
        }
 
        if (crq->format == VIOSRP_SRP_FORMAT)
-               atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta,
+               atomic_add(be32_to_cpu(evt_struct->xfer_iu->srp.rsp.req_lim_delta),
                           &hostdata->request_limit);
 
        del_timer(&evt_struct->timer);
@@ -1856,13 +1874,11 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
 
        /* Set up a lun reset SRP command */
        memset(host_config, 0x00, sizeof(*host_config));
-       host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
-       host_config->common.length = length;
-       host_config->buffer = addr = dma_map_single(hostdata->dev, buffer,
-                                                   length,
-                                                   DMA_BIDIRECTIONAL);
+       host_config->common.type = cpu_to_be32(VIOSRP_HOST_CONFIG_TYPE);
+       host_config->common.length = cpu_to_be16(length);
+       addr = dma_map_single(hostdata->dev, buffer, length, DMA_BIDIRECTIONAL);
 
-       if (dma_mapping_error(hostdata->dev, host_config->buffer)) {
+       if (dma_mapping_error(hostdata->dev, addr)) {
                if (!firmware_has_feature(FW_FEATURE_CMO))
                        dev_err(hostdata->dev,
                                "dma_mapping error getting host config\n");
@@ -1870,6 +1886,8 @@ static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
                return -1;
        }
 
+       host_config->buffer = cpu_to_be64(addr);
+
        init_completion(&evt_struct->comp);
        spin_lock_irqsave(hostdata->host->host_lock, flags);
        rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2);
index 2cd735d1d1962fe43eee7b65f85f1774bfd95fef..1162430876227e3ce3815d8d2b278f0ce4ca6de4 100644 (file)
@@ -75,9 +75,9 @@ struct viosrp_crq {
        u8 format;              /* SCSI vs out-of-band */
        u8 reserved;
        u8 status;              /* non-scsi failure? (e.g. DMA failure) */
-       u16 timeout;            /* in seconds */
-       u16 IU_length;          /* in bytes */
-       u64 IU_data_ptr;        /* the TCE for transferring data */
+       __be16 timeout;         /* in seconds */
+       __be16 IU_length;               /* in bytes */
+       __be64 IU_data_ptr;     /* the TCE for transferring data */
 };
 
 /* MADs are Management requests above and beyond the IUs defined in the SRP
@@ -124,10 +124,10 @@ enum viosrp_capability_flag {
  * Common MAD header
  */
 struct mad_common {
-       u32 type;
-       u16 status;
-       u16 length;
-       u64 tag;
+       __be32 type;
+       __be16 status;
+       __be16 length;
+       __be64 tag;
 };
 
 /*
@@ -139,23 +139,23 @@ struct mad_common {
  */
 struct viosrp_empty_iu {
        struct mad_common common;
-       u64 buffer;
-       u32 port;
+       __be64 buffer;
+       __be32 port;
 };
 
 struct viosrp_error_log {
        struct mad_common common;
-       u64 buffer;
+       __be64 buffer;
 };
 
 struct viosrp_adapter_info {
        struct mad_common common;
-       u64 buffer;
+       __be64 buffer;
 };
 
 struct viosrp_host_config {
        struct mad_common common;
-       u64 buffer;
+       __be64 buffer;
 };
 
 struct viosrp_fast_fail {
@@ -164,27 +164,27 @@ struct viosrp_fast_fail {
 
 struct viosrp_capabilities {
        struct mad_common common;
-       u64 buffer;
+       __be64 buffer;
 };
 
 struct mad_capability_common {
-       u32 cap_type;
-       u16 length;
-       u16 server_support;
+       __be32 cap_type;
+       __be16 length;
+       __be16 server_support;
 };
 
 struct mad_reserve_cap {
        struct mad_capability_common common;
-       u32 type;
+       __be32 type;
 };
 
 struct mad_migration_cap {
        struct mad_capability_common common;
-       u32 ecl;
+       __be32 ecl;
 };
 
 struct capabilities{
-       u32 flags;
+       __be32 flags;
        char name[SRP_MAX_LOC_LEN];
        char loc[SRP_MAX_LOC_LEN];
        struct mad_migration_cap migration;
@@ -208,10 +208,10 @@ union viosrp_iu {
 struct mad_adapter_info_data {
        char srp_version[8];
        char partition_name[96];
-       u32 partition_number;
-       u32 mad_version;
-       u32 os_type;
-       u32 port_max_txu[8];    /* per-port maximum transfer */
+       __be32 partition_number;
+       __be32 mad_version;
+       __be32 os_type;
+       __be32 port_max_txu[8]; /* per-port maximum transfer */
 };
 
 #endif
index df43bfe6d5731c960aeefce2a36bfe1ca7b79aa3..4e1b75ca74518dbb8843b9f4fc8c678fc1bce004 100644 (file)
@@ -708,6 +708,7 @@ struct lpfc_hba {
        uint32_t cfg_multi_ring_type;
        uint32_t cfg_poll;
        uint32_t cfg_poll_tmo;
+       uint32_t cfg_task_mgmt_tmo;
        uint32_t cfg_use_msi;
        uint32_t cfg_fcp_imax;
        uint32_t cfg_fcp_cpu_map;
index 16498e030c70392e2b5986f498d2c1b4ae4142e0..00656fc92b93a608611df0c8ee23ffc46a3d55ae 100644 (file)
@@ -1865,8 +1865,10 @@ lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \
 { \
        if (val >= minval && val <= maxval) {\
                lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \
-                       "3053 lpfc_" #attr " changed from %d to %d\n", \
-                       vport->cfg_##attr, val); \
+                       "3053 lpfc_" #attr \
+                       " changed from %d (x%x) to %d (x%x)\n", \
+                       vport->cfg_##attr, vport->cfg_##attr, \
+                       val, val); \
                vport->cfg_##attr = val;\
                return 0;\
        }\
@@ -4011,8 +4013,11 @@ LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support");
 # For [0], FCP commands are issued to Work Queues ina round robin fashion.
 # For [1], FCP commands are issued to a Work Queue associated with the
 #          current CPU.
+# It would be set to 1 by the driver if it's able to set up cpu affinity
+# for FCP I/Os through Work Queue associated with the current CPU. Otherwise,
+# roundrobin scheduling of FCP I/Os through WQs will be used.
 */
-LPFC_ATTR_RW(fcp_io_sched, 0, 0, 1, "Determine scheduling algrithmn for "
+LPFC_ATTR_RW(fcp_io_sched, 0, 0, 1, "Determine scheduling algorithm for "
                "issuing commands [0] - Round Robin, [1] - Current CPU");
 
 /*
@@ -4110,6 +4115,12 @@ LPFC_ATTR_RW(poll_tmo, 10, 1, 255,
             "Milliseconds driver will wait between polling FCP ring");
 
 /*
+# lpfc_task_mgmt_tmo: Maximum time to wait for task management commands
+# to complete in seconds. Value range is [5,180], default value is 60.
+*/
+LPFC_ATTR_RW(task_mgmt_tmo, 60, 5, 180,
+            "Maximum time to wait for task management commands to complete");
+/*
 # lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that
 #              support this feature
 #       0  = MSI disabled
@@ -4295,6 +4306,7 @@ struct device_attribute *lpfc_hba_attrs[] = {
        &dev_attr_issue_reset,
        &dev_attr_lpfc_poll,
        &dev_attr_lpfc_poll_tmo,
+       &dev_attr_lpfc_task_mgmt_tmo,
        &dev_attr_lpfc_use_msi,
        &dev_attr_lpfc_fcp_imax,
        &dev_attr_lpfc_fcp_cpu_map,
@@ -5274,6 +5286,7 @@ lpfc_get_cfgparam(struct lpfc_hba *phba)
        lpfc_topology_init(phba, lpfc_topology);
        lpfc_link_speed_init(phba, lpfc_link_speed);
        lpfc_poll_tmo_init(phba, lpfc_poll_tmo);
+       lpfc_task_mgmt_tmo_init(phba, lpfc_task_mgmt_tmo);
        lpfc_enable_npiv_init(phba, lpfc_enable_npiv);
        lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy);
        lpfc_enable_rrq_init(phba, lpfc_enable_rrq);
index 79c13c3263f15a7afbc3b11c0bb5aca4345a306b..b92aec989d60fed0e78c7ad61723529d8b0943da 100644 (file)
@@ -317,6 +317,11 @@ lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba,
        }
        spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
+       /* Close the timeout handler abort window */
+       spin_lock_irqsave(&phba->hbalock, flags);
+       cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING;
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+
        iocb = &dd_data->context_un.iocb;
        ndlp = iocb->ndlp;
        rmp = iocb->rmp;
@@ -387,6 +392,7 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
        int request_nseg;
        int reply_nseg;
        struct bsg_job_data *dd_data;
+       unsigned long flags;
        uint32_t creg_val;
        int rc = 0;
        int iocb_stat;
@@ -501,14 +507,24 @@ lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job)
        }
 
        iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
-       if (iocb_stat == IOCB_SUCCESS)
+
+       if (iocb_stat == IOCB_SUCCESS) {
+               spin_lock_irqsave(&phba->hbalock, flags);
+               /* make sure the I/O had not been completed yet */
+               if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) {
+                       /* open up abort window to timeout handler */
+                       cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING;
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
                return 0; /* done for now */
-       else if (iocb_stat == IOCB_BUSY)
+       } else if (iocb_stat == IOCB_BUSY) {
                rc = -EAGAIN;
-       else
+       } else {
                rc = -EIO;
+       }
 
        /* iocb failed so cleanup */
+       job->dd_data = NULL;
 
 free_rmp:
        lpfc_free_bsg_buffers(phba, rmp);
@@ -577,6 +593,11 @@ lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba,
        }
        spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
+       /* Close the timeout handler abort window */
+       spin_lock_irqsave(&phba->hbalock, flags);
+       cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING;
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+
        rsp = &rspiocbq->iocb;
        pcmd = (struct lpfc_dmabuf *)cmdiocbq->context2;
        prsp = (struct lpfc_dmabuf *)pcmd->list.next;
@@ -639,6 +660,7 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
        struct lpfc_iocbq *cmdiocbq;
        uint16_t rpi = 0;
        struct bsg_job_data *dd_data;
+       unsigned long flags;
        uint32_t creg_val;
        int rc = 0;
 
@@ -721,15 +743,25 @@ lpfc_bsg_rport_els(struct fc_bsg_job *job)
 
        rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0);
 
-       if (rc == IOCB_SUCCESS)
+       if (rc == IOCB_SUCCESS) {
+               spin_lock_irqsave(&phba->hbalock, flags);
+               /* make sure the I/O had not been completed/released */
+               if (cmdiocbq->iocb_flag & LPFC_IO_LIBDFC) {
+                       /* open up abort window to timeout handler */
+                       cmdiocbq->iocb_flag |= LPFC_IO_CMD_OUTSTANDING;
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
                return 0; /* done for now */
-       else if (rc == IOCB_BUSY)
+       } else if (rc == IOCB_BUSY) {
                rc = -EAGAIN;
-       else
+       } else {
                rc = -EIO;
+       }
 
-linkdown_err:
+       /* iocb failed so cleanup */
+       job->dd_data = NULL;
 
+linkdown_err:
        cmdiocbq->context1 = ndlp;
        lpfc_els_free_iocb(phba, cmdiocbq);
 
@@ -1249,7 +1281,7 @@ lpfc_bsg_hba_get_event(struct fc_bsg_job *job)
        struct lpfc_hba *phba = vport->phba;
        struct get_ct_event *event_req;
        struct get_ct_event_reply *event_reply;
-       struct lpfc_bsg_event *evt;
+       struct lpfc_bsg_event *evt, *evt_next;
        struct event_data *evt_dat = NULL;
        unsigned long flags;
        uint32_t rc = 0;
@@ -1269,7 +1301,7 @@ lpfc_bsg_hba_get_event(struct fc_bsg_job *job)
        event_reply = (struct get_ct_event_reply *)
                job->reply->reply_data.vendor_reply.vendor_rsp;
        spin_lock_irqsave(&phba->ct_ev_lock, flags);
-       list_for_each_entry(evt, &phba->ct_ev_waiters, node) {
+       list_for_each_entry_safe(evt, evt_next, &phba->ct_ev_waiters, node) {
                if (evt->reg_id == event_req->ev_reg_id) {
                        if (list_empty(&evt->events_to_get))
                                break;
@@ -1370,6 +1402,11 @@ lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba,
        }
        spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
 
+       /* Close the timeout handler abort window */
+       spin_lock_irqsave(&phba->hbalock, flags);
+       cmdiocbq->iocb_flag &= ~LPFC_IO_CMD_OUTSTANDING;
+       spin_unlock_irqrestore(&phba->hbalock, flags);
+
        ndlp = dd_data->context_un.iocb.ndlp;
        cmp = cmdiocbq->context2;
        bmp = cmdiocbq->context3;
@@ -1433,6 +1470,7 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
        int rc = 0;
        struct lpfc_nodelist *ndlp = NULL;
        struct bsg_job_data *dd_data;
+       unsigned long flags;
        uint32_t creg_val;
 
        /* allocate our bsg tracking structure */
@@ -1542,8 +1580,19 @@ lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag,
 
        rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0);
 
-       if (rc == IOCB_SUCCESS)
+       if (rc == IOCB_SUCCESS) {
+               spin_lock_irqsave(&phba->hbalock, flags);
+               /* make sure the I/O had not been completed/released */
+               if (ctiocb->iocb_flag & LPFC_IO_LIBDFC) {
+                       /* open up abort window to timeout handler */
+                       ctiocb->iocb_flag |= LPFC_IO_CMD_OUTSTANDING;
+               }
+               spin_unlock_irqrestore(&phba->hbalock, flags);
                return 0; /* done for now */
+       }
+
+       /* iocb failed so cleanup */
+       job->dd_data = NULL;
 
 issue_ct_rsp_exit:
        lpfc_sli_release_iocbq(phba, ctiocb);
@@ -5284,9 +5333,15 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                 * remove it from the txq queue and call cancel iocbs.
                 * Otherwise, call abort iotag
                 */
-
                cmdiocb = dd_data->context_un.iocb.cmdiocbq;
-               spin_lock_irq(&phba->hbalock);
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+               spin_lock_irqsave(&phba->hbalock, flags);
+               /* make sure the I/O abort window is still open */
+               if (!(cmdiocb->iocb_flag & LPFC_IO_CMD_OUTSTANDING)) {
+                       spin_unlock_irqrestore(&phba->hbalock, flags);
+                       return -EAGAIN;
+               }
                list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
                                         list) {
                        if (check_iocb == cmdiocb) {
@@ -5296,8 +5351,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                }
                if (list_empty(&completions))
                        lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
-               spin_unlock_irq(&phba->hbalock);
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               spin_unlock_irqrestore(&phba->hbalock, flags);
                if (!list_empty(&completions)) {
                        lpfc_sli_cancel_iocbs(phba, &completions,
                                              IOSTAT_LOCAL_REJECT,
@@ -5321,9 +5375,10 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                 * remove it from the txq queue and call cancel iocbs.
                 * Otherwise, call abort iotag.
                 */
-
                cmdiocb = dd_data->context_un.menlo.cmdiocbq;
-               spin_lock_irq(&phba->hbalock);
+               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+
+               spin_lock_irqsave(&phba->hbalock, flags);
                list_for_each_entry_safe(check_iocb, next_iocb, &pring->txq,
                                         list) {
                        if (check_iocb == cmdiocb) {
@@ -5333,8 +5388,7 @@ lpfc_bsg_timeout(struct fc_bsg_job *job)
                }
                if (list_empty(&completions))
                        lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb);
-               spin_unlock_irq(&phba->hbalock);
-               spin_unlock_irqrestore(&phba->ct_ev_lock, flags);
+               spin_unlock_irqrestore(&phba->hbalock, flags);
                if (!list_empty(&completions)) {
                        lpfc_sli_cancel_iocbs(phba, &completions,
                                              IOSTAT_LOCAL_REJECT,
index 60d6ca2f68c22bea28a888c19940eb10acaefea9..7801601aa5d9e1977904124b2e9220cda8d66465 100644 (file)
@@ -4437,6 +4437,7 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        if (!ndlp)
                return;
        lpfc_issue_els_logo(vport, ndlp, 0);
+       mempool_free(pmb, phba->mbox_mem_pool);
 }
 
 /*
@@ -4456,7 +4457,15 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        int rc;
        uint16_t rpi;
 
-       if (ndlp->nlp_flag & NLP_RPI_REGISTERED) {
+       if (ndlp->nlp_flag & NLP_RPI_REGISTERED ||
+           ndlp->nlp_flag & NLP_REG_LOGIN_SEND) {
+               if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND)
+                       lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI,
+                                        "3366 RPI x%x needs to be "
+                                        "unregistered nlp_flag x%x "
+                                        "did x%x\n",
+                                        ndlp->nlp_rpi, ndlp->nlp_flag,
+                                        ndlp->nlp_DID);
                mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
                if (mbox) {
                        /* SLI4 ports require the physical rpi value. */
index 501147c4a147233be1ee8a1b2a0ff0b118bf5751..647f5bfb3bd33f312135a869b8ee0793a879a7a8 100644 (file)
@@ -3031,10 +3031,10 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
                        phba->sli4_hba.scsi_xri_max);
 
        spin_lock_irq(&phba->scsi_buf_list_get_lock);
-       spin_lock_irq(&phba->scsi_buf_list_put_lock);
+       spin_lock(&phba->scsi_buf_list_put_lock);
        list_splice_init(&phba->lpfc_scsi_buf_list_get, &scsi_sgl_list);
        list_splice(&phba->lpfc_scsi_buf_list_put, &scsi_sgl_list);
-       spin_unlock_irq(&phba->scsi_buf_list_put_lock);
+       spin_unlock(&phba->scsi_buf_list_put_lock);
        spin_unlock_irq(&phba->scsi_buf_list_get_lock);
 
        if (phba->sli4_hba.scsi_xri_cnt > phba->sli4_hba.scsi_xri_max) {
@@ -3070,10 +3070,10 @@ lpfc_sli4_xri_sgl_update(struct lpfc_hba *phba)
                psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri];
        }
        spin_lock_irq(&phba->scsi_buf_list_get_lock);
-       spin_lock_irq(&phba->scsi_buf_list_put_lock);
+       spin_lock(&phba->scsi_buf_list_put_lock);
        list_splice_init(&scsi_sgl_list, &phba->lpfc_scsi_buf_list_get);
        INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
-       spin_unlock_irq(&phba->scsi_buf_list_put_lock);
+       spin_unlock(&phba->scsi_buf_list_put_lock);
        spin_unlock_irq(&phba->scsi_buf_list_get_lock);
 
        return 0;
@@ -4859,6 +4859,9 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
        struct lpfc_mqe *mqe;
        int longs;
 
+       /* Get all the module params for configuring this host */
+       lpfc_get_cfgparam(phba);
+
        /* Before proceed, wait for POST done and device ready */
        rc = lpfc_sli4_post_status_check(phba);
        if (rc)
@@ -4902,15 +4905,6 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba)
                sizeof(struct lpfc_mbox_ext_buf_ctx));
        INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list);
 
-       /*
-        * We need to do a READ_CONFIG mailbox command here before
-        * calling lpfc_get_cfgparam. For VFs this will report the
-        * MAX_XRI, MAX_VPI, MAX_RPI, MAX_IOCB, and MAX_VFI settings.
-        * All of the resources allocated
-        * for this Port are tied to these values.
-        */
-       /* Get all the module params for configuring this host */
-       lpfc_get_cfgparam(phba);
        phba->max_vpi = LPFC_MAX_VPI;
 
        /* This will be set to correct value after the read_config mbox */
@@ -7141,19 +7135,6 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba)
                phba->sli4_hba.fcp_wq = NULL;
        }
 
-       if (phba->pci_bar0_memmap_p) {
-               iounmap(phba->pci_bar0_memmap_p);
-               phba->pci_bar0_memmap_p = NULL;
-       }
-       if (phba->pci_bar2_memmap_p) {
-               iounmap(phba->pci_bar2_memmap_p);
-               phba->pci_bar2_memmap_p = NULL;
-       }
-       if (phba->pci_bar4_memmap_p) {
-               iounmap(phba->pci_bar4_memmap_p);
-               phba->pci_bar4_memmap_p = NULL;
-       }
-
        /* Release FCP CQ mapping array */
        if (phba->sli4_hba.fcp_cq_map != NULL) {
                kfree(phba->sli4_hba.fcp_cq_map);
@@ -7942,9 +7923,9 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
         * particular PCI BARs regions is dependent on the type of
         * SLI4 device.
         */
-       if (pci_resource_start(pdev, 0)) {
-               phba->pci_bar0_map = pci_resource_start(pdev, 0);
-               bar0map_len = pci_resource_len(pdev, 0);
+       if (pci_resource_start(pdev, PCI_64BIT_BAR0)) {
+               phba->pci_bar0_map = pci_resource_start(pdev, PCI_64BIT_BAR0);
+               bar0map_len = pci_resource_len(pdev, PCI_64BIT_BAR0);
 
                /*
                 * Map SLI4 PCI Config Space Register base to a kernel virtual
@@ -7958,6 +7939,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
                                   "registers.\n");
                        goto out;
                }
+               phba->pci_bar0_memmap_p = phba->sli4_hba.conf_regs_memmap_p;
                /* Set up BAR0 PCI config space register memory map */
                lpfc_sli4_bar0_register_memmap(phba, if_type);
        } else {
@@ -7980,13 +7962,13 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
        }
 
        if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) &&
-           (pci_resource_start(pdev, 2))) {
+           (pci_resource_start(pdev, PCI_64BIT_BAR2))) {
                /*
                 * Map SLI4 if type 0 HBA Control Register base to a kernel
                 * virtual address and setup the registers.
                 */
-               phba->pci_bar1_map = pci_resource_start(pdev, 2);
-               bar1map_len = pci_resource_len(pdev, 2);
+               phba->pci_bar1_map = pci_resource_start(pdev, PCI_64BIT_BAR2);
+               bar1map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
                phba->sli4_hba.ctrl_regs_memmap_p =
                                ioremap(phba->pci_bar1_map, bar1map_len);
                if (!phba->sli4_hba.ctrl_regs_memmap_p) {
@@ -7994,17 +7976,18 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
                           "ioremap failed for SLI4 HBA control registers.\n");
                        goto out_iounmap_conf;
                }
+               phba->pci_bar2_memmap_p = phba->sli4_hba.ctrl_regs_memmap_p;
                lpfc_sli4_bar1_register_memmap(phba);
        }
 
        if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) &&
-           (pci_resource_start(pdev, 4))) {
+           (pci_resource_start(pdev, PCI_64BIT_BAR4))) {
                /*
                 * Map SLI4 if type 0 HBA Doorbell Register base to a kernel
                 * virtual address and setup the registers.
                 */
-               phba->pci_bar2_map = pci_resource_start(pdev, 4);
-               bar2map_len = pci_resource_len(pdev, 4);
+               phba->pci_bar2_map = pci_resource_start(pdev, PCI_64BIT_BAR4);
+               bar2map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
                phba->sli4_hba.drbl_regs_memmap_p =
                                ioremap(phba->pci_bar2_map, bar2map_len);
                if (!phba->sli4_hba.drbl_regs_memmap_p) {
@@ -8012,6 +7995,7 @@ lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba)
                           "ioremap failed for SLI4 HBA doorbell registers.\n");
                        goto out_iounmap_ctrl;
                }
+               phba->pci_bar4_memmap_p = phba->sli4_hba.drbl_regs_memmap_p;
                error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0);
                if (error)
                        goto out_iounmap_all;
@@ -8405,7 +8389,8 @@ static int
 lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
 {
        int i, idx, saved_chann, used_chann, cpu, phys_id;
-       int max_phys_id, num_io_channel, first_cpu;
+       int max_phys_id, min_phys_id;
+       int num_io_channel, first_cpu, chan;
        struct lpfc_vector_map_info *cpup;
 #ifdef CONFIG_X86
        struct cpuinfo_x86 *cpuinfo;
@@ -8423,6 +8408,7 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
                phba->sli4_hba.num_present_cpu));
 
        max_phys_id = 0;
+       min_phys_id = 0xff;
        phys_id = 0;
        num_io_channel = 0;
        first_cpu = LPFC_VECTOR_MAP_EMPTY;
@@ -8446,9 +8432,12 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
 
                if (cpup->phys_id > max_phys_id)
                        max_phys_id = cpup->phys_id;
+               if (cpup->phys_id < min_phys_id)
+                       min_phys_id = cpup->phys_id;
                cpup++;
        }
 
+       phys_id = min_phys_id;
        /* Now associate the HBA vectors with specific CPUs */
        for (idx = 0; idx < vectors; idx++) {
                cpup = phba->sli4_hba.cpu_map;
@@ -8459,13 +8448,25 @@ lpfc_sli4_set_affinity(struct lpfc_hba *phba, int vectors)
                        for (i = 1; i < max_phys_id; i++) {
                                phys_id++;
                                if (phys_id > max_phys_id)
-                                       phys_id = 0;
+                                       phys_id = min_phys_id;
                                cpu = lpfc_find_next_cpu(phba, phys_id);
                                if (cpu == LPFC_VECTOR_MAP_EMPTY)
                                        continue;
                                goto found;
                        }
 
+                       /* Use round robin for scheduling */
+                       phba->cfg_fcp_io_sched = LPFC_FCP_SCHED_ROUND_ROBIN;
+                       chan = 0;
+                       cpup = phba->sli4_hba.cpu_map;
+                       for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) {
+                               cpup->channel_id = chan;
+                               cpup++;
+                               chan++;
+                               if (chan >= phba->cfg_fcp_io_channel)
+                                       chan = 0;
+                       }
+
                        lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                        "3329 Cannot set affinity:"
                                        "Error mapping vector %d (%d)\n",
@@ -8503,7 +8504,7 @@ found:
                /* Spread vector mapping across multple physical CPU nodes */
                phys_id++;
                if (phys_id > max_phys_id)
-                       phys_id = 0;
+                       phys_id = min_phys_id;
        }
 
        /*
@@ -8513,7 +8514,7 @@ found:
         * Base the remaining IO channel assigned, to IO channels already
         * assigned to other CPUs on the same phys_id.
         */
-       for (i = 0; i <= max_phys_id; i++) {
+       for (i = min_phys_id; i <= max_phys_id; i++) {
                /*
                 * If there are no io channels already mapped to
                 * this phys_id, just round robin thru the io_channels.
@@ -8595,10 +8596,11 @@ out:
        if (num_io_channel != phba->sli4_hba.num_present_cpu)
                lpfc_printf_log(phba, KERN_ERR, LOG_INIT,
                                "3333 Set affinity mismatch:"
-                               "%d chann != %d cpus: %d vactors\n",
+                               "%d chann != %d cpus: %d vectors\n",
                                num_io_channel, phba->sli4_hba.num_present_cpu,
                                vectors);
 
+       /* Enable using cpu affinity for scheduling */
        phba->cfg_fcp_io_sched = LPFC_FCP_SCHED_BY_CPU;
        return 1;
 }
@@ -8689,9 +8691,12 @@ enable_msix_vectors:
 
 cfg_fail_out:
        /* free the irq already requested */
-       for (--index; index >= 0; index--)
+       for (--index; index >= 0; index--) {
+               irq_set_affinity_hint(phba->sli4_hba.msix_entries[index].
+                                         vector, NULL);
                free_irq(phba->sli4_hba.msix_entries[index].vector,
                         &phba->sli4_hba.fcp_eq_hdl[index]);
+       }
 
 msi_fail_out:
        /* Unconfigure MSI-X capability structure */
@@ -8712,9 +8717,12 @@ lpfc_sli4_disable_msix(struct lpfc_hba *phba)
        int index;
 
        /* Free up MSI-X multi-message vectors */
-       for (index = 0; index < phba->cfg_fcp_io_channel; index++)
+       for (index = 0; index < phba->cfg_fcp_io_channel; index++) {
+               irq_set_affinity_hint(phba->sli4_hba.msix_entries[index].
+                                         vector, NULL);
                free_irq(phba->sli4_hba.msix_entries[index].vector,
                         &phba->sli4_hba.fcp_eq_hdl[index]);
+       }
 
        /* Disable MSI-X */
        pci_disable_msix(phba->pcidev);
index 1242b6c4308b51eda7311d140c6ca52b76805374..c913e8cc3b269ca82096efd6e356dc8e9e635de9 100644 (file)
@@ -926,10 +926,10 @@ lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba)
 
        /* get all SCSI buffers need to repost to a local list */
        spin_lock_irq(&phba->scsi_buf_list_get_lock);
-       spin_lock_irq(&phba->scsi_buf_list_put_lock);
+       spin_lock(&phba->scsi_buf_list_put_lock);
        list_splice_init(&phba->lpfc_scsi_buf_list_get, &post_sblist);
        list_splice(&phba->lpfc_scsi_buf_list_put, &post_sblist);
-       spin_unlock_irq(&phba->scsi_buf_list_put_lock);
+       spin_unlock(&phba->scsi_buf_list_put_lock);
        spin_unlock_irq(&phba->scsi_buf_list_get_lock);
 
        /* post the list of scsi buffer sgls to port if available */
@@ -1000,9 +1000,12 @@ lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc)
                }
                memset(psb->data, 0, phba->cfg_sg_dma_buf_size);
 
-               /* Page alignment is CRITICAL, double check to be sure */
-               if (((unsigned long)(psb->data) &
-                   (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0) {
+               /*
+                * 4K Page alignment is CRITICAL to BlockGuard, double check
+                * to be sure.
+                */
+               if (phba->cfg_enable_bg  && (((unsigned long)(psb->data) &
+                   (unsigned long)(SLI4_PAGE_SIZE - 1)) != 0)) {
                        pci_pool_free(phba->lpfc_scsi_dma_buf_pool,
                                      psb->data, psb->dma_handle);
                        kfree(psb);
@@ -1134,22 +1137,21 @@ lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        struct  lpfc_scsi_buf * lpfc_cmd = NULL;
        struct list_head *scsi_buf_list_get = &phba->lpfc_scsi_buf_list_get;
-       unsigned long gflag = 0;
-       unsigned long pflag = 0;
+       unsigned long iflag = 0;
 
-       spin_lock_irqsave(&phba->scsi_buf_list_get_lock, gflag);
+       spin_lock_irqsave(&phba->scsi_buf_list_get_lock, iflag);
        list_remove_head(scsi_buf_list_get, lpfc_cmd, struct lpfc_scsi_buf,
                         list);
        if (!lpfc_cmd) {
-               spin_lock_irqsave(&phba->scsi_buf_list_put_lock, pflag);
+               spin_lock(&phba->scsi_buf_list_put_lock);
                list_splice(&phba->lpfc_scsi_buf_list_put,
                            &phba->lpfc_scsi_buf_list_get);
                INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
                list_remove_head(scsi_buf_list_get, lpfc_cmd,
                                 struct lpfc_scsi_buf, list);
-               spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, pflag);
+               spin_unlock(&phba->scsi_buf_list_put_lock);
        }
-       spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, gflag);
+       spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, iflag);
        return  lpfc_cmd;
 }
 /**
@@ -1167,11 +1169,10 @@ static struct lpfc_scsi_buf*
 lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
 {
        struct lpfc_scsi_buf *lpfc_cmd, *lpfc_cmd_next;
-       unsigned long gflag = 0;
-       unsigned long pflag = 0;
+       unsigned long iflag = 0;
        int found = 0;
 
-       spin_lock_irqsave(&phba->scsi_buf_list_get_lock, gflag);
+       spin_lock_irqsave(&phba->scsi_buf_list_get_lock, iflag);
        list_for_each_entry_safe(lpfc_cmd, lpfc_cmd_next,
                                 &phba->lpfc_scsi_buf_list_get, list) {
                if (lpfc_test_rrq_active(phba, ndlp,
@@ -1182,11 +1183,11 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
                break;
        }
        if (!found) {
-               spin_lock_irqsave(&phba->scsi_buf_list_put_lock, pflag);
+               spin_lock(&phba->scsi_buf_list_put_lock);
                list_splice(&phba->lpfc_scsi_buf_list_put,
                            &phba->lpfc_scsi_buf_list_get);
                INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list_put);
-               spin_unlock_irqrestore(&phba->scsi_buf_list_put_lock, pflag);
+               spin_unlock(&phba->scsi_buf_list_put_lock);
                list_for_each_entry_safe(lpfc_cmd, lpfc_cmd_next,
                                         &phba->lpfc_scsi_buf_list_get, list) {
                        if (lpfc_test_rrq_active(
@@ -1197,7 +1198,7 @@ lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
                        break;
                }
        }
-       spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, gflag);
+       spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, iflag);
        if (!found)
                return NULL;
        return  lpfc_cmd;
@@ -3966,11 +3967,11 @@ lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
 
        /*
         * Check SLI validation that all the transfer was actually done
-        * (fcpi_parm should be zero).
+        * (fcpi_parm should be zero). Apply check only to reads.
         */
-       } else if (fcpi_parm) {
+       } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) {
                lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR,
-                                "9029 FCP Data Transfer Check Error: "
+                                "9029 FCP Read Check Error Data: "
                                 "x%x x%x x%x x%x x%x\n",
                                 be32_to_cpu(fcpcmd->fcpDl),
                                 be32_to_cpu(fcprsp->rspResId),
@@ -4342,6 +4343,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
        char tag[2];
        uint8_t *ptr;
        bool sli4;
+       uint32_t fcpdl;
 
        if (!pnode || !NLP_CHK_NODE_ACT(pnode))
                return;
@@ -4389,8 +4391,12 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
                        iocb_cmd->ulpPU = PARM_READ_CHECK;
                        if (vport->cfg_first_burst_size &&
                            (pnode->nlp_flag & NLP_FIRSTBURST)) {
-                               piocbq->iocb.un.fcpi.fcpi_XRdy =
-                                       vport->cfg_first_burst_size;
+                               fcpdl = scsi_bufflen(scsi_cmnd);
+                               if (fcpdl < vport->cfg_first_burst_size)
+                                       piocbq->iocb.un.fcpi.fcpi_XRdy = fcpdl;
+                               else
+                                       piocbq->iocb.un.fcpi.fcpi_XRdy =
+                                               vport->cfg_first_burst_size;
                        }
                        fcp_cmnd->fcpCntl3 = WRITE_DATA;
                        phba->fc4OutputRequests++;
@@ -4878,6 +4884,9 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd)
                goto out_unlock;
        }
 
+       /* Indicate the IO is being aborted by the driver. */
+       iocb->iocb_flag |= LPFC_DRIVER_ABORTED;
+
        /*
         * The scsi command can not be in txq and it is in flight because the
         * pCmd is still pointig at the SCSI command we have to abort. There
@@ -5006,7 +5015,7 @@ lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata,
        lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode);
        if (lpfc_cmd == NULL)
                return FAILED;
-       lpfc_cmd->timeout = 60;
+       lpfc_cmd->timeout = phba->cfg_task_mgmt_tmo;
        lpfc_cmd->rdata = rdata;
 
        status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id,
index 0392e114531c5620169f65ff6a889960735a960f..612f48973ff2c2c7c7f5e7f571a42a0b74b1f30f 100644 (file)
@@ -9831,6 +9831,13 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                                               abort_cmd) != 0)
                        continue;
 
+               /*
+                * If the iocbq is already being aborted, don't take a second
+                * action, but do count it.
+                */
+               if (iocbq->iocb_flag & LPFC_DRIVER_ABORTED)
+                       continue;
+
                /* issue ABTS for this IOCB based on iotag */
                abtsiocb = lpfc_sli_get_iocbq(phba);
                if (abtsiocb == NULL) {
@@ -9838,6 +9845,9 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                        continue;
                }
 
+               /* indicate the IO is being aborted by the driver. */
+               iocbq->iocb_flag |= LPFC_DRIVER_ABORTED;
+
                cmd = &iocbq->iocb;
                abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS;
                abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext;
@@ -9847,7 +9857,7 @@ lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring,
                        abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag;
                abtsiocb->iocb.ulpLe = 1;
                abtsiocb->iocb.ulpClass = cmd->ulpClass;
-               abtsiocb->vport = phba->pport;
+               abtsiocb->vport = vport;
 
                /* ABTS WQE must go to the same WQ as the WQE to be aborted */
                abtsiocb->fcp_wqidx = iocbq->fcp_wqidx;
@@ -12233,7 +12243,6 @@ static void __iomem *
 lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
 {
        struct pci_dev *pdev;
-       unsigned long bar_map, bar_map_len;
 
        if (!phba->pcidev)
                return NULL;
@@ -12242,25 +12251,10 @@ lpfc_dual_chute_pci_bar_map(struct lpfc_hba *phba, uint16_t pci_barset)
 
        switch (pci_barset) {
        case WQ_PCI_BAR_0_AND_1:
-               if (!phba->pci_bar0_memmap_p) {
-                       bar_map = pci_resource_start(pdev, PCI_64BIT_BAR0);
-                       bar_map_len = pci_resource_len(pdev, PCI_64BIT_BAR0);
-                       phba->pci_bar0_memmap_p = ioremap(bar_map, bar_map_len);
-               }
                return phba->pci_bar0_memmap_p;
        case WQ_PCI_BAR_2_AND_3:
-               if (!phba->pci_bar2_memmap_p) {
-                       bar_map = pci_resource_start(pdev, PCI_64BIT_BAR2);
-                       bar_map_len = pci_resource_len(pdev, PCI_64BIT_BAR2);
-                       phba->pci_bar2_memmap_p = ioremap(bar_map, bar_map_len);
-               }
                return phba->pci_bar2_memmap_p;
        case WQ_PCI_BAR_4_AND_5:
-               if (!phba->pci_bar4_memmap_p) {
-                       bar_map = pci_resource_start(pdev, PCI_64BIT_BAR4);
-                       bar_map_len = pci_resource_len(pdev, PCI_64BIT_BAR4);
-                       phba->pci_bar4_memmap_p = ioremap(bar_map, bar_map_len);
-               }
                return phba->pci_bar4_memmap_p;
        default:
                break;
@@ -15808,7 +15802,7 @@ lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index)
 void
 lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
 {
-       struct lpfc_fcf_pri *fcf_pri;
+       struct lpfc_fcf_pri *fcf_pri, *fcf_pri_next;
        if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) {
                lpfc_printf_log(phba, KERN_ERR, LOG_FIP,
                                "2762 FCF (x%x) reached driver's book "
@@ -15818,7 +15812,8 @@ lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index)
        }
        /* Clear the eligible FCF record index bmask */
        spin_lock_irq(&phba->hbalock);
-       list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) {
+       list_for_each_entry_safe(fcf_pri, fcf_pri_next, &phba->fcf.fcf_pri_list,
+                                list) {
                if (fcf_pri->fcf_rec.fcf_index == fcf_index) {
                        list_del_init(&fcf_pri->list);
                        break;
index 97617996206dd63864924997ba30065d0f9e552f..6b0f2478706ec2c94bc2d9382be03a25df4afd53 100644 (file)
@@ -58,7 +58,7 @@ struct lpfc_iocbq {
 
        IOCB_t iocb;            /* IOCB cmd */
        uint8_t retry;          /* retry counter for IOCB cmd - if needed */
-       uint16_t iocb_flag;
+       uint32_t iocb_flag;
 #define LPFC_IO_LIBDFC         1       /* libdfc iocb */
 #define LPFC_IO_WAKE           2       /* Synchronous I/O completed */
 #define LPFC_IO_WAKE_TMO       LPFC_IO_WAKE /* Synchronous I/O timed out */
@@ -73,11 +73,11 @@ struct lpfc_iocbq {
 #define LPFC_IO_DIF_PASS       0x400   /* T10 DIF IO pass-thru prot */
 #define LPFC_IO_DIF_STRIP      0x800   /* T10 DIF IO strip prot */
 #define LPFC_IO_DIF_INSERT     0x1000  /* T10 DIF IO insert prot */
+#define LPFC_IO_CMD_OUTSTANDING        0x2000 /* timeout handler abort window */
 
 #define LPFC_FIP_ELS_ID_MASK   0xc000  /* ELS_ID range 0-3, non-shifted mask */
 #define LPFC_FIP_ELS_ID_SHIFT  14
 
-       uint8_t rsvd2;
        uint32_t drvrTimeout;   /* driver timeout in seconds */
        uint32_t fcp_wqidx;     /* index to FCP work queue */
        struct lpfc_vport *vport;/* virtual port pointer */
index 5bcc38223ac9fff92e6757ca44da9c65d8cc3f3e..85120b77aa0e99aea4621c2204342a47e11ce5ef 100644 (file)
@@ -523,7 +523,7 @@ struct lpfc_sli4_hba {
        struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */
        struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */
 
-       uint8_t fw_func_mode;   /* FW function protocol mode */
+       uint32_t fw_func_mode;  /* FW function protocol mode */
        uint32_t ulp0_mode;     /* ULP0 protocol mode */
        uint32_t ulp1_mode;     /* ULP1 protocol mode */
 
index 21859d2006ce64cf99b3987c2a6bb0f09ff6b59d..f58f18342bc3e9b001cd9156a64cab7ddf344695 100644 (file)
@@ -18,7 +18,7 @@
  * included with this package.                                     *
  *******************************************************************/
 
-#define LPFC_DRIVER_VERSION "8.3.41"
+#define LPFC_DRIVER_VERSION "8.3.42"
 #define LPFC_DRIVER_NAME               "lpfc"
 
 /* Used for SLI 2/3 */
index 04a42a505852e141c620d9bec33ca5aa378e79b8..0c73ba4bf451425e36f97bd8642b8499aebbb764 100644 (file)
@@ -33,9 +33,9 @@
 /*
  * MegaRAID SAS Driver meta data
  */
-#define MEGASAS_VERSION                                "06.600.18.00-rc1"
-#define MEGASAS_RELDATE                                "May. 15, 2013"
-#define MEGASAS_EXT_VERSION                    "Wed. May. 15 17:00:00 PDT 2013"
+#define MEGASAS_VERSION                                "06.700.06.00-rc1"
+#define MEGASAS_RELDATE                                "Aug. 31, 2013"
+#define MEGASAS_EXT_VERSION                    "Sat. Aug. 31 17:00:00 PDT 2013"
 
 /*
  * Device IDs
 
 #define MR_DCMD_CTRL_GET_INFO                  0x01010000
 #define MR_DCMD_LD_GET_LIST                    0x03010000
+#define MR_DCMD_LD_LIST_QUERY                  0x03010100
 
 #define MR_DCMD_CTRL_CACHE_FLUSH               0x01101000
 #define MR_FLUSH_CTRL_CACHE                    0x01
@@ -345,6 +346,15 @@ enum MR_PD_QUERY_TYPE {
        MR_PD_QUERY_TYPE_EXPOSED_TO_HOST    = 5,
 };
 
+enum MR_LD_QUERY_TYPE {
+       MR_LD_QUERY_TYPE_ALL             = 0,
+       MR_LD_QUERY_TYPE_EXPOSED_TO_HOST = 1,
+       MR_LD_QUERY_TYPE_USED_TGT_IDS    = 2,
+       MR_LD_QUERY_TYPE_CLUSTER_ACCESS  = 3,
+       MR_LD_QUERY_TYPE_CLUSTER_LOCALE  = 4,
+};
+
+
 #define MR_EVT_CFG_CLEARED                              0x0004
 #define MR_EVT_LD_STATE_CHANGE                          0x0051
 #define MR_EVT_PD_INSERTED                              0x005b
@@ -435,6 +445,14 @@ struct MR_LD_LIST {
        } ldList[MAX_LOGICAL_DRIVES];
 } __packed;
 
+struct MR_LD_TARGETID_LIST {
+       u32     size;
+       u32     count;
+       u8      pad[3];
+       u8      targetId[MAX_LOGICAL_DRIVES];
+};
+
+
 /*
  * SAS controller properties
  */
@@ -474,21 +492,39 @@ struct megasas_ctrl_prop {
        * a bit in the following structure.
        */
        struct {
-               u32     copyBackDisabled            : 1;
-               u32     SMARTerEnabled              : 1;
-               u32     prCorrectUnconfiguredAreas  : 1;
-               u32     useFdeOnly                  : 1;
-               u32     disableNCQ                  : 1;
-               u32     SSDSMARTerEnabled           : 1;
-               u32     SSDPatrolReadEnabled        : 1;
-               u32     enableSpinDownUnconfigured  : 1;
-               u32     autoEnhancedImport          : 1;
-               u32     enableSecretKeyControl      : 1;
-               u32     disableOnlineCtrlReset      : 1;
-               u32     allowBootWithPinnedCache    : 1;
-               u32     disableSpinDownHS           : 1;
-               u32     enableJBOD                  : 1;
-               u32     reserved                    :18;
+#if   defined(__BIG_ENDIAN_BITFIELD)
+               u32     reserved:18;
+               u32     enableJBOD:1;
+               u32     disableSpinDownHS:1;
+               u32     allowBootWithPinnedCache:1;
+               u32     disableOnlineCtrlReset:1;
+               u32     enableSecretKeyControl:1;
+               u32     autoEnhancedImport:1;
+               u32     enableSpinDownUnconfigured:1;
+               u32     SSDPatrolReadEnabled:1;
+               u32     SSDSMARTerEnabled:1;
+               u32     disableNCQ:1;
+               u32     useFdeOnly:1;
+               u32     prCorrectUnconfiguredAreas:1;
+               u32     SMARTerEnabled:1;
+               u32     copyBackDisabled:1;
+#else
+               u32     copyBackDisabled:1;
+               u32     SMARTerEnabled:1;
+               u32     prCorrectUnconfiguredAreas:1;
+               u32     useFdeOnly:1;
+               u32     disableNCQ:1;
+               u32     SSDSMARTerEnabled:1;
+               u32     SSDPatrolReadEnabled:1;
+               u32     enableSpinDownUnconfigured:1;
+               u32     autoEnhancedImport:1;
+               u32     enableSecretKeyControl:1;
+               u32     disableOnlineCtrlReset:1;
+               u32     allowBootWithPinnedCache:1;
+               u32     disableSpinDownHS:1;
+               u32     enableJBOD:1;
+               u32     reserved:18;
+#endif
        } OnOffProperties;
        u8 autoSnapVDSpace;
        u8 viewSpace;
@@ -802,6 +838,30 @@ struct megasas_ctrl_info {
        u16 cacheMemorySize;                    /*7A2h */
 
        struct {                                /*7A4h */
+#if   defined(__BIG_ENDIAN_BITFIELD)
+               u32     reserved:11;
+               u32     supportUnevenSpans:1;
+               u32     dedicatedHotSparesLimited:1;
+               u32     headlessMode:1;
+               u32     supportEmulatedDrives:1;
+               u32     supportResetNow:1;
+               u32     realTimeScheduler:1;
+               u32     supportSSDPatrolRead:1;
+               u32     supportPerfTuning:1;
+               u32     disableOnlinePFKChange:1;
+               u32     supportJBOD:1;
+               u32     supportBootTimePFKChange:1;
+               u32     supportSetLinkSpeed:1;
+               u32     supportEmergencySpares:1;
+               u32     supportSuspendResumeBGops:1;
+               u32     blockSSDWriteCacheChange:1;
+               u32     supportShieldState:1;
+               u32     supportLdBBMInfo:1;
+               u32     supportLdPIType3:1;
+               u32     supportLdPIType2:1;
+               u32     supportLdPIType1:1;
+               u32     supportPIcontroller:1;
+#else
                u32     supportPIcontroller:1;
                u32     supportLdPIType1:1;
                u32     supportLdPIType2:1;
@@ -827,6 +887,7 @@ struct megasas_ctrl_info {
 
                u32     supportUnevenSpans:1;
                u32     reserved:11;
+#endif
        } adapterOperations2;
 
        u8  driverVersion[32];                  /*7A8h */
@@ -863,7 +924,7 @@ struct megasas_ctrl_info {
  * ===============================
  */
 #define MEGASAS_MAX_PD_CHANNELS                        2
-#define MEGASAS_MAX_LD_CHANNELS                        2
+#define MEGASAS_MAX_LD_CHANNELS                        1
 #define MEGASAS_MAX_CHANNELS                   (MEGASAS_MAX_PD_CHANNELS + \
                                                MEGASAS_MAX_LD_CHANNELS)
 #define MEGASAS_MAX_DEV_PER_CHANNEL            128
@@ -1051,9 +1112,15 @@ union megasas_sgl_frame {
 
 typedef union _MFI_CAPABILITIES {
        struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+               u32     reserved:30;
+               u32     support_additional_msix:1;
+               u32     support_fp_remote_lun:1;
+#else
                u32     support_fp_remote_lun:1;
                u32     support_additional_msix:1;
                u32     reserved:30;
+#endif
        } mfi_capabilities;
        u32     reg;
 } MFI_CAPABILITIES;
@@ -1656,4 +1723,16 @@ struct megasas_mgmt_info {
        int max_index;
 };
 
+u8
+MR_BuildRaidContext(struct megasas_instance *instance,
+                   struct IO_REQUEST_INFO *io_info,
+                   struct RAID_CONTEXT *pRAID_Context,
+                   struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN);
+u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
+struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map);
+u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map);
+u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map);
+u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
+
 #endif                         /*LSI_MEGARAID_SAS_H */
index 1f0ca68409d43a09ae24bd98a1703d34ec2ba2cc..3020921a474671e6c9845ba26979d56c389a96c3 100644 (file)
@@ -18,7 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
  *  FILE: megaraid_sas_base.c
- *  Version : 06.600.18.00-rc1
+ *  Version : 06.700.06.00-rc1
  *
  *  Authors: LSI Corporation
  *           Sreenivas Bagalkote
@@ -92,6 +92,8 @@ MODULE_DESCRIPTION("LSI MegaRAID SAS Driver");
 
 int megasas_transition_to_ready(struct megasas_instance *instance, int ocr);
 static int megasas_get_pd_list(struct megasas_instance *instance);
+static int megasas_ld_list_query(struct megasas_instance *instance,
+                                u8 query_type);
 static int megasas_issue_init_mfi(struct megasas_instance *instance);
 static int megasas_register_aen(struct megasas_instance *instance,
                                u32 seq_num, u32 class_locale_word);
@@ -374,13 +376,11 @@ static int
 megasas_check_reset_xscale(struct megasas_instance *instance,
                struct megasas_register_set __iomem *regs)
 {
-       u32 consumer;
-       consumer = *instance->consumer;
 
        if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) &&
-               (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) {
+           (le32_to_cpu(*instance->consumer) ==
+               MEGASAS_ADPRESET_INPROG_SIGN))
                return 1;
-       }
        return 0;
 }
 
@@ -629,9 +629,10 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance,
 {
        unsigned long flags;
        spin_lock_irqsave(&instance->hba_lock, flags);
-       writel(0, &(regs)->inbound_high_queue_port);
-       writel((frame_phys_addr | (frame_count<<1))|1,
-               &(regs)->inbound_low_queue_port);
+       writel(upper_32_bits(frame_phys_addr),
+              &(regs)->inbound_high_queue_port);
+       writel((lower_32_bits(frame_phys_addr) | (frame_count<<1))|1,
+              &(regs)->inbound_low_queue_port);
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 }
 
@@ -879,8 +880,8 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
 
        struct megasas_header *frame_hdr = &cmd->frame->hdr;
 
-       frame_hdr->cmd_status = 0xFF;
-       frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+       frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE;
+       frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
        /*
         * Issue the frame using inbound queue port
@@ -944,10 +945,12 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
         */
        abort_fr->cmd = MFI_CMD_ABORT;
        abort_fr->cmd_status = 0xFF;
-       abort_fr->flags = 0;
-       abort_fr->abort_context = cmd_to_abort->index;
-       abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr;
-       abort_fr->abort_mfi_phys_addr_hi = 0;
+       abort_fr->flags = cpu_to_le16(0);
+       abort_fr->abort_context = cpu_to_le32(cmd_to_abort->index);
+       abort_fr->abort_mfi_phys_addr_lo =
+               cpu_to_le32(lower_32_bits(cmd_to_abort->frame_phys_addr));
+       abort_fr->abort_mfi_phys_addr_hi =
+               cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
 
        cmd->sync_cmd = 1;
        cmd->cmd_status = 0xFF;
@@ -986,8 +989,8 @@ megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp,
 
        if (sge_count) {
                scsi_for_each_sg(scp, os_sgl, sge_count, i) {
-                       mfi_sgl->sge32[i].length = sg_dma_len(os_sgl);
-                       mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl);
+                       mfi_sgl->sge32[i].length = cpu_to_le32(sg_dma_len(os_sgl));
+                       mfi_sgl->sge32[i].phys_addr = cpu_to_le32(sg_dma_address(os_sgl));
                }
        }
        return sge_count;
@@ -1015,8 +1018,8 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
 
        if (sge_count) {
                scsi_for_each_sg(scp, os_sgl, sge_count, i) {
-                       mfi_sgl->sge64[i].length = sg_dma_len(os_sgl);
-                       mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl);
+                       mfi_sgl->sge64[i].length = cpu_to_le32(sg_dma_len(os_sgl));
+                       mfi_sgl->sge64[i].phys_addr = cpu_to_le64(sg_dma_address(os_sgl));
                }
        }
        return sge_count;
@@ -1043,10 +1046,11 @@ megasas_make_sgl_skinny(struct megasas_instance *instance,
 
        if (sge_count) {
                scsi_for_each_sg(scp, os_sgl, sge_count, i) {
-                       mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
+                       mfi_sgl->sge_skinny[i].length =
+                               cpu_to_le32(sg_dma_len(os_sgl));
                        mfi_sgl->sge_skinny[i].phys_addr =
-                                               sg_dma_address(os_sgl);
-                       mfi_sgl->sge_skinny[i].flag = 0;
+                               cpu_to_le64(sg_dma_address(os_sgl));
+                       mfi_sgl->sge_skinny[i].flag = cpu_to_le32(0);
                }
        }
        return sge_count;
@@ -1155,8 +1159,8 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
        pthru->cdb_len = scp->cmd_len;
        pthru->timeout = 0;
        pthru->pad_0 = 0;
-       pthru->flags = flags;
-       pthru->data_xfer_len = scsi_bufflen(scp);
+       pthru->flags = cpu_to_le16(flags);
+       pthru->data_xfer_len = cpu_to_le32(scsi_bufflen(scp));
 
        memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
 
@@ -1168,18 +1172,18 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
                if ((scp->request->timeout / HZ) > 0xFFFF)
                        pthru->timeout = 0xFFFF;
                else
-                       pthru->timeout = scp->request->timeout / HZ;
+                       pthru->timeout = cpu_to_le16(scp->request->timeout / HZ);
        }
 
        /*
         * Construct SGL
         */
        if (instance->flag_ieee == 1) {
-               pthru->flags |= MFI_FRAME_SGL64;
+               pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64);
                pthru->sge_count = megasas_make_sgl_skinny(instance, scp,
                                                      &pthru->sgl);
        } else if (IS_DMA64) {
-               pthru->flags |= MFI_FRAME_SGL64;
+               pthru->flags |= cpu_to_le16(MFI_FRAME_SGL64);
                pthru->sge_count = megasas_make_sgl64(instance, scp,
                                                      &pthru->sgl);
        } else
@@ -1196,8 +1200,10 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
         * Sense info specific
         */
        pthru->sense_len = SCSI_SENSE_BUFFERSIZE;
-       pthru->sense_buf_phys_addr_hi = 0;
-       pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
+       pthru->sense_buf_phys_addr_hi =
+               cpu_to_le32(upper_32_bits(cmd->sense_phys_addr));
+       pthru->sense_buf_phys_addr_lo =
+               cpu_to_le32(lower_32_bits(cmd->sense_phys_addr));
 
        /*
         * Compute the total number of frames this command consumes. FW uses
@@ -1248,7 +1254,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
        ldio->timeout = 0;
        ldio->reserved_0 = 0;
        ldio->pad_0 = 0;
-       ldio->flags = flags;
+       ldio->flags = cpu_to_le16(flags);
        ldio->start_lba_hi = 0;
        ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0;
 
@@ -1256,52 +1262,59 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
         * 6-byte READ(0x08) or WRITE(0x0A) cdb
         */
        if (scp->cmd_len == 6) {
-               ldio->lba_count = (u32) scp->cmnd[4];
-               ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) |
-                   ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3];
+               ldio->lba_count = cpu_to_le32((u32) scp->cmnd[4]);
+               ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[1] << 16) |
+                                                ((u32) scp->cmnd[2] << 8) |
+                                                (u32) scp->cmnd[3]);
 
-               ldio->start_lba_lo &= 0x1FFFFF;
+               ldio->start_lba_lo &= cpu_to_le32(0x1FFFFF);
        }
 
        /*
         * 10-byte READ(0x28) or WRITE(0x2A) cdb
         */
        else if (scp->cmd_len == 10) {
-               ldio->lba_count = (u32) scp->cmnd[8] |
-                   ((u32) scp->cmnd[7] << 8);
-               ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
-                   ((u32) scp->cmnd[3] << 16) |
-                   ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+               ldio->lba_count = cpu_to_le32((u32) scp->cmnd[8] |
+                                             ((u32) scp->cmnd[7] << 8));
+               ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
+                                                ((u32) scp->cmnd[3] << 16) |
+                                                ((u32) scp->cmnd[4] << 8) |
+                                                (u32) scp->cmnd[5]);
        }
 
        /*
         * 12-byte READ(0xA8) or WRITE(0xAA) cdb
         */
        else if (scp->cmd_len == 12) {
-               ldio->lba_count = ((u32) scp->cmnd[6] << 24) |
-                   ((u32) scp->cmnd[7] << 16) |
-                   ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+               ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[6] << 24) |
+                                             ((u32) scp->cmnd[7] << 16) |
+                                             ((u32) scp->cmnd[8] << 8) |
+                                             (u32) scp->cmnd[9]);
 
-               ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) |
-                   ((u32) scp->cmnd[3] << 16) |
-                   ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+               ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
+                                                ((u32) scp->cmnd[3] << 16) |
+                                                ((u32) scp->cmnd[4] << 8) |
+                                                (u32) scp->cmnd[5]);
        }
 
        /*
         * 16-byte READ(0x88) or WRITE(0x8A) cdb
         */
        else if (scp->cmd_len == 16) {
-               ldio->lba_count = ((u32) scp->cmnd[10] << 24) |
-                   ((u32) scp->cmnd[11] << 16) |
-                   ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13];
+               ldio->lba_count = cpu_to_le32(((u32) scp->cmnd[10] << 24) |
+                                             ((u32) scp->cmnd[11] << 16) |
+                                             ((u32) scp->cmnd[12] << 8) |
+                                             (u32) scp->cmnd[13]);
 
-               ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) |
-                   ((u32) scp->cmnd[7] << 16) |
-                   ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9];
+               ldio->start_lba_lo = cpu_to_le32(((u32) scp->cmnd[6] << 24) |
+                                                ((u32) scp->cmnd[7] << 16) |
+                                                ((u32) scp->cmnd[8] << 8) |
+                                                (u32) scp->cmnd[9]);
 
-               ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) |
-                   ((u32) scp->cmnd[3] << 16) |
-                   ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5];
+               ldio->start_lba_hi = cpu_to_le32(((u32) scp->cmnd[2] << 24) |
+                                                ((u32) scp->cmnd[3] << 16) |
+                                                ((u32) scp->cmnd[4] << 8) |
+                                                (u32) scp->cmnd[5]);
 
        }
 
@@ -1309,11 +1322,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
         * Construct SGL
         */
        if (instance->flag_ieee) {
-               ldio->flags |= MFI_FRAME_SGL64;
+               ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64);
                ldio->sge_count = megasas_make_sgl_skinny(instance, scp,
                                              &ldio->sgl);
        } else if (IS_DMA64) {
-               ldio->flags |= MFI_FRAME_SGL64;
+               ldio->flags |= cpu_to_le16(MFI_FRAME_SGL64);
                ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
        } else
                ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl);
@@ -1329,7 +1342,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
         */
        ldio->sense_len = SCSI_SENSE_BUFFERSIZE;
        ldio->sense_buf_phys_addr_hi = 0;
-       ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
+       ldio->sense_buf_phys_addr_lo = cpu_to_le32(cmd->sense_phys_addr);
 
        /*
         * Compute the total number of frames this command consumes. FW uses
@@ -1400,20 +1413,32 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
                        ldio = (struct megasas_io_frame *)cmd->frame;
                        mfi_sgl = &ldio->sgl;
                        sgcount = ldio->sge_count;
-                       printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+                       printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x,"
+                       " lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
+                       instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id,
+                       le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi),
+                       le32_to_cpu(ldio->sense_buf_phys_addr_lo), sgcount);
                }
                else {
                        pthru = (struct megasas_pthru_frame *) cmd->frame;
                        mfi_sgl = &pthru->sgl;
                        sgcount = pthru->sge_count;
-                       printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+                       printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, "
+                       "lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",
+                       instance->host->host_no, cmd->frame_count, pthru->cmd, pthru->target_id,
+                       pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len),
+                       le32_to_cpu(pthru->sense_buf_phys_addr_lo), sgcount);
                }
        if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
                for (n = 0; n < sgcount; n++){
                        if (IS_DMA64)
-                               printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+                               printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%llx ",
+                                       le32_to_cpu(mfi_sgl->sge64[n].length),
+                                       le64_to_cpu(mfi_sgl->sge64[n].phys_addr));
                        else
-                               printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+                               printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",
+                                       le32_to_cpu(mfi_sgl->sge32[n].length),
+                                       le32_to_cpu(mfi_sgl->sge32[n].phys_addr));
                        }
                }
                printk(KERN_ERR "\n");
@@ -1674,11 +1699,11 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
 
        spin_lock_irqsave(&instance->completion_lock, flags);
 
-       producer = *instance->producer;
-       consumer = *instance->consumer;
+       producer = le32_to_cpu(*instance->producer);
+       consumer = le32_to_cpu(*instance->consumer);
 
        while (consumer != producer) {
-               context = instance->reply_queue[consumer];
+               context = le32_to_cpu(instance->reply_queue[consumer]);
                if (context >= instance->max_fw_cmds) {
                        printk(KERN_ERR "Unexpected context value %x\n",
                                context);
@@ -1695,7 +1720,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
                }
        }
 
-       *instance->consumer = producer;
+       *instance->consumer = cpu_to_le32(producer);
 
        spin_unlock_irqrestore(&instance->completion_lock, flags);
 
@@ -1716,7 +1741,7 @@ void megasas_do_ocr(struct megasas_instance *instance)
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
        (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
        (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
-               *instance->consumer     = MEGASAS_ADPRESET_INPROG_SIGN;
+               *instance->consumer = cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
        }
        instance->instancet->disable_intr(instance);
        instance->adprecovery   = MEGASAS_ADPRESET_SM_INFAULT;
@@ -2186,6 +2211,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
        struct megasas_header *hdr = &cmd->frame->hdr;
        unsigned long flags;
        struct fusion_context *fusion = instance->ctrl_context;
+       u32 opcode;
 
        /* flag for the retry reset */
        cmd->retry_for_fw_reset = 0;
@@ -2287,9 +2313,10 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
        case MFI_CMD_SMP:
        case MFI_CMD_STP:
        case MFI_CMD_DCMD:
+               opcode = le32_to_cpu(cmd->frame->dcmd.opcode);
                /* Check for LD map update */
-               if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) &&
-                   (cmd->frame->dcmd.mbox.b[1] == 1)) {
+               if ((opcode == MR_DCMD_LD_MAP_GET_INFO)
+                       && (cmd->frame->dcmd.mbox.b[1] == 1)) {
                        fusion->fast_path_io = 0;
                        spin_lock_irqsave(instance->host->host_lock, flags);
                        if (cmd->frame->hdr.cmd_status != 0) {
@@ -2323,8 +2350,8 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                                               flags);
                        break;
                }
-               if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
-                       cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) {
+               if (opcode == MR_DCMD_CTRL_EVENT_GET_INFO ||
+                   opcode == MR_DCMD_CTRL_EVENT_GET) {
                        spin_lock_irqsave(&poll_aen_lock, flags);
                        megasas_poll_wait_aen = 0;
                        spin_unlock_irqrestore(&poll_aen_lock, flags);
@@ -2333,7 +2360,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
                /*
                 * See if got an event notification
                 */
-               if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT)
+               if (opcode == MR_DCMD_CTRL_EVENT_WAIT)
                        megasas_service_aen(instance, cmd);
                else
                        megasas_complete_int_cmd(instance, cmd);
@@ -2606,7 +2633,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance,
                                        PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
 
                                *instance->consumer =
-                                       MEGASAS_ADPRESET_INPROG_SIGN;
+                                       cpu_to_le32(MEGASAS_ADPRESET_INPROG_SIGN);
                        }
 
 
@@ -2983,7 +3010,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
                }
 
                memset(cmd->frame, 0, total_sz);
-               cmd->frame->io.context = cmd->index;
+               cmd->frame->io.context = cpu_to_le32(cmd->index);
                cmd->frame->io.pad_0 = 0;
                if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
                    (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
@@ -3143,13 +3170,13 @@ megasas_get_pd_list(struct megasas_instance *instance)
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0xFF;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
-       dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
-       dcmd->opcode = MR_DCMD_PD_LIST_QUERY;
-       dcmd->sgl.sge32[0].phys_addr = ci_h;
-       dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST);
+       dcmd->data_xfer_len = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_PD_LIST_QUERY);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST));
 
        if (!megasas_issue_polled(instance, cmd)) {
                ret = 0;
@@ -3164,16 +3191,16 @@ megasas_get_pd_list(struct megasas_instance *instance)
        pd_addr = ci->addr;
 
        if ( ret == 0 &&
-               (ci->count <
+            (le32_to_cpu(ci->count) <
                  (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) {
 
                memset(instance->pd_list, 0,
                        MEGASAS_MAX_PD * sizeof(struct megasas_pd_list));
 
-               for (pd_index = 0; pd_index < ci->count; pd_index++) {
+               for (pd_index = 0; pd_index < le32_to_cpu(ci->count); pd_index++) {
 
                        instance->pd_list[pd_addr->deviceId].tid        =
-                                                       pd_addr->deviceId;
+                               le16_to_cpu(pd_addr->deviceId);
                        instance->pd_list[pd_addr->deviceId].driveType  =
                                                        pd_addr->scsiDevType;
                        instance->pd_list[pd_addr->deviceId].driveState =
@@ -3207,6 +3234,7 @@ megasas_get_ld_list(struct megasas_instance *instance)
        struct megasas_dcmd_frame *dcmd;
        struct MR_LD_LIST *ci;
        dma_addr_t ci_h = 0;
+       u32 ld_count;
 
        cmd = megasas_get_cmd(instance);
 
@@ -3233,12 +3261,12 @@ megasas_get_ld_list(struct megasas_instance *instance)
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0xFF;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
        dcmd->timeout = 0;
-       dcmd->data_xfer_len = sizeof(struct MR_LD_LIST);
-       dcmd->opcode = MR_DCMD_LD_GET_LIST;
-       dcmd->sgl.sge32[0].phys_addr = ci_h;
-       dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST);
+       dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_LIST));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_LD_GET_LIST);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_LD_LIST));
        dcmd->pad_0  = 0;
 
        if (!megasas_issue_polled(instance, cmd)) {
@@ -3247,12 +3275,14 @@ megasas_get_ld_list(struct megasas_instance *instance)
                ret = -1;
        }
 
+       ld_count = le32_to_cpu(ci->ldCount);
+
        /* the following function will get the instance PD LIST */
 
-       if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) {
+       if ((ret == 0) && (ld_count <= MAX_LOGICAL_DRIVES)) {
                memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
 
-               for (ld_index = 0; ld_index < ci->ldCount; ld_index++) {
+               for (ld_index = 0; ld_index < ld_count; ld_index++) {
                        if (ci->ldList[ld_index].state != 0) {
                                ids = ci->ldList[ld_index].ref.targetId;
                                instance->ld_ids[ids] =
@@ -3270,6 +3300,87 @@ megasas_get_ld_list(struct megasas_instance *instance)
        return ret;
 }
 
+/**
+ * megasas_ld_list_query -     Returns FW's ld_list structure
+ * @instance:                          Adapter soft state
+ * @ld_list:                           ld_list structure
+ *
+ * Issues an internal command (DCMD) to get the FW's controller PD
+ * list structure.  This information is mainly used to find out SYSTEM
+ * supported by the FW.
+ */
+static int
+megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
+{
+       int ret = 0, ld_index = 0, ids = 0;
+       struct megasas_cmd *cmd;
+       struct megasas_dcmd_frame *dcmd;
+       struct MR_LD_TARGETID_LIST *ci;
+       dma_addr_t ci_h = 0;
+       u32 tgtid_count;
+
+       cmd = megasas_get_cmd(instance);
+
+       if (!cmd) {
+               printk(KERN_WARNING
+                      "megasas:(megasas_ld_list_query): Failed to get cmd\n");
+               return -ENOMEM;
+       }
+
+       dcmd = &cmd->frame->dcmd;
+
+       ci = pci_alloc_consistent(instance->pdev,
+                                 sizeof(struct MR_LD_TARGETID_LIST), &ci_h);
+
+       if (!ci) {
+               printk(KERN_WARNING
+                      "megasas: Failed to alloc mem for ld_list_query\n");
+               megasas_return_cmd(instance, cmd);
+               return -ENOMEM;
+       }
+
+       memset(ci, 0, sizeof(*ci));
+       memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+
+       dcmd->mbox.b[0] = query_type;
+
+       dcmd->cmd = MFI_CMD_DCMD;
+       dcmd->cmd_status = 0xFF;
+       dcmd->sge_count = 1;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+       dcmd->timeout = 0;
+       dcmd->data_xfer_len = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_LD_LIST_QUERY);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_LD_TARGETID_LIST));
+       dcmd->pad_0  = 0;
+
+       if (!megasas_issue_polled(instance, cmd) && !dcmd->cmd_status) {
+               ret = 0;
+       } else {
+               /* On failure, call older LD list DCMD */
+               ret = 1;
+       }
+
+       tgtid_count = le32_to_cpu(ci->count);
+
+       if ((ret == 0) && (tgtid_count <= (MAX_LOGICAL_DRIVES))) {
+               memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
+               for (ld_index = 0; ld_index < tgtid_count; ld_index++) {
+                       ids = ci->targetId[ld_index];
+                       instance->ld_ids[ids] = ci->targetId[ld_index];
+               }
+
+       }
+
+       pci_free_consistent(instance->pdev, sizeof(struct MR_LD_TARGETID_LIST),
+                           ci, ci_h);
+
+       megasas_return_cmd(instance, cmd);
+
+       return ret;
+}
+
 /**
  * megasas_get_controller_info -       Returns FW's controller structure
  * @instance:                          Adapter soft state
@@ -3313,13 +3424,13 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0xFF;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
-       dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info);
-       dcmd->opcode = MR_DCMD_CTRL_GET_INFO;
-       dcmd->sgl.sge32[0].phys_addr = ci_h;
-       dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info);
+       dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_ctrl_info));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_GET_INFO);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_ctrl_info));
 
        if (!megasas_issue_polled(instance, cmd)) {
                ret = 0;
@@ -3375,17 +3486,20 @@ megasas_issue_init_mfi(struct megasas_instance *instance)
        memset(initq_info, 0, sizeof(struct megasas_init_queue_info));
        init_frame->context = context;
 
-       initq_info->reply_queue_entries = instance->max_fw_cmds + 1;
-       initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h;
+       initq_info->reply_queue_entries = cpu_to_le32(instance->max_fw_cmds + 1);
+       initq_info->reply_queue_start_phys_addr_lo = cpu_to_le32(instance->reply_queue_h);
 
-       initq_info->producer_index_phys_addr_lo = instance->producer_h;
-       initq_info->consumer_index_phys_addr_lo = instance->consumer_h;
+       initq_info->producer_index_phys_addr_lo = cpu_to_le32(instance->producer_h);
+       initq_info->consumer_index_phys_addr_lo = cpu_to_le32(instance->consumer_h);
 
        init_frame->cmd = MFI_CMD_INIT;
        init_frame->cmd_status = 0xFF;
-       init_frame->queue_info_new_phys_addr_lo = initq_info_h;
+       init_frame->queue_info_new_phys_addr_lo =
+               cpu_to_le32(lower_32_bits(initq_info_h));
+       init_frame->queue_info_new_phys_addr_hi =
+               cpu_to_le32(upper_32_bits(initq_info_h));
 
-       init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info);
+       init_frame->data_xfer_len = cpu_to_le32(sizeof(struct megasas_init_queue_info));
 
        /*
         * disable the intr before firing the init frame to FW
@@ -3648,7 +3762,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
        megasas_get_pd_list(instance);
 
        memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
-       megasas_get_ld_list(instance);
+       if (megasas_ld_list_query(instance,
+                                 MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+               megasas_get_ld_list(instance);
 
        ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL);
 
@@ -3665,8 +3781,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
        if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) {
 
                max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) *
-                   ctrl_info->max_strips_per_io;
-               max_sectors_2 = ctrl_info->max_request_size;
+                       le16_to_cpu(ctrl_info->max_strips_per_io);
+               max_sectors_2 = le32_to_cpu(ctrl_info->max_request_size);
 
                tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2);
 
@@ -3675,14 +3791,18 @@ static int megasas_init_fw(struct megasas_instance *instance)
                        instance->is_imr = 0;
                        dev_info(&instance->pdev->dev, "Controller type: MR,"
                                "Memory size is: %dMB\n",
-                               ctrl_info->memory_size);
+                               le16_to_cpu(ctrl_info->memory_size));
                } else {
                        instance->is_imr = 1;
                        dev_info(&instance->pdev->dev,
                                "Controller type: iMR\n");
                }
+               /* OnOffProperties are converted into CPU arch*/
+               le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
                instance->disableOnlineCtrlReset =
                ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
+               /* adapterOperations2 are converted into CPU arch*/
+               le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
                instance->UnevenSpanSupport =
                        ctrl_info->adapterOperations2.supportUnevenSpans;
                if (instance->UnevenSpanSupport) {
@@ -3696,7 +3816,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
 
                }
        }
-
        instance->max_sectors_per_req = instance->max_num_sge *
                                                PAGE_SIZE / 512;
        if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
@@ -3802,20 +3921,24 @@ megasas_get_seq_num(struct megasas_instance *instance,
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0x0;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
-       dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info);
-       dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO;
-       dcmd->sgl.sge32[0].phys_addr = el_info_h;
-       dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_log_info);
+       dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_log_info));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_GET_INFO);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(el_info_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_log_info));
 
        megasas_issue_blocked_cmd(instance, cmd);
 
        /*
         * Copy the data back into callers buffer
         */
-       memcpy(eli, el_info, sizeof(struct megasas_evt_log_info));
+       eli->newest_seq_num = le32_to_cpu(el_info->newest_seq_num);
+       eli->oldest_seq_num = le32_to_cpu(el_info->oldest_seq_num);
+       eli->clear_seq_num = le32_to_cpu(el_info->clear_seq_num);
+       eli->shutdown_seq_num = le32_to_cpu(el_info->shutdown_seq_num);
+       eli->boot_seq_num = le32_to_cpu(el_info->boot_seq_num);
 
        pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info),
                            el_info, el_info_h);
@@ -3862,6 +3985,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        if (instance->aen_cmd) {
 
                prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1];
+               prev_aen.members.locale = le16_to_cpu(prev_aen.members.locale);
 
                /*
                 * A class whose enum value is smaller is inclusive of all
@@ -3874,7 +3998,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
                 * values
                 */
                if ((prev_aen.members.class <= curr_aen.members.class) &&
-                   !((prev_aen.members.locale & curr_aen.members.locale) ^
+                   !((le16_to_cpu(prev_aen.members.locale) & curr_aen.members.locale) ^
                      curr_aen.members.locale)) {
                        /*
                         * Previously issued event registration includes
@@ -3882,7 +4006,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
                         */
                        return 0;
                } else {
-                       curr_aen.members.locale |= prev_aen.members.locale;
+                       curr_aen.members.locale |= le16_to_cpu(prev_aen.members.locale);
 
                        if (prev_aen.members.class < curr_aen.members.class)
                                curr_aen.members.class = prev_aen.members.class;
@@ -3917,16 +4041,16 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num,
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0x0;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
+       dcmd->data_xfer_len = cpu_to_le32(sizeof(struct megasas_evt_detail));
+       dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_EVENT_WAIT);
+       dcmd->mbox.w[0] = cpu_to_le32(seq_num);
        instance->last_seq_num = seq_num;
-       dcmd->data_xfer_len = sizeof(struct megasas_evt_detail);
-       dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT;
-       dcmd->mbox.w[0] = seq_num;
-       dcmd->mbox.w[1] = curr_aen.word;
-       dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h;
-       dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail);
+       dcmd->mbox.w[1] = cpu_to_le32(curr_aen.word);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->evt_detail_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct megasas_evt_detail));
 
        if (instance->aen_cmd != NULL) {
                megasas_return_cmd(instance, cmd);
@@ -3972,8 +4096,9 @@ static int megasas_start_aen(struct megasas_instance *instance)
        class_locale.members.locale = MR_EVT_LOCALE_ALL;
        class_locale.members.class = MR_EVT_CLASS_DEBUG;
 
-       return megasas_register_aen(instance, eli.newest_seq_num + 1,
-                                   class_locale.word);
+       return megasas_register_aen(instance,
+                       le32_to_cpu(eli.newest_seq_num) + 1,
+                       class_locale.word);
 }
 
 /**
@@ -4068,6 +4193,7 @@ megasas_set_dma_mask(struct pci_dev *pdev)
                if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)
                        goto fail_set_dma_mask;
        }
+
        return 0;
 
 fail_set_dma_mask:
@@ -4386,11 +4512,11 @@ static void megasas_flush_cache(struct megasas_instance *instance)
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0x0;
        dcmd->sge_count = 0;
-       dcmd->flags = MFI_FRAME_DIR_NONE;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
        dcmd->data_xfer_len = 0;
-       dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH;
+       dcmd->opcode = cpu_to_le32(MR_DCMD_CTRL_CACHE_FLUSH);
        dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE;
 
        megasas_issue_blocked_cmd(instance, cmd);
@@ -4431,11 +4557,11 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0x0;
        dcmd->sge_count = 0;
-       dcmd->flags = MFI_FRAME_DIR_NONE;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_NONE);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
        dcmd->data_xfer_len = 0;
-       dcmd->opcode = opcode;
+       dcmd->opcode = cpu_to_le32(opcode);
 
        megasas_issue_blocked_cmd(instance, cmd);
 
@@ -4850,10 +4976,11 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
         * alone separately
         */
        memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE);
-       cmd->frame->hdr.context = cmd->index;
+       cmd->frame->hdr.context = cpu_to_le32(cmd->index);
        cmd->frame->hdr.pad_0 = 0;
-       cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 |
-                                  MFI_FRAME_SENSE64);
+       cmd->frame->hdr.flags &= cpu_to_le16(~(MFI_FRAME_IEEE |
+                                              MFI_FRAME_SGL64 |
+                                              MFI_FRAME_SENSE64));
 
        /*
         * The management interface between applications and the fw uses
@@ -4887,8 +5014,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
                 * We don't change the dma_coherent_mask, so
                 * pci_alloc_consistent only returns 32bit addresses
                 */
-               kern_sge32[i].phys_addr = (u32) buf_handle;
-               kern_sge32[i].length = ioc->sgl[i].iov_len;
+               kern_sge32[i].phys_addr = cpu_to_le32(buf_handle);
+               kern_sge32[i].length = cpu_to_le32(ioc->sgl[i].iov_len);
 
                /*
                 * We created a kernel buffer corresponding to the
@@ -4911,7 +5038,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
 
                sense_ptr =
                (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off);
-               *sense_ptr = sense_handle;
+               *sense_ptr = cpu_to_le32(sense_handle);
        }
 
        /*
@@ -4971,9 +5098,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
        for (i = 0; i < ioc->sge_count; i++) {
                if (kbuff_arr[i])
                        dma_free_coherent(&instance->pdev->dev,
-                                         kern_sge32[i].length,
+                                         le32_to_cpu(kern_sge32[i].length),
                                          kbuff_arr[i],
-                                         kern_sge32[i].phys_addr);
+                                         le32_to_cpu(kern_sge32[i].phys_addr));
        }
 
        megasas_return_cmd(instance, cmd);
@@ -5327,7 +5454,7 @@ megasas_aen_polling(struct work_struct *work)
        host = instance->host;
        if (instance->evt_detail) {
 
-               switch (instance->evt_detail->code) {
+               switch (le32_to_cpu(instance->evt_detail->code)) {
                case MR_EVT_PD_INSERTED:
                        if (megasas_get_pd_list(instance) == 0) {
                        for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) {
@@ -5389,7 +5516,9 @@ megasas_aen_polling(struct work_struct *work)
                case MR_EVT_LD_OFFLINE:
                case MR_EVT_CFG_CLEARED:
                case MR_EVT_LD_DELETED:
-                       megasas_get_ld_list(instance);
+                       if (megasas_ld_list_query(instance,
+                                       MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+                               megasas_get_ld_list(instance);
                        for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
                                for (j = 0;
                                j < MEGASAS_MAX_DEV_PER_CHANNEL;
@@ -5399,7 +5528,7 @@ megasas_aen_polling(struct work_struct *work)
                                (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
 
                                sdev1 = scsi_device_lookup(host,
-                                       i + MEGASAS_MAX_LD_CHANNELS,
+                                       MEGASAS_MAX_PD_CHANNELS + i,
                                        j,
                                        0);
 
@@ -5418,7 +5547,9 @@ megasas_aen_polling(struct work_struct *work)
                        doscan = 0;
                        break;
                case MR_EVT_LD_CREATED:
-                       megasas_get_ld_list(instance);
+                       if (megasas_ld_list_query(instance,
+                                       MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+                               megasas_get_ld_list(instance);
                        for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
                                for (j = 0;
                                        j < MEGASAS_MAX_DEV_PER_CHANNEL;
@@ -5427,14 +5558,14 @@ megasas_aen_polling(struct work_struct *work)
                                        (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
 
                                        sdev1 = scsi_device_lookup(host,
-                                               i+MEGASAS_MAX_LD_CHANNELS,
+                                               MEGASAS_MAX_PD_CHANNELS + i,
                                                j, 0);
 
                                        if (instance->ld_ids[ld_index] !=
                                                                0xff) {
                                                if (!sdev1) {
                                                        scsi_add_device(host,
-                                                               i + 2,
+                                               MEGASAS_MAX_PD_CHANNELS + i,
                                                                j, 0);
                                                }
                                        }
@@ -5483,18 +5614,20 @@ megasas_aen_polling(struct work_struct *work)
                        }
                }
 
-               megasas_get_ld_list(instance);
+               if (megasas_ld_list_query(instance,
+                                         MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
+                       megasas_get_ld_list(instance);
                for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) {
                        for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) {
                                ld_index =
                                (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j;
 
                                sdev1 = scsi_device_lookup(host,
-                                       i+MEGASAS_MAX_LD_CHANNELS, j, 0);
+                                       MEGASAS_MAX_PD_CHANNELS + i, j, 0);
                                if (instance->ld_ids[ld_index] != 0xff) {
                                        if (!sdev1) {
                                                scsi_add_device(host,
-                                                               i+2,
+                                               MEGASAS_MAX_PD_CHANNELS + i,
                                                                j, 0);
                                        } else {
                                                scsi_device_put(sdev1);
@@ -5514,7 +5647,7 @@ megasas_aen_polling(struct work_struct *work)
                return ;
        }
 
-       seq_num = instance->evt_detail->seq_num + 1;
+       seq_num = le32_to_cpu(instance->evt_detail->seq_num) + 1;
 
        /* Register AEN with FW for latest sequence number plus 1 */
        class_locale.members.reserved = 0;
index 4f401f753f8e98b11532df1bcfd7ea1efa6c7d87..e24b6eb645b5740d78cc50b987d38b7e881491c0 100644 (file)
@@ -126,17 +126,17 @@ static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map)
        return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx];
 }
 
-static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
+u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map)
 {
-       return map->raidMap.arMapInfo[ar].pd[arm];
+       return le16_to_cpu(map->raidMap.arMapInfo[ar].pd[arm]);
 }
 
-static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
+u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map)
 {
-       return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef;
+       return le16_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef);
 }
 
-static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
+u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map)
 {
        return map->raidMap.devHndlInfo[pd].curDevHdl;
 }
@@ -148,7 +148,7 @@ u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map)
 
 u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map)
 {
-       return map->raidMap.ldTgtIdToLd[ldTgtId];
+       return le16_to_cpu(map->raidMap.ldTgtIdToLd[ldTgtId]);
 }
 
 static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span,
@@ -167,18 +167,22 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
        struct LD_LOAD_BALANCE_INFO *lbInfo = fusion->load_balance_info;
        PLD_SPAN_INFO ldSpanInfo = fusion->log_to_span;
        struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap;
+       struct MR_LD_RAID         *raid;
+       int ldCount, num_lds;
+       u16 ld;
+
 
-       if (pFwRaidMap->totalSize !=
+       if (le32_to_cpu(pFwRaidMap->totalSize) !=
            (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) +
-            (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) {
+            (sizeof(struct MR_LD_SPAN_MAP) * le32_to_cpu(pFwRaidMap->ldCount)))) {
                printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n",
                       (unsigned int)((sizeof(struct MR_FW_RAID_MAP) -
                                       sizeof(struct MR_LD_SPAN_MAP)) +
                                      (sizeof(struct MR_LD_SPAN_MAP) *
-                                      pFwRaidMap->ldCount)));
+                                       le32_to_cpu(pFwRaidMap->ldCount))));
                printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize "
                       ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP),
-                      pFwRaidMap->totalSize);
+                       le32_to_cpu(pFwRaidMap->totalSize));
                return 0;
        }
 
@@ -187,6 +191,15 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
 
        mr_update_load_balance_params(map, lbInfo);
 
+       num_lds = le32_to_cpu(map->raidMap.ldCount);
+
+       /*Convert Raid capability values to CPU arch */
+       for (ldCount = 0; ldCount < num_lds; ldCount++) {
+               ld = MR_TargetIdToLdGet(ldCount, map);
+               raid = MR_LdRaidGet(ld, map);
+               le32_to_cpus((u32 *)&raid->capability);
+       }
+
        return 1;
 }
 
@@ -200,23 +213,20 @@ u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk,
 
        for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) {
 
-               for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) {
+               for (j = 0; j < le32_to_cpu(pSpanBlock->block_span_info.noElements); j++) {
                        quad = &pSpanBlock->block_span_info.quad[j];
 
-                       if (quad->diff == 0)
+                       if (le32_to_cpu(quad->diff) == 0)
                                return SPAN_INVALID;
-                       if (quad->logStart <= row  &&  row <= quad->logEnd  &&
-                           (mega_mod64(row-quad->logStart, quad->diff)) == 0) {
+                       if (le64_to_cpu(quad->logStart) <= row && row <=
+                               le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart),
+                               le32_to_cpu(quad->diff))) == 0) {
                                if (span_blk != NULL) {
                                        u64  blk, debugBlk;
-                                       blk =
-                                               mega_div64_32(
-                                                       (row-quad->logStart),
-                                                       quad->diff);
+                                       blk =  mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff));
                                        debugBlk = blk;
 
-                                       blk = (blk + quad->offsetInSpan) <<
-                                               raid->stripeShift;
+                                       blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift;
                                        *span_blk = blk;
                                }
                                return span;
@@ -257,8 +267,8 @@ static int getSpanInfo(struct MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
                for (span = 0; span < raid->spanDepth; span++)
                        dev_dbg(&instance->pdev->dev, "Span=%x,"
                        " number of quads=%x\n", span,
-                       map->raidMap.ldSpanMap[ld].spanBlock[span].
-                       block_span_info.noElements);
+                       le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                       block_span_info.noElements));
                for (element = 0; element < MAX_QUAD_DEPTH; element++) {
                        span_set = &(ldSpanInfo[ld].span_set[element]);
                        if (span_set->span_row_data_width == 0)
@@ -286,22 +296,22 @@ static int getSpanInfo(struct MR_FW_RAID_MAP_ALL *map, PLD_SPAN_INFO ldSpanInfo)
                                (long unsigned int)span_set->data_strip_end);
 
                        for (span = 0; span < raid->spanDepth; span++) {
-                               if (map->raidMap.ldSpanMap[ld].spanBlock[span].
-                                       block_span_info.noElements >=
+                               if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                                       block_span_info.noElements) >=
                                        element + 1) {
                                        quad = &map->raidMap.ldSpanMap[ld].
                                                spanBlock[span].block_span_info.
                                                quad[element];
                                dev_dbg(&instance->pdev->dev, "Span=%x,"
                                        "Quad=%x, diff=%x\n", span,
-                                       element, quad->diff);
+                                       element, le32_to_cpu(quad->diff));
                                dev_dbg(&instance->pdev->dev,
                                        "offset_in_span=0x%08lx\n",
-                                       (long unsigned int)quad->offsetInSpan);
+                                       (long unsigned int)le64_to_cpu(quad->offsetInSpan));
                                dev_dbg(&instance->pdev->dev,
                                        "logical start=0x%08lx, end=0x%08lx\n",
-                                       (long unsigned int)quad->logStart,
-                                       (long unsigned int)quad->logEnd);
+                                       (long unsigned int)le64_to_cpu(quad->logStart),
+                                       (long unsigned int)le64_to_cpu(quad->logEnd));
                                }
                        }
                }
@@ -348,23 +358,23 @@ u32 mr_spanset_get_span_block(struct megasas_instance *instance,
                        continue;
 
                for (span = 0; span < raid->spanDepth; span++)
-                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
-                               block_span_info.noElements >= info+1) {
+                       if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                               block_span_info.noElements) >= info+1) {
                                quad = &map->raidMap.ldSpanMap[ld].
                                        spanBlock[span].
                                        block_span_info.quad[info];
-                               if (quad->diff == 0)
+                               if (le32_to_cpu(quad->diff == 0))
                                        return SPAN_INVALID;
-                               if (quad->logStart <= row  &&
-                                       row <= quad->logEnd  &&
-                                       (mega_mod64(row - quad->logStart,
-                                               quad->diff)) == 0) {
+                               if (le64_to_cpu(quad->logStart) <= row  &&
+                                       row <= le64_to_cpu(quad->logEnd)  &&
+                                       (mega_mod64(row - le64_to_cpu(quad->logStart),
+                                               le32_to_cpu(quad->diff))) == 0) {
                                        if (span_blk != NULL) {
                                                u64  blk;
                                                blk = mega_div64_32
-                                                   ((row - quad->logStart),
-                                                   quad->diff);
-                                               blk = (blk + quad->offsetInSpan)
+                                                   ((row - le64_to_cpu(quad->logStart)),
+                                                   le32_to_cpu(quad->diff));
+                                               blk = (blk + le64_to_cpu(quad->offsetInSpan))
                                                         << raid->stripeShift;
                                                *span_blk = blk;
                                        }
@@ -415,8 +425,8 @@ static u64  get_row_from_strip(struct megasas_instance *instance,
                span_set_Row = mega_div64_32(span_set_Strip,
                                span_set->span_row_data_width) * span_set->diff;
                for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
-                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
-                               block_span_info.noElements >= info+1) {
+                       if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                               block_span_info.noElements >= info+1)) {
                                if (strip_offset >=
                                        span_set->strip_offset[span])
                                        span_offset++;
@@ -480,18 +490,18 @@ static u64 get_strip_from_row(struct megasas_instance *instance,
                        continue;
 
                for (span = 0; span < raid->spanDepth; span++)
-                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
-                               block_span_info.noElements >= info+1) {
+                       if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                               block_span_info.noElements) >= info+1) {
                                quad = &map->raidMap.ldSpanMap[ld].
                                        spanBlock[span].block_span_info.quad[info];
-                               if (quad->logStart <= row  &&
-                                       row <= quad->logEnd  &&
-                                       mega_mod64((row - quad->logStart),
-                                       quad->diff) == 0) {
+                               if (le64_to_cpu(quad->logStart) <= row  &&
+                                       row <= le64_to_cpu(quad->logEnd)  &&
+                                       mega_mod64((row - le64_to_cpu(quad->logStart)),
+                                       le32_to_cpu(quad->diff)) == 0) {
                                        strip = mega_div64_32
                                                (((row - span_set->data_row_start)
-                                                       - quad->logStart),
-                                                       quad->diff);
+                                                       - le64_to_cpu(quad->logStart)),
+                                                       le32_to_cpu(quad->diff));
                                        strip *= span_set->span_row_data_width;
                                        strip += span_set->data_strip_start;
                                        strip += span_set->strip_offset[span];
@@ -543,8 +553,8 @@ static u32 get_arm_from_strip(struct megasas_instance *instance,
                                span_set->span_row_data_width);
 
                for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
-                       if (map->raidMap.ldSpanMap[ld].spanBlock[span].
-                               block_span_info.noElements >= info+1) {
+                       if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                               block_span_info.noElements) >= info+1) {
                                if (strip_offset >=
                                        span_set->strip_offset[span])
                                        span_offset =
@@ -669,7 +679,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
                }
        }
 
-       *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
+       *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);
        pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
                                        physArm;
        return retval;
@@ -765,7 +775,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
                }
        }
 
-       *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk;
+       *pdBlock += stripRef + le64_to_cpu(MR_LdSpanPtrGet(ld, span, map)->startBlk);
        pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) |
                physArm;
        return retval;
@@ -784,7 +794,7 @@ u8
 MR_BuildRaidContext(struct megasas_instance *instance,
                    struct IO_REQUEST_INFO *io_info,
                    struct RAID_CONTEXT *pRAID_Context,
-                   struct MR_FW_RAID_MAP_ALL *map)
+                   struct MR_FW_RAID_MAP_ALL *map, u8 **raidLUN)
 {
        struct MR_LD_RAID  *raid;
        u32         ld, stripSize, stripe_mask;
@@ -965,7 +975,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                        regSize += stripSize;
        }
 
-       pRAID_Context->timeoutValue     = map->raidMap.fpPdIoTimeoutSec;
+       pRAID_Context->timeoutValue     = cpu_to_le16(map->raidMap.fpPdIoTimeoutSec);
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
                (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
                pRAID_Context->regLockFlags = (isRead) ?
@@ -974,9 +984,12 @@ MR_BuildRaidContext(struct megasas_instance *instance,
                pRAID_Context->regLockFlags = (isRead) ?
                        REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite;
        pRAID_Context->VirtualDiskTgtId = raid->targetId;
-       pRAID_Context->regLockRowLBA    = regStart;
-       pRAID_Context->regLockLength    = regSize;
+       pRAID_Context->regLockRowLBA    = cpu_to_le64(regStart);
+       pRAID_Context->regLockLength    = cpu_to_le32(regSize);
        pRAID_Context->configSeqNum     = raid->seqNum;
+       /* save pointer to raid->LUN array */
+       *raidLUN = raid->LUN;
+
 
        /*Get Phy Params only if FP capable, or else leave it to MR firmware
          to do the calculation.*/
@@ -1047,8 +1060,8 @@ void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
                raid = MR_LdRaidGet(ld, map);
                for (element = 0; element < MAX_QUAD_DEPTH; element++) {
                        for (span = 0; span < raid->spanDepth; span++) {
-                               if (map->raidMap.ldSpanMap[ld].spanBlock[span].
-                                       block_span_info.noElements <
+                               if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
+                                       block_span_info.noElements) <
                                        element + 1)
                                        continue;
                                span_set = &(ldSpanInfo[ld].span_set[element]);
@@ -1056,14 +1069,14 @@ void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
                                        spanBlock[span].block_span_info.
                                        quad[element];
 
-                               span_set->diff = quad->diff;
+                               span_set->diff = le32_to_cpu(quad->diff);
 
                                for (count = 0, span_row_width = 0;
                                        count < raid->spanDepth; count++) {
-                                       if (map->raidMap.ldSpanMap[ld].
+                                       if (le32_to_cpu(map->raidMap.ldSpanMap[ld].
                                                spanBlock[count].
                                                block_span_info.
-                                               noElements >= element + 1) {
+                                               noElements) >= element + 1) {
                                                span_set->strip_offset[count] =
                                                        span_row_width;
                                                span_row_width +=
@@ -1077,9 +1090,9 @@ void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
                                }
 
                                span_set->span_row_data_width = span_row_width;
-                               span_row = mega_div64_32(((quad->logEnd -
-                                       quad->logStart) + quad->diff),
-                                       quad->diff);
+                               span_row = mega_div64_32(((le64_to_cpu(quad->logEnd) -
+                                       le64_to_cpu(quad->logStart)) + le32_to_cpu(quad->diff)),
+                                       le32_to_cpu(quad->diff));
 
                                if (element == 0) {
                                        span_set->log_start_lba = 0;
@@ -1096,7 +1109,7 @@ void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
 
                                        span_set->data_row_start = 0;
                                        span_set->data_row_end =
-                                               (span_row * quad->diff) - 1;
+                                               (span_row * le32_to_cpu(quad->diff)) - 1;
                                } else {
                                        span_set_prev = &(ldSpanInfo[ld].
                                                        span_set[element - 1]);
@@ -1122,7 +1135,7 @@ void mr_update_span_set(struct MR_FW_RAID_MAP_ALL *map,
                                                span_set_prev->data_row_end + 1;
                                        span_set->data_row_end =
                                                span_set->data_row_start +
-                                               (span_row * quad->diff) - 1;
+                                               (span_row * le32_to_cpu(quad->diff)) - 1;
                                }
                                break;
                }
index 417d5f167aa2b2e4a001521b132436be87a78c87..f6555921fd7aa111eedc958d580eed9bbf9b848c 100644 (file)
@@ -72,17 +72,6 @@ megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs);
 int
 megasas_issue_polled(struct megasas_instance *instance,
                     struct megasas_cmd *cmd);
-
-u8
-MR_BuildRaidContext(struct megasas_instance *instance,
-                   struct IO_REQUEST_INFO *io_info,
-                   struct RAID_CONTEXT *pRAID_Context,
-                   struct MR_FW_RAID_MAP_ALL *map);
-u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map);
-struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
-
-u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map);
-
 void
 megasas_check_and_restore_queue_depth(struct megasas_instance *instance);
 
@@ -626,23 +615,20 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
 
        IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT;
        IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER;
-       IOCInitMessage->MsgVersion = MPI2_VERSION;
-       IOCInitMessage->HeaderVersion = MPI2_HEADER_VERSION;
-       IOCInitMessage->SystemRequestFrameSize =
-               MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4;
-
-       IOCInitMessage->ReplyDescriptorPostQueueDepth = fusion->reply_q_depth;
-       IOCInitMessage->ReplyDescriptorPostQueueAddress =
-               fusion->reply_frames_desc_phys;
-       IOCInitMessage->SystemRequestFrameBaseAddress =
-               fusion->io_request_frames_phys;
+       IOCInitMessage->MsgVersion = cpu_to_le16(MPI2_VERSION);
+       IOCInitMessage->HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
+       IOCInitMessage->SystemRequestFrameSize = cpu_to_le16(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4);
+
+       IOCInitMessage->ReplyDescriptorPostQueueDepth = cpu_to_le16(fusion->reply_q_depth);
+       IOCInitMessage->ReplyDescriptorPostQueueAddress = cpu_to_le64(fusion->reply_frames_desc_phys);
+       IOCInitMessage->SystemRequestFrameBaseAddress = cpu_to_le64(fusion->io_request_frames_phys);
        IOCInitMessage->HostMSIxVectors = instance->msix_vectors;
        init_frame = (struct megasas_init_frame *)cmd->frame;
        memset(init_frame, 0, MEGAMFI_FRAME_SIZE);
 
        frame_hdr = &cmd->frame->hdr;
        frame_hdr->cmd_status = 0xFF;
-       frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
+       frame_hdr->flags |= cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE);
 
        init_frame->cmd = MFI_CMD_INIT;
        init_frame->cmd_status = 0xFF;
@@ -652,17 +638,24 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
                (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
                init_frame->driver_operations.
                        mfi_capabilities.support_additional_msix = 1;
+       /* driver supports HA / Remote LUN over Fast Path interface */
+       init_frame->driver_operations.mfi_capabilities.support_fp_remote_lun
+               = 1;
+       /* Convert capability to LE32 */
+       cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
 
-       init_frame->queue_info_new_phys_addr_lo = ioc_init_handle;
-       init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST);
+       init_frame->queue_info_new_phys_addr_lo = cpu_to_le32((u32)ioc_init_handle);
+       init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
 
        req_desc =
          (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc;
 
-       req_desc->Words = cmd->frame_phys_addr;
+       req_desc->Words = 0;
        req_desc->MFAIo.RequestFlags =
                (MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
                 MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+       cpu_to_le32s((u32 *)&req_desc->MFAIo);
+       req_desc->Words |= cpu_to_le64(cmd->frame_phys_addr);
 
        /*
         * disable the intr before firing the init frame
@@ -753,13 +746,13 @@ megasas_get_ld_map_info(struct megasas_instance *instance)
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0xFF;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_READ;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
-       dcmd->data_xfer_len = size_map_info;
-       dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
-       dcmd->sgl.sge32[0].phys_addr = ci_h;
-       dcmd->sgl.sge32[0].length = size_map_info;
+       dcmd->data_xfer_len = cpu_to_le32(size_map_info);
+       dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(size_map_info);
 
        if (!megasas_issue_polled(instance, cmd))
                ret = 0;
@@ -828,7 +821,7 @@ megasas_sync_map_info(struct megasas_instance *instance)
 
        map = fusion->ld_map[instance->map_id & 1];
 
-       num_lds = map->raidMap.ldCount;
+       num_lds = le32_to_cpu(map->raidMap.ldCount);
 
        dcmd = &cmd->frame->dcmd;
 
@@ -856,15 +849,15 @@ megasas_sync_map_info(struct megasas_instance *instance)
        dcmd->cmd = MFI_CMD_DCMD;
        dcmd->cmd_status = 0xFF;
        dcmd->sge_count = 1;
-       dcmd->flags = MFI_FRAME_DIR_WRITE;
+       dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE);
        dcmd->timeout = 0;
        dcmd->pad_0 = 0;
-       dcmd->data_xfer_len = size_map_info;
+       dcmd->data_xfer_len = cpu_to_le32(size_map_info);
        dcmd->mbox.b[0] = num_lds;
        dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG;
-       dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO;
-       dcmd->sgl.sge32[0].phys_addr = ci_h;
-       dcmd->sgl.sge32[0].length = size_map_info;
+       dcmd->opcode = cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO);
+       dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(ci_h);
+       dcmd->sgl.sge32[0].length = cpu_to_le32(size_map_info);
 
        instance->map_update_cmd = cmd;
 
@@ -1067,9 +1060,8 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
 
        spin_lock_irqsave(&instance->hba_lock, flags);
 
-       writel(req_desc_lo,
-              &(regs)->inbound_low_queue_port);
-       writel(req_desc_hi, &(regs)->inbound_high_queue_port);
+       writel(le32_to_cpu(req_desc_lo), &(regs)->inbound_low_queue_port);
+       writel(le32_to_cpu(req_desc_hi), &(regs)->inbound_high_queue_port);
        spin_unlock_irqrestore(&instance->hba_lock, flags);
 }
 
@@ -1157,8 +1149,8 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                return sge_count;
 
        scsi_for_each_sg(scp, os_sgl, sge_count, i) {
-               sgl_ptr->Length = sg_dma_len(os_sgl);
-               sgl_ptr->Address = sg_dma_address(os_sgl);
+               sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl));
+               sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl));
                sgl_ptr->Flags = 0;
                if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
                        (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
@@ -1177,9 +1169,9 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                                PCI_DEVICE_ID_LSI_INVADER) ||
                                (instance->pdev->device ==
                                PCI_DEVICE_ID_LSI_FURY)) {
-                               if ((cmd->io_request->IoFlags &
-                               MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
-                               MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
+                               if ((le16_to_cpu(cmd->io_request->IoFlags) &
+                                       MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
+                                       MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
                                        cmd->io_request->ChainOffset =
                                                fusion->
                                                chain_offset_io_request;
@@ -1201,9 +1193,8 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
                                sg_chain->Flags =
                                        (IEEE_SGE_FLAGS_CHAIN_ELEMENT |
                                         MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR);
-                       sg_chain->Length =  (sizeof(union MPI2_SGE_IO_UNION)
-                                            *(sge_count - sg_processed));
-                       sg_chain->Address = cmd->sg_frame_phys_addr;
+                       sg_chain->Length =  cpu_to_le32((sizeof(union MPI2_SGE_IO_UNION) * (sge_count - sg_processed)));
+                       sg_chain->Address = cpu_to_le64(cmd->sg_frame_phys_addr);
 
                        sgl_ptr =
                          (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
@@ -1261,7 +1252,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
                io_request->CDB.EEDP32.PrimaryReferenceTag =
                        cpu_to_be32(ref_tag);
                io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
-               io_request->IoFlags = 32; /* Specify 32-byte cdb */
+               io_request->IoFlags = cpu_to_le16(32); /* Specify 32-byte cdb */
 
                /* Transfer length */
                cdb[28] = (u8)((num_blocks >> 24) & 0xff);
@@ -1271,19 +1262,19 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
 
                /* set SCSI IO EEDPFlags */
                if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) {
-                       io_request->EEDPFlags =
+                       io_request->EEDPFlags = cpu_to_le16(
                                MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG  |
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP |
                                MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG |
-                               MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
+                               MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD);
                } else {
-                       io_request->EEDPFlags =
+                       io_request->EEDPFlags = cpu_to_le16(
                                MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
-                               MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
+                               MPI2_SCSIIO_EEDPFLAGS_INSERT_OP);
                }
-               io_request->Control |= (0x4 << 26);
-               io_request->EEDPBlockSize = scp->device->sector_size;
+               io_request->Control |= cpu_to_le32((0x4 << 26));
+               io_request->EEDPBlockSize = cpu_to_le32(scp->device->sector_size);
        } else {
                /* Some drives don't support 16/12 byte CDB's, convert to 10 */
                if (((cdb_len == 12) || (cdb_len == 16)) &&
@@ -1311,7 +1302,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
                        cdb[8] = (u8)(num_blocks & 0xff);
                        cdb[7] = (u8)((num_blocks >> 8) & 0xff);
 
-                       io_request->IoFlags = 10; /* Specify 10-byte cdb */
+                       io_request->IoFlags = cpu_to_le16(10); /* Specify 10-byte cdb */
                        cdb_len = 10;
                } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) {
                        /* Convert to 16 byte CDB for large LBA's */
@@ -1349,7 +1340,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
                        cdb[11] = (u8)((num_blocks >> 16) & 0xff);
                        cdb[10] = (u8)((num_blocks >> 24) & 0xff);
 
-                       io_request->IoFlags = 16; /* Specify 16-byte cdb */
+                       io_request->IoFlags = cpu_to_le16(16); /* Specify 16-byte cdb */
                        cdb_len = 16;
                }
 
@@ -1410,13 +1401,14 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        struct IO_REQUEST_INFO io_info;
        struct fusion_context *fusion;
        struct MR_FW_RAID_MAP_ALL *local_map_ptr;
+       u8 *raidLUN;
 
        device_id = MEGASAS_DEV_INDEX(instance, scp);
 
        fusion = instance->ctrl_context;
 
        io_request = cmd->io_request;
-       io_request->RaidContext.VirtualDiskTgtId = device_id;
+       io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id);
        io_request->RaidContext.status = 0;
        io_request->RaidContext.exStatus = 0;
 
@@ -1480,7 +1472,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo;
        io_info.numBlocks = datalength;
        io_info.ldTgtId = device_id;
-       io_request->DataLength = scsi_bufflen(scp);
+       io_request->DataLength = cpu_to_le32(scsi_bufflen(scp));
 
        if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
                io_info.isRead = 1;
@@ -1494,7 +1486,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
        } else {
                if (MR_BuildRaidContext(instance, &io_info,
                                        &io_request->RaidContext,
-                                       local_map_ptr))
+                                       local_map_ptr, &raidLUN))
                        fp_possible = io_info.fpOkForIo;
        }
 
@@ -1520,8 +1512,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                                        MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
                        io_request->RaidContext.Type = MPI2_TYPE_CUDA;
                        io_request->RaidContext.nseg = 0x1;
-                       io_request->IoFlags |=
-                         MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH;
+                       io_request->IoFlags |= cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
                        io_request->RaidContext.regLockFlags |=
                          (MR_RL_FLAGS_GRANT_DESTINATION_CUDA |
                           MR_RL_FLAGS_SEQ_NUM_ENABLE);
@@ -1537,9 +1528,11 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
                cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle;
                io_request->DevHandle = io_info.devHandle;
+               /* populate the LUN field */
+               memcpy(io_request->LUN, raidLUN, 8);
        } else {
                io_request->RaidContext.timeoutValue =
-                       local_map_ptr->raidMap.fpPdIoTimeoutSec;
+                       cpu_to_le16(local_map_ptr->raidMap.fpPdIoTimeoutSec);
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
                         << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
@@ -1557,7 +1550,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
                        io_request->RaidContext.nseg = 0x1;
                }
                io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
-               io_request->DevHandle = device_id;
+               io_request->DevHandle = cpu_to_le16(device_id);
        } /* Not FP */
 }
 
@@ -1579,6 +1572,11 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
        u16 pd_index = 0;
        struct MR_FW_RAID_MAP_ALL *local_map_ptr;
        struct fusion_context *fusion = instance->ctrl_context;
+       u8                          span, physArm;
+       u16                         devHandle;
+       u32                         ld, arRef, pd;
+       struct MR_LD_RAID                  *raid;
+       struct RAID_CONTEXT                *pRAID_Context;
 
        io_request = cmd->io_request;
        device_id = MEGASAS_DEV_INDEX(instance, scmd);
@@ -1586,6 +1584,9 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
                +scmd->device->id;
        local_map_ptr = fusion->ld_map[(instance->map_id & 1)];
 
+       io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
+
+
        /* Check if this is a system PD I/O */
        if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS &&
            instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
@@ -1623,15 +1624,62 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
                                        scmd->request->timeout / HZ;
                }
        } else {
+               if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS)
+                       goto NonFastPath;
+
+               ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
+               if ((ld >= MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io))
+                       goto NonFastPath;
+
+               raid = MR_LdRaidGet(ld, local_map_ptr);
+
+               /* check if this LD is FP capable */
+               if (!(raid->capability.fpNonRWCapable))
+                       /* not FP capable, send as non-FP */
+                       goto NonFastPath;
+
+               /* get RAID_Context pointer */
+               pRAID_Context = &io_request->RaidContext;
+
+               /* set RAID context values */
+               pRAID_Context->regLockFlags     = REGION_TYPE_SHARED_READ;
+               pRAID_Context->timeoutValue     = raid->fpIoTimeoutForLd;
+               pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+               pRAID_Context->regLockRowLBA    = 0;
+               pRAID_Context->regLockLength    = 0;
+               pRAID_Context->configSeqNum     = raid->seqNum;
+
+               /* get the DevHandle for the PD (since this is
+                  fpNonRWCapable, this is a single disk RAID0) */
+               span = physArm = 0;
+               arRef = MR_LdSpanArrayGet(ld, span, local_map_ptr);
+               pd = MR_ArPdGet(arRef, physArm, local_map_ptr);
+               devHandle = MR_PdDevHandleGet(pd, local_map_ptr);
+
+               /* build request descriptor */
+               cmd->request_desc->SCSIIO.RequestFlags =
+                       (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+                        MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+               cmd->request_desc->SCSIIO.DevHandle = devHandle;
+
+               /* populate the LUN field */
+               memcpy(io_request->LUN, raid->LUN, 8);
+
+               /* build the raidScsiIO structure */
+               io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+               io_request->DevHandle = devHandle;
+
+               return;
+
+NonFastPath:
                io_request->Function  = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
-               io_request->DevHandle = device_id;
+               io_request->DevHandle = cpu_to_le16(device_id);
                cmd->request_desc->SCSIIO.RequestFlags =
                        (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
                         MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
        }
-       io_request->RaidContext.VirtualDiskTgtId = device_id;
+       io_request->RaidContext.VirtualDiskTgtId = cpu_to_le16(device_id);
        io_request->LUN[1] = scmd->device->lun;
-       io_request->DataLength = scsi_bufflen(scmd);
 }
 
 /**
@@ -1670,7 +1718,7 @@ megasas_build_io_fusion(struct megasas_instance *instance,
         * Just the CDB length,rest of the Flags are zero
         * This will be modified for FP in build_ldio_fusion
         */
-       io_request->IoFlags = scp->cmd_len;
+       io_request->IoFlags = cpu_to_le16(scp->cmd_len);
 
        if (megasas_is_ldio(scp))
                megasas_build_ldio_fusion(instance, scp, cmd);
@@ -1695,17 +1743,17 @@ megasas_build_io_fusion(struct megasas_instance *instance,
 
        io_request->RaidContext.numSGE = sge_count;
 
-       io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING;
+       io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
 
        if (scp->sc_data_direction == PCI_DMA_TODEVICE)
-               io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE;
+               io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_WRITE);
        else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE)
-               io_request->Control |= MPI2_SCSIIO_CONTROL_READ;
+               io_request->Control |= cpu_to_le32(MPI2_SCSIIO_CONTROL_READ);
 
        io_request->SGLOffset0 =
                offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4;
 
-       io_request->SenseBufferLowAddress = cmd->sense_phys_addr;
+       io_request->SenseBufferLowAddress = cpu_to_le32(cmd->sense_phys_addr);
        io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
 
        cmd->scmd = scp;
@@ -1770,7 +1818,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance,
        }
 
        req_desc = cmd->request_desc;
-       req_desc->SCSIIO.SMID = index;
+       req_desc->SCSIIO.SMID = cpu_to_le16(index);
 
        if (cmd->io_request->ChainOffset != 0 &&
            cmd->io_request->ChainOffset != 0xF)
@@ -1832,7 +1880,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
        num_completed = 0;
 
        while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) {
-               smid = reply_desc->SMID;
+               smid = le16_to_cpu(reply_desc->SMID);
 
                cmd_fusion = fusion->cmd_list[smid - 1];
 
@@ -2050,12 +2098,12 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
                                       SGL) / 4;
        io_req->ChainOffset = fusion->chain_offset_mfi_pthru;
 
-       mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr;
+       mpi25_ieee_chain->Address = cpu_to_le64(mfi_cmd->frame_phys_addr);
 
        mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
                MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
 
-       mpi25_ieee_chain->Length = MEGASAS_MAX_SZ_CHAIN_FRAME;
+       mpi25_ieee_chain->Length = cpu_to_le32(MEGASAS_MAX_SZ_CHAIN_FRAME);
 
        return 0;
 }
@@ -2088,7 +2136,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
        req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
                                         MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
 
-       req_desc->SCSIIO.SMID = index;
+       req_desc->SCSIIO.SMID = cpu_to_le16(index);
 
        return req_desc;
 }
index 4eb84011cb07f2470a29b7b6ee426f1d60d464f0..35a51397b36478828e2649cac833249f0b38b2bb 100644 (file)
@@ -93,8 +93,13 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
  */
 
 struct RAID_CONTEXT {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+       u8      nseg:4;
+       u8      Type:4;
+#else
        u8      Type:4;
        u8      nseg:4;
+#endif
        u8      resvd0;
        u16     timeoutValue;
        u8      regLockFlags;
@@ -298,8 +303,13 @@ struct MPI2_RAID_SCSI_IO_REQUEST {
  * MPT RAID MFA IO Descriptor.
  */
 struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+       u32     MessageAddress1:24; /* bits 31:8*/
+       u32     RequestFlags:8;
+#else
        u32     RequestFlags:8;
        u32     MessageAddress1:24; /* bits 31:8*/
+#endif
        u32     MessageAddress2;      /* bits 61:32 */
 };
 
@@ -518,6 +528,19 @@ struct MR_SPAN_BLOCK_INFO {
 
 struct MR_LD_RAID {
        struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+               u32     reserved4:7;
+               u32     fpNonRWCapable:1;
+               u32     fpReadAcrossStripe:1;
+               u32     fpWriteAcrossStripe:1;
+               u32     fpReadCapable:1;
+               u32     fpWriteCapable:1;
+               u32     encryptionType:8;
+               u32     pdPiMode:4;
+               u32     ldPiMode:4;
+               u32     reserved5:3;
+               u32     fpCapable:1;
+#else
                u32     fpCapable:1;
                u32     reserved5:3;
                u32     ldPiMode:4;
@@ -527,7 +550,9 @@ struct MR_LD_RAID {
                u32     fpReadCapable:1;
                u32     fpWriteAcrossStripe:1;
                u32     fpReadAcrossStripe:1;
-               u32     reserved4:8;
+               u32     fpNonRWCapable:1;
+               u32     reserved4:7;
+#endif
        } capability;
        u32     reserved6;
        u64     size;
@@ -551,7 +576,9 @@ struct MR_LD_RAID {
                u32 reserved:31;
        } flags;
 
-       u8      reserved3[0x5C];
+       u8      LUN[8]; /* 0x24 8 byte LUN field used for SCSI IO's */
+       u8      fpIoTimeoutForLd;/*0x2C timeout value used by driver in FP IO*/
+       u8      reserved3[0x80-0x2D]; /* 0x2D */
 };
 
 struct MR_LD_SPAN_MAP {
index 4c1d2e7a11768a027063b546c408f0852cc98447..efb0c4c2e31000fd6f8e96777570c0d1086d1dae 100644 (file)
@@ -1,5 +1,5 @@
 # mpt3sas makefile
-obj-m += mpt3sas.o
+obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas.o
 mpt3sas-y +=  mpt3sas_base.o     \
                mpt3sas_config.o \
                mpt3sas_scsih.o      \
index ff12d4677cc449f61b291152a109090e9ed7447f..596480022b0a4b88eb7a3d855e472200d5ab4fef 100644 (file)
@@ -10,7 +10,7 @@
  *
  *  Forward port and refactoring to modern qla2xxx and target/configfs
  *
- *  Copyright (C) 2010-2011 Nicholas A. Bellinger <nab@kernel.org>
+ *  Copyright (C) 2010-2013 Nicholas A. Bellinger <nab@kernel.org>
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License
index a6da313e253bb13000bcf30090f78f48f680d135..f85b9e5c1f059dca0d62399ac52ecfe031dfbae0 100644 (file)
@@ -2,12 +2,9 @@
  * This file contains tcm implementation using v4 configfs fabric infrastructure
  * for QLogic target mode HBAs
  *
- * ?? Copyright 2010-2011 RisingTide Systems LLC.
+ * (c) Copyright 2010-2013 Datera, Inc.
  *
- * Licensed to the Linux Foundation under the General Public License (GPL)
- * version 2.
- *
- * Author: Nicholas A. Bellinger <nab@risingtidesystems.com>
+ * Author: Nicholas A. Bellinger <nab@daterainc.com>
  *
  * tcm_qla2xxx_parse_wwn() and tcm_qla2xxx_format_wwn() contains code from
  * the TCM_FC / Open-FCoE.org fabric module.
@@ -360,6 +357,14 @@ static int tcm_qla2xxx_check_prod_write_protect(struct se_portal_group *se_tpg)
        return QLA_TPG_ATTRIB(tpg)->prod_mode_write_protect;
 }
 
+static int tcm_qla2xxx_check_demo_mode_login_only(struct se_portal_group *se_tpg)
+{
+       struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
+                               struct tcm_qla2xxx_tpg, se_tpg);
+
+       return QLA_TPG_ATTRIB(tpg)->demo_mode_login_only;
+}
+
 static struct se_node_acl *tcm_qla2xxx_alloc_fabric_acl(
        struct se_portal_group *se_tpg)
 {
@@ -489,38 +494,13 @@ static u32 tcm_qla2xxx_sess_get_index(struct se_session *se_sess)
        return 0;
 }
 
-/*
- * The LIO target core uses DMA_TO_DEVICE to mean that data is going
- * to the target (eg handling a WRITE) and DMA_FROM_DEVICE to mean
- * that data is coming from the target (eg handling a READ).  However,
- * this is just the opposite of what we have to tell the DMA mapping
- * layer -- eg when handling a READ, the HBA will have to DMA the data
- * out of memory so it can send it to the initiator, which means we
- * need to use DMA_TO_DEVICE when we map the data.
- */
-static enum dma_data_direction tcm_qla2xxx_mapping_dir(struct se_cmd *se_cmd)
-{
-       if (se_cmd->se_cmd_flags & SCF_BIDI)
-               return DMA_BIDIRECTIONAL;
-
-       switch (se_cmd->data_direction) {
-       case DMA_TO_DEVICE:
-               return DMA_FROM_DEVICE;
-       case DMA_FROM_DEVICE:
-               return DMA_TO_DEVICE;
-       case DMA_NONE:
-       default:
-               return DMA_NONE;
-       }
-}
-
 static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd)
 {
        struct qla_tgt_cmd *cmd = container_of(se_cmd,
                                struct qla_tgt_cmd, se_cmd);
 
        cmd->bufflen = se_cmd->data_length;
-       cmd->dma_data_direction = tcm_qla2xxx_mapping_dir(se_cmd);
+       cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
 
        cmd->sg_cnt = se_cmd->t_data_nents;
        cmd->sg = se_cmd->t_data_sg;
@@ -656,7 +636,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd)
                                struct qla_tgt_cmd, se_cmd);
 
        cmd->bufflen = se_cmd->data_length;
-       cmd->dma_data_direction = tcm_qla2xxx_mapping_dir(se_cmd);
+       cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
        cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
 
        cmd->sg_cnt = se_cmd->t_data_nents;
@@ -680,7 +660,7 @@ static int tcm_qla2xxx_queue_status(struct se_cmd *se_cmd)
        cmd->sg = NULL;
        cmd->sg_cnt = 0;
        cmd->offset = 0;
-       cmd->dma_data_direction = tcm_qla2xxx_mapping_dir(se_cmd);
+       cmd->dma_data_direction = target_reverse_dma_direction(se_cmd);
        cmd->aborted = (se_cmd->transport_state & CMD_T_ABORTED);
 
        if (se_cmd->data_direction == DMA_FROM_DEVICE) {
@@ -939,11 +919,19 @@ DEF_QLA_TPG_ATTR_BOOL(prod_mode_write_protect);
 DEF_QLA_TPG_ATTRIB(prod_mode_write_protect);
 QLA_TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR);
 
+/*
+ * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_login_only
+ */
+DEF_QLA_TPG_ATTR_BOOL(demo_mode_login_only);
+DEF_QLA_TPG_ATTRIB(demo_mode_login_only);
+QLA_TPG_ATTR(demo_mode_login_only, S_IRUGO | S_IWUSR);
+
 static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = {
        &tcm_qla2xxx_tpg_attrib_generate_node_acls.attr,
        &tcm_qla2xxx_tpg_attrib_cache_dynamic_acls.attr,
        &tcm_qla2xxx_tpg_attrib_demo_mode_write_protect.attr,
        &tcm_qla2xxx_tpg_attrib_prod_mode_write_protect.attr,
+       &tcm_qla2xxx_tpg_attrib_demo_mode_login_only.attr,
        NULL,
 };
 
@@ -1042,6 +1030,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
        QLA_TPG_ATTRIB(tpg)->generate_node_acls = 1;
        QLA_TPG_ATTRIB(tpg)->demo_mode_write_protect = 1;
        QLA_TPG_ATTRIB(tpg)->cache_dynamic_acls = 1;
+       QLA_TPG_ATTRIB(tpg)->demo_mode_login_only = 1;
 
        ret = core_tpg_register(&tcm_qla2xxx_fabric_configfs->tf_ops, wwn,
                                &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
@@ -1736,7 +1725,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = {
                                        tcm_qla2xxx_check_demo_write_protect,
        .tpg_check_prod_mode_write_protect =
                                        tcm_qla2xxx_check_prod_write_protect,
-       .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_true,
+       .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
        .tpg_alloc_fabric_acl           = tcm_qla2xxx_alloc_fabric_acl,
        .tpg_release_fabric_acl         = tcm_qla2xxx_release_fabric_acl,
        .tpg_get_inst_index             = tcm_qla2xxx_tpg_get_inst_index,
@@ -1784,7 +1773,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .tpg_check_demo_mode_cache      = tcm_qla2xxx_check_true,
        .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_true,
        .tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_false,
-       .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_true,
+       .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
        .tpg_alloc_fabric_acl           = tcm_qla2xxx_alloc_fabric_acl,
        .tpg_release_fabric_acl         = tcm_qla2xxx_release_fabric_acl,
        .tpg_get_inst_index             = tcm_qla2xxx_tpg_get_inst_index,
index 9ba075fe9781f0148dca9aa73b6525e554a91154..329327528a55b508711b79da5ead5b86817108ca 100644 (file)
@@ -29,6 +29,7 @@ struct tcm_qla2xxx_tpg_attrib {
        int cache_dynamic_acls;
        int demo_mode_write_protect;
        int prod_mode_write_protect;
+       int demo_mode_login_only;
 };
 
 struct tcm_qla2xxx_tpg {
index b58e8f815a002548cdea5724be023c55802760f0..e62d17d41d4e7b84ddf7469194aa0c63d541d59d 100644 (file)
@@ -2420,14 +2420,9 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
                        }
                }
 
-               if (modepage == 0x3F) {
-                       sd_printk(KERN_ERR, sdkp, "No Caching mode page "
-                                 "present\n");
-                       goto defaults;
-               } else if ((buffer[offset] & 0x3f) != modepage) {
-                       sd_printk(KERN_ERR, sdkp, "Got wrong page\n");
-                       goto defaults;
-               }
+               sd_printk(KERN_ERR, sdkp, "No Caching mode page found\n");
+               goto defaults;
+
        Page_found:
                if (modepage == 8) {
                        sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0);
index bce09a6898c4562c8778ea3d88f1995386721016..7210500905207e0b7ef343beff02a7195c6bfb23 100644 (file)
@@ -177,6 +177,7 @@ enum {
        MASK_TASK_RESPONSE              = 0xFF00,
        MASK_RSP_UPIU_RESULT            = 0xFFFF,
        MASK_QUERY_DATA_SEG_LEN         = 0xFFFF,
+       MASK_RSP_UPIU_DATA_SEG_LEN      = 0xFFFF,
        MASK_RSP_EXCEPTION_EVENT        = 0x10000,
 };
 
index b36ca9a2dfbb2b497fab3995df96f659940a7c48..04884d663e4e13bcb88b4ac46dcc76e48f77620d 100644 (file)
 #include <linux/async.h>
 
 #include "ufshcd.h"
+#include "unipro.h"
 
 #define UFSHCD_ENABLE_INTRS    (UTP_TRANSFER_REQ_COMPL |\
                                 UTP_TASK_REQ_COMPL |\
+                                UIC_POWER_MODE |\
                                 UFSHCD_ERROR_MASK)
 /* UIC command timeout, unit: ms */
 #define UIC_CMD_TIMEOUT        500
@@ -56,6 +58,9 @@
 /* Expose the flag value from utp_upiu_query.value */
 #define MASK_QUERY_UPIU_FLAG_LOC 0xFF
 
+/* Interrupt aggregation default timeout, unit: 40us */
+#define INT_AGGR_DEF_TO        0x02
+
 enum {
        UFSHCD_MAX_CHANNEL      = 0,
        UFSHCD_MAX_ID           = 1,
@@ -78,12 +83,6 @@ enum {
        UFSHCD_INT_CLEAR,
 };
 
-/* Interrupt aggregation options */
-enum {
-       INT_AGGR_RESET,
-       INT_AGGR_CONFIG,
-};
-
 /*
  * ufshcd_wait_for_register - wait for register value to change
  * @hba - per-adapter interface
@@ -237,6 +236,18 @@ static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba)
               MASK_UIC_COMMAND_RESULT;
 }
 
+/**
+ * ufshcd_get_dme_attr_val - Get the value of attribute returned by UIC command
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets UIC command argument3
+ * Returns 0 on success, non zero value on error
+ */
+static inline u32 ufshcd_get_dme_attr_val(struct ufs_hba *hba)
+{
+       return ufshcd_readl(hba, REG_UIC_COMMAND_ARG_3);
+}
+
 /**
  * ufshcd_get_req_rsp - returns the TR response transaction type
  * @ucd_rsp_ptr: pointer to response UPIU
@@ -260,6 +271,20 @@ ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr)
        return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT;
 }
 
+/*
+ * ufshcd_get_rsp_upiu_data_seg_len - Get the data segment length
+ *                             from response UPIU
+ * @ucd_rsp_ptr: pointer to response UPIU
+ *
+ * Return the data segment length.
+ */
+static inline unsigned int
+ufshcd_get_rsp_upiu_data_seg_len(struct utp_upiu_rsp *ucd_rsp_ptr)
+{
+       return be32_to_cpu(ucd_rsp_ptr->header.dword_2) &
+               MASK_RSP_UPIU_DATA_SEG_LEN;
+}
+
 /**
  * ufshcd_is_exception_event - Check if the device raised an exception event
  * @ucd_rsp_ptr: pointer to response UPIU
@@ -276,30 +301,30 @@ static inline bool ufshcd_is_exception_event(struct utp_upiu_rsp *ucd_rsp_ptr)
 }
 
 /**
- * ufshcd_config_int_aggr - Configure interrupt aggregation values.
- *             Currently there is no use case where we want to configure
- *             interrupt aggregation dynamically. So to configure interrupt
- *             aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and
- *             INT_AGGR_TIMEOUT_VALUE are used.
+ * ufshcd_reset_intr_aggr - Reset interrupt aggregation values.
  * @hba: per adapter instance
- * @option: Interrupt aggregation option
  */
 static inline void
-ufshcd_config_int_aggr(struct ufs_hba *hba, int option)
+ufshcd_reset_intr_aggr(struct ufs_hba *hba)
 {
-       switch (option) {
-       case INT_AGGR_RESET:
-               ufshcd_writel(hba, INT_AGGR_ENABLE |
-                             INT_AGGR_COUNTER_AND_TIMER_RESET,
-                             REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-               break;
-       case INT_AGGR_CONFIG:
-               ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
-                             INT_AGGR_COUNTER_THRESHOLD_VALUE |
-                             INT_AGGR_TIMEOUT_VALUE,
-                             REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
-               break;
-       }
+       ufshcd_writel(hba, INT_AGGR_ENABLE |
+                     INT_AGGR_COUNTER_AND_TIMER_RESET,
+                     REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
+}
+
+/**
+ * ufshcd_config_intr_aggr - Configure interrupt aggregation values.
+ * @hba: per adapter instance
+ * @cnt: Interrupt aggregation counter threshold
+ * @tmout: Interrupt aggregation timeout value
+ */
+static inline void
+ufshcd_config_intr_aggr(struct ufs_hba *hba, u8 cnt, u8 tmout)
+{
+       ufshcd_writel(hba, INT_AGGR_ENABLE | INT_AGGR_PARAM_WRITE |
+                     INT_AGGR_COUNTER_THLD_VAL(cnt) |
+                     INT_AGGR_TIMEOUT_VAL(tmout),
+                     REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL);
 }
 
 /**
@@ -355,7 +380,8 @@ void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag)
 static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp)
 {
        int len;
-       if (lrbp->sense_buffer) {
+       if (lrbp->sense_buffer &&
+           ufshcd_get_rsp_upiu_data_seg_len(lrbp->ucd_rsp_ptr)) {
                len = be16_to_cpu(lrbp->ucd_rsp_ptr->sr.sense_data_len);
                memcpy(lrbp->sense_buffer,
                        lrbp->ucd_rsp_ptr->sr.sense_data,
@@ -445,6 +471,18 @@ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba)
                return false;
 }
 
+/**
+ * ufshcd_get_upmcrs - Get the power mode change request status
+ * @hba: Pointer to adapter instance
+ *
+ * This function gets the UPMCRS field of HCS register
+ * Returns value of UPMCRS field
+ */
+static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
+{
+       return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
+}
+
 /**
  * ufshcd_dispatch_uic_cmd - Dispatch UIC commands to unipro layers
  * @hba: per adapter instance
@@ -1361,6 +1399,202 @@ static int ufshcd_dme_link_startup(struct ufs_hba *hba)
        return ret;
 }
 
+/**
+ * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @attr_set: attribute set type as uic command argument2
+ * @mib_val: setting value as uic command argument3
+ * @peer: indicate whether peer or local
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+                       u8 attr_set, u32 mib_val, u8 peer)
+{
+       struct uic_command uic_cmd = {0};
+       static const char *const action[] = {
+               "dme-set",
+               "dme-peer-set"
+       };
+       const char *set = action[!!peer];
+       int ret;
+
+       uic_cmd.command = peer ?
+               UIC_CMD_DME_PEER_SET : UIC_CMD_DME_SET;
+       uic_cmd.argument1 = attr_sel;
+       uic_cmd.argument2 = UIC_ARG_ATTR_TYPE(attr_set);
+       uic_cmd.argument3 = mib_val;
+
+       ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+       if (ret)
+               dev_err(hba->dev, "%s: attr-id 0x%x val 0x%x error code %d\n",
+                       set, UIC_GET_ATTR_ID(attr_sel), mib_val, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_set_attr);
+
+/**
+ * ufshcd_dme_get_attr - UIC command for DME_GET, DME_PEER_GET
+ * @hba: per adapter instance
+ * @attr_sel: uic command argument1
+ * @mib_val: the value of the attribute as returned by the UIC command
+ * @peer: indicate whether peer or local
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+                       u32 *mib_val, u8 peer)
+{
+       struct uic_command uic_cmd = {0};
+       static const char *const action[] = {
+               "dme-get",
+               "dme-peer-get"
+       };
+       const char *get = action[!!peer];
+       int ret;
+
+       uic_cmd.command = peer ?
+               UIC_CMD_DME_PEER_GET : UIC_CMD_DME_GET;
+       uic_cmd.argument1 = attr_sel;
+
+       ret = ufshcd_send_uic_cmd(hba, &uic_cmd);
+       if (ret) {
+               dev_err(hba->dev, "%s: attr-id 0x%x error code %d\n",
+                       get, UIC_GET_ATTR_ID(attr_sel), ret);
+               goto out;
+       }
+
+       if (mib_val)
+               *mib_val = uic_cmd.argument3;
+out:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ufshcd_dme_get_attr);
+
+/**
+ * ufshcd_uic_change_pwr_mode - Perform the UIC power mode chage
+ *                             using DME_SET primitives.
+ * @hba: per adapter instance
+ * @mode: powr mode value
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode)
+{
+       struct uic_command uic_cmd = {0};
+       struct completion pwr_done;
+       unsigned long flags;
+       u8 status;
+       int ret;
+
+       uic_cmd.command = UIC_CMD_DME_SET;
+       uic_cmd.argument1 = UIC_ARG_MIB(PA_PWRMODE);
+       uic_cmd.argument3 = mode;
+       init_completion(&pwr_done);
+
+       mutex_lock(&hba->uic_cmd_mutex);
+
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       hba->pwr_done = &pwr_done;
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       ret = __ufshcd_send_uic_cmd(hba, &uic_cmd);
+       if (ret) {
+               dev_err(hba->dev,
+                       "pwr mode change with mode 0x%x uic error %d\n",
+                       mode, ret);
+               goto out;
+       }
+
+       if (!wait_for_completion_timeout(hba->pwr_done,
+                                        msecs_to_jiffies(UIC_CMD_TIMEOUT))) {
+               dev_err(hba->dev,
+                       "pwr mode change with mode 0x%x completion timeout\n",
+                       mode);
+               ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       status = ufshcd_get_upmcrs(hba);
+       if (status != PWR_LOCAL) {
+               dev_err(hba->dev,
+                       "pwr mode change failed, host umpcrs:0x%x\n",
+                       status);
+               ret = (status != PWR_OK) ? status : -1;
+       }
+out:
+       spin_lock_irqsave(hba->host->host_lock, flags);
+       hba->pwr_done = NULL;
+       spin_unlock_irqrestore(hba->host->host_lock, flags);
+       mutex_unlock(&hba->uic_cmd_mutex);
+       return ret;
+}
+
+/**
+ * ufshcd_config_max_pwr_mode - Set & Change power mode with
+ *     maximum capability attribute information.
+ * @hba: per adapter instance
+ *
+ * Returns 0 on success, non-zero value on failure
+ */
+static int ufshcd_config_max_pwr_mode(struct ufs_hba *hba)
+{
+       enum {RX = 0, TX = 1};
+       u32 lanes[] = {1, 1};
+       u32 gear[] = {1, 1};
+       u8 pwr[] = {FASTAUTO_MODE, FASTAUTO_MODE};
+       int ret;
+
+       /* Get the connected lane count */
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDRXDATALANES), &lanes[RX]);
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), &lanes[TX]);
+
+       /*
+        * First, get the maximum gears of HS speed.
+        * If a zero value, it means there is no HSGEAR capability.
+        * Then, get the maximum gears of PWM speed.
+        */
+       ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[RX]);
+       if (!gear[RX]) {
+               ufshcd_dme_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR), &gear[RX]);
+               pwr[RX] = SLOWAUTO_MODE;
+       }
+
+       ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXHSGEAR), &gear[TX]);
+       if (!gear[TX]) {
+               ufshcd_dme_peer_get(hba, UIC_ARG_MIB(PA_MAXRXPWMGEAR),
+                                   &gear[TX]);
+               pwr[TX] = SLOWAUTO_MODE;
+       }
+
+       /*
+        * Configure attributes for power mode change with below.
+        * - PA_RXGEAR, PA_ACTIVERXDATALANES, PA_RXTERMINATION,
+        * - PA_TXGEAR, PA_ACTIVETXDATALANES, PA_TXTERMINATION,
+        * - PA_HSSERIES
+        */
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXGEAR), gear[RX]);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVERXDATALANES), lanes[RX]);
+       if (pwr[RX] == FASTAUTO_MODE)
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_RXTERMINATION), TRUE);
+
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXGEAR), gear[TX]);
+       ufshcd_dme_set(hba, UIC_ARG_MIB(PA_ACTIVETXDATALANES), lanes[TX]);
+       if (pwr[TX] == FASTAUTO_MODE)
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_TXTERMINATION), TRUE);
+
+       if (pwr[RX] == FASTAUTO_MODE || pwr[TX] == FASTAUTO_MODE)
+               ufshcd_dme_set(hba, UIC_ARG_MIB(PA_HSSERIES), PA_HS_MODE_B);
+
+       ret = ufshcd_uic_change_pwr_mode(hba, pwr[RX] << 4 | pwr[TX]);
+       if (ret)
+               dev_err(hba->dev,
+                       "pwr_mode: power mode change failed %d\n", ret);
+
+       return ret;
+}
+
 /**
  * ufshcd_complete_dev_init() - checks device readiness
  * hba: per-adapter instance
@@ -1442,7 +1676,7 @@ static int ufshcd_make_hba_operational(struct ufs_hba *hba)
        ufshcd_enable_intr(hba, UFSHCD_ENABLE_INTRS);
 
        /* Configure interrupt aggregation */
-       ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG);
+       ufshcd_config_intr_aggr(hba, hba->nutrs - 1, INT_AGGR_DEF_TO);
 
        /* Configure UTRL and UTMRL base address registers */
        ufshcd_writel(hba, lower_32_bits(hba->utrdl_dma_addr),
@@ -1788,32 +2022,24 @@ ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status)
        int result = 0;
 
        switch (scsi_status) {
-       case SAM_STAT_GOOD:
-               result |= DID_OK << 16 |
-                         COMMAND_COMPLETE << 8 |
-                         SAM_STAT_GOOD;
-               break;
        case SAM_STAT_CHECK_CONDITION:
+               ufshcd_copy_sense_data(lrbp);
+       case SAM_STAT_GOOD:
                result |= DID_OK << 16 |
                          COMMAND_COMPLETE << 8 |
-                         SAM_STAT_CHECK_CONDITION;
-               ufshcd_copy_sense_data(lrbp);
-               break;
-       case SAM_STAT_BUSY:
-               result |= SAM_STAT_BUSY;
+                         scsi_status;
                break;
        case SAM_STAT_TASK_SET_FULL:
-
                /*
                 * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue
                 * depth needs to be adjusted to the exact number of
                 * outstanding commands the LUN can handle at any given time.
                 */
                ufshcd_adjust_lun_qdepth(lrbp->cmd);
-               result |= SAM_STAT_TASK_SET_FULL;
-               break;
+       case SAM_STAT_BUSY:
        case SAM_STAT_TASK_ABORTED:
-               result |= SAM_STAT_TASK_ABORTED;
+               ufshcd_copy_sense_data(lrbp);
+               result |= scsi_status;
                break;
        default:
                result |= DID_ERROR << 16;
@@ -1898,14 +2124,20 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 /**
  * ufshcd_uic_cmd_compl - handle completion of uic command
  * @hba: per adapter instance
+ * @intr_status: interrupt status generated by the controller
  */
-static void ufshcd_uic_cmd_compl(struct ufs_hba *hba)
+static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status)
 {
-       if (hba->active_uic_cmd) {
+       if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) {
                hba->active_uic_cmd->argument2 |=
                        ufshcd_get_uic_cmd_result(hba);
+               hba->active_uic_cmd->argument3 =
+                       ufshcd_get_dme_attr_val(hba);
                complete(&hba->active_uic_cmd->done);
        }
+
+       if ((intr_status & UIC_POWER_MODE) && hba->pwr_done)
+               complete(hba->pwr_done);
 }
 
 /**
@@ -1960,7 +2192,7 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba)
 
        /* Reset interrupt aggregation counters */
        if (int_aggr_reset)
-               ufshcd_config_int_aggr(hba, INT_AGGR_RESET);
+               ufshcd_reset_intr_aggr(hba);
 }
 
 /**
@@ -2251,8 +2483,8 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status)
        if (hba->errors)
                ufshcd_err_handler(hba);
 
-       if (intr_status & UIC_COMMAND_COMPL)
-               ufshcd_uic_cmd_compl(hba);
+       if (intr_status & UFSHCD_UIC_MASK)
+               ufshcd_uic_cmd_compl(hba, intr_status);
 
        if (intr_status & UTP_TASK_REQ_COMPL)
                ufshcd_tmc_handler(hba);
@@ -2494,6 +2726,8 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
        if (ret)
                goto out;
 
+       ufshcd_config_max_pwr_mode(hba);
+
        ret = ufshcd_verify_dev_init(hba);
        if (ret)
                goto out;
index 59c9c4848be1bd10a88bcea3d552d623bf0a24e3..577679a2d1898f919826ec8f27e18213414b908d 100644 (file)
@@ -175,6 +175,7 @@ struct ufs_dev_cmd {
  * @active_uic_cmd: handle of active UIC command
  * @uic_cmd_mutex: mutex for uic command
  * @ufshcd_tm_wait_queue: wait queue for task management
+ * @pwr_done: completion for power mode change
  * @tm_condition: condition variable for task management
  * @ufshcd_state: UFSHCD states
  * @intr_mask: Interrupt Mask Bits
@@ -219,6 +220,8 @@ struct ufs_hba {
        wait_queue_head_t ufshcd_tm_wait_queue;
        unsigned long tm_condition;
 
+       struct completion *pwr_done;
+
        u32 ufshcd_state;
        u32 intr_mask;
        u16 ee_ctrl_mask;
@@ -263,4 +266,55 @@ static inline void check_upiu_size(void)
 extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
 extern int ufshcd_runtime_resume(struct ufs_hba *hba);
 extern int ufshcd_runtime_idle(struct ufs_hba *hba);
+extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel,
+                              u8 attr_set, u32 mib_val, u8 peer);
+extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel,
+                              u32 *mib_val, u8 peer);
+
+/* UIC command interfaces for DME primitives */
+#define DME_LOCAL      0
+#define DME_PEER       1
+#define ATTR_SET_NOR   0       /* NORMAL */
+#define ATTR_SET_ST    1       /* STATIC */
+
+static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel,
+                                u32 mib_val)
+{
+       return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR,
+                                  mib_val, DME_LOCAL);
+}
+
+static inline int ufshcd_dme_st_set(struct ufs_hba *hba, u32 attr_sel,
+                                   u32 mib_val)
+{
+       return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_ST,
+                                  mib_val, DME_LOCAL);
+}
+
+static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel,
+                                     u32 mib_val)
+{
+       return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR,
+                                  mib_val, DME_PEER);
+}
+
+static inline int ufshcd_dme_peer_st_set(struct ufs_hba *hba, u32 attr_sel,
+                                        u32 mib_val)
+{
+       return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_ST,
+                                  mib_val, DME_PEER);
+}
+
+static inline int ufshcd_dme_get(struct ufs_hba *hba,
+                                u32 attr_sel, u32 *mib_val)
+{
+       return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_LOCAL);
+}
+
+static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
+                                     u32 attr_sel, u32 *mib_val)
+{
+       return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER);
+}
+
 #endif /* End of Header */
index f1e1b74591078b139ba797bd374c6d2ad3d701ff..0475c6619a68109dd100f47cd7f41b793aea8aa9 100644 (file)
@@ -124,6 +124,9 @@ enum {
 #define CONTROLLER_FATAL_ERROR                 UFS_BIT(16)
 #define SYSTEM_BUS_FATAL_ERROR                 UFS_BIT(17)
 
+#define UFSHCD_UIC_MASK                (UIC_COMMAND_COMPL |\
+                                UIC_POWER_MODE)
+
 #define UFSHCD_ERROR_MASK      (UIC_ERROR |\
                                DEVICE_FATAL_ERROR |\
                                CONTROLLER_FATAL_ERROR |\
@@ -142,6 +145,15 @@ enum {
 #define DEVICE_ERROR_INDICATOR                 UFS_BIT(5)
 #define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK  UFS_MASK(0x7, 8)
 
+enum {
+       PWR_OK          = 0x0,
+       PWR_LOCAL       = 0x01,
+       PWR_REMOTE      = 0x02,
+       PWR_BUSY        = 0x03,
+       PWR_ERROR_CAP   = 0x04,
+       PWR_FATAL_ERROR = 0x05,
+};
+
 /* HCE - Host Controller Enable 34h */
 #define CONTROLLER_ENABLE      UFS_BIT(0)
 #define CONTROLLER_DISABLE     0x0
@@ -191,6 +203,12 @@ enum {
 #define CONFIG_RESULT_CODE_MASK                0xFF
 #define GENERIC_ERROR_CODE_MASK                0xFF
 
+#define UIC_ARG_MIB_SEL(attr, sel)     ((((attr) & 0xFFFF) << 16) |\
+                                        ((sel) & 0xFFFF))
+#define UIC_ARG_MIB(attr)              UIC_ARG_MIB_SEL(attr, 0)
+#define UIC_ARG_ATTR_TYPE(t)           (((t) & 0xFF) << 16)
+#define UIC_GET_ATTR_ID(v)             (((v) >> 16) & 0xFFFF)
+
 /* UIC Commands */
 enum {
        UIC_CMD_DME_GET                 = 0x01,
@@ -226,8 +244,8 @@ enum {
 
 #define MASK_UIC_COMMAND_RESULT                        0xFF
 
-#define INT_AGGR_COUNTER_THRESHOLD_VALUE       (0x1F << 8)
-#define INT_AGGR_TIMEOUT_VALUE                 (0x02)
+#define INT_AGGR_COUNTER_THLD_VAL(c)   (((c) & 0x1F) << 8)
+#define INT_AGGR_TIMEOUT_VAL(t)                (((t) & 0xFF) << 0)
 
 /* Interrupt disable masks */
 enum {
diff --git a/drivers/scsi/ufs/unipro.h b/drivers/scsi/ufs/unipro.h
new file mode 100644 (file)
index 0000000..0bb8041
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * drivers/scsi/ufs/unipro.h
+ *
+ * Copyright (C) 2013 Samsung Electronics Co., Ltd.
+ *
+ * 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 _UNIPRO_H_
+#define _UNIPRO_H_
+
+/*
+ * PHY Adpater attributes
+ */
+#define PA_ACTIVETXDATALANES   0x1560
+#define PA_ACTIVERXDATALANES   0x1580
+#define PA_TXTRAILINGCLOCKS    0x1564
+#define PA_PHY_TYPE            0x1500
+#define PA_AVAILTXDATALANES    0x1520
+#define PA_AVAILRXDATALANES    0x1540
+#define PA_MINRXTRAILINGCLOCKS 0x1543
+#define PA_TXPWRSTATUS         0x1567
+#define PA_RXPWRSTATUS         0x1582
+#define PA_TXFORCECLOCK                0x1562
+#define PA_TXPWRMODE           0x1563
+#define PA_LEGACYDPHYESCDL     0x1570
+#define PA_MAXTXSPEEDFAST      0x1521
+#define PA_MAXTXSPEEDSLOW      0x1522
+#define PA_MAXRXSPEEDFAST      0x1541
+#define PA_MAXRXSPEEDSLOW      0x1542
+#define PA_TXLINKSTARTUPHS     0x1544
+#define PA_TXSPEEDFAST         0x1565
+#define PA_TXSPEEDSLOW         0x1566
+#define PA_REMOTEVERINFO       0x15A0
+#define PA_TXGEAR              0x1568
+#define PA_TXTERMINATION       0x1569
+#define PA_HSSERIES            0x156A
+#define PA_PWRMODE             0x1571
+#define PA_RXGEAR              0x1583
+#define PA_RXTERMINATION       0x1584
+#define PA_MAXRXPWMGEAR                0x1586
+#define PA_MAXRXHSGEAR         0x1587
+#define PA_RXHSUNTERMCAP       0x15A5
+#define PA_RXLSTERMCAP         0x15A6
+#define PA_PACPREQTIMEOUT      0x1590
+#define PA_PACPREQEOBTIMEOUT   0x1591
+#define PA_HIBERN8TIME         0x15A7
+#define PA_LOCALVERINFO                0x15A9
+#define PA_TACTIVATE           0x15A8
+#define PA_PACPFRAMECOUNT      0x15C0
+#define PA_PACPERRORCOUNT      0x15C1
+#define PA_PHYTESTCONTROL      0x15C2
+#define PA_PWRMODEUSERDATA0    0x15B0
+#define PA_PWRMODEUSERDATA1    0x15B1
+#define PA_PWRMODEUSERDATA2    0x15B2
+#define PA_PWRMODEUSERDATA3    0x15B3
+#define PA_PWRMODEUSERDATA4    0x15B4
+#define PA_PWRMODEUSERDATA5    0x15B5
+#define PA_PWRMODEUSERDATA6    0x15B6
+#define PA_PWRMODEUSERDATA7    0x15B7
+#define PA_PWRMODEUSERDATA8    0x15B8
+#define PA_PWRMODEUSERDATA9    0x15B9
+#define PA_PWRMODEUSERDATA10   0x15BA
+#define PA_PWRMODEUSERDATA11   0x15BB
+#define PA_CONNECTEDTXDATALANES        0x1561
+#define PA_CONNECTEDRXDATALANES        0x1581
+#define PA_LOGICALLANEMAP      0x15A1
+#define PA_SLEEPNOCONFIGTIME   0x15A2
+#define PA_STALLNOCONFIGTIME   0x15A3
+#define PA_SAVECONFIGTIME      0x15A4
+
+/* PA power modes */
+enum {
+       FAST_MODE       = 1,
+       SLOW_MODE       = 2,
+       FASTAUTO_MODE   = 4,
+       SLOWAUTO_MODE   = 5,
+       UNCHANGED       = 7,
+};
+
+/* PA TX/RX Frequency Series */
+enum {
+       PA_HS_MODE_A    = 1,
+       PA_HS_MODE_B    = 2,
+};
+
+/*
+ * Data Link Layer Attributes
+ */
+#define DL_TC0TXFCTHRESHOLD    0x2040
+#define DL_FC0PROTTIMEOUTVAL   0x2041
+#define DL_TC0REPLAYTIMEOUTVAL 0x2042
+#define DL_AFC0REQTIMEOUTVAL   0x2043
+#define DL_AFC0CREDITTHRESHOLD 0x2044
+#define DL_TC0OUTACKTHRESHOLD  0x2045
+#define DL_TC1TXFCTHRESHOLD    0x2060
+#define DL_FC1PROTTIMEOUTVAL   0x2061
+#define DL_TC1REPLAYTIMEOUTVAL 0x2062
+#define DL_AFC1REQTIMEOUTVAL   0x2063
+#define DL_AFC1CREDITTHRESHOLD 0x2064
+#define DL_TC1OUTACKTHRESHOLD  0x2065
+#define DL_TXPREEMPTIONCAP     0x2000
+#define DL_TC0TXMAXSDUSIZE     0x2001
+#define DL_TC0RXINITCREDITVAL  0x2002
+#define DL_TC0TXBUFFERSIZE     0x2005
+#define DL_PEERTC0PRESENT      0x2046
+#define DL_PEERTC0RXINITCREVAL 0x2047
+#define DL_TC1TXMAXSDUSIZE     0x2003
+#define DL_TC1RXINITCREDITVAL  0x2004
+#define DL_TC1TXBUFFERSIZE     0x2006
+#define DL_PEERTC1PRESENT      0x2066
+#define DL_PEERTC1RXINITCREVAL 0x2067
+
+/*
+ * Network Layer Attributes
+ */
+#define N_DEVICEID             0x3000
+#define N_DEVICEID_VALID       0x3001
+#define N_TC0TXMAXSDUSIZE      0x3020
+#define N_TC1TXMAXSDUSIZE      0x3021
+
+/*
+ * Transport Layer Attributes
+ */
+#define T_NUMCPORTS            0x4000
+#define T_NUMTESTFEATURES      0x4001
+#define T_CONNECTIONSTATE      0x4020
+#define T_PEERDEVICEID         0x4021
+#define T_PEERCPORTID          0x4022
+#define T_TRAFFICCLASS         0x4023
+#define T_PROTOCOLID           0x4024
+#define T_CPORTFLAGS           0x4025
+#define T_TXTOKENVALUE         0x4026
+#define T_RXTOKENVALUE         0x4027
+#define T_LOCALBUFFERSPACE     0x4028
+#define T_PEERBUFFERSPACE      0x4029
+#define T_CREDITSTOSEND                0x402A
+#define T_CPORTMODE            0x402B
+#define T_TC0TXMAXSDUSIZE      0x4060
+#define T_TC1TXMAXSDUSIZE      0x4061
+
+/* Boolean attribute values */
+enum {
+       FALSE = 0,
+       TRUE,
+};
+
+#endif /* _UNIPRO_H_ */
index 0170d4c4a8a32aff8fceaa14e9705b07366ef980..b9c53cc40e1fa487dd3d73cd9c83d713a3334e6a 100644 (file)
@@ -55,7 +55,6 @@ comment "SPI Master Controller Drivers"
 
 config SPI_ALTERA
        tristate "Altera SPI Controller"
-       depends on GENERIC_HARDIRQS
        select SPI_BITBANG
        help
          This is the driver for the Altera SPI Controller.
@@ -358,7 +357,7 @@ config SPI_PXA2XX_DMA
 
 config SPI_PXA2XX
        tristate "PXA2xx SSP SPI master"
-       depends on (ARCH_PXA || PCI || ACPI) && GENERIC_HARDIRQS
+       depends on (ARCH_PXA || PCI || ACPI)
        select PXA_SSP if ARCH_PXA
        help
          This enables using a PXA2xx or Sodaville SSP port as a SPI master
index 21a3f7250531c6a4e7891843f08f1919a31f890e..8e76ddca0999dd29e50d68f61d4f78c0ba6fbac3 100644 (file)
@@ -341,27 +341,26 @@ out:
 /*
  * ashmem_shrink - our cache shrinker, called from mm/vmscan.c :: shrink_slab
  *
- * 'nr_to_scan' is the number of objects (pages) to prune, or 0 to query how
- * many objects (pages) we have in total.
+ * 'nr_to_scan' is the number of objects to scan for freeing.
  *
  * 'gfp_mask' is the mask of the allocation that got us into this mess.
  *
- * Return value is the number of objects (pages) remaining, or -1 if we cannot
+ * Return value is the number of objects freed or -1 if we cannot
  * proceed without risk of deadlock (due to gfp_mask).
  *
  * We approximate LRU via least-recently-unpinned, jettisoning unpinned partial
  * chunks of ashmem regions LRU-wise one-at-a-time until we hit 'nr_to_scan'
  * pages freed.
  */
-static int ashmem_shrink(struct shrinker *s, struct shrink_control *sc)
+static unsigned long
+ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct ashmem_range *range, *next;
+       unsigned long freed = 0;
 
        /* We might recurse into filesystem code, so bail out if necessary */
-       if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS))
-               return -1;
-       if (!sc->nr_to_scan)
-               return lru_count;
+       if (!(sc->gfp_mask & __GFP_FS))
+               return SHRINK_STOP;
 
        mutex_lock(&ashmem_mutex);
        list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
@@ -374,17 +373,32 @@ static int ashmem_shrink(struct shrinker *s, struct shrink_control *sc)
                range->purged = ASHMEM_WAS_PURGED;
                lru_del(range);
 
-               sc->nr_to_scan -= range_size(range);
-               if (sc->nr_to_scan <= 0)
+               freed += range_size(range);
+               if (--sc->nr_to_scan <= 0)
                        break;
        }
        mutex_unlock(&ashmem_mutex);
+       return freed;
+}
 
+static unsigned long
+ashmem_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+       /*
+        * note that lru_count is count of pages on the lru, not a count of
+        * objects on the list. This means the scan function needs to return the
+        * number of pages freed, not the number of objects scanned.
+        */
        return lru_count;
 }
 
 static struct shrinker ashmem_shrinker = {
-       .shrink = ashmem_shrink,
+       .count_objects = ashmem_shrink_count,
+       .scan_objects = ashmem_shrink_scan,
+       /*
+        * XXX (dchinner): I wish people would comment on why they need on
+        * significant changes to the default value here
+        */
        .seeks = DEFAULT_SEEKS * 4,
 };
 
@@ -690,11 +704,11 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                if (capable(CAP_SYS_ADMIN)) {
                        struct shrink_control sc = {
                                .gfp_mask = GFP_KERNEL,
-                               .nr_to_scan = 0,
+                               .nr_to_scan = LONG_MAX,
                        };
-                       ret = ashmem_shrink(&ashmem_shrinker, &sc);
-                       sc.nr_to_scan = ret;
-                       ashmem_shrink(&ashmem_shrinker, &sc);
+
+                       nodes_setall(sc.nodes_to_scan);
+                       ashmem_shrink_scan(&ashmem_shrinker, &sc);
                }
                break;
        }
index a8c344422a77d5cce6c34fcadfd7d61781d660bc..d42f5785f09833d79684fc9668a23d6451425e9c 100644 (file)
@@ -481,7 +481,7 @@ static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
        header.sec = now.tv_sec;
        header.nsec = now.tv_nsec;
        header.euid = current_euid();
-       header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
+       header.len = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
        header.hdr_size = sizeof(struct logger_entry);
 
        /* null writes succeed, return zero */
index fe74494868ef33037e7e43602471b51780f6c37d..6f094b37f1f1dc0388d07246635eadbe9c7399ff 100644 (file)
@@ -66,11 +66,20 @@ static unsigned long lowmem_deathpending_timeout;
                        pr_info(x);                     \
        } while (0)
 
-static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
+static unsigned long lowmem_count(struct shrinker *s,
+                                 struct shrink_control *sc)
+{
+       return global_page_state(NR_ACTIVE_ANON) +
+               global_page_state(NR_ACTIVE_FILE) +
+               global_page_state(NR_INACTIVE_ANON) +
+               global_page_state(NR_INACTIVE_FILE);
+}
+
+static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
 {
        struct task_struct *tsk;
        struct task_struct *selected = NULL;
-       int rem = 0;
+       unsigned long rem = 0;
        int tasksize;
        int i;
        short min_score_adj = OOM_SCORE_ADJ_MAX + 1;
@@ -92,19 +101,17 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
                        break;
                }
        }
-       if (sc->nr_to_scan > 0)
-               lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %hd\n",
-                               sc->nr_to_scan, sc->gfp_mask, other_free,
-                               other_file, min_score_adj);
-       rem = global_page_state(NR_ACTIVE_ANON) +
-               global_page_state(NR_ACTIVE_FILE) +
-               global_page_state(NR_INACTIVE_ANON) +
-               global_page_state(NR_INACTIVE_FILE);
-       if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
-               lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
-                            sc->nr_to_scan, sc->gfp_mask, rem);
-               return rem;
+
+       lowmem_print(3, "lowmem_scan %lu, %x, ofree %d %d, ma %hd\n",
+                       sc->nr_to_scan, sc->gfp_mask, other_free,
+                       other_file, min_score_adj);
+
+       if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
+               lowmem_print(5, "lowmem_scan %lu, %x, return 0\n",
+                            sc->nr_to_scan, sc->gfp_mask);
+               return 0;
        }
+
        selected_oom_score_adj = min_score_adj;
 
        rcu_read_lock();
@@ -154,16 +161,18 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
                lowmem_deathpending_timeout = jiffies + HZ;
                send_sig(SIGKILL, selected, 0);
                set_tsk_thread_flag(selected, TIF_MEMDIE);
-               rem -= selected_tasksize;
+               rem += selected_tasksize;
        }
-       lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
+
+       lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n",
                     sc->nr_to_scan, sc->gfp_mask, rem);
        rcu_read_unlock();
        return rem;
 }
 
 static struct shrinker lowmem_shrinker = {
-       .shrink = lowmem_shrink,
+       .scan_objects = lowmem_scan,
+       .count_objects = lowmem_count,
        .seeks = DEFAULT_SEEKS * 16
 };
 
index 63efb7b456c6ecf1ad94c4a0a8c72ee25b226dce..2af15d41e77aefe1e9925dce785bdeefe62b0f02 100644 (file)
        do { __oldfs = get_fs(); set_fs(get_ds());} while(0)
 #define MMSPACE_CLOSE         set_fs(__oldfs)
 
-/*
- * Shrinker
- */
-
-# define SHRINKER_ARGS(sc, nr_to_scan, gfp_mask)  \
-                      struct shrinker *shrinker, \
-                      struct shrink_control *sc
-# define shrink_param(sc, var) ((sc)->var)
-
-typedef int (*shrinker_t)(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask));
-
-static inline
-struct shrinker *set_shrinker(int seek, shrinker_t func)
-{
-       struct shrinker *s;
-
-       s = kmalloc(sizeof(*s), GFP_KERNEL);
-       if (s == NULL)
-               return (NULL);
-
-       s->shrink = func;
-       s->seeks = seek;
-
-       register_shrinker(s);
-
-       return s;
-}
-
-static inline
-void remove_shrinker(struct shrinker *shrinker)
-{
-       if (shrinker == NULL)
-               return;
-
-       unregister_shrinker(shrinker);
-       kfree(shrinker);
-}
-
 #endif /* __LINUX_CFS_MEM_H__ */
index 454027d68d5466ca828bde7fed2a96da258930d6..0025ee6356da017941698aa9b6bb6f28711be135 100644 (file)
@@ -521,7 +521,7 @@ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
                                int nr, unsigned int gfp_mask)
 {
        struct ldlm_namespace *ns;
-       int canceled = 0, unused;
+       int unused;
 
        ns = ldlm_pl2ns(pl);
 
@@ -540,14 +540,10 @@ static int ldlm_cli_pool_shrink(struct ldlm_pool *pl,
        unused = ns->ns_nr_unused;
        spin_unlock(&ns->ns_lock);
 
-       if (nr) {
-               canceled = ldlm_cancel_lru(ns, nr, LCF_ASYNC,
-                                          LDLM_CANCEL_SHRINK);
-       }
-       /*
-        * Return the number of potentially reclaimable locks.
-        */
-       return ((unused - canceled) / 100) * sysctl_vfs_cache_pressure;
+       if (nr == 0)
+               return (unused / 100) * sysctl_vfs_cache_pressure;
+       else
+               return ldlm_cancel_lru(ns, nr, LCF_ASYNC, LDLM_CANCEL_SHRINK);
 }
 
 struct ldlm_pool_ops ldlm_srv_pool_ops = {
@@ -601,9 +597,10 @@ int ldlm_pool_recalc(struct ldlm_pool *pl)
        return recalc_interval_sec;
 }
 
-/**
+/*
  * Pool shrink wrapper. Will call either client or server pool recalc callback
- * depending what pool \a pl is used.
+ * depending what pool pl is used. When nr == 0, just return the number of
+ * freeable locks. Otherwise, return the number of canceled locks.
  */
 int ldlm_pool_shrink(struct ldlm_pool *pl, int nr,
                     unsigned int gfp_mask)
@@ -1017,29 +1014,24 @@ static int ldlm_pool_granted(struct ldlm_pool *pl)
 }
 
 static struct ptlrpc_thread *ldlm_pools_thread;
-static struct shrinker *ldlm_pools_srv_shrinker;
-static struct shrinker *ldlm_pools_cli_shrinker;
 static struct completion ldlm_pools_comp;
 
 /*
- * Cancel \a nr locks from all namespaces (if possible). Returns number of
- * cached locks after shrink is finished. All namespaces are asked to
- * cancel approximately equal amount of locks to keep balancing.
+ * count locks from all namespaces (if possible). Returns number of
+ * cached locks.
  */
-static int ldlm_pools_shrink(ldlm_side_t client, int nr,
-                            unsigned int gfp_mask)
+static unsigned long ldlm_pools_count(ldlm_side_t client, unsigned int gfp_mask)
 {
-       int total = 0, cached = 0, nr_ns;
+       int total = 0, nr_ns;
        struct ldlm_namespace *ns;
        struct ldlm_namespace *ns_old = NULL; /* loop detection */
        void *cookie;
 
-       if (client == LDLM_NAMESPACE_CLIENT && nr != 0 &&
-           !(gfp_mask & __GFP_FS))
-               return -1;
+       if (client == LDLM_NAMESPACE_CLIENT && !(gfp_mask & __GFP_FS))
+               return 0;
 
-       CDEBUG(D_DLMTRACE, "Request to shrink %d %s locks from all pools\n",
-              nr, client == LDLM_NAMESPACE_CLIENT ? "client" : "server");
+       CDEBUG(D_DLMTRACE, "Request to count %s locks from all pools\n",
+              client == LDLM_NAMESPACE_CLIENT ? "client" : "server");
 
        cookie = cl_env_reenter();
 
@@ -1047,8 +1039,7 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
         * Find out how many resources we may release.
         */
        for (nr_ns = ldlm_namespace_nr_read(client);
-            nr_ns > 0; nr_ns--)
-       {
+            nr_ns > 0; nr_ns--) {
                mutex_lock(ldlm_namespace_lock(client));
                if (list_empty(ldlm_namespace_list(client))) {
                        mutex_unlock(ldlm_namespace_lock(client));
@@ -1078,17 +1069,27 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
                ldlm_namespace_put(ns);
        }
 
-       if (nr == 0 || total == 0) {
-               cl_env_reexit(cookie);
-               return total;
-       }
+       cl_env_reexit(cookie);
+       return total;
+}
+
+static unsigned long ldlm_pools_scan(ldlm_side_t client, int nr, unsigned int gfp_mask)
+{
+       unsigned long freed = 0;
+       int tmp, nr_ns;
+       struct ldlm_namespace *ns;
+       void *cookie;
+
+       if (client == LDLM_NAMESPACE_CLIENT && !(gfp_mask & __GFP_FS))
+               return -1;
+
+       cookie = cl_env_reenter();
 
        /*
-        * Shrink at least ldlm_namespace_nr(client) namespaces.
+        * Shrink at least ldlm_namespace_nr_read(client) namespaces.
         */
-       for (nr_ns = ldlm_namespace_nr_read(client) - nr_ns;
-            nr_ns > 0; nr_ns--)
-       {
+       for (tmp = nr_ns = ldlm_namespace_nr_read(client);
+            tmp > 0; tmp--) {
                int cancel, nr_locks;
 
                /*
@@ -1097,12 +1098,6 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
                mutex_lock(ldlm_namespace_lock(client));
                if (list_empty(ldlm_namespace_list(client))) {
                        mutex_unlock(ldlm_namespace_lock(client));
-                       /*
-                        * If list is empty, we can't return any @cached > 0,
-                        * that probably would cause needless shrinker
-                        * call.
-                        */
-                       cached = 0;
                        break;
                }
                ns = ldlm_namespace_first_locked(client);
@@ -1111,29 +1106,42 @@ static int ldlm_pools_shrink(ldlm_side_t client, int nr,
                mutex_unlock(ldlm_namespace_lock(client));
 
                nr_locks = ldlm_pool_granted(&ns->ns_pool);
-               cancel = 1 + nr_locks * nr / total;
-               ldlm_pool_shrink(&ns->ns_pool, cancel, gfp_mask);
-               cached += ldlm_pool_granted(&ns->ns_pool);
+               /*
+                * We use to shrink propotionally but with new shrinker API,
+                * we lost the total number of freeable locks.
+                */
+               cancel = 1 + min_t(int, nr_locks, nr / nr_ns);
+               freed += ldlm_pool_shrink(&ns->ns_pool, cancel, gfp_mask);
                ldlm_namespace_put(ns);
        }
        cl_env_reexit(cookie);
-       /* we only decrease the SLV in server pools shrinker, return -1 to
-        * kernel to avoid needless loop. LU-1128 */
-       return (client == LDLM_NAMESPACE_SERVER) ? -1 : cached;
+       /*
+        * we only decrease the SLV in server pools shrinker, return
+        * SHRINK_STOP to kernel to avoid needless loop. LU-1128
+        */
+       return (client == LDLM_NAMESPACE_SERVER) ? SHRINK_STOP : freed;
+}
+
+static unsigned long ldlm_pools_srv_count(struct shrinker *s, struct shrink_control *sc)
+{
+       return ldlm_pools_count(LDLM_NAMESPACE_SERVER, sc->gfp_mask);
 }
 
-static int ldlm_pools_srv_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
+static unsigned long ldlm_pools_srv_scan(struct shrinker *s, struct shrink_control *sc)
 {
-       return ldlm_pools_shrink(LDLM_NAMESPACE_SERVER,
-                                shrink_param(sc, nr_to_scan),
-                                shrink_param(sc, gfp_mask));
+       return ldlm_pools_scan(LDLM_NAMESPACE_SERVER, sc->nr_to_scan,
+                              sc->gfp_mask);
 }
 
-static int ldlm_pools_cli_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
+static unsigned long ldlm_pools_cli_count(struct shrinker *s, struct shrink_control *sc)
 {
-       return ldlm_pools_shrink(LDLM_NAMESPACE_CLIENT,
-                                shrink_param(sc, nr_to_scan),
-                                shrink_param(sc, gfp_mask));
+       return ldlm_pools_count(LDLM_NAMESPACE_CLIENT, sc->gfp_mask);
+}
+
+static unsigned long ldlm_pools_cli_scan(struct shrinker *s, struct shrink_control *sc)
+{
+       return ldlm_pools_scan(LDLM_NAMESPACE_CLIENT, sc->nr_to_scan,
+                              sc->gfp_mask);
 }
 
 int ldlm_pools_recalc(ldlm_side_t client)
@@ -1216,7 +1224,7 @@ int ldlm_pools_recalc(ldlm_side_t client)
        }
 
        /*
-        * Recalc at least ldlm_namespace_nr(client) namespaces.
+        * Recalc at least ldlm_namespace_nr_read(client) namespaces.
         */
        for (nr = ldlm_namespace_nr_read(client); nr > 0; nr--) {
                int     skip;
@@ -1383,18 +1391,26 @@ static void ldlm_pools_thread_stop(void)
        ldlm_pools_thread = NULL;
 }
 
+static struct shrinker ldlm_pools_srv_shrinker = {
+       .count_objects  = ldlm_pools_srv_count,
+       .scan_objects   = ldlm_pools_srv_scan,
+       .seeks          = DEFAULT_SEEKS,
+};
+
+static struct shrinker ldlm_pools_cli_shrinker = {
+       .count_objects  = ldlm_pools_cli_count,
+       .scan_objects   = ldlm_pools_cli_scan,
+       .seeks          = DEFAULT_SEEKS,
+};
+
 int ldlm_pools_init(void)
 {
        int rc;
 
        rc = ldlm_pools_thread_start();
        if (rc == 0) {
-               ldlm_pools_srv_shrinker =
-                       set_shrinker(DEFAULT_SEEKS,
-                                        ldlm_pools_srv_shrink);
-               ldlm_pools_cli_shrinker =
-                       set_shrinker(DEFAULT_SEEKS,
-                                        ldlm_pools_cli_shrink);
+               register_shrinker(&ldlm_pools_srv_shrinker);
+               register_shrinker(&ldlm_pools_cli_shrinker);
        }
        return rc;
 }
@@ -1402,14 +1418,8 @@ EXPORT_SYMBOL(ldlm_pools_init);
 
 void ldlm_pools_fini(void)
 {
-       if (ldlm_pools_srv_shrinker != NULL) {
-               remove_shrinker(ldlm_pools_srv_shrinker);
-               ldlm_pools_srv_shrinker = NULL;
-       }
-       if (ldlm_pools_cli_shrinker != NULL) {
-               remove_shrinker(ldlm_pools_cli_shrinker);
-               ldlm_pools_cli_shrinker = NULL;
-       }
+       unregister_shrinker(&ldlm_pools_srv_shrinker);
+       unregister_shrinker(&ldlm_pools_cli_shrinker);
        ldlm_pools_thread_stop();
 }
 EXPORT_SYMBOL(ldlm_pools_fini);
index 253f02688f4fe32de728e73c5e03859689b3eb0a..bc534db1243169b8866f84b4875ed4852a66c963 100644 (file)
@@ -1009,7 +1009,7 @@ static ssize_t ll_file_read(struct file *file, char *buf, size_t count,
        local_iov->iov_len = count;
        init_sync_kiocb(kiocb, file);
        kiocb->ki_pos = *ppos;
-       kiocb->ki_left = count;
+       kiocb->ki_nbytes = count;
 
        result = ll_file_aio_read(kiocb, local_iov, 1, kiocb->ki_pos);
        *ppos = kiocb->ki_pos;
@@ -1068,7 +1068,7 @@ static ssize_t ll_file_write(struct file *file, const char *buf, size_t count,
        local_iov->iov_len = count;
        init_sync_kiocb(kiocb, file);
        kiocb->ki_pos = *ppos;
-       kiocb->ki_left = count;
+       kiocb->ki_nbytes = count;
 
        result = ll_file_aio_write(kiocb, local_iov, 1, kiocb->ki_pos);
        *ppos = kiocb->ki_pos;
index c29ac1c2defd1850fabfd2186dc80ee0920af7eb..3a3d5bc5a628a05e45def8d74112e55138655a80 100644 (file)
@@ -1779,7 +1779,6 @@ int lu_env_refill_by_tags(struct lu_env *env, __u32 ctags,
 }
 EXPORT_SYMBOL(lu_env_refill_by_tags);
 
-static struct shrinker *lu_site_shrinker = NULL;
 
 typedef struct lu_site_stats{
        unsigned        lss_populated;
@@ -1835,61 +1834,68 @@ static void lu_site_stats_get(cfs_hash_t *hs,
  * objects without taking the  lu_sites_guard lock, but this is not
  * possible in the current implementation.
  */
-static int lu_cache_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
+static unsigned long lu_cache_shrink_count(struct shrinker *sk,
+                                          struct shrink_control *sc)
 {
        lu_site_stats_t stats;
        struct lu_site *s;
        struct lu_site *tmp;
-       int cached = 0;
-       int remain = shrink_param(sc, nr_to_scan);
-       LIST_HEAD(splice);
-
-       if (!(shrink_param(sc, gfp_mask) & __GFP_FS)) {
-               if (remain != 0)
-                       return -1;
-               else
-                       /* We must not take the lu_sites_guard lock when
-                        * __GFP_FS is *not* set because of the deadlock
-                        * possibility detailed above. Additionally,
-                        * since we cannot determine the number of
-                        * objects in the cache without taking this
-                        * lock, we're in a particularly tough spot. As
-                        * a result, we'll just lie and say our cache is
-                        * empty. This _should_ be ok, as we can't
-                        * reclaim objects when __GFP_FS is *not* set
-                        * anyways.
-                        */
-                       return 0;
-       }
+       unsigned long cached = 0;
 
-       CDEBUG(D_INODE, "Shrink %d objects\n", remain);
+       if (!(sc->gfp_mask & __GFP_FS))
+               return 0;
 
        mutex_lock(&lu_sites_guard);
        list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage) {
-               if (shrink_param(sc, nr_to_scan) != 0) {
-                       remain = lu_site_purge(&lu_shrink_env, s, remain);
-                       /*
-                        * Move just shrunk site to the tail of site list to
-                        * assure shrinking fairness.
-                        */
-                       list_move_tail(&s->ls_linkage, &splice);
-               }
-
                memset(&stats, 0, sizeof(stats));
                lu_site_stats_get(s->ls_obj_hash, &stats, 0);
                cached += stats.lss_total - stats.lss_busy;
-               if (shrink_param(sc, nr_to_scan) && remain <= 0)
-                       break;
        }
-       list_splice(&splice, lu_sites.prev);
        mutex_unlock(&lu_sites_guard);
 
        cached = (cached / 100) * sysctl_vfs_cache_pressure;
-       if (shrink_param(sc, nr_to_scan) == 0)
-               CDEBUG(D_INODE, "%d objects cached\n", cached);
+       CDEBUG(D_INODE, "%ld objects cached\n", cached);
        return cached;
 }
 
+static unsigned long lu_cache_shrink_scan(struct shrinker *sk,
+                                         struct shrink_control *sc)
+{
+       struct lu_site *s;
+       struct lu_site *tmp;
+       unsigned long remain = sc->nr_to_scan, freed = 0;
+       LIST_HEAD(splice);
+
+       if (!(sc->gfp_mask & __GFP_FS))
+               /* We must not take the lu_sites_guard lock when
+                * __GFP_FS is *not* set because of the deadlock
+                * possibility detailed above. Additionally,
+                * since we cannot determine the number of
+                * objects in the cache without taking this
+                * lock, we're in a particularly tough spot. As
+                * a result, we'll just lie and say our cache is
+                * empty. This _should_ be ok, as we can't
+                * reclaim objects when __GFP_FS is *not* set
+                * anyways.
+                */
+               return SHRINK_STOP;
+
+       mutex_lock(&lu_sites_guard);
+       list_for_each_entry_safe(s, tmp, &lu_sites, ls_linkage) {
+               freed = lu_site_purge(&lu_shrink_env, s, remain);
+               remain -= freed;
+               /*
+                * Move just shrunk site to the tail of site list to
+                * assure shrinking fairness.
+                */
+               list_move_tail(&s->ls_linkage, &splice);
+       }
+       list_splice(&splice, lu_sites.prev);
+       mutex_unlock(&lu_sites_guard);
+
+       return sc->nr_to_scan - remain;
+}
+
 /*
  * Debugging stuff.
  */
@@ -1913,6 +1919,12 @@ int lu_printk_printer(const struct lu_env *env,
        return 0;
 }
 
+static struct shrinker lu_site_shrinker = {
+       .count_objects  = lu_cache_shrink_count,
+       .scan_objects   = lu_cache_shrink_scan,
+       .seeks          = DEFAULT_SEEKS,
+};
+
 /**
  * Initialization of global lu_* data.
  */
@@ -1947,9 +1959,7 @@ int lu_global_init(void)
         * inode, one for ea. Unfortunately setting this high value results in
         * lu_object/inode cache consuming all the memory.
         */
-       lu_site_shrinker = set_shrinker(DEFAULT_SEEKS, lu_cache_shrink);
-       if (lu_site_shrinker == NULL)
-               return -ENOMEM;
+       register_shrinker(&lu_site_shrinker);
 
        return result;
 }
@@ -1959,11 +1969,7 @@ int lu_global_init(void)
  */
 void lu_global_fini(void)
 {
-       if (lu_site_shrinker != NULL) {
-               remove_shrinker(lu_site_shrinker);
-               lu_site_shrinker = NULL;
-       }
-
+       unregister_shrinker(&lu_site_shrinker);
        lu_context_key_degister(&lu_global_key);
 
        /*
index 9013745ab1059fb716e2f1cb6df2166cd163b4a1..e90c8fb7da6a73643531c1cd1914d5826a280c2d 100644 (file)
@@ -120,13 +120,6 @@ static struct ptlrpc_enc_page_pool {
        struct page    ***epp_pools;
 } page_pools;
 
-/*
- * memory shrinker
- */
-const int pools_shrinker_seeks = DEFAULT_SEEKS;
-static struct shrinker *pools_shrinker = NULL;
-
-
 /*
  * /proc/fs/lustre/sptlrpc/encrypt_page_pools
  */
@@ -226,30 +219,46 @@ static void enc_pools_release_free_pages(long npages)
 }
 
 /*
- * could be called frequently for query (@nr_to_scan == 0).
  * we try to keep at least PTLRPC_MAX_BRW_PAGES pages in the pool.
  */
-static int enc_pools_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
+static unsigned long enc_pools_shrink_count(struct shrinker *s,
+                                           struct shrink_control *sc)
 {
-       if (unlikely(shrink_param(sc, nr_to_scan) != 0)) {
+       /*
+        * if no pool access for a long time, we consider it's fully idle.
+        * a little race here is fine.
+        */
+       if (unlikely(cfs_time_current_sec() - page_pools.epp_last_access >
+                    CACHE_QUIESCENT_PERIOD)) {
                spin_lock(&page_pools.epp_lock);
-               shrink_param(sc, nr_to_scan) = min_t(unsigned long,
-                                                  shrink_param(sc, nr_to_scan),
-                                                  page_pools.epp_free_pages -
-                                                  PTLRPC_MAX_BRW_PAGES);
-               if (shrink_param(sc, nr_to_scan) > 0) {
-                       enc_pools_release_free_pages(shrink_param(sc,
-                                                                 nr_to_scan));
-                       CDEBUG(D_SEC, "released %ld pages, %ld left\n",
-                              (long)shrink_param(sc, nr_to_scan),
-                              page_pools.epp_free_pages);
-
-                       page_pools.epp_st_shrinks++;
-                       page_pools.epp_last_shrink = cfs_time_current_sec();
-               }
+               page_pools.epp_idle_idx = IDLE_IDX_MAX;
                spin_unlock(&page_pools.epp_lock);
        }
 
+       LASSERT(page_pools.epp_idle_idx <= IDLE_IDX_MAX);
+       return max((int)page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES, 0) *
+               (IDLE_IDX_MAX - page_pools.epp_idle_idx) / IDLE_IDX_MAX;
+}
+
+/*
+ * we try to keep at least PTLRPC_MAX_BRW_PAGES pages in the pool.
+ */
+static unsigned long enc_pools_shrink_scan(struct shrinker *s,
+                                          struct shrink_control *sc)
+{
+       spin_lock(&page_pools.epp_lock);
+       sc->nr_to_scan = min_t(unsigned long, sc->nr_to_scan,
+                             page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES);
+       if (sc->nr_to_scan > 0) {
+               enc_pools_release_free_pages(sc->nr_to_scan);
+               CDEBUG(D_SEC, "released %ld pages, %ld left\n",
+                      (long)sc->nr_to_scan, page_pools.epp_free_pages);
+
+               page_pools.epp_st_shrinks++;
+               page_pools.epp_last_shrink = cfs_time_current_sec();
+       }
+       spin_unlock(&page_pools.epp_lock);
+
        /*
         * if no pool access for a long time, we consider it's fully idle.
         * a little race here is fine.
@@ -262,8 +271,7 @@ static int enc_pools_shrink(SHRINKER_ARGS(sc, nr_to_scan, gfp_mask))
        }
 
        LASSERT(page_pools.epp_idle_idx <= IDLE_IDX_MAX);
-       return max((int)page_pools.epp_free_pages - PTLRPC_MAX_BRW_PAGES, 0) *
-               (IDLE_IDX_MAX - page_pools.epp_idle_idx) / IDLE_IDX_MAX;
+       return sc->nr_to_scan;
 }
 
 static inline
@@ -699,6 +707,12 @@ static inline void enc_pools_free(void)
                       sizeof(*page_pools.epp_pools));
 }
 
+static struct shrinker pools_shrinker = {
+       .count_objects  = enc_pools_shrink_count,
+       .scan_objects   = enc_pools_shrink_scan,
+       .seeks          = DEFAULT_SEEKS,
+};
+
 int sptlrpc_enc_pool_init(void)
 {
        /*
@@ -736,12 +750,7 @@ int sptlrpc_enc_pool_init(void)
        if (page_pools.epp_pools == NULL)
                return -ENOMEM;
 
-       pools_shrinker = set_shrinker(pools_shrinker_seeks,
-                                         enc_pools_shrink);
-       if (pools_shrinker == NULL) {
-               enc_pools_free();
-               return -ENOMEM;
-       }
+       register_shrinker(&pools_shrinker);
 
        return 0;
 }
@@ -750,11 +759,10 @@ void sptlrpc_enc_pool_fini(void)
 {
        unsigned long cleaned, npools;
 
-       LASSERT(pools_shrinker);
        LASSERT(page_pools.epp_pools);
        LASSERT(page_pools.epp_total_pages == page_pools.epp_free_pages);
 
-       remove_shrinker(pools_shrinker);
+       unregister_shrinker(&pools_shrinker);
 
        npools = npages_to_npools(page_pools.epp_total_pages);
        cleaned = enc_pools_cleanup(page_pools.epp_pools, npools);
index 78b6cb7437695a2f36a3d04adcb338346596b37c..199059d64c9b56796a8a3fb3cf4157ed3ee71ab5 100644 (file)
@@ -48,13 +48,8 @@ static int cvm_oct_fill_hw_skbuff(int pool, int size, int elements)
        while (freed) {
 
                struct sk_buff *skb = dev_alloc_skb(size + 256);
-               if (unlikely(skb == NULL)) {
-                       pr_warning
-                           ("Failed to allocate skb for hardware pool %d\n",
-                            pool);
+               if (unlikely(skb == NULL))
                        break;
-               }
-
                skb_reserve(skb, 256 - (((unsigned long)skb->data) & 0x7f));
                *(struct sk_buff **)(skb->data - sizeof(void *)) = skb;
                cvmx_fpa_free(skb->data, pool, DONT_WRITEBACK(size / 128));
index d8f5f694ec35532055781ff48b6edd79f4e502cd..ea53af30dfa7c619f7d500a8dc3518d648916270 100644 (file)
@@ -373,9 +373,7 @@ int cvm_oct_rgmii_init(struct net_device *dev)
                         * Enable interrupts on inband status changes
                         * for this port.
                         */
-                       gmx_rx_int_en.u64 =
-                           cvmx_read_csr(CVMX_GMXX_RXX_INT_EN
-                                         (index, interface));
+                       gmx_rx_int_en.u64 = 0;
                        gmx_rx_int_en.s.phy_dupx = 1;
                        gmx_rx_int_en.s.phy_link = 1;
                        gmx_rx_int_en.s.phy_spd = 1;
index 34afc16bc4935e35f5e47c12d27925f6fe7c62f3..e14a1bb0436129da4c7f969c4f477063d78da1d9 100644 (file)
@@ -303,6 +303,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
                        if (backlog > budget * cores_in_use && napi != NULL)
                                cvm_oct_enable_one_cpu();
                }
+               rx_count++;
 
                skb_in_hw = USE_SKBUFFS_IN_HW && work->word2.s.bufs == 1;
                if (likely(skb_in_hw)) {
@@ -336,9 +337,6 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
                         */
                        skb = dev_alloc_skb(work->len);
                        if (!skb) {
-                               printk_ratelimited("Port %d failed to allocate "
-                                                  "skbuff, packet dropped\n",
-                                                  work->ipprt);
                                cvm_oct_free_work(work);
                                continue;
                        }
@@ -429,7 +427,6 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
 #endif
                                }
                                netif_receive_skb(skb);
-                               rx_count++;
                        } else {
                                /* Drop any packet received for a device that isn't up */
                                /*
index 9fdcb561422ff844346598d0f3057bf8c3cff439..85b012d2f89bb2bce6b69a446adbd3b878ae76be 100644 (file)
@@ -13,7 +13,8 @@ target_core_mod-y             := target_core_configfs.o \
                                   target_core_spc.o \
                                   target_core_ua.o \
                                   target_core_rd.o \
-                                  target_core_stat.o
+                                  target_core_stat.o \
+                                  target_core_xcopy.o
 
 obj-$(CONFIG_TARGET_CORE)      += target_core_mod.o
 
index 3a179302b9044318ac41d5e81b4cdfa853274c5d..35b61f7d6c6305f79535c3c9e7d8dbbd8bd788dc 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains main functions related to the iSCSI Target Core Driver.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -63,7 +61,6 @@ spinlock_t sess_idr_lock;
 
 struct iscsit_global *iscsit_global;
 
-struct kmem_cache *lio_cmd_cache;
 struct kmem_cache *lio_qr_cache;
 struct kmem_cache *lio_dr_cache;
 struct kmem_cache *lio_ooo_cache;
@@ -220,11 +217,6 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
                spin_unlock_bh(&np->np_thread_lock);
                return -1;
        }
-       if (np->np_login_tpg) {
-               pr_err("np->np_login_tpg() is not NULL!\n");
-               spin_unlock_bh(&np->np_thread_lock);
-               return -1;
-       }
        spin_unlock_bh(&np->np_thread_lock);
        /*
         * Determine if the portal group is accepting storage traffic.
@@ -239,26 +231,38 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
        /*
         * Here we serialize access across the TIQN+TPG Tuple.
         */
-       ret = mutex_lock_interruptible(&tpg->np_login_lock);
+       ret = down_interruptible(&tpg->np_login_sem);
        if ((ret != 0) || signal_pending(current))
                return -1;
 
-       spin_lock_bh(&np->np_thread_lock);
-       np->np_login_tpg = tpg;
-       spin_unlock_bh(&np->np_thread_lock);
+       spin_lock_bh(&tpg->tpg_state_lock);
+       if (tpg->tpg_state != TPG_STATE_ACTIVE) {
+               spin_unlock_bh(&tpg->tpg_state_lock);
+               up(&tpg->np_login_sem);
+               return -1;
+       }
+       spin_unlock_bh(&tpg->tpg_state_lock);
 
        return 0;
 }
 
-int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg)
+void iscsit_login_kref_put(struct kref *kref)
+{
+       struct iscsi_tpg_np *tpg_np = container_of(kref,
+                               struct iscsi_tpg_np, tpg_np_kref);
+
+       complete(&tpg_np->tpg_np_comp);
+}
+
+int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg,
+                      struct iscsi_tpg_np *tpg_np)
 {
        struct iscsi_tiqn *tiqn = tpg->tpg_tiqn;
 
-       spin_lock_bh(&np->np_thread_lock);
-       np->np_login_tpg = NULL;
-       spin_unlock_bh(&np->np_thread_lock);
+       up(&tpg->np_login_sem);
 
-       mutex_unlock(&tpg->np_login_lock);
+       if (tpg_np)
+               kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
 
        if (tiqn)
                iscsit_put_tiqn_for_login(tiqn);
@@ -410,20 +414,10 @@ struct iscsi_np *iscsit_add_np(
 int iscsit_reset_np_thread(
        struct iscsi_np *np,
        struct iscsi_tpg_np *tpg_np,
-       struct iscsi_portal_group *tpg)
+       struct iscsi_portal_group *tpg,
+       bool shutdown)
 {
        spin_lock_bh(&np->np_thread_lock);
-       if (tpg && tpg_np) {
-               /*
-                * The reset operation need only be performed when the
-                * passed struct iscsi_portal_group has a login in progress
-                * to one of the network portals.
-                */
-               if (tpg_np->tpg_np->np_login_tpg != tpg) {
-                       spin_unlock_bh(&np->np_thread_lock);
-                       return 0;
-               }
-       }
        if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) {
                spin_unlock_bh(&np->np_thread_lock);
                return 0;
@@ -438,6 +432,12 @@ int iscsit_reset_np_thread(
        }
        spin_unlock_bh(&np->np_thread_lock);
 
+       if (tpg_np && shutdown) {
+               kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
+
+               wait_for_completion(&tpg_np->tpg_np_comp);
+       }
+
        return 0;
 }
 
@@ -497,7 +497,6 @@ static struct iscsit_transport iscsi_target_transport = {
        .iscsit_setup_np        = iscsit_setup_np,
        .iscsit_accept_np       = iscsit_accept_np,
        .iscsit_free_np         = iscsit_free_np,
-       .iscsit_alloc_cmd       = iscsit_alloc_cmd,
        .iscsit_get_login_rx    = iscsit_get_login_rx,
        .iscsit_put_login_tx    = iscsit_put_login_tx,
        .iscsit_get_dataout     = iscsit_build_r2ts_for_cmd,
@@ -538,22 +537,13 @@ static int __init iscsi_target_init_module(void)
                goto ts_out1;
        }
 
-       lio_cmd_cache = kmem_cache_create("lio_cmd_cache",
-                       sizeof(struct iscsi_cmd), __alignof__(struct iscsi_cmd),
-                       0, NULL);
-       if (!lio_cmd_cache) {
-               pr_err("Unable to kmem_cache_create() for"
-                               " lio_cmd_cache\n");
-               goto ts_out2;
-       }
-
        lio_qr_cache = kmem_cache_create("lio_qr_cache",
                        sizeof(struct iscsi_queue_req),
                        __alignof__(struct iscsi_queue_req), 0, NULL);
        if (!lio_qr_cache) {
                pr_err("nable to kmem_cache_create() for"
                                " lio_qr_cache\n");
-               goto cmd_out;
+               goto ts_out2;
        }
 
        lio_dr_cache = kmem_cache_create("lio_dr_cache",
@@ -597,8 +587,6 @@ dr_out:
        kmem_cache_destroy(lio_dr_cache);
 qr_out:
        kmem_cache_destroy(lio_qr_cache);
-cmd_out:
-       kmem_cache_destroy(lio_cmd_cache);
 ts_out2:
        iscsi_deallocate_thread_sets();
 ts_out1:
@@ -616,7 +604,6 @@ static void __exit iscsi_target_cleanup_module(void)
        iscsi_thread_set_free();
        iscsit_release_discovery_tpg();
        iscsit_unregister_transport(&iscsi_target_transport);
-       kmem_cache_destroy(lio_cmd_cache);
        kmem_cache_destroy(lio_qr_cache);
        kmem_cache_destroy(lio_dr_cache);
        kmem_cache_destroy(lio_ooo_cache);
@@ -3447,12 +3434,10 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd)
                                bool inaddr_any = iscsit_check_inaddr_any(np);
 
                                len = sprintf(buf, "TargetAddress="
-                                       "%s%s%s:%hu,%hu",
-                                       (np->np_sockaddr.ss_family == AF_INET6) ?
-                                       "[" : "", (inaddr_any == false) ?
+                                       "%s:%hu,%hu",
+                                       (inaddr_any == false) ?
                                                np->np_ip : conn->local_ip,
-                                       (np->np_sockaddr.ss_family == AF_INET6) ?
-                                       "]" : "", (inaddr_any == false) ?
+                                       (inaddr_any == false) ?
                                                np->np_port : conn->local_port,
                                        tpg->tpgt);
                                len += 1;
index 2c437cb8ca00eedfd05f6ff8747f42acc5195375..e936d56fb523988cf29e0a66c2ea097c5b05a7e0 100644 (file)
@@ -7,13 +7,15 @@ extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *);
 extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *);
 extern void iscsit_del_tiqn(struct iscsi_tiqn *);
 extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *);
-extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *);
+extern void iscsit_login_kref_put(struct kref *);
+extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *,
+                               struct iscsi_tpg_np *);
 extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *,
                                struct iscsi_np *, int);
 extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *,
                                char *, int);
 extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *,
-                               struct iscsi_portal_group *);
+                               struct iscsi_portal_group *, bool);
 extern int iscsit_del_np(struct iscsi_np *);
 extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *);
 extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *);
@@ -37,7 +39,6 @@ extern struct target_fabric_configfs *lio_target_fabric_configfs;
 
 extern struct kmem_cache *lio_dr_cache;
 extern struct kmem_cache *lio_ooo_cache;
-extern struct kmem_cache *lio_cmd_cache;
 extern struct kmem_cache *lio_qr_cache;
 extern struct kmem_cache *lio_r2t_cache;
 
index cee17543278ceea34ef478f80db2940f3f58fd31..7505fddca15f639b0a40fde300a2ca19c19d37bd 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file houses the main functions for the iSCSI CHAP support
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index bbfd28893164e612c672823f97191eaa34c10bb7..fd145259361ddd0773500307ce8820fa7873db8b 100644 (file)
@@ -2,9 +2,7 @@
  * This file contains the configfs implementation for iSCSI Target mode
  * from the LIO-Target Project.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -265,9 +263,9 @@ static struct se_tpg_np *lio_target_call_addnptotpg(
                *port_str = '\0'; /* Terminate string for IP */
                port_str++; /* Skip over ":" */
 
-               ret = strict_strtoul(port_str, 0, &port);
+               ret = kstrtoul(port_str, 0, &port);
                if (ret < 0) {
-                       pr_err("strict_strtoul() failed for port_str: %d\n", ret);
+                       pr_err("kstrtoul() failed for port_str: %d\n", ret);
                        return ERR_PTR(ret);
                }
                sock_in6 = (struct sockaddr_in6 *)&sockaddr;
@@ -290,9 +288,9 @@ static struct se_tpg_np *lio_target_call_addnptotpg(
                *port_str = '\0'; /* Terminate string for IP */
                port_str++; /* Skip over ":" */
 
-               ret = strict_strtoul(port_str, 0, &port);
+               ret = kstrtoul(port_str, 0, &port);
                if (ret < 0) {
-                       pr_err("strict_strtoul() failed for port_str: %d\n", ret);
+                       pr_err("kstrtoul() failed for port_str: %d\n", ret);
                        return ERR_PTR(ret);
                }
                sock_in = (struct sockaddr_in *)&sockaddr;
@@ -1481,7 +1479,7 @@ static ssize_t lio_target_wwn_show_attr_lio_version(
        struct target_fabric_configfs *tf,
        char *page)
 {
-       return sprintf(page, "RisingTide Systems Linux-iSCSI Target "ISCSIT_VERSION"\n");
+       return sprintf(page, "Datera Inc. iSCSI Target "ISCSIT_VERSION"\n");
 }
 
 TF_WWN_ATTR_RO(lio_target, lio_version);
@@ -1925,7 +1923,7 @@ static void lio_release_cmd(struct se_cmd *se_cmd)
        struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd);
 
        pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd);
-       cmd->release_cmd(cmd);
+       iscsit_release_cmd(cmd);
 }
 
 /* End functions for target_core_fabric_ops */
index 4f77a78edef9dbfc26f218ca3e6147e986a5ebc8..9a5721b8ff96f83edee065f8d27d933e3aad33ac 100644 (file)
@@ -9,7 +9,7 @@
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
 
-#define ISCSIT_VERSION                 "v4.1.0-rc2"
+#define ISCSIT_VERSION                 "v4.1.0"
 #define ISCSI_MAX_DATASN_MISSING_COUNT 16
 #define ISCSI_TX_THREAD_TCP_TIMEOUT    2
 #define ISCSI_RX_THREAD_TCP_TIMEOUT    2
@@ -17,6 +17,9 @@
 #define SECONDS_FOR_ASYNC_TEXT         10
 #define SECONDS_FOR_LOGOUT_COMP                15
 #define WHITE_SPACE                    " \t\v\f\n\r"
+#define ISCSIT_MIN_TAGS                        16
+#define ISCSIT_EXTRA_TAGS              8
+#define ISCSIT_TCP_BACKLOG             256
 
 /* struct iscsi_node_attrib sanity values */
 #define NA_DATAOUT_TIMEOUT             3
@@ -47,7 +50,7 @@
 #define TA_NETIF_TIMEOUT_MAX           15
 #define TA_NETIF_TIMEOUT_MIN           2
 #define TA_GENERATE_NODE_ACLS          0
-#define TA_DEFAULT_CMDSN_DEPTH         16
+#define TA_DEFAULT_CMDSN_DEPTH         64
 #define TA_DEFAULT_CMDSN_DEPTH_MAX     512
 #define TA_DEFAULT_CMDSN_DEPTH_MIN     1
 #define TA_CACHE_DYNAMIC_ACLS          0
@@ -489,7 +492,6 @@ struct iscsi_cmd {
        u32                     first_data_sg_off;
        u32                     kmapped_nents;
        sense_reason_t          sense_reason;
-       void (*release_cmd)(struct iscsi_cmd *);
 }  ____cacheline_aligned;
 
 struct iscsi_tmr_req {
@@ -554,9 +556,19 @@ struct iscsi_conn {
        struct completion       rx_half_close_comp;
        /* socket used by this connection */
        struct socket           *sock;
+       void                    (*orig_data_ready)(struct sock *, int);
+       void                    (*orig_state_change)(struct sock *);
+#define LOGIN_FLAGS_READ_ACTIVE                1
+#define LOGIN_FLAGS_CLOSED             2
+#define LOGIN_FLAGS_READY              4
+       unsigned long           login_flags;
+       struct delayed_work     login_work;
+       struct delayed_work     login_cleanup_work;
+       struct iscsi_login      *login;
        struct timer_list       nopin_timer;
        struct timer_list       nopin_response_timer;
        struct timer_list       transport_timer;
+       struct task_struct      *login_kworker;
        /* Spinlock used for add/deleting cmd's from conn_cmd_list */
        spinlock_t              cmd_lock;
        spinlock_t              conn_usage_lock;
@@ -584,6 +596,7 @@ struct iscsi_conn {
        void                    *context;
        struct iscsi_login_thread_s *login_thread;
        struct iscsi_portal_group *tpg;
+       struct iscsi_tpg_np     *tpg_np;
        /* Pointer to parent session */
        struct iscsi_session    *sess;
        /* Pointer to thread_set in use for this conn's threads */
@@ -682,6 +695,7 @@ struct iscsi_login {
        u8 version_max;
        u8 login_complete;
        u8 login_failed;
+       bool zero_tsih;
        char isid[6];
        u32 cmd_sn;
        itt_t init_task_tag;
@@ -694,6 +708,7 @@ struct iscsi_login {
        char *req_buf;
        char *rsp_buf;
        struct iscsi_conn *conn;
+       struct iscsi_np *np;
 } ____cacheline_aligned;
 
 struct iscsi_node_attrib {
@@ -773,7 +788,6 @@ struct iscsi_np {
        struct __kernel_sockaddr_storage np_sockaddr;
        struct task_struct      *np_thread;
        struct timer_list       np_login_timer;
-       struct iscsi_portal_group *np_login_tpg;
        void                    *np_context;
        struct iscsit_transport *np_transport;
        struct list_head        np_list;
@@ -788,6 +802,8 @@ struct iscsi_tpg_np {
        struct list_head        tpg_np_parent_list;
        struct se_tpg_np        se_tpg_np;
        spinlock_t              tpg_np_parent_lock;
+       struct completion       tpg_np_comp;
+       struct kref             tpg_np_kref;
 };
 
 struct iscsi_portal_group {
@@ -809,7 +825,7 @@ struct iscsi_portal_group {
        spinlock_t              tpg_state_lock;
        struct se_portal_group tpg_se_tpg;
        struct mutex            tpg_access_lock;
-       struct mutex            np_login_lock;
+       struct semaphore        np_login_sem;
        struct iscsi_tpg_attrib tpg_attrib;
        struct iscsi_node_auth  tpg_demo_auth;
        /* Pointer to default list of iSCSI parameters for TPG */
index 848fee7689485643a6231a09e84e8c5dc0d05d81..e93d5a7a3f8168b9330cbd2ff6238f7a588c88f4 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains the iSCSI Target DataIN value generation functions.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 1b74033510a09f0bd7a3df6633b8e3a54bb4e70a..6c7a5104a4cd108b526ec8754c2dc0bd7fa99102 100644 (file)
@@ -2,9 +2,7 @@
  * This file contains the iSCSI Virtual Device and Disk Transport
  * agnostic related functions.
  *
- \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 08bd87833321c09b14938c210b14e76d2f24a618..41052e512d92f5731a6f02e6fd3fe1f2eaa8e925 100644 (file)
@@ -2,9 +2,7 @@
  * This file contains error recovery level zero functions used by
  * the iSCSI Target driver.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 586c268679a450aa9b382d9d42b23ca5dfe0cf35..e048d6439f4a67bac09c27010bc07953ddac78d4 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains error recovery level one used by the iSCSI Target driver.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 45a5afd5ea13b2eda8bfb11de4f6f238e3996219..33be1fb1df32f2850b6ceb1d54b3b5340a2b6bb1 100644 (file)
@@ -2,9 +2,7 @@
  * This file contains error recovery level two functions used by
  * the iSCSI Target driver.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index bc788c52b6cc861d9c2dfd3753b723c70f09b7b0..1794c753954ab95cd56cdbdd85023bc69ba3d39c 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains the login functions used by the iSCSI Target driver.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -50,6 +48,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn)
                pr_err("Unable to allocate memory for struct iscsi_login.\n");
                return NULL;
        }
+       conn->login = login;
        login->conn = conn;
        login->first_request = 1;
 
@@ -428,7 +427,7 @@ static int iscsi_login_zero_tsih_s2(
                                ISCSI_LOGIN_STATUS_NO_RESOURCES);
                        return -1;
                }
-               rc = strict_strtoul(param->value, 0, &mrdsl);
+               rc = kstrtoul(param->value, 0, &mrdsl);
                if (rc < 0) {
                        iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_NO_RESOURCES);
@@ -684,7 +683,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn)
                iscsit_start_nopin_timer(conn);
 }
 
-static int iscsi_post_login_handler(
+int iscsi_post_login_handler(
        struct iscsi_np *np,
        struct iscsi_conn *conn,
        u8 zero_tsih)
@@ -872,7 +871,7 @@ int iscsit_setup_np(
        struct __kernel_sockaddr_storage *sockaddr)
 {
        struct socket *sock = NULL;
-       int backlog = 5, ret, opt = 0, len;
+       int backlog = ISCSIT_TCP_BACKLOG, ret, opt = 0, len;
 
        switch (np->np_network_transport) {
        case ISCSI_TCP:
@@ -1007,16 +1006,24 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn)
                rc = conn->sock->ops->getname(conn->sock,
                                (struct sockaddr *)&sock_in6, &err, 1);
                if (!rc) {
-                       snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c",
-                               &sock_in6.sin6_addr.in6_u);
+                       if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr))
+                               snprintf(conn->login_ip, sizeof(conn->login_ip), "[%pI6c]",
+                                       &sock_in6.sin6_addr.in6_u);
+                       else
+                               snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI4",
+                                       &sock_in6.sin6_addr.s6_addr32[3]);
                        conn->login_port = ntohs(sock_in6.sin6_port);
                }
 
                rc = conn->sock->ops->getname(conn->sock,
                                (struct sockaddr *)&sock_in6, &err, 0);
                if (!rc) {
-                       snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c",
-                               &sock_in6.sin6_addr.in6_u);
+                       if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr))
+                               snprintf(conn->local_ip, sizeof(conn->local_ip), "[%pI6c]",
+                                       &sock_in6.sin6_addr.in6_u);
+                       else
+                               snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI4",
+                                       &sock_in6.sin6_addr.s6_addr32[3]);
                        conn->local_port = ntohs(sock_in6.sin6_port);
                }
        } else {
@@ -1116,6 +1123,77 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t)
        return 0;
 }
 
+void iscsi_target_login_sess_out(struct iscsi_conn *conn,
+               struct iscsi_np *np, bool zero_tsih, bool new_sess)
+{
+       if (new_sess == false)
+               goto old_sess_out;
+
+       pr_err("iSCSI Login negotiation failed.\n");
+       iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
+                                  ISCSI_LOGIN_STATUS_INIT_ERR);
+       if (!zero_tsih || !conn->sess)
+               goto old_sess_out;
+       if (conn->sess->se_sess)
+               transport_free_session(conn->sess->se_sess);
+       if (conn->sess->session_index != 0) {
+               spin_lock_bh(&sess_idr_lock);
+               idr_remove(&sess_idr, conn->sess->session_index);
+               spin_unlock_bh(&sess_idr_lock);
+       }
+       kfree(conn->sess->sess_ops);
+       kfree(conn->sess);
+
+old_sess_out:
+       iscsi_stop_login_thread_timer(np);
+       /*
+        * If login negotiation fails check if the Time2Retain timer
+        * needs to be restarted.
+        */
+       if (!zero_tsih && conn->sess) {
+               spin_lock_bh(&conn->sess->conn_lock);
+               if (conn->sess->session_state == TARG_SESS_STATE_FAILED) {
+                       struct se_portal_group *se_tpg =
+                                       &ISCSI_TPG_C(conn)->tpg_se_tpg;
+
+                       atomic_set(&conn->sess->session_continuation, 0);
+                       spin_unlock_bh(&conn->sess->conn_lock);
+                       spin_lock_bh(&se_tpg->session_lock);
+                       iscsit_start_time2retain_handler(conn->sess);
+                       spin_unlock_bh(&se_tpg->session_lock);
+               } else
+                       spin_unlock_bh(&conn->sess->conn_lock);
+               iscsit_dec_session_usage_count(conn->sess);
+       }
+
+       if (!IS_ERR(conn->conn_rx_hash.tfm))
+               crypto_free_hash(conn->conn_rx_hash.tfm);
+       if (!IS_ERR(conn->conn_tx_hash.tfm))
+               crypto_free_hash(conn->conn_tx_hash.tfm);
+
+       if (conn->conn_cpumask)
+               free_cpumask_var(conn->conn_cpumask);
+
+       kfree(conn->conn_ops);
+
+       if (conn->param_list) {
+               iscsi_release_param_list(conn->param_list);
+               conn->param_list = NULL;
+       }
+       iscsi_target_nego_release(conn);
+
+       if (conn->sock) {
+               sock_release(conn->sock);
+               conn->sock = NULL;
+       }
+
+       if (conn->conn_transport->iscsit_free_conn)
+               conn->conn_transport->iscsit_free_conn(conn);
+
+       iscsit_put_transport(conn->conn_transport);
+       kfree(conn);
+}
+
 static int __iscsi_target_login_thread(struct iscsi_np *np)
 {
        u8 *buffer, zero_tsih = 0;
@@ -1124,6 +1202,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        struct iscsi_login *login;
        struct iscsi_portal_group *tpg = NULL;
        struct iscsi_login_req *pdu;
+       struct iscsi_tpg_np *tpg_np;
+       bool new_sess = false;
 
        flush_signals(current);
 
@@ -1264,6 +1344,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
                tpg = conn->tpg;
                goto new_sess_out;
        }
+       login->zero_tsih = zero_tsih;
 
        tpg = conn->tpg;
        if (!tpg) {
@@ -1279,7 +1360,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
                        goto old_sess_out;
        }
 
-       if (iscsi_target_start_negotiation(login, conn) < 0)
+       ret = iscsi_target_start_negotiation(login, conn);
+       if (ret < 0)
                goto new_sess_out;
 
        if (!conn->sess) {
@@ -1292,84 +1374,32 @@ static int __iscsi_target_login_thread(struct iscsi_np *np)
        if (signal_pending(current))
                goto new_sess_out;
 
-       ret = iscsi_post_login_handler(np, conn, zero_tsih);
+       if (ret == 1) {
+               tpg_np = conn->tpg_np;
 
-       if (ret < 0)
-               goto new_sess_out;
+               ret = iscsi_post_login_handler(np, conn, zero_tsih);
+               if (ret < 0)
+                       goto new_sess_out;
+
+               iscsit_deaccess_np(np, tpg, tpg_np);
+       }
 
-       iscsit_deaccess_np(np, tpg);
        tpg = NULL;
+       tpg_np = NULL;
        /* Get another socket */
        return 1;
 
 new_sess_out:
-       pr_err("iSCSI Login negotiation failed.\n");
-       iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
-                                 ISCSI_LOGIN_STATUS_INIT_ERR);
-       if (!zero_tsih || !conn->sess)
-               goto old_sess_out;
-       if (conn->sess->se_sess)
-               transport_free_session(conn->sess->se_sess);
-       if (conn->sess->session_index != 0) {
-               spin_lock_bh(&sess_idr_lock);
-               idr_remove(&sess_idr, conn->sess->session_index);
-               spin_unlock_bh(&sess_idr_lock);
-       }
-       kfree(conn->sess->sess_ops);
-       kfree(conn->sess);
+       new_sess = true;
 old_sess_out:
-       iscsi_stop_login_thread_timer(np);
-       /*
-        * If login negotiation fails check if the Time2Retain timer
-        * needs to be restarted.
-        */
-       if (!zero_tsih && conn->sess) {
-               spin_lock_bh(&conn->sess->conn_lock);
-               if (conn->sess->session_state == TARG_SESS_STATE_FAILED) {
-                       struct se_portal_group *se_tpg =
-                                       &ISCSI_TPG_C(conn)->tpg_se_tpg;
-
-                       atomic_set(&conn->sess->session_continuation, 0);
-                       spin_unlock_bh(&conn->sess->conn_lock);
-                       spin_lock_bh(&se_tpg->session_lock);
-                       iscsit_start_time2retain_handler(conn->sess);
-                       spin_unlock_bh(&se_tpg->session_lock);
-               } else
-                       spin_unlock_bh(&conn->sess->conn_lock);
-               iscsit_dec_session_usage_count(conn->sess);
-       }
-
-       if (!IS_ERR(conn->conn_rx_hash.tfm))
-               crypto_free_hash(conn->conn_rx_hash.tfm);
-       if (!IS_ERR(conn->conn_tx_hash.tfm))
-               crypto_free_hash(conn->conn_tx_hash.tfm);
-
-       if (conn->conn_cpumask)
-               free_cpumask_var(conn->conn_cpumask);
-
-       kfree(conn->conn_ops);
-
-       if (conn->param_list) {
-               iscsi_release_param_list(conn->param_list);
-               conn->param_list = NULL;
-       }
-       iscsi_target_nego_release(conn);
-
-       if (conn->sock) {
-               sock_release(conn->sock);
-               conn->sock = NULL;
-       }
-
-       if (conn->conn_transport->iscsit_free_conn)
-               conn->conn_transport->iscsit_free_conn(conn);
-
-       iscsit_put_transport(conn->conn_transport);
-
-       kfree(conn);
+       tpg_np = conn->tpg_np;
+       iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess);
+       new_sess = false;
 
        if (tpg) {
-               iscsit_deaccess_np(np, tpg);
+               iscsit_deaccess_np(np, tpg, tpg_np);
                tpg = NULL;
+               tpg_np = NULL;
        }
 
 out:
index 63efd2878451717823a5835f213e524c3b4e6460..29d098324b7f947e553eade28ad2ccbecc8b887b 100644 (file)
@@ -12,6 +12,9 @@ extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *);
 extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *);
 extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32);
 extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *);
+extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8);
+extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *,
+                               bool, bool);
 extern int iscsi_target_login_thread(void *);
 extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *);
 
index c4675b4ceb494ca5f5ec62c6297d48cfcdf627bc..14d1aed5af1dbef98aa9b05ad31573b08bdf72ed 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains main functions related to iSCSI Parameter negotiation.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -377,15 +375,284 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log
        return 0;
 }
 
-static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login)
+static void iscsi_target_sk_data_ready(struct sock *sk, int count)
 {
-       if (iscsi_target_do_tx_login_io(conn, login) < 0)
-               return -1;
+       struct iscsi_conn *conn = sk->sk_user_data;
+       bool rc;
 
-       if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0)
-               return -1;
+       pr_debug("Entering iscsi_target_sk_data_ready: conn: %p\n", conn);
 
-       return 0;
+       write_lock_bh(&sk->sk_callback_lock);
+       if (!sk->sk_user_data) {
+               write_unlock_bh(&sk->sk_callback_lock);
+               return;
+       }
+       if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) {
+               write_unlock_bh(&sk->sk_callback_lock);
+               pr_debug("Got LOGIN_FLAGS_READY=0, conn: %p >>>>\n", conn);
+               return;
+       }
+       if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
+               write_unlock_bh(&sk->sk_callback_lock);
+               pr_debug("Got LOGIN_FLAGS_CLOSED=1, conn: %p >>>>\n", conn);
+               return;
+       }
+       if (test_and_set_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) {
+               write_unlock_bh(&sk->sk_callback_lock);
+               pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1, conn: %p >>>>\n", conn);
+               return;
+       }
+
+       rc = schedule_delayed_work(&conn->login_work, 0);
+       if (rc == false) {
+               pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work"
+                        " got false\n");
+       }
+       write_unlock_bh(&sk->sk_callback_lock);
+}
+
+static void iscsi_target_sk_state_change(struct sock *);
+
+static void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn)
+{
+       struct sock *sk;
+
+       if (!conn->sock)
+               return;
+
+       sk = conn->sock->sk;
+       pr_debug("Entering iscsi_target_set_sock_callbacks: conn: %p\n", conn);
+
+       write_lock_bh(&sk->sk_callback_lock);
+       sk->sk_user_data = conn;
+       conn->orig_data_ready = sk->sk_data_ready;
+       conn->orig_state_change = sk->sk_state_change;
+       sk->sk_data_ready = iscsi_target_sk_data_ready;
+       sk->sk_state_change = iscsi_target_sk_state_change;
+       write_unlock_bh(&sk->sk_callback_lock);
+
+       sk->sk_sndtimeo = TA_LOGIN_TIMEOUT * HZ;
+       sk->sk_rcvtimeo = TA_LOGIN_TIMEOUT * HZ;
+}
+
+static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn)
+{
+       struct sock *sk;
+
+       if (!conn->sock)
+               return;
+
+       sk = conn->sock->sk;
+       pr_debug("Entering iscsi_target_restore_sock_callbacks: conn: %p\n", conn);
+
+       write_lock_bh(&sk->sk_callback_lock);
+       if (!sk->sk_user_data) {
+               write_unlock_bh(&sk->sk_callback_lock);
+               return;
+       }
+       sk->sk_user_data = NULL;
+       sk->sk_data_ready = conn->orig_data_ready;
+       sk->sk_state_change = conn->orig_state_change;
+       write_unlock_bh(&sk->sk_callback_lock);
+
+       sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
+       sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT;
+}
+
+static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *);
+
+static bool iscsi_target_sk_state_check(struct sock *sk)
+{
+       if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) {
+               pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE,"
+                       "returning FALSE\n");
+               return false;
+       }
+       return true;
+}
+
+static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login)
+{
+       struct iscsi_np *np = login->np;
+       bool zero_tsih = login->zero_tsih;
+
+       iscsi_remove_failed_auth_entry(conn);
+       iscsi_target_nego_release(conn);
+       iscsi_target_login_sess_out(conn, np, zero_tsih, true);
+}
+
+static void iscsi_target_login_timeout(unsigned long data)
+{
+       struct iscsi_conn *conn = (struct iscsi_conn *)data;
+
+       pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n");
+
+       if (conn->login_kworker) {
+               pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n",
+                        conn->login_kworker->comm, conn->login_kworker->pid);
+               send_sig(SIGINT, conn->login_kworker, 1);
+       }
+}
+
+static void iscsi_target_do_login_rx(struct work_struct *work)
+{
+       struct iscsi_conn *conn = container_of(work,
+                               struct iscsi_conn, login_work.work);
+       struct iscsi_login *login = conn->login;
+       struct iscsi_np *np = login->np;
+       struct iscsi_portal_group *tpg = conn->tpg;
+       struct iscsi_tpg_np *tpg_np = conn->tpg_np;
+       struct timer_list login_timer;
+       int rc, zero_tsih = login->zero_tsih;
+       bool state;
+
+       pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n",
+                       conn, current->comm, current->pid);
+
+       spin_lock(&tpg->tpg_state_lock);
+       state = (tpg->tpg_state == TPG_STATE_ACTIVE);
+       spin_unlock(&tpg->tpg_state_lock);
+
+       if (state == false) {
+               pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n");
+               iscsi_target_restore_sock_callbacks(conn);
+               iscsi_target_login_drop(conn, login);
+               iscsit_deaccess_np(np, tpg, tpg_np);
+               return;
+       }
+
+       if (conn->sock) {
+               struct sock *sk = conn->sock->sk;
+
+               read_lock_bh(&sk->sk_callback_lock);
+               state = iscsi_target_sk_state_check(sk);
+               read_unlock_bh(&sk->sk_callback_lock);
+
+               if (state == false) {
+                       pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n");
+                       iscsi_target_restore_sock_callbacks(conn);
+                       iscsi_target_login_drop(conn, login);
+                       iscsit_deaccess_np(np, tpg, tpg_np);
+                       return;
+               }
+       }
+
+       conn->login_kworker = current;
+       allow_signal(SIGINT);
+
+       init_timer(&login_timer);
+       login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ);
+       login_timer.data = (unsigned long)conn;
+       login_timer.function = iscsi_target_login_timeout;
+       add_timer(&login_timer);
+       pr_debug("Starting login_timer for %s/%d\n", current->comm, current->pid);
+
+       rc = conn->conn_transport->iscsit_get_login_rx(conn, login);
+       del_timer_sync(&login_timer);
+       flush_signals(current);
+       conn->login_kworker = NULL;
+
+       if (rc < 0) {
+               iscsi_target_restore_sock_callbacks(conn);
+               iscsi_target_login_drop(conn, login);
+               iscsit_deaccess_np(np, tpg, tpg_np);
+               return;
+       }
+
+       pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n",
+                       conn, current->comm, current->pid);
+
+       rc = iscsi_target_do_login(conn, login);
+       if (rc < 0) {
+               iscsi_target_restore_sock_callbacks(conn);
+               iscsi_target_login_drop(conn, login);
+               iscsit_deaccess_np(np, tpg, tpg_np);
+       } else if (!rc) {
+               if (conn->sock) {
+                       struct sock *sk = conn->sock->sk;
+
+                       write_lock_bh(&sk->sk_callback_lock);
+                       clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags);
+                       write_unlock_bh(&sk->sk_callback_lock);
+               }
+       } else if (rc == 1) {
+               iscsi_target_nego_release(conn);
+               iscsi_post_login_handler(np, conn, zero_tsih);
+               iscsit_deaccess_np(np, tpg, tpg_np);
+       }
+}
+
+static void iscsi_target_do_cleanup(struct work_struct *work)
+{
+       struct iscsi_conn *conn = container_of(work,
+                               struct iscsi_conn, login_cleanup_work.work);
+       struct sock *sk = conn->sock->sk;
+       struct iscsi_login *login = conn->login;
+       struct iscsi_np *np = login->np;
+       struct iscsi_portal_group *tpg = conn->tpg;
+       struct iscsi_tpg_np *tpg_np = conn->tpg_np;
+
+       pr_debug("Entering iscsi_target_do_cleanup\n");
+
+       cancel_delayed_work_sync(&conn->login_work);
+       conn->orig_state_change(sk);
+
+       iscsi_target_restore_sock_callbacks(conn);
+       iscsi_target_login_drop(conn, login);
+       iscsit_deaccess_np(np, tpg, tpg_np);
+
+       pr_debug("iscsi_target_do_cleanup done()\n");
+}
+
+static void iscsi_target_sk_state_change(struct sock *sk)
+{
+       struct iscsi_conn *conn;
+       void (*orig_state_change)(struct sock *);
+       bool state;
+
+       pr_debug("Entering iscsi_target_sk_state_change\n");
+
+       write_lock_bh(&sk->sk_callback_lock);
+       conn = sk->sk_user_data;
+       if (!conn) {
+               write_unlock_bh(&sk->sk_callback_lock);
+               return;
+       }
+       orig_state_change = conn->orig_state_change;
+
+       if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) {
+               pr_debug("Got LOGIN_FLAGS_READY=0 sk_state_change conn: %p\n",
+                        conn);
+               write_unlock_bh(&sk->sk_callback_lock);
+               orig_state_change(sk);
+               return;
+       }
+       if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) {
+               pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change"
+                        " conn: %p\n", conn);
+               write_unlock_bh(&sk->sk_callback_lock);
+               orig_state_change(sk);
+               return;
+       }
+       if (test_and_set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) {
+               pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n",
+                        conn);
+               write_unlock_bh(&sk->sk_callback_lock);
+               orig_state_change(sk);
+               return;
+       }
+
+       state = iscsi_target_sk_state_check(sk);
+       write_unlock_bh(&sk->sk_callback_lock);
+
+       pr_debug("iscsi_target_sk_state_change: state: %d\n", state);
+
+       if (!state) {
+               pr_debug("iscsi_target_sk_state_change got failed state\n");
+               schedule_delayed_work(&conn->login_cleanup_work, 0);
+               return;
+       }
+       orig_state_change(sk);
 }
 
 /*
@@ -643,10 +910,11 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
                        if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
                                login->tsih = conn->sess->tsih;
                                login->login_complete = 1;
+                               iscsi_target_restore_sock_callbacks(conn);
                                if (iscsi_target_do_tx_login_io(conn,
                                                login) < 0)
                                        return -1;
-                               return 0;
+                               return 1;
                        }
                        break;
                default:
@@ -656,13 +924,29 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo
                        break;
                }
 
-               if (iscsi_target_do_login_io(conn, login) < 0)
+               if (iscsi_target_do_tx_login_io(conn, login) < 0)
                        return -1;
 
                if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) {
                        login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT;
                        login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK;
                }
+               break;
+       }
+
+       if (conn->sock) {
+               struct sock *sk = conn->sock->sk;
+               bool state;
+
+               read_lock_bh(&sk->sk_callback_lock);
+               state = iscsi_target_sk_state_check(sk);
+               read_unlock_bh(&sk->sk_callback_lock);
+
+               if (!state) {
+                       pr_debug("iscsi_target_do_login() failed state for"
+                                " conn: %p\n", conn);
+                       return -1;
+               }
        }
 
        return 0;
@@ -695,9 +979,17 @@ int iscsi_target_locate_portal(
        char *tmpbuf, *start = NULL, *end = NULL, *key, *value;
        struct iscsi_session *sess = conn->sess;
        struct iscsi_tiqn *tiqn;
+       struct iscsi_tpg_np *tpg_np = NULL;
        struct iscsi_login_req *login_req;
-       u32 payload_length;
-       int sessiontype = 0, ret = 0;
+       struct se_node_acl *se_nacl;
+       u32 payload_length, queue_depth = 0;
+       int sessiontype = 0, ret = 0, tag_num, tag_size;
+
+       INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx);
+       INIT_DELAYED_WORK(&conn->login_cleanup_work, iscsi_target_do_cleanup);
+       iscsi_target_set_sock_callbacks(conn);
+
+       login->np = np;
 
        login_req = (struct iscsi_login_req *) login->req;
        payload_length = ntoh24(login_req->dlength);
@@ -791,7 +1083,7 @@ int iscsi_target_locate_portal(
                        goto out;
                }
                ret = 0;
-               goto out;
+               goto alloc_tags;
        }
 
 get_target:
@@ -822,7 +1114,7 @@ get_target:
        /*
         * Locate Target Portal Group from Storage Node.
         */
-       conn->tpg = iscsit_get_tpg_from_np(tiqn, np);
+       conn->tpg = iscsit_get_tpg_from_np(tiqn, np, &tpg_np);
        if (!conn->tpg) {
                pr_err("Unable to locate Target Portal Group"
                                " on %s\n", tiqn->tiqn);
@@ -832,12 +1124,16 @@ get_target:
                ret = -1;
                goto out;
        }
+       conn->tpg_np = tpg_np;
        pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt);
        /*
         * Setup crc32c modules from libcrypto
         */
        if (iscsi_login_setup_crypto(conn) < 0) {
                pr_err("iscsi_login_setup_crypto() failed\n");
+               kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
+               iscsit_put_tiqn_for_login(tiqn);
+               conn->tpg = NULL;
                ret = -1;
                goto out;
        }
@@ -846,11 +1142,12 @@ get_target:
         * process login attempt.
         */
        if (iscsit_access_np(np, conn->tpg) < 0) {
+               kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put);
                iscsit_put_tiqn_for_login(tiqn);
                iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
-               ret = -1;
                conn->tpg = NULL;
+               ret = -1;
                goto out;
        }
 
@@ -883,8 +1180,27 @@ get_target:
                ret = -1;
                goto out;
        }
+       se_nacl = sess->se_sess->se_node_acl;
+       queue_depth = se_nacl->queue_depth;
+       /*
+        * Setup pre-allocated tags based upon allowed per NodeACL CmdSN
+        * depth for non immediate commands, plus extra tags for immediate
+        * commands.
+        *
+        * Also enforce a ISCSIT_MIN_TAGS to prevent unnecessary contention
+        * in per-cpu-ida tag allocation logic + small queue_depth.
+        */
+alloc_tags:
+       tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth);
+       tag_num += ISCSIT_EXTRA_TAGS;
+       tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
 
-       ret = 0;
+       ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size);
+       if (ret < 0) {
+               iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
+                                   ISCSI_LOGIN_STATUS_NO_RESOURCES);
+               ret = -1;
+       }
 out:
        kfree(tmpbuf);
        return ret;
@@ -897,10 +1213,23 @@ int iscsi_target_start_negotiation(
        int ret;
 
        ret = iscsi_target_do_login(conn, login);
-       if (ret != 0)
+       if (!ret) {
+               if (conn->sock) {
+                       struct sock *sk = conn->sock->sk;
+
+                       write_lock_bh(&sk->sk_callback_lock);
+                       set_bit(LOGIN_FLAGS_READY, &conn->login_flags);
+                       write_unlock_bh(&sk->sk_callback_lock);
+               }
+       } else if (ret < 0) {
+               cancel_delayed_work_sync(&conn->login_work);
+               cancel_delayed_work_sync(&conn->login_cleanup_work);
+               iscsi_target_restore_sock_callbacks(conn);
                iscsi_remove_failed_auth_entry(conn);
+       }
+       if (ret != 0)
+               iscsi_target_nego_release(conn);
 
-       iscsi_target_nego_release(conn);
        return ret;
 }
 
index 11dc2936af769af9116d6e8da1c17871a78fae23..93bdc475eb00696c96216d0d1679334bb02ec832 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains the main functions related to Initiator Node Attributes.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 35fd6439eb010d08d84c2529416005f4e69950d0..4d2e23fc76fda72be2b7ec59c801f0696a8470e3 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains main functions related to iSCSI Parameter negotiation.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -1182,7 +1180,7 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value,
                        unsigned long long tmp;
                        int rc;
 
-                       rc = strict_strtoull(param->value, 0, &tmp);
+                       rc = kstrtoull(param->value, 0, &tmp);
                        if (rc < 0)
                                return -1;
 
index edb592a368ef521f9dc77f8abca20054b1a78577..ca41b583f2f6d048927b318d69fd56ae9907c015 100644 (file)
@@ -2,9 +2,7 @@
  * This file contains main functions related to iSCSI DataSequenceInOrder=No
  * and DataPDUInOrder=No.
  *
- \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 464b4206a51ef0eb06b1c5b4a33f1fcde58aeeed..f788e8b5e8552211bc9655f2de8a43d842dc8a3a 100644 (file)
@@ -2,9 +2,7 @@
  * Modern ConfigFS group context specific iSCSI statistics based on original
  * iscsi_target_mib.c code
  *
- * Copyright (c) 2011 Rising Tide Systems
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * Copyright (c) 2011-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -177,7 +175,7 @@ ISCSI_STAT_INSTANCE_ATTR_RO(description);
 static ssize_t iscsi_stat_instance_show_attr_vendor(
        struct iscsi_wwn_stat_grps *igrps, char *page)
 {
-       return snprintf(page, PAGE_SIZE, "RisingTide Systems iSCSI-Target\n");
+       return snprintf(page, PAGE_SIZE, "Datera, Inc. iSCSI-Target\n");
 }
 ISCSI_STAT_INSTANCE_ATTR_RO(vendor);
 
@@ -432,13 +430,7 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr(
        int ret;
 
        spin_lock(&lstat->lock);
-       if (lstat->last_intr_fail_ip_family == AF_INET6) {
-               ret = snprintf(page, PAGE_SIZE, "[%s]\n",
-                              lstat->last_intr_fail_ip_addr);
-       } else {
-               ret = snprintf(page, PAGE_SIZE, "%s\n",
-                              lstat->last_intr_fail_ip_addr);
-       }
+       ret = snprintf(page, PAGE_SIZE, "%s\n", lstat->last_intr_fail_ip_addr);
        spin_unlock(&lstat->lock);
 
        return ret;
index b997e5da47d359f17001ca59d086cdf4d87978f4..78404b1cc0bf311eb80b738d68eacca99ea446d0 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains the iSCSI Target specific Task Management functions.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 439260b7d87fa69a7e379c66e4474c416e35a21d..4faeb47fa5e11377408c71c407a4f8c5afffa294 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains iSCSI Target Portal Group related functions.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -49,7 +47,7 @@ struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u1
        INIT_LIST_HEAD(&tpg->tpg_gnp_list);
        INIT_LIST_HEAD(&tpg->tpg_list);
        mutex_init(&tpg->tpg_access_lock);
-       mutex_init(&tpg->np_login_lock);
+       sema_init(&tpg->np_login_sem, 1);
        spin_lock_init(&tpg->tpg_state_lock);
        spin_lock_init(&tpg->tpg_np_lock);
 
@@ -129,7 +127,8 @@ void iscsit_release_discovery_tpg(void)
 
 struct iscsi_portal_group *iscsit_get_tpg_from_np(
        struct iscsi_tiqn *tiqn,
-       struct iscsi_np *np)
+       struct iscsi_np *np,
+       struct iscsi_tpg_np **tpg_np_out)
 {
        struct iscsi_portal_group *tpg = NULL;
        struct iscsi_tpg_np *tpg_np;
@@ -147,6 +146,8 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np(
                spin_lock(&tpg->tpg_np_lock);
                list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) {
                        if (tpg_np->tpg_np == np) {
+                               *tpg_np_out = tpg_np;
+                               kref_get(&tpg_np->tpg_np_kref);
                                spin_unlock(&tpg->tpg_np_lock);
                                spin_unlock(&tiqn->tiqn_tpg_lock);
                                return tpg;
@@ -175,18 +176,20 @@ void iscsit_put_tpg(struct iscsi_portal_group *tpg)
 
 static void iscsit_clear_tpg_np_login_thread(
        struct iscsi_tpg_np *tpg_np,
-       struct iscsi_portal_group *tpg)
+       struct iscsi_portal_group *tpg,
+       bool shutdown)
 {
        if (!tpg_np->tpg_np) {
                pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n");
                return;
        }
 
-       iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg);
+       iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown);
 }
 
 void iscsit_clear_tpg_np_login_threads(
-       struct iscsi_portal_group *tpg)
+       struct iscsi_portal_group *tpg,
+       bool shutdown)
 {
        struct iscsi_tpg_np *tpg_np;
 
@@ -197,7 +200,7 @@ void iscsit_clear_tpg_np_login_threads(
                        continue;
                }
                spin_unlock(&tpg->tpg_np_lock);
-               iscsit_clear_tpg_np_login_thread(tpg_np, tpg);
+               iscsit_clear_tpg_np_login_thread(tpg_np, tpg, shutdown);
                spin_lock(&tpg->tpg_np_lock);
        }
        spin_unlock(&tpg->tpg_np_lock);
@@ -268,6 +271,8 @@ int iscsit_tpg_del_portal_group(
        tpg->tpg_state = TPG_STATE_INACTIVE;
        spin_unlock(&tpg->tpg_state_lock);
 
+       iscsit_clear_tpg_np_login_threads(tpg, true);
+
        if (iscsit_release_sessions_for_tpg(tpg, force) < 0) {
                pr_err("Unable to delete iSCSI Target Portal Group:"
                        " %hu while active sessions exist, and force=0\n",
@@ -368,7 +373,7 @@ int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force)
        tpg->tpg_state = TPG_STATE_INACTIVE;
        spin_unlock(&tpg->tpg_state_lock);
 
-       iscsit_clear_tpg_np_login_threads(tpg);
+       iscsit_clear_tpg_np_login_threads(tpg, false);
 
        if (iscsit_release_sessions_for_tpg(tpg, force) < 0) {
                spin_lock(&tpg->tpg_state_lock);
@@ -490,6 +495,8 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal(
        INIT_LIST_HEAD(&tpg_np->tpg_np_child_list);
        INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list);
        spin_lock_init(&tpg_np->tpg_np_parent_lock);
+       init_completion(&tpg_np->tpg_np_comp);
+       kref_init(&tpg_np->tpg_np_kref);
        tpg_np->tpg_np          = np;
        tpg_np->tpg             = tpg;
 
@@ -520,7 +527,7 @@ static int iscsit_tpg_release_np(
        struct iscsi_portal_group *tpg,
        struct iscsi_np *np)
 {
-       iscsit_clear_tpg_np_login_thread(tpg_np, tpg);
+       iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true);
 
        pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n",
                tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt,
index dda48c141a8c8613a6c2172a9f958bd3332372af..b77693e2c209c9a85289228158f0f6d13d70dae2 100644 (file)
@@ -5,10 +5,10 @@ extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *,
 extern int iscsit_load_discovery_tpg(void);
 extern void iscsit_release_discovery_tpg(void);
 extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *,
-                       struct iscsi_np *);
+                       struct iscsi_np *, struct iscsi_tpg_np **);
 extern int iscsit_get_tpg(struct iscsi_portal_group *);
 extern void iscsit_put_tpg(struct iscsi_portal_group *);
-extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *);
+extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool);
 extern void iscsit_tpg_dump_params(struct iscsi_portal_group *);
 extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *);
 extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *,
index 81289520f96b3915bf1e4e8cfaf330ac27625566..601e9cc61e98e754f9a4927f8be3f0ae6d2fc3c3 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains the iSCSI Login Thread and Thread Queue functions.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -105,12 +103,11 @@ int iscsi_allocate_thread_sets(u32 thread_pair_count)
                ts->status = ISCSI_THREAD_SET_FREE;
                INIT_LIST_HEAD(&ts->ts_list);
                spin_lock_init(&ts->ts_state_lock);
-               init_completion(&ts->rx_post_start_comp);
-               init_completion(&ts->tx_post_start_comp);
                init_completion(&ts->rx_restart_comp);
                init_completion(&ts->tx_restart_comp);
                init_completion(&ts->rx_start_comp);
                init_completion(&ts->tx_start_comp);
+               sema_init(&ts->ts_activate_sem, 0);
 
                ts->create_threads = 1;
                ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s",
@@ -139,35 +136,44 @@ int iscsi_allocate_thread_sets(u32 thread_pair_count)
        return allocated_thread_pair_count;
 }
 
-void iscsi_deallocate_thread_sets(void)
+static void iscsi_deallocate_thread_one(struct iscsi_thread_set *ts)
 {
-       u32 released_count = 0;
-       struct iscsi_thread_set *ts = NULL;
-
-       while ((ts = iscsi_get_ts_from_inactive_list())) {
+       spin_lock_bh(&ts->ts_state_lock);
+       ts->status = ISCSI_THREAD_SET_DIE;
 
+       if (ts->rx_thread) {
+               complete(&ts->rx_start_comp);
+               spin_unlock_bh(&ts->ts_state_lock);
+               kthread_stop(ts->rx_thread);
                spin_lock_bh(&ts->ts_state_lock);
-               ts->status = ISCSI_THREAD_SET_DIE;
+       }
+       if (ts->tx_thread) {
+               complete(&ts->tx_start_comp);
                spin_unlock_bh(&ts->ts_state_lock);
+               kthread_stop(ts->tx_thread);
+               spin_lock_bh(&ts->ts_state_lock);
+       }
+       spin_unlock_bh(&ts->ts_state_lock);
+       /*
+        * Release this thread_id in the thread_set_bitmap
+        */
+       spin_lock(&ts_bitmap_lock);
+       bitmap_release_region(iscsit_global->ts_bitmap,
+                       ts->thread_id, get_order(1));
+       spin_unlock(&ts_bitmap_lock);
 
-               if (ts->rx_thread) {
-                       send_sig(SIGINT, ts->rx_thread, 1);
-                       kthread_stop(ts->rx_thread);
-               }
-               if (ts->tx_thread) {
-                       send_sig(SIGINT, ts->tx_thread, 1);
-                       kthread_stop(ts->tx_thread);
-               }
-               /*
-                * Release this thread_id in the thread_set_bitmap
-                */
-               spin_lock(&ts_bitmap_lock);
-               bitmap_release_region(iscsit_global->ts_bitmap,
-                               ts->thread_id, get_order(1));
-               spin_unlock(&ts_bitmap_lock);
+       kfree(ts);
+}
 
+void iscsi_deallocate_thread_sets(void)
+{
+       struct iscsi_thread_set *ts = NULL;
+       u32 released_count = 0;
+
+       while ((ts = iscsi_get_ts_from_inactive_list())) {
+
+               iscsi_deallocate_thread_one(ts);
                released_count++;
-               kfree(ts);
        }
 
        if (released_count)
@@ -187,34 +193,13 @@ static void iscsi_deallocate_extra_thread_sets(void)
                if (!ts)
                        break;
 
-               spin_lock_bh(&ts->ts_state_lock);
-               ts->status = ISCSI_THREAD_SET_DIE;
-               spin_unlock_bh(&ts->ts_state_lock);
-
-               if (ts->rx_thread) {
-                       send_sig(SIGINT, ts->rx_thread, 1);
-                       kthread_stop(ts->rx_thread);
-               }
-               if (ts->tx_thread) {
-                       send_sig(SIGINT, ts->tx_thread, 1);
-                       kthread_stop(ts->tx_thread);
-               }
-               /*
-                * Release this thread_id in the thread_set_bitmap
-                */
-               spin_lock(&ts_bitmap_lock);
-               bitmap_release_region(iscsit_global->ts_bitmap,
-                               ts->thread_id, get_order(1));
-               spin_unlock(&ts_bitmap_lock);
-
+               iscsi_deallocate_thread_one(ts);
                released_count++;
-               kfree(ts);
        }
 
-       if (released_count) {
+       if (released_count)
                pr_debug("Stopped %d thread set(s) (%d total threads)."
                        "\n", released_count, released_count * 2);
-       }
 }
 
 void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
@@ -224,37 +209,23 @@ void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set
        spin_lock_bh(&ts->ts_state_lock);
        conn->thread_set = ts;
        ts->conn = conn;
+       ts->status = ISCSI_THREAD_SET_ACTIVE;
        spin_unlock_bh(&ts->ts_state_lock);
-       /*
-        * Start up the RX thread and wait on rx_post_start_comp.  The RX
-        * Thread will then do the same for the TX Thread in
-        * iscsi_rx_thread_pre_handler().
-        */
+
        complete(&ts->rx_start_comp);
-       wait_for_completion(&ts->rx_post_start_comp);
+       complete(&ts->tx_start_comp);
+
+       down(&ts->ts_activate_sem);
 }
 
 struct iscsi_thread_set *iscsi_get_thread_set(void)
 {
-       int allocate_ts = 0;
-       struct completion comp;
-       struct iscsi_thread_set *ts = NULL;
-       /*
-        * If no inactive thread set is available on the first call to
-        * iscsi_get_ts_from_inactive_list(), sleep for a second and
-        * try again.  If still none are available after two attempts,
-        * allocate a set ourselves.
-        */
+       struct iscsi_thread_set *ts;
+
 get_set:
        ts = iscsi_get_ts_from_inactive_list();
        if (!ts) {
-               if (allocate_ts == 2)
-                       iscsi_allocate_thread_sets(1);
-
-               init_completion(&comp);
-               wait_for_completion_timeout(&comp, 1 * HZ);
-
-               allocate_ts++;
+               iscsi_allocate_thread_sets(1);
                goto get_set;
        }
 
@@ -263,6 +234,7 @@ get_set:
        ts->thread_count = 2;
        init_completion(&ts->rx_restart_comp);
        init_completion(&ts->tx_restart_comp);
+       sema_init(&ts->ts_activate_sem, 0);
 
        return ts;
 }
@@ -400,7 +372,8 @@ static void iscsi_check_to_add_additional_sets(void)
 static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts)
 {
        spin_lock_bh(&ts->ts_state_lock);
-       if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) {
+       if (ts->status == ISCSI_THREAD_SET_DIE || kthread_should_stop() ||
+           signal_pending(current)) {
                spin_unlock_bh(&ts->ts_state_lock);
                return -1;
        }
@@ -419,7 +392,8 @@ struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts)
                goto sleep;
        }
 
-       flush_signals(current);
+       if (ts->status != ISCSI_THREAD_SET_DIE)
+               flush_signals(current);
 
        if (ts->delay_inactive && (--ts->thread_count == 0)) {
                spin_unlock_bh(&ts->ts_state_lock);
@@ -446,18 +420,19 @@ sleep:
        if (iscsi_signal_thread_pre_handler(ts) < 0)
                return NULL;
 
+       iscsi_check_to_add_additional_sets();
+
+       spin_lock_bh(&ts->ts_state_lock);
        if (!ts->conn) {
                pr_err("struct iscsi_thread_set->conn is NULL for"
-                       " thread_id: %d, going back to sleep\n", ts->thread_id);
-               goto sleep;
+                       " RX thread_id: %s/%d\n", current->comm, current->pid);
+               spin_unlock_bh(&ts->ts_state_lock);
+               return NULL;
        }
-       iscsi_check_to_add_additional_sets();
-       /*
-        * The RX Thread starts up the TX Thread and sleeps.
-        */
        ts->thread_clear |= ISCSI_CLEAR_RX_THREAD;
-       complete(&ts->tx_start_comp);
-       wait_for_completion(&ts->tx_post_start_comp);
+       spin_unlock_bh(&ts->ts_state_lock);
+
+       up(&ts->ts_activate_sem);
 
        return ts->conn;
 }
@@ -472,7 +447,8 @@ struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts)
                goto sleep;
        }
 
-       flush_signals(current);
+       if (ts->status != ISCSI_THREAD_SET_DIE)
+               flush_signals(current);
 
        if (ts->delay_inactive && (--ts->thread_count == 0)) {
                spin_unlock_bh(&ts->ts_state_lock);
@@ -498,27 +474,20 @@ sleep:
        if (iscsi_signal_thread_pre_handler(ts) < 0)
                return NULL;
 
-       if (!ts->conn) {
-               pr_err("struct iscsi_thread_set->conn is NULL for "
-                       " thread_id: %d, going back to sleep\n",
-                       ts->thread_id);
-               goto sleep;
-       }
-
        iscsi_check_to_add_additional_sets();
-       /*
-        * From the TX thread, up the tx_post_start_comp that the RX Thread is
-        * sleeping on in iscsi_rx_thread_pre_handler(), then up the
-        * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on.
-        */
-       ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
-       complete(&ts->tx_post_start_comp);
-       complete(&ts->rx_post_start_comp);
 
        spin_lock_bh(&ts->ts_state_lock);
-       ts->status = ISCSI_THREAD_SET_ACTIVE;
+       if (!ts->conn) {
+               pr_err("struct iscsi_thread_set->conn is NULL for"
+                       " TX thread_id: %s/%d\n", current->comm, current->pid);
+               spin_unlock_bh(&ts->ts_state_lock);
+               return NULL;
+       }
+       ts->thread_clear |= ISCSI_CLEAR_TX_THREAD;
        spin_unlock_bh(&ts->ts_state_lock);
 
+       up(&ts->ts_activate_sem);
+
        return ts->conn;
 }
 
index 547d118312820d2a39ba960b11844298810190ce..cc1eede5ab3a9cc4ad09fcbe3714eae77cdfb083 100644 (file)
@@ -64,10 +64,6 @@ struct iscsi_thread_set {
        struct iscsi_conn       *conn;
        /* used for controlling ts state accesses */
        spinlock_t      ts_state_lock;
-       /* Used for rx side post startup */
-       struct completion       rx_post_start_comp;
-       /* Used for tx side post startup */
-       struct completion       tx_post_start_comp;
        /* used for restarting thread queue */
        struct completion       rx_restart_comp;
        /* used for restarting thread queue */
@@ -82,6 +78,7 @@ struct iscsi_thread_set {
        struct task_struct      *tx_thread;
        /* struct iscsi_thread_set in list list head*/
        struct list_head        ts_list;
+       struct semaphore        ts_activate_sem;
 };
 
 #endif   /*** ISCSI_THREAD_QUEUE_H ***/
index 1df06d5e4e01ee29353801a671b43d62bf934fbf..f2de28e178fd738cd93dce94ad7980422749f9d2 100644 (file)
@@ -1,9 +1,7 @@
 /*******************************************************************************
  * This file contains the iSCSI Target specific utility functions.
  *
- * \u00a9 Copyright 2007-2011 RisingTide Systems LLC.
- *
- * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
+ * (c) Copyright 2007-2013 Datera, Inc.
  *
  * Author: Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
@@ -19,6 +17,7 @@
  ******************************************************************************/
 
 #include <linux/list.h>
+#include <linux/percpu_ida.h>
 #include <scsi/scsi_tcq.h>
 #include <scsi/iscsi_proto.h>
 #include <target/target_core_base.h>
@@ -149,18 +148,6 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
        spin_unlock_bh(&cmd->r2t_lock);
 }
 
-struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
-{
-       struct iscsi_cmd *cmd;
-
-       cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask);
-       if (!cmd)
-               return NULL;
-
-       cmd->release_cmd = &iscsit_release_cmd;
-       return cmd;
-}
-
 /*
  * May be called from software interrupt (timer) context for allocating
  * iSCSI NopINs.
@@ -168,12 +155,15 @@ struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
 struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
 {
        struct iscsi_cmd *cmd;
+       struct se_session *se_sess = conn->sess->se_sess;
+       int size, tag;
 
-       cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask);
-       if (!cmd) {
-               pr_err("Unable to allocate memory for struct iscsi_cmd.\n");
-               return NULL;
-       }
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, gfp_mask);
+       size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
+       cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size));
+       memset(cmd, 0, size);
+
+       cmd->se_cmd.map_tag = tag;
        cmd->conn = conn;
        INIT_LIST_HEAD(&cmd->i_conn_node);
        INIT_LIST_HEAD(&cmd->datain_list);
@@ -689,6 +679,16 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn)
 
 void iscsit_release_cmd(struct iscsi_cmd *cmd)
 {
+       struct iscsi_session *sess;
+       struct se_cmd *se_cmd = &cmd->se_cmd;
+
+       if (cmd->conn)
+               sess = cmd->conn->sess;
+       else
+               sess = cmd->sess;
+
+       BUG_ON(!sess || !sess->se_sess);
+
        kfree(cmd->buf_ptr);
        kfree(cmd->pdu_list);
        kfree(cmd->seq_list);
@@ -696,8 +696,9 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd)
        kfree(cmd->iov_data);
        kfree(cmd->text_in_ptr);
 
-       kmem_cache_free(lio_cmd_cache, cmd);
+       percpu_ida_free(&sess->se_sess->sess_tag_pool, se_cmd->map_tag);
 }
+EXPORT_SYMBOL(iscsit_release_cmd);
 
 static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd,
                              bool check_queues)
@@ -761,7 +762,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown)
                /* Fall-through */
        default:
                __iscsit_free_cmd(cmd, false, shutdown);
-               cmd->release_cmd(cmd);
+               iscsit_release_cmd(cmd);
                break;
        }
 }
index 568ad25f25d3d328b901ac3357b0a5bff8eb2115..0f6d69dabca1eca22a345be1dd42768517bd60a1 100644 (file)
@@ -3,7 +3,7 @@
  * This file contains the Linux/SCSI LLD virtual SCSI initiator driver
  * for emulated SAS initiator ports
  *
- * Â© Copyright 2011 RisingTide Systems LLC.
+ * Â© Copyright 2011-2013 Datera, Inc.
  *
  * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
  *
index cbe48ab417459de02ec06660934ec8b3ff8804c0..47244102281e8432775d55fc55bee0d1bd9ee2e7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA)
  *
- * (c) Copyright 2009-2012 RisingTide Systems LLC.
+ * (c) Copyright 2009-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -557,6 +557,9 @@ target_alua_state_check(struct se_cmd *cmd)
         * a ALUA logical unit group.
         */
        tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem;
+       if (!tg_pt_gp_mem)
+               return 0;
+
        spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
        tg_pt_gp = tg_pt_gp_mem->tg_pt_gp;
        out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
@@ -730,7 +733,7 @@ static int core_alua_write_tpg_metadata(
        if (ret < 0)
                pr_err("Error writing ALUA metadata file: %s\n", path);
        fput(file);
-       return ret ? -EIO : 0;
+       return (ret < 0) ? -EIO : 0;
 }
 
 /*
@@ -1756,10 +1759,10 @@ ssize_t core_alua_store_access_type(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract alua_access_type\n");
-               return -EINVAL;
+               return ret;
        }
        if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) {
                pr_err("Illegal value for alua_access_type:"
@@ -1794,10 +1797,10 @@ ssize_t core_alua_store_nonop_delay_msecs(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract nonop_delay_msecs\n");
-               return -EINVAL;
+               return ret;
        }
        if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) {
                pr_err("Passed nonop_delay_msecs: %lu, exceeds"
@@ -1825,10 +1828,10 @@ ssize_t core_alua_store_trans_delay_msecs(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract trans_delay_msecs\n");
-               return -EINVAL;
+               return ret;
        }
        if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) {
                pr_err("Passed trans_delay_msecs: %lu, exceeds"
@@ -1856,10 +1859,10 @@ ssize_t core_alua_store_implict_trans_secs(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract implict_trans_secs\n");
-               return -EINVAL;
+               return ret;
        }
        if (tmp > ALUA_MAX_IMPLICT_TRANS_SECS) {
                pr_err("Passed implict_trans_secs: %lu, exceeds"
@@ -1887,10 +1890,10 @@ ssize_t core_alua_store_preferred_bit(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract preferred ALUA value\n");
-               return -EINVAL;
+               return ret;
        }
        if ((tmp != 0) && (tmp != 1)) {
                pr_err("Illegal value for preferred ALUA: %lu\n", tmp);
@@ -1922,10 +1925,10 @@ ssize_t core_alua_store_offline_bit(
        if (!lun->lun_sep)
                return -ENODEV;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract alua_tg_pt_offline value\n");
-               return -EINVAL;
+               return ret;
        }
        if ((tmp != 0) && (tmp != 1)) {
                pr_err("Illegal value for alua_tg_pt_offline: %lu\n",
@@ -1961,10 +1964,10 @@ ssize_t core_alua_store_secondary_status(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract alua_tg_pt_status\n");
-               return -EINVAL;
+               return ret;
        }
        if ((tmp != ALUA_STATUS_NONE) &&
            (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) &&
@@ -1994,10 +1997,10 @@ ssize_t core_alua_store_secondary_write_metadata(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract alua_tg_pt_write_md\n");
-               return -EINVAL;
+               return ret;
        }
        if ((tmp != 0) && (tmp != 1)) {
                pr_err("Illegal value for alua_tg_pt_write_md:"
index e4d22933efaf8ce38a3de9aee51df9d3027c4f6a..82e81c542e4350271c68bc1bbddded380d8811d1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains ConfigFS logic for the Generic Target Engine project.
  *
- * (c) Copyright 2008-2012 RisingTide Systems LLC.
+ * (c) Copyright 2008-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -48,6 +48,7 @@
 #include "target_core_alua.h"
 #include "target_core_pr.h"
 #include "target_core_rd.h"
+#include "target_core_xcopy.h"
 
 extern struct t10_alua_lu_gp *default_lu_gp;
 
@@ -268,7 +269,7 @@ static struct configfs_subsystem target_core_fabrics = {
        },
 };
 
-static struct configfs_subsystem *target_core_subsystem[] = {
+struct configfs_subsystem *target_core_subsystem[] = {
        &target_core_fabrics,
        NULL,
 };
@@ -577,9 +578,9 @@ static ssize_t target_core_dev_store_attr_##_name(                  \
        unsigned long val;                                              \
        int ret;                                                        \
                                                                        \
-       ret = strict_strtoul(page, 0, &val);                            \
+       ret = kstrtoul(page, 0, &val);                          \
        if (ret < 0) {                                                  \
-               pr_err("strict_strtoul() failed with"           \
+               pr_err("kstrtoul() failed with"         \
                        " ret: %d\n", ret);                             \
                return -EINVAL;                                         \
        }                                                               \
@@ -636,6 +637,12 @@ SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR);
 DEF_DEV_ATTRIB(emulate_tpws);
 SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR);
 
+DEF_DEV_ATTRIB(emulate_caw);
+SE_DEV_ATTR(emulate_caw, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB(emulate_3pc);
+SE_DEV_ATTR(emulate_3pc, S_IRUGO | S_IWUSR);
+
 DEF_DEV_ATTRIB(enforce_pr_isids);
 SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR);
 
@@ -693,6 +700,8 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
        &target_core_dev_attrib_emulate_tas.attr,
        &target_core_dev_attrib_emulate_tpu.attr,
        &target_core_dev_attrib_emulate_tpws.attr,
+       &target_core_dev_attrib_emulate_caw.attr,
+       &target_core_dev_attrib_emulate_3pc.attr,
        &target_core_dev_attrib_enforce_pr_isids.attr,
        &target_core_dev_attrib_is_nonrot.attr,
        &target_core_dev_attrib_emulate_rest_reord.attr,
@@ -1310,9 +1319,9 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
                                ret = -ENOMEM;
                                goto out;
                        }
-                       ret = strict_strtoull(arg_p, 0, &tmp_ll);
+                       ret = kstrtoull(arg_p, 0, &tmp_ll);
                        if (ret < 0) {
-                               pr_err("strict_strtoull() failed for"
+                               pr_err("kstrtoull() failed for"
                                        " sa_res_key=\n");
                                goto out;
                        }
@@ -1836,11 +1845,11 @@ static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id(
        unsigned long lu_gp_id;
        int ret;
 
-       ret = strict_strtoul(page, 0, &lu_gp_id);
+       ret = kstrtoul(page, 0, &lu_gp_id);
        if (ret < 0) {
-               pr_err("strict_strtoul() returned %d for"
+               pr_err("kstrtoul() returned %d for"
                        " lu_gp_id\n", ret);
-               return -EINVAL;
+               return ret;
        }
        if (lu_gp_id > 0x0000ffff) {
                pr_err("ALUA lu_gp_id: %lu exceeds maximum:"
@@ -2032,11 +2041,11 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
                return -EINVAL;
        }
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract new ALUA access state from"
                                " %s\n", page);
-               return -EINVAL;
+               return ret;
        }
        new_state = (int)tmp;
 
@@ -2079,11 +2088,11 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status(
                return -EINVAL;
        }
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract new ALUA access status"
                                " from %s\n", page);
-               return -EINVAL;
+               return ret;
        }
        new_status = (int)tmp;
 
@@ -2139,10 +2148,10 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata(
        unsigned long tmp;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tmp);
+       ret = kstrtoul(page, 0, &tmp);
        if (ret < 0) {
                pr_err("Unable to extract alua_write_metadata\n");
-               return -EINVAL;
+               return ret;
        }
 
        if ((tmp != 0) && (tmp != 1)) {
@@ -2263,11 +2272,11 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id(
        unsigned long tg_pt_gp_id;
        int ret;
 
-       ret = strict_strtoul(page, 0, &tg_pt_gp_id);
+       ret = kstrtoul(page, 0, &tg_pt_gp_id);
        if (ret < 0) {
-               pr_err("strict_strtoul() returned %d for"
+               pr_err("kstrtoul() returned %d for"
                        " tg_pt_gp_id\n", ret);
-               return -EINVAL;
+               return ret;
        }
        if (tg_pt_gp_id > 0x0000ffff) {
                pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum:"
@@ -2676,10 +2685,10 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba,
        if (transport->pmode_enable_hba == NULL)
                return -EINVAL;
 
-       ret = strict_strtoul(page, 0, &mode_flag);
+       ret = kstrtoul(page, 0, &mode_flag);
        if (ret < 0) {
                pr_err("Unable to extract hba mode flag: %d\n", ret);
-               return -EINVAL;
+               return ret;
        }
 
        if (hba->dev_count) {
@@ -2767,11 +2776,11 @@ static struct config_group *target_core_call_addhbatotarget(
                str++; /* Skip to start of plugin dependent ID */
        }
 
-       ret = strict_strtoul(str, 0, &plugin_dep_id);
+       ret = kstrtoul(str, 0, &plugin_dep_id);
        if (ret < 0) {
-               pr_err("strict_strtoul() returned %d for"
+               pr_err("kstrtoul() returned %d for"
                                " plugin_dep_id\n", ret);
-               return ERR_PTR(-EINVAL);
+               return ERR_PTR(ret);
        }
        /*
         * Load up TCM subsystem plugins if they have not already been loaded.
@@ -2927,6 +2936,10 @@ static int __init target_core_init_configfs(void)
        if (ret < 0)
                goto out;
 
+       ret = target_xcopy_setup_pt();
+       if (ret < 0)
+               goto out;
+
        return 0;
 
 out:
@@ -2999,6 +3012,7 @@ static void __exit target_core_exit_configfs(void)
 
        core_dev_release_virtual_lun0();
        rd_module_exit();
+       target_xcopy_release_pt();
        release_se_kmem_caches();
 }
 
index 8f4142fe5f19fdd336bf55bfc761f100ae67ce2c..d90dbb0f1a69753a6654413587d9da31a32bdbaa 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains the TCM Virtual Device and Disk Transport
  * agnostic related functions.
  *
- * (c) Copyright 2003-2012 RisingTide Systems LLC.
+ * (c) Copyright 2003-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -47,6 +47,9 @@
 #include "target_core_pr.h"
 #include "target_core_ua.h"
 
+DEFINE_MUTEX(g_device_mutex);
+LIST_HEAD(g_device_list);
+
 static struct se_hba *lun0_hba;
 /* not static, needed by tpg.c */
 struct se_device *g_lun0_dev;
@@ -890,6 +893,32 @@ int se_dev_set_emulate_tpws(struct se_device *dev, int flag)
        return 0;
 }
 
+int se_dev_set_emulate_caw(struct se_device *dev, int flag)
+{
+       if (flag != 0 && flag != 1) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+       dev->dev_attrib.emulate_caw = flag;
+       pr_debug("dev[%p]: SE Device CompareAndWrite (AtomicTestandSet): %d\n",
+                dev, flag);
+
+       return 0;
+}
+
+int se_dev_set_emulate_3pc(struct se_device *dev, int flag)
+{
+       if (flag != 0 && flag != 1) {
+               pr_err("Illegal value %d\n", flag);
+               return -EINVAL;
+       }
+       dev->dev_attrib.emulate_3pc = flag;
+       pr_debug("dev[%p]: SE Device 3rd Party Copy (EXTENDED_COPY): %d\n",
+               dev, flag);
+
+       return 0;
+}
+
 int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
 {
        if ((flag != 0) && (flag != 1)) {
@@ -1393,6 +1422,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        INIT_LIST_HEAD(&dev->delayed_cmd_list);
        INIT_LIST_HEAD(&dev->state_list);
        INIT_LIST_HEAD(&dev->qf_cmd_list);
+       INIT_LIST_HEAD(&dev->g_dev_node);
        spin_lock_init(&dev->stats_lock);
        spin_lock_init(&dev->execute_task_lock);
        spin_lock_init(&dev->delayed_cmd_lock);
@@ -1400,6 +1430,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        spin_lock_init(&dev->se_port_lock);
        spin_lock_init(&dev->se_tmr_lock);
        spin_lock_init(&dev->qf_cmd_lock);
+       sema_init(&dev->caw_sem, 1);
        atomic_set(&dev->dev_ordered_id, 0);
        INIT_LIST_HEAD(&dev->t10_wwn.t10_vpd_list);
        spin_lock_init(&dev->t10_wwn.t10_vpd_lock);
@@ -1423,6 +1454,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        dev->dev_attrib.emulate_tas = DA_EMULATE_TAS;
        dev->dev_attrib.emulate_tpu = DA_EMULATE_TPU;
        dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS;
+       dev->dev_attrib.emulate_caw = DA_EMULATE_CAW;
+       dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC;
        dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
        dev->dev_attrib.is_nonrot = DA_IS_NONROT;
        dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD;
@@ -1510,6 +1543,11 @@ int target_configure_device(struct se_device *dev)
        spin_lock(&hba->device_lock);
        hba->dev_count++;
        spin_unlock(&hba->device_lock);
+
+       mutex_lock(&g_device_mutex);
+       list_add_tail(&dev->g_dev_node, &g_device_list);
+       mutex_unlock(&g_device_mutex);
+
        return 0;
 
 out_free_alua:
@@ -1528,6 +1566,10 @@ void target_free_device(struct se_device *dev)
        if (dev->dev_flags & DF_CONFIGURED) {
                destroy_workqueue(dev->tmr_wq);
 
+               mutex_lock(&g_device_mutex);
+               list_del(&dev->g_dev_node);
+               mutex_unlock(&g_device_mutex);
+
                spin_lock(&hba->device_lock);
                hba->dev_count--;
                spin_unlock(&hba->device_lock);
index eb56eb1295635848f9577c2c4872f9cfab656324..3503996d7d10f667c4328c20ce8101e82b2b5c8e 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains generic fabric module configfs infrastructure for
  * TCM v4.x code
  *
- * (c) Copyright 2010-2012 RisingTide Systems LLC.
+ * (c) Copyright 2010-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@linux-iscsi.org>
 *
@@ -189,9 +189,11 @@ static ssize_t target_fabric_mappedlun_store_write_protect(
        struct se_node_acl *se_nacl = lacl->se_lun_nacl;
        struct se_portal_group *se_tpg = se_nacl->se_tpg;
        unsigned long op;
+       int ret;
 
-       if (strict_strtoul(page, 0, &op))
-               return -EINVAL;
+       ret = kstrtoul(page, 0, &op);
+       if (ret)
+               return ret;
 
        if ((op != 1) && (op != 0))
                return -EINVAL;
@@ -350,7 +352,10 @@ static struct config_group *target_fabric_make_mappedlun(
         * Determine the Mapped LUN value.  This is what the SCSI Initiator
         * Port will actually see.
         */
-       if (strict_strtoul(buf + 4, 0, &mapped_lun) || mapped_lun > UINT_MAX) {
+       ret = kstrtoul(buf + 4, 0, &mapped_lun);
+       if (ret)
+               goto out;
+       if (mapped_lun > UINT_MAX) {
                ret = -EINVAL;
                goto out;
        }
@@ -875,7 +880,10 @@ static struct config_group *target_fabric_make_lun(
                                " \"lun_$LUN_NUMBER\"\n");
                return ERR_PTR(-EINVAL);
        }
-       if (strict_strtoul(name + 4, 0, &unpacked_lun) || unpacked_lun > UINT_MAX)
+       errno = kstrtoul(name + 4, 0, &unpacked_lun);
+       if (errno)
+               return ERR_PTR(errno);
+       if (unpacked_lun > UINT_MAX)
                return ERR_PTR(-EINVAL);
 
        lun = core_get_lun_from_tpg(se_tpg, unpacked_lun);
index 687b0b0a4aa6794cffaf4174a9e9ec6c44067341..0d1cf8b4f49f64a182287f1c74e05a841fce6a30 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains generic high level protocol identifier and PR
  * handlers for TCM fabric modules
  *
- * (c) Copyright 2010-2012 RisingTide Systems LLC.
+ * (c) Copyright 2010-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index b11890d85120977d6e380db19192143ddab6251c..b662f89dedac39b0fe824e4d31583a9dc4553986 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains the Storage Engine <-> FILEIO transport specific functions
  *
- * (c) Copyright 2005-2012 RisingTide Systems LLC.
+ * (c) Copyright 2005-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -547,11 +547,9 @@ fd_execute_unmap(struct se_cmd *cmd)
 }
 
 static sense_reason_t
-fd_execute_rw(struct se_cmd *cmd)
+fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
+             enum dma_data_direction data_direction)
 {
-       struct scatterlist *sgl = cmd->t_data_sg;
-       u32 sgl_nents = cmd->t_data_nents;
-       enum dma_data_direction data_direction = cmd->data_direction;
        struct se_device *dev = cmd->se_dev;
        int ret = 0;
 
@@ -635,10 +633,10 @@ static ssize_t fd_set_configfs_dev_params(struct se_device *dev,
                                ret = -ENOMEM;
                                break;
                        }
-                       ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size);
+                       ret = kstrtoull(arg_p, 0, &fd_dev->fd_dev_size);
                        kfree(arg_p);
                        if (ret < 0) {
-                               pr_err("strict_strtoull() failed for"
+                               pr_err("kstrtoull() failed for"
                                                " fd_dev_size=\n");
                                goto out;
                        }
index d2616cd48f1e1febcc8d84efe62b2f27c5332184..a25051a37dd78fe7c17b7a807eb882332df828be 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains the TCM HBA Transport related functions.
  *
- * (c) Copyright 2003-2012 RisingTide Systems LLC.
+ * (c) Copyright 2003-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
index aa1620abec6dc0b1ccb5a78305ca2ed41800ac5d..b9a3394fe479225fe2bd16c84cb19bd448be99a3 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains the Storage Engine  <-> Linux BlockIO transport
  * specific functions.
  *
- * (c) Copyright 2003-2012 RisingTide Systems LLC.
+ * (c) Copyright 2003-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -536,10 +536,10 @@ static ssize_t iblock_set_configfs_dev_params(struct se_device *dev,
                                ret = -ENOMEM;
                                break;
                        }
-                       ret = strict_strtoul(arg_p, 0, &tmp_readonly);
+                       ret = kstrtoul(arg_p, 0, &tmp_readonly);
                        kfree(arg_p);
                        if (ret < 0) {
-                               pr_err("strict_strtoul() failed for"
+                               pr_err("kstrtoul() failed for"
                                                " readonly=\n");
                                goto out;
                        }
@@ -587,11 +587,9 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)
 }
 
 static sense_reason_t
-iblock_execute_rw(struct se_cmd *cmd)
+iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
+                 enum dma_data_direction data_direction)
 {
-       struct scatterlist *sgl = cmd->t_data_sg;
-       u32 sgl_nents = cmd->t_data_nents;
-       enum dma_data_direction data_direction = cmd->data_direction;
        struct se_device *dev = cmd->se_dev;
        struct iblock_req *ibr;
        struct bio *bio;
index 18d49df4d0ac59435c9b50ef87fb61723415c1c5..579128abe3f57e0f49a1689df47bffb4e4e307c8 100644 (file)
@@ -33,6 +33,8 @@ int   se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int);
 int    se_dev_set_emulate_tas(struct se_device *, int);
 int    se_dev_set_emulate_tpu(struct se_device *, int);
 int    se_dev_set_emulate_tpws(struct se_device *, int);
+int    se_dev_set_emulate_caw(struct se_device *, int);
+int    se_dev_set_emulate_3pc(struct se_device *, int);
 int    se_dev_set_enforce_pr_isids(struct se_device *, int);
 int    se_dev_set_is_nonrot(struct se_device *, int);
 int    se_dev_set_emulate_rest_reord(struct se_device *dev, int);
index bd78faf67c6b366657d572b8e8d1461af77abfec..d1ae4c5c3ffd05c5a849183387ac949cb1fed42b 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains SPC-3 compliant persistent reservations and
  * legacy SPC-2 reservations with compatible reservation handling (CRH=1)
  *
- * (c) Copyright 2009-2012 RisingTide Systems LLC.
+ * (c) Copyright 2009-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -1949,7 +1949,7 @@ static int __core_scsi3_write_aptpl_to_file(
                pr_debug("Error writing APTPL metadata file: %s\n", path);
        fput(file);
 
-       return ret ? -EIO : 0;
+       return (ret < 0) ? -EIO : 0;
 }
 
 /*
index e992b27aa0904b75320991b0adbb65b3d84037b6..551c96ca60acab10e0033a8946693b1371bcbfbe 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains the generic target mode <-> Linux SCSI subsystem plugin.
  *
- * (c) Copyright 2003-2012 RisingTide Systems LLC.
+ * (c) Copyright 2003-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -1050,9 +1050,8 @@ pscsi_execute_cmd(struct se_cmd *cmd)
                req = blk_get_request(pdv->pdv_sd->request_queue,
                                (data_direction == DMA_TO_DEVICE),
                                GFP_KERNEL);
-               if (!req || IS_ERR(req)) {
-                       pr_err("PSCSI: blk_get_request() failed: %ld\n",
-                                       req ? IS_ERR(req) : -ENOMEM);
+               if (!req) {
+                       pr_err("PSCSI: blk_get_request() failed\n");
                        ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
                        goto fail;
                }
index 51127d15d5c5accd6e39a8c408ef35a0f521db2f..131327ac7f5b947652539dda2eef052ba464854b 100644 (file)
@@ -4,7 +4,7 @@
  * This file contains the Storage Engine <-> Ramdisk transport
  * specific functions.
  *
- * (c) Copyright 2003-2012 RisingTide Systems LLC.
+ * (c) Copyright 2003-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -280,11 +280,9 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
 }
 
 static sense_reason_t
-rd_execute_rw(struct se_cmd *cmd)
+rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
+             enum dma_data_direction data_direction)
 {
-       struct scatterlist *sgl = cmd->t_data_sg;
-       u32 sgl_nents = cmd->t_data_nents;
-       enum dma_data_direction data_direction = cmd->data_direction;
        struct se_device *se_dev = cmd->se_dev;
        struct rd_dev *dev = RD_DEV(se_dev);
        struct rd_dev_sg_table *table;
index 8a462773d0c84cec3ae46f1006d75e12dec75279..6c17295e8d7ca9db7a0d262a087ce81ffaa1091c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SCSI Block Commands (SBC) parsing and emulation.
  *
- * (c) Copyright 2002-2012 RisingTide Systems LLC.
+ * (c) Copyright 2002-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -25,6 +25,7 @@
 #include <linux/ratelimit.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
 
 #include <target/target_core_base.h>
 #include <target/target_core_backend.h>
@@ -280,13 +281,13 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
        return 0;
 }
 
-static void xdreadwrite_callback(struct se_cmd *cmd)
+static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd)
 {
        unsigned char *buf, *addr;
        struct scatterlist *sg;
        unsigned int offset;
-       int i;
-       int count;
+       sense_reason_t ret = TCM_NO_SENSE;
+       int i, count;
        /*
         * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command
         *
@@ -301,7 +302,7 @@ static void xdreadwrite_callback(struct se_cmd *cmd)
        buf = kmalloc(cmd->data_length, GFP_KERNEL);
        if (!buf) {
                pr_err("Unable to allocate xor_callback buf\n");
-               return;
+               return TCM_OUT_OF_RESOURCES;
        }
        /*
         * Copy the scatterlist WRITE buffer located at cmd->t_data_sg
@@ -320,8 +321,10 @@ static void xdreadwrite_callback(struct se_cmd *cmd)
        offset = 0;
        for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) {
                addr = kmap_atomic(sg_page(sg));
-               if (!addr)
+               if (!addr) {
+                       ret = TCM_OUT_OF_RESOURCES;
                        goto out;
+               }
 
                for (i = 0; i < sg->length; i++)
                        *(addr + sg->offset + i) ^= *(buf + offset + i);
@@ -332,6 +335,193 @@ static void xdreadwrite_callback(struct se_cmd *cmd)
 
 out:
        kfree(buf);
+       return ret;
+}
+
+static sense_reason_t
+sbc_execute_rw(struct se_cmd *cmd)
+{
+       return cmd->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents,
+                              cmd->data_direction);
+}
+
+static sense_reason_t compare_and_write_post(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+
+       cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+       /*
+        * Unlock ->caw_sem originally obtained during sbc_compare_and_write()
+        * before the original READ I/O submission.
+        */
+       up(&dev->caw_sem);
+
+       return TCM_NO_SENSE;
+}
+
+static sense_reason_t compare_and_write_callback(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct scatterlist *write_sg = NULL, *sg;
+       unsigned char *buf, *addr;
+       struct sg_mapping_iter m;
+       unsigned int offset = 0, len;
+       unsigned int nlbas = cmd->t_task_nolb;
+       unsigned int block_size = dev->dev_attrib.block_size;
+       unsigned int compare_len = (nlbas * block_size);
+       sense_reason_t ret = TCM_NO_SENSE;
+       int rc, i;
+
+       /*
+        * Handle early failure in transport_generic_request_failure(),
+        * which will not have taken ->caw_mutex yet..
+        */
+       if (!cmd->t_data_sg || !cmd->t_bidi_data_sg)
+               return TCM_NO_SENSE;
+
+       buf = kzalloc(cmd->data_length, GFP_KERNEL);
+       if (!buf) {
+               pr_err("Unable to allocate compare_and_write buf\n");
+               ret = TCM_OUT_OF_RESOURCES;
+               goto out;
+       }
+
+       write_sg = kzalloc(sizeof(struct scatterlist) * cmd->t_data_nents,
+                          GFP_KERNEL);
+       if (!write_sg) {
+               pr_err("Unable to allocate compare_and_write sg\n");
+               ret = TCM_OUT_OF_RESOURCES;
+               goto out;
+       }
+       /*
+        * Setup verify and write data payloads from total NumberLBAs.
+        */
+       rc = sg_copy_to_buffer(cmd->t_data_sg, cmd->t_data_nents, buf,
+                              cmd->data_length);
+       if (!rc) {
+               pr_err("sg_copy_to_buffer() failed for compare_and_write\n");
+               ret = TCM_OUT_OF_RESOURCES;
+               goto out;
+       }
+       /*
+        * Compare against SCSI READ payload against verify payload
+        */
+       for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, i) {
+               addr = (unsigned char *)kmap_atomic(sg_page(sg));
+               if (!addr) {
+                       ret = TCM_OUT_OF_RESOURCES;
+                       goto out;
+               }
+
+               len = min(sg->length, compare_len);
+
+               if (memcmp(addr, buf + offset, len)) {
+                       pr_warn("Detected MISCOMPARE for addr: %p buf: %p\n",
+                               addr, buf + offset);
+                       kunmap_atomic(addr);
+                       goto miscompare;
+               }
+               kunmap_atomic(addr);
+
+               offset += len;
+               compare_len -= len;
+               if (!compare_len)
+                       break;
+       }
+
+       i = 0;
+       len = cmd->t_task_nolb * block_size;
+       sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG);
+       /*
+        * Currently assumes NoLB=1 and SGLs are PAGE_SIZE..
+        */
+       while (len) {
+               sg_miter_next(&m);
+
+               if (block_size < PAGE_SIZE) {
+                       sg_set_page(&write_sg[i], m.page, block_size,
+                                   block_size);
+               } else {
+                       sg_miter_next(&m);
+                       sg_set_page(&write_sg[i], m.page, block_size,
+                                   0);
+               }
+               len -= block_size;
+               i++;
+       }
+       sg_miter_stop(&m);
+       /*
+        * Save the original SGL + nents values before updating to new
+        * assignments, to be released in transport_free_pages() ->
+        * transport_reset_sgl_orig()
+        */
+       cmd->t_data_sg_orig = cmd->t_data_sg;
+       cmd->t_data_sg = write_sg;
+       cmd->t_data_nents_orig = cmd->t_data_nents;
+       cmd->t_data_nents = 1;
+
+       cmd->sam_task_attr = MSG_HEAD_TAG;
+       cmd->transport_complete_callback = compare_and_write_post;
+       /*
+        * Now reset ->execute_cmd() to the normal sbc_execute_rw() handler
+        * for submitting the adjusted SGL to write instance user-data.
+        */
+       cmd->execute_cmd = sbc_execute_rw;
+
+       spin_lock_irq(&cmd->t_state_lock);
+       cmd->t_state = TRANSPORT_PROCESSING;
+       cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT;
+       spin_unlock_irq(&cmd->t_state_lock);
+
+       __target_execute_cmd(cmd);
+
+       kfree(buf);
+       return ret;
+
+miscompare:
+       pr_warn("Target/%s: Send MISCOMPARE check condition and sense\n",
+               dev->transport->name);
+       ret = TCM_MISCOMPARE_VERIFY;
+out:
+       /*
+        * In the MISCOMPARE or failure case, unlock ->caw_sem obtained in
+        * sbc_compare_and_write() before the original READ I/O submission.
+        */
+       up(&dev->caw_sem);
+       kfree(write_sg);
+       kfree(buf);
+       return ret;
+}
+
+static sense_reason_t
+sbc_compare_and_write(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       sense_reason_t ret;
+       int rc;
+       /*
+        * Submit the READ first for COMPARE_AND_WRITE to perform the
+        * comparision using SGLs at cmd->t_bidi_data_sg..
+        */
+       rc = down_interruptible(&dev->caw_sem);
+       if ((rc != 0) || signal_pending(current)) {
+               cmd->transport_complete_callback = NULL;
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+       }
+
+       ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents,
+                             DMA_FROM_DEVICE);
+       if (ret) {
+               cmd->transport_complete_callback = NULL;
+               up(&dev->caw_sem);
+               return ret;
+       }
+       /*
+        * Unlock of dev->caw_sem to occur in compare_and_write_callback()
+        * upon MISCOMPARE, or in compare_and_write_done() upon completion
+        * of WRITE instance user-data.
+        */
+       return TCM_NO_SENSE;
 }
 
 sense_reason_t
@@ -348,31 +538,36 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                sectors = transport_get_sectors_6(cdb);
                cmd->t_task_lba = transport_lba_21(cdb);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case READ_10:
                sectors = transport_get_sectors_10(cdb);
                cmd->t_task_lba = transport_lba_32(cdb);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case READ_12:
                sectors = transport_get_sectors_12(cdb);
                cmd->t_task_lba = transport_lba_32(cdb);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case READ_16:
                sectors = transport_get_sectors_16(cdb);
                cmd->t_task_lba = transport_lba_64(cdb);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case WRITE_6:
                sectors = transport_get_sectors_6(cdb);
                cmd->t_task_lba = transport_lba_21(cdb);
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case WRITE_10:
        case WRITE_VERIFY:
@@ -381,7 +576,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case WRITE_12:
                sectors = transport_get_sectors_12(cdb);
@@ -389,7 +585,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case WRITE_16:
                sectors = transport_get_sectors_16(cdb);
@@ -397,7 +594,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                break;
        case XDWRITEREAD_10:
                if (cmd->data_direction != DMA_TO_DEVICE ||
@@ -411,7 +609,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                /*
                 * Setup BIDI XOR callback to be run after I/O completion.
                 */
-               cmd->execute_cmd = ops->execute_rw;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_execute_rw;
                cmd->transport_complete_callback = &xdreadwrite_callback;
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
@@ -434,7 +633,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                         * Setup BIDI XOR callback to be run during after I/O
                         * completion.
                         */
-                       cmd->execute_cmd = ops->execute_rw;
+                       cmd->execute_rw = ops->execute_rw;
+                       cmd->execute_cmd = sbc_execute_rw;
                        cmd->transport_complete_callback = &xdreadwrite_callback;
                        if (cdb[1] & 0x8)
                                cmd->se_cmd_flags |= SCF_FUA;
@@ -461,6 +661,28 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                }
                break;
        }
+       case COMPARE_AND_WRITE:
+               sectors = cdb[13];
+               /*
+                * Currently enforce COMPARE_AND_WRITE for a single sector
+                */
+               if (sectors > 1) {
+                       pr_err("COMPARE_AND_WRITE contains NoLB: %u greater"
+                              " than 1\n", sectors);
+                       return TCM_INVALID_CDB_FIELD;
+               }
+               /*
+                * Double size because we have two buffers, note that
+                * zero is not an error..
+                */
+               size = 2 * sbc_get_size(cmd, sectors);
+               cmd->t_task_lba = get_unaligned_be64(&cdb[2]);
+               cmd->t_task_nolb = sectors;
+               cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB | SCF_COMPARE_AND_WRITE;
+               cmd->execute_rw = ops->execute_rw;
+               cmd->execute_cmd = sbc_compare_and_write;
+               cmd->transport_complete_callback = compare_and_write_callback;
+               break;
        case READ_CAPACITY:
                size = READ_CAP_LEN;
                cmd->execute_cmd = sbc_emulate_readcapacity;
@@ -600,7 +822,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                        return TCM_ADDRESS_OUT_OF_RANGE;
                }
 
-               size = sbc_get_size(cmd, sectors);
+               if (!(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE))
+                       size = sbc_get_size(cmd, sectors);
        }
 
        return target_cmd_size_check(cmd, size);
index 9fabbf7214cd70cc3d4ad3e1bfa74f7ac516cdd0..074539558a542d5a38dc4f911f0032dc4ed0c998 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SCSI Primary Commands (SPC) parsing and emulation.
  *
- * (c) Copyright 2002-2012 RisingTide Systems LLC.
+ * (c) Copyright 2002-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -35,7 +35,7 @@
 #include "target_core_alua.h"
 #include "target_core_pr.h"
 #include "target_core_ua.h"
-
+#include "target_core_xcopy.h"
 
 static void spc_fill_alua_data(struct se_port *port, unsigned char *buf)
 {
@@ -95,6 +95,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
         */
        spc_fill_alua_data(lun->lun_sep, buf);
 
+       /*
+        * Set Third-Party Copy (3PC) bit to indicate support for EXTENDED_COPY
+        */
+       if (dev->dev_attrib.emulate_3pc)
+               buf[5] |= 0x8;
+
        buf[7] = 0x2; /* CmdQue=1 */
 
        memcpy(&buf[8], "LIO-ORG ", 8);
@@ -129,8 +135,8 @@ spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf)
        return 0;
 }
 
-static void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
-               unsigned char *buf)
+void spc_parse_naa_6h_vendor_specific(struct se_device *dev,
+                                     unsigned char *buf)
 {
        unsigned char *p = &dev->t10_wwn.unit_serial[0];
        int cnt;
@@ -460,6 +466,11 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf)
 
        /* Set WSNZ to 1 */
        buf[4] = 0x01;
+       /*
+        * Set MAXIMUM COMPARE AND WRITE LENGTH
+        */
+       if (dev->dev_attrib.emulate_caw)
+               buf[5] = 0x01;
 
        /*
         * Set OPTIMAL TRANSFER LENGTH GRANULARITY
@@ -1250,8 +1261,14 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
                *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
                break;
        case EXTENDED_COPY:
-       case READ_ATTRIBUTE:
+               *size = get_unaligned_be32(&cdb[10]);
+               cmd->execute_cmd = target_do_xcopy;
+               break;
        case RECEIVE_COPY_RESULTS:
+               *size = get_unaligned_be32(&cdb[10]);
+               cmd->execute_cmd = target_do_receive_copy_results;
+               break;
+       case READ_ATTRIBUTE:
        case WRITE_ATTRIBUTE:
                *size = (cdb[10] << 24) | (cdb[11] << 16) |
                       (cdb[12] << 8) | cdb[13];
index d154ce7971801c54a86bcf6f510246826aa67371..9c642e02cba15e37c149800a2ff5fa2a1c42c920 100644 (file)
@@ -4,7 +4,7 @@
  * Modern ConfigFS group context specific statistics based on original
  * target_core_mib.c code
  *
- * (c) Copyright 2006-2012 RisingTide Systems LLC.
+ * (c) Copyright 2006-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@linux-iscsi.org>
  *
index 0d7cacb911078929ae99d94abbb249e0c7c699b5..250009909d497119fb356fd678c674f094a37185 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains SPC-3 task management infrastructure
  *
- * (c) Copyright 2009-2012 RisingTide Systems LLC.
+ * (c) Copyright 2009-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
index aac9d2727e3c8584a20db563ef5c914bc758de19..b9a6ec0aa5fe8fc0a76f4833fe0591ebdea7e155 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains generic Target Portal Group related functions.
  *
- * (c) Copyright 2002-2012 RisingTide Systems LLC.
+ * (c) Copyright 2002-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
index d8e49d79f8cca5f45bc02355a32a02d2261a5e4e..84747cc1aac0aa4d001dda34bc22d09c52685362 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains the Generic Target Engine Core.
  *
- * (c) Copyright 2002-2012 RisingTide Systems LLC.
+ * (c) Copyright 2002-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
@@ -67,7 +67,6 @@ struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
 static void transport_complete_task_attr(struct se_cmd *cmd);
 static void transport_handle_queue_full(struct se_cmd *cmd,
                struct se_device *dev);
-static int transport_generic_get_mem(struct se_cmd *cmd);
 static int transport_put_cmd(struct se_cmd *cmd);
 static void target_complete_ok_work(struct work_struct *work);
 
@@ -232,6 +231,50 @@ struct se_session *transport_init_session(void)
 }
 EXPORT_SYMBOL(transport_init_session);
 
+int transport_alloc_session_tags(struct se_session *se_sess,
+                                unsigned int tag_num, unsigned int tag_size)
+{
+       int rc;
+
+       se_sess->sess_cmd_map = kzalloc(tag_num * tag_size, GFP_KERNEL);
+       if (!se_sess->sess_cmd_map) {
+               pr_err("Unable to allocate se_sess->sess_cmd_map\n");
+               return -ENOMEM;
+       }
+
+       rc = percpu_ida_init(&se_sess->sess_tag_pool, tag_num);
+       if (rc < 0) {
+               pr_err("Unable to init se_sess->sess_tag_pool,"
+                       " tag_num: %u\n", tag_num);
+               kfree(se_sess->sess_cmd_map);
+               se_sess->sess_cmd_map = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(transport_alloc_session_tags);
+
+struct se_session *transport_init_session_tags(unsigned int tag_num,
+                                              unsigned int tag_size)
+{
+       struct se_session *se_sess;
+       int rc;
+
+       se_sess = transport_init_session();
+       if (IS_ERR(se_sess))
+               return se_sess;
+
+       rc = transport_alloc_session_tags(se_sess, tag_num, tag_size);
+       if (rc < 0) {
+               transport_free_session(se_sess);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return se_sess;
+}
+EXPORT_SYMBOL(transport_init_session_tags);
+
 /*
  * Called with spin_lock_irqsave(&struct se_portal_group->session_lock called.
  */
@@ -367,6 +410,10 @@ EXPORT_SYMBOL(transport_deregister_session_configfs);
 
 void transport_free_session(struct se_session *se_sess)
 {
+       if (se_sess->sess_cmd_map) {
+               percpu_ida_destroy(&se_sess->sess_tag_pool);
+               kfree(se_sess->sess_cmd_map);
+       }
        kmem_cache_free(se_sess_cache, se_sess);
 }
 EXPORT_SYMBOL(transport_free_session);
@@ -1206,7 +1253,7 @@ int transport_handle_cdb_direct(
 }
 EXPORT_SYMBOL(transport_handle_cdb_direct);
 
-static sense_reason_t
+sense_reason_t
 transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
                u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count)
 {
@@ -1512,6 +1559,13 @@ void transport_generic_request_failure(struct se_cmd *cmd,
         * For SAM Task Attribute emulation for failed struct se_cmd
         */
        transport_complete_task_attr(cmd);
+       /*
+        * Handle special case for COMPARE_AND_WRITE failure, where the
+        * callback is expected to drop the per device ->caw_mutex.
+        */
+       if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
+            cmd->transport_complete_callback)
+               cmd->transport_complete_callback(cmd);
 
        switch (sense_reason) {
        case TCM_NON_EXISTENT_LUN:
@@ -1579,7 +1633,7 @@ queue_full:
 }
 EXPORT_SYMBOL(transport_generic_request_failure);
 
-static void __target_execute_cmd(struct se_cmd *cmd)
+void __target_execute_cmd(struct se_cmd *cmd)
 {
        sense_reason_t ret;
 
@@ -1784,7 +1838,7 @@ static void transport_complete_qf(struct se_cmd *cmd)
                ret = cmd->se_tfo->queue_data_in(cmd);
                break;
        case DMA_TO_DEVICE:
-               if (cmd->t_bidi_data_sg) {
+               if (cmd->se_cmd_flags & SCF_BIDI) {
                        ret = cmd->se_tfo->queue_data_in(cmd);
                        if (ret < 0)
                                break;
@@ -1856,10 +1910,25 @@ static void target_complete_ok_work(struct work_struct *work)
        }
        /*
         * Check for a callback, used by amongst other things
-        * XDWRITE_READ_10 emulation.
+        * XDWRITE_READ_10 and COMPARE_AND_WRITE emulation.
         */
-       if (cmd->transport_complete_callback)
-               cmd->transport_complete_callback(cmd);
+       if (cmd->transport_complete_callback) {
+               sense_reason_t rc;
+
+               rc = cmd->transport_complete_callback(cmd);
+               if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) {
+                       return;
+               } else if (rc) {
+                       ret = transport_send_check_condition_and_sense(cmd,
+                                               rc, 0);
+                       if (ret == -EAGAIN || ret == -ENOMEM)
+                               goto queue_full;
+
+                       transport_lun_remove_cmd(cmd);
+                       transport_cmd_check_stop_to_fabric(cmd);
+                       return;
+               }
+       }
 
        switch (cmd->data_direction) {
        case DMA_FROM_DEVICE:
@@ -1885,7 +1954,7 @@ static void target_complete_ok_work(struct work_struct *work)
                /*
                 * Check if we need to send READ payload for BIDI-COMMAND
                 */
-               if (cmd->t_bidi_data_sg) {
+               if (cmd->se_cmd_flags & SCF_BIDI) {
                        spin_lock(&cmd->se_lun->lun_sep_lock);
                        if (cmd->se_lun->lun_sep) {
                                cmd->se_lun->lun_sep->sep_stats.tx_data_octets +=
@@ -1930,10 +1999,29 @@ static inline void transport_free_sgl(struct scatterlist *sgl, int nents)
        kfree(sgl);
 }
 
+static inline void transport_reset_sgl_orig(struct se_cmd *cmd)
+{
+       /*
+        * Check for saved t_data_sg that may be used for COMPARE_AND_WRITE
+        * emulation, and free + reset pointers if necessary..
+        */
+       if (!cmd->t_data_sg_orig)
+               return;
+
+       kfree(cmd->t_data_sg);
+       cmd->t_data_sg = cmd->t_data_sg_orig;
+       cmd->t_data_sg_orig = NULL;
+       cmd->t_data_nents = cmd->t_data_nents_orig;
+       cmd->t_data_nents_orig = 0;
+}
+
 static inline void transport_free_pages(struct se_cmd *cmd)
 {
-       if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC)
+       if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) {
+               transport_reset_sgl_orig(cmd);
                return;
+       }
+       transport_reset_sgl_orig(cmd);
 
        transport_free_sgl(cmd->t_data_sg, cmd->t_data_nents);
        cmd->t_data_sg = NULL;
@@ -2029,24 +2117,22 @@ void transport_kunmap_data_sg(struct se_cmd *cmd)
 }
 EXPORT_SYMBOL(transport_kunmap_data_sg);
 
-static int
-transport_generic_get_mem(struct se_cmd *cmd)
+int
+target_alloc_sgl(struct scatterlist **sgl, unsigned int *nents, u32 length,
+                bool zero_page)
 {
-       u32 length = cmd->data_length;
-       unsigned int nents;
+       struct scatterlist *sg;
        struct page *page;
-       gfp_t zero_flag;
+       gfp_t zero_flag = (zero_page) ? __GFP_ZERO : 0;
+       unsigned int nent;
        int i = 0;
 
-       nents = DIV_ROUND_UP(length, PAGE_SIZE);
-       cmd->t_data_sg = kmalloc(sizeof(struct scatterlist) * nents, GFP_KERNEL);
-       if (!cmd->t_data_sg)
+       nent = DIV_ROUND_UP(length, PAGE_SIZE);
+       sg = kmalloc(sizeof(struct scatterlist) * nent, GFP_KERNEL);
+       if (!sg)
                return -ENOMEM;
 
-       cmd->t_data_nents = nents;
-       sg_init_table(cmd->t_data_sg, nents);
-
-       zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_CDB ? 0 : __GFP_ZERO;
+       sg_init_table(sg, nent);
 
        while (length) {
                u32 page_len = min_t(u32, length, PAGE_SIZE);
@@ -2054,19 +2140,20 @@ transport_generic_get_mem(struct se_cmd *cmd)
                if (!page)
                        goto out;
 
-               sg_set_page(&cmd->t_data_sg[i], page, page_len, 0);
+               sg_set_page(&sg[i], page, page_len, 0);
                length -= page_len;
                i++;
        }
+       *sgl = sg;
+       *nents = nent;
        return 0;
 
 out:
        while (i > 0) {
                i--;
-               __free_page(sg_page(&cmd->t_data_sg[i]));
+               __free_page(sg_page(&sg[i]));
        }
-       kfree(cmd->t_data_sg);
-       cmd->t_data_sg = NULL;
+       kfree(sg);
        return -ENOMEM;
 }
 
@@ -2087,7 +2174,27 @@ transport_generic_new_cmd(struct se_cmd *cmd)
         */
        if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) &&
            cmd->data_length) {
-               ret = transport_generic_get_mem(cmd);
+               bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB);
+
+               if ((cmd->se_cmd_flags & SCF_BIDI) ||
+                   (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) {
+                       u32 bidi_length;
+
+                       if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)
+                               bidi_length = cmd->t_task_nolb *
+                                             cmd->se_dev->dev_attrib.block_size;
+                       else
+                               bidi_length = cmd->data_length;
+
+                       ret = target_alloc_sgl(&cmd->t_bidi_data_sg,
+                                              &cmd->t_bidi_data_nents,
+                                              bidi_length, zero_flag);
+                       if (ret < 0)
+                               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               }
+
+               ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents,
+                                      cmd->data_length, zero_flag);
                if (ret < 0)
                        return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
        }
@@ -2740,6 +2847,15 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
                buffer[SPC_ASC_KEY_OFFSET] = asc;
                buffer[SPC_ASCQ_KEY_OFFSET] = ascq;
                break;
+       case TCM_MISCOMPARE_VERIFY:
+               /* CURRENT ERROR */
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               buffer[SPC_SENSE_KEY_OFFSET] = MISCOMPARE;
+               /* MISCOMPARE DURING VERIFY OPERATION */
+               buffer[SPC_ASC_KEY_OFFSET] = 0x1d;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x00;
+               break;
        case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
        default:
                /* CURRENT ERROR */
index bf0e390ce2d70503a7f6b006da8aeb2d26bdfcba..b04467e7547c97817e611e2341568bd7a592a1e1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * This file contains logic for SPC-3 Unit Attention emulation
  *
- * (c) Copyright 2009-2012 RisingTide Systems LLC.
+ * (c) Copyright 2009-2013 Datera, Inc.
  *
  * Nicholas A. Bellinger <nab@kernel.org>
  *
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c
new file mode 100644 (file)
index 0000000..4d22e7d
--- /dev/null
@@ -0,0 +1,1081 @@
+/*******************************************************************************
+ * Filename: target_core_xcopy.c
+ *
+ * This file contains support for SPC-4 Extended-Copy offload with generic
+ * TCM backends.
+ *
+ * Copyright (c) 2011-2013 Datera, Inc. All rights reserved.
+ *
+ * Author:
+ * Nicholas A. Bellinger <nab@daterainc.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.
+ *
+ ******************************************************************************/
+
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/configfs.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <asm/unaligned.h>
+
+#include <target/target_core_base.h>
+#include <target/target_core_backend.h>
+#include <target/target_core_fabric.h>
+#include <target/target_core_configfs.h>
+
+#include "target_core_pr.h"
+#include "target_core_ua.h"
+#include "target_core_xcopy.h"
+
+static struct workqueue_struct *xcopy_wq = NULL;
+/*
+ * From target_core_spc.c
+ */
+extern void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *);
+/*
+ * From target_core_device.c
+ */
+extern struct mutex g_device_mutex;
+extern struct list_head g_device_list;
+/*
+ * From target_core_configfs.c
+ */
+extern struct configfs_subsystem *target_core_subsystem[];
+
+static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf)
+{
+       int off = 0;
+
+       buf[off++] = (0x6 << 4);
+       buf[off++] = 0x01;
+       buf[off++] = 0x40;
+       buf[off] = (0x5 << 4);
+
+       spc_parse_naa_6h_vendor_specific(dev, &buf[off]);
+       return 0;
+}
+
+static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
+                                       bool src)
+{
+       struct se_device *se_dev;
+       struct configfs_subsystem *subsys = target_core_subsystem[0];
+       unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn;
+       int rc;
+
+       if (src == true)
+               dev_wwn = &xop->dst_tid_wwn[0];
+       else
+               dev_wwn = &xop->src_tid_wwn[0];
+
+       mutex_lock(&g_device_mutex);
+       list_for_each_entry(se_dev, &g_device_list, g_dev_node) {
+
+               memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+               target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]);
+
+               rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN);
+               if (rc != 0)
+                       continue;
+
+               if (src == true) {
+                       xop->dst_dev = se_dev;
+                       pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located"
+                               " se_dev\n", xop->dst_dev);
+               } else {
+                       xop->src_dev = se_dev;
+                       pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located"
+                               " se_dev\n", xop->src_dev);
+               }
+
+               rc = configfs_depend_item(subsys,
+                               &se_dev->dev_group.cg_item);
+               if (rc != 0) {
+                       pr_err("configfs_depend_item attempt failed:"
+                               " %d for se_dev: %p\n", rc, se_dev);
+                       mutex_unlock(&g_device_mutex);
+                       return rc;
+               }
+
+               pr_debug("Called configfs_depend_item for subsys: %p se_dev: %p"
+                       " se_dev->se_dev_group: %p\n", subsys, se_dev,
+                       &se_dev->dev_group);
+
+               mutex_unlock(&g_device_mutex);
+               return 0;
+       }
+       mutex_unlock(&g_device_mutex);
+
+       pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n");
+       return -EINVAL;
+}
+
+static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop,
+                               unsigned char *p, bool src)
+{
+       unsigned char *desc = p;
+       unsigned short ript;
+       u8 desig_len;
+       /*
+        * Extract RELATIVE INITIATOR PORT IDENTIFIER
+        */
+       ript = get_unaligned_be16(&desc[2]);
+       pr_debug("XCOPY 0xe4: RELATIVE INITIATOR PORT IDENTIFIER: %hu\n", ript);
+       /*
+        * Check for supported code set, association, and designator type
+        */
+       if ((desc[4] & 0x0f) != 0x1) {
+               pr_err("XCOPY 0xe4: code set of non binary type not supported\n");
+               return -EINVAL;
+       }
+       if ((desc[5] & 0x30) != 0x00) {
+               pr_err("XCOPY 0xe4: association other than LUN not supported\n");
+               return -EINVAL;
+       }
+       if ((desc[5] & 0x0f) != 0x3) {
+               pr_err("XCOPY 0xe4: designator type unsupported: 0x%02x\n",
+                               (desc[5] & 0x0f));
+               return -EINVAL;
+       }
+       /*
+        * Check for matching 16 byte length for NAA IEEE Registered Extended
+        * Assigned designator
+        */
+       desig_len = desc[7];
+       if (desig_len != 16) {
+               pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len);
+               return -EINVAL;
+       }
+       pr_debug("XCOPY 0xe4: desig_len: %d\n", (int)desig_len);
+       /*
+        * Check for NAA IEEE Registered Extended Assigned header..
+        */
+       if ((desc[8] & 0xf0) != 0x60) {
+               pr_err("XCOPY 0xe4: Unsupported DESIGNATOR TYPE: 0x%02x\n",
+                                       (desc[8] & 0xf0));
+               return -EINVAL;
+       }
+
+       if (src == true) {
+               memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
+               /*
+                * Determine if the source designator matches the local device
+                */
+               if (!memcmp(&xop->local_dev_wwn[0], &xop->src_tid_wwn[0],
+                               XCOPY_NAA_IEEE_REGEX_LEN)) {
+                       xop->op_origin = XCOL_SOURCE_RECV_OP;
+                       xop->src_dev = se_cmd->se_dev;
+                       pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source"
+                                       " received xop\n", xop->src_dev);
+               }
+       } else {
+               memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN);
+               /*
+                * Determine if the destination designator matches the local device
+                */
+               if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0],
+                               XCOPY_NAA_IEEE_REGEX_LEN)) {
+                       xop->op_origin = XCOL_DEST_RECV_OP;
+                       xop->dst_dev = se_cmd->se_dev;
+                       pr_debug("XCOPY 0xe4: Set xop->dst_dev: %p from destination"
+                               " received xop\n", xop->dst_dev);
+               }
+       }
+
+       return 0;
+}
+
+static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd,
+                               struct xcopy_op *xop, unsigned char *p,
+                               unsigned short tdll)
+{
+       struct se_device *local_dev = se_cmd->se_dev;
+       unsigned char *desc = p;
+       int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0;
+       unsigned short start = 0;
+       bool src = true;
+
+       if (offset != 0) {
+               pr_err("XCOPY target descriptor list length is not"
+                       " multiple of %d\n", XCOPY_TARGET_DESC_LEN);
+               return -EINVAL;
+       }
+       if (tdll > 64) {
+               pr_err("XCOPY target descriptor supports a maximum"
+                       " two src/dest descriptors, tdll: %hu too large..\n", tdll);
+               return -EINVAL;
+       }
+       /*
+        * Generate an IEEE Registered Extended designator based upon the
+        * se_device the XCOPY was received upon..
+        */
+       memset(&xop->local_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN);
+       target_xcopy_gen_naa_ieee(local_dev, &xop->local_dev_wwn[0]);
+
+       while (start < tdll) {
+               /*
+                * Check target descriptor identification with 0xE4 type with
+                * use VPD 0x83 WWPN matching ..
+                */
+               switch (desc[0]) {
+               case 0xe4:
+                       rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop,
+                                                       &desc[0], src);
+                       if (rc != 0)
+                               goto out;
+                       /*
+                        * Assume target descriptors are in source -> destination order..
+                        */
+                       if (src == true)
+                               src = false;
+                       else
+                               src = true;
+                       start += XCOPY_TARGET_DESC_LEN;
+                       desc += XCOPY_TARGET_DESC_LEN;
+                       ret++;
+                       break;
+               default:
+                       pr_err("XCOPY unsupported descriptor type code:"
+                                       " 0x%02x\n", desc[0]);
+                       goto out;
+               }
+       }
+
+       if (xop->op_origin == XCOL_SOURCE_RECV_OP)
+               rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true);
+       else
+               rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false);
+
+       if (rc < 0)
+               goto out;
+
+       pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n",
+                xop->src_dev, &xop->src_tid_wwn[0]);
+       pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n",
+                xop->dst_dev, &xop->dst_tid_wwn[0]);
+
+       return ret;
+
+out:
+       return -EINVAL;
+}
+
+static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op *xop,
+                                       unsigned char *p)
+{
+       unsigned char *desc = p;
+       int dc = (desc[1] & 0x02);
+       unsigned short desc_len;
+
+       desc_len = get_unaligned_be16(&desc[2]);
+       if (desc_len != 0x18) {
+               pr_err("XCOPY segment desc 0x02: Illegal desc_len:"
+                               " %hu\n", desc_len);
+               return -EINVAL;
+       }
+
+       xop->stdi = get_unaligned_be16(&desc[4]);
+       xop->dtdi = get_unaligned_be16(&desc[6]);
+       pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n",
+               desc_len, xop->stdi, xop->dtdi, dc);
+
+       xop->nolb = get_unaligned_be16(&desc[10]);
+       xop->src_lba = get_unaligned_be64(&desc[12]);
+       xop->dst_lba = get_unaligned_be64(&desc[20]);
+       pr_debug("XCOPY seg desc 0x02: nolb: %hu src_lba: %llu dst_lba: %llu\n",
+               xop->nolb, (unsigned long long)xop->src_lba,
+               (unsigned long long)xop->dst_lba);
+
+       if (dc != 0) {
+               xop->dbl = (desc[29] << 16) & 0xff;
+               xop->dbl |= (desc[30] << 8) & 0xff;
+               xop->dbl |= desc[31] & 0xff;
+
+               pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl);
+       }
+       return 0;
+}
+
+static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd,
+                               struct xcopy_op *xop, unsigned char *p,
+                               unsigned int sdll)
+{
+       unsigned char *desc = p;
+       unsigned int start = 0;
+       int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0;
+
+       if (offset != 0) {
+               pr_err("XCOPY segment descriptor list length is not"
+                       " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN);
+               return -EINVAL;
+       }
+
+       while (start < sdll) {
+               /*
+                * Check segment descriptor type code for block -> block
+                */
+               switch (desc[0]) {
+               case 0x02:
+                       rc = target_xcopy_parse_segdesc_02(se_cmd, xop, desc);
+                       if (rc < 0)
+                               goto out;
+
+                       ret++;
+                       start += XCOPY_SEGMENT_DESC_LEN;
+                       desc += XCOPY_SEGMENT_DESC_LEN;
+                       break;
+               default:
+                       pr_err("XCOPY unspported segment descriptor"
+                               "type: 0x%02x\n", desc[0]);
+                       goto out;
+               }
+       }
+
+       return ret;
+
+out:
+       return -EINVAL;
+}
+
+/*
+ * Start xcopy_pt ops
+ */
+
+struct xcopy_pt_cmd {
+       bool remote_port;
+       struct se_cmd se_cmd;
+       struct xcopy_op *xcopy_op;
+       struct completion xpt_passthrough_sem;
+};
+
+static struct se_port xcopy_pt_port;
+static struct se_portal_group xcopy_pt_tpg;
+static struct se_session xcopy_pt_sess;
+static struct se_node_acl xcopy_pt_nacl;
+
+static char *xcopy_pt_get_fabric_name(void)
+{
+        return "xcopy-pt";
+}
+
+static u32 xcopy_pt_get_tag(struct se_cmd *se_cmd)
+{
+        return 0;
+}
+
+static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd)
+{
+        return 0;
+}
+
+static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop)
+{
+       struct configfs_subsystem *subsys = target_core_subsystem[0];
+       struct se_device *remote_dev;
+
+       if (xop->op_origin == XCOL_SOURCE_RECV_OP)
+               remote_dev = xop->dst_dev;
+       else
+               remote_dev = xop->src_dev;
+
+       pr_debug("Calling configfs_undepend_item for subsys: %p"
+                 " remote_dev: %p remote_dev->dev_group: %p\n",
+                 subsys, remote_dev, &remote_dev->dev_group.cg_item);
+
+       configfs_undepend_item(subsys, &remote_dev->dev_group.cg_item);
+}
+
+static void xcopy_pt_release_cmd(struct se_cmd *se_cmd)
+{
+       struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
+                               struct xcopy_pt_cmd, se_cmd);
+
+       if (xpt_cmd->remote_port)
+               kfree(se_cmd->se_lun);
+
+       kfree(xpt_cmd);
+}
+
+static int xcopy_pt_check_stop_free(struct se_cmd *se_cmd)
+{
+       struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd,
+                               struct xcopy_pt_cmd, se_cmd);
+
+       complete(&xpt_cmd->xpt_passthrough_sem);
+       return 0;
+}
+
+static int xcopy_pt_write_pending(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int xcopy_pt_write_pending_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int xcopy_pt_queue_data_in(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static int xcopy_pt_queue_status(struct se_cmd *se_cmd)
+{
+       return 0;
+}
+
+static struct target_core_fabric_ops xcopy_pt_tfo = {
+       .get_fabric_name        = xcopy_pt_get_fabric_name,
+       .get_task_tag           = xcopy_pt_get_tag,
+       .get_cmd_state          = xcopy_pt_get_cmd_state,
+       .release_cmd            = xcopy_pt_release_cmd,
+       .check_stop_free        = xcopy_pt_check_stop_free,
+       .write_pending          = xcopy_pt_write_pending,
+       .write_pending_status   = xcopy_pt_write_pending_status,
+       .queue_data_in          = xcopy_pt_queue_data_in,
+       .queue_status           = xcopy_pt_queue_status,
+};
+
+/*
+ * End xcopy_pt_ops
+ */
+
+int target_xcopy_setup_pt(void)
+{
+       xcopy_wq = alloc_workqueue("xcopy_wq", WQ_MEM_RECLAIM, 0);
+       if (!xcopy_wq) {
+               pr_err("Unable to allocate xcopy_wq\n");
+               return -ENOMEM;
+       }
+
+       memset(&xcopy_pt_port, 0, sizeof(struct se_port));
+       INIT_LIST_HEAD(&xcopy_pt_port.sep_alua_list);
+       INIT_LIST_HEAD(&xcopy_pt_port.sep_list);
+       mutex_init(&xcopy_pt_port.sep_tg_pt_md_mutex);
+
+       memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group));
+       INIT_LIST_HEAD(&xcopy_pt_tpg.se_tpg_node);
+       INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list);
+       INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list);
+
+       xcopy_pt_port.sep_tpg = &xcopy_pt_tpg;
+       xcopy_pt_tpg.se_tpg_tfo = &xcopy_pt_tfo;
+
+       memset(&xcopy_pt_nacl, 0, sizeof(struct se_node_acl));
+       INIT_LIST_HEAD(&xcopy_pt_nacl.acl_list);
+       INIT_LIST_HEAD(&xcopy_pt_nacl.acl_sess_list);
+       memset(&xcopy_pt_sess, 0, sizeof(struct se_session));
+       INIT_LIST_HEAD(&xcopy_pt_sess.sess_list);
+       INIT_LIST_HEAD(&xcopy_pt_sess.sess_acl_list);
+
+       xcopy_pt_nacl.se_tpg = &xcopy_pt_tpg;
+       xcopy_pt_nacl.nacl_sess = &xcopy_pt_sess;
+
+       xcopy_pt_sess.se_tpg = &xcopy_pt_tpg;
+       xcopy_pt_sess.se_node_acl = &xcopy_pt_nacl;
+
+       return 0;
+}
+
+void target_xcopy_release_pt(void)
+{
+       if (xcopy_wq)
+               destroy_workqueue(xcopy_wq);
+}
+
+static void target_xcopy_setup_pt_port(
+       struct xcopy_pt_cmd *xpt_cmd,
+       struct xcopy_op *xop,
+       bool remote_port)
+{
+       struct se_cmd *ec_cmd = xop->xop_se_cmd;
+       struct se_cmd *pt_cmd = &xpt_cmd->se_cmd;
+
+       if (xop->op_origin == XCOL_SOURCE_RECV_OP) {
+               /*
+                * Honor destination port reservations for X-COPY PUSH emulation
+                * when CDB is received on local source port, and READs blocks to
+                * WRITE on remote destination port.
+                */
+               if (remote_port) {
+                       xpt_cmd->remote_port = remote_port;
+                       pt_cmd->se_lun->lun_sep = &xcopy_pt_port;
+                       pr_debug("Setup emulated remote DEST xcopy_pt_port: %p to"
+                               " cmd->se_lun->lun_sep for X-COPY data PUSH\n",
+                               pt_cmd->se_lun->lun_sep);
+               } else {
+                       pt_cmd->se_lun = ec_cmd->se_lun;
+                       pt_cmd->se_dev = ec_cmd->se_dev;
+
+                       pr_debug("Honoring local SRC port from ec_cmd->se_dev:"
+                               " %p\n", pt_cmd->se_dev);
+                       pt_cmd->se_lun = ec_cmd->se_lun;
+                       pr_debug("Honoring local SRC port from ec_cmd->se_lun: %p\n",
+                               pt_cmd->se_lun);
+               }
+       } else {
+               /*
+                * Honor source port reservation for X-COPY PULL emulation
+                * when CDB is received on local desintation port, and READs
+                * blocks from the remote source port to WRITE on local
+                * destination port.
+                */
+               if (remote_port) {
+                       xpt_cmd->remote_port = remote_port;
+                       pt_cmd->se_lun->lun_sep = &xcopy_pt_port;
+                       pr_debug("Setup emulated remote SRC xcopy_pt_port: %p to"
+                               " cmd->se_lun->lun_sep for X-COPY data PULL\n",
+                               pt_cmd->se_lun->lun_sep);
+               } else {
+                       pt_cmd->se_lun = ec_cmd->se_lun;
+                       pt_cmd->se_dev = ec_cmd->se_dev;
+
+                       pr_debug("Honoring local DST port from ec_cmd->se_dev:"
+                               " %p\n", pt_cmd->se_dev);
+                       pt_cmd->se_lun = ec_cmd->se_lun;
+                       pr_debug("Honoring local DST port from ec_cmd->se_lun: %p\n",
+                               pt_cmd->se_lun);
+               }
+       }
+}
+
+static int target_xcopy_init_pt_lun(
+       struct xcopy_pt_cmd *xpt_cmd,
+       struct xcopy_op *xop,
+       struct se_device *se_dev,
+       struct se_cmd *pt_cmd,
+       bool remote_port)
+{
+       /*
+        * Don't allocate + init an pt_cmd->se_lun if honoring local port for
+        * reservations.  The pt_cmd->se_lun pointer will be setup from within
+        * target_xcopy_setup_pt_port()
+        */
+       if (remote_port == false) {
+               pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
+               return 0;
+       }
+
+       pt_cmd->se_lun = kzalloc(sizeof(struct se_lun), GFP_KERNEL);
+       if (!pt_cmd->se_lun) {
+               pr_err("Unable to allocate pt_cmd->se_lun\n");
+               return -ENOMEM;
+       }
+       init_completion(&pt_cmd->se_lun->lun_shutdown_comp);
+       INIT_LIST_HEAD(&pt_cmd->se_lun->lun_cmd_list);
+       INIT_LIST_HEAD(&pt_cmd->se_lun->lun_acl_list);
+       spin_lock_init(&pt_cmd->se_lun->lun_acl_lock);
+       spin_lock_init(&pt_cmd->se_lun->lun_cmd_lock);
+       spin_lock_init(&pt_cmd->se_lun->lun_sep_lock);
+
+       pt_cmd->se_dev = se_dev;
+
+       pr_debug("Setup emulated se_dev: %p from se_dev\n", pt_cmd->se_dev);
+       pt_cmd->se_lun->lun_se_dev = se_dev;
+       pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH;
+
+       pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n",
+               pt_cmd->se_lun->lun_se_dev);
+
+       return 0;
+}
+
+static int target_xcopy_setup_pt_cmd(
+       struct xcopy_pt_cmd *xpt_cmd,
+       struct xcopy_op *xop,
+       struct se_device *se_dev,
+       unsigned char *cdb,
+       bool remote_port,
+       bool alloc_mem)
+{
+       struct se_cmd *cmd = &xpt_cmd->se_cmd;
+       sense_reason_t sense_rc;
+       int ret = 0, rc;
+       /*
+        * Setup LUN+port to honor reservations based upon xop->op_origin for
+        * X-COPY PUSH or X-COPY PULL based upon where the CDB was received.
+        */
+       rc = target_xcopy_init_pt_lun(xpt_cmd, xop, se_dev, cmd, remote_port);
+       if (rc < 0) {
+               ret = rc;
+               goto out;
+       }
+       xpt_cmd->xcopy_op = xop;
+       target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port);
+
+       sense_rc = target_setup_cmd_from_cdb(cmd, cdb);
+       if (sense_rc) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (alloc_mem) {
+               rc = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents,
+                                     cmd->data_length, false);
+               if (rc < 0) {
+                       ret = rc;
+                       goto out;
+               }
+               /*
+                * Set this bit so that transport_free_pages() allows the
+                * caller to release SGLs + physical memory allocated by
+                * transport_generic_get_mem()..
+                */
+               cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+       } else {
+               /*
+                * Here the previously allocated SGLs for the internal READ
+                * are mapped zero-copy to the internal WRITE.
+                */
+               sense_rc = transport_generic_map_mem_to_cmd(cmd,
+                                       xop->xop_data_sg, xop->xop_data_nents,
+                                       NULL, 0);
+               if (sense_rc) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:"
+                        " %u\n", cmd->t_data_sg, cmd->t_data_nents);
+       }
+
+       return 0;
+
+out:
+       if (remote_port == true)
+               kfree(cmd->se_lun);
+       return ret;
+}
+
+static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd)
+{
+       struct se_cmd *se_cmd = &xpt_cmd->se_cmd;
+       sense_reason_t sense_rc;
+
+       sense_rc = transport_generic_new_cmd(se_cmd);
+       if (sense_rc)
+               return -EINVAL;
+
+       if (se_cmd->data_direction == DMA_TO_DEVICE)
+               target_execute_cmd(se_cmd);
+
+       wait_for_completion_interruptible(&xpt_cmd->xpt_passthrough_sem);
+
+       pr_debug("target_xcopy_issue_pt_cmd(): SCSI status: 0x%02x\n",
+                       se_cmd->scsi_status);
+       return 0;
+}
+
+static int target_xcopy_read_source(
+       struct se_cmd *ec_cmd,
+       struct xcopy_op *xop,
+       struct se_device *src_dev,
+       sector_t src_lba,
+       u32 src_sectors)
+{
+       struct xcopy_pt_cmd *xpt_cmd;
+       struct se_cmd *se_cmd;
+       u32 length = (src_sectors * src_dev->dev_attrib.block_size);
+       int rc;
+       unsigned char cdb[16];
+       bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP);
+
+       xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL);
+       if (!xpt_cmd) {
+               pr_err("Unable to allocate xcopy_pt_cmd\n");
+               return -ENOMEM;
+       }
+       init_completion(&xpt_cmd->xpt_passthrough_sem);
+       se_cmd = &xpt_cmd->se_cmd;
+
+       memset(&cdb[0], 0, 16);
+       cdb[0] = READ_16;
+       put_unaligned_be64(src_lba, &cdb[2]);
+       put_unaligned_be32(src_sectors, &cdb[10]);
+       pr_debug("XCOPY: Built READ_16: LBA: %llu Sectors: %u Length: %u\n",
+               (unsigned long long)src_lba, src_sectors, length);
+
+       transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length,
+                               DMA_FROM_DEVICE, 0, NULL);
+       xop->src_pt_cmd = xpt_cmd;
+
+       rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0],
+                               remote_port, true);
+       if (rc < 0) {
+               transport_generic_free_cmd(se_cmd, 0);
+               return rc;
+       }
+
+       xop->xop_data_sg = se_cmd->t_data_sg;
+       xop->xop_data_nents = se_cmd->t_data_nents;
+       pr_debug("XCOPY-READ: Saved xop->xop_data_sg: %p, num: %u for READ"
+               " memory\n", xop->xop_data_sg, xop->xop_data_nents);
+
+       rc = target_xcopy_issue_pt_cmd(xpt_cmd);
+       if (rc < 0) {
+               transport_generic_free_cmd(se_cmd, 0);
+               return rc;
+       }
+       /*
+        * Clear off the allocated t_data_sg, that has been saved for
+        * zero-copy WRITE submission reuse in struct xcopy_op..
+        */
+       se_cmd->t_data_sg = NULL;
+       se_cmd->t_data_nents = 0;
+
+       return 0;
+}
+
+static int target_xcopy_write_destination(
+       struct se_cmd *ec_cmd,
+       struct xcopy_op *xop,
+       struct se_device *dst_dev,
+       sector_t dst_lba,
+       u32 dst_sectors)
+{
+       struct xcopy_pt_cmd *xpt_cmd;
+       struct se_cmd *se_cmd;
+       u32 length = (dst_sectors * dst_dev->dev_attrib.block_size);
+       int rc;
+       unsigned char cdb[16];
+       bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP);
+
+       xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL);
+       if (!xpt_cmd) {
+               pr_err("Unable to allocate xcopy_pt_cmd\n");
+               return -ENOMEM;
+       }
+       init_completion(&xpt_cmd->xpt_passthrough_sem);
+       se_cmd = &xpt_cmd->se_cmd;
+
+       memset(&cdb[0], 0, 16);
+       cdb[0] = WRITE_16;
+       put_unaligned_be64(dst_lba, &cdb[2]);
+       put_unaligned_be32(dst_sectors, &cdb[10]);
+       pr_debug("XCOPY: Built WRITE_16: LBA: %llu Sectors: %u Length: %u\n",
+               (unsigned long long)dst_lba, dst_sectors, length);
+
+       transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length,
+                               DMA_TO_DEVICE, 0, NULL);
+       xop->dst_pt_cmd = xpt_cmd;
+
+       rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, dst_dev, &cdb[0],
+                               remote_port, false);
+       if (rc < 0) {
+               struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd;
+               /*
+                * If the failure happened before the t_mem_list hand-off in
+                * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that
+                * core releases this memory on error during X-COPY WRITE I/O.
+                */
+               src_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+               src_cmd->t_data_sg = xop->xop_data_sg;
+               src_cmd->t_data_nents = xop->xop_data_nents;
+
+               transport_generic_free_cmd(se_cmd, 0);
+               return rc;
+       }
+
+       rc = target_xcopy_issue_pt_cmd(xpt_cmd);
+       if (rc < 0) {
+               se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+               transport_generic_free_cmd(se_cmd, 0);
+               return rc;
+       }
+
+       return 0;
+}
+
+static void target_xcopy_do_work(struct work_struct *work)
+{
+       struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work);
+       struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev;
+       struct se_cmd *ec_cmd = xop->xop_se_cmd;
+       sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba;
+       unsigned int max_sectors;
+       int rc;
+       unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0;
+
+       end_lba = src_lba + nolb;
+       /*
+        * Break up XCOPY I/O into hw_max_sectors sized I/O based on the
+        * smallest max_sectors between src_dev + dev_dev, or
+        */
+       max_sectors = min(src_dev->dev_attrib.hw_max_sectors,
+                         dst_dev->dev_attrib.hw_max_sectors);
+       max_sectors = min_t(u32, max_sectors, XCOPY_MAX_SECTORS);
+
+       max_nolb = min_t(u16, max_sectors, ((u16)(~0U)));
+
+       pr_debug("target_xcopy_do_work: nolb: %hu, max_nolb: %hu end_lba: %llu\n",
+                       nolb, max_nolb, (unsigned long long)end_lba);
+       pr_debug("target_xcopy_do_work: Starting src_lba: %llu, dst_lba: %llu\n",
+                       (unsigned long long)src_lba, (unsigned long long)dst_lba);
+
+       while (src_lba < end_lba) {
+               cur_nolb = min(nolb, max_nolb);
+
+               pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu,"
+                       " cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb);
+
+               rc = target_xcopy_read_source(ec_cmd, xop, src_dev, src_lba, cur_nolb);
+               if (rc < 0)
+                       goto out;
+
+               src_lba += cur_nolb;
+               pr_debug("target_xcopy_do_work: Incremented READ src_lba to %llu\n",
+                               (unsigned long long)src_lba);
+
+               pr_debug("target_xcopy_do_work: Calling write dst_dev: %p dst_lba: %llu,"
+                       " cur_nolb: %hu\n", dst_dev, (unsigned long long)dst_lba, cur_nolb);
+
+               rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev,
+                                               dst_lba, cur_nolb);
+               if (rc < 0) {
+                       transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0);
+                       goto out;
+               }
+
+               dst_lba += cur_nolb;
+               pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n",
+                               (unsigned long long)dst_lba);
+
+               copied_nolb += cur_nolb;
+               nolb -= cur_nolb;
+
+               transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0);
+               xop->dst_pt_cmd->se_cmd.se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC;
+
+               transport_generic_free_cmd(&xop->dst_pt_cmd->se_cmd, 0);
+       }
+
+       xcopy_pt_undepend_remotedev(xop);
+       kfree(xop);
+
+       pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n",
+               (unsigned long long)src_lba, (unsigned long long)dst_lba);
+       pr_debug("target_xcopy_do_work: Blocks copied: %hu, Bytes Copied: %u\n",
+               copied_nolb, copied_nolb * dst_dev->dev_attrib.block_size);
+
+       pr_debug("target_xcopy_do_work: Setting X-COPY GOOD status -> sending response\n");
+       target_complete_cmd(ec_cmd, SAM_STAT_GOOD);
+       return;
+
+out:
+       xcopy_pt_undepend_remotedev(xop);
+       kfree(xop);
+
+       pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n");
+       ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION;
+       target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION);
+}
+
+sense_reason_t target_do_xcopy(struct se_cmd *se_cmd)
+{
+       struct xcopy_op *xop = NULL;
+       unsigned char *p = NULL, *seg_desc;
+       unsigned int list_id, list_id_usage, sdll, inline_dl, sa;
+       int rc;
+       unsigned short tdll;
+
+       sa = se_cmd->t_task_cdb[1] & 0x1f;
+       if (sa != 0x00) {
+               pr_err("EXTENDED_COPY(LID4) not supported\n");
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
+       p = transport_kmap_data_sg(se_cmd);
+       if (!p) {
+               pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n");
+               return TCM_OUT_OF_RESOURCES;
+       }
+
+       list_id = p[0];
+       if (list_id != 0x00) {
+               pr_err("XCOPY with non zero list_id: 0x%02x\n", list_id);
+               goto out;
+       }
+       list_id_usage = (p[1] & 0x18);
+       /*
+        * Determine TARGET DESCRIPTOR LIST LENGTH + SEGMENT DESCRIPTOR LIST LENGTH
+        */
+       tdll = get_unaligned_be16(&p[2]);
+       sdll = get_unaligned_be32(&p[8]);
+
+       inline_dl = get_unaligned_be32(&p[12]);
+       if (inline_dl != 0) {
+               pr_err("XCOPY with non zero inline data length\n");
+               goto out;
+       }
+
+       xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL);
+       if (!xop) {
+               pr_err("Unable to allocate xcopy_op\n");
+               goto out;
+       }
+       xop->xop_se_cmd = se_cmd;
+
+       pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x"
+               " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage,
+               tdll, sdll, inline_dl);
+
+       rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll);
+       if (rc <= 0)
+               goto out;
+
+       pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc,
+                               rc * XCOPY_TARGET_DESC_LEN);
+       seg_desc = &p[16];
+       seg_desc += (rc * XCOPY_TARGET_DESC_LEN);
+
+       rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll);
+       if (rc <= 0) {
+               xcopy_pt_undepend_remotedev(xop);
+               goto out;
+       }
+       transport_kunmap_data_sg(se_cmd);
+
+       pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc,
+                               rc * XCOPY_SEGMENT_DESC_LEN);
+       INIT_WORK(&xop->xop_work, target_xcopy_do_work);
+       queue_work(xcopy_wq, &xop->xop_work);
+       return TCM_NO_SENSE;
+
+out:
+       if (p)
+               transport_kunmap_data_sg(se_cmd);
+       kfree(xop);
+       return TCM_INVALID_CDB_FIELD;
+}
+
+static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd)
+{
+       unsigned char *p;
+
+       p = transport_kmap_data_sg(se_cmd);
+       if (!p) {
+               pr_err("transport_kmap_data_sg failed in"
+                      " target_rcr_operating_parameters\n");
+               return TCM_OUT_OF_RESOURCES;
+       }
+
+       if (se_cmd->data_length < 54) {
+               pr_err("Receive Copy Results Op Parameters length"
+                      " too small: %u\n", se_cmd->data_length);
+               transport_kunmap_data_sg(se_cmd);
+               return TCM_INVALID_CDB_FIELD;
+       }
+       /*
+        * Set SNLID=1 (Supports no List ID)
+        */
+       p[4] = 0x1;
+       /*
+        * MAXIMUM TARGET DESCRIPTOR COUNT
+        */
+       put_unaligned_be16(RCR_OP_MAX_TARGET_DESC_COUNT, &p[8]);
+       /*
+        * MAXIMUM SEGMENT DESCRIPTOR COUNT
+        */
+       put_unaligned_be16(RCR_OP_MAX_SG_DESC_COUNT, &p[10]);
+       /*
+        * MAXIMUM DESCRIPTOR LIST LENGTH
+        */
+       put_unaligned_be32(RCR_OP_MAX_DESC_LIST_LEN, &p[12]);
+       /*
+        * MAXIMUM SEGMENT LENGTH
+        */
+       put_unaligned_be32(RCR_OP_MAX_SEGMENT_LEN, &p[16]);
+       /*
+        * MAXIMUM INLINE DATA LENGTH for SA 0x04 (NOT SUPPORTED)
+        */
+       put_unaligned_be32(0x0, &p[20]);
+       /*
+        * HELD DATA LIMIT
+        */
+       put_unaligned_be32(0x0, &p[24]);
+       /*
+        * MAXIMUM STREAM DEVICE TRANSFER SIZE
+        */
+       put_unaligned_be32(0x0, &p[28]);
+       /*
+        * TOTAL CONCURRENT COPIES
+        */
+       put_unaligned_be16(RCR_OP_TOTAL_CONCURR_COPIES, &p[34]);
+       /*
+        * MAXIMUM CONCURRENT COPIES
+        */
+       p[36] = RCR_OP_MAX_CONCURR_COPIES;
+       /*
+        * DATA SEGMENT GRANULARITY (log 2)
+        */
+       p[37] = RCR_OP_DATA_SEG_GRAN_LOG2;
+       /*
+        * INLINE DATA GRANULARITY log 2)
+        */
+       p[38] = RCR_OP_INLINE_DATA_GRAN_LOG2;
+       /*
+        * HELD DATA GRANULARITY
+        */
+       p[39] = RCR_OP_HELD_DATA_GRAN_LOG2;
+       /*
+        * IMPLEMENTED DESCRIPTOR LIST LENGTH
+        */
+       p[43] = 0x2;
+       /*
+        * List of implemented descriptor type codes (ordered)
+        */
+       p[44] = 0x02; /* Copy Block to Block device */
+       p[45] = 0xe4; /* Identification descriptor target descriptor */
+
+       /*
+        * AVAILABLE DATA (n-3)
+        */
+       put_unaligned_be32(42, &p[0]);
+
+       transport_kunmap_data_sg(se_cmd);
+       target_complete_cmd(se_cmd, GOOD);
+
+       return TCM_NO_SENSE;
+}
+
+sense_reason_t target_do_receive_copy_results(struct se_cmd *se_cmd)
+{
+       unsigned char *cdb = &se_cmd->t_task_cdb[0];
+       int sa = (cdb[1] & 0x1f), list_id = cdb[2];
+       sense_reason_t rc = TCM_NO_SENSE;
+
+       pr_debug("Entering target_do_receive_copy_results: SA: 0x%02x, List ID:"
+               " 0x%02x, AL: %u\n", sa, list_id, se_cmd->data_length);
+
+       if (list_id != 0) {
+               pr_err("Receive Copy Results with non zero list identifier"
+                      " not supported\n");
+               return TCM_INVALID_CDB_FIELD;
+       }
+
+       switch (sa) {
+       case RCR_SA_OPERATING_PARAMETERS:
+               rc = target_rcr_operating_parameters(se_cmd);
+               break;
+       case RCR_SA_COPY_STATUS:
+       case RCR_SA_RECEIVE_DATA:
+       case RCR_SA_FAILED_SEGMENT_DETAILS:
+       default:
+               pr_err("Unsupported SA for receive copy results: 0x%02x\n", sa);
+               return TCM_INVALID_CDB_FIELD;
+       }
+
+       return rc;
+}
diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h
new file mode 100644 (file)
index 0000000..700a981
--- /dev/null
@@ -0,0 +1,62 @@
+#define XCOPY_TARGET_DESC_LEN          32
+#define XCOPY_SEGMENT_DESC_LEN         28
+#define XCOPY_NAA_IEEE_REGEX_LEN       16
+#define XCOPY_MAX_SECTORS              1024
+
+enum xcopy_origin_list {
+       XCOL_SOURCE_RECV_OP = 0x01,
+       XCOL_DEST_RECV_OP = 0x02,
+};
+
+struct xcopy_pt_cmd;
+
+struct xcopy_op {
+       int op_origin;
+
+       struct se_cmd *xop_se_cmd;
+       struct se_device *src_dev;
+       unsigned char src_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+       struct se_device *dst_dev;
+       unsigned char dst_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+       unsigned char local_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN];
+
+       sector_t src_lba;
+       sector_t dst_lba;
+       unsigned short stdi;
+       unsigned short dtdi;
+       unsigned short nolb;
+       unsigned int dbl;
+
+       struct xcopy_pt_cmd *src_pt_cmd;
+       struct xcopy_pt_cmd *dst_pt_cmd;
+
+       u32 xop_data_nents;
+       struct scatterlist *xop_data_sg;
+       struct work_struct xop_work;
+};
+
+/*
+ * Receive Copy Results Sevice Actions
+ */
+#define RCR_SA_COPY_STATUS             0x00
+#define RCR_SA_RECEIVE_DATA            0x01
+#define RCR_SA_OPERATING_PARAMETERS    0x03
+#define RCR_SA_FAILED_SEGMENT_DETAILS  0x04
+
+/*
+ * Receive Copy Results defs for Operating Parameters
+ */
+#define RCR_OP_MAX_TARGET_DESC_COUNT   0x2
+#define RCR_OP_MAX_SG_DESC_COUNT       0x1
+#define RCR_OP_MAX_DESC_LIST_LEN       1024
+#define RCR_OP_MAX_SEGMENT_LEN         268435456 /* 256 MB */
+#define RCR_OP_TOTAL_CONCURR_COPIES    0x1 /* Must be <= 16384 */
+#define RCR_OP_MAX_CONCURR_COPIES      0x1 /* Must be <= 255 */
+#define RCR_OP_DATA_SEG_GRAN_LOG2      9 /* 512 bytes in log 2 */
+#define RCR_OP_INLINE_DATA_GRAN_LOG2   9 /* 512 bytes in log 2 */
+#define RCR_OP_HELD_DATA_GRAN_LOG2     9 /* 512 bytes in log 2 */
+
+extern int target_xcopy_setup_pt(void);
+extern void target_xcopy_release_pt(void);
+extern sense_reason_t target_do_xcopy(struct se_cmd *);
+extern sense_reason_t target_do_receive_copy_results(struct se_cmd *);
index b74feb0d5133bee4a41a0a5c2d32fe5d36d08416..4e0050840a72833ddcc42c108daaf28ed1fc5b19 100644 (file)
@@ -311,7 +311,11 @@ static struct se_portal_group *ft_add_tpg(
         */
        if (strstr(name, "tpgt_") != name)
                return NULL;
-       if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX)
+
+       ret = kstrtoul(name + 5, 10, &index);
+       if (ret)
+               return NULL;
+       if (index > UINT_MAX)
                return NULL;
 
        lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn);
index e988c81d763c7d4e3d96c32a9834bcb54a63ee25..dbfc390330acf2ee8bc6af339ff22f3b6fc3ec77 100644 (file)
@@ -17,8 +17,17 @@ if THERMAL
 
 config THERMAL_HWMON
        bool
+       prompt "Expose thermal sensors as hwmon device"
        depends on HWMON=y || HWMON=THERMAL
        default y
+       help
+         In case a sensor is registered with the thermal
+         framework, this option will also register it
+         as a hwmon. The sensor will then have the common
+         hwmon sysfs interface.
+
+         Say 'Y' here if you want all thermal sensors to
+         have hwmon sysfs interface too.
 
 choice
        prompt "Default Thermal governor"
@@ -91,6 +100,17 @@ config THERMAL_EMULATION
          because userland can easily disable the thermal policy by simply
          flooding this sysfs node with low temperature values.
 
+config IMX_THERMAL
+       tristate "Temperature sensor driver for Freescale i.MX SoCs"
+       depends on CPU_THERMAL
+       depends on MFD_SYSCON
+       depends on OF
+       help
+         Support for Temperature Monitor (TEMPMON) found on Freescale i.MX SoCs.
+         It supports one critical trip point and one passive trip point.  The
+         cpufreq is used as the cooling device to throttle CPUs when the
+         passive trip is crossed.
+
 config SPEAR_THERMAL
        bool "SPEAr thermal sensor driver"
        depends on PLAT_SPEAR
@@ -114,14 +134,6 @@ config KIRKWOOD_THERMAL
          Support for the Kirkwood thermal sensor driver into the Linux thermal
          framework. Only kirkwood 88F6282 and 88F6283 have this sensor.
 
-config EXYNOS_THERMAL
-       tristate "Temperature sensor on Samsung EXYNOS"
-       depends on (ARCH_EXYNOS4 || ARCH_EXYNOS5)
-       depends on CPU_THERMAL
-       help
-         If you say yes here you get support for TMU (Thermal Management
-         Unit) on SAMSUNG EXYNOS series of SoC.
-
 config DOVE_THERMAL
        tristate "Temperature sensor on Marvell Dove SoCs"
        depends on ARCH_DOVE
@@ -184,4 +196,9 @@ menu "Texas Instruments thermal drivers"
 source "drivers/thermal/ti-soc-thermal/Kconfig"
 endmenu
 
+menu "Samsung thermal drivers"
+depends on PLAT_SAMSUNG
+source "drivers/thermal/samsung/Kconfig"
+endmenu
+
 endif
index 67184a293e3f615524225c166ec5b2ee2d00d831..584b36319d51a1234bdebe04b5fd9a7bfd2b34fe 100644 (file)
@@ -5,6 +5,9 @@
 obj-$(CONFIG_THERMAL)          += thermal_sys.o
 thermal_sys-y                  += thermal_core.o
 
+# interface to/from other layers providing sensors
+thermal_sys-$(CONFIG_THERMAL_HWMON)            += thermal_hwmon.o
+
 # governors
 thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)   += fair_share.o
 thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)    += step_wise.o
@@ -17,10 +20,11 @@ thermal_sys-$(CONFIG_CPU_THERMAL)   += cpu_cooling.o
 obj-$(CONFIG_SPEAR_THERMAL)    += spear_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)     += rcar_thermal.o
 obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
-obj-$(CONFIG_EXYNOS_THERMAL)   += exynos_thermal.o
+obj-y                          += samsung/
 obj-$(CONFIG_DOVE_THERMAL)     += dove_thermal.o
 obj-$(CONFIG_DB8500_THERMAL)   += db8500_thermal.o
 obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
+obj-$(CONFIG_IMX_THERMAL)      += imx_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)   += db8500_cpufreq_cooling.o
 obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
 obj-$(CONFIG_X86_PKG_TEMP_THERMAL)     += x86_pkg_temp_thermal.o
index 82e15dbb3ac7a1b3b9063a1577c61f3b1025fb27..d17902886c3f28f31047b27f4ab52be0dceb67ec 100644 (file)
@@ -322,6 +322,8 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb,
 
        if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus))
                max_freq = notify_device->cpufreq_val;
+       else
+               return 0;
 
        /* Never exceed user_policy.max */
        if (max_freq > policy->user_policy.max)
@@ -496,8 +498,12 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
 {
-       struct cpufreq_cooling_device *cpufreq_dev = cdev->devdata;
+       struct cpufreq_cooling_device *cpufreq_dev;
+
+       if (!cdev)
+               return;
 
+       cpufreq_dev = cdev->devdata;
        mutex_lock(&cooling_cpufreq_lock);
        cpufreq_dev_count--;
 
diff --git a/drivers/thermal/exynos_thermal.c b/drivers/thermal/exynos_thermal.c
deleted file mode 100644 (file)
index 9af4b93..0000000
+++ /dev/null
@@ -1,1059 +0,0 @@
-/*
- * exynos_thermal.c - Samsung EXYNOS TMU (Thermal Management Unit)
- *
- *  Copyright (C) 2011 Samsung Electronics
- *  Donggeun Kim <dg77.kim@samsung.com>
- *  Amit Daniel Kachhap <amit.kachhap@linaro.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.
- *
- * This program is distributed in 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/module.h>
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/clk.h>
-#include <linux/workqueue.h>
-#include <linux/sysfs.h>
-#include <linux/kobject.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/platform_data/exynos_thermal.h>
-#include <linux/thermal.h>
-#include <linux/cpufreq.h>
-#include <linux/cpu_cooling.h>
-#include <linux/of.h>
-
-/* Exynos generic registers */
-#define EXYNOS_TMU_REG_TRIMINFO                0x0
-#define EXYNOS_TMU_REG_CONTROL         0x20
-#define EXYNOS_TMU_REG_STATUS          0x28
-#define EXYNOS_TMU_REG_CURRENT_TEMP    0x40
-#define EXYNOS_TMU_REG_INTEN           0x70
-#define EXYNOS_TMU_REG_INTSTAT         0x74
-#define EXYNOS_TMU_REG_INTCLEAR                0x78
-
-#define EXYNOS_TMU_TRIM_TEMP_MASK      0xff
-#define EXYNOS_TMU_GAIN_SHIFT          8
-#define EXYNOS_TMU_REF_VOLTAGE_SHIFT   24
-#define EXYNOS_TMU_CORE_ON             3
-#define EXYNOS_TMU_CORE_OFF            2
-#define EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET     50
-
-/* Exynos4210 specific registers */
-#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP      0x44
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
-#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
-#define EXYNOS4210_TMU_REG_PAST_TEMP0  0x60
-#define EXYNOS4210_TMU_REG_PAST_TEMP1  0x64
-#define EXYNOS4210_TMU_REG_PAST_TEMP2  0x68
-#define EXYNOS4210_TMU_REG_PAST_TEMP3  0x6C
-
-#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK        0x1
-#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK        0x10
-#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK        0x100
-#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK        0x1000
-#define EXYNOS4210_TMU_INTCLEAR_VAL    0x1111
-
-/* Exynos5250 and Exynos4412 specific registers */
-#define EXYNOS_TMU_TRIMINFO_CON        0x14
-#define EXYNOS_THD_TEMP_RISE           0x50
-#define EXYNOS_THD_TEMP_FALL           0x54
-#define EXYNOS_EMUL_CON                0x80
-
-#define EXYNOS_TRIMINFO_RELOAD         0x1
-#define EXYNOS_TMU_CLEAR_RISE_INT      0x111
-#define EXYNOS_TMU_CLEAR_FALL_INT      (0x111 << 12)
-#define EXYNOS_MUX_ADDR_VALUE          6
-#define EXYNOS_MUX_ADDR_SHIFT          20
-#define EXYNOS_TMU_TRIP_MODE_SHIFT     13
-
-#define EFUSE_MIN_VALUE 40
-#define EFUSE_MAX_VALUE 100
-
-/* In-kernel thermal framework related macros & definations */
-#define SENSOR_NAME_LEN        16
-#define MAX_TRIP_COUNT 8
-#define MAX_COOLING_DEVICE 4
-#define MAX_THRESHOLD_LEVS 4
-
-#define ACTIVE_INTERVAL 500
-#define IDLE_INTERVAL 10000
-#define MCELSIUS       1000
-
-#ifdef CONFIG_THERMAL_EMULATION
-#define EXYNOS_EMUL_TIME       0x57F0
-#define EXYNOS_EMUL_TIME_SHIFT 16
-#define EXYNOS_EMUL_DATA_SHIFT 8
-#define EXYNOS_EMUL_DATA_MASK  0xFF
-#define EXYNOS_EMUL_ENABLE     0x1
-#endif /* CONFIG_THERMAL_EMULATION */
-
-/* CPU Zone information */
-#define PANIC_ZONE      4
-#define WARN_ZONE       3
-#define MONITOR_ZONE    2
-#define SAFE_ZONE       1
-
-#define GET_ZONE(trip) (trip + 2)
-#define GET_TRIP(zone) (zone - 2)
-
-#define EXYNOS_ZONE_COUNT      3
-
-struct exynos_tmu_data {
-       struct exynos_tmu_platform_data *pdata;
-       struct resource *mem;
-       void __iomem *base;
-       int irq;
-       enum soc_type soc;
-       struct work_struct irq_work;
-       struct mutex lock;
-       struct clk *clk;
-       u8 temp_error1, temp_error2;
-};
-
-struct thermal_trip_point_conf {
-       int trip_val[MAX_TRIP_COUNT];
-       int trip_count;
-       u8 trigger_falling;
-};
-
-struct thermal_cooling_conf {
-       struct freq_clip_table freq_data[MAX_TRIP_COUNT];
-       int freq_clip_count;
-};
-
-struct thermal_sensor_conf {
-       char name[SENSOR_NAME_LEN];
-       int (*read_temperature)(void *data);
-       int (*write_emul_temp)(void *drv_data, unsigned long temp);
-       struct thermal_trip_point_conf trip_data;
-       struct thermal_cooling_conf cooling_data;
-       void *private_data;
-};
-
-struct exynos_thermal_zone {
-       enum thermal_device_mode mode;
-       struct thermal_zone_device *therm_dev;
-       struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
-       unsigned int cool_dev_size;
-       struct platform_device *exynos4_dev;
-       struct thermal_sensor_conf *sensor_conf;
-       bool bind;
-};
-
-static struct exynos_thermal_zone *th_zone;
-static void exynos_unregister_thermal(void);
-static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
-
-/* Get mode callback functions for thermal zone */
-static int exynos_get_mode(struct thermal_zone_device *thermal,
-                       enum thermal_device_mode *mode)
-{
-       if (th_zone)
-               *mode = th_zone->mode;
-       return 0;
-}
-
-/* Set mode callback functions for thermal zone */
-static int exynos_set_mode(struct thermal_zone_device *thermal,
-                       enum thermal_device_mode mode)
-{
-       if (!th_zone->therm_dev) {
-               pr_notice("thermal zone not registered\n");
-               return 0;
-       }
-
-       mutex_lock(&th_zone->therm_dev->lock);
-
-       if (mode == THERMAL_DEVICE_ENABLED &&
-               !th_zone->sensor_conf->trip_data.trigger_falling)
-               th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
-       else
-               th_zone->therm_dev->polling_delay = 0;
-
-       mutex_unlock(&th_zone->therm_dev->lock);
-
-       th_zone->mode = mode;
-       thermal_zone_device_update(th_zone->therm_dev);
-       pr_info("thermal polling set for duration=%d msec\n",
-                               th_zone->therm_dev->polling_delay);
-       return 0;
-}
-
-
-/* Get trip type callback functions for thermal zone */
-static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
-                                enum thermal_trip_type *type)
-{
-       switch (GET_ZONE(trip)) {
-       case MONITOR_ZONE:
-       case WARN_ZONE:
-               *type = THERMAL_TRIP_ACTIVE;
-               break;
-       case PANIC_ZONE:
-               *type = THERMAL_TRIP_CRITICAL;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* Get trip temperature callback functions for thermal zone */
-static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
-                               unsigned long *temp)
-{
-       if (trip < GET_TRIP(MONITOR_ZONE) || trip > GET_TRIP(PANIC_ZONE))
-               return -EINVAL;
-
-       *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
-       /* convert the temperature into millicelsius */
-       *temp = *temp * MCELSIUS;
-
-       return 0;
-}
-
-/* Get critical temperature callback functions for thermal zone */
-static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
-                               unsigned long *temp)
-{
-       int ret;
-       /* Panic zone */
-       ret = exynos_get_trip_temp(thermal, GET_TRIP(PANIC_ZONE), temp);
-       return ret;
-}
-
-/* Bind callback functions for thermal zone */
-static int exynos_bind(struct thermal_zone_device *thermal,
-                       struct thermal_cooling_device *cdev)
-{
-       int ret = 0, i, tab_size, level;
-       struct freq_clip_table *tab_ptr, *clip_data;
-       struct thermal_sensor_conf *data = th_zone->sensor_conf;
-
-       tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
-       tab_size = data->cooling_data.freq_clip_count;
-
-       if (tab_ptr == NULL || tab_size == 0)
-               return -EINVAL;
-
-       /* find the cooling device registered*/
-       for (i = 0; i < th_zone->cool_dev_size; i++)
-               if (cdev == th_zone->cool_dev[i])
-                       break;
-
-       /* No matching cooling device */
-       if (i == th_zone->cool_dev_size)
-               return 0;
-
-       /* Bind the thermal zone to the cpufreq cooling device */
-       for (i = 0; i < tab_size; i++) {
-               clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
-               level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
-               if (level == THERMAL_CSTATE_INVALID)
-                       return 0;
-               switch (GET_ZONE(i)) {
-               case MONITOR_ZONE:
-               case WARN_ZONE:
-                       if (thermal_zone_bind_cooling_device(thermal, i, cdev,
-                                                               level, 0)) {
-                               pr_err("error binding cdev inst %d\n", i);
-                               ret = -EINVAL;
-                       }
-                       th_zone->bind = true;
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       }
-
-       return ret;
-}
-
-/* Unbind callback functions for thermal zone */
-static int exynos_unbind(struct thermal_zone_device *thermal,
-                       struct thermal_cooling_device *cdev)
-{
-       int ret = 0, i, tab_size;
-       struct thermal_sensor_conf *data = th_zone->sensor_conf;
-
-       if (th_zone->bind == false)
-               return 0;
-
-       tab_size = data->cooling_data.freq_clip_count;
-
-       if (tab_size == 0)
-               return -EINVAL;
-
-       /* find the cooling device registered*/
-       for (i = 0; i < th_zone->cool_dev_size; i++)
-               if (cdev == th_zone->cool_dev[i])
-                       break;
-
-       /* No matching cooling device */
-       if (i == th_zone->cool_dev_size)
-               return 0;
-
-       /* Bind the thermal zone to the cpufreq cooling device */
-       for (i = 0; i < tab_size; i++) {
-               switch (GET_ZONE(i)) {
-               case MONITOR_ZONE:
-               case WARN_ZONE:
-                       if (thermal_zone_unbind_cooling_device(thermal, i,
-                                                               cdev)) {
-                               pr_err("error unbinding cdev inst=%d\n", i);
-                               ret = -EINVAL;
-                       }
-                       th_zone->bind = false;
-                       break;
-               default:
-                       ret = -EINVAL;
-               }
-       }
-       return ret;
-}
-
-/* Get temperature callback functions for thermal zone */
-static int exynos_get_temp(struct thermal_zone_device *thermal,
-                       unsigned long *temp)
-{
-       void *data;
-
-       if (!th_zone->sensor_conf) {
-               pr_info("Temperature sensor not initialised\n");
-               return -EINVAL;
-       }
-       data = th_zone->sensor_conf->private_data;
-       *temp = th_zone->sensor_conf->read_temperature(data);
-       /* convert the temperature into millicelsius */
-       *temp = *temp * MCELSIUS;
-       return 0;
-}
-
-/* Get temperature callback functions for thermal zone */
-static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
-                                               unsigned long temp)
-{
-       void *data;
-       int ret = -EINVAL;
-
-       if (!th_zone->sensor_conf) {
-               pr_info("Temperature sensor not initialised\n");
-               return -EINVAL;
-       }
-       data = th_zone->sensor_conf->private_data;
-       if (th_zone->sensor_conf->write_emul_temp)
-               ret = th_zone->sensor_conf->write_emul_temp(data, temp);
-       return ret;
-}
-
-/* Get the temperature trend */
-static int exynos_get_trend(struct thermal_zone_device *thermal,
-                       int trip, enum thermal_trend *trend)
-{
-       int ret;
-       unsigned long trip_temp;
-
-       ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
-       if (ret < 0)
-               return ret;
-
-       if (thermal->temperature >= trip_temp)
-               *trend = THERMAL_TREND_RAISE_FULL;
-       else
-               *trend = THERMAL_TREND_DROP_FULL;
-
-       return 0;
-}
-/* Operation callback functions for thermal zone */
-static struct thermal_zone_device_ops const exynos_dev_ops = {
-       .bind = exynos_bind,
-       .unbind = exynos_unbind,
-       .get_temp = exynos_get_temp,
-       .set_emul_temp = exynos_set_emul_temp,
-       .get_trend = exynos_get_trend,
-       .get_mode = exynos_get_mode,
-       .set_mode = exynos_set_mode,
-       .get_trip_type = exynos_get_trip_type,
-       .get_trip_temp = exynos_get_trip_temp,
-       .get_crit_temp = exynos_get_crit_temp,
-};
-
-/*
- * This function may be called from interrupt based temperature sensor
- * when threshold is changed.
- */
-static void exynos_report_trigger(void)
-{
-       unsigned int i;
-       char data[10];
-       char *envp[] = { data, NULL };
-
-       if (!th_zone || !th_zone->therm_dev)
-               return;
-       if (th_zone->bind == false) {
-               for (i = 0; i < th_zone->cool_dev_size; i++) {
-                       if (!th_zone->cool_dev[i])
-                               continue;
-                       exynos_bind(th_zone->therm_dev,
-                                       th_zone->cool_dev[i]);
-               }
-       }
-
-       thermal_zone_device_update(th_zone->therm_dev);
-
-       mutex_lock(&th_zone->therm_dev->lock);
-       /* Find the level for which trip happened */
-       for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
-               if (th_zone->therm_dev->last_temperature <
-                       th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
-                       break;
-       }
-
-       if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
-               !th_zone->sensor_conf->trip_data.trigger_falling) {
-               if (i > 0)
-                       th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
-               else
-                       th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
-       }
-
-       snprintf(data, sizeof(data), "%u", i);
-       kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
-       mutex_unlock(&th_zone->therm_dev->lock);
-}
-
-/* Register with the in-kernel thermal management */
-static int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
-{
-       int ret;
-       struct cpumask mask_val;
-
-       if (!sensor_conf || !sensor_conf->read_temperature) {
-               pr_err("Temperature sensor not initialised\n");
-               return -EINVAL;
-       }
-
-       th_zone = kzalloc(sizeof(struct exynos_thermal_zone), GFP_KERNEL);
-       if (!th_zone)
-               return -ENOMEM;
-
-       th_zone->sensor_conf = sensor_conf;
-       cpumask_set_cpu(0, &mask_val);
-       th_zone->cool_dev[0] = cpufreq_cooling_register(&mask_val);
-       if (IS_ERR(th_zone->cool_dev[0])) {
-               pr_err("Failed to register cpufreq cooling device\n");
-               ret = -EINVAL;
-               goto err_unregister;
-       }
-       th_zone->cool_dev_size++;
-
-       th_zone->therm_dev = thermal_zone_device_register(sensor_conf->name,
-                       EXYNOS_ZONE_COUNT, 0, NULL, &exynos_dev_ops, NULL, 0,
-                       sensor_conf->trip_data.trigger_falling ?
-                       0 : IDLE_INTERVAL);
-
-       if (IS_ERR(th_zone->therm_dev)) {
-               pr_err("Failed to register thermal zone device\n");
-               ret = PTR_ERR(th_zone->therm_dev);
-               goto err_unregister;
-       }
-       th_zone->mode = THERMAL_DEVICE_ENABLED;
-
-       pr_info("Exynos: Kernel Thermal management registered\n");
-
-       return 0;
-
-err_unregister:
-       exynos_unregister_thermal();
-       return ret;
-}
-
-/* Un-Register with the in-kernel thermal management */
-static void exynos_unregister_thermal(void)
-{
-       int i;
-
-       if (!th_zone)
-               return;
-
-       if (th_zone->therm_dev)
-               thermal_zone_device_unregister(th_zone->therm_dev);
-
-       for (i = 0; i < th_zone->cool_dev_size; i++) {
-               if (th_zone->cool_dev[i])
-                       cpufreq_cooling_unregister(th_zone->cool_dev[i]);
-       }
-
-       kfree(th_zone);
-       pr_info("Exynos: Kernel Thermal management unregistered\n");
-}
-
-/*
- * TMU treats temperature as a mapped temperature code.
- * The temperature is converted differently depending on the calibration type.
- */
-static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
-{
-       struct exynos_tmu_platform_data *pdata = data->pdata;
-       int temp_code;
-
-       if (data->soc == SOC_ARCH_EXYNOS4210)
-               /* temp should range between 25 and 125 */
-               if (temp < 25 || temp > 125) {
-                       temp_code = -EINVAL;
-                       goto out;
-               }
-
-       switch (pdata->cal_type) {
-       case TYPE_TWO_POINT_TRIMMING:
-               temp_code = (temp - 25) *
-                   (data->temp_error2 - data->temp_error1) /
-                   (85 - 25) + data->temp_error1;
-               break;
-       case TYPE_ONE_POINT_TRIMMING:
-               temp_code = temp + data->temp_error1 - 25;
-               break;
-       default:
-               temp_code = temp + EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
-               break;
-       }
-out:
-       return temp_code;
-}
-
-/*
- * Calculate a temperature value from a temperature code.
- * The unit of the temperature is degree Celsius.
- */
-static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
-{
-       struct exynos_tmu_platform_data *pdata = data->pdata;
-       int temp;
-
-       if (data->soc == SOC_ARCH_EXYNOS4210)
-               /* temp_code should range between 75 and 175 */
-               if (temp_code < 75 || temp_code > 175) {
-                       temp = -ENODATA;
-                       goto out;
-               }
-
-       switch (pdata->cal_type) {
-       case TYPE_TWO_POINT_TRIMMING:
-               temp = (temp_code - data->temp_error1) * (85 - 25) /
-                   (data->temp_error2 - data->temp_error1) + 25;
-               break;
-       case TYPE_ONE_POINT_TRIMMING:
-               temp = temp_code - data->temp_error1 + 25;
-               break;
-       default:
-               temp = temp_code - EXYNOS_TMU_DEF_CODE_TO_TEMP_OFFSET;
-               break;
-       }
-out:
-       return temp;
-}
-
-static int exynos_tmu_initialize(struct platform_device *pdev)
-{
-       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-       struct exynos_tmu_platform_data *pdata = data->pdata;
-       unsigned int status, trim_info;
-       unsigned int rising_threshold = 0, falling_threshold = 0;
-       int ret = 0, threshold_code, i, trigger_levs = 0;
-
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-
-       status = readb(data->base + EXYNOS_TMU_REG_STATUS);
-       if (!status) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       if (data->soc == SOC_ARCH_EXYNOS) {
-               __raw_writel(EXYNOS_TRIMINFO_RELOAD,
-                               data->base + EXYNOS_TMU_TRIMINFO_CON);
-       }
-       /* Save trimming info in order to perform calibration */
-       trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
-       data->temp_error1 = trim_info & EXYNOS_TMU_TRIM_TEMP_MASK;
-       data->temp_error2 = ((trim_info >> 8) & EXYNOS_TMU_TRIM_TEMP_MASK);
-
-       if ((EFUSE_MIN_VALUE > data->temp_error1) ||
-                       (data->temp_error1 > EFUSE_MAX_VALUE) ||
-                       (data->temp_error2 != 0))
-               data->temp_error1 = pdata->efuse_value;
-
-       /* Count trigger levels to be enabled */
-       for (i = 0; i < MAX_THRESHOLD_LEVS; i++)
-               if (pdata->trigger_levels[i])
-                       trigger_levs++;
-
-       if (data->soc == SOC_ARCH_EXYNOS4210) {
-               /* Write temperature code for threshold */
-               threshold_code = temp_to_code(data, pdata->threshold);
-               if (threshold_code < 0) {
-                       ret = threshold_code;
-                       goto out;
-               }
-               writeb(threshold_code,
-                       data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
-               for (i = 0; i < trigger_levs; i++)
-                       writeb(pdata->trigger_levels[i],
-                       data->base + EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
-
-               writel(EXYNOS4210_TMU_INTCLEAR_VAL,
-                       data->base + EXYNOS_TMU_REG_INTCLEAR);
-       } else if (data->soc == SOC_ARCH_EXYNOS) {
-               /* Write temperature code for rising and falling threshold */
-               for (i = 0; i < trigger_levs; i++) {
-                       threshold_code = temp_to_code(data,
-                                               pdata->trigger_levels[i]);
-                       if (threshold_code < 0) {
-                               ret = threshold_code;
-                               goto out;
-                       }
-                       rising_threshold |= threshold_code << 8 * i;
-                       if (pdata->threshold_falling) {
-                               threshold_code = temp_to_code(data,
-                                               pdata->trigger_levels[i] -
-                                               pdata->threshold_falling);
-                               if (threshold_code > 0)
-                                       falling_threshold |=
-                                               threshold_code << 8 * i;
-                       }
-               }
-
-               writel(rising_threshold,
-                               data->base + EXYNOS_THD_TEMP_RISE);
-               writel(falling_threshold,
-                               data->base + EXYNOS_THD_TEMP_FALL);
-
-               writel(EXYNOS_TMU_CLEAR_RISE_INT | EXYNOS_TMU_CLEAR_FALL_INT,
-                               data->base + EXYNOS_TMU_REG_INTCLEAR);
-       }
-out:
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-
-       return ret;
-}
-
-static void exynos_tmu_control(struct platform_device *pdev, bool on)
-{
-       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-       struct exynos_tmu_platform_data *pdata = data->pdata;
-       unsigned int con, interrupt_en;
-
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-
-       con = pdata->reference_voltage << EXYNOS_TMU_REF_VOLTAGE_SHIFT |
-               pdata->gain << EXYNOS_TMU_GAIN_SHIFT;
-
-       if (data->soc == SOC_ARCH_EXYNOS) {
-               con |= pdata->noise_cancel_mode << EXYNOS_TMU_TRIP_MODE_SHIFT;
-               con |= (EXYNOS_MUX_ADDR_VALUE << EXYNOS_MUX_ADDR_SHIFT);
-       }
-
-       if (on) {
-               con |= EXYNOS_TMU_CORE_ON;
-               interrupt_en = pdata->trigger_level3_en << 12 |
-                       pdata->trigger_level2_en << 8 |
-                       pdata->trigger_level1_en << 4 |
-                       pdata->trigger_level0_en;
-               if (pdata->threshold_falling)
-                       interrupt_en |= interrupt_en << 16;
-       } else {
-               con |= EXYNOS_TMU_CORE_OFF;
-               interrupt_en = 0; /* Disable all interrupts */
-       }
-       writel(interrupt_en, data->base + EXYNOS_TMU_REG_INTEN);
-       writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
-
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-}
-
-static int exynos_tmu_read(struct exynos_tmu_data *data)
-{
-       u8 temp_code;
-       int temp;
-
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-
-       temp_code = readb(data->base + EXYNOS_TMU_REG_CURRENT_TEMP);
-       temp = code_to_temp(data, temp_code);
-
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-
-       return temp;
-}
-
-#ifdef CONFIG_THERMAL_EMULATION
-static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
-{
-       struct exynos_tmu_data *data = drv_data;
-       unsigned int reg;
-       int ret = -EINVAL;
-
-       if (data->soc == SOC_ARCH_EXYNOS4210)
-               goto out;
-
-       if (temp && temp < MCELSIUS)
-               goto out;
-
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-
-       reg = readl(data->base + EXYNOS_EMUL_CON);
-
-       if (temp) {
-               temp /= MCELSIUS;
-
-               reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
-                       (temp_to_code(data, temp)
-                        << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
-       } else {
-               reg &= ~EXYNOS_EMUL_ENABLE;
-       }
-
-       writel(reg, data->base + EXYNOS_EMUL_CON);
-
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-       return 0;
-out:
-       return ret;
-}
-#else
-static int exynos_tmu_set_emulation(void *drv_data,    unsigned long temp)
-       { return -EINVAL; }
-#endif/*CONFIG_THERMAL_EMULATION*/
-
-static void exynos_tmu_work(struct work_struct *work)
-{
-       struct exynos_tmu_data *data = container_of(work,
-                       struct exynos_tmu_data, irq_work);
-
-       exynos_report_trigger();
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-       if (data->soc == SOC_ARCH_EXYNOS)
-               writel(EXYNOS_TMU_CLEAR_RISE_INT |
-                               EXYNOS_TMU_CLEAR_FALL_INT,
-                               data->base + EXYNOS_TMU_REG_INTCLEAR);
-       else
-               writel(EXYNOS4210_TMU_INTCLEAR_VAL,
-                               data->base + EXYNOS_TMU_REG_INTCLEAR);
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-
-       enable_irq(data->irq);
-}
-
-static irqreturn_t exynos_tmu_irq(int irq, void *id)
-{
-       struct exynos_tmu_data *data = id;
-
-       disable_irq_nosync(irq);
-       schedule_work(&data->irq_work);
-
-       return IRQ_HANDLED;
-}
-static struct thermal_sensor_conf exynos_sensor_conf = {
-       .name                   = "exynos-therm",
-       .read_temperature       = (int (*)(void *))exynos_tmu_read,
-       .write_emul_temp        = exynos_tmu_set_emulation,
-};
-
-#if defined(CONFIG_CPU_EXYNOS4210)
-static struct exynos_tmu_platform_data const exynos4210_default_tmu_data = {
-       .threshold = 80,
-       .trigger_levels[0] = 5,
-       .trigger_levels[1] = 20,
-       .trigger_levels[2] = 30,
-       .trigger_level0_en = 1,
-       .trigger_level1_en = 1,
-       .trigger_level2_en = 1,
-       .trigger_level3_en = 0,
-       .gain = 15,
-       .reference_voltage = 7,
-       .cal_type = TYPE_ONE_POINT_TRIMMING,
-       .freq_tab[0] = {
-               .freq_clip_max = 800 * 1000,
-               .temp_level = 85,
-       },
-       .freq_tab[1] = {
-               .freq_clip_max = 200 * 1000,
-               .temp_level = 100,
-       },
-       .freq_tab_count = 2,
-       .type = SOC_ARCH_EXYNOS4210,
-};
-#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
-#else
-#define EXYNOS4210_TMU_DRV_DATA (NULL)
-#endif
-
-#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412) || \
-       defined(CONFIG_SOC_EXYNOS4212)
-static struct exynos_tmu_platform_data const exynos_default_tmu_data = {
-       .threshold_falling = 10,
-       .trigger_levels[0] = 85,
-       .trigger_levels[1] = 103,
-       .trigger_levels[2] = 110,
-       .trigger_level0_en = 1,
-       .trigger_level1_en = 1,
-       .trigger_level2_en = 1,
-       .trigger_level3_en = 0,
-       .gain = 8,
-       .reference_voltage = 16,
-       .noise_cancel_mode = 4,
-       .cal_type = TYPE_ONE_POINT_TRIMMING,
-       .efuse_value = 55,
-       .freq_tab[0] = {
-               .freq_clip_max = 800 * 1000,
-               .temp_level = 85,
-       },
-       .freq_tab[1] = {
-               .freq_clip_max = 200 * 1000,
-               .temp_level = 103,
-       },
-       .freq_tab_count = 2,
-       .type = SOC_ARCH_EXYNOS,
-};
-#define EXYNOS_TMU_DRV_DATA (&exynos_default_tmu_data)
-#else
-#define EXYNOS_TMU_DRV_DATA (NULL)
-#endif
-
-#ifdef CONFIG_OF
-static const struct of_device_id exynos_tmu_match[] = {
-       {
-               .compatible = "samsung,exynos4210-tmu",
-               .data = (void *)EXYNOS4210_TMU_DRV_DATA,
-       },
-       {
-               .compatible = "samsung,exynos4412-tmu",
-               .data = (void *)EXYNOS_TMU_DRV_DATA,
-       },
-       {
-               .compatible = "samsung,exynos5250-tmu",
-               .data = (void *)EXYNOS_TMU_DRV_DATA,
-       },
-       {},
-};
-MODULE_DEVICE_TABLE(of, exynos_tmu_match);
-#endif
-
-static struct platform_device_id exynos_tmu_driver_ids[] = {
-       {
-               .name           = "exynos4210-tmu",
-               .driver_data    = (kernel_ulong_t)EXYNOS4210_TMU_DRV_DATA,
-       },
-       {
-               .name           = "exynos5250-tmu",
-               .driver_data    = (kernel_ulong_t)EXYNOS_TMU_DRV_DATA,
-       },
-       { },
-};
-MODULE_DEVICE_TABLE(platform, exynos_tmu_driver_ids);
-
-static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
-                       struct platform_device *pdev)
-{
-#ifdef CONFIG_OF
-       if (pdev->dev.of_node) {
-               const struct of_device_id *match;
-               match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
-               if (!match)
-                       return NULL;
-               return (struct exynos_tmu_platform_data *) match->data;
-       }
-#endif
-       return (struct exynos_tmu_platform_data *)
-                       platform_get_device_id(pdev)->driver_data;
-}
-
-static int exynos_tmu_probe(struct platform_device *pdev)
-{
-       struct exynos_tmu_data *data;
-       struct exynos_tmu_platform_data *pdata = pdev->dev.platform_data;
-       int ret, i;
-
-       if (!pdata)
-               pdata = exynos_get_driver_data(pdev);
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "No platform init data supplied.\n");
-               return -ENODEV;
-       }
-       data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
-                                       GFP_KERNEL);
-       if (!data) {
-               dev_err(&pdev->dev, "Failed to allocate driver structure\n");
-               return -ENOMEM;
-       }
-
-       data->irq = platform_get_irq(pdev, 0);
-       if (data->irq < 0) {
-               dev_err(&pdev->dev, "Failed to get platform irq\n");
-               return data->irq;
-       }
-
-       INIT_WORK(&data->irq_work, exynos_tmu_work);
-
-       data->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data->base = devm_ioremap_resource(&pdev->dev, data->mem);
-       if (IS_ERR(data->base))
-               return PTR_ERR(data->base);
-
-       ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
-               IRQF_TRIGGER_RISING, "exynos-tmu", data);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
-               return ret;
-       }
-
-       data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
-       if (IS_ERR(data->clk)) {
-               dev_err(&pdev->dev, "Failed to get clock\n");
-               return  PTR_ERR(data->clk);
-       }
-
-       ret = clk_prepare(data->clk);
-       if (ret)
-               return ret;
-
-       if (pdata->type == SOC_ARCH_EXYNOS ||
-                               pdata->type == SOC_ARCH_EXYNOS4210)
-               data->soc = pdata->type;
-       else {
-               ret = -EINVAL;
-               dev_err(&pdev->dev, "Platform not supported\n");
-               goto err_clk;
-       }
-
-       data->pdata = pdata;
-       platform_set_drvdata(pdev, data);
-       mutex_init(&data->lock);
-
-       ret = exynos_tmu_initialize(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to initialize TMU\n");
-               goto err_clk;
-       }
-
-       exynos_tmu_control(pdev, true);
-
-       /* Register the sensor with thermal management interface */
-       (&exynos_sensor_conf)->private_data = data;
-       exynos_sensor_conf.trip_data.trip_count = pdata->trigger_level0_en +
-                       pdata->trigger_level1_en + pdata->trigger_level2_en +
-                       pdata->trigger_level3_en;
-
-       for (i = 0; i < exynos_sensor_conf.trip_data.trip_count; i++)
-               exynos_sensor_conf.trip_data.trip_val[i] =
-                       pdata->threshold + pdata->trigger_levels[i];
-
-       exynos_sensor_conf.trip_data.trigger_falling = pdata->threshold_falling;
-
-       exynos_sensor_conf.cooling_data.freq_clip_count =
-                                               pdata->freq_tab_count;
-       for (i = 0; i < pdata->freq_tab_count; i++) {
-               exynos_sensor_conf.cooling_data.freq_data[i].freq_clip_max =
-                                       pdata->freq_tab[i].freq_clip_max;
-               exynos_sensor_conf.cooling_data.freq_data[i].temp_level =
-                                       pdata->freq_tab[i].temp_level;
-       }
-
-       ret = exynos_register_thermal(&exynos_sensor_conf);
-       if (ret) {
-               dev_err(&pdev->dev, "Failed to register thermal interface\n");
-               goto err_clk;
-       }
-
-       return 0;
-err_clk:
-       clk_unprepare(data->clk);
-       return ret;
-}
-
-static int exynos_tmu_remove(struct platform_device *pdev)
-{
-       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-
-       exynos_tmu_control(pdev, false);
-
-       exynos_unregister_thermal();
-
-       clk_unprepare(data->clk);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos_tmu_suspend(struct device *dev)
-{
-       exynos_tmu_control(to_platform_device(dev), false);
-
-       return 0;
-}
-
-static int exynos_tmu_resume(struct device *dev)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-
-       exynos_tmu_initialize(pdev);
-       exynos_tmu_control(pdev, true);
-
-       return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
-                        exynos_tmu_suspend, exynos_tmu_resume);
-#define EXYNOS_TMU_PM  (&exynos_tmu_pm)
-#else
-#define EXYNOS_TMU_PM  NULL
-#endif
-
-static struct platform_driver exynos_tmu_driver = {
-       .driver = {
-               .name   = "exynos-tmu",
-               .owner  = THIS_MODULE,
-               .pm     = EXYNOS_TMU_PM,
-               .of_match_table = of_match_ptr(exynos_tmu_match),
-       },
-       .probe = exynos_tmu_probe,
-       .remove = exynos_tmu_remove,
-       .id_table = exynos_tmu_driver_ids,
-};
-
-module_platform_driver(exynos_tmu_driver);
-
-MODULE_DESCRIPTION("EXYNOS TMU Driver");
-MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:exynos-tmu");
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
new file mode 100644 (file)
index 0000000..1d6c801
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright 2013 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/cpu_cooling.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+#include <linux/types.h>
+
+#define REG_SET                0x4
+#define REG_CLR                0x8
+#define REG_TOG                0xc
+
+#define MISC0                          0x0150
+#define MISC0_REFTOP_SELBIASOFF                (1 << 3)
+
+#define TEMPSENSE0                     0x0180
+#define TEMPSENSE0_ALARM_VALUE_SHIFT   20
+#define TEMPSENSE0_ALARM_VALUE_MASK    (0xfff << TEMPSENSE0_ALARM_VALUE_SHIFT)
+#define TEMPSENSE0_TEMP_CNT_SHIFT      8
+#define TEMPSENSE0_TEMP_CNT_MASK       (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
+#define TEMPSENSE0_FINISHED            (1 << 2)
+#define TEMPSENSE0_MEASURE_TEMP                (1 << 1)
+#define TEMPSENSE0_POWER_DOWN          (1 << 0)
+
+#define TEMPSENSE1                     0x0190
+#define TEMPSENSE1_MEASURE_FREQ                0xffff
+
+#define OCOTP_ANA1                     0x04e0
+
+/* The driver supports 1 passive trip point and 1 critical trip point */
+enum imx_thermal_trip {
+       IMX_TRIP_PASSIVE,
+       IMX_TRIP_CRITICAL,
+       IMX_TRIP_NUM,
+};
+
+/*
+ * It defines the temperature in millicelsius for passive trip point
+ * that will trigger cooling action when crossed.
+ */
+#define IMX_TEMP_PASSIVE               85000
+
+#define IMX_POLLING_DELAY              2000 /* millisecond */
+#define IMX_PASSIVE_DELAY              1000
+
+struct imx_thermal_data {
+       struct thermal_zone_device *tz;
+       struct thermal_cooling_device *cdev;
+       enum thermal_device_mode mode;
+       struct regmap *tempmon;
+       int c1, c2; /* See formula in imx_get_sensor_data() */
+       unsigned long temp_passive;
+       unsigned long temp_critical;
+       unsigned long alarm_temp;
+       unsigned long last_temp;
+       bool irq_enabled;
+       int irq;
+};
+
+static void imx_set_alarm_temp(struct imx_thermal_data *data,
+                              signed long alarm_temp)
+{
+       struct regmap *map = data->tempmon;
+       int alarm_value;
+
+       data->alarm_temp = alarm_temp;
+       alarm_value = (alarm_temp - data->c2) / data->c1;
+       regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
+       regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value <<
+                       TEMPSENSE0_ALARM_VALUE_SHIFT);
+}
+
+static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
+{
+       struct imx_thermal_data *data = tz->devdata;
+       struct regmap *map = data->tempmon;
+       unsigned int n_meas;
+       bool wait;
+       u32 val;
+
+       if (data->mode == THERMAL_DEVICE_ENABLED) {
+               /* Check if a measurement is currently in progress */
+               regmap_read(map, TEMPSENSE0, &val);
+               wait = !(val & TEMPSENSE0_FINISHED);
+       } else {
+               /*
+                * Every time we measure the temperature, we will power on the
+                * temperature sensor, enable measurements, take a reading,
+                * disable measurements, power off the temperature sensor.
+                */
+               regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
+               regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+
+               wait = true;
+       }
+
+       /*
+        * According to the temp sensor designers, it may require up to ~17us
+        * to complete a measurement.
+        */
+       if (wait)
+               usleep_range(20, 50);
+
+       regmap_read(map, TEMPSENSE0, &val);
+
+       if (data->mode != THERMAL_DEVICE_ENABLED) {
+               regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
+               regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+       }
+
+       if ((val & TEMPSENSE0_FINISHED) == 0) {
+               dev_dbg(&tz->device, "temp measurement never finished\n");
+               return -EAGAIN;
+       }
+
+       n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
+
+       /* See imx_get_sensor_data() for formula derivation */
+       *temp = data->c2 + data->c1 * n_meas;
+
+       /* Update alarm value to next higher trip point */
+       if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive)
+               imx_set_alarm_temp(data, data->temp_critical);
+       if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) {
+               imx_set_alarm_temp(data, data->temp_passive);
+               dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
+                       data->alarm_temp / 1000);
+       }
+
+       if (*temp != data->last_temp) {
+               dev_dbg(&tz->device, "millicelsius: %ld\n", *temp);
+               data->last_temp = *temp;
+       }
+
+       /* Reenable alarm IRQ if temperature below alarm temperature */
+       if (!data->irq_enabled && *temp < data->alarm_temp) {
+               data->irq_enabled = true;
+               enable_irq(data->irq);
+       }
+
+       return 0;
+}
+
+static int imx_get_mode(struct thermal_zone_device *tz,
+                       enum thermal_device_mode *mode)
+{
+       struct imx_thermal_data *data = tz->devdata;
+
+       *mode = data->mode;
+
+       return 0;
+}
+
+static int imx_set_mode(struct thermal_zone_device *tz,
+                       enum thermal_device_mode mode)
+{
+       struct imx_thermal_data *data = tz->devdata;
+       struct regmap *map = data->tempmon;
+
+       if (mode == THERMAL_DEVICE_ENABLED) {
+               tz->polling_delay = IMX_POLLING_DELAY;
+               tz->passive_delay = IMX_PASSIVE_DELAY;
+
+               regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
+               regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+
+               if (!data->irq_enabled) {
+                       data->irq_enabled = true;
+                       enable_irq(data->irq);
+               }
+       } else {
+               regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
+               regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+
+               tz->polling_delay = 0;
+               tz->passive_delay = 0;
+
+               if (data->irq_enabled) {
+                       disable_irq(data->irq);
+                       data->irq_enabled = false;
+               }
+       }
+
+       data->mode = mode;
+       thermal_zone_device_update(tz);
+
+       return 0;
+}
+
+static int imx_get_trip_type(struct thermal_zone_device *tz, int trip,
+                            enum thermal_trip_type *type)
+{
+       *type = (trip == IMX_TRIP_PASSIVE) ? THERMAL_TRIP_PASSIVE :
+                                            THERMAL_TRIP_CRITICAL;
+       return 0;
+}
+
+static int imx_get_crit_temp(struct thermal_zone_device *tz,
+                            unsigned long *temp)
+{
+       struct imx_thermal_data *data = tz->devdata;
+
+       *temp = data->temp_critical;
+       return 0;
+}
+
+static int imx_get_trip_temp(struct thermal_zone_device *tz, int trip,
+                            unsigned long *temp)
+{
+       struct imx_thermal_data *data = tz->devdata;
+
+       *temp = (trip == IMX_TRIP_PASSIVE) ? data->temp_passive :
+                                            data->temp_critical;
+       return 0;
+}
+
+static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
+                            unsigned long temp)
+{
+       struct imx_thermal_data *data = tz->devdata;
+
+       if (trip == IMX_TRIP_CRITICAL)
+               return -EPERM;
+
+       if (temp > IMX_TEMP_PASSIVE)
+               return -EINVAL;
+
+       data->temp_passive = temp;
+
+       imx_set_alarm_temp(data, temp);
+
+       return 0;
+}
+
+static int imx_bind(struct thermal_zone_device *tz,
+                   struct thermal_cooling_device *cdev)
+{
+       int ret;
+
+       ret = thermal_zone_bind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev,
+                                              THERMAL_NO_LIMIT,
+                                              THERMAL_NO_LIMIT);
+       if (ret) {
+               dev_err(&tz->device,
+                       "binding zone %s with cdev %s failed:%d\n",
+                       tz->type, cdev->type, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int imx_unbind(struct thermal_zone_device *tz,
+                     struct thermal_cooling_device *cdev)
+{
+       int ret;
+
+       ret = thermal_zone_unbind_cooling_device(tz, IMX_TRIP_PASSIVE, cdev);
+       if (ret) {
+               dev_err(&tz->device,
+                       "unbinding zone %s with cdev %s failed:%d\n",
+                       tz->type, cdev->type, ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct thermal_zone_device_ops imx_tz_ops = {
+       .bind = imx_bind,
+       .unbind = imx_unbind,
+       .get_temp = imx_get_temp,
+       .get_mode = imx_get_mode,
+       .set_mode = imx_set_mode,
+       .get_trip_type = imx_get_trip_type,
+       .get_trip_temp = imx_get_trip_temp,
+       .get_crit_temp = imx_get_crit_temp,
+       .set_trip_temp = imx_set_trip_temp,
+};
+
+static int imx_get_sensor_data(struct platform_device *pdev)
+{
+       struct imx_thermal_data *data = platform_get_drvdata(pdev);
+       struct regmap *map;
+       int t1, t2, n1, n2;
+       int ret;
+       u32 val;
+
+       map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                             "fsl,tempmon-data");
+       if (IS_ERR(map)) {
+               ret = PTR_ERR(map);
+               dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
+               return ret;
+       }
+
+       ret = regmap_read(map, OCOTP_ANA1, &val);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
+               return ret;
+       }
+
+       if (val == 0 || val == ~0) {
+               dev_err(&pdev->dev, "invalid sensor calibration data\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Sensor data layout:
+        *   [31:20] - sensor value @ 25C
+        *    [19:8] - sensor value of hot
+        *     [7:0] - hot temperature value
+        */
+       n1 = val >> 20;
+       n2 = (val & 0xfff00) >> 8;
+       t2 = val & 0xff;
+       t1 = 25; /* t1 always 25C */
+
+       /*
+        * Derived from linear interpolation,
+        * Tmeas = T2 + (Nmeas - N2) * (T1 - T2) / (N1 - N2)
+        * We want to reduce this down to the minimum computation necessary
+        * for each temperature read.  Also, we want Tmeas in millicelsius
+        * and we don't want to lose precision from integer division. So...
+        * milli_Tmeas = 1000 * T2 + 1000 * (Nmeas - N2) * (T1 - T2) / (N1 - N2)
+        * Let constant c1 = 1000 * (T1 - T2) / (N1 - N2)
+        * milli_Tmeas = (1000 * T2) + c1 * (Nmeas - N2)
+        * milli_Tmeas = (1000 * T2) + (c1 * Nmeas) - (c1 * N2)
+        * Let constant c2 = (1000 * T2) - (c1 * N2)
+        * milli_Tmeas = c2 + (c1 * Nmeas)
+        */
+       data->c1 = 1000 * (t1 - t2) / (n1 - n2);
+       data->c2 = 1000 * t2 - data->c1 * n2;
+
+       /*
+        * Set the default passive cooling trip point to 20 Â°C below the
+        * maximum die temperature. Can be changed from userspace.
+        */
+       data->temp_passive = 1000 * (t2 - 20);
+
+       /*
+        * The maximum die temperature is t2, let's give 5 Â°C cushion
+        * for noise and possible temperature rise between measurements.
+        */
+       data->temp_critical = 1000 * (t2 - 5);
+
+       return 0;
+}
+
+static irqreturn_t imx_thermal_alarm_irq(int irq, void *dev)
+{
+       struct imx_thermal_data *data = dev;
+
+       disable_irq_nosync(irq);
+       data->irq_enabled = false;
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
+{
+       struct imx_thermal_data *data = dev;
+
+       dev_dbg(&data->tz->device, "THERMAL ALARM: T > %lu\n",
+               data->alarm_temp / 1000);
+
+       thermal_zone_device_update(data->tz);
+
+       return IRQ_HANDLED;
+}
+
+static int imx_thermal_probe(struct platform_device *pdev)
+{
+       struct imx_thermal_data *data;
+       struct cpumask clip_cpus;
+       struct regmap *map;
+       int measure_freq;
+       int ret;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "fsl,tempmon");
+       if (IS_ERR(map)) {
+               ret = PTR_ERR(map);
+               dev_err(&pdev->dev, "failed to get tempmon regmap: %d\n", ret);
+               return ret;
+       }
+       data->tempmon = map;
+
+       data->irq = platform_get_irq(pdev, 0);
+       if (data->irq < 0)
+               return data->irq;
+
+       ret = devm_request_threaded_irq(&pdev->dev, data->irq,
+                       imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
+                       0, "imx_thermal", data);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, data);
+
+       ret = imx_get_sensor_data(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get sensor data\n");
+               return ret;
+       }
+
+       /* Make sure sensor is in known good state for measurements */
+       regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
+       regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
+       regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
+       regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF);
+       regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+
+       cpumask_set_cpu(0, &clip_cpus);
+       data->cdev = cpufreq_cooling_register(&clip_cpus);
+       if (IS_ERR(data->cdev)) {
+               ret = PTR_ERR(data->cdev);
+               dev_err(&pdev->dev,
+                       "failed to register cpufreq cooling device: %d\n", ret);
+               return ret;
+       }
+
+       data->tz = thermal_zone_device_register("imx_thermal_zone",
+                                               IMX_TRIP_NUM,
+                                               BIT(IMX_TRIP_PASSIVE), data,
+                                               &imx_tz_ops, NULL,
+                                               IMX_PASSIVE_DELAY,
+                                               IMX_POLLING_DELAY);
+       if (IS_ERR(data->tz)) {
+               ret = PTR_ERR(data->tz);
+               dev_err(&pdev->dev,
+                       "failed to register thermal zone device %d\n", ret);
+               cpufreq_cooling_unregister(data->cdev);
+               return ret;
+       }
+
+       /* Enable measurements at ~ 10 Hz */
+       regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
+       measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
+       regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
+       imx_set_alarm_temp(data, data->temp_passive);
+       regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
+       regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+
+       data->irq_enabled = true;
+       data->mode = THERMAL_DEVICE_ENABLED;
+
+       return 0;
+}
+
+static int imx_thermal_remove(struct platform_device *pdev)
+{
+       struct imx_thermal_data *data = platform_get_drvdata(pdev);
+       struct regmap *map = data->tempmon;
+
+       /* Disable measurements */
+       regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
+
+       thermal_zone_device_unregister(data->tz);
+       cpufreq_cooling_unregister(data->cdev);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int imx_thermal_suspend(struct device *dev)
+{
+       struct imx_thermal_data *data = dev_get_drvdata(dev);
+       struct regmap *map = data->tempmon;
+       u32 val;
+
+       regmap_read(map, TEMPSENSE0, &val);
+       if ((val & TEMPSENSE0_POWER_DOWN) == 0) {
+               /*
+                * If a measurement is taking place, wait for a long enough
+                * time for it to finish, and then check again.  If it still
+                * does not finish, something must go wrong.
+                */
+               udelay(50);
+               regmap_read(map, TEMPSENSE0, &val);
+               if ((val & TEMPSENSE0_POWER_DOWN) == 0)
+                       return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+static int imx_thermal_resume(struct device *dev)
+{
+       /* Nothing to do for now */
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
+                        imx_thermal_suspend, imx_thermal_resume);
+
+static const struct of_device_id of_imx_thermal_match[] = {
+       { .compatible = "fsl,imx6q-tempmon", },
+       { /* end */ }
+};
+
+static struct platform_driver imx_thermal = {
+       .driver = {
+               .name   = "imx_thermal",
+               .owner  = THIS_MODULE,
+               .pm     = &imx_thermal_pm_ops,
+               .of_match_table = of_imx_thermal_match,
+       },
+       .probe          = imx_thermal_probe,
+       .remove         = imx_thermal_remove,
+};
+module_platform_driver(imx_thermal);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("Thermal driver for Freescale i.MX SoCs");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:imx-thermal");
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
new file mode 100644 (file)
index 0000000..f760389
--- /dev/null
@@ -0,0 +1,18 @@
+config EXYNOS_THERMAL
+       tristate "Exynos thermal management unit driver"
+       depends on ARCH_HAS_BANDGAP && OF
+       help
+         If you say yes here you get support for the TMU (Thermal Management
+         Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises
+         the TMU, reports temperature and handles cooling action if defined.
+         This driver uses the Exynos core thermal APIs and TMU configuration
+         data from the supported SoCs.
+
+config EXYNOS_THERMAL_CORE
+       bool "Core thermal framework support for EXYNOS SOCs"
+       depends on EXYNOS_THERMAL
+       help
+         If you say yes here you get support for EXYNOS TMU
+         (Thermal Management Unit) common registration/unregistration
+         functions to the core thermal layer and also to use the generic
+         CPU cooling APIs.
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
new file mode 100644 (file)
index 0000000..c09d830
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Samsung thermal specific Makefile
+#
+obj-$(CONFIG_EXYNOS_THERMAL)                   += exynos_thermal.o
+exynos_thermal-y                               := exynos_tmu.o
+exynos_thermal-y                               += exynos_tmu_data.o
+exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE)   += exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
new file mode 100644 (file)
index 0000000..f10a6ad
--- /dev/null
@@ -0,0 +1,432 @@
+/*
+ * exynos_thermal_common.c - Samsung EXYNOS common thermal file
+ *
+ *  Copyright (C) 2013 Samsung Electronics
+ *  Amit Daniel Kachhap <amit.daniel@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/cpu_cooling.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/thermal.h>
+
+#include "exynos_thermal_common.h"
+
+struct exynos_thermal_zone {
+       enum thermal_device_mode mode;
+       struct thermal_zone_device *therm_dev;
+       struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
+       unsigned int cool_dev_size;
+       struct platform_device *exynos4_dev;
+       struct thermal_sensor_conf *sensor_conf;
+       bool bind;
+};
+
+/* Get mode callback functions for thermal zone */
+static int exynos_get_mode(struct thermal_zone_device *thermal,
+                       enum thermal_device_mode *mode)
+{
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       if (th_zone)
+               *mode = th_zone->mode;
+       return 0;
+}
+
+/* Set mode callback functions for thermal zone */
+static int exynos_set_mode(struct thermal_zone_device *thermal,
+                       enum thermal_device_mode mode)
+{
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       if (!th_zone) {
+               dev_err(&thermal->device,
+                       "thermal zone not registered\n");
+               return 0;
+       }
+
+       mutex_lock(&thermal->lock);
+
+       if (mode == THERMAL_DEVICE_ENABLED &&
+               !th_zone->sensor_conf->trip_data.trigger_falling)
+               thermal->polling_delay = IDLE_INTERVAL;
+       else
+               thermal->polling_delay = 0;
+
+       mutex_unlock(&thermal->lock);
+
+       th_zone->mode = mode;
+       thermal_zone_device_update(thermal);
+       dev_dbg(th_zone->sensor_conf->dev,
+               "thermal polling set for duration=%d msec\n",
+               thermal->polling_delay);
+       return 0;
+}
+
+
+/* Get trip type callback functions for thermal zone */
+static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
+                                enum thermal_trip_type *type)
+{
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+       int trip_type;
+
+       if (trip < 0 || trip >= max_trip)
+               return -EINVAL;
+
+       trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
+
+       if (trip_type == SW_TRIP)
+               *type = THERMAL_TRIP_CRITICAL;
+       else if (trip_type == THROTTLE_ACTIVE)
+               *type = THERMAL_TRIP_ACTIVE;
+       else if (trip_type == THROTTLE_PASSIVE)
+               *type = THERMAL_TRIP_PASSIVE;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+/* Get trip temperature callback functions for thermal zone */
+static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
+                               unsigned long *temp)
+{
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+
+       if (trip < 0 || trip >= max_trip)
+               return -EINVAL;
+
+       *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
+       /* convert the temperature into millicelsius */
+       *temp = *temp * MCELSIUS;
+
+       return 0;
+}
+
+/* Get critical temperature callback functions for thermal zone */
+static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
+                               unsigned long *temp)
+{
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       int max_trip = th_zone->sensor_conf->trip_data.trip_count;
+       /* Get the temp of highest trip*/
+       return exynos_get_trip_temp(thermal, max_trip - 1, temp);
+}
+
+/* Bind callback functions for thermal zone */
+static int exynos_bind(struct thermal_zone_device *thermal,
+                       struct thermal_cooling_device *cdev)
+{
+       int ret = 0, i, tab_size, level;
+       struct freq_clip_table *tab_ptr, *clip_data;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       struct thermal_sensor_conf *data = th_zone->sensor_conf;
+
+       tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
+       tab_size = data->cooling_data.freq_clip_count;
+
+       if (tab_ptr == NULL || tab_size == 0)
+               return 0;
+
+       /* find the cooling device registered*/
+       for (i = 0; i < th_zone->cool_dev_size; i++)
+               if (cdev == th_zone->cool_dev[i])
+                       break;
+
+       /* No matching cooling device */
+       if (i == th_zone->cool_dev_size)
+               return 0;
+
+       /* Bind the thermal zone to the cpufreq cooling device */
+       for (i = 0; i < tab_size; i++) {
+               clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
+               level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
+               if (level == THERMAL_CSTATE_INVALID)
+                       return 0;
+               switch (GET_ZONE(i)) {
+               case MONITOR_ZONE:
+               case WARN_ZONE:
+                       if (thermal_zone_bind_cooling_device(thermal, i, cdev,
+                                                               level, 0)) {
+                               dev_err(data->dev,
+                                       "error unbinding cdev inst=%d\n", i);
+                               ret = -EINVAL;
+                       }
+                       th_zone->bind = true;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       }
+
+       return ret;
+}
+
+/* Unbind callback functions for thermal zone */
+static int exynos_unbind(struct thermal_zone_device *thermal,
+                       struct thermal_cooling_device *cdev)
+{
+       int ret = 0, i, tab_size;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       struct thermal_sensor_conf *data = th_zone->sensor_conf;
+
+       if (th_zone->bind == false)
+               return 0;
+
+       tab_size = data->cooling_data.freq_clip_count;
+
+       if (tab_size == 0)
+               return 0;
+
+       /* find the cooling device registered*/
+       for (i = 0; i < th_zone->cool_dev_size; i++)
+               if (cdev == th_zone->cool_dev[i])
+                       break;
+
+       /* No matching cooling device */
+       if (i == th_zone->cool_dev_size)
+               return 0;
+
+       /* Bind the thermal zone to the cpufreq cooling device */
+       for (i = 0; i < tab_size; i++) {
+               switch (GET_ZONE(i)) {
+               case MONITOR_ZONE:
+               case WARN_ZONE:
+                       if (thermal_zone_unbind_cooling_device(thermal, i,
+                                                               cdev)) {
+                               dev_err(data->dev,
+                                       "error unbinding cdev inst=%d\n", i);
+                               ret = -EINVAL;
+                       }
+                       th_zone->bind = false;
+                       break;
+               default:
+                       ret = -EINVAL;
+               }
+       }
+       return ret;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos_get_temp(struct thermal_zone_device *thermal,
+                       unsigned long *temp)
+{
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+       void *data;
+
+       if (!th_zone->sensor_conf) {
+               dev_err(&thermal->device,
+                       "Temperature sensor not initialised\n");
+               return -EINVAL;
+       }
+       data = th_zone->sensor_conf->driver_data;
+       *temp = th_zone->sensor_conf->read_temperature(data);
+       /* convert the temperature into millicelsius */
+       *temp = *temp * MCELSIUS;
+       return 0;
+}
+
+/* Get temperature callback functions for thermal zone */
+static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
+                                               unsigned long temp)
+{
+       void *data;
+       int ret = -EINVAL;
+       struct exynos_thermal_zone *th_zone = thermal->devdata;
+
+       if (!th_zone->sensor_conf) {
+               dev_err(&thermal->device,
+                       "Temperature sensor not initialised\n");
+               return -EINVAL;
+       }
+       data = th_zone->sensor_conf->driver_data;
+       if (th_zone->sensor_conf->write_emul_temp)
+               ret = th_zone->sensor_conf->write_emul_temp(data, temp);
+       return ret;
+}
+
+/* Get the temperature trend */
+static int exynos_get_trend(struct thermal_zone_device *thermal,
+                       int trip, enum thermal_trend *trend)
+{
+       int ret;
+       unsigned long trip_temp;
+
+       ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
+       if (ret < 0)
+               return ret;
+
+       if (thermal->temperature >= trip_temp)
+               *trend = THERMAL_TREND_RAISE_FULL;
+       else
+               *trend = THERMAL_TREND_DROP_FULL;
+
+       return 0;
+}
+/* Operation callback functions for thermal zone */
+static struct thermal_zone_device_ops const exynos_dev_ops = {
+       .bind = exynos_bind,
+       .unbind = exynos_unbind,
+       .get_temp = exynos_get_temp,
+       .set_emul_temp = exynos_set_emul_temp,
+       .get_trend = exynos_get_trend,
+       .get_mode = exynos_get_mode,
+       .set_mode = exynos_set_mode,
+       .get_trip_type = exynos_get_trip_type,
+       .get_trip_temp = exynos_get_trip_temp,
+       .get_crit_temp = exynos_get_crit_temp,
+};
+
+/*
+ * This function may be called from interrupt based temperature sensor
+ * when threshold is changed.
+ */
+void exynos_report_trigger(struct thermal_sensor_conf *conf)
+{
+       unsigned int i;
+       char data[10];
+       char *envp[] = { data, NULL };
+       struct exynos_thermal_zone *th_zone;
+
+       if (!conf || !conf->pzone_data) {
+               pr_err("Invalid temperature sensor configuration data\n");
+               return;
+       }
+
+       th_zone = conf->pzone_data;
+       if (th_zone->therm_dev)
+               return;
+
+       if (th_zone->bind == false) {
+               for (i = 0; i < th_zone->cool_dev_size; i++) {
+                       if (!th_zone->cool_dev[i])
+                               continue;
+                       exynos_bind(th_zone->therm_dev,
+                                       th_zone->cool_dev[i]);
+               }
+       }
+
+       thermal_zone_device_update(th_zone->therm_dev);
+
+       mutex_lock(&th_zone->therm_dev->lock);
+       /* Find the level for which trip happened */
+       for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
+               if (th_zone->therm_dev->last_temperature <
+                       th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
+                       break;
+       }
+
+       if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
+               !th_zone->sensor_conf->trip_data.trigger_falling) {
+               if (i > 0)
+                       th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
+               else
+                       th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
+       }
+
+       snprintf(data, sizeof(data), "%u", i);
+       kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
+       mutex_unlock(&th_zone->therm_dev->lock);
+}
+
+/* Register with the in-kernel thermal management */
+int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+       int ret;
+       struct cpumask mask_val;
+       struct exynos_thermal_zone *th_zone;
+
+       if (!sensor_conf || !sensor_conf->read_temperature) {
+               pr_err("Temperature sensor not initialised\n");
+               return -EINVAL;
+       }
+
+       th_zone = devm_kzalloc(sensor_conf->dev,
+                               sizeof(struct exynos_thermal_zone), GFP_KERNEL);
+       if (!th_zone)
+               return -ENOMEM;
+
+       th_zone->sensor_conf = sensor_conf;
+       /*
+        * TODO: 1) Handle multiple cooling devices in a thermal zone
+        *       2) Add a flag/name in cooling info to map to specific
+        *       sensor
+        */
+       if (sensor_conf->cooling_data.freq_clip_count > 0) {
+               cpumask_set_cpu(0, &mask_val);
+               th_zone->cool_dev[th_zone->cool_dev_size] =
+                                       cpufreq_cooling_register(&mask_val);
+               if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) {
+                       dev_err(sensor_conf->dev,
+                               "Failed to register cpufreq cooling device\n");
+                       ret = -EINVAL;
+                       goto err_unregister;
+               }
+               th_zone->cool_dev_size++;
+       }
+
+       th_zone->therm_dev = thermal_zone_device_register(
+                       sensor_conf->name, sensor_conf->trip_data.trip_count,
+                       0, th_zone, &exynos_dev_ops, NULL, 0,
+                       sensor_conf->trip_data.trigger_falling ? 0 :
+                       IDLE_INTERVAL);
+
+       if (IS_ERR(th_zone->therm_dev)) {
+               dev_err(sensor_conf->dev,
+                       "Failed to register thermal zone device\n");
+               ret = PTR_ERR(th_zone->therm_dev);
+               goto err_unregister;
+       }
+       th_zone->mode = THERMAL_DEVICE_ENABLED;
+       sensor_conf->pzone_data = th_zone;
+
+       dev_info(sensor_conf->dev,
+               "Exynos: Thermal zone(%s) registered\n", sensor_conf->name);
+
+       return 0;
+
+err_unregister:
+       exynos_unregister_thermal(sensor_conf);
+       return ret;
+}
+
+/* Un-Register with the in-kernel thermal management */
+void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
+{
+       int i;
+       struct exynos_thermal_zone *th_zone;
+
+       if (!sensor_conf || !sensor_conf->pzone_data) {
+               pr_err("Invalid temperature sensor configuration data\n");
+               return;
+       }
+
+       th_zone = sensor_conf->pzone_data;
+
+       if (th_zone->therm_dev)
+               thermal_zone_device_unregister(th_zone->therm_dev);
+
+       for (i = 0; i < th_zone->cool_dev_size; i++) {
+               if (th_zone->cool_dev[i])
+                       cpufreq_cooling_unregister(th_zone->cool_dev[i]);
+       }
+
+       dev_info(sensor_conf->dev,
+               "Exynos: Kernel Thermal management unregistered\n");
+}
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
new file mode 100644 (file)
index 0000000..3eb2ed9
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * exynos_thermal_common.h - Samsung EXYNOS common header file
+ *
+ *  Copyright (C) 2013 Samsung Electronics
+ *  Amit Daniel Kachhap <amit.daniel@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _EXYNOS_THERMAL_COMMON_H
+#define _EXYNOS_THERMAL_COMMON_H
+
+/* In-kernel thermal framework related macros & definations */
+#define SENSOR_NAME_LEN        16
+#define MAX_TRIP_COUNT 8
+#define MAX_COOLING_DEVICE 4
+#define MAX_THRESHOLD_LEVS 5
+
+#define ACTIVE_INTERVAL 500
+#define IDLE_INTERVAL 10000
+#define MCELSIUS       1000
+
+/* CPU Zone information */
+#define PANIC_ZONE      4
+#define WARN_ZONE       3
+#define MONITOR_ZONE    2
+#define SAFE_ZONE       1
+
+#define GET_ZONE(trip) (trip + 2)
+#define GET_TRIP(zone) (zone - 2)
+
+enum trigger_type {
+       THROTTLE_ACTIVE = 1,
+       THROTTLE_PASSIVE,
+       SW_TRIP,
+       HW_TRIP,
+};
+
+/**
+ * struct freq_clip_table
+ * @freq_clip_max: maximum frequency allowed for this cooling state.
+ * @temp_level: Temperature level at which the temperature clipping will
+ *     happen.
+ * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
+ *
+ * This structure is required to be filled and passed to the
+ * cpufreq_cooling_unregister function.
+ */
+struct freq_clip_table {
+       unsigned int freq_clip_max;
+       unsigned int temp_level;
+       const struct cpumask *mask_val;
+};
+
+struct thermal_trip_point_conf {
+       int trip_val[MAX_TRIP_COUNT];
+       int trip_type[MAX_TRIP_COUNT];
+       int trip_count;
+       unsigned char trigger_falling;
+};
+
+struct thermal_cooling_conf {
+       struct freq_clip_table freq_data[MAX_TRIP_COUNT];
+       int freq_clip_count;
+};
+
+struct thermal_sensor_conf {
+       char name[SENSOR_NAME_LEN];
+       int (*read_temperature)(void *data);
+       int (*write_emul_temp)(void *drv_data, unsigned long temp);
+       struct thermal_trip_point_conf trip_data;
+       struct thermal_cooling_conf cooling_data;
+       void *driver_data;
+       void *pzone_data;
+       struct device *dev;
+};
+
+/*Functions used exynos based thermal sensor driver*/
+#ifdef CONFIG_EXYNOS_THERMAL_CORE
+void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf);
+int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
+void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf);
+#else
+static inline void
+exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) { return; }
+
+static inline int
+exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
+
+static inline void
+exynos_report_trigger(struct thermal_sensor_conf *sensor_conf) { return; }
+
+#endif /* CONFIG_EXYNOS_THERMAL_CORE */
+#endif /* _EXYNOS_THERMAL_COMMON_H */
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
new file mode 100644 (file)
index 0000000..b43afda
--- /dev/null
@@ -0,0 +1,762 @@
+/*
+ * exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *  Donggeun Kim <dg77.kim@samsung.com>
+ *  Amit Daniel Kachhap <amit.kachhap@linaro.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.
+ *
+ * This program is distributed in 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/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include "exynos_thermal_common.h"
+#include "exynos_tmu.h"
+#include "exynos_tmu_data.h"
+
+/**
+ * struct exynos_tmu_data : A structure to hold the private data of the TMU
+       driver
+ * @id: identifier of the one instance of the TMU controller.
+ * @pdata: pointer to the tmu platform/configuration data
+ * @base: base address of the single instance of the TMU controller.
+ * @base_common: base address of the common registers of the TMU controller.
+ * @irq: irq number of the TMU controller.
+ * @soc: id of the SOC type.
+ * @irq_work: pointer to the irq work structure.
+ * @lock: lock to implement synchronization.
+ * @clk: pointer to the clock structure.
+ * @temp_error1: fused value of the first point trim.
+ * @temp_error2: fused value of the second point trim.
+ * @regulator: pointer to the TMU regulator structure.
+ * @reg_conf: pointer to structure to register with core thermal.
+ */
+struct exynos_tmu_data {
+       int id;
+       struct exynos_tmu_platform_data *pdata;
+       void __iomem *base;
+       void __iomem *base_common;
+       int irq;
+       enum soc_type soc;
+       struct work_struct irq_work;
+       struct mutex lock;
+       struct clk *clk;
+       u8 temp_error1, temp_error2;
+       struct regulator *regulator;
+       struct thermal_sensor_conf *reg_conf;
+};
+
+/*
+ * TMU treats temperature as a mapped temperature code.
+ * The temperature is converted differently depending on the calibration type.
+ */
+static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
+{
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       int temp_code;
+
+       if (pdata->cal_mode == HW_MODE)
+               return temp;
+
+       if (data->soc == SOC_ARCH_EXYNOS4210)
+               /* temp should range between 25 and 125 */
+               if (temp < 25 || temp > 125) {
+                       temp_code = -EINVAL;
+                       goto out;
+               }
+
+       switch (pdata->cal_type) {
+       case TYPE_TWO_POINT_TRIMMING:
+               temp_code = (temp - pdata->first_point_trim) *
+                       (data->temp_error2 - data->temp_error1) /
+                       (pdata->second_point_trim - pdata->first_point_trim) +
+                       data->temp_error1;
+               break;
+       case TYPE_ONE_POINT_TRIMMING:
+               temp_code = temp + data->temp_error1 - pdata->first_point_trim;
+               break;
+       default:
+               temp_code = temp + pdata->default_temp_offset;
+               break;
+       }
+out:
+       return temp_code;
+}
+
+/*
+ * Calculate a temperature value from a temperature code.
+ * The unit of the temperature is degree Celsius.
+ */
+static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
+{
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       int temp;
+
+       if (pdata->cal_mode == HW_MODE)
+               return temp_code;
+
+       if (data->soc == SOC_ARCH_EXYNOS4210)
+               /* temp_code should range between 75 and 175 */
+               if (temp_code < 75 || temp_code > 175) {
+                       temp = -ENODATA;
+                       goto out;
+               }
+
+       switch (pdata->cal_type) {
+       case TYPE_TWO_POINT_TRIMMING:
+               temp = (temp_code - data->temp_error1) *
+                       (pdata->second_point_trim - pdata->first_point_trim) /
+                       (data->temp_error2 - data->temp_error1) +
+                       pdata->first_point_trim;
+               break;
+       case TYPE_ONE_POINT_TRIMMING:
+               temp = temp_code - data->temp_error1 + pdata->first_point_trim;
+               break;
+       default:
+               temp = temp_code - pdata->default_temp_offset;
+               break;
+       }
+out:
+       return temp;
+}
+
+static int exynos_tmu_initialize(struct platform_device *pdev)
+{
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       const struct exynos_tmu_registers *reg = pdata->registers;
+       unsigned int status, trim_info = 0, con;
+       unsigned int rising_threshold = 0, falling_threshold = 0;
+       int ret = 0, threshold_code, i, trigger_levs = 0;
+
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+
+       if (TMU_SUPPORTS(pdata, READY_STATUS)) {
+               status = readb(data->base + reg->tmu_status);
+               if (!status) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+       }
+
+       if (TMU_SUPPORTS(pdata, TRIM_RELOAD))
+               __raw_writel(1, data->base + reg->triminfo_ctrl);
+
+       if (pdata->cal_mode == HW_MODE)
+               goto skip_calib_data;
+
+       /* Save trimming info in order to perform calibration */
+       if (data->soc == SOC_ARCH_EXYNOS5440) {
+               /*
+                * For exynos5440 soc triminfo value is swapped between TMU0 and
+                * TMU2, so the below logic is needed.
+                */
+               switch (data->id) {
+               case 0:
+                       trim_info = readl(data->base +
+                       EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
+                       break;
+               case 1:
+                       trim_info = readl(data->base + reg->triminfo_data);
+                       break;
+               case 2:
+                       trim_info = readl(data->base -
+                       EXYNOS5440_EFUSE_SWAP_OFFSET + reg->triminfo_data);
+               }
+       } else {
+               trim_info = readl(data->base + reg->triminfo_data);
+       }
+       data->temp_error1 = trim_info & EXYNOS_TMU_TEMP_MASK;
+       data->temp_error2 = ((trim_info >> reg->triminfo_85_shift) &
+                               EXYNOS_TMU_TEMP_MASK);
+
+       if (!data->temp_error1 ||
+               (pdata->min_efuse_value > data->temp_error1) ||
+               (data->temp_error1 > pdata->max_efuse_value))
+               data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
+
+       if (!data->temp_error2)
+               data->temp_error2 =
+                       (pdata->efuse_value >> reg->triminfo_85_shift) &
+                       EXYNOS_TMU_TEMP_MASK;
+
+skip_calib_data:
+       if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
+               dev_err(&pdev->dev, "Invalid max trigger level\n");
+               goto out;
+       }
+
+       for (i = 0; i < pdata->max_trigger_level; i++) {
+               if (!pdata->trigger_levels[i])
+                       continue;
+
+               if ((pdata->trigger_type[i] == HW_TRIP) &&
+               (!pdata->trigger_levels[pdata->max_trigger_level - 1])) {
+                       dev_err(&pdev->dev, "Invalid hw trigger level\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               /* Count trigger levels except the HW trip*/
+               if (!(pdata->trigger_type[i] == HW_TRIP))
+                       trigger_levs++;
+       }
+
+       if (data->soc == SOC_ARCH_EXYNOS4210) {
+               /* Write temperature code for threshold */
+               threshold_code = temp_to_code(data, pdata->threshold);
+               if (threshold_code < 0) {
+                       ret = threshold_code;
+                       goto out;
+               }
+               writeb(threshold_code,
+                       data->base + reg->threshold_temp);
+               for (i = 0; i < trigger_levs; i++)
+                       writeb(pdata->trigger_levels[i], data->base +
+                       reg->threshold_th0 + i * sizeof(reg->threshold_th0));
+
+               writel(reg->inten_rise_mask, data->base + reg->tmu_intclear);
+       } else {
+               /* Write temperature code for rising and falling threshold */
+               for (i = 0;
+               i < trigger_levs && i < EXYNOS_MAX_TRIGGER_PER_REG; i++) {
+                       threshold_code = temp_to_code(data,
+                                               pdata->trigger_levels[i]);
+                       if (threshold_code < 0) {
+                               ret = threshold_code;
+                               goto out;
+                       }
+                       rising_threshold |= threshold_code << 8 * i;
+                       if (pdata->threshold_falling) {
+                               threshold_code = temp_to_code(data,
+                                               pdata->trigger_levels[i] -
+                                               pdata->threshold_falling);
+                               if (threshold_code > 0)
+                                       falling_threshold |=
+                                               threshold_code << 8 * i;
+                       }
+               }
+
+               writel(rising_threshold,
+                               data->base + reg->threshold_th0);
+               writel(falling_threshold,
+                               data->base + reg->threshold_th1);
+
+               writel((reg->inten_rise_mask << reg->inten_rise_shift) |
+                       (reg->inten_fall_mask << reg->inten_fall_shift),
+                               data->base + reg->tmu_intclear);
+
+               /* if last threshold limit is also present */
+               i = pdata->max_trigger_level - 1;
+               if (pdata->trigger_levels[i] &&
+                               (pdata->trigger_type[i] == HW_TRIP)) {
+                       threshold_code = temp_to_code(data,
+                                               pdata->trigger_levels[i]);
+                       if (threshold_code < 0) {
+                               ret = threshold_code;
+                               goto out;
+                       }
+                       if (i == EXYNOS_MAX_TRIGGER_PER_REG - 1) {
+                               /* 1-4 level to be assigned in th0 reg */
+                               rising_threshold |= threshold_code << 8 * i;
+                               writel(rising_threshold,
+                                       data->base + reg->threshold_th0);
+                       } else if (i == EXYNOS_MAX_TRIGGER_PER_REG) {
+                               /* 5th level to be assigned in th2 reg */
+                               rising_threshold =
+                               threshold_code << reg->threshold_th3_l0_shift;
+                               writel(rising_threshold,
+                                       data->base + reg->threshold_th2);
+                       }
+                       con = readl(data->base + reg->tmu_ctrl);
+                       con |= (1 << reg->therm_trip_en_shift);
+                       writel(con, data->base + reg->tmu_ctrl);
+               }
+       }
+       /*Clear the PMIN in the common TMU register*/
+       if (reg->tmu_pmin && !data->id)
+               writel(0, data->base_common + reg->tmu_pmin);
+out:
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+
+       return ret;
+}
+
+static void exynos_tmu_control(struct platform_device *pdev, bool on)
+{
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       const struct exynos_tmu_registers *reg = pdata->registers;
+       unsigned int con, interrupt_en, cal_val;
+
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+
+       con = readl(data->base + reg->tmu_ctrl);
+
+       if (pdata->reference_voltage) {
+               con &= ~(reg->buf_vref_sel_mask << reg->buf_vref_sel_shift);
+               con |= pdata->reference_voltage << reg->buf_vref_sel_shift;
+       }
+
+       if (pdata->gain) {
+               con &= ~(reg->buf_slope_sel_mask << reg->buf_slope_sel_shift);
+               con |= (pdata->gain << reg->buf_slope_sel_shift);
+       }
+
+       if (pdata->noise_cancel_mode) {
+               con &= ~(reg->therm_trip_mode_mask <<
+                                       reg->therm_trip_mode_shift);
+               con |= (pdata->noise_cancel_mode << reg->therm_trip_mode_shift);
+       }
+
+       if (pdata->cal_mode == HW_MODE) {
+               con &= ~(reg->calib_mode_mask << reg->calib_mode_shift);
+               cal_val = 0;
+               switch (pdata->cal_type) {
+               case TYPE_TWO_POINT_TRIMMING:
+                       cal_val = 3;
+                       break;
+               case TYPE_ONE_POINT_TRIMMING_85:
+                       cal_val = 2;
+                       break;
+               case TYPE_ONE_POINT_TRIMMING_25:
+                       cal_val = 1;
+                       break;
+               case TYPE_NONE:
+                       break;
+               default:
+                       dev_err(&pdev->dev, "Invalid calibration type, using none\n");
+               }
+               con |= cal_val << reg->calib_mode_shift;
+       }
+
+       if (on) {
+               con |= (1 << reg->core_en_shift);
+               interrupt_en =
+                       pdata->trigger_enable[3] << reg->inten_rise3_shift |
+                       pdata->trigger_enable[2] << reg->inten_rise2_shift |
+                       pdata->trigger_enable[1] << reg->inten_rise1_shift |
+                       pdata->trigger_enable[0] << reg->inten_rise0_shift;
+               if (TMU_SUPPORTS(pdata, FALLING_TRIP))
+                       interrupt_en |=
+                               interrupt_en << reg->inten_fall0_shift;
+       } else {
+               con &= ~(1 << reg->core_en_shift);
+               interrupt_en = 0; /* Disable all interrupts */
+       }
+       writel(interrupt_en, data->base + reg->tmu_inten);
+       writel(con, data->base + reg->tmu_ctrl);
+
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+}
+
+static int exynos_tmu_read(struct exynos_tmu_data *data)
+{
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       const struct exynos_tmu_registers *reg = pdata->registers;
+       u8 temp_code;
+       int temp;
+
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+
+       temp_code = readb(data->base + reg->tmu_cur_temp);
+       temp = code_to_temp(data, temp_code);
+
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+
+       return temp;
+}
+
+#ifdef CONFIG_THERMAL_EMULATION
+static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
+{
+       struct exynos_tmu_data *data = drv_data;
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       const struct exynos_tmu_registers *reg = pdata->registers;
+       unsigned int val;
+       int ret = -EINVAL;
+
+       if (!TMU_SUPPORTS(pdata, EMULATION))
+               goto out;
+
+       if (temp && temp < MCELSIUS)
+               goto out;
+
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+
+       val = readl(data->base + reg->emul_con);
+
+       if (temp) {
+               temp /= MCELSIUS;
+
+               if (TMU_SUPPORTS(pdata, EMUL_TIME)) {
+                       val &= ~(EXYNOS_EMUL_TIME_MASK << reg->emul_time_shift);
+                       val |= (EXYNOS_EMUL_TIME << reg->emul_time_shift);
+               }
+               val &= ~(EXYNOS_EMUL_DATA_MASK << reg->emul_temp_shift);
+               val |= (temp_to_code(data, temp) << reg->emul_temp_shift) |
+                       EXYNOS_EMUL_ENABLE;
+       } else {
+               val &= ~EXYNOS_EMUL_ENABLE;
+       }
+
+       writel(val, data->base + reg->emul_con);
+
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+       return 0;
+out:
+       return ret;
+}
+#else
+static int exynos_tmu_set_emulation(void *drv_data,    unsigned long temp)
+       { return -EINVAL; }
+#endif/*CONFIG_THERMAL_EMULATION*/
+
+static void exynos_tmu_work(struct work_struct *work)
+{
+       struct exynos_tmu_data *data = container_of(work,
+                       struct exynos_tmu_data, irq_work);
+       struct exynos_tmu_platform_data *pdata = data->pdata;
+       const struct exynos_tmu_registers *reg = pdata->registers;
+       unsigned int val_irq, val_type;
+
+       /* Find which sensor generated this interrupt */
+       if (reg->tmu_irqstatus) {
+               val_type = readl(data->base_common + reg->tmu_irqstatus);
+               if (!((val_type >> data->id) & 0x1))
+                       goto out;
+       }
+
+       exynos_report_trigger(data->reg_conf);
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+
+       /* TODO: take action based on particular interrupt */
+       val_irq = readl(data->base + reg->tmu_intstat);
+       /* clear the interrupts */
+       writel(val_irq, data->base + reg->tmu_intclear);
+
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+out:
+       enable_irq(data->irq);
+}
+
+static irqreturn_t exynos_tmu_irq(int irq, void *id)
+{
+       struct exynos_tmu_data *data = id;
+
+       disable_irq_nosync(irq);
+       schedule_work(&data->irq_work);
+
+       return IRQ_HANDLED;
+}
+
+static const struct of_device_id exynos_tmu_match[] = {
+       {
+               .compatible = "samsung,exynos4210-tmu",
+               .data = (void *)EXYNOS4210_TMU_DRV_DATA,
+       },
+       {
+               .compatible = "samsung,exynos4412-tmu",
+               .data = (void *)EXYNOS5250_TMU_DRV_DATA,
+       },
+       {
+               .compatible = "samsung,exynos5250-tmu",
+               .data = (void *)EXYNOS5250_TMU_DRV_DATA,
+       },
+       {
+               .compatible = "samsung,exynos5440-tmu",
+               .data = (void *)EXYNOS5440_TMU_DRV_DATA,
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, exynos_tmu_match);
+
+static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
+                       struct platform_device *pdev, int id)
+{
+       struct  exynos_tmu_init_data *data_table;
+       struct exynos_tmu_platform_data *tmu_data;
+       const struct of_device_id *match;
+
+       match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
+       if (!match)
+               return NULL;
+       data_table = (struct exynos_tmu_init_data *) match->data;
+       if (!data_table || id >= data_table->tmu_count)
+               return NULL;
+       tmu_data = data_table->tmu_data;
+       return (struct exynos_tmu_platform_data *) (tmu_data + id);
+}
+
+static int exynos_map_dt_data(struct platform_device *pdev)
+{
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+       struct exynos_tmu_platform_data *pdata;
+       struct resource res;
+       int ret;
+
+       if (!data || !pdev->dev.of_node)
+               return -ENODEV;
+
+       /*
+        * Try enabling the regulator if found
+        * TODO: Add regulator as an SOC feature, so that regulator enable
+        * is a compulsory call.
+        */
+       data->regulator = devm_regulator_get(&pdev->dev, "vtmu");
+       if (!IS_ERR(data->regulator)) {
+               ret = regulator_enable(data->regulator);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to enable vtmu\n");
+                       return ret;
+               }
+       } else {
+               dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
+       }
+
+       data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
+       if (data->id < 0)
+               data->id = 0;
+
+       data->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+       if (data->irq <= 0) {
+               dev_err(&pdev->dev, "failed to get IRQ\n");
+               return -ENODEV;
+       }
+
+       if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
+               dev_err(&pdev->dev, "failed to get Resource 0\n");
+               return -ENODEV;
+       }
+
+       data->base = devm_ioremap(&pdev->dev, res.start, resource_size(&res));
+       if (!data->base) {
+               dev_err(&pdev->dev, "Failed to ioremap memory\n");
+               return -EADDRNOTAVAIL;
+       }
+
+       pdata = exynos_get_driver_data(pdev, data->id);
+       if (!pdata) {
+               dev_err(&pdev->dev, "No platform init data supplied.\n");
+               return -ENODEV;
+       }
+       data->pdata = pdata;
+       /*
+        * Check if the TMU shares some registers and then try to map the
+        * memory of common registers.
+        */
+       if (!TMU_SUPPORTS(pdata, SHARED_MEMORY))
+               return 0;
+
+       if (of_address_to_resource(pdev->dev.of_node, 1, &res)) {
+               dev_err(&pdev->dev, "failed to get Resource 1\n");
+               return -ENODEV;
+       }
+
+       data->base_common = devm_ioremap(&pdev->dev, res.start,
+                                       resource_size(&res));
+       if (!data->base_common) {
+               dev_err(&pdev->dev, "Failed to ioremap memory\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int exynos_tmu_probe(struct platform_device *pdev)
+{
+       struct exynos_tmu_data *data;
+       struct exynos_tmu_platform_data *pdata;
+       struct thermal_sensor_conf *sensor_conf;
+       int ret, i;
+
+       data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
+                                       GFP_KERNEL);
+       if (!data) {
+               dev_err(&pdev->dev, "Failed to allocate driver structure\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, data);
+       mutex_init(&data->lock);
+
+       ret = exynos_map_dt_data(pdev);
+       if (ret)
+               return ret;
+
+       pdata = data->pdata;
+
+       INIT_WORK(&data->irq_work, exynos_tmu_work);
+
+       data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
+       if (IS_ERR(data->clk)) {
+               dev_err(&pdev->dev, "Failed to get clock\n");
+               return  PTR_ERR(data->clk);
+       }
+
+       ret = clk_prepare(data->clk);
+       if (ret)
+               return ret;
+
+       if (pdata->type == SOC_ARCH_EXYNOS ||
+               pdata->type == SOC_ARCH_EXYNOS4210 ||
+                               pdata->type == SOC_ARCH_EXYNOS5440)
+               data->soc = pdata->type;
+       else {
+               ret = -EINVAL;
+               dev_err(&pdev->dev, "Platform not supported\n");
+               goto err_clk;
+       }
+
+       ret = exynos_tmu_initialize(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialize TMU\n");
+               goto err_clk;
+       }
+
+       exynos_tmu_control(pdev, true);
+
+       /* Allocate a structure to register with the exynos core thermal */
+       sensor_conf = devm_kzalloc(&pdev->dev,
+                               sizeof(struct thermal_sensor_conf), GFP_KERNEL);
+       if (!sensor_conf) {
+               dev_err(&pdev->dev, "Failed to allocate registration struct\n");
+               ret = -ENOMEM;
+               goto err_clk;
+       }
+       sprintf(sensor_conf->name, "therm_zone%d", data->id);
+       sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
+       sensor_conf->write_emul_temp =
+               (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
+       sensor_conf->driver_data = data;
+       sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
+                       pdata->trigger_enable[1] + pdata->trigger_enable[2]+
+                       pdata->trigger_enable[3];
+
+       for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
+               sensor_conf->trip_data.trip_val[i] =
+                       pdata->threshold + pdata->trigger_levels[i];
+               sensor_conf->trip_data.trip_type[i] =
+                                       pdata->trigger_type[i];
+       }
+
+       sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
+
+       sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
+       for (i = 0; i < pdata->freq_tab_count; i++) {
+               sensor_conf->cooling_data.freq_data[i].freq_clip_max =
+                                       pdata->freq_tab[i].freq_clip_max;
+               sensor_conf->cooling_data.freq_data[i].temp_level =
+                                       pdata->freq_tab[i].temp_level;
+       }
+       sensor_conf->dev = &pdev->dev;
+       /* Register the sensor with thermal management interface */
+       ret = exynos_register_thermal(sensor_conf);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to register thermal interface\n");
+               goto err_clk;
+       }
+       data->reg_conf = sensor_conf;
+
+       ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
+               IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
+               goto err_clk;
+       }
+
+       return 0;
+err_clk:
+       clk_unprepare(data->clk);
+       return ret;
+}
+
+static int exynos_tmu_remove(struct platform_device *pdev)
+{
+       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+
+       exynos_tmu_control(pdev, false);
+
+       exynos_unregister_thermal(data->reg_conf);
+
+       clk_unprepare(data->clk);
+
+       if (!IS_ERR(data->regulator))
+               regulator_disable(data->regulator);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_tmu_suspend(struct device *dev)
+{
+       exynos_tmu_control(to_platform_device(dev), false);
+
+       return 0;
+}
+
+static int exynos_tmu_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+
+       exynos_tmu_initialize(pdev);
+       exynos_tmu_control(pdev, true);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(exynos_tmu_pm,
+                        exynos_tmu_suspend, exynos_tmu_resume);
+#define EXYNOS_TMU_PM  (&exynos_tmu_pm)
+#else
+#define EXYNOS_TMU_PM  NULL
+#endif
+
+static struct platform_driver exynos_tmu_driver = {
+       .driver = {
+               .name   = "exynos-tmu",
+               .owner  = THIS_MODULE,
+               .pm     = EXYNOS_TMU_PM,
+               .of_match_table = exynos_tmu_match,
+       },
+       .probe = exynos_tmu_probe,
+       .remove = exynos_tmu_remove,
+};
+
+module_platform_driver(exynos_tmu_driver);
+
+MODULE_DESCRIPTION("EXYNOS TMU Driver");
+MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:exynos-tmu");
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
new file mode 100644 (file)
index 0000000..b364c9e
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * exynos_tmu.h - Samsung EXYNOS TMU (Thermal Management Unit)
+ *
+ *  Copyright (C) 2011 Samsung Electronics
+ *  Donggeun Kim <dg77.kim@samsung.com>
+ *  Amit Daniel Kachhap <amit.daniel@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _EXYNOS_TMU_H
+#define _EXYNOS_TMU_H
+#include <linux/cpu_cooling.h>
+
+#include "exynos_thermal_common.h"
+
+enum calibration_type {
+       TYPE_ONE_POINT_TRIMMING,
+       TYPE_ONE_POINT_TRIMMING_25,
+       TYPE_ONE_POINT_TRIMMING_85,
+       TYPE_TWO_POINT_TRIMMING,
+       TYPE_NONE,
+};
+
+enum calibration_mode {
+       SW_MODE,
+       HW_MODE,
+};
+
+enum soc_type {
+       SOC_ARCH_EXYNOS4210 = 1,
+       SOC_ARCH_EXYNOS,
+       SOC_ARCH_EXYNOS5440,
+};
+
+/**
+ * EXYNOS TMU supported features.
+ * TMU_SUPPORT_EMULATION - This features is used to set user defined
+ *                     temperature to the TMU controller.
+ * TMU_SUPPORT_MULTI_INST - This features denotes that the soc
+ *                     has many instances of TMU.
+ * TMU_SUPPORT_TRIM_RELOAD - This features shows that trimming can
+ *                     be reloaded.
+ * TMU_SUPPORT_FALLING_TRIP - This features shows that interrupt can
+ *                     be registered for falling trips also.
+ * TMU_SUPPORT_READY_STATUS - This feature tells that the TMU current
+ *                     state(active/idle) can be checked.
+ * TMU_SUPPORT_EMUL_TIME - This features allows to set next temp emulation
+ *                     sample time.
+ * TMU_SUPPORT_SHARED_MEMORY - This feature tells that the different TMU
+ *                     sensors shares some common registers.
+ * TMU_SUPPORT - macro to compare the above features with the supplied.
+ */
+#define TMU_SUPPORT_EMULATION                  BIT(0)
+#define TMU_SUPPORT_MULTI_INST                 BIT(1)
+#define TMU_SUPPORT_TRIM_RELOAD                        BIT(2)
+#define TMU_SUPPORT_FALLING_TRIP               BIT(3)
+#define TMU_SUPPORT_READY_STATUS               BIT(4)
+#define TMU_SUPPORT_EMUL_TIME                  BIT(5)
+#define TMU_SUPPORT_SHARED_MEMORY              BIT(6)
+
+#define TMU_SUPPORTS(a, b)     (a->features & TMU_SUPPORT_ ## b)
+
+/**
+ * struct exynos_tmu_register - register descriptors to access registers and
+ * bitfields. The register validity, offsets and bitfield values may vary
+ * slightly across different exynos SOC's.
+ * @triminfo_data: register containing 2 pont trimming data
+ * @triminfo_25_shift: shift bit of the 25 C trim value in triminfo_data reg.
+ * @triminfo_85_shift: shift bit of the 85 C trim value in triminfo_data reg.
+ * @triminfo_ctrl: trim info controller register.
+ * @triminfo_reload_shift: shift of triminfo reload enable bit in triminfo_ctrl
+       reg.
+ * @tmu_ctrl: TMU main controller register.
+ * @buf_vref_sel_shift: shift bits of reference voltage in tmu_ctrl register.
+ * @buf_vref_sel_mask: mask bits of reference voltage in tmu_ctrl register.
+ * @therm_trip_mode_shift: shift bits of tripping mode in tmu_ctrl register.
+ * @therm_trip_mode_mask: mask bits of tripping mode in tmu_ctrl register.
+ * @therm_trip_en_shift: shift bits of tripping enable in tmu_ctrl register.
+ * @buf_slope_sel_shift: shift bits of amplifier gain value in tmu_ctrl
+       register.
+ * @buf_slope_sel_mask: mask bits of amplifier gain value in tmu_ctrl register.
+ * @calib_mode_shift: shift bits of calibration mode value in tmu_ctrl
+       register.
+ * @calib_mode_mask: mask bits of calibration mode value in tmu_ctrl
+       register.
+ * @therm_trip_tq_en_shift: shift bits of thermal trip enable by TQ pin in
+       tmu_ctrl register.
+ * @core_en_shift: shift bits of TMU core enable bit in tmu_ctrl register.
+ * @tmu_status: register drescribing the TMU status.
+ * @tmu_cur_temp: register containing the current temperature of the TMU.
+ * @tmu_cur_temp_shift: shift bits of current temp value in tmu_cur_temp
+       register.
+ * @threshold_temp: register containing the base threshold level.
+ * @threshold_th0: Register containing first set of rising levels.
+ * @threshold_th0_l0_shift: shift bits of level0 threshold temperature.
+ * @threshold_th0_l1_shift: shift bits of level1 threshold temperature.
+ * @threshold_th0_l2_shift: shift bits of level2 threshold temperature.
+ * @threshold_th0_l3_shift: shift bits of level3 threshold temperature.
+ * @threshold_th1: Register containing second set of rising levels.
+ * @threshold_th1_l0_shift: shift bits of level0 threshold temperature.
+ * @threshold_th1_l1_shift: shift bits of level1 threshold temperature.
+ * @threshold_th1_l2_shift: shift bits of level2 threshold temperature.
+ * @threshold_th1_l3_shift: shift bits of level3 threshold temperature.
+ * @threshold_th2: Register containing third set of rising levels.
+ * @threshold_th2_l0_shift: shift bits of level0 threshold temperature.
+ * @threshold_th3: Register containing fourth set of rising levels.
+ * @threshold_th3_l0_shift: shift bits of level0 threshold temperature.
+ * @tmu_inten: register containing the different threshold interrupt
+       enable bits.
+ * @inten_rise_shift: shift bits of all rising interrupt bits.
+ * @inten_rise_mask: mask bits of all rising interrupt bits.
+ * @inten_fall_shift: shift bits of all rising interrupt bits.
+ * @inten_fall_mask: mask bits of all rising interrupt bits.
+ * @inten_rise0_shift: shift bits of rising 0 interrupt bits.
+ * @inten_rise1_shift: shift bits of rising 1 interrupt bits.
+ * @inten_rise2_shift: shift bits of rising 2 interrupt bits.
+ * @inten_rise3_shift: shift bits of rising 3 interrupt bits.
+ * @inten_fall0_shift: shift bits of falling 0 interrupt bits.
+ * @inten_fall1_shift: shift bits of falling 1 interrupt bits.
+ * @inten_fall2_shift: shift bits of falling 2 interrupt bits.
+ * @inten_fall3_shift: shift bits of falling 3 interrupt bits.
+ * @tmu_intstat: Register containing the interrupt status values.
+ * @tmu_intclear: Register for clearing the raised interrupt status.
+ * @emul_con: TMU emulation controller register.
+ * @emul_temp_shift: shift bits of emulation temperature.
+ * @emul_time_shift: shift bits of emulation time.
+ * @emul_time_mask: mask bits of emulation time.
+ * @tmu_irqstatus: register to find which TMU generated interrupts.
+ * @tmu_pmin: register to get/set the Pmin value.
+ */
+struct exynos_tmu_registers {
+       u32     triminfo_data;
+       u32     triminfo_25_shift;
+       u32     triminfo_85_shift;
+
+       u32     triminfo_ctrl;
+       u32     triminfo_reload_shift;
+
+       u32     tmu_ctrl;
+       u32     buf_vref_sel_shift;
+       u32     buf_vref_sel_mask;
+       u32     therm_trip_mode_shift;
+       u32     therm_trip_mode_mask;
+       u32     therm_trip_en_shift;
+       u32     buf_slope_sel_shift;
+       u32     buf_slope_sel_mask;
+       u32     calib_mode_shift;
+       u32     calib_mode_mask;
+       u32     therm_trip_tq_en_shift;
+       u32     core_en_shift;
+
+       u32     tmu_status;
+
+       u32     tmu_cur_temp;
+       u32     tmu_cur_temp_shift;
+
+       u32     threshold_temp;
+
+       u32     threshold_th0;
+       u32     threshold_th0_l0_shift;
+       u32     threshold_th0_l1_shift;
+       u32     threshold_th0_l2_shift;
+       u32     threshold_th0_l3_shift;
+
+       u32     threshold_th1;
+       u32     threshold_th1_l0_shift;
+       u32     threshold_th1_l1_shift;
+       u32     threshold_th1_l2_shift;
+       u32     threshold_th1_l3_shift;
+
+       u32     threshold_th2;
+       u32     threshold_th2_l0_shift;
+
+       u32     threshold_th3;
+       u32     threshold_th3_l0_shift;
+
+       u32     tmu_inten;
+       u32     inten_rise_shift;
+       u32     inten_rise_mask;
+       u32     inten_fall_shift;
+       u32     inten_fall_mask;
+       u32     inten_rise0_shift;
+       u32     inten_rise1_shift;
+       u32     inten_rise2_shift;
+       u32     inten_rise3_shift;
+       u32     inten_fall0_shift;
+       u32     inten_fall1_shift;
+       u32     inten_fall2_shift;
+       u32     inten_fall3_shift;
+
+       u32     tmu_intstat;
+
+       u32     tmu_intclear;
+
+       u32     emul_con;
+       u32     emul_temp_shift;
+       u32     emul_time_shift;
+       u32     emul_time_mask;
+
+       u32     tmu_irqstatus;
+       u32     tmu_pmin;
+};
+
+/**
+ * struct exynos_tmu_platform_data
+ * @threshold: basic temperature for generating interrupt
+ *            25 <= threshold <= 125 [unit: degree Celsius]
+ * @threshold_falling: differntial value for setting threshold
+ *                    of temperature falling interrupt.
+ * @trigger_levels: array for each interrupt levels
+ *     [unit: degree Celsius]
+ *     0: temperature for trigger_level0 interrupt
+ *        condition for trigger_level0 interrupt:
+ *             current temperature > threshold + trigger_levels[0]
+ *     1: temperature for trigger_level1 interrupt
+ *        condition for trigger_level1 interrupt:
+ *             current temperature > threshold + trigger_levels[1]
+ *     2: temperature for trigger_level2 interrupt
+ *        condition for trigger_level2 interrupt:
+ *             current temperature > threshold + trigger_levels[2]
+ *     3: temperature for trigger_level3 interrupt
+ *        condition for trigger_level3 interrupt:
+ *             current temperature > threshold + trigger_levels[3]
+ * @trigger_type: defines the type of trigger. Possible values are,
+ *     THROTTLE_ACTIVE trigger type
+ *     THROTTLE_PASSIVE trigger type
+ *     SW_TRIP trigger type
+ *     HW_TRIP
+ * @trigger_enable[]: array to denote which trigger levels are enabled.
+ *     1 = enable trigger_level[] interrupt,
+ *     0 = disable trigger_level[] interrupt
+ * @max_trigger_level: max trigger level supported by the TMU
+ * @gain: gain of amplifier in the positive-TC generator block
+ *     0 <= gain <= 15
+ * @reference_voltage: reference voltage of amplifier
+ *     in the positive-TC generator block
+ *     0 <= reference_voltage <= 31
+ * @noise_cancel_mode: noise cancellation mode
+ *     000, 100, 101, 110 and 111 can be different modes
+ * @type: determines the type of SOC
+ * @efuse_value: platform defined fuse value
+ * @min_efuse_value: minimum valid trimming data
+ * @max_efuse_value: maximum valid trimming data
+ * @first_point_trim: temp value of the first point trimming
+ * @second_point_trim: temp value of the second point trimming
+ * @default_temp_offset: default temperature offset in case of no trimming
+ * @cal_type: calibration type for temperature
+ * @cal_mode: calibration mode for temperature
+ * @freq_clip_table: Table representing frequency reduction percentage.
+ * @freq_tab_count: Count of the above table as frequency reduction may
+ *     applicable to only some of the trigger levels.
+ * @registers: Pointer to structure containing all the TMU controller registers
+ *     and bitfields shifts and masks.
+ * @features: a bitfield value indicating the features supported in SOC like
+ *     emulation, multi instance etc
+ *
+ * This structure is required for configuration of exynos_tmu driver.
+ */
+struct exynos_tmu_platform_data {
+       u8 threshold;
+       u8 threshold_falling;
+       u8 trigger_levels[MAX_TRIP_COUNT];
+       enum trigger_type trigger_type[MAX_TRIP_COUNT];
+       bool trigger_enable[MAX_TRIP_COUNT];
+       u8 max_trigger_level;
+       u8 gain;
+       u8 reference_voltage;
+       u8 noise_cancel_mode;
+
+       u32 efuse_value;
+       u32 min_efuse_value;
+       u32 max_efuse_value;
+       u8 first_point_trim;
+       u8 second_point_trim;
+       u8 default_temp_offset;
+
+       enum calibration_type cal_type;
+       enum calibration_mode cal_mode;
+       enum soc_type type;
+       struct freq_clip_table freq_tab[4];
+       unsigned int freq_tab_count;
+       const struct exynos_tmu_registers *registers;
+       unsigned int features;
+};
+
+/**
+ * struct exynos_tmu_init_data
+ * @tmu_count: number of TMU instances.
+ * @tmu_data: platform data of all TMU instances.
+ * This structure is required to store data for multi-instance exynos tmu
+ * driver.
+ */
+struct exynos_tmu_init_data {
+       int tmu_count;
+       struct exynos_tmu_platform_data tmu_data[];
+};
+
+#endif /* _EXYNOS_TMU_H */
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
new file mode 100644 (file)
index 0000000..9002499
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * exynos_tmu_data.c - Samsung EXYNOS tmu data file
+ *
+ *  Copyright (C) 2013 Samsung Electronics
+ *  Amit Daniel Kachhap <amit.daniel@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "exynos_thermal_common.h"
+#include "exynos_tmu.h"
+#include "exynos_tmu_data.h"
+
+#if defined(CONFIG_CPU_EXYNOS4210)
+static const struct exynos_tmu_registers exynos4210_tmu_registers = {
+       .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
+       .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
+       .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
+       .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
+       .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
+       .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
+       .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
+       .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+       .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
+       .tmu_status = EXYNOS_TMU_REG_STATUS,
+       .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
+       .threshold_temp = EXYNOS4210_TMU_REG_THRESHOLD_TEMP,
+       .threshold_th0 = EXYNOS4210_TMU_REG_TRIG_LEVEL0,
+       .tmu_inten = EXYNOS_TMU_REG_INTEN,
+       .inten_rise_mask = EXYNOS4210_TMU_TRIG_LEVEL_MASK,
+       .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
+       .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
+       .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
+       .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
+       .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
+       .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
+};
+
+struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
+       .tmu_data = {
+               {
+               .threshold = 80,
+               .trigger_levels[0] = 5,
+               .trigger_levels[1] = 20,
+               .trigger_levels[2] = 30,
+               .trigger_enable[0] = true,
+               .trigger_enable[1] = true,
+               .trigger_enable[2] = true,
+               .trigger_enable[3] = false,
+               .trigger_type[0] = THROTTLE_ACTIVE,
+               .trigger_type[1] = THROTTLE_ACTIVE,
+               .trigger_type[2] = SW_TRIP,
+               .max_trigger_level = 4,
+               .gain = 15,
+               .reference_voltage = 7,
+               .cal_type = TYPE_ONE_POINT_TRIMMING,
+               .min_efuse_value = 40,
+               .max_efuse_value = 100,
+               .first_point_trim = 25,
+               .second_point_trim = 85,
+               .default_temp_offset = 50,
+               .freq_tab[0] = {
+                       .freq_clip_max = 800 * 1000,
+                       .temp_level = 85,
+                       },
+               .freq_tab[1] = {
+                       .freq_clip_max = 200 * 1000,
+                       .temp_level = 100,
+               },
+               .freq_tab_count = 2,
+               .type = SOC_ARCH_EXYNOS4210,
+               .registers = &exynos4210_tmu_registers,
+               .features = TMU_SUPPORT_READY_STATUS,
+               },
+       },
+       .tmu_count = 1,
+};
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412)
+static const struct exynos_tmu_registers exynos5250_tmu_registers = {
+       .triminfo_data = EXYNOS_TMU_REG_TRIMINFO,
+       .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
+       .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
+       .triminfo_ctrl = EXYNOS_TMU_TRIMINFO_CON,
+       .triminfo_reload_shift = EXYNOS_TRIMINFO_RELOAD_SHIFT,
+       .tmu_ctrl = EXYNOS_TMU_REG_CONTROL,
+       .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
+       .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
+       .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
+       .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
+       .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
+       .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
+       .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+       .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
+       .tmu_status = EXYNOS_TMU_REG_STATUS,
+       .tmu_cur_temp = EXYNOS_TMU_REG_CURRENT_TEMP,
+       .threshold_th0 = EXYNOS_THD_TEMP_RISE,
+       .threshold_th1 = EXYNOS_THD_TEMP_FALL,
+       .tmu_inten = EXYNOS_TMU_REG_INTEN,
+       .inten_rise_mask = EXYNOS_TMU_RISE_INT_MASK,
+       .inten_rise_shift = EXYNOS_TMU_RISE_INT_SHIFT,
+       .inten_fall_mask = EXYNOS_TMU_FALL_INT_MASK,
+       .inten_fall_shift = EXYNOS_TMU_FALL_INT_SHIFT,
+       .inten_rise0_shift = EXYNOS_TMU_INTEN_RISE0_SHIFT,
+       .inten_rise1_shift = EXYNOS_TMU_INTEN_RISE1_SHIFT,
+       .inten_rise2_shift = EXYNOS_TMU_INTEN_RISE2_SHIFT,
+       .inten_rise3_shift = EXYNOS_TMU_INTEN_RISE3_SHIFT,
+       .inten_fall0_shift = EXYNOS_TMU_INTEN_FALL0_SHIFT,
+       .tmu_intstat = EXYNOS_TMU_REG_INTSTAT,
+       .tmu_intclear = EXYNOS_TMU_REG_INTCLEAR,
+       .emul_con = EXYNOS_EMUL_CON,
+       .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
+       .emul_time_shift = EXYNOS_EMUL_TIME_SHIFT,
+       .emul_time_mask = EXYNOS_EMUL_TIME_MASK,
+};
+
+#define EXYNOS5250_TMU_DATA \
+       .threshold_falling = 10, \
+       .trigger_levels[0] = 85, \
+       .trigger_levels[1] = 103, \
+       .trigger_levels[2] = 110, \
+       .trigger_levels[3] = 120, \
+       .trigger_enable[0] = true, \
+       .trigger_enable[1] = true, \
+       .trigger_enable[2] = true, \
+       .trigger_enable[3] = false, \
+       .trigger_type[0] = THROTTLE_ACTIVE, \
+       .trigger_type[1] = THROTTLE_ACTIVE, \
+       .trigger_type[2] = SW_TRIP, \
+       .trigger_type[3] = HW_TRIP, \
+       .max_trigger_level = 4, \
+       .gain = 8, \
+       .reference_voltage = 16, \
+       .noise_cancel_mode = 4, \
+       .cal_type = TYPE_ONE_POINT_TRIMMING, \
+       .efuse_value = 55, \
+       .min_efuse_value = 40, \
+       .max_efuse_value = 100, \
+       .first_point_trim = 25, \
+       .second_point_trim = 85, \
+       .default_temp_offset = 50, \
+       .freq_tab[0] = { \
+               .freq_clip_max = 800 * 1000, \
+               .temp_level = 85, \
+       }, \
+       .freq_tab[1] = { \
+               .freq_clip_max = 200 * 1000, \
+               .temp_level = 103, \
+       }, \
+       .freq_tab_count = 2, \
+       .type = SOC_ARCH_EXYNOS, \
+       .registers = &exynos5250_tmu_registers, \
+       .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_TRIM_RELOAD | \
+                       TMU_SUPPORT_FALLING_TRIP | TMU_SUPPORT_READY_STATUS | \
+                       TMU_SUPPORT_EMUL_TIME)
+
+struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
+       .tmu_data = {
+               { EXYNOS5250_TMU_DATA },
+       },
+       .tmu_count = 1,
+};
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5440)
+static const struct exynos_tmu_registers exynos5440_tmu_registers = {
+       .triminfo_data = EXYNOS5440_TMU_S0_7_TRIM,
+       .triminfo_25_shift = EXYNOS_TRIMINFO_25_SHIFT,
+       .triminfo_85_shift = EXYNOS_TRIMINFO_85_SHIFT,
+       .tmu_ctrl = EXYNOS5440_TMU_S0_7_CTRL,
+       .buf_vref_sel_shift = EXYNOS_TMU_REF_VOLTAGE_SHIFT,
+       .buf_vref_sel_mask = EXYNOS_TMU_REF_VOLTAGE_MASK,
+       .therm_trip_mode_shift = EXYNOS_TMU_TRIP_MODE_SHIFT,
+       .therm_trip_mode_mask = EXYNOS_TMU_TRIP_MODE_MASK,
+       .therm_trip_en_shift = EXYNOS_TMU_THERM_TRIP_EN_SHIFT,
+       .buf_slope_sel_shift = EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT,
+       .buf_slope_sel_mask = EXYNOS_TMU_BUF_SLOPE_SEL_MASK,
+       .calib_mode_shift = EXYNOS_TMU_CALIB_MODE_SHIFT,
+       .calib_mode_mask = EXYNOS_TMU_CALIB_MODE_MASK,
+       .core_en_shift = EXYNOS_TMU_CORE_EN_SHIFT,
+       .tmu_status = EXYNOS5440_TMU_S0_7_STATUS,
+       .tmu_cur_temp = EXYNOS5440_TMU_S0_7_TEMP,
+       .threshold_th0 = EXYNOS5440_TMU_S0_7_TH0,
+       .threshold_th1 = EXYNOS5440_TMU_S0_7_TH1,
+       .threshold_th2 = EXYNOS5440_TMU_S0_7_TH2,
+       .threshold_th3_l0_shift = EXYNOS5440_TMU_TH_RISE4_SHIFT,
+       .tmu_inten = EXYNOS5440_TMU_S0_7_IRQEN,
+       .inten_rise_mask = EXYNOS5440_TMU_RISE_INT_MASK,
+       .inten_rise_shift = EXYNOS5440_TMU_RISE_INT_SHIFT,
+       .inten_fall_mask = EXYNOS5440_TMU_FALL_INT_MASK,
+       .inten_fall_shift = EXYNOS5440_TMU_FALL_INT_SHIFT,
+       .inten_rise0_shift = EXYNOS5440_TMU_INTEN_RISE0_SHIFT,
+       .inten_rise1_shift = EXYNOS5440_TMU_INTEN_RISE1_SHIFT,
+       .inten_rise2_shift = EXYNOS5440_TMU_INTEN_RISE2_SHIFT,
+       .inten_rise3_shift = EXYNOS5440_TMU_INTEN_RISE3_SHIFT,
+       .inten_fall0_shift = EXYNOS5440_TMU_INTEN_FALL0_SHIFT,
+       .tmu_intstat = EXYNOS5440_TMU_S0_7_IRQ,
+       .tmu_intclear = EXYNOS5440_TMU_S0_7_IRQ,
+       .tmu_irqstatus = EXYNOS5440_TMU_IRQ_STATUS,
+       .emul_con = EXYNOS5440_TMU_S0_7_DEBUG,
+       .emul_temp_shift = EXYNOS_EMUL_DATA_SHIFT,
+       .tmu_pmin = EXYNOS5440_TMU_PMIN,
+};
+
+#define EXYNOS5440_TMU_DATA \
+       .trigger_levels[0] = 100, \
+       .trigger_levels[4] = 105, \
+       .trigger_enable[0] = 1, \
+       .trigger_type[0] = SW_TRIP, \
+       .trigger_type[4] = HW_TRIP, \
+       .max_trigger_level = 5, \
+       .gain = 5, \
+       .reference_voltage = 16, \
+       .noise_cancel_mode = 4, \
+       .cal_type = TYPE_ONE_POINT_TRIMMING, \
+       .cal_mode = 0, \
+       .efuse_value = 0x5b2d, \
+       .min_efuse_value = 16, \
+       .max_efuse_value = 76, \
+       .first_point_trim = 25, \
+       .second_point_trim = 70, \
+       .default_temp_offset = 25, \
+       .type = SOC_ARCH_EXYNOS5440, \
+       .registers = &exynos5440_tmu_registers, \
+       .features = (TMU_SUPPORT_EMULATION | TMU_SUPPORT_FALLING_TRIP | \
+                       TMU_SUPPORT_MULTI_INST | TMU_SUPPORT_SHARED_MEMORY),
+
+struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
+       .tmu_data = {
+               { EXYNOS5440_TMU_DATA } ,
+               { EXYNOS5440_TMU_DATA } ,
+               { EXYNOS5440_TMU_DATA } ,
+       },
+       .tmu_count = 3,
+};
+#endif
diff --git a/drivers/thermal/samsung/exynos_tmu_data.h b/drivers/thermal/samsung/exynos_tmu_data.h
new file mode 100644 (file)
index 0000000..dc7feb5
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * exynos_tmu_data.h - Samsung EXYNOS tmu data header file
+ *
+ *  Copyright (C) 2013 Samsung Electronics
+ *  Amit Daniel Kachhap <amit.daniel@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _EXYNOS_TMU_DATA_H
+#define _EXYNOS_TMU_DATA_H
+
+/* Exynos generic registers */
+#define EXYNOS_TMU_REG_TRIMINFO                0x0
+#define EXYNOS_TMU_REG_CONTROL         0x20
+#define EXYNOS_TMU_REG_STATUS          0x28
+#define EXYNOS_TMU_REG_CURRENT_TEMP    0x40
+#define EXYNOS_TMU_REG_INTEN           0x70
+#define EXYNOS_TMU_REG_INTSTAT         0x74
+#define EXYNOS_TMU_REG_INTCLEAR                0x78
+
+#define EXYNOS_TMU_TEMP_MASK           0xff
+#define EXYNOS_TMU_REF_VOLTAGE_SHIFT   24
+#define EXYNOS_TMU_REF_VOLTAGE_MASK    0x1f
+#define EXYNOS_TMU_BUF_SLOPE_SEL_MASK  0xf
+#define EXYNOS_TMU_BUF_SLOPE_SEL_SHIFT 8
+#define EXYNOS_TMU_CORE_EN_SHIFT       0
+
+/* Exynos4210 specific registers */
+#define EXYNOS4210_TMU_REG_THRESHOLD_TEMP      0x44
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL0 0x50
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL1 0x54
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL2 0x58
+#define EXYNOS4210_TMU_REG_TRIG_LEVEL3 0x5C
+#define EXYNOS4210_TMU_REG_PAST_TEMP0  0x60
+#define EXYNOS4210_TMU_REG_PAST_TEMP1  0x64
+#define EXYNOS4210_TMU_REG_PAST_TEMP2  0x68
+#define EXYNOS4210_TMU_REG_PAST_TEMP3  0x6C
+
+#define EXYNOS4210_TMU_TRIG_LEVEL0_MASK        0x1
+#define EXYNOS4210_TMU_TRIG_LEVEL1_MASK        0x10
+#define EXYNOS4210_TMU_TRIG_LEVEL2_MASK        0x100
+#define EXYNOS4210_TMU_TRIG_LEVEL3_MASK        0x1000
+#define EXYNOS4210_TMU_TRIG_LEVEL_MASK 0x1111
+#define EXYNOS4210_TMU_INTCLEAR_VAL    0x1111
+
+/* Exynos5250 and Exynos4412 specific registers */
+#define EXYNOS_TMU_TRIMINFO_CON        0x14
+#define EXYNOS_THD_TEMP_RISE           0x50
+#define EXYNOS_THD_TEMP_FALL           0x54
+#define EXYNOS_EMUL_CON                0x80
+
+#define EXYNOS_TRIMINFO_RELOAD_SHIFT   1
+#define EXYNOS_TRIMINFO_25_SHIFT       0
+#define EXYNOS_TRIMINFO_85_SHIFT       8
+#define EXYNOS_TMU_RISE_INT_MASK       0x111
+#define EXYNOS_TMU_RISE_INT_SHIFT      0
+#define EXYNOS_TMU_FALL_INT_MASK       0x111
+#define EXYNOS_TMU_FALL_INT_SHIFT      12
+#define EXYNOS_TMU_CLEAR_RISE_INT      0x111
+#define EXYNOS_TMU_CLEAR_FALL_INT      (0x111 << 12)
+#define EXYNOS_TMU_TRIP_MODE_SHIFT     13
+#define EXYNOS_TMU_TRIP_MODE_MASK      0x7
+#define EXYNOS_TMU_THERM_TRIP_EN_SHIFT 12
+#define EXYNOS_TMU_CALIB_MODE_SHIFT    4
+#define EXYNOS_TMU_CALIB_MODE_MASK     0x3
+
+#define EXYNOS_TMU_INTEN_RISE0_SHIFT   0
+#define EXYNOS_TMU_INTEN_RISE1_SHIFT   4
+#define EXYNOS_TMU_INTEN_RISE2_SHIFT   8
+#define EXYNOS_TMU_INTEN_RISE3_SHIFT   12
+#define EXYNOS_TMU_INTEN_FALL0_SHIFT   16
+#define EXYNOS_TMU_INTEN_FALL1_SHIFT   20
+#define EXYNOS_TMU_INTEN_FALL2_SHIFT   24
+
+#define EXYNOS_EMUL_TIME       0x57F0
+#define EXYNOS_EMUL_TIME_MASK  0xffff
+#define EXYNOS_EMUL_TIME_SHIFT 16
+#define EXYNOS_EMUL_DATA_SHIFT 8
+#define EXYNOS_EMUL_DATA_MASK  0xFF
+#define EXYNOS_EMUL_ENABLE     0x1
+
+#define EXYNOS_MAX_TRIGGER_PER_REG     4
+
+/*exynos5440 specific registers*/
+#define EXYNOS5440_TMU_S0_7_TRIM               0x000
+#define EXYNOS5440_TMU_S0_7_CTRL               0x020
+#define EXYNOS5440_TMU_S0_7_DEBUG              0x040
+#define EXYNOS5440_TMU_S0_7_STATUS             0x060
+#define EXYNOS5440_TMU_S0_7_TEMP               0x0f0
+#define EXYNOS5440_TMU_S0_7_TH0                        0x110
+#define EXYNOS5440_TMU_S0_7_TH1                        0x130
+#define EXYNOS5440_TMU_S0_7_TH2                        0x150
+#define EXYNOS5440_TMU_S0_7_EVTEN              0x1F0
+#define EXYNOS5440_TMU_S0_7_IRQEN              0x210
+#define EXYNOS5440_TMU_S0_7_IRQ                        0x230
+/* exynos5440 common registers */
+#define EXYNOS5440_TMU_IRQ_STATUS              0x000
+#define EXYNOS5440_TMU_PMIN                    0x004
+#define EXYNOS5440_TMU_TEMP                    0x008
+
+#define EXYNOS5440_TMU_RISE_INT_MASK           0xf
+#define EXYNOS5440_TMU_RISE_INT_SHIFT          0
+#define EXYNOS5440_TMU_FALL_INT_MASK           0xf
+#define EXYNOS5440_TMU_FALL_INT_SHIFT          4
+#define EXYNOS5440_TMU_INTEN_RISE0_SHIFT       0
+#define EXYNOS5440_TMU_INTEN_RISE1_SHIFT       1
+#define EXYNOS5440_TMU_INTEN_RISE2_SHIFT       2
+#define EXYNOS5440_TMU_INTEN_RISE3_SHIFT       3
+#define EXYNOS5440_TMU_INTEN_FALL0_SHIFT       4
+#define EXYNOS5440_TMU_INTEN_FALL1_SHIFT       5
+#define EXYNOS5440_TMU_INTEN_FALL2_SHIFT       6
+#define EXYNOS5440_TMU_INTEN_FALL3_SHIFT       7
+#define EXYNOS5440_TMU_TH_RISE0_SHIFT          0
+#define EXYNOS5440_TMU_TH_RISE1_SHIFT          8
+#define EXYNOS5440_TMU_TH_RISE2_SHIFT          16
+#define EXYNOS5440_TMU_TH_RISE3_SHIFT          24
+#define EXYNOS5440_TMU_TH_RISE4_SHIFT          24
+#define EXYNOS5440_EFUSE_SWAP_OFFSET           8
+
+#if defined(CONFIG_CPU_EXYNOS4210)
+extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
+#define EXYNOS4210_TMU_DRV_DATA (&exynos4210_default_tmu_data)
+#else
+#define EXYNOS4210_TMU_DRV_DATA (NULL)
+#endif
+
+#if (defined(CONFIG_SOC_EXYNOS5250) || defined(CONFIG_SOC_EXYNOS4412))
+extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
+#define EXYNOS5250_TMU_DRV_DATA (&exynos5250_default_tmu_data)
+#else
+#define EXYNOS5250_TMU_DRV_DATA (NULL)
+#endif
+
+#if defined(CONFIG_SOC_EXYNOS5440)
+extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
+#define EXYNOS5440_TMU_DRV_DATA (&exynos5440_default_tmu_data)
+#else
+#define EXYNOS5440_TMU_DRV_DATA (NULL)
+#endif
+
+#endif /*_EXYNOS_TMU_DATA_H*/
index 4d4ddae1a99183cee9705f24e7acdc91cde62cc6..d89e781b0a18d9a71fce0ff18c77683c7699dc10 100644 (file)
@@ -51,44 +51,51 @@ static unsigned long get_target_state(struct thermal_instance *instance,
 {
        struct thermal_cooling_device *cdev = instance->cdev;
        unsigned long cur_state;
+       unsigned long next_target;
 
+       /*
+        * We keep this instance the way it is by default.
+        * Otherwise, we use the current state of the
+        * cdev in use to determine the next_target.
+        */
        cdev->ops->get_cur_state(cdev, &cur_state);
+       next_target = instance->target;
 
        switch (trend) {
        case THERMAL_TREND_RAISING:
                if (throttle) {
-                       cur_state = cur_state < instance->upper ?
+                       next_target = cur_state < instance->upper ?
                                    (cur_state + 1) : instance->upper;
-                       if (cur_state < instance->lower)
-                               cur_state = instance->lower;
+                       if (next_target < instance->lower)
+                               next_target = instance->lower;
                }
                break;
        case THERMAL_TREND_RAISE_FULL:
                if (throttle)
-                       cur_state = instance->upper;
+                       next_target = instance->upper;
                break;
        case THERMAL_TREND_DROPPING:
                if (cur_state == instance->lower) {
                        if (!throttle)
-                               cur_state = -1;
+                               next_target = THERMAL_NO_TARGET;
                } else {
-                       cur_state -= 1;
-                       if (cur_state > instance->upper)
-                               cur_state = instance->upper;
+                       next_target = cur_state - 1;
+                       if (next_target > instance->upper)
+                               next_target = instance->upper;
                }
                break;
        case THERMAL_TREND_DROP_FULL:
                if (cur_state == instance->lower) {
                        if (!throttle)
-                               cur_state = -1;
+                               next_target = THERMAL_NO_TARGET;
                } else
-                       cur_state = instance->lower;
+                       next_target = instance->lower;
                break;
        default:
                break;
        }
 
-       return cur_state;
+       return next_target;
 }
 
 static void update_passive_instance(struct thermal_zone_device *tz,
@@ -133,6 +140,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
                old_target = instance->target;
                instance->target = get_target_state(instance, trend, throttle);
 
+               if (old_target == instance->target)
+                       continue;
+
                /* Activate a passive thermal instance */
                if (old_target == THERMAL_NO_TARGET &&
                        instance->target != THERMAL_NO_TARGET)
index 1f02e8edb45c9f6b36dae08a563b47efecf4c99d..4962a6aaf2957d737dfadc2376e803d5d849ff7b 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/genetlink.h>
 
 #include "thermal_core.h"
+#include "thermal_hwmon.h"
 
 MODULE_AUTHOR("Zhang Rui");
 MODULE_DESCRIPTION("Generic thermal management sysfs support");
@@ -201,14 +202,23 @@ static void print_bind_err_msg(struct thermal_zone_device *tz,
 }
 
 static void __bind(struct thermal_zone_device *tz, int mask,
-                       struct thermal_cooling_device *cdev)
+                       struct thermal_cooling_device *cdev,
+                       unsigned long *limits)
 {
        int i, ret;
 
        for (i = 0; i < tz->trips; i++) {
                if (mask & (1 << i)) {
+                       unsigned long upper, lower;
+
+                       upper = THERMAL_NO_LIMIT;
+                       lower = THERMAL_NO_LIMIT;
+                       if (limits) {
+                               lower = limits[i * 2];
+                               upper = limits[i * 2 + 1];
+                       }
                        ret = thermal_zone_bind_cooling_device(tz, i, cdev,
-                                       THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+                                                              upper, lower);
                        if (ret)
                                print_bind_err_msg(tz, cdev, ret);
                }
@@ -253,7 +263,8 @@ static void bind_cdev(struct thermal_cooling_device *cdev)
                        if (tzp->tbp[i].match(pos, cdev))
                                continue;
                        tzp->tbp[i].cdev = cdev;
-                       __bind(pos, tzp->tbp[i].trip_mask, cdev);
+                       __bind(pos, tzp->tbp[i].trip_mask, cdev,
+                              tzp->tbp[i].binding_limits);
                }
        }
 
@@ -291,7 +302,8 @@ static void bind_tz(struct thermal_zone_device *tz)
                        if (tzp->tbp[i].match(tz, pos))
                                continue;
                        tzp->tbp[i].cdev = pos;
-                       __bind(tz, tzp->tbp[i].trip_mask, pos);
+                       __bind(tz, tzp->tbp[i].trip_mask, pos,
+                              tzp->tbp[i].binding_limits);
                }
        }
 exit:
@@ -859,260 +871,6 @@ thermal_cooling_device_trip_point_show(struct device *dev,
 
 /* Device management */
 
-#if defined(CONFIG_THERMAL_HWMON)
-
-/* hwmon sys I/F */
-#include <linux/hwmon.h>
-
-/* thermal zone devices with the same type share one hwmon device */
-struct thermal_hwmon_device {
-       char type[THERMAL_NAME_LENGTH];
-       struct device *device;
-       int count;
-       struct list_head tz_list;
-       struct list_head node;
-};
-
-struct thermal_hwmon_attr {
-       struct device_attribute attr;
-       char name[16];
-};
-
-/* one temperature input for each thermal zone */
-struct thermal_hwmon_temp {
-       struct list_head hwmon_node;
-       struct thermal_zone_device *tz;
-       struct thermal_hwmon_attr temp_input;   /* hwmon sys attr */
-       struct thermal_hwmon_attr temp_crit;    /* hwmon sys attr */
-};
-
-static LIST_HEAD(thermal_hwmon_list);
-
-static ssize_t
-name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
-       return sprintf(buf, "%s\n", hwmon->type);
-}
-static DEVICE_ATTR(name, 0444, name_show, NULL);
-
-static ssize_t
-temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       long temperature;
-       int ret;
-       struct thermal_hwmon_attr *hwmon_attr
-                       = container_of(attr, struct thermal_hwmon_attr, attr);
-       struct thermal_hwmon_temp *temp
-                       = container_of(hwmon_attr, struct thermal_hwmon_temp,
-                                      temp_input);
-       struct thermal_zone_device *tz = temp->tz;
-
-       ret = thermal_zone_get_temp(tz, &temperature);
-
-       if (ret)
-               return ret;
-
-       return sprintf(buf, "%ld\n", temperature);
-}
-
-static ssize_t
-temp_crit_show(struct device *dev, struct device_attribute *attr,
-               char *buf)
-{
-       struct thermal_hwmon_attr *hwmon_attr
-                       = container_of(attr, struct thermal_hwmon_attr, attr);
-       struct thermal_hwmon_temp *temp
-                       = container_of(hwmon_attr, struct thermal_hwmon_temp,
-                                      temp_crit);
-       struct thermal_zone_device *tz = temp->tz;
-       long temperature;
-       int ret;
-
-       ret = tz->ops->get_trip_temp(tz, 0, &temperature);
-       if (ret)
-               return ret;
-
-       return sprintf(buf, "%ld\n", temperature);
-}
-
-
-static struct thermal_hwmon_device *
-thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
-{
-       struct thermal_hwmon_device *hwmon;
-
-       mutex_lock(&thermal_list_lock);
-       list_for_each_entry(hwmon, &thermal_hwmon_list, node)
-               if (!strcmp(hwmon->type, tz->type)) {
-                       mutex_unlock(&thermal_list_lock);
-                       return hwmon;
-               }
-       mutex_unlock(&thermal_list_lock);
-
-       return NULL;
-}
-
-/* Find the temperature input matching a given thermal zone */
-static struct thermal_hwmon_temp *
-thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
-                         const struct thermal_zone_device *tz)
-{
-       struct thermal_hwmon_temp *temp;
-
-       mutex_lock(&thermal_list_lock);
-       list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
-               if (temp->tz == tz) {
-                       mutex_unlock(&thermal_list_lock);
-                       return temp;
-               }
-       mutex_unlock(&thermal_list_lock);
-
-       return NULL;
-}
-
-static int
-thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-       struct thermal_hwmon_device *hwmon;
-       struct thermal_hwmon_temp *temp;
-       int new_hwmon_device = 1;
-       int result;
-
-       hwmon = thermal_hwmon_lookup_by_type(tz);
-       if (hwmon) {
-               new_hwmon_device = 0;
-               goto register_sys_interface;
-       }
-
-       hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
-       if (!hwmon)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&hwmon->tz_list);
-       strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
-       hwmon->device = hwmon_device_register(NULL);
-       if (IS_ERR(hwmon->device)) {
-               result = PTR_ERR(hwmon->device);
-               goto free_mem;
-       }
-       dev_set_drvdata(hwmon->device, hwmon);
-       result = device_create_file(hwmon->device, &dev_attr_name);
-       if (result)
-               goto free_mem;
-
- register_sys_interface:
-       temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
-       if (!temp) {
-               result = -ENOMEM;
-               goto unregister_name;
-       }
-
-       temp->tz = tz;
-       hwmon->count++;
-
-       snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
-                "temp%d_input", hwmon->count);
-       temp->temp_input.attr.attr.name = temp->temp_input.name;
-       temp->temp_input.attr.attr.mode = 0444;
-       temp->temp_input.attr.show = temp_input_show;
-       sysfs_attr_init(&temp->temp_input.attr.attr);
-       result = device_create_file(hwmon->device, &temp->temp_input.attr);
-       if (result)
-               goto free_temp_mem;
-
-       if (tz->ops->get_crit_temp) {
-               unsigned long temperature;
-               if (!tz->ops->get_crit_temp(tz, &temperature)) {
-                       snprintf(temp->temp_crit.name,
-                                sizeof(temp->temp_crit.name),
-                               "temp%d_crit", hwmon->count);
-                       temp->temp_crit.attr.attr.name = temp->temp_crit.name;
-                       temp->temp_crit.attr.attr.mode = 0444;
-                       temp->temp_crit.attr.show = temp_crit_show;
-                       sysfs_attr_init(&temp->temp_crit.attr.attr);
-                       result = device_create_file(hwmon->device,
-                                                   &temp->temp_crit.attr);
-                       if (result)
-                               goto unregister_input;
-               }
-       }
-
-       mutex_lock(&thermal_list_lock);
-       if (new_hwmon_device)
-               list_add_tail(&hwmon->node, &thermal_hwmon_list);
-       list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
-       mutex_unlock(&thermal_list_lock);
-
-       return 0;
-
- unregister_input:
-       device_remove_file(hwmon->device, &temp->temp_input.attr);
- free_temp_mem:
-       kfree(temp);
- unregister_name:
-       if (new_hwmon_device) {
-               device_remove_file(hwmon->device, &dev_attr_name);
-               hwmon_device_unregister(hwmon->device);
-       }
- free_mem:
-       if (new_hwmon_device)
-               kfree(hwmon);
-
-       return result;
-}
-
-static void
-thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-       struct thermal_hwmon_device *hwmon;
-       struct thermal_hwmon_temp *temp;
-
-       hwmon = thermal_hwmon_lookup_by_type(tz);
-       if (unlikely(!hwmon)) {
-               /* Should never happen... */
-               dev_dbg(&tz->device, "hwmon device lookup failed!\n");
-               return;
-       }
-
-       temp = thermal_hwmon_lookup_temp(hwmon, tz);
-       if (unlikely(!temp)) {
-               /* Should never happen... */
-               dev_dbg(&tz->device, "temperature input lookup failed!\n");
-               return;
-       }
-
-       device_remove_file(hwmon->device, &temp->temp_input.attr);
-       if (tz->ops->get_crit_temp)
-               device_remove_file(hwmon->device, &temp->temp_crit.attr);
-
-       mutex_lock(&thermal_list_lock);
-       list_del(&temp->hwmon_node);
-       kfree(temp);
-       if (!list_empty(&hwmon->tz_list)) {
-               mutex_unlock(&thermal_list_lock);
-               return;
-       }
-       list_del(&hwmon->node);
-       mutex_unlock(&thermal_list_lock);
-
-       device_remove_file(hwmon->device, &dev_attr_name);
-       hwmon_device_unregister(hwmon->device);
-       kfree(hwmon);
-}
-#else
-static int
-thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-       return 0;
-}
-
-static void
-thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-}
-#endif
-
 /**
  * thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
  * @tz:                pointer to struct thermal_zone_device
@@ -1715,9 +1473,11 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 
        mutex_unlock(&thermal_governor_lock);
 
-       result = thermal_add_hwmon_sysfs(tz);
-       if (result)
-               goto unregister;
+       if (!tz->tzp || !tz->tzp->no_hwmon) {
+               result = thermal_add_hwmon_sysfs(tz);
+               if (result)
+                       goto unregister;
+       }
 
        mutex_lock(&thermal_list_lock);
        list_add_tail(&tz->node, &thermal_tz_list);
diff --git a/drivers/thermal/thermal_hwmon.c b/drivers/thermal/thermal_hwmon.c
new file mode 100644 (file)
index 0000000..eeef0e2
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ *  thermal_hwmon.c - Generic Thermal Management hwmon support.
+ *
+ *  Code based on Intel thermal_core.c. Copyrights of the original code:
+ *  Copyright (C) 2008 Intel Corp
+ *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *
+ *  Copyright (C) 2013 Texas Instruments
+ *  Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.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.
+ *
+ *  This program is distributed in 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/hwmon.h>
+#include <linux/thermal.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include "thermal_hwmon.h"
+
+/* hwmon sys I/F */
+/* thermal zone devices with the same type share one hwmon device */
+struct thermal_hwmon_device {
+       char type[THERMAL_NAME_LENGTH];
+       struct device *device;
+       int count;
+       struct list_head tz_list;
+       struct list_head node;
+};
+
+struct thermal_hwmon_attr {
+       struct device_attribute attr;
+       char name[16];
+};
+
+/* one temperature input for each thermal zone */
+struct thermal_hwmon_temp {
+       struct list_head hwmon_node;
+       struct thermal_zone_device *tz;
+       struct thermal_hwmon_attr temp_input;   /* hwmon sys attr */
+       struct thermal_hwmon_attr temp_crit;    /* hwmon sys attr */
+};
+
+static LIST_HEAD(thermal_hwmon_list);
+
+static DEFINE_MUTEX(thermal_hwmon_list_lock);
+
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
+       return sprintf(buf, "%s\n", hwmon->type);
+}
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       long temperature;
+       int ret;
+       struct thermal_hwmon_attr *hwmon_attr
+                       = container_of(attr, struct thermal_hwmon_attr, attr);
+       struct thermal_hwmon_temp *temp
+                       = container_of(hwmon_attr, struct thermal_hwmon_temp,
+                                      temp_input);
+       struct thermal_zone_device *tz = temp->tz;
+
+       ret = thermal_zone_get_temp(tz, &temperature);
+
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%ld\n", temperature);
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct thermal_hwmon_attr *hwmon_attr
+                       = container_of(attr, struct thermal_hwmon_attr, attr);
+       struct thermal_hwmon_temp *temp
+                       = container_of(hwmon_attr, struct thermal_hwmon_temp,
+                                      temp_crit);
+       struct thermal_zone_device *tz = temp->tz;
+       long temperature;
+       int ret;
+
+       ret = tz->ops->get_trip_temp(tz, 0, &temperature);
+       if (ret)
+               return ret;
+
+       return sprintf(buf, "%ld\n", temperature);
+}
+
+
+static struct thermal_hwmon_device *
+thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
+{
+       struct thermal_hwmon_device *hwmon;
+
+       mutex_lock(&thermal_hwmon_list_lock);
+       list_for_each_entry(hwmon, &thermal_hwmon_list, node)
+               if (!strcmp(hwmon->type, tz->type)) {
+                       mutex_unlock(&thermal_hwmon_list_lock);
+                       return hwmon;
+               }
+       mutex_unlock(&thermal_hwmon_list_lock);
+
+       return NULL;
+}
+
+/* Find the temperature input matching a given thermal zone */
+static struct thermal_hwmon_temp *
+thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
+                         const struct thermal_zone_device *tz)
+{
+       struct thermal_hwmon_temp *temp;
+
+       mutex_lock(&thermal_hwmon_list_lock);
+       list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
+               if (temp->tz == tz) {
+                       mutex_unlock(&thermal_hwmon_list_lock);
+                       return temp;
+               }
+       mutex_unlock(&thermal_hwmon_list_lock);
+
+       return NULL;
+}
+
+int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+       struct thermal_hwmon_device *hwmon;
+       struct thermal_hwmon_temp *temp;
+       int new_hwmon_device = 1;
+       int result;
+
+       hwmon = thermal_hwmon_lookup_by_type(tz);
+       if (hwmon) {
+               new_hwmon_device = 0;
+               goto register_sys_interface;
+       }
+
+       hwmon = kzalloc(sizeof(*hwmon), GFP_KERNEL);
+       if (!hwmon)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&hwmon->tz_list);
+       strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
+       hwmon->device = hwmon_device_register(&tz->device);
+       if (IS_ERR(hwmon->device)) {
+               result = PTR_ERR(hwmon->device);
+               goto free_mem;
+       }
+       dev_set_drvdata(hwmon->device, hwmon);
+       result = device_create_file(hwmon->device, &dev_attr_name);
+       if (result)
+               goto free_mem;
+
+ register_sys_interface:
+       temp = kzalloc(sizeof(*temp), GFP_KERNEL);
+       if (!temp) {
+               result = -ENOMEM;
+               goto unregister_name;
+       }
+
+       temp->tz = tz;
+       hwmon->count++;
+
+       snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
+                "temp%d_input", hwmon->count);
+       temp->temp_input.attr.attr.name = temp->temp_input.name;
+       temp->temp_input.attr.attr.mode = 0444;
+       temp->temp_input.attr.show = temp_input_show;
+       sysfs_attr_init(&temp->temp_input.attr.attr);
+       result = device_create_file(hwmon->device, &temp->temp_input.attr);
+       if (result)
+               goto free_temp_mem;
+
+       if (tz->ops->get_crit_temp) {
+               unsigned long temperature;
+               if (!tz->ops->get_crit_temp(tz, &temperature)) {
+                       snprintf(temp->temp_crit.name,
+                                sizeof(temp->temp_crit.name),
+                               "temp%d_crit", hwmon->count);
+                       temp->temp_crit.attr.attr.name = temp->temp_crit.name;
+                       temp->temp_crit.attr.attr.mode = 0444;
+                       temp->temp_crit.attr.show = temp_crit_show;
+                       sysfs_attr_init(&temp->temp_crit.attr.attr);
+                       result = device_create_file(hwmon->device,
+                                                   &temp->temp_crit.attr);
+                       if (result)
+                               goto unregister_input;
+               }
+       }
+
+       mutex_lock(&thermal_hwmon_list_lock);
+       if (new_hwmon_device)
+               list_add_tail(&hwmon->node, &thermal_hwmon_list);
+       list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
+       mutex_unlock(&thermal_hwmon_list_lock);
+
+       return 0;
+
+ unregister_input:
+       device_remove_file(hwmon->device, &temp->temp_input.attr);
+ free_temp_mem:
+       kfree(temp);
+ unregister_name:
+       if (new_hwmon_device) {
+               device_remove_file(hwmon->device, &dev_attr_name);
+               hwmon_device_unregister(hwmon->device);
+       }
+ free_mem:
+       if (new_hwmon_device)
+               kfree(hwmon);
+
+       return result;
+}
+
+void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+       struct thermal_hwmon_device *hwmon;
+       struct thermal_hwmon_temp *temp;
+
+       hwmon = thermal_hwmon_lookup_by_type(tz);
+       if (unlikely(!hwmon)) {
+               /* Should never happen... */
+               dev_dbg(&tz->device, "hwmon device lookup failed!\n");
+               return;
+       }
+
+       temp = thermal_hwmon_lookup_temp(hwmon, tz);
+       if (unlikely(!temp)) {
+               /* Should never happen... */
+               dev_dbg(&tz->device, "temperature input lookup failed!\n");
+               return;
+       }
+
+       device_remove_file(hwmon->device, &temp->temp_input.attr);
+       if (tz->ops->get_crit_temp)
+               device_remove_file(hwmon->device, &temp->temp_crit.attr);
+
+       mutex_lock(&thermal_hwmon_list_lock);
+       list_del(&temp->hwmon_node);
+       kfree(temp);
+       if (!list_empty(&hwmon->tz_list)) {
+               mutex_unlock(&thermal_hwmon_list_lock);
+               return;
+       }
+       list_del(&hwmon->node);
+       mutex_unlock(&thermal_hwmon_list_lock);
+
+       device_remove_file(hwmon->device, &dev_attr_name);
+       hwmon_device_unregister(hwmon->device);
+       kfree(hwmon);
+}
diff --git a/drivers/thermal/thermal_hwmon.h b/drivers/thermal/thermal_hwmon.h
new file mode 100644 (file)
index 0000000..c798fdb
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  thermal_hwmon.h - Generic Thermal Management hwmon support.
+ *
+ *  Code based on Intel thermal_core.c. Copyrights of the original code:
+ *  Copyright (C) 2008 Intel Corp
+ *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *
+ *  Copyright (C) 2013 Texas Instruments
+ *  Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.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.
+ *
+ *  This program is distributed in 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 __THERMAL_HWMON_H__
+#define __THERMAL_HWMON_H__
+
+#include <linux/thermal.h>
+
+#ifdef CONFIG_THERMAL_HWMON
+int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz);
+void thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz);
+#else
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+       return 0;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+}
+#endif
+
+#endif /* __THERMAL_HWMON_H__ */
index e5d8326a54d6621c019767dfc922fc336f5b2e70..a4929272074f3f8a161ff7978289af475560b9eb 100644 (file)
@@ -42,6 +42,7 @@ dra752_core_temp_sensor_registers = {
        .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_CORE_MASK,
        .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_CORE_MASK,
        .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
        .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_CORE_MASK,
        .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_CORE_MASK,
        .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_CORE_MASK,
@@ -77,6 +78,7 @@ dra752_iva_temp_sensor_registers = {
        .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_IVA_MASK,
        .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_IVA_MASK,
        .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
        .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_IVA_MASK,
        .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_IVA_MASK,
        .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_IVA_MASK,
@@ -112,6 +114,7 @@ dra752_mpu_temp_sensor_registers = {
        .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_MPU_MASK,
        .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_MPU_MASK,
        .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
        .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_MPU_MASK,
        .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_MPU_MASK,
        .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_MPU_MASK,
@@ -147,6 +150,7 @@ dra752_dspeve_temp_sensor_registers = {
        .mask_hot_mask = DRA752_BANDGAP_CTRL_2_MASK_HOT_DSPEVE_MASK,
        .mask_cold_mask = DRA752_BANDGAP_CTRL_2_MASK_COLD_DSPEVE_MASK,
        .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
        .mask_freeze_mask = DRA752_BANDGAP_CTRL_2_FREEZE_DSPEVE_MASK,
        .mask_clear_mask = DRA752_BANDGAP_CTRL_2_CLEAR_DSPEVE_MASK,
        .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_2_CLEAR_ACCUM_DSPEVE_MASK,
@@ -182,6 +186,7 @@ dra752_gpu_temp_sensor_registers = {
        .mask_hot_mask = DRA752_BANDGAP_CTRL_1_MASK_HOT_GPU_MASK,
        .mask_cold_mask = DRA752_BANDGAP_CTRL_1_MASK_COLD_GPU_MASK,
        .mask_sidlemode_mask = DRA752_BANDGAP_CTRL_1_SIDLEMODE_MASK,
+       .mask_counter_delay_mask = DRA752_BANDGAP_CTRL_1_COUNTER_DELAY_MASK,
        .mask_freeze_mask = DRA752_BANDGAP_CTRL_1_FREEZE_GPU_MASK,
        .mask_clear_mask = DRA752_BANDGAP_CTRL_1_CLEAR_GPU_MASK,
        .mask_clear_accum_mask = DRA752_BANDGAP_CTRL_1_CLEAR_ACCUM_GPU_MASK,
index 9dfd47196e63d2ff05c29ecef6ce6a3425b0e63c..74c0e3474d6e935a7d16bf29e6304e59b9a01a1f 100644 (file)
@@ -1020,9 +1020,13 @@ int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend)
 
        /* Fetch the update interval */
        ret = ti_bandgap_read_update_interval(bgp, id, &interval);
-       if (ret || !interval)
+       if (ret)
                goto unfreeze;
 
+       /* Set the interval to 1 ms if bandgap counter delay is not set */
+       if (interval == 0)
+               interval = 1;
+
        *trend = (t1 - t2) / interval;
 
        dev_dbg(bgp->dev, "The temperatures are t1 = %d and t2 = %d and trend =%d\n",
index 4c5f55c373496e30fde2cbff0d18893268fe58d7..4f8b9af54a5a75d1de884a342920ccb50f9ba869 100644 (file)
@@ -174,6 +174,9 @@ static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
                               enum thermal_device_mode mode)
 {
        struct ti_thermal_data *data = thermal->devdata;
+       struct ti_bandgap *bgp;
+
+       bgp = data->bgp;
 
        if (!data->ti_thermal) {
                dev_notice(&thermal->device, "thermal zone not registered\n");
@@ -190,6 +193,8 @@ static int ti_thermal_set_mode(struct thermal_zone_device *thermal,
        mutex_unlock(&data->ti_thermal->lock);
 
        data->mode = mode;
+       ti_bandgap_write_update_interval(bgp, data->sensor_id,
+                                       data->ti_thermal->polling_delay);
        thermal_zone_device_update(data->ti_thermal);
        dev_dbg(&thermal->device, "thermal polling set for duration=%d msec\n",
                data->ti_thermal->polling_delay);
@@ -313,6 +318,8 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
        }
        data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
        ti_bandgap_set_sensor_data(bgp, id, data);
+       ti_bandgap_write_update_interval(bgp, data->sensor_id,
+                                       data->ti_thermal->polling_delay);
 
        return 0;
 }
index 47c6e7b9e150fe4c579459915e8bd4bf85e64b33..febd45cd50273532e99c1a4d790d2690c6ae750d 100644 (file)
@@ -5,7 +5,7 @@
 if TTY
 
 menu "Serial drivers"
-       depends on HAS_IOMEM && GENERIC_HARDIRQS
+       depends on HAS_IOMEM
 
 source "drivers/tty/serial/8250/Kconfig"
 
index a9355ce1c6d586cef3c9cd62641a141bfa91c245..3a1a01af9a805b38b05f1833eefa80400072f4f4 100644 (file)
@@ -854,7 +854,8 @@ void disassociate_ctty(int on_exit)
                        struct pid *tty_pgrp = tty_get_pgrp(tty);
                        if (tty_pgrp) {
                                kill_pgrp(tty_pgrp, SIGHUP, on_exit);
-                               kill_pgrp(tty_pgrp, SIGCONT, on_exit);
+                               if (!on_exit)
+                                       kill_pgrp(tty_pgrp, SIGCONT, on_exit);
                                put_pid(tty_pgrp);
                        }
                }
index f969ea266acb854850d151c06294f29c330ca793..b870872e020f1e0bd8e93c157b76d145bc2b2122 100644 (file)
@@ -1,6 +1,6 @@
 config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
-       depends on (USB || USB_GADGET) && GENERIC_HARDIRQS && HAS_DMA
+       depends on (USB || USB_GADGET) && HAS_DMA
        depends on EXTCON
        select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD
        help
index 30e2dd8a1f2c42c87ed16aedf1d7f3bb9cefa104..48cddf3cd6b889b420d45da418e852ecd671d2c5 100644 (file)
@@ -313,7 +313,7 @@ config USB_S3C_HSUDC
 
 config USB_MV_UDC
        tristate "Marvell USB2.0 Device Controller"
-       depends on GENERIC_HARDIRQS && HAS_DMA
+       depends on HAS_DMA
        help
          Marvell Socs (including PXA and MMP series) include a high speed
          USB2.0 OTG controller, which can be configured as high speed or
@@ -425,7 +425,7 @@ config USB_GOKU
 
 config USB_EG20T
        tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
-       depends on PCI && GENERIC_HARDIRQS
+       depends on PCI
        help
          This is a USB device driver for EG20T PCH.
          EG20T PCH is the platform controller hub that is used in Intel's
index 465ef8e2cc910e04ffd5194fddbf3b14391887c0..b94c049ab0d0877762a5d76e1cac957eff34771f 100644 (file)
@@ -524,7 +524,7 @@ struct kiocb_priv {
        unsigned                actual;
 };
 
-static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
+static int ep_aio_cancel(struct kiocb *iocb)
 {
        struct kiocb_priv       *priv = iocb->private;
        struct ep_data          *epdata;
@@ -540,7 +540,6 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
        // spin_unlock(&epdata->dev->lock);
        local_irq_enable();
 
-       aio_put_req(iocb);
        return value;
 }
 
@@ -709,11 +708,11 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
        if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
                return -EINVAL;
 
-       buf = kmalloc(iocb->ki_left, GFP_KERNEL);
+       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
        if (unlikely(!buf))
                return -ENOMEM;
 
-       return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
+       return ep_aio_rwtail(iocb, buf, iocb->ki_nbytes, epdata, iov, nr_segs);
 }
 
 static ssize_t
@@ -728,7 +727,7 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
        if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
                return -EINVAL;
 
-       buf = kmalloc(iocb->ki_left, GFP_KERNEL);
+       buf = kmalloc(iocb->ki_nbytes, GFP_KERNEL);
        if (unlikely(!buf))
                return -ENOMEM;
 
index 5be0326aae38f602fd41a15a2c52a3d40db0ebbc..b3f20d7f15dee9554ef9ef96acd735c3e3926064 100644 (file)
@@ -278,7 +278,6 @@ endif # USB_EHCI_HCD
 
 config USB_OXU210HP_HCD
        tristate "OXU210HP HCD support"
-       depends on GENERIC_HARDIRQS
        ---help---
          The OXU210HP is an USB host/OTG/device controller. Enable this
          option if your board has this chip. If unsure, say N.
index c64ee09a7c0e30ad4f36cde52e1dce98e4d128b4..c258a97ef1b0050f41e02d0a8e08b0052af488e7 100644 (file)
@@ -71,7 +71,6 @@ config USB_MUSB_DA8XX
 
 config USB_MUSB_TUSB6010
        tristate "TUSB6010"
-       depends on GENERIC_HARDIRQS
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
index 019bf7e49ee6b1d2d64055326fdbf54589ff8b4f..1c4195abc1080295dcd145eb2519cc99b28f3c22 100644 (file)
@@ -4,7 +4,7 @@
 
 config USB_RENESAS_USBHS
        tristate 'Renesas USBHS controller'
-       depends on USB_GADGET && GENERIC_HARDIRQS
+       depends on USB_GADGET
        default n
        help
          Renesas USBHS is a discrete USB host and peripheral controller chip
index cef6002acbd49aa078568fe2fe9ea4511230e861..6ab71b9fcf8d692dcb9891d05ab02c2f153d72ef 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/device.h>
 #include <linux/eventfd.h>
+#include <linux/file.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
 #include <linux/module.h>
@@ -227,6 +228,110 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
        return 0;
 }
 
+static int vfio_pci_count_devs(struct pci_dev *pdev, void *data)
+{
+       (*(int *)data)++;
+       return 0;
+}
+
+struct vfio_pci_fill_info {
+       int max;
+       int cur;
+       struct vfio_pci_dependent_device *devices;
+};
+
+static int vfio_pci_fill_devs(struct pci_dev *pdev, void *data)
+{
+       struct vfio_pci_fill_info *fill = data;
+       struct iommu_group *iommu_group;
+
+       if (fill->cur == fill->max)
+               return -EAGAIN; /* Something changed, try again */
+
+       iommu_group = iommu_group_get(&pdev->dev);
+       if (!iommu_group)
+               return -EPERM; /* Cannot reset non-isolated devices */
+
+       fill->devices[fill->cur].group_id = iommu_group_id(iommu_group);
+       fill->devices[fill->cur].segment = pci_domain_nr(pdev->bus);
+       fill->devices[fill->cur].bus = pdev->bus->number;
+       fill->devices[fill->cur].devfn = pdev->devfn;
+       fill->cur++;
+       iommu_group_put(iommu_group);
+       return 0;
+}
+
+struct vfio_pci_group_entry {
+       struct vfio_group *group;
+       int id;
+};
+
+struct vfio_pci_group_info {
+       int count;
+       struct vfio_pci_group_entry *groups;
+};
+
+static int vfio_pci_validate_devs(struct pci_dev *pdev, void *data)
+{
+       struct vfio_pci_group_info *info = data;
+       struct iommu_group *group;
+       int id, i;
+
+       group = iommu_group_get(&pdev->dev);
+       if (!group)
+               return -EPERM;
+
+       id = iommu_group_id(group);
+
+       for (i = 0; i < info->count; i++)
+               if (info->groups[i].id == id)
+                       break;
+
+       iommu_group_put(group);
+
+       return (i == info->count) ? -EINVAL : 0;
+}
+
+static bool vfio_pci_dev_below_slot(struct pci_dev *pdev, struct pci_slot *slot)
+{
+       for (; pdev; pdev = pdev->bus->self)
+               if (pdev->bus == slot->bus)
+                       return (pdev->slot == slot);
+       return false;
+}
+
+struct vfio_pci_walk_info {
+       int (*fn)(struct pci_dev *, void *data);
+       void *data;
+       struct pci_dev *pdev;
+       bool slot;
+       int ret;
+};
+
+static int vfio_pci_walk_wrapper(struct pci_dev *pdev, void *data)
+{
+       struct vfio_pci_walk_info *walk = data;
+
+       if (!walk->slot || vfio_pci_dev_below_slot(pdev, walk->pdev->slot))
+               walk->ret = walk->fn(pdev, walk->data);
+
+       return walk->ret;
+}
+
+static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev,
+                                        int (*fn)(struct pci_dev *,
+                                                  void *data), void *data,
+                                        bool slot)
+{
+       struct vfio_pci_walk_info walk = {
+               .fn = fn, .data = data, .pdev = pdev, .slot = slot, .ret = 0,
+       };
+
+       pci_walk_bus(pdev->bus, vfio_pci_walk_wrapper, &walk);
+
+       return walk.ret;
+}
+
 static long vfio_pci_ioctl(void *device_data,
                           unsigned int cmd, unsigned long arg)
 {
@@ -407,10 +512,189 @@ static long vfio_pci_ioctl(void *device_data,
 
                return ret;
 
-       } else if (cmd == VFIO_DEVICE_RESET)
+       } else if (cmd == VFIO_DEVICE_RESET) {
                return vdev->reset_works ?
                        pci_reset_function(vdev->pdev) : -EINVAL;
 
+       } else if (cmd == VFIO_DEVICE_GET_PCI_HOT_RESET_INFO) {
+               struct vfio_pci_hot_reset_info hdr;
+               struct vfio_pci_fill_info fill = { 0 };
+               struct vfio_pci_dependent_device *devices = NULL;
+               bool slot = false;
+               int ret = 0;
+
+               minsz = offsetofend(struct vfio_pci_hot_reset_info, count);
+
+               if (copy_from_user(&hdr, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (hdr.argsz < minsz)
+                       return -EINVAL;
+
+               hdr.flags = 0;
+
+               /* Can we do a slot or bus reset or neither? */
+               if (!pci_probe_reset_slot(vdev->pdev->slot))
+                       slot = true;
+               else if (pci_probe_reset_bus(vdev->pdev->bus))
+                       return -ENODEV;
+
+               /* How many devices are affected? */
+               ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
+                                                   vfio_pci_count_devs,
+                                                   &fill.max, slot);
+               if (ret)
+                       return ret;
+
+               WARN_ON(!fill.max); /* Should always be at least one */
+
+               /*
+                * If there's enough space, fill it now, otherwise return
+                * -ENOSPC and the number of devices affected.
+                */
+               if (hdr.argsz < sizeof(hdr) + (fill.max * sizeof(*devices))) {
+                       ret = -ENOSPC;
+                       hdr.count = fill.max;
+                       goto reset_info_exit;
+               }
+
+               devices = kcalloc(fill.max, sizeof(*devices), GFP_KERNEL);
+               if (!devices)
+                       return -ENOMEM;
+
+               fill.devices = devices;
+
+               ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
+                                                   vfio_pci_fill_devs,
+                                                   &fill, slot);
+
+               /*
+                * If a device was removed between counting and filling,
+                * we may come up short of fill.max.  If a device was
+                * added, we'll have a return of -EAGAIN above.
+                */
+               if (!ret)
+                       hdr.count = fill.cur;
+
+reset_info_exit:
+               if (copy_to_user((void __user *)arg, &hdr, minsz))
+                       ret = -EFAULT;
+
+               if (!ret) {
+                       if (copy_to_user((void __user *)(arg + minsz), devices,
+                                        hdr.count * sizeof(*devices)))
+                               ret = -EFAULT;
+               }
+
+               kfree(devices);
+               return ret;
+
+       } else if (cmd == VFIO_DEVICE_PCI_HOT_RESET) {
+               struct vfio_pci_hot_reset hdr;
+               int32_t *group_fds;
+               struct vfio_pci_group_entry *groups;
+               struct vfio_pci_group_info info;
+               bool slot = false;
+               int i, count = 0, ret = 0;
+
+               minsz = offsetofend(struct vfio_pci_hot_reset, count);
+
+               if (copy_from_user(&hdr, (void __user *)arg, minsz))
+                       return -EFAULT;
+
+               if (hdr.argsz < minsz || hdr.flags)
+                       return -EINVAL;
+
+               /* Can we do a slot or bus reset or neither? */
+               if (!pci_probe_reset_slot(vdev->pdev->slot))
+                       slot = true;
+               else if (pci_probe_reset_bus(vdev->pdev->bus))
+                       return -ENODEV;
+
+               /*
+                * We can't let userspace give us an arbitrarily large
+                * buffer to copy, so verify how many we think there
+                * could be.  Note groups can have multiple devices so
+                * one group per device is the max.
+                */
+               ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
+                                                   vfio_pci_count_devs,
+                                                   &count, slot);
+               if (ret)
+                       return ret;
+
+               /* Somewhere between 1 and count is OK */
+               if (!hdr.count || hdr.count > count)
+                       return -EINVAL;
+
+               group_fds = kcalloc(hdr.count, sizeof(*group_fds), GFP_KERNEL);
+               groups = kcalloc(hdr.count, sizeof(*groups), GFP_KERNEL);
+               if (!group_fds || !groups) {
+                       kfree(group_fds);
+                       kfree(groups);
+                       return -ENOMEM;
+               }
+
+               if (copy_from_user(group_fds, (void __user *)(arg + minsz),
+                                  hdr.count * sizeof(*group_fds))) {
+                       kfree(group_fds);
+                       kfree(groups);
+                       return -EFAULT;
+               }
+
+               /*
+                * For each group_fd, get the group through the vfio external
+                * user interface and store the group and iommu ID.  This
+                * ensures the group is held across the reset.
+                */
+               for (i = 0; i < hdr.count; i++) {
+                       struct vfio_group *group;
+                       struct fd f = fdget(group_fds[i]);
+                       if (!f.file) {
+                               ret = -EBADF;
+                               break;
+                       }
+
+                       group = vfio_group_get_external_user(f.file);
+                       fdput(f);
+                       if (IS_ERR(group)) {
+                               ret = PTR_ERR(group);
+                               break;
+                       }
+
+                       groups[i].group = group;
+                       groups[i].id = vfio_external_user_iommu_id(group);
+               }
+
+               kfree(group_fds);
+
+               /* release reference to groups on error */
+               if (ret)
+                       goto hot_reset_release;
+
+               info.count = hdr.count;
+               info.groups = groups;
+
+               /*
+                * Test whether all the affected devices are contained
+                * by the set of groups provided by the user.
+                */
+               ret = vfio_pci_for_each_slot_or_bus(vdev->pdev,
+                                                   vfio_pci_validate_devs,
+                                                   &info, slot);
+               if (!ret)
+                       /* User has access, do the reset */
+                       ret = slot ? pci_reset_slot(vdev->pdev->slot) :
+                                    pci_reset_bus(vdev->pdev->bus);
+
+hot_reset_release:
+               for (i--; i >= 0; i--)
+                       vfio_group_put_external_user(groups[i].group);
+
+               kfree(groups);
+               return ret;
+       }
+
        return -ENOTTY;
 }
 
index affa34745be92bdfe16e83ebb81ee4073c002729..ffd0632c3cbcbf78e1eac6d241eefae57021319f 100644 (file)
@@ -1012,6 +1012,7 @@ static int vfio_vc_cap_len(struct vfio_pci_device *vdev, u16 pos)
 static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
 {
        struct pci_dev *pdev = vdev->pdev;
+       u32 dword;
        u16 word;
        u8 byte;
        int ret;
@@ -1025,7 +1026,9 @@ static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
                        return pcibios_err_to_errno(ret);
 
                if (PCI_X_CMD_VERSION(word)) {
-                       vdev->extended_caps = true;
+                       /* Test for extended capabilities */
+                       pci_read_config_dword(pdev, PCI_CFG_SPACE_SIZE, &dword);
+                       vdev->extended_caps = (dword != 0);
                        return PCI_CAP_PCIX_SIZEOF_V2;
                } else
                        return PCI_CAP_PCIX_SIZEOF_V0;
@@ -1037,9 +1040,11 @@ static int vfio_cap_len(struct vfio_pci_device *vdev, u8 cap, u8 pos)
 
                return byte;
        case PCI_CAP_ID_EXP:
-               /* length based on version */
-               vdev->extended_caps = true;
+               /* Test for extended capabilities */
+               pci_read_config_dword(pdev, PCI_CFG_SPACE_SIZE, &dword);
+               vdev->extended_caps = (dword != 0);
 
+               /* length based on version */
                if ((pcie_caps_reg(pdev) & PCI_EXP_FLAGS_VERS) == 1)
                        return PCI_CAP_EXP_ENDPOINT_SIZEOF_V1;
                else
index 4bc704e1b7c725d59cdcf7e754a63493f861b01b..641bc87bdb96aa23500c48483c81defbf0088026 100644 (file)
@@ -130,8 +130,8 @@ static int virqfd_enable(struct vfio_pci_device *vdev,
                         void (*thread)(struct vfio_pci_device *, void *),
                         void *data, struct virqfd **pvirqfd, int fd)
 {
-       struct file *file = NULL;
-       struct eventfd_ctx *ctx = NULL;
+       struct fd irqfd;
+       struct eventfd_ctx *ctx;
        struct virqfd *virqfd;
        int ret = 0;
        unsigned int events;
@@ -149,16 +149,16 @@ static int virqfd_enable(struct vfio_pci_device *vdev,
        INIT_WORK(&virqfd->shutdown, virqfd_shutdown);
        INIT_WORK(&virqfd->inject, virqfd_inject);
 
-       file = eventfd_fget(fd);
-       if (IS_ERR(file)) {
-               ret = PTR_ERR(file);
-               goto fail;
+       irqfd = fdget(fd);
+       if (!irqfd.file) {
+               ret = -EBADF;
+               goto err_fd;
        }
 
-       ctx = eventfd_ctx_fileget(file);
+       ctx = eventfd_ctx_fileget(irqfd.file);
        if (IS_ERR(ctx)) {
                ret = PTR_ERR(ctx);
-               goto fail;
+               goto err_ctx;
        }
 
        virqfd->eventfd = ctx;
@@ -174,7 +174,7 @@ static int virqfd_enable(struct vfio_pci_device *vdev,
        if (*pvirqfd) {
                spin_unlock_irq(&vdev->irqlock);
                ret = -EBUSY;
-               goto fail;
+               goto err_busy;
        }
        *pvirqfd = virqfd;
 
@@ -187,7 +187,7 @@ static int virqfd_enable(struct vfio_pci_device *vdev,
        init_waitqueue_func_entry(&virqfd->wait, virqfd_wakeup);
        init_poll_funcptr(&virqfd->pt, virqfd_ptable_queue_proc);
 
-       events = file->f_op->poll(file, &virqfd->pt);
+       events = irqfd.file->f_op->poll(irqfd.file, &virqfd->pt);
 
        /*
         * Check if there was an event already pending on the eventfd
@@ -202,17 +202,14 @@ static int virqfd_enable(struct vfio_pci_device *vdev,
         * Do not drop the file until the irqfd is fully initialized,
         * otherwise we might race against the POLLHUP.
         */
-       fput(file);
+       fdput(irqfd);
 
        return 0;
-
-fail:
-       if (ctx && !IS_ERR(ctx))
-               eventfd_ctx_put(ctx);
-
-       if (file && !IS_ERR(file))
-               fput(file);
-
+err_busy:
+       eventfd_ctx_put(ctx);
+err_ctx:
+       fdput(irqfd);
+err_fd:
        kfree(virqfd);
 
        return ret;
index 842f4507883e1b1d10c99d343e35e450abf56db0..1eab4ace06718ac38574414d11de280755de6334 100644 (file)
@@ -1109,7 +1109,7 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
                 * We can't use anon_inode_getfd() because we need to modify
                 * the f_mode flags directly to allow more than just ioctls
                 */
-               ret = get_unused_fd();
+               ret = get_unused_fd_flags(O_CLOEXEC);
                if (ret < 0) {
                        device->ops->release(device->device_data);
                        break;
@@ -1352,6 +1352,68 @@ static const struct file_operations vfio_device_fops = {
        .mmap           = vfio_device_fops_mmap,
 };
 
+/**
+ * External user API, exported by symbols to be linked dynamically.
+ *
+ * The protocol includes:
+ *  1. do normal VFIO init operation:
+ *     - opening a new container;
+ *     - attaching group(s) to it;
+ *     - setting an IOMMU driver for a container.
+ * When IOMMU is set for a container, all groups in it are
+ * considered ready to use by an external user.
+ *
+ * 2. User space passes a group fd to an external user.
+ * The external user calls vfio_group_get_external_user()
+ * to verify that:
+ *     - the group is initialized;
+ *     - IOMMU is set for it.
+ * If both checks passed, vfio_group_get_external_user()
+ * increments the container user counter to prevent
+ * the VFIO group from disposal before KVM exits.
+ *
+ * 3. The external user calls vfio_external_user_iommu_id()
+ * to know an IOMMU ID.
+ *
+ * 4. When the external KVM finishes, it calls
+ * vfio_group_put_external_user() to release the VFIO group.
+ * This call decrements the container user counter.
+ */
+struct vfio_group *vfio_group_get_external_user(struct file *filep)
+{
+       struct vfio_group *group = filep->private_data;
+
+       if (filep->f_op != &vfio_group_fops)
+               return ERR_PTR(-EINVAL);
+
+       if (!atomic_inc_not_zero(&group->container_users))
+               return ERR_PTR(-EINVAL);
+
+       if (!group->container->iommu_driver ||
+                       !vfio_group_viable(group)) {
+               atomic_dec(&group->container_users);
+               return ERR_PTR(-EINVAL);
+       }
+
+       vfio_group_get(group);
+
+       return group;
+}
+EXPORT_SYMBOL_GPL(vfio_group_get_external_user);
+
+void vfio_group_put_external_user(struct vfio_group *group)
+{
+       vfio_group_put(group);
+       vfio_group_try_dissolve_container(group);
+}
+EXPORT_SYMBOL_GPL(vfio_group_put_external_user);
+
+int vfio_external_user_iommu_id(struct vfio_group *group)
+{
+       return iommu_group_id(group->iommu_group);
+}
+EXPORT_SYMBOL_GPL(vfio_external_user_iommu_id);
+
 /**
  * Module/class support
  */
index 0c27c7df1b093e6ad64292a5211387a3103543e2..4b79a1f2f901e86eb7726fd64d1af3bac66e7385 100644 (file)
@@ -1,12 +1,12 @@
 /*******************************************************************************
  * Vhost kernel TCM fabric driver for virtio SCSI initiators
  *
- * (C) Copyright 2010-2012 RisingTide Systems LLC.
+ * (C) Copyright 2010-2013 Datera, Inc.
  * (C) Copyright 2010-2012 IBM Corp.
  *
  * Licensed to the Linux Foundation under the General Public License (GPL) version 2.
  *
- * Authors: Nicholas A. Bellinger <nab@risingtidesystems.com>
+ * Authors: Nicholas A. Bellinger <nab@daterainc.com>
  *          Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
  *
  * This program is free software; you can redistribute it and/or modify
 #include <linux/virtio_scsi.h>
 #include <linux/llist.h>
 #include <linux/bitmap.h>
+#include <linux/percpu_ida.h>
 
 #include "vhost.h"
 
 #define TCM_VHOST_VERSION  "v0.1"
 #define TCM_VHOST_NAMELEN 256
 #define TCM_VHOST_MAX_CDB_SIZE 32
+#define TCM_VHOST_DEFAULT_TAGS 256
+#define TCM_VHOST_PREALLOC_SGLS 2048
+#define TCM_VHOST_PREALLOC_PAGES 2048
 
 struct vhost_scsi_inflight {
        /* Wait for the flush operation to finish */
@@ -79,6 +83,7 @@ struct tcm_vhost_cmd {
        u32 tvc_lun;
        /* Pointer to the SGL formatted memory from virtio-scsi */
        struct scatterlist *tvc_sgl;
+       struct page **tvc_upages;
        /* Pointer to response */
        struct virtio_scsi_cmd_resp __user *tvc_resp;
        /* Pointer to vhost_scsi for our device */
@@ -450,17 +455,16 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
 {
        struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
                                struct tcm_vhost_cmd, tvc_se_cmd);
+       struct se_session *se_sess = se_cmd->se_sess;
 
        if (tv_cmd->tvc_sgl_count) {
                u32 i;
                for (i = 0; i < tv_cmd->tvc_sgl_count; i++)
                        put_page(sg_page(&tv_cmd->tvc_sgl[i]));
-
-               kfree(tv_cmd->tvc_sgl);
         }
 
        tcm_vhost_put_inflight(tv_cmd->inflight);
-       kfree(tv_cmd);
+       percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
 }
 
 static int tcm_vhost_shutdown_session(struct se_session *se_sess)
@@ -704,7 +708,7 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
 }
 
 static struct tcm_vhost_cmd *
-vhost_scsi_allocate_cmd(struct vhost_virtqueue *vq,
+vhost_scsi_get_tag(struct vhost_virtqueue *vq,
                        struct tcm_vhost_tpg *tpg,
                        struct virtio_scsi_cmd_req *v_req,
                        u32 exp_data_len,
@@ -712,18 +716,27 @@ vhost_scsi_allocate_cmd(struct vhost_virtqueue *vq,
 {
        struct tcm_vhost_cmd *cmd;
        struct tcm_vhost_nexus *tv_nexus;
+       struct se_session *se_sess;
+       struct scatterlist *sg;
+       struct page **pages;
+       int tag;
 
        tv_nexus = tpg->tpg_nexus;
        if (!tv_nexus) {
                pr_err("Unable to locate active struct tcm_vhost_nexus\n");
                return ERR_PTR(-EIO);
        }
+       se_sess = tv_nexus->tvn_se_sess;
 
-       cmd = kzalloc(sizeof(struct tcm_vhost_cmd), GFP_ATOMIC);
-       if (!cmd) {
-               pr_err("Unable to allocate struct tcm_vhost_cmd\n");
-               return ERR_PTR(-ENOMEM);
-       }
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_KERNEL);
+       cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
+       sg = cmd->tvc_sgl;
+       pages = cmd->tvc_upages;
+       memset(cmd, 0, sizeof(struct tcm_vhost_cmd));
+
+       cmd->tvc_sgl = sg;
+       cmd->tvc_upages = pages;
+       cmd->tvc_se_cmd.map_tag = tag;
        cmd->tvc_tag = v_req->tag;
        cmd->tvc_task_attr = v_req->task_attr;
        cmd->tvc_exp_data_len = exp_data_len;
@@ -740,7 +753,8 @@ vhost_scsi_allocate_cmd(struct vhost_virtqueue *vq,
  * Returns the number of scatterlist entries used or -errno on error.
  */
 static int
-vhost_scsi_map_to_sgl(struct scatterlist *sgl,
+vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd,
+                     struct scatterlist *sgl,
                      unsigned int sgl_count,
                      struct iovec *iov,
                      int write)
@@ -752,13 +766,25 @@ vhost_scsi_map_to_sgl(struct scatterlist *sgl,
        struct page **pages;
        int ret, i;
 
+       if (sgl_count > TCM_VHOST_PREALLOC_SGLS) {
+               pr_err("vhost_scsi_map_to_sgl() psgl_count: %u greater than"
+                      " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n",
+                       sgl_count, TCM_VHOST_PREALLOC_SGLS);
+               return -ENOBUFS;
+       }
+
        pages_nr = iov_num_pages(iov);
        if (pages_nr > sgl_count)
                return -ENOBUFS;
 
-       pages = kmalloc(pages_nr * sizeof(struct page *), GFP_KERNEL);
-       if (!pages)
-               return -ENOMEM;
+       if (pages_nr > TCM_VHOST_PREALLOC_PAGES) {
+               pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
+                      " preallocated TCM_VHOST_PREALLOC_PAGES: %u\n",
+                       pages_nr, TCM_VHOST_PREALLOC_PAGES);
+               return -ENOBUFS;
+       }
+
+       pages = tv_cmd->tvc_upages;
 
        ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages);
        /* No pages were pinned */
@@ -783,7 +809,6 @@ vhost_scsi_map_to_sgl(struct scatterlist *sgl,
        }
 
 out:
-       kfree(pages);
        return ret;
 }
 
@@ -807,24 +832,20 @@ vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
 
        /* TODO overflow checking */
 
-       sg = kmalloc(sizeof(cmd->tvc_sgl[0]) * sgl_count, GFP_ATOMIC);
-       if (!sg)
-               return -ENOMEM;
-       pr_debug("%s sg %p sgl_count %u is_err %d\n", __func__,
-              sg, sgl_count, !sg);
+       sg = cmd->tvc_sgl;
+       pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count);
        sg_init_table(sg, sgl_count);
 
-       cmd->tvc_sgl = sg;
        cmd->tvc_sgl_count = sgl_count;
 
        pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count);
        for (i = 0; i < niov; i++) {
-               ret = vhost_scsi_map_to_sgl(sg, sgl_count, &iov[i], write);
+               ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i],
+                                           write);
                if (ret < 0) {
                        for (i = 0; i < cmd->tvc_sgl_count; i++)
                                put_page(sg_page(&cmd->tvc_sgl[i]));
-                       kfree(cmd->tvc_sgl);
-                       cmd->tvc_sgl = NULL;
+
                        cmd->tvc_sgl_count = 0;
                        return ret;
                }
@@ -989,10 +1010,10 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
                for (i = 0; i < data_num; i++)
                        exp_data_len += vq->iov[data_first + i].iov_len;
 
-               cmd = vhost_scsi_allocate_cmd(vq, tpg, &v_req,
-                                       exp_data_len, data_direction);
+               cmd = vhost_scsi_get_tag(vq, tpg, &v_req,
+                                        exp_data_len, data_direction);
                if (IS_ERR(cmd)) {
-                       vq_err(vq, "vhost_scsi_allocate_cmd failed %ld\n",
+                       vq_err(vq, "vhost_scsi_get_tag failed %ld\n",
                                        PTR_ERR(cmd));
                        goto err_cmd;
                }
@@ -1654,11 +1675,31 @@ static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
        kfree(nacl);
 }
 
+static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus,
+                                      struct se_session *se_sess)
+{
+       struct tcm_vhost_cmd *tv_cmd;
+       unsigned int i;
+
+       if (!se_sess->sess_cmd_map)
+               return;
+
+       for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
+               tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
+
+               kfree(tv_cmd->tvc_sgl);
+               kfree(tv_cmd->tvc_upages);
+       }
+}
+
 static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
                                const char *name)
 {
        struct se_portal_group *se_tpg;
+       struct se_session *se_sess;
        struct tcm_vhost_nexus *tv_nexus;
+       struct tcm_vhost_cmd *tv_cmd;
+       unsigned int i;
 
        mutex_lock(&tpg->tv_tpg_mutex);
        if (tpg->tpg_nexus) {
@@ -1675,14 +1716,37 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
                return -ENOMEM;
        }
        /*
-        *  Initialize the struct se_session pointer
+        *  Initialize the struct se_session pointer and setup tagpool
+        *  for struct tcm_vhost_cmd descriptors
         */
-       tv_nexus->tvn_se_sess = transport_init_session();
+       tv_nexus->tvn_se_sess = transport_init_session_tags(
+                                       TCM_VHOST_DEFAULT_TAGS,
+                                       sizeof(struct tcm_vhost_cmd));
        if (IS_ERR(tv_nexus->tvn_se_sess)) {
                mutex_unlock(&tpg->tv_tpg_mutex);
                kfree(tv_nexus);
                return -ENOMEM;
        }
+       se_sess = tv_nexus->tvn_se_sess;
+       for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
+               tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
+
+               tv_cmd->tvc_sgl = kzalloc(sizeof(struct scatterlist) *
+                                       TCM_VHOST_PREALLOC_SGLS, GFP_KERNEL);
+               if (!tv_cmd->tvc_sgl) {
+                       mutex_unlock(&tpg->tv_tpg_mutex);
+                       pr_err("Unable to allocate tv_cmd->tvc_sgl\n");
+                       goto out;
+               }
+
+               tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) *
+                                       TCM_VHOST_PREALLOC_PAGES, GFP_KERNEL);
+               if (!tv_cmd->tvc_upages) {
+                       mutex_unlock(&tpg->tv_tpg_mutex);
+                       pr_err("Unable to allocate tv_cmd->tvc_upages\n");
+                       goto out;
+               }
+       }
        /*
         * Since we are running in 'demo mode' this call with generate a
         * struct se_node_acl for the tcm_vhost struct se_portal_group with
@@ -1694,9 +1758,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
                mutex_unlock(&tpg->tv_tpg_mutex);
                pr_debug("core_tpg_check_initiator_node_acl() failed"
                                " for %s\n", name);
-               transport_free_session(tv_nexus->tvn_se_sess);
-               kfree(tv_nexus);
-               return -ENOMEM;
+               goto out;
        }
        /*
         * Now register the TCM vhost virtual I_T Nexus as active with the
@@ -1708,6 +1770,12 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
 
        mutex_unlock(&tpg->tv_tpg_mutex);
        return 0;
+
+out:
+       tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
+       transport_free_session(se_sess);
+       kfree(tv_nexus);
+       return -ENOMEM;
 }
 
 static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
@@ -1747,6 +1815,8 @@ static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
        pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
                " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport),
                tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
+
+       tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
        /*
         * Release the SCSI I_T Nexus to the emulated vhost Target Port
         */
index 6488a7351a6055adbe1c80c6cdc68390aa4c4d25..7e8346ec9cdc32f1a04e0c493e4d859d71efa189 100644 (file)
 
 #include "acornfb.h"
 
-/*
- * VIDC machines can't do 16 or 32BPP modes.
- */
-#ifdef HAS_VIDC
-#undef FBCON_HAS_CFB16
-#undef FBCON_HAS_CFB32
-#endif
-
 /*
  * Default resolution.
  * NOTE that it has to be supported in the table towards
@@ -106,238 +98,6 @@ static struct vidc_timing current_vidc;
 
 extern unsigned int vram_size; /* set by setup.c */
 
-#ifdef HAS_VIDC
-
-#define MAX_SIZE       480*1024
-
-/* CTL     VIDC        Actual
- * 24.000  0    8.000
- * 25.175  0    8.392
- * 36.000  0   12.000
- * 24.000  1   12.000
- * 25.175  1   12.588
- * 24.000  2   16.000
- * 25.175  2   16.783
- * 36.000  1   18.000
- * 24.000  3   24.000
- * 36.000  2   24.000
- * 25.175  3   25.175
- * 36.000  3   36.000
- */
-struct pixclock {
-       u_long  min_clock;
-       u_long  max_clock;
-       u_int   vidc_ctl;
-       u_int   vid_ctl;
-};
-
-static struct pixclock arc_clocks[] = {
-       /* we allow +/-1% on these */
-       { 123750, 126250, VIDC_CTRL_DIV3,   VID_CTL_24MHz },    /*  8.000MHz */
-       {  82500,  84167, VIDC_CTRL_DIV2,   VID_CTL_24MHz },    /* 12.000MHz */
-       {  61875,  63125, VIDC_CTRL_DIV1_5, VID_CTL_24MHz },    /* 16.000MHz */
-       {  41250,  42083, VIDC_CTRL_DIV1,   VID_CTL_24MHz },    /* 24.000MHz */
-};
-
-static struct pixclock *
-acornfb_valid_pixrate(struct fb_var_screeninfo *var)
-{
-       u_long pixclock = var->pixclock;
-       u_int i;
-
-       if (!var->pixclock)
-               return NULL;
-
-       for (i = 0; i < ARRAY_SIZE(arc_clocks); i++)
-               if (pixclock > arc_clocks[i].min_clock &&
-                   pixclock < arc_clocks[i].max_clock)
-                       return arc_clocks + i;
-
-       return NULL;
-}
-
-/* VIDC Rules:
- * hcr  : must be even (interlace, hcr/2 must be even)
- * hswr : must be even
- * hdsr : must be odd
- * hder : must be odd
- *
- * vcr  : must be odd
- * vswr : >= 1
- * vdsr : >= 1
- * vder : >= vdsr
- * if interlaced, then hcr/2 must be even
- */
-static void
-acornfb_set_timing(struct fb_var_screeninfo *var)
-{
-       struct pixclock *pclk;
-       struct vidc_timing vidc;
-       u_int horiz_correction;
-       u_int sync_len, display_start, display_end, cycle;
-       u_int is_interlaced;
-       u_int vid_ctl, vidc_ctl;
-       u_int bandwidth;
-
-       memset(&vidc, 0, sizeof(vidc));
-
-       pclk = acornfb_valid_pixrate(var);
-       vidc_ctl = pclk->vidc_ctl;
-       vid_ctl  = pclk->vid_ctl;
-
-       bandwidth = var->pixclock * 8 / var->bits_per_pixel;
-       /* 25.175, 4bpp = 79.444ns per byte, 317.776ns per word: fifo = 2,6 */
-       if (bandwidth > 143500)
-               vidc_ctl |= VIDC_CTRL_FIFO_3_7;
-       else if (bandwidth > 71750)
-               vidc_ctl |= VIDC_CTRL_FIFO_2_6;
-       else if (bandwidth > 35875)
-               vidc_ctl |= VIDC_CTRL_FIFO_1_5;
-       else
-               vidc_ctl |= VIDC_CTRL_FIFO_0_4;
-
-       switch (var->bits_per_pixel) {
-       case 1:
-               horiz_correction = 19;
-               vidc_ctl |= VIDC_CTRL_1BPP;
-               break;
-
-       case 2:
-               horiz_correction = 11;
-               vidc_ctl |= VIDC_CTRL_2BPP;
-               break;
-
-       case 4:
-               horiz_correction = 7;
-               vidc_ctl |= VIDC_CTRL_4BPP;
-               break;
-
-       default:
-       case 8:
-               horiz_correction = 5;
-               vidc_ctl |= VIDC_CTRL_8BPP;
-               break;
-       }
-
-       if (var->sync & FB_SYNC_COMP_HIGH_ACT) /* should be FB_SYNC_COMP */
-               vidc_ctl |= VIDC_CTRL_CSYNC;
-       else {
-               if (!(var->sync & FB_SYNC_HOR_HIGH_ACT))
-                       vid_ctl |= VID_CTL_HS_NHSYNC;
-
-               if (!(var->sync & FB_SYNC_VERT_HIGH_ACT))
-                       vid_ctl |= VID_CTL_VS_NVSYNC;
-       }
-
-       sync_len        = var->hsync_len;
-       display_start   = sync_len + var->left_margin;
-       display_end     = display_start + var->xres;
-       cycle           = display_end + var->right_margin;
-
-       /* if interlaced, then hcr/2 must be even */
-       is_interlaced = (var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED;
-
-       if (is_interlaced) {
-               vidc_ctl |= VIDC_CTRL_INTERLACE;
-               if (cycle & 2) {
-                       cycle += 2;
-                       var->right_margin += 2;
-               }
-       }
-
-       vidc.h_cycle            = (cycle - 2) / 2;
-       vidc.h_sync_width       = (sync_len - 2) / 2;
-       vidc.h_border_start     = (display_start - 1) / 2;
-       vidc.h_display_start    = (display_start - horiz_correction) / 2;
-       vidc.h_display_end      = (display_end - horiz_correction) / 2;
-       vidc.h_border_end       = (display_end - 1) / 2;
-       vidc.h_interlace        = (vidc.h_cycle + 1) / 2;
-
-       sync_len        = var->vsync_len;
-       display_start   = sync_len + var->upper_margin;
-       display_end     = display_start + var->yres;
-       cycle           = display_end + var->lower_margin;
-
-       if (is_interlaced)
-               cycle = (cycle - 3) / 2;
-       else
-               cycle = cycle - 1;
-
-       vidc.v_cycle            = cycle;
-       vidc.v_sync_width       = sync_len - 1;
-       vidc.v_border_start     = display_start - 1;
-       vidc.v_display_start    = vidc.v_border_start;
-       vidc.v_display_end      = display_end - 1;
-       vidc.v_border_end       = vidc.v_display_end;
-
-       if (machine_is_a5k())
-               __raw_writeb(vid_ctl, IOEB_VID_CTL);
-
-       if (memcmp(&current_vidc, &vidc, sizeof(vidc))) {
-               current_vidc = vidc;
-
-               vidc_writel(0xe0000000 | vidc_ctl);
-               vidc_writel(0x80000000 | (vidc.h_cycle << 14));
-               vidc_writel(0x84000000 | (vidc.h_sync_width << 14));
-               vidc_writel(0x88000000 | (vidc.h_border_start << 14));
-               vidc_writel(0x8c000000 | (vidc.h_display_start << 14));
-               vidc_writel(0x90000000 | (vidc.h_display_end << 14));
-               vidc_writel(0x94000000 | (vidc.h_border_end << 14));
-               vidc_writel(0x98000000);
-               vidc_writel(0x9c000000 | (vidc.h_interlace << 14));
-               vidc_writel(0xa0000000 | (vidc.v_cycle << 14));
-               vidc_writel(0xa4000000 | (vidc.v_sync_width << 14));
-               vidc_writel(0xa8000000 | (vidc.v_border_start << 14));
-               vidc_writel(0xac000000 | (vidc.v_display_start << 14));
-               vidc_writel(0xb0000000 | (vidc.v_display_end << 14));
-               vidc_writel(0xb4000000 | (vidc.v_border_end << 14));
-               vidc_writel(0xb8000000);
-               vidc_writel(0xbc000000);
-       }
-#ifdef DEBUG_MODE_SELECTION
-       printk(KERN_DEBUG "VIDC registers for %dx%dx%d:\n", var->xres,
-              var->yres, var->bits_per_pixel);
-       printk(KERN_DEBUG " H-cycle          : %d\n", vidc.h_cycle);
-       printk(KERN_DEBUG " H-sync-width     : %d\n", vidc.h_sync_width);
-       printk(KERN_DEBUG " H-border-start   : %d\n", vidc.h_border_start);
-       printk(KERN_DEBUG " H-display-start  : %d\n", vidc.h_display_start);
-       printk(KERN_DEBUG " H-display-end    : %d\n", vidc.h_display_end);
-       printk(KERN_DEBUG " H-border-end     : %d\n", vidc.h_border_end);
-       printk(KERN_DEBUG " H-interlace      : %d\n", vidc.h_interlace);
-       printk(KERN_DEBUG " V-cycle          : %d\n", vidc.v_cycle);
-       printk(KERN_DEBUG " V-sync-width     : %d\n", vidc.v_sync_width);
-       printk(KERN_DEBUG " V-border-start   : %d\n", vidc.v_border_start);
-       printk(KERN_DEBUG " V-display-start  : %d\n", vidc.v_display_start);
-       printk(KERN_DEBUG " V-display-end    : %d\n", vidc.v_display_end);
-       printk(KERN_DEBUG " V-border-end     : %d\n", vidc.v_border_end);
-       printk(KERN_DEBUG " VIDC Ctrl (E)    : 0x%08X\n", vidc_ctl);
-       printk(KERN_DEBUG " IOEB Ctrl        : 0x%08X\n", vid_ctl);
-#endif
-}
-
-static int
-acornfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                 u_int trans, struct fb_info *info)
-{
-       union palette pal;
-
-       if (regno >= current_par.palette_size)
-               return 1;
-
-       pal.p = 0;
-       pal.vidc.reg   = regno;
-       pal.vidc.red   = red >> 12;
-       pal.vidc.green = green >> 12;
-       pal.vidc.blue  = blue >> 12;
-
-       current_par.palette[regno] = pal;
-
-       vidc_writel(pal.p);
-
-       return 0;
-}
-#endif
-
 #ifdef HAS_VIDC20
 #include <mach/acornfb.h>
 
@@ -634,16 +394,7 @@ acornfb_adjust_timing(struct fb_info *info, struct fb_var_screeninfo *var, u_int
        /* hsync_len must be even */
        var->hsync_len = (var->hsync_len + 1) & ~1;
 
-#ifdef HAS_VIDC
-       /* left_margin must be odd */
-       if ((var->left_margin & 1) == 0) {
-               var->left_margin -= 1;
-               var->right_margin += 1;
-       }
-
-       /* right_margin must be odd */
-       var->right_margin |= 1;
-#elif defined(HAS_VIDC20)
+#if defined(HAS_VIDC20)
        /* left_margin must be even */
        if (var->left_margin & 1) {
                var->left_margin += 1;
@@ -787,11 +538,7 @@ static int acornfb_set_par(struct fb_info *info)
                break;
        case 8:
                current_par.palette_size = VIDC_PALETTE_SIZE;
-#ifdef HAS_VIDC
-               info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
-#else
                info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
-#endif
                break;
 #ifdef HAS_VIDC20
        case 16:
@@ -971,9 +718,6 @@ static void acornfb_init_fbinfo(void)
 #if defined(HAS_VIDC20)
        fb_info.var.red.length     = 8;
        fb_info.var.transp.length  = 4;
-#elif defined(HAS_VIDC)
-       fb_info.var.red.length     = 4;
-       fb_info.var.transp.length  = 1;
 #endif
        fb_info.var.green          = fb_info.var.red;
        fb_info.var.blue           = fb_info.var.red;
@@ -1310,14 +1054,6 @@ static int acornfb_probe(struct platform_device *dev)
                fb_info.fix.smem_start = handle;
        }
 #endif
-#if defined(HAS_VIDC)
-       /*
-        * Archimedes/A5000 machines use a fixed address for their
-        * framebuffers.  Free unused pages
-        */
-       free_unused_pages(PAGE_OFFSET + size, PAGE_OFFSET + MAX_SIZE);
-#endif
-
        fb_info.fix.smem_len = size;
        current_par.palette_size   = VIDC_PALETTE_SIZE;
 
index fb2a7fffe5063f6a0a96f0640d9cab77b846472d..175c8ff3367ca956d293dee1d069011a1af964c2 100644 (file)
 #include <asm/hardware/iomd.h>
 #define VIDC_PALETTE_SIZE      256
 #define VIDC_NAME              "VIDC20"
-#elif defined(HAS_VIDC)
-#include <asm/hardware/memc.h>
-#define VIDC_PALETTE_SIZE      16
-#define VIDC_NAME              "VIDC"
 #endif
 
 #define EXTEND8(x) ((x)|(x)<<8)
@@ -101,31 +97,6 @@ struct modex_params {
        const struct modey_params *modey;
 };
 
-#ifdef HAS_VIDC
-
-#define VID_CTL_VS_NVSYNC      (1 << 3)
-#define VID_CTL_HS_NHSYNC      (1 << 2)
-#define VID_CTL_24MHz          (0)
-#define VID_CTL_25MHz          (1)
-#define VID_CTL_36MHz          (2)
-
-#define VIDC_CTRL_CSYNC                (1 << 7)
-#define VIDC_CTRL_INTERLACE    (1 << 6)
-#define VIDC_CTRL_FIFO_0_4     (0 << 4)
-#define VIDC_CTRL_FIFO_1_5     (1 << 4)
-#define VIDC_CTRL_FIFO_2_6     (2 << 4)
-#define VIDC_CTRL_FIFO_3_7     (3 << 4)
-#define VIDC_CTRL_1BPP         (0 << 2)
-#define VIDC_CTRL_2BPP         (1 << 2)
-#define VIDC_CTRL_4BPP         (2 << 2)
-#define VIDC_CTRL_8BPP         (3 << 2)
-#define VIDC_CTRL_DIV3         (0 << 0)
-#define VIDC_CTRL_DIV2         (1 << 0)
-#define VIDC_CTRL_DIV1_5       (2 << 0)
-#define VIDC_CTRL_DIV1         (3 << 0)
-
-#endif
-
 #ifdef HAS_VIDC20
 /*
  * VIDC20 registers
index 285d552089f25301bd389e0a45dc2e0f51918d43..3c14e43b82fefe1d32f591d1b2f61d2cd28d0fa8 100644 (file)
 P3
+# Standard 224-color Linux logo
 80 80
 255
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 11 15 17 33 49 54 59 85 92 73 97 106 
-83 116 129 105 131 142 115 114 122 74 88 93 20 29 31 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 10 10 10 10 10 10 
-10 10 10 6 6 6 6 6 6 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 2 3 3 17 23 26 50 67 72 73 97 106 59 85 92 73 97 106 
-105 131 142 124 127 131 105 131 142 105 131 142 53 75 83 6 8 8 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 6 6 6 10 10 10 14 14 14 22 22 22 26 26 26 30 30 30 34 34 34 
-30 30 30 30 30 30 26 26 26 18 18 18 14 14 14 10 10 10 6 6 6 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 
-0 0 0 1 1 1 26 35 39 59 85 92 59 85 92 59 85 92 29 43 47 53 75 83 
-108 122 132 132 98 104 108 122 132 105 131 142 101 101 101 43 45 48 6 8 8 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-6 6 6 14 14 14 26 26 26 42 42 42 54 54 54 66 66 66 78 78 78 78 78 78 
-78 78 78 74 74 74 66 66 66 54 54 54 42 42 42 26 26 26 18 18 18 10 10 10 
-6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 
-11 15 17 27 40 45 59 85 92 59 85 92 27 40 45 31 45 49 73 97 106 93 121 133 
-108 122 132 108 122 132 105 131 142 108 122 132 105 131 142 73 97 106 26 35 39 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-22 22 22 42 42 42 66 66 66 86 86 86 66 66 66 38 38 38 38 38 38 22 22 22 
-26 26 26 34 34 34 54 54 54 66 66 66 86 86 86 70 70 70 46 46 46 26 26 26 
-14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 7 12 13 21 31 35 42 59 64 
-53 75 83 53 75 83 50 67 72 42 59 64 32 40 45 42 59 64 73 97 106 116 116 116 
-132 98 104 116 116 116 108 122 132 117 104 110 105 131 142 83 116 129 50 67 72 7 12 13 
-1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 
-50 50 50 82 82 82 58 58 58 6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 54 54 54 86 86 86 66 66 66 
-38 38 38 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 1 1 1 6 8 8 15 22 25 26 35 39 36 54 60 53 75 83 59 85 92 
-59 85 92 48 63 69 15 22 25 12 17 20 52 67 79 94 94 94 132 98 104 132 98 104 
-117 104 110 108 122 132 108 122 132 115 114 122 105 131 142 77 105 114 59 85 92 36 54 60 
-7 12 13 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50 
-78 78 78 34 34 34 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 
-78 78 78 46 46 46 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 15 22 25 29 43 47 36 54 60 42 59 64 42 59 64 48 63 69 21 31 35 
-6 8 8 29 43 47 36 50 56 43 45 48 79 78 84 132 98 104 165 78 79 132 98 104 
-108 122 132 117 104 110 117 104 110 108 122 132 77 105 114 73 97 106 95 131 149 78 102 129 
-36 50 56 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 42 42 42 82 82 82 
-26 26 26 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 14 14 14 46 46 46 34 34 34 6 6 6 2 2 6 
-42 42 42 78 78 78 42 42 42 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-27 40 45 53 75 83 48 63 69 24 31 37 6 8 12 0 0 0 18 25 28 26 35 39 
-12 17 20 26 35 39 65 78 84 112 81 86 152 81 83 137 83 86 132 98 104 117 104 110 
-117 104 110 132 98 104 132 98 104 115 114 122 73 97 106 53 75 83 95 131 149 93 124 152 
-68 78 128 15 22 25 0 0 0 0 0 0 10 10 10 30 30 30 66 66 66 58 58 58 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 26 26 26 86 86 86 101 101 101 46 46 46 10 10 10 
-2 2 6 58 58 58 70 70 70 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-36 50 56 21 30 33 4 7 7 0 0 0 1 1 1 17 12 12 69 31 31 68 59 64 
-57 59 63 21 31 35 32 40 45 86 73 69 152 81 83 152 81 83 117 104 110 132 98 104 
-152 81 83 132 98 104 108 122 132 77 105 114 77 105 114 93 121 133 95 131 149 93 124 152 
-95 131 149 53 75 83 11 15 17 0 0 0 14 14 14 42 42 42 86 86 86 10 10 10 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 30 30 30 94 94 94 94 94 94 58 58 58 26 26 26 
-2 2 6 6 6 6 78 78 78 54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-17 23 26 2 3 3 0 0 0 17 12 12 69 31 31 123 55 55 123 55 55 152 81 83 
-86 73 69 17 23 26 7 12 13 45 54 57 101 101 101 137 83 86 132 98 104 132 98 104 
-137 83 86 117 104 110 77 105 114 42 59 64 50 67 72 78 102 129 91 117 157 91 117 157 
-95 131 149 83 116 129 40 48 73 6 6 6 22 22 22 62 62 62 62 62 62 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 26 26 26 54 54 54 38 38 38 18 18 18 10 10 10 
-2 2 6 2 2 6 34 34 34 82 82 82 38 38 38 14 14 14 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-1 1 1 1 2 2 2 3 3 28 12 12 123 55 55 174 79 79 174 79 79 174 79 79 
-152 81 83 68 59 64 26 35 39 27 40 45 79 78 84 137 83 86 165 78 79 137 83 86 
-94 94 94 48 63 69 36 50 56 50 67 72 73 97 106 93 121 133 93 124 152 93 124 152 
-95 131 149 91 118 149 78 102 129 27 40 45 30 30 30 78 78 78 30 30 30 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 10 10 10 10 10 10 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 78 78 78 50 50 50 18 18 18 6 6 6 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-4 5 3 24 53 24 19 31 15 8 7 3 90 61 47 165 78 79 174 79 79 174 79 79 
-174 79 79 137 83 86 60 52 57 7 12 13 17 23 26 70 70 70 132 98 104 112 81 86 
-79 78 84 31 45 49 15 22 25 53 75 83 91 118 149 86 106 160 91 117 157 93 124 152 
-91 117 157 93 124 152 95 131 149 53 75 83 50 50 50 86 86 86 14 14 14 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 54 54 54 66 66 66 26 26 26 6 6 6 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-19 31 15 34 76 34 34 76 34 19 31 15 28 12 12 123 55 55 174 79 79 174 79 79 
-174 79 79 165 78 79 112 81 86 32 40 45 15 22 25 38 53 58 65 78 84 29 31 32 
-21 30 33 42 59 64 60 80 103 78 102 129 87 112 149 84 96 162 91 117 157 93 124 152 
-91 117 157 93 124 152 93 121 133 59 85 92 57 68 71 82 85 86 2 2 6 2 2 6 
-2 2 6 6 6 6 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 6 6 6 14 14 14 10 10 10 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 18 18 18 82 82 82 34 34 34 10 10 10 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-34 76 34 40 89 40 40 89 40 34 76 34 8 15 6 48 26 18 123 55 55 174 79 79 
-174 79 79 174 79 79 137 83 86 68 59 64 32 40 45 21 30 33 31 45 49 21 31 35 
-12 17 20 48 63 69 78 102 129 81 88 166 84 96 162 91 117 157 93 124 152 91 117 157 
-93 124 152 95 131 149 83 116 129 59 85 92 57 68 71 86 86 86 2 2 6 2 2 6 
-6 6 6 6 6 6 22 22 22 34 34 34 6 6 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 18 18 18 34 34 34 10 10 10 50 50 50 22 22 22 2 2 6 
-2 2 6 2 2 6 2 2 6 10 10 10 86 86 86 42 42 42 14 14 14 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-40 89 40 40 89 40 40 89 40 40 89 40 24 53 24 6 6 6 69 31 31 123 55 55 
-123 55 55 90 61 47 69 31 31 36 32 33 21 31 35 7 12 13 18 25 28 48 63 69 
-60 80 103 68 78 128 84 101 153 84 96 162 84 96 162 91 117 157 91 117 157 84 96 162 
-91 117 157 73 97 106 48 63 69 50 67 72 57 59 63 86 86 86 2 2 6 2 2 6 
-38 38 38 116 116 116 94 94 94 22 22 22 22 22 22 2 2 6 2 2 6 2 2 6 
-14 14 14 86 86 86 124 131 137 170 170 170 151 151 151 38 38 38 26 26 26 6 6 6 
-2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 46 46 46 14 14 14 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-34 76 34 40 89 40 40 89 40 40 89 40 34 76 34 19 31 15 17 12 12 48 26 18 
-48 26 18 8 7 3 10 10 22 23 29 47 51 61 92 42 59 64 21 30 33 34 45 54 
-68 78 128 81 88 166 81 82 173 86 106 160 86 106 160 84 96 162 86 106 160 87 112 149 
-91 118 149 77 105 114 52 67 79 32 40 45 50 50 50 86 86 86 2 2 6 14 14 14 
-124 131 137 198 198 198 195 195 195 116 116 116 10 10 10 2 2 6 2 2 6 6 6 6 
-101 98 89 187 187 187 210 210 210 218 218 218 214 214 214 124 131 137 14 14 14 6 6 6 
-2 2 6 2 2 6 2 2 6 2 2 6 86 86 86 50 50 50 18 18 18 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-19 31 15 34 76 34 40 89 40 40 89 40 40 89 40 24 53 24 8 7 3 0 0 0 
-6 8 12 28 32 52 51 61 92 54 54 122 74 77 160 68 78 128 26 35 39 6 8 8 
-34 45 54 68 78 128 84 96 162 86 106 160 86 106 160 81 88 166 84 96 162 87 112 149 
-73 97 106 36 50 56 33 49 54 18 18 18 46 46 46 86 86 86 2 2 6 54 54 54 
-218 218 218 195 195 195 226 226 226 246 246 246 58 58 58 2 2 6 2 2 6 30 30 30 
-210 210 210 253 253 253 170 170 170 124 127 131 221 221 221 234 234 234 74 74 74 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 22 22 22 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-4 5 3 24 53 24 40 89 40 40 89 40 34 76 34 12 22 15 4 5 3 4 5 3 
-13 17 26 54 54 122 78 78 174 78 78 174 78 78 174 74 77 160 51 61 92 21 31 35 
-26 35 39 53 75 83 84 101 153 81 82 173 81 88 166 84 101 153 60 80 103 60 80 103 
-53 75 83 38 53 58 42 59 64 22 22 22 46 46 46 82 82 82 2 2 6 106 106 106 
-170 170 170 26 26 26 86 86 86 226 226 226 124 127 131 10 10 10 14 14 14 46 46 46 
-231 231 231 190 190 190 6 6 6 70 70 70 90 90 90 238 238 238 151 151 151 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 58 58 58 22 22 22 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-1 2 2 8 15 6 24 53 24 34 76 34 19 31 15 8 15 6 63 55 20 63 55 20 
-18 18 18 40 48 73 74 77 160 78 78 174 78 78 174 81 82 173 74 77 160 52 67 79 
-17 23 26 21 31 35 60 80 103 81 88 166 74 77 160 78 102 129 36 54 60 12 17 20 
-42 59 64 48 63 69 21 31 35 18 18 18 42 42 42 86 86 86 6 6 6 116 116 116 
-106 106 106 6 6 6 70 70 70 151 151 151 124 127 131 18 18 18 38 38 38 54 54 54 
-221 221 221 106 106 106 2 2 6 14 14 14 46 46 46 190 190 190 198 198 198 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 22 22 22 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-11 15 17 0 0 0 12 22 15 19 31 15 8 15 6 63 55 20 149 139 69 149 139 69 
-63 55 20 10 10 22 54 54 122 78 78 174 78 78 174 78 78 174 81 82 173 68 78 128 
-24 31 37 6 6 6 36 50 56 60 80 103 51 61 92 42 59 64 36 50 56 31 45 49 
-29 43 47 27 40 45 6 8 8 14 14 14 42 42 42 94 94 94 14 14 14 101 101 101 
-124 127 131 2 2 6 18 18 18 116 116 116 106 107 48 121 92 8 121 92 8 98 70 6 
-170 170 170 106 106 106 2 2 6 2 2 6 2 2 6 195 195 195 195 195 195 6 6 6 
-2 2 6 2 2 6 2 2 6 2 2 6 74 74 74 62 62 62 22 22 22 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-26 35 39 3 5 6 1 1 1 2 3 3 35 31 12 133 118 54 175 176 80 175 176 80 
-133 118 54 35 31 12 23 29 47 54 54 122 78 78 174 78 78 174 74 77 160 68 78 128 
-51 61 92 31 45 49 26 35 39 36 50 56 29 43 47 7 12 13 21 30 33 42 59 64 
-18 25 28 7 12 13 1 1 1 10 10 10 38 38 38 90 90 90 14 14 14 58 58 58 
-210 210 210 26 26 26 62 42 6 154 114 10 226 170 11 237 188 10 220 174 15 184 138 11 
-220 174 15 174 140 55 35 31 12 2 2 6 70 70 70 246 246 246 124 131 137 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 70 70 70 66 66 66 26 26 26 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-27 40 45 17 23 26 2 3 3 1 1 1 56 77 35 165 152 80 175 176 80 175 176 80 
-175 176 80 106 107 48 22 22 22 28 32 52 54 54 122 54 54 122 51 61 92 28 32 52 
-20 27 34 31 45 49 11 15 17 7 12 13 36 50 56 31 45 49 29 43 47 36 50 56 
-6 8 8 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 14 14 14 10 10 10 
-195 195 195 198 179 130 192 133 9 220 174 15 239 182 13 237 188 10 232 195 16 239 207 25 
-237 201 50 241 208 19 232 195 16 184 138 11 198 179 130 208 206 196 42 42 42 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 74 74 74 30 30 30 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-15 22 25 26 35 39 15 22 25 0 0 0 35 31 12 133 118 54 175 176 80 175 176 80 
-175 176 80 165 152 80 56 77 35 6 8 12 23 29 47 13 17 26 2 2 6 0 0 0 
-1 2 2 26 35 39 26 35 39 26 35 39 42 59 64 42 59 64 20 29 31 6 8 8 
-0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 86 86 86 14 14 14 2 2 6 
-121 92 8 192 133 9 219 162 10 239 182 13 237 188 10 232 195 16 241 208 19 237 201 50 
-237 201 50 239 207 25 241 208 19 241 208 19 241 208 19 230 187 11 121 92 8 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 50 50 50 82 82 82 34 34 34 10 10 10 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-1 2 2 15 22 25 31 45 49 6 8 12 4 5 3 63 55 20 149 139 69 175 176 80 
-175 176 80 175 176 80 106 107 48 20 16 6 1 1 1 0 0 0 2 3 3 11 15 17 
-21 30 33 36 50 56 36 50 56 24 31 37 15 22 25 6 8 8 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 82 82 82 30 30 30 62 42 6 
-180 123 7 206 145 10 230 174 11 239 182 13 237 188 10 238 202 15 241 208 19 237 201 50 
-239 207 25 241 208 19 241 208 19 241 208 19 230 187 11 220 174 15 184 138 11 6 6 6 
-2 2 6 2 2 6 2 2 6 2 2 6 26 26 26 94 94 94 42 42 42 14 14 14 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 1 2 2 29 43 47 26 35 39 3 5 6 8 7 3 106 107 48 165 152 80 
-175 176 80 149 139 69 63 55 20 4 5 3 2 3 3 12 17 20 26 35 39 26 35 39 
-17 23 26 7 12 13 6 8 8 3 5 6 1 2 2 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 50 50 50 104 69 6 
-192 133 9 216 158 10 236 178 12 237 188 10 232 195 16 241 208 19 237 201 50 237 201 50 
-241 208 19 241 208 19 241 208 19 204 160 10 200 144 11 216 158 10 156 118 10 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 90 90 90 54 54 54 18 18 18 
-6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 12 17 20 27 40 45 18 25 28 1 1 1 35 31 12 106 107 48 
-149 139 69 56 77 35 8 7 3 1 2 2 12 17 20 26 35 39 21 31 35 11 15 17 
-3 5 6 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 78 78 78 46 46 46 22 22 22 
-137 92 6 204 160 10 239 182 13 237 188 10 238 202 15 241 208 19 241 208 19 241 208 19 
-241 208 19 204 160 10 184 138 11 210 150 10 216 158 10 210 150 10 98 70 6 2 2 6 
-6 6 6 54 54 54 14 14 14 2 2 6 2 2 6 62 62 62 74 74 74 30 30 30 
-10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 1 1 1 15 22 25 33 49 54 12 17 20 2 3 3 35 31 12 
-56 77 35 20 16 6 1 1 1 18 25 28 21 31 35 11 15 17 1 1 1 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 10 10 10 34 34 34 78 78 78 50 50 50 6 6 6 
-88 55 22 139 102 15 190 146 13 230 187 11 239 207 25 232 195 16 220 174 15 190 146 13 
-171 120 8 192 133 9 210 150 10 213 154 11 185 146 40 165 152 80 101 98 89 2 2 6 
-2 2 6 78 78 78 116 116 116 58 58 58 2 2 6 22 22 22 90 90 90 46 46 46 
-18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 1 1 1 27 40 45 29 43 47 3 5 6 2 3 3 
-8 7 3 1 1 1 17 23 26 31 45 49 15 22 25 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 10 10 10 38 38 38 86 86 86 50 50 50 6 6 6 
-124 127 131 168 158 138 156 107 11 171 120 8 204 160 10 184 138 11 197 138 11 200 144 11 
-206 145 10 206 145 10 197 138 11 198 179 130 195 195 195 198 198 198 170 170 170 14 14 14 
-2 2 6 22 22 22 116 116 116 116 116 116 22 22 22 2 2 6 74 74 74 70 70 70 
-30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 11 15 17 31 45 49 26 35 39 3 5 6 
-0 0 0 7 12 13 27 40 45 18 25 28 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 6 6 6 18 18 18 50 50 50 101 101 101 26 26 26 10 10 10 
-124 131 137 190 190 190 168 158 138 156 107 11 197 138 11 200 144 11 197 138 11 192 133 9 
-180 123 7 185 146 40 198 179 130 187 187 187 202 202 202 221 221 221 214 214 214 66 66 66 
-2 2 6 2 2 6 50 50 50 62 62 62 6 6 6 2 2 6 10 10 10 90 90 90 
-50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 15 22 25 36 54 60 18 25 28 
-0 0 0 21 30 33 27 40 45 2 3 3 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 10 10 10 34 34 34 74 74 74 74 74 74 2 2 6 6 6 6 
-151 151 151 198 198 198 190 190 190 168 158 138 148 132 55 156 107 11 156 107 11 169 125 40 
-168 158 138 187 187 187 190 190 190 210 210 210 246 246 246 253 253 253 253 253 253 180 180 180 
-6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 
-74 74 74 34 34 34 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 27 40 45 35 52 58 
-18 25 28 35 52 58 17 23 26 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 10 10 10 22 22 22 54 54 54 94 94 94 18 18 18 2 2 6 46 46 46 
-234 234 234 221 221 221 190 190 190 190 190 190 190 190 190 187 187 187 187 187 187 190 190 190 
-190 190 190 195 195 195 214 214 214 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 14 14 14 
-86 86 86 54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 12 13 33 49 54 
-52 72 81 36 54 60 6 8 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-6 6 6 18 18 18 46 46 46 90 90 90 46 46 46 18 18 18 6 6 6 180 180 180 
-253 253 253 246 246 246 202 202 202 190 190 190 190 190 190 190 190 190 190 190 190 190 190 190 
-202 202 202 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-202 202 202 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-42 42 42 86 86 86 42 42 42 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 17 20 
-36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-14 14 14 38 38 38 74 74 74 66 66 66 2 2 6 6 6 6 90 90 90 250 250 250 
-253 253 253 253 253 253 238 238 238 198 198 198 190 190 190 190 190 190 195 195 195 221 221 221 
-246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 82 82 82 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 78 78 78 70 70 70 34 34 34 14 14 14 6 6 6 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 
-34 34 34 66 66 66 78 78 78 6 6 6 2 2 6 18 18 18 218 218 218 253 253 253 
-253 253 253 253 253 253 253 253 253 246 246 246 226 226 226 231 231 231 246 246 246 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 180 180 180 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 18 18 18 90 90 90 62 62 62 30 30 30 10 10 10 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 
-58 58 58 90 90 90 18 18 18 2 2 6 2 2 6 106 106 106 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 231 231 231 18 18 18 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 18 18 18 94 94 94 54 54 54 26 26 26 10 10 10 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 50 50 50 
-90 90 90 26 26 26 2 2 6 2 2 6 14 14 14 195 195 195 250 250 250 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-250 250 250 242 242 242 54 54 54 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 38 38 38 86 86 86 50 50 50 22 22 22 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 38 38 38 82 82 82 
-34 34 34 2 2 6 2 2 6 2 2 6 42 42 42 195 195 195 246 246 246 253 253 253 
-253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 242 242 242 250 250 250 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 246 246 246 238 238 238 
-226 226 226 231 231 231 101 101 101 6 6 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 82 82 82 42 42 42 14 14 14 
-6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 26 26 26 62 62 62 66 66 66 
-2 2 6 2 2 6 2 2 6 6 6 6 70 70 70 170 170 170 202 202 202 234 234 234 
-246 246 246 250 250 250 250 250 250 238 238 238 226 226 226 231 231 231 238 238 238 250 250 250 
-250 250 250 250 250 250 246 246 246 231 231 231 214 214 214 202 202 202 202 202 202 202 202 202 
-198 198 198 202 202 202 180 180 180 18 18 18 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 66 66 66 30 30 30 
-10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 12 17 20 36 54 60 29 43 47 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 82 82 82 18 18 18 
-2 2 6 2 2 6 2 2 6 10 10 10 94 94 94 180 180 180 218 218 218 242 242 242 
-250 250 250 253 253 253 253 253 253 250 250 250 234 234 234 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 246 246 246 238 238 238 226 226 226 210 210 210 202 202 202 
-195 195 195 195 195 195 210 210 210 151 151 151 6 6 6 14 14 14 50 50 50 14 14 14 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 86 86 86 46 46 46 
-18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 21 30 33 35 52 58 6 8 12 0 0 0 
-0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 54 54 54 70 70 70 2 2 6 
-2 2 6 10 10 10 2 2 6 22 22 22 170 170 170 231 231 231 250 250 250 253 253 253 
-253 253 253 253 253 253 253 253 253 250 250 250 242 242 242 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 246 246 246 
-231 231 231 202 202 202 198 198 198 226 226 226 94 94 94 2 2 6 6 6 6 38 38 38 
-30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 62 62 66 66 66 
-26 26 26 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 6 8 8 33 49 54 29 43 47 6 8 12 
-0 0 0 0 0 0 0 0 0 10 10 10 30 30 30 74 74 74 50 50 50 2 2 6 
-26 26 26 26 26 26 2 2 6 106 106 106 238 238 238 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 246 246 246 218 218 218 202 202 202 210 210 210 14 14 14 2 2 6 2 2 6 
-30 30 30 22 22 22 2 2 6 2 2 6 2 2 6 2 2 6 18 18 18 86 86 86 
-42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 17 20 33 49 54 17 23 26 
-0 0 0 0 0 0 0 0 0 14 14 14 42 42 42 90 90 90 22 22 22 2 2 6 
-42 42 42 2 2 6 18 18 18 218 218 218 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 250 250 250 221 221 221 218 218 218 101 101 101 2 2 6 14 14 14 
-18 18 18 38 38 38 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 78 78 78 
-58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 15 22 25 36 54 60 
-0 0 0 0 0 0 0 0 0 18 18 18 54 54 54 82 82 82 2 2 6 26 26 26 
-22 22 22 2 2 6 124 127 131 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 250 250 250 238 238 238 198 198 198 6 6 6 38 38 38 
-58 58 58 26 26 26 38 38 38 2 2 6 2 2 6 2 2 6 2 2 6 46 46 46 
-78 78 78 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 21 30 33 
-36 54 60 0 0 0 0 0 0 30 30 30 74 74 74 58 58 58 2 2 6 42 42 42 
-2 2 6 22 22 22 231 231 231 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 246 246 246 46 46 46 38 38 38 
-42 42 42 14 14 14 38 38 38 14 14 14 2 2 6 2 2 6 2 2 6 6 6 6 
-86 86 86 46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-36 54 60 0 0 0 0 0 0 42 42 42 90 90 90 18 18 18 18 18 18 26 26 26 
-2 2 6 116 116 116 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 250 250 250 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 94 94 94 6 6 6 
-2 2 6 2 2 6 10 10 10 34 34 34 2 2 6 2 2 6 2 2 6 2 2 6 
-74 74 74 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 36 54 60 26 26 26 66 66 66 82 82 82 2 2 6 38 38 38 6 6 6 
-14 14 14 210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 246 246 246 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 151 151 151 2 2 6 
-2 2 6 2 2 6 2 2 6 46 46 46 2 2 6 2 2 6 2 2 6 2 2 6 
-42 42 42 74 74 74 30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-6 6 6 36 54 60 21 30 33 90 90 90 26 26 26 6 6 6 42 42 42 2 2 6 
-74 74 74 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 242 242 242 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 180 180 180 2 2 6 
-2 2 6 2 2 6 2 2 6 46 46 46 2 2 6 2 2 6 2 2 6 2 2 6 
-10 10 10 86 86 86 38 38 38 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-10 10 10 26 26 26 36 54 60 82 82 82 2 2 6 22 22 22 18 18 18 2 2 6 
-151 151 151 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 202 202 202 2 2 6 
-2 2 6 2 2 6 2 2 6 38 38 38 2 2 6 2 2 6 2 2 6 2 2 6 
-6 6 6 86 86 86 46 46 46 14 14 14 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-18 18 18 46 46 46 86 86 86 36 54 60 2 2 6 34 34 34 10 10 10 6 6 6 
-210 210 210 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 221 221 221 6 6 6 
-2 2 6 2 2 6 6 6 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 82 82 82 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-26 26 26 66 66 66 62 62 62 2 2 6 2 2 6 38 38 38 10 10 10 26 26 26 
-238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 231 231 231 6 6 6 
-2 2 6 2 2 6 10 10 10 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 66 66 66 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-38 38 38 78 78 78 6 6 6 2 2 6 2 2 6 46 46 46 14 14 14 42 42 42 
-246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 10 10 10 
-2 2 6 2 2 6 22 22 22 14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 66 66 66 62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
-50 50 50 74 74 74 2 2 6 2 2 6 14 14 14 70 70 70 34 34 34 62 62 62 
-250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 234 234 234 14 14 14 
-2 2 6 2 2 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 66 66 66 62 62 62 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
-54 54 54 62 62 62 2 2 6 2 2 6 2 2 6 30 30 30 46 46 46 70 70 70 
-250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 226 226 226 10 10 10 
-2 2 6 6 6 6 30 30 30 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 66 66 66 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 
-58 58 58 62 62 62 2 2 6 2 2 6 2 2 6 2 2 6 30 30 30 78 78 78 
-250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 202 202 202 2 2 6 
-22 22 22 34 34 34 20 16 6 22 22 22 26 26 26 18 18 18 6 6 6 2 2 6 
-2 2 6 82 82 82 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 26 26 26 
-62 62 62 106 106 106 63 55 20 184 138 11 204 160 10 121 92 8 6 6 6 62 62 62 
-238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 151 151 151 18 18 18 
-14 14 14 2 2 6 2 2 6 2 2 6 6 6 6 18 18 18 66 66 66 38 38 38 
-6 6 6 94 94 94 50 50 50 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 6 6 6 10 10 10 10 10 10 18 18 18 38 38 38 
-78 78 78 138 132 106 216 158 10 242 186 14 246 190 14 246 190 14 156 118 10 10 10 10 
-90 90 90 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 246 230 190 214 187 87 214 187 87 185 146 40 35 31 12 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 38 38 38 46 46 46 
-26 26 26 106 106 106 54 54 54 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 6 6 6 14 14 14 22 22 22 30 30 30 38 38 38 50 50 50 70 70 70 
-106 106 106 185 146 40 226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 154 114 10 
-6 6 6 74 74 74 226 226 226 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 231 231 231 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 237 201 50 241 196 14 241 208 19 232 195 16 35 31 12 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 30 30 30 26 26 26 
-204 160 10 165 152 80 66 66 66 26 26 26 6 6 6 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-6 6 6 18 18 18 38 38 38 58 58 58 78 78 78 86 86 86 101 101 101 124 127 131 
-174 140 55 210 150 10 234 174 13 246 186 14 246 190 14 246 190 14 246 190 14 237 188 10 
-98 70 6 2 2 6 46 46 46 198 198 198 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 234 234 234 242 242 242 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 214 187 87 242 186 14 241 196 14 204 160 10 20 16 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 6 6 6 121 92 8 
-238 202 15 232 195 16 82 82 82 34 34 34 10 10 10 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-14 14 14 38 38 38 70 70 70 148 132 55 185 146 40 200 144 11 197 138 11 197 138 11 
-213 154 11 226 170 11 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-220 174 15 35 31 12 2 2 6 22 22 22 151 151 151 250 250 250 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 250 250 250 242 242 242 214 187 87 239 182 13 237 188 10 213 154 11 35 31 12 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 62 42 6 220 174 15 
-237 188 10 237 188 10 113 101 86 42 42 42 14 14 14 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-22 22 22 54 54 54 148 132 55 213 154 11 226 170 11 230 174 11 226 170 11 226 170 11 
-236 178 12 242 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-241 196 14 184 138 11 10 10 10 2 2 6 6 6 6 116 116 116 242 242 242 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 231 231 231 198 198 198 213 164 39 236 178 12 236 178 12 210 150 10 137 92 6 
-20 16 6 2 2 6 2 2 6 2 2 6 6 6 6 62 42 6 200 144 11 236 178 12 
-239 182 13 239 182 13 124 112 88 58 58 58 22 22 22 6 6 6 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-30 30 30 70 70 70 169 125 40 226 170 11 239 182 13 242 186 14 242 186 14 246 186 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 232 195 16 98 70 6 2 2 6 2 2 6 2 2 6 66 66 66 221 221 221 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 202 202 202 198 198 198 213 164 39 230 174 11 230 174 11 216 158 10 192 133 9 
-163 110 8 120 80 7 98 70 6 120 80 7 167 114 7 197 138 11 226 170 11 239 182 13 
-242 186 14 242 186 14 165 152 80 78 78 78 34 34 34 14 14 14 6 6 6 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-30 30 30 78 78 78 185 146 40 226 170 11 239 182 13 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 241 196 14 204 160 10 20 16 6 2 2 6 2 2 6 2 2 6 38 38 38 
-218 218 218 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-250 250 250 202 202 202 198 198 198 213 164 39 226 170 11 236 178 12 224 166 10 210 150 10 
-200 144 11 197 138 11 192 133 9 197 138 11 210 150 10 226 170 11 242 186 14 246 190 14 
-246 190 14 246 186 14 220 174 15 124 112 88 62 62 62 30 30 30 14 14 14 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-30 30 30 78 78 78 174 140 55 224 166 10 239 182 13 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 241 196 14 139 102 15 2 2 6 2 2 6 2 2 6 2 2 6 
-78 78 78 250 250 250 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-250 250 250 214 214 214 198 198 198 185 146 40 219 162 10 236 178 12 234 174 13 224 166 10 
-216 158 10 213 154 11 213 154 11 216 158 10 226 170 11 239 182 13 246 190 14 246 190 14 
-246 190 14 246 190 14 242 186 14 213 164 39 101 101 101 58 58 58 30 30 30 14 14 14 
-6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-30 30 30 74 74 74 174 140 55 216 158 10 236 178 12 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 241 196 14 230 187 11 62 42 6 2 2 6 2 2 6 2 2 6 
-22 22 22 238 238 238 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 226 226 226 187 187 187 169 125 40 216 158 10 236 178 12 239 182 13 236 178 12 
-230 174 11 226 170 11 226 170 11 230 174 11 236 178 12 242 186 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 186 14 239 182 13 213 164 39 106 106 106 66 66 66 34 34 34 
-14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-26 26 26 70 70 70 149 139 69 213 154 11 236 178 12 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 241 196 14 190 146 13 20 16 6 2 2 6 2 2 6 
-46 46 46 246 246 246 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 221 221 221 86 86 86 156 107 11 216 158 10 236 178 12 242 186 14 246 186 14 
-242 186 14 239 182 13 239 182 13 242 186 14 242 186 14 246 186 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 220 174 15 149 139 69 66 66 66 
-30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-26 26 26 70 70 70 149 139 69 210 150 10 236 178 12 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 121 92 8 34 34 34 106 106 106 
-221 221 221 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-242 242 242 82 82 82 20 16 6 163 110 8 216 158 10 236 178 12 242 186 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 149 139 69 
-46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 10 10 
-30 30 30 78 78 78 149 139 69 210 150 10 236 178 12 246 186 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 241 196 14 220 174 15 198 179 130 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 218 218 218 
-58 58 58 2 2 6 20 16 6 167 114 7 216 158 10 236 178 12 246 186 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 242 186 14 185 146 40 
-54 54 54 22 22 22 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 
-38 38 38 86 86 86 169 125 40 213 154 11 236 178 12 246 186 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 232 195 16 190 146 13 214 214 214 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 250 250 250 170 170 170 26 26 26 
-2 2 6 2 2 6 35 31 12 163 110 8 219 162 10 239 182 13 246 186 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 224 166 10 149 139 69 
-46 46 46 18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
-50 50 50 113 101 86 192 133 9 224 166 10 242 186 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 230 187 11 204 160 10 133 118 54 
-226 226 226 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 253 
-253 253 253 253 253 253 253 253 253 253 253 253 198 198 198 66 66 66 2 2 6 2 2 6 
-2 2 6 2 2 6 62 42 6 156 107 11 219 162 10 239 182 13 246 186 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 242 186 14 234 174 13 213 154 11 148 132 55 66 66 66 
-30 30 30 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 
-58 58 58 148 132 55 206 145 10 234 174 13 242 186 14 246 186 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 236 178 12 204 160 10 163 110 8 
-62 42 6 124 131 137 218 218 218 250 250 250 253 253 253 253 253 253 253 253 253 250 250 250 
-242 242 242 210 210 210 151 151 151 66 66 66 6 6 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 62 42 6 163 110 8 216 158 10 236 178 12 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 239 182 13 230 174 11 216 158 10 185 146 40 124 112 88 70 70 70 38 38 38 
-18 18 18 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 22 22 22 
-62 62 62 169 125 40 206 145 10 224 166 10 236 178 12 239 182 13 242 186 14 242 186 14 
-246 186 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 236 178 12 216 158 10 171 120 8 
-85 57 6 2 2 6 6 6 6 30 30 30 54 54 54 62 62 62 50 50 50 38 38 38 
-14 14 14 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 6 6 6 85 57 6 167 114 7 213 154 11 236 178 12 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 190 14 242 186 14 239 182 13 239 182 13 
-230 174 11 210 150 10 174 140 55 124 112 88 82 82 82 54 54 54 34 34 34 18 18 18 
-6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 18 18 18 
-50 50 50 169 125 40 192 133 9 200 144 11 216 158 10 219 162 10 224 166 10 226 170 11 
-230 174 11 236 178 12 239 182 13 239 182 13 242 186 14 246 186 14 246 190 14 246 190 14 
-246 190 14 246 190 14 246 190 14 246 190 14 246 186 14 230 174 11 210 150 10 163 110 8 
-104 69 6 10 10 10 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 6 6 6 85 57 6 167 114 7 206 145 10 230 174 11 242 186 14 246 190 14 
-246 190 14 246 190 14 246 186 14 242 186 14 239 182 13 230 174 11 224 166 10 213 154 11 
-169 125 40 124 112 88 86 86 86 58 58 58 38 38 38 22 22 22 10 10 10 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 14 14 
-34 34 34 70 70 70 133 118 54 169 125 40 167 114 7 180 123 7 192 133 9 197 138 11 
-200 144 11 206 145 10 213 154 11 219 162 10 224 166 10 230 174 11 239 182 13 242 186 14 
-246 186 14 246 186 14 246 186 14 246 186 14 239 182 13 216 158 10 184 138 11 152 99 6 
-104 69 6 20 16 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 2 2 6 
-2 2 6 6 6 6 85 57 6 152 99 6 192 133 9 219 162 10 236 178 12 239 182 13 
-246 186 14 242 186 14 239 182 13 236 178 12 224 166 10 206 145 10 192 133 9 148 132 55 
-94 94 94 62 62 62 42 42 42 22 22 22 14 14 14 6 6 6 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-18 18 18 34 34 34 58 58 58 78 78 78 101 98 89 124 112 88 133 118 54 156 107 11 
-163 110 8 167 114 7 171 120 8 180 123 7 184 138 11 197 138 11 210 150 10 219 162 10 
-226 170 11 236 178 12 236 178 12 234 174 13 219 162 10 197 138 11 163 110 8 134 84 6 
-85 57 6 10 10 10 2 2 6 2 2 6 18 18 18 38 38 38 38 38 38 38 38 38 
-38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 26 26 26 2 2 6 
-2 2 6 6 6 6 62 42 6 137 92 6 171 120 8 200 144 11 219 162 10 230 174 11 
-234 174 13 230 174 11 219 162 10 210 150 10 192 133 9 163 110 8 124 112 88 82 82 82 
-50 50 50 30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-6 6 6 14 14 14 22 22 22 34 34 34 42 42 42 58 58 58 74 74 74 86 86 86 
-101 98 89 113 101 86 133 118 54 121 92 8 137 92 6 152 99 6 163 110 8 180 123 7 
-184 138 11 197 138 11 206 145 10 200 144 11 180 123 7 156 107 11 134 84 6 104 69 6 
-62 42 6 54 54 54 106 106 106 101 98 89 86 86 86 82 82 82 78 78 78 78 78 78 
-78 78 78 78 78 78 78 78 78 78 78 78 78 78 78 82 82 82 86 86 86 94 94 94 
-106 106 106 101 101 101 90 61 47 120 80 7 156 107 11 180 123 7 192 133 9 200 144 11 
-206 145 10 200 144 11 192 133 9 171 120 8 139 102 15 113 101 86 70 70 70 42 42 42 
-22 22 22 10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 6 6 6 10 10 10 14 14 14 22 22 22 30 30 30 38 38 38 
-50 50 50 62 62 62 74 74 74 90 90 90 101 98 89 113 101 86 121 92 8 120 80 7 
-137 92 6 152 99 6 152 99 6 152 99 6 134 84 6 120 80 7 98 70 6 88 55 22 
-101 98 89 82 82 82 58 58 58 46 46 46 38 38 38 34 34 34 34 34 34 34 34 34 
-34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 38 38 38 42 42 42 
-54 54 54 82 82 82 94 86 71 85 57 6 134 84 6 156 107 11 167 114 7 171 120 8 
-171 120 8 167 114 7 152 99 6 121 92 8 101 98 89 62 62 62 34 34 34 18 18 18 
-6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 10 10 10 
-18 18 18 22 22 22 30 30 30 42 42 42 50 50 50 66 66 66 86 86 86 101 98 89 
-94 86 71 98 70 6 104 69 6 104 69 6 104 69 6 85 57 6 88 55 22 90 90 90 
-62 62 62 38 38 38 22 22 22 14 14 14 10 10 10 10 10 10 10 10 10 10 10 10 
-10 10 10 10 10 10 6 6 6 10 10 10 10 10 10 10 10 10 10 10 10 14 14 14 
-22 22 22 42 42 42 70 70 70 94 86 71 85 57 6 104 69 6 120 80 7 137 92 6 
-134 84 6 120 80 7 94 86 71 86 86 86 58 58 58 30 30 30 14 14 14 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 6 6 6 10 10 10 14 14 14 18 18 18 26 26 26 38 38 38 54 54 54 
-70 70 70 86 86 86 94 86 71 94 86 71 94 86 71 86 86 86 74 74 74 50 50 50 
-30 30 30 14 14 14 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-6 6 6 18 18 18 34 34 34 58 58 58 82 82 82 94 86 71 94 86 71 94 86 71 
-94 86 71 94 86 71 74 74 74 50 50 50 26 26 26 14 14 14 6 6 6 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 6 6 6 14 14 14 18 18 18 
-30 30 30 38 38 38 46 46 46 54 54 54 50 50 50 42 42 42 30 30 30 18 18 18 
-10 10 10 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 6 6 6 14 14 14 26 26 26 38 38 38 50 50 50 58 58 58 58 58 58 
-54 54 54 42 42 42 30 30 30 18 18 18 10 10 10 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6 6 6 
-6 6 6 10 10 10 14 14 14 18 18 18 18 18 18 14 14 14 10 10 10 6 6 6 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 6 6 6 14 14 14 18 18 18 22 22 22 22 22 22 
-18 18 18 14 14 14 10 10 10 6 6 6 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
-
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  10  10  10  10  10  10
+ 10  10  10   6   6   6   6   6   6   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 22  22  22  26  26  26  30  30  30  34  34  34
+ 30  30  30  30  30  30  26  26  26  18  18  18
+ 14  14  14  10  10  10   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  26  26  26  42  42  42
+ 54  54  54  66  66  66  78  78  78  78  78  78
+ 78  78  78  74  74  74  66  66  66  54  54  54
+ 42  42  42  26  26  26  18  18  18  10  10  10
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 22  22  22  42  42  42  66  66  66  86  86  86
+ 66  66  66  38  38  38  38  38  38  22  22  22
+ 26  26  26  34  34  34  54  54  54  66  66  66
+ 86  86  86  70  70  70  46  46  46  26  26  26
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 50  50  50  82  82  82  58  58  58   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  54  54  54  86  86  86  66  66  66
+ 38  38  38  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 78  78  78  34  34  34   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6  70  70  70
+ 78  78  78  46  46  46  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  42  42  42  82  82  82
+ 26  26  26   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 46  46  46  34  34  34   6   6   6   2   2   6
+ 42  42  42  78  78  78  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  30  30  30  66  66  66  58  58  58
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 86  86  86 101 101 101  46  46  46  10  10  10
+  2   2   6  58  58  58  70  70  70  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  86  86  86  10  10  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  30  30  30
+ 94  94  94  94  94  94  58  58  58  26  26  26
+  2   2   6   6   6   6  78  78  78  54  54  54
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  62  62  62  62  62  62   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  26  26  26
+ 54  54  54  38  38  38  18  18  18  10  10  10
+  2   2   6   2   2   6  34  34  34  82  82  82
+ 38  38  38  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 10  10  10   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  54  54  54
+ 66  66  66  26  26  26   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  82  82  82   2   2   6   2   2   6
+  2   2   6   6   6   6  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 14  14  14  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  18  18  18
+ 82  82  82  34  34  34  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+  6   6   6   6   6   6  22  22  22  34  34  34
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  34  34  34
+ 10  10  10  50  50  50  22  22  22   2   2   6
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 86  86  86  42  42  42  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6   2   2   6
+ 38  38  38 116 116 116  94  94  94  22  22  22
+ 22  22  22   2   2   6   2   2   6   2   2   6
+ 14  14  14  86  86  86 138 138 138 162 162 162
+154 154 154  38  38  38  26  26  26   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  14  14  14
+134 134 134 198 198 198 195 195 195 116 116 116
+ 10  10  10   2   2   6   2   2   6   6   6   6
+101  98  89 187 187 187 210 210 210 218 218 218
+214 214 214 134 134 134  14  14  14   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 86  86  86  50  50  50  18  18  18   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  86  86  86   2   2   6  54  54  54
+218 218 218 195 195 195 226 226 226 246 246 246
+ 58  58  58   2   2   6   2   2   6  30  30  30
+210 210 210 253 253 253 174 174 174 123 123 123
+221 221 221 234 234 234  74  74  74   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 46  46  46  82  82  82   2   2   6 106 106 106
+170 170 170  26  26  26  86  86  86 226 226 226
+123 123 123  10  10  10  14  14  14  46  46  46
+231 231 231 190 190 190   6   6   6  70  70  70
+ 90  90  90 238 238 238 158 158 158   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   1   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  86  86  86   6   6   6 116 116 116
+106 106 106   6   6   6  70  70  70 149 149 149
+128 128 128  18  18  18  38  38  38  54  54  54
+221 221 221 106 106 106   2   2   6  14  14  14
+ 46  46  46 190 190 190 198 198 198   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   0
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  94  94  94  14  14  14 101 101 101
+128 128 128   2   2   6  18  18  18 116 116 116
+118  98  46 121  92   8 121  92   8  98  78  10
+162 162 162 106 106 106   2   2   6   2   2   6
+  2   2   6 195 195 195 195 195 195   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  62  62  62  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   1   0   0   1
+  0   0   1   0   0   0   0   0   1   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  90  90  90  14  14  14  58  58  58
+210 210 210  26  26  26  54  38   6 154 114  10
+226 170  11 236 186  11 225 175  15 184 144  12
+215 174  15 175 146  61  37  26   9   2   2   6
+ 70  70  70 246 246 246 138 138 138   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 70  70  70  66  66  66  26  26  26   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  14  14  14  10  10  10
+195 195 195 188 164 115 192 133   9 225 175  15
+239 182  13 234 190  10 232 195  16 232 200  30
+245 207  45 241 208  19 232 195  16 184 144  12
+218 194 134 211 206 186  42  42  42   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  74  74  74  30  30  30   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  86  86  86  14  14  14   2   2   6
+121  87  25 192 133   9 219 162  10 239 182  13
+236 186  11 232 195  16 241 208  19 244 214  54
+246 218  60 246 218  38 246 215  20 241 208  19
+241 208  19 226 184  13 121  87  25   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 50  50  50  82  82  82  34  34  34  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  82  82  82  30  30  30  61  42   6
+180 123   7 206 145  10 230 174  11 239 182  13
+234 190  10 238 202  15 241 208  19 246 218  74
+246 218  38 246 215  20 246 215  20 246 215  20
+226 184  13 215 174  15 184 144  12   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 26  26  26  94  94  94  42  42  42  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  50  50  50 104  69   6
+192 133   9 216 158  10 236 178  12 236 186  11
+232 195  16 241 208  19 244 214  54 245 215  43
+246 215  20 246 215  20 241 208  19 198 155  10
+200 144  11 216 158  10 156 118  10   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  90  90  90  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78  46  46  46  22  22  22
+137  92   6 210 162  10 239 182  13 238 190  10
+238 202  15 241 208  19 246 215  20 246 215  20
+241 208  19 203 166  17 185 133  11 210 150  10
+216 158  10 210 150  10 102  78  10   2   2   6
+  6   6   6  54  54  54  14  14  14   2   2   6
+  2   2   6  62  62  62  74  74  74  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 34  34  34  78  78  78  50  50  50   6   6   6
+ 94  70  30 139 102  15 190 146  13 226 184  13
+232 200  30 232 195  16 215 174  15 190 146  13
+168 122  10 192 133   9 210 150  10 213 154  11
+202 150  34 182 157 106 101  98  89   2   2   6
+  2   2   6  78  78  78 116 116 116  58  58  58
+  2   2   6  22  22  22  90  90  90  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  86  86  86  50  50  50   6   6   6
+128 128 128 174 154 114 156 107  11 168 122  10
+198 155  10 184 144  12 197 138  11 200 144  11
+206 145  10 206 145  10 197 138  11 188 164 115
+195 195 195 198 198 198 174 174 174  14  14  14
+  2   2   6  22  22  22 116 116 116 116 116 116
+ 22  22  22   2   2   6  74  74  74  70  70  70
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 101 101 101  26  26  26  10  10  10
+138 138 138 190 190 190 174 154 114 156 107  11
+197 138  11 200 144  11 197 138  11 192 133   9
+180 123   7 190 142  34 190 178 144 187 187 187
+202 202 202 221 221 221 214 214 214  66  66  66
+  2   2   6   2   2   6  50  50  50  62  62  62
+  6   6   6   2   2   6  10  10  10  90  90  90
+ 50  50  50  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  34  34  34
+ 74  74  74  74  74  74   2   2   6   6   6   6
+144 144 144 198 198 198 190 190 190 178 166 146
+154 121  60 156 107  11 156 107  11 168 124  44
+174 154 114 187 187 187 190 190 190 210 210 210
+246 246 246 253 253 253 253 253 253 182 182 182
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  62  62  62
+ 74  74  74  34  34  34  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  22  22  22  54  54  54
+ 94  94  94  18  18  18   2   2   6  46  46  46
+234 234 234 221 221 221 190 190 190 190 190 190
+190 190 190 187 187 187 187 187 187 190 190 190
+190 190 190 195 195 195 214 214 214 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+ 82  82  82   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  14  14  14
+ 86  86  86  54  54  54  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  46  46  46  90  90  90
+ 46  46  46  18  18  18   6   6   6 182 182 182
+253 253 253 246 246 246 206 206 206 190 190 190
+190 190 190 190 190 190 190 190 190 190 190 190
+206 206 206 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+202 202 202  14  14  14   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  86  86  86  42  42  42  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  38  38  38  74  74  74  66  66  66
+  2   2   6   6   6   6  90  90  90 250 250 250
+253 253 253 253 253 253 238 238 238 198 198 198
+190 190 190 190 190 190 195 195 195 221 221 221
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253  82  82  82   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  78  78  78  70  70  70  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  66  66  66  78  78  78   6   6   6
+  2   2   6  18  18  18 218 218 218 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+226 226 226 231 231 231 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 178 178 178   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  18  18  18  90  90  90  62  62  62
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  26  26  26
+ 58  58  58  90  90  90  18  18  18   2   2   6
+  2   2   6 110 110 110 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231  18  18  18   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  94  94  94
+ 54  54  54  26  26  26  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  22  22  22  50  50  50
+ 90  90  90  26  26  26   2   2   6   2   2   6
+ 14  14  14 195 195 195 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 242 242 242  54  54  54   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+ 86  86  86  50  50  50  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  38  38  38  82  82  82
+ 34  34  34   2   2   6   2   2   6   2   2   6
+ 42  42  42 195 195 195 246 246 246 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 242 242 242 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 246 246 246 238 238 238
+226 226 226 231 231 231 101 101 101   6   6   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 38  38  38  82  82  82  42  42  42  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  62  62  62  66  66  66
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 70  70  70 170 170 170 206 206 206 234 234 234
+246 246 246 250 250 250 250 250 250 238 238 238
+226 226 226 231 231 231 238 238 238 250 250 250
+250 250 250 250 250 250 246 246 246 231 231 231
+214 214 214 206 206 206 202 202 202 202 202 202
+198 198 198 202 202 202 182 182 182  18  18  18
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  62  62  62  66  66  66  30  30  30
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  42  42  42  82  82  82  18  18  18
+  2   2   6   2   2   6   2   2   6  10  10  10
+ 94  94  94 182 182 182 218 218 218 242 242 242
+250 250 250 253 253 253 253 253 253 250 250 250
+234 234 234 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+238 238 238 226 226 226 210 210 210 202 202 202
+195 195 195 195 195 195 210 210 210 158 158 158
+  6   6   6  14  14  14  50  50  50  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  86  86  86  46  46  46
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54  70  70  70   2   2   6
+  2   2   6  10  10  10   2   2   6  22  22  22
+166 166 166 231 231 231 250 250 250 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 246 246
+231 231 231 206 206 206 198 198 198 226 226 226
+ 94  94  94   2   2   6   6   6   6  38  38  38
+ 30  30  30   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  62  62  62  66  66  66
+ 26  26  26  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74  50  50  50   2   2   6
+ 26  26  26  26  26  26   2   2   6 106 106 106
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 246 246 246 218 218 218 202 202 202
+210 210 210  14  14  14   2   2   6   2   2   6
+ 30  30  30  22  22  22   2   2   6   2   2   6
+  2   2   6   2   2   6  18  18  18  86  86  86
+ 42  42  42  14  14  14   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 42  42  42  90  90  90  22  22  22   2   2   6
+ 42  42  42   2   2   6  18  18  18 218 218 218
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 250 250 250 221 221 221
+218 218 218 101 101 101   2   2   6  14  14  14
+ 18  18  18  38  38  38  10  10  10   2   2   6
+  2   2   6   2   2   6   2   2   6  78  78  78
+ 58  58  58  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  82  82  82   2   2   6  26  26  26
+ 22  22  22   2   2   6 123 123 123 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+238 238 238 198 198 198   6   6   6  38  38  38
+ 58  58  58  26  26  26  38  38  38   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+ 78  78  78  30  30  30  10  10  10   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0  10  10  10  30  30  30
+ 74  74  74  58  58  58   2   2   6  42  42  42
+  2   2   6  22  22  22 231 231 231 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 246 246 246  46  46  46  38  38  38
+ 42  42  42  14  14  14  38  38  38  14  14  14
+  2   2   6   2   2   6   2   2   6   6   6   6
+ 86  86  86  46  46  46  14  14  14   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  42  42  42
+ 90  90  90  18  18  18  18  18  18  26  26  26
+  2   2   6 116 116 116 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 250 250 250 238 238 238
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253  94  94  94   6   6   6
+  2   2   6   2   2   6  10  10  10  34  34  34
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 74  74  74  58  58  58  22  22  22   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0  10  10  10  26  26  26  66  66  66
+ 82  82  82   2   2   6  38  38  38   6   6   6
+ 14  14  14 210 210 210 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 246 246 246 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 144 144 144   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 42  42  42  74  74  74  30  30  30  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  42  42  42  90  90  90
+ 26  26  26   6   6   6  42  42  42   2   2   6
+ 74  74  74 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 242 242 242 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 182 182 182   2   2   6
+  2   2   6   2   2   6   2   2   6  46  46  46
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 10  10  10  86  86  86  38  38  38  10  10  10
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 10  10  10  26  26  26  66  66  66  82  82  82
+  2   2   6  22  22  22  18  18  18   2   2   6
+149 149 149 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 206 206 206   2   2   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+  2   2   6   2   2   6   2   2   6   2   2   6
+  6   6   6  86  86  86  46  46  46  14  14  14
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  46  46  46  86  86  86  18  18  18
+  2   2   6  34  34  34  10  10  10   6   6   6
+210 210 210 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 221 221 221   6   6   6
+  2   2   6   2   2   6   6   6   6  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 26  26  26  66  66  66  62  62  62   2   2   6
+  2   2   6  38  38  38  10  10  10  26  26  26
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 238 238 238
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231   6   6   6
+  2   2   6   2   2   6  10  10  10  30  30  30
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 38  38  38  78  78  78   6   6   6   2   2   6
+  2   2   6  46  46  46  14  14  14  42  42  42
+246 246 246 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234  10  10  10
+  2   2   6   2   2   6  22  22  22  14  14  14
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50  74  74  74   2   2   6   2   2   6
+ 14  14  14  70  70  70  34  34  34  62  62  62
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234  14  14  14
+  2   2   6   2   2   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  62  62  62  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 54  54  54  62  62  62   2   2   6   2   2   6
+  2   2   6  30  30  30  46  46  46  70  70  70
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 226 226 226  10  10  10
+  2   2   6   6   6   6  30  30  30   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6  66  66  66  58  58  58  22  22  22
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58  62  62  62   2   2   6   2   2   6
+  2   2   6   2   2   6  30  30  30  78  78  78
+250 250 250 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 206 206 206   2   2   6
+ 22  22  22  34  34  34  18  14   6  22  22  22
+ 26  26  26  18  18  18   6   6   6   2   2   6
+  2   2   6  82  82  82  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  26  26  26
+ 62  62  62 106 106 106  74  54  14 185 133  11
+210 162  10 121  92   8   6   6   6  62  62  62
+238 238 238 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 246 246 246
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 158 158 158  18  18  18
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  6   6   6  18  18  18  66  66  66  38  38  38
+  6   6   6  94  94  94  50  50  50  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 10  10  10  10  10  10  18  18  18  38  38  38
+ 78  78  78 142 134 106 216 158  10 242 186  14
+246 190  14 246 190  14 156 118  10  10  10  10
+ 90  90  90 238 238 238 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 246 230 190
+238 204  91 238 204  91 181 142  44  37  26   9
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  38  38  38  46  46  46
+ 26  26  26 106 106 106  54  54  54  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  22  22  22
+ 30  30  30  38  38  38  50  50  50  70  70  70
+106 106 106 190 142  34 226 170  11 242 186  14
+246 190  14 246 190  14 246 190  14 154 114  10
+  6   6   6  74  74  74 226 226 226 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 231 231 231 250 250 250
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 228 184  62
+241 196  14 241 208  19 232 195  16  38  30  10
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  30  30  30  26  26  26
+203 166  17 154 142  90  66  66  66  26  26  26
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  38  38  38  58  58  58
+ 78  78  78  86  86  86 101 101 101 123 123 123
+175 146  61 210 150  10 234 174  13 246 186  14
+246 190  14 246 190  14 246 190  14 238 190  10
+102  78  10   2   2   6  46  46  46 198 198 198
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 234 234 234 242 242 242
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 224 178  62
+242 186  14 241 196  14 210 166  10  22  18   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   6   6   6 121  92   8
+238 202  15 232 195  16  82  82  82  34  34  34
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+ 14  14  14  38  38  38  70  70  70 154 122  46
+190 142  34 200 144  11 197 138  11 197 138  11
+213 154  11 226 170  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+225 175  15  46  32   6   2   2   6  22  22  22
+158 158 158 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 242 242 242 224 178  62
+239 182  13 236 186  11 213 154  11  46  32   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 225 175  15
+238 190  10 236 186  11 112 100  78  42  42  42
+ 14  14  14   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 22  22  22  54  54  54 154 122  46 213 154  11
+226 170  11 230 174  11 226 170  11 226 170  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 184 144  12  10  10  10   2   2   6
+  6   6   6 116 116 116 242 242 242 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 231 231 231 198 198 198 214 170  54
+236 178  12 236 178  12 210 150  10 137  92   6
+ 18  14   6   2   2   6   2   2   6   2   2   6
+  6   6   6  70  47   6 200 144  11 236 178  12
+239 182  13 239 182  13 124 112  88  58  58  58
+ 22  22  22   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  70  70  70 180 133  36 226 170  11
+239 182  13 242 186  14 242 186  14 246 186  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16  98  70   6   2   2   6
+  2   2   6   2   2   6  66  66  66 221 221 221
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 206 206 206 198 198 198 214 166  58
+230 174  11 230 174  11 216 158  10 192 133   9
+163 110   8 116  81   8 102  78  10 116  81   8
+167 114   7 197 138  11 226 170  11 239 182  13
+242 186  14 242 186  14 162 146  94  78  78  78
+ 34  34  34  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 30  30  30  78  78  78 190 142  34 226 170  11
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 241 196  14 203 166  17  22  18   6
+  2   2   6   2   2   6   2   2   6  38  38  38
+218 218 218 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 206 206 206 198 198 198 202 162  69
+226 170  11 236 178  12 224 166  10 210 150  10
+200 144  11 197 138  11 192 133   9 197 138  11
+210 150  10 226 170  11 242 186  14 246 190  14
+246 190  14 246 186  14 225 175  15 124 112  88
+ 62  62  62  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 174 135  50 224 166  10
+239 182  13 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 139 102  15
+  2   2   6   2   2   6   2   2   6   2   2   6
+ 78  78  78 250 250 250 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+250 250 250 214 214 214 198 198 198 190 150  46
+219 162  10 236 178  12 234 174  13 224 166  10
+216 158  10 213 154  11 213 154  11 216 158  10
+226 170  11 239 182  13 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 206 162  42
+101 101 101  58  58  58  30  30  30  14  14  14
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  74  74  74 174 135  50 216 158  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 241 196  14 226 184  13
+ 61  42   6   2   2   6   2   2   6   2   2   6
+ 22  22  22 238 238 238 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 226 226 226 187 187 187 180 133  36
+216 158  10 236 178  12 239 182  13 236 178  12
+230 174  11 226 170  11 226 170  11 230 174  11
+236 178  12 242 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 186  14 239 182  13
+206 162  42 106 106 106  66  66  66  34  34  34
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 213 154  11
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 241 196  14
+190 146  13  18  14   6   2   2   6   2   2   6
+ 46  46  46 246 246 246 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 221 221 221  86  86  86 156 107  11
+216 158  10 236 178  12 242 186  14 246 186  14
+242 186  14 239 182  13 239 182  13 242 186  14
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 225 175  15 142 122  72  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 26  26  26  70  70  70 163 133  67 210 150  10
+236 178  12 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+232 195  16 121  92   8  34  34  34 106 106 106
+221 221 221 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+242 242 242  82  82  82  18  14   6 163 110   8
+216 158  10 236 178  12 242 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 242 186  14 163 133  67
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  10  10  10
+ 30  30  30  78  78  78 163 133  67 210 150  10
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+241 196  14 215 174  15 190 178 144 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 218 218 218
+ 58  58  58   2   2   6  22  18   6 167 114   7
+216 158  10 236 178  12 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 186  14 242 186  14 190 150  46
+ 54  54  54  22  22  22   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 38  38  38  86  86  86 180 133  36 213 154  11
+236 178  12 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 232 195  16 190 146  13 214 214 214
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 250 250 250 170 170 170  26  26  26
+  2   2   6   2   2   6  37  26   9 163 110   8
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 224 166  10 142 122  72
+ 46  46  46  18  18  18   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 109 106  95 192 133   9 224 166  10
+242 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+242 186  14 226 184  13 210 162  10 142 110  46
+226 226 226 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+253 253 253 253 253 253 253 253 253 253 253 253
+198 198 198  66  66  66   2   2   6   2   2   6
+  2   2   6   2   2   6  50  34   6 156 107  11
+219 162  10 239 182  13 246 186  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 242 186  14
+234 174  13 213 154  11 154 122  46  66  66  66
+ 30  30  30  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 58  58  58 154 121  60 206 145  10 234 174  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 236 178  12 210 162  10 163 110   8
+ 61  42   6 138 138 138 218 218 218 250 250 250
+253 253 253 253 253 253 253 253 253 250 250 250
+242 242 242 210 210 210 144 144 144  66  66  66
+  6   6   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6  61  42   6 163 110   8
+216 158  10 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 239 182  13 230 174  11 216 158  10
+190 142  34 124 112  88  70  70  70  38  38  38
+ 18  18  18   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  22  22  22
+ 62  62  62 168 124  44 206 145  10 224 166  10
+236 178  12 239 182  13 242 186  14 242 186  14
+246 186  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 236 178  12 216 158  10 175 118   6
+ 80  54   7   2   2   6   6   6   6  30  30  30
+ 54  54  54  62  62  62  50  50  50  38  38  38
+ 14  14  14   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 167 114   7
+213 154  11 236 178  12 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 190  14 242 186  14 239 182  13 239 182  13
+230 174  11 210 150  10 174 135  50 124 112  88
+ 82  82  82  54  54  54  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  18  18  18
+ 50  50  50 158 118  36 192 133   9 200 144  11
+216 158  10 219 162  10 224 166  10 226 170  11
+230 174  11 236 178  12 239 182  13 239 182  13
+242 186  14 246 186  14 246 190  14 246 190  14
+246 190  14 246 190  14 246 190  14 246 190  14
+246 186  14 230 174  11 210 150  10 163 110   8
+104  69   6  10  10  10   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  91  60   6 167 114   7
+206 145  10 230 174  11 242 186  14 246 190  14
+246 190  14 246 190  14 246 186  14 242 186  14
+239 182  13 230 174  11 224 166  10 213 154  11
+180 133  36 124 112  88  86  86  86  58  58  58
+ 38  38  38  22  22  22  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0  14  14  14
+ 34  34  34  70  70  70 138 110  50 158 118  36
+167 114   7 180 123   7 192 133   9 197 138  11
+200 144  11 206 145  10 213 154  11 219 162  10
+224 166  10 230 174  11 239 182  13 242 186  14
+246 186  14 246 186  14 246 186  14 246 186  14
+239 182  13 216 158  10 185 133  11 152  99   6
+104  69   6  18  14   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   2   2   6   2   2   6   2   2   6
+  2   2   6   6   6   6  80  54   7 152  99   6
+192 133   9 219 162  10 236 178  12 239 182  13
+246 186  14 242 186  14 239 182  13 236 178  12
+224 166  10 206 145  10 192 133   9 154 121  60
+ 94  94  94  62  62  62  42  42  42  22  22  22
+ 14  14  14   6   6   6   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 18  18  18  34  34  34  58  58  58  78  78  78
+101  98  89 124 112  88 142 110  46 156 107  11
+163 110   8 167 114   7 175 118   6 180 123   7
+185 133  11 197 138  11 210 150  10 219 162  10
+226 170  11 236 178  12 236 178  12 234 174  13
+219 162  10 197 138  11 163 110   8 130  83   6
+ 91  60   6  10  10  10   2   2   6   2   2   6
+ 18  18  18  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  38  38  38  38  38  38
+ 38  38  38  38  38  38  26  26  26   2   2   6
+  2   2   6   6   6   6  70  47   6 137  92   6
+175 118   6 200 144  11 219 162  10 230 174  11
+234 174  13 230 174  11 219 162  10 210 150  10
+192 133   9 163 110   8 124 112  88  82  82  82
+ 50  50  50  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  14  14  14  22  22  22  34  34  34
+ 42  42  42  58  58  58  74  74  74  86  86  86
+101  98  89 122 102  70 130  98  46 121  87  25
+137  92   6 152  99   6 163 110   8 180 123   7
+185 133  11 197 138  11 206 145  10 200 144  11
+180 123   7 156 107  11 130  83   6 104  69   6
+ 50  34   6  54  54  54 110 110 110 101  98  89
+ 86  86  86  82  82  82  78  78  78  78  78  78
+ 78  78  78  78  78  78  78  78  78  78  78  78
+ 78  78  78  82  82  82  86  86  86  94  94  94
+106 106 106 101 101 101  86  66  34 124  80   6
+156 107  11 180 123   7 192 133   9 200 144  11
+206 145  10 200 144  11 192 133   9 175 118   6
+139 102  15 109 106  95  70  70  70  42  42  42
+ 22  22  22  10  10  10   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   6   6   6  10  10  10
+ 14  14  14  22  22  22  30  30  30  38  38  38
+ 50  50  50  62  62  62  74  74  74  90  90  90
+101  98  89 112 100  78 121  87  25 124  80   6
+137  92   6 152  99   6 152  99   6 152  99   6
+138  86   6 124  80   6  98  70   6  86  66  30
+101  98  89  82  82  82  58  58  58  46  46  46
+ 38  38  38  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  34  34  34  34  34  34
+ 34  34  34  34  34  34  38  38  38  42  42  42
+ 54  54  54  82  82  82  94  86  76  91  60   6
+134  86   6 156 107  11 167 114   7 175 118   6
+175 118   6 167 114   7 152  99   6 121  87  25
+101  98  89  62  62  62  34  34  34  18  18  18
+  6   6   6   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6   6   6   6  10  10  10
+ 18  18  18  22  22  22  30  30  30  42  42  42
+ 50  50  50  66  66  66  86  86  86 101  98  89
+106  86  58  98  70   6 104  69   6 104  69   6
+104  69   6  91  60   6  82  62  34  90  90  90
+ 62  62  62  38  38  38  22  22  22  14  14  14
+ 10  10  10  10  10  10  10  10  10  10  10  10
+ 10  10  10  10  10  10   6   6   6  10  10  10
+ 10  10  10  10  10  10  10  10  10  14  14  14
+ 22  22  22  42  42  42  70  70  70  89  81  66
+ 80  54   7 104  69   6 124  80   6 137  92   6
+134  86   6 116  81   8 100  82  52  86  86  86
+ 58  58  58  30  30  30  14  14  14   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  10  10  10  14  14  14
+ 18  18  18  26  26  26  38  38  38  54  54  54
+ 70  70  70  86  86  86  94  86  76  89  81  66
+ 89  81  66  86  86  86  74  74  74  50  50  50
+ 30  30  30  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6  18  18  18  34  34  34  58  58  58
+ 82  82  82  89  81  66  89  81  66  89  81  66
+ 94  86  66  94  86  76  74  74  74  50  50  50
+ 26  26  26  14  14  14   6   6   6   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  6   6   6   6   6   6  14  14  14  18  18  18
+ 30  30  30  38  38  38  46  46  46  54  54  54
+ 50  50  50  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   6   6   6  14  14  14  26  26  26
+ 38  38  38  50  50  50  58  58  58  58  58  58
+ 54  54  54  42  42  42  30  30  30  18  18  18
+ 10  10  10   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+  6   6   6  10  10  10  14  14  14  18  18  18
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   6   6   6
+ 14  14  14  18  18  18  22  22  22  22  22  22
+ 18  18  18  14  14  14  10  10  10   6   6   6
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
+  0   0   0   0   0   0   0   0   0   0   0   0
index dbfe2c18a4342dbcc37ffb9806a2e000ddfc379c..b269abd932aab586d57ee62b8198dabbdf37ce21 100644 (file)
@@ -952,7 +952,7 @@ static struct fb_ops ps3fb_ops = {
        .fb_compat_ioctl = ps3fb_ioctl
 };
 
-static struct fb_fix_screeninfo ps3fb_fix __initdata = {
+static struct fb_fix_screeninfo ps3fb_fix = {
        .id =           DEVICE_NAME,
        .type =         FB_TYPE_PACKED_PIXELS,
        .visual =       FB_VISUAL_TRUECOLOR,
index 1aba255b5879a10243c5426abba873103ff15696..98917fc872a429a1ab3aee94cd7d499bc1dafa25 100644 (file)
@@ -766,7 +766,7 @@ static void virtio_pci_remove(struct pci_dev *pci_dev)
        kfree(vp_dev);
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int virtio_pci_freeze(struct device *dev)
 {
        struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -824,7 +824,7 @@ static struct pci_driver virtio_pci_driver = {
        .id_table       = virtio_pci_id_table,
        .probe          = virtio_pci_probe,
        .remove         = virtio_pci_remove,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .driver.pm      = &virtio_pci_pm_ops,
 #endif
 };
index 2bd1257dcc1cb0a1809f544a884a3e1a3dbe9128..efc7f075fcbe2de8f09cbebbf4d0209b765379ed 100644 (file)
@@ -42,7 +42,7 @@ config W1_MASTER_MXC
 
 config W1_MASTER_DS1WM
        tristate "Maxim DS1WM 1-wire busmaster"
-       depends on W1 && GENERIC_HARDIRQS
+       depends on W1
        help
          Say Y here to enable the DS1WM 1-wire driver, such as that
          in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like
index 47e12cfc2a570cb5d379863e7a73dfcfd6711597..15c7251b05563d5cbef5df2aeca278dd4f4a8502 100644 (file)
@@ -152,8 +152,6 @@ static int mxc_w1_remove(struct platform_device *pdev)
 
        clk_disable_unprepare(mdev->clk);
 
-       platform_set_drvdata(pdev, NULL);
-
        return 0;
 }
 
index 22013ca2119ce415e407f48844225eb06d0d30f2..c7c64f18773d87d5f23e81ec90ba7d8bfaee504a 100644 (file)
@@ -234,9 +234,11 @@ static ssize_t w1_master_attribute_store_search(struct device * dev,
 {
        long tmp;
        struct w1_master *md = dev_to_w1_master(dev);
+       int ret;
 
-       if (strict_strtol(buf, 0, &tmp) == -EINVAL)
-               return -EINVAL;
+       ret = kstrtol(buf, 0, &tmp);
+       if (ret)
+               return ret;
 
        mutex_lock(&md->mutex);
        md->search_count = tmp;
@@ -266,9 +268,11 @@ static ssize_t w1_master_attribute_store_pullup(struct device *dev,
 {
        long tmp;
        struct w1_master *md = dev_to_w1_master(dev);
+       int ret;
 
-       if (strict_strtol(buf, 0, &tmp) == -EINVAL)
-               return -EINVAL;
+       ret = kstrtol(buf, 0, &tmp);
+       if (ret)
+               return ret;
 
        mutex_lock(&md->mutex);
        md->enable_pullup = tmp;
index 362085d7ad8fc1787f234039ecb4b9620237657b..d1d53f301de7589960ea07322fdccde47fb3f7fa 100644 (file)
@@ -290,6 +290,16 @@ config ORION_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called orion_wdt.
 
+config SUNXI_WATCHDOG
+       tristate "Allwinner SoCs watchdog support"
+       depends on ARCH_SUNXI
+       select WATCHDOG_CORE
+       help
+         Say Y here to include support for the watchdog timer
+         in Allwinner SoCs.
+         To compile this driver as a module, choose M here: the
+         module will be called sunxi_wdt.
+
 config COH901327_WATCHDOG
        bool "ST-Ericsson COH 901 327 watchdog"
        depends on ARCH_U300
index 2f26a0b47ddc1f701cbd101cc81be713c0e04d77..6c5bb274d3cd22dfa4814e0c4a341e042dcd381c 100644 (file)
@@ -46,6 +46,7 @@ obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
 obj-$(CONFIG_IOP_WATCHDOG) += iop_wdt.o
 obj-$(CONFIG_DAVINCI_WATCHDOG) += davinci_wdt.o
 obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o
+obj-$(CONFIG_SUNXI_WATCHDOG) += sunxi_wdt.o
 obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o
 obj-$(CONFIG_STMP3XXX_RTC_WATCHDOG) += stmp3xxx_rtc_wdt.o
 obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o
index 2f3cc8fb471af041ffc82039b98c461f52d38c3b..b3709f9cf5beab1d5e6d8f51136ae90e3bf23726 100644 (file)
@@ -280,11 +280,6 @@ static int ar7_wdt_probe(struct platform_device *pdev)
 
        ar7_regs_wdt =
                platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
-       if (!ar7_regs_wdt) {
-               pr_err("could not get registers resource\n");
-               return -ENODEV;
-       }
-
        ar7_wdt = devm_ioremap_resource(&pdev->dev, ar7_regs_wdt);
        if (IS_ERR(ar7_wdt))
                return PTR_ERR(ar7_wdt);
index de7e4f497222ffc858d2df762c27003c08874722..5be5e3d14f794a3bdc446b78b5d0bb3fcb9b7fa9 100644 (file)
@@ -162,7 +162,8 @@ extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs,
 #define HPWDT_ARCH     32
 
 asm(".text                          \n\t"
-    ".align 4                       \n"
+    ".align 4                       \n\t"
+    ".globl asminline_call         \n"
     "asminline_call:                \n\t"
     "pushl       %ebp               \n\t"
     "movl        %esp, %ebp         \n\t"
@@ -352,7 +353,8 @@ static int detect_cru_service(void)
 #define HPWDT_ARCH     64
 
 asm(".text                      \n\t"
-    ".align 4                   \n"
+    ".align 4                   \n\t"
+    ".globl asminline_call     \n"
     "asminline_call:            \n\t"
     "pushq      %rbp            \n\t"
     "movq       %rsp, %rbp      \n\t"
index e2b6d2cf5c9d6e48150c3dd52be102ebc85574be..b15b6efd91a146f08d8bac2cc6664172c79b194c 100644 (file)
@@ -256,11 +256,6 @@ static int nuc900wdt_probe(struct platform_device *pdev)
        spin_lock_init(&nuc900_wdt->wdt_lock);
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(&pdev->dev, "no memory resource specified\n");
-               return -ENOENT;
-       }
-
        nuc900_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(nuc900_wdt->wdt_base))
                return PTR_ERR(nuc900_wdt->wdt_base);
index 6a22cf5d35bdde323a94f2aebc20fc3dc4d4264a..23aad7c6bf5d67dac3c4f43064186dc689fe292a 100644 (file)
@@ -84,13 +84,17 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
                        "0 to reboot (default 0)");
 MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
 
-static struct device    *wdt_dev;      /* platform device attached to */
-static struct resource *wdt_mem;
-static struct resource *wdt_irq;
-static struct clk      *wdt_clock;
-static void __iomem    *wdt_base;
-static unsigned int     wdt_count;
-static DEFINE_SPINLOCK(wdt_lock);
+struct s3c2410_wdt {
+       struct device           *dev;
+       struct clk              *clock;
+       void __iomem            *reg_base;
+       unsigned int            count;
+       spinlock_t              lock;
+       unsigned long           wtcon_save;
+       unsigned long           wtdat_save;
+       struct watchdog_device  wdt_device;
+       struct notifier_block   freq_transition;
+};
 
 /* watchdog control routines */
 
@@ -102,29 +106,38 @@ do {                                                      \
 
 /* functions */
 
+static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb)
+{
+       return container_of(nb, struct s3c2410_wdt, freq_transition);
+}
+
 static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
 {
-       spin_lock(&wdt_lock);
-       writel(wdt_count, wdt_base + S3C2410_WTCNT);
-       spin_unlock(&wdt_lock);
+       struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       spin_lock(&wdt->lock);
+       writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
+       spin_unlock(&wdt->lock);
 
        return 0;
 }
 
-static void __s3c2410wdt_stop(void)
+static void __s3c2410wdt_stop(struct s3c2410_wdt *wdt)
 {
        unsigned long wtcon;
 
-       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon = readl(wdt->reg_base + S3C2410_WTCON);
        wtcon &= ~(S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN);
-       writel(wtcon, wdt_base + S3C2410_WTCON);
+       writel(wtcon, wdt->reg_base + S3C2410_WTCON);
 }
 
 static int s3c2410wdt_stop(struct watchdog_device *wdd)
 {
-       spin_lock(&wdt_lock);
-       __s3c2410wdt_stop();
-       spin_unlock(&wdt_lock);
+       struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       spin_lock(&wdt->lock);
+       __s3c2410wdt_stop(wdt);
+       spin_unlock(&wdt->lock);
 
        return 0;
 }
@@ -132,12 +145,13 @@ static int s3c2410wdt_stop(struct watchdog_device *wdd)
 static int s3c2410wdt_start(struct watchdog_device *wdd)
 {
        unsigned long wtcon;
+       struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
 
-       spin_lock(&wdt_lock);
+       spin_lock(&wdt->lock);
 
-       __s3c2410wdt_stop();
+       __s3c2410wdt_stop(wdt);
 
-       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon = readl(wdt->reg_base + S3C2410_WTCON);
        wtcon |= S3C2410_WTCON_ENABLE | S3C2410_WTCON_DIV128;
 
        if (soft_noboot) {
@@ -148,25 +162,26 @@ static int s3c2410wdt_start(struct watchdog_device *wdd)
                wtcon |= S3C2410_WTCON_RSTEN;
        }
 
-       DBG("%s: wdt_count=0x%08x, wtcon=%08lx\n",
-           __func__, wdt_count, wtcon);
+       DBG("%s: count=0x%08x, wtcon=%08lx\n",
+           __func__, wdt->count, wtcon);
 
-       writel(wdt_count, wdt_base + S3C2410_WTDAT);
-       writel(wdt_count, wdt_base + S3C2410_WTCNT);
-       writel(wtcon, wdt_base + S3C2410_WTCON);
-       spin_unlock(&wdt_lock);
+       writel(wdt->count, wdt->reg_base + S3C2410_WTDAT);
+       writel(wdt->count, wdt->reg_base + S3C2410_WTCNT);
+       writel(wtcon, wdt->reg_base + S3C2410_WTCON);
+       spin_unlock(&wdt->lock);
 
        return 0;
 }
 
-static inline int s3c2410wdt_is_running(void)
+static inline int s3c2410wdt_is_running(struct s3c2410_wdt *wdt)
 {
-       return readl(wdt_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
+       return readl(wdt->reg_base + S3C2410_WTCON) & S3C2410_WTCON_ENABLE;
 }
 
 static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeout)
 {
-       unsigned long freq = clk_get_rate(wdt_clock);
+       struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
+       unsigned long freq = clk_get_rate(wdt->clock);
        unsigned int count;
        unsigned int divisor = 1;
        unsigned long wtcon;
@@ -192,7 +207,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
                }
 
                if ((count / divisor) >= 0x10000) {
-                       dev_err(wdt_dev, "timeout %d too big\n", timeout);
+                       dev_err(wdt->dev, "timeout %d too big\n", timeout);
                        return -EINVAL;
                }
        }
@@ -201,15 +216,15 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
            __func__, timeout, divisor, count, count/divisor);
 
        count /= divisor;
-       wdt_count = count;
+       wdt->count = count;
 
        /* update the pre-scaler */
-       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon = readl(wdt->reg_base + S3C2410_WTCON);
        wtcon &= ~S3C2410_WTCON_PRESCALE_MASK;
        wtcon |= S3C2410_WTCON_PRESCALE(divisor-1);
 
-       writel(count, wdt_base + S3C2410_WTDAT);
-       writel(wtcon, wdt_base + S3C2410_WTCON);
+       writel(count, wdt->reg_base + S3C2410_WTDAT);
+       writel(wtcon, wdt->reg_base + S3C2410_WTCON);
 
        wdd->timeout = (count * divisor) / freq;
 
@@ -242,21 +257,23 @@ static struct watchdog_device s3c2410_wdd = {
 
 static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
 {
-       dev_info(wdt_dev, "watchdog timer expired (irq)\n");
+       struct s3c2410_wdt *wdt = platform_get_drvdata(param);
+
+       dev_info(wdt->dev, "watchdog timer expired (irq)\n");
 
-       s3c2410wdt_keepalive(&s3c2410_wdd);
+       s3c2410wdt_keepalive(&wdt->wdt_device);
        return IRQ_HANDLED;
 }
 
-
 #ifdef CONFIG_CPU_FREQ
 
 static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
                                          unsigned long val, void *data)
 {
        int ret;
+       struct s3c2410_wdt *wdt = freq_to_wdt(nb);
 
-       if (!s3c2410wdt_is_running())
+       if (!s3c2410wdt_is_running(wdt))
                goto done;
 
        if (val == CPUFREQ_PRECHANGE) {
@@ -265,14 +282,15 @@ static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
                 * the watchdog is running.
                 */
 
-               s3c2410wdt_keepalive(&s3c2410_wdd);
+               s3c2410wdt_keepalive(&wdt->wdt_device);
        } else if (val == CPUFREQ_POSTCHANGE) {
-               s3c2410wdt_stop(&s3c2410_wdd);
+               s3c2410wdt_stop(&wdt->wdt_device);
 
-               ret = s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout);
+               ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
+                                               wdt->wdt_device.timeout);
 
                if (ret >= 0)
-                       s3c2410wdt_start(&s3c2410_wdd);
+                       s3c2410wdt_start(&wdt->wdt_device);
                else
                        goto err;
        }
@@ -281,34 +299,35 @@ done:
        return 0;
 
  err:
-       dev_err(wdt_dev, "cannot set new value for timeout %d\n",
-                               s3c2410_wdd.timeout);
+       dev_err(wdt->dev, "cannot set new value for timeout %d\n",
+                               wdt->wdt_device.timeout);
        return ret;
 }
 
-static struct notifier_block s3c2410wdt_cpufreq_transition_nb = {
-       .notifier_call  = s3c2410wdt_cpufreq_transition,
-};
-
-static inline int s3c2410wdt_cpufreq_register(void)
+static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt)
 {
-       return cpufreq_register_notifier(&s3c2410wdt_cpufreq_transition_nb,
+       wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition;
+
+       return cpufreq_register_notifier(&wdt->freq_transition,
                                         CPUFREQ_TRANSITION_NOTIFIER);
 }
 
-static inline void s3c2410wdt_cpufreq_deregister(void)
+static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 {
-       cpufreq_unregister_notifier(&s3c2410wdt_cpufreq_transition_nb,
+       wdt->freq_transition.notifier_call = s3c2410wdt_cpufreq_transition;
+
+       cpufreq_unregister_notifier(&wdt->freq_transition,
                                    CPUFREQ_TRANSITION_NOTIFIER);
 }
 
 #else
-static inline int s3c2410wdt_cpufreq_register(void)
+
+static inline int s3c2410wdt_cpufreq_register(struct s3c2410_wdt *wdt)
 {
        return 0;
 }
 
-static inline void s3c2410wdt_cpufreq_deregister(void)
+static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 {
 }
 #endif
@@ -316,6 +335,9 @@ static inline void s3c2410wdt_cpufreq_deregister(void)
 static int s3c2410wdt_probe(struct platform_device *pdev)
 {
        struct device *dev;
+       struct s3c2410_wdt *wdt;
+       struct resource *wdt_mem;
+       struct resource *wdt_irq;
        unsigned int wtcon;
        int started = 0;
        int ret;
@@ -323,13 +345,14 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        DBG("%s: probe=%p\n", __func__, pdev);
 
        dev = &pdev->dev;
-       wdt_dev = &pdev->dev;
 
-       wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (wdt_mem == NULL) {
-               dev_err(dev, "no memory resource specified\n");
-               return -ENOENT;
-       }
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       wdt->dev = &pdev->dev;
+       spin_lock_init(&wdt->lock);
+       wdt->wdt_device = s3c2410_wdd;
 
        wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (wdt_irq == NULL) {
@@ -339,35 +362,40 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        }
 
        /* get the memory region for the watchdog timer */
-       wdt_base = devm_ioremap_resource(dev, wdt_mem);
-       if (IS_ERR(wdt_base)) {
-               ret = PTR_ERR(wdt_base);
+       wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->reg_base = devm_ioremap_resource(dev, wdt_mem);
+       if (IS_ERR(wdt->reg_base)) {
+               ret = PTR_ERR(wdt->reg_base);
                goto err;
        }
 
-       DBG("probe: mapped wdt_base=%p\n", wdt_base);
+       DBG("probe: mapped reg_base=%p\n", wdt->reg_base);
 
-       wdt_clock = devm_clk_get(dev, "watchdog");
-       if (IS_ERR(wdt_clock)) {
+       wdt->clock = devm_clk_get(dev, "watchdog");
+       if (IS_ERR(wdt->clock)) {
                dev_err(dev, "failed to find watchdog clock source\n");
-               ret = PTR_ERR(wdt_clock);
+               ret = PTR_ERR(wdt->clock);
                goto err;
        }
 
-       clk_prepare_enable(wdt_clock);
+       clk_prepare_enable(wdt->clock);
 
-       ret = s3c2410wdt_cpufreq_register();
+       ret = s3c2410wdt_cpufreq_register(wdt);
        if (ret < 0) {
                dev_err(dev, "failed to register cpufreq\n");
                goto err_clk;
        }
 
+       watchdog_set_drvdata(&wdt->wdt_device, wdt);
+
        /* see if we can actually set the requested timer margin, and if
         * not, try the default value */
 
-       watchdog_init_timeout(&s3c2410_wdd, tmr_margin,  &pdev->dev);
-       if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, s3c2410_wdd.timeout)) {
-               started = s3c2410wdt_set_heartbeat(&s3c2410_wdd,
+       watchdog_init_timeout(&wdt->wdt_device, tmr_margin, &pdev->dev);
+       ret = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
+                                       wdt->wdt_device.timeout);
+       if (ret) {
+               started = s3c2410wdt_set_heartbeat(&wdt->wdt_device,
                                        CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
 
                if (started == 0)
@@ -386,9 +414,9 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
                goto err_cpufreq;
        }
 
-       watchdog_set_nowayout(&s3c2410_wdd, nowayout);
+       watchdog_set_nowayout(&wdt->wdt_device, nowayout);
 
-       ret = watchdog_register_device(&s3c2410_wdd);
+       ret = watchdog_register_device(&wdt->wdt_device);
        if (ret) {
                dev_err(dev, "cannot register watchdog (%d)\n", ret);
                goto err_cpufreq;
@@ -396,18 +424,20 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        if (tmr_atboot && started == 0) {
                dev_info(dev, "starting watchdog timer\n");
-               s3c2410wdt_start(&s3c2410_wdd);
+               s3c2410wdt_start(&wdt->wdt_device);
        } else if (!tmr_atboot) {
                /* if we're not enabling the watchdog, then ensure it is
                 * disabled if it has been left running from the bootloader
                 * or other source */
 
-               s3c2410wdt_stop(&s3c2410_wdd);
+               s3c2410wdt_stop(&wdt->wdt_device);
        }
 
+       platform_set_drvdata(pdev, wdt);
+
        /* print out a statement of readiness */
 
-       wtcon = readl(wdt_base + S3C2410_WTCON);
+       wtcon = readl(wdt->reg_base + S3C2410_WTCON);
 
        dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
                 (wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",
@@ -417,64 +447,64 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        return 0;
 
  err_cpufreq:
-       s3c2410wdt_cpufreq_deregister();
+       s3c2410wdt_cpufreq_deregister(wdt);
 
  err_clk:
-       clk_disable_unprepare(wdt_clock);
-       wdt_clock = NULL;
+       clk_disable_unprepare(wdt->clock);
+       wdt->clock = NULL;
 
  err:
-       wdt_irq = NULL;
-       wdt_mem = NULL;
        return ret;
 }
 
 static int s3c2410wdt_remove(struct platform_device *dev)
 {
-       watchdog_unregister_device(&s3c2410_wdd);
+       struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
 
-       s3c2410wdt_cpufreq_deregister();
+       watchdog_unregister_device(&wdt->wdt_device);
 
-       clk_disable_unprepare(wdt_clock);
-       wdt_clock = NULL;
+       s3c2410wdt_cpufreq_deregister(wdt);
+
+       clk_disable_unprepare(wdt->clock);
+       wdt->clock = NULL;
 
-       wdt_irq = NULL;
-       wdt_mem = NULL;
        return 0;
 }
 
 static void s3c2410wdt_shutdown(struct platform_device *dev)
 {
-       s3c2410wdt_stop(&s3c2410_wdd);
+       struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
+
+       s3c2410wdt_stop(&wdt->wdt_device);
 }
 
 #ifdef CONFIG_PM_SLEEP
 
-static unsigned long wtcon_save;
-static unsigned long wtdat_save;
-
 static int s3c2410wdt_suspend(struct device *dev)
 {
+       struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
+
        /* Save watchdog state, and turn it off. */
-       wtcon_save = readl(wdt_base + S3C2410_WTCON);
-       wtdat_save = readl(wdt_base + S3C2410_WTDAT);
+       wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON);
+       wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT);
 
        /* Note that WTCNT doesn't need to be saved. */
-       s3c2410wdt_stop(&s3c2410_wdd);
+       s3c2410wdt_stop(&wdt->wdt_device);
 
        return 0;
 }
 
 static int s3c2410wdt_resume(struct device *dev)
 {
-       /* Restore watchdog state. */
+       struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
 
-       writel(wtdat_save, wdt_base + S3C2410_WTDAT);
-       writel(wtdat_save, wdt_base + S3C2410_WTCNT); /* Reset count */
-       writel(wtcon_save, wdt_base + S3C2410_WTCON);
+       /* Restore watchdog state. */
+       writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTDAT);
+       writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */
+       writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON);
 
        dev_info(dev, "watchdog %sabled\n",
-               (wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
+               (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
 
        return 0;
 }
diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c
new file mode 100644 (file)
index 0000000..1f94b42
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ *      sunxi Watchdog Driver
+ *
+ *      Copyright (c) 2013 Carlo Caione
+ *                    2012 Henrik Nordstrom
+ *
+ *      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.
+ *
+ *      Based on xen_wdt.c
+ *      (c) Copyright 2010 Novell, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+
+#define WDT_MAX_TIMEOUT         16
+#define WDT_MIN_TIMEOUT         1
+#define WDT_MODE_TIMEOUT(n)     ((n) << 3)
+#define WDT_TIMEOUT_MASK        WDT_MODE_TIMEOUT(0x0F)
+
+#define WDT_CTRL                0x00
+#define WDT_CTRL_RELOAD         ((1 << 0) | (0x0a57 << 1))
+
+#define WDT_MODE                0x04
+#define WDT_MODE_EN             (1 << 0)
+#define WDT_MODE_RST_EN         (1 << 1)
+
+#define DRV_NAME               "sunxi-wdt"
+#define DRV_VERSION            "1.0"
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int timeout = WDT_MAX_TIMEOUT;
+
+struct sunxi_wdt_dev {
+       struct watchdog_device wdt_dev;
+       void __iomem *wdt_base;
+};
+
+/*
+ * wdt_timeout_map maps the watchdog timer interval value in seconds to
+ * the value of the register WDT_MODE bit 3:6
+ *
+ * [timeout seconds] = register value
+ *
+ */
+
+static const int wdt_timeout_map[] = {
+       [1] = 0b0001,  /* 1s  */
+       [2] = 0b0010,  /* 2s  */
+       [3] = 0b0011,  /* 3s  */
+       [4] = 0b0100,  /* 4s  */
+       [5] = 0b0101,  /* 5s  */
+       [6] = 0b0110,  /* 6s  */
+       [8] = 0b0111,  /* 8s  */
+       [10] = 0b1000, /* 10s */
+       [12] = 0b1001, /* 12s */
+       [14] = 0b1010, /* 14s */
+       [16] = 0b1011, /* 16s */
+};
+
+static int sunxi_wdt_ping(struct watchdog_device *wdt_dev)
+{
+       struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
+       void __iomem *wdt_base = sunxi_wdt->wdt_base;
+
+       iowrite32(WDT_CTRL_RELOAD, wdt_base + WDT_CTRL);
+
+       return 0;
+}
+
+static int sunxi_wdt_set_timeout(struct watchdog_device *wdt_dev,
+               unsigned int timeout)
+{
+       struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
+       void __iomem *wdt_base = sunxi_wdt->wdt_base;
+       u32 reg;
+
+       if (wdt_timeout_map[timeout] == 0)
+               timeout++;
+
+       sunxi_wdt->wdt_dev.timeout = timeout;
+
+       reg = ioread32(wdt_base + WDT_MODE);
+       reg &= ~WDT_TIMEOUT_MASK;
+       reg |= WDT_MODE_TIMEOUT(wdt_timeout_map[timeout]);
+       iowrite32(reg, wdt_base + WDT_MODE);
+
+       sunxi_wdt_ping(wdt_dev);
+
+       return 0;
+}
+
+static int sunxi_wdt_stop(struct watchdog_device *wdt_dev)
+{
+       struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
+       void __iomem *wdt_base = sunxi_wdt->wdt_base;
+
+       iowrite32(0, wdt_base + WDT_MODE);
+
+       return 0;
+}
+
+static int sunxi_wdt_start(struct watchdog_device *wdt_dev)
+{
+       u32 reg;
+       struct sunxi_wdt_dev *sunxi_wdt = watchdog_get_drvdata(wdt_dev);
+       void __iomem *wdt_base = sunxi_wdt->wdt_base;
+       int ret;
+
+       ret = sunxi_wdt_set_timeout(&sunxi_wdt->wdt_dev,
+                       sunxi_wdt->wdt_dev.timeout);
+       if (ret < 0)
+               return ret;
+
+       reg = ioread32(wdt_base + WDT_MODE);
+       reg |= (WDT_MODE_RST_EN | WDT_MODE_EN);
+       iowrite32(reg, wdt_base + WDT_MODE);
+
+       return 0;
+}
+
+static const struct watchdog_info sunxi_wdt_info = {
+       .identity       = DRV_NAME,
+       .options        = WDIOF_SETTIMEOUT |
+                         WDIOF_KEEPALIVEPING |
+                         WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops sunxi_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = sunxi_wdt_start,
+       .stop           = sunxi_wdt_stop,
+       .ping           = sunxi_wdt_ping,
+       .set_timeout    = sunxi_wdt_set_timeout,
+};
+
+static int __init sunxi_wdt_probe(struct platform_device *pdev)
+{
+       struct sunxi_wdt_dev *sunxi_wdt;
+       struct resource *res;
+       int err;
+
+       sunxi_wdt = devm_kzalloc(&pdev->dev, sizeof(*sunxi_wdt), GFP_KERNEL);
+       if (!sunxi_wdt)
+               return -EINVAL;
+
+       platform_set_drvdata(pdev, sunxi_wdt);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sunxi_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(sunxi_wdt->wdt_base))
+               return PTR_ERR(sunxi_wdt->wdt_base);
+
+       sunxi_wdt->wdt_dev.info = &sunxi_wdt_info;
+       sunxi_wdt->wdt_dev.ops = &sunxi_wdt_ops;
+       sunxi_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
+       sunxi_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
+       sunxi_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
+       sunxi_wdt->wdt_dev.parent = &pdev->dev;
+
+       watchdog_init_timeout(&sunxi_wdt->wdt_dev, timeout, &pdev->dev);
+       watchdog_set_nowayout(&sunxi_wdt->wdt_dev, nowayout);
+
+       watchdog_set_drvdata(&sunxi_wdt->wdt_dev, sunxi_wdt);
+
+       sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
+
+       err = watchdog_register_device(&sunxi_wdt->wdt_dev);
+       if (unlikely(err))
+               return err;
+
+       dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)",
+                       sunxi_wdt->wdt_dev.timeout, nowayout);
+
+       return 0;
+}
+
+static int __exit sunxi_wdt_remove(struct platform_device *pdev)
+{
+       struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&sunxi_wdt->wdt_dev);
+       watchdog_set_drvdata(&sunxi_wdt->wdt_dev, NULL);
+
+       return 0;
+}
+
+static void sunxi_wdt_shutdown(struct platform_device *pdev)
+{
+       struct sunxi_wdt_dev *sunxi_wdt = platform_get_drvdata(pdev);
+
+       sunxi_wdt_stop(&sunxi_wdt->wdt_dev);
+}
+
+static const struct of_device_id sunxi_wdt_dt_ids[] = {
+       { .compatible = "allwinner,sun4i-wdt" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sunxi_wdt_dt_ids);
+
+static struct platform_driver sunxi_wdt_driver = {
+       .probe          = sunxi_wdt_probe,
+       .remove         = sunxi_wdt_remove,
+       .shutdown       = sunxi_wdt_shutdown,
+       .driver         = {
+               .owner          = THIS_MODULE,
+               .name           = DRV_NAME,
+               .of_match_table = of_match_ptr(sunxi_wdt_dt_ids)
+       },
+};
+
+module_platform_driver(sunxi_wdt_driver);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds");
+
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+               "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Carlo Caione <carlo.caione@gmail.com>");
+MODULE_AUTHOR("Henrik Nordstrom <henrik@henriknordstrom.net>");
+MODULE_DESCRIPTION("sunxi WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
index 4da59b4d73f006a4caea2a41c1f6d8b950790f49..42913f131dc2b051cdb89db52e72726bb228dd61 100644 (file)
@@ -403,21 +403,11 @@ static int ts72xx_wdt_probe(struct platform_device *pdev)
        }
 
        r1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r1) {
-               dev_err(&pdev->dev, "failed to get memory resource\n");
-               return -ENODEV;
-       }
-
        wdt->control_reg = devm_ioremap_resource(&pdev->dev, r1);
        if (IS_ERR(wdt->control_reg))
                return PTR_ERR(wdt->control_reg);
 
        r2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!r2) {
-               dev_err(&pdev->dev, "failed to get memory resource\n");
-               return -ENODEV;
-       }
-
        wdt->feed_reg = devm_ioremap_resource(&pdev->dev, r2);
        if (IS_ERR(wdt->feed_reg))
                return PTR_ERR(wdt->feed_reg);
index 3101cf6daf5662440682ee5746a5b15d2da04d6c..a50c6e3a7cc4824db07f43e84732ee64a58b65cb 100644 (file)
@@ -349,8 +349,6 @@ static enum bp_state increase_reservation(unsigned long nr_pages)
                BUG_ON(page == NULL);
 
                pfn = page_to_pfn(page);
-               BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) &&
-                      phys_to_machine_mapping_valid(pfn));
 
                set_phys_to_machine(pfn, frame_list[i]);
 
@@ -380,6 +378,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
        enum bp_state state = BP_DONE;
        unsigned long  pfn, i;
        struct page   *page;
+       struct page   *scratch_page;
        int ret;
        struct xen_memory_reservation reservation = {
                .address_bits = 0,
@@ -399,6 +398,8 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
        if (nr_pages > ARRAY_SIZE(frame_list))
                nr_pages = ARRAY_SIZE(frame_list);
 
+       scratch_page = get_balloon_scratch_page();
+
        for (i = 0; i < nr_pages; i++) {
                page = alloc_page(gfp);
                if (page == NULL) {
@@ -416,7 +417,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                if (xen_pv_domain() && !PageHighMem(page)) {
                        ret = HYPERVISOR_update_va_mapping(
                                (unsigned long)__va(pfn << PAGE_SHIFT),
-                               pfn_pte(page_to_pfn(__get_cpu_var(balloon_scratch_page)),
+                               pfn_pte(page_to_pfn(scratch_page),
                                        PAGE_KERNEL_RO), 0);
                        BUG_ON(ret);
                }
@@ -432,14 +433,14 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
                pfn = mfn_to_pfn(frame_list[i]);
                if (!xen_feature(XENFEAT_auto_translated_physmap)) {
                        unsigned long p;
-                       struct page *pg;
-                       pg = __get_cpu_var(balloon_scratch_page);
-                       p = page_to_pfn(pg);
+                       p = page_to_pfn(scratch_page);
                        __set_phys_to_machine(pfn, pfn_to_mfn(p));
                }
                balloon_append(pfn_to_page(pfn));
        }
 
+       put_balloon_scratch_page();
+
        set_xen_guest_handle(reservation.extent_start, frame_list);
        reservation.nr_extents   = nr_pages;
        ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
index 58e6cbce4156fb37a9820297e3a35c83d3524e81..08f2e1e9a7e6a4b66d08ea92e5ddf834dcb9d4a4 100644 (file)
@@ -603,10 +603,11 @@ static int v9fs_cache_register(void)
        if (ret < 0)
                return ret;
 #ifdef CONFIG_9P_FSCACHE
-       return fscache_register_netfs(&v9fs_cache_netfs);
-#else
-       return ret;
+       ret = fscache_register_netfs(&v9fs_cache_netfs);
+       if (ret < 0)
+               v9fs_destroy_inode_cache();
 #endif
+       return ret;
 }
 
 static void v9fs_cache_unregister(void)
index d384a8b77ee8a705fe9763de2257b3c43224b816..aa5ecf479a57bf1614100011de047d8c184c620e 100644 (file)
@@ -183,7 +183,7 @@ static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
        else
                flock.length = fl->fl_end - fl->fl_start + 1;
        flock.proc_id = fl->fl_pid;
-       flock.client_id = utsname()->nodename;
+       flock.client_id = fid->clnt->name;
        if (IS_SETLKW(cmd))
                flock.flags = P9_LOCK_FLAGS_BLOCK;
 
@@ -260,7 +260,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
        else
                glock.length = fl->fl_end - fl->fl_start + 1;
        glock.proc_id = fl->fl_pid;
-       glock.client_id = utsname()->nodename;
+       glock.client_id = fid->clnt->name;
 
        res = p9_client_getlock_dotl(fid, &glock);
        if (res < 0)
index 25b018efb8abd8bb82189daf711a9fa4372f3c54..94de6d1482e2e076c4b3d10451c39fc245cce6ef 100644 (file)
@@ -146,7 +146,7 @@ static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses,
                char type = 0, ext[32];
                int major = -1, minor = -1;
 
-               strncpy(ext, stat->extension, sizeof(ext));
+               strlcpy(ext, stat->extension, sizeof(ext));
                sscanf(ext, "%c %u %u", &type, &major, &minor);
                switch (type) {
                case 'c':
@@ -1186,7 +1186,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
                         * this even with .u extension. So check
                         * for non NULL stat->extension
                         */
-                       strncpy(ext, stat->extension, sizeof(ext));
+                       strlcpy(ext, stat->extension, sizeof(ext));
                        /* HARDLINKCOUNT %u */
                        sscanf(ext, "%13s %u", tag_name, &i_nlink);
                        if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
index 53687bbf2296f8b799583786b16b59a574369f9e..a7c481402c4654416106d22d1ed7d85f65f6f8e1 100644 (file)
@@ -267,14 +267,8 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
        }
 
        /* Only creates */
-       if (!(flags & O_CREAT))
+       if (!(flags & O_CREAT) || dentry->d_inode)
                return  finish_no_open(file, res);
-       else if (dentry->d_inode) {
-               if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
-                       return -EEXIST;
-               else
-                       return finish_no_open(file, res);
-       }
 
        v9ses = v9fs_inode2v9ses(dir);
 
index 5f95d1ed9c6dbf882e3b73e85b6cf0469f7d63af..b9acadafa4a10780d92c6d520008406fce4d5ddc 100644 (file)
@@ -50,7 +50,7 @@ static void adfs_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);
+               truncate_pagecache(inode, inode->i_size);
 }
 
 static int adfs_write_begin(struct file *file, struct address_space *mapping,
index af3261b781021f0a51dda6b73b5fb5b3d051baa7..8669b6ecddee4cc030e21f39358ce2cf5058bddb 100644 (file)
@@ -406,7 +406,7 @@ static void affs_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);
+               truncate_pagecache(inode, inode->i_size);
                affs_truncate(inode);
        }
 }
@@ -836,7 +836,7 @@ affs_truncate(struct inode *inode)
                struct address_space *mapping = inode->i_mapping;
                struct page *page;
                void *fsdata;
-               u32 size = inode->i_size;
+               loff_t size = inode->i_size;
                int res;
 
                res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
index 0b74d3176ab7c9293c0583e1b2cff730e7f4df0d..646337dc5201e702227309cc17db99f96af99173 100644 (file)
@@ -751,10 +751,6 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        _enter("{%x:%u},{%s},%ho",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
-       ret = -ENAMETOOLONG;
-       if (dentry->d_name.len >= AFSNAMEMAX)
-               goto error;
-
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
@@ -816,10 +812,6 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
        _enter("{%x:%u},{%s}",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
 
-       ret = -ENAMETOOLONG;
-       if (dentry->d_name.len >= AFSNAMEMAX)
-               goto error;
-
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
@@ -936,10 +928,6 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
        _enter("{%x:%u},{%s},%ho,",
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
 
-       ret = -ENAMETOOLONG;
-       if (dentry->d_name.len >= AFSNAMEMAX)
-               goto error;
-
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
@@ -1005,10 +993,6 @@ static int afs_link(struct dentry *from, struct inode *dir,
               dvnode->fid.vid, dvnode->fid.vnode,
               dentry->d_name.name);
 
-       ret = -ENAMETOOLONG;
-       if (dentry->d_name.len >= AFSNAMEMAX)
-               goto error;
-
        key = afs_request_key(dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
@@ -1053,10 +1037,6 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
               dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
               content);
 
-       ret = -ENAMETOOLONG;
-       if (dentry->d_name.len >= AFSNAMEMAX)
-               goto error;
-
        ret = -EINVAL;
        if (strlen(content) >= AFSPATHMAX)
                goto error;
@@ -1127,10 +1107,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
               new_dvnode->fid.vid, new_dvnode->fid.vnode,
               new_dentry->d_name.name);
 
-       ret = -ENAMETOOLONG;
-       if (new_dentry->d_name.len >= AFSNAMEMAX)
-               goto error;
-
        key = afs_request_key(orig_dvnode->volume->cell);
        if (IS_ERR(key)) {
                ret = PTR_ERR(key);
index 9b5ca113741948d95330d866e8e4e2cce113f3e5..6b868f0e0c4c019c3b68712ca230deb979711a98 100644 (file)
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -26,6 +26,7 @@
 #include <linux/mm.h>
 #include <linux/mman.h>
 #include <linux/mmu_context.h>
+#include <linux/percpu.h>
 #include <linux/slab.h>
 #include <linux/timer.h>
 #include <linux/aio.h>
 #include <linux/eventfd.h>
 #include <linux/blkdev.h>
 #include <linux/compat.h>
+#include <linux/anon_inodes.h>
+#include <linux/migrate.h>
+#include <linux/ramfs.h>
+#include <linux/percpu-refcount.h>
 
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
@@ -61,14 +66,29 @@ struct aio_ring {
 
 #define AIO_RING_PAGES 8
 
+struct kioctx_table {
+       struct rcu_head rcu;
+       unsigned        nr;
+       struct kioctx   *table[];
+};
+
+struct kioctx_cpu {
+       unsigned                reqs_available;
+};
+
 struct kioctx {
-       atomic_t                users;
+       struct percpu_ref       users;
        atomic_t                dead;
 
-       /* This needs improving */
        unsigned long           user_id;
-       struct hlist_node       list;
 
+       struct __percpu kioctx_cpu *cpu;
+
+       /*
+        * For percpu reqs_available, number of slots we move to/from global
+        * counter at a time:
+        */
+       unsigned                req_batch;
        /*
         * This is what userspace passed to io_setup(), it's not used for
         * anything but counting against the global max_reqs quota.
@@ -88,10 +108,18 @@ struct kioctx {
        long                    nr_pages;
 
        struct rcu_head         rcu_head;
-       struct work_struct      rcu_work;
+       struct work_struct      free_work;
 
        struct {
-               atomic_t        reqs_active;
+               /*
+                * This counts the number of available slots in the ringbuffer,
+                * so we avoid overflowing it: it's decremented (if positive)
+                * when allocating a kiocb and incremented when the resulting
+                * io_event is pulled off the ringbuffer.
+                *
+                * We batch accesses to it with a percpu version.
+                */
+               atomic_t        reqs_available;
        } ____cacheline_aligned_in_smp;
 
        struct {
@@ -110,6 +138,9 @@ struct kioctx {
        } ____cacheline_aligned_in_smp;
 
        struct page             *internal_pages[AIO_RING_PAGES];
+       struct file             *aio_ring_file;
+
+       unsigned                id;
 };
 
 /*------ sysctl variables----*/
@@ -138,15 +169,77 @@ __initcall(aio_setup);
 
 static void aio_free_ring(struct kioctx *ctx)
 {
-       long i;
+       int i;
+       struct file *aio_ring_file = ctx->aio_ring_file;
 
-       for (i = 0; i < ctx->nr_pages; i++)
+       for (i = 0; i < ctx->nr_pages; i++) {
+               pr_debug("pid(%d) [%d] page->count=%d\n", current->pid, i,
+                               page_count(ctx->ring_pages[i]));
                put_page(ctx->ring_pages[i]);
+       }
 
        if (ctx->ring_pages && ctx->ring_pages != ctx->internal_pages)
                kfree(ctx->ring_pages);
+
+       if (aio_ring_file) {
+               truncate_setsize(aio_ring_file->f_inode, 0);
+               fput(aio_ring_file);
+               ctx->aio_ring_file = NULL;
+       }
+}
+
+static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       vma->vm_ops = &generic_file_vm_ops;
+       return 0;
 }
 
+static const struct file_operations aio_ring_fops = {
+       .mmap = aio_ring_mmap,
+};
+
+static int aio_set_page_dirty(struct page *page)
+{
+       return 0;
+}
+
+#if IS_ENABLED(CONFIG_MIGRATION)
+static int aio_migratepage(struct address_space *mapping, struct page *new,
+                       struct page *old, enum migrate_mode mode)
+{
+       struct kioctx *ctx = mapping->private_data;
+       unsigned long flags;
+       unsigned idx = old->index;
+       int rc;
+
+       /* Writeback must be complete */
+       BUG_ON(PageWriteback(old));
+       put_page(old);
+
+       rc = migrate_page_move_mapping(mapping, new, old, NULL, mode);
+       if (rc != MIGRATEPAGE_SUCCESS) {
+               get_page(old);
+               return rc;
+       }
+
+       get_page(new);
+
+       spin_lock_irqsave(&ctx->completion_lock, flags);
+       migrate_page_copy(new, old);
+       ctx->ring_pages[idx] = new;
+       spin_unlock_irqrestore(&ctx->completion_lock, flags);
+
+       return rc;
+}
+#endif
+
+static const struct address_space_operations aio_ctx_aops = {
+       .set_page_dirty = aio_set_page_dirty,
+#if IS_ENABLED(CONFIG_MIGRATION)
+       .migratepage    = aio_migratepage,
+#endif
+};
+
 static int aio_setup_ring(struct kioctx *ctx)
 {
        struct aio_ring *ring;
@@ -154,20 +247,45 @@ static int aio_setup_ring(struct kioctx *ctx)
        struct mm_struct *mm = current->mm;
        unsigned long size, populate;
        int nr_pages;
+       int i;
+       struct file *file;
 
        /* Compensate for the ring buffer's head/tail overlap entry */
        nr_events += 2; /* 1 is required, 2 for good luck */
 
        size = sizeof(struct aio_ring);
        size += sizeof(struct io_event) * nr_events;
-       nr_pages = (size + PAGE_SIZE-1) >> PAGE_SHIFT;
 
+       nr_pages = PFN_UP(size);
        if (nr_pages < 0)
                return -EINVAL;
 
-       nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) / sizeof(struct io_event);
+       file = anon_inode_getfile_private("[aio]", &aio_ring_fops, ctx, O_RDWR);
+       if (IS_ERR(file)) {
+               ctx->aio_ring_file = NULL;
+               return -EAGAIN;
+       }
+
+       file->f_inode->i_mapping->a_ops = &aio_ctx_aops;
+       file->f_inode->i_mapping->private_data = ctx;
+       file->f_inode->i_size = PAGE_SIZE * (loff_t)nr_pages;
+
+       for (i = 0; i < nr_pages; i++) {
+               struct page *page;
+               page = find_or_create_page(file->f_inode->i_mapping,
+                                          i, GFP_HIGHUSER | __GFP_ZERO);
+               if (!page)
+                       break;
+               pr_debug("pid(%d) page[%d]->count=%d\n",
+                        current->pid, i, page_count(page));
+               SetPageUptodate(page);
+               SetPageDirty(page);
+               unlock_page(page);
+       }
+       ctx->aio_ring_file = file;
+       nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring))
+                       / sizeof(struct io_event);
 
-       ctx->nr_events = 0;
        ctx->ring_pages = ctx->internal_pages;
        if (nr_pages > AIO_RING_PAGES) {
                ctx->ring_pages = kcalloc(nr_pages, sizeof(struct page *),
@@ -178,10 +296,11 @@ static int aio_setup_ring(struct kioctx *ctx)
 
        ctx->mmap_size = nr_pages * PAGE_SIZE;
        pr_debug("attempting mmap of %lu bytes\n", ctx->mmap_size);
+
        down_write(&mm->mmap_sem);
-       ctx->mmap_base = do_mmap_pgoff(NULL, 0, ctx->mmap_size,
-                                      PROT_READ|PROT_WRITE,
-                                      MAP_ANONYMOUS|MAP_PRIVATE, 0, &populate);
+       ctx->mmap_base = do_mmap_pgoff(ctx->aio_ring_file, 0, ctx->mmap_size,
+                                      PROT_READ | PROT_WRITE,
+                                      MAP_SHARED | MAP_POPULATE, 0, &populate);
        if (IS_ERR((void *)ctx->mmap_base)) {
                up_write(&mm->mmap_sem);
                ctx->mmap_size = 0;
@@ -190,23 +309,34 @@ static int aio_setup_ring(struct kioctx *ctx)
        }
 
        pr_debug("mmap address: 0x%08lx\n", ctx->mmap_base);
+
+       /* We must do this while still holding mmap_sem for write, as we
+        * need to be protected against userspace attempting to mremap()
+        * or munmap() the ring buffer.
+        */
        ctx->nr_pages = get_user_pages(current, mm, ctx->mmap_base, nr_pages,
                                       1, 0, ctx->ring_pages, NULL);
+
+       /* Dropping the reference here is safe as the page cache will hold
+        * onto the pages for us.  It is also required so that page migration
+        * can unmap the pages and get the right reference count.
+        */
+       for (i = 0; i < ctx->nr_pages; i++)
+               put_page(ctx->ring_pages[i]);
+
        up_write(&mm->mmap_sem);
 
        if (unlikely(ctx->nr_pages != nr_pages)) {
                aio_free_ring(ctx);
                return -EAGAIN;
        }
-       if (populate)
-               mm_populate(ctx->mmap_base, populate);
 
        ctx->user_id = ctx->mmap_base;
        ctx->nr_events = nr_events; /* trusted copy */
 
        ring = kmap_atomic(ctx->ring_pages[0]);
        ring->nr = nr_events;   /* user copy */
-       ring->id = ctx->user_id;
+       ring->id = ~0U;
        ring->head = ring->tail = 0;
        ring->magic = AIO_RING_MAGIC;
        ring->compat_features = AIO_RING_COMPAT_FEATURES;
@@ -238,11 +368,9 @@ void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel)
 }
 EXPORT_SYMBOL(kiocb_set_cancel_fn);
 
-static int kiocb_cancel(struct kioctx *ctx, struct kiocb *kiocb,
-                       struct io_event *res)
+static int kiocb_cancel(struct kioctx *ctx, struct kiocb *kiocb)
 {
        kiocb_cancel_fn *old, *cancel;
-       int ret = -EINVAL;
 
        /*
         * Don't want to set kiocb->ki_cancel = KIOCB_CANCELLED unless it
@@ -252,28 +380,20 @@ static int kiocb_cancel(struct kioctx *ctx, struct kiocb *kiocb,
        cancel = ACCESS_ONCE(kiocb->ki_cancel);
        do {
                if (!cancel || cancel == KIOCB_CANCELLED)
-                       return ret;
+                       return -EINVAL;
 
                old = cancel;
                cancel = cmpxchg(&kiocb->ki_cancel, old, KIOCB_CANCELLED);
        } while (cancel != old);
 
-       atomic_inc(&kiocb->ki_users);
-       spin_unlock_irq(&ctx->ctx_lock);
-
-       memset(res, 0, sizeof(*res));
-       res->obj = (u64)(unsigned long)kiocb->ki_obj.user;
-       res->data = kiocb->ki_user_data;
-       ret = cancel(kiocb, res);
-
-       spin_lock_irq(&ctx->ctx_lock);
-
-       return ret;
+       return cancel(kiocb);
 }
 
 static void free_ioctx_rcu(struct rcu_head *head)
 {
        struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
+
+       free_percpu(ctx->cpu);
        kmem_cache_free(kioctx_cachep, ctx);
 }
 
@@ -282,12 +402,13 @@ static void free_ioctx_rcu(struct rcu_head *head)
  * and ctx->users has dropped to 0, so we know no more kiocbs can be submitted -
  * now it's safe to cancel any that need to be.
  */
-static void free_ioctx(struct kioctx *ctx)
+static void free_ioctx(struct work_struct *work)
 {
+       struct kioctx *ctx = container_of(work, struct kioctx, free_work);
        struct aio_ring *ring;
-       struct io_event res;
        struct kiocb *req;
-       unsigned head, avail;
+       unsigned cpu, avail;
+       DEFINE_WAIT(wait);
 
        spin_lock_irq(&ctx->ctx_lock);
 
@@ -296,28 +417,38 @@ static void free_ioctx(struct kioctx *ctx)
                                       struct kiocb, ki_list);
 
                list_del_init(&req->ki_list);
-               kiocb_cancel(ctx, req, &res);
+               kiocb_cancel(ctx, req);
        }
 
        spin_unlock_irq(&ctx->ctx_lock);
 
-       ring = kmap_atomic(ctx->ring_pages[0]);
-       head = ring->head;
-       kunmap_atomic(ring);
+       for_each_possible_cpu(cpu) {
+               struct kioctx_cpu *kcpu = per_cpu_ptr(ctx->cpu, cpu);
 
-       while (atomic_read(&ctx->reqs_active) > 0) {
-               wait_event(ctx->wait,
-                               head != ctx->tail ||
-                               atomic_read(&ctx->reqs_active) <= 0);
+               atomic_add(kcpu->reqs_available, &ctx->reqs_available);
+               kcpu->reqs_available = 0;
+       }
 
-               avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head;
+       while (1) {
+               prepare_to_wait(&ctx->wait, &wait, TASK_UNINTERRUPTIBLE);
 
-               atomic_sub(avail, &ctx->reqs_active);
-               head += avail;
-               head %= ctx->nr_events;
+               ring = kmap_atomic(ctx->ring_pages[0]);
+               avail = (ring->head <= ring->tail)
+                        ? ring->tail - ring->head
+                        : ctx->nr_events - ring->head + ring->tail;
+
+               atomic_add(avail, &ctx->reqs_available);
+               ring->head = ring->tail;
+               kunmap_atomic(ring);
+
+               if (atomic_read(&ctx->reqs_available) >= ctx->nr_events - 1)
+                       break;
+
+               schedule();
        }
+       finish_wait(&ctx->wait, &wait);
 
-       WARN_ON(atomic_read(&ctx->reqs_active) < 0);
+       WARN_ON(atomic_read(&ctx->reqs_available) > ctx->nr_events - 1);
 
        aio_free_ring(ctx);
 
@@ -333,10 +464,68 @@ static void free_ioctx(struct kioctx *ctx)
        call_rcu(&ctx->rcu_head, free_ioctx_rcu);
 }
 
-static void put_ioctx(struct kioctx *ctx)
+static void free_ioctx_ref(struct percpu_ref *ref)
 {
-       if (unlikely(atomic_dec_and_test(&ctx->users)))
-               free_ioctx(ctx);
+       struct kioctx *ctx = container_of(ref, struct kioctx, users);
+
+       INIT_WORK(&ctx->free_work, free_ioctx);
+       schedule_work(&ctx->free_work);
+}
+
+static int ioctx_add_table(struct kioctx *ctx, struct mm_struct *mm)
+{
+       unsigned i, new_nr;
+       struct kioctx_table *table, *old;
+       struct aio_ring *ring;
+
+       spin_lock(&mm->ioctx_lock);
+       rcu_read_lock();
+       table = rcu_dereference(mm->ioctx_table);
+
+       while (1) {
+               if (table)
+                       for (i = 0; i < table->nr; i++)
+                               if (!table->table[i]) {
+                                       ctx->id = i;
+                                       table->table[i] = ctx;
+                                       rcu_read_unlock();
+                                       spin_unlock(&mm->ioctx_lock);
+
+                                       ring = kmap_atomic(ctx->ring_pages[0]);
+                                       ring->id = ctx->id;
+                                       kunmap_atomic(ring);
+                                       return 0;
+                               }
+
+               new_nr = (table ? table->nr : 1) * 4;
+
+               rcu_read_unlock();
+               spin_unlock(&mm->ioctx_lock);
+
+               table = kzalloc(sizeof(*table) + sizeof(struct kioctx *) *
+                               new_nr, GFP_KERNEL);
+               if (!table)
+                       return -ENOMEM;
+
+               table->nr = new_nr;
+
+               spin_lock(&mm->ioctx_lock);
+               rcu_read_lock();
+               old = rcu_dereference(mm->ioctx_table);
+
+               if (!old) {
+                       rcu_assign_pointer(mm->ioctx_table, table);
+               } else if (table->nr > old->nr) {
+                       memcpy(table->table, old->table,
+                              old->nr * sizeof(struct kioctx *));
+
+                       rcu_assign_pointer(mm->ioctx_table, table);
+                       kfree_rcu(old, rcu);
+               } else {
+                       kfree(table);
+                       table = old;
+               }
+       }
 }
 
 /* ioctx_alloc
@@ -348,6 +537,18 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
        struct kioctx *ctx;
        int err = -ENOMEM;
 
+       /*
+        * We keep track of the number of available ringbuffer slots, to prevent
+        * overflow (reqs_available), and we also use percpu counters for this.
+        *
+        * So since up to half the slots might be on other cpu's percpu counters
+        * and unavailable, double nr_events so userspace sees what they
+        * expected: additionally, we move req_batch slots to/from percpu
+        * counters at a time, so make sure that isn't 0:
+        */
+       nr_events = max(nr_events, num_possible_cpus() * 4);
+       nr_events *= 2;
+
        /* Prevent overflows */
        if ((nr_events > (0x10000000U / sizeof(struct io_event))) ||
            (nr_events > (0x10000000U / sizeof(struct kiocb)))) {
@@ -355,7 +556,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
                return ERR_PTR(-EINVAL);
        }
 
-       if (!nr_events || (unsigned long)nr_events > aio_max_nr)
+       if (!nr_events || (unsigned long)nr_events > (aio_max_nr * 2UL))
                return ERR_PTR(-EAGAIN);
 
        ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL);
@@ -364,8 +565,9 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
 
        ctx->max_reqs = nr_events;
 
-       atomic_set(&ctx->users, 2);
-       atomic_set(&ctx->dead, 0);
+       if (percpu_ref_init(&ctx->users, free_ioctx_ref))
+               goto out_freectx;
+
        spin_lock_init(&ctx->ctx_lock);
        spin_lock_init(&ctx->completion_lock);
        mutex_init(&ctx->ring_lock);
@@ -373,12 +575,21 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
 
        INIT_LIST_HEAD(&ctx->active_reqs);
 
+       ctx->cpu = alloc_percpu(struct kioctx_cpu);
+       if (!ctx->cpu)
+               goto out_freeref;
+
        if (aio_setup_ring(ctx) < 0)
-               goto out_freectx;
+               goto out_freepcpu;
+
+       atomic_set(&ctx->reqs_available, ctx->nr_events - 1);
+       ctx->req_batch = (ctx->nr_events - 1) / (num_possible_cpus() * 4);
+       if (ctx->req_batch < 1)
+               ctx->req_batch = 1;
 
        /* limit the number of system wide aios */
        spin_lock(&aio_nr_lock);
-       if (aio_nr + nr_events > aio_max_nr ||
+       if (aio_nr + nr_events > (aio_max_nr * 2UL) ||
            aio_nr + nr_events < aio_nr) {
                spin_unlock(&aio_nr_lock);
                goto out_cleanup;
@@ -386,49 +597,54 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
        aio_nr += ctx->max_reqs;
        spin_unlock(&aio_nr_lock);
 
-       /* now link into global list. */
-       spin_lock(&mm->ioctx_lock);
-       hlist_add_head_rcu(&ctx->list, &mm->ioctx_list);
-       spin_unlock(&mm->ioctx_lock);
+       percpu_ref_get(&ctx->users); /* io_setup() will drop this ref */
+
+       err = ioctx_add_table(ctx, mm);
+       if (err)
+               goto out_cleanup_put;
 
        pr_debug("allocated ioctx %p[%ld]: mm=%p mask=0x%x\n",
                 ctx, ctx->user_id, mm, ctx->nr_events);
        return ctx;
 
+out_cleanup_put:
+       percpu_ref_put(&ctx->users);
 out_cleanup:
        err = -EAGAIN;
        aio_free_ring(ctx);
+out_freepcpu:
+       free_percpu(ctx->cpu);
+out_freeref:
+       free_percpu(ctx->users.pcpu_count);
 out_freectx:
+       if (ctx->aio_ring_file)
+               fput(ctx->aio_ring_file);
        kmem_cache_free(kioctx_cachep, ctx);
        pr_debug("error allocating ioctx %d\n", err);
        return ERR_PTR(err);
 }
 
-static void kill_ioctx_work(struct work_struct *work)
-{
-       struct kioctx *ctx = container_of(work, struct kioctx, rcu_work);
-
-       wake_up_all(&ctx->wait);
-       put_ioctx(ctx);
-}
-
-static void kill_ioctx_rcu(struct rcu_head *head)
-{
-       struct kioctx *ctx = container_of(head, struct kioctx, rcu_head);
-
-       INIT_WORK(&ctx->rcu_work, kill_ioctx_work);
-       schedule_work(&ctx->rcu_work);
-}
-
 /* kill_ioctx
  *     Cancels all outstanding aio requests on an aio context.  Used
  *     when the processes owning a context have all exited to encourage
  *     the rapid destruction of the kioctx.
  */
-static void kill_ioctx(struct kioctx *ctx)
+static void kill_ioctx(struct mm_struct *mm, struct kioctx *ctx)
 {
        if (!atomic_xchg(&ctx->dead, 1)) {
-               hlist_del_rcu(&ctx->list);
+               struct kioctx_table *table;
+
+               spin_lock(&mm->ioctx_lock);
+               rcu_read_lock();
+               table = rcu_dereference(mm->ioctx_table);
+
+               WARN_ON(ctx != table->table[ctx->id]);
+               table->table[ctx->id] = NULL;
+               rcu_read_unlock();
+               spin_unlock(&mm->ioctx_lock);
+
+               /* percpu_ref_kill() will do the necessary call_rcu() */
+               wake_up_all(&ctx->wait);
 
                /*
                 * It'd be more correct to do this in free_ioctx(), after all
@@ -445,24 +661,23 @@ static void kill_ioctx(struct kioctx *ctx)
                if (ctx->mmap_size)
                        vm_munmap(ctx->mmap_base, ctx->mmap_size);
 
-               /* Between hlist_del_rcu() and dropping the initial ref */
-               call_rcu(&ctx->rcu_head, kill_ioctx_rcu);
+               percpu_ref_kill(&ctx->users);
        }
 }
 
 /* wait_on_sync_kiocb:
  *     Waits on the given sync kiocb to complete.
  */
-ssize_t wait_on_sync_kiocb(struct kiocb *iocb)
+ssize_t wait_on_sync_kiocb(struct kiocb *req)
 {
-       while (atomic_read(&iocb->ki_users)) {
+       while (!req->ki_ctx) {
                set_current_state(TASK_UNINTERRUPTIBLE);
-               if (!atomic_read(&iocb->ki_users))
+               if (req->ki_ctx)
                        break;
                io_schedule();
        }
        __set_current_state(TASK_RUNNING);
-       return iocb->ki_user_data;
+       return req->ki_user_data;
 }
 EXPORT_SYMBOL(wait_on_sync_kiocb);
 
@@ -476,16 +691,28 @@ EXPORT_SYMBOL(wait_on_sync_kiocb);
  */
 void exit_aio(struct mm_struct *mm)
 {
+       struct kioctx_table *table;
        struct kioctx *ctx;
-       struct hlist_node *n;
-
-       hlist_for_each_entry_safe(ctx, n, &mm->ioctx_list, list) {
-               if (1 != atomic_read(&ctx->users))
-                       printk(KERN_DEBUG
-                               "exit_aio:ioctx still alive: %d %d %d\n",
-                               atomic_read(&ctx->users),
-                               atomic_read(&ctx->dead),
-                               atomic_read(&ctx->reqs_active));
+       unsigned i = 0;
+
+       while (1) {
+               rcu_read_lock();
+               table = rcu_dereference(mm->ioctx_table);
+
+               do {
+                       if (!table || i >= table->nr) {
+                               rcu_read_unlock();
+                               rcu_assign_pointer(mm->ioctx_table, NULL);
+                               if (table)
+                                       kfree(table);
+                               return;
+                       }
+
+                       ctx = table->table[i++];
+               } while (!ctx);
+
+               rcu_read_unlock();
+
                /*
                 * We don't need to bother with munmap() here -
                 * exit_mmap(mm) is coming and it'll unmap everything.
@@ -496,40 +723,75 @@ void exit_aio(struct mm_struct *mm)
                 */
                ctx->mmap_size = 0;
 
-               kill_ioctx(ctx);
+               kill_ioctx(mm, ctx);
+       }
+}
+
+static void put_reqs_available(struct kioctx *ctx, unsigned nr)
+{
+       struct kioctx_cpu *kcpu;
+
+       preempt_disable();
+       kcpu = this_cpu_ptr(ctx->cpu);
+
+       kcpu->reqs_available += nr;
+       while (kcpu->reqs_available >= ctx->req_batch * 2) {
+               kcpu->reqs_available -= ctx->req_batch;
+               atomic_add(ctx->req_batch, &ctx->reqs_available);
+       }
+
+       preempt_enable();
+}
+
+static bool get_reqs_available(struct kioctx *ctx)
+{
+       struct kioctx_cpu *kcpu;
+       bool ret = false;
+
+       preempt_disable();
+       kcpu = this_cpu_ptr(ctx->cpu);
+
+       if (!kcpu->reqs_available) {
+               int old, avail = atomic_read(&ctx->reqs_available);
+
+               do {
+                       if (avail < ctx->req_batch)
+                               goto out;
+
+                       old = avail;
+                       avail = atomic_cmpxchg(&ctx->reqs_available,
+                                              avail, avail - ctx->req_batch);
+               } while (avail != old);
+
+               kcpu->reqs_available += ctx->req_batch;
        }
+
+       ret = true;
+       kcpu->reqs_available--;
+out:
+       preempt_enable();
+       return ret;
 }
 
 /* aio_get_req
- *     Allocate a slot for an aio request.  Increments the ki_users count
- * of the kioctx so that the kioctx stays around until all requests are
- * complete.  Returns NULL if no requests are free.
- *
- * Returns with kiocb->ki_users set to 2.  The io submit code path holds
- * an extra reference while submitting the i/o.
- * This prevents races between the aio code path referencing the
- * req (after submitting it) and aio_complete() freeing the req.
+ *     Allocate a slot for an aio request.
+ * Returns NULL if no requests are free.
  */
 static inline struct kiocb *aio_get_req(struct kioctx *ctx)
 {
        struct kiocb *req;
 
-       if (atomic_read(&ctx->reqs_active) >= ctx->nr_events)
+       if (!get_reqs_available(ctx))
                return NULL;
 
-       if (atomic_inc_return(&ctx->reqs_active) > ctx->nr_events - 1)
-               goto out_put;
-
        req = kmem_cache_alloc(kiocb_cachep, GFP_KERNEL|__GFP_ZERO);
        if (unlikely(!req))
                goto out_put;
 
-       atomic_set(&req->ki_users, 2);
        req->ki_ctx = ctx;
-
        return req;
 out_put:
-       atomic_dec(&ctx->reqs_active);
+       put_reqs_available(ctx, 1);
        return NULL;
 }
 
@@ -539,35 +801,32 @@ static void kiocb_free(struct kiocb *req)
                fput(req->ki_filp);
        if (req->ki_eventfd != NULL)
                eventfd_ctx_put(req->ki_eventfd);
-       if (req->ki_dtor)
-               req->ki_dtor(req);
-       if (req->ki_iovec != &req->ki_inline_vec)
-               kfree(req->ki_iovec);
        kmem_cache_free(kiocb_cachep, req);
 }
 
-void aio_put_req(struct kiocb *req)
-{
-       if (atomic_dec_and_test(&req->ki_users))
-               kiocb_free(req);
-}
-EXPORT_SYMBOL(aio_put_req);
-
 static struct kioctx *lookup_ioctx(unsigned long ctx_id)
 {
+       struct aio_ring __user *ring  = (void __user *)ctx_id;
        struct mm_struct *mm = current->mm;
        struct kioctx *ctx, *ret = NULL;
+       struct kioctx_table *table;
+       unsigned id;
+
+       if (get_user(id, &ring->id))
+               return NULL;
 
        rcu_read_lock();
+       table = rcu_dereference(mm->ioctx_table);
 
-       hlist_for_each_entry_rcu(ctx, &mm->ioctx_list, list) {
-               if (ctx->user_id == ctx_id) {
-                       atomic_inc(&ctx->users);
-                       ret = ctx;
-                       break;
-               }
-       }
+       if (!table || id >= table->nr)
+               goto out;
 
+       ctx = table->table[id];
+       if (ctx && ctx->user_id == ctx_id) {
+               percpu_ref_get(&ctx->users);
+               ret = ctx;
+       }
+out:
        rcu_read_unlock();
        return ret;
 }
@@ -591,16 +850,16 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
         *  - the sync task helpfully left a reference to itself in the iocb
         */
        if (is_sync_kiocb(iocb)) {
-               BUG_ON(atomic_read(&iocb->ki_users) != 1);
                iocb->ki_user_data = res;
-               atomic_set(&iocb->ki_users, 0);
+               smp_wmb();
+               iocb->ki_ctx = ERR_PTR(-EXDEV);
                wake_up_process(iocb->ki_obj.tsk);
                return;
        }
 
        /*
         * Take rcu_read_lock() in case the kioctx is being destroyed, as we
-        * need to issue a wakeup after decrementing reqs_active.
+        * need to issue a wakeup after incrementing reqs_available.
         */
        rcu_read_lock();
 
@@ -612,17 +871,6 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
                spin_unlock_irqrestore(&ctx->ctx_lock, flags);
        }
 
-       /*
-        * cancelled requests don't get events, userland was given one
-        * when the event got cancelled.
-        */
-       if (unlikely(xchg(&iocb->ki_cancel,
-                         KIOCB_CANCELLED) == KIOCB_CANCELLED)) {
-               atomic_dec(&ctx->reqs_active);
-               /* Still need the wake_up in case free_ioctx is waiting */
-               goto put_rq;
-       }
-
        /*
         * Add a completion event to the ring buffer. Must be done holding
         * ctx->completion_lock to prevent other code from messing with the tail
@@ -675,9 +923,8 @@ void aio_complete(struct kiocb *iocb, long res, long res2)
        if (iocb->ki_eventfd != NULL)
                eventfd_signal(iocb->ki_eventfd, 1);
 
-put_rq:
        /* everything turned out well, dispose of the aiocb. */
-       aio_put_req(iocb);
+       kiocb_free(iocb);
 
        /*
         * We have to order our ring_info tail store above and test
@@ -702,7 +949,7 @@ static long aio_read_events_ring(struct kioctx *ctx,
                                 struct io_event __user *event, long nr)
 {
        struct aio_ring *ring;
-       unsigned head, pos;
+       unsigned head, tail, pos;
        long ret = 0;
        int copy_ret;
 
@@ -710,11 +957,12 @@ static long aio_read_events_ring(struct kioctx *ctx,
 
        ring = kmap_atomic(ctx->ring_pages[0]);
        head = ring->head;
+       tail = ring->tail;
        kunmap_atomic(ring);
 
-       pr_debug("h%u t%u m%u\n", head, ctx->tail, ctx->nr_events);
+       pr_debug("h%u t%u m%u\n", head, tail, ctx->nr_events);
 
-       if (head == ctx->tail)
+       if (head == tail)
                goto out;
 
        while (ret < nr) {
@@ -722,8 +970,8 @@ static long aio_read_events_ring(struct kioctx *ctx,
                struct io_event *ev;
                struct page *page;
 
-               avail = (head <= ctx->tail ? ctx->tail : ctx->nr_events) - head;
-               if (head == ctx->tail)
+               avail = (head <= tail ?  tail : ctx->nr_events) - head;
+               if (head == tail)
                        break;
 
                avail = min(avail, nr - ret);
@@ -754,9 +1002,9 @@ static long aio_read_events_ring(struct kioctx *ctx,
        kunmap_atomic(ring);
        flush_dcache_page(ctx->ring_pages[0]);
 
-       pr_debug("%li  h%u t%u\n", ret, head, ctx->tail);
+       pr_debug("%li  h%u t%u\n", ret, head, tail);
 
-       atomic_sub(ret, &ctx->reqs_active);
+       put_reqs_available(ctx, ret);
 out:
        mutex_unlock(&ctx->ring_lock);
 
@@ -854,8 +1102,8 @@ SYSCALL_DEFINE2(io_setup, unsigned, nr_events, aio_context_t __user *, ctxp)
        if (!IS_ERR(ioctx)) {
                ret = put_user(ioctx->user_id, ctxp);
                if (ret)
-                       kill_ioctx(ioctx);
-               put_ioctx(ioctx);
+                       kill_ioctx(current->mm, ioctx);
+               percpu_ref_put(&ioctx->users);
        }
 
 out:
@@ -872,101 +1120,37 @@ SYSCALL_DEFINE1(io_destroy, aio_context_t, ctx)
 {
        struct kioctx *ioctx = lookup_ioctx(ctx);
        if (likely(NULL != ioctx)) {
-               kill_ioctx(ioctx);
-               put_ioctx(ioctx);
+               kill_ioctx(current->mm, ioctx);
+               percpu_ref_put(&ioctx->users);
                return 0;
        }
        pr_debug("EINVAL: io_destroy: invalid context id\n");
        return -EINVAL;
 }
 
-static void aio_advance_iovec(struct kiocb *iocb, ssize_t ret)
-{
-       struct iovec *iov = &iocb->ki_iovec[iocb->ki_cur_seg];
-
-       BUG_ON(ret <= 0);
-
-       while (iocb->ki_cur_seg < iocb->ki_nr_segs && ret > 0) {
-               ssize_t this = min((ssize_t)iov->iov_len, ret);
-               iov->iov_base += this;
-               iov->iov_len -= this;
-               iocb->ki_left -= this;
-               ret -= this;
-               if (iov->iov_len == 0) {
-                       iocb->ki_cur_seg++;
-                       iov++;
-               }
-       }
-
-       /* the caller should not have done more io than what fit in
-        * the remaining iovecs */
-       BUG_ON(ret > 0 && iocb->ki_left == 0);
-}
-
 typedef ssize_t (aio_rw_op)(struct kiocb *, const struct iovec *,
                            unsigned long, loff_t);
 
-static ssize_t aio_rw_vect_retry(struct kiocb *iocb, int rw, aio_rw_op *rw_op)
-{
-       struct file *file = iocb->ki_filp;
-       struct address_space *mapping = file->f_mapping;
-       struct inode *inode = mapping->host;
-       ssize_t ret = 0;
-
-       /* This matches the pread()/pwrite() logic */
-       if (iocb->ki_pos < 0)
-               return -EINVAL;
-
-       if (rw == WRITE)
-               file_start_write(file);
-       do {
-               ret = rw_op(iocb, &iocb->ki_iovec[iocb->ki_cur_seg],
-                           iocb->ki_nr_segs - iocb->ki_cur_seg,
-                           iocb->ki_pos);
-               if (ret > 0)
-                       aio_advance_iovec(iocb, ret);
-
-       /* retry all partial writes.  retry partial reads as long as its a
-        * regular file. */
-       } while (ret > 0 && iocb->ki_left > 0 &&
-                (rw == WRITE ||
-                 (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode))));
-       if (rw == WRITE)
-               file_end_write(file);
-
-       /* This means we must have transferred all that we could */
-       /* No need to retry anymore */
-       if ((ret == 0) || (iocb->ki_left == 0))
-               ret = iocb->ki_nbytes - iocb->ki_left;
-
-       /* If we managed to write some out we return that, rather than
-        * the eventual error. */
-       if (rw == WRITE
-           && ret < 0 && ret != -EIOCBQUEUED
-           && iocb->ki_nbytes - iocb->ki_left)
-               ret = iocb->ki_nbytes - iocb->ki_left;
-
-       return ret;
-}
-
-static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat)
+static ssize_t aio_setup_vectored_rw(struct kiocb *kiocb,
+                                    int rw, char __user *buf,
+                                    unsigned long *nr_segs,
+                                    struct iovec **iovec,
+                                    bool compat)
 {
        ssize_t ret;
 
-       kiocb->ki_nr_segs = kiocb->ki_nbytes;
+       *nr_segs = kiocb->ki_nbytes;
 
 #ifdef CONFIG_COMPAT
        if (compat)
                ret = compat_rw_copy_check_uvector(rw,
-                               (struct compat_iovec __user *)kiocb->ki_buf,
-                               kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec,
-                               &kiocb->ki_iovec);
+                               (struct compat_iovec __user *)buf,
+                               *nr_segs, 1, *iovec, iovec);
        else
 #endif
                ret = rw_copy_check_uvector(rw,
-                               (struct iovec __user *)kiocb->ki_buf,
-                               kiocb->ki_nr_segs, 1, &kiocb->ki_inline_vec,
-                               &kiocb->ki_iovec);
+                               (struct iovec __user *)buf,
+                               *nr_segs, 1, *iovec, iovec);
        if (ret < 0)
                return ret;
 
@@ -975,15 +1159,17 @@ static ssize_t aio_setup_vectored_rw(int rw, struct kiocb *kiocb, bool compat)
        return 0;
 }
 
-static ssize_t aio_setup_single_vector(int rw, struct kiocb *kiocb)
+static ssize_t aio_setup_single_vector(struct kiocb *kiocb,
+                                      int rw, char __user *buf,
+                                      unsigned long *nr_segs,
+                                      struct iovec *iovec)
 {
-       if (unlikely(!access_ok(!rw, kiocb->ki_buf, kiocb->ki_nbytes)))
+       if (unlikely(!access_ok(!rw, buf, kiocb->ki_nbytes)))
                return -EFAULT;
 
-       kiocb->ki_iovec = &kiocb->ki_inline_vec;
-       kiocb->ki_iovec->iov_base = kiocb->ki_buf;
-       kiocb->ki_iovec->iov_len = kiocb->ki_nbytes;
-       kiocb->ki_nr_segs = 1;
+       iovec->iov_base = buf;
+       iovec->iov_len = kiocb->ki_nbytes;
+       *nr_segs = 1;
        return 0;
 }
 
@@ -992,15 +1178,18 @@ static ssize_t aio_setup_single_vector(int rw, 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_run_iocb(struct kiocb *req, bool compat)
+static ssize_t aio_run_iocb(struct kiocb *req, unsigned opcode,
+                           char __user *buf, bool compat)
 {
        struct file *file = req->ki_filp;
        ssize_t ret;
+       unsigned long nr_segs;
        int rw;
        fmode_t mode;
        aio_rw_op *rw_op;
+       struct iovec inline_vec, *iovec = &inline_vec;
 
-       switch (req->ki_opcode) {
+       switch (opcode) {
        case IOCB_CMD_PREAD:
        case IOCB_CMD_PREADV:
                mode    = FMODE_READ;
@@ -1021,21 +1210,38 @@ rw_common:
                if (!rw_op)
                        return -EINVAL;
 
-               ret = (req->ki_opcode == IOCB_CMD_PREADV ||
-                      req->ki_opcode == IOCB_CMD_PWRITEV)
-                       ? aio_setup_vectored_rw(rw, req, compat)
-                       : aio_setup_single_vector(rw, req);
+               ret = (opcode == IOCB_CMD_PREADV ||
+                      opcode == IOCB_CMD_PWRITEV)
+                       ? aio_setup_vectored_rw(req, rw, buf, &nr_segs,
+                                               &iovec, compat)
+                       : aio_setup_single_vector(req, rw, buf, &nr_segs,
+                                                 iovec);
                if (ret)
                        return ret;
 
                ret = rw_verify_area(rw, file, &req->ki_pos, req->ki_nbytes);
-               if (ret < 0)
+               if (ret < 0) {
+                       if (iovec != &inline_vec)
+                               kfree(iovec);
                        return ret;
+               }
 
                req->ki_nbytes = ret;
-               req->ki_left = ret;
 
-               ret = aio_rw_vect_retry(req, rw, rw_op);
+               /* XXX: move/kill - rw_verify_area()? */
+               /* This matches the pread()/pwrite() logic */
+               if (req->ki_pos < 0) {
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (rw == WRITE)
+                       file_start_write(file);
+
+               ret = rw_op(req, iovec, nr_segs, req->ki_pos);
+
+               if (rw == WRITE)
+                       file_end_write(file);
                break;
 
        case IOCB_CMD_FDSYNC:
@@ -1057,6 +1263,9 @@ rw_common:
                return -EINVAL;
        }
 
+       if (iovec != &inline_vec)
+               kfree(iovec);
+
        if (ret != -EIOCBQUEUED) {
                /*
                 * There's no easy way to restart the syscall since other AIO's
@@ -1128,21 +1337,18 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
        req->ki_obj.user = user_iocb;
        req->ki_user_data = iocb->aio_data;
        req->ki_pos = iocb->aio_offset;
+       req->ki_nbytes = iocb->aio_nbytes;
 
-       req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf;
-       req->ki_left = req->ki_nbytes = iocb->aio_nbytes;
-       req->ki_opcode = iocb->aio_lio_opcode;
-
-       ret = aio_run_iocb(req, compat);
+       ret = aio_run_iocb(req, iocb->aio_lio_opcode,
+                          (char __user *)(unsigned long)iocb->aio_buf,
+                          compat);
        if (ret)
                goto out_put_req;
 
-       aio_put_req(req);       /* drop extra ref to req */
        return 0;
 out_put_req:
-       atomic_dec(&ctx->reqs_active);
-       aio_put_req(req);       /* drop extra ref to req */
-       aio_put_req(req);       /* drop i/o ref to req */
+       put_reqs_available(ctx, 1);
+       kiocb_free(req);
        return ret;
 }
 
@@ -1195,7 +1401,7 @@ long do_io_submit(aio_context_t ctx_id, long nr,
        }
        blk_finish_plug(&plug);
 
-       put_ioctx(ctx);
+       percpu_ref_put(&ctx->users);
        return i ? i : ret;
 }
 
@@ -1252,7 +1458,6 @@ static struct kiocb *lookup_kiocb(struct kioctx *ctx, struct iocb __user *iocb,
 SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb,
                struct io_event __user *, result)
 {
-       struct io_event res;
        struct kioctx *ctx;
        struct kiocb *kiocb;
        u32 key;
@@ -1270,21 +1475,22 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb,
 
        kiocb = lookup_kiocb(ctx, iocb, key);
        if (kiocb)
-               ret = kiocb_cancel(ctx, kiocb, &res);
+               ret = kiocb_cancel(ctx, kiocb);
        else
                ret = -EINVAL;
 
        spin_unlock_irq(&ctx->ctx_lock);
 
        if (!ret) {
-               /* Cancellation succeeded -- copy the result
-                * into the user's buffer.
+               /*
+                * The result argument is no longer used - the io_event is
+                * always delivered via the ring buffer. -EINPROGRESS indicates
+                * cancellation is progress:
                 */
-               if (copy_to_user(result, &res, sizeof(res)))
-                       ret = -EFAULT;
+               ret = -EINPROGRESS;
        }
 
-       put_ioctx(ctx);
+       percpu_ref_put(&ctx->users);
 
        return ret;
 }
@@ -1313,7 +1519,7 @@ SYSCALL_DEFINE5(io_getevents, aio_context_t, ctx_id,
        if (likely(ioctx)) {
                if (likely(min_nr <= nr && min_nr >= 0))
                        ret = read_events(ioctx, min_nr, nr, events, timeout);
-               put_ioctx(ioctx);
+               percpu_ref_put(&ioctx->users);
        }
        return ret;
 }
index 47a65df8c87142e60600d69391f1d25c357b52a5..85c961849953c090091e2154cbf5618a62750b2f 100644 (file)
@@ -108,6 +108,72 @@ static struct file_system_type anon_inode_fs_type = {
        .kill_sb        = kill_anon_super,
 };
 
+/**
+ * anon_inode_getfile_private - creates a new file instance by hooking it up to an
+ *                      anonymous inode, and a dentry that describe the "class"
+ *                      of the file
+ *
+ * @name:    [in]    name of the "class" of the new file
+ * @fops:    [in]    file operations for the new file
+ * @priv:    [in]    private data for the new file (will be file's private_data)
+ * @flags:   [in]    flags
+ *
+ *
+ * Similar to anon_inode_getfile, but each file holds a single inode.
+ *
+ */
+struct file *anon_inode_getfile_private(const char *name,
+                                       const struct file_operations *fops,
+                                       void *priv, int flags)
+{
+       struct qstr this;
+       struct path path;
+       struct file *file;
+       struct inode *inode;
+
+       if (fops->owner && !try_module_get(fops->owner))
+               return ERR_PTR(-ENOENT);
+
+       inode = anon_inode_mkinode(anon_inode_mnt->mnt_sb);
+       if (IS_ERR(inode)) {
+               file = ERR_PTR(-ENOMEM);
+               goto err_module;
+       }
+
+       /*
+        * Link the inode to a directory entry by creating a unique name
+        * using the inode sequence number.
+        */
+       file = ERR_PTR(-ENOMEM);
+       this.name = name;
+       this.len = strlen(name);
+       this.hash = 0;
+       path.dentry = d_alloc_pseudo(anon_inode_mnt->mnt_sb, &this);
+       if (!path.dentry)
+               goto err_module;
+
+       path.mnt = mntget(anon_inode_mnt);
+
+       d_instantiate(path.dentry, inode);
+
+       file = alloc_file(&path, OPEN_FMODE(flags), fops);
+       if (IS_ERR(file))
+               goto err_dput;
+
+       file->f_mapping = inode->i_mapping;
+       file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
+       file->private_data = priv;
+
+       return file;
+
+err_dput:
+       path_put(&path);
+err_module:
+       module_put(fops->owner);
+       return file;
+}
+EXPORT_SYMBOL_GPL(anon_inode_getfile_private);
+
 /**
  * anon_inode_getfile - creates a new file instance by hooking it up to an
  *                      anonymous inode, and a dentry that describe the "class"
index 743c7c2c949d2571c1c0ae0571c604d516c914e4..0f00da329e718ab465ddb1488dda626db71cca23 100644 (file)
@@ -183,13 +183,14 @@ static int autofs_dev_ioctl_protosubver(struct file *fp,
        return 0;
 }
 
+/* Find the topmost mount satisfying test() */
 static int find_autofs_mount(const char *pathname,
                             struct path *res,
                             int test(struct path *path, void *data),
                             void *data)
 {
        struct path path;
-       int err = kern_path(pathname, 0, &path);
+       int err = kern_path_mountpoint(AT_FDCWD, pathname, &path, 0);
        if (err)
                return err;
        err = -ENOENT;
@@ -197,10 +198,9 @@ static int find_autofs_mount(const char *pathname,
                if (path.dentry->d_sb->s_magic == AUTOFS_SUPER_MAGIC) {
                        if (test(&path, data)) {
                                path_get(&path);
-                               if (!err) /* already found some */
-                                       path_put(res);
                                *res = path;
                                err = 0;
+                               break;
                        }
                }
                if (!follow_up(&path))
@@ -486,12 +486,11 @@ static int autofs_dev_ioctl_askumount(struct file *fp,
  * mount if there is one or 0 if it isn't a mountpoint.
  *
  * If we aren't supplied with a file descriptor then we
- * lookup the nameidata of the path and check if it is the
- * root of a mount. If a type is given we are looking for
- * a particular autofs mount and if we don't find a match
- * we return fail. If the located nameidata path is the
- * root of a mount we return 1 along with the super magic
- * of the mount or 0 otherwise.
+ * lookup the path and check if it is the root of a mount.
+ * If a type is given we are looking for a particular autofs
+ * mount and if we don't find a match we return fail. If the
+ * located path is the root of a mount we return 1 along with
+ * the super magic of the mount or 0 otherwise.
  *
  * In both cases the the device number (as returned by
  * new_encode_dev()) is also returned.
@@ -519,9 +518,11 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
 
        if (!fp || param->ioctlfd == -1) {
                if (autofs_type_any(type))
-                       err = kern_path(name, LOOKUP_FOLLOW, &path);
+                       err = kern_path_mountpoint(AT_FDCWD,
+                                                  name, &path, LOOKUP_FOLLOW);
                else
-                       err = find_autofs_mount(name, &path, test_by_type, &type);
+                       err = find_autofs_mount(name, &path,
+                                               test_by_type, &type);
                if (err)
                        goto out;
                devid = new_encode_dev(path.dentry->d_sb->s_dev);
index 3db70dae40d3a842de562c9fb4e26c29f9284239..689e40d983ad64ca3726cd5f8dd64c44d49bb5e6 100644 (file)
@@ -109,13 +109,7 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
 
        pkt.hdr.proto_version = sbi->version;
        pkt.hdr.type = type;
-       mutex_lock(&sbi->wq_mutex);
 
-       /* Check if we have become catatonic */
-       if (sbi->catatonic) {
-               mutex_unlock(&sbi->wq_mutex);
-               return;
-       }
        switch (type) {
        /* Kernel protocol v4 missing and expire packets */
        case autofs_ptype_missing:
@@ -427,7 +421,6 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                wq->tgid = current->tgid;
                wq->status = -EINTR; /* Status return if interrupted */
                wq->wait_ctr = 2;
-               mutex_unlock(&sbi->wq_mutex);
 
                if (sbi->version < 5) {
                        if (notify == NFY_MOUNT)
@@ -449,15 +442,15 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
                        (unsigned long) wq->wait_queue_token, wq->name.len,
                        wq->name.name, notify);
 
-               /* autofs4_notify_daemon() may block */
+               /* autofs4_notify_daemon() may block; it will unlock ->wq_mutex */
                autofs4_notify_daemon(sbi, wq, type);
        } else {
                wq->wait_ctr++;
-               mutex_unlock(&sbi->wq_mutex);
-               kfree(qstr.name);
                DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
                        (unsigned long) wq->wait_queue_token, wq->name.len,
                        wq->name.name, notify);
+               mutex_unlock(&sbi->wq_mutex);
+               kfree(qstr.name);
        }
 
        /*
index ad3ea1497cc3825d4fdf795cd6b5735618005e0e..ae28922183357d4c0e4d491a452919e125ba8bc3 100644 (file)
@@ -166,7 +166,7 @@ static void bfs_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);
+               truncate_pagecache(inode, inode->i_size);
 }
 
 static int bfs_write_begin(struct file *file, struct address_space *mapping,
index 8fb42916d8a29812e349fdbfa980ef1c34056ce4..60250847929fcd0421e5d72b9655bbe4c3a785e1 100644 (file)
@@ -716,13 +716,14 @@ int bioset_integrity_create(struct bio_set *bs, int pool_size)
                return 0;
 
        bs->bio_integrity_pool = mempool_create_slab_pool(pool_size, bip_slab);
-
-       bs->bvec_integrity_pool = biovec_create_pool(bs, pool_size);
-       if (!bs->bvec_integrity_pool)
+       if (!bs->bio_integrity_pool)
                return -1;
 
-       if (!bs->bio_integrity_pool)
+       bs->bvec_integrity_pool = biovec_create_pool(bs, pool_size);
+       if (!bs->bvec_integrity_pool) {
+               mempool_destroy(bs->bio_integrity_pool);
                return -1;
+       }
 
        return 0;
 }
index 1173a4ee0830a41fd39d1546921af239645d9507..1e86823a9cbda37f8451269d91a50f90d00c9566 100644 (file)
@@ -592,7 +592,7 @@ static struct block_device *bd_acquire(struct inode *inode)
        return bdev;
 }
 
-static inline int sb_is_blkdev_sb(struct super_block *sb)
+int sb_is_blkdev_sb(struct super_block *sb)
 {
        return sb == blockdev_superblock;
 }
@@ -1542,7 +1542,7 @@ static ssize_t blkdev_aio_read(struct kiocb *iocb, const struct iovec *iov,
                return 0;
 
        size -= pos;
-       if (size < iocb->ki_left)
+       if (size < iocb->ki_nbytes)
                nr_segs = iov_shorten((struct iovec *)iov, nr_segs, size);
        return generic_file_aio_read(iocb, iov, nr_segs, pos);
 }
index 2b3b83296977d2f10239c6c5b0a40b6af1673c97..398cbd517be218bbfc155f06e1bec5e5fe71717c 100644 (file)
@@ -72,3 +72,12 @@ config BTRFS_DEBUG
          performance, or export extra information via sysfs.
 
          If unsure, say N.
+
+config BTRFS_ASSERT
+       bool "Btrfs assert support"
+       depends on BTRFS_FS
+       help
+         Enable run-time assertion checking.  This will result in panics if
+         any of the assertions trip.  This is meant for btrfs developers only.
+
+         If unsure, say N.
index 3932224f99e975d8fce434049520bb7a2eeda389..a91a6a355cc5d20528f120b076a9a18cac9b9699 100644 (file)
@@ -8,7 +8,10 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \
           export.o tree-log.o free-space-cache.o zlib.o lzo.o \
           compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
-          reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o
+          reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
+          uuid-tree.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
+
+btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o
index 8bc5e8ccb091852dd53f262eb556fe5578a419a3..0552a599b28f366ca2a4549458bfedeb8500fdd0 100644 (file)
@@ -119,6 +119,26 @@ struct __prelim_ref {
        u64 wanted_disk_byte;
 };
 
+static struct kmem_cache *btrfs_prelim_ref_cache;
+
+int __init btrfs_prelim_ref_init(void)
+{
+       btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref",
+                                       sizeof(struct __prelim_ref),
+                                       0,
+                                       SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD,
+                                       NULL);
+       if (!btrfs_prelim_ref_cache)
+               return -ENOMEM;
+       return 0;
+}
+
+void btrfs_prelim_ref_exit(void)
+{
+       if (btrfs_prelim_ref_cache)
+               kmem_cache_destroy(btrfs_prelim_ref_cache);
+}
+
 /*
  * the rules for all callers of this function are:
  * - obtaining the parent is the goal
@@ -160,12 +180,12 @@ struct __prelim_ref {
 
 static int __add_prelim_ref(struct list_head *head, u64 root_id,
                            struct btrfs_key *key, int level,
-                           u64 parent, u64 wanted_disk_byte, int count)
+                           u64 parent, u64 wanted_disk_byte, int count,
+                           gfp_t gfp_mask)
 {
        struct __prelim_ref *ref;
 
-       /* in case we're adding delayed refs, we're holding the refs spinlock */
-       ref = kmalloc(sizeof(*ref), GFP_ATOMIC);
+       ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask);
        if (!ref)
                return -ENOMEM;
 
@@ -295,10 +315,9 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
        ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq);
        pr_debug("search slot in root %llu (level %d, ref count %d) returned "
                 "%d for key (%llu %u %llu)\n",
-                (unsigned long long)ref->root_id, level, ref->count, ret,
-                (unsigned long long)ref->key_for_search.objectid,
-                ref->key_for_search.type,
-                (unsigned long long)ref->key_for_search.offset);
+                ref->root_id, level, ref->count, ret,
+                ref->key_for_search.objectid, ref->key_for_search.type,
+                ref->key_for_search.offset);
        if (ret < 0)
                goto out;
 
@@ -365,11 +384,12 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                node = ulist_next(parents, &uiter);
                ref->parent = node ? node->val : 0;
                ref->inode_list = node ?
-                       (struct extent_inode_elem *)(uintptr_t)node->aux : 0;
+                       (struct extent_inode_elem *)(uintptr_t)node->aux : NULL;
 
                /* additional parents require new refs being added here */
                while ((node = ulist_next(parents, &uiter))) {
-                       new_ref = kmalloc(sizeof(*new_ref), GFP_NOFS);
+                       new_ref = kmem_cache_alloc(btrfs_prelim_ref_cache,
+                                                  GFP_NOFS);
                        if (!new_ref) {
                                ret = -ENOMEM;
                                goto out;
@@ -493,7 +513,7 @@ static void __merge_refs(struct list_head *head, int mode)
                        ref1->count += ref2->count;
 
                        list_del(&ref2->list);
-                       kfree(ref2);
+                       kmem_cache_free(btrfs_prelim_ref_cache, ref2);
                }
 
        }
@@ -548,7 +568,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        ref = btrfs_delayed_node_to_tree_ref(node);
                        ret = __add_prelim_ref(prefs, ref->root, &op_key,
                                               ref->level + 1, 0, node->bytenr,
-                                              node->ref_mod * sgn);
+                                              node->ref_mod * sgn, GFP_ATOMIC);
                        break;
                }
                case BTRFS_SHARED_BLOCK_REF_KEY: {
@@ -558,7 +578,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        ret = __add_prelim_ref(prefs, ref->root, NULL,
                                               ref->level + 1, ref->parent,
                                               node->bytenr,
-                                              node->ref_mod * sgn);
+                                              node->ref_mod * sgn, GFP_ATOMIC);
                        break;
                }
                case BTRFS_EXTENT_DATA_REF_KEY: {
@@ -570,7 +590,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        key.offset = ref->offset;
                        ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0,
                                               node->bytenr,
-                                              node->ref_mod * sgn);
+                                              node->ref_mod * sgn, GFP_ATOMIC);
                        break;
                }
                case BTRFS_SHARED_DATA_REF_KEY: {
@@ -583,7 +603,7 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        key.offset = ref->offset;
                        ret = __add_prelim_ref(prefs, ref->root, &key, 0,
                                               ref->parent, node->bytenr,
-                                              node->ref_mod * sgn);
+                                              node->ref_mod * sgn, GFP_ATOMIC);
                        break;
                }
                default:
@@ -657,7 +677,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
                case BTRFS_SHARED_BLOCK_REF_KEY:
                        ret = __add_prelim_ref(prefs, 0, NULL,
                                                *info_level + 1, offset,
-                                               bytenr, 1);
+                                               bytenr, 1, GFP_NOFS);
                        break;
                case BTRFS_SHARED_DATA_REF_KEY: {
                        struct btrfs_shared_data_ref *sdref;
@@ -666,13 +686,13 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
                        sdref = (struct btrfs_shared_data_ref *)(iref + 1);
                        count = btrfs_shared_data_ref_count(leaf, sdref);
                        ret = __add_prelim_ref(prefs, 0, NULL, 0, offset,
-                                              bytenr, count);
+                                              bytenr, count, GFP_NOFS);
                        break;
                }
                case BTRFS_TREE_BLOCK_REF_KEY:
                        ret = __add_prelim_ref(prefs, offset, NULL,
                                               *info_level + 1, 0,
-                                              bytenr, 1);
+                                              bytenr, 1, GFP_NOFS);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY: {
                        struct btrfs_extent_data_ref *dref;
@@ -687,7 +707,7 @@ static int __add_inline_refs(struct btrfs_fs_info *fs_info,
                        key.offset = btrfs_extent_data_ref_offset(leaf, dref);
                        root = btrfs_extent_data_ref_root(leaf, dref);
                        ret = __add_prelim_ref(prefs, root, &key, 0, 0,
-                                              bytenr, count);
+                                              bytenr, count, GFP_NOFS);
                        break;
                }
                default:
@@ -738,7 +758,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
                case BTRFS_SHARED_BLOCK_REF_KEY:
                        ret = __add_prelim_ref(prefs, 0, NULL,
                                                info_level + 1, key.offset,
-                                               bytenr, 1);
+                                               bytenr, 1, GFP_NOFS);
                        break;
                case BTRFS_SHARED_DATA_REF_KEY: {
                        struct btrfs_shared_data_ref *sdref;
@@ -748,13 +768,13 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
                                              struct btrfs_shared_data_ref);
                        count = btrfs_shared_data_ref_count(leaf, sdref);
                        ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset,
-                                               bytenr, count);
+                                               bytenr, count, GFP_NOFS);
                        break;
                }
                case BTRFS_TREE_BLOCK_REF_KEY:
                        ret = __add_prelim_ref(prefs, key.offset, NULL,
                                               info_level + 1, 0,
-                                              bytenr, 1);
+                                              bytenr, 1, GFP_NOFS);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY: {
                        struct btrfs_extent_data_ref *dref;
@@ -770,7 +790,7 @@ static int __add_keyed_refs(struct btrfs_fs_info *fs_info,
                        key.offset = btrfs_extent_data_ref_offset(leaf, dref);
                        root = btrfs_extent_data_ref_root(leaf, dref);
                        ret = __add_prelim_ref(prefs, root, &key, 0, 0,
-                                              bytenr, count);
+                                              bytenr, count, GFP_NOFS);
                        break;
                }
                default:
@@ -911,7 +931,6 @@ again:
 
        while (!list_empty(&prefs)) {
                ref = list_first_entry(&prefs, struct __prelim_ref, list);
-               list_del(&ref->list);
                WARN_ON(ref->count < 0);
                if (ref->count && ref->root_id && ref->parent == 0) {
                        /* no parent == root of tree */
@@ -935,8 +954,10 @@ again:
                                }
                                ret = find_extent_in_eb(eb, bytenr,
                                                        *extent_item_pos, &eie);
-                               ref->inode_list = eie;
                                free_extent_buffer(eb);
+                               if (ret < 0)
+                                       goto out;
+                               ref->inode_list = eie;
                        }
                        ret = ulist_add_merge(refs, ref->parent,
                                              (uintptr_t)ref->inode_list,
@@ -954,7 +975,8 @@ again:
                                eie->next = ref->inode_list;
                        }
                }
-               kfree(ref);
+               list_del(&ref->list);
+               kmem_cache_free(btrfs_prelim_ref_cache, ref);
        }
 
 out:
@@ -962,13 +984,13 @@ out:
        while (!list_empty(&prefs)) {
                ref = list_first_entry(&prefs, struct __prelim_ref, list);
                list_del(&ref->list);
-               kfree(ref);
+               kmem_cache_free(btrfs_prelim_ref_cache, ref);
        }
        while (!list_empty(&prefs_delayed)) {
                ref = list_first_entry(&prefs_delayed, struct __prelim_ref,
                                       list);
                list_del(&ref->list);
-               kfree(ref);
+               kmem_cache_free(btrfs_prelim_ref_cache, ref);
        }
 
        return ret;
@@ -1326,8 +1348,7 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
             found_key->type != BTRFS_METADATA_ITEM_KEY) ||
            found_key->objectid > logical ||
            found_key->objectid + size <= logical) {
-               pr_debug("logical %llu is not within any extent\n",
-                        (unsigned long long)logical);
+               pr_debug("logical %llu is not within any extent\n", logical);
                return -ENOENT;
        }
 
@@ -1340,11 +1361,8 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
 
        pr_debug("logical %llu is at position %llu within the extent (%llu "
                 "EXTENT_ITEM %llu) flags %#llx size %u\n",
-                (unsigned long long)logical,
-                (unsigned long long)(logical - found_key->objectid),
-                (unsigned long long)found_key->objectid,
-                (unsigned long long)found_key->offset,
-                (unsigned long long)flags, item_size);
+                logical, logical - found_key->objectid, found_key->objectid,
+                found_key->offset, flags, item_size);
 
        WARN_ON(!flags_ret);
        if (flags_ret) {
@@ -1516,7 +1534,7 @@ int iterate_extent_inodes(struct btrfs_fs_info *fs_info,
                while (!ret && (root_node = ulist_next(roots, &root_uiter))) {
                        pr_debug("root %llu references leaf %llu, data list "
                                 "%#llx\n", root_node->val, ref_node->val,
-                                (long long)ref_node->aux);
+                                ref_node->aux);
                        ret = iterate_leaf_refs((struct extent_inode_elem *)
                                                (uintptr_t)ref_node->aux,
                                                root_node->val,
@@ -1608,9 +1626,8 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
                        name_len = btrfs_inode_ref_name_len(eb, iref);
                        /* path must be released before calling iterate()! */
                        pr_debug("following ref at offset %u for inode %llu in "
-                                "tree %llu\n", cur,
-                                (unsigned long long)found_key.objectid,
-                                (unsigned long long)fs_root->objectid);
+                                "tree %llu\n", cur, found_key.objectid,
+                                fs_root->objectid);
                        ret = iterate(parent, name_len,
                                      (unsigned long)(iref + 1), eb, ctx);
                        if (ret)
index 8f2e767029322d2d3d0ac2baf996c3964e999cdf..a910b27a8ad9a025985b491f5b169fc3270999a0 100644 (file)
@@ -72,4 +72,6 @@ int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
                          struct btrfs_inode_extref **ret_extref,
                          u64 *found_off);
 
+int __init btrfs_prelim_ref_init(void);
+void btrfs_prelim_ref_exit(void);
 #endif
index 08b286b2a2c59c78aa7a5497fe51e4da24e192c1..d0ae226926ee2d2f43d29220da8fd531f31e8687 100644 (file)
@@ -218,6 +218,27 @@ static inline int btrfs_inode_in_log(struct inode *inode, u64 generation)
        return 0;
 }
 
+struct btrfs_dio_private {
+       struct inode *inode;
+       u64 logical_offset;
+       u64 disk_bytenr;
+       u64 bytes;
+       void *private;
+
+       /* number of bios pending for this dio */
+       atomic_t pending_bios;
+
+       /* IO errors */
+       int errors;
+
+       /* orig_bio is our btrfs_io_bio */
+       struct bio *orig_bio;
+
+       /* dio_bio came from fs/direct-io.c */
+       struct bio *dio_bio;
+       u8 csum[0];
+};
+
 /*
  * Disable DIO read nolock optimization, so new dio readers will be forced
  * to grab i_mutex. It is used to avoid the endless truncate due to
index 1431a696501704d3f9e0901c64de537b2b20183a..1c47be1872406715183cd1da184f1fd11dabc3be 100644 (file)
@@ -701,15 +701,13 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
                        next_bytenr = btrfs_super_root(selected_super);
                        if (state->print_mask &
                            BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
-                               printk(KERN_INFO "root@%llu\n",
-                                      (unsigned long long)next_bytenr);
+                               printk(KERN_INFO "root@%llu\n", next_bytenr);
                        break;
                case 1:
                        next_bytenr = btrfs_super_chunk_root(selected_super);
                        if (state->print_mask &
                            BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
-                               printk(KERN_INFO "chunk@%llu\n",
-                                      (unsigned long long)next_bytenr);
+                               printk(KERN_INFO "chunk@%llu\n", next_bytenr);
                        break;
                case 2:
                        next_bytenr = btrfs_super_log_root(selected_super);
@@ -717,8 +715,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
                                continue;
                        if (state->print_mask &
                            BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
-                               printk(KERN_INFO "log@%llu\n",
-                                      (unsigned long long)next_bytenr);
+                               printk(KERN_INFO "log@%llu\n", next_bytenr);
                        break;
                }
 
@@ -727,7 +724,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
                                     next_bytenr, state->metablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
-                              (unsigned long long)next_bytenr, num_copies);
+                              next_bytenr, num_copies);
 
                for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
                        struct btrfsic_block *next_block;
@@ -742,8 +739,7 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
                                printk(KERN_INFO "btrfsic:"
                                       " btrfsic_map_block(root @%llu,"
                                       " mirror %d) failed!\n",
-                                      (unsigned long long)next_bytenr,
-                                      mirror_num);
+                                      next_bytenr, mirror_num);
                                kfree(selected_super);
                                return -1;
                        }
@@ -767,7 +763,6 @@ static int btrfsic_process_superblock(struct btrfsic_state *state,
                        if (ret < (int)PAGE_CACHE_SIZE) {
                                printk(KERN_INFO
                                       "btrfsic: read @logical %llu failed!\n",
-                                      (unsigned long long)
                                       tmp_next_block_ctx.start);
                                btrfsic_release_block_ctx(&tmp_next_block_ctx);
                                kfree(selected_super);
@@ -813,7 +808,7 @@ static int btrfsic_process_superblock_dev_mirror(
            (bh->b_data + (dev_bytenr & 4095));
 
        if (btrfs_super_bytenr(super_tmp) != dev_bytenr ||
-           super_tmp->magic != cpu_to_le64(BTRFS_MAGIC) ||
+           btrfs_super_magic(super_tmp) != BTRFS_MAGIC ||
            memcmp(device->uuid, super_tmp->dev_item.uuid, BTRFS_UUID_SIZE) ||
            btrfs_super_nodesize(super_tmp) != state->metablock_size ||
            btrfs_super_leafsize(super_tmp) != state->metablock_size ||
@@ -847,10 +842,8 @@ static int btrfsic_process_superblock_dev_mirror(
                        printk_in_rcu(KERN_INFO "New initial S-block (bdev %p, %s)"
                                     " @%llu (%s/%llu/%d)\n",
                                     superblock_bdev,
-                                    rcu_str_deref(device->name),
-                                    (unsigned long long)dev_bytenr,
-                                    dev_state->name,
-                                    (unsigned long long)dev_bytenr,
+                                    rcu_str_deref(device->name), dev_bytenr,
+                                    dev_state->name, dev_bytenr,
                                     superblock_mirror_num);
                list_add(&superblock_tmp->all_blocks_node,
                         &state->all_blocks_list);
@@ -880,20 +873,20 @@ static int btrfsic_process_superblock_dev_mirror(
                tmp_disk_key.offset = 0;
                switch (pass) {
                case 0:
-                       tmp_disk_key.objectid =
-                           cpu_to_le64(BTRFS_ROOT_TREE_OBJECTID);
+                       btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                                   BTRFS_ROOT_TREE_OBJECTID);
                        additional_string = "initial root ";
                        next_bytenr = btrfs_super_root(super_tmp);
                        break;
                case 1:
-                       tmp_disk_key.objectid =
-                           cpu_to_le64(BTRFS_CHUNK_TREE_OBJECTID);
+                       btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                                   BTRFS_CHUNK_TREE_OBJECTID);
                        additional_string = "initial chunk ";
                        next_bytenr = btrfs_super_chunk_root(super_tmp);
                        break;
                case 2:
-                       tmp_disk_key.objectid =
-                           cpu_to_le64(BTRFS_TREE_LOG_OBJECTID);
+                       btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                                   BTRFS_TREE_LOG_OBJECTID);
                        additional_string = "initial log ";
                        next_bytenr = btrfs_super_log_root(super_tmp);
                        if (0 == next_bytenr)
@@ -906,7 +899,7 @@ static int btrfsic_process_superblock_dev_mirror(
                                     next_bytenr, state->metablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
-                              (unsigned long long)next_bytenr, num_copies);
+                              next_bytenr, num_copies);
                for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
                        struct btrfsic_block *next_block;
                        struct btrfsic_block_data_ctx tmp_next_block_ctx;
@@ -918,8 +911,7 @@ static int btrfsic_process_superblock_dev_mirror(
                                              mirror_num)) {
                                printk(KERN_INFO "btrfsic: btrfsic_map_block("
                                       "bytenr @%llu, mirror %d) failed!\n",
-                                      (unsigned long long)next_bytenr,
-                                      mirror_num);
+                                      next_bytenr, mirror_num);
                                brelse(bh);
                                return -1;
                        }
@@ -1003,19 +995,17 @@ continue_with_new_stack_frame:
                    (struct btrfs_leaf *)sf->hdr;
 
                if (-1 == sf->i) {
-                       sf->nr = le32_to_cpu(leafhdr->header.nritems);
+                       sf->nr = btrfs_stack_header_nritems(&leafhdr->header);
 
                        if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
                                printk(KERN_INFO
                                       "leaf %llu items %d generation %llu"
                                       " owner %llu\n",
-                                      (unsigned long long)
-                                      sf->block_ctx->start,
-                                      sf->nr,
-                                      (unsigned long long)
-                                      le64_to_cpu(leafhdr->header.generation),
-                                      (unsigned long long)
-                                      le64_to_cpu(leafhdr->header.owner));
+                                      sf->block_ctx->start, sf->nr,
+                                      btrfs_stack_header_generation(
+                                              &leafhdr->header),
+                                      btrfs_stack_header_owner(
+                                              &leafhdr->header));
                }
 
 continue_with_current_leaf_stack_frame:
@@ -1047,10 +1037,10 @@ leaf_item_out_of_bounce_error:
                                                     &disk_item,
                                                     disk_item_offset,
                                                     sizeof(struct btrfs_item));
-                       item_offset = le32_to_cpu(disk_item.offset);
-                       item_size = le32_to_cpu(disk_item.size);
+                       item_offset = btrfs_stack_item_offset(&disk_item);
+                       item_size = btrfs_stack_item_offset(&disk_item);
                        disk_key = &disk_item.key;
-                       type = disk_key->type;
+                       type = btrfs_disk_key_type(disk_key);
 
                        if (BTRFS_ROOT_ITEM_KEY == type) {
                                struct btrfs_root_item root_item;
@@ -1066,7 +1056,7 @@ leaf_item_out_of_bounce_error:
                                        sf->block_ctx, &root_item,
                                        root_item_offset,
                                        item_size);
-                               next_bytenr = le64_to_cpu(root_item.bytenr);
+                               next_bytenr = btrfs_root_bytenr(&root_item);
 
                                sf->error =
                                    btrfsic_create_link_to_next_block(
@@ -1081,8 +1071,8 @@ leaf_item_out_of_bounce_error:
                                                &sf->num_copies,
                                                &sf->mirror_num,
                                                disk_key,
-                                               le64_to_cpu(root_item.
-                                               generation));
+                                               btrfs_root_generation(
+                                               &root_item));
                                if (sf->error)
                                        goto one_stack_frame_backwards;
 
@@ -1130,18 +1120,17 @@ leaf_item_out_of_bounce_error:
                struct btrfs_node *const nodehdr = (struct btrfs_node *)sf->hdr;
 
                if (-1 == sf->i) {
-                       sf->nr = le32_to_cpu(nodehdr->header.nritems);
+                       sf->nr = btrfs_stack_header_nritems(&nodehdr->header);
 
                        if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
                                printk(KERN_INFO "node %llu level %d items %d"
                                       " generation %llu owner %llu\n",
-                                      (unsigned long long)
                                       sf->block_ctx->start,
                                       nodehdr->header.level, sf->nr,
-                                      (unsigned long long)
-                                      le64_to_cpu(nodehdr->header.generation),
-                                      (unsigned long long)
-                                      le64_to_cpu(nodehdr->header.owner));
+                                      btrfs_stack_header_generation(
+                                      &nodehdr->header),
+                                      btrfs_stack_header_owner(
+                                      &nodehdr->header));
                }
 
 continue_with_current_node_stack_frame:
@@ -1168,7 +1157,7 @@ continue_with_current_node_stack_frame:
                        btrfsic_read_from_block_data(
                                sf->block_ctx, &key_ptr, key_ptr_offset,
                                sizeof(struct btrfs_key_ptr));
-                       next_bytenr = le64_to_cpu(key_ptr.blockptr);
+                       next_bytenr = btrfs_stack_key_blockptr(&key_ptr);
 
                        sf->error = btrfsic_create_link_to_next_block(
                                        state,
@@ -1182,7 +1171,7 @@ continue_with_current_node_stack_frame:
                                        &sf->num_copies,
                                        &sf->mirror_num,
                                        &key_ptr.key,
-                                       le64_to_cpu(key_ptr.generation));
+                                       btrfs_stack_key_generation(&key_ptr));
                        if (sf->error)
                                goto one_stack_frame_backwards;
 
@@ -1247,8 +1236,7 @@ static void btrfsic_read_from_block_data(
        unsigned long i = (start_offset + offset) >> PAGE_CACHE_SHIFT;
 
        WARN_ON(offset + len > block_ctx->len);
-       offset_in_page = (start_offset + offset) &
-                        ((unsigned long)PAGE_CACHE_SIZE - 1);
+       offset_in_page = (start_offset + offset) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
                cur = min(len, ((size_t)PAGE_CACHE_SIZE - offset_in_page));
@@ -1290,7 +1278,7 @@ static int btrfsic_create_link_to_next_block(
                                     next_bytenr, state->metablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
-                              (unsigned long long)next_bytenr, *num_copiesp);
+                              next_bytenr, *num_copiesp);
                *mirror_nump = 1;
        }
 
@@ -1307,7 +1295,7 @@ static int btrfsic_create_link_to_next_block(
        if (ret) {
                printk(KERN_INFO
                       "btrfsic: btrfsic_map_block(@%llu, mirror=%d) failed!\n",
-                      (unsigned long long)next_bytenr, *mirror_nump);
+                      next_bytenr, *mirror_nump);
                btrfsic_release_block_ctx(next_block_ctx);
                *next_blockp = NULL;
                return -1;
@@ -1335,20 +1323,16 @@ static int btrfsic_create_link_to_next_block(
                               "Referenced block @%llu (%s/%llu/%d)"
                               " found in hash table, %c,"
                               " bytenr mismatch (!= stored %llu).\n",
-                              (unsigned long long)next_bytenr,
-                              next_block_ctx->dev->name,
-                              (unsigned long long)next_block_ctx->dev_bytenr,
-                              *mirror_nump,
+                              next_bytenr, next_block_ctx->dev->name,
+                              next_block_ctx->dev_bytenr, *mirror_nump,
                               btrfsic_get_block_type(state, next_block),
-                              (unsigned long long)next_block->logical_bytenr);
+                              next_block->logical_bytenr);
                } else if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
                        printk(KERN_INFO
                               "Referenced block @%llu (%s/%llu/%d)"
                               " found in hash table, %c.\n",
-                              (unsigned long long)next_bytenr,
-                              next_block_ctx->dev->name,
-                              (unsigned long long)next_block_ctx->dev_bytenr,
-                              *mirror_nump,
+                              next_bytenr, next_block_ctx->dev->name,
+                              next_block_ctx->dev_bytenr, *mirror_nump,
                               btrfsic_get_block_type(state, next_block));
                next_block->logical_bytenr = next_bytenr;
 
@@ -1400,7 +1384,7 @@ static int btrfsic_create_link_to_next_block(
                if (ret < (int)next_block_ctx->len) {
                        printk(KERN_INFO
                               "btrfsic: read block @logical %llu failed!\n",
-                              (unsigned long long)next_bytenr);
+                              next_bytenr);
                        btrfsic_release_block_ctx(next_block_ctx);
                        *next_blockp = NULL;
                        return -1;
@@ -1444,12 +1428,12 @@ static int btrfsic_handle_extent_data(
                file_extent_item_offset,
                offsetof(struct btrfs_file_extent_item, disk_num_bytes));
        if (BTRFS_FILE_EXTENT_REG != file_extent_item.type ||
-           ((u64)0) == le64_to_cpu(file_extent_item.disk_bytenr)) {
+           btrfs_stack_file_extent_disk_bytenr(&file_extent_item) == 0) {
                if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
                        printk(KERN_INFO "extent_data: type %u, disk_bytenr = %llu\n",
                               file_extent_item.type,
-                              (unsigned long long)
-                              le64_to_cpu(file_extent_item.disk_bytenr));
+                              btrfs_stack_file_extent_disk_bytenr(
+                              &file_extent_item));
                return 0;
        }
 
@@ -1463,20 +1447,19 @@ static int btrfsic_handle_extent_data(
        btrfsic_read_from_block_data(block_ctx, &file_extent_item,
                                     file_extent_item_offset,
                                     sizeof(struct btrfs_file_extent_item));
-       next_bytenr = le64_to_cpu(file_extent_item.disk_bytenr) +
-                     le64_to_cpu(file_extent_item.offset);
-       generation = le64_to_cpu(file_extent_item.generation);
-       num_bytes = le64_to_cpu(file_extent_item.num_bytes);
-       generation = le64_to_cpu(file_extent_item.generation);
+       next_bytenr = btrfs_stack_file_extent_disk_bytenr(&file_extent_item) +
+                     btrfs_stack_file_extent_offset(&file_extent_item);
+       generation = btrfs_stack_file_extent_generation(&file_extent_item);
+       num_bytes = btrfs_stack_file_extent_num_bytes(&file_extent_item);
+       generation = btrfs_stack_file_extent_generation(&file_extent_item);
 
        if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
                printk(KERN_INFO "extent_data: type %u, disk_bytenr = %llu,"
                       " offset = %llu, num_bytes = %llu\n",
                       file_extent_item.type,
-                      (unsigned long long)
-                      le64_to_cpu(file_extent_item.disk_bytenr),
-                      (unsigned long long)le64_to_cpu(file_extent_item.offset),
-                      (unsigned long long)num_bytes);
+                      btrfs_stack_file_extent_disk_bytenr(&file_extent_item),
+                      btrfs_stack_file_extent_offset(&file_extent_item),
+                      num_bytes);
        while (num_bytes > 0) {
                u32 chunk_len;
                int num_copies;
@@ -1492,7 +1475,7 @@ static int btrfsic_handle_extent_data(
                                     next_bytenr, state->datablock_size);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
-                              (unsigned long long)next_bytenr, num_copies);
+                              next_bytenr, num_copies);
                for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
                        struct btrfsic_block_data_ctx next_block_ctx;
                        struct btrfsic_block *next_block;
@@ -1504,8 +1487,7 @@ static int btrfsic_handle_extent_data(
                        if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
                                printk(KERN_INFO
                                       "\tdisk_bytenr = %llu, num_bytes %u\n",
-                                      (unsigned long long)next_bytenr,
-                                      chunk_len);
+                                      next_bytenr, chunk_len);
                        ret = btrfsic_map_block(state, next_bytenr,
                                                chunk_len, &next_block_ctx,
                                                mirror_num);
@@ -1513,8 +1495,7 @@ static int btrfsic_handle_extent_data(
                                printk(KERN_INFO
                                       "btrfsic: btrfsic_map_block(@%llu,"
                                       " mirror=%d) failed!\n",
-                                      (unsigned long long)next_bytenr,
-                                      mirror_num);
+                                      next_bytenr, mirror_num);
                                return -1;
                        }
 
@@ -1543,12 +1524,10 @@ static int btrfsic_handle_extent_data(
                                               " found in hash table, D,"
                                               " bytenr mismatch"
                                               " (!= stored %llu).\n",
-                                              (unsigned long long)next_bytenr,
+                                              next_bytenr,
                                               next_block_ctx.dev->name,
-                                              (unsigned long long)
                                               next_block_ctx.dev_bytenr,
                                               mirror_num,
-                                              (unsigned long long)
                                               next_block->logical_bytenr);
                                }
                                next_block->logical_bytenr = next_bytenr;
@@ -1675,7 +1654,7 @@ static int btrfsic_read_block(struct btrfsic_state *state,
        if (block_ctx->dev_bytenr & ((u64)PAGE_CACHE_SIZE - 1)) {
                printk(KERN_INFO
                       "btrfsic: read_block() with unaligned bytenr %llu\n",
-                      (unsigned long long)block_ctx->dev_bytenr);
+                      block_ctx->dev_bytenr);
                return -1;
        }
 
@@ -1772,10 +1751,8 @@ static void btrfsic_dump_database(struct btrfsic_state *state)
 
                printk(KERN_INFO "%c-block @%llu (%s/%llu/%d)\n",
                       btrfsic_get_block_type(state, b_all),
-                      (unsigned long long)b_all->logical_bytenr,
-                      b_all->dev_state->name,
-                      (unsigned long long)b_all->dev_bytenr,
-                      b_all->mirror_num);
+                      b_all->logical_bytenr, b_all->dev_state->name,
+                      b_all->dev_bytenr, b_all->mirror_num);
 
                list_for_each(elem_ref_to, &b_all->ref_to_list) {
                        const struct btrfsic_block_link *const l =
@@ -1787,16 +1764,13 @@ static void btrfsic_dump_database(struct btrfsic_state *state)
                               " refers %u* to"
                               " %c @%llu (%s/%llu/%d)\n",
                               btrfsic_get_block_type(state, b_all),
-                              (unsigned long long)b_all->logical_bytenr,
-                              b_all->dev_state->name,
-                              (unsigned long long)b_all->dev_bytenr,
-                              b_all->mirror_num,
+                              b_all->logical_bytenr, b_all->dev_state->name,
+                              b_all->dev_bytenr, b_all->mirror_num,
                               l->ref_cnt,
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->dev_bytenr,
                               l->block_ref_to->mirror_num);
                }
 
@@ -1810,16 +1784,12 @@ static void btrfsic_dump_database(struct btrfsic_state *state)
                               " is ref %u* from"
                               " %c @%llu (%s/%llu/%d)\n",
                               btrfsic_get_block_type(state, b_all),
-                              (unsigned long long)b_all->logical_bytenr,
-                              b_all->dev_state->name,
-                              (unsigned long long)b_all->dev_bytenr,
-                              b_all->mirror_num,
+                              b_all->logical_bytenr, b_all->dev_state->name,
+                              b_all->dev_bytenr, b_all->mirror_num,
                               l->ref_cnt,
                               btrfsic_get_block_type(state, l->block_ref_from),
-                              (unsigned long long)
                               l->block_ref_from->logical_bytenr,
                               l->block_ref_from->dev_state->name,
-                              (unsigned long long)
                               l->block_ref_from->dev_bytenr,
                               l->block_ref_from->mirror_num);
                }
@@ -1896,8 +1866,8 @@ again:
                struct list_head *tmp_ref_to;
 
                if (block->is_superblock) {
-                       bytenr = le64_to_cpu(((struct btrfs_super_block *)
-                                             mapped_datav[0])->bytenr);
+                       bytenr = btrfs_super_bytenr((struct btrfs_super_block *)
+                                                   mapped_datav[0]);
                        if (num_pages * PAGE_CACHE_SIZE <
                            BTRFS_SUPER_INFO_SIZE) {
                                printk(KERN_INFO
@@ -1923,8 +1893,9 @@ again:
                                        return;
                                }
                                processed_len = state->metablock_size;
-                               bytenr = le64_to_cpu(((struct btrfs_header *)
-                                                     mapped_datav[0])->bytenr);
+                               bytenr = btrfs_stack_header_bytenr(
+                                               (struct btrfs_header *)
+                                               mapped_datav[0]);
                                btrfsic_cmp_log_and_dev_bytenr(state, bytenr,
                                                               dev_state,
                                                               dev_bytenr);
@@ -1935,12 +1906,9 @@ again:
                                       " found in hash table, %c,"
                                       " bytenr mismatch"
                                       " (!= stored %llu).\n",
-                                      (unsigned long long)bytenr,
-                                      dev_state->name,
-                                      (unsigned long long)dev_bytenr,
+                                      bytenr, dev_state->name, dev_bytenr,
                                       block->mirror_num,
                                       btrfsic_get_block_type(state, block),
-                                      (unsigned long long)
                                       block->logical_bytenr);
                                block->logical_bytenr = bytenr;
                        } else if (state->print_mask &
@@ -1948,9 +1916,7 @@ again:
                                printk(KERN_INFO
                                       "Written block @%llu (%s/%llu/%d)"
                                       " found in hash table, %c.\n",
-                                      (unsigned long long)bytenr,
-                                      dev_state->name,
-                                      (unsigned long long)dev_bytenr,
+                                      bytenr, dev_state->name, dev_bytenr,
                                       block->mirror_num,
                                       btrfsic_get_block_type(state, block));
                } else {
@@ -1966,9 +1932,7 @@ again:
                                printk(KERN_INFO
                                       "Written block @%llu (%s/%llu/%d)"
                                       " found in hash table, %c.\n",
-                                      (unsigned long long)bytenr,
-                                      dev_state->name,
-                                      (unsigned long long)dev_bytenr,
+                                      bytenr, dev_state->name, dev_bytenr,
                                       block->mirror_num,
                                       btrfsic_get_block_type(state, block));
                }
@@ -1985,21 +1949,14 @@ again:
                               " new(gen=%llu),"
                               " which is referenced by most recent superblock"
                               " (superblockgen=%llu)!\n",
-                              btrfsic_get_block_type(state, block),
-                              (unsigned long long)bytenr,
-                              dev_state->name,
-                              (unsigned long long)dev_bytenr,
-                              block->mirror_num,
-                              (unsigned long long)block->generation,
-                              (unsigned long long)
-                              le64_to_cpu(block->disk_key.objectid),
+                              btrfsic_get_block_type(state, block), bytenr,
+                              dev_state->name, dev_bytenr, block->mirror_num,
+                              block->generation,
+                              btrfs_disk_key_objectid(&block->disk_key),
                               block->disk_key.type,
-                              (unsigned long long)
-                              le64_to_cpu(block->disk_key.offset),
-                              (unsigned long long)
-                              le64_to_cpu(((struct btrfs_header *)
-                                           mapped_datav[0])->generation),
-                              (unsigned long long)
+                              btrfs_disk_key_offset(&block->disk_key),
+                              btrfs_stack_header_generation(
+                                      (struct btrfs_header *) mapped_datav[0]),
                               state->max_superblock_generation);
                        btrfsic_dump_tree(state);
                }
@@ -2008,15 +1965,12 @@ again:
                        printk(KERN_INFO "btrfs: attempt to overwrite %c-block"
                               " @%llu (%s/%llu/%d), oldgen=%llu, newgen=%llu,"
                               " which is not yet iodone!\n",
-                              btrfsic_get_block_type(state, block),
-                              (unsigned long long)bytenr,
-                              dev_state->name,
-                              (unsigned long long)dev_bytenr,
-                              block->mirror_num,
-                              (unsigned long long)block->generation,
-                              (unsigned long long)
-                              le64_to_cpu(((struct btrfs_header *)
-                                           mapped_datav[0])->generation));
+                              btrfsic_get_block_type(state, block), bytenr,
+                              dev_state->name, dev_bytenr, block->mirror_num,
+                              block->generation,
+                              btrfs_stack_header_generation(
+                                      (struct btrfs_header *)
+                                      mapped_datav[0]));
                        /* it would not be safe to go on */
                        btrfsic_dump_tree(state);
                        goto continue_loop;
@@ -2056,7 +2010,7 @@ again:
                if (ret) {
                        printk(KERN_INFO
                               "btrfsic: btrfsic_map_block(root @%llu)"
-                              " failed!\n", (unsigned long long)bytenr);
+                              " failed!\n", bytenr);
                        goto continue_loop;
                }
                block_ctx.datav = mapped_datav;
@@ -2140,7 +2094,7 @@ again:
                                printk(KERN_INFO
                                       "btrfsic: btrfsic_process_metablock"
                                       "(root @%llu) failed!\n",
-                                      (unsigned long long)dev_bytenr);
+                                      dev_bytenr);
                } else {
                        block->is_metadata = 0;
                        block->mirror_num = 0;  /* unknown */
@@ -2168,8 +2122,7 @@ again:
                        if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
                                printk(KERN_INFO "Written block (%s/%llu/?)"
                                       " !found in hash table, D.\n",
-                                      dev_state->name,
-                                      (unsigned long long)dev_bytenr);
+                                      dev_state->name, dev_bytenr);
                        if (!state->include_extent_data) {
                                /* ignore that written D block */
                                goto continue_loop;
@@ -2184,17 +2137,16 @@ again:
                        block_ctx.pagev = NULL;
                } else {
                        processed_len = state->metablock_size;
-                       bytenr = le64_to_cpu(((struct btrfs_header *)
-                                             mapped_datav[0])->bytenr);
+                       bytenr = btrfs_stack_header_bytenr(
+                                       (struct btrfs_header *)
+                                       mapped_datav[0]);
                        btrfsic_cmp_log_and_dev_bytenr(state, bytenr, dev_state,
                                                       dev_bytenr);
                        if (state->print_mask & BTRFSIC_PRINT_MASK_VERBOSE)
                                printk(KERN_INFO
                                       "Written block @%llu (%s/%llu/?)"
                                       " !found in hash table, M.\n",
-                                      (unsigned long long)bytenr,
-                                      dev_state->name,
-                                      (unsigned long long)dev_bytenr);
+                                      bytenr, dev_state->name, dev_bytenr);
 
                        ret = btrfsic_map_block(state, bytenr, processed_len,
                                                &block_ctx, 0);
@@ -2202,7 +2154,7 @@ again:
                                printk(KERN_INFO
                                       "btrfsic: btrfsic_map_block(root @%llu)"
                                       " failed!\n",
-                                      (unsigned long long)dev_bytenr);
+                                      dev_bytenr);
                                goto continue_loop;
                        }
                }
@@ -2267,10 +2219,8 @@ again:
                        printk(KERN_INFO
                               "New written %c-block @%llu (%s/%llu/%d)\n",
                               is_metadata ? 'M' : 'D',
-                              (unsigned long long)block->logical_bytenr,
-                              block->dev_state->name,
-                              (unsigned long long)block->dev_bytenr,
-                              block->mirror_num);
+                              block->logical_bytenr, block->dev_state->name,
+                              block->dev_bytenr, block->mirror_num);
                list_add(&block->all_blocks_node, &state->all_blocks_list);
                btrfsic_block_hashtable_add(block, &state->block_hashtable);
 
@@ -2281,7 +2231,7 @@ again:
                                printk(KERN_INFO
                                       "btrfsic: process_metablock(root @%llu)"
                                       " failed!\n",
-                                      (unsigned long long)dev_bytenr);
+                                      dev_bytenr);
                }
                btrfsic_release_block_ctx(&block_ctx);
        }
@@ -2319,10 +2269,8 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
                               "bio_end_io(err=%d) for %c @%llu (%s/%llu/%d)\n",
                               bio_error_status,
                               btrfsic_get_block_type(dev_state->state, block),
-                              (unsigned long long)block->logical_bytenr,
-                              dev_state->name,
-                              (unsigned long long)block->dev_bytenr,
-                              block->mirror_num);
+                              block->logical_bytenr, dev_state->name,
+                              block->dev_bytenr, block->mirror_num);
                next_block = block->next_in_same_bio;
                block->iodone_w_error = iodone_w_error;
                if (block->submit_bio_bh_rw & REQ_FLUSH) {
@@ -2332,7 +2280,6 @@ static void btrfsic_bio_end_io(struct bio *bp, int bio_error_status)
                                printk(KERN_INFO
                                       "bio_end_io() new %s flush_gen=%llu\n",
                                       dev_state->name,
-                                      (unsigned long long)
                                       dev_state->last_flush_gen);
                }
                if (block->submit_bio_bh_rw & REQ_FUA)
@@ -2358,10 +2305,8 @@ static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate)
                       "bh_end_io(error=%d) for %c @%llu (%s/%llu/%d)\n",
                       iodone_w_error,
                       btrfsic_get_block_type(dev_state->state, block),
-                      (unsigned long long)block->logical_bytenr,
-                      block->dev_state->name,
-                      (unsigned long long)block->dev_bytenr,
-                      block->mirror_num);
+                      block->logical_bytenr, block->dev_state->name,
+                      block->dev_bytenr, block->mirror_num);
 
        block->iodone_w_error = iodone_w_error;
        if (block->submit_bio_bh_rw & REQ_FLUSH) {
@@ -2370,8 +2315,7 @@ static void btrfsic_bh_end_io(struct buffer_head *bh, int uptodate)
                     BTRFSIC_PRINT_MASK_END_IO_BIO_BH))
                        printk(KERN_INFO
                               "bh_end_io() new %s flush_gen=%llu\n",
-                              dev_state->name,
-                              (unsigned long long)dev_state->last_flush_gen);
+                              dev_state->name, dev_state->last_flush_gen);
        }
        if (block->submit_bio_bh_rw & REQ_FUA)
                block->flush_gen = 0; /* FUA completed means block is on disk */
@@ -2396,26 +2340,20 @@ static int btrfsic_process_written_superblock(
                        printk(KERN_INFO
                               "btrfsic: superblock @%llu (%s/%llu/%d)"
                               " with old gen %llu <= %llu\n",
-                              (unsigned long long)superblock->logical_bytenr,
+                              superblock->logical_bytenr,
                               superblock->dev_state->name,
-                              (unsigned long long)superblock->dev_bytenr,
-                              superblock->mirror_num,
-                              (unsigned long long)
+                              superblock->dev_bytenr, superblock->mirror_num,
                               btrfs_super_generation(super_hdr),
-                              (unsigned long long)
                               state->max_superblock_generation);
        } else {
                if (state->print_mask & BTRFSIC_PRINT_MASK_SUPERBLOCK_WRITE)
                        printk(KERN_INFO
                               "btrfsic: got new superblock @%llu (%s/%llu/%d)"
                               " with new gen %llu > %llu\n",
-                              (unsigned long long)superblock->logical_bytenr,
+                              superblock->logical_bytenr,
                               superblock->dev_state->name,
-                              (unsigned long long)superblock->dev_bytenr,
-                              superblock->mirror_num,
-                              (unsigned long long)
+                              superblock->dev_bytenr, superblock->mirror_num,
                               btrfs_super_generation(super_hdr),
-                              (unsigned long long)
                               state->max_superblock_generation);
 
                state->max_superblock_generation =
@@ -2432,43 +2370,41 @@ static int btrfsic_process_written_superblock(
                int num_copies;
                int mirror_num;
                const char *additional_string = NULL;
-               struct btrfs_disk_key tmp_disk_key;
+               struct btrfs_disk_key tmp_disk_key = {0};
 
-               tmp_disk_key.type = BTRFS_ROOT_ITEM_KEY;
-               tmp_disk_key.offset = 0;
+               btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                           BTRFS_ROOT_ITEM_KEY);
+               btrfs_set_disk_key_objectid(&tmp_disk_key, 0);
 
                switch (pass) {
                case 0:
-                       tmp_disk_key.objectid =
-                           cpu_to_le64(BTRFS_ROOT_TREE_OBJECTID);
+                       btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                                   BTRFS_ROOT_TREE_OBJECTID);
                        additional_string = "root ";
                        next_bytenr = btrfs_super_root(super_hdr);
                        if (state->print_mask &
                            BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
-                               printk(KERN_INFO "root@%llu\n",
-                                      (unsigned long long)next_bytenr);
+                               printk(KERN_INFO "root@%llu\n", next_bytenr);
                        break;
                case 1:
-                       tmp_disk_key.objectid =
-                           cpu_to_le64(BTRFS_CHUNK_TREE_OBJECTID);
+                       btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                                   BTRFS_CHUNK_TREE_OBJECTID);
                        additional_string = "chunk ";
                        next_bytenr = btrfs_super_chunk_root(super_hdr);
                        if (state->print_mask &
                            BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
-                               printk(KERN_INFO "chunk@%llu\n",
-                                      (unsigned long long)next_bytenr);
+                               printk(KERN_INFO "chunk@%llu\n", next_bytenr);
                        break;
                case 2:
-                       tmp_disk_key.objectid =
-                           cpu_to_le64(BTRFS_TREE_LOG_OBJECTID);
+                       btrfs_set_disk_key_objectid(&tmp_disk_key,
+                                                   BTRFS_TREE_LOG_OBJECTID);
                        additional_string = "log ";
                        next_bytenr = btrfs_super_log_root(super_hdr);
                        if (0 == next_bytenr)
                                continue;
                        if (state->print_mask &
                            BTRFSIC_PRINT_MASK_ROOT_CHUNK_LOG_TREE_LOCATION)
-                               printk(KERN_INFO "log@%llu\n",
-                                      (unsigned long long)next_bytenr);
+                               printk(KERN_INFO "log@%llu\n", next_bytenr);
                        break;
                }
 
@@ -2477,7 +2413,7 @@ static int btrfsic_process_written_superblock(
                                     next_bytenr, BTRFS_SUPER_INFO_SIZE);
                if (state->print_mask & BTRFSIC_PRINT_MASK_NUM_COPIES)
                        printk(KERN_INFO "num_copies(log_bytenr=%llu) = %d\n",
-                              (unsigned long long)next_bytenr, num_copies);
+                              next_bytenr, num_copies);
                for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
                        int was_created;
 
@@ -2493,8 +2429,7 @@ static int btrfsic_process_written_superblock(
                                printk(KERN_INFO
                                       "btrfsic: btrfsic_map_block(@%llu,"
                                       " mirror=%d) failed!\n",
-                                      (unsigned long long)next_bytenr,
-                                      mirror_num);
+                                      next_bytenr, mirror_num);
                                return -1;
                        }
 
@@ -2579,26 +2514,22 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
                               " %u* refers to %c @%llu (%s/%llu/%d)\n",
                               recursion_level,
                               btrfsic_get_block_type(state, block),
-                              (unsigned long long)block->logical_bytenr,
-                              block->dev_state->name,
-                              (unsigned long long)block->dev_bytenr,
-                              block->mirror_num,
+                              block->logical_bytenr, block->dev_state->name,
+                              block->dev_bytenr, block->mirror_num,
                               l->ref_cnt,
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->dev_bytenr,
                               l->block_ref_to->mirror_num);
                if (l->block_ref_to->never_written) {
                        printk(KERN_INFO "btrfs: attempt to write superblock"
                               " which references block %c @%llu (%s/%llu/%d)"
                               " which is never written!\n",
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->dev_bytenr,
                               l->block_ref_to->mirror_num);
                        ret = -1;
                } else if (!l->block_ref_to->is_iodone) {
@@ -2606,10 +2537,9 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
                               " which references block %c @%llu (%s/%llu/%d)"
                               " which is not yet iodone!\n",
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->dev_bytenr,
                               l->block_ref_to->mirror_num);
                        ret = -1;
                } else if (l->block_ref_to->iodone_w_error) {
@@ -2617,10 +2547,9 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
                               " which references block %c @%llu (%s/%llu/%d)"
                               " which has write error!\n",
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->dev_bytenr,
                               l->block_ref_to->mirror_num);
                        ret = -1;
                } else if (l->parent_generation !=
@@ -2634,13 +2563,12 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
                               " with generation %llu !="
                               " parent generation %llu!\n",
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->dev_bytenr,
                               l->block_ref_to->mirror_num,
-                              (unsigned long long)l->block_ref_to->generation,
-                              (unsigned long long)l->parent_generation);
+                              l->block_ref_to->generation,
+                              l->parent_generation);
                        ret = -1;
                } else if (l->block_ref_to->flush_gen >
                           l->block_ref_to->dev_state->last_flush_gen) {
@@ -2650,13 +2578,10 @@ static int btrfsic_check_all_ref_blocks(struct btrfsic_state *state,
                               " (block flush_gen=%llu,"
                               " dev->flush_gen=%llu)!\n",
                               btrfsic_get_block_type(state, l->block_ref_to),
-                              (unsigned long long)
                               l->block_ref_to->logical_bytenr,
                               l->block_ref_to->dev_state->name,
-                              (unsigned long long)l->block_ref_to->dev_bytenr,
-                              l->block_ref_to->mirror_num,
-                              (unsigned long long)block->flush_gen,
-                              (unsigned long long)
+                              l->block_ref_to->dev_bytenr,
+                              l->block_ref_to->mirror_num, block->flush_gen,
                               l->block_ref_to->dev_state->last_flush_gen);
                        ret = -1;
                } else if (-1 == btrfsic_check_all_ref_blocks(state,
@@ -2701,16 +2626,12 @@ static int btrfsic_is_block_ref_by_superblock(
                               " is ref %u* from %c @%llu (%s/%llu/%d)\n",
                               recursion_level,
                               btrfsic_get_block_type(state, block),
-                              (unsigned long long)block->logical_bytenr,
-                              block->dev_state->name,
-                              (unsigned long long)block->dev_bytenr,
-                              block->mirror_num,
+                              block->logical_bytenr, block->dev_state->name,
+                              block->dev_bytenr, block->mirror_num,
                               l->ref_cnt,
                               btrfsic_get_block_type(state, l->block_ref_from),
-                              (unsigned long long)
                               l->block_ref_from->logical_bytenr,
                               l->block_ref_from->dev_state->name,
-                              (unsigned long long)
                               l->block_ref_from->dev_bytenr,
                               l->block_ref_from->mirror_num);
                if (l->block_ref_from->is_superblock &&
@@ -2737,14 +2658,12 @@ static void btrfsic_print_add_link(const struct btrfsic_state *state,
               " to %c @%llu (%s/%llu/%d).\n",
               l->ref_cnt,
               btrfsic_get_block_type(state, l->block_ref_from),
-              (unsigned long long)l->block_ref_from->logical_bytenr,
+              l->block_ref_from->logical_bytenr,
               l->block_ref_from->dev_state->name,
-              (unsigned long long)l->block_ref_from->dev_bytenr,
-              l->block_ref_from->mirror_num,
+              l->block_ref_from->dev_bytenr, l->block_ref_from->mirror_num,
               btrfsic_get_block_type(state, l->block_ref_to),
-              (unsigned long long)l->block_ref_to->logical_bytenr,
-              l->block_ref_to->dev_state->name,
-              (unsigned long long)l->block_ref_to->dev_bytenr,
+              l->block_ref_to->logical_bytenr,
+              l->block_ref_to->dev_state->name, l->block_ref_to->dev_bytenr,
               l->block_ref_to->mirror_num);
 }
 
@@ -2756,14 +2675,12 @@ static void btrfsic_print_rem_link(const struct btrfsic_state *state,
               " to %c @%llu (%s/%llu/%d).\n",
               l->ref_cnt,
               btrfsic_get_block_type(state, l->block_ref_from),
-              (unsigned long long)l->block_ref_from->logical_bytenr,
+              l->block_ref_from->logical_bytenr,
               l->block_ref_from->dev_state->name,
-              (unsigned long long)l->block_ref_from->dev_bytenr,
-              l->block_ref_from->mirror_num,
+              l->block_ref_from->dev_bytenr, l->block_ref_from->mirror_num,
               btrfsic_get_block_type(state, l->block_ref_to),
-              (unsigned long long)l->block_ref_to->logical_bytenr,
-              l->block_ref_to->dev_state->name,
-              (unsigned long long)l->block_ref_to->dev_bytenr,
+              l->block_ref_to->logical_bytenr,
+              l->block_ref_to->dev_state->name, l->block_ref_to->dev_bytenr,
               l->block_ref_to->mirror_num);
 }
 
@@ -2807,10 +2724,8 @@ static void btrfsic_dump_tree_sub(const struct btrfsic_state *state,
         */
        indent_add = sprintf(buf, "%c-%llu(%s/%llu/%d)",
                             btrfsic_get_block_type(state, block),
-                            (unsigned long long)block->logical_bytenr,
-                            block->dev_state->name,
-                            (unsigned long long)block->dev_bytenr,
-                            block->mirror_num);
+                            block->logical_bytenr, block->dev_state->name,
+                            block->dev_bytenr, block->mirror_num);
        if (indent_level + indent_add > BTRFSIC_TREE_DUMP_MAX_INDENT_LEVEL) {
                printk("[...]\n");
                return;
@@ -2943,10 +2858,8 @@ static struct btrfsic_block *btrfsic_block_lookup_or_add(
                               "New %s%c-block @%llu (%s/%llu/%d)\n",
                               additional_string,
                               btrfsic_get_block_type(state, block),
-                              (unsigned long long)block->logical_bytenr,
-                              dev_state->name,
-                              (unsigned long long)block->dev_bytenr,
-                              mirror_num);
+                              block->logical_bytenr, dev_state->name,
+                              block->dev_bytenr, mirror_num);
                list_add(&block->all_blocks_node, &state->all_blocks_list);
                btrfsic_block_hashtable_add(block, &state->block_hashtable);
                if (NULL != was_created)
@@ -2980,7 +2893,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
                        printk(KERN_INFO "btrfsic:"
                               " btrfsic_map_block(logical @%llu,"
                               " mirror %d) failed!\n",
-                              (unsigned long long)bytenr, mirror_num);
+                              bytenr, mirror_num);
                        continue;
                }
 
@@ -2997,8 +2910,7 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
                printk(KERN_INFO "btrfs: attempt to write M-block which contains logical bytenr that doesn't map to dev+physical bytenr of submit_bio,"
                       " buffer->log_bytenr=%llu, submit_bio(bdev=%s,"
                       " phys_bytenr=%llu)!\n",
-                      (unsigned long long)bytenr, dev_state->name,
-                      (unsigned long long)dev_bytenr);
+                      bytenr, dev_state->name, dev_bytenr);
                for (mirror_num = 1; mirror_num <= num_copies; mirror_num++) {
                        ret = btrfsic_map_block(state, bytenr,
                                                state->metablock_size,
@@ -3008,10 +2920,8 @@ static void btrfsic_cmp_log_and_dev_bytenr(struct btrfsic_state *state,
 
                        printk(KERN_INFO "Read logical bytenr @%llu maps to"
                               " (%s/%llu/%d)\n",
-                              (unsigned long long)bytenr,
-                              block_ctx.dev->name,
-                              (unsigned long long)block_ctx.dev_bytenr,
-                              mirror_num);
+                              bytenr, block_ctx.dev->name,
+                              block_ctx.dev_bytenr, mirror_num);
                }
                WARN_ON(1);
        }
@@ -3048,12 +2958,10 @@ int btrfsic_submit_bh(int rw, struct buffer_head *bh)
                if (dev_state->state->print_mask &
                    BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
                        printk(KERN_INFO
-                              "submit_bh(rw=0x%x, blocknr=%lu (bytenr %llu),"
-                              " size=%lu, data=%p, bdev=%p)\n",
-                              rw, (unsigned long)bh->b_blocknr,
-                              (unsigned long long)dev_bytenr,
-                              (unsigned long)bh->b_size, bh->b_data,
-                              bh->b_bdev);
+                              "submit_bh(rw=0x%x, blocknr=%llu (bytenr %llu),"
+                              " size=%zu, data=%p, bdev=%p)\n",
+                              rw, (unsigned long long)bh->b_blocknr,
+                              dev_bytenr, bh->b_size, bh->b_data, bh->b_bdev);
                btrfsic_process_written_block(dev_state, dev_bytenr,
                                              &bh->b_data, 1, NULL,
                                              NULL, bh, rw);
@@ -3118,9 +3026,9 @@ void btrfsic_submit_bio(int rw, struct bio *bio)
                    BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
                        printk(KERN_INFO
                               "submit_bio(rw=0x%x, bi_vcnt=%u,"
-                              " bi_sector=%lu (bytenr %llu), bi_bdev=%p)\n",
-                              rw, bio->bi_vcnt, (unsigned long)bio->bi_sector,
-                              (unsigned long long)dev_bytenr,
+                              " bi_sector=%llu (bytenr %llu), bi_bdev=%p)\n",
+                              rw, bio->bi_vcnt,
+                              (unsigned long long)bio->bi_sector, dev_bytenr,
                               bio->bi_bdev);
 
                mapped_datav = kmalloc(sizeof(*mapped_datav) * bio->bi_vcnt,
@@ -3213,19 +3121,19 @@ int btrfsic_mount(struct btrfs_root *root,
        if (root->nodesize & ((u64)PAGE_CACHE_SIZE - 1)) {
                printk(KERN_INFO
                       "btrfsic: cannot handle nodesize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
-                      root->nodesize, (unsigned long)PAGE_CACHE_SIZE);
+                      root->nodesize, PAGE_CACHE_SIZE);
                return -1;
        }
        if (root->leafsize & ((u64)PAGE_CACHE_SIZE - 1)) {
                printk(KERN_INFO
                       "btrfsic: cannot handle leafsize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
-                      root->leafsize, (unsigned long)PAGE_CACHE_SIZE);
+                      root->leafsize, PAGE_CACHE_SIZE);
                return -1;
        }
        if (root->sectorsize & ((u64)PAGE_CACHE_SIZE - 1)) {
                printk(KERN_INFO
                       "btrfsic: cannot handle sectorsize %d not being a multiple of PAGE_CACHE_SIZE %ld!\n",
-                      root->sectorsize, (unsigned long)PAGE_CACHE_SIZE);
+                      root->sectorsize, PAGE_CACHE_SIZE);
                return -1;
        }
        state = kzalloc(sizeof(*state), GFP_NOFS);
@@ -3369,10 +3277,8 @@ void btrfsic_unmount(struct btrfs_root *root,
                               " @%llu (%s/%llu/%d) on umount which is"
                               " not yet iodone!\n",
                               btrfsic_get_block_type(state, b_all),
-                              (unsigned long long)b_all->logical_bytenr,
-                              b_all->dev_state->name,
-                              (unsigned long long)b_all->dev_bytenr,
-                              b_all->mirror_num);
+                              b_all->logical_bytenr, b_all->dev_state->name,
+                              b_all->dev_bytenr, b_all->mirror_num);
        }
 
        mutex_unlock(&btrfsic_mutex);
index b189bd1e7a3e45bf92002e35c8db525886c7593d..6aad98cb343fba0941b9044dabaa9e64697c7354 100644 (file)
@@ -132,9 +132,8 @@ static int check_compressed_csum(struct inode *inode,
                        printk(KERN_INFO "btrfs csum failed ino %llu "
                               "extent %llu csum %u "
                               "wanted %u mirror %d\n",
-                              (unsigned long long)btrfs_ino(inode),
-                              (unsigned long long)disk_start,
-                              csum, *cb_sum, cb->mirror_num);
+                              btrfs_ino(inode), disk_start, csum, *cb_sum,
+                              cb->mirror_num);
                        ret = -EIO;
                        goto fail;
                }
@@ -639,7 +638,11 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        faili = nr_pages - 1;
        cb->nr_pages = nr_pages;
 
-       add_ra_bio_pages(inode, em_start + em_len, cb);
+       /* In the parent-locked case, we only locked the range we are
+        * interested in.  In all other cases, we can opportunistically
+        * cache decompressed data that goes beyond the requested range. */
+       if (!(bio_flags & EXTENT_BIO_PARENT_LOCKED))
+               add_ra_bio_pages(inode, em_start + em_len, cb);
 
        /* include any pages we added in add_ra-bio_pages */
        uncompressed_len = bio->bi_vcnt * PAGE_CACHE_SIZE;
index ed504607d8ecc9e7e492b9c0f2d88ce02ae1d32b..64346721173f24f31170a8e70e85f7d49a83b609 100644 (file)
@@ -274,8 +274,7 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
        else
                btrfs_set_header_owner(cow, new_root_objectid);
 
-       write_extent_buffer(cow, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(cow),
+       write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(cow),
                            BTRFS_FSID_SIZE);
 
        WARN_ON(btrfs_header_generation(buf) > trans->transid);
@@ -484,8 +483,27 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
        struct rb_node **new;
        struct rb_node *parent = NULL;
        struct tree_mod_elem *cur;
+       int ret = 0;
+
+       BUG_ON(!tm);
+
+       tree_mod_log_write_lock(fs_info);
+       if (list_empty(&fs_info->tree_mod_seq_list)) {
+               tree_mod_log_write_unlock(fs_info);
+               /*
+                * Ok we no longer care about logging modifications, free up tm
+                * and return 0.  Any callers shouldn't be using tm after
+                * calling tree_mod_log_insert, but if they do we can just
+                * change this to return a special error code to let the callers
+                * do their own thing.
+                */
+               kfree(tm);
+               return 0;
+       }
 
-       BUG_ON(!tm || !tm->seq);
+       spin_lock(&fs_info->tree_mod_seq_lock);
+       tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
+       spin_unlock(&fs_info->tree_mod_seq_lock);
 
        tm_root = &fs_info->tree_mod_log;
        new = &tm_root->rb_node;
@@ -501,14 +519,17 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
                else if (cur->seq > tm->seq)
                        new = &((*new)->rb_right);
                else {
+                       ret = -EEXIST;
                        kfree(tm);
-                       return -EEXIST;
+                       goto out;
                }
        }
 
        rb_link_node(&tm->node, parent, new);
        rb_insert_color(&tm->node, tm_root);
-       return 0;
+out:
+       tree_mod_log_write_unlock(fs_info);
+       return ret;
 }
 
 /*
@@ -524,57 +545,19 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
                return 1;
        if (eb && btrfs_header_level(eb) == 0)
                return 1;
-
-       tree_mod_log_write_lock(fs_info);
-       if (list_empty(&fs_info->tree_mod_seq_list)) {
-               /*
-                * someone emptied the list while we were waiting for the lock.
-                * we must not add to the list when no blocker exists.
-                */
-               tree_mod_log_write_unlock(fs_info);
-               return 1;
-       }
-
        return 0;
 }
 
-/*
- * This allocates memory and gets a tree modification sequence number.
- *
- * Returns <0 on error.
- * Returns >0 (the added sequence number) on success.
- */
-static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags,
-                                struct tree_mod_elem **tm_ret)
-{
-       struct tree_mod_elem *tm;
-
-       /*
-        * once we switch from spin locks to something different, we should
-        * honor the flags parameter here.
-        */
-       tm = *tm_ret = kzalloc(sizeof(*tm), GFP_ATOMIC);
-       if (!tm)
-               return -ENOMEM;
-
-       spin_lock(&fs_info->tree_mod_seq_lock);
-       tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
-       spin_unlock(&fs_info->tree_mod_seq_lock);
-
-       return tm->seq;
-}
-
 static inline int
 __tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
                          struct extent_buffer *eb, int slot,
                          enum mod_log_op op, gfp_t flags)
 {
-       int ret;
        struct tree_mod_elem *tm;
 
-       ret = tree_mod_alloc(fs_info, flags, &tm);
-       if (ret < 0)
-               return ret;
+       tm = kzalloc(sizeof(*tm), flags);
+       if (!tm)
+               return -ENOMEM;
 
        tm->index = eb->start >> PAGE_CACHE_SHIFT;
        if (op != MOD_LOG_KEY_ADD) {
@@ -589,34 +572,14 @@ __tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
 }
 
 static noinline int
-tree_mod_log_insert_key_mask(struct btrfs_fs_info *fs_info,
-                            struct extent_buffer *eb, int slot,
-                            enum mod_log_op op, gfp_t flags)
+tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
+                       struct extent_buffer *eb, int slot,
+                       enum mod_log_op op, gfp_t flags)
 {
-       int ret;
-
        if (tree_mod_dont_log(fs_info, eb))
                return 0;
 
-       ret = __tree_mod_log_insert_key(fs_info, eb, slot, op, flags);
-
-       tree_mod_log_write_unlock(fs_info);
-       return ret;
-}
-
-static noinline int
-tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
-                       int slot, enum mod_log_op op)
-{
-       return tree_mod_log_insert_key_mask(fs_info, eb, slot, op, GFP_NOFS);
-}
-
-static noinline int
-tree_mod_log_insert_key_locked(struct btrfs_fs_info *fs_info,
-                            struct extent_buffer *eb, int slot,
-                            enum mod_log_op op)
-{
-       return __tree_mod_log_insert_key(fs_info, eb, slot, op, GFP_NOFS);
+       return __tree_mod_log_insert_key(fs_info, eb, slot, op, flags);
 }
 
 static noinline int
@@ -637,14 +600,14 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
         * buffer, i.e. dst_slot < src_slot.
         */
        for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
-               ret = tree_mod_log_insert_key_locked(fs_info, eb, i + dst_slot,
-                                             MOD_LOG_KEY_REMOVE_WHILE_MOVING);
+               ret = __tree_mod_log_insert_key(fs_info, eb, i + dst_slot,
+                               MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS);
                BUG_ON(ret < 0);
        }
 
-       ret = tree_mod_alloc(fs_info, flags, &tm);
-       if (ret < 0)
-               goto out;
+       tm = kzalloc(sizeof(*tm), flags);
+       if (!tm)
+               return -ENOMEM;
 
        tm->index = eb->start >> PAGE_CACHE_SHIFT;
        tm->slot = src_slot;
@@ -652,10 +615,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
        tm->move.nr_items = nr_items;
        tm->op = MOD_LOG_MOVE_KEYS;
 
-       ret = __tree_mod_log_insert(fs_info, tm);
-out:
-       tree_mod_log_write_unlock(fs_info);
-       return ret;
+       return __tree_mod_log_insert(fs_info, tm);
 }
 
 static inline void
@@ -670,8 +630,8 @@ __tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
 
        nritems = btrfs_header_nritems(eb);
        for (i = nritems - 1; i >= 0; i--) {
-               ret = tree_mod_log_insert_key_locked(fs_info, eb, i,
-                                             MOD_LOG_KEY_REMOVE_WHILE_FREEING);
+               ret = __tree_mod_log_insert_key(fs_info, eb, i,
+                               MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
                BUG_ON(ret < 0);
        }
 }
@@ -683,7 +643,6 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
                         int log_removal)
 {
        struct tree_mod_elem *tm;
-       int ret;
 
        if (tree_mod_dont_log(fs_info, NULL))
                return 0;
@@ -691,9 +650,9 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
        if (log_removal)
                __tree_mod_log_free_eb(fs_info, old_root);
 
-       ret = tree_mod_alloc(fs_info, flags, &tm);
-       if (ret < 0)
-               goto out;
+       tm = kzalloc(sizeof(*tm), flags);
+       if (!tm)
+               return -ENOMEM;
 
        tm->index = new_root->start >> PAGE_CACHE_SHIFT;
        tm->old_root.logical = old_root->start;
@@ -701,10 +660,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
        tm->generation = btrfs_header_generation(old_root);
        tm->op = MOD_LOG_ROOT_REPLACE;
 
-       ret = __tree_mod_log_insert(fs_info, tm);
-out:
-       tree_mod_log_write_unlock(fs_info);
-       return ret;
+       return __tree_mod_log_insert(fs_info, tm);
 }
 
 static struct tree_mod_elem *
@@ -784,23 +740,20 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
        if (tree_mod_dont_log(fs_info, NULL))
                return;
 
-       if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) {
-               tree_mod_log_write_unlock(fs_info);
+       if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0)
                return;
-       }
 
        for (i = 0; i < nr_items; i++) {
-               ret = tree_mod_log_insert_key_locked(fs_info, src,
+               ret = __tree_mod_log_insert_key(fs_info, src,
                                                i + src_offset,
-                                               MOD_LOG_KEY_REMOVE);
+                                               MOD_LOG_KEY_REMOVE, GFP_NOFS);
                BUG_ON(ret < 0);
-               ret = tree_mod_log_insert_key_locked(fs_info, dst,
+               ret = __tree_mod_log_insert_key(fs_info, dst,
                                                     i + dst_offset,
-                                                    MOD_LOG_KEY_ADD);
+                                                    MOD_LOG_KEY_ADD,
+                                                    GFP_NOFS);
                BUG_ON(ret < 0);
        }
-
-       tree_mod_log_write_unlock(fs_info);
 }
 
 static inline void
@@ -819,9 +772,9 @@ tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
 {
        int ret;
 
-       ret = tree_mod_log_insert_key_mask(fs_info, eb, slot,
-                                          MOD_LOG_KEY_REPLACE,
-                                          atomic ? GFP_ATOMIC : GFP_NOFS);
+       ret = __tree_mod_log_insert_key(fs_info, eb, slot,
+                                       MOD_LOG_KEY_REPLACE,
+                                       atomic ? GFP_ATOMIC : GFP_NOFS);
        BUG_ON(ret < 0);
 }
 
@@ -830,10 +783,7 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
 {
        if (tree_mod_dont_log(fs_info, eb))
                return;
-
        __tree_mod_log_free_eb(fs_info, eb);
-
-       tree_mod_log_write_unlock(fs_info);
 }
 
 static noinline void
@@ -1046,8 +996,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
        else
                btrfs_set_header_owner(cow, root->root_key.objectid);
 
-       write_extent_buffer(cow, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(cow),
+       write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(cow),
                            BTRFS_FSID_SIZE);
 
        ret = update_ref_for_cow(trans, root, buf, cow, &last_ref);
@@ -1083,7 +1032,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
 
                WARN_ON(trans->transid != btrfs_header_generation(parent));
                tree_mod_log_insert_key(root->fs_info, parent, parent_slot,
-                                       MOD_LOG_KEY_REPLACE);
+                                       MOD_LOG_KEY_REPLACE, GFP_NOFS);
                btrfs_set_node_blockptr(parent, parent_slot,
                                        cow->start);
                btrfs_set_node_ptr_generation(parent, parent_slot,
@@ -1116,7 +1065,7 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
        int looped = 0;
 
        if (!time_seq)
-               return 0;
+               return NULL;
 
        /*
         * the very last operation that's logged for a root is the replacement
@@ -1127,7 +1076,7 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info,
                tm = tree_mod_log_search_oldest(fs_info, root_logical,
                                                time_seq);
                if (!looped && !tm)
-                       return 0;
+                       return NULL;
                /*
                 * if there are no tree operation for the oldest root, we simply
                 * return it. this should only happen if that (old) root is at
@@ -1240,8 +1189,8 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
  * is freed (its refcount is decremented).
  */
 static struct extent_buffer *
-tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
-                   u64 time_seq)
+tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
+                   struct extent_buffer *eb, u64 time_seq)
 {
        struct extent_buffer *eb_rewin;
        struct tree_mod_elem *tm;
@@ -1256,11 +1205,18 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
        if (!tm)
                return eb;
 
+       btrfs_set_path_blocking(path);
+       btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
+
        if (tm->op == MOD_LOG_KEY_REMOVE_WHILE_FREEING) {
                BUG_ON(tm->slot != 0);
                eb_rewin = alloc_dummy_extent_buffer(eb->start,
                                                fs_info->tree_root->nodesize);
-               BUG_ON(!eb_rewin);
+               if (!eb_rewin) {
+                       btrfs_tree_read_unlock_blocking(eb);
+                       free_extent_buffer(eb);
+                       return NULL;
+               }
                btrfs_set_header_bytenr(eb_rewin, eb->start);
                btrfs_set_header_backref_rev(eb_rewin,
                                             btrfs_header_backref_rev(eb));
@@ -1268,10 +1224,15 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
                btrfs_set_header_level(eb_rewin, btrfs_header_level(eb));
        } else {
                eb_rewin = btrfs_clone_extent_buffer(eb);
-               BUG_ON(!eb_rewin);
+               if (!eb_rewin) {
+                       btrfs_tree_read_unlock_blocking(eb);
+                       free_extent_buffer(eb);
+                       return NULL;
+               }
        }
 
-       btrfs_tree_read_unlock(eb);
+       btrfs_clear_path_blocking(path, NULL, BTRFS_READ_LOCK);
+       btrfs_tree_read_unlock_blocking(eb);
        free_extent_buffer(eb);
 
        extent_buffer_get(eb_rewin);
@@ -1335,8 +1296,9 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
                free_extent_buffer(eb_root);
                eb = alloc_dummy_extent_buffer(logical, root->nodesize);
        } else {
+               btrfs_set_lock_blocking_rw(eb_root, BTRFS_READ_LOCK);
                eb = btrfs_clone_extent_buffer(eb_root);
-               btrfs_tree_read_unlock(eb_root);
+               btrfs_tree_read_unlock_blocking(eb_root);
                free_extent_buffer(eb_root);
        }
 
@@ -1419,14 +1381,12 @@ noinline int btrfs_cow_block(struct btrfs_trans_handle *trans,
 
        if (trans->transaction != root->fs_info->running_transaction)
                WARN(1, KERN_CRIT "trans %llu running %llu\n",
-                      (unsigned long long)trans->transid,
-                      (unsigned long long)
+                      trans->transid,
                       root->fs_info->running_transaction->transid);
 
        if (trans->transid != root->fs_info->generation)
                WARN(1, KERN_CRIT "trans %llu running %llu\n",
-                      (unsigned long long)trans->transid,
-                      (unsigned long long)root->fs_info->generation);
+                      trans->transid, root->fs_info->generation);
 
        if (!should_cow_block(trans, root, buf)) {
                *cow_ret = buf;
@@ -2466,6 +2426,40 @@ done:
        return ret;
 }
 
+static void key_search_validate(struct extent_buffer *b,
+                               struct btrfs_key *key,
+                               int level)
+{
+#ifdef CONFIG_BTRFS_ASSERT
+       struct btrfs_disk_key disk_key;
+
+       btrfs_cpu_key_to_disk(&disk_key, key);
+
+       if (level == 0)
+               ASSERT(!memcmp_extent_buffer(b, &disk_key,
+                   offsetof(struct btrfs_leaf, items[0].key),
+                   sizeof(disk_key)));
+       else
+               ASSERT(!memcmp_extent_buffer(b, &disk_key,
+                   offsetof(struct btrfs_node, ptrs[0].key),
+                   sizeof(disk_key)));
+#endif
+}
+
+static int key_search(struct extent_buffer *b, struct btrfs_key *key,
+                     int level, int *prev_cmp, int *slot)
+{
+       if (*prev_cmp != 0) {
+               *prev_cmp = bin_search(b, key, level, slot);
+               return *prev_cmp;
+       }
+
+       key_search_validate(b, key, level);
+       *slot = 0;
+
+       return 0;
+}
+
 /*
  * look for key in the tree.  path is filled in with nodes along the way
  * if key is found, we return zero and you can find the item in the leaf
@@ -2494,6 +2488,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        int write_lock_level = 0;
        u8 lowest_level = 0;
        int min_write_lock_level;
+       int prev_cmp;
 
        lowest_level = p->lowest_level;
        WARN_ON(lowest_level && ins_len > 0);
@@ -2524,6 +2519,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        min_write_lock_level = write_lock_level;
 
 again:
+       prev_cmp = -1;
        /*
         * we try very hard to do read locks on the root
         */
@@ -2624,7 +2620,7 @@ cow_done:
                if (!cow)
                        btrfs_unlock_up_safe(p, level + 1);
 
-               ret = bin_search(b, key, level, &slot);
+               ret = key_search(b, key, level, &prev_cmp, &slot);
 
                if (level != 0) {
                        int dec = 0;
@@ -2759,6 +2755,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
        int level;
        int lowest_unlock = 1;
        u8 lowest_level = 0;
+       int prev_cmp;
 
        lowest_level = p->lowest_level;
        WARN_ON(p->nodes[0] != NULL);
@@ -2769,6 +2766,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
        }
 
 again:
+       prev_cmp = -1;
        b = get_old_root(root, time_seq);
        level = btrfs_header_level(b);
        p->locks[level] = BTRFS_READ_LOCK;
@@ -2786,7 +2784,7 @@ again:
                 */
                btrfs_unlock_up_safe(p, level + 1);
 
-               ret = bin_search(b, key, level, &slot);
+               ret = key_search(b, key, level, &prev_cmp, &slot);
 
                if (level != 0) {
                        int dec = 0;
@@ -2820,7 +2818,11 @@ again:
                                btrfs_clear_path_blocking(p, b,
                                                          BTRFS_READ_LOCK);
                        }
-                       b = tree_mod_log_rewind(root->fs_info, b, time_seq);
+                       b = tree_mod_log_rewind(root->fs_info, p, b, time_seq);
+                       if (!b) {
+                               ret = -ENOMEM;
+                               goto done;
+                       }
                        p->locks[level] = BTRFS_READ_LOCK;
                        p->nodes[level] = b;
                } else {
@@ -3143,13 +3145,11 @@ static noinline int insert_new_root(struct btrfs_trans_handle *trans,
        btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV);
        btrfs_set_header_owner(c, root->root_key.objectid);
 
-       write_extent_buffer(c, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(c),
+       write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(c),
                            BTRFS_FSID_SIZE);
 
        write_extent_buffer(c, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(c),
-                           BTRFS_UUID_SIZE);
+                           btrfs_header_chunk_tree_uuid(c), BTRFS_UUID_SIZE);
 
        btrfs_set_node_key(c, &lower_key, 0);
        btrfs_set_node_blockptr(c, 0, lower->start);
@@ -3208,7 +3208,7 @@ static void insert_ptr(struct btrfs_trans_handle *trans,
        }
        if (level) {
                ret = tree_mod_log_insert_key(root->fs_info, lower, slot,
-                                             MOD_LOG_KEY_ADD);
+                                             MOD_LOG_KEY_ADD, GFP_NOFS);
                BUG_ON(ret < 0);
        }
        btrfs_set_node_key(lower, key, slot);
@@ -3284,10 +3284,9 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
        btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV);
        btrfs_set_header_owner(split, root->root_key.objectid);
        write_extent_buffer(split, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(split),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(split), BTRFS_FSID_SIZE);
        write_extent_buffer(split, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(split),
+                           btrfs_header_chunk_tree_uuid(split),
                            BTRFS_UUID_SIZE);
 
        tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid);
@@ -4040,11 +4039,10 @@ again:
        btrfs_set_header_owner(right, root->root_key.objectid);
        btrfs_set_header_level(right, 0);
        write_extent_buffer(right, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(right),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(right), BTRFS_FSID_SIZE);
 
        write_extent_buffer(right, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(right),
+                           btrfs_header_chunk_tree_uuid(right),
                            BTRFS_UUID_SIZE);
 
        if (split == 0) {
@@ -4642,7 +4640,7 @@ static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
                              (nritems - slot - 1));
        } else if (level) {
                ret = tree_mod_log_insert_key(root->fs_info, parent, slot,
-                                             MOD_LOG_KEY_REMOVE);
+                                             MOD_LOG_KEY_REMOVE, GFP_NOFS);
                BUG_ON(ret < 0);
        }
 
@@ -4814,7 +4812,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
  * This may release the path, and so you may lose any locks held at the
  * time you call it.
  */
-int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
+static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 {
        struct btrfs_key key;
        struct btrfs_disk_key found_key;
@@ -5329,19 +5327,20 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
                                        goto out;
                                advance_right = ADVANCE;
                        } else {
+                               enum btrfs_compare_tree_result cmp;
+
                                WARN_ON(!extent_buffer_uptodate(left_path->nodes[0]));
                                ret = tree_compare_item(left_root, left_path,
                                                right_path, tmp_buf);
-                               if (ret) {
-                                       WARN_ON(!extent_buffer_uptodate(left_path->nodes[0]));
-                                       ret = changed_cb(left_root, right_root,
-                                               left_path, right_path,
-                                               &left_key,
-                                               BTRFS_COMPARE_TREE_CHANGED,
-                                               ctx);
-                                       if (ret < 0)
-                                               goto out;
-                               }
+                               if (ret)
+                                       cmp = BTRFS_COMPARE_TREE_CHANGED;
+                               else
+                                       cmp = BTRFS_COMPARE_TREE_SAME;
+                               ret = changed_cb(left_root, right_root,
+                                                left_path, right_path,
+                                                &left_key, cmp, ctx);
+                               if (ret < 0)
+                                       goto out;
                                advance_left = ADVANCE;
                                advance_right = ADVANCE;
                        }
index e795bf135e809fa473190e0169edf21ef7acfb2d..3c1da6f98a4d25666f4a2afb6fce25bff80ac8c8 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/highmem.h>
 #include <linux/fs.h>
 #include <linux/rwsem.h>
+#include <linux/semaphore.h>
 #include <linux/completion.h>
 #include <linux/backing-dev.h>
 #include <linux/wait.h>
@@ -91,6 +92,9 @@ struct btrfs_ordered_sum;
 /* holds quota configuration and tracking */
 #define BTRFS_QUOTA_TREE_OBJECTID 8ULL
 
+/* for storing items that use the BTRFS_UUID_KEY* types */
+#define BTRFS_UUID_TREE_OBJECTID 9ULL
+
 /* for storing balance parameters in the root tree */
 #define BTRFS_BALANCE_OBJECTID -4ULL
 
@@ -142,7 +146,7 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2
 
-#define BTRFS_DEV_REPLACE_DEVID 0
+#define BTRFS_DEV_REPLACE_DEVID 0ULL
 
 /*
  * the max metadata block size.  This limit is somewhat artificial,
@@ -478,9 +482,10 @@ struct btrfs_super_block {
        char label[BTRFS_LABEL_SIZE];
 
        __le64 cache_generation;
+       __le64 uuid_tree_generation;
 
        /* future expansion */
-       __le64 reserved[31];
+       __le64 reserved[30];
        u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
        struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS];
 } __attribute__ ((__packed__));
@@ -1188,6 +1193,7 @@ enum btrfs_caching_type {
        BTRFS_CACHE_STARTED     = 1,
        BTRFS_CACHE_FAST        = 2,
        BTRFS_CACHE_FINISHED    = 3,
+       BTRFS_CACHE_ERROR       = 4,
 };
 
 enum btrfs_disk_cache_state {
@@ -1302,6 +1308,7 @@ struct btrfs_fs_info {
        struct btrfs_root *fs_root;
        struct btrfs_root *csum_root;
        struct btrfs_root *quota_root;
+       struct btrfs_root *uuid_root;
 
        /* the log root tree is a directory of all the other log roots */
        struct btrfs_root *log_root_tree;
@@ -1350,6 +1357,7 @@ struct btrfs_fs_info {
        u64 last_trans_log_full_commit;
        unsigned long mount_opt;
        unsigned long compress_type:4;
+       int commit_interval;
        /*
         * It is a suggestive number, the read side is safe even it gets a
         * wrong number because we will write out the data into a regular
@@ -1411,6 +1419,13 @@ struct btrfs_fs_info {
         * before jumping into the main commit.
         */
        struct mutex ordered_operations_mutex;
+
+       /*
+        * Same as ordered_operations_mutex except this is for ordered extents
+        * and not the operations.
+        */
+       struct mutex ordered_extent_flush_mutex;
+
        struct rw_semaphore extent_commit_sem;
 
        struct rw_semaphore cleanup_work_sem;
@@ -1641,6 +1656,9 @@ struct btrfs_fs_info {
        struct btrfs_dev_replace dev_replace;
 
        atomic_t mutually_exclusive_operation_running;
+
+       struct semaphore uuid_tree_rescan_sem;
+       unsigned int update_uuid_tree_gen:1;
 };
 
 /*
@@ -1933,6 +1951,19 @@ struct btrfs_ioctl_defrag_range_args {
  */
 #define BTRFS_DEV_REPLACE_KEY  250
 
+/*
+ * Stores items that allow to quickly map UUIDs to something else.
+ * These items are part of the filesystem UUID tree.
+ * The key is built like this:
+ * (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits).
+ */
+#if BTRFS_UUID_SIZE != 16
+#error "UUID items require BTRFS_UUID_SIZE == 16!"
+#endif
+#define BTRFS_UUID_KEY_SUBVOL  251     /* for UUIDs assigned to subvols */
+#define BTRFS_UUID_KEY_RECEIVED_SUBVOL 252     /* for UUIDs assigned to
+                                                * received subvols */
+
 /*
  * string items are for debugging.  They just store a short string of
  * data in the FS
@@ -1967,6 +1998,9 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_MOUNT_CHECK_INTEGRITY    (1 << 20)
 #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
 #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR       (1 << 22)
+#define BTRFS_MOUNT_RESCAN_UUID_TREE   (1 << 23)
+
+#define BTRFS_DEFAULT_COMMIT_INTERVAL  (30)
 
 #define btrfs_clear_opt(o, opt)                ((o) &= ~BTRFS_MOUNT_##opt)
 #define btrfs_set_opt(o, opt)          ((o) |= BTRFS_MOUNT_##opt)
@@ -2130,14 +2164,14 @@ BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item,
 BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item,
                         generation, 64);
 
-static inline char *btrfs_device_uuid(struct btrfs_dev_item *d)
+static inline unsigned long btrfs_device_uuid(struct btrfs_dev_item *d)
 {
-       return (char *)d + offsetof(struct btrfs_dev_item, uuid);
+       return (unsigned long)d + offsetof(struct btrfs_dev_item, uuid);
 }
 
-static inline char *btrfs_device_fsid(struct btrfs_dev_item *d)
+static inline unsigned long btrfs_device_fsid(struct btrfs_dev_item *d)
 {
-       return (char *)d + offsetof(struct btrfs_dev_item, fsid);
+       return (unsigned long)d + offsetof(struct btrfs_dev_item, fsid);
 }
 
 BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64);
@@ -2240,6 +2274,23 @@ BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
 BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
 BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);
 BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
+                        generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
+                        sequence, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
+                        transid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item,
+                        nbytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
+                        block_group, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
 
 static inline struct btrfs_timespec *
 btrfs_inode_atime(struct btrfs_inode_item *inode_item)
@@ -2267,6 +2318,8 @@ btrfs_inode_ctime(struct btrfs_inode_item *inode_item)
 
 BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64);
 BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
 
 /* struct btrfs_dev_extent */
 BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent,
@@ -2277,10 +2330,10 @@ BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent,
                   chunk_offset, 64);
 BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64);
 
-static inline u8 *btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
+static inline unsigned long btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev)
 {
        unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid);
-       return (u8 *)((unsigned long)dev + ptr);
+       return (unsigned long)dev + ptr;
 }
 
 BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64);
@@ -2348,6 +2401,10 @@ BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32);
 /* struct btrfs_node */
 BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64);
 BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_key_blockptr, struct btrfs_key_ptr,
+                        blockptr, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_key_generation, struct btrfs_key_ptr,
+                        generation, 64);
 
 static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr)
 {
@@ -2404,6 +2461,8 @@ static inline void btrfs_set_node_key(struct extent_buffer *eb,
 /* struct btrfs_item */
 BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32);
 BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32);
 
 static inline unsigned long btrfs_item_nr_offset(int nr)
 {
@@ -2466,6 +2525,13 @@ BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16);
 BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8);
 BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16);
 BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item,
+                        data_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item,
+                        name_len, 16);
+BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item,
+                        transid, 64);
 
 static inline void btrfs_dir_item_key(struct extent_buffer *eb,
                                      struct btrfs_dir_item *item,
@@ -2568,6 +2634,12 @@ BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64);
 BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32);
 BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64);
 BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header,
+                        generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header,
+                        nritems, 32);
+BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64);
 
 static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag)
 {
@@ -2603,16 +2675,14 @@ static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb,
        btrfs_set_header_flags(eb, flags);
 }
 
-static inline u8 *btrfs_header_fsid(struct extent_buffer *eb)
+static inline unsigned long btrfs_header_fsid(struct extent_buffer *eb)
 {
-       unsigned long ptr = offsetof(struct btrfs_header, fsid);
-       return (u8 *)ptr;
+       return offsetof(struct btrfs_header, fsid);
 }
 
-static inline u8 *btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
+static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb)
 {
-       unsigned long ptr = offsetof(struct btrfs_header, chunk_tree_uuid);
-       return (u8 *)ptr;
+       return offsetof(struct btrfs_header, chunk_tree_uuid);
 }
 
 static inline int btrfs_is_leaf(struct extent_buffer *eb)
@@ -2830,6 +2900,9 @@ BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block,
                         csum_type, 16);
 BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block,
                         cache_generation, 64);
+BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64);
+BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block,
+                        uuid_tree_generation, 64);
 
 static inline int btrfs_super_csum_size(struct btrfs_super_block *s)
 {
@@ -2847,6 +2920,14 @@ static inline unsigned long btrfs_leaf_data(struct extent_buffer *l)
 
 /* struct btrfs_file_extent_item */
 BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr,
+                        struct btrfs_file_extent_item, disk_bytenr, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset,
+                        struct btrfs_file_extent_item, offset, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation,
+                        struct btrfs_file_extent_item, generation, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes,
+                        struct btrfs_file_extent_item, num_bytes, 64);
 
 static inline unsigned long
 btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
@@ -3107,11 +3188,9 @@ int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
                                   u64 root_objectid, u64 owner, u64 offset,
                                   struct btrfs_key *ins);
-int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
-                                 struct btrfs_root *root,
-                                 u64 num_bytes, u64 min_alloc_size,
-                                 u64 empty_size, u64 hint_byte,
-                                 struct btrfs_key *ins, int is_data);
+int btrfs_reserve_extent(struct btrfs_root *root, u64 num_bytes,
+                        u64 min_alloc_size, u64 empty_size, u64 hint_byte,
+                        struct btrfs_key *ins, int is_data);
 int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                  struct extent_buffer *buf, int full_backref, int for_cow);
 int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -3175,7 +3254,7 @@ void btrfs_orphan_release_metadata(struct inode *inode);
 int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
                                     struct btrfs_block_rsv *rsv,
                                     int nitems,
-                                    u64 *qgroup_reserved);
+                                    u64 *qgroup_reserved, bool use_global_rsv);
 void btrfs_subvolume_release_metadata(struct btrfs_root *root,
                                      struct btrfs_block_rsv *rsv,
                                      u64 qgroup_reserved);
@@ -3245,6 +3324,7 @@ enum btrfs_compare_tree_result {
        BTRFS_COMPARE_TREE_NEW,
        BTRFS_COMPARE_TREE_DELETED,
        BTRFS_COMPARE_TREE_CHANGED,
+       BTRFS_COMPARE_TREE_SAME,
 };
 typedef int (*btrfs_changed_cb_t)(struct btrfs_root *left_root,
                                  struct btrfs_root *right_root,
@@ -3380,6 +3460,7 @@ static inline void free_fs_info(struct btrfs_fs_info *fs_info)
        kfree(fs_info->dev_root);
        kfree(fs_info->csum_root);
        kfree(fs_info->quota_root);
+       kfree(fs_info->uuid_root);
        kfree(fs_info->super_copy);
        kfree(fs_info->super_for_commit);
        kfree(fs_info);
@@ -3414,8 +3495,6 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root,
                                   struct btrfs_key *key,
                                   struct btrfs_root_item *item);
-void btrfs_read_root_item(struct extent_buffer *eb, int slot,
-                         struct btrfs_root_item *item);
 int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key,
                    struct btrfs_path *path, struct btrfs_root_item *root_item,
                    struct btrfs_key *root_key);
@@ -3426,6 +3505,17 @@ void btrfs_check_and_init_root_item(struct btrfs_root_item *item);
 void btrfs_update_root_times(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root);
 
+/* uuid-tree.c */
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid);
+int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid);
+int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
+                           int (*check_func)(struct btrfs_fs_info *, u8 *, u8,
+                                             u64));
+
 /* dir-item.c */
 int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
                          const char *name, int name_len);
@@ -3509,12 +3599,14 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path,
                                   struct btrfs_inode_extref **extref_ret);
 
 /* file-item.c */
+struct btrfs_dio_private;
 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);
+                             struct btrfs_dio_private *dip, struct bio *bio,
+                             u64 logical_offset);
 int btrfs_insert_file_extent(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             u64 objectid, u64 pos,
@@ -3552,8 +3644,7 @@ void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work);
 struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page,
                                           size_t pg_offset, u64 start, u64 len,
                                           int create);
-noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
-                             struct inode *inode, u64 offset, u64 *len,
+noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                              u64 *orig_start, u64 *orig_block_len,
                              u64 *ram_bytes);
 
@@ -3643,11 +3734,15 @@ extern const struct dentry_operations btrfs_dentry_operations;
 long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 void btrfs_update_iflags(struct inode *inode);
 void btrfs_inherit_iflags(struct inode *inode, struct inode *dir);
+int btrfs_is_empty_uuid(u8 *uuid);
 int btrfs_defrag_file(struct inode *inode, struct file *file,
                      struct btrfs_ioctl_defrag_range_args *range,
                      u64 newer_than, unsigned long max_pages);
 void btrfs_get_block_group_info(struct list_head *groups_list,
                                struct btrfs_ioctl_space_info *space);
+void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
+                              struct btrfs_ioctl_balance_args *bargs);
+
 
 /* file.c */
 int btrfs_auto_defrag_init(void);
@@ -3720,6 +3815,22 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
 #define btrfs_debug(fs_info, fmt, args...) \
        btrfs_printk(fs_info, KERN_DEBUG fmt, ##args)
 
+#ifdef CONFIG_BTRFS_ASSERT
+
+static inline void assfail(char *expr, char *file, int line)
+{
+       printk(KERN_ERR "BTRFS assertion failed: %s, file: %s, line: %d",
+              expr, file, line);
+       BUG();
+}
+
+#define ASSERT(expr)   \
+       (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
+#else
+#define ASSERT(expr)   ((void)0)
+#endif
+
+#define btrfs_assert()
 __printf(5, 6)
 void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
                     unsigned int line, int errno, const char *fmt, ...);
index 375510913fe744784f8f56966ed29693ee8e3612..cbd9523ad09cae0ffff1688371b370a756aef2f5 100644 (file)
@@ -21,6 +21,7 @@
 #include "delayed-inode.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "ctree.h"
 
 #define BTRFS_DELAYED_WRITEBACK                512
 #define BTRFS_DELAYED_BACKGROUND       128
@@ -1453,10 +1454,10 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
 
        dir_item = (struct btrfs_dir_item *)delayed_item->data;
        dir_item->location = *disk_key;
-       dir_item->transid = cpu_to_le64(trans->transid);
-       dir_item->data_len = 0;
-       dir_item->name_len = cpu_to_le16(name_len);
-       dir_item->type = type;
+       btrfs_set_stack_dir_transid(dir_item, trans->transid);
+       btrfs_set_stack_dir_data_len(dir_item, 0);
+       btrfs_set_stack_dir_name_len(dir_item, name_len);
+       btrfs_set_stack_dir_type(dir_item, type);
        memcpy((char *)(dir_item + 1), name, name_len);
 
        ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item);
@@ -1470,13 +1471,11 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
        mutex_lock(&delayed_node->mutex);
        ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
        if (unlikely(ret)) {
-               printk(KERN_ERR "err add delayed dir index item(name: %s) into "
-                               "the insertion tree of the delayed node"
+               printk(KERN_ERR "err add delayed dir index item(name: %.*s) "
+                               "into the insertion tree of the delayed node"
                                "(root id: %llu, inode id: %llu, errno: %d)\n",
-                               name,
-                               (unsigned long long)delayed_node->root->objectid,
-                               (unsigned long long)delayed_node->inode_id,
-                               ret);
+                               name_len, name, delayed_node->root->objectid,
+                               delayed_node->inode_id, ret);
                BUG();
        }
        mutex_unlock(&delayed_node->mutex);
@@ -1547,9 +1546,7 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
                printk(KERN_ERR "err add delayed dir index item(index: %llu) "
                                "into the deletion tree of the delayed node"
                                "(root id: %llu, inode id: %llu, errno: %d)\n",
-                               (unsigned long long)index,
-                               (unsigned long long)node->root->objectid,
-                               (unsigned long long)node->inode_id,
+                               index, node->root->objectid, node->inode_id,
                                ret);
                BUG();
        }
@@ -1699,7 +1696,7 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
 
                di = (struct btrfs_dir_item *)curr->data;
                name = (char *)(di + 1);
-               name_len = le16_to_cpu(di->name_len);
+               name_len = btrfs_stack_dir_name_len(di);
 
                d_type = btrfs_filetype_table[di->type];
                btrfs_disk_key_to_cpu(&location, &di->location);
@@ -1716,27 +1713,6 @@ int btrfs_readdir_delayed_dir_index(struct dir_context *ctx,
        return 0;
 }
 
-BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item,
-                        generation, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item,
-                        sequence, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item,
-                        transid, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item,
-                        nbytes, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item,
-                        block_group, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64);
-
-BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64);
-BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32);
-
 static void fill_stack_inode_item(struct btrfs_trans_handle *trans,
                                  struct btrfs_inode_item *inode_item,
                                  struct inode *inode)
index c219463fb1fde9ede3cbe9d53622c8659b1545b0..e4d467be2dd44d131977d64c3029af3fc9d99ce3 100644 (file)
@@ -241,7 +241,7 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-static void inline drop_delayed_ref(struct btrfs_trans_handle *trans,
+static inline void drop_delayed_ref(struct btrfs_trans_handle *trans,
                                    struct btrfs_delayed_ref_root *delayed_refs,
                                    struct btrfs_delayed_ref_node *ref)
 {
@@ -600,7 +600,7 @@ static noinline void add_delayed_ref_head(struct btrfs_fs_info *fs_info,
        INIT_LIST_HEAD(&head_ref->cluster);
        mutex_init(&head_ref->mutex);
 
-       trace_btrfs_delayed_ref_head(ref, head_ref, action);
+       trace_add_delayed_ref_head(ref, head_ref, action);
 
        existing = tree_insert(&delayed_refs->root, &ref->rb_node);
 
@@ -661,7 +661,7 @@ static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
                ref->type = BTRFS_TREE_BLOCK_REF_KEY;
        full_ref->level = level;
 
-       trace_btrfs_delayed_tree_ref(ref, full_ref, action);
+       trace_add_delayed_tree_ref(ref, full_ref, action);
 
        existing = tree_insert(&delayed_refs->root, &ref->rb_node);
 
@@ -722,7 +722,7 @@ static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
        full_ref->objectid = owner;
        full_ref->offset = offset;
 
-       trace_btrfs_delayed_data_ref(ref, full_ref, action);
+       trace_add_delayed_data_ref(ref, full_ref, action);
 
        existing = tree_insert(&delayed_refs->root, &ref->rb_node);
 
index 5f8f3341c099ecd088226726ac8981908868ac00..a64435359385e86a483f30696c932da2c8d5bdb0 100644 (file)
@@ -148,13 +148,13 @@ no_valid_dev_replace_entry_found:
                    !btrfs_test_opt(dev_root, DEGRADED)) {
                        ret = -EIO;
                        pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?\n",
-                               (unsigned long long)src_devid);
+                               src_devid);
                }
                if (!dev_replace->tgtdev &&
                    !btrfs_test_opt(dev_root, DEGRADED)) {
                        ret = -EIO;
                        pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "tgtdev (devid %llu) is missing, need to run btrfs dev scan?\n",
-                               (unsigned long long)BTRFS_DEV_REPLACE_DEVID);
+                               BTRFS_DEV_REPLACE_DEVID);
                }
                if (dev_replace->tgtdev) {
                        if (dev_replace->srcdev) {
index 6b092a1c4e37bab47adb0e9fc35ae6ec3e6081f8..4cbb00af92ff3bed86561b9f02ec6fbcc04665b2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/migrate.h>
 #include <linux/ratelimit.h>
 #include <linux/uuid.h>
+#include <linux/semaphore.h>
 #include <asm/unaligned.h>
 #include "compat.h"
 #include "ctree.h"
@@ -302,9 +303,8 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
                        printk_ratelimited(KERN_INFO "btrfs: %s checksum verify "
                                       "failed on %llu wanted %X found %X "
                                       "level %d\n",
-                                      root->fs_info->sb->s_id,
-                                      (unsigned long long)buf->start, val, found,
-                                      btrfs_header_level(buf));
+                                      root->fs_info->sb->s_id, buf->start,
+                                      val, found, btrfs_header_level(buf));
                        if (result != (char *)&inline_result)
                                kfree(result);
                        return 1;
@@ -345,9 +345,7 @@ static int verify_parent_transid(struct extent_io_tree *io_tree,
        }
        printk_ratelimited("parent transid verify failed on %llu wanted %llu "
                       "found %llu\n",
-                      (unsigned long long)eb->start,
-                      (unsigned long long)parent_transid,
-                      (unsigned long long)btrfs_header_generation(eb));
+                      eb->start, parent_transid, btrfs_header_generation(eb));
        ret = 1;
        clear_extent_buffer_uptodate(eb);
 out:
@@ -497,8 +495,7 @@ static int check_tree_block_fsid(struct btrfs_root *root,
        u8 fsid[BTRFS_UUID_SIZE];
        int ret = 1;
 
-       read_extent_buffer(eb, fsid, (unsigned long)btrfs_header_fsid(eb),
-                          BTRFS_FSID_SIZE);
+       read_extent_buffer(eb, fsid, btrfs_header_fsid(eb), BTRFS_FSID_SIZE);
        while (fs_devices) {
                if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) {
                        ret = 0;
@@ -512,8 +509,7 @@ static int check_tree_block_fsid(struct btrfs_root *root,
 #define CORRUPT(reason, eb, root, slot)                                \
        printk(KERN_CRIT "btrfs: corrupt leaf, %s: block=%llu," \
               "root=%llu, slot=%d\n", reason,                  \
-              (unsigned long long)btrfs_header_bytenr(eb),     \
-              (unsigned long long)root->objectid, slot)
+              btrfs_header_bytenr(eb), root->objectid, slot)
 
 static noinline int check_leaf(struct btrfs_root *root,
                               struct extent_buffer *leaf)
@@ -576,8 +572,9 @@ static noinline int check_leaf(struct btrfs_root *root,
        return 0;
 }
 
-static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
-                              struct extent_state *state, int mirror)
+static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+                                     u64 phy_offset, struct page *page,
+                                     u64 start, u64 end, int mirror)
 {
        struct extent_io_tree *tree;
        u64 found_start;
@@ -612,14 +609,13 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        if (found_start != eb->start) {
                printk_ratelimited(KERN_INFO "btrfs bad tree block start "
                               "%llu %llu\n",
-                              (unsigned long long)found_start,
-                              (unsigned long long)eb->start);
+                              found_start, eb->start);
                ret = -EIO;
                goto err;
        }
        if (check_tree_block_fsid(root, eb)) {
                printk_ratelimited(KERN_INFO "btrfs bad fsid on block %llu\n",
-                              (unsigned long long)eb->start);
+                              eb->start);
                ret = -EIO;
                goto err;
        }
@@ -1148,6 +1144,10 @@ struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr,
                return NULL;
 
        ret = btree_read_extent_buffer_pages(root, buf, 0, parent_transid);
+       if (ret) {
+               free_extent_buffer(buf);
+               return NULL;
+       }
        return buf;
 
 }
@@ -1291,11 +1291,10 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
        btrfs_set_header_owner(leaf, objectid);
        root->node = leaf;
 
-       write_extent_buffer(leaf, fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(leaf),
+       write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(leaf),
                            BTRFS_FSID_SIZE);
        write_extent_buffer(leaf, fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(leaf),
+                           btrfs_header_chunk_tree_uuid(leaf),
                            BTRFS_UUID_SIZE);
        btrfs_mark_buffer_dirty(leaf);
 
@@ -1379,8 +1378,7 @@ static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans,
        root->node = leaf;
 
        write_extent_buffer(root->node, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(root->node),
-                           BTRFS_FSID_SIZE);
+                           btrfs_header_fsid(root->node), BTRFS_FSID_SIZE);
        btrfs_mark_buffer_dirty(root->node);
        btrfs_tree_unlock(root->node);
        return root;
@@ -1413,11 +1411,11 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
        log_root->root_key.offset = root->root_key.objectid;
 
        inode_item = &log_root->root_item.inode;
-       inode_item->generation = cpu_to_le64(1);
-       inode_item->size = cpu_to_le64(3);
-       inode_item->nlink = cpu_to_le32(1);
-       inode_item->nbytes = cpu_to_le64(root->leafsize);
-       inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
+       btrfs_set_stack_inode_generation(inode_item, 1);
+       btrfs_set_stack_inode_size(inode_item, 3);
+       btrfs_set_stack_inode_nlink(inode_item, 1);
+       btrfs_set_stack_inode_nbytes(inode_item, root->leafsize);
+       btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
 
        btrfs_set_root_node(&log_root->root_item, log_root->node);
 
@@ -1428,8 +1426,8 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
        return 0;
 }
 
-struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
-                                       struct btrfs_key *key)
+static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
+                                              struct btrfs_key *key)
 {
        struct btrfs_root *root;
        struct btrfs_fs_info *fs_info = tree_root->fs_info;
@@ -1529,8 +1527,8 @@ fail:
        return ret;
 }
 
-struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
-                                       u64 root_id)
+static struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
+                                              u64 root_id)
 {
        struct btrfs_root *root;
 
@@ -1581,10 +1579,16 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
        if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
                return fs_info->quota_root ? fs_info->quota_root :
                                             ERR_PTR(-ENOENT);
+       if (location->objectid == BTRFS_UUID_TREE_OBJECTID)
+               return fs_info->uuid_root ? fs_info->uuid_root :
+                                           ERR_PTR(-ENOENT);
 again:
        root = btrfs_lookup_fs_root(fs_info, location->objectid);
-       if (root)
+       if (root) {
+               if (btrfs_root_refs(&root->root_item) == 0)
+                       return ERR_PTR(-ENOENT);
                return root;
+       }
 
        root = btrfs_read_fs_root(fs_info->tree_root, location);
        if (IS_ERR(root))
@@ -1737,7 +1741,7 @@ static int transaction_kthread(void *arg)
 
        do {
                cannot_commit = false;
-               delay = HZ * 30;
+               delay = HZ * root->fs_info->commit_interval;
                mutex_lock(&root->fs_info->transaction_kthread_mutex);
 
                spin_lock(&root->fs_info->trans_lock);
@@ -1749,7 +1753,8 @@ static int transaction_kthread(void *arg)
 
                now = get_seconds();
                if (cur->state < TRANS_STATE_BLOCKED &&
-                   (now < cur->start_time || now - cur->start_time < 30)) {
+                   (now < cur->start_time ||
+                    now - cur->start_time < root->fs_info->commit_interval)) {
                        spin_unlock(&root->fs_info->trans_lock);
                        delay = HZ * 5;
                        goto sleep;
@@ -2038,6 +2043,12 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
                info->quota_root->node = NULL;
                info->quota_root->commit_root = NULL;
        }
+       if (info->uuid_root) {
+               free_extent_buffer(info->uuid_root->node);
+               free_extent_buffer(info->uuid_root->commit_root);
+               info->uuid_root->node = NULL;
+               info->uuid_root->commit_root = NULL;
+       }
        if (chunk_root) {
                free_extent_buffer(info->chunk_root->node);
                free_extent_buffer(info->chunk_root->commit_root);
@@ -2098,11 +2109,14 @@ int open_ctree(struct super_block *sb,
        struct btrfs_root *chunk_root;
        struct btrfs_root *dev_root;
        struct btrfs_root *quota_root;
+       struct btrfs_root *uuid_root;
        struct btrfs_root *log_tree_root;
        int ret;
        int err = -EINVAL;
        int num_backups_tried = 0;
        int backup_index = 0;
+       bool create_uuid_tree;
+       bool check_uuid_tree;
 
        tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info);
        chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
@@ -2189,6 +2203,7 @@ int open_ctree(struct super_block *sb,
        fs_info->defrag_inodes = RB_ROOT;
        fs_info->free_chunk_space = 0;
        fs_info->tree_mod_log = RB_ROOT;
+       fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
 
        /* readahead state */
        INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
@@ -2270,6 +2285,7 @@ int open_ctree(struct super_block *sb,
 
 
        mutex_init(&fs_info->ordered_operations_mutex);
+       mutex_init(&fs_info->ordered_extent_flush_mutex);
        mutex_init(&fs_info->tree_log_mutex);
        mutex_init(&fs_info->chunk_mutex);
        mutex_init(&fs_info->transaction_kthread_mutex);
@@ -2278,6 +2294,7 @@ int open_ctree(struct super_block *sb,
        init_rwsem(&fs_info->extent_commit_sem);
        init_rwsem(&fs_info->cleanup_work_sem);
        init_rwsem(&fs_info->subvol_sem);
+       sema_init(&fs_info->uuid_tree_rescan_sem, 1);
        fs_info->dev_replace.lock_owner = 0;
        atomic_set(&fs_info->dev_replace.nesting_level, 0);
        mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount);
@@ -2383,7 +2400,7 @@ int open_ctree(struct super_block *sb,
        if (features) {
                printk(KERN_ERR "BTRFS: couldn't mount because of "
                       "unsupported optional features (%Lx).\n",
-                      (unsigned long long)features);
+                      features);
                err = -EINVAL;
                goto fail_alloc;
        }
@@ -2453,7 +2470,7 @@ int open_ctree(struct super_block *sb,
        if (!(sb->s_flags & MS_RDONLY) && features) {
                printk(KERN_ERR "BTRFS: couldn't mount RDWR because of "
                       "unsupported option features (%Lx).\n",
-                      (unsigned long long)features);
+                      features);
                err = -EINVAL;
                goto fail_alloc;
        }
@@ -2466,20 +2483,17 @@ int open_ctree(struct super_block *sb,
                           &fs_info->generic_worker);
 
        btrfs_init_workers(&fs_info->delalloc_workers, "delalloc",
-                          fs_info->thread_pool_size,
-                          &fs_info->generic_worker);
+                          fs_info->thread_pool_size, NULL);
 
        btrfs_init_workers(&fs_info->flush_workers, "flush_delalloc",
-                          fs_info->thread_pool_size,
-                          &fs_info->generic_worker);
+                          fs_info->thread_pool_size, NULL);
 
        btrfs_init_workers(&fs_info->submit_workers, "submit",
                           min_t(u64, fs_devices->num_devices,
-                          fs_info->thread_pool_size),
-                          &fs_info->generic_worker);
+                          fs_info->thread_pool_size), NULL);
 
        btrfs_init_workers(&fs_info->caching_workers, "cache",
-                          2, &fs_info->generic_worker);
+                          fs_info->thread_pool_size, NULL);
 
        /* 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
@@ -2575,7 +2589,7 @@ int open_ctree(struct super_block *sb,
        sb->s_blocksize = sectorsize;
        sb->s_blocksize_bits = blksize_bits(sectorsize);
 
-       if (disk_super->magic != cpu_to_le64(BTRFS_MAGIC)) {
+       if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
                printk(KERN_INFO "btrfs: valid FS not found on %s\n", sb->s_id);
                goto fail_sb_buffer;
        }
@@ -2615,8 +2629,7 @@ int open_ctree(struct super_block *sb,
        chunk_root->commit_root = btrfs_root_node(chunk_root);
 
        read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid,
-          (unsigned long)btrfs_header_chunk_tree_uuid(chunk_root->node),
-          BTRFS_UUID_SIZE);
+          btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE);
 
        ret = btrfs_read_chunk_tree(chunk_root);
        if (ret) {
@@ -2696,6 +2709,22 @@ retry_root_backup:
                fs_info->quota_root = quota_root;
        }
 
+       location.objectid = BTRFS_UUID_TREE_OBJECTID;
+       uuid_root = btrfs_read_tree_root(tree_root, &location);
+       if (IS_ERR(uuid_root)) {
+               ret = PTR_ERR(uuid_root);
+               if (ret != -ENOENT)
+                       goto recovery_tree_root;
+               create_uuid_tree = true;
+               check_uuid_tree = false;
+       } else {
+               uuid_root->track_dirty = 1;
+               fs_info->uuid_root = uuid_root;
+               create_uuid_tree = false;
+               check_uuid_tree =
+                   generation != btrfs_super_uuid_tree_generation(disk_super);
+       }
+
        fs_info->generation = generation;
        fs_info->last_trans_committed = generation;
 
@@ -2882,6 +2911,29 @@ retry_root_backup:
 
        btrfs_qgroup_rescan_resume(fs_info);
 
+       if (create_uuid_tree) {
+               pr_info("btrfs: creating UUID tree\n");
+               ret = btrfs_create_uuid_tree(fs_info);
+               if (ret) {
+                       pr_warn("btrfs: failed to create the UUID tree %d\n",
+                               ret);
+                       close_ctree(tree_root);
+                       return ret;
+               }
+       } else if (check_uuid_tree ||
+                  btrfs_test_opt(tree_root, RESCAN_UUID_TREE)) {
+               pr_info("btrfs: checking UUID tree\n");
+               ret = btrfs_check_uuid_tree(fs_info);
+               if (ret) {
+                       pr_warn("btrfs: failed to check the UUID tree %d\n",
+                               ret);
+                       close_ctree(tree_root);
+                       return ret;
+               }
+       } else {
+               fs_info->update_uuid_tree_gen = 1;
+       }
+
        return 0;
 
 fail_qgroup:
@@ -2983,15 +3035,17 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev)
         */
        for (i = 0; i < 1; i++) {
                bytenr = btrfs_sb_offset(i);
-               if (bytenr + 4096 >= i_size_read(bdev->bd_inode))
+               if (bytenr + BTRFS_SUPER_INFO_SIZE >=
+                                       i_size_read(bdev->bd_inode))
                        break;
-               bh = __bread(bdev, bytenr / 4096, 4096);
+               bh = __bread(bdev, bytenr / 4096,
+                                       BTRFS_SUPER_INFO_SIZE);
                if (!bh)
                        continue;
 
                super = (struct btrfs_super_block *)bh->b_data;
                if (btrfs_super_bytenr(super) != bytenr ||
-                   super->magic != cpu_to_le64(BTRFS_MAGIC)) {
+                   btrfs_super_magic(super) != BTRFS_MAGIC) {
                        brelse(bh);
                        continue;
                }
@@ -3311,7 +3365,6 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
        int total_errors = 0;
        u64 flags;
 
-       max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
        do_barriers = !btrfs_test_opt(root, NOBARRIER);
        backup_super_roots(root->fs_info);
 
@@ -3320,6 +3373,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
 
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        head = &root->fs_info->fs_devices->devices;
+       max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
 
        if (do_barriers) {
                ret = barrier_all_devices(root->fs_info);
@@ -3362,8 +3416,10 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                printk(KERN_ERR "btrfs: %d errors while writing supers\n",
                       total_errors);
 
-               /* This shouldn't happen. FUA is masked off if unsupported */
-               BUG();
+               /* FUA is masked off if unsupported and can't be the reason */
+               btrfs_error(root->fs_info, -EIO,
+                           "%d errors while writing supers", total_errors);
+               return -EIO;
        }
 
        total_errors = 0;
@@ -3421,6 +3477,8 @@ static void free_fs_root(struct btrfs_root *root)
 {
        iput(root->cache_inode);
        WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree));
+       btrfs_free_block_rsv(root, root->orphan_block_rsv);
+       root->orphan_block_rsv = NULL;
        if (root->anon_dev)
                free_anon_bdev(root->anon_dev);
        free_extent_buffer(root->node);
@@ -3510,6 +3568,11 @@ int close_ctree(struct btrfs_root *root)
        fs_info->closing = 1;
        smp_mb();
 
+       /* wait for the uuid_scan task to finish */
+       down(&fs_info->uuid_tree_rescan_sem);
+       /* avoid complains from lockdep et al., set sem back to initial state */
+       up(&fs_info->uuid_tree_rescan_sem);
+
        /* pause restriper - we want to resume on mount */
        btrfs_pause_balance(fs_info);
 
@@ -3573,6 +3636,9 @@ int close_ctree(struct btrfs_root *root)
 
        btrfs_free_stripe_hash_table(fs_info);
 
+       btrfs_free_block_rsv(root, root->orphan_block_rsv);
+       root->orphan_block_rsv = NULL;
+
        return 0;
 }
 
@@ -3608,9 +3674,7 @@ void btrfs_mark_buffer_dirty(struct extent_buffer *buf)
        if (transid != root->fs_info->generation)
                WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, "
                       "found %llu running %llu\n",
-                       (unsigned long long)buf->start,
-                       (unsigned long long)transid,
-                       (unsigned long long)root->fs_info->generation);
+                       buf->start, transid, root->fs_info->generation);
        was_dirty = set_extent_buffer_dirty(buf);
        if (!was_dirty)
                __percpu_counter_add(&root->fs_info->dirty_metadata_bytes,
@@ -3744,8 +3808,8 @@ static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info)
        spin_unlock(&fs_info->ordered_root_lock);
 }
 
-int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
-                              struct btrfs_root *root)
+static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
+                                     struct btrfs_root *root)
 {
        struct rb_node *node;
        struct btrfs_delayed_ref_root *delayed_refs;
index 1204c8ef6f32751bd859d2ef1a2ab3444061f708..cfb3cf711b34d6555afed3d21dd16480c662cc55 100644 (file)
@@ -113,7 +113,8 @@ static noinline int
 block_group_cache_done(struct btrfs_block_group_cache *cache)
 {
        smp_mb();
-       return cache->cached == BTRFS_CACHE_FINISHED;
+       return cache->cached == BTRFS_CACHE_FINISHED ||
+               cache->cached == BTRFS_CACHE_ERROR;
 }
 
 static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
@@ -389,7 +390,7 @@ static noinline void caching_thread(struct btrfs_work *work)
        u64 total_found = 0;
        u64 last = 0;
        u32 nritems;
-       int ret = 0;
+       int ret = -ENOMEM;
 
        caching_ctl = container_of(work, struct btrfs_caching_control, work);
        block_group = caching_ctl->block_group;
@@ -420,6 +421,7 @@ again:
        /* need to make sure the commit_root doesn't disappear */
        down_read(&fs_info->extent_commit_sem);
 
+next:
        ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0);
        if (ret < 0)
                goto err;
@@ -459,6 +461,16 @@ again:
                        continue;
                }
 
+               if (key.objectid < last) {
+                       key.objectid = last;
+                       key.offset = 0;
+                       key.type = BTRFS_EXTENT_ITEM_KEY;
+
+                       caching_ctl->progress = last;
+                       btrfs_release_path(path);
+                       goto next;
+               }
+
                if (key.objectid < block_group->key.objectid) {
                        path->slots[0]++;
                        continue;
@@ -506,6 +518,12 @@ err:
 
        mutex_unlock(&caching_ctl->mutex);
 out:
+       if (ret) {
+               spin_lock(&block_group->lock);
+               block_group->caching_ctl = NULL;
+               block_group->cached = BTRFS_CACHE_ERROR;
+               spin_unlock(&block_group->lock);
+       }
        wake_up(&caching_ctl->wait);
 
        put_caching_control(caching_ctl);
@@ -771,10 +789,23 @@ again:
                goto out_free;
 
        if (ret > 0 && metadata && key.type == BTRFS_METADATA_ITEM_KEY) {
-               key.type = BTRFS_EXTENT_ITEM_KEY;
-               key.offset = root->leafsize;
-               btrfs_release_path(path);
-               goto again;
+               metadata = 0;
+               if (path->slots[0]) {
+                       path->slots[0]--;
+                       btrfs_item_key_to_cpu(path->nodes[0], &key,
+                                             path->slots[0]);
+                       if (key.objectid == bytenr &&
+                           key.type == BTRFS_EXTENT_ITEM_KEY &&
+                           key.offset == root->leafsize)
+                               ret = 0;
+               }
+               if (ret) {
+                       key.objectid = bytenr;
+                       key.type = BTRFS_EXTENT_ITEM_KEY;
+                       key.offset = root->leafsize;
+                       btrfs_release_path(path);
+                       goto again;
+               }
        }
 
        if (ret == 0) {
@@ -2011,6 +2042,8 @@ static int run_delayed_data_ref(struct btrfs_trans_handle *trans,
        ins.type = BTRFS_EXTENT_ITEM_KEY;
 
        ref = btrfs_delayed_node_to_data_ref(node);
+       trace_run_delayed_data_ref(node, ref, node->action);
+
        if (node->type == BTRFS_SHARED_DATA_REF_KEY)
                parent = ref->parent;
        else
@@ -2154,6 +2187,8 @@ static int run_delayed_tree_ref(struct btrfs_trans_handle *trans,
                                                 SKINNY_METADATA);
 
        ref = btrfs_delayed_node_to_tree_ref(node);
+       trace_run_delayed_tree_ref(node, ref, node->action);
+
        if (node->type == BTRFS_SHARED_BLOCK_REF_KEY)
                parent = ref->parent;
        else
@@ -2212,6 +2247,8 @@ static int run_one_delayed_ref(struct btrfs_trans_handle *trans,
                 */
                BUG_ON(extent_op);
                head = btrfs_delayed_node_to_head(node);
+               trace_run_delayed_ref_head(node, head, node->action);
+
                if (insert_reserved) {
                        btrfs_pin_extent(root, node->bytenr,
                                         node->num_bytes, 1);
@@ -2403,6 +2440,8 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                        default:
                                WARN_ON(1);
                        }
+               } else {
+                       list_del_init(&locked_ref->cluster);
                }
                spin_unlock(&delayed_refs->lock);
 
@@ -2425,7 +2464,6 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                 * list before we release it.
                 */
                if (btrfs_delayed_ref_is_head(ref)) {
-                       list_del_init(&locked_ref->cluster);
                        btrfs_delayed_ref_unlock(locked_ref);
                        locked_ref = NULL;
                }
@@ -3799,8 +3837,12 @@ again:
        if (force < space_info->force_alloc)
                force = space_info->force_alloc;
        if (space_info->full) {
+               if (should_alloc_chunk(extent_root, space_info, force))
+                       ret = -ENOSPC;
+               else
+                       ret = 0;
                spin_unlock(&space_info->lock);
-               return 0;
+               return ret;
        }
 
        if (!should_alloc_chunk(extent_root, space_info, force)) {
@@ -4320,6 +4362,9 @@ static struct btrfs_block_rsv *get_block_rsv(
        if (root == root->fs_info->csum_root && trans->adding_csums)
                block_rsv = trans->block_rsv;
 
+       if (root == root->fs_info->uuid_root)
+               block_rsv = trans->block_rsv;
+
        if (!block_rsv)
                block_rsv = root->block_rsv;
 
@@ -4729,10 +4774,12 @@ void btrfs_orphan_release_metadata(struct inode *inode)
 int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
                                     struct btrfs_block_rsv *rsv,
                                     int items,
-                                    u64 *qgroup_reserved)
+                                    u64 *qgroup_reserved,
+                                    bool use_global_rsv)
 {
        u64 num_bytes;
        int ret;
+       struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
 
        if (root->fs_info->quota_enabled) {
                /* One for parent inode, two for dir entries */
@@ -4751,6 +4798,10 @@ int btrfs_subvolume_reserve_metadata(struct btrfs_root *root,
                                            BTRFS_BLOCK_GROUP_METADATA);
        ret = btrfs_block_rsv_add(root, rsv, num_bytes,
                                  BTRFS_RESERVE_FLUSH_ALL);
+
+       if (ret == -ENOSPC && use_global_rsv)
+               ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes);
+
        if (ret) {
                if (*qgroup_reserved)
                        btrfs_qgroup_free(root, *qgroup_reserved);
@@ -5668,7 +5719,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
 
                        if (ret) {
                                btrfs_err(info, "umm, got %d back from search, was looking for %llu",
-                                       ret, (unsigned long long)bytenr);
+                                       ret, bytenr);
                                if (ret > 0)
                                        btrfs_print_leaf(extent_root,
                                                         path->nodes[0]);
@@ -5684,11 +5735,8 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                WARN_ON(1);
                btrfs_err(info,
                        "unable to find ref byte nr %llu parent %llu root %llu  owner %llu offset %llu",
-                       (unsigned long long)bytenr,
-                       (unsigned long long)parent,
-                       (unsigned long long)root_objectid,
-                       (unsigned long long)owner_objectid,
-                       (unsigned long long)owner_offset);
+                       bytenr, parent, root_objectid, owner_objectid,
+                       owner_offset);
        } else {
                btrfs_abort_transaction(trans, extent_root, ret);
                goto out;
@@ -5717,7 +5765,7 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
                                        -1, 1);
                if (ret) {
                        btrfs_err(info, "umm, got %d back from search, was looking for %llu",
-                               ret, (unsigned long long)bytenr);
+                               ret, bytenr);
                        btrfs_print_leaf(extent_root, path->nodes[0]);
                }
                if (ret < 0) {
@@ -5999,8 +6047,11 @@ static u64 stripe_align(struct btrfs_root *root,
  * for our min num_bytes.  Another option is to have it go ahead
  * and look in the rbtree for a free extent of a given size, but this
  * is a good start.
+ *
+ * Callers of this must check if cache->cached == BTRFS_CACHE_ERROR before using
+ * any of the information in this block group.
  */
-static noinline int
+static noinline void
 wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
                                u64 num_bytes)
 {
@@ -6008,28 +6059,29 @@ wait_block_group_cache_progress(struct btrfs_block_group_cache *cache,
 
        caching_ctl = get_caching_control(cache);
        if (!caching_ctl)
-               return 0;
+               return;
 
        wait_event(caching_ctl->wait, block_group_cache_done(cache) ||
                   (cache->free_space_ctl->free_space >= num_bytes));
 
        put_caching_control(caching_ctl);
-       return 0;
 }
 
 static noinline int
 wait_block_group_cache_done(struct btrfs_block_group_cache *cache)
 {
        struct btrfs_caching_control *caching_ctl;
+       int ret = 0;
 
        caching_ctl = get_caching_control(cache);
        if (!caching_ctl)
-               return 0;
+               return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0;
 
        wait_event(caching_ctl->wait, block_group_cache_done(cache));
-
+       if (cache->cached == BTRFS_CACHE_ERROR)
+               ret = -EIO;
        put_caching_control(caching_ctl);
-       return 0;
+       return ret;
 }
 
 int __get_raid_index(u64 flags)
@@ -6070,8 +6122,7 @@ enum btrfs_loop_type {
  * ins->offset == number of blocks
  * Any available blocks before search_start are skipped.
  */
-static noinline int find_free_extent(struct btrfs_trans_handle *trans,
-                                    struct btrfs_root *orig_root,
+static noinline int find_free_extent(struct btrfs_root *orig_root,
                                     u64 num_bytes, u64 empty_size,
                                     u64 hint_byte, struct btrfs_key *ins,
                                     u64 flags)
@@ -6212,6 +6263,8 @@ have_block_group:
                        ret = 0;
                }
 
+               if (unlikely(block_group->cached == BTRFS_CACHE_ERROR))
+                       goto loop;
                if (unlikely(block_group->ro))
                        goto loop;
 
@@ -6292,10 +6345,10 @@ refill_cluster:
                                              block_group->full_stripe_len);
 
                        /* allocate a cluster in this block group */
-                       ret = btrfs_find_space_cluster(trans, root,
-                                              block_group, last_ptr,
-                                              search_start, num_bytes,
-                                              aligned_cluster);
+                       ret = btrfs_find_space_cluster(root, block_group,
+                                                      last_ptr, search_start,
+                                                      num_bytes,
+                                                      aligned_cluster);
                        if (ret == 0) {
                                /*
                                 * now pull our allocation out of this
@@ -6426,17 +6479,28 @@ loop:
                index = 0;
                loop++;
                if (loop == LOOP_ALLOC_CHUNK) {
+                       struct btrfs_trans_handle *trans;
+
+                       trans = btrfs_join_transaction(root);
+                       if (IS_ERR(trans)) {
+                               ret = PTR_ERR(trans);
+                               goto out;
+                       }
+
                        ret = do_chunk_alloc(trans, root, flags,
                                             CHUNK_ALLOC_FORCE);
                        /*
                         * Do not bail out on ENOSPC since we
                         * can do more things.
                         */
-                       if (ret < 0 && ret != -ENOSPC) {
+                       if (ret < 0 && ret != -ENOSPC)
                                btrfs_abort_transaction(trans,
                                                        root, ret);
+                       else
+                               ret = 0;
+                       btrfs_end_transaction(trans, root);
+                       if (ret)
                                goto out;
-                       }
                }
 
                if (loop == LOOP_NO_EMPTY_SIZE) {
@@ -6463,19 +6527,15 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
 
        spin_lock(&info->lock);
        printk(KERN_INFO "space_info %llu has %llu free, is %sfull\n",
-              (unsigned long long)info->flags,
-              (unsigned long long)(info->total_bytes - info->bytes_used -
-                                   info->bytes_pinned - info->bytes_reserved -
-                                   info->bytes_readonly),
+              info->flags,
+              info->total_bytes - info->bytes_used - info->bytes_pinned -
+              info->bytes_reserved - info->bytes_readonly,
               (info->full) ? "" : "not ");
        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_reserved,
-              (unsigned long long)info->bytes_may_use,
-              (unsigned long long)info->bytes_readonly);
+              info->total_bytes, info->bytes_used, info->bytes_pinned,
+              info->bytes_reserved, info->bytes_may_use,
+              info->bytes_readonly);
        spin_unlock(&info->lock);
 
        if (!dump_block_groups)
@@ -6486,12 +6546,9 @@ 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 %s\n",
-                      (unsigned long long)cache->key.objectid,
-                      (unsigned long long)cache->key.offset,
-                      (unsigned long long)btrfs_block_group_used(&cache->item),
-                      (unsigned long long)cache->pinned,
-                      (unsigned long long)cache->reserved,
-                      cache->ro ? "[readonly]" : "");
+                      cache->key.objectid, cache->key.offset,
+                      btrfs_block_group_used(&cache->item), cache->pinned,
+                      cache->reserved, cache->ro ? "[readonly]" : "");
                btrfs_dump_free_space(cache, bytes);
                spin_unlock(&cache->lock);
        }
@@ -6500,8 +6557,7 @@ again:
        up_read(&info->groups_sem);
 }
 
-int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
-                        struct btrfs_root *root,
+int btrfs_reserve_extent(struct btrfs_root *root,
                         u64 num_bytes, u64 min_alloc_size,
                         u64 empty_size, u64 hint_byte,
                         struct btrfs_key *ins, int is_data)
@@ -6513,8 +6569,8 @@ int btrfs_reserve_extent(struct btrfs_trans_handle *trans,
        flags = btrfs_get_alloc_profile(root, is_data);
 again:
        WARN_ON(num_bytes < root->sectorsize);
-       ret = find_free_extent(trans, root, num_bytes, empty_size,
-                              hint_byte, ins, flags);
+       ret = find_free_extent(root, num_bytes, empty_size, hint_byte, ins,
+                              flags);
 
        if (ret == -ENOSPC) {
                if (!final_tried) {
@@ -6529,8 +6585,7 @@ again:
 
                        sinfo = __find_space_info(root->fs_info, flags);
                        btrfs_err(root->fs_info, "allocation failed flags %llu, wanted %llu",
-                               (unsigned long long)flags,
-                               (unsigned long long)num_bytes);
+                               flags, num_bytes);
                        if (sinfo)
                                dump_space_info(sinfo, num_bytes, 1);
                }
@@ -6550,7 +6605,7 @@ static int __btrfs_free_reserved_extent(struct btrfs_root *root,
        cache = btrfs_lookup_block_group(root->fs_info, start);
        if (!cache) {
                btrfs_err(root->fs_info, "Unable to find block group for %llu",
-                       (unsigned long long)start);
+                       start);
                return -ENOSPC;
        }
 
@@ -6646,8 +6701,7 @@ static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans,
        ret = update_block_group(root, ins->objectid, ins->offset, 1);
        if (ret) { /* -ENOENT, logic error */
                btrfs_err(fs_info, "update block group failed for %llu %llu",
-                       (unsigned long long)ins->objectid,
-                       (unsigned long long)ins->offset);
+                       ins->objectid, ins->offset);
                BUG();
        }
        return ret;
@@ -6719,8 +6773,7 @@ static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans,
        ret = update_block_group(root, ins->objectid, root->leafsize, 1);
        if (ret) { /* -ENOENT, logic error */
                btrfs_err(fs_info, "update block group failed for %llu %llu",
-                       (unsigned long long)ins->objectid,
-                       (unsigned long long)ins->offset);
+                       ins->objectid, ins->offset);
                BUG();
        }
        return ret;
@@ -6902,7 +6955,7 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
        if (IS_ERR(block_rsv))
                return ERR_CAST(block_rsv);
 
-       ret = btrfs_reserve_extent(trans, root, blocksize, blocksize,
+       ret = btrfs_reserve_extent(root, blocksize, blocksize,
                                   empty_size, hint, &ins, 0);
        if (ret) {
                unuse_block_rsv(root->fs_info, block_rsv, blocksize);
@@ -7173,6 +7226,8 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
                next = btrfs_find_create_tree_block(root, bytenr, blocksize);
                if (!next)
                        return -ENOMEM;
+               btrfs_set_buffer_lockdep_class(root->root_key.objectid, next,
+                                              level - 1);
                reada = 1;
        }
        btrfs_tree_lock(next);
@@ -7658,7 +7713,7 @@ out:
         * don't have it in the radix (like when we recover after a power fail
         * or unmount) so we don't leak memory.
         */
-       if (root_dropped == false)
+       if (!for_reloc && root_dropped == false)
                btrfs_add_dead_root(root);
        if (err)
                btrfs_std_error(root->fs_info, err);
@@ -8192,7 +8247,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                 * We haven't cached this block group, which means we could
                 * possibly have excluded extents on this block group.
                 */
-               if (block_group->cached == BTRFS_CACHE_NO)
+               if (block_group->cached == BTRFS_CACHE_NO ||
+                   block_group->cached == BTRFS_CACHE_ERROR)
                        free_excluded_extents(info->extent_root, block_group);
 
                btrfs_remove_free_space_cache(block_group);
@@ -8409,9 +8465,13 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                 * avoid allocating from un-mirrored block group if there are
                 * mirrored block groups.
                 */
-               list_for_each_entry(cache, &space_info->block_groups[3], list)
+               list_for_each_entry(cache,
+                               &space_info->block_groups[BTRFS_RAID_RAID0],
+                               list)
                        set_block_group_ro(cache, 1);
-               list_for_each_entry(cache, &space_info->block_groups[4], list)
+               list_for_each_entry(cache,
+                               &space_info->block_groups[BTRFS_RAID_SINGLE],
+                               list)
                        set_block_group_ro(cache, 1);
        }
 
index fe443fece85111d69b833f9cac4e2bbb85b6ea80..09582b81640cc8e02ced7ea7c8ec6b22acdc8dba 100644 (file)
@@ -61,9 +61,8 @@ void btrfs_leak_debug_check(void)
                state = list_entry(states.next, struct extent_state, leak_list);
                printk(KERN_ERR "btrfs state leak: start %llu end %llu "
                       "state %lu in tree %p refs %d\n",
-                      (unsigned long long)state->start,
-                      (unsigned long long)state->end,
-                      state->state, state->tree, atomic_read(&state->refs));
+                      state->start, state->end, state->state, state->tree,
+                      atomic_read(&state->refs));
                list_del(&state->leak_list);
                kmem_cache_free(extent_state_cache, state);
        }
@@ -71,8 +70,8 @@ void btrfs_leak_debug_check(void)
        while (!list_empty(&buffers)) {
                eb = list_entry(buffers.next, struct extent_buffer, leak_list);
                printk(KERN_ERR "btrfs buffer leak start %llu len %lu "
-                      "refs %d\n", (unsigned long long)eb->start,
-                      eb->len, atomic_read(&eb->refs));
+                      "refs %d\n",
+                      eb->start, eb->len, atomic_read(&eb->refs));
                list_del(&eb->leak_list);
                kmem_cache_free(extent_buffer_cache, eb);
        }
@@ -88,11 +87,7 @@ static inline void __btrfs_debug_check_extent_io_range(const char *caller,
        if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) {
                printk_ratelimited(KERN_DEBUG
                    "btrfs: %s: ino %llu isize %llu odd range [%llu,%llu]\n",
-                               caller,
-                               (unsigned long long)btrfs_ino(inode),
-                               (unsigned long long)isize,
-                               (unsigned long long)start,
-                               (unsigned long long)end);
+                               caller, btrfs_ino(inode), isize, start, end);
        }
 }
 #else
@@ -388,8 +383,7 @@ static int insert_state(struct extent_io_tree *tree,
 
        if (end < start)
                WARN(1, KERN_ERR "btrfs end < start %llu %llu\n",
-                      (unsigned long long)end,
-                      (unsigned long long)start);
+                      end, start);
        state->start = start;
        state->end = end;
 
@@ -400,9 +394,8 @@ static int insert_state(struct extent_io_tree *tree,
                struct extent_state *found;
                found = rb_entry(node, struct extent_state, rb_node);
                printk(KERN_ERR "btrfs found node %llu %llu on insert of "
-                      "%llu %llu\n", (unsigned long long)found->start,
-                      (unsigned long long)found->end,
-                      (unsigned long long)start, (unsigned long long)end);
+                      "%llu %llu\n",
+                      found->start, found->end, start, end);
                return -EEXIST;
        }
        state->tree = tree;
@@ -762,15 +755,6 @@ static void cache_state(struct extent_state *state,
        }
 }
 
-static void uncache_state(struct extent_state **cached_ptr)
-{
-       if (cached_ptr && (*cached_ptr)) {
-               struct extent_state *state = *cached_ptr;
-               *cached_ptr = NULL;
-               free_extent_state(state);
-       }
-}
-
 /*
  * set some bits on a range in the tree.  This may require allocations or
  * sleeping, so the gfp mask is used to indicate what is allowed.
@@ -1687,31 +1671,21 @@ out_failed:
        return found;
 }
 
-int extent_clear_unlock_delalloc(struct inode *inode,
-                               struct extent_io_tree *tree,
-                               u64 start, u64 end, struct page *locked_page,
-                               unsigned long op)
+int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
+                                struct page *locked_page,
+                                unsigned long clear_bits,
+                                unsigned long page_ops)
 {
+       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
        int ret;
        struct page *pages[16];
        unsigned long index = start >> PAGE_CACHE_SHIFT;
        unsigned long end_index = end >> PAGE_CACHE_SHIFT;
        unsigned long nr_pages = end_index - index + 1;
        int i;
-       unsigned long clear_bits = 0;
-
-       if (op & EXTENT_CLEAR_UNLOCK)
-               clear_bits |= EXTENT_LOCKED;
-       if (op & EXTENT_CLEAR_DIRTY)
-               clear_bits |= EXTENT_DIRTY;
-
-       if (op & EXTENT_CLEAR_DELALLOC)
-               clear_bits |= EXTENT_DELALLOC;
 
        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 |
-                   EXTENT_SET_PRIVATE2)))
+       if (page_ops == 0)
                return 0;
 
        while (nr_pages > 0) {
@@ -1720,20 +1694,20 @@ int extent_clear_unlock_delalloc(struct inode *inode,
                                     nr_pages, ARRAY_SIZE(pages)), pages);
                for (i = 0; i < ret; i++) {
 
-                       if (op & EXTENT_SET_PRIVATE2)
+                       if (page_ops & PAGE_SET_PRIVATE2)
                                SetPagePrivate2(pages[i]);
 
                        if (pages[i] == locked_page) {
                                page_cache_release(pages[i]);
                                continue;
                        }
-                       if (op & EXTENT_CLEAR_DIRTY)
+                       if (page_ops & PAGE_CLEAR_DIRTY)
                                clear_page_dirty_for_io(pages[i]);
-                       if (op & EXTENT_SET_WRITEBACK)
+                       if (page_ops & PAGE_SET_WRITEBACK)
                                set_page_writeback(pages[i]);
-                       if (op & EXTENT_END_WRITEBACK)
+                       if (page_ops & PAGE_END_WRITEBACK)
                                end_page_writeback(pages[i]);
-                       if (op & EXTENT_CLEAR_UNLOCK_PAGE)
+                       if (page_ops & PAGE_UNLOCK)
                                unlock_page(pages[i]);
                        page_cache_release(pages[i]);
                }
@@ -1810,7 +1784,7 @@ out:
  * set the private field for a given byte offset in the tree.  If there isn't
  * an extent_state there already, this does nothing.
  */
-int set_state_private(struct extent_io_tree *tree, u64 start, u64 private)
+static int set_state_private(struct extent_io_tree *tree, u64 start, u64 private)
 {
        struct rb_node *node;
        struct extent_state *state;
@@ -1837,64 +1811,6 @@ out:
        return ret;
 }
 
-void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[],
-                           int count)
-{
-       struct rb_node *node;
-       struct extent_state *state;
-
-       spin_lock(&tree->lock);
-       /*
-        * this search will find all the extents that end after
-        * our range starts.
-        */
-       node = tree_search(tree, start);
-       BUG_ON(!node);
-
-       state = rb_entry(node, struct extent_state, rb_node);
-       BUG_ON(state->start != start);
-
-       while (count) {
-               state->private = *csums++;
-               count--;
-               state = next_state(state);
-       }
-       spin_unlock(&tree->lock);
-}
-
-static inline u64 __btrfs_get_bio_offset(struct bio *bio, int bio_index)
-{
-       struct bio_vec *bvec = bio->bi_io_vec + bio_index;
-
-       return page_offset(bvec->bv_page) + bvec->bv_offset;
-}
-
-void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio, int bio_index,
-                       u32 csums[], int count)
-{
-       struct rb_node *node;
-       struct extent_state *state = NULL;
-       u64 start;
-
-       spin_lock(&tree->lock);
-       do {
-               start = __btrfs_get_bio_offset(bio, bio_index);
-               if (state == NULL || state->start != start) {
-                       node = tree_search(tree, start);
-                       BUG_ON(!node);
-
-                       state = rb_entry(node, struct extent_state, rb_node);
-                       BUG_ON(state->start != start);
-               }
-               state->private = *csums++;
-               count--;
-               bio_index++;
-
-               state = next_state(state);
-       } while (count);
-       spin_unlock(&tree->lock);
-}
-
 int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private)
 {
        struct rb_node *node;
@@ -2173,7 +2089,8 @@ static int clean_io_failure(u64 start, struct page *page)
                                            EXTENT_LOCKED);
        spin_unlock(&BTRFS_I(inode)->io_tree.lock);
 
-       if (state && state->start == failrec->start) {
+       if (state && state->start <= failrec->start &&
+           state->end >= failrec->start + failrec->len - 1) {
                fs_info = BTRFS_I(inode)->root->fs_info;
                num_copies = btrfs_num_copies(fs_info, failrec->logical,
                                              failrec->len);
@@ -2201,9 +2118,9 @@ out:
  * needed
  */
 
-static int bio_readpage_error(struct bio *failed_bio, struct page *page,
-                               u64 start, u64 end, int failed_mirror,
-                               struct extent_state *state)
+static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
+                             struct page *page, u64 start, u64 end,
+                             int failed_mirror)
 {
        struct io_failure_record *failrec = NULL;
        u64 private;
@@ -2213,6 +2130,8 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
        struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
        struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree;
        struct bio *bio;
+       struct btrfs_io_bio *btrfs_failed_bio;
+       struct btrfs_io_bio *btrfs_bio;
        int num_copies;
        int ret;
        int read_mode;
@@ -2296,23 +2215,12 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
                 * all the retry and error correction code that follows. no
                 * matter what the error is, it is very likely to persist.
                 */
-               pr_debug("bio_readpage_error: cannot repair, num_copies == 1. "
-                        "state=%p, num_copies=%d, next_mirror %d, "
-                        "failed_mirror %d\n", state, num_copies,
-                        failrec->this_mirror, failed_mirror);
+               pr_debug("bio_readpage_error: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d\n",
+                        num_copies, failrec->this_mirror, failed_mirror);
                free_io_failure(inode, failrec, 0);
                return -EIO;
        }
 
-       if (!state) {
-               spin_lock(&tree->lock);
-               state = find_first_extent_bit_state(tree, failrec->start,
-                                                   EXTENT_LOCKED);
-               if (state && state->start != failrec->start)
-                       state = NULL;
-               spin_unlock(&tree->lock);
-       }
-
        /*
         * there are two premises:
         *      a) deliver good data to the caller
@@ -2349,9 +2257,8 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
                read_mode = READ_SYNC;
        }
 
-       if (!state || failrec->this_mirror > num_copies) {
-               pr_debug("bio_readpage_error: (fail) state=%p, num_copies=%d, "
-                        "next_mirror %d, failed_mirror %d\n", state,
+       if (failrec->this_mirror > num_copies) {
+               pr_debug("bio_readpage_error: (fail) num_copies=%d, next_mirror %d, failed_mirror %d\n",
                         num_copies, failrec->this_mirror, failed_mirror);
                free_io_failure(inode, failrec, 0);
                return -EIO;
@@ -2362,12 +2269,24 @@ static int bio_readpage_error(struct bio *failed_bio, struct page *page,
                free_io_failure(inode, failrec, 0);
                return -EIO;
        }
-       bio->bi_private = state;
        bio->bi_end_io = failed_bio->bi_end_io;
        bio->bi_sector = failrec->logical >> 9;
        bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
        bio->bi_size = 0;
 
+       btrfs_failed_bio = btrfs_io_bio(failed_bio);
+       if (btrfs_failed_bio->csum) {
+               struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info;
+               u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
+
+               btrfs_bio = btrfs_io_bio(bio);
+               btrfs_bio->csum = btrfs_bio->csum_inline;
+               phy_offset >>= inode->i_sb->s_blocksize_bits;
+               phy_offset *= csum_size;
+               memcpy(btrfs_bio->csum, btrfs_failed_bio->csum + phy_offset,
+                      csum_size);
+       }
+
        bio_add_page(bio, page, failrec->len, start - page_offset(page));
 
        pr_debug("bio_readpage_error: submitting new read[%#x] to "
@@ -2450,6 +2369,18 @@ static void end_bio_extent_writepage(struct bio *bio, int err)
        bio_put(bio);
 }
 
+static void
+endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len,
+                             int uptodate)
+{
+       struct extent_state *cached = NULL;
+       u64 end = start + len - 1;
+
+       if (uptodate && tree->track_uptodate)
+               set_extent_uptodate(tree, start, end, &cached, GFP_ATOMIC);
+       unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC);
+}
+
 /*
  * after a readpage IO is done, we need to:
  * clear the uptodate bits on error
@@ -2466,9 +2397,14 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
        struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
        struct bio_vec *bvec = bio->bi_io_vec;
+       struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        struct extent_io_tree *tree;
+       u64 offset = 0;
        u64 start;
        u64 end;
+       u64 len;
+       u64 extent_start = 0;
+       u64 extent_len = 0;
        int mirror;
        int ret;
 
@@ -2477,9 +2413,6 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
 
        do {
                struct page *page = bvec->bv_page;
-               struct extent_state *cached = NULL;
-               struct extent_state *state;
-               struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
                struct inode *inode = page->mapping->host;
 
                pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, "
@@ -2500,37 +2433,32 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
 
                start = page_offset(page);
                end = start + bvec->bv_offset + bvec->bv_len - 1;
+               len = bvec->bv_len;
 
                if (++bvec <= bvec_end)
                        prefetchw(&bvec->bv_page->flags);
 
-               spin_lock(&tree->lock);
-               state = find_first_extent_bit_state(tree, start, EXTENT_LOCKED);
-               if (state && state->start == start) {
-                       /*
-                        * take a reference on the state, unlock will drop
-                        * the ref
-                        */
-                       cache_state(state, &cached);
-               }
-               spin_unlock(&tree->lock);
-
                mirror = io_bio->mirror_num;
-               if (uptodate && tree->ops && tree->ops->readpage_end_io_hook) {
-                       ret = tree->ops->readpage_end_io_hook(page, start, end,
-                                                             state, mirror);
+               if (likely(uptodate && tree->ops &&
+                          tree->ops->readpage_end_io_hook)) {
+                       ret = tree->ops->readpage_end_io_hook(io_bio, offset,
+                                                             page, start, end,
+                                                             mirror);
                        if (ret)
                                uptodate = 0;
                        else
                                clean_io_failure(start, page);
                }
 
-               if (!uptodate && tree->ops && tree->ops->readpage_io_failed_hook) {
+               if (likely(uptodate))
+                       goto readpage_ok;
+
+               if (tree->ops && tree->ops->readpage_io_failed_hook) {
                        ret = tree->ops->readpage_io_failed_hook(page, mirror);
                        if (!ret && !err &&
                            test_bit(BIO_UPTODATE, &bio->bi_flags))
                                uptodate = 1;
-               } else if (!uptodate) {
+               } else {
                        /*
                         * The generic bio_readpage_error handles errors the
                         * following way: If possible, new read requests are
@@ -2541,24 +2469,18 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                         * can't handle the error it will return -EIO and we
                         * remain responsible for that page.
                         */
-                       ret = bio_readpage_error(bio, page, start, end, mirror, NULL);
+                       ret = bio_readpage_error(bio, offset, page, start, end,
+                                                mirror);
                        if (ret == 0) {
                                uptodate =
                                        test_bit(BIO_UPTODATE, &bio->bi_flags);
                                if (err)
                                        uptodate = 0;
-                               uncache_state(&cached);
                                continue;
                        }
                }
-
-               if (uptodate && tree->track_uptodate) {
-                       set_extent_uptodate(tree, start, end, &cached,
-                                           GFP_ATOMIC);
-               }
-               unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC);
-
-               if (uptodate) {
+readpage_ok:
+               if (likely(uptodate)) {
                        loff_t i_size = i_size_read(inode);
                        pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
                        unsigned offset;
@@ -2573,8 +2495,36 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                        SetPageError(page);
                }
                unlock_page(page);
+               offset += len;
+
+               if (unlikely(!uptodate)) {
+                       if (extent_len) {
+                               endio_readpage_release_extent(tree,
+                                                             extent_start,
+                                                             extent_len, 1);
+                               extent_start = 0;
+                               extent_len = 0;
+                       }
+                       endio_readpage_release_extent(tree, start,
+                                                     end - start + 1, 0);
+               } else if (!extent_len) {
+                       extent_start = start;
+                       extent_len = end + 1 - start;
+               } else if (extent_start + extent_len == start) {
+                       extent_len += end + 1 - start;
+               } else {
+                       endio_readpage_release_extent(tree, extent_start,
+                                                     extent_len, uptodate);
+                       extent_start = start;
+                       extent_len = end + 1 - start;
+               }
        } while (bvec <= bvec_end);
 
+       if (extent_len)
+               endio_readpage_release_extent(tree, extent_start, extent_len,
+                                             uptodate);
+       if (io_bio->end_io)
+               io_bio->end_io(io_bio, err);
        bio_put(bio);
 }
 
@@ -2586,6 +2536,7 @@ struct bio *
 btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
                gfp_t gfp_flags)
 {
+       struct btrfs_io_bio *btrfs_bio;
        struct bio *bio;
 
        bio = bio_alloc_bioset(gfp_flags, nr_vecs, btrfs_bioset);
@@ -2601,6 +2552,10 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
                bio->bi_size = 0;
                bio->bi_bdev = bdev;
                bio->bi_sector = first_sector;
+               btrfs_bio = btrfs_io_bio(bio);
+               btrfs_bio->csum = NULL;
+               btrfs_bio->csum_allocated = NULL;
+               btrfs_bio->end_io = NULL;
        }
        return bio;
 }
@@ -2614,7 +2569,17 @@ struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask)
 /* this also allocates from the btrfs_bioset */
 struct bio *btrfs_io_bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs)
 {
-       return bio_alloc_bioset(gfp_mask, nr_iovecs, btrfs_bioset);
+       struct btrfs_io_bio *btrfs_bio;
+       struct bio *bio;
+
+       bio = bio_alloc_bioset(gfp_mask, nr_iovecs, btrfs_bioset);
+       if (bio) {
+               btrfs_bio = btrfs_io_bio(bio);
+               btrfs_bio->csum = NULL;
+               btrfs_bio->csum_allocated = NULL;
+               btrfs_bio->end_io = NULL;
+       }
+       return bio;
 }
 
 
@@ -2738,17 +2703,45 @@ void set_page_extent_mapped(struct page *page)
        }
 }
 
+static struct extent_map *
+__get_extent_map(struct inode *inode, struct page *page, size_t pg_offset,
+                u64 start, u64 len, get_extent_t *get_extent,
+                struct extent_map **em_cached)
+{
+       struct extent_map *em;
+
+       if (em_cached && *em_cached) {
+               em = *em_cached;
+               if (em->in_tree && start >= em->start &&
+                   start < extent_map_end(em)) {
+                       atomic_inc(&em->refs);
+                       return em;
+               }
+
+               free_extent_map(em);
+               *em_cached = NULL;
+       }
+
+       em = get_extent(inode, page, pg_offset, start, len, 0);
+       if (em_cached && !IS_ERR_OR_NULL(em)) {
+               BUG_ON(*em_cached);
+               atomic_inc(&em->refs);
+               *em_cached = em;
+       }
+       return em;
+}
 /*
  * basic readpage implementation.  Locked extent state structs are inserted
  * into the tree that are removed when the IO is done (by the end_io
  * handlers)
  * XXX JDM: This needs looking at to ensure proper page locking
  */
-static int __extent_read_full_page(struct extent_io_tree *tree,
-                                  struct page *page,
-                                  get_extent_t *get_extent,
-                                  struct bio **bio, int mirror_num,
-                                  unsigned long *bio_flags, int rw)
+static int __do_readpage(struct extent_io_tree *tree,
+                        struct page *page,
+                        get_extent_t *get_extent,
+                        struct extent_map **em_cached,
+                        struct bio **bio, int mirror_num,
+                        unsigned long *bio_flags, int rw)
 {
        struct inode *inode = page->mapping->host;
        u64 start = page_offset(page);
@@ -2762,35 +2755,26 @@ 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;
+       int parent_locked = *bio_flags & EXTENT_BIO_PARENT_LOCKED;
        size_t pg_offset = 0;
        size_t iosize;
        size_t disk_io_size;
        size_t blocksize = inode->i_sb->s_blocksize;
-       unsigned long this_bio_flag = 0;
+       unsigned long this_bio_flag = *bio_flags & EXTENT_BIO_PARENT_LOCKED;
 
        set_page_extent_mapped(page);
 
+       end = page_end;
        if (!PageUptodate(page)) {
                if (cleancache_get_page(page) == 0) {
                        BUG_ON(blocksize != PAGE_SIZE);
+                       unlock_extent(tree, start, end);
                        goto out;
                }
        }
 
-       end = page_end;
-       while (1) {
-               lock_extent(tree, start, end);
-               ordered = btrfs_lookup_ordered_extent(inode, start);
-               if (!ordered)
-                       break;
-               unlock_extent(tree, start, end);
-               btrfs_start_ordered_extent(inode, ordered, 1);
-               btrfs_put_ordered_extent(ordered);
-       }
-
        if (page->index == last_byte >> PAGE_CACHE_SHIFT) {
                char *userpage;
                size_t zero_offset = last_byte & (PAGE_CACHE_SIZE - 1);
@@ -2817,15 +2801,18 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        kunmap_atomic(userpage);
                        set_extent_uptodate(tree, cur, cur + iosize - 1,
                                            &cached, GFP_NOFS);
-                       unlock_extent_cached(tree, cur, cur + iosize - 1,
-                                            &cached, GFP_NOFS);
+                       if (!parent_locked)
+                               unlock_extent_cached(tree, cur,
+                                                    cur + iosize - 1,
+                                                    &cached, GFP_NOFS);
                        break;
                }
-               em = get_extent(inode, page, pg_offset, cur,
-                               end - cur + 1, 0);
+               em = __get_extent_map(inode, page, pg_offset, cur,
+                                     end - cur + 1, get_extent, em_cached);
                if (IS_ERR_OR_NULL(em)) {
                        SetPageError(page);
-                       unlock_extent(tree, cur, end);
+                       if (!parent_locked)
+                               unlock_extent(tree, cur, end);
                        break;
                }
                extent_offset = cur - em->start;
@@ -2833,7 +2820,7 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                BUG_ON(end < cur);
 
                if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) {
-                       this_bio_flag = EXTENT_BIO_COMPRESSED;
+                       this_bio_flag |= EXTENT_BIO_COMPRESSED;
                        extent_set_compress_type(&this_bio_flag,
                                                 em->compress_type);
                }
@@ -2877,7 +2864,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                if (test_range_bit(tree, cur, cur_end,
                                   EXTENT_UPTODATE, 1, NULL)) {
                        check_page_uptodate(tree, page);
-                       unlock_extent(tree, cur, cur + iosize - 1);
+                       if (!parent_locked)
+                               unlock_extent(tree, cur, cur + iosize - 1);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;
@@ -2887,7 +2875,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                 */
                if (block_start == EXTENT_MAP_INLINE) {
                        SetPageError(page);
-                       unlock_extent(tree, cur, cur + iosize - 1);
+                       if (!parent_locked)
+                               unlock_extent(tree, cur, cur + iosize - 1);
                        cur = cur + iosize;
                        pg_offset += iosize;
                        continue;
@@ -2905,7 +2894,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,
                        *bio_flags = this_bio_flag;
                } else {
                        SetPageError(page);
-                       unlock_extent(tree, cur, cur + iosize - 1);
+                       if (!parent_locked)
+                               unlock_extent(tree, cur, cur + iosize - 1);
                }
                cur = cur + iosize;
                pg_offset += iosize;
@@ -2919,6 +2909,104 @@ out:
        return 0;
 }
 
+static inline void __do_contiguous_readpages(struct extent_io_tree *tree,
+                                            struct page *pages[], int nr_pages,
+                                            u64 start, u64 end,
+                                            get_extent_t *get_extent,
+                                            struct extent_map **em_cached,
+                                            struct bio **bio, int mirror_num,
+                                            unsigned long *bio_flags, int rw)
+{
+       struct inode *inode;
+       struct btrfs_ordered_extent *ordered;
+       int index;
+
+       inode = pages[0]->mapping->host;
+       while (1) {
+               lock_extent(tree, start, end);
+               ordered = btrfs_lookup_ordered_range(inode, start,
+                                                    end - start + 1);
+               if (!ordered)
+                       break;
+               unlock_extent(tree, start, end);
+               btrfs_start_ordered_extent(inode, ordered, 1);
+               btrfs_put_ordered_extent(ordered);
+       }
+
+       for (index = 0; index < nr_pages; index++) {
+               __do_readpage(tree, pages[index], get_extent, em_cached, bio,
+                             mirror_num, bio_flags, rw);
+               page_cache_release(pages[index]);
+       }
+}
+
+static void __extent_readpages(struct extent_io_tree *tree,
+                              struct page *pages[],
+                              int nr_pages, get_extent_t *get_extent,
+                              struct extent_map **em_cached,
+                              struct bio **bio, int mirror_num,
+                              unsigned long *bio_flags, int rw)
+{
+       u64 start = 0;
+       u64 end = 0;
+       u64 page_start;
+       int index;
+       int first_index = 0;
+
+       for (index = 0; index < nr_pages; index++) {
+               page_start = page_offset(pages[index]);
+               if (!end) {
+                       start = page_start;
+                       end = start + PAGE_CACHE_SIZE - 1;
+                       first_index = index;
+               } else if (end + 1 == page_start) {
+                       end += PAGE_CACHE_SIZE;
+               } else {
+                       __do_contiguous_readpages(tree, &pages[first_index],
+                                                 index - first_index, start,
+                                                 end, get_extent, em_cached,
+                                                 bio, mirror_num, bio_flags,
+                                                 rw);
+                       start = page_start;
+                       end = start + PAGE_CACHE_SIZE - 1;
+                       first_index = index;
+               }
+       }
+
+       if (end)
+               __do_contiguous_readpages(tree, &pages[first_index],
+                                         index - first_index, start,
+                                         end, get_extent, em_cached, bio,
+                                         mirror_num, bio_flags, rw);
+}
+
+static int __extent_read_full_page(struct extent_io_tree *tree,
+                                  struct page *page,
+                                  get_extent_t *get_extent,
+                                  struct bio **bio, int mirror_num,
+                                  unsigned long *bio_flags, int rw)
+{
+       struct inode *inode = page->mapping->host;
+       struct btrfs_ordered_extent *ordered;
+       u64 start = page_offset(page);
+       u64 end = start + PAGE_CACHE_SIZE - 1;
+       int ret;
+
+       while (1) {
+               lock_extent(tree, start, end);
+               ordered = btrfs_lookup_ordered_extent(inode, start);
+               if (!ordered)
+                       break;
+               unlock_extent(tree, start, end);
+               btrfs_start_ordered_extent(inode, ordered, 1);
+               btrfs_put_ordered_extent(ordered);
+       }
+
+       ret = __do_readpage(tree, page, get_extent, NULL, bio, mirror_num,
+                           bio_flags, rw);
+       return ret;
+}
+
 int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
                            get_extent_t *get_extent, int mirror_num)
 {
@@ -2933,6 +3021,20 @@ int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
        return ret;
 }
 
+int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
+                                get_extent_t *get_extent, int mirror_num)
+{
+       struct bio *bio = NULL;
+       unsigned long bio_flags = EXTENT_BIO_PARENT_LOCKED;
+       int ret;
+
+       ret = __do_readpage(tree, page, get_extent, NULL, &bio, mirror_num,
+                                     &bio_flags, READ);
+       if (bio)
+               ret = submit_one_bio(READ, bio, mirror_num, bio_flags);
+       return ret;
+}
+
 static noinline void update_nr_written(struct page *page,
                                      struct writeback_control *wbc,
                                      unsigned long nr_written)
@@ -3189,8 +3291,7 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
                        if (!PageWriteback(page)) {
                                printk(KERN_ERR "btrfs warning page %lu not "
                                       "writeback, cur %llu end %llu\n",
-                                      page->index, (unsigned long long)cur,
-                                      (unsigned long long)end);
+                                      page->index, cur, end);
                        }
 
                        ret = submit_extent_page(write_flags, tree, page,
@@ -3769,7 +3870,7 @@ int extent_readpages(struct extent_io_tree *tree,
        unsigned long bio_flags = 0;
        struct page *pagepool[16];
        struct page *page;
-       int i = 0;
+       struct extent_map *em_cached = NULL;
        int nr = 0;
 
        for (page_idx = 0; page_idx < nr_pages; page_idx++) {
@@ -3786,18 +3887,16 @@ int extent_readpages(struct extent_io_tree *tree,
                pagepool[nr++] = page;
                if (nr < ARRAY_SIZE(pagepool))
                        continue;
-               for (i = 0; i < nr; i++) {
-                       __extent_read_full_page(tree, pagepool[i], get_extent,
-                                       &bio, 0, &bio_flags, READ);
-                       page_cache_release(pagepool[i]);
-               }
+               __extent_readpages(tree, pagepool, nr, get_extent, &em_cached,
+                                  &bio, 0, &bio_flags, READ);
                nr = 0;
        }
-       for (i = 0; i < nr; i++) {
-               __extent_read_full_page(tree, pagepool[i], get_extent,
-                                       &bio, 0, &bio_flags, READ);
-               page_cache_release(pagepool[i]);
-       }
+       if (nr)
+               __extent_readpages(tree, pagepool, nr, get_extent, &em_cached,
+                                  &bio, 0, &bio_flags, READ);
+
+       if (em_cached)
+               free_extent_map(em_cached);
 
        BUG_ON(!list_empty(pages));
        if (bio)
@@ -4136,6 +4235,76 @@ static void __free_extent_buffer(struct extent_buffer *eb)
        kmem_cache_free(extent_buffer_cache, eb);
 }
 
+static int extent_buffer_under_io(struct extent_buffer *eb)
+{
+       return (atomic_read(&eb->io_pages) ||
+               test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags) ||
+               test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
+}
+
+/*
+ * Helper for releasing extent buffer page.
+ */
+static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
+                                               unsigned long start_idx)
+{
+       unsigned long index;
+       unsigned long num_pages;
+       struct page *page;
+       int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags);
+
+       BUG_ON(extent_buffer_under_io(eb));
+
+       num_pages = num_extent_pages(eb->start, eb->len);
+       index = start_idx + num_pages;
+       if (start_idx >= index)
+               return;
+
+       do {
+               index--;
+               page = extent_buffer_page(eb, index);
+               if (page && mapped) {
+                       spin_lock(&page->mapping->private_lock);
+                       /*
+                        * We do this since we'll remove the pages after we've
+                        * removed the eb from the radix tree, so we could race
+                        * and have this page now attached to the new eb.  So
+                        * only clear page_private if it's still connected to
+                        * this eb.
+                        */
+                       if (PagePrivate(page) &&
+                           page->private == (unsigned long)eb) {
+                               BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
+                               BUG_ON(PageDirty(page));
+                               BUG_ON(PageWriteback(page));
+                               /*
+                                * We need to make sure we haven't be attached
+                                * to a new eb.
+                                */
+                               ClearPagePrivate(page);
+                               set_page_private(page, 0);
+                               /* One for the page private */
+                               page_cache_release(page);
+                       }
+                       spin_unlock(&page->mapping->private_lock);
+
+               }
+               if (page) {
+                       /* One for when we alloced the page */
+                       page_cache_release(page);
+               }
+       } while (index != start_idx);
+}
+
+/*
+ * Helper for releasing the extent buffer.
+ */
+static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
+{
+       btrfs_release_extent_buffer_page(eb, 0);
+       __free_extent_buffer(eb);
+}
+
 static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
                                                   u64 start,
                                                   unsigned long len,
@@ -4184,13 +4353,16 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src)
        struct extent_buffer *new;
        unsigned long num_pages = num_extent_pages(src->start, src->len);
 
-       new = __alloc_extent_buffer(NULL, src->start, src->len, GFP_ATOMIC);
+       new = __alloc_extent_buffer(NULL, src->start, src->len, GFP_NOFS);
        if (new == NULL)
                return NULL;
 
        for (i = 0; i < num_pages; i++) {
-               p = alloc_page(GFP_ATOMIC);
-               BUG_ON(!p);
+               p = alloc_page(GFP_NOFS);
+               if (!p) {
+                       btrfs_release_extent_buffer(new);
+                       return NULL;
+               }
                attach_extent_buffer_page(new, p);
                WARN_ON(PageDirty(p));
                SetPageUptodate(p);
@@ -4210,12 +4382,12 @@ struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len)
        unsigned long num_pages = num_extent_pages(0, len);
        unsigned long i;
 
-       eb = __alloc_extent_buffer(NULL, start, len, GFP_ATOMIC);
+       eb = __alloc_extent_buffer(NULL, start, len, GFP_NOFS);
        if (!eb)
                return NULL;
 
        for (i = 0; i < num_pages; i++) {
-               eb->pages[i] = alloc_page(GFP_ATOMIC);
+               eb->pages[i] = alloc_page(GFP_NOFS);
                if (!eb->pages[i])
                        goto err;
        }
@@ -4231,76 +4403,6 @@ err:
        return NULL;
 }
 
-static int extent_buffer_under_io(struct extent_buffer *eb)
-{
-       return (atomic_read(&eb->io_pages) ||
-               test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags) ||
-               test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
-}
-
-/*
- * Helper for releasing extent buffer page.
- */
-static void btrfs_release_extent_buffer_page(struct extent_buffer *eb,
-                                               unsigned long start_idx)
-{
-       unsigned long index;
-       unsigned long num_pages;
-       struct page *page;
-       int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags);
-
-       BUG_ON(extent_buffer_under_io(eb));
-
-       num_pages = num_extent_pages(eb->start, eb->len);
-       index = start_idx + num_pages;
-       if (start_idx >= index)
-               return;
-
-       do {
-               index--;
-               page = extent_buffer_page(eb, index);
-               if (page && mapped) {
-                       spin_lock(&page->mapping->private_lock);
-                       /*
-                        * We do this since we'll remove the pages after we've
-                        * removed the eb from the radix tree, so we could race
-                        * and have this page now attached to the new eb.  So
-                        * only clear page_private if it's still connected to
-                        * this eb.
-                        */
-                       if (PagePrivate(page) &&
-                           page->private == (unsigned long)eb) {
-                               BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags));
-                               BUG_ON(PageDirty(page));
-                               BUG_ON(PageWriteback(page));
-                               /*
-                                * We need to make sure we haven't be attached
-                                * to a new eb.
-                                */
-                               ClearPagePrivate(page);
-                               set_page_private(page, 0);
-                               /* One for the page private */
-                               page_cache_release(page);
-                       }
-                       spin_unlock(&page->mapping->private_lock);
-
-               }
-               if (page) {
-                       /* One for when we alloced the page */
-                       page_cache_release(page);
-               }
-       } while (index != start_idx);
-}
-
-/*
- * Helper for releasing the extent buffer.
- */
-static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
-{
-       btrfs_release_extent_buffer_page(eb, 0);
-       __free_extent_buffer(eb);
-}
-
 static void check_buffer_tree_ref(struct extent_buffer *eb)
 {
        int refs;
@@ -4771,7 +4873,7 @@ void read_extent_buffer(struct extent_buffer *eb, void *dstv,
        WARN_ON(start > eb->len);
        WARN_ON(start + len > eb->start + eb->len);
 
-       offset = (start_offset + start) & ((unsigned long)PAGE_CACHE_SIZE - 1);
+       offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
                page = extent_buffer_page(eb, i);
@@ -4813,8 +4915,8 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start,
 
        if (start + min_len > eb->len) {
                WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, "
-                      "wanted %lu %lu\n", (unsigned long long)eb->start,
-                      eb->len, start, min_len);
+                      "wanted %lu %lu\n",
+                      eb->start, eb->len, start, min_len);
                return -EINVAL;
        }
 
@@ -4841,7 +4943,7 @@ int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv,
        WARN_ON(start > eb->len);
        WARN_ON(start + len > eb->start + eb->len);
 
-       offset = (start_offset + start) & ((unsigned long)PAGE_CACHE_SIZE - 1);
+       offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
                page = extent_buffer_page(eb, i);
@@ -4875,7 +4977,7 @@ void write_extent_buffer(struct extent_buffer *eb, const void *srcv,
        WARN_ON(start > eb->len);
        WARN_ON(start + len > eb->start + eb->len);
 
-       offset = (start_offset + start) & ((unsigned long)PAGE_CACHE_SIZE - 1);
+       offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
                page = extent_buffer_page(eb, i);
@@ -4905,7 +5007,7 @@ void memset_extent_buffer(struct extent_buffer *eb, char c,
        WARN_ON(start > eb->len);
        WARN_ON(start + len > eb->start + eb->len);
 
-       offset = (start_offset + start) & ((unsigned long)PAGE_CACHE_SIZE - 1);
+       offset = (start_offset + start) & (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
                page = extent_buffer_page(eb, i);
@@ -4936,7 +5038,7 @@ void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src,
        WARN_ON(src->len != dst_len);
 
        offset = (start_offset + dst_offset) &
-               ((unsigned long)PAGE_CACHE_SIZE - 1);
+               (PAGE_CACHE_SIZE - 1);
 
        while (len > 0) {
                page = extent_buffer_page(dst, i);
@@ -5022,9 +5124,9 @@ void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
 
        while (len > 0) {
                dst_off_in_page = (start_offset + dst_offset) &
-                       ((unsigned long)PAGE_CACHE_SIZE - 1);
+                       (PAGE_CACHE_SIZE - 1);
                src_off_in_page = (start_offset + src_offset) &
-                       ((unsigned long)PAGE_CACHE_SIZE - 1);
+                       (PAGE_CACHE_SIZE - 1);
 
                dst_i = (start_offset + dst_offset) >> PAGE_CACHE_SHIFT;
                src_i = (start_offset + src_offset) >> PAGE_CACHE_SHIFT;
@@ -5075,9 +5177,9 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
                src_i = (start_offset + src_end) >> PAGE_CACHE_SHIFT;
 
                dst_off_in_page = (start_offset + dst_end) &
-                       ((unsigned long)PAGE_CACHE_SIZE - 1);
+                       (PAGE_CACHE_SIZE - 1);
                src_off_in_page = (start_offset + src_end) &
-                       ((unsigned long)PAGE_CACHE_SIZE - 1);
+                       (PAGE_CACHE_SIZE - 1);
 
                cur = min_t(unsigned long, len, src_off_in_page + 1);
                cur = min(cur, dst_off_in_page + 1);
index 3b8c4e26e1da08f69e081a75a518d452b221bbf4..6dbc645f1f3d00e9b05e290aea4ce05e8f95617a 100644 (file)
@@ -29,6 +29,7 @@
  */
 #define EXTENT_BIO_COMPRESSED 1
 #define EXTENT_BIO_TREE_LOG 2
+#define EXTENT_BIO_PARENT_LOCKED 4
 #define EXTENT_BIO_FLAG_SHIFT 16
 
 /* these are bit numbers for test/set bit */
 #define EXTENT_BUFFER_DUMMY 9
 
 /* these are flags for extent_clear_unlock_delalloc */
-#define EXTENT_CLEAR_UNLOCK_PAGE 0x1
-#define EXTENT_CLEAR_UNLOCK     0x2
-#define EXTENT_CLEAR_DELALLOC   0x4
-#define EXTENT_CLEAR_DIRTY      0x8
-#define EXTENT_SET_WRITEBACK    0x10
-#define EXTENT_END_WRITEBACK    0x20
-#define EXTENT_SET_PRIVATE2     0x40
-#define EXTENT_CLEAR_ACCOUNTING  0x80
+#define PAGE_UNLOCK            (1 << 0)
+#define PAGE_CLEAR_DIRTY       (1 << 1)
+#define PAGE_SET_WRITEBACK     (1 << 2)
+#define PAGE_END_WRITEBACK     (1 << 3)
+#define PAGE_SET_PRIVATE2      (1 << 4)
 
 /*
  * page->private values.  Every page that is controlled by the extent
@@ -62,6 +60,7 @@
 
 struct extent_state;
 struct btrfs_root;
+struct btrfs_io_bio;
 
 typedef        int (extent_submit_bio_hook_t)(struct inode *inode, int rw,
                                       struct bio *bio, int mirror_num,
@@ -77,8 +76,9 @@ struct extent_io_ops {
                              size_t size, struct bio *bio,
                              unsigned long bio_flags);
        int (*readpage_io_failed_hook)(struct page *page, int failed_mirror);
-       int (*readpage_end_io_hook)(struct page *page, u64 start, u64 end,
-                                   struct extent_state *state, int mirror);
+       int (*readpage_end_io_hook)(struct btrfs_io_bio *io_bio, u64 phy_offset,
+                                   struct page *page, u64 start, u64 end,
+                                   int mirror);
        int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end,
                                      struct extent_state *state, int uptodate);
        void (*set_bit_hook)(struct inode *inode, struct extent_state *state,
@@ -200,6 +200,8 @@ int unlock_extent_cached(struct extent_io_tree *tree, u64 start, u64 end,
 int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end);
 int extent_read_full_page(struct extent_io_tree *tree, struct page *page,
                          get_extent_t *get_extent, int mirror_num);
+int extent_read_full_page_nolock(struct extent_io_tree *tree, struct page *page,
+                                get_extent_t *get_extent, int mirror_num);
 int __init extent_io_init(void);
 void extent_io_exit(void);
 
@@ -261,11 +263,6 @@ int extent_readpages(struct extent_io_tree *tree,
                     get_extent_t get_extent);
 int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                __u64 start, __u64 len, get_extent_t *get_extent);
-int set_state_private(struct extent_io_tree *tree, u64 start, u64 private);
-void extent_cache_csums_dio(struct extent_io_tree *tree, u64 start, u32 csums[],
-                           int count);
-void extent_cache_csums(struct extent_io_tree *tree, struct bio *bio,
-                       int bvec_index, u32 csums[], int count);
 int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
 void set_page_extent_mapped(struct page *page);
 
@@ -330,10 +327,10 @@ int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset,
                      unsigned long *map_len);
 int extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end);
 int extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end);
-int extent_clear_unlock_delalloc(struct inode *inode,
-                               struct extent_io_tree *tree,
-                               u64 start, u64 end, struct page *locked_page,
-                               unsigned long op);
+int extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end,
+                                struct page *locked_page,
+                                unsigned long bits_to_clear,
+                                unsigned long page_ops);
 struct bio *
 btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
                gfp_t gfp_flags);
index a7bfc954180336348273f8e8f0f145b40581012e..4f53159bdb9d4fd9d4421cab7399abe562467bc8 100644 (file)
@@ -23,6 +23,7 @@
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "volumes.h"
 #include "print-tree.h"
 
 #define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \
@@ -152,28 +153,54 @@ int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err)
+{
+       kfree(bio->csum_allocated);
+}
+
 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[16];
-       int len;
        struct bio_vec *bvec = bio->bi_io_vec;
-       int bio_index = 0;
+       struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio);
+       struct btrfs_csum_item *item = NULL;
+       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct btrfs_path *path;
+       u8 *csum;
        u64 offset = 0;
        u64 item_start_offset = 0;
        u64 item_last_offset = 0;
        u64 disk_bytenr;
        u32 diff;
-       u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
+       int nblocks;
+       int bio_index = 0;
        int count;
-       struct btrfs_path *path;
-       struct btrfs_csum_item *item = NULL;
-       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
+
+       nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits;
+       if (!dst) {
+               if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
+                       btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size,
+                                                           GFP_NOFS);
+                       if (!btrfs_bio->csum_allocated) {
+                               btrfs_free_path(path);
+                               return -ENOMEM;
+                       }
+                       btrfs_bio->csum = btrfs_bio->csum_allocated;
+                       btrfs_bio->end_io = btrfs_io_bio_endio_readpage;
+               } else {
+                       btrfs_bio->csum = btrfs_bio->csum_inline;
+               }
+               csum = btrfs_bio->csum;
+       } else {
+               csum = (u8 *)dst;
+       }
+
        if (bio->bi_size > PAGE_CACHE_SIZE * 8)
                path->reada = 2;
 
@@ -194,11 +221,10 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
        if (dio)
                offset = logical_offset;
        while (bio_index < bio->bi_vcnt) {
-               len = min_t(int, ARRAY_SIZE(sum), bio->bi_vcnt - bio_index);
                if (!dio)
                        offset = page_offset(bvec->bv_page) + bvec->bv_offset;
-               count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, sum,
-                                              len);
+               count = btrfs_find_ordered_sum(inode, offset, disk_bytenr,
+                                              (u32 *)csum, nblocks);
                if (count)
                        goto found;
 
@@ -213,7 +239,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                                 path, disk_bytenr, 0);
                        if (IS_ERR(item)) {
                                count = 1;
-                               sum[0] = 0;
+                               memset(csum, 0, csum_size);
                                if (BTRFS_I(inode)->root->root_key.objectid ==
                                    BTRFS_DATA_RELOC_TREE_OBJECTID) {
                                        set_extent_bits(io_tree, offset,
@@ -222,9 +248,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                } else {
                                        printk(KERN_INFO "btrfs no csum found "
                                               "for inode %llu start %llu\n",
-                                              (unsigned long long)
-                                              btrfs_ino(inode),
-                                              (unsigned long long)offset);
+                                              btrfs_ino(inode), offset);
                                }
                                item = NULL;
                                btrfs_release_path(path);
@@ -249,23 +273,14 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                diff = disk_bytenr - item_start_offset;
                diff = diff / root->sectorsize;
                diff = diff * csum_size;
-               count = min_t(int, len, (item_last_offset - disk_bytenr) >>
-                                       inode->i_sb->s_blocksize_bits);
-               read_extent_buffer(path->nodes[0], sum,
+               count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >>
+                                           inode->i_sb->s_blocksize_bits);
+               read_extent_buffer(path->nodes[0], csum,
                                   ((unsigned long)item) + diff,
                                   csum_size * count);
 found:
-               if (dst) {
-                       memcpy(dst, sum, count * csum_size);
-                       dst += count;
-               } else {
-                       if (dio)
-                               extent_cache_csums_dio(io_tree, offset, sum,
-                                                      count);
-                       else
-                               extent_cache_csums(io_tree, bio, bio_index, sum,
-                                           count);
-               }
+               csum += count * csum_size;
+               nblocks -= count;
                while (count--) {
                        disk_bytenr += bvec->bv_len;
                        offset += bvec->bv_len;
@@ -284,9 +299,19 @@ int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode,
 }
 
 int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
-                             struct bio *bio, u64 offset)
+                             struct btrfs_dio_private *dip, struct bio *bio,
+                             u64 offset)
 {
-       return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1);
+       int len = (bio->bi_sector << 9) - dip->disk_bytenr;
+       u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
+       int ret;
+
+       len >>= inode->i_sb->s_blocksize_bits;
+       len *= csum_size;
+
+       ret = __btrfs_lookup_bio_sums(root, inode, bio, offset,
+                                     (u32 *)(dip->csum + len), 1);
+       return ret;
 }
 
 int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end,
index 4d2eb6417145964c8731bf5e56673a0e816d59aa..bc5072b2db537f0f27af1851532b7417b41a8489 100644 (file)
@@ -1334,7 +1334,6 @@ fail:
 static noinline int check_can_nocow(struct inode *inode, loff_t pos,
                                    size_t *write_bytes)
 {
-       struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_ordered_extent *ordered;
        u64 lockstart, lockend;
@@ -1356,16 +1355,8 @@ static noinline int check_can_nocow(struct inode *inode, loff_t pos,
                btrfs_put_ordered_extent(ordered);
        }
 
-       trans = btrfs_join_transaction(root);
-       if (IS_ERR(trans)) {
-               unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend);
-               return PTR_ERR(trans);
-       }
-
        num_bytes = lockend - lockstart + 1;
-       ret = can_nocow_extent(trans, inode, lockstart, &num_bytes, NULL, NULL,
-                              NULL);
-       btrfs_end_transaction(trans, root);
+       ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, NULL, NULL);
        if (ret <= 0) {
                ret = 0;
        } else {
index b21a3cd667d8cc656878b8d462aa7cd45ebc8435..3f0ddfce96e6ff2bdaaef019ea7ee00f9af070af 100644 (file)
@@ -221,12 +221,10 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
                                    struct btrfs_path *path,
                                    struct inode *inode)
 {
-       loff_t oldsize;
        int ret = 0;
 
-       oldsize = i_size_read(inode);
        btrfs_i_size_write(inode, 0);
-       truncate_pagecache(inode, oldsize, 0);
+       truncate_pagecache(inode, 0);
 
        /*
         * We don't need an orphan item because truncating the free space cache
@@ -308,7 +306,7 @@ static void io_ctl_unmap_page(struct io_ctl *io_ctl)
 
 static void io_ctl_map_page(struct io_ctl *io_ctl, int clear)
 {
-       BUG_ON(io_ctl->index >= io_ctl->num_pages);
+       ASSERT(io_ctl->index < io_ctl->num_pages);
        io_ctl->page = io_ctl->pages[io_ctl->index++];
        io_ctl->cur = kmap(io_ctl->page);
        io_ctl->orig = io_ctl->cur;
@@ -673,8 +671,7 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
                btrfs_err(root->fs_info,
                        "free space inode generation (%llu) "
                        "did not match free space cache generation (%llu)",
-                       (unsigned long long)BTRFS_I(inode)->generation,
-                       (unsigned long long)generation);
+                       BTRFS_I(inode)->generation, generation);
                return 0;
        }
 
@@ -729,7 +726,7 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
                                goto free_cache;
                        }
                } else {
-                       BUG_ON(!num_bitmaps);
+                       ASSERT(num_bitmaps);
                        num_bitmaps--;
                        e->bitmap = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
                        if (!e->bitmap) {
@@ -1029,7 +1026,7 @@ static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode,
        leaf = path->nodes[0];
        if (ret > 0) {
                struct btrfs_key found_key;
-               BUG_ON(!path->slots[0]);
+               ASSERT(path->slots[0]);
                path->slots[0]--;
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
                if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID ||
@@ -1117,7 +1114,7 @@ int btrfs_write_out_cache(struct btrfs_root *root,
 static inline unsigned long offset_to_bit(u64 bitmap_start, u32 unit,
                                          u64 offset)
 {
-       BUG_ON(offset < bitmap_start);
+       ASSERT(offset >= bitmap_start);
        offset -= bitmap_start;
        return (unsigned long)(div_u64(offset, unit));
 }
@@ -1272,7 +1269,7 @@ tree_search_offset(struct btrfs_free_space_ctl *ctl,
                if (n) {
                        entry = rb_entry(n, struct btrfs_free_space,
                                        offset_index);
-                       BUG_ON(entry->offset > offset);
+                       ASSERT(entry->offset <= offset);
                } else {
                        if (fuzzy)
                                return entry;
@@ -1336,7 +1333,7 @@ static int link_free_space(struct btrfs_free_space_ctl *ctl,
 {
        int ret = 0;
 
-       BUG_ON(!info->bitmap && !info->bytes);
+       ASSERT(info->bytes || info->bitmap);
        ret = tree_insert_offset(&ctl->free_space_offset, info->offset,
                                 &info->offset_index, (info->bitmap != NULL));
        if (ret)
@@ -1359,7 +1356,7 @@ static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl)
 
        max_bitmaps = max(max_bitmaps, 1);
 
-       BUG_ON(ctl->total_bitmaps > max_bitmaps);
+       ASSERT(ctl->total_bitmaps <= max_bitmaps);
 
        /*
         * The goal is to keep the total amount of memory used per 1gb of space
@@ -1403,7 +1400,7 @@ static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl,
 
        start = offset_to_bit(info->offset, ctl->unit, offset);
        count = bytes_to_bits(bytes, ctl->unit);
-       BUG_ON(start + count > BITS_PER_BITMAP);
+       ASSERT(start + count <= BITS_PER_BITMAP);
 
        bitmap_clear(info->bitmap, start, count);
 
@@ -1426,7 +1423,7 @@ static void bitmap_set_bits(struct btrfs_free_space_ctl *ctl,
 
        start = offset_to_bit(info->offset, ctl->unit, offset);
        count = bytes_to_bits(bytes, ctl->unit);
-       BUG_ON(start + count > BITS_PER_BITMAP);
+       ASSERT(start + count <= BITS_PER_BITMAP);
 
        bitmap_set(info->bitmap, start, count);
 
@@ -1742,7 +1739,7 @@ no_cluster_bitmap:
        bitmap_info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
                                         1, 0);
        if (!bitmap_info) {
-               BUG_ON(added);
+               ASSERT(added == 0);
                goto new_bitmap;
        }
 
@@ -1882,7 +1879,7 @@ out:
 
        if (ret) {
                printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret);
-               BUG_ON(ret == -EEXIST);
+               ASSERT(ret != -EEXIST);
        }
 
        return ret;
@@ -1991,8 +1988,7 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                if (info->bytes >= bytes && !block_group->ro)
                        count++;
                printk(KERN_CRIT "entry offset %llu, bytes %llu, bitmap %s\n",
-                      (unsigned long long)info->offset,
-                      (unsigned long long)info->bytes,
+                      info->offset, info->bytes,
                       (info->bitmap) ? "yes" : "no");
        }
        printk(KERN_INFO "block group has cluster?: %s\n",
@@ -2371,7 +2367,7 @@ again:
        rb_erase(&entry->offset_index, &ctl->free_space_offset);
        ret = tree_insert_offset(&cluster->root, entry->offset,
                                 &entry->offset_index, 1);
-       BUG_ON(ret); /* -EEXIST; Logic error */
+       ASSERT(!ret); /* -EEXIST; Logic error */
 
        trace_btrfs_setup_cluster(block_group, cluster,
                                  total_found * ctl->unit, 1);
@@ -2464,7 +2460,7 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                ret = tree_insert_offset(&cluster->root, entry->offset,
                                         &entry->offset_index, 0);
                total_size += entry->bytes;
-               BUG_ON(ret); /* -EEXIST; Logic error */
+               ASSERT(!ret); /* -EEXIST; Logic error */
        } while (node && entry != last);
 
        cluster->max_size = max_extent;
@@ -2525,8 +2521,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
  * returns zero and sets up cluster if things worked out, otherwise
  * it returns -enospc
  */
-int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *root,
+int btrfs_find_space_cluster(struct btrfs_root *root,
                             struct btrfs_block_group_cache *block_group,
                             struct btrfs_free_cluster *cluster,
                             u64 offset, u64 bytes, u64 empty_size)
@@ -2856,7 +2851,7 @@ u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root)
 
                ret = search_bitmap(ctl, entry, &offset, &count);
                /* Logic error; Should be empty if it can't find anything */
-               BUG_ON(ret);
+               ASSERT(!ret);
 
                ino = offset;
                bitmap_clear_bits(ctl, entry, offset, 1);
@@ -2973,33 +2968,68 @@ int btrfs_write_out_ino_cache(struct btrfs_root *root,
 }
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
-static struct btrfs_block_group_cache *init_test_block_group(void)
+/*
+ * Use this if you need to make a bitmap or extent entry specifically, it
+ * doesn't do any of the merging that add_free_space does, this acts a lot like
+ * how the free space cache loading stuff works, so you can get really weird
+ * configurations.
+ */
+int test_add_free_space_entry(struct btrfs_block_group_cache *cache,
+                             u64 offset, u64 bytes, bool bitmap)
 {
-       struct btrfs_block_group_cache *cache;
+       struct btrfs_free_space_ctl *ctl = cache->free_space_ctl;
+       struct btrfs_free_space *info = NULL, *bitmap_info;
+       void *map = NULL;
+       u64 bytes_added;
+       int ret;
 
-       cache = kzalloc(sizeof(*cache), GFP_NOFS);
-       if (!cache)
-               return NULL;
-       cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
-                                       GFP_NOFS);
-       if (!cache->free_space_ctl) {
-               kfree(cache);
-               return NULL;
+again:
+       if (!info) {
+               info = kmem_cache_zalloc(btrfs_free_space_cachep, GFP_NOFS);
+               if (!info)
+                       return -ENOMEM;
        }
 
-       cache->key.objectid = 0;
-       cache->key.offset = 1024 * 1024 * 1024;
-       cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
-       cache->sectorsize = 4096;
+       if (!bitmap) {
+               spin_lock(&ctl->tree_lock);
+               info->offset = offset;
+               info->bytes = bytes;
+               ret = link_free_space(ctl, info);
+               spin_unlock(&ctl->tree_lock);
+               if (ret)
+                       kmem_cache_free(btrfs_free_space_cachep, info);
+               return ret;
+       }
+
+       if (!map) {
+               map = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
+               if (!map) {
+                       kmem_cache_free(btrfs_free_space_cachep, info);
+                       return -ENOMEM;
+               }
+       }
+
+       spin_lock(&ctl->tree_lock);
+       bitmap_info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
+                                        1, 0);
+       if (!bitmap_info) {
+               info->bitmap = map;
+               map = NULL;
+               add_new_bitmap(ctl, info, offset);
+               bitmap_info = info;
+       }
 
-       spin_lock_init(&cache->lock);
-       INIT_LIST_HEAD(&cache->list);
-       INIT_LIST_HEAD(&cache->cluster_list);
-       INIT_LIST_HEAD(&cache->new_bg_list);
+       bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes);
+       bytes -= bytes_added;
+       offset += bytes_added;
+       spin_unlock(&ctl->tree_lock);
 
-       btrfs_init_free_space_ctl(cache);
+       if (bytes)
+               goto again;
 
-       return cache;
+       if (map)
+               kfree(map);
+       return 0;
 }
 
 /*
@@ -3007,8 +3037,8 @@ static struct btrfs_block_group_cache *init_test_block_group(void)
  * just used to check the absence of space, so if there is free space in the
  * range at all we will return 1.
  */
-static int check_exists(struct btrfs_block_group_cache *cache, u64 offset,
-                       u64 bytes)
+int test_check_exists(struct btrfs_block_group_cache *cache,
+                     u64 offset, u64 bytes)
 {
        struct btrfs_free_space_ctl *ctl = cache->free_space_ctl;
        struct btrfs_free_space *info;
@@ -3085,411 +3115,4 @@ out:
        spin_unlock(&ctl->tree_lock);
        return ret;
 }
-
-/*
- * Use this if you need to make a bitmap or extent entry specifically, it
- * doesn't do any of the merging that add_free_space does, this acts a lot like
- * how the free space cache loading stuff works, so you can get really weird
- * configurations.
- */
-static int add_free_space_entry(struct btrfs_block_group_cache *cache,
-                               u64 offset, u64 bytes, bool bitmap)
-{
-       struct btrfs_free_space_ctl *ctl = cache->free_space_ctl;
-       struct btrfs_free_space *info = NULL, *bitmap_info;
-       void *map = NULL;
-       u64 bytes_added;
-       int ret;
-
-again:
-       if (!info) {
-               info = kmem_cache_zalloc(btrfs_free_space_cachep, GFP_NOFS);
-               if (!info)
-                       return -ENOMEM;
-       }
-
-       if (!bitmap) {
-               spin_lock(&ctl->tree_lock);
-               info->offset = offset;
-               info->bytes = bytes;
-               ret = link_free_space(ctl, info);
-               spin_unlock(&ctl->tree_lock);
-               if (ret)
-                       kmem_cache_free(btrfs_free_space_cachep, info);
-               return ret;
-       }
-
-       if (!map) {
-               map = kzalloc(PAGE_CACHE_SIZE, GFP_NOFS);
-               if (!map) {
-                       kmem_cache_free(btrfs_free_space_cachep, info);
-                       return -ENOMEM;
-               }
-       }
-
-       spin_lock(&ctl->tree_lock);
-       bitmap_info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset),
-                                        1, 0);
-       if (!bitmap_info) {
-               info->bitmap = map;
-               map = NULL;
-               add_new_bitmap(ctl, info, offset);
-               bitmap_info = info;
-       }
-
-       bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes);
-       bytes -= bytes_added;
-       offset += bytes_added;
-       spin_unlock(&ctl->tree_lock);
-
-       if (bytes)
-               goto again;
-
-       if (map)
-               kfree(map);
-       return 0;
-}
-
-#define test_msg(fmt, ...) printk(KERN_INFO "btrfs: selftest: " fmt, ##__VA_ARGS__)
-
-/*
- * This test just does basic sanity checking, making sure we can add an exten
- * entry and remove space from either end and the middle, and make sure we can
- * remove space that covers adjacent extent entries.
- */
-static int test_extents(struct btrfs_block_group_cache *cache)
-{
-       int ret = 0;
-
-       test_msg("Running extent only tests\n");
-
-       /* First just make sure we can remove an entire entry */
-       ret = btrfs_add_free_space(cache, 0, 4 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error adding initial extents %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 0, 4 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error removing extent %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 0, 4 * 1024 * 1024)) {
-               test_msg("Full remove left some lingering space\n");
-               return -1;
-       }
-
-       /* Ok edge and middle cases now */
-       ret = btrfs_add_free_space(cache, 0, 4 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error adding half extent %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 3 * 1024 * 1024, 1 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error removing tail end %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 0, 1 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error removing front end %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 2 * 1024 * 1024, 4096);
-       if (ret) {
-               test_msg("Error removing middle piece %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 0, 1 * 1024 * 1024)) {
-               test_msg("Still have space at the front\n");
-               return -1;
-       }
-
-       if (check_exists(cache, 2 * 1024 * 1024, 4096)) {
-               test_msg("Still have space in the middle\n");
-               return -1;
-       }
-
-       if (check_exists(cache, 3 * 1024 * 1024, 1 * 1024 * 1024)) {
-               test_msg("Still have space at the end\n");
-               return -1;
-       }
-
-       /* Cleanup */
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-
-       return 0;
-}
-
-static int test_bitmaps(struct btrfs_block_group_cache *cache)
-{
-       u64 next_bitmap_offset;
-       int ret;
-
-       test_msg("Running bitmap only tests\n");
-
-       ret = add_free_space_entry(cache, 0, 4 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't create a bitmap entry %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 0, 4 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error removing bitmap full range %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 0, 4 * 1024 * 1024)) {
-               test_msg("Left some space in bitmap\n");
-               return -1;
-       }
-
-       ret = add_free_space_entry(cache, 0, 4 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't add to our bitmap entry %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 1 * 1024 * 1024, 2 * 1024 * 1024);
-       if (ret) {
-               test_msg("Couldn't remove middle chunk %d\n", ret);
-               return ret;
-       }
-
-       /*
-        * The first bitmap we have starts at offset 0 so the next one is just
-        * at the end of the first bitmap.
-        */
-       next_bitmap_offset = (u64)(BITS_PER_BITMAP * 4096);
-
-       /* Test a bit straddling two bitmaps */
-       ret = add_free_space_entry(cache, next_bitmap_offset -
-                                  (2 * 1024 * 1024), 4 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't add space that straddles two bitmaps %d\n",
-                               ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, next_bitmap_offset -
-                                     (1 * 1024 * 1024), 2 * 1024 * 1024);
-       if (ret) {
-               test_msg("Couldn't remove overlapping space %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, next_bitmap_offset - (1 * 1024 * 1024),
-                        2 * 1024 * 1024)) {
-               test_msg("Left some space when removing overlapping\n");
-               return -1;
-       }
-
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-
-       return 0;
-}
-
-/* This is the high grade jackassery */
-static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
-{
-       u64 bitmap_offset = (u64)(BITS_PER_BITMAP * 4096);
-       int ret;
-
-       test_msg("Running bitmap and extent tests\n");
-
-       /*
-        * First let's do something simple, an extent at the same offset as the
-        * bitmap, but the free space completely in the extent and then
-        * completely in the bitmap.
-        */
-       ret = add_free_space_entry(cache, 4 * 1024 * 1024, 1 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't create bitmap entry %d\n", ret);
-               return ret;
-       }
-
-       ret = add_free_space_entry(cache, 0, 1 * 1024 * 1024, 0);
-       if (ret) {
-               test_msg("Couldn't add extent entry %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 0, 1 * 1024 * 1024);
-       if (ret) {
-               test_msg("Couldn't remove extent entry %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 0, 1 * 1024 * 1024)) {
-               test_msg("Left remnants after our remove\n");
-               return -1;
-       }
-
-       /* Now to add back the extent entry and remove from the bitmap */
-       ret = add_free_space_entry(cache, 0, 1 * 1024 * 1024, 0);
-       if (ret) {
-               test_msg("Couldn't re-add extent entry %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 4 * 1024 * 1024, 1 * 1024 * 1024);
-       if (ret) {
-               test_msg("Couldn't remove from bitmap %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 4 * 1024 * 1024, 1 * 1024 * 1024)) {
-               test_msg("Left remnants in the bitmap\n");
-               return -1;
-       }
-
-       /*
-        * Ok so a little more evil, extent entry and bitmap at the same offset,
-        * removing an overlapping chunk.
-        */
-       ret = add_free_space_entry(cache, 1 * 1024 * 1024, 4 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't add to a bitmap %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 512 * 1024, 3 * 1024 * 1024);
-       if (ret) {
-               test_msg("Couldn't remove overlapping space %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 512 * 1024, 3 * 1024 * 1024)) {
-               test_msg("Left over peices after removing overlapping\n");
-               return -1;
-       }
-
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-
-       /* Now with the extent entry offset into the bitmap */
-       ret = add_free_space_entry(cache, 4 * 1024 * 1024, 4 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't add space to the bitmap %d\n", ret);
-               return ret;
-       }
-
-       ret = add_free_space_entry(cache, 2 * 1024 * 1024, 2 * 1024 * 1024, 0);
-       if (ret) {
-               test_msg("Couldn't add extent to the cache %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 3 * 1024 * 1024, 4 * 1024 * 1024);
-       if (ret) {
-               test_msg("Problem removing overlapping space %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, 3 * 1024 * 1024, 4 * 1024 * 1024)) {
-               test_msg("Left something behind when removing space");
-               return -1;
-       }
-
-       /*
-        * This has blown up in the past, the extent entry starts before the
-        * bitmap entry, but we're trying to remove an offset that falls
-        * completely within the bitmap range and is in both the extent entry
-        * and the bitmap entry, looks like this
-        *
-        *   [ extent ]
-        *      [ bitmap ]
-        *        [ del ]
-        */
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-       ret = add_free_space_entry(cache, bitmap_offset + 4 * 1024 * 1024,
-                                  4 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't add bitmap %d\n", ret);
-               return ret;
-       }
-
-       ret = add_free_space_entry(cache, bitmap_offset - 1 * 1024 * 1024,
-                                  5 * 1024 * 1024, 0);
-       if (ret) {
-               test_msg("Couldn't add extent entry %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, bitmap_offset + 1 * 1024 * 1024,
-                                     5 * 1024 * 1024);
-       if (ret) {
-               test_msg("Failed to free our space %d\n", ret);
-               return ret;
-       }
-
-       if (check_exists(cache, bitmap_offset + 1 * 1024 * 1024,
-                        5 * 1024 * 1024)) {
-               test_msg("Left stuff over\n");
-               return -1;
-       }
-
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-
-       /*
-        * This blew up before, we have part of the free space in a bitmap and
-        * then the entirety of the rest of the space in an extent.  This used
-        * to return -EAGAIN back from btrfs_remove_extent, make sure this
-        * doesn't happen.
-        */
-       ret = add_free_space_entry(cache, 1 * 1024 * 1024, 2 * 1024 * 1024, 1);
-       if (ret) {
-               test_msg("Couldn't add bitmap entry %d\n", ret);
-               return ret;
-       }
-
-       ret = add_free_space_entry(cache, 3 * 1024 * 1024, 1 * 1024 * 1024, 0);
-       if (ret) {
-               test_msg("Couldn't add extent entry %d\n", ret);
-               return ret;
-       }
-
-       ret = btrfs_remove_free_space(cache, 1 * 1024 * 1024, 3 * 1024 * 1024);
-       if (ret) {
-               test_msg("Error removing bitmap and extent overlapping %d\n", ret);
-               return ret;
-       }
-
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-       return 0;
-}
-
-void btrfs_test_free_space_cache(void)
-{
-       struct btrfs_block_group_cache *cache;
-
-       test_msg("Running btrfs free space cache tests\n");
-
-       cache = init_test_block_group();
-       if (!cache) {
-               test_msg("Couldn't run the tests\n");
-               return;
-       }
-
-       if (test_extents(cache))
-               goto out;
-       if (test_bitmaps(cache))
-               goto out;
-       if (test_bitmaps_and_extents(cache))
-               goto out;
-out:
-       __btrfs_remove_free_space_cache(cache->free_space_ctl);
-       kfree(cache->free_space_ctl);
-       kfree(cache);
-       test_msg("Free space cache tests finished\n");
-}
-#undef test_msg
-#else /* !CONFIG_BTRFS_FS_RUN_SANITY_TESTS */
-void btrfs_test_free_space_cache(void) {}
-#endif /* !CONFIG_BTRFS_FS_RUN_SANITY_TESTS */
+#endif /* CONFIG_BTRFS_FS_RUN_SANITY_TESTS */
index 894116b71304c391aca53d31e4f063913952a6e6..c7490416747656e1f3f119c5dc4f91cbf315e2ca 100644 (file)
@@ -98,8 +98,7 @@ u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group,
 u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root);
 void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                           u64 bytes);
-int btrfs_find_space_cluster(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *root,
+int btrfs_find_space_cluster(struct btrfs_root *root,
                             struct btrfs_block_group_cache *block_group,
                             struct btrfs_free_cluster *cluster,
                             u64 offset, u64 bytes, u64 empty_size);
@@ -113,6 +112,12 @@ int btrfs_return_cluster_to_free_space(
 int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group,
                           u64 *trimmed, u64 start, u64 end, u64 minlen);
 
-void btrfs_test_free_space_cache(void);
+/* Support functions for runnint our sanity tests */
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+int test_add_free_space_entry(struct btrfs_block_group_cache *cache,
+                             u64 offset, u64 bytes, bool bitmap);
+int test_check_exists(struct btrfs_block_group_cache *cache,
+                     u64 offset, u64 bytes);
+#endif
 
 #endif
index 7bdc83d04d54ca36006ae54e221092f2d789ef0c..f338c5672d583a27dddc37c5e217fa6a8995e271 100644 (file)
@@ -230,12 +230,13 @@ fail:
  * does the checks required to make sure the data is small enough
  * to fit as an inline extent.
  */
-static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
-                                struct btrfs_root *root,
-                                struct inode *inode, u64 start, u64 end,
-                                size_t compressed_size, int compress_type,
-                                struct page **compressed_pages)
+static noinline int cow_file_range_inline(struct btrfs_root *root,
+                                         struct inode *inode, u64 start,
+                                         u64 end, size_t compressed_size,
+                                         int compress_type,
+                                         struct page **compressed_pages)
 {
+       struct btrfs_trans_handle *trans;
        u64 isize = i_size_read(inode);
        u64 actual_end = min(end + 1, isize);
        u64 inline_len = actual_end - start;
@@ -256,9 +257,16 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
                return 1;
        }
 
+       trans = btrfs_join_transaction(root);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
+
        ret = btrfs_drop_extents(trans, root, inode, start, aligned_end, 1);
-       if (ret)
-               return ret;
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out;
+       }
 
        if (isize > actual_end)
                inline_len = min_t(u64, isize, actual_end);
@@ -267,15 +275,18 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
                                   compress_type, compressed_pages);
        if (ret && ret != -ENOSPC) {
                btrfs_abort_transaction(trans, root, ret);
-               return ret;
+               goto out;
        } else if (ret == -ENOSPC) {
-               return 1;
+               ret = 1;
+               goto out;
        }
 
        set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
        btrfs_delalloc_release_metadata(inode, end + 1 - start);
        btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
-       return 0;
+out:
+       btrfs_end_transaction(trans, root);
+       return ret;
 }
 
 struct async_extent {
@@ -343,7 +354,6 @@ static noinline int compress_file_range(struct inode *inode,
                                        int *num_added)
 {
        struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct btrfs_trans_handle *trans;
        u64 num_bytes;
        u64 blocksize = root->sectorsize;
        u64 actual_end;
@@ -461,45 +471,36 @@ again:
        }
 cont:
        if (start == 0) {
-               trans = btrfs_join_transaction(root);
-               if (IS_ERR(trans)) {
-                       ret = PTR_ERR(trans);
-                       trans = NULL;
-                       goto cleanup_and_out;
-               }
-               trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-
                /* lets try to make an inline extent */
                if (ret || total_in < (actual_end - start)) {
                        /* we didn't compress the entire range, try
                         * to make an uncompressed inline extent.
                         */
-                       ret = cow_file_range_inline(trans, root, inode,
-                                                   start, end, 0, 0, NULL);
+                       ret = cow_file_range_inline(root, inode, start, end,
+                                                   0, 0, NULL);
                } else {
                        /* try making a compressed inline extent */
-                       ret = cow_file_range_inline(trans, root, inode,
-                                                   start, end,
+                       ret = cow_file_range_inline(root, inode, start, end,
                                                    total_compressed,
                                                    compress_type, pages);
                }
                if (ret <= 0) {
+                       unsigned long clear_flags = EXTENT_DELALLOC |
+                               EXTENT_DEFRAG;
+                       clear_flags |= (ret < 0) ? EXTENT_DO_ACCOUNTING : 0;
+
                        /*
                         * inline extent creation worked or returned error,
                         * we don't need to create any more async work items.
                         * Unlock and free up our temp pages.
                         */
-                       extent_clear_unlock_delalloc(inode,
-                            &BTRFS_I(inode)->io_tree,
-                            start, end, NULL,
-                            EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
-                            EXTENT_CLEAR_DELALLOC |
-                            EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK);
-
-                       btrfs_end_transaction(trans, root);
+                       extent_clear_unlock_delalloc(inode, start, end, NULL,
+                                                    clear_flags, PAGE_UNLOCK |
+                                                    PAGE_CLEAR_DIRTY |
+                                                    PAGE_SET_WRITEBACK |
+                                                    PAGE_END_WRITEBACK);
                        goto free_pages_out;
                }
-               btrfs_end_transaction(trans, root);
        }
 
        if (will_compress) {
@@ -590,20 +591,6 @@ free_pages_out:
        kfree(pages);
 
        goto out;
-
-cleanup_and_out:
-       extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
-                                    start, end, NULL,
-                                    EXTENT_CLEAR_UNLOCK_PAGE |
-                                    EXTENT_CLEAR_DIRTY |
-                                    EXTENT_CLEAR_DELALLOC |
-                                    EXTENT_SET_WRITEBACK |
-                                    EXTENT_END_WRITEBACK);
-       if (!trans || IS_ERR(trans))
-               btrfs_error(root->fs_info, ret, "Failed to join transaction");
-       else
-               btrfs_abort_transaction(trans, root, ret);
-       goto free_pages_out;
 }
 
 /*
@@ -617,7 +604,6 @@ static noinline int submit_compressed_extents(struct inode *inode,
 {
        struct async_extent *async_extent;
        u64 alloc_hint = 0;
-       struct btrfs_trans_handle *trans;
        struct btrfs_key ins;
        struct extent_map *em;
        struct btrfs_root *root = BTRFS_I(inode)->root;
@@ -678,20 +664,10 @@ retry:
                lock_extent(io_tree, async_extent->start,
                            async_extent->start + async_extent->ram_size - 1);
 
-               trans = btrfs_join_transaction(root);
-               if (IS_ERR(trans)) {
-                       ret = PTR_ERR(trans);
-               } else {
-                       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-                       ret = btrfs_reserve_extent(trans, root,
+               ret = btrfs_reserve_extent(root,
                                           async_extent->compressed_size,
                                           async_extent->compressed_size,
                                           0, alloc_hint, &ins, 1);
-                       if (ret && ret != -ENOSPC)
-                               btrfs_abort_transaction(trans, root, ret);
-                       btrfs_end_transaction(trans, root);
-               }
-
                if (ret) {
                        int i;
 
@@ -770,16 +746,12 @@ retry:
                /*
                 * clear dirty, set writeback and unlock the pages.
                 */
-               extent_clear_unlock_delalloc(inode,
-                               &BTRFS_I(inode)->io_tree,
-                               async_extent->start,
+               extent_clear_unlock_delalloc(inode, async_extent->start,
                                async_extent->start +
                                async_extent->ram_size - 1,
-                               NULL, EXTENT_CLEAR_UNLOCK_PAGE |
-                               EXTENT_CLEAR_UNLOCK |
-                               EXTENT_CLEAR_DELALLOC |
-                               EXTENT_CLEAR_DIRTY | EXTENT_SET_WRITEBACK);
-
+                               NULL, EXTENT_LOCKED | EXTENT_DELALLOC,
+                               PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
+                               PAGE_SET_WRITEBACK);
                ret = btrfs_submit_compressed_write(inode,
                                    async_extent->start,
                                    async_extent->ram_size,
@@ -798,16 +770,13 @@ out:
 out_free_reserve:
        btrfs_free_reserved_extent(root, ins.objectid, ins.offset);
 out_free:
-       extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
-                                    async_extent->start,
+       extent_clear_unlock_delalloc(inode, async_extent->start,
                                     async_extent->start +
                                     async_extent->ram_size - 1,
-                                    NULL, EXTENT_CLEAR_UNLOCK_PAGE |
-                                    EXTENT_CLEAR_UNLOCK |
-                                    EXTENT_CLEAR_DELALLOC |
-                                    EXTENT_CLEAR_DIRTY |
-                                    EXTENT_SET_WRITEBACK |
-                                    EXTENT_END_WRITEBACK);
+                                    NULL, EXTENT_LOCKED | EXTENT_DELALLOC |
+                                    EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING,
+                                    PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
+                                    PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK);
        kfree(async_extent);
        goto again;
 }
@@ -857,14 +826,13 @@ static u64 get_extent_allocation_hint(struct inode *inode, u64 start,
  * required to start IO on it.  It may be clean and already done with
  * IO when we return.
  */
-static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
-                                    struct inode *inode,
-                                    struct btrfs_root *root,
-                                    struct page *locked_page,
-                                    u64 start, u64 end, int *page_started,
-                                    unsigned long *nr_written,
-                                    int unlock)
+static noinline int cow_file_range(struct inode *inode,
+                                  struct page *locked_page,
+                                  u64 start, u64 end, int *page_started,
+                                  unsigned long *nr_written,
+                                  int unlock)
 {
+       struct btrfs_root *root = BTRFS_I(inode)->root;
        u64 alloc_hint = 0;
        u64 num_bytes;
        unsigned long ram_size;
@@ -885,29 +853,24 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
        /* if this is a small write inside eof, kick off defrag */
        if (num_bytes < 64 * 1024 &&
            (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size))
-               btrfs_add_inode_defrag(trans, inode);
+               btrfs_add_inode_defrag(NULL, inode);
 
        if (start == 0) {
                /* lets try to make an inline extent */
-               ret = cow_file_range_inline(trans, root, inode,
-                                           start, end, 0, 0, NULL);
+               ret = cow_file_range_inline(root, inode, start, end, 0, 0,
+                                           NULL);
                if (ret == 0) {
-                       extent_clear_unlock_delalloc(inode,
-                                    &BTRFS_I(inode)->io_tree,
-                                    start, end, NULL,
-                                    EXTENT_CLEAR_UNLOCK_PAGE |
-                                    EXTENT_CLEAR_UNLOCK |
-                                    EXTENT_CLEAR_DELALLOC |
-                                    EXTENT_CLEAR_DIRTY |
-                                    EXTENT_SET_WRITEBACK |
-                                    EXTENT_END_WRITEBACK);
+                       extent_clear_unlock_delalloc(inode, start, end, NULL,
+                                    EXTENT_LOCKED | EXTENT_DELALLOC |
+                                    EXTENT_DEFRAG, PAGE_UNLOCK |
+                                    PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK |
+                                    PAGE_END_WRITEBACK);
 
                        *nr_written = *nr_written +
                             (end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
                        *page_started = 1;
                        goto out;
                } else if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
                        goto out_unlock;
                }
        }
@@ -922,13 +885,11 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
                unsigned long op;
 
                cur_alloc_size = disk_num_bytes;
-               ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
+               ret = btrfs_reserve_extent(root, cur_alloc_size,
                                           root->sectorsize, 0, alloc_hint,
                                           &ins, 1);
-               if (ret < 0) {
-                       btrfs_abort_transaction(trans, root, ret);
+               if (ret < 0)
                        goto out_unlock;
-               }
 
                em = alloc_extent_map();
                if (!em) {
@@ -974,10 +935,8 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
                    BTRFS_DATA_RELOC_TREE_OBJECTID) {
                        ret = btrfs_reloc_clone_csums(inode, start,
                                                      cur_alloc_size);
-                       if (ret) {
-                               btrfs_abort_transaction(trans, root, ret);
+                       if (ret)
                                goto out_reserve;
-                       }
                }
 
                if (disk_num_bytes < cur_alloc_size)
@@ -990,13 +949,13 @@ static noinline int __cow_file_range(struct btrfs_trans_handle *trans,
                 * Do set the Private2 bit so we know this page was properly
                 * setup for writepage
                 */
-               op = unlock ? EXTENT_CLEAR_UNLOCK_PAGE : 0;
-               op |= EXTENT_CLEAR_UNLOCK | EXTENT_CLEAR_DELALLOC |
-                       EXTENT_SET_PRIVATE2;
+               op = unlock ? PAGE_UNLOCK : 0;
+               op |= PAGE_SET_PRIVATE2;
 
-               extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
-                                            start, start + ram_size - 1,
-                                            locked_page, op);
+               extent_clear_unlock_delalloc(inode, start,
+                                            start + ram_size - 1, locked_page,
+                                            EXTENT_LOCKED | EXTENT_DELALLOC,
+                                            op);
                disk_num_bytes -= cur_alloc_size;
                num_bytes -= cur_alloc_size;
                alloc_hint = ins.objectid + ins.offset;
@@ -1008,52 +967,14 @@ out:
 out_reserve:
        btrfs_free_reserved_extent(root, ins.objectid, ins.offset);
 out_unlock:
-       extent_clear_unlock_delalloc(inode,
-                    &BTRFS_I(inode)->io_tree,
-                    start, end, locked_page,
-                    EXTENT_CLEAR_UNLOCK_PAGE |
-                    EXTENT_CLEAR_UNLOCK |
-                    EXTENT_CLEAR_DELALLOC |
-                    EXTENT_CLEAR_DIRTY |
-                    EXTENT_SET_WRITEBACK |
-                    EXTENT_END_WRITEBACK);
-
+       extent_clear_unlock_delalloc(inode, start, end, locked_page,
+                                    EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
+                                    EXTENT_DELALLOC | EXTENT_DEFRAG,
+                                    PAGE_UNLOCK | PAGE_CLEAR_DIRTY |
+                                    PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK);
        goto out;
 }
 
-static noinline int cow_file_range(struct inode *inode,
-                                  struct page *locked_page,
-                                  u64 start, u64 end, int *page_started,
-                                  unsigned long *nr_written,
-                                  int unlock)
-{
-       struct btrfs_trans_handle *trans;
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       int ret;
-
-       trans = btrfs_join_transaction(root);
-       if (IS_ERR(trans)) {
-               extent_clear_unlock_delalloc(inode,
-                            &BTRFS_I(inode)->io_tree,
-                            start, end, locked_page,
-                            EXTENT_CLEAR_UNLOCK_PAGE |
-                            EXTENT_CLEAR_UNLOCK |
-                            EXTENT_CLEAR_DELALLOC |
-                            EXTENT_CLEAR_DIRTY |
-                            EXTENT_SET_WRITEBACK |
-                            EXTENT_END_WRITEBACK);
-               return PTR_ERR(trans);
-       }
-       trans->block_rsv = &root->fs_info->delalloc_block_rsv;
-
-       ret = __cow_file_range(trans, inode, root, locked_page, start, end,
-                              page_started, nr_written, unlock);
-
-       btrfs_end_transaction(trans, root);
-
-       return ret;
-}
-
 /*
  * work queue call back to started compression on a file and pages
  */
@@ -1221,15 +1142,13 @@ static noinline int run_delalloc_nocow(struct inode *inode,
 
        path = btrfs_alloc_path();
        if (!path) {
-               extent_clear_unlock_delalloc(inode,
-                            &BTRFS_I(inode)->io_tree,
-                            start, end, locked_page,
-                            EXTENT_CLEAR_UNLOCK_PAGE |
-                            EXTENT_CLEAR_UNLOCK |
-                            EXTENT_CLEAR_DELALLOC |
-                            EXTENT_CLEAR_DIRTY |
-                            EXTENT_SET_WRITEBACK |
-                            EXTENT_END_WRITEBACK);
+               extent_clear_unlock_delalloc(inode, start, end, locked_page,
+                                            EXTENT_LOCKED | EXTENT_DELALLOC |
+                                            EXTENT_DO_ACCOUNTING |
+                                            EXTENT_DEFRAG, PAGE_UNLOCK |
+                                            PAGE_CLEAR_DIRTY |
+                                            PAGE_SET_WRITEBACK |
+                                            PAGE_END_WRITEBACK);
                return -ENOMEM;
        }
 
@@ -1241,15 +1160,13 @@ static noinline int run_delalloc_nocow(struct inode *inode,
                trans = btrfs_join_transaction(root);
 
        if (IS_ERR(trans)) {
-               extent_clear_unlock_delalloc(inode,
-                            &BTRFS_I(inode)->io_tree,
-                            start, end, locked_page,
-                            EXTENT_CLEAR_UNLOCK_PAGE |
-                            EXTENT_CLEAR_UNLOCK |
-                            EXTENT_CLEAR_DELALLOC |
-                            EXTENT_CLEAR_DIRTY |
-                            EXTENT_SET_WRITEBACK |
-                            EXTENT_END_WRITEBACK);
+               extent_clear_unlock_delalloc(inode, start, end, locked_page,
+                                            EXTENT_LOCKED | EXTENT_DELALLOC |
+                                            EXTENT_DO_ACCOUNTING |
+                                            EXTENT_DEFRAG, PAGE_UNLOCK |
+                                            PAGE_CLEAR_DIRTY |
+                                            PAGE_SET_WRITEBACK |
+                                            PAGE_END_WRITEBACK);
                btrfs_free_path(path);
                return PTR_ERR(trans);
        }
@@ -1369,9 +1286,9 @@ out_check:
 
                btrfs_release_path(path);
                if (cow_start != (u64)-1) {
-                       ret = __cow_file_range(trans, inode, root, locked_page,
-                                              cow_start, found_key.offset - 1,
-                                              page_started, nr_written, 1);
+                       ret = cow_file_range(inode, locked_page,
+                                            cow_start, found_key.offset - 1,
+                                            page_started, nr_written, 1);
                        if (ret) {
                                btrfs_abort_transaction(trans, root, ret);
                                goto error;
@@ -1428,11 +1345,11 @@ out_check:
                        }
                }
 
-               extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
-                               cur_offset, cur_offset + num_bytes - 1,
-                               locked_page, EXTENT_CLEAR_UNLOCK_PAGE |
-                               EXTENT_CLEAR_UNLOCK | EXTENT_CLEAR_DELALLOC |
-                               EXTENT_SET_PRIVATE2);
+               extent_clear_unlock_delalloc(inode, cur_offset,
+                                            cur_offset + num_bytes - 1,
+                                            locked_page, EXTENT_LOCKED |
+                                            EXTENT_DELALLOC, PAGE_UNLOCK |
+                                            PAGE_SET_PRIVATE2);
                cur_offset = extent_end;
                if (cur_offset > end)
                        break;
@@ -1445,9 +1362,8 @@ out_check:
        }
 
        if (cow_start != (u64)-1) {
-               ret = __cow_file_range(trans, inode, root, locked_page,
-                                      cow_start, end,
-                                      page_started, nr_written, 1);
+               ret = cow_file_range(inode, locked_page, cow_start, end,
+                                    page_started, nr_written, 1);
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
                        goto error;
@@ -1460,16 +1376,13 @@ error:
                ret = err;
 
        if (ret && cur_offset < end)
-               extent_clear_unlock_delalloc(inode,
-                            &BTRFS_I(inode)->io_tree,
-                            cur_offset, end, locked_page,
-                            EXTENT_CLEAR_UNLOCK_PAGE |
-                            EXTENT_CLEAR_UNLOCK |
-                            EXTENT_CLEAR_DELALLOC |
-                            EXTENT_CLEAR_DIRTY |
-                            EXTENT_SET_WRITEBACK |
-                            EXTENT_END_WRITEBACK);
-
+               extent_clear_unlock_delalloc(inode, cur_offset, end,
+                                            locked_page, EXTENT_LOCKED |
+                                            EXTENT_DELALLOC | EXTENT_DEFRAG |
+                                            EXTENT_DO_ACCOUNTING, PAGE_UNLOCK |
+                                            PAGE_CLEAR_DIRTY |
+                                            PAGE_SET_WRITEBACK |
+                                            PAGE_END_WRITEBACK);
        btrfs_free_path(path);
        return ret;
 }
@@ -2132,6 +2045,7 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
                WARN_ON(1);
                return ret;
        }
+       ret = 0;
 
        while (1) {
                cond_resched();
@@ -2181,8 +2095,6 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
                    old->len || extent_offset + num_bytes <=
                    old->extent_offset + old->offset)
                        continue;
-
-               ret = 0;
                break;
        }
 
@@ -2238,16 +2150,18 @@ static noinline bool record_extent_backrefs(struct btrfs_path *path,
 
 static int relink_is_mergable(struct extent_buffer *leaf,
                              struct btrfs_file_extent_item *fi,
-                             u64 disk_bytenr)
+                             struct new_sa_defrag_extent *new)
 {
-       if (btrfs_file_extent_disk_bytenr(leaf, fi) != disk_bytenr)
+       if (btrfs_file_extent_disk_bytenr(leaf, fi) != new->bytenr)
                return 0;
 
        if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG)
                return 0;
 
-       if (btrfs_file_extent_compression(leaf, fi) ||
-           btrfs_file_extent_encryption(leaf, fi) ||
+       if (btrfs_file_extent_compression(leaf, fi) != new->compress_type)
+               return 0;
+
+       if (btrfs_file_extent_encryption(leaf, fi) ||
            btrfs_file_extent_other_encoding(leaf, fi))
                return 0;
 
@@ -2391,8 +2305,8 @@ again:
                                    struct btrfs_file_extent_item);
                extent_len = btrfs_file_extent_num_bytes(leaf, fi);
 
-               if (relink_is_mergable(leaf, fi, new->bytenr) &&
-                   extent_len + found_key.offset == start) {
+               if (extent_len + found_key.offset == start &&
+                   relink_is_mergable(leaf, fi, new)) {
                        btrfs_set_file_extent_num_bytes(leaf, fi,
                                                        extent_len + len);
                        btrfs_mark_buffer_dirty(leaf);
@@ -2648,8 +2562,10 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
        struct extent_state *cached_state = NULL;
        struct new_sa_defrag_extent *new = NULL;
        int compress_type = 0;
-       int ret;
+       int ret = 0;
+       u64 logical_len = ordered_extent->len;
        bool nolock;
+       bool truncated = false;
 
        nolock = btrfs_is_free_space_inode(inode);
 
@@ -2658,6 +2574,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                goto out;
        }
 
+       if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) {
+               truncated = true;
+               logical_len = ordered_extent->truncated_len;
+               /* Truncated the entire extent, don't bother adding */
+               if (!logical_len)
+                       goto out;
+       }
+
        if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) {
                BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */
                btrfs_ordered_update_i_size(inode, 0, ordered_extent);
@@ -2713,15 +2637,14 @@ static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent)
                ret = btrfs_mark_extent_written(trans, inode,
                                                ordered_extent->file_offset,
                                                ordered_extent->file_offset +
-                                               ordered_extent->len);
+                                               logical_len);
        } else {
                BUG_ON(root == root->fs_info->tree_root);
                ret = insert_reserved_file_extent(trans, inode,
                                                ordered_extent->file_offset,
                                                ordered_extent->start,
                                                ordered_extent->disk_len,
-                                               ordered_extent->len,
-                                               ordered_extent->len,
+                                               logical_len, logical_len,
                                                compress_type, 0, 0,
                                                BTRFS_FILE_EXTENT_REG);
        }
@@ -2753,17 +2676,27 @@ out:
        if (trans)
                btrfs_end_transaction(trans, root);
 
-       if (ret) {
-               clear_extent_uptodate(io_tree, ordered_extent->file_offset,
-                                     ordered_extent->file_offset +
-                                     ordered_extent->len - 1, NULL, GFP_NOFS);
+       if (ret || truncated) {
+               u64 start, end;
+
+               if (truncated)
+                       start = ordered_extent->file_offset + logical_len;
+               else
+                       start = ordered_extent->file_offset;
+               end = ordered_extent->file_offset + ordered_extent->len - 1;
+               clear_extent_uptodate(io_tree, start, end, NULL, GFP_NOFS);
+
+               /* Drop the cache for the part of the extent we didn't write. */
+               btrfs_drop_extent_cache(inode, start, end, 0);
 
                /*
                 * If the ordered extent had an IOERR or something else went
                 * wrong we need to return the space for this ordered extent
-                * back to the allocator.
+                * back to the allocator.  We only free the extent in the
+                * truncated case if we didn't write out the extent at all.
                 */
-               if (!test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) &&
+               if ((ret || !logical_len) &&
+                   !test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) &&
                    !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags))
                        btrfs_free_reserved_extent(root, ordered_extent->start,
                                                   ordered_extent->disk_len);
@@ -2827,16 +2760,16 @@ static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end,
  * if there's a match, we allow the bio to finish.  If not, the code in
  * extent_io.c will try to find good copies for us.
  */
-static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
-                              struct extent_state *state, int mirror)
+static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
+                                     u64 phy_offset, struct page *page,
+                                     u64 start, u64 end, int mirror)
 {
        size_t offset = start - page_offset(page);
        struct inode *inode = page->mapping->host;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        char *kaddr;
-       u64 private = ~(u32)0;
-       int ret;
        struct btrfs_root *root = BTRFS_I(inode)->root;
+       u32 csum_expected;
        u32 csum = ~(u32)0;
        static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
                                      DEFAULT_RATELIMIT_BURST);
@@ -2856,19 +2789,13 @@ static int btrfs_readpage_end_io_hook(struct page *page, u64 start, u64 end,
                return 0;
        }
 
-       if (state && state->start == start) {
-               private = state->private;
-               ret = 0;
-       } else {
-               ret = get_state_private(io_tree, start, &private);
-       }
-       kaddr = kmap_atomic(page);
-       if (ret)
-               goto zeroit;
+       phy_offset >>= inode->i_sb->s_blocksize_bits;
+       csum_expected = *(((u32 *)io_bio->csum) + phy_offset);
 
+       kaddr = kmap_atomic(page);
        csum = btrfs_csum_data(kaddr + offset, csum,  end - start + 1);
        btrfs_csum_final(csum, (char *)&csum);
-       if (csum != private)
+       if (csum != csum_expected)
                goto zeroit;
 
        kunmap_atomic(kaddr);
@@ -2877,14 +2804,12 @@ good:
 
 zeroit:
        if (__ratelimit(&_rs))
-               btrfs_info(root->fs_info, "csum failed ino %llu off %llu csum %u private %llu",
-                       (unsigned long long)btrfs_ino(page->mapping->host),
-                       (unsigned long long)start, csum,
-                       (unsigned long long)private);
+               btrfs_info(root->fs_info, "csum failed ino %llu off %llu csum %u expected csum %u",
+                       btrfs_ino(page->mapping->host), start, csum, csum_expected);
        memset(kaddr + offset, 1, end - start + 1);
        flush_dcache_page(page);
        kunmap_atomic(kaddr);
-       if (private == 0)
+       if (csum_expected == 0)
                return 0;
        return -EIO;
 }
@@ -2971,8 +2896,10 @@ void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans,
            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 (ret)
+                       btrfs_abort_transaction(trans, root, ret);
+               else
+                       root->orphan_item_inserted = 0;
        }
 
        if (block_rsv) {
@@ -3041,11 +2968,18 @@ int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode)
        /* insert an orphan item to track this unlinked/truncated file */
        if (insert >= 1) {
                ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode));
-               if (ret && ret != -EEXIST) {
-                       clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
-                                 &BTRFS_I(inode)->runtime_flags);
-                       btrfs_abort_transaction(trans, root, ret);
-                       return ret;
+               if (ret) {
+                       if (reserve) {
+                               clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED,
+                                         &BTRFS_I(inode)->runtime_flags);
+                               btrfs_orphan_release_metadata(inode);
+                       }
+                       if (ret != -EEXIST) {
+                               clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
+                                         &BTRFS_I(inode)->runtime_flags);
+                               btrfs_abort_transaction(trans, root, ret);
+                               return ret;
+                       }
                }
                ret = 0;
        }
@@ -3084,17 +3018,15 @@ static int btrfs_orphan_del(struct btrfs_trans_handle *trans,
                release_rsv = 1;
        spin_unlock(&root->orphan_lock);
 
-       if (trans && delete_item) {
+       if (trans && delete_item)
                ret = btrfs_del_orphan_item(trans, root, btrfs_ino(inode));
-               BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
-       }
 
        if (release_rsv) {
                btrfs_orphan_release_metadata(inode);
                atomic_dec(&root->orphan_inodes);
        }
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -3224,8 +3156,9 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
                                found_key.objectid);
                        ret = btrfs_del_orphan_item(trans, root,
                                                    found_key.objectid);
-                       BUG_ON(ret); /* -ENOMEM or corruption (JDM: Recheck) */
                        btrfs_end_transaction(trans, root);
+                       if (ret)
+                               goto out;
                        continue;
                }
 
@@ -3657,8 +3590,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
        if (ret) {
                btrfs_info(root->fs_info,
                        "failed to delete reference to %.*s, inode %llu parent %llu",
-                       name_len, name,
-                       (unsigned long long)ino, (unsigned long long)dir_ino);
+                       name_len, name, ino, dir_ino);
                btrfs_abort_transaction(trans, root, ret);
                goto err;
        }
@@ -3929,6 +3861,7 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        u64 extent_num_bytes = 0;
        u64 extent_offset = 0;
        u64 item_end = 0;
+       u64 last_size = (u64)-1;
        u32 found_type = (u8)-1;
        int found_extent;
        int del_item;
@@ -4026,6 +3959,11 @@ search_again:
                if (found_type != BTRFS_EXTENT_DATA_KEY)
                        goto delete;
 
+               if (del_item)
+                       last_size = found_key.offset;
+               else
+                       last_size = new_size;
+
                if (extent_type != BTRFS_FILE_EXTENT_INLINE) {
                        u64 num_dec;
                        extent_start = btrfs_file_extent_disk_bytenr(leaf, fi);
@@ -4137,6 +4075,8 @@ out:
                        btrfs_abort_transaction(trans, root, ret);
        }
 error:
+       if (last_size != (u64)-1)
+               btrfs_ordered_update_i_size(inode, last_size, NULL);
        btrfs_free_path(path);
        return err;
 }
@@ -4409,7 +4349,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
                inode->i_ctime = inode->i_mtime = current_fs_time(inode->i_sb);
 
        if (newsize > oldsize) {
-               truncate_pagecache(inode, oldsize, newsize);
+               truncate_pagecache(inode, newsize);
                ret = btrfs_cont_expand(inode, oldsize, newsize);
                if (ret)
                        return ret;
@@ -4465,8 +4405,26 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
                btrfs_inode_resume_unlocked_dio(inode);
 
                ret = btrfs_truncate(inode);
-               if (ret && inode->i_nlink)
-                       btrfs_orphan_del(NULL, inode);
+               if (ret && inode->i_nlink) {
+                       int err;
+
+                       /*
+                        * failed to truncate, disk_i_size is only adjusted down
+                        * as we remove extents, so it should represent the true
+                        * size of the inode, so reset the in memory size and
+                        * delete our orphan entry.
+                        */
+                       trans = btrfs_join_transaction(root);
+                       if (IS_ERR(trans)) {
+                               btrfs_orphan_del(NULL, inode);
+                               return ret;
+                       }
+                       i_size_write(inode, BTRFS_I(inode)->disk_i_size);
+                       err = btrfs_orphan_del(trans, inode);
+                       if (err)
+                               btrfs_abort_transaction(trans, root, err);
+                       btrfs_end_transaction(trans, root);
+               }
        }
 
        return ret;
@@ -4601,10 +4559,15 @@ void btrfs_evict_inode(struct inode *inode)
 
        btrfs_free_block_rsv(root, rsv);
 
+       /*
+        * Errors here aren't a big deal, it just means we leave orphan items
+        * in the tree.  They will be cleaned up on the next mount.
+        */
        if (ret == 0) {
                trans->block_rsv = root->orphan_block_rsv;
-               ret = btrfs_orphan_del(trans, inode);
-               BUG_ON(ret);
+               btrfs_orphan_del(trans, inode);
+       } else {
+               btrfs_orphan_del(NULL, inode);
        }
 
        trans->block_rsv = &root->fs_info->trans_block_rsv;
@@ -6161,10 +6124,7 @@ insert:
        btrfs_release_path(path);
        if (em->start > start || extent_map_end(em) <= start) {
                btrfs_err(root->fs_info, "bad extent! em: [%llu %llu] passed [%llu %llu]",
-                       (unsigned long long)em->start,
-                       (unsigned long long)em->len,
-                       (unsigned long long)start,
-                       (unsigned long long)len);
+                       em->start, em->len, start, len);
                err = -EIO;
                goto out;
        }
@@ -6362,39 +6322,32 @@ 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 btrfs_key ins;
        u64 alloc_hint;
        int ret;
 
-       trans = btrfs_join_transaction(root);
-       if (IS_ERR(trans))
-               return ERR_CAST(trans);
-
-       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,
+       ret = btrfs_reserve_extent(root, len, root->sectorsize, 0,
                                   alloc_hint, &ins, 1);
-       if (ret) {
-               em = ERR_PTR(ret);
-               goto out;
-       }
+       if (ret)
+               return ERR_PTR(ret);
 
        em = create_pinned_em(inode, start, ins.offset, start, ins.objectid,
                              ins.offset, ins.offset, ins.offset, 0);
-       if (IS_ERR(em))
-               goto out;
+       if (IS_ERR(em)) {
+               btrfs_free_reserved_extent(root, ins.objectid, ins.offset);
+               return em;
+       }
 
        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);
+               free_extent_map(em);
+               return ERR_PTR(ret);
        }
-out:
-       btrfs_end_transaction(trans, root);
+
        return em;
 }
 
@@ -6402,11 +6355,11 @@ out:
  * returns 1 when the nocow is safe, < 1 on error, 0 if the
  * block must be cow'd
  */
-noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
-                             struct inode *inode, u64 offset, u64 *len,
+noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                              u64 *orig_start, u64 *orig_block_len,
                              u64 *ram_bytes)
 {
+       struct btrfs_trans_handle *trans;
        struct btrfs_path *path;
        int ret;
        struct extent_buffer *leaf;
@@ -6424,7 +6377,7 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
 
-       ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode),
+       ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(inode),
                                       offset, 0);
        if (ret < 0)
                goto out;
@@ -6489,9 +6442,19 @@ noinline int can_nocow_extent(struct btrfs_trans_handle *trans,
         * look for other files referencing this extent, if we
         * find any we must cow
         */
-       if (btrfs_cross_ref_exist(trans, root, btrfs_ino(inode),
-                                 key.offset - backref_offset, disk_bytenr))
+       trans = btrfs_join_transaction(root);
+       if (IS_ERR(trans)) {
+               ret = 0;
                goto out;
+       }
+
+       ret = btrfs_cross_ref_exist(trans, root, btrfs_ino(inode),
+                                   key.offset - backref_offset, disk_bytenr);
+       btrfs_end_transaction(trans, root);
+       if (ret) {
+               ret = 0;
+               goto out;
+       }
 
        /*
         * adjust disk_bytenr and num_bytes to cover just the bytes
@@ -6633,7 +6596,6 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
        u64 start = iblock << inode->i_blkbits;
        u64 lockstart, lockend;
        u64 len = bh_result->b_size;
-       struct btrfs_trans_handle *trans;
        int unlock_bits = EXTENT_LOCKED;
        int ret = 0;
 
@@ -6715,16 +6677,7 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                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);
-               if (IS_ERR(trans))
-                       goto must_cow;
-
-               if (can_nocow_extent(trans, inode, start, &len, &orig_start,
+               if (can_nocow_extent(inode, start, &len, &orig_start,
                                     &orig_block_len, &ram_bytes) == 1) {
                        if (type == BTRFS_ORDERED_PREALLOC) {
                                free_extent_map(em);
@@ -6733,24 +6686,20 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
                                                       block_start, len,
                                                       orig_block_len,
                                                       ram_bytes, type);
-                               if (IS_ERR(em)) {
-                                       btrfs_end_transaction(trans, root);
+                               if (IS_ERR(em))
                                        goto unlock_err;
-                               }
                        }
 
                        ret = btrfs_add_ordered_extent_dio(inode, start,
                                           block_start, len, len, type);
-                       btrfs_end_transaction(trans, root);
                        if (ret) {
                                free_extent_map(em);
                                goto unlock_err;
                        }
                        goto unlock;
                }
-               btrfs_end_transaction(trans, root);
        }
-must_cow:
+
        /*
         * this will cow the extent, reset the len in case we changed
         * it above
@@ -6813,26 +6762,6 @@ unlock_err:
        return ret;
 }
 
-struct btrfs_dio_private {
-       struct inode *inode;
-       u64 logical_offset;
-       u64 disk_bytenr;
-       u64 bytes;
-       void *private;
-
-       /* number of bios pending for this dio */
-       atomic_t pending_bios;
-
-       /* IO errors */
-       int errors;
-
-       /* orig_bio is our btrfs_io_bio */
-       struct bio *orig_bio;
-
-       /* dio_bio came from fs/direct-io.c */
-       struct bio *dio_bio;
-};
-
 static void btrfs_endio_direct_read(struct bio *bio, int err)
 {
        struct btrfs_dio_private *dip = bio->bi_private;
@@ -6841,6 +6770,8 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
        struct inode *inode = dip->inode;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct bio *dio_bio;
+       u32 *csums = (u32 *)dip->csum;
+       int index = 0;
        u64 start;
 
        start = dip->logical_offset;
@@ -6849,12 +6780,8 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
                        struct page *page = bvec->bv_page;
                        char *kaddr;
                        u32 csum = ~(u32)0;
-                       u64 private = ~(u32)0;
                        unsigned long flags;
 
-                       if (get_state_private(&BTRFS_I(inode)->io_tree,
-                                             start, &private))
-                               goto failed;
                        local_irq_save(flags);
                        kaddr = kmap_atomic(page);
                        csum = btrfs_csum_data(kaddr + bvec->bv_offset,
@@ -6864,18 +6791,17 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
                        local_irq_restore(flags);
 
                        flush_dcache_page(bvec->bv_page);
-                       if (csum != private) {
-failed:
-                               btrfs_err(root->fs_info, "csum failed ino %llu off %llu csum %u private %u",
-                                       (unsigned long long)btrfs_ino(inode),
-                                       (unsigned long long)start,
-                                       csum, (unsigned)private);
+                       if (csum != csums[index]) {
+                               btrfs_err(root->fs_info, "csum failed ino %llu off %llu csum %u expected csum %u",
+                                         btrfs_ino(inode), start, csum,
+                                         csums[index]);
                                err = -EIO;
                        }
                }
 
                start += bvec->bv_len;
                bvec++;
+               index++;
        } while (bvec <= bvec_end);
 
        unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset,
@@ -6956,7 +6882,7 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
        if (err) {
                printk(KERN_ERR "btrfs direct IO failed ino %llu rw %lu "
                      "sector %#Lx len %u err no %d\n",
-                     (unsigned long long)btrfs_ino(dip->inode), bio->bi_rw,
+                     btrfs_ino(dip->inode), bio->bi_rw,
                      (unsigned long long)bio->bi_sector, bio->bi_size, err);
                dip->errors = 1;
 
@@ -6992,6 +6918,7 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
                                         int rw, u64 file_offset, int skip_sum,
                                         int async_submit)
 {
+       struct btrfs_dio_private *dip = bio->bi_private;
        int write = rw & REQ_WRITE;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        int ret;
@@ -7026,7 +6953,8 @@ static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode,
                if (ret)
                        goto err;
        } else if (!skip_sum) {
-               ret = btrfs_lookup_bio_sums_dio(root, inode, bio, file_offset);
+               ret = btrfs_lookup_bio_sums_dio(root, inode, dip, bio,
+                                               file_offset);
                if (ret)
                        goto err;
        }
@@ -7061,6 +6989,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
                bio_put(orig_bio);
                return -EIO;
        }
+
        if (map_length >= orig_bio->bi_size) {
                bio = orig_bio;
                goto submit;
@@ -7156,19 +7085,28 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
        struct btrfs_dio_private *dip;
        struct bio *io_bio;
        int skip_sum;
+       int sum_len;
        int write = rw & REQ_WRITE;
        int ret = 0;
+       u16 csum_size;
 
        skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
 
        io_bio = btrfs_bio_clone(dio_bio, GFP_NOFS);
-
        if (!io_bio) {
                ret = -ENOMEM;
                goto free_ordered;
        }
 
-       dip = kmalloc(sizeof(*dip), GFP_NOFS);
+       if (!skip_sum && !write) {
+               csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
+               sum_len = dio_bio->bi_size >> inode->i_sb->s_blocksize_bits;
+               sum_len *= csum_size;
+       } else {
+               sum_len = 0;
+       }
+
+       dip = kmalloc(sizeof(*dip) + sum_len, GFP_NOFS);
        if (!dip) {
                ret = -ENOMEM;
                goto free_io_bio;
@@ -7443,10 +7381,23 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
                 * whoever cleared the private bit is responsible
                 * for the finish_ordered_io
                 */
-               if (TestClearPagePrivate2(page) &&
-                   btrfs_dec_test_ordered_pending(inode, &ordered, page_start,
-                                                  PAGE_CACHE_SIZE, 1)) {
-                       btrfs_finish_ordered_io(ordered);
+               if (TestClearPagePrivate2(page)) {
+                       struct btrfs_ordered_inode_tree *tree;
+                       u64 new_len;
+
+                       tree = &BTRFS_I(inode)->ordered_tree;
+
+                       spin_lock_irq(&tree->lock);
+                       set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
+                       new_len = page_start - ordered->file_offset;
+                       if (new_len < ordered->truncated_len)
+                               ordered->truncated_len = new_len;
+                       spin_unlock_irq(&tree->lock);
+
+                       if (btrfs_dec_test_ordered_pending(inode, &ordered,
+                                                          page_start,
+                                                          PAGE_CACHE_SIZE, 1))
+                               btrfs_finish_ordered_io(ordered);
                }
                btrfs_put_ordered_extent(ordered);
                cached_state = NULL;
@@ -7612,7 +7563,6 @@ static int btrfs_truncate(struct inode *inode)
        u64 min_size = btrfs_calc_trunc_metadata_size(root, 1);
 
        btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
-       btrfs_ordered_update_i_size(inode, inode->i_size, NULL);
 
        /*
         * Yes ladies and gentelment, this is indeed ugly.  The fact is we have
@@ -7876,7 +7826,7 @@ void btrfs_destroy_inode(struct inode *inode)
        if (test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM,
                     &BTRFS_I(inode)->runtime_flags)) {
                btrfs_info(root->fs_info, "inode %llu still on the orphan list",
-                       (unsigned long long)btrfs_ino(inode));
+                       btrfs_ino(inode));
                atomic_dec(&root->orphan_inodes);
        }
 
@@ -7886,8 +7836,7 @@ void btrfs_destroy_inode(struct inode *inode)
                        break;
                else {
                        btrfs_err(root->fs_info, "found ordered extent %llu %llu on inode cleanup",
-                               (unsigned long long)ordered->file_offset,
-                               (unsigned long long)ordered->len);
+                               ordered->file_offset, ordered->len);
                        btrfs_remove_ordered_extent(inode, ordered);
                        btrfs_put_ordered_extent(ordered);
                        btrfs_put_ordered_extent(ordered);
@@ -8161,10 +8110,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                                                 new_dentry->d_name.name,
                                                 new_dentry->d_name.len);
                }
-               if (!ret && new_inode->i_nlink == 0) {
+               if (!ret && new_inode->i_nlink == 0)
                        ret = btrfs_orphan_add(trans, new_dentry->d_inode);
-                       BUG_ON(ret);
-               }
                if (ret) {
                        btrfs_abort_transaction(trans, root, ret);
                        goto out_fail;
@@ -8525,8 +8472,8 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
 
                cur_bytes = min(num_bytes, 256ULL * 1024 * 1024);
                cur_bytes = max(cur_bytes, min_size);
-               ret = btrfs_reserve_extent(trans, root, cur_bytes,
-                                          min_size, 0, *alloc_hint, &ins, 1);
+               ret = btrfs_reserve_extent(root, cur_bytes, min_size, 0,
+                                          *alloc_hint, &ins, 1);
                if (ret) {
                        if (own_trans)
                                btrfs_end_transaction(trans, root);
index 238a05545ee2230629fc850191f348b94cadd8cf..1a5b9462dd9ae2639513237358c2f55662bf366f 100644 (file)
@@ -43,6 +43,7 @@
 #include <linux/blkdev.h>
 #include <linux/uuid.h>
 #include <linux/btrfs.h>
+#include <linux/uaccess.h>
 #include "compat.h"
 #include "ctree.h"
 #include "disk-io.h"
@@ -57,6 +58,9 @@
 #include "send.h"
 #include "dev-replace.h"
 
+static int btrfs_clone(struct inode *src, struct inode *inode,
+                      u64 off, u64 olen, u64 olen_aligned, u64 destoff);
+
 /* Mask out flags that are inappropriate for the given type of inode. */
 static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags)
 {
@@ -363,6 +367,13 @@ static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg)
        return 0;
 }
 
+int btrfs_is_empty_uuid(u8 *uuid)
+{
+       static char empty_uuid[BTRFS_UUID_SIZE] = {0};
+
+       return !memcmp(uuid, empty_uuid, BTRFS_UUID_SIZE);
+}
+
 static noinline int create_subvol(struct inode *dir,
                                  struct dentry *dentry,
                                  char *name, int namelen,
@@ -396,7 +407,7 @@ static noinline int create_subvol(struct inode *dir,
         * of create_snapshot().
         */
        ret = btrfs_subvolume_reserve_metadata(root, &block_rsv,
-                                              7, &qgroup_reserved);
+                                              8, &qgroup_reserved, false);
        if (ret)
                return ret;
 
@@ -425,26 +436,25 @@ static noinline int create_subvol(struct inode *dir,
        btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV);
        btrfs_set_header_owner(leaf, objectid);
 
-       write_extent_buffer(leaf, root->fs_info->fsid,
-                           (unsigned long)btrfs_header_fsid(leaf),
+       write_extent_buffer(leaf, root->fs_info->fsid, btrfs_header_fsid(leaf),
                            BTRFS_FSID_SIZE);
        write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
-                           (unsigned long)btrfs_header_chunk_tree_uuid(leaf),
+                           btrfs_header_chunk_tree_uuid(leaf),
                            BTRFS_UUID_SIZE);
        btrfs_mark_buffer_dirty(leaf);
 
        memset(&root_item, 0, sizeof(root_item));
 
        inode_item = &root_item.inode;
-       inode_item->generation = cpu_to_le64(1);
-       inode_item->size = cpu_to_le64(3);
-       inode_item->nlink = cpu_to_le32(1);
-       inode_item->nbytes = cpu_to_le64(root->leafsize);
-       inode_item->mode = cpu_to_le32(S_IFDIR | 0755);
+       btrfs_set_stack_inode_generation(inode_item, 1);
+       btrfs_set_stack_inode_size(inode_item, 3);
+       btrfs_set_stack_inode_nlink(inode_item, 1);
+       btrfs_set_stack_inode_nbytes(inode_item, root->leafsize);
+       btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755);
 
-       root_item.flags = 0;
-       root_item.byte_limit = 0;
-       inode_item->flags = cpu_to_le64(BTRFS_INODE_ROOT_ITEM_INIT);
+       btrfs_set_root_flags(&root_item, 0);
+       btrfs_set_root_limit(&root_item, 0);
+       btrfs_set_stack_inode_flags(inode_item, BTRFS_INODE_ROOT_ITEM_INIT);
 
        btrfs_set_root_bytenr(&root_item, leaf->start);
        btrfs_set_root_generation(&root_item, trans->transid);
@@ -457,8 +467,8 @@ static noinline int create_subvol(struct inode *dir,
                        btrfs_root_generation(&root_item));
        uuid_le_gen(&new_uuid);
        memcpy(root_item.uuid, new_uuid.b, BTRFS_UUID_SIZE);
-       root_item.otime.sec = cpu_to_le64(cur_time.tv_sec);
-       root_item.otime.nsec = cpu_to_le32(cur_time.tv_nsec);
+       btrfs_set_stack_timespec_sec(&root_item.otime, cur_time.tv_sec);
+       btrfs_set_stack_timespec_nsec(&root_item.otime, cur_time.tv_nsec);
        root_item.ctime = root_item.otime;
        btrfs_set_root_ctransid(&root_item, trans->transid);
        btrfs_set_root_otransid(&root_item, trans->transid);
@@ -518,9 +528,14 @@ static noinline int create_subvol(struct inode *dir,
        ret = btrfs_add_root_ref(trans, root->fs_info->tree_root,
                                 objectid, root->root_key.objectid,
                                 btrfs_ino(dir), index, name, namelen);
-
        BUG_ON(ret);
 
+       ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root,
+                                 root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
+                                 objectid);
+       if (ret)
+               btrfs_abort_transaction(trans, root, ret);
+
 fail:
        trans->block_rsv = NULL;
        trans->bytes_reserved = 0;
@@ -573,10 +588,12 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
         * 1 - root item
         * 2 - root ref/backref
         * 1 - root of snapshot
+        * 1 - UUID item
         */
        ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
-                                       &pending_snapshot->block_rsv, 7,
-                                       &pending_snapshot->qgroup_reserved);
+                                       &pending_snapshot->block_rsv, 8,
+                                       &pending_snapshot->qgroup_reserved,
+                                       false);
        if (ret)
                goto out;
 
@@ -1267,9 +1284,6 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                        cluster = max_cluster;
                }
 
-               if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
-                       BTRFS_I(inode)->force_compress = compress_type;
-
                if (i + cluster > ra_index) {
                        ra_index = max(i, ra_index);
                        btrfs_force_ra(inode->i_mapping, ra, file, ra_index,
@@ -1278,6 +1292,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                }
 
                mutex_lock(&inode->i_mutex);
+               if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)
+                       BTRFS_I(inode)->force_compress = compress_type;
                ret = cluster_pages_for_defrag(inode, pages, i, cluster);
                if (ret < 0) {
                        mutex_unlock(&inode->i_mutex);
@@ -1334,10 +1350,6 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                            atomic_read(&root->fs_info->async_delalloc_pages) == 0));
                }
                atomic_dec(&root->fs_info->async_submit_draining);
-
-               mutex_lock(&inode->i_mutex);
-               BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
-               mutex_unlock(&inode->i_mutex);
        }
 
        if (range->compress_type == BTRFS_COMPRESS_LZO) {
@@ -1347,6 +1359,11 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        ret = defrag_count;
 
 out_ra:
+       if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) {
+               mutex_lock(&inode->i_mutex);
+               BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
+               mutex_unlock(&inode->i_mutex);
+       }
        if (!file)
                kfree(ra);
        kfree(pages);
@@ -1377,9 +1394,8 @@ static noinline int btrfs_ioctl_resize(struct file *file,
 
        if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
                        1)) {
-               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
                mnt_drop_write_file(file);
-               return -EINVAL;
+               return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
        }
 
        mutex_lock(&root->fs_info->volume_mutex);
@@ -1403,14 +1419,13 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                        ret = -EINVAL;
                        goto out_free;
                }
-               printk(KERN_INFO "btrfs: resizing devid %llu\n",
-                      (unsigned long long)devid);
+               printk(KERN_INFO "btrfs: resizing devid %llu\n", devid);
        }
 
        device = btrfs_find_device(root->fs_info, devid, NULL, NULL);
        if (!device) {
                printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
-                      (unsigned long long)devid);
+                      devid);
                ret = -ENODEV;
                goto out_free;
        }
@@ -1418,7 +1433,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        if (!device->writeable) {
                printk(KERN_INFO "btrfs: resizer unable to apply on "
                       "readonly device %llu\n",
-                      (unsigned long long)devid);
+                      devid);
                ret = -EPERM;
                goto out_free;
        }
@@ -1470,8 +1485,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        new_size *= root->sectorsize;
 
        printk_in_rcu(KERN_INFO "btrfs: new size for %s is %llu\n",
-                     rcu_str_deref(device->name),
-                     (unsigned long long)new_size);
+                     rcu_str_deref(device->name), new_size);
 
        if (new_size > old_size) {
                trans = btrfs_start_transaction(root, 0);
@@ -1721,13 +1735,28 @@ out:
 static noinline int may_destroy_subvol(struct btrfs_root *root)
 {
        struct btrfs_path *path;
+       struct btrfs_dir_item *di;
        struct btrfs_key key;
+       u64 dir_id;
        int ret;
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
+       /* Make sure this root isn't set as the default subvol */
+       dir_id = btrfs_super_root_dir(root->fs_info->super_copy);
+       di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, path,
+                                  dir_id, "default", 7, 0);
+       if (di && !IS_ERR(di)) {
+               btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key);
+               if (key.objectid == root->root_key.objectid) {
+                       ret = -ENOTEMPTY;
+                       goto out;
+               }
+               btrfs_release_path(path);
+       }
+
        key.objectid = root->root_key.objectid;
        key.type = BTRFS_ROOT_REF_KEY;
        key.offset = (u64)-1;
@@ -1993,25 +2022,29 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
                if (ret < 0)
                        goto out;
+               else if (ret > 0) {
+                       ret = btrfs_previous_item(root, path, dirid,
+                                                 BTRFS_INODE_REF_KEY);
+                       if (ret < 0)
+                               goto out;
+                       else if (ret > 0) {
+                               ret = -ENOENT;
+                               goto out;
+                       }
+               }
 
                l = path->nodes[0];
                slot = path->slots[0];
-               if (ret > 0 && slot > 0)
-                       slot--;
                btrfs_item_key_to_cpu(l, &key, slot);
 
-               if (ret > 0 && (key.objectid != dirid ||
-                               key.type != BTRFS_INODE_REF_KEY)) {
-                       ret = -ENOENT;
-                       goto out;
-               }
-
                iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref);
                len = btrfs_inode_ref_name_len(l, iref);
                ptr -= len + 1;
                total_len += len + 1;
-               if (ptr < name)
+               if (ptr < name) {
+                       ret = -ENAMETOOLONG;
                        goto out;
+               }
 
                *(ptr + len) = '/';
                read_extent_buffer(l, ptr,(unsigned long)(iref + 1), len);
@@ -2024,8 +2057,6 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
                key.offset = (u64)-1;
                dirid = key.objectid;
        }
-       if (ptr < name)
-               goto out;
        memmove(name, ptr, total_len);
        name[total_len]='\0';
        ret = 0;
@@ -2174,7 +2205,7 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
         * ref/backref.
         */
        err = btrfs_subvolume_reserve_metadata(root, &block_rsv,
-                                              5, &qgroup_reserved);
+                                              5, &qgroup_reserved, true);
        if (err)
                goto out_up_write;
 
@@ -2213,6 +2244,27 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
                        goto out_end_trans;
                }
        }
+
+       ret = btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root,
+                                 dest->root_item.uuid, BTRFS_UUID_KEY_SUBVOL,
+                                 dest->root_key.objectid);
+       if (ret && ret != -ENOENT) {
+               btrfs_abort_transaction(trans, root, ret);
+               err = ret;
+               goto out_end_trans;
+       }
+       if (!btrfs_is_empty_uuid(dest->root_item.received_uuid)) {
+               ret = btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root,
+                                         dest->root_item.received_uuid,
+                                         BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                         dest->root_key.objectid);
+               if (ret && ret != -ENOENT) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       err = ret;
+                       goto out_end_trans;
+               }
+       }
+
 out_end_trans:
        trans->block_rsv = NULL;
        trans->bytes_reserved = 0;
@@ -2326,8 +2378,7 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
 
        if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running,
                        1)) {
-               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
-               return -EINVAL;
+               return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
        }
 
        mutex_lock(&root->fs_info->volume_mutex);
@@ -2400,10 +2451,10 @@ static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg)
        if (!fi_args)
                return -ENOMEM;
 
+       mutex_lock(&fs_devices->device_list_mutex);
        fi_args->num_devices = fs_devices->num_devices;
        memcpy(&fi_args->fsid, root->fs_info->fsid, sizeof(fi_args->fsid));
 
-       mutex_lock(&fs_devices->device_list_mutex);
        list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) {
                if (device->devid > fi_args->max_id)
                        fi_args->max_id = device->devid;
@@ -2424,7 +2475,6 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
        int ret = 0;
        char *s_uuid = NULL;
-       char empty_uuid[BTRFS_UUID_SIZE] = {0};
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -2433,7 +2483,7 @@ static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg)
        if (IS_ERR(di_args))
                return PTR_ERR(di_args);
 
-       if (memcmp(empty_uuid, di_args->uuid, BTRFS_UUID_SIZE) != 0)
+       if (!btrfs_is_empty_uuid(di_args->uuid))
                s_uuid = di_args->uuid;
 
        mutex_lock(&fs_devices->device_list_mutex);
@@ -2469,150 +2519,336 @@ out:
        return ret;
 }
 
-static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
-                                      u64 off, u64 olen, u64 destoff)
+static struct page *extent_same_get_page(struct inode *inode, u64 off)
+{
+       struct page *page;
+       pgoff_t index;
+       struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
+
+       index = off >> PAGE_CACHE_SHIFT;
+
+       page = grab_cache_page(inode->i_mapping, index);
+       if (!page)
+               return NULL;
+
+       if (!PageUptodate(page)) {
+               if (extent_read_full_page_nolock(tree, page, btrfs_get_extent,
+                                                0))
+                       return NULL;
+               lock_page(page);
+               if (!PageUptodate(page)) {
+                       unlock_page(page);
+                       page_cache_release(page);
+                       return NULL;
+               }
+       }
+       unlock_page(page);
+
+       return page;
+}
+
+static inline void lock_extent_range(struct inode *inode, u64 off, u64 len)
+{
+       /* do any pending delalloc/csum calc on src, one way or
+          another, and lock file content */
+       while (1) {
+               struct btrfs_ordered_extent *ordered;
+               lock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
+               ordered = btrfs_lookup_first_ordered_extent(inode,
+                                                           off + len - 1);
+               if (!ordered &&
+                   !test_range_bit(&BTRFS_I(inode)->io_tree, off,
+                                   off + len - 1, EXTENT_DELALLOC, 0, NULL))
+                       break;
+               unlock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1);
+               if (ordered)
+                       btrfs_put_ordered_extent(ordered);
+               btrfs_wait_ordered_range(inode, off, len);
+       }
+}
+
+static void btrfs_double_unlock(struct inode *inode1, u64 loff1,
+                               struct inode *inode2, u64 loff2, u64 len)
+{
+       unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1);
+       unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1);
+
+       mutex_unlock(&inode1->i_mutex);
+       mutex_unlock(&inode2->i_mutex);
+}
+
+static void btrfs_double_lock(struct inode *inode1, u64 loff1,
+                             struct inode *inode2, u64 loff2, u64 len)
+{
+       if (inode1 < inode2) {
+               swap(inode1, inode2);
+               swap(loff1, loff2);
+       }
+
+       mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
+       lock_extent_range(inode1, loff1, len);
+       if (inode1 != inode2) {
+               mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
+               lock_extent_range(inode2, loff2, len);
+       }
+}
+
+static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
+                         u64 dst_loff, u64 len)
+{
+       int ret = 0;
+       struct page *src_page, *dst_page;
+       unsigned int cmp_len = PAGE_CACHE_SIZE;
+       void *addr, *dst_addr;
+
+       while (len) {
+               if (len < PAGE_CACHE_SIZE)
+                       cmp_len = len;
+
+               src_page = extent_same_get_page(src, loff);
+               if (!src_page)
+                       return -EINVAL;
+               dst_page = extent_same_get_page(dst, dst_loff);
+               if (!dst_page) {
+                       page_cache_release(src_page);
+                       return -EINVAL;
+               }
+               addr = kmap_atomic(src_page);
+               dst_addr = kmap_atomic(dst_page);
+
+               flush_dcache_page(src_page);
+               flush_dcache_page(dst_page);
+
+               if (memcmp(addr, dst_addr, cmp_len))
+                       ret = BTRFS_SAME_DATA_DIFFERS;
+
+               kunmap_atomic(addr);
+               kunmap_atomic(dst_addr);
+               page_cache_release(src_page);
+               page_cache_release(dst_page);
+
+               if (ret)
+                       break;
+
+               loff += cmp_len;
+               dst_loff += cmp_len;
+               len -= cmp_len;
+       }
+
+       return ret;
+}
+
+static int extent_same_check_offsets(struct inode *inode, u64 off, u64 len)
+{
+       u64 bs = BTRFS_I(inode)->root->fs_info->sb->s_blocksize;
+
+       if (off + len > inode->i_size || off + len < off)
+               return -EINVAL;
+       /* Check that we are block aligned - btrfs_clone() requires this */
+       if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs))
+               return -EINVAL;
+
+       return 0;
+}
+
+static int btrfs_extent_same(struct inode *src, u64 loff, u64 len,
+                            struct inode *dst, u64 dst_loff)
 {
-       struct inode *inode = file_inode(file);
-       struct btrfs_root *root = BTRFS_I(inode)->root;
-       struct fd src_file;
-       struct inode *src;
-       struct btrfs_trans_handle *trans;
-       struct btrfs_path *path;
-       struct extent_buffer *leaf;
-       char *buf;
-       struct btrfs_key key;
-       u32 nritems;
-       int slot;
        int ret;
-       u64 len = olen;
-       u64 bs = root->fs_info->sb->s_blocksize;
-       int same_inode = 0;
 
        /*
-        * TODO:
-        * - split compressed inline extents.  annoying: we need to
-        *   decompress into destination's address_space (the file offset
-        *   may change, so source mapping won't do), then recompress (or
-        *   otherwise reinsert) a subrange.
-        * - allow ranges within the same file to be cloned (provided
-        *   they don't overlap)?
+        * btrfs_clone() can't handle extents in the same file
+        * yet. Once that works, we can drop this check and replace it
+        * with a check for the same inode, but overlapping extents.
         */
-
-       /* the destination must be opened for writing */
-       if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
+       if (src == dst)
                return -EINVAL;
 
-       if (btrfs_root_readonly(root))
-               return -EROFS;
+       btrfs_double_lock(src, loff, dst, dst_loff, len);
+
+       ret = extent_same_check_offsets(src, loff, len);
+       if (ret)
+               goto out_unlock;
+
+       ret = extent_same_check_offsets(dst, dst_loff, len);
+       if (ret)
+               goto out_unlock;
+
+       /* don't make the dst file partly checksummed */
+       if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
+           (BTRFS_I(dst)->flags & BTRFS_INODE_NODATASUM)) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       ret = btrfs_cmp_data(src, loff, dst, dst_loff, len);
+       if (ret == 0)
+               ret = btrfs_clone(src, dst, loff, len, len, dst_loff);
+
+out_unlock:
+       btrfs_double_unlock(src, loff, dst, dst_loff, len);
+
+       return ret;
+}
+
+#define BTRFS_MAX_DEDUPE_LEN   (16 * 1024 * 1024)
+
+static long btrfs_ioctl_file_extent_same(struct file *file,
+                                        void __user *argp)
+{
+       struct btrfs_ioctl_same_args *args = argp;
+       struct btrfs_ioctl_same_args same;
+       struct btrfs_ioctl_same_extent_info info;
+       struct inode *src = file->f_dentry->d_inode;
+       struct file *dst_file = NULL;
+       struct inode *dst;
+       u64 off;
+       u64 len;
+       int i;
+       int ret;
+       u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
+       bool is_admin = capable(CAP_SYS_ADMIN);
+
+       if (!(file->f_mode & FMODE_READ))
+               return -EINVAL;
 
        ret = mnt_want_write_file(file);
        if (ret)
                return ret;
 
-       src_file = fdget(srcfd);
-       if (!src_file.file) {
-               ret = -EBADF;
-               goto out_drop_write;
+       if (copy_from_user(&same,
+                          (struct btrfs_ioctl_same_args __user *)argp,
+                          sizeof(same))) {
+               ret = -EFAULT;
+               goto out;
        }
 
-       ret = -EXDEV;
-       if (src_file.file->f_path.mnt != file->f_path.mnt)
-               goto out_fput;
+       off = same.logical_offset;
+       len = same.length;
 
-       src = file_inode(src_file.file);
+       /*
+        * Limit the total length we will dedupe for each operation.
+        * This is intended to bound the total time spent in this
+        * ioctl to something sane.
+        */
+       if (len > BTRFS_MAX_DEDUPE_LEN)
+               len = BTRFS_MAX_DEDUPE_LEN;
 
-       ret = -EINVAL;
-       if (src == inode)
-               same_inode = 1;
+       if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) {
+               /*
+                * Btrfs does not support blocksize < page_size. As a
+                * result, btrfs_cmp_data() won't correctly handle
+                * this situation without an update.
+                */
+               ret = -EINVAL;
+               goto out;
+       }
 
-       /* the src must be open for reading */
-       if (!(src_file.file->f_mode & FMODE_READ))
-               goto out_fput;
+       ret = -EISDIR;
+       if (S_ISDIR(src->i_mode))
+               goto out;
 
-       /* don't make the dst file partly checksummed */
-       if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
-           (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
-               goto out_fput;
+       ret = -EACCES;
+       if (!S_ISREG(src->i_mode))
+               goto out;
 
-       ret = -EISDIR;
-       if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
-               goto out_fput;
+       ret = 0;
+       for (i = 0; i < same.dest_count; i++) {
+               if (copy_from_user(&info, &args->info[i], sizeof(info))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
 
-       ret = -EXDEV;
-       if (src->i_sb != inode->i_sb)
-               goto out_fput;
+               info.bytes_deduped = 0;
 
-       ret = -ENOMEM;
-       buf = vmalloc(btrfs_level_size(root, 0));
-       if (!buf)
-               goto out_fput;
+               dst_file = fget(info.fd);
+               if (!dst_file) {
+                       info.status = -EBADF;
+                       goto next;
+               }
 
-       path = btrfs_alloc_path();
-       if (!path) {
-               vfree(buf);
-               goto out_fput;
-       }
-       path->reada = 2;
+               if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
+                       info.status = -EINVAL;
+                       goto next;
+               }
 
-       if (!same_inode) {
-               if (inode < src) {
-                       mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
-                       mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
-               } else {
-                       mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
-                       mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+               info.status = -EXDEV;
+               if (file->f_path.mnt != dst_file->f_path.mnt)
+                       goto next;
+
+               dst = dst_file->f_dentry->d_inode;
+               if (src->i_sb != dst->i_sb)
+                       goto next;
+
+               if (S_ISDIR(dst->i_mode)) {
+                       info.status = -EISDIR;
+                       goto next;
                }
-       } else {
-               mutex_lock(&src->i_mutex);
-       }
 
-       /* determine range to clone */
-       ret = -EINVAL;
-       if (off + len > src->i_size || off + len < off)
-               goto out_unlock;
-       if (len == 0)
-               olen = len = src->i_size - off;
-       /* if we extend to eof, continue to block boundary */
-       if (off + len == src->i_size)
-               len = ALIGN(src->i_size, bs) - off;
+               if (!S_ISREG(dst->i_mode)) {
+                       info.status = -EACCES;
+                       goto next;
+               }
 
-       /* verify the end result is block aligned */
-       if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
-           !IS_ALIGNED(destoff, bs))
-               goto out_unlock;
+               info.status = btrfs_extent_same(src, off, len, dst,
+                                               info.logical_offset);
+               if (info.status == 0)
+                       info.bytes_deduped += len;
 
-       /* verify if ranges are overlapped within the same file */
-       if (same_inode) {
-               if (destoff + len > off && destoff < off + len)
-                       goto out_unlock;
-       }
+next:
+               if (dst_file)
+                       fput(dst_file);
 
-       if (destoff > inode->i_size) {
-               ret = btrfs_cont_expand(inode, inode->i_size, destoff);
-               if (ret)
-                       goto out_unlock;
+               if (__put_user_unaligned(info.status, &args->info[i].status) ||
+                   __put_user_unaligned(info.bytes_deduped,
+                                        &args->info[i].bytes_deduped)) {
+                       ret = -EFAULT;
+                       goto out;
+               }                                                               
        }
 
-       /* truncate page cache pages from target inode range */
-       truncate_inode_pages_range(&inode->i_data, destoff,
-                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
+out:
+       mnt_drop_write_file(file);
+       return ret;
+}
 
-       /* do any pending delalloc/csum calc on src, one way or
-          another, and lock file content */
-       while (1) {
-               struct btrfs_ordered_extent *ordered;
-               lock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
-               ordered = btrfs_lookup_first_ordered_extent(src, off + len - 1);
-               if (!ordered &&
-                   !test_range_bit(&BTRFS_I(src)->io_tree, off, off + len - 1,
-                                   EXTENT_DELALLOC, 0, NULL))
-                       break;
-               unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
-               if (ordered)
-                       btrfs_put_ordered_extent(ordered);
-               btrfs_wait_ordered_range(src, off, len);
+/**
+ * btrfs_clone() - clone a range from inode file to another
+ *
+ * @src: Inode to clone from
+ * @inode: Inode to clone to
+ * @off: Offset within source to start clone from
+ * @olen: Original length, passed by user, of range to clone
+ * @olen_aligned: Block-aligned value of olen, extent_same uses
+ *               identical values here
+ * @destoff: Offset within @inode to start clone
+ */
+static int btrfs_clone(struct inode *src, struct inode *inode,
+                      u64 off, u64 olen, u64 olen_aligned, u64 destoff)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct btrfs_path *path = NULL;
+       struct extent_buffer *leaf;
+       struct btrfs_trans_handle *trans;
+       char *buf = NULL;
+       struct btrfs_key key;
+       u32 nritems;
+       int slot;
+       int ret;
+       u64 len = olen_aligned;
+
+       ret = -ENOMEM;
+       buf = vmalloc(btrfs_level_size(root, 0));
+       if (!buf)
+               return ret;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               vfree(buf);
+               return ret;
        }
 
+       path->reada = 2;
        /* clone data */
        key.objectid = btrfs_ino(src);
        key.type = BTRFS_EXTENT_DATA_KEY;
@@ -2858,15 +3094,132 @@ next:
                key.offset++;
        }
        ret = 0;
+
 out:
        btrfs_release_path(path);
+       btrfs_free_path(path);
+       vfree(buf);
+       return ret;
+}
+
+static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
+                                      u64 off, u64 olen, u64 destoff)
+{
+       struct inode *inode = fdentry(file)->d_inode;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       struct fd src_file;
+       struct inode *src;
+       int ret;
+       u64 len = olen;
+       u64 bs = root->fs_info->sb->s_blocksize;
+       int same_inode = 0;
+
+       /*
+        * TODO:
+        * - split compressed inline extents.  annoying: we need to
+        *   decompress into destination's address_space (the file offset
+        *   may change, so source mapping won't do), then recompress (or
+        *   otherwise reinsert) a subrange.
+        * - allow ranges within the same file to be cloned (provided
+        *   they don't overlap)?
+        */
+
+       /* the destination must be opened for writing */
+       if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
+               return -EINVAL;
+
+       if (btrfs_root_readonly(root))
+               return -EROFS;
+
+       ret = mnt_want_write_file(file);
+       if (ret)
+               return ret;
+
+       src_file = fdget(srcfd);
+       if (!src_file.file) {
+               ret = -EBADF;
+               goto out_drop_write;
+       }
+
+       ret = -EXDEV;
+       if (src_file.file->f_path.mnt != file->f_path.mnt)
+               goto out_fput;
+
+       src = file_inode(src_file.file);
+
+       ret = -EINVAL;
+       if (src == inode)
+               same_inode = 1;
+
+       /* the src must be open for reading */
+       if (!(src_file.file->f_mode & FMODE_READ))
+               goto out_fput;
+
+       /* don't make the dst file partly checksummed */
+       if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
+           (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
+               goto out_fput;
+
+       ret = -EISDIR;
+       if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
+               goto out_fput;
+
+       ret = -EXDEV;
+       if (src->i_sb != inode->i_sb)
+               goto out_fput;
+
+       if (!same_inode) {
+               if (inode < src) {
+                       mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT);
+                       mutex_lock_nested(&src->i_mutex, I_MUTEX_CHILD);
+               } else {
+                       mutex_lock_nested(&src->i_mutex, I_MUTEX_PARENT);
+                       mutex_lock_nested(&inode->i_mutex, I_MUTEX_CHILD);
+               }
+       } else {
+               mutex_lock(&src->i_mutex);
+       }
+
+       /* determine range to clone */
+       ret = -EINVAL;
+       if (off + len > src->i_size || off + len < off)
+               goto out_unlock;
+       if (len == 0)
+               olen = len = src->i_size - off;
+       /* if we extend to eof, continue to block boundary */
+       if (off + len == src->i_size)
+               len = ALIGN(src->i_size, bs) - off;
+
+       /* verify the end result is block aligned */
+       if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) ||
+           !IS_ALIGNED(destoff, bs))
+               goto out_unlock;
+
+       /* verify if ranges are overlapped within the same file */
+       if (same_inode) {
+               if (destoff + len > off && destoff < off + len)
+                       goto out_unlock;
+       }
+
+       if (destoff > inode->i_size) {
+               ret = btrfs_cont_expand(inode, inode->i_size, destoff);
+               if (ret)
+                       goto out_unlock;
+       }
+
+       /* truncate page cache pages from target inode range */
+       truncate_inode_pages_range(&inode->i_data, destoff,
+                                  PAGE_CACHE_ALIGN(destoff + len) - 1);
+
+       lock_extent_range(src, off, len);
+
+       ret = btrfs_clone(src, inode, off, olen, len, destoff);
+
        unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
 out_unlock:
        mutex_unlock(&src->i_mutex);
        if (!same_inode)
                mutex_unlock(&inode->i_mutex);
-       vfree(buf);
-       btrfs_free_path(path);
 out_fput:
        fdput(src_file);
 out_drop_write:
@@ -3312,11 +3665,13 @@ static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg)
 
        switch (p->cmd) {
        case BTRFS_IOCTL_DEV_REPLACE_CMD_START:
+               if (root->fs_info->sb->s_flags & MS_RDONLY)
+                       return -EROFS;
+
                if (atomic_xchg(
                        &root->fs_info->mutually_exclusive_operation_running,
                        1)) {
-                       pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
-                       ret = -EINPROGRESS;
+                       ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
                } else {
                        ret = btrfs_dev_replace_start(root, p);
                        atomic_set(
@@ -3560,8 +3915,7 @@ again:
        } else {
                /* this is (1) */
                mutex_unlock(&fs_info->balance_mutex);
-               pr_info("btrfs: dev add/delete/balance/replace/resize operation in progress\n");
-               ret = -EINVAL;
+               ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS;
                goto out;
        }
 
@@ -3967,6 +4321,7 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
        struct btrfs_trans_handle *trans;
        struct timespec ct = CURRENT_TIME;
        int ret = 0;
+       int received_uuid_changed;
 
        ret = mnt_want_write_file(file);
        if (ret < 0)
@@ -3996,7 +4351,11 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
                goto out;
        }
 
-       trans = btrfs_start_transaction(root, 1);
+       /*
+        * 1 - root item
+        * 2 - uuid items (received uuid + subvol uuid)
+        */
+       trans = btrfs_start_transaction(root, 3);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                trans = NULL;
@@ -4007,24 +4366,42 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
        sa->rtime.sec = ct.tv_sec;
        sa->rtime.nsec = ct.tv_nsec;
 
+       received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid,
+                                      BTRFS_UUID_SIZE);
+       if (received_uuid_changed &&
+           !btrfs_is_empty_uuid(root_item->received_uuid))
+               btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root,
+                                   root_item->received_uuid,
+                                   BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                   root->root_key.objectid);
        memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE);
        btrfs_set_root_stransid(root_item, sa->stransid);
        btrfs_set_root_rtransid(root_item, sa->rtransid);
-       root_item->stime.sec = cpu_to_le64(sa->stime.sec);
-       root_item->stime.nsec = cpu_to_le32(sa->stime.nsec);
-       root_item->rtime.sec = cpu_to_le64(sa->rtime.sec);
-       root_item->rtime.nsec = cpu_to_le32(sa->rtime.nsec);
+       btrfs_set_stack_timespec_sec(&root_item->stime, sa->stime.sec);
+       btrfs_set_stack_timespec_nsec(&root_item->stime, sa->stime.nsec);
+       btrfs_set_stack_timespec_sec(&root_item->rtime, sa->rtime.sec);
+       btrfs_set_stack_timespec_nsec(&root_item->rtime, sa->rtime.nsec);
 
        ret = btrfs_update_root(trans, root->fs_info->tree_root,
                                &root->root_key, &root->root_item);
        if (ret < 0) {
                btrfs_end_transaction(trans, root);
-               trans = NULL;
                goto out;
-       } else {
-               ret = btrfs_commit_transaction(trans, root);
-               if (ret < 0)
+       }
+       if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) {
+               ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root,
+                                         sa->uuid,
+                                         BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                         root->root_key.objectid);
+               if (ret < 0 && ret != -EEXIST) {
+                       btrfs_abort_transaction(trans, root, ret);
                        goto out;
+               }
+       }
+       ret = btrfs_commit_transaction(trans, root);
+       if (ret < 0) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto out;
        }
 
        ret = copy_to_user(arg, sa, sizeof(*sa));
@@ -4041,18 +4418,22 @@ out:
 static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
 {
        struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
-       const char *label = root->fs_info->super_copy->label;
-       size_t len = strnlen(label, BTRFS_LABEL_SIZE);
+       size_t len;
        int ret;
+       char label[BTRFS_LABEL_SIZE];
+
+       spin_lock(&root->fs_info->super_lock);
+       memcpy(label, root->fs_info->super_copy->label, BTRFS_LABEL_SIZE);
+       spin_unlock(&root->fs_info->super_lock);
+
+       len = strnlen(label, BTRFS_LABEL_SIZE);
 
        if (len == BTRFS_LABEL_SIZE) {
                pr_warn("btrfs: label is too long, return the first %zu bytes\n",
                        --len);
        }
 
-       mutex_lock(&root->fs_info->volume_mutex);
        ret = copy_to_user(arg, label, len);
-       mutex_unlock(&root->fs_info->volume_mutex);
 
        return ret ? -EFAULT : 0;
 }
@@ -4081,18 +4462,18 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
        if (ret)
                return ret;
 
-       mutex_lock(&root->fs_info->volume_mutex);
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                goto out_unlock;
        }
 
+       spin_lock(&root->fs_info->super_lock);
        strcpy(super_block->label, label);
+       spin_unlock(&root->fs_info->super_lock);
        ret = btrfs_end_transaction(trans, root);
 
 out_unlock:
-       mutex_unlock(&root->fs_info->volume_mutex);
        mnt_drop_write_file(file);
        return ret;
 }
@@ -4207,6 +4588,8 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_get_fslabel(file, argp);
        case BTRFS_IOC_SET_FSLABEL:
                return btrfs_ioctl_set_fslabel(file, argp);
+       case BTRFS_IOC_FILE_EXTENT_SAME:
+               return btrfs_ioctl_file_extent_same(file, argp);
        }
 
        return -ENOTTY;
index f93151a98886d460bdf2c357c00a8c7613f2d08e..b6a6f07c5ce20fe4cecf6917497a6e705be26c9c 100644 (file)
@@ -207,8 +207,10 @@ static int lzo_compress_pages(struct list_head *ws,
                }
 
                /* we're making it bigger, give up */
-               if (tot_in > 8192 && tot_in < tot_out)
+               if (tot_in > 8192 && tot_in < tot_out) {
+                       ret = -1;
                        goto out;
+               }
 
                /* we're all done */
                if (tot_in >= len)
index 81369827e5146552edd7428911faef52ca3e1de6..966b413a33b800d096eda96d662bb3a66770145f 100644 (file)
@@ -67,7 +67,7 @@ static void ordered_data_tree_panic(struct inode *inode, int errno,
 {
        struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
        btrfs_panic(fs_info, errno, "Inconsistency in ordered tree at offset "
-                   "%llu\n", (unsigned long long)offset);
+                   "%llu\n", offset);
 }
 
 /*
@@ -205,6 +205,7 @@ static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset,
        entry->bytes_left = len;
        entry->inode = igrab(inode);
        entry->compress_type = compress_type;
+       entry->truncated_len = (u64)-1;
        if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE)
                set_bit(type, &entry->flags);
 
@@ -336,14 +337,12 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode,
        *file_offset = dec_end;
        if (dec_start > dec_end) {
                printk(KERN_CRIT "bad ordering dec_start %llu end %llu\n",
-                      (unsigned long long)dec_start,
-                      (unsigned long long)dec_end);
+                      dec_start, dec_end);
        }
        to_dec = dec_end - dec_start;
        if (to_dec > entry->bytes_left) {
                printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
-                      (unsigned long long)entry->bytes_left,
-                      (unsigned long long)to_dec);
+                      entry->bytes_left, to_dec);
        }
        entry->bytes_left -= to_dec;
        if (!uptodate)
@@ -403,8 +402,7 @@ have_entry:
 
        if (io_size > entry->bytes_left) {
                printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
-                      (unsigned long long)entry->bytes_left,
-                      (unsigned long long)io_size);
+                      entry->bytes_left, io_size);
        }
        entry->bytes_left -= io_size;
        if (!uptodate)
@@ -671,7 +669,7 @@ int btrfs_run_ordered_operations(struct btrfs_trans_handle *trans,
        INIT_LIST_HEAD(&splice);
        INIT_LIST_HEAD(&works);
 
-       mutex_lock(&root->fs_info->ordered_operations_mutex);
+       mutex_lock(&root->fs_info->ordered_extent_flush_mutex);
        spin_lock(&root->fs_info->ordered_root_lock);
        list_splice_init(&cur_trans->ordered_operations, &splice);
        while (!list_empty(&splice)) {
@@ -718,7 +716,7 @@ out:
                list_del_init(&work->list);
                btrfs_wait_and_free_delalloc_work(work);
        }
-       mutex_unlock(&root->fs_info->ordered_operations_mutex);
+       mutex_unlock(&root->fs_info->ordered_extent_flush_mutex);
        return ret;
 }
 
@@ -923,12 +921,16 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
        struct btrfs_ordered_extent *test;
        int ret = 1;
 
-       if (ordered)
+       spin_lock_irq(&tree->lock);
+       if (ordered) {
                offset = entry_end(ordered);
-       else
+               if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags))
+                       offset = min(offset,
+                                    ordered->file_offset +
+                                    ordered->truncated_len);
+       } else {
                offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize);
-
-       spin_lock_irq(&tree->lock);
+       }
        disk_i_size = BTRFS_I(inode)->disk_i_size;
 
        /* truncate file */
index 68844d59ee6f10e05403102fa1f53e87c270d030..d9a5aa097b4fea86cabf16e649e11775555de260 100644 (file)
@@ -69,6 +69,7 @@ struct btrfs_ordered_sum {
                                       * the isize. */
 #define BTRFS_ORDERED_LOGGED_CSUM 8 /* We've logged the csums on this ordered
                                       ordered extent */
+#define BTRFS_ORDERED_TRUNCATED 9 /* Set when we have to truncate an extent */
 
 struct btrfs_ordered_extent {
        /* logical offset in the file */
@@ -96,6 +97,12 @@ struct btrfs_ordered_extent {
         */
        u64 outstanding_isize;
 
+       /*
+        * If we get truncated we need to adjust the file extent we enter for
+        * this ordered extent so that we do not expose stale data.
+        */
+       u64 truncated_len;
+
        /* flags (described above) */
        unsigned long flags;
 
index dc0024f17c1f5a1a671ab4809d6ca5ae250464f4..0088bedc8631f6b5d1ca53924e894e55fa614397 100644 (file)
@@ -26,14 +26,12 @@ static void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk)
        int i;
        printk(KERN_INFO "\t\tchunk length %llu owner %llu type %llu "
               "num_stripes %d\n",
-              (unsigned long long)btrfs_chunk_length(eb, chunk),
-              (unsigned long long)btrfs_chunk_owner(eb, chunk),
-              (unsigned long long)btrfs_chunk_type(eb, chunk),
-              num_stripes);
+              btrfs_chunk_length(eb, chunk), btrfs_chunk_owner(eb, chunk),
+              btrfs_chunk_type(eb, chunk), num_stripes);
        for (i = 0 ; i < num_stripes ; i++) {
                printk(KERN_INFO "\t\t\tstripe %d devid %llu offset %llu\n", i,
-                     (unsigned long long)btrfs_stripe_devid_nr(eb, chunk, i),
-                     (unsigned long long)btrfs_stripe_offset_nr(eb, chunk, i));
+                     btrfs_stripe_devid_nr(eb, chunk, i),
+                     btrfs_stripe_offset_nr(eb, chunk, i));
        }
 }
 static void print_dev_item(struct extent_buffer *eb,
@@ -41,18 +39,18 @@ static void print_dev_item(struct extent_buffer *eb,
 {
        printk(KERN_INFO "\t\tdev item devid %llu "
               "total_bytes %llu bytes used %llu\n",
-              (unsigned long long)btrfs_device_id(eb, dev_item),
-              (unsigned long long)btrfs_device_total_bytes(eb, dev_item),
-              (unsigned long long)btrfs_device_bytes_used(eb, dev_item));
+              btrfs_device_id(eb, dev_item),
+              btrfs_device_total_bytes(eb, dev_item),
+              btrfs_device_bytes_used(eb, dev_item));
 }
 static void print_extent_data_ref(struct extent_buffer *eb,
                                  struct btrfs_extent_data_ref *ref)
 {
        printk(KERN_INFO "\t\textent data backref root %llu "
               "objectid %llu offset %llu count %u\n",
-              (unsigned long long)btrfs_extent_data_ref_root(eb, ref),
-              (unsigned long long)btrfs_extent_data_ref_objectid(eb, ref),
-              (unsigned long long)btrfs_extent_data_ref_offset(eb, ref),
+              btrfs_extent_data_ref_root(eb, ref),
+              btrfs_extent_data_ref_objectid(eb, ref),
+              btrfs_extent_data_ref_offset(eb, ref),
               btrfs_extent_data_ref_count(eb, ref));
 }
 
@@ -87,19 +85,17 @@ static void print_extent_item(struct extent_buffer *eb, int slot)
        flags = btrfs_extent_flags(eb, ei);
 
        printk(KERN_INFO "\t\textent refs %llu gen %llu flags %llu\n",
-              (unsigned long long)btrfs_extent_refs(eb, ei),
-              (unsigned long long)btrfs_extent_generation(eb, ei),
-              (unsigned long long)flags);
+              btrfs_extent_refs(eb, ei), btrfs_extent_generation(eb, ei),
+              flags);
 
        if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) {
                struct btrfs_tree_block_info *info;
                info = (struct btrfs_tree_block_info *)(ei + 1);
                btrfs_tree_block_key(eb, info, &key);
-               printk(KERN_INFO "\t\ttree block key (%llu %x %llu) "
+               printk(KERN_INFO "\t\ttree block key (%llu %u %llu) "
                       "level %d\n",
-                      (unsigned long long)btrfs_disk_key_objectid(&key),
-                      key.type,
-                      (unsigned long long)btrfs_disk_key_offset(&key),
+                      btrfs_disk_key_objectid(&key), key.type,
+                      btrfs_disk_key_offset(&key),
                       btrfs_tree_block_level(eb, info));
                iref = (struct btrfs_extent_inline_ref *)(info + 1);
        } else {
@@ -115,11 +111,11 @@ static void print_extent_item(struct extent_buffer *eb, int slot)
                switch (type) {
                case BTRFS_TREE_BLOCK_REF_KEY:
                        printk(KERN_INFO "\t\ttree block backref "
-                               "root %llu\n", (unsigned long long)offset);
+                               "root %llu\n", offset);
                        break;
                case BTRFS_SHARED_BLOCK_REF_KEY:
                        printk(KERN_INFO "\t\tshared block backref "
-                               "parent %llu\n", (unsigned long long)offset);
+                               "parent %llu\n", offset);
                        break;
                case BTRFS_EXTENT_DATA_REF_KEY:
                        dref = (struct btrfs_extent_data_ref *)(&iref->offset);
@@ -129,8 +125,7 @@ static void print_extent_item(struct extent_buffer *eb, int slot)
                        sref = (struct btrfs_shared_data_ref *)(iref + 1);
                        printk(KERN_INFO "\t\tshared data backref "
                               "parent %llu count %u\n",
-                              (unsigned long long)offset,
-                              btrfs_shared_data_ref_count(eb, sref));
+                              offset, btrfs_shared_data_ref_count(eb, sref));
                        break;
                default:
                        BUG();
@@ -148,13 +143,32 @@ static void print_extent_ref_v0(struct extent_buffer *eb, int slot)
        ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0);
        printk("\t\textent back ref root %llu gen %llu "
                "owner %llu num_refs %lu\n",
-               (unsigned long long)btrfs_ref_root_v0(eb, ref0),
-               (unsigned long long)btrfs_ref_generation_v0(eb, ref0),
-               (unsigned long long)btrfs_ref_objectid_v0(eb, ref0),
+               btrfs_ref_root_v0(eb, ref0),
+               btrfs_ref_generation_v0(eb, ref0),
+               btrfs_ref_objectid_v0(eb, ref0),
                (unsigned long)btrfs_ref_count_v0(eb, ref0));
 }
 #endif
 
+static void print_uuid_item(struct extent_buffer *l, unsigned long offset,
+                           u32 item_size)
+{
+       if (!IS_ALIGNED(item_size, sizeof(u64))) {
+               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                       (unsigned long)item_size);
+               return;
+       }
+       while (item_size) {
+               __le64 subvol_id;
+
+               read_extent_buffer(l, &subvol_id, offset, sizeof(subvol_id));
+               printk(KERN_INFO "\t\tsubvol_id %llu\n",
+                      (unsigned long long)le64_to_cpu(subvol_id));
+               item_size -= sizeof(u64);
+               offset += sizeof(u64);
+       }
+}
+
 void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
 {
        int i;
@@ -177,39 +191,34 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
        nr = btrfs_header_nritems(l);
 
        btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d",
-               (unsigned long long)btrfs_header_bytenr(l), nr,
-               btrfs_leaf_free_space(root, l));
+                  btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l));
        for (i = 0 ; i < nr ; i++) {
                item = btrfs_item_nr(l, i);
                btrfs_item_key_to_cpu(l, &key, i);
                type = btrfs_key_type(&key);
-               printk(KERN_INFO "\titem %d key (%llu %x %llu) itemoff %d "
+               printk(KERN_INFO "\titem %d key (%llu %u %llu) itemoff %d "
                       "itemsize %d\n",
-                       i,
-                       (unsigned long long)key.objectid, type,
-                       (unsigned long long)key.offset,
+                       i, key.objectid, type, key.offset,
                        btrfs_item_offset(l, item), btrfs_item_size(l, item));
                switch (type) {
                case BTRFS_INODE_ITEM_KEY:
                        ii = btrfs_item_ptr(l, i, struct btrfs_inode_item);
                        printk(KERN_INFO "\t\tinode generation %llu size %llu "
                               "mode %o\n",
-                              (unsigned long long)
                               btrfs_inode_generation(l, ii),
-                             (unsigned long long)btrfs_inode_size(l, ii),
+                              btrfs_inode_size(l, ii),
                               btrfs_inode_mode(l, ii));
                        break;
                case BTRFS_DIR_ITEM_KEY:
                        di = btrfs_item_ptr(l, i, struct btrfs_dir_item);
                        btrfs_dir_item_key_to_cpu(l, di, &found_key);
                        printk(KERN_INFO "\t\tdir oid %llu type %u\n",
-                               (unsigned long long)found_key.objectid,
+                               found_key.objectid,
                                btrfs_dir_type(l, di));
                        break;
                case BTRFS_ROOT_ITEM_KEY:
                        ri = btrfs_item_ptr(l, i, struct btrfs_root_item);
                        printk(KERN_INFO "\t\troot data bytenr %llu refs %u\n",
-                               (unsigned long long)
                                btrfs_disk_root_bytenr(l, ri),
                                btrfs_disk_root_refs(l, ri));
                        break;
@@ -245,17 +254,12 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
                        }
                        printk(KERN_INFO "\t\textent data disk bytenr %llu "
                               "nr %llu\n",
-                              (unsigned long long)
                               btrfs_file_extent_disk_bytenr(l, fi),
-                              (unsigned long long)
                               btrfs_file_extent_disk_num_bytes(l, fi));
                        printk(KERN_INFO "\t\textent data offset %llu "
                               "nr %llu ram %llu\n",
-                              (unsigned long long)
                               btrfs_file_extent_offset(l, fi),
-                              (unsigned long long)
                               btrfs_file_extent_num_bytes(l, fi),
-                              (unsigned long long)
                               btrfs_file_extent_ram_bytes(l, fi));
                        break;
                case BTRFS_EXTENT_REF_V0_KEY:
@@ -269,7 +273,6 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
                        bi = btrfs_item_ptr(l, i,
                                            struct btrfs_block_group_item);
                        printk(KERN_INFO "\t\tblock group used %llu\n",
-                              (unsigned long long)
                               btrfs_disk_block_group_used(l, bi));
                        break;
                case BTRFS_CHUNK_ITEM_KEY:
@@ -286,13 +289,9 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
                        printk(KERN_INFO "\t\tdev extent chunk_tree %llu\n"
                               "\t\tchunk objectid %llu chunk offset %llu "
                               "length %llu\n",
-                              (unsigned long long)
                               btrfs_dev_extent_chunk_tree(l, dev_extent),
-                              (unsigned long long)
                               btrfs_dev_extent_chunk_objectid(l, dev_extent),
-                              (unsigned long long)
                               btrfs_dev_extent_chunk_offset(l, dev_extent),
-                              (unsigned long long)
                               btrfs_dev_extent_length(l, dev_extent));
                        break;
                case BTRFS_DEV_STATS_KEY:
@@ -301,6 +300,11 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
                case BTRFS_DEV_REPLACE_KEY:
                        printk(KERN_INFO "\t\tdev replace\n");
                        break;
+               case BTRFS_UUID_KEY_SUBVOL:
+               case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
+                       print_uuid_item(l, btrfs_item_ptr_offset(l, i),
+                                       btrfs_item_size_nr(l, i));
+                       break;
                };
        }
 }
@@ -320,16 +324,13 @@ void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c)
                return;
        }
        btrfs_info(root->fs_info, "node %llu level %d total ptrs %d free spc %u",
-               (unsigned long long)btrfs_header_bytenr(c),
-               level, nr, (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr);
+               btrfs_header_bytenr(c), level, nr,
+               (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr);
        for (i = 0; i < nr; i++) {
                btrfs_node_key_to_cpu(c, &key, i);
                printk(KERN_INFO "\tkey %d (%llu %u %llu) block %llu\n",
-                      i,
-                      (unsigned long long)key.objectid,
-                      key.type,
-                      (unsigned long long)key.offset,
-                      (unsigned long long)btrfs_node_blockptr(c, i));
+                      i, key.objectid, key.type, key.offset,
+                      btrfs_node_blockptr(c, i));
        }
        for (i = 0; i < nr; i++) {
                struct extent_buffer *next = read_tree_block(root,
index 1280eff8af56989dcc4a00e822527bd31ce2b3f9..4e6ef490619e59b90fb64bf2cca251d6f11eae80 100644 (file)
@@ -157,18 +157,11 @@ static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info,
        return qgroup;
 }
 
-/* must be called with qgroup_lock held */
-static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid)
+static void __del_qgroup_rb(struct btrfs_qgroup *qgroup)
 {
-       struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid);
        struct btrfs_qgroup_list *list;
 
-       if (!qgroup)
-               return -ENOENT;
-
-       rb_erase(&qgroup->node, &fs_info->qgroup_tree);
        list_del(&qgroup->dirty);
-
        while (!list_empty(&qgroup->groups)) {
                list = list_first_entry(&qgroup->groups,
                                        struct btrfs_qgroup_list, next_group);
@@ -185,7 +178,18 @@ static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid)
                kfree(list);
        }
        kfree(qgroup);
+}
 
+/* must be called with qgroup_lock held */
+static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid)
+{
+       struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid);
+
+       if (!qgroup)
+               return -ENOENT;
+
+       rb_erase(&qgroup->node, &fs_info->qgroup_tree);
+       __del_qgroup_rb(qgroup);
        return 0;
 }
 
@@ -394,8 +398,7 @@ next1:
                if (ret == -ENOENT) {
                        printk(KERN_WARNING
                                "btrfs: orphan qgroup relation 0x%llx->0x%llx\n",
-                               (unsigned long long)found_key.objectid,
-                               (unsigned long long)found_key.offset);
+                               found_key.objectid, found_key.offset);
                        ret = 0;        /* ignore the error */
                }
                if (ret)
@@ -428,39 +431,28 @@ out:
 }
 
 /*
- * This is only called from close_ctree() or open_ctree(), both in single-
- * treaded paths. Clean up the in-memory structures. No locking needed.
+ * This is called from close_ctree() or open_ctree() or btrfs_quota_disable(),
+ * first two are in single-threaded paths.And for the third one, we have set
+ * quota_root to be null with qgroup_lock held before, so it is safe to clean
+ * up the in-memory structures without qgroup_lock held.
  */
 void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info)
 {
        struct rb_node *n;
        struct btrfs_qgroup *qgroup;
-       struct btrfs_qgroup_list *list;
 
        while ((n = rb_first(&fs_info->qgroup_tree))) {
                qgroup = rb_entry(n, struct btrfs_qgroup, node);
                rb_erase(n, &fs_info->qgroup_tree);
-
-               while (!list_empty(&qgroup->groups)) {
-                       list = list_first_entry(&qgroup->groups,
-                                               struct btrfs_qgroup_list,
-                                               next_group);
-                       list_del(&list->next_group);
-                       list_del(&list->next_member);
-                       kfree(list);
-               }
-
-               while (!list_empty(&qgroup->members)) {
-                       list = list_first_entry(&qgroup->members,
-                                               struct btrfs_qgroup_list,
-                                               next_member);
-                       list_del(&list->next_group);
-                       list_del(&list->next_member);
-                       kfree(list);
-               }
-               kfree(qgroup);
+               __del_qgroup_rb(qgroup);
        }
+       /*
+        * we call btrfs_free_qgroup_config() when umounting
+        * filesystem and disabling quota, so we set qgroup_ulit
+        * to be null here to avoid double free.
+        */
        ulist_free(fs_info->qgroup_ulist);
+       fs_info->qgroup_ulist = NULL;
 }
 
 static int add_qgroup_relation_item(struct btrfs_trans_handle *trans,
@@ -946,13 +938,9 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
        fs_info->pending_quota_state = 0;
        quota_root = fs_info->quota_root;
        fs_info->quota_root = NULL;
-       btrfs_free_qgroup_config(fs_info);
        spin_unlock(&fs_info->qgroup_lock);
 
-       if (!quota_root) {
-               ret = -EINVAL;
-               goto out;
-       }
+       btrfs_free_qgroup_config(fs_info);
 
        ret = btrfs_clean_quota_tree(trans, quota_root);
        if (ret)
@@ -1174,7 +1162,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
        if (ret) {
                fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
                printk(KERN_INFO "unable to update quota limit for %llu\n",
-                      (unsigned long long)qgroupid);
+                      qgroupid);
        }
 
        spin_lock(&fs_info->qgroup_lock);
@@ -1884,10 +1872,9 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
                                         path, 1, 0);
 
        pr_debug("current progress key (%llu %u %llu), search_slot ret %d\n",
-                (unsigned long long)fs_info->qgroup_rescan_progress.objectid,
+                fs_info->qgroup_rescan_progress.objectid,
                 fs_info->qgroup_rescan_progress.type,
-                (unsigned long long)fs_info->qgroup_rescan_progress.offset,
-                ret);
+                fs_info->qgroup_rescan_progress.offset, ret);
 
        if (ret) {
                /*
index 0525e1389f5b16658ccea028da6408da812c974b..d0ecfbd9cc9fc5e07a23173b0d1482d5eb9fb75d 100644 (file)
@@ -1540,8 +1540,10 @@ static int full_stripe_write(struct btrfs_raid_bio *rbio)
        int ret;
 
        ret = alloc_rbio_parity_pages(rbio);
-       if (ret)
+       if (ret) {
+               __free_raid_bio(rbio);
                return ret;
+       }
 
        ret = lock_stripe_add(rbio);
        if (ret == 0)
@@ -1687,11 +1689,8 @@ int raid56_parity_write(struct btrfs_root *root, struct bio *bio,
        struct blk_plug_cb *cb;
 
        rbio = alloc_rbio(root, bbio, raid_map, stripe_len);
-       if (IS_ERR(rbio)) {
-               kfree(raid_map);
-               kfree(bbio);
+       if (IS_ERR(rbio))
                return PTR_ERR(rbio);
-       }
        bio_list_add(&rbio->bio_list, bio);
        rbio->bio_list_bytes = bio->bi_size;
 
@@ -2041,9 +2040,8 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio,
        int ret;
 
        rbio = alloc_rbio(root, bbio, raid_map, stripe_len);
-       if (IS_ERR(rbio)) {
+       if (IS_ERR(rbio))
                return PTR_ERR(rbio);
-       }
 
        rbio->read_rebuild = 1;
        bio_list_add(&rbio->bio_list, bio);
@@ -2052,6 +2050,8 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio,
        rbio->faila = find_logical_bio_stripe(rbio, bio);
        if (rbio->faila == -1) {
                BUG();
+               kfree(raid_map);
+               kfree(bbio);
                kfree(rbio);
                return -EIO;
        }
index 12096496cc99eb24e6412ebc3ed5780f0e2b2430..aacc2121e87c5df2f7dac46e90daca2514a7912f 100644 (file)
@@ -335,7 +335,7 @@ static void backref_tree_panic(struct rb_node *rb_node, int errno, u64 bytenr)
        if (bnode->root)
                fs_info = bnode->root->fs_info;
        btrfs_panic(fs_info, errno, "Inconsistency in backref cache "
-                   "found at offset %llu\n", (unsigned long long)bytenr);
+                   "found at offset %llu\n", bytenr);
 }
 
 /*
@@ -641,6 +641,11 @@ int find_inline_backref(struct extent_buffer *leaf, int slot,
                WARN_ON(item_size < sizeof(*ei) + sizeof(*bi));
                return 1;
        }
+       if (key.type == BTRFS_METADATA_ITEM_KEY &&
+           item_size <= sizeof(*ei)) {
+               WARN_ON(item_size < sizeof(*ei));
+               return 1;
+       }
 
        if (key.type == BTRFS_EXTENT_ITEM_KEY) {
                bi = (struct btrfs_tree_block_info *)(ei + 1);
@@ -691,6 +696,7 @@ struct backref_node *build_backref_tree(struct reloc_control *rc,
        int cowonly;
        int ret;
        int err = 0;
+       bool need_check = true;
 
        path1 = btrfs_alloc_path();
        path2 = btrfs_alloc_path();
@@ -914,6 +920,7 @@ again:
                        cur->bytenr);
 
                lower = cur;
+               need_check = true;
                for (; level < BTRFS_MAX_LEVEL; level++) {
                        if (!path2->nodes[level]) {
                                BUG_ON(btrfs_root_bytenr(&root->root_item) !=
@@ -957,14 +964,12 @@ again:
 
                                /*
                                 * add the block to pending list if we
-                                * need check its backrefs. only block
-                                * at 'cur->level + 1' is added to the
-                                * tail of pending list. this guarantees
-                                * we check backrefs from lower level
-                                * blocks to upper level blocks.
+                                * need check its backrefs, we only do this once
+                                * while walking up a tree as we will catch
+                                * anything else later on.
                                 */
-                               if (!upper->checked &&
-                                   level == cur->level + 1) {
+                               if (!upper->checked && need_check) {
+                                       need_check = false;
                                        list_add_tail(&edge->list[UPPER],
                                                      &list);
                                } else
@@ -2314,8 +2319,13 @@ again:
                        BUG_ON(root->reloc_root != reloc_root);
 
                        ret = merge_reloc_root(rc, root);
-                       if (ret)
+                       if (ret) {
+                               __update_reloc_root(reloc_root, 1);
+                               free_extent_buffer(reloc_root->node);
+                               free_extent_buffer(reloc_root->commit_root);
+                               kfree(reloc_root);
                                goto out;
+                       }
                } else {
                        list_del_init(&reloc_root->root_list);
                }
@@ -2344,9 +2354,6 @@ again:
                        if (IS_ERR(root))
                                continue;
 
-                       if (btrfs_root_refs(&root->root_item) == 0)
-                               continue;
-
                        trans = btrfs_join_transaction(root);
                        BUG_ON(IS_ERR(trans));
 
@@ -3628,7 +3635,7 @@ int add_data_references(struct reloc_control *rc,
        unsigned long ptr;
        unsigned long end;
        u32 blocksize = btrfs_level_size(rc->extent_root, 0);
-       int ret;
+       int ret = 0;
        int err = 0;
 
        eb = path->nodes[0];
@@ -3655,6 +3662,10 @@ int add_data_references(struct reloc_control *rc,
                } else {
                        BUG();
                }
+               if (ret) {
+                       err = ret;
+                       goto out;
+               }
                ptr += btrfs_extent_inline_ref_size(key.type);
        }
        WARN_ON(ptr > end);
@@ -3700,6 +3711,7 @@ int add_data_references(struct reloc_control *rc,
                }
                path->slots[0]++;
        }
+out:
        btrfs_release_path(path);
        if (err)
                free_block_list(blocks);
@@ -4219,8 +4231,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
        }
 
        printk(KERN_INFO "btrfs: relocating block group %llu flags %llu\n",
-              (unsigned long long)rc->block_group->key.objectid,
-              (unsigned long long)rc->block_group->flags);
+              rc->block_group->key.objectid, rc->block_group->flags);
 
        ret = btrfs_start_all_delalloc_inodes(fs_info, 0);
        if (ret < 0) {
@@ -4242,7 +4253,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
                        break;
 
                printk(KERN_INFO "btrfs: found %llu extents\n",
-                       (unsigned long long)rc->extents_found);
+                       rc->extents_found);
 
                if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) {
                        btrfs_wait_ordered_range(rc->data_inode, 0, (u64)-1);
index ffb1036ef10db97f31bfa4c00ca7c36a45d09e4f..0b1f4ef8db987da12951128f092a052018d5c6b9 100644 (file)
@@ -29,8 +29,8 @@
  * generation numbers as then we know the root was once mounted with an older
  * kernel that was not aware of the root item structure change.
  */
-void btrfs_read_root_item(struct extent_buffer *eb, int slot,
-                         struct btrfs_root_item *item)
+static void btrfs_read_root_item(struct extent_buffer *eb, int slot,
+                               struct btrfs_root_item *item)
 {
        uuid_le uuid;
        int len;
@@ -155,8 +155,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
        if (ret != 0) {
                btrfs_print_leaf(root, path->nodes[0]);
                printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
-                      (unsigned long long)key->objectid, key->type,
-                      (unsigned long long)key->offset);
+                      key->objectid, key->type, key->offset);
                BUG_ON(1);
        }
 
@@ -490,13 +489,13 @@ again:
  */
 void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item)
 {
-       u64 inode_flags = le64_to_cpu(root_item->inode.flags);
+       u64 inode_flags = btrfs_stack_inode_flags(&root_item->inode);
 
        if (!(inode_flags & BTRFS_INODE_ROOT_ITEM_INIT)) {
                inode_flags |= BTRFS_INODE_ROOT_ITEM_INIT;
-               root_item->inode.flags = cpu_to_le64(inode_flags);
-               root_item->flags = 0;
-               root_item->byte_limit = 0;
+               btrfs_set_stack_inode_flags(&root_item->inode, inode_flags);
+               btrfs_set_root_flags(root_item, 0);
+               btrfs_set_root_limit(root_item, 0);
        }
 }
 
@@ -507,8 +506,8 @@ void btrfs_update_root_times(struct btrfs_trans_handle *trans,
        struct timespec ct = CURRENT_TIME;
 
        spin_lock(&root->root_item_lock);
-       item->ctransid = cpu_to_le64(trans->transid);
-       item->ctime.sec = cpu_to_le64(ct.tv_sec);
-       item->ctime.nsec = cpu_to_le32(ct.tv_nsec);
+       btrfs_set_root_ctransid(item, trans->transid);
+       btrfs_set_stack_timespec_sec(&item->ctime, ct.tv_sec);
+       btrfs_set_stack_timespec_nsec(&item->ctime, ct.tv_nsec);
        spin_unlock(&root->root_item_lock);
 }
index 64a157becbe573f778c02e9475483cff5e167ea9..0afcd452fcb3d62c9804089ef1cb056687917784 100644 (file)
@@ -754,8 +754,7 @@ out:
                        num_uncorrectable_read_errors);
                printk_ratelimited_in_rcu(KERN_ERR
                        "btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n",
-                       (unsigned long long)fixup->logical,
-                       rcu_str_deref(fixup->dev->name));
+                       fixup->logical, rcu_str_deref(fixup->dev->name));
        }
 
        btrfs_free_path(path);
@@ -1154,8 +1153,7 @@ corrected_error:
                        spin_unlock(&sctx->stat_lock);
                        printk_ratelimited_in_rcu(KERN_ERR
                                "btrfs: fixed up error at logical %llu on dev %s\n",
-                               (unsigned long long)logical,
-                               rcu_str_deref(dev->name));
+                               logical, rcu_str_deref(dev->name));
                }
        } else {
 did_not_correct_error:
@@ -1164,8 +1162,7 @@ did_not_correct_error:
                spin_unlock(&sctx->stat_lock);
                printk_ratelimited_in_rcu(KERN_ERR
                        "btrfs: unable to fixup (regular) error at logical %llu on dev %s\n",
-                       (unsigned long long)logical,
-                       rcu_str_deref(dev->name));
+                       logical, rcu_str_deref(dev->name));
        }
 
 out:
@@ -1345,12 +1342,12 @@ static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
                mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
                h = (struct btrfs_header *)mapped_buffer;
 
-               if (sblock->pagev[0]->logical != le64_to_cpu(h->bytenr) ||
+               if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h) ||
                    memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE) ||
                    memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
                           BTRFS_UUID_SIZE)) {
                        sblock->header_error = 1;
-               } else if (generation != le64_to_cpu(h->generation)) {
+               } else if (generation != btrfs_stack_header_generation(h)) {
                        sblock->header_error = 1;
                        sblock->generation_error = 1;
                }
@@ -1720,10 +1717,10 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
         * b) the page is already kmapped
         */
 
-       if (sblock->pagev[0]->logical != le64_to_cpu(h->bytenr))
+       if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h))
                ++fail;
 
-       if (sblock->pagev[0]->generation != le64_to_cpu(h->generation))
+       if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h))
                ++fail;
 
        if (memcmp(h->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
@@ -1786,10 +1783,10 @@ static int scrub_checksum_super(struct scrub_block *sblock)
        s = (struct btrfs_super_block *)mapped_buffer;
        memcpy(on_disk_csum, s->csum, sctx->csum_size);
 
-       if (sblock->pagev[0]->logical != le64_to_cpu(s->bytenr))
+       if (sblock->pagev[0]->logical != btrfs_super_bytenr(s))
                ++fail_cor;
 
-       if (sblock->pagev[0]->generation != le64_to_cpu(s->generation))
+       if (sblock->pagev[0]->generation != btrfs_super_generation(s))
                ++fail_gen;
 
        if (memcmp(s->fsid, fs_info->fsid, BTRFS_UUID_SIZE))
@@ -2455,8 +2452,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
                                printk(KERN_ERR
                                       "btrfs scrub: tree block %llu spanning "
                                       "stripes, ignored. logical=%llu\n",
-                                      (unsigned long long)key.objectid,
-                                      (unsigned long long)logical);
+                                      key.objectid, logical);
                                goto next;
                        }
 
@@ -2863,9 +2859,8 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
        if (fs_info->chunk_root->sectorsize != PAGE_SIZE) {
                /* not supported for data w/o checksums */
                printk(KERN_ERR
-                      "btrfs_scrub: size assumption sectorsize != PAGE_SIZE (%d != %lld) fails\n",
-                      fs_info->chunk_root->sectorsize,
-                      (unsigned long long)PAGE_SIZE);
+                      "btrfs_scrub: size assumption sectorsize != PAGE_SIZE (%d != %lu) fails\n",
+                      fs_info->chunk_root->sectorsize, PAGE_SIZE);
                return -EINVAL;
        }
 
@@ -3175,11 +3170,9 @@ static void copy_nocow_pages_worker(struct btrfs_work *work)
                                          copy_nocow_pages_for_inode,
                                          nocow_ctx);
        if (ret != 0 && ret != -ENOENT) {
-               pr_warn("iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %llu, ret %d\n",
-                       (unsigned long long)logical,
-                       (unsigned long long)physical_for_dev_replace,
-                       (unsigned long long)len,
-                       (unsigned long long)mirror_num, ret);
+               pr_warn("iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %u, ret %d\n",
+                       logical, physical_for_dev_replace, len, mirror_num,
+                       ret);
                not_written = 1;
                goto out;
        }
@@ -3224,11 +3217,6 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, void *ctx)
                return PTR_ERR(local_root);
        }
 
-       if (btrfs_root_refs(&local_root->root_item) == 0) {
-               srcu_read_unlock(&fs_info->subvol_srcu, srcu_index);
-               return -ENOENT;
-       }
-
        key.type = BTRFS_INODE_ITEM_KEY;
        key.objectid = inum;
        key.offset = 0;
index 2e14fd89a8b46e80622168ef30b9ac206b4b6a04..e46e0ed7492555646e58659f4cbb4c94ddf4c4d1 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/radix-tree.h>
 #include <linux/crc32c.h>
 #include <linux/vmalloc.h>
+#include <linux/string.h>
 
 #include "send.h"
 #include "backref.h"
@@ -54,8 +55,8 @@ struct fs_path {
 
                        char *buf;
                        int buf_len;
-                       int reversed:1;
-                       int virtual_mem:1;
+                       unsigned int reversed:1;
+                       unsigned int virtual_mem:1;
                        char inline_buf[];
                };
                char pad[PAGE_SIZE];
@@ -1668,6 +1669,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
                              u64 *who_ino, u64 *who_gen)
 {
        int ret = 0;
+       u64 gen;
        u64 other_inode = 0;
        u8 other_type = 0;
 
@@ -1678,6 +1680,24 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
        if (ret <= 0)
                goto out;
 
+       /*
+        * If we have a parent root we need to verify that the parent dir was
+        * not delted and then re-created, if it was then we have no overwrite
+        * and we can just unlink this entry.
+        */
+       if (sctx->parent_root) {
+               ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL,
+                                    NULL, NULL, NULL);
+               if (ret < 0 && ret != -ENOENT)
+                       goto out;
+               if (ret) {
+                       ret = 0;
+                       goto out;
+               }
+               if (gen != dir_gen)
+                       goto out;
+       }
+
        ret = lookup_dir_item_inode(sctx->parent_root, dir, name, name_len,
                        &other_inode, &other_type);
        if (ret < 0 && ret != -ENOENT)
@@ -2519,7 +2539,8 @@ static int did_create_dir(struct send_ctx *sctx, u64 dir)
                di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item);
                btrfs_dir_item_key_to_cpu(eb, di, &di_key);
 
-               if (di_key.objectid < sctx->send_progress) {
+               if (di_key.type != BTRFS_ROOT_ITEM_KEY &&
+                   di_key.objectid < sctx->send_progress) {
                        ret = 1;
                        goto out;
                }
@@ -2581,7 +2602,6 @@ static int record_ref(struct list_head *head, u64 dir,
                      u64 dir_gen, struct fs_path *path)
 {
        struct recorded_ref *ref;
-       char *tmp;
 
        ref = kmalloc(sizeof(*ref), GFP_NOFS);
        if (!ref)
@@ -2591,25 +2611,35 @@ static int record_ref(struct list_head *head, u64 dir,
        ref->dir_gen = dir_gen;
        ref->full_path = path;
 
-       tmp = strrchr(ref->full_path->start, '/');
-       if (!tmp) {
-               ref->name_len = ref->full_path->end - ref->full_path->start;
-               ref->name = ref->full_path->start;
+       ref->name = (char *)kbasename(ref->full_path->start);
+       ref->name_len = ref->full_path->end - ref->name;
+       ref->dir_path = ref->full_path->start;
+       if (ref->name == ref->full_path->start)
                ref->dir_path_len = 0;
-               ref->dir_path = ref->full_path->start;
-       } else {
-               tmp++;
-               ref->name_len = ref->full_path->end - tmp;
-               ref->name = tmp;
-               ref->dir_path = ref->full_path->start;
+       else
                ref->dir_path_len = ref->full_path->end -
                                ref->full_path->start - 1 - ref->name_len;
-       }
 
        list_add_tail(&ref->list, head);
        return 0;
 }
 
+static int dup_ref(struct recorded_ref *ref, struct list_head *list)
+{
+       struct recorded_ref *new;
+
+       new = kmalloc(sizeof(*ref), GFP_NOFS);
+       if (!new)
+               return -ENOMEM;
+
+       new->dir = ref->dir;
+       new->dir_gen = ref->dir_gen;
+       new->full_path = NULL;
+       INIT_LIST_HEAD(&new->list);
+       list_add_tail(&new->list, list);
+       return 0;
+}
+
 static void __free_recorded_refs(struct list_head *head)
 {
        struct recorded_ref *cur;
@@ -2724,9 +2754,7 @@ static int process_recorded_refs(struct send_ctx *sctx)
        int ret = 0;
        struct recorded_ref *cur;
        struct recorded_ref *cur2;
-       struct ulist *check_dirs = NULL;
-       struct ulist_iterator uit;
-       struct ulist_node *un;
+       struct list_head check_dirs;
        struct fs_path *valid_path = NULL;
        u64 ow_inode = 0;
        u64 ow_gen;
@@ -2740,6 +2768,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
         * which is always '..'
         */
        BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID);
+       INIT_LIST_HEAD(&check_dirs);
 
        valid_path = fs_path_alloc();
        if (!valid_path) {
@@ -2747,12 +2776,6 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                goto out;
        }
 
-       check_dirs = ulist_alloc(GFP_NOFS);
-       if (!check_dirs) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
        /*
         * First, check if the first ref of the current inode was overwritten
         * before. If yes, we know that the current inode was already orphanized
@@ -2889,8 +2912,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                                        goto out;
                        }
                }
-               ret = ulist_add(check_dirs, cur->dir, cur->dir_gen,
-                               GFP_NOFS);
+               ret = dup_ref(cur, &check_dirs);
                if (ret < 0)
                        goto out;
        }
@@ -2918,8 +2940,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                }
 
                list_for_each_entry(cur, &sctx->deleted_refs, list) {
-                       ret = ulist_add(check_dirs, cur->dir, cur->dir_gen,
-                                       GFP_NOFS);
+                       ret = dup_ref(cur, &check_dirs);
                        if (ret < 0)
                                goto out;
                }
@@ -2930,8 +2951,7 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                 */
                cur = list_entry(sctx->deleted_refs.next, struct recorded_ref,
                                list);
-               ret = ulist_add(check_dirs, cur->dir, cur->dir_gen,
-                               GFP_NOFS);
+               ret = dup_ref(cur, &check_dirs);
                if (ret < 0)
                        goto out;
        } else if (!S_ISDIR(sctx->cur_inode_mode)) {
@@ -2951,12 +2971,10 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                                if (ret < 0)
                                        goto out;
                        }
-                       ret = ulist_add(check_dirs, cur->dir, cur->dir_gen,
-                                       GFP_NOFS);
+                       ret = dup_ref(cur, &check_dirs);
                        if (ret < 0)
                                goto out;
                }
-
                /*
                 * If the inode is still orphan, unlink the orphan. This may
                 * happen when a previous inode did overwrite the first ref
@@ -2978,33 +2996,32 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
         * deletion and if it's finally possible to perform the rmdir now.
         * We also update the inode stats of the parent dirs here.
         */
-       ULIST_ITER_INIT(&uit);
-       while ((un = ulist_next(check_dirs, &uit))) {
+       list_for_each_entry(cur, &check_dirs, list) {
                /*
                 * In case we had refs into dirs that were not processed yet,
                 * we don't need to do the utime and rmdir logic for these dirs.
                 * The dir will be processed later.
                 */
-               if (un->val > sctx->cur_ino)
+               if (cur->dir > sctx->cur_ino)
                        continue;
 
-               ret = get_cur_inode_state(sctx, un->val, un->aux);
+               ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen);
                if (ret < 0)
                        goto out;
 
                if (ret == inode_state_did_create ||
                    ret == inode_state_no_change) {
                        /* TODO delayed utimes */
-                       ret = send_utimes(sctx, un->val, un->aux);
+                       ret = send_utimes(sctx, cur->dir, cur->dir_gen);
                        if (ret < 0)
                                goto out;
                } else if (ret == inode_state_did_delete) {
-                       ret = can_rmdir(sctx, un->val, sctx->cur_ino);
+                       ret = can_rmdir(sctx, cur->dir, sctx->cur_ino);
                        if (ret < 0)
                                goto out;
                        if (ret) {
-                               ret = get_cur_path(sctx, un->val, un->aux,
-                                               valid_path);
+                               ret = get_cur_path(sctx, cur->dir,
+                                                  cur->dir_gen, valid_path);
                                if (ret < 0)
                                        goto out;
                                ret = send_rmdir(sctx, valid_path);
@@ -3017,8 +3034,8 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
        ret = 0;
 
 out:
+       __free_recorded_refs(&check_dirs);
        free_recorded_refs(sctx);
-       ulist_free(check_dirs);
        fs_path_free(valid_path);
        return ret;
 }
@@ -3119,6 +3136,8 @@ out:
 
 struct find_ref_ctx {
        u64 dir;
+       u64 dir_gen;
+       struct btrfs_root *root;
        struct fs_path *name;
        int found_idx;
 };
@@ -3128,9 +3147,21 @@ static int __find_iref(int num, u64 dir, int index,
                       void *ctx_)
 {
        struct find_ref_ctx *ctx = ctx_;
+       u64 dir_gen;
+       int ret;
 
        if (dir == ctx->dir && fs_path_len(name) == fs_path_len(ctx->name) &&
            strncmp(name->start, ctx->name->start, fs_path_len(name)) == 0) {
+               /*
+                * To avoid doing extra lookups we'll only do this if everything
+                * else matches.
+                */
+               ret = get_inode_info(ctx->root, dir, NULL, &dir_gen, NULL,
+                                    NULL, NULL, NULL);
+               if (ret)
+                       return ret;
+               if (dir_gen != ctx->dir_gen)
+                       return 0;
                ctx->found_idx = num;
                return 1;
        }
@@ -3140,14 +3171,16 @@ static int __find_iref(int num, u64 dir, int index,
 static int find_iref(struct btrfs_root *root,
                     struct btrfs_path *path,
                     struct btrfs_key *key,
-                    u64 dir, struct fs_path *name)
+                    u64 dir, u64 dir_gen, struct fs_path *name)
 {
        int ret;
        struct find_ref_ctx ctx;
 
        ctx.dir = dir;
        ctx.name = name;
+       ctx.dir_gen = dir_gen;
        ctx.found_idx = -1;
+       ctx.root = root;
 
        ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx);
        if (ret < 0)
@@ -3163,11 +3196,17 @@ static int __record_changed_new_ref(int num, u64 dir, int index,
                                    struct fs_path *name,
                                    void *ctx)
 {
+       u64 dir_gen;
        int ret;
        struct send_ctx *sctx = ctx;
 
+       ret = get_inode_info(sctx->send_root, dir, NULL, &dir_gen, NULL,
+                            NULL, NULL, NULL);
+       if (ret)
+               return ret;
+
        ret = find_iref(sctx->parent_root, sctx->right_path,
-                       sctx->cmp_key, dir, name);
+                       sctx->cmp_key, dir, dir_gen, name);
        if (ret == -ENOENT)
                ret = __record_new_ref(num, dir, index, name, sctx);
        else if (ret > 0)
@@ -3180,11 +3219,17 @@ static int __record_changed_deleted_ref(int num, u64 dir, int index,
                                        struct fs_path *name,
                                        void *ctx)
 {
+       u64 dir_gen;
        int ret;
        struct send_ctx *sctx = ctx;
 
+       ret = get_inode_info(sctx->parent_root, dir, NULL, &dir_gen, NULL,
+                            NULL, NULL, NULL);
+       if (ret)
+               return ret;
+
        ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key,
-                       dir, name);
+                       dir, dir_gen, name);
        if (ret == -ENOENT)
                ret = __record_deleted_ref(num, dir, index, name, sctx);
        else if (ret > 0)
@@ -3869,7 +3914,8 @@ static int is_extent_unchanged(struct send_ctx *sctx,
        btrfs_item_key_to_cpu(eb, &found_key, slot);
        if (found_key.objectid != key.objectid ||
            found_key.type != key.type) {
-               ret = 0;
+               /* If we're a hole then just pretend nothing changed */
+               ret = (left_disknr) ? 0 : 1;
                goto out;
        }
 
@@ -3895,7 +3941,8 @@ static int is_extent_unchanged(struct send_ctx *sctx,
                 * This may only happen on the first iteration.
                 */
                if (found_key.offset + right_len <= ekey->offset) {
-                       ret = 0;
+                       /* If we're a hole just pretend nothing changed */
+                       ret = (left_disknr) ? 0 : 1;
                        goto out;
                }
 
@@ -3960,8 +4007,8 @@ static int process_extent(struct send_ctx *sctx,
                          struct btrfs_path *path,
                          struct btrfs_key *key)
 {
-       int ret = 0;
        struct clone_root *found_clone = NULL;
+       int ret = 0;
 
        if (S_ISLNK(sctx->cur_inode_mode))
                return 0;
@@ -3974,6 +4021,32 @@ static int process_extent(struct send_ctx *sctx,
                        ret = 0;
                        goto out;
                }
+       } else {
+               struct btrfs_file_extent_item *ei;
+               u8 type;
+
+               ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                                   struct btrfs_file_extent_item);
+               type = btrfs_file_extent_type(path->nodes[0], ei);
+               if (type == BTRFS_FILE_EXTENT_PREALLOC ||
+                   type == BTRFS_FILE_EXTENT_REG) {
+                       /*
+                        * The send spec does not have a prealloc command yet,
+                        * so just leave a hole for prealloc'ed extents until
+                        * we have enough commands queued up to justify rev'ing
+                        * the send spec.
+                        */
+                       if (type == BTRFS_FILE_EXTENT_PREALLOC) {
+                               ret = 0;
+                               goto out;
+                       }
+
+                       /* Have a hole, just skip it. */
+                       if (btrfs_file_extent_disk_bytenr(path->nodes[0], ei) == 0) {
+                               ret = 0;
+                               goto out;
+                       }
+               }
        }
 
        ret = find_extent_clone(sctx, path, key->objectid, key->offset,
@@ -4361,6 +4434,64 @@ static int changed_extent(struct send_ctx *sctx,
        return ret;
 }
 
+static int dir_changed(struct send_ctx *sctx, u64 dir)
+{
+       u64 orig_gen, new_gen;
+       int ret;
+
+       ret = get_inode_info(sctx->send_root, dir, NULL, &new_gen, NULL, NULL,
+                            NULL, NULL);
+       if (ret)
+               return ret;
+
+       ret = get_inode_info(sctx->parent_root, dir, NULL, &orig_gen, NULL,
+                            NULL, NULL, NULL);
+       if (ret)
+               return ret;
+
+       return (orig_gen != new_gen) ? 1 : 0;
+}
+
+static int compare_refs(struct send_ctx *sctx, struct btrfs_path *path,
+                       struct btrfs_key *key)
+{
+       struct btrfs_inode_extref *extref;
+       struct extent_buffer *leaf;
+       u64 dirid = 0, last_dirid = 0;
+       unsigned long ptr;
+       u32 item_size;
+       u32 cur_offset = 0;
+       int ref_name_len;
+       int ret = 0;
+
+       /* Easy case, just check this one dirid */
+       if (key->type == BTRFS_INODE_REF_KEY) {
+               dirid = key->offset;
+
+               ret = dir_changed(sctx, dirid);
+               goto out;
+       }
+
+       leaf = path->nodes[0];
+       item_size = btrfs_item_size_nr(leaf, path->slots[0]);
+       ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+       while (cur_offset < item_size) {
+               extref = (struct btrfs_inode_extref *)(ptr +
+                                                      cur_offset);
+               dirid = btrfs_inode_extref_parent(leaf, extref);
+               ref_name_len = btrfs_inode_extref_name_len(leaf, extref);
+               cur_offset += ref_name_len + sizeof(*extref);
+               if (dirid == last_dirid)
+                       continue;
+               ret = dir_changed(sctx, dirid);
+               if (ret)
+                       break;
+               last_dirid = dirid;
+       }
+out:
+       return ret;
+}
+
 /*
  * Updates compare related fields in sctx and simply forwards to the actual
  * changed_xxx functions.
@@ -4376,6 +4507,19 @@ static int changed_cb(struct btrfs_root *left_root,
        int ret = 0;
        struct send_ctx *sctx = ctx;
 
+       if (result == BTRFS_COMPARE_TREE_SAME) {
+               if (key->type != BTRFS_INODE_REF_KEY &&
+                   key->type != BTRFS_INODE_EXTREF_KEY)
+                       return 0;
+               ret = compare_refs(sctx, left_path, key);
+               if (!ret)
+                       return 0;
+               if (ret < 0)
+                       return ret;
+               result = BTRFS_COMPARE_TREE_CHANGED;
+               ret = 0;
+       }
+
        sctx->left_path = left_path;
        sctx->right_path = right_path;
        sctx->cmp_key = key;
index 8eb6191d86da8c3f3bb31b838c97a755f5c96853..3aab10ce63e84812b8e9c5a9250235db9b1bbe86 100644 (file)
@@ -56,6 +56,8 @@
 #include "rcu-string.h"
 #include "dev-replace.h"
 #include "free-space-cache.h"
+#include "backref.h"
+#include "tests/btrfs-tests.h"
 
 #define CREATE_TRACE_POINTS
 #include <trace/events/btrfs.h>
@@ -320,14 +322,15 @@ enum {
        Opt_enospc_debug, Opt_subvolrootid, Opt_defrag, Opt_inode_cache,
        Opt_no_space_cache, Opt_recovery, Opt_skip_balance,
        Opt_check_integrity, Opt_check_integrity_including_extent_data,
-       Opt_check_integrity_print_mask, Opt_fatal_errors,
+       Opt_check_integrity_print_mask, Opt_fatal_errors, Opt_rescan_uuid_tree,
+       Opt_commit_interval,
        Opt_err,
 };
 
 static match_table_t tokens = {
        {Opt_degraded, "degraded"},
        {Opt_subvol, "subvol=%s"},
-       {Opt_subvolid, "subvolid=%d"},
+       {Opt_subvolid, "subvolid=%s"},
        {Opt_device, "device=%s"},
        {Opt_nodatasum, "nodatasum"},
        {Opt_nodatacow, "nodatacow"},
@@ -360,7 +363,9 @@ static match_table_t tokens = {
        {Opt_check_integrity, "check_int"},
        {Opt_check_integrity_including_extent_data, "check_int_data"},
        {Opt_check_integrity_print_mask, "check_int_print_mask=%d"},
+       {Opt_rescan_uuid_tree, "rescan_uuid_tree"},
        {Opt_fatal_errors, "fatal_errors=%s"},
+       {Opt_commit_interval, "commit=%d"},
        {Opt_err, NULL},
 };
 
@@ -496,10 +501,15 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        btrfs_set_opt(info->mount_opt, NOBARRIER);
                        break;
                case Opt_thread_pool:
-                       intarg = 0;
-                       match_int(&args[0], &intarg);
-                       if (intarg)
+                       ret = match_int(&args[0], &intarg);
+                       if (ret) {
+                               goto out;
+                       } else if (intarg > 0) {
                                info->thread_pool_size = intarg;
+                       } else {
+                               ret = -EINVAL;
+                               goto out;
+                       }
                        break;
                case Opt_max_inline:
                        num = match_strdup(&args[0]);
@@ -513,7 +523,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                                root->sectorsize);
                                }
                                printk(KERN_INFO "btrfs: max_inline at %llu\n",
-                                       (unsigned long long)info->max_inline);
+                                       info->max_inline);
+                       } else {
+                               ret = -ENOMEM;
+                               goto out;
                        }
                        break;
                case Opt_alloc_start:
@@ -525,7 +538,10 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                kfree(num);
                                printk(KERN_INFO
                                        "btrfs: allocations start at %llu\n",
-                                       (unsigned long long)info->alloc_start);
+                                       info->alloc_start);
+                       } else {
+                               ret = -ENOMEM;
+                               goto out;
                        }
                        break;
                case Opt_noacl:
@@ -540,12 +556,16 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
                        break;
                case Opt_ratio:
-                       intarg = 0;
-                       match_int(&args[0], &intarg);
-                       if (intarg) {
+                       ret = match_int(&args[0], &intarg);
+                       if (ret) {
+                               goto out;
+                       } else if (intarg >= 0) {
                                info->metadata_ratio = intarg;
                                printk(KERN_INFO "btrfs: metadata ratio %d\n",
                                       info->metadata_ratio);
+                       } else {
+                               ret = -EINVAL;
+                               goto out;
                        }
                        break;
                case Opt_discard:
@@ -554,6 +574,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_space_cache:
                        btrfs_set_opt(info->mount_opt, SPACE_CACHE);
                        break;
+               case Opt_rescan_uuid_tree:
+                       btrfs_set_opt(info->mount_opt, RESCAN_UUID_TREE);
+                       break;
                case Opt_no_space_cache:
                        printk(KERN_INFO "btrfs: disabling disk space caching\n");
                        btrfs_clear_opt(info->mount_opt, SPACE_CACHE);
@@ -596,13 +619,17 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
                        break;
                case Opt_check_integrity_print_mask:
-                       intarg = 0;
-                       match_int(&args[0], &intarg);
-                       if (intarg) {
+                       ret = match_int(&args[0], &intarg);
+                       if (ret) {
+                               goto out;
+                       } else if (intarg >= 0) {
                                info->check_integrity_print_mask = intarg;
                                printk(KERN_INFO "btrfs:"
                                       " check_integrity_print_mask 0x%x\n",
                                       info->check_integrity_print_mask);
+                       } else {
+                               ret = -EINVAL;
+                               goto out;
                        }
                        break;
 #else
@@ -626,6 +653,29 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                goto out;
                        }
                        break;
+               case Opt_commit_interval:
+                       intarg = 0;
+                       ret = match_int(&args[0], &intarg);
+                       if (ret < 0) {
+                               printk(KERN_ERR
+                                       "btrfs: invalid commit interval\n");
+                               ret = -EINVAL;
+                               goto out;
+                       }
+                       if (intarg > 0) {
+                               if (intarg > 300) {
+                                       printk(KERN_WARNING
+                                           "btrfs: excessive commit interval %d\n",
+                                                       intarg);
+                               }
+                               info->commit_interval = intarg;
+                       } else {
+                               printk(KERN_INFO
+                                   "btrfs: using default commit interval %ds\n",
+                                   BTRFS_DEFAULT_COMMIT_INTERVAL);
+                               info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
+                       }
+                       break;
                case Opt_err:
                        printk(KERN_INFO "btrfs: unrecognized mount option "
                               "'%s'\n", p);
@@ -654,8 +704,8 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
 {
        substring_t args[MAX_OPT_ARGS];
        char *device_name, *opts, *orig, *p;
+       char *num = NULL;
        int error = 0;
-       int intarg;
 
        if (!options)
                return 0;
@@ -679,17 +729,23 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                case Opt_subvol:
                        kfree(*subvol_name);
                        *subvol_name = match_strdup(&args[0]);
+                       if (!*subvol_name) {
+                               error = -ENOMEM;
+                               goto out;
+                       }
                        break;
                case Opt_subvolid:
-                       intarg = 0;
-                       error = match_int(&args[0], &intarg);
-                       if (!error) {
+                       num = match_strdup(&args[0]);
+                       if (num) {
+                               *subvol_objectid = memparse(num, NULL);
+                               kfree(num);
                                /* we want the original fs_tree */
-                               if (!intarg)
+                               if (!*subvol_objectid)
                                        *subvol_objectid =
                                                BTRFS_FS_TREE_OBJECTID;
-                               else
-                                       *subvol_objectid = intarg;
+                       } else {
+                               error = -EINVAL;
+                               goto out;
                        }
                        break;
                case Opt_subvolrootid:
@@ -892,11 +948,9 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
        if (btrfs_test_opt(root, NOBARRIER))
                seq_puts(seq, ",nobarrier");
        if (info->max_inline != 8192 * 1024)
-               seq_printf(seq, ",max_inline=%llu",
-                          (unsigned long long)info->max_inline);
+               seq_printf(seq, ",max_inline=%llu", info->max_inline);
        if (info->alloc_start != 0)
-               seq_printf(seq, ",alloc_start=%llu",
-                          (unsigned long long)info->alloc_start);
+               seq_printf(seq, ",alloc_start=%llu", info->alloc_start);
        if (info->thread_pool_size !=  min_t(unsigned long,
                                             num_online_cpus() + 2, 8))
                seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
@@ -928,6 +982,8 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_puts(seq, ",space_cache");
        else
                seq_puts(seq, ",nospace_cache");
+       if (btrfs_test_opt(root, RESCAN_UUID_TREE))
+               seq_puts(seq, ",rescan_uuid_tree");
        if (btrfs_test_opt(root, CLEAR_CACHE))
                seq_puts(seq, ",clear_cache");
        if (btrfs_test_opt(root, USER_SUBVOL_RM_ALLOWED))
@@ -940,8 +996,24 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
                seq_puts(seq, ",inode_cache");
        if (btrfs_test_opt(root, SKIP_BALANCE))
                seq_puts(seq, ",skip_balance");
+       if (btrfs_test_opt(root, RECOVERY))
+               seq_puts(seq, ",recovery");
+#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
+       if (btrfs_test_opt(root, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA))
+               seq_puts(seq, ",check_int_data");
+       else if (btrfs_test_opt(root, CHECK_INTEGRITY))
+               seq_puts(seq, ",check_int");
+       if (info->check_integrity_print_mask)
+               seq_printf(seq, ",check_int_print_mask=%d",
+                               info->check_integrity_print_mask);
+#endif
+       if (info->metadata_ratio)
+               seq_printf(seq, ",metadata_ratio=%d",
+                               info->metadata_ratio);
        if (btrfs_test_opt(root, PANIC_ON_FATAL_ERROR))
                seq_puts(seq, ",fatal_errors=panic");
+       if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
+               seq_printf(seq, ",commit=%d", info->commit_interval);
        return 0;
 }
 
@@ -1696,6 +1768,11 @@ static void btrfs_print_info(void)
                        "\n");
 }
 
+static int btrfs_run_sanity_tests(void)
+{
+       return btrfs_test_free_space_cache();
+}
+
 static int __init init_btrfs_fs(void)
 {
        int err;
@@ -1734,23 +1811,32 @@ static int __init init_btrfs_fs(void)
        if (err)
                goto free_auto_defrag;
 
-       err = btrfs_interface_init();
+       err = btrfs_prelim_ref_init();
        if (err)
-               goto free_delayed_ref;
+               goto free_prelim_ref;
 
-       err = register_filesystem(&btrfs_fs_type);
+       err = btrfs_interface_init();
        if (err)
-               goto unregister_ioctl;
+               goto free_delayed_ref;
 
        btrfs_init_lockdep();
 
        btrfs_print_info();
-       btrfs_test_free_space_cache();
+
+       err = btrfs_run_sanity_tests();
+       if (err)
+               goto unregister_ioctl;
+
+       err = register_filesystem(&btrfs_fs_type);
+       if (err)
+               goto unregister_ioctl;
 
        return 0;
 
 unregister_ioctl:
        btrfs_interface_exit();
+free_prelim_ref:
+       btrfs_prelim_ref_exit();
 free_delayed_ref:
        btrfs_delayed_ref_exit();
 free_auto_defrag:
@@ -1777,6 +1863,7 @@ static void __exit exit_btrfs_fs(void)
        btrfs_delayed_ref_exit();
        btrfs_auto_defrag_exit();
        btrfs_delayed_inode_exit();
+       btrfs_prelim_ref_exit();
        ordered_data_exit();
        extent_map_exit();
        extent_io_exit();
diff --git a/fs/btrfs/tests/btrfs-tests.h b/fs/btrfs/tests/btrfs-tests.h
new file mode 100644 (file)
index 0000000..5808776
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2013 Fusion IO.  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 v2 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 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_TESTS
+#define __BTRFS_TESTS
+
+#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
+
+#define test_msg(fmt, ...) pr_info("btrfs: selftest: " fmt, ##__VA_ARGS__)
+
+int btrfs_test_free_space_cache(void);
+#else
+static inline int btrfs_test_free_space_cache(void)
+{
+       return 0;
+}
+#endif
+
+#endif
diff --git a/fs/btrfs/tests/free-space-tests.c b/fs/btrfs/tests/free-space-tests.c
new file mode 100644 (file)
index 0000000..6fc8201
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Copyright (C) 2013 Fusion IO.  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 v2 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 021110-1307, USA.
+ */
+
+#include <linux/slab.h>
+#include "btrfs-tests.h"
+#include "../ctree.h"
+#include "../free-space-cache.h"
+
+#define BITS_PER_BITMAP                (PAGE_CACHE_SIZE * 8)
+static struct btrfs_block_group_cache *init_test_block_group(void)
+{
+       struct btrfs_block_group_cache *cache;
+
+       cache = kzalloc(sizeof(*cache), GFP_NOFS);
+       if (!cache)
+               return NULL;
+       cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
+                                       GFP_NOFS);
+       if (!cache->free_space_ctl) {
+               kfree(cache);
+               return NULL;
+       }
+
+       cache->key.objectid = 0;
+       cache->key.offset = 1024 * 1024 * 1024;
+       cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+       cache->sectorsize = 4096;
+
+       spin_lock_init(&cache->lock);
+       INIT_LIST_HEAD(&cache->list);
+       INIT_LIST_HEAD(&cache->cluster_list);
+       INIT_LIST_HEAD(&cache->new_bg_list);
+
+       btrfs_init_free_space_ctl(cache);
+
+       return cache;
+}
+
+/*
+ * This test just does basic sanity checking, making sure we can add an exten
+ * entry and remove space from either end and the middle, and make sure we can
+ * remove space that covers adjacent extent entries.
+ */
+static int test_extents(struct btrfs_block_group_cache *cache)
+{
+       int ret = 0;
+
+       test_msg("Running extent only tests\n");
+
+       /* First just make sure we can remove an entire entry */
+       ret = btrfs_add_free_space(cache, 0, 4 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error adding initial extents %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 0, 4 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error removing extent %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 0, 4 * 1024 * 1024)) {
+               test_msg("Full remove left some lingering space\n");
+               return -1;
+       }
+
+       /* Ok edge and middle cases now */
+       ret = btrfs_add_free_space(cache, 0, 4 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error adding half extent %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 3 * 1024 * 1024, 1 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error removing tail end %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 0, 1 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error removing front end %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 2 * 1024 * 1024, 4096);
+       if (ret) {
+               test_msg("Error removing middle peice %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 0, 1 * 1024 * 1024)) {
+               test_msg("Still have space at the front\n");
+               return -1;
+       }
+
+       if (test_check_exists(cache, 2 * 1024 * 1024, 4096)) {
+               test_msg("Still have space in the middle\n");
+               return -1;
+       }
+
+       if (test_check_exists(cache, 3 * 1024 * 1024, 1 * 1024 * 1024)) {
+               test_msg("Still have space at the end\n");
+               return -1;
+       }
+
+       /* Cleanup */
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+
+       return 0;
+}
+
+static int test_bitmaps(struct btrfs_block_group_cache *cache)
+{
+       u64 next_bitmap_offset;
+       int ret;
+
+       test_msg("Running bitmap only tests\n");
+
+       ret = test_add_free_space_entry(cache, 0, 4 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't create a bitmap entry %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 0, 4 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error removing bitmap full range %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 0, 4 * 1024 * 1024)) {
+               test_msg("Left some space in bitmap\n");
+               return -1;
+       }
+
+       ret = test_add_free_space_entry(cache, 0, 4 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add to our bitmap entry %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 1 * 1024 * 1024, 2 * 1024 * 1024);
+       if (ret) {
+               test_msg("Couldn't remove middle chunk %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * The first bitmap we have starts at offset 0 so the next one is just
+        * at the end of the first bitmap.
+        */
+       next_bitmap_offset = (u64)(BITS_PER_BITMAP * 4096);
+
+       /* Test a bit straddling two bitmaps */
+       ret = test_add_free_space_entry(cache, next_bitmap_offset -
+                                  (2 * 1024 * 1024), 4 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add space that straddles two bitmaps %d\n",
+                               ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, next_bitmap_offset -
+                                     (1 * 1024 * 1024), 2 * 1024 * 1024);
+       if (ret) {
+               test_msg("Couldn't remove overlapping space %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, next_bitmap_offset - (1 * 1024 * 1024),
+                        2 * 1024 * 1024)) {
+               test_msg("Left some space when removing overlapping\n");
+               return -1;
+       }
+
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+
+       return 0;
+}
+
+/* This is the high grade jackassery */
+static int test_bitmaps_and_extents(struct btrfs_block_group_cache *cache)
+{
+       u64 bitmap_offset = (u64)(BITS_PER_BITMAP * 4096);
+       int ret;
+
+       test_msg("Running bitmap and extent tests\n");
+
+       /*
+        * First let's do something simple, an extent at the same offset as the
+        * bitmap, but the free space completely in the extent and then
+        * completely in the bitmap.
+        */
+       ret = test_add_free_space_entry(cache, 4 * 1024 * 1024, 1 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't create bitmap entry %d\n", ret);
+               return ret;
+       }
+
+       ret = test_add_free_space_entry(cache, 0, 1 * 1024 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't add extent entry %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 0, 1 * 1024 * 1024);
+       if (ret) {
+               test_msg("Couldn't remove extent entry %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 0, 1 * 1024 * 1024)) {
+               test_msg("Left remnants after our remove\n");
+               return -1;
+       }
+
+       /* Now to add back the extent entry and remove from the bitmap */
+       ret = test_add_free_space_entry(cache, 0, 1 * 1024 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't re-add extent entry %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 4 * 1024 * 1024, 1 * 1024 * 1024);
+       if (ret) {
+               test_msg("Couldn't remove from bitmap %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 4 * 1024 * 1024, 1 * 1024 * 1024)) {
+               test_msg("Left remnants in the bitmap\n");
+               return -1;
+       }
+
+       /*
+        * Ok so a little more evil, extent entry and bitmap at the same offset,
+        * removing an overlapping chunk.
+        */
+       ret = test_add_free_space_entry(cache, 1 * 1024 * 1024, 4 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add to a bitmap %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 512 * 1024, 3 * 1024 * 1024);
+       if (ret) {
+               test_msg("Couldn't remove overlapping space %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 512 * 1024, 3 * 1024 * 1024)) {
+               test_msg("Left over peices after removing overlapping\n");
+               return -1;
+       }
+
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+
+       /* Now with the extent entry offset into the bitmap */
+       ret = test_add_free_space_entry(cache, 4 * 1024 * 1024, 4 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add space to the bitmap %d\n", ret);
+               return ret;
+       }
+
+       ret = test_add_free_space_entry(cache, 2 * 1024 * 1024, 2 * 1024 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't add extent to the cache %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 3 * 1024 * 1024, 4 * 1024 * 1024);
+       if (ret) {
+               test_msg("Problem removing overlapping space %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, 3 * 1024 * 1024, 4 * 1024 * 1024)) {
+               test_msg("Left something behind when removing space");
+               return -1;
+       }
+
+       /*
+        * This has blown up in the past, the extent entry starts before the
+        * bitmap entry, but we're trying to remove an offset that falls
+        * completely within the bitmap range and is in both the extent entry
+        * and the bitmap entry, looks like this
+        *
+        *   [ extent ]
+        *      [ bitmap ]
+        *        [ del ]
+        */
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+       ret = test_add_free_space_entry(cache, bitmap_offset + 4 * 1024 * 1024,
+                                  4 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add bitmap %d\n", ret);
+               return ret;
+       }
+
+       ret = test_add_free_space_entry(cache, bitmap_offset - 1 * 1024 * 1024,
+                                  5 * 1024 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't add extent entry %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, bitmap_offset + 1 * 1024 * 1024,
+                                     5 * 1024 * 1024);
+       if (ret) {
+               test_msg("Failed to free our space %d\n", ret);
+               return ret;
+       }
+
+       if (test_check_exists(cache, bitmap_offset + 1 * 1024 * 1024,
+                        5 * 1024 * 1024)) {
+               test_msg("Left stuff over\n");
+               return -1;
+       }
+
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+
+       /*
+        * This blew up before, we have part of the free space in a bitmap and
+        * then the entirety of the rest of the space in an extent.  This used
+        * to return -EAGAIN back from btrfs_remove_extent, make sure this
+        * doesn't happen.
+        */
+       ret = test_add_free_space_entry(cache, 1 * 1024 * 1024, 2 * 1024 * 1024, 1);
+       if (ret) {
+               test_msg("Couldn't add bitmap entry %d\n", ret);
+               return ret;
+       }
+
+       ret = test_add_free_space_entry(cache, 3 * 1024 * 1024, 1 * 1024 * 1024, 0);
+       if (ret) {
+               test_msg("Couldn't add extent entry %d\n", ret);
+               return ret;
+       }
+
+       ret = btrfs_remove_free_space(cache, 1 * 1024 * 1024, 3 * 1024 * 1024);
+       if (ret) {
+               test_msg("Error removing bitmap and extent overlapping %d\n", ret);
+               return ret;
+       }
+
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+       return 0;
+}
+
+int btrfs_test_free_space_cache(void)
+{
+       struct btrfs_block_group_cache *cache;
+       int ret;
+
+       test_msg("Running btrfs free space cache tests\n");
+
+       cache = init_test_block_group();
+       if (!cache) {
+               test_msg("Couldn't run the tests\n");
+               return 0;
+       }
+
+       ret = test_extents(cache);
+       if (ret)
+               goto out;
+       ret = test_bitmaps(cache);
+       if (ret)
+               goto out;
+       ret = test_bitmaps_and_extents(cache);
+       if (ret)
+               goto out;
+out:
+       __btrfs_remove_free_space_cache(cache->free_space_ctl);
+       kfree(cache->free_space_ctl);
+       kfree(cache);
+       test_msg("Free space cache tests finished\n");
+       return ret;
+}
index af1931a5960d9d602688fe8bb89242d752b71c5f..cac4a3f763230f7e448ca6de68a0859a42b13af8 100644 (file)
@@ -837,7 +837,7 @@ int btrfs_wait_marked_extents(struct btrfs_root *root,
  * them in one of two extent_io trees.  This is used to make sure all of
  * those extents are on disk for transaction or log commit
  */
-int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
+static int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
                                struct extent_io_tree *dirty_pages, int mark)
 {
        int ret;
@@ -1225,8 +1225,8 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                btrfs_set_root_stransid(new_root_item, 0);
                btrfs_set_root_rtransid(new_root_item, 0);
        }
-       new_root_item->otime.sec = cpu_to_le64(cur_time.tv_sec);
-       new_root_item->otime.nsec = cpu_to_le32(cur_time.tv_nsec);
+       btrfs_set_stack_timespec_sec(&new_root_item->otime, cur_time.tv_sec);
+       btrfs_set_stack_timespec_nsec(&new_root_item->otime, cur_time.tv_nsec);
        btrfs_set_root_otransid(new_root_item, trans->transid);
 
        old = btrfs_lock_root_node(root);
@@ -1311,8 +1311,26 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans,
                                         dentry->d_name.len * 2);
        parent_inode->i_mtime = parent_inode->i_ctime = CURRENT_TIME;
        ret = btrfs_update_inode_fallback(trans, parent_root, parent_inode);
-       if (ret)
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               goto fail;
+       }
+       ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, new_uuid.b,
+                                 BTRFS_UUID_KEY_SUBVOL, objectid);
+       if (ret) {
                btrfs_abort_transaction(trans, root, ret);
+               goto fail;
+       }
+       if (!btrfs_is_empty_uuid(new_root_item->received_uuid)) {
+               ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
+                                         new_root_item->received_uuid,
+                                         BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                         objectid);
+               if (ret && ret != -EEXIST) {
+                       btrfs_abort_transaction(trans, root, ret);
+                       goto fail;
+               }
+       }
 fail:
        pending->error = ret;
 dir_item_existed:
@@ -1362,6 +1380,8 @@ static void update_super_roots(struct btrfs_root *root)
        super->root_level = root_item->level;
        if (btrfs_test_opt(root, SPACE_CACHE))
                super->cache_generation = root_item->generation;
+       if (root->fs_info->update_uuid_tree_gen)
+               super->uuid_tree_generation = root_item->generation;
 }
 
 int btrfs_transaction_in_commit(struct btrfs_fs_info *info)
@@ -1928,8 +1948,7 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
        list_del_init(&root->root_list);
        spin_unlock(&fs_info->trans_lock);
 
-       pr_debug("btrfs: cleaner removing %llu\n",
-                       (unsigned long long)root->objectid);
+       pr_debug("btrfs: cleaner removing %llu\n", root->objectid);
 
        btrfs_kill_all_delayed_nodes(root);
 
@@ -1942,6 +1961,5 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
         * If we encounter a transaction abort during snapshot cleaning, we
         * don't want to crash here
         */
-       BUG_ON(ret < 0 && ret != -EAGAIN && ret != -EROFS);
-       return 1;
+       return (ret < 0) ? 0 : 1;
 }
index defbc426989787e405e69f6e360fa82b3dc26556..5c2af8491621ced0d1b35110210143a09a1aa418 100644 (file)
@@ -160,8 +160,6 @@ int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
 void btrfs_throttle(struct btrfs_root *root);
 int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
                                struct btrfs_root *root);
-int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
-                               struct extent_io_tree *dirty_pages, int mark);
 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,
index ff60d8978ae264d95709d83342e1c309113521f0..0d9613c3f5e507cc6087decdbc3ef43e3436b396 100644 (file)
@@ -747,7 +747,8 @@ static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans,
        ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len);
        if (ret)
                goto out;
-       btrfs_run_delayed_items(trans, root);
+       else
+               ret = btrfs_run_delayed_items(trans, root);
 out:
        kfree(name);
        iput(inode);
@@ -923,7 +924,9 @@ again:
                                kfree(victim_name);
                                if (ret)
                                        return ret;
-                               btrfs_run_delayed_items(trans, root);
+                               ret = btrfs_run_delayed_items(trans, root);
+                               if (ret)
+                                       return ret;
                                *search_done = 1;
                                goto again;
                        }
@@ -990,7 +993,9 @@ again:
                                                                 inode,
                                                                 victim_name,
                                                                 victim_name_len);
-                                       btrfs_run_delayed_items(trans, root);
+                                       if (!ret)
+                                               ret = btrfs_run_delayed_items(
+                                                                 trans, root);
                                }
                                iput(victim_parent);
                                kfree(victim_name);
@@ -1536,8 +1541,10 @@ static noinline int replay_one_name(struct btrfs_trans_handle *trans,
 
        name_len = btrfs_dir_name_len(eb, di);
        name = kmalloc(name_len, GFP_NOFS);
-       if (!name)
-               return -ENOMEM;
+       if (!name) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        log_type = btrfs_dir_type(eb, di);
        read_extent_buffer(eb, name, (unsigned long)(di + 1),
@@ -1810,7 +1817,7 @@ again:
                        ret = btrfs_unlink_inode(trans, root, dir, inode,
                                                 name, name_len);
                        if (!ret)
-                               btrfs_run_delayed_items(trans, root);
+                               ret = btrfs_run_delayed_items(trans, root);
                        kfree(name);
                        iput(inode);
                        if (ret)
diff --git a/fs/btrfs/uuid-tree.c b/fs/btrfs/uuid-tree.c
new file mode 100644 (file)
index 0000000..dd0dea3
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) STRATO AG 2013.  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 v2 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 021110-1307, USA.
+ */
+#include <linux/uuid.h>
+#include <asm/unaligned.h>
+#include "ctree.h"
+#include "transaction.h"
+#include "disk-io.h"
+#include "print-tree.h"
+
+
+static void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key)
+{
+       key->type = type;
+       key->objectid = get_unaligned_le64(uuid);
+       key->offset = get_unaligned_le64(uuid + sizeof(u64));
+}
+
+/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */
+static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
+                                 u8 type, u64 subid)
+{
+       int ret;
+       struct btrfs_path *path = NULL;
+       struct extent_buffer *eb;
+       int slot;
+       u32 item_size;
+       unsigned long offset;
+       struct btrfs_key key;
+
+       if (WARN_ON_ONCE(!uuid_root)) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       btrfs_uuid_to_key(uuid, type, &key);
+       ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0);
+       if (ret < 0) {
+               goto out;
+       } else if (ret > 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       eb = path->nodes[0];
+       slot = path->slots[0];
+       item_size = btrfs_item_size_nr(eb, slot);
+       offset = btrfs_item_ptr_offset(eb, slot);
+       ret = -ENOENT;
+
+       if (!IS_ALIGNED(item_size, sizeof(u64))) {
+               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                       (unsigned long)item_size);
+               goto out;
+       }
+       while (item_size) {
+               __le64 data;
+
+               read_extent_buffer(eb, &data, offset, sizeof(data));
+               if (le64_to_cpu(data) == subid) {
+                       ret = 0;
+                       break;
+               }
+               offset += sizeof(data);
+               item_size -= sizeof(data);
+       }
+
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid_cpu)
+{
+       int ret;
+       struct btrfs_path *path = NULL;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       int slot;
+       unsigned long offset;
+       __le64 subid_le;
+
+       ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu);
+       if (ret != -ENOENT)
+               return ret;
+
+       if (WARN_ON_ONCE(!uuid_root)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       btrfs_uuid_to_key(uuid, type, &key);
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = btrfs_insert_empty_item(trans, uuid_root, path, &key,
+                                     sizeof(subid_le));
+       if (ret >= 0) {
+               /* Add an item for the type for the first time */
+               eb = path->nodes[0];
+               slot = path->slots[0];
+               offset = btrfs_item_ptr_offset(eb, slot);
+       } else if (ret == -EEXIST) {
+               /*
+                * An item with that type already exists.
+                * Extend the item and store the new subid at the end.
+                */
+               btrfs_extend_item(uuid_root, path, sizeof(subid_le));
+               eb = path->nodes[0];
+               slot = path->slots[0];
+               offset = btrfs_item_ptr_offset(eb, slot);
+               offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le);
+       } else if (ret < 0) {
+               pr_warn("btrfs: insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!\n",
+                       ret, (unsigned long long)key.objectid,
+                       (unsigned long long)key.offset, type);
+               goto out;
+       }
+
+       ret = 0;
+       subid_le = cpu_to_le64(subid_cpu);
+       write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le));
+       btrfs_mark_buffer_dirty(eb);
+
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
+                       struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                       u64 subid)
+{
+       int ret;
+       struct btrfs_path *path = NULL;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       int slot;
+       unsigned long offset;
+       u32 item_size;
+       unsigned long move_dst;
+       unsigned long move_src;
+       unsigned long move_len;
+
+       if (WARN_ON_ONCE(!uuid_root)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       btrfs_uuid_to_key(uuid, type, &key);
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
+       if (ret < 0) {
+               pr_warn("btrfs: error %d while searching for uuid item!\n",
+                       ret);
+               goto out;
+       }
+       if (ret > 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       eb = path->nodes[0];
+       slot = path->slots[0];
+       offset = btrfs_item_ptr_offset(eb, slot);
+       item_size = btrfs_item_size_nr(eb, slot);
+       if (!IS_ALIGNED(item_size, sizeof(u64))) {
+               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                       (unsigned long)item_size);
+               ret = -ENOENT;
+               goto out;
+       }
+       while (item_size) {
+               __le64 read_subid;
+
+               read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid));
+               if (le64_to_cpu(read_subid) == subid)
+                       break;
+               offset += sizeof(read_subid);
+               item_size -= sizeof(read_subid);
+       }
+
+       if (!item_size) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       item_size = btrfs_item_size_nr(eb, slot);
+       if (item_size == sizeof(subid)) {
+               ret = btrfs_del_item(trans, uuid_root, path);
+               goto out;
+       }
+
+       move_dst = offset;
+       move_src = offset + sizeof(subid);
+       move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot));
+       memmove_extent_buffer(eb, move_dst, move_src, move_len);
+       btrfs_truncate_item(uuid_root, path, item_size - sizeof(subid), 1);
+
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type,
+                              u64 subid)
+{
+       struct btrfs_trans_handle *trans;
+       int ret;
+
+       /* 1 - for the uuid item */
+       trans = btrfs_start_transaction(uuid_root, 1);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto out;
+       }
+
+       ret = btrfs_uuid_tree_rem(trans, uuid_root, uuid, type, subid);
+       btrfs_end_transaction(trans, uuid_root);
+
+out:
+       return ret;
+}
+
+int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info,
+                           int (*check_func)(struct btrfs_fs_info *, u8 *, u8,
+                                             u64))
+{
+       struct btrfs_root *root = fs_info->uuid_root;
+       struct btrfs_key key;
+       struct btrfs_key max_key;
+       struct btrfs_path *path;
+       int ret = 0;
+       struct extent_buffer *leaf;
+       int slot;
+       u32 item_size;
+       unsigned long offset;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key.objectid = 0;
+       key.type = 0;
+       key.offset = 0;
+       max_key.objectid = (u64)-1;
+       max_key.type = (u8)-1;
+       max_key.offset = (u64)-1;
+
+again_search_slot:
+       path->keep_locks = 1;
+       ret = btrfs_search_forward(root, &key, &max_key, path, 0);
+       if (ret) {
+               if (ret > 0)
+                       ret = 0;
+               goto out;
+       }
+
+       while (1) {
+               cond_resched();
+               leaf = path->nodes[0];
+               slot = path->slots[0];
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+
+               if (key.type != BTRFS_UUID_KEY_SUBVOL &&
+                   key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
+                       goto skip;
+
+               offset = btrfs_item_ptr_offset(leaf, slot);
+               item_size = btrfs_item_size_nr(leaf, slot);
+               if (!IS_ALIGNED(item_size, sizeof(u64))) {
+                       pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                               (unsigned long)item_size);
+                       goto skip;
+               }
+               while (item_size) {
+                       u8 uuid[BTRFS_UUID_SIZE];
+                       __le64 subid_le;
+                       u64 subid_cpu;
+
+                       put_unaligned_le64(key.objectid, uuid);
+                       put_unaligned_le64(key.offset, uuid + sizeof(u64));
+                       read_extent_buffer(leaf, &subid_le, offset,
+                                          sizeof(subid_le));
+                       subid_cpu = le64_to_cpu(subid_le);
+                       ret = check_func(fs_info, uuid, key.type, subid_cpu);
+                       if (ret < 0)
+                               goto out;
+                       if (ret > 0) {
+                               btrfs_release_path(path);
+                               ret = btrfs_uuid_iter_rem(root, uuid, key.type,
+                                                         subid_cpu);
+                               if (ret == 0) {
+                                       /*
+                                        * this might look inefficient, but the
+                                        * justification is that it is an
+                                        * exception that check_func returns 1,
+                                        * and that in the regular case only one
+                                        * entry per UUID exists.
+                                        */
+                                       goto again_search_slot;
+                               }
+                               if (ret < 0 && ret != -ENOENT)
+                                       goto out;
+                       }
+                       item_size -= sizeof(subid_le);
+                       offset += sizeof(subid_le);
+               }
+
+skip:
+               ret = btrfs_next_item(root, path);
+               if (ret == 0)
+                       continue;
+               else if (ret > 0)
+                       ret = 0;
+               break;
+       }
+
+out:
+       btrfs_free_path(path);
+       if (ret)
+               pr_warn("btrfs: btrfs_uuid_tree_iterate failed %d\n", ret);
+       return 0;
+}
index 67a08538184557486ec802840d610828696edf46..0052ca8264d9b37cc171e52e0954b165fd6dad46 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/ratelimit.h>
 #include <linux/kthread.h>
 #include <linux/raid/pq.h>
+#include <linux/semaphore.h>
 #include <asm/div64.h>
 #include "compat.h"
 #include "ctree.h"
@@ -62,6 +63,48 @@ static void unlock_chunks(struct btrfs_root *root)
        mutex_unlock(&root->fs_info->chunk_mutex);
 }
 
+static struct btrfs_fs_devices *__alloc_fs_devices(void)
+{
+       struct btrfs_fs_devices *fs_devs;
+
+       fs_devs = kzalloc(sizeof(*fs_devs), GFP_NOFS);
+       if (!fs_devs)
+               return ERR_PTR(-ENOMEM);
+
+       mutex_init(&fs_devs->device_list_mutex);
+
+       INIT_LIST_HEAD(&fs_devs->devices);
+       INIT_LIST_HEAD(&fs_devs->alloc_list);
+       INIT_LIST_HEAD(&fs_devs->list);
+
+       return fs_devs;
+}
+
+/**
+ * alloc_fs_devices - allocate struct btrfs_fs_devices
+ * @fsid:      a pointer to UUID for this FS.  If NULL a new UUID is
+ *             generated.
+ *
+ * Return: a pointer to a new &struct btrfs_fs_devices on success;
+ * ERR_PTR() on error.  Returned struct is not linked onto any lists and
+ * can be destroyed with kfree() right away.
+ */
+static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid)
+{
+       struct btrfs_fs_devices *fs_devs;
+
+       fs_devs = __alloc_fs_devices();
+       if (IS_ERR(fs_devs))
+               return fs_devs;
+
+       if (fsid)
+               memcpy(fs_devs->fsid, fsid, BTRFS_FSID_SIZE);
+       else
+               generate_random_uuid(fs_devs->fsid);
+
+       return fs_devs;
+}
+
 static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
 {
        struct btrfs_device *device;
@@ -101,6 +144,27 @@ void btrfs_cleanup_fs_uuids(void)
        }
 }
 
+static struct btrfs_device *__alloc_device(void)
+{
+       struct btrfs_device *dev;
+
+       dev = kzalloc(sizeof(*dev), GFP_NOFS);
+       if (!dev)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&dev->dev_list);
+       INIT_LIST_HEAD(&dev->dev_alloc_list);
+
+       spin_lock_init(&dev->io_lock);
+
+       spin_lock_init(&dev->reada_lock);
+       atomic_set(&dev->reada_in_flight, 0);
+       INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_WAIT);
+       INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_WAIT);
+
+       return dev;
+}
+
 static noinline struct btrfs_device *__find_device(struct list_head *head,
                                                   u64 devid, u8 *uuid)
 {
@@ -395,16 +459,14 @@ static noinline int device_list_add(const char *path,
 
        fs_devices = find_fsid(disk_super->fsid);
        if (!fs_devices) {
-               fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
-               if (!fs_devices)
-                       return -ENOMEM;
-               INIT_LIST_HEAD(&fs_devices->devices);
-               INIT_LIST_HEAD(&fs_devices->alloc_list);
+               fs_devices = alloc_fs_devices(disk_super->fsid);
+               if (IS_ERR(fs_devices))
+                       return PTR_ERR(fs_devices);
+
                list_add(&fs_devices->list, &fs_uuids);
-               memcpy(fs_devices->fsid, disk_super->fsid, BTRFS_FSID_SIZE);
                fs_devices->latest_devid = devid;
                fs_devices->latest_trans = found_transid;
-               mutex_init(&fs_devices->device_list_mutex);
+
                device = NULL;
        } else {
                device = __find_device(&fs_devices->devices, devid,
@@ -414,17 +476,12 @@ static noinline int device_list_add(const char *path,
                if (fs_devices->opened)
                        return -EBUSY;
 
-               device = kzalloc(sizeof(*device), GFP_NOFS);
-               if (!device) {
+               device = btrfs_alloc_device(NULL, &devid,
+                                           disk_super->dev_item.uuid);
+               if (IS_ERR(device)) {
                        /* we can safely leave the fs_devices entry around */
-                       return -ENOMEM;
+                       return PTR_ERR(device);
                }
-               device->devid = devid;
-               device->dev_stats_valid = 0;
-               device->work.func = pending_bios_fn;
-               memcpy(device->uuid, disk_super->dev_item.uuid,
-                      BTRFS_UUID_SIZE);
-               spin_lock_init(&device->io_lock);
 
                name = rcu_string_strdup(path, GFP_NOFS);
                if (!name) {
@@ -432,22 +489,13 @@ static noinline int device_list_add(const char *path,
                        return -ENOMEM;
                }
                rcu_assign_pointer(device->name, name);
-               INIT_LIST_HEAD(&device->dev_alloc_list);
-
-               /* init readahead state */
-               spin_lock_init(&device->reada_lock);
-               device->reada_curr_zone = NULL;
-               atomic_set(&device->reada_in_flight, 0);
-               device->reada_next = 0;
-               INIT_RADIX_TREE(&device->reada_zones, GFP_NOFS & ~__GFP_WAIT);
-               INIT_RADIX_TREE(&device->reada_extents, GFP_NOFS & ~__GFP_WAIT);
 
                mutex_lock(&fs_devices->device_list_mutex);
                list_add_rcu(&device->dev_list, &fs_devices->devices);
+               fs_devices->num_devices++;
                mutex_unlock(&fs_devices->device_list_mutex);
 
                device->fs_devices = fs_devices;
-               fs_devices->num_devices++;
        } else if (!device->name || strcmp(device->name->str, path)) {
                name = rcu_string_strdup(path, GFP_NOFS);
                if (!name)
@@ -474,25 +522,21 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
        struct btrfs_device *device;
        struct btrfs_device *orig_dev;
 
-       fs_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
-       if (!fs_devices)
-               return ERR_PTR(-ENOMEM);
+       fs_devices = alloc_fs_devices(orig->fsid);
+       if (IS_ERR(fs_devices))
+               return fs_devices;
 
-       INIT_LIST_HEAD(&fs_devices->devices);
-       INIT_LIST_HEAD(&fs_devices->alloc_list);
-       INIT_LIST_HEAD(&fs_devices->list);
-       mutex_init(&fs_devices->device_list_mutex);
        fs_devices->latest_devid = orig->latest_devid;
        fs_devices->latest_trans = orig->latest_trans;
        fs_devices->total_devices = orig->total_devices;
-       memcpy(fs_devices->fsid, orig->fsid, sizeof(fs_devices->fsid));
 
        /* We have held the volume lock, it is safe to get the devices. */
        list_for_each_entry(orig_dev, &orig->devices, dev_list) {
                struct rcu_string *name;
 
-               device = kzalloc(sizeof(*device), GFP_NOFS);
-               if (!device)
+               device = btrfs_alloc_device(NULL, &orig_dev->devid,
+                                           orig_dev->uuid);
+               if (IS_ERR(device))
                        goto error;
 
                /*
@@ -506,13 +550,6 @@ static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig)
                }
                rcu_assign_pointer(device->name, name);
 
-               device->devid = orig_dev->devid;
-               device->work.func = pending_bios_fn;
-               memcpy(device->uuid, orig_dev->uuid, sizeof(device->uuid));
-               spin_lock_init(&device->io_lock);
-               INIT_LIST_HEAD(&device->dev_list);
-               INIT_LIST_HEAD(&device->dev_alloc_list);
-
                list_add(&device->dev_list, &fs_devices->devices);
                device->fs_devices = fs_devices;
                fs_devices->num_devices++;
@@ -636,23 +673,22 @@ static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices)
 
                if (device->can_discard)
                        fs_devices->num_can_discard--;
+               if (device->missing)
+                       fs_devices->missing_devices--;
 
-               new_device = kmalloc(sizeof(*new_device), GFP_NOFS);
-               BUG_ON(!new_device); /* -ENOMEM */
-               memcpy(new_device, device, sizeof(*new_device));
+               new_device = btrfs_alloc_device(NULL, &device->devid,
+                                               device->uuid);
+               BUG_ON(IS_ERR(new_device)); /* -ENOMEM */
 
                /* Safe because we are under uuid_mutex */
                if (device->name) {
                        name = rcu_string_strdup(device->name->str, GFP_NOFS);
-                       BUG_ON(device->name && !name); /* -ENOMEM */
+                       BUG_ON(!name); /* -ENOMEM */
                        rcu_assign_pointer(new_device->name, name);
                }
-               new_device->bdev = NULL;
-               new_device->writeable = 0;
-               new_device->in_fs_metadata = 0;
-               new_device->can_discard = 0;
-               spin_lock_init(&new_device->io_lock);
+
                list_replace_rcu(&device->dev_list, &new_device->dev_list);
+               new_device->fs_devices = device->fs_devices;
 
                call_rcu(&device->rcu, free_device);
        }
@@ -865,7 +901,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
        disk_super = p + (bytenr & ~PAGE_CACHE_MASK);
 
        if (btrfs_super_bytenr(disk_super) != bytenr ||
-           disk_super->magic != cpu_to_le64(BTRFS_MAGIC))
+           btrfs_super_magic(disk_super) != BTRFS_MAGIC)
                goto error_unmap;
 
        devid = btrfs_stack_device_id(&disk_super->dev_item);
@@ -880,8 +916,7 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
                printk(KERN_INFO "device fsid %pU ", disk_super->fsid);
        }
 
-       printk(KERN_CONT "devid %llu transid %llu %s\n",
-              (unsigned long long)devid, (unsigned long long)transid, path);
+       printk(KERN_CONT "devid %llu transid %llu %s\n", devid, transid, path);
 
        ret = device_list_add(path, disk_super, devid, fs_devices_ret);
        if (!ret && fs_devices_ret)
@@ -1278,8 +1313,7 @@ static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans,
        btrfs_set_dev_extent_chunk_offset(leaf, extent, chunk_offset);
 
        write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid,
-                   (unsigned long)btrfs_dev_extent_chunk_tree_uuid(extent),
-                   BTRFS_UUID_SIZE);
+                   btrfs_dev_extent_chunk_tree_uuid(extent), BTRFS_UUID_SIZE);
 
        btrfs_set_dev_extent_length(leaf, extent, num_bytes);
        btrfs_mark_buffer_dirty(leaf);
@@ -1307,15 +1341,14 @@ static u64 find_next_chunk(struct btrfs_fs_info *fs_info)
        return ret;
 }
 
-static noinline int find_next_devid(struct btrfs_root *root, u64 *objectid)
+static noinline int find_next_devid(struct btrfs_fs_info *fs_info,
+                                   u64 *devid_ret)
 {
        int ret;
        struct btrfs_key key;
        struct btrfs_key found_key;
        struct btrfs_path *path;
 
-       root = root->fs_info->chunk_root;
-
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -1324,20 +1357,21 @@ static noinline int find_next_devid(struct btrfs_root *root, u64 *objectid)
        key.type = BTRFS_DEV_ITEM_KEY;
        key.offset = (u64)-1;
 
-       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       ret = btrfs_search_slot(NULL, fs_info->chunk_root, &key, path, 0, 0);
        if (ret < 0)
                goto error;
 
        BUG_ON(ret == 0); /* Corruption */
 
-       ret = btrfs_previous_item(root, path, BTRFS_DEV_ITEMS_OBJECTID,
+       ret = btrfs_previous_item(fs_info->chunk_root, path,
+                                 BTRFS_DEV_ITEMS_OBJECTID,
                                  BTRFS_DEV_ITEM_KEY);
        if (ret) {
-               *objectid = 1;
+               *devid_ret = 1;
        } else {
                btrfs_item_key_to_cpu(path->nodes[0], &found_key,
                                      path->slots[0]);
-               *objectid = found_key.offset + 1;
+               *devid_ret = found_key.offset + 1;
        }
        ret = 0;
 error:
@@ -1391,9 +1425,9 @@ static int btrfs_add_device(struct btrfs_trans_handle *trans,
        btrfs_set_device_bandwidth(leaf, dev_item, 0);
        btrfs_set_device_start_offset(leaf, dev_item, 0);
 
-       ptr = (unsigned long)btrfs_device_uuid(dev_item);
+       ptr = btrfs_device_uuid(dev_item);
        write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
-       ptr = (unsigned long)btrfs_device_fsid(dev_item);
+       ptr = btrfs_device_fsid(dev_item);
        write_extent_buffer(leaf, root->fs_info->fsid, ptr, BTRFS_UUID_SIZE);
        btrfs_mark_buffer_dirty(leaf);
 
@@ -1562,7 +1596,9 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                clear_super = true;
        }
 
+       mutex_unlock(&uuid_mutex);
        ret = btrfs_shrink_device(device, 0);
+       mutex_lock(&uuid_mutex);
        if (ret)
                goto error_undo;
 
@@ -1586,7 +1622,11 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
        /*
         * the device list mutex makes sure that we don't change
         * the device list while someone else is writing out all
-        * the device supers.
+        * the device supers. Whoever is writing all supers, should
+        * lock the device list mutex before getting the number of
+        * devices in the super block (super_copy). Conversely,
+        * whoever updates the number of devices in the super block
+        * (super_copy) should hold the device list mutex.
         */
 
        cur_devices = device->fs_devices;
@@ -1610,10 +1650,10 @@ int btrfs_rm_device(struct btrfs_root *root, char *device_path)
                device->fs_devices->open_devices--;
 
        call_rcu(&device->rcu, free_device);
-       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1;
        btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        if (cur_devices->open_devices == 0) {
                struct btrfs_fs_devices *fs_devices;
@@ -1793,9 +1833,9 @@ static int btrfs_prepare_sprout(struct btrfs_root *root)
        if (!fs_devices->seeding)
                return -EINVAL;
 
-       seed_devices = kzalloc(sizeof(*fs_devices), GFP_NOFS);
-       if (!seed_devices)
-               return -ENOMEM;
+       seed_devices = __alloc_fs_devices();
+       if (IS_ERR(seed_devices))
+               return PTR_ERR(seed_devices);
 
        old_devices = clone_fs_devices(fs_devices);
        if (IS_ERR(old_devices)) {
@@ -1814,7 +1854,6 @@ static int btrfs_prepare_sprout(struct btrfs_root *root)
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices,
                              synchronize_rcu);
-       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
        list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list);
        list_for_each_entry(device, &seed_devices->devices, dev_list) {
@@ -1830,6 +1869,8 @@ static int btrfs_prepare_sprout(struct btrfs_root *root)
        generate_random_uuid(fs_devices->fsid);
        memcpy(root->fs_info->fsid, fs_devices->fsid, BTRFS_FSID_SIZE);
        memcpy(disk_super->fsid, fs_devices->fsid, BTRFS_FSID_SIZE);
+       mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
+
        super_flags = btrfs_super_flags(disk_super) &
                      ~BTRFS_SUPER_FLAG_SEEDING;
        btrfs_set_super_flags(disk_super, super_flags);
@@ -1889,11 +1930,9 @@ next_slot:
                dev_item = btrfs_item_ptr(leaf, path->slots[0],
                                          struct btrfs_dev_item);
                devid = btrfs_device_id(leaf, dev_item);
-               read_extent_buffer(leaf, dev_uuid,
-                                  (unsigned long)btrfs_device_uuid(dev_item),
+               read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
                                   BTRFS_UUID_SIZE);
-               read_extent_buffer(leaf, fs_uuid,
-                                  (unsigned long)btrfs_device_fsid(dev_item),
+               read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
                                   BTRFS_UUID_SIZE);
                device = btrfs_find_device(root->fs_info, devid, dev_uuid,
                                           fs_uuid);
@@ -1956,10 +1995,10 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        }
        mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
-       device = kzalloc(sizeof(*device), GFP_NOFS);
-       if (!device) {
+       device = btrfs_alloc_device(root->fs_info, NULL, NULL);
+       if (IS_ERR(device)) {
                /* we can safely leave the fs_devices entry around */
-               ret = -ENOMEM;
+               ret = PTR_ERR(device);
                goto error;
        }
 
@@ -1971,13 +2010,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        }
        rcu_assign_pointer(device->name, name);
 
-       ret = find_next_devid(root, &device->devid);
-       if (ret) {
-               rcu_string_free(device->name);
-               kfree(device);
-               goto error;
-       }
-
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                rcu_string_free(device->name);
@@ -1992,9 +2024,6 @@ int btrfs_init_new_device(struct btrfs_root *root, char *device_path)
        if (blk_queue_discard(q))
                device->can_discard = 1;
        device->writeable = 1;
-       device->work.func = pending_bios_fn;
-       generate_random_uuid(device->uuid);
-       spin_lock_init(&device->io_lock);
        device->generation = trans->transid;
        device->io_width = root->sectorsize;
        device->io_align = root->sectorsize;
@@ -2121,6 +2150,7 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct list_head *devices;
        struct rcu_string *name;
+       u64 devid = BTRFS_DEV_REPLACE_DEVID;
        int ret = 0;
 
        *device_out = NULL;
@@ -2142,9 +2172,9 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
                }
        }
 
-       device = kzalloc(sizeof(*device), GFP_NOFS);
-       if (!device) {
-               ret = -ENOMEM;
+       device = btrfs_alloc_device(NULL, &devid, NULL);
+       if (IS_ERR(device)) {
+               ret = PTR_ERR(device);
                goto error;
        }
 
@@ -2161,10 +2191,6 @@ int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path,
                device->can_discard = 1;
        mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
        device->writeable = 1;
-       device->work.func = pending_bios_fn;
-       generate_random_uuid(device->uuid);
-       device->devid = BTRFS_DEV_REPLACE_DEVID;
-       spin_lock_init(&device->io_lock);
        device->generation = 0;
        device->io_width = root->sectorsize;
        device->io_align = root->sectorsize;
@@ -2971,10 +2997,6 @@ again:
                if (found_key.objectid != key.objectid)
                        break;
 
-               /* chunk zero is special */
-               if (found_key.offset == 0)
-                       break;
-
                chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
 
                if (!counting) {
@@ -3010,6 +3032,8 @@ again:
                        spin_unlock(&fs_info->balance_lock);
                }
 loop:
+               if (found_key.offset == 0)
+                       break;
                key.offset = found_key.offset - 1;
        }
 
@@ -3074,9 +3098,6 @@ static void __cancel_balance(struct btrfs_fs_info *fs_info)
        atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
 }
 
-void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
-                              struct btrfs_ioctl_balance_args *bargs);
-
 /*
  * Should be called with both balance and volume mutexes held
  */
@@ -3139,7 +3160,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
             (bctl->data.target & ~allowed))) {
                printk(KERN_ERR "btrfs: unable to start balance with target "
                       "data profile %llu\n",
-                      (unsigned long long)bctl->data.target);
+                      bctl->data.target);
                ret = -EINVAL;
                goto out;
        }
@@ -3148,7 +3169,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
             (bctl->meta.target & ~allowed))) {
                printk(KERN_ERR "btrfs: unable to start balance with target "
                       "metadata profile %llu\n",
-                      (unsigned long long)bctl->meta.target);
+                      bctl->meta.target);
                ret = -EINVAL;
                goto out;
        }
@@ -3157,7 +3178,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
             (bctl->sys.target & ~allowed))) {
                printk(KERN_ERR "btrfs: unable to start balance with target "
                       "system profile %llu\n",
-                      (unsigned long long)bctl->sys.target);
+                      bctl->sys.target);
                ret = -EINVAL;
                goto out;
        }
@@ -3430,6 +3451,264 @@ int btrfs_cancel_balance(struct btrfs_fs_info *fs_info)
        return 0;
 }
 
+static int btrfs_uuid_scan_kthread(void *data)
+{
+       struct btrfs_fs_info *fs_info = data;
+       struct btrfs_root *root = fs_info->tree_root;
+       struct btrfs_key key;
+       struct btrfs_key max_key;
+       struct btrfs_path *path = NULL;
+       int ret = 0;
+       struct extent_buffer *eb;
+       int slot;
+       struct btrfs_root_item root_item;
+       u32 item_size;
+       struct btrfs_trans_handle *trans = NULL;
+
+       path = btrfs_alloc_path();
+       if (!path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       key.objectid = 0;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+       key.offset = 0;
+
+       max_key.objectid = (u64)-1;
+       max_key.type = BTRFS_ROOT_ITEM_KEY;
+       max_key.offset = (u64)-1;
+
+       path->keep_locks = 1;
+
+       while (1) {
+               ret = btrfs_search_forward(root, &key, &max_key, path, 0);
+               if (ret) {
+                       if (ret > 0)
+                               ret = 0;
+                       break;
+               }
+
+               if (key.type != BTRFS_ROOT_ITEM_KEY ||
+                   (key.objectid < BTRFS_FIRST_FREE_OBJECTID &&
+                    key.objectid != BTRFS_FS_TREE_OBJECTID) ||
+                   key.objectid > BTRFS_LAST_FREE_OBJECTID)
+                       goto skip;
+
+               eb = path->nodes[0];
+               slot = path->slots[0];
+               item_size = btrfs_item_size_nr(eb, slot);
+               if (item_size < sizeof(root_item))
+                       goto skip;
+
+               read_extent_buffer(eb, &root_item,
+                                  btrfs_item_ptr_offset(eb, slot),
+                                  (int)sizeof(root_item));
+               if (btrfs_root_refs(&root_item) == 0)
+                       goto skip;
+
+               if (!btrfs_is_empty_uuid(root_item.uuid) ||
+                   !btrfs_is_empty_uuid(root_item.received_uuid)) {
+                       if (trans)
+                               goto update_tree;
+
+                       btrfs_release_path(path);
+                       /*
+                        * 1 - subvol uuid item
+                        * 1 - received_subvol uuid item
+                        */
+                       trans = btrfs_start_transaction(fs_info->uuid_root, 2);
+                       if (IS_ERR(trans)) {
+                               ret = PTR_ERR(trans);
+                               break;
+                       }
+                       continue;
+               } else {
+                       goto skip;
+               }
+update_tree:
+               if (!btrfs_is_empty_uuid(root_item.uuid)) {
+                       ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
+                                                 root_item.uuid,
+                                                 BTRFS_UUID_KEY_SUBVOL,
+                                                 key.objectid);
+                       if (ret < 0) {
+                               pr_warn("btrfs: uuid_tree_add failed %d\n",
+                                       ret);
+                               break;
+                       }
+               }
+
+               if (!btrfs_is_empty_uuid(root_item.received_uuid)) {
+                       ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root,
+                                                 root_item.received_uuid,
+                                                BTRFS_UUID_KEY_RECEIVED_SUBVOL,
+                                                 key.objectid);
+                       if (ret < 0) {
+                               pr_warn("btrfs: uuid_tree_add failed %d\n",
+                                       ret);
+                               break;
+                       }
+               }
+
+skip:
+               if (trans) {
+                       ret = btrfs_end_transaction(trans, fs_info->uuid_root);
+                       trans = NULL;
+                       if (ret)
+                               break;
+               }
+
+               btrfs_release_path(path);
+               if (key.offset < (u64)-1) {
+                       key.offset++;
+               } else if (key.type < BTRFS_ROOT_ITEM_KEY) {
+                       key.offset = 0;
+                       key.type = BTRFS_ROOT_ITEM_KEY;
+               } else if (key.objectid < (u64)-1) {
+                       key.offset = 0;
+                       key.type = BTRFS_ROOT_ITEM_KEY;
+                       key.objectid++;
+               } else {
+                       break;
+               }
+               cond_resched();
+       }
+
+out:
+       btrfs_free_path(path);
+       if (trans && !IS_ERR(trans))
+               btrfs_end_transaction(trans, fs_info->uuid_root);
+       if (ret)
+               pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret);
+       else
+               fs_info->update_uuid_tree_gen = 1;
+       up(&fs_info->uuid_tree_rescan_sem);
+       return 0;
+}
+
+/*
+ * Callback for btrfs_uuid_tree_iterate().
+ * returns:
+ * 0   check succeeded, the entry is not outdated.
+ * < 0 if an error occured.
+ * > 0 if the check failed, which means the caller shall remove the entry.
+ */
+static int btrfs_check_uuid_tree_entry(struct btrfs_fs_info *fs_info,
+                                      u8 *uuid, u8 type, u64 subid)
+{
+       struct btrfs_key key;
+       int ret = 0;
+       struct btrfs_root *subvol_root;
+
+       if (type != BTRFS_UUID_KEY_SUBVOL &&
+           type != BTRFS_UUID_KEY_RECEIVED_SUBVOL)
+               goto out;
+
+       key.objectid = subid;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+       key.offset = (u64)-1;
+       subvol_root = btrfs_read_fs_root_no_name(fs_info, &key);
+       if (IS_ERR(subvol_root)) {
+               ret = PTR_ERR(subvol_root);
+               if (ret == -ENOENT)
+                       ret = 1;
+               goto out;
+       }
+
+       switch (type) {
+       case BTRFS_UUID_KEY_SUBVOL:
+               if (memcmp(uuid, subvol_root->root_item.uuid, BTRFS_UUID_SIZE))
+                       ret = 1;
+               break;
+       case BTRFS_UUID_KEY_RECEIVED_SUBVOL:
+               if (memcmp(uuid, subvol_root->root_item.received_uuid,
+                          BTRFS_UUID_SIZE))
+                       ret = 1;
+               break;
+       }
+
+out:
+       return ret;
+}
+
+static int btrfs_uuid_rescan_kthread(void *data)
+{
+       struct btrfs_fs_info *fs_info = (struct btrfs_fs_info *)data;
+       int ret;
+
+       /*
+        * 1st step is to iterate through the existing UUID tree and
+        * to delete all entries that contain outdated data.
+        * 2nd step is to add all missing entries to the UUID tree.
+        */
+       ret = btrfs_uuid_tree_iterate(fs_info, btrfs_check_uuid_tree_entry);
+       if (ret < 0) {
+               pr_warn("btrfs: iterating uuid_tree failed %d\n", ret);
+               up(&fs_info->uuid_tree_rescan_sem);
+               return ret;
+       }
+       return btrfs_uuid_scan_kthread(data);
+}
+
+int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *tree_root = fs_info->tree_root;
+       struct btrfs_root *uuid_root;
+       struct task_struct *task;
+       int ret;
+
+       /*
+        * 1 - root node
+        * 1 - root item
+        */
+       trans = btrfs_start_transaction(tree_root, 2);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       uuid_root = btrfs_create_tree(trans, fs_info,
+                                     BTRFS_UUID_TREE_OBJECTID);
+       if (IS_ERR(uuid_root)) {
+               btrfs_abort_transaction(trans, tree_root,
+                                       PTR_ERR(uuid_root));
+               return PTR_ERR(uuid_root);
+       }
+
+       fs_info->uuid_root = uuid_root;
+
+       ret = btrfs_commit_transaction(trans, tree_root);
+       if (ret)
+               return ret;
+
+       down(&fs_info->uuid_tree_rescan_sem);
+       task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid");
+       if (IS_ERR(task)) {
+               /* fs_info->update_uuid_tree_gen remains 0 in all error case */
+               pr_warn("btrfs: failed to start uuid_scan task\n");
+               up(&fs_info->uuid_tree_rescan_sem);
+               return PTR_ERR(task);
+       }
+
+       return 0;
+}
+
+int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
+{
+       struct task_struct *task;
+
+       down(&fs_info->uuid_tree_rescan_sem);
+       task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid");
+       if (IS_ERR(task)) {
+               /* fs_info->update_uuid_tree_gen remains 0 in all error case */
+               pr_warn("btrfs: failed to start uuid_rescan task\n");
+               up(&fs_info->uuid_tree_rescan_sem);
+               return PTR_ERR(task);
+       }
+
+       return 0;
+}
+
 /*
  * shrinking a device means finding all of the device extents past
  * the new size, and then following the back refs to the chunks.
@@ -4194,13 +4473,13 @@ int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)
         * and exit, so return 1 so the callers don't try to use other copies.
         */
        if (!em) {
-               btrfs_emerg(fs_info, "No mapping for %Lu-%Lu\n", logical,
+               btrfs_crit(fs_info, "No mapping for %Lu-%Lu\n", logical,
                            logical+len);
                return 1;
        }
 
        if (em->start > logical || em->start + em->len < logical) {
-               btrfs_emerg(fs_info, "Invalid mapping for %Lu-%Lu, got "
+               btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got "
                            "%Lu-%Lu\n", logical, logical+len, em->start,
                            em->start + em->len);
                return 1;
@@ -4375,8 +4654,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
 
        if (!em) {
                btrfs_crit(fs_info, "unable to find logical %llu len %llu",
-                       (unsigned long long)logical,
-                       (unsigned long long)*length);
+                       logical, *length);
                return -EINVAL;
        }
 
@@ -4671,6 +4949,7 @@ static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int rw,
        }
        bbio = kzalloc(btrfs_bio_size(num_alloc_stripes), GFP_NOFS);
        if (!bbio) {
+               kfree(raid_map);
                ret = -ENOMEM;
                goto out;
        }
@@ -5246,9 +5525,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
 
        if (map_length < length) {
                btrfs_crit(root->fs_info, "mapping failed logical %llu bio len %llu len %llu",
-                       (unsigned long long)logical,
-                       (unsigned long long)length,
-                       (unsigned long long)map_length);
+                       logical, length, map_length);
                BUG();
        }
 
@@ -5314,23 +5591,72 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
        struct btrfs_device *device;
        struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
 
-       device = kzalloc(sizeof(*device), GFP_NOFS);
-       if (!device)
+       device = btrfs_alloc_device(NULL, &devid, dev_uuid);
+       if (IS_ERR(device))
                return NULL;
-       list_add(&device->dev_list,
-                &fs_devices->devices);
-       device->devid = devid;
-       device->work.func = pending_bios_fn;
+
+       list_add(&device->dev_list, &fs_devices->devices);
        device->fs_devices = fs_devices;
-       device->missing = 1;
        fs_devices->num_devices++;
+
+       device->missing = 1;
        fs_devices->missing_devices++;
-       spin_lock_init(&device->io_lock);
-       INIT_LIST_HEAD(&device->dev_alloc_list);
-       memcpy(device->uuid, dev_uuid, BTRFS_UUID_SIZE);
+
        return device;
 }
 
+/**
+ * btrfs_alloc_device - allocate struct btrfs_device
+ * @fs_info:   used only for generating a new devid, can be NULL if
+ *             devid is provided (i.e. @devid != NULL).
+ * @devid:     a pointer to devid for this device.  If NULL a new devid
+ *             is generated.
+ * @uuid:      a pointer to UUID for this device.  If NULL a new UUID
+ *             is generated.
+ *
+ * Return: a pointer to a new &struct btrfs_device on success; ERR_PTR()
+ * on error.  Returned struct is not linked onto any lists and can be
+ * destroyed with kfree() right away.
+ */
+struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
+                                       const u64 *devid,
+                                       const u8 *uuid)
+{
+       struct btrfs_device *dev;
+       u64 tmp;
+
+       if (!devid && !fs_info) {
+               WARN_ON(1);
+               return ERR_PTR(-EINVAL);
+       }
+
+       dev = __alloc_device();
+       if (IS_ERR(dev))
+               return dev;
+
+       if (devid)
+               tmp = *devid;
+       else {
+               int ret;
+
+               ret = find_next_devid(fs_info, &tmp);
+               if (ret) {
+                       kfree(dev);
+                       return ERR_PTR(ret);
+               }
+       }
+       dev->devid = tmp;
+
+       if (uuid)
+               memcpy(dev->uuid, uuid, BTRFS_UUID_SIZE);
+       else
+               generate_random_uuid(dev->uuid);
+
+       dev->work.func = pending_bios_fn;
+
+       return dev;
+}
+
 static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                          struct extent_buffer *leaf,
                          struct btrfs_chunk *chunk)
@@ -5437,7 +5763,7 @@ static void fill_device_from_item(struct extent_buffer *leaf,
        WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID);
        device->is_tgtdev_for_dev_replace = 0;
 
-       ptr = (unsigned long)btrfs_device_uuid(dev_item);
+       ptr = btrfs_device_uuid(dev_item);
        read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE);
 }
 
@@ -5500,11 +5826,9 @@ static int read_one_dev(struct btrfs_root *root,
        u8 dev_uuid[BTRFS_UUID_SIZE];
 
        devid = btrfs_device_id(leaf, dev_item);
-       read_extent_buffer(leaf, dev_uuid,
-                          (unsigned long)btrfs_device_uuid(dev_item),
+       read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item),
                           BTRFS_UUID_SIZE);
-       read_extent_buffer(leaf, fs_uuid,
-                          (unsigned long)btrfs_device_fsid(dev_item),
+       read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item),
                           BTRFS_UUID_SIZE);
 
        if (memcmp(fs_uuid, root->fs_info->fsid, BTRFS_UUID_SIZE)) {
@@ -5519,8 +5843,7 @@ static int read_one_dev(struct btrfs_root *root,
                        return -EIO;
 
                if (!device) {
-                       btrfs_warn(root->fs_info, "devid %llu missing",
-                               (unsigned long long)devid);
+                       btrfs_warn(root->fs_info, "devid %llu missing", devid);
                        device = add_missing_dev(root, devid, dev_uuid);
                        if (!device)
                                return -ENOMEM;
@@ -5644,14 +5967,15 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
        mutex_lock(&uuid_mutex);
        lock_chunks(root);
 
-       /* first we search for all of the device items, and then we
-        * read in all of the chunk items.  This way we can create chunk
-        * mappings that reference all of the devices that are afound
+       /*
+        * Read all device items, and then all the chunk items. All
+        * device items are found before any chunk item (their object id
+        * is smaller than the lowest possible object id for a chunk
+        * item - BTRFS_FIRST_CHUNK_TREE_OBJECTID).
         */
        key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
        key.offset = 0;
        key.type = 0;
-again:
        ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
        if (ret < 0)
                goto error;
@@ -5667,17 +5991,13 @@ again:
                        break;
                }
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
-               if (key.objectid == BTRFS_DEV_ITEMS_OBJECTID) {
-                       if (found_key.objectid != BTRFS_DEV_ITEMS_OBJECTID)
-                               break;
-                       if (found_key.type == BTRFS_DEV_ITEM_KEY) {
-                               struct btrfs_dev_item *dev_item;
-                               dev_item = btrfs_item_ptr(leaf, slot,
+               if (found_key.type == BTRFS_DEV_ITEM_KEY) {
+                       struct btrfs_dev_item *dev_item;
+                       dev_item = btrfs_item_ptr(leaf, slot,
                                                  struct btrfs_dev_item);
-                               ret = read_one_dev(root, leaf, dev_item);
-                               if (ret)
-                                       goto error;
-                       }
+                       ret = read_one_dev(root, leaf, dev_item);
+                       if (ret)
+                               goto error;
                } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) {
                        struct btrfs_chunk *chunk;
                        chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk);
@@ -5687,11 +6007,6 @@ again:
                }
                path->slots[0]++;
        }
-       if (key.objectid == BTRFS_DEV_ITEMS_OBJECTID) {
-               key.objectid = 0;
-               btrfs_release_path(path);
-               goto again;
-       }
        ret = 0;
 error:
        unlock_chunks(root);
index 86705583480d61c9f88c46df734bb4b057abd2d8..b72f540c8b295d1be0b3642d695ee0b8b75ebed1 100644 (file)
@@ -152,6 +152,8 @@ struct btrfs_fs_devices {
        int rotating;
 };
 
+#define BTRFS_BIO_INLINE_CSUM_SIZE     64
+
 /*
  * we need the mirror number and stripe index to be passed around
  * the call chain while we are processing end_io (especially errors).
@@ -161,9 +163,14 @@ struct btrfs_fs_devices {
  * we allocate are actually btrfs_io_bios.  We'll cram as much of
  * struct btrfs_bio as we can into this over time.
  */
+typedef void (btrfs_io_bio_end_io_t) (struct btrfs_io_bio *bio, int err);
 struct btrfs_io_bio {
        unsigned long mirror_num;
        unsigned long stripe_index;
+       u8 *csum;
+       u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE];
+       u8 *csum_allocated;
+       btrfs_io_bio_end_io_t *end_io;
        struct bio bio;
 };
 
@@ -298,6 +305,9 @@ void btrfs_close_extra_devices(struct btrfs_fs_info *fs_info,
 int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
                                         char *device_path,
                                         struct btrfs_device **device);
+struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info,
+                                       const u64 *devid,
+                                       const u8 *uuid);
 int btrfs_rm_device(struct btrfs_root *root, char *device_path);
 void btrfs_cleanup_fs_uuids(void);
 int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len);
@@ -315,6 +325,8 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info);
 int btrfs_recover_balance(struct btrfs_fs_info *fs_info);
 int btrfs_pause_balance(struct btrfs_fs_info *fs_info);
 int btrfs_cancel_balance(struct btrfs_fs_info *fs_info);
+int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info);
+int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info);
 int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset);
 int find_free_dev_extent(struct btrfs_trans_handle *trans,
                         struct btrfs_device *device, u64 num_bytes,
index d4c1206af9fca6009a7591a8d36b36684043bf52..43eb5592cdea83c83df854a489edea79d076cfda 100644 (file)
@@ -377,6 +377,31 @@ static void cachefiles_sync_cache(struct fscache_cache *_cache)
                                    ret);
 }
 
+/*
+ * check if the backing cache is updated to FS-Cache
+ * - called by FS-Cache when evaluates if need to invalidate the cache
+ */
+static bool cachefiles_check_consistency(struct fscache_operation *op)
+{
+       struct cachefiles_object *object;
+       struct cachefiles_cache *cache;
+       const struct cred *saved_cred;
+       int ret;
+
+       _enter("{OBJ%x}", op->object->debug_id);
+
+       object = container_of(op->object, struct cachefiles_object, fscache);
+       cache = container_of(object->fscache.cache,
+                            struct cachefiles_cache, cache);
+
+       cachefiles_begin_secure(cache, &saved_cred);
+       ret = cachefiles_check_auxdata(object);
+       cachefiles_end_secure(cache, saved_cred);
+
+       _leave(" = %d", ret);
+       return ret;
+}
+
 /*
  * notification the attributes on an object have changed
  * - called with reads/writes excluded by FS-Cache
@@ -522,4 +547,5 @@ const struct fscache_cache_ops cachefiles_cache_ops = {
        .write_page             = cachefiles_write_page,
        .uncache_page           = cachefiles_uncache_page,
        .dissociate_pages       = cachefiles_dissociate_pages,
+       .check_consistency      = cachefiles_check_consistency,
 };
index 49382519907a28ec7addc1f3a6257871cba9a025..5349473df1b1ff5b900f5eca7a8b1786669b5b0c 100644 (file)
@@ -235,6 +235,7 @@ extern int cachefiles_set_object_xattr(struct cachefiles_object *object,
                                       struct cachefiles_xattr *auxdata);
 extern int cachefiles_update_object_xattr(struct cachefiles_object *object,
                                          struct cachefiles_xattr *auxdata);
+extern int cachefiles_check_auxdata(struct cachefiles_object *object);
 extern int cachefiles_check_object_xattr(struct cachefiles_object *object,
                                         struct cachefiles_xattr *auxdata);
 extern int cachefiles_remove_object_xattr(struct cachefiles_cache *cache,
index 2476e5162609ffc4db6be49549e27999e288f06f..34c88b83e39f1214b0ed7f2c22bc58f5acd00fa4 100644 (file)
@@ -156,6 +156,42 @@ int cachefiles_update_object_xattr(struct cachefiles_object *object,
        return ret;
 }
 
+/*
+ * check the consistency between the backing cache and the FS-Cache cookie
+ */
+int cachefiles_check_auxdata(struct cachefiles_object *object)
+{
+       struct cachefiles_xattr *auxbuf;
+       struct dentry *dentry = object->dentry;
+       unsigned int dlen;
+       int ret;
+
+       ASSERT(dentry);
+       ASSERT(dentry->d_inode);
+       ASSERT(object->fscache.cookie->def->check_aux);
+
+       auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
+       if (!auxbuf)
+               return -ENOMEM;
+
+       auxbuf->len = vfs_getxattr(dentry, cachefiles_xattr_cache,
+                                  &auxbuf->type, 512 + 1);
+       if (auxbuf->len < 1)
+               return -ESTALE;
+
+       if (auxbuf->type != object->fscache.cookie->def->type)
+               return -ESTALE;
+
+       dlen = auxbuf->len - 1;
+       ret = fscache_check_aux(&object->fscache, &auxbuf->data, dlen);
+
+       kfree(auxbuf);
+       if (ret != FSCACHE_CHECKAUX_OKAY)
+               return -ESTALE;
+
+       return 0;
+}
+
 /*
  * check the state xattr on a cache file
  * - return -ESTALE if the object should be deleted
index 49bc78243db9f2f3f147de0bcc0e3c4f7f72fd66..ac9a2ef5bb9b8f0e8638c0d594e1cd51b5719c91 100644 (file)
@@ -16,3 +16,12 @@ config CEPH_FS
 
          If unsure, say N.
 
+if CEPH_FS
+config CEPH_FSCACHE
+       bool "Enable Ceph client caching support"
+       depends on CEPH_FS=m && FSCACHE || CEPH_FS=y && FSCACHE=y
+       help
+         Choose Y here to enable persistent, read-only local
+         caching support for Ceph clients using FS-Cache
+
+endif
index bd352125e829827246d5591d1a485e3b4e52f17b..32e30106a2f01e8bf62138981e1c4b678a509cfc 100644 (file)
@@ -9,3 +9,4 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \
        mds_client.o mdsmap.o strings.o ceph_frag.o \
        debugfs.o
 
+ceph-$(CONFIG_CEPH_FSCACHE) += cache.o
index 5318a3b704f6d6f908520a9c1fc18b4dadc9a509..6df8bd481425379006912990ee6f9461eaf3cf1b 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "cache.h"
 #include <linux/ceph/osd_client.h>
 
 /*
@@ -70,15 +71,16 @@ static int ceph_set_page_dirty(struct page *page)
        struct address_space *mapping = page->mapping;
        struct inode *inode;
        struct ceph_inode_info *ci;
-       int undo = 0;
        struct ceph_snap_context *snapc;
+       int ret;
 
        if (unlikely(!mapping))
                return !TestSetPageDirty(page);
 
-       if (TestSetPageDirty(page)) {
+       if (PageDirty(page)) {
                dout("%p set_page_dirty %p idx %lu -- already dirty\n",
                     mapping->host, page, page->index);
+               BUG_ON(!PagePrivate(page));
                return 0;
        }
 
@@ -107,35 +109,19 @@ static int ceph_set_page_dirty(struct page *page)
             snapc, snapc->seq, snapc->num_snaps);
        spin_unlock(&ci->i_ceph_lock);
 
-       /* now adjust page */
-       spin_lock_irq(&mapping->tree_lock);
-       if (page->mapping) {    /* Race with truncate? */
-               WARN_ON_ONCE(!PageUptodate(page));
-               account_page_dirtied(page, page->mapping);
-               radix_tree_tag_set(&mapping->page_tree,
-                               page_index(page), PAGECACHE_TAG_DIRTY);
-
-               /*
-                * Reference snap context in page->private.  Also set
-                * PagePrivate so that we get invalidatepage callback.
-                */
-               page->private = (unsigned long)snapc;
-               SetPagePrivate(page);
-       } else {
-               dout("ANON set_page_dirty %p (raced truncate?)\n", page);
-               undo = 1;
-       }
-
-       spin_unlock_irq(&mapping->tree_lock);
-
-       if (undo)
-               /* whoops, we failed to dirty the page */
-               ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+       /*
+        * Reference snap context in page->private.  Also set
+        * PagePrivate so that we get invalidatepage callback.
+        */
+       BUG_ON(PagePrivate(page));
+       page->private = (unsigned long)snapc;
+       SetPagePrivate(page);
 
-       __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
+       ret = __set_page_dirty_nobuffers(page);
+       WARN_ON(!PageLocked(page));
+       WARN_ON(!page->mapping);
 
-       BUG_ON(!PageDirty(page));
-       return 1;
+       return ret;
 }
 
 /*
@@ -150,11 +136,19 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset,
        struct ceph_inode_info *ci;
        struct ceph_snap_context *snapc = page_snap_context(page);
 
-       BUG_ON(!PageLocked(page));
-       BUG_ON(!PagePrivate(page));
-       BUG_ON(!page->mapping);
-
        inode = page->mapping->host;
+       ci = ceph_inode(inode);
+
+       if (offset != 0 || length != PAGE_CACHE_SIZE) {
+               dout("%p invalidatepage %p idx %lu partial dirty page %u~%u\n",
+                    inode, page, page->index, offset, length);
+               return;
+       }
+
+       ceph_invalidate_fscache_page(inode, page);
+
+       if (!PagePrivate(page))
+               return;
 
        /*
         * We can get non-dirty pages here due to races between
@@ -164,31 +158,28 @@ static void ceph_invalidatepage(struct page *page, unsigned int offset,
        if (!PageDirty(page))
                pr_err("%p invalidatepage %p page not dirty\n", inode, page);
 
-       if (offset == 0 && length == PAGE_CACHE_SIZE)
-               ClearPageChecked(page);
+       ClearPageChecked(page);
 
-       ci = ceph_inode(inode);
-       if (offset == 0 && length == PAGE_CACHE_SIZE) {
-               dout("%p invalidatepage %p idx %lu full dirty page\n",
-                    inode, page, page->index);
-               ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
-               ceph_put_snap_context(snapc);
-               page->private = 0;
-               ClearPagePrivate(page);
-       } else {
-               dout("%p invalidatepage %p idx %lu partial dirty page %u(%u)\n",
-                    inode, page, page->index, offset, length);
-       }
+       dout("%p invalidatepage %p idx %lu full dirty page\n",
+            inode, page, page->index);
+
+       ceph_put_wrbuffer_cap_refs(ci, 1, snapc);
+       ceph_put_snap_context(snapc);
+       page->private = 0;
+       ClearPagePrivate(page);
 }
 
-/* just a sanity check */
 static int ceph_releasepage(struct page *page, gfp_t g)
 {
        struct inode *inode = page->mapping ? page->mapping->host : NULL;
        dout("%p releasepage %p idx %lu\n", inode, page, page->index);
        WARN_ON(PageDirty(page));
-       WARN_ON(PagePrivate(page));
-       return 0;
+
+       /* Can we release the page from the cache? */
+       if (!ceph_release_fscache_page(page, g))
+               return 0;
+
+       return !PagePrivate(page);
 }
 
 /*
@@ -198,11 +189,16 @@ static int readpage_nounlock(struct file *filp, struct page *page)
 {
        struct inode *inode = file_inode(filp);
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct ceph_osd_client *osdc = 
+       struct ceph_osd_client *osdc =
                &ceph_inode_to_client(inode)->client->osdc;
        int err = 0;
        u64 len = PAGE_CACHE_SIZE;
 
+       err = ceph_readpage_from_fscache(inode, page);
+
+       if (err == 0)
+               goto out;
+
        dout("readpage inode %p file %p page %p index %lu\n",
             inode, filp, page, page->index);
        err = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout,
@@ -220,6 +216,9 @@ static int readpage_nounlock(struct file *filp, struct page *page)
        }
        SetPageUptodate(page);
 
+       if (err == 0)
+               ceph_readpage_to_fscache(inode, page);
+
 out:
        return err < 0 ? err : 0;
 }
@@ -262,6 +261,7 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg)
                     page->index);
                flush_dcache_page(page);
                SetPageUptodate(page);
+               ceph_readpage_to_fscache(inode, page);
                unlock_page(page);
                page_cache_release(page);
                bytes -= PAGE_CACHE_SIZE;
@@ -331,11 +331,12 @@ static int start_read(struct inode *inode, struct list_head *page_list, int max)
                page = list_entry(page_list->prev, struct page, lru);
                BUG_ON(PageLocked(page));
                list_del(&page->lru);
-               
+
                dout("start_read %p adding %p idx %lu\n", inode, page,
                     page->index);
                if (add_to_page_cache_lru(page, &inode->i_data, page->index,
                                          GFP_NOFS)) {
+                       ceph_fscache_uncache_page(inode, page);
                        page_cache_release(page);
                        dout("start_read %p add_to_page_cache failed %p\n",
                             inode, page);
@@ -378,6 +379,12 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
        int rc = 0;
        int max = 0;
 
+       rc = ceph_readpages_from_fscache(mapping->host, mapping, page_list,
+                                        &nr_pages);
+
+       if (rc == 0)
+               goto out;
+
        if (fsc->mount_options->rsize >= PAGE_CACHE_SIZE)
                max = (fsc->mount_options->rsize + PAGE_CACHE_SIZE - 1)
                        >> PAGE_SHIFT;
@@ -392,6 +399,8 @@ static int ceph_readpages(struct file *file, struct address_space *mapping,
                BUG_ON(rc == 0);
        }
 out:
+       ceph_fscache_readpages_cancel(inode, page_list);
+
        dout("readpages %p file %p ret %d\n", inode, file, rc);
        return rc;
 }
@@ -497,6 +506,8 @@ static int writepage_nounlock(struct page *page, struct writeback_control *wbc)
            CONGESTION_ON_THRESH(fsc->mount_options->congestion_kb))
                set_bdi_congested(&fsc->backing_dev_info, BLK_RW_ASYNC);
 
+       ceph_readpage_to_fscache(inode, page);
+
        set_page_writeback(page);
        err = ceph_osdc_writepages(osdc, ceph_vino(inode),
                                   &ci->i_layout, snapc,
@@ -552,7 +563,6 @@ static void ceph_release_pages(struct page **pages, int num)
        pagevec_release(&pvec);
 }
 
-
 /*
  * async writeback completion handler.
  *
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
new file mode 100644 (file)
index 0000000..6bfe65e
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ * Ceph cache definitions.
+ *
+ *  Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved.
+ *  Written by Milosz Tanski (milosz@adfin.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:
+ *  Free Software Foundation
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02111-1301  USA
+ *
+ */
+
+#include "super.h"
+#include "cache.h"
+
+struct ceph_aux_inode {
+       struct timespec mtime;
+       loff_t          size;
+};
+
+struct fscache_netfs ceph_cache_netfs = {
+       .name           = "ceph",
+       .version        = 0,
+};
+
+static uint16_t ceph_fscache_session_get_key(const void *cookie_netfs_data,
+                                            void *buffer, uint16_t maxbuf)
+{
+       const struct ceph_fs_client* fsc = cookie_netfs_data;
+       uint16_t klen;
+
+       klen = sizeof(fsc->client->fsid);
+       if (klen > maxbuf)
+               return 0;
+
+       memcpy(buffer, &fsc->client->fsid, klen);
+       return klen;
+}
+
+static const struct fscache_cookie_def ceph_fscache_fsid_object_def = {
+       .name           = "CEPH.fsid",
+       .type           = FSCACHE_COOKIE_TYPE_INDEX,
+       .get_key        = ceph_fscache_session_get_key,
+};
+
+int ceph_fscache_register(void)
+{
+       return fscache_register_netfs(&ceph_cache_netfs);
+}
+
+void ceph_fscache_unregister(void)
+{
+       fscache_unregister_netfs(&ceph_cache_netfs);
+}
+
+int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
+{
+       fsc->fscache = fscache_acquire_cookie(ceph_cache_netfs.primary_index,
+                                             &ceph_fscache_fsid_object_def,
+                                             fsc);
+
+       if (fsc->fscache == NULL) {
+               pr_err("Unable to resgister fsid: %p fscache cookie", fsc);
+               return 0;
+       }
+
+       fsc->revalidate_wq = alloc_workqueue("ceph-revalidate", 0, 1);
+       if (fsc->revalidate_wq == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static uint16_t ceph_fscache_inode_get_key(const void *cookie_netfs_data,
+                                          void *buffer, uint16_t maxbuf)
+{
+       const struct ceph_inode_info* ci = cookie_netfs_data;
+       uint16_t klen;
+
+       /* use ceph virtual inode (id + snaphot) */
+       klen = sizeof(ci->i_vino);
+       if (klen > maxbuf)
+               return 0;
+
+       memcpy(buffer, &ci->i_vino, klen);
+       return klen;
+}
+
+static uint16_t ceph_fscache_inode_get_aux(const void *cookie_netfs_data,
+                                          void *buffer, uint16_t bufmax)
+{
+       struct ceph_aux_inode aux;
+       const struct ceph_inode_info* ci = cookie_netfs_data;
+       const struct inode* inode = &ci->vfs_inode;
+
+       memset(&aux, 0, sizeof(aux));
+       aux.mtime = inode->i_mtime;
+       aux.size = inode->i_size;
+
+       memcpy(buffer, &aux, sizeof(aux));
+
+       return sizeof(aux);
+}
+
+static void ceph_fscache_inode_get_attr(const void *cookie_netfs_data,
+                                       uint64_t *size)
+{
+       const struct ceph_inode_info* ci = cookie_netfs_data;
+       const struct inode* inode = &ci->vfs_inode;
+
+       *size = inode->i_size;
+}
+
+static enum fscache_checkaux ceph_fscache_inode_check_aux(
+       void *cookie_netfs_data, const void *data, uint16_t dlen)
+{
+       struct ceph_aux_inode aux;
+       struct ceph_inode_info* ci = cookie_netfs_data;
+       struct inode* inode = &ci->vfs_inode;
+
+       if (dlen != sizeof(aux))
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       memset(&aux, 0, sizeof(aux));
+       aux.mtime = inode->i_mtime;
+       aux.size = inode->i_size;
+
+       if (memcmp(data, &aux, sizeof(aux)) != 0)
+               return FSCACHE_CHECKAUX_OBSOLETE;
+
+       dout("ceph inode 0x%p cached okay", ci);
+       return FSCACHE_CHECKAUX_OKAY;
+}
+
+static void ceph_fscache_inode_now_uncached(void* cookie_netfs_data)
+{
+       struct ceph_inode_info* ci = cookie_netfs_data;
+       struct pagevec pvec;
+       pgoff_t first;
+       int loop, nr_pages;
+
+       pagevec_init(&pvec, 0);
+       first = 0;
+
+       dout("ceph inode 0x%p now uncached", ci);
+
+       while (1) {
+               nr_pages = pagevec_lookup(&pvec, ci->vfs_inode.i_mapping, first,
+                                         PAGEVEC_SIZE - pagevec_count(&pvec));
+
+               if (!nr_pages)
+                       break;
+
+               for (loop = 0; loop < nr_pages; loop++)
+                       ClearPageFsCache(pvec.pages[loop]);
+
+               first = pvec.pages[nr_pages - 1]->index + 1;
+
+               pvec.nr = nr_pages;
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+}
+
+static const struct fscache_cookie_def ceph_fscache_inode_object_def = {
+       .name           = "CEPH.inode",
+       .type           = FSCACHE_COOKIE_TYPE_DATAFILE,
+       .get_key        = ceph_fscache_inode_get_key,
+       .get_attr       = ceph_fscache_inode_get_attr,
+       .get_aux        = ceph_fscache_inode_get_aux,
+       .check_aux      = ceph_fscache_inode_check_aux,
+       .now_uncached   = ceph_fscache_inode_now_uncached,
+};
+
+void ceph_fscache_register_inode_cookie(struct ceph_fs_client* fsc,
+                                       struct ceph_inode_info* ci)
+{
+       struct inode* inode = &ci->vfs_inode;
+
+       /* No caching for filesystem */
+       if (fsc->fscache == NULL)
+               return;
+
+       /* Only cache for regular files that are read only */
+       if ((ci->vfs_inode.i_mode & S_IFREG) == 0)
+               return;
+
+       /* Avoid multiple racing open requests */
+       mutex_lock(&inode->i_mutex);
+
+       if (ci->fscache)
+               goto done;
+
+       ci->fscache = fscache_acquire_cookie(fsc->fscache,
+                                            &ceph_fscache_inode_object_def,
+                                            ci);
+done:
+       mutex_unlock(&inode->i_mutex);
+
+}
+
+void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci)
+{
+       struct fscache_cookie* cookie;
+
+       if ((cookie = ci->fscache) == NULL)
+               return;
+
+       ci->fscache = NULL;
+
+       fscache_uncache_all_inode_pages(cookie, &ci->vfs_inode);
+       fscache_relinquish_cookie(cookie, 0);
+}
+
+static void ceph_vfs_readpage_complete(struct page *page, void *data, int error)
+{
+       if (!error)
+               SetPageUptodate(page);
+}
+
+static void ceph_vfs_readpage_complete_unlock(struct page *page, void *data, int error)
+{
+       if (!error)
+               SetPageUptodate(page);
+
+       unlock_page(page);
+}
+
+static inline int cache_valid(struct ceph_inode_info *ci)
+{
+       return ((ceph_caps_issued(ci) & CEPH_CAP_FILE_CACHE) &&
+               (ci->i_fscache_gen == ci->i_rdcache_gen));
+}
+
+
+/* Atempt to read from the fscache,
+ *
+ * This function is called from the readpage_nounlock context. DO NOT attempt to
+ * unlock the page here (or in the callback).
+ */
+int ceph_readpage_from_fscache(struct inode *inode, struct page *page)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int ret;
+
+       if (!cache_valid(ci))
+               return -ENOBUFS;
+
+       ret = fscache_read_or_alloc_page(ci->fscache, page,
+                                        ceph_vfs_readpage_complete, NULL,
+                                        GFP_KERNEL);
+
+       switch (ret) {
+               case 0: /* Page found */
+                       dout("page read submitted\n");
+                       return 0;
+               case -ENOBUFS: /* Pages were not found, and can't be */
+               case -ENODATA: /* Pages were not found */
+                       dout("page/inode not in cache\n");
+                       return ret;
+               default:
+                       dout("%s: unknown error ret = %i\n", __func__, ret);
+                       return ret;
+       }
+}
+
+int ceph_readpages_from_fscache(struct inode *inode,
+                                 struct address_space *mapping,
+                                 struct list_head *pages,
+                                 unsigned *nr_pages)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int ret;
+
+       if (!cache_valid(ci))
+               return -ENOBUFS;
+
+       ret = fscache_read_or_alloc_pages(ci->fscache, mapping, pages, nr_pages,
+                                         ceph_vfs_readpage_complete_unlock,
+                                         NULL, mapping_gfp_mask(mapping));
+
+       switch (ret) {
+               case 0: /* All pages found */
+                       dout("all-page read submitted\n");
+                       return 0;
+               case -ENOBUFS: /* Some pages were not found, and can't be */
+               case -ENODATA: /* some pages were not found */
+                       dout("page/inode not in cache\n");
+                       return ret;
+               default:
+                       dout("%s: unknown error ret = %i\n", __func__, ret);
+                       return ret;
+       }
+}
+
+void ceph_readpage_to_fscache(struct inode *inode, struct page *page)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int ret;
+
+       if (!PageFsCache(page))
+               return;
+
+       if (!cache_valid(ci))
+               return;
+
+       ret = fscache_write_page(ci->fscache, page, GFP_KERNEL);
+       if (ret)
+                fscache_uncache_page(ci->fscache, page);
+}
+
+void ceph_invalidate_fscache_page(struct inode* inode, struct page *page)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       fscache_wait_on_page_write(ci->fscache, page);
+       fscache_uncache_page(ci->fscache, page);
+}
+
+void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
+{
+       if (fsc->revalidate_wq)
+               destroy_workqueue(fsc->revalidate_wq);
+
+       fscache_relinquish_cookie(fsc->fscache, 0);
+       fsc->fscache = NULL;
+}
+
+static void ceph_revalidate_work(struct work_struct *work)
+{
+       int issued;
+       u32 orig_gen;
+       struct ceph_inode_info *ci = container_of(work, struct ceph_inode_info,
+                                                 i_revalidate_work);
+       struct inode *inode = &ci->vfs_inode;
+
+       spin_lock(&ci->i_ceph_lock);
+       issued = __ceph_caps_issued(ci, NULL);
+       orig_gen = ci->i_rdcache_gen;
+       spin_unlock(&ci->i_ceph_lock);
+
+       if (!(issued & CEPH_CAP_FILE_CACHE)) {
+               dout("revalidate_work lost cache before validation %p\n",
+                    inode);
+               goto out;
+       }
+
+       if (!fscache_check_consistency(ci->fscache))
+               fscache_invalidate(ci->fscache);
+
+       spin_lock(&ci->i_ceph_lock);
+       /* Update the new valid generation (backwards sanity check too) */
+       if (orig_gen > ci->i_fscache_gen) {
+               ci->i_fscache_gen = orig_gen;
+       }
+       spin_unlock(&ci->i_ceph_lock);
+
+out:
+       iput(&ci->vfs_inode);
+}
+
+void ceph_queue_revalidate(struct inode *inode)
+{
+       struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       if (fsc->revalidate_wq == NULL || ci->fscache == NULL)
+               return;
+
+       ihold(inode);
+
+       if (queue_work(ceph_sb_to_client(inode->i_sb)->revalidate_wq,
+                      &ci->i_revalidate_work)) {
+               dout("ceph_queue_revalidate %p\n", inode);
+       } else {
+               dout("ceph_queue_revalidate %p failed\n)", inode);
+               iput(inode);
+       }
+}
+
+void ceph_fscache_inode_init(struct ceph_inode_info *ci)
+{
+       ci->fscache = NULL;
+       /* The first load is verifed cookie open time */
+       ci->i_fscache_gen = 1;
+       INIT_WORK(&ci->i_revalidate_work, ceph_revalidate_work);
+}
diff --git a/fs/ceph/cache.h b/fs/ceph/cache.h
new file mode 100644 (file)
index 0000000..ba94940
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Ceph cache definitions.
+ *
+ *  Copyright (C) 2013 by Adfin Solutions, Inc. All Rights Reserved.
+ *  Written by Milosz Tanski (milosz@adfin.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:
+ *  Free Software Foundation
+ *  51 Franklin Street, Fifth Floor
+ *  Boston, MA  02111-1301  USA
+ *
+ */
+
+#ifndef _CEPH_CACHE_H
+#define _CEPH_CACHE_H
+
+#ifdef CONFIG_CEPH_FSCACHE
+
+extern struct fscache_netfs ceph_cache_netfs;
+
+int ceph_fscache_register(void);
+void ceph_fscache_unregister(void);
+
+int ceph_fscache_register_fs(struct ceph_fs_client* fsc);
+void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc);
+
+void ceph_fscache_inode_init(struct ceph_inode_info *ci);
+void ceph_fscache_register_inode_cookie(struct ceph_fs_client* fsc,
+                                       struct ceph_inode_info* ci);
+void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci);
+
+int ceph_readpage_from_fscache(struct inode *inode, struct page *page);
+int ceph_readpages_from_fscache(struct inode *inode,
+                               struct address_space *mapping,
+                               struct list_head *pages,
+                               unsigned *nr_pages);
+void ceph_readpage_to_fscache(struct inode *inode, struct page *page);
+void ceph_invalidate_fscache_page(struct inode* inode, struct page *page);
+void ceph_queue_revalidate(struct inode *inode);
+
+static inline void ceph_fscache_invalidate(struct inode *inode)
+{
+       fscache_invalidate(ceph_inode(inode)->fscache);
+}
+
+static inline void ceph_fscache_uncache_page(struct inode *inode,
+                                            struct page *page)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       return fscache_uncache_page(ci->fscache, page);
+}
+
+static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp)
+{
+       struct inode* inode = page->mapping->host;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       return fscache_maybe_release_page(ci->fscache, page, gfp);
+}
+
+static inline void ceph_fscache_readpages_cancel(struct inode *inode,
+                                                struct list_head *pages)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       return fscache_readpages_cancel(ci->fscache, pages);
+}
+
+#else
+
+static inline int ceph_fscache_register(void)
+{
+       return 0;
+}
+
+static inline void ceph_fscache_unregister(void)
+{
+}
+
+static inline int ceph_fscache_register_fs(struct ceph_fs_client* fsc)
+{
+       return 0;
+}
+
+static inline void ceph_fscache_unregister_fs(struct ceph_fs_client* fsc)
+{
+}
+
+static inline void ceph_fscache_inode_init(struct ceph_inode_info *ci)
+{
+}
+
+static inline void ceph_fscache_register_inode_cookie(struct ceph_fs_client* parent_fsc,
+                                                     struct ceph_inode_info* ci)
+{
+}
+
+static inline void ceph_fscache_uncache_page(struct inode *inode,
+                                            struct page *pages)
+{
+}
+
+static inline int ceph_readpage_from_fscache(struct inode* inode,
+                                            struct page *page)
+{
+       return -ENOBUFS;
+}
+
+static inline int ceph_readpages_from_fscache(struct inode *inode,
+                                             struct address_space *mapping,
+                                             struct list_head *pages,
+                                             unsigned *nr_pages)
+{
+       return -ENOBUFS;
+}
+
+static inline void ceph_readpage_to_fscache(struct inode *inode,
+                                           struct page *page)
+{
+}
+
+static inline void ceph_fscache_invalidate(struct inode *inode)
+{
+}
+
+static inline void ceph_invalidate_fscache_page(struct inode *inode,
+                                               struct page *page)
+{
+}
+
+static inline void ceph_fscache_unregister_inode_cookie(struct ceph_inode_info* ci)
+{
+}
+
+static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp)
+{
+       return 1;
+}
+
+static inline void ceph_fscache_readpages_cancel(struct inode *inode,
+                                                struct list_head *pages)
+{
+}
+
+static inline void ceph_queue_revalidate(struct inode *inode)
+{
+}
+
+#endif
+
+#endif
index 25442b40c25a71761596e071612140f01279fb69..13976c33332ec1fd7ca3999053b15b7079c5ab31 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "cache.h"
 #include <linux/ceph/decode.h>
 #include <linux/ceph/messenger.h>
 
@@ -479,8 +480,9 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap,
         * i_rdcache_gen.
         */
        if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) &&
-           (had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0)
+           (had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0) {
                ci->i_rdcache_gen++;
+       }
 
        /*
         * if we are newly issued FILE_SHARED, mark dir not complete; we
@@ -2072,19 +2074,17 @@ static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want,
        /* finish pending truncate */
        while (ci->i_truncate_pending) {
                spin_unlock(&ci->i_ceph_lock);
-               if (!(need & CEPH_CAP_FILE_WR))
-                       mutex_lock(&inode->i_mutex);
                __ceph_do_pending_vmtruncate(inode);
-               if (!(need & CEPH_CAP_FILE_WR))
-                       mutex_unlock(&inode->i_mutex);
                spin_lock(&ci->i_ceph_lock);
        }
 
-       if (need & CEPH_CAP_FILE_WR) {
+       have = __ceph_caps_issued(ci, &implemented);
+
+       if (have & need & CEPH_CAP_FILE_WR) {
                if (endoff >= 0 && endoff > (loff_t)ci->i_max_size) {
                        dout("get_cap_refs %p endoff %llu > maxsize %llu\n",
                             inode, endoff, ci->i_max_size);
-                       if (endoff > ci->i_wanted_max_size) {
+                       if (endoff > ci->i_requested_max_size) {
                                *check_max = 1;
                                ret = 1;
                        }
@@ -2099,7 +2099,6 @@ static int try_get_cap_refs(struct ceph_inode_info *ci, int need, int want,
                        goto out;
                }
        }
-       have = __ceph_caps_issued(ci, &implemented);
 
        if ((have & need) == need) {
                /*
@@ -2141,14 +2140,17 @@ static void check_max_size(struct inode *inode, loff_t endoff)
 
        /* do we need to explicitly request a larger max_size? */
        spin_lock(&ci->i_ceph_lock);
-       if ((endoff >= ci->i_max_size ||
-            endoff > (inode->i_size << 1)) &&
-           endoff > ci->i_wanted_max_size) {
+       if (endoff >= ci->i_max_size && endoff > ci->i_wanted_max_size) {
                dout("write %p at large endoff %llu, req max_size\n",
                     inode, endoff);
                ci->i_wanted_max_size = endoff;
-               check = 1;
        }
+       /* duplicate ceph_check_caps()'s logic */
+       if (ci->i_auth_cap &&
+           (ci->i_auth_cap->issued & CEPH_CAP_FILE_WR) &&
+           ci->i_wanted_max_size > ci->i_max_size &&
+           ci->i_wanted_max_size > ci->i_requested_max_size)
+               check = 1;
        spin_unlock(&ci->i_ceph_lock);
        if (check)
                ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
@@ -2333,6 +2335,38 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr,
                iput(inode);
 }
 
+/*
+ * Invalidate unlinked inode's aliases, so we can drop the inode ASAP.
+ */
+static void invalidate_aliases(struct inode *inode)
+{
+       struct dentry *dn, *prev = NULL;
+
+       dout("invalidate_aliases inode %p\n", inode);
+       d_prune_aliases(inode);
+       /*
+        * For non-directory inode, d_find_alias() only returns
+        * connected dentry. After calling d_invalidate(), the
+        * dentry become disconnected.
+        *
+        * For directory inode, d_find_alias() can return
+        * disconnected dentry. But directory inode should have
+        * one alias at most.
+        */
+       while ((dn = d_find_alias(inode))) {
+               if (dn == prev) {
+                       dput(dn);
+                       break;
+               }
+               d_invalidate(dn);
+               if (prev)
+                       dput(prev);
+               prev = dn;
+       }
+       if (prev)
+               dput(prev);
+}
+
 /*
  * Handle a cap GRANT message from the MDS.  (Note that a GRANT may
  * actually be a revocation if it specifies a smaller cap set.)
@@ -2361,8 +2395,9 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        int check_caps = 0;
        int wake = 0;
        int writeback = 0;
-       int revoked_rdcache = 0;
        int queue_invalidate = 0;
+       int deleted_inode = 0;
+       int queue_revalidate = 0;
 
        dout("handle_cap_grant inode %p cap %p mds%d seq %d %s\n",
             inode, cap, mds, seq, ceph_cap_string(newcaps));
@@ -2377,9 +2412,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) &&
            (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 &&
            !ci->i_wrbuffer_ref) {
-               if (try_nonblocking_invalidate(inode) == 0) {
-                       revoked_rdcache = 1;
-               } else {
+               if (try_nonblocking_invalidate(inode)) {
                        /* there were locked pages.. invalidate later
                           in a separate thread. */
                        if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
@@ -2387,6 +2420,8 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                                ci->i_rdcache_revoking = ci->i_rdcache_gen;
                        }
                }
+
+               ceph_fscache_invalidate(inode);
        }
 
        /* side effects now are allowed */
@@ -2407,8 +2442,12 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                     from_kgid(&init_user_ns, inode->i_gid));
        }
 
-       if ((issued & CEPH_CAP_LINK_EXCL) == 0)
+       if ((issued & CEPH_CAP_LINK_EXCL) == 0) {
                set_nlink(inode, le32_to_cpu(grant->nlink));
+               if (inode->i_nlink == 0 &&
+                   (newcaps & (CEPH_CAP_LINK_SHARED | CEPH_CAP_LINK_EXCL)))
+                       deleted_inode = 1;
+       }
 
        if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) {
                int len = le32_to_cpu(grant->xattr_len);
@@ -2424,6 +2463,11 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                }
        }
 
+       /* Do we need to revalidate our fscache cookie. Don't bother on the
+        * first cache cap as we already validate at cookie creation time. */
+       if ((issued & CEPH_CAP_FILE_CACHE) && ci->i_rdcache_gen > 1)
+               queue_revalidate = 1;
+
        /* size/ctime/mtime/atime? */
        ceph_fill_file_size(inode, issued,
                            le32_to_cpu(grant->truncate_seq),
@@ -2508,6 +2552,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        BUG_ON(cap->issued & ~cap->implemented);
 
        spin_unlock(&ci->i_ceph_lock);
+
        if (writeback)
                /*
                 * queue inode for writeback: we can't actually call
@@ -2517,6 +2562,10 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                ceph_queue_writeback(inode);
        if (queue_invalidate)
                ceph_queue_invalidate(inode);
+       if (deleted_inode)
+               invalidate_aliases(inode);
+       if (queue_revalidate)
+               ceph_queue_revalidate(inode);
        if (wake)
                wake_up_all(&ci->i_cap_wq);
 
@@ -2673,8 +2722,10 @@ static void handle_cap_trunc(struct inode *inode,
                                          truncate_seq, truncate_size, size);
        spin_unlock(&ci->i_ceph_lock);
 
-       if (queue_trunc)
+       if (queue_trunc) {
                ceph_queue_vmtruncate(inode);
+               ceph_fscache_invalidate(inode);
+       }
 }
 
 /*
index a40ceda47a3218ee53c2167d8844899c5de3e9cf..868b61d56cac77f3a8328d5ba4851ec7947fe827 100644 (file)
@@ -793,6 +793,8 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
        req->r_locked_dir = dir;
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
+       /* release LINK_SHARED on source inode (mds will lock it) */
+       req->r_old_inode_drop = CEPH_CAP_LINK_SHARED;
        err = ceph_mdsc_do_request(mdsc, dir, req);
        if (err) {
                d_drop(dentry);
index 2ddf061c1c4af730885365b07dcb9388d7af98f9..3de89829e2a162ab6bce2a58296b25aef9235c43 100644 (file)
@@ -8,9 +8,11 @@
 #include <linux/namei.h>
 #include <linux/writeback.h>
 #include <linux/aio.h>
+#include <linux/falloc.h>
 
 #include "super.h"
 #include "mds_client.h"
+#include "cache.h"
 
 /*
  * Ceph file operations
@@ -68,9 +70,23 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
 {
        struct ceph_file_info *cf;
        int ret = 0;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_fs_client *fsc = ceph_sb_to_client(inode->i_sb);
+       struct ceph_mds_client *mdsc = fsc->mdsc;
 
        switch (inode->i_mode & S_IFMT) {
        case S_IFREG:
+               /* First file open request creates the cookie, we want to keep
+                * this cookie around for the filetime of the inode as not to
+                * have to worry about fscache register / revoke / operation
+                * races.
+                *
+                * Also, if we know the operation is going to invalidate data
+                * (non readonly) just nuke the cache right away.
+                */
+               ceph_fscache_register_inode_cookie(mdsc->fsc, ci);
+               if ((fmode & CEPH_FILE_MODE_WR))
+                       ceph_fscache_invalidate(inode);
        case S_IFDIR:
                dout("init_file %p %p 0%o (regular)\n", inode, file,
                     inode->i_mode);
@@ -181,6 +197,7 @@ int ceph_open(struct inode *inode, struct file *file)
                spin_unlock(&ci->i_ceph_lock);
                return ceph_init_file(inode, file, fmode);
        }
+
        spin_unlock(&ci->i_ceph_lock);
 
        dout("open fmode %d wants %s\n", fmode, ceph_cap_string(wanted));
@@ -191,6 +208,7 @@ int ceph_open(struct inode *inode, struct file *file)
        }
        req->r_inode = inode;
        ihold(inode);
+
        req->r_num_caps = 1;
        if (flags & (O_CREAT|O_TRUNC))
                parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
@@ -313,9 +331,9 @@ static int striped_read(struct inode *inode,
 {
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_inode_info *ci = ceph_inode(inode);
-       u64 pos, this_len;
+       u64 pos, this_len, left;
        int io_align, page_align;
-       int left, pages_left;
+       int pages_left;
        int read;
        struct page **page_pos;
        int ret;
@@ -346,47 +364,40 @@ more:
                ret = 0;
        hit_stripe = this_len < left;
        was_short = ret >= 0 && ret < this_len;
-       dout("striped_read %llu~%u (read %u) got %d%s%s\n", pos, left, read,
+       dout("striped_read %llu~%llu (read %u) got %d%s%s\n", pos, left, read,
             ret, hit_stripe ? " HITSTRIPE" : "", was_short ? " SHORT" : "");
 
-       if (ret > 0) {
-               int didpages = (page_align + ret) >> PAGE_CACHE_SHIFT;
-
-               if (read < pos - off) {
-                       dout(" zero gap %llu to %llu\n", off + read, pos);
-                       ceph_zero_page_vector_range(page_align + read,
-                                                   pos - off - read, pages);
+       if (ret >= 0) {
+               int didpages;
+               if (was_short && (pos + ret < inode->i_size)) {
+                       u64 tmp = min(this_len - ret,
+                                       inode->i_size - pos - ret);
+                       dout(" zero gap %llu to %llu\n",
+                               pos + ret, pos + ret + tmp);
+                       ceph_zero_page_vector_range(page_align + read + ret,
+                                                       tmp, pages);
+                       ret += tmp;
                }
+
+               didpages = (page_align + ret) >> PAGE_CACHE_SHIFT;
                pos += ret;
                read = pos - off;
                left -= ret;
                page_pos += didpages;
                pages_left -= didpages;
 
-               /* hit stripe*/
-               if (left && hit_stripe)
+               /* hit stripe and need continue*/
+               if (left && hit_stripe && pos < inode->i_size)
                        goto more;
        }
 
-       if (was_short) {
+       if (read > 0) {
+               ret = read;
                /* did we bounce off eof? */
                if (pos + left > inode->i_size)
                        *checkeof = 1;
-
-               /* zero trailing bytes (inside i_size) */
-               if (left > 0 && pos < inode->i_size) {
-                       if (pos + left > inode->i_size)
-                               left = inode->i_size - pos;
-
-                       dout("zero tail %d\n", left);
-                       ceph_zero_page_vector_range(page_align + read, left,
-                                                   pages);
-                       read += left;
-               }
        }
 
-       if (ret >= 0)
-               ret = read;
        dout("striped_read returns %d\n", ret);
        return ret;
 }
@@ -618,6 +629,8 @@ out:
                if (check_caps)
                        ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY,
                                        NULL);
+       } else if (ret != -EOLDSNAPC && written > 0) {
+               ret = written;
        }
        return ret;
 }
@@ -659,7 +672,6 @@ again:
 
        if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
            (iocb->ki_filp->f_flags & O_DIRECT) ||
-           (inode->i_sb->s_flags & MS_SYNCHRONOUS) ||
            (fi->flags & CEPH_F_SYNC))
                /* hmm, this isn't really async... */
                ret = ceph_sync_read(filp, base, len, ppos, &checkeof);
@@ -711,13 +723,11 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov,
                &ceph_sb_to_client(inode->i_sb)->client->osdc;
        ssize_t count, written = 0;
        int err, want, got;
-       bool hold_mutex;
 
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
 
        mutex_lock(&inode->i_mutex);
-       hold_mutex = true;
 
        err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
        if (err)
@@ -763,18 +773,31 @@ retry_snap:
 
        if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
            (iocb->ki_filp->f_flags & O_DIRECT) ||
-           (inode->i_sb->s_flags & MS_SYNCHRONOUS) ||
            (fi->flags & CEPH_F_SYNC)) {
                mutex_unlock(&inode->i_mutex);
                written = ceph_sync_write(file, iov->iov_base, count,
                                          pos, &iocb->ki_pos);
+               if (written == -EOLDSNAPC) {
+                       dout("aio_write %p %llx.%llx %llu~%u"
+                               "got EOLDSNAPC, retrying\n",
+                               inode, ceph_vinop(inode),
+                               pos, (unsigned)iov->iov_len);
+                       mutex_lock(&inode->i_mutex);
+                       goto retry_snap;
+               }
        } else {
+               /*
+                * No need to acquire the i_truncate_mutex. Because
+                * the MDS revokes Fwb caps before sending truncate
+                * message to us. We can't get Fwb cap while there
+                * are pending vmtruncate. So write and vmtruncate
+                * can not run at the same time
+                */
                written = generic_file_buffered_write(iocb, iov, nr_segs,
                                                      pos, &iocb->ki_pos,
                                                      count, 0);
                mutex_unlock(&inode->i_mutex);
        }
-       hold_mutex = false;
 
        if (written >= 0) {
                int dirty;
@@ -798,18 +821,12 @@ retry_snap:
                        written = err;
        }
 
-       if (written == -EOLDSNAPC) {
-               dout("aio_write %p %llx.%llx %llu~%u got EOLDSNAPC, retrying\n",
-                    inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len);
-               mutex_lock(&inode->i_mutex);
-               hold_mutex = true;
-               goto retry_snap;
-       }
+       goto out_unlocked;
+
 out:
-       if (hold_mutex)
-               mutex_unlock(&inode->i_mutex);
+       mutex_unlock(&inode->i_mutex);
+out_unlocked:
        current->backing_dev_info = NULL;
-
        return written ? written : err;
 }
 
@@ -822,7 +839,6 @@ static loff_t ceph_llseek(struct file *file, loff_t offset, int whence)
        int ret;
 
        mutex_lock(&inode->i_mutex);
-       __ceph_do_pending_vmtruncate(inode);
 
        if (whence == SEEK_END || whence == SEEK_DATA || whence == SEEK_HOLE) {
                ret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
@@ -871,6 +887,204 @@ out:
        return offset;
 }
 
+static inline void ceph_zero_partial_page(
+       struct inode *inode, loff_t offset, unsigned size)
+{
+       struct page *page;
+       pgoff_t index = offset >> PAGE_CACHE_SHIFT;
+
+       page = find_lock_page(inode->i_mapping, index);
+       if (page) {
+               wait_on_page_writeback(page);
+               zero_user(page, offset & (PAGE_CACHE_SIZE - 1), size);
+               unlock_page(page);
+               page_cache_release(page);
+       }
+}
+
+static void ceph_zero_pagecache_range(struct inode *inode, loff_t offset,
+                                     loff_t length)
+{
+       loff_t nearly = round_up(offset, PAGE_CACHE_SIZE);
+       if (offset < nearly) {
+               loff_t size = nearly - offset;
+               if (length < size)
+                       size = length;
+               ceph_zero_partial_page(inode, offset, size);
+               offset += size;
+               length -= size;
+       }
+       if (length >= PAGE_CACHE_SIZE) {
+               loff_t size = round_down(length, PAGE_CACHE_SIZE);
+               truncate_pagecache_range(inode, offset, offset + size - 1);
+               offset += size;
+               length -= size;
+       }
+       if (length)
+               ceph_zero_partial_page(inode, offset, length);
+}
+
+static int ceph_zero_partial_object(struct inode *inode,
+                                   loff_t offset, loff_t *length)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
+       struct ceph_osd_request *req;
+       int ret = 0;
+       loff_t zero = 0;
+       int op;
+
+       if (!length) {
+               op = offset ? CEPH_OSD_OP_DELETE : CEPH_OSD_OP_TRUNCATE;
+               length = &zero;
+       } else {
+               op = CEPH_OSD_OP_ZERO;
+       }
+
+       req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
+                                       ceph_vino(inode),
+                                       offset, length,
+                                       1, op,
+                                       CEPH_OSD_FLAG_WRITE |
+                                       CEPH_OSD_FLAG_ONDISK,
+                                       NULL, 0, 0, false);
+       if (IS_ERR(req)) {
+               ret = PTR_ERR(req);
+               goto out;
+       }
+
+       ceph_osdc_build_request(req, offset, NULL, ceph_vino(inode).snap,
+                               &inode->i_mtime);
+
+       ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
+       if (!ret) {
+               ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+               if (ret == -ENOENT)
+                       ret = 0;
+       }
+       ceph_osdc_put_request(req);
+
+out:
+       return ret;
+}
+
+static int ceph_zero_objects(struct inode *inode, loff_t offset, loff_t length)
+{
+       int ret = 0;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       s32 stripe_unit = ceph_file_layout_su(ci->i_layout);
+       s32 stripe_count = ceph_file_layout_stripe_count(ci->i_layout);
+       s32 object_size = ceph_file_layout_object_size(ci->i_layout);
+       u64 object_set_size = object_size * stripe_count;
+       u64 nearly, t;
+
+       /* round offset up to next period boundary */
+       nearly = offset + object_set_size - 1;
+       t = nearly;
+       nearly -= do_div(t, object_set_size);
+
+       while (length && offset < nearly) {
+               loff_t size = length;
+               ret = ceph_zero_partial_object(inode, offset, &size);
+               if (ret < 0)
+                       return ret;
+               offset += size;
+               length -= size;
+       }
+       while (length >= object_set_size) {
+               int i;
+               loff_t pos = offset;
+               for (i = 0; i < stripe_count; ++i) {
+                       ret = ceph_zero_partial_object(inode, pos, NULL);
+                       if (ret < 0)
+                               return ret;
+                       pos += stripe_unit;
+               }
+               offset += object_set_size;
+               length -= object_set_size;
+       }
+       while (length) {
+               loff_t size = length;
+               ret = ceph_zero_partial_object(inode, offset, &size);
+               if (ret < 0)
+                       return ret;
+               offset += size;
+               length -= size;
+       }
+       return ret;
+}
+
+static long ceph_fallocate(struct file *file, int mode,
+                               loff_t offset, loff_t length)
+{
+       struct ceph_file_info *fi = file->private_data;
+       struct inode *inode = file->f_dentry->d_inode;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_osd_client *osdc =
+               &ceph_inode_to_client(inode)->client->osdc;
+       int want, got = 0;
+       int dirty;
+       int ret = 0;
+       loff_t endoff = 0;
+       loff_t size;
+
+       if (!S_ISREG(inode->i_mode))
+               return -EOPNOTSUPP;
+
+       if (IS_SWAPFILE(inode))
+               return -ETXTBSY;
+
+       mutex_lock(&inode->i_mutex);
+
+       if (ceph_snap(inode) != CEPH_NOSNAP) {
+               ret = -EROFS;
+               goto unlock;
+       }
+
+       if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL) &&
+               !(mode & FALLOC_FL_PUNCH_HOLE)) {
+               ret = -ENOSPC;
+               goto unlock;
+       }
+
+       size = i_size_read(inode);
+       if (!(mode & FALLOC_FL_KEEP_SIZE))
+               endoff = offset + length;
+
+       if (fi->fmode & CEPH_FILE_MODE_LAZY)
+               want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
+       else
+               want = CEPH_CAP_FILE_BUFFER;
+
+       ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff);
+       if (ret < 0)
+               goto unlock;
+
+       if (mode & FALLOC_FL_PUNCH_HOLE) {
+               if (offset < size)
+                       ceph_zero_pagecache_range(inode, offset, length);
+               ret = ceph_zero_objects(inode, offset, length);
+       } else if (endoff > size) {
+               truncate_pagecache_range(inode, size, -1);
+               if (ceph_inode_set_size(inode, endoff))
+                       ceph_check_caps(ceph_inode(inode),
+                               CHECK_CAPS_AUTHONLY, NULL);
+       }
+
+       if (!ret) {
+               spin_lock(&ci->i_ceph_lock);
+               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
+               spin_unlock(&ci->i_ceph_lock);
+               if (dirty)
+                       __mark_inode_dirty(inode, dirty);
+       }
+
+       ceph_put_cap_refs(ci, got);
+unlock:
+       mutex_unlock(&inode->i_mutex);
+       return ret;
+}
+
 const struct file_operations ceph_file_fops = {
        .open = ceph_open,
        .release = ceph_release,
@@ -887,5 +1101,6 @@ const struct file_operations ceph_file_fops = {
        .splice_write = generic_file_splice_write,
        .unlocked_ioctl = ceph_ioctl,
        .compat_ioctl   = ceph_ioctl,
+       .fallocate      = ceph_fallocate,
 };
 
index f3a2abf28a77df362faf5c38dc471a64dcbfdffc..8549a48115f71b23e1f35ef444caf3eb32dbced3 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "cache.h"
 #include <linux/ceph/decode.h>
 
 /*
@@ -344,6 +345,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        for (i = 0; i < CEPH_FILE_MODE_NUM; i++)
                ci->i_nr_by_mode[i] = 0;
 
+       mutex_init(&ci->i_truncate_mutex);
        ci->i_truncate_seq = 0;
        ci->i_truncate_size = 0;
        ci->i_truncate_pending = 0;
@@ -377,6 +379,8 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
 
        INIT_WORK(&ci->i_vmtruncate_work, ceph_vmtruncate_work);
 
+       ceph_fscache_inode_init(ci);
+
        return &ci->vfs_inode;
 }
 
@@ -396,6 +400,8 @@ void ceph_destroy_inode(struct inode *inode)
 
        dout("destroy_inode %p ino %llx.%llx\n", inode, ceph_vinop(inode));
 
+       ceph_fscache_unregister_inode_cookie(ci);
+
        ceph_queue_caps_release(inode);
 
        /*
@@ -430,7 +436,6 @@ void ceph_destroy_inode(struct inode *inode)
        call_rcu(&inode->i_rcu, ceph_i_callback);
 }
 
-
 /*
  * Helpers to fill in size, ctime, mtime, and atime.  We have to be
  * careful because either the client or MDS may have more up to date
@@ -455,16 +460,20 @@ int ceph_fill_file_size(struct inode *inode, int issued,
                        dout("truncate_seq %u -> %u\n",
                             ci->i_truncate_seq, truncate_seq);
                        ci->i_truncate_seq = truncate_seq;
+
+                       /* the MDS should have revoked these caps */
+                       WARN_ON_ONCE(issued & (CEPH_CAP_FILE_EXCL |
+                                              CEPH_CAP_FILE_RD |
+                                              CEPH_CAP_FILE_WR |
+                                              CEPH_CAP_FILE_LAZYIO));
                        /*
                         * If we hold relevant caps, or in the case where we're
                         * not the only client referencing this file and we
                         * don't hold those caps, then we need to check whether
                         * the file is either opened or mmaped
                         */
-                       if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD|
-                                      CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER|
-                                      CEPH_CAP_FILE_EXCL|
-                                      CEPH_CAP_FILE_LAZYIO)) ||
+                       if ((issued & (CEPH_CAP_FILE_CACHE|
+                                      CEPH_CAP_FILE_BUFFER)) ||
                            mapping_mapped(inode->i_mapping) ||
                            __ceph_caps_file_wanted(ci)) {
                                ci->i_truncate_pending++;
@@ -478,6 +487,10 @@ int ceph_fill_file_size(struct inode *inode, int issued,
                     truncate_size);
                ci->i_truncate_size = truncate_size;
        }
+
+       if (queue_trunc)
+               ceph_fscache_invalidate(inode);
+
        return queue_trunc;
 }
 
@@ -1066,7 +1079,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                         * complete.
                         */
                        ceph_set_dentry_offset(req->r_old_dentry);
-                       dout("dn %p gets new offset %lld\n", req->r_old_dentry, 
+                       dout("dn %p gets new offset %lld\n", req->r_old_dentry,
                             ceph_dentry(req->r_old_dentry)->offset);
 
                        dn = req->r_old_dentry;  /* use old_dentry */
@@ -1419,18 +1432,20 @@ static void ceph_invalidate_work(struct work_struct *work)
        u32 orig_gen;
        int check = 0;
 
+       mutex_lock(&ci->i_truncate_mutex);
        spin_lock(&ci->i_ceph_lock);
        dout("invalidate_pages %p gen %d revoking %d\n", inode,
             ci->i_rdcache_gen, ci->i_rdcache_revoking);
        if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
                /* nevermind! */
                spin_unlock(&ci->i_ceph_lock);
+               mutex_unlock(&ci->i_truncate_mutex);
                goto out;
        }
        orig_gen = ci->i_rdcache_gen;
        spin_unlock(&ci->i_ceph_lock);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       truncate_inode_pages(inode->i_mapping, 0);
 
        spin_lock(&ci->i_ceph_lock);
        if (orig_gen == ci->i_rdcache_gen &&
@@ -1445,6 +1460,7 @@ static void ceph_invalidate_work(struct work_struct *work)
                     ci->i_rdcache_revoking);
        }
        spin_unlock(&ci->i_ceph_lock);
+       mutex_unlock(&ci->i_truncate_mutex);
 
        if (check)
                ceph_check_caps(ci, 0, NULL);
@@ -1465,9 +1481,7 @@ static void ceph_vmtruncate_work(struct work_struct *work)
        struct inode *inode = &ci->vfs_inode;
 
        dout("vmtruncate_work %p\n", inode);
-       mutex_lock(&inode->i_mutex);
        __ceph_do_pending_vmtruncate(inode);
-       mutex_unlock(&inode->i_mutex);
        iput(inode);
 }
 
@@ -1480,6 +1494,7 @@ void ceph_queue_vmtruncate(struct inode *inode)
        struct ceph_inode_info *ci = ceph_inode(inode);
 
        ihold(inode);
+
        if (queue_work(ceph_sb_to_client(inode->i_sb)->trunc_wq,
                       &ci->i_vmtruncate_work)) {
                dout("ceph_queue_vmtruncate %p\n", inode);
@@ -1500,11 +1515,13 @@ void __ceph_do_pending_vmtruncate(struct inode *inode)
        u64 to;
        int wrbuffer_refs, finish = 0;
 
+       mutex_lock(&ci->i_truncate_mutex);
 retry:
        spin_lock(&ci->i_ceph_lock);
        if (ci->i_truncate_pending == 0) {
                dout("__do_pending_vmtruncate %p none pending\n", inode);
                spin_unlock(&ci->i_ceph_lock);
+               mutex_unlock(&ci->i_truncate_mutex);
                return;
        }
 
@@ -1521,6 +1538,9 @@ retry:
                goto retry;
        }
 
+       /* there should be no reader or writer */
+       WARN_ON_ONCE(ci->i_rd_ref || ci->i_wr_ref);
+
        to = ci->i_truncate_size;
        wrbuffer_refs = ci->i_wrbuffer_ref;
        dout("__do_pending_vmtruncate %p (%d) to %lld\n", inode,
@@ -1538,13 +1558,14 @@ retry:
        if (!finish)
                goto retry;
 
+       mutex_unlock(&ci->i_truncate_mutex);
+
        if (wrbuffer_refs == 0)
                ceph_check_caps(ci, CHECK_CAPS_AUTHONLY, NULL);
 
        wake_up_all(&ci->i_cap_wq);
 }
 
-
 /*
  * symlinks
  */
@@ -1586,8 +1607,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EROFS;
 
-       __ceph_do_pending_vmtruncate(inode);
-
        err = inode_change_ok(inode, attr);
        if (err != 0)
                return err;
@@ -1768,7 +1787,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
             ceph_cap_string(dirtied), mask);
 
        ceph_mdsc_put_request(req);
-       __ceph_do_pending_vmtruncate(inode);
+       if (mask & CEPH_SETATTR_SIZE)
+               __ceph_do_pending_vmtruncate(inode);
        return err;
 out:
        spin_unlock(&ci->i_ceph_lock);
index e0b4ef31d3c870c9e73fecad303e9f9957542385..669622fd1ae3d52af418cc4c283a5f22513bca73 100644 (file)
@@ -196,8 +196,10 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        r = ceph_calc_file_object_mapping(&ci->i_layout, dl.file_offset, len,
                                          &dl.object_no, &dl.object_offset,
                                          &olen);
-       if (r < 0)
+       if (r < 0) {
+               up_read(&osdc->map_sem);
                return -EIO;
+       }
        dl.file_offset -= dl.object_offset;
        dl.object_size = ceph_file_layout_object_size(ci->i_layout);
        dl.block_size = ceph_file_layout_su(ci->i_layout);
@@ -209,8 +211,12 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
                 ceph_ino(inode), dl.object_no);
 
-       ceph_calc_ceph_pg(&pgid, dl.object_name, osdc->osdmap,
-               ceph_file_layout_pg_pool(ci->i_layout));
+       r = ceph_calc_ceph_pg(&pgid, dl.object_name, osdc->osdmap,
+                               ceph_file_layout_pg_pool(ci->i_layout));
+       if (r < 0) {
+               up_read(&osdc->map_sem);
+               return r;
+       }
 
        dl.osd = ceph_calc_pg_primary(osdc->osdmap, pgid);
        if (dl.osd >= 0) {
index 187bf214444da8c8fc9c6a8603b699a258f773f8..b7bda5d9611da031aaf6f104ece9fa6351993070 100644 (file)
@@ -414,6 +414,9 @@ static struct ceph_mds_session *register_session(struct ceph_mds_client *mdsc,
 {
        struct ceph_mds_session *s;
 
+       if (mds >= mdsc->mdsmap->m_max_mds)
+               return ERR_PTR(-EINVAL);
+
        s = kzalloc(sizeof(*s), GFP_NOFS);
        if (!s)
                return ERR_PTR(-ENOMEM);
@@ -1028,6 +1031,37 @@ 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);
+
+       spin_lock(&session->s_cap_lock);
+       if (session->s_nr_caps > 0) {
+               struct super_block *sb = session->s_mdsc->fsc->sb;
+               struct inode *inode;
+               struct ceph_cap *cap, *prev = NULL;
+               struct ceph_vino vino;
+               /*
+                * iterate_session_caps() skips inodes that are being
+                * deleted, we need to wait until deletions are complete.
+                * __wait_on_freeing_inode() is designed for the job,
+                * but it is not exported, so use lookup inode function
+                * to access it.
+                */
+               while (!list_empty(&session->s_caps)) {
+                       cap = list_entry(session->s_caps.next,
+                                        struct ceph_cap, session_caps);
+                       if (cap == prev)
+                               break;
+                       prev = cap;
+                       vino = cap->ci->i_vino;
+                       spin_unlock(&session->s_cap_lock);
+
+                       inode = ceph_find_inode(sb, vino);
+                       iput(inode);
+
+                       spin_lock(&session->s_cap_lock);
+               }
+       }
+       spin_unlock(&session->s_cap_lock);
+
        BUG_ON(session->s_nr_caps > 0);
        BUG_ON(!list_empty(&session->s_cap_flushing));
        cleanup_cap_releases(session);
index 6627b26a800ca0e74649ecf439076bb9c6a4b095..6a0951e4304441a241ca8fe550aba36cc097c271 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "super.h"
 #include "mds_client.h"
+#include "cache.h"
 
 #include <linux/ceph/ceph_features.h>
 #include <linux/ceph/decode.h>
@@ -142,6 +143,8 @@ enum {
        Opt_nodcache,
        Opt_ino32,
        Opt_noino32,
+       Opt_fscache,
+       Opt_nofscache
 };
 
 static match_table_t fsopt_tokens = {
@@ -167,6 +170,8 @@ static match_table_t fsopt_tokens = {
        {Opt_nodcache, "nodcache"},
        {Opt_ino32, "ino32"},
        {Opt_noino32, "noino32"},
+       {Opt_fscache, "fsc"},
+       {Opt_nofscache, "nofsc"},
        {-1, NULL}
 };
 
@@ -260,6 +265,12 @@ static int parse_fsopt_token(char *c, void *private)
        case Opt_noino32:
                fsopt->flags &= ~CEPH_MOUNT_OPT_INO32;
                break;
+       case Opt_fscache:
+               fsopt->flags |= CEPH_MOUNT_OPT_FSCACHE;
+               break;
+       case Opt_nofscache:
+               fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE;
+               break;
        default:
                BUG_ON(token);
        }
@@ -422,6 +433,10 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root)
                seq_puts(m, ",dcache");
        else
                seq_puts(m, ",nodcache");
+       if (fsopt->flags & CEPH_MOUNT_OPT_FSCACHE)
+               seq_puts(m, ",fsc");
+       else
+               seq_puts(m, ",nofsc");
 
        if (fsopt->wsize)
                seq_printf(m, ",wsize=%d", fsopt->wsize);
@@ -530,11 +545,18 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
        if (!fsc->wb_pagevec_pool)
                goto fail_trunc_wq;
 
+       /* setup fscache */
+       if ((fsopt->flags & CEPH_MOUNT_OPT_FSCACHE) &&
+           (ceph_fscache_register_fs(fsc) != 0))
+               goto fail_fscache;
+
        /* caps */
        fsc->min_caps = fsopt->max_readdir;
 
        return fsc;
 
+fail_fscache:
+       ceph_fscache_unregister_fs(fsc);
 fail_trunc_wq:
        destroy_workqueue(fsc->trunc_wq);
 fail_pg_inv_wq:
@@ -554,6 +576,8 @@ static void destroy_fs_client(struct ceph_fs_client *fsc)
 {
        dout("destroy_fs_client %p\n", fsc);
 
+       ceph_fscache_unregister_fs(fsc);
+
        destroy_workqueue(fsc->wb_wq);
        destroy_workqueue(fsc->pg_inv_wq);
        destroy_workqueue(fsc->trunc_wq);
@@ -588,6 +612,8 @@ static void ceph_inode_init_once(void *foo)
 
 static int __init init_caches(void)
 {
+       int error = -ENOMEM;
+
        ceph_inode_cachep = kmem_cache_create("ceph_inode_info",
                                      sizeof(struct ceph_inode_info),
                                      __alignof__(struct ceph_inode_info),
@@ -611,15 +637,17 @@ static int __init init_caches(void)
        if (ceph_file_cachep == NULL)
                goto bad_file;
 
-       return 0;
+       if ((error = ceph_fscache_register()))
+               goto bad_file;
 
+       return 0;
 bad_file:
        kmem_cache_destroy(ceph_dentry_cachep);
 bad_dentry:
        kmem_cache_destroy(ceph_cap_cachep);
 bad_cap:
        kmem_cache_destroy(ceph_inode_cachep);
-       return -ENOMEM;
+       return error;
 }
 
 static void destroy_caches(void)
@@ -629,10 +657,13 @@ static void destroy_caches(void)
         * destroy cache.
         */
        rcu_barrier();
+
        kmem_cache_destroy(ceph_inode_cachep);
        kmem_cache_destroy(ceph_cap_cachep);
        kmem_cache_destroy(ceph_dentry_cachep);
        kmem_cache_destroy(ceph_file_cachep);
+
+       ceph_fscache_unregister();
 }
 
 
index cbded572345e77a107e539aa4e433d6f6f7964c0..6014b0a3c405cb12dfb62fdac7887f83a4977b96 100644 (file)
 
 #include <linux/ceph/libceph.h>
 
+#ifdef CONFIG_CEPH_FSCACHE
+#include <linux/fscache.h>
+#endif
+
 /* f_type in struct statfs */
 #define CEPH_SUPER_MAGIC 0x00c36400
 
@@ -29,6 +33,7 @@
 #define CEPH_MOUNT_OPT_NOASYNCREADDIR  (1<<7) /* no dcache readdir */
 #define CEPH_MOUNT_OPT_INO32           (1<<8) /* 32 bit inos */
 #define CEPH_MOUNT_OPT_DCACHE          (1<<9) /* use dcache for readdir etc */
+#define CEPH_MOUNT_OPT_FSCACHE         (1<<10) /* use fscache */
 
 #define CEPH_MOUNT_OPT_DEFAULT    (CEPH_MOUNT_OPT_RBYTES)
 
@@ -90,6 +95,11 @@ struct ceph_fs_client {
        struct dentry *debugfs_bdi;
        struct dentry *debugfs_mdsc, *debugfs_mdsmap;
 #endif
+
+#ifdef CONFIG_CEPH_FSCACHE
+       struct fscache_cookie *fscache;
+       struct workqueue_struct *revalidate_wq;
+#endif
 };
 
 
@@ -288,6 +298,7 @@ struct ceph_inode_info {
 
        int i_nr_by_mode[CEPH_FILE_MODE_NUM];  /* open file counts */
 
+       struct mutex i_truncate_mutex;
        u32 i_truncate_seq;        /* last truncate to smaller size */
        u64 i_truncate_size;       /*  and the size we last truncated down to */
        int i_truncate_pending;    /*  still need to call vmtruncate */
@@ -319,6 +330,12 @@ struct ceph_inode_info {
 
        struct work_struct i_vmtruncate_work;
 
+#ifdef CONFIG_CEPH_FSCACHE
+       struct fscache_cookie *fscache;
+       u32 i_fscache_gen; /* sequence, for delayed fscache validate */
+       struct work_struct i_revalidate_work;
+#endif
+
        struct inode vfs_inode; /* at end */
 };
 
diff --git a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
deleted file mode 100644 (file)
index ea940b1..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-Original Author
-===============
-Steve French (sfrench@samba.org)
-
-The author wishes to express his appreciation and thanks to:
-Andrew Tridgell (Samba team) for his early suggestions about smb/cifs VFS
-improvements. Thanks to IBM for allowing me time and test resources to pursue
-this project, to Jim McDonough from IBM (and the Samba Team) for his help, to
-the IBM Linux JFS team for explaining many esoteric Linux filesystem features.
-Jeremy Allison of the Samba team has done invaluable work in adding the server
-side of the original CIFS Unix extensions and reviewing and implementing
-portions of the newer CIFS POSIX extensions into the Samba 3 file server. Thank
-Dave Boutcher of IBM Rochester (author of the OS/400 smb/cifs filesystem client)
-for proving years ago that very good smb/cifs clients could be done on Unix-like
-operating systems.  Volker Lendecke, Andrew Tridgell, Urban Widmark, John 
-Newbigin and others for their work on the Linux smbfs module.  Thanks to
-the other members of the Storage Network Industry Association CIFS Technical
-Workgroup for their work specifying this highly complex protocol and finally
-thanks to the Samba team for their technical advice and encouragement.
-
-Patch Contributors
-------------------
-Zwane Mwaikambo
-Andi Kleen
-Amrut Joshi
-Shobhit Dayal
-Sergey Vlasov
-Richard Hughes
-Yury Umanets
-Mark Hamzy (for some of the early cifs IPv6 work)
-Domen Puncer
-Jesper Juhl (in particular for lots of whitespace/formatting cleanup)
-Vince Negri and Dave Stahl (for finding an important caching bug)
-Adrian Bunk (kcalloc cleanups)
-Miklos Szeredi 
-Kazeon team for various fixes especially for 2.4 version.
-Asser Ferno (Change Notify support)
-Shaggy (Dave Kleikamp) for innumerable small fs suggestions and some good cleanup
-Gunter Kukkukk (testing and suggestions for support of old servers)
-Igor Mammedov (DFS support)
-Jeff Layton (many, many fixes, as well as great work on the cifs Kerberos code)
-
-Test case and Bug Report contributors
--------------------------------------
-Thanks to those in the community who have submitted detailed bug reports
-and debug of problems they have found:  Jochen Dolze, David Blaine,
-Rene Scharfe, Martin Josefsson, Alexander Wild, Anthony Liguori,
-Lars Muller, Urban Widmark, Massimiliano Ferrero, Howard Owen,
-Olaf Kirch, Kieron Briggs, Nick Millington and others. Also special
-mention to the Stanford Checker (SWAT) which pointed out many minor
-bugs in error paths.  Valuable suggestions also have come from Al Viro
-and Dave Miller.
-
-And thanks to the IBM LTC and Power test teams and SuSE testers for
-finding multiple bugs during excellent stress test runs.
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES
deleted file mode 100644 (file)
index bc0025c..0000000
+++ /dev/null
@@ -1,1065 +0,0 @@
-Version 1.62
-------------
-Add sockopt=TCP_NODELAY mount option. EA (xattr) routines hardened
-to more strictly handle corrupt frames.
-
-Version 1.61
-------------
-Fix append problem to Samba servers (files opened with O_APPEND could
-have duplicated data). Fix oops in cifs_lookup. Workaround problem
-mounting to OS/400 Netserve. Fix oops in cifs_get_tcp_session.
-Disable use of server inode numbers when server only
-partially supports them (e.g. for one server querying inode numbers on
-FindFirst fails but QPathInfo queries works). Fix oops with dfs in 
-cifs_put_smb_ses. Fix mmap to work on directio mounts (needed
-for OpenOffice when on forcedirectio mount e.g.)
-
-Version 1.60
--------------
-Fix memory leak in reconnect.  Fix oops in DFS mount error path.
-Set s_maxbytes to smaller (the max that vfs can handle) so that
-sendfile will now work over cifs mounts again.  Add noforcegid
-and noforceuid mount parameters. Fix small mem leak when using
-ntlmv2. Fix 2nd mount to same server but with different port to
-be allowed (rather than reusing the 1st port) - only when the
-user explicitly overrides the port on the 2nd mount.
-
-Version 1.59
-------------
-Client uses server inode numbers (which are persistent) rather than
-client generated ones by default (mount option "serverino" turned
-on by default if server supports it).  Add forceuid and forcegid
-mount options (so that when negotiating unix extensions specifying
-which uid mounted does not immediately force the server's reported
-uids to be overridden).  Add support for scope mount parm. Improve
-hard link detection to use same inode for both.  Do not set
-read-only dos attribute on directories (for chmod) since Windows
-explorer special cases this attribute bit for directories for
-a different purpose.
-
-Version 1.58
-------------
-Guard against buffer overruns in various UCS-2 to UTF-8 string conversions
-when the UTF-8 string is composed of unusually long (more than 4 byte) converted
-characters. Add support for mounting root of a share which redirects immediately
-to DFS target. Convert string conversion functions from Unicode to more
-accurately mark string length before allocating memory (which may help the
-rare cases where a UTF-8 string is much larger than the UCS2 string that
-we converted from).  Fix endianness of the vcnum field used during
-session setup to distinguish multiple mounts to same server from different
-userids. Raw NTLMSSP fixed (it requires /proc/fs/cifs/experimental
-flag to be set to 2, and mount must enable krb5 to turn on extended security).
-Performance of file create to Samba improved (posix create on lookup
-removes 1 of 2 network requests sent on file create)
-Version 1.57
-------------
-Improve support for multiple security contexts to the same server. We
-used to use the same "vcnumber" for all connections which could cause
-the server to treat subsequent connections, especially those that
-are authenticated as guest, as reconnections, invalidating the earlier
-user's smb session.  This fix allows cifs to mount multiple times to the
-same server with different userids without risking invalidating earlier
-established security contexts.  fsync now sends SMB Flush operation
-to better ensure that we wait for server to write all of the data to
-server disk (not just write it over the network).  Add new mount
-parameter to allow user to disable sending the (slow) SMB flush on
-fsync if desired (fsync still flushes all cached write data to the server).
-Posix file open support added (turned off after one attempt if server
-fails to support it properly, as with Samba server versions prior to 3.3.2)
-Fix "redzone overwritten" bug in cifs_put_tcon (CIFSTcon may allocate too
-little memory for the "nativeFileSystem" field returned by the server
-during mount).  Endian convert inode numbers if necessary (makes it easier
-to compare inode numbers on network files from big endian systems). 
-
-Version 1.56
-------------
-Add "forcemandatorylock" mount option to allow user to use mandatory
-rather than posix (advisory) byte range locks, even though server would
-support posix byte range locks.  Fix query of root inode when prefixpath
-specified and user does not have access to query information about the
-top of the share.  Fix problem in 2.6.28 resolving DFS paths to
-Samba servers (worked to Windows).  Fix rmdir so that pending search
-(readdir) requests do not get invalid results which include the now
-removed directory.  Fix oops in cifs_dfs_ref.c when prefixpath is not reachable
-when using DFS.  Add better file create support to servers which support
-the CIFS POSIX protocol extensions (this adds support for new flags
-on create, and improves semantics for write of locked ranges).
-
-Version 1.55
-------------
-Various fixes to make delete of open files behavior more predictable
-(when delete of an open file fails we mark the file as "delete-on-close"
-in a way that more servers accept, but only if we can first rename the
-file to a temporary name).  Add experimental support for more safely
-handling fcntl(F_SETLEASE).  Convert cifs to using blocking tcp
-sends, and also let tcp autotune the socket send and receive buffers.
-This reduces the number of EAGAIN errors returned by TCP/IP in
-high stress workloads (and the number of retries on socket writes
-when sending large SMBWriteX requests).  Fix case in which a portion of
-data can in some cases not get written to the file on the server before the
-file is closed.  Fix DFS parsing to properly handle path consumed field,
-and to handle certain codepage conversions better.  Fix mount and
-umount race that can cause oops in mount or umount or reconnect.
-
-Version 1.54
-------------
-Fix premature write failure on congested networks (we would give up
-on EAGAIN from the socket too quickly on large writes).
-Cifs_mkdir and cifs_create now respect the setgid bit on parent dir.
-Fix endian problems in acl (mode from/to cifs acl) on bigendian
-architectures.  Fix problems with preserving timestamps on copying open
-files (e.g. "cp -a") to Windows servers.  For mkdir and create honor setgid bit
-on parent directory when server supports Unix Extensions but not POSIX
-create. Update cifs.upcall version to handle new Kerberos sec flags
-(this requires update of cifs.upcall program from Samba).  Fix memory leak
-on dns_upcall (resolving DFS referralls).  Fix plain text password
-authentication (requires setting SecurityFlags to 0x30030 to enable
-lanman and plain text though).  Fix writes to be at correct offset when
-file is open with O_APPEND and file is on a directio (forcediretio) mount.
-Fix bug in rewinding readdir directory searches.  Add nodfs mount option.
-
-Version 1.53
-------------
-DFS support added (Microsoft Distributed File System client support needed
-for referrals which enable a hierarchical name space among servers).
-Disable temporary caching of mode bits to servers which do not support
-storing of mode (e.g. Windows servers, when client mounts without cifsacl
-mount option) and add new "dynperm" mount option to enable temporary caching
-of mode (enable old behavior).  Fix hang on mount caused when server crashes
-tcp session during negotiate protocol.
-
-Version 1.52
-------------
-Fix oops on second mount to server when null auth is used.
-Enable experimental Kerberos support.  Return writebehind errors on flush
-and sync so that events like out of disk space get reported properly on
-cached files. Fix setxattr failure to certain Samba versions. Fix mount
-of second share to disconnected server session (autoreconnect on this).
-Add ability to modify cifs acls for handling chmod (when mounted with
-cifsacl flag). Fix prefixpath path separator so we can handle mounts
-with prefixpaths longer than one directory (one path component) when
-mounted to Windows servers.  Fix slow file open when cifsacl
-enabled. Fix memory leak in FindNext when the SMB call returns -EBADF.
-
-
-Version 1.51
-------------
-Fix memory leak in statfs when mounted to very old servers (e.g.
-Windows 9x).  Add new feature "POSIX open" which allows servers
-which support the current POSIX Extensions to provide better semantics
-(e.g. delete for open files opened with posix open).  Take into
-account umask on posix mkdir not just older style mkdir.  Add
-ability to mount to IPC$ share (which allows CIFS named pipes to be
-opened, read and written as if they were files).  When 1st tree
-connect fails (e.g. due to signing negotiation failure) fix
-leak that causes cifsd not to stop and rmmod to fail to cleanup
-cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on
-bigendian architectures. Fix possible memory corruption when
-EAGAIN returned on kern_recvmsg. Return better error if server
-requires packet signing but client has disabled it. When mounted
-with cifsacl mount option - mode bits are approximated based
-on the contents of the ACL of the file or directory. When cifs
-mount helper is missing convert make sure that UNC name 
-has backslash (not forward slash) between ip address of server
-and the share name.
-
-Version 1.50
-------------
-Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is
-done with "serverino" mount option).  Add support for POSIX Unlink
-(helps with certain sharing violation cases when server such as
-Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix"
-mount option to allow disabling the CIFS Unix Extensions for just
-that mount. Fix hang on spinlock in find_writable_file (race when
-reopening file after session crash).  Byte range unlock request to
-windows server could unlock more bytes (on server copy of file)
-than intended if start of unlock request is well before start of
-a previous byte range lock that we issued.
-
-Version 1.49
-------------
-IPv6 support.  Enable ipv6 addresses to be passed on mount (put the ipv6
-address after the "ip=" mount option, at least until mount.cifs is fixed to
-handle DNS host to ipv6 name translation).  Accept override of uid or gid
-on mount even when Unix Extensions are negotiated (it used to be ignored
-when Unix Extensions were ignored).  This allows users to override the
-default uid and gid for files when they are certain that the uids or
-gids on the server do not match those of the client.  Make "sec=none"
-mount override username (so that null user connection is attempted)
-to match what documentation said. Support for very large reads, over 127K,
-available to some newer servers (such as Samba 3.0.26 and later but
-note that it also requires setting CIFSMaxBufSize at module install
-time to a larger value which may hurt performance in some cases).
-Make sign option force signing (or fail if server does not support it).
-
-Version 1.48
-------------
-Fix mtime bouncing around from local idea of last write times to remote time.
-Fix hang (in i_size_read) when simultaneous size update of same remote file
-on smp system corrupts sequence number. Do not reread unnecessarily partial page
-(which we are about to overwrite anyway) when writing out file opened rw.
-When DOS attribute of file on non-Unix server's file changes on the server side
-from read-only back to read-write, reflect this change in default file mode
-(we had been leaving a file's mode read-only until the inode were reloaded).
-Allow setting of attribute back to ATTR_NORMAL (removing readonly dos attribute
-when archive dos attribute not set and we are changing mode back to writeable
-on server which does not support the Unix Extensions).  Remove read only dos
-attribute on chmod when adding any write permission (ie on any of
-user/group/other (not all of user/group/other ie  0222) when
-mounted to windows.  Add support for POSIX MkDir (slight performance
-enhancement and eliminates the network race between the mkdir and set 
-path info of the mode).
-
-
-Version 1.47
-------------
-Fix oops in list_del during mount caused by unaligned string.
-Fix file corruption which could occur on some large file
-copies caused by writepages page i/o completion bug.
-Seek to SEEK_END forces check for update of file size for non-cached
-files. Allow file size to be updated on remote extend of locally open,
-non-cached file.  Fix reconnect to newer Samba servers (or other servers
-which support the CIFS Unix/POSIX extensions) so that we again tell the
-server the Unix/POSIX cifs capabilities which we support (SetFSInfo).
-Add experimental support for new POSIX Open/Mkdir (which returns
-stat information on the open, and allows setting the mode).
-
-Version 1.46
-------------
-Support deep tree mounts.  Better support OS/2, Win9x (DOS) time stamps.
-Allow null user to be specified on mount ("username="). Do not return
-EINVAL on readdir when filldir fails due to overwritten blocksize
-(fixes FC problem).  Return error in rename 2nd attempt retry (ie report
-if rename by handle also fails, after rename by path fails, we were
-not reporting whether the retry worked or not). Fix NTLMv2 to
-work to Windows servers (mount with option "sec=ntlmv2").
-
-Version 1.45
-------------
-Do not time out lockw calls when using posix extensions. Do not
-time out requests if server still responding reasonably fast
-on requests on other threads.  Improve POSIX locking emulation,
-(lock cancel now works, and unlock of merged range works even
-to Windows servers now).  Fix oops on mount to lanman servers
-(win9x, os/2 etc.) when null password.  Do not send listxattr
-(SMB to query all EAs) if nouser_xattr specified.  Fix SE Linux
-problem (instantiate inodes/dentries in right order for readdir).
-
-Version 1.44
-------------
-Rewritten sessionsetup support, including support for legacy SMB
-session setup needed for OS/2 and older servers such as Windows 95 and 98.
-Fix oops on ls to OS/2 servers.  Add support for level 1 FindFirst
-so we can do search (ls etc.) to OS/2.  Do not send NTCreateX
-or recent levels of FindFirst unless server says it supports NT SMBs
-(instead use legacy equivalents from LANMAN dialect). Fix to allow
-NTLMv2 authentication support (now can use stronger password hashing
-on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004).
-Allow override of global cifs security flags on mount via "sec=" option(s).
-
-Version 1.43
-------------
-POSIX locking to servers which support CIFS POSIX Extensions
-(disabled by default controlled by proc/fs/cifs/Experimental).
-Handle conversion of long share names (especially Asian languages)
-to Unicode during mount. Fix memory leak in sess struct on reconnect.
-Fix rare oops after acpi suspend.  Fix O_TRUNC opens to overwrite on
-cifs open which helps rare case when setpathinfo fails or server does
-not support it. 
-
-Version 1.42
-------------
-Fix slow oplock break when mounted to different servers at the same time and
-the tids match and we try to find matching fid on wrong server. Fix read
-looping when signing required by server (2.6.16 kernel only). Fix readdir
-vs. rename race which could cause each to hang. Return . and .. even
-if server does not.  Allow searches to skip first three entries and
-begin at any location. Fix oops in find_writeable_file.
-
-Version 1.41
-------------
-Fix NTLMv2 security (can be enabled in /proc/fs/cifs) so customers can
-configure stronger authentication.  Fix sfu symlinks so they can
-be followed (not just recognized).  Fix wraparound of bcc on
-read responses when buffer size over 64K and also fix wrap of
-max smb buffer size when CIFSMaxBufSize over 64K.  Fix oops in
-cifs_user_read and cifs_readpages (when EAGAIN on send of smb
-on socket is returned over and over).  Add POSIX (advisory) byte range
-locking support (requires server with newest CIFS UNIX Extensions
-to the protocol implemented). Slow down negprot slightly in port 139
-RFC1001 case to give session_init time on buggy servers.
-
-Version 1.40
-------------
-Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance
-of readpages by eliminating one extra memcpy. Allow update of file size
-from remote server even if file is open for write as long as mount is
-directio.  Recognize share mode security and send NTLM encrypted password
-on tree connect if share mode negotiated.
-
-Version 1.39
-------------
-Defer close of a file handle slightly if pending writes depend on that handle
-(this reduces the EBADF bad file handle errors that can be logged under heavy
-stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 
-Fix SFU style symlinks and mknod needed for servers which do not support the
-CIFS Unix Extensions.  Fix setfacl/getfacl on bigendian. Timeout negative
-dentries so files that the client sees as deleted but that later get created
-on the server will be recognized.  Add client side permission check on setattr.
-Timeout stuck requests better (where server has never responded or sent corrupt
-responses)
-
-Version 1.38
-------------
-Fix tcp socket retransmission timeouts (e.g. on ENOSPACE from the socket)
-to be smaller at first (but increasing) so large write performance performance
-over GigE is better.  Do not hang thread on illegal byte range lock response
-from Windows (Windows can send an RFC1001 size which does not match smb size) by
-allowing an SMBs TCP length to be up to a few bytes longer than it should be.
-wsize and rsize can now be larger than negotiated buffer size if server
-supports large readx/writex, even when directio mount flag not specified.
-Write size will in many cases now be 16K instead of 4K which greatly helps
-file copy performance on lightly loaded networks.  Fix oops in dnotify
-when experimental config flag enabled. Make cifsFYI more granular.
-
-Version 1.37
-------------
-Fix readdir caching when unlink removes file in current search buffer,
-and this is followed by a rewind search to just before the deleted entry.
-Do not attempt to set ctime unless atime and/or mtime change requested
-(most servers throw it away anyway). Fix length check of received smbs
-to be more accurate. Fix big endian problem with mapchars mount option,
-and with a field returned by statfs.
-
-Version 1.36
-------------
-Add support for mounting to older pre-CIFS servers such as Windows9x and ME.
-For these older servers, add option for passing netbios name of server in
-on mount (servernetbiosname).  Add suspend support for power management, to
-avoid cifsd thread preventing software suspend from working.
-Add mount option for disabling the default behavior of sending byte range lock
-requests to the server (necessary for certain applications which break with
-mandatory lock behavior such as Evolution), and also mount option for
-requesting case insensitive matching for path based requests (requesting
-case sensitive is the default).
-
-Version 1.35
-------------
-Add writepage performance improvements.  Fix path name conversions
-for long filenames on mounts which were done with "mapchars" mount option
-specified.  Ensure multiplex ids do not collide.  Fix case in which 
-rmmod can oops if done soon after last unmount.  Fix truncated
-search (readdir) output when resume filename was a long filename.
-Fix filename conversion when mapchars mount option was specified and
-filename was a long filename.
-
-Version 1.34
-------------
-Fix error mapping of the TOO_MANY_LINKS (hardlinks) case.
-Do not oops if root user kills cifs oplock kernel thread or
-kills the cifsd thread (NB: killing the cifs kernel threads is not
-recommended, unmount and rmmod cifs will kill them when they are
-no longer needed).  Fix readdir to ASCII servers (ie older servers
-which do not support Unicode) and also require asterisk.
-Fix out of memory case in which data could be written one page
-off in the page cache.
-
-Version 1.33
-------------
-Fix caching problem, in which readdir of directory containing a file
-which was cached could cause the file's time stamp to be updated
-without invalidating the readahead data (so we could get stale
-file data on the client for that file even as the server copy changed).
-Cleanup response processing so cifsd can not loop when abnormally
-terminated.
-
-
-Version 1.32
-------------
-Fix oops in ls when Transact2 FindFirst (or FindNext) returns more than one
-transact response for an SMB request and search entry split across two frames.
-Add support for lsattr (getting ext2/ext3/reiserfs attr flags from the server)
-as new protocol extensions. Do not send Get/Set calls for POSIX ACLs
-unless server explicitly claims to support them in CIFS Unix extensions
-POSIX ACL capability bit. Fix packet signing when multiuser mounting with
-different users from the same client to the same server. Fix oops in
-cifs_close. Add mount option for remapping reserved characters in
-filenames (also allow recognizing files with created by SFU which have any
-of these seven reserved characters, except backslash, to be recognized).
-Fix invalid transact2 message (we were sometimes trying to interpret
-oplock breaks as SMB responses). Add ioctl for checking that the
-current uid matches the uid of the mounter (needed by umount.cifs).
-Reduce the number of large buffer allocations in cifs response processing
-(significantly reduces memory pressure under heavy stress with multiple
-processes accessing the same server at the same time).
-
-Version 1.31
-------------
-Fix updates of DOS attributes and time fields so that files on NT4 servers
-do not get marked delete on close. Display sizes of cifs buffer pools in
-cifs stats. Fix oops in unmount when cifsd thread being killed by 
-shutdown. Add generic readv/writev and aio support. Report inode numbers 
-consistently in readdir and lookup (when serverino mount option is
-specified use the inode number that the server reports - for both lookup
-and readdir, otherwise by default the locally generated inode number is used
-for inodes created in either path since servers are not always able to 
-provide unique inode numbers when exporting multiple volumes from under one
-sharename).
-
-Version 1.30
-------------
-Allow new nouser_xattr mount parm to disable xattr support for user namespace.
-Do not flag user_xattr mount parm in dmesg.  Retry failures setting file time  
-(mostly affects NT4 servers) by retry with handle based network operation. 
-Add new POSIX Query FS Info for returning statfs info more accurately.
-Handle passwords with multiple commas in them.
-
-Version 1.29
-------------
-Fix default mode in sysfs of cifs module parms.  Remove old readdir routine.
-Fix capabilities flags for large readx so as to allow reads larger than 64K.
-
-Version 1.28
-------------
-Add module init parm for large SMB buffer size (to allow it to be changed
-from its default of 16K) which is especially useful for large file copy
-when mounting with the directio mount option. Fix oops after 
-returning from mount when experimental ExtendedSecurity enabled and
-SpnegoNegotiated returning invalid error. Fix case to retry better when 
-peek returns from 1 to 3 bytes on socket which should have more data.
-Fixed path based calls (such as cifs lookup) to handle path names
-longer than 530 (now can handle PATH_MAX). Fix pass through authentication
-from Samba server to DC (Samba required dummy LM password).
-
-Version 1.27
-------------
-Turn off DNOTIFY (directory change notification support) by default
-(unless built with the experimental flag) to fix hang with KDE
-file browser. Fix DNOTIFY flag mappings.  Fix hang (in wait_event
-waiting on an SMB response) in SendReceive when session dies but
-reconnects quickly from another task.  Add module init  parms for
-minimum number of large and small network buffers in the buffer pools,
-and for the maximum number of simultaneous requests.
-
-Version 1.26
-------------
-Add setfacl support to allow setting of ACLs remotely to Samba 3.10 and later
-and other POSIX CIFS compliant servers.  Fix error mapping for getfacl 
-to EOPNOTSUPP when server does not support posix acls on the wire. Fix 
-improperly zeroed buffer in CIFS Unix extensions set times call. 
-
-Version 1.25
-------------
-Fix internationalization problem in cifs readdir with filenames that map to 
-longer UTF-8 strings than the string on the wire was in Unicode.  Add workaround
-for readdir to netapp servers. Fix search rewind (seek into readdir to return 
-non-consecutive entries).  Do not do readdir when server negotiates 
-buffer size to small to fit filename. Add support for reading POSIX ACLs from
-the server (add also acl and noacl mount options).
-
-Version 1.24
-------------
-Optionally allow using server side inode numbers, rather than client generated
-ones by specifying mount option "serverino" - this is required for some apps
-to work which double check hardlinked files and have persistent inode numbers.
-
-Version 1.23
-------------
-Multiple bigendian fixes. On little endian systems (for reconnect after
-network failure) fix tcp session reconnect code so we do not try first
-to reconnect on reverse of port 445. Treat reparse points (NTFS junctions)
-as directories rather than symlinks because we can do follow link on them.
-
-Version 1.22
-------------
-Add config option to enable XATTR (extended attribute) support, mapping
-xattr names in the "user." namespace space to SMB/CIFS EAs. Lots of
-minor fixes pointed out by the Stanford SWAT checker (mostly missing
-or out of order NULL pointer checks in little used error paths).
-
-Version 1.21
-------------
-Add new mount parm to control whether mode check (generic_permission) is done
-on the client.  If Unix extensions are enabled and the uids on the client
-and server do not match, client permission checks are meaningless on
-server uids that do not exist on the client (this does not affect the
-normal ACL check which occurs on the server).  Fix default uid
-on mknod to match create and mkdir. Add optional mount parm to allow
-override of the default uid behavior (in which the server sets the uid
-and gid of newly created files). Normally for network filesystem mounts
-user want the server to set the uid/gid on newly created files (rather than 
-using uid of the client processes you would in a local filesystem).
-
-Version 1.20
-------------
-Make transaction counts more consistent. Merge /proc/fs/cifs/SimultaneousOps
-info into /proc/fs/cifs/DebugData.  Fix oops in rare oops in readdir 
-(in build_wildcard_path_from_dentry).  Fix mknod to pass type field
-(block/char/fifo) properly.  Remove spurious mount warning log entry when
-credentials passed as mount argument. Set major/minor device number in
-inode for block and char devices when unix extensions enabled.
-
-Version 1.19
-------------
-Fix /proc/fs/cifs/Stats and DebugData display to handle larger
-amounts of return data. Properly limit requests to MAX_REQ (50
-is the usual maximum active multiplex SMB/CIFS requests per server).
-Do not kill cifsd (and thus hurt the other SMB session) when more than one
-session to the same server (but with different userids) exists and one
-of the two user's smb sessions is being removed while leaving the other.
-Do not loop reconnecting in cifsd demultiplex thread when admin
-kills the thread without going through unmount.
-
-Version 1.18
-------------
-Do not rename hardlinked files (since that should be a noop). Flush
-cached write behind data when reopening a file after session abend,
-except when already in write. Grab per socket sem during reconnect 
-to avoid oops in sendmsg if overlapping with reconnect. Do not
-reset cached inode file size on readdir for files open for write on 
-client.
-
-
-Version 1.17
-------------
-Update number of blocks in file so du command is happier (in Linux a fake
-blocksize of 512 is required for calculating number of blocks in inode).
-Fix prepare write of partial pages to read in data from server if possible.
-Fix race on tcpStatus field between unmount and reconnection code, causing
-cifsd process sometimes to hang around forever. Improve out of memory
-checks in cifs_filldir
-
-Version 1.16
-------------
-Fix incorrect file size in file handle based setattr on big endian hardware.
-Fix oops in build_path_from_dentry when out of memory.  Add checks for invalid
-and closing file structs in writepage/partialpagewrite.  Add statistics
-for each mounted share (new menuconfig option). Fix endianness problem in
-volume information displayed in /proc/fs/cifs/DebugData (only affects
-affects big endian architectures). Prevent renames while constructing
-path names for open, mkdir and rmdir.
-
-Version 1.15
-------------
-Change to mempools for alloc smb request buffers and multiplex structs
-to better handle low memory problems (and potential deadlocks).
-
-Version 1.14
-------------
-Fix incomplete listings of large directories on Samba servers when Unix
-extensions enabled.  Fix oops when smb_buffer can not be allocated. Fix
-rename deadlock when writing out dirty pages at same time.
-
-Version 1.13
-------------
-Fix open of files in which O_CREATE can cause the mode to change in
-some cases. Fix case in which retry of write overlaps file close.
-Fix PPC64 build error.  Reduce excessive stack usage in smb password
-hashing. Fix overwrite of Linux user's view of file mode to Windows servers.
-
-Version 1.12
-------------
-Fixes for large file copy, signal handling, socket retry, buffer
-allocation and low memory situations.
-
-Version 1.11
-------------
-Better port 139 support to Windows servers (RFC1001/RFC1002 Session_Initialize)
-also now allowing support for specifying client netbiosname.  NT4 support added.
-
-Version 1.10
-------------
-Fix reconnection (and certain failed mounts) to properly wake up the
-blocked users thread so it does not seem hung (in some cases was blocked
-until the cifs receive timeout expired). Fix spurious error logging
-to kernel log when application with open network files killed. 
-
-Version 1.09
-------------
-Fix /proc/fs module unload warning message (that could be logged
-to the kernel log). Fix intermittent failure in connectathon
-test7 (hardlink count not immediately refreshed in case in which
-inode metadata can be incorrectly kept cached when time near zero)
-
-Version 1.08
-------------
-Allow file_mode and dir_mode (specified at mount time) to be enforced
-locally (the server already enforced its own ACLs too) for servers
-that do not report the correct mode (do not support the 
-CIFS Unix Extensions).
-
-Version 1.07
-------------
-Fix some small memory leaks in some unmount error paths. Fix major leak
-of cache pages in readpages causing multiple read oriented stress
-testcases (including fsx, and even large file copy) to fail over time. 
-
-Version 1.06
-------------
-Send NTCreateX with ATTR_POSIX if Linux/Unix extensions negotiated with server.
-This allows files that differ only in case and improves performance of file
-creation and file open to such servers.  Fix semaphore conflict which causes 
-slow delete of open file to Samba (which unfortunately can cause an oplock
-break to self while vfs_unlink held i_sem) which can hang for 20 seconds.
-
-Version 1.05
-------------
-fixes to cifs_readpages for fsx test case
-
-Version 1.04
-------------
-Fix caching data integrity bug when extending file size especially when no
-oplock on file.  Fix spurious logging of valid already parsed mount options
-that are parsed outside of the cifs vfs such as nosuid.
-
-
-Version 1.03
-------------
-Connect to server when port number override not specified, and tcp port
-unitialized.  Reset search to restart at correct file when kernel routine
-filldir returns error during large directory searches (readdir). 
-
-Version 1.02
-------------
-Fix caching problem when files opened by multiple clients in which 
-page cache could contain stale data, and write through did
-not occur often enough while file was still open when read ahead
-(read oplock) not allowed.  Treat "sep=" when first mount option
-as an override of comma as the default separator between mount
-options. 
-
-Version 1.01
-------------
-Allow passwords longer than 16 bytes. Allow null password string.
-
-Version 1.00
-------------
-Gracefully clean up failed mounts when attempting to mount to servers such as
-Windows 98 that terminate tcp sessions during protocol negotiation.  Handle
-embedded commas in mount parsing of passwords.
-
-Version 0.99
-------------
-Invalidate local inode cached pages on oplock break and when last file
-instance is closed so that the client does not continue using stale local
-copy rather than later modified server copy of file.  Do not reconnect
-when server drops the tcp session prematurely before negotiate
-protocol response.  Fix oops in reopen_file when dentry freed.  Allow
-the support for CIFS Unix Extensions to be disabled via proc interface.
-
-Version 0.98
-------------
-Fix hang in commit_write during reconnection of open files under heavy load.
-Fix unload_nls oops in a mount failure path. Serialize writes to same socket
-which also fixes any possible races when cifs signatures are enabled in SMBs
-being sent out of signature sequence number order.    
-
-Version 0.97
-------------
-Fix byte range locking bug (endian problem) causing bad offset and
-length.
-
-Version 0.96
-------------
-Fix oops (in send_sig) caused by CIFS unmount code trying to
-wake up the demultiplex thread after it had exited. Do not log
-error on harmless oplock release of closed handle.
-
-Version 0.95
-------------
-Fix unsafe global variable usage and password hash failure on gcc 3.3.1
-Fix problem reconnecting secondary mounts to same server after session 
-failure.  Fix invalid dentry - race in mkdir when directory gets created
-by another client between the lookup and mkdir.
-Version 0.94
-------------
-Fix to list processing in reopen_files. Fix reconnection when server hung
-but tcpip session still alive.  Set proper timeout on socket read.
-
-Version 0.93
-------------
-Add missing mount options including iocharset.  SMP fixes in write and open. 
-Fix errors in reconnecting after TCP session failure.  Fix module unloading
-of default nls codepage
-
-Version 0.92
-------------
-Active smb transactions should never go negative (fix double FreeXid). Fix
-list processing in file routines. Check return code on kmalloc in open.
-Fix spinlock usage for SMP.
-
-Version 0.91
-------------
-Fix oops in reopen_files when invalid dentry. drop dentry on server rename 
-and on revalidate errors. Fix cases where pid is now tgid.  Fix return code
-on create hard link when server does not support them. 
-
-Version 0.90
-------------
-Fix scheduling while atomic error in getting inode info on newly created file. 
-Fix truncate of existing files opened with O_CREAT but not O_TRUNC set.
-
-Version 0.89
-------------
-Fix oops on write to dead tcp session. Remove error log write for case when file open
-O_CREAT but not O_EXCL
-
-Version 0.88
-------------
-Fix non-POSIX behavior on rename of open file and delete of open file by taking 
-advantage of trans2 SetFileInfo rename facility if available on target server.
-Retry on ENOSPC and EAGAIN socket errors.
-
-Version 0.87
-------------
-Fix oops on big endian readdir.  Set blksize to be even power of two (2**blkbits) to fix
-allocation size miscalculation. After oplock token lost do not read through
-cache. 
-
-Version 0.86
-------------
-Fix oops on empty file readahead.  Fix for file size handling for locally cached files.
-
-Version 0.85
-------------
-Fix oops in mkdir when server fails to return inode info. Fix oops in reopen_files
-during auto reconnection to server after server recovered from failure.
-
-Version 0.84
-------------
-Finish support for Linux 2.5 open/create changes, which removes the
-redundant NTCreate/QPathInfo/close that was sent during file create.
-Enable oplock by default. Enable packet signing by default (needed to 
-access many recent Windows servers)
-
-Version 0.83
-------------
-Fix oops when mounting to long server names caused by inverted parms to kmalloc.
-Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled
-we will choose a cifs user session (smb uid) that better matches the local
-uid if a) the mount uid does not match the current uid and b) we have another
-session to the same server (ip address) for a different mount which
-matches the current local uid.
-
-Version 0.82
-------------
-Add support for mknod of block or character devices.  Fix oplock
-code (distributed caching) to properly send response to oplock
-break from server.
-
-Version 0.81
-------------
-Finish up CIFS packet digital signing for the default
-NTLM security case. This should help Windows 2003
-network interoperability since it is common for
-packet signing to be required now. Fix statfs (stat -f)
-which recently started returning errors due to 
-invalid value (-1 instead of 0) being set in the
-struct kstatfs f_ffiles field.
-
-Version 0.80
------------
-Fix oops on stopping oplock thread when removing cifs when
-built as module.
-
-Version 0.79
-------------
-Fix mount options for ro (readonly), uid, gid and file and directory mode. 
-
-Version 0.78
-------------
-Fix errors displayed on failed mounts to be more understandable.
-Fixed various incorrect or misleading smb to posix error code mappings.
-
-Version 0.77
-------------
-Fix display of NTFS DFS junctions to display as symlinks.
-They are the network equivalent.  Fix oops in 
-cifs_partialpagewrite caused by missing spinlock protection
-of openfile linked list.  Allow writebehind caching errors to 
-be returned to the application at file close.
-
-Version 0.76
-------------
-Clean up options displayed in /proc/mounts by show_options to
-be more consistent with other filesystems.
-
-Version 0.75
-------------
-Fix delete of readonly file to Windows servers.  Reflect
-presence or absence of read only dos attribute in mode
-bits for servers that do not support CIFS Unix extensions.
-Fix shortened results on readdir of large directories to
-servers supporting CIFS Unix extensions (caused by
-incorrect resume key).
-
-Version 0.74
-------------
-Fix truncate bug (set file size) that could cause hangs e.g. running fsx
-
-Version 0.73
-------------
-unload nls if mount fails.
-
-Version 0.72
-------------
-Add resume key support to search (readdir) code to workaround
-Windows bug.  Add /proc/fs/cifs/LookupCacheEnable which
-allows disabling caching of attribute information for
-lookups.
-
-Version 0.71
-------------
-Add more oplock handling (distributed caching code).  Remove
-dead code.  Remove excessive stack space utilization from
-symlink routines.
-
-Version 0.70
-------------
-Fix oops in get dfs referral (triggered when null path sent in to
-mount).  Add support for overriding rsize at mount time.
-
-Version 0.69
-------------
-Fix buffer overrun in readdir which caused intermittent kernel oopses.
-Fix writepage code to release kmap on write data.  Allow "-ip=" new 
-mount option to be passed in on parameter distinct from the first part
-(server name portion of) the UNC name.  Allow override of the
-tcp port of the target server via new mount option "-port="  
-
-Version 0.68
-------------
-Fix search handle leak on rewind.  Fix setuid and gid so that they are 
-reflected in the local inode immediately.  Cleanup of whitespace
-to make 2.4 and 2.5 versions more consistent.
-
-
-Version 0.67
-------------
-Fix signal sending so that captive thread (cifsd) exits on umount 
-(which was causing the warning in kmem_cache_free of the request buffers
-at rmmod time).  This had broken as a sideeffect of the recent global
-kernel change to daemonize.  Fix memory leak in readdir code which
-showed up in "ls -R" (and applications that did search rewinding).
-
-Version 0.66
-------------
-Reconnect tids and fids after session reconnection (still do not
-reconnect byte range locks though).  Fix problem caching
-lookup information for directory inodes, improving performance,
-especially in deep directory trees.  Fix various build warnings.
-
-Version 0.65
-------------
-Finish fixes to commit write for caching/readahead consistency.  fsx 
-now works to Samba servers.  Fix oops caused when readahead
-was interrupted by a signal.
-
-Version 0.64
-------------
-Fix data corruption (in partial page after truncate) that caused fsx to
-fail to Windows servers.  Cleaned up some extraneous error logging in
-common error paths.  Add generic sendfile support.
-
-Version 0.63
-------------
-Fix memory leak in AllocMidQEntry.
-Finish reconnection logic, so connection with server can be dropped
-(or server rebooted) and the cifs client will reconnect.  
-
-Version 0.62
-------------
-Fix temporary socket leak when bad userid or password specified 
-(or other SMBSessSetup failure).  Increase maximum buffer size to slightly
-over 16K to allow negotiation of up to Samba and Windows server default read 
-sizes.  Add support for readpages
-
-Version 0.61
-------------
-Fix oops when username not passed in on mount.  Extensive fixes and improvements
-to error logging (strip redundant newlines, change debug macros to ensure newline
-passed in and to be more consistent).  Fix writepage wrong file handle problem,
-a readonly file handle could be incorrectly used to attempt to write out
-file updates through the page cache to multiply open files.  This could cause
-the iozone benchmark to fail on the fwrite test. Fix bug mounting two different
-shares to the same Windows server when using different usernames
-(doing this to Samba servers worked but Windows was rejecting it) - now it is
-possible to use different userids when connecting to the same server from a
-Linux client. Fix oops when treeDisconnect called during unmount on
-previously freed socket.
-
-Version 0.60
-------------
-Fix oops in readpages caused by not setting address space operations in inode in 
-rare code path. 
-
-Version 0.59
-------------
-Includes support for deleting of open files and renaming over existing files (per POSIX
-requirement).  Add readlink support for Windows junction points (directory symlinks).
-
-Version 0.58
-------------
-Changed read and write to go through pagecache. Added additional address space operations.
-Memory mapped operations now working.
-
-Version 0.57
-------------
-Added writepage code for additional memory mapping support.  Fixed leak in xids causing
-the simultaneous operations counter (/proc/fs/cifs/SimultaneousOps) to increase on 
-every stat call.  Additional formatting cleanup. 
-
-Version 0.56
-------------
-Fix bigendian bug in order of time conversion. Merge 2.5 to 2.4 version.  Formatting cleanup.   
-
-Version 0.55
-------------
-Fixes from Zwane Mwaikambo for adding missing return code checking in a few places.
-Also included a modified version of his fix to protect global list manipulation of
-the smb session and tree connection and mid related global variables.
-
-Version 0.54
-------------
-Fix problem with captive thread hanging around at unmount time.  Adjust to 2.5.42-pre
-changes to superblock layout.   Remove wasteful allocation of smb buffers (now the send 
-buffer is reused for responses).  Add more oplock handling. Additional minor cleanup.
-
-Version 0.53
-------------
-More stylistic updates to better match kernel style.  Add additional statistics
-for filesystem which can be viewed via /proc/fs/cifs.  Add more pieces of NTLMv2
-and CIFS Packet Signing enablement.
-
-Version 0.52
-------------
-Replace call to sleep_on with safer wait_on_event.
-Make stylistic changes to better match kernel style recommendations.
-Remove most typedef usage (except for the PDUs themselves).
-
-Version 0.51
-------------
-Update mount so the -unc mount option is no longer required (the ip address can be specified
-in a UNC style device name.   Implementation of readpage/writepage started.
-
-Version 0.50
-------------
-Fix intermittent problem with incorrect smb header checking on badly 
-fragmented tcp responses
-
-Version 0.49
-------------
-Fixes to setting of allocation size and file size.
-
-Version 0.48
-------------
-Various 2.5.38 fixes.  Now works on 2.5.38
-
-Version 0.47
-------------
-Prepare for 2.5 kernel merge.  Remove ifdefs.
-
-Version 0.46
-------------
-Socket buffer management fixes.  Fix dual free.
-
-Version 0.45
-------------
-Various big endian fixes for hardlinks and symlinks and also for dfs.
-
-Version 0.44
-------------
-Various big endian fixes for servers with Unix extensions such as Samba
-
-Version 0.43
-------------
-Various FindNext fixes for incorrect filenames on large directory searches on big endian
-clients.  basic posix file i/o tests now work on big endian machines, not just le
-
-Version 0.42
-------------
-SessionSetup and NegotiateProtocol now work from Big Endian machines.
-Various Big Endian fixes found during testing on the Linux on 390.  Various fixes for compatibility with older
-versions of 2.4 kernel (now builds and works again on kernels at least as early as 2.4.7).
-
-Version 0.41
-------------
-Various minor fixes for Connectathon Posix "basic" file i/o test suite.  Directory caching fixed so hardlinked
-files now return the correct number of links on fstat as they are repeatedly linked and unlinked.
-
-Version 0.40
-------------
-Implemented "Raw" (i.e. not encapsulated in SPNEGO) NTLMSSP (i.e. the Security Provider Interface used to negotiate
-session advanced session authentication).  Raw NTLMSSP is preferred by Windows 2000 Professional and Windows XP.
-Began implementing support for SPNEGO encapsulation of NTLMSSP based session authentication blobs
-(which is the mechanism preferred by Windows 2000 server in the absence of Kerberos).
-
-Version 0.38
-------------
-Introduced optional mount helper utility mount.cifs and made coreq changes to cifs vfs to enable
-it. Fixed a few bugs in the DFS code (e.g. bcc two bytes too short and incorrect uid in PDU).
-
-Version 0.37
-------------
-Rewrote much of connection and mount/unmount logic to handle bugs with
-multiple uses to same share, multiple users to same server etc.
-
-Version 0.36
-------------
-Fixed major problem with dentry corruption (missing call to dput)
-
-Version 0.35
-------------
-Rewrite of readdir code to fix bug. Various fixes for bigendian machines.
-Begin adding oplock support.  Multiusermount and oplockEnabled flags added to /proc/fs/cifs
-although corresponding function not fully implemented in the vfs yet
-
-Version 0.34
-------------
-Fixed dentry caching bug, misc. cleanup 
-
-Version 0.33
-------------
-Fixed 2.5 support to handle build and configure changes as well as misc. 2.5 changes.  Now can build
-on current 2.5 beta version (2.5.24) of the Linux kernel as well as on 2.4 Linux kernels.
-Support for STATUS codes (newer 32 bit NT error codes) added.  DFS support begun to be added.
-
-Version 0.32
-------------
-Unix extensions (symlink, readlink, hardlink, chmod and some chgrp and chown) implemented
-and tested against Samba 2.2.5
-
-
-Version 0.31
-------------
-1) Fixed lockrange to be correct (it was one byte too short)
-
-2) Fixed GETLK (i.e. the fcntl call to test a range of bytes in a file to see if locked) to correctly 
-show range as locked when there is a conflict with an existing lock.
-
-3) default file perms are now 2767 (indicating support for mandatory locks) instead of 777 for directories
-in most cases.  Eventually will offer optional ability to query server for the correct perms.
-
-3) Fixed eventual trap when mounting twice to different shares on the same server when the first succeeded 
-but the second one was invalid and failed (the second one was incorrectly disconnecting the tcp and smb
-session) 
-
-4) Fixed error logging of valid mount options
-
-5) Removed logging of password field.
-
-6) Moved negotiate, treeDisconnect and uloggoffX (only tConx and SessSetup remain in connect.c) to cifssmb.c
-and cleaned them up and made them more consistent with other cifs functions. 
-
-7) Server support for Unix extensions is now fully detected and FindFirst is implemented both ways 
-(with or without Unix extensions) but FindNext and QueryPathInfo with the Unix extensions are not completed,
-nor is the symlink support using the Unix extensions
-
-8) Started adding the readlink and follow_link code 
-
-Version 0.3 
------------
-Initial drop
-
index aa0d68b086ebcf47cfcd84bf66cc9c8ecfdcc0dd..1964d212ab08c864062916afccc9af1e3d85fb21 100644 (file)
@@ -6,7 +6,7 @@ obj-$(CONFIG_CIFS) += cifs.o
 cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \
          link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \
          cifs_unicode.o nterr.o xattr.o cifsencrypt.o \
-         readdir.o ioctl.o sess.o export.o smb1ops.o
+         readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o
 
 cifs-$(CONFIG_CIFS_ACL) += cifsacl.o
 
diff --git a/fs/cifs/README b/fs/cifs/README
deleted file mode 100644 (file)
index 2d5622f..0000000
+++ /dev/null
@@ -1,753 +0,0 @@
-The CIFS VFS support for Linux supports many advanced network filesystem 
-features such as hierarchical dfs like namespace, hardlinks, locking and more.  
-It was designed to comply with the SNIA CIFS Technical Reference (which 
-supersedes the 1992 X/Open SMB Standard) as well as to perform best practice 
-practical interoperability with Windows 2000, Windows XP, Samba and equivalent 
-servers.  This code was developed in participation with the Protocol Freedom
-Information Foundation.
-
-Please see
-  http://protocolfreedom.org/ and
-  http://samba.org/samba/PFIF/
-for more details.
-
-
-For questions or bug reports please contact:
-    sfrench@samba.org (sfrench@us.ibm.com) 
-
-Build instructions:
-==================
-For Linux 2.4:
-1) Get the kernel source (e.g.from http://www.kernel.org)
-and download the cifs vfs source (see the project page
-at http://us1.samba.org/samba/Linux_CIFS_client.html)
-and change directory into the top of the kernel directory
-then patch the kernel (e.g. "patch -p1 < cifs_24.patch") 
-to add the cifs vfs to your kernel configure options if
-it has not already been added (e.g. current SuSE and UL
-users do not need to apply the cifs_24.patch since the cifs vfs is
-already in the kernel configure menu) and then
-mkdir linux/fs/cifs and then copy the current cifs vfs files from
-the cifs download to your kernel build directory e.g.
-
-       cp <cifs_download_dir>/fs/cifs/* to <kernel_download_dir>/fs/cifs
-       
-2) make menuconfig (or make xconfig)
-3) select cifs from within the network filesystem choices
-4) save and exit
-5) make dep
-6) make modules (or "make" if CIFS VFS not to be built as a module)
-
-For Linux 2.6:
-1) Download the kernel (e.g. from http://www.kernel.org)
-and change directory into the top of the kernel directory tree
-(e.g. /usr/src/linux-2.5.73)
-2) make menuconfig (or make xconfig)
-3) select cifs from within the network filesystem choices
-4) save and exit
-5) make
-
-
-Installation instructions:
-=========================
-If you have built the CIFS vfs as module (successfully) simply
-type "make modules_install" (or if you prefer, manually copy the file to
-the modules directory e.g. /lib/modules/2.4.10-4GB/kernel/fs/cifs/cifs.o).
-
-If you have built the CIFS vfs into the kernel itself, follow the instructions
-for your distribution on how to install a new kernel (usually you
-would simply type "make install").
-
-If you do not have the utility mount.cifs (in the Samba 3.0 source tree and on 
-the CIFS VFS web site) copy it to the same directory in which mount.smbfs and 
-similar files reside (usually /sbin).  Although the helper software is not  
-required, mount.cifs is recommended.  Eventually the Samba 3.0 utility program 
-"net" may also be helpful since it may someday provide easier mount syntax for
-users who are used to Windows e.g.
-       net use <mount point> <UNC name or cifs URL>
-Note that running the Winbind pam/nss module (logon service) on all of your
-Linux clients is useful in mapping Uids and Gids consistently across the
-domain to the proper network user.  The mount.cifs mount helper can be
-trivially built from Samba 3.0 or later source e.g. by executing:
-
-       gcc samba/source/client/mount.cifs.c -o mount.cifs
-
-If cifs is built as a module, then the size and number of network buffers
-and maximum number of simultaneous requests to one server can be configured.
-Changing these from their defaults is not recommended. By executing modinfo
-       modinfo kernel/fs/cifs/cifs.ko
-on kernel/fs/cifs/cifs.ko the list of configuration changes that can be made
-at module initialization time (by running insmod cifs.ko) can be seen.
-
-Allowing User Mounts
-====================
-To permit users to mount and unmount over directories they own is possible
-with the cifs vfs.  A way to enable such mounting is to mark the mount.cifs
-utility as suid (e.g. "chmod +s /sbin/mount.cifs). To enable users to 
-umount shares they mount requires
-1) mount.cifs version 1.4 or later
-2) an entry for the share in /etc/fstab indicating that a user may
-unmount it e.g.
-//server/usersharename  /mnt/username cifs user 0 0
-
-Note that when the mount.cifs utility is run suid (allowing user mounts), 
-in order to reduce risks, the "nosuid" mount flag is passed in on mount to
-disallow execution of an suid program mounted on the remote target.
-When mount is executed as root, nosuid is not passed in by default,
-and execution of suid programs on the remote target would be enabled
-by default. This can be changed, as with nfs and other filesystems, 
-by simply specifying "nosuid" among the mount options. For user mounts 
-though to be able to pass the suid flag to mount requires rebuilding 
-mount.cifs with the following flag: 
-        gcc samba/source/client/mount.cifs.c -DCIFS_ALLOW_USR_SUID -o mount.cifs
-
-There is a corresponding manual page for cifs mounting in the Samba 3.0 and
-later source tree in docs/manpages/mount.cifs.8 
-
-Allowing User Unmounts
-======================
-To permit users to ummount directories that they have user mounted (see above),
-the utility umount.cifs may be used.  It may be invoked directly, or if 
-umount.cifs is placed in /sbin, umount can invoke the cifs umount helper
-(at least for most versions of the umount utility) for umount of cifs
-mounts, unless umount is invoked with -i (which will avoid invoking a umount
-helper). As with mount.cifs, to enable user unmounts umount.cifs must be marked
-as suid (e.g. "chmod +s /sbin/umount.cifs") or equivalent (some distributions
-allow adding entries to a file to the /etc/permissions file to achieve the
-equivalent suid effect).  For this utility to succeed the target path
-must be a cifs mount, and the uid of the current user must match the uid
-of the user who mounted the resource.
-
-Also note that the customary way of allowing user mounts and unmounts is 
-(instead of using mount.cifs and unmount.cifs as suid) to add a line
-to the file /etc/fstab for each //server/share you wish to mount, but
-this can become unwieldy when potential mount targets include many
-or  unpredictable UNC names.
-
-Samba Considerations 
-==================== 
-To get the maximum benefit from the CIFS VFS, we recommend using a server that 
-supports the SNIA CIFS Unix Extensions standard (e.g.  Samba 2.2.5 or later or 
-Samba 3.0) but the CIFS vfs works fine with a wide variety of CIFS servers.  
-Note that uid, gid and file permissions will display default values if you do 
-not have a server that supports the Unix extensions for CIFS (such as Samba 
-2.2.5 or later).  To enable the Unix CIFS Extensions in the Samba server, add 
-the line: 
-
-       unix extensions = yes
-       
-to your smb.conf file on the server.  Note that the following smb.conf settings 
-are also useful (on the Samba server) when the majority of clients are Unix or 
-Linux: 
-
-       case sensitive = yes
-       delete readonly = yes 
-       ea support = yes
-
-Note that server ea support is required for supporting xattrs from the Linux
-cifs client, and that EA support is present in later versions of Samba (e.g. 
-3.0.6 and later (also EA support works in all versions of Windows, at least to
-shares on NTFS filesystems).  Extended Attribute (xattr) support is an optional
-feature of most Linux filesystems which may require enabling via
-make menuconfig. Client support for extended attributes (user xattr) can be
-disabled on a per-mount basis by specifying "nouser_xattr" on mount.
-
-The CIFS client can get and set POSIX ACLs (getfacl, setfacl) to Samba servers
-version 3.10 and later.  Setting POSIX ACLs requires enabling both XATTR and 
-then POSIX support in the CIFS configuration options when building the cifs
-module.  POSIX ACL support can be disabled on a per mount basic by specifying
-"noacl" on mount.
-Some administrators may want to change Samba's smb.conf "map archive" and 
-"create mask" parameters from the default.  Unless the create mask is changed
-newly created files can end up with an unnecessarily restrictive default mode,
-which may not be what you want, although if the CIFS Unix extensions are
-enabled on the server and client, subsequent setattr calls (e.g. chmod) can
-fix the mode.  Note that creating special devices (mknod) remotely 
-may require specifying a mkdev function to Samba if you are not using 
-Samba 3.0.6 or later.  For more information on these see the manual pages
-("man smb.conf") on the Samba server system.  Note that the cifs vfs,
-unlike the smbfs vfs, does not read the smb.conf on the client system 
-(the few optional settings are passed in on mount via -o parameters instead).  
-Note that Samba 2.2.7 or later includes a fix that allows the CIFS VFS to delete
-open files (required for strict POSIX compliance).  Windows Servers already 
-supported this feature. Samba server does not allow symlinks that refer to files
-outside of the share, so in Samba versions prior to 3.0.6, most symlinks to
-files with absolute paths (ie beginning with slash) such as:
-        ln -s /mnt/foo bar
-would be forbidden. Samba 3.0.6 server or later includes the ability to create 
-such symlinks safely by converting unsafe symlinks (ie symlinks to server 
-files that are outside of the share) to a samba specific format on the server
-that is ignored by local server applications and non-cifs clients and that will
-not be traversed by the Samba server).  This is opaque to the Linux client
-application using the cifs vfs. Absolute symlinks will work to Samba 3.0.5 or
-later, but only for remote clients using the CIFS Unix extensions, and will
-be invisbile to Windows clients and typically will not affect local
-applications running on the same server as Samba.  
-
-Use instructions:
-================
-Once the CIFS VFS support is built into the kernel or installed as a module 
-(cifs.o), you can use mount syntax like the following to access Samba or Windows 
-servers: 
-
-  mount -t cifs //9.53.216.11/e$ /mnt -o user=myname,pass=mypassword
-
-Before -o the option -v may be specified to make the mount.cifs
-mount helper display the mount steps more verbosely.  
-After -o the following commonly used cifs vfs specific options
-are supported:
-
-  user=<username>
-  pass=<password>
-  domain=<domain name>
-  
-Other cifs mount options are described below.  Use of TCP names (in addition to
-ip addresses) is available if the mount helper (mount.cifs) is installed. If
-you do not trust the server to which are mounted, or if you do not have
-cifs signing enabled (and the physical network is insecure), consider use
-of the standard mount options "noexec" and "nosuid" to reduce the risk of 
-running an altered binary on your local system (downloaded from a hostile server
-or altered by a hostile router).
-
-Although mounting using format corresponding to the CIFS URL specification is
-not possible in mount.cifs yet, it is possible to use an alternate format
-for the server and sharename (which is somewhat similar to NFS style mount
-syntax) instead of the more widely used UNC format (i.e. \\server\share):
-  mount -t cifs tcp_name_of_server:share_name /mnt -o user=myname,pass=mypasswd
-
-When using the mount helper mount.cifs, passwords may be specified via alternate
-mechanisms, instead of specifying it after -o using the normal "pass=" syntax
-on the command line:
-1) By including it in a credential file. Specify credentials=filename as one
-of the mount options. Credential files contain two lines
-        username=someuser
-        password=your_password
-2) By specifying the password in the PASSWD environment variable (similarly
-the user name can be taken from the USER environment variable).
-3) By specifying the password in a file by name via PASSWD_FILE
-4) By specifying the password in a file by file descriptor via PASSWD_FD
-
-If no password is provided, mount.cifs will prompt for password entry
-
-Restrictions
-============
-Servers must support either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 
-1001/1002 support for "Netbios-Over-TCP/IP." This is not likely to be a 
-problem as most servers support this.
-
-Valid filenames differ between Windows and Linux.  Windows typically restricts
-filenames which contain certain reserved characters (e.g.the character : 
-which is used to delimit the beginning of a stream name by Windows), while
-Linux allows a slightly wider set of valid characters in filenames. Windows
-servers can remap such characters when an explicit mapping is specified in
-the Server's registry.  Samba starting with version 3.10 will allow such 
-filenames (ie those which contain valid Linux characters, which normally
-would be forbidden for Windows/CIFS semantics) as long as the server is
-configured for Unix Extensions (and the client has not disabled
-/proc/fs/cifs/LinuxExtensionsEnabled).
-  
-
-CIFS VFS Mount Options
-======================
-A partial list of the supported mount options follows:
-  user         The user name to use when trying to establish
-               the CIFS session.
-  password     The user password.  If the mount helper is
-               installed, the user will be prompted for password
-               if not supplied.
-  ip           The ip address of the target server
-  unc          The target server Universal Network Name (export) to 
-               mount.  
-  domain       Set the SMB/CIFS workgroup name prepended to the
-               username during CIFS session establishment
-  forceuid     Set the default uid for inodes to the uid
-               passed in on mount. For mounts to servers
-               which do support the CIFS Unix extensions, such as a
-               properly configured Samba server, the server provides
-               the uid, gid and mode so this parameter should not be
-               specified unless the server and clients uid and gid
-               numbering differ.  If the server and client are in the
-               same domain (e.g. running winbind or nss_ldap) and
-               the server supports the Unix Extensions then the uid
-               and gid can be retrieved from the server (and uid
-               and gid would not have to be specifed on the mount. 
-               For servers which do not support the CIFS Unix
-               extensions, the default uid (and gid) returned on lookup
-               of existing files will be the uid (gid) of the person
-               who executed the mount (root, except when mount.cifs
-               is configured setuid for user mounts) unless the "uid=" 
-               (gid) mount option is specified. Also note that permission
-               checks (authorization checks) on accesses to a file occur
-               at the server, but there are cases in which an administrator
-               may want to restrict at the client as well.  For those
-               servers which do not report a uid/gid owner
-               (such as Windows), permissions can also be checked at the
-               client, and a crude form of client side permission checking 
-               can be enabled by specifying file_mode and dir_mode on 
-               the client.  (default)
-  forcegid     (similar to above but for the groupid instead of uid) (default)
-  noforceuid   Fill in file owner information (uid) by requesting it from
-               the server if possible. With this option, the value given in
-               the uid= option (on mount) will only be used if the server
-               can not support returning uids on inodes.
-  noforcegid   (similar to above but for the group owner, gid, instead of uid)
-  uid          Set the default uid for inodes, and indicate to the
-               cifs kernel driver which local user mounted. If the server
-               supports the unix extensions the default uid is
-               not used to fill in the owner fields of inodes (files)
-               unless the "forceuid" parameter is specified.
-  gid          Set the default gid for inodes (similar to above).
-  file_mode     If CIFS Unix extensions are not supported by the server
-               this overrides the default mode for file inodes.
-  fsc          Enable local disk caching using FS-Cache (off by default). This
-               option could be useful to improve performance on a slow link,
-               heavily loaded server and/or network where reading from the
-               disk is faster than reading from the server (over the network).
-               This could also impact scalability positively as the
-               number of calls to the server are reduced. However, local
-               caching is not suitable for all workloads for e.g. read-once
-               type workloads. So, you need to consider carefully your
-               workload/scenario before using this option. Currently, local
-               disk caching is functional for CIFS files opened as read-only.
-  dir_mode      If CIFS Unix extensions are not supported by the server 
-               this overrides the default mode for directory inodes.
-  port         attempt to contact the server on this tcp port, before
-               trying the usual ports (port 445, then 139).
-  iocharset     Codepage used to convert local path names to and from
-               Unicode. Unicode is used by default for network path
-               names if the server supports it.  If iocharset is
-               not specified then the nls_default specified
-               during the local client kernel build will be used.
-               If server does not support Unicode, this parameter is
-               unused.
-  rsize                default read size (usually 16K). The client currently
-               can not use rsize larger than CIFSMaxBufSize. CIFSMaxBufSize
-               defaults to 16K and may be changed (from 8K to the maximum
-               kmalloc size allowed by your kernel) at module install time
-               for cifs.ko. Setting CIFSMaxBufSize to a very large value
-               will cause cifs to use more memory and may reduce performance
-               in some cases.  To use rsize greater than 127K (the original
-               cifs protocol maximum) also requires that the server support
-               a new Unix Capability flag (for very large read) which some
-               newer servers (e.g. Samba 3.0.26 or later) do. rsize can be
-               set from a minimum of 2048 to a maximum of 130048 (127K or
-               CIFSMaxBufSize, whichever is smaller)
-  wsize                default write size (default 57344)
-               maximum wsize currently allowed by CIFS is 57344 (fourteen
-               4096 byte pages)
-  actimeo=n    attribute cache timeout in seconds (default 1 second).
-               After this timeout, the cifs client requests fresh attribute
-               information from the server. This option allows to tune the
-               attribute cache timeout to suit the workload needs. Shorter
-               timeouts mean better the cache coherency, but increased number
-               of calls to the server. Longer timeouts mean reduced number
-               of calls to the server at the expense of less stricter cache
-               coherency checks (i.e. incorrect attribute cache for a short
-               period of time).
-  rw           mount the network share read-write (note that the
-               server may still consider the share read-only)
-  ro           mount network share read-only
-  version      used to distinguish different versions of the
-               mount helper utility (not typically needed)
-  sep          if first mount option (after the -o), overrides
-               the comma as the separator between the mount
-               parms. e.g.
-                       -o user=myname,password=mypassword,domain=mydom
-               could be passed instead with period as the separator by
-                       -o sep=.user=myname.password=mypassword.domain=mydom
-               this might be useful when comma is contained within username
-               or password or domain. This option is less important
-               when the cifs mount helper cifs.mount (version 1.1 or later)
-               is used.
-  nosuid        Do not allow remote executables with the suid bit 
-               program to be executed.  This is only meaningful for mounts
-               to servers such as Samba which support the CIFS Unix Extensions.
-               If you do not trust the servers in your network (your mount
-               targets) it is recommended that you specify this option for
-               greater security.
-  exec         Permit execution of binaries on the mount.
-  noexec       Do not permit execution of binaries on the mount.
-  dev          Recognize block devices on the remote mount.
-  nodev                Do not recognize devices on the remote mount.
-  suid          Allow remote files on this mountpoint with suid enabled to 
-               be executed (default for mounts when executed as root,
-               nosuid is default for user mounts).
-  credentials   Although ignored by the cifs kernel component, it is used by 
-               the mount helper, mount.cifs. When mount.cifs is installed it
-               opens and reads the credential file specified in order  
-               to obtain the userid and password arguments which are passed to
-               the cifs vfs.
-  guest         Although ignored by the kernel component, the mount.cifs
-               mount helper will not prompt the user for a password
-               if guest is specified on the mount options.  If no
-               password is specified a null password will be used.
-  perm          Client does permission checks (vfs_permission check of uid
-               and gid of the file against the mode and desired operation),
-               Note that this is in addition to the normal ACL check on the
-               target machine done by the server software. 
-               Client permission checking is enabled by default.
-  noperm        Client does not do permission checks.  This can expose
-               files on this mount to access by other users on the local
-               client system. It is typically only needed when the server
-               supports the CIFS Unix Extensions but the UIDs/GIDs on the
-               client and server system do not match closely enough to allow
-               access by the user doing the mount, but it may be useful with
-               non CIFS Unix Extension mounts for cases in which the default
-               mode is specified on the mount but is not to be enforced on the
-               client (e.g. perhaps when MultiUserMount is enabled)
-               Note that this does not affect the normal ACL check on the
-               target machine done by the server software (of the server
-               ACL against the user name provided at mount time).
-  serverino    Use server's inode numbers instead of generating automatically
-               incrementing inode numbers on the client.  Although this will
-               make it easier to spot hardlinked files (as they will have
-               the same inode numbers) and inode numbers may be persistent,
-               note that the server does not guarantee that the inode numbers
-               are unique if multiple server side mounts are exported under a
-               single share (since inode numbers on the servers might not
-               be unique if multiple filesystems are mounted under the same
-               shared higher level directory).  Note that some older
-               (e.g. pre-Windows 2000) do not support returning UniqueIDs
-               or the CIFS Unix Extensions equivalent and for those
-               this mount option will have no effect.  Exporting cifs mounts
-               under nfsd requires this mount option on the cifs mount.
-               This is now the default if server supports the 
-               required network operation.
-  noserverino   Client generates inode numbers (rather than using the actual one
-               from the server). These inode numbers will vary after
-               unmount or reboot which can confuse some applications,
-               but not all server filesystems support unique inode
-               numbers.
-  setuids       If the CIFS Unix extensions are negotiated with the server
-               the client will attempt to set the effective uid and gid of
-               the local process on newly created files, directories, and
-               devices (create, mkdir, mknod).  If the CIFS Unix Extensions
-               are not negotiated, for newly created files and directories
-               instead of using the default uid and gid specified on
-               the mount, cache the new file's uid and gid locally which means
-               that the uid for the file can change when the inode is
-               reloaded (or the user remounts the share).
-  nosetuids     The client will not attempt to set the uid and gid on
-               on newly created files, directories, and devices (create, 
-               mkdir, mknod) which will result in the server setting the
-               uid and gid to the default (usually the server uid of the
-               user who mounted the share).  Letting the server (rather than
-               the client) set the uid and gid is the default. If the CIFS
-               Unix Extensions are not negotiated then the uid and gid for
-               new files will appear to be the uid (gid) of the mounter or the
-               uid (gid) parameter specified on the mount.
-  netbiosname   When mounting to servers via port 139, specifies the RFC1001
-               source name to use to represent the client netbios machine 
-               name when doing the RFC1001 netbios session initialize.
-  direct        Do not do inode data caching on files opened on this mount.
-               This precludes mmapping files on this mount. In some cases
-               with fast networks and little or no caching benefits on the
-               client (e.g. when the application is doing large sequential
-               reads bigger than page size without rereading the same data) 
-               this can provide better performance than the default
-               behavior which caches reads (readahead) and writes 
-               (writebehind) through the local Linux client pagecache 
-               if oplock (caching token) is granted and held. Note that
-               direct allows write operations larger than page size
-               to be sent to the server.
-  strictcache   Use for switching on strict cache mode. In this mode the
-               client read from the cache all the time it has Oplock Level II,
-               otherwise - read from the server. All written data are stored
-               in the cache, but if the client doesn't have Exclusive Oplock,
-               it writes the data to the server.
-  rwpidforward  Forward pid of a process who opened a file to any read or write
-               operation on that file. This prevent applications like WINE
-               from failing on read and write if we use mandatory brlock style.
-  acl          Allow setfacl and getfacl to manage posix ACLs if server
-               supports them.  (default)
-  noacl        Do not allow setfacl and getfacl calls on this mount
-  user_xattr    Allow getting and setting user xattrs (those attributes whose
-               name begins with "user." or "os2.") as OS/2 EAs (extended
-               attributes) to the server.  This allows support of the
-               setfattr and getfattr utilities. (default)
-  nouser_xattr  Do not allow getfattr/setfattr to get/set/list xattrs 
-  mapchars      Translate six of the seven reserved characters (not backslash)
-                       *?<>|:
-               to the remap range (above 0xF000), which also
-               allows the CIFS client to recognize files created with
-               such characters by Windows's POSIX emulation. This can
-               also be useful when mounting to most versions of Samba
-               (which also forbids creating and opening files
-               whose names contain any of these seven characters).
-               This has no effect if the server does not support
-               Unicode on the wire.
- nomapchars     Do not translate any of these seven characters (default).
- nocase         Request case insensitive path name matching (case
-               sensitive is the default if the server supports it).
-               (mount option "ignorecase" is identical to "nocase")
- posixpaths     If CIFS Unix extensions are supported, attempt to
-               negotiate posix path name support which allows certain
-               characters forbidden in typical CIFS filenames, without
-               requiring remapping. (default)
- noposixpaths   If CIFS Unix extensions are supported, do not request
-               posix path name support (this may cause servers to
-               reject creatingfile with certain reserved characters).
- nounix         Disable the CIFS Unix Extensions for this mount (tree
-               connection). This is rarely needed, but it may be useful
-               in order to turn off multiple settings all at once (ie
-               posix acls, posix locks, posix paths, symlink support
-               and retrieving uids/gids/mode from the server) or to
-               work around a bug in server which implement the Unix
-               Extensions.
- nobrl          Do not send byte range lock requests to the server.
-               This is necessary for certain applications that break
-               with cifs style mandatory byte range locks (and most
-               cifs servers do not yet support requesting advisory
-               byte range locks).
- forcemandatorylock Even if the server supports posix (advisory) byte range
-               locking, send only mandatory lock requests.  For some
-               (presumably rare) applications, originally coded for
-               DOS/Windows, which require Windows style mandatory byte range
-               locking, they may be able to take advantage of this option,
-               forcing the cifs client to only send mandatory locks
-               even if the cifs server would support posix advisory locks.
-               "forcemand" is accepted as a shorter form of this mount
-               option.
- nostrictsync   If this mount option is set, when an application does an
-               fsync call then the cifs client does not send an SMB Flush
-               to the server (to force the server to write all dirty data
-               for this file immediately to disk), although cifs still sends
-               all dirty (cached) file data to the server and waits for the
-               server to respond to the write.  Since SMB Flush can be
-               very slow, and some servers may be reliable enough (to risk
-               delaying slightly flushing the data to disk on the server),
-               turning on this option may be useful to improve performance for
-               applications that fsync too much, at a small risk of server
-               crash.  If this mount option is not set, by default cifs will
-               send an SMB flush request (and wait for a response) on every
-               fsync call.
- nodfs          Disable DFS (global name space support) even if the
-               server claims to support it.  This can help work around
-               a problem with parsing of DFS paths with Samba server
-               versions 3.0.24 and 3.0.25.
- remount        remount the share (often used to change from ro to rw mounts
-               or vice versa)
- cifsacl        Report mode bits (e.g. on stat) based on the Windows ACL for
-               the file. (EXPERIMENTAL)
- servern        Specify the server 's netbios name (RFC1001 name) to use
-               when attempting to setup a session to the server. 
-               This is needed for mounting to some older servers (such
-               as OS/2 or Windows 98 and Windows ME) since they do not
-               support a default server name.  A server name can be up
-               to 15 characters long and is usually uppercased.
- sfu            When the CIFS Unix Extensions are not negotiated, attempt to
-               create device files and fifos in a format compatible with
-               Services for Unix (SFU).  In addition retrieve bits 10-12
-               of the mode via the SETFILEBITS extended attribute (as
-               SFU does).  In the future the bottom 9 bits of the
-               mode also will be emulated using queries of the security
-               descriptor (ACL).
- mfsymlinks     Enable support for Minshall+French symlinks
-               (see http://wiki.samba.org/index.php/UNIX_Extensions#Minshall.2BFrench_symlinks)
-               This option is ignored when specified together with the
-               'sfu' option. Minshall+French symlinks are used even if
-               the server supports the CIFS Unix Extensions.
- sign           Must use packet signing (helps avoid unwanted data modification
-               by intermediate systems in the route).  Note that signing
-               does not work with lanman or plaintext authentication.
- seal           Must seal (encrypt) all data on this mounted share before
-               sending on the network.  Requires support for Unix Extensions.
-               Note that this differs from the sign mount option in that it
-               causes encryption of data sent over this mounted share but other
-               shares mounted to the same server are unaffected.
- locallease     This option is rarely needed. Fcntl F_SETLEASE is
-               used by some applications such as Samba and NFSv4 server to
-               check to see whether a file is cacheable.  CIFS has no way
-               to explicitly request a lease, but can check whether a file
-               is cacheable (oplocked).  Unfortunately, even if a file
-               is not oplocked, it could still be cacheable (ie cifs client
-               could grant fcntl leases if no other local processes are using
-               the file) for cases for example such as when the server does not
-               support oplocks and the user is sure that the only updates to
-               the file will be from this client. Specifying this mount option
-               will allow the cifs client to check for leases (only) locally
-               for files which are not oplocked instead of denying leases
-               in that case. (EXPERIMENTAL)
- sec            Security mode.  Allowed values are:
-                       none    attempt to connection as a null user (no name)
-                       krb5    Use Kerberos version 5 authentication
-                       krb5i   Use Kerberos authentication and packet signing
-                       ntlm    Use NTLM password hashing (default)
-                       ntlmi   Use NTLM password hashing with signing (if
-                               /proc/fs/cifs/PacketSigningEnabled on or if
-                               server requires signing also can be the default) 
-                       ntlmv2  Use NTLMv2 password hashing      
-                       ntlmv2i Use NTLMv2 password hashing with packet signing
-                       lanman  (if configured in kernel config) use older
-                               lanman hash
-hard           Retry file operations if server is not responding
-soft           Limit retries to unresponsive servers (usually only
-               one retry) before returning an error.  (default)
-
-The mount.cifs mount helper also accepts a few mount options before -o
-including:
-
-       -S      take password from stdin (equivalent to setting the environment
-               variable "PASSWD_FD=0"
-       -V      print mount.cifs version
-       -?      display simple usage information
-
-With most 2.6 kernel versions of modutils, the version of the cifs kernel
-module can be displayed via modinfo.
-
-Misc /proc/fs/cifs Flags and Debug Info
-=======================================
-Informational pseudo-files:
-DebugData              Displays information about active CIFS sessions and
-                       shares, features enabled as well as the cifs.ko
-                       version.
-Stats                  Lists summary resource usage information as well as per
-                       share statistics, if CONFIG_CIFS_STATS in enabled
-                       in the kernel configuration.
-
-Configuration pseudo-files:
-PacketSigningEnabled   If set to one, cifs packet signing is enabled
-                       and will be used if the server requires 
-                       it.  If set to two, cifs packet signing is
-                       required even if the server considers packet
-                       signing optional. (default 1)
-SecurityFlags          Flags which control security negotiation and
-                       also packet signing. Authentication (may/must)
-                       flags (e.g. for NTLM and/or NTLMv2) may be combined with
-                       the signing flags.  Specifying two different password
-                       hashing mechanisms (as "must use") on the other hand 
-                       does not make much sense. Default flags are 
-                               0x07007 
-                       (NTLM, NTLMv2 and packet signing allowed).  The maximum 
-                       allowable flags if you want to allow mounts to servers
-                       using weaker password hashes is 0x37037 (lanman,
-                       plaintext, ntlm, ntlmv2, signing allowed).  Some
-                       SecurityFlags require the corresponding menuconfig
-                       options to be enabled (lanman and plaintext require
-                       CONFIG_CIFS_WEAK_PW_HASH for example).  Enabling
-                       plaintext authentication currently requires also
-                       enabling lanman authentication in the security flags
-                       because the cifs module only supports sending
-                       laintext passwords using the older lanman dialect
-                       form of the session setup SMB.  (e.g. for authentication
-                       using plain text passwords, set the SecurityFlags
-                       to 0x30030):
-                       may use packet signing                          0x00001
-                       must use packet signing                         0x01001
-                       may use NTLM (most common password hash)        0x00002
-                       must use NTLM                                   0x02002
-                       may use NTLMv2                                  0x00004
-                       must use NTLMv2                                 0x04004
-                       may use Kerberos security                       0x00008
-                       must use Kerberos                               0x08008
-                       may use lanman (weak) password hash             0x00010
-                       must use lanman password hash                   0x10010
-                       may use plaintext passwords                     0x00020
-                       must use plaintext passwords                    0x20020
-                       (reserved for future packet encryption)         0x00040
-
-cifsFYI                        If set to non-zero value, additional debug information
-                       will be logged to the system error log.  This field
-                       contains three flags controlling different classes of
-                       debugging entries.  The maximum value it can be set
-                       to is 7 which enables all debugging points (default 0).
-                       Some debugging statements are not compiled into the
-                       cifs kernel unless CONFIG_CIFS_DEBUG2 is enabled in the
-                       kernel configuration. cifsFYI may be set to one or
-                       nore of the following flags (7 sets them all):
-
-                       log cifs informational messages                 0x01
-                       log return codes from cifs entry points         0x02
-                       log slow responses (ie which take longer than 1 second)
-                         CONFIG_CIFS_STATS2 must be enabled in .config 0x04
-                               
-                               
-traceSMB               If set to one, debug information is logged to the
-                       system error log with the start of smb requests
-                       and responses (default 0)
-LookupCacheEnable      If set to one, inode information is kept cached
-                       for one second improving performance of lookups
-                       (default 1)
-OplockEnabled          If set to one, safe distributed caching enabled.
-                       (default 1)
-LinuxExtensionsEnabled If set to one then the client will attempt to
-                       use the CIFS "UNIX" extensions which are optional
-                       protocol enhancements that allow CIFS servers
-                       to return accurate UID/GID information as well
-                       as support symbolic links. If you use servers
-                       such as Samba that support the CIFS Unix
-                       extensions but do not want to use symbolic link
-                       support and want to map the uid and gid fields 
-                       to values supplied at mount (rather than the 
-                       actual values, then set this to zero. (default 1)
-
-These experimental features and tracing can be enabled by changing flags in 
-/proc/fs/cifs (after the cifs module has been installed or built into the 
-kernel, e.g.  insmod cifs).  To enable a feature set it to 1 e.g.  to enable 
-tracing to the kernel message log type: 
-
-       echo 7 > /proc/fs/cifs/cifsFYI
-       
-cifsFYI functions as a bit mask. Setting it to 1 enables additional kernel
-logging of various informational messages.  2 enables logging of non-zero
-SMB return codes while 4 enables logging of requests that take longer
-than one second to complete (except for byte range lock requests). 
-Setting it to 4 requires defining CONFIG_CIFS_STATS2 manually in the
-source code (typically by setting it in the beginning of cifsglob.h),
-and setting it to seven enables all three.  Finally, tracing
-the start of smb requests and responses can be enabled via:
-
-       echo 1 > /proc/fs/cifs/traceSMB
-
-Per share (per client mount) statistics are available in /proc/fs/cifs/Stats
-if the kernel was configured with cifs statistics enabled.  The statistics
-represent the number of successful (ie non-zero return code from the server) 
-SMB responses to some of the more common commands (open, delete, mkdir etc.).
-Also recorded is the total bytes read and bytes written to the server for
-that share.  Note that due to client caching effects this can be less than the
-number of bytes read and written by the application running on the client.
-The statistics for the number of total SMBs and oplock breaks are different in
-that they represent all for that share, not just those for which the server
-returned success.
-       
-Also note that "cat /proc/fs/cifs/DebugData" will display information about
-the active sessions and the shares that are mounted.
-
-Enabling Kerberos (extended security) works but requires version 1.2 or later
-of the helper program cifs.upcall to be present and to be configured in the
-/etc/request-key.conf file.  The cifs.upcall helper program is from the Samba
-project(http://www.samba.org). NTLM and NTLMv2 and LANMAN support do not
-require this helper. Note that NTLMv2 security (which does not require the
-cifs.upcall helper program), instead of using Kerberos, is sufficient for
-some use cases.
-
-DFS support allows transparent redirection to shares in an MS-DFS name space.
-In addition, DFS support for target shares which are specified as UNC
-names which begin with host names (rather than IP addresses) requires
-a user space helper (such as cifs.upcall) to be present in order to
-translate host names to ip address, and the user space helper must also
-be configured in the file /etc/request-key.conf.  Samba, Windows servers and
-many NAS appliances support DFS as a way of constructing a global name
-space to ease network configuration and improve reliability.
-
-To use cifs Kerberos and DFS support, the Linux keyutils package should be
-installed and something like the following lines should be added to the
-/etc/request-key.conf file:
-
-create cifs.spnego * * /usr/local/sbin/cifs.upcall %k
-create dns_resolver * * /usr/local/sbin/cifs.upcall %k
-
-CIFS kernel module parameters
-=============================
-These module parameters can be specified or modified either during the time of
-module loading or during the runtime by using the interface
-       /proc/module/cifs/parameters/<param>
-
-i.e. echo "value" > /sys/module/cifs/parameters/<param>
-
-1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default.
-                   [Y/y/1]. To disable use any of [N/n/0].
-
diff --git a/fs/cifs/TODO b/fs/cifs/TODO
deleted file mode 100644 (file)
index 355abcd..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-Version 1.53 May 20, 2008
-
-A Partial List of Missing Features
-==================================
-
-Contributions are welcome.  There are plenty of opportunities
-for visible, important contributions to this module.  Here
-is a partial list of the known problems and missing features:
-
-a) Support for SecurityDescriptors(Windows/CIFS ACLs) for chmod/chgrp/chown
-so that these operations can be supported to Windows servers
-
-b) Mapping POSIX ACLs (and eventually NFSv4 ACLs) to CIFS
-SecurityDescriptors
-
-c) Better pam/winbind integration (e.g. to handle uid mapping
-better)
-
-d) Cleanup now unneeded SessSetup code in
-fs/cifs/connect.c and add back in NTLMSSP code if any servers
-need it
-
-e) fix NTLMv2 signing when two mounts with different users to same
-server.
-
-f) Directory entry caching relies on a 1 second timer, rather than 
-using FindNotify or equivalent.  - (started)
-
-g) quota support (needs minor kernel change since quota calls
-to make it to network filesystems or deviceless filesystems)
-
-h) investigate sync behavior (including syncpage) and check  
-for proper behavior of intr/nointr
-
-i) improve support for very old servers (OS/2 and Win9x for example)
-Including support for changing the time remotely (utimes command).
-
-j) hook lower into the sockets api (as NFS/SunRPC does) to avoid the
-extra copy in/out of the socket buffers in some cases.
-
-k) Better optimize open (and pathbased setfilesize) to reduce the
-oplock breaks coming from windows srv.  Piggyback identical file
-opens on top of each other by incrementing reference count rather
-than resending (helps reduce server resource utilization and avoid
-spurious oplock breaks).
-
-l) Improve performance of readpages by sending more than one read
-at a time when 8 pages or more are requested. In conjuntion
-add support for async_cifs_readpages.
-
-m) Add support for storing symlink info to Windows servers 
-in the Extended Attribute format their SFU clients would recognize.
-
-n) Finish fcntl D_NOTIFY support so kde and gnome file list windows
-will autorefresh (partially complete by Asser). Needs minor kernel
-vfs change to support removing D_NOTIFY on a file.   
-
-o) Add GUI tool to configure /proc/fs/cifs settings and for display of
-the CIFS statistics (started)
-
-p) implement support for security and trusted categories of xattrs
-(requires minor protocol extension) to enable better support for SELINUX
-
-q) Implement O_DIRECT flag on open (already supported on mount)
-
-r) Create UID mapping facility so server UIDs can be mapped on a per
-mount or a per server basis to client UIDs or nobody if no mapping
-exists.  This is helpful when Unix extensions are negotiated to
-allow better permission checking when UIDs differ on the server
-and client.  Add new protocol request to the CIFS protocol 
-standard for asking the server for the corresponding name of a
-particular uid.
-
-s) Add support for CIFS Unix and also the newer POSIX extensions to the
-server side for Samba 4.
-
-t) In support for OS/2 (LANMAN 1.2 and LANMAN2.1 based SMB servers) 
-need to add ability to set time to server (utimes command)
-
-u) DOS attrs - returned as pseudo-xattr in Samba format (check VFAT and NTFS for this too)
-
-v) mount check for unmatched uids
-
-w) Add support for new vfs entry point for fallocate
-
-x) Fix Samba 3 server to handle Linux kernel aio so dbench with lots of 
-processes can proceed better in parallel (on the server)
-
-y) Fix Samba 3 to handle reads/writes over 127K (and remove the cifs mount
-restriction of wsize max being 127K) 
-
-KNOWN BUGS (updated April 24, 2007)
-====================================
-See http://bugzilla.samba.org - search on product "CifsVFS" for
-current bug list.
-
-1) existing symbolic links (Windows reparse points) are recognized but
-can not be created remotely. They are implemented for Samba and those that
-support the CIFS Unix extensions, although earlier versions of Samba
-overly restrict the pathnames.
-2) follow_link and readdir code does not follow dfs junctions
-but recognizes them
-3) create of new files to FAT partitions on Windows servers can
-succeed but still return access denied (appears to be Windows 
-server not cifs client problem) and has not been reproduced recently.
-NTFS partitions do not have this problem.
-4) Unix/POSIX capabilities are reset after reconnection, and affect
-a few fields in the tree connection but we do do not know which
-superblocks to apply these changes to.  We should probably walk
-the list of superblocks to set these.  Also need to check the
-flags on the second mount to the same share, and see if we
-can do the same trick that NFS does to remount duplicate shares.
-
-Misc testing to do
-==================
-1) check out max path names and max path name components against various server
-types. Try nested symlinks (8 deep). Return max path name in stat -f information
-
-2) Modify file portion of ltp so it can run against a mounted network
-share and run it against cifs vfs in automated fashion.
-
-3) Additional performance testing and optimization using iozone and similar - 
-there are some easy changes that can be done to parallelize sequential writes,
-and when signing is disabled to request larger read sizes (larger than 
-negotiated size) and send larger write sizes to modern servers.
-
-4) More exhaustively test against less common servers.  More testing
-against Windows 9x, Windows ME servers.
-
index fe8d6276410a5613230743f20312d4f283db2f4f..d8eac3b6cefb35639000ff74367129fbc72f37dc 100644 (file)
@@ -91,6 +91,8 @@ extern __le16 *cifs_strndup_to_utf16(const char *src, const int maxlen,
 #endif /* CONFIG_CIFS_SMB2 */
 #endif
 
+wchar_t cifs_toupper(wchar_t in);
+
 /*
  * UniStrcat:  Concatenate the second string to the first
  *
index 85ea98d139fc5643b0606b67959bb1f320037d80..a16b4e58bcc62ee88f9772f75120ef250d0112bd 100644 (file)
@@ -255,6 +255,7 @@ cifs_alloc_inode(struct super_block *sb)
        cifs_inode->server_eof = 0;
        cifs_inode->uniqueid = 0;
        cifs_inode->createtime = 0;
+       cifs_inode->epoch = 0;
 #ifdef CONFIG_CIFS_SMB2
        get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
 #endif
@@ -357,6 +358,18 @@ cifs_show_cache_flavor(struct seq_file *s, struct cifs_sb_info *cifs_sb)
                seq_printf(s, "loose");
 }
 
+static void
+cifs_show_nls(struct seq_file *s, struct nls_table *cur)
+{
+       struct nls_table *def;
+
+       /* Display iocharset= option if it's not default charset */
+       def = load_nls_default();
+       if (def != cur)
+               seq_printf(s, ",iocharset=%s", cur->charset);
+       unload_nls(def);
+}
+
 /*
  * cifs_show_options() is for displaying mount options in /proc/mounts.
  * Not all settable options are displayed but most of the important
@@ -418,6 +431,9 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
                seq_printf(s, ",file_mode=0%ho,dir_mode=0%ho",
                                           cifs_sb->mnt_file_mode,
                                           cifs_sb->mnt_dir_mode);
+
+       cifs_show_nls(s, cifs_sb->local_nls);
+
        if (tcon->seal)
                seq_printf(s, ",seal");
        if (tcon->nocase)
@@ -718,7 +734,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
 
        written = generic_file_aio_write(iocb, iov, nr_segs, pos);
 
-       if (CIFS_I(inode)->clientCanCacheAll)
+       if (CIFS_CACHE_WRITE(CIFS_I(inode)))
                return written;
 
        rc = filemap_fdatawrite(inode->i_mapping);
@@ -743,7 +759,7 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
                 * We need to be sure that all dirty pages are written and the
                 * server has the newest file length.
                 */
-               if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
+               if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
                    inode->i_mapping->nrpages != 0) {
                        rc = filemap_fdatawait(inode->i_mapping);
                        if (rc) {
@@ -767,8 +783,10 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int whence)
 
 static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
 {
-       /* note that this is called by vfs setlease with i_lock held
-          to protect *lease from going away */
+       /*
+        * Note that this is called by vfs setlease with i_lock held to
+        * protect *lease from going away.
+        */
        struct inode *inode = file_inode(file);
        struct cifsFileInfo *cfile = file->private_data;
 
@@ -776,20 +794,19 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
                return -EINVAL;
 
        /* check if file is oplocked */
-       if (((arg == F_RDLCK) &&
-               (CIFS_I(inode)->clientCanCacheRead)) ||
-           ((arg == F_WRLCK) &&
-               (CIFS_I(inode)->clientCanCacheAll)))
+       if (((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
+           ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode))))
                return generic_setlease(file, arg, lease);
        else if (tlink_tcon(cfile->tlink)->local_lease &&
-                !CIFS_I(inode)->clientCanCacheRead)
-               /* If the server claims to support oplock on this
-                  file, then we still need to check oplock even
-                  if the local_lease mount option is set, but there
-                  are servers which do not support oplock for which
-                  this mount option may be useful if the user
-                  knows that the file won't be changed on the server
-                  by anyone else */
+                !CIFS_CACHE_READ(CIFS_I(inode)))
+               /*
+                * If the server claims to support oplock on this file, then we
+                * still need to check oplock even if the local_lease mount
+                * option is set, but there are servers which do not support
+                * oplock for which this mount option may be useful if the user
+                * knows that the file won't be changed on the server by anyone
+                * else.
+                */
                return generic_setlease(file, arg, lease);
        else
                return -EAGAIN;
index 52ca861ed35e4fe3fbf78ec387ff401fb0e8fb94..cfa14c80ef3b6a76f5a1cfe1de5c8a6878d988e3 100644 (file)
@@ -28,6 +28,7 @@
 #include "cifsacl.h"
 #include <crypto/internal/hash.h>
 #include <linux/scatterlist.h>
+#include <uapi/linux/cifs/cifs_mount.h>
 #ifdef CONFIG_CIFS_SMB2
 #include "smb2pdu.h"
 #endif
 #define MAX_SES_INFO 2
 #define MAX_TCON_INFO 4
 
-#define MAX_TREE_SIZE (2 + MAX_SERVER_SIZE + 1 + MAX_SHARE_SIZE + 1)
-#define MAX_SERVER_SIZE 15
-#define MAX_SHARE_SIZE 80
-#define CIFS_MAX_DOMAINNAME_LEN 256 /* max domain name length */
-#define MAX_USERNAME_SIZE 256  /* reasonable maximum for current servers */
-#define MAX_PASSWORD_SIZE 512  /* max for windows seems to be 256 wide chars */
+#define MAX_TREE_SIZE (2 + CIFS_NI_MAXHOST + 1 + CIFS_MAX_SHARE_LEN + 1)
 
 #define CIFS_MIN_RCV_POOL 4
 
@@ -135,6 +131,7 @@ struct cifs_secmech {
 
 /* per smb session structure/fields */
 struct ntlmssp_auth {
+       bool sesskey_per_smbsess; /* whether session key is per smb session */
        __u32 client_flags; /* sent by client in type 1 ntlmsssp exchange */
        __u32 server_flags; /* sent by server in type 2 ntlmssp exchange */
        unsigned char ciphertext[CIFS_CPHTXT_SIZE]; /* sent to server */
@@ -308,6 +305,9 @@ struct smb_version_operations {
        int (*create_hardlink)(const unsigned int, struct cifs_tcon *,
                               const char *, const char *,
                               struct cifs_sb_info *);
+       /* query symlink target */
+       int (*query_symlink)(const unsigned int, struct cifs_tcon *,
+                            const char *, char **, struct cifs_sb_info *);
        /* open a file for non-posix mounts */
        int (*open)(const unsigned int, struct cifs_open_parms *,
                    __u32 *, FILE_ALL_INFO *);
@@ -361,18 +361,24 @@ struct smb_version_operations {
        /* push brlocks from the cache to the server */
        int (*push_mand_locks)(struct cifsFileInfo *);
        /* get lease key of the inode */
-       void (*get_lease_key)(struct inode *, struct cifs_fid *fid);
+       void (*get_lease_key)(struct inode *, struct cifs_fid *);
        /* set lease key of the inode */
-       void (*set_lease_key)(struct inode *, struct cifs_fid *fid);
+       void (*set_lease_key)(struct inode *, struct cifs_fid *);
        /* generate new lease key */
-       void (*new_lease_key)(struct cifs_fid *fid);
-       /* The next two functions will need to be changed to per smb session */
-       void (*generate_signingkey)(struct TCP_Server_Info *server);
-       int (*calc_signature)(struct smb_rqst *rqst,
-                                  struct TCP_Server_Info *server);
-       int (*query_mf_symlink)(const unsigned char *path, char *pbuf,
-                       unsigned int *pbytes_read, struct cifs_sb_info *cifs_sb,
-                       unsigned int xid);
+       void (*new_lease_key)(struct cifs_fid *);
+       int (*generate_signingkey)(struct cifs_ses *);
+       int (*calc_signature)(struct smb_rqst *, struct TCP_Server_Info *);
+       int (*query_mf_symlink)(const unsigned char *, char *, unsigned int *,
+                               struct cifs_sb_info *, unsigned int);
+       /* if we can do cache read operations */
+       bool (*is_read_op)(__u32);
+       /* set oplock level for the inode */
+       void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int,
+                                bool *);
+       /* create lease context buffer for CREATE request */
+       char * (*create_lease_buf)(u8 *, u8);
+       /* parse lease context buffer and return oplock/epoch info */
+       __u8 (*parse_lease_buf)(void *, unsigned int *);
 };
 
 struct smb_version_values {
@@ -390,9 +396,9 @@ struct smb_version_values {
        unsigned int    cap_unix;
        unsigned int    cap_nt_find;
        unsigned int    cap_large_files;
-       unsigned int    oplock_read;
        __u16           signing_enabled;
        __u16           signing_required;
+       size_t          create_lease_size;
 };
 
 #define HEADER_SIZE(server) (server->vals->header_size)
@@ -548,7 +554,6 @@ struct TCP_Server_Info {
        int timeAdj;  /* Adjust for difference in server time zone in sec */
        __u64 CurrentMid;         /* multiplex id - rotating counter */
        char cryptkey[CIFS_CRYPTO_KEY_SIZE]; /* used by ntlm, ntlmv2 etc */
-       char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
        /* 16th byte of RFC1001 workstation name is always null */
        char workstation_RFC1001_name[RFC1001_NAME_LEN_WITH_NULL];
        __u32 sequence_number; /* for signing, protected by srv_mutex */
@@ -731,6 +736,7 @@ struct cifs_ses {
        bool need_reconnect:1; /* connection reset, uid now invalid */
 #ifdef CONFIG_CIFS_SMB2
        __u16 session_flags;
+       char smb3signingkey[SMB3_SIGN_KEY_SIZE]; /* for signing smb3 packets */
 #endif /* CONFIG_CIFS_SMB2 */
 };
 
@@ -935,6 +941,8 @@ struct cifs_fid {
        __u8 lease_key[SMB2_LEASE_KEY_SIZE];    /* lease key for smb2 */
 #endif
        struct cifs_pending_open *pending_open;
+       unsigned int epoch;
+       bool purge_cache;
 };
 
 struct cifs_fid_locks {
@@ -1032,6 +1040,17 @@ cifsFileInfo_get_locked(struct cifsFileInfo *cifs_file)
 struct cifsFileInfo *cifsFileInfo_get(struct cifsFileInfo *cifs_file);
 void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
 
+#define CIFS_CACHE_READ_FLG    1
+#define CIFS_CACHE_HANDLE_FLG  2
+#define CIFS_CACHE_RH_FLG      (CIFS_CACHE_READ_FLG | CIFS_CACHE_HANDLE_FLG)
+#define CIFS_CACHE_WRITE_FLG   4
+#define CIFS_CACHE_RW_FLG      (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)
+#define CIFS_CACHE_RHW_FLG     (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG)
+
+#define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG)
+#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
+#define CIFS_CACHE_WRITE(cinode) (cinode->oplock & CIFS_CACHE_WRITE_FLG)
+
 /*
  * One of these for each file inode
  */
@@ -1043,8 +1062,8 @@ struct cifsInodeInfo {
        /* BB add in lists for dirty pages i.e. write caching info for oplock */
        struct list_head openFileList;
        __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
-       bool clientCanCacheRead;        /* read oplock */
-       bool clientCanCacheAll;         /* read and writebehind oplock */
+       unsigned int oplock;            /* oplock/lease level we have */
+       unsigned int epoch;             /* used to track lease state changes */
        bool delete_pending;            /* DELETE_ON_CLOSE is set */
        bool invalid_mapping;           /* pagecache is invalid */
        unsigned long time;             /* jiffies of last update of inode */
@@ -1502,7 +1521,7 @@ extern mempool_t *cifs_mid_poolp;
 extern struct smb_version_operations smb1_operations;
 extern struct smb_version_values smb1_values;
 #define SMB20_VERSION_STRING   "2.0"
-/*extern struct smb_version_operations smb20_operations; */ /* not needed yet */
+extern struct smb_version_operations smb20_operations;
 extern struct smb_version_values smb20_values;
 #define SMB21_VERSION_STRING   "2.1"
 extern struct smb_version_operations smb21_operations;
index 11ca24a8e054ef11472ba634472e6e8622008305..948676db8e2ea5f65d276535caa087c86792b18c 100644 (file)
@@ -1495,11 +1495,12 @@ struct reparse_data {
        __u32   ReparseTag;
        __u16   ReparseDataLength;
        __u16   Reserved;
-       __u16   AltNameOffset;
-       __u16   AltNameLen;
-       __u16   TargetNameOffset;
-       __u16   TargetNameLen;
-       char    LinkNamesBuf[1];
+       __u16   SubstituteNameOffset;
+       __u16   SubstituteNameLength;
+       __u16   PrintNameOffset;
+       __u16   PrintNameLength;
+       __u32   Flags;
+       char    PathBuffer[0];
 } __attribute__((packed));
 
 struct cifs_quota_data {
index b29a012bed33a24b6ba45b17f95c70303e3e3014..b5ec2a268f560c77424744c55266480f25f3c8bb 100644 (file)
@@ -357,13 +357,9 @@ extern int CIFSSMBUnixQuerySymLink(const unsigned int xid,
                        struct cifs_tcon *tcon,
                        const unsigned char *searchName, char **syminfo,
                        const struct nls_table *nls_codepage);
-#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
-extern int CIFSSMBQueryReparseLinkInfo(const unsigned int xid,
-                       struct cifs_tcon *tcon,
-                       const unsigned char *searchName,
-                       char *symlinkinfo, const int buflen, __u16 fid,
-                       const struct nls_table *nls_codepage);
-#endif /* temporarily unused until cifs_symlink fixed */
+extern int CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
+                              __u16 fid, char **symlinkinfo,
+                              const struct nls_table *nls_codepage);
 extern int CIFSSMBOpen(const unsigned int xid, struct cifs_tcon *tcon,
                        const char *fileName, const int disposition,
                        const int access_flags, const int omode,
@@ -435,7 +431,7 @@ extern int setup_ntlm_response(struct cifs_ses *, const struct nls_table *);
 extern int setup_ntlmv2_rsp(struct cifs_ses *, const struct nls_table *);
 extern void cifs_crypto_shash_release(struct TCP_Server_Info *);
 extern int calc_seckey(struct cifs_ses *);
-extern void generate_smb3signingkey(struct TCP_Server_Info *);
+extern int generate_smb3signingkey(struct cifs_ses *);
 
 #ifdef CONFIG_CIFS_WEAK_PW_HASH
 extern int calc_lanman_hash(const char *password, const char *cryptkey,
index a89c4cb4e6cf64e8cbd92fe6f7ceb6b7e941eca3..a3d74fea16233ef9d4c32a0179b4b96cccb8fa2b 100644 (file)
@@ -3067,7 +3067,6 @@ querySymLinkRetry:
        return rc;
 }
 
-#ifdef CONFIG_CIFS_SYMLINK_EXPERIMENTAL
 /*
  *     Recent Windows versions now create symlinks more frequently
  *     and they use the "reparse point" mechanism below.  We can of course
@@ -3079,18 +3078,22 @@ querySymLinkRetry:
  *     it is not compiled in by default until callers fixed up and more tested.
  */
 int
-CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
-                       const unsigned char *searchName,
-                       char *symlinkinfo, const int buflen, __u16 fid,
-                       const struct nls_table *nls_codepage)
+CIFSSMBQuerySymLink(const unsigned int xid, struct cifs_tcon *tcon,
+                   __u16 fid, char **symlinkinfo,
+                   const struct nls_table *nls_codepage)
 {
        int rc = 0;
        int bytes_returned;
        struct smb_com_transaction_ioctl_req *pSMB;
        struct smb_com_transaction_ioctl_rsp *pSMBr;
+       bool is_unicode;
+       unsigned int sub_len;
+       char *sub_start;
+       struct reparse_data *reparse_buf;
+       __u32 data_offset, data_count;
+       char *end_of_smb;
 
-       cifs_dbg(FYI, "In Windows reparse style QueryLink for path %s\n",
-                searchName);
+       cifs_dbg(FYI, "In Windows reparse style QueryLink for fid %u\n", fid);
        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
@@ -3119,66 +3122,55 @@ CIFSSMBQueryReparseLinkInfo(const unsigned int xid, struct cifs_tcon *tcon,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cifs_dbg(FYI, "Send error in QueryReparseLinkInfo = %d\n", rc);
-       } else {                /* decode response */
-               __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
-               __u32 data_count = le32_to_cpu(pSMBr->DataCount);
-               if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
-                       /* BB also check enough total bytes returned */
-                       rc = -EIO;      /* bad smb */
-                       goto qreparse_out;
-               }
-               if (data_count && (data_count < 2048)) {
-                       char *end_of_smb = 2 /* sizeof byte count */ +
-                              get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
-
-                       struct reparse_data *reparse_buf =
-                                               (struct reparse_data *)
-                                               ((char *)&pSMBr->hdr.Protocol
-                                                                + data_offset);
-                       if ((char *)reparse_buf >= end_of_smb) {
-                               rc = -EIO;
-                               goto qreparse_out;
-                       }
-                       if ((reparse_buf->LinkNamesBuf +
-                               reparse_buf->TargetNameOffset +
-                               reparse_buf->TargetNameLen) > end_of_smb) {
-                               cifs_dbg(FYI, "reparse buf beyond SMB\n");
-                               rc = -EIO;
-                               goto qreparse_out;
-                       }
+               goto qreparse_out;
+       }
 
-                       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
-                               cifs_from_ucs2(symlinkinfo, (__le16 *)
-                                               (reparse_buf->LinkNamesBuf +
-                                               reparse_buf->TargetNameOffset),
-                                               buflen,
-                                               reparse_buf->TargetNameLen,
-                                               nls_codepage, 0);
-                       } else { /* ASCII names */
-                               strncpy(symlinkinfo,
-                                       reparse_buf->LinkNamesBuf +
-                                       reparse_buf->TargetNameOffset,
-                                       min_t(const int, buflen,
-                                          reparse_buf->TargetNameLen));
-                       }
-               } else {
-                       rc = -EIO;
-                       cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
-               }
-               symlinkinfo[buflen] = 0; /* just in case so the caller
-                                       does not go off the end of the buffer */
-               cifs_dbg(FYI, "readlink result - %s\n", symlinkinfo);
+       data_offset = le32_to_cpu(pSMBr->DataOffset);
+       data_count = le32_to_cpu(pSMBr->DataCount);
+       if (get_bcc(&pSMBr->hdr) < 2 || data_offset > 512) {
+               /* BB also check enough total bytes returned */
+               rc = -EIO;      /* bad smb */
+               goto qreparse_out;
+       }
+       if (!data_count || (data_count > 2048)) {
+               rc = -EIO;
+               cifs_dbg(FYI, "Invalid return data count on get reparse info ioctl\n");
+               goto qreparse_out;
+       }
+       end_of_smb = 2 + get_bcc(&pSMBr->hdr) + (char *)&pSMBr->ByteCount;
+       reparse_buf = (struct reparse_data *)
+                               ((char *)&pSMBr->hdr.Protocol + data_offset);
+       if ((char *)reparse_buf >= end_of_smb) {
+               rc = -EIO;
+               goto qreparse_out;
        }
+       if ((reparse_buf->PathBuffer + reparse_buf->PrintNameOffset +
+                               reparse_buf->PrintNameLength) > end_of_smb) {
+               cifs_dbg(FYI, "reparse buf beyond SMB\n");
+               rc = -EIO;
+               goto qreparse_out;
+       }
+       sub_start = reparse_buf->SubstituteNameOffset + reparse_buf->PathBuffer;
+       sub_len = reparse_buf->SubstituteNameLength;
+       if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
+               is_unicode = true;
+       else
+               is_unicode = false;
 
+       /* BB FIXME investigate remapping reserved chars here */
+       *symlinkinfo = cifs_strndup_from_utf16(sub_start, sub_len, is_unicode,
+                                              nls_codepage);
+       if (!*symlinkinfo)
+               rc = -ENOMEM;
 qreparse_out:
        cifs_buf_release(pSMB);
 
-       /* Note: On -EAGAIN error only caller can retry on handle based calls
-               since file handle passed in no longer valid */
-
+       /*
+        * Note: On -EAGAIN error only caller can retry on handle based calls
+        * since file handle passed in no longer valid.
+        */
        return rc;
 }
-#endif /* CIFS_SYMLINK_EXPERIMENTAL */ /* BB temporarily unused */
 
 #ifdef CONFIG_CIFS_POSIX
 
index d67c550c49806254da76ca6f7dd32d29144c3c16..a279ffc0bc29577ed447319467b2e92248f09149 100644 (file)
@@ -379,6 +379,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                try_to_freeze();
 
                /* we should try only the port we connected to before */
+               mutex_lock(&server->srv_mutex);
                rc = generic_ip_connect(server);
                if (rc) {
                        cifs_dbg(FYI, "reconnect error %d\n", rc);
@@ -390,6 +391,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
                                server->tcpStatus = CifsNeedNegotiate;
                        spin_unlock(&GlobalMid_Lock);
                }
+               mutex_unlock(&server->srv_mutex);
        } while (server->tcpStatus == CifsNeedReconnect);
 
        return rc;
@@ -1114,7 +1116,7 @@ cifs_parse_smb_version(char *value, struct smb_vol *vol)
                break;
 #ifdef CONFIG_CIFS_SMB2
        case Smb_20:
-               vol->ops = &smb21_operations; /* currently identical with 2.1 */
+               vol->ops = &smb20_operations;
                vol->vals = &smb20_values;
                break;
        case Smb_21:
@@ -1575,8 +1577,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                        if (string == NULL)
                                goto out_nomem;
 
-                       if (strnlen(string, MAX_USERNAME_SIZE) >
-                                                       MAX_USERNAME_SIZE) {
+                       if (strnlen(string, CIFS_MAX_USERNAME_LEN) >
+                                                       CIFS_MAX_USERNAME_LEN) {
                                printk(KERN_WARNING "CIFS: username too long\n");
                                goto cifs_parse_mount_err;
                        }
@@ -2221,13 +2223,13 @@ static int match_session(struct cifs_ses *ses, struct smb_vol *vol)
                /* anything else takes username/password */
                if (strncmp(ses->user_name,
                            vol->username ? vol->username : "",
-                           MAX_USERNAME_SIZE))
+                           CIFS_MAX_USERNAME_LEN))
                        return 0;
                if (strlen(vol->username) != 0 &&
                    ses->password != NULL &&
                    strncmp(ses->password,
                            vol->password ? vol->password : "",
-                           MAX_PASSWORD_SIZE))
+                           CIFS_MAX_PASSWORD_LEN))
                        return 0;
        }
        return 1;
@@ -2352,7 +2354,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
        }
 
        len = delim - payload;
-       if (len > MAX_USERNAME_SIZE || len <= 0) {
+       if (len > CIFS_MAX_USERNAME_LEN || len <= 0) {
                cifs_dbg(FYI, "Bad value from username search (len=%zd)\n",
                         len);
                rc = -EINVAL;
@@ -2369,7 +2371,7 @@ cifs_set_cifscreds(struct smb_vol *vol, struct cifs_ses *ses)
        cifs_dbg(FYI, "%s: username=%s\n", __func__, vol->username);
 
        len = key->datalen - (len + 1);
-       if (len > MAX_PASSWORD_SIZE || len <= 0) {
+       if (len > CIFS_MAX_PASSWORD_LEN || len <= 0) {
                cifs_dbg(FYI, "Bad len for password search (len=%zd)\n", len);
                rc = -EINVAL;
                kfree(vol->username);
@@ -3826,33 +3828,8 @@ cifs_setup_session(const unsigned int xid, struct cifs_ses *ses,
        if (server->ops->sess_setup)
                rc = server->ops->sess_setup(xid, ses, nls_info);
 
-       if (rc) {
+       if (rc)
                cifs_dbg(VFS, "Send error in SessSetup = %d\n", rc);
-       } else {
-               mutex_lock(&server->srv_mutex);
-               if (!server->session_estab) {
-                       server->session_key.response = ses->auth_key.response;
-                       server->session_key.len = ses->auth_key.len;
-                       server->sequence_number = 0x2;
-                       server->session_estab = true;
-                       ses->auth_key.response = NULL;
-                       if (server->ops->generate_signingkey)
-                               server->ops->generate_signingkey(server);
-               }
-               mutex_unlock(&server->srv_mutex);
-
-               cifs_dbg(FYI, "CIFS Session Established successfully\n");
-               spin_lock(&GlobalMid_Lock);
-               ses->status = CifsGood;
-               ses->need_reconnect = false;
-               spin_unlock(&GlobalMid_Lock);
-       }
-
-       kfree(ses->auth_key.response);
-       ses->auth_key.response = NULL;
-       ses->auth_key.len = 0;
-       kfree(ses->ntlmssp);
-       ses->ntlmssp = NULL;
 
        return rc;
 }
index d62ce0d4814173645f9bbd2da0b0553b527a98b2..5384c2a640ca6fc06962a01261ca4f8ce890b246 100644 (file)
@@ -32,6 +32,7 @@
 #include "cifsproto.h"
 #include "cifs_debug.h"
 #include "cifs_fs_sb.h"
+#include "cifs_unicode.h"
 
 static void
 renew_parental_timestamps(struct dentry *direntry)
@@ -499,6 +500,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
                if (server->ops->close)
                        server->ops->close(xid, tcon, &fid);
                cifs_del_pending_open(&open);
+               fput(file);
                rc = -ENOMEM;
        }
 
@@ -834,12 +836,17 @@ static int cifs_ci_hash(const struct dentry *dentry, struct qstr *q)
 {
        struct nls_table *codepage = CIFS_SB(dentry->d_sb)->local_nls;
        unsigned long hash;
-       int i;
+       wchar_t c;
+       int i, charlen;
 
        hash = init_name_hash();
-       for (i = 0; i < q->len; i++)
-               hash = partial_name_hash(nls_tolower(codepage, q->name[i]),
-                                        hash);
+       for (i = 0; i < q->len; i += charlen) {
+               charlen = codepage->char2uni(&q->name[i], q->len - i, &c);
+               /* error out if we can't convert the character */
+               if (unlikely(charlen < 0))
+                       return charlen;
+               hash = partial_name_hash(cifs_toupper(c), hash);
+       }
        q->hash = end_name_hash(hash);
 
        return 0;
@@ -849,11 +856,47 @@ static int cifs_ci_compare(const struct dentry *parent, const struct dentry *den
                unsigned int len, const char *str, const struct qstr *name)
 {
        struct nls_table *codepage = CIFS_SB(parent->d_sb)->local_nls;
+       wchar_t c1, c2;
+       int i, l1, l2;
 
-       if ((name->len == len) &&
-           (nls_strnicmp(codepage, name->name, str, len) == 0))
-               return 0;
-       return 1;
+       /*
+        * We make the assumption here that uppercase characters in the local
+        * codepage are always the same length as their lowercase counterparts.
+        *
+        * If that's ever not the case, then this will fail to match it.
+        */
+       if (name->len != len)
+               return 1;
+
+       for (i = 0; i < len; i += l1) {
+               /* Convert characters in both strings to UTF-16. */
+               l1 = codepage->char2uni(&str[i], len - i, &c1);
+               l2 = codepage->char2uni(&name->name[i], name->len - i, &c2);
+
+               /*
+                * If we can't convert either character, just declare it to
+                * be 1 byte long and compare the original byte.
+                */
+               if (unlikely(l1 < 0 && l2 < 0)) {
+                       if (str[i] != name->name[i])
+                               return 1;
+                       l1 = 1;
+                       continue;
+               }
+
+               /*
+                * Here, we again ass|u|me that upper/lowercase versions of
+                * a character are the same length in the local NLS.
+                */
+               if (l1 != l2)
+                       return 1;
+
+               /* Now compare uppercase versions of these characters */
+               if (cifs_toupper(c1) != cifs_toupper(c2))
+                       return 1;
+       }
+
+       return 0;
 }
 
 const struct dentry_operations cifs_ci_dentry_ops = {
index 9d0dd952ad7954ae3dcbfaeb5a953a0e0b13a99e..eb955b525e55307a18c1b534e95e5bfbe8462764 100644 (file)
@@ -313,8 +313,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
         * If the server returned a read oplock and we have mandatory brlocks,
         * set oplock level to None.
         */
-       if (oplock == server->vals->oplock_read &&
-                                               cifs_has_mand_locks(cinode)) {
+       if (server->ops->is_read_op(oplock) && cifs_has_mand_locks(cinode)) {
                cifs_dbg(FYI, "Reset oplock val from read to None due to mand locks\n");
                oplock = 0;
        }
@@ -324,6 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
                oplock = fid->pending_open->oplock;
        list_del(&fid->pending_open->olist);
 
+       fid->purge_cache = false;
        server->ops->set_fid(cfile, fid, oplock);
 
        list_add(&cfile->tlist, &tcon->openFileList);
@@ -334,6 +334,9 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
                list_add_tail(&cfile->flist, &cinode->openFileList);
        spin_unlock(&cifs_file_list_lock);
 
+       if (fid->purge_cache)
+               cifs_invalidate_mapping(inode);
+
        file->private_data = cfile;
        return cfile;
 }
@@ -1524,12 +1527,12 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type,
                 * read won't conflict with non-overlapted locks due to
                 * pagereading.
                 */
-               if (!CIFS_I(inode)->clientCanCacheAll &&
-                                       CIFS_I(inode)->clientCanCacheRead) {
+               if (!CIFS_CACHE_WRITE(CIFS_I(inode)) &&
+                                       CIFS_CACHE_READ(CIFS_I(inode))) {
                        cifs_invalidate_mapping(inode);
                        cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n",
                                 inode);
-                       CIFS_I(inode)->clientCanCacheRead = false;
+                       CIFS_I(inode)->oplock = 0;
                }
 
                rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length,
@@ -2213,7 +2216,7 @@ int cifs_strict_fsync(struct file *file, loff_t start, loff_t end,
        cifs_dbg(FYI, "Sync file - name: %s datasync: 0x%x\n",
                 file->f_path.dentry->d_name.name, datasync);
 
-       if (!CIFS_I(inode)->clientCanCacheRead) {
+       if (!CIFS_CACHE_READ(CIFS_I(inode))) {
                rc = cifs_invalidate_mapping(inode);
                if (rc) {
                        cifs_dbg(FYI, "rc: %d during invalidate phase\n", rc);
@@ -2577,7 +2580,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        ssize_t written;
 
-       if (cinode->clientCanCacheAll) {
+       if (CIFS_CACHE_WRITE(cinode)) {
                if (cap_unix(tcon->ses) &&
                (CIFS_UNIX_FCNTL_CAP & le64_to_cpu(tcon->fsUnixInfo.Capability))
                    && ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NOPOSIXBRL) == 0))
@@ -2591,7 +2594,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
         * these pages but not on the region from pos to ppos+len-1.
         */
        written = cifs_user_writev(iocb, iov, nr_segs, pos);
-       if (written > 0 && cinode->clientCanCacheRead) {
+       if (written > 0 && CIFS_CACHE_READ(cinode)) {
                /*
                 * Windows 7 server can delay breaking level2 oplock if a write
                 * request comes - break it on the client to prevent reading
@@ -2600,7 +2603,7 @@ cifs_strict_writev(struct kiocb *iocb, const struct iovec *iov,
                cifs_invalidate_mapping(inode);
                cifs_dbg(FYI, "Set no oplock for inode=%p after a write operation\n",
                         inode);
-               cinode->clientCanCacheRead = false;
+               cinode->oplock = 0;
        }
        return written;
 }
@@ -2957,7 +2960,7 @@ cifs_strict_readv(struct kiocb *iocb, const struct iovec *iov,
         * on pages affected by this read but not on the region from pos to
         * pos+len-1.
         */
-       if (!cinode->clientCanCacheRead)
+       if (!CIFS_CACHE_READ(cinode))
                return cifs_user_readv(iocb, iov, nr_segs, pos);
 
        if (cap_unix(tcon->ses) &&
@@ -3093,7 +3096,7 @@ int cifs_file_strict_mmap(struct file *file, struct vm_area_struct *vma)
 
        xid = get_xid();
 
-       if (!CIFS_I(inode)->clientCanCacheRead) {
+       if (!CIFS_CACHE_READ(CIFS_I(inode))) {
                rc = cifs_invalidate_mapping(inode);
                if (rc)
                        return rc;
@@ -3376,6 +3379,9 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
        return rc;
 }
 
+/*
+ * cifs_readpage_worker must be called with the page pinned
+ */
 static int cifs_readpage_worker(struct file *file, struct page *page,
        loff_t *poffset)
 {
@@ -3387,7 +3393,6 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
        if (rc == 0)
                goto read_complete;
 
-       page_cache_get(page);
        read_data = kmap(page);
        /* for reads over a certain size could initiate async read ahead */
 
@@ -3414,7 +3419,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page,
 
 io_error:
        kunmap(page);
-       page_cache_release(page);
+       unlock_page(page);
 
 read_complete:
        return rc;
@@ -3439,8 +3444,6 @@ static int cifs_readpage(struct file *file, struct page *page)
 
        rc = cifs_readpage_worker(file, page, &offset);
 
-       unlock_page(page);
-
        free_xid(xid);
        return rc;
 }
@@ -3494,6 +3497,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,
                        loff_t pos, unsigned len, unsigned flags,
                        struct page **pagep, void **fsdata)
 {
+       int oncethru = 0;
        pgoff_t index = pos >> PAGE_CACHE_SHIFT;
        loff_t offset = pos & (PAGE_CACHE_SIZE - 1);
        loff_t page_start = pos & PAGE_MASK;
@@ -3503,6 +3507,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,
 
        cifs_dbg(FYI, "write_begin from %lld len %d\n", (long long)pos, len);
 
+start:
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page) {
                rc = -ENOMEM;
@@ -3526,7 +3531,7 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,
         * is, when the page lies beyond the EOF, or straddles the EOF
         * and the write will cover all of the existing data.
         */
-       if (CIFS_I(mapping->host)->clientCanCacheRead) {
+       if (CIFS_CACHE_READ(CIFS_I(mapping->host))) {
                i_size = i_size_read(mapping->host);
                if (page_start >= i_size ||
                    (offset == 0 && (pos + len) >= i_size)) {
@@ -3544,13 +3549,16 @@ static int cifs_write_begin(struct file *file, struct address_space *mapping,
                }
        }
 
-       if ((file->f_flags & O_ACCMODE) != O_WRONLY) {
+       if ((file->f_flags & O_ACCMODE) != O_WRONLY && !oncethru) {
                /*
                 * might as well read a page, it is fast enough. If we get
                 * an error, we don't need to return it. cifs_write_end will
                 * do a sync write instead since PG_uptodate isn't set.
                 */
                cifs_readpage_worker(file, page, &page_start);
+               page_cache_release(page);
+               oncethru = 1;
+               goto start;
        } else {
                /* we could try using another file handle if there is one -
                   but how would we lock it to prevent close of that handle
@@ -3609,20 +3617,20 @@ void cifs_oplock_break(struct work_struct *work)
        struct cifs_tcon *tcon = tlink_tcon(cfile->tlink);
        int rc = 0;
 
-       if (!cinode->clientCanCacheAll && cinode->clientCanCacheRead &&
+       if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) &&
                                                cifs_has_mand_locks(cinode)) {
                cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n",
                         inode);
-               cinode->clientCanCacheRead = false;
+               cinode->oplock = 0;
        }
 
        if (inode && S_ISREG(inode->i_mode)) {
-               if (cinode->clientCanCacheRead)
+               if (CIFS_CACHE_READ(cinode))
                        break_lease(inode, O_RDONLY);
                else
                        break_lease(inode, O_WRONLY);
                rc = filemap_fdatawrite(inode->i_mapping);
-               if (cinode->clientCanCacheRead == 0) {
+               if (!CIFS_CACHE_READ(cinode)) {
                        rc = filemap_fdatawait(inode->i_mapping);
                        mapping_set_error(inode->i_mapping, rc);
                        cifs_invalidate_mapping(inode);
index 449b6cf09b09dbc15e90f311e09bc011a0157b44..f9ff9c173f78ad6a8abcc6afb56849109dbfd515 100644 (file)
@@ -101,7 +101,7 @@ cifs_revalidate_cache(struct inode *inode, struct cifs_fattr *fattr)
        }
 
        /* don't bother with revalidation if we have an oplock */
-       if (cifs_i->clientCanCacheRead) {
+       if (CIFS_CACHE_READ(cifs_i)) {
                cifs_dbg(FYI, "%s: inode %llu is oplocked\n",
                         __func__, cifs_i->uniqueid);
                return;
@@ -549,6 +549,10 @@ cifs_all_info_to_fattr(struct cifs_fattr *fattr, FILE_ALL_INFO *info,
                 * when Unix extensions are disabled - fake it.
                 */
                fattr->cf_nlink = 2;
+       } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
+               fattr->cf_mode = S_IFLNK;
+               fattr->cf_dtype = DT_LNK;
+               fattr->cf_nlink = le32_to_cpu(info->NumberOfLinks);
        } else {
                fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
                fattr->cf_dtype = DT_REG;
@@ -646,7 +650,7 @@ cifs_get_inode_info(struct inode **inode, const char *full_path,
        cifs_dbg(FYI, "Getting info on %s\n", full_path);
 
        if ((data == NULL) && (*inode != NULL)) {
-               if (CIFS_I(*inode)->clientCanCacheRead) {
+               if (CIFS_CACHE_READ(CIFS_I(*inode))) {
                        cifs_dbg(FYI, "No need to revalidate cached inode sizes\n");
                        goto cgii_exit;
                }
@@ -1657,7 +1661,7 @@ cifs_inode_needs_reval(struct inode *inode)
        struct cifsInodeInfo *cifs_i = CIFS_I(inode);
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
 
-       if (cifs_i->clientCanCacheRead)
+       if (CIFS_CACHE_READ(cifs_i))
                return false;
 
        if (!lookupCacheEnabled)
@@ -1800,7 +1804,7 @@ int cifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
         * We need to be sure that all dirty pages are written and the server
         * has actual ctime, mtime and file length.
         */
-       if (!CIFS_I(inode)->clientCanCacheRead && inode->i_mapping &&
+       if (!CIFS_CACHE_READ(CIFS_I(inode)) && inode->i_mapping &&
            inode->i_mapping->nrpages != 0) {
                rc = filemap_fdatawait(inode->i_mapping);
                if (rc) {
@@ -1852,14 +1856,11 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from)
 
 static void cifs_setsize(struct inode *inode, loff_t offset)
 {
-       loff_t oldsize;
-
        spin_lock(&inode->i_lock);
-       oldsize = inode->i_size;
        i_size_write(inode, offset);
        spin_unlock(&inode->i_lock);
 
-       truncate_pagecache(inode, oldsize, offset);
+       truncate_pagecache(inode, offset);
 }
 
 static int
index 562044f700e56bf27997bf7ef7490bddf6bc1c91..7e36ceba0c7a72d797a798de500847d4fa6ac66d 100644 (file)
@@ -509,6 +509,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
        struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
        struct tcon_link *tlink = NULL;
        struct cifs_tcon *tcon;
+       struct TCP_Server_Info *server;
 
        xid = get_xid();
 
@@ -519,25 +520,7 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
                goto out;
        }
        tcon = tlink_tcon(tlink);
-
-       /*
-        * For now, we just handle symlinks with unix extensions enabled.
-        * Eventually we should handle NTFS reparse points, and MacOS
-        * symlink support. For instance...
-        *
-        * rc = CIFSSMBQueryReparseLinkInfo(...)
-        *
-        * For now, just return -EACCES when the server doesn't support posix
-        * extensions. Note that we still allow querying symlinks when posix
-        * extensions are manually disabled. We could disable these as well
-        * but there doesn't seem to be any harm in allowing the client to
-        * read them.
-        */
-       if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MF_SYMLINKS) &&
-           !cap_unix(tcon->ses)) {
-               rc = -EACCES;
-               goto out;
-       }
+       server = tcon->ses->server;
 
        full_path = build_path_from_dentry(direntry);
        if (!full_path)
@@ -559,6 +542,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
        if ((rc != 0) && cap_unix(tcon->ses))
                rc = CIFSSMBUnixQuerySymLink(xid, tcon, full_path, &target_path,
                                             cifs_sb->local_nls);
+       else if (rc != 0 && server->ops->query_symlink)
+               rc = server->ops->query_symlink(xid, tcon, full_path,
+                                               &target_path, cifs_sb);
 
        kfree(full_path);
 out:
index f7d4b2285efea06fee58d52b94e72a332412cb1a..138a011633fe8ae4feabb965530c99eda25e1226 100644 (file)
@@ -105,6 +105,7 @@ sesInfoFree(struct cifs_ses *buf_to_free)
        }
        kfree(buf_to_free->user_name);
        kfree(buf_to_free->domainName);
+       kfree(buf_to_free->auth_key.response);
        kfree(buf_to_free);
 }
 
@@ -545,19 +546,15 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
        oplock &= 0xF;
 
        if (oplock == OPLOCK_EXCLUSIVE) {
-               cinode->clientCanCacheAll = true;
-               cinode->clientCanCacheRead = true;
+               cinode->oplock = CIFS_CACHE_WRITE_FLG | CIFS_CACHE_READ_FLG;
                cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
                         &cinode->vfs_inode);
        } else if (oplock == OPLOCK_READ) {
-               cinode->clientCanCacheAll = false;
-               cinode->clientCanCacheRead = true;
+               cinode->oplock = CIFS_CACHE_READ_FLG;
                cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
                         &cinode->vfs_inode);
-       } else {
-               cinode->clientCanCacheAll = false;
-               cinode->clientCanCacheRead = false;
-       }
+       } else
+               cinode->oplock = 0;
 }
 
 bool
index 69d2c826a23badc552bb686b518beaea297b473c..42ef03be089f2bc9aaabd2e3f40d2b6d6ac207a8 100644 (file)
@@ -172,6 +172,9 @@ cifs_fill_common_info(struct cifs_fattr *fattr, struct cifs_sb_info *cifs_sb)
                if (cifs_dfs_is_possible(cifs_sb) &&
                    (fattr->cf_cifsattrs & ATTR_REPARSE))
                        fattr->cf_flags |= CIFS_FATTR_NEED_REVAL;
+       } else if (fattr->cf_cifsattrs & ATTR_REPARSE) {
+               fattr->cf_mode = S_IFLNK;
+               fattr->cf_dtype = DT_LNK;
        } else {
                fattr->cf_mode = S_IFREG | cifs_sb->mnt_file_mode;
                fattr->cf_dtype = DT_REG;
index 08dd37bb23aac8ea04fe979743f8c963990a80f7..5f99b7f19e7870d72aa6f1945550c41ca34e173d 100644 (file)
@@ -226,7 +226,7 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
                *(bcc_ptr+1) = 0;
        } else {
                bytes_ret = cifs_strtoUTF16((__le16 *) bcc_ptr, ses->user_name,
-                                           MAX_USERNAME_SIZE, nls_cp);
+                                           CIFS_MAX_USERNAME_LEN, nls_cp);
        }
        bcc_ptr += 2 * bytes_ret;
        bcc_ptr += 2; /* account for null termination */
@@ -246,8 +246,8 @@ static void ascii_ssetup_strings(char **pbcc_area, struct cifs_ses *ses,
        /* BB what about null user mounts - check that we do this BB */
        /* copy user */
        if (ses->user_name != NULL) {
-               strncpy(bcc_ptr, ses->user_name, MAX_USERNAME_SIZE);
-               bcc_ptr += strnlen(ses->user_name, MAX_USERNAME_SIZE);
+               strncpy(bcc_ptr, ses->user_name, CIFS_MAX_USERNAME_LEN);
+               bcc_ptr += strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN);
        }
        /* else null user mount */
        *bcc_ptr = 0;
@@ -428,7 +428,8 @@ void build_ntlmssp_negotiate_blob(unsigned char *pbuffer,
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
        if (ses->server->sign) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
-               if (!ses->server->session_estab)
+               if (!ses->server->session_estab ||
+                               ses->ntlmssp->sesskey_per_smbsess)
                        flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
        }
 
@@ -466,7 +467,8 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
                NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC;
        if (ses->server->sign) {
                flags |= NTLMSSP_NEGOTIATE_SIGN;
-               if (!ses->server->session_estab)
+               if (!ses->server->session_estab ||
+                               ses->ntlmssp->sesskey_per_smbsess)
                        flags |= NTLMSSP_NEGOTIATE_KEY_XCH;
        }
 
@@ -501,7 +503,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
        } else {
                int len;
                len = cifs_strtoUTF16((__le16 *)tmp, ses->domainName,
-                                     MAX_USERNAME_SIZE, nls_cp);
+                                     CIFS_MAX_USERNAME_LEN, nls_cp);
                len *= 2; /* unicode is 2 bytes each */
                sec_blob->DomainName.BufferOffset = cpu_to_le32(tmp - pbuffer);
                sec_blob->DomainName.Length = cpu_to_le16(len);
@@ -517,7 +519,7 @@ int build_ntlmssp_auth_blob(unsigned char *pbuffer,
        } else {
                int len;
                len = cifs_strtoUTF16((__le16 *)tmp, ses->user_name,
-                                     MAX_USERNAME_SIZE, nls_cp);
+                                     CIFS_MAX_USERNAME_LEN, nls_cp);
                len *= 2; /* unicode is 2 bytes each */
                sec_blob->UserName.BufferOffset = cpu_to_le32(tmp - pbuffer);
                sec_blob->UserName.Length = cpu_to_le16(len);
@@ -629,7 +631,8 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
        type = select_sectype(ses->server, ses->sectype);
        cifs_dbg(FYI, "sess setup type %d\n", type);
        if (type == Unspecified) {
-               cifs_dbg(VFS, "Unable to select appropriate authentication method!");
+               cifs_dbg(VFS,
+                       "Unable to select appropriate authentication method!");
                return -EINVAL;
        }
 
@@ -640,6 +643,8 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
                ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
                if (!ses->ntlmssp)
                        return -ENOMEM;
+               ses->ntlmssp->sesskey_per_smbsess = false;
+
        }
 
 ssetup_ntlmssp_authenticate:
@@ -815,8 +820,9 @@ ssetup_ntlmssp_authenticate:
                ses->auth_key.response = kmemdup(msg->data, msg->sesskey_len,
                                                 GFP_KERNEL);
                if (!ses->auth_key.response) {
-                       cifs_dbg(VFS, "Kerberos can't allocate (%u bytes) memory",
-                                       msg->sesskey_len);
+                       cifs_dbg(VFS,
+                               "Kerberos can't allocate (%u bytes) memory",
+                               msg->sesskey_len);
                        rc = -ENOMEM;
                        goto ssetup_exit;
                }
@@ -1005,5 +1011,37 @@ ssetup_exit:
        if ((phase == NtLmChallenge) && (rc == 0))
                goto ssetup_ntlmssp_authenticate;
 
+       if (!rc) {
+               mutex_lock(&ses->server->srv_mutex);
+               if (!ses->server->session_estab) {
+                       if (ses->server->sign) {
+                               ses->server->session_key.response =
+                                       kmemdup(ses->auth_key.response,
+                                       ses->auth_key.len, GFP_KERNEL);
+                               if (!ses->server->session_key.response) {
+                                       rc = -ENOMEM;
+                                       mutex_unlock(&ses->server->srv_mutex);
+                                       goto keycp_exit;
+                               }
+                               ses->server->session_key.len =
+                                                       ses->auth_key.len;
+                       }
+                       ses->server->sequence_number = 0x2;
+                       ses->server->session_estab = true;
+               }
+               mutex_unlock(&ses->server->srv_mutex);
+
+               cifs_dbg(FYI, "CIFS session established successfully\n");
+               spin_lock(&GlobalMid_Lock);
+               ses->status = CifsGood;
+               ses->need_reconnect = false;
+               spin_unlock(&GlobalMid_Lock);
+       }
+
+keycp_exit:
+       kfree(ses->auth_key.response);
+       ses->auth_key.response = NULL;
+       kfree(ses->ntlmssp);
+
        return rc;
 }
index 60943978aec35bb06360adb7e060802d5775bee1..8233b174de3d62c6e5a3223919e83db8f7c57016 100644 (file)
@@ -700,7 +700,7 @@ cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
        struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
        cfile->fid.netfid = fid->netfid;
        cifs_set_oplock_level(cinode, oplock);
-       cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+       cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
 }
 
 static void
@@ -837,7 +837,7 @@ cifs_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
 {
        return CIFSSMBLock(0, tcon, fid->netfid, current->tgid, 0, 0, 0, 0,
                           LOCKING_ANDX_OPLOCK_RELEASE, false,
-                          cinode->clientCanCacheRead ? 1 : 0);
+                          CIFS_CACHE_READ(cinode) ? 1 : 0);
 }
 
 static int
@@ -881,6 +881,43 @@ cifs_mand_lock(const unsigned int xid, struct cifsFileInfo *cfile, __u64 offset,
                           (__u8)type, wait, 0);
 }
 
+static int
+cifs_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
+                  const char *full_path, char **target_path,
+                  struct cifs_sb_info *cifs_sb)
+{
+       int rc;
+       int oplock = 0;
+       __u16 netfid;
+
+       cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
+
+       rc = CIFSSMBOpen(xid, tcon, full_path, FILE_OPEN,
+                        FILE_READ_ATTRIBUTES, OPEN_REPARSE_POINT, &netfid,
+                        &oplock, NULL, cifs_sb->local_nls,
+                        cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc)
+               return rc;
+
+       rc = CIFSSMBQuerySymLink(xid, tcon, netfid, target_path,
+                                cifs_sb->local_nls);
+       if (rc) {
+               CIFSSMBClose(xid, tcon, netfid);
+               return rc;
+       }
+
+       convert_delimiter(*target_path, '/');
+       CIFSSMBClose(xid, tcon, netfid);
+       cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
+       return rc;
+}
+
+static bool
+cifs_is_read_op(__u32 oplock)
+{
+       return oplock == OPLOCK_READ;
+}
+
 struct smb_version_operations smb1_operations = {
        .send_cancel = send_nt_cancel,
        .compare_fids = cifs_compare_fids,
@@ -927,6 +964,7 @@ struct smb_version_operations smb1_operations = {
        .rename_pending_delete = cifs_rename_pending_delete,
        .rename = CIFSSMBRename,
        .create_hardlink = CIFSCreateHardLink,
+       .query_symlink = cifs_query_symlink,
        .open = cifs_open_file,
        .set_fid = cifs_set_fid,
        .close = cifs_close_file,
@@ -945,6 +983,7 @@ struct smb_version_operations smb1_operations = {
        .mand_unlock_range = cifs_unlock_range,
        .push_mand_locks = cifs_push_mandatory_locks,
        .query_mf_symlink = open_query_close_cifs_symlink,
+       .is_read_op = cifs_is_read_op,
 };
 
 struct smb_version_values smb1_values = {
@@ -960,7 +999,6 @@ struct smb_version_values smb1_values = {
        .cap_unix = CAP_UNIX,
        .cap_nt_find = CAP_NT_SMBS | CAP_NT_FIND,
        .cap_large_files = CAP_LARGE_FILES,
-       .oplock_read = OPLOCK_READ,
        .signing_enabled = SECMODE_SIGN_ENABLED,
        .signing_required = SECMODE_SIGN_REQUIRED,
 };
index 04a81a4142c3235f1bb1693b9be4c73580023c2b..3f17b455083141c572fac5d88e95e56fbe54f89a 100644 (file)
 #include "fscache.h"
 #include "smb2proto.h"
 
-void
-smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
-{
-       oplock &= 0xFF;
-       if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
-               return;
-       if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
-           oplock == SMB2_OPLOCK_LEVEL_BATCH) {
-               cinode->clientCanCacheAll = true;
-               cinode->clientCanCacheRead = true;
-               cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
-                        &cinode->vfs_inode);
-       } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
-               cinode->clientCanCacheAll = false;
-               cinode->clientCanCacheRead = true;
-               cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
-                        &cinode->vfs_inode);
-       } else {
-               cinode->clientCanCacheAll = false;
-               cinode->clientCanCacheRead = false;
-       }
-}
-
 int
 smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
               __u32 *oplock, FILE_ALL_INFO *buf)
@@ -86,7 +63,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
        if (oparms->tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING)
                memcpy(smb2_oplock + 1, fid->lease_key, SMB2_LEASE_KEY_SIZE);
 
-       rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data);
+       rc = SMB2_open(xid, oparms, smb2_path, smb2_oplock, smb2_data, NULL);
        if (rc)
                goto out;
 
index c6ec1633309abad6464995e4aad8352129f5fed6..78ff88c467b99b9a17c706032a9ed655f92c58b0 100644 (file)
@@ -60,7 +60,7 @@ smb2_open_op_close(const unsigned int xid, struct cifs_tcon *tcon,
        oparms.fid = &fid;
        oparms.reconnect = false;
 
-       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
@@ -136,7 +136,8 @@ smb2_query_path_info(const unsigned int xid, struct cifs_tcon *tcon,
                return -ENOMEM;
 
        rc = smb2_open_op_close(xid, tcon, cifs_sb, full_path,
-                               FILE_READ_ATTRIBUTES, FILE_OPEN, 0, smb2_data,
+                               FILE_READ_ATTRIBUTES, FILE_OPEN,
+                               OPEN_REPARSE_POINT, smb2_data,
                                SMB2_OP_QUERY_INFO);
        if (rc)
                goto out;
@@ -191,8 +192,8 @@ smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
            struct cifs_sb_info *cifs_sb)
 {
        return smb2_open_op_close(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
-                                 CREATE_DELETE_ON_CLOSE, NULL,
-                                 SMB2_OP_DELETE);
+                                 CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
+                                 NULL, SMB2_OP_DELETE);
 }
 
 static int
index b0c43345cd981c082e3de5965e647a5432197605..fb3966265b6ef6b1e40095ad8008e647d3569939 100644 (file)
@@ -171,6 +171,10 @@ smb2_check_message(char *buf, unsigned int length)
        if (4 + len != clc_len) {
                cifs_dbg(FYI, "Calculated size %u length %u mismatch mid %llu\n",
                         clc_len, 4 + len, mid);
+               /* create failed on symlink */
+               if (command == SMB2_CREATE_HE &&
+                   hdr->Status == STATUS_STOPPED_ON_SYMLINK)
+                       return 0;
                /* Windows 7 server returns 24 bytes more */
                if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
                        return 0;
@@ -376,23 +380,15 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
 __le32
 smb2_get_lease_state(struct cifsInodeInfo *cinode)
 {
-       if (cinode->clientCanCacheAll)
-               return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING;
-       else if (cinode->clientCanCacheRead)
-               return SMB2_LEASE_READ_CACHING;
-       return 0;
-}
-
-__u8 smb2_map_lease_to_oplock(__le32 lease_state)
-{
-       if (lease_state & SMB2_LEASE_WRITE_CACHING) {
-               if (lease_state & SMB2_LEASE_HANDLE_CACHING)
-                       return SMB2_OPLOCK_LEVEL_BATCH;
-               else
-                       return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
-       } else if (lease_state & SMB2_LEASE_READ_CACHING)
-               return SMB2_OPLOCK_LEVEL_II;
-       return 0;
+       __le32 lease = 0;
+
+       if (CIFS_CACHE_WRITE(cinode))
+               lease |= SMB2_LEASE_WRITE_CACHING;
+       if (CIFS_CACHE_HANDLE(cinode))
+               lease |= SMB2_LEASE_HANDLE_CACHING;
+       if (CIFS_CACHE_READ(cinode))
+               lease |= SMB2_LEASE_READ_CACHING;
+       return lease;
 }
 
 struct smb2_lease_break_work {
@@ -417,96 +413,109 @@ cifs_ses_oplock_break(struct work_struct *work)
 }
 
 static bool
-smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
+smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
+                   struct smb2_lease_break_work *lw)
 {
-       struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer;
-       struct list_head *tmp, *tmp1, *tmp2;
-       struct cifs_ses *ses;
-       struct cifs_tcon *tcon;
-       struct cifsInodeInfo *cinode;
+       bool found;
+       __u8 lease_state;
+       struct list_head *tmp;
        struct cifsFileInfo *cfile;
+       struct TCP_Server_Info *server = tcon->ses->server;
        struct cifs_pending_open *open;
-       struct smb2_lease_break_work *lw;
-       bool found;
+       struct cifsInodeInfo *cinode;
        int ack_req = le32_to_cpu(rsp->Flags &
                                  SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED);
 
-       lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
-       if (!lw)
-               return false;
+       lease_state = le32_to_cpu(rsp->NewLeaseState);
 
-       INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
-       lw->lease_state = rsp->NewLeaseState;
+       list_for_each(tmp, &tcon->openFileList) {
+               cfile = list_entry(tmp, struct cifsFileInfo, tlist);
+               cinode = CIFS_I(cfile->dentry->d_inode);
 
-       cifs_dbg(FYI, "Checking for lease break\n");
+               if (memcmp(cinode->lease_key, rsp->LeaseKey,
+                                                       SMB2_LEASE_KEY_SIZE))
+                       continue;
 
-       /* look up tcon based on tid & uid */
-       spin_lock(&cifs_tcp_ses_lock);
-       list_for_each(tmp, &server->smb_ses_list) {
-               ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
+               cifs_dbg(FYI, "found in the open list\n");
+               cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
+                        le32_to_cpu(rsp->NewLeaseState));
 
-               spin_lock(&cifs_file_list_lock);
-               list_for_each(tmp1, &ses->tcon_list) {
-                       tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
+               server->ops->set_oplock_level(cinode, lease_state, 0, NULL);
 
-                       cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
-                       list_for_each(tmp2, &tcon->openFileList) {
-                               cfile = list_entry(tmp2, struct cifsFileInfo,
-                                                  tlist);
-                               cinode = CIFS_I(cfile->dentry->d_inode);
+               if (ack_req)
+                       cfile->oplock_break_cancelled = false;
+               else
+                       cfile->oplock_break_cancelled = true;
 
-                               if (memcmp(cinode->lease_key, rsp->LeaseKey,
-                                          SMB2_LEASE_KEY_SIZE))
-                                       continue;
+               queue_work(cifsiod_wq, &cfile->oplock_break);
+               kfree(lw);
+               return true;
+       }
 
-                               cifs_dbg(FYI, "found in the open list\n");
-                               cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
-                                        le32_to_cpu(rsp->NewLeaseState));
+       found = false;
+       list_for_each_entry(open, &tcon->pending_opens, olist) {
+               if (memcmp(open->lease_key, rsp->LeaseKey,
+                          SMB2_LEASE_KEY_SIZE))
+                       continue;
+
+               if (!found && ack_req) {
+                       found = true;
+                       memcpy(lw->lease_key, open->lease_key,
+                              SMB2_LEASE_KEY_SIZE);
+                       lw->tlink = cifs_get_tlink(open->tlink);
+                       queue_work(cifsiod_wq, &lw->lease_break);
+               }
 
-                               smb2_set_oplock_level(cinode,
-                                 smb2_map_lease_to_oplock(rsp->NewLeaseState));
+               cifs_dbg(FYI, "found in the pending open list\n");
+               cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
+                        le32_to_cpu(rsp->NewLeaseState));
 
-                               if (ack_req)
-                                       cfile->oplock_break_cancelled = false;
-                               else
-                                       cfile->oplock_break_cancelled = true;
+               open->oplock = lease_state;
+       }
+       return found;
+}
 
-                               queue_work(cifsiod_wq, &cfile->oplock_break);
+static bool
+smb2_is_valid_lease_break(char *buffer)
+{
+       struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer;
+       struct list_head *tmp, *tmp1, *tmp2;
+       struct TCP_Server_Info *server;
+       struct cifs_ses *ses;
+       struct cifs_tcon *tcon;
+       struct smb2_lease_break_work *lw;
 
-                               spin_unlock(&cifs_file_list_lock);
-                               spin_unlock(&cifs_tcp_ses_lock);
-                               return true;
-                       }
+       lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
+       if (!lw)
+               return false;
 
-                       found = false;
-                       list_for_each_entry(open, &tcon->pending_opens, olist) {
-                               if (memcmp(open->lease_key, rsp->LeaseKey,
-                                          SMB2_LEASE_KEY_SIZE))
-                                       continue;
+       INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
+       lw->lease_state = rsp->NewLeaseState;
 
-                               if (!found && ack_req) {
-                                       found = true;
-                                       memcpy(lw->lease_key, open->lease_key,
-                                              SMB2_LEASE_KEY_SIZE);
-                                       lw->tlink = cifs_get_tlink(open->tlink);
-                                       queue_work(cifsiod_wq,
-                                                  &lw->lease_break);
-                               }
+       cifs_dbg(FYI, "Checking for lease break\n");
 
-                               cifs_dbg(FYI, "found in the pending open list\n");
-                               cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
-                                        le32_to_cpu(rsp->NewLeaseState));
+       /* look up tcon based on tid & uid */
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each(tmp, &cifs_tcp_ses_list) {
+               server = list_entry(tmp, struct TCP_Server_Info, tcp_ses_list);
 
-                               open->oplock =
-                                 smb2_map_lease_to_oplock(rsp->NewLeaseState);
-                       }
-                       if (found) {
-                               spin_unlock(&cifs_file_list_lock);
-                               spin_unlock(&cifs_tcp_ses_lock);
-                               return true;
+               list_for_each(tmp1, &server->smb_ses_list) {
+                       ses = list_entry(tmp1, struct cifs_ses, smb_ses_list);
+
+                       spin_lock(&cifs_file_list_lock);
+                       list_for_each(tmp2, &ses->tcon_list) {
+                               tcon = list_entry(tmp2, struct cifs_tcon,
+                                                 tcon_list);
+                               cifs_stats_inc(
+                                   &tcon->stats.cifs_stats.num_oplock_brks);
+                               if (smb2_tcon_has_lease(tcon, rsp, lw)) {
+                                       spin_unlock(&cifs_file_list_lock);
+                                       spin_unlock(&cifs_tcp_ses_lock);
+                                       return true;
+                               }
                        }
+                       spin_unlock(&cifs_file_list_lock);
                }
-               spin_unlock(&cifs_file_list_lock);
        }
        spin_unlock(&cifs_tcp_ses_lock);
        kfree(lw);
@@ -532,7 +541,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
        if (rsp->StructureSize !=
                                smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
                if (le16_to_cpu(rsp->StructureSize) == 44)
-                       return smb2_is_valid_lease_break(buffer, server);
+                       return smb2_is_valid_lease_break(buffer);
                else
                        return false;
        }
@@ -560,14 +569,15 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
                                cifs_dbg(FYI, "file id match, oplock break\n");
                                cinode = CIFS_I(cfile->dentry->d_inode);
 
-                               if (!cinode->clientCanCacheAll &&
+                               if (!CIFS_CACHE_WRITE(cinode) &&
                                    rsp->OplockLevel == SMB2_OPLOCK_LEVEL_NONE)
                                        cfile->oplock_break_cancelled = true;
                                else
                                        cfile->oplock_break_cancelled = false;
 
-                               smb2_set_oplock_level(cinode,
-                                 rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0);
+                               server->ops->set_oplock_level(cinode,
+                                 rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0,
+                                 0, NULL);
 
                                queue_work(cifsiod_wq, &cfile->oplock_break);
 
index f259e6cc835791f20e34acce582f83ca1b78102c..861b332141440c35c3a1b56ec1587b0166399006 100644 (file)
@@ -24,6 +24,7 @@
 #include "smb2proto.h"
 #include "cifsproto.h"
 #include "cifs_debug.h"
+#include "cifs_unicode.h"
 #include "smb2status.h"
 #include "smb2glob.h"
 
@@ -229,7 +230,7 @@ smb2_is_path_accessible(const unsigned int xid, struct cifs_tcon *tcon,
        oparms.fid = &fid;
        oparms.reconnect = false;
 
-       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
        if (rc) {
                kfree(utf16_path);
                return rc;
@@ -376,10 +377,13 @@ static void
 smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
 {
        struct cifsInodeInfo *cinode = CIFS_I(cfile->dentry->d_inode);
+       struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server;
+
        cfile->fid.persistent_fid = fid->persistent_fid;
        cfile->fid.volatile_fid = fid->volatile_fid;
-       smb2_set_oplock_level(cinode, oplock);
-       cinode->can_cache_brlcks = cinode->clientCanCacheAll;
+       server->ops->set_oplock_level(cinode, oplock, fid->epoch,
+                                     &fid->purge_cache);
+       cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
 }
 
 static void
@@ -463,7 +467,7 @@ smb2_query_dir_first(const unsigned int xid, struct cifs_tcon *tcon,
        oparms.fid = fid;
        oparms.reconnect = false;
 
-       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL);
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL);
        kfree(utf16_path);
        if (rc) {
                cifs_dbg(VFS, "open dir failed\n");
@@ -530,7 +534,7 @@ smb2_oplock_response(struct cifs_tcon *tcon, struct cifs_fid *fid,
 
        return SMB2_oplock_break(0, tcon, fid->persistent_fid,
                                 fid->volatile_fid,
-                                cinode->clientCanCacheRead ? 1 : 0);
+                                CIFS_CACHE_READ(cinode) ? 1 : 0);
 }
 
 static int
@@ -550,7 +554,7 @@ smb2_queryfs(const unsigned int xid, struct cifs_tcon *tcon,
        oparms.fid = &fid;
        oparms.reconnect = false;
 
-       rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL);
+       rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL);
        if (rc)
                return rc;
        buf->f_type = SMB2_MAGIC_NUMBER;
@@ -596,7 +600,245 @@ smb2_new_lease_key(struct cifs_fid *fid)
        get_random_bytes(fid->lease_key, SMB2_LEASE_KEY_SIZE);
 }
 
-struct smb_version_operations smb21_operations = {
+static int
+smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
+                  const char *full_path, char **target_path,
+                  struct cifs_sb_info *cifs_sb)
+{
+       int rc;
+       __le16 *utf16_path;
+       __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+       struct cifs_open_parms oparms;
+       struct cifs_fid fid;
+       struct smb2_err_rsp *err_buf = NULL;
+       struct smb2_symlink_err_rsp *symlink;
+       unsigned int sub_len, sub_offset;
+
+       cifs_dbg(FYI, "%s: path: %s\n", __func__, full_path);
+
+       utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
+       if (!utf16_path)
+               return -ENOMEM;
+
+       oparms.tcon = tcon;
+       oparms.desired_access = FILE_READ_ATTRIBUTES;
+       oparms.disposition = FILE_OPEN;
+       oparms.create_options = 0;
+       oparms.fid = &fid;
+       oparms.reconnect = false;
+
+       rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, &err_buf);
+
+       if (!rc || !err_buf) {
+               kfree(utf16_path);
+               return -ENOENT;
+       }
+       /* open must fail on symlink - reset rc */
+       rc = 0;
+       symlink = (struct smb2_symlink_err_rsp *)err_buf->ErrorData;
+       sub_len = le16_to_cpu(symlink->SubstituteNameLength);
+       sub_offset = le16_to_cpu(symlink->SubstituteNameOffset);
+       *target_path = cifs_strndup_from_utf16(
+                               (char *)symlink->PathBuffer + sub_offset,
+                               sub_len, true, cifs_sb->local_nls);
+       if (!(*target_path)) {
+               kfree(utf16_path);
+               return -ENOMEM;
+       }
+       convert_delimiter(*target_path, '/');
+       cifs_dbg(FYI, "%s: target path: %s\n", __func__, *target_path);
+       kfree(utf16_path);
+       return rc;
+}
+
+static void
+smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
+                     unsigned int epoch, bool *purge_cache)
+{
+       oplock &= 0xFF;
+       if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
+               return;
+       if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
+               cinode->oplock = CIFS_CACHE_RHW_FLG;
+               cifs_dbg(FYI, "Batch Oplock granted on inode %p\n",
+                        &cinode->vfs_inode);
+       } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+               cinode->oplock = CIFS_CACHE_RW_FLG;
+               cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
+                        &cinode->vfs_inode);
+       } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
+               cinode->oplock = CIFS_CACHE_READ_FLG;
+               cifs_dbg(FYI, "Level II Oplock granted on inode %p\n",
+                        &cinode->vfs_inode);
+       } else
+               cinode->oplock = 0;
+}
+
+static void
+smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
+                      unsigned int epoch, bool *purge_cache)
+{
+       char message[5] = {0};
+
+       oplock &= 0xFF;
+       if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
+               return;
+
+       cinode->oplock = 0;
+       if (oplock & SMB2_LEASE_READ_CACHING_HE) {
+               cinode->oplock |= CIFS_CACHE_READ_FLG;
+               strcat(message, "R");
+       }
+       if (oplock & SMB2_LEASE_HANDLE_CACHING_HE) {
+               cinode->oplock |= CIFS_CACHE_HANDLE_FLG;
+               strcat(message, "H");
+       }
+       if (oplock & SMB2_LEASE_WRITE_CACHING_HE) {
+               cinode->oplock |= CIFS_CACHE_WRITE_FLG;
+               strcat(message, "W");
+       }
+       if (!cinode->oplock)
+               strcat(message, "None");
+       cifs_dbg(FYI, "%s Lease granted on inode %p\n", message,
+                &cinode->vfs_inode);
+}
+
+static void
+smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
+                     unsigned int epoch, bool *purge_cache)
+{
+       unsigned int old_oplock = cinode->oplock;
+
+       smb21_set_oplock_level(cinode, oplock, epoch, purge_cache);
+
+       if (purge_cache) {
+               *purge_cache = false;
+               if (old_oplock == CIFS_CACHE_READ_FLG) {
+                       if (cinode->oplock == CIFS_CACHE_READ_FLG &&
+                           (epoch - cinode->epoch > 0))
+                               *purge_cache = true;
+                       else if (cinode->oplock == CIFS_CACHE_RH_FLG &&
+                                (epoch - cinode->epoch > 1))
+                               *purge_cache = true;
+                       else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
+                                (epoch - cinode->epoch > 1))
+                               *purge_cache = true;
+                       else if (cinode->oplock == 0 &&
+                                (epoch - cinode->epoch > 0))
+                               *purge_cache = true;
+               } else if (old_oplock == CIFS_CACHE_RH_FLG) {
+                       if (cinode->oplock == CIFS_CACHE_RH_FLG &&
+                           (epoch - cinode->epoch > 0))
+                               *purge_cache = true;
+                       else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
+                                (epoch - cinode->epoch > 1))
+                               *purge_cache = true;
+               }
+               cinode->epoch = epoch;
+       }
+}
+
+static bool
+smb2_is_read_op(__u32 oplock)
+{
+       return oplock == SMB2_OPLOCK_LEVEL_II;
+}
+
+static bool
+smb21_is_read_op(__u32 oplock)
+{
+       return (oplock & SMB2_LEASE_READ_CACHING_HE) &&
+              !(oplock & SMB2_LEASE_WRITE_CACHING_HE);
+}
+
+static __le32
+map_oplock_to_lease(u8 oplock)
+{
+       if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
+               return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING;
+       else if (oplock == SMB2_OPLOCK_LEVEL_II)
+               return SMB2_LEASE_READ_CACHING;
+       else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
+               return SMB2_LEASE_HANDLE_CACHING | SMB2_LEASE_READ_CACHING |
+                      SMB2_LEASE_WRITE_CACHING;
+       return 0;
+}
+
+static char *
+smb2_create_lease_buf(u8 *lease_key, u8 oplock)
+{
+       struct create_lease *buf;
+
+       buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
+       buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
+       buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct create_lease, lcontext));
+       buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct create_lease, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+       buf->Name[0] = 'R';
+       buf->Name[1] = 'q';
+       buf->Name[2] = 'L';
+       buf->Name[3] = 's';
+       return (char *)buf;
+}
+
+static char *
+smb3_create_lease_buf(u8 *lease_key, u8 oplock)
+{
+       struct create_lease_v2 *buf;
+
+       buf = kzalloc(sizeof(struct create_lease_v2), GFP_KERNEL);
+       if (!buf)
+               return NULL;
+
+       buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
+       buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
+       buf->lcontext.LeaseState = map_oplock_to_lease(oplock);
+
+       buf->ccontext.DataOffset = cpu_to_le16(offsetof
+                                       (struct create_lease_v2, lcontext));
+       buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context_v2));
+       buf->ccontext.NameOffset = cpu_to_le16(offsetof
+                               (struct create_lease_v2, Name));
+       buf->ccontext.NameLength = cpu_to_le16(4);
+       buf->Name[0] = 'R';
+       buf->Name[1] = 'q';
+       buf->Name[2] = 'L';
+       buf->Name[3] = 's';
+       return (char *)buf;
+}
+
+static __u8
+smb2_parse_lease_buf(void *buf, unsigned int *epoch)
+{
+       struct create_lease *lc = (struct create_lease *)buf;
+
+       *epoch = 0; /* not used */
+       if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
+               return SMB2_OPLOCK_LEVEL_NOCHANGE;
+       return le32_to_cpu(lc->lcontext.LeaseState);
+}
+
+static __u8
+smb3_parse_lease_buf(void *buf, unsigned int *epoch)
+{
+       struct create_lease_v2 *lc = (struct create_lease_v2 *)buf;
+
+       *epoch = le16_to_cpu(lc->lcontext.Epoch);
+       if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
+               return SMB2_OPLOCK_LEVEL_NOCHANGE;
+       return le32_to_cpu(lc->lcontext.LeaseState);
+}
+
+struct smb_version_operations smb20_operations = {
        .compare_fids = smb2_compare_fids,
        .setup_request = smb2_setup_request,
        .setup_async_request = smb2_setup_async_request,
@@ -638,6 +880,7 @@ struct smb_version_operations smb21_operations = {
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
+       .query_symlink = smb2_query_symlink,
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
@@ -660,8 +903,82 @@ struct smb_version_operations smb21_operations = {
        .set_lease_key = smb2_set_lease_key,
        .new_lease_key = smb2_new_lease_key,
        .calc_signature = smb2_calc_signature,
+       .is_read_op = smb2_is_read_op,
+       .set_oplock_level = smb2_set_oplock_level,
+       .create_lease_buf = smb2_create_lease_buf,
+       .parse_lease_buf = smb2_parse_lease_buf,
 };
 
+struct smb_version_operations smb21_operations = {
+       .compare_fids = smb2_compare_fids,
+       .setup_request = smb2_setup_request,
+       .setup_async_request = smb2_setup_async_request,
+       .check_receive = smb2_check_receive,
+       .add_credits = smb2_add_credits,
+       .set_credits = smb2_set_credits,
+       .get_credits_field = smb2_get_credits_field,
+       .get_credits = smb2_get_credits,
+       .get_next_mid = smb2_get_next_mid,
+       .read_data_offset = smb2_read_data_offset,
+       .read_data_length = smb2_read_data_length,
+       .map_error = map_smb2_to_linux_error,
+       .find_mid = smb2_find_mid,
+       .check_message = smb2_check_message,
+       .dump_detail = smb2_dump_detail,
+       .clear_stats = smb2_clear_stats,
+       .print_stats = smb2_print_stats,
+       .is_oplock_break = smb2_is_valid_oplock_break,
+       .need_neg = smb2_need_neg,
+       .negotiate = smb2_negotiate,
+       .negotiate_wsize = smb2_negotiate_wsize,
+       .negotiate_rsize = smb2_negotiate_rsize,
+       .sess_setup = SMB2_sess_setup,
+       .logoff = SMB2_logoff,
+       .tree_connect = SMB2_tcon,
+       .tree_disconnect = SMB2_tdis,
+       .is_path_accessible = smb2_is_path_accessible,
+       .can_echo = smb2_can_echo,
+       .echo = SMB2_echo,
+       .query_path_info = smb2_query_path_info,
+       .get_srv_inum = smb2_get_srv_inum,
+       .query_file_info = smb2_query_file_info,
+       .set_path_size = smb2_set_path_size,
+       .set_file_size = smb2_set_file_size,
+       .set_file_info = smb2_set_file_info,
+       .mkdir = smb2_mkdir,
+       .mkdir_setinfo = smb2_mkdir_setinfo,
+       .rmdir = smb2_rmdir,
+       .unlink = smb2_unlink,
+       .rename = smb2_rename_path,
+       .create_hardlink = smb2_create_hardlink,
+       .query_symlink = smb2_query_symlink,
+       .open = smb2_open_file,
+       .set_fid = smb2_set_fid,
+       .close = smb2_close_file,
+       .flush = smb2_flush_file,
+       .async_readv = smb2_async_readv,
+       .async_writev = smb2_async_writev,
+       .sync_read = smb2_sync_read,
+       .sync_write = smb2_sync_write,
+       .query_dir_first = smb2_query_dir_first,
+       .query_dir_next = smb2_query_dir_next,
+       .close_dir = smb2_close_dir,
+       .calc_smb_size = smb2_calc_size,
+       .is_status_pending = smb2_is_status_pending,
+       .oplock_response = smb2_oplock_response,
+       .queryfs = smb2_queryfs,
+       .mand_lock = smb2_mand_lock,
+       .mand_unlock_range = smb2_unlock_range,
+       .push_mand_locks = smb2_push_mandatory_locks,
+       .get_lease_key = smb2_get_lease_key,
+       .set_lease_key = smb2_set_lease_key,
+       .new_lease_key = smb2_new_lease_key,
+       .calc_signature = smb2_calc_signature,
+       .is_read_op = smb21_is_read_op,
+       .set_oplock_level = smb21_set_oplock_level,
+       .create_lease_buf = smb2_create_lease_buf,
+       .parse_lease_buf = smb2_parse_lease_buf,
+};
 
 struct smb_version_operations smb30_operations = {
        .compare_fids = smb2_compare_fids,
@@ -706,6 +1023,7 @@ struct smb_version_operations smb30_operations = {
        .unlink = smb2_unlink,
        .rename = smb2_rename_path,
        .create_hardlink = smb2_create_hardlink,
+       .query_symlink = smb2_query_symlink,
        .open = smb2_open_file,
        .set_fid = smb2_set_fid,
        .close = smb2_close_file,
@@ -729,6 +1047,10 @@ struct smb_version_operations smb30_operations = {
        .new_lease_key = smb2_new_lease_key,
        .generate_signingkey = generate_smb3signingkey,
        .calc_signature = smb3_calc_signature,
+       .is_read_op = smb21_is_read_op,
+       .set_oplock_level = smb3_set_oplock_level,
+       .create_lease_buf = smb3_create_lease_buf,
+       .parse_lease_buf = smb3_parse_lease_buf,
 };
 
 struct smb_version_values smb20_values = {
@@ -746,9 +1068,9 @@ struct smb_version_values smb20_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .create_lease_size = sizeof(struct create_lease),
 };
 
 struct smb_version_values smb21_values = {
@@ -766,9 +1088,9 @@ struct smb_version_values smb21_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .create_lease_size = sizeof(struct create_lease),
 };
 
 struct smb_version_values smb30_values = {
@@ -786,9 +1108,9 @@ struct smb_version_values smb30_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .create_lease_size = sizeof(struct create_lease_v2),
 };
 
 struct smb_version_values smb302_values = {
@@ -806,7 +1128,7 @@ struct smb_version_values smb302_values = {
        .cap_unix = 0,
        .cap_nt_find = SMB2_NT_FIND,
        .cap_large_files = SMB2_LARGE_FILES,
-       .oplock_read = SMB2_OPLOCK_LEVEL_II,
        .signing_enabled = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED,
        .signing_required = SMB2_NEGOTIATE_SIGNING_REQUIRED,
+       .create_lease_size = sizeof(struct create_lease_v2),
 };
index abc9c2809b519c50623209d341733c31a752b2b3..eba0efde66d70ae15974eef74b10ff6d83ca44d8 100644 (file)
@@ -477,6 +477,13 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
                return -EIO;
        }
 
+       /*
+        * If we are here due to reconnect, free per-smb session key
+        * in case signing was required.
+        */
+       kfree(ses->auth_key.response);
+       ses->auth_key.response = NULL;
+
        /*
         * If memory allocation is successful, caller of this function
         * frees it.
@@ -484,6 +491,7 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_ses *ses,
        ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
        if (!ses->ntlmssp)
                return -ENOMEM;
+       ses->ntlmssp->sesskey_per_smbsess = true;
 
        /* FIXME: allow for other auth types besides NTLMSSP (e.g. krb5) */
        ses->sectype = RawNTLMSSP;
@@ -628,6 +636,40 @@ ssetup_exit:
        /* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
        if ((phase == NtLmChallenge) && (rc == 0))
                goto ssetup_ntlmssp_authenticate;
+
+       if (!rc) {
+               mutex_lock(&server->srv_mutex);
+               if (server->sign && server->ops->generate_signingkey) {
+                       rc = server->ops->generate_signingkey(ses);
+                       kfree(ses->auth_key.response);
+                       ses->auth_key.response = NULL;
+                       if (rc) {
+                               cifs_dbg(FYI,
+                                       "SMB3 session key generation failed\n");
+                               mutex_unlock(&server->srv_mutex);
+                               goto keygen_exit;
+                       }
+               }
+               if (!server->session_estab) {
+                       server->sequence_number = 0x2;
+                       server->session_estab = true;
+               }
+               mutex_unlock(&server->srv_mutex);
+
+               cifs_dbg(FYI, "SMB2/3 session established successfully\n");
+               spin_lock(&GlobalMid_Lock);
+               ses->status = CifsGood;
+               ses->need_reconnect = false;
+               spin_unlock(&GlobalMid_Lock);
+       }
+
+keygen_exit:
+       if (!server->sign) {
+               kfree(ses->auth_key.response);
+               ses->auth_key.response = NULL;
+       }
+       kfree(ses->ntlmssp);
+
        return rc;
 }
 
@@ -813,39 +855,6 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
        return rc;
 }
 
-static struct create_lease *
-create_lease_buf(u8 *lease_key, u8 oplock)
-{
-       struct create_lease *buf;
-
-       buf = kzalloc(sizeof(struct create_lease), GFP_KERNEL);
-       if (!buf)
-               return NULL;
-
-       buf->lcontext.LeaseKeyLow = cpu_to_le64(*((u64 *)lease_key));
-       buf->lcontext.LeaseKeyHigh = cpu_to_le64(*((u64 *)(lease_key + 8)));
-       if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
-               buf->lcontext.LeaseState = SMB2_LEASE_WRITE_CACHING |
-                                          SMB2_LEASE_READ_CACHING;
-       else if (oplock == SMB2_OPLOCK_LEVEL_II)
-               buf->lcontext.LeaseState = SMB2_LEASE_READ_CACHING;
-       else if (oplock == SMB2_OPLOCK_LEVEL_BATCH)
-               buf->lcontext.LeaseState = SMB2_LEASE_HANDLE_CACHING |
-                                          SMB2_LEASE_READ_CACHING |
-                                          SMB2_LEASE_WRITE_CACHING;
-
-       buf->ccontext.DataOffset = cpu_to_le16(offsetof
-                                       (struct create_lease, lcontext));
-       buf->ccontext.DataLength = cpu_to_le32(sizeof(struct lease_context));
-       buf->ccontext.NameOffset = cpu_to_le16(offsetof
-                               (struct create_lease, Name));
-       buf->ccontext.NameLength = cpu_to_le16(4);
-       buf->Name[0] = 'R';
-       buf->Name[1] = 'q';
-       buf->Name[2] = 'L';
-       buf->Name[3] = 's';
-       return buf;
-}
 
 static struct create_durable *
 create_durable_buf(void)
@@ -894,55 +903,49 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
 }
 
 static __u8
-parse_lease_state(struct smb2_create_rsp *rsp)
+parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
+                 unsigned int *epoch)
 {
        char *data_offset;
-       struct create_lease *lc;
-       bool found = false;
+       struct create_context *cc;
        unsigned int next = 0;
        char *name;
 
        data_offset = (char *)rsp + 4 + le32_to_cpu(rsp->CreateContextsOffset);
-       lc = (struct create_lease *)data_offset;
+       cc = (struct create_context *)data_offset;
        do {
-               lc = (struct create_lease *)((char *)lc + next);
-               name = le16_to_cpu(lc->ccontext.NameOffset) + (char *)lc;
-               if (le16_to_cpu(lc->ccontext.NameLength) != 4 ||
+               cc = (struct create_context *)((char *)cc + next);
+               name = le16_to_cpu(cc->NameOffset) + (char *)cc;
+               if (le16_to_cpu(cc->NameLength) != 4 ||
                    strncmp(name, "RqLs", 4)) {
-                       next = le32_to_cpu(lc->ccontext.Next);
+                       next = le32_to_cpu(cc->Next);
                        continue;
                }
-               if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
-                       return SMB2_OPLOCK_LEVEL_NOCHANGE;
-               found = true;
-               break;
+               return server->ops->parse_lease_buf(cc, epoch);
        } while (next != 0);
 
-       if (!found)
-               return 0;
-
-       return smb2_map_lease_to_oplock(lc->lcontext.LeaseState);
+       return 0;
 }
 
 static int
-add_lease_context(struct kvec *iov, unsigned int *num_iovec, __u8 *oplock)
+add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
+                 unsigned int *num_iovec, __u8 *oplock)
 {
        struct smb2_create_req *req = iov[0].iov_base;
        unsigned int num = *num_iovec;
 
-       iov[num].iov_base = create_lease_buf(oplock+1, *oplock);
+       iov[num].iov_base = server->ops->create_lease_buf(oplock+1, *oplock);
        if (iov[num].iov_base == NULL)
                return -ENOMEM;
-       iov[num].iov_len = sizeof(struct create_lease);
+       iov[num].iov_len = server->vals->create_lease_size;
        req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_LEASE;
        if (!req->CreateContextsOffset)
                req->CreateContextsOffset = cpu_to_le32(
                                sizeof(struct smb2_create_req) - 4 +
                                iov[num - 1].iov_len);
-       req->CreateContextsLength = cpu_to_le32(
-                               le32_to_cpu(req->CreateContextsLength) +
-                               sizeof(struct create_lease));
-       inc_rfc1001_len(&req->hdr, sizeof(struct create_lease));
+       le32_add_cpu(&req->CreateContextsLength,
+                    server->vals->create_lease_size);
+       inc_rfc1001_len(&req->hdr, server->vals->create_lease_size);
        *num_iovec = num + 1;
        return 0;
 }
@@ -967,9 +970,7 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
                req->CreateContextsOffset =
                        cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
                                                                iov[1].iov_len);
-       req->CreateContextsLength =
-                       cpu_to_le32(le32_to_cpu(req->CreateContextsLength) +
-                                               sizeof(struct create_durable));
+       le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable));
        inc_rfc1001_len(&req->hdr, sizeof(struct create_durable));
        *num_iovec = num + 1;
        return 0;
@@ -977,7 +978,8 @@ add_durable_context(struct kvec *iov, unsigned int *num_iovec,
 
 int
 SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
-         __u8 *oplock, struct smb2_file_all_info *buf)
+         __u8 *oplock, struct smb2_file_all_info *buf,
+         struct smb2_err_rsp **err_buf)
 {
        struct smb2_create_req *req;
        struct smb2_create_rsp *rsp;
@@ -1048,11 +1050,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        if (!server->oplocks)
                *oplock = SMB2_OPLOCK_LEVEL_NONE;
 
-       if (!(tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
+       if (!(server->capabilities & SMB2_GLOBAL_CAP_LEASING) ||
            *oplock == SMB2_OPLOCK_LEVEL_NONE)
                req->RequestedOplockLevel = *oplock;
        else {
-               rc = add_lease_context(iov, &num_iovecs, oplock);
+               rc = add_lease_context(server, iov, &num_iovecs, oplock);
                if (rc) {
                        cifs_small_buf_release(req);
                        kfree(copy_path);
@@ -1062,11 +1064,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 
        if (*oplock == SMB2_OPLOCK_LEVEL_BATCH) {
                /* need to set Next field of lease context if we request it */
-               if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
+               if (server->capabilities & SMB2_GLOBAL_CAP_LEASING) {
                        struct create_context *ccontext =
                            (struct create_context *)iov[num_iovecs-1].iov_base;
                        ccontext->Next =
-                               cpu_to_le32(sizeof(struct create_lease));
+                               cpu_to_le32(server->vals->create_lease_size);
                }
                rc = add_durable_context(iov, &num_iovecs, oparms);
                if (rc) {
@@ -1082,6 +1084,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
 
        if (rc != 0) {
                cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
+               if (err_buf)
+                       *err_buf = kmemdup(rsp, get_rfc1002_length(rsp) + 4,
+                                          GFP_KERNEL);
                goto creat_exit;
        }
 
@@ -1098,7 +1103,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
        }
 
        if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
-               *oplock = parse_lease_state(rsp);
+               *oplock = parse_lease_state(server, rsp, &oparms->fid->epoch);
        else
                *oplock = rsp->OplockLevel;
 creat_exit:
index 36b0d37ea69b8d9f7bab7d1e1e3fcd167afe34e3..b83d0118a7577256ee4084d8a3abce4666e90bb7 100644 (file)
@@ -150,6 +150,20 @@ struct smb2_err_rsp {
        __u8   ErrorData[1];  /* variable length */
 } __packed;
 
+struct smb2_symlink_err_rsp {
+       __le32 SymLinkLength;
+       __le32 SymLinkErrorTag;
+       __le32 ReparseTag;
+       __le16 ReparseDataLength;
+       __le16 UnparsedPathLength;
+       __le16 SubstituteNameOffset;
+       __le16 SubstituteNameLength;
+       __le16 PrintNameOffset;
+       __le16 PrintNameLength;
+       __le32 Flags;
+       __u8  PathBuffer[0];
+} __packed;
+
 #define SMB2_CLIENT_GUID_SIZE 16
 
 extern __u8 cifs_client_guid[SMB2_CLIENT_GUID_SIZE];
@@ -462,6 +476,10 @@ struct create_context {
        __u8 Buffer[0];
 } __packed;
 
+#define SMB2_LEASE_READ_CACHING_HE     0x01
+#define SMB2_LEASE_HANDLE_CACHING_HE   0x02
+#define SMB2_LEASE_WRITE_CACHING_HE    0x04
+
 #define SMB2_LEASE_NONE                        __constant_cpu_to_le32(0x00)
 #define SMB2_LEASE_READ_CACHING                __constant_cpu_to_le32(0x01)
 #define SMB2_LEASE_HANDLE_CACHING      __constant_cpu_to_le32(0x02)
@@ -479,12 +497,31 @@ struct lease_context {
        __le64 LeaseDuration;
 } __packed;
 
+struct lease_context_v2 {
+       __le64 LeaseKeyLow;
+       __le64 LeaseKeyHigh;
+       __le32 LeaseState;
+       __le32 LeaseFlags;
+       __le64 LeaseDuration;
+       __le64 ParentLeaseKeyLow;
+       __le64 ParentLeaseKeyHigh;
+       __le16 Epoch;
+       __le16 Reserved;
+} __packed;
+
 struct create_lease {
        struct create_context ccontext;
        __u8   Name[8];
        struct lease_context lcontext;
 } __packed;
 
+struct create_lease_v2 {
+       struct create_context ccontext;
+       __u8   Name[8];
+       struct lease_context_v2 lcontext;
+       __u8   Pad[4];
+} __packed;
+
 struct create_durable {
        struct create_context ccontext;
        __u8   Name[8];
index 1a5ecbed40edac9ae352a1baa2c162697712e9fd..e3fb4801ee969295484fd8324bec855fc9600e0b 100644 (file)
@@ -53,7 +53,6 @@ extern int smb3_calc_signature(struct smb_rqst *rqst,
                                struct TCP_Server_Info *server);
 extern void smb2_echo_request(struct work_struct *work);
 extern __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode);
-extern __u8 smb2_map_lease_to_oplock(__le32 lease_state);
 extern bool smb2_is_valid_oplock_break(char *buffer,
                                       struct TCP_Server_Info *srv);
 
@@ -87,7 +86,6 @@ extern int smb2_create_hardlink(const unsigned int xid, struct cifs_tcon *tcon,
 extern int smb2_open_file(const unsigned int xid,
                          struct cifs_open_parms *oparms,
                          __u32 *oplock, FILE_ALL_INFO *buf);
-extern void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock);
 extern int smb2_unlock_range(struct cifsFileInfo *cfile,
                             struct file_lock *flock, const unsigned int xid);
 extern int smb2_push_mandatory_locks(struct cifsFileInfo *cfile);
@@ -106,7 +104,8 @@ extern int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses,
 extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon);
 extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms,
                     __le16 *path, __u8 *oplock,
-                    struct smb2_file_all_info *buf);
+                    struct smb2_file_all_info *buf,
+                    struct smb2_err_rsp **err_buf);
 extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon,
                     u64 persistent_fid, u64 volatile_fid, u32 opcode,
                     bool is_fsctl, char *in_data, u32 indatalen,
index 4f2300d020c7e517a6fa89be5d955fa4b12753da..340abca3aa522f31490d0c483e76b60aa08d582a 100644 (file)
@@ -114,6 +114,23 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
        return 0;
 }
 
+static struct cifs_ses *
+smb2_find_smb_ses(struct smb2_hdr *smb2hdr, struct TCP_Server_Info *server)
+{
+       struct cifs_ses *ses;
+
+       spin_lock(&cifs_tcp_ses_lock);
+       list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
+               if (ses->Suid != smb2hdr->SessionId)
+                       continue;
+               spin_unlock(&cifs_tcp_ses_lock);
+               return ses;
+       }
+       spin_unlock(&cifs_tcp_ses_lock);
+
+       return NULL;
+}
+
 
 int
 smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
@@ -124,6 +141,13 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
        struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+       struct cifs_ses *ses;
+
+       ses = smb2_find_smb_ses(smb2_pdu, server);
+       if (!ses) {
+               cifs_dbg(VFS, "%s: Could not find session\n", __func__);
+               return 0;
+       }
 
        memset(smb2_signature, 0x0, SMB2_HMACSHA256_SIZE);
        memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
@@ -135,7 +159,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        }
 
        rc = crypto_shash_setkey(server->secmech.hmacsha256,
-               server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+               ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with response\n", __func__);
                return rc;
@@ -198,8 +222,8 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        return rc;
 }
 
-void
-generate_smb3signingkey(struct TCP_Server_Info *server)
+int
+generate_smb3signingkey(struct cifs_ses *ses)
 {
        unsigned char zero = 0x0;
        __u8 i[4] = {0, 0, 0, 1};
@@ -209,90 +233,99 @@ generate_smb3signingkey(struct TCP_Server_Info *server)
        unsigned char *hashptr = prfhash;
 
        memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
-       memset(server->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
+       memset(ses->smb3signingkey, 0x0, SMB3_SIGNKEY_SIZE);
 
-       rc = smb3_crypto_shash_allocate(server);
+       rc = smb3_crypto_shash_allocate(ses->server);
        if (rc) {
                cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_setkey(server->secmech.hmacsha256,
-               server->session_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
+       rc = crypto_shash_setkey(ses->server->secmech.hmacsha256,
+               ses->auth_key.response, SMB2_NTLMV2_SESSKEY_SIZE);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not set with session key\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_init(&server->secmech.sdeschmacsha256->shash);
+       rc = crypto_shash_init(&ses->server->secmech.sdeschmacsha256->shash);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not init sign hmac\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+       rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
                                i, 4);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with n\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+       rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
                                "SMB2AESCMAC", 12);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with label\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+       rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
                                &zero, 1);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with zero\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+       rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
                                "SmbSign", 8);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with context\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_update(&server->secmech.sdeschmacsha256->shash,
+       rc = crypto_shash_update(&ses->server->secmech.sdeschmacsha256->shash,
                                L, 4);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not update with L\n", __func__);
                goto smb3signkey_ret;
        }
 
-       rc = crypto_shash_final(&server->secmech.sdeschmacsha256->shash,
+       rc = crypto_shash_final(&ses->server->secmech.sdeschmacsha256->shash,
                                hashptr);
        if (rc) {
                cifs_dbg(VFS, "%s: Could not generate sha256 hash\n", __func__);
                goto smb3signkey_ret;
        }
 
-       memcpy(server->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
+       memcpy(ses->smb3signingkey, hashptr, SMB3_SIGNKEY_SIZE);
 
 smb3signkey_ret:
-       return;
+       return rc;
 }
 
 int
 smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
-       int i, rc;
+       int i;
+       int rc = 0;
        unsigned char smb3_signature[SMB2_CMACAES_SIZE];
        unsigned char *sigptr = smb3_signature;
        struct kvec *iov = rqst->rq_iov;
        int n_vec = rqst->rq_nvec;
        struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)iov[0].iov_base;
+       struct cifs_ses *ses;
+
+       ses = smb2_find_smb_ses(smb2_pdu, server);
+       if (!ses) {
+               cifs_dbg(VFS, "%s: Could not find session\n", __func__);
+               return 0;
+       }
 
        memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
        memset(smb2_pdu->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
        rc = crypto_shash_setkey(server->secmech.cmacaes,
-               server->smb3signingkey, SMB2_CMACAES_SIZE);
+               ses->smb3signingkey, SMB2_CMACAES_SIZE);
+
        if (rc) {
                cifs_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
                return rc;
@@ -389,6 +422,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
        struct smb2_hdr *smb2_pdu = (struct smb2_hdr *)rqst->rq_iov[0].iov_base;
 
        if ((smb2_pdu->Command == SMB2_NEGOTIATE) ||
+           (smb2_pdu->Command == SMB2_SESSION_SETUP) ||
            (smb2_pdu->Command == SMB2_OPLOCK_BREAK) ||
            (!server->session_estab))
                return 0;
diff --git a/fs/cifs/winucase.c b/fs/cifs/winucase.c
new file mode 100644 (file)
index 0000000..1506d4f
--- /dev/null
@@ -0,0 +1,663 @@
+/*
+ * fs/cifs/winucase.c
+ *
+ * Copyright (c) Jeffrey Layton <jlayton@redhat.com>, 2013
+ *
+ * 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
+ *
+ * The const tables in this file were converted from the following info
+ * provided by Microsoft:
+ *
+ * 3.1.5.3 Mapping UTF-16 Strings to Upper Case:
+ *
+ * http://msdn.microsoft.com/en-us/library/hh877830.aspx
+ * http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&id=10921
+ *
+ * In particular, the table in "Windows 8 Upper Case Mapping Table.txt" was
+ * post-processed using the winucase_convert.pl script.
+ */
+
+#include <linux/nls.h>
+
+wchar_t cifs_toupper(wchar_t in);  /* quiet sparse */
+
+static const wchar_t t2_00[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+       0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+       0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+       0x0058, 0x0059, 0x005a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7,
+       0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+       0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x0000,
+       0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178,
+};
+
+static const wchar_t t2_01[256] = {
+       0x0000, 0x0100, 0x0000, 0x0102, 0x0000, 0x0104, 0x0000, 0x0106,
+       0x0000, 0x0108, 0x0000, 0x010a, 0x0000, 0x010c, 0x0000, 0x010e,
+       0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0000, 0x0116,
+       0x0000, 0x0118, 0x0000, 0x011a, 0x0000, 0x011c, 0x0000, 0x011e,
+       0x0000, 0x0120, 0x0000, 0x0122, 0x0000, 0x0124, 0x0000, 0x0126,
+       0x0000, 0x0128, 0x0000, 0x012a, 0x0000, 0x012c, 0x0000, 0x012e,
+       0x0000, 0x0000, 0x0000, 0x0132, 0x0000, 0x0134, 0x0000, 0x0136,
+       0x0000, 0x0000, 0x0139, 0x0000, 0x013b, 0x0000, 0x013d, 0x0000,
+       0x013f, 0x0000, 0x0141, 0x0000, 0x0143, 0x0000, 0x0145, 0x0000,
+       0x0147, 0x0000, 0x0000, 0x014a, 0x0000, 0x014c, 0x0000, 0x014e,
+       0x0000, 0x0150, 0x0000, 0x0152, 0x0000, 0x0154, 0x0000, 0x0156,
+       0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x0000, 0x015e,
+       0x0000, 0x0160, 0x0000, 0x0162, 0x0000, 0x0164, 0x0000, 0x0166,
+       0x0000, 0x0168, 0x0000, 0x016a, 0x0000, 0x016c, 0x0000, 0x016e,
+       0x0000, 0x0170, 0x0000, 0x0172, 0x0000, 0x0174, 0x0000, 0x0176,
+       0x0000, 0x0000, 0x0179, 0x0000, 0x017b, 0x0000, 0x017d, 0x0000,
+       0x0243, 0x0000, 0x0000, 0x0182, 0x0000, 0x0184, 0x0000, 0x0000,
+       0x0187, 0x0000, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0191, 0x0000, 0x0000, 0x01f6, 0x0000, 0x0000,
+       0x0000, 0x0198, 0x023d, 0x0000, 0x0000, 0x0000, 0x0220, 0x0000,
+       0x0000, 0x01a0, 0x0000, 0x01a2, 0x0000, 0x01a4, 0x0000, 0x0000,
+       0x01a7, 0x0000, 0x0000, 0x0000, 0x0000, 0x01ac, 0x0000, 0x0000,
+       0x01af, 0x0000, 0x0000, 0x0000, 0x01b3, 0x0000, 0x01b5, 0x0000,
+       0x0000, 0x01b8, 0x0000, 0x0000, 0x0000, 0x01bc, 0x0000, 0x01f7,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x01c4, 0x0000,
+       0x0000, 0x01c7, 0x0000, 0x0000, 0x01ca, 0x0000, 0x01cd, 0x0000,
+       0x01cf, 0x0000, 0x01d1, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000,
+       0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x018e, 0x0000, 0x01de,
+       0x0000, 0x01e0, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
+       0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
+       0x0000, 0x0000, 0x0000, 0x01f1, 0x0000, 0x01f4, 0x0000, 0x0000,
+       0x0000, 0x01f8, 0x0000, 0x01fa, 0x0000, 0x01fc, 0x0000, 0x01fe,
+};
+
+static const wchar_t t2_02[256] = {
+       0x0000, 0x0200, 0x0000, 0x0202, 0x0000, 0x0204, 0x0000, 0x0206,
+       0x0000, 0x0208, 0x0000, 0x020a, 0x0000, 0x020c, 0x0000, 0x020e,
+       0x0000, 0x0210, 0x0000, 0x0212, 0x0000, 0x0214, 0x0000, 0x0216,
+       0x0000, 0x0218, 0x0000, 0x021a, 0x0000, 0x021c, 0x0000, 0x021e,
+       0x0000, 0x0000, 0x0000, 0x0222, 0x0000, 0x0224, 0x0000, 0x0226,
+       0x0000, 0x0228, 0x0000, 0x022a, 0x0000, 0x022c, 0x0000, 0x022e,
+       0x0000, 0x0230, 0x0000, 0x0232, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x023b, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0241, 0x0000, 0x0000, 0x0000, 0x0000, 0x0246,
+       0x0000, 0x0248, 0x0000, 0x024a, 0x0000, 0x024c, 0x0000, 0x024e,
+       0x2c6f, 0x2c6d, 0x0000, 0x0181, 0x0186, 0x0000, 0x0189, 0x018a,
+       0x0000, 0x018f, 0x0000, 0x0190, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0193, 0x0000, 0x0000, 0x0194, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0197, 0x0196, 0x0000, 0x2c62, 0x0000, 0x0000, 0x0000, 0x019c,
+       0x0000, 0x2c6e, 0x019d, 0x0000, 0x0000, 0x019f, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2c64, 0x0000, 0x0000,
+       0x01a6, 0x0000, 0x0000, 0x01a9, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x01ae, 0x0244, 0x01b1, 0x01b2, 0x0245, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x01b7, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_03[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0370, 0x0000, 0x0372, 0x0000, 0x0000, 0x0000, 0x0376,
+       0x0000, 0x0000, 0x0000, 0x03fd, 0x03fe, 0x03ff, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0386, 0x0388, 0x0389, 0x038a,
+       0x0000, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+       0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
+       0x03a0, 0x03a1, 0x0000, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
+       0x03a8, 0x03a9, 0x03aa, 0x03ab, 0x038c, 0x038e, 0x038f, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x03cf,
+       0x0000, 0x03d8, 0x0000, 0x03da, 0x0000, 0x03dc, 0x0000, 0x03de,
+       0x0000, 0x03e0, 0x0000, 0x03e2, 0x0000, 0x03e4, 0x0000, 0x03e6,
+       0x0000, 0x03e8, 0x0000, 0x03ea, 0x0000, 0x03ec, 0x0000, 0x03ee,
+       0x0000, 0x0000, 0x03f9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x03f7, 0x0000, 0x0000, 0x03fa, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_04[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+       0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
+       0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+       0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
+       0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407,
+       0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040d, 0x040e, 0x040f,
+       0x0000, 0x0460, 0x0000, 0x0462, 0x0000, 0x0464, 0x0000, 0x0466,
+       0x0000, 0x0468, 0x0000, 0x046a, 0x0000, 0x046c, 0x0000, 0x046e,
+       0x0000, 0x0470, 0x0000, 0x0472, 0x0000, 0x0474, 0x0000, 0x0476,
+       0x0000, 0x0478, 0x0000, 0x047a, 0x0000, 0x047c, 0x0000, 0x047e,
+       0x0000, 0x0480, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x048a, 0x0000, 0x048c, 0x0000, 0x048e,
+       0x0000, 0x0490, 0x0000, 0x0492, 0x0000, 0x0494, 0x0000, 0x0496,
+       0x0000, 0x0498, 0x0000, 0x049a, 0x0000, 0x049c, 0x0000, 0x049e,
+       0x0000, 0x04a0, 0x0000, 0x04a2, 0x0000, 0x04a4, 0x0000, 0x04a6,
+       0x0000, 0x04a8, 0x0000, 0x04aa, 0x0000, 0x04ac, 0x0000, 0x04ae,
+       0x0000, 0x04b0, 0x0000, 0x04b2, 0x0000, 0x04b4, 0x0000, 0x04b6,
+       0x0000, 0x04b8, 0x0000, 0x04ba, 0x0000, 0x04bc, 0x0000, 0x04be,
+       0x0000, 0x0000, 0x04c1, 0x0000, 0x04c3, 0x0000, 0x04c5, 0x0000,
+       0x04c7, 0x0000, 0x04c9, 0x0000, 0x04cb, 0x0000, 0x04cd, 0x04c0,
+       0x0000, 0x04d0, 0x0000, 0x04d2, 0x0000, 0x04d4, 0x0000, 0x04d6,
+       0x0000, 0x04d8, 0x0000, 0x04da, 0x0000, 0x04dc, 0x0000, 0x04de,
+       0x0000, 0x04e0, 0x0000, 0x04e2, 0x0000, 0x04e4, 0x0000, 0x04e6,
+       0x0000, 0x04e8, 0x0000, 0x04ea, 0x0000, 0x04ec, 0x0000, 0x04ee,
+       0x0000, 0x04f0, 0x0000, 0x04f2, 0x0000, 0x04f4, 0x0000, 0x04f6,
+       0x0000, 0x04f8, 0x0000, 0x04fa, 0x0000, 0x04fc, 0x0000, 0x04fe,
+};
+
+static const wchar_t t2_05[256] = {
+       0x0000, 0x0500, 0x0000, 0x0502, 0x0000, 0x0504, 0x0000, 0x0506,
+       0x0000, 0x0508, 0x0000, 0x050a, 0x0000, 0x050c, 0x0000, 0x050e,
+       0x0000, 0x0510, 0x0000, 0x0512, 0x0000, 0x0514, 0x0000, 0x0516,
+       0x0000, 0x0518, 0x0000, 0x051a, 0x0000, 0x051c, 0x0000, 0x051e,
+       0x0000, 0x0520, 0x0000, 0x0522, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0531, 0x0532, 0x0533, 0x0534, 0x0535, 0x0536, 0x0537,
+       0x0538, 0x0539, 0x053a, 0x053b, 0x053c, 0x053d, 0x053e, 0x053f,
+       0x0540, 0x0541, 0x0542, 0x0543, 0x0544, 0x0545, 0x0546, 0x0547,
+       0x0548, 0x0549, 0x054a, 0x054b, 0x054c, 0x054d, 0x054e, 0x054f,
+       0x0550, 0x0551, 0x0552, 0x0553, 0x0554, 0x0555, 0x0556, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_1d[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0xa77d, 0x0000, 0x0000, 0x0000, 0x2c63, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_1e[256] = {
+       0x0000, 0x1e00, 0x0000, 0x1e02, 0x0000, 0x1e04, 0x0000, 0x1e06,
+       0x0000, 0x1e08, 0x0000, 0x1e0a, 0x0000, 0x1e0c, 0x0000, 0x1e0e,
+       0x0000, 0x1e10, 0x0000, 0x1e12, 0x0000, 0x1e14, 0x0000, 0x1e16,
+       0x0000, 0x1e18, 0x0000, 0x1e1a, 0x0000, 0x1e1c, 0x0000, 0x1e1e,
+       0x0000, 0x1e20, 0x0000, 0x1e22, 0x0000, 0x1e24, 0x0000, 0x1e26,
+       0x0000, 0x1e28, 0x0000, 0x1e2a, 0x0000, 0x1e2c, 0x0000, 0x1e2e,
+       0x0000, 0x1e30, 0x0000, 0x1e32, 0x0000, 0x1e34, 0x0000, 0x1e36,
+       0x0000, 0x1e38, 0x0000, 0x1e3a, 0x0000, 0x1e3c, 0x0000, 0x1e3e,
+       0x0000, 0x1e40, 0x0000, 0x1e42, 0x0000, 0x1e44, 0x0000, 0x1e46,
+       0x0000, 0x1e48, 0x0000, 0x1e4a, 0x0000, 0x1e4c, 0x0000, 0x1e4e,
+       0x0000, 0x1e50, 0x0000, 0x1e52, 0x0000, 0x1e54, 0x0000, 0x1e56,
+       0x0000, 0x1e58, 0x0000, 0x1e5a, 0x0000, 0x1e5c, 0x0000, 0x1e5e,
+       0x0000, 0x1e60, 0x0000, 0x1e62, 0x0000, 0x1e64, 0x0000, 0x1e66,
+       0x0000, 0x1e68, 0x0000, 0x1e6a, 0x0000, 0x1e6c, 0x0000, 0x1e6e,
+       0x0000, 0x1e70, 0x0000, 0x1e72, 0x0000, 0x1e74, 0x0000, 0x1e76,
+       0x0000, 0x1e78, 0x0000, 0x1e7a, 0x0000, 0x1e7c, 0x0000, 0x1e7e,
+       0x0000, 0x1e80, 0x0000, 0x1e82, 0x0000, 0x1e84, 0x0000, 0x1e86,
+       0x0000, 0x1e88, 0x0000, 0x1e8a, 0x0000, 0x1e8c, 0x0000, 0x1e8e,
+       0x0000, 0x1e90, 0x0000, 0x1e92, 0x0000, 0x1e94, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x1ea0, 0x0000, 0x1ea2, 0x0000, 0x1ea4, 0x0000, 0x1ea6,
+       0x0000, 0x1ea8, 0x0000, 0x1eaa, 0x0000, 0x1eac, 0x0000, 0x1eae,
+       0x0000, 0x1eb0, 0x0000, 0x1eb2, 0x0000, 0x1eb4, 0x0000, 0x1eb6,
+       0x0000, 0x1eb8, 0x0000, 0x1eba, 0x0000, 0x1ebc, 0x0000, 0x1ebe,
+       0x0000, 0x1ec0, 0x0000, 0x1ec2, 0x0000, 0x1ec4, 0x0000, 0x1ec6,
+       0x0000, 0x1ec8, 0x0000, 0x1eca, 0x0000, 0x1ecc, 0x0000, 0x1ece,
+       0x0000, 0x1ed0, 0x0000, 0x1ed2, 0x0000, 0x1ed4, 0x0000, 0x1ed6,
+       0x0000, 0x1ed8, 0x0000, 0x1eda, 0x0000, 0x1edc, 0x0000, 0x1ede,
+       0x0000, 0x1ee0, 0x0000, 0x1ee2, 0x0000, 0x1ee4, 0x0000, 0x1ee6,
+       0x0000, 0x1ee8, 0x0000, 0x1eea, 0x0000, 0x1eec, 0x0000, 0x1eee,
+       0x0000, 0x1ef0, 0x0000, 0x1ef2, 0x0000, 0x1ef4, 0x0000, 0x1ef6,
+       0x0000, 0x1ef8, 0x0000, 0x1efa, 0x0000, 0x1efc, 0x0000, 0x1efe,
+};
+
+static const wchar_t t2_1f[256] = {
+       0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x1f59, 0x0000, 0x1f5b, 0x0000, 0x1f5d, 0x0000, 0x1f5f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb,
+       0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0x0000, 0x0000,
+       0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1fb8, 0x1fb9, 0x0000, 0x1fbc, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x1fcc, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1fd8, 0x1fd9, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x1fe8, 0x1fe9, 0x0000, 0x0000, 0x0000, 0x1fec, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x1ffc, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_21[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2132, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x2160, 0x2161, 0x2162, 0x2163, 0x2164, 0x2165, 0x2166, 0x2167,
+       0x2168, 0x2169, 0x216a, 0x216b, 0x216c, 0x216d, 0x216e, 0x216f,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x2183, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_24[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x24b6, 0x24b7, 0x24b8, 0x24b9, 0x24ba, 0x24bb, 0x24bc, 0x24bd,
+       0x24be, 0x24bf, 0x24c0, 0x24c1, 0x24c2, 0x24c3, 0x24c4, 0x24c5,
+       0x24c6, 0x24c7, 0x24c8, 0x24c9, 0x24ca, 0x24cb, 0x24cc, 0x24cd,
+       0x24ce, 0x24cf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_2c[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x2c00, 0x2c01, 0x2c02, 0x2c03, 0x2c04, 0x2c05, 0x2c06, 0x2c07,
+       0x2c08, 0x2c09, 0x2c0a, 0x2c0b, 0x2c0c, 0x2c0d, 0x2c0e, 0x2c0f,
+       0x2c10, 0x2c11, 0x2c12, 0x2c13, 0x2c14, 0x2c15, 0x2c16, 0x2c17,
+       0x2c18, 0x2c19, 0x2c1a, 0x2c1b, 0x2c1c, 0x2c1d, 0x2c1e, 0x2c1f,
+       0x2c20, 0x2c21, 0x2c22, 0x2c23, 0x2c24, 0x2c25, 0x2c26, 0x2c27,
+       0x2c28, 0x2c29, 0x2c2a, 0x2c2b, 0x2c2c, 0x2c2d, 0x2c2e, 0x0000,
+       0x0000, 0x2c60, 0x0000, 0x0000, 0x0000, 0x023a, 0x023e, 0x0000,
+       0x2c67, 0x0000, 0x2c69, 0x0000, 0x2c6b, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x2c72, 0x0000, 0x0000, 0x2c75, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x2c80, 0x0000, 0x2c82, 0x0000, 0x2c84, 0x0000, 0x2c86,
+       0x0000, 0x2c88, 0x0000, 0x2c8a, 0x0000, 0x2c8c, 0x0000, 0x2c8e,
+       0x0000, 0x2c90, 0x0000, 0x2c92, 0x0000, 0x2c94, 0x0000, 0x2c96,
+       0x0000, 0x2c98, 0x0000, 0x2c9a, 0x0000, 0x2c9c, 0x0000, 0x2c9e,
+       0x0000, 0x2ca0, 0x0000, 0x2ca2, 0x0000, 0x2ca4, 0x0000, 0x2ca6,
+       0x0000, 0x2ca8, 0x0000, 0x2caa, 0x0000, 0x2cac, 0x0000, 0x2cae,
+       0x0000, 0x2cb0, 0x0000, 0x2cb2, 0x0000, 0x2cb4, 0x0000, 0x2cb6,
+       0x0000, 0x2cb8, 0x0000, 0x2cba, 0x0000, 0x2cbc, 0x0000, 0x2cbe,
+       0x0000, 0x2cc0, 0x0000, 0x2cc2, 0x0000, 0x2cc4, 0x0000, 0x2cc6,
+       0x0000, 0x2cc8, 0x0000, 0x2cca, 0x0000, 0x2ccc, 0x0000, 0x2cce,
+       0x0000, 0x2cd0, 0x0000, 0x2cd2, 0x0000, 0x2cd4, 0x0000, 0x2cd6,
+       0x0000, 0x2cd8, 0x0000, 0x2cda, 0x0000, 0x2cdc, 0x0000, 0x2cde,
+       0x0000, 0x2ce0, 0x0000, 0x2ce2, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_2d[256] = {
+       0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7,
+       0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af,
+       0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7,
+       0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf,
+       0x10c0, 0x10c1, 0x10c2, 0x10c3, 0x10c4, 0x10c5, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_a6[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0xa640, 0x0000, 0xa642, 0x0000, 0xa644, 0x0000, 0xa646,
+       0x0000, 0xa648, 0x0000, 0xa64a, 0x0000, 0xa64c, 0x0000, 0xa64e,
+       0x0000, 0xa650, 0x0000, 0xa652, 0x0000, 0xa654, 0x0000, 0xa656,
+       0x0000, 0xa658, 0x0000, 0xa65a, 0x0000, 0xa65c, 0x0000, 0xa65e,
+       0x0000, 0x0000, 0x0000, 0xa662, 0x0000, 0xa664, 0x0000, 0xa666,
+       0x0000, 0xa668, 0x0000, 0xa66a, 0x0000, 0xa66c, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0xa680, 0x0000, 0xa682, 0x0000, 0xa684, 0x0000, 0xa686,
+       0x0000, 0xa688, 0x0000, 0xa68a, 0x0000, 0xa68c, 0x0000, 0xa68e,
+       0x0000, 0xa690, 0x0000, 0xa692, 0x0000, 0xa694, 0x0000, 0xa696,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_a7[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0xa722, 0x0000, 0xa724, 0x0000, 0xa726,
+       0x0000, 0xa728, 0x0000, 0xa72a, 0x0000, 0xa72c, 0x0000, 0xa72e,
+       0x0000, 0x0000, 0x0000, 0xa732, 0x0000, 0xa734, 0x0000, 0xa736,
+       0x0000, 0xa738, 0x0000, 0xa73a, 0x0000, 0xa73c, 0x0000, 0xa73e,
+       0x0000, 0xa740, 0x0000, 0xa742, 0x0000, 0xa744, 0x0000, 0xa746,
+       0x0000, 0xa748, 0x0000, 0xa74a, 0x0000, 0xa74c, 0x0000, 0xa74e,
+       0x0000, 0xa750, 0x0000, 0xa752, 0x0000, 0xa754, 0x0000, 0xa756,
+       0x0000, 0xa758, 0x0000, 0xa75a, 0x0000, 0xa75c, 0x0000, 0xa75e,
+       0x0000, 0xa760, 0x0000, 0xa762, 0x0000, 0xa764, 0x0000, 0xa766,
+       0x0000, 0xa768, 0x0000, 0xa76a, 0x0000, 0xa76c, 0x0000, 0xa76e,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0xa779, 0x0000, 0xa77b, 0x0000, 0x0000, 0xa77e,
+       0x0000, 0xa780, 0x0000, 0xa782, 0x0000, 0xa784, 0x0000, 0xa786,
+       0x0000, 0x0000, 0x0000, 0x0000, 0xa78b, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t t2_ff[256] = {
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27,
+       0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f,
+       0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37,
+       0xff38, 0xff39, 0xff3a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+       0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+static const wchar_t *const toplevel[256] = {
+       t2_00, t2_01, t2_02, t2_03, t2_04, t2_05,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL, t2_1d, t2_1e, t2_1f,
+       NULL, t2_21,  NULL,  NULL, t2_24,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL, t2_2c, t2_2d,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL, t2_a6, t2_a7,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+       NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL, t2_ff,
+};
+
+/**
+ * cifs_toupper - convert a wchar_t from lower to uppercase
+ * @in: character to convert from lower to uppercase
+ *
+ * This function consults the static tables above to convert a wchar_t from
+ * lower to uppercase. In the event that there is no mapping, the original
+ * "in" character is returned.
+ */
+wchar_t
+cifs_toupper(wchar_t in)
+{
+       unsigned char idx;
+       const wchar_t *tbl;
+       wchar_t out;
+
+       /* grab upper byte */
+       idx = (in & 0xff00) >> 8;
+
+       /* find pointer to 2nd layer table */
+       tbl = toplevel[idx];
+       if (!tbl)
+               return in;
+
+       /* grab lower byte */
+       idx = in & 0xff;
+
+       /* look up character in table */
+       out = tbl[idx];
+       if (out)
+               return out;
+
+       return in;
+}
index 72f816d6cad99d4d1f81433e928d42e540295188..9bdeca12ae0e388ecda010964c5209313cb363a9 100644 (file)
@@ -190,6 +190,11 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
                                err = cn_printf(cn, "%d",
                                              task_tgid_vnr(current));
                                break;
+                       /* global pid */
+                       case 'P':
+                               err = cn_printf(cn, "%d",
+                                             task_tgid_nr(current));
+                               break;
                        /* uid */
                        case 'u':
                                err = cn_printf(cn, "%d", cred->uid);
index 761e31bacbc2022b7db0b1c81a62dc2d2bc8c788..41000305d716ea51c47ed52ddb5abe024045e958 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/rculist_bl.h>
 #include <linux/prefetch.h>
 #include <linux/ratelimit.h>
+#include <linux/list_lru.h>
 #include "internal.h"
 #include "mount.h"
 
@@ -48,7 +49,7 @@
  *   - the dcache hash table
  * s_anon bl list spinlock protects:
  *   - the s_anon list (see __d_drop)
- * dcache_lru_lock protects:
+ * dentry->d_sb->s_dentry_lru_lock protects:
  *   - the dcache lru lists and counters
  * d_lock protects:
  *   - d_flags
@@ -63,7 +64,7 @@
  * Ordering:
  * dentry->d_inode->i_lock
  *   dentry->d_lock
- *     dcache_lru_lock
+ *     dentry->d_sb->s_dentry_lru_lock
  *     dcache_hash_bucket lock
  *     s_anon lock
  *
 int sysctl_vfs_cache_pressure __read_mostly = 100;
 EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure);
 
-static __cacheline_aligned_in_smp DEFINE_SPINLOCK(dcache_lru_lock);
 __cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock);
 
 EXPORT_SYMBOL(rename_lock);
 
 static struct kmem_cache *dentry_cache __read_mostly;
 
+/**
+ * read_seqbegin_or_lock - begin a sequence number check or locking block
+ * @lock: sequence lock
+ * @seq : sequence number to be checked
+ *
+ * First try it once optimistically without taking the lock. If that fails,
+ * take the lock. The sequence number is also used as a marker for deciding
+ * whether to be a reader (even) or writer (odd).
+ * N.B. seq must be initialized to an even number to begin with.
+ */
+static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq)
+{
+       if (!(*seq & 1))        /* Even */
+               *seq = read_seqbegin(lock);
+       else                    /* Odd */
+               read_seqlock_excl(lock);
+}
+
+static inline int need_seqretry(seqlock_t *lock, int seq)
+{
+       return !(seq & 1) && read_seqretry(lock, seq);
+}
+
+static inline void done_seqretry(seqlock_t *lock, int seq)
+{
+       if (seq & 1)
+               read_sequnlock_excl(lock);
+}
+
 /*
  * This is the single most critical data structure when it comes
  * to the dcache: the hashtable for lookups. Somebody should try
@@ -117,23 +146,47 @@ struct dentry_stat_t dentry_stat = {
        .age_limit = 45,
 };
 
-static DEFINE_PER_CPU(unsigned int, nr_dentry);
+static DEFINE_PER_CPU(long, nr_dentry);
+static DEFINE_PER_CPU(long, nr_dentry_unused);
 
 #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS)
-static int get_nr_dentry(void)
+
+/*
+ * Here we resort to our own counters instead of using generic per-cpu counters
+ * for consistency with what the vfs inode code does. We are expected to harvest
+ * better code and performance by having our own specialized counters.
+ *
+ * Please note that the loop is done over all possible CPUs, not over all online
+ * CPUs. The reason for this is that we don't want to play games with CPUs going
+ * on and off. If one of them goes off, we will just keep their counters.
+ *
+ * glommer: See cffbc8a for details, and if you ever intend to change this,
+ * please update all vfs counters to match.
+ */
+static long get_nr_dentry(void)
 {
        int i;
-       int sum = 0;
+       long sum = 0;
        for_each_possible_cpu(i)
                sum += per_cpu(nr_dentry, i);
        return sum < 0 ? 0 : sum;
 }
 
+static long get_nr_dentry_unused(void)
+{
+       int i;
+       long sum = 0;
+       for_each_possible_cpu(i)
+               sum += per_cpu(nr_dentry_unused, i);
+       return sum < 0 ? 0 : sum;
+}
+
 int proc_nr_dentry(ctl_table *table, int write, void __user *buffer,
                   size_t *lenp, loff_t *ppos)
 {
        dentry_stat.nr_dentry = get_nr_dentry();
-       return proc_dointvec(table, write, buffer, lenp, ppos);
+       dentry_stat.nr_unused = get_nr_dentry_unused();
+       return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 #endif
 
@@ -229,7 +282,7 @@ static void __d_free(struct rcu_head *head)
  */
 static void d_free(struct dentry *dentry)
 {
-       BUG_ON(dentry->d_lockref.count);
+       BUG_ON((int)dentry->d_lockref.count > 0);
        this_cpu_dec(nr_dentry);
        if (dentry->d_op && dentry->d_op->d_release)
                dentry->d_op->d_release(dentry);
@@ -304,50 +357,96 @@ static void dentry_unlink_inode(struct dentry * dentry)
 }
 
 /*
- * dentry_lru_(add|del|prune|move_tail) must be called with d_lock held.
+ * The DCACHE_LRU_LIST bit is set whenever the 'd_lru' entry
+ * is in use - which includes both the "real" per-superblock
+ * LRU list _and_ the DCACHE_SHRINK_LIST use.
+ *
+ * The DCACHE_SHRINK_LIST bit is set whenever the dentry is
+ * on the shrink list (ie not on the superblock LRU list).
+ *
+ * The per-cpu "nr_dentry_unused" counters are updated with
+ * the DCACHE_LRU_LIST bit.
+ *
+ * These helper functions make sure we always follow the
+ * rules. d_lock must be held by the caller.
  */
-static void dentry_lru_add(struct dentry *dentry)
+#define D_FLAG_VERIFY(dentry,x) WARN_ON_ONCE(((dentry)->d_flags & (DCACHE_LRU_LIST | DCACHE_SHRINK_LIST)) != (x))
+static void d_lru_add(struct dentry *dentry)
 {
-       if (list_empty(&dentry->d_lru)) {
-               spin_lock(&dcache_lru_lock);
-               list_add(&dentry->d_lru, &dentry->d_sb->s_dentry_lru);
-               dentry->d_sb->s_nr_dentry_unused++;
-               dentry_stat.nr_unused++;
-               spin_unlock(&dcache_lru_lock);
-       }
+       D_FLAG_VERIFY(dentry, 0);
+       dentry->d_flags |= DCACHE_LRU_LIST;
+       this_cpu_inc(nr_dentry_unused);
+       WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
+}
+
+static void d_lru_del(struct dentry *dentry)
+{
+       D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
+       dentry->d_flags &= ~DCACHE_LRU_LIST;
+       this_cpu_dec(nr_dentry_unused);
+       WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru));
 }
 
-static void __dentry_lru_del(struct dentry *dentry)
+static void d_shrink_del(struct dentry *dentry)
 {
+       D_FLAG_VERIFY(dentry, DCACHE_SHRINK_LIST | DCACHE_LRU_LIST);
        list_del_init(&dentry->d_lru);
-       dentry->d_flags &= ~DCACHE_SHRINK_LIST;
-       dentry->d_sb->s_nr_dentry_unused--;
-       dentry_stat.nr_unused--;
+       dentry->d_flags &= ~(DCACHE_SHRINK_LIST | DCACHE_LRU_LIST);
+       this_cpu_dec(nr_dentry_unused);
+}
+
+static void d_shrink_add(struct dentry *dentry, struct list_head *list)
+{
+       D_FLAG_VERIFY(dentry, 0);
+       list_add(&dentry->d_lru, list);
+       dentry->d_flags |= DCACHE_SHRINK_LIST | DCACHE_LRU_LIST;
+       this_cpu_inc(nr_dentry_unused);
 }
 
 /*
- * Remove a dentry with references from the LRU.
+ * These can only be called under the global LRU lock, ie during the
+ * callback for freeing the LRU list. "isolate" removes it from the
+ * LRU lists entirely, while shrink_move moves it to the indicated
+ * private list.
  */
-static void dentry_lru_del(struct dentry *dentry)
+static void d_lru_isolate(struct dentry *dentry)
 {
-       if (!list_empty(&dentry->d_lru)) {
-               spin_lock(&dcache_lru_lock);
-               __dentry_lru_del(dentry);
-               spin_unlock(&dcache_lru_lock);
-       }
+       D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
+       dentry->d_flags &= ~DCACHE_LRU_LIST;
+       this_cpu_dec(nr_dentry_unused);
+       list_del_init(&dentry->d_lru);
 }
 
-static void dentry_lru_move_list(struct dentry *dentry, struct list_head *list)
+static void d_lru_shrink_move(struct dentry *dentry, struct list_head *list)
 {
-       spin_lock(&dcache_lru_lock);
-       if (list_empty(&dentry->d_lru)) {
-               list_add_tail(&dentry->d_lru, list);
-               dentry->d_sb->s_nr_dentry_unused++;
-               dentry_stat.nr_unused++;
-       } else {
-               list_move_tail(&dentry->d_lru, list);
+       D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST);
+       dentry->d_flags |= DCACHE_SHRINK_LIST;
+       list_move_tail(&dentry->d_lru, list);
+}
+
+/*
+ * dentry_lru_(add|del)_list) must be called with d_lock held.
+ */
+static void dentry_lru_add(struct dentry *dentry)
+{
+       if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST)))
+               d_lru_add(dentry);
+}
+
+/*
+ * Remove a dentry with references from the LRU.
+ *
+ * If we are on the shrink list, then we can get to try_prune_one_dentry() and
+ * lose our last reference through the parent walk. In this case, we need to
+ * remove ourselves from the shrink list, not the LRU.
+ */
+static void dentry_lru_del(struct dentry *dentry)
+{
+       if (dentry->d_flags & DCACHE_LRU_LIST) {
+               if (dentry->d_flags & DCACHE_SHRINK_LIST)
+                       return d_shrink_del(dentry);
+               d_lru_del(dentry);
        }
-       spin_unlock(&dcache_lru_lock);
 }
 
 /**
@@ -443,7 +542,8 @@ EXPORT_SYMBOL(d_drop);
  * If ref is non-zero, then decrement the refcount too.
  * Returns dentry requiring refcount drop, or NULL if we're done.
  */
-static inline struct dentry *dentry_kill(struct dentry *dentry, int ref)
+static inline struct dentry *
+dentry_kill(struct dentry *dentry, int unlock_on_failure)
        __releases(dentry->d_lock)
 {
        struct inode *inode;
@@ -452,8 +552,10 @@ static inline struct dentry *dentry_kill(struct dentry *dentry, int ref)
        inode = dentry->d_inode;
        if (inode && !spin_trylock(&inode->i_lock)) {
 relock:
-               spin_unlock(&dentry->d_lock);
-               cpu_relax();
+               if (unlock_on_failure) {
+                       spin_unlock(&dentry->d_lock);
+                       cpu_relax();
+               }
                return dentry; /* try again with same dentry */
        }
        if (IS_ROOT(dentry))
@@ -466,8 +568,11 @@ relock:
                goto relock;
        }
 
-       if (ref)
-               dentry->d_lockref.count--;
+       /*
+        * The dentry is now unrecoverably dead to the world.
+        */
+       lockref_mark_dead(&dentry->d_lockref);
+
        /*
         * inform the fs via d_prune that this dentry is about to be
         * unhashed and destroyed.
@@ -509,24 +614,22 @@ relock:
  */
 void dput(struct dentry *dentry)
 {
-       if (!dentry)
+       if (unlikely(!dentry))
                return;
 
 repeat:
-       if (dentry->d_lockref.count == 1)
-               might_sleep();
        if (lockref_put_or_lock(&dentry->d_lockref))
                return;
 
-       if (dentry->d_flags & DCACHE_OP_DELETE) {
+       /* Unreachable? Get rid of it */
+       if (unlikely(d_unhashed(dentry)))
+               goto kill_it;
+
+       if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) {
                if (dentry->d_op->d_delete(dentry))
                        goto kill_it;
        }
 
-       /* Unreachable? Get rid of it */
-       if (d_unhashed(dentry))
-               goto kill_it;
-
        dentry->d_flags |= DCACHE_REFERENCED;
        dentry_lru_add(dentry);
 
@@ -755,7 +858,7 @@ EXPORT_SYMBOL(d_prune_aliases);
  *
  * This may fail if locks cannot be acquired no problem, just try again.
  */
-static void try_prune_one_dentry(struct dentry *dentry)
+static struct dentry * try_prune_one_dentry(struct dentry *dentry)
        __releases(dentry->d_lock)
 {
        struct dentry *parent;
@@ -772,17 +875,18 @@ static void try_prune_one_dentry(struct dentry *dentry)
         * fragmentation.
         */
        if (!parent)
-               return;
+               return NULL;
        if (parent == dentry)
-               return;
+               return dentry;
 
        /* Prune ancestors. */
        dentry = parent;
        while (dentry) {
                if (lockref_put_or_lock(&dentry->d_lockref))
-                       return;
+                       return NULL;
                dentry = dentry_kill(dentry, 1);
        }
+       return NULL;
 }
 
 static void shrink_dentry_list(struct list_head *list)
@@ -794,83 +898,159 @@ static void shrink_dentry_list(struct list_head *list)
                dentry = list_entry_rcu(list->prev, struct dentry, d_lru);
                if (&dentry->d_lru == list)
                        break; /* empty */
+
+               /*
+                * Get the dentry lock, and re-verify that the dentry is
+                * this on the shrinking list. If it is, we know that
+                * DCACHE_SHRINK_LIST and DCACHE_LRU_LIST are set.
+                */
                spin_lock(&dentry->d_lock);
                if (dentry != list_entry(list->prev, struct dentry, d_lru)) {
                        spin_unlock(&dentry->d_lock);
                        continue;
                }
 
+               /*
+                * The dispose list is isolated and dentries are not accounted
+                * to the LRU here, so we can simply remove it from the list
+                * here regardless of whether it is referenced or not.
+                */
+               d_shrink_del(dentry);
+
                /*
                 * We found an inuse dentry which was not removed from
-                * the LRU because of laziness during lookup.  Do not free
-                * it - just keep it off the LRU list.
+                * the LRU because of laziness during lookup. Do not free it.
                 */
                if (dentry->d_lockref.count) {
-                       dentry_lru_del(dentry);
                        spin_unlock(&dentry->d_lock);
                        continue;
                }
-
                rcu_read_unlock();
 
-               try_prune_one_dentry(dentry);
+               /*
+                * If 'try_to_prune()' returns a dentry, it will
+                * be the same one we passed in, and d_lock will
+                * have been held the whole time, so it will not
+                * have been added to any other lists. We failed
+                * to get the inode lock.
+                *
+                * We just add it back to the shrink list.
+                */
+               dentry = try_prune_one_dentry(dentry);
 
                rcu_read_lock();
+               if (dentry) {
+                       d_shrink_add(dentry, list);
+                       spin_unlock(&dentry->d_lock);
+               }
        }
        rcu_read_unlock();
 }
 
+static enum lru_status
+dentry_lru_isolate(struct list_head *item, spinlock_t *lru_lock, void *arg)
+{
+       struct list_head *freeable = arg;
+       struct dentry   *dentry = container_of(item, struct dentry, d_lru);
+
+
+       /*
+        * we are inverting the lru lock/dentry->d_lock here,
+        * so use a trylock. If we fail to get the lock, just skip
+        * it
+        */
+       if (!spin_trylock(&dentry->d_lock))
+               return LRU_SKIP;
+
+       /*
+        * Referenced dentries are still in use. If they have active
+        * counts, just remove them from the LRU. Otherwise give them
+        * another pass through the LRU.
+        */
+       if (dentry->d_lockref.count) {
+               d_lru_isolate(dentry);
+               spin_unlock(&dentry->d_lock);
+               return LRU_REMOVED;
+       }
+
+       if (dentry->d_flags & DCACHE_REFERENCED) {
+               dentry->d_flags &= ~DCACHE_REFERENCED;
+               spin_unlock(&dentry->d_lock);
+
+               /*
+                * The list move itself will be made by the common LRU code. At
+                * this point, we've dropped the dentry->d_lock but keep the
+                * lru lock. This is safe to do, since every list movement is
+                * protected by the lru lock even if both locks are held.
+                *
+                * This is guaranteed by the fact that all LRU management
+                * functions are intermediated by the LRU API calls like
+                * list_lru_add and list_lru_del. List movement in this file
+                * only ever occur through this functions or through callbacks
+                * like this one, that are called from the LRU API.
+                *
+                * The only exceptions to this are functions like
+                * shrink_dentry_list, and code that first checks for the
+                * DCACHE_SHRINK_LIST flag.  Those are guaranteed to be
+                * operating only with stack provided lists after they are
+                * properly isolated from the main list.  It is thus, always a
+                * local access.
+                */
+               return LRU_ROTATE;
+       }
+
+       d_lru_shrink_move(dentry, freeable);
+       spin_unlock(&dentry->d_lock);
+
+       return LRU_REMOVED;
+}
+
 /**
  * prune_dcache_sb - shrink the dcache
  * @sb: superblock
- * @count: number of entries to try to free
+ * @nr_to_scan : number of entries to try to free
+ * @nid: which node to scan for freeable entities
  *
- * Attempt to shrink the superblock dcache LRU by @count entries. This is
+ * Attempt to shrink the superblock dcache LRU by @nr_to_scan entries. This is
  * done when we need more memory an called from the superblock shrinker
  * function.
  *
  * This function may fail to free any resources if all the dentries are in
  * use.
  */
-void prune_dcache_sb(struct super_block *sb, int count)
+long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan,
+                    int nid)
 {
-       struct dentry *dentry;
-       LIST_HEAD(referenced);
-       LIST_HEAD(tmp);
+       LIST_HEAD(dispose);
+       long freed;
 
-relock:
-       spin_lock(&dcache_lru_lock);
-       while (!list_empty(&sb->s_dentry_lru)) {
-               dentry = list_entry(sb->s_dentry_lru.prev,
-                               struct dentry, d_lru);
-               BUG_ON(dentry->d_sb != sb);
-
-               if (!spin_trylock(&dentry->d_lock)) {
-                       spin_unlock(&dcache_lru_lock);
-                       cpu_relax();
-                       goto relock;
-               }
+       freed = list_lru_walk_node(&sb->s_dentry_lru, nid, dentry_lru_isolate,
+                                      &dispose, &nr_to_scan);
+       shrink_dentry_list(&dispose);
+       return freed;
+}
 
-               if (dentry->d_flags & DCACHE_REFERENCED) {
-                       dentry->d_flags &= ~DCACHE_REFERENCED;
-                       list_move(&dentry->d_lru, &referenced);
-                       spin_unlock(&dentry->d_lock);
-               } else {
-                       list_move_tail(&dentry->d_lru, &tmp);
-                       dentry->d_flags |= DCACHE_SHRINK_LIST;
-                       spin_unlock(&dentry->d_lock);
-                       if (!--count)
-                               break;
-               }
-               cond_resched_lock(&dcache_lru_lock);
-       }
-       if (!list_empty(&referenced))
-               list_splice(&referenced, &sb->s_dentry_lru);
-       spin_unlock(&dcache_lru_lock);
+static enum lru_status dentry_lru_isolate_shrink(struct list_head *item,
+                                               spinlock_t *lru_lock, void *arg)
+{
+       struct list_head *freeable = arg;
+       struct dentry   *dentry = container_of(item, struct dentry, d_lru);
+
+       /*
+        * we are inverting the lru lock/dentry->d_lock here,
+        * so use a trylock. If we fail to get the lock, just skip
+        * it
+        */
+       if (!spin_trylock(&dentry->d_lock))
+               return LRU_SKIP;
+
+       d_lru_shrink_move(dentry, freeable);
+       spin_unlock(&dentry->d_lock);
 
-       shrink_dentry_list(&tmp);
+       return LRU_REMOVED;
 }
 
+
 /**
  * shrink_dcache_sb - shrink dcache for a superblock
  * @sb: superblock
@@ -880,16 +1060,17 @@ relock:
  */
 void shrink_dcache_sb(struct super_block *sb)
 {
-       LIST_HEAD(tmp);
+       long freed;
 
-       spin_lock(&dcache_lru_lock);
-       while (!list_empty(&sb->s_dentry_lru)) {
-               list_splice_init(&sb->s_dentry_lru, &tmp);
-               spin_unlock(&dcache_lru_lock);
-               shrink_dentry_list(&tmp);
-               spin_lock(&dcache_lru_lock);
-       }
-       spin_unlock(&dcache_lru_lock);
+       do {
+               LIST_HEAD(dispose);
+
+               freed = list_lru_walk(&sb->s_dentry_lru,
+                       dentry_lru_isolate_shrink, &dispose, UINT_MAX);
+
+               this_cpu_sub(nr_dentry_unused, freed);
+               shrink_dentry_list(&dispose);
+       } while (freed > 0);
 }
 EXPORT_SYMBOL(shrink_dcache_sb);
 
@@ -1009,7 +1190,7 @@ void shrink_dcache_for_umount(struct super_block *sb)
  * the parenthood after dropping the lock and check
  * that the sequence number still matches.
  */
-static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq)
+static struct dentry *try_to_ascend(struct dentry *old, unsigned seq)
 {
        struct dentry *new = old->d_parent;
 
@@ -1023,7 +1204,7 @@ static struct dentry *try_to_ascend(struct dentry *old, int locked, unsigned seq
         */
        if (new != old->d_parent ||
                 (old->d_flags & DCACHE_DENTRY_KILLED) ||
-                (!locked && read_seqretry(&rename_lock, seq))) {
+                need_seqretry(&rename_lock, seq)) {
                spin_unlock(&new->d_lock);
                new = NULL;
        }
@@ -1060,13 +1241,12 @@ static void d_walk(struct dentry *parent, void *data,
 {
        struct dentry *this_parent;
        struct list_head *next;
-       unsigned seq;
-       int locked = 0;
+       unsigned seq = 0;
        enum d_walk_ret ret;
        bool retry = true;
 
-       seq = read_seqbegin(&rename_lock);
 again:
+       read_seqbegin_or_lock(&rename_lock, &seq);
        this_parent = parent;
        spin_lock(&this_parent->d_lock);
 
@@ -1120,13 +1300,13 @@ resume:
         */
        if (this_parent != parent) {
                struct dentry *child = this_parent;
-               this_parent = try_to_ascend(this_parent, locked, seq);
+               this_parent = try_to_ascend(this_parent, seq);
                if (!this_parent)
                        goto rename_retry;
                next = child->d_u.d_child.next;
                goto resume;
        }
-       if (!locked && read_seqretry(&rename_lock, seq)) {
+       if (need_seqretry(&rename_lock, seq)) {
                spin_unlock(&this_parent->d_lock);
                goto rename_retry;
        }
@@ -1135,17 +1315,13 @@ resume:
 
 out_unlock:
        spin_unlock(&this_parent->d_lock);
-       if (locked)
-               write_sequnlock(&rename_lock);
+       done_seqretry(&rename_lock, seq);
        return;
 
 rename_retry:
        if (!retry)
                return;
-       if (locked)
-               goto again;
-       locked = 1;
-       write_seqlock(&rename_lock);
+       seq = 1;
        goto again;
 }
 
@@ -1256,8 +1432,13 @@ static enum d_walk_ret select_collect(void *_data, struct dentry *dentry)
        if (dentry->d_lockref.count) {
                dentry_lru_del(dentry);
        } else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
-               dentry_lru_move_list(dentry, &data->dispose);
-               dentry->d_flags |= DCACHE_SHRINK_LIST;
+               /*
+                * We can't use d_lru_shrink_move() because we
+                * need to get the global LRU lock and do the
+                * LRU accounting.
+                */
+               d_lru_del(dentry);
+               d_shrink_add(dentry, &data->dispose);
                data->found++;
                ret = D_WALK_NORETRY;
        }
@@ -2644,9 +2825,39 @@ static int prepend(char **buffer, int *buflen, const char *str, int namelen)
        return 0;
 }
 
+/**
+ * prepend_name - prepend a pathname in front of current buffer pointer
+ * @buffer: buffer pointer
+ * @buflen: allocated length of the buffer
+ * @name:   name string and length qstr structure
+ *
+ * With RCU path tracing, it may race with d_move(). Use ACCESS_ONCE() to
+ * make sure that either the old or the new name pointer and length are
+ * fetched. However, there may be mismatch between length and pointer.
+ * The length cannot be trusted, we need to copy it byte-by-byte until
+ * the length is reached or a null byte is found. It also prepends "/" at
+ * the beginning of the name. The sequence number check at the caller will
+ * retry it again when a d_move() does happen. So any garbage in the buffer
+ * due to mismatched pointer and length will be discarded.
+ */
 static int prepend_name(char **buffer, int *buflen, struct qstr *name)
 {
-       return prepend(buffer, buflen, name->name, name->len);
+       const char *dname = ACCESS_ONCE(name->name);
+       u32 dlen = ACCESS_ONCE(name->len);
+       char *p;
+
+       if (*buflen < dlen + 1)
+               return -ENAMETOOLONG;
+       *buflen -= dlen + 1;
+       p = *buffer -= dlen + 1;
+       *p++ = '/';
+       while (dlen--) {
+               char c = *dname++;
+               if (!c)
+                       break;
+               *p++ = c;
+       }
+       return 0;
 }
 
 /**
@@ -2656,7 +2867,15 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name)
  * @buffer: pointer to the end of the buffer
  * @buflen: pointer to buffer length
  *
- * Caller holds the rename_lock.
+ * The function will first try to write out the pathname without taking any
+ * lock other than the RCU read lock to make sure that dentries won't go away.
+ * It only checks the sequence number of the global rename_lock as any change
+ * in the dentry's d_seq will be preceded by changes in the rename_lock
+ * sequence number. If the sequence number had been changed, it will restart
+ * the whole pathname back-tracing sequence again by taking the rename_lock.
+ * In this case, there is no need to take the RCU read lock as the recursive
+ * parent pointer references will keep the dentry chain alive as long as no
+ * rename operation is performed.
  */
 static int prepend_path(const struct path *path,
                        const struct path *root,
@@ -2665,54 +2884,66 @@ static int prepend_path(const struct path *path,
        struct dentry *dentry = path->dentry;
        struct vfsmount *vfsmnt = path->mnt;
        struct mount *mnt = real_mount(vfsmnt);
-       bool slash = false;
        int error = 0;
+       unsigned seq = 0;
+       char *bptr;
+       int blen;
 
+       rcu_read_lock();
+restart:
+       bptr = *buffer;
+       blen = *buflen;
+       read_seqbegin_or_lock(&rename_lock, &seq);
        while (dentry != root->dentry || vfsmnt != root->mnt) {
                struct dentry * parent;
 
                if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
                        /* Global root? */
-                       if (!mnt_has_parent(mnt))
-                               goto global_root;
-                       dentry = mnt->mnt_mountpoint;
-                       mnt = mnt->mnt_parent;
-                       vfsmnt = &mnt->mnt;
-                       continue;
+                       if (mnt_has_parent(mnt)) {
+                               dentry = mnt->mnt_mountpoint;
+                               mnt = mnt->mnt_parent;
+                               vfsmnt = &mnt->mnt;
+                               continue;
+                       }
+                       /*
+                        * Filesystems needing to implement special "root names"
+                        * should do so with ->d_dname()
+                        */
+                       if (IS_ROOT(dentry) &&
+                          (dentry->d_name.len != 1 ||
+                           dentry->d_name.name[0] != '/')) {
+                               WARN(1, "Root dentry has weird name <%.*s>\n",
+                                    (int) dentry->d_name.len,
+                                    dentry->d_name.name);
+                       }
+                       if (!error)
+                               error = is_mounted(vfsmnt) ? 1 : 2;
+                       break;
                }
                parent = dentry->d_parent;
                prefetch(parent);
-               spin_lock(&dentry->d_lock);
-               error = prepend_name(buffer, buflen, &dentry->d_name);
-               spin_unlock(&dentry->d_lock);
-               if (!error)
-                       error = prepend(buffer, buflen, "/", 1);
+               error = prepend_name(&bptr, &blen, &dentry->d_name);
                if (error)
                        break;
 
-               slash = true;
                dentry = parent;
        }
+       if (!(seq & 1))
+               rcu_read_unlock();
+       if (need_seqretry(&rename_lock, seq)) {
+               seq = 1;
+               goto restart;
+       }
+       done_seqretry(&rename_lock, seq);
 
-       if (!error && !slash)
-               error = prepend(buffer, buflen, "/", 1);
-
-       return error;
-
-global_root:
-       /*
-        * Filesystems needing to implement special "root names"
-        * should do so with ->d_dname()
-        */
-       if (IS_ROOT(dentry) &&
-           (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) {
-               WARN(1, "Root dentry has weird name <%.*s>\n",
-                    (int) dentry->d_name.len, dentry->d_name.name);
-       }
-       if (!slash)
-               error = prepend(buffer, buflen, "/", 1);
-       if (!error)
-               error = is_mounted(vfsmnt) ? 1 : 2;
+       if (error >= 0 && bptr == *buffer) {
+               if (--blen < 0)
+                       error = -ENAMETOOLONG;
+               else
+                       *--bptr = '/';
+       }
+       *buffer = bptr;
+       *buflen = blen;
        return error;
 }
 
@@ -2741,9 +2972,7 @@ char *__d_path(const struct path *path,
 
        prepend(&res, &buflen, "\0", 1);
        br_read_lock(&vfsmount_lock);
-       write_seqlock(&rename_lock);
        error = prepend_path(path, root, &res, &buflen);
-       write_sequnlock(&rename_lock);
        br_read_unlock(&vfsmount_lock);
 
        if (error < 0)
@@ -2762,9 +2991,7 @@ char *d_absolute_path(const struct path *path,
 
        prepend(&res, &buflen, "\0", 1);
        br_read_lock(&vfsmount_lock);
-       write_seqlock(&rename_lock);
        error = prepend_path(path, &root, &res, &buflen);
-       write_sequnlock(&rename_lock);
        br_read_unlock(&vfsmount_lock);
 
        if (error > 1)
@@ -2796,6 +3023,16 @@ static int prepend_unreachable(char **buffer, int *buflen)
        return prepend(buffer, buflen, "(unreachable)", 13);
 }
 
+static void get_fs_root_rcu(struct fs_struct *fs, struct path *root)
+{
+       unsigned seq;
+
+       do {
+               seq = read_seqcount_begin(&fs->seq);
+               *root = fs->root;
+       } while (read_seqcount_retry(&fs->seq, seq));
+}
+
 /**
  * d_path - return the path of a dentry
  * @path: path to report
@@ -2828,15 +3065,15 @@ char *d_path(const struct path *path, char *buf, int buflen)
        if (path->dentry->d_op && path->dentry->d_op->d_dname)
                return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
 
-       get_fs_root(current->fs, &root);
+       rcu_read_lock();
+       get_fs_root_rcu(current->fs, &root);
        br_read_lock(&vfsmount_lock);
-       write_seqlock(&rename_lock);
        error = path_with_deleted(path, &root, &res, &buflen);
-       write_sequnlock(&rename_lock);
        br_read_unlock(&vfsmount_lock);
+       rcu_read_unlock();
+
        if (error < 0)
                res = ERR_PTR(error);
-       path_put(&root);
        return res;
 }
 EXPORT_SYMBOL(d_path);
@@ -2867,10 +3104,10 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
        char *end = buffer + buflen;
        /* these dentries are never renamed, so d_lock is not needed */
        if (prepend(&end, &buflen, " (deleted)", 11) ||
-           prepend_name(&end, &buflen, &dentry->d_name) ||
+           prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) ||
            prepend(&end, &buflen, "/", 1))  
                end = ERR_PTR(-ENAMETOOLONG);
-       return end;  
+       return end;
 }
 
 /*
@@ -2878,30 +3115,42 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
  */
 static char *__dentry_path(struct dentry *dentry, char *buf, int buflen)
 {
-       char *end = buf + buflen;
-       char *retval;
+       char *end, *retval;
+       int len, seq = 0;
+       int error = 0;
 
-       prepend(&end, &buflen, "\0", 1);
+       rcu_read_lock();
+restart:
+       end = buf + buflen;
+       len = buflen;
+       prepend(&end, &len, "\0", 1);
        if (buflen < 1)
                goto Elong;
        /* Get '/' right */
        retval = end-1;
        *retval = '/';
-
+       read_seqbegin_or_lock(&rename_lock, &seq);
        while (!IS_ROOT(dentry)) {
                struct dentry *parent = dentry->d_parent;
                int error;
 
                prefetch(parent);
-               spin_lock(&dentry->d_lock);
-               error = prepend_name(&end, &buflen, &dentry->d_name);
-               spin_unlock(&dentry->d_lock);
-               if (error != 0 || prepend(&end, &buflen, "/", 1) != 0)
-                       goto Elong;
+               error = prepend_name(&end, &len, &dentry->d_name);
+               if (error)
+                       break;
 
                retval = end;
                dentry = parent;
        }
+       if (!(seq & 1))
+               rcu_read_unlock();
+       if (need_seqretry(&rename_lock, seq)) {
+               seq = 1;
+               goto restart;
+       }
+       done_seqretry(&rename_lock, seq);
+       if (error)
+               goto Elong;
        return retval;
 Elong:
        return ERR_PTR(-ENAMETOOLONG);
@@ -2909,13 +3158,7 @@ Elong:
 
 char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen)
 {
-       char *retval;
-
-       write_seqlock(&rename_lock);
-       retval = __dentry_path(dentry, buf, buflen);
-       write_sequnlock(&rename_lock);
-
-       return retval;
+       return __dentry_path(dentry, buf, buflen);
 }
 EXPORT_SYMBOL(dentry_path_raw);
 
@@ -2924,7 +3167,6 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)
        char *p = NULL;
        char *retval;
 
-       write_seqlock(&rename_lock);
        if (d_unlinked(dentry)) {
                p = buf + buflen;
                if (prepend(&p, &buflen, "//deleted", 10) != 0)
@@ -2932,7 +3174,6 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)
                buflen++;
        }
        retval = __dentry_path(dentry, buf, buflen);
-       write_sequnlock(&rename_lock);
        if (!IS_ERR(retval) && p)
                *p = '/';       /* restore '/' overriden with '\0' */
        return retval;
@@ -2940,6 +3181,18 @@ Elong:
        return ERR_PTR(-ENAMETOOLONG);
 }
 
+static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root,
+                                   struct path *pwd)
+{
+       unsigned seq;
+
+       do {
+               seq = read_seqcount_begin(&fs->seq);
+               *root = fs->root;
+               *pwd = fs->pwd;
+       } while (read_seqcount_retry(&fs->seq, seq));
+}
+
 /*
  * NOTE! The user-level library version returns a
  * character pointer. The kernel system call just
@@ -2962,25 +3215,25 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
 {
        int error;
        struct path pwd, root;
-       char *page = (char *) __get_free_page(GFP_USER);
+       char *page = __getname();
 
        if (!page)
                return -ENOMEM;
 
-       get_fs_root_and_pwd(current->fs, &root, &pwd);
+       rcu_read_lock();
+       get_fs_root_and_pwd_rcu(current->fs, &root, &pwd);
 
        error = -ENOENT;
        br_read_lock(&vfsmount_lock);
-       write_seqlock(&rename_lock);
        if (!d_unlinked(pwd.dentry)) {
                unsigned long len;
-               char *cwd = page + PAGE_SIZE;
-               int buflen = PAGE_SIZE;
+               char *cwd = page + PATH_MAX;
+               int buflen = PATH_MAX;
 
                prepend(&cwd, &buflen, "\0", 1);
                error = prepend_path(&pwd, &root, &cwd, &buflen);
-               write_sequnlock(&rename_lock);
                br_read_unlock(&vfsmount_lock);
+               rcu_read_unlock();
 
                if (error < 0)
                        goto out;
@@ -2993,21 +3246,19 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size)
                }
 
                error = -ERANGE;
-               len = PAGE_SIZE + page - cwd;
+               len = PATH_MAX + page - cwd;
                if (len <= size) {
                        error = len;
                        if (copy_to_user(buf, cwd, len))
                                error = -EFAULT;
                }
        } else {
-               write_sequnlock(&rename_lock);
                br_read_unlock(&vfsmount_lock);
+               rcu_read_unlock();
        }
 
 out:
-       path_put(&pwd);
-       path_put(&root);
-       free_page((unsigned long) page);
+       __putname(page);
        return error;
 }
 
index 1782023bd68a6655d6def2258263d22080c06c33..0e04142d5962312fcb055738479247b2364a252e 100644 (file)
@@ -544,6 +544,7 @@ static inline int dio_bio_reap(struct dio *dio, struct dio_submit *sdio)
  */
 static int sb_init_dio_done_wq(struct super_block *sb)
 {
+       struct workqueue_struct *old;
        struct workqueue_struct *wq = alloc_workqueue("dio/%s",
                                                      WQ_MEM_RECLAIM, 0,
                                                      sb->s_id);
@@ -552,9 +553,9 @@ static int sb_init_dio_done_wq(struct super_block *sb)
        /*
         * This has to be atomic as more DIOs can race to create the workqueue
         */
-       cmpxchg(&sb->s_dio_done_wq, NULL, wq);
+       old = cmpxchg(&sb->s_dio_done_wq, NULL, wq);
        /* Someone created workqueue before us? Free ours... */
-       if (wq != sb->s_dio_done_wq)
+       if (old)
                destroy_workqueue(wq);
        return 0;
 }
index c00e055b62820945bef291fa68b145a4d7145667..9fd702f5bfb2886a715e787b6470615ea07021e0 100644 (file)
@@ -44,6 +44,7 @@ static void drop_slab(void)
                .gfp_mask = GFP_KERNEL,
        };
 
+       nodes_setall(shrink.nodes_to_scan);
        do {
                nr_objects = shrink_slab(&shrink, 1000, 1000);
        } while (nr_objects > 10);
index d10757635b9c9360288e18217b28de298fc48407..c88e355f7635f61e59f58cb4acc617b84928e4e5 100644 (file)
@@ -609,39 +609,35 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
        char *full_alg_name;
        int rc = -EINVAL;
 
-       if (!crypt_stat->cipher) {
-               ecryptfs_printk(KERN_ERR, "No cipher specified\n");
-               goto out;
-       }
        ecryptfs_printk(KERN_DEBUG,
                        "Initializing cipher [%s]; strlen = [%d]; "
                        "key_size_bits = [%zd]\n",
                        crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
                        crypt_stat->key_size << 3);
+       mutex_lock(&crypt_stat->cs_tfm_mutex);
        if (crypt_stat->tfm) {
                rc = 0;
-               goto out;
+               goto out_unlock;
        }
-       mutex_lock(&crypt_stat->cs_tfm_mutex);
        rc = ecryptfs_crypto_api_algify_cipher_name(&full_alg_name,
                                                    crypt_stat->cipher, "cbc");
        if (rc)
                goto out_unlock;
        crypt_stat->tfm = crypto_alloc_ablkcipher(full_alg_name, 0, 0);
-       kfree(full_alg_name);
        if (IS_ERR(crypt_stat->tfm)) {
                rc = PTR_ERR(crypt_stat->tfm);
                crypt_stat->tfm = NULL;
                ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
                                "Error initializing cipher [%s]\n",
-                               crypt_stat->cipher);
-               goto out_unlock;
+                               full_alg_name);
+               goto out_free;
        }
        crypto_ablkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);
        rc = 0;
+out_free:
+       kfree(full_alg_name);
 out_unlock:
        mutex_unlock(&crypt_stat->cs_tfm_mutex);
-out:
        return rc;
 }
 
index 293f86741ddb08a0bc625c3a7fdccbbe96ad7486..473e09da7d02d3396273221f3094824c91f3b030 100644 (file)
@@ -740,6 +740,7 @@ static void ep_free(struct eventpoll *ep)
                epi = rb_entry(rbp, struct epitem, rbn);
 
                ep_unregister_pollwait(ep, epi);
+               cond_resched();
        }
 
        /*
@@ -754,6 +755,7 @@ static void ep_free(struct eventpoll *ep)
        while ((rbp = rb_first(&ep->rbr)) != NULL) {
                epi = rb_entry(rbp, struct epitem, rbn);
                ep_remove(ep, epi);
+               cond_resched();
        }
        mutex_unlock(&ep->mtx);
 
index fd774c7cb4831be8817799ed6cab355a368fa19f..8875dd10ae7ac77444db95e33c9fde83dde67512 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -74,6 +74,8 @@ static DEFINE_RWLOCK(binfmt_lock);
 void __register_binfmt(struct linux_binfmt * fmt, int insert)
 {
        BUG_ON(!fmt);
+       if (WARN_ON(!fmt->load_binary))
+               return;
        write_lock(&binfmt_lock);
        insert ? list_add(&fmt->lh, &formats) :
                 list_add_tail(&fmt->lh, &formats);
@@ -266,7 +268,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
        BUILD_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 | VM_STACK_INCOMPLETE_SETUP;
+       vma->vm_flags = VM_SOFTDIRTY | 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);
 
@@ -1365,18 +1367,18 @@ out:
 }
 EXPORT_SYMBOL(remove_arg_zero);
 
+#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
 /*
  * cycle the list of binary formats handler, until one recognizes the image
  */
 int search_binary_handler(struct linux_binprm *bprm)
 {
-       unsigned int depth = bprm->recursion_depth;
-       int try,retval;
+       bool need_retry = IS_ENABLED(CONFIG_MODULES);
        struct linux_binfmt *fmt;
-       pid_t old_pid, old_vpid;
+       int retval;
 
        /* This allows 4 levels of binfmt rewrites before failing hard. */
-       if (depth > 5)
+       if (bprm->recursion_depth > 5)
                return -ELOOP;
 
        retval = security_bprm_check(bprm);
@@ -1387,71 +1389,67 @@ int search_binary_handler(struct linux_binprm *bprm)
        if (retval)
                return retval;
 
+       retval = -ENOENT;
+ retry:
+       read_lock(&binfmt_lock);
+       list_for_each_entry(fmt, &formats, lh) {
+               if (!try_module_get(fmt->module))
+                       continue;
+               read_unlock(&binfmt_lock);
+               bprm->recursion_depth++;
+               retval = fmt->load_binary(bprm);
+               bprm->recursion_depth--;
+               if (retval >= 0 || retval != -ENOEXEC ||
+                   bprm->mm == NULL || bprm->file == NULL) {
+                       put_binfmt(fmt);
+                       return retval;
+               }
+               read_lock(&binfmt_lock);
+               put_binfmt(fmt);
+       }
+       read_unlock(&binfmt_lock);
+
+       if (need_retry && retval == -ENOEXEC) {
+               if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
+                   printable(bprm->buf[2]) && printable(bprm->buf[3]))
+                       return retval;
+               if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0)
+                       return retval;
+               need_retry = false;
+               goto retry;
+       }
+
+       return retval;
+}
+EXPORT_SYMBOL(search_binary_handler);
+
+static int exec_binprm(struct linux_binprm *bprm)
+{
+       pid_t old_pid, old_vpid;
+       int ret;
+
        /* Need to fetch pid before load_binary changes it */
        old_pid = current->pid;
        rcu_read_lock();
        old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
        rcu_read_unlock();
 
-       retval = -ENOENT;
-       for (try=0; try<2; try++) {
-               read_lock(&binfmt_lock);
-               list_for_each_entry(fmt, &formats, lh) {
-                       int (*fn)(struct linux_binprm *) = fmt->load_binary;
-                       if (!fn)
-                               continue;
-                       if (!try_module_get(fmt->module))
-                               continue;
-                       read_unlock(&binfmt_lock);
-                       bprm->recursion_depth = depth + 1;
-                       retval = fn(bprm);
-                       bprm->recursion_depth = depth;
-                       if (retval >= 0) {
-                               if (depth == 0) {
-                                       trace_sched_process_exec(current, old_pid, bprm);
-                                       ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
-                               }
-                               put_binfmt(fmt);
-                               allow_write_access(bprm->file);
-                               if (bprm->file)
-                                       fput(bprm->file);
-                               bprm->file = NULL;
-                               current->did_exec = 1;
-                               proc_exec_connector(current);
-                               return retval;
-                       }
-                       read_lock(&binfmt_lock);
-                       put_binfmt(fmt);
-                       if (retval != -ENOEXEC || bprm->mm == NULL)
-                               break;
-                       if (!bprm->file) {
-                               read_unlock(&binfmt_lock);
-                               return retval;
-                       }
+       ret = search_binary_handler(bprm);
+       if (ret >= 0) {
+               trace_sched_process_exec(current, old_pid, bprm);
+               ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
+               current->did_exec = 1;
+               proc_exec_connector(current);
+
+               if (bprm->file) {
+                       allow_write_access(bprm->file);
+                       fput(bprm->file);
+                       bprm->file = NULL; /* to catch use-after-free */
                }
-               read_unlock(&binfmt_lock);
-#ifdef CONFIG_MODULES
-               if (retval != -ENOEXEC || bprm->mm == NULL) {
-                       break;
-               } else {
-#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
-                       if (printable(bprm->buf[0]) &&
-                           printable(bprm->buf[1]) &&
-                           printable(bprm->buf[2]) &&
-                           printable(bprm->buf[3]))
-                               break; /* -ENOEXEC */
-                       if (try)
-                               break; /* -ENOEXEC */
-                       request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
-               }
-#else
-               break;
-#endif
        }
-       return retval;
-}
 
-EXPORT_SYMBOL(search_binary_handler);
+       return ret;
+}
 
 /*
  * sys_execve() executes a new program.
@@ -1541,7 +1539,7 @@ static int do_execve_common(const char *filename,
        if (retval < 0)
                goto out;
 
-       retval = search_binary_handler(bprm);
+       retval = exec_binprm(bprm);
        if (retval < 0)
                goto out;
 
index 2ec8eb1ab269ae292d338d5d97ee48990af5b2c7..a52a5d23c30bcfac672df7197c51b966cc087787 100644 (file)
@@ -861,7 +861,7 @@ static int exofs_writepage(struct page *page, struct writeback_control *wbc)
 static void _write_failed(struct inode *inode, loff_t to)
 {
        if (to > inode->i_size)
-               truncate_pagecache(inode, to, inode->i_size);
+               truncate_pagecache(inode, inode->i_size);
 }
 
 int exofs_write_begin(struct file *file, struct address_space *mapping,
index 293bc2e47a735807a75eaad424764315172367b6..a235f0016889b557e06d6273f0f3dca7d873a608 100644 (file)
@@ -231,7 +231,7 @@ static int filldir_one(void * __buf, const char * name, int len,
        int result = 0;
 
        buf->sequence++;
-       if (buf->ino == ino) {
+       if (buf->ino == ino && len <= NAME_MAX) {
                memcpy(buf->name, name, len);
                buf->name[len] = '\0';
                buf->found = 1;
index 0a87bb10998dc00070bc6d05d6f536c21de44e3a..c260de6d7b6df9e5350ecfc019f41ed6def75470 100644 (file)
@@ -58,7 +58,7 @@ 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);
+               truncate_pagecache(inode, inode->i_size);
                ext2_truncate_blocks(inode, inode->i_size);
        }
 }
index 2d1bdbe78c0408402c2eff05fac8f781d393f074..3981ff7839503df43a56ff282cd570d522bf764e 100644 (file)
@@ -931,13 +931,15 @@ static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,
        struct ext4_inode_info *ei;
        struct list_head *cur, *tmp;
        LIST_HEAD(skipped);
-       int ret, nr_shrunk = 0;
+       int nr_shrunk = 0;
        int retried = 0, skip_precached = 1, nr_skipped = 0;
 
        spin_lock(&sbi->s_es_lru_lock);
 
 retry:
        list_for_each_safe(cur, tmp, &sbi->s_es_lru) {
+               int shrunk;
+
                /*
                 * If we have already reclaimed all extents from extent
                 * status tree, just stop the loop immediately.
@@ -964,13 +966,13 @@ retry:
                        continue;
 
                write_lock(&ei->i_es_lock);
-               ret = __es_try_to_reclaim_extents(ei, nr_to_scan);
+               shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan);
                if (ei->i_es_lru_nr == 0)
                        list_del_init(&ei->i_es_lru);
                write_unlock(&ei->i_es_lock);
 
-               nr_shrunk += ret;
-               nr_to_scan -= ret;
+               nr_shrunk += shrunk;
+               nr_to_scan -= shrunk;
                if (nr_to_scan == 0)
                        break;
        }
@@ -1007,7 +1009,20 @@ retry:
        return nr_shrunk;
 }
 
-static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long ext4_es_count(struct shrinker *shrink,
+                                  struct shrink_control *sc)
+{
+       unsigned long nr;
+       struct ext4_sb_info *sbi;
+
+       sbi = container_of(shrink, struct ext4_sb_info, s_es_shrinker);
+       nr = percpu_counter_read_positive(&sbi->s_extent_cache_cnt);
+       trace_ext4_es_shrink_enter(sbi->s_sb, sc->nr_to_scan, nr);
+       return nr;
+}
+
+static unsigned long ext4_es_scan(struct shrinker *shrink,
+                                 struct shrink_control *sc)
 {
        struct ext4_sb_info *sbi = container_of(shrink,
                                        struct ext4_sb_info, s_es_shrinker);
@@ -1022,9 +1037,8 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc)
 
        nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL);
 
-       ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt);
        trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret);
-       return ret;
+       return nr_shrunk;
 }
 
 void ext4_es_register_shrinker(struct ext4_sb_info *sbi)
@@ -1032,7 +1046,8 @@ void ext4_es_register_shrinker(struct ext4_sb_info *sbi)
        INIT_LIST_HEAD(&sbi->s_es_lru);
        spin_lock_init(&sbi->s_es_lru_lock);
        sbi->s_es_last_sorted = 0;
-       sbi->s_es_shrinker.shrink = ext4_es_shrink;
+       sbi->s_es_shrinker.scan_objects = ext4_es_scan;
+       sbi->s_es_shrinker.count_objects = ext4_es_count;
        sbi->s_es_shrinker.seeks = DEFAULT_SEEKS;
        register_shrinker(&sbi->s_es_shrinker);
 }
@@ -1076,7 +1091,7 @@ static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei,
        struct ext4_es_tree *tree = &ei->i_es_tree;
        struct rb_node *node;
        struct extent_status *es;
-       int nr_shrunk = 0;
+       unsigned long nr_shrunk = 0;
        static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
                                      DEFAULT_RATELIMIT_BURST);
 
index c79fd7dabe7953898f64b28101c8057fb7139119..0d424d7ac02b0a30f98e713bb10403e90ced51b5 100644 (file)
@@ -4587,7 +4587,6 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
 
        if (attr->ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
                handle_t *handle;
-               loff_t oldsize = inode->i_size;
 
                if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) {
                        struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
@@ -4650,7 +4649,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                 * Truncate pagecache after we've waited for commit
                 * in data=journal mode to make pages freeable.
                 */
-               truncate_pagecache(inode, oldsize, inode->i_size);
+                       truncate_pagecache(inode, inode->i_size);
        }
        /*
         * We want to call ext4_truncate() even if attr->ia_size ==
index 11b51bb55b42b03187fc8436125e986c0cdcc047..0062da21dd8b7995aa1764bfd943cde9d2e22364 100644 (file)
@@ -147,7 +147,7 @@ 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);
+               truncate_pagecache(inode, inode->i_size);
                fat_truncate_blocks(inode, inode->i_size);
        }
 }
index 322cd37626cbc6de1e75ec5bdd6e4010d851e730..abdd15ad13c9c52bf672465787e3811c06ef7224 100644 (file)
@@ -311,8 +311,7 @@ void fput(struct file *file)
                                return;
                        /*
                         * After this task has run exit_task_work(),
-                        * task_work_add() will fail.  free_ipc_ns()->
-                        * shm_destroy() can do this.  Fall through to delayed
+                        * task_work_add() will fail.  Fall through to delayed
                         * fput to avoid leaking *file.
                         */
                }
index 68851ff2fd41c04385c5d237d8ef4a109680bc0b..9f4935b8f2087eb44475bf7fb8aab20f44889e86 100644 (file)
@@ -69,7 +69,7 @@ static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
 {
        struct super_block *sb = inode->i_sb;
 
-       if (strcmp(sb->s_type->name, "bdev") == 0)
+       if (sb_is_blkdev_sb(sb))
                return inode->i_mapping->backing_dev_info;
 
        return sb->s_bdi;
@@ -251,11 +251,13 @@ static int move_expired_inodes(struct list_head *delaying_queue,
                if (work->older_than_this &&
                    inode_dirtied_after(inode, *work->older_than_this))
                        break;
+               list_move(&inode->i_wb_list, &tmp);
+               moved++;
+               if (sb_is_blkdev_sb(inode->i_sb))
+                       continue;
                if (sb && sb != inode->i_sb)
                        do_sb_sort = 1;
                sb = inode->i_sb;
-               list_move(&inode->i_wb_list, &tmp);
-               moved++;
        }
 
        /* just one sb in list, splice to dispatch_queue and we're done */
@@ -723,7 +725,7 @@ static long __writeback_inodes_wb(struct bdi_writeback *wb,
        return wrote;
 }
 
-long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
+static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
                                enum wb_reason reason)
 {
        struct wb_writeback_work work = {
@@ -1049,10 +1051,8 @@ void wakeup_flusher_threads(long nr_pages, enum wb_reason reason)
 {
        struct backing_dev_info *bdi;
 
-       if (!nr_pages) {
-               nr_pages = global_page_state(NR_FILE_DIRTY) +
-                               global_page_state(NR_UNSTABLE_NFS);
-       }
+       if (!nr_pages)
+               nr_pages = get_nr_dirty_pages();
 
        rcu_read_lock();
        list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) {
@@ -1173,6 +1173,8 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                        bool wakeup_bdi = false;
                        bdi = inode_to_bdi(inode);
 
+                       spin_unlock(&inode->i_lock);
+                       spin_lock(&bdi->wb.list_lock);
                        if (bdi_cap_writeback_dirty(bdi)) {
                                WARN(!test_bit(BDI_registered, &bdi->state),
                                     "bdi-%s not registered\n", bdi->name);
@@ -1187,8 +1189,6 @@ void __mark_inode_dirty(struct inode *inode, int flags)
                                        wakeup_bdi = true;
                        }
 
-                       spin_unlock(&inode->i_lock);
-                       spin_lock(&bdi->wb.list_lock);
                        inode->dirtied_when = jiffies;
                        list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
                        spin_unlock(&bdi->wb.list_lock);
index 0e91a3c9fdb2018abfcd2588d859876c78b545fd..b2a86e324aac05f7bf64b7ce0d0e2c30d91f3d68 100644 (file)
@@ -558,3 +558,75 @@ void __fscache_cookie_put(struct fscache_cookie *cookie)
 
        _leave("");
 }
+
+/*
+ * check the consistency between the netfs inode and the backing cache
+ *
+ * NOTE: it only serves no-index type
+ */
+int __fscache_check_consistency(struct fscache_cookie *cookie)
+{
+       struct fscache_operation *op;
+       struct fscache_object *object;
+       int ret;
+
+       _enter("%p,", cookie);
+
+       ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE);
+
+       if (fscache_wait_for_deferred_lookup(cookie) < 0)
+               return -ERESTARTSYS;
+
+       if (hlist_empty(&cookie->backing_objects))
+               return 0;
+
+       op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY);
+       if (!op)
+               return -ENOMEM;
+
+       fscache_operation_init(op, NULL, NULL);
+       op->flags = FSCACHE_OP_MYTHREAD |
+               (1 << FSCACHE_OP_WAITING) |
+               (1 << FSCACHE_OP_UNUSE_COOKIE);
+
+       spin_lock(&cookie->lock);
+
+       if (hlist_empty(&cookie->backing_objects))
+               goto inconsistent;
+       object = hlist_entry(cookie->backing_objects.first,
+                            struct fscache_object, cookie_link);
+       if (test_bit(FSCACHE_IOERROR, &object->cache->flags))
+               goto inconsistent;
+
+       op->debug_id = atomic_inc_return(&fscache_op_debug_id);
+
+       atomic_inc(&cookie->n_active);
+       if (fscache_submit_op(object, op) < 0)
+               goto submit_failed;
+
+       /* the work queue now carries its own ref on the object */
+       spin_unlock(&cookie->lock);
+
+       ret = fscache_wait_for_operation_activation(object, op,
+                                                   NULL, NULL, NULL);
+       if (ret == 0) {
+               /* ask the cache to honour the operation */
+               ret = object->cache->ops->check_consistency(op);
+               fscache_op_complete(op, false);
+       } else if (ret == -ENOBUFS) {
+               ret = 0;
+       }
+
+       fscache_put_operation(op);
+       _leave(" = %d", ret);
+       return ret;
+
+submit_failed:
+       atomic_dec(&cookie->n_active);
+inconsistent:
+       spin_unlock(&cookie->lock);
+       kfree(op);
+       _leave(" = -ESTALE");
+       return -ESTALE;
+}
+EXPORT_SYMBOL(__fscache_check_consistency);
index 12d505bedb5c2ce6a808948b5ee082bca9e127cc..4226f6680b06b7ff5dae4c3934009dab2ef18201 100644 (file)
@@ -130,6 +130,12 @@ extern void fscache_operation_gc(struct work_struct *);
 /*
  * page.c
  */
+extern int fscache_wait_for_deferred_lookup(struct fscache_cookie *);
+extern int fscache_wait_for_operation_activation(struct fscache_object *,
+                                                struct fscache_operation *,
+                                                atomic_t *,
+                                                atomic_t *,
+                                                void (*)(struct fscache_operation *));
 extern void fscache_invalidate_writes(struct fscache_cookie *);
 
 /*
index d479ab3c63e487ba097ff2b865c34401a9fcbfcb..73899c1c34494555d73dd5714ecb21eb74c0296d 100644 (file)
@@ -278,7 +278,7 @@ static struct fscache_retrieval *fscache_alloc_retrieval(
 /*
  * wait for a deferred lookup to complete
  */
-static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
+int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie)
 {
        unsigned long jif;
 
@@ -322,42 +322,46 @@ static void fscache_do_cancel_retrieval(struct fscache_operation *_op)
 /*
  * wait for an object to become active (or dead)
  */
-static int fscache_wait_for_retrieval_activation(struct fscache_object *object,
-                                                struct fscache_retrieval *op,
-                                                atomic_t *stat_op_waits,
-                                                atomic_t *stat_object_dead)
+int fscache_wait_for_operation_activation(struct fscache_object *object,
+                                         struct fscache_operation *op,
+                                         atomic_t *stat_op_waits,
+                                         atomic_t *stat_object_dead,
+                                         void (*do_cancel)(struct fscache_operation *))
 {
        int ret;
 
-       if (!test_bit(FSCACHE_OP_WAITING, &op->op.flags))
+       if (!test_bit(FSCACHE_OP_WAITING, &op->flags))
                goto check_if_dead;
 
        _debug(">>> WT");
-       fscache_stat(stat_op_waits);
-       if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
+       if (stat_op_waits)
+               fscache_stat(stat_op_waits);
+       if (wait_on_bit(&op->flags, FSCACHE_OP_WAITING,
                        fscache_wait_bit_interruptible,
                        TASK_INTERRUPTIBLE) != 0) {
-               ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval);
+               ret = fscache_cancel_op(op, do_cancel);
                if (ret == 0)
                        return -ERESTARTSYS;
 
                /* it's been removed from the pending queue by another party,
                 * so we should get to run shortly */
-               wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING,
+               wait_on_bit(&op->flags, FSCACHE_OP_WAITING,
                            fscache_wait_bit, TASK_UNINTERRUPTIBLE);
        }
        _debug("<<< GO");
 
 check_if_dead:
-       if (op->op.state == FSCACHE_OP_ST_CANCELLED) {
-               fscache_stat(stat_object_dead);
+       if (op->state == FSCACHE_OP_ST_CANCELLED) {
+               if (stat_object_dead)
+                       fscache_stat(stat_object_dead);
                _leave(" = -ENOBUFS [cancelled]");
                return -ENOBUFS;
        }
        if (unlikely(fscache_object_is_dead(object))) {
-               pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state);
-               fscache_cancel_op(&op->op, fscache_do_cancel_retrieval);
-               fscache_stat(stat_object_dead);
+               pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->state);
+               fscache_cancel_op(op, do_cancel);
+               if (stat_object_dead)
+                       fscache_stat(stat_object_dead);
                return -ENOBUFS;
        }
        return 0;
@@ -432,10 +436,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie,
 
        /* we wait for the operation to become active, and then process it
         * *here*, in this thread, and not in the thread pool */
-       ret = fscache_wait_for_retrieval_activation(
-               object, op,
+       ret = fscache_wait_for_operation_activation(
+               object, &op->op,
                __fscache_stat(&fscache_n_retrieval_op_waits),
-               __fscache_stat(&fscache_n_retrievals_object_dead));
+               __fscache_stat(&fscache_n_retrievals_object_dead),
+               fscache_do_cancel_retrieval);
        if (ret < 0)
                goto error;
 
@@ -557,10 +562,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie,
 
        /* we wait for the operation to become active, and then process it
         * *here*, in this thread, and not in the thread pool */
-       ret = fscache_wait_for_retrieval_activation(
-               object, op,
+       ret = fscache_wait_for_operation_activation(
+               object, &op->op,
                __fscache_stat(&fscache_n_retrieval_op_waits),
-               __fscache_stat(&fscache_n_retrievals_object_dead));
+               __fscache_stat(&fscache_n_retrievals_object_dead),
+               fscache_do_cancel_retrieval);
        if (ret < 0)
                goto error;
 
@@ -658,10 +664,11 @@ int __fscache_alloc_page(struct fscache_cookie *cookie,
 
        fscache_stat(&fscache_n_alloc_ops);
 
-       ret = fscache_wait_for_retrieval_activation(
-               object, op,
+       ret = fscache_wait_for_operation_activation(
+               object, &op->op,
                __fscache_stat(&fscache_n_alloc_op_waits),
-               __fscache_stat(&fscache_n_allocs_object_dead));
+               __fscache_stat(&fscache_n_allocs_object_dead),
+               fscache_do_cancel_retrieval);
        if (ret < 0)
                goto error;
 
@@ -693,6 +700,22 @@ nobufs:
 }
 EXPORT_SYMBOL(__fscache_alloc_page);
 
+/*
+ * Unmark pages allocate in the readahead code path (via:
+ * fscache_readpages_or_alloc) after delegating to the base filesystem
+ */
+void __fscache_readpages_cancel(struct fscache_cookie *cookie,
+                               struct list_head *pages)
+{
+       struct page *page;
+
+       list_for_each_entry(page, pages, lru) {
+               if (PageFsCache(page))
+                       __fscache_uncache_page(cookie, page);
+       }
+}
+EXPORT_SYMBOL(__fscache_readpages_cancel);
+
 /*
  * release a write op reference
  */
@@ -890,7 +913,7 @@ int __fscache_write_page(struct fscache_cookie *cookie,
                (1 << FSCACHE_OP_WAITING) |
                (1 << FSCACHE_OP_UNUSE_COOKIE);
 
-       ret = radix_tree_preload(gfp & ~__GFP_HIGHMEM);
+       ret = radix_tree_maybe_preload(gfp & ~__GFP_HIGHMEM);
        if (ret < 0)
                goto nomem_free;
 
index 1d55f94654000dbc8e8c0de37e0cb32471e3791a..ef74ad5fd362b193d858fdd2cfe3335d951d2a99 100644 (file)
@@ -1765,11 +1765,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
 /* Look up request on processing list by unique ID */
 static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
 {
-       struct list_head *entry;
+       struct fuse_req *req;
 
-       list_for_each(entry, &fc->processing) {
-               struct fuse_req *req;
-               req = list_entry(entry, struct fuse_req, list);
+       list_for_each_entry(req, &fc->processing, list) {
                if (req->in.h.unique == unique || req->intr_unique == unique)
                        return req;
        }
index 0e6961aae6c02e04414e432abb8b62826907bfbf..62b43b577bfce40b116a7a8eb77a91cea1c8b7b4 100644 (file)
@@ -1177,6 +1177,8 @@ static int parse_dirfile(char *buf, size_t nbytes, struct file *file,
                        return -EIO;
                if (reclen > nbytes)
                        break;
+               if (memchr(dirent->name, '/', dirent->namelen) != NULL)
+                       return -EIO;
 
                if (!dir_emit(ctx, dirent->name, dirent->namelen,
                               dirent->ino, dirent->type))
@@ -1315,6 +1317,8 @@ static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
                        return -EIO;
                if (reclen > nbytes)
                        break;
+               if (memchr(dirent->name, '/', dirent->namelen) != NULL)
+                       return -EIO;
 
                if (!over) {
                        /* We fill entries into dstbuf only as much as
@@ -1585,6 +1589,7 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
                    struct file *file)
 {
        struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_inode *fi = get_fuse_inode(inode);
        struct fuse_req *req;
        struct fuse_setattr_in inarg;
        struct fuse_attr_out outarg;
@@ -1612,8 +1617,10 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
-       if (is_truncate)
+       if (is_truncate) {
                fuse_set_nowrite(inode);
+               set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+       }
 
        memset(&inarg, 0, sizeof(inarg));
        memset(&outarg, 0, sizeof(outarg));
@@ -1671,16 +1678,18 @@ int fuse_do_setattr(struct inode *inode, struct iattr *attr,
         * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
         */
        if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
-               truncate_pagecache(inode, oldsize, outarg.attr.size);
+               truncate_pagecache(inode, outarg.attr.size);
                invalidate_inode_pages2(inode->i_mapping);
        }
 
+       clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
        return 0;
 
 error:
        if (is_truncate)
                fuse_release_nowrite(inode);
 
+       clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
        return err;
 }
 
@@ -1744,6 +1753,8 @@ static int fuse_setxattr(struct dentry *entry, const char *name,
                fc->no_setxattr = 1;
                err = -EOPNOTSUPP;
        }
+       if (!err)
+               fuse_invalidate_attr(inode);
        return err;
 }
 
@@ -1873,6 +1884,8 @@ static int fuse_removexattr(struct dentry *entry, const char *name)
                fc->no_removexattr = 1;
                err = -EOPNOTSUPP;
        }
+       if (!err)
+               fuse_invalidate_attr(inode);
        return err;
 }
 
index 5c121fe19c5f9b6122b687cc14bbcd7b1bbe0dc9..d409deafc67b2f6c94fb3fa53b96a21c60585d56 100644 (file)
@@ -629,7 +629,8 @@ static void fuse_read_update_size(struct inode *inode, loff_t size,
        struct fuse_inode *fi = get_fuse_inode(inode);
 
        spin_lock(&fc->lock);
-       if (attr_ver == fi->attr_version && size < inode->i_size) {
+       if (attr_ver == fi->attr_version && size < inode->i_size &&
+           !test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
                fi->attr_version = ++fc->attr_version;
                i_size_write(inode, size);
        }
@@ -1032,12 +1033,16 @@ static ssize_t fuse_perform_write(struct file *file,
 {
        struct inode *inode = mapping->host;
        struct fuse_conn *fc = get_fuse_conn(inode);
+       struct fuse_inode *fi = get_fuse_inode(inode);
        int err = 0;
        ssize_t res = 0;
 
        if (is_bad_inode(inode))
                return -EIO;
 
+       if (inode->i_size < pos + iov_iter_count(ii))
+               set_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
+
        do {
                struct fuse_req *req;
                ssize_t count;
@@ -1073,6 +1078,7 @@ static ssize_t fuse_perform_write(struct file *file,
        if (res > 0)
                fuse_write_update_size(inode, pos);
 
+       clear_bit(FUSE_I_SIZE_UNSTABLE, &fi->state);
        fuse_invalidate_attr(inode);
 
        return res > 0 ? res : err;
@@ -1529,7 +1535,6 @@ static int fuse_writepage_locked(struct page *page)
 
        inc_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK);
        inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
-       end_page_writeback(page);
 
        spin_lock(&fc->lock);
        list_add(&req->writepages_entry, &fi->writepages);
@@ -1537,6 +1542,8 @@ static int fuse_writepage_locked(struct page *page)
        fuse_flush_writepages(inode);
        spin_unlock(&fc->lock);
 
+       end_page_writeback(page);
+
        return 0;
 
 err_free:
index fde7249a3a9608c8c6e49be4316a1d155b7cdfba..5ced199b50bbb19a9dcd8fb42313de4afba26d6c 100644 (file)
@@ -115,6 +115,8 @@ struct fuse_inode {
 enum {
        /** Advise readdirplus  */
        FUSE_I_ADVISE_RDPLUS,
+       /** An operation changing file size is in progress  */
+       FUSE_I_SIZE_UNSTABLE,
 };
 
 struct fuse_conn;
index 0b578598c6ac8a66f17ed7f4511d7ec0cf9132db..a8ce6dab60a0b0e3279b6996c8462610c0cbef14 100644 (file)
@@ -201,7 +201,8 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
        struct timespec old_mtime;
 
        spin_lock(&fc->lock);
-       if (attr_version != 0 && fi->attr_version > attr_version) {
+       if ((attr_version != 0 && fi->attr_version > attr_version) ||
+           test_bit(FUSE_I_SIZE_UNSTABLE, &fi->state)) {
                spin_unlock(&fc->lock);
                return;
        }
@@ -217,7 +218,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
                bool inval = false;
 
                if (oldsize != attr->size) {
-                       truncate_pagecache(inode, oldsize, attr->size);
+                       truncate_pagecache(inode, attr->size);
                        inval = true;
                } else if (fc->auto_inval_data) {
                        struct timespec new_mtime = {
@@ -929,7 +930,7 @@ static int fuse_bdi_init(struct fuse_conn *fc, struct super_block *sb)
        fc->bdi.name = "fuse";
        fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
        /* fuse does it's own writeback accounting */
-       fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
+       fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB | BDI_CAP_STRICTLIMIT;
 
        err = bdi_init(&fc->bdi);
        if (err)
index ee48ad37d9c0109dfd81bcca983c13a29492f0cb..1f7d8057ea68d1c7214d3db0a6446aa248888eea 100644 (file)
@@ -122,14 +122,13 @@ out:
 }
 
 /**
- * gfs2_writeback_writepage - Write page for writeback mappings
+ * gfs2_writepage - Write page for writeback mappings
  * @page: The page
  * @wbc: The writeback control
  *
  */
 
-static int gfs2_writeback_writepage(struct page *page,
-                                   struct writeback_control *wbc)
+static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
 {
        int ret;
 
@@ -140,32 +139,6 @@ static int gfs2_writeback_writepage(struct page *page,
        return nobh_writepage(page, gfs2_get_block_noalloc, wbc);
 }
 
-/**
- * gfs2_ordered_writepage - Write page for ordered data files
- * @page: The page to write
- * @wbc: The writeback control
- *
- */
-
-static int gfs2_ordered_writepage(struct page *page,
-                                 struct writeback_control *wbc)
-{
-       struct inode *inode = page->mapping->host;
-       struct gfs2_inode *ip = GFS2_I(inode);
-       int ret;
-
-       ret = gfs2_writepage_common(page, wbc);
-       if (ret <= 0)
-               return ret;
-
-       if (!page_has_buffers(page)) {
-               create_empty_buffers(page, inode->i_sb->s_blocksize,
-                                    (1 << BH_Dirty)|(1 << BH_Uptodate));
-       }
-       gfs2_page_add_databufs(ip, page, 0, inode->i_sb->s_blocksize-1);
-       return block_write_full_page(page, gfs2_get_block_noalloc, wbc);
-}
-
 /**
  * __gfs2_jdata_writepage - The core of jdata writepage
  * @page: The page to write
@@ -842,6 +815,8 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
        unsigned int from = pos & (PAGE_CACHE_SIZE - 1);
        unsigned int to = from + len;
        int ret;
+       struct gfs2_trans *tr = current->journal_info;
+       BUG_ON(!tr);
 
        BUG_ON(gfs2_glock_is_locked_by_me(ip->i_gl) == NULL);
 
@@ -852,8 +827,6 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
                goto failed;
        }
 
-       gfs2_trans_add_meta(ip->i_gl, dibh);
-
        if (gfs2_is_stuffed(ip))
                return gfs2_stuffed_write_end(inode, dibh, pos, len, copied, page);
 
@@ -861,6 +834,11 @@ static int gfs2_write_end(struct file *file, struct address_space *mapping,
                gfs2_page_add_databufs(ip, page, from, to);
 
        ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
+       if (tr->tr_num_buf_new)
+               __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
+       else
+               gfs2_trans_add_meta(ip->i_gl, dibh);
+
 
        if (inode == sdp->sd_rindex) {
                adjust_fs_space(inode);
@@ -1107,7 +1085,7 @@ cannot_release:
 }
 
 static const struct address_space_operations gfs2_writeback_aops = {
-       .writepage = gfs2_writeback_writepage,
+       .writepage = gfs2_writepage,
        .writepages = gfs2_writepages,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
@@ -1123,7 +1101,7 @@ static const struct address_space_operations gfs2_writeback_aops = {
 };
 
 static const struct address_space_operations gfs2_ordered_aops = {
-       .writepage = gfs2_ordered_writepage,
+       .writepage = gfs2_writepage,
        .writepages = gfs2_writepages,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
index 5e2f56fccf6b3dfd516c04bd01649852dd1e855d..62a65fc448dcedf5009f85a233cb43ad7cd4b442 100644 (file)
@@ -1016,7 +1016,7 @@ static int gfs2_journaled_truncate(struct inode *inode, u64 oldsize, u64 newsize
                chunk = oldsize - newsize;
                if (chunk > max_chunk)
                        chunk = max_chunk;
-               truncate_pagecache(inode, oldsize, oldsize - chunk);
+               truncate_pagecache(inode, oldsize - chunk);
                oldsize -= chunk;
                gfs2_trans_end(sdp);
                error = gfs2_trans_begin(sdp, RES_DINODE, GFS2_JTRUNC_REVOKES);
@@ -1067,7 +1067,7 @@ static int trunc_start(struct inode *inode, u64 oldsize, u64 newsize)
        if (journaled)
                error = gfs2_journaled_truncate(inode, oldsize, newsize);
        else
-               truncate_pagecache(inode, oldsize, newsize);
+               truncate_pagecache(inode, newsize);
 
        if (error) {
                brelse(dibh);
index 72c3866a73205217b9fe57d7863ce2376ce8002b..0621b46d474d0e6d82157e6701b3e49449839908 100644 (file)
@@ -650,7 +650,7 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
 {
        struct address_space *mapping = file->f_mapping;
        struct inode *inode = mapping->host;
-       int sync_state = inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC);
+       int sync_state = inode->i_state & I_DIRTY;
        struct gfs2_inode *ip = GFS2_I(inode);
        int ret = 0, ret1 = 0;
 
@@ -660,6 +660,8 @@ static int gfs2_fsync(struct file *file, loff_t start, loff_t end,
                        return ret1;
        }
 
+       if (!gfs2_is_jdata(ip))
+               sync_state &= ~I_DIRTY_PAGES;
        if (datasync)
                sync_state &= ~I_DIRTY_SYNC;
 
index 544a809819c3ee5c16ddaa42a8ce0ce26d2194f4..c2f41b4d00b9872ccfb4f5f23f988d46f154df32 100644 (file)
@@ -1411,7 +1411,6 @@ __acquires(&lru_lock)
                if (demote_ok(gl))
                        handle_callback(gl, LM_ST_UNLOCKED, 0, false);
                WARN_ON(!test_and_clear_bit(GLF_LOCK, &gl->gl_flags));
-               smp_mb__after_clear_bit();
                if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
                        gfs2_glock_put_nolock(gl);
                spin_unlock(&gl->gl_spin);
@@ -1428,21 +1427,22 @@ __acquires(&lru_lock)
  * gfs2_dispose_glock_lru() above.
  */
 
-static void gfs2_scan_glock_lru(int nr)
+static long gfs2_scan_glock_lru(int nr)
 {
        struct gfs2_glock *gl;
        LIST_HEAD(skipped);
        LIST_HEAD(dispose);
+       long freed = 0;
 
        spin_lock(&lru_lock);
-       while(nr && !list_empty(&lru_list)) {
+       while ((nr-- >= 0) && !list_empty(&lru_list)) {
                gl = list_entry(lru_list.next, struct gfs2_glock, gl_lru);
 
                /* Test for being demotable */
                if (!test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
                        list_move(&gl->gl_lru, &dispose);
                        atomic_dec(&lru_count);
-                       nr--;
+                       freed++;
                        continue;
                }
 
@@ -1452,23 +1452,28 @@ static void gfs2_scan_glock_lru(int nr)
        if (!list_empty(&dispose))
                gfs2_dispose_glock_lru(&dispose);
        spin_unlock(&lru_lock);
+
+       return freed;
 }
 
-static int gfs2_shrink_glock_memory(struct shrinker *shrink,
-                                   struct shrink_control *sc)
+static unsigned long gfs2_glock_shrink_scan(struct shrinker *shrink,
+                                           struct shrink_control *sc)
 {
-       if (sc->nr_to_scan) {
-               if (!(sc->gfp_mask & __GFP_FS))
-                       return -1;
-               gfs2_scan_glock_lru(sc->nr_to_scan);
-       }
+       if (!(sc->gfp_mask & __GFP_FS))
+               return SHRINK_STOP;
+       return gfs2_scan_glock_lru(sc->nr_to_scan);
+}
 
-       return (atomic_read(&lru_count) / 100) * sysctl_vfs_cache_pressure;
+static unsigned long gfs2_glock_shrink_count(struct shrinker *shrink,
+                                            struct shrink_control *sc)
+{
+       return vfs_pressure_ratio(atomic_read(&lru_count));
 }
 
 static struct shrinker glock_shrinker = {
-       .shrink = gfs2_shrink_glock_memory,
        .seeks = DEFAULT_SEEKS,
+       .count_objects = gfs2_glock_shrink_count,
+       .scan_objects = gfs2_glock_shrink_scan,
 };
 
 /**
@@ -1488,7 +1493,7 @@ static void examine_bucket(glock_examiner examiner, const struct gfs2_sbd *sdp,
 
        rcu_read_lock();
        hlist_bl_for_each_entry_rcu(gl, pos, head, gl_list) {
-               if ((gl->gl_sbd == sdp) && atomic_read(&gl->gl_ref))
+               if ((gl->gl_sbd == sdp) && atomic_inc_not_zero(&gl->gl_ref))
                        examiner(gl);
        }
        rcu_read_unlock();
@@ -1508,18 +1513,17 @@ static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp)
  * thaw_glock - thaw out a glock which has an unprocessed reply waiting
  * @gl: The glock to thaw
  *
- * N.B. When we freeze a glock, we leave a ref to the glock outstanding,
- * so this has to result in the ref count being dropped by one.
  */
 
 static void thaw_glock(struct gfs2_glock *gl)
 {
        if (!test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))
-               return;
+               goto out;
        set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
-       gfs2_glock_hold(gl);
-       if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+       if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0) {
+out:
                gfs2_glock_put(gl);
+       }
 }
 
 /**
@@ -1536,7 +1540,6 @@ static void clear_glock(struct gfs2_glock *gl)
        if (gl->gl_state != LM_ST_UNLOCKED)
                handle_callback(gl, LM_ST_UNLOCKED, 0, false);
        spin_unlock(&gl->gl_spin);
-       gfs2_glock_hold(gl);
        if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
                gfs2_glock_put(gl);
 }
index 64915eeae5a7112f59256185a00a1cc9f3b2a193..ced3257f06e84bd24b6d96063a4f88f5e2b81525 100644 (file)
@@ -694,8 +694,10 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
 
        mark_inode_dirty(inode);
        d_instantiate(dentry, inode);
-       if (file)
+       if (file) {
+               *opened |= FILE_CREATED;
                error = finish_open(file, dentry, gfs2_open_common, opened);
+       }
        gfs2_glock_dq_uninit(ghs);
        gfs2_glock_dq_uninit(ghs + 1);
        return error;
index 17c5b5d7dc88c4b73e00c5918f97473df15b354f..010b9fb9fec6e781cb80a6982d746896ba6cffdb 100644 (file)
@@ -579,6 +579,24 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
        return error;
 }
 
+/**
+ * gfs2_meta_sync - Sync all buffers associated with a glock
+ * @gl: The glock
+ *
+ */
+
+static void gfs2_meta_sync(struct gfs2_glock *gl)
+{
+       struct address_space *mapping = gfs2_glock2aspace(gl);
+       int error;
+
+       filemap_fdatawrite(mapping);
+       error = filemap_fdatawait(mapping);
+
+       if (error)
+               gfs2_io_error(gl->gl_sbd);
+}
+
 static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
 {
        struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
index 7b0f5043cf24c253612451787588d638da5483ce..351586e24e3004f59b8bf3c5db022ce07afeaedd 100644 (file)
@@ -32,7 +32,8 @@
 struct workqueue_struct *gfs2_control_wq;
 
 static struct shrinker qd_shrinker = {
-       .shrink = gfs2_shrink_qd_memory,
+       .count_objects = gfs2_qd_shrink_count,
+       .scan_objects = gfs2_qd_shrink_scan,
        .seeks = DEFAULT_SEEKS,
 };
 
index 0da390686c08f458e12aeb44df92d7301a96d788..932415050540e2a1bdefc6d957e68ef7a0d82d01 100644 (file)
@@ -97,24 +97,6 @@ const struct address_space_operations gfs2_meta_aops = {
        .releasepage = gfs2_releasepage,
 };
 
-/**
- * gfs2_meta_sync - Sync all buffers associated with a glock
- * @gl: The glock
- *
- */
-
-void gfs2_meta_sync(struct gfs2_glock *gl)
-{
-       struct address_space *mapping = gfs2_glock2aspace(gl);
-       int error;
-
-       filemap_fdatawrite(mapping);
-       error = filemap_fdatawait(mapping);
-
-       if (error)
-               gfs2_io_error(gl->gl_sbd);
-}
-
 /**
  * gfs2_getbuf - Get a buffer with a given address space
  * @gl: the glock
index 0d4c843b6f8e59aec3f143a80417d0e4e6de43e0..4823b934208a2be6012a71ded8f4e950fca753fb 100644 (file)
@@ -48,21 +48,17 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping)
                return inode->i_sb->s_fs_info;
 }
 
-void gfs2_meta_sync(struct gfs2_glock *gl);
-
-struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
-int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno,
-                  int flags, struct buffer_head **bhp);
-int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
-struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create);
-
-void gfs2_remove_from_journal(struct buffer_head *bh, struct gfs2_trans *tr,
-                             int meta);
-
-void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
-
-int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
-                             struct buffer_head **bhp);
+extern struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
+extern int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
+                         struct buffer_head **bhp);
+extern int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
+extern struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno,
+                                      int create);
+extern void gfs2_remove_from_journal(struct buffer_head *bh,
+                                    struct gfs2_trans *tr, int meta);
+extern void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
+extern int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+                                    struct buffer_head **bhp);
 
 static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip,
                                         struct buffer_head **bhp)
index 0262c190b6f95c6c7dec1da9a8937db4e0701724..19ff5e8c285c4c0764d402a719146f1416d9f35a 100644 (file)
@@ -646,6 +646,48 @@ static int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
        return error;
 }
 
+/**
+ * check_journal_clean - Make sure a journal is clean for a spectator mount
+ * @sdp: The GFS2 superblock
+ * @jd: The journal descriptor
+ *
+ * Returns: 0 if the journal is clean or locked, else an error
+ */
+static int check_journal_clean(struct gfs2_sbd *sdp, struct gfs2_jdesc *jd)
+{
+       int error;
+       struct gfs2_holder j_gh;
+       struct gfs2_log_header_host head;
+       struct gfs2_inode *ip;
+
+       ip = GFS2_I(jd->jd_inode);
+       error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_NOEXP |
+                                  GL_EXACT | GL_NOCACHE, &j_gh);
+       if (error) {
+               fs_err(sdp, "Error locking journal for spectator mount.\n");
+               return -EPERM;
+       }
+       error = gfs2_jdesc_check(jd);
+       if (error) {
+               fs_err(sdp, "Error checking journal for spectator mount.\n");
+               goto out_unlock;
+       }
+       error = gfs2_find_jhead(jd, &head);
+       if (error) {
+               fs_err(sdp, "Error parsing journal for spectator mount.\n");
+               goto out_unlock;
+       }
+       if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+               error = -EPERM;
+               fs_err(sdp, "jid=%u: Journal is dirty, so the first mounter "
+                      "must not be a spectator.\n", jd->jd_jid);
+       }
+
+out_unlock:
+       gfs2_glock_dq_uninit(&j_gh);
+       return error;
+}
+
 static int init_journal(struct gfs2_sbd *sdp, int undo)
 {
        struct inode *master = sdp->sd_master_dir->d_inode;
@@ -732,8 +774,15 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
        if (sdp->sd_lockstruct.ls_first) {
                unsigned int x;
                for (x = 0; x < sdp->sd_journals; x++) {
-                       error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x),
-                                                    true);
+                       struct gfs2_jdesc *jd = gfs2_jdesc_find(sdp, x);
+
+                       if (sdp->sd_args.ar_spectator) {
+                               error = check_journal_clean(sdp, jd);
+                               if (error)
+                                       goto fail_jinode_gh;
+                               continue;
+                       }
+                       error = gfs2_recover_journal(jd, true);
                        if (error) {
                                fs_err(sdp, "error recovering journal %u: %d\n",
                                       x, error);
index 3768c2f40e43350f3586769e9b40974ac9138a74..db441359ee8cd2f31fa4a980afe8c54a3f715447 100644 (file)
@@ -75,17 +75,16 @@ static LIST_HEAD(qd_lru_list);
 static atomic_t qd_lru_count = ATOMIC_INIT(0);
 static DEFINE_SPINLOCK(qd_lru_lock);
 
-int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc)
+unsigned long gfs2_qd_shrink_scan(struct shrinker *shrink,
+                                 struct shrink_control *sc)
 {
        struct gfs2_quota_data *qd;
        struct gfs2_sbd *sdp;
        int nr_to_scan = sc->nr_to_scan;
-
-       if (nr_to_scan == 0)
-               goto out;
+       long freed = 0;
 
        if (!(sc->gfp_mask & __GFP_FS))
-               return -1;
+               return SHRINK_STOP;
 
        spin_lock(&qd_lru_lock);
        while (nr_to_scan && !list_empty(&qd_lru_list)) {
@@ -110,11 +109,16 @@ int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc)
                kmem_cache_free(gfs2_quotad_cachep, qd);
                spin_lock(&qd_lru_lock);
                nr_to_scan--;
+               freed++;
        }
        spin_unlock(&qd_lru_lock);
+       return freed;
+}
 
-out:
-       return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100;
+unsigned long gfs2_qd_shrink_count(struct shrinker *shrink,
+                                  struct shrink_control *sc)
+{
+       return vfs_pressure_ratio(atomic_read(&qd_lru_count));
 }
 
 static u64 qd2index(struct gfs2_quota_data *qd)
index 4f5e6e44ed8320feec952a71096cc55b1b385a96..0f64d9deb1b027c892caaf377ec76681dbbfce4f 100644 (file)
@@ -53,8 +53,10 @@ static inline int gfs2_quota_lock_check(struct gfs2_inode *ip)
        return ret;
 }
 
-extern int gfs2_shrink_qd_memory(struct shrinker *shrink,
-                                struct shrink_control *sc);
+extern unsigned long gfs2_qd_shrink_count(struct shrinker *shrink,
+                                         struct shrink_control *sc);
+extern unsigned long gfs2_qd_shrink_scan(struct shrinker *shrink,
+                                        struct shrink_control *sc);
 extern const struct quotactl_ops gfs2_quotactl_ops;
 
 #endif /* __QUOTA_DOT_H__ */
index f9299d8a64e3a2af9f6ef2aadd009a097c74ccf6..380ab31b5e0f4870ee966cbcfd5af1e805035f58 100644 (file)
@@ -41,7 +41,7 @@ static void hfs_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);
+               truncate_pagecache(inode, inode->i_size);
                hfs_file_truncate(inode);
        }
 }
index a63371815aaba6a0dfda4399b3b5cf8f789b15c2..24bc20fd42f7b93081d8c22954a5a38ec44d3037 100644 (file)
@@ -11,3 +11,21 @@ config HFSPLUS_FS
          MacOS 8. It includes all Mac specific filesystem data such as
          data forks and creator codes, but it also has several UNIX
          style features such as file ownership and permissions.
+
+config HFSPLUS_FS_POSIX_ACL
+       bool "HFS+ POSIX Access Control Lists"
+       depends on HFSPLUS_FS
+       select FS_POSIX_ACL
+       help
+         POSIX Access Control Lists (ACLs) support permissions for users and
+         groups beyond the owner/group/world scheme.
+
+         To learn more about Access Control Lists, visit the POSIX ACLs for
+         Linux website <http://acl.bestbits.at/>.
+
+         It needs to understand that POSIX ACLs are treated only under
+         Linux. POSIX ACLs doesn't mean something under Mac OS X.
+         Mac OS X beginning with version 10.4 ("Tiger") support NFSv4 ACLs,
+         which are part of the NFSv4 standard.
+
+         If you don't know what Access Control Lists are, say N
index 09d278bb7b91f57d2061f66c1ffed63d45ff3ea3..683fca2e5e65a479b89be09ee3be3d289a4ee358 100644 (file)
@@ -7,3 +7,5 @@ obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o
 hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \
                bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \
                attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o
+
+hfsplus-$(CONFIG_HFSPLUS_FS_POSIX_ACL) += posix_acl.o
diff --git a/fs/hfsplus/acl.h b/fs/hfsplus/acl.h
new file mode 100644 (file)
index 0000000..07c0d49
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * linux/fs/hfsplus/acl.h
+ *
+ * Vyacheslav Dubeyko <slava@dubeyko.com>
+ *
+ * Handler for Posix Access Control Lists (ACLs) support.
+ */
+
+#include <linux/posix_acl_xattr.h>
+
+#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
+
+/* posix_acl.c */
+struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type);
+extern int hfsplus_posix_acl_chmod(struct inode *);
+extern int hfsplus_init_posix_acl(struct inode *, struct inode *);
+
+#else  /* CONFIG_HFSPLUS_FS_POSIX_ACL */
+#define hfsplus_get_posix_acl NULL
+
+static inline int hfsplus_posix_acl_chmod(struct inode *inode)
+{
+       return 0;
+}
+
+static inline int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
+{
+       return 0;
+}
+#endif  /* CONFIG_HFSPLUS_FS_POSIX_ACL */
index d8ce4bd17fc5f43058eaae416532b2e4019cc870..4a4fea0026735c8fb365d031c57165888e9bb079 100644 (file)
@@ -16,6 +16,7 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 #include "xattr.h"
+#include "acl.h"
 
 static inline void hfsplus_instantiate(struct dentry *dentry,
                                       struct inode *inode, u32 cnid)
@@ -529,6 +530,9 @@ const struct inode_operations hfsplus_dir_inode_operations = {
        .getxattr               = generic_getxattr,
        .listxattr              = hfsplus_listxattr,
        .removexattr            = hfsplus_removexattr,
+#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
+       .get_acl                = hfsplus_get_posix_acl,
+#endif
 };
 
 const struct file_operations hfsplus_dir_operations = {
index ede79317cfb8cf5fa521dd187465a8cd63787979..2b9cd01696e2081a7a003ff3e52d261eb51db51c 100644 (file)
@@ -30,6 +30,7 @@
 #define DBG_EXTENT     0x00000020
 #define DBG_BITMAP     0x00000040
 #define DBG_ATTR_MOD   0x00000080
+#define DBG_ACL_MOD    0x00000100
 
 #if 0
 #define DBG_MASK       (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
index f833d35630abbd4d98c4ca322e32704d792cf9e9..37213d075f3c5c9f29029b280b093781ddb526ca 100644 (file)
@@ -19,6 +19,7 @@
 #include "hfsplus_fs.h"
 #include "hfsplus_raw.h"
 #include "xattr.h"
+#include "acl.h"
 
 static int hfsplus_readpage(struct file *file, struct page *page)
 {
@@ -35,7 +36,7 @@ static void hfsplus_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);
+               truncate_pagecache(inode, inode->i_size);
                hfsplus_file_truncate(inode);
        }
 }
@@ -316,6 +317,13 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
 
        setattr_copy(inode, attr);
        mark_inode_dirty(inode);
+
+       if (attr->ia_valid & ATTR_MODE) {
+               error = hfsplus_posix_acl_chmod(inode);
+               if (unlikely(error))
+                       return error;
+       }
+
        return 0;
 }
 
@@ -383,6 +391,9 @@ static const struct inode_operations hfsplus_file_inode_operations = {
        .getxattr       = generic_getxattr,
        .listxattr      = hfsplus_listxattr,
        .removexattr    = hfsplus_removexattr,
+#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
+       .get_acl        = hfsplus_get_posix_acl,
+#endif
 };
 
 static const struct file_operations hfsplus_file_operations = {
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
new file mode 100644 (file)
index 0000000..b609cc1
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * linux/fs/hfsplus/posix_acl.c
+ *
+ * Vyacheslav Dubeyko <slava@dubeyko.com>
+ *
+ * Handler for Posix Access Control Lists (ACLs) support.
+ */
+
+#include "hfsplus_fs.h"
+#include "xattr.h"
+#include "acl.h"
+
+struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
+{
+       struct posix_acl *acl;
+       char *xattr_name;
+       char *value = NULL;
+       ssize_t size;
+
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               xattr_name = POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               xattr_name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               return ERR_PTR(-EINVAL);
+       }
+
+       size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);
+
+       if (size > 0) {
+               value = (char *)hfsplus_alloc_attr_entry();
+               if (unlikely(!value))
+                       return ERR_PTR(-ENOMEM);
+               size = __hfsplus_getxattr(inode, xattr_name, value, size);
+       }
+
+       if (size > 0)
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+       else if (size == -ENODATA)
+               acl = NULL;
+       else
+               acl = ERR_PTR(size);
+
+       hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
+
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
+
+       return acl;
+}
+
+static int hfsplus_set_posix_acl(struct inode *inode,
+                                       int type,
+                                       struct posix_acl *acl)
+{
+       int err;
+       char *xattr_name;
+       size_t size = 0;
+       char *value = NULL;
+
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               xattr_name = POSIX_ACL_XATTR_ACCESS;
+               if (acl) {
+                       err = posix_acl_equiv_mode(acl, &inode->i_mode);
+                       if (err < 0)
+                               return err;
+               }
+               err = 0;
+               break;
+
+       case ACL_TYPE_DEFAULT:
+               xattr_name = POSIX_ACL_XATTR_DEFAULT;
+               if (!S_ISDIR(inode->i_mode))
+                       return acl ? -EACCES : 0;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       if (acl) {
+               size = posix_acl_xattr_size(acl->a_count);
+               if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE))
+                       return -ENOMEM;
+               value = (char *)hfsplus_alloc_attr_entry();
+               if (unlikely(!value))
+                       return -ENOMEM;
+               err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+               if (unlikely(err < 0))
+                       goto end_set_acl;
+       }
+
+       err = __hfsplus_setxattr(inode, xattr_name, value, size, 0);
+
+end_set_acl:
+       hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
+
+       if (!err)
+               set_cached_acl(inode, type, acl);
+
+       return err;
+}
+
+int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
+{
+       int err = 0;
+       struct posix_acl *acl = NULL;
+
+       hfs_dbg(ACL_MOD,
+               "[%s]: ino %lu, dir->ino %lu\n",
+               __func__, inode->i_ino, dir->i_ino);
+
+       if (S_ISLNK(inode->i_mode))
+               return 0;
+
+       acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+
+       if (acl) {
+               if (S_ISDIR(inode->i_mode)) {
+                       err = hfsplus_set_posix_acl(inode,
+                                                       ACL_TYPE_DEFAULT,
+                                                       acl);
+                       if (unlikely(err))
+                               goto init_acl_cleanup;
+               }
+
+               err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
+               if (unlikely(err < 0))
+                       return err;
+
+               if (err > 0)
+                       err = hfsplus_set_posix_acl(inode,
+                                                       ACL_TYPE_ACCESS,
+                                                       acl);
+       } else
+               inode->i_mode &= ~current_umask();
+
+init_acl_cleanup:
+       posix_acl_release(acl);
+       return err;
+}
+
+int hfsplus_posix_acl_chmod(struct inode *inode)
+{
+       int err;
+       struct posix_acl *acl;
+
+       hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
+
+       if (S_ISLNK(inode->i_mode))
+               return -EOPNOTSUPP;
+
+       acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl) || !acl)
+               return PTR_ERR(acl);
+
+       err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
+       if (unlikely(err))
+               return err;
+
+       err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl);
+       posix_acl_release(acl);
+       return err;
+}
+
+static int hfsplus_xattr_get_posix_acl(struct dentry *dentry,
+                                       const char *name,
+                                       void *buffer,
+                                       size_t size,
+                                       int type)
+{
+       int err = 0;
+       struct posix_acl *acl;
+
+       hfs_dbg(ACL_MOD,
+               "[%s]: ino %lu, buffer %p, size %zu, type %#x\n",
+               __func__, dentry->d_inode->i_ino, buffer, size, type);
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+
+       acl = hfsplus_get_posix_acl(dentry->d_inode, type);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl == NULL)
+               return -ENODATA;
+
+       err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
+       posix_acl_release(acl);
+
+       return err;
+}
+
+static int hfsplus_xattr_set_posix_acl(struct dentry *dentry,
+                                       const char *name,
+                                       const void *value,
+                                       size_t size,
+                                       int flags,
+                                       int type)
+{
+       int err = 0;
+       struct inode *inode = dentry->d_inode;
+       struct posix_acl *acl = NULL;
+
+       hfs_dbg(ACL_MOD,
+               "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n",
+               __func__, inode->i_ino, value, size, flags, type);
+
+       if (strcmp(name, "") != 0)
+               return -EINVAL;
+
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
+       if (value) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+               else if (acl) {
+                       err = posix_acl_valid(acl);
+                       if (err)
+                               goto end_xattr_set_acl;
+               }
+       }
+
+       err = hfsplus_set_posix_acl(inode, type, acl);
+
+end_xattr_set_acl:
+       posix_acl_release(acl);
+       return err;
+}
+
+static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry,
+                                               char *list,
+                                               size_t list_size,
+                                               const char *name,
+                                               size_t name_len,
+                                               int type)
+{
+       /*
+        * This method is not used.
+        * It is used hfsplus_listxattr() instead of generic_listxattr().
+        */
+       return -EOPNOTSUPP;
+}
+
+const struct xattr_handler hfsplus_xattr_acl_access_handler = {
+       .prefix = POSIX_ACL_XATTR_ACCESS,
+       .flags  = ACL_TYPE_ACCESS,
+       .list   = hfsplus_xattr_list_posix_acl,
+       .get    = hfsplus_xattr_get_posix_acl,
+       .set    = hfsplus_xattr_set_posix_acl,
+};
+
+const struct xattr_handler hfsplus_xattr_acl_default_handler = {
+       .prefix = POSIX_ACL_XATTR_DEFAULT,
+       .flags  = ACL_TYPE_DEFAULT,
+       .list   = hfsplus_xattr_list_posix_acl,
+       .get    = hfsplus_xattr_get_posix_acl,
+       .set    = hfsplus_xattr_set_posix_acl,
+};
index f66346155df5cc17f5189760c6ad4d17ee08e979..bd8471fb9a6a80fdf74abdbd673714931c0b7867 100644 (file)
@@ -8,11 +8,16 @@
 
 #include "hfsplus_fs.h"
 #include "xattr.h"
+#include "acl.h"
 
 const struct xattr_handler *hfsplus_xattr_handlers[] = {
        &hfsplus_xattr_osx_handler,
        &hfsplus_xattr_user_handler,
        &hfsplus_xattr_trusted_handler,
+#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
+       &hfsplus_xattr_acl_access_handler,
+       &hfsplus_xattr_acl_default_handler,
+#endif
        &hfsplus_xattr_security_handler,
        NULL
 };
@@ -46,11 +51,58 @@ static inline int is_known_namespace(const char *name)
        return true;
 }
 
+static int can_set_system_xattr(struct inode *inode, const char *name,
+                               const void *value, size_t size)
+{
+#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
+       struct posix_acl *acl;
+       int err;
+
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
+       /*
+        * POSIX_ACL_XATTR_ACCESS is tied to i_mode
+        */
+       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+               if (acl) {
+                       err = posix_acl_equiv_mode(acl, &inode->i_mode);
+                       posix_acl_release(acl);
+                       if (err < 0)
+                               return err;
+                       mark_inode_dirty(inode);
+               }
+               /*
+                * We're changing the ACL.  Get rid of the cached one
+                */
+               forget_cached_acl(inode, ACL_TYPE_ACCESS);
+
+               return 0;
+       } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+               posix_acl_release(acl);
+
+               /*
+                * We're changing the default ACL.  Get rid of the cached one
+                */
+               forget_cached_acl(inode, ACL_TYPE_DEFAULT);
+
+               return 0;
+       }
+#endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */
+       return -EOPNOTSUPP;
+}
+
 static int can_set_xattr(struct inode *inode, const char *name,
                                const void *value, size_t value_len)
 {
        if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return -EOPNOTSUPP; /* TODO: implement ACL support */
+               return can_set_system_xattr(inode, name, value, value_len);
 
        if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
                /*
@@ -253,11 +305,10 @@ static int copy_name(char *buffer, const char *xattr_name, int name_len)
        return len;
 }
 
-static ssize_t hfsplus_getxattr_finder_info(struct dentry *dentry,
+static ssize_t hfsplus_getxattr_finder_info(struct inode *inode,
                                                void *value, size_t size)
 {
        ssize_t res = 0;
-       struct inode *inode = dentry->d_inode;
        struct hfs_find_data fd;
        u16 entry_type;
        u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo);
@@ -304,10 +355,9 @@ end_getxattr_finder_info:
        return res;
 }
 
-ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
+ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
                         void *value, size_t size)
 {
-       struct inode *inode = dentry->d_inode;
        struct hfs_find_data fd;
        hfsplus_attr_entry *entry;
        __be32 xattr_record_type;
@@ -333,7 +383,7 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
        }
 
        if (!strcmp_xattr_finder_info(name))
-               return hfsplus_getxattr_finder_info(dentry, value, size);
+               return hfsplus_getxattr_finder_info(inode, value, size);
 
        if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
                return -EOPNOTSUPP;
index 847b695b984dfe22148cfb61a4708ac844221d66..841b5698c0fc4b5375c8d5e153fea62bdc931da9 100644 (file)
@@ -14,8 +14,8 @@
 extern const struct xattr_handler hfsplus_xattr_osx_handler;
 extern const struct xattr_handler hfsplus_xattr_user_handler;
 extern const struct xattr_handler hfsplus_xattr_trusted_handler;
-/*extern const struct xattr_handler hfsplus_xattr_acl_access_handler;*/
-/*extern const struct xattr_handler hfsplus_xattr_acl_default_handler;*/
+extern const struct xattr_handler hfsplus_xattr_acl_access_handler;
+extern const struct xattr_handler hfsplus_xattr_acl_default_handler;
 extern const struct xattr_handler hfsplus_xattr_security_handler;
 
 extern const struct xattr_handler *hfsplus_xattr_handlers[];
@@ -29,9 +29,17 @@ static inline int hfsplus_setxattr(struct dentry *dentry, const char *name,
        return __hfsplus_setxattr(dentry->d_inode, name, value, size, flags);
 }
 
-ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
+ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
                        void *value, size_t size);
 
+static inline ssize_t hfsplus_getxattr(struct dentry *dentry,
+                                       const char *name,
+                                       void *value,
+                                       size_t size)
+{
+       return __hfsplus_getxattr(dentry->d_inode, name, value, size);
+}
+
 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size);
 
 int hfsplus_removexattr(struct dentry *dentry, const char *name);
@@ -39,22 +47,7 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name);
 int hfsplus_init_security(struct inode *inode, struct inode *dir,
                                const struct qstr *qstr);
 
-static inline int hfsplus_init_acl(struct inode *inode, struct inode *dir)
-{
-       /*TODO: implement*/
-       return 0;
-}
-
-static inline int hfsplus_init_inode_security(struct inode *inode,
-                                               struct inode *dir,
-                                               const struct qstr *qstr)
-{
-       int err;
-
-       err = hfsplus_init_acl(inode, dir);
-       if (!err)
-               err = hfsplus_init_security(inode, dir, qstr);
-       return err;
-}
+int hfsplus_init_inode_security(struct inode *inode, struct inode *dir,
+                               const struct qstr *qstr);
 
 #endif
index 83b842f113c5924ccaf91607ae9158695eb6a273..00722765ea79b9a689b889623fab0e6213c05570 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/security.h>
 #include "hfsplus_fs.h"
 #include "xattr.h"
+#include "acl.h"
 
 static int hfsplus_security_getxattr(struct dentry *dentry, const char *name,
                                        void *buffer, size_t size, int type)
@@ -96,6 +97,18 @@ int hfsplus_init_security(struct inode *inode, struct inode *dir,
                                        &hfsplus_initxattrs, NULL);
 }
 
+int hfsplus_init_inode_security(struct inode *inode,
+                                               struct inode *dir,
+                                               const struct qstr *qstr)
+{
+       int err;
+
+       err = hfsplus_init_posix_acl(inode, dir);
+       if (!err)
+               err = hfsplus_init_security(inode, dir, qstr);
+       return err;
+}
+
 const struct xattr_handler hfsplus_xattr_security_handler = {
        .prefix = XATTR_SECURITY_PREFIX,
        .list   = hfsplus_security_listxattr,
index cddb0521751278526dfc1b678acbf708a906a815..25437280a2071b8970efe6e394edb97a4433acd8 100644 (file)
@@ -361,6 +361,13 @@ retry:
        return 0;
 }
 
+static int hostfs_file_release(struct inode *inode, struct file *file)
+{
+       filemap_write_and_wait(inode->i_mapping);
+
+       return 0;
+}
+
 int hostfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
@@ -386,7 +393,7 @@ static const struct file_operations hostfs_file_fops = {
        .write          = do_sync_write,
        .mmap           = generic_file_mmap,
        .open           = hostfs_file_open,
-       .release        = NULL,
+       .release        = hostfs_file_release,
        .fsync          = hostfs_fsync,
 };
 
index 4e9dabcf1f4cc35f8c3abd6455818f6b15c03a99..67c1a61e09558e0bb632638b0f65d8316ab9b5f2 100644 (file)
@@ -138,7 +138,7 @@ static void hpfs_write_failed(struct address_space *mapping, loff_t to)
        hpfs_lock(inode->i_sb);
 
        if (to > inode->i_size) {
-               truncate_pagecache(inode, to, inode->i_size);
+               truncate_pagecache(inode, inode->i_size);
                hpfs_truncate(inode);
        }
 
index 93a0625b46e490252c03dab43310919763a8eca9..b33ba8e021cc286d500d94abd64d8f85115ebcd2 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/prefetch.h>
 #include <linux/buffer_head.h> /* for inode_has_buffers */
 #include <linux/ratelimit.h>
+#include <linux/list_lru.h>
 #include "internal.h"
 
 /*
@@ -24,7 +25,7 @@
  *
  * inode->i_lock protects:
  *   inode->i_state, inode->i_hash, __iget()
- * inode->i_sb->s_inode_lru_lock protects:
+ * Inode LRU list locks protect:
  *   inode->i_sb->s_inode_lru, inode->i_lru
  * inode_sb_list_lock protects:
  *   sb->s_inodes, inode->i_sb_list
@@ -37,7 +38,7 @@
  *
  * inode_sb_list_lock
  *   inode->i_lock
- *     inode->i_sb->s_inode_lru_lock
+ *     Inode LRU list locks
  *
  * bdi->wb.list_lock
  *   inode->i_lock
@@ -70,33 +71,33 @@ EXPORT_SYMBOL(empty_aops);
  */
 struct inodes_stat_t inodes_stat;
 
-static DEFINE_PER_CPU(unsigned int, nr_inodes);
-static DEFINE_PER_CPU(unsigned int, nr_unused);
+static DEFINE_PER_CPU(unsigned long, nr_inodes);
+static DEFINE_PER_CPU(unsigned long, nr_unused);
 
 static struct kmem_cache *inode_cachep __read_mostly;
 
-static int get_nr_inodes(void)
+static long get_nr_inodes(void)
 {
        int i;
-       int sum = 0;
+       long sum = 0;
        for_each_possible_cpu(i)
                sum += per_cpu(nr_inodes, i);
        return sum < 0 ? 0 : sum;
 }
 
-static inline int get_nr_inodes_unused(void)
+static inline long get_nr_inodes_unused(void)
 {
        int i;
-       int sum = 0;
+       long sum = 0;
        for_each_possible_cpu(i)
                sum += per_cpu(nr_unused, i);
        return sum < 0 ? 0 : sum;
 }
 
-int get_nr_dirty_inodes(void)
+long get_nr_dirty_inodes(void)
 {
        /* not actually dirty inodes, but a wild approximation */
-       int nr_dirty = get_nr_inodes() - get_nr_inodes_unused();
+       long nr_dirty = get_nr_inodes() - get_nr_inodes_unused();
        return nr_dirty > 0 ? nr_dirty : 0;
 }
 
@@ -109,7 +110,7 @@ int proc_nr_inodes(ctl_table *table, int write,
 {
        inodes_stat.nr_inodes = get_nr_inodes();
        inodes_stat.nr_unused = get_nr_inodes_unused();
-       return proc_dointvec(table, write, buffer, lenp, ppos);
+       return proc_doulongvec_minmax(table, write, buffer, lenp, ppos);
 }
 #endif
 
@@ -401,13 +402,8 @@ EXPORT_SYMBOL(ihold);
 
 static void inode_lru_list_add(struct inode *inode)
 {
-       spin_lock(&inode->i_sb->s_inode_lru_lock);
-       if (list_empty(&inode->i_lru)) {
-               list_add(&inode->i_lru, &inode->i_sb->s_inode_lru);
-               inode->i_sb->s_nr_inodes_unused++;
+       if (list_lru_add(&inode->i_sb->s_inode_lru, &inode->i_lru))
                this_cpu_inc(nr_unused);
-       }
-       spin_unlock(&inode->i_sb->s_inode_lru_lock);
 }
 
 /*
@@ -425,13 +421,9 @@ void inode_add_lru(struct inode *inode)
 
 static void inode_lru_list_del(struct inode *inode)
 {
-       spin_lock(&inode->i_sb->s_inode_lru_lock);
-       if (!list_empty(&inode->i_lru)) {
-               list_del_init(&inode->i_lru);
-               inode->i_sb->s_nr_inodes_unused--;
+
+       if (list_lru_del(&inode->i_sb->s_inode_lru, &inode->i_lru))
                this_cpu_dec(nr_unused);
-       }
-       spin_unlock(&inode->i_sb->s_inode_lru_lock);
 }
 
 /**
@@ -675,24 +667,8 @@ int invalidate_inodes(struct super_block *sb, bool kill_dirty)
        return busy;
 }
 
-static int can_unuse(struct inode *inode)
-{
-       if (inode->i_state & ~I_REFERENCED)
-               return 0;
-       if (inode_has_buffers(inode))
-               return 0;
-       if (atomic_read(&inode->i_count))
-               return 0;
-       if (inode->i_data.nrpages)
-               return 0;
-       return 1;
-}
-
 /*
- * Walk the superblock inode LRU for freeable inodes and attempt to free them.
- * This is called from the superblock shrinker function with a number of inodes
- * to trim from the LRU. Inodes to be freed are moved to a temporary list and
- * then are freed outside inode_lock by dispose_list().
+ * Isolate the inode from the LRU in preparation for freeing it.
  *
  * Any inodes which are pinned purely because of attached pagecache have their
  * pagecache removed.  If the inode has metadata buffers attached to
@@ -706,89 +682,82 @@ static int can_unuse(struct inode *inode)
  * LRU does not have strict ordering. Hence we don't want to reclaim inodes
  * with this flag set because they are the inodes that are out of order.
  */
-void prune_icache_sb(struct super_block *sb, int nr_to_scan)
+static enum lru_status
+inode_lru_isolate(struct list_head *item, spinlock_t *lru_lock, void *arg)
 {
-       LIST_HEAD(freeable);
-       int nr_scanned;
-       unsigned long reap = 0;
+       struct list_head *freeable = arg;
+       struct inode    *inode = container_of(item, struct inode, i_lru);
 
-       spin_lock(&sb->s_inode_lru_lock);
-       for (nr_scanned = nr_to_scan; nr_scanned >= 0; nr_scanned--) {
-               struct inode *inode;
+       /*
+        * we are inverting the lru lock/inode->i_lock here, so use a trylock.
+        * If we fail to get the lock, just skip it.
+        */
+       if (!spin_trylock(&inode->i_lock))
+               return LRU_SKIP;
 
-               if (list_empty(&sb->s_inode_lru))
-                       break;
+       /*
+        * Referenced or dirty inodes are still in use. Give them another pass
+        * through the LRU as we canot reclaim them now.
+        */
+       if (atomic_read(&inode->i_count) ||
+           (inode->i_state & ~I_REFERENCED)) {
+               list_del_init(&inode->i_lru);
+               spin_unlock(&inode->i_lock);
+               this_cpu_dec(nr_unused);
+               return LRU_REMOVED;
+       }
 
-               inode = list_entry(sb->s_inode_lru.prev, struct inode, i_lru);
+       /* recently referenced inodes get one more pass */
+       if (inode->i_state & I_REFERENCED) {
+               inode->i_state &= ~I_REFERENCED;
+               spin_unlock(&inode->i_lock);
+               return LRU_ROTATE;
+       }
 
-               /*
-                * we are inverting the sb->s_inode_lru_lock/inode->i_lock here,
-                * so use a trylock. If we fail to get the lock, just move the
-                * inode to the back of the list so we don't spin on it.
-                */
-               if (!spin_trylock(&inode->i_lock)) {
-                       list_move(&inode->i_lru, &sb->s_inode_lru);
-                       continue;
+       if (inode_has_buffers(inode) || inode->i_data.nrpages) {
+               __iget(inode);
+               spin_unlock(&inode->i_lock);
+               spin_unlock(lru_lock);
+               if (remove_inode_buffers(inode)) {
+                       unsigned long reap;
+                       reap = invalidate_mapping_pages(&inode->i_data, 0, -1);
+                       if (current_is_kswapd())
+                               __count_vm_events(KSWAPD_INODESTEAL, reap);
+                       else
+                               __count_vm_events(PGINODESTEAL, reap);
+                       if (current->reclaim_state)
+                               current->reclaim_state->reclaimed_slab += reap;
                }
+               iput(inode);
+               spin_lock(lru_lock);
+               return LRU_RETRY;
+       }
 
-               /*
-                * Referenced or dirty inodes are still in use. Give them
-                * another pass through the LRU as we canot reclaim them now.
-                */
-               if (atomic_read(&inode->i_count) ||
-                   (inode->i_state & ~I_REFERENCED)) {
-                       list_del_init(&inode->i_lru);
-                       spin_unlock(&inode->i_lock);
-                       sb->s_nr_inodes_unused--;
-                       this_cpu_dec(nr_unused);
-                       continue;
-               }
+       WARN_ON(inode->i_state & I_NEW);
+       inode->i_state |= I_FREEING;
+       list_move(&inode->i_lru, freeable);
+       spin_unlock(&inode->i_lock);
 
-               /* recently referenced inodes get one more pass */
-               if (inode->i_state & I_REFERENCED) {
-                       inode->i_state &= ~I_REFERENCED;
-                       list_move(&inode->i_lru, &sb->s_inode_lru);
-                       spin_unlock(&inode->i_lock);
-                       continue;
-               }
-               if (inode_has_buffers(inode) || inode->i_data.nrpages) {
-                       __iget(inode);
-                       spin_unlock(&inode->i_lock);
-                       spin_unlock(&sb->s_inode_lru_lock);
-                       if (remove_inode_buffers(inode))
-                               reap += invalidate_mapping_pages(&inode->i_data,
-                                                               0, -1);
-                       iput(inode);
-                       spin_lock(&sb->s_inode_lru_lock);
-
-                       if (inode != list_entry(sb->s_inode_lru.next,
-                                               struct inode, i_lru))
-                               continue;       /* wrong inode or list_empty */
-                       /* avoid lock inversions with trylock */
-                       if (!spin_trylock(&inode->i_lock))
-                               continue;
-                       if (!can_unuse(inode)) {
-                               spin_unlock(&inode->i_lock);
-                               continue;
-                       }
-               }
-               WARN_ON(inode->i_state & I_NEW);
-               inode->i_state |= I_FREEING;
-               spin_unlock(&inode->i_lock);
+       this_cpu_dec(nr_unused);
+       return LRU_REMOVED;
+}
 
-               list_move(&inode->i_lru, &freeable);
-               sb->s_nr_inodes_unused--;
-               this_cpu_dec(nr_unused);
-       }
-       if (current_is_kswapd())
-               __count_vm_events(KSWAPD_INODESTEAL, reap);
-       else
-               __count_vm_events(PGINODESTEAL, reap);
-       spin_unlock(&sb->s_inode_lru_lock);
-       if (current->reclaim_state)
-               current->reclaim_state->reclaimed_slab += reap;
+/*
+ * Walk the superblock inode LRU for freeable inodes and attempt to free them.
+ * This is called from the superblock shrinker function with a number of inodes
+ * to trim from the LRU. Inodes to be freed are moved to a temporary list and
+ * then are freed outside inode_lock by dispose_list().
+ */
+long prune_icache_sb(struct super_block *sb, unsigned long nr_to_scan,
+                    int nid)
+{
+       LIST_HEAD(freeable);
+       long freed;
 
+       freed = list_lru_walk_node(&sb->s_inode_lru, nid, inode_lru_isolate,
+                                      &freeable, &nr_to_scan);
        dispose_list(&freeable);
+       return freed;
 }
 
 static void __wait_on_freeing_inode(struct inode *inode);
index d208937955265998fd4e02ff1bfeaaa0807dfd3e..513e0d859a6c18d7b274a9ebe16afcc9e7f8eca4 100644 (file)
@@ -45,6 +45,9 @@ extern void __init chrdev_init(void);
  * namei.c
  */
 extern int __inode_permission(struct inode *, int);
+extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *);
+extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+                          const char *, unsigned int, struct path *);
 
 /*
  * namespace.c
@@ -111,6 +114,8 @@ extern int open_check_o_direct(struct file *f);
  * inode.c
  */
 extern spinlock_t inode_sb_list_lock;
+extern long prune_icache_sb(struct super_block *sb, unsigned long nr_to_scan,
+                           int nid);
 extern void inode_add_lru(struct inode *inode);
 
 /*
@@ -118,7 +123,7 @@ extern void inode_add_lru(struct inode *inode);
  */
 extern void inode_wb_list_del(struct inode *inode);
 
-extern int get_nr_dirty_inodes(void);
+extern long get_nr_dirty_inodes(void);
 extern void evict_inodes(struct super_block *);
 extern int invalidate_inodes(struct super_block *, bool);
 
@@ -127,6 +132,8 @@ extern int invalidate_inodes(struct super_block *, bool);
  */
 extern struct dentry *__d_alloc(struct super_block *, const struct qstr *);
 extern int d_set_mounted(struct dentry *dentry);
+extern long prune_dcache_sb(struct super_block *sb, unsigned long nr_to_scan,
+                           int nid);
 
 /*
  * read_write.c
index 730f24e282a652029ca14b0f5032411512914beb..f4aab719add57bf354f90536486d88182be0b1b3 100644 (file)
@@ -306,7 +306,7 @@ static void jfs_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);
+               truncate_pagecache(inode, inode->i_size);
                jfs_truncate(inode);
        }
 }
index 8c32ef3ba88e7ac25a197866a38c4590836f12be..e519e45bf6735e7f59dc7fef969451791e5e1cef 100644 (file)
@@ -86,18 +86,6 @@ static LIST_HEAD(mb_cache_list);
 static LIST_HEAD(mb_cache_lru_list);
 static DEFINE_SPINLOCK(mb_cache_spinlock);
 
-/*
- * What the mbcache registers as to get shrunk dynamically.
- */
-
-static int mb_cache_shrink_fn(struct shrinker *shrink,
-                             struct shrink_control *sc);
-
-static struct shrinker mb_cache_shrinker = {
-       .shrink = mb_cache_shrink_fn,
-       .seeks = DEFAULT_SEEKS,
-};
-
 static inline int
 __mb_cache_entry_is_hashed(struct mb_cache_entry *ce)
 {
@@ -151,7 +139,7 @@ forget:
 
 
 /*
- * mb_cache_shrink_fn()  memory pressure callback
+ * mb_cache_shrink_scan()  memory pressure callback
  *
  * This function is called by the kernel memory management when memory
  * gets low.
@@ -159,17 +147,16 @@ forget:
  * @shrink: (ignored)
  * @sc: shrink_control passed from reclaim
  *
- * Returns the number of objects which are present in the cache.
+ * Returns the number of objects freed.
  */
-static int
-mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long
+mb_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(free_list);
-       struct mb_cache *cache;
        struct mb_cache_entry *entry, *tmp;
-       int count = 0;
        int nr_to_scan = sc->nr_to_scan;
        gfp_t gfp_mask = sc->gfp_mask;
+       unsigned long freed = 0;
 
        mb_debug("trying to free %d entries", nr_to_scan);
        spin_lock(&mb_cache_spinlock);
@@ -179,19 +166,37 @@ mb_cache_shrink_fn(struct shrinker *shrink, struct shrink_control *sc)
                                   struct mb_cache_entry, e_lru_list);
                list_move_tail(&ce->e_lru_list, &free_list);
                __mb_cache_entry_unhash(ce);
+               freed++;
+       }
+       spin_unlock(&mb_cache_spinlock);
+       list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) {
+               __mb_cache_entry_forget(entry, gfp_mask);
        }
+       return freed;
+}
+
+static unsigned long
+mb_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+       struct mb_cache *cache;
+       unsigned long count = 0;
+
+       spin_lock(&mb_cache_spinlock);
        list_for_each_entry(cache, &mb_cache_list, c_cache_list) {
                mb_debug("cache %s (%d)", cache->c_name,
                          atomic_read(&cache->c_entry_count));
                count += atomic_read(&cache->c_entry_count);
        }
        spin_unlock(&mb_cache_spinlock);
-       list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) {
-               __mb_cache_entry_forget(entry, gfp_mask);
-       }
-       return (count / 100) * sysctl_vfs_cache_pressure;
+
+       return vfs_pressure_ratio(count);
 }
 
+static struct shrinker mb_cache_shrinker = {
+       .count_objects = mb_cache_shrink_count,
+       .scan_objects = mb_cache_shrink_scan,
+       .seeks = DEFAULT_SEEKS,
+};
 
 /*
  * mb_cache_create()  create a new cache
index df122496f32821bd145490800467d41d02c87f63..0332109162a53f614c3c169297e25faf4bb06852 100644 (file)
@@ -400,7 +400,7 @@ static void minix_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);
+               truncate_pagecache(inode, inode->i_size);
                minix_truncate(inode);
        }
 }
index f415c6683a837ac3cb1c5bf1d9600b6a3aec9d7e..645268f23eb64cb8c2931ce33391beb2d0080c36 100644 (file)
@@ -494,50 +494,6 @@ static inline void unlock_rcu_walk(void)
        br_read_unlock(&vfsmount_lock);
 }
 
-/*
- * When we move over from the RCU domain to properly refcounted
- * long-lived dentries, we need to check the sequence numbers
- * we got before lookup very carefully.
- *
- * We cannot blindly increment a dentry refcount - even if it
- * is not locked - if it is zero, because it may have gone
- * through the final d_kill() logic already.
- *
- * So for a zero refcount, we need to get the spinlock (which is
- * safe even for a dead dentry because the de-allocation is
- * RCU-delayed), and check the sequence count under the lock.
- *
- * Once we have checked the sequence count, we know it is live,
- * and since we hold the spinlock it cannot die from under us.
- *
- * In contrast, if the reference count wasn't zero, we can just
- * increment the lockref without having to take the spinlock.
- * Even if the sequence number ends up being stale, we haven't
- * gone through the final dput() and killed the dentry yet.
- */
-static inline int d_rcu_to_refcount(struct dentry *dentry, seqcount_t *validate, unsigned seq)
-{
-       int gotref;
-
-       gotref = lockref_get_or_lock(&dentry->d_lockref);
-
-       /* Does the sequence number still match? */
-       if (read_seqcount_retry(validate, seq)) {
-               if (gotref)
-                       dput(dentry);
-               else
-                       spin_unlock(&dentry->d_lock);
-               return -ECHILD;
-       }
-
-       /* Get the ref now, if we couldn't get it originally */
-       if (!gotref) {
-               dentry->d_lockref.count++;
-               spin_unlock(&dentry->d_lock);
-       }
-       return 0;
-}
-
 /**
  * unlazy_walk - try to switch to ref-walk mode.
  * @nd: nameidata pathwalk data
@@ -552,16 +508,29 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
 {
        struct fs_struct *fs = current->fs;
        struct dentry *parent = nd->path.dentry;
-       int want_root = 0;
 
        BUG_ON(!(nd->flags & LOOKUP_RCU));
-       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
-               want_root = 1;
-               spin_lock(&fs->lock);
-               if (nd->root.mnt != fs->root.mnt ||
-                               nd->root.dentry != fs->root.dentry)
-                       goto err_root;
-       }
+
+       /*
+        * Get a reference to the parent first: we're
+        * going to make "path_put(nd->path)" valid in
+        * non-RCU context for "terminate_walk()".
+        *
+        * If this doesn't work, return immediately with
+        * RCU walking still active (and then we will do
+        * the RCU walk cleanup in terminate_walk()).
+        */
+       if (!lockref_get_not_dead(&parent->d_lockref))
+               return -ECHILD;
+
+       /*
+        * After the mntget(), we terminate_walk() will do
+        * the right thing for non-RCU mode, and all our
+        * subsequent exit cases should unlock_rcu_walk()
+        * before returning.
+        */
+       mntget(nd->path.mnt);
+       nd->flags &= ~LOOKUP_RCU;
 
        /*
         * For a negative lookup, the lookup sequence point is the parents
@@ -575,30 +544,42 @@ static int unlazy_walk(struct nameidata *nd, struct dentry *dentry)
         * be valid if the child sequence number is still valid.
         */
        if (!dentry) {
-               if (d_rcu_to_refcount(parent, &parent->d_seq, nd->seq) < 0)
-                       goto err_root;
+               if (read_seqcount_retry(&parent->d_seq, nd->seq))
+                       goto out;
                BUG_ON(nd->inode != parent->d_inode);
        } else {
-               if (d_rcu_to_refcount(dentry, &dentry->d_seq, nd->seq) < 0)
-                       goto err_root;
-               if (d_rcu_to_refcount(parent, &dentry->d_seq, nd->seq) < 0)
-                       goto err_parent;
+               if (!lockref_get_not_dead(&dentry->d_lockref))
+                       goto out;
+               if (read_seqcount_retry(&dentry->d_seq, nd->seq))
+                       goto drop_dentry;
        }
-       if (want_root) {
+
+       /*
+        * Sequence counts matched. Now make sure that the root is
+        * still valid and get it if required.
+        */
+       if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
+               spin_lock(&fs->lock);
+               if (nd->root.mnt != fs->root.mnt || nd->root.dentry != fs->root.dentry)
+                       goto unlock_and_drop_dentry;
                path_get(&nd->root);
                spin_unlock(&fs->lock);
        }
-       mntget(nd->path.mnt);
 
        unlock_rcu_walk();
-       nd->flags &= ~LOOKUP_RCU;
        return 0;
 
-err_parent:
+unlock_and_drop_dentry:
+       spin_unlock(&fs->lock);
+drop_dentry:
+       unlock_rcu_walk();
        dput(dentry);
-err_root:
-       if (want_root)
-               spin_unlock(&fs->lock);
+       goto drop_root_mnt;
+out:
+       unlock_rcu_walk();
+drop_root_mnt:
+       if (!(nd->flags & LOOKUP_ROOT))
+               nd->root.mnt = NULL;
        return -ECHILD;
 }
 
@@ -627,10 +608,15 @@ static int complete_walk(struct nameidata *nd)
                if (!(nd->flags & LOOKUP_ROOT))
                        nd->root.mnt = NULL;
 
-               if (d_rcu_to_refcount(dentry, &dentry->d_seq, nd->seq) < 0) {
+               if (unlikely(!lockref_get_not_dead(&dentry->d_lockref))) {
                        unlock_rcu_walk();
                        return -ECHILD;
                }
+               if (read_seqcount_retry(&dentry->d_seq, nd->seq)) {
+                       unlock_rcu_walk();
+                       dput(dentry);
+                       return -ECHILD;
+               }
                mntget(nd->path.mnt);
                unlock_rcu_walk();
        }
@@ -674,29 +660,6 @@ static __always_inline void set_root_rcu(struct nameidata *nd)
        }
 }
 
-static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
-{
-       int ret;
-
-       if (IS_ERR(link))
-               goto fail;
-
-       if (*link == '/') {
-               set_root(nd);
-               path_put(&nd->path);
-               nd->path = nd->root;
-               path_get(&nd->root);
-               nd->flags |= LOOKUP_JUMPED;
-       }
-       nd->inode = nd->path.dentry->d_inode;
-
-       ret = link_path_walk(link, nd);
-       return ret;
-fail:
-       path_put(&nd->path);
-       return PTR_ERR(link);
-}
-
 static void path_put_conditional(struct path *path, struct nameidata *nd)
 {
        dput(path->dentry);
@@ -888,7 +851,20 @@ follow_link(struct path *link, struct nameidata *nd, void **p)
        error = 0;
        s = nd_get_link(nd);
        if (s) {
-               error = __vfs_follow_link(nd, s);
+               if (unlikely(IS_ERR(s))) {
+                       path_put(&nd->path);
+                       put_link(nd, link, *p);
+                       return PTR_ERR(s);
+               }
+               if (*s == '/') {
+                       set_root(nd);
+                       path_put(&nd->path);
+                       nd->path = nd->root;
+                       path_get(&nd->root);
+                       nd->flags |= LOOKUP_JUMPED;
+               }
+               nd->inode = nd->path.dentry->d_inode;
+               error = link_path_walk(s, nd);
                if (unlikely(error))
                        put_link(nd, link, *p);
        }
@@ -2223,7 +2199,7 @@ user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
 }
 
 /**
- * umount_lookup_last - look up last component for umount
+ * mountpoint_last - look up last component for umount
  * @nd:   pathwalk nameidata - currently pointing at parent directory of "last"
  * @path: pointer to container for result
  *
@@ -2250,25 +2226,28 @@ user_path_parent(int dfd, const char __user *path, struct nameidata *nd,
  *         to the link, and nd->path will *not* be put.
  */
 static int
-umount_lookup_last(struct nameidata *nd, struct path *path)
+mountpoint_last(struct nameidata *nd, struct path *path)
 {
        int error = 0;
        struct dentry *dentry;
        struct dentry *dir = nd->path.dentry;
 
-       if (unlikely(nd->flags & LOOKUP_RCU)) {
-               WARN_ON_ONCE(1);
-               error = -ECHILD;
-               goto error_check;
+       /* If we're in rcuwalk, drop out of it to handle last component */
+       if (nd->flags & LOOKUP_RCU) {
+               if (unlazy_walk(nd, NULL)) {
+                       error = -ECHILD;
+                       goto out;
+               }
        }
 
        nd->flags &= ~LOOKUP_PARENT;
 
        if (unlikely(nd->last_type != LAST_NORM)) {
                error = handle_dots(nd, nd->last_type);
-               if (!error)
-                       dentry = dget(nd->path.dentry);
-               goto error_check;
+               if (error)
+                       goto out;
+               dentry = dget(nd->path.dentry);
+               goto done;
        }
 
        mutex_lock(&dir->d_inode->i_mutex);
@@ -2282,44 +2261,46 @@ umount_lookup_last(struct nameidata *nd, struct path *path)
                dentry = d_alloc(dir, &nd->last);
                if (!dentry) {
                        error = -ENOMEM;
-               } else {
-                       dentry = lookup_real(dir->d_inode, dentry, nd->flags);
-                       if (IS_ERR(dentry))
-                               error = PTR_ERR(dentry);
+                       mutex_unlock(&dir->d_inode->i_mutex);
+                       goto out;
+               }
+               dentry = lookup_real(dir->d_inode, dentry, nd->flags);
+               error = PTR_ERR(dentry);
+               if (IS_ERR(dentry)) {
+                       mutex_unlock(&dir->d_inode->i_mutex);
+                       goto out;
                }
        }
        mutex_unlock(&dir->d_inode->i_mutex);
 
-error_check:
-       if (!error) {
-               if (!dentry->d_inode) {
-                       error = -ENOENT;
-                       dput(dentry);
-               } else {
-                       path->dentry = dentry;
-                       path->mnt = mntget(nd->path.mnt);
-                       if (should_follow_link(dentry->d_inode,
-                                               nd->flags & LOOKUP_FOLLOW))
-                               return 1;
-                       follow_mount(path);
-               }
+done:
+       if (!dentry->d_inode) {
+               error = -ENOENT;
+               dput(dentry);
+               goto out;
        }
+       path->dentry = dentry;
+       path->mnt = mntget(nd->path.mnt);
+       if (should_follow_link(dentry->d_inode, nd->flags & LOOKUP_FOLLOW))
+               return 1;
+       follow_mount(path);
+       error = 0;
+out:
        terminate_walk(nd);
        return error;
 }
 
 /**
- * path_umountat - look up a path to be umounted
+ * path_mountpoint - look up a path to be umounted
  * @dfd:       directory file descriptor to start walk from
  * @name:      full pathname to walk
  * @flags:     lookup flags
- * @nd:                pathwalk nameidata
  *
  * Look up the given name, but don't attempt to revalidate the last component.
  * Returns 0 and "path" will be valid on success; Retuns error otherwise.
  */
 static int
-path_umountat(int dfd, const char *name, struct path *path, unsigned int flags)
+path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags)
 {
        struct file *base = NULL;
        struct nameidata nd;
@@ -2334,16 +2315,7 @@ path_umountat(int dfd, const char *name, struct path *path, unsigned int flags)
        if (err)
                goto out;
 
-       /* If we're in rcuwalk, drop out of it to handle last component */
-       if (nd.flags & LOOKUP_RCU) {
-               err = unlazy_walk(&nd, NULL);
-               if (err) {
-                       terminate_walk(&nd);
-                       goto out;
-               }
-       }
-
-       err = umount_lookup_last(&nd, path);
+       err = mountpoint_last(&nd, path);
        while (err > 0) {
                void *cookie;
                struct path link = *path;
@@ -2354,7 +2326,7 @@ path_umountat(int dfd, const char *name, struct path *path, unsigned int flags)
                err = follow_link(&link, &nd, &cookie);
                if (err)
                        break;
-               err = umount_lookup_last(&nd, path);
+               err = mountpoint_last(&nd, path);
                put_link(&nd, &link, cookie);
        }
 out:
@@ -2367,8 +2339,22 @@ out:
        return err;
 }
 
+static int
+filename_mountpoint(int dfd, struct filename *s, struct path *path,
+                       unsigned int flags)
+{
+       int error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU);
+       if (unlikely(error == -ECHILD))
+               error = path_mountpoint(dfd, s->name, path, flags);
+       if (unlikely(error == -ESTALE))
+               error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL);
+       if (likely(!error))
+               audit_inode(s, path->dentry, 0);
+       return error;
+}
+
 /**
- * user_path_umountat - lookup a path from userland in order to umount it
+ * user_path_mountpoint_at - lookup a path from userland in order to umount it
  * @dfd:       directory file descriptor
  * @name:      pathname from userland
  * @flags:     lookup flags
@@ -2382,28 +2368,27 @@ out:
  * Returns 0 and populates "path" on success.
  */
 int
-user_path_umountat(int dfd, const char __user *name, unsigned int flags,
+user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags,
                        struct path *path)
 {
        struct filename *s = getname(name);
        int error;
-
        if (IS_ERR(s))
                return PTR_ERR(s);
-
-       error = path_umountat(dfd, s->name, path, flags | LOOKUP_RCU);
-       if (unlikely(error == -ECHILD))
-               error = path_umountat(dfd, s->name, path, flags);
-       if (unlikely(error == -ESTALE))
-               error = path_umountat(dfd, s->name, path, flags | LOOKUP_REVAL);
-
-       if (likely(!error))
-               audit_inode(s, path->dentry, 0);
-
+       error = filename_mountpoint(dfd, s, path, flags);
        putname(s);
        return error;
 }
 
+int
+kern_path_mountpoint(int dfd, const char *name, struct path *path,
+                       unsigned int flags)
+{
+       struct filename s = {.name = name};
+       return filename_mountpoint(dfd, &s, path, flags);
+}
+EXPORT_SYMBOL(kern_path_mountpoint);
+
 /*
  * It's inline, so penalty for filesystems that don't use sticky bit is
  * minimal.
@@ -2671,6 +2656,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
        int acc_mode;
        int create_error = 0;
        struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
+       bool excl;
 
        BUG_ON(dentry->d_inode);
 
@@ -2684,10 +2670,9 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
        if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
                mode &= ~current_umask();
 
-       if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
+       excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
+       if (excl)
                open_flag &= ~O_TRUNC;
-               *opened |= FILE_CREATED;
-       }
 
        /*
         * Checking write permission is tricky, bacuse we don't know if we are
@@ -2740,12 +2725,6 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                goto out;
        }
 
-       acc_mode = op->acc_mode;
-       if (*opened & FILE_CREATED) {
-               fsnotify_create(dir, dentry);
-               acc_mode = MAY_OPEN;
-       }
-
        if (error) {    /* returned 1, that is */
                if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
                        error = -EIO;
@@ -2755,9 +2734,19 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
                        dput(dentry);
                        dentry = file->f_path.dentry;
                }
-               if (create_error && dentry->d_inode == NULL) {
-                       error = create_error;
-                       goto out;
+               if (*opened & FILE_CREATED)
+                       fsnotify_create(dir, dentry);
+               if (!dentry->d_inode) {
+                       WARN_ON(*opened & FILE_CREATED);
+                       if (create_error) {
+                               error = create_error;
+                               goto out;
+                       }
+               } else {
+                       if (excl && !(*opened & FILE_CREATED)) {
+                               error = -EEXIST;
+                               goto out;
+                       }
                }
                goto looked_up;
        }
@@ -2766,6 +2755,12 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
         * We didn't have the inode before the open, so check open permission
         * here.
         */
+       acc_mode = op->acc_mode;
+       if (*opened & FILE_CREATED) {
+               WARN_ON(!(open_flag & O_CREAT));
+               fsnotify_create(dir, dentry);
+               acc_mode = MAY_OPEN;
+       }
        error = may_open(&file->f_path, acc_mode, open_flag);
        if (error)
                fput(file);
@@ -4244,11 +4239,6 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
        return res;
 }
 
-int vfs_follow_link(struct nameidata *nd, const char *link)
-{
-       return __vfs_follow_link(nd, link);
-}
-
 /* get the link contents into pagecache */
 static char *page_getlink(struct dentry * dentry, struct page **ppage)
 {
@@ -4360,7 +4350,6 @@ EXPORT_SYMBOL(vfs_path_lookup);
 EXPORT_SYMBOL(inode_permission);
 EXPORT_SYMBOL(unlock_rename);
 EXPORT_SYMBOL(vfs_create);
-EXPORT_SYMBOL(vfs_follow_link);
 EXPORT_SYMBOL(vfs_link);
 EXPORT_SYMBOL(vfs_mkdir);
 EXPORT_SYMBOL(vfs_mknod);
index fc2b5226278dbc4d8c0daaa1a2be987fbc7eca5e..da5c494834306178dc9efd3b3826d1b7f0e0d17b 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/security.h>
 #include <linux/idr.h>
 #include <linux/acct.h>                /* acct_auto_close_mnt */
-#include <linux/ramfs.h>       /* init_rootfs */
+#include <linux/init.h>                /* init_rootfs */
 #include <linux/fs_struct.h>   /* get_fs_root et.al. */
 #include <linux/fsnotify.h>    /* fsnotify_vfsmount_delete */
 #include <linux/uaccess.h>
@@ -1321,7 +1321,7 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
        if (!(flags & UMOUNT_NOFOLLOW))
                lookup_flags |= LOOKUP_FOLLOW;
 
-       retval = user_path_umountat(AT_FDCWD, name, lookup_flags, &path);
+       retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path);
        if (retval)
                goto out;
        mnt = real_mount(path.mnt);
index e0bb048e9576209181fb127d109f9e353e802984..03192a66c143a2fd382ea7d75d79bdf596f05d88 100644 (file)
@@ -4,9 +4,10 @@
 
 obj-$(CONFIG_NFS_FS) += nfs.o
 
+CFLAGS_nfstrace.o += -I$(src)
 nfs-y                  := client.o dir.o file.o getroot.o inode.o super.o \
                           direct.o pagelist.o read.o symlink.o unlink.o \
-                          write.o namespace.o mount_clnt.o
+                          write.o namespace.o mount_clnt.o nfstrace.o
 nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
 nfs-$(CONFIG_SYSCTL)   += sysctl.o
 nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
@@ -19,12 +20,14 @@ nfsv3-y := nfs3super.o nfs3client.o nfs3proc.o nfs3xdr.o
 nfsv3-$(CONFIG_NFS_V3_ACL) += nfs3acl.o
 
 obj-$(CONFIG_NFS_V4) += nfsv4.o
+CFLAGS_nfs4trace.o += -I$(src)
 nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
          delegation.o idmap.o callback.o callback_xdr.o callback_proc.o \
-         nfs4namespace.o nfs4getroot.o nfs4client.o dns_resolve.o
+         nfs4namespace.o nfs4getroot.o nfs4client.o nfs4session.o \
+         dns_resolve.o nfs4trace.o
 nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o
 nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
-nfsv4-$(CONFIG_NFS_V4_1)       += nfs4session.o pnfs.o pnfs_dev.o
+nfsv4-$(CONFIG_NFS_V4_1)       += pnfs.o pnfs_dev.o
 
 obj-$(CONFIG_PNFS_FILE_LAYOUT) += nfs_layout_nfsv41_files.o
 nfs_layout_nfsv41_files-y := nfs4filelayout.o nfs4filelayoutdev.o
index e6ebc4c38c812c01c79c587862ac9192d721765a..ae2e87b95453d2b21f746bdb931da675197ad0ba 100644 (file)
@@ -15,6 +15,7 @@
 #include "internal.h"
 #include "pnfs.h"
 #include "nfs4session.h"
+#include "nfs4trace.h"
 
 #ifdef NFS_DEBUG
 #define NFSDBG_FACILITY NFSDBG_CALLBACK
@@ -93,6 +94,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
        default:
                res = htonl(NFS4ERR_RESOURCE);
        }
+       trace_nfs4_recall_delegation(inode, -ntohl(res));
        iput(inode);
 out:
        dprintk("%s: exit with status = %d\n", __func__, ntohl(res));
@@ -301,14 +303,14 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
 {
        struct nfs4_slot *slot;
 
-       dprintk("%s enter. slotid %d seqid %d\n",
+       dprintk("%s enter. slotid %u seqid %u\n",
                __func__, args->csa_slotid, args->csa_sequenceid);
 
        if (args->csa_slotid >= NFS41_BC_MAX_CALLBACKS)
                return htonl(NFS4ERR_BADSLOT);
 
        slot = tbl->slots + args->csa_slotid;
-       dprintk("%s slot table seqid: %d\n", __func__, slot->seq_nr);
+       dprintk("%s slot table seqid: %u\n", __func__, slot->seq_nr);
 
        /* Normal */
        if (likely(args->csa_sequenceid == slot->seq_nr + 1)) {
@@ -318,7 +320,7 @@ validate_seqid(struct nfs4_slot_table *tbl, struct cb_sequenceargs * args)
 
        /* Replay */
        if (args->csa_sequenceid == slot->seq_nr) {
-               dprintk("%s seqid %d is a replay\n",
+               dprintk("%s seqid %u is a replay\n",
                        __func__, args->csa_sequenceid);
                /* Signal process_op to set this error on next op */
                if (args->csa_cachethis == 0)
@@ -462,6 +464,7 @@ out:
        } else
                res->csr_status = status;
 
+       trace_nfs4_cb_sequence(args, res, status);
        dprintk("%s: exit with status = %d res->csr_status %d\n", __func__,
                ntohl(status), ntohl(res->csr_status));
        return status;
@@ -518,7 +521,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
        if (!cps->clp) /* set in cb_sequence */
                goto out;
 
-       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %d\n",
+       dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target highest slotid %u\n",
                rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
                args->crsa_target_highest_slotid);
 
index 340b1eff02679ad3485f51f6c526ba3363b2ef53..2dceee4db07652fd449ef713037a8a268d864f00 100644 (file)
@@ -501,8 +501,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
                                        &nn->nfs_client_list);
                        spin_unlock(&nn->nfs_client_lock);
                        new->cl_flags = cl_init->init_flags;
-                       return rpc_ops->init_client(new, timeparms, ip_addr,
-                                                   authflavour);
+                       return rpc_ops->init_client(new, timeparms, ip_addr);
                }
 
                spin_unlock(&nn->nfs_client_lock);
@@ -694,13 +693,12 @@ EXPORT_SYMBOL_GPL(nfs_init_server_rpcclient);
  * @clp: nfs_client to initialise
  * @timeparms: timeout parameters for underlying RPC transport
  * @ip_addr: IP presentation address (not used)
- * @authflavor: authentication flavor for underlying RPC transport
  *
  * Returns pointer to an NFS client, or an ERR_PTR value.
  */
 struct nfs_client *nfs_init_client(struct nfs_client *clp,
                    const struct rpc_timeout *timeparms,
-                   const char *ip_addr, rpc_authflavor_t authflavour)
+                   const char *ip_addr)
 {
        int error;
 
index 7ec4814e298d4d957fd4bfa17cb59de20e429ba9..ef792f29f831c4c72e3e4edd7db9257165aca2fe 100644 (file)
@@ -20,6 +20,7 @@
 #include "nfs4_fs.h"
 #include "delegation.h"
 #include "internal.h"
+#include "nfs4trace.h"
 
 static void nfs_free_delegation(struct nfs_delegation *delegation)
 {
@@ -160,6 +161,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
                        spin_unlock(&delegation->lock);
                        put_rpccred(oldcred);
                        rcu_read_unlock();
+                       trace_nfs4_reclaim_delegation(inode, res->delegation_type);
                } else {
                        /* We appear to have raced with a delegation return. */
                        spin_unlock(&delegation->lock);
@@ -344,6 +346,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
        spin_lock(&inode->i_lock);
        nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
        spin_unlock(&inode->i_lock);
+       trace_nfs4_set_delegation(inode, res->delegation_type);
 
 out:
        spin_unlock(&clp->cl_lock);
index 7468735d299ed1d4d027ee783b5eeb806f62944a..854a8f05a61007bf14b2dd75e7f080fbb248cce4 100644 (file)
@@ -43,6 +43,8 @@
 #include "internal.h"
 #include "fscache.h"
 
+#include "nfstrace.h"
+
 /* #define NFS_DEBUG_VERBOSE 1 */
 
 static int nfs_opendir(struct inode *, struct file *);
@@ -1100,7 +1102,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
        if (IS_ERR(label))
                goto out_error;
 
+       trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
+       trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
        if (error)
                goto out_bad;
        if (nfs_compare_fh(NFS_FH(inode), fhandle))
@@ -1312,6 +1316,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
 
        parent = dentry->d_parent;
        /* Protect against concurrent sillydeletes */
+       trace_nfs_lookup_enter(dir, dentry, flags);
        nfs_block_sillyrename(parent);
        error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
        if (error == -ENOENT)
@@ -1338,6 +1343,7 @@ no_entry:
        nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
 out_unblock_sillyrename:
        nfs_unblock_sillyrename(parent);
+       trace_nfs_lookup_exit(dir, dentry, flags, error);
        nfs4_label_free(label);
 out:
        nfs_free_fattr(fattr);
@@ -1386,13 +1392,15 @@ static int nfs_finish_open(struct nfs_open_context *ctx,
 {
        int err;
 
+       if ((open_flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
+               *opened |= FILE_CREATED;
+
        err = finish_open(file, dentry, do_open, opened);
        if (err)
                goto out;
        nfs_file_set_open_context(file, ctx);
 
 out:
-       put_nfs_open_context(ctx);
        return err;
 }
 
@@ -1404,6 +1412,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        struct dentry *res;
        struct iattr attr = { .ia_valid = ATTR_OPEN };
        struct inode *inode;
+       unsigned int lookup_flags = 0;
        int err;
 
        /* Expect a negative dentry */
@@ -1412,6 +1421,10 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        dfprintk(VFS, "NFS: atomic_open(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
+       err = nfs_check_flags(open_flags);
+       if (err)
+               return err;
+
        /* NFS only supports OPEN on regular files */
        if ((open_flags & O_DIRECTORY)) {
                if (!d_unhashed(dentry)) {
@@ -1422,6 +1435,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
                         */
                        return -ENOENT;
                }
+               lookup_flags = LOOKUP_OPEN|LOOKUP_DIRECTORY;
                goto no_open;
        }
 
@@ -1442,12 +1456,14 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        if (IS_ERR(ctx))
                goto out;
 
+       trace_nfs_atomic_open_enter(dir, ctx, open_flags);
        nfs_block_sillyrename(dentry->d_parent);
        inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr);
        nfs_unblock_sillyrename(dentry->d_parent);
        if (IS_ERR(inode)) {
-               put_nfs_open_context(ctx);
                err = PTR_ERR(inode);
+               trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
+               put_nfs_open_context(ctx);
                switch (err) {
                case -ENOENT:
                        d_drop(dentry);
@@ -1468,11 +1484,13 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        }
 
        err = nfs_finish_open(ctx, ctx->dentry, file, open_flags, opened);
+       trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
+       put_nfs_open_context(ctx);
 out:
        return err;
 
 no_open:
-       res = nfs_lookup(dir, dentry, 0);
+       res = nfs_lookup(dir, dentry, lookup_flags);
        err = PTR_ERR(res);
        if (IS_ERR(res))
                goto out;
@@ -1596,7 +1614,9 @@ int nfs_create(struct inode *dir, struct dentry *dentry,
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
 
+       trace_nfs_create_enter(dir, dentry, open_flags);
        error = NFS_PROTO(dir)->create(dir, dentry, &attr, open_flags);
+       trace_nfs_create_exit(dir, dentry, open_flags, error);
        if (error != 0)
                goto out_err;
        return 0;
@@ -1624,7 +1644,9 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
        attr.ia_mode = mode;
        attr.ia_valid = ATTR_MODE;
 
+       trace_nfs_mknod_enter(dir, dentry);
        status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
+       trace_nfs_mknod_exit(dir, dentry, status);
        if (status != 0)
                goto out_err;
        return 0;
@@ -1648,7 +1670,9 @@ int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        attr.ia_valid = ATTR_MODE;
        attr.ia_mode = mode | S_IFDIR;
 
+       trace_nfs_mkdir_enter(dir, dentry);
        error = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
+       trace_nfs_mkdir_exit(dir, dentry, error);
        if (error != 0)
                goto out_err;
        return 0;
@@ -1671,12 +1695,21 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry)
        dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n",
                        dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
 
-       error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
-       /* Ensure the VFS deletes this inode */
-       if (error == 0 && dentry->d_inode != NULL)
-               clear_nlink(dentry->d_inode);
-       else if (error == -ENOENT)
-               nfs_dentry_handle_enoent(dentry);
+       trace_nfs_rmdir_enter(dir, dentry);
+       if (dentry->d_inode) {
+               nfs_wait_on_sillyrename(dentry);
+               error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+               /* Ensure the VFS deletes this inode */
+               switch (error) {
+               case 0:
+                       clear_nlink(dentry->d_inode);
+                       break;
+               case -ENOENT:
+                       nfs_dentry_handle_enoent(dentry);
+               }
+       } else
+               error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
+       trace_nfs_rmdir_exit(dir, dentry, error);
 
        return error;
 }
@@ -1704,6 +1737,7 @@ static int nfs_safe_remove(struct dentry *dentry)
                goto out;
        }
 
+       trace_nfs_remove_enter(dir, dentry);
        if (inode != NULL) {
                NFS_PROTO(inode)->return_delegation(inode);
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
@@ -1713,6 +1747,7 @@ static int nfs_safe_remove(struct dentry *dentry)
                error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
        if (error == -ENOENT)
                nfs_dentry_handle_enoent(dentry);
+       trace_nfs_remove_exit(dir, dentry, error);
 out:
        return error;
 }
@@ -1730,13 +1765,14 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
        dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id,
                dir->i_ino, dentry->d_name.name);
 
+       trace_nfs_unlink_enter(dir, dentry);
        spin_lock(&dentry->d_lock);
        if (d_count(dentry) > 1) {
                spin_unlock(&dentry->d_lock);
                /* Start asynchronous writeout of the inode */
                write_inode_now(dentry->d_inode, 0);
                error = nfs_sillyrename(dir, dentry);
-               return error;
+               goto out;
        }
        if (!d_unhashed(dentry)) {
                __d_drop(dentry);
@@ -1748,6 +1784,8 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
                nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
        } else if (need_rehash)
                d_rehash(dentry);
+out:
+       trace_nfs_unlink_exit(dir, dentry, error);
        return error;
 }
 EXPORT_SYMBOL_GPL(nfs_unlink);
@@ -1794,7 +1832,9 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
                memset(kaddr + pathlen, 0, PAGE_SIZE - pathlen);
        kunmap_atomic(kaddr);
 
+       trace_nfs_symlink_enter(dir, dentry);
        error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
+       trace_nfs_symlink_exit(dir, dentry, error);
        if (error != 0) {
                dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s) error %d\n",
                        dir->i_sb->s_id, dir->i_ino,
@@ -1829,6 +1869,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
+       trace_nfs_link_enter(inode, dir, dentry);
        NFS_PROTO(inode)->return_delegation(inode);
 
        d_drop(dentry);
@@ -1837,6 +1878,7 @@ nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
                ihold(inode);
                d_add(dentry, inode);
        }
+       trace_nfs_link_exit(inode, dir, dentry, error);
        return error;
 }
 EXPORT_SYMBOL_GPL(nfs_link);
@@ -1878,6 +1920,7 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
                 d_count(new_dentry));
 
+       trace_nfs_rename_enter(old_dir, old_dentry, new_dir, new_dentry);
        /*
         * For non-directories, check whether the target is busy and if so,
         * make a copy of the dentry and then do a silly-rename. If the
@@ -1924,6 +1967,8 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 out:
        if (rehash)
                d_rehash(rehash);
+       trace_nfs_rename_exit(old_dir, old_dentry,
+                       new_dir, new_dentry, error);
        if (!error) {
                if (new_inode != NULL)
                        nfs_drop_nlink(new_inode);
@@ -1964,17 +2009,18 @@ static void nfs_access_free_list(struct list_head *head)
        }
 }
 
-int nfs_access_cache_shrinker(struct shrinker *shrink,
-                             struct shrink_control *sc)
+unsigned long
+nfs_access_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        LIST_HEAD(head);
        struct nfs_inode *nfsi, *next;
        struct nfs_access_entry *cache;
        int nr_to_scan = sc->nr_to_scan;
        gfp_t gfp_mask = sc->gfp_mask;
+       long freed = 0;
 
        if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
-               return (nr_to_scan == 0) ? 0 : -1;
+               return SHRINK_STOP;
 
        spin_lock(&nfs_access_lru_lock);
        list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) {
@@ -1990,6 +2036,7 @@ int nfs_access_cache_shrinker(struct shrinker *shrink,
                                struct nfs_access_entry, lru);
                list_move(&cache->lru, &head);
                rb_erase(&cache->rb_node, &nfsi->access_cache);
+               freed++;
                if (!list_empty(&nfsi->access_cache_entry_lru))
                        list_move_tail(&nfsi->access_cache_inode_lru,
                                        &nfs_access_lru_list);
@@ -2004,7 +2051,13 @@ remove_lru_entry:
        }
        spin_unlock(&nfs_access_lru_lock);
        nfs_access_free_list(&head);
-       return (atomic_long_read(&nfs_access_nr_entries) / 100) * sysctl_vfs_cache_pressure;
+       return freed;
+}
+
+unsigned long
+nfs_access_cache_count(struct shrinker *shrink, struct shrink_control *sc)
+{
+       return vfs_pressure_ratio(atomic_long_read(&nfs_access_nr_entries));
 }
 
 static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head)
@@ -2173,9 +2226,11 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
        struct nfs_access_entry cache;
        int status;
 
+       trace_nfs_access_enter(inode);
+
        status = nfs_access_get_cached(inode, cred, &cache);
        if (status == 0)
-               goto out;
+               goto out_cached;
 
        /* Be clever: ask server to check for all possible rights */
        cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
@@ -2188,13 +2243,15 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
                        if (!S_ISDIR(inode->i_mode))
                                set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
                }
-               return status;
+               goto out;
        }
        nfs_access_add_cache(inode, &cache);
+out_cached:
+       if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) != 0)
+               status = -EACCES;
 out:
-       if ((mask & ~cache.mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
-               return 0;
-       return -EACCES;
+       trace_nfs_access_exit(inode, status);
+       return status;
 }
 
 static int nfs_open_permission_mask(int openflags)
@@ -2240,11 +2297,6 @@ int nfs_permission(struct inode *inode, int mask)
                case S_IFLNK:
                        goto out;
                case S_IFREG:
-                       /* NFSv4 has atomic_open... */
-                       if (nfs_server_capable(inode, NFS_CAP_ATOMIC_OPEN)
-                                       && (mask & MAY_OPEN)
-                                       && !(mask & MAY_EXEC))
-                               goto out;
                        break;
                case S_IFDIR:
                        /*
index 0bd7a55a5f073befd4d0ce97e87cca2dd0d42e37..91ff089d34126d8ae5d8d4a96bca232fbd921958 100644 (file)
@@ -130,7 +130,6 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_
 
        return -EINVAL;
 #else
-       VM_BUG_ON(iocb->ki_left != PAGE_SIZE);
        VM_BUG_ON(iocb->ki_nbytes != PAGE_SIZE);
 
        if (rw == READ || rw == KERNEL_READ)
index 94e94bd11aae6d0a6c32acf5c16491448edb93f8..1e6bfdbc1aff4403a194798d3c3928993948710d 100644 (file)
@@ -37,6 +37,8 @@
 #include "iostat.h"
 #include "fscache.h"
 
+#include "nfstrace.h"
+
 #define NFSDBG_FACILITY                NFSDBG_FILE
 
 static const struct vm_operations_struct nfs_file_vm_ops;
@@ -294,6 +296,8 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        int ret;
        struct inode *inode = file_inode(file);
 
+       trace_nfs_fsync_enter(inode);
+
        do {
                ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
                if (ret != 0)
@@ -310,6 +314,7 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                end = LLONG_MAX;
        } while (ret == -EAGAIN);
 
+       trace_nfs_fsync_exit(inode, ret);
        return ret;
 }
 
@@ -406,6 +411,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
                        struct page *page, void *fsdata)
 {
        unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+       struct nfs_open_context *ctx = nfs_file_open_context(file);
        int status;
 
        dfprintk(PAGECACHE, "NFS: write_end(%s/%s(%ld), %u@%lld)\n",
@@ -441,6 +447,13 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
        if (status < 0)
                return status;
        NFS_I(mapping->host)->write_io += copied;
+
+       if (nfs_ctx_key_to_expire(ctx)) {
+               status = nfs_wb_all(mapping->host);
+               if (status < 0)
+                       return status;
+       }
+
        return copied;
 }
 
@@ -637,7 +650,8 @@ static int nfs_need_sync_write(struct file *filp, struct inode *inode)
        if (IS_SYNC(inode) || (filp->f_flags & O_DSYNC))
                return 1;
        ctx = nfs_file_open_context(filp);
-       if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags))
+       if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags) ||
+           nfs_ctx_key_to_expire(ctx))
                return 1;
        return 0;
 }
@@ -651,6 +665,10 @@ ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
        ssize_t result;
        size_t count = iov_length(iov, nr_segs);
 
+       result = nfs_key_timeout_notify(iocb->ki_filp, inode);
+       if (result)
+               return result;
+
        if (iocb->ki_filp->f_flags & O_DIRECT)
                return nfs_file_direct_write(iocb, iov, nr_segs, pos, true);
 
index c2c4163d56832fd94193c2865faeb64df11e8b74..567983d2c0ebada3105f5c1ef42bc0c4595c2ca6 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "internal.h"
 #include "netns.h"
+#include "nfs4trace.h"
 
 #define NFS_UINT_MAXLEN 11
 
@@ -63,6 +64,7 @@ struct idmap_legacy_upcalldata {
 };
 
 struct idmap {
+       struct rpc_pipe_dir_object idmap_pdo;
        struct rpc_pipe         *idmap_pipe;
        struct idmap_legacy_upcalldata *idmap_upcall_data;
        struct mutex            idmap_mutex;
@@ -310,7 +312,7 @@ static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
        if (ret < 0)
                goto out_up;
 
-       payload = rcu_dereference(rkey->payload.data);
+       payload = rcu_dereference(rkey->payload.rcudata);
        if (IS_ERR_OR_NULL(payload)) {
                ret = PTR_ERR(payload);
                goto out_up;
@@ -401,16 +403,23 @@ static struct key_type key_type_id_resolver_legacy = {
        .request_key    = nfs_idmap_legacy_upcall,
 };
 
-static void __nfs_idmap_unregister(struct rpc_pipe *pipe)
+static void nfs_idmap_pipe_destroy(struct dentry *dir,
+               struct rpc_pipe_dir_object *pdo)
 {
-       if (pipe->dentry)
+       struct idmap *idmap = pdo->pdo_data;
+       struct rpc_pipe *pipe = idmap->idmap_pipe;
+
+       if (pipe->dentry) {
                rpc_unlink(pipe->dentry);
+               pipe->dentry = NULL;
+       }
 }
 
-static int __nfs_idmap_register(struct dentry *dir,
-                                    struct idmap *idmap,
-                                    struct rpc_pipe *pipe)
+static int nfs_idmap_pipe_create(struct dentry *dir,
+               struct rpc_pipe_dir_object *pdo)
 {
+       struct idmap *idmap = pdo->pdo_data;
+       struct rpc_pipe *pipe = idmap->idmap_pipe;
        struct dentry *dentry;
 
        dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
@@ -420,36 +429,10 @@ static int __nfs_idmap_register(struct dentry *dir,
        return 0;
 }
 
-static void nfs_idmap_unregister(struct nfs_client *clp,
-                                     struct rpc_pipe *pipe)
-{
-       struct net *net = clp->cl_net;
-       struct super_block *pipefs_sb;
-
-       pipefs_sb = rpc_get_sb_net(net);
-       if (pipefs_sb) {
-               __nfs_idmap_unregister(pipe);
-               rpc_put_sb_net(net);
-       }
-}
-
-static int nfs_idmap_register(struct nfs_client *clp,
-                                  struct idmap *idmap,
-                                  struct rpc_pipe *pipe)
-{
-       struct net *net = clp->cl_net;
-       struct super_block *pipefs_sb;
-       int err = 0;
-
-       pipefs_sb = rpc_get_sb_net(net);
-       if (pipefs_sb) {
-               if (clp->cl_rpcclient->cl_dentry)
-                       err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
-                                                  idmap, pipe);
-               rpc_put_sb_net(net);
-       }
-       return err;
-}
+static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = {
+       .create = nfs_idmap_pipe_create,
+       .destroy = nfs_idmap_pipe_destroy,
+};
 
 int
 nfs_idmap_new(struct nfs_client *clp)
@@ -462,23 +445,31 @@ nfs_idmap_new(struct nfs_client *clp)
        if (idmap == NULL)
                return -ENOMEM;
 
+       rpc_init_pipe_dir_object(&idmap->idmap_pdo,
+                       &nfs_idmap_pipe_dir_object_ops,
+                       idmap);
+
        pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
        if (IS_ERR(pipe)) {
                error = PTR_ERR(pipe);
-               kfree(idmap);
-               return error;
-       }
-       error = nfs_idmap_register(clp, idmap, pipe);
-       if (error) {
-               rpc_destroy_pipe_data(pipe);
-               kfree(idmap);
-               return error;
+               goto err;
        }
        idmap->idmap_pipe = pipe;
        mutex_init(&idmap->idmap_mutex);
 
+       error = rpc_add_pipe_dir_object(clp->cl_net,
+                       &clp->cl_rpcclient->cl_pipedir_objects,
+                       &idmap->idmap_pdo);
+       if (error)
+               goto err_destroy_pipe;
+
        clp->cl_idmap = idmap;
        return 0;
+err_destroy_pipe:
+       rpc_destroy_pipe_data(idmap->idmap_pipe);
+err:
+       kfree(idmap);
+       return error;
 }
 
 void
@@ -488,130 +479,26 @@ nfs_idmap_delete(struct nfs_client *clp)
 
        if (!idmap)
                return;
-       nfs_idmap_unregister(clp, idmap->idmap_pipe);
-       rpc_destroy_pipe_data(idmap->idmap_pipe);
        clp->cl_idmap = NULL;
+       rpc_remove_pipe_dir_object(clp->cl_net,
+                       &clp->cl_rpcclient->cl_pipedir_objects,
+                       &idmap->idmap_pdo);
+       rpc_destroy_pipe_data(idmap->idmap_pipe);
        kfree(idmap);
 }
 
-static int __rpc_pipefs_event(struct nfs_client *clp, unsigned long event,
-                             struct super_block *sb)
-{
-       int err = 0;
-
-       switch (event) {
-       case RPC_PIPEFS_MOUNT:
-               err = __nfs_idmap_register(clp->cl_rpcclient->cl_dentry,
-                                               clp->cl_idmap,
-                                               clp->cl_idmap->idmap_pipe);
-               break;
-       case RPC_PIPEFS_UMOUNT:
-               if (clp->cl_idmap->idmap_pipe) {
-                       struct dentry *parent;
-
-                       parent = clp->cl_idmap->idmap_pipe->dentry->d_parent;
-                       __nfs_idmap_unregister(clp->cl_idmap->idmap_pipe);
-                       /*
-                        * Note: This is a dirty hack. SUNRPC hook has been
-                        * called already but simple_rmdir() call for the
-                        * directory returned with error because of idmap pipe
-                        * inside. Thus now we have to remove this directory
-                        * here.
-                        */
-                       if (rpc_rmdir(parent))
-                               printk(KERN_ERR "NFS: %s: failed to remove "
-                                       "clnt dir!\n", __func__);
-               }
-               break;
-       default:
-               printk(KERN_ERR "NFS: %s: unknown event: %ld\n", __func__,
-                       event);
-               return -ENOTSUPP;
-       }
-       return err;
-}
-
-static struct nfs_client *nfs_get_client_for_event(struct net *net, int event)
-{
-       struct nfs_net *nn = net_generic(net, nfs_net_id);
-       struct dentry *cl_dentry;
-       struct nfs_client *clp;
-       int err;
-
-restart:
-       spin_lock(&nn->nfs_client_lock);
-       list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
-               /* Wait for initialisation to finish */
-               if (clp->cl_cons_state == NFS_CS_INITING) {
-                       atomic_inc(&clp->cl_count);
-                       spin_unlock(&nn->nfs_client_lock);
-                       err = nfs_wait_client_init_complete(clp);
-                       nfs_put_client(clp);
-                       if (err)
-                               return NULL;
-                       goto restart;
-               }
-               /* Skip nfs_clients that failed to initialise */
-               if (clp->cl_cons_state < 0)
-                       continue;
-               smp_rmb();
-               if (clp->rpc_ops != &nfs_v4_clientops)
-                       continue;
-               cl_dentry = clp->cl_idmap->idmap_pipe->dentry;
-               if (((event == RPC_PIPEFS_MOUNT) && cl_dentry) ||
-                   ((event == RPC_PIPEFS_UMOUNT) && !cl_dentry))
-                       continue;
-               atomic_inc(&clp->cl_count);
-               spin_unlock(&nn->nfs_client_lock);
-               return clp;
-       }
-       spin_unlock(&nn->nfs_client_lock);
-       return NULL;
-}
-
-static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
-                           void *ptr)
-{
-       struct super_block *sb = ptr;
-       struct nfs_client *clp;
-       int error = 0;
-
-       if (!try_module_get(THIS_MODULE))
-               return 0;
-
-       while ((clp = nfs_get_client_for_event(sb->s_fs_info, event))) {
-               error = __rpc_pipefs_event(clp, event, sb);
-               nfs_put_client(clp);
-               if (error)
-                       break;
-       }
-       module_put(THIS_MODULE);
-       return error;
-}
-
-#define PIPEFS_NFS_PRIO                1
-
-static struct notifier_block nfs_idmap_block = {
-       .notifier_call  = rpc_pipefs_event,
-       .priority       = SUNRPC_PIPEFS_NFS_PRIO,
-};
-
 int nfs_idmap_init(void)
 {
        int ret;
        ret = nfs_idmap_init_keyring();
        if (ret != 0)
                goto out;
-       ret = rpc_pipefs_notifier_register(&nfs_idmap_block);
-       if (ret != 0)
-               nfs_idmap_quit_keyring();
 out:
        return ret;
 }
 
 void nfs_idmap_quit(void)
 {
-       rpc_pipefs_notifier_unregister(&nfs_idmap_block);
        nfs_idmap_quit_keyring();
 }
 
@@ -849,6 +736,7 @@ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_
                if (!uid_valid(*uid))
                        ret = -ERANGE;
        }
+       trace_nfs4_map_name_to_uid(name, namelen, id, ret);
        return ret;
 }
 
@@ -865,6 +753,7 @@ int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size
                if (!gid_valid(*gid))
                        ret = -ERANGE;
        }
+       trace_nfs4_map_group_to_gid(name, namelen, id, ret);
        return ret;
 }
 
@@ -879,6 +768,7 @@ int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf,
                ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(id, buf, buflen);
+       trace_nfs4_map_uid_to_name(buf, ret, id, ret);
        return ret;
 }
 int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen)
@@ -892,5 +782,6 @@ int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf,
                ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);
        if (ret < 0)
                ret = nfs_map_numeric_to_string(id, buf, buflen);
+       trace_nfs4_map_gid_to_group(buf, ret, id, ret);
        return ret;
 }
index 941246f2b43d266827666dee7fec5051c2289586..eda8879171c47e3225ee6891a77aac70e1531af2 100644 (file)
@@ -38,7 +38,6 @@
 #include <linux/slab.h>
 #include <linux/compat.h>
 #include <linux/freezer.h>
-#include <linux/crc32.h>
 
 #include <asm/uaccess.h>
 
@@ -52,6 +51,8 @@
 #include "nfs.h"
 #include "netns.h"
 
+#include "nfstrace.h"
+
 #define NFSDBG_FACILITY                NFSDBG_VFS
 
 #define NFS_64_BIT_INODE_NUMBERS_ENABLED       1
@@ -503,6 +504,8 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
        if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
 
+       trace_nfs_setattr_enter(inode);
+
        /* Write all dirty data */
        if (S_ISREG(inode->i_mode)) {
                nfs_inode_dio_wait(inode);
@@ -522,6 +525,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
                error = nfs_refresh_inode(inode, fattr);
        nfs_free_fattr(fattr);
 out:
+       trace_nfs_setattr_exit(inode, error);
        return error;
 }
 EXPORT_SYMBOL_GPL(nfs_setattr);
@@ -537,7 +541,6 @@ EXPORT_SYMBOL_GPL(nfs_setattr);
  */
 static int nfs_vmtruncate(struct inode * inode, loff_t offset)
 {
-       loff_t oldsize;
        int err;
 
        err = inode_newsize_ok(inode, offset);
@@ -545,11 +548,10 @@ static int nfs_vmtruncate(struct inode * inode, loff_t offset)
                goto out;
 
        spin_lock(&inode->i_lock);
-       oldsize = inode->i_size;
        i_size_write(inode, offset);
        spin_unlock(&inode->i_lock);
 
-       truncate_pagecache(inode, oldsize, offset);
+       truncate_pagecache(inode, offset);
 out:
        return err;
 }
@@ -591,6 +593,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
        int need_atime = NFS_I(inode)->cache_validity & NFS_INO_INVALID_ATIME;
        int err;
 
+       trace_nfs_getattr_enter(inode);
        /* Flush out writes to the server in order to update c/mtime.  */
        if (S_ISREG(inode->i_mode)) {
                nfs_inode_dio_wait(inode);
@@ -621,6 +624,7 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
                stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
        }
 out:
+       trace_nfs_getattr_exit(inode, err);
        return err;
 }
 EXPORT_SYMBOL_GPL(nfs_getattr);
@@ -875,6 +879,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
                inode->i_sb->s_id, (long long)NFS_FILEID(inode));
 
+       trace_nfs_revalidate_inode_enter(inode);
+
        if (is_bad_inode(inode))
                goto out;
        if (NFS_STALE(inode))
@@ -925,6 +931,7 @@ err_out:
        nfs4_label_free(label);
 out:
        nfs_free_fattr(fattr);
+       trace_nfs_revalidate_inode_exit(inode, status);
        return status;
 }
 
@@ -981,6 +988,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
        spin_unlock(&inode->i_lock);
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
        nfs_fscache_wait_on_invalidate(inode);
+
        dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
                        inode->i_sb->s_id, (long long)NFS_FILEID(inode));
        return 0;
@@ -1014,8 +1022,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
                if (ret < 0)
                        goto out;
        }
-       if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+       if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
+               trace_nfs_invalidate_mapping_enter(inode);
                ret = nfs_invalidate_mapping(inode, mapping);
+               trace_nfs_invalidate_mapping_exit(inode, ret);
+       }
+
 out:
        return ret;
 }
@@ -1195,7 +1207,7 @@ u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh)
 {
        /* wireshark uses 32-bit AUTODIN crc and does a bitwise
         * not on the result */
-       return ~crc32(0xFFFFFFFF, &fh->data[0], fh->size);
+       return nfs_fhandle_hash(fh);
 }
 
 /*
@@ -1274,9 +1286,17 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
 
 static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
+       int ret;
+
+       trace_nfs_refresh_inode_enter(inode);
+
        if (nfs_inode_attrs_need_update(inode, fattr))
-               return nfs_update_inode(inode, fattr);
-       return nfs_check_inode_attributes(inode, fattr);
+               ret = nfs_update_inode(inode, fattr);
+       else
+               ret = nfs_check_inode_attributes(inode, fattr);
+
+       trace_nfs_refresh_inode_exit(inode, ret);
+       return ret;
 }
 
 /**
index 3c8373f90ab3150f2530a795b977c1489a344771..38da8c2b81ac09d526b3b402d1964e0c7c17c2dc 100644 (file)
@@ -5,6 +5,7 @@
 #include "nfs4_fs.h"
 #include <linux/mount.h>
 #include <linux/security.h>
+#include <linux/crc32.h>
 
 #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)
 
@@ -185,6 +186,8 @@ extern struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,
                                             int ds_addrlen, int ds_proto,
                                             unsigned int ds_timeo,
                                             unsigned int ds_retrans);
+extern struct rpc_clnt *nfs4_find_or_create_ds_client(struct nfs_client *,
+                                               struct inode *);
 #ifdef CONFIG_PROC_FS
 extern int __init nfs_fs_proc_init(void);
 extern void nfs_fs_proc_exit(void);
@@ -267,11 +270,13 @@ extern struct rpc_procinfo nfs4_procedures[];
 void nfs_close_context(struct nfs_open_context *ctx, int is_sync);
 extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
                           const struct rpc_timeout *timeparms,
-                          const char *ip_addr, rpc_authflavor_t authflavour);
+                          const char *ip_addr);
 
 /* dir.c */
-extern int nfs_access_cache_shrinker(struct shrinker *shrink,
-                                       struct shrink_control *sc);
+extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
+                                           struct shrink_control *sc);
+extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
+                                          struct shrink_control *sc);
 struct dentry *nfs_lookup(struct inode *, struct dentry *, unsigned int);
 int nfs_create(struct inode *, struct dentry *, umode_t, bool);
 int nfs_mkdir(struct inode *, struct dentry *, umode_t);
@@ -355,7 +360,7 @@ extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
 extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
                                    const char *);
 
-extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh);
+extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool);
 #endif
 
 struct nfs_pgio_completion_ops;
@@ -430,6 +435,8 @@ void nfs_request_remove_commit_list(struct nfs_page *req,
 void nfs_init_cinfo(struct nfs_commit_info *cinfo,
                    struct inode *inode,
                    struct nfs_direct_req *dreq);
+int nfs_key_timeout_notify(struct file *filp, struct inode *inode);
+bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx);
 
 #ifdef CONFIG_MIGRATION
 extern int nfs_migrate_page(struct address_space *,
@@ -451,8 +458,7 @@ extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq);
 extern void __nfs4_read_done_cb(struct nfs_read_data *);
 extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                            const struct rpc_timeout *timeparms,
-                           const char *ip_addr,
-                           rpc_authflavor_t authflavour);
+                           const char *ip_addr);
 extern int nfs40_walk_client_list(struct nfs_client *clp,
                                struct nfs_client **result,
                                struct rpc_cred *cred);
@@ -575,3 +581,22 @@ u64 nfs_timespec_to_change_attr(const struct timespec *ts)
 {
        return ((u64)ts->tv_sec << 30) + ts->tv_nsec;
 }
+
+#ifdef CONFIG_CRC32
+/**
+ * nfs_fhandle_hash - calculate the crc32 hash for the filehandle
+ * @fh - pointer to filehandle
+ *
+ * returns a crc32 hash for the filehandle that is compatible with
+ * the one displayed by "wireshark".
+ */
+static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
+{
+       return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size);
+}
+#else
+static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
+{
+       return 0;
+}
+#endif
index f5c84c3efbca24df1ee53947a86dfe28c992cf46..90cb10d7b6936d1fc478f46572728e65e3874f29 100644 (file)
@@ -336,8 +336,8 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        data->arg.create.createmode = NFS3_CREATE_UNCHECKED;
        if (flags & O_EXCL) {
                data->arg.create.createmode  = NFS3_CREATE_EXCLUSIVE;
-               data->arg.create.verifier[0] = jiffies;
-               data->arg.create.verifier[1] = current->pid;
+               data->arg.create.verifier[0] = cpu_to_be32(jiffies);
+               data->arg.create.verifier[1] = cpu_to_be32(current->pid);
        }
 
        sattr->ia_mode &= ~current_umask();
@@ -826,9 +826,10 @@ static void nfs3_proc_read_setup(struct nfs_read_data *data, struct rpc_message
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ];
 }
 
-static void nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+static int nfs3_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 {
        rpc_call_start(task);
+       return 0;
 }
 
 static int nfs3_write_done(struct rpc_task *task, struct nfs_write_data *data)
@@ -847,9 +848,10 @@ static void nfs3_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE];
 }
 
-static void nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+static int nfs3_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 {
        rpc_call_start(task);
+       return 0;
 }
 
 static void nfs3_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
index ee81e354bce7a9d7fbc36023c993fe312ef3e255..28842abafab45ad8b351e96f0ba06517b6676b28 100644 (file)
@@ -38,17 +38,15 @@ struct nfs4_minor_version_ops {
        u32     minor_version;
        unsigned init_caps;
 
-       int     (*call_sync)(struct rpc_clnt *clnt,
-                       struct nfs_server *server,
-                       struct rpc_message *msg,
-                       struct nfs4_sequence_args *args,
-                       struct nfs4_sequence_res *res);
+       int     (*init_client)(struct nfs_client *);
+       void    (*shutdown_client)(struct nfs_client *);
        bool    (*match_stateid)(const nfs4_stateid *,
                        const nfs4_stateid *);
        int     (*find_root_sec)(struct nfs_server *, struct nfs_fh *,
                        struct nfs_fsinfo *);
        int     (*free_lock_state)(struct nfs_server *,
                        struct nfs4_lock_state *);
+       const struct rpc_call_ops *call_sync_ops;
        const struct nfs4_state_recovery_ops *reboot_recovery_ops;
        const struct nfs4_state_recovery_ops *nograce_recovery_ops;
        const struct nfs4_state_maintenance_ops *state_renewal_ops;
@@ -135,6 +133,7 @@ struct nfs4_lock_state {
        struct list_head        ls_locks;       /* Other lock stateids */
        struct nfs4_state *     ls_state;       /* Pointer to open state */
 #define NFS_LOCK_INITIALIZED 0
+#define NFS_LOCK_LOST        1
        unsigned long           ls_flags;
        struct nfs_seqid_counter        ls_seqid;
        nfs4_stateid            ls_stateid;
@@ -193,7 +192,6 @@ struct nfs4_state_recovery_ops {
        int (*recover_open)(struct nfs4_state_owner *, struct nfs4_state *);
        int (*recover_lock)(struct nfs4_state *, struct file_lock *);
        int (*establish_clid)(struct nfs_client *, struct rpc_cred *);
-       struct rpc_cred * (*get_clid_cred)(struct nfs_client *);
        int (*reclaim_complete)(struct nfs_client *, struct rpc_cred *);
        int (*detect_trunking)(struct nfs_client *, struct nfs_client **,
                struct rpc_cred *);
@@ -223,7 +221,7 @@ struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
 /* nfs4proc.c */
 extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struct rpc_cred *, struct nfs4_setclientid_res *);
 extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, struct rpc_cred *);
-extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
+extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *, bool);
 extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, struct rpc_cred *cred);
 extern int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred);
 extern int nfs4_destroy_clientid(struct nfs_client *clp);
@@ -248,9 +246,6 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
        return server->nfs_client->cl_session;
 }
 
-extern int nfs4_setup_sequence(const struct nfs_server *server,
-               struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-               struct rpc_task *task);
 extern int nfs41_setup_sequence(struct nfs4_session *session,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task);
@@ -273,18 +268,63 @@ is_ds_client(struct nfs_client *clp)
 {
        return clp->cl_exchange_flags & EXCHGID4_FLAG_USE_PNFS_DS;
 }
-#else /* CONFIG_NFS_v4_1 */
-static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
+
+static inline bool
+_nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
+                   struct rpc_clnt **clntp, struct rpc_message *msg)
 {
-       return NULL;
+       struct rpc_cred *newcred = NULL;
+       rpc_authflavor_t flavor;
+
+       if (test_bit(sp4_mode, &clp->cl_sp4_flags)) {
+               spin_lock(&clp->cl_lock);
+               if (clp->cl_machine_cred != NULL)
+                       /* don't call get_rpccred on the machine cred -
+                        * a reference will be held for life of clp */
+                       newcred = clp->cl_machine_cred;
+               spin_unlock(&clp->cl_lock);
+               msg->rpc_cred = newcred;
+
+               flavor = clp->cl_rpcclient->cl_auth->au_flavor;
+               WARN_ON_ONCE(flavor != RPC_AUTH_GSS_KRB5I &&
+                            flavor != RPC_AUTH_GSS_KRB5P);
+               *clntp = clp->cl_rpcclient;
+
+               return true;
+       }
+       return false;
 }
 
-static inline int nfs4_setup_sequence(const struct nfs_server *server,
-               struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
-               struct rpc_task *task)
+/*
+ * Function responsible for determining if an rpc_message should use the
+ * machine cred under SP4_MACH_CRED and if so switching the credential and
+ * authflavor (using the nfs_client's rpc_clnt which will be krb5i/p).
+ * Should be called before rpc_call_sync/rpc_call_async.
+ */
+static inline void
+nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode,
+                  struct rpc_clnt **clntp, struct rpc_message *msg)
 {
-       rpc_call_start(task);
-       return 0;
+       _nfs4_state_protect(clp, sp4_mode, clntp, msg);
+}
+
+/*
+ * Special wrapper to nfs4_state_protect for write.
+ * If WRITE can use machine cred but COMMIT cannot, make sure all writes
+ * that use machine cred use NFS_FILE_SYNC.
+ */
+static inline void
+nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
+                        struct rpc_message *msg, struct nfs_write_data *wdata)
+{
+       if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) &&
+           !test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags))
+               wdata->args.stable = NFS_FILE_SYNC;
+}
+#else /* CONFIG_NFS_v4_1 */
+static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server)
+{
+       return NULL;
 }
 
 static inline bool
@@ -298,6 +338,18 @@ is_ds_client(struct nfs_client *clp)
 {
        return false;
 }
+
+static inline void
+nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags,
+                  struct rpc_clnt **clntp, struct rpc_message *msg)
+{
+}
+
+static inline void
+nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
+                        struct rpc_message *msg, struct nfs_write_data *wdata)
+{
+}
 #endif /* CONFIG_NFS_V4_1 */
 
 extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
@@ -308,6 +360,10 @@ extern const u32 nfs4_pathconf_bitmap[3];
 extern const u32 nfs4_fsinfo_bitmap[3];
 extern const u32 nfs4_fs_locations_bitmap[3];
 
+void nfs40_shutdown_client(struct nfs_client *);
+void nfs41_shutdown_client(struct nfs_client *);
+int nfs40_init_client(struct nfs_client *);
+int nfs41_init_client(struct nfs_client *);
 void nfs4_free_client(struct nfs_client *);
 
 struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *);
@@ -319,7 +375,7 @@ extern void nfs4_kill_renewd(struct nfs_client *);
 extern void nfs4_renew_state(struct work_struct *);
 
 /* nfs4state.c */
-struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp);
+struct rpc_cred *nfs4_get_clid_cred(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp);
 struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp);
 int nfs4_discover_server_trunking(struct nfs_client *clp,
@@ -327,7 +383,6 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
 int nfs40_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **, struct rpc_cred *);
 #if defined(CONFIG_NFS_V4_1)
-struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp);
 int nfs41_discover_server_trunking(struct nfs_client *clp,
                        struct nfs_client **, struct rpc_cred *);
 extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
@@ -382,6 +437,7 @@ struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *, struct
 extern bool nfs4_disable_idmapping;
 extern unsigned short max_session_slots;
 extern unsigned short send_implementation_id;
+extern bool recover_lost_locks;
 
 #define NFS4_CLIENT_ID_UNIQ_LEN                (64)
 extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
@@ -429,6 +485,8 @@ static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
 
 #define nfs4_close_state(a, b) do { } while (0)
 #define nfs4_close_sync(a, b) do { } while (0)
+#define nfs4_state_protect(a, b, c, d) do { } while (0)
+#define nfs4_state_protect_write(a, b, c, d) do { } while (0)
 
 #endif /* CONFIG_NFS_V4 */
 #endif /* __LINUX_FS_NFS_NFS4_FS.H */
index 90dce91dd5b5c7aa61a7a17c34242619bbfc5b8d..a860ab566d6e98e5ce2f2f1c42686a15837254bc 100644 (file)
@@ -41,19 +41,138 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
 }
 
 #ifdef CONFIG_NFS_V4_1
-static void nfs4_shutdown_session(struct nfs_client *clp)
+/**
+ * Per auth flavor data server rpc clients
+ */
+struct nfs4_ds_server {
+       struct list_head        list;   /* ds_clp->cl_ds_clients */
+       struct rpc_clnt         *rpc_clnt;
+};
+
+/**
+ * Common lookup case for DS I/O
+ */
+static struct nfs4_ds_server *
+nfs4_find_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
+{
+       struct nfs4_ds_server *dss;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(dss, &ds_clp->cl_ds_clients, list) {
+               if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
+                       continue;
+               goto out;
+       }
+       dss = NULL;
+out:
+       rcu_read_unlock();
+       return dss;
+}
+
+static struct nfs4_ds_server *
+nfs4_add_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor,
+                          struct nfs4_ds_server *new)
+{
+       struct nfs4_ds_server *dss;
+
+       spin_lock(&ds_clp->cl_lock);
+       list_for_each_entry(dss, &ds_clp->cl_ds_clients, list) {
+               if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
+                       continue;
+               goto out;
+       }
+       if (new)
+               list_add_rcu(&new->list, &ds_clp->cl_ds_clients);
+       dss = new;
+out:
+       spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */
+       return dss;
+}
+
+static struct nfs4_ds_server *
+nfs4_alloc_ds_server(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
+{
+       struct nfs4_ds_server *dss;
+
+       dss = kmalloc(sizeof(*dss), GFP_NOFS);
+       if (dss == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       dss->rpc_clnt = rpc_clone_client_set_auth(ds_clp->cl_rpcclient, flavor);
+       if (IS_ERR(dss->rpc_clnt)) {
+               int err = PTR_ERR(dss->rpc_clnt);
+               kfree (dss);
+               return ERR_PTR(err);
+       }
+       INIT_LIST_HEAD(&dss->list);
+
+       return dss;
+}
+
+static void
+nfs4_free_ds_server(struct nfs4_ds_server *dss)
+{
+       rpc_release_client(dss->rpc_clnt);
+       kfree(dss);
+}
+
+/**
+* Find or create a DS rpc client with th MDS server rpc client auth flavor
+* in the nfs_client cl_ds_clients list.
+*/
+struct rpc_clnt *
+nfs4_find_or_create_ds_client(struct nfs_client *ds_clp, struct inode *inode)
+{
+       struct nfs4_ds_server *dss, *new;
+       rpc_authflavor_t flavor = NFS_SERVER(inode)->client->cl_auth->au_flavor;
+
+       dss = nfs4_find_ds_client(ds_clp, flavor);
+       if (dss != NULL)
+               goto out;
+       new = nfs4_alloc_ds_server(ds_clp, flavor);
+       if (IS_ERR(new))
+               return ERR_CAST(new);
+       dss = nfs4_add_ds_client(ds_clp, flavor, new);
+       if (dss != new)
+               nfs4_free_ds_server(new);
+out:
+       return dss->rpc_clnt;
+}
+EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client);
+
+static void
+nfs4_shutdown_ds_clients(struct nfs_client *clp)
+{
+       struct nfs4_ds_server *dss;
+       LIST_HEAD(shutdown_list);
+
+       while (!list_empty(&clp->cl_ds_clients)) {
+               dss = list_entry(clp->cl_ds_clients.next,
+                                       struct nfs4_ds_server, list);
+               list_del(&dss->list);
+               rpc_shutdown_client(dss->rpc_clnt);
+               kfree (dss);
+       }
+}
+
+void nfs41_shutdown_client(struct nfs_client *clp)
 {
        if (nfs4_has_session(clp)) {
+               nfs4_shutdown_ds_clients(clp);
                nfs4_destroy_session(clp->cl_session);
                nfs4_destroy_clientid(clp);
        }
 
 }
-#else /* CONFIG_NFS_V4_1 */
-static void nfs4_shutdown_session(struct nfs_client *clp)
+#endif /* CONFIG_NFS_V4_1 */
+
+void nfs40_shutdown_client(struct nfs_client *clp)
 {
+       if (clp->cl_slot_tbl) {
+               nfs4_release_slot_table(clp->cl_slot_tbl);
+               kfree(clp->cl_slot_tbl);
+       }
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
 {
@@ -73,6 +192,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
 
        spin_lock_init(&clp->cl_lock);
        INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
+       INIT_LIST_HEAD(&clp->cl_ds_clients);
        rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
        clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
        clp->cl_minorversion = cl_init->minorversion;
@@ -97,7 +217,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
 {
        if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
                nfs4_kill_renewd(clp);
-       nfs4_shutdown_session(clp);
+       clp->cl_mvops->shutdown_client(clp);
        nfs4_destroy_callback(clp);
        if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
                nfs_idmap_delete(clp);
@@ -144,34 +264,77 @@ static int nfs4_init_callback(struct nfs_client *clp)
        return 0;
 }
 
+/**
+ * nfs40_init_client - nfs_client initialization tasks for NFSv4.0
+ * @clp - nfs_client to initialize
+ *
+ * Returns zero on success, or a negative errno if some error occurred.
+ */
+int nfs40_init_client(struct nfs_client *clp)
+{
+       struct nfs4_slot_table *tbl;
+       int ret;
+
+       tbl = kzalloc(sizeof(*tbl), GFP_NOFS);
+       if (tbl == NULL)
+               return -ENOMEM;
+
+       ret = nfs4_setup_slot_table(tbl, NFS4_MAX_SLOT_TABLE,
+                                       "NFSv4.0 transport Slot table");
+       if (ret) {
+               kfree(tbl);
+               return ret;
+       }
+
+       clp->cl_slot_tbl = tbl;
+       return 0;
+}
+
+#if defined(CONFIG_NFS_V4_1)
+
+/**
+ * nfs41_init_client - nfs_client initialization tasks for NFSv4.1+
+ * @clp - nfs_client to initialize
+ *
+ * Returns zero on success, or a negative errno if some error occurred.
+ */
+int nfs41_init_client(struct nfs_client *clp)
+{
+       struct nfs4_session *session = NULL;
+
+       /*
+        * Create the session and mark it expired.
+        * When a SEQUENCE operation encounters the expired session
+        * it will do session recovery to initialize it.
+        */
+       session = nfs4_alloc_session(clp);
+       if (!session)
+               return -ENOMEM;
+
+       clp->cl_session = session;
+
+       /*
+        * The create session reply races with the server back
+        * channel probe. Mark the client NFS_CS_SESSION_INITING
+        * so that the client back channel can find the
+        * nfs_client struct
+        */
+       nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
+       return 0;
+}
+
+#endif /* CONFIG_NFS_V4_1 */
+
 /*
  * Initialize the minor version specific parts of an NFS4 client record
  */
 static int nfs4_init_client_minor_version(struct nfs_client *clp)
 {
-#if defined(CONFIG_NFS_V4_1)
-       if (clp->cl_mvops->minor_version) {
-               struct nfs4_session *session = NULL;
-               /*
-                * Create the session and mark it expired.
-                * When a SEQUENCE operation encounters the expired session
-                * it will do session recovery to initialize it.
-                */
-               session = nfs4_alloc_session(clp);
-               if (!session)
-                       return -ENOMEM;
-
-               clp->cl_session = session;
-               /*
-                * The create session reply races with the server back
-                * channel probe. Mark the client NFS_CS_SESSION_INITING
-                * so that the client back channel can find the
-                * nfs_client struct
-                */
-               nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
-       }
-#endif /* CONFIG_NFS_V4_1 */
+       int ret;
 
+       ret = clp->cl_mvops->init_client(clp);
+       if (ret)
+               return ret;
        return nfs4_init_callback(clp);
 }
 
@@ -187,8 +350,7 @@ static int nfs4_init_client_minor_version(struct nfs_client *clp)
  */
 struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                                    const struct rpc_timeout *timeparms,
-                                   const char *ip_addr,
-                                   rpc_authflavor_t authflavour)
+                                   const char *ip_addr)
 {
        char buf[INET6_ADDRSTRLEN + 1];
        struct nfs_client *old;
@@ -723,7 +885,7 @@ static void nfs4_session_set_rwsize(struct nfs_server *server)
 }
 
 static int nfs4_server_common_setup(struct nfs_server *server,
-               struct nfs_fh *mntfh)
+               struct nfs_fh *mntfh, bool auth_probe)
 {
        struct nfs_fattr *fattr;
        int error;
@@ -755,7 +917,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
 
 
        /* Probe the root fh to retrieve its FSID and filehandle */
-       error = nfs4_get_rootfh(server, mntfh);
+       error = nfs4_get_rootfh(server, mntfh, auth_probe);
        if (error < 0)
                goto out;
 
@@ -787,6 +949,7 @@ out:
 static int nfs4_init_server(struct nfs_server *server,
                const struct nfs_parsed_mount_data *data)
 {
+       rpc_authflavor_t pseudoflavor = RPC_AUTH_UNIX;
        struct rpc_timeout timeparms;
        int error;
 
@@ -799,13 +962,16 @@ static int nfs4_init_server(struct nfs_server *server,
        server->flags = data->flags;
        server->options = data->options;
 
+       if (data->auth_flavor_len >= 1)
+               pseudoflavor = data->auth_flavors[0];
+
        /* Get a client record */
        error = nfs4_set_client(server,
                        data->nfs_server.hostname,
                        (const struct sockaddr *)&data->nfs_server.address,
                        data->nfs_server.addrlen,
                        data->client_address,
-                       data->auth_flavors[0],
+                       pseudoflavor,
                        data->nfs_server.protocol,
                        &timeparms,
                        data->minorversion,
@@ -825,7 +991,7 @@ static int nfs4_init_server(struct nfs_server *server,
 
        server->port = data->nfs_server.port;
 
-       error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]);
+       error = nfs_init_server_rpcclient(server, &timeparms, pseudoflavor);
 
 error:
        /* Done */
@@ -843,6 +1009,7 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
                                      struct nfs_subversion *nfs_mod)
 {
        struct nfs_server *server;
+       bool auth_probe;
        int error;
 
        dprintk("--> nfs4_create_server()\n");
@@ -851,12 +1018,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
        if (!server)
                return ERR_PTR(-ENOMEM);
 
+       auth_probe = mount_info->parsed->auth_flavor_len < 1;
+
        /* set up the general RPC client */
        error = nfs4_init_server(server, mount_info->parsed);
        if (error < 0)
                goto error;
 
-       error = nfs4_server_common_setup(server, mount_info->mntfh);
+       error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
        if (error < 0)
                goto error;
 
@@ -909,7 +1078,8 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
        if (error < 0)
                goto error;
 
-       error = nfs4_server_common_setup(server, mntfh);
+       error = nfs4_server_common_setup(server, mntfh,
+                       !(parent_server->flags & NFS_MOUNT_SECFLAVOUR));
        if (error < 0)
                goto error;
 
index 17ed87ef9de809cf76f7ea6e4af4e2b0f3f3f614..b86464ba25e119711142e2b2959c1647d563f3e6 100644 (file)
@@ -39,6 +39,7 @@
 #include "internal.h"
 #include "delegation.h"
 #include "nfs4filelayout.h"
+#include "nfs4trace.h"
 
 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
 
@@ -247,6 +248,7 @@ static int filelayout_read_done_cb(struct rpc_task *task,
        struct nfs_pgio_header *hdr = data->header;
        int err;
 
+       trace_nfs4_pnfs_read(data, task->tk_status);
        err = filelayout_async_handle_error(task, data->args.context->state,
                                            data->ds_clp, hdr->lseg);
 
@@ -363,6 +365,7 @@ static int filelayout_write_done_cb(struct rpc_task *task,
        struct nfs_pgio_header *hdr = data->header;
        int err;
 
+       trace_nfs4_pnfs_write(data, task->tk_status);
        err = filelayout_async_handle_error(task, data->args.context->state,
                                            data->ds_clp, hdr->lseg);
 
@@ -395,6 +398,7 @@ static int filelayout_commit_done_cb(struct rpc_task *task,
 {
        int err;
 
+       trace_nfs4_pnfs_commit_ds(data, task->tk_status);
        err = filelayout_async_handle_error(task, NULL, data->ds_clp,
                                            data->lseg);
 
@@ -524,6 +528,7 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        struct nfs_pgio_header *hdr = data->header;
        struct pnfs_layout_segment *lseg = hdr->lseg;
        struct nfs4_pnfs_ds *ds;
+       struct rpc_clnt *ds_clnt;
        loff_t offset = data->args.offset;
        u32 j, idx;
        struct nfs_fh *fh;
@@ -538,6 +543,11 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        ds = nfs4_fl_prepare_ds(lseg, idx);
        if (!ds)
                return PNFS_NOT_ATTEMPTED;
+
+       ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
+       if (IS_ERR(ds_clnt))
+               return PNFS_NOT_ATTEMPTED;
+
        dprintk("%s USE DS: %s cl_count %d\n", __func__,
                ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count));
 
@@ -552,7 +562,7 @@ filelayout_read_pagelist(struct nfs_read_data *data)
        data->mds_offset = offset;
 
        /* Perform an asynchronous read to ds */
-       nfs_initiate_read(ds->ds_clp->cl_rpcclient, data,
+       nfs_initiate_read(ds_clnt, data,
                                  &filelayout_read_call_ops, RPC_TASK_SOFTCONN);
        return PNFS_ATTEMPTED;
 }
@@ -564,6 +574,7 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        struct nfs_pgio_header *hdr = data->header;
        struct pnfs_layout_segment *lseg = hdr->lseg;
        struct nfs4_pnfs_ds *ds;
+       struct rpc_clnt *ds_clnt;
        loff_t offset = data->args.offset;
        u32 j, idx;
        struct nfs_fh *fh;
@@ -574,6 +585,11 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        ds = nfs4_fl_prepare_ds(lseg, idx);
        if (!ds)
                return PNFS_NOT_ATTEMPTED;
+
+       ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, hdr->inode);
+       if (IS_ERR(ds_clnt))
+               return PNFS_NOT_ATTEMPTED;
+
        dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n",
                __func__, hdr->inode->i_ino, sync, (size_t) data->args.count,
                offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count));
@@ -591,7 +607,7 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync)
        data->args.offset = filelayout_get_dserver_offset(lseg, offset);
 
        /* Perform an asynchronous write */
-       nfs_initiate_write(ds->ds_clp->cl_rpcclient, data,
+       nfs_initiate_write(ds_clnt, data,
                                    &filelayout_write_call_ops, sync,
                                    RPC_TASK_SOFTCONN);
        return PNFS_ATTEMPTED;
@@ -1101,16 +1117,19 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
 {
        struct pnfs_layout_segment *lseg = data->lseg;
        struct nfs4_pnfs_ds *ds;
+       struct rpc_clnt *ds_clnt;
        u32 idx;
        struct nfs_fh *fh;
 
        idx = calc_ds_index_from_commit(lseg, data->ds_commit_index);
        ds = nfs4_fl_prepare_ds(lseg, idx);
-       if (!ds) {
-               prepare_to_resend_writes(data);
-               filelayout_commit_release(data);
-               return -EAGAIN;
-       }
+       if (!ds)
+               goto out_err;
+
+       ds_clnt = nfs4_find_or_create_ds_client(ds->ds_clp, data->inode);
+       if (IS_ERR(ds_clnt))
+               goto out_err;
+
        dprintk("%s ino %lu, how %d cl_count %d\n", __func__,
                data->inode->i_ino, how, atomic_read(&ds->ds_clp->cl_count));
        data->commit_done_cb = filelayout_commit_done_cb;
@@ -1119,9 +1138,13 @@ static int filelayout_initiate_commit(struct nfs_commit_data *data, int how)
        fh = select_ds_fh_from_commit(lseg, data->ds_commit_index);
        if (fh)
                data->args.fh = fh;
-       return nfs_initiate_commit(ds->ds_clp->cl_rpcclient, data,
+       return nfs_initiate_commit(ds_clnt, data,
                                   &filelayout_commit_call_ops, how,
                                   RPC_TASK_SOFTCONN);
+out_err:
+       prepare_to_resend_writes(data);
+       filelayout_commit_release(data);
+       return -EAGAIN;
 }
 
 static int
index 549462e5b9b0633239a1b2766ce17433446874dc..c0b3a16b4a00806f79ea9eb28b6933a8d94bcc52 100644 (file)
@@ -9,7 +9,7 @@
 
 #define NFSDBG_FACILITY                NFSDBG_CLIENT
 
-int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
+int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool auth_probe)
 {
        struct nfs_fsinfo fsinfo;
        int ret = -ENOMEM;
@@ -21,7 +21,7 @@ int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
                goto out;
 
        /* Start by getting the root filehandle from the server */
-       ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo);
+       ret = nfs4_proc_get_rootfh(server, mntfh, &fsinfo, auth_probe);
        if (ret < 0) {
                dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
                goto out;
index cdb0b41a48109e274364e4e69150c5b222114953..2288cd3c92784305c9669fe5e87682ad3293c843 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/sunrpc/clnt.h>
@@ -369,21 +370,33 @@ out:
 struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
                               struct nfs_fh *fh, struct nfs_fattr *fattr)
 {
+       rpc_authflavor_t flavor = server->client->cl_auth->au_flavor;
        struct dentry *parent = dget_parent(dentry);
+       struct inode *dir = parent->d_inode;
+       struct qstr *name = &dentry->d_name;
        struct rpc_clnt *client;
        struct vfsmount *mnt;
 
        /* Look it up again to get its attributes and sec flavor */
-       client = nfs4_proc_lookup_mountpoint(parent->d_inode, &dentry->d_name, fh, fattr);
+       client = nfs4_proc_lookup_mountpoint(dir, name, fh, fattr);
        dput(parent);
        if (IS_ERR(client))
                return ERR_CAST(client);
 
-       if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)
+       if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
                mnt = nfs_do_refmount(client, dentry);
-       else
-               mnt = nfs_do_submount(dentry, fh, fattr, client->cl_auth->au_flavor);
+               goto out;
+       }
 
+       if (client->cl_auth->au_flavor != flavor)
+               flavor = client->cl_auth->au_flavor;
+       else if (!(server->flags & NFS_MOUNT_SECFLAVOUR)) {
+               rpc_authflavor_t new = nfs4_negotiate_security(dir, name);
+               if ((int)new >= 0)
+                       flavor = new;
+       }
+       mnt = nfs_do_submount(dentry, fh, fattr, flavor);
+out:
        rpc_shutdown_client(client);
        return mnt;
 }
index 108a774095f7ef6a53fc04366aec3caa3bfea717..989bb9d3074d0d4c88d63a486f05491423b090d4 100644 (file)
@@ -66,6 +66,8 @@
 #include "nfs4session.h"
 #include "fscache.h"
 
+#include "nfs4trace.h"
+
 #define NFSDBG_FACILITY                NFSDBG_PROC
 
 #define NFS4_POLL_RETRY_MIN    (HZ/10)
@@ -150,6 +152,7 @@ static int nfs4_map_errors(int err)
        case -NFS4ERR_RECALLCONFLICT:
                return -EREMOTEIO;
        case -NFS4ERR_WRONGSEC:
+       case -NFS4ERR_WRONG_CRED:
                return -EPERM;
        case -NFS4ERR_BADOWNER:
        case -NFS4ERR_BADNAME:
@@ -433,6 +436,20 @@ wait_on_recovery:
        return ret;
 }
 
+/*
+ * Return 'true' if 'clp' is using an rpc_client that is integrity protected
+ * or 'false' otherwise.
+ */
+static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
+{
+       rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
+
+       if (flavor == RPC_AUTH_GSS_KRB5I ||
+           flavor == RPC_AUTH_GSS_KRB5P)
+               return true;
+
+       return false;
+}
 
 static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
 {
@@ -447,6 +464,88 @@ static void renew_lease(const struct nfs_server *server, unsigned long timestamp
        do_renew_lease(server->nfs_client, timestamp);
 }
 
+struct nfs4_call_sync_data {
+       const struct nfs_server *seq_server;
+       struct nfs4_sequence_args *seq_args;
+       struct nfs4_sequence_res *seq_res;
+};
+
+static void nfs4_init_sequence(struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res, int cache_reply)
+{
+       args->sa_slot = NULL;
+       args->sa_cache_this = cache_reply;
+       args->sa_privileged = 0;
+
+       res->sr_slot = NULL;
+}
+
+static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
+{
+       args->sa_privileged = 1;
+}
+
+static int nfs40_setup_sequence(const struct nfs_server *server,
+                               struct nfs4_sequence_args *args,
+                               struct nfs4_sequence_res *res,
+                               struct rpc_task *task)
+{
+       struct nfs4_slot_table *tbl = server->nfs_client->cl_slot_tbl;
+       struct nfs4_slot *slot;
+
+       /* slot already allocated? */
+       if (res->sr_slot != NULL)
+               goto out_start;
+
+       spin_lock(&tbl->slot_tbl_lock);
+       if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
+               goto out_sleep;
+
+       slot = nfs4_alloc_slot(tbl);
+       if (IS_ERR(slot)) {
+               if (slot == ERR_PTR(-ENOMEM))
+                       task->tk_timeout = HZ >> 2;
+               goto out_sleep;
+       }
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       args->sa_slot = slot;
+       res->sr_slot = slot;
+
+out_start:
+       rpc_call_start(task);
+       return 0;
+
+out_sleep:
+       if (args->sa_privileged)
+               rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
+                               NULL, RPC_PRIORITY_PRIVILEGED);
+       else
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
+       spin_unlock(&tbl->slot_tbl_lock);
+       return -EAGAIN;
+}
+
+static int nfs40_sequence_done(struct rpc_task *task,
+                              struct nfs4_sequence_res *res)
+{
+       struct nfs4_slot *slot = res->sr_slot;
+       struct nfs4_slot_table *tbl;
+
+       if (!RPC_WAS_SENT(task))
+               goto out;
+
+       tbl = slot->table;
+       spin_lock(&tbl->slot_tbl_lock);
+       if (!nfs41_wake_and_assign_slot(tbl, slot))
+               nfs4_free_slot(tbl, slot);
+       spin_unlock(&tbl->slot_tbl_lock);
+
+       res->sr_slot = NULL;
+out:
+       return 1;
+}
+
 #if defined(CONFIG_NFS_V4_1)
 
 static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
@@ -506,6 +605,7 @@ static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *
                interrupted = true;
        }
 
+       trace_nfs4_sequence_done(session, res);
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
@@ -591,25 +691,11 @@ static int nfs4_sequence_done(struct rpc_task *task,
 {
        if (res->sr_slot == NULL)
                return 1;
+       if (!res->sr_slot->table->session)
+               return nfs40_sequence_done(task, res);
        return nfs41_sequence_done(task, res);
 }
 
-static void nfs41_init_sequence(struct nfs4_sequence_args *args,
-               struct nfs4_sequence_res *res, int cache_reply)
-{
-       args->sa_slot = NULL;
-       args->sa_cache_this = 0;
-       args->sa_privileged = 0;
-       if (cache_reply)
-               args->sa_cache_this = 1;
-       res->sr_slot = NULL;
-}
-
-static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
-{
-       args->sa_privileged = 1;
-}
-
 int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
@@ -647,7 +733,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
 
        args->sa_slot = slot;
 
-       dprintk("<-- %s slotid=%d seqid=%d\n", __func__,
+       dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
                        slot->slot_nr, slot->seq_nr);
 
        res->sr_slot = slot;
@@ -658,6 +744,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
         * set to 1 if an rpc level failure occurs.
         */
        res->sr_status = 1;
+       trace_nfs4_setup_sequence(session, args);
 out_success:
        rpc_call_start(task);
        return 0;
@@ -673,38 +760,30 @@ out_sleep:
 }
 EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
 
-int nfs4_setup_sequence(const struct nfs_server *server,
-                       struct nfs4_sequence_args *args,
-                       struct nfs4_sequence_res *res,
-                       struct rpc_task *task)
+static int nfs4_setup_sequence(const struct nfs_server *server,
+                              struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res,
+                              struct rpc_task *task)
 {
        struct nfs4_session *session = nfs4_get_session(server);
        int ret = 0;
 
-       if (session == NULL) {
-               rpc_call_start(task);
-               goto out;
-       }
+       if (!session)
+               return nfs40_setup_sequence(server, args, res, task);
 
-       dprintk("--> %s clp %p session %p sr_slot %d\n",
+       dprintk("--> %s clp %p session %p sr_slot %u\n",
                __func__, session->clp, session, res->sr_slot ?
-                       res->sr_slot->slot_nr : -1);
+                       res->sr_slot->slot_nr : NFS4_NO_SLOT);
 
        ret = nfs41_setup_sequence(session, args, res, task);
-out:
+
        dprintk("<-- %s status=%d\n", __func__, ret);
        return ret;
 }
 
-struct nfs41_call_sync_data {
-       const struct nfs_server *seq_server;
-       struct nfs4_sequence_args *seq_args;
-       struct nfs4_sequence_res *seq_res;
-};
-
 static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 {
-       struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_call_sync_data *data = calldata;
        struct nfs4_session *session = nfs4_get_session(data->seq_server);
 
        dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
@@ -714,7 +793,7 @@ static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
 
 static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
 {
-       struct nfs41_call_sync_data *data = calldata;
+       struct nfs4_call_sync_data *data = calldata;
 
        nfs41_sequence_done(task, data->seq_res);
 }
@@ -724,6 +803,42 @@ static const struct rpc_call_ops nfs41_call_sync_ops = {
        .rpc_call_done = nfs41_call_sync_done,
 };
 
+#else  /* !CONFIG_NFS_V4_1 */
+
+static int nfs4_setup_sequence(const struct nfs_server *server,
+                              struct nfs4_sequence_args *args,
+                              struct nfs4_sequence_res *res,
+                              struct rpc_task *task)
+{
+       return nfs40_setup_sequence(server, args, res, task);
+}
+
+static int nfs4_sequence_done(struct rpc_task *task,
+                              struct nfs4_sequence_res *res)
+{
+       return nfs40_sequence_done(task, res);
+}
+
+#endif /* !CONFIG_NFS_V4_1 */
+
+static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_call_sync_data *data = calldata;
+       nfs4_setup_sequence(data->seq_server,
+                               data->seq_args, data->seq_res, task);
+}
+
+static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_call_sync_data *data = calldata;
+       nfs4_sequence_done(task, data->seq_res);
+}
+
+static const struct rpc_call_ops nfs40_call_sync_ops = {
+       .rpc_call_prepare = nfs40_call_sync_prepare,
+       .rpc_call_done = nfs40_call_sync_done,
+};
+
 static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                                   struct nfs_server *server,
                                   struct rpc_message *msg,
@@ -732,7 +847,8 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
 {
        int ret;
        struct rpc_task *task;
-       struct nfs41_call_sync_data data = {
+       struct nfs_client *clp = server->nfs_client;
+       struct nfs4_call_sync_data data = {
                .seq_server = server,
                .seq_args = args,
                .seq_res = res,
@@ -740,7 +856,7 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
        struct rpc_task_setup task_setup = {
                .rpc_client = clnt,
                .rpc_message = msg,
-               .callback_ops = &nfs41_call_sync_ops,
+               .callback_ops = clp->cl_mvops->call_sync_ops,
                .callback_data = &data
        };
 
@@ -754,35 +870,6 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
        return ret;
 }
 
-#else
-static
-void nfs41_init_sequence(struct nfs4_sequence_args *args,
-               struct nfs4_sequence_res *res, int cache_reply)
-{
-}
-
-static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
-{
-}
-
-
-static int nfs4_sequence_done(struct rpc_task *task,
-                              struct nfs4_sequence_res *res)
-{
-       return 1;
-}
-#endif /* CONFIG_NFS_V4_1 */
-
-static
-int _nfs4_call_sync(struct rpc_clnt *clnt,
-                   struct nfs_server *server,
-                   struct rpc_message *msg,
-                   struct nfs4_sequence_args *args,
-                   struct nfs4_sequence_res *res)
-{
-       return rpc_call_sync(clnt, msg, 0);
-}
-
 static
 int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs_server *server,
@@ -791,9 +878,8 @@ int nfs4_call_sync(struct rpc_clnt *clnt,
                   struct nfs4_sequence_res *res,
                   int cache_reply)
 {
-       nfs41_init_sequence(args, res, cache_reply);
-       return server->nfs_client->cl_mvops->call_sync(clnt, server, msg,
-                                               args, res);
+       nfs4_init_sequence(args, res, cache_reply);
+       return nfs4_call_sync_sequence(clnt, server, msg, args, res);
 }
 
 static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
@@ -933,7 +1019,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
                p->o_arg.fh = NFS_FH(dentry->d_inode);
        }
        if (attrs != NULL && attrs->ia_valid != 0) {
-               __be32 verf[2];
+               __u32 verf[2];
 
                p->o_arg.u.attrs = &p->attrs;
                memcpy(&p->attrs, attrs, sizeof(p->attrs));
@@ -1103,7 +1189,7 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
                goto no_delegation;
 
        spin_lock(&deleg_cur->lock);
-       if (nfsi->delegation != deleg_cur ||
+       if (rcu_dereference(nfsi->delegation) != deleg_cur ||
           test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
            (deleg_cur->type & fmode) != fmode)
                goto no_delegation_unlock;
@@ -1440,6 +1526,7 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
        int err;
        do {
                err = _nfs4_do_open_reclaim(ctx, state);
+               trace_nfs4_open_reclaim(ctx, 0, err);
                if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
                        continue;
                if (err != -NFS4ERR_DELAY)
@@ -1524,10 +1611,20 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state
        return nfs4_handle_delegation_recall_error(server, state, stateid, err);
 }
 
+static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs4_opendata *data = calldata;
+
+       nfs40_setup_sequence(data->o_arg.server, &data->o_arg.seq_args,
+                               &data->o_res.seq_res, task);
+}
+
 static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
 {
        struct nfs4_opendata *data = calldata;
 
+       nfs40_sequence_done(task, &data->o_res.seq_res);
+
        data->rpc_status = task->tk_status;
        if (data->rpc_status == 0) {
                nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
@@ -1556,6 +1653,7 @@ out_free:
 }
 
 static const struct rpc_call_ops nfs4_open_confirm_ops = {
+       .rpc_call_prepare = nfs4_open_confirm_prepare,
        .rpc_call_done = nfs4_open_confirm_done,
        .rpc_release = nfs4_open_confirm_release,
 };
@@ -1583,6 +1681,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
        };
        int status;
 
+       nfs4_init_sequence(&data->o_arg.seq_args, &data->o_res.seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -1742,7 +1841,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
        };
        int status;
 
-       nfs41_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
+       nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
        kref_get(&data->kref);
        data->rpc_done = 0;
        data->rpc_status = 0;
@@ -1895,6 +1994,7 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
 
        do {
                err = _nfs4_open_expired(ctx, state);
+               trace_nfs4_open_expired(ctx, 0, err);
                if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
                        continue;
                switch (err) {
@@ -1944,6 +2044,7 @@ static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
                cred = get_rpccred(delegation->cred);
                rcu_read_unlock();
                status = nfs41_test_stateid(server, stateid, cred);
+               trace_nfs4_test_delegation_stateid(state, NULL, status);
        } else
                rcu_read_unlock();
 
@@ -1986,6 +2087,7 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
                return -NFS4ERR_BAD_STATEID;
 
        status = nfs41_test_stateid(server, stateid, cred);
+       trace_nfs4_test_open_stateid(state, NULL, status);
        if (status != NFS_OK) {
                /* Free the stateid unless the server explicitly
                 * informs us the stateid is unrecognized. */
@@ -2197,6 +2299,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
        do {
                status = _nfs4_do_open(dir, ctx, flags, sattr, label);
                res = ctx->state;
+               trace_nfs4_open_file(ctx, flags, status);
                if (status == 0)
                        break;
                /* NOTE: BAD_SEQID means the server and client disagree about the
@@ -2310,6 +2413,7 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
        int err;
        do {
                err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
+               trace_nfs4_setattr(inode, err);
                switch (err) {
                case -NFS4ERR_OPENMODE:
                        if (!(sattr->ia_valid & ATTR_SIZE)) {
@@ -2387,6 +2491,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
        dprintk("%s: begin!\n", __func__);
        if (!nfs4_sequence_done(task, &calldata->res.seq_res))
                return;
+       trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
         /* hmm. we are done with the inode, and in the process of freeing
         * the state_owner. we keep this around to process errors
         */
@@ -2511,10 +2616,13 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
        };
        int status = -ENOMEM;
 
+       nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
+               &task_setup_data.rpc_client, &msg);
+
        calldata = kzalloc(sizeof(*calldata), gfp_mask);
        if (calldata == NULL)
                goto out;
-       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
+       nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
        calldata->inode = state->inode;
        calldata->state = state;
        calldata->arg.fh = NFS_FH(state->inode);
@@ -2690,6 +2798,7 @@ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
        int err;
        do {
                err = _nfs4_lookup_root(server, fhandle, info);
+               trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
@@ -2705,10 +2814,13 @@ out:
 static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
                                struct nfs_fsinfo *info, rpc_authflavor_t flavor)
 {
+       struct rpc_auth_create_args auth_args = {
+               .pseudoflavor = flavor,
+       };
        struct rpc_auth *auth;
        int ret;
 
-       auth = rpcauth_create(flavor, server->client);
+       auth = rpcauth_create(&auth_args, server->client);
        if (IS_ERR(auth)) {
                ret = -EACCES;
                goto out;
@@ -2772,18 +2884,27 @@ static int nfs4_do_find_root_sec(struct nfs_server *server,
  * @server: initialized nfs_server handle
  * @fhandle: we fill in the pseudo-fs root file handle
  * @info: we fill in an FSINFO struct
+ * @auth_probe: probe the auth flavours
  *
  * Returns zero on success, or a negative errno.
  */
 int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
-                        struct nfs_fsinfo *info)
+                        struct nfs_fsinfo *info,
+                        bool auth_probe)
 {
        int status;
 
-       status = nfs4_lookup_root(server, fhandle, info);
-       if ((status == -NFS4ERR_WRONGSEC) &&
-           !(server->flags & NFS_MOUNT_SECFLAVOUR))
+       switch (auth_probe) {
+       case false:
+               status = nfs4_lookup_root(server, fhandle, info);
+               if (status != -NFS4ERR_WRONGSEC)
+                       break;
+               /* Did user force a 'sec=' mount option? */
+               if (server->flags & NFS_MOUNT_SECFLAVOUR)
+                       break;
+       default:
                status = nfs4_do_find_root_sec(server, fhandle, info);
+       }
 
        if (status == 0)
                status = nfs4_server_capabilities(server, fhandle);
@@ -2899,8 +3020,9 @@ static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(server,
-                               _nfs4_proc_getattr(server, fhandle, fattr, label),
+               err = _nfs4_proc_getattr(server, fhandle, fattr, label);
+               trace_nfs4_getattr(server, fhandle, fattr, err);
+               err = nfs4_handle_exception(server, err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -2940,10 +3062,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
        
        /* Deal with open(O_TRUNC) */
        if (sattr->ia_valid & ATTR_OPEN)
-               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN);
+               sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
 
        /* Optimization: if the end result is no change, don't RPC */
-       if ((sattr->ia_valid & ~(ATTR_FILE)) == 0)
+       if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
                return 0;
 
        /* Search for an existing open(O_WRITE) file */
@@ -3020,6 +3142,7 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
        int err;
        do {
                err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
+               trace_nfs4_lookup(dir, name, err);
                switch (err) {
                case -NFS4ERR_BADNAME:
                        err = -ENOENT;
@@ -3031,7 +3154,9 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
                        err = -EPERM;
                        if (client != *clnt)
                                goto out;
-
+                       /* No security negotiation if the user specified 'sec=' */
+                       if (NFS_SERVER(dir)->flags & NFS_MOUNT_SECFLAVOUR)
+                               goto out;
                        client = nfs4_create_sec_client(client, dir, name);
                        if (IS_ERR(client))
                                return PTR_ERR(client);
@@ -3134,8 +3259,9 @@ static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_proc_access(inode, entry),
+               err = _nfs4_proc_access(inode, entry);
+               trace_nfs4_access(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3188,8 +3314,9 @@ static int nfs4_proc_readlink(struct inode *inode, struct page *page,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_proc_readlink(inode, page, pgbase, pglen),
+               err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
+               trace_nfs4_readlink(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3253,8 +3380,9 @@ static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_remove(dir, name),
+               err = _nfs4_proc_remove(dir, name);
+               trace_nfs4_remove(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3268,7 +3396,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
 
        res->server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
-       nfs41_init_sequence(&args->seq_args, &res->seq_res, 1);
+       nfs4_init_sequence(&args->seq_args, &res->seq_res, 1);
 
        nfs_fattr_init(res->dir_attr);
 }
@@ -3283,7 +3411,8 @@ static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlin
 
 static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
 {
-       struct nfs_removeres *res = task->tk_msg.rpc_resp;
+       struct nfs_unlinkdata *data = task->tk_calldata;
+       struct nfs_removeres *res = &data->res;
 
        if (!nfs4_sequence_done(task, &res->seq_res))
                return 0;
@@ -3301,7 +3430,7 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
        res->server = server;
-       nfs41_init_sequence(&arg->seq_args, &res->seq_res, 1);
+       nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1);
 }
 
 static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
@@ -3315,7 +3444,8 @@ static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renam
 static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
                                 struct inode *new_dir)
 {
-       struct nfs_renameres *res = task->tk_msg.rpc_resp;
+       struct nfs_renamedata *data = task->tk_calldata;
+       struct nfs_renameres *res = &data->res;
 
        if (!nfs4_sequence_done(task, &res->seq_res))
                return 0;
@@ -3361,9 +3491,10 @@ static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(old_dir),
-                               _nfs4_proc_rename(old_dir, old_name,
-                                       new_dir, new_name),
+               err = _nfs4_proc_rename(old_dir, old_name,
+                                       new_dir, new_name);
+               trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(old_dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3525,9 +3656,9 @@ static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
        label = nfs4_label_init_security(dir, dentry, sattr, &l);
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_symlink(dir, dentry, page,
-                                                       len, sattr, label),
+               err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
+               trace_nfs4_symlink(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
 
@@ -3564,8 +3695,9 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
 
        sattr->ia_mode &= ~current_umask();
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_mkdir(dir, dentry, sattr, label),
+               err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
+               trace_nfs4_mkdir(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        nfs4_label_release_security(label);
@@ -3618,9 +3750,10 @@ static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
-                               _nfs4_proc_readdir(dentry, cred, cookie,
-                                       pages, count, plus),
+               err = _nfs4_proc_readdir(dentry, cred, cookie,
+                               pages, count, plus);
+               trace_nfs4_readdir(dentry->d_inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -3672,8 +3805,9 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
 
        sattr->ia_mode &= ~current_umask();
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_mknod(dir, dentry, sattr, label, rdev),
+               err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
+               trace_nfs4_mknod(dir, &dentry->d_name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
 
@@ -3741,6 +3875,7 @@ static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, str
 
        do {
                err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
+               trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
                if (err == 0) {
                        struct nfs_client *clp = server->nfs_client;
 
@@ -3859,6 +3994,7 @@ static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
 {
        struct nfs_server *server = NFS_SERVER(data->header->inode);
 
+       trace_nfs4_read(data, task->tk_status);
        if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@ -3902,24 +4038,29 @@ static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message
        data->timestamp   = jiffies;
        data->read_done_cb = nfs4_read_done_cb;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
 }
 
-static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+static int nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 {
        if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task))
-               return;
-       nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
-                       data->args.lock_context, FMODE_READ);
+               return 0;
+       if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+                               data->args.lock_context, FMODE_READ) == -EIO)
+               return -EIO;
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               return -EIO;
+       return 0;
 }
 
 static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
 {
        struct inode *inode = data->header->inode;
        
+       trace_nfs4_write(data, task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@ -3985,18 +4126,22 @@ static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_messag
        data->timestamp   = jiffies;
 
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
-static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+static int nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 {
        if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
                        &data->args.seq_args,
                        &data->res.seq_res,
                        task))
-               return;
-       nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
-                       data->args.lock_context, FMODE_WRITE);
+               return 0;
+       if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
+                               data->args.lock_context, FMODE_WRITE) == -EIO)
+               return -EIO;
+       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
+               return -EIO;
+       return 0;
 }
 
 static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
@@ -4011,6 +4156,7 @@ static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *da
 {
        struct inode *inode = data->inode;
 
+       trace_nfs4_commit(data, task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return -EAGAIN;
@@ -4033,7 +4179,7 @@ static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_mess
                data->commit_done_cb = nfs4_commit_done_cb;
        data->res.server = server;
        msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
 }
 
 struct nfs4_renewdata {
@@ -4062,6 +4208,7 @@ static void nfs4_renew_done(struct rpc_task *task, void *calldata)
        struct nfs_client *clp = data->client;
        unsigned long timestamp = data->timestamp;
 
+       trace_nfs4_renew_async(clp, task->tk_status);
        if (task->tk_status < 0) {
                /* Unless we're shutting down, schedule state recovery! */
                if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
@@ -4319,6 +4466,7 @@ static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bufl
        ssize_t ret;
        do {
                ret = __nfs4_get_acl_uncached(inode, buf, buflen);
+               trace_nfs4_get_acl(inode, ret);
                if (ret >= 0)
                        break;
                ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
@@ -4398,8 +4546,9 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               __nfs4_proc_set_acl(inode, buf, buflen),
+               err = __nfs4_proc_set_acl(inode, buf, buflen);
+               trace_nfs4_set_acl(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -4452,8 +4601,9 @@ static int nfs4_get_security_label(struct inode *inode, void *buf,
                return -EOPNOTSUPP;
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_get_security_label(inode, buf, buflen),
+               err = _nfs4_get_security_label(inode, buf, buflen);
+               trace_nfs4_get_security_label(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -4505,9 +4655,10 @@ static int nfs4_do_set_security_label(struct inode *inode,
        int err;
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(inode),
-                               _nfs4_do_set_security_label(inode, ilabel,
-                               fattr, olabel),
+               err = _nfs4_do_set_security_label(inode, ilabel,
+                               fattr, olabel);
+               trace_nfs4_set_security_label(inode, err);
+               err = nfs4_handle_exception(NFS_SERVER(inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -4630,11 +4781,11 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
                /* An impossible timestamp guarantees this value
                 * will never match a generated boot time. */
                verf[0] = 0;
-               verf[1] = (__be32)(NSEC_PER_SEC + 1);
+               verf[1] = cpu_to_be32(NSEC_PER_SEC + 1);
        } else {
                struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
-               verf[0] = (__be32)nn->boot_time.tv_sec;
-               verf[1] = (__be32)nn->boot_time.tv_nsec;
+               verf[0] = cpu_to_be32(nn->boot_time.tv_sec);
+               verf[1] = cpu_to_be32(nn->boot_time.tv_nsec);
        }
        memcpy(bootverf->data, verf, sizeof(bootverf->data));
 }
@@ -4660,10 +4811,14 @@ static unsigned int
 nfs4_init_uniform_client_string(const struct nfs_client *clp,
                                char *buf, size_t len)
 {
-       char *nodename = clp->cl_rpcclient->cl_nodename;
+       const char *nodename = clp->cl_rpcclient->cl_nodename;
 
        if (nfs4_client_id_uniquifier[0] != '\0')
-               nodename = nfs4_client_id_uniquifier;
+               return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s",
+                               clp->rpc_ops->version,
+                               clp->cl_minorversion,
+                               nfs4_client_id_uniquifier,
+                               nodename);
        return scnprintf(buf, len, "Linux NFSv%u.%u %s",
                                clp->rpc_ops->version, clp->cl_minorversion,
                                nodename);
@@ -4724,6 +4879,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                setclientid.sc_name_len, setclientid.sc_name);
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_setclientid(clp, status);
        dprintk("NFS reply setclientid: %d\n", status);
        return status;
 }
@@ -4751,6 +4907,7 @@ int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
                clp->cl_rpcclient->cl_auth->au_ops->au_name,
                clp->cl_clientid);
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_setclientid_confirm(clp, status);
        dprintk("NFS reply setclientid_confirm: %d\n", status);
        return status;
 }
@@ -4772,6 +4929,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
        if (!nfs4_sequence_done(task, &data->res.seq_res))
                return;
 
+       trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
        switch (task->tk_status) {
        case -NFS4ERR_STALE_STATEID:
        case -NFS4ERR_EXPIRED:
@@ -4793,7 +4951,6 @@ static void nfs4_delegreturn_release(void *calldata)
        kfree(calldata);
 }
 
-#if defined(CONFIG_NFS_V4_1)
 static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
 {
        struct nfs4_delegreturndata *d_data;
@@ -4805,12 +4962,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
                        &d_data->res.seq_res,
                        task);
 }
-#endif /* CONFIG_NFS_V4_1 */
 
 static const struct rpc_call_ops nfs4_delegreturn_ops = {
-#if defined(CONFIG_NFS_V4_1)
        .rpc_call_prepare = nfs4_delegreturn_prepare,
-#endif /* CONFIG_NFS_V4_1 */
        .rpc_call_done = nfs4_delegreturn_done,
        .rpc_release = nfs4_delegreturn_release,
 };
@@ -4835,7 +4989,7 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co
        data = kzalloc(sizeof(*data), GFP_NOFS);
        if (data == NULL)
                return -ENOMEM;
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        data->args.fhandle = &data->fh;
        data->args.stateid = &data->stateid;
        data->args.bitmask = server->cache_consistency_bitmask;
@@ -4875,6 +5029,7 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
        int err;
        do {
                err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
+               trace_nfs4_delegreturn(inode, err);
                switch (err) {
                        case -NFS4ERR_STALE_STATEID:
                        case -NFS4ERR_EXPIRED:
@@ -4949,8 +5104,9 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *
        int err;
 
        do {
-               err = nfs4_handle_exception(NFS_SERVER(state->inode),
-                               _nfs4_proc_getlk(state, cmd, request),
+               err = _nfs4_proc_getlk(state, cmd, request);
+               trace_nfs4_get_lock(request, state, cmd, err);
+               err = nfs4_handle_exception(NFS_SERVER(state->inode), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -5087,6 +5243,9 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                .flags = RPC_TASK_ASYNC,
        };
 
+       nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
+               NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg);
+
        /* Ensure this is an unlock - when canceling a lock, the
         * canceled lock is passed in, and it won't be an unlock.
         */
@@ -5098,7 +5257,7 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                return ERR_PTR(-ENOMEM);
        }
 
-       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
@@ -5148,6 +5307,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
        rpc_put_task(task);
 out:
        request->fl_flags = fl_flags;
+       trace_nfs4_unlock(request, state, F_SETLK, status);
        return status;
 }
 
@@ -5333,7 +5493,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f
                return -ENOMEM;
        if (IS_SETLKW(cmd))
                data->arg.block = 1;
-       nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
@@ -5371,6 +5531,7 @@ static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
+               trace_nfs4_lock_reclaim(request, state, F_SETLK, err);
                if (err != -NFS4ERR_DELAY)
                        break;
                nfs4_handle_exception(server, err, &exception);
@@ -5389,10 +5550,15 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
        err = nfs4_set_lock_state(state, request);
        if (err != 0)
                return err;
+       if (!recover_lost_locks) {
+               set_bit(NFS_LOCK_LOST, &request->fl_u.nfs4_fl.owner->ls_flags);
+               return 0;
+       }
        do {
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
+               trace_nfs4_lock_expired(request, state, F_SETLK, err);
                switch (err) {
                default:
                        goto out;
@@ -5428,6 +5594,7 @@ static int nfs41_check_expired_locks(struct nfs4_state *state)
                        status = nfs41_test_stateid(server,
                                        &lsp->ls_stateid,
                                        cred);
+                       trace_nfs4_test_lock_stateid(state, lsp, status);
                        if (status != NFS_OK) {
                                /* Free the stateid unless the server
                                 * informs us the stateid is unrecognized. */
@@ -5515,6 +5682,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
 
        do {
                err = _nfs4_proc_setlk(state, cmd, request);
+               trace_nfs4_set_lock(request, state, cmd, err);
                if (err == -NFS4ERR_DENIED)
                        err = -EAGAIN;
                err = nfs4_handle_exception(NFS_SERVER(state->inode),
@@ -5597,8 +5765,23 @@ struct nfs_release_lockowner_data {
        struct nfs4_lock_state *lsp;
        struct nfs_server *server;
        struct nfs_release_lockowner_args args;
+       struct nfs4_sequence_args seq_args;
+       struct nfs4_sequence_res seq_res;
 };
 
+static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata)
+{
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs40_setup_sequence(data->server,
+                               &data->seq_args, &data->seq_res, task);
+}
+
+static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
+{
+       struct nfs_release_lockowner_data *data = calldata;
+       nfs40_sequence_done(task, &data->seq_res);
+}
+
 static void nfs4_release_lockowner_release(void *calldata)
 {
        struct nfs_release_lockowner_data *data = calldata;
@@ -5607,6 +5790,8 @@ static void nfs4_release_lockowner_release(void *calldata)
 }
 
 static const struct rpc_call_ops nfs4_release_lockowner_ops = {
+       .rpc_call_prepare = nfs4_release_lockowner_prepare,
+       .rpc_call_done = nfs4_release_lockowner_done,
        .rpc_release = nfs4_release_lockowner_release,
 };
 
@@ -5619,14 +5804,17 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st
 
        if (server->nfs_client->cl_mvops->minor_version != 0)
                return -EINVAL;
+
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
+       nfs4_init_sequence(&data->seq_args, &data->seq_res, 0);
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
        data->args.lock_owner.id = lsp->ls_seqid.owner_id;
        data->args.lock_owner.s_dev = server->s_dev;
+
        msg.rpc_argp = &data->args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
@@ -5781,14 +5969,23 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_fs_locations(client, dir, name, fs_locations, page),
+               err = _nfs4_proc_fs_locations(client, dir, name,
+                               fs_locations, page);
+               trace_nfs4_get_fs_locations(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
 }
 
-static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
+/**
+ * If 'use_integrity' is true and the state managment nfs_client
+ * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
+ * and the machine credential as per RFC3530bis and RFC5661 Security
+ * Considerations sections. Otherwise, just use the user cred with the
+ * filesystem's rpc_client.
+ */
+static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors, bool use_integrity)
 {
        int status;
        struct nfs4_secinfo_arg args = {
@@ -5803,10 +6000,27 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
+       struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
+       struct rpc_cred *cred = NULL;
+
+       if (use_integrity) {
+               clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient;
+               cred = nfs4_get_clid_cred(NFS_SERVER(dir)->nfs_client);
+               msg.rpc_cred = cred;
+       }
 
        dprintk("NFS call  secinfo %s\n", name->name);
-       status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
+
+       nfs4_state_protect(NFS_SERVER(dir)->nfs_client,
+               NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
+
+       status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
+                               &res.seq_res, 0);
        dprintk("NFS reply  secinfo: %d\n", status);
+
+       if (cred)
+               put_rpccred(cred);
+
        return status;
 }
 
@@ -5816,8 +6030,23 @@ int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = nfs4_handle_exception(NFS_SERVER(dir),
-                               _nfs4_proc_secinfo(dir, name, flavors),
+               err = -NFS4ERR_WRONGSEC;
+
+               /* try to use integrity protection with machine cred */
+               if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
+                       err = _nfs4_proc_secinfo(dir, name, flavors, true);
+
+               /*
+                * if unable to use integrity protection, or SECINFO with
+                * integrity protection returns NFS4ERR_WRONGSEC (which is
+                * disallowed by spec, but exists in deployed servers) use
+                * the current filesystem's rpc_client and the user cred.
+                */
+               if (err == -NFS4ERR_WRONGSEC)
+                       err = _nfs4_proc_secinfo(dir, name, flavors, false);
+
+               trace_nfs4_secinfo(dir, name, err);
+               err = nfs4_handle_exception(NFS_SERVER(dir), err,
                                &exception);
        } while (exception.retry);
        return err;
@@ -5881,6 +6110,7 @@ int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred
        }
 
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_bind_conn_to_session(clp, status);
        if (status == 0) {
                if (memcmp(res.session->sess_id.data,
                    clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
@@ -5909,16 +6139,126 @@ out:
 }
 
 /*
- * nfs4_proc_exchange_id()
+ * Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map
+ * and operations we'd like to see to enable certain features in the allow map
+ */
+static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
+       .how = SP4_MACH_CRED,
+       .enforce.u.words = {
+               [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+                     1 << (OP_EXCHANGE_ID - 32) |
+                     1 << (OP_CREATE_SESSION - 32) |
+                     1 << (OP_DESTROY_SESSION - 32) |
+                     1 << (OP_DESTROY_CLIENTID - 32)
+       },
+       .allow.u.words = {
+               [0] = 1 << (OP_CLOSE) |
+                     1 << (OP_LOCKU) |
+                     1 << (OP_COMMIT),
+               [1] = 1 << (OP_SECINFO - 32) |
+                     1 << (OP_SECINFO_NO_NAME - 32) |
+                     1 << (OP_TEST_STATEID - 32) |
+                     1 << (OP_FREE_STATEID - 32) |
+                     1 << (OP_WRITE - 32)
+       }
+};
+
+/*
+ * Select the state protection mode for client `clp' given the server results
+ * from exchange_id in `sp'.
  *
- * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ * Returns 0 on success, negative errno otherwise.
+ */
+static int nfs4_sp4_select_mode(struct nfs_client *clp,
+                                struct nfs41_state_protection *sp)
+{
+       static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
+               [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
+                     1 << (OP_EXCHANGE_ID - 32) |
+                     1 << (OP_CREATE_SESSION - 32) |
+                     1 << (OP_DESTROY_SESSION - 32) |
+                     1 << (OP_DESTROY_CLIENTID - 32)
+       };
+       unsigned int i;
+
+       if (sp->how == SP4_MACH_CRED) {
+               /* Print state protect result */
+               dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
+               for (i = 0; i <= LAST_NFS4_OP; i++) {
+                       if (test_bit(i, sp->enforce.u.longs))
+                               dfprintk(MOUNT, "  enforce op %d\n", i);
+                       if (test_bit(i, sp->allow.u.longs))
+                               dfprintk(MOUNT, "  allow op %d\n", i);
+               }
+
+               /* make sure nothing is on enforce list that isn't supported */
+               for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
+                       if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
+                               dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
+                               return -EINVAL;
+                       }
+               }
+
+               /*
+                * Minimal mode - state operations are allowed to use machine
+                * credential.  Note this already happens by default, so the
+                * client doesn't have to do anything more than the negotiation.
+                *
+                * NOTE: we don't care if EXCHANGE_ID is in the list -
+                *       we're already using the machine cred for exchange_id
+                *       and will never use a different cred.
+                */
+               if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
+                   test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
+                       dfprintk(MOUNT, "sp4_mach_cred:\n");
+                       dfprintk(MOUNT, "  minimal mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_MINIMAL, &clp->cl_sp4_flags);
+               } else {
+                       dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
+                       return -EINVAL;
+               }
+
+               if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
+                   test_bit(OP_LOCKU, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  cleanup mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_CLEANUP, &clp->cl_sp4_flags);
+               }
+
+               if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
+                   test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  secinfo mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_SECINFO, &clp->cl_sp4_flags);
+               }
+
+               if (test_bit(OP_TEST_STATEID, sp->allow.u.longs) &&
+                   test_bit(OP_FREE_STATEID, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  stateid mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_STATEID, &clp->cl_sp4_flags);
+               }
+
+               if (test_bit(OP_WRITE, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  write mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_WRITE, &clp->cl_sp4_flags);
+               }
+
+               if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
+                       dfprintk(MOUNT, "  commit mode enabled\n");
+                       set_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags);
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * _nfs4_proc_exchange_id()
  *
- * Since the clientid has expired, all compounds using sessions
- * associated with the stale clientid will be returning
- * NFS4ERR_BADSESSION in the sequence operation, and will therefore
- * be in some phase of session reset.
+ * Wrapper for EXCHANGE_ID operation.
  */
-int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
+       u32 sp4_how)
 {
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
@@ -5965,10 +6305,30 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
                goto out_server_scope;
        }
 
+       switch (sp4_how) {
+       case SP4_NONE:
+               args.state_protect.how = SP4_NONE;
+               break;
+
+       case SP4_MACH_CRED:
+               args.state_protect = nfs4_sp4_mach_cred_request;
+               break;
+
+       default:
+               /* unsupported! */
+               WARN_ON_ONCE(1);
+               status = -EINVAL;
+               goto out_server_scope;
+       }
+
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_exchange_id(clp, status);
        if (status == 0)
                status = nfs4_check_cl_exchange_flags(res.flags);
 
+       if (status == 0)
+               status = nfs4_sp4_select_mode(clp, &res.state_protect);
+
        if (status == 0) {
                clp->cl_clientid = res.clientid;
                clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
@@ -6015,6 +6375,35 @@ out:
        return status;
 }
 
+/*
+ * nfs4_proc_exchange_id()
+ *
+ * Returns zero, a negative errno, or a negative NFS4ERR status code.
+ *
+ * Since the clientid has expired, all compounds using sessions
+ * associated with the stale clientid will be returning
+ * NFS4ERR_BADSESSION in the sequence operation, and will therefore
+ * be in some phase of session reset.
+ *
+ * Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used.
+ */
+int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+{
+       rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor;
+       int status;
+
+       /* try SP4_MACH_CRED if krb5i/p */
+       if (authflavor == RPC_AUTH_GSS_KRB5I ||
+           authflavor == RPC_AUTH_GSS_KRB5P) {
+               status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
+               if (!status)
+                       return 0;
+       }
+
+       /* try SP4_NONE */
+       return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
+}
+
 static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
                struct rpc_cred *cred)
 {
@@ -6026,6 +6415,7 @@ static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
        int status;
 
        status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_destroy_clientid(clp, status);
        if (status)
                dprintk("NFS: Got error %d from the server %s on "
                        "DESTROY_CLIENTID.", status, clp->cl_hostname);
@@ -6063,7 +6453,7 @@ int nfs4_destroy_clientid(struct nfs_client *clp)
                goto out;
        if (clp->cl_preserve_clid)
                goto out;
-       cred = nfs4_get_exchange_id_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        ret = nfs4_proc_destroy_clientid(clp, cred);
        if (cred)
                put_rpccred(cred);
@@ -6155,7 +6545,7 @@ int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
        };
        int status;
 
-       nfs41_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
+       nfs4_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
        nfs4_set_sequence_privileged(&args.la_seq_args);
        dprintk("--> %s\n", __func__);
        task = rpc_run_task(&task_setup);
@@ -6289,6 +6679,7 @@ static int _nfs4_proc_create_session(struct nfs_client *clp,
        args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_create_session(clp, status);
 
        if (!status) {
                /* Verify the session's negotiated channel_attrs values */
@@ -6352,6 +6743,7 @@ int nfs4_proc_destroy_session(struct nfs4_session *session,
                return status;
 
        status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
+       trace_nfs4_destroy_session(session->clp, status);
 
        if (status)
                dprintk("NFS: Got error %d from the server on DESTROY_SESSION. "
@@ -6401,6 +6793,7 @@ static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
        if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
                return;
 
+       trace_nfs4_sequence(clp, task->tk_status);
        if (task->tk_status < 0) {
                dprintk("%s ERROR %d\n", __func__, task->tk_status);
                if (atomic_read(&clp->cl_count) == 1)
@@ -6458,7 +6851,7 @@ static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
                nfs_put_client(clp);
                return ERR_PTR(-ENOMEM);
        }
-       nfs41_init_sequence(&calldata->args, &calldata->res, 0);
+       nfs4_init_sequence(&calldata->args, &calldata->res, 0);
        if (is_privileged)
                nfs4_set_sequence_privileged(&calldata->args);
        msg.rpc_argp = &calldata->args;
@@ -6553,6 +6946,7 @@ static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
        if (!nfs41_sequence_done(task, res))
                return;
 
+       trace_nfs4_reclaim_complete(clp, task->tk_status);
        if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
                rpc_restart_call_prepare(task);
                return;
@@ -6600,7 +6994,7 @@ static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
        calldata->clp = clp;
        calldata->arg.one_fs = 0;
 
-       nfs41_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
+       nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
        nfs4_set_sequence_privileged(&calldata->arg.seq_args);
        msg.rpc_argp = &calldata->arg;
        msg.rpc_resp = &calldata->res;
@@ -6791,7 +7185,7 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
 
        lgp->res.layoutp = &lgp->args.layout;
        lgp->res.seq_res.sr_slot = NULL;
-       nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
+       nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
 
        /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
        pnfs_get_layout_hdr(NFS_I(inode)->layout);
@@ -6802,6 +7196,10 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
        status = nfs4_wait_for_completion_rpc_task(task);
        if (status == 0)
                status = task->tk_status;
+       trace_nfs4_layoutget(lgp->args.ctx,
+                       &lgp->args.range,
+                       &lgp->res.range,
+                       status);
        /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
        if (status == 0 && lgp->res.layoutp->len)
                lseg = pnfs_layout_process(lgp);
@@ -6874,7 +7272,7 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
                .rpc_cred = lrp->cred,
        };
        struct rpc_task_setup task_setup_data = {
-               .rpc_client = lrp->clp->cl_rpcclient,
+               .rpc_client = NFS_SERVER(lrp->args.inode)->client,
                .rpc_message = &msg,
                .callback_ops = &nfs4_layoutreturn_call_ops,
                .callback_data = lrp,
@@ -6882,11 +7280,12 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
        int status;
 
        dprintk("--> %s\n", __func__);
-       nfs41_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
+       nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
        status = task->tk_status;
+       trace_nfs4_layoutreturn(lrp->args.inode, status);
        dprintk("<-- %s status=%d\n", __func__, status);
        rpc_put_task(task);
        return status;
@@ -7063,7 +7462,7 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
                data->args.lastbytewritten,
                data->args.inode->i_ino);
 
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -7073,15 +7472,21 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
        if (status != 0)
                goto out;
        status = task->tk_status;
+       trace_nfs4_layoutcommit(data->args.inode, status);
 out:
        dprintk("%s: status %d\n", __func__, status);
        rpc_put_task(task);
        return status;
 }
 
+/**
+ * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
+ * possible) as per RFC3530bis and RFC5661 Security Considerations sections
+ */
 static int
 _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
-                   struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
+                   struct nfs_fsinfo *info,
+                   struct nfs4_secinfo_flavors *flavors, bool use_integrity)
 {
        struct nfs41_secinfo_no_name_args args = {
                .style = SECINFO_STYLE_CURRENT_FH,
@@ -7094,7 +7499,25 @@ _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .rpc_resp = &res,
        };
-       return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
+       struct rpc_clnt *clnt = server->client;
+       struct rpc_cred *cred = NULL;
+       int status;
+
+       if (use_integrity) {
+               clnt = server->nfs_client->cl_rpcclient;
+               cred = nfs4_get_clid_cred(server->nfs_client);
+               msg.rpc_cred = cred;
+       }
+
+       dprintk("--> %s\n", __func__);
+       status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
+                               &res.seq_res, 0);
+       dprintk("<-- %s status=%d\n", __func__, status);
+
+       if (cred)
+               put_rpccred(cred);
+
+       return status;
 }
 
 static int
@@ -7104,7 +7527,24 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
        struct nfs4_exception exception = { };
        int err;
        do {
-               err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
+               /* first try using integrity protection */
+               err = -NFS4ERR_WRONGSEC;
+
+               /* try to use integrity protection with machine cred */
+               if (_nfs4_is_integrity_protected(server->nfs_client))
+                       err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+                                                         flavors, true);
+
+               /*
+                * if unable to use integrity protection, or SECINFO with
+                * integrity protection returns NFS4ERR_WRONGSEC (which is
+                * disallowed by spec, but exists in deployed servers) use
+                * the current filesystem's rpc_client and the user cred.
+                */
+               if (err == -NFS4ERR_WRONGSEC)
+                       err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
+                                                         flavors, false);
+
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
@@ -7174,11 +7614,15 @@ static int _nfs41_test_stateid(struct nfs_server *server,
                .rpc_resp = &res,
                .rpc_cred = cred,
        };
+       struct rpc_clnt *rpc_client = server->client;
+
+       nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+               &rpc_client, &msg);
 
        dprintk("NFS call  test_stateid %p\n", stateid);
-       nfs41_init_sequence(&args.seq_args, &res.seq_res, 0);
+       nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
        nfs4_set_sequence_privileged(&args.seq_args);
-       status = nfs4_call_sync_sequence(server->client, server, &msg,
+       status = nfs4_call_sync_sequence(rpc_client, server, &msg,
                        &args.seq_args, &res.seq_res);
        if (status != NFS_OK) {
                dprintk("NFS reply test_stateid: failed, %d\n", status);
@@ -7247,7 +7691,7 @@ static void nfs41_free_stateid_release(void *calldata)
        kfree(calldata);
 }
 
-const struct rpc_call_ops nfs41_free_stateid_ops = {
+static const struct rpc_call_ops nfs41_free_stateid_ops = {
        .rpc_call_prepare = nfs41_free_stateid_prepare,
        .rpc_call_done = nfs41_free_stateid_done,
        .rpc_release = nfs41_free_stateid_release,
@@ -7270,6 +7714,9 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
        };
        struct nfs_free_stateid_data *data;
 
+       nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
+               &task_setup.rpc_client, &msg);
+
        dprintk("NFS call  free_stateid %p\n", stateid);
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
@@ -7281,7 +7728,7 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
 
        msg.rpc_argp = &data->args;
        msg.rpc_resp = &data->res;
-       nfs41_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
+       nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
        if (privileged)
                nfs4_set_sequence_privileged(&data->args.seq_args);
 
@@ -7357,7 +7804,6 @@ static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs4_init_clientid,
-       .get_clid_cred  = nfs4_get_setclientid_cred,
        .detect_trunking = nfs40_discover_server_trunking,
 };
 
@@ -7368,7 +7814,6 @@ static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
        .establish_clid = nfs41_init_clientid,
-       .get_clid_cred  = nfs4_get_exchange_id_cred,
        .reclaim_complete = nfs41_proc_reclaim_complete,
        .detect_trunking = nfs41_discover_server_trunking,
 };
@@ -7380,7 +7825,6 @@ static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
        .establish_clid = nfs4_init_clientid,
-       .get_clid_cred  = nfs4_get_setclientid_cred,
 };
 
 #if defined(CONFIG_NFS_V4_1)
@@ -7390,7 +7834,6 @@ static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .recover_open   = nfs41_open_expired,
        .recover_lock   = nfs41_lock_expired,
        .establish_clid = nfs41_init_clientid,
-       .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
 #endif /* CONFIG_NFS_V4_1 */
 
@@ -7414,10 +7857,12 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
                | NFS_CAP_ATOMIC_OPEN
                | NFS_CAP_CHANGE_ATTR
                | NFS_CAP_POSIX_LOCK,
-       .call_sync = _nfs4_call_sync,
+       .init_client = nfs40_init_client,
+       .shutdown_client = nfs40_shutdown_client,
        .match_stateid = nfs4_match_stateid,
        .find_root_sec = nfs4_find_root_sec,
        .free_lock_state = nfs4_release_lockowner,
+       .call_sync_ops = &nfs40_call_sync_ops,
        .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
        .state_renewal_ops = &nfs40_state_renewal_ops,
@@ -7432,10 +7877,12 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
-       .call_sync = nfs4_call_sync_sequence,
+       .init_client = nfs41_init_client,
+       .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
@@ -7451,10 +7898,12 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
                | NFS_CAP_POSIX_LOCK
                | NFS_CAP_STATEID_NFSV41
                | NFS_CAP_ATOMIC_OPEN_V1,
-       .call_sync = nfs4_call_sync_sequence,
+       .init_client = nfs41_init_client,
+       .shutdown_client = nfs41_shutdown_client,
        .match_stateid = nfs41_match_stateid,
        .find_root_sec = nfs41_find_root_sec,
        .free_lock_state = nfs41_free_lock_state,
+       .call_sync_ops = &nfs41_call_sync_ops,
        .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
        .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
        .state_renewal_ops = &nfs41_state_renewal_ops,
@@ -7471,7 +7920,7 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
 #endif
 };
 
-const struct inode_operations nfs4_dir_inode_operations = {
+static const struct inode_operations nfs4_dir_inode_operations = {
        .create         = nfs_create,
        .lookup         = nfs_lookup,
        .atomic_open    = nfs_atomic_open,
index 36e21cb29d65971dff3f1b104d5685a8cae27d83..cf883c7ae053322626b8aa3c5b18861cd81f0085 100644 (file)
 
 #define NFSDBG_FACILITY                NFSDBG_STATE
 
+static void nfs4_init_slot_table(struct nfs4_slot_table *tbl, const char *queue)
+{
+       tbl->highest_used_slotid = NFS4_NO_SLOT;
+       spin_lock_init(&tbl->slot_tbl_lock);
+       rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, queue);
+       init_completion(&tbl->complete);
+}
+
 /*
  * nfs4_shrink_slot_table - free retired slots from the slot table
  */
@@ -44,6 +52,17 @@ static void nfs4_shrink_slot_table(struct nfs4_slot_table  *tbl, u32 newsize)
        }
 }
 
+/**
+ * nfs4_slot_tbl_drain_complete - wake waiters when drain is complete
+ * @tbl - controlling slot table
+ *
+ */
+void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl)
+{
+       if (nfs4_slot_tbl_draining(tbl))
+               complete(&tbl->complete);
+}
+
 /*
  * nfs4_free_slot - free a slot and efficiently update slot table.
  *
@@ -76,7 +95,7 @@ void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot)
                        nfs4_slot_tbl_drain_complete(tbl);
                }
        }
-       dprintk("%s: slotid %u highest_used_slotid %d\n", __func__,
+       dprintk("%s: slotid %u highest_used_slotid %u\n", __func__,
                slotid, tbl->highest_used_slotid);
 }
 
@@ -146,9 +165,9 @@ struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl)
        ret->generation = tbl->generation;
 
 out:
-       dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d \n",
+       dprintk("<-- %s used_slots=%04lx highest_used=%u slotid=%u\n",
                __func__, tbl->used_slots[0], tbl->highest_used_slotid,
-               !IS_ERR(ret) ? ret->slot_nr : -1);
+               !IS_ERR(ret) ? ret->slot_nr : NFS4_NO_SLOT);
        return ret;
 }
 
@@ -191,7 +210,7 @@ static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl,
 {
        int ret;
 
-       dprintk("--> %s: max_reqs=%u, tbl->max_slots %d\n", __func__,
+       dprintk("--> %s: max_reqs=%u, tbl->max_slots %u\n", __func__,
                max_reqs, tbl->max_slots);
 
        if (max_reqs > NFS4_MAX_SLOT_TABLE)
@@ -205,18 +224,36 @@ static int nfs4_realloc_slot_table(struct nfs4_slot_table *tbl,
        nfs4_reset_slot_table(tbl, max_reqs - 1, ivalue);
        spin_unlock(&tbl->slot_tbl_lock);
 
-       dprintk("%s: tbl=%p slots=%p max_slots=%d\n", __func__,
+       dprintk("%s: tbl=%p slots=%p max_slots=%u\n", __func__,
                tbl, tbl->slots, tbl->max_slots);
 out:
        dprintk("<-- %s: return %d\n", __func__, ret);
        return ret;
 }
 
-/* Destroy the slot table */
-static void nfs4_destroy_slot_tables(struct nfs4_session *session)
+/**
+ * nfs4_release_slot_table - release resources attached to a slot table
+ * @tbl: slot table to shut down
+ *
+ */
+void nfs4_release_slot_table(struct nfs4_slot_table *tbl)
+{
+       nfs4_shrink_slot_table(tbl, 0);
+}
+
+/**
+ * nfs4_setup_slot_table - prepare a stand-alone slot table for use
+ * @tbl: slot table to set up
+ * @max_reqs: maximum number of requests allowed
+ * @queue: name to give RPC wait queue
+ *
+ * Returns zero on success, or a negative errno.
+ */
+int nfs4_setup_slot_table(struct nfs4_slot_table *tbl, unsigned int max_reqs,
+               const char *queue)
 {
-       nfs4_shrink_slot_table(&session->fc_slot_table, 0);
-       nfs4_shrink_slot_table(&session->bc_slot_table, 0);
+       nfs4_init_slot_table(tbl, queue);
+       return nfs4_realloc_slot_table(tbl, max_reqs, 0);
 }
 
 static bool nfs41_assign_slot(struct rpc_task *task, void *pslot)
@@ -273,6 +310,8 @@ void nfs41_wake_slot_table(struct nfs4_slot_table *tbl)
        }
 }
 
+#if defined(CONFIG_NFS_V4_1)
+
 static void nfs41_set_max_slotid_locked(struct nfs4_slot_table *tbl,
                u32 target_highest_slotid)
 {
@@ -383,6 +422,12 @@ void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
        spin_unlock(&tbl->slot_tbl_lock);
 }
 
+static void nfs4_destroy_session_slot_tables(struct nfs4_session *session)
+{
+       nfs4_release_slot_table(&session->fc_slot_table);
+       nfs4_release_slot_table(&session->bc_slot_table);
+}
+
 /*
  * Initialize or reset the forechannel and backchannel tables
  */
@@ -405,31 +450,20 @@ int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
        if (status && tbl->slots == NULL)
                /* Fore and back channel share a connection so get
                 * both slot tables or neither */
-               nfs4_destroy_slot_tables(ses);
+               nfs4_destroy_session_slot_tables(ses);
        return status;
 }
 
 struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
 {
        struct nfs4_session *session;
-       struct nfs4_slot_table *tbl;
 
        session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
        if (!session)
                return NULL;
 
-       tbl = &session->fc_slot_table;
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
-       init_completion(&tbl->complete);
-
-       tbl = &session->bc_slot_table;
-       tbl->highest_used_slotid = NFS4_NO_SLOT;
-       spin_lock_init(&tbl->slot_tbl_lock);
-       rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
-       init_completion(&tbl->complete);
-
+       nfs4_init_slot_table(&session->fc_slot_table, "ForeChannel Slot table");
+       nfs4_init_slot_table(&session->bc_slot_table, "BackChannel Slot table");
        session->session_state = 1<<NFS4_SESSION_INITING;
 
        session->clp = clp;
@@ -441,7 +475,7 @@ void nfs4_destroy_session(struct nfs4_session *session)
        struct rpc_xprt *xprt;
        struct rpc_cred *cred;
 
-       cred = nfs4_get_exchange_id_cred(session->clp);
+       cred = nfs4_get_clid_cred(session->clp);
        nfs4_proc_destroy_session(session, cred);
        if (cred)
                put_rpccred(cred);
@@ -452,7 +486,7 @@ void nfs4_destroy_session(struct nfs4_session *session)
        dprintk("%s Destroy backchannel for xprt %p\n",
                __func__, xprt);
        xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
-       nfs4_destroy_slot_tables(session);
+       nfs4_destroy_session_slot_tables(session);
        kfree(session);
 }
 
@@ -513,4 +547,4 @@ int nfs4_init_ds_session(struct nfs_client *clp, unsigned long lease_time)
 }
 EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
 
-
+#endif /* defined(CONFIG_NFS_V4_1) */
index 3a153d82b90c638215b5d01c68b68116a454d515..2323061006512c37b2189a79ddf41441d0aafff9 100644 (file)
@@ -8,7 +8,7 @@
 #define __LINUX_FS_NFS_NFS4SESSION_H
 
 /* maximum number of slots to use */
-#define NFS4_DEF_SLOT_TABLE_SIZE (16U)
+#define NFS4_DEF_SLOT_TABLE_SIZE (64U)
 #define NFS4_MAX_SLOT_TABLE (1024U)
 #define NFS4_NO_SLOT ((u32)-1)
 
@@ -72,10 +72,22 @@ enum nfs4_session_state {
        NFS4_SESSION_INITING,
 };
 
-#if defined(CONFIG_NFS_V4_1)
+extern int nfs4_setup_slot_table(struct nfs4_slot_table *tbl,
+               unsigned int max_reqs, const char *queue);
+extern void nfs4_release_slot_table(struct nfs4_slot_table *tbl);
 extern struct nfs4_slot *nfs4_alloc_slot(struct nfs4_slot_table *tbl);
 extern void nfs4_free_slot(struct nfs4_slot_table *tbl, struct nfs4_slot *slot);
+extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl);
+bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
+               struct nfs4_slot *slot);
+void nfs41_wake_slot_table(struct nfs4_slot_table *tbl);
+
+static inline bool nfs4_slot_tbl_draining(struct nfs4_slot_table *tbl)
+{
+       return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state);
+}
 
+#if defined(CONFIG_NFS_V4_1)
 extern void nfs41_set_target_slotid(struct nfs4_slot_table *tbl,
                u32 target_highest_slotid);
 extern void nfs41_update_target_slotid(struct nfs4_slot_table *tbl,
@@ -89,17 +101,6 @@ extern void nfs4_destroy_session(struct nfs4_session *session);
 extern int nfs4_init_session(struct nfs_client *clp);
 extern int nfs4_init_ds_session(struct nfs_client *, unsigned long);
 
-extern void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl);
-
-static inline bool nfs4_slot_tbl_draining(struct nfs4_slot_table *tbl)
-{
-       return !!test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state);
-}
-
-bool nfs41_wake_and_assign_slot(struct nfs4_slot_table *tbl,
-               struct nfs4_slot *slot);
-void nfs41_wake_slot_table(struct nfs4_slot_table *tbl);
-
 /*
  * Determine if sessions are in use.
  */
@@ -117,6 +118,16 @@ static inline int nfs4_has_persistent_session(const struct nfs_client *clp)
        return 0;
 }
 
+#ifdef CONFIG_CRC32
+/*
+ * nfs_session_id_hash - calculate the crc32 hash for the session id
+ * @session - pointer to session
+ */
+#define nfs_session_id_hash(sess_id) \
+       (~crc32_le(0xFFFFFFFF, &(sess_id)->data[0], sizeof((sess_id)->data)))
+#else
+#define nfs_session_id_hash(session) (0)
+#endif
 #else /* defined(CONFIG_NFS_V4_1) */
 
 static inline int nfs4_init_session(struct nfs_client *clp)
index e22862f13564486ab535a437f4d46e6709a30ed9..cc14cbb78b7322637ae74f6ad013c9183e7a996a 100644 (file)
@@ -154,6 +154,19 @@ struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
        return cred;
 }
 
+static void nfs4_root_machine_cred(struct nfs_client *clp)
+{
+       struct rpc_cred *cred, *new;
+
+       new = rpc_lookup_machine_cred(NULL);
+       spin_lock(&clp->cl_lock);
+       cred = clp->cl_machine_cred;
+       clp->cl_machine_cred = new;
+       spin_unlock(&clp->cl_lock);
+       if (cred != NULL)
+               put_rpccred(cred);
+}
+
 static struct rpc_cred *
 nfs4_get_renew_cred_server_locked(struct nfs_server *server)
 {
@@ -202,32 +215,6 @@ out:
        return cred;
 }
 
-#if defined(CONFIG_NFS_V4_1)
-
-static int nfs41_setup_state_renewal(struct nfs_client *clp)
-{
-       int status;
-       struct nfs_fsinfo fsinfo;
-
-       if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
-               nfs4_schedule_state_renewal(clp);
-               return 0;
-       }
-
-       status = nfs4_proc_get_lease_time(clp, &fsinfo);
-       if (status == 0) {
-               /* Update lease time and schedule renewal */
-               spin_lock(&clp->cl_lock);
-               clp->cl_lease_time = fsinfo.lease_time * HZ;
-               clp->cl_last_renewal = jiffies;
-               spin_unlock(&clp->cl_lock);
-
-               nfs4_schedule_state_renewal(clp);
-       }
-
-       return status;
-}
-
 static void nfs4_end_drain_slot_table(struct nfs4_slot_table *tbl)
 {
        if (test_and_clear_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state)) {
@@ -241,20 +228,18 @@ static void nfs4_end_drain_session(struct nfs_client *clp)
 {
        struct nfs4_session *ses = clp->cl_session;
 
+       if (clp->cl_slot_tbl) {
+               nfs4_end_drain_slot_table(clp->cl_slot_tbl);
+               return;
+       }
+
        if (ses != NULL) {
                nfs4_end_drain_slot_table(&ses->bc_slot_table);
                nfs4_end_drain_slot_table(&ses->fc_slot_table);
        }
 }
 
-/*
- * Signal state manager thread if session fore channel is drained
- */
-void nfs4_slot_tbl_drain_complete(struct nfs4_slot_table *tbl)
-{
-       if (nfs4_slot_tbl_draining(tbl))
-               complete(&tbl->complete);
-}
+#if defined(CONFIG_NFS_V4_1)
 
 static int nfs4_drain_slot_tbl(struct nfs4_slot_table *tbl)
 {
@@ -274,6 +259,9 @@ static int nfs4_begin_drain_session(struct nfs_client *clp)
        struct nfs4_session *ses = clp->cl_session;
        int ret = 0;
 
+       if (clp->cl_slot_tbl)
+               return nfs4_drain_slot_tbl(clp->cl_slot_tbl);
+
        /* back channel */
        ret = nfs4_drain_slot_tbl(&ses->bc_slot_table);
        if (ret)
@@ -282,6 +270,30 @@ static int nfs4_begin_drain_session(struct nfs_client *clp)
        return nfs4_drain_slot_tbl(&ses->fc_slot_table);
 }
 
+static int nfs41_setup_state_renewal(struct nfs_client *clp)
+{
+       int status;
+       struct nfs_fsinfo fsinfo;
+
+       if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
+               nfs4_schedule_state_renewal(clp);
+               return 0;
+       }
+
+       status = nfs4_proc_get_lease_time(clp, &fsinfo);
+       if (status == 0) {
+               /* Update lease time and schedule renewal */
+               spin_lock(&clp->cl_lock);
+               clp->cl_lease_time = fsinfo.lease_time * HZ;
+               clp->cl_last_renewal = jiffies;
+               spin_unlock(&clp->cl_lock);
+
+               nfs4_schedule_state_renewal(clp);
+       }
+
+       return status;
+}
+
 static void nfs41_finish_session_reset(struct nfs_client *clp)
 {
        clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
@@ -339,62 +351,21 @@ int nfs41_discover_server_trunking(struct nfs_client *clp,
        return nfs41_walk_client_list(clp, result, cred);
 }
 
-struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
-{
-       struct rpc_cred *cred;
-
-       spin_lock(&clp->cl_lock);
-       cred = nfs4_get_machine_cred_locked(clp);
-       spin_unlock(&clp->cl_lock);
-       return cred;
-}
-
 #endif /* CONFIG_NFS_V4_1 */
 
-static struct rpc_cred *
-nfs4_get_setclientid_cred_server(struct nfs_server *server)
-{
-       struct nfs_client *clp = server->nfs_client;
-       struct rpc_cred *cred = NULL;
-       struct nfs4_state_owner *sp;
-       struct rb_node *pos;
-
-       spin_lock(&clp->cl_lock);
-       pos = rb_first(&server->state_owners);
-       if (pos != NULL) {
-               sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
-               cred = get_rpccred(sp->so_cred);
-       }
-       spin_unlock(&clp->cl_lock);
-       return cred;
-}
-
 /**
- * nfs4_get_setclientid_cred - Acquire credential for a setclientid operation
+ * nfs4_get_clid_cred - Acquire credential for a setclientid operation
  * @clp: client state handle
  *
  * Returns an rpc_cred with reference count bumped, or NULL.
  */
-struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
+struct rpc_cred *nfs4_get_clid_cred(struct nfs_client *clp)
 {
-       struct nfs_server *server;
        struct rpc_cred *cred;
 
        spin_lock(&clp->cl_lock);
        cred = nfs4_get_machine_cred_locked(clp);
        spin_unlock(&clp->cl_lock);
-       if (cred != NULL)
-               goto out;
-
-       rcu_read_lock();
-       list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
-               cred = nfs4_get_setclientid_cred_server(server);
-               if (cred != NULL)
-                       break;
-       }
-       rcu_read_unlock();
-
-out:
        return cred;
 }
 
@@ -998,7 +969,9 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
        fl_pid = lockowner->l_pid;
        spin_lock(&state->state_lock);
        lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
-       if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
+       if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
+               ret = -EIO;
+       else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
                nfs4_stateid_copy(dst, &lsp->ls_stateid);
                ret = 0;
                smp_rmb();
@@ -1038,11 +1011,17 @@ static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
 int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
                fmode_t fmode, const struct nfs_lockowner *lockowner)
 {
-       int ret = 0;
+       int ret = nfs4_copy_lock_stateid(dst, state, lockowner);
+       if (ret == -EIO)
+               /* A lost lock - don't even consider delegations */
+               goto out;
        if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
                goto out;
-       ret = nfs4_copy_lock_stateid(dst, state, lockowner);
        if (ret != -ENOENT)
+               /* nfs4_copy_delegation_stateid() didn't over-write
+                * dst, so it still has the lock stateid which we now
+                * choose to use.
+                */
                goto out;
        ret = nfs4_copy_open_stateid(dst, state);
 out:
@@ -1443,14 +1422,16 @@ restart:
                if (status >= 0) {
                        status = nfs4_reclaim_locks(state, ops);
                        if (status >= 0) {
-                               spin_lock(&state->state_lock);
-                               list_for_each_entry(lock, &state->lock_states, ls_locks) {
-                                       if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
-                                               pr_warn_ratelimited("NFS: "
-                                                       "%s: Lock reclaim "
-                                                       "failed!\n", __func__);
+                               if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0) {
+                                       spin_lock(&state->state_lock);
+                                       list_for_each_entry(lock, &state->lock_states, ls_locks) {
+                                               if (!test_bit(NFS_LOCK_INITIALIZED, &lock->ls_flags))
+                                                       pr_warn_ratelimited("NFS: "
+                                                                           "%s: Lock reclaim "
+                                                                           "failed!\n", __func__);
+                                       }
+                                       spin_unlock(&state->state_lock);
                                }
-                               spin_unlock(&state->state_lock);
                                nfs4_put_open_state(state);
                                spin_lock(&sp->so_lock);
                                goto restart;
@@ -1618,7 +1599,7 @@ static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
        if (!nfs4_state_clear_reclaim_reboot(clp))
                return;
        ops = clp->cl_mvops->reboot_recovery_ops;
-       cred = ops->get_clid_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        nfs4_reclaim_complete(clp, ops, cred);
        put_rpccred(cred);
 }
@@ -1732,7 +1713,7 @@ static int nfs4_check_lease(struct nfs_client *clp)
        cred = ops->get_state_renewal_cred_locked(clp);
        spin_unlock(&clp->cl_lock);
        if (cred == NULL) {
-               cred = nfs4_get_setclientid_cred(clp);
+               cred = nfs4_get_clid_cred(clp);
                status = -ENOKEY;
                if (cred == NULL)
                        goto out;
@@ -1804,7 +1785,7 @@ static int nfs4_establish_lease(struct nfs_client *clp)
                clp->cl_mvops->reboot_recovery_ops;
        int status;
 
-       cred = ops->get_clid_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        if (cred == NULL)
                return -ENOENT;
        status = ops->establish_clid(clp, cred);
@@ -1878,7 +1859,7 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
        mutex_lock(&nfs_clid_init_mutex);
 again:
        status  = -ENOENT;
-       cred = ops->get_clid_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        if (cred == NULL)
                goto out_unlock;
 
@@ -1896,7 +1877,11 @@ again:
                        __func__, status);
                goto again;
        case -EACCES:
-               if (i++)
+               if (i++ == 0) {
+                       nfs4_root_machine_cred(clp);
+                       goto again;
+               }
+               if (i > 2)
                        break;
        case -NFS4ERR_CLID_INUSE:
        case -NFS4ERR_WRONGSEC:
@@ -2052,7 +2037,7 @@ static int nfs4_reset_session(struct nfs_client *clp)
        if (!nfs4_has_session(clp))
                return 0;
        nfs4_begin_drain_session(clp);
-       cred = nfs4_get_exchange_id_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        status = nfs4_proc_destroy_session(clp->cl_session, cred);
        switch (status) {
        case 0:
@@ -2095,7 +2080,7 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
        if (!nfs4_has_session(clp))
                return 0;
        nfs4_begin_drain_session(clp);
-       cred = nfs4_get_exchange_id_cred(clp);
+       cred = nfs4_get_clid_cred(clp);
        ret = nfs4_proc_bind_conn_to_session(clp, cred);
        if (cred)
                put_rpccred(cred);
@@ -2116,7 +2101,6 @@ static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 }
 #else /* CONFIG_NFS_V4_1 */
 static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
-static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
 
 static int nfs4_bind_conn_to_session(struct nfs_client *clp)
 {
index 5dbe2d269210f000132547d3c21daa33e7e1b224..e26acdd1a6456c2e4dc62410f191a720f18babd7 100644 (file)
@@ -253,8 +253,6 @@ struct dentry *nfs4_try_mount(int flags, const char *dev_name,
 
        dfprintk(MOUNT, "--> nfs4_try_mount()\n");
 
-       if (data->auth_flavors[0] == RPC_AUTH_MAXFLAVOR)
-               data->auth_flavors[0] = RPC_AUTH_UNIX;
        export_path = data->nfs_server.export_path;
        data->nfs_server.export_path = "/";
        root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info,
diff --git a/fs/nfs/nfs4trace.c b/fs/nfs/nfs4trace.c
new file mode 100644 (file)
index 0000000..d774335
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2013 Trond Myklebust <Trond.Myklebust@netapp.com>
+ */
+#include <linux/nfs_fs.h>
+#include "nfs4_fs.h"
+#include "internal.h"
+#include "nfs4session.h"
+#include "callback.h"
+
+#define CREATE_TRACE_POINTS
+#include "nfs4trace.h"
+
+#ifdef CONFIG_NFS_V4_1
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs4_pnfs_read);
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs4_pnfs_write);
+EXPORT_TRACEPOINT_SYMBOL_GPL(nfs4_pnfs_commit_ds);
+#endif
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h
new file mode 100644 (file)
index 0000000..849cf14
--- /dev/null
@@ -0,0 +1,1148 @@
+/*
+ * Copyright (c) 2013 Trond Myklebust <Trond.Myklebust@netapp.com>
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM nfs4
+
+#if !defined(_TRACE_NFS4_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NFS4_H
+
+#include <linux/tracepoint.h>
+
+#define show_nfsv4_errors(error) \
+       __print_symbolic(error, \
+               { NFS4_OK, "OK" }, \
+               /* Mapped by nfs4_stat_to_errno() */ \
+               { -EPERM, "EPERM" }, \
+               { -ENOENT, "ENOENT" }, \
+               { -EIO, "EIO" }, \
+               { -ENXIO, "ENXIO" }, \
+               { -EACCES, "EACCES" }, \
+               { -EEXIST, "EEXIST" }, \
+               { -EXDEV, "EXDEV" }, \
+               { -ENOTDIR, "ENOTDIR" }, \
+               { -EISDIR, "EISDIR" }, \
+               { -EFBIG, "EFBIG" }, \
+               { -ENOSPC, "ENOSPC" }, \
+               { -EROFS, "EROFS" }, \
+               { -EMLINK, "EMLINK" }, \
+               { -ENAMETOOLONG, "ENAMETOOLONG" }, \
+               { -ENOTEMPTY, "ENOTEMPTY" }, \
+               { -EDQUOT, "EDQUOT" }, \
+               { -ESTALE, "ESTALE" }, \
+               { -EBADHANDLE, "EBADHANDLE" }, \
+               { -EBADCOOKIE, "EBADCOOKIE" }, \
+               { -ENOTSUPP, "ENOTSUPP" }, \
+               { -ETOOSMALL, "ETOOSMALL" }, \
+               { -EREMOTEIO, "EREMOTEIO" }, \
+               { -EBADTYPE, "EBADTYPE" }, \
+               { -EAGAIN, "EAGAIN" }, \
+               { -ELOOP, "ELOOP" }, \
+               { -EOPNOTSUPP, "EOPNOTSUPP" }, \
+               { -EDEADLK, "EDEADLK" }, \
+               /* RPC errors */ \
+               { -ENOMEM, "ENOMEM" }, \
+               { -EKEYEXPIRED, "EKEYEXPIRED" }, \
+               { -ETIMEDOUT, "ETIMEDOUT" }, \
+               { -ERESTARTSYS, "ERESTARTSYS" }, \
+               { -ECONNREFUSED, "ECONNREFUSED" }, \
+               { -ECONNRESET, "ECONNRESET" }, \
+               { -ENETUNREACH, "ENETUNREACH" }, \
+               { -EHOSTUNREACH, "EHOSTUNREACH" }, \
+               { -EHOSTDOWN, "EHOSTDOWN" }, \
+               { -EPIPE, "EPIPE" }, \
+               { -EPFNOSUPPORT, "EPFNOSUPPORT" }, \
+               { -EPROTONOSUPPORT, "EPROTONOSUPPORT" }, \
+               /* NFSv4 native errors */ \
+               { -NFS4ERR_ACCESS, "ACCESS" }, \
+               { -NFS4ERR_ATTRNOTSUPP, "ATTRNOTSUPP" }, \
+               { -NFS4ERR_ADMIN_REVOKED, "ADMIN_REVOKED" }, \
+               { -NFS4ERR_BACK_CHAN_BUSY, "BACK_CHAN_BUSY" }, \
+               { -NFS4ERR_BADCHAR, "BADCHAR" }, \
+               { -NFS4ERR_BADHANDLE, "BADHANDLE" }, \
+               { -NFS4ERR_BADIOMODE, "BADIOMODE" }, \
+               { -NFS4ERR_BADLAYOUT, "BADLAYOUT" }, \
+               { -NFS4ERR_BADLABEL, "BADLABEL" }, \
+               { -NFS4ERR_BADNAME, "BADNAME" }, \
+               { -NFS4ERR_BADOWNER, "BADOWNER" }, \
+               { -NFS4ERR_BADSESSION, "BADSESSION" }, \
+               { -NFS4ERR_BADSLOT, "BADSLOT" }, \
+               { -NFS4ERR_BADTYPE, "BADTYPE" }, \
+               { -NFS4ERR_BADXDR, "BADXDR" }, \
+               { -NFS4ERR_BAD_COOKIE, "BAD_COOKIE" }, \
+               { -NFS4ERR_BAD_HIGH_SLOT, "BAD_HIGH_SLOT" }, \
+               { -NFS4ERR_BAD_RANGE, "BAD_RANGE" }, \
+               { -NFS4ERR_BAD_SEQID, "BAD_SEQID" }, \
+               { -NFS4ERR_BAD_SESSION_DIGEST, "BAD_SESSION_DIGEST" }, \
+               { -NFS4ERR_BAD_STATEID, "BAD_STATEID" }, \
+               { -NFS4ERR_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
+               { -NFS4ERR_CLID_INUSE, "CLID_INUSE" }, \
+               { -NFS4ERR_CLIENTID_BUSY, "CLIENTID_BUSY" }, \
+               { -NFS4ERR_COMPLETE_ALREADY, "COMPLETE_ALREADY" }, \
+               { -NFS4ERR_CONN_NOT_BOUND_TO_SESSION, \
+                       "CONN_NOT_BOUND_TO_SESSION" }, \
+               { -NFS4ERR_DEADLOCK, "DEADLOCK" }, \
+               { -NFS4ERR_DEADSESSION, "DEAD_SESSION" }, \
+               { -NFS4ERR_DELAY, "DELAY" }, \
+               { -NFS4ERR_DELEG_ALREADY_WANTED, \
+                       "DELEG_ALREADY_WANTED" }, \
+               { -NFS4ERR_DELEG_REVOKED, "DELEG_REVOKED" }, \
+               { -NFS4ERR_DENIED, "DENIED" }, \
+               { -NFS4ERR_DIRDELEG_UNAVAIL, "DIRDELEG_UNAVAIL" }, \
+               { -NFS4ERR_DQUOT, "DQUOT" }, \
+               { -NFS4ERR_ENCR_ALG_UNSUPP, "ENCR_ALG_UNSUPP" }, \
+               { -NFS4ERR_EXIST, "EXIST" }, \
+               { -NFS4ERR_EXPIRED, "EXPIRED" }, \
+               { -NFS4ERR_FBIG, "FBIG" }, \
+               { -NFS4ERR_FHEXPIRED, "FHEXPIRED" }, \
+               { -NFS4ERR_FILE_OPEN, "FILE_OPEN" }, \
+               { -NFS4ERR_GRACE, "GRACE" }, \
+               { -NFS4ERR_HASH_ALG_UNSUPP, "HASH_ALG_UNSUPP" }, \
+               { -NFS4ERR_INVAL, "INVAL" }, \
+               { -NFS4ERR_IO, "IO" }, \
+               { -NFS4ERR_ISDIR, "ISDIR" }, \
+               { -NFS4ERR_LAYOUTTRYLATER, "LAYOUTTRYLATER" }, \
+               { -NFS4ERR_LAYOUTUNAVAILABLE, "LAYOUTUNAVAILABLE" }, \
+               { -NFS4ERR_LEASE_MOVED, "LEASE_MOVED" }, \
+               { -NFS4ERR_LOCKED, "LOCKED" }, \
+               { -NFS4ERR_LOCKS_HELD, "LOCKS_HELD" }, \
+               { -NFS4ERR_LOCK_RANGE, "LOCK_RANGE" }, \
+               { -NFS4ERR_MINOR_VERS_MISMATCH, "MINOR_VERS_MISMATCH" }, \
+               { -NFS4ERR_MLINK, "MLINK" }, \
+               { -NFS4ERR_MOVED, "MOVED" }, \
+               { -NFS4ERR_NAMETOOLONG, "NAMETOOLONG" }, \
+               { -NFS4ERR_NOENT, "NOENT" }, \
+               { -NFS4ERR_NOFILEHANDLE, "NOFILEHANDLE" }, \
+               { -NFS4ERR_NOMATCHING_LAYOUT, "NOMATCHING_LAYOUT" }, \
+               { -NFS4ERR_NOSPC, "NOSPC" }, \
+               { -NFS4ERR_NOTDIR, "NOTDIR" }, \
+               { -NFS4ERR_NOTEMPTY, "NOTEMPTY" }, \
+               { -NFS4ERR_NOTSUPP, "NOTSUPP" }, \
+               { -NFS4ERR_NOT_ONLY_OP, "NOT_ONLY_OP" }, \
+               { -NFS4ERR_NOT_SAME, "NOT_SAME" }, \
+               { -NFS4ERR_NO_GRACE, "NO_GRACE" }, \
+               { -NFS4ERR_NXIO, "NXIO" }, \
+               { -NFS4ERR_OLD_STATEID, "OLD_STATEID" }, \
+               { -NFS4ERR_OPENMODE, "OPENMODE" }, \
+               { -NFS4ERR_OP_ILLEGAL, "OP_ILLEGAL" }, \
+               { -NFS4ERR_OP_NOT_IN_SESSION, "OP_NOT_IN_SESSION" }, \
+               { -NFS4ERR_PERM, "PERM" }, \
+               { -NFS4ERR_PNFS_IO_HOLE, "PNFS_IO_HOLE" }, \
+               { -NFS4ERR_PNFS_NO_LAYOUT, "PNFS_NO_LAYOUT" }, \
+               { -NFS4ERR_RECALLCONFLICT, "RECALLCONFLICT" }, \
+               { -NFS4ERR_RECLAIM_BAD, "RECLAIM_BAD" }, \
+               { -NFS4ERR_RECLAIM_CONFLICT, "RECLAIM_CONFLICT" }, \
+               { -NFS4ERR_REJECT_DELEG, "REJECT_DELEG" }, \
+               { -NFS4ERR_REP_TOO_BIG, "REP_TOO_BIG" }, \
+               { -NFS4ERR_REP_TOO_BIG_TO_CACHE, \
+                       "REP_TOO_BIG_TO_CACHE" }, \
+               { -NFS4ERR_REQ_TOO_BIG, "REQ_TOO_BIG" }, \
+               { -NFS4ERR_RESOURCE, "RESOURCE" }, \
+               { -NFS4ERR_RESTOREFH, "RESTOREFH" }, \
+               { -NFS4ERR_RETRY_UNCACHED_REP, "RETRY_UNCACHED_REP" }, \
+               { -NFS4ERR_RETURNCONFLICT, "RETURNCONFLICT" }, \
+               { -NFS4ERR_ROFS, "ROFS" }, \
+               { -NFS4ERR_SAME, "SAME" }, \
+               { -NFS4ERR_SHARE_DENIED, "SHARE_DENIED" }, \
+               { -NFS4ERR_SEQUENCE_POS, "SEQUENCE_POS" }, \
+               { -NFS4ERR_SEQ_FALSE_RETRY, "SEQ_FALSE_RETRY" }, \
+               { -NFS4ERR_SEQ_MISORDERED, "SEQ_MISORDERED" }, \
+               { -NFS4ERR_SERVERFAULT, "SERVERFAULT" }, \
+               { -NFS4ERR_STALE, "STALE" }, \
+               { -NFS4ERR_STALE_CLIENTID, "STALE_CLIENTID" }, \
+               { -NFS4ERR_STALE_STATEID, "STALE_STATEID" }, \
+               { -NFS4ERR_SYMLINK, "SYMLINK" }, \
+               { -NFS4ERR_TOOSMALL, "TOOSMALL" }, \
+               { -NFS4ERR_TOO_MANY_OPS, "TOO_MANY_OPS" }, \
+               { -NFS4ERR_UNKNOWN_LAYOUTTYPE, "UNKNOWN_LAYOUTTYPE" }, \
+               { -NFS4ERR_UNSAFE_COMPOUND, "UNSAFE_COMPOUND" }, \
+               { -NFS4ERR_WRONGSEC, "WRONGSEC" }, \
+               { -NFS4ERR_WRONG_CRED, "WRONG_CRED" }, \
+               { -NFS4ERR_WRONG_TYPE, "WRONG_TYPE" }, \
+               { -NFS4ERR_XDEV, "XDEV" })
+
+#define show_open_flags(flags) \
+       __print_flags(flags, "|", \
+               { O_CREAT, "O_CREAT" }, \
+               { O_EXCL, "O_EXCL" }, \
+               { O_TRUNC, "O_TRUNC" }, \
+               { O_DIRECT, "O_DIRECT" })
+
+#define show_fmode_flags(mode) \
+       __print_flags(mode, "|", \
+               { ((__force unsigned long)FMODE_READ), "READ" }, \
+               { ((__force unsigned long)FMODE_WRITE), "WRITE" }, \
+               { ((__force unsigned long)FMODE_EXEC), "EXEC" })
+
+#define show_nfs_fattr_flags(valid) \
+       __print_flags((unsigned long)valid, "|", \
+               { NFS_ATTR_FATTR_TYPE, "TYPE" }, \
+               { NFS_ATTR_FATTR_MODE, "MODE" }, \
+               { NFS_ATTR_FATTR_NLINK, "NLINK" }, \
+               { NFS_ATTR_FATTR_OWNER, "OWNER" }, \
+               { NFS_ATTR_FATTR_GROUP, "GROUP" }, \
+               { NFS_ATTR_FATTR_RDEV, "RDEV" }, \
+               { NFS_ATTR_FATTR_SIZE, "SIZE" }, \
+               { NFS_ATTR_FATTR_FSID, "FSID" }, \
+               { NFS_ATTR_FATTR_FILEID, "FILEID" }, \
+               { NFS_ATTR_FATTR_ATIME, "ATIME" }, \
+               { NFS_ATTR_FATTR_MTIME, "MTIME" }, \
+               { NFS_ATTR_FATTR_CTIME, "CTIME" }, \
+               { NFS_ATTR_FATTR_CHANGE, "CHANGE" }, \
+               { NFS_ATTR_FATTR_OWNER_NAME, "OWNER_NAME" }, \
+               { NFS_ATTR_FATTR_GROUP_NAME, "GROUP_NAME" })
+
+DECLARE_EVENT_CLASS(nfs4_clientid_event,
+               TP_PROTO(
+                       const struct nfs_client *clp,
+                       int error
+               ),
+
+               TP_ARGS(clp, error),
+
+               TP_STRUCT__entry(
+                       __string(dstaddr,
+                               rpc_peeraddr2str(clp->cl_rpcclient,
+                                       RPC_DISPLAY_ADDR))
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->error = error;
+                       __assign_str(dstaddr,
+                               rpc_peeraddr2str(clp->cl_rpcclient,
+                                               RPC_DISPLAY_ADDR));
+               ),
+
+               TP_printk(
+                       "error=%d (%s) dstaddr=%s",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       __get_str(dstaddr)
+               )
+);
+#define DEFINE_NFS4_CLIENTID_EVENT(name) \
+       DEFINE_EVENT(nfs4_clientid_event, name,  \
+                       TP_PROTO( \
+                               const struct nfs_client *clp, \
+                               int error \
+                       ), \
+                       TP_ARGS(clp, error))
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_setclientid);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_setclientid_confirm);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_renew);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_renew_async);
+#ifdef CONFIG_NFS_V4_1
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_exchange_id);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_create_session);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_destroy_session);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_destroy_clientid);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_bind_conn_to_session);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_sequence);
+DEFINE_NFS4_CLIENTID_EVENT(nfs4_reclaim_complete);
+
+TRACE_EVENT(nfs4_setup_sequence,
+               TP_PROTO(
+                       const struct nfs4_session *session,
+                       const struct nfs4_sequence_args *args
+               ),
+               TP_ARGS(session, args),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, session)
+                       __field(unsigned int, slot_nr)
+                       __field(unsigned int, seq_nr)
+                       __field(unsigned int, highest_used_slotid)
+               ),
+
+               TP_fast_assign(
+                       const struct nfs4_slot *sa_slot = args->sa_slot;
+                       __entry->session = nfs_session_id_hash(&session->sess_id);
+                       __entry->slot_nr = sa_slot->slot_nr;
+                       __entry->seq_nr = sa_slot->seq_nr;
+                       __entry->highest_used_slotid =
+                                       sa_slot->table->highest_used_slotid;
+               ),
+               TP_printk(
+                       "session=0x%08x slot_nr=%u seq_nr=%u "
+                       "highest_used_slotid=%u",
+                       __entry->session,
+                       __entry->slot_nr,
+                       __entry->seq_nr,
+                       __entry->highest_used_slotid
+               )
+);
+
+#define show_nfs4_sequence_status_flags(status) \
+       __print_flags((unsigned long)status, "|", \
+               { SEQ4_STATUS_CB_PATH_DOWN, "CB_PATH_DOWN" }, \
+               { SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING, \
+                       "CB_GSS_CONTEXTS_EXPIRING" }, \
+               { SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED, \
+                       "CB_GSS_CONTEXTS_EXPIRED" }, \
+               { SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED, \
+                       "EXPIRED_ALL_STATE_REVOKED" }, \
+               { SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED, \
+                       "EXPIRED_SOME_STATE_REVOKED" }, \
+               { SEQ4_STATUS_ADMIN_STATE_REVOKED, \
+                       "ADMIN_STATE_REVOKED" }, \
+               { SEQ4_STATUS_RECALLABLE_STATE_REVOKED,  \
+                       "RECALLABLE_STATE_REVOKED" }, \
+               { SEQ4_STATUS_LEASE_MOVED, "LEASE_MOVED" }, \
+               { SEQ4_STATUS_RESTART_RECLAIM_NEEDED, \
+                       "RESTART_RECLAIM_NEEDED" }, \
+               { SEQ4_STATUS_CB_PATH_DOWN_SESSION, \
+                       "CB_PATH_DOWN_SESSION" }, \
+               { SEQ4_STATUS_BACKCHANNEL_FAULT, \
+                       "BACKCHANNEL_FAULT" })
+
+TRACE_EVENT(nfs4_sequence_done,
+               TP_PROTO(
+                       const struct nfs4_session *session,
+                       const struct nfs4_sequence_res *res
+               ),
+               TP_ARGS(session, res),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, session)
+                       __field(unsigned int, slot_nr)
+                       __field(unsigned int, seq_nr)
+                       __field(unsigned int, highest_slotid)
+                       __field(unsigned int, target_highest_slotid)
+                       __field(unsigned int, status_flags)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       const struct nfs4_slot *sr_slot = res->sr_slot;
+                       __entry->session = nfs_session_id_hash(&session->sess_id);
+                       __entry->slot_nr = sr_slot->slot_nr;
+                       __entry->seq_nr = sr_slot->seq_nr;
+                       __entry->highest_slotid = res->sr_highest_slotid;
+                       __entry->target_highest_slotid =
+                                       res->sr_target_highest_slotid;
+                       __entry->error = res->sr_status;
+               ),
+               TP_printk(
+                       "error=%d (%s) session=0x%08x slot_nr=%u seq_nr=%u "
+                       "highest_slotid=%u target_highest_slotid=%u "
+                       "status_flags=%u (%s)",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       __entry->session,
+                       __entry->slot_nr,
+                       __entry->seq_nr,
+                       __entry->highest_slotid,
+                       __entry->target_highest_slotid,
+                       __entry->status_flags,
+                       show_nfs4_sequence_status_flags(__entry->status_flags)
+               )
+);
+
+struct cb_sequenceargs;
+struct cb_sequenceres;
+
+TRACE_EVENT(nfs4_cb_sequence,
+               TP_PROTO(
+                       const struct cb_sequenceargs *args,
+                       const struct cb_sequenceres *res,
+                       __be32 status
+               ),
+               TP_ARGS(args, res, status),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, session)
+                       __field(unsigned int, slot_nr)
+                       __field(unsigned int, seq_nr)
+                       __field(unsigned int, highest_slotid)
+                       __field(unsigned int, cachethis)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->session = nfs_session_id_hash(&args->csa_sessionid);
+                       __entry->slot_nr = args->csa_slotid;
+                       __entry->seq_nr = args->csa_sequenceid;
+                       __entry->highest_slotid = args->csa_highestslotid;
+                       __entry->cachethis = args->csa_cachethis;
+                       __entry->error = -be32_to_cpu(status);
+               ),
+
+               TP_printk(
+                       "error=%d (%s) session=0x%08x slot_nr=%u seq_nr=%u "
+                       "highest_slotid=%u",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       __entry->session,
+                       __entry->slot_nr,
+                       __entry->seq_nr,
+                       __entry->highest_slotid
+               )
+);
+#endif /* CONFIG_NFS_V4_1 */
+
+DECLARE_EVENT_CLASS(nfs4_open_event,
+               TP_PROTO(
+                       const struct nfs_open_context *ctx,
+                       int flags,
+                       int error
+               ),
+
+               TP_ARGS(ctx, flags, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(unsigned int, flags)
+                       __field(unsigned int, fmode)
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(u64, dir)
+                       __string(name, ctx->dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       const struct nfs4_state *state = ctx->state;
+                       const struct inode *inode = NULL;
+
+                       __entry->error = error;
+                       __entry->flags = flags;
+                       __entry->fmode = (__force unsigned int)ctx->mode;
+                       __entry->dev = ctx->dentry->d_sb->s_dev;
+                       if (!IS_ERR(state))
+                               inode = state->inode;
+                       if (inode != NULL) {
+                               __entry->fileid = NFS_FILEID(inode);
+                               __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       } else {
+                               __entry->fileid = 0;
+                               __entry->fhandle = 0;
+                       }
+                       __entry->dir = NFS_FILEID(ctx->dentry->d_parent->d_inode);
+                       __assign_str(name, ctx->dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d (%s) flags=%d (%s) fmode=%s "
+                       "fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "name=%02x:%02x:%llu/%s",
+                        __entry->error,
+                        show_nfsv4_errors(__entry->error),
+                        __entry->flags,
+                        show_open_flags(__entry->flags),
+                        show_fmode_flags(__entry->fmode),
+                        MAJOR(__entry->dev), MINOR(__entry->dev),
+                        (unsigned long long)__entry->fileid,
+                        __entry->fhandle,
+                        MAJOR(__entry->dev), MINOR(__entry->dev),
+                        (unsigned long long)__entry->dir,
+                        __get_str(name)
+               )
+);
+
+#define DEFINE_NFS4_OPEN_EVENT(name) \
+       DEFINE_EVENT(nfs4_open_event, name, \
+                       TP_PROTO( \
+                               const struct nfs_open_context *ctx, \
+                               int flags, \
+                               int error \
+                       ), \
+                       TP_ARGS(ctx, flags, error))
+DEFINE_NFS4_OPEN_EVENT(nfs4_open_reclaim);
+DEFINE_NFS4_OPEN_EVENT(nfs4_open_expired);
+DEFINE_NFS4_OPEN_EVENT(nfs4_open_file);
+
+TRACE_EVENT(nfs4_close,
+               TP_PROTO(
+                       const struct nfs4_state *state,
+                       const struct nfs_closeargs *args,
+                       const struct nfs_closeres *res,
+                       int error
+               ),
+
+               TP_ARGS(state, args, res, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(unsigned int, fmode)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = state->inode;
+
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->fmode = (__force unsigned int)state->state;
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fmode=%s fileid=%02x:%02x:%llu "
+                       "fhandle=0x%08x",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       __entry->fmode ?  show_fmode_flags(__entry->fmode) :
+                                         "closed",
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle
+               )
+);
+
+#define show_lock_cmd(type) \
+       __print_symbolic((int)type, \
+               { F_GETLK, "GETLK" }, \
+               { F_SETLK, "SETLK" }, \
+               { F_SETLKW, "SETLKW" })
+#define show_lock_type(type) \
+       __print_symbolic((int)type, \
+               { F_RDLCK, "RDLCK" }, \
+               { F_WRLCK, "WRLCK" }, \
+               { F_UNLCK, "UNLCK" })
+
+DECLARE_EVENT_CLASS(nfs4_lock_event,
+               TP_PROTO(
+                       const struct file_lock *request,
+                       const struct nfs4_state *state,
+                       int cmd,
+                       int error
+               ),
+
+               TP_ARGS(request, state, cmd, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(int, cmd)
+                       __field(char, type)
+                       __field(loff_t, start)
+                       __field(loff_t, end)
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = state->inode;
+
+                       __entry->error = error;
+                       __entry->cmd = cmd;
+                       __entry->type = request->fl_type;
+                       __entry->start = request->fl_start;
+                       __entry->end = request->fl_end;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+               ),
+
+               TP_printk(
+                       "error=%d (%s) cmd=%s:%s range=%lld:%lld "
+                       "fileid=%02x:%02x:%llu fhandle=0x%08x",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       show_lock_cmd(__entry->cmd),
+                       show_lock_type(__entry->type),
+                       (long long)__entry->start,
+                       (long long)__entry->end,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle
+               )
+);
+
+#define DEFINE_NFS4_LOCK_EVENT(name) \
+       DEFINE_EVENT(nfs4_lock_event, name, \
+                       TP_PROTO( \
+                               const struct file_lock *request, \
+                               const struct nfs4_state *state, \
+                               int cmd, \
+                               int error \
+                       ), \
+                       TP_ARGS(request, state, cmd, error))
+DEFINE_NFS4_LOCK_EVENT(nfs4_get_lock);
+DEFINE_NFS4_LOCK_EVENT(nfs4_set_lock);
+DEFINE_NFS4_LOCK_EVENT(nfs4_lock_reclaim);
+DEFINE_NFS4_LOCK_EVENT(nfs4_lock_expired);
+DEFINE_NFS4_LOCK_EVENT(nfs4_unlock);
+
+DECLARE_EVENT_CLASS(nfs4_set_delegation_event,
+               TP_PROTO(
+                       const struct inode *inode,
+                       fmode_t fmode
+               ),
+
+               TP_ARGS(inode, fmode),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(unsigned int, fmode)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->fmode = (__force unsigned int)fmode;
+               ),
+
+               TP_printk(
+                       "fmode=%s fileid=%02x:%02x:%llu fhandle=0x%08x",
+                       show_fmode_flags(__entry->fmode),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle
+               )
+);
+#define DEFINE_NFS4_SET_DELEGATION_EVENT(name) \
+       DEFINE_EVENT(nfs4_set_delegation_event, name, \
+                       TP_PROTO( \
+                               const struct inode *inode, \
+                               fmode_t fmode \
+                       ), \
+                       TP_ARGS(inode, fmode))
+DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_set_delegation);
+DEFINE_NFS4_SET_DELEGATION_EVENT(nfs4_reclaim_delegation);
+
+TRACE_EVENT(nfs4_delegreturn_exit,
+               TP_PROTO(
+                       const struct nfs4_delegreturnargs *args,
+                       const struct nfs4_delegreturnres *res,
+                       int error
+               ),
+
+               TP_ARGS(args, res, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = res->server->s_dev;
+                       __entry->fhandle = nfs_fhandle_hash(args->fhandle);
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) dev=%02x:%02x fhandle=0x%08x",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       __entry->fhandle
+               )
+);
+
+#ifdef CONFIG_NFS_V4_1
+DECLARE_EVENT_CLASS(nfs4_test_stateid_event,
+               TP_PROTO(
+                       const struct nfs4_state *state,
+                       const struct nfs4_lock_state *lsp,
+                       int error
+               ),
+
+               TP_ARGS(state, lsp, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = state->inode;
+
+                       __entry->error = error;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle
+               )
+);
+
+#define DEFINE_NFS4_TEST_STATEID_EVENT(name) \
+       DEFINE_EVENT(nfs4_test_stateid_event, name, \
+                       TP_PROTO( \
+                               const struct nfs4_state *state, \
+                               const struct nfs4_lock_state *lsp, \
+                               int error \
+                       ), \
+                       TP_ARGS(state, lsp, error))
+DEFINE_NFS4_TEST_STATEID_EVENT(nfs4_test_delegation_stateid);
+DEFINE_NFS4_TEST_STATEID_EVENT(nfs4_test_open_stateid);
+DEFINE_NFS4_TEST_STATEID_EVENT(nfs4_test_lock_stateid);
+#endif /* CONFIG_NFS_V4_1 */
+
+DECLARE_EVENT_CLASS(nfs4_lookup_event,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct qstr *name,
+                       int error
+               ),
+
+               TP_ARGS(dir, name, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(int, error)
+                       __field(u64, dir)
+                       __string(name, name->name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->error = error;
+                       __assign_str(name, name->name);
+               ),
+
+               TP_printk(
+                       "error=%d (%s) name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+#define DEFINE_NFS4_LOOKUP_EVENT(name) \
+       DEFINE_EVENT(nfs4_lookup_event, name, \
+                       TP_PROTO( \
+                               const struct inode *dir, \
+                               const struct qstr *name, \
+                               int error \
+                       ), \
+                       TP_ARGS(dir, name, error))
+
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_lookup);
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_symlink);
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_mkdir);
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_mknod);
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_remove);
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_get_fs_locations);
+DEFINE_NFS4_LOOKUP_EVENT(nfs4_secinfo);
+
+TRACE_EVENT(nfs4_rename,
+               TP_PROTO(
+                       const struct inode *olddir,
+                       const struct qstr *oldname,
+                       const struct inode *newdir,
+                       const struct qstr *newname,
+                       int error
+               ),
+
+               TP_ARGS(olddir, oldname, newdir, newname, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(int, error)
+                       __field(u64, olddir)
+                       __string(oldname, oldname->name)
+                       __field(u64, newdir)
+                       __string(newname, newname->name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = olddir->i_sb->s_dev;
+                       __entry->olddir = NFS_FILEID(olddir);
+                       __entry->newdir = NFS_FILEID(newdir);
+                       __entry->error = error;
+                       __assign_str(oldname, oldname->name);
+                       __assign_str(newname, newname->name);
+               ),
+
+               TP_printk(
+                       "error=%d (%s) oldname=%02x:%02x:%llu/%s "
+                       "newname=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->olddir,
+                       __get_str(oldname),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->newdir,
+                       __get_str(newname)
+               )
+);
+
+DECLARE_EVENT_CLASS(nfs4_inode_event,
+               TP_PROTO(
+                       const struct inode *inode,
+                       int error
+               ),
+
+               TP_ARGS(inode, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle
+               )
+);
+
+#define DEFINE_NFS4_INODE_EVENT(name) \
+       DEFINE_EVENT(nfs4_inode_event, name, \
+                       TP_PROTO( \
+                               const struct inode *inode, \
+                               int error \
+                       ), \
+                       TP_ARGS(inode, error))
+
+DEFINE_NFS4_INODE_EVENT(nfs4_setattr);
+DEFINE_NFS4_INODE_EVENT(nfs4_access);
+DEFINE_NFS4_INODE_EVENT(nfs4_readlink);
+DEFINE_NFS4_INODE_EVENT(nfs4_readdir);
+DEFINE_NFS4_INODE_EVENT(nfs4_get_acl);
+DEFINE_NFS4_INODE_EVENT(nfs4_set_acl);
+#ifdef CONFIG_NFS_V4_SECURITY_LABEL
+DEFINE_NFS4_INODE_EVENT(nfs4_get_security_label);
+DEFINE_NFS4_INODE_EVENT(nfs4_set_security_label);
+#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
+DEFINE_NFS4_INODE_EVENT(nfs4_recall_delegation);
+DEFINE_NFS4_INODE_EVENT(nfs4_delegreturn);
+
+DECLARE_EVENT_CLASS(nfs4_getattr_event,
+               TP_PROTO(
+                       const struct nfs_server *server,
+                       const struct nfs_fh *fhandle,
+                       const struct nfs_fattr *fattr,
+                       int error
+               ),
+
+               TP_ARGS(server, fhandle, fattr, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(unsigned int, valid)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = server->s_dev;
+                       __entry->valid = fattr->valid;
+                       __entry->fhandle = nfs_fhandle_hash(fhandle);
+                       __entry->fileid = (fattr->valid & NFS_ATTR_FATTR_FILEID) ? fattr->fileid : 0;
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "valid=%s",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       show_nfs_fattr_flags(__entry->valid)
+               )
+);
+
+#define DEFINE_NFS4_GETATTR_EVENT(name) \
+       DEFINE_EVENT(nfs4_getattr_event, name, \
+                       TP_PROTO( \
+                               const struct nfs_server *server, \
+                               const struct nfs_fh *fhandle, \
+                               const struct nfs_fattr *fattr, \
+                               int error \
+                       ), \
+                       TP_ARGS(server, fhandle, fattr, error))
+DEFINE_NFS4_GETATTR_EVENT(nfs4_getattr);
+DEFINE_NFS4_GETATTR_EVENT(nfs4_lookup_root);
+DEFINE_NFS4_GETATTR_EVENT(nfs4_fsinfo);
+
+DECLARE_EVENT_CLASS(nfs4_idmap_event,
+               TP_PROTO(
+                       const char *name,
+                       int len,
+                       u32 id,
+                       int error
+               ),
+
+               TP_ARGS(name, len, id, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(u32, id)
+                       __dynamic_array(char, name, len > 0 ? len + 1 : 1)
+               ),
+
+               TP_fast_assign(
+                       if (len < 0)
+                               len = 0;
+                       __entry->error = error < 0 ? error : 0;
+                       __entry->id = id;
+                       memcpy(__get_dynamic_array(name), name, len);
+                       ((char *)__get_dynamic_array(name))[len] = 0;
+               ),
+
+               TP_printk(
+                       "error=%d id=%u name=%s",
+                       __entry->error,
+                       __entry->id,
+                       __get_str(name)
+               )
+);
+#define DEFINE_NFS4_IDMAP_EVENT(name) \
+       DEFINE_EVENT(nfs4_idmap_event, name, \
+                       TP_PROTO( \
+                               const char *name, \
+                               int len, \
+                               u32 id, \
+                               int error \
+                       ), \
+                       TP_ARGS(name, len, id, error))
+DEFINE_NFS4_IDMAP_EVENT(nfs4_map_name_to_uid);
+DEFINE_NFS4_IDMAP_EVENT(nfs4_map_group_to_gid);
+DEFINE_NFS4_IDMAP_EVENT(nfs4_map_uid_to_name);
+DEFINE_NFS4_IDMAP_EVENT(nfs4_map_gid_to_group);
+
+DECLARE_EVENT_CLASS(nfs4_read_event,
+               TP_PROTO(
+                       const struct nfs_read_data *data,
+                       int error
+               ),
+
+               TP_ARGS(data, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(loff_t, offset)
+                       __field(size_t, count)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = data->header->inode;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->offset = data->args.offset;
+                       __entry->count = data->args.count;
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "offset=%lld count=%zu",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       (long long)__entry->offset,
+                       __entry->count
+               )
+);
+#define DEFINE_NFS4_READ_EVENT(name) \
+       DEFINE_EVENT(nfs4_read_event, name, \
+                       TP_PROTO( \
+                               const struct nfs_read_data *data, \
+                               int error \
+                       ), \
+                       TP_ARGS(data, error))
+DEFINE_NFS4_READ_EVENT(nfs4_read);
+#ifdef CONFIG_NFS_V4_1
+DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read);
+#endif /* CONFIG_NFS_V4_1 */
+
+DECLARE_EVENT_CLASS(nfs4_write_event,
+               TP_PROTO(
+                       const struct nfs_write_data *data,
+                       int error
+               ),
+
+               TP_ARGS(data, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(loff_t, offset)
+                       __field(size_t, count)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = data->header->inode;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->offset = data->args.offset;
+                       __entry->count = data->args.count;
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "offset=%lld count=%zu",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       (long long)__entry->offset,
+                       __entry->count
+               )
+);
+
+#define DEFINE_NFS4_WRITE_EVENT(name) \
+       DEFINE_EVENT(nfs4_write_event, name, \
+                       TP_PROTO( \
+                               const struct nfs_write_data *data, \
+                               int error \
+                       ), \
+                       TP_ARGS(data, error))
+DEFINE_NFS4_WRITE_EVENT(nfs4_write);
+#ifdef CONFIG_NFS_V4_1
+DEFINE_NFS4_WRITE_EVENT(nfs4_pnfs_write);
+#endif /* CONFIG_NFS_V4_1 */
+
+DECLARE_EVENT_CLASS(nfs4_commit_event,
+               TP_PROTO(
+                       const struct nfs_commit_data *data,
+                       int error
+               ),
+
+               TP_ARGS(data, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(loff_t, offset)
+                       __field(size_t, count)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = data->inode;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->offset = data->args.offset;
+                       __entry->count = data->args.count;
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "offset=%lld count=%zu",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       (long long)__entry->offset,
+                       __entry->count
+               )
+);
+#define DEFINE_NFS4_COMMIT_EVENT(name) \
+       DEFINE_EVENT(nfs4_commit_event, name, \
+                       TP_PROTO( \
+                               const struct nfs_commit_data *data, \
+                               int error \
+                       ), \
+                       TP_ARGS(data, error))
+DEFINE_NFS4_COMMIT_EVENT(nfs4_commit);
+#ifdef CONFIG_NFS_V4_1
+DEFINE_NFS4_COMMIT_EVENT(nfs4_pnfs_commit_ds);
+
+#define show_pnfs_iomode(iomode) \
+       __print_symbolic(iomode, \
+               { IOMODE_READ, "READ" }, \
+               { IOMODE_RW, "RW" }, \
+               { IOMODE_ANY, "ANY" })
+
+TRACE_EVENT(nfs4_layoutget,
+               TP_PROTO(
+                       const struct nfs_open_context *ctx,
+                       const struct pnfs_layout_range *args,
+                       const struct pnfs_layout_range *res,
+                       int error
+               ),
+
+               TP_ARGS(ctx, args, res, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(u32, iomode)
+                       __field(u64, offset)
+                       __field(u64, count)
+                       __field(int, error)
+               ),
+
+               TP_fast_assign(
+                       const struct inode *inode = ctx->dentry->d_inode;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode));
+                       __entry->iomode = args->iomode;
+                       __entry->offset = args->offset;
+                       __entry->count = args->length;
+                       __entry->error = error;
+               ),
+
+               TP_printk(
+                       "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "iomode=%s offset=%llu count=%llu",
+                       __entry->error,
+                       show_nfsv4_errors(__entry->error),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       show_pnfs_iomode(__entry->iomode),
+                       (unsigned long long)__entry->offset,
+                       (unsigned long long)__entry->count
+               )
+);
+
+DEFINE_NFS4_INODE_EVENT(nfs4_layoutcommit);
+DEFINE_NFS4_INODE_EVENT(nfs4_layoutreturn);
+
+#endif /* CONFIG_NFS_V4_1 */
+
+#endif /* _TRACE_NFS4_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE nfs4trace
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 3850b018815f2d07e4740fdd3ff8200523b9fe92..79210d23f60770cfc3e7ede9d4156a299f45ee01 100644 (file)
@@ -294,7 +294,9 @@ static int nfs4_stat_to_errno(int);
                                XDR_QUADLEN(NFS4_EXCHANGE_ID_LEN) + \
                                1 /* flags */ + \
                                1 /* spa_how */ + \
-                               0 /* SP4_NONE (for now) */ + \
+                               /* max is SP4_MACH_CRED (for now) */ + \
+                               1 + NFS4_OP_MAP_NUM_WORDS + \
+                               1 + NFS4_OP_MAP_NUM_WORDS + \
                                1 /* implementation id array of size 1 */ + \
                                1 /* nii_domain */ + \
                                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + \
@@ -306,7 +308,9 @@ static int nfs4_stat_to_errno(int);
                                1 /* eir_sequenceid */ + \
                                1 /* eir_flags */ + \
                                1 /* spr_how */ + \
-                               0 /* SP4_NONE (for now) */ + \
+                                 /* max is SP4_MACH_CRED (for now) */ + \
+                               1 + NFS4_OP_MAP_NUM_WORDS + \
+                               1 + NFS4_OP_MAP_NUM_WORDS + \
                                2 /* eir_server_owner.so_minor_id */ + \
                                /* eir_server_owner.so_major_id<> */ \
                                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 + \
@@ -410,7 +414,7 @@ static int nfs4_stat_to_errno(int);
 #define decode_test_stateid_maxsz      (op_decode_hdr_maxsz + 2 + 1)
 #define encode_free_stateid_maxsz      (op_encode_hdr_maxsz + 1 + \
                                         XDR_QUADLEN(NFS4_STATEID_SIZE))
-#define decode_free_stateid_maxsz      (op_decode_hdr_maxsz + 1)
+#define decode_free_stateid_maxsz      (op_decode_hdr_maxsz)
 #else /* CONFIG_NFS_V4_1 */
 #define encode_sequence_maxsz  0
 #define decode_sequence_maxsz  0
@@ -997,12 +1001,10 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
        int owner_namelen = 0;
        int owner_grouplen = 0;
        __be32 *p;
-       __be32 *q;
-       int len;
-       uint32_t bmval_len = 2;
-       uint32_t bmval0 = 0;
-       uint32_t bmval1 = 0;
-       uint32_t bmval2 = 0;
+       unsigned i;
+       uint32_t len = 0;
+       uint32_t bmval_len;
+       uint32_t bmval[3] = { 0 };
 
        /*
         * We reserve enough space to write the entire attribute buffer at once.
@@ -1011,13 +1013,14 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
         * = 40 bytes, plus any contribution from variable-length fields
         *            such as owner/group.
         */
-       len = 8;
-
-       /* Sigh */
-       if (iap->ia_valid & ATTR_SIZE)
+       if (iap->ia_valid & ATTR_SIZE) {
+               bmval[0] |= FATTR4_WORD0_SIZE;
                len += 8;
-       if (iap->ia_valid & ATTR_MODE)
+       }
+       if (iap->ia_valid & ATTR_MODE) {
+               bmval[1] |= FATTR4_WORD1_MODE;
                len += 4;
+       }
        if (iap->ia_valid & ATTR_UID) {
                owner_namelen = nfs_map_uid_to_name(server, iap->ia_uid, owner_name, IDMAP_NAMESZ);
                if (owner_namelen < 0) {
@@ -1028,6 +1031,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                        owner_namelen = sizeof("nobody") - 1;
                        /* goto out; */
                }
+               bmval[1] |= FATTR4_WORD1_OWNER;
                len += 4 + (XDR_QUADLEN(owner_namelen) << 2);
        }
        if (iap->ia_valid & ATTR_GID) {
@@ -1039,92 +1043,73 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
                        owner_grouplen = sizeof("nobody") - 1;
                        /* goto out; */
                }
+               bmval[1] |= FATTR4_WORD1_OWNER_GROUP;
                len += 4 + (XDR_QUADLEN(owner_grouplen) << 2);
        }
-       if (iap->ia_valid & ATTR_ATIME_SET)
+       if (iap->ia_valid & ATTR_ATIME_SET) {
+               bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
                len += 16;
-       else if (iap->ia_valid & ATTR_ATIME)
+       } else if (iap->ia_valid & ATTR_ATIME) {
+               bmval[1] |= FATTR4_WORD1_TIME_ACCESS_SET;
                len += 4;
-       if (iap->ia_valid & ATTR_MTIME_SET)
+       }
+       if (iap->ia_valid & ATTR_MTIME_SET) {
+               bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
                len += 16;
-       else if (iap->ia_valid & ATTR_MTIME)
+       } else if (iap->ia_valid & ATTR_MTIME) {
+               bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET;
                len += 4;
+       }
        if (label) {
                len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
-               bmval_len = 3;
+               bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
        }
 
-       len += bmval_len << 2;
-       p = reserve_space(xdr, len);
+       if (bmval[2] != 0)
+               bmval_len = 3;
+       else if (bmval[1] != 0)
+               bmval_len = 2;
+       else
+               bmval_len = 1;
+
+       p = reserve_space(xdr, 4 + (bmval_len << 2) + 4 + len);
 
-       /*
-        * We write the bitmap length now, but leave the bitmap and the attribute
-        * buffer length to be backfilled at the end of this routine.
-        */
        *p++ = cpu_to_be32(bmval_len);
-       q = p;
-       /* Skip bitmap entries + attrlen */
-       p += bmval_len + 1;
+       for (i = 0; i < bmval_len; i++)
+               *p++ = cpu_to_be32(bmval[i]);
+       *p++ = cpu_to_be32(len);
 
-       if (iap->ia_valid & ATTR_SIZE) {
-               bmval0 |= FATTR4_WORD0_SIZE;
+       if (bmval[0] & FATTR4_WORD0_SIZE)
                p = xdr_encode_hyper(p, iap->ia_size);
-       }
-       if (iap->ia_valid & ATTR_MODE) {
-               bmval1 |= FATTR4_WORD1_MODE;
+       if (bmval[1] & FATTR4_WORD1_MODE)
                *p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
-       }
-       if (iap->ia_valid & ATTR_UID) {
-               bmval1 |= FATTR4_WORD1_OWNER;
+       if (bmval[1] & FATTR4_WORD1_OWNER)
                p = xdr_encode_opaque(p, owner_name, owner_namelen);
-       }
-       if (iap->ia_valid & ATTR_GID) {
-               bmval1 |= FATTR4_WORD1_OWNER_GROUP;
+       if (bmval[1] & FATTR4_WORD1_OWNER_GROUP)
                p = xdr_encode_opaque(p, owner_group, owner_grouplen);
+       if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) {
+               if (iap->ia_valid & ATTR_ATIME_SET) {
+                       *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
+                       p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
+                       *p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
+               } else
+                       *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
-       if (iap->ia_valid & ATTR_ATIME_SET) {
-               bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-               p = xdr_encode_hyper(p, (s64)iap->ia_atime.tv_sec);
-               *p++ = cpu_to_be32(iap->ia_atime.tv_nsec);
-       }
-       else if (iap->ia_valid & ATTR_ATIME) {
-               bmval1 |= FATTR4_WORD1_TIME_ACCESS_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
-       }
-       if (iap->ia_valid & ATTR_MTIME_SET) {
-               bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
-               p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
-               *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
-       }
-       else if (iap->ia_valid & ATTR_MTIME) {
-               bmval1 |= FATTR4_WORD1_TIME_MODIFY_SET;
-               *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
+       if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) {
+               if (iap->ia_valid & ATTR_MTIME_SET) {
+                       *p++ = cpu_to_be32(NFS4_SET_TO_CLIENT_TIME);
+                       p = xdr_encode_hyper(p, (s64)iap->ia_mtime.tv_sec);
+                       *p++ = cpu_to_be32(iap->ia_mtime.tv_nsec);
+               } else
+                       *p++ = cpu_to_be32(NFS4_SET_TO_SERVER_TIME);
        }
-       if (label) {
-               bmval2 |= FATTR4_WORD2_SECURITY_LABEL;
+       if (bmval[2] & FATTR4_WORD2_SECURITY_LABEL) {
                *p++ = cpu_to_be32(label->lfs);
                *p++ = cpu_to_be32(label->pi);
                *p++ = cpu_to_be32(label->len);
                p = xdr_encode_opaque_fixed(p, label->label, label->len);
        }
 
-       /*
-        * Now we backfill the bitmap and the attribute buffer length.
-        */
-       if (len != ((char *)p - (char *)q) + 4) {
-               printk(KERN_ERR "NFS: Attr length error, %u != %Zu\n",
-                               len, ((char *)p - (char *)q) + 4);
-               BUG();
-       }
-       *q++ = htonl(bmval0);
-       *q++ = htonl(bmval1);
-       if (bmval_len == 3)
-               *q++ = htonl(bmval2);
-       len = (char *)p - (char *)(q + 1);
-       *q = htonl(len);
-
 /* out: */
 }
 
@@ -1745,6 +1730,14 @@ static void encode_bind_conn_to_session(struct xdr_stream *xdr,
        *p = 0; /* use_conn_in_rdma_mode = False */
 }
 
+static void encode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
+{
+       unsigned int i;
+       encode_uint32(xdr, NFS4_OP_MAP_NUM_WORDS);
+       for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++)
+               encode_uint32(xdr, op_map->u.words[i]);
+}
+
 static void encode_exchange_id(struct xdr_stream *xdr,
                               struct nfs41_exchange_id_args *args,
                               struct compound_hdr *hdr)
@@ -1758,9 +1751,20 @@ static void encode_exchange_id(struct xdr_stream *xdr,
 
        encode_string(xdr, args->id_len, args->id);
 
-       p = reserve_space(xdr, 12);
-       *p++ = cpu_to_be32(args->flags);
-       *p++ = cpu_to_be32(0);  /* zero length state_protect4_a */
+       encode_uint32(xdr, args->flags);
+       encode_uint32(xdr, args->state_protect.how);
+
+       switch (args->state_protect.how) {
+       case SP4_NONE:
+               break;
+       case SP4_MACH_CRED:
+               encode_op_map(xdr, &args->state_protect.enforce);
+               encode_op_map(xdr, &args->state_protect.allow);
+               break;
+       default:
+               WARN_ON_ONCE(1);
+               break;
+       }
 
        if (send_implementation_id &&
            sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) > 1 &&
@@ -1771,7 +1775,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
                               utsname()->version, utsname()->machine);
 
        if (len > 0) {
-               *p = cpu_to_be32(1);    /* implementation id array length=1 */
+               encode_uint32(xdr, 1);  /* implementation id array length=1 */
 
                encode_string(xdr,
                        sizeof(CONFIG_NFS_V4_1_IMPLEMENTATION_ID_DOMAIN) - 1,
@@ -1782,7 +1786,7 @@ static void encode_exchange_id(struct xdr_stream *xdr,
                p = xdr_encode_hyper(p, 0);
                *p = cpu_to_be32(0);
        } else
-               *p = cpu_to_be32(0);    /* implementation id array length=0 */
+               encode_uint32(xdr, 0);  /* implementation id array length=0 */
 }
 
 static void encode_create_session(struct xdr_stream *xdr,
@@ -1835,7 +1839,7 @@ static void encode_create_session(struct xdr_stream *xdr,
        *p++ = cpu_to_be32(RPC_AUTH_UNIX);                      /* auth_sys */
 
        /* authsys_parms rfc1831 */
-       *p++ = (__be32)nn->boot_time.tv_nsec;           /* stamp */
+       *p++ = cpu_to_be32(nn->boot_time.tv_nsec);      /* stamp */
        p = xdr_encode_opaque(p, machine_name, len);
        *p++ = cpu_to_be32(0);                          /* UID */
        *p++ = cpu_to_be32(0);                          /* GID */
@@ -1877,11 +1881,10 @@ static void encode_sequence(struct xdr_stream *xdr,
        struct nfs4_slot *slot = args->sa_slot;
        __be32 *p;
 
-       if (slot == NULL)
-               return;
-
        tp = slot->table;
        session = tp->session;
+       if (!session)
+               return;
 
        encode_op_hdr(xdr, OP_SEQUENCE, decode_sequence_maxsz, hdr);
 
@@ -2062,9 +2065,9 @@ static void encode_free_stateid(struct xdr_stream *xdr,
 static u32 nfs4_xdr_minorversion(const struct nfs4_sequence_args *args)
 {
 #if defined(CONFIG_NFS_V4_1)
-
-       if (args->sa_slot)
-               return args->sa_slot->table->session->clp->cl_mvops->minor_version;
+       struct nfs4_session *session = args->sa_slot->table->session;
+       if (session)
+               return session->clp->cl_mvops->minor_version;
 #endif /* CONFIG_NFS_V4_1 */
        return 0;
 }
@@ -4649,7 +4652,7 @@ static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
 static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
                                         uint32_t *layouttype)
 {
-       uint32_t *p;
+       __be32 *p;
        int num;
 
        p = xdr_inline_decode(xdr, 4);
@@ -5394,6 +5397,23 @@ static int decode_secinfo_no_name(struct xdr_stream *xdr, struct nfs4_secinfo_re
        return decode_secinfo_common(xdr, res);
 }
 
+static int decode_op_map(struct xdr_stream *xdr, struct nfs4_op_map *op_map)
+{
+       __be32 *p;
+       uint32_t bitmap_words;
+       unsigned int i;
+
+       p = xdr_inline_decode(xdr, 4);
+       bitmap_words = be32_to_cpup(p++);
+       if (bitmap_words > NFS4_OP_MAP_NUM_WORDS)
+               return -EIO;
+       p = xdr_inline_decode(xdr, 4 * bitmap_words);
+       for (i = 0; i < bitmap_words; i++)
+               op_map->u.words[i] = be32_to_cpup(p++);
+
+       return 0;
+}
+
 static int decode_exchange_id(struct xdr_stream *xdr,
                              struct nfs41_exchange_id_res *res)
 {
@@ -5417,10 +5437,22 @@ static int decode_exchange_id(struct xdr_stream *xdr,
        res->seqid = be32_to_cpup(p++);
        res->flags = be32_to_cpup(p++);
 
-       /* We ask for SP4_NONE */
-       dummy = be32_to_cpup(p);
-       if (dummy != SP4_NONE)
+       res->state_protect.how = be32_to_cpup(p);
+       switch (res->state_protect.how) {
+       case SP4_NONE:
+               break;
+       case SP4_MACH_CRED:
+               status = decode_op_map(xdr, &res->state_protect.enforce);
+               if (status)
+                       return status;
+               status = decode_op_map(xdr, &res->state_protect.allow);
+               if (status)
+                       return status;
+               break;
+       default:
+               WARN_ON_ONCE(1);
                return -EIO;
+       }
 
        /* server_owner4.so_minor_id */
        p = xdr_inline_decode(xdr, 8);
@@ -5614,6 +5646,8 @@ static int decode_sequence(struct xdr_stream *xdr,
 
        if (res->sr_slot == NULL)
                return 0;
+       if (!res->sr_slot->table->session)
+               return 0;
 
        status = decode_op_hdr(xdr, OP_SEQUENCE);
        if (!status)
@@ -5932,21 +5966,8 @@ out:
 static int decode_free_stateid(struct xdr_stream *xdr,
                               struct nfs41_free_stateid_res *res)
 {
-       __be32 *p;
-       int status;
-
-       status = decode_op_hdr(xdr, OP_FREE_STATEID);
-       if (status)
-               return status;
-
-       p = xdr_inline_decode(xdr, 4);
-       if (unlikely(!p))
-               goto out_overflow;
-       res->status = be32_to_cpup(p++);
+       res->status = decode_op_hdr(xdr, OP_FREE_STATEID);
        return res->status;
-out_overflow:
-       print_overflow_msg(__func__, xdr);
-       return -EIO;
 }
 #endif /* CONFIG_NFS_V4_1 */
 
diff --git a/fs/nfs/nfstrace.c b/fs/nfs/nfstrace.c
new file mode 100644 (file)
index 0000000..4eb0aea
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (c) 2013 Trond Myklebust <Trond.Myklebust@netapp.com>
+ */
+#include <linux/nfs_fs.h>
+#include <linux/namei.h>
+#include "internal.h"
+
+#define CREATE_TRACE_POINTS
+#include "nfstrace.h"
diff --git a/fs/nfs/nfstrace.h b/fs/nfs/nfstrace.h
new file mode 100644 (file)
index 0000000..89fe741
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2013 Trond Myklebust <Trond.Myklebust@netapp.com>
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM nfs
+
+#if !defined(_TRACE_NFS_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_NFS_H
+
+#include <linux/tracepoint.h>
+
+#define nfs_show_file_type(ftype) \
+       __print_symbolic(ftype, \
+                       { DT_UNKNOWN, "UNKNOWN" }, \
+                       { DT_FIFO, "FIFO" }, \
+                       { DT_CHR, "CHR" }, \
+                       { DT_DIR, "DIR" }, \
+                       { DT_BLK, "BLK" }, \
+                       { DT_REG, "REG" }, \
+                       { DT_LNK, "LNK" }, \
+                       { DT_SOCK, "SOCK" }, \
+                       { DT_WHT, "WHT" })
+
+#define nfs_show_cache_validity(v) \
+       __print_flags(v, "|", \
+                       { NFS_INO_INVALID_ATTR, "INVALID_ATTR" }, \
+                       { NFS_INO_INVALID_DATA, "INVALID_DATA" }, \
+                       { NFS_INO_INVALID_ATIME, "INVALID_ATIME" }, \
+                       { NFS_INO_INVALID_ACCESS, "INVALID_ACCESS" }, \
+                       { NFS_INO_INVALID_ACL, "INVALID_ACL" }, \
+                       { NFS_INO_REVAL_PAGECACHE, "REVAL_PAGECACHE" }, \
+                       { NFS_INO_REVAL_FORCED, "REVAL_FORCED" }, \
+                       { NFS_INO_INVALID_LABEL, "INVALID_LABEL" })
+
+#define nfs_show_nfsi_flags(v) \
+       __print_flags(v, "|", \
+                       { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \
+                       { 1 << NFS_INO_STALE, "STALE" }, \
+                       { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
+                       { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
+                       { 1 << NFS_INO_COMMIT, "COMMIT" }, \
+                       { 1 << NFS_INO_LAYOUTCOMMIT, "NEED_LAYOUTCOMMIT" }, \
+                       { 1 << NFS_INO_LAYOUTCOMMITTING, "LAYOUTCOMMIT" })
+
+DECLARE_EVENT_CLASS(nfs_inode_event,
+               TP_PROTO(
+                       const struct inode *inode
+               ),
+
+               TP_ARGS(inode),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(u64, fileid)
+                       __field(u64, version)
+               ),
+
+               TP_fast_assign(
+                       const struct nfs_inode *nfsi = NFS_I(inode);
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = nfsi->fileid;
+                       __entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
+                       __entry->version = inode->i_version;
+               ),
+
+               TP_printk(
+                       "fileid=%02x:%02x:%llu fhandle=0x%08x version=%llu ",
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       (unsigned long long)__entry->version
+               )
+);
+
+DECLARE_EVENT_CLASS(nfs_inode_event_done,
+               TP_PROTO(
+                       const struct inode *inode,
+                       int error
+               ),
+
+               TP_ARGS(inode, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(dev_t, dev)
+                       __field(u32, fhandle)
+                       __field(unsigned char, type)
+                       __field(u64, fileid)
+                       __field(u64, version)
+                       __field(loff_t, size)
+                       __field(unsigned long, nfsi_flags)
+                       __field(unsigned long, cache_validity)
+               ),
+
+               TP_fast_assign(
+                       const struct nfs_inode *nfsi = NFS_I(inode);
+                       __entry->error = error;
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = nfsi->fileid;
+                       __entry->fhandle = nfs_fhandle_hash(&nfsi->fh);
+                       __entry->type = nfs_umode_to_dtype(inode->i_mode);
+                       __entry->version = inode->i_version;
+                       __entry->size = i_size_read(inode);
+                       __entry->nfsi_flags = nfsi->flags;
+                       __entry->cache_validity = nfsi->cache_validity;
+               ),
+
+               TP_printk(
+                       "error=%d fileid=%02x:%02x:%llu fhandle=0x%08x "
+                       "type=%u (%s) version=%llu size=%lld "
+                       "cache_validity=%lu (%s) nfs_flags=%ld (%s)",
+                       __entry->error,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->fileid,
+                       __entry->fhandle,
+                       __entry->type,
+                       nfs_show_file_type(__entry->type),
+                       (unsigned long long)__entry->version,
+                       (long long)__entry->size,
+                       __entry->cache_validity,
+                       nfs_show_cache_validity(__entry->cache_validity),
+                       __entry->nfsi_flags,
+                       nfs_show_nfsi_flags(__entry->nfsi_flags)
+               )
+);
+
+#define DEFINE_NFS_INODE_EVENT(name) \
+       DEFINE_EVENT(nfs_inode_event, name, \
+                       TP_PROTO( \
+                               const struct inode *inode \
+                       ), \
+                       TP_ARGS(inode))
+#define DEFINE_NFS_INODE_EVENT_DONE(name) \
+       DEFINE_EVENT(nfs_inode_event_done, name, \
+                       TP_PROTO( \
+                               const struct inode *inode, \
+                               int error \
+                       ), \
+                       TP_ARGS(inode, error))
+DEFINE_NFS_INODE_EVENT(nfs_refresh_inode_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_refresh_inode_exit);
+DEFINE_NFS_INODE_EVENT(nfs_revalidate_inode_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_revalidate_inode_exit);
+DEFINE_NFS_INODE_EVENT(nfs_invalidate_mapping_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_invalidate_mapping_exit);
+DEFINE_NFS_INODE_EVENT(nfs_getattr_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_getattr_exit);
+DEFINE_NFS_INODE_EVENT(nfs_setattr_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_setattr_exit);
+DEFINE_NFS_INODE_EVENT(nfs_writeback_page_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_writeback_page_exit);
+DEFINE_NFS_INODE_EVENT(nfs_writeback_inode_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_writeback_inode_exit);
+DEFINE_NFS_INODE_EVENT(nfs_fsync_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_fsync_exit);
+DEFINE_NFS_INODE_EVENT(nfs_access_enter);
+DEFINE_NFS_INODE_EVENT_DONE(nfs_access_exit);
+
+#define show_lookup_flags(flags) \
+       __print_flags((unsigned long)flags, "|", \
+                       { LOOKUP_AUTOMOUNT, "AUTOMOUNT" }, \
+                       { LOOKUP_DIRECTORY, "DIRECTORY" }, \
+                       { LOOKUP_OPEN, "OPEN" }, \
+                       { LOOKUP_CREATE, "CREATE" }, \
+                       { LOOKUP_EXCL, "EXCL" })
+
+DECLARE_EVENT_CLASS(nfs_lookup_event,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct dentry *dentry,
+                       unsigned int flags
+               ),
+
+               TP_ARGS(dir, dentry, flags),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, flags)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->flags = flags;
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "flags=%u (%s) name=%02x:%02x:%llu/%s",
+                       __entry->flags,
+                       show_lookup_flags(__entry->flags),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+#define DEFINE_NFS_LOOKUP_EVENT(name) \
+       DEFINE_EVENT(nfs_lookup_event, name, \
+                       TP_PROTO( \
+                               const struct inode *dir, \
+                               const struct dentry *dentry, \
+                               unsigned int flags \
+                       ), \
+                       TP_ARGS(dir, dentry, flags))
+
+DECLARE_EVENT_CLASS(nfs_lookup_event_done,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct dentry *dentry,
+                       unsigned int flags,
+                       int error
+               ),
+
+               TP_ARGS(dir, dentry, flags, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(unsigned int, flags)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->error = error;
+                       __entry->flags = flags;
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d flags=%u (%s) name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       __entry->flags,
+                       show_lookup_flags(__entry->flags),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+#define DEFINE_NFS_LOOKUP_EVENT_DONE(name) \
+       DEFINE_EVENT(nfs_lookup_event_done, name, \
+                       TP_PROTO( \
+                               const struct inode *dir, \
+                               const struct dentry *dentry, \
+                               unsigned int flags, \
+                               int error \
+                       ), \
+                       TP_ARGS(dir, dentry, flags, error))
+
+DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_enter);
+DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_exit);
+DEFINE_NFS_LOOKUP_EVENT(nfs_lookup_revalidate_enter);
+DEFINE_NFS_LOOKUP_EVENT_DONE(nfs_lookup_revalidate_exit);
+
+#define show_open_flags(flags) \
+       __print_flags((unsigned long)flags, "|", \
+               { O_CREAT, "O_CREAT" }, \
+               { O_EXCL, "O_EXCL" }, \
+               { O_TRUNC, "O_TRUNC" }, \
+               { O_APPEND, "O_APPEND" }, \
+               { O_DSYNC, "O_DSYNC" }, \
+               { O_DIRECT, "O_DIRECT" }, \
+               { O_DIRECTORY, "O_DIRECTORY" })
+
+#define show_fmode_flags(mode) \
+       __print_flags(mode, "|", \
+               { ((__force unsigned long)FMODE_READ), "READ" }, \
+               { ((__force unsigned long)FMODE_WRITE), "WRITE" }, \
+               { ((__force unsigned long)FMODE_EXEC), "EXEC" })
+
+TRACE_EVENT(nfs_atomic_open_enter,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct nfs_open_context *ctx,
+                       unsigned int flags
+               ),
+
+               TP_ARGS(dir, ctx, flags),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, flags)
+                       __field(unsigned int, fmode)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, ctx->dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->flags = flags;
+                       __entry->fmode = (__force unsigned int)ctx->mode;
+                       __assign_str(name, ctx->dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "flags=%u (%s) fmode=%s name=%02x:%02x:%llu/%s",
+                       __entry->flags,
+                       show_open_flags(__entry->flags),
+                       show_fmode_flags(__entry->fmode),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+TRACE_EVENT(nfs_atomic_open_exit,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct nfs_open_context *ctx,
+                       unsigned int flags,
+                       int error
+               ),
+
+               TP_ARGS(dir, ctx, flags, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(unsigned int, flags)
+                       __field(unsigned int, fmode)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, ctx->dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->error = error;
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->flags = flags;
+                       __entry->fmode = (__force unsigned int)ctx->mode;
+                       __assign_str(name, ctx->dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d flags=%u (%s) fmode=%s "
+                       "name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       __entry->flags,
+                       show_open_flags(__entry->flags),
+                       show_fmode_flags(__entry->fmode),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+TRACE_EVENT(nfs_create_enter,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct dentry *dentry,
+                       unsigned int flags
+               ),
+
+               TP_ARGS(dir, dentry, flags),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, flags)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->flags = flags;
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "flags=%u (%s) name=%02x:%02x:%llu/%s",
+                       __entry->flags,
+                       show_open_flags(__entry->flags),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+TRACE_EVENT(nfs_create_exit,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct dentry *dentry,
+                       unsigned int flags,
+                       int error
+               ),
+
+               TP_ARGS(dir, dentry, flags, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(unsigned int, flags)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->error = error;
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->flags = flags;
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d flags=%u (%s) name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       __entry->flags,
+                       show_open_flags(__entry->flags),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+DECLARE_EVENT_CLASS(nfs_directory_event,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct dentry *dentry
+               ),
+
+               TP_ARGS(dir, dentry),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "name=%02x:%02x:%llu/%s",
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+#define DEFINE_NFS_DIRECTORY_EVENT(name) \
+       DEFINE_EVENT(nfs_directory_event, name, \
+                       TP_PROTO( \
+                               const struct inode *dir, \
+                               const struct dentry *dentry \
+                       ), \
+                       TP_ARGS(dir, dentry))
+
+DECLARE_EVENT_CLASS(nfs_directory_event_done,
+               TP_PROTO(
+                       const struct inode *dir,
+                       const struct dentry *dentry,
+                       int error
+               ),
+
+               TP_ARGS(dir, dentry, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(dev_t, dev)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->error = error;
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+#define DEFINE_NFS_DIRECTORY_EVENT_DONE(name) \
+       DEFINE_EVENT(nfs_directory_event_done, name, \
+                       TP_PROTO( \
+                               const struct inode *dir, \
+                               const struct dentry *dentry, \
+                               int error \
+                       ), \
+                       TP_ARGS(dir, dentry, error))
+
+DEFINE_NFS_DIRECTORY_EVENT(nfs_mknod_enter);
+DEFINE_NFS_DIRECTORY_EVENT_DONE(nfs_mknod_exit);
+DEFINE_NFS_DIRECTORY_EVENT(nfs_mkdir_enter);
+DEFINE_NFS_DIRECTORY_EVENT_DONE(nfs_mkdir_exit);
+DEFINE_NFS_DIRECTORY_EVENT(nfs_rmdir_enter);
+DEFINE_NFS_DIRECTORY_EVENT_DONE(nfs_rmdir_exit);
+DEFINE_NFS_DIRECTORY_EVENT(nfs_remove_enter);
+DEFINE_NFS_DIRECTORY_EVENT_DONE(nfs_remove_exit);
+DEFINE_NFS_DIRECTORY_EVENT(nfs_unlink_enter);
+DEFINE_NFS_DIRECTORY_EVENT_DONE(nfs_unlink_exit);
+DEFINE_NFS_DIRECTORY_EVENT(nfs_symlink_enter);
+DEFINE_NFS_DIRECTORY_EVENT_DONE(nfs_symlink_exit);
+
+TRACE_EVENT(nfs_link_enter,
+               TP_PROTO(
+                       const struct inode *inode,
+                       const struct inode *dir,
+                       const struct dentry *dentry
+               ),
+
+               TP_ARGS(inode, dir, dentry),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u64, fileid)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->dir = NFS_FILEID(dir);
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "fileid=%02x:%02x:%llu name=%02x:%02x:%llu/%s",
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       __entry->fileid,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+TRACE_EVENT(nfs_link_exit,
+               TP_PROTO(
+                       const struct inode *inode,
+                       const struct inode *dir,
+                       const struct dentry *dentry,
+                       int error
+               ),
+
+               TP_ARGS(inode, dir, dentry, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(dev_t, dev)
+                       __field(u64, fileid)
+                       __field(u64, dir)
+                       __string(name, dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = inode->i_sb->s_dev;
+                       __entry->fileid = NFS_FILEID(inode);
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->error = error;
+                       __assign_str(name, dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d fileid=%02x:%02x:%llu name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       __entry->fileid,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+
+DECLARE_EVENT_CLASS(nfs_rename_event,
+               TP_PROTO(
+                       const struct inode *old_dir,
+                       const struct dentry *old_dentry,
+                       const struct inode *new_dir,
+                       const struct dentry *new_dentry
+               ),
+
+               TP_ARGS(old_dir, old_dentry, new_dir, new_dentry),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(u64, old_dir)
+                       __field(u64, new_dir)
+                       __string(old_name, old_dentry->d_name.name)
+                       __string(new_name, new_dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = old_dir->i_sb->s_dev;
+                       __entry->old_dir = NFS_FILEID(old_dir);
+                       __entry->new_dir = NFS_FILEID(new_dir);
+                       __assign_str(old_name, old_dentry->d_name.name);
+                       __assign_str(new_name, new_dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "old_name=%02x:%02x:%llu/%s new_name=%02x:%02x:%llu/%s",
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->old_dir,
+                       __get_str(old_name),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->new_dir,
+                       __get_str(new_name)
+               )
+);
+#define DEFINE_NFS_RENAME_EVENT(name) \
+       DEFINE_EVENT(nfs_rename_event, name, \
+                       TP_PROTO( \
+                               const struct inode *old_dir, \
+                               const struct dentry *old_dentry, \
+                               const struct inode *new_dir, \
+                               const struct dentry *new_dentry \
+                       ), \
+                       TP_ARGS(old_dir, old_dentry, new_dir, new_dentry))
+
+DECLARE_EVENT_CLASS(nfs_rename_event_done,
+               TP_PROTO(
+                       const struct inode *old_dir,
+                       const struct dentry *old_dentry,
+                       const struct inode *new_dir,
+                       const struct dentry *new_dentry,
+                       int error
+               ),
+
+               TP_ARGS(old_dir, old_dentry, new_dir, new_dentry, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(int, error)
+                       __field(u64, old_dir)
+                       __string(old_name, old_dentry->d_name.name)
+                       __field(u64, new_dir)
+                       __string(new_name, new_dentry->d_name.name)
+               ),
+
+               TP_fast_assign(
+                       __entry->dev = old_dir->i_sb->s_dev;
+                       __entry->old_dir = NFS_FILEID(old_dir);
+                       __entry->new_dir = NFS_FILEID(new_dir);
+                       __entry->error = error;
+                       __assign_str(old_name, old_dentry->d_name.name);
+                       __assign_str(new_name, new_dentry->d_name.name);
+               ),
+
+               TP_printk(
+                       "error=%d old_name=%02x:%02x:%llu/%s "
+                       "new_name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->old_dir,
+                       __get_str(old_name),
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->new_dir,
+                       __get_str(new_name)
+               )
+);
+#define DEFINE_NFS_RENAME_EVENT_DONE(name) \
+       DEFINE_EVENT(nfs_rename_event_done, name, \
+                       TP_PROTO( \
+                               const struct inode *old_dir, \
+                               const struct dentry *old_dentry, \
+                               const struct inode *new_dir, \
+                               const struct dentry *new_dentry, \
+                               int error \
+                       ), \
+                       TP_ARGS(old_dir, old_dentry, new_dir, \
+                               new_dentry, error))
+
+DEFINE_NFS_RENAME_EVENT(nfs_rename_enter);
+DEFINE_NFS_RENAME_EVENT_DONE(nfs_rename_exit);
+
+DEFINE_NFS_RENAME_EVENT_DONE(nfs_sillyrename_rename);
+
+TRACE_EVENT(nfs_sillyrename_unlink,
+               TP_PROTO(
+                       const struct nfs_unlinkdata *data,
+                       int error
+               ),
+
+               TP_ARGS(data, error),
+
+               TP_STRUCT__entry(
+                       __field(dev_t, dev)
+                       __field(int, error)
+                       __field(u64, dir)
+                       __dynamic_array(char, name, data->args.name.len + 1)
+               ),
+
+               TP_fast_assign(
+                       struct inode *dir = data->dir;
+                       size_t len = data->args.name.len;
+                       __entry->dev = dir->i_sb->s_dev;
+                       __entry->dir = NFS_FILEID(dir);
+                       __entry->error = error;
+                       memcpy(__get_dynamic_array(name),
+                               data->args.name.name, len);
+                       ((char *)__get_dynamic_array(name))[len] = 0;
+               ),
+
+               TP_printk(
+                       "error=%d name=%02x:%02x:%llu/%s",
+                       __entry->error,
+                       MAJOR(__entry->dev), MINOR(__entry->dev),
+                       (unsigned long long)__entry->dir,
+                       __get_str(name)
+               )
+);
+#endif /* _TRACE_NFS_H */
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE nfstrace
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 29cfb7ade121276e2d5ed7372d01949c5e0c2819..2ffebf2081ceb5c779cf7f53644fa453bff45ca2 100644 (file)
@@ -328,6 +328,19 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc,
 }
 EXPORT_SYMBOL_GPL(nfs_pageio_init);
 
+static bool nfs_match_open_context(const struct nfs_open_context *ctx1,
+               const struct nfs_open_context *ctx2)
+{
+       return ctx1->cred == ctx2->cred && ctx1->state == ctx2->state;
+}
+
+static bool nfs_match_lock_context(const struct nfs_lock_context *l1,
+               const struct nfs_lock_context *l2)
+{
+       return l1->lockowner.l_owner == l2->lockowner.l_owner
+               && l1->lockowner.l_pid == l2->lockowner.l_pid;
+}
+
 /**
  * nfs_can_coalesce_requests - test two requests for compatibility
  * @prev: pointer to nfs_page
@@ -343,13 +356,10 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev,
                                      struct nfs_page *req,
                                      struct nfs_pageio_descriptor *pgio)
 {
-       if (req->wb_context->cred != prev->wb_context->cred)
-               return false;
-       if (req->wb_lock_context->lockowner.l_owner != prev->wb_lock_context->lockowner.l_owner)
-               return false;
-       if (req->wb_lock_context->lockowner.l_pid != prev->wb_lock_context->lockowner.l_pid)
+       if (!nfs_match_open_context(req->wb_context, prev->wb_context))
                return false;
-       if (req->wb_context->state != prev->wb_context->state)
+       if (req->wb_context->dentry->d_inode->i_flock != NULL &&
+           !nfs_match_lock_context(req->wb_lock_context, prev->wb_lock_context))
                return false;
        if (req->wb_pgbase != 0)
                return false;
index 3a3a79d6bf15c4fa4dfabdf10802a0ee4be9c5aa..d75d938d36cbff83bee4f905e142eeaf95c9b33b 100644 (file)
@@ -33,6 +33,7 @@
 #include "internal.h"
 #include "pnfs.h"
 #include "iostat.h"
+#include "nfs4trace.h"
 
 #define NFSDBG_FACILITY                NFSDBG_PNFS
 #define PNFS_LAYOUTGET_RETRY_TIMEOUT (120*HZ)
@@ -1526,6 +1527,7 @@ void pnfs_ld_write_done(struct nfs_write_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
+       trace_nfs4_pnfs_write(data, hdr->pnfs_error);
        if (!hdr->pnfs_error) {
                pnfs_set_layoutcommit(data);
                hdr->mds_ops->rpc_call_done(&data->task, data);
@@ -1680,6 +1682,7 @@ void pnfs_ld_read_done(struct nfs_read_data *data)
 {
        struct nfs_pgio_header *hdr = data->header;
 
+       trace_nfs4_pnfs_read(data, hdr->pnfs_error);
        if (likely(!hdr->pnfs_error)) {
                __nfs4_read_done_cb(data);
                hdr->mds_ops->rpc_call_done(&data->task, data);
index c041c41f7a52bcc849400bd55eae238c47b1ad0d..a8f57c728df561ac58e158c9fb46ca3b7c77004e 100644 (file)
@@ -623,9 +623,10 @@ static void nfs_proc_read_setup(struct nfs_read_data *data, struct rpc_message *
        msg->rpc_proc = &nfs_procedures[NFSPROC_READ];
 }
 
-static void nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
+static int nfs_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
 {
        rpc_call_start(task);
+       return 0;
 }
 
 static int nfs_write_done(struct rpc_task *task, struct nfs_write_data *data)
@@ -644,9 +645,10 @@ static void nfs_proc_write_setup(struct nfs_write_data *data, struct rpc_message
        msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE];
 }
 
-static void nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
+static int nfs_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
 {
        rpc_call_start(task);
+       return 0;
 }
 
 static void nfs_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
index 70a26c651f0952e596cebd8191f53c2ac937d939..31db5c366b816e4c18d806ae0ae80d0c9207905e 100644 (file)
@@ -513,9 +513,10 @@ static void nfs_readpage_release_common(void *calldata)
 void nfs_read_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_read_data *data = calldata;
-       NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
-       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
-               rpc_exit(task, -EIO);
+       int err;
+       err = NFS_PROTO(data->header->inode)->read_rpc_prepare(task, data);
+       if (err)
+               rpc_exit(task, err);
 }
 
 static const struct rpc_call_ops nfs_read_common_ops = {
index f6db66d8f647069a4cffde4e609bc7f23e3a2da0..a03b9c6f94895c4bec17b7191aac69a190d3e35f 100644 (file)
@@ -360,7 +360,8 @@ static void unregister_nfs4_fs(void)
 #endif
 
 static struct shrinker acl_shrinker = {
-       .shrink         = nfs_access_cache_shrinker,
+       .count_objects  = nfs_access_cache_count,
+       .scan_objects   = nfs_access_cache_scan,
        .seeks          = DEFAULT_SEEKS,
 };
 
@@ -923,7 +924,7 @@ static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
                data->nfs_server.port   = NFS_UNSPEC_PORT;
                data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
                data->auth_flavors[0]   = RPC_AUTH_MAXFLAVOR;
-               data->auth_flavor_len   = 1;
+               data->auth_flavor_len   = 0;
                data->minorversion      = 0;
                data->need_mount        = true;
                data->net               = current->nsproxy->net_ns;
@@ -1018,6 +1019,13 @@ static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
        }
 }
 
+static void nfs_set_auth_parsed_mount_data(struct nfs_parsed_mount_data *data,
+               rpc_authflavor_t pseudoflavor)
+{
+       data->auth_flavors[0] = pseudoflavor;
+       data->auth_flavor_len = 1;
+}
+
 /*
  * Parse the value of the 'sec=' option.
  */
@@ -1025,49 +1033,50 @@ static int nfs_parse_security_flavors(char *value,
                                      struct nfs_parsed_mount_data *mnt)
 {
        substring_t args[MAX_OPT_ARGS];
+       rpc_authflavor_t pseudoflavor;
 
        dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
 
        switch (match_token(value, nfs_secflavor_tokens, args)) {
        case Opt_sec_none:
-               mnt->auth_flavors[0] = RPC_AUTH_NULL;
+               pseudoflavor = RPC_AUTH_NULL;
                break;
        case Opt_sec_sys:
-               mnt->auth_flavors[0] = RPC_AUTH_UNIX;
+               pseudoflavor = RPC_AUTH_UNIX;
                break;
        case Opt_sec_krb5:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5;
+               pseudoflavor = RPC_AUTH_GSS_KRB5;
                break;
        case Opt_sec_krb5i:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5I;
+               pseudoflavor = RPC_AUTH_GSS_KRB5I;
                break;
        case Opt_sec_krb5p:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_KRB5P;
+               pseudoflavor = RPC_AUTH_GSS_KRB5P;
                break;
        case Opt_sec_lkey:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEY;
+               pseudoflavor = RPC_AUTH_GSS_LKEY;
                break;
        case Opt_sec_lkeyi:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYI;
+               pseudoflavor = RPC_AUTH_GSS_LKEYI;
                break;
        case Opt_sec_lkeyp:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_LKEYP;
+               pseudoflavor = RPC_AUTH_GSS_LKEYP;
                break;
        case Opt_sec_spkm:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKM;
+               pseudoflavor = RPC_AUTH_GSS_SPKM;
                break;
        case Opt_sec_spkmi:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMI;
+               pseudoflavor = RPC_AUTH_GSS_SPKMI;
                break;
        case Opt_sec_spkmp:
-               mnt->auth_flavors[0] = RPC_AUTH_GSS_SPKMP;
+               pseudoflavor = RPC_AUTH_GSS_SPKMP;
                break;
        default:
                return 0;
        }
 
        mnt->flags |= NFS_MOUNT_SECFLAVOUR;
-       mnt->auth_flavor_len = 1;
+       nfs_set_auth_parsed_mount_data(mnt, pseudoflavor);
        return 1;
 }
 
@@ -1729,7 +1738,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
         * Was a sec= authflavor specified in the options? First, verify
         * whether the server supports it, and then just try to use it if so.
         */
-       if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) {
+       if (args->auth_flavor_len > 0) {
                status = nfs_verify_authflavor(args, authlist, authlist_len);
                dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]);
                if (status)
@@ -1760,7 +1769,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
                        /* Fallthrough */
                }
                dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
-               args->auth_flavors[0] = flavor;
+               nfs_set_auth_parsed_mount_data(args, flavor);
                server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
                if (!IS_ERR(server))
                        return server;
@@ -1776,7 +1785,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
 
        /* Last chance! Try AUTH_UNIX */
        dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
-       args->auth_flavors[0] = RPC_AUTH_UNIX;
+       nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX);
        return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 }
 
@@ -1893,6 +1902,7 @@ static int nfs23_validate_mount_data(void *options,
 {
        struct nfs_mount_data *data = (struct nfs_mount_data *)options;
        struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+       int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
 
        if (data == NULL)
                goto out_no_data;
@@ -1908,6 +1918,8 @@ static int nfs23_validate_mount_data(void *options,
                        goto out_no_v3;
                data->root.size = NFS2_FHSIZE;
                memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+               /* Turn off security negotiation */
+               extra_flags |= NFS_MOUNT_SECFLAVOUR;
        case 4:
                if (data->flags & NFS_MOUNT_SECFLAVOUR)
                        goto out_no_sec;
@@ -1935,7 +1947,7 @@ static int nfs23_validate_mount_data(void *options,
                 * can deal with.
                 */
                args->flags             = data->flags & NFS_MOUNT_FLAGMASK;
-               args->flags             |= NFS_MOUNT_LEGACY_INTERFACE;
+               args->flags             |= extra_flags;
                args->rsize             = data->rsize;
                args->wsize             = data->wsize;
                args->timeo             = data->timeo;
@@ -1959,9 +1971,10 @@ static int nfs23_validate_mount_data(void *options,
                args->namlen            = data->namlen;
                args->bsize             = data->bsize;
 
-               args->auth_flavors[0] = RPC_AUTH_UNIX;
                if (data->flags & NFS_MOUNT_SECFLAVOUR)
-                       args->auth_flavors[0] = data->pseudoflavor;
+                       nfs_set_auth_parsed_mount_data(args, data->pseudoflavor);
+               else
+                       nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX);
                if (!args->nfs_server.hostname)
                        goto out_nomem;
 
@@ -2084,6 +2097,8 @@ static int nfs_validate_text_mount_data(void *options,
                max_namelen = NFS4_MAXNAMLEN;
                max_pathlen = NFS4_MAXPATHLEN;
                nfs_validate_transport_protocol(args);
+               if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+                       goto out_invalid_transport_udp;
                nfs4_validate_mount_flags(args);
 #else
                goto out_v4_not_compiled;
@@ -2106,6 +2121,10 @@ static int nfs_validate_text_mount_data(void *options,
 out_v4_not_compiled:
        dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
        return -EPROTONOSUPPORT;
+#else
+out_invalid_transport_udp:
+       dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+       return -EINVAL;
 #endif /* !CONFIG_NFS_V4 */
 
 out_no_address:
@@ -2170,7 +2189,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
        data->rsize = nfss->rsize;
        data->wsize = nfss->wsize;
        data->retrans = nfss->client->cl_timeout->to_retries;
-       data->auth_flavors[0] = nfss->client->cl_auth->au_flavor;
+       nfs_set_auth_parsed_mount_data(data, nfss->client->cl_auth->au_flavor);
        data->acregmin = nfss->acregmin / HZ;
        data->acregmax = nfss->acregmax / HZ;
        data->acdirmin = nfss->acdirmin / HZ;
@@ -2277,6 +2296,18 @@ void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info)
        nfs_initialise_sb(sb);
 }
 
+#define NFS_MOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
+               | NFS_MOUNT_SECURE \
+               | NFS_MOUNT_TCP \
+               | NFS_MOUNT_VER3 \
+               | NFS_MOUNT_KERBEROS \
+               | NFS_MOUNT_NONLM \
+               | NFS_MOUNT_BROKEN_SUID \
+               | NFS_MOUNT_STRICTLOCK \
+               | NFS_MOUNT_UNSHARED \
+               | NFS_MOUNT_NORESVPORT \
+               | NFS_MOUNT_LEGACY_INTERFACE)
+
 static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
 {
        const struct nfs_server *a = s->s_fs_info;
@@ -2287,7 +2318,7 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
                goto Ebusy;
        if (a->nfs_client != b->nfs_client)
                goto Ebusy;
-       if (a->flags != b->flags)
+       if ((a->flags ^ b->flags) & NFS_MOUNT_CMP_FLAGMASK)
                goto Ebusy;
        if (a->wsize != b->wsize)
                goto Ebusy;
@@ -2301,7 +2332,8 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
                goto Ebusy;
        if (a->acdirmax != b->acdirmax)
                goto Ebusy;
-       if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
+       if (b->flags & NFS_MOUNT_SECFLAVOUR &&
+          clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor)
                goto Ebusy;
        return 1;
 Ebusy:
@@ -2673,15 +2705,17 @@ static int nfs4_validate_mount_data(void *options,
                        goto out_no_address;
                args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
 
-               args->auth_flavors[0] = RPC_AUTH_UNIX;
                if (data->auth_flavourlen) {
+                       rpc_authflavor_t pseudoflavor;
                        if (data->auth_flavourlen > 1)
                                goto out_inval_auth;
-                       if (copy_from_user(&args->auth_flavors[0],
+                       if (copy_from_user(&pseudoflavor,
                                           data->auth_flavours,
-                                          sizeof(args->auth_flavors[0])))
+                                          sizeof(pseudoflavor)))
                                return -EFAULT;
-               }
+                       nfs_set_auth_parsed_mount_data(args, pseudoflavor);
+               } else
+                       nfs_set_auth_parsed_mount_data(args, RPC_AUTH_UNIX);
 
                c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
                if (IS_ERR(c))
@@ -2715,6 +2749,8 @@ static int nfs4_validate_mount_data(void *options,
                args->acdirmax  = data->acdirmax;
                args->nfs_server.protocol = data->proto;
                nfs_validate_transport_protocol(args);
+               if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+                       goto out_invalid_transport_udp;
 
                break;
        default:
@@ -2735,6 +2771,10 @@ out_inval_auth:
 out_no_address:
        dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
        return -EINVAL;
+
+out_invalid_transport_udp:
+       dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+       return -EINVAL;
 }
 
 /*
@@ -2750,6 +2790,7 @@ bool nfs4_disable_idmapping = true;
 unsigned short max_session_slots = NFS4_DEF_SLOT_TABLE_SIZE;
 unsigned short send_implementation_id = 1;
 char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN] = "";
+bool recover_lost_locks = false;
 
 EXPORT_SYMBOL_GPL(nfs_callback_set_tcpport);
 EXPORT_SYMBOL_GPL(nfs_callback_tcpport);
@@ -2758,6 +2799,7 @@ EXPORT_SYMBOL_GPL(nfs4_disable_idmapping);
 EXPORT_SYMBOL_GPL(max_session_slots);
 EXPORT_SYMBOL_GPL(send_implementation_id);
 EXPORT_SYMBOL_GPL(nfs4_client_id_uniquifier);
+EXPORT_SYMBOL_GPL(recover_lost_locks);
 
 #define NFS_CALLBACK_MAXPORTNR (65535U)
 
@@ -2795,4 +2837,10 @@ MODULE_PARM_DESC(send_implementation_id,
                "Send implementation ID with NFSv4.1 exchange_id");
 MODULE_PARM_DESC(nfs4_unique_id, "nfs_client_id4 uniquifier string");
 
+module_param(recover_lost_locks, bool, 0644);
+MODULE_PARM_DESC(recover_lost_locks,
+                "If the server reports that a lock might be lost, "
+                "try to recover it risking data corruption.");
+
+
 #endif /* CONFIG_NFS_V4 */
index 60395ad3a2e475076ee3382e05b221aacdcaa60b..bb939edd4c998cb98b7aeb56ae1aa308e4d9009d 100644 (file)
@@ -20,6 +20,8 @@
 #include "iostat.h"
 #include "delegation.h"
 
+#include "nfstrace.h"
+
 /**
  * nfs_free_unlinkdata - release data from a sillydelete operation.
  * @data: pointer to unlink structure.
@@ -77,6 +79,7 @@ static void nfs_async_unlink_done(struct rpc_task *task, void *calldata)
        struct nfs_unlinkdata *data = calldata;
        struct inode *dir = data->dir;
 
+       trace_nfs_sillyrename_unlink(data, task->tk_status);
        if (!NFS_PROTO(dir)->unlink_done(task, dir))
                rpc_restart_call_prepare(task);
 }
@@ -204,6 +207,13 @@ out_free:
        return ret;
 }
 
+void nfs_wait_on_sillyrename(struct dentry *dentry)
+{
+       struct nfs_inode *nfsi = NFS_I(dentry->d_inode);
+
+       wait_event(nfsi->waitqueue, atomic_read(&nfsi->silly_count) <= 1);
+}
+
 void nfs_block_sillyrename(struct dentry *dentry)
 {
        struct nfs_inode *nfsi = NFS_I(dentry->d_inode);
@@ -336,6 +346,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
        struct inode *new_dir = data->new_dir;
        struct dentry *old_dentry = data->old_dentry;
 
+       trace_nfs_sillyrename_rename(old_dir, old_dentry,
+                       new_dir, data->new_dentry, task->tk_status);
        if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {
                rpc_restart_call_prepare(task);
                return;
@@ -444,6 +456,14 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
        return rpc_run_task(&task_setup_data);
 }
 
+#define SILLYNAME_PREFIX ".nfs"
+#define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1)
+#define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1)
+#define SILLYNAME_COUNTER_LEN ((unsigned)sizeof(unsigned int) << 1)
+#define SILLYNAME_LEN (SILLYNAME_PREFIX_LEN + \
+               SILLYNAME_FILEID_LEN + \
+               SILLYNAME_COUNTER_LEN)
+
 /**
  * nfs_sillyrename - Perform a silly-rename of a dentry
  * @dir: inode of directory that contains dentry
@@ -469,10 +489,8 @@ int
 nfs_sillyrename(struct inode *dir, struct dentry *dentry)
 {
        static unsigned int sillycounter;
-       const int      fileidsize  = sizeof(NFS_FILEID(dentry->d_inode))*2;
-       const int      countersize = sizeof(sillycounter)*2;
-       const int      slen        = sizeof(".nfs")+fileidsize+countersize-1;
-       char           silly[slen+1];
+       unsigned char silly[SILLYNAME_LEN + 1];
+       unsigned long long fileid;
        struct dentry *sdentry;
        struct rpc_task *task;
        int            error = -EIO;
@@ -489,20 +507,20 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
        if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
                goto out;
 
-       sprintf(silly, ".nfs%*.*Lx",
-               fileidsize, fileidsize,
-               (unsigned long long)NFS_FILEID(dentry->d_inode));
+       fileid = NFS_FILEID(dentry->d_inode);
 
        /* Return delegation in anticipation of the rename */
        NFS_PROTO(dentry->d_inode)->return_delegation(dentry->d_inode);
 
        sdentry = NULL;
        do {
-               char *suffix = silly + slen - countersize;
-
+               int slen;
                dput(sdentry);
                sillycounter++;
-               sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
+               slen = scnprintf(silly, sizeof(silly),
+                               SILLYNAME_PREFIX "%0*llx%0*x",
+                               SILLYNAME_FILEID_LEN, fileid,
+                               SILLYNAME_COUNTER_LEN, sillycounter);
 
                dfprintk(VFS, "NFS: trying to rename %s to %s\n",
                                dentry->d_name.name, silly);
index f1bdb72547768deabc4d0cae87a3271a200e67fc..ac1dc331ba31212108cd5c93352ecdb620122690 100644 (file)
@@ -31,6 +31,8 @@
 #include "fscache.h"
 #include "pnfs.h"
 
+#include "nfstrace.h"
+
 #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
 
 #define MIN_POOL_WRITE         (32)
@@ -861,7 +863,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
                        return 0;
                l_ctx = req->wb_lock_context;
                do_flush = req->wb_page != page || req->wb_context != ctx;
-               if (l_ctx) {
+               if (l_ctx && ctx->dentry->d_inode->i_flock != NULL) {
                        do_flush |= l_ctx->lockowner.l_owner != current->files
                                || l_ctx->lockowner.l_pid != current->tgid;
                }
@@ -873,6 +875,33 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
        return status;
 }
 
+/*
+ * Avoid buffered writes when a open context credential's key would
+ * expire soon.
+ *
+ * Returns -EACCES if the key will expire within RPC_KEY_EXPIRE_FAIL.
+ *
+ * Return 0 and set a credential flag which triggers the inode to flush
+ * and performs  NFS_FILE_SYNC writes if the key will expired within
+ * RPC_KEY_EXPIRE_TIMEO.
+ */
+int
+nfs_key_timeout_notify(struct file *filp, struct inode *inode)
+{
+       struct nfs_open_context *ctx = nfs_file_open_context(filp);
+       struct rpc_auth *auth = NFS_SERVER(inode)->client->cl_auth;
+
+       return rpcauth_key_timeout_notify(auth, ctx->cred);
+}
+
+/*
+ * Test if the open context credential key is marked to expire soon.
+ */
+bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx)
+{
+       return rpcauth_cred_key_to_expire(ctx->cred);
+}
+
 /*
  * If the page cache is marked as unsafe or invalid, then we can't rely on
  * the PageUptodate() flag. In this case, we will need to turn off
@@ -993,6 +1022,9 @@ int nfs_initiate_write(struct rpc_clnt *clnt,
                data->args.count,
                (unsigned long long)data->args.offset);
 
+       nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client,
+                                &task_setup_data.rpc_client, &msg, data);
+
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task)) {
                ret = PTR_ERR(task);
@@ -1265,9 +1297,10 @@ EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
 void nfs_write_prepare(struct rpc_task *task, void *calldata)
 {
        struct nfs_write_data *data = calldata;
-       NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data);
-       if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags)))
-               rpc_exit(task, -EIO);
+       int err;
+       err = NFS_PROTO(data->header->inode)->write_rpc_prepare(task, data);
+       if (err)
+               rpc_exit(task, err);
 }
 
 void nfs_commit_prepare(struct rpc_task *task, void *calldata)
@@ -1458,6 +1491,9 @@ int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data,
 
        dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
 
+       nfs4_state_protect(NFS_SERVER(data->inode)->nfs_client,
+               NFS_SP4_MACH_CRED_COMMIT, &task_setup_data.rpc_client, &msg);
+
        task = rpc_run_task(&task_setup_data);
        if (IS_ERR(task))
                return PTR_ERR(task);
@@ -1732,8 +1768,14 @@ int nfs_wb_all(struct inode *inode)
                .range_start = 0,
                .range_end = LLONG_MAX,
        };
+       int ret;
 
-       return sync_inode(inode, &wbc);
+       trace_nfs_writeback_inode_enter(inode);
+
+       ret = sync_inode(inode, &wbc);
+
+       trace_nfs_writeback_inode_exit(inode, ret);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(nfs_wb_all);
 
@@ -1781,6 +1823,8 @@ int nfs_wb_page(struct inode *inode, struct page *page)
        };
        int ret;
 
+       trace_nfs_writeback_page_enter(inode);
+
        for (;;) {
                wait_on_page_writeback(page);
                if (clear_page_dirty_for_io(page)) {
@@ -1789,14 +1833,15 @@ int nfs_wb_page(struct inode *inode, struct page *page)
                                goto out_error;
                        continue;
                }
+               ret = 0;
                if (!PagePrivate(page))
                        break;
                ret = nfs_commit_inode(inode, FLUSH_SYNC);
                if (ret < 0)
                        goto out_error;
        }
-       return 0;
 out_error:
+       trace_nfs_writeback_page_exit(inode, ret);
        return ret;
 }
 
index 105a3b080d1236c24afed6267354705fd8da5d94..e0a65a9e37e97ac1a8702a48487349d599be4aab 100644 (file)
@@ -173,8 +173,6 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
        int status;
        struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id);
 
-       dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
-
        if (test_and_set_bit(NFSD4_CLIENT_STABLE, &clp->cl_flags))
                return;
        if (!nn->rec_file)
index 43f42290e5df096fe7eced0266759b45264a61a1..0874998a49cd40081dc34483bb8f400a64ad2528 100644 (file)
@@ -368,11 +368,8 @@ static struct nfs4_delegation *
 alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh)
 {
        struct nfs4_delegation *dp;
-       struct nfs4_file *fp = stp->st_file;
 
        dprintk("NFSD alloc_init_deleg\n");
-       if (fp->fi_had_conflict)
-               return NULL;
        if (num_delegations > max_delegations)
                return NULL;
        dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab));
@@ -389,8 +386,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv
        INIT_LIST_HEAD(&dp->dl_perfile);
        INIT_LIST_HEAD(&dp->dl_perclnt);
        INIT_LIST_HEAD(&dp->dl_recall_lru);
-       get_nfs4_file(fp);
-       dp->dl_file = fp;
+       dp->dl_file = NULL;
        dp->dl_type = NFS4_OPEN_DELEGATE_READ;
        fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
        dp->dl_time = 0;
@@ -3035,7 +3031,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
        if (status) {
                list_del_init(&dp->dl_perclnt);
                locks_free_lock(fl);
-               return -ENOMEM;
+               return status;
        }
        fp->fi_lease = fl;
        fp->fi_deleg_file = get_file(fl->fl_file);
@@ -3044,22 +3040,35 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
        return 0;
 }
 
-static int nfs4_set_delegation(struct nfs4_delegation *dp)
+static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
 {
-       struct nfs4_file *fp = dp->dl_file;
+       int status;
 
-       if (!fp->fi_lease)
-               return nfs4_setlease(dp);
+       if (fp->fi_had_conflict)
+               return -EAGAIN;
+       get_nfs4_file(fp);
+       dp->dl_file = fp;
+       if (!fp->fi_lease) {
+               status = nfs4_setlease(dp);
+               if (status)
+                       goto out_free;
+               return 0;
+       }
        spin_lock(&recall_lock);
        if (fp->fi_had_conflict) {
                spin_unlock(&recall_lock);
-               return -EAGAIN;
+               status = -EAGAIN;
+               goto out_free;
        }
        atomic_inc(&fp->fi_delegees);
        list_add(&dp->dl_perfile, &fp->fi_delegations);
        spin_unlock(&recall_lock);
        list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
        return 0;
+out_free:
+       put_nfs4_file(fp);
+       dp->dl_file = fp;
+       return status;
 }
 
 static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
@@ -3134,7 +3143,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
        dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh);
        if (dp == NULL)
                goto out_no_deleg;
-       status = nfs4_set_delegation(dp);
+       status = nfs4_set_delegation(dp, stp->st_file);
        if (status)
                goto out_free;
 
index e76244edd748843cc7b906ba9ebf5dadd5784641..9186c7ce0b141b187a8b127a6608005a05ad53d1 100644 (file)
@@ -59,11 +59,14 @@ static unsigned int         longest_chain_cachesize;
 
 static int     nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
 static void    cache_cleaner_func(struct work_struct *unused);
-static int     nfsd_reply_cache_shrink(struct shrinker *shrink,
-                                       struct shrink_control *sc);
+static unsigned long nfsd_reply_cache_count(struct shrinker *shrink,
+                                           struct shrink_control *sc);
+static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink,
+                                          struct shrink_control *sc);
 
 static struct shrinker nfsd_reply_cache_shrinker = {
-       .shrink = nfsd_reply_cache_shrink,
+       .scan_objects = nfsd_reply_cache_scan,
+       .count_objects = nfsd_reply_cache_count,
        .seeks  = 1,
 };
 
@@ -232,16 +235,18 @@ nfsd_cache_entry_expired(struct svc_cacherep *rp)
  * Walk the LRU list and prune off entries that are older than RC_EXPIRE.
  * Also prune the oldest ones when the total exceeds the max number of entries.
  */
-static void
+static long
 prune_cache_entries(void)
 {
        struct svc_cacherep *rp, *tmp;
+       long freed = 0;
 
        list_for_each_entry_safe(rp, tmp, &lru_head, c_lru) {
                if (!nfsd_cache_entry_expired(rp) &&
                    num_drc_entries <= max_drc_entries)
                        break;
                nfsd_reply_cache_free_locked(rp);
+               freed++;
        }
 
        /*
@@ -254,6 +259,7 @@ prune_cache_entries(void)
                cancel_delayed_work(&cache_cleaner);
        else
                mod_delayed_work(system_wq, &cache_cleaner, RC_EXPIRE);
+       return freed;
 }
 
 static void
@@ -264,20 +270,28 @@ cache_cleaner_func(struct work_struct *unused)
        spin_unlock(&cache_lock);
 }
 
-static int
-nfsd_reply_cache_shrink(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long
+nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc)
 {
-       unsigned int num;
+       unsigned long num;
 
        spin_lock(&cache_lock);
-       if (sc->nr_to_scan)
-               prune_cache_entries();
        num = num_drc_entries;
        spin_unlock(&cache_lock);
 
        return num;
 }
 
+static unsigned long
+nfsd_reply_cache_scan(struct shrinker *shrink, struct shrink_control *sc)
+{
+       unsigned long freed;
+
+       spin_lock(&cache_lock);
+       freed = prune_cache_entries();
+       spin_unlock(&cache_lock);
+       return freed;
+}
 /*
  * Walk an xdr_buf and get a CRC for at most the first RC_CSUMLEN bytes
  */
index b1a5277cfd182adcbfda860ad395e07a14f94db8..7e350c562e0ea1dd491a8ee6c72371b770666e1f 100644 (file)
@@ -254,7 +254,7 @@ void nilfs_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);
+               truncate_pagecache(inode, inode->i_size);
                nilfs_truncate(inode);
        }
 }
index c5670b8d198caf5aea663b224c02e7289d572565..ea4ba9daeb472069cd9d8664b58ff363806ab4e4 100644 (file)
@@ -1768,7 +1768,7 @@ static void ntfs_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);
+               truncate_pagecache(inode, inode->i_size);
                ntfs_truncate_vfs(inode);
        }
 }
index 8a404576fb26557eb8578e21f66d0277a94a9e76..b4f788e0ca318955ab797f2350f8dffa320a53cb 100644 (file)
@@ -51,10 +51,6 @@ static struct posix_acl *ocfs2_acl_from_xattr(const void *value, size_t size)
                return ERR_PTR(-EINVAL);
 
        count = size / sizeof(struct posix_acl_entry);
-       if (count < 0)
-               return ERR_PTR(-EINVAL);
-       if (count == 0)
-               return NULL;
 
        acl = posix_acl_alloc(count, GFP_NOFS);
        if (!acl)
index 94417a85ce6eecce9ce3367365fb2d40581c5a7e..f37d3c0e20535eacce542c7184f48d8b509884a2 100644 (file)
@@ -2044,7 +2044,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping,
 
 out_write_size:
        pos += copied;
-       if (pos > inode->i_size) {
+       if (pos > i_size_read(inode)) {
                i_size_write(inode, pos);
                mark_inode_dirty(inode);
        }
index 5c1c864e81cc0dbcb0cd2f358f52f3c62ae6907d..363f0dcc924fb5b05c433b98e43c5ad9038ddc3b 100644 (file)
@@ -628,11 +628,9 @@ static void o2hb_fire_callbacks(struct o2hb_callback *hbcall,
                                struct o2nm_node *node,
                                int idx)
 {
-       struct list_head *iter;
        struct o2hb_callback_func *f;
 
-       list_for_each(iter, &hbcall->list) {
-               f = list_entry(iter, struct o2hb_callback_func, hc_item);
+       list_for_each_entry(f, &hbcall->list, hc_item) {
                mlog(ML_HEARTBEAT, "calling funcs %p\n", f);
                (f->hc_func)(node, idx, f->hc_data);
        }
@@ -641,16 +639,9 @@ static void o2hb_fire_callbacks(struct o2hb_callback *hbcall,
 /* Will run the list in order until we process the passed event */
 static void o2hb_run_event_list(struct o2hb_node_event *queued_event)
 {
-       int empty;
        struct o2hb_callback *hbcall;
        struct o2hb_node_event *event;
 
-       spin_lock(&o2hb_live_lock);
-       empty = list_empty(&queued_event->hn_item);
-       spin_unlock(&o2hb_live_lock);
-       if (empty)
-               return;
-
        /* Holding callback sem assures we don't alter the callback
         * lists when doing this, and serializes ourselves with other
         * processes wanting callbacks. */
@@ -709,6 +700,7 @@ static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot)
        struct o2hb_node_event event =
                { .hn_item = LIST_HEAD_INIT(event.hn_item), };
        struct o2nm_node *node;
+       int queued = 0;
 
        node = o2nm_get_node_by_num(slot->ds_node_num);
        if (!node)
@@ -726,11 +718,13 @@ static void o2hb_shutdown_slot(struct o2hb_disk_slot *slot)
 
                        o2hb_queue_node_event(&event, O2HB_NODE_DOWN_CB, node,
                                              slot->ds_node_num);
+                       queued = 1;
                }
        }
        spin_unlock(&o2hb_live_lock);
 
-       o2hb_run_event_list(&event);
+       if (queued)
+               o2hb_run_event_list(&event);
 
        o2nm_node_put(node);
 }
@@ -790,6 +784,7 @@ static int o2hb_check_slot(struct o2hb_region *reg,
        unsigned int dead_ms = o2hb_dead_threshold * O2HB_REGION_TIMEOUT_MS;
        unsigned int slot_dead_ms;
        int tmp;
+       int queued = 0;
 
        memcpy(hb_block, slot->ds_raw_block, reg->hr_block_bytes);
 
@@ -883,6 +878,7 @@ fire_callbacks:
                                              slot->ds_node_num);
 
                        changed = 1;
+                       queued = 1;
                }
 
                list_add_tail(&slot->ds_live_item,
@@ -934,6 +930,7 @@ fire_callbacks:
                                              node, slot->ds_node_num);
 
                        changed = 1;
+                       queued = 1;
                }
 
                /* We don't clear this because the node is still
@@ -949,7 +946,8 @@ fire_callbacks:
 out:
        spin_unlock(&o2hb_live_lock);
 
-       o2hb_run_event_list(&event);
+       if (queued)
+               o2hb_run_event_list(&event);
 
        if (node)
                o2nm_node_put(node);
@@ -2516,8 +2514,7 @@ unlock:
 int o2hb_register_callback(const char *region_uuid,
                           struct o2hb_callback_func *hc)
 {
-       struct o2hb_callback_func *tmp;
-       struct list_head *iter;
+       struct o2hb_callback_func *f;
        struct o2hb_callback *hbcall;
        int ret;
 
@@ -2540,10 +2537,9 @@ int o2hb_register_callback(const char *region_uuid,
 
        down_write(&o2hb_callback_sem);
 
-       list_for_each(iter, &hbcall->list) {
-               tmp = list_entry(iter, struct o2hb_callback_func, hc_item);
-               if (hc->hc_priority < tmp->hc_priority) {
-                       list_add_tail(&hc->hc_item, iter);
+       list_for_each_entry(f, &hbcall->list, hc_item) {
+               if (hc->hc_priority < f->hc_priority) {
+                       list_add_tail(&hc->hc_item, &f->hc_item);
                        break;
                }
        }
index d644dc611425a4b71680b1ecbc76c37a1b0f15cf..2cd2406b41408b61dc0797e2e87e6f29a84506e0 100644 (file)
@@ -543,8 +543,9 @@ static void o2net_set_nn_state(struct o2net_node *nn,
        }
 
        if (was_valid && !valid) {
-               printk(KERN_NOTICE "o2net: No longer connected to "
-                      SC_NODEF_FMT "\n", SC_NODEF_ARGS(old_sc));
+               if (old_sc)
+                       printk(KERN_NOTICE "o2net: No longer connected to "
+                               SC_NODEF_FMT "\n", SC_NODEF_ARGS(old_sc));
                o2net_complete_nodes_nsw(nn);
        }
 
@@ -765,32 +766,32 @@ static struct o2net_msg_handler *
 o2net_handler_tree_lookup(u32 msg_type, u32 key, struct rb_node ***ret_p,
                          struct rb_node **ret_parent)
 {
-        struct rb_node **p = &o2net_handler_tree.rb_node;
-        struct rb_node *parent = NULL;
+       struct rb_node **p = &o2net_handler_tree.rb_node;
+       struct rb_node *parent = NULL;
        struct o2net_msg_handler *nmh, *ret = NULL;
        int cmp;
 
-        while (*p) {
-                parent = *p;
-                nmh = rb_entry(parent, struct o2net_msg_handler, nh_node);
+       while (*p) {
+               parent = *p;
+               nmh = rb_entry(parent, struct o2net_msg_handler, nh_node);
                cmp = o2net_handler_cmp(nmh, msg_type, key);
 
-                if (cmp < 0)
-                        p = &(*p)->rb_left;
-                else if (cmp > 0)
-                        p = &(*p)->rb_right;
-                else {
+               if (cmp < 0)
+                       p = &(*p)->rb_left;
+               else if (cmp > 0)
+                       p = &(*p)->rb_right;
+               else {
                        ret = nmh;
-                        break;
+                       break;
                }
-        }
+       }
 
-        if (ret_p != NULL)
-                *ret_p = p;
-        if (ret_parent != NULL)
-                *ret_parent = parent;
+       if (ret_p != NULL)
+               *ret_p = p;
+       if (ret_parent != NULL)
+               *ret_parent = parent;
 
-        return ret;
+       return ret;
 }
 
 static void o2net_handler_kref_release(struct kref *kref)
@@ -1695,13 +1696,12 @@ static void o2net_start_connect(struct work_struct *work)
                ret = 0;
 
 out:
-       if (ret) {
+       if (ret && sc) {
                printk(KERN_NOTICE "o2net: Connect attempt to " SC_NODEF_FMT
                       " failed with errno %d\n", SC_NODEF_ARGS(sc), ret);
                /* 0 err so that another will be queued and attempted
                 * from set_nn_state */
-               if (sc)
-                       o2net_ensure_shutdown(nn, sc, 0);
+               o2net_ensure_shutdown(nn, sc, 0);
        }
        if (sc)
                sc_put(sc);
@@ -1873,12 +1873,16 @@ static int o2net_accept_one(struct socket *sock)
 
        if (o2nm_this_node() >= node->nd_num) {
                local_node = o2nm_get_node_by_num(o2nm_this_node());
-               printk(KERN_NOTICE "o2net: Unexpected connect attempt seen "
-                      "at node '%s' (%u, %pI4:%d) from node '%s' (%u, "
-                      "%pI4:%d)\n", local_node->nd_name, local_node->nd_num,
-                      &(local_node->nd_ipv4_address),
-                      ntohs(local_node->nd_ipv4_port), node->nd_name,
-                      node->nd_num, &sin.sin_addr.s_addr, ntohs(sin.sin_port));
+               if (local_node)
+                       printk(KERN_NOTICE "o2net: Unexpected connect attempt "
+                                       "seen at node '%s' (%u, %pI4:%d) from "
+                                       "node '%s' (%u, %pI4:%d)\n",
+                                       local_node->nd_name, local_node->nd_num,
+                                       &(local_node->nd_ipv4_address),
+                                       ntohs(local_node->nd_ipv4_port),
+                                       node->nd_name,
+                                       node->nd_num, &sin.sin_addr.s_addr,
+                                       ntohs(sin.sin_port));
                ret = -EINVAL;
                goto out;
        }
index fbec0be6232622ddda0c3ed4ed49c50cc0129386..b46278f9ae446ac1b139bd89c69649c66ea807b9 100644 (file)
@@ -292,7 +292,7 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
        struct dlm_lock *lock = NULL;
        struct dlm_proxy_ast *past = (struct dlm_proxy_ast *) msg->buf;
        char *name;
-       struct list_head *iter, *head=NULL;
+       struct list_head *head = NULL;
        __be64 cookie;
        u32 flags;
        u8 node;
@@ -373,8 +373,7 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
        /* try convert queue for both ast/bast */
        head = &res->converting;
        lock = NULL;
-       list_for_each(iter, head) {
-               lock = list_entry (iter, struct dlm_lock, list);
+       list_for_each_entry(lock, head, list) {
                if (lock->ml.cookie == cookie)
                        goto do_ast;
        }
@@ -385,8 +384,7 @@ int dlm_proxy_ast_handler(struct o2net_msg *msg, u32 len, void *data,
        else
                head = &res->granted;
 
-       list_for_each(iter, head) {
-               lock = list_entry (iter, struct dlm_lock, list);
+       list_for_each_entry(lock, head, list) {
                if (lock->ml.cookie == cookie)
                        goto do_ast;
        }
index de854cca12a2d23dea5652d3dad38461c7dbde13..e0517762fcc014c8973398edfdb05c0db7c98ceb 100644 (file)
@@ -1079,11 +1079,9 @@ static inline int dlm_lock_compatible(int existing, int request)
 static inline int dlm_lock_on_list(struct list_head *head,
                                   struct dlm_lock *lock)
 {
-       struct list_head *iter;
        struct dlm_lock *tmplock;
 
-       list_for_each(iter, head) {
-               tmplock = list_entry(iter, struct dlm_lock, list);
+       list_for_each_entry(tmplock, head, list) {
                if (tmplock == lock)
                        return 1;
        }
index 29a886d1e82c84dd7338380b0ed65a0becd1e3bb..e36d63ff17830bf321a1809d1b81a87827290037 100644 (file)
@@ -123,7 +123,6 @@ static enum dlm_status __dlmconvert_master(struct dlm_ctxt *dlm,
                                           int *kick_thread)
 {
        enum dlm_status status = DLM_NORMAL;
-       struct list_head *iter;
        struct dlm_lock *tmplock=NULL;
 
        assert_spin_locked(&res->spinlock);
@@ -185,16 +184,14 @@ static enum dlm_status __dlmconvert_master(struct dlm_ctxt *dlm,
 
        /* upconvert from here on */
        status = DLM_NORMAL;
-       list_for_each(iter, &res->granted) {
-               tmplock = list_entry(iter, struct dlm_lock, list);
+       list_for_each_entry(tmplock, &res->granted, list) {
                if (tmplock == lock)
                        continue;
                if (!dlm_lock_compatible(tmplock->ml.type, type))
                        goto switch_queues;
        }
 
-       list_for_each(iter, &res->converting) {
-               tmplock = list_entry(iter, struct dlm_lock, list);
+       list_for_each_entry(tmplock, &res->converting, list) {
                if (!dlm_lock_compatible(tmplock->ml.type, type))
                        goto switch_queues;
                /* existing conversion requests take precedence */
@@ -424,8 +421,8 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
        struct dlm_ctxt *dlm = data;
        struct dlm_convert_lock *cnv = (struct dlm_convert_lock *)msg->buf;
        struct dlm_lock_resource *res = NULL;
-       struct list_head *iter;
        struct dlm_lock *lock = NULL;
+       struct dlm_lock *tmp_lock;
        struct dlm_lockstatus *lksb;
        enum dlm_status status = DLM_NORMAL;
        u32 flags;
@@ -471,14 +468,13 @@ int dlm_convert_lock_handler(struct o2net_msg *msg, u32 len, void *data,
                dlm_error(status);
                goto leave;
        }
-       list_for_each(iter, &res->granted) {
-               lock = list_entry(iter, struct dlm_lock, list);
-               if (lock->ml.cookie == cnv->cookie &&
-                   lock->ml.node == cnv->node_idx) {
+       list_for_each_entry(tmp_lock, &res->granted, list) {
+               if (tmp_lock->ml.cookie == cnv->cookie &&
+                   tmp_lock->ml.node == cnv->node_idx) {
+                       lock = tmp_lock;
                        dlm_lock_get(lock);
                        break;
                }
-               lock = NULL;
        }
        spin_unlock(&res->spinlock);
        if (!lock) {
index 0e28e242226d8f69dfc638b8426c7700b8b1ba18..e33cd7a3c5821aaeadca19f6cd37e8d0660fc16f 100644 (file)
@@ -96,7 +96,6 @@ static void __dlm_print_lock(struct dlm_lock *lock)
 
 void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
 {
-       struct list_head *iter2;
        struct dlm_lock *lock;
        char buf[DLM_LOCKID_NAME_MAX];
 
@@ -118,18 +117,15 @@ void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
               res->inflight_locks, atomic_read(&res->asts_reserved));
        dlm_print_lockres_refmap(res);
        printk("  granted queue:\n");
-       list_for_each(iter2, &res->granted) {
-               lock = list_entry(iter2, struct dlm_lock, list);
+       list_for_each_entry(lock, &res->granted, list) {
                __dlm_print_lock(lock);
        }
        printk("  converting queue:\n");
-       list_for_each(iter2, &res->converting) {
-               lock = list_entry(iter2, struct dlm_lock, list);
+       list_for_each_entry(lock, &res->converting, list) {
                __dlm_print_lock(lock);
        }
        printk("  blocked queue:\n");
-       list_for_each(iter2, &res->blocked) {
-               lock = list_entry(iter2, struct dlm_lock, list);
+       list_for_each_entry(lock, &res->blocked, list) {
                __dlm_print_lock(lock);
        }
 }
@@ -446,7 +442,6 @@ static int debug_mle_print(struct dlm_ctxt *dlm, char *buf, int len)
 {
        struct dlm_master_list_entry *mle;
        struct hlist_head *bucket;
-       struct hlist_node *list;
        int i, out = 0;
        unsigned long total = 0, longest = 0, bucket_count = 0;
 
@@ -456,9 +451,7 @@ static int debug_mle_print(struct dlm_ctxt *dlm, char *buf, int len)
        spin_lock(&dlm->master_lock);
        for (i = 0; i < DLM_HASH_BUCKETS; i++) {
                bucket = dlm_master_hash(dlm, i);
-               hlist_for_each(list, bucket) {
-                       mle = hlist_entry(list, struct dlm_master_list_entry,
-                                         master_hash_node);
+               hlist_for_each_entry(mle, bucket, master_hash_node) {
                        ++total;
                        ++bucket_count;
                        if (len - out < 200)
index dbb17c07656ae3ca88c75f02bb4d75100190ffea..8b3382abf840d6939a66fb3b99c389a18354768a 100644 (file)
@@ -193,7 +193,7 @@ struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
                                                     unsigned int hash)
 {
        struct hlist_head *bucket;
-       struct hlist_node *list;
+       struct dlm_lock_resource *res;
 
        mlog(0, "%.*s\n", len, name);
 
@@ -201,9 +201,7 @@ struct dlm_lock_resource * __dlm_lookup_lockres_full(struct dlm_ctxt *dlm,
 
        bucket = dlm_lockres_hash(dlm, hash);
 
-       hlist_for_each(list, bucket) {
-               struct dlm_lock_resource *res = hlist_entry(list,
-                       struct dlm_lock_resource, hash_node);
+       hlist_for_each_entry(res, bucket, hash_node) {
                if (res->lockname.name[0] != name[0])
                        continue;
                if (unlikely(res->lockname.len != len))
@@ -262,22 +260,19 @@ struct dlm_lock_resource * dlm_lookup_lockres(struct dlm_ctxt *dlm,
 
 static struct dlm_ctxt * __dlm_lookup_domain_full(const char *domain, int len)
 {
-       struct dlm_ctxt *tmp = NULL;
-       struct list_head *iter;
+       struct dlm_ctxt *tmp;
 
        assert_spin_locked(&dlm_domain_lock);
 
        /* tmp->name here is always NULL terminated,
         * but domain may not be! */
-       list_for_each(iter, &dlm_domains) {
-               tmp = list_entry (iter, struct dlm_ctxt, list);
+       list_for_each_entry(tmp, &dlm_domains, list) {
                if (strlen(tmp->name) == len &&
                    memcmp(tmp->name, domain, len)==0)
-                       break;
-               tmp = NULL;
+                       return tmp;
        }
 
-       return tmp;
+       return NULL;
 }
 
 /* For null terminated domain strings ONLY */
@@ -366,25 +361,22 @@ static void __dlm_get(struct dlm_ctxt *dlm)
  * you shouldn't trust your pointer. */
 struct dlm_ctxt *dlm_grab(struct dlm_ctxt *dlm)
 {
-       struct list_head *iter;
-       struct dlm_ctxt *target = NULL;
+       struct dlm_ctxt *target;
+       struct dlm_ctxt *ret = NULL;
 
        spin_lock(&dlm_domain_lock);
 
-       list_for_each(iter, &dlm_domains) {
-               target = list_entry (iter, struct dlm_ctxt, list);
-
+       list_for_each_entry(target, &dlm_domains, list) {
                if (target == dlm) {
                        __dlm_get(target);
+                       ret = target;
                        break;
                }
-
-               target = NULL;
        }
 
        spin_unlock(&dlm_domain_lock);
 
-       return target;
+       return ret;
 }
 
 int dlm_domain_fully_joined(struct dlm_ctxt *dlm)
@@ -2296,13 +2288,10 @@ static DECLARE_RWSEM(dlm_callback_sem);
 void dlm_fire_domain_eviction_callbacks(struct dlm_ctxt *dlm,
                                        int node_num)
 {
-       struct list_head *iter;
        struct dlm_eviction_cb *cb;
 
        down_read(&dlm_callback_sem);
-       list_for_each(iter, &dlm->dlm_eviction_callbacks) {
-               cb = list_entry(iter, struct dlm_eviction_cb, ec_item);
-
+       list_for_each_entry(cb, &dlm->dlm_eviction_callbacks, ec_item) {
                cb->ec_func(node_num, cb->ec_data);
        }
        up_read(&dlm_callback_sem);
index 47e67c2d228feff6259aa6d2a47b4b7c7b2ee103..5d32f7511f7423acc4f54b7665796eaf993bfe6b 100644 (file)
@@ -91,19 +91,14 @@ void dlm_destroy_lock_cache(void)
 static int dlm_can_grant_new_lock(struct dlm_lock_resource *res,
                                  struct dlm_lock *lock)
 {
-       struct list_head *iter;
        struct dlm_lock *tmplock;
 
-       list_for_each(iter, &res->granted) {
-               tmplock = list_entry(iter, struct dlm_lock, list);
-
+       list_for_each_entry(tmplock, &res->granted, list) {
                if (!dlm_lock_compatible(tmplock->ml.type, lock->ml.type))
                        return 0;
        }
 
-       list_for_each(iter, &res->converting) {
-               tmplock = list_entry(iter, struct dlm_lock, list);
-
+       list_for_each_entry(tmplock, &res->converting, list) {
                if (!dlm_lock_compatible(tmplock->ml.type, lock->ml.type))
                        return 0;
                if (!dlm_lock_compatible(tmplock->ml.convert_type,
index 33ecbe0e6734a7deaf0c8712934b9eb78fb44197..cf0f103963b1a05192cc124e9976cbc5a318b64b 100644 (file)
@@ -342,16 +342,13 @@ static int dlm_find_mle(struct dlm_ctxt *dlm,
 {
        struct dlm_master_list_entry *tmpmle;
        struct hlist_head *bucket;
-       struct hlist_node *list;
        unsigned int hash;
 
        assert_spin_locked(&dlm->master_lock);
 
        hash = dlm_lockid_hash(name, namelen);
        bucket = dlm_master_hash(dlm, hash);
-       hlist_for_each(list, bucket) {
-               tmpmle = hlist_entry(list, struct dlm_master_list_entry,
-                                    master_hash_node);
+       hlist_for_each_entry(tmpmle, bucket, master_hash_node) {
                if (!dlm_mle_equal(dlm, tmpmle, name, namelen))
                        continue;
                dlm_get_mle(tmpmle);
@@ -3183,7 +3180,7 @@ void dlm_clean_master_list(struct dlm_ctxt *dlm, u8 dead_node)
        struct dlm_master_list_entry *mle;
        struct dlm_lock_resource *res;
        struct hlist_head *bucket;
-       struct hlist_node *list;
+       struct hlist_node *tmp;
        unsigned int i;
 
        mlog(0, "dlm=%s, dead node=%u\n", dlm->name, dead_node);
@@ -3194,10 +3191,7 @@ top:
        spin_lock(&dlm->master_lock);
        for (i = 0; i < DLM_HASH_BUCKETS; i++) {
                bucket = dlm_master_hash(dlm, i);
-               hlist_for_each(list, bucket) {
-                       mle = hlist_entry(list, struct dlm_master_list_entry,
-                                         master_hash_node);
-
+               hlist_for_each_entry_safe(mle, tmp, bucket, master_hash_node) {
                        BUG_ON(mle->type != DLM_MLE_BLOCK &&
                               mle->type != DLM_MLE_MASTER &&
                               mle->type != DLM_MLE_MIGRATION);
@@ -3378,7 +3372,7 @@ void dlm_force_free_mles(struct dlm_ctxt *dlm)
        int i;
        struct hlist_head *bucket;
        struct dlm_master_list_entry *mle;
-       struct hlist_node *tmp, *list;
+       struct hlist_node *tmp;
 
        /*
         * We notified all other nodes that we are exiting the domain and
@@ -3394,9 +3388,7 @@ void dlm_force_free_mles(struct dlm_ctxt *dlm)
 
        for (i = 0; i < DLM_HASH_BUCKETS; i++) {
                bucket = dlm_master_hash(dlm, i);
-               hlist_for_each_safe(list, tmp, bucket) {
-                       mle = hlist_entry(list, struct dlm_master_list_entry,
-                                         master_hash_node);
+               hlist_for_each_entry_safe(mle, tmp, bucket, master_hash_node) {
                        if (mle->type != DLM_MLE_BLOCK) {
                                mlog(ML_ERROR, "bad mle: %p\n", mle);
                                dlm_print_one_mle(mle);
index 773bd32bfd8c8bb56bcf5f7ee7880cd65bbe8f26..0b5adca1b1787bbc09284255417979c0c13f3f32 100644 (file)
@@ -787,6 +787,7 @@ static int dlm_request_all_locks(struct dlm_ctxt *dlm, u8 request_from,
 {
        struct dlm_lock_request lr;
        int ret;
+       int status;
 
        mlog(0, "\n");
 
@@ -800,13 +801,15 @@ static int dlm_request_all_locks(struct dlm_ctxt *dlm, u8 request_from,
 
        // send message
        ret = o2net_send_message(DLM_LOCK_REQUEST_MSG, dlm->key,
-                                &lr, sizeof(lr), request_from, NULL);
+                                &lr, sizeof(lr), request_from, &status);
 
        /* negative status is handled by caller */
        if (ret < 0)
                mlog(ML_ERROR, "%s: Error %d send LOCK_REQUEST to node %u "
                     "to recover dead node %u\n", dlm->name, ret,
                     request_from, dead_node);
+       else
+               ret = status;
        // return from here, then
        // sleep until all received or error
        return ret;
@@ -2328,6 +2331,14 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
                        } else if (res->owner == dlm->node_num) {
                                dlm_free_dead_locks(dlm, res, dead_node);
                                __dlm_lockres_calc_usage(dlm, res);
+                       } else if (res->owner == DLM_LOCK_RES_OWNER_UNKNOWN) {
+                               if (test_bit(dead_node, res->refmap)) {
+                                       mlog(0, "%s:%.*s: dead node %u had a ref, but had "
+                                               "no locks and had not purged before dying\n",
+                                               dlm->name, res->lockname.len,
+                                               res->lockname.name, dead_node);
+                                       dlm_lockres_clear_refmap_bit(dlm, res, dead_node);
+                               }
                        }
                        spin_unlock(&res->spinlock);
                }
index e73c833fc2a1a97cac35903f0439115cef813c69..9db869de829d0ebcf35ff598c3ee4b7541934f26 100644 (file)
@@ -286,8 +286,6 @@ static void dlm_shuffle_lists(struct dlm_ctxt *dlm,
                              struct dlm_lock_resource *res)
 {
        struct dlm_lock *lock, *target;
-       struct list_head *iter;
-       struct list_head *head;
        int can_grant = 1;
 
        /*
@@ -314,9 +312,7 @@ converting:
                     dlm->name, res->lockname.len, res->lockname.name);
                BUG();
        }
-       head = &res->granted;
-       list_for_each(iter, head) {
-               lock = list_entry(iter, struct dlm_lock, list);
+       list_for_each_entry(lock, &res->granted, list) {
                if (lock==target)
                        continue;
                if (!dlm_lock_compatible(lock->ml.type,
@@ -333,9 +329,8 @@ converting:
                                        target->ml.convert_type;
                }
        }
-       head = &res->converting;
-       list_for_each(iter, head) {
-               lock = list_entry(iter, struct dlm_lock, list);
+
+       list_for_each_entry(lock, &res->converting, list) {
                if (lock==target)
                        continue;
                if (!dlm_lock_compatible(lock->ml.type,
@@ -384,9 +379,7 @@ blocked:
                goto leave;
        target = list_entry(res->blocked.next, struct dlm_lock, list);
 
-       head = &res->granted;
-       list_for_each(iter, head) {
-               lock = list_entry(iter, struct dlm_lock, list);
+       list_for_each_entry(lock, &res->granted, list) {
                if (lock==target)
                        continue;
                if (!dlm_lock_compatible(lock->ml.type, target->ml.type)) {
@@ -400,9 +393,7 @@ blocked:
                }
        }
 
-       head = &res->converting;
-       list_for_each(iter, head) {
-               lock = list_entry(iter, struct dlm_lock, list);
+       list_for_each_entry(lock, &res->converting, list) {
                if (lock==target)
                        continue;
                if (!dlm_lock_compatible(lock->ml.type, target->ml.type)) {
index 850aa7e875377b76eaae054b675367aea157c13c..5698b52cf5c984c9e2e7bd21e68a76191dcc5abe 100644 (file)
@@ -388,7 +388,6 @@ int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
        struct dlm_ctxt *dlm = data;
        struct dlm_unlock_lock *unlock = (struct dlm_unlock_lock *)msg->buf;
        struct dlm_lock_resource *res = NULL;
-       struct list_head *iter;
        struct dlm_lock *lock = NULL;
        enum dlm_status status = DLM_NORMAL;
        int found = 0, i;
@@ -458,8 +457,7 @@ int dlm_unlock_lock_handler(struct o2net_msg *msg, u32 len, void *data,
        }
 
        for (i=0; i<3; i++) {
-               list_for_each(iter, queue) {
-                       lock = list_entry(iter, struct dlm_lock, list);
+               list_for_each_entry(lock, queue, list) {
                        if (lock->ml.cookie == unlock->cookie &&
                            lock->ml.node == unlock->node_idx) {
                                dlm_lock_get(lock);
index 12bafb7265ceb8d2a13e8a1fb3aa86a73149a43e..efa2b3d339e3146e91dafcc6359f1db8f14fd96e 100644 (file)
@@ -401,11 +401,8 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
 {
        struct inode *inode = new_inode(sb);
        umode_t mode = S_IFDIR | 0755;
-       struct dlmfs_inode_private *ip;
 
        if (inode) {
-               ip = DLMFS_I(inode);
-
                inode->i_ino = get_next_ino();
                inode_init_owner(inode, NULL, mode);
                inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
index 2487116d0d3312981834aa3667fd708dc7aa05ab..767370b656ca67af7ba8d2ed81783752c83742d2 100644 (file)
@@ -781,7 +781,6 @@ int ocfs2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        cpos = map_start >> osb->s_clustersize_bits;
        mapping_end = ocfs2_clusters_for_bytes(inode->i_sb,
                                               map_start + map_len);
-       mapping_end -= cpos;
        is_last = 0;
        while (cpos < mapping_end && !is_last) {
                u32 fe_flags;
@@ -852,20 +851,20 @@ int ocfs2_seek_data_hole_offset(struct file *file, loff_t *offset, int whence)
 
        down_read(&OCFS2_I(inode)->ip_alloc_sem);
 
-       if (*offset >= inode->i_size) {
+       if (*offset >= i_size_read(inode)) {
                ret = -ENXIO;
                goto out_unlock;
        }
 
        if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) {
                if (whence == SEEK_HOLE)
-                       *offset = inode->i_size;
+                       *offset = i_size_read(inode);
                goto out_unlock;
        }
 
        clen = 0;
        cpos = *offset >> cs_bits;
-       cend = ocfs2_clusters_for_bytes(inode->i_sb, inode->i_size);
+       cend = ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode));
 
        while (cpos < cend && !is_last) {
                ret = ocfs2_get_clusters_nocache(inode, di_bh, cpos, &hole_size,
@@ -904,8 +903,8 @@ int ocfs2_seek_data_hole_offset(struct file *file, loff_t *offset, int whence)
                extlen = clen;
                extlen <<=  cs_bits;
 
-               if ((extoff + extlen) > inode->i_size)
-                       extlen = inode->i_size - extoff;
+               if ((extoff + extlen) > i_size_read(inode))
+                       extlen = i_size_read(inode) - extoff;
                extoff += extlen;
                if (extoff > *offset)
                        *offset = extoff;
index 3261d71319eeb27d3a569aeccf4f3f6e27a95496..d71903c6068b94f37836854762691a7a1c9d9f12 100644 (file)
@@ -671,11 +671,7 @@ restarted_transaction:
                } else {
                        BUG_ON(why != RESTART_TRANS);
 
-                       /* TODO: This can be more intelligent. */
-                       credits = ocfs2_calc_extend_credits(osb->sb,
-                                                           &fe->id2.i_list,
-                                                           clusters_to_add);
-                       status = ocfs2_extend_trans(handle, credits);
+                       status = ocfs2_allocate_extend_trans(handle, 1);
                        if (status < 0) {
                                /* handle still has to be committed at
                                 * this point. */
@@ -1800,6 +1796,7 @@ static int ocfs2_remove_inode_range(struct inode *inode,
        ocfs2_truncate_cluster_pages(inode, byte_start, byte_len);
 
 out:
+       ocfs2_free_path(path);
        ocfs2_schedule_truncate_log_flush(osb, 1);
        ocfs2_run_deallocs(osb, &dealloc);
 
@@ -2245,7 +2242,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
                file->f_path.dentry->d_name.name,
                (unsigned int)nr_segs);
 
-       if (iocb->ki_left == 0)
+       if (iocb->ki_nbytes == 0)
                return 0;
 
        appending = file->f_flags & O_APPEND ? 1 : 0;
@@ -2296,7 +2293,7 @@ relock:
 
        can_do_direct = direct_io;
        ret = ocfs2_prepare_inode_for_write(file, ppos,
-                                           iocb->ki_left, appending,
+                                           iocb->ki_nbytes, appending,
                                            &can_do_direct, &has_refcount);
        if (ret < 0) {
                mlog_errno(ret);
@@ -2304,7 +2301,7 @@ relock:
        }
 
        if (direct_io && !is_sync_kiocb(iocb))
-               unaligned_dio = ocfs2_is_io_unaligned(inode, iocb->ki_left,
+               unaligned_dio = ocfs2_is_io_unaligned(inode, iocb->ki_nbytes,
                                                      *ppos);
 
        /*
index 0c60ef2d8056ea4412e1338a3580f03acc72210a..fa32ce9b455df9ad7ff06e812ad79eb8f42a4e4b 100644 (file)
@@ -303,7 +303,7 @@ int ocfs2_info_handle_journal_size(struct inode *inode,
        if (o2info_from_user(oij, req))
                goto bail;
 
-       oij.ij_journal_size = osb->journal->j_inode->i_size;
+       oij.ij_journal_size = i_size_read(osb->journal->j_inode);
 
        o2info_set_request_filled(&oij.ij_req);
 
index 242170d83971a9bef488197111154db6c75cba0b..44fc3e530c3d82c5a0d42d838461365cc53d72f3 100644 (file)
@@ -455,6 +455,41 @@ bail:
        return status;
 }
 
+/*
+ * If we have fewer than thresh credits, extend by OCFS2_MAX_TRANS_DATA.
+ * If that fails, restart the transaction & regain write access for the
+ * buffer head which is used for metadata modifications.
+ * Taken from Ext4: extend_or_restart_transaction()
+ */
+int ocfs2_allocate_extend_trans(handle_t *handle, int thresh)
+{
+       int status, old_nblks;
+
+       BUG_ON(!handle);
+
+       old_nblks = handle->h_buffer_credits;
+       trace_ocfs2_allocate_extend_trans(old_nblks, thresh);
+
+       if (old_nblks < thresh)
+               return 0;
+
+       status = jbd2_journal_extend(handle, OCFS2_MAX_TRANS_DATA);
+       if (status < 0) {
+               mlog_errno(status);
+               goto bail;
+       }
+
+       if (status > 0) {
+               status = jbd2_journal_restart(handle, OCFS2_MAX_TRANS_DATA);
+               if (status < 0)
+                       mlog_errno(status);
+       }
+
+bail:
+       return status;
+}
+
+
 struct ocfs2_triggers {
        struct jbd2_buffer_trigger_type ot_triggers;
        int                             ot_offset;
@@ -801,14 +836,14 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
        inode_lock = 1;
        di = (struct ocfs2_dinode *)bh->b_data;
 
-       if (inode->i_size <  OCFS2_MIN_JOURNAL_SIZE) {
+       if (i_size_read(inode) <  OCFS2_MIN_JOURNAL_SIZE) {
                mlog(ML_ERROR, "Journal file size (%lld) is too small!\n",
-                    inode->i_size);
+                    i_size_read(inode));
                status = -EINVAL;
                goto done;
        }
 
-       trace_ocfs2_journal_init(inode->i_size,
+       trace_ocfs2_journal_init(i_size_read(inode),
                                 (unsigned long long)inode->i_blocks,
                                 OCFS2_I(inode)->ip_clusters);
 
@@ -1096,7 +1131,7 @@ static int ocfs2_force_read_journal(struct inode *inode)
 
        memset(bhs, 0, sizeof(struct buffer_head *) * CONCURRENT_JOURNAL_FILL);
 
-       num_blocks = ocfs2_blocks_for_bytes(inode->i_sb, inode->i_size);
+       num_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode));
        v_blkno = 0;
        while (v_blkno < num_blocks) {
                status = ocfs2_extent_map_get_blocks(inode, v_blkno,
index 0a992737dcaf8e76d0b57b18dcb21b57d5ed6479..0b479bab36713ec3ef147c314fe2473b08ed1d9e 100644 (file)
@@ -258,6 +258,17 @@ handle_t               *ocfs2_start_trans(struct ocfs2_super *osb,
 int                         ocfs2_commit_trans(struct ocfs2_super *osb,
                                                handle_t *handle);
 int                         ocfs2_extend_trans(handle_t *handle, int nblocks);
+int                         ocfs2_allocate_extend_trans(handle_t *handle,
+                                               int thresh);
+
+/*
+ * Define an arbitrary limit for the amount of data we will anticipate
+ * writing to any given transaction.  For unbounded transactions such as
+ * fallocate(2) we can write more than this, but we always
+ * start off at the maximum transaction size and grow the transaction
+ * optimistically as we go.
+ */
+#define OCFS2_MAX_TRANS_DATA   64U
 
 /*
  * Create access is for when we get a newly created buffer and we're
index aebeacd807c3b9505c5e9bb859008469985588e2..cd5496b7a0a39d4ab7658b59a8480a1bb5d6d1eb 100644 (file)
@@ -1082,7 +1082,7 @@ static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb,
        }
 
 retry_enospc:
-       (*ac)->ac_bits_wanted = osb->local_alloc_default_bits;
+       (*ac)->ac_bits_wanted = osb->local_alloc_bits;
        status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac);
        if (status == -ENOSPC) {
                if (ocfs2_recalc_la_window(osb, OCFS2_LA_EVENT_ENOSPC) ==
@@ -1154,7 +1154,7 @@ retry_enospc:
                    OCFS2_LA_DISABLED)
                        goto bail;
 
-               ac->ac_bits_wanted = osb->local_alloc_default_bits;
+               ac->ac_bits_wanted = osb->local_alloc_bits;
                status = ocfs2_claim_clusters(handle, ac,
                                              osb->local_alloc_bits,
                                              &cluster_off,
index 452068b45749a7545002543f0b0b450b52612dec..3d3f3c83065ca3ed51d9dac690bac2e2012a36f9 100644 (file)
@@ -152,6 +152,7 @@ static int __ocfs2_move_extent(handle_t *handle,
        }
 
 out:
+       ocfs2_free_path(path);
        return ret;
 }
 
@@ -845,7 +846,7 @@ static int __ocfs2_move_extents_range(struct buffer_head *di_bh,
        struct ocfs2_move_extents *range = context->range;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
 
-       if ((inode->i_size == 0) || (range->me_len == 0))
+       if ((i_size_read(inode) == 0) || (range->me_len == 0))
                return 0;
 
        if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL)
index 3b481f490633af2f483afd1817fe8ad538908b6a..1b60c62aa9d6fa62940c0a9b8f9889943604170e 100644 (file)
@@ -2579,6 +2579,8 @@ DEFINE_OCFS2_INT_INT_EVENT(ocfs2_extend_trans);
 
 DEFINE_OCFS2_INT_EVENT(ocfs2_extend_trans_restart);
 
+DEFINE_OCFS2_INT_INT_EVENT(ocfs2_allocate_extend_trans);
+
 DEFINE_OCFS2_ULL_ULL_UINT_UINT_EVENT(ocfs2_journal_access);
 
 DEFINE_OCFS2_ULL_EVENT(ocfs2_journal_dirty);
index 332a281f217ed021dee419722bd4dd5ca83de9a9..aaa50611ec66c27f2b6cd9a67a039a05e0253787 100644 (file)
@@ -234,7 +234,7 @@ ssize_t ocfs2_quota_write(struct super_block *sb, int type,
                len = sb->s_blocksize - OCFS2_QBLK_RESERVED_SPACE - offset;
        }
 
-       if (gqinode->i_size < off + len) {
+       if (i_size_read(gqinode) < off + len) {
                loff_t rounded_end =
                                ocfs2_align_bytes_to_blocks(sb, off + len);
 
@@ -778,8 +778,8 @@ static int ocfs2_acquire_dquot(struct dquot *dquot)
                 */
                WARN_ON(journal_current_handle());
                status = ocfs2_extend_no_holes(gqinode, NULL,
-                       gqinode->i_size + (need_alloc << sb->s_blocksize_bits),
-                       gqinode->i_size);
+                       i_size_read(gqinode) + (need_alloc << sb->s_blocksize_bits),
+                       i_size_read(gqinode));
                if (status < 0)
                        goto out_dq;
        }
index 27fe7ee4874cbac39381b90694e0ce7c0c11ce66..2e4344be3b962b40a6cd4e5743a87f088b7abe63 100644 (file)
@@ -982,14 +982,14 @@ static struct ocfs2_quota_chunk *ocfs2_local_quota_add_chunk(
 
        /* We are protected by dqio_sem so no locking needed */
        status = ocfs2_extend_no_holes(lqinode, NULL,
-                                      lqinode->i_size + 2 * sb->s_blocksize,
-                                      lqinode->i_size);
+                                      i_size_read(lqinode) + 2 * sb->s_blocksize,
+                                      i_size_read(lqinode));
        if (status < 0) {
                mlog_errno(status);
                goto out;
        }
        status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh,
-                                         lqinode->i_size + 2 * sb->s_blocksize);
+                                         i_size_read(lqinode) + 2 * sb->s_blocksize);
        if (status < 0) {
                mlog_errno(status);
                goto out;
@@ -1125,14 +1125,14 @@ static struct ocfs2_quota_chunk *ocfs2_extend_local_quota_file(
 
        /* We are protected by dqio_sem so no locking needed */
        status = ocfs2_extend_no_holes(lqinode, NULL,
-                                      lqinode->i_size + sb->s_blocksize,
-                                      lqinode->i_size);
+                                      i_size_read(lqinode) + sb->s_blocksize,
+                                      i_size_read(lqinode));
        if (status < 0) {
                mlog_errno(status);
                goto out;
        }
        status = ocfs2_simple_size_update(lqinode, oinfo->dqi_lqi_bh,
-                                         lqinode->i_size + sb->s_blocksize);
+                                         i_size_read(lqinode) + sb->s_blocksize);
        if (status < 0) {
                mlog_errno(status);
                goto out;
index a70d604593b61c0ffbce761a92b1207148f3b346..bf4dfc14bb2c7cca75b618de73bfcaf656103ff2 100644 (file)
@@ -3854,7 +3854,10 @@ static int ocfs2_attach_refcount_tree(struct inode *inode,
        while (cpos < clusters) {
                ret = ocfs2_get_clusters(inode, cpos, &p_cluster,
                                         &num_clusters, &ext_flags);
-
+               if (ret) {
+                       mlog_errno(ret);
+                       goto unlock;
+               }
                if (p_cluster && !(ext_flags & OCFS2_EXT_REFCOUNTED)) {
                        ret = ocfs2_add_refcount_flag(inode, &di_et,
                                                      &ref_tree->rf_ci,
@@ -4025,7 +4028,10 @@ static int ocfs2_duplicate_extent_list(struct inode *s_inode,
        while (cpos < clusters) {
                ret = ocfs2_get_clusters(s_inode, cpos, &p_cluster,
                                         &num_clusters, &ext_flags);
-
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
                if (p_cluster) {
                        ret = ocfs2_add_refcounted_extent(t_inode, &et,
                                                          ref_ci, ref_root_bh,
index 317ef0abccbbd22bf320c31ddc0c99ba9f4aa713..6ce0686eab7202b29cd9f29a39e6692b8a1d618a 100644 (file)
@@ -3505,7 +3505,7 @@ int ocfs2_xattr_set(struct inode *inode,
        int ret, credits, ref_meta = 0, ref_credits = 0;
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct inode *tl_inode = osb->osb_tl_inode;
-       struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, };
+       struct ocfs2_xattr_set_ctxt ctxt = { NULL, NULL, NULL, };
        struct ocfs2_refcount_tree *ref_tree = NULL;
 
        struct ocfs2_xattr_info xi = {
@@ -3609,13 +3609,14 @@ int ocfs2_xattr_set(struct inode *inode,
        if (IS_ERR(ctxt.handle)) {
                ret = PTR_ERR(ctxt.handle);
                mlog_errno(ret);
-               goto cleanup;
+               goto out_free_ac;
        }
 
        ret = __ocfs2_xattr_set_handle(inode, di, &xi, &xis, &xbs, &ctxt);
 
        ocfs2_commit_trans(osb, ctxt.handle);
 
+out_free_ac:
        if (ctxt.data_ac)
                ocfs2_free_alloc_context(ctxt.data_ac);
        if (ctxt.meta_ac)
@@ -5881,6 +5882,10 @@ static int ocfs2_xattr_value_attach_refcount(struct inode *inode,
        while (cpos < clusters) {
                ret = ocfs2_xattr_get_clusters(inode, cpos, &p_cluster,
                                               &num_clusters, el, &ext_flags);
+               if (ret) {
+                       mlog_errno(ret);
+                       break;
+               }
 
                cpos += num_clusters;
                if ((ext_flags & OCFS2_EXT_REFCOUNTED))
@@ -6797,7 +6802,7 @@ out:
        if (ret) {
                if (*meta_ac) {
                        ocfs2_free_alloc_context(*meta_ac);
-                       meta_ac = NULL;
+                       *meta_ac = NULL;
                }
        }
 
index e0d9b3e722bd41f91cf4b58f76aa1f34e2684149..54d57d6ba68dd5b91df6cbc9269e1ccf3c05a950 100644 (file)
@@ -311,7 +311,7 @@ static void omfs_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);
+               truncate_pagecache(inode, inode->i_size);
                omfs_truncate(inode);
        }
 }
index 2a731b0d08bc456af047ad58ce68c6823f7b1972..d420331ca32a20b20b00c1da468a9af516e6a037 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -744,14 +744,24 @@ cleanup_file:
 
 /**
  * finish_open - finish opening a file
- * @od: opaque open data
+ * @file: file pointer
  * @dentry: pointer to dentry
  * @open: open callback
+ * @opened: state of open
  *
  * This can be used to finish opening a file passed to i_op->atomic_open().
  *
  * If the open callback is set to NULL, then the standard f_op->open()
  * filesystem callback is substituted.
+ *
+ * NB: the dentry reference is _not_ consumed.  If, for example, the dentry is
+ * the return value of d_splice_alias(), then the caller needs to perform dput()
+ * on it after finish_open().
+ *
+ * On successful return @file is a fully instantiated open file.  After this, if
+ * an error occurs in ->atomic_open(), it needs to clean up with fput().
+ *
+ * Returns zero on success or -errno if the open failed.
  */
 int finish_open(struct file *file, struct dentry *dentry,
                int (*open)(struct inode *, struct file *),
@@ -772,11 +782,16 @@ EXPORT_SYMBOL(finish_open);
 /**
  * finish_no_open - finish ->atomic_open() without opening the file
  *
- * @od: opaque open data
+ * @file: file pointer
  * @dentry: dentry or NULL (as returned from ->lookup())
  *
  * This can be used to set the result of a successful lookup in ->atomic_open().
- * The filesystem's atomic_open() method shall return NULL after calling this.
+ *
+ * NB: unlike finish_open() this function does consume the dentry reference and
+ * the caller need not dput() it.
+ *
+ * Returns "1" which must be the return value of ->atomic_open() after having
+ * called this function.
  */
 int finish_no_open(struct file *file, struct dentry *dentry)
 {
index 0ff80f9b930f7226124e670c2814d7f4618d4532..985ea881b5bc489aa7ae0657e23fbe23d650d844 100644 (file)
@@ -286,7 +286,7 @@ int proc_fd_permission(struct inode *inode, int mask)
        int rv = generic_permission(inode, mask);
        if (rv == 0)
                return 0;
-       if (task_pid(current) == proc_pid(inode))
+       if (task_tgid(current) == proc_pid(inode))
                rv = 0;
        return rv;
 }
index 5aa847a603c0d1325c31d1b1e968a926fa170cb8..59d85d608898354169520fb26209789b27888978 100644 (file)
@@ -132,13 +132,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
                K(i.freeswap),
                K(global_page_state(NR_FILE_DIRTY)),
                K(global_page_state(NR_WRITEBACK)),
-#ifdef CONFIG_TRANSPARENT_HUGEPAGE
-               K(global_page_state(NR_ANON_PAGES)
-                 + global_page_state(NR_ANON_TRANSPARENT_HUGEPAGES) *
-                 HPAGE_PMD_NR),
-#else
                K(global_page_state(NR_ANON_PAGES)),
-#endif
                K(global_page_state(NR_FILE_MAPPED)),
                K(global_page_state(NR_SHMEM)),
                K(global_page_state(NR_SLAB_RECLAIMABLE) +
index 107d026f5d6e0cbebc068fce65f201f167c425c5..7366e9d63cee7d8658e9fed949a2fe7b22519c6f 100644 (file)
@@ -740,6 +740,9 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma,
                ptent = pte_file_clear_soft_dirty(ptent);
        }
 
+       if (vma->vm_flags & VM_SOFTDIRTY)
+               vma->vm_flags &= ~VM_SOFTDIRTY;
+
        set_pte_at(vma->vm_mm, addr, pte, ptent);
 #endif
 }
@@ -949,13 +952,15 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
                if (is_migration_entry(entry))
                        page = migration_entry_to_page(entry);
        } else {
-               *pme = make_pme(PM_NOT_PRESENT(pm->v2));
+               if (vma->vm_flags & VM_SOFTDIRTY)
+                       flags2 |= __PM_SOFT_DIRTY;
+               *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2));
                return;
        }
 
        if (page && !PageAnon(page))
                flags |= PM_FILE;
-       if (pte_soft_dirty(pte))
+       if ((vma->vm_flags & VM_SOFTDIRTY) || pte_soft_dirty(pte))
                flags2 |= __PM_SOFT_DIRTY;
 
        *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags);
@@ -974,7 +979,7 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *p
                *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset)
                                | PM_STATUS2(pm->v2, pmd_flags2) | PM_PRESENT);
        else
-               *pme = make_pme(PM_NOT_PRESENT(pm->v2));
+               *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, pmd_flags2));
 }
 #else
 static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
@@ -997,7 +1002,11 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
        if (vma && pmd_trans_huge_lock(pmd, vma) == 1) {
                int pmd_flags2;
 
-               pmd_flags2 = (pmd_soft_dirty(*pmd) ? __PM_SOFT_DIRTY : 0);
+               if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(*pmd))
+                       pmd_flags2 = __PM_SOFT_DIRTY;
+               else
+                       pmd_flags2 = 0;
+
                for (; addr != end; addr += PAGE_SIZE) {
                        unsigned long offset;
 
@@ -1015,12 +1024,17 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
        if (pmd_trans_unstable(pmd))
                return 0;
        for (; addr != end; addr += PAGE_SIZE) {
+               int flags2;
 
                /* check to see if we've left 'vma' behind
                 * and need a new, higher one */
                if (vma && (addr >= vma->vm_end)) {
                        vma = find_vma(walk->mm, addr);
-                       pme = make_pme(PM_NOT_PRESENT(pm->v2));
+                       if (vma && (vma->vm_flags & VM_SOFTDIRTY))
+                               flags2 = __PM_SOFT_DIRTY;
+                       else
+                               flags2 = 0;
+                       pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2));
                }
 
                /* check that 'vma' actually covers this address,
@@ -1044,13 +1058,15 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
 
 #ifdef CONFIG_HUGETLB_PAGE
 static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm,
-                                       pte_t pte, int offset)
+                                       pte_t pte, int offset, int flags2)
 {
        if (pte_present(pte))
-               *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset)
-                               | PM_STATUS2(pm->v2, 0) | PM_PRESENT);
+               *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset)        |
+                               PM_STATUS2(pm->v2, flags2)              |
+                               PM_PRESENT);
        else
-               *pme = make_pme(PM_NOT_PRESENT(pm->v2));
+               *pme = make_pme(PM_NOT_PRESENT(pm->v2)                  |
+                               PM_STATUS2(pm->v2, flags2));
 }
 
 /* This function walks within one hugetlb entry in the single call */
@@ -1059,12 +1075,22 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask,
                                 struct mm_walk *walk)
 {
        struct pagemapread *pm = walk->private;
+       struct vm_area_struct *vma;
        int err = 0;
+       int flags2;
        pagemap_entry_t pme;
 
+       vma = find_vma(walk->mm, addr);
+       WARN_ON_ONCE(!vma);
+
+       if (vma && (vma->vm_flags & VM_SOFTDIRTY))
+               flags2 = __PM_SOFT_DIRTY;
+       else
+               flags2 = 0;
+
        for (; addr != end; addr += PAGE_SIZE) {
                int offset = (addr & ~hmask) >> PAGE_SHIFT;
-               huge_pte_to_pagemap_entry(&pme, pm, *pte, offset);
+               huge_pte_to_pagemap_entry(&pme, pm, *pte, offset, flags2);
                err = add_to_pagemap(addr, &pme, pm);
                if (err)
                        return err;
@@ -1376,8 +1402,10 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid)
        walk.mm = mm;
 
        pol = get_vma_policy(task, vma, vma->vm_start);
-       mpol_to_str(buffer, sizeof(buffer), pol);
+       n = mpol_to_str(buffer, sizeof(buffer), pol);
        mpol_cond_put(pol);
+       if (n < 0)
+               return n;
 
        seq_printf(m, "%08lx %s", vma->vm_start, buffer);
 
index a1a16eb97c7bd141c7a68419b44769ebea35c854..9100d695988690e0ae7e3263ad2502aa43d94e8c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/crash_dump.h>
 #include <linux/list.h>
 #include <linux/vmalloc.h>
+#include <linux/pagemap.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include "internal.h"
@@ -123,11 +124,65 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
        return read;
 }
 
+/*
+ * Architectures may override this function to allocate ELF header in 2nd kernel
+ */
+int __weak elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
+{
+       return 0;
+}
+
+/*
+ * Architectures may override this function to free header
+ */
+void __weak elfcorehdr_free(unsigned long long addr)
+{}
+
+/*
+ * Architectures may override this function to read from ELF header
+ */
+ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos)
+{
+       return read_from_oldmem(buf, count, ppos, 0);
+}
+
+/*
+ * Architectures may override this function to read from notes sections
+ */
+ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos)
+{
+       return read_from_oldmem(buf, count, ppos, 0);
+}
+
+/*
+ * Architectures may override this function to map oldmem
+ */
+int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma,
+                                 unsigned long from, unsigned long pfn,
+                                 unsigned long size, pgprot_t prot)
+{
+       return remap_pfn_range(vma, from, pfn, size, prot);
+}
+
+/*
+ * Copy to either kernel or user space
+ */
+static int copy_to(void *target, void *src, size_t size, int userbuf)
+{
+       if (userbuf) {
+               if (copy_to_user((char __user *) target, src, size))
+                       return -EFAULT;
+       } else {
+               memcpy(target, src, size);
+       }
+       return 0;
+}
+
 /* Read from the ELF header and then the crash dump. On error, negative value is
  * returned otherwise number of bytes read are returned.
  */
-static ssize_t read_vmcore(struct file *file, char __user *buffer,
-                               size_t buflen, loff_t *fpos)
+static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
+                            int userbuf)
 {
        ssize_t acc = 0, tmp;
        size_t tsz;
@@ -144,7 +199,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
        /* Read ELF core header */
        if (*fpos < elfcorebuf_sz) {
                tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
-               if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
+               if (copy_to(buffer, elfcorebuf + *fpos, tsz, userbuf))
                        return -EFAULT;
                buflen -= tsz;
                *fpos += tsz;
@@ -162,7 +217,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
 
                tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
                kaddr = elfnotes_buf + *fpos - elfcorebuf_sz;
-               if (copy_to_user(buffer, kaddr, tsz))
+               if (copy_to(buffer, kaddr, tsz, userbuf))
                        return -EFAULT;
                buflen -= tsz;
                *fpos += tsz;
@@ -178,7 +233,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
                if (*fpos < m->offset + m->size) {
                        tsz = min_t(size_t, m->offset + m->size - *fpos, buflen);
                        start = m->paddr + *fpos - m->offset;
-                       tmp = read_from_oldmem(buffer, tsz, &start, 1);
+                       tmp = read_from_oldmem(buffer, tsz, &start, userbuf);
                        if (tmp < 0)
                                return tmp;
                        buflen -= tsz;
@@ -195,6 +250,55 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
        return acc;
 }
 
+static ssize_t read_vmcore(struct file *file, char __user *buffer,
+                          size_t buflen, loff_t *fpos)
+{
+       return __read_vmcore((__force char *) buffer, buflen, fpos, 1);
+}
+
+/*
+ * The vmcore fault handler uses the page cache and fills data using the
+ * standard __vmcore_read() function.
+ *
+ * On s390 the fault handler is used for memory regions that can't be mapped
+ * directly with remap_pfn_range().
+ */
+static int mmap_vmcore_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+#ifdef CONFIG_S390
+       struct address_space *mapping = vma->vm_file->f_mapping;
+       pgoff_t index = vmf->pgoff;
+       struct page *page;
+       loff_t offset;
+       char *buf;
+       int rc;
+
+       page = find_or_create_page(mapping, index, GFP_KERNEL);
+       if (!page)
+               return VM_FAULT_OOM;
+       if (!PageUptodate(page)) {
+               offset = (loff_t) index << PAGE_CACHE_SHIFT;
+               buf = __va((page_to_pfn(page) << PAGE_SHIFT));
+               rc = __read_vmcore(buf, PAGE_SIZE, &offset, 0);
+               if (rc < 0) {
+                       unlock_page(page);
+                       page_cache_release(page);
+                       return (rc == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS;
+               }
+               SetPageUptodate(page);
+       }
+       unlock_page(page);
+       vmf->page = page;
+       return 0;
+#else
+       return VM_FAULT_SIGBUS;
+#endif
+}
+
+static const struct vm_operations_struct vmcore_mmap_ops = {
+       .fault = mmap_vmcore_fault,
+};
+
 /**
  * alloc_elfnotes_buf - allocate buffer for ELF note segment in
  *                      vmalloc memory
@@ -223,7 +327,7 @@ static inline char *alloc_elfnotes_buf(size_t notes_sz)
  * regions in the 1st kernel pointed to by PT_LOAD entries) into
  * virtually contiguous user-space in ELF layout.
  */
-#if defined(CONFIG_MMU) && !defined(CONFIG_S390)
+#ifdef CONFIG_MMU
 static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
 {
        size_t size = vma->vm_end - vma->vm_start;
@@ -241,6 +345,7 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
 
        vma->vm_flags &= ~(VM_MAYWRITE | VM_MAYEXEC);
        vma->vm_flags |= VM_MIXEDMAP;
+       vma->vm_ops = &vmcore_mmap_ops;
 
        len = 0;
 
@@ -282,9 +387,9 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
 
                        tsz = min_t(size_t, m->offset + m->size - start, size);
                        paddr = m->paddr + start - m->offset;
-                       if (remap_pfn_range(vma, vma->vm_start + len,
-                                           paddr >> PAGE_SHIFT, tsz,
-                                           vma->vm_page_prot))
+                       if (remap_oldmem_pfn_range(vma, vma->vm_start + len,
+                                                  paddr >> PAGE_SHIFT, tsz,
+                                                  vma->vm_page_prot))
                                goto fail;
                        size -= tsz;
                        start += tsz;
@@ -357,7 +462,7 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
                notes_section = kmalloc(max_sz, GFP_KERNEL);
                if (!notes_section)
                        return -ENOMEM;
-               rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
+               rc = elfcorehdr_read_notes(notes_section, max_sz, &offset);
                if (rc < 0) {
                        kfree(notes_section);
                        return rc;
@@ -444,7 +549,8 @@ static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf)
                if (phdr_ptr->p_type != PT_NOTE)
                        continue;
                offset = phdr_ptr->p_offset;
-               rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
+               rc = elfcorehdr_read_notes(notes_buf, phdr_ptr->p_memsz,
+                                          &offset);
                if (rc < 0)
                        return rc;
                notes_buf += phdr_ptr->p_memsz;
@@ -536,7 +642,7 @@ static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
                notes_section = kmalloc(max_sz, GFP_KERNEL);
                if (!notes_section)
                        return -ENOMEM;
-               rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
+               rc = elfcorehdr_read_notes(notes_section, max_sz, &offset);
                if (rc < 0) {
                        kfree(notes_section);
                        return rc;
@@ -623,7 +729,8 @@ static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf)
                if (phdr_ptr->p_type != PT_NOTE)
                        continue;
                offset = phdr_ptr->p_offset;
-               rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
+               rc = elfcorehdr_read_notes(notes_buf, phdr_ptr->p_memsz,
+                                          &offset);
                if (rc < 0)
                        return rc;
                notes_buf += phdr_ptr->p_memsz;
@@ -810,7 +917,7 @@ static int __init parse_crash_elf64_headers(void)
        addr = elfcorehdr_addr;
 
        /* Read Elf header */
-       rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0);
+       rc = elfcorehdr_read((char *)&ehdr, sizeof(Elf64_Ehdr), &addr);
        if (rc < 0)
                return rc;
 
@@ -837,7 +944,7 @@ static int __init parse_crash_elf64_headers(void)
        if (!elfcorebuf)
                return -ENOMEM;
        addr = elfcorehdr_addr;
-       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
+       rc = elfcorehdr_read(elfcorebuf, elfcorebuf_sz_orig, &addr);
        if (rc < 0)
                goto fail;
 
@@ -866,7 +973,7 @@ static int __init parse_crash_elf32_headers(void)
        addr = elfcorehdr_addr;
 
        /* Read Elf header */
-       rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0);
+       rc = elfcorehdr_read((char *)&ehdr, sizeof(Elf32_Ehdr), &addr);
        if (rc < 0)
                return rc;
 
@@ -892,7 +999,7 @@ static int __init parse_crash_elf32_headers(void)
        if (!elfcorebuf)
                return -ENOMEM;
        addr = elfcorehdr_addr;
-       rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
+       rc = elfcorehdr_read(elfcorebuf, elfcorebuf_sz_orig, &addr);
        if (rc < 0)
                goto fail;
 
@@ -919,7 +1026,7 @@ static int __init parse_crash_elf_headers(void)
        int rc=0;
 
        addr = elfcorehdr_addr;
-       rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0);
+       rc = elfcorehdr_read(e_ident, EI_NIDENT, &addr);
        if (rc < 0)
                return rc;
        if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
@@ -952,7 +1059,14 @@ static int __init vmcore_init(void)
 {
        int rc = 0;
 
-       /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/
+       /* Allow architectures to allocate ELF header in 2nd kernel */
+       rc = elfcorehdr_alloc(&elfcorehdr_addr, &elfcorehdr_size);
+       if (rc)
+               return rc;
+       /*
+        * If elfcorehdr= has been passed in cmdline or created in 2nd kernel,
+        * then capture the dump.
+        */
        if (!(is_vmcore_usable()))
                return rc;
        rc = parse_crash_elf_headers();
@@ -960,6 +1074,8 @@ static int __init vmcore_init(void)
                pr_warn("Kdump: vmcore not initialized\n");
                return rc;
        }
+       elfcorehdr_free(elfcorehdr_addr);
+       elfcorehdr_addr = ELFCORE_ADDR_ERR;
 
        proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
        if (proc_vmcore)
index 4ffb7ab5e397ecfcaede608a39c5025cb4ecd858..b8e93a40a5d3342767a26959858d24f2a24274c0 100644 (file)
@@ -168,7 +168,7 @@ static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
        int err, ret;
 
        ret = -EIO;
-       err = zlib_inflateInit(&stream);
+       err = zlib_inflateInit2(&stream, WINDOW_BITS);
        if (err != Z_OK)
                goto error;
 
@@ -195,8 +195,29 @@ error:
 static void allocate_buf_for_compression(void)
 {
        size_t size;
+       size_t cmpr;
+
+       switch (psinfo->bufsize) {
+       /* buffer range for efivars */
+       case 1000 ... 2000:
+               cmpr = 56;
+               break;
+       case 2001 ... 3000:
+               cmpr = 54;
+               break;
+       case 3001 ... 3999:
+               cmpr = 52;
+               break;
+       /* buffer range for nvram, erst */
+       case 4000 ... 10000:
+               cmpr = 45;
+               break;
+       default:
+               cmpr = 60;
+               break;
+       }
 
-       big_oops_buf_sz = (psinfo->bufsize * 100) / 45;
+       big_oops_buf_sz = (psinfo->bufsize * 100) / cmpr;
        big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
        if (big_oops_buf) {
                size = max(zlib_deflate_workspacesize(WINDOW_BITS, MEM_LEVEL),
@@ -295,10 +316,6 @@ static void pstore_dump(struct kmsg_dumper *dumper,
                                compressed = true;
                                total_len = zipped_len;
                        } else {
-                               pr_err("pstore: compression failed for Part %d"
-                                       " returned %d\n", part, zipped_len);
-                               pr_err("pstore: Capture uncompressed"
-                                       " oops/panic report of Part %d\n", part);
                                compressed = false;
                                total_len = copy_kmsg_to_buffer(hsize, len);
                        }
index 9a702e1935383d1e8deda7678e529426262a8636..831d49a4111f8405716d96ff6a451fc9ebd59e91 100644 (file)
@@ -687,45 +687,37 @@ int dquot_quota_sync(struct super_block *sb, int type)
 }
 EXPORT_SYMBOL(dquot_quota_sync);
 
-/* Free unused dquots from cache */
-static void prune_dqcache(int count)
+static unsigned long
+dqcache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
 {
        struct list_head *head;
        struct dquot *dquot;
+       unsigned long freed = 0;
 
        head = free_dquots.prev;
-       while (head != &free_dquots && count) {
+       while (head != &free_dquots && sc->nr_to_scan) {
                dquot = list_entry(head, struct dquot, dq_free);
                remove_dquot_hash(dquot);
                remove_free_dquot(dquot);
                remove_inuse(dquot);
                do_destroy_dquot(dquot);
-               count--;
+               sc->nr_to_scan--;
+               freed++;
                head = free_dquots.prev;
        }
+       return freed;
 }
 
-/*
- * This is called from kswapd when we think we need some
- * more memory
- */
-static int shrink_dqcache_memory(struct shrinker *shrink,
-                                struct shrink_control *sc)
+static unsigned long
+dqcache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
 {
-       int nr = sc->nr_to_scan;
-
-       if (nr) {
-               spin_lock(&dq_list_lock);
-               prune_dqcache(nr);
-               spin_unlock(&dq_list_lock);
-       }
-       return ((unsigned)
-               percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS])
-               /100) * sysctl_vfs_cache_pressure;
+       return vfs_pressure_ratio(
+       percpu_counter_read_positive(&dqstats.counter[DQST_FREE_DQUOTS]));
 }
 
 static struct shrinker dqcache_shrinker = {
-       .shrink = shrink_dqcache_memory,
+       .count_objects = dqcache_shrink_count,
+       .scan_objects = dqcache_shrink_scan,
        .seeks = DEFAULT_SEEKS,
 };
 
index c7314f1771f5824be95fffb4cd27695494c767ff..dea86e8967ee2c354d489384a83d1492b1dbcba3 100644 (file)
@@ -27,6 +27,7 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
        case Q_SYNC:
        case Q_GETINFO:
        case Q_XGETQSTAT:
+       case Q_XGETQSTATV:
        case Q_XQUOTASYNC:
                break;
        /* allow to query information for dquots we "own" */
@@ -217,6 +218,31 @@ static int quota_getxstate(struct super_block *sb, void __user *addr)
        return ret;
 }
 
+static int quota_getxstatev(struct super_block *sb, void __user *addr)
+{
+       struct fs_quota_statv fqs;
+       int ret;
+
+       if (!sb->s_qcop->get_xstatev)
+               return -ENOSYS;
+
+       memset(&fqs, 0, sizeof(fqs));
+       if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
+               return -EFAULT;
+
+       /* If this kernel doesn't support user specified version, fail */
+       switch (fqs.qs_version) {
+       case FS_QSTATV_VERSION1:
+               break;
+       default:
+               return -EINVAL;
+       }
+       ret = sb->s_qcop->get_xstatev(sb, &fqs);
+       if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
+               return -EFAULT;
+       return ret;
+}
+
 static int quota_setxquota(struct super_block *sb, int type, qid_t id,
                           void __user *addr)
 {
@@ -293,6 +319,8 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
                return quota_setxstate(sb, cmd, addr);
        case Q_XGETQSTAT:
                return quota_getxstate(sb, addr);
+       case Q_XGETQSTATV:
+               return quota_getxstatev(sb, addr);
        case Q_XSETQLIM:
                return quota_setxquota(sb, type, id, addr);
        case Q_XGETQUOTA:
@@ -317,6 +345,7 @@ static int quotactl_cmd_write(int cmd)
        case Q_GETINFO:
        case Q_SYNC:
        case Q_XGETQSTAT:
+       case Q_XGETQSTATV:
        case Q_XGETQUOTA:
        case Q_XQUOTASYNC:
                return 0;
index c24f1e10b94695e13ba7c576e1e394f81ea43747..39d14659a8d3e47b8171f5e1d840d574802edba0 100644 (file)
@@ -244,12 +244,6 @@ struct dentry *ramfs_mount(struct file_system_type *fs_type,
        return mount_nodev(fs_type, flags, data, ramfs_fill_super);
 }
 
-static struct dentry *rootfs_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
-{
-       return mount_nodev(fs_type, flags|MS_NOUSER, data, ramfs_fill_super);
-}
-
 static void ramfs_kill_sb(struct super_block *sb)
 {
        kfree(sb->s_fs_info);
@@ -262,29 +256,23 @@ static struct file_system_type ramfs_fs_type = {
        .kill_sb        = ramfs_kill_sb,
        .fs_flags       = FS_USERNS_MOUNT,
 };
-static struct file_system_type rootfs_fs_type = {
-       .name           = "rootfs",
-       .mount          = rootfs_mount,
-       .kill_sb        = kill_litter_super,
-};
 
-static int __init init_ramfs_fs(void)
-{
-       return register_filesystem(&ramfs_fs_type);
-}
-module_init(init_ramfs_fs)
-
-int __init init_rootfs(void)
+int __init init_ramfs_fs(void)
 {
+       static unsigned long once;
        int err;
 
+       if (test_and_set_bit(0, &once))
+               return 0;
+
        err = bdi_init(&ramfs_backing_dev_info);
        if (err)
                return err;
 
-       err = register_filesystem(&rootfs_fs_type);
+       err = register_filesystem(&ramfs_fs_type);
        if (err)
                bdi_destroy(&ramfs_backing_dev_info);
 
        return err;
 }
+module_init(init_ramfs_fs)
index 122a3846d9e14270a26952e92b25971257ebd82b..e3cd280b158c1132a98c1b53ab2ab8bcdb14de02 100644 (file)
@@ -367,7 +367,6 @@ ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *pp
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = *ppos;
-       kiocb.ki_left = len;
        kiocb.ki_nbytes = len;
 
        ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
@@ -417,7 +416,6 @@ ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, lof
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = *ppos;
-       kiocb.ki_left = len;
        kiocb.ki_nbytes = len;
 
        ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
@@ -599,7 +597,6 @@ static ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
 
        init_sync_kiocb(&kiocb, filp);
        kiocb.ki_pos = *ppos;
-       kiocb.ki_left = len;
        kiocb.ki_nbytes = len;
 
        ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
index fb50652e4e113f54a4447eb147fa56da59a8ba45..41d108ecc9be305211a635bfdf7932ac52d91097 100644 (file)
@@ -167,17 +167,14 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
                /*
                 * Block is uncompressed.
                 */
-               int i, in, pg_offset = 0;
-
-               for (i = 0; i < b; i++) {
-                       wait_on_buffer(bh[i]);
-                       if (!buffer_uptodate(bh[i]))
-                               goto block_release;
-               }
+               int in, pg_offset = 0;
 
                for (bytes = length; k < b; k++) {
                        in = min(bytes, msblk->devblksize - offset);
                        bytes -= in;
+                       wait_on_buffer(bh[k]);
+                       if (!buffer_uptodate(bh[k]))
+                               goto block_release;
                        while (in) {
                                if (pg_offset == PAGE_CACHE_SIZE) {
                                        page++;
index f7f527bf8c10f9f5271e4788c7d1e3ec8e80fd4b..d8c2d747be28d183542a0f2bd4a5d18060436783 100644 (file)
@@ -54,6 +54,7 @@ static int get_dir_index_using_offset(struct super_block *sb,
 {
        struct squashfs_sb_info *msblk = sb->s_fs_info;
        int err, i, index, length = 0;
+       unsigned int size;
        struct squashfs_dir_index dir_index;
 
        TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %lld\n",
@@ -81,8 +82,14 @@ static int get_dir_index_using_offset(struct super_block *sb,
                         */
                        break;
 
+               size = le32_to_cpu(dir_index.size) + 1;
+
+               /* size should never be larger than SQUASHFS_NAME_LEN */
+               if (size > SQUASHFS_NAME_LEN)
+                       break;
+
                err = squashfs_read_metadata(sb, NULL, &index_start,
-                               &index_offset, le32_to_cpu(dir_index.size) + 1);
+                               &index_offset, size);
                if (err < 0)
                        break;
 
@@ -105,9 +112,8 @@ static int squashfs_readdir(struct file *file, struct dir_context *ctx)
        struct inode *inode = file_inode(file);
        struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
        u64 block = squashfs_i(inode)->start + msblk->directory_table;
-       int offset = squashfs_i(inode)->offset, length, dir_count, size,
-                               type, err;
-       unsigned int inode_number;
+       int offset = squashfs_i(inode)->offset, length, err;
+       unsigned int inode_number, dir_count, size, type;
        struct squashfs_dir_header dirh;
        struct squashfs_dir_entry *dire;
 
@@ -200,6 +206,9 @@ static int squashfs_readdir(struct file *file, struct dir_context *ctx)
                                ((short) le16_to_cpu(dire->inode_number));
                        type = le16_to_cpu(dire->type);
 
+                       if (type > SQUASHFS_MAX_DIR_TYPE)
+                               goto failed_read;
+
                        if (!dir_emit(ctx, dire->name, size,
                                        inode_number,
                                        squashfs_filetype_table[type]))
index 7834a517f7f422cfb9bc35f997e8c69e4e91e52d..67cad77fefb4ac165bfd92fbba02db473a02e22e 100644 (file)
@@ -79,7 +79,8 @@ static int get_dir_index_using_name(struct super_block *sb,
                        int len)
 {
        struct squashfs_sb_info *msblk = sb->s_fs_info;
-       int i, size, length = 0, err;
+       int i, length = 0, err;
+       unsigned int size;
        struct squashfs_dir_index *index;
        char *str;
 
@@ -103,6 +104,8 @@ static int get_dir_index_using_name(struct super_block *sb,
 
 
                size = le32_to_cpu(index->size) + 1;
+               if (size > SQUASHFS_NAME_LEN)
+                       break;
 
                err = squashfs_read_metadata(sb, index->name, &index_start,
                                        &index_offset, size);
@@ -144,7 +147,8 @@ static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
        struct squashfs_dir_entry *dire;
        u64 block = squashfs_i(dir)->start + msblk->directory_table;
        int offset = squashfs_i(dir)->offset;
-       int err, length, dir_count, size;
+       int err, length;
+       unsigned int dir_count, size;
 
        TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);
 
index 9e2349d07cb1c98334fd19ffbeb5441361f65edf..4b2beda49498a39036d4db729d539042d1d750d5 100644 (file)
@@ -87,7 +87,7 @@
 #define SQUASHFS_COMP_OPTS(flags)              SQUASHFS_BIT(flags, \
                                                SQUASHFS_COMP_OPT)
 
-/* Max number of types and file types */
+/* Inode types including extended types */
 #define SQUASHFS_DIR_TYPE              1
 #define SQUASHFS_REG_TYPE              2
 #define SQUASHFS_SYMLINK_TYPE          3
 #define SQUASHFS_LFIFO_TYPE            13
 #define SQUASHFS_LSOCKET_TYPE          14
 
+/* Max type value stored in directory entry */
+#define SQUASHFS_MAX_DIR_TYPE          7
+
 /* Xattr types */
 #define SQUASHFS_XATTR_USER             0
 #define SQUASHFS_XATTR_TRUSTED          1
index 5536a95186e28cc60d27676714cc5bb8a1ec350b..3a96c9783a8b959015af96e0b0548bd8e51cc606 100644 (file)
@@ -53,11 +53,15 @@ static char *sb_writers_name[SB_FREEZE_LEVELS] = {
  * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we
  * take a passive reference to the superblock to avoid this from occurring.
  */
-static int prune_super(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long super_cache_scan(struct shrinker *shrink,
+                                     struct shrink_control *sc)
 {
        struct super_block *sb;
-       int     fs_objects = 0;
-       int     total_objects;
+       long    fs_objects = 0;
+       long    total_objects;
+       long    freed = 0;
+       long    dentries;
+       long    inodes;
 
        sb = container_of(shrink, struct super_block, s_shrink);
 
@@ -65,46 +69,62 @@ static int prune_super(struct shrinker *shrink, struct shrink_control *sc)
         * Deadlock avoidance.  We may hold various FS locks, and we don't want
         * to recurse into the FS that called us in clear_inode() and friends..
         */
-       if (sc->nr_to_scan && !(sc->gfp_mask & __GFP_FS))
-               return -1;
+       if (!(sc->gfp_mask & __GFP_FS))
+               return SHRINK_STOP;
 
        if (!grab_super_passive(sb))
-               return -1;
+               return SHRINK_STOP;
 
-       if (sb->s_op && sb->s_op->nr_cached_objects)
-               fs_objects = sb->s_op->nr_cached_objects(sb);
-
-       total_objects = sb->s_nr_dentry_unused +
-                       sb->s_nr_inodes_unused + fs_objects + 1;
-
-       if (sc->nr_to_scan) {
-               int     dentries;
-               int     inodes;
-
-               /* proportion the scan between the caches */
-               dentries = (sc->nr_to_scan * sb->s_nr_dentry_unused) /
-                                                       total_objects;
-               inodes = (sc->nr_to_scan * sb->s_nr_inodes_unused) /
-                                                       total_objects;
-               if (fs_objects)
-                       fs_objects = (sc->nr_to_scan * fs_objects) /
-                                                       total_objects;
-               /*
-                * prune the dcache first as the icache is pinned by it, then
-                * prune the icache, followed by the filesystem specific caches
-                */
-               prune_dcache_sb(sb, dentries);
-               prune_icache_sb(sb, inodes);
+       if (sb->s_op->nr_cached_objects)
+               fs_objects = sb->s_op->nr_cached_objects(sb, sc->nid);
 
-               if (fs_objects && sb->s_op->free_cached_objects) {
-                       sb->s_op->free_cached_objects(sb, fs_objects);
-                       fs_objects = sb->s_op->nr_cached_objects(sb);
-               }
-               total_objects = sb->s_nr_dentry_unused +
-                               sb->s_nr_inodes_unused + fs_objects;
+       inodes = list_lru_count_node(&sb->s_inode_lru, sc->nid);
+       dentries = list_lru_count_node(&sb->s_dentry_lru, sc->nid);
+       total_objects = dentries + inodes + fs_objects + 1;
+
+       /* proportion the scan between the caches */
+       dentries = mult_frac(sc->nr_to_scan, dentries, total_objects);
+       inodes = mult_frac(sc->nr_to_scan, inodes, total_objects);
+
+       /*
+        * prune the dcache first as the icache is pinned by it, then
+        * prune the icache, followed by the filesystem specific caches
+        */
+       freed = prune_dcache_sb(sb, dentries, sc->nid);
+       freed += prune_icache_sb(sb, inodes, sc->nid);
+
+       if (fs_objects) {
+               fs_objects = mult_frac(sc->nr_to_scan, fs_objects,
+                                                               total_objects);
+               freed += sb->s_op->free_cached_objects(sb, fs_objects,
+                                                      sc->nid);
        }
 
-       total_objects = (total_objects / 100) * sysctl_vfs_cache_pressure;
+       drop_super(sb);
+       return freed;
+}
+
+static unsigned long super_cache_count(struct shrinker *shrink,
+                                      struct shrink_control *sc)
+{
+       struct super_block *sb;
+       long    total_objects = 0;
+
+       sb = container_of(shrink, struct super_block, s_shrink);
+
+       if (!grab_super_passive(sb))
+               return 0;
+
+       if (sb->s_op && sb->s_op->nr_cached_objects)
+               total_objects = sb->s_op->nr_cached_objects(sb,
+                                                sc->nid);
+
+       total_objects += list_lru_count_node(&sb->s_dentry_lru,
+                                                sc->nid);
+       total_objects += list_lru_count_node(&sb->s_inode_lru,
+                                                sc->nid);
+
+       total_objects = vfs_pressure_ratio(total_objects);
        drop_super(sb);
        return total_objects;
 }
@@ -175,9 +195,12 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags)
                INIT_HLIST_NODE(&s->s_instances);
                INIT_HLIST_BL_HEAD(&s->s_anon);
                INIT_LIST_HEAD(&s->s_inodes);
-               INIT_LIST_HEAD(&s->s_dentry_lru);
-               INIT_LIST_HEAD(&s->s_inode_lru);
-               spin_lock_init(&s->s_inode_lru_lock);
+
+               if (list_lru_init(&s->s_dentry_lru))
+                       goto err_out;
+               if (list_lru_init(&s->s_inode_lru))
+                       goto err_out_dentry_lru;
+
                INIT_LIST_HEAD(&s->s_mounts);
                init_rwsem(&s->s_umount);
                lockdep_set_class(&s->s_umount, &type->s_umount_key);
@@ -210,11 +233,16 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags)
                s->cleancache_poolid = -1;
 
                s->s_shrink.seeks = DEFAULT_SEEKS;
-               s->s_shrink.shrink = prune_super;
+               s->s_shrink.scan_objects = super_cache_scan;
+               s->s_shrink.count_objects = super_cache_count;
                s->s_shrink.batch = 1024;
+               s->s_shrink.flags = SHRINKER_NUMA_AWARE;
        }
 out:
        return s;
+
+err_out_dentry_lru:
+       list_lru_destroy(&s->s_dentry_lru);
 err_out:
        security_sb_free(s);
 #ifdef CONFIG_SMP
@@ -295,6 +323,9 @@ void deactivate_locked_super(struct super_block *s)
 
                /* caches are now gone, we can safely kill the shrinker now */
                unregister_shrinker(&s->s_shrink);
+               list_lru_destroy(&s->s_dentry_lru);
+               list_lru_destroy(&s->s_inode_lru);
+
                put_filesystem(fs);
                put_super(s);
        } else {
index c1a591a4725b0ba4344862f97e7ab2c72de974f6..66bc316927e8a01f60a387aa19bac4ab81abcd87 100644 (file)
@@ -469,7 +469,7 @@ static void sysv_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);
+               truncate_pagecache(inode, inode->i_size);
                sysv_truncate(inode);
        }
 }
index 7f60e900edff6ff758e84ddf95f0da693570832e..6e025e02ffde80c924bec1b90b4fe62b7d163121 100644 (file)
@@ -2587,10 +2587,11 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
                return -EROFS;
 
        failing = power_cut_emulated(c, lnum, 1);
-       if (failing)
+       if (failing) {
                len = corrupt_data(c, buf, len);
-       ubifs_warn("actually write %d bytes to LEB %d:%d (the buffer was corrupted)",
-                  len, lnum, offs);
+               ubifs_warn("actually write %d bytes to LEB %d:%d (the buffer was corrupted)",
+                          len, lnum, offs);
+       }
        err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
        if (err)
                return err;
index 9e1d05666fed5d1ad03589995f8ecb3f78ec7b82..f35135e28e96f11913e8727983c80f7ba77e2956 100644 (file)
@@ -277,18 +277,25 @@ static int kick_a_thread(void)
        return 0;
 }
 
-int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc)
+unsigned long ubifs_shrink_count(struct shrinker *shrink,
+                                struct shrink_control *sc)
 {
-       int nr = sc->nr_to_scan;
-       int freed, contention = 0;
        long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
 
-       if (nr == 0)
-               /*
-                * Due to the way UBIFS updates the clean znode counter it may
-                * temporarily be negative.
-                */
-               return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
+       /*
+        * Due to the way UBIFS updates the clean znode counter it may
+        * temporarily be negative.
+        */
+       return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
+}
+
+unsigned long ubifs_shrink_scan(struct shrinker *shrink,
+                               struct shrink_control *sc)
+{
+       unsigned long nr = sc->nr_to_scan;
+       int contention = 0;
+       unsigned long freed;
+       long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
 
        if (!clean_zn_cnt) {
                /*
@@ -316,10 +323,10 @@ int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc)
 
        if (!freed && contention) {
                dbg_tnc("freed nothing, but contention");
-               return -1;
+               return SHRINK_STOP;
        }
 
 out:
-       dbg_tnc("%d znodes were freed, requested %d", freed, nr);
+       dbg_tnc("%lu znodes were freed, requested %lu", freed, nr);
        return freed;
 }
index 879b9976c12bf9ab7cc841a1930e0c9b3df41446..3e4aa7281e04b38ecc8063e64d22ccef34c6291f 100644 (file)
@@ -49,7 +49,8 @@ struct kmem_cache *ubifs_inode_slab;
 
 /* UBIFS TNC shrinker description */
 static struct shrinker ubifs_shrinker_info = {
-       .shrink = ubifs_shrinker,
+       .scan_objects = ubifs_shrink_scan,
+       .count_objects = ubifs_shrink_count,
        .seeks = DEFAULT_SEEKS,
 };
 
index b2babce4d70f21845778dbb82a0b2b83fbb97d75..e8c8cfe1435c5cd05809404ea4de182741cd3bf4 100644 (file)
@@ -1624,7 +1624,10 @@ int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
 int ubifs_tnc_end_commit(struct ubifs_info *c);
 
 /* shrinker.c */
-int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc);
+unsigned long ubifs_shrink_scan(struct shrinker *shrink,
+                               struct shrink_control *sc);
+unsigned long ubifs_shrink_count(struct shrinker *shrink,
+                                struct shrink_control *sc);
 
 /* commit.c */
 int ubifs_bg_thread(void *info);
index 29569dd0816814f23a34d713a3f3178c4e822929..c02a27a19c6df0984eb3ea13fc5a06c5e251aaa5 100644 (file)
@@ -141,7 +141,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
        struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
        int err, pos;
-       size_t count = iocb->ki_left;
+       size_t count = iocb->ki_nbytes;
        struct udf_inode_info *iinfo = UDF_I(inode);
 
        down_write(&iinfo->i_data_sem);
index b6d15d349810fe5ca21649208bd86d220caf338c..062b7925bca04c02949919ac37aab790d7b982a2 100644 (file)
@@ -172,7 +172,7 @@ static void udf_write_failed(struct address_space *mapping, loff_t to)
        loff_t isize = inode->i_size;
 
        if (to > isize) {
-               truncate_pagecache(inode, to, isize);
+               truncate_pagecache(inode, isize);
                if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
                        down_write(&iinfo->i_data_sem);
                        udf_clear_extent_cache(inode);
index ff24e4449ece0184436a179b1815571f2da87e10..c8ca9608678433052c5d8d13893513208db72e43 100644 (file)
@@ -531,7 +531,7 @@ static void ufs_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);
+               truncate_pagecache(inode, inode->i_size);
 }
 
 static int ufs_write_begin(struct file *file, struct address_space *mapping,
index 4a4508023a3c15724a2edfd87204550f718c805b..0719e4db93f274de9af844f3ef66ce387b02a716 100644 (file)
@@ -27,9 +27,12 @@ xfs-y                                += xfs_trace.o
 
 # highlevel code
 xfs-y                          += xfs_aops.o \
+                                  xfs_attr_inactive.o \
+                                  xfs_attr_list.o \
                                   xfs_bit.o \
+                                  xfs_bmap_util.o \
                                   xfs_buf.o \
-                                  xfs_dfrag.o \
+                                  xfs_dir2_readdir.o \
                                   xfs_discard.o \
                                   xfs_error.o \
                                   xfs_export.o \
@@ -44,11 +47,11 @@ xfs-y                               += xfs_aops.o \
                                   xfs_iops.o \
                                   xfs_itable.o \
                                   xfs_message.o \
+                                  xfs_mount.o \
                                   xfs_mru_cache.o \
-                                  xfs_rename.o \
                                   xfs_super.o \
-                                  xfs_utils.o \
-                                  xfs_vnodeops.o \
+                                  xfs_symlink.o \
+                                  xfs_trans.o \
                                   xfs_xattr.o \
                                   kmem.o \
                                   uuid.o
@@ -73,10 +76,13 @@ xfs-y                               += xfs_alloc.o \
                                   xfs_ialloc_btree.o \
                                   xfs_icreate_item.o \
                                   xfs_inode.o \
+                                  xfs_inode_fork.o \
+                                  xfs_inode_buf.o \
                                   xfs_log_recover.o \
-                                  xfs_mount.o \
-                                  xfs_symlink.o \
-                                  xfs_trans.o
+                                  xfs_log_rlimit.o \
+                                  xfs_sb.o \
+                                  xfs_symlink_remote.o \
+                                  xfs_trans_resv.o
 
 # low-level transaction/log code
 xfs-y                          += xfs_log.o \
index 4a7286c1dc80d270af40a3733870bb9dd769ee82..a02cfb9e3bcea43d49a033f313387fa217aa789c 100644 (file)
@@ -27,8 +27,6 @@
 
 /*
  * Greedy allocation.  May fail and may return vmalloced memory.
- *
- * Must be freed using kmem_free_large.
  */
 void *
 kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
@@ -36,7 +34,7 @@ kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize)
        void            *ptr;
        size_t          kmsize = maxsize;
 
-       while (!(ptr = kmem_zalloc_large(kmsize))) {
+       while (!(ptr = vzalloc(kmsize))) {
                if ((kmsize >>= 1) <= minsize)
                        kmsize = minsize;
        }
@@ -75,6 +73,17 @@ kmem_zalloc(size_t size, xfs_km_flags_t flags)
        return ptr;
 }
 
+void *
+kmem_zalloc_large(size_t size, xfs_km_flags_t flags)
+{
+       void    *ptr;
+
+       ptr = kmem_zalloc(size, flags | KM_MAYFAIL);
+       if (ptr)
+               return ptr;
+       return vzalloc(size);
+}
+
 void
 kmem_free(const void *ptr)
 {
index b2f2620f9a87b9f1bf6836c8faf3d5039e7af94f..3a7371cab508a7ffea0fc9441d5319026ce089e2 100644 (file)
@@ -57,17 +57,10 @@ kmem_flags_convert(xfs_km_flags_t flags)
 
 extern void *kmem_alloc(size_t, xfs_km_flags_t);
 extern void *kmem_zalloc(size_t, xfs_km_flags_t);
+extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t);
 extern void *kmem_realloc(const void *, size_t, size_t, xfs_km_flags_t);
 extern void  kmem_free(const void *);
 
-static inline void *kmem_zalloc_large(size_t size)
-{
-       return vzalloc(size);
-}
-static inline void kmem_free_large(void *ptr)
-{
-       vfree(ptr);
-}
 
 extern void *kmem_zalloc_greedy(size_t *, size_t, size_t);
 
index 306d883d89bc7d6420ca4b5b8c5f848e573249bf..0e2f37efedd0547a05b5bec4c0109db83192bb72 100644 (file)
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "xfs.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
 #include "xfs_acl.h"
 #include "xfs_attr.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
-#include "xfs_vnodeops.h"
+#include "xfs_ag.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_trace.h"
@@ -68,14 +70,15 @@ xfs_acl_from_disk(
 
                switch (acl_e->e_tag) {
                case ACL_USER:
+                       acl_e->e_uid = xfs_uid_to_kuid(be32_to_cpu(ace->ae_id));
+                       break;
                case ACL_GROUP:
-                       acl_e->e_id = be32_to_cpu(ace->ae_id);
+                       acl_e->e_gid = xfs_gid_to_kgid(be32_to_cpu(ace->ae_id));
                        break;
                case ACL_USER_OBJ:
                case ACL_GROUP_OBJ:
                case ACL_MASK:
                case ACL_OTHER:
-                       acl_e->e_id = ACL_UNDEFINED_ID;
                        break;
                default:
                        goto fail;
@@ -101,7 +104,18 @@ xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl)
                acl_e = &acl->a_entries[i];
 
                ace->ae_tag = cpu_to_be32(acl_e->e_tag);
-               ace->ae_id = cpu_to_be32(acl_e->e_id);
+               switch (acl_e->e_tag) {
+               case ACL_USER:
+                       ace->ae_id = cpu_to_be32(xfs_kuid_to_uid(acl_e->e_uid));
+                       break;
+               case ACL_GROUP:
+                       ace->ae_id = cpu_to_be32(xfs_kgid_to_gid(acl_e->e_gid));
+                       break;
+               default:
+                       ace->ae_id = cpu_to_be32(ACL_UNDEFINED_ID);
+                       break;
+               }
+
                ace->ae_perm = cpu_to_be16(acl_e->e_perm);
        }
 }
@@ -138,7 +152,7 @@ xfs_get_acl(struct inode *inode, int type)
         * go out to the disk.
         */
        len = XFS_ACL_MAX_SIZE(ip->i_mount);
-       xfs_acl = kzalloc(len, GFP_KERNEL);
+       xfs_acl = kmem_zalloc_large(len, KM_SLEEP);
        if (!xfs_acl)
                return ERR_PTR(-ENOMEM);
 
@@ -161,10 +175,10 @@ xfs_get_acl(struct inode *inode, int type)
        if (IS_ERR(acl))
                goto out;
 
- out_update_cache:
+out_update_cache:
        set_cached_acl(inode, type, acl);
- out:
-       kfree(xfs_acl);
+out:
+       kmem_free(xfs_acl);
        return acl;
 }
 
@@ -195,7 +209,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                struct xfs_acl *xfs_acl;
                int len = XFS_ACL_MAX_SIZE(ip->i_mount);
 
-               xfs_acl = kzalloc(len, GFP_KERNEL);
+               xfs_acl = kmem_zalloc_large(len, KM_SLEEP);
                if (!xfs_acl)
                        return -ENOMEM;
 
@@ -208,7 +222,7 @@ xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
                error = -xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
                                len, ATTR_ROOT);
 
-               kfree(xfs_acl);
+               kmem_free(xfs_acl);
        } else {
                /*
                 * A NULL ACL argument means we want to remove the ACL.
@@ -360,7 +374,7 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
                return -EINVAL;
        if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
                return value ? -EACCES : 0;
-       if ((current_fsuid() != inode->i_uid) && !capable(CAP_FOWNER))
+       if (!inode_owner_or_capable(inode))
                return -EPERM;
 
        if (!value)
index 317aa86d96ea04925b35e995cc70e1eb024beb28..1cb740afd674e8fd3f5ce0a3f47bfc00f8b36471 100644 (file)
@@ -226,59 +226,6 @@ typedef struct xfs_agfl {
        __be32          agfl_bno[];     /* actually XFS_AGFL_SIZE(mp) */
 } xfs_agfl_t;
 
-/*
- * Per-ag incore structure, copies of information in agf and agi,
- * to improve the performance of allocation group selection.
- */
-#define XFS_PAGB_NUM_SLOTS     128
-
-typedef struct xfs_perag {
-       struct xfs_mount *pag_mount;    /* owner filesystem */
-       xfs_agnumber_t  pag_agno;       /* AG this structure belongs to */
-       atomic_t        pag_ref;        /* perag reference count */
-       char            pagf_init;      /* this agf's entry is initialized */
-       char            pagi_init;      /* this agi's entry is initialized */
-       char            pagf_metadata;  /* the agf is preferred to be metadata */
-       char            pagi_inodeok;   /* The agi is ok for inodes */
-       __uint8_t       pagf_levels[XFS_BTNUM_AGF];
-                                       /* # of levels in bno & cnt btree */
-       __uint32_t      pagf_flcount;   /* count of blocks in freelist */
-       xfs_extlen_t    pagf_freeblks;  /* total free blocks */
-       xfs_extlen_t    pagf_longest;   /* longest free space */
-       __uint32_t      pagf_btreeblks; /* # of blocks held in AGF btrees */
-       xfs_agino_t     pagi_freecount; /* number of free inodes */
-       xfs_agino_t     pagi_count;     /* number of allocated inodes */
-
-       /*
-        * Inode allocation search lookup optimisation.
-        * If the pagino matches, the search for new inodes
-        * doesn't need to search the near ones again straight away
-        */
-       xfs_agino_t     pagl_pagino;
-       xfs_agino_t     pagl_leftrec;
-       xfs_agino_t     pagl_rightrec;
-#ifdef __KERNEL__
-       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 */
-
-       spinlock_t      pag_ici_lock;   /* incore inode cache lock */
-       struct radix_tree_root pag_ici_root;    /* incore inode cache root */
-       int             pag_ici_reclaimable;    /* reclaimable inodes */
-       struct mutex    pag_ici_reclaim_lock;   /* serialisation point */
-       unsigned long   pag_ici_reclaim_cursor; /* reclaim restart point */
-
-       /* buffer cache index */
-       spinlock_t      pag_buf_lock;   /* lock for pag_buf_tree */
-       struct rb_root  pag_buf_tree;   /* ordered tree of active buffers */
-
-       /* for rcu-safe freeing */
-       struct rcu_head rcu_head;
-#endif
-       int             pagb_count;     /* pagb slots in use */
-} xfs_perag_t;
-
 /*
  * tags for inode radix tree
  */
index 71596e57283ae6b44702f8d6866405de6b911728..5a1393f5e020739a648612002f7ae9a3f704d032 100644 (file)
@@ -878,7 +878,7 @@ xfs_alloc_ag_vextent_near(
        xfs_agblock_t   ltnew;          /* useful start bno of left side */
        xfs_extlen_t    rlen;           /* length of returned extent */
        int             forced = 0;
-#if defined(DEBUG) && defined(__KERNEL__)
+#ifdef DEBUG
        /*
         * Randomly don't execute the first algorithm.
         */
@@ -938,8 +938,8 @@ restart:
                xfs_extlen_t    blen=0;
                xfs_agblock_t   bnew=0;
 
-#if defined(DEBUG) && defined(__KERNEL__)
-               if (!dofirst)
+#ifdef DEBUG
+               if (dofirst)
                        break;
 #endif
                /*
index e11d654af786b580086f188f72881fe7416ca928..e51e581454e93113c7ead8d81136ab82bd29da94 100644 (file)
@@ -28,9 +28,9 @@
 #include "xfs_alloc.h"
 #include "xfs_error.h"
 #include "xfs_iomap.h"
-#include "xfs_vnodeops.h"
 #include "xfs_trace.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include <linux/aio.h>
 #include <linux/gfp.h>
 #include <linux/mpage.h>
@@ -108,7 +108,7 @@ xfs_setfilesize_trans_alloc(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
 
-       error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
@@ -440,7 +440,7 @@ xfs_start_page_writeback(
                end_page_writeback(page);
 }
 
-static inline int bio_add_buffer(struct bio *bio, struct buffer_head *bh)
+static inline int xfs_bio_add_buffer(struct bio *bio, struct buffer_head *bh)
 {
        return bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh));
 }
@@ -514,7 +514,7 @@ xfs_submit_ioend(
                                goto retry;
                        }
 
-                       if (bio_add_buffer(bio, bh) != bh->b_size) {
+                       if (xfs_bio_add_buffer(bio, bh) != bh->b_size) {
                                xfs_submit_ioend_bio(wbc, ioend, bio);
                                goto retry;
                        }
@@ -1498,13 +1498,26 @@ xfs_vm_write_failed(
        loff_t                  pos,
        unsigned                len)
 {
-       loff_t                  block_offset = pos & PAGE_MASK;
+       loff_t                  block_offset;
        loff_t                  block_start;
        loff_t                  block_end;
        loff_t                  from = pos & (PAGE_CACHE_SIZE - 1);
        loff_t                  to = from + len;
        struct buffer_head      *bh, *head;
 
+       /*
+        * The request pos offset might be 32 or 64 bit, this is all fine
+        * on 64-bit platform.  However, for 64-bit pos request on 32-bit
+        * platform, the high 32-bit will be masked off if we evaluate the
+        * block_offset via (pos & PAGE_MASK) because the PAGE_MASK is
+        * 0xfffff000 as an unsigned long, hence the result is incorrect
+        * which could cause the following ASSERT failed in most cases.
+        * In order to avoid this, we can evaluate the block_offset of the
+        * start of the page by using shifts rather than masks the mismatch
+        * problem.
+        */
+       block_offset = (pos >> PAGE_CACHE_SHIFT) << PAGE_CACHE_SHIFT;
+
        ASSERT(block_offset + from == pos);
 
        head = page_buffers(page);
@@ -1569,7 +1582,7 @@ xfs_vm_write_begin(
                unlock_page(page);
 
                if (pos + len > i_size_read(inode))
-                       truncate_pagecache(inode, pos + len, i_size_read(inode));
+                       truncate_pagecache(inode, i_size_read(inode));
 
                page_cache_release(page);
                page = NULL;
@@ -1605,7 +1618,7 @@ xfs_vm_write_end(
                loff_t          to = pos + len;
 
                if (to > isize) {
-                       truncate_pagecache(inode, to, isize);
+                       truncate_pagecache(inode, isize);
                        xfs_vm_kill_delalloc_range(inode, isize, to);
                }
        }
index 20fe3fe9d3417aabcd566ddad7719d3653ad4443..ddcf2267ffa6fdf1bcf33cf7439c6b379472c2b4 100644 (file)
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
+#include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
 #include "xfs_alloc.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_attr_remote.h"
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_trans_space.h"
-#include "xfs_vnodeops.h"
 #include "xfs_trace.h"
 
 /*
@@ -62,7 +63,6 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
-STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
 
 /*
  * Internal routines when attribute list is more than one block.
@@ -70,7 +70,6 @@ STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context);
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
-STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
@@ -90,7 +89,7 @@ xfs_attr_name_to_xname(
        return 0;
 }
 
-STATIC int
+int
 xfs_inode_hasattr(
        struct xfs_inode        *ip)
 {
@@ -227,13 +226,14 @@ xfs_attr_set_int(
        int             valuelen,
        int             flags)
 {
-       xfs_da_args_t   args;
-       xfs_fsblock_t   firstblock;
-       xfs_bmap_free_t flist;
-       int             error, err2, committed;
-       xfs_mount_t     *mp = dp->i_mount;
-       int             rsvd = (flags & ATTR_ROOT) != 0;
-       int             local;
+       xfs_da_args_t           args;
+       xfs_fsblock_t           firstblock;
+       xfs_bmap_free_t         flist;
+       int                     error, err2, committed;
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_trans_res    tres;
+       int                     rsvd = (flags & ATTR_ROOT) != 0;
+       int                     local;
 
        /*
         * Attach the dquots to the inode.
@@ -293,11 +293,11 @@ xfs_attr_set_int(
        if (rsvd)
                args.trans->t_flags |= XFS_TRANS_RESERVE;
 
-       error = xfs_trans_reserve(args.trans, args.total,
-                                 XFS_ATTRSETM_LOG_RES(mp) +
-                                 XFS_ATTRSETRT_LOG_RES(mp) * args.total,
-                                 0, XFS_TRANS_PERM_LOG_RES,
-                                 XFS_ATTRSET_LOG_COUNT);
+       tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres +
+                        M_RES(mp)->tr_attrsetrt.tr_logres * args.total;
+       tres.tr_logcount = XFS_ATTRSET_LOG_COUNT;
+       tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+       error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
        if (error) {
                xfs_trans_cancel(args.trans, 0);
                return(error);
@@ -517,11 +517,9 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
        if (flags & ATTR_ROOT)
                args.trans->t_flags |= XFS_TRANS_RESERVE;
 
-       if ((error = xfs_trans_reserve(args.trans,
-                                     XFS_ATTRRM_SPACE_RES(mp),
-                                     XFS_ATTRRM_LOG_RES(mp),
-                                     0, XFS_TRANS_PERM_LOG_RES,
-                                     XFS_ATTRRM_LOG_COUNT))) {
+       error = xfs_trans_reserve(args.trans, &M_RES(mp)->tr_attrrm,
+                                 XFS_ATTRRM_SPACE_RES(mp), 0);
+       if (error) {
                xfs_trans_cancel(args.trans, 0);
                return(error);
        }
@@ -611,228 +609,6 @@ xfs_attr_remove(
        return xfs_attr_remove_int(dp, &xname, flags);
 }
 
-int
-xfs_attr_list_int(xfs_attr_list_context_t *context)
-{
-       int error;
-       xfs_inode_t *dp = context->dp;
-
-       XFS_STATS_INC(xs_attr_list);
-
-       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
-               return EIO;
-
-       xfs_ilock(dp, XFS_ILOCK_SHARED);
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (!xfs_inode_hasattr(dp)) {
-               error = 0;
-       } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-               error = xfs_attr_shortform_list(context);
-       } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
-               error = xfs_attr_leaf_list(context);
-       } else {
-               error = xfs_attr_node_list(context);
-       }
-
-       xfs_iunlock(dp, XFS_ILOCK_SHARED);
-
-       return error;
-}
-
-#define        ATTR_ENTBASESIZE                /* minimum bytes used by an attr */ \
-       (((struct attrlist_ent *) 0)->a_name - (char *) 0)
-#define        ATTR_ENTSIZE(namelen)           /* actual bytes used by an attr */ \
-       ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
-        & ~(sizeof(u_int32_t)-1))
-
-/*
- * Format an attribute and copy it out to the user's buffer.
- * Take care to check values and protect against them changing later,
- * we may be reading them directly out of a user buffer.
- */
-/*ARGSUSED*/
-STATIC int
-xfs_attr_put_listent(
-       xfs_attr_list_context_t *context,
-       int             flags,
-       unsigned char   *name,
-       int             namelen,
-       int             valuelen,
-       unsigned char   *value)
-{
-       struct attrlist *alist = (struct attrlist *)context->alist;
-       attrlist_ent_t *aep;
-       int arraytop;
-
-       ASSERT(!(context->flags & ATTR_KERNOVAL));
-       ASSERT(context->count >= 0);
-       ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
-       ASSERT(context->firstu >= sizeof(*alist));
-       ASSERT(context->firstu <= context->bufsize);
-
-       /*
-        * Only list entries in the right namespace.
-        */
-       if (((context->flags & ATTR_SECURE) == 0) !=
-           ((flags & XFS_ATTR_SECURE) == 0))
-               return 0;
-       if (((context->flags & ATTR_ROOT) == 0) !=
-           ((flags & XFS_ATTR_ROOT) == 0))
-               return 0;
-
-       arraytop = sizeof(*alist) +
-                       context->count * sizeof(alist->al_offset[0]);
-       context->firstu -= ATTR_ENTSIZE(namelen);
-       if (context->firstu < arraytop) {
-               trace_xfs_attr_list_full(context);
-               alist->al_more = 1;
-               context->seen_enough = 1;
-               return 1;
-       }
-
-       aep = (attrlist_ent_t *)&context->alist[context->firstu];
-       aep->a_valuelen = valuelen;
-       memcpy(aep->a_name, name, namelen);
-       aep->a_name[namelen] = 0;
-       alist->al_offset[context->count++] = context->firstu;
-       alist->al_count = context->count;
-       trace_xfs_attr_list_add(context);
-       return 0;
-}
-
-/*
- * Generate a list of extended attribute names and optionally
- * also value lengths.  Positive return value follows the XFS
- * convention of being an error, zero or negative return code
- * is the length of the buffer returned (negated), indicating
- * success.
- */
-int
-xfs_attr_list(
-       xfs_inode_t     *dp,
-       char            *buffer,
-       int             bufsize,
-       int             flags,
-       attrlist_cursor_kern_t *cursor)
-{
-       xfs_attr_list_context_t context;
-       struct attrlist *alist;
-       int error;
-
-       /*
-        * Validate the cursor.
-        */
-       if (cursor->pad1 || cursor->pad2)
-               return(XFS_ERROR(EINVAL));
-       if ((cursor->initted == 0) &&
-           (cursor->hashval || cursor->blkno || cursor->offset))
-               return XFS_ERROR(EINVAL);
-
-       /*
-        * Check for a properly aligned buffer.
-        */
-       if (((long)buffer) & (sizeof(int)-1))
-               return XFS_ERROR(EFAULT);
-       if (flags & ATTR_KERNOVAL)
-               bufsize = 0;
-
-       /*
-        * Initialize the output buffer.
-        */
-       memset(&context, 0, sizeof(context));
-       context.dp = dp;
-       context.cursor = cursor;
-       context.resynch = 1;
-       context.flags = flags;
-       context.alist = buffer;
-       context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
-       context.firstu = context.bufsize;
-       context.put_listent = xfs_attr_put_listent;
-
-       alist = (struct attrlist *)context.alist;
-       alist->al_count = 0;
-       alist->al_more = 0;
-       alist->al_offset[0] = context.bufsize;
-
-       error = xfs_attr_list_int(&context);
-       ASSERT(error >= 0);
-       return error;
-}
-
-int                                                            /* error */
-xfs_attr_inactive(xfs_inode_t *dp)
-{
-       xfs_trans_t *trans;
-       xfs_mount_t *mp;
-       int error;
-
-       mp = dp->i_mount;
-       ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
-
-       xfs_ilock(dp, XFS_ILOCK_SHARED);
-       if (!xfs_inode_hasattr(dp) ||
-           dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-               xfs_iunlock(dp, XFS_ILOCK_SHARED);
-               return 0;
-       }
-       xfs_iunlock(dp, XFS_ILOCK_SHARED);
-
-       /*
-        * Start our first transaction of the day.
-        *
-        * All future transactions during this code must be "chained" off
-        * this one via the trans_dup() call.  All transactions will contain
-        * the inode, and the inode will always be marked with trans_ihold().
-        * Since the inode will be locked in all transactions, we must log
-        * the inode in every transaction to let it float upward through
-        * the log.
-        */
-       trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
-       if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0,
-                                     XFS_TRANS_PERM_LOG_RES,
-                                     XFS_ATTRINVAL_LOG_COUNT))) {
-               xfs_trans_cancel(trans, 0);
-               return(error);
-       }
-       xfs_ilock(dp, XFS_ILOCK_EXCL);
-
-       /*
-        * No need to make quota reservations here. We expect to release some
-        * blocks, not allocate, in the common case.
-        */
-       xfs_trans_ijoin(trans, dp, 0);
-
-       /*
-        * Decide on what work routines to call based on the inode size.
-        */
-       if (!xfs_inode_hasattr(dp) ||
-           dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
-               error = 0;
-               goto out;
-       }
-       error = xfs_attr3_root_inactive(&trans, dp);
-       if (error)
-               goto out;
-
-       error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
-       if (error)
-               goto out;
-
-       error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-
-       return(error);
-
-out:
-       xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
-       xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       return(error);
-}
-
-
 
 /*========================================================================
  * External routines when attribute list is inside the inode
@@ -1166,28 +942,6 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
        return error;
 }
 
-/*
- * Copy out attribute entries for attr_list(), for leaf attribute lists.
- */
-STATIC int
-xfs_attr_leaf_list(xfs_attr_list_context_t *context)
-{
-       int error;
-       struct xfs_buf *bp;
-
-       trace_xfs_attr_leaf_list(context);
-
-       context->cursor->blkno = 0;
-       error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp);
-       if (error)
-               return XFS_ERROR(error);
-
-       error = xfs_attr3_leaf_list_int(bp, context);
-       xfs_trans_brelse(NULL, bp);
-       return XFS_ERROR(error);
-}
-
-
 /*========================================================================
  * External routines when attribute list size > XFS_LBSIZE(mp).
  *========================================================================*/
@@ -1260,6 +1014,7 @@ restart:
                         * have been a b-tree.
                         */
                        xfs_da_state_free(state);
+                       state = NULL;
                        xfs_bmap_init(args->flist, args->firstblock);
                        error = xfs_attr3_leaf_to_node(args);
                        if (!error) {
@@ -1780,143 +1535,3 @@ xfs_attr_node_get(xfs_da_args_t *args)
        xfs_da_state_free(state);
        return(retval);
 }
-
-STATIC int                                                     /* error */
-xfs_attr_node_list(xfs_attr_list_context_t *context)
-{
-       attrlist_cursor_kern_t *cursor;
-       xfs_attr_leafblock_t *leaf;
-       xfs_da_intnode_t *node;
-       struct xfs_attr3_icleaf_hdr leafhdr;
-       struct xfs_da3_icnode_hdr nodehdr;
-       struct xfs_da_node_entry *btree;
-       int error, i;
-       struct xfs_buf *bp;
-
-       trace_xfs_attr_node_list(context);
-
-       cursor = context->cursor;
-       cursor->initted = 1;
-
-       /*
-        * Do all sorts of validation on the passed-in cursor structure.
-        * If anything is amiss, ignore the cursor and look up the hashval
-        * starting from the btree root.
-        */
-       bp = NULL;
-       if (cursor->blkno > 0) {
-               error = xfs_da3_node_read(NULL, context->dp, cursor->blkno, -1,
-                                             &bp, XFS_ATTR_FORK);
-               if ((error != 0) && (error != EFSCORRUPTED))
-                       return(error);
-               if (bp) {
-                       struct xfs_attr_leaf_entry *entries;
-
-                       node = bp->b_addr;
-                       switch (be16_to_cpu(node->hdr.info.magic)) {
-                       case XFS_DA_NODE_MAGIC:
-                       case XFS_DA3_NODE_MAGIC:
-                               trace_xfs_attr_list_wrong_blk(context);
-                               xfs_trans_brelse(NULL, bp);
-                               bp = NULL;
-                               break;
-                       case XFS_ATTR_LEAF_MAGIC:
-                       case XFS_ATTR3_LEAF_MAGIC:
-                               leaf = bp->b_addr;
-                               xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
-                               entries = xfs_attr3_leaf_entryp(leaf);
-                               if (cursor->hashval > be32_to_cpu(
-                                               entries[leafhdr.count - 1].hashval)) {
-                                       trace_xfs_attr_list_wrong_blk(context);
-                                       xfs_trans_brelse(NULL, bp);
-                                       bp = NULL;
-                               } else if (cursor->hashval <= be32_to_cpu(
-                                               entries[0].hashval)) {
-                                       trace_xfs_attr_list_wrong_blk(context);
-                                       xfs_trans_brelse(NULL, bp);
-                                       bp = NULL;
-                               }
-                               break;
-                       default:
-                               trace_xfs_attr_list_wrong_blk(context);
-                               xfs_trans_brelse(NULL, bp);
-                               bp = NULL;
-                       }
-               }
-       }
-
-       /*
-        * We did not find what we expected given the cursor's contents,
-        * so we start from the top and work down based on the hash value.
-        * Note that start of node block is same as start of leaf block.
-        */
-       if (bp == NULL) {
-               cursor->blkno = 0;
-               for (;;) {
-                       __uint16_t magic;
-
-                       error = xfs_da3_node_read(NULL, context->dp,
-                                                     cursor->blkno, -1, &bp,
-                                                     XFS_ATTR_FORK);
-                       if (error)
-                               return(error);
-                       node = bp->b_addr;
-                       magic = be16_to_cpu(node->hdr.info.magic);
-                       if (magic == XFS_ATTR_LEAF_MAGIC ||
-                           magic == XFS_ATTR3_LEAF_MAGIC)
-                               break;
-                       if (magic != XFS_DA_NODE_MAGIC &&
-                           magic != XFS_DA3_NODE_MAGIC) {
-                               XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
-                                                    XFS_ERRLEVEL_LOW,
-                                                    context->dp->i_mount,
-                                                    node);
-                               xfs_trans_brelse(NULL, bp);
-                               return XFS_ERROR(EFSCORRUPTED);
-                       }
-
-                       xfs_da3_node_hdr_from_disk(&nodehdr, node);
-                       btree = xfs_da3_node_tree_p(node);
-                       for (i = 0; i < nodehdr.count; btree++, i++) {
-                               if (cursor->hashval
-                                               <= be32_to_cpu(btree->hashval)) {
-                                       cursor->blkno = be32_to_cpu(btree->before);
-                                       trace_xfs_attr_list_node_descend(context,
-                                                                        btree);
-                                       break;
-                               }
-                       }
-                       if (i == nodehdr.count) {
-                               xfs_trans_brelse(NULL, bp);
-                               return 0;
-                       }
-                       xfs_trans_brelse(NULL, bp);
-               }
-       }
-       ASSERT(bp != NULL);
-
-       /*
-        * Roll upward through the blocks, processing each leaf block in
-        * order.  As long as there is space in the result buffer, keep
-        * adding the information.
-        */
-       for (;;) {
-               leaf = bp->b_addr;
-               error = xfs_attr3_leaf_list_int(bp, context);
-               if (error) {
-                       xfs_trans_brelse(NULL, bp);
-                       return error;
-               }
-               xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
-               if (context->seen_enough || leafhdr.forw == 0)
-                       break;
-               cursor->blkno = leafhdr.forw;
-               xfs_trans_brelse(NULL, bp);
-               error = xfs_attr3_leaf_read(NULL, context->dp, cursor->blkno, -1,
-                                          &bp);
-               if (error)
-                       return error;
-       }
-       xfs_trans_brelse(NULL, bp);
-       return 0;
-}
index de8dd58da46c28ec078dbd5e6d829ae725e973ab..dd4824589470eb106a2b5a764da6039d56121726 100644 (file)
@@ -141,5 +141,14 @@ typedef struct xfs_attr_list_context {
  */
 int xfs_attr_inactive(struct xfs_inode *dp);
 int xfs_attr_list_int(struct xfs_attr_list_context *);
+int xfs_inode_hasattr(struct xfs_inode *ip);
+int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
+                unsigned char *value, int *valuelenp, int flags);
+int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
+                unsigned char *value, int valuelen, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
+                 int flags, struct attrlist_cursor_kern *cursor);
+
 
 #endif /* __XFS_ATTR_H__ */
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
new file mode 100644 (file)
index 0000000..bb24b07
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2013 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_format.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_alloc.h"
+#include "xfs_btree.h"
+#include "xfs_attr_remote.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_inode_item.h"
+#include "xfs_bmap.h"
+#include "xfs_attr.h"
+#include "xfs_attr_leaf.h"
+#include "xfs_error.h"
+#include "xfs_quota.h"
+#include "xfs_trace.h"
+#include "xfs_trans_priv.h"
+
+/*
+ * Look at all the extents for this logical region,
+ * invalidate any buffers that are incore/in transactions.
+ */
+STATIC int
+xfs_attr3_leaf_freextent(
+       struct xfs_trans        **trans,
+       struct xfs_inode        *dp,
+       xfs_dablk_t             blkno,
+       int                     blkcnt)
+{
+       struct xfs_bmbt_irec    map;
+       struct xfs_buf          *bp;
+       xfs_dablk_t             tblkno;
+       xfs_daddr_t             dblkno;
+       int                     tblkcnt;
+       int                     dblkcnt;
+       int                     nmap;
+       int                     error;
+
+       /*
+        * Roll through the "value", invalidating the attribute value's
+        * blocks.
+        */
+       tblkno = blkno;
+       tblkcnt = blkcnt;
+       while (tblkcnt > 0) {
+               /*
+                * Try to remember where we decided to put the value.
+                */
+               nmap = 1;
+               error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt,
+                                      &map, &nmap, XFS_BMAPI_ATTRFORK);
+               if (error) {
+                       return(error);
+               }
+               ASSERT(nmap == 1);
+               ASSERT(map.br_startblock != DELAYSTARTBLOCK);
+
+               /*
+                * If it's a hole, these are already unmapped
+                * so there's nothing to invalidate.
+                */
+               if (map.br_startblock != HOLESTARTBLOCK) {
+
+                       dblkno = XFS_FSB_TO_DADDR(dp->i_mount,
+                                                 map.br_startblock);
+                       dblkcnt = XFS_FSB_TO_BB(dp->i_mount,
+                                               map.br_blockcount);
+                       bp = xfs_trans_get_buf(*trans,
+                                       dp->i_mount->m_ddev_targp,
+                                       dblkno, dblkcnt, 0);
+                       if (!bp)
+                               return ENOMEM;
+                       xfs_trans_binval(*trans, bp);
+                       /*
+                        * Roll to next transaction.
+                        */
+                       error = xfs_trans_roll(trans, dp);
+                       if (error)
+                               return (error);
+               }
+
+               tblkno += map.br_blockcount;
+               tblkcnt -= map.br_blockcount;
+       }
+
+       return(0);
+}
+
+/*
+ * Invalidate all of the "remote" value regions pointed to by a particular
+ * leaf block.
+ * Note that we must release the lock on the buffer so that we are not
+ * caught holding something that the logging code wants to flush to disk.
+ */
+STATIC int
+xfs_attr3_leaf_inactive(
+       struct xfs_trans        **trans,
+       struct xfs_inode        *dp,
+       struct xfs_buf          *bp)
+{
+       struct xfs_attr_leafblock *leaf;
+       struct xfs_attr3_icleaf_hdr ichdr;
+       struct xfs_attr_leaf_entry *entry;
+       struct xfs_attr_leaf_name_remote *name_rmt;
+       struct xfs_attr_inactive_list *list;
+       struct xfs_attr_inactive_list *lp;
+       int                     error;
+       int                     count;
+       int                     size;
+       int                     tmp;
+       int                     i;
+
+       leaf = bp->b_addr;
+       xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
+
+       /*
+        * Count the number of "remote" value extents.
+        */
+       count = 0;
+       entry = xfs_attr3_leaf_entryp(leaf);
+       for (i = 0; i < ichdr.count; entry++, i++) {
+               if (be16_to_cpu(entry->nameidx) &&
+                   ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
+                       name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
+                       if (name_rmt->valueblk)
+                               count++;
+               }
+       }
+
+       /*
+        * If there are no "remote" values, we're done.
+        */
+       if (count == 0) {
+               xfs_trans_brelse(*trans, bp);
+               return 0;
+       }
+
+       /*
+        * Allocate storage for a list of all the "remote" value extents.
+        */
+       size = count * sizeof(xfs_attr_inactive_list_t);
+       list = kmem_alloc(size, KM_SLEEP);
+
+       /*
+        * Identify each of the "remote" value extents.
+        */
+       lp = list;
+       entry = xfs_attr3_leaf_entryp(leaf);
+       for (i = 0; i < ichdr.count; entry++, i++) {
+               if (be16_to_cpu(entry->nameidx) &&
+                   ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
+                       name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
+                       if (name_rmt->valueblk) {
+                               lp->valueblk = be32_to_cpu(name_rmt->valueblk);
+                               lp->valuelen = xfs_attr3_rmt_blocks(dp->i_mount,
+                                                   be32_to_cpu(name_rmt->valuelen));
+                               lp++;
+                       }
+               }
+       }
+       xfs_trans_brelse(*trans, bp);   /* unlock for trans. in freextent() */
+
+       /*
+        * Invalidate each of the "remote" value extents.
+        */
+       error = 0;
+       for (lp = list, i = 0; i < count; i++, lp++) {
+               tmp = xfs_attr3_leaf_freextent(trans, dp,
+                               lp->valueblk, lp->valuelen);
+
+               if (error == 0)
+                       error = tmp;    /* save only the 1st errno */
+       }
+
+       kmem_free(list);
+       return error;
+}
+
+/*
+ * Recurse (gasp!) through the attribute nodes until we find leaves.
+ * We're doing a depth-first traversal in order to invalidate everything.
+ */
+STATIC int
+xfs_attr3_node_inactive(
+       struct xfs_trans **trans,
+       struct xfs_inode *dp,
+       struct xfs_buf  *bp,
+       int             level)
+{
+       xfs_da_blkinfo_t *info;
+       xfs_da_intnode_t *node;
+       xfs_dablk_t child_fsb;
+       xfs_daddr_t parent_blkno, child_blkno;
+       int error, i;
+       struct xfs_buf *child_bp;
+       struct xfs_da_node_entry *btree;
+       struct xfs_da3_icnode_hdr ichdr;
+
+       /*
+        * Since this code is recursive (gasp!) we must protect ourselves.
+        */
+       if (level > XFS_DA_NODE_MAXDEPTH) {
+               xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
+               return XFS_ERROR(EIO);
+       }
+
+       node = bp->b_addr;
+       xfs_da3_node_hdr_from_disk(&ichdr, node);
+       parent_blkno = bp->b_bn;
+       if (!ichdr.count) {
+               xfs_trans_brelse(*trans, bp);
+               return 0;
+       }
+       btree = xfs_da3_node_tree_p(node);
+       child_fsb = be32_to_cpu(btree[0].before);
+       xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
+
+       /*
+        * If this is the node level just above the leaves, simply loop
+        * over the leaves removing all of them.  If this is higher up
+        * in the tree, recurse downward.
+        */
+       for (i = 0; i < ichdr.count; i++) {
+               /*
+                * Read the subsidiary block to see what we have to work with.
+                * Don't do this in a transaction.  This is a depth-first
+                * traversal of the tree so we may deal with many blocks
+                * before we come back to this one.
+                */
+               error = xfs_da3_node_read(*trans, dp, child_fsb, -2, &child_bp,
+                                               XFS_ATTR_FORK);
+               if (error)
+                       return(error);
+               if (child_bp) {
+                                               /* save for re-read later */
+                       child_blkno = XFS_BUF_ADDR(child_bp);
+
+                       /*
+                        * Invalidate the subtree, however we have to.
+                        */
+                       info = child_bp->b_addr;
+                       switch (info->magic) {
+                       case cpu_to_be16(XFS_DA_NODE_MAGIC):
+                       case cpu_to_be16(XFS_DA3_NODE_MAGIC):
+                               error = xfs_attr3_node_inactive(trans, dp,
+                                                       child_bp, level + 1);
+                               break;
+                       case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
+                       case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
+                               error = xfs_attr3_leaf_inactive(trans, dp,
+                                                       child_bp);
+                               break;
+                       default:
+                               error = XFS_ERROR(EIO);
+                               xfs_trans_brelse(*trans, child_bp);
+                               break;
+                       }
+                       if (error)
+                               return error;
+
+                       /*
+                        * Remove the subsidiary block from the cache
+                        * and from the log.
+                        */
+                       error = xfs_da_get_buf(*trans, dp, 0, child_blkno,
+                               &child_bp, XFS_ATTR_FORK);
+                       if (error)
+                               return error;
+                       xfs_trans_binval(*trans, child_bp);
+               }
+
+               /*
+                * If we're not done, re-read the parent to get the next
+                * child block number.
+                */
+               if (i + 1 < ichdr.count) {
+                       error = xfs_da3_node_read(*trans, dp, 0, parent_blkno,
+                                                &bp, XFS_ATTR_FORK);
+                       if (error)
+                               return error;
+                       child_fsb = be32_to_cpu(btree[i + 1].before);
+                       xfs_trans_brelse(*trans, bp);
+               }
+               /*
+                * Atomically commit the whole invalidate stuff.
+                */
+               error = xfs_trans_roll(trans, dp);
+               if (error)
+                       return  error;
+       }
+
+       return 0;
+}
+
+/*
+ * Indiscriminately delete the entire attribute fork
+ *
+ * Recurse (gasp!) through the attribute nodes until we find leaves.
+ * We're doing a depth-first traversal in order to invalidate everything.
+ */
+int
+xfs_attr3_root_inactive(
+       struct xfs_trans        **trans,
+       struct xfs_inode        *dp)
+{
+       struct xfs_da_blkinfo   *info;
+       struct xfs_buf          *bp;
+       xfs_daddr_t             blkno;
+       int                     error;
+
+       /*
+        * Read block 0 to see what we have to work with.
+        * We only get here if we have extents, since we remove
+        * the extents in reverse order the extent containing
+        * block 0 must still be there.
+        */
+       error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
+       if (error)
+               return error;
+       blkno = bp->b_bn;
+
+       /*
+        * Invalidate the tree, even if the "tree" is only a single leaf block.
+        * This is a depth-first traversal!
+        */
+       info = bp->b_addr;
+       switch (info->magic) {
+       case cpu_to_be16(XFS_DA_NODE_MAGIC):
+       case cpu_to_be16(XFS_DA3_NODE_MAGIC):
+               error = xfs_attr3_node_inactive(trans, dp, bp, 1);
+               break;
+       case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
+       case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
+               error = xfs_attr3_leaf_inactive(trans, dp, bp);
+               break;
+       default:
+               error = XFS_ERROR(EIO);
+               xfs_trans_brelse(*trans, bp);
+               break;
+       }
+       if (error)
+               return error;
+
+       /*
+        * Invalidate the incore copy of the root block.
+        */
+       error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK);
+       if (error)
+               return error;
+       xfs_trans_binval(*trans, bp);   /* remove from cache */
+       /*
+        * Commit the invalidate and start the next transaction.
+        */
+       error = xfs_trans_roll(trans, dp);
+
+       return error;
+}
+
+int
+xfs_attr_inactive(xfs_inode_t *dp)
+{
+       xfs_trans_t *trans;
+       xfs_mount_t *mp;
+       int error;
+
+       mp = dp->i_mount;
+       ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
+
+       xfs_ilock(dp, XFS_ILOCK_SHARED);
+       if (!xfs_inode_hasattr(dp) ||
+           dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+               xfs_iunlock(dp, XFS_ILOCK_SHARED);
+               return 0;
+       }
+       xfs_iunlock(dp, XFS_ILOCK_SHARED);
+
+       /*
+        * Start our first transaction of the day.
+        *
+        * All future transactions during this code must be "chained" off
+        * this one via the trans_dup() call.  All transactions will contain
+        * the inode, and the inode will always be marked with trans_ihold().
+        * Since the inode will be locked in all transactions, we must log
+        * the inode in every transaction to let it float upward through
+        * the log.
+        */
+       trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
+       error = xfs_trans_reserve(trans, &M_RES(mp)->tr_attrinval, 0, 0);
+       if (error) {
+               xfs_trans_cancel(trans, 0);
+               return(error);
+       }
+       xfs_ilock(dp, XFS_ILOCK_EXCL);
+
+       /*
+        * No need to make quota reservations here. We expect to release some
+        * blocks, not allocate, in the common case.
+        */
+       xfs_trans_ijoin(trans, dp, 0);
+
+       /*
+        * Decide on what work routines to call based on the inode size.
+        */
+       if (!xfs_inode_hasattr(dp) ||
+           dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+               error = 0;
+               goto out;
+       }
+       error = xfs_attr3_root_inactive(&trans, dp);
+       if (error)
+               goto out;
+
+       error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
+       if (error)
+               goto out;
+
+       error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
+       xfs_iunlock(dp, XFS_ILOCK_EXCL);
+
+       return(error);
+
+out:
+       xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
+       xfs_iunlock(dp, XFS_ILOCK_EXCL);
+       return(error);
+}
index b800fbcafc7f639f05a83fc97fc5e964f77422b0..86db20a9cc02b5df2dd7ecb3c44eca39d7498dd7 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
+#include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
@@ -77,16 +78,6 @@ STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state,
                        int *number_entries_in_blk1,
                        int *number_usedbytes_in_blk1);
 
-/*
- * Routines used for shrinking the Btree.
- */
-STATIC int xfs_attr3_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
-                                 struct xfs_buf *bp, int level);
-STATIC int xfs_attr3_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
-                                 struct xfs_buf *bp);
-STATIC int xfs_attr3_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
-                                  xfs_dablk_t blkno, int blkcnt);
-
 /*
  * Utility routines.
  */
@@ -635,7 +626,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
        xfs_attr_sf_entry_t *sfe;
        int i;
 
-       ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE);
+       ASSERT(args->dp->i_afp->if_flags == XFS_IFINLINE);
        sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data;
        sfe = &sf->list[0];
        for (i = 0; i < sf->hdr.count;
@@ -751,182 +742,6 @@ out:
        return(error);
 }
 
-STATIC int
-xfs_attr_shortform_compare(const void *a, const void *b)
-{
-       xfs_attr_sf_sort_t *sa, *sb;
-
-       sa = (xfs_attr_sf_sort_t *)a;
-       sb = (xfs_attr_sf_sort_t *)b;
-       if (sa->hash < sb->hash) {
-               return(-1);
-       } else if (sa->hash > sb->hash) {
-               return(1);
-       } else {
-               return(sa->entno - sb->entno);
-       }
-}
-
-
-#define XFS_ISRESET_CURSOR(cursor) \
-       (!((cursor)->initted) && !((cursor)->hashval) && \
-        !((cursor)->blkno) && !((cursor)->offset))
-/*
- * Copy out entries of shortform attribute lists for attr_list().
- * Shortform attribute lists are not stored in hashval sorted order.
- * If the output buffer is not large enough to hold them all, then we
- * we have to calculate each entries' hashvalue and sort them before
- * we can begin returning them to the user.
- */
-/*ARGSUSED*/
-int
-xfs_attr_shortform_list(xfs_attr_list_context_t *context)
-{
-       attrlist_cursor_kern_t *cursor;
-       xfs_attr_sf_sort_t *sbuf, *sbp;
-       xfs_attr_shortform_t *sf;
-       xfs_attr_sf_entry_t *sfe;
-       xfs_inode_t *dp;
-       int sbsize, nsbuf, count, i;
-       int error;
-
-       ASSERT(context != NULL);
-       dp = context->dp;
-       ASSERT(dp != NULL);
-       ASSERT(dp->i_afp != NULL);
-       sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
-       ASSERT(sf != NULL);
-       if (!sf->hdr.count)
-               return(0);
-       cursor = context->cursor;
-       ASSERT(cursor != NULL);
-
-       trace_xfs_attr_list_sf(context);
-
-       /*
-        * If the buffer is large enough and the cursor is at the start,
-        * do not bother with sorting since we will return everything in
-        * one buffer and another call using the cursor won't need to be
-        * made.
-        * Note the generous fudge factor of 16 overhead bytes per entry.
-        * If bufsize is zero then put_listent must be a search function
-        * and can just scan through what we have.
-        */
-       if (context->bufsize == 0 ||
-           (XFS_ISRESET_CURSOR(cursor) &&
-             (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
-               for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
-                       error = context->put_listent(context,
-                                          sfe->flags,
-                                          sfe->nameval,
-                                          (int)sfe->namelen,
-                                          (int)sfe->valuelen,
-                                          &sfe->nameval[sfe->namelen]);
-
-                       /*
-                        * Either search callback finished early or
-                        * didn't fit it all in the buffer after all.
-                        */
-                       if (context->seen_enough)
-                               break;
-
-                       if (error)
-                               return error;
-                       sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
-               }
-               trace_xfs_attr_list_sf_all(context);
-               return(0);
-       }
-
-       /* do no more for a search callback */
-       if (context->bufsize == 0)
-               return 0;
-
-       /*
-        * It didn't all fit, so we have to sort everything on hashval.
-        */
-       sbsize = sf->hdr.count * sizeof(*sbuf);
-       sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP | KM_NOFS);
-
-       /*
-        * Scan the attribute list for the rest of the entries, storing
-        * the relevant info from only those that match into a buffer.
-        */
-       nsbuf = 0;
-       for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
-               if (unlikely(
-                   ((char *)sfe < (char *)sf) ||
-                   ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
-                       XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
-                                            XFS_ERRLEVEL_LOW,
-                                            context->dp->i_mount, sfe);
-                       kmem_free(sbuf);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-
-               sbp->entno = i;
-               sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
-               sbp->name = sfe->nameval;
-               sbp->namelen = sfe->namelen;
-               /* These are bytes, and both on-disk, don't endian-flip */
-               sbp->valuelen = sfe->valuelen;
-               sbp->flags = sfe->flags;
-               sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
-               sbp++;
-               nsbuf++;
-       }
-
-       /*
-        * Sort the entries on hash then entno.
-        */
-       xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
-
-       /*
-        * Re-find our place IN THE SORTED LIST.
-        */
-       count = 0;
-       cursor->initted = 1;
-       cursor->blkno = 0;
-       for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
-               if (sbp->hash == cursor->hashval) {
-                       if (cursor->offset == count) {
-                               break;
-                       }
-                       count++;
-               } else if (sbp->hash > cursor->hashval) {
-                       break;
-               }
-       }
-       if (i == nsbuf) {
-               kmem_free(sbuf);
-               return(0);
-       }
-
-       /*
-        * Loop putting entries into the user buffer.
-        */
-       for ( ; i < nsbuf; i++, sbp++) {
-               if (cursor->hashval != sbp->hash) {
-                       cursor->hashval = sbp->hash;
-                       cursor->offset = 0;
-               }
-               error = context->put_listent(context,
-                                       sbp->flags,
-                                       sbp->name,
-                                       sbp->namelen,
-                                       sbp->valuelen,
-                                       &sbp->name[sbp->namelen]);
-               if (error)
-                       return error;
-               if (context->seen_enough)
-                       break;
-               cursor->offset++;
-       }
-
-       kmem_free(sbuf);
-       return(0);
-}
-
 /*
  * Check a leaf attribute block to see if all the entries would fit into
  * a shortform attribute list.
@@ -1121,7 +936,6 @@ out:
        return error;
 }
 
-
 /*========================================================================
  * Routines used for growing the Btree.
  *========================================================================*/
@@ -1482,7 +1296,6 @@ xfs_attr3_leaf_compact(
        ichdr_dst->freemap[0].size = ichdr_dst->firstused -
                                                ichdr_dst->freemap[0].base;
 
-
        /* write the header back to initialise the underlying buffer */
        xfs_attr3_leaf_hdr_to_disk(leaf_dst, ichdr_dst);
 
@@ -2643,130 +2456,6 @@ xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, int *local)
        return size;
 }
 
-/*
- * Copy out attribute list entries for attr_list(), for leaf attribute lists.
- */
-int
-xfs_attr3_leaf_list_int(
-       struct xfs_buf                  *bp,
-       struct xfs_attr_list_context    *context)
-{
-       struct attrlist_cursor_kern     *cursor;
-       struct xfs_attr_leafblock       *leaf;
-       struct xfs_attr3_icleaf_hdr     ichdr;
-       struct xfs_attr_leaf_entry      *entries;
-       struct xfs_attr_leaf_entry      *entry;
-       int                             retval;
-       int                             i;
-
-       trace_xfs_attr_list_leaf(context);
-
-       leaf = bp->b_addr;
-       xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
-       entries = xfs_attr3_leaf_entryp(leaf);
-
-       cursor = context->cursor;
-       cursor->initted = 1;
-
-       /*
-        * Re-find our place in the leaf block if this is a new syscall.
-        */
-       if (context->resynch) {
-               entry = &entries[0];
-               for (i = 0; i < ichdr.count; entry++, i++) {
-                       if (be32_to_cpu(entry->hashval) == cursor->hashval) {
-                               if (cursor->offset == context->dupcnt) {
-                                       context->dupcnt = 0;
-                                       break;
-                               }
-                               context->dupcnt++;
-                       } else if (be32_to_cpu(entry->hashval) >
-                                       cursor->hashval) {
-                               context->dupcnt = 0;
-                               break;
-                       }
-               }
-               if (i == ichdr.count) {
-                       trace_xfs_attr_list_notfound(context);
-                       return 0;
-               }
-       } else {
-               entry = &entries[0];
-               i = 0;
-       }
-       context->resynch = 0;
-
-       /*
-        * We have found our place, start copying out the new attributes.
-        */
-       retval = 0;
-       for (; i < ichdr.count; entry++, i++) {
-               if (be32_to_cpu(entry->hashval) != cursor->hashval) {
-                       cursor->hashval = be32_to_cpu(entry->hashval);
-                       cursor->offset = 0;
-               }
-
-               if (entry->flags & XFS_ATTR_INCOMPLETE)
-                       continue;               /* skip incomplete entries */
-
-               if (entry->flags & XFS_ATTR_LOCAL) {
-                       xfs_attr_leaf_name_local_t *name_loc =
-                               xfs_attr3_leaf_name_local(leaf, i);
-
-                       retval = context->put_listent(context,
-                                               entry->flags,
-                                               name_loc->nameval,
-                                               (int)name_loc->namelen,
-                                               be16_to_cpu(name_loc->valuelen),
-                                               &name_loc->nameval[name_loc->namelen]);
-                       if (retval)
-                               return retval;
-               } else {
-                       xfs_attr_leaf_name_remote_t *name_rmt =
-                               xfs_attr3_leaf_name_remote(leaf, i);
-
-                       int valuelen = be32_to_cpu(name_rmt->valuelen);
-
-                       if (context->put_value) {
-                               xfs_da_args_t args;
-
-                               memset((char *)&args, 0, sizeof(args));
-                               args.dp = context->dp;
-                               args.whichfork = XFS_ATTR_FORK;
-                               args.valuelen = valuelen;
-                               args.value = kmem_alloc(valuelen, KM_SLEEP | KM_NOFS);
-                               args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
-                               args.rmtblkcnt = xfs_attr3_rmt_blocks(
-                                                       args.dp->i_mount, valuelen);
-                               retval = xfs_attr_rmtval_get(&args);
-                               if (retval)
-                                       return retval;
-                               retval = context->put_listent(context,
-                                               entry->flags,
-                                               name_rmt->name,
-                                               (int)name_rmt->namelen,
-                                               valuelen,
-                                               args.value);
-                               kmem_free(args.value);
-                       } else {
-                               retval = context->put_listent(context,
-                                               entry->flags,
-                                               name_rmt->name,
-                                               (int)name_rmt->namelen,
-                                               valuelen,
-                                               NULL);
-                       }
-                       if (retval)
-                               return retval;
-               }
-               if (context->seen_enough)
-                       break;
-               cursor->offset++;
-       }
-       trace_xfs_attr_list_leaf_end(context);
-       return retval;
-}
-
 
 /*========================================================================
  * Manage the INCOMPLETE flag in a leaf entry
@@ -3011,345 +2700,3 @@ xfs_attr3_leaf_flipflags(
 
        return error;
 }
-
-/*========================================================================
- * Indiscriminately delete the entire attribute fork
- *========================================================================*/
-
-/*
- * Recurse (gasp!) through the attribute nodes until we find leaves.
- * We're doing a depth-first traversal in order to invalidate everything.
- */
-int
-xfs_attr3_root_inactive(
-       struct xfs_trans        **trans,
-       struct xfs_inode        *dp)
-{
-       struct xfs_da_blkinfo   *info;
-       struct xfs_buf          *bp;
-       xfs_daddr_t             blkno;
-       int                     error;
-
-       /*
-        * Read block 0 to see what we have to work with.
-        * We only get here if we have extents, since we remove
-        * the extents in reverse order the extent containing
-        * block 0 must still be there.
-        */
-       error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
-       if (error)
-               return error;
-       blkno = bp->b_bn;
-
-       /*
-        * Invalidate the tree, even if the "tree" is only a single leaf block.
-        * This is a depth-first traversal!
-        */
-       info = bp->b_addr;
-       switch (info->magic) {
-       case cpu_to_be16(XFS_DA_NODE_MAGIC):
-       case cpu_to_be16(XFS_DA3_NODE_MAGIC):
-               error = xfs_attr3_node_inactive(trans, dp, bp, 1);
-               break;
-       case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
-       case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
-               error = xfs_attr3_leaf_inactive(trans, dp, bp);
-               break;
-       default:
-               error = XFS_ERROR(EIO);
-               xfs_trans_brelse(*trans, bp);
-               break;
-       }
-       if (error)
-               return error;
-
-       /*
-        * Invalidate the incore copy of the root block.
-        */
-       error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK);
-       if (error)
-               return error;
-       xfs_trans_binval(*trans, bp);   /* remove from cache */
-       /*
-        * Commit the invalidate and start the next transaction.
-        */
-       error = xfs_trans_roll(trans, dp);
-
-       return error;
-}
-
-/*
- * Recurse (gasp!) through the attribute nodes until we find leaves.
- * We're doing a depth-first traversal in order to invalidate everything.
- */
-STATIC int
-xfs_attr3_node_inactive(
-       struct xfs_trans **trans,
-       struct xfs_inode *dp,
-       struct xfs_buf  *bp,
-       int             level)
-{
-       xfs_da_blkinfo_t *info;
-       xfs_da_intnode_t *node;
-       xfs_dablk_t child_fsb;
-       xfs_daddr_t parent_blkno, child_blkno;
-       int error, i;
-       struct xfs_buf *child_bp;
-       struct xfs_da_node_entry *btree;
-       struct xfs_da3_icnode_hdr ichdr;
-
-       /*
-        * Since this code is recursive (gasp!) we must protect ourselves.
-        */
-       if (level > XFS_DA_NODE_MAXDEPTH) {
-               xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
-               return XFS_ERROR(EIO);
-       }
-
-       node = bp->b_addr;
-       xfs_da3_node_hdr_from_disk(&ichdr, node);
-       parent_blkno = bp->b_bn;
-       if (!ichdr.count) {
-               xfs_trans_brelse(*trans, bp);
-               return 0;
-       }
-       btree = xfs_da3_node_tree_p(node);
-       child_fsb = be32_to_cpu(btree[0].before);
-       xfs_trans_brelse(*trans, bp);   /* no locks for later trans */
-
-       /*
-        * If this is the node level just above the leaves, simply loop
-        * over the leaves removing all of them.  If this is higher up
-        * in the tree, recurse downward.
-        */
-       for (i = 0; i < ichdr.count; i++) {
-               /*
-                * Read the subsidiary block to see what we have to work with.
-                * Don't do this in a transaction.  This is a depth-first
-                * traversal of the tree so we may deal with many blocks
-                * before we come back to this one.
-                */
-               error = xfs_da3_node_read(*trans, dp, child_fsb, -2, &child_bp,
-                                               XFS_ATTR_FORK);
-               if (error)
-                       return(error);
-               if (child_bp) {
-                                               /* save for re-read later */
-                       child_blkno = XFS_BUF_ADDR(child_bp);
-
-                       /*
-                        * Invalidate the subtree, however we have to.
-                        */
-                       info = child_bp->b_addr;
-                       switch (info->magic) {
-                       case cpu_to_be16(XFS_DA_NODE_MAGIC):
-                       case cpu_to_be16(XFS_DA3_NODE_MAGIC):
-                               error = xfs_attr3_node_inactive(trans, dp,
-                                                       child_bp, level + 1);
-                               break;
-                       case cpu_to_be16(XFS_ATTR_LEAF_MAGIC):
-                       case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC):
-                               error = xfs_attr3_leaf_inactive(trans, dp,
-                                                       child_bp);
-                               break;
-                       default:
-                               error = XFS_ERROR(EIO);
-                               xfs_trans_brelse(*trans, child_bp);
-                               break;
-                       }
-                       if (error)
-                               return error;
-
-                       /*
-                        * Remove the subsidiary block from the cache
-                        * and from the log.
-                        */
-                       error = xfs_da_get_buf(*trans, dp, 0, child_blkno,
-                               &child_bp, XFS_ATTR_FORK);
-                       if (error)
-                               return error;
-                       xfs_trans_binval(*trans, child_bp);
-               }
-
-               /*
-                * If we're not done, re-read the parent to get the next
-                * child block number.
-                */
-               if (i + 1 < ichdr.count) {
-                       error = xfs_da3_node_read(*trans, dp, 0, parent_blkno,
-                                                &bp, XFS_ATTR_FORK);
-                       if (error)
-                               return error;
-                       child_fsb = be32_to_cpu(btree[i + 1].before);
-                       xfs_trans_brelse(*trans, bp);
-               }
-               /*
-                * Atomically commit the whole invalidate stuff.
-                */
-               error = xfs_trans_roll(trans, dp);
-               if (error)
-                       return  error;
-       }
-
-       return 0;
-}
-
-/*
- * Invalidate all of the "remote" value regions pointed to by a particular
- * leaf block.
- * Note that we must release the lock on the buffer so that we are not
- * caught holding something that the logging code wants to flush to disk.
- */
-STATIC int
-xfs_attr3_leaf_inactive(
-       struct xfs_trans        **trans,
-       struct xfs_inode        *dp,
-       struct xfs_buf          *bp)
-{
-       struct xfs_attr_leafblock *leaf;
-       struct xfs_attr3_icleaf_hdr ichdr;
-       struct xfs_attr_leaf_entry *entry;
-       struct xfs_attr_leaf_name_remote *name_rmt;
-       struct xfs_attr_inactive_list *list;
-       struct xfs_attr_inactive_list *lp;
-       int                     error;
-       int                     count;
-       int                     size;
-       int                     tmp;
-       int                     i;
-
-       leaf = bp->b_addr;
-       xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
-
-       /*
-        * Count the number of "remote" value extents.
-        */
-       count = 0;
-       entry = xfs_attr3_leaf_entryp(leaf);
-       for (i = 0; i < ichdr.count; entry++, i++) {
-               if (be16_to_cpu(entry->nameidx) &&
-                   ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
-                       name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
-                       if (name_rmt->valueblk)
-                               count++;
-               }
-       }
-
-       /*
-        * If there are no "remote" values, we're done.
-        */
-       if (count == 0) {
-               xfs_trans_brelse(*trans, bp);
-               return 0;
-       }
-
-       /*
-        * Allocate storage for a list of all the "remote" value extents.
-        */
-       size = count * sizeof(xfs_attr_inactive_list_t);
-       list = kmem_alloc(size, KM_SLEEP);
-
-       /*
-        * Identify each of the "remote" value extents.
-        */
-       lp = list;
-       entry = xfs_attr3_leaf_entryp(leaf);
-       for (i = 0; i < ichdr.count; entry++, i++) {
-               if (be16_to_cpu(entry->nameidx) &&
-                   ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
-                       name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
-                       if (name_rmt->valueblk) {
-                               lp->valueblk = be32_to_cpu(name_rmt->valueblk);
-                               lp->valuelen = xfs_attr3_rmt_blocks(dp->i_mount,
-                                                   be32_to_cpu(name_rmt->valuelen));
-                               lp++;
-                       }
-               }
-       }
-       xfs_trans_brelse(*trans, bp);   /* unlock for trans. in freextent() */
-
-       /*
-        * Invalidate each of the "remote" value extents.
-        */
-       error = 0;
-       for (lp = list, i = 0; i < count; i++, lp++) {
-               tmp = xfs_attr3_leaf_freextent(trans, dp,
-                               lp->valueblk, lp->valuelen);
-
-               if (error == 0)
-                       error = tmp;    /* save only the 1st errno */
-       }
-
-       kmem_free(list);
-       return error;
-}
-
-/*
- * Look at all the extents for this logical region,
- * invalidate any buffers that are incore/in transactions.
- */
-STATIC int
-xfs_attr3_leaf_freextent(
-       struct xfs_trans        **trans,
-       struct xfs_inode        *dp,
-       xfs_dablk_t             blkno,
-       int                     blkcnt)
-{
-       struct xfs_bmbt_irec    map;
-       struct xfs_buf          *bp;
-       xfs_dablk_t             tblkno;
-       xfs_daddr_t             dblkno;
-       int                     tblkcnt;
-       int                     dblkcnt;
-       int                     nmap;
-       int                     error;
-
-       /*
-        * Roll through the "value", invalidating the attribute value's
-        * blocks.
-        */
-       tblkno = blkno;
-       tblkcnt = blkcnt;
-       while (tblkcnt > 0) {
-               /*
-                * Try to remember where we decided to put the value.
-                */
-               nmap = 1;
-               error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt,
-                                      &map, &nmap, XFS_BMAPI_ATTRFORK);
-               if (error) {
-                       return(error);
-               }
-               ASSERT(nmap == 1);
-               ASSERT(map.br_startblock != DELAYSTARTBLOCK);
-
-               /*
-                * If it's a hole, these are already unmapped
-                * so there's nothing to invalidate.
-                */
-               if (map.br_startblock != HOLESTARTBLOCK) {
-
-                       dblkno = XFS_FSB_TO_DADDR(dp->i_mount,
-                                                 map.br_startblock);
-                       dblkcnt = XFS_FSB_TO_BB(dp->i_mount,
-                                               map.br_blockcount);
-                       bp = xfs_trans_get_buf(*trans,
-                                       dp->i_mount->m_ddev_targp,
-                                       dblkno, dblkcnt, 0);
-                       if (!bp)
-                               return ENOMEM;
-                       xfs_trans_binval(*trans, bp);
-                       /*
-                        * Roll to next transaction.
-                        */
-                       error = xfs_trans_roll(trans, dp);
-                       if (error)
-                               return (error);
-               }
-
-               tblkno += map.br_blockcount;
-               tblkcnt -= map.br_blockcount;
-       }
-
-       return(0);
-}
index 444a7704596c409f43f0ec495c9e6cc9838460c4..c1022138c7e6f3261819a0c52618b6bb1a9cf34f 100644 (file)
@@ -333,6 +333,8 @@ int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp,
                        struct xfs_buf **bpp);
 void   xfs_attr3_leaf_hdr_from_disk(struct xfs_attr3_icleaf_hdr *to,
                                     struct xfs_attr_leafblock *from);
+void   xfs_attr3_leaf_hdr_to_disk(struct xfs_attr_leafblock *to,
+                                  struct xfs_attr3_icleaf_hdr *from);
 
 extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops;
 
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
new file mode 100644 (file)
index 0000000..cbc80d4
--- /dev/null
@@ -0,0 +1,655 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2013 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_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_alloc.h"
+#include "xfs_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_attr_remote.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_inode_item.h"
+#include "xfs_bmap.h"
+#include "xfs_attr.h"
+#include "xfs_attr_leaf.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_buf_item.h"
+#include "xfs_cksum.h"
+
+STATIC int
+xfs_attr_shortform_compare(const void *a, const void *b)
+{
+       xfs_attr_sf_sort_t *sa, *sb;
+
+       sa = (xfs_attr_sf_sort_t *)a;
+       sb = (xfs_attr_sf_sort_t *)b;
+       if (sa->hash < sb->hash) {
+               return(-1);
+       } else if (sa->hash > sb->hash) {
+               return(1);
+       } else {
+               return(sa->entno - sb->entno);
+       }
+}
+
+#define XFS_ISRESET_CURSOR(cursor) \
+       (!((cursor)->initted) && !((cursor)->hashval) && \
+        !((cursor)->blkno) && !((cursor)->offset))
+/*
+ * Copy out entries of shortform attribute lists for attr_list().
+ * Shortform attribute lists are not stored in hashval sorted order.
+ * If the output buffer is not large enough to hold them all, then we
+ * we have to calculate each entries' hashvalue and sort them before
+ * we can begin returning them to the user.
+ */
+int
+xfs_attr_shortform_list(xfs_attr_list_context_t *context)
+{
+       attrlist_cursor_kern_t *cursor;
+       xfs_attr_sf_sort_t *sbuf, *sbp;
+       xfs_attr_shortform_t *sf;
+       xfs_attr_sf_entry_t *sfe;
+       xfs_inode_t *dp;
+       int sbsize, nsbuf, count, i;
+       int error;
+
+       ASSERT(context != NULL);
+       dp = context->dp;
+       ASSERT(dp != NULL);
+       ASSERT(dp->i_afp != NULL);
+       sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
+       ASSERT(sf != NULL);
+       if (!sf->hdr.count)
+               return(0);
+       cursor = context->cursor;
+       ASSERT(cursor != NULL);
+
+       trace_xfs_attr_list_sf(context);
+
+       /*
+        * If the buffer is large enough and the cursor is at the start,
+        * do not bother with sorting since we will return everything in
+        * one buffer and another call using the cursor won't need to be
+        * made.
+        * Note the generous fudge factor of 16 overhead bytes per entry.
+        * If bufsize is zero then put_listent must be a search function
+        * and can just scan through what we have.
+        */
+       if (context->bufsize == 0 ||
+           (XFS_ISRESET_CURSOR(cursor) &&
+             (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
+               for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
+                       error = context->put_listent(context,
+                                          sfe->flags,
+                                          sfe->nameval,
+                                          (int)sfe->namelen,
+                                          (int)sfe->valuelen,
+                                          &sfe->nameval[sfe->namelen]);
+
+                       /*
+                        * Either search callback finished early or
+                        * didn't fit it all in the buffer after all.
+                        */
+                       if (context->seen_enough)
+                               break;
+
+                       if (error)
+                               return error;
+                       sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+               }
+               trace_xfs_attr_list_sf_all(context);
+               return(0);
+       }
+
+       /* do no more for a search callback */
+       if (context->bufsize == 0)
+               return 0;
+
+       /*
+        * It didn't all fit, so we have to sort everything on hashval.
+        */
+       sbsize = sf->hdr.count * sizeof(*sbuf);
+       sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP | KM_NOFS);
+
+       /*
+        * Scan the attribute list for the rest of the entries, storing
+        * the relevant info from only those that match into a buffer.
+        */
+       nsbuf = 0;
+       for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
+               if (unlikely(
+                   ((char *)sfe < (char *)sf) ||
+                   ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
+                       XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
+                                            XFS_ERRLEVEL_LOW,
+                                            context->dp->i_mount, sfe);
+                       kmem_free(sbuf);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+
+               sbp->entno = i;
+               sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
+               sbp->name = sfe->nameval;
+               sbp->namelen = sfe->namelen;
+               /* These are bytes, and both on-disk, don't endian-flip */
+               sbp->valuelen = sfe->valuelen;
+               sbp->flags = sfe->flags;
+               sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
+               sbp++;
+               nsbuf++;
+       }
+
+       /*
+        * Sort the entries on hash then entno.
+        */
+       xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
+
+       /*
+        * Re-find our place IN THE SORTED LIST.
+        */
+       count = 0;
+       cursor->initted = 1;
+       cursor->blkno = 0;
+       for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
+               if (sbp->hash == cursor->hashval) {
+                       if (cursor->offset == count) {
+                               break;
+                       }
+                       count++;
+               } else if (sbp->hash > cursor->hashval) {
+                       break;
+               }
+       }
+       if (i == nsbuf) {
+               kmem_free(sbuf);
+               return(0);
+       }
+
+       /*
+        * Loop putting entries into the user buffer.
+        */
+       for ( ; i < nsbuf; i++, sbp++) {
+               if (cursor->hashval != sbp->hash) {
+                       cursor->hashval = sbp->hash;
+                       cursor->offset = 0;
+               }
+               error = context->put_listent(context,
+                                       sbp->flags,
+                                       sbp->name,
+                                       sbp->namelen,
+                                       sbp->valuelen,
+                                       &sbp->name[sbp->namelen]);
+               if (error)
+                       return error;
+               if (context->seen_enough)
+                       break;
+               cursor->offset++;
+       }
+
+       kmem_free(sbuf);
+       return(0);
+}
+
+STATIC int
+xfs_attr_node_list(xfs_attr_list_context_t *context)
+{
+       attrlist_cursor_kern_t *cursor;
+       xfs_attr_leafblock_t *leaf;
+       xfs_da_intnode_t *node;
+       struct xfs_attr3_icleaf_hdr leafhdr;
+       struct xfs_da3_icnode_hdr nodehdr;
+       struct xfs_da_node_entry *btree;
+       int error, i;
+       struct xfs_buf *bp;
+
+       trace_xfs_attr_node_list(context);
+
+       cursor = context->cursor;
+       cursor->initted = 1;
+
+       /*
+        * Do all sorts of validation on the passed-in cursor structure.
+        * If anything is amiss, ignore the cursor and look up the hashval
+        * starting from the btree root.
+        */
+       bp = NULL;
+       if (cursor->blkno > 0) {
+               error = xfs_da3_node_read(NULL, context->dp, cursor->blkno, -1,
+                                             &bp, XFS_ATTR_FORK);
+               if ((error != 0) && (error != EFSCORRUPTED))
+                       return(error);
+               if (bp) {
+                       struct xfs_attr_leaf_entry *entries;
+
+                       node = bp->b_addr;
+                       switch (be16_to_cpu(node->hdr.info.magic)) {
+                       case XFS_DA_NODE_MAGIC:
+                       case XFS_DA3_NODE_MAGIC:
+                               trace_xfs_attr_list_wrong_blk(context);
+                               xfs_trans_brelse(NULL, bp);
+                               bp = NULL;
+                               break;
+                       case XFS_ATTR_LEAF_MAGIC:
+                       case XFS_ATTR3_LEAF_MAGIC:
+                               leaf = bp->b_addr;
+                               xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
+                               entries = xfs_attr3_leaf_entryp(leaf);
+                               if (cursor->hashval > be32_to_cpu(
+                                               entries[leafhdr.count - 1].hashval)) {
+                                       trace_xfs_attr_list_wrong_blk(context);
+                                       xfs_trans_brelse(NULL, bp);
+                                       bp = NULL;
+                               } else if (cursor->hashval <= be32_to_cpu(
+                                               entries[0].hashval)) {
+                                       trace_xfs_attr_list_wrong_blk(context);
+                                       xfs_trans_brelse(NULL, bp);
+                                       bp = NULL;
+                               }
+                               break;
+                       default:
+                               trace_xfs_attr_list_wrong_blk(context);
+                               xfs_trans_brelse(NULL, bp);
+                               bp = NULL;
+                       }
+               }
+       }
+
+       /*
+        * We did not find what we expected given the cursor's contents,
+        * so we start from the top and work down based on the hash value.
+        * Note that start of node block is same as start of leaf block.
+        */
+       if (bp == NULL) {
+               cursor->blkno = 0;
+               for (;;) {
+                       __uint16_t magic;
+
+                       error = xfs_da3_node_read(NULL, context->dp,
+                                                     cursor->blkno, -1, &bp,
+                                                     XFS_ATTR_FORK);
+                       if (error)
+                               return(error);
+                       node = bp->b_addr;
+                       magic = be16_to_cpu(node->hdr.info.magic);
+                       if (magic == XFS_ATTR_LEAF_MAGIC ||
+                           magic == XFS_ATTR3_LEAF_MAGIC)
+                               break;
+                       if (magic != XFS_DA_NODE_MAGIC &&
+                           magic != XFS_DA3_NODE_MAGIC) {
+                               XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
+                                                    XFS_ERRLEVEL_LOW,
+                                                    context->dp->i_mount,
+                                                    node);
+                               xfs_trans_brelse(NULL, bp);
+                               return XFS_ERROR(EFSCORRUPTED);
+                       }
+
+                       xfs_da3_node_hdr_from_disk(&nodehdr, node);
+                       btree = xfs_da3_node_tree_p(node);
+                       for (i = 0; i < nodehdr.count; btree++, i++) {
+                               if (cursor->hashval
+                                               <= be32_to_cpu(btree->hashval)) {
+                                       cursor->blkno = be32_to_cpu(btree->before);
+                                       trace_xfs_attr_list_node_descend(context,
+                                                                        btree);
+                                       break;
+                               }
+                       }
+                       if (i == nodehdr.count) {
+                               xfs_trans_brelse(NULL, bp);
+                               return 0;
+                       }
+                       xfs_trans_brelse(NULL, bp);
+               }
+       }
+       ASSERT(bp != NULL);
+
+       /*
+        * Roll upward through the blocks, processing each leaf block in
+        * order.  As long as there is space in the result buffer, keep
+        * adding the information.
+        */
+       for (;;) {
+               leaf = bp->b_addr;
+               error = xfs_attr3_leaf_list_int(bp, context);
+               if (error) {
+                       xfs_trans_brelse(NULL, bp);
+                       return error;
+               }
+               xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
+               if (context->seen_enough || leafhdr.forw == 0)
+                       break;
+               cursor->blkno = leafhdr.forw;
+               xfs_trans_brelse(NULL, bp);
+               error = xfs_attr3_leaf_read(NULL, context->dp, cursor->blkno, -1,
+                                          &bp);
+               if (error)
+                       return error;
+       }
+       xfs_trans_brelse(NULL, bp);
+       return 0;
+}
+
+/*
+ * Copy out attribute list entries for attr_list(), for leaf attribute lists.
+ */
+int
+xfs_attr3_leaf_list_int(
+       struct xfs_buf                  *bp,
+       struct xfs_attr_list_context    *context)
+{
+       struct attrlist_cursor_kern     *cursor;
+       struct xfs_attr_leafblock       *leaf;
+       struct xfs_attr3_icleaf_hdr     ichdr;
+       struct xfs_attr_leaf_entry      *entries;
+       struct xfs_attr_leaf_entry      *entry;
+       int                             retval;
+       int                             i;
+
+       trace_xfs_attr_list_leaf(context);
+
+       leaf = bp->b_addr;
+       xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
+       entries = xfs_attr3_leaf_entryp(leaf);
+
+       cursor = context->cursor;
+       cursor->initted = 1;
+
+       /*
+        * Re-find our place in the leaf block if this is a new syscall.
+        */
+       if (context->resynch) {
+               entry = &entries[0];
+               for (i = 0; i < ichdr.count; entry++, i++) {
+                       if (be32_to_cpu(entry->hashval) == cursor->hashval) {
+                               if (cursor->offset == context->dupcnt) {
+                                       context->dupcnt = 0;
+                                       break;
+                               }
+                               context->dupcnt++;
+                       } else if (be32_to_cpu(entry->hashval) >
+                                       cursor->hashval) {
+                               context->dupcnt = 0;
+                               break;
+                       }
+               }
+               if (i == ichdr.count) {
+                       trace_xfs_attr_list_notfound(context);
+                       return 0;
+               }
+       } else {
+               entry = &entries[0];
+               i = 0;
+       }
+       context->resynch = 0;
+
+       /*
+        * We have found our place, start copying out the new attributes.
+        */
+       retval = 0;
+       for (; i < ichdr.count; entry++, i++) {
+               if (be32_to_cpu(entry->hashval) != cursor->hashval) {
+                       cursor->hashval = be32_to_cpu(entry->hashval);
+                       cursor->offset = 0;
+               }
+
+               if (entry->flags & XFS_ATTR_INCOMPLETE)
+                       continue;               /* skip incomplete entries */
+
+               if (entry->flags & XFS_ATTR_LOCAL) {
+                       xfs_attr_leaf_name_local_t *name_loc =
+                               xfs_attr3_leaf_name_local(leaf, i);
+
+                       retval = context->put_listent(context,
+                                               entry->flags,
+                                               name_loc->nameval,
+                                               (int)name_loc->namelen,
+                                               be16_to_cpu(name_loc->valuelen),
+                                               &name_loc->nameval[name_loc->namelen]);
+                       if (retval)
+                               return retval;
+               } else {
+                       xfs_attr_leaf_name_remote_t *name_rmt =
+                               xfs_attr3_leaf_name_remote(leaf, i);
+
+                       int valuelen = be32_to_cpu(name_rmt->valuelen);
+
+                       if (context->put_value) {
+                               xfs_da_args_t args;
+
+                               memset((char *)&args, 0, sizeof(args));
+                               args.dp = context->dp;
+                               args.whichfork = XFS_ATTR_FORK;
+                               args.valuelen = valuelen;
+                               args.value = kmem_alloc(valuelen, KM_SLEEP | KM_NOFS);
+                               args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
+                               args.rmtblkcnt = xfs_attr3_rmt_blocks(
+                                                       args.dp->i_mount, valuelen);
+                               retval = xfs_attr_rmtval_get(&args);
+                               if (retval)
+                                       return retval;
+                               retval = context->put_listent(context,
+                                               entry->flags,
+                                               name_rmt->name,
+                                               (int)name_rmt->namelen,
+                                               valuelen,
+                                               args.value);
+                               kmem_free(args.value);
+                       } else {
+                               retval = context->put_listent(context,
+                                               entry->flags,
+                                               name_rmt->name,
+                                               (int)name_rmt->namelen,
+                                               valuelen,
+                                               NULL);
+                       }
+                       if (retval)
+                               return retval;
+               }
+               if (context->seen_enough)
+                       break;
+               cursor->offset++;
+       }
+       trace_xfs_attr_list_leaf_end(context);
+       return retval;
+}
+
+/*
+ * Copy out attribute entries for attr_list(), for leaf attribute lists.
+ */
+STATIC int
+xfs_attr_leaf_list(xfs_attr_list_context_t *context)
+{
+       int error;
+       struct xfs_buf *bp;
+
+       trace_xfs_attr_leaf_list(context);
+
+       context->cursor->blkno = 0;
+       error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp);
+       if (error)
+               return XFS_ERROR(error);
+
+       error = xfs_attr3_leaf_list_int(bp, context);
+       xfs_trans_brelse(NULL, bp);
+       return XFS_ERROR(error);
+}
+
+int
+xfs_attr_list_int(
+       xfs_attr_list_context_t *context)
+{
+       int error;
+       xfs_inode_t *dp = context->dp;
+
+       XFS_STATS_INC(xs_attr_list);
+
+       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
+               return EIO;
+
+       xfs_ilock(dp, XFS_ILOCK_SHARED);
+
+       /*
+        * Decide on what work routines to call based on the inode size.
+        */
+       if (!xfs_inode_hasattr(dp)) {
+               error = 0;
+       } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+               error = xfs_attr_shortform_list(context);
+       } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+               error = xfs_attr_leaf_list(context);
+       } else {
+               error = xfs_attr_node_list(context);
+       }
+
+       xfs_iunlock(dp, XFS_ILOCK_SHARED);
+
+       return error;
+}
+
+#define        ATTR_ENTBASESIZE                /* minimum bytes used by an attr */ \
+       (((struct attrlist_ent *) 0)->a_name - (char *) 0)
+#define        ATTR_ENTSIZE(namelen)           /* actual bytes used by an attr */ \
+       ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
+        & ~(sizeof(u_int32_t)-1))
+
+/*
+ * Format an attribute and copy it out to the user's buffer.
+ * Take care to check values and protect against them changing later,
+ * we may be reading them directly out of a user buffer.
+ */
+STATIC int
+xfs_attr_put_listent(
+       xfs_attr_list_context_t *context,
+       int             flags,
+       unsigned char   *name,
+       int             namelen,
+       int             valuelen,
+       unsigned char   *value)
+{
+       struct attrlist *alist = (struct attrlist *)context->alist;
+       attrlist_ent_t *aep;
+       int arraytop;
+
+       ASSERT(!(context->flags & ATTR_KERNOVAL));
+       ASSERT(context->count >= 0);
+       ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
+       ASSERT(context->firstu >= sizeof(*alist));
+       ASSERT(context->firstu <= context->bufsize);
+
+       /*
+        * Only list entries in the right namespace.
+        */
+       if (((context->flags & ATTR_SECURE) == 0) !=
+           ((flags & XFS_ATTR_SECURE) == 0))
+               return 0;
+       if (((context->flags & ATTR_ROOT) == 0) !=
+           ((flags & XFS_ATTR_ROOT) == 0))
+               return 0;
+
+       arraytop = sizeof(*alist) +
+                       context->count * sizeof(alist->al_offset[0]);
+       context->firstu -= ATTR_ENTSIZE(namelen);
+       if (context->firstu < arraytop) {
+               trace_xfs_attr_list_full(context);
+               alist->al_more = 1;
+               context->seen_enough = 1;
+               return 1;
+       }
+
+       aep = (attrlist_ent_t *)&context->alist[context->firstu];
+       aep->a_valuelen = valuelen;
+       memcpy(aep->a_name, name, namelen);
+       aep->a_name[namelen] = 0;
+       alist->al_offset[context->count++] = context->firstu;
+       alist->al_count = context->count;
+       trace_xfs_attr_list_add(context);
+       return 0;
+}
+
+/*
+ * Generate a list of extended attribute names and optionally
+ * also value lengths.  Positive return value follows the XFS
+ * convention of being an error, zero or negative return code
+ * is the length of the buffer returned (negated), indicating
+ * success.
+ */
+int
+xfs_attr_list(
+       xfs_inode_t     *dp,
+       char            *buffer,
+       int             bufsize,
+       int             flags,
+       attrlist_cursor_kern_t *cursor)
+{
+       xfs_attr_list_context_t context;
+       struct attrlist *alist;
+       int error;
+
+       /*
+        * Validate the cursor.
+        */
+       if (cursor->pad1 || cursor->pad2)
+               return(XFS_ERROR(EINVAL));
+       if ((cursor->initted == 0) &&
+           (cursor->hashval || cursor->blkno || cursor->offset))
+               return XFS_ERROR(EINVAL);
+
+       /*
+        * Check for a properly aligned buffer.
+        */
+       if (((long)buffer) & (sizeof(int)-1))
+               return XFS_ERROR(EFAULT);
+       if (flags & ATTR_KERNOVAL)
+               bufsize = 0;
+
+       /*
+        * Initialize the output buffer.
+        */
+       memset(&context, 0, sizeof(context));
+       context.dp = dp;
+       context.cursor = cursor;
+       context.resynch = 1;
+       context.flags = flags;
+       context.alist = buffer;
+       context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
+       context.firstu = context.bufsize;
+       context.put_listent = xfs_attr_put_listent;
+
+       alist = (struct attrlist *)context.alist;
+       alist->al_count = 0;
+       alist->al_more = 0;
+       alist->al_offset[0] = context.bufsize;
+
+       error = xfs_attr_list_int(&context);
+       ASSERT(error >= 0);
+       return error;
+}
index ef6b0c124528f6bff8d59c0fee5fa31a1d5dcc8b..712a502de619b097df202f744ba481bd3471847d 100644 (file)
@@ -22,6 +22,7 @@
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
+#include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
@@ -33,6 +34,7 @@
 #include "xfs_alloc.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_attr_remote.h"
@@ -237,7 +239,7 @@ xfs_attr_rmtval_copyout(
        xfs_ino_t       ino,
        int             *offset,
        int             *valuelen,
-       char            **dst)
+       __uint8_t       **dst)
 {
        char            *src = bp->b_addr;
        xfs_daddr_t     bno = bp->b_bn;
@@ -249,7 +251,7 @@ xfs_attr_rmtval_copyout(
                int hdr_size = 0;
                int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, XFS_LBSIZE(mp));
 
-               byte_cnt = min_t(int, *valuelen, byte_cnt);
+               byte_cnt = min(*valuelen, byte_cnt);
 
                if (xfs_sb_version_hascrc(&mp->m_sb)) {
                        if (!xfs_attr3_rmt_hdr_ok(mp, src, ino, *offset,
@@ -284,7 +286,7 @@ xfs_attr_rmtval_copyin(
        xfs_ino_t       ino,
        int             *offset,
        int             *valuelen,
-       char            **src)
+       __uint8_t       **src)
 {
        char            *dst = bp->b_addr;
        xfs_daddr_t     bno = bp->b_bn;
@@ -337,7 +339,7 @@ xfs_attr_rmtval_get(
        struct xfs_mount        *mp = args->dp->i_mount;
        struct xfs_buf          *bp;
        xfs_dablk_t             lblkno = args->rmtblkno;
-       char                    *dst = args->value;
+       __uint8_t               *dst = args->value;
        int                     valuelen = args->valuelen;
        int                     nmap;
        int                     error;
@@ -401,7 +403,7 @@ xfs_attr_rmtval_set(
        struct xfs_bmbt_irec    map;
        xfs_dablk_t             lblkno;
        xfs_fileoff_t           lfileoff = 0;
-       char                    *src = args->value;
+       __uint8_t               *src = args->value;
        int                     blkcnt;
        int                     valuelen;
        int                     nmap;
@@ -543,11 +545,6 @@ xfs_attr_rmtval_remove(
 
        /*
         * Roll through the "value", invalidating the attribute value's blocks.
-        * Note that args->rmtblkcnt is the minimum number of data blocks we'll
-        * see for a CRC enabled remote attribute. Each extent will have a
-        * header, and so we may have more blocks than we realise here.  If we
-        * fail to map the blocks correctly, we'll have problems with the buffer
-        * lookups.
         */
        lblkno = args->rmtblkno;
        blkcnt = args->rmtblkcnt;
@@ -628,4 +625,3 @@ xfs_attr_rmtval_remove(
        }
        return(0);
 }
-
index 05c698ccb238f4fa9eef9a1844683fe24f62bd13..f47e65c30be6ddde5caa276d3262540d603d07dc 100644 (file)
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
@@ -39,6 +40,7 @@
 #include "xfs_extfree_item.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_attr_leaf.h"
@@ -46,7 +48,6 @@
 #include "xfs_trans_space.h"
 #include "xfs_buf_item.h"
 #include "xfs_filestream.h"
-#include "xfs_vnodeops.h"
 #include "xfs_trace.h"
 #include "xfs_symlink.h"
 
@@ -108,19 +109,6 @@ xfs_bmap_compute_maxlevels(
        mp->m_bm_maxlevels[whichfork] = level;
 }
 
-/*
- * Convert the given file system block to a disk block.  We have to treat it
- * differently based on whether the file is a real time file or not, because the
- * bmap code does.
- */
-xfs_daddr_t
-xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
-{
-       return (XFS_IS_REALTIME_INODE(ip) ? \
-                (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \
-                XFS_FSB_TO_DADDR((ip)->i_mount, (fsb)));
-}
-
 STATIC int                             /* error */
 xfs_bmbt_lookup_eq(
        struct xfs_btree_cur    *cur,
@@ -262,173 +250,6 @@ xfs_bmap_forkoff_reset(
        }
 }
 
-/*
- * Extent tree block counting routines.
- */
-
-/*
- * Count leaf blocks given a range of extent records.
- */
-STATIC void
-xfs_bmap_count_leaves(
-       xfs_ifork_t             *ifp,
-       xfs_extnum_t            idx,
-       int                     numrecs,
-       int                     *count)
-{
-       int             b;
-
-       for (b = 0; b < numrecs; b++) {
-               xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, idx + b);
-               *count += xfs_bmbt_get_blockcount(frp);
-       }
-}
-
-/*
- * Count leaf blocks given a range of extent records originally
- * in btree format.
- */
-STATIC void
-xfs_bmap_disk_count_leaves(
-       struct xfs_mount        *mp,
-       struct xfs_btree_block  *block,
-       int                     numrecs,
-       int                     *count)
-{
-       int             b;
-       xfs_bmbt_rec_t  *frp;
-
-       for (b = 1; b <= numrecs; b++) {
-               frp = XFS_BMBT_REC_ADDR(mp, block, b);
-               *count += xfs_bmbt_disk_get_blockcount(frp);
-       }
-}
-
-/*
- * Recursively walks each level of a btree
- * to count total fsblocks is use.
- */
-STATIC int                                     /* error */
-xfs_bmap_count_tree(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_fsblock_t   blockno,        /* file system block number */
-       int             levelin,        /* level in btree */
-       int             *count)         /* Count of blocks */
-{
-       int                     error;
-       xfs_buf_t               *bp, *nbp;
-       int                     level = levelin;
-       __be64                  *pp;
-       xfs_fsblock_t           bno = blockno;
-       xfs_fsblock_t           nextbno;
-       struct xfs_btree_block  *block, *nextblock;
-       int                     numrecs;
-
-       error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF,
-                                               &xfs_bmbt_buf_ops);
-       if (error)
-               return error;
-       *count += 1;
-       block = XFS_BUF_TO_BLOCK(bp);
-
-       if (--level) {
-               /* Not at node above leaves, count this level of nodes */
-               nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
-               while (nextbno != NULLFSBLOCK) {
-                       error = xfs_btree_read_bufl(mp, tp, nextbno, 0, &nbp,
-                                               XFS_BMAP_BTREE_REF,
-                                               &xfs_bmbt_buf_ops);
-                       if (error)
-                               return error;
-                       *count += 1;
-                       nextblock = XFS_BUF_TO_BLOCK(nbp);
-                       nextbno = be64_to_cpu(nextblock->bb_u.l.bb_rightsib);
-                       xfs_trans_brelse(tp, nbp);
-               }
-
-               /* Dive to the next level */
-               pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
-               bno = be64_to_cpu(*pp);
-               if (unlikely((error =
-                    xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
-                       xfs_trans_brelse(tp, bp);
-                       XFS_ERROR_REPORT("xfs_bmap_count_tree(1)",
-                                        XFS_ERRLEVEL_LOW, mp);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-               xfs_trans_brelse(tp, bp);
-       } else {
-               /* count all level 1 nodes and their leaves */
-               for (;;) {
-                       nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
-                       numrecs = be16_to_cpu(block->bb_numrecs);
-                       xfs_bmap_disk_count_leaves(mp, block, numrecs, count);
-                       xfs_trans_brelse(tp, bp);
-                       if (nextbno == NULLFSBLOCK)
-                               break;
-                       bno = nextbno;
-                       error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
-                                               XFS_BMAP_BTREE_REF,
-                                               &xfs_bmbt_buf_ops);
-                       if (error)
-                               return error;
-                       *count += 1;
-                       block = XFS_BUF_TO_BLOCK(bp);
-               }
-       }
-       return 0;
-}
-
-/*
- * Count fsblocks of the given fork.
- */
-int                                            /* error */
-xfs_bmap_count_blocks(
-       xfs_trans_t             *tp,            /* transaction pointer */
-       xfs_inode_t             *ip,            /* incore inode */
-       int                     whichfork,      /* data or attr fork */
-       int                     *count)         /* out: count of blocks */
-{
-       struct xfs_btree_block  *block; /* current btree block */
-       xfs_fsblock_t           bno;    /* block # of "block" */
-       xfs_ifork_t             *ifp;   /* fork structure */
-       int                     level;  /* btree level, for checking */
-       xfs_mount_t             *mp;    /* file system mount structure */
-       __be64                  *pp;    /* pointer to block address */
-
-       bno = NULLFSBLOCK;
-       mp = ip->i_mount;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) {
-               xfs_bmap_count_leaves(ifp, 0,
-                       ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t),
-                       count);
-               return 0;
-       }
-
-       /*
-        * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
-        */
-       block = ifp->if_broot;
-       level = be16_to_cpu(block->bb_level);
-       ASSERT(level > 0);
-       pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
-       bno = be64_to_cpu(*pp);
-       ASSERT(bno != NULLDFSBNO);
-       ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
-       ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
-
-       if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
-               XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
-                                mp);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       return 0;
-}
-
 /*
  * Debug/sanity checking code
  */
@@ -724,8 +545,8 @@ xfs_bmap_trace_exlist(
 
 /*
  * Validate that the bmbt_irecs being returned from bmapi are valid
- * given the callers original parameters.  Specifically check the
- * ranges of the returned irecs to ensure that they only extent beyond
+ * given the caller's original parameters.  Specifically check the
+ * ranges of the returned irecs to ensure that they only extend beyond
  * the given parameters if the XFS_BMAPI_ENTIRE flag was set.
  */
 STATIC void
@@ -823,7 +644,7 @@ xfs_bmap_add_free(
  * Remove the entry "free" from the free item list.  Prev points to the
  * previous entry, unless "free" is the head of the list.
  */
-STATIC void
+void
 xfs_bmap_del_free(
        xfs_bmap_free_t         *flist, /* free item list header */
        xfs_bmap_free_item_t    *prev,  /* previous item on list, if any */
@@ -837,92 +658,6 @@ xfs_bmap_del_free(
        kmem_zone_free(xfs_bmap_free_item_zone, free);
 }
 
-
-/*
- * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
- * caller.  Frees all the extents that need freeing, which must be done
- * last due to locking considerations.  We never free any extents in
- * the first transaction.
- *
- * Return 1 if the given transaction was committed and a new one
- * started, and 0 otherwise in the committed parameter.
- */
-int                                            /* error */
-xfs_bmap_finish(
-       xfs_trans_t             **tp,           /* transaction pointer addr */
-       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
-       int                     *committed)     /* xact committed or not */
-{
-       xfs_efd_log_item_t      *efd;           /* extent free data */
-       xfs_efi_log_item_t      *efi;           /* extent free intention */
-       int                     error;          /* error return value */
-       xfs_bmap_free_item_t    *free;          /* free extent item */
-       unsigned int            logres;         /* new log reservation */
-       unsigned int            logcount;       /* new log count */
-       xfs_mount_t             *mp;            /* filesystem mount structure */
-       xfs_bmap_free_item_t    *next;          /* next item on free list */
-       xfs_trans_t             *ntp;           /* new transaction pointer */
-
-       ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
-       if (flist->xbf_count == 0) {
-               *committed = 0;
-               return 0;
-       }
-       ntp = *tp;
-       efi = xfs_trans_get_efi(ntp, flist->xbf_count);
-       for (free = flist->xbf_first; free; free = free->xbfi_next)
-               xfs_trans_log_efi_extent(ntp, efi, free->xbfi_startblock,
-                       free->xbfi_blockcount);
-       logres = ntp->t_log_res;
-       logcount = ntp->t_log_count;
-       ntp = xfs_trans_dup(*tp);
-       error = xfs_trans_commit(*tp, 0);
-       *tp = ntp;
-       *committed = 1;
-       /*
-        * We have a new transaction, so we should return committed=1,
-        * even though we're returning an error.
-        */
-       if (error)
-               return error;
-
-       /*
-        * transaction commit worked ok so we can drop the extra ticket
-        * reference that we gained in xfs_trans_dup()
-        */
-       xfs_log_ticket_put(ntp->t_ticket);
-
-       if ((error = xfs_trans_reserve(ntp, 0, logres, 0, XFS_TRANS_PERM_LOG_RES,
-                       logcount)))
-               return error;
-       efd = xfs_trans_get_efd(ntp, efi, flist->xbf_count);
-       for (free = flist->xbf_first; free != NULL; free = next) {
-               next = free->xbfi_next;
-               if ((error = xfs_free_extent(ntp, free->xbfi_startblock,
-                               free->xbfi_blockcount))) {
-                       /*
-                        * The bmap free list will be cleaned up at a
-                        * higher level.  The EFI will be canceled when
-                        * this transaction is aborted.
-                        * Need to force shutdown here to make sure it
-                        * happens, since this transaction may not be
-                        * dirty yet.
-                        */
-                       mp = ntp->t_mountp;
-                       if (!XFS_FORCED_SHUTDOWN(mp))
-                               xfs_force_shutdown(mp,
-                                                  (error == EFSCORRUPTED) ?
-                                                  SHUTDOWN_CORRUPT_INCORE :
-                                                  SHUTDOWN_META_IO_ERROR);
-                       return error;
-               }
-               xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock,
-                       free->xbfi_blockcount);
-               xfs_bmap_del_free(flist, NULL, free);
-       }
-       return 0;
-}
-
 /*
  * Free up any items left in the list.
  */
@@ -1413,8 +1148,8 @@ xfs_bmap_add_attrfork(
        blks = XFS_ADDAFORK_SPACE_RES(mp);
        if (rsvd)
                tp->t_flags |= XFS_TRANS_RESERVE;
-       if ((error = xfs_trans_reserve(tp, blks, XFS_ADDAFORK_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_ADDAFORK_LOG_COUNT)))
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_addafork, blks, 0);
+       if (error)
                goto error0;
        xfs_ilock(ip, XFS_ILOCK_EXCL);
        error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ?
@@ -1815,7 +1550,7 @@ xfs_bmap_first_unused(
 }
 
 /*
- * Returns the file-relative block number of the last block + 1 before
+ * Returns the file-relative block number of the last block - 1 before
  * last_block (input value) in the file.
  * This is not based on i_size, it is based on the extent records.
  * Returns 0 for local files, as they do not have extent records.
@@ -1863,7 +1598,7 @@ xfs_bmap_last_before(
        return 0;
 }
 
-STATIC int
+int
 xfs_bmap_last_extent(
        struct xfs_trans        *tp,
        struct xfs_inode        *ip,
@@ -1926,29 +1661,6 @@ xfs_bmap_isaeof(
        return 0;
 }
 
-/*
- * Check if the endoff is outside the last extent. If so the caller will grow
- * the allocation to a stripe unit boundary.  All offsets are considered outside
- * the end of file for an empty fork, so 1 is returned in *eof in that case.
- */
-int
-xfs_bmap_eof(
-       struct xfs_inode        *ip,
-       xfs_fileoff_t           endoff,
-       int                     whichfork,
-       int                     *eof)
-{
-       struct xfs_bmbt_irec    rec;
-       int                     error;
-
-       error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof);
-       if (error || *eof)
-               return error;
-
-       *eof = endoff >= rec.br_startoff + rec.br_blockcount;
-       return 0;
-}
-
 /*
  * Returns the file-relative block number of the first block past eof in
  * the file.  This is not based on i_size, it is based on the extent records.
@@ -3488,7 +3200,7 @@ done:
 /*
  * Adjust the size of the new extent based on di_extsize and rt extsize.
  */
-STATIC int
+int
 xfs_bmap_extsize_align(
        xfs_mount_t     *mp,
        xfs_bmbt_irec_t *gotp,          /* next extent pointer */
@@ -3650,9 +3362,9 @@ xfs_bmap_extsize_align(
 
 #define XFS_ALLOC_GAP_UNITS    4
 
-STATIC void
+void
 xfs_bmap_adjacent(
-       xfs_bmalloca_t  *ap)            /* bmap alloc argument struct */
+       struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
 {
        xfs_fsblock_t   adjust;         /* adjustment to block numbers */
        xfs_agnumber_t  fb_agno;        /* ag number of ap->firstblock */
@@ -3798,109 +3510,6 @@ xfs_bmap_adjacent(
 #undef ISVALID
 }
 
-STATIC int
-xfs_bmap_rtalloc(
-       xfs_bmalloca_t  *ap)            /* bmap alloc argument struct */
-{
-       xfs_alloctype_t atype = 0;      /* type for allocation routines */
-       int             error;          /* error return value */
-       xfs_mount_t     *mp;            /* mount point structure */
-       xfs_extlen_t    prod = 0;       /* product factor for allocators */
-       xfs_extlen_t    ralen = 0;      /* realtime allocation length */
-       xfs_extlen_t    align;          /* minimum allocation alignment */
-       xfs_rtblock_t   rtb;
-
-       mp = ap->ip->i_mount;
-       align = xfs_get_extsz_hint(ap->ip);
-       prod = align / mp->m_sb.sb_rextsize;
-       error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
-                                       align, 1, ap->eof, 0,
-                                       ap->conv, &ap->offset, &ap->length);
-       if (error)
-               return error;
-       ASSERT(ap->length);
-       ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
-
-       /*
-        * If the offset & length are not perfectly aligned
-        * then kill prod, it will just get us in trouble.
-        */
-       if (do_mod(ap->offset, align) || ap->length % align)
-               prod = 1;
-       /*
-        * Set ralen to be the actual requested length in rtextents.
-        */
-       ralen = ap->length / mp->m_sb.sb_rextsize;
-       /*
-        * If the old value was close enough to MAXEXTLEN that
-        * we rounded up to it, cut it back so it's valid again.
-        * Note that if it's a really large request (bigger than
-        * MAXEXTLEN), we don't hear about that number, and can't
-        * adjust the starting point to match it.
-        */
-       if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN)
-               ralen = MAXEXTLEN / mp->m_sb.sb_rextsize;
-
-       /*
-        * Lock out other modifications to the RT bitmap inode.
-        */
-       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
-
-       /*
-        * If it's an allocation to an empty file at offset 0,
-        * pick an extent that will space things out in the rt area.
-        */
-       if (ap->eof && ap->offset == 0) {
-               xfs_rtblock_t uninitialized_var(rtx); /* realtime extent no */
-
-               error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
-               if (error)
-                       return error;
-               ap->blkno = rtx * mp->m_sb.sb_rextsize;
-       } else {
-               ap->blkno = 0;
-       }
-
-       xfs_bmap_adjacent(ap);
-
-       /*
-        * Realtime allocation, done through xfs_rtallocate_extent.
-        */
-       atype = ap->blkno == 0 ?  XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO;
-       do_div(ap->blkno, mp->m_sb.sb_rextsize);
-       rtb = ap->blkno;
-       ap->length = ralen;
-       if ((error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length,
-                               &ralen, atype, ap->wasdel, prod, &rtb)))
-               return error;
-       if (rtb == NULLFSBLOCK && prod > 1 &&
-           (error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1,
-                                          ap->length, &ralen, atype,
-                                          ap->wasdel, 1, &rtb)))
-               return error;
-       ap->blkno = rtb;
-       if (ap->blkno != NULLFSBLOCK) {
-               ap->blkno *= mp->m_sb.sb_rextsize;
-               ralen *= mp->m_sb.sb_rextsize;
-               ap->length = ralen;
-               ap->ip->i_d.di_nblocks += ralen;
-               xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
-               if (ap->wasdel)
-                       ap->ip->i_delayed_blks -= ralen;
-               /*
-                * Adjust the disk quota also. This was reserved
-                * earlier.
-                */
-               xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
-                       ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
-                                       XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
-       } else {
-               ap->length = 0;
-       }
-       return 0;
-}
-
 STATIC int
 xfs_bmap_btalloc_nullfb(
        struct xfs_bmalloca     *ap,
@@ -4018,7 +3627,7 @@ xfs_bmap_btalloc_nullfb(
 
 STATIC int
 xfs_bmap_btalloc(
-       xfs_bmalloca_t  *ap)            /* bmap alloc argument struct */
+       struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
 {
        xfs_mount_t     *mp;            /* mount point structure */
        xfs_alloctype_t atype = 0;      /* type for allocation routines */
@@ -4250,7 +3859,7 @@ xfs_bmap_btalloc(
  */
 STATIC int
 xfs_bmap_alloc(
-       xfs_bmalloca_t  *ap)            /* bmap alloc argument struct */
+       struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
 {
        if (XFS_IS_REALTIME_INODE(ap->ip) && ap->userdata)
                return xfs_bmap_rtalloc(ap);
@@ -4638,7 +4247,7 @@ xfs_bmapi_delay(
 }
 
 
-STATIC int
+int
 __xfs_bmapi_allocate(
        struct xfs_bmalloca     *bma)
 {
@@ -4648,12 +4257,9 @@ __xfs_bmapi_allocate(
        struct xfs_ifork        *ifp = XFS_IFORK_PTR(bma->ip, whichfork);
        int                     tmp_logflags = 0;
        int                     error;
-       int                     rt;
 
        ASSERT(bma->length > 0);
 
-       rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(bma->ip);
-
        /*
         * For the wasdelay case, we could also just allocate the stuff asked
         * for in this bmap call but that wouldn't be as good.
@@ -4756,45 +4362,6 @@ __xfs_bmapi_allocate(
        return 0;
 }
 
-static void
-xfs_bmapi_allocate_worker(
-       struct work_struct      *work)
-{
-       struct xfs_bmalloca     *args = container_of(work,
-                                               struct xfs_bmalloca, work);
-       unsigned long           pflags;
-
-       /* we are in a transaction context here */
-       current_set_flags_nested(&pflags, PF_FSTRANS);
-
-       args->result = __xfs_bmapi_allocate(args);
-       complete(args->done);
-
-       current_restore_flags_nested(&pflags, PF_FSTRANS);
-}
-
-/*
- * Some allocation requests often come in with little stack to work on. Push
- * them off to a worker thread so there is lots of stack to use. Otherwise just
- * call directly to avoid the context switch overhead here.
- */
-int
-xfs_bmapi_allocate(
-       struct xfs_bmalloca     *args)
-{
-       DECLARE_COMPLETION_ONSTACK(done);
-
-       if (!args->stack_switch)
-               return __xfs_bmapi_allocate(args);
-
-
-       args->done = &done;
-       INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker);
-       queue_work(xfs_alloc_wq, &args->work);
-       wait_for_completion(&done);
-       return args->result;
-}
-
 STATIC int
 xfs_bmapi_convert_unwritten(
        struct xfs_bmalloca     *bma,
@@ -4883,7 +4450,7 @@ xfs_bmapi_write(
 {
        struct xfs_mount        *mp = ip->i_mount;
        struct xfs_ifork        *ifp;
-       struct xfs_bmalloca     bma = { 0 };    /* args for xfs_bmap_alloc */
+       struct xfs_bmalloca     bma = { NULL }; /* args for xfs_bmap_alloc */
        xfs_fileoff_t           end;            /* end of mapped file region */
        int                     eof;            /* after the end of extents */
        int                     error;          /* error return */
@@ -5789,359 +5356,3 @@ error0:
        }
        return error;
 }
-
-/*
- * returns 1 for success, 0 if we failed to map the extent.
- */
-STATIC int
-xfs_getbmapx_fix_eof_hole(
-       xfs_inode_t             *ip,            /* xfs incore inode pointer */
-       struct getbmapx         *out,           /* output structure */
-       int                     prealloced,     /* this is a file with
-                                                * preallocated data space */
-       __int64_t               end,            /* last block requested */
-       xfs_fsblock_t           startblock)
-{
-       __int64_t               fixlen;
-       xfs_mount_t             *mp;            /* file system mount point */
-       xfs_ifork_t             *ifp;           /* inode fork pointer */
-       xfs_extnum_t            lastx;          /* last extent pointer */
-       xfs_fileoff_t           fileblock;
-
-       if (startblock == HOLESTARTBLOCK) {
-               mp = ip->i_mount;
-               out->bmv_block = -1;
-               fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, XFS_ISIZE(ip)));
-               fixlen -= out->bmv_offset;
-               if (prealloced && out->bmv_offset + out->bmv_length == end) {
-                       /* Came to hole at EOF. Trim it. */
-                       if (fixlen <= 0)
-                               return 0;
-                       out->bmv_length = fixlen;
-               }
-       } else {
-               if (startblock == DELAYSTARTBLOCK)
-                       out->bmv_block = -2;
-               else
-                       out->bmv_block = xfs_fsb_to_db(ip, startblock);
-               fileblock = XFS_BB_TO_FSB(ip->i_mount, out->bmv_offset);
-               ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
-               if (xfs_iext_bno_to_ext(ifp, fileblock, &lastx) &&
-                  (lastx == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))-1))
-                       out->bmv_oflags |= BMV_OF_LAST;
-       }
-
-       return 1;
-}
-
-/*
- * Get inode's extents as described in bmv, and format for output.
- * Calls formatter to fill the user's buffer until all extents
- * are mapped, until the passed-in bmv->bmv_count slots have
- * been filled, or until the formatter short-circuits the loop,
- * if it is tracking filled-in extents on its own.
- */
-int                                            /* error code */
-xfs_getbmap(
-       xfs_inode_t             *ip,
-       struct getbmapx         *bmv,           /* user bmap structure */
-       xfs_bmap_format_t       formatter,      /* format to user */
-       void                    *arg)           /* formatter arg */
-{
-       __int64_t               bmvend;         /* last block requested */
-       int                     error = 0;      /* return value */
-       __int64_t               fixlen;         /* length for -1 case */
-       int                     i;              /* extent number */
-       int                     lock;           /* lock state */
-       xfs_bmbt_irec_t         *map;           /* buffer for user's data */
-       xfs_mount_t             *mp;            /* file system mount point */
-       int                     nex;            /* # of user extents can do */
-       int                     nexleft;        /* # of user extents left */
-       int                     subnex;         /* # of bmapi's can do */
-       int                     nmap;           /* number of map entries */
-       struct getbmapx         *out;           /* output structure */
-       int                     whichfork;      /* data or attr fork */
-       int                     prealloced;     /* this is a file with
-                                                * preallocated data space */
-       int                     iflags;         /* interface flags */
-       int                     bmapi_flags;    /* flags for xfs_bmapi */
-       int                     cur_ext = 0;
-
-       mp = ip->i_mount;
-       iflags = bmv->bmv_iflags;
-       whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
-
-       if (whichfork == XFS_ATTR_FORK) {
-               if (XFS_IFORK_Q(ip)) {
-                       if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS &&
-                           ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE &&
-                           ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)
-                               return XFS_ERROR(EINVAL);
-               } else if (unlikely(
-                          ip->i_d.di_aformat != 0 &&
-                          ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS)) {
-                       XFS_ERROR_REPORT("xfs_getbmap", XFS_ERRLEVEL_LOW,
-                                        ip->i_mount);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-
-               prealloced = 0;
-               fixlen = 1LL << 32;
-       } else {
-               if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
-                   ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
-                   ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
-                       return XFS_ERROR(EINVAL);
-
-               if (xfs_get_extsz_hint(ip) ||
-                   ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
-                       prealloced = 1;
-                       fixlen = mp->m_super->s_maxbytes;
-               } else {
-                       prealloced = 0;
-                       fixlen = XFS_ISIZE(ip);
-               }
-       }
-
-       if (bmv->bmv_length == -1) {
-               fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen));
-               bmv->bmv_length =
-                       max_t(__int64_t, fixlen - bmv->bmv_offset, 0);
-       } else if (bmv->bmv_length == 0) {
-               bmv->bmv_entries = 0;
-               return 0;
-       } else if (bmv->bmv_length < 0) {
-               return XFS_ERROR(EINVAL);
-       }
-
-       nex = bmv->bmv_count - 1;
-       if (nex <= 0)
-               return XFS_ERROR(EINVAL);
-       bmvend = bmv->bmv_offset + bmv->bmv_length;
-
-
-       if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
-               return XFS_ERROR(ENOMEM);
-       out = kmem_zalloc(bmv->bmv_count * sizeof(struct getbmapx), KM_MAYFAIL);
-       if (!out) {
-               out = kmem_zalloc_large(bmv->bmv_count *
-                                       sizeof(struct getbmapx));
-               if (!out)
-                       return XFS_ERROR(ENOMEM);
-       }
-
-       xfs_ilock(ip, XFS_IOLOCK_SHARED);
-       if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
-               if (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size) {
-                       error = -filemap_write_and_wait(VFS_I(ip)->i_mapping);
-                       if (error)
-                               goto out_unlock_iolock;
-               }
-               /*
-                * even after flushing the inode, there can still be delalloc
-                * blocks on the inode beyond EOF due to speculative
-                * preallocation. These are not removed until the release
-                * function is called or the inode is inactivated. Hence we
-                * cannot assert here that ip->i_delayed_blks == 0.
-                */
-       }
-
-       lock = xfs_ilock_map_shared(ip);
-
-       /*
-        * Don't let nex be bigger than the number of extents
-        * we can have assuming alternating holes and real extents.
-        */
-       if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1)
-               nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1;
-
-       bmapi_flags = xfs_bmapi_aflag(whichfork);
-       if (!(iflags & BMV_IF_PREALLOC))
-               bmapi_flags |= XFS_BMAPI_IGSTATE;
-
-       /*
-        * Allocate enough space to handle "subnex" maps at a time.
-        */
-       error = ENOMEM;
-       subnex = 16;
-       map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS);
-       if (!map)
-               goto out_unlock_ilock;
-
-       bmv->bmv_entries = 0;
-
-       if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0 &&
-           (whichfork == XFS_ATTR_FORK || !(iflags & BMV_IF_DELALLOC))) {
-               error = 0;
-               goto out_free_map;
-       }
-
-       nexleft = nex;
-
-       do {
-               nmap = (nexleft > subnex) ? subnex : nexleft;
-               error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
-                                      XFS_BB_TO_FSB(mp, bmv->bmv_length),
-                                      map, &nmap, bmapi_flags);
-               if (error)
-                       goto out_free_map;
-               ASSERT(nmap <= subnex);
-
-               for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
-                       out[cur_ext].bmv_oflags = 0;
-                       if (map[i].br_state == XFS_EXT_UNWRITTEN)
-                               out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC;
-                       else if (map[i].br_startblock == DELAYSTARTBLOCK)
-                               out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC;
-                       out[cur_ext].bmv_offset =
-                               XFS_FSB_TO_BB(mp, map[i].br_startoff);
-                       out[cur_ext].bmv_length =
-                               XFS_FSB_TO_BB(mp, map[i].br_blockcount);
-                       out[cur_ext].bmv_unused1 = 0;
-                       out[cur_ext].bmv_unused2 = 0;
-
-                       /*
-                        * delayed allocation extents that start beyond EOF can
-                        * occur due to speculative EOF allocation when the
-                        * delalloc extent is larger than the largest freespace
-                        * extent at conversion time. These extents cannot be
-                        * converted by data writeback, so can exist here even
-                        * if we are not supposed to be finding delalloc
-                        * extents.
-                        */
-                       if (map[i].br_startblock == DELAYSTARTBLOCK &&
-                           map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
-                               ASSERT((iflags & BMV_IF_DELALLOC) != 0);
-
-                        if (map[i].br_startblock == HOLESTARTBLOCK &&
-                           whichfork == XFS_ATTR_FORK) {
-                               /* came to the end of attribute fork */
-                               out[cur_ext].bmv_oflags |= BMV_OF_LAST;
-                               goto out_free_map;
-                       }
-
-                       if (!xfs_getbmapx_fix_eof_hole(ip, &out[cur_ext],
-                                       prealloced, bmvend,
-                                       map[i].br_startblock))
-                               goto out_free_map;
-
-                       bmv->bmv_offset =
-                               out[cur_ext].bmv_offset +
-                               out[cur_ext].bmv_length;
-                       bmv->bmv_length =
-                               max_t(__int64_t, 0, bmvend - bmv->bmv_offset);
-
-                       /*
-                        * In case we don't want to return the hole,
-                        * don't increase cur_ext so that we can reuse
-                        * it in the next loop.
-                        */
-                       if ((iflags & BMV_IF_NO_HOLES) &&
-                           map[i].br_startblock == HOLESTARTBLOCK) {
-                               memset(&out[cur_ext], 0, sizeof(out[cur_ext]));
-                               continue;
-                       }
-
-                       nexleft--;
-                       bmv->bmv_entries++;
-                       cur_ext++;
-               }
-       } while (nmap && nexleft && bmv->bmv_length);
-
- out_free_map:
-       kmem_free(map);
- out_unlock_ilock:
-       xfs_iunlock_map_shared(ip, lock);
- out_unlock_iolock:
-       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
-
-       for (i = 0; i < cur_ext; i++) {
-               int full = 0;   /* user array is full */
-
-               /* format results & advance arg */
-               error = formatter(&arg, &out[i], &full);
-               if (error || full)
-                       break;
-       }
-
-       if (is_vmalloc_addr(out))
-               kmem_free_large(out);
-       else
-               kmem_free(out);
-       return error;
-}
-
-/*
- * dead simple method of punching delalyed allocation blocks from a range in
- * the inode. Walks a block at a time so will be slow, but is only executed in
- * rare error cases so the overhead is not critical. This will alays punch out
- * both the start and end blocks, even if the ranges only partially overlap
- * them, so it is up to the caller to ensure that partial blocks are not
- * passed in.
- */
-int
-xfs_bmap_punch_delalloc_range(
-       struct xfs_inode        *ip,
-       xfs_fileoff_t           start_fsb,
-       xfs_fileoff_t           length)
-{
-       xfs_fileoff_t           remaining = length;
-       int                     error = 0;
-
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-
-       do {
-               int             done;
-               xfs_bmbt_irec_t imap;
-               int             nimaps = 1;
-               xfs_fsblock_t   firstblock;
-               xfs_bmap_free_t flist;
-
-               /*
-                * Map the range first and check that it is a delalloc extent
-                * before trying to unmap the range. Otherwise we will be
-                * trying to remove a real extent (which requires a
-                * transaction) or a hole, which is probably a bad idea...
-                */
-               error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
-                                      XFS_BMAPI_ENTIRE);
-
-               if (error) {
-                       /* something screwed, just bail */
-                       if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-                               xfs_alert(ip->i_mount,
-                       "Failed delalloc mapping lookup ino %lld fsb %lld.",
-                                               ip->i_ino, start_fsb);
-                       }
-                       break;
-               }
-               if (!nimaps) {
-                       /* nothing there */
-                       goto next_block;
-               }
-               if (imap.br_startblock != DELAYSTARTBLOCK) {
-                       /* been converted, ignore */
-                       goto next_block;
-               }
-               WARN_ON(imap.br_blockcount == 0);
-
-               /*
-                * Note: while we initialise the firstblock/flist pair, they
-                * should never be used because blocks should never be
-                * allocated or freed for a delalloc extent and hence we need
-                * don't cancel or finish them after the xfs_bunmapi() call.
-                */
-               xfs_bmap_init(&flist, &firstblock);
-               error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
-                                       &flist, &done);
-               if (error)
-                       break;
-
-               ASSERT(!flist.xbf_count && !flist.xbf_first);
-next_block:
-               start_fsb++;
-               remaining--;
-       } while(remaining > 0);
-
-       return error;
-}
index 1cf1292d29b70cdbee6168c9a530d3a891547d7f..33b41f35122574e0b1cf7ad7a2a9ae23ecfadddb 100644 (file)
@@ -107,41 +107,6 @@ static inline void xfs_bmap_init(xfs_bmap_free_t *flp, xfs_fsblock_t *fbp)
                (flp)->xbf_low = 0, *(fbp) = NULLFSBLOCK);
 }
 
-/*
- * Argument structure for xfs_bmap_alloc.
- */
-typedef struct xfs_bmalloca {
-       xfs_fsblock_t           *firstblock; /* i/o first block allocated */
-       struct xfs_bmap_free    *flist; /* bmap freelist */
-       struct xfs_trans        *tp;    /* transaction pointer */
-       struct xfs_inode        *ip;    /* incore inode pointer */
-       struct xfs_bmbt_irec    prev;   /* extent before the new one */
-       struct xfs_bmbt_irec    got;    /* extent after, or delayed */
-
-       xfs_fileoff_t           offset; /* offset in file filling in */
-       xfs_extlen_t            length; /* i/o length asked/allocated */
-       xfs_fsblock_t           blkno;  /* starting block of new extent */
-
-       struct xfs_btree_cur    *cur;   /* btree cursor */
-       xfs_extnum_t            idx;    /* current extent index */
-       int                     nallocs;/* number of extents alloc'd */
-       int                     logflags;/* flags for transaction logging */
-
-       xfs_extlen_t            total;  /* total blocks needed for xaction */
-       xfs_extlen_t            minlen; /* minimum allocation size (blocks) */
-       xfs_extlen_t            minleft; /* amount must be left after alloc */
-       char                    eof;    /* set if allocating past last extent */
-       char                    wasdel; /* replacing a delayed allocation */
-       char                    userdata;/* set if is user data */
-       char                    aeof;   /* allocated space at eof */
-       char                    conv;   /* overwriting unwritten extents */
-       char                    stack_switch;
-       int                     flags;
-       struct completion       *done;
-       struct work_struct      work;
-       int                     result;
-} xfs_bmalloca_t;
-
 /*
  * Flags for xfs_bmap_add_extent*.
  */
@@ -162,7 +127,7 @@ typedef struct xfs_bmalloca {
        { BMAP_RIGHT_FILLING,   "RF" }, \
        { BMAP_ATTRFORK,        "ATTR" }
 
-#if defined(__KERNEL) && defined(DEBUG)
+#ifdef DEBUG
 void   xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt,
                int whichfork, unsigned long caller_ip);
 #define        XFS_BMAP_TRACE_EXLIST(ip,c,w)   \
@@ -205,23 +170,4 @@ int        xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx,
                xfs_extnum_t num);
 uint   xfs_default_attroffset(struct xfs_inode *ip);
 
-#ifdef __KERNEL__
-/* bmap to userspace formatter - copy to user & advance pointer */
-typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
-
-int    xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
-               int *committed);
-int    xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
-               xfs_bmap_format_t formatter, void *arg);
-int    xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
-               int whichfork, int *eof);
-int    xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
-               int whichfork, int *count);
-int    xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
-               xfs_fileoff_t start_fsb, xfs_fileoff_t length);
-
-xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
-
-#endif /* __KERNEL__ */
-
 #endif /* __XFS_BMAP_H__ */
index 0c61a22be6fd630668a16d0f92b3db625fa03173..bb8de8e399c4b351effa08e6669e000438751d37 100644 (file)
@@ -17,7 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
@@ -722,7 +722,7 @@ xfs_bmbt_key_diff(
                                      cur->bc_rec.b.br_startoff;
 }
 
-static int
+static bool
 xfs_bmbt_verify(
        struct xfs_buf          *bp)
 {
@@ -775,7 +775,6 @@ xfs_bmbt_verify(
                return false;
 
        return true;
-
 }
 
 static void
@@ -789,7 +788,6 @@ xfs_bmbt_read_verify(
                                     bp->b_target->bt_mount, bp->b_addr);
                xfs_buf_ioerror(bp, EFSCORRUPTED);
        }
-
 }
 
 static void
@@ -927,3 +925,47 @@ xfs_bmdr_maxrecs(
                return blocklen / sizeof(xfs_bmdr_rec_t);
        return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t));
 }
+
+/*
+ * Change the owner of a btree format fork fo the inode passed in. Change it to
+ * the owner of that is passed in so that we can change owners before or after
+ * we switch forks between inodes. The operation that the caller is doing will
+ * determine whether is needs to change owner before or after the switch.
+ *
+ * For demand paged transactional modification, the fork switch should be done
+ * after reading in all the blocks, modifying them and pinning them in the
+ * transaction. For modification when the buffers are already pinned in memory,
+ * the fork switch can be done before changing the owner as we won't need to
+ * validate the owner until the btree buffers are unpinned and writes can occur
+ * again.
+ *
+ * For recovery based ownership change, there is no transactional context and
+ * so a buffer list must be supplied so that we can record the buffers that we
+ * modified for the caller to issue IO on.
+ */
+int
+xfs_bmbt_change_owner(
+       struct xfs_trans        *tp,
+       struct xfs_inode        *ip,
+       int                     whichfork,
+       xfs_ino_t               new_owner,
+       struct list_head        *buffer_list)
+{
+       struct xfs_btree_cur    *cur;
+       int                     error;
+
+       ASSERT(tp || buffer_list);
+       ASSERT(!(tp && buffer_list));
+       if (whichfork == XFS_DATA_FORK)
+               ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE);
+       else
+               ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE);
+
+       cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork);
+       if (!cur)
+               return ENOMEM;
+
+       error = xfs_btree_change_owner(cur, new_owner, buffer_list);
+       xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR);
+       return error;
+}
index 1b726d6269412d8a9685a6db71c33bf9da9558ae..e367461a638e5b65ffdedc77bed6121dc1150161 100644 (file)
@@ -236,6 +236,10 @@ extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
 extern int xfs_bmdr_maxrecs(struct xfs_mount *, int blocklen, int leaf);
 extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
 
+extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
+                                int whichfork, xfs_ino_t new_owner,
+                                struct list_head *buffer_list);
+
 extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
                struct xfs_trans *, struct xfs_inode *, int);
 
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
new file mode 100644 (file)
index 0000000..97f952c
--- /dev/null
@@ -0,0 +1,2045 @@
+/*
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
+ * Copyright (c) 2012 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_format.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_btree.h"
+#include "xfs_extfree_item.h"
+#include "xfs_alloc.h"
+#include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
+#include "xfs_rtalloc.h"
+#include "xfs_error.h"
+#include "xfs_quota.h"
+#include "xfs_trans_space.h"
+#include "xfs_trace.h"
+#include "xfs_icache.h"
+
+/* Kernel only BMAP related definitions and functions */
+
+/*
+ * Convert the given file system block to a disk block.  We have to treat it
+ * differently based on whether the file is a real time file or not, because the
+ * bmap code does.
+ */
+xfs_daddr_t
+xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
+{
+       return (XFS_IS_REALTIME_INODE(ip) ? \
+                (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \
+                XFS_FSB_TO_DADDR((ip)->i_mount, (fsb)));
+}
+
+/*
+ * Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
+ * caller.  Frees all the extents that need freeing, which must be done
+ * last due to locking considerations.  We never free any extents in
+ * the first transaction.
+ *
+ * Return 1 if the given transaction was committed and a new one
+ * started, and 0 otherwise in the committed parameter.
+ */
+int                                            /* error */
+xfs_bmap_finish(
+       xfs_trans_t             **tp,           /* transaction pointer addr */
+       xfs_bmap_free_t         *flist,         /* i/o: list extents to free */
+       int                     *committed)     /* xact committed or not */
+{
+       xfs_efd_log_item_t      *efd;           /* extent free data */
+       xfs_efi_log_item_t      *efi;           /* extent free intention */
+       int                     error;          /* error return value */
+       xfs_bmap_free_item_t    *free;          /* free extent item */
+       struct xfs_trans_res    tres;           /* new log reservation */
+       xfs_mount_t             *mp;            /* filesystem mount structure */
+       xfs_bmap_free_item_t    *next;          /* next item on free list */
+       xfs_trans_t             *ntp;           /* new transaction pointer */
+
+       ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
+       if (flist->xbf_count == 0) {
+               *committed = 0;
+               return 0;
+       }
+       ntp = *tp;
+       efi = xfs_trans_get_efi(ntp, flist->xbf_count);
+       for (free = flist->xbf_first; free; free = free->xbfi_next)
+               xfs_trans_log_efi_extent(ntp, efi, free->xbfi_startblock,
+                       free->xbfi_blockcount);
+
+       tres.tr_logres = ntp->t_log_res;
+       tres.tr_logcount = ntp->t_log_count;
+       tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+       ntp = xfs_trans_dup(*tp);
+       error = xfs_trans_commit(*tp, 0);
+       *tp = ntp;
+       *committed = 1;
+       /*
+        * We have a new transaction, so we should return committed=1,
+        * even though we're returning an error.
+        */
+       if (error)
+               return error;
+
+       /*
+        * transaction commit worked ok so we can drop the extra ticket
+        * reference that we gained in xfs_trans_dup()
+        */
+       xfs_log_ticket_put(ntp->t_ticket);
+
+       error = xfs_trans_reserve(ntp, &tres, 0, 0);
+       if (error)
+               return error;
+       efd = xfs_trans_get_efd(ntp, efi, flist->xbf_count);
+       for (free = flist->xbf_first; free != NULL; free = next) {
+               next = free->xbfi_next;
+               if ((error = xfs_free_extent(ntp, free->xbfi_startblock,
+                               free->xbfi_blockcount))) {
+                       /*
+                        * The bmap free list will be cleaned up at a
+                        * higher level.  The EFI will be canceled when
+                        * this transaction is aborted.
+                        * Need to force shutdown here to make sure it
+                        * happens, since this transaction may not be
+                        * dirty yet.
+                        */
+                       mp = ntp->t_mountp;
+                       if (!XFS_FORCED_SHUTDOWN(mp))
+                               xfs_force_shutdown(mp,
+                                                  (error == EFSCORRUPTED) ?
+                                                  SHUTDOWN_CORRUPT_INCORE :
+                                                  SHUTDOWN_META_IO_ERROR);
+                       return error;
+               }
+               xfs_trans_log_efd_extent(ntp, efd, free->xbfi_startblock,
+                       free->xbfi_blockcount);
+               xfs_bmap_del_free(flist, NULL, free);
+       }
+       return 0;
+}
+
+int
+xfs_bmap_rtalloc(
+       struct xfs_bmalloca     *ap)    /* bmap alloc argument struct */
+{
+       xfs_alloctype_t atype = 0;      /* type for allocation routines */
+       int             error;          /* error return value */
+       xfs_mount_t     *mp;            /* mount point structure */
+       xfs_extlen_t    prod = 0;       /* product factor for allocators */
+       xfs_extlen_t    ralen = 0;      /* realtime allocation length */
+       xfs_extlen_t    align;          /* minimum allocation alignment */
+       xfs_rtblock_t   rtb;
+
+       mp = ap->ip->i_mount;
+       align = xfs_get_extsz_hint(ap->ip);
+       prod = align / mp->m_sb.sb_rextsize;
+       error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev,
+                                       align, 1, ap->eof, 0,
+                                       ap->conv, &ap->offset, &ap->length);
+       if (error)
+               return error;
+       ASSERT(ap->length);
+       ASSERT(ap->length % mp->m_sb.sb_rextsize == 0);
+
+       /*
+        * If the offset & length are not perfectly aligned
+        * then kill prod, it will just get us in trouble.
+        */
+       if (do_mod(ap->offset, align) || ap->length % align)
+               prod = 1;
+       /*
+        * Set ralen to be the actual requested length in rtextents.
+        */
+       ralen = ap->length / mp->m_sb.sb_rextsize;
+       /*
+        * If the old value was close enough to MAXEXTLEN that
+        * we rounded up to it, cut it back so it's valid again.
+        * Note that if it's a really large request (bigger than
+        * MAXEXTLEN), we don't hear about that number, and can't
+        * adjust the starting point to match it.
+        */
+       if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN)
+               ralen = MAXEXTLEN / mp->m_sb.sb_rextsize;
+
+       /*
+        * Lock out other modifications to the RT bitmap inode.
+        */
+       xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL);
+
+       /*
+        * If it's an allocation to an empty file at offset 0,
+        * pick an extent that will space things out in the rt area.
+        */
+       if (ap->eof && ap->offset == 0) {
+               xfs_rtblock_t uninitialized_var(rtx); /* realtime extent no */
+
+               error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx);
+               if (error)
+                       return error;
+               ap->blkno = rtx * mp->m_sb.sb_rextsize;
+       } else {
+               ap->blkno = 0;
+       }
+
+       xfs_bmap_adjacent(ap);
+
+       /*
+        * Realtime allocation, done through xfs_rtallocate_extent.
+        */
+       atype = ap->blkno == 0 ?  XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO;
+       do_div(ap->blkno, mp->m_sb.sb_rextsize);
+       rtb = ap->blkno;
+       ap->length = ralen;
+       if ((error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length,
+                               &ralen, atype, ap->wasdel, prod, &rtb)))
+               return error;
+       if (rtb == NULLFSBLOCK && prod > 1 &&
+           (error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1,
+                                          ap->length, &ralen, atype,
+                                          ap->wasdel, 1, &rtb)))
+               return error;
+       ap->blkno = rtb;
+       if (ap->blkno != NULLFSBLOCK) {
+               ap->blkno *= mp->m_sb.sb_rextsize;
+               ralen *= mp->m_sb.sb_rextsize;
+               ap->length = ralen;
+               ap->ip->i_d.di_nblocks += ralen;
+               xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE);
+               if (ap->wasdel)
+                       ap->ip->i_delayed_blks -= ralen;
+               /*
+                * Adjust the disk quota also. This was reserved
+                * earlier.
+                */
+               xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
+                       ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
+                                       XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
+       } else {
+               ap->length = 0;
+       }
+       return 0;
+}
+
+/*
+ * Stack switching interfaces for allocation
+ */
+static void
+xfs_bmapi_allocate_worker(
+       struct work_struct      *work)
+{
+       struct xfs_bmalloca     *args = container_of(work,
+                                               struct xfs_bmalloca, work);
+       unsigned long           pflags;
+
+       /* we are in a transaction context here */
+       current_set_flags_nested(&pflags, PF_FSTRANS);
+
+       args->result = __xfs_bmapi_allocate(args);
+       complete(args->done);
+
+       current_restore_flags_nested(&pflags, PF_FSTRANS);
+}
+
+/*
+ * Some allocation requests often come in with little stack to work on. Push
+ * them off to a worker thread so there is lots of stack to use. Otherwise just
+ * call directly to avoid the context switch overhead here.
+ */
+int
+xfs_bmapi_allocate(
+       struct xfs_bmalloca     *args)
+{
+       DECLARE_COMPLETION_ONSTACK(done);
+
+       if (!args->stack_switch)
+               return __xfs_bmapi_allocate(args);
+
+
+       args->done = &done;
+       INIT_WORK_ONSTACK(&args->work, xfs_bmapi_allocate_worker);
+       queue_work(xfs_alloc_wq, &args->work);
+       wait_for_completion(&done);
+       return args->result;
+}
+
+/*
+ * Check if the endoff is outside the last extent. If so the caller will grow
+ * the allocation to a stripe unit boundary.  All offsets are considered outside
+ * the end of file for an empty fork, so 1 is returned in *eof in that case.
+ */
+int
+xfs_bmap_eof(
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           endoff,
+       int                     whichfork,
+       int                     *eof)
+{
+       struct xfs_bmbt_irec    rec;
+       int                     error;
+
+       error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof);
+       if (error || *eof)
+               return error;
+
+       *eof = endoff >= rec.br_startoff + rec.br_blockcount;
+       return 0;
+}
+
+/*
+ * Extent tree block counting routines.
+ */
+
+/*
+ * Count leaf blocks given a range of extent records.
+ */
+STATIC void
+xfs_bmap_count_leaves(
+       xfs_ifork_t             *ifp,
+       xfs_extnum_t            idx,
+       int                     numrecs,
+       int                     *count)
+{
+       int             b;
+
+       for (b = 0; b < numrecs; b++) {
+               xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, idx + b);
+               *count += xfs_bmbt_get_blockcount(frp);
+       }
+}
+
+/*
+ * Count leaf blocks given a range of extent records originally
+ * in btree format.
+ */
+STATIC void
+xfs_bmap_disk_count_leaves(
+       struct xfs_mount        *mp,
+       struct xfs_btree_block  *block,
+       int                     numrecs,
+       int                     *count)
+{
+       int             b;
+       xfs_bmbt_rec_t  *frp;
+
+       for (b = 1; b <= numrecs; b++) {
+               frp = XFS_BMBT_REC_ADDR(mp, block, b);
+               *count += xfs_bmbt_disk_get_blockcount(frp);
+       }
+}
+
+/*
+ * Recursively walks each level of a btree
+ * to count total fsblocks in use.
+ */
+STATIC int                                     /* error */
+xfs_bmap_count_tree(
+       xfs_mount_t     *mp,            /* file system mount point */
+       xfs_trans_t     *tp,            /* transaction pointer */
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_fsblock_t   blockno,        /* file system block number */
+       int             levelin,        /* level in btree */
+       int             *count)         /* Count of blocks */
+{
+       int                     error;
+       xfs_buf_t               *bp, *nbp;
+       int                     level = levelin;
+       __be64                  *pp;
+       xfs_fsblock_t           bno = blockno;
+       xfs_fsblock_t           nextbno;
+       struct xfs_btree_block  *block, *nextblock;
+       int                     numrecs;
+
+       error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF,
+                                               &xfs_bmbt_buf_ops);
+       if (error)
+               return error;
+       *count += 1;
+       block = XFS_BUF_TO_BLOCK(bp);
+
+       if (--level) {
+               /* Not at node above leaves, count this level of nodes */
+               nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
+               while (nextbno != NULLFSBLOCK) {
+                       error = xfs_btree_read_bufl(mp, tp, nextbno, 0, &nbp,
+                                               XFS_BMAP_BTREE_REF,
+                                               &xfs_bmbt_buf_ops);
+                       if (error)
+                               return error;
+                       *count += 1;
+                       nextblock = XFS_BUF_TO_BLOCK(nbp);
+                       nextbno = be64_to_cpu(nextblock->bb_u.l.bb_rightsib);
+                       xfs_trans_brelse(tp, nbp);
+               }
+
+               /* Dive to the next level */
+               pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+               bno = be64_to_cpu(*pp);
+               if (unlikely((error =
+                    xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
+                       xfs_trans_brelse(tp, bp);
+                       XFS_ERROR_REPORT("xfs_bmap_count_tree(1)",
+                                        XFS_ERRLEVEL_LOW, mp);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+               xfs_trans_brelse(tp, bp);
+       } else {
+               /* count all level 1 nodes and their leaves */
+               for (;;) {
+                       nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
+                       numrecs = be16_to_cpu(block->bb_numrecs);
+                       xfs_bmap_disk_count_leaves(mp, block, numrecs, count);
+                       xfs_trans_brelse(tp, bp);
+                       if (nextbno == NULLFSBLOCK)
+                               break;
+                       bno = nextbno;
+                       error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp,
+                                               XFS_BMAP_BTREE_REF,
+                                               &xfs_bmbt_buf_ops);
+                       if (error)
+                               return error;
+                       *count += 1;
+                       block = XFS_BUF_TO_BLOCK(bp);
+               }
+       }
+       return 0;
+}
+
+/*
+ * Count fsblocks of the given fork.
+ */
+int                                            /* error */
+xfs_bmap_count_blocks(
+       xfs_trans_t             *tp,            /* transaction pointer */
+       xfs_inode_t             *ip,            /* incore inode */
+       int                     whichfork,      /* data or attr fork */
+       int                     *count)         /* out: count of blocks */
+{
+       struct xfs_btree_block  *block; /* current btree block */
+       xfs_fsblock_t           bno;    /* block # of "block" */
+       xfs_ifork_t             *ifp;   /* fork structure */
+       int                     level;  /* btree level, for checking */
+       xfs_mount_t             *mp;    /* file system mount structure */
+       __be64                  *pp;    /* pointer to block address */
+
+       bno = NULLFSBLOCK;
+       mp = ip->i_mount;
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) {
+               xfs_bmap_count_leaves(ifp, 0,
+                       ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t),
+                       count);
+               return 0;
+       }
+
+       /*
+        * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out.
+        */
+       block = ifp->if_broot;
+       level = be16_to_cpu(block->bb_level);
+       ASSERT(level > 0);
+       pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
+       bno = be64_to_cpu(*pp);
+       ASSERT(bno != NULLDFSBNO);
+       ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
+       ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
+
+       if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
+               XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
+                                mp);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       return 0;
+}
+
+/*
+ * returns 1 for success, 0 if we failed to map the extent.
+ */
+STATIC int
+xfs_getbmapx_fix_eof_hole(
+       xfs_inode_t             *ip,            /* xfs incore inode pointer */
+       struct getbmapx         *out,           /* output structure */
+       int                     prealloced,     /* this is a file with
+                                                * preallocated data space */
+       __int64_t               end,            /* last block requested */
+       xfs_fsblock_t           startblock)
+{
+       __int64_t               fixlen;
+       xfs_mount_t             *mp;            /* file system mount point */
+       xfs_ifork_t             *ifp;           /* inode fork pointer */
+       xfs_extnum_t            lastx;          /* last extent pointer */
+       xfs_fileoff_t           fileblock;
+
+       if (startblock == HOLESTARTBLOCK) {
+               mp = ip->i_mount;
+               out->bmv_block = -1;
+               fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, XFS_ISIZE(ip)));
+               fixlen -= out->bmv_offset;
+               if (prealloced && out->bmv_offset + out->bmv_length == end) {
+                       /* Came to hole at EOF. Trim it. */
+                       if (fixlen <= 0)
+                               return 0;
+                       out->bmv_length = fixlen;
+               }
+       } else {
+               if (startblock == DELAYSTARTBLOCK)
+                       out->bmv_block = -2;
+               else
+                       out->bmv_block = xfs_fsb_to_db(ip, startblock);
+               fileblock = XFS_BB_TO_FSB(ip->i_mount, out->bmv_offset);
+               ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK);
+               if (xfs_iext_bno_to_ext(ifp, fileblock, &lastx) &&
+                  (lastx == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))-1))
+                       out->bmv_oflags |= BMV_OF_LAST;
+       }
+
+       return 1;
+}
+
+/*
+ * Get inode's extents as described in bmv, and format for output.
+ * Calls formatter to fill the user's buffer until all extents
+ * are mapped, until the passed-in bmv->bmv_count slots have
+ * been filled, or until the formatter short-circuits the loop,
+ * if it is tracking filled-in extents on its own.
+ */
+int                                            /* error code */
+xfs_getbmap(
+       xfs_inode_t             *ip,
+       struct getbmapx         *bmv,           /* user bmap structure */
+       xfs_bmap_format_t       formatter,      /* format to user */
+       void                    *arg)           /* formatter arg */
+{
+       __int64_t               bmvend;         /* last block requested */
+       int                     error = 0;      /* return value */
+       __int64_t               fixlen;         /* length for -1 case */
+       int                     i;              /* extent number */
+       int                     lock;           /* lock state */
+       xfs_bmbt_irec_t         *map;           /* buffer for user's data */
+       xfs_mount_t             *mp;            /* file system mount point */
+       int                     nex;            /* # of user extents can do */
+       int                     nexleft;        /* # of user extents left */
+       int                     subnex;         /* # of bmapi's can do */
+       int                     nmap;           /* number of map entries */
+       struct getbmapx         *out;           /* output structure */
+       int                     whichfork;      /* data or attr fork */
+       int                     prealloced;     /* this is a file with
+                                                * preallocated data space */
+       int                     iflags;         /* interface flags */
+       int                     bmapi_flags;    /* flags for xfs_bmapi */
+       int                     cur_ext = 0;
+
+       mp = ip->i_mount;
+       iflags = bmv->bmv_iflags;
+       whichfork = iflags & BMV_IF_ATTRFORK ? XFS_ATTR_FORK : XFS_DATA_FORK;
+
+       if (whichfork == XFS_ATTR_FORK) {
+               if (XFS_IFORK_Q(ip)) {
+                       if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS &&
+                           ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE &&
+                           ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)
+                               return XFS_ERROR(EINVAL);
+               } else if (unlikely(
+                          ip->i_d.di_aformat != 0 &&
+                          ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS)) {
+                       XFS_ERROR_REPORT("xfs_getbmap", XFS_ERRLEVEL_LOW,
+                                        ip->i_mount);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+
+               prealloced = 0;
+               fixlen = 1LL << 32;
+       } else {
+               if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS &&
+                   ip->i_d.di_format != XFS_DINODE_FMT_BTREE &&
+                   ip->i_d.di_format != XFS_DINODE_FMT_LOCAL)
+                       return XFS_ERROR(EINVAL);
+
+               if (xfs_get_extsz_hint(ip) ||
+                   ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){
+                       prealloced = 1;
+                       fixlen = mp->m_super->s_maxbytes;
+               } else {
+                       prealloced = 0;
+                       fixlen = XFS_ISIZE(ip);
+               }
+       }
+
+       if (bmv->bmv_length == -1) {
+               fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen));
+               bmv->bmv_length =
+                       max_t(__int64_t, fixlen - bmv->bmv_offset, 0);
+       } else if (bmv->bmv_length == 0) {
+               bmv->bmv_entries = 0;
+               return 0;
+       } else if (bmv->bmv_length < 0) {
+               return XFS_ERROR(EINVAL);
+       }
+
+       nex = bmv->bmv_count - 1;
+       if (nex <= 0)
+               return XFS_ERROR(EINVAL);
+       bmvend = bmv->bmv_offset + bmv->bmv_length;
+
+
+       if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx))
+               return XFS_ERROR(ENOMEM);
+       out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0);
+       if (!out)
+               return XFS_ERROR(ENOMEM);
+
+       xfs_ilock(ip, XFS_IOLOCK_SHARED);
+       if (whichfork == XFS_DATA_FORK && !(iflags & BMV_IF_DELALLOC)) {
+               if (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size) {
+                       error = -filemap_write_and_wait(VFS_I(ip)->i_mapping);
+                       if (error)
+                               goto out_unlock_iolock;
+               }
+               /*
+                * even after flushing the inode, there can still be delalloc
+                * blocks on the inode beyond EOF due to speculative
+                * preallocation. These are not removed until the release
+                * function is called or the inode is inactivated. Hence we
+                * cannot assert here that ip->i_delayed_blks == 0.
+                */
+       }
+
+       lock = xfs_ilock_map_shared(ip);
+
+       /*
+        * Don't let nex be bigger than the number of extents
+        * we can have assuming alternating holes and real extents.
+        */
+       if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1)
+               nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1;
+
+       bmapi_flags = xfs_bmapi_aflag(whichfork);
+       if (!(iflags & BMV_IF_PREALLOC))
+               bmapi_flags |= XFS_BMAPI_IGSTATE;
+
+       /*
+        * Allocate enough space to handle "subnex" maps at a time.
+        */
+       error = ENOMEM;
+       subnex = 16;
+       map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS);
+       if (!map)
+               goto out_unlock_ilock;
+
+       bmv->bmv_entries = 0;
+
+       if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0 &&
+           (whichfork == XFS_ATTR_FORK || !(iflags & BMV_IF_DELALLOC))) {
+               error = 0;
+               goto out_free_map;
+       }
+
+       nexleft = nex;
+
+       do {
+               nmap = (nexleft > subnex) ? subnex : nexleft;
+               error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset),
+                                      XFS_BB_TO_FSB(mp, bmv->bmv_length),
+                                      map, &nmap, bmapi_flags);
+               if (error)
+                       goto out_free_map;
+               ASSERT(nmap <= subnex);
+
+               for (i = 0; i < nmap && nexleft && bmv->bmv_length; i++) {
+                       out[cur_ext].bmv_oflags = 0;
+                       if (map[i].br_state == XFS_EXT_UNWRITTEN)
+                               out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC;
+                       else if (map[i].br_startblock == DELAYSTARTBLOCK)
+                               out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC;
+                       out[cur_ext].bmv_offset =
+                               XFS_FSB_TO_BB(mp, map[i].br_startoff);
+                       out[cur_ext].bmv_length =
+                               XFS_FSB_TO_BB(mp, map[i].br_blockcount);
+                       out[cur_ext].bmv_unused1 = 0;
+                       out[cur_ext].bmv_unused2 = 0;
+
+                       /*
+                        * delayed allocation extents that start beyond EOF can
+                        * occur due to speculative EOF allocation when the
+                        * delalloc extent is larger than the largest freespace
+                        * extent at conversion time. These extents cannot be
+                        * converted by data writeback, so can exist here even
+                        * if we are not supposed to be finding delalloc
+                        * extents.
+                        */
+                       if (map[i].br_startblock == DELAYSTARTBLOCK &&
+                           map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip)))
+                               ASSERT((iflags & BMV_IF_DELALLOC) != 0);
+
+                        if (map[i].br_startblock == HOLESTARTBLOCK &&
+                           whichfork == XFS_ATTR_FORK) {
+                               /* came to the end of attribute fork */
+                               out[cur_ext].bmv_oflags |= BMV_OF_LAST;
+                               goto out_free_map;
+                       }
+
+                       if (!xfs_getbmapx_fix_eof_hole(ip, &out[cur_ext],
+                                       prealloced, bmvend,
+                                       map[i].br_startblock))
+                               goto out_free_map;
+
+                       bmv->bmv_offset =
+                               out[cur_ext].bmv_offset +
+                               out[cur_ext].bmv_length;
+                       bmv->bmv_length =
+                               max_t(__int64_t, 0, bmvend - bmv->bmv_offset);
+
+                       /*
+                        * In case we don't want to return the hole,
+                        * don't increase cur_ext so that we can reuse
+                        * it in the next loop.
+                        */
+                       if ((iflags & BMV_IF_NO_HOLES) &&
+                           map[i].br_startblock == HOLESTARTBLOCK) {
+                               memset(&out[cur_ext], 0, sizeof(out[cur_ext]));
+                               continue;
+                       }
+
+                       nexleft--;
+                       bmv->bmv_entries++;
+                       cur_ext++;
+               }
+       } while (nmap && nexleft && bmv->bmv_length);
+
+ out_free_map:
+       kmem_free(map);
+ out_unlock_ilock:
+       xfs_iunlock_map_shared(ip, lock);
+ out_unlock_iolock:
+       xfs_iunlock(ip, XFS_IOLOCK_SHARED);
+
+       for (i = 0; i < cur_ext; i++) {
+               int full = 0;   /* user array is full */
+
+               /* format results & advance arg */
+               error = formatter(&arg, &out[i], &full);
+               if (error || full)
+                       break;
+       }
+
+       kmem_free(out);
+       return error;
+}
+
+/*
+ * dead simple method of punching delalyed allocation blocks from a range in
+ * the inode. Walks a block at a time so will be slow, but is only executed in
+ * rare error cases so the overhead is not critical. This will always punch out
+ * both the start and end blocks, even if the ranges only partially overlap
+ * them, so it is up to the caller to ensure that partial blocks are not
+ * passed in.
+ */
+int
+xfs_bmap_punch_delalloc_range(
+       struct xfs_inode        *ip,
+       xfs_fileoff_t           start_fsb,
+       xfs_fileoff_t           length)
+{
+       xfs_fileoff_t           remaining = length;
+       int                     error = 0;
+
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+
+       do {
+               int             done;
+               xfs_bmbt_irec_t imap;
+               int             nimaps = 1;
+               xfs_fsblock_t   firstblock;
+               xfs_bmap_free_t flist;
+
+               /*
+                * Map the range first and check that it is a delalloc extent
+                * before trying to unmap the range. Otherwise we will be
+                * trying to remove a real extent (which requires a
+                * transaction) or a hole, which is probably a bad idea...
+                */
+               error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps,
+                                      XFS_BMAPI_ENTIRE);
+
+               if (error) {
+                       /* something screwed, just bail */
+                       if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+                               xfs_alert(ip->i_mount,
+                       "Failed delalloc mapping lookup ino %lld fsb %lld.",
+                                               ip->i_ino, start_fsb);
+                       }
+                       break;
+               }
+               if (!nimaps) {
+                       /* nothing there */
+                       goto next_block;
+               }
+               if (imap.br_startblock != DELAYSTARTBLOCK) {
+                       /* been converted, ignore */
+                       goto next_block;
+               }
+               WARN_ON(imap.br_blockcount == 0);
+
+               /*
+                * Note: while we initialise the firstblock/flist pair, they
+                * should never be used because blocks should never be
+                * allocated or freed for a delalloc extent and hence we need
+                * don't cancel or finish them after the xfs_bunmapi() call.
+                */
+               xfs_bmap_init(&flist, &firstblock);
+               error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock,
+                                       &flist, &done);
+               if (error)
+                       break;
+
+               ASSERT(!flist.xbf_count && !flist.xbf_first);
+next_block:
+               start_fsb++;
+               remaining--;
+       } while(remaining > 0);
+
+       return error;
+}
+
+/*
+ * Test whether it is appropriate to check an inode for and free post EOF
+ * blocks. The 'force' parameter determines whether we should also consider
+ * regular files that are marked preallocated or append-only.
+ */
+bool
+xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
+{
+       /* prealloc/delalloc exists only on regular files */
+       if (!S_ISREG(ip->i_d.di_mode))
+               return false;
+
+       /*
+        * Zero sized files with no cached pages and delalloc blocks will not
+        * have speculative prealloc/delalloc blocks to remove.
+        */
+       if (VFS_I(ip)->i_size == 0 &&
+           VN_CACHED(VFS_I(ip)) == 0 &&
+           ip->i_delayed_blks == 0)
+               return false;
+
+       /* If we haven't read in the extent list, then don't do it now. */
+       if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
+               return false;
+
+       /*
+        * Do not free real preallocated or append-only files unless the file
+        * has delalloc blocks and we are forced to remove them.
+        */
+       if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
+               if (!force || ip->i_delayed_blks == 0)
+                       return false;
+
+       return true;
+}
+
+/*
+ * This is called by xfs_inactive to free any blocks beyond eof
+ * when the link count isn't zero and by xfs_dm_punch_hole() when
+ * punching a hole to EOF.
+ */
+int
+xfs_free_eofblocks(
+       xfs_mount_t     *mp,
+       xfs_inode_t     *ip,
+       bool            need_iolock)
+{
+       xfs_trans_t     *tp;
+       int             error;
+       xfs_fileoff_t   end_fsb;
+       xfs_fileoff_t   last_fsb;
+       xfs_filblks_t   map_len;
+       int             nimaps;
+       xfs_bmbt_irec_t imap;
+
+       /*
+        * Figure out if there are any blocks beyond the end
+        * of the file.  If not, then there is nothing to do.
+        */
+       end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
+       last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
+       if (last_fsb <= end_fsb)
+               return 0;
+       map_len = last_fsb - end_fsb;
+
+       nimaps = 1;
+       xfs_ilock(ip, XFS_ILOCK_SHARED);
+       error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
+       xfs_iunlock(ip, XFS_ILOCK_SHARED);
+
+       if (!error && (nimaps != 0) &&
+           (imap.br_startblock != HOLESTARTBLOCK ||
+            ip->i_delayed_blks)) {
+               /*
+                * Attach the dquots to the inode up front.
+                */
+               error = xfs_qm_dqattach(ip, 0);
+               if (error)
+                       return error;
+
+               /*
+                * There are blocks after the end of file.
+                * Free them up now by truncating the file to
+                * its current size.
+                */
+               tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
+
+               if (need_iolock) {
+                       if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
+                               xfs_trans_cancel(tp, 0);
+                               return EAGAIN;
+                       }
+               }
+
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+               if (error) {
+                       ASSERT(XFS_FORCED_SHUTDOWN(mp));
+                       xfs_trans_cancel(tp, 0);
+                       if (need_iolock)
+                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+                       return error;
+               }
+
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, ip, 0);
+
+               /*
+                * Do not update the on-disk file size.  If we update the
+                * on-disk file size and then the system crashes before the
+                * contents of the file are flushed to disk then the files
+                * may be full of holes (ie NULL files bug).
+                */
+               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK,
+                                             XFS_ISIZE(ip));
+               if (error) {
+                       /*
+                        * If we get an error at this point we simply don't
+                        * bother truncating the file.
+                        */
+                       xfs_trans_cancel(tp,
+                                        (XFS_TRANS_RELEASE_LOG_RES |
+                                         XFS_TRANS_ABORT));
+               } else {
+                       error = xfs_trans_commit(tp,
+                                               XFS_TRANS_RELEASE_LOG_RES);
+                       if (!error)
+                               xfs_inode_clear_eofblocks_tag(ip);
+               }
+
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               if (need_iolock)
+                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+       }
+       return error;
+}
+
+/*
+ * xfs_alloc_file_space()
+ *      This routine allocates disk space for the given file.
+ *
+ *     If alloc_type == 0, this request is for an ALLOCSP type
+ *     request which will change the file size.  In this case, no
+ *     DMAPI event will be generated by the call.  A TRUNCATE event
+ *     will be generated later by xfs_setattr.
+ *
+ *     If alloc_type != 0, this request is for a RESVSP type
+ *     request, and a DMAPI DM_EVENT_WRITE will be generated if the
+ *     lower block boundary byte address is less than the file's
+ *     length.
+ *
+ * RETURNS:
+ *       0 on success
+ *      errno on error
+ *
+ */
+STATIC int
+xfs_alloc_file_space(
+       xfs_inode_t             *ip,
+       xfs_off_t               offset,
+       xfs_off_t               len,
+       int                     alloc_type,
+       int                     attr_flags)
+{
+       xfs_mount_t             *mp = ip->i_mount;
+       xfs_off_t               count;
+       xfs_filblks_t           allocated_fsb;
+       xfs_filblks_t           allocatesize_fsb;
+       xfs_extlen_t            extsz, temp;
+       xfs_fileoff_t           startoffset_fsb;
+       xfs_fsblock_t           firstfsb;
+       int                     nimaps;
+       int                     quota_flag;
+       int                     rt;
+       xfs_trans_t             *tp;
+       xfs_bmbt_irec_t         imaps[1], *imapp;
+       xfs_bmap_free_t         free_list;
+       uint                    qblocks, resblks, resrtextents;
+       int                     committed;
+       int                     error;
+
+       trace_xfs_alloc_file_space(ip);
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
+               return error;
+
+       if (len <= 0)
+               return XFS_ERROR(EINVAL);
+
+       rt = XFS_IS_REALTIME_INODE(ip);
+       extsz = xfs_get_extsz_hint(ip);
+
+       count = len;
+       imapp = &imaps[0];
+       nimaps = 1;
+       startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
+       allocatesize_fsb = XFS_B_TO_FSB(mp, count);
+
+       /*
+        * Allocate file space until done or until there is an error
+        */
+       while (allocatesize_fsb && !error) {
+               xfs_fileoff_t   s, e;
+
+               /*
+                * Determine space reservations for data/realtime.
+                */
+               if (unlikely(extsz)) {
+                       s = startoffset_fsb;
+                       do_div(s, extsz);
+                       s *= extsz;
+                       e = startoffset_fsb + allocatesize_fsb;
+                       if ((temp = do_mod(startoffset_fsb, extsz)))
+                               e += temp;
+                       if ((temp = do_mod(e, extsz)))
+                               e += extsz - temp;
+               } else {
+                       s = 0;
+                       e = allocatesize_fsb;
+               }
+
+               /*
+                * The transaction reservation is limited to a 32-bit block
+                * count, hence we need to limit the number of blocks we are
+                * trying to reserve to avoid an overflow. We can't allocate
+                * more than @nimaps extents, and an extent is limited on disk
+                * to MAXEXTLEN (21 bits), so use that to enforce the limit.
+                */
+               resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps));
+               if (unlikely(rt)) {
+                       resrtextents = qblocks = resblks;
+                       resrtextents /= mp->m_sb.sb_rextsize;
+                       resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+                       quota_flag = XFS_QMOPT_RES_RTBLKS;
+               } else {
+                       resrtextents = 0;
+                       resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
+                       quota_flag = XFS_QMOPT_RES_REGBLKS;
+               }
+
+               /*
+                * Allocate and setup the transaction.
+                */
+               tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
+                                         resblks, resrtextents);
+               /*
+                * Check for running out of space
+                */
+               if (error) {
+                       /*
+                        * Free the transaction structure.
+                        */
+                       ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
+                       xfs_trans_cancel(tp, 0);
+                       break;
+               }
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+               error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
+                                                     0, quota_flag);
+               if (error)
+                       goto error1;
+
+               xfs_trans_ijoin(tp, ip, 0);
+
+               xfs_bmap_init(&free_list, &firstfsb);
+               error = xfs_bmapi_write(tp, ip, startoffset_fsb,
+                                       allocatesize_fsb, alloc_type, &firstfsb,
+                                       0, imapp, &nimaps, &free_list);
+               if (error) {
+                       goto error0;
+               }
+
+               /*
+                * Complete the transaction
+                */
+               error = xfs_bmap_finish(&tp, &free_list, &committed);
+               if (error) {
+                       goto error0;
+               }
+
+               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+               if (error) {
+                       break;
+               }
+
+               allocated_fsb = imapp->br_blockcount;
+
+               if (nimaps == 0) {
+                       error = XFS_ERROR(ENOSPC);
+                       break;
+               }
+
+               startoffset_fsb += allocated_fsb;
+               allocatesize_fsb -= allocated_fsb;
+       }
+
+       return error;
+
+error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
+       xfs_bmap_cancel(&free_list);
+       xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
+
+error1:        /* Just cancel transaction */
+       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       return error;
+}
+
+/*
+ * Zero file bytes between startoff and endoff inclusive.
+ * The iolock is held exclusive and no blocks are buffered.
+ *
+ * This function is used by xfs_free_file_space() to zero
+ * partial blocks when the range to free is not block aligned.
+ * When unreserving space with boundaries that are not block
+ * aligned we round up the start and round down the end
+ * boundaries and then use this function to zero the parts of
+ * the blocks that got dropped during the rounding.
+ */
+STATIC int
+xfs_zero_remaining_bytes(
+       xfs_inode_t             *ip,
+       xfs_off_t               startoff,
+       xfs_off_t               endoff)
+{
+       xfs_bmbt_irec_t         imap;
+       xfs_fileoff_t           offset_fsb;
+       xfs_off_t               lastoffset;
+       xfs_off_t               offset;
+       xfs_buf_t               *bp;
+       xfs_mount_t             *mp = ip->i_mount;
+       int                     nimap;
+       int                     error = 0;
+
+       /*
+        * Avoid doing I/O beyond eof - it's not necessary
+        * since nothing can read beyond eof.  The space will
+        * be zeroed when the file is extended anyway.
+        */
+       if (startoff >= XFS_ISIZE(ip))
+               return 0;
+
+       if (endoff > XFS_ISIZE(ip))
+               endoff = XFS_ISIZE(ip);
+
+       bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
+                                       mp->m_rtdev_targp : mp->m_ddev_targp,
+                                 BTOBB(mp->m_sb.sb_blocksize), 0);
+       if (!bp)
+               return XFS_ERROR(ENOMEM);
+
+       xfs_buf_unlock(bp);
+
+       for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
+               offset_fsb = XFS_B_TO_FSBT(mp, offset);
+               nimap = 1;
+               error = xfs_bmapi_read(ip, offset_fsb, 1, &imap, &nimap, 0);
+               if (error || nimap < 1)
+                       break;
+               ASSERT(imap.br_blockcount >= 1);
+               ASSERT(imap.br_startoff == offset_fsb);
+               lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1;
+               if (lastoffset > endoff)
+                       lastoffset = endoff;
+               if (imap.br_startblock == HOLESTARTBLOCK)
+                       continue;
+               ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
+               if (imap.br_state == XFS_EXT_UNWRITTEN)
+                       continue;
+               XFS_BUF_UNDONE(bp);
+               XFS_BUF_UNWRITE(bp);
+               XFS_BUF_READ(bp);
+               XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
+               xfsbdstrat(mp, bp);
+               error = xfs_buf_iowait(bp);
+               if (error) {
+                       xfs_buf_ioerror_alert(bp,
+                                       "xfs_zero_remaining_bytes(read)");
+                       break;
+               }
+               memset(bp->b_addr +
+                       (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
+                     0, lastoffset - offset + 1);
+               XFS_BUF_UNDONE(bp);
+               XFS_BUF_UNREAD(bp);
+               XFS_BUF_WRITE(bp);
+               xfsbdstrat(mp, bp);
+               error = xfs_buf_iowait(bp);
+               if (error) {
+                       xfs_buf_ioerror_alert(bp,
+                                       "xfs_zero_remaining_bytes(write)");
+                       break;
+               }
+       }
+       xfs_buf_free(bp);
+       return error;
+}
+
+/*
+ * xfs_free_file_space()
+ *      This routine frees disk space for the given file.
+ *
+ *     This routine is only called by xfs_change_file_space
+ *     for an UNRESVSP type call.
+ *
+ * RETURNS:
+ *       0 on success
+ *      errno on error
+ *
+ */
+STATIC int
+xfs_free_file_space(
+       xfs_inode_t             *ip,
+       xfs_off_t               offset,
+       xfs_off_t               len,
+       int                     attr_flags)
+{
+       int                     committed;
+       int                     done;
+       xfs_fileoff_t           endoffset_fsb;
+       int                     error;
+       xfs_fsblock_t           firstfsb;
+       xfs_bmap_free_t         free_list;
+       xfs_bmbt_irec_t         imap;
+       xfs_off_t               ioffset;
+       xfs_extlen_t            mod=0;
+       xfs_mount_t             *mp;
+       int                     nimap;
+       uint                    resblks;
+       xfs_off_t               rounding;
+       int                     rt;
+       xfs_fileoff_t           startoffset_fsb;
+       xfs_trans_t             *tp;
+       int                     need_iolock = 1;
+
+       mp = ip->i_mount;
+
+       trace_xfs_free_file_space(ip);
+
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
+               return error;
+
+       error = 0;
+       if (len <= 0)   /* if nothing being freed */
+               return error;
+       rt = XFS_IS_REALTIME_INODE(ip);
+       startoffset_fsb = XFS_B_TO_FSB(mp, offset);
+       endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
+
+       if (attr_flags & XFS_ATTR_NOLOCK)
+               need_iolock = 0;
+       if (need_iolock) {
+               xfs_ilock(ip, XFS_IOLOCK_EXCL);
+               /* wait for the completion of any pending DIOs */
+               inode_dio_wait(VFS_I(ip));
+       }
+
+       rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
+       ioffset = offset & ~(rounding - 1);
+       error = -filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
+                                             ioffset, -1);
+       if (error)
+               goto out_unlock_iolock;
+       truncate_pagecache_range(VFS_I(ip), ioffset, -1);
+
+       /*
+        * Need to zero the stuff we're not freeing, on disk.
+        * If it's a realtime file & can't use unwritten extents then we
+        * actually need to zero the extent edges.  Otherwise xfs_bunmapi
+        * will take care of it for us.
+        */
+       if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
+               nimap = 1;
+               error = xfs_bmapi_read(ip, startoffset_fsb, 1,
+                                       &imap, &nimap, 0);
+               if (error)
+                       goto out_unlock_iolock;
+               ASSERT(nimap == 0 || nimap == 1);
+               if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
+                       xfs_daddr_t     block;
+
+                       ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
+                       block = imap.br_startblock;
+                       mod = do_div(block, mp->m_sb.sb_rextsize);
+                       if (mod)
+                               startoffset_fsb += mp->m_sb.sb_rextsize - mod;
+               }
+               nimap = 1;
+               error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
+                                       &imap, &nimap, 0);
+               if (error)
+                       goto out_unlock_iolock;
+               ASSERT(nimap == 0 || nimap == 1);
+               if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
+                       ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
+                       mod++;
+                       if (mod && (mod != mp->m_sb.sb_rextsize))
+                               endoffset_fsb -= mod;
+               }
+       }
+       if ((done = (endoffset_fsb <= startoffset_fsb)))
+               /*
+                * One contiguous piece to clear
+                */
+               error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1);
+       else {
+               /*
+                * Some full blocks, possibly two pieces to clear
+                */
+               if (offset < XFS_FSB_TO_B(mp, startoffset_fsb))
+                       error = xfs_zero_remaining_bytes(ip, offset,
+                               XFS_FSB_TO_B(mp, startoffset_fsb) - 1);
+               if (!error &&
+                   XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len)
+                       error = xfs_zero_remaining_bytes(ip,
+                               XFS_FSB_TO_B(mp, endoffset_fsb),
+                               offset + len - 1);
+       }
+
+       /*
+        * free file space until done or until there is an error
+        */
+       resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
+       while (!error && !done) {
+
+               /*
+                * allocate and setup the transaction. Allow this
+                * transaction to dip into the reserve blocks to ensure
+                * the freeing of the space succeeds at ENOSPC.
+                */
+               tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+               tp->t_flags |= XFS_TRANS_RESERVE;
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write, resblks, 0);
+
+               /*
+                * check for running out of space
+                */
+               if (error) {
+                       /*
+                        * Free the transaction structure.
+                        */
+                       ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
+                       xfs_trans_cancel(tp, 0);
+                       break;
+               }
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+               error = xfs_trans_reserve_quota(tp, mp,
+                               ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
+                               resblks, 0, XFS_QMOPT_RES_REGBLKS);
+               if (error)
+                       goto error1;
+
+               xfs_trans_ijoin(tp, ip, 0);
+
+               /*
+                * issue the bunmapi() call to free the blocks
+                */
+               xfs_bmap_init(&free_list, &firstfsb);
+               error = xfs_bunmapi(tp, ip, startoffset_fsb,
+                                 endoffset_fsb - startoffset_fsb,
+                                 0, 2, &firstfsb, &free_list, &done);
+               if (error) {
+                       goto error0;
+               }
+
+               /*
+                * complete the transaction
+                */
+               error = xfs_bmap_finish(&tp, &free_list, &committed);
+               if (error) {
+                       goto error0;
+               }
+
+               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       }
+
+ out_unlock_iolock:
+       if (need_iolock)
+               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+       return error;
+
+ error0:
+       xfs_bmap_cancel(&free_list);
+ error1:
+       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+       xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) :
+                   XFS_ILOCK_EXCL);
+       return error;
+}
+
+
+STATIC int
+xfs_zero_file_space(
+       struct xfs_inode        *ip,
+       xfs_off_t               offset,
+       xfs_off_t               len,
+       int                     attr_flags)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       uint                    granularity;
+       xfs_off_t               start_boundary;
+       xfs_off_t               end_boundary;
+       int                     error;
+
+       granularity = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
+
+       /*
+        * Round the range of extents we are going to convert inwards.  If the
+        * offset is aligned, then it doesn't get changed so we zero from the
+        * start of the block offset points to.
+        */
+       start_boundary = round_up(offset, granularity);
+       end_boundary = round_down(offset + len, granularity);
+
+       ASSERT(start_boundary >= offset);
+       ASSERT(end_boundary <= offset + len);
+
+       if (!(attr_flags & XFS_ATTR_NOLOCK))
+               xfs_ilock(ip, XFS_IOLOCK_EXCL);
+
+       if (start_boundary < end_boundary - 1) {
+               /* punch out the page cache over the conversion range */
+               truncate_pagecache_range(VFS_I(ip), start_boundary,
+                                        end_boundary - 1);
+               /* convert the blocks */
+               error = xfs_alloc_file_space(ip, start_boundary,
+                                       end_boundary - start_boundary - 1,
+                                       XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT,
+                                       attr_flags);
+               if (error)
+                       goto out_unlock;
+
+               /* We've handled the interior of the range, now for the edges */
+               if (start_boundary != offset)
+                       error = xfs_iozero(ip, offset, start_boundary - offset);
+               if (error)
+                       goto out_unlock;
+
+               if (end_boundary != offset + len)
+                       error = xfs_iozero(ip, end_boundary,
+                                          offset + len - end_boundary);
+
+       } else {
+               /*
+                * It's either a sub-granularity range or the range spanned lies
+                * partially across two adjacent blocks.
+                */
+               error = xfs_iozero(ip, offset, len);
+       }
+
+out_unlock:
+       if (!(attr_flags & XFS_ATTR_NOLOCK))
+               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+       return error;
+
+}
+
+/*
+ * xfs_change_file_space()
+ *      This routine allocates or frees disk space for the given file.
+ *      The user specified parameters are checked for alignment and size
+ *      limitations.
+ *
+ * RETURNS:
+ *       0 on success
+ *      errno on error
+ *
+ */
+int
+xfs_change_file_space(
+       xfs_inode_t     *ip,
+       int             cmd,
+       xfs_flock64_t   *bf,
+       xfs_off_t       offset,
+       int             attr_flags)
+{
+       xfs_mount_t     *mp = ip->i_mount;
+       int             clrprealloc;
+       int             error;
+       xfs_fsize_t     fsize;
+       int             setprealloc;
+       xfs_off_t       startoffset;
+       xfs_trans_t     *tp;
+       struct iattr    iattr;
+
+       if (!S_ISREG(ip->i_d.di_mode))
+               return XFS_ERROR(EINVAL);
+
+       switch (bf->l_whence) {
+       case 0: /*SEEK_SET*/
+               break;
+       case 1: /*SEEK_CUR*/
+               bf->l_start += offset;
+               break;
+       case 2: /*SEEK_END*/
+               bf->l_start += XFS_ISIZE(ip);
+               break;
+       default:
+               return XFS_ERROR(EINVAL);
+       }
+
+       /*
+        * length of <= 0 for resv/unresv/zero is invalid.  length for
+        * alloc/free is ignored completely and we have no idea what userspace
+        * might have set it to, so set it to zero to allow range
+        * checks to pass.
+        */
+       switch (cmd) {
+       case XFS_IOC_ZERO_RANGE:
+       case XFS_IOC_RESVSP:
+       case XFS_IOC_RESVSP64:
+       case XFS_IOC_UNRESVSP:
+       case XFS_IOC_UNRESVSP64:
+               if (bf->l_len <= 0)
+                       return XFS_ERROR(EINVAL);
+               break;
+       default:
+               bf->l_len = 0;
+               break;
+       }
+
+       if (bf->l_start < 0 ||
+           bf->l_start > mp->m_super->s_maxbytes ||
+           bf->l_start + bf->l_len < 0 ||
+           bf->l_start + bf->l_len >= mp->m_super->s_maxbytes)
+               return XFS_ERROR(EINVAL);
+
+       bf->l_whence = 0;
+
+       startoffset = bf->l_start;
+       fsize = XFS_ISIZE(ip);
+
+       setprealloc = clrprealloc = 0;
+       switch (cmd) {
+       case XFS_IOC_ZERO_RANGE:
+               error = xfs_zero_file_space(ip, startoffset, bf->l_len,
+                                               attr_flags);
+               if (error)
+                       return error;
+               setprealloc = 1;
+               break;
+
+       case XFS_IOC_RESVSP:
+       case XFS_IOC_RESVSP64:
+               error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
+                                               XFS_BMAPI_PREALLOC, attr_flags);
+               if (error)
+                       return error;
+               setprealloc = 1;
+               break;
+
+       case XFS_IOC_UNRESVSP:
+       case XFS_IOC_UNRESVSP64:
+               if ((error = xfs_free_file_space(ip, startoffset, bf->l_len,
+                                                               attr_flags)))
+                       return error;
+               break;
+
+       case XFS_IOC_ALLOCSP:
+       case XFS_IOC_ALLOCSP64:
+       case XFS_IOC_FREESP:
+       case XFS_IOC_FREESP64:
+               /*
+                * These operations actually do IO when extending the file, but
+                * the allocation is done seperately to the zeroing that is
+                * done. This set of operations need to be serialised against
+                * other IO operations, such as truncate and buffered IO. We
+                * need to take the IOLOCK here to serialise the allocation and
+                * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
+                * truncate, direct IO) from racing against the transient
+                * allocated but not written state we can have here.
+                */
+               xfs_ilock(ip, XFS_IOLOCK_EXCL);
+               if (startoffset > fsize) {
+                       error = xfs_alloc_file_space(ip, fsize,
+                                       startoffset - fsize, 0,
+                                       attr_flags | XFS_ATTR_NOLOCK);
+                       if (error) {
+                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+                               break;
+                       }
+               }
+
+               iattr.ia_valid = ATTR_SIZE;
+               iattr.ia_size = startoffset;
+
+               error = xfs_setattr_size(ip, &iattr,
+                                        attr_flags | XFS_ATTR_NOLOCK);
+               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
+
+               if (error)
+                       return error;
+
+               clrprealloc = 1;
+               break;
+
+       default:
+               ASSERT(0);
+               return XFS_ERROR(EINVAL);
+       }
+
+       /*
+        * update the inode timestamp, mode, and prealloc flag bits
+        */
+       tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_writeid, 0, 0);
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               return error;
+       }
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       if ((attr_flags & XFS_ATTR_DMI) == 0) {
+               ip->i_d.di_mode &= ~S_ISUID;
+
+               /*
+                * Note that we don't have to worry about mandatory
+                * file locking being disabled here because we only
+                * clear the S_ISGID bit if the Group execute bit is
+                * on, but if it was on then mandatory locking wouldn't
+                * have been enabled.
+                */
+               if (ip->i_d.di_mode & S_IXGRP)
+                       ip->i_d.di_mode &= ~S_ISGID;
+
+               xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       }
+       if (setprealloc)
+               ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
+       else if (clrprealloc)
+               ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
+
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       if (attr_flags & XFS_ATTR_SYNC)
+               xfs_trans_set_sync(tp);
+       return xfs_trans_commit(tp, 0);
+}
+
+/*
+ * We need to check that the format of the data fork in the temporary inode is
+ * valid for the target inode before doing the swap. This is not a problem with
+ * attr1 because of the fixed fork offset, but attr2 has a dynamically sized
+ * data fork depending on the space the attribute fork is taking so we can get
+ * invalid formats on the target inode.
+ *
+ * E.g. target has space for 7 extents in extent format, temp inode only has
+ * space for 6.  If we defragment down to 7 extents, then the tmp format is a
+ * btree, but when swapped it needs to be in extent format. Hence we can't just
+ * blindly swap data forks on attr2 filesystems.
+ *
+ * Note that we check the swap in both directions so that we don't end up with
+ * a corrupt temporary inode, either.
+ *
+ * Note that fixing the way xfs_fsr sets up the attribute fork in the source
+ * inode will prevent this situation from occurring, so all we do here is
+ * reject and log the attempt. basically we are putting the responsibility on
+ * userspace to get this right.
+ */
+static int
+xfs_swap_extents_check_format(
+       xfs_inode_t     *ip,    /* target inode */
+       xfs_inode_t     *tip)   /* tmp inode */
+{
+
+       /* Should never get a local format */
+       if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
+           tip->i_d.di_format == XFS_DINODE_FMT_LOCAL)
+               return EINVAL;
+
+       /*
+        * if the target inode has less extents that then temporary inode then
+        * why did userspace call us?
+        */
+       if (ip->i_d.di_nextents < tip->i_d.di_nextents)
+               return EINVAL;
+
+       /*
+        * if the target inode is in extent form and the temp inode is in btree
+        * form then we will end up with the target inode in the wrong format
+        * as we already know there are less extents in the temp inode.
+        */
+       if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
+           tip->i_d.di_format == XFS_DINODE_FMT_BTREE)
+               return EINVAL;
+
+       /* Check temp in extent form to max in target */
+       if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
+           XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) >
+                       XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
+               return EINVAL;
+
+       /* Check target in extent form to max in temp */
+       if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
+           XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) >
+                       XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
+               return EINVAL;
+
+       /*
+        * If we are in a btree format, check that the temp root block will fit
+        * in the target and that it has enough extents to be in btree format
+        * in the target.
+        *
+        * Note that we have to be careful to allow btree->extent conversions
+        * (a common defrag case) which will occur when the temp inode is in
+        * extent format...
+        */
+       if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+               if (XFS_IFORK_BOFF(ip) &&
+                   XFS_BMAP_BMDR_SPACE(tip->i_df.if_broot) > XFS_IFORK_BOFF(ip))
+                       return EINVAL;
+               if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <=
+                   XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
+                       return EINVAL;
+       }
+
+       /* Reciprocal target->temp btree format checks */
+       if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+               if (XFS_IFORK_BOFF(tip) &&
+                   XFS_BMAP_BMDR_SPACE(ip->i_df.if_broot) > XFS_IFORK_BOFF(tip))
+                       return EINVAL;
+               if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <=
+                   XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
+                       return EINVAL;
+       }
+
+       return 0;
+}
+
+int
+xfs_swap_extents(
+       xfs_inode_t     *ip,    /* target inode */
+       xfs_inode_t     *tip,   /* tmp inode */
+       xfs_swapext_t   *sxp)
+{
+       xfs_mount_t     *mp = ip->i_mount;
+       xfs_trans_t     *tp;
+       xfs_bstat_t     *sbp = &sxp->sx_stat;
+       xfs_ifork_t     *tempifp, *ifp, *tifp;
+       int             src_log_flags, target_log_flags;
+       int             error = 0;
+       int             aforkblks = 0;
+       int             taforkblks = 0;
+       __uint64_t      tmp;
+
+       tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
+       if (!tempifp) {
+               error = XFS_ERROR(ENOMEM);
+               goto out;
+       }
+
+       /*
+        * we have to do two separate lock calls here to keep lockdep
+        * happy. If we try to get all the locks in one call, lock will
+        * report false positives when we drop the ILOCK and regain them
+        * below.
+        */
+       xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
+       xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
+
+       /* Verify that both files have the same format */
+       if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
+               error = XFS_ERROR(EINVAL);
+               goto out_unlock;
+       }
+
+       /* Verify both files are either real-time or non-realtime */
+       if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) {
+               error = XFS_ERROR(EINVAL);
+               goto out_unlock;
+       }
+
+       error = -filemap_write_and_wait(VFS_I(tip)->i_mapping);
+       if (error)
+               goto out_unlock;
+       truncate_pagecache_range(VFS_I(tip), 0, -1);
+
+       /* Verify O_DIRECT for ftmp */
+       if (VN_CACHED(VFS_I(tip)) != 0) {
+               error = XFS_ERROR(EINVAL);
+               goto out_unlock;
+       }
+
+       /* Verify all data are being swapped */
+       if (sxp->sx_offset != 0 ||
+           sxp->sx_length != ip->i_d.di_size ||
+           sxp->sx_length != tip->i_d.di_size) {
+               error = XFS_ERROR(EFAULT);
+               goto out_unlock;
+       }
+
+       trace_xfs_swap_extent_before(ip, 0);
+       trace_xfs_swap_extent_before(tip, 1);
+
+       /* check inode formats now that data is flushed */
+       error = xfs_swap_extents_check_format(ip, tip);
+       if (error) {
+               xfs_notice(mp,
+                   "%s: inode 0x%llx format is incompatible for exchanging.",
+                               __func__, ip->i_ino);
+               goto out_unlock;
+       }
+
+       /*
+        * Compare the current change & modify times with that
+        * passed in.  If they differ, we abort this swap.
+        * This is the mechanism used to ensure the calling
+        * process that the file was not changed out from
+        * under it.
+        */
+       if ((sbp->bs_ctime.tv_sec != VFS_I(ip)->i_ctime.tv_sec) ||
+           (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) ||
+           (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
+           (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
+               error = XFS_ERROR(EBUSY);
+               goto out_unlock;
+       }
+
+       /* We need to fail if the file is memory mapped.  Once we have tossed
+        * all existing pages, the page fault will have no option
+        * but to go to the filesystem for pages. By making the page fault call
+        * vop_read (or write in the case of autogrow) they block on the iolock
+        * until we have switched the extents.
+        */
+       if (VN_MAPPED(VFS_I(ip))) {
+               error = XFS_ERROR(EBUSY);
+               goto out_unlock;
+       }
+
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
+       xfs_iunlock(tip, XFS_ILOCK_EXCL);
+
+       /*
+        * There is a race condition here since we gave up the
+        * ilock.  However, the data fork will not change since
+        * we have the iolock (locked for truncation too) so we
+        * are safe.  We don't really care if non-io related
+        * fields change.
+        */
+       truncate_pagecache_range(VFS_I(ip), 0, -1);
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
+       if (error) {
+               xfs_iunlock(ip,  XFS_IOLOCK_EXCL);
+               xfs_iunlock(tip, XFS_IOLOCK_EXCL);
+               xfs_trans_cancel(tp, 0);
+               goto out;
+       }
+       xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
+
+       /*
+        * Count the number of extended attribute blocks
+        */
+       if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
+            (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
+               error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks);
+               if (error)
+                       goto out_trans_cancel;
+       }
+       if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
+            (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
+               error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
+                       &taforkblks);
+               if (error)
+                       goto out_trans_cancel;
+       }
+
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+
+       /*
+        * Before we've swapped the forks, lets set the owners of the forks
+        * appropriately. We have to do this as we are demand paging the btree
+        * buffers, and so the validation done on read will expect the owner
+        * field to be correctly set. Once we change the owners, we can swap the
+        * inode forks.
+        *
+        * Note the trickiness in setting the log flags - we set the owner log
+        * flag on the opposite inode (i.e. the inode we are setting the new
+        * owner to be) because once we swap the forks and log that, log
+        * recovery is going to see the fork as owned by the swapped inode,
+        * not the pre-swapped inodes.
+        */
+       src_log_flags = XFS_ILOG_CORE;
+       target_log_flags = XFS_ILOG_CORE;
+       if (ip->i_d.di_version == 3 &&
+           ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+               target_log_flags |= XFS_ILOG_DOWNER;
+               error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK,
+                                             tip->i_ino, NULL);
+               if (error)
+                       goto out_trans_cancel;
+       }
+
+       if (tip->i_d.di_version == 3 &&
+           tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
+               src_log_flags |= XFS_ILOG_DOWNER;
+               error = xfs_bmbt_change_owner(tp, tip, XFS_DATA_FORK,
+                                             ip->i_ino, NULL);
+               if (error)
+                       goto out_trans_cancel;
+       }
+
+       /*
+        * Swap the data forks of the inodes
+        */
+       ifp = &ip->i_df;
+       tifp = &tip->i_df;
+       *tempifp = *ifp;        /* struct copy */
+       *ifp = *tifp;           /* struct copy */
+       *tifp = *tempifp;       /* struct copy */
+
+       /*
+        * Fix the on-disk inode values
+        */
+       tmp = (__uint64_t)ip->i_d.di_nblocks;
+       ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks;
+       tip->i_d.di_nblocks = tmp + taforkblks - aforkblks;
+
+       tmp = (__uint64_t) ip->i_d.di_nextents;
+       ip->i_d.di_nextents = tip->i_d.di_nextents;
+       tip->i_d.di_nextents = tmp;
+
+       tmp = (__uint64_t) ip->i_d.di_format;
+       ip->i_d.di_format = tip->i_d.di_format;
+       tip->i_d.di_format = tmp;
+
+       /*
+        * The extents in the source inode could still contain speculative
+        * preallocation beyond EOF (e.g. the file is open but not modified
+        * while defrag is in progress). In that case, we need to copy over the
+        * number of delalloc blocks the data fork in the source inode is
+        * tracking beyond EOF so that when the fork is truncated away when the
+        * temporary inode is unlinked we don't underrun the i_delayed_blks
+        * counter on that inode.
+        */
+       ASSERT(tip->i_delayed_blks == 0);
+       tip->i_delayed_blks = ip->i_delayed_blks;
+       ip->i_delayed_blks = 0;
+
+       switch (ip->i_d.di_format) {
+       case XFS_DINODE_FMT_EXTENTS:
+               /* If the extents fit in the inode, fix the
+                * pointer.  Otherwise it's already NULL or
+                * pointing to the extent.
+                */
+               if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
+                       ifp->if_u1.if_extents =
+                               ifp->if_u2.if_inline_ext;
+               }
+               src_log_flags |= XFS_ILOG_DEXT;
+               break;
+       case XFS_DINODE_FMT_BTREE:
+               ASSERT(ip->i_d.di_version < 3 ||
+                      (src_log_flags & XFS_ILOG_DOWNER));
+               src_log_flags |= XFS_ILOG_DBROOT;
+               break;
+       }
+
+       switch (tip->i_d.di_format) {
+       case XFS_DINODE_FMT_EXTENTS:
+               /* If the extents fit in the inode, fix the
+                * pointer.  Otherwise it's already NULL or
+                * pointing to the extent.
+                */
+               if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
+                       tifp->if_u1.if_extents =
+                               tifp->if_u2.if_inline_ext;
+               }
+               target_log_flags |= XFS_ILOG_DEXT;
+               break;
+       case XFS_DINODE_FMT_BTREE:
+               target_log_flags |= XFS_ILOG_DBROOT;
+               ASSERT(tip->i_d.di_version < 3 ||
+                      (target_log_flags & XFS_ILOG_DOWNER));
+               break;
+       }
+
+       xfs_trans_log_inode(tp, ip,  src_log_flags);
+       xfs_trans_log_inode(tp, tip, target_log_flags);
+
+       /*
+        * If this is a synchronous mount, make sure that the
+        * transaction goes to disk before returning to the user.
+        */
+       if (mp->m_flags & XFS_MOUNT_WSYNC)
+               xfs_trans_set_sync(tp);
+
+       error = xfs_trans_commit(tp, 0);
+
+       trace_xfs_swap_extent_after(ip, 0);
+       trace_xfs_swap_extent_after(tip, 1);
+out:
+       kmem_free(tempifp);
+       return error;
+
+out_unlock:
+       xfs_iunlock(ip,  XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
+       goto out;
+
+out_trans_cancel:
+       xfs_trans_cancel(tp, 0);
+       goto out_unlock;
+}
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
new file mode 100644 (file)
index 0000000..0612609
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2000-2006 Silicon Graphics, 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
+ */
+#ifndef __XFS_BMAP_UTIL_H__
+#define        __XFS_BMAP_UTIL_H__
+
+/* Kernel only BMAP related definitions and functions */
+
+struct xfs_bmbt_irec;
+struct xfs_bmap_free_item;
+struct xfs_ifork;
+struct xfs_inode;
+struct xfs_mount;
+struct xfs_trans;
+
+/*
+ * Argument structure for xfs_bmap_alloc.
+ */
+struct xfs_bmalloca {
+       xfs_fsblock_t           *firstblock; /* i/o first block allocated */
+       struct xfs_bmap_free    *flist; /* bmap freelist */
+       struct xfs_trans        *tp;    /* transaction pointer */
+       struct xfs_inode        *ip;    /* incore inode pointer */
+       struct xfs_bmbt_irec    prev;   /* extent before the new one */
+       struct xfs_bmbt_irec    got;    /* extent after, or delayed */
+
+       xfs_fileoff_t           offset; /* offset in file filling in */
+       xfs_extlen_t            length; /* i/o length asked/allocated */
+       xfs_fsblock_t           blkno;  /* starting block of new extent */
+
+       struct xfs_btree_cur    *cur;   /* btree cursor */
+       xfs_extnum_t            idx;    /* current extent index */
+       int                     nallocs;/* number of extents alloc'd */
+       int                     logflags;/* flags for transaction logging */
+
+       xfs_extlen_t            total;  /* total blocks needed for xaction */
+       xfs_extlen_t            minlen; /* minimum allocation size (blocks) */
+       xfs_extlen_t            minleft; /* amount must be left after alloc */
+       char                    eof;    /* set if allocating past last extent */
+       char                    wasdel; /* replacing a delayed allocation */
+       char                    userdata;/* set if is user data */
+       char                    aeof;   /* allocated space at eof */
+       char                    conv;   /* overwriting unwritten extents */
+       char                    stack_switch;
+       int                     flags;
+       struct completion       *done;
+       struct work_struct      work;
+       int                     result;
+};
+
+int    xfs_bmap_finish(struct xfs_trans **tp, struct xfs_bmap_free *flist,
+                       int *committed);
+int    xfs_bmap_rtalloc(struct xfs_bmalloca *ap);
+int    xfs_bmapi_allocate(struct xfs_bmalloca *args);
+int    __xfs_bmapi_allocate(struct xfs_bmalloca *args);
+int    xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff,
+                    int whichfork, int *eof);
+int    xfs_bmap_count_blocks(struct xfs_trans *tp, struct xfs_inode *ip,
+                             int whichfork, int *count);
+int    xfs_bmap_punch_delalloc_range(struct xfs_inode *ip,
+               xfs_fileoff_t start_fsb, xfs_fileoff_t length);
+
+/* bmap to userspace formatter - copy to user & advance pointer */
+typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *);
+int    xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv,
+               xfs_bmap_format_t formatter, void *arg);
+
+/* functions in xfs_bmap.c that are only needed by xfs_bmap_util.c */
+void   xfs_bmap_del_free(struct xfs_bmap_free *flist,
+                         struct xfs_bmap_free_item *prev,
+                         struct xfs_bmap_free_item *free);
+int    xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp,
+                              struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz,
+                              int rt, int eof, int delay, int convert,
+                              xfs_fileoff_t *offp, xfs_extlen_t *lenp);
+void   xfs_bmap_adjacent(struct xfs_bmalloca *ap);
+int    xfs_bmap_last_extent(struct xfs_trans *tp, struct xfs_inode *ip,
+                            int whichfork, struct xfs_bmbt_irec *rec,
+                            int *is_empty);
+
+/* preallocation and hole punch interface */
+int    xfs_change_file_space(struct xfs_inode *ip, int cmd,
+                             xfs_flock64_t *bf, xfs_off_t offset,
+                             int attr_flags);
+
+/* EOF block manipulation functions */
+bool   xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
+int    xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip,
+                          bool need_iolock);
+
+int    xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
+                        struct xfs_swapext *sx);
+
+xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb);
+
+#endif /* __XFS_BMAP_UTIL_H__ */
index 0903960410a255c171a7b663ffb3ba4af9137074..5690e102243d70e7b87876f0ef9bc07be058da86 100644 (file)
@@ -510,7 +510,7 @@ xfs_btree_ptr_addr(
 }
 
 /*
- * Get the root block which is stored in the inode.
+ * Get the root block which is stored in the inode.
  *
  * For now this btree implementation assumes the btree root is always
  * stored in the if_broot field of an inode fork.
@@ -855,6 +855,41 @@ xfs_btree_readahead(
        return xfs_btree_readahead_sblock(cur, lr, block);
 }
 
+STATIC xfs_daddr_t
+xfs_btree_ptr_to_daddr(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr)
+{
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
+               ASSERT(ptr->l != cpu_to_be64(NULLDFSBNO));
+
+               return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l));
+       } else {
+               ASSERT(cur->bc_private.a.agno != NULLAGNUMBER);
+               ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK));
+
+               return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
+                                       be32_to_cpu(ptr->s));
+       }
+}
+
+/*
+ * Readahead @count btree blocks at the given @ptr location.
+ *
+ * We don't need to care about long or short form btrees here as we have a
+ * method of converting the ptr directly to a daddr available to us.
+ */
+STATIC void
+xfs_btree_readahead_ptr(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr,
+       xfs_extlen_t            count)
+{
+       xfs_buf_readahead(cur->bc_mp->m_ddev_targp,
+                         xfs_btree_ptr_to_daddr(cur, ptr),
+                         cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops);
+}
+
 /*
  * Set the buffer for level "lev" in the cursor to bp, releasing
  * any previous buffer.
@@ -978,6 +1013,7 @@ xfs_btree_init_block_int(
                        buf->bb_u.l.bb_owner = cpu_to_be64(owner);
                        uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_uuid);
                        buf->bb_u.l.bb_pad = 0;
+                       buf->bb_u.l.bb_lsn = 0;
                }
        } else {
                /* owner is a 32 bit value on short blocks */
@@ -989,6 +1025,7 @@ xfs_btree_init_block_int(
                        buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
                        buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
                        uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_uuid);
+                       buf->bb_u.s.bb_lsn = 0;
                }
        }
 }
@@ -1071,24 +1108,6 @@ xfs_btree_buf_to_ptr(
        }
 }
 
-STATIC xfs_daddr_t
-xfs_btree_ptr_to_daddr(
-       struct xfs_btree_cur    *cur,
-       union xfs_btree_ptr     *ptr)
-{
-       if (cur->bc_flags & XFS_BTREE_LONG_PTRS) {
-               ASSERT(ptr->l != cpu_to_be64(NULLDFSBNO));
-
-               return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l));
-       } else {
-               ASSERT(cur->bc_private.a.agno != NULLAGNUMBER);
-               ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK));
-
-               return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno,
-                                       be32_to_cpu(ptr->s));
-       }
-}
-
 STATIC void
 xfs_btree_set_refs(
        struct xfs_btree_cur    *cur,
@@ -1684,7 +1703,7 @@ xfs_lookup_get_search_key(
 
 /*
  * Lookup the record.  The cursor is made to point to it, based on dir.
- * Return 0 if can't find any such record, 1 for success.
+ * stat is set to 0 if can't find any such record, 1 for success.
  */
 int                                    /* error */
 xfs_btree_lookup(
@@ -2756,7 +2775,6 @@ xfs_btree_make_block_unfull(
 
                if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
                        /* A root block that can be made bigger. */
-
                        xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork);
                } else {
                        /* A root block that needs replacing */
@@ -3868,3 +3886,120 @@ xfs_btree_get_rec(
        *stat = 1;
        return 0;
 }
+
+/*
+ * Change the owner of a btree.
+ *
+ * The mechanism we use here is ordered buffer logging. Because we don't know
+ * how many buffers were are going to need to modify, we don't really want to
+ * have to make transaction reservations for the worst case of every buffer in a
+ * full size btree as that may be more space that we can fit in the log....
+ *
+ * We do the btree walk in the most optimal manner possible - we have sibling
+ * pointers so we can just walk all the blocks on each level from left to right
+ * in a single pass, and then move to the next level and do the same. We can
+ * also do readahead on the sibling pointers to get IO moving more quickly,
+ * though for slow disks this is unlikely to make much difference to performance
+ * as the amount of CPU work we have to do before moving to the next block is
+ * relatively small.
+ *
+ * For each btree block that we load, modify the owner appropriately, set the
+ * buffer as an ordered buffer and log it appropriately. We need to ensure that
+ * we mark the region we change dirty so that if the buffer is relogged in
+ * a subsequent transaction the changes we make here as an ordered buffer are
+ * correctly relogged in that transaction.  If we are in recovery context, then
+ * just queue the modified buffer as delayed write buffer so the transaction
+ * recovery completion writes the changes to disk.
+ */
+static int
+xfs_btree_block_change_owner(
+       struct xfs_btree_cur    *cur,
+       int                     level,
+       __uint64_t              new_owner,
+       struct list_head        *buffer_list)
+{
+       struct xfs_btree_block  *block;
+       struct xfs_buf          *bp;
+       union xfs_btree_ptr     rptr;
+
+       /* do right sibling readahead */
+       xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
+
+       /* modify the owner */
+       block = xfs_btree_get_block(cur, level, &bp);
+       if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
+               block->bb_u.l.bb_owner = cpu_to_be64(new_owner);
+       else
+               block->bb_u.s.bb_owner = cpu_to_be32(new_owner);
+
+       /*
+        * If the block is a root block hosted in an inode, we might not have a
+        * buffer pointer here and we shouldn't attempt to log the change as the
+        * information is already held in the inode and discarded when the root
+        * block is formatted into the on-disk inode fork. We still change it,
+        * though, so everything is consistent in memory.
+        */
+       if (bp) {
+               if (cur->bc_tp) {
+                       xfs_trans_ordered_buf(cur->bc_tp, bp);
+                       xfs_btree_log_block(cur, bp, XFS_BB_OWNER);
+               } else {
+                       xfs_buf_delwri_queue(bp, buffer_list);
+               }
+       } else {
+               ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE);
+               ASSERT(level == cur->bc_nlevels - 1);
+       }
+
+       /* now read rh sibling block for next iteration */
+       xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB);
+       if (xfs_btree_ptr_is_null(cur, &rptr))
+               return ENOENT;
+
+       return xfs_btree_lookup_get_block(cur, level, &rptr, &block);
+}
+
+int
+xfs_btree_change_owner(
+       struct xfs_btree_cur    *cur,
+       __uint64_t              new_owner,
+       struct list_head        *buffer_list)
+{
+       union xfs_btree_ptr     lptr;
+       int                     level;
+       struct xfs_btree_block  *block = NULL;
+       int                     error = 0;
+
+       cur->bc_ops->init_ptr_from_cur(cur, &lptr);
+
+       /* for each level */
+       for (level = cur->bc_nlevels - 1; level >= 0; level--) {
+               /* grab the left hand block */
+               error = xfs_btree_lookup_get_block(cur, level, &lptr, &block);
+               if (error)
+                       return error;
+
+               /* readahead the left most block for the next level down */
+               if (level > 0) {
+                       union xfs_btree_ptr     *ptr;
+
+                       ptr = xfs_btree_ptr_addr(cur, 1, block);
+                       xfs_btree_readahead_ptr(cur, ptr, 1);
+
+                       /* save for the next iteration of the loop */
+                       lptr = *ptr;
+               }
+
+               /* for each buffer in the level */
+               do {
+                       error = xfs_btree_block_change_owner(cur, level,
+                                                            new_owner,
+                                                            buffer_list);
+               } while (!error);
+
+               if (error != ENOENT)
+                       return error;
+       }
+
+       return 0;
+}
index 55e3c7cc3c3d3f22178fb1feb8aab44679821172..06729b67ad58ec2c394a3ecdb1104938ced672c2 100644 (file)
@@ -88,13 +88,11 @@ struct xfs_btree_block {
 #define XFS_BTREE_SBLOCK_CRC_LEN       (XFS_BTREE_SBLOCK_LEN + 40)
 #define XFS_BTREE_LBLOCK_CRC_LEN       (XFS_BTREE_LBLOCK_LEN + 48)
 
-
 #define XFS_BTREE_SBLOCK_CRC_OFF \
        offsetof(struct xfs_btree_block, bb_u.s.bb_crc)
 #define XFS_BTREE_LBLOCK_CRC_OFF \
        offsetof(struct xfs_btree_block, bb_u.l.bb_crc)
 
-
 /*
  * Generic key, ptr and record wrapper structures.
  *
@@ -123,15 +121,18 @@ union xfs_btree_rec {
 /*
  * For logging record fields.
  */
-#define        XFS_BB_MAGIC            0x01
-#define        XFS_BB_LEVEL            0x02
-#define        XFS_BB_NUMRECS          0x04
-#define        XFS_BB_LEFTSIB          0x08
-#define        XFS_BB_RIGHTSIB         0x10
-#define        XFS_BB_BLKNO            0x20
+#define        XFS_BB_MAGIC            (1 << 0)
+#define        XFS_BB_LEVEL            (1 << 1)
+#define        XFS_BB_NUMRECS          (1 << 2)
+#define        XFS_BB_LEFTSIB          (1 << 3)
+#define        XFS_BB_RIGHTSIB         (1 << 4)
+#define        XFS_BB_BLKNO            (1 << 5)
+#define        XFS_BB_LSN              (1 << 6)
+#define        XFS_BB_UUID             (1 << 7)
+#define        XFS_BB_OWNER            (1 << 8)
 #define        XFS_BB_NUM_BITS         5
 #define        XFS_BB_ALL_BITS         ((1 << XFS_BB_NUM_BITS) - 1)
-#define        XFS_BB_NUM_BITS_CRC     8
+#define        XFS_BB_NUM_BITS_CRC     9
 #define        XFS_BB_ALL_BITS_CRC     ((1 << XFS_BB_NUM_BITS_CRC) - 1)
 
 /*
@@ -444,6 +445,8 @@ int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *);
 int xfs_btree_insert(struct xfs_btree_cur *, int *);
 int xfs_btree_delete(struct xfs_btree_cur *, int *);
 int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *);
+int xfs_btree_change_owner(struct xfs_btree_cur *cur, __uint64_t new_owner,
+                          struct list_head *buffer_list);
 
 /*
  * btree block CRC helpers
index 1b2472a46e46b96e31e0615f670120218ed7cf24..263470075ea2ce11dd39a83603e0b9fa1f0f5a60 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/freezer.h>
 
 #include "xfs_sb.h"
+#include "xfs_trans_resv.h"
 #include "xfs_log.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
@@ -79,54 +80,6 @@ xfs_buf_vmap_len(
        return (bp->b_page_count * PAGE_SIZE) - bp->b_offset;
 }
 
-/*
- * xfs_buf_lru_add - add a buffer to the LRU.
- *
- * The LRU takes a new reference to the buffer so that it will only be freed
- * once the shrinker takes the buffer off the LRU.
- */
-STATIC void
-xfs_buf_lru_add(
-       struct xfs_buf  *bp)
-{
-       struct xfs_buftarg *btp = bp->b_target;
-
-       spin_lock(&btp->bt_lru_lock);
-       if (list_empty(&bp->b_lru)) {
-               atomic_inc(&bp->b_hold);
-               list_add_tail(&bp->b_lru, &btp->bt_lru);
-               btp->bt_lru_nr++;
-               bp->b_lru_flags &= ~_XBF_LRU_DISPOSE;
-       }
-       spin_unlock(&btp->bt_lru_lock);
-}
-
-/*
- * xfs_buf_lru_del - remove a buffer from the LRU
- *
- * The unlocked check is safe here because it only occurs when there are not
- * b_lru_ref counts left on the inode under the pag->pag_buf_lock. it is there
- * to optimise the shrinker removing the buffer from the LRU and calling
- * xfs_buf_free(). i.e. it removes an unnecessary round trip on the
- * bt_lru_lock.
- */
-STATIC void
-xfs_buf_lru_del(
-       struct xfs_buf  *bp)
-{
-       struct xfs_buftarg *btp = bp->b_target;
-
-       if (list_empty(&bp->b_lru))
-               return;
-
-       spin_lock(&btp->bt_lru_lock);
-       if (!list_empty(&bp->b_lru)) {
-               list_del_init(&bp->b_lru);
-               btp->bt_lru_nr--;
-       }
-       spin_unlock(&btp->bt_lru_lock);
-}
-
 /*
  * When we mark a buffer stale, we remove the buffer from the LRU and clear the
  * b_lru_ref count so that the buffer is freed immediately when the buffer
@@ -150,20 +103,14 @@ xfs_buf_stale(
         */
        bp->b_flags &= ~_XBF_DELWRI_Q;
 
-       atomic_set(&(bp)->b_lru_ref, 0);
-       if (!list_empty(&bp->b_lru)) {
-               struct xfs_buftarg *btp = bp->b_target;
+       spin_lock(&bp->b_lock);
+       atomic_set(&bp->b_lru_ref, 0);
+       if (!(bp->b_state & XFS_BSTATE_DISPOSE) &&
+           (list_lru_del(&bp->b_target->bt_lru, &bp->b_lru)))
+               atomic_dec(&bp->b_hold);
 
-               spin_lock(&btp->bt_lru_lock);
-               if (!list_empty(&bp->b_lru) &&
-                   !(bp->b_lru_flags & _XBF_LRU_DISPOSE)) {
-                       list_del_init(&bp->b_lru);
-                       btp->bt_lru_nr--;
-                       atomic_dec(&bp->b_hold);
-               }
-               spin_unlock(&btp->bt_lru_lock);
-       }
        ASSERT(atomic_read(&bp->b_hold) >= 1);
+       spin_unlock(&bp->b_lock);
 }
 
 static int
@@ -227,6 +174,7 @@ _xfs_buf_alloc(
        INIT_LIST_HEAD(&bp->b_list);
        RB_CLEAR_NODE(&bp->b_rbnode);
        sema_init(&bp->b_sema, 0); /* held, no waiters */
+       spin_lock_init(&bp->b_lock);
        XB_SET_OWNER(bp);
        bp->b_target = target;
        bp->b_flags = flags;
@@ -303,7 +251,7 @@ _xfs_buf_free_pages(
  *     Releases the specified buffer.
  *
  *     The modification state of any associated pages is left unchanged.
- *     The buffer most not be on any hash - use xfs_buf_rele instead for
+ *     The buffer must not be on any hash - use xfs_buf_rele instead for
  *     hashed and refcounted buffers
  */
 void
@@ -916,12 +864,33 @@ xfs_buf_rele(
 
        ASSERT(atomic_read(&bp->b_hold) > 0);
        if (atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock)) {
-               if (!(bp->b_flags & XBF_STALE) &&
-                          atomic_read(&bp->b_lru_ref)) {
-                       xfs_buf_lru_add(bp);
+               spin_lock(&bp->b_lock);
+               if (!(bp->b_flags & XBF_STALE) && atomic_read(&bp->b_lru_ref)) {
+                       /*
+                        * If the buffer is added to the LRU take a new
+                        * reference to the buffer for the LRU and clear the
+                        * (now stale) dispose list state flag
+                        */
+                       if (list_lru_add(&bp->b_target->bt_lru, &bp->b_lru)) {
+                               bp->b_state &= ~XFS_BSTATE_DISPOSE;
+                               atomic_inc(&bp->b_hold);
+                       }
+                       spin_unlock(&bp->b_lock);
                        spin_unlock(&pag->pag_buf_lock);
                } else {
-                       xfs_buf_lru_del(bp);
+                       /*
+                        * most of the time buffers will already be removed from
+                        * the LRU, so optimise that case by checking for the
+                        * XFS_BSTATE_DISPOSE flag indicating the last list the
+                        * buffer was on was the disposal list
+                        */
+                       if (!(bp->b_state & XFS_BSTATE_DISPOSE)) {
+                               list_lru_del(&bp->b_target->bt_lru, &bp->b_lru);
+                       } else {
+                               ASSERT(list_empty(&bp->b_lru));
+                       }
+                       spin_unlock(&bp->b_lock);
+
                        ASSERT(!(bp->b_flags & _XBF_DELWRI_Q));
                        rb_erase(&bp->b_rbnode, &pag->pag_buf_tree);
                        spin_unlock(&pag->pag_buf_lock);
@@ -1501,83 +1470,121 @@ xfs_buf_iomove(
  * returned. These buffers will have an elevated hold count, so wait on those
  * while freeing all the buffers only held by the LRU.
  */
+static enum lru_status
+xfs_buftarg_wait_rele(
+       struct list_head        *item,
+       spinlock_t              *lru_lock,
+       void                    *arg)
+
+{
+       struct xfs_buf          *bp = container_of(item, struct xfs_buf, b_lru);
+       struct list_head        *dispose = arg;
+
+       if (atomic_read(&bp->b_hold) > 1) {
+               /* need to wait, so skip it this pass */
+               trace_xfs_buf_wait_buftarg(bp, _RET_IP_);
+               return LRU_SKIP;
+       }
+       if (!spin_trylock(&bp->b_lock))
+               return LRU_SKIP;
+
+       /*
+        * clear the LRU reference count so the buffer doesn't get
+        * ignored in xfs_buf_rele().
+        */
+       atomic_set(&bp->b_lru_ref, 0);
+       bp->b_state |= XFS_BSTATE_DISPOSE;
+       list_move(item, dispose);
+       spin_unlock(&bp->b_lock);
+       return LRU_REMOVED;
+}
+
 void
 xfs_wait_buftarg(
        struct xfs_buftarg      *btp)
 {
-       struct xfs_buf          *bp;
+       LIST_HEAD(dispose);
+       int loop = 0;
 
-restart:
-       spin_lock(&btp->bt_lru_lock);
-       while (!list_empty(&btp->bt_lru)) {
-               bp = list_first_entry(&btp->bt_lru, struct xfs_buf, b_lru);
-               if (atomic_read(&bp->b_hold) > 1) {
-                       trace_xfs_buf_wait_buftarg(bp, _RET_IP_);
-                       list_move_tail(&bp->b_lru, &btp->bt_lru);
-                       spin_unlock(&btp->bt_lru_lock);
-                       delay(100);
-                       goto restart;
+       /* loop until there is nothing left on the lru list. */
+       while (list_lru_count(&btp->bt_lru)) {
+               list_lru_walk(&btp->bt_lru, xfs_buftarg_wait_rele,
+                             &dispose, LONG_MAX);
+
+               while (!list_empty(&dispose)) {
+                       struct xfs_buf *bp;
+                       bp = list_first_entry(&dispose, struct xfs_buf, b_lru);
+                       list_del_init(&bp->b_lru);
+                       xfs_buf_rele(bp);
                }
-               /*
-                * clear the LRU reference count so the buffer doesn't get
-                * ignored in xfs_buf_rele().
-                */
-               atomic_set(&bp->b_lru_ref, 0);
-               spin_unlock(&btp->bt_lru_lock);
-               xfs_buf_rele(bp);
-               spin_lock(&btp->bt_lru_lock);
+               if (loop++ != 0)
+                       delay(100);
        }
-       spin_unlock(&btp->bt_lru_lock);
 }
 
-int
-xfs_buftarg_shrink(
+static enum lru_status
+xfs_buftarg_isolate(
+       struct list_head        *item,
+       spinlock_t              *lru_lock,
+       void                    *arg)
+{
+       struct xfs_buf          *bp = container_of(item, struct xfs_buf, b_lru);
+       struct list_head        *dispose = arg;
+
+       /*
+        * we are inverting the lru lock/bp->b_lock here, so use a trylock.
+        * If we fail to get the lock, just skip it.
+        */
+       if (!spin_trylock(&bp->b_lock))
+               return LRU_SKIP;
+       /*
+        * Decrement the b_lru_ref count unless the value is already
+        * zero. If the value is already zero, we need to reclaim the
+        * buffer, otherwise it gets another trip through the LRU.
+        */
+       if (!atomic_add_unless(&bp->b_lru_ref, -1, 0)) {
+               spin_unlock(&bp->b_lock);
+               return LRU_ROTATE;
+       }
+
+       bp->b_state |= XFS_BSTATE_DISPOSE;
+       list_move(item, dispose);
+       spin_unlock(&bp->b_lock);
+       return LRU_REMOVED;
+}
+
+static unsigned long
+xfs_buftarg_shrink_scan(
        struct shrinker         *shrink,
        struct shrink_control   *sc)
 {
        struct xfs_buftarg      *btp = container_of(shrink,
                                        struct xfs_buftarg, bt_shrinker);
-       struct xfs_buf          *bp;
-       int nr_to_scan = sc->nr_to_scan;
        LIST_HEAD(dispose);
+       unsigned long           freed;
+       unsigned long           nr_to_scan = sc->nr_to_scan;
 
-       if (!nr_to_scan)
-               return btp->bt_lru_nr;
-
-       spin_lock(&btp->bt_lru_lock);
-       while (!list_empty(&btp->bt_lru)) {
-               if (nr_to_scan-- <= 0)
-                       break;
-
-               bp = list_first_entry(&btp->bt_lru, struct xfs_buf, b_lru);
-
-               /*
-                * Decrement the b_lru_ref count unless the value is already
-                * zero. If the value is already zero, we need to reclaim the
-                * buffer, otherwise it gets another trip through the LRU.
-                */
-               if (!atomic_add_unless(&bp->b_lru_ref, -1, 0)) {
-                       list_move_tail(&bp->b_lru, &btp->bt_lru);
-                       continue;
-               }
-
-               /*
-                * remove the buffer from the LRU now to avoid needing another
-                * lock round trip inside xfs_buf_rele().
-                */
-               list_move(&bp->b_lru, &dispose);
-               btp->bt_lru_nr--;
-               bp->b_lru_flags |= _XBF_LRU_DISPOSE;
-       }
-       spin_unlock(&btp->bt_lru_lock);
+       freed = list_lru_walk_node(&btp->bt_lru, sc->nid, xfs_buftarg_isolate,
+                                      &dispose, &nr_to_scan);
 
        while (!list_empty(&dispose)) {
+               struct xfs_buf *bp;
                bp = list_first_entry(&dispose, struct xfs_buf, b_lru);
                list_del_init(&bp->b_lru);
                xfs_buf_rele(bp);
        }
 
-       return btp->bt_lru_nr;
+       return freed;
+}
+
+static unsigned long
+xfs_buftarg_shrink_count(
+       struct shrinker         *shrink,
+       struct shrink_control   *sc)
+{
+       struct xfs_buftarg      *btp = container_of(shrink,
+                                       struct xfs_buftarg, bt_shrinker);
+       return list_lru_count_node(&btp->bt_lru, sc->nid);
 }
 
 void
@@ -1586,6 +1593,7 @@ xfs_free_buftarg(
        struct xfs_buftarg      *btp)
 {
        unregister_shrinker(&btp->bt_shrinker);
+       list_lru_destroy(&btp->bt_lru);
 
        if (mp->m_flags & XFS_MOUNT_BARRIER)
                xfs_blkdev_issue_flush(btp);
@@ -1621,7 +1629,7 @@ xfs_setsize_buftarg_flags(
 /*
  *     When allocating the initial buffer target we have not yet
  *     read in the superblock, so don't know what sized sectors
- *     are being used is at this early stage.  Play safe.
+ *     are being used at this early stage.  Play safe.
  */
 STATIC int
 xfs_setsize_buftarg_early(
@@ -1659,12 +1667,16 @@ xfs_alloc_buftarg(
        if (!btp->bt_bdi)
                goto error;
 
-       INIT_LIST_HEAD(&btp->bt_lru);
-       spin_lock_init(&btp->bt_lru_lock);
        if (xfs_setsize_buftarg_early(btp, bdev))
                goto error;
-       btp->bt_shrinker.shrink = xfs_buftarg_shrink;
+
+       if (list_lru_init(&btp->bt_lru))
+               goto error;
+
+       btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count;
+       btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan;
        btp->bt_shrinker.seeks = DEFAULT_SEEKS;
+       btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE;
        register_shrinker(&btp->bt_shrinker);
        return btp;
 
index 433a12ed7b179e44ef784e8a144346af4faa9852..e65683361017745eff61e245ee72896d2e6ff8df 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/fs.h>
 #include <linux/buffer_head.h>
 #include <linux/uio.h>
+#include <linux/list_lru.h>
 
 /*
  *     Base types
@@ -59,7 +60,6 @@ typedef enum {
 #define _XBF_KMEM       (1 << 21)/* backed by heap memory */
 #define _XBF_DELWRI_Q   (1 << 22)/* buffer on a delwri queue */
 #define _XBF_COMPOUND   (1 << 23)/* compound buffer */
-#define _XBF_LRU_DISPOSE (1 << 24)/* buffer being discarded */
 
 typedef unsigned int xfs_buf_flags_t;
 
@@ -78,8 +78,12 @@ typedef unsigned int xfs_buf_flags_t;
        { _XBF_PAGES,           "PAGES" }, \
        { _XBF_KMEM,            "KMEM" }, \
        { _XBF_DELWRI_Q,        "DELWRI_Q" }, \
-       { _XBF_COMPOUND,        "COMPOUND" }, \
-       { _XBF_LRU_DISPOSE,     "LRU_DISPOSE" }
+       { _XBF_COMPOUND,        "COMPOUND" }
+
+/*
+ * Internal state flags.
+ */
+#define XFS_BSTATE_DISPOSE      (1 << 0)       /* buffer being discarded */
 
 typedef struct xfs_buftarg {
        dev_t                   bt_dev;
@@ -92,9 +96,7 @@ typedef struct xfs_buftarg {
 
        /* LRU control structures */
        struct shrinker         bt_shrinker;
-       struct list_head        bt_lru;
-       spinlock_t              bt_lru_lock;
-       unsigned int            bt_lru_nr;
+       struct list_lru         bt_lru;
 } xfs_buftarg_t;
 
 struct xfs_buf;
@@ -137,7 +139,8 @@ typedef struct xfs_buf {
         * bt_lru_lock and not by b_sema
         */
        struct list_head        b_lru;          /* lru list */
-       xfs_buf_flags_t         b_lru_flags;    /* internal lru status flags */
+       spinlock_t              b_lock;         /* internal state lock */
+       unsigned int            b_state;        /* internal state flags */
        wait_queue_head_t       b_waiters;      /* unpin waiters */
        struct list_head        b_list;
        struct xfs_perag        *b_pag;         /* contains rbtree root */
index bfc4e0c26fd3404fb36f007da344be79543aea4c..88c5ea75ebf66abd175bdf2d71898380f2aca9a8 100644 (file)
@@ -39,6 +39,14 @@ static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip)
 
 STATIC void    xfs_buf_do_callbacks(struct xfs_buf *bp);
 
+static inline int
+xfs_buf_log_format_size(
+       struct xfs_buf_log_format *blfp)
+{
+       return offsetof(struct xfs_buf_log_format, blf_data_map) +
+                       (blfp->blf_map_size * sizeof(blfp->blf_data_map[0]));
+}
+
 /*
  * This returns the number of log iovecs needed to log the
  * given buf log item.
@@ -49,25 +57,27 @@ STATIC void xfs_buf_do_callbacks(struct xfs_buf *bp);
  *
  * If the XFS_BLI_STALE flag has been set, then log nothing.
  */
-STATIC uint
+STATIC void
 xfs_buf_item_size_segment(
        struct xfs_buf_log_item *bip,
-       struct xfs_buf_log_format *blfp)
+       struct xfs_buf_log_format *blfp,
+       int                     *nvecs,
+       int                     *nbytes)
 {
        struct xfs_buf          *bp = bip->bli_buf;
-       uint                    nvecs;
        int                     next_bit;
        int                     last_bit;
 
        last_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
        if (last_bit == -1)
-               return 0;
+               return;
 
        /*
         * initial count for a dirty buffer is 2 vectors - the format structure
         * and the first dirty region.
         */
-       nvecs = 2;
+       *nvecs += 2;
+       *nbytes += xfs_buf_log_format_size(blfp) + XFS_BLF_CHUNK;
 
        while (last_bit != -1) {
                /*
@@ -87,18 +97,17 @@ xfs_buf_item_size_segment(
                        break;
                } else if (next_bit != last_bit + 1) {
                        last_bit = next_bit;
-                       nvecs++;
+                       (*nvecs)++;
                } 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++;
+                       (*nvecs)++;
                } else {
                        last_bit++;
                }
+               *nbytes += XFS_BLF_CHUNK;
        }
-
-       return nvecs;
 }
 
 /*
@@ -118,12 +127,13 @@ xfs_buf_item_size_segment(
  * If the XFS_BLI_STALE flag has been set, then log nothing but the buf log
  * format structures.
  */
-STATIC uint
+STATIC void
 xfs_buf_item_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
        struct xfs_buf_log_item *bip = BUF_ITEM(lip);
-       uint                    nvecs;
        int                     i;
 
        ASSERT(atomic_read(&bip->bli_refcount) > 0);
@@ -135,7 +145,11 @@ xfs_buf_item_size(
                 */
                trace_xfs_buf_item_size_stale(bip);
                ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
-               return bip->bli_format_count;
+               *nvecs += bip->bli_format_count;
+               for (i = 0; i < bip->bli_format_count; i++) {
+                       *nbytes += xfs_buf_log_format_size(&bip->bli_formats[i]);
+               }
+               return;
        }
 
        ASSERT(bip->bli_flags & XFS_BLI_LOGGED);
@@ -147,7 +161,8 @@ xfs_buf_item_size(
                 * commit, so no vectors are used at all.
                 */
                trace_xfs_buf_item_size_ordered(bip);
-               return XFS_LOG_VEC_ORDERED;
+               *nvecs = XFS_LOG_VEC_ORDERED;
+               return;
        }
 
        /*
@@ -159,13 +174,11 @@ xfs_buf_item_size(
         * count for the extra buf log format structure that will need to be
         * written.
         */
-       nvecs = 0;
        for (i = 0; i < bip->bli_format_count; i++) {
-               nvecs += xfs_buf_item_size_segment(bip, &bip->bli_formats[i]);
+               xfs_buf_item_size_segment(bip, &bip->bli_formats[i],
+                                         nvecs, nbytes);
        }
-
        trace_xfs_buf_item_size(bip);
-       return nvecs;
 }
 
 static struct xfs_log_iovec *
@@ -192,8 +205,7 @@ xfs_buf_item_format_segment(
         * the actual size of the dirty bitmap rather than the size of the in
         * memory structure.
         */
-       base_size = offsetof(struct xfs_buf_log_format, blf_data_map) +
-                       (blfp->blf_map_size * sizeof(blfp->blf_data_map[0]));
+       base_size = xfs_buf_log_format_size(blfp);
 
        nvecs = 0;
        first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
@@ -601,15 +613,27 @@ xfs_buf_item_unlock(
                        }
                }
        }
-       if (clean)
-               xfs_buf_item_relse(bp);
-       else if (aborted) {
-               if (atomic_dec_and_test(&bip->bli_refcount)) {
+
+       /*
+        * Clean buffers, by definition, cannot be in the AIL. However, aborted
+        * buffers may be dirty and hence in the AIL. Therefore if we are
+        * aborting a buffer and we've just taken the last refernce away, we
+        * have to check if it is in the AIL before freeing it. We need to free
+        * it in this case, because an aborted transaction has already shut the
+        * filesystem down and this is the last chance we will have to do so.
+        */
+       if (atomic_dec_and_test(&bip->bli_refcount)) {
+               if (clean)
+                       xfs_buf_item_relse(bp);
+               else if (aborted) {
                        ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp));
+                       if (lip->li_flags & XFS_LI_IN_AIL) {
+                               xfs_trans_ail_delete(lip->li_ailp, lip,
+                                                    SHUTDOWN_LOG_IO_ERROR);
+                       }
                        xfs_buf_item_relse(bp);
                }
-       } else
-               atomic_dec(&bip->bli_refcount);
+       }
 
        if (!(flags & XFS_BLI_HOLD))
                xfs_buf_relse(bp);
index 0f1c247dc680031fe06554a4bd41f6f962290a53..db6371087fe8ea9b786f82189b387c55979a2460 100644 (file)
 #ifndef        __XFS_BUF_ITEM_H__
 #define        __XFS_BUF_ITEM_H__
 
-extern kmem_zone_t     *xfs_buf_item_zone;
-
-/*
- * This flag indicates that the buffer contains on disk inodes
- * and requires special recovery handling.
- */
-#define        XFS_BLF_INODE_BUF       (1<<0)
-/*
- * This flag indicates that the buffer should not be replayed
- * during recovery because its blocks are being freed.
- */
-#define        XFS_BLF_CANCEL          (1<<1)
-
-/*
- * This flag indicates that the buffer contains on disk
- * user or group dquots and may require special recovery handling.
- */
-#define        XFS_BLF_UDQUOT_BUF      (1<<2)
-#define XFS_BLF_PDQUOT_BUF     (1<<3)
-#define        XFS_BLF_GDQUOT_BUF      (1<<4)
-
-#define        XFS_BLF_CHUNK           128
-#define        XFS_BLF_SHIFT           7
-#define        BIT_TO_WORD_SHIFT       5
-#define        NBWORD                  (NBBY * sizeof(unsigned int))
-
-/*
- * This is the structure used to lay out a buf log item in the
- * log.  The data map describes which 128 byte chunks of the buffer
- * have been logged.
- */
-#define XFS_BLF_DATAMAP_SIZE   ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD)
+/* kernel only definitions */
 
-typedef struct xfs_buf_log_format {
-       unsigned short  blf_type;       /* buf log item type indicator */
-       unsigned short  blf_size;       /* size of this item */
-       ushort          blf_flags;      /* misc state */
-       ushort          blf_len;        /* number of blocks in this buf */
-       __int64_t       blf_blkno;      /* starting blkno of this buf */
-       unsigned int    blf_map_size;   /* used size of data bitmap in words */
-       unsigned int    blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */
-} xfs_buf_log_format_t;
-
-/*
- * All buffers now need to tell recovery where the magic number
- * is so that it can verify and calculate the CRCs on the buffer correctly
- * once the changes have been replayed into the buffer.
- *
- * The type value is held in the upper 5 bits of the blf_flags field, which is
- * an unsigned 16 bit field. Hence we need to shift it 11 bits up and down.
- */
-#define XFS_BLFT_BITS  5
-#define XFS_BLFT_SHIFT 11
-#define XFS_BLFT_MASK  (((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT)
-
-enum xfs_blft {
-       XFS_BLFT_UNKNOWN_BUF = 0,
-       XFS_BLFT_UDQUOT_BUF,
-       XFS_BLFT_PDQUOT_BUF,
-       XFS_BLFT_GDQUOT_BUF,
-       XFS_BLFT_BTREE_BUF,
-       XFS_BLFT_AGF_BUF,
-       XFS_BLFT_AGFL_BUF,
-       XFS_BLFT_AGI_BUF,
-       XFS_BLFT_DINO_BUF,
-       XFS_BLFT_SYMLINK_BUF,
-       XFS_BLFT_DIR_BLOCK_BUF,
-       XFS_BLFT_DIR_DATA_BUF,
-       XFS_BLFT_DIR_FREE_BUF,
-       XFS_BLFT_DIR_LEAF1_BUF,
-       XFS_BLFT_DIR_LEAFN_BUF,
-       XFS_BLFT_DA_NODE_BUF,
-       XFS_BLFT_ATTR_LEAF_BUF,
-       XFS_BLFT_ATTR_RMT_BUF,
-       XFS_BLFT_SB_BUF,
-       XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS),
-};
-
-static inline void
-xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type)
-{
-       ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF);
-       blf->blf_flags &= ~XFS_BLFT_MASK;
-       blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK);
-}
-
-static inline __uint16_t
-xfs_blft_from_flags(struct xfs_buf_log_format *blf)
-{
-       return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT;
-}
-
-/*
- * buf log item flags
- */
+/* buf log item flags */
 #define        XFS_BLI_HOLD            0x01
 #define        XFS_BLI_DIRTY           0x02
 #define        XFS_BLI_STALE           0x04
@@ -133,8 +41,6 @@ xfs_blft_from_flags(struct xfs_buf_log_format *blf)
        { XFS_BLI_ORDERED,      "ORDERED" }
 
 
-#ifdef __KERNEL__
-
 struct xfs_buf;
 struct xfs_mount;
 struct xfs_buf_log_item;
@@ -169,6 +75,6 @@ void xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *,
                               enum xfs_blft);
 void   xfs_trans_buf_copy_type(struct xfs_buf *dst_bp, struct xfs_buf *src_bp);
 
-#endif /* __KERNEL__ */
+extern kmem_zone_t     *xfs_buf_item_zone;
 
 #endif /* __XFS_BUF_ITEM_H__ */
index 0b8b2a13cd24debe493c8982679a2c565ebae5a1..069537c845e5cc424ce02bf3cec7838250357a32 100644 (file)
@@ -27,8 +27,8 @@
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
-#include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
@@ -399,7 +399,7 @@ xfs_da3_split(
        struct xfs_da_intnode   *node;
        struct xfs_buf          *bp;
        int                     max;
-       int                     action;
+       int                     action = 0;
        int                     error;
        int                     i;
 
@@ -635,6 +635,7 @@ xfs_da3_root_split(
        xfs_trans_log_buf(tp, bp, 0, size - 1);
 
        bp->b_ops = blk1->bp->b_ops;
+       xfs_trans_buf_copy_type(bp, blk1->bp);
        blk1->bp = bp;
        blk1->blkno = blkno;
 
@@ -2454,9 +2455,9 @@ static int
 xfs_buf_map_from_irec(
        struct xfs_mount        *mp,
        struct xfs_buf_map      **mapp,
-       unsigned int            *nmaps,
+       int                     *nmaps,
        struct xfs_bmbt_irec    *irecs,
-       unsigned int            nirecs)
+       int                     nirecs)
 {
        struct xfs_buf_map      *map;
        int                     i;
index 6fb3371c63cf3db535ea84cd6d62c31445b8c4f2..b1f267995dea32e97dc041c7dd14af77e1630dc8 100644 (file)
@@ -133,12 +133,19 @@ extern void xfs_da3_node_hdr_to_disk(struct xfs_da_intnode *to,
                                     struct xfs_da3_icnode_hdr *from);
 
 static inline int
-xfs_da3_node_hdr_size(struct xfs_da_intnode *dap)
+__xfs_da3_node_hdr_size(bool v3)
 {
-       if (dap->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC))
+       if (v3)
                return sizeof(struct xfs_da3_node_hdr);
        return sizeof(struct xfs_da_node_hdr);
 }
+static inline int
+xfs_da3_node_hdr_size(struct xfs_da_intnode *dap)
+{
+       bool    v3 = dap->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC);
+
+       return __xfs_da3_node_hdr_size(v3);
+}
 
 static inline struct xfs_da_node_entry *
 xfs_da3_node_tree_p(struct xfs_da_intnode *dap)
@@ -176,6 +183,7 @@ enum xfs_dacmp {
 typedef struct xfs_da_args {
        const __uint8_t *name;          /* string (maybe not NULL terminated) */
        int             namelen;        /* length of string (maybe no NULL) */
+       __uint8_t       filetype;       /* filetype of inode for directories */
        __uint8_t       *value;         /* set of bytes (maybe contain NULLs) */
        int             valuelen;       /* length of value */
        int             flags;          /* argument flags (eg: ATTR_NOCREATE) */
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
deleted file mode 100644 (file)
index e36445c..0000000
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (c) 2000-2006 Silicon Graphics, 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_log.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_mount.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_btree.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_bmap.h"
-#include "xfs_itable.h"
-#include "xfs_dfrag.h"
-#include "xfs_error.h"
-#include "xfs_vnodeops.h"
-#include "xfs_trace.h"
-
-
-static int xfs_swap_extents(
-       xfs_inode_t     *ip,    /* target inode */
-       xfs_inode_t     *tip,   /* tmp inode */
-       xfs_swapext_t   *sxp);
-
-/*
- * ioctl interface for swapext
- */
-int
-xfs_swapext(
-       xfs_swapext_t   *sxp)
-{
-       xfs_inode_t     *ip, *tip;
-       struct fd       f, tmp;
-       int             error = 0;
-
-       /* Pull information for the target fd */
-       f = fdget((int)sxp->sx_fdtarget);
-       if (!f.file) {
-               error = XFS_ERROR(EINVAL);
-               goto out;
-       }
-
-       if (!(f.file->f_mode & FMODE_WRITE) ||
-           !(f.file->f_mode & FMODE_READ) ||
-           (f.file->f_flags & O_APPEND)) {
-               error = XFS_ERROR(EBADF);
-               goto out_put_file;
-       }
-
-       tmp = fdget((int)sxp->sx_fdtmp);
-       if (!tmp.file) {
-               error = XFS_ERROR(EINVAL);
-               goto out_put_file;
-       }
-
-       if (!(tmp.file->f_mode & FMODE_WRITE) ||
-           !(tmp.file->f_mode & FMODE_READ) ||
-           (tmp.file->f_flags & O_APPEND)) {
-               error = XFS_ERROR(EBADF);
-               goto out_put_tmp_file;
-       }
-
-       if (IS_SWAPFILE(file_inode(f.file)) ||
-           IS_SWAPFILE(file_inode(tmp.file))) {
-               error = XFS_ERROR(EINVAL);
-               goto out_put_tmp_file;
-       }
-
-       ip = XFS_I(file_inode(f.file));
-       tip = XFS_I(file_inode(tmp.file));
-
-       if (ip->i_mount != tip->i_mount) {
-               error = XFS_ERROR(EINVAL);
-               goto out_put_tmp_file;
-       }
-
-       if (ip->i_ino == tip->i_ino) {
-               error = XFS_ERROR(EINVAL);
-               goto out_put_tmp_file;
-       }
-
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
-               error = XFS_ERROR(EIO);
-               goto out_put_tmp_file;
-       }
-
-       error = xfs_swap_extents(ip, tip, sxp);
-
- out_put_tmp_file:
-       fdput(tmp);
- out_put_file:
-       fdput(f);
- out:
-       return error;
-}
-
-/*
- * We need to check that the format of the data fork in the temporary inode is
- * valid for the target inode before doing the swap. This is not a problem with
- * attr1 because of the fixed fork offset, but attr2 has a dynamically sized
- * data fork depending on the space the attribute fork is taking so we can get
- * invalid formats on the target inode.
- *
- * E.g. target has space for 7 extents in extent format, temp inode only has
- * space for 6.  If we defragment down to 7 extents, then the tmp format is a
- * btree, but when swapped it needs to be in extent format. Hence we can't just
- * blindly swap data forks on attr2 filesystems.
- *
- * Note that we check the swap in both directions so that we don't end up with
- * a corrupt temporary inode, either.
- *
- * Note that fixing the way xfs_fsr sets up the attribute fork in the source
- * inode will prevent this situation from occurring, so all we do here is
- * reject and log the attempt. basically we are putting the responsibility on
- * userspace to get this right.
- */
-static int
-xfs_swap_extents_check_format(
-       xfs_inode_t     *ip,    /* target inode */
-       xfs_inode_t     *tip)   /* tmp inode */
-{
-
-       /* Should never get a local format */
-       if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL ||
-           tip->i_d.di_format == XFS_DINODE_FMT_LOCAL)
-               return EINVAL;
-
-       /*
-        * if the target inode has less extents that then temporary inode then
-        * why did userspace call us?
-        */
-       if (ip->i_d.di_nextents < tip->i_d.di_nextents)
-               return EINVAL;
-
-       /*
-        * if the target inode is in extent form and the temp inode is in btree
-        * form then we will end up with the target inode in the wrong format
-        * as we already know there are less extents in the temp inode.
-        */
-       if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-           tip->i_d.di_format == XFS_DINODE_FMT_BTREE)
-               return EINVAL;
-
-       /* Check temp in extent form to max in target */
-       if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) >
-                       XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
-               return EINVAL;
-
-       /* Check target in extent form to max in temp */
-       if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS &&
-           XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) >
-                       XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
-               return EINVAL;
-
-       /*
-        * If we are in a btree format, check that the temp root block will fit
-        * in the target and that it has enough extents to be in btree format
-        * in the target.
-        *
-        * Note that we have to be careful to allow btree->extent conversions
-        * (a common defrag case) which will occur when the temp inode is in
-        * extent format...
-        */
-       if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
-               if (XFS_IFORK_BOFF(ip) &&
-                   XFS_BMAP_BMDR_SPACE(tip->i_df.if_broot) > XFS_IFORK_BOFF(ip))
-                       return EINVAL;
-               if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <=
-                   XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK))
-                       return EINVAL;
-       }
-
-       /* Reciprocal target->temp btree format checks */
-       if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) {
-               if (XFS_IFORK_BOFF(tip) &&
-                   XFS_BMAP_BMDR_SPACE(ip->i_df.if_broot) > XFS_IFORK_BOFF(tip))
-                       return EINVAL;
-               if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <=
-                   XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK))
-                       return EINVAL;
-       }
-
-       return 0;
-}
-
-static int
-xfs_swap_extents(
-       xfs_inode_t     *ip,    /* target inode */
-       xfs_inode_t     *tip,   /* tmp inode */
-       xfs_swapext_t   *sxp)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       xfs_trans_t     *tp;
-       xfs_bstat_t     *sbp = &sxp->sx_stat;
-       xfs_ifork_t     *tempifp, *ifp, *tifp;
-       int             src_log_flags, target_log_flags;
-       int             error = 0;
-       int             aforkblks = 0;
-       int             taforkblks = 0;
-       __uint64_t      tmp;
-
-       /*
-        * We have no way of updating owner information in the BMBT blocks for
-        * each inode on CRC enabled filesystems, so to avoid corrupting the
-        * this metadata we simply don't allow extent swaps to occur.
-        */
-       if (xfs_sb_version_hascrc(&mp->m_sb))
-               return XFS_ERROR(EINVAL);
-
-       tempifp = kmem_alloc(sizeof(xfs_ifork_t), KM_MAYFAIL);
-       if (!tempifp) {
-               error = XFS_ERROR(ENOMEM);
-               goto out;
-       }
-
-       /*
-        * we have to do two separate lock calls here to keep lockdep
-        * happy. If we try to get all the locks in one call, lock will
-        * report false positives when we drop the ILOCK and regain them
-        * below.
-        */
-       xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL);
-       xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
-
-       /* Verify that both files have the same format */
-       if ((ip->i_d.di_mode & S_IFMT) != (tip->i_d.di_mode & S_IFMT)) {
-               error = XFS_ERROR(EINVAL);
-               goto out_unlock;
-       }
-
-       /* Verify both files are either real-time or non-realtime */
-       if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) {
-               error = XFS_ERROR(EINVAL);
-               goto out_unlock;
-       }
-
-       error = -filemap_write_and_wait(VFS_I(tip)->i_mapping);
-       if (error)
-               goto out_unlock;
-       truncate_pagecache_range(VFS_I(tip), 0, -1);
-
-       /* Verify O_DIRECT for ftmp */
-       if (VN_CACHED(VFS_I(tip)) != 0) {
-               error = XFS_ERROR(EINVAL);
-               goto out_unlock;
-       }
-
-       /* Verify all data are being swapped */
-       if (sxp->sx_offset != 0 ||
-           sxp->sx_length != ip->i_d.di_size ||
-           sxp->sx_length != tip->i_d.di_size) {
-               error = XFS_ERROR(EFAULT);
-               goto out_unlock;
-       }
-
-       trace_xfs_swap_extent_before(ip, 0);
-       trace_xfs_swap_extent_before(tip, 1);
-
-       /* check inode formats now that data is flushed */
-       error = xfs_swap_extents_check_format(ip, tip);
-       if (error) {
-               xfs_notice(mp,
-                   "%s: inode 0x%llx format is incompatible for exchanging.",
-                               __func__, ip->i_ino);
-               goto out_unlock;
-       }
-
-       /*
-        * Compare the current change & modify times with that
-        * passed in.  If they differ, we abort this swap.
-        * This is the mechanism used to ensure the calling
-        * process that the file was not changed out from
-        * under it.
-        */
-       if ((sbp->bs_ctime.tv_sec != VFS_I(ip)->i_ctime.tv_sec) ||
-           (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) ||
-           (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
-           (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
-               error = XFS_ERROR(EBUSY);
-               goto out_unlock;
-       }
-
-       /* We need to fail if the file is memory mapped.  Once we have tossed
-        * all existing pages, the page fault will have no option
-        * but to go to the filesystem for pages. By making the page fault call
-        * vop_read (or write in the case of autogrow) they block on the iolock
-        * until we have switched the extents.
-        */
-       if (VN_MAPPED(VFS_I(ip))) {
-               error = XFS_ERROR(EBUSY);
-               goto out_unlock;
-       }
-
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       xfs_iunlock(tip, XFS_ILOCK_EXCL);
-
-       /*
-        * There is a race condition here since we gave up the
-        * ilock.  However, the data fork will not change since
-        * we have the iolock (locked for truncation too) so we
-        * are safe.  We don't really care if non-io related
-        * fields change.
-        */
-       truncate_pagecache_range(VFS_I(ip), 0, -1);
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_SWAPEXT);
-       if ((error = xfs_trans_reserve(tp, 0,
-                                    XFS_ICHANGE_LOG_RES(mp), 0,
-                                    0, 0))) {
-               xfs_iunlock(ip,  XFS_IOLOCK_EXCL);
-               xfs_iunlock(tip, XFS_IOLOCK_EXCL);
-               xfs_trans_cancel(tp, 0);
-               goto out;
-       }
-       xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL);
-
-       /*
-        * Count the number of extended attribute blocks
-        */
-       if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) &&
-            (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
-               error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, &aforkblks);
-               if (error)
-                       goto out_trans_cancel;
-       }
-       if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) &&
-            (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) {
-               error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK,
-                       &taforkblks);
-               if (error)
-                       goto out_trans_cancel;
-       }
-
-       /*
-        * Swap the data forks of the inodes
-        */
-       ifp = &ip->i_df;
-       tifp = &tip->i_df;
-       *tempifp = *ifp;        /* struct copy */
-       *ifp = *tifp;           /* struct copy */
-       *tifp = *tempifp;       /* struct copy */
-
-       /*
-        * Fix the on-disk inode values
-        */
-       tmp = (__uint64_t)ip->i_d.di_nblocks;
-       ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks;
-       tip->i_d.di_nblocks = tmp + taforkblks - aforkblks;
-
-       tmp = (__uint64_t) ip->i_d.di_nextents;
-       ip->i_d.di_nextents = tip->i_d.di_nextents;
-       tip->i_d.di_nextents = tmp;
-
-       tmp = (__uint64_t) ip->i_d.di_format;
-       ip->i_d.di_format = tip->i_d.di_format;
-       tip->i_d.di_format = tmp;
-
-       /*
-        * The extents in the source inode could still contain speculative
-        * preallocation beyond EOF (e.g. the file is open but not modified
-        * while defrag is in progress). In that case, we need to copy over the
-        * number of delalloc blocks the data fork in the source inode is
-        * tracking beyond EOF so that when the fork is truncated away when the
-        * temporary inode is unlinked we don't underrun the i_delayed_blks
-        * counter on that inode.
-        */
-       ASSERT(tip->i_delayed_blks == 0);
-       tip->i_delayed_blks = ip->i_delayed_blks;
-       ip->i_delayed_blks = 0;
-
-       src_log_flags = XFS_ILOG_CORE;
-       switch (ip->i_d.di_format) {
-       case XFS_DINODE_FMT_EXTENTS:
-               /* If the extents fit in the inode, fix the
-                * pointer.  Otherwise it's already NULL or
-                * pointing to the extent.
-                */
-               if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) {
-                       ifp->if_u1.if_extents =
-                               ifp->if_u2.if_inline_ext;
-               }
-               src_log_flags |= XFS_ILOG_DEXT;
-               break;
-       case XFS_DINODE_FMT_BTREE:
-               src_log_flags |= XFS_ILOG_DBROOT;
-               break;
-       }
-
-       target_log_flags = XFS_ILOG_CORE;
-       switch (tip->i_d.di_format) {
-       case XFS_DINODE_FMT_EXTENTS:
-               /* If the extents fit in the inode, fix the
-                * pointer.  Otherwise it's already NULL or
-                * pointing to the extent.
-                */
-               if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) {
-                       tifp->if_u1.if_extents =
-                               tifp->if_u2.if_inline_ext;
-               }
-               target_log_flags |= XFS_ILOG_DEXT;
-               break;
-       case XFS_DINODE_FMT_BTREE:
-               target_log_flags |= XFS_ILOG_DBROOT;
-               break;
-       }
-
-
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_trans_ijoin(tp, tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-
-       xfs_trans_log_inode(tp, ip,  src_log_flags);
-       xfs_trans_log_inode(tp, tip, target_log_flags);
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * transaction goes to disk before returning to the user.
-        */
-       if (mp->m_flags & XFS_MOUNT_WSYNC)
-               xfs_trans_set_sync(tp);
-
-       error = xfs_trans_commit(tp, 0);
-
-       trace_xfs_swap_extent_after(ip, 0);
-       trace_xfs_swap_extent_after(tip, 1);
-out:
-       kmem_free(tempifp);
-       return error;
-
-out_unlock:
-       xfs_iunlock(ip,  XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       xfs_iunlock(tip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
-       goto out;
-
-out_trans_cancel:
-       xfs_trans_cancel(tp, 0);
-       goto out_unlock;
-}
diff --git a/fs/xfs/xfs_dfrag.h b/fs/xfs/xfs_dfrag.h
deleted file mode 100644 (file)
index 20bdd93..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2000,2005 Silicon Graphics, 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
- */
-#ifndef __XFS_DFRAG_H__
-#define        __XFS_DFRAG_H__
-
-/*
- * Structure passed to xfs_swapext
- */
-
-typedef struct xfs_swapext
-{
-       __int64_t       sx_version;     /* version */
-       __int64_t       sx_fdtarget;    /* fd of target file */
-       __int64_t       sx_fdtmp;       /* fd of tmp file */
-       xfs_off_t       sx_offset;      /* offset into file */
-       xfs_off_t       sx_length;      /* leng from offset */
-       char            sx_pad[16];     /* pad space, unused */
-       xfs_bstat_t     sx_stat;        /* stat of target b4 copy */
-} xfs_swapext_t;
-
-/*
- * Version flag
- */
-#define XFS_SX_VERSION         0
-
-#ifdef __KERNEL__
-/*
- * Prototypes for visible xfs_dfrag.c routines.
- */
-
-/*
- * Syscall interface for xfs_swapext
- */
-int    xfs_swapext(struct xfs_swapext *sx);
-
-#endif /* __KERNEL__ */
-
-#endif /* __XFS_DFRAG_H__ */
index 8f023dee404da0da9c2092ba15d5ad904588d5e4..edf203ab50afa734a74faaace8e626721e7fc1bb 100644 (file)
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
-#include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
-#include "xfs_vnodeops.h"
 #include "xfs_trace.h"
 
-struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2};
+struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
+
 
 /*
  * ASCII case-insensitive (ie. A-Z) support for directories that was
@@ -90,6 +90,9 @@ void
 xfs_dir_mount(
        xfs_mount_t     *mp)
 {
+       int     nodehdr_size;
+
+
        ASSERT(xfs_sb_version_hasdirv2(&mp->m_sb));
        ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <=
               XFS_MAX_BLOCKSIZE);
@@ -98,12 +101,13 @@ xfs_dir_mount(
        mp->m_dirdatablk = xfs_dir2_db_to_da(mp, XFS_DIR2_DATA_FIRSTDB(mp));
        mp->m_dirleafblk = xfs_dir2_db_to_da(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
        mp->m_dirfreeblk = xfs_dir2_db_to_da(mp, XFS_DIR2_FREE_FIRSTDB(mp));
-       mp->m_attr_node_ents =
-               (mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
-               (uint)sizeof(xfs_da_node_entry_t);
-       mp->m_dir_node_ents =
-               (mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
-               (uint)sizeof(xfs_da_node_entry_t);
+
+       nodehdr_size = __xfs_da3_node_hdr_size(xfs_sb_version_hascrc(&mp->m_sb));
+       mp->m_attr_node_ents = (mp->m_sb.sb_blocksize - nodehdr_size) /
+                               (uint)sizeof(xfs_da_node_entry_t);
+       mp->m_dir_node_ents = (mp->m_dirblksize - nodehdr_size) /
+                               (uint)sizeof(xfs_da_node_entry_t);
+
        mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
        if (xfs_sb_version_hasasciici(&mp->m_sb))
                mp->m_dirnameops = &xfs_ascii_ci_nameops;
@@ -209,6 +213,7 @@ xfs_dir_createname(
        memset(&args, 0, sizeof(xfs_da_args_t));
        args.name = name->name;
        args.namelen = name->len;
+       args.filetype = name->type;
        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.inumber = inum;
        args.dp = dp;
@@ -283,6 +288,7 @@ xfs_dir_lookup(
        memset(&args, 0, sizeof(xfs_da_args_t));
        args.name = name->name;
        args.namelen = name->len;
+       args.filetype = name->type;
        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.dp = dp;
        args.whichfork = XFS_DATA_FORK;
@@ -338,6 +344,7 @@ xfs_dir_removename(
        memset(&args, 0, sizeof(xfs_da_args_t));
        args.name = name->name;
        args.namelen = name->len;
+       args.filetype = name->type;
        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.inumber = ino;
        args.dp = dp;
@@ -362,37 +369,6 @@ xfs_dir_removename(
        return rval;
 }
 
-/*
- * Read a directory.
- */
-int
-xfs_readdir(
-       xfs_inode_t     *dp,
-       struct dir_context *ctx,
-       size_t          bufsize)
-{
-       int             rval;           /* return value */
-       int             v;              /* type-checking value */
-
-       trace_xfs_readdir(dp);
-
-       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
-               return XFS_ERROR(EIO);
-
-       ASSERT(S_ISDIR(dp->i_d.di_mode));
-       XFS_STATS_INC(xs_dir_getdents);
-
-       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
-               rval = xfs_dir2_sf_getdents(dp, ctx);
-       else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
-               ;
-       else if (v)
-               rval = xfs_dir2_block_getdents(dp, ctx);
-       else
-               rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize);
-       return rval;
-}
-
 /*
  * Replace the inode number of a directory entry.
  */
@@ -418,6 +394,7 @@ xfs_dir_replace(
        memset(&args, 0, sizeof(xfs_da_args_t));
        args.name = name->name;
        args.namelen = name->len;
+       args.filetype = name->type;
        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.inumber = inum;
        args.dp = dp;
@@ -465,6 +442,7 @@ xfs_dir_canenter(
        memset(&args, 0, sizeof(xfs_da_args_t));
        args.name = name->name;
        args.namelen = name->len;
+       args.filetype = name->type;
        args.hashval = dp->i_mount->m_dirnameops->hashname(name);
        args.dp = dp;
        args.whichfork = XFS_DATA_FORK;
index e937d9991c1850c5427ecae7419011c8395d09c3..9910401327d45c788586b2e0953309b81c8c7c6d 100644 (file)
@@ -23,6 +23,11 @@ struct xfs_da_args;
 struct xfs_inode;
 struct xfs_mount;
 struct xfs_trans;
+struct xfs_dir2_sf_hdr;
+struct xfs_dir2_sf_entry;
+struct xfs_dir2_data_hdr;
+struct xfs_dir2_data_entry;
+struct xfs_dir2_data_unused;
 
 extern struct xfs_name xfs_name_dotdot;
 
@@ -57,4 +62,45 @@ extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
  */
 extern int xfs_dir2_sf_to_block(struct xfs_da_args *args);
 
+/*
+ * Interface routines used by userspace utilities
+ */
+extern xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *sfp);
+extern void xfs_dir2_sf_put_parent_ino(struct xfs_dir2_sf_hdr *sfp,
+               xfs_ino_t ino);
+extern xfs_ino_t xfs_dir3_sfe_get_ino(struct xfs_mount *mp,
+               struct xfs_dir2_sf_hdr *sfp, struct xfs_dir2_sf_entry *sfep);
+extern void xfs_dir3_sfe_put_ino(struct xfs_mount *mp,
+               struct xfs_dir2_sf_hdr *hdr, struct xfs_dir2_sf_entry *sfep,
+               xfs_ino_t ino);
+
+extern int xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
+extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
+extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
+                               struct xfs_buf *bp);
+
+extern void xfs_dir2_data_freescan(struct xfs_mount *mp,
+               struct xfs_dir2_data_hdr *hdr, int *loghead);
+extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp,
+               struct xfs_dir2_data_entry *dep);
+extern void xfs_dir2_data_log_header(struct xfs_trans *tp,
+               struct xfs_buf *bp);
+extern void xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_buf *bp,
+               struct xfs_dir2_data_unused *dup);
+extern void xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_buf *bp,
+               xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
+               int *needlogp, int *needscanp);
+extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp,
+               struct xfs_dir2_data_unused *dup, xfs_dir2_data_aoff_t offset,
+               xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
+
+extern struct xfs_dir2_data_free *xfs_dir2_data_freefind(
+               struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_unused *dup);
+
+extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
+extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
+extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;
+extern const struct xfs_buf_ops xfs_dir3_free_buf_ops;
+extern const struct xfs_buf_ops xfs_dir3_data_buf_ops;
+
 #endif /* __XFS_DIR2_H__ */
index 5e7fbd72cf5255c53a8494a991986c339ea5293a..0957aa98b6c0d6bb1fdc3fa23161d761aeb58567 100644 (file)
@@ -31,8 +31,8 @@
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
 #include "xfs_buf_item.h"
-#include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
@@ -126,7 +126,7 @@ const struct xfs_buf_ops xfs_dir3_block_buf_ops = {
        .verify_write = xfs_dir3_block_write_verify,
 };
 
-static int
+int
 xfs_dir3_block_read(
        struct xfs_trans        *tp,
        struct xfs_inode        *dp,
@@ -369,7 +369,7 @@ xfs_dir2_block_addname(
        if (error)
                return error;
 
-       len = xfs_dir2_data_entsize(args->namelen);
+       len = xfs_dir3_data_entsize(mp, args->namelen);
 
        /*
         * Set up pointers to parts of the block.
@@ -549,7 +549,8 @@ xfs_dir2_block_addname(
        dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, args->namelen);
-       tagp = xfs_dir2_data_entry_tag_p(dep);
+       xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
+       tagp = xfs_dir3_data_entry_tag_p(mp, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        /*
         * Clean up the bestfree array and log the header, tail, and entry.
@@ -564,101 +565,6 @@ xfs_dir2_block_addname(
        return 0;
 }
 
-/*
- * Readdir for block directories.
- */
-int                                            /* error */
-xfs_dir2_block_getdents(
-       xfs_inode_t             *dp,            /* incore inode */
-       struct dir_context      *ctx)
-{
-       xfs_dir2_data_hdr_t     *hdr;           /* block header */
-       struct xfs_buf          *bp;            /* buffer for block */
-       xfs_dir2_block_tail_t   *btp;           /* block tail */
-       xfs_dir2_data_entry_t   *dep;           /* block data entry */
-       xfs_dir2_data_unused_t  *dup;           /* block unused entry */
-       char                    *endptr;        /* end of the data entries */
-       int                     error;          /* error return value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
-       char                    *ptr;           /* current data entry */
-       int                     wantoff;        /* starting block offset */
-       xfs_off_t               cook;
-
-       mp = dp->i_mount;
-       /*
-        * If the block number in the offset is out of range, we're done.
-        */
-       if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
-               return 0;
-
-       error = xfs_dir3_block_read(NULL, dp, &bp);
-       if (error)
-               return error;
-
-       /*
-        * Extract the byte offset we start at from the seek pointer.
-        * We'll skip entries before this.
-        */
-       wantoff = xfs_dir2_dataptr_to_off(mp, ctx->pos);
-       hdr = bp->b_addr;
-       xfs_dir3_data_check(dp, bp);
-       /*
-        * Set up values for the loop.
-        */
-       btp = xfs_dir2_block_tail_p(mp, hdr);
-       ptr = (char *)xfs_dir3_data_entry_p(hdr);
-       endptr = (char *)xfs_dir2_block_leaf_p(btp);
-
-       /*
-        * Loop over the data portion of the block.
-        * Each object is a real entry (dep) or an unused one (dup).
-        */
-       while (ptr < endptr) {
-               dup = (xfs_dir2_data_unused_t *)ptr;
-               /*
-                * Unused, skip it.
-                */
-               if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-                       ptr += be16_to_cpu(dup->length);
-                       continue;
-               }
-
-               dep = (xfs_dir2_data_entry_t *)ptr;
-
-               /*
-                * Bump pointer for the next iteration.
-                */
-               ptr += xfs_dir2_data_entsize(dep->namelen);
-               /*
-                * The entry is before the desired starting point, skip it.
-                */
-               if ((char *)dep - (char *)hdr < wantoff)
-                       continue;
-
-               cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
-                                           (char *)dep - (char *)hdr);
-
-               ctx->pos = cook & 0x7fffffff;
-               /*
-                * If it didn't fit, set the final offset to here & return.
-                */
-               if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
-                           be64_to_cpu(dep->inumber), DT_UNKNOWN)) {
-                       xfs_trans_brelse(NULL, bp);
-                       return 0;
-               }
-       }
-
-       /*
-        * Reached the end of the block.
-        * Set the offset to a non-existent block 1 and return.
-        */
-       ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
-                       0x7fffffff;
-       xfs_trans_brelse(NULL, bp);
-       return 0;
-}
-
 /*
  * Log leaf entries from the block.
  */
@@ -736,6 +642,7 @@ xfs_dir2_block_lookup(
         * Fill in inode number, CI name if appropriate, release the block.
         */
        args->inumber = be64_to_cpu(dep->inumber);
+       args->filetype = xfs_dir3_dirent_get_ftype(mp, dep);
        error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
        xfs_trans_brelse(args->trans, bp);
        return XFS_ERROR(error);
@@ -894,7 +801,7 @@ xfs_dir2_block_removename(
        needlog = needscan = 0;
        xfs_dir2_data_make_free(tp, bp,
                (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
-               xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
+               xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
        /*
         * Fix up the block tail.
         */
@@ -968,6 +875,7 @@ xfs_dir2_block_replace(
         * Change the inode number to the new value.
         */
        dep->inumber = cpu_to_be64(args->inumber);
+       xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
        xfs_dir2_data_log_entry(args->trans, bp, dep);
        xfs_dir3_data_check(dp, bp);
        return 0;
@@ -1254,7 +1162,8 @@ xfs_dir2_sf_to_block(
        dep->inumber = cpu_to_be64(dp->i_ino);
        dep->namelen = 1;
        dep->name[0] = '.';
-       tagp = xfs_dir2_data_entry_tag_p(dep);
+       xfs_dir3_dirent_put_ftype(mp, dep, XFS_DIR3_FT_DIR);
+       tagp = xfs_dir3_data_entry_tag_p(mp, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        xfs_dir2_data_log_entry(tp, bp, dep);
        blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);
@@ -1267,7 +1176,8 @@ xfs_dir2_sf_to_block(
        dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
        dep->namelen = 2;
        dep->name[0] = dep->name[1] = '.';
-       tagp = xfs_dir2_data_entry_tag_p(dep);
+       xfs_dir3_dirent_put_ftype(mp, dep, XFS_DIR3_FT_DIR);
+       tagp = xfs_dir3_data_entry_tag_p(mp, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        xfs_dir2_data_log_entry(tp, bp, dep);
        blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
@@ -1312,10 +1222,12 @@ xfs_dir2_sf_to_block(
                 * Copy a real entry.
                 */
                dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset);
-               dep->inumber = cpu_to_be64(xfs_dir2_sfe_get_ino(sfp, sfep));
+               dep->inumber = cpu_to_be64(xfs_dir3_sfe_get_ino(mp, sfp, sfep));
                dep->namelen = sfep->namelen;
+               xfs_dir3_dirent_put_ftype(mp, dep,
+                                       xfs_dir3_sfe_get_ftype(mp, sfp, sfep));
                memcpy(dep->name, sfep->name, dep->namelen);
-               tagp = xfs_dir2_data_entry_tag_p(dep);
+               tagp = xfs_dir3_data_entry_tag_p(mp, dep);
                *tagp = cpu_to_be16((char *)dep - (char *)hdr);
                xfs_dir2_data_log_entry(tp, bp, dep);
                name.name = sfep->name;
@@ -1328,7 +1240,7 @@ xfs_dir2_sf_to_block(
                if (++i == sfp->count)
                        sfep = NULL;
                else
-                       sfep = xfs_dir2_sf_nextentry(sfp, sfep);
+                       sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
        }
        /* Done with the temporary buffer */
        kmem_free(sfp);
index c2930238005c6605c1e69e4dc455b9ed7267f3da..47e1326c169a08c71d8d21ac51e8d113444d3295 100644 (file)
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_buf_item.h"
 #include "xfs_cksum.h"
 
-STATIC xfs_dir2_data_free_t *
-xfs_dir2_data_freefind(xfs_dir2_data_hdr_t *hdr, xfs_dir2_data_unused_t *dup);
-
 /*
  * Check the consistency of the data block.
  * The input can also be a block-format directory.
@@ -149,8 +147,10 @@ __xfs_dir3_data_check(
                XFS_WANT_CORRUPTED_RETURN(
                        !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber)));
                XFS_WANT_CORRUPTED_RETURN(
-                       be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)) ==
+                       be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)) ==
                                               (char *)dep - (char *)hdr);
+               XFS_WANT_CORRUPTED_RETURN(
+                       xfs_dir3_dirent_get_ftype(mp, dep) < XFS_DIR3_FT_MAX);
                count++;
                lastfree = 0;
                if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) ||
@@ -168,7 +168,7 @@ __xfs_dir3_data_check(
                        }
                        XFS_WANT_CORRUPTED_RETURN(i < be32_to_cpu(btp->count));
                }
-               p += xfs_dir2_data_entsize(dep->namelen);
+               p += xfs_dir3_data_entsize(mp, dep->namelen);
        }
        /*
         * Need to have seen all the entries and all the bestfree slots.
@@ -325,7 +325,7 @@ xfs_dir3_data_readahead(
  * Given a data block and an unused entry from that block,
  * return the bestfree entry if any that corresponds to it.
  */
-STATIC xfs_dir2_data_free_t *
+xfs_dir2_data_free_t *
 xfs_dir2_data_freefind(
        xfs_dir2_data_hdr_t     *hdr,           /* data block */
        xfs_dir2_data_unused_t  *dup)           /* data unused entry */
@@ -333,7 +333,7 @@ xfs_dir2_data_freefind(
        xfs_dir2_data_free_t    *dfp;           /* bestfree entry */
        xfs_dir2_data_aoff_t    off;            /* offset value needed */
        struct xfs_dir2_data_free *bf;
-#if defined(DEBUG) && defined(__KERNEL__)
+#ifdef DEBUG
        int                     matched;        /* matched the value */
        int                     seenzero;       /* saw a 0 bestfree entry */
 #endif
@@ -341,7 +341,7 @@ xfs_dir2_data_freefind(
        off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr);
        bf = xfs_dir3_data_bestfree_p(hdr);
 
-#if defined(DEBUG) && defined(__KERNEL__)
+#ifdef DEBUG
        /*
         * Validate some consistency in the bestfree table.
         * Check order, non-overlapping entries, and if we find the
@@ -538,8 +538,8 @@ xfs_dir2_data_freescan(
                else {
                        dep = (xfs_dir2_data_entry_t *)p;
                        ASSERT((char *)dep - (char *)hdr ==
-                              be16_to_cpu(*xfs_dir2_data_entry_tag_p(dep)));
-                       p += xfs_dir2_data_entsize(dep->namelen);
+                              be16_to_cpu(*xfs_dir3_data_entry_tag_p(mp, dep)));
+                       p += xfs_dir3_data_entsize(mp, dep->namelen);
                }
        }
 }
@@ -629,7 +629,8 @@ xfs_dir2_data_log_entry(
        struct xfs_buf          *bp,
        xfs_dir2_data_entry_t   *dep)           /* data entry pointer */
 {
-       xfs_dir2_data_hdr_t     *hdr = bp->b_addr;
+       struct xfs_dir2_data_hdr *hdr = bp->b_addr;
+       struct xfs_mount        *mp = tp->t_mountp;
 
        ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) ||
               hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
@@ -637,7 +638,7 @@ xfs_dir2_data_log_entry(
               hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC));
 
        xfs_trans_log_buf(tp, bp, (uint)((char *)dep - (char *)hdr),
-               (uint)((char *)(xfs_dir2_data_entry_tag_p(dep) + 1) -
+               (uint)((char *)(xfs_dir3_data_entry_tag_p(mp, dep) + 1) -
                       (char *)hdr - 1));
 }
 
index 7826782b8d789461eef5a5443ae1d29944887815..a0961a61ac1a9a419fd537cd47dbb7337fbbc3a0 100644 (file)
 #define        XFS_DIR3_DATA_MAGIC     0x58444433      /* XDD3: multiblock dirs */
 #define        XFS_DIR3_FREE_MAGIC     0x58444633      /* XDF3: free index blocks */
 
+/*
+ * Dirents in version 3 directories have a file type field. Additions to this
+ * list are an on-disk format change, requiring feature bits. Valid values
+ * are as follows:
+ */
+#define XFS_DIR3_FT_UNKNOWN            0
+#define XFS_DIR3_FT_REG_FILE           1
+#define XFS_DIR3_FT_DIR                        2
+#define XFS_DIR3_FT_CHRDEV             3
+#define XFS_DIR3_FT_BLKDEV             4
+#define XFS_DIR3_FT_FIFO               5
+#define XFS_DIR3_FT_SOCK               6
+#define XFS_DIR3_FT_SYMLINK            7
+#define XFS_DIR3_FT_WHT                        8
+
+#define XFS_DIR3_FT_MAX                        9
+
 /*
  * Byte offset in data block and shortform entry.
  */
@@ -138,6 +155,9 @@ typedef struct xfs_dir2_sf_entry {
        xfs_dir2_sf_off_t       offset;         /* saved offset */
        __u8                    name[];         /* name, variable size */
        /*
+        * A single byte containing the file type field follows the inode
+        * number for version 3 directory entries.
+        *
         * A xfs_dir2_ino8_t or xfs_dir2_ino4_t follows here, at a
         * variable offset after the name.
         */
@@ -162,16 +182,6 @@ xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off)
        put_unaligned_be16(off, &sfep->offset.i);
 }
 
-static inline int
-xfs_dir2_sf_entsize(struct xfs_dir2_sf_hdr *hdr, int len)
-{
-       return sizeof(struct xfs_dir2_sf_entry) +       /* namelen + offset */
-               len +                                   /* name */
-               (hdr->i8count ?                         /* ino */
-                sizeof(xfs_dir2_ino8_t) :
-                sizeof(xfs_dir2_ino4_t));
-}
-
 static inline struct xfs_dir2_sf_entry *
 xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr)
 {
@@ -179,14 +189,78 @@ xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr)
                ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count));
 }
 
+static inline int
+xfs_dir3_sf_entsize(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_hdr  *hdr,
+       int                     len)
+{
+       int count = sizeof(struct xfs_dir2_sf_entry);   /* namelen + offset */
+
+       count += len;                                   /* name */
+       count += hdr->i8count ? sizeof(xfs_dir2_ino8_t) :
+                               sizeof(xfs_dir2_ino4_t); /* ino # */
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               count += sizeof(__uint8_t);             /* file type */
+       return count;
+}
+
 static inline struct xfs_dir2_sf_entry *
-xfs_dir2_sf_nextentry(struct xfs_dir2_sf_hdr *hdr,
-               struct xfs_dir2_sf_entry *sfep)
+xfs_dir3_sf_nextentry(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_hdr  *hdr,
+       struct xfs_dir2_sf_entry *sfep)
 {
        return (struct xfs_dir2_sf_entry *)
-               ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen));
+               ((char *)sfep + xfs_dir3_sf_entsize(mp, hdr, sfep->namelen));
 }
 
+/*
+ * in dir3 shortform directories, the file type field is stored at a variable
+ * offset after the inode number. Because it's only a single byte, endian
+ * conversion is not necessary.
+ */
+static inline __uint8_t *
+xfs_dir3_sfe_ftypep(
+       struct xfs_dir2_sf_hdr  *hdr,
+       struct xfs_dir2_sf_entry *sfep)
+{
+       return (__uint8_t *)&sfep->name[sfep->namelen];
+}
+
+static inline __uint8_t
+xfs_dir3_sfe_get_ftype(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_hdr  *hdr,
+       struct xfs_dir2_sf_entry *sfep)
+{
+       __uint8_t       *ftp;
+
+       if (!xfs_sb_version_hasftype(&mp->m_sb))
+               return XFS_DIR3_FT_UNKNOWN;
+
+       ftp = xfs_dir3_sfe_ftypep(hdr, sfep);
+       if (*ftp >= XFS_DIR3_FT_MAX)
+               return XFS_DIR3_FT_UNKNOWN;
+       return *ftp;
+}
+
+static inline void
+xfs_dir3_sfe_put_ftype(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_sf_hdr  *hdr,
+       struct xfs_dir2_sf_entry *sfep,
+       __uint8_t               ftype)
+{
+       __uint8_t       *ftp;
+
+       ASSERT(ftype < XFS_DIR3_FT_MAX);
+
+       if (!xfs_sb_version_hasftype(&mp->m_sb))
+               return;
+       ftp = xfs_dir3_sfe_ftypep(hdr, sfep);
+       *ftp = ftype;
+}
 
 /*
  * Data block structures.
@@ -286,12 +360,18 @@ xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr)
  * Active entry in a data block.
  *
  * Aligned to 8 bytes.  After the variable length name field there is a
- * 2 byte tag field, which can be accessed using xfs_dir2_data_entry_tag_p.
+ * 2 byte tag field, which can be accessed using xfs_dir3_data_entry_tag_p.
+ *
+ * For dir3 structures, there is file type field between the name and the tag.
+ * This can only be manipulated by helper functions. It is packed hard against
+ * the end of the name so any padding for rounding is between the file type and
+ * the tag.
  */
 typedef struct xfs_dir2_data_entry {
        __be64                  inumber;        /* inode number */
        __u8                    namelen;        /* name length */
        __u8                    name[];         /* name bytes, no null */
+     /* __u8                   filetype; */    /* type of inode we point to */
      /*        __be16                  tag; */         /* starting offset of us */
 } xfs_dir2_data_entry_t;
 
@@ -311,20 +391,67 @@ typedef struct xfs_dir2_data_unused {
 /*
  * Size of a data entry.
  */
-static inline int xfs_dir2_data_entsize(int n)
+static inline int
+__xfs_dir3_data_entsize(
+       bool    ftype,
+       int     n)
 {
-       return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
-                (uint)sizeof(xfs_dir2_data_off_t), XFS_DIR2_DATA_ALIGN);
+       int     size = offsetof(struct xfs_dir2_data_entry, name[0]);
+
+       size += n;
+       size += sizeof(xfs_dir2_data_off_t);
+       if (ftype)
+               size += sizeof(__uint8_t);
+       return roundup(size, XFS_DIR2_DATA_ALIGN);
+}
+static inline int
+xfs_dir3_data_entsize(
+       struct xfs_mount        *mp,
+       int                     n)
+{
+       bool ftype = xfs_sb_version_hasftype(&mp->m_sb) ? true : false;
+       return __xfs_dir3_data_entsize(ftype, n);
+}
+
+static inline __uint8_t
+xfs_dir3_dirent_get_ftype(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_entry *dep)
+{
+       if (xfs_sb_version_hasftype(&mp->m_sb)) {
+               __uint8_t       type = dep->name[dep->namelen];
+
+               ASSERT(type < XFS_DIR3_FT_MAX);
+               if (type < XFS_DIR3_FT_MAX)
+                       return type;
+
+       }
+       return XFS_DIR3_FT_UNKNOWN;
+}
+
+static inline void
+xfs_dir3_dirent_put_ftype(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_entry *dep,
+       __uint8_t               type)
+{
+       ASSERT(type < XFS_DIR3_FT_MAX);
+       ASSERT(dep->namelen != 0);
+
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               dep->name[dep->namelen] = type;
 }
 
 /*
  * Pointer to an entry's tag word.
  */
 static inline __be16 *
-xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
+xfs_dir3_data_entry_tag_p(
+       struct xfs_mount        *mp,
+       struct xfs_dir2_data_entry *dep)
 {
        return (__be16 *)((char *)dep +
-               xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16));
+               xfs_dir3_data_entsize(mp, dep->namelen) - sizeof(__be16));
 }
 
 /*
@@ -375,13 +502,17 @@ xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr)
  * data block header because the sfe embeds the block offset of the entry into
  * it so that it doesn't change when format conversion occurs. Bad Things Happen
  * if we don't follow this rule.
+ *
+ * XXX: there is scope for significant optimisation of the logic here. Right
+ * now we are checking for "dir3 format" over and over again. Ideally we should
+ * only do it once for each operation.
  */
 #define        XFS_DIR3_DATA_DOT_OFFSET(mp)    \
        xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&(mp)->m_sb))
 #define        XFS_DIR3_DATA_DOTDOT_OFFSET(mp) \
-       (XFS_DIR3_DATA_DOT_OFFSET(mp) + xfs_dir2_data_entsize(1))
+       (XFS_DIR3_DATA_DOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 1))
 #define        XFS_DIR3_DATA_FIRST_OFFSET(mp)          \
-       (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir2_data_entsize(2))
+       (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 2))
 
 static inline xfs_dir2_data_aoff_t
 xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr)
@@ -392,13 +523,19 @@ xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr)
 static inline xfs_dir2_data_aoff_t
 xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr)
 {
-       return xfs_dir3_data_dot_offset(hdr) + xfs_dir2_data_entsize(1);
+       bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
+                   hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
+       return xfs_dir3_data_dot_offset(hdr) +
+               __xfs_dir3_data_entsize(dir3, 1);
 }
 
 static inline xfs_dir2_data_aoff_t
 xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr)
 {
-       return xfs_dir3_data_dotdot_offset(hdr) + xfs_dir2_data_entsize(2);
+       bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
+                   hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
+       return xfs_dir3_data_dotdot_offset(hdr) +
+               __xfs_dir3_data_entsize(dir3, 2);
 }
 
 /*
@@ -519,6 +656,9 @@ struct xfs_dir3_leaf {
 
 #define XFS_DIR3_LEAF_CRC_OFF  offsetof(struct xfs_dir3_leaf_hdr, info.crc)
 
+extern void xfs_dir3_leaf_hdr_from_disk(struct xfs_dir3_icleaf_hdr *to,
+                                       struct xfs_dir2_leaf *from);
+
 static inline int
 xfs_dir3_leaf_hdr_size(struct xfs_dir2_leaf *lp)
 {
index 2aed25cae04d9f265df00aba8e5d63a624350a0f..1021c8356d0836318e300adefc4a35f170d120c3 100644 (file)
@@ -31,6 +31,7 @@
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
@@ -179,6 +180,11 @@ xfs_dir3_leaf_check_int(
        return true;
 }
 
+/*
+ * We verify the magic numbers before decoding the leaf header so that on debug
+ * kernels we don't get assertion failures in xfs_dir3_leaf_hdr_from_disk() due
+ * to incorrect magic numbers.
+ */
 static bool
 xfs_dir3_leaf_verify(
        struct xfs_buf          *bp,
@@ -190,24 +196,25 @@ xfs_dir3_leaf_verify(
 
        ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC);
 
-       xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
                struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr;
+               __uint16_t              magic3;
 
-               if ((magic == XFS_DIR2_LEAF1_MAGIC &&
-                    leafhdr.magic != XFS_DIR3_LEAF1_MAGIC) ||
-                   (magic == XFS_DIR2_LEAFN_MAGIC &&
-                    leafhdr.magic != XFS_DIR3_LEAFN_MAGIC))
-                       return false;
+               magic3 = (magic == XFS_DIR2_LEAF1_MAGIC) ? XFS_DIR3_LEAF1_MAGIC
+                                                        : XFS_DIR3_LEAFN_MAGIC;
 
+               if (leaf3->info.hdr.magic != cpu_to_be16(magic3))
+                       return false;
                if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_uuid))
                        return false;
                if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
                        return false;
        } else {
-               if (leafhdr.magic != magic)
+               if (leaf->hdr.info.magic != cpu_to_be16(magic))
                        return false;
        }
+
+       xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
        return xfs_dir3_leaf_check_int(mp, &leafhdr, leaf);
 }
 
@@ -695,7 +702,7 @@ xfs_dir2_leaf_addname(
        ents = xfs_dir3_leaf_ents_p(leaf);
        xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
        bestsp = xfs_dir2_leaf_bests_p(ltp);
-       length = xfs_dir2_data_entsize(args->namelen);
+       length = xfs_dir3_data_entsize(mp, args->namelen);
 
        /*
         * See if there are any entries with the same hash value
@@ -896,7 +903,8 @@ xfs_dir2_leaf_addname(
        dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, dep->namelen);
-       tagp = xfs_dir2_data_entry_tag_p(dep);
+       xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
+       tagp = xfs_dir3_data_entry_tag_p(mp, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        /*
         * Need to scan fix up the bestfree table.
@@ -1083,396 +1091,6 @@ xfs_dir3_leaf_compact_x1(
        *highstalep = highstale;
 }
 
-struct xfs_dir2_leaf_map_info {
-       xfs_extlen_t    map_blocks;     /* number of fsbs in map */
-       xfs_dablk_t     map_off;        /* last mapped file offset */
-       int             map_size;       /* total entries in *map */
-       int             map_valid;      /* valid entries in *map */
-       int             nmap;           /* mappings to ask xfs_bmapi */
-       xfs_dir2_db_t   curdb;          /* db for current block */
-       int             ra_current;     /* number of read-ahead blks */
-       int             ra_index;       /* *map index for read-ahead */
-       int             ra_offset;      /* map entry offset for ra */
-       int             ra_want;        /* readahead count wanted */
-       struct xfs_bmbt_irec map[];     /* map vector for blocks */
-};
-
-STATIC int
-xfs_dir2_leaf_readbuf(
-       struct xfs_inode        *dp,
-       size_t                  bufsize,
-       struct xfs_dir2_leaf_map_info *mip,
-       xfs_dir2_off_t          *curoff,
-       struct xfs_buf          **bpp)
-{
-       struct xfs_mount        *mp = dp->i_mount;
-       struct xfs_buf          *bp = *bpp;
-       struct xfs_bmbt_irec    *map = mip->map;
-       struct blk_plug         plug;
-       int                     error = 0;
-       int                     length;
-       int                     i;
-       int                     j;
-
-       /*
-        * If we have a buffer, we need to release it and
-        * take it out of the mapping.
-        */
-
-       if (bp) {
-               xfs_trans_brelse(NULL, bp);
-               bp = NULL;
-               mip->map_blocks -= mp->m_dirblkfsbs;
-               /*
-                * Loop to get rid of the extents for the
-                * directory block.
-                */
-               for (i = mp->m_dirblkfsbs; i > 0; ) {
-                       j = min_t(int, map->br_blockcount, i);
-                       map->br_blockcount -= j;
-                       map->br_startblock += j;
-                       map->br_startoff += j;
-                       /*
-                        * If mapping is done, pitch it from
-                        * the table.
-                        */
-                       if (!map->br_blockcount && --mip->map_valid)
-                               memmove(&map[0], &map[1],
-                                       sizeof(map[0]) * mip->map_valid);
-                       i -= j;
-               }
-       }
-
-       /*
-        * Recalculate the readahead blocks wanted.
-        */
-       mip->ra_want = howmany(bufsize + mp->m_dirblksize,
-                              mp->m_sb.sb_blocksize) - 1;
-       ASSERT(mip->ra_want >= 0);
-
-       /*
-        * If we don't have as many as we want, and we haven't
-        * run out of data blocks, get some more mappings.
-        */
-       if (1 + mip->ra_want > mip->map_blocks &&
-           mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
-               /*
-                * Get more bmaps, fill in after the ones
-                * we already have in the table.
-                */
-               mip->nmap = mip->map_size - mip->map_valid;
-               error = xfs_bmapi_read(dp, mip->map_off,
-                               xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
-                                                               mip->map_off,
-                               &map[mip->map_valid], &mip->nmap, 0);
-
-               /*
-                * Don't know if we should ignore this or try to return an
-                * error.  The trouble with returning errors is that readdir
-                * will just stop without actually passing the error through.
-                */
-               if (error)
-                       goto out;       /* XXX */
-
-               /*
-                * If we got all the mappings we asked for, set the final map
-                * offset based on the last bmap value received.  Otherwise,
-                * we've reached the end.
-                */
-               if (mip->nmap == mip->map_size - mip->map_valid) {
-                       i = mip->map_valid + mip->nmap - 1;
-                       mip->map_off = map[i].br_startoff + map[i].br_blockcount;
-               } else
-                       mip->map_off = xfs_dir2_byte_to_da(mp,
-                                                       XFS_DIR2_LEAF_OFFSET);
-
-               /*
-                * Look for holes in the mapping, and eliminate them.  Count up
-                * the valid blocks.
-                */
-               for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) {
-                       if (map[i].br_startblock == HOLESTARTBLOCK) {
-                               mip->nmap--;
-                               length = mip->map_valid + mip->nmap - i;
-                               if (length)
-                                       memmove(&map[i], &map[i + 1],
-                                               sizeof(map[i]) * length);
-                       } else {
-                               mip->map_blocks += map[i].br_blockcount;
-                               i++;
-                       }
-               }
-               mip->map_valid += mip->nmap;
-       }
-
-       /*
-        * No valid mappings, so no more data blocks.
-        */
-       if (!mip->map_valid) {
-               *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
-               goto out;
-       }
-
-       /*
-        * Read the directory block starting at the first mapping.
-        */
-       mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
-       error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
-                       map->br_blockcount >= mp->m_dirblkfsbs ?
-                           XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
-
-       /*
-        * Should just skip over the data block instead of giving up.
-        */
-       if (error)
-               goto out;       /* XXX */
-
-       /*
-        * Adjust the current amount of read-ahead: we just read a block that
-        * was previously ra.
-        */
-       if (mip->ra_current)
-               mip->ra_current -= mp->m_dirblkfsbs;
-
-       /*
-        * Do we need more readahead?
-        */
-       blk_start_plug(&plug);
-       for (mip->ra_index = mip->ra_offset = i = 0;
-            mip->ra_want > mip->ra_current && i < mip->map_blocks;
-            i += mp->m_dirblkfsbs) {
-               ASSERT(mip->ra_index < mip->map_valid);
-               /*
-                * Read-ahead a contiguous directory block.
-                */
-               if (i > mip->ra_current &&
-                   map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
-                       xfs_dir3_data_readahead(NULL, dp,
-                               map[mip->ra_index].br_startoff + mip->ra_offset,
-                               XFS_FSB_TO_DADDR(mp,
-                                       map[mip->ra_index].br_startblock +
-                                                       mip->ra_offset));
-                       mip->ra_current = i;
-               }
-
-               /*
-                * Read-ahead a non-contiguous directory block.  This doesn't
-                * use our mapping, but this is a very rare case.
-                */
-               else if (i > mip->ra_current) {
-                       xfs_dir3_data_readahead(NULL, dp,
-                                       map[mip->ra_index].br_startoff +
-                                                       mip->ra_offset, -1);
-                       mip->ra_current = i;
-               }
-
-               /*
-                * Advance offset through the mapping table.
-                */
-               for (j = 0; j < mp->m_dirblkfsbs; j++) {
-                       /*
-                        * The rest of this extent but not more than a dir
-                        * block.
-                        */
-                       length = min_t(int, mp->m_dirblkfsbs,
-                                       map[mip->ra_index].br_blockcount -
-                                                       mip->ra_offset);
-                       j += length;
-                       mip->ra_offset += length;
-
-                       /*
-                        * Advance to the next mapping if this one is used up.
-                        */
-                       if (mip->ra_offset == map[mip->ra_index].br_blockcount) {
-                               mip->ra_offset = 0;
-                               mip->ra_index++;
-                       }
-               }
-       }
-       blk_finish_plug(&plug);
-
-out:
-       *bpp = bp;
-       return error;
-}
-
-/*
- * Getdents (readdir) for leaf and node directories.
- * This reads the data blocks only, so is the same for both forms.
- */
-int                                            /* error */
-xfs_dir2_leaf_getdents(
-       xfs_inode_t             *dp,            /* incore directory inode */
-       struct dir_context      *ctx,
-       size_t                  bufsize)
-{
-       struct xfs_buf          *bp = NULL;     /* data block buffer */
-       xfs_dir2_data_hdr_t     *hdr;           /* data block header */
-       xfs_dir2_data_entry_t   *dep;           /* data entry */
-       xfs_dir2_data_unused_t  *dup;           /* unused entry */
-       int                     error = 0;      /* error return value */
-       int                     length;         /* temporary length value */
-       xfs_mount_t             *mp;            /* filesystem mount point */
-       int                     byteoff;        /* offset in current block */
-       xfs_dir2_off_t          curoff;         /* current overall offset */
-       xfs_dir2_off_t          newoff;         /* new curoff after new blk */
-       char                    *ptr = NULL;    /* pointer to current data */
-       struct xfs_dir2_leaf_map_info *map_info;
-
-       /*
-        * If the offset is at or past the largest allowed value,
-        * give up right away.
-        */
-       if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
-               return 0;
-
-       mp = dp->i_mount;
-
-       /*
-        * Set up to bmap a number of blocks based on the caller's
-        * buffer size, the directory block size, and the filesystem
-        * block size.
-        */
-       length = howmany(bufsize + mp->m_dirblksize,
-                                    mp->m_sb.sb_blocksize);
-       map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
-                               (length * sizeof(struct xfs_bmbt_irec)),
-                              KM_SLEEP | KM_NOFS);
-       map_info->map_size = length;
-
-       /*
-        * Inside the loop we keep the main offset value as a byte offset
-        * in the directory file.
-        */
-       curoff = xfs_dir2_dataptr_to_byte(mp, ctx->pos);
-
-       /*
-        * Force this conversion through db so we truncate the offset
-        * down to get the start of the data block.
-        */
-       map_info->map_off = xfs_dir2_db_to_da(mp,
-                                             xfs_dir2_byte_to_db(mp, curoff));
-
-       /*
-        * Loop over directory entries until we reach the end offset.
-        * Get more blocks and readahead as necessary.
-        */
-       while (curoff < XFS_DIR2_LEAF_OFFSET) {
-               /*
-                * If we have no buffer, or we're off the end of the
-                * current buffer, need to get another one.
-                */
-               if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
-
-                       error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
-                                                     &curoff, &bp);
-                       if (error || !map_info->map_valid)
-                               break;
-
-                       /*
-                        * Having done a read, we need to set a new offset.
-                        */
-                       newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
-                       /*
-                        * Start of the current block.
-                        */
-                       if (curoff < newoff)
-                               curoff = newoff;
-                       /*
-                        * Make sure we're in the right block.
-                        */
-                       else if (curoff > newoff)
-                               ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
-                                      map_info->curdb);
-                       hdr = bp->b_addr;
-                       xfs_dir3_data_check(dp, bp);
-                       /*
-                        * Find our position in the block.
-                        */
-                       ptr = (char *)xfs_dir3_data_entry_p(hdr);
-                       byteoff = xfs_dir2_byte_to_off(mp, curoff);
-                       /*
-                        * Skip past the header.
-                        */
-                       if (byteoff == 0)
-                               curoff += xfs_dir3_data_entry_offset(hdr);
-                       /*
-                        * Skip past entries until we reach our offset.
-                        */
-                       else {
-                               while ((char *)ptr - (char *)hdr < byteoff) {
-                                       dup = (xfs_dir2_data_unused_t *)ptr;
-
-                                       if (be16_to_cpu(dup->freetag)
-                                                 == XFS_DIR2_DATA_FREE_TAG) {
-
-                                               length = be16_to_cpu(dup->length);
-                                               ptr += length;
-                                               continue;
-                                       }
-                                       dep = (xfs_dir2_data_entry_t *)ptr;
-                                       length =
-                                          xfs_dir2_data_entsize(dep->namelen);
-                                       ptr += length;
-                               }
-                               /*
-                                * Now set our real offset.
-                                */
-                               curoff =
-                                       xfs_dir2_db_off_to_byte(mp,
-                                           xfs_dir2_byte_to_db(mp, curoff),
-                                           (char *)ptr - (char *)hdr);
-                               if (ptr >= (char *)hdr + mp->m_dirblksize) {
-                                       continue;
-                               }
-                       }
-               }
-               /*
-                * We have a pointer to an entry.
-                * Is it a live one?
-                */
-               dup = (xfs_dir2_data_unused_t *)ptr;
-               /*
-                * No, it's unused, skip over it.
-                */
-               if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
-                       length = be16_to_cpu(dup->length);
-                       ptr += length;
-                       curoff += length;
-                       continue;
-               }
-
-               dep = (xfs_dir2_data_entry_t *)ptr;
-               length = xfs_dir2_data_entsize(dep->namelen);
-
-               ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
-               if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
-                           be64_to_cpu(dep->inumber), DT_UNKNOWN))
-                       break;
-
-               /*
-                * Advance to next entry in the block.
-                */
-               ptr += length;
-               curoff += length;
-               /* bufsize may have just been a guess; don't go negative */
-               bufsize = bufsize > length ? bufsize - length : 0;
-       }
-
-       /*
-        * All done.  Set output offset value to current offset.
-        */
-       if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
-               ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
-       else
-               ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
-       kmem_free(map_info);
-       if (bp)
-               xfs_trans_brelse(NULL, bp);
-       return error;
-}
-
-
 /*
  * Log the bests entries indicated from a leaf1 block.
  */
@@ -1614,6 +1232,7 @@ xfs_dir2_leaf_lookup(
         * Return the found inode number & CI name if appropriate
         */
        args->inumber = be64_to_cpu(dep->inumber);
+       args->filetype = xfs_dir3_dirent_get_ftype(dp->i_mount, dep);
        error = xfs_dir_cilookup_result(args, dep->name, dep->namelen);
        xfs_trans_brelse(tp, dbp);
        xfs_trans_brelse(tp, lbp);
@@ -1816,7 +1435,7 @@ xfs_dir2_leaf_removename(
         */
        xfs_dir2_data_make_free(tp, dbp,
                (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr),
-               xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
+               xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
        /*
         * We just mark the leaf entry stale by putting a null in it.
         */
@@ -1944,6 +1563,7 @@ xfs_dir2_leaf_replace(
         * Put the new inode number in, log it.
         */
        dep->inumber = cpu_to_be64(args->inumber);
+       xfs_dir3_dirent_put_ftype(dp->i_mount, dep, args->filetype);
        tp = args->trans;
        xfs_dir2_data_log_entry(tp, dbp, dep);
        xfs_dir3_leaf_check(dp->i_mount, lbp);
@@ -1975,10 +1595,6 @@ xfs_dir2_leaf_search_hash(
        ents = xfs_dir3_leaf_ents_p(leaf);
        xfs_dir3_leaf_hdr_from_disk(&leafhdr, leaf);
 
-#ifndef __KERNEL__
-       if (!leafhdr.count)
-               return 0;
-#endif
        /*
         * Note, the table cannot be empty, so we have to go through the loop.
         * Binary search the leaf entries looking for our hash value.
index 2226a00acd156118a2998ce37c2c95ae628503d9..4c3dba7ffb7439d250b0af44e4de237a9359a795 100644 (file)
@@ -30,6 +30,7 @@
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_error.h"
 #include "xfs_trace.h"
@@ -312,11 +313,13 @@ xfs_dir2_free_log_header(
        struct xfs_trans        *tp,
        struct xfs_buf          *bp)
 {
+#ifdef DEBUG
        xfs_dir2_free_t         *free;          /* freespace structure */
 
        free = bp->b_addr;
        ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
               free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
+#endif
        xfs_trans_log_buf(tp, bp, 0, xfs_dir3_free_hdr_size(tp->t_mountp) - 1);
 }
 
@@ -602,7 +605,7 @@ xfs_dir2_leafn_lookup_for_addname(
                ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
                       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
        }
-       length = xfs_dir2_data_entsize(args->namelen);
+       length = xfs_dir3_data_entsize(mp, args->namelen);
        /*
         * Loop over leaf entries with the right hash value.
         */
@@ -813,6 +816,7 @@ xfs_dir2_leafn_lookup_for_entry(
                                xfs_trans_brelse(tp, state->extrablk.bp);
                        args->cmpresult = cmp;
                        args->inumber = be64_to_cpu(dep->inumber);
+                       args->filetype = xfs_dir3_dirent_get_ftype(mp, dep);
                        *indexp = index;
                        state->extravalid = 1;
                        state->extrablk.bp = curbp;
@@ -1256,7 +1260,7 @@ xfs_dir2_leafn_remove(
        longest = be16_to_cpu(bf[0].length);
        needlog = needscan = 0;
        xfs_dir2_data_make_free(tp, dbp, off,
-               xfs_dir2_data_entsize(dep->namelen), &needlog, &needscan);
+               xfs_dir3_data_entsize(mp, dep->namelen), &needlog, &needscan);
        /*
         * Rescan the data block freespaces for bestfree.
         * Log the data block header if needed.
@@ -1708,7 +1712,7 @@ xfs_dir2_node_addname_int(
        dp = args->dp;
        mp = dp->i_mount;
        tp = args->trans;
-       length = xfs_dir2_data_entsize(args->namelen);
+       length = xfs_dir3_data_entsize(mp, args->namelen);
        /*
         * If we came in with a freespace block that means that lookup
         * found an entry with our hash value.  This is the freespace
@@ -2004,7 +2008,8 @@ xfs_dir2_node_addname_int(
        dep->inumber = cpu_to_be64(args->inumber);
        dep->namelen = args->namelen;
        memcpy(dep->name, args->name, dep->namelen);
-       tagp = xfs_dir2_data_entry_tag_p(dep);
+       xfs_dir3_dirent_put_ftype(mp, dep, args->filetype);
+       tagp = xfs_dir3_data_entry_tag_p(mp, dep);
        *tagp = cpu_to_be16((char *)dep - (char *)hdr);
        xfs_dir2_data_log_entry(tp, dbp, dep);
        /*
@@ -2224,6 +2229,7 @@ xfs_dir2_node_replace(
                 * Fill in the new inode number and log the entry.
                 */
                dep->inumber = cpu_to_be64(inum);
+               xfs_dir3_dirent_put_ftype(state->mp, dep, args->filetype);
                xfs_dir2_data_log_entry(args->trans, state->extrablk.bp, dep);
                rval = 0;
        }
index 0511cda4a712a480682b946829c5587cf37c4070..1bad84c408295ae4db2de71d96c74b18fff5b2b2 100644 (file)
 #ifndef __XFS_DIR2_PRIV_H__
 #define __XFS_DIR2_PRIV_H__
 
+struct dir_context;
+
 /* xfs_dir2.c */
 extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino);
-extern int xfs_dir2_isblock(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
-extern int xfs_dir2_isleaf(struct xfs_trans *tp, struct xfs_inode *dp, int *r);
 extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space,
                                xfs_dir2_db_t *dbp);
-extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db,
-                               struct xfs_buf *bp);
 extern int xfs_dir_cilookup_result(struct xfs_da_args *args,
                                const unsigned char *name, int len);
 
-/* xfs_dir2_block.c */
-extern const struct xfs_buf_ops xfs_dir3_block_buf_ops;
+#define S_SHIFT 12
+extern const unsigned char xfs_mode_to_ftype[];
+
+extern unsigned char xfs_dir3_get_dtype(struct xfs_mount *mp,
+                                       __uint8_t filetype);
 
+
+/* xfs_dir2_block.c */
+extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp,
+                              struct xfs_buf **bpp);
 extern int xfs_dir2_block_addname(struct xfs_da_args *args);
-extern int xfs_dir2_block_getdents(struct xfs_inode *dp,
-               struct dir_context *ctx);
 extern int xfs_dir2_block_lookup(struct xfs_da_args *args);
 extern int xfs_dir2_block_removename(struct xfs_da_args *args);
 extern int xfs_dir2_block_replace(struct xfs_da_args *args);
@@ -48,9 +51,6 @@ extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args,
 #define        xfs_dir3_data_check(dp,bp)
 #endif
 
-extern const struct xfs_buf_ops xfs_dir3_data_buf_ops;
-extern const struct xfs_buf_ops xfs_dir3_free_buf_ops;
-
 extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp);
 extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp,
                xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp);
@@ -60,27 +60,10 @@ extern int xfs_dir3_data_readahead(struct xfs_trans *tp, struct xfs_inode *dp,
 extern struct xfs_dir2_data_free *
 xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr,
                struct xfs_dir2_data_unused *dup, int *loghead);
-extern void xfs_dir2_data_freescan(struct xfs_mount *mp,
-               struct xfs_dir2_data_hdr *hdr, int *loghead);
 extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno,
                struct xfs_buf **bpp);
-extern void xfs_dir2_data_log_entry(struct xfs_trans *tp, struct xfs_buf *bp,
-               struct xfs_dir2_data_entry *dep);
-extern void xfs_dir2_data_log_header(struct xfs_trans *tp,
-               struct xfs_buf *bp);
-extern void xfs_dir2_data_log_unused(struct xfs_trans *tp, struct xfs_buf *bp,
-               struct xfs_dir2_data_unused *dup);
-extern void xfs_dir2_data_make_free(struct xfs_trans *tp, struct xfs_buf *bp,
-               xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len,
-               int *needlogp, int *needscanp);
-extern void xfs_dir2_data_use_free(struct xfs_trans *tp, struct xfs_buf *bp,
-               struct xfs_dir2_data_unused *dup, xfs_dir2_data_aoff_t offset,
-               xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp);
 
 /* xfs_dir2_leaf.c */
-extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops;
-extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops;
-
 extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp,
                xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp);
 extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args,
@@ -91,8 +74,6 @@ extern void xfs_dir3_leaf_compact(struct xfs_da_args *args,
 extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr,
                struct xfs_dir2_leaf_entry *ents, int *indexp,
                int *lowstalep, int *highstalep, int *lowlogp, int *highlogp);
-extern int xfs_dir2_leaf_getdents(struct xfs_inode *dp, struct dir_context *ctx,
-               size_t bufsize);
 extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno,
                struct xfs_buf **bpp, __uint16_t magic);
 extern void xfs_dir3_leaf_log_ents(struct xfs_trans *tp, struct xfs_buf *bp,
@@ -144,18 +125,18 @@ extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp,
                xfs_dablk_t fbno, struct xfs_buf **bpp);
 
 /* xfs_dir2_sf.c */
-extern xfs_ino_t xfs_dir2_sf_get_parent_ino(struct xfs_dir2_sf_hdr *sfp);
-extern xfs_ino_t xfs_dir2_sfe_get_ino(struct xfs_dir2_sf_hdr *sfp,
-               struct xfs_dir2_sf_entry *sfep);
 extern int xfs_dir2_block_sfsize(struct xfs_inode *dp,
                struct xfs_dir2_data_hdr *block, struct xfs_dir2_sf_hdr *sfhp);
 extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp,
                int size, xfs_dir2_sf_hdr_t *sfhp);
 extern int xfs_dir2_sf_addname(struct xfs_da_args *args);
 extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino);
-extern int xfs_dir2_sf_getdents(struct xfs_inode *dp, struct dir_context *ctx);
 extern int xfs_dir2_sf_lookup(struct xfs_da_args *args);
 extern int xfs_dir2_sf_removename(struct xfs_da_args *args);
 extern int xfs_dir2_sf_replace(struct xfs_da_args *args);
 
+/* xfs_dir2_readdir.c */
+extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx,
+                      size_t bufsize);
+
 #endif /* __XFS_DIR2_PRIV_H__ */
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
new file mode 100644 (file)
index 0000000..8993ec1
--- /dev/null
@@ -0,0 +1,695 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2013 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_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
+#include "xfs_dir2_priv.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_bmap.h"
+
+/*
+ * Directory file type support functions
+ */
+static unsigned char xfs_dir3_filetype_table[] = {
+       DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK,
+       DT_FIFO, DT_SOCK, DT_LNK, DT_WHT,
+};
+
+unsigned char
+xfs_dir3_get_dtype(
+       struct xfs_mount        *mp,
+       __uint8_t               filetype)
+{
+       if (!xfs_sb_version_hasftype(&mp->m_sb))
+               return DT_UNKNOWN;
+
+       if (filetype >= XFS_DIR3_FT_MAX)
+               return DT_UNKNOWN;
+
+       return xfs_dir3_filetype_table[filetype];
+}
+/*
+ * @mode, if set, indicates that the type field needs to be set up.
+ * This uses the transformation from file mode to DT_* as defined in linux/fs.h
+ * for file type specification. This will be propagated into the directory
+ * structure if appropriate for the given operation and filesystem config.
+ */
+const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
+       [0]                     = XFS_DIR3_FT_UNKNOWN,
+       [S_IFREG >> S_SHIFT]    = XFS_DIR3_FT_REG_FILE,
+       [S_IFDIR >> S_SHIFT]    = XFS_DIR3_FT_DIR,
+       [S_IFCHR >> S_SHIFT]    = XFS_DIR3_FT_CHRDEV,
+       [S_IFBLK >> S_SHIFT]    = XFS_DIR3_FT_BLKDEV,
+       [S_IFIFO >> S_SHIFT]    = XFS_DIR3_FT_FIFO,
+       [S_IFSOCK >> S_SHIFT]   = XFS_DIR3_FT_SOCK,
+       [S_IFLNK >> S_SHIFT]    = XFS_DIR3_FT_SYMLINK,
+};
+
+STATIC int
+xfs_dir2_sf_getdents(
+       xfs_inode_t             *dp,            /* incore directory inode */
+       struct dir_context      *ctx)
+{
+       int                     i;              /* shortform entry number */
+       xfs_mount_t             *mp;            /* filesystem mount point */
+       xfs_dir2_dataptr_t      off;            /* current entry's offset */
+       xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
+       xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
+       xfs_dir2_dataptr_t      dot_offset;
+       xfs_dir2_dataptr_t      dotdot_offset;
+       xfs_ino_t               ino;
+
+       mp = dp->i_mount;
+
+       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
+       /*
+        * Give up if the directory is way too short.
+        */
+       if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
+               ASSERT(XFS_FORCED_SHUTDOWN(mp));
+               return XFS_ERROR(EIO);
+       }
+
+       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
+       ASSERT(dp->i_df.if_u1.if_data != NULL);
+
+       sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
+
+       ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
+
+       /*
+        * If the block number in the offset is out of range, we're done.
+        */
+       if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
+               return 0;
+
+       /*
+        * Precalculate offsets for . and .. as we will always need them.
+        *
+        * XXX(hch): the second argument is sometimes 0 and sometimes
+        * mp->m_dirdatablk.
+        */
+       dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+                                            XFS_DIR3_DATA_DOT_OFFSET(mp));
+       dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+                                               XFS_DIR3_DATA_DOTDOT_OFFSET(mp));
+
+       /*
+        * Put . entry unless we're starting past it.
+        */
+       if (ctx->pos <= dot_offset) {
+               ctx->pos = dot_offset & 0x7fffffff;
+               if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR))
+                       return 0;
+       }
+
+       /*
+        * Put .. entry unless we're starting past it.
+        */
+       if (ctx->pos <= dotdot_offset) {
+               ino = xfs_dir2_sf_get_parent_ino(sfp);
+               ctx->pos = dotdot_offset & 0x7fffffff;
+               if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
+                       return 0;
+       }
+
+       /*
+        * Loop while there are more entries and put'ing works.
+        */
+       sfep = xfs_dir2_sf_firstentry(sfp);
+       for (i = 0; i < sfp->count; i++) {
+               __uint8_t filetype;
+
+               off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+                               xfs_dir2_sf_get_offset(sfep));
+
+               if (ctx->pos > off) {
+                       sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
+                       continue;
+               }
+
+               ino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
+               filetype = xfs_dir3_sfe_get_ftype(mp, sfp, sfep);
+               ctx->pos = off & 0x7fffffff;
+               if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino,
+                           xfs_dir3_get_dtype(mp, filetype)))
+                       return 0;
+               sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
+       }
+
+       ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
+                       0x7fffffff;
+       return 0;
+}
+
+/*
+ * Readdir for block directories.
+ */
+STATIC int
+xfs_dir2_block_getdents(
+       xfs_inode_t             *dp,            /* incore inode */
+       struct dir_context      *ctx)
+{
+       xfs_dir2_data_hdr_t     *hdr;           /* block header */
+       struct xfs_buf          *bp;            /* buffer for block */
+       xfs_dir2_block_tail_t   *btp;           /* block tail */
+       xfs_dir2_data_entry_t   *dep;           /* block data entry */
+       xfs_dir2_data_unused_t  *dup;           /* block unused entry */
+       char                    *endptr;        /* end of the data entries */
+       int                     error;          /* error return value */
+       xfs_mount_t             *mp;            /* filesystem mount point */
+       char                    *ptr;           /* current data entry */
+       int                     wantoff;        /* starting block offset */
+       xfs_off_t               cook;
+
+       mp = dp->i_mount;
+       /*
+        * If the block number in the offset is out of range, we're done.
+        */
+       if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
+               return 0;
+
+       error = xfs_dir3_block_read(NULL, dp, &bp);
+       if (error)
+               return error;
+
+       /*
+        * Extract the byte offset we start at from the seek pointer.
+        * We'll skip entries before this.
+        */
+       wantoff = xfs_dir2_dataptr_to_off(mp, ctx->pos);
+       hdr = bp->b_addr;
+       xfs_dir3_data_check(dp, bp);
+       /*
+        * Set up values for the loop.
+        */
+       btp = xfs_dir2_block_tail_p(mp, hdr);
+       ptr = (char *)xfs_dir3_data_entry_p(hdr);
+       endptr = (char *)xfs_dir2_block_leaf_p(btp);
+
+       /*
+        * Loop over the data portion of the block.
+        * Each object is a real entry (dep) or an unused one (dup).
+        */
+       while (ptr < endptr) {
+               __uint8_t filetype;
+
+               dup = (xfs_dir2_data_unused_t *)ptr;
+               /*
+                * Unused, skip it.
+                */
+               if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+                       ptr += be16_to_cpu(dup->length);
+                       continue;
+               }
+
+               dep = (xfs_dir2_data_entry_t *)ptr;
+
+               /*
+                * Bump pointer for the next iteration.
+                */
+               ptr += xfs_dir3_data_entsize(mp, dep->namelen);
+               /*
+                * The entry is before the desired starting point, skip it.
+                */
+               if ((char *)dep - (char *)hdr < wantoff)
+                       continue;
+
+               cook = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
+                                           (char *)dep - (char *)hdr);
+
+               ctx->pos = cook & 0x7fffffff;
+               filetype = xfs_dir3_dirent_get_ftype(mp, dep);
+               /*
+                * If it didn't fit, set the final offset to here & return.
+                */
+               if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
+                           be64_to_cpu(dep->inumber),
+                           xfs_dir3_get_dtype(mp, filetype))) {
+                       xfs_trans_brelse(NULL, bp);
+                       return 0;
+               }
+       }
+
+       /*
+        * Reached the end of the block.
+        * Set the offset to a non-existent block 1 and return.
+        */
+       ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
+                       0x7fffffff;
+       xfs_trans_brelse(NULL, bp);
+       return 0;
+}
+
+struct xfs_dir2_leaf_map_info {
+       xfs_extlen_t    map_blocks;     /* number of fsbs in map */
+       xfs_dablk_t     map_off;        /* last mapped file offset */
+       int             map_size;       /* total entries in *map */
+       int             map_valid;      /* valid entries in *map */
+       int             nmap;           /* mappings to ask xfs_bmapi */
+       xfs_dir2_db_t   curdb;          /* db for current block */
+       int             ra_current;     /* number of read-ahead blks */
+       int             ra_index;       /* *map index for read-ahead */
+       int             ra_offset;      /* map entry offset for ra */
+       int             ra_want;        /* readahead count wanted */
+       struct xfs_bmbt_irec map[];     /* map vector for blocks */
+};
+
+STATIC int
+xfs_dir2_leaf_readbuf(
+       struct xfs_inode        *dp,
+       size_t                  bufsize,
+       struct xfs_dir2_leaf_map_info *mip,
+       xfs_dir2_off_t          *curoff,
+       struct xfs_buf          **bpp)
+{
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_buf          *bp = *bpp;
+       struct xfs_bmbt_irec    *map = mip->map;
+       struct blk_plug         plug;
+       int                     error = 0;
+       int                     length;
+       int                     i;
+       int                     j;
+
+       /*
+        * If we have a buffer, we need to release it and
+        * take it out of the mapping.
+        */
+
+       if (bp) {
+               xfs_trans_brelse(NULL, bp);
+               bp = NULL;
+               mip->map_blocks -= mp->m_dirblkfsbs;
+               /*
+                * Loop to get rid of the extents for the
+                * directory block.
+                */
+               for (i = mp->m_dirblkfsbs; i > 0; ) {
+                       j = min_t(int, map->br_blockcount, i);
+                       map->br_blockcount -= j;
+                       map->br_startblock += j;
+                       map->br_startoff += j;
+                       /*
+                        * If mapping is done, pitch it from
+                        * the table.
+                        */
+                       if (!map->br_blockcount && --mip->map_valid)
+                               memmove(&map[0], &map[1],
+                                       sizeof(map[0]) * mip->map_valid);
+                       i -= j;
+               }
+       }
+
+       /*
+        * Recalculate the readahead blocks wanted.
+        */
+       mip->ra_want = howmany(bufsize + mp->m_dirblksize,
+                              mp->m_sb.sb_blocksize) - 1;
+       ASSERT(mip->ra_want >= 0);
+
+       /*
+        * If we don't have as many as we want, and we haven't
+        * run out of data blocks, get some more mappings.
+        */
+       if (1 + mip->ra_want > mip->map_blocks &&
+           mip->map_off < xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET)) {
+               /*
+                * Get more bmaps, fill in after the ones
+                * we already have in the table.
+                */
+               mip->nmap = mip->map_size - mip->map_valid;
+               error = xfs_bmapi_read(dp, mip->map_off,
+                               xfs_dir2_byte_to_da(mp, XFS_DIR2_LEAF_OFFSET) -
+                                                               mip->map_off,
+                               &map[mip->map_valid], &mip->nmap, 0);
+
+               /*
+                * Don't know if we should ignore this or try to return an
+                * error.  The trouble with returning errors is that readdir
+                * will just stop without actually passing the error through.
+                */
+               if (error)
+                       goto out;       /* XXX */
+
+               /*
+                * If we got all the mappings we asked for, set the final map
+                * offset based on the last bmap value received.  Otherwise,
+                * we've reached the end.
+                */
+               if (mip->nmap == mip->map_size - mip->map_valid) {
+                       i = mip->map_valid + mip->nmap - 1;
+                       mip->map_off = map[i].br_startoff + map[i].br_blockcount;
+               } else
+                       mip->map_off = xfs_dir2_byte_to_da(mp,
+                                                       XFS_DIR2_LEAF_OFFSET);
+
+               /*
+                * Look for holes in the mapping, and eliminate them.  Count up
+                * the valid blocks.
+                */
+               for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) {
+                       if (map[i].br_startblock == HOLESTARTBLOCK) {
+                               mip->nmap--;
+                               length = mip->map_valid + mip->nmap - i;
+                               if (length)
+                                       memmove(&map[i], &map[i + 1],
+                                               sizeof(map[i]) * length);
+                       } else {
+                               mip->map_blocks += map[i].br_blockcount;
+                               i++;
+                       }
+               }
+               mip->map_valid += mip->nmap;
+       }
+
+       /*
+        * No valid mappings, so no more data blocks.
+        */
+       if (!mip->map_valid) {
+               *curoff = xfs_dir2_da_to_byte(mp, mip->map_off);
+               goto out;
+       }
+
+       /*
+        * Read the directory block starting at the first mapping.
+        */
+       mip->curdb = xfs_dir2_da_to_db(mp, map->br_startoff);
+       error = xfs_dir3_data_read(NULL, dp, map->br_startoff,
+                       map->br_blockcount >= mp->m_dirblkfsbs ?
+                           XFS_FSB_TO_DADDR(mp, map->br_startblock) : -1, &bp);
+
+       /*
+        * Should just skip over the data block instead of giving up.
+        */
+       if (error)
+               goto out;       /* XXX */
+
+       /*
+        * Adjust the current amount of read-ahead: we just read a block that
+        * was previously ra.
+        */
+       if (mip->ra_current)
+               mip->ra_current -= mp->m_dirblkfsbs;
+
+       /*
+        * Do we need more readahead?
+        */
+       blk_start_plug(&plug);
+       for (mip->ra_index = mip->ra_offset = i = 0;
+            mip->ra_want > mip->ra_current && i < mip->map_blocks;
+            i += mp->m_dirblkfsbs) {
+               ASSERT(mip->ra_index < mip->map_valid);
+               /*
+                * Read-ahead a contiguous directory block.
+                */
+               if (i > mip->ra_current &&
+                   map[mip->ra_index].br_blockcount >= mp->m_dirblkfsbs) {
+                       xfs_dir3_data_readahead(NULL, dp,
+                               map[mip->ra_index].br_startoff + mip->ra_offset,
+                               XFS_FSB_TO_DADDR(mp,
+                                       map[mip->ra_index].br_startblock +
+                                                       mip->ra_offset));
+                       mip->ra_current = i;
+               }
+
+               /*
+                * Read-ahead a non-contiguous directory block.  This doesn't
+                * use our mapping, but this is a very rare case.
+                */
+               else if (i > mip->ra_current) {
+                       xfs_dir3_data_readahead(NULL, dp,
+                                       map[mip->ra_index].br_startoff +
+                                                       mip->ra_offset, -1);
+                       mip->ra_current = i;
+               }
+
+               /*
+                * Advance offset through the mapping table.
+                */
+               for (j = 0; j < mp->m_dirblkfsbs; j++) {
+                       /*
+                        * The rest of this extent but not more than a dir
+                        * block.
+                        */
+                       length = min_t(int, mp->m_dirblkfsbs,
+                                       map[mip->ra_index].br_blockcount -
+                                                       mip->ra_offset);
+                       j += length;
+                       mip->ra_offset += length;
+
+                       /*
+                        * Advance to the next mapping if this one is used up.
+                        */
+                       if (mip->ra_offset == map[mip->ra_index].br_blockcount) {
+                               mip->ra_offset = 0;
+                               mip->ra_index++;
+                       }
+               }
+       }
+       blk_finish_plug(&plug);
+
+out:
+       *bpp = bp;
+       return error;
+}
+
+/*
+ * Getdents (readdir) for leaf and node directories.
+ * This reads the data blocks only, so is the same for both forms.
+ */
+STATIC int
+xfs_dir2_leaf_getdents(
+       xfs_inode_t             *dp,            /* incore directory inode */
+       struct dir_context      *ctx,
+       size_t                  bufsize)
+{
+       struct xfs_buf          *bp = NULL;     /* data block buffer */
+       xfs_dir2_data_hdr_t     *hdr;           /* data block header */
+       xfs_dir2_data_entry_t   *dep;           /* data entry */
+       xfs_dir2_data_unused_t  *dup;           /* unused entry */
+       int                     error = 0;      /* error return value */
+       int                     length;         /* temporary length value */
+       xfs_mount_t             *mp;            /* filesystem mount point */
+       int                     byteoff;        /* offset in current block */
+       xfs_dir2_off_t          curoff;         /* current overall offset */
+       xfs_dir2_off_t          newoff;         /* new curoff after new blk */
+       char                    *ptr = NULL;    /* pointer to current data */
+       struct xfs_dir2_leaf_map_info *map_info;
+
+       /*
+        * If the offset is at or past the largest allowed value,
+        * give up right away.
+        */
+       if (ctx->pos >= XFS_DIR2_MAX_DATAPTR)
+               return 0;
+
+       mp = dp->i_mount;
+
+       /*
+        * Set up to bmap a number of blocks based on the caller's
+        * buffer size, the directory block size, and the filesystem
+        * block size.
+        */
+       length = howmany(bufsize + mp->m_dirblksize,
+                                    mp->m_sb.sb_blocksize);
+       map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) +
+                               (length * sizeof(struct xfs_bmbt_irec)),
+                              KM_SLEEP | KM_NOFS);
+       map_info->map_size = length;
+
+       /*
+        * Inside the loop we keep the main offset value as a byte offset
+        * in the directory file.
+        */
+       curoff = xfs_dir2_dataptr_to_byte(mp, ctx->pos);
+
+       /*
+        * Force this conversion through db so we truncate the offset
+        * down to get the start of the data block.
+        */
+       map_info->map_off = xfs_dir2_db_to_da(mp,
+                                             xfs_dir2_byte_to_db(mp, curoff));
+
+       /*
+        * Loop over directory entries until we reach the end offset.
+        * Get more blocks and readahead as necessary.
+        */
+       while (curoff < XFS_DIR2_LEAF_OFFSET) {
+               __uint8_t filetype;
+
+               /*
+                * If we have no buffer, or we're off the end of the
+                * current buffer, need to get another one.
+                */
+               if (!bp || ptr >= (char *)bp->b_addr + mp->m_dirblksize) {
+
+                       error = xfs_dir2_leaf_readbuf(dp, bufsize, map_info,
+                                                     &curoff, &bp);
+                       if (error || !map_info->map_valid)
+                               break;
+
+                       /*
+                        * Having done a read, we need to set a new offset.
+                        */
+                       newoff = xfs_dir2_db_off_to_byte(mp, map_info->curdb, 0);
+                       /*
+                        * Start of the current block.
+                        */
+                       if (curoff < newoff)
+                               curoff = newoff;
+                       /*
+                        * Make sure we're in the right block.
+                        */
+                       else if (curoff > newoff)
+                               ASSERT(xfs_dir2_byte_to_db(mp, curoff) ==
+                                      map_info->curdb);
+                       hdr = bp->b_addr;
+                       xfs_dir3_data_check(dp, bp);
+                       /*
+                        * Find our position in the block.
+                        */
+                       ptr = (char *)xfs_dir3_data_entry_p(hdr);
+                       byteoff = xfs_dir2_byte_to_off(mp, curoff);
+                       /*
+                        * Skip past the header.
+                        */
+                       if (byteoff == 0)
+                               curoff += xfs_dir3_data_entry_offset(hdr);
+                       /*
+                        * Skip past entries until we reach our offset.
+                        */
+                       else {
+                               while ((char *)ptr - (char *)hdr < byteoff) {
+                                       dup = (xfs_dir2_data_unused_t *)ptr;
+
+                                       if (be16_to_cpu(dup->freetag)
+                                                 == XFS_DIR2_DATA_FREE_TAG) {
+
+                                               length = be16_to_cpu(dup->length);
+                                               ptr += length;
+                                               continue;
+                                       }
+                                       dep = (xfs_dir2_data_entry_t *)ptr;
+                                       length =
+                                          xfs_dir3_data_entsize(mp, dep->namelen);
+                                       ptr += length;
+                               }
+                               /*
+                                * Now set our real offset.
+                                */
+                               curoff =
+                                       xfs_dir2_db_off_to_byte(mp,
+                                           xfs_dir2_byte_to_db(mp, curoff),
+                                           (char *)ptr - (char *)hdr);
+                               if (ptr >= (char *)hdr + mp->m_dirblksize) {
+                                       continue;
+                               }
+                       }
+               }
+               /*
+                * We have a pointer to an entry.
+                * Is it a live one?
+                */
+               dup = (xfs_dir2_data_unused_t *)ptr;
+               /*
+                * No, it's unused, skip over it.
+                */
+               if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
+                       length = be16_to_cpu(dup->length);
+                       ptr += length;
+                       curoff += length;
+                       continue;
+               }
+
+               dep = (xfs_dir2_data_entry_t *)ptr;
+               length = xfs_dir3_data_entsize(mp, dep->namelen);
+               filetype = xfs_dir3_dirent_get_ftype(mp, dep);
+
+               ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
+               if (!dir_emit(ctx, (char *)dep->name, dep->namelen,
+                           be64_to_cpu(dep->inumber),
+                           xfs_dir3_get_dtype(mp, filetype)))
+                       break;
+
+               /*
+                * Advance to next entry in the block.
+                */
+               ptr += length;
+               curoff += length;
+               /* bufsize may have just been a guess; don't go negative */
+               bufsize = bufsize > length ? bufsize - length : 0;
+       }
+
+       /*
+        * All done.  Set output offset value to current offset.
+        */
+       if (curoff > xfs_dir2_dataptr_to_byte(mp, XFS_DIR2_MAX_DATAPTR))
+               ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff;
+       else
+               ctx->pos = xfs_dir2_byte_to_dataptr(mp, curoff) & 0x7fffffff;
+       kmem_free(map_info);
+       if (bp)
+               xfs_trans_brelse(NULL, bp);
+       return error;
+}
+
+/*
+ * Read a directory.
+ */
+int
+xfs_readdir(
+       xfs_inode_t     *dp,
+       struct dir_context *ctx,
+       size_t          bufsize)
+{
+       int             rval;           /* return value */
+       int             v;              /* type-checking value */
+
+       trace_xfs_readdir(dp);
+
+       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
+               return XFS_ERROR(EIO);
+
+       ASSERT(S_ISDIR(dp->i_d.di_mode));
+       XFS_STATS_INC(xs_dir_getdents);
+
+       if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL)
+               rval = xfs_dir2_sf_getdents(dp, ctx);
+       else if ((rval = xfs_dir2_isblock(NULL, dp, &v)))
+               ;
+       else if (v)
+               rval = xfs_dir2_block_getdents(dp, ctx);
+       else
+               rval = xfs_dir2_leaf_getdents(dp, ctx, bufsize);
+       return rval;
+}
index 97676a347da166e5d843db8ab2052666390e018d..bb6e2848f473d024d5ff1dd70a1232443901ea9f 100644 (file)
@@ -29,8 +29,8 @@
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_error.h"
-#include "xfs_dir2.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_trace.h"
 
@@ -95,7 +95,7 @@ xfs_dir2_sf_get_parent_ino(
        return xfs_dir2_sf_get_ino(hdr, &hdr->parent);
 }
 
-static void
+void
 xfs_dir2_sf_put_parent_ino(
        struct xfs_dir2_sf_hdr  *hdr,
        xfs_ino_t               ino)
@@ -105,31 +105,38 @@ xfs_dir2_sf_put_parent_ino(
 
 /*
  * In short-form directory entries the inode numbers are stored at variable
- * offset behind the entry name.  The inode numbers may only be accessed
- * through the helpers below.
+ * offset behind the entry name. If the entry stores a filetype value, then it
+ * sits between the name and the inode number. Hence the inode numbers may only
+ * be accessed through the helpers below.
  */
 static xfs_dir2_inou_t *
-xfs_dir2_sfe_inop(
+xfs_dir3_sfe_inop(
+       struct xfs_mount        *mp,
        struct xfs_dir2_sf_entry *sfep)
 {
-       return (xfs_dir2_inou_t *)&sfep->name[sfep->namelen];
+       __uint8_t       *ptr = &sfep->name[sfep->namelen];
+       if (xfs_sb_version_hasftype(&mp->m_sb))
+               ptr++;
+       return (xfs_dir2_inou_t *)ptr;
 }
 
 xfs_ino_t
-xfs_dir2_sfe_get_ino(
+xfs_dir3_sfe_get_ino(
+       struct xfs_mount        *mp,
        struct xfs_dir2_sf_hdr  *hdr,
        struct xfs_dir2_sf_entry *sfep)
 {
-       return xfs_dir2_sf_get_ino(hdr, xfs_dir2_sfe_inop(sfep));
+       return xfs_dir2_sf_get_ino(hdr, xfs_dir3_sfe_inop(mp, sfep));
 }
 
-static void
-xfs_dir2_sfe_put_ino(
+void
+xfs_dir3_sfe_put_ino(
+       struct xfs_mount        *mp,
        struct xfs_dir2_sf_hdr  *hdr,
        struct xfs_dir2_sf_entry *sfep,
        xfs_ino_t               ino)
 {
-       xfs_dir2_sf_put_ino(hdr, xfs_dir2_sfe_inop(sfep), ino);
+       xfs_dir2_sf_put_ino(hdr, xfs_dir3_sfe_inop(mp, sfep), ino);
 }
 
 /*
@@ -157,9 +164,16 @@ xfs_dir2_block_sfsize(
        int                     namelen;        /* total name bytes */
        xfs_ino_t               parent = 0;     /* parent inode number */
        int                     size=0;         /* total computed size */
+       int                     has_ftype;
 
        mp = dp->i_mount;
 
+       /*
+        * if there is a filetype field, add the extra byte to the namelen
+        * for each entry that we see.
+        */
+       has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0;
+
        count = i8count = namelen = 0;
        btp = xfs_dir2_block_tail_p(mp, hdr);
        blp = xfs_dir2_block_leaf_p(btp);
@@ -188,9 +202,10 @@ xfs_dir2_block_sfsize(
                if (!isdot)
                        i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM;
 #endif
+               /* take into account the file type field */
                if (!isdot && !isdotdot) {
                        count++;
-                       namelen += dep->namelen;
+                       namelen += dep->namelen + has_ftype;
                } else if (isdotdot)
                        parent = be64_to_cpu(dep->inumber);
                /*
@@ -316,12 +331,14 @@ xfs_dir2_block_to_sf(
                                (xfs_dir2_data_aoff_t)
                                ((char *)dep - (char *)hdr));
                        memcpy(sfep->name, dep->name, dep->namelen);
-                       xfs_dir2_sfe_put_ino(sfp, sfep,
+                       xfs_dir3_sfe_put_ino(mp, sfp, sfep,
                                             be64_to_cpu(dep->inumber));
+                       xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
+                                       xfs_dir3_dirent_get_ftype(mp, dep));
 
-                       sfep = xfs_dir2_sf_nextentry(sfp, sfep);
+                       sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
                }
-               ptr += xfs_dir2_data_entsize(dep->namelen);
+               ptr += xfs_dir3_data_entsize(mp, dep->namelen);
        }
        ASSERT((char *)sfep - (char *)sfp == size);
        xfs_dir2_sf_check(args);
@@ -372,7 +389,7 @@ xfs_dir2_sf_addname(
        /*
         * Compute entry (and change in) size.
         */
-       add_entsize = xfs_dir2_sf_entsize(sfp, args->namelen);
+       add_entsize = xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen);
        incr_isize = add_entsize;
        objchange = 0;
 #if XFS_BIG_INUMS
@@ -466,8 +483,9 @@ xfs_dir2_sf_addname_easy(
        /*
         * Grow the in-inode space.
         */
-       xfs_idata_realloc(dp, xfs_dir2_sf_entsize(sfp, args->namelen),
-               XFS_DATA_FORK);
+       xfs_idata_realloc(dp,
+                         xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen),
+                         XFS_DATA_FORK);
        /*
         * Need to set up again due to realloc of the inode data.
         */
@@ -479,7 +497,9 @@ xfs_dir2_sf_addname_easy(
        sfep->namelen = args->namelen;
        xfs_dir2_sf_put_offset(sfep, offset);
        memcpy(sfep->name, args->name, sfep->namelen);
-       xfs_dir2_sfe_put_ino(sfp, sfep, args->inumber);
+       xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep, args->inumber);
+       xfs_dir3_sfe_put_ftype(dp->i_mount, sfp, sfep, args->filetype);
+
        /*
         * Update the header and inode.
         */
@@ -519,11 +539,13 @@ xfs_dir2_sf_addname_hard(
        xfs_dir2_sf_hdr_t       *oldsfp;        /* original shortform dir */
        xfs_dir2_sf_entry_t     *sfep;          /* entry in new dir */
        xfs_dir2_sf_hdr_t       *sfp;           /* new shortform dir */
+       struct xfs_mount        *mp;
 
        /*
         * Copy the old directory to the stack buffer.
         */
        dp = args->dp;
+       mp = dp->i_mount;
 
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
        old_isize = (int)dp->i_d.di_size;
@@ -535,13 +557,13 @@ xfs_dir2_sf_addname_hard(
         * to insert the new entry.
         * If it's going to end up at the end then oldsfep will point there.
         */
-       for (offset = XFS_DIR3_DATA_FIRST_OFFSET(dp->i_mount),
+       for (offset = XFS_DIR3_DATA_FIRST_OFFSET(mp),
              oldsfep = xfs_dir2_sf_firstentry(oldsfp),
-             add_datasize = xfs_dir2_data_entsize(args->namelen),
+             add_datasize = xfs_dir3_data_entsize(mp, args->namelen),
              eof = (char *)oldsfep == &buf[old_isize];
             !eof;
-            offset = new_offset + xfs_dir2_data_entsize(oldsfep->namelen),
-             oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep),
+            offset = new_offset + xfs_dir3_data_entsize(mp, oldsfep->namelen),
+             oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep),
              eof = (char *)oldsfep == &buf[old_isize]) {
                new_offset = xfs_dir2_sf_get_offset(oldsfep);
                if (offset + add_datasize <= new_offset)
@@ -570,7 +592,8 @@ xfs_dir2_sf_addname_hard(
        sfep->namelen = args->namelen;
        xfs_dir2_sf_put_offset(sfep, offset);
        memcpy(sfep->name, args->name, sfep->namelen);
-       xfs_dir2_sfe_put_ino(sfp, sfep, args->inumber);
+       xfs_dir3_sfe_put_ino(mp, sfp, sfep, args->inumber);
+       xfs_dir3_sfe_put_ftype(mp, sfp, sfep, args->filetype);
        sfp->count++;
 #if XFS_BIG_INUMS
        if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange)
@@ -580,7 +603,7 @@ xfs_dir2_sf_addname_hard(
         * If there's more left to copy, do that.
         */
        if (!eof) {
-               sfep = xfs_dir2_sf_nextentry(sfp, sfep);
+               sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
                memcpy(sfep, oldsfep, old_isize - nbytes);
        }
        kmem_free(buf);
@@ -616,7 +639,7 @@ xfs_dir2_sf_addname_pick(
        mp = dp->i_mount;
 
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       size = xfs_dir2_data_entsize(args->namelen);
+       size = xfs_dir3_data_entsize(mp, args->namelen);
        offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
        sfep = xfs_dir2_sf_firstentry(sfp);
        holefit = 0;
@@ -629,8 +652,8 @@ xfs_dir2_sf_addname_pick(
                if (!holefit)
                        holefit = offset + size <= xfs_dir2_sf_get_offset(sfep);
                offset = xfs_dir2_sf_get_offset(sfep) +
-                        xfs_dir2_data_entsize(sfep->namelen);
-               sfep = xfs_dir2_sf_nextentry(sfp, sfep);
+                        xfs_dir3_data_entsize(mp, sfep->namelen);
+               sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep);
        }
        /*
         * Calculate data bytes used excluding the new entry, if this
@@ -684,31 +707,34 @@ xfs_dir2_sf_check(
        int                     offset;         /* data offset */
        xfs_dir2_sf_entry_t     *sfep;          /* shortform dir entry */
        xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
+       struct xfs_mount        *mp;
 
        dp = args->dp;
+       mp = dp->i_mount;
 
        sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-       offset = XFS_DIR3_DATA_FIRST_OFFSET(dp->i_mount);
+       offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
        ino = xfs_dir2_sf_get_parent_ino(sfp);
        i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
 
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
             i < sfp->count;
-            i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
+            i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep)) {
                ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset);
-               ino = xfs_dir2_sfe_get_ino(sfp, sfep);
+               ino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
                i8count += ino > XFS_DIR2_MAX_SHORT_INUM;
                offset =
                        xfs_dir2_sf_get_offset(sfep) +
-                       xfs_dir2_data_entsize(sfep->namelen);
+                       xfs_dir3_data_entsize(mp, sfep->namelen);
+               ASSERT(xfs_dir3_sfe_get_ftype(mp, sfp, sfep) <
+                                                       XFS_DIR3_FT_MAX);
        }
        ASSERT(i8count == sfp->i8count);
        ASSERT(XFS_BIG_INUMS || i8count == 0);
        ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size);
        ASSERT(offset +
               (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) +
-              (uint)sizeof(xfs_dir2_block_tail_t) <=
-              dp->i_mount->m_dirblksize);
+              (uint)sizeof(xfs_dir2_block_tail_t) <= mp->m_dirblksize);
 }
 #endif /* DEBUG */
 
@@ -765,100 +791,6 @@ xfs_dir2_sf_create(
        return 0;
 }
 
-int                                            /* error */
-xfs_dir2_sf_getdents(
-       xfs_inode_t             *dp,            /* incore directory inode */
-       struct dir_context      *ctx)
-{
-       int                     i;              /* shortform entry number */
-       xfs_mount_t             *mp;            /* filesystem mount point */
-       xfs_dir2_dataptr_t      off;            /* current entry's offset */
-       xfs_dir2_sf_entry_t     *sfep;          /* shortform directory entry */
-       xfs_dir2_sf_hdr_t       *sfp;           /* shortform structure */
-       xfs_dir2_dataptr_t      dot_offset;
-       xfs_dir2_dataptr_t      dotdot_offset;
-       xfs_ino_t               ino;
-
-       mp = dp->i_mount;
-
-       ASSERT(dp->i_df.if_flags & XFS_IFINLINE);
-       /*
-        * Give up if the directory is way too short.
-        */
-       if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {
-               ASSERT(XFS_FORCED_SHUTDOWN(mp));
-               return XFS_ERROR(EIO);
-       }
-
-       ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);
-       ASSERT(dp->i_df.if_u1.if_data != NULL);
-
-       sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-
-       ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count));
-
-       /*
-        * If the block number in the offset is out of range, we're done.
-        */
-       if (xfs_dir2_dataptr_to_db(mp, ctx->pos) > mp->m_dirdatablk)
-               return 0;
-
-       /*
-        * Precalculate offsets for . and .. as we will always need them.
-        *
-        * XXX(hch): the second argument is sometimes 0 and sometimes
-        * mp->m_dirdatablk.
-        */
-       dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
-                                            XFS_DIR3_DATA_DOT_OFFSET(mp));
-       dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
-                                               XFS_DIR3_DATA_DOTDOT_OFFSET(mp));
-
-       /*
-        * Put . entry unless we're starting past it.
-        */
-       if (ctx->pos <= dot_offset) {
-               ctx->pos = dot_offset & 0x7fffffff;
-               if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR))
-                       return 0;
-       }
-
-       /*
-        * Put .. entry unless we're starting past it.
-        */
-       if (ctx->pos <= dotdot_offset) {
-               ino = xfs_dir2_sf_get_parent_ino(sfp);
-               ctx->pos = dotdot_offset & 0x7fffffff;
-               if (!dir_emit(ctx, "..", 2, ino, DT_DIR))
-                       return 0;
-       }
-
-       /*
-        * Loop while there are more entries and put'ing works.
-        */
-       sfep = xfs_dir2_sf_firstentry(sfp);
-       for (i = 0; i < sfp->count; i++) {
-               off = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
-                               xfs_dir2_sf_get_offset(sfep));
-
-               if (ctx->pos > off) {
-                       sfep = xfs_dir2_sf_nextentry(sfp, sfep);
-                       continue;
-               }
-
-               ino = xfs_dir2_sfe_get_ino(sfp, sfep);
-               ctx->pos = off & 0x7fffffff;
-               if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen,
-                           ino, DT_UNKNOWN))
-                       return 0;
-               sfep = xfs_dir2_sf_nextentry(sfp, sfep);
-       }
-
-       ctx->pos = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk + 1, 0) &
-                       0x7fffffff;
-       return 0;
-}
-
 /*
  * Lookup an entry in a shortform directory.
  * Returns EEXIST if found, ENOENT if not found.
@@ -898,6 +830,7 @@ xfs_dir2_sf_lookup(
        if (args->namelen == 1 && args->name[0] == '.') {
                args->inumber = dp->i_ino;
                args->cmpresult = XFS_CMP_EXACT;
+               args->filetype = XFS_DIR3_FT_DIR;
                return XFS_ERROR(EEXIST);
        }
        /*
@@ -907,6 +840,7 @@ xfs_dir2_sf_lookup(
            args->name[0] == '.' && args->name[1] == '.') {
                args->inumber = xfs_dir2_sf_get_parent_ino(sfp);
                args->cmpresult = XFS_CMP_EXACT;
+               args->filetype = XFS_DIR3_FT_DIR;
                return XFS_ERROR(EEXIST);
        }
        /*
@@ -914,7 +848,7 @@ xfs_dir2_sf_lookup(
         */
        ci_sfep = NULL;
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
-                               i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
+            i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
                /*
                 * Compare name and if it's an exact match, return the inode
                 * number. If it's the first case-insensitive match, store the
@@ -924,7 +858,10 @@ xfs_dir2_sf_lookup(
                                                                sfep->namelen);
                if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) {
                        args->cmpresult = cmp;
-                       args->inumber = xfs_dir2_sfe_get_ino(sfp, sfep);
+                       args->inumber = xfs_dir3_sfe_get_ino(dp->i_mount,
+                                                            sfp, sfep);
+                       args->filetype = xfs_dir3_sfe_get_ftype(dp->i_mount,
+                                                               sfp, sfep);
                        if (cmp == XFS_CMP_EXACT)
                                return XFS_ERROR(EEXIST);
                        ci_sfep = sfep;
@@ -980,10 +917,10 @@ xfs_dir2_sf_removename(
         * Find the one we're deleting.
         */
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
-                               i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
+            i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
                if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
                                                                XFS_CMP_EXACT) {
-                       ASSERT(xfs_dir2_sfe_get_ino(sfp, sfep) ==
+                       ASSERT(xfs_dir3_sfe_get_ino(dp->i_mount, sfp, sfep) ==
                               args->inumber);
                        break;
                }
@@ -997,7 +934,7 @@ xfs_dir2_sf_removename(
         * Calculate sizes.
         */
        byteoff = (int)((char *)sfep - (char *)sfp);
-       entsize = xfs_dir2_sf_entsize(sfp, args->namelen);
+       entsize = xfs_dir3_sf_entsize(dp->i_mount, sfp, args->namelen);
        newsize = oldsize - entsize;
        /*
         * Copy the part if any after the removed entry, sliding it down.
@@ -1113,16 +1050,19 @@ xfs_dir2_sf_replace(
         * Normal entry, look for the name.
         */
        else {
-               for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp);
-                               i < sfp->count;
-                               i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep)) {
+               for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count;
+                    i++, sfep = xfs_dir3_sf_nextentry(dp->i_mount, sfp, sfep)) {
                        if (xfs_da_compname(args, sfep->name, sfep->namelen) ==
                                                                XFS_CMP_EXACT) {
 #if XFS_BIG_INUMS || defined(DEBUG)
-                               ino = xfs_dir2_sfe_get_ino(sfp, sfep);
+                               ino = xfs_dir3_sfe_get_ino(dp->i_mount,
+                                                          sfp, sfep);
                                ASSERT(args->inumber != ino);
 #endif
-                               xfs_dir2_sfe_put_ino(sfp, sfep, args->inumber);
+                               xfs_dir3_sfe_put_ino(dp->i_mount, sfp, sfep,
+                                                    args->inumber);
+                               xfs_dir3_sfe_put_ftype(dp->i_mount, sfp, sfep,
+                                                      args->filetype);
                                break;
                        }
                }
@@ -1189,10 +1129,12 @@ xfs_dir2_sf_toino4(
        int                     oldsize;        /* old inode size */
        xfs_dir2_sf_entry_t     *sfep;          /* new sf entry */
        xfs_dir2_sf_hdr_t       *sfp;           /* new sf directory */
+       struct xfs_mount        *mp;
 
        trace_xfs_dir2_sf_toino4(args);
 
        dp = args->dp;
+       mp = dp->i_mount;
 
        /*
         * Copy the old directory to the buffer.
@@ -1230,13 +1172,15 @@ xfs_dir2_sf_toino4(
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
                    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
             i < sfp->count;
-            i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
-                 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
+            i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep),
+                 oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep)) {
                sfep->namelen = oldsfep->namelen;
                sfep->offset = oldsfep->offset;
                memcpy(sfep->name, oldsfep->name, sfep->namelen);
-               xfs_dir2_sfe_put_ino(sfp, sfep,
-                       xfs_dir2_sfe_get_ino(oldsfp, oldsfep));
+               xfs_dir3_sfe_put_ino(mp, sfp, sfep,
+                       xfs_dir3_sfe_get_ino(mp, oldsfp, oldsfep));
+               xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
+                       xfs_dir3_sfe_get_ftype(mp, oldsfp, oldsfep));
        }
        /*
         * Clean up the inode.
@@ -1264,10 +1208,12 @@ xfs_dir2_sf_toino8(
        int                     oldsize;        /* old inode size */
        xfs_dir2_sf_entry_t     *sfep;          /* new sf entry */
        xfs_dir2_sf_hdr_t       *sfp;           /* new sf directory */
+       struct xfs_mount        *mp;
 
        trace_xfs_dir2_sf_toino8(args);
 
        dp = args->dp;
+       mp = dp->i_mount;
 
        /*
         * Copy the old directory to the buffer.
@@ -1305,13 +1251,15 @@ xfs_dir2_sf_toino8(
        for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp),
                    oldsfep = xfs_dir2_sf_firstentry(oldsfp);
             i < sfp->count;
-            i++, sfep = xfs_dir2_sf_nextentry(sfp, sfep),
-                 oldsfep = xfs_dir2_sf_nextentry(oldsfp, oldsfep)) {
+            i++, sfep = xfs_dir3_sf_nextentry(mp, sfp, sfep),
+                 oldsfep = xfs_dir3_sf_nextentry(mp, oldsfp, oldsfep)) {
                sfep->namelen = oldsfep->namelen;
                sfep->offset = oldsfep->offset;
                memcpy(sfep->name, oldsfep->name, sfep->namelen);
-               xfs_dir2_sfe_put_ino(sfp, sfep,
-                       xfs_dir2_sfe_get_ino(oldsfp, oldsfep));
+               xfs_dir3_sfe_put_ino(mp, sfp, sfep,
+                       xfs_dir3_sfe_get_ino(mp, oldsfp, oldsfep));
+               xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
+                       xfs_dir3_sfe_get_ftype(mp, oldsfp, oldsfep));
        }
        /*
         * Clean up the inode.
index 69cf4fcde03e2d31266f70f6dfee1b73fe71b4a7..45560ee1a4ba8b1ccfdc36f9616cc5355e03558d 100644 (file)
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "xfs.h"
-#include "xfs_sb.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
 #include "xfs_quota.h"
-#include "xfs_trans.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_ialloc_btree.h"
index 0adf27ecf3f1cd4e98d8fcc06a732e4d476437db..71520e6e5d65048c04996133621b2916653b5c31 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
@@ -28,6 +29,7 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_itable.h"
@@ -710,10 +712,8 @@ xfs_qm_dqread(
 
        if (flags & XFS_QMOPT_DQALLOC) {
                tp = xfs_trans_alloc(mp, XFS_TRANS_QM_DQALLOC);
-               error = xfs_trans_reserve(tp, XFS_QM_DQALLOC_SPACE_RES(mp),
-                                         XFS_QM_DQALLOC_LOG_RES(mp), 0,
-                                         XFS_TRANS_PERM_LOG_RES,
-                                         XFS_WRITE_LOG_COUNT);
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_attrsetm,
+                                         XFS_QM_DQALLOC_SPACE_RES(mp), 0);
                if (error)
                        goto error1;
                cancelflags = XFS_TRANS_RELEASE_LOG_RES;
@@ -940,13 +940,8 @@ xfs_qm_dqput_final(
 
        trace_xfs_dqput_free(dqp);
 
-       mutex_lock(&qi->qi_lru_lock);
-       if (list_empty(&dqp->q_lru)) {
-               list_add_tail(&dqp->q_lru, &qi->qi_lru_list);
-               qi->qi_lru_count++;
+       if (list_lru_add(&qi->qi_lru, &dqp->q_lru))
                XFS_STATS_INC(xs_qm_dquot_unused);
-       }
-       mutex_unlock(&qi->qi_lru_lock);
 
        /*
         * If we just added a udquot to the freelist, then we want to release
index 57aa4b03720cb7440acef44a920d18f81955ba72..e838d84b4e85697917c8623418c06ae28140a8b7 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
@@ -43,14 +44,15 @@ static inline struct xfs_dq_logitem *DQUOT_ITEM(struct xfs_log_item *lip)
 /*
  * returns the number of iovecs needed to log the given dquot item.
  */
-STATIC uint
+STATIC void
 xfs_qm_dquot_logitem_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
-       /*
-        * we need only two iovecs, one for the format, one for the real thing
-        */
-       return 2;
+       *nvecs += 2;
+       *nbytes += sizeof(struct xfs_dq_logformat) +
+                  sizeof(struct xfs_disk_dquot);
 }
 
 /*
@@ -140,7 +142,8 @@ xfs_qm_dqunpin_wait(
 STATIC uint
 xfs_qm_dquot_logitem_push(
        struct xfs_log_item     *lip,
-       struct list_head        *buffer_list)
+       struct list_head        *buffer_list) __releases(&lip->li_ailp->xa_lock)
+                                             __acquires(&lip->li_ailp->xa_lock)
 {
        struct xfs_dquot        *dqp = DQUOT_ITEM(lip)->qli_dquot;
        struct xfs_buf          *bp = NULL;
@@ -285,11 +288,14 @@ static inline struct xfs_qoff_logitem *QOFF_ITEM(struct xfs_log_item *lip)
  * We only need 1 iovec for an quotaoff item.  It just logs the
  * quotaoff_log_format structure.
  */
-STATIC uint
+STATIC void
 xfs_qm_qoff_logitem_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
-       return 1;
+       *nvecs += 1;
+       *nbytes += sizeof(struct xfs_qoff_logitem);
 }
 
 /*
index 35d3f5b041ddc0977f47981cb88991edee857245..1123d93ff79546efe3a9d962460ab1e44e2e1bac 100644 (file)
@@ -26,7 +26,6 @@
 #include "xfs_bmap_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_utils.h"
 #include "xfs_error.h"
 
 #ifdef DEBUG
index c585bc646395e04c5497621eeb4ec34bd1f262e7..066df425c14ffca5b4dacb20f7b3c6fcdd139acb 100644 (file)
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_export.h"
-#include "xfs_vnodeops.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
index 85e9f87a1a7ce7945da58e305a21818262542cfa..e43708e2f0806d4daae241ee32e18abcac1a017f 100644 (file)
@@ -147,7 +147,7 @@ xfs_extent_busy_search(
  * extent.  If the overlap covers the beginning, the end, or all of the busy
  * extent, the overlapping portion can be made unbusy and used for the
  * allocation.  We can't split a busy extent because we can't modify a
- * transaction/CIL context busy list, but we can update an entries block
+ * transaction/CIL context busy list, but we can update an entry's block
  * number or length.
  *
  * Returns true if the extent can safely be reused, or false if the search
@@ -160,7 +160,8 @@ xfs_extent_busy_update_extent(
        struct xfs_extent_busy  *busyp,
        xfs_agblock_t           fbno,
        xfs_extlen_t            flen,
-       bool                    userdata)
+       bool                    userdata) __releases(&pag->pagb_lock)
+                                         __acquires(&pag->pagb_lock)
 {
        xfs_agblock_t           fend = fbno + flen;
        xfs_agblock_t           bbno = busyp->bno;
index 452920a3f03fb2e4405ce52e34587e55acfb7abe..dc53e8febbbeaa54812b4e72dc25938718da69c1 100644 (file)
@@ -73,11 +73,22 @@ __xfs_efi_release(
  * We only need 1 iovec for an efi item.  It just logs the efi_log_format
  * structure.
  */
-STATIC uint
+static inline int
+xfs_efi_item_sizeof(
+       struct xfs_efi_log_item *efip)
+{
+       return sizeof(struct xfs_efi_log_format) +
+              (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t);
+}
+
+STATIC void
 xfs_efi_item_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
-       return 1;
+       *nvecs += 1;
+       *nbytes += xfs_efi_item_sizeof(EFI_ITEM(lip));
 }
 
 /*
@@ -93,21 +104,17 @@ xfs_efi_item_format(
        struct xfs_log_iovec    *log_vector)
 {
        struct xfs_efi_log_item *efip = EFI_ITEM(lip);
-       uint                    size;
 
        ASSERT(atomic_read(&efip->efi_next_extent) ==
                                efip->efi_format.efi_nextents);
 
        efip->efi_format.efi_type = XFS_LI_EFI;
-
-       size = sizeof(xfs_efi_log_format_t);
-       size += (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t);
        efip->efi_format.efi_size = 1;
 
        log_vector->i_addr = &efip->efi_format;
-       log_vector->i_len = size;
+       log_vector->i_len = xfs_efi_item_sizeof(efip);
        log_vector->i_type = XLOG_REG_TYPE_EFI_FORMAT;
-       ASSERT(size >= sizeof(xfs_efi_log_format_t));
+       ASSERT(log_vector->i_len >= sizeof(xfs_efi_log_format_t));
 }
 
 
@@ -333,11 +340,22 @@ xfs_efd_item_free(struct xfs_efd_log_item *efdp)
  * We only need 1 iovec for an efd item.  It just logs the efd_log_format
  * structure.
  */
-STATIC uint
+static inline int
+xfs_efd_item_sizeof(
+       struct xfs_efd_log_item *efdp)
+{
+       return sizeof(xfs_efd_log_format_t) +
+              (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t);
+}
+
+STATIC void
 xfs_efd_item_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
-       return 1;
+       *nvecs += 1;
+       *nbytes += xfs_efd_item_sizeof(EFD_ITEM(lip));
 }
 
 /*
@@ -353,20 +371,16 @@ xfs_efd_item_format(
        struct xfs_log_iovec    *log_vector)
 {
        struct xfs_efd_log_item *efdp = EFD_ITEM(lip);
-       uint                    size;
 
        ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents);
 
        efdp->efd_format.efd_type = XFS_LI_EFD;
-
-       size = sizeof(xfs_efd_log_format_t);
-       size += (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t);
        efdp->efd_format.efd_size = 1;
 
        log_vector->i_addr = &efdp->efd_format;
-       log_vector->i_len = size;
+       log_vector->i_len = xfs_efd_item_sizeof(efdp);
        log_vector->i_type = XLOG_REG_TYPE_EFD_FORMAT;
-       ASSERT(size >= sizeof(xfs_efd_log_format_t));
+       ASSERT(log_vector->i_len >= sizeof(xfs_efd_log_format_t));
 }
 
 /*
index 432222418c566f6d7f30bed9951289ea9c5f1d10..0ffbce32d5693e05e042de8983c8274942616196 100644 (file)
 #ifndef        __XFS_EXTFREE_ITEM_H__
 #define        __XFS_EXTFREE_ITEM_H__
 
+/* kernel only EFI/EFD definitions */
+
 struct xfs_mount;
 struct kmem_zone;
 
-typedef struct xfs_extent {
-       xfs_dfsbno_t    ext_start;
-       xfs_extlen_t    ext_len;
-} xfs_extent_t;
-
-/*
- * Since an xfs_extent_t has types (start:64, len: 32)
- * there are different alignments on 32 bit and 64 bit kernels.
- * So we provide the different variants for use by a
- * conversion routine.
- */
-
-typedef struct xfs_extent_32 {
-       __uint64_t      ext_start;
-       __uint32_t      ext_len;
-} __attribute__((packed)) xfs_extent_32_t;
-
-typedef struct xfs_extent_64 {
-       __uint64_t      ext_start;
-       __uint32_t      ext_len;
-       __uint32_t      ext_pad;
-} xfs_extent_64_t;
-
-/*
- * This is the structure used to lay out an efi log item in the
- * log.  The efi_extents field is a variable size array whose
- * size is given by efi_nextents.
- */
-typedef struct xfs_efi_log_format {
-       __uint16_t              efi_type;       /* efi log item type */
-       __uint16_t              efi_size;       /* size of this item */
-       __uint32_t              efi_nextents;   /* # extents to free */
-       __uint64_t              efi_id;         /* efi identifier */
-       xfs_extent_t            efi_extents[1]; /* array of extents to free */
-} xfs_efi_log_format_t;
-
-typedef struct xfs_efi_log_format_32 {
-       __uint16_t              efi_type;       /* efi log item type */
-       __uint16_t              efi_size;       /* size of this item */
-       __uint32_t              efi_nextents;   /* # extents to free */
-       __uint64_t              efi_id;         /* efi identifier */
-       xfs_extent_32_t         efi_extents[1]; /* array of extents to free */
-} __attribute__((packed)) xfs_efi_log_format_32_t;
-
-typedef struct xfs_efi_log_format_64 {
-       __uint16_t              efi_type;       /* efi log item type */
-       __uint16_t              efi_size;       /* size of this item */
-       __uint32_t              efi_nextents;   /* # extents to free */
-       __uint64_t              efi_id;         /* efi identifier */
-       xfs_extent_64_t         efi_extents[1]; /* array of extents to free */
-} xfs_efi_log_format_64_t;
-
-/*
- * This is the structure used to lay out an efd log item in the
- * log.  The efd_extents array is a variable size array whose
- * size is given by efd_nextents;
- */
-typedef struct xfs_efd_log_format {
-       __uint16_t              efd_type;       /* efd log item type */
-       __uint16_t              efd_size;       /* size of this item */
-       __uint32_t              efd_nextents;   /* # of extents freed */
-       __uint64_t              efd_efi_id;     /* id of corresponding efi */
-       xfs_extent_t            efd_extents[1]; /* array of extents freed */
-} xfs_efd_log_format_t;
-
-typedef struct xfs_efd_log_format_32 {
-       __uint16_t              efd_type;       /* efd log item type */
-       __uint16_t              efd_size;       /* size of this item */
-       __uint32_t              efd_nextents;   /* # of extents freed */
-       __uint64_t              efd_efi_id;     /* id of corresponding efi */
-       xfs_extent_32_t         efd_extents[1]; /* array of extents freed */
-} __attribute__((packed)) xfs_efd_log_format_32_t;
-
-typedef struct xfs_efd_log_format_64 {
-       __uint16_t              efd_type;       /* efd log item type */
-       __uint16_t              efd_size;       /* size of this item */
-       __uint32_t              efd_nextents;   /* # of extents freed */
-       __uint64_t              efd_efi_id;     /* id of corresponding efi */
-       xfs_extent_64_t         efd_extents[1]; /* array of extents freed */
-} xfs_efd_log_format_64_t;
-
-
-#ifdef __KERNEL__
-
 /*
  * Max number of extents in fast allocation path.
  */
@@ -160,6 +78,4 @@ int                  xfs_efi_copy_format(xfs_log_iovec_t *buf,
                                            xfs_efi_log_format_t *dst_efi_fmt);
 void                   xfs_efi_item_free(xfs_efi_log_item_t *);
 
-#endif /* __KERNEL__ */
-
 #endif /* __XFS_EXTFREE_ITEM_H__ */
index de3dc98f4e8f76067c1e7d0ee4631a8638d87988..4c749ab543d0de17646993a282f925ebd0314ccf 100644 (file)
 #include "xfs_inode.h"
 #include "xfs_inode_item.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_error.h"
-#include "xfs_vnodeops.h"
 #include "xfs_da_btree.h"
 #include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_dir2_priv.h"
 #include "xfs_ioctl.h"
 #include "xfs_trace.h"
index 5170306a1009e22e287c425b1968d97b7a885a82..ce78e654d37b73693aa4c637e021dda9154ad5d6 100644 (file)
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "xfs.h"
+#include "xfs_log.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inum.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_ag.h"
-#include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_mount.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_alloc.h"
-#include "xfs_utils.h"
 #include "xfs_mru_cache.h"
 #include "xfs_filestream.h"
 #include "xfs_trace.h"
@@ -668,8 +668,8 @@ exit:
  */
 int
 xfs_filestream_new_ag(
-       xfs_bmalloca_t  *ap,
-       xfs_agnumber_t  *agp)
+       struct xfs_bmalloca     *ap,
+       xfs_agnumber_t          *agp)
 {
        int             flags, err;
        xfs_inode_t     *ip, *pip = NULL;
index 09dd9af454349b57fe2a8a7bec0f3c5c3c7e4e3e..6d61dbee8564b12cca254721bf78685975799a74 100644 (file)
@@ -18,8 +18,6 @@
 #ifndef __XFS_FILESTREAM_H__
 #define __XFS_FILESTREAM_H__
 
-#ifdef __KERNEL__
-
 struct xfs_mount;
 struct xfs_inode;
 struct xfs_perag;
@@ -69,6 +67,4 @@ xfs_inode_is_filestream(
                (ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM);
 }
 
-#endif /* __KERNEL__ */
-
 #endif /* __XFS_FILESTREAM_H__ */
diff --git a/fs/xfs/xfs_format.h b/fs/xfs/xfs_format.h
new file mode 100644 (file)
index 0000000..35c08ff
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, 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
+ */
+#ifndef __XFS_FORMAT_H__
+#define __XFS_FORMAT_H__
+
+/*
+ * XFS On Disk Format Definitions
+ *
+ * This header file defines all the on-disk format definitions for 
+ * general XFS objects. Directory and attribute related objects are defined in
+ * xfs_da_format.h, which log and log item formats are defined in
+ * xfs_log_format.h. Everything else goes here.
+ */
+
+struct xfs_mount;
+struct xfs_trans;
+struct xfs_inode;
+struct xfs_buf;
+struct xfs_ifork;
+
+/*
+ * RealTime Device format definitions
+ */
+
+/* Min and max rt extent sizes, specified in bytes */
+#define        XFS_MAX_RTEXTSIZE       (1024 * 1024 * 1024)    /* 1GB */
+#define        XFS_DFL_RTEXTSIZE       (64 * 1024)             /* 64kB */
+#define        XFS_MIN_RTEXTSIZE       (4 * 1024)              /* 4kB */
+
+#define        XFS_BLOCKSIZE(mp)       ((mp)->m_sb.sb_blocksize)
+#define        XFS_BLOCKMASK(mp)       ((mp)->m_blockmask)
+#define        XFS_BLOCKWSIZE(mp)      ((mp)->m_blockwsize)
+#define        XFS_BLOCKWMASK(mp)      ((mp)->m_blockwmask)
+
+/*
+ * RT Summary and bit manipulation macros.
+ */
+#define        XFS_SUMOFFS(mp,ls,bb)   ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb)))
+#define        XFS_SUMOFFSTOBLOCK(mp,s)        \
+       (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog)
+#define        XFS_SUMPTR(mp,bp,so)    \
+       ((xfs_suminfo_t *)((bp)->b_addr + \
+               (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp))))
+
+#define        XFS_BITTOBLOCK(mp,bi)   ((bi) >> (mp)->m_blkbit_log)
+#define        XFS_BLOCKTOBIT(mp,bb)   ((bb) << (mp)->m_blkbit_log)
+#define        XFS_BITTOWORD(mp,bi)    \
+       ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp)))
+
+#define        XFS_RTMIN(a,b)  ((a) < (b) ? (a) : (b))
+#define        XFS_RTMAX(a,b)  ((a) > (b) ? (a) : (b))
+
+#define        XFS_RTLOBIT(w)  xfs_lowbit32(w)
+#define        XFS_RTHIBIT(w)  xfs_highbit32(w)
+
+#if XFS_BIG_BLKNOS
+#define        XFS_RTBLOCKLOG(b)       xfs_highbit64(b)
+#else
+#define        XFS_RTBLOCKLOG(b)       xfs_highbit32(b)
+#endif
+
+/*
+ * Dquot and dquot block format definitions
+ */
+#define XFS_DQUOT_MAGIC                0x4451          /* 'DQ' */
+#define XFS_DQUOT_VERSION      (u_int8_t)0x01  /* latest version number */
+
+/*
+ * This is the main portion of the on-disk representation of quota
+ * information for a user. This is the q_core of the xfs_dquot_t that
+ * is kept in kernel memory. We pad this with some more expansion room
+ * to construct the on disk structure.
+ */
+typedef struct xfs_disk_dquot {
+       __be16          d_magic;        /* dquot magic = XFS_DQUOT_MAGIC */
+       __u8            d_version;      /* dquot version */
+       __u8            d_flags;        /* XFS_DQ_USER/PROJ/GROUP */
+       __be32          d_id;           /* user,project,group id */
+       __be64          d_blk_hardlimit;/* absolute limit on disk blks */
+       __be64          d_blk_softlimit;/* preferred limit on disk blks */
+       __be64          d_ino_hardlimit;/* maximum # allocated inodes */
+       __be64          d_ino_softlimit;/* preferred inode limit */
+       __be64          d_bcount;       /* disk blocks owned by the user */
+       __be64          d_icount;       /* inodes owned by the user */
+       __be32          d_itimer;       /* zero if within inode limits if not,
+                                          this is when we refuse service */
+       __be32          d_btimer;       /* similar to above; for disk blocks */
+       __be16          d_iwarns;       /* warnings issued wrt num inodes */
+       __be16          d_bwarns;       /* warnings issued wrt disk blocks */
+       __be32          d_pad0;         /* 64 bit align */
+       __be64          d_rtb_hardlimit;/* absolute limit on realtime blks */
+       __be64          d_rtb_softlimit;/* preferred limit on RT disk blks */
+       __be64          d_rtbcount;     /* realtime blocks owned */
+       __be32          d_rtbtimer;     /* similar to above; for RT disk blocks */
+       __be16          d_rtbwarns;     /* warnings issued wrt RT disk blocks */
+       __be16          d_pad;
+} xfs_disk_dquot_t;
+
+/*
+ * This is what goes on disk. This is separated from the xfs_disk_dquot because
+ * carrying the unnecessary padding would be a waste of memory.
+ */
+typedef struct xfs_dqblk {
+       xfs_disk_dquot_t  dd_diskdq;    /* portion that lives incore as well */
+       char              dd_fill[4];   /* filling for posterity */
+
+       /*
+        * These two are only present on filesystems with the CRC bits set.
+        */
+       __be32            dd_crc;       /* checksum */
+       __be64            dd_lsn;       /* last modification in log */
+       uuid_t            dd_uuid;      /* location information */
+} xfs_dqblk_t;
+
+#define XFS_DQUOT_CRC_OFF      offsetof(struct xfs_dqblk, dd_crc)
+
+/*
+ * Remote symlink format and access functions.
+ */
+#define XFS_SYMLINK_MAGIC      0x58534c4d      /* XSLM */
+
+struct xfs_dsymlink_hdr {
+       __be32  sl_magic;
+       __be32  sl_offset;
+       __be32  sl_bytes;
+       __be32  sl_crc;
+       uuid_t  sl_uuid;
+       __be64  sl_owner;
+       __be64  sl_blkno;
+       __be64  sl_lsn;
+};
+
+/*
+ * The maximum pathlen is 1024 bytes. Since the minimum file system
+ * blocksize is 512 bytes, we can get a max of 3 extents back from
+ * bmapi when crc headers are taken into account.
+ */
+#define XFS_SYMLINK_MAPS 3
+
+#define XFS_SYMLINK_BUF_SPACE(mp, bufsize)     \
+       ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
+                       sizeof(struct xfs_dsymlink_hdr) : 0))
+
+int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
+int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
+                       uint32_t size, struct xfs_buf *bp);
+bool xfs_symlink_hdr_ok(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset,
+                       uint32_t size, struct xfs_buf *bp);
+void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
+                                struct xfs_inode *ip, struct xfs_ifork *ifp);
+
+extern const struct xfs_buf_ops xfs_symlink_buf_ops;
+
+#endif /* __XFS_FORMAT_H__ */
index d04695545397308a6596f5109a72f8923fd79419..1edb5cc3e5f495fdca3059054d1f2e7bd5d9fd58 100644 (file)
@@ -240,7 +240,9 @@ typedef struct xfs_fsop_resblks {
 
 
 /*
- * Minimum and maximum sizes need for growth checks
+ * Minimum and maximum sizes need for growth checks.
+ *
+ * Block counts are in units of filesystem blocks, not basic blocks.
  */
 #define XFS_MIN_AG_BLOCKS      64
 #define XFS_MIN_LOG_BLOCKS     512ULL
@@ -310,6 +312,17 @@ typedef struct xfs_bstat {
        __u16           bs_aextents;    /* attribute number of extents  */
 } xfs_bstat_t;
 
+/*
+ * Project quota id helpers (previously projid was 16bit only
+ * and using two 16bit values to hold new 32bit projid was choosen
+ * to retain compatibility with "old" filesystems).
+ */
+static inline __uint32_t
+bstat_get_projid(struct xfs_bstat *bs)
+{
+       return (__uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo;
+}
+
 /*
  * The user-level BulkStat Request interface structure.
  */
@@ -344,7 +357,7 @@ typedef struct xfs_error_injection {
  * Speculative preallocation trimming.
  */
 #define XFS_EOFBLOCKS_VERSION          1
-struct xfs_eofblocks {
+struct xfs_fs_eofblocks {
        __u32           eof_version;
        __u32           eof_flags;
        uid_t           eof_uid;
@@ -449,6 +462,21 @@ typedef struct xfs_handle {
                                 - (char *) &(handle))                    \
                                 + (handle).ha_fid.fid_len)
 
+/*
+ * Structure passed to XFS_IOC_SWAPEXT
+ */
+typedef struct xfs_swapext
+{
+       __int64_t       sx_version;     /* version */
+#define XFS_SX_VERSION         0
+       __int64_t       sx_fdtarget;    /* fd of target file */
+       __int64_t       sx_fdtmp;       /* fd of tmp file */
+       xfs_off_t       sx_offset;      /* offset into file */
+       xfs_off_t       sx_length;      /* leng from offset */
+       char            sx_pad[16];     /* pad space, unused */
+       xfs_bstat_t     sx_stat;        /* stat of target b4 copy */
+} xfs_swapext_t;
+
 /*
  * Flags for going down operation
  */
@@ -511,8 +539,14 @@ typedef struct xfs_handle {
 #define XFS_IOC_ERROR_INJECTION             _IOW ('X', 116, struct xfs_error_injection)
 #define XFS_IOC_ERROR_CLEARALL      _IOW ('X', 117, struct xfs_error_injection)
 /*     XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118      */
+
 /*     XFS_IOC_FREEZE            -- FIFREEZE   119      */
 /*     XFS_IOC_THAW              -- FITHAW     120      */
+#ifndef FIFREEZE
+#define XFS_IOC_FREEZE              _IOWR('X', 119, int)
+#define XFS_IOC_THAW                _IOWR('X', 120, int)
+#endif
+
 #define XFS_IOC_FSSETDM_BY_HANDLE    _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
 #define XFS_IOC_ATTRLIST_BY_HANDLE   _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
 #define XFS_IOC_ATTRMULTI_BY_HANDLE  _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
index 614eb0cc360860214ce08443ff84993afa531143..e64ee5288b86be2d0c0267b383d3f6f9297e60a1 100644 (file)
@@ -203,8 +203,9 @@ xfs_growfs_data_private(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFS);
        tp->t_flags |= XFS_TRANS_RESERVE;
-       if ((error = xfs_trans_reserve(tp, XFS_GROWFS_SPACE_RES(mp),
-                       XFS_GROWDATA_LOG_RES(mp), 0, 0, 0))) {
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growdata,
+                                 XFS_GROWFS_SPACE_RES(mp), 0);
+       if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
        }
@@ -739,8 +740,7 @@ xfs_fs_log_dummy(
        int             error;
 
        tp = _xfs_trans_alloc(mp, XFS_TRANS_DUMMY1, KM_SLEEP);
-       error = xfs_trans_reserve(tp, 0, XFS_SB_LOG_RES(mp), 0, 0,
-                                 XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
index 7a0c17d7ec0974354cfd645695e9f4f7778704fa..ccf2fb1439629fae273a239625f97f6879192878 100644 (file)
@@ -39,6 +39,7 @@
 #include "xfs_cksum.h"
 #include "xfs_buf_item.h"
 #include "xfs_icreate_item.h"
+#include "xfs_icache.h"
 
 
 /*
@@ -506,7 +507,7 @@ xfs_ialloc_next_ag(
 
 /*
  * Select an allocation group to look for a free inode in, based on the parent
- * inode and then mode.  Return the allocation group buffer.
+ * inode and the mode.  Return the allocation group buffer.
  */
 STATIC xfs_agnumber_t
 xfs_ialloc_ag_select(
@@ -728,7 +729,7 @@ xfs_dialloc_ag(
                error = xfs_inobt_get_rec(cur, &rec, &j);
                if (error)
                        goto error0;
-               XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
+               XFS_WANT_CORRUPTED_GOTO(j == 1, error0);
 
                if (rec.ir_freecount > 0) {
                        /*
@@ -1341,7 +1342,7 @@ xfs_imap(
        xfs_agblock_t   cluster_agbno;  /* first block in inode cluster */
        int             error;  /* error code */
        int             offset; /* index of inode in its buffer */
-       int             offset_agbno;   /* blks from chunk start to inode */
+       xfs_agblock_t   offset_agbno;   /* blks from chunk start to inode */
 
        ASSERT(ino != NULLFSINO);
 
index 3f90e1ceb8d68c4655bb033da592f495b91e9772..193206ba43582c0aecbea7afd1d23220bfff554f 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_types.h"
 #include "xfs_log.h"
 #include "xfs_log_priv.h"
 #include "xfs_dinode.h"
 #include "xfs_error.h"
 #include "xfs_filestream.h"
-#include "xfs_vnodeops.h"
 #include "xfs_inode_item.h"
 #include "xfs_quota.h"
 #include "xfs_trace.h"
 #include "xfs_fsops.h"
 #include "xfs_icache.h"
+#include "xfs_bmap_util.h"
 
 #include <linux/kthread.h>
 #include <linux/freezer.h>
@@ -47,7 +48,7 @@ STATIC void __xfs_inode_clear_reclaim_tag(struct xfs_mount *mp,
 /*
  * Allocate and initialise an xfs_inode.
  */
-STATIC struct xfs_inode *
+struct xfs_inode *
 xfs_inode_alloc(
        struct xfs_mount        *mp,
        xfs_ino_t               ino)
@@ -97,7 +98,7 @@ xfs_inode_free_callback(
        kmem_zone_free(xfs_inode_zone, ip);
 }
 
-STATIC void
+void
 xfs_inode_free(
        struct xfs_inode        *ip)
 {
@@ -619,7 +620,7 @@ restart:
 
 /*
  * Background scanning to trim post-EOF preallocated space. This is queued
- * based on the 'background_prealloc_discard_period' tunable (5m by default).
+ * based on the 'speculative_prealloc_lifetime' tunable (5m by default).
  */
 STATIC void
 xfs_queue_eofblocks(
@@ -1166,7 +1167,7 @@ xfs_reclaim_inodes(
  * them to be cleaned, which we hope will not be very long due to the
  * background walker having already kicked the IO off on those dirty inodes.
  */
-void
+long
 xfs_reclaim_inodes_nr(
        struct xfs_mount        *mp,
        int                     nr_to_scan)
@@ -1175,7 +1176,7 @@ xfs_reclaim_inodes_nr(
        xfs_reclaim_work_queue(mp);
        xfs_ail_push_all(mp->m_ail);
 
-       xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan);
+       return xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan);
 }
 
 /*
@@ -1203,15 +1204,15 @@ xfs_inode_match_id(
        struct xfs_inode        *ip,
        struct xfs_eofblocks    *eofb)
 {
-       if (eofb->eof_flags & XFS_EOF_FLAGS_UID &&
-           ip->i_d.di_uid != eofb->eof_uid)
+       if ((eofb->eof_flags & XFS_EOF_FLAGS_UID) &&
+           !uid_eq(VFS_I(ip)->i_uid, eofb->eof_uid))
                return 0;
 
-       if (eofb->eof_flags & XFS_EOF_FLAGS_GID &&
-           ip->i_d.di_gid != eofb->eof_gid)
+       if ((eofb->eof_flags & XFS_EOF_FLAGS_GID) &&
+           !gid_eq(VFS_I(ip)->i_gid, eofb->eof_gid))
                return 0;
 
-       if (eofb->eof_flags & XFS_EOF_FLAGS_PRID &&
+       if ((eofb->eof_flags & XFS_EOF_FLAGS_PRID) &&
            xfs_get_projid(ip) != eofb->eof_prid)
                return 0;
 
index a01afbb3909a465a6e94f23bdc819530a3f22140..9ed68bb750f50871a1ba17a4a67e24a8b4d4829b 100644 (file)
 struct xfs_mount;
 struct xfs_perag;
 
+struct xfs_eofblocks {
+       __u32           eof_flags;
+       kuid_t          eof_uid;
+       kgid_t          eof_gid;
+       prid_t          eof_prid;
+       __u64           eof_min_file_size;
+};
+
 #define SYNC_WAIT              0x0001  /* wait for i/o to complete */
 #define SYNC_TRYLOCK           0x0002  /* only try to lock inodes */
 
+/*
+ * Flags for xfs_iget()
+ */
+#define XFS_IGET_CREATE                0x1
+#define XFS_IGET_UNTRUSTED     0x2
+#define XFS_IGET_DONTCACHE     0x4
+
 int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino,
             uint flags, uint lock_flags, xfs_inode_t **ipp);
 
+/* recovery needs direct inode allocation capability */
+struct xfs_inode * xfs_inode_alloc(struct xfs_mount *mp, xfs_ino_t ino);
+void xfs_inode_free(struct xfs_inode *ip);
+
 void xfs_reclaim_worker(struct work_struct *work);
 
 int xfs_reclaim_inodes(struct xfs_mount *mp, int mode);
 int xfs_reclaim_inodes_count(struct xfs_mount *mp);
-void xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
+long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan);
 
 void xfs_inode_set_reclaim_tag(struct xfs_inode *ip);
 
@@ -49,4 +68,39 @@ int xfs_inode_ag_iterator_tag(struct xfs_mount *mp,
                int flags, void *args),
        int flags, void *args, int tag);
 
+static inline int
+xfs_fs_eofblocks_from_user(
+       struct xfs_fs_eofblocks         *src,
+       struct xfs_eofblocks            *dst)
+{
+       if (src->eof_version != XFS_EOFBLOCKS_VERSION)
+               return EINVAL;
+
+       if (src->eof_flags & ~XFS_EOF_FLAGS_VALID)
+               return EINVAL;
+
+       if (memchr_inv(&src->pad32, 0, sizeof(src->pad32)) ||
+           memchr_inv(src->pad64, 0, sizeof(src->pad64)))
+               return EINVAL;
+
+       dst->eof_flags = src->eof_flags;
+       dst->eof_prid = src->eof_prid;
+       dst->eof_min_file_size = src->eof_min_file_size;
+
+       dst->eof_uid = INVALID_UID;
+       if (src->eof_flags & XFS_EOF_FLAGS_UID) {
+               dst->eof_uid = make_kuid(current_user_ns(), src->eof_uid);
+               if (!uid_valid(dst->eof_uid))
+                       return EINVAL;
+       }
+
+       dst->eof_gid = INVALID_GID;
+       if (src->eof_flags & XFS_EOF_FLAGS_GID) {
+               dst->eof_gid = make_kgid(current_user_ns(), src->eof_gid);
+               if (!gid_valid(dst->eof_gid))
+                       return EINVAL;
+       }
+       return 0;
+}
+
 #endif
index 7716a4e7375e296e926ef402f8687169dcc295c3..5a5a593994d4196d3b18c2e959df90dc28c7588f 100644 (file)
 #include "xfs_types.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
-#include "xfs_inum.h"
 #include "xfs_trans.h"
-#include "xfs_buf_item.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_mount.h"
 #include "xfs_trans_priv.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_alloc_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_attr_sf.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_btree.h"
-#include "xfs_ialloc.h"
 #include "xfs_error.h"
 #include "xfs_icreate_item.h"
 
@@ -52,11 +40,14 @@ static inline struct xfs_icreate_item *ICR_ITEM(struct xfs_log_item *lip)
  *
  * We only need one iovec for the icreate log structure.
  */
-STATIC uint
+STATIC void
 xfs_icreate_item_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
-       return 1;
+       *nvecs += 1;
+       *nbytes += sizeof(struct xfs_icreate_log);
 }
 
 /*
index 88ba8aa0bc41c0f3aa291da6b621dfea7445f56b..59e89f87c09b3fb8483326a30a9fcb879a4c4665 100644 (file)
 #ifndef XFS_ICREATE_ITEM_H
 #define XFS_ICREATE_ITEM_H     1
 
-/*
- * on disk log item structure
- *
- * Log recovery assumes the first two entries are the type and size and they fit
- * in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so
- * decoding can be done correctly.
- */
-struct xfs_icreate_log {
-       __uint16_t      icl_type;       /* type of log format structure */
-       __uint16_t      icl_size;       /* size of log format structure */
-       __be32          icl_ag;         /* ag being allocated in */
-       __be32          icl_agbno;      /* start block of inode range */
-       __be32          icl_count;      /* number of inodes to initialise */
-       __be32          icl_isize;      /* size of inodes */
-       __be32          icl_length;     /* length of extent to initialise */
-       __be32          icl_gen;        /* inode generation number to use */
-};
-
 /* in memory log item structure */
 struct xfs_icreate_item {
        struct xfs_log_item     ic_item;
index bb262c25c8de463276e9282d64b299c975eceb7b..e3d75385aa76a6e45b7711a65bb39c268c9f689b 100644 (file)
 
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
 #include "xfs_trans.h"
+#include "xfs_trans_space.h"
 #include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_attr_sf.h"
+#include "xfs_attr.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_buf_item.h"
 #include "xfs_alloc.h"
 #include "xfs_ialloc.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_error.h"
-#include "xfs_utils.h"
 #include "xfs_quota.h"
 #include "xfs_filestream.h"
-#include "xfs_vnodeops.h"
 #include "xfs_cksum.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
+#include "xfs_symlink.h"
 
-kmem_zone_t *xfs_ifork_zone;
 kmem_zone_t *xfs_inode_zone;
 
 /*
@@ -58,9 +62,6 @@ kmem_zone_t *xfs_inode_zone;
 #define        XFS_ITRUNC_MAX_EXTENTS  2
 
 STATIC int xfs_iflush_int(xfs_inode_t *, xfs_buf_t *);
-STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);
-STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);
-STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
 
 /*
  * helper function to extract extent size hint from inode
@@ -310,623 +311,202 @@ xfs_isilocked(
 }
 #endif
 
-void
-__xfs_iflock(
-       struct xfs_inode        *ip)
-{
-       wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT);
-       DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT);
-
-       do {
-               prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
-               if (xfs_isiflocked(ip))
-                       io_schedule();
-       } while (!xfs_iflock_nowait(ip));
-
-       finish_wait(wq, &wait.wait);
-}
-
 #ifdef DEBUG
+int xfs_locked_n;
+int xfs_small_retries;
+int xfs_middle_retries;
+int xfs_lots_retries;
+int xfs_lock_delays;
+#endif
+
 /*
- * Make sure that the extents in the given memory buffer
- * are valid.
+ * Bump the subclass so xfs_lock_inodes() acquires each lock with
+ * a different value
  */
-STATIC void
-xfs_validate_extents(
-       xfs_ifork_t             *ifp,
-       int                     nrecs,
-       xfs_exntfmt_t           fmt)
+static inline int
+xfs_lock_inumorder(int lock_mode, int subclass)
 {
-       xfs_bmbt_irec_t         irec;
-       xfs_bmbt_rec_host_t     rec;
-       int                     i;
+       if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+               lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
+       if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
+               lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;
 
-       for (i = 0; i < nrecs; i++) {
-               xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
-               rec.l0 = get_unaligned(&ep->l0);
-               rec.l1 = get_unaligned(&ep->l1);
-               xfs_bmbt_get_all(&rec, &irec);
-               if (fmt == XFS_EXTFMT_NOSTATE)
-                       ASSERT(irec.br_state == XFS_EXT_NORM);
-       }
+       return lock_mode;
 }
-#else /* DEBUG */
-#define xfs_validate_extents(ifp, nrecs, fmt)
-#endif /* DEBUG */
 
 /*
- * Check that none of the inode's in the buffer have a next
- * unlinked field of 0.
+ * The following routine will lock n inodes in exclusive mode.
+ * We assume the caller calls us with the inodes in i_ino order.
+ *
+ * We need to detect deadlock where an inode that we lock
+ * is in the AIL and we start waiting for another inode that is locked
+ * by a thread in a long running transaction (such as truncate). This can
+ * result in deadlock since the long running trans might need to wait
+ * for the inode we just locked in order to push the tail and free space
+ * in the log.
  */
-#if defined(DEBUG)
 void
-xfs_inobp_check(
-       xfs_mount_t     *mp,
-       xfs_buf_t       *bp)
-{
-       int             i;
-       int             j;
-       xfs_dinode_t    *dip;
-
-       j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
-
-       for (i = 0; i < j; i++) {
-               dip = (xfs_dinode_t *)xfs_buf_offset(bp,
-                                       i * mp->m_sb.sb_inodesize);
-               if (!dip->di_next_unlinked)  {
-                       xfs_alert(mp,
-       "Detected bogus zero next_unlinked field in incore inode buffer 0x%p.",
-                               bp);
-                       ASSERT(dip->di_next_unlinked);
-               }
-       }
-}
-#endif
-
-static void
-xfs_inode_buf_verify(
-       struct xfs_buf  *bp)
+xfs_lock_inodes(
+       xfs_inode_t     **ips,
+       int             inodes,
+       uint            lock_mode)
 {
-       struct xfs_mount *mp = bp->b_target->bt_mount;
-       int             i;
-       int             ni;
-
-       /*
-        * Validate the magic number and version of every inode in the buffer
-        */
-       ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;
-       for (i = 0; i < ni; i++) {
-               int             di_ok;
-               xfs_dinode_t    *dip;
-
-               dip = (struct xfs_dinode *)xfs_buf_offset(bp,
-                                       (i << mp->m_sb.sb_inodelog));
-               di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
-                           XFS_DINODE_GOOD_VERSION(dip->di_version);
-               if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
-                                               XFS_ERRTAG_ITOBP_INOTOBP,
-                                               XFS_RANDOM_ITOBP_INOTOBP))) {
-                       xfs_buf_ioerror(bp, EFSCORRUPTED);
-                       XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
-                                            mp, dip);
-#ifdef DEBUG
-                       xfs_emerg(mp,
-                               "bad inode magic/vsn daddr %lld #%d (magic=%x)",
-                               (unsigned long long)bp->b_bn, i,
-                               be16_to_cpu(dip->di_magic));
-                       ASSERT(0);
-#endif
-               }
-       }
-       xfs_inobp_check(mp, bp);
-}
+       int             attempts = 0, i, j, try_lock;
+       xfs_log_item_t  *lp;
 
+       ASSERT(ips && (inodes >= 2)); /* we need at least two */
 
-static void
-xfs_inode_buf_read_verify(
-       struct xfs_buf  *bp)
-{
-       xfs_inode_buf_verify(bp);
-}
-
-static void
-xfs_inode_buf_write_verify(
-       struct xfs_buf  *bp)
-{
-       xfs_inode_buf_verify(bp);
-}
+       try_lock = 0;
+       i = 0;
 
-const struct xfs_buf_ops xfs_inode_buf_ops = {
-       .verify_read = xfs_inode_buf_read_verify,
-       .verify_write = xfs_inode_buf_write_verify,
-};
+again:
+       for (; i < inodes; i++) {
+               ASSERT(ips[i]);
 
+               if (i && (ips[i] == ips[i-1]))  /* Already locked */
+                       continue;
 
-/*
- * This routine is called to map an inode to the buffer containing the on-disk
- * version of the inode.  It returns a pointer to the buffer containing the
- * on-disk inode in the bpp parameter, and in the dipp parameter it returns a
- * pointer to the on-disk inode within that buffer.
- *
- * If a non-zero error is returned, then the contents of bpp and dipp are
- * undefined.
- */
-int
-xfs_imap_to_bp(
-       struct xfs_mount        *mp,
-       struct xfs_trans        *tp,
-       struct xfs_imap         *imap,
-       struct xfs_dinode       **dipp,
-       struct xfs_buf          **bpp,
-       uint                    buf_flags,
-       uint                    iget_flags)
-{
-       struct xfs_buf          *bp;
-       int                     error;
+               /*
+                * If try_lock is not set yet, make sure all locked inodes
+                * are not in the AIL.
+                * If any are, set try_lock to be used later.
+                */
 
-       buf_flags |= XBF_UNMAPPED;
-       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
-                                  (int)imap->im_len, buf_flags, &bp,
-                                  &xfs_inode_buf_ops);
-       if (error) {
-               if (error == EAGAIN) {
-                       ASSERT(buf_flags & XBF_TRYLOCK);
-                       return error;
+               if (!try_lock) {
+                       for (j = (i - 1); j >= 0 && !try_lock; j--) {
+                               lp = (xfs_log_item_t *)ips[j]->i_itemp;
+                               if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
+                                       try_lock++;
+                               }
+                       }
                }
 
-               if (error == EFSCORRUPTED &&
-                   (iget_flags & XFS_IGET_UNTRUSTED))
-                       return XFS_ERROR(EINVAL);
-
-               xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.",
-                       __func__, error);
-               return error;
-       }
-
-       *bpp = bp;
-       *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);
-       return 0;
-}
-
-/*
- * Move inode type and inode format specific information from the
- * on-disk inode to the in-core inode.  For fifos, devs, and sockets
- * this means set if_rdev to the proper value.  For files, directories,
- * and symlinks this means to bring in the in-line data or extent
- * pointers.  For a file in B-tree format, only the root is immediately
- * brought in-core.  The rest will be in-lined in if_extents when it
- * is first referenced (see xfs_iread_extents()).
- */
-STATIC int
-xfs_iformat(
-       xfs_inode_t             *ip,
-       xfs_dinode_t            *dip)
-{
-       xfs_attr_shortform_t    *atp;
-       int                     size;
-       int                     error = 0;
-       xfs_fsize_t             di_size;
-
-       if (unlikely(be32_to_cpu(dip->di_nextents) +
-                    be16_to_cpu(dip->di_anextents) >
-                    be64_to_cpu(dip->di_nblocks))) {
-               xfs_warn(ip->i_mount,
-                       "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
-                       (unsigned long long)ip->i_ino,
-                       (int)(be32_to_cpu(dip->di_nextents) +
-                             be16_to_cpu(dip->di_anextents)),
-                       (unsigned long long)
-                               be64_to_cpu(dip->di_nblocks));
-               XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
-                                    ip->i_mount, dip);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
-               xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.",
-                       (unsigned long long)ip->i_ino,
-                       dip->di_forkoff);
-               XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
-                                    ip->i_mount, dip);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
-                    !ip->i_mount->m_rtdev_targp)) {
-               xfs_warn(ip->i_mount,
-                       "corrupt dinode %Lu, has realtime flag set.",
-                       ip->i_ino);
-               XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
-                                    XFS_ERRLEVEL_LOW, ip->i_mount, dip);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       switch (ip->i_d.di_mode & S_IFMT) {
-       case S_IFIFO:
-       case S_IFCHR:
-       case S_IFBLK:
-       case S_IFSOCK:
-               if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
-                       XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
-                                             ip->i_mount, dip);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
-               ip->i_d.di_size = 0;
-               ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
-               break;
+               /*
+                * If any of the previous locks we have locked is in the AIL,
+                * we must TRY to get the second and subsequent locks. If
+                * we can't get any, we must release all we have
+                * and try again.
+                */
 
-       case S_IFREG:
-       case S_IFLNK:
-       case S_IFDIR:
-               switch (dip->di_format) {
-               case XFS_DINODE_FMT_LOCAL:
+               if (try_lock) {
+                       /* try_lock must be 0 if i is 0. */
                        /*
-                        * no local regular files yet
+                        * try_lock means we have an inode locked
+                        * that is in the AIL.
                         */
-                       if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) {
-                               xfs_warn(ip->i_mount,
-                       "corrupt inode %Lu (local format for regular file).",
-                                       (unsigned long long) ip->i_ino);
-                               XFS_CORRUPTION_ERROR("xfs_iformat(4)",
-                                                    XFS_ERRLEVEL_LOW,
-                                                    ip->i_mount, dip);
-                               return XFS_ERROR(EFSCORRUPTED);
-                       }
+                       ASSERT(i != 0);
+                       if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
+                               attempts++;
+
+                               /*
+                                * Unlock all previous guys and try again.
+                                * xfs_iunlock will try to push the tail
+                                * if the inode is in the AIL.
+                                */
+
+                               for(j = i - 1; j >= 0; j--) {
+
+                                       /*
+                                        * Check to see if we've already
+                                        * unlocked this one.
+                                        * Not the first one going back,
+                                        * and the inode ptr is the same.
+                                        */
+                                       if ((j != (i - 1)) && ips[j] ==
+                                                               ips[j+1])
+                                               continue;
+
+                                       xfs_iunlock(ips[j], lock_mode);
+                               }
 
-                       di_size = be64_to_cpu(dip->di_size);
-                       if (unlikely(di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
-                               xfs_warn(ip->i_mount,
-                       "corrupt inode %Lu (bad size %Ld for local inode).",
-                                       (unsigned long long) ip->i_ino,
-                                       (long long) di_size);
-                               XFS_CORRUPTION_ERROR("xfs_iformat(5)",
-                                                    XFS_ERRLEVEL_LOW,
-                                                    ip->i_mount, dip);
-                               return XFS_ERROR(EFSCORRUPTED);
+                               if ((attempts % 5) == 0) {
+                                       delay(1); /* Don't just spin the CPU */
+#ifdef DEBUG
+                                       xfs_lock_delays++;
+#endif
+                               }
+                               i = 0;
+                               try_lock = 0;
+                               goto again;
                        }
-
-                       size = (int)di_size;
-                       error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size);
-                       break;
-               case XFS_DINODE_FMT_EXTENTS:
-                       error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
-                       break;
-               case XFS_DINODE_FMT_BTREE:
-                       error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
-                       break;
-               default:
-                       XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW,
-                                        ip->i_mount);
-                       return XFS_ERROR(EFSCORRUPTED);
+               } else {
+                       xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
                }
-               break;
-
-       default:
-               XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-       if (error) {
-               return error;
        }
-       if (!XFS_DFORK_Q(dip))
-               return 0;
-
-       ASSERT(ip->i_afp == NULL);
-       ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
-
-       switch (dip->di_aformat) {
-       case XFS_DINODE_FMT_LOCAL:
-               atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
-               size = be16_to_cpu(atp->hdr.totsize);
-
-               if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
-                       xfs_warn(ip->i_mount,
-                               "corrupt inode %Lu (bad attr fork size %Ld).",
-                               (unsigned long long) ip->i_ino,
-                               (long long) size);
-                       XFS_CORRUPTION_ERROR("xfs_iformat(8)",
-                                            XFS_ERRLEVEL_LOW,
-                                            ip->i_mount, dip);
-                       return XFS_ERROR(EFSCORRUPTED);
-               }
 
-               error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
-               break;
-       case XFS_DINODE_FMT_EXTENTS:
-               error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK);
-               break;
-       case XFS_DINODE_FMT_BTREE:
-               error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
-               break;
-       default:
-               error = XFS_ERROR(EFSCORRUPTED);
-               break;
-       }
-       if (error) {
-               kmem_zone_free(xfs_ifork_zone, ip->i_afp);
-               ip->i_afp = NULL;
-               xfs_idestroy_fork(ip, XFS_DATA_FORK);
+#ifdef DEBUG
+       if (attempts) {
+               if (attempts < 5) xfs_small_retries++;
+               else if (attempts < 100) xfs_middle_retries++;
+               else xfs_lots_retries++;
+       } else {
+               xfs_locked_n++;
        }
-       return error;
+#endif
 }
 
 /*
- * The file is in-lined in the on-disk inode.
- * If it fits into if_inline_data, then copy
- * it there, otherwise allocate a buffer for it
- * and copy the data there.  Either way, set
- * if_data to point at the data.
- * If we allocate a buffer for the data, make
- * sure that its size is a multiple of 4 and
- * record the real size in i_real_bytes.
+ * xfs_lock_two_inodes() can only be used to lock one type of lock
+ * at a time - the iolock or the ilock, but not both at once. If
+ * we lock both at once, lockdep will report false positives saying
+ * we have violated locking orders.
  */
-STATIC int
-xfs_iformat_local(
-       xfs_inode_t     *ip,
-       xfs_dinode_t    *dip,
-       int             whichfork,
-       int             size)
+void
+xfs_lock_two_inodes(
+       xfs_inode_t             *ip0,
+       xfs_inode_t             *ip1,
+       uint                    lock_mode)
 {
-       xfs_ifork_t     *ifp;
-       int             real_size;
-
-       /*
-        * If the size is unreasonable, then something
-        * is wrong and we just bail out rather than crash in
-        * kmem_alloc() or memcpy() below.
-        */
-       if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
-               xfs_warn(ip->i_mount,
-       "corrupt inode %Lu (bad size %d for local fork, size = %d).",
-                       (unsigned long long) ip->i_ino, size,
-                       XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
-               XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
-                                    ip->i_mount, dip);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       real_size = 0;
-       if (size == 0)
-               ifp->if_u1.if_data = NULL;
-       else if (size <= sizeof(ifp->if_u2.if_inline_data))
-               ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
-       else {
-               real_size = roundup(size, 4);
-               ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
-       }
-       ifp->if_bytes = size;
-       ifp->if_real_bytes = real_size;
-       if (size)
-               memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
-       ifp->if_flags &= ~XFS_IFEXTENTS;
-       ifp->if_flags |= XFS_IFINLINE;
-       return 0;
-}
+       xfs_inode_t             *temp;
+       int                     attempts = 0;
+       xfs_log_item_t          *lp;
 
-/*
- * The file consists of a set of extents all
- * of which fit into the on-disk inode.
- * If there are few enough extents to fit into
- * the if_inline_ext, then copy them there.
- * Otherwise allocate a buffer for them and copy
- * them into it.  Either way, set if_extents
- * to point at the extents.
- */
-STATIC int
-xfs_iformat_extents(
-       xfs_inode_t     *ip,
-       xfs_dinode_t    *dip,
-       int             whichfork)
-{
-       xfs_bmbt_rec_t  *dp;
-       xfs_ifork_t     *ifp;
-       int             nex;
-       int             size;
-       int             i;
-
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       nex = XFS_DFORK_NEXTENTS(dip, whichfork);
-       size = nex * (uint)sizeof(xfs_bmbt_rec_t);
-
-       /*
-        * If the number of extents is unreasonable, then something
-        * is wrong and we just bail out rather than crash in
-        * kmem_alloc() or memcpy() below.
-        */
-       if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
-               xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
-                       (unsigned long long) ip->i_ino, nex);
-               XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
-                                    ip->i_mount, dip);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       ifp->if_real_bytes = 0;
-       if (nex == 0)
-               ifp->if_u1.if_extents = NULL;
-       else if (nex <= XFS_INLINE_EXTS)
-               ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
-       else
-               xfs_iext_add(ifp, 0, nex);
-
-       ifp->if_bytes = size;
-       if (size) {
-               dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
-               xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip));
-               for (i = 0; i < nex; i++, dp++) {
-                       xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
-                       ep->l0 = get_unaligned_be64(&dp->l0);
-                       ep->l1 = get_unaligned_be64(&dp->l1);
-               }
-               XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
-               if (whichfork != XFS_DATA_FORK ||
-                       XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
-                               if (unlikely(xfs_check_nostate_extents(
-                                   ifp, 0, nex))) {
-                                       XFS_ERROR_REPORT("xfs_iformat_extents(2)",
-                                                        XFS_ERRLEVEL_LOW,
-                                                        ip->i_mount);
-                                       return XFS_ERROR(EFSCORRUPTED);
-                               }
-       }
-       ifp->if_flags |= XFS_IFEXTENTS;
-       return 0;
-}
+       if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
+               ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0);
+       ASSERT(ip0->i_ino != ip1->i_ino);
 
-/*
- * The file has too many extents to fit into
- * the inode, so they are in B-tree format.
- * Allocate a buffer for the root of the B-tree
- * and copy the root into it.  The i_extents
- * field will remain NULL until all of the
- * extents are read in (when they are needed).
- */
-STATIC int
-xfs_iformat_btree(
-       xfs_inode_t             *ip,
-       xfs_dinode_t            *dip,
-       int                     whichfork)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       xfs_bmdr_block_t        *dfp;
-       xfs_ifork_t             *ifp;
-       /* REFERENCED */
-       int                     nrecs;
-       int                     size;
-
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
-       size = XFS_BMAP_BROOT_SPACE(mp, dfp);
-       nrecs = be16_to_cpu(dfp->bb_numrecs);
-
-       /*
-        * blow out if -- fork has less extents than can fit in
-        * fork (fork shouldn't be a btree format), root btree
-        * block has more records than can fit into the fork,
-        * or the number of extents is greater than the number of
-        * blocks.
-        */
-       if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
-                                       XFS_IFORK_MAXEXT(ip, whichfork) ||
-                    XFS_BMDR_SPACE_CALC(nrecs) >
-                                       XFS_DFORK_SIZE(dip, mp, whichfork) ||
-                    XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
-               xfs_warn(mp, "corrupt inode %Lu (btree).",
-                                       (unsigned long long) ip->i_ino);
-               XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
-                                        mp, dip);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       ifp->if_broot_bytes = size;
-       ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
-       ASSERT(ifp->if_broot != NULL);
-       /*
-        * Copy and convert from the on-disk structure
-        * to the in-memory structure.
-        */
-       xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
-                        ifp->if_broot, size);
-       ifp->if_flags &= ~XFS_IFEXTENTS;
-       ifp->if_flags |= XFS_IFBROOT;
+       if (ip0->i_ino > ip1->i_ino) {
+               temp = ip0;
+               ip0 = ip1;
+               ip1 = temp;
+       }
 
-       return 0;
-}
+ again:
+       xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0));
 
-STATIC void
-xfs_dinode_from_disk(
-       xfs_icdinode_t          *to,
-       xfs_dinode_t            *from)
-{
-       to->di_magic = be16_to_cpu(from->di_magic);
-       to->di_mode = be16_to_cpu(from->di_mode);
-       to->di_version = from ->di_version;
-       to->di_format = from->di_format;
-       to->di_onlink = be16_to_cpu(from->di_onlink);
-       to->di_uid = be32_to_cpu(from->di_uid);
-       to->di_gid = be32_to_cpu(from->di_gid);
-       to->di_nlink = be32_to_cpu(from->di_nlink);
-       to->di_projid_lo = be16_to_cpu(from->di_projid_lo);
-       to->di_projid_hi = be16_to_cpu(from->di_projid_hi);
-       memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
-       to->di_flushiter = be16_to_cpu(from->di_flushiter);
-       to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec);
-       to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec);
-       to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec);
-       to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec);
-       to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec);
-       to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec);
-       to->di_size = be64_to_cpu(from->di_size);
-       to->di_nblocks = be64_to_cpu(from->di_nblocks);
-       to->di_extsize = be32_to_cpu(from->di_extsize);
-       to->di_nextents = be32_to_cpu(from->di_nextents);
-       to->di_anextents = be16_to_cpu(from->di_anextents);
-       to->di_forkoff = from->di_forkoff;
-       to->di_aformat  = from->di_aformat;
-       to->di_dmevmask = be32_to_cpu(from->di_dmevmask);
-       to->di_dmstate  = be16_to_cpu(from->di_dmstate);
-       to->di_flags    = be16_to_cpu(from->di_flags);
-       to->di_gen      = be32_to_cpu(from->di_gen);
-
-       if (to->di_version == 3) {
-               to->di_changecount = be64_to_cpu(from->di_changecount);
-               to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec);
-               to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec);
-               to->di_flags2 = be64_to_cpu(from->di_flags2);
-               to->di_ino = be64_to_cpu(from->di_ino);
-               to->di_lsn = be64_to_cpu(from->di_lsn);
-               memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
-               uuid_copy(&to->di_uuid, &from->di_uuid);
+       /*
+        * If the first lock we have locked is in the AIL, we must TRY to get
+        * the second lock. If we can't get it, we must release the first one
+        * and try again.
+        */
+       lp = (xfs_log_item_t *)ip0->i_itemp;
+       if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
+               if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) {
+                       xfs_iunlock(ip0, lock_mode);
+                       if ((++attempts % 5) == 0)
+                               delay(1); /* Don't just spin the CPU */
+                       goto again;
+               }
+       } else {
+               xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1));
        }
 }
 
+
 void
-xfs_dinode_to_disk(
-       xfs_dinode_t            *to,
-       xfs_icdinode_t          *from)
+__xfs_iflock(
+       struct xfs_inode        *ip)
 {
-       to->di_magic = cpu_to_be16(from->di_magic);
-       to->di_mode = cpu_to_be16(from->di_mode);
-       to->di_version = from ->di_version;
-       to->di_format = from->di_format;
-       to->di_onlink = cpu_to_be16(from->di_onlink);
-       to->di_uid = cpu_to_be32(from->di_uid);
-       to->di_gid = cpu_to_be32(from->di_gid);
-       to->di_nlink = cpu_to_be32(from->di_nlink);
-       to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
-       to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
-       memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
-       to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
-       to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec);
-       to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec);
-       to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec);
-       to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec);
-       to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec);
-       to->di_size = cpu_to_be64(from->di_size);
-       to->di_nblocks = cpu_to_be64(from->di_nblocks);
-       to->di_extsize = cpu_to_be32(from->di_extsize);
-       to->di_nextents = cpu_to_be32(from->di_nextents);
-       to->di_anextents = cpu_to_be16(from->di_anextents);
-       to->di_forkoff = from->di_forkoff;
-       to->di_aformat = from->di_aformat;
-       to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
-       to->di_dmstate = cpu_to_be16(from->di_dmstate);
-       to->di_flags = cpu_to_be16(from->di_flags);
-       to->di_gen = cpu_to_be32(from->di_gen);
-
-       if (from->di_version == 3) {
-               to->di_changecount = cpu_to_be64(from->di_changecount);
-               to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
-               to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
-               to->di_flags2 = cpu_to_be64(from->di_flags2);
-               to->di_ino = cpu_to_be64(from->di_ino);
-               to->di_lsn = cpu_to_be64(from->di_lsn);
-               memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
-               uuid_copy(&to->di_uuid, &from->di_uuid);
-               to->di_flushiter = 0;
-       } else {
-               to->di_flushiter = cpu_to_be16(from->di_flushiter);
-       }
+       wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT);
+       DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT);
+
+       do {
+               prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
+               if (xfs_isiflocked(ip))
+                       io_schedule();
+       } while (!xfs_iflock_nowait(ip));
+
+       finish_wait(wq, &wait.wait);
 }
 
 STATIC uint
@@ -987,234 +567,49 @@ xfs_dic2xflags(
                                (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0);
 }
 
-static bool
-xfs_dinode_verify(
-       struct xfs_mount        *mp,
-       struct xfs_inode        *ip,
-       struct xfs_dinode       *dip)
-{
-       if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
-               return false;
-
-       /* only version 3 or greater inodes are extensively verified here */
-       if (dip->di_version < 3)
-               return true;
-
-       if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return false;
-       if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize,
-                             offsetof(struct xfs_dinode, di_crc)))
-               return false;
-       if (be64_to_cpu(dip->di_ino) != ip->i_ino)
-               return false;
-       if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
-               return false;
-       return true;
-}
-
-void
-xfs_dinode_calc_crc(
-       struct xfs_mount        *mp,
-       struct xfs_dinode       *dip)
-{
-       __uint32_t              crc;
-
-       if (dip->di_version < 3)
-               return;
-
-       ASSERT(xfs_sb_version_hascrc(&mp->m_sb));
-       crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize,
-                             offsetof(struct xfs_dinode, di_crc));
-       dip->di_crc = xfs_end_cksum(crc);
-}
-
 /*
- * Read the disk inode attributes into the in-core inode structure.
- *
- * For version 5 superblocks, if we are initialising a new inode and we are not
- * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new
- * inode core with a random generation number. If we are keeping inodes around,
- * we need to read the inode cluster to get the existing generation number off
- * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode
- * format) then log recovery is dependent on the di_flushiter field being
- * initialised from the current on-disk value and hence we must also read the
- * inode off disk.
+ * Lookups up an inode from "name". If ci_name is not NULL, then a CI match
+ * is allowed, otherwise it has to be an exact match. If a CI match is found,
+ * ci_name->name will point to a the actual name (caller must free) or
+ * will be set to NULL if an exact match is found.
  */
 int
-xfs_iread(
-       xfs_mount_t     *mp,
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       uint            iget_flags)
+xfs_lookup(
+       xfs_inode_t             *dp,
+       struct xfs_name         *name,
+       xfs_inode_t             **ipp,
+       struct xfs_name         *ci_name)
 {
-       xfs_buf_t       *bp;
-       xfs_dinode_t    *dip;
-       int             error;
-
-       /*
-        * Fill in the location information in the in-core inode.
-        */
-       error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags);
-       if (error)
-               return error;
-
-       /* shortcut IO on inode allocation if possible */
-       if ((iget_flags & XFS_IGET_CREATE) &&
-           xfs_sb_version_hascrc(&mp->m_sb) &&
-           !(mp->m_flags & XFS_MOUNT_IKEEP)) {
-               /* initialise the on-disk inode core */
-               memset(&ip->i_d, 0, sizeof(ip->i_d));
-               ip->i_d.di_magic = XFS_DINODE_MAGIC;
-               ip->i_d.di_gen = prandom_u32();
-               if (xfs_sb_version_hascrc(&mp->m_sb)) {
-                       ip->i_d.di_version = 3;
-                       ip->i_d.di_ino = ip->i_ino;
-                       uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
-               } else
-                       ip->i_d.di_version = 2;
-               return 0;
-       }
-
-       /*
-        * Get pointers to the on-disk inode and the buffer containing it.
-        */
-       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags);
-       if (error)
-               return error;
-
-       /* even unallocated inodes are verified */
-       if (!xfs_dinode_verify(mp, ip, dip)) {
-               xfs_alert(mp, "%s: validation failed for inode %lld failed",
-                               __func__, ip->i_ino);
+       xfs_ino_t               inum;
+       int                     error;
+       uint                    lock_mode;
 
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip);
-               error = XFS_ERROR(EFSCORRUPTED);
-               goto out_brelse;
-       }
+       trace_xfs_lookup(dp, name);
 
-       /*
-        * If the on-disk inode is already linked to a directory
-        * entry, copy all of the inode into the in-core inode.
-        * xfs_iformat() handles copying in the inode format
-        * specific information.
-        * Otherwise, just get the truly permanent information.
-        */
-       if (dip->di_mode) {
-               xfs_dinode_from_disk(&ip->i_d, dip);
-               error = xfs_iformat(ip, dip);
-               if (error)  {
-#ifdef DEBUG
-                       xfs_alert(mp, "%s: xfs_iformat() returned error %d",
-                               __func__, error);
-#endif /* DEBUG */
-                       goto out_brelse;
-               }
-       } else {
-               /*
-                * Partial initialisation of the in-core inode. Just the bits
-                * that xfs_ialloc won't overwrite or relies on being correct.
-                */
-               ip->i_d.di_magic = be16_to_cpu(dip->di_magic);
-               ip->i_d.di_version = dip->di_version;
-               ip->i_d.di_gen = be32_to_cpu(dip->di_gen);
-               ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter);
-
-               if (dip->di_version == 3) {
-                       ip->i_d.di_ino = be64_to_cpu(dip->di_ino);
-                       uuid_copy(&ip->i_d.di_uuid, &dip->di_uuid);
-               }
+       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
+               return XFS_ERROR(EIO);
 
-               /*
-                * Make sure to pull in the mode here as well in
-                * case the inode is released without being used.
-                * This ensures that xfs_inactive() will see that
-                * the inode is already free and not try to mess
-                * with the uninitialized part of it.
-                */
-               ip->i_d.di_mode = 0;
-       }
+       lock_mode = xfs_ilock_map_shared(dp);
+       error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
+       xfs_iunlock_map_shared(dp, lock_mode);
 
-       /*
-        * The inode format changed when we moved the link count and
-        * made it 32 bits long.  If this is an old format inode,
-        * convert it in memory to look like a new one.  If it gets
-        * flushed to disk we will convert back before flushing or
-        * logging it.  We zero out the new projid field and the old link
-        * count field.  We'll handle clearing the pad field (the remains
-        * of the old uuid field) when we actually convert the inode to
-        * the new format. We don't change the version number so that we
-        * can distinguish this from a real new format inode.
-        */
-       if (ip->i_d.di_version == 1) {
-               ip->i_d.di_nlink = ip->i_d.di_onlink;
-               ip->i_d.di_onlink = 0;
-               xfs_set_projid(ip, 0);
-       }
+       if (error)
+               goto out;
 
-       ip->i_delayed_blks = 0;
+       error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);
+       if (error)
+               goto out_free_name;
 
-       /*
-        * Mark the buffer containing the inode as something to keep
-        * around for a while.  This helps to keep recently accessed
-        * meta-data in-core longer.
-        */
-       xfs_buf_set_ref(bp, XFS_INO_REF);
+       return 0;
 
-       /*
-        * Use xfs_trans_brelse() to release the buffer containing the on-disk
-        * inode, because it was acquired with xfs_trans_read_buf() in
-        * xfs_imap_to_bp() above.  If tp is NULL, this is just a normal
-        * brelse().  If we're within a transaction, then xfs_trans_brelse()
-        * will only release the buffer if it is not dirty within the
-        * transaction.  It will be OK to release the buffer in this case,
-        * because inodes on disk are never destroyed and we will be locking the
-        * new in-core inode before putting it in the cache where other
-        * processes can find it.  Thus we don't have to worry about the inode
-        * being changed just because we released the buffer.
-        */
- out_brelse:
-       xfs_trans_brelse(tp, bp);
+out_free_name:
+       if (ci_name)
+               kmem_free(ci_name->name);
+out:
+       *ipp = NULL;
        return error;
 }
 
-/*
- * Read in extents from a btree-format inode.
- * Allocate and fill in if_extents.  Real work is done in xfs_bmap.c.
- */
-int
-xfs_iread_extents(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip,
-       int             whichfork)
-{
-       int             error;
-       xfs_ifork_t     *ifp;
-       xfs_extnum_t    nextents;
-
-       if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
-               XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
-                                ip->i_mount);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-       nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-
-       /*
-        * We know that the size is valid (it's checked in iformat_btree)
-        */
-       ifp->if_bytes = ifp->if_real_bytes = 0;
-       ifp->if_flags |= XFS_IFEXTENTS;
-       xfs_iext_add(ifp, 0, nextents);
-       error = xfs_bmap_read_extents(tp, ip, whichfork);
-       if (error) {
-               xfs_iext_destroy(ifp);
-               ifp->if_flags &= ~XFS_IFEXTENTS;
-               return error;
-       }
-       xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));
-       return 0;
-}
-
 /*
  * Allocate an inode on disk and return a copy of its in-core version.
  * The in-core inode is locked exclusively.  Set mode, nlink, and rdev
@@ -1295,8 +690,8 @@ xfs_ialloc(
        ip->i_d.di_onlink = 0;
        ip->i_d.di_nlink = nlink;
        ASSERT(ip->i_d.di_nlink == nlink);
-       ip->i_d.di_uid = current_fsuid();
-       ip->i_d.di_gid = current_fsgid();
+       ip->i_d.di_uid = xfs_kuid_to_uid(current_fsuid());
+       ip->i_d.di_gid = xfs_kgid_to_gid(current_fsgid());
        xfs_set_projid(ip, prid);
        memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 
@@ -1335,7 +730,7 @@ xfs_ialloc(
         */
        if ((irix_sgid_inherit) &&
            (ip->i_d.di_mode & S_ISGID) &&
-           (!in_group_p((gid_t)ip->i_d.di_gid))) {
+           (!in_group_p(xfs_gid_to_kgid(ip->i_d.di_gid)))) {
                ip->i_d.di_mode &= ~S_ISGID;
        }
 
@@ -1467,31 +862,608 @@ xfs_ialloc(
 }
 
 /*
- * Free up the underlying blocks past new_size.  The new size must be smaller
- * than the current size.  This routine can be used both for the attribute and
- * data fork, and does not modify the inode size, which is left to the caller.
+ * Allocates a new inode from disk and return a pointer to the
+ * incore copy. This routine will internally commit the current
+ * transaction and allocate a new one if the Space Manager needed
+ * to do an allocation to replenish the inode free-list.
  *
- * The transaction passed to this routine must have made a permanent log
- * reservation of at least XFS_ITRUNCATE_LOG_RES.  This routine may commit the
- * given transaction and start new ones, so make sure everything involved in
- * the transaction is tidy before calling here.  Some transaction will be
- * returned to the caller to be committed.  The incoming transaction must
- * already include the inode, and both inode locks must be held exclusively.
- * The inode must also be "held" within the transaction.  On return the inode
- * will be "held" within the returned transaction.  This routine does NOT
- * require any disk space to be reserved for it within the transaction.
+ * This routine is designed to be called from xfs_create and
+ * xfs_create_dir.
  *
- * If we get an error, we must return with the inode locked and linked into the
- * current transaction. This keeps things simple for the higher level code,
- * because it always knows that the inode is locked and held in the transaction
- * that returns to it whether errors occur or not.  We don't mark the inode
- * dirty on error so that transactions can be easily aborted if possible.
  */
 int
-xfs_itruncate_extents(
-       struct xfs_trans        **tpp,
-       struct xfs_inode        *ip,
-       int                     whichfork,
+xfs_dir_ialloc(
+       xfs_trans_t     **tpp,          /* input: current transaction;
+                                          output: may be a new transaction. */
+       xfs_inode_t     *dp,            /* directory within whose allocate
+                                          the inode. */
+       umode_t         mode,
+       xfs_nlink_t     nlink,
+       xfs_dev_t       rdev,
+       prid_t          prid,           /* project id */
+       int             okalloc,        /* ok to allocate new space */
+       xfs_inode_t     **ipp,          /* pointer to inode; it will be
+                                          locked. */
+       int             *committed)
+
+{
+       xfs_trans_t     *tp;
+       xfs_trans_t     *ntp;
+       xfs_inode_t     *ip;
+       xfs_buf_t       *ialloc_context = NULL;
+       int             code;
+       void            *dqinfo;
+       uint            tflags;
+
+       tp = *tpp;
+       ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
+
+       /*
+        * xfs_ialloc will return a pointer to an incore inode if
+        * the Space Manager has an available inode on the free
+        * list. Otherwise, it will do an allocation and replenish
+        * the freelist.  Since we can only do one allocation per
+        * transaction without deadlocks, we will need to commit the
+        * current transaction and start a new one.  We will then
+        * need to call xfs_ialloc again to get the inode.
+        *
+        * If xfs_ialloc did an allocation to replenish the freelist,
+        * it returns the bp containing the head of the freelist as
+        * ialloc_context. We will hold a lock on it across the
+        * transaction commit so that no other process can steal
+        * the inode(s) that we've just allocated.
+        */
+       code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc,
+                         &ialloc_context, &ip);
+
+       /*
+        * Return an error if we were unable to allocate a new inode.
+        * This should only happen if we run out of space on disk or
+        * encounter a disk error.
+        */
+       if (code) {
+               *ipp = NULL;
+               return code;
+       }
+       if (!ialloc_context && !ip) {
+               *ipp = NULL;
+               return XFS_ERROR(ENOSPC);
+       }
+
+       /*
+        * If the AGI buffer is non-NULL, then we were unable to get an
+        * inode in one operation.  We need to commit the current
+        * transaction and call xfs_ialloc() again.  It is guaranteed
+        * to succeed the second time.
+        */
+       if (ialloc_context) {
+               struct xfs_trans_res tres;
+
+               /*
+                * Normally, xfs_trans_commit releases all the locks.
+                * We call bhold to hang on to the ialloc_context across
+                * the commit.  Holding this buffer prevents any other
+                * processes from doing any allocations in this
+                * allocation group.
+                */
+               xfs_trans_bhold(tp, ialloc_context);
+               /*
+                * Save the log reservation so we can use
+                * them in the next transaction.
+                */
+               tres.tr_logres = xfs_trans_get_log_res(tp);
+               tres.tr_logcount = xfs_trans_get_log_count(tp);
+
+               /*
+                * We want the quota changes to be associated with the next
+                * transaction, NOT this one. So, detach the dqinfo from this
+                * and attach it to the next transaction.
+                */
+               dqinfo = NULL;
+               tflags = 0;
+               if (tp->t_dqinfo) {
+                       dqinfo = (void *)tp->t_dqinfo;
+                       tp->t_dqinfo = NULL;
+                       tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY;
+                       tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY);
+               }
+
+               ntp = xfs_trans_dup(tp);
+               code = xfs_trans_commit(tp, 0);
+               tp = ntp;
+               if (committed != NULL) {
+                       *committed = 1;
+               }
+               /*
+                * If we get an error during the commit processing,
+                * release the buffer that is still held and return
+                * to the caller.
+                */
+               if (code) {
+                       xfs_buf_relse(ialloc_context);
+                       if (dqinfo) {
+                               tp->t_dqinfo = dqinfo;
+                               xfs_trans_free_dqinfo(tp);
+                       }
+                       *tpp = ntp;
+                       *ipp = NULL;
+                       return code;
+               }
+
+               /*
+                * transaction commit worked ok so we can drop the extra ticket
+                * reference that we gained in xfs_trans_dup()
+                */
+               xfs_log_ticket_put(tp->t_ticket);
+               tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+               code = xfs_trans_reserve(tp, &tres, 0, 0);
+
+               /*
+                * Re-attach the quota info that we detached from prev trx.
+                */
+               if (dqinfo) {
+                       tp->t_dqinfo = dqinfo;
+                       tp->t_flags |= tflags;
+               }
+
+               if (code) {
+                       xfs_buf_relse(ialloc_context);
+                       *tpp = ntp;
+                       *ipp = NULL;
+                       return code;
+               }
+               xfs_trans_bjoin(tp, ialloc_context);
+
+               /*
+                * Call ialloc again. Since we've locked out all
+                * other allocations in this allocation group,
+                * this call should always succeed.
+                */
+               code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
+                                 okalloc, &ialloc_context, &ip);
+
+               /*
+                * If we get an error at this point, return to the caller
+                * so that the current transaction can be aborted.
+                */
+               if (code) {
+                       *tpp = tp;
+                       *ipp = NULL;
+                       return code;
+               }
+               ASSERT(!ialloc_context && ip);
+
+       } else {
+               if (committed != NULL)
+                       *committed = 0;
+       }
+
+       *ipp = ip;
+       *tpp = tp;
+
+       return 0;
+}
+
+/*
+ * Decrement the link count on an inode & log the change.
+ * If this causes the link count to go to zero, initiate the
+ * logging activity required to truncate a file.
+ */
+int                            /* error */
+xfs_droplink(
+       xfs_trans_t *tp,
+       xfs_inode_t *ip)
+{
+       int     error;
+
+       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
+
+       ASSERT (ip->i_d.di_nlink > 0);
+       ip->i_d.di_nlink--;
+       drop_nlink(VFS_I(ip));
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+       error = 0;
+       if (ip->i_d.di_nlink == 0) {
+               /*
+                * We're dropping the last link to this file.
+                * Move the on-disk inode to the AGI unlinked list.
+                * From xfs_inactive() we will pull the inode from
+                * the list and free it.
+                */
+               error = xfs_iunlink(tp, ip);
+       }
+       return error;
+}
+
+/*
+ * This gets called when the inode's version needs to be changed from 1 to 2.
+ * Currently this happens when the nlink field overflows the old 16-bit value
+ * or when chproj is called to change the project for the first time.
+ * As a side effect the superblock version will also get rev'd
+ * to contain the NLINK bit.
+ */
+void
+xfs_bump_ino_vers2(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip)
+{
+       xfs_mount_t     *mp;
+
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+       ASSERT(ip->i_d.di_version == 1);
+
+       ip->i_d.di_version = 2;
+       ip->i_d.di_onlink = 0;
+       memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
+       mp = tp->t_mountp;
+       if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
+               spin_lock(&mp->m_sb_lock);
+               if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
+                       xfs_sb_version_addnlink(&mp->m_sb);
+                       spin_unlock(&mp->m_sb_lock);
+                       xfs_mod_sb(tp, XFS_SB_VERSIONNUM);
+               } else {
+                       spin_unlock(&mp->m_sb_lock);
+               }
+       }
+       /* Caller must log the inode */
+}
+
+/*
+ * Increment the link count on an inode & log the change.
+ */
+int
+xfs_bumplink(
+       xfs_trans_t *tp,
+       xfs_inode_t *ip)
+{
+       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
+
+       ASSERT(ip->i_d.di_nlink > 0);
+       ip->i_d.di_nlink++;
+       inc_nlink(VFS_I(ip));
+       if ((ip->i_d.di_version == 1) &&
+           (ip->i_d.di_nlink > XFS_MAXLINK_1)) {
+               /*
+                * The inode has increased its number of links beyond
+                * what can fit in an old format inode.  It now needs
+                * to be converted to a version 2 inode with a 32 bit
+                * link count.  If this is the first inode in the file
+                * system to do this, then we need to bump the superblock
+                * version number as well.
+                */
+               xfs_bump_ino_vers2(tp, ip);
+       }
+
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       return 0;
+}
+
+int
+xfs_create(
+       xfs_inode_t             *dp,
+       struct xfs_name         *name,
+       umode_t                 mode,
+       xfs_dev_t               rdev,
+       xfs_inode_t             **ipp)
+{
+       int                     is_dir = S_ISDIR(mode);
+       struct xfs_mount        *mp = dp->i_mount;
+       struct xfs_inode        *ip = NULL;
+       struct xfs_trans        *tp = NULL;
+       int                     error;
+       xfs_bmap_free_t         free_list;
+       xfs_fsblock_t           first_block;
+       bool                    unlock_dp_on_error = false;
+       uint                    cancel_flags;
+       int                     committed;
+       prid_t                  prid;
+       struct xfs_dquot        *udqp = NULL;
+       struct xfs_dquot        *gdqp = NULL;
+       struct xfs_dquot        *pdqp = NULL;
+       struct xfs_trans_res    tres;
+       uint                    resblks;
+
+       trace_xfs_create(dp, name);
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
+               prid = xfs_get_projid(dp);
+       else
+               prid = XFS_PROJID_DEFAULT;
+
+       /*
+        * Make sure that we have allocated dquot(s) on disk.
+        */
+       error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()),
+                                       xfs_kgid_to_gid(current_fsgid()), prid,
+                                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                                       &udqp, &gdqp, &pdqp);
+       if (error)
+               return error;
+
+       if (is_dir) {
+               rdev = 0;
+               resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
+               tres.tr_logres = M_RES(mp)->tr_mkdir.tr_logres;
+               tres.tr_logcount = XFS_MKDIR_LOG_COUNT;
+               tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
+       } else {
+               resblks = XFS_CREATE_SPACE_RES(mp, name->len);
+               tres.tr_logres = M_RES(mp)->tr_create.tr_logres;
+               tres.tr_logcount = XFS_CREATE_LOG_COUNT;
+               tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
+       }
+
+       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
+
+       /*
+        * Initially assume that the file does not exist and
+        * reserve the resources for that case.  If that is not
+        * the case we'll drop the one we have and get a more
+        * appropriate transaction later.
+        */
+       tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+       error = xfs_trans_reserve(tp, &tres, resblks, 0);
+       if (error == ENOSPC) {
+               /* flush outstanding delalloc blocks and retry */
+               xfs_flush_inodes(mp);
+               error = xfs_trans_reserve(tp, &tres, resblks, 0);
+       }
+       if (error == ENOSPC) {
+               /* No space at all so try a "no-allocation" reservation */
+               resblks = 0;
+               error = xfs_trans_reserve(tp, &tres, 0, 0);
+       }
+       if (error) {
+               cancel_flags = 0;
+               goto out_trans_cancel;
+       }
+
+       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
+       unlock_dp_on_error = true;
+
+       xfs_bmap_init(&free_list, &first_block);
+
+       /*
+        * Reserve disk quota and the inode.
+        */
+       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
+                                               pdqp, resblks, 1, 0);
+       if (error)
+               goto out_trans_cancel;
+
+       error = xfs_dir_canenter(tp, dp, name, resblks);
+       if (error)
+               goto out_trans_cancel;
+
+       /*
+        * A newly created regular or special file just has one directory
+        * entry pointing to them, but a directory also the "." entry
+        * pointing to itself.
+        */
+       error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
+                              prid, resblks > 0, &ip, &committed);
+       if (error) {
+               if (error == ENOSPC)
+                       goto out_trans_cancel;
+               goto out_trans_abort;
+       }
+
+       /*
+        * Now we join the directory inode to the transaction.  We do not do it
+        * earlier because xfs_dir_ialloc might commit the previous transaction
+        * (and release all the locks).  An error from here on will result in
+        * the transaction cancel unlocking dp so don't do it explicitly in the
+        * error path.
+        */
+       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       unlock_dp_on_error = false;
+
+       error = xfs_dir_createname(tp, dp, name, ip->i_ino,
+                                       &first_block, &free_list, resblks ?
+                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
+       if (error) {
+               ASSERT(error != ENOSPC);
+               goto out_trans_abort;
+       }
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
+
+       if (is_dir) {
+               error = xfs_dir_init(tp, ip, dp);
+               if (error)
+                       goto out_bmap_cancel;
+
+               error = xfs_bumplink(tp, dp);
+               if (error)
+                       goto out_bmap_cancel;
+       }
+
+       /*
+        * If this is a synchronous mount, make sure that the
+        * create transaction goes to disk before returning to
+        * the user.
+        */
+       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
+               xfs_trans_set_sync(tp);
+
+       /*
+        * Attach the dquot(s) to the inodes and modify them incore.
+        * These ids of the inode couldn't have changed since the new
+        * inode has been locked ever since it was created.
+        */
+       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
+
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
+       if (error)
+               goto out_bmap_cancel;
+
+       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+       if (error)
+               goto out_release_inode;
+
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
+
+       *ipp = ip;
+       return 0;
+
+ out_bmap_cancel:
+       xfs_bmap_cancel(&free_list);
+ out_trans_abort:
+       cancel_flags |= XFS_TRANS_ABORT;
+ out_trans_cancel:
+       xfs_trans_cancel(tp, cancel_flags);
+ out_release_inode:
+       /*
+        * Wait until after the current transaction is aborted to
+        * release the inode.  This prevents recursive transactions
+        * and deadlocks from xfs_inactive.
+        */
+       if (ip)
+               IRELE(ip);
+
+       xfs_qm_dqrele(udqp);
+       xfs_qm_dqrele(gdqp);
+       xfs_qm_dqrele(pdqp);
+
+       if (unlock_dp_on_error)
+               xfs_iunlock(dp, XFS_ILOCK_EXCL);
+       return error;
+}
+
+int
+xfs_link(
+       xfs_inode_t             *tdp,
+       xfs_inode_t             *sip,
+       struct xfs_name         *target_name)
+{
+       xfs_mount_t             *mp = tdp->i_mount;
+       xfs_trans_t             *tp;
+       int                     error;
+       xfs_bmap_free_t         free_list;
+       xfs_fsblock_t           first_block;
+       int                     cancel_flags;
+       int                     committed;
+       int                     resblks;
+
+       trace_xfs_link(tdp, target_name);
+
+       ASSERT(!S_ISDIR(sip->i_d.di_mode));
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       error = xfs_qm_dqattach(sip, 0);
+       if (error)
+               goto std_return;
+
+       error = xfs_qm_dqattach(tdp, 0);
+       if (error)
+               goto std_return;
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
+       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
+       resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_link, resblks, 0);
+       if (error == ENOSPC) {
+               resblks = 0;
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_link, 0, 0);
+       }
+       if (error) {
+               cancel_flags = 0;
+               goto error_return;
+       }
+
+       xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
+
+       xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
+
+       /*
+        * If we are using project inheritance, we only allow hard link
+        * creation in our tree when the project IDs are the same; else
+        * the tree quota mechanism could be circumvented.
+        */
+       if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
+                    (xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
+               error = XFS_ERROR(EXDEV);
+               goto error_return;
+       }
+
+       error = xfs_dir_canenter(tp, tdp, target_name, resblks);
+       if (error)
+               goto error_return;
+
+       xfs_bmap_init(&free_list, &first_block);
+
+       error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
+                                       &first_block, &free_list, resblks);
+       if (error)
+               goto abort_return;
+       xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
+
+       error = xfs_bumplink(tp, sip);
+       if (error)
+               goto abort_return;
+
+       /*
+        * If this is a synchronous mount, make sure that the
+        * link transaction goes to disk before returning to
+        * the user.
+        */
+       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
+               xfs_trans_set_sync(tp);
+       }
+
+       error = xfs_bmap_finish (&tp, &free_list, &committed);
+       if (error) {
+               xfs_bmap_cancel(&free_list);
+               goto abort_return;
+       }
+
+       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+
+ abort_return:
+       cancel_flags |= XFS_TRANS_ABORT;
+ error_return:
+       xfs_trans_cancel(tp, cancel_flags);
+ std_return:
+       return error;
+}
+
+/*
+ * Free up the underlying blocks past new_size.  The new size must be smaller
+ * than the current size.  This routine can be used both for the attribute and
+ * data fork, and does not modify the inode size, which is left to the caller.
+ *
+ * The transaction passed to this routine must have made a permanent log
+ * reservation of at least XFS_ITRUNCATE_LOG_RES.  This routine may commit the
+ * given transaction and start new ones, so make sure everything involved in
+ * the transaction is tidy before calling here.  Some transaction will be
+ * returned to the caller to be committed.  The incoming transaction must
+ * already include the inode, and both inode locks must be held exclusively.
+ * The inode must also be "held" within the transaction.  On return the inode
+ * will be "held" within the returned transaction.  This routine does NOT
+ * require any disk space to be reserved for it within the transaction.
+ *
+ * If we get an error, we must return with the inode locked and linked into the
+ * current transaction. This keeps things simple for the higher level code,
+ * because it always knows that the inode is locked and held in the transaction
+ * that returns to it whether errors occur or not.  We don't mark the inode
+ * dirty on error so that transactions can be easily aborted if possible.
+ */
+int
+xfs_itruncate_extents(
+       struct xfs_trans        **tpp,
+       struct xfs_inode        *ip,
+       int                     whichfork,
        xfs_fsize_t             new_size)
 {
        struct xfs_mount        *mp = ip->i_mount;
@@ -1572,37 +1544,299 @@ xfs_itruncate_extents(
                        goto out;
 
                /*
-                * Transaction commit worked ok so we can drop the extra ticket
-                * reference that we gained in xfs_trans_dup()
+                * Transaction commit worked ok so we can drop the extra ticket
+                * reference that we gained in xfs_trans_dup()
+                */
+               xfs_log_ticket_put(tp->t_ticket);
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+               if (error)
+                       goto out;
+       }
+
+       /*
+        * Always re-log the inode so that our permanent transaction can keep
+        * on rolling it forward in the log.
+        */
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+       trace_xfs_itruncate_extents_end(ip, new_size);
+
+out:
+       *tpp = tp;
+       return error;
+out_bmap_cancel:
+       /*
+        * If the bunmapi call encounters an error, return to the caller where
+        * the transaction can be properly aborted.  We just need to make sure
+        * we're not holding any resources that we were not when we came in.
+        */
+       xfs_bmap_cancel(&free_list);
+       goto out;
+}
+
+int
+xfs_release(
+       xfs_inode_t     *ip)
+{
+       xfs_mount_t     *mp = ip->i_mount;
+       int             error;
+
+       if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0))
+               return 0;
+
+       /* If this is a read-only mount, don't do this (would generate I/O) */
+       if (mp->m_flags & XFS_MOUNT_RDONLY)
+               return 0;
+
+       if (!XFS_FORCED_SHUTDOWN(mp)) {
+               int truncated;
+
+               /*
+                * If we are using filestreams, and we have an unlinked
+                * file that we are processing the last close on, then nothing
+                * will be able to reopen and write to this file. Purge this
+                * inode from the filestreams cache so that it doesn't delay
+                * teardown of the inode.
+                */
+               if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
+                       xfs_filestream_deassociate(ip);
+
+               /*
+                * If we previously truncated this file and removed old data
+                * in the process, we want to initiate "early" writeout on
+                * the last close.  This is an attempt to combat the notorious
+                * NULL files problem which is particularly noticeable from a
+                * truncate down, buffered (re-)write (delalloc), followed by
+                * a crash.  What we are effectively doing here is
+                * significantly reducing the time window where we'd otherwise
+                * be exposed to that problem.
+                */
+               truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
+               if (truncated) {
+                       xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
+                       if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) {
+                               error = -filemap_flush(VFS_I(ip)->i_mapping);
+                               if (error)
+                                       return error;
+                       }
+               }
+       }
+
+       if (ip->i_d.di_nlink == 0)
+               return 0;
+
+       if (xfs_can_free_eofblocks(ip, false)) {
+
+               /*
+                * If we can't get the iolock just skip truncating the blocks
+                * past EOF because we could deadlock with the mmap_sem
+                * otherwise.  We'll get another chance to drop them once the
+                * last reference to the inode is dropped, so we'll never leak
+                * blocks permanently.
+                *
+                * Further, check if the inode is being opened, written and
+                * closed frequently and we have delayed allocation blocks
+                * outstanding (e.g. streaming writes from the NFS server),
+                * truncating the blocks past EOF will cause fragmentation to
+                * occur.
+                *
+                * In this case don't do the truncation, either, but we have to
+                * be careful how we detect this case. Blocks beyond EOF show
+                * up as i_delayed_blks even when the inode is clean, so we
+                * need to truncate them away first before checking for a dirty
+                * release. Hence on the first dirty close we will still remove
+                * the speculative allocation, but after that we will leave it
+                * in place.
+                */
+               if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
+                       return 0;
+
+               error = xfs_free_eofblocks(mp, ip, true);
+               if (error && error != EAGAIN)
+                       return error;
+
+               /* delalloc blocks after truncation means it really is dirty */
+               if (ip->i_delayed_blks)
+                       xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
+       }
+       return 0;
+}
+
+/*
+ * xfs_inactive
+ *
+ * This is called when the vnode reference count for the vnode
+ * goes to zero.  If the file has been unlinked, then it must
+ * now be truncated.  Also, we clear all of the read-ahead state
+ * kept for the inode here since the file is now closed.
+ */
+int
+xfs_inactive(
+       xfs_inode_t     *ip)
+{
+       xfs_bmap_free_t         free_list;
+       xfs_fsblock_t           first_block;
+       int                     committed;
+       struct xfs_trans        *tp;
+       struct xfs_mount        *mp;
+       struct xfs_trans_res    *resp;
+       int                     error;
+       int                     truncate = 0;
+
+       /*
+        * If the inode is already free, then there can be nothing
+        * to clean up here.
+        */
+       if (ip->i_d.di_mode == 0 || is_bad_inode(VFS_I(ip))) {
+               ASSERT(ip->i_df.if_real_bytes == 0);
+               ASSERT(ip->i_df.if_broot_bytes == 0);
+               return VN_INACTIVE_CACHE;
+       }
+
+       mp = ip->i_mount;
+
+       error = 0;
+
+       /* If this is a read-only mount, don't do this (would generate I/O) */
+       if (mp->m_flags & XFS_MOUNT_RDONLY)
+               goto out;
+
+       if (ip->i_d.di_nlink != 0) {
+               /*
+                * force is true because we are evicting an inode from the
+                * cache. Post-eof blocks must be freed, lest we end up with
+                * broken free space accounting.
+                */
+               if (xfs_can_free_eofblocks(ip, true)) {
+                       error = xfs_free_eofblocks(mp, ip, false);
+                       if (error)
+                               return VN_INACTIVE_CACHE;
+               }
+               goto out;
+       }
+
+       if (S_ISREG(ip->i_d.di_mode) &&
+           (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
+            ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
+               truncate = 1;
+
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
+               return VN_INACTIVE_CACHE;
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
+       resp = (truncate || S_ISLNK(ip->i_d.di_mode)) ?
+               &M_RES(mp)->tr_itruncate : &M_RES(mp)->tr_ifree;
+
+       error = xfs_trans_reserve(tp, resp, 0, 0);
+       if (error) {
+               ASSERT(XFS_FORCED_SHUTDOWN(mp));
+               xfs_trans_cancel(tp, 0);
+               return VN_INACTIVE_CACHE;
+       }
+
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, 0);
+
+       if (S_ISLNK(ip->i_d.di_mode)) {
+               error = xfs_inactive_symlink(ip, &tp);
+               if (error)
+                       goto out_cancel;
+       } else if (truncate) {
+               ip->i_d.di_size = 0;
+               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+
+               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
+               if (error)
+                       goto out_cancel;
+
+               ASSERT(ip->i_d.di_nextents == 0);
+       }
+
+       /*
+        * If there are attributes associated with the file then blow them away
+        * now.  The code calls a routine that recursively deconstructs the
+        * attribute fork.  We need to just commit the current transaction
+        * because we can't use it for xfs_attr_inactive().
+        */
+       if (ip->i_d.di_anextents > 0) {
+               ASSERT(ip->i_d.di_forkoff != 0);
+
+               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+               if (error)
+                       goto out_unlock;
+
+               xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+               error = xfs_attr_inactive(ip);
+               if (error)
+                       goto out;
+
+               tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
+               if (error) {
+                       xfs_trans_cancel(tp, 0);
+                       goto out;
+               }
+
+               xfs_ilock(ip, XFS_ILOCK_EXCL);
+               xfs_trans_ijoin(tp, ip, 0);
+       }
+
+       if (ip->i_afp)
+               xfs_idestroy_fork(ip, XFS_ATTR_FORK);
+
+       ASSERT(ip->i_d.di_anextents == 0);
+
+       /*
+        * Free the inode.
+        */
+       xfs_bmap_init(&free_list, &first_block);
+       error = xfs_ifree(tp, ip, &free_list);
+       if (error) {
+               /*
+                * If we fail to free the inode, shut down.  The cancel
+                * might do that, we need to make sure.  Otherwise the
+                * inode might be lost for a long time or forever.
+                */
+               if (!XFS_FORCED_SHUTDOWN(mp)) {
+                       xfs_notice(mp, "%s: xfs_ifree returned error %d",
+                               __func__, error);
+                       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
+               }
+               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
+       } else {
+               /*
+                * Credit the quota account(s). The inode is gone.
+                */
+               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
+
+               /*
+                * Just ignore errors at this point.  There is nothing we can
+                * do except to try to keep going. Make sure it's not a silent
+                * error.
                 */
-               xfs_log_ticket_put(tp->t_ticket);
-               error = xfs_trans_reserve(tp, 0,
-                                       XFS_ITRUNCATE_LOG_RES(mp), 0,
-                                       XFS_TRANS_PERM_LOG_RES,
-                                       XFS_ITRUNCATE_LOG_COUNT);
+               error = xfs_bmap_finish(&tp,  &free_list, &committed);
                if (error)
-                       goto out;
+                       xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
+                               __func__, error);
+               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+               if (error)
+                       xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
+                               __func__, error);
        }
 
        /*
-        * Always re-log the inode so that our permanent transaction can keep
-        * on rolling it forward in the log.
+        * Release the dquots held by inode, if any.
         */
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-
-       trace_xfs_itruncate_extents_end(ip, new_size);
-
+       xfs_qm_dqdetach(ip);
+out_unlock:
+       xfs_iunlock(ip, XFS_ILOCK_EXCL);
 out:
-       *tpp = tp;
-       return error;
-out_bmap_cancel:
-       /*
-        * If the bunmapi call encounters an error, return to the caller where
-        * the transaction can be properly aborted.  We just need to make sure
-        * we're not holding any resources that we were not when we came in.
-        */
-       xfs_bmap_cancel(&free_list);
-       goto out;
+       return VN_INACTIVE_CACHE;
+out_cancel:
+       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+       goto out_unlock;
 }
 
 /*
@@ -1861,7 +2095,7 @@ xfs_iunlink_remove(
 }
 
 /*
- * A big issue when freeing the inode cluster is is that we _cannot_ skip any
+ * A big issue when freeing the inode cluster is that we _cannot_ skip any
  * inodes that are in memory - they all must be marked stale and attached to
  * the cluster buffer.
  */
@@ -2093,272 +2327,6 @@ xfs_ifree(
        return error;
 }
 
-/*
- * Reallocate the space for if_broot based on the number of records
- * being added or deleted as indicated in rec_diff.  Move the records
- * and pointers in if_broot to fit the new size.  When shrinking this
- * will eliminate holes between the records and pointers created by
- * the caller.  When growing this will create holes to be filled in
- * by the caller.
- *
- * The caller must not request to add more records than would fit in
- * the on-disk inode root.  If the if_broot is currently NULL, then
- * if we adding records one will be allocated.  The caller must also
- * not request that the number of records go below zero, although
- * it can go to zero.
- *
- * ip -- the inode whose if_broot area is changing
- * ext_diff -- the change in the number of records, positive or negative,
- *      requested for the if_broot array.
- */
-void
-xfs_iroot_realloc(
-       xfs_inode_t             *ip,
-       int                     rec_diff,
-       int                     whichfork)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       int                     cur_max;
-       xfs_ifork_t             *ifp;
-       struct xfs_btree_block  *new_broot;
-       int                     new_max;
-       size_t                  new_size;
-       char                    *np;
-       char                    *op;
-
-       /*
-        * Handle the degenerate case quietly.
-        */
-       if (rec_diff == 0) {
-               return;
-       }
-
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (rec_diff > 0) {
-               /*
-                * If there wasn't any memory allocated before, just
-                * allocate it now and get out.
-                */
-               if (ifp->if_broot_bytes == 0) {
-                       new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
-                       ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
-                       ifp->if_broot_bytes = (int)new_size;
-                       return;
-               }
-
-               /*
-                * If there is already an existing if_broot, then we need
-                * to realloc() it and shift the pointers to their new
-                * location.  The records don't change location because
-                * they are kept butted up against the btree block header.
-                */
-               cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
-               new_max = cur_max + rec_diff;
-               new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
-               ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
-                               XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max),
-                               KM_SLEEP | KM_NOFS);
-               op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
-                                                    ifp->if_broot_bytes);
-               np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
-                                                    (int)new_size);
-               ifp->if_broot_bytes = (int)new_size;
-               ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
-                       XFS_IFORK_SIZE(ip, whichfork));
-               memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
-               return;
-       }
-
-       /*
-        * rec_diff is less than 0.  In this case, we are shrinking the
-        * if_broot buffer.  It must already exist.  If we go to zero
-        * records, just get rid of the root and clear the status bit.
-        */
-       ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
-       cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
-       new_max = cur_max + rec_diff;
-       ASSERT(new_max >= 0);
-       if (new_max > 0)
-               new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
-       else
-               new_size = 0;
-       if (new_size > 0) {
-               new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
-               /*
-                * First copy over the btree block header.
-                */
-               memcpy(new_broot, ifp->if_broot,
-                       XFS_BMBT_BLOCK_LEN(ip->i_mount));
-       } else {
-               new_broot = NULL;
-               ifp->if_flags &= ~XFS_IFBROOT;
-       }
-
-       /*
-        * Only copy the records and pointers if there are any.
-        */
-       if (new_max > 0) {
-               /*
-                * First copy the records.
-                */
-               op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
-               np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
-               memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
-
-               /*
-                * Then copy the pointers.
-                */
-               op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
-                                                    ifp->if_broot_bytes);
-               np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
-                                                    (int)new_size);
-               memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
-       }
-       kmem_free(ifp->if_broot);
-       ifp->if_broot = new_broot;
-       ifp->if_broot_bytes = (int)new_size;
-       if (ifp->if_broot)
-               ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
-                       XFS_IFORK_SIZE(ip, whichfork));
-       return;
-}
-
-
-/*
- * This is called when the amount of space needed for if_data
- * is increased or decreased.  The change in size is indicated by
- * the number of bytes that need to be added or deleted in the
- * byte_diff parameter.
- *
- * If the amount of space needed has decreased below the size of the
- * inline buffer, then switch to using the inline buffer.  Otherwise,
- * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer
- * to what is needed.
- *
- * ip -- the inode whose if_data area is changing
- * byte_diff -- the change in the number of bytes, positive or negative,
- *      requested for the if_data array.
- */
-void
-xfs_idata_realloc(
-       xfs_inode_t     *ip,
-       int             byte_diff,
-       int             whichfork)
-{
-       xfs_ifork_t     *ifp;
-       int             new_size;
-       int             real_size;
-
-       if (byte_diff == 0) {
-               return;
-       }
-
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       new_size = (int)ifp->if_bytes + byte_diff;
-       ASSERT(new_size >= 0);
-
-       if (new_size == 0) {
-               if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
-                       kmem_free(ifp->if_u1.if_data);
-               }
-               ifp->if_u1.if_data = NULL;
-               real_size = 0;
-       } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) {
-               /*
-                * If the valid extents/data can fit in if_inline_ext/data,
-                * copy them from the malloc'd vector and free it.
-                */
-               if (ifp->if_u1.if_data == NULL) {
-                       ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
-               } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
-                       ASSERT(ifp->if_real_bytes != 0);
-                       memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
-                             new_size);
-                       kmem_free(ifp->if_u1.if_data);
-                       ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
-               }
-               real_size = 0;
-       } else {
-               /*
-                * Stuck with malloc/realloc.
-                * For inline data, the underlying buffer must be
-                * a multiple of 4 bytes in size so that it can be
-                * logged and stay on word boundaries.  We enforce
-                * that here.
-                */
-               real_size = roundup(new_size, 4);
-               if (ifp->if_u1.if_data == NULL) {
-                       ASSERT(ifp->if_real_bytes == 0);
-                       ifp->if_u1.if_data = kmem_alloc(real_size,
-                                                       KM_SLEEP | KM_NOFS);
-               } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
-                       /*
-                        * Only do the realloc if the underlying size
-                        * is really changing.
-                        */
-                       if (ifp->if_real_bytes != real_size) {
-                               ifp->if_u1.if_data =
-                                       kmem_realloc(ifp->if_u1.if_data,
-                                                       real_size,
-                                                       ifp->if_real_bytes,
-                                                       KM_SLEEP | KM_NOFS);
-                       }
-               } else {
-                       ASSERT(ifp->if_real_bytes == 0);
-                       ifp->if_u1.if_data = kmem_alloc(real_size,
-                                                       KM_SLEEP | KM_NOFS);
-                       memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
-                               ifp->if_bytes);
-               }
-       }
-       ifp->if_real_bytes = real_size;
-       ifp->if_bytes = new_size;
-       ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
-}
-
-void
-xfs_idestroy_fork(
-       xfs_inode_t     *ip,
-       int             whichfork)
-{
-       xfs_ifork_t     *ifp;
-
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       if (ifp->if_broot != NULL) {
-               kmem_free(ifp->if_broot);
-               ifp->if_broot = NULL;
-       }
-
-       /*
-        * If the format is local, then we can't have an extents
-        * array so just look for an inline data array.  If we're
-        * not local then we may or may not have an extents list,
-        * so check and free it up if we do.
-        */
-       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
-               if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
-                   (ifp->if_u1.if_data != NULL)) {
-                       ASSERT(ifp->if_real_bytes != 0);
-                       kmem_free(ifp->if_u1.if_data);
-                       ifp->if_u1.if_data = NULL;
-                       ifp->if_real_bytes = 0;
-               }
-       } else if ((ifp->if_flags & XFS_IFEXTENTS) &&
-                  ((ifp->if_flags & XFS_IFEXTIREC) ||
-                   ((ifp->if_u1.if_extents != NULL) &&
-                    (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) {
-               ASSERT(ifp->if_real_bytes != 0);
-               xfs_iext_destroy(ifp);
-       }
-       ASSERT(ifp->if_u1.if_extents == NULL ||
-              ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
-       ASSERT(ifp->if_real_bytes == 0);
-       if (whichfork == XFS_ATTR_FORK) {
-               kmem_zone_free(xfs_ifork_zone, ip->i_afp);
-               ip->i_afp = NULL;
-       }
-}
-
 /*
  * This is called to unpin an inode.  The caller must have the inode locked
  * in at least shared mode so that the buffer cannot be subsequently pinned
@@ -2402,162 +2370,471 @@ xfs_iunpin_wait(
                __xfs_iunpin_wait(ip);
 }
 
-/*
- * xfs_iextents_copy()
- *
- * This is called to copy the REAL extents (as opposed to the delayed
- * allocation extents) from the inode into the given buffer.  It
- * returns the number of bytes copied into the buffer.
- *
- * If there are no delayed allocation extents, then we can just
- * memcpy() the extents into the buffer.  Otherwise, we need to
- * examine each extent in turn and skip those which are delayed.
- */
 int
-xfs_iextents_copy(
-       xfs_inode_t             *ip,
-       xfs_bmbt_rec_t          *dp,
-       int                     whichfork)
+xfs_remove(
+       xfs_inode_t             *dp,
+       struct xfs_name         *name,
+       xfs_inode_t             *ip)
 {
-       int                     copied;
-       int                     i;
-       xfs_ifork_t             *ifp;
-       int                     nrecs;
-       xfs_fsblock_t           start_block;
+       xfs_mount_t             *mp = dp->i_mount;
+       xfs_trans_t             *tp = NULL;
+       int                     is_dir = S_ISDIR(ip->i_d.di_mode);
+       int                     error = 0;
+       xfs_bmap_free_t         free_list;
+       xfs_fsblock_t           first_block;
+       int                     cancel_flags;
+       int                     committed;
+       int                     link_zero;
+       uint                    resblks;
+       uint                    log_count;
 
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
-       ASSERT(ifp->if_bytes > 0);
+       trace_xfs_remove(dp, name);
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       error = xfs_qm_dqattach(dp, 0);
+       if (error)
+               goto std_return;
 
-       nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
-       ASSERT(nrecs > 0);
+       error = xfs_qm_dqattach(ip, 0);
+       if (error)
+               goto std_return;
+
+       if (is_dir) {
+               tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
+               log_count = XFS_DEFAULT_LOG_COUNT;
+       } else {
+               tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
+               log_count = XFS_REMOVE_LOG_COUNT;
+       }
+       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
 
        /*
-        * There are some delayed allocation extents in the
-        * inode, so copy the extents one at a time and skip
-        * the delayed ones.  There must be at least one
-        * non-delayed extent.
+        * We try to get the real space reservation first,
+        * allowing for directory btree deletion(s) implying
+        * possible bmap insert(s).  If we can't get the space
+        * reservation then we use 0 instead, and avoid the bmap
+        * btree insert(s) in the directory code by, if the bmap
+        * insert tries to happen, instead trimming the LAST
+        * block from the directory.
         */
-       copied = 0;
-       for (i = 0; i < nrecs; i++) {
-               xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
-               start_block = xfs_bmbt_get_startblock(ep);
-               if (isnullstartblock(start_block)) {
-                       /*
-                        * It's a delayed allocation extent, so skip it.
-                        */
-                       continue;
+       resblks = XFS_REMOVE_SPACE_RES(mp);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_remove, resblks, 0);
+       if (error == ENOSPC) {
+               resblks = 0;
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_remove, 0, 0);
+       }
+       if (error) {
+               ASSERT(error != ENOSPC);
+               cancel_flags = 0;
+               goto out_trans_cancel;
+       }
+
+       xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
+
+       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       /*
+        * If we're removing a directory perform some additional validation.
+        */
+       if (is_dir) {
+               ASSERT(ip->i_d.di_nlink >= 2);
+               if (ip->i_d.di_nlink != 2) {
+                       error = XFS_ERROR(ENOTEMPTY);
+                       goto out_trans_cancel;
                }
+               if (!xfs_dir_isempty(ip)) {
+                       error = XFS_ERROR(ENOTEMPTY);
+                       goto out_trans_cancel;
+               }
+       }
+
+       xfs_bmap_init(&free_list, &first_block);
+       error = xfs_dir_removename(tp, dp, name, ip->i_ino,
+                                       &first_block, &free_list, resblks);
+       if (error) {
+               ASSERT(error != ENOENT);
+               goto out_bmap_cancel;
+       }
+       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+
+       if (is_dir) {
+               /*
+                * Drop the link from ip's "..".
+                */
+               error = xfs_droplink(tp, dp);
+               if (error)
+                       goto out_bmap_cancel;
 
-               /* Translate to on disk format */
-               put_unaligned(cpu_to_be64(ep->l0), &dp->l0);
-               put_unaligned(cpu_to_be64(ep->l1), &dp->l1);
-               dp++;
-               copied++;
+               /*
+                * Drop the "." link from ip to self.
+                */
+               error = xfs_droplink(tp, ip);
+               if (error)
+                       goto out_bmap_cancel;
+       } else {
+               /*
+                * When removing a non-directory we need to log the parent
+                * inode here.  For a directory this is done implicitly
+                * by the xfs_droplink call for the ".." entry.
+                */
+               xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
        }
-       ASSERT(copied != 0);
-       xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip));
 
-       return (copied * (uint)sizeof(xfs_bmbt_rec_t));
+       /*
+        * Drop the link from dp to ip.
+        */
+       error = xfs_droplink(tp, ip);
+       if (error)
+               goto out_bmap_cancel;
+
+       /*
+        * Determine if this is the last link while
+        * we are in the transaction.
+        */
+       link_zero = (ip->i_d.di_nlink == 0);
+
+       /*
+        * If this is a synchronous mount, make sure that the
+        * remove transaction goes to disk before returning to
+        * the user.
+        */
+       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
+               xfs_trans_set_sync(tp);
+
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
+       if (error)
+               goto out_bmap_cancel;
+
+       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+       if (error)
+               goto std_return;
+
+       /*
+        * If we are using filestreams, kill the stream association.
+        * If the file is still open it may get a new one but that
+        * will get killed on last close in xfs_close() so we don't
+        * have to worry about that.
+        */
+       if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
+               xfs_filestream_deassociate(ip);
+
+       return 0;
+
+ out_bmap_cancel:
+       xfs_bmap_cancel(&free_list);
+       cancel_flags |= XFS_TRANS_ABORT;
+ out_trans_cancel:
+       xfs_trans_cancel(tp, cancel_flags);
+ std_return:
+       return error;
 }
 
 /*
- * Each of the following cases stores data into the same region
- * of the on-disk inode, so only one of them can be valid at
- * any given time. While it is possible to have conflicting formats
- * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is
- * in EXTENTS format, this can only happen when the fork has
- * changed formats after being modified but before being flushed.
- * In these cases, the format always takes precedence, because the
- * format indicates the current state of the fork.
+ * Enter all inodes for a rename transaction into a sorted array.
  */
-/*ARGSUSED*/
 STATIC void
-xfs_iflush_fork(
-       xfs_inode_t             *ip,
-       xfs_dinode_t            *dip,
-       xfs_inode_log_item_t    *iip,
-       int                     whichfork,
-       xfs_buf_t               *bp)
-{
-       char                    *cp;
-       xfs_ifork_t             *ifp;
-       xfs_mount_t             *mp;
-       static const short      brootflag[2] =
-               { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };
-       static const short      dataflag[2] =
-               { XFS_ILOG_DDATA, XFS_ILOG_ADATA };
-       static const short      extflag[2] =
-               { XFS_ILOG_DEXT, XFS_ILOG_AEXT };
-
-       if (!iip)
-               return;
-       ifp = XFS_IFORK_PTR(ip, whichfork);
-       /*
-        * This can happen if we gave up in iformat in an error path,
-        * for the attribute fork.
-        */
-       if (!ifp) {
-               ASSERT(whichfork == XFS_ATTR_FORK);
-               return;
-       }
-       cp = XFS_DFORK_PTR(dip, whichfork);
-       mp = ip->i_mount;
-       switch (XFS_IFORK_FORMAT(ip, whichfork)) {
-       case XFS_DINODE_FMT_LOCAL:
-               if ((iip->ili_fields & dataflag[whichfork]) &&
-                   (ifp->if_bytes > 0)) {
-                       ASSERT(ifp->if_u1.if_data != NULL);
-                       ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
-                       memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
+xfs_sort_for_rename(
+       xfs_inode_t     *dp1,   /* in: old (source) directory inode */
+       xfs_inode_t     *dp2,   /* in: new (target) directory inode */
+       xfs_inode_t     *ip1,   /* in: inode of old entry */
+       xfs_inode_t     *ip2,   /* in: inode of new entry, if it
+                                  already exists, NULL otherwise. */
+       xfs_inode_t     **i_tab,/* out: array of inode returned, sorted */
+       int             *num_inodes)  /* out: number of inodes in array */
+{
+       xfs_inode_t             *temp;
+       int                     i, j;
+
+       /*
+        * i_tab contains a list of pointers to inodes.  We initialize
+        * the table here & we'll sort it.  We will then use it to
+        * order the acquisition of the inode locks.
+        *
+        * Note that the table may contain duplicates.  e.g., dp1 == dp2.
+        */
+       i_tab[0] = dp1;
+       i_tab[1] = dp2;
+       i_tab[2] = ip1;
+       if (ip2) {
+               *num_inodes = 4;
+               i_tab[3] = ip2;
+       } else {
+               *num_inodes = 3;
+               i_tab[3] = NULL;
+       }
+
+       /*
+        * Sort the elements via bubble sort.  (Remember, there are at
+        * most 4 elements to sort, so this is adequate.)
+        */
+       for (i = 0; i < *num_inodes; i++) {
+               for (j = 1; j < *num_inodes; j++) {
+                       if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) {
+                               temp = i_tab[j];
+                               i_tab[j] = i_tab[j-1];
+                               i_tab[j-1] = temp;
+                       }
                }
-               break;
+       }
+}
+
+/*
+ * xfs_rename
+ */
+int
+xfs_rename(
+       xfs_inode_t     *src_dp,
+       struct xfs_name *src_name,
+       xfs_inode_t     *src_ip,
+       xfs_inode_t     *target_dp,
+       struct xfs_name *target_name,
+       xfs_inode_t     *target_ip)
+{
+       xfs_trans_t     *tp = NULL;
+       xfs_mount_t     *mp = src_dp->i_mount;
+       int             new_parent;             /* moving to a new dir */
+       int             src_is_directory;       /* src_name is a directory */
+       int             error;
+       xfs_bmap_free_t free_list;
+       xfs_fsblock_t   first_block;
+       int             cancel_flags;
+       int             committed;
+       xfs_inode_t     *inodes[4];
+       int             spaceres;
+       int             num_inodes;
+
+       trace_xfs_rename(src_dp, target_dp, src_name, target_name);
+
+       new_parent = (src_dp != target_dp);
+       src_is_directory = S_ISDIR(src_ip->i_d.di_mode);
+
+       xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip,
+                               inodes, &num_inodes);
+
+       xfs_bmap_init(&free_list, &first_block);
+       tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
+       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
+       spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, spaceres, 0);
+       if (error == ENOSPC) {
+               spaceres = 0;
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_rename, 0, 0);
+       }
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               goto std_return;
+       }
+
+       /*
+        * Attach the dquots to the inodes
+        */
+       error = xfs_qm_vop_rename_dqattach(inodes);
+       if (error) {
+               xfs_trans_cancel(tp, cancel_flags);
+               goto std_return;
+       }
+
+       /*
+        * Lock all the participating inodes. Depending upon whether
+        * the target_name exists in the target directory, and
+        * whether the target directory is the same as the source
+        * directory, we can lock from 2 to 4 inodes.
+        */
+       xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
+
+       /*
+        * Join all the inodes to the transaction. From this point on,
+        * we can rely on either trans_commit or trans_cancel to unlock
+        * them.
+        */
+       xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
+       if (new_parent)
+               xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
+       if (target_ip)
+               xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
+
+       /*
+        * If we are using project inheritance, we only allow renames
+        * into our tree when the project IDs are the same; else the
+        * tree quota mechanism would be circumvented.
+        */
+       if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
+                    (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
+               error = XFS_ERROR(EXDEV);
+               goto error_return;
+       }
+
+       /*
+        * Set up the target.
+        */
+       if (target_ip == NULL) {
+               /*
+                * If there's no space reservation, check the entry will
+                * fit before actually inserting it.
+                */
+               error = xfs_dir_canenter(tp, target_dp, target_name, spaceres);
+               if (error)
+                       goto error_return;
+               /*
+                * If target does not exist and the rename crosses
+                * directories, adjust the target directory link count
+                * to account for the ".." reference from the new entry.
+                */
+               error = xfs_dir_createname(tp, target_dp, target_name,
+                                               src_ip->i_ino, &first_block,
+                                               &free_list, spaceres);
+               if (error == ENOSPC)
+                       goto error_return;
+               if (error)
+                       goto abort_return;
+
+               xfs_trans_ichgtime(tp, target_dp,
+                                       XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
-       case XFS_DINODE_FMT_EXTENTS:
-               ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
-                      !(iip->ili_fields & extflag[whichfork]));
-               if ((iip->ili_fields & extflag[whichfork]) &&
-                   (ifp->if_bytes > 0)) {
-                       ASSERT(xfs_iext_get_ext(ifp, 0));
-                       ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
-                       (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
-                               whichfork);
+               if (new_parent && src_is_directory) {
+                       error = xfs_bumplink(tp, target_dp);
+                       if (error)
+                               goto abort_return;
                }
-               break;
+       } else { /* target_ip != NULL */
+               /*
+                * If target exists and it's a directory, check that both
+                * target and source are directories and that target can be
+                * destroyed, or that neither is a directory.
+                */
+               if (S_ISDIR(target_ip->i_d.di_mode)) {
+                       /*
+                        * Make sure target dir is empty.
+                        */
+                       if (!(xfs_dir_isempty(target_ip)) ||
+                           (target_ip->i_d.di_nlink > 2)) {
+                               error = XFS_ERROR(EEXIST);
+                               goto error_return;
+                       }
+               }
+
+               /*
+                * Link the source inode under the target name.
+                * If the source inode is a directory and we are moving
+                * it across directories, its ".." entry will be
+                * inconsistent until we replace that down below.
+                *
+                * In case there is already an entry with the same
+                * name at the destination directory, remove it first.
+                */
+               error = xfs_dir_replace(tp, target_dp, target_name,
+                                       src_ip->i_ino,
+                                       &first_block, &free_list, spaceres);
+               if (error)
+                       goto abort_return;
+
+               xfs_trans_ichgtime(tp, target_dp,
+                                       XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+
+               /*
+                * Decrement the link count on the target since the target
+                * dir no longer points to it.
+                */
+               error = xfs_droplink(tp, target_ip);
+               if (error)
+                       goto abort_return;
+
+               if (src_is_directory) {
+                       /*
+                        * Drop the link from the old "." entry.
+                        */
+                       error = xfs_droplink(tp, target_ip);
+                       if (error)
+                               goto abort_return;
+               }
+       } /* target_ip != NULL */
+
+       /*
+        * Remove the source.
+        */
+       if (new_parent && src_is_directory) {
+               /*
+                * Rewrite the ".." entry to point to the new
+                * directory.
+                */
+               error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
+                                       target_dp->i_ino,
+                                       &first_block, &free_list, spaceres);
+               ASSERT(error != EEXIST);
+               if (error)
+                       goto abort_return;
+       }
+
+       /*
+        * We always want to hit the ctime on the source inode.
+        *
+        * This isn't strictly required by the standards since the source
+        * inode isn't really being changed, but old unix file systems did
+        * it and some incremental backup programs won't work without it.
+        */
+       xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE);
+
+       /*
+        * Adjust the link count on src_dp.  This is necessary when
+        * renaming a directory, either within one parent when
+        * the target existed, or across two parent directories.
+        */
+       if (src_is_directory && (new_parent || target_ip != NULL)) {
+
+               /*
+                * Decrement link count on src_directory since the
+                * entry that's moved no longer points to it.
+                */
+               error = xfs_droplink(tp, src_dp);
+               if (error)
+                       goto abort_return;
+       }
 
-       case XFS_DINODE_FMT_BTREE:
-               if ((iip->ili_fields & brootflag[whichfork]) &&
-                   (ifp->if_broot_bytes > 0)) {
-                       ASSERT(ifp->if_broot != NULL);
-                       ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
-                               XFS_IFORK_SIZE(ip, whichfork));
-                       xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
-                               (xfs_bmdr_block_t *)cp,
-                               XFS_DFORK_SIZE(dip, mp, whichfork));
-               }
-               break;
+       error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
+                                       &first_block, &free_list, spaceres);
+       if (error)
+               goto abort_return;
 
-       case XFS_DINODE_FMT_DEV:
-               if (iip->ili_fields & XFS_ILOG_DEV) {
-                       ASSERT(whichfork == XFS_DATA_FORK);
-                       xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
-               }
-               break;
+       xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+       xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
+       if (new_parent)
+               xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
 
-       case XFS_DINODE_FMT_UUID:
-               if (iip->ili_fields & XFS_ILOG_UUID) {
-                       ASSERT(whichfork == XFS_DATA_FORK);
-                       memcpy(XFS_DFORK_DPTR(dip),
-                              &ip->i_df.if_u2.if_uuid,
-                              sizeof(uuid_t));
-               }
-               break;
+       /*
+        * If this is a synchronous mount, make sure that the
+        * rename transaction goes to disk before returning to
+        * the user.
+        */
+       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
+               xfs_trans_set_sync(tp);
+       }
 
-       default:
-               ASSERT(0);
-               break;
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
+       if (error) {
+               xfs_bmap_cancel(&free_list);
+               xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
+                                XFS_TRANS_ABORT));
+               goto std_return;
        }
+
+       /*
+        * trans_commit will unlock src_ip, target_ip & decrement
+        * the vnode references.
+        */
+       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
+
+ abort_return:
+       cancel_flags |= XFS_TRANS_ABORT;
+ error_return:
+       xfs_bmap_cancel(&free_list);
+       xfs_trans_cancel(tp, cancel_flags);
+ std_return:
+       return error;
 }
 
 STATIC int
@@ -2816,7 +3093,6 @@ abort_out:
        return error;
 }
 
-
 STATIC int
 xfs_iflush_int(
        struct xfs_inode        *ip,
@@ -3004,1072 +3280,3 @@ xfs_iflush_int(
 corrupt_out:
        return XFS_ERROR(EFSCORRUPTED);
 }
-
-/*
- * Return a pointer to the extent record at file index idx.
- */
-xfs_bmbt_rec_host_t *
-xfs_iext_get_ext(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    idx)            /* index of target extent */
-{
-       ASSERT(idx >= 0);
-       ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
-
-       if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
-               return ifp->if_u1.if_ext_irec->er_extbuf;
-       } else if (ifp->if_flags & XFS_IFEXTIREC) {
-               xfs_ext_irec_t  *erp;           /* irec pointer */
-               int             erp_idx = 0;    /* irec index */
-               xfs_extnum_t    page_idx = idx; /* ext index in target list */
-
-               erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
-               return &erp->er_extbuf[page_idx];
-       } else if (ifp->if_bytes) {
-               return &ifp->if_u1.if_extents[idx];
-       } else {
-               return NULL;
-       }
-}
-
-/*
- * Insert new item(s) into the extent records for incore inode
- * fork 'ifp'.  'count' new items are inserted at index 'idx'.
- */
-void
-xfs_iext_insert(
-       xfs_inode_t     *ip,            /* incore inode pointer */
-       xfs_extnum_t    idx,            /* starting index of new items */
-       xfs_extnum_t    count,          /* number of inserted items */
-       xfs_bmbt_irec_t *new,           /* items to insert */
-       int             state)          /* type of extent conversion */
-{
-       xfs_ifork_t     *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
-       xfs_extnum_t    i;              /* extent record index */
-
-       trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_);
-
-       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
-       xfs_iext_add(ifp, idx, count);
-       for (i = idx; i < idx + count; i++, new++)
-               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new);
-}
-
-/*
- * This is called when the amount of space required for incore file
- * extents needs to be increased. The ext_diff parameter stores the
- * number of new extents being added and the idx parameter contains
- * the extent index where the new extents will be added. If the new
- * extents are being appended, then we just need to (re)allocate and
- * initialize the space. Otherwise, if the new extents are being
- * inserted into the middle of the existing entries, a bit more work
- * is required to make room for the new extents to be inserted. The
- * caller is responsible for filling in the new extent entries upon
- * return.
- */
-void
-xfs_iext_add(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    idx,            /* index to begin adding exts */
-       int             ext_diff)       /* number of extents to add */
-{
-       int             byte_diff;      /* new bytes being added */
-       int             new_size;       /* size of extents after adding */
-       xfs_extnum_t    nextents;       /* number of extents in file */
-
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       ASSERT((idx >= 0) && (idx <= nextents));
-       byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
-       new_size = ifp->if_bytes + byte_diff;
-       /*
-        * If the new number of extents (nextents + ext_diff)
-        * fits inside the inode, then continue to use the inline
-        * extent buffer.
-        */
-       if (nextents + ext_diff <= XFS_INLINE_EXTS) {
-               if (idx < nextents) {
-                       memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
-                               &ifp->if_u2.if_inline_ext[idx],
-                               (nextents - idx) * sizeof(xfs_bmbt_rec_t));
-                       memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
-               }
-               ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
-               ifp->if_real_bytes = 0;
-       }
-       /*
-        * Otherwise use a linear (direct) extent list.
-        * If the extents are currently inside the inode,
-        * xfs_iext_realloc_direct will switch us from
-        * inline to direct extent allocation mode.
-        */
-       else if (nextents + ext_diff <= XFS_LINEAR_EXTS) {
-               xfs_iext_realloc_direct(ifp, new_size);
-               if (idx < nextents) {
-                       memmove(&ifp->if_u1.if_extents[idx + ext_diff],
-                               &ifp->if_u1.if_extents[idx],
-                               (nextents - idx) * sizeof(xfs_bmbt_rec_t));
-                       memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
-               }
-       }
-       /* Indirection array */
-       else {
-               xfs_ext_irec_t  *erp;
-               int             erp_idx = 0;
-               int             page_idx = idx;
-
-               ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS);
-               if (ifp->if_flags & XFS_IFEXTIREC) {
-                       erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1);
-               } else {
-                       xfs_iext_irec_init(ifp);
-                       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-                       erp = ifp->if_u1.if_ext_irec;
-               }
-               /* Extents fit in target extent page */
-               if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) {
-                       if (page_idx < erp->er_extcount) {
-                               memmove(&erp->er_extbuf[page_idx + ext_diff],
-                                       &erp->er_extbuf[page_idx],
-                                       (erp->er_extcount - page_idx) *
-                                       sizeof(xfs_bmbt_rec_t));
-                               memset(&erp->er_extbuf[page_idx], 0, byte_diff);
-                       }
-                       erp->er_extcount += ext_diff;
-                       xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
-               }
-               /* Insert a new extent page */
-               else if (erp) {
-                       xfs_iext_add_indirect_multi(ifp,
-                               erp_idx, page_idx, ext_diff);
-               }
-               /*
-                * If extent(s) are being appended to the last page in
-                * the indirection array and the new extent(s) don't fit
-                * in the page, then erp is NULL and erp_idx is set to
-                * the next index needed in the indirection array.
-                */
-               else {
-                       int     count = ext_diff;
-
-                       while (count) {
-                               erp = xfs_iext_irec_new(ifp, erp_idx);
-                               erp->er_extcount = count;
-                               count -= MIN(count, (int)XFS_LINEAR_EXTS);
-                               if (count) {
-                                       erp_idx++;
-                               }
-                       }
-               }
-       }
-       ifp->if_bytes = new_size;
-}
-
-/*
- * This is called when incore extents are being added to the indirection
- * array and the new extents do not fit in the target extent list. The
- * erp_idx parameter contains the irec index for the target extent list
- * in the indirection array, and the idx parameter contains the extent
- * index within the list. The number of extents being added is stored
- * in the count parameter.
- *
- *    |-------|   |-------|
- *    |       |   |       |    idx - number of extents before idx
- *    |  idx  |   | count |
- *    |       |   |       |    count - number of extents being inserted at idx
- *    |-------|   |-------|
- *    | count |   | nex2  |    nex2 - number of extents after idx + count
- *    |-------|   |-------|
- */
-void
-xfs_iext_add_indirect_multi(
-       xfs_ifork_t     *ifp,                   /* inode fork pointer */
-       int             erp_idx,                /* target extent irec index */
-       xfs_extnum_t    idx,                    /* index within target list */
-       int             count)                  /* new extents being added */
-{
-       int             byte_diff;              /* new bytes being added */
-       xfs_ext_irec_t  *erp;                   /* pointer to irec entry */
-       xfs_extnum_t    ext_diff;               /* number of extents to add */
-       xfs_extnum_t    ext_cnt;                /* new extents still needed */
-       xfs_extnum_t    nex2;                   /* extents after idx + count */
-       xfs_bmbt_rec_t  *nex2_ep = NULL;        /* temp list for nex2 extents */
-       int             nlists;                 /* number of irec's (lists) */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       erp = &ifp->if_u1.if_ext_irec[erp_idx];
-       nex2 = erp->er_extcount - idx;
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-
-       /*
-        * Save second part of target extent list
-        * (all extents past */
-       if (nex2) {
-               byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
-               nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS);
-               memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff);
-               erp->er_extcount -= nex2;
-               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2);
-               memset(&erp->er_extbuf[idx], 0, byte_diff);
-       }
-
-       /*
-        * Add the new extents to the end of the target
-        * list, then allocate new irec record(s) and
-        * extent buffer(s) as needed to store the rest
-        * of the new extents.
-        */
-       ext_cnt = count;
-       ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount);
-       if (ext_diff) {
-               erp->er_extcount += ext_diff;
-               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
-               ext_cnt -= ext_diff;
-       }
-       while (ext_cnt) {
-               erp_idx++;
-               erp = xfs_iext_irec_new(ifp, erp_idx);
-               ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS);
-               erp->er_extcount = ext_diff;
-               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
-               ext_cnt -= ext_diff;
-       }
-
-       /* Add nex2 extents back to indirection array */
-       if (nex2) {
-               xfs_extnum_t    ext_avail;
-               int             i;
-
-               byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
-               ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
-               i = 0;
-               /*
-                * If nex2 extents fit in the current page, append
-                * nex2_ep after the new extents.
-                */
-               if (nex2 <= ext_avail) {
-                       i = erp->er_extcount;
-               }
-               /*
-                * Otherwise, check if space is available in the
-                * next page.
-                */
-               else if ((erp_idx < nlists - 1) &&
-                        (nex2 <= (ext_avail = XFS_LINEAR_EXTS -
-                         ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) {
-                       erp_idx++;
-                       erp++;
-                       /* Create a hole for nex2 extents */
-                       memmove(&erp->er_extbuf[nex2], erp->er_extbuf,
-                               erp->er_extcount * sizeof(xfs_bmbt_rec_t));
-               }
-               /*
-                * Final choice, create a new extent page for
-                * nex2 extents.
-                */
-               else {
-                       erp_idx++;
-                       erp = xfs_iext_irec_new(ifp, erp_idx);
-               }
-               memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
-               kmem_free(nex2_ep);
-               erp->er_extcount += nex2;
-               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
-       }
-}
-
-/*
- * This is called when the amount of space required for incore file
- * extents needs to be decreased. The ext_diff parameter stores the
- * number of extents to be removed and the idx parameter contains
- * the extent index where the extents will be removed from.
- *
- * If the amount of space needed has decreased below the linear
- * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous
- * extent array.  Otherwise, use kmem_realloc() to adjust the
- * size to what is needed.
- */
-void
-xfs_iext_remove(
-       xfs_inode_t     *ip,            /* incore inode pointer */
-       xfs_extnum_t    idx,            /* index to begin removing exts */
-       int             ext_diff,       /* number of extents to remove */
-       int             state)          /* type of extent conversion */
-{
-       xfs_ifork_t     *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
-       xfs_extnum_t    nextents;       /* number of extents in file */
-       int             new_size;       /* size of extents after removal */
-
-       trace_xfs_iext_remove(ip, idx, state, _RET_IP_);
-
-       ASSERT(ext_diff > 0);
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
-
-       if (new_size == 0) {
-               xfs_iext_destroy(ifp);
-       } else if (ifp->if_flags & XFS_IFEXTIREC) {
-               xfs_iext_remove_indirect(ifp, idx, ext_diff);
-       } else if (ifp->if_real_bytes) {
-               xfs_iext_remove_direct(ifp, idx, ext_diff);
-       } else {
-               xfs_iext_remove_inline(ifp, idx, ext_diff);
-       }
-       ifp->if_bytes = new_size;
-}
-
-/*
- * This removes ext_diff extents from the inline buffer, beginning
- * at extent index idx.
- */
-void
-xfs_iext_remove_inline(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    idx,            /* index to begin removing exts */
-       int             ext_diff)       /* number of extents to remove */
-{
-       int             nextents;       /* number of extents in file */
-
-       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
-       ASSERT(idx < XFS_INLINE_EXTS);
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       ASSERT(((nextents - ext_diff) > 0) &&
-               (nextents - ext_diff) < XFS_INLINE_EXTS);
-
-       if (idx + ext_diff < nextents) {
-               memmove(&ifp->if_u2.if_inline_ext[idx],
-                       &ifp->if_u2.if_inline_ext[idx + ext_diff],
-                       (nextents - (idx + ext_diff)) *
-                        sizeof(xfs_bmbt_rec_t));
-               memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
-                       0, ext_diff * sizeof(xfs_bmbt_rec_t));
-       } else {
-               memset(&ifp->if_u2.if_inline_ext[idx], 0,
-                       ext_diff * sizeof(xfs_bmbt_rec_t));
-       }
-}
-
-/*
- * This removes ext_diff extents from a linear (direct) extent list,
- * beginning at extent index idx. If the extents are being removed
- * from the end of the list (ie. truncate) then we just need to re-
- * allocate the list to remove the extra space. Otherwise, if the
- * extents are being removed from the middle of the existing extent
- * entries, then we first need to move the extent records beginning
- * at idx + ext_diff up in the list to overwrite the records being
- * removed, then remove the extra space via kmem_realloc.
- */
-void
-xfs_iext_remove_direct(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    idx,            /* index to begin removing exts */
-       int             ext_diff)       /* number of extents to remove */
-{
-       xfs_extnum_t    nextents;       /* number of extents in file */
-       int             new_size;       /* size of extents after removal */
-
-       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
-       new_size = ifp->if_bytes -
-               (ext_diff * sizeof(xfs_bmbt_rec_t));
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-
-       if (new_size == 0) {
-               xfs_iext_destroy(ifp);
-               return;
-       }
-       /* Move extents up in the list (if needed) */
-       if (idx + ext_diff < nextents) {
-               memmove(&ifp->if_u1.if_extents[idx],
-                       &ifp->if_u1.if_extents[idx + ext_diff],
-                       (nextents - (idx + ext_diff)) *
-                        sizeof(xfs_bmbt_rec_t));
-       }
-       memset(&ifp->if_u1.if_extents[nextents - ext_diff],
-               0, ext_diff * sizeof(xfs_bmbt_rec_t));
-       /*
-        * Reallocate the direct extent list. If the extents
-        * will fit inside the inode then xfs_iext_realloc_direct
-        * will switch from direct to inline extent allocation
-        * mode for us.
-        */
-       xfs_iext_realloc_direct(ifp, new_size);
-       ifp->if_bytes = new_size;
-}
-
-/*
- * This is called when incore extents are being removed from the
- * indirection array and the extents being removed span multiple extent
- * buffers. The idx parameter contains the file extent index where we
- * want to begin removing extents, and the count parameter contains
- * how many extents need to be removed.
- *
- *    |-------|   |-------|
- *    | nex1  |   |       |    nex1 - number of extents before idx
- *    |-------|   | count |
- *    |       |   |       |    count - number of extents being removed at idx
- *    | count |   |-------|
- *    |       |   | nex2  |    nex2 - number of extents after idx + count
- *    |-------|   |-------|
- */
-void
-xfs_iext_remove_indirect(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    idx,            /* index to begin removing extents */
-       int             count)          /* number of extents to remove */
-{
-       xfs_ext_irec_t  *erp;           /* indirection array pointer */
-       int             erp_idx = 0;    /* indirection array index */
-       xfs_extnum_t    ext_cnt;        /* extents left to remove */
-       xfs_extnum_t    ext_diff;       /* extents to remove in current list */
-       xfs_extnum_t    nex1;           /* number of extents before idx */
-       xfs_extnum_t    nex2;           /* extents after idx + count */
-       int             page_idx = idx; /* index in target extent list */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       erp = xfs_iext_idx_to_irec(ifp,  &page_idx, &erp_idx, 0);
-       ASSERT(erp != NULL);
-       nex1 = page_idx;
-       ext_cnt = count;
-       while (ext_cnt) {
-               nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0);
-               ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1));
-               /*
-                * Check for deletion of entire list;
-                * xfs_iext_irec_remove() updates extent offsets.
-                */
-               if (ext_diff == erp->er_extcount) {
-                       xfs_iext_irec_remove(ifp, erp_idx);
-                       ext_cnt -= ext_diff;
-                       nex1 = 0;
-                       if (ext_cnt) {
-                               ASSERT(erp_idx < ifp->if_real_bytes /
-                                       XFS_IEXT_BUFSZ);
-                               erp = &ifp->if_u1.if_ext_irec[erp_idx];
-                               nex1 = 0;
-                               continue;
-                       } else {
-                               break;
-                       }
-               }
-               /* Move extents up (if needed) */
-               if (nex2) {
-                       memmove(&erp->er_extbuf[nex1],
-                               &erp->er_extbuf[nex1 + ext_diff],
-                               nex2 * sizeof(xfs_bmbt_rec_t));
-               }
-               /* Zero out rest of page */
-               memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ -
-                       ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t))));
-               /* Update remaining counters */
-               erp->er_extcount -= ext_diff;
-               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff);
-               ext_cnt -= ext_diff;
-               nex1 = 0;
-               erp_idx++;
-               erp++;
-       }
-       ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t);
-       xfs_iext_irec_compact(ifp);
-}
-
-/*
- * Create, destroy, or resize a linear (direct) block of extents.
- */
-void
-xfs_iext_realloc_direct(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       int             new_size)       /* new size of extents */
-{
-       int             rnew_size;      /* real new size of extents */
-
-       rnew_size = new_size;
-
-       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) ||
-               ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) &&
-                (new_size != ifp->if_real_bytes)));
-
-       /* Free extent records */
-       if (new_size == 0) {
-               xfs_iext_destroy(ifp);
-       }
-       /* Resize direct extent list and zero any new bytes */
-       else if (ifp->if_real_bytes) {
-               /* Check if extents will fit inside the inode */
-               if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
-                       xfs_iext_direct_to_inline(ifp, new_size /
-                               (uint)sizeof(xfs_bmbt_rec_t));
-                       ifp->if_bytes = new_size;
-                       return;
-               }
-               if (!is_power_of_2(new_size)){
-                       rnew_size = roundup_pow_of_two(new_size);
-               }
-               if (rnew_size != ifp->if_real_bytes) {
-                       ifp->if_u1.if_extents =
-                               kmem_realloc(ifp->if_u1.if_extents,
-                                               rnew_size,
-                                               ifp->if_real_bytes, KM_NOFS);
-               }
-               if (rnew_size > ifp->if_real_bytes) {
-                       memset(&ifp->if_u1.if_extents[ifp->if_bytes /
-                               (uint)sizeof(xfs_bmbt_rec_t)], 0,
-                               rnew_size - ifp->if_real_bytes);
-               }
-       }
-       /*
-        * Switch from the inline extent buffer to a direct
-        * extent list. Be sure to include the inline extent
-        * bytes in new_size.
-        */
-       else {
-               new_size += ifp->if_bytes;
-               if (!is_power_of_2(new_size)) {
-                       rnew_size = roundup_pow_of_two(new_size);
-               }
-               xfs_iext_inline_to_direct(ifp, rnew_size);
-       }
-       ifp->if_real_bytes = rnew_size;
-       ifp->if_bytes = new_size;
-}
-
-/*
- * Switch from linear (direct) extent records to inline buffer.
- */
-void
-xfs_iext_direct_to_inline(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    nextents)       /* number of extents in file */
-{
-       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
-       ASSERT(nextents <= XFS_INLINE_EXTS);
-       /*
-        * The inline buffer was zeroed when we switched
-        * from inline to direct extent allocation mode,
-        * so we don't need to clear it here.
-        */
-       memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
-               nextents * sizeof(xfs_bmbt_rec_t));
-       kmem_free(ifp->if_u1.if_extents);
-       ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
-       ifp->if_real_bytes = 0;
-}
-
-/*
- * Switch from inline buffer to linear (direct) extent records.
- * new_size should already be rounded up to the next power of 2
- * by the caller (when appropriate), so use new_size as it is.
- * However, since new_size may be rounded up, we can't update
- * if_bytes here. It is the caller's responsibility to update
- * if_bytes upon return.
- */
-void
-xfs_iext_inline_to_direct(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       int             new_size)       /* number of extents in file */
-{
-       ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS);
-       memset(ifp->if_u1.if_extents, 0, new_size);
-       if (ifp->if_bytes) {
-               memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
-                       ifp->if_bytes);
-               memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
-                       sizeof(xfs_bmbt_rec_t));
-       }
-       ifp->if_real_bytes = new_size;
-}
-
-/*
- * Resize an extent indirection array to new_size bytes.
- */
-STATIC void
-xfs_iext_realloc_indirect(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       int             new_size)       /* new indirection array size */
-{
-       int             nlists;         /* number of irec's (ex lists) */
-       int             size;           /* current indirection array size */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       size = nlists * sizeof(xfs_ext_irec_t);
-       ASSERT(ifp->if_real_bytes);
-       ASSERT((new_size >= 0) && (new_size != size));
-       if (new_size == 0) {
-               xfs_iext_destroy(ifp);
-       } else {
-               ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *)
-                       kmem_realloc(ifp->if_u1.if_ext_irec,
-                               new_size, size, KM_NOFS);
-       }
-}
-
-/*
- * Switch from indirection array to linear (direct) extent allocations.
- */
-STATIC void
-xfs_iext_indirect_to_direct(
-        xfs_ifork_t    *ifp)           /* inode fork pointer */
-{
-       xfs_bmbt_rec_host_t *ep;        /* extent record pointer */
-       xfs_extnum_t    nextents;       /* number of extents in file */
-       int             size;           /* size of file extents */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       ASSERT(nextents <= XFS_LINEAR_EXTS);
-       size = nextents * sizeof(xfs_bmbt_rec_t);
-
-       xfs_iext_irec_compact_pages(ifp);
-       ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
-
-       ep = ifp->if_u1.if_ext_irec->er_extbuf;
-       kmem_free(ifp->if_u1.if_ext_irec);
-       ifp->if_flags &= ~XFS_IFEXTIREC;
-       ifp->if_u1.if_extents = ep;
-       ifp->if_bytes = size;
-       if (nextents < XFS_LINEAR_EXTS) {
-               xfs_iext_realloc_direct(ifp, size);
-       }
-}
-
-/*
- * Free incore file extents.
- */
-void
-xfs_iext_destroy(
-       xfs_ifork_t     *ifp)           /* inode fork pointer */
-{
-       if (ifp->if_flags & XFS_IFEXTIREC) {
-               int     erp_idx;
-               int     nlists;
-
-               nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-               for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) {
-                       xfs_iext_irec_remove(ifp, erp_idx);
-               }
-               ifp->if_flags &= ~XFS_IFEXTIREC;
-       } else if (ifp->if_real_bytes) {
-               kmem_free(ifp->if_u1.if_extents);
-       } else if (ifp->if_bytes) {
-               memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
-                       sizeof(xfs_bmbt_rec_t));
-       }
-       ifp->if_u1.if_extents = NULL;
-       ifp->if_real_bytes = 0;
-       ifp->if_bytes = 0;
-}
-
-/*
- * Return a pointer to the extent record for file system block bno.
- */
-xfs_bmbt_rec_host_t *                  /* pointer to found extent record */
-xfs_iext_bno_to_ext(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_fileoff_t   bno,            /* block number to search for */
-       xfs_extnum_t    *idxp)          /* index of target extent */
-{
-       xfs_bmbt_rec_host_t *base;      /* pointer to first extent */
-       xfs_filblks_t   blockcount = 0; /* number of blocks in extent */
-       xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */
-       xfs_ext_irec_t  *erp = NULL;    /* indirection array pointer */
-       int             high;           /* upper boundary in search */
-       xfs_extnum_t    idx = 0;        /* index of target extent */
-       int             low;            /* lower boundary in search */
-       xfs_extnum_t    nextents;       /* number of file extents */
-       xfs_fileoff_t   startoff = 0;   /* start offset of extent */
-
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       if (nextents == 0) {
-               *idxp = 0;
-               return NULL;
-       }
-       low = 0;
-       if (ifp->if_flags & XFS_IFEXTIREC) {
-               /* Find target extent list */
-               int     erp_idx = 0;
-               erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
-               base = erp->er_extbuf;
-               high = erp->er_extcount - 1;
-       } else {
-               base = ifp->if_u1.if_extents;
-               high = nextents - 1;
-       }
-       /* Binary search extent records */
-       while (low <= high) {
-               idx = (low + high) >> 1;
-               ep = base + idx;
-               startoff = xfs_bmbt_get_startoff(ep);
-               blockcount = xfs_bmbt_get_blockcount(ep);
-               if (bno < startoff) {
-                       high = idx - 1;
-               } else if (bno >= startoff + blockcount) {
-                       low = idx + 1;
-               } else {
-                       /* Convert back to file-based extent index */
-                       if (ifp->if_flags & XFS_IFEXTIREC) {
-                               idx += erp->er_extoff;
-                       }
-                       *idxp = idx;
-                       return ep;
-               }
-       }
-       /* Convert back to file-based extent index */
-       if (ifp->if_flags & XFS_IFEXTIREC) {
-               idx += erp->er_extoff;
-       }
-       if (bno >= startoff + blockcount) {
-               if (++idx == nextents) {
-                       ep = NULL;
-               } else {
-                       ep = xfs_iext_get_ext(ifp, idx);
-               }
-       }
-       *idxp = idx;
-       return ep;
-}
-
-/*
- * Return a pointer to the indirection array entry containing the
- * extent record for filesystem block bno. Store the index of the
- * target irec in *erp_idxp.
- */
-xfs_ext_irec_t *                       /* pointer to found extent record */
-xfs_iext_bno_to_irec(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_fileoff_t   bno,            /* block number to search for */
-       int             *erp_idxp)      /* irec index of target ext list */
-{
-       xfs_ext_irec_t  *erp = NULL;    /* indirection array pointer */
-       xfs_ext_irec_t  *erp_next;      /* next indirection array entry */
-       int             erp_idx;        /* indirection array index */
-       int             nlists;         /* number of extent irec's (lists) */
-       int             high;           /* binary search upper limit */
-       int             low;            /* binary search lower limit */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       erp_idx = 0;
-       low = 0;
-       high = nlists - 1;
-       while (low <= high) {
-               erp_idx = (low + high) >> 1;
-               erp = &ifp->if_u1.if_ext_irec[erp_idx];
-               erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL;
-               if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) {
-                       high = erp_idx - 1;
-               } else if (erp_next && bno >=
-                          xfs_bmbt_get_startoff(erp_next->er_extbuf)) {
-                       low = erp_idx + 1;
-               } else {
-                       break;
-               }
-       }
-       *erp_idxp = erp_idx;
-       return erp;
-}
-
-/*
- * Return a pointer to the indirection array entry containing the
- * extent record at file extent index *idxp. Store the index of the
- * target irec in *erp_idxp and store the page index of the target
- * extent record in *idxp.
- */
-xfs_ext_irec_t *
-xfs_iext_idx_to_irec(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       xfs_extnum_t    *idxp,          /* extent index (file -> page) */
-       int             *erp_idxp,      /* pointer to target irec */
-       int             realloc)        /* new bytes were just added */
-{
-       xfs_ext_irec_t  *prev;          /* pointer to previous irec */
-       xfs_ext_irec_t  *erp = NULL;    /* pointer to current irec */
-       int             erp_idx;        /* indirection array index */
-       int             nlists;         /* number of irec's (ex lists) */
-       int             high;           /* binary search upper limit */
-       int             low;            /* binary search lower limit */
-       xfs_extnum_t    page_idx = *idxp; /* extent index in target list */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       ASSERT(page_idx >= 0);
-       ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
-       ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc);
-
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       erp_idx = 0;
-       low = 0;
-       high = nlists - 1;
-
-       /* Binary search extent irec's */
-       while (low <= high) {
-               erp_idx = (low + high) >> 1;
-               erp = &ifp->if_u1.if_ext_irec[erp_idx];
-               prev = erp_idx > 0 ? erp - 1 : NULL;
-               if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff &&
-                    realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) {
-                       high = erp_idx - 1;
-               } else if (page_idx > erp->er_extoff + erp->er_extcount ||
-                          (page_idx == erp->er_extoff + erp->er_extcount &&
-                           !realloc)) {
-                       low = erp_idx + 1;
-               } else if (page_idx == erp->er_extoff + erp->er_extcount &&
-                          erp->er_extcount == XFS_LINEAR_EXTS) {
-                       ASSERT(realloc);
-                       page_idx = 0;
-                       erp_idx++;
-                       erp = erp_idx < nlists ? erp + 1 : NULL;
-                       break;
-               } else {
-                       page_idx -= erp->er_extoff;
-                       break;
-               }
-       }
-       *idxp = page_idx;
-       *erp_idxp = erp_idx;
-       return(erp);
-}
-
-/*
- * Allocate and initialize an indirection array once the space needed
- * for incore extents increases above XFS_IEXT_BUFSZ.
- */
-void
-xfs_iext_irec_init(
-       xfs_ifork_t     *ifp)           /* inode fork pointer */
-{
-       xfs_ext_irec_t  *erp;           /* indirection array pointer */
-       xfs_extnum_t    nextents;       /* number of extents in file */
-
-       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-       ASSERT(nextents <= XFS_LINEAR_EXTS);
-
-       erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS);
-
-       if (nextents == 0) {
-               ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
-       } else if (!ifp->if_real_bytes) {
-               xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ);
-       } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) {
-               xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ);
-       }
-       erp->er_extbuf = ifp->if_u1.if_extents;
-       erp->er_extcount = nextents;
-       erp->er_extoff = 0;
-
-       ifp->if_flags |= XFS_IFEXTIREC;
-       ifp->if_real_bytes = XFS_IEXT_BUFSZ;
-       ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t);
-       ifp->if_u1.if_ext_irec = erp;
-
-       return;
-}
-
-/*
- * Allocate and initialize a new entry in the indirection array.
- */
-xfs_ext_irec_t *
-xfs_iext_irec_new(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       int             erp_idx)        /* index for new irec */
-{
-       xfs_ext_irec_t  *erp;           /* indirection array pointer */
-       int             i;              /* loop counter */
-       int             nlists;         /* number of irec's (ex lists) */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-
-       /* Resize indirection array */
-       xfs_iext_realloc_indirect(ifp, ++nlists *
-                                 sizeof(xfs_ext_irec_t));
-       /*
-        * Move records down in the array so the
-        * new page can use erp_idx.
-        */
-       erp = ifp->if_u1.if_ext_irec;
-       for (i = nlists - 1; i > erp_idx; i--) {
-               memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t));
-       }
-       ASSERT(i == erp_idx);
-
-       /* Initialize new extent record */
-       erp = ifp->if_u1.if_ext_irec;
-       erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
-       ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
-       memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ);
-       erp[erp_idx].er_extcount = 0;
-       erp[erp_idx].er_extoff = erp_idx > 0 ?
-               erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0;
-       return (&erp[erp_idx]);
-}
-
-/*
- * Remove a record from the indirection array.
- */
-void
-xfs_iext_irec_remove(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       int             erp_idx)        /* irec index to remove */
-{
-       xfs_ext_irec_t  *erp;           /* indirection array pointer */
-       int             i;              /* loop counter */
-       int             nlists;         /* number of irec's (ex lists) */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       erp = &ifp->if_u1.if_ext_irec[erp_idx];
-       if (erp->er_extbuf) {
-               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
-                       -erp->er_extcount);
-               kmem_free(erp->er_extbuf);
-       }
-       /* Compact extent records */
-       erp = ifp->if_u1.if_ext_irec;
-       for (i = erp_idx; i < nlists - 1; i++) {
-               memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t));
-       }
-       /*
-        * Manually free the last extent record from the indirection
-        * array.  A call to xfs_iext_realloc_indirect() with a size
-        * of zero would result in a call to xfs_iext_destroy() which
-        * would in turn call this function again, creating a nasty
-        * infinite loop.
-        */
-       if (--nlists) {
-               xfs_iext_realloc_indirect(ifp,
-                       nlists * sizeof(xfs_ext_irec_t));
-       } else {
-               kmem_free(ifp->if_u1.if_ext_irec);
-       }
-       ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
-}
-
-/*
- * This is called to clean up large amounts of unused memory allocated
- * by the indirection array.  Before compacting anything though, verify
- * that the indirection array is still needed and switch back to the
- * linear extent list (or even the inline buffer) if possible.  The
- * compaction policy is as follows:
- *
- *    Full Compaction: Extents fit into a single page (or inline buffer)
- * Partial Compaction: Extents occupy less than 50% of allocated space
- *      No Compaction: Extents occupy at least 50% of allocated space
- */
-void
-xfs_iext_irec_compact(
-       xfs_ifork_t     *ifp)           /* inode fork pointer */
-{
-       xfs_extnum_t    nextents;       /* number of extents in file */
-       int             nlists;         /* number of irec's (ex lists) */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
-
-       if (nextents == 0) {
-               xfs_iext_destroy(ifp);
-       } else if (nextents <= XFS_INLINE_EXTS) {
-               xfs_iext_indirect_to_direct(ifp);
-               xfs_iext_direct_to_inline(ifp, nextents);
-       } else if (nextents <= XFS_LINEAR_EXTS) {
-               xfs_iext_indirect_to_direct(ifp);
-       } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
-               xfs_iext_irec_compact_pages(ifp);
-       }
-}
-
-/*
- * Combine extents from neighboring extent pages.
- */
-void
-xfs_iext_irec_compact_pages(
-       xfs_ifork_t     *ifp)           /* inode fork pointer */
-{
-       xfs_ext_irec_t  *erp, *erp_next;/* pointers to irec entries */
-       int             erp_idx = 0;    /* indirection array index */
-       int             nlists;         /* number of irec's (ex lists) */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       while (erp_idx < nlists - 1) {
-               erp = &ifp->if_u1.if_ext_irec[erp_idx];
-               erp_next = erp + 1;
-               if (erp_next->er_extcount <=
-                   (XFS_LINEAR_EXTS - erp->er_extcount)) {
-                       memcpy(&erp->er_extbuf[erp->er_extcount],
-                               erp_next->er_extbuf, erp_next->er_extcount *
-                               sizeof(xfs_bmbt_rec_t));
-                       erp->er_extcount += erp_next->er_extcount;
-                       /*
-                        * Free page before removing extent record
-                        * so er_extoffs don't get modified in
-                        * xfs_iext_irec_remove.
-                        */
-                       kmem_free(erp_next->er_extbuf);
-                       erp_next->er_extbuf = NULL;
-                       xfs_iext_irec_remove(ifp, erp_idx + 1);
-                       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-               } else {
-                       erp_idx++;
-               }
-       }
-}
-
-/*
- * This is called to update the er_extoff field in the indirection
- * array when extents have been added or removed from one of the
- * extent lists. erp_idx contains the irec index to begin updating
- * at and ext_diff contains the number of extents that were added
- * or removed.
- */
-void
-xfs_iext_irec_update_extoffs(
-       xfs_ifork_t     *ifp,           /* inode fork pointer */
-       int             erp_idx,        /* irec index to update */
-       int             ext_diff)       /* number of new extents */
-{
-       int             i;              /* loop counter */
-       int             nlists;         /* number of irec's (ex lists */
-
-       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
-       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
-       for (i = erp_idx; i < nlists; i++) {
-               ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
-       }
-}
-
-/*
- * Test whether it is appropriate to check an inode for and free post EOF
- * blocks. The 'force' parameter determines whether we should also consider
- * regular files that are marked preallocated or append-only.
- */
-bool
-xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
-{
-       /* prealloc/delalloc exists only on regular files */
-       if (!S_ISREG(ip->i_d.di_mode))
-               return false;
-
-       /*
-        * Zero sized files with no cached pages and delalloc blocks will not
-        * have speculative prealloc/delalloc blocks to remove.
-        */
-       if (VFS_I(ip)->i_size == 0 &&
-           VN_CACHED(VFS_I(ip)) == 0 &&
-           ip->i_delayed_blks == 0)
-               return false;
-
-       /* If we haven't read in the extent list, then don't do it now. */
-       if (!(ip->i_df.if_flags & XFS_IFEXTENTS))
-               return false;
-
-       /*
-        * Do not free real preallocated or append-only files unless the file
-        * has delalloc blocks and we are forced to remove them.
-        */
-       if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND))
-               if (!force || ip->i_delayed_blks == 0)
-                       return false;
-
-       return true;
-}
-
index b55fd347ab5b9b9ff51fd555115c854d7cfd8084..4a91358c1470b9ac029d451dd38c3fa77daf6fc0 100644 (file)
 #ifndef        __XFS_INODE_H__
 #define        __XFS_INODE_H__
 
-struct posix_acl;
-struct xfs_dinode;
-struct xfs_inode;
-
-/*
- * Fork identifiers.
- */
-#define        XFS_DATA_FORK   0
-#define        XFS_ATTR_FORK   1
-
-/*
- * The following xfs_ext_irec_t struct introduces a second (top) level
- * to the in-core extent allocation scheme. These structs are allocated
- * in a contiguous block, creating an indirection array where each entry
- * (irec) contains a pointer to a buffer of in-core extent records which
- * it manages. Each extent buffer is 4k in size, since 4k is the system
- * page size on Linux i386 and systems with larger page sizes don't seem
- * to gain much, if anything, by using their native page size as the
- * extent buffer size. Also, using 4k extent buffers everywhere provides
- * a consistent interface for CXFS across different platforms.
- *
- * There is currently no limit on the number of irec's (extent lists)
- * allowed, so heavily fragmented files may require an indirection array
- * which spans multiple system pages of memory. The number of extents
- * which would require this amount of contiguous memory is very large
- * and should not cause problems in the foreseeable future. However,
- * if the memory needed for the contiguous array ever becomes a problem,
- * it is possible that a third level of indirection may be required.
- */
-typedef struct xfs_ext_irec {
-       xfs_bmbt_rec_host_t *er_extbuf; /* block of extent records */
-       xfs_extnum_t    er_extoff;      /* extent offset in file */
-       xfs_extnum_t    er_extcount;    /* number of extents in page/block */
-} xfs_ext_irec_t;
+#include "xfs_inode_buf.h"
+#include "xfs_inode_fork.h"
 
 /*
- * File incore extent information, present for each of data & attr forks.
+ * Kernel only inode definitions
  */
-#define        XFS_IEXT_BUFSZ          4096
-#define        XFS_LINEAR_EXTS         (XFS_IEXT_BUFSZ / (uint)sizeof(xfs_bmbt_rec_t))
-#define        XFS_INLINE_EXTS         2
-#define        XFS_INLINE_DATA         32
-typedef struct xfs_ifork {
-       int                     if_bytes;       /* bytes in if_u1 */
-       int                     if_real_bytes;  /* bytes allocated in if_u1 */
-       struct xfs_btree_block  *if_broot;      /* file's incore btree root */
-       short                   if_broot_bytes; /* bytes allocated for root */
-       unsigned char           if_flags;       /* per-fork flags */
-       union {
-               xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */
-               xfs_ext_irec_t  *if_ext_irec;   /* irec map file exts */
-               char            *if_data;       /* inline file data */
-       } if_u1;
-       union {
-               xfs_bmbt_rec_host_t if_inline_ext[XFS_INLINE_EXTS];
-                                               /* very small file extents */
-               char            if_inline_data[XFS_INLINE_DATA];
-                                               /* very small file data */
-               xfs_dev_t       if_rdev;        /* dev number if special */
-               uuid_t          if_uuid;        /* mount point value */
-       } if_u2;
-} xfs_ifork_t;
-
-/*
- * Inode location information.  Stored in the inode and passed to
- * xfs_imap_to_bp() to get a buffer and dinode for a given inode.
- */
-struct xfs_imap {
-       xfs_daddr_t     im_blkno;       /* starting BB of inode chunk */
-       ushort          im_len;         /* length in BBs of inode chunk */
-       ushort          im_boffset;     /* inode offset in block in bytes */
-};
-
-/*
- * This is the xfs in-core inode structure.
- * Most of the on-disk inode is embedded in the i_d field.
- *
- * The extent pointers/inline file space, however, are managed
- * separately.  The memory for this information is pointed to by
- * the if_u1 unions depending on the type of the data.
- * This is used to linearize the array of extents for fast in-core
- * access.  This is used until the file's number of extents
- * surpasses XFS_MAX_INCORE_EXTENTS, at which point all extent pointers
- * are accessed through the buffer cache.
- *
- * Other state kept in the in-core inode is used for identification,
- * locking, transactional updating, etc of the inode.
- *
- * Generally, we do not want to hold the i_rlock while holding the
- * i_ilock. Hierarchy is i_iolock followed by i_rlock.
- *
- * xfs_iptr_t contains all the inode fields up to and including the
- * i_mnext and i_mprev fields, it is used as a marker in the inode
- * chain off the mount structure by xfs_sync calls.
- */
-
-typedef struct xfs_ictimestamp {
-       __int32_t       t_sec;          /* timestamp seconds */
-       __int32_t       t_nsec;         /* timestamp nanoseconds */
-} xfs_ictimestamp_t;
-
-/*
- * NOTE:  This structure must be kept identical to struct xfs_dinode
- *       in xfs_dinode.h except for the endianness annotations.
- */
-typedef struct xfs_icdinode {
-       __uint16_t      di_magic;       /* inode magic # = XFS_DINODE_MAGIC */
-       __uint16_t      di_mode;        /* mode and type of file */
-       __int8_t        di_version;     /* inode version */
-       __int8_t        di_format;      /* format of di_c data */
-       __uint16_t      di_onlink;      /* old number of links to file */
-       __uint32_t      di_uid;         /* owner's user id */
-       __uint32_t      di_gid;         /* owner's group id */
-       __uint32_t      di_nlink;       /* number of links to file */
-       __uint16_t      di_projid_lo;   /* lower part of owner's project id */
-       __uint16_t      di_projid_hi;   /* higher part of owner's project id */
-       __uint8_t       di_pad[6];      /* unused, zeroed space */
-       __uint16_t      di_flushiter;   /* incremented on flush */
-       xfs_ictimestamp_t di_atime;     /* time last accessed */
-       xfs_ictimestamp_t di_mtime;     /* time last modified */
-       xfs_ictimestamp_t di_ctime;     /* time created/inode modified */
-       xfs_fsize_t     di_size;        /* number of bytes in file */
-       xfs_drfsbno_t   di_nblocks;     /* # of direct & btree blocks used */
-       xfs_extlen_t    di_extsize;     /* basic/minimum extent size for file */
-       xfs_extnum_t    di_nextents;    /* number of extents in data fork */
-       xfs_aextnum_t   di_anextents;   /* number of extents in attribute fork*/
-       __uint8_t       di_forkoff;     /* attr fork offs, <<3 for 64b align */
-       __int8_t        di_aformat;     /* format of attr fork's data */
-       __uint32_t      di_dmevmask;    /* DMIG event mask */
-       __uint16_t      di_dmstate;     /* DMIG state info */
-       __uint16_t      di_flags;       /* random flags, XFS_DIFLAG_... */
-       __uint32_t      di_gen;         /* generation number */
-
-       /* di_next_unlinked is the only non-core field in the old dinode */
-       xfs_agino_t     di_next_unlinked;/* agi unlinked list ptr */
-
-       /* start of the extended dinode, writable fields */
-       __uint32_t      di_crc;         /* CRC of the inode */
-       __uint64_t      di_changecount; /* number of attribute changes */
-       xfs_lsn_t       di_lsn;         /* flush sequence */
-       __uint64_t      di_flags2;      /* more random flags */
-       __uint8_t       di_pad2[16];    /* more padding for future expansion */
-
-       /* fields only written to during inode creation */
-       xfs_ictimestamp_t di_crtime;    /* time created */
-       xfs_ino_t       di_ino;         /* inode number */
-       uuid_t          di_uuid;        /* UUID of the filesystem */
-
-       /* structure must be padded to 64 bit alignment */
-} xfs_icdinode_t;
-
-static inline uint xfs_icdinode_size(int version)
-{
-       if (version == 3)
-               return sizeof(struct xfs_icdinode);
-       return offsetof(struct xfs_icdinode, di_next_unlinked);
-}
-
-/*
- * Flags for xfs_ichgtime().
- */
-#define        XFS_ICHGTIME_MOD        0x1     /* data fork modification timestamp */
-#define        XFS_ICHGTIME_CHG        0x2     /* inode field change timestamp */
-#define        XFS_ICHGTIME_CREATE     0x4     /* inode create timestamp */
-
-/*
- * Per-fork incore inode flags.
- */
-#define        XFS_IFINLINE    0x01    /* Inline data is read in */
-#define        XFS_IFEXTENTS   0x02    /* All extent pointers are read in */
-#define        XFS_IFBROOT     0x04    /* i_broot points to the bmap b-tree root */
-#define        XFS_IFEXTIREC   0x08    /* Indirection array of extent blocks */
-
-/*
- * Fork handling.
- */
-
-#define XFS_IFORK_Q(ip)                        ((ip)->i_d.di_forkoff != 0)
-#define XFS_IFORK_BOFF(ip)             ((int)((ip)->i_d.di_forkoff << 3))
-
-#define XFS_IFORK_PTR(ip,w)            \
-       ((w) == XFS_DATA_FORK ? \
-               &(ip)->i_df : \
-               (ip)->i_afp)
-#define XFS_IFORK_DSIZE(ip) \
-       (XFS_IFORK_Q(ip) ? \
-               XFS_IFORK_BOFF(ip) : \
-               XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version))
-#define XFS_IFORK_ASIZE(ip) \
-       (XFS_IFORK_Q(ip) ? \
-               XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version) - \
-                       XFS_IFORK_BOFF(ip) : \
-               0)
-#define XFS_IFORK_SIZE(ip,w) \
-       ((w) == XFS_DATA_FORK ? \
-               XFS_IFORK_DSIZE(ip) : \
-               XFS_IFORK_ASIZE(ip))
-#define XFS_IFORK_FORMAT(ip,w) \
-       ((w) == XFS_DATA_FORK ? \
-               (ip)->i_d.di_format : \
-               (ip)->i_d.di_aformat)
-#define XFS_IFORK_FMT_SET(ip,w,n) \
-       ((w) == XFS_DATA_FORK ? \
-               ((ip)->i_d.di_format = (n)) : \
-               ((ip)->i_d.di_aformat = (n)))
-#define XFS_IFORK_NEXTENTS(ip,w) \
-       ((w) == XFS_DATA_FORK ? \
-               (ip)->i_d.di_nextents : \
-               (ip)->i_d.di_anextents)
-#define XFS_IFORK_NEXT_SET(ip,w,n) \
-       ((w) == XFS_DATA_FORK ? \
-               ((ip)->i_d.di_nextents = (n)) : \
-               ((ip)->i_d.di_anextents = (n)))
-#define XFS_IFORK_MAXEXT(ip, w) \
-       (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t))
-
-
-#ifdef __KERNEL__
 
+struct xfs_dinode;
+struct xfs_inode;
 struct xfs_buf;
 struct xfs_bmap_free;
 struct xfs_bmbt_irec;
@@ -525,9 +315,21 @@ static inline int xfs_isiflocked(struct xfs_inode *ip)
         ((pip)->i_d.di_mode & S_ISGID))
 
 
-/*
- * xfs_inode.c prototypes.
- */
+int            xfs_release(struct xfs_inode *ip);
+int            xfs_inactive(struct xfs_inode *ip);
+int            xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
+                          struct xfs_inode **ipp, struct xfs_name *ci_name);
+int            xfs_create(struct xfs_inode *dp, struct xfs_name *name,
+                          umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp);
+int            xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
+                          struct xfs_inode *ip);
+int            xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
+                        struct xfs_name *target_name);
+int            xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
+                          struct xfs_inode *src_ip, struct xfs_inode *target_dp,
+                          struct xfs_name *target_name,
+                          struct xfs_inode *target_ip);
+
 void           xfs_ilock(xfs_inode_t *, uint);
 int            xfs_ilock_nowait(xfs_inode_t *, uint);
 void           xfs_iunlock(xfs_inode_t *, uint);
@@ -548,13 +350,28 @@ int               xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *,
 int            xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
 
 void           xfs_iext_realloc(xfs_inode_t *, int, int);
+
 void           xfs_iunpin_wait(xfs_inode_t *);
+#define xfs_ipincount(ip)      ((unsigned int) atomic_read(&ip->i_pincount))
+
 int            xfs_iflush(struct xfs_inode *, struct xfs_buf **);
 void           xfs_lock_inodes(xfs_inode_t **, int, uint);
 void           xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
 
 xfs_extlen_t   xfs_get_extsz_hint(struct xfs_inode *ip);
 
+int            xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t,
+                              xfs_nlink_t, xfs_dev_t, prid_t, int,
+                              struct xfs_inode **, int *);
+int            xfs_droplink(struct xfs_trans *, struct xfs_inode *);
+int            xfs_bumplink(struct xfs_trans *, struct xfs_inode *);
+void           xfs_bump_ino_vers2(struct xfs_trans *, struct xfs_inode *);
+
+/* from xfs_file.c */
+int            xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
+int            xfs_iozero(struct xfs_inode *, loff_t, size_t);
+
+
 #define IHOLD(ip) \
 do { \
        ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \
@@ -568,65 +385,6 @@ do { \
        iput(VFS_I(ip)); \
 } while (0)
 
-#endif /* __KERNEL__ */
-
-/*
- * Flags for xfs_iget()
- */
-#define XFS_IGET_CREATE                0x1
-#define XFS_IGET_UNTRUSTED     0x2
-#define XFS_IGET_DONTCACHE     0x4
-
-int            xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *,
-                              struct xfs_imap *, struct xfs_dinode **,
-                              struct xfs_buf **, uint, uint);
-int            xfs_iread(struct xfs_mount *, struct xfs_trans *,
-                         struct xfs_inode *, uint);
-void           xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *);
-void           xfs_dinode_to_disk(struct xfs_dinode *,
-                                  struct xfs_icdinode *);
-void           xfs_idestroy_fork(struct xfs_inode *, int);
-void           xfs_idata_realloc(struct xfs_inode *, int, int);
-void           xfs_iroot_realloc(struct xfs_inode *, int, int);
-int            xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
-int            xfs_iextents_copy(struct xfs_inode *, xfs_bmbt_rec_t *, int);
-
-xfs_bmbt_rec_host_t *xfs_iext_get_ext(xfs_ifork_t *, xfs_extnum_t);
-void           xfs_iext_insert(xfs_inode_t *, xfs_extnum_t, xfs_extnum_t,
-                               xfs_bmbt_irec_t *, int);
-void           xfs_iext_add(xfs_ifork_t *, xfs_extnum_t, int);
-void           xfs_iext_add_indirect_multi(xfs_ifork_t *, int, xfs_extnum_t, int);
-void           xfs_iext_remove(xfs_inode_t *, xfs_extnum_t, int, int);
-void           xfs_iext_remove_inline(xfs_ifork_t *, xfs_extnum_t, int);
-void           xfs_iext_remove_direct(xfs_ifork_t *, xfs_extnum_t, int);
-void           xfs_iext_remove_indirect(xfs_ifork_t *, xfs_extnum_t, int);
-void           xfs_iext_realloc_direct(xfs_ifork_t *, int);
-void           xfs_iext_direct_to_inline(xfs_ifork_t *, xfs_extnum_t);
-void           xfs_iext_inline_to_direct(xfs_ifork_t *, int);
-void           xfs_iext_destroy(xfs_ifork_t *);
-xfs_bmbt_rec_host_t *xfs_iext_bno_to_ext(xfs_ifork_t *, xfs_fileoff_t, int *);
-xfs_ext_irec_t *xfs_iext_bno_to_irec(xfs_ifork_t *, xfs_fileoff_t, int *);
-xfs_ext_irec_t *xfs_iext_idx_to_irec(xfs_ifork_t *, xfs_extnum_t *, int *, int);
-void           xfs_iext_irec_init(xfs_ifork_t *);
-xfs_ext_irec_t *xfs_iext_irec_new(xfs_ifork_t *, int);
-void           xfs_iext_irec_remove(xfs_ifork_t *, int);
-void           xfs_iext_irec_compact(xfs_ifork_t *);
-void           xfs_iext_irec_compact_pages(xfs_ifork_t *);
-void           xfs_iext_irec_compact_full(xfs_ifork_t *);
-void           xfs_iext_irec_update_extoffs(xfs_ifork_t *, int, int);
-bool           xfs_can_free_eofblocks(struct xfs_inode *, bool);
-
-#define xfs_ipincount(ip)      ((unsigned int) atomic_read(&ip->i_pincount))
-
-#if defined(DEBUG)
-void           xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
-#else
-#define        xfs_inobp_check(mp, bp)
-#endif /* DEBUG */
-
-extern struct kmem_zone        *xfs_ifork_zone;
 extern struct kmem_zone        *xfs_inode_zone;
-extern struct kmem_zone        *xfs_ili_zone;
-extern const struct xfs_buf_ops xfs_inode_buf_ops;
 
 #endif /* __XFS_INODE_H__ */
diff --git a/fs/xfs/xfs_inode_buf.c b/fs/xfs/xfs_inode_buf.c
new file mode 100644 (file)
index 0000000..63382d3
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2000-2006 Silicon Graphics, 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_format.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_error.h"
+#include "xfs_cksum.h"
+#include "xfs_icache.h"
+#include "xfs_ialloc.h"
+
+/*
+ * Check that none of the inode's in the buffer have a next
+ * unlinked field of 0.
+ */
+#if defined(DEBUG)
+void
+xfs_inobp_check(
+       xfs_mount_t     *mp,
+       xfs_buf_t       *bp)
+{
+       int             i;
+       int             j;
+       xfs_dinode_t    *dip;
+
+       j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog;
+
+       for (i = 0; i < j; i++) {
+               dip = (xfs_dinode_t *)xfs_buf_offset(bp,
+                                       i * mp->m_sb.sb_inodesize);
+               if (!dip->di_next_unlinked)  {
+                       xfs_alert(mp,
+       "Detected bogus zero next_unlinked field in inode %d buffer 0x%llx.",
+                               i, (long long)bp->b_bn);
+               }
+       }
+}
+#endif
+
+/*
+ * If we are doing readahead on an inode buffer, we might be in log recovery
+ * reading an inode allocation buffer that hasn't yet been replayed, and hence
+ * has not had the inode cores stamped into it. Hence for readahead, the buffer
+ * may be potentially invalid.
+ *
+ * If the readahead buffer is invalid, we don't want to mark it with an error,
+ * but we do want to clear the DONE status of the buffer so that a followup read
+ * will re-read it from disk. This will ensure that we don't get an unnecessary
+ * warnings during log recovery and we don't get unnecssary panics on debug
+ * kernels.
+ */
+static void
+xfs_inode_buf_verify(
+       struct xfs_buf  *bp,
+       bool            readahead)
+{
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       int             i;
+       int             ni;
+
+       /*
+        * Validate the magic number and version of every inode in the buffer
+        */
+       ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock;
+       for (i = 0; i < ni; i++) {
+               int             di_ok;
+               xfs_dinode_t    *dip;
+
+               dip = (struct xfs_dinode *)xfs_buf_offset(bp,
+                                       (i << mp->m_sb.sb_inodelog));
+               di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) &&
+                           XFS_DINODE_GOOD_VERSION(dip->di_version);
+               if (unlikely(XFS_TEST_ERROR(!di_ok, mp,
+                                               XFS_ERRTAG_ITOBP_INOTOBP,
+                                               XFS_RANDOM_ITOBP_INOTOBP))) {
+                       if (readahead) {
+                               bp->b_flags &= ~XBF_DONE;
+                               return;
+                       }
+
+                       xfs_buf_ioerror(bp, EFSCORRUPTED);
+                       XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_HIGH,
+                                            mp, dip);
+#ifdef DEBUG
+                       xfs_alert(mp,
+                               "bad inode magic/vsn daddr %lld #%d (magic=%x)",
+                               (unsigned long long)bp->b_bn, i,
+                               be16_to_cpu(dip->di_magic));
+#endif
+               }
+       }
+       xfs_inobp_check(mp, bp);
+}
+
+
+static void
+xfs_inode_buf_read_verify(
+       struct xfs_buf  *bp)
+{
+       xfs_inode_buf_verify(bp, false);
+}
+
+static void
+xfs_inode_buf_readahead_verify(
+       struct xfs_buf  *bp)
+{
+       xfs_inode_buf_verify(bp, true);
+}
+
+static void
+xfs_inode_buf_write_verify(
+       struct xfs_buf  *bp)
+{
+       xfs_inode_buf_verify(bp, false);
+}
+
+const struct xfs_buf_ops xfs_inode_buf_ops = {
+       .verify_read = xfs_inode_buf_read_verify,
+       .verify_write = xfs_inode_buf_write_verify,
+};
+
+const struct xfs_buf_ops xfs_inode_buf_ra_ops = {
+       .verify_read = xfs_inode_buf_readahead_verify,
+       .verify_write = xfs_inode_buf_write_verify,
+};
+
+
+/*
+ * This routine is called to map an inode to the buffer containing the on-disk
+ * version of the inode.  It returns a pointer to the buffer containing the
+ * on-disk inode in the bpp parameter, and in the dipp parameter it returns a
+ * pointer to the on-disk inode within that buffer.
+ *
+ * If a non-zero error is returned, then the contents of bpp and dipp are
+ * undefined.
+ */
+int
+xfs_imap_to_bp(
+       struct xfs_mount        *mp,
+       struct xfs_trans        *tp,
+       struct xfs_imap         *imap,
+       struct xfs_dinode       **dipp,
+       struct xfs_buf          **bpp,
+       uint                    buf_flags,
+       uint                    iget_flags)
+{
+       struct xfs_buf          *bp;
+       int                     error;
+
+       buf_flags |= XBF_UNMAPPED;
+       error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno,
+                                  (int)imap->im_len, buf_flags, &bp,
+                                  &xfs_inode_buf_ops);
+       if (error) {
+               if (error == EAGAIN) {
+                       ASSERT(buf_flags & XBF_TRYLOCK);
+                       return error;
+               }
+
+               if (error == EFSCORRUPTED &&
+                   (iget_flags & XFS_IGET_UNTRUSTED))
+                       return XFS_ERROR(EINVAL);
+
+               xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.",
+                       __func__, error);
+               return error;
+       }
+
+       *bpp = bp;
+       *dipp = (struct xfs_dinode *)xfs_buf_offset(bp, imap->im_boffset);
+       return 0;
+}
+
+void
+xfs_dinode_from_disk(
+       xfs_icdinode_t          *to,
+       xfs_dinode_t            *from)
+{
+       to->di_magic = be16_to_cpu(from->di_magic);
+       to->di_mode = be16_to_cpu(from->di_mode);
+       to->di_version = from ->di_version;
+       to->di_format = from->di_format;
+       to->di_onlink = be16_to_cpu(from->di_onlink);
+       to->di_uid = be32_to_cpu(from->di_uid);
+       to->di_gid = be32_to_cpu(from->di_gid);
+       to->di_nlink = be32_to_cpu(from->di_nlink);
+       to->di_projid_lo = be16_to_cpu(from->di_projid_lo);
+       to->di_projid_hi = be16_to_cpu(from->di_projid_hi);
+       memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
+       to->di_flushiter = be16_to_cpu(from->di_flushiter);
+       to->di_atime.t_sec = be32_to_cpu(from->di_atime.t_sec);
+       to->di_atime.t_nsec = be32_to_cpu(from->di_atime.t_nsec);
+       to->di_mtime.t_sec = be32_to_cpu(from->di_mtime.t_sec);
+       to->di_mtime.t_nsec = be32_to_cpu(from->di_mtime.t_nsec);
+       to->di_ctime.t_sec = be32_to_cpu(from->di_ctime.t_sec);
+       to->di_ctime.t_nsec = be32_to_cpu(from->di_ctime.t_nsec);
+       to->di_size = be64_to_cpu(from->di_size);
+       to->di_nblocks = be64_to_cpu(from->di_nblocks);
+       to->di_extsize = be32_to_cpu(from->di_extsize);
+       to->di_nextents = be32_to_cpu(from->di_nextents);
+       to->di_anextents = be16_to_cpu(from->di_anextents);
+       to->di_forkoff = from->di_forkoff;
+       to->di_aformat  = from->di_aformat;
+       to->di_dmevmask = be32_to_cpu(from->di_dmevmask);
+       to->di_dmstate  = be16_to_cpu(from->di_dmstate);
+       to->di_flags    = be16_to_cpu(from->di_flags);
+       to->di_gen      = be32_to_cpu(from->di_gen);
+
+       if (to->di_version == 3) {
+               to->di_changecount = be64_to_cpu(from->di_changecount);
+               to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec);
+               to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec);
+               to->di_flags2 = be64_to_cpu(from->di_flags2);
+               to->di_ino = be64_to_cpu(from->di_ino);
+               to->di_lsn = be64_to_cpu(from->di_lsn);
+               memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
+               uuid_copy(&to->di_uuid, &from->di_uuid);
+       }
+}
+
+void
+xfs_dinode_to_disk(
+       xfs_dinode_t            *to,
+       xfs_icdinode_t          *from)
+{
+       to->di_magic = cpu_to_be16(from->di_magic);
+       to->di_mode = cpu_to_be16(from->di_mode);
+       to->di_version = from ->di_version;
+       to->di_format = from->di_format;
+       to->di_onlink = cpu_to_be16(from->di_onlink);
+       to->di_uid = cpu_to_be32(from->di_uid);
+       to->di_gid = cpu_to_be32(from->di_gid);
+       to->di_nlink = cpu_to_be32(from->di_nlink);
+       to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
+       to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
+       memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
+       to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec);
+       to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec);
+       to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec);
+       to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec);
+       to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec);
+       to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec);
+       to->di_size = cpu_to_be64(from->di_size);
+       to->di_nblocks = cpu_to_be64(from->di_nblocks);
+       to->di_extsize = cpu_to_be32(from->di_extsize);
+       to->di_nextents = cpu_to_be32(from->di_nextents);
+       to->di_anextents = cpu_to_be16(from->di_anextents);
+       to->di_forkoff = from->di_forkoff;
+       to->di_aformat = from->di_aformat;
+       to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
+       to->di_dmstate = cpu_to_be16(from->di_dmstate);
+       to->di_flags = cpu_to_be16(from->di_flags);
+       to->di_gen = cpu_to_be32(from->di_gen);
+
+       if (from->di_version == 3) {
+               to->di_changecount = cpu_to_be64(from->di_changecount);
+               to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec);
+               to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec);
+               to->di_flags2 = cpu_to_be64(from->di_flags2);
+               to->di_ino = cpu_to_be64(from->di_ino);
+               to->di_lsn = cpu_to_be64(from->di_lsn);
+               memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
+               uuid_copy(&to->di_uuid, &from->di_uuid);
+               to->di_flushiter = 0;
+       } else {
+               to->di_flushiter = cpu_to_be16(from->di_flushiter);
+       }
+}
+
+static bool
+xfs_dinode_verify(
+       struct xfs_mount        *mp,
+       struct xfs_inode        *ip,
+       struct xfs_dinode       *dip)
+{
+       if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
+               return false;
+
+       /* only version 3 or greater inodes are extensively verified here */
+       if (dip->di_version < 3)
+               return true;
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return false;
+       if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize,
+                             offsetof(struct xfs_dinode, di_crc)))
+               return false;
+       if (be64_to_cpu(dip->di_ino) != ip->i_ino)
+               return false;
+       if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_uuid))
+               return false;
+       return true;
+}
+
+void
+xfs_dinode_calc_crc(
+       struct xfs_mount        *mp,
+       struct xfs_dinode       *dip)
+{
+       __uint32_t              crc;
+
+       if (dip->di_version < 3)
+               return;
+
+       ASSERT(xfs_sb_version_hascrc(&mp->m_sb));
+       crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize,
+                             offsetof(struct xfs_dinode, di_crc));
+       dip->di_crc = xfs_end_cksum(crc);
+}
+
+/*
+ * Read the disk inode attributes into the in-core inode structure.
+ *
+ * For version 5 superblocks, if we are initialising a new inode and we are not
+ * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new
+ * inode core with a random generation number. If we are keeping inodes around,
+ * we need to read the inode cluster to get the existing generation number off
+ * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode
+ * format) then log recovery is dependent on the di_flushiter field being
+ * initialised from the current on-disk value and hence we must also read the
+ * inode off disk.
+ */
+int
+xfs_iread(
+       xfs_mount_t     *mp,
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       uint            iget_flags)
+{
+       xfs_buf_t       *bp;
+       xfs_dinode_t    *dip;
+       int             error;
+
+       /*
+        * Fill in the location information in the in-core inode.
+        */
+       error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags);
+       if (error)
+               return error;
+
+       /* shortcut IO on inode allocation if possible */
+       if ((iget_flags & XFS_IGET_CREATE) &&
+           xfs_sb_version_hascrc(&mp->m_sb) &&
+           !(mp->m_flags & XFS_MOUNT_IKEEP)) {
+               /* initialise the on-disk inode core */
+               memset(&ip->i_d, 0, sizeof(ip->i_d));
+               ip->i_d.di_magic = XFS_DINODE_MAGIC;
+               ip->i_d.di_gen = prandom_u32();
+               if (xfs_sb_version_hascrc(&mp->m_sb)) {
+                       ip->i_d.di_version = 3;
+                       ip->i_d.di_ino = ip->i_ino;
+                       uuid_copy(&ip->i_d.di_uuid, &mp->m_sb.sb_uuid);
+               } else
+                       ip->i_d.di_version = 2;
+               return 0;
+       }
+
+       /*
+        * Get pointers to the on-disk inode and the buffer containing it.
+        */
+       error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags);
+       if (error)
+               return error;
+
+       /* even unallocated inodes are verified */
+       if (!xfs_dinode_verify(mp, ip, dip)) {
+               xfs_alert(mp, "%s: validation failed for inode %lld failed",
+                               __func__, ip->i_ino);
+
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip);
+               error = XFS_ERROR(EFSCORRUPTED);
+               goto out_brelse;
+       }
+
+       /*
+        * If the on-disk inode is already linked to a directory
+        * entry, copy all of the inode into the in-core inode.
+        * xfs_iformat_fork() handles copying in the inode format
+        * specific information.
+        * Otherwise, just get the truly permanent information.
+        */
+       if (dip->di_mode) {
+               xfs_dinode_from_disk(&ip->i_d, dip);
+               error = xfs_iformat_fork(ip, dip);
+               if (error)  {
+#ifdef DEBUG
+                       xfs_alert(mp, "%s: xfs_iformat() returned error %d",
+                               __func__, error);
+#endif /* DEBUG */
+                       goto out_brelse;
+               }
+       } else {
+               /*
+                * Partial initialisation of the in-core inode. Just the bits
+                * that xfs_ialloc won't overwrite or relies on being correct.
+                */
+               ip->i_d.di_magic = be16_to_cpu(dip->di_magic);
+               ip->i_d.di_version = dip->di_version;
+               ip->i_d.di_gen = be32_to_cpu(dip->di_gen);
+               ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter);
+
+               if (dip->di_version == 3) {
+                       ip->i_d.di_ino = be64_to_cpu(dip->di_ino);
+                       uuid_copy(&ip->i_d.di_uuid, &dip->di_uuid);
+               }
+
+               /*
+                * Make sure to pull in the mode here as well in
+                * case the inode is released without being used.
+                * This ensures that xfs_inactive() will see that
+                * the inode is already free and not try to mess
+                * with the uninitialized part of it.
+                */
+               ip->i_d.di_mode = 0;
+       }
+
+       /*
+        * The inode format changed when we moved the link count and
+        * made it 32 bits long.  If this is an old format inode,
+        * convert it in memory to look like a new one.  If it gets
+        * flushed to disk we will convert back before flushing or
+        * logging it.  We zero out the new projid field and the old link
+        * count field.  We'll handle clearing the pad field (the remains
+        * of the old uuid field) when we actually convert the inode to
+        * the new format. We don't change the version number so that we
+        * can distinguish this from a real new format inode.
+        */
+       if (ip->i_d.di_version == 1) {
+               ip->i_d.di_nlink = ip->i_d.di_onlink;
+               ip->i_d.di_onlink = 0;
+               xfs_set_projid(ip, 0);
+       }
+
+       ip->i_delayed_blks = 0;
+
+       /*
+        * Mark the buffer containing the inode as something to keep
+        * around for a while.  This helps to keep recently accessed
+        * meta-data in-core longer.
+        */
+       xfs_buf_set_ref(bp, XFS_INO_REF);
+
+       /*
+        * Use xfs_trans_brelse() to release the buffer containing the on-disk
+        * inode, because it was acquired with xfs_trans_read_buf() in
+        * xfs_imap_to_bp() above.  If tp is NULL, this is just a normal
+        * brelse().  If we're within a transaction, then xfs_trans_brelse()
+        * will only release the buffer if it is not dirty within the
+        * transaction.  It will be OK to release the buffer in this case,
+        * because inodes on disk are never destroyed and we will be locking the
+        * new in-core inode before putting it in the cache where other
+        * processes can find it.  Thus we don't have to worry about the inode
+        * being changed just because we released the buffer.
+        */
+ out_brelse:
+       xfs_trans_brelse(tp, bp);
+       return error;
+}
diff --git a/fs/xfs/xfs_inode_buf.h b/fs/xfs/xfs_inode_buf.h
new file mode 100644 (file)
index 0000000..abba0ae
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, 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
+ */
+#ifndef        __XFS_INODE_BUF_H__
+#define        __XFS_INODE_BUF_H__
+
+struct xfs_inode;
+struct xfs_dinode;
+struct xfs_icdinode;
+
+/*
+ * Inode location information.  Stored in the inode and passed to
+ * xfs_imap_to_bp() to get a buffer and dinode for a given inode.
+ */
+struct xfs_imap {
+       xfs_daddr_t     im_blkno;       /* starting BB of inode chunk */
+       ushort          im_len;         /* length in BBs of inode chunk */
+       ushort          im_boffset;     /* inode offset in block in bytes */
+};
+
+int    xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *,
+                      struct xfs_imap *, struct xfs_dinode **,
+                      struct xfs_buf **, uint, uint);
+int    xfs_iread(struct xfs_mount *, struct xfs_trans *,
+                 struct xfs_inode *, uint);
+void   xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *);
+void   xfs_dinode_to_disk(struct xfs_dinode *to, struct xfs_icdinode *from);
+void   xfs_dinode_from_disk(struct xfs_icdinode *to, struct xfs_dinode *from);
+
+#if defined(DEBUG)
+void   xfs_inobp_check(struct xfs_mount *, struct xfs_buf *);
+#else
+#define        xfs_inobp_check(mp, bp)
+#endif /* DEBUG */
+
+extern const struct xfs_buf_ops xfs_inode_buf_ops;
+extern const struct xfs_buf_ops xfs_inode_buf_ra_ops;
+
+#endif /* __XFS_INODE_BUF_H__ */
diff --git a/fs/xfs/xfs_inode_fork.c b/fs/xfs/xfs_inode_fork.c
new file mode 100644 (file)
index 0000000..02f1083
--- /dev/null
@@ -0,0 +1,1920 @@
+/*
+ * Copyright (c) 2000-2006 Silicon Graphics, 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 <linux/log2.h>
+
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_format.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_attr_sf.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_buf_item.h"
+#include "xfs_inode_item.h"
+#include "xfs_btree.h"
+#include "xfs_alloc.h"
+#include "xfs_ialloc.h"
+#include "xfs_bmap.h"
+#include "xfs_error.h"
+#include "xfs_quota.h"
+#include "xfs_filestream.h"
+#include "xfs_cksum.h"
+#include "xfs_trace.h"
+#include "xfs_icache.h"
+
+kmem_zone_t *xfs_ifork_zone;
+
+STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int);
+STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int);
+STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int);
+
+#ifdef DEBUG
+/*
+ * Make sure that the extents in the given memory buffer
+ * are valid.
+ */
+void
+xfs_validate_extents(
+       xfs_ifork_t             *ifp,
+       int                     nrecs,
+       xfs_exntfmt_t           fmt)
+{
+       xfs_bmbt_irec_t         irec;
+       xfs_bmbt_rec_host_t     rec;
+       int                     i;
+
+       for (i = 0; i < nrecs; i++) {
+               xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
+               rec.l0 = get_unaligned(&ep->l0);
+               rec.l1 = get_unaligned(&ep->l1);
+               xfs_bmbt_get_all(&rec, &irec);
+               if (fmt == XFS_EXTFMT_NOSTATE)
+                       ASSERT(irec.br_state == XFS_EXT_NORM);
+       }
+}
+#else /* DEBUG */
+#define xfs_validate_extents(ifp, nrecs, fmt)
+#endif /* DEBUG */
+
+
+/*
+ * Move inode type and inode format specific information from the
+ * on-disk inode to the in-core inode.  For fifos, devs, and sockets
+ * this means set if_rdev to the proper value.  For files, directories,
+ * and symlinks this means to bring in the in-line data or extent
+ * pointers.  For a file in B-tree format, only the root is immediately
+ * brought in-core.  The rest will be in-lined in if_extents when it
+ * is first referenced (see xfs_iread_extents()).
+ */
+int
+xfs_iformat_fork(
+       xfs_inode_t             *ip,
+       xfs_dinode_t            *dip)
+{
+       xfs_attr_shortform_t    *atp;
+       int                     size;
+       int                     error = 0;
+       xfs_fsize_t             di_size;
+
+       if (unlikely(be32_to_cpu(dip->di_nextents) +
+                    be16_to_cpu(dip->di_anextents) >
+                    be64_to_cpu(dip->di_nblocks))) {
+               xfs_warn(ip->i_mount,
+                       "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.",
+                       (unsigned long long)ip->i_ino,
+                       (int)(be32_to_cpu(dip->di_nextents) +
+                             be16_to_cpu(dip->di_anextents)),
+                       (unsigned long long)
+                               be64_to_cpu(dip->di_nblocks));
+               XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW,
+                                    ip->i_mount, dip);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) {
+               xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.",
+                       (unsigned long long)ip->i_ino,
+                       dip->di_forkoff);
+               XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW,
+                                    ip->i_mount, dip);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) &&
+                    !ip->i_mount->m_rtdev_targp)) {
+               xfs_warn(ip->i_mount,
+                       "corrupt dinode %Lu, has realtime flag set.",
+                       ip->i_ino);
+               XFS_CORRUPTION_ERROR("xfs_iformat(realtime)",
+                                    XFS_ERRLEVEL_LOW, ip->i_mount, dip);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       switch (ip->i_d.di_mode & S_IFMT) {
+       case S_IFIFO:
+       case S_IFCHR:
+       case S_IFBLK:
+       case S_IFSOCK:
+               if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) {
+                       XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW,
+                                             ip->i_mount, dip);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+               ip->i_d.di_size = 0;
+               ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip);
+               break;
+
+       case S_IFREG:
+       case S_IFLNK:
+       case S_IFDIR:
+               switch (dip->di_format) {
+               case XFS_DINODE_FMT_LOCAL:
+                       /*
+                        * no local regular files yet
+                        */
+                       if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) {
+                               xfs_warn(ip->i_mount,
+                       "corrupt inode %Lu (local format for regular file).",
+                                       (unsigned long long) ip->i_ino);
+                               XFS_CORRUPTION_ERROR("xfs_iformat(4)",
+                                                    XFS_ERRLEVEL_LOW,
+                                                    ip->i_mount, dip);
+                               return XFS_ERROR(EFSCORRUPTED);
+                       }
+
+                       di_size = be64_to_cpu(dip->di_size);
+                       if (unlikely(di_size < 0 ||
+                                    di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) {
+                               xfs_warn(ip->i_mount,
+                       "corrupt inode %Lu (bad size %Ld for local inode).",
+                                       (unsigned long long) ip->i_ino,
+                                       (long long) di_size);
+                               XFS_CORRUPTION_ERROR("xfs_iformat(5)",
+                                                    XFS_ERRLEVEL_LOW,
+                                                    ip->i_mount, dip);
+                               return XFS_ERROR(EFSCORRUPTED);
+                       }
+
+                       size = (int)di_size;
+                       error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size);
+                       break;
+               case XFS_DINODE_FMT_EXTENTS:
+                       error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK);
+                       break;
+               case XFS_DINODE_FMT_BTREE:
+                       error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK);
+                       break;
+               default:
+                       XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW,
+                                        ip->i_mount);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+               break;
+
+       default:
+               XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+       if (error) {
+               return error;
+       }
+       if (!XFS_DFORK_Q(dip))
+               return 0;
+
+       ASSERT(ip->i_afp == NULL);
+       ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS);
+
+       switch (dip->di_aformat) {
+       case XFS_DINODE_FMT_LOCAL:
+               atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
+               size = be16_to_cpu(atp->hdr.totsize);
+
+               if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) {
+                       xfs_warn(ip->i_mount,
+                               "corrupt inode %Lu (bad attr fork size %Ld).",
+                               (unsigned long long) ip->i_ino,
+                               (long long) size);
+                       XFS_CORRUPTION_ERROR("xfs_iformat(8)",
+                                            XFS_ERRLEVEL_LOW,
+                                            ip->i_mount, dip);
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+
+               error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size);
+               break;
+       case XFS_DINODE_FMT_EXTENTS:
+               error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK);
+               break;
+       case XFS_DINODE_FMT_BTREE:
+               error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK);
+               break;
+       default:
+               error = XFS_ERROR(EFSCORRUPTED);
+               break;
+       }
+       if (error) {
+               kmem_zone_free(xfs_ifork_zone, ip->i_afp);
+               ip->i_afp = NULL;
+               xfs_idestroy_fork(ip, XFS_DATA_FORK);
+       }
+       return error;
+}
+
+/*
+ * The file is in-lined in the on-disk inode.
+ * If it fits into if_inline_data, then copy
+ * it there, otherwise allocate a buffer for it
+ * and copy the data there.  Either way, set
+ * if_data to point at the data.
+ * If we allocate a buffer for the data, make
+ * sure that its size is a multiple of 4 and
+ * record the real size in i_real_bytes.
+ */
+STATIC int
+xfs_iformat_local(
+       xfs_inode_t     *ip,
+       xfs_dinode_t    *dip,
+       int             whichfork,
+       int             size)
+{
+       xfs_ifork_t     *ifp;
+       int             real_size;
+
+       /*
+        * If the size is unreasonable, then something
+        * is wrong and we just bail out rather than crash in
+        * kmem_alloc() or memcpy() below.
+        */
+       if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
+               xfs_warn(ip->i_mount,
+       "corrupt inode %Lu (bad size %d for local fork, size = %d).",
+                       (unsigned long long) ip->i_ino, size,
+                       XFS_DFORK_SIZE(dip, ip->i_mount, whichfork));
+               XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW,
+                                    ip->i_mount, dip);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       real_size = 0;
+       if (size == 0)
+               ifp->if_u1.if_data = NULL;
+       else if (size <= sizeof(ifp->if_u2.if_inline_data))
+               ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
+       else {
+               real_size = roundup(size, 4);
+               ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS);
+       }
+       ifp->if_bytes = size;
+       ifp->if_real_bytes = real_size;
+       if (size)
+               memcpy(ifp->if_u1.if_data, XFS_DFORK_PTR(dip, whichfork), size);
+       ifp->if_flags &= ~XFS_IFEXTENTS;
+       ifp->if_flags |= XFS_IFINLINE;
+       return 0;
+}
+
+/*
+ * The file consists of a set of extents all
+ * of which fit into the on-disk inode.
+ * If there are few enough extents to fit into
+ * the if_inline_ext, then copy them there.
+ * Otherwise allocate a buffer for them and copy
+ * them into it.  Either way, set if_extents
+ * to point at the extents.
+ */
+STATIC int
+xfs_iformat_extents(
+       xfs_inode_t     *ip,
+       xfs_dinode_t    *dip,
+       int             whichfork)
+{
+       xfs_bmbt_rec_t  *dp;
+       xfs_ifork_t     *ifp;
+       int             nex;
+       int             size;
+       int             i;
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       nex = XFS_DFORK_NEXTENTS(dip, whichfork);
+       size = nex * (uint)sizeof(xfs_bmbt_rec_t);
+
+       /*
+        * If the number of extents is unreasonable, then something
+        * is wrong and we just bail out rather than crash in
+        * kmem_alloc() or memcpy() below.
+        */
+       if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) {
+               xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
+                       (unsigned long long) ip->i_ino, nex);
+               XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW,
+                                    ip->i_mount, dip);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       ifp->if_real_bytes = 0;
+       if (nex == 0)
+               ifp->if_u1.if_extents = NULL;
+       else if (nex <= XFS_INLINE_EXTS)
+               ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
+       else
+               xfs_iext_add(ifp, 0, nex);
+
+       ifp->if_bytes = size;
+       if (size) {
+               dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork);
+               xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip));
+               for (i = 0; i < nex; i++, dp++) {
+                       xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
+                       ep->l0 = get_unaligned_be64(&dp->l0);
+                       ep->l1 = get_unaligned_be64(&dp->l1);
+               }
+               XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork);
+               if (whichfork != XFS_DATA_FORK ||
+                       XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE)
+                               if (unlikely(xfs_check_nostate_extents(
+                                   ifp, 0, nex))) {
+                                       XFS_ERROR_REPORT("xfs_iformat_extents(2)",
+                                                        XFS_ERRLEVEL_LOW,
+                                                        ip->i_mount);
+                                       return XFS_ERROR(EFSCORRUPTED);
+                               }
+       }
+       ifp->if_flags |= XFS_IFEXTENTS;
+       return 0;
+}
+
+/*
+ * The file has too many extents to fit into
+ * the inode, so they are in B-tree format.
+ * Allocate a buffer for the root of the B-tree
+ * and copy the root into it.  The i_extents
+ * field will remain NULL until all of the
+ * extents are read in (when they are needed).
+ */
+STATIC int
+xfs_iformat_btree(
+       xfs_inode_t             *ip,
+       xfs_dinode_t            *dip,
+       int                     whichfork)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       xfs_bmdr_block_t        *dfp;
+       xfs_ifork_t             *ifp;
+       /* REFERENCED */
+       int                     nrecs;
+       int                     size;
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
+       size = XFS_BMAP_BROOT_SPACE(mp, dfp);
+       nrecs = be16_to_cpu(dfp->bb_numrecs);
+
+       /*
+        * blow out if -- fork has less extents than can fit in
+        * fork (fork shouldn't be a btree format), root btree
+        * block has more records than can fit into the fork,
+        * or the number of extents is greater than the number of
+        * blocks.
+        */
+       if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <=
+                                       XFS_IFORK_MAXEXT(ip, whichfork) ||
+                    XFS_BMDR_SPACE_CALC(nrecs) >
+                                       XFS_DFORK_SIZE(dip, mp, whichfork) ||
+                    XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) {
+               xfs_warn(mp, "corrupt inode %Lu (btree).",
+                                       (unsigned long long) ip->i_ino);
+               XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW,
+                                        mp, dip);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       ifp->if_broot_bytes = size;
+       ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS);
+       ASSERT(ifp->if_broot != NULL);
+       /*
+        * Copy and convert from the on-disk structure
+        * to the in-memory structure.
+        */
+       xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork),
+                        ifp->if_broot, size);
+       ifp->if_flags &= ~XFS_IFEXTENTS;
+       ifp->if_flags |= XFS_IFBROOT;
+
+       return 0;
+}
+
+/*
+ * Read in extents from a btree-format inode.
+ * Allocate and fill in if_extents.  Real work is done in xfs_bmap.c.
+ */
+int
+xfs_iread_extents(
+       xfs_trans_t     *tp,
+       xfs_inode_t     *ip,
+       int             whichfork)
+{
+       int             error;
+       xfs_ifork_t     *ifp;
+       xfs_extnum_t    nextents;
+
+       if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) {
+               XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW,
+                                ip->i_mount);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+       nextents = XFS_IFORK_NEXTENTS(ip, whichfork);
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+
+       /*
+        * We know that the size is valid (it's checked in iformat_btree)
+        */
+       ifp->if_bytes = ifp->if_real_bytes = 0;
+       ifp->if_flags |= XFS_IFEXTENTS;
+       xfs_iext_add(ifp, 0, nextents);
+       error = xfs_bmap_read_extents(tp, ip, whichfork);
+       if (error) {
+               xfs_iext_destroy(ifp);
+               ifp->if_flags &= ~XFS_IFEXTENTS;
+               return error;
+       }
+       xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip));
+       return 0;
+}
+/*
+ * Reallocate the space for if_broot based on the number of records
+ * being added or deleted as indicated in rec_diff.  Move the records
+ * and pointers in if_broot to fit the new size.  When shrinking this
+ * will eliminate holes between the records and pointers created by
+ * the caller.  When growing this will create holes to be filled in
+ * by the caller.
+ *
+ * The caller must not request to add more records than would fit in
+ * the on-disk inode root.  If the if_broot is currently NULL, then
+ * if we are adding records, one will be allocated.  The caller must also
+ * not request that the number of records go below zero, although
+ * it can go to zero.
+ *
+ * ip -- the inode whose if_broot area is changing
+ * ext_diff -- the change in the number of records, positive or negative,
+ *      requested for the if_broot array.
+ */
+void
+xfs_iroot_realloc(
+       xfs_inode_t             *ip,
+       int                     rec_diff,
+       int                     whichfork)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       int                     cur_max;
+       xfs_ifork_t             *ifp;
+       struct xfs_btree_block  *new_broot;
+       int                     new_max;
+       size_t                  new_size;
+       char                    *np;
+       char                    *op;
+
+       /*
+        * Handle the degenerate case quietly.
+        */
+       if (rec_diff == 0) {
+               return;
+       }
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       if (rec_diff > 0) {
+               /*
+                * If there wasn't any memory allocated before, just
+                * allocate it now and get out.
+                */
+               if (ifp->if_broot_bytes == 0) {
+                       new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
+                       ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
+                       ifp->if_broot_bytes = (int)new_size;
+                       return;
+               }
+
+               /*
+                * If there is already an existing if_broot, then we need
+                * to realloc() it and shift the pointers to their new
+                * location.  The records don't change location because
+                * they are kept butted up against the btree block header.
+                */
+               cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
+               new_max = cur_max + rec_diff;
+               new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
+               ifp->if_broot = kmem_realloc(ifp->if_broot, new_size,
+                               XFS_BMAP_BROOT_SPACE_CALC(mp, cur_max),
+                               KM_SLEEP | KM_NOFS);
+               op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+                                                    ifp->if_broot_bytes);
+               np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+                                                    (int)new_size);
+               ifp->if_broot_bytes = (int)new_size;
+               ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+                       XFS_IFORK_SIZE(ip, whichfork));
+               memmove(np, op, cur_max * (uint)sizeof(xfs_dfsbno_t));
+               return;
+       }
+
+       /*
+        * rec_diff is less than 0.  In this case, we are shrinking the
+        * if_broot buffer.  It must already exist.  If we go to zero
+        * records, just get rid of the root and clear the status bit.
+        */
+       ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
+       cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
+       new_max = cur_max + rec_diff;
+       ASSERT(new_max >= 0);
+       if (new_max > 0)
+               new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
+       else
+               new_size = 0;
+       if (new_size > 0) {
+               new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS);
+               /*
+                * First copy over the btree block header.
+                */
+               memcpy(new_broot, ifp->if_broot,
+                       XFS_BMBT_BLOCK_LEN(ip->i_mount));
+       } else {
+               new_broot = NULL;
+               ifp->if_flags &= ~XFS_IFBROOT;
+       }
+
+       /*
+        * Only copy the records and pointers if there are any.
+        */
+       if (new_max > 0) {
+               /*
+                * First copy the records.
+                */
+               op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
+               np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
+               memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
+
+               /*
+                * Then copy the pointers.
+                */
+               op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+                                                    ifp->if_broot_bytes);
+               np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
+                                                    (int)new_size);
+               memcpy(np, op, new_max * (uint)sizeof(xfs_dfsbno_t));
+       }
+       kmem_free(ifp->if_broot);
+       ifp->if_broot = new_broot;
+       ifp->if_broot_bytes = (int)new_size;
+       if (ifp->if_broot)
+               ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+                       XFS_IFORK_SIZE(ip, whichfork));
+       return;
+}
+
+
+/*
+ * This is called when the amount of space needed for if_data
+ * is increased or decreased.  The change in size is indicated by
+ * the number of bytes that need to be added or deleted in the
+ * byte_diff parameter.
+ *
+ * If the amount of space needed has decreased below the size of the
+ * inline buffer, then switch to using the inline buffer.  Otherwise,
+ * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer
+ * to what is needed.
+ *
+ * ip -- the inode whose if_data area is changing
+ * byte_diff -- the change in the number of bytes, positive or negative,
+ *      requested for the if_data array.
+ */
+void
+xfs_idata_realloc(
+       xfs_inode_t     *ip,
+       int             byte_diff,
+       int             whichfork)
+{
+       xfs_ifork_t     *ifp;
+       int             new_size;
+       int             real_size;
+
+       if (byte_diff == 0) {
+               return;
+       }
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       new_size = (int)ifp->if_bytes + byte_diff;
+       ASSERT(new_size >= 0);
+
+       if (new_size == 0) {
+               if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
+                       kmem_free(ifp->if_u1.if_data);
+               }
+               ifp->if_u1.if_data = NULL;
+               real_size = 0;
+       } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) {
+               /*
+                * If the valid extents/data can fit in if_inline_ext/data,
+                * copy them from the malloc'd vector and free it.
+                */
+               if (ifp->if_u1.if_data == NULL) {
+                       ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
+               } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
+                       ASSERT(ifp->if_real_bytes != 0);
+                       memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data,
+                             new_size);
+                       kmem_free(ifp->if_u1.if_data);
+                       ifp->if_u1.if_data = ifp->if_u2.if_inline_data;
+               }
+               real_size = 0;
+       } else {
+               /*
+                * Stuck with malloc/realloc.
+                * For inline data, the underlying buffer must be
+                * a multiple of 4 bytes in size so that it can be
+                * logged and stay on word boundaries.  We enforce
+                * that here.
+                */
+               real_size = roundup(new_size, 4);
+               if (ifp->if_u1.if_data == NULL) {
+                       ASSERT(ifp->if_real_bytes == 0);
+                       ifp->if_u1.if_data = kmem_alloc(real_size,
+                                                       KM_SLEEP | KM_NOFS);
+               } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) {
+                       /*
+                        * Only do the realloc if the underlying size
+                        * is really changing.
+                        */
+                       if (ifp->if_real_bytes != real_size) {
+                               ifp->if_u1.if_data =
+                                       kmem_realloc(ifp->if_u1.if_data,
+                                                       real_size,
+                                                       ifp->if_real_bytes,
+                                                       KM_SLEEP | KM_NOFS);
+                       }
+               } else {
+                       ASSERT(ifp->if_real_bytes == 0);
+                       ifp->if_u1.if_data = kmem_alloc(real_size,
+                                                       KM_SLEEP | KM_NOFS);
+                       memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data,
+                               ifp->if_bytes);
+               }
+       }
+       ifp->if_real_bytes = real_size;
+       ifp->if_bytes = new_size;
+       ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
+}
+
+void
+xfs_idestroy_fork(
+       xfs_inode_t     *ip,
+       int             whichfork)
+{
+       xfs_ifork_t     *ifp;
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       if (ifp->if_broot != NULL) {
+               kmem_free(ifp->if_broot);
+               ifp->if_broot = NULL;
+       }
+
+       /*
+        * If the format is local, then we can't have an extents
+        * array so just look for an inline data array.  If we're
+        * not local then we may or may not have an extents list,
+        * so check and free it up if we do.
+        */
+       if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) {
+               if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) &&
+                   (ifp->if_u1.if_data != NULL)) {
+                       ASSERT(ifp->if_real_bytes != 0);
+                       kmem_free(ifp->if_u1.if_data);
+                       ifp->if_u1.if_data = NULL;
+                       ifp->if_real_bytes = 0;
+               }
+       } else if ((ifp->if_flags & XFS_IFEXTENTS) &&
+                  ((ifp->if_flags & XFS_IFEXTIREC) ||
+                   ((ifp->if_u1.if_extents != NULL) &&
+                    (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) {
+               ASSERT(ifp->if_real_bytes != 0);
+               xfs_iext_destroy(ifp);
+       }
+       ASSERT(ifp->if_u1.if_extents == NULL ||
+              ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext);
+       ASSERT(ifp->if_real_bytes == 0);
+       if (whichfork == XFS_ATTR_FORK) {
+               kmem_zone_free(xfs_ifork_zone, ip->i_afp);
+               ip->i_afp = NULL;
+       }
+}
+
+/*
+ * xfs_iextents_copy()
+ *
+ * This is called to copy the REAL extents (as opposed to the delayed
+ * allocation extents) from the inode into the given buffer.  It
+ * returns the number of bytes copied into the buffer.
+ *
+ * If there are no delayed allocation extents, then we can just
+ * memcpy() the extents into the buffer.  Otherwise, we need to
+ * examine each extent in turn and skip those which are delayed.
+ */
+int
+xfs_iextents_copy(
+       xfs_inode_t             *ip,
+       xfs_bmbt_rec_t          *dp,
+       int                     whichfork)
+{
+       int                     copied;
+       int                     i;
+       xfs_ifork_t             *ifp;
+       int                     nrecs;
+       xfs_fsblock_t           start_block;
+
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
+       ASSERT(ifp->if_bytes > 0);
+
+       nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork);
+       ASSERT(nrecs > 0);
+
+       /*
+        * There are some delayed allocation extents in the
+        * inode, so copy the extents one at a time and skip
+        * the delayed ones.  There must be at least one
+        * non-delayed extent.
+        */
+       copied = 0;
+       for (i = 0; i < nrecs; i++) {
+               xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i);
+               start_block = xfs_bmbt_get_startblock(ep);
+               if (isnullstartblock(start_block)) {
+                       /*
+                        * It's a delayed allocation extent, so skip it.
+                        */
+                       continue;
+               }
+
+               /* Translate to on disk format */
+               put_unaligned_be64(ep->l0, &dp->l0);
+               put_unaligned_be64(ep->l1, &dp->l1);
+               dp++;
+               copied++;
+       }
+       ASSERT(copied != 0);
+       xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip));
+
+       return (copied * (uint)sizeof(xfs_bmbt_rec_t));
+}
+
+/*
+ * Each of the following cases stores data into the same region
+ * of the on-disk inode, so only one of them can be valid at
+ * any given time. While it is possible to have conflicting formats
+ * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is
+ * in EXTENTS format, this can only happen when the fork has
+ * changed formats after being modified but before being flushed.
+ * In these cases, the format always takes precedence, because the
+ * format indicates the current state of the fork.
+ */
+void
+xfs_iflush_fork(
+       xfs_inode_t             *ip,
+       xfs_dinode_t            *dip,
+       xfs_inode_log_item_t    *iip,
+       int                     whichfork,
+       xfs_buf_t               *bp)
+{
+       char                    *cp;
+       xfs_ifork_t             *ifp;
+       xfs_mount_t             *mp;
+       static const short      brootflag[2] =
+               { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT };
+       static const short      dataflag[2] =
+               { XFS_ILOG_DDATA, XFS_ILOG_ADATA };
+       static const short      extflag[2] =
+               { XFS_ILOG_DEXT, XFS_ILOG_AEXT };
+
+       if (!iip)
+               return;
+       ifp = XFS_IFORK_PTR(ip, whichfork);
+       /*
+        * This can happen if we gave up in iformat in an error path,
+        * for the attribute fork.
+        */
+       if (!ifp) {
+               ASSERT(whichfork == XFS_ATTR_FORK);
+               return;
+       }
+       cp = XFS_DFORK_PTR(dip, whichfork);
+       mp = ip->i_mount;
+       switch (XFS_IFORK_FORMAT(ip, whichfork)) {
+       case XFS_DINODE_FMT_LOCAL:
+               if ((iip->ili_fields & dataflag[whichfork]) &&
+                   (ifp->if_bytes > 0)) {
+                       ASSERT(ifp->if_u1.if_data != NULL);
+                       ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork));
+                       memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes);
+               }
+               break;
+
+       case XFS_DINODE_FMT_EXTENTS:
+               ASSERT((ifp->if_flags & XFS_IFEXTENTS) ||
+                      !(iip->ili_fields & extflag[whichfork]));
+               if ((iip->ili_fields & extflag[whichfork]) &&
+                   (ifp->if_bytes > 0)) {
+                       ASSERT(xfs_iext_get_ext(ifp, 0));
+                       ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0);
+                       (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp,
+                               whichfork);
+               }
+               break;
+
+       case XFS_DINODE_FMT_BTREE:
+               if ((iip->ili_fields & brootflag[whichfork]) &&
+                   (ifp->if_broot_bytes > 0)) {
+                       ASSERT(ifp->if_broot != NULL);
+                       ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+                               XFS_IFORK_SIZE(ip, whichfork));
+                       xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
+                               (xfs_bmdr_block_t *)cp,
+                               XFS_DFORK_SIZE(dip, mp, whichfork));
+               }
+               break;
+
+       case XFS_DINODE_FMT_DEV:
+               if (iip->ili_fields & XFS_ILOG_DEV) {
+                       ASSERT(whichfork == XFS_DATA_FORK);
+                       xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev);
+               }
+               break;
+
+       case XFS_DINODE_FMT_UUID:
+               if (iip->ili_fields & XFS_ILOG_UUID) {
+                       ASSERT(whichfork == XFS_DATA_FORK);
+                       memcpy(XFS_DFORK_DPTR(dip),
+                              &ip->i_df.if_u2.if_uuid,
+                              sizeof(uuid_t));
+               }
+               break;
+
+       default:
+               ASSERT(0);
+               break;
+       }
+}
+
+/*
+ * Return a pointer to the extent record at file index idx.
+ */
+xfs_bmbt_rec_host_t *
+xfs_iext_get_ext(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    idx)            /* index of target extent */
+{
+       ASSERT(idx >= 0);
+       ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
+
+       if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) {
+               return ifp->if_u1.if_ext_irec->er_extbuf;
+       } else if (ifp->if_flags & XFS_IFEXTIREC) {
+               xfs_ext_irec_t  *erp;           /* irec pointer */
+               int             erp_idx = 0;    /* irec index */
+               xfs_extnum_t    page_idx = idx; /* ext index in target list */
+
+               erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0);
+               return &erp->er_extbuf[page_idx];
+       } else if (ifp->if_bytes) {
+               return &ifp->if_u1.if_extents[idx];
+       } else {
+               return NULL;
+       }
+}
+
+/*
+ * Insert new item(s) into the extent records for incore inode
+ * fork 'ifp'.  'count' new items are inserted at index 'idx'.
+ */
+void
+xfs_iext_insert(
+       xfs_inode_t     *ip,            /* incore inode pointer */
+       xfs_extnum_t    idx,            /* starting index of new items */
+       xfs_extnum_t    count,          /* number of inserted items */
+       xfs_bmbt_irec_t *new,           /* items to insert */
+       int             state)          /* type of extent conversion */
+{
+       xfs_ifork_t     *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
+       xfs_extnum_t    i;              /* extent record index */
+
+       trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_);
+
+       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
+       xfs_iext_add(ifp, idx, count);
+       for (i = idx; i < idx + count; i++, new++)
+               xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new);
+}
+
+/*
+ * This is called when the amount of space required for incore file
+ * extents needs to be increased. The ext_diff parameter stores the
+ * number of new extents being added and the idx parameter contains
+ * the extent index where the new extents will be added. If the new
+ * extents are being appended, then we just need to (re)allocate and
+ * initialize the space. Otherwise, if the new extents are being
+ * inserted into the middle of the existing entries, a bit more work
+ * is required to make room for the new extents to be inserted. The
+ * caller is responsible for filling in the new extent entries upon
+ * return.
+ */
+void
+xfs_iext_add(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    idx,            /* index to begin adding exts */
+       int             ext_diff)       /* number of extents to add */
+{
+       int             byte_diff;      /* new bytes being added */
+       int             new_size;       /* size of extents after adding */
+       xfs_extnum_t    nextents;       /* number of extents in file */
+
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       ASSERT((idx >= 0) && (idx <= nextents));
+       byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t);
+       new_size = ifp->if_bytes + byte_diff;
+       /*
+        * If the new number of extents (nextents + ext_diff)
+        * fits inside the inode, then continue to use the inline
+        * extent buffer.
+        */
+       if (nextents + ext_diff <= XFS_INLINE_EXTS) {
+               if (idx < nextents) {
+                       memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff],
+                               &ifp->if_u2.if_inline_ext[idx],
+                               (nextents - idx) * sizeof(xfs_bmbt_rec_t));
+                       memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff);
+               }
+               ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
+               ifp->if_real_bytes = 0;
+       }
+       /*
+        * Otherwise use a linear (direct) extent list.
+        * If the extents are currently inside the inode,
+        * xfs_iext_realloc_direct will switch us from
+        * inline to direct extent allocation mode.
+        */
+       else if (nextents + ext_diff <= XFS_LINEAR_EXTS) {
+               xfs_iext_realloc_direct(ifp, new_size);
+               if (idx < nextents) {
+                       memmove(&ifp->if_u1.if_extents[idx + ext_diff],
+                               &ifp->if_u1.if_extents[idx],
+                               (nextents - idx) * sizeof(xfs_bmbt_rec_t));
+                       memset(&ifp->if_u1.if_extents[idx], 0, byte_diff);
+               }
+       }
+       /* Indirection array */
+       else {
+               xfs_ext_irec_t  *erp;
+               int             erp_idx = 0;
+               int             page_idx = idx;
+
+               ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS);
+               if (ifp->if_flags & XFS_IFEXTIREC) {
+                       erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1);
+               } else {
+                       xfs_iext_irec_init(ifp);
+                       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+                       erp = ifp->if_u1.if_ext_irec;
+               }
+               /* Extents fit in target extent page */
+               if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) {
+                       if (page_idx < erp->er_extcount) {
+                               memmove(&erp->er_extbuf[page_idx + ext_diff],
+                                       &erp->er_extbuf[page_idx],
+                                       (erp->er_extcount - page_idx) *
+                                       sizeof(xfs_bmbt_rec_t));
+                               memset(&erp->er_extbuf[page_idx], 0, byte_diff);
+                       }
+                       erp->er_extcount += ext_diff;
+                       xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
+               }
+               /* Insert a new extent page */
+               else if (erp) {
+                       xfs_iext_add_indirect_multi(ifp,
+                               erp_idx, page_idx, ext_diff);
+               }
+               /*
+                * If extent(s) are being appended to the last page in
+                * the indirection array and the new extent(s) don't fit
+                * in the page, then erp is NULL and erp_idx is set to
+                * the next index needed in the indirection array.
+                */
+               else {
+                       int     count = ext_diff;
+
+                       while (count) {
+                               erp = xfs_iext_irec_new(ifp, erp_idx);
+                               erp->er_extcount = count;
+                               count -= MIN(count, (int)XFS_LINEAR_EXTS);
+                               if (count) {
+                                       erp_idx++;
+                               }
+                       }
+               }
+       }
+       ifp->if_bytes = new_size;
+}
+
+/*
+ * This is called when incore extents are being added to the indirection
+ * array and the new extents do not fit in the target extent list. The
+ * erp_idx parameter contains the irec index for the target extent list
+ * in the indirection array, and the idx parameter contains the extent
+ * index within the list. The number of extents being added is stored
+ * in the count parameter.
+ *
+ *    |-------|   |-------|
+ *    |       |   |       |    idx - number of extents before idx
+ *    |  idx  |   | count |
+ *    |       |   |       |    count - number of extents being inserted at idx
+ *    |-------|   |-------|
+ *    | count |   | nex2  |    nex2 - number of extents after idx + count
+ *    |-------|   |-------|
+ */
+void
+xfs_iext_add_indirect_multi(
+       xfs_ifork_t     *ifp,                   /* inode fork pointer */
+       int             erp_idx,                /* target extent irec index */
+       xfs_extnum_t    idx,                    /* index within target list */
+       int             count)                  /* new extents being added */
+{
+       int             byte_diff;              /* new bytes being added */
+       xfs_ext_irec_t  *erp;                   /* pointer to irec entry */
+       xfs_extnum_t    ext_diff;               /* number of extents to add */
+       xfs_extnum_t    ext_cnt;                /* new extents still needed */
+       xfs_extnum_t    nex2;                   /* extents after idx + count */
+       xfs_bmbt_rec_t  *nex2_ep = NULL;        /* temp list for nex2 extents */
+       int             nlists;                 /* number of irec's (lists) */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       erp = &ifp->if_u1.if_ext_irec[erp_idx];
+       nex2 = erp->er_extcount - idx;
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+
+       /*
+        * Save second part of target extent list
+        * (all extents past */
+       if (nex2) {
+               byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
+               nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS);
+               memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff);
+               erp->er_extcount -= nex2;
+               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2);
+               memset(&erp->er_extbuf[idx], 0, byte_diff);
+       }
+
+       /*
+        * Add the new extents to the end of the target
+        * list, then allocate new irec record(s) and
+        * extent buffer(s) as needed to store the rest
+        * of the new extents.
+        */
+       ext_cnt = count;
+       ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount);
+       if (ext_diff) {
+               erp->er_extcount += ext_diff;
+               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
+               ext_cnt -= ext_diff;
+       }
+       while (ext_cnt) {
+               erp_idx++;
+               erp = xfs_iext_irec_new(ifp, erp_idx);
+               ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS);
+               erp->er_extcount = ext_diff;
+               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff);
+               ext_cnt -= ext_diff;
+       }
+
+       /* Add nex2 extents back to indirection array */
+       if (nex2) {
+               xfs_extnum_t    ext_avail;
+               int             i;
+
+               byte_diff = nex2 * sizeof(xfs_bmbt_rec_t);
+               ext_avail = XFS_LINEAR_EXTS - erp->er_extcount;
+               i = 0;
+               /*
+                * If nex2 extents fit in the current page, append
+                * nex2_ep after the new extents.
+                */
+               if (nex2 <= ext_avail) {
+                       i = erp->er_extcount;
+               }
+               /*
+                * Otherwise, check if space is available in the
+                * next page.
+                */
+               else if ((erp_idx < nlists - 1) &&
+                        (nex2 <= (ext_avail = XFS_LINEAR_EXTS -
+                         ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) {
+                       erp_idx++;
+                       erp++;
+                       /* Create a hole for nex2 extents */
+                       memmove(&erp->er_extbuf[nex2], erp->er_extbuf,
+                               erp->er_extcount * sizeof(xfs_bmbt_rec_t));
+               }
+               /*
+                * Final choice, create a new extent page for
+                * nex2 extents.
+                */
+               else {
+                       erp_idx++;
+                       erp = xfs_iext_irec_new(ifp, erp_idx);
+               }
+               memmove(&erp->er_extbuf[i], nex2_ep, byte_diff);
+               kmem_free(nex2_ep);
+               erp->er_extcount += nex2;
+               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2);
+       }
+}
+
+/*
+ * This is called when the amount of space required for incore file
+ * extents needs to be decreased. The ext_diff parameter stores the
+ * number of extents to be removed and the idx parameter contains
+ * the extent index where the extents will be removed from.
+ *
+ * If the amount of space needed has decreased below the linear
+ * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous
+ * extent array.  Otherwise, use kmem_realloc() to adjust the
+ * size to what is needed.
+ */
+void
+xfs_iext_remove(
+       xfs_inode_t     *ip,            /* incore inode pointer */
+       xfs_extnum_t    idx,            /* index to begin removing exts */
+       int             ext_diff,       /* number of extents to remove */
+       int             state)          /* type of extent conversion */
+{
+       xfs_ifork_t     *ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
+       xfs_extnum_t    nextents;       /* number of extents in file */
+       int             new_size;       /* size of extents after removal */
+
+       trace_xfs_iext_remove(ip, idx, state, _RET_IP_);
+
+       ASSERT(ext_diff > 0);
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t);
+
+       if (new_size == 0) {
+               xfs_iext_destroy(ifp);
+       } else if (ifp->if_flags & XFS_IFEXTIREC) {
+               xfs_iext_remove_indirect(ifp, idx, ext_diff);
+       } else if (ifp->if_real_bytes) {
+               xfs_iext_remove_direct(ifp, idx, ext_diff);
+       } else {
+               xfs_iext_remove_inline(ifp, idx, ext_diff);
+       }
+       ifp->if_bytes = new_size;
+}
+
+/*
+ * This removes ext_diff extents from the inline buffer, beginning
+ * at extent index idx.
+ */
+void
+xfs_iext_remove_inline(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    idx,            /* index to begin removing exts */
+       int             ext_diff)       /* number of extents to remove */
+{
+       int             nextents;       /* number of extents in file */
+
+       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
+       ASSERT(idx < XFS_INLINE_EXTS);
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       ASSERT(((nextents - ext_diff) > 0) &&
+               (nextents - ext_diff) < XFS_INLINE_EXTS);
+
+       if (idx + ext_diff < nextents) {
+               memmove(&ifp->if_u2.if_inline_ext[idx],
+                       &ifp->if_u2.if_inline_ext[idx + ext_diff],
+                       (nextents - (idx + ext_diff)) *
+                        sizeof(xfs_bmbt_rec_t));
+               memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff],
+                       0, ext_diff * sizeof(xfs_bmbt_rec_t));
+       } else {
+               memset(&ifp->if_u2.if_inline_ext[idx], 0,
+                       ext_diff * sizeof(xfs_bmbt_rec_t));
+       }
+}
+
+/*
+ * This removes ext_diff extents from a linear (direct) extent list,
+ * beginning at extent index idx. If the extents are being removed
+ * from the end of the list (ie. truncate) then we just need to re-
+ * allocate the list to remove the extra space. Otherwise, if the
+ * extents are being removed from the middle of the existing extent
+ * entries, then we first need to move the extent records beginning
+ * at idx + ext_diff up in the list to overwrite the records being
+ * removed, then remove the extra space via kmem_realloc.
+ */
+void
+xfs_iext_remove_direct(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    idx,            /* index to begin removing exts */
+       int             ext_diff)       /* number of extents to remove */
+{
+       xfs_extnum_t    nextents;       /* number of extents in file */
+       int             new_size;       /* size of extents after removal */
+
+       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
+       new_size = ifp->if_bytes -
+               (ext_diff * sizeof(xfs_bmbt_rec_t));
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+
+       if (new_size == 0) {
+               xfs_iext_destroy(ifp);
+               return;
+       }
+       /* Move extents up in the list (if needed) */
+       if (idx + ext_diff < nextents) {
+               memmove(&ifp->if_u1.if_extents[idx],
+                       &ifp->if_u1.if_extents[idx + ext_diff],
+                       (nextents - (idx + ext_diff)) *
+                        sizeof(xfs_bmbt_rec_t));
+       }
+       memset(&ifp->if_u1.if_extents[nextents - ext_diff],
+               0, ext_diff * sizeof(xfs_bmbt_rec_t));
+       /*
+        * Reallocate the direct extent list. If the extents
+        * will fit inside the inode then xfs_iext_realloc_direct
+        * will switch from direct to inline extent allocation
+        * mode for us.
+        */
+       xfs_iext_realloc_direct(ifp, new_size);
+       ifp->if_bytes = new_size;
+}
+
+/*
+ * This is called when incore extents are being removed from the
+ * indirection array and the extents being removed span multiple extent
+ * buffers. The idx parameter contains the file extent index where we
+ * want to begin removing extents, and the count parameter contains
+ * how many extents need to be removed.
+ *
+ *    |-------|   |-------|
+ *    | nex1  |   |       |    nex1 - number of extents before idx
+ *    |-------|   | count |
+ *    |       |   |       |    count - number of extents being removed at idx
+ *    | count |   |-------|
+ *    |       |   | nex2  |    nex2 - number of extents after idx + count
+ *    |-------|   |-------|
+ */
+void
+xfs_iext_remove_indirect(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    idx,            /* index to begin removing extents */
+       int             count)          /* number of extents to remove */
+{
+       xfs_ext_irec_t  *erp;           /* indirection array pointer */
+       int             erp_idx = 0;    /* indirection array index */
+       xfs_extnum_t    ext_cnt;        /* extents left to remove */
+       xfs_extnum_t    ext_diff;       /* extents to remove in current list */
+       xfs_extnum_t    nex1;           /* number of extents before idx */
+       xfs_extnum_t    nex2;           /* extents after idx + count */
+       int             page_idx = idx; /* index in target extent list */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       erp = xfs_iext_idx_to_irec(ifp,  &page_idx, &erp_idx, 0);
+       ASSERT(erp != NULL);
+       nex1 = page_idx;
+       ext_cnt = count;
+       while (ext_cnt) {
+               nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0);
+               ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1));
+               /*
+                * Check for deletion of entire list;
+                * xfs_iext_irec_remove() updates extent offsets.
+                */
+               if (ext_diff == erp->er_extcount) {
+                       xfs_iext_irec_remove(ifp, erp_idx);
+                       ext_cnt -= ext_diff;
+                       nex1 = 0;
+                       if (ext_cnt) {
+                               ASSERT(erp_idx < ifp->if_real_bytes /
+                                       XFS_IEXT_BUFSZ);
+                               erp = &ifp->if_u1.if_ext_irec[erp_idx];
+                               nex1 = 0;
+                               continue;
+                       } else {
+                               break;
+                       }
+               }
+               /* Move extents up (if needed) */
+               if (nex2) {
+                       memmove(&erp->er_extbuf[nex1],
+                               &erp->er_extbuf[nex1 + ext_diff],
+                               nex2 * sizeof(xfs_bmbt_rec_t));
+               }
+               /* Zero out rest of page */
+               memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ -
+                       ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t))));
+               /* Update remaining counters */
+               erp->er_extcount -= ext_diff;
+               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff);
+               ext_cnt -= ext_diff;
+               nex1 = 0;
+               erp_idx++;
+               erp++;
+       }
+       ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t);
+       xfs_iext_irec_compact(ifp);
+}
+
+/*
+ * Create, destroy, or resize a linear (direct) block of extents.
+ */
+void
+xfs_iext_realloc_direct(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       int             new_size)       /* new size of extents */
+{
+       int             rnew_size;      /* real new size of extents */
+
+       rnew_size = new_size;
+
+       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) ||
+               ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) &&
+                (new_size != ifp->if_real_bytes)));
+
+       /* Free extent records */
+       if (new_size == 0) {
+               xfs_iext_destroy(ifp);
+       }
+       /* Resize direct extent list and zero any new bytes */
+       else if (ifp->if_real_bytes) {
+               /* Check if extents will fit inside the inode */
+               if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) {
+                       xfs_iext_direct_to_inline(ifp, new_size /
+                               (uint)sizeof(xfs_bmbt_rec_t));
+                       ifp->if_bytes = new_size;
+                       return;
+               }
+               if (!is_power_of_2(new_size)){
+                       rnew_size = roundup_pow_of_two(new_size);
+               }
+               if (rnew_size != ifp->if_real_bytes) {
+                       ifp->if_u1.if_extents =
+                               kmem_realloc(ifp->if_u1.if_extents,
+                                               rnew_size,
+                                               ifp->if_real_bytes, KM_NOFS);
+               }
+               if (rnew_size > ifp->if_real_bytes) {
+                       memset(&ifp->if_u1.if_extents[ifp->if_bytes /
+                               (uint)sizeof(xfs_bmbt_rec_t)], 0,
+                               rnew_size - ifp->if_real_bytes);
+               }
+       }
+       /*
+        * Switch from the inline extent buffer to a direct
+        * extent list. Be sure to include the inline extent
+        * bytes in new_size.
+        */
+       else {
+               new_size += ifp->if_bytes;
+               if (!is_power_of_2(new_size)) {
+                       rnew_size = roundup_pow_of_two(new_size);
+               }
+               xfs_iext_inline_to_direct(ifp, rnew_size);
+       }
+       ifp->if_real_bytes = rnew_size;
+       ifp->if_bytes = new_size;
+}
+
+/*
+ * Switch from linear (direct) extent records to inline buffer.
+ */
+void
+xfs_iext_direct_to_inline(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    nextents)       /* number of extents in file */
+{
+       ASSERT(ifp->if_flags & XFS_IFEXTENTS);
+       ASSERT(nextents <= XFS_INLINE_EXTS);
+       /*
+        * The inline buffer was zeroed when we switched
+        * from inline to direct extent allocation mode,
+        * so we don't need to clear it here.
+        */
+       memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents,
+               nextents * sizeof(xfs_bmbt_rec_t));
+       kmem_free(ifp->if_u1.if_extents);
+       ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext;
+       ifp->if_real_bytes = 0;
+}
+
+/*
+ * Switch from inline buffer to linear (direct) extent records.
+ * new_size should already be rounded up to the next power of 2
+ * by the caller (when appropriate), so use new_size as it is.
+ * However, since new_size may be rounded up, we can't update
+ * if_bytes here. It is the caller's responsibility to update
+ * if_bytes upon return.
+ */
+void
+xfs_iext_inline_to_direct(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       int             new_size)       /* number of extents in file */
+{
+       ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS);
+       memset(ifp->if_u1.if_extents, 0, new_size);
+       if (ifp->if_bytes) {
+               memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext,
+                       ifp->if_bytes);
+               memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
+                       sizeof(xfs_bmbt_rec_t));
+       }
+       ifp->if_real_bytes = new_size;
+}
+
+/*
+ * Resize an extent indirection array to new_size bytes.
+ */
+STATIC void
+xfs_iext_realloc_indirect(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       int             new_size)       /* new indirection array size */
+{
+       int             nlists;         /* number of irec's (ex lists) */
+       int             size;           /* current indirection array size */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       size = nlists * sizeof(xfs_ext_irec_t);
+       ASSERT(ifp->if_real_bytes);
+       ASSERT((new_size >= 0) && (new_size != size));
+       if (new_size == 0) {
+               xfs_iext_destroy(ifp);
+       } else {
+               ifp->if_u1.if_ext_irec = (xfs_ext_irec_t *)
+                       kmem_realloc(ifp->if_u1.if_ext_irec,
+                               new_size, size, KM_NOFS);
+       }
+}
+
+/*
+ * Switch from indirection array to linear (direct) extent allocations.
+ */
+STATIC void
+xfs_iext_indirect_to_direct(
+        xfs_ifork_t    *ifp)           /* inode fork pointer */
+{
+       xfs_bmbt_rec_host_t *ep;        /* extent record pointer */
+       xfs_extnum_t    nextents;       /* number of extents in file */
+       int             size;           /* size of file extents */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       ASSERT(nextents <= XFS_LINEAR_EXTS);
+       size = nextents * sizeof(xfs_bmbt_rec_t);
+
+       xfs_iext_irec_compact_pages(ifp);
+       ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ);
+
+       ep = ifp->if_u1.if_ext_irec->er_extbuf;
+       kmem_free(ifp->if_u1.if_ext_irec);
+       ifp->if_flags &= ~XFS_IFEXTIREC;
+       ifp->if_u1.if_extents = ep;
+       ifp->if_bytes = size;
+       if (nextents < XFS_LINEAR_EXTS) {
+               xfs_iext_realloc_direct(ifp, size);
+       }
+}
+
+/*
+ * Free incore file extents.
+ */
+void
+xfs_iext_destroy(
+       xfs_ifork_t     *ifp)           /* inode fork pointer */
+{
+       if (ifp->if_flags & XFS_IFEXTIREC) {
+               int     erp_idx;
+               int     nlists;
+
+               nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+               for (erp_idx = nlists - 1; erp_idx >= 0 ; erp_idx--) {
+                       xfs_iext_irec_remove(ifp, erp_idx);
+               }
+               ifp->if_flags &= ~XFS_IFEXTIREC;
+       } else if (ifp->if_real_bytes) {
+               kmem_free(ifp->if_u1.if_extents);
+       } else if (ifp->if_bytes) {
+               memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS *
+                       sizeof(xfs_bmbt_rec_t));
+       }
+       ifp->if_u1.if_extents = NULL;
+       ifp->if_real_bytes = 0;
+       ifp->if_bytes = 0;
+}
+
+/*
+ * Return a pointer to the extent record for file system block bno.
+ */
+xfs_bmbt_rec_host_t *                  /* pointer to found extent record */
+xfs_iext_bno_to_ext(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_fileoff_t   bno,            /* block number to search for */
+       xfs_extnum_t    *idxp)          /* index of target extent */
+{
+       xfs_bmbt_rec_host_t *base;      /* pointer to first extent */
+       xfs_filblks_t   blockcount = 0; /* number of blocks in extent */
+       xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */
+       xfs_ext_irec_t  *erp = NULL;    /* indirection array pointer */
+       int             high;           /* upper boundary in search */
+       xfs_extnum_t    idx = 0;        /* index of target extent */
+       int             low;            /* lower boundary in search */
+       xfs_extnum_t    nextents;       /* number of file extents */
+       xfs_fileoff_t   startoff = 0;   /* start offset of extent */
+
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       if (nextents == 0) {
+               *idxp = 0;
+               return NULL;
+       }
+       low = 0;
+       if (ifp->if_flags & XFS_IFEXTIREC) {
+               /* Find target extent list */
+               int     erp_idx = 0;
+               erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx);
+               base = erp->er_extbuf;
+               high = erp->er_extcount - 1;
+       } else {
+               base = ifp->if_u1.if_extents;
+               high = nextents - 1;
+       }
+       /* Binary search extent records */
+       while (low <= high) {
+               idx = (low + high) >> 1;
+               ep = base + idx;
+               startoff = xfs_bmbt_get_startoff(ep);
+               blockcount = xfs_bmbt_get_blockcount(ep);
+               if (bno < startoff) {
+                       high = idx - 1;
+               } else if (bno >= startoff + blockcount) {
+                       low = idx + 1;
+               } else {
+                       /* Convert back to file-based extent index */
+                       if (ifp->if_flags & XFS_IFEXTIREC) {
+                               idx += erp->er_extoff;
+                       }
+                       *idxp = idx;
+                       return ep;
+               }
+       }
+       /* Convert back to file-based extent index */
+       if (ifp->if_flags & XFS_IFEXTIREC) {
+               idx += erp->er_extoff;
+       }
+       if (bno >= startoff + blockcount) {
+               if (++idx == nextents) {
+                       ep = NULL;
+               } else {
+                       ep = xfs_iext_get_ext(ifp, idx);
+               }
+       }
+       *idxp = idx;
+       return ep;
+}
+
+/*
+ * Return a pointer to the indirection array entry containing the
+ * extent record for filesystem block bno. Store the index of the
+ * target irec in *erp_idxp.
+ */
+xfs_ext_irec_t *                       /* pointer to found extent record */
+xfs_iext_bno_to_irec(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_fileoff_t   bno,            /* block number to search for */
+       int             *erp_idxp)      /* irec index of target ext list */
+{
+       xfs_ext_irec_t  *erp = NULL;    /* indirection array pointer */
+       xfs_ext_irec_t  *erp_next;      /* next indirection array entry */
+       int             erp_idx;        /* indirection array index */
+       int             nlists;         /* number of extent irec's (lists) */
+       int             high;           /* binary search upper limit */
+       int             low;            /* binary search lower limit */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       erp_idx = 0;
+       low = 0;
+       high = nlists - 1;
+       while (low <= high) {
+               erp_idx = (low + high) >> 1;
+               erp = &ifp->if_u1.if_ext_irec[erp_idx];
+               erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL;
+               if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) {
+                       high = erp_idx - 1;
+               } else if (erp_next && bno >=
+                          xfs_bmbt_get_startoff(erp_next->er_extbuf)) {
+                       low = erp_idx + 1;
+               } else {
+                       break;
+               }
+       }
+       *erp_idxp = erp_idx;
+       return erp;
+}
+
+/*
+ * Return a pointer to the indirection array entry containing the
+ * extent record at file extent index *idxp. Store the index of the
+ * target irec in *erp_idxp and store the page index of the target
+ * extent record in *idxp.
+ */
+xfs_ext_irec_t *
+xfs_iext_idx_to_irec(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       xfs_extnum_t    *idxp,          /* extent index (file -> page) */
+       int             *erp_idxp,      /* pointer to target irec */
+       int             realloc)        /* new bytes were just added */
+{
+       xfs_ext_irec_t  *prev;          /* pointer to previous irec */
+       xfs_ext_irec_t  *erp = NULL;    /* pointer to current irec */
+       int             erp_idx;        /* indirection array index */
+       int             nlists;         /* number of irec's (ex lists) */
+       int             high;           /* binary search upper limit */
+       int             low;            /* binary search lower limit */
+       xfs_extnum_t    page_idx = *idxp; /* extent index in target list */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       ASSERT(page_idx >= 0);
+       ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t));
+       ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc);
+
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       erp_idx = 0;
+       low = 0;
+       high = nlists - 1;
+
+       /* Binary search extent irec's */
+       while (low <= high) {
+               erp_idx = (low + high) >> 1;
+               erp = &ifp->if_u1.if_ext_irec[erp_idx];
+               prev = erp_idx > 0 ? erp - 1 : NULL;
+               if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff &&
+                    realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) {
+                       high = erp_idx - 1;
+               } else if (page_idx > erp->er_extoff + erp->er_extcount ||
+                          (page_idx == erp->er_extoff + erp->er_extcount &&
+                           !realloc)) {
+                       low = erp_idx + 1;
+               } else if (page_idx == erp->er_extoff + erp->er_extcount &&
+                          erp->er_extcount == XFS_LINEAR_EXTS) {
+                       ASSERT(realloc);
+                       page_idx = 0;
+                       erp_idx++;
+                       erp = erp_idx < nlists ? erp + 1 : NULL;
+                       break;
+               } else {
+                       page_idx -= erp->er_extoff;
+                       break;
+               }
+       }
+       *idxp = page_idx;
+       *erp_idxp = erp_idx;
+       return(erp);
+}
+
+/*
+ * Allocate and initialize an indirection array once the space needed
+ * for incore extents increases above XFS_IEXT_BUFSZ.
+ */
+void
+xfs_iext_irec_init(
+       xfs_ifork_t     *ifp)           /* inode fork pointer */
+{
+       xfs_ext_irec_t  *erp;           /* indirection array pointer */
+       xfs_extnum_t    nextents;       /* number of extents in file */
+
+       ASSERT(!(ifp->if_flags & XFS_IFEXTIREC));
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+       ASSERT(nextents <= XFS_LINEAR_EXTS);
+
+       erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS);
+
+       if (nextents == 0) {
+               ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
+       } else if (!ifp->if_real_bytes) {
+               xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ);
+       } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) {
+               xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ);
+       }
+       erp->er_extbuf = ifp->if_u1.if_extents;
+       erp->er_extcount = nextents;
+       erp->er_extoff = 0;
+
+       ifp->if_flags |= XFS_IFEXTIREC;
+       ifp->if_real_bytes = XFS_IEXT_BUFSZ;
+       ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t);
+       ifp->if_u1.if_ext_irec = erp;
+
+       return;
+}
+
+/*
+ * Allocate and initialize a new entry in the indirection array.
+ */
+xfs_ext_irec_t *
+xfs_iext_irec_new(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       int             erp_idx)        /* index for new irec */
+{
+       xfs_ext_irec_t  *erp;           /* indirection array pointer */
+       int             i;              /* loop counter */
+       int             nlists;         /* number of irec's (ex lists) */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+
+       /* Resize indirection array */
+       xfs_iext_realloc_indirect(ifp, ++nlists *
+                                 sizeof(xfs_ext_irec_t));
+       /*
+        * Move records down in the array so the
+        * new page can use erp_idx.
+        */
+       erp = ifp->if_u1.if_ext_irec;
+       for (i = nlists - 1; i > erp_idx; i--) {
+               memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t));
+       }
+       ASSERT(i == erp_idx);
+
+       /* Initialize new extent record */
+       erp = ifp->if_u1.if_ext_irec;
+       erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS);
+       ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
+       memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ);
+       erp[erp_idx].er_extcount = 0;
+       erp[erp_idx].er_extoff = erp_idx > 0 ?
+               erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0;
+       return (&erp[erp_idx]);
+}
+
+/*
+ * Remove a record from the indirection array.
+ */
+void
+xfs_iext_irec_remove(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       int             erp_idx)        /* irec index to remove */
+{
+       xfs_ext_irec_t  *erp;           /* indirection array pointer */
+       int             i;              /* loop counter */
+       int             nlists;         /* number of irec's (ex lists) */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       erp = &ifp->if_u1.if_ext_irec[erp_idx];
+       if (erp->er_extbuf) {
+               xfs_iext_irec_update_extoffs(ifp, erp_idx + 1,
+                       -erp->er_extcount);
+               kmem_free(erp->er_extbuf);
+       }
+       /* Compact extent records */
+       erp = ifp->if_u1.if_ext_irec;
+       for (i = erp_idx; i < nlists - 1; i++) {
+               memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t));
+       }
+       /*
+        * Manually free the last extent record from the indirection
+        * array.  A call to xfs_iext_realloc_indirect() with a size
+        * of zero would result in a call to xfs_iext_destroy() which
+        * would in turn call this function again, creating a nasty
+        * infinite loop.
+        */
+       if (--nlists) {
+               xfs_iext_realloc_indirect(ifp,
+                       nlists * sizeof(xfs_ext_irec_t));
+       } else {
+               kmem_free(ifp->if_u1.if_ext_irec);
+       }
+       ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ;
+}
+
+/*
+ * This is called to clean up large amounts of unused memory allocated
+ * by the indirection array.  Before compacting anything though, verify
+ * that the indirection array is still needed and switch back to the
+ * linear extent list (or even the inline buffer) if possible.  The
+ * compaction policy is as follows:
+ *
+ *    Full Compaction: Extents fit into a single page (or inline buffer)
+ * Partial Compaction: Extents occupy less than 50% of allocated space
+ *      No Compaction: Extents occupy at least 50% of allocated space
+ */
+void
+xfs_iext_irec_compact(
+       xfs_ifork_t     *ifp)           /* inode fork pointer */
+{
+       xfs_extnum_t    nextents;       /* number of extents in file */
+       int             nlists;         /* number of irec's (ex lists) */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
+
+       if (nextents == 0) {
+               xfs_iext_destroy(ifp);
+       } else if (nextents <= XFS_INLINE_EXTS) {
+               xfs_iext_indirect_to_direct(ifp);
+               xfs_iext_direct_to_inline(ifp, nextents);
+       } else if (nextents <= XFS_LINEAR_EXTS) {
+               xfs_iext_indirect_to_direct(ifp);
+       } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) {
+               xfs_iext_irec_compact_pages(ifp);
+       }
+}
+
+/*
+ * Combine extents from neighboring extent pages.
+ */
+void
+xfs_iext_irec_compact_pages(
+       xfs_ifork_t     *ifp)           /* inode fork pointer */
+{
+       xfs_ext_irec_t  *erp, *erp_next;/* pointers to irec entries */
+       int             erp_idx = 0;    /* indirection array index */
+       int             nlists;         /* number of irec's (ex lists) */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       while (erp_idx < nlists - 1) {
+               erp = &ifp->if_u1.if_ext_irec[erp_idx];
+               erp_next = erp + 1;
+               if (erp_next->er_extcount <=
+                   (XFS_LINEAR_EXTS - erp->er_extcount)) {
+                       memcpy(&erp->er_extbuf[erp->er_extcount],
+                               erp_next->er_extbuf, erp_next->er_extcount *
+                               sizeof(xfs_bmbt_rec_t));
+                       erp->er_extcount += erp_next->er_extcount;
+                       /*
+                        * Free page before removing extent record
+                        * so er_extoffs don't get modified in
+                        * xfs_iext_irec_remove.
+                        */
+                       kmem_free(erp_next->er_extbuf);
+                       erp_next->er_extbuf = NULL;
+                       xfs_iext_irec_remove(ifp, erp_idx + 1);
+                       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+               } else {
+                       erp_idx++;
+               }
+       }
+}
+
+/*
+ * This is called to update the er_extoff field in the indirection
+ * array when extents have been added or removed from one of the
+ * extent lists. erp_idx contains the irec index to begin updating
+ * at and ext_diff contains the number of extents that were added
+ * or removed.
+ */
+void
+xfs_iext_irec_update_extoffs(
+       xfs_ifork_t     *ifp,           /* inode fork pointer */
+       int             erp_idx,        /* irec index to update */
+       int             ext_diff)       /* number of new extents */
+{
+       int             i;              /* loop counter */
+       int             nlists;         /* number of irec's (ex lists */
+
+       ASSERT(ifp->if_flags & XFS_IFEXTIREC);
+       nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ;
+       for (i = erp_idx; i < nlists; i++) {
+               ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
+       }
+}
diff --git a/fs/xfs/xfs_inode_fork.h b/fs/xfs/xfs_inode_fork.h
new file mode 100644 (file)
index 0000000..28661a0
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, 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
+ */
+#ifndef        __XFS_INODE_FORK_H__
+#define        __XFS_INODE_FORK_H__
+
+struct xfs_inode_log_item;
+
+/*
+ * The following xfs_ext_irec_t struct introduces a second (top) level
+ * to the in-core extent allocation scheme. These structs are allocated
+ * in a contiguous block, creating an indirection array where each entry
+ * (irec) contains a pointer to a buffer of in-core extent records which
+ * it manages. Each extent buffer is 4k in size, since 4k is the system
+ * page size on Linux i386 and systems with larger page sizes don't seem
+ * to gain much, if anything, by using their native page size as the
+ * extent buffer size. Also, using 4k extent buffers everywhere provides
+ * a consistent interface for CXFS across different platforms.
+ *
+ * There is currently no limit on the number of irec's (extent lists)
+ * allowed, so heavily fragmented files may require an indirection array
+ * which spans multiple system pages of memory. The number of extents
+ * which would require this amount of contiguous memory is very large
+ * and should not cause problems in the foreseeable future. However,
+ * if the memory needed for the contiguous array ever becomes a problem,
+ * it is possible that a third level of indirection may be required.
+ */
+typedef struct xfs_ext_irec {
+       xfs_bmbt_rec_host_t *er_extbuf; /* block of extent records */
+       xfs_extnum_t    er_extoff;      /* extent offset in file */
+       xfs_extnum_t    er_extcount;    /* number of extents in page/block */
+} xfs_ext_irec_t;
+
+/*
+ * File incore extent information, present for each of data & attr forks.
+ */
+#define        XFS_IEXT_BUFSZ          4096
+#define        XFS_LINEAR_EXTS         (XFS_IEXT_BUFSZ / (uint)sizeof(xfs_bmbt_rec_t))
+#define        XFS_INLINE_EXTS         2
+#define        XFS_INLINE_DATA         32
+typedef struct xfs_ifork {
+       int                     if_bytes;       /* bytes in if_u1 */
+       int                     if_real_bytes;  /* bytes allocated in if_u1 */
+       struct xfs_btree_block  *if_broot;      /* file's incore btree root */
+       short                   if_broot_bytes; /* bytes allocated for root */
+       unsigned char           if_flags;       /* per-fork flags */
+       union {
+               xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */
+               xfs_ext_irec_t  *if_ext_irec;   /* irec map file exts */
+               char            *if_data;       /* inline file data */
+       } if_u1;
+       union {
+               xfs_bmbt_rec_host_t if_inline_ext[XFS_INLINE_EXTS];
+                                               /* very small file extents */
+               char            if_inline_data[XFS_INLINE_DATA];
+                                               /* very small file data */
+               xfs_dev_t       if_rdev;        /* dev number if special */
+               uuid_t          if_uuid;        /* mount point value */
+       } if_u2;
+} xfs_ifork_t;
+
+/*
+ * Per-fork incore inode flags.
+ */
+#define        XFS_IFINLINE    0x01    /* Inline data is read in */
+#define        XFS_IFEXTENTS   0x02    /* All extent pointers are read in */
+#define        XFS_IFBROOT     0x04    /* i_broot points to the bmap b-tree root */
+#define        XFS_IFEXTIREC   0x08    /* Indirection array of extent blocks */
+
+/*
+ * Fork handling.
+ */
+
+#define XFS_IFORK_Q(ip)                        ((ip)->i_d.di_forkoff != 0)
+#define XFS_IFORK_BOFF(ip)             ((int)((ip)->i_d.di_forkoff << 3))
+
+#define XFS_IFORK_PTR(ip,w)            \
+       ((w) == XFS_DATA_FORK ? \
+               &(ip)->i_df : \
+               (ip)->i_afp)
+#define XFS_IFORK_DSIZE(ip) \
+       (XFS_IFORK_Q(ip) ? \
+               XFS_IFORK_BOFF(ip) : \
+               XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version))
+#define XFS_IFORK_ASIZE(ip) \
+       (XFS_IFORK_Q(ip) ? \
+               XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version) - \
+                       XFS_IFORK_BOFF(ip) : \
+               0)
+#define XFS_IFORK_SIZE(ip,w) \
+       ((w) == XFS_DATA_FORK ? \
+               XFS_IFORK_DSIZE(ip) : \
+               XFS_IFORK_ASIZE(ip))
+#define XFS_IFORK_FORMAT(ip,w) \
+       ((w) == XFS_DATA_FORK ? \
+               (ip)->i_d.di_format : \
+               (ip)->i_d.di_aformat)
+#define XFS_IFORK_FMT_SET(ip,w,n) \
+       ((w) == XFS_DATA_FORK ? \
+               ((ip)->i_d.di_format = (n)) : \
+               ((ip)->i_d.di_aformat = (n)))
+#define XFS_IFORK_NEXTENTS(ip,w) \
+       ((w) == XFS_DATA_FORK ? \
+               (ip)->i_d.di_nextents : \
+               (ip)->i_d.di_anextents)
+#define XFS_IFORK_NEXT_SET(ip,w,n) \
+       ((w) == XFS_DATA_FORK ? \
+               ((ip)->i_d.di_nextents = (n)) : \
+               ((ip)->i_d.di_anextents = (n)))
+#define XFS_IFORK_MAXEXT(ip, w) \
+       (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t))
+
+int            xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *);
+void           xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *,
+                               struct xfs_inode_log_item *, int,
+                               struct xfs_buf *);
+void           xfs_idestroy_fork(struct xfs_inode *, int);
+void           xfs_idata_realloc(struct xfs_inode *, int, int);
+void           xfs_iroot_realloc(struct xfs_inode *, int, int);
+int            xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int);
+int            xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *,
+                                 int);
+
+struct xfs_bmbt_rec_host *
+               xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t);
+void           xfs_iext_insert(struct xfs_inode *, xfs_extnum_t, xfs_extnum_t,
+                               struct xfs_bmbt_irec *, int);
+void           xfs_iext_add(struct xfs_ifork *, xfs_extnum_t, int);
+void           xfs_iext_add_indirect_multi(struct xfs_ifork *, int,
+                                           xfs_extnum_t, int);
+void           xfs_iext_remove(struct xfs_inode *, xfs_extnum_t, int, int);
+void           xfs_iext_remove_inline(struct xfs_ifork *, xfs_extnum_t, int);
+void           xfs_iext_remove_direct(struct xfs_ifork *, xfs_extnum_t, int);
+void           xfs_iext_remove_indirect(struct xfs_ifork *, xfs_extnum_t, int);
+void           xfs_iext_realloc_direct(struct xfs_ifork *, int);
+void           xfs_iext_direct_to_inline(struct xfs_ifork *, xfs_extnum_t);
+void           xfs_iext_inline_to_direct(struct xfs_ifork *, int);
+void           xfs_iext_destroy(struct xfs_ifork *);
+struct xfs_bmbt_rec_host *
+               xfs_iext_bno_to_ext(struct xfs_ifork *, xfs_fileoff_t, int *);
+struct xfs_ext_irec *
+               xfs_iext_bno_to_irec(struct xfs_ifork *, xfs_fileoff_t, int *);
+struct xfs_ext_irec *
+               xfs_iext_idx_to_irec(struct xfs_ifork *, xfs_extnum_t *, int *,
+                                    int);
+void           xfs_iext_irec_init(struct xfs_ifork *);
+struct xfs_ext_irec *
+               xfs_iext_irec_new(struct xfs_ifork *, int);
+void           xfs_iext_irec_remove(struct xfs_ifork *, int);
+void           xfs_iext_irec_compact(struct xfs_ifork *);
+void           xfs_iext_irec_compact_pages(struct xfs_ifork *);
+void           xfs_iext_irec_compact_full(struct xfs_ifork *);
+void           xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int);
+
+extern struct kmem_zone        *xfs_ifork_zone;
+
+#endif /* __XFS_INODE_FORK_H__ */
index f76ff52e43c0a4f5536163a61230f1ac89f77358..378081109844b09b2bbfd07dcb4214027fefe2c2 100644 (file)
@@ -47,32 +47,44 @@ static inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip)
  * inode core, and possibly one for the inode data/extents/b-tree root
  * and one for the inode attribute data/extents/b-tree root.
  */
-STATIC uint
+STATIC void
 xfs_inode_item_size(
-       struct xfs_log_item     *lip)
+       struct xfs_log_item     *lip,
+       int                     *nvecs,
+       int                     *nbytes)
 {
        struct xfs_inode_log_item *iip = INODE_ITEM(lip);
        struct xfs_inode        *ip = iip->ili_inode;
-       uint                    nvecs = 2;
+
+       *nvecs += 2;
+       *nbytes += sizeof(struct xfs_inode_log_format) +
+                  xfs_icdinode_size(ip->i_d.di_version);
 
        switch (ip->i_d.di_format) {
        case XFS_DINODE_FMT_EXTENTS:
                if ((iip->ili_fields & XFS_ILOG_DEXT) &&
                    ip->i_d.di_nextents > 0 &&
-                   ip->i_df.if_bytes > 0)
-                       nvecs++;
+                   ip->i_df.if_bytes > 0) {
+                       /* worst case, doesn't subtract delalloc extents */
+                       *nbytes += XFS_IFORK_DSIZE(ip);
+                       *nvecs += 1;
+               }
                break;
 
        case XFS_DINODE_FMT_BTREE:
                if ((iip->ili_fields & XFS_ILOG_DBROOT) &&
-                   ip->i_df.if_broot_bytes > 0)
-                       nvecs++;
+                   ip->i_df.if_broot_bytes > 0) {
+                       *nbytes += ip->i_df.if_broot_bytes;
+                       *nvecs += 1;
+               }
                break;
 
        case XFS_DINODE_FMT_LOCAL:
                if ((iip->ili_fields & XFS_ILOG_DDATA) &&
-                   ip->i_df.if_bytes > 0)
-                       nvecs++;
+                   ip->i_df.if_bytes > 0) {
+                       *nbytes += roundup(ip->i_df.if_bytes, 4);
+                       *nvecs += 1;
+               }
                break;
 
        case XFS_DINODE_FMT_DEV:
@@ -85,7 +97,7 @@ xfs_inode_item_size(
        }
 
        if (!XFS_IFORK_Q(ip))
-               return nvecs;
+               return;
 
 
        /*
@@ -95,28 +107,33 @@ xfs_inode_item_size(
        case XFS_DINODE_FMT_EXTENTS:
                if ((iip->ili_fields & XFS_ILOG_AEXT) &&
                    ip->i_d.di_anextents > 0 &&
-                   ip->i_afp->if_bytes > 0)
-                       nvecs++;
+                   ip->i_afp->if_bytes > 0) {
+                       /* worst case, doesn't subtract unused space */
+                       *nbytes += XFS_IFORK_ASIZE(ip);
+                       *nvecs += 1;
+               }
                break;
 
        case XFS_DINODE_FMT_BTREE:
                if ((iip->ili_fields & XFS_ILOG_ABROOT) &&
-                   ip->i_afp->if_broot_bytes > 0)
-                       nvecs++;
+                   ip->i_afp->if_broot_bytes > 0) {
+                       *nbytes += ip->i_afp->if_broot_bytes;
+                       *nvecs += 1;
+               }
                break;
 
        case XFS_DINODE_FMT_LOCAL:
                if ((iip->ili_fields & XFS_ILOG_ADATA) &&
-                   ip->i_afp->if_bytes > 0)
-                       nvecs++;
+                   ip->i_afp->if_bytes > 0) {
+                       *nbytes += roundup(ip->i_afp->if_bytes, 4);
+                       *nvecs += 1;
+               }
                break;
 
        default:
                ASSERT(0);
                break;
        }
-
-       return nvecs;
 }
 
 /*
index 779812fb3d80b27c94d97f288fea9195db8be4fb..dce4d656768c32888521dc0c9007c6c2961b7c4e 100644 (file)
 #ifndef        __XFS_INODE_ITEM_H__
 #define        __XFS_INODE_ITEM_H__
 
-/*
- * This is the structure used to lay out an inode log item in the
- * log.  The size of the inline data/extents/b-tree root to be logged
- * (if any) is indicated in the ilf_dsize field.  Changes to this structure
- * must be added on to the end.
- */
-typedef struct xfs_inode_log_format {
-       __uint16_t              ilf_type;       /* inode log item type */
-       __uint16_t              ilf_size;       /* size of this item */
-       __uint32_t              ilf_fields;     /* flags for fields logged */
-       __uint16_t              ilf_asize;      /* size of attr d/ext/root */
-       __uint16_t              ilf_dsize;      /* size of data/ext/root */
-       __uint64_t              ilf_ino;        /* inode number */
-       union {
-               __uint32_t      ilfu_rdev;      /* rdev value for dev inode*/
-               uuid_t          ilfu_uuid;      /* mount point value */
-       } ilf_u;
-       __int64_t               ilf_blkno;      /* blkno of inode buffer */
-       __int32_t               ilf_len;        /* len of inode buffer */
-       __int32_t               ilf_boffset;    /* off of inode in buffer */
-} xfs_inode_log_format_t;
-
-typedef struct xfs_inode_log_format_32 {
-       __uint16_t              ilf_type;       /* inode log item type */
-       __uint16_t              ilf_size;       /* size of this item */
-       __uint32_t              ilf_fields;     /* flags for fields logged */
-       __uint16_t              ilf_asize;      /* size of attr d/ext/root */
-       __uint16_t              ilf_dsize;      /* size of data/ext/root */
-       __uint64_t              ilf_ino;        /* inode number */
-       union {
-               __uint32_t      ilfu_rdev;      /* rdev value for dev inode*/
-               uuid_t          ilfu_uuid;      /* mount point value */
-       } ilf_u;
-       __int64_t               ilf_blkno;      /* blkno of inode buffer */
-       __int32_t               ilf_len;        /* len of inode buffer */
-       __int32_t               ilf_boffset;    /* off of inode in buffer */
-} __attribute__((packed)) xfs_inode_log_format_32_t;
-
-typedef struct xfs_inode_log_format_64 {
-       __uint16_t              ilf_type;       /* inode log item type */
-       __uint16_t              ilf_size;       /* size of this item */
-       __uint32_t              ilf_fields;     /* flags for fields logged */
-       __uint16_t              ilf_asize;      /* size of attr d/ext/root */
-       __uint16_t              ilf_dsize;      /* size of data/ext/root */
-       __uint32_t              ilf_pad;        /* pad for 64 bit boundary */
-       __uint64_t              ilf_ino;        /* inode number */
-       union {
-               __uint32_t      ilfu_rdev;      /* rdev value for dev inode*/
-               uuid_t          ilfu_uuid;      /* mount point value */
-       } ilf_u;
-       __int64_t               ilf_blkno;      /* blkno of inode buffer */
-       __int32_t               ilf_len;        /* len of inode buffer */
-       __int32_t               ilf_boffset;    /* off of inode in buffer */
-} xfs_inode_log_format_64_t;
-
-/*
- * Flags for xfs_trans_log_inode flags field.
- */
-#define        XFS_ILOG_CORE   0x001   /* log standard inode fields */
-#define        XFS_ILOG_DDATA  0x002   /* log i_df.if_data */
-#define        XFS_ILOG_DEXT   0x004   /* log i_df.if_extents */
-#define        XFS_ILOG_DBROOT 0x008   /* log i_df.i_broot */
-#define        XFS_ILOG_DEV    0x010   /* log the dev field */
-#define        XFS_ILOG_UUID   0x020   /* log the uuid field */
-#define        XFS_ILOG_ADATA  0x040   /* log i_af.if_data */
-#define        XFS_ILOG_AEXT   0x080   /* log i_af.if_extents */
-#define        XFS_ILOG_ABROOT 0x100   /* log i_af.i_broot */
-
-
-/*
- * The timestamps are dirty, but not necessarily anything else in the inode
- * core.  Unlike the other fields above this one must never make it to disk
- * in the ilf_fields of the inode_log_format, but is purely store in-memory in
- * ili_fields in the inode_log_item.
- */
-#define XFS_ILOG_TIMESTAMP     0x4000
-
-#define        XFS_ILOG_NONCORE        (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
-                                XFS_ILOG_DBROOT | XFS_ILOG_DEV | \
-                                XFS_ILOG_UUID | XFS_ILOG_ADATA | \
-                                XFS_ILOG_AEXT | XFS_ILOG_ABROOT)
-
-#define        XFS_ILOG_DFORK          (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
-                                XFS_ILOG_DBROOT)
-
-#define        XFS_ILOG_AFORK          (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
-                                XFS_ILOG_ABROOT)
-
-#define        XFS_ILOG_ALL            (XFS_ILOG_CORE | XFS_ILOG_DDATA | \
-                                XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \
-                                XFS_ILOG_DEV | XFS_ILOG_UUID | \
-                                XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
-                                XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP)
-
-static inline int xfs_ilog_fbroot(int w)
-{
-       return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
-}
-
-static inline int xfs_ilog_fext(int w)
-{
-       return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT);
-}
-
-static inline int xfs_ilog_fdata(int w)
-{
-       return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA);
-}
-
-#ifdef __KERNEL__
+/* kernel only definitions */
 
 struct xfs_buf;
 struct xfs_bmbt_rec;
 struct xfs_inode;
 struct xfs_mount;
 
-
 typedef struct xfs_inode_log_item {
        xfs_log_item_t          ili_item;          /* common portion */
        struct xfs_inode        *ili_inode;        /* inode ptr */
@@ -151,7 +41,6 @@ typedef struct xfs_inode_log_item {
        xfs_inode_log_format_t  ili_format;        /* logged structure */
 } xfs_inode_log_item_t;
 
-
 static inline int xfs_inode_clean(xfs_inode_t *ip)
 {
        return !ip->i_itemp || !(ip->i_itemp->ili_fields & XFS_ILOG_ALL);
@@ -165,6 +54,6 @@ extern void xfs_iflush_abort(struct xfs_inode *, bool);
 extern int xfs_inode_item_format_convert(xfs_log_iovec_t *,
                                         xfs_inode_log_format_t *);
 
-#endif /* __KERNEL__ */
+extern struct kmem_zone        *xfs_ili_zone;
 
 #endif /* __XFS_INODE_ITEM_H__ */
index 6e2bca5d44d67acb52a58115a6b9482fc04a5bc1..668e8f4ccf5e7201e8e6a360cd26668484f6d515 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_error.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_buf_item.h"
-#include "xfs_utils.h"
-#include "xfs_dfrag.h"
 #include "xfs_fsops.h"
-#include "xfs_vnodeops.h"
 #include "xfs_discard.h"
 #include "xfs_quota.h"
 #include "xfs_inode_item.h"
 #include "xfs_export.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
+#include "xfs_symlink.h"
 
 #include <linux/capability.h>
 #include <linux/dcache.h>
@@ -71,7 +71,7 @@ xfs_find_handle(
        int                     hsize;
        xfs_handle_t            handle;
        struct inode            *inode;
-       struct fd               f = {0};
+       struct fd               f = {NULL};
        struct path             path;
        int                     error;
        struct xfs_inode        *ip;
@@ -350,6 +350,40 @@ xfs_readlink_by_handle(
        return error;
 }
 
+int
+xfs_set_dmattrs(
+       xfs_inode_t     *ip,
+       u_int           evmask,
+       u_int16_t       state)
+{
+       xfs_mount_t     *mp = ip->i_mount;
+       xfs_trans_t     *tp;
+       int             error;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return XFS_ERROR(EPERM);
+
+       if (XFS_FORCED_SHUTDOWN(mp))
+               return XFS_ERROR(EIO);
+
+       tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
+       if (error) {
+               xfs_trans_cancel(tp, 0);
+               return error;
+       }
+       xfs_ilock(ip, XFS_ILOCK_EXCL);
+       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+       ip->i_d.di_dmevmask = evmask;
+       ip->i_d.di_dmstate  = state;
+
+       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+       error = xfs_trans_commit(tp, 0);
+
+       return error;
+}
+
 STATIC int
 xfs_fssetdm_by_handle(
        struct file             *parfilp,
@@ -422,12 +456,9 @@ xfs_attrlist_by_handle(
        if (IS_ERR(dentry))
                return PTR_ERR(dentry);
 
-       kbuf = kmem_zalloc(al_hreq.buflen, KM_SLEEP | KM_MAYFAIL);
-       if (!kbuf) {
-               kbuf = kmem_zalloc_large(al_hreq.buflen);
-               if (!kbuf)
-                       goto out_dput;
-       }
+       kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP);
+       if (!kbuf)
+               goto out_dput;
 
        cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
        error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen,
@@ -438,12 +469,9 @@ xfs_attrlist_by_handle(
        if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))
                error = -EFAULT;
 
- out_kfree:
-       if (is_vmalloc_addr(kbuf))
-               kmem_free_large(kbuf);
-       else
-               kmem_free(kbuf);
- out_dput:
+out_kfree:
+       kmem_free(kbuf);
+out_dput:
        dput(dentry);
        return error;
 }
@@ -461,12 +489,9 @@ xfs_attrmulti_attr_get(
 
        if (*len > XATTR_SIZE_MAX)
                return EINVAL;
-       kbuf = kmem_zalloc(*len, KM_SLEEP | KM_MAYFAIL);
-       if (!kbuf) {
-               kbuf = kmem_zalloc_large(*len);
-               if (!kbuf)
-                       return ENOMEM;
-       }
+       kbuf = kmem_zalloc_large(*len, KM_SLEEP);
+       if (!kbuf)
+               return ENOMEM;
 
        error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
        if (error)
@@ -475,11 +500,8 @@ xfs_attrmulti_attr_get(
        if (copy_to_user(ubuf, kbuf, *len))
                error = EFAULT;
 
- out_kfree:
-       if (is_vmalloc_addr(kbuf))
-               kmem_free_large(kbuf);
-       else
-               kmem_free(kbuf);
+out_kfree:
+       kmem_free(kbuf);
        return error;
 }
 
@@ -967,7 +989,7 @@ xfs_ioctl_setattr(
         * first do an error checking pass.
         */
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
-       code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
+       code = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
        if (code)
                goto error_return;
 
@@ -981,15 +1003,22 @@ xfs_ioctl_setattr(
         * to the file owner ID, except in cases where the
         * CAP_FSETID capability is applicable.
         */
-       if (current_fsuid() != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
+       if (!inode_owner_or_capable(VFS_I(ip))) {
                code = XFS_ERROR(EPERM);
                goto error_return;
        }
 
        /*
         * Do a quota reservation only if projid is actually going to change.
+        * Only allow changing of projid from init_user_ns since it is a
+        * non user namespace aware identifier.
         */
        if (mask & FSX_PROJID) {
+               if (current_user_ns() != &init_user_ns) {
+                       code = XFS_ERROR(EINVAL);
+                       goto error_return;
+               }
+
                if (XFS_IS_QUOTA_RUNNING(mp) &&
                    XFS_IS_PQUOTA_ON(mp) &&
                    xfs_get_projid(ip) != fa->fsx_projid) {
@@ -1103,7 +1132,7 @@ xfs_ioctl_setattr(
                 * cleared upon successful return from chown()
                 */
                if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
-                   !capable(CAP_FSETID))
+                   !inode_capable(VFS_I(ip), CAP_FSETID))
                        ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
 
                /*
@@ -1328,6 +1357,75 @@ xfs_ioc_getbmapx(
        return 0;
 }
 
+int
+xfs_ioc_swapext(
+       xfs_swapext_t   *sxp)
+{
+       xfs_inode_t     *ip, *tip;
+       struct fd       f, tmp;
+       int             error = 0;
+
+       /* Pull information for the target fd */
+       f = fdget((int)sxp->sx_fdtarget);
+       if (!f.file) {
+               error = XFS_ERROR(EINVAL);
+               goto out;
+       }
+
+       if (!(f.file->f_mode & FMODE_WRITE) ||
+           !(f.file->f_mode & FMODE_READ) ||
+           (f.file->f_flags & O_APPEND)) {
+               error = XFS_ERROR(EBADF);
+               goto out_put_file;
+       }
+
+       tmp = fdget((int)sxp->sx_fdtmp);
+       if (!tmp.file) {
+               error = XFS_ERROR(EINVAL);
+               goto out_put_file;
+       }
+
+       if (!(tmp.file->f_mode & FMODE_WRITE) ||
+           !(tmp.file->f_mode & FMODE_READ) ||
+           (tmp.file->f_flags & O_APPEND)) {
+               error = XFS_ERROR(EBADF);
+               goto out_put_tmp_file;
+       }
+
+       if (IS_SWAPFILE(file_inode(f.file)) ||
+           IS_SWAPFILE(file_inode(tmp.file))) {
+               error = XFS_ERROR(EINVAL);
+               goto out_put_tmp_file;
+       }
+
+       ip = XFS_I(file_inode(f.file));
+       tip = XFS_I(file_inode(tmp.file));
+
+       if (ip->i_mount != tip->i_mount) {
+               error = XFS_ERROR(EINVAL);
+               goto out_put_tmp_file;
+       }
+
+       if (ip->i_ino == tip->i_ino) {
+               error = XFS_ERROR(EINVAL);
+               goto out_put_tmp_file;
+       }
+
+       if (XFS_FORCED_SHUTDOWN(ip->i_mount)) {
+               error = XFS_ERROR(EIO);
+               goto out_put_tmp_file;
+       }
+
+       error = xfs_swap_extents(ip, tip, sxp);
+
+ out_put_tmp_file:
+       fdput(tmp);
+ out_put_file:
+       fdput(f);
+ out:
+       return error;
+}
+
 /*
  * Note: some of the ioctl's return positive numbers as a
  * byte count indicating success, such as readlink_by_handle.
@@ -1472,7 +1570,7 @@ xfs_file_ioctl(
                error = mnt_want_write_file(filp);
                if (error)
                        return error;
-               error = xfs_swapext(&sxp);
+               error = xfs_ioc_swapext(&sxp);
                mnt_drop_write_file(filp);
                return -error;
        }
@@ -1610,23 +1708,23 @@ xfs_file_ioctl(
                return -error;
 
        case XFS_IOC_FREE_EOFBLOCKS: {
-               struct xfs_eofblocks eofb;
+               struct xfs_fs_eofblocks eofb;
+               struct xfs_eofblocks keofb;
 
-               if (copy_from_user(&eofb, arg, sizeof(eofb)))
-                       return -XFS_ERROR(EFAULT);
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
 
-               if (eofb.eof_version != XFS_EOFBLOCKS_VERSION)
-                       return -XFS_ERROR(EINVAL);
+               if (mp->m_flags & XFS_MOUNT_RDONLY)
+                       return -XFS_ERROR(EROFS);
 
-               if (eofb.eof_flags & ~XFS_EOF_FLAGS_VALID)
-                       return -XFS_ERROR(EINVAL);
+               if (copy_from_user(&eofb, arg, sizeof(eofb)))
+                       return -XFS_ERROR(EFAULT);
 
-               if (memchr_inv(&eofb.pad32, 0, sizeof(eofb.pad32)) ||
-                   memchr_inv(eofb.pad64, 0, sizeof(eofb.pad64)))
-                       return -XFS_ERROR(EINVAL);
+               error = xfs_fs_eofblocks_from_user(&eofb, &keofb);
+               if (error)
+                       return -error;
 
-               error = xfs_icache_free_eofblocks(mp, &eofb);
-               return -error;
+               return -xfs_icache_free_eofblocks(mp, &keofb);
        }
 
        default:
index d56173b34a2a55662575f79a4ba5426662b647c9..77c02c7900b6eb8d78276abdd7d0b6ec03c12e29 100644 (file)
@@ -27,6 +27,10 @@ xfs_ioc_space(
        unsigned int            cmd,
        xfs_flock64_t           *bf);
 
+int
+xfs_ioc_swapext(
+       xfs_swapext_t   *sxp);
+
 extern int
 xfs_find_handle(
        unsigned int            cmd,
@@ -82,4 +86,10 @@ xfs_file_compat_ioctl(
        unsigned int            cmd,
        unsigned long           arg);
 
+extern int
+xfs_set_dmattrs(
+       struct xfs_inode        *ip,
+       u_int                   evmask,
+       u_int16_t               state);
+
 #endif
index c0c66259cc913d3a19df61efeab3bb86cb028aaf..f671f7e472ac008511ca4df2068c9d4fb91d169c 100644 (file)
@@ -33,8 +33,6 @@
 #include "xfs_inode.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
-#include "xfs_dfrag.h"
-#include "xfs_vnodeops.h"
 #include "xfs_fsops.h"
 #include "xfs_alloc.h"
 #include "xfs_rtalloc.h"
@@ -373,12 +371,9 @@ xfs_compat_attrlist_by_handle(
                return PTR_ERR(dentry);
 
        error = -ENOMEM;
-       kbuf = kmem_zalloc(al_hreq.buflen, KM_SLEEP | KM_MAYFAIL);
-       if (!kbuf) {
-               kbuf = kmem_zalloc_large(al_hreq.buflen);
-               if (!kbuf)
-                       goto out_dput;
-       }
+       kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP);
+       if (!kbuf)
+               goto out_dput;
 
        cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
        error = -xfs_attr_list(XFS_I(dentry->d_inode), kbuf, al_hreq.buflen,
@@ -389,12 +384,9 @@ xfs_compat_attrlist_by_handle(
        if (copy_to_user(compat_ptr(al_hreq.buffer), kbuf, al_hreq.buflen))
                error = -EFAULT;
 
- out_kfree:
-       if (is_vmalloc_addr(kbuf))
-               kmem_free_large(kbuf);
-       else
-               kmem_free(kbuf);
- out_dput:
+out_kfree:
+       kmem_free(kbuf);
+out_dput:
        dput(dentry);
        return error;
 }
@@ -644,7 +636,7 @@ xfs_file_compat_ioctl(
                error = mnt_want_write_file(filp);
                if (error)
                        return error;
-               error = xfs_swapext(&sxp);
+               error = xfs_ioc_swapext(&sxp);
                mnt_drop_write_file(filp);
                return -error;
        }
index 6a7096422295d1d821f1e0bab397041c42f53de1..8d4d49b6fbf347b3add01ed4675b489a653a6dfb 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_inode_item.h"
 #include "xfs_btree.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
-#include "xfs_utils.h"
 #include "xfs_iomap.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
@@ -187,10 +188,8 @@ xfs_iomap_write_direct(
         * Allocate and setup the transaction
         */
        tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
-       error = xfs_trans_reserve(tp, resblks,
-                       XFS_WRITE_LOG_RES(mp), resrtextents,
-                       XFS_TRANS_PERM_LOG_RES,
-                       XFS_WRITE_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
+                                 resblks, resrtextents);
        /*
         * Check for running out of space, note: need lock to return
         */
@@ -698,10 +697,8 @@ xfs_iomap_write_allocate(
                        tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
                        tp->t_flags |= XFS_TRANS_RESERVE;
                        nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK);
-                       error = xfs_trans_reserve(tp, nres,
-                                       XFS_WRITE_LOG_RES(mp),
-                                       0, XFS_TRANS_PERM_LOG_RES,
-                                       XFS_WRITE_LOG_COUNT);
+                       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
+                                                 nres, 0);
                        if (error) {
                                xfs_trans_cancel(tp, 0);
                                return XFS_ERROR(error);
@@ -864,10 +861,8 @@ xfs_iomap_write_unwritten(
                sb_start_intwrite(mp->m_super);
                tp = _xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE, KM_NOFS);
                tp->t_flags |= XFS_TRANS_RESERVE | XFS_TRANS_FREEZE_PROT;
-               error = xfs_trans_reserve(tp, resblks,
-                               XFS_WRITE_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES,
-                               XFS_WRITE_LOG_COUNT);
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
+                                         resblks, 0);
                if (error) {
                        xfs_trans_cancel(tp, 0);
                        return XFS_ERROR(error);
index 96dda62d497b7e04a68a1a6ddfc579aececf8374..2b8952d9199bbd145473a48b326120b8d43ed9b6 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_acl.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_rtalloc.h"
 #include "xfs_error.h"
 #include "xfs_itable.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
-#include "xfs_utils.h"
-#include "xfs_vnodeops.h"
 #include "xfs_inode_item.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
+#include "xfs_symlink.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2_priv.h"
 
 #include <linux/capability.h>
 #include <linux/xattr.h>
@@ -87,10 +91,12 @@ xfs_init_security(
 static void
 xfs_dentry_to_name(
        struct xfs_name *namep,
-       struct dentry   *dentry)
+       struct dentry   *dentry,
+       int             mode)
 {
        namep->name = dentry->d_name.name;
        namep->len = dentry->d_name.len;
+       namep->type = xfs_mode_to_ftype[(mode & S_IFMT) >> S_SHIFT];
 }
 
 STATIC void
@@ -106,7 +112,7 @@ xfs_cleanup_inode(
         * xfs_init_security we must back out.
         * ENOSPC can hit here, among other things.
         */
-       xfs_dentry_to_name(&teardown, dentry);
+       xfs_dentry_to_name(&teardown, dentry, 0);
 
        xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
        iput(inode);
@@ -146,7 +152,7 @@ xfs_vn_mknod(
                        mode &= ~current_umask();
        }
 
-       xfs_dentry_to_name(&name, dentry);
+       xfs_dentry_to_name(&name, dentry, mode);
        error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
        if (unlikely(error))
                goto out_free_acl;
@@ -207,7 +213,7 @@ xfs_vn_lookup(
        if (dentry->d_name.len >= MAXNAMELEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       xfs_dentry_to_name(&name, dentry);
+       xfs_dentry_to_name(&name, dentry, 0);
        error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
        if (unlikely(error)) {
                if (unlikely(error != ENOENT))
@@ -234,7 +240,7 @@ xfs_vn_ci_lookup(
        if (dentry->d_name.len >= MAXNAMELEN)
                return ERR_PTR(-ENAMETOOLONG);
 
-       xfs_dentry_to_name(&xname, dentry);
+       xfs_dentry_to_name(&xname, dentry, 0);
        error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
        if (unlikely(error)) {
                if (unlikely(error != ENOENT))
@@ -269,7 +275,7 @@ xfs_vn_link(
        struct xfs_name name;
        int             error;
 
-       xfs_dentry_to_name(&name, dentry);
+       xfs_dentry_to_name(&name, dentry, inode->i_mode);
 
        error = xfs_link(XFS_I(dir), XFS_I(inode), &name);
        if (unlikely(error))
@@ -288,7 +294,7 @@ xfs_vn_unlink(
        struct xfs_name name;
        int             error;
 
-       xfs_dentry_to_name(&name, dentry);
+       xfs_dentry_to_name(&name, dentry, 0);
 
        error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
        if (error)
@@ -318,7 +324,7 @@ xfs_vn_symlink(
 
        mode = S_IFLNK |
                (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO);
-       xfs_dentry_to_name(&name, dentry);
+       xfs_dentry_to_name(&name, dentry, mode);
 
        error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip);
        if (unlikely(error))
@@ -350,12 +356,12 @@ xfs_vn_rename(
        struct xfs_name oname;
        struct xfs_name nname;
 
-       xfs_dentry_to_name(&oname, odentry);
-       xfs_dentry_to_name(&nname, ndentry);
+       xfs_dentry_to_name(&oname, odentry, 0);
+       xfs_dentry_to_name(&nname, ndentry, odentry->d_inode->i_mode);
 
        return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
                           XFS_I(ndir), &nname, new_inode ?
-                                               XFS_I(new_inode) : NULL);
+                                               XFS_I(new_inode) : NULL);
 }
 
 /*
@@ -420,8 +426,8 @@ xfs_vn_getattr(
        stat->dev = inode->i_sb->s_dev;
        stat->mode = ip->i_d.di_mode;
        stat->nlink = ip->i_d.di_nlink;
-       stat->uid = ip->i_d.di_uid;
-       stat->gid = ip->i_d.di_gid;
+       stat->uid = inode->i_uid;
+       stat->gid = inode->i_gid;
        stat->ino = ip->i_ino;
        stat->atime = inode->i_atime;
        stat->mtime = inode->i_mtime;
@@ -485,8 +491,8 @@ xfs_setattr_nonsize(
        int                     mask = iattr->ia_valid;
        xfs_trans_t             *tp;
        int                     error;
-       uid_t                   uid = 0, iuid = 0;
-       gid_t                   gid = 0, igid = 0;
+       kuid_t                  uid = GLOBAL_ROOT_UID, iuid = GLOBAL_ROOT_UID;
+       kgid_t                  gid = GLOBAL_ROOT_GID, igid = GLOBAL_ROOT_GID;
        struct xfs_dquot        *udqp = NULL, *gdqp = NULL;
        struct xfs_dquot        *olddquot1 = NULL, *olddquot2 = NULL;
 
@@ -522,13 +528,13 @@ xfs_setattr_nonsize(
                        uid = iattr->ia_uid;
                        qflags |= XFS_QMOPT_UQUOTA;
                } else {
-                       uid = ip->i_d.di_uid;
+                       uid = inode->i_uid;
                }
                if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) {
                        gid = iattr->ia_gid;
                        qflags |= XFS_QMOPT_GQUOTA;
                }  else {
-                       gid = ip->i_d.di_gid;
+                       gid = inode->i_gid;
                }
 
                /*
@@ -538,14 +544,16 @@ xfs_setattr_nonsize(
                 */
                ASSERT(udqp == NULL);
                ASSERT(gdqp == NULL);
-               error = xfs_qm_vop_dqalloc(ip, uid, gid, xfs_get_projid(ip),
-                                        qflags, &udqp, &gdqp, NULL);
+               error = xfs_qm_vop_dqalloc(ip, xfs_kuid_to_uid(uid),
+                                          xfs_kgid_to_gid(gid),
+                                          xfs_get_projid(ip),
+                                          qflags, &udqp, &gdqp, NULL);
                if (error)
                        return error;
        }
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
-       error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
        if (error)
                goto out_dqrele;
 
@@ -561,8 +569,8 @@ xfs_setattr_nonsize(
                 * while we didn't have the inode locked, inode's dquot(s)
                 * would have changed also.
                 */
-               iuid = ip->i_d.di_uid;
-               igid = ip->i_d.di_gid;
+               iuid = inode->i_uid;
+               igid = inode->i_gid;
                gid = (mask & ATTR_GID) ? iattr->ia_gid : igid;
                uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
 
@@ -571,8 +579,8 @@ xfs_setattr_nonsize(
                 * going to change.
                 */
                if (XFS_IS_QUOTA_RUNNING(mp) &&
-                   ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) ||
-                    (XFS_IS_GQUOTA_ON(mp) && igid != gid))) {
+                   ((XFS_IS_UQUOTA_ON(mp) && !uid_eq(iuid, uid)) ||
+                    (XFS_IS_GQUOTA_ON(mp) && !gid_eq(igid, gid)))) {
                        ASSERT(tp);
                        error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp,
                                                NULL, capable(CAP_FOWNER) ?
@@ -602,17 +610,17 @@ xfs_setattr_nonsize(
                 * Change the ownerships and register quota modifications
                 * in the transaction.
                 */
-               if (iuid != uid) {
+               if (!uid_eq(iuid, uid)) {
                        if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) {
                                ASSERT(mask & ATTR_UID);
                                ASSERT(udqp);
                                olddquot1 = xfs_qm_vop_chown(tp, ip,
                                                        &ip->i_udquot, udqp);
                        }
-                       ip->i_d.di_uid = uid;
+                       ip->i_d.di_uid = xfs_kuid_to_uid(uid);
                        inode->i_uid = uid;
                }
-               if (igid != gid) {
+               if (!gid_eq(igid, gid)) {
                        if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) {
                                ASSERT(!XFS_IS_PQUOTA_ON(mp));
                                ASSERT(mask & ATTR_GID);
@@ -620,7 +628,7 @@ xfs_setattr_nonsize(
                                olddquot2 = xfs_qm_vop_chown(tp, ip,
                                                        &ip->i_gdquot, gdqp);
                        }
-                       ip->i_d.di_gid = gid;
+                       ip->i_d.di_gid = xfs_kgid_to_gid(gid);
                        inode->i_gid = gid;
                }
        }
@@ -807,9 +815,7 @@ xfs_setattr_size(
                goto out_unlock;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE);
-       error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
-                                XFS_TRANS_PERM_LOG_RES,
-                                XFS_ITRUNCATE_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
        if (error)
                goto out_trans_cancel;
 
@@ -932,7 +938,7 @@ xfs_vn_update_time(
        trace_xfs_update_time(ip);
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_FSYNC_TS);
-       error = xfs_trans_reserve(tp, 0, XFS_FSYNC_TS_LOG_RES(mp), 0, 0, 0);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_fsyncts, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return -error;
@@ -1173,8 +1179,8 @@ xfs_setup_inode(
 
        inode->i_mode   = ip->i_d.di_mode;
        set_nlink(inode, ip->i_d.di_nlink);
-       inode->i_uid    = ip->i_d.di_uid;
-       inode->i_gid    = ip->i_d.di_gid;
+       inode->i_uid    = xfs_uid_to_kuid(ip->i_d.di_uid);
+       inode->i_gid    = xfs_gid_to_kgid(ip->i_d.di_gid);
 
        switch (inode->i_mode & S_IFMT) {
        case S_IFBLK:
index ef41c92ce66e9e8159a2c3b1319774e589877ce6..d81fb41205ec97b9a00ecc0789e99763adc5af71 100644 (file)
@@ -27,4 +27,17 @@ extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size);
 
 extern void xfs_setup_inode(struct xfs_inode *);
 
+/*
+ * Internal setattr interfaces.
+ */
+#define        XFS_ATTR_DMI            0x01    /* invocation from a DMI function */
+#define        XFS_ATTR_NONBLOCK       0x02    /* return EAGAIN if op would block */
+#define XFS_ATTR_NOLOCK                0x04    /* Don't grab any conflicting locks */
+#define XFS_ATTR_NOACL         0x08    /* Don't call xfs_acl_chmod */
+#define XFS_ATTR_SYNC          0x10    /* synchronous operation required */
+
+extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
+                              int flags);
+extern int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap, int flags);
+
 #endif /* __XFS_IOPS_H__ */
index b93e14b86754a6cf6b12e4e9952e911e10a008ad..084b3e1741fd0346cac1d8279ed8085553ee7486 100644 (file)
@@ -495,7 +495,7 @@ xfs_bulkstat(
        /*
         * Done, we're either out of filesystem or space to put the data.
         */
-       kmem_free_large(irbuf);
+       kmem_free(irbuf);
        *ubcountp = ubelem;
        /*
         * Found some inodes, return them now and return the error next time.
@@ -541,8 +541,9 @@ xfs_bulkstat_single(
         * at the expense of the error case.
         */
 
-       ino = (xfs_ino_t)*lastinop;
-       error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t), 0, &res);
+       ino = *lastinop;
+       error = xfs_bulkstat_one(mp, ino, buffer, sizeof(xfs_bstat_t),
+                                NULL, &res);
        if (error) {
                /*
                 * Special case way failed, do it the "long" way
index 800f896a6cc48cdffc19f85d6a9dd4c30ef897d5..f9bb590acc0ebfd38a4aaaee3baaa5b0bf6ec505 100644 (file)
 # define XFS_BIG_INUMS 0
 #endif
 
+/*
+ * Kernel specific type declarations for XFS
+ */
+typedef signed char            __int8_t;
+typedef unsigned char          __uint8_t;
+typedef signed short int       __int16_t;
+typedef unsigned short int     __uint16_t;
+typedef signed int             __int32_t;
+typedef unsigned int           __uint32_t;
+typedef signed long long int   __int64_t;
+typedef unsigned long long int __uint64_t;
+
+typedef __uint32_t             inst_t;         /* an instruction */
+
+typedef __s64                  xfs_off_t;      /* <file offset> type */
+typedef unsigned long long     xfs_ino_t;      /* <inode> type */
+typedef __s64                  xfs_daddr_t;    /* <disk address> type */
+typedef char *                 xfs_caddr_t;    /* <core address> type */
+typedef __u32                  xfs_dev_t;
+typedef __u32                  xfs_nlink_t;
+
+/* __psint_t is the same size as a pointer */
+#if (BITS_PER_LONG == 32)
+typedef __int32_t __psint_t;
+typedef __uint32_t __psunsigned_t;
+#elif (BITS_PER_LONG == 64)
+typedef __int64_t __psint_t;
+typedef __uint64_t __psunsigned_t;
+#else
+#error BITS_PER_LONG must be 32 or 64
+#endif
+
 #include "xfs_types.h"
 
 #include "kmem.h"
 #define xfs_inherit_sync       xfs_params.inherit_sync.val
 #define xfs_inherit_nodump     xfs_params.inherit_nodump.val
 #define xfs_inherit_noatime    xfs_params.inherit_noatim.val
-#define xfs_buf_timer_centisecs        xfs_params.xfs_buf_timer.val
-#define xfs_buf_age_centisecs  xfs_params.xfs_buf_age.val
 #define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val
 #define xfs_rotorstep          xfs_params.rotorstep.val
 #define xfs_inherit_nodefrag   xfs_params.inherit_nodfrg.val
 #define MAX(a,b)       (max(a,b))
 #define howmany(x, y)  (((x)+((y)-1))/(y))
 
+/* Kernel uid/gid conversion. These are used to convert to/from the on disk
+ * uid_t/gid_t types to the kuid_t/kgid_t types that the kernel uses internally.
+ * The conversion here is type only, the value will remain the same since we
+ * are converting to the init_user_ns. The uid is later mapped to a particular
+ * user namespace value when crossing the kernel/user boundary.
+ */
+static inline __uint32_t xfs_kuid_to_uid(kuid_t uid)
+{
+       return from_kuid(&init_user_ns, uid);
+}
+
+static inline kuid_t xfs_uid_to_kuid(__uint32_t uid)
+{
+       return make_kuid(&init_user_ns, uid);
+}
+
+static inline __uint32_t xfs_kgid_to_gid(kgid_t gid)
+{
+       return from_kgid(&init_user_ns, gid);
+}
+
+static inline kgid_t xfs_gid_to_kgid(__uint32_t gid)
+{
+       return make_kgid(&init_user_ns, gid);
+}
+
 /*
  * Various platform dependent calls that don't fit anywhere else
  */
index d852a2b3e1fdfae0c4fb5bf18452ec79fd03ab01..a2dea108071ae6e81d0e683a98a4a011b74f23ee 100644 (file)
@@ -257,7 +257,8 @@ xlog_grant_head_wait(
        struct xlog             *log,
        struct xlog_grant_head  *head,
        struct xlog_ticket      *tic,
-       int                     need_bytes)
+       int                     need_bytes) __releases(&head->lock)
+                                           __acquires(&head->lock)
 {
        list_add_tail(&tic->t_queue, &head->waiters);
 
@@ -614,7 +615,8 @@ xfs_log_mount(
        xfs_daddr_t     blk_offset,
        int             num_bblks)
 {
-       int             error;
+       int             error = 0;
+       int             min_logfsbs;
 
        if (!(mp->m_flags & XFS_MOUNT_NORECOVERY))
                xfs_notice(mp, "Mounting Filesystem");
@@ -630,6 +632,50 @@ xfs_log_mount(
                goto out;
        }
 
+       /*
+        * Validate the given log space and drop a critical message via syslog
+        * if the log size is too small that would lead to some unexpected
+        * situations in transaction log space reservation stage.
+        *
+        * Note: we can't just reject the mount if the validation fails.  This
+        * would mean that people would have to downgrade their kernel just to
+        * remedy the situation as there is no way to grow the log (short of
+        * black magic surgery with xfs_db).
+        *
+        * We can, however, reject mounts for CRC format filesystems, as the
+        * mkfs binary being used to make the filesystem should never create a
+        * filesystem with a log that is too small.
+        */
+       min_logfsbs = xfs_log_calc_minimum_size(mp);
+
+       if (mp->m_sb.sb_logblocks < min_logfsbs) {
+               xfs_warn(mp,
+               "Log size %d blocks too small, minimum size is %d blocks",
+                        mp->m_sb.sb_logblocks, min_logfsbs);
+               error = EINVAL;
+       } else if (mp->m_sb.sb_logblocks > XFS_MAX_LOG_BLOCKS) {
+               xfs_warn(mp,
+               "Log size %d blocks too large, maximum size is %lld blocks",
+                        mp->m_sb.sb_logblocks, XFS_MAX_LOG_BLOCKS);
+               error = EINVAL;
+       } else if (XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks) > XFS_MAX_LOG_BYTES) {
+               xfs_warn(mp,
+               "log size %lld bytes too large, maximum size is %lld bytes",
+                        XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks),
+                        XFS_MAX_LOG_BYTES);
+               error = EINVAL;
+       }
+       if (error) {
+               if (xfs_sb_version_hascrc(&mp->m_sb)) {
+                       xfs_crit(mp, "AAIEEE! Log failed size checks. Abort!");
+                       ASSERT(0);
+                       goto out_free_log;
+               }
+               xfs_crit(mp,
+"Log size out of supported range. Continuing onwards, but if log hangs are\n"
+"experienced then please report this message in the bug report.");
+       }
+
        /*
         * Initialize the AIL now we have a log.
         */
@@ -720,7 +766,7 @@ xfs_log_mount_finish(xfs_mount_t *mp)
  * Unmount record used to have a string "Unmount filesystem--" in the
  * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE).
  * We just write the magic number now since that particular field isn't
- * currently architecture converted and "nUmount" is a bit foo.
+ * currently architecture converted and "Unmount" is a bit foo.
  * As far as I know, there weren't any dependencies on the old behaviour.
  */
 
@@ -1941,7 +1987,7 @@ xlog_print_tic_res(
 
        xfs_alert_tag(mp, XFS_PTAG_LOGRES,
                "xlog_write: reservation ran out. Need to up reservation");
-       xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
+       xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR);
 }
 
 /*
@@ -2044,7 +2090,7 @@ xlog_write_setup_ophdr(
  * Set up the parameters of the region copy into the log. This has
  * to handle region write split across multiple log buffers - this
  * state is kept external to this function so that this code can
- * can be written in an obvious, self documenting manner.
+ * be written in an obvious, self documenting manner.
  */
 static int
 xlog_write_setup_copy(
@@ -3391,24 +3437,17 @@ xfs_log_ticket_get(
 }
 
 /*
- * Allocate and initialise a new log ticket.
+ * Figure out the total log space unit (in bytes) that would be
+ * required for a log ticket.
  */
-struct xlog_ticket *
-xlog_ticket_alloc(
-       struct xlog     *log,
-       int             unit_bytes,
-       int             cnt,
-       char            client,
-       bool            permanent,
-       xfs_km_flags_t  alloc_flags)
+int
+xfs_log_calc_unit_res(
+       struct xfs_mount        *mp,
+       int                     unit_bytes)
 {
-       struct xlog_ticket *tic;
-       uint            num_headers;
-       int             iclog_space;
-
-       tic = kmem_zone_zalloc(xfs_log_ticket_zone, alloc_flags);
-       if (!tic)
-               return NULL;
+       struct xlog             *log = mp->m_log;
+       int                     iclog_space;
+       uint                    num_headers;
 
        /*
         * Permanent reservations have up to 'cnt'-1 active log operations
@@ -3483,20 +3522,43 @@ xlog_ticket_alloc(
        unit_bytes += log->l_iclog_hsize;
 
        /* for roundoff padding for transaction data and one for commit record */
-       if (xfs_sb_version_haslogv2(&log->l_mp->m_sb) &&
-           log->l_mp->m_sb.sb_logsunit > 1) {
+       if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) {
                /* log su roundoff */
-               unit_bytes += 2*log->l_mp->m_sb.sb_logsunit;
+               unit_bytes += 2 * mp->m_sb.sb_logsunit;
        } else {
                /* BB roundoff */
-               unit_bytes += 2*BBSIZE;
+               unit_bytes += 2 * BBSIZE;
         }
 
+       return unit_bytes;
+}
+
+/*
+ * Allocate and initialise a new log ticket.
+ */
+struct xlog_ticket *
+xlog_ticket_alloc(
+       struct xlog             *log,
+       int                     unit_bytes,
+       int                     cnt,
+       char                    client,
+       bool                    permanent,
+       xfs_km_flags_t          alloc_flags)
+{
+       struct xlog_ticket      *tic;
+       int                     unit_res;
+
+       tic = kmem_zone_zalloc(xfs_log_ticket_zone, alloc_flags);
+       if (!tic)
+               return NULL;
+
+       unit_res = xfs_log_calc_unit_res(log->l_mp, unit_bytes);
+
        atomic_set(&tic->t_ref, 1);
        tic->t_task             = current;
        INIT_LIST_HEAD(&tic->t_queue);
-       tic->t_unit_res         = unit_bytes;
-       tic->t_curr_res         = unit_bytes;
+       tic->t_unit_res         = unit_res;
+       tic->t_curr_res         = unit_res;
        tic->t_cnt              = cnt;
        tic->t_ocnt             = cnt;
        tic->t_tid              = prandom_u32();
index fb630e496c12406c558b7cc53854bf0cd123ccaf..1c458487f000a42306cb44f14509d80fea0c2f02 100644 (file)
 #ifndef        __XFS_LOG_H__
 #define __XFS_LOG_H__
 
-/* get lsn fields */
-#define CYCLE_LSN(lsn) ((uint)((lsn)>>32))
-#define BLOCK_LSN(lsn) ((uint)(lsn))
+#include "xfs_log_format.h"
 
-/* this is used in a spot where we might otherwise double-endian-flip */
-#define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0])
+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 */
+       int                     lv_size;        /* size of allocated lv */
+};
+
+#define XFS_LOG_VEC_ORDERED    (-1)
+
+/*
+ * Structure used to pass callback function and the function's argument
+ * to the log manager.
+ */
+typedef struct xfs_log_callback {
+       struct xfs_log_callback *cb_next;
+       void                    (*cb_func)(void *, int);
+       void                    *cb_arg;
+} xfs_log_callback_t;
 
-#ifdef __KERNEL__
 /*
  * By comparing each component, we don't have to worry about extra
  * endian issues in treating two 32 bit numbers as one 64 bit number
@@ -59,67 +75,6 @@ static inline xfs_lsn_t      _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
  */
 #define XFS_LOG_SYNC           0x1
 
-#endif /* __KERNEL__ */
-
-
-/* Log Clients */
-#define XFS_TRANSACTION                0x69
-#define XFS_VOLUME             0x2
-#define XFS_LOG                        0xaa
-
-
-/* Region types for iovec's i_type */
-#define XLOG_REG_TYPE_BFORMAT          1
-#define XLOG_REG_TYPE_BCHUNK           2
-#define XLOG_REG_TYPE_EFI_FORMAT       3
-#define XLOG_REG_TYPE_EFD_FORMAT       4
-#define XLOG_REG_TYPE_IFORMAT          5
-#define XLOG_REG_TYPE_ICORE            6
-#define XLOG_REG_TYPE_IEXT             7
-#define XLOG_REG_TYPE_IBROOT           8
-#define XLOG_REG_TYPE_ILOCAL           9
-#define XLOG_REG_TYPE_IATTR_EXT                10
-#define XLOG_REG_TYPE_IATTR_BROOT      11
-#define XLOG_REG_TYPE_IATTR_LOCAL      12
-#define XLOG_REG_TYPE_QFORMAT          13
-#define XLOG_REG_TYPE_DQUOT            14
-#define XLOG_REG_TYPE_QUOTAOFF         15
-#define XLOG_REG_TYPE_LRHEADER         16
-#define XLOG_REG_TYPE_UNMOUNT          17
-#define XLOG_REG_TYPE_COMMIT           18
-#define XLOG_REG_TYPE_TRANSHDR         19
-#define XLOG_REG_TYPE_ICREATE          20
-#define XLOG_REG_TYPE_MAX              20
-
-typedef struct xfs_log_iovec {
-       void            *i_addr;        /* beginning address of region */
-       int             i_len;          /* length in bytes of region */
-       uint            i_type;         /* type of region */
-} xfs_log_iovec_t;
-
-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 */
-};
-
-#define XFS_LOG_VEC_ORDERED    (-1)
-
-/*
- * Structure used to pass callback function and the function's argument
- * to the log manager.
- */
-typedef struct xfs_log_callback {
-       struct xfs_log_callback *cb_next;
-       void                    (*cb_func)(void *, int);
-       void                    *cb_arg;
-} xfs_log_callback_t;
-
-
-#ifdef __KERNEL__
 /* Log manager interfaces */
 struct xfs_mount;
 struct xlog_in_core;
@@ -188,5 +143,4 @@ void        xfs_log_work_queue(struct xfs_mount *mp);
 void   xfs_log_worker(struct work_struct *work);
 void   xfs_log_quiesce(struct xfs_mount *mp);
 
-#endif
 #endif /* __XFS_LOG_H__ */
index 02b9cf3f8252baeade5d4e99b3e88853a7b50b98..cfe97973ba36d1d586c3704b536aebce2e391af1 100644 (file)
@@ -80,6 +80,83 @@ xlog_cil_init_post_recovery(
                                                                log->l_curr_block);
 }
 
+STATIC int
+xlog_cil_lv_item_format(
+       struct xfs_log_item     *lip,
+       struct xfs_log_vec      *lv)
+{
+       int     index;
+       char    *ptr;
+
+       /* format new vectors into array */
+       lip->li_ops->iop_format(lip, lv->lv_iovecp);
+
+       /* copy data into existing array */
+       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;
+       }
+
+       /*
+        * some size calculations for log vectors over-estimate, so the caller
+        * doesn't know the amount of space actually used by the item. Return
+        * the byte count to the caller so they can check and store it
+        * appropriately.
+        */
+       return ptr - lv->lv_buf;
+}
+
+/*
+ * Prepare the log item for insertion into the CIL. Calculate the difference in
+ * log space and vectors it will consume, and if it is a new item pin it as
+ * well.
+ */
+STATIC void
+xfs_cil_prepare_item(
+       struct xlog             *log,
+       struct xfs_log_vec      *lv,
+       struct xfs_log_vec      *old_lv,
+       int                     *diff_len,
+       int                     *diff_iovecs)
+{
+       /* Account for the new LV being passed in */
+       if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) {
+               *diff_len += lv->lv_buf_len;
+               *diff_iovecs += lv->lv_niovecs;
+       }
+
+       /*
+        * If there is no old LV, this is the first time we've seen the item in
+        * this CIL context and so we need to pin it. If we are replacing the
+        * old_lv, then remove the space it accounts for and free it.
+        */
+       if (!old_lv)
+               lv->lv_item->li_ops->iop_pin(lv->lv_item);
+       else if (old_lv != lv) {
+               ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED);
+
+               *diff_len -= old_lv->lv_buf_len;
+               *diff_iovecs -= old_lv->lv_niovecs;
+               kmem_free(old_lv);
+       }
+
+       /* attach new log vector to log item */
+       lv->lv_item->li_lv = lv;
+
+       /*
+        * 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 (!lv->lv_item->li_seq)
+               lv->lv_item->li_seq = log->l_cilp->xc_ctx->sequence;
+}
+
 /*
  * Format log item into a flat buffers
  *
@@ -106,35 +183,39 @@ xlog_cil_init_post_recovery(
  * format the regions into the iclog as though they are being formatted
  * directly out of the objects themselves.
  */
-static struct xfs_log_vec *
-xlog_cil_prepare_log_vecs(
-       struct xfs_trans        *tp)
+static void
+xlog_cil_insert_format_items(
+       struct xlog             *log,
+       struct xfs_trans        *tp,
+       int                     *diff_len,
+       int                     *diff_iovecs)
 {
        struct xfs_log_item_desc *lidp;
-       struct xfs_log_vec      *lv = NULL;
-       struct xfs_log_vec      *ret_lv = NULL;
 
 
        /* Bail out if we didn't find a log item.  */
        if (list_empty(&tp->t_items)) {
                ASSERT(0);
-               return NULL;
+               return;
        }
 
        list_for_each_entry(lidp, &tp->t_items, lid_trans) {
-               struct xfs_log_vec *new_lv;
-               void    *ptr;
-               int     index;
-               int     len = 0;
-               uint    niovecs;
+               struct xfs_log_item *lip = lidp->lid_item;
+               struct xfs_log_vec *lv;
+               struct xfs_log_vec *old_lv;
+               int     niovecs = 0;
+               int     nbytes = 0;
+               int     buf_size;
                bool    ordered = false;
 
                /* Skip items which aren't dirty in this transaction. */
                if (!(lidp->lid_flags & XFS_LID_DIRTY))
                        continue;
 
+               /* get number of vecs and size of data to be stored */
+               lip->li_ops->iop_size(lip, &niovecs, &nbytes);
+
                /* Skip items that do not have any vectors for writing */
-               niovecs = IOP_SIZE(lidp->lid_item);
                if (!niovecs)
                        continue;
 
@@ -146,109 +227,63 @@ xlog_cil_prepare_log_vecs(
                if (niovecs == XFS_LOG_VEC_ORDERED) {
                        ordered = true;
                        niovecs = 0;
+                       nbytes = 0;
                }
 
-               new_lv = kmem_zalloc(sizeof(*new_lv) +
-                               niovecs * sizeof(struct xfs_log_iovec),
-                               KM_SLEEP|KM_NOFS);
-
-               new_lv->lv_item = lidp->lid_item;
-               new_lv->lv_niovecs = niovecs;
-               if (ordered) {
-                       /* track as an ordered logvec */
-                       new_lv->lv_buf_len = XFS_LOG_VEC_ORDERED;
-                       goto next;
-               }
-
-               /* The allocated iovec region lies beyond the log vector. */
-               new_lv->lv_iovecp = (struct xfs_log_iovec *)&new_lv[1];
+               /* grab the old item if it exists for reservation accounting */
+               old_lv = lip->li_lv;
 
-               /* build the vector array and calculate it's length */
-               IOP_FORMAT(new_lv->lv_item, new_lv->lv_iovecp);
-               for (index = 0; index < new_lv->lv_niovecs; index++)
-                       len += new_lv->lv_iovecp[index].i_len;
+               /* calc buffer size */
+               buf_size = sizeof(struct xfs_log_vec) + nbytes +
+                               niovecs * sizeof(struct xfs_log_iovec);
 
-               new_lv->lv_buf_len = len;
-               new_lv->lv_buf = kmem_alloc(new_lv->lv_buf_len,
-                               KM_SLEEP|KM_NOFS);
-               ptr = new_lv->lv_buf;
+               /* compare to existing item size */
+               if (lip->li_lv && buf_size <= lip->li_lv->lv_size) {
+                       /* same or smaller, optimise common overwrite case */
+                       lv = lip->li_lv;
+                       lv->lv_next = NULL;
 
-               for (index = 0; index < new_lv->lv_niovecs; index++) {
-                       struct xfs_log_iovec *vec = &new_lv->lv_iovecp[index];
+                       if (ordered)
+                               goto insert;
 
-                       memcpy(ptr, vec->i_addr, vec->i_len);
-                       vec->i_addr = ptr;
-                       ptr += vec->i_len;
-               }
-               ASSERT(ptr == new_lv->lv_buf + new_lv->lv_buf_len);
-
-next:
-               if (!ret_lv)
-                       ret_lv = new_lv;
-               else
-                       lv->lv_next = new_lv;
-               lv = new_lv;
-       }
-
-       return ret_lv;
-}
-
-/*
- * Prepare the log item for insertion into the CIL. Calculate the difference in
- * log space and vectors it will consume, and if it is a new item pin it as
- * well.
- */
-STATIC void
-xfs_cil_prepare_item(
-       struct xlog             *log,
-       struct xfs_log_vec      *lv,
-       int                     *len,
-       int                     *diff_iovecs)
-{
-       struct xfs_log_vec      *old = lv->lv_item->li_lv;
+                       /*
+                        * set the item up as though it is a new insertion so
+                        * that the space reservation accounting is correct.
+                        */
+                       *diff_iovecs -= lv->lv_niovecs;
+                       *diff_len -= lv->lv_buf_len;
 
-       if (old) {
-               /* existing lv on log item, space used is a delta */
-               ASSERT((old->lv_buf && old->lv_buf_len && old->lv_niovecs) ||
-                       old->lv_buf_len == XFS_LOG_VEC_ORDERED);
+                       /* Ensure the lv is set up according to ->iop_size */
+                       lv->lv_niovecs = niovecs;
+                       lv->lv_buf = (char *)lv + buf_size - nbytes;
 
-               /*
-                * If the new item is ordered, keep the old one that is already
-                * tracking dirty or ordered regions
-                */
-               if (lv->lv_buf_len == XFS_LOG_VEC_ORDERED) {
-                       ASSERT(!lv->lv_buf);
-                       kmem_free(lv);
-                       return;
+                       lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv);
+                       goto insert;
                }
 
-               *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);
-
-               if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) {
-                       *len += lv->lv_buf_len;
-                       *diff_iovecs += lv->lv_niovecs;
+               /* allocate new data chunk */
+               lv = kmem_zalloc(buf_size, KM_SLEEP|KM_NOFS);
+               lv->lv_item = lip;
+               lv->lv_size = buf_size;
+               lv->lv_niovecs = niovecs;
+               if (ordered) {
+                       /* track as an ordered logvec */
+                       ASSERT(lip->li_lv == NULL);
+                       lv->lv_buf_len = XFS_LOG_VEC_ORDERED;
+                       goto insert;
                }
-               IOP_PIN(lv->lv_item);
 
-       }
+               /* The allocated iovec region lies beyond the log vector. */
+               lv->lv_iovecp = (struct xfs_log_iovec *)&lv[1];
 
-       /* attach new log vector to log item */
-       lv->lv_item->li_lv = lv;
+               /* The allocated data region lies beyond the iovec region */
+               lv->lv_buf = (char *)lv + buf_size - nbytes;
 
-       /*
-        * 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 (!lv->lv_item->li_seq)
-               lv->lv_item->li_seq = log->l_cilp->xc_ctx->sequence;
+               lv->lv_buf_len = xlog_cil_lv_item_format(lip, lv);
+insert:
+               ASSERT(lv->lv_buf_len <= nbytes);
+               xfs_cil_prepare_item(log, lv, old_lv, diff_len, diff_iovecs);
+       }
 }
 
 /*
@@ -261,53 +296,47 @@ xfs_cil_prepare_item(
 static void
 xlog_cil_insert_items(
        struct xlog             *log,
-       struct xfs_log_vec      *log_vector,
-       struct xlog_ticket      *ticket)
+       struct xfs_trans        *tp)
 {
        struct xfs_cil          *cil = log->l_cilp;
        struct xfs_cil_ctx      *ctx = cil->xc_ctx;
-       struct xfs_log_vec      *lv;
+       struct xfs_log_item_desc *lidp;
        int                     len = 0;
        int                     diff_iovecs = 0;
        int                     iclog_space;
 
-       ASSERT(log_vector);
+       ASSERT(tp);
 
        /*
-        * Do all the accounting aggregation and switching of log vectors
-        * around in a separate loop to the insertion of items into the CIL.
-        * Then we can do a separate loop to update the CIL within a single
-        * lock/unlock pair. This reduces the number of round trips on the CIL
-        * lock from O(nr_logvectors) to O(1) and greatly reduces the overall
-        * hold time for the transaction commit.
-        *
-        * 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.
-        *
         * We can do this safely because the context can't checkpoint until we
         * are done so it doesn't matter exactly how we update the CIL.
         */
+       xlog_cil_insert_format_items(log, tp, &len, &diff_iovecs);
+
+       /*
+        * Now (re-)position everything modified at the tail of the CIL.
+        * We do this here so we only need to take the CIL lock once during
+        * the transaction commit.
+        */
        spin_lock(&cil->xc_cil_lock);
-       for (lv = log_vector; lv; ) {
-               struct xfs_log_vec *next = lv->lv_next;
+       list_for_each_entry(lidp, &tp->t_items, lid_trans) {
+               struct xfs_log_item     *lip = lidp->lid_item;
 
-               ASSERT(lv->lv_item->li_lv || list_empty(&lv->lv_item->li_cil));
-               lv->lv_next = NULL;
+               /* Skip items which aren't dirty in this transaction. */
+               if (!(lidp->lid_flags & XFS_LID_DIRTY))
+                       continue;
 
-               /*
-                * xfs_cil_prepare_item() may free the lv, so move the item on
-                * the CIL first.
-                */
-               list_move_tail(&lv->lv_item->li_cil, &cil->xc_cil);
-               xfs_cil_prepare_item(log, lv, &len, &diff_iovecs);
-               lv = next;
+               list_move_tail(&lip->li_cil, &cil->xc_cil);
        }
 
        /* account for space used by new iovec headers  */
        len += diff_iovecs * sizeof(xlog_op_header_t);
        ctx->nvecs += diff_iovecs;
 
+       /* attach the transaction to the CIL if it has any busy extents */
+       if (!list_empty(&tp->t_busy))
+               list_splice_init(&tp->t_busy, &ctx->busy_extents);
+
        /*
         * Now transfer enough transaction reservation to the context ticket
         * for the checkpoint. The context ticket is special - the unit
@@ -316,10 +345,8 @@ xlog_cil_insert_items(
         * 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;
+               tp->t_ticket->t_curr_res -= ctx->ticket->t_unit_res;
        }
 
        /* do we need space for more log record headers? */
@@ -333,10 +360,10 @@ xlog_cil_insert_items(
                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);
+               tp->t_ticket->t_curr_res -= hdrs;
+               ASSERT(tp->t_ticket->t_curr_res >= len);
        }
-       ticket->t_curr_res -= len;
+       tp->t_ticket->t_curr_res -= len;
        ctx->space_used += len;
 
        spin_unlock(&cil->xc_cil_lock);
@@ -350,7 +377,6 @@ xlog_cil_free_logvec(
 
        for (lv = log_vector; lv; ) {
                struct xfs_log_vec *next = lv->lv_next;
-               kmem_free(lv->lv_buf);
                kmem_free(lv);
                lv = next;
        }
@@ -376,9 +402,9 @@ xlog_cil_committed(
        xfs_extent_busy_clear(mp, &ctx->busy_extents,
                             (mp->m_flags & XFS_MOUNT_DISCARD) && !abort);
 
-       spin_lock(&ctx->cil->xc_cil_lock);
+       spin_lock(&ctx->cil->xc_push_lock);
        list_del(&ctx->committing);
-       spin_unlock(&ctx->cil->xc_cil_lock);
+       spin_unlock(&ctx->cil->xc_push_lock);
 
        xlog_cil_free_logvec(ctx->lv_chain);
 
@@ -433,7 +459,7 @@ xlog_cil_push(
        down_write(&cil->xc_ctx_lock);
        ctx = cil->xc_ctx;
 
-       spin_lock(&cil->xc_cil_lock);
+       spin_lock(&cil->xc_push_lock);
        push_seq = cil->xc_push_seq;
        ASSERT(push_seq <= ctx->sequence);
 
@@ -444,10 +470,10 @@ xlog_cil_push(
         */
        if (list_empty(&cil->xc_cil)) {
                cil->xc_push_seq = 0;
-               spin_unlock(&cil->xc_cil_lock);
+               spin_unlock(&cil->xc_push_lock);
                goto out_skip;
        }
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
 
 
        /* check for a previously pushed seqeunce */
@@ -515,9 +541,9 @@ xlog_cil_push(
         * that higher sequences will wait for us to write out a commit record
         * before they do.
         */
-       spin_lock(&cil->xc_cil_lock);
+       spin_lock(&cil->xc_push_lock);
        list_add(&ctx->committing, &cil->xc_committing);
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
        up_write(&cil->xc_ctx_lock);
 
        /*
@@ -552,7 +578,7 @@ xlog_cil_push(
         * order the commit records so replay will get them in the right order.
         */
 restart:
-       spin_lock(&cil->xc_cil_lock);
+       spin_lock(&cil->xc_push_lock);
        list_for_each_entry(new_ctx, &cil->xc_committing, committing) {
                /*
                 * Higher sequences will wait for this one so skip them.
@@ -565,11 +591,11 @@ restart:
                         * It is still being pushed! Wait for the push to
                         * complete, then start again from the beginning.
                         */
-                       xlog_wait(&cil->xc_commit_wait, &cil->xc_cil_lock);
+                       xlog_wait(&cil->xc_commit_wait, &cil->xc_push_lock);
                        goto restart;
                }
        }
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
 
        /* xfs_log_done always frees the ticket on error. */
        commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, 0);
@@ -588,10 +614,10 @@ restart:
         * 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);
+       spin_lock(&cil->xc_push_lock);
        ctx->commit_lsn = commit_lsn;
        wake_up_all(&cil->xc_commit_wait);
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
 
        /* release the hounds! */
        return xfs_log_release_iclog(log->l_mp, commit_iclog);
@@ -644,12 +670,12 @@ xlog_cil_push_background(
        if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log))
                return;
 
-       spin_lock(&cil->xc_cil_lock);
+       spin_lock(&cil->xc_push_lock);
        if (cil->xc_push_seq < cil->xc_current_sequence) {
                cil->xc_push_seq = cil->xc_current_sequence;
                queue_work(log->l_mp->m_cil_workqueue, &cil->xc_push_work);
        }
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
 
 }
 
@@ -672,14 +698,14 @@ xlog_cil_push_foreground(
         * If the CIL is empty or we've already pushed the sequence then
         * there's no work we need to do.
         */
-       spin_lock(&cil->xc_cil_lock);
+       spin_lock(&cil->xc_push_lock);
        if (list_empty(&cil->xc_cil) || push_seq <= cil->xc_push_seq) {
-               spin_unlock(&cil->xc_cil_lock);
+               spin_unlock(&cil->xc_push_lock);
                return;
        }
 
        cil->xc_push_seq = push_seq;
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
 
        /* do the push now */
        xlog_cil_push(log);
@@ -706,43 +732,25 @@ xfs_log_commit_cil(
        int                     flags)
 {
        struct xlog             *log = mp->m_log;
+       struct xfs_cil          *cil = log->l_cilp;
        int                     log_flags = 0;
-       struct xfs_log_vec      *log_vector;
 
        if (flags & XFS_TRANS_RELEASE_LOG_RES)
                log_flags = XFS_LOG_REL_PERM_RESERV;
 
-       /*
-        * Do all the hard work of formatting items (including memory
-        * allocation) outside the CIL context lock. This prevents stalling CIL
-        * pushes when we are low on memory and a transaction commit spends a
-        * lot of time in memory reclaim.
-        */
-       log_vector = xlog_cil_prepare_log_vecs(tp);
-       if (!log_vector)
-               return ENOMEM;
-
        /* lock out background commit */
-       down_read(&log->l_cilp->xc_ctx_lock);
-       if (commit_lsn)
-               *commit_lsn = log->l_cilp->xc_ctx->sequence;
+       down_read(&cil->xc_ctx_lock);
 
-       /* xlog_cil_insert_items() destroys log_vector list */
-       xlog_cil_insert_items(log, log_vector, tp->t_ticket);
+       xlog_cil_insert_items(log, tp);
 
        /* 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);
+               xlog_print_tic_res(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 = cil->xc_ctx->sequence;
+       if (commit_lsn)
+               *commit_lsn = tp->t_commit_lsn;
 
-       tp->t_commit_lsn = *commit_lsn;
        xfs_log_done(mp, tp->t_ticket, NULL, log_flags);
        xfs_trans_unreserve_and_mod_sb(tp);
 
@@ -757,11 +765,11 @@ xfs_log_commit_cil(
         * the log items. This affects (at least) processing of stale buffers,
         * inodes and EFIs.
         */
-       xfs_trans_free_items(tp, *commit_lsn, 0);
+       xfs_trans_free_items(tp, tp->t_commit_lsn, 0);
 
        xlog_cil_push_background(log);
 
-       up_read(&log->l_cilp->xc_ctx_lock);
+       up_read(&cil->xc_ctx_lock);
        return 0;
 }
 
@@ -800,7 +808,7 @@ xlog_cil_force_lsn(
         * on commits for those as well.
         */
 restart:
-       spin_lock(&cil->xc_cil_lock);
+       spin_lock(&cil->xc_push_lock);
        list_for_each_entry(ctx, &cil->xc_committing, committing) {
                if (ctx->sequence > sequence)
                        continue;
@@ -809,7 +817,7 @@ restart:
                         * It is still being pushed! Wait for the push to
                         * complete, then start again from the beginning.
                         */
-                       xlog_wait(&cil->xc_commit_wait, &cil->xc_cil_lock);
+                       xlog_wait(&cil->xc_commit_wait, &cil->xc_push_lock);
                        goto restart;
                }
                if (ctx->sequence != sequence)
@@ -817,7 +825,7 @@ restart:
                /* found it! */
                commit_lsn = ctx->commit_lsn;
        }
-       spin_unlock(&cil->xc_cil_lock);
+       spin_unlock(&cil->xc_push_lock);
        return commit_lsn;
 }
 
@@ -875,6 +883,7 @@ xlog_cil_init(
        INIT_LIST_HEAD(&cil->xc_cil);
        INIT_LIST_HEAD(&cil->xc_committing);
        spin_lock_init(&cil->xc_cil_lock);
+       spin_lock_init(&cil->xc_push_lock);
        init_rwsem(&cil->xc_ctx_lock);
        init_waitqueue_head(&cil->xc_commit_wait);
 
diff --git a/fs/xfs/xfs_log_format.h b/fs/xfs/xfs_log_format.h
new file mode 100644 (file)
index 0000000..ca7e28a
--- /dev/null
@@ -0,0 +1,856 @@
+/*
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, 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
+ */
+#ifndef        __XFS_LOG_FORMAT_H__
+#define __XFS_LOG_FORMAT_H__
+
+struct xfs_mount;
+struct xfs_trans_res;
+
+/*
+ * On-disk Log Format definitions.
+ *
+ * This file contains all the on-disk format definitions used within the log. It
+ * includes the physical log structure itself, as well as all the log item
+ * format structures that are written into the log and intepreted by log
+ * recovery. We start with the physical log format definitions, and then work
+ * through all the log items definitions and everything they encode into the
+ * log.
+ */
+typedef __uint32_t xlog_tid_t;
+
+#define XLOG_MIN_ICLOGS                2
+#define XLOG_MAX_ICLOGS                8
+#define XLOG_HEADER_MAGIC_NUM  0xFEEDbabe      /* Invalid cycle number */
+#define XLOG_VERSION_1         1
+#define XLOG_VERSION_2         2               /* Large IClogs, Log sunit */
+#define XLOG_VERSION_OKBITS    (XLOG_VERSION_1 | XLOG_VERSION_2)
+#define XLOG_MIN_RECORD_BSIZE  (16*1024)       /* eventually 32k */
+#define XLOG_BIG_RECORD_BSIZE  (32*1024)       /* 32k buffers */
+#define XLOG_MAX_RECORD_BSIZE  (256*1024)
+#define XLOG_HEADER_CYCLE_SIZE (32*1024)       /* cycle data in header */
+#define XLOG_MIN_RECORD_BSHIFT 14              /* 16384 == 1 << 14 */
+#define XLOG_BIG_RECORD_BSHIFT 15              /* 32k == 1 << 15 */
+#define XLOG_MAX_RECORD_BSHIFT 18              /* 256k == 1 << 18 */
+#define XLOG_BTOLSUNIT(log, b)  (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \
+                                 (log)->l_mp->m_sb.sb_logsunit)
+#define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit)
+
+#define XLOG_HEADER_SIZE       512
+
+/* Minimum number of transactions that must fit in the log (defined by mkfs) */
+#define XFS_MIN_LOG_FACTOR     3
+
+#define XLOG_REC_SHIFT(log) \
+       BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \
+        XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
+#define XLOG_TOTAL_REC_SHIFT(log) \
+       BTOBB(XLOG_MAX_ICLOGS << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \
+        XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
+
+/* get lsn fields */
+#define CYCLE_LSN(lsn) ((uint)((lsn)>>32))
+#define BLOCK_LSN(lsn) ((uint)(lsn))
+
+/* this is used in a spot where we might otherwise double-endian-flip */
+#define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0])
+
+static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block)
+{
+       return ((xfs_lsn_t)cycle << 32) | block;
+}
+
+static inline uint xlog_get_cycle(char *ptr)
+{
+       if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM)
+               return be32_to_cpu(*((__be32 *)ptr + 1));
+       else
+               return be32_to_cpu(*(__be32 *)ptr);
+}
+
+/* Log Clients */
+#define XFS_TRANSACTION                0x69
+#define XFS_VOLUME             0x2
+#define XFS_LOG                        0xaa
+
+#define XLOG_UNMOUNT_TYPE      0x556e  /* Un for Unmount */
+
+/* Region types for iovec's i_type */
+#define XLOG_REG_TYPE_BFORMAT          1
+#define XLOG_REG_TYPE_BCHUNK           2
+#define XLOG_REG_TYPE_EFI_FORMAT       3
+#define XLOG_REG_TYPE_EFD_FORMAT       4
+#define XLOG_REG_TYPE_IFORMAT          5
+#define XLOG_REG_TYPE_ICORE            6
+#define XLOG_REG_TYPE_IEXT             7
+#define XLOG_REG_TYPE_IBROOT           8
+#define XLOG_REG_TYPE_ILOCAL           9
+#define XLOG_REG_TYPE_IATTR_EXT                10
+#define XLOG_REG_TYPE_IATTR_BROOT      11
+#define XLOG_REG_TYPE_IATTR_LOCAL      12
+#define XLOG_REG_TYPE_QFORMAT          13
+#define XLOG_REG_TYPE_DQUOT            14
+#define XLOG_REG_TYPE_QUOTAOFF         15
+#define XLOG_REG_TYPE_LRHEADER         16
+#define XLOG_REG_TYPE_UNMOUNT          17
+#define XLOG_REG_TYPE_COMMIT           18
+#define XLOG_REG_TYPE_TRANSHDR         19
+#define XLOG_REG_TYPE_ICREATE          20
+#define XLOG_REG_TYPE_MAX              20
+
+/*
+ * Flags to log operation header
+ *
+ * The first write of a new transaction will be preceded with a start
+ * record, XLOG_START_TRANS.  Once a transaction is committed, a commit
+ * record is written, XLOG_COMMIT_TRANS.  If a single region can not fit into
+ * the remainder of the current active in-core log, it is split up into
+ * multiple regions.  Each partial region will be marked with a
+ * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS.
+ *
+ */
+#define XLOG_START_TRANS       0x01    /* Start a new transaction */
+#define XLOG_COMMIT_TRANS      0x02    /* Commit this transaction */
+#define XLOG_CONTINUE_TRANS    0x04    /* Cont this trans into new region */
+#define XLOG_WAS_CONT_TRANS    0x08    /* Cont this trans into new region */
+#define XLOG_END_TRANS         0x10    /* End a continued transaction */
+#define XLOG_UNMOUNT_TRANS     0x20    /* Unmount a filesystem transaction */
+
+
+typedef struct xlog_op_header {
+       __be32     oh_tid;      /* transaction id of operation  :  4 b */
+       __be32     oh_len;      /* bytes in data region         :  4 b */
+       __u8       oh_clientid; /* who sent me this             :  1 b */
+       __u8       oh_flags;    /*                              :  1 b */
+       __u16      oh_res2;     /* 32 bit align                 :  2 b */
+} xlog_op_header_t;
+
+/* valid values for h_fmt */
+#define XLOG_FMT_UNKNOWN  0
+#define XLOG_FMT_LINUX_LE 1
+#define XLOG_FMT_LINUX_BE 2
+#define XLOG_FMT_IRIX_BE  3
+
+/* our fmt */
+#ifdef XFS_NATIVE_HOST
+#define XLOG_FMT XLOG_FMT_LINUX_BE
+#else
+#define XLOG_FMT XLOG_FMT_LINUX_LE
+#endif
+
+typedef struct xlog_rec_header {
+       __be32    h_magicno;    /* log record (LR) identifier           :  4 */
+       __be32    h_cycle;      /* write cycle of log                   :  4 */
+       __be32    h_version;    /* LR version                           :  4 */
+       __be32    h_len;        /* len in bytes; should be 64-bit aligned: 4 */
+       __be64    h_lsn;        /* lsn of this LR                       :  8 */
+       __be64    h_tail_lsn;   /* lsn of 1st LR w/ buffers not committed: 8 */
+       __le32    h_crc;        /* crc of log record                    :  4 */
+       __be32    h_prev_block; /* block number to previous LR          :  4 */
+       __be32    h_num_logops; /* number of log operations in this LR  :  4 */
+       __be32    h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE];
+       /* new fields */
+       __be32    h_fmt;        /* format of log record                 :  4 */
+       uuid_t    h_fs_uuid;    /* uuid of FS                           : 16 */
+       __be32    h_size;       /* iclog size                           :  4 */
+} xlog_rec_header_t;
+
+typedef struct xlog_rec_ext_header {
+       __be32    xh_cycle;     /* write cycle of log                   : 4 */
+       __be32    xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /*    : 256 */
+} xlog_rec_ext_header_t;
+
+/*
+ * Quite misnamed, because this union lays out the actual on-disk log buffer.
+ */
+typedef union xlog_in_core2 {
+       xlog_rec_header_t       hic_header;
+       xlog_rec_ext_header_t   hic_xheader;
+       char                    hic_sector[XLOG_HEADER_SIZE];
+} xlog_in_core_2_t;
+
+/* not an on-disk structure, but needed by log recovery in userspace */
+typedef struct xfs_log_iovec {
+       void            *i_addr;        /* beginning address of region */
+       int             i_len;          /* length in bytes of region */
+       uint            i_type;         /* type of region */
+} xfs_log_iovec_t;
+
+
+/*
+ * Transaction Header definitions.
+ *
+ * This is the structure written in the log at the head of every transaction. It
+ * identifies the type and id of the transaction, and contains the number of
+ * items logged by the transaction so we know how many to expect during
+ * recovery.
+ *
+ * Do not change the below structure without redoing the code in
+ * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans().
+ */
+typedef struct xfs_trans_header {
+       uint            th_magic;               /* magic number */
+       uint            th_type;                /* transaction type */
+       __int32_t       th_tid;                 /* transaction id (unused) */
+       uint            th_num_items;           /* num items logged by trans */
+} xfs_trans_header_t;
+
+#define        XFS_TRANS_HEADER_MAGIC  0x5452414e      /* TRAN */
+
+/*
+ * Log item types.
+ */
+#define        XFS_LI_EFI              0x1236
+#define        XFS_LI_EFD              0x1237
+#define        XFS_LI_IUNLINK          0x1238
+#define        XFS_LI_INODE            0x123b  /* aligned ino chunks, var-size ibufs */
+#define        XFS_LI_BUF              0x123c  /* v2 bufs, variable sized inode bufs */
+#define        XFS_LI_DQUOT            0x123d
+#define        XFS_LI_QUOTAOFF         0x123e
+#define        XFS_LI_ICREATE          0x123f
+
+#define XFS_LI_TYPE_DESC \
+       { XFS_LI_EFI,           "XFS_LI_EFI" }, \
+       { XFS_LI_EFD,           "XFS_LI_EFD" }, \
+       { XFS_LI_IUNLINK,       "XFS_LI_IUNLINK" }, \
+       { XFS_LI_INODE,         "XFS_LI_INODE" }, \
+       { XFS_LI_BUF,           "XFS_LI_BUF" }, \
+       { XFS_LI_DQUOT,         "XFS_LI_DQUOT" }, \
+       { XFS_LI_QUOTAOFF,      "XFS_LI_QUOTAOFF" }, \
+       { XFS_LI_ICREATE,       "XFS_LI_ICREATE" }
+
+/*
+ * Transaction types.  Used to distinguish types of buffers.
+ */
+#define XFS_TRANS_SETATTR_NOT_SIZE     1
+#define XFS_TRANS_SETATTR_SIZE         2
+#define XFS_TRANS_INACTIVE             3
+#define XFS_TRANS_CREATE               4
+#define XFS_TRANS_CREATE_TRUNC         5
+#define XFS_TRANS_TRUNCATE_FILE                6
+#define XFS_TRANS_REMOVE               7
+#define XFS_TRANS_LINK                 8
+#define XFS_TRANS_RENAME               9
+#define XFS_TRANS_MKDIR                        10
+#define XFS_TRANS_RMDIR                        11
+#define XFS_TRANS_SYMLINK              12
+#define XFS_TRANS_SET_DMATTRS          13
+#define XFS_TRANS_GROWFS               14
+#define XFS_TRANS_STRAT_WRITE          15
+#define XFS_TRANS_DIOSTRAT             16
+/* 17 was XFS_TRANS_WRITE_SYNC */
+#define        XFS_TRANS_WRITEID               18
+#define        XFS_TRANS_ADDAFORK              19
+#define        XFS_TRANS_ATTRINVAL             20
+#define        XFS_TRANS_ATRUNCATE             21
+#define        XFS_TRANS_ATTR_SET              22
+#define        XFS_TRANS_ATTR_RM               23
+#define        XFS_TRANS_ATTR_FLAG             24
+#define        XFS_TRANS_CLEAR_AGI_BUCKET      25
+#define XFS_TRANS_QM_SBCHANGE          26
+/*
+ * Dummy entries since we use the transaction type to index into the
+ * trans_type[] in xlog_recover_print_trans_head()
+ */
+#define XFS_TRANS_DUMMY1               27
+#define XFS_TRANS_DUMMY2               28
+#define XFS_TRANS_QM_QUOTAOFF          29
+#define XFS_TRANS_QM_DQALLOC           30
+#define XFS_TRANS_QM_SETQLIM           31
+#define XFS_TRANS_QM_DQCLUSTER         32
+#define XFS_TRANS_QM_QINOCREATE                33
+#define XFS_TRANS_QM_QUOTAOFF_END      34
+#define XFS_TRANS_SB_UNIT              35
+#define XFS_TRANS_FSYNC_TS             36
+#define        XFS_TRANS_GROWFSRT_ALLOC        37
+#define        XFS_TRANS_GROWFSRT_ZERO         38
+#define        XFS_TRANS_GROWFSRT_FREE         39
+#define        XFS_TRANS_SWAPEXT               40
+#define        XFS_TRANS_SB_COUNT              41
+#define        XFS_TRANS_CHECKPOINT            42
+#define        XFS_TRANS_ICREATE               43
+#define        XFS_TRANS_TYPE_MAX              43
+/* new transaction types need to be reflected in xfs_logprint(8) */
+
+#define XFS_TRANS_TYPES \
+       { XFS_TRANS_SETATTR_NOT_SIZE,   "SETATTR_NOT_SIZE" }, \
+       { XFS_TRANS_SETATTR_SIZE,       "SETATTR_SIZE" }, \
+       { XFS_TRANS_INACTIVE,           "INACTIVE" }, \
+       { XFS_TRANS_CREATE,             "CREATE" }, \
+       { XFS_TRANS_CREATE_TRUNC,       "CREATE_TRUNC" }, \
+       { XFS_TRANS_TRUNCATE_FILE,      "TRUNCATE_FILE" }, \
+       { XFS_TRANS_REMOVE,             "REMOVE" }, \
+       { XFS_TRANS_LINK,               "LINK" }, \
+       { XFS_TRANS_RENAME,             "RENAME" }, \
+       { XFS_TRANS_MKDIR,              "MKDIR" }, \
+       { XFS_TRANS_RMDIR,              "RMDIR" }, \
+       { XFS_TRANS_SYMLINK,            "SYMLINK" }, \
+       { XFS_TRANS_SET_DMATTRS,        "SET_DMATTRS" }, \
+       { XFS_TRANS_GROWFS,             "GROWFS" }, \
+       { XFS_TRANS_STRAT_WRITE,        "STRAT_WRITE" }, \
+       { XFS_TRANS_DIOSTRAT,           "DIOSTRAT" }, \
+       { XFS_TRANS_WRITEID,            "WRITEID" }, \
+       { XFS_TRANS_ADDAFORK,           "ADDAFORK" }, \
+       { XFS_TRANS_ATTRINVAL,          "ATTRINVAL" }, \
+       { XFS_TRANS_ATRUNCATE,          "ATRUNCATE" }, \
+       { XFS_TRANS_ATTR_SET,           "ATTR_SET" }, \
+       { XFS_TRANS_ATTR_RM,            "ATTR_RM" }, \
+       { XFS_TRANS_ATTR_FLAG,          "ATTR_FLAG" }, \
+       { XFS_TRANS_CLEAR_AGI_BUCKET,   "CLEAR_AGI_BUCKET" }, \
+       { XFS_TRANS_QM_SBCHANGE,        "QM_SBCHANGE" }, \
+       { XFS_TRANS_QM_QUOTAOFF,        "QM_QUOTAOFF" }, \
+       { XFS_TRANS_QM_DQALLOC,         "QM_DQALLOC" }, \
+       { XFS_TRANS_QM_SETQLIM,         "QM_SETQLIM" }, \
+       { XFS_TRANS_QM_DQCLUSTER,       "QM_DQCLUSTER" }, \
+       { XFS_TRANS_QM_QINOCREATE,      "QM_QINOCREATE" }, \
+       { XFS_TRANS_QM_QUOTAOFF_END,    "QM_QOFF_END" }, \
+       { XFS_TRANS_SB_UNIT,            "SB_UNIT" }, \
+       { XFS_TRANS_FSYNC_TS,           "FSYNC_TS" }, \
+       { XFS_TRANS_GROWFSRT_ALLOC,     "GROWFSRT_ALLOC" }, \
+       { XFS_TRANS_GROWFSRT_ZERO,      "GROWFSRT_ZERO" }, \
+       { 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" }
+
+/*
+ * This structure is used to track log items associated with
+ * a transaction.  It points to the log item and keeps some
+ * flags to track the state of the log item.  It also tracks
+ * the amount of space needed to log the item it describes
+ * once we get to commit processing (see xfs_trans_commit()).
+ */
+struct xfs_log_item_desc {
+       struct xfs_log_item     *lid_item;
+       struct list_head        lid_trans;
+       unsigned char           lid_flags;
+};
+
+#define XFS_LID_DIRTY          0x1
+
+/*
+ * Values for t_flags.
+ */
+#define        XFS_TRANS_DIRTY         0x01    /* something needs to be logged */
+#define        XFS_TRANS_SB_DIRTY      0x02    /* superblock is modified */
+#define        XFS_TRANS_PERM_LOG_RES  0x04    /* xact took a permanent log res */
+#define        XFS_TRANS_SYNC          0x08    /* make commit synchronous */
+#define XFS_TRANS_DQ_DIRTY     0x10    /* at least one dquot in trx dirty */
+#define XFS_TRANS_RESERVE      0x20    /* OK to use reserved data blocks */
+#define XFS_TRANS_FREEZE_PROT  0x40    /* Transaction has elevated writer
+                                          count in superblock */
+
+/*
+ * Values for call flags parameter.
+ */
+#define        XFS_TRANS_RELEASE_LOG_RES       0x4
+#define        XFS_TRANS_ABORT                 0x8
+
+/*
+ * Field values for xfs_trans_mod_sb.
+ */
+#define        XFS_TRANS_SB_ICOUNT             0x00000001
+#define        XFS_TRANS_SB_IFREE              0x00000002
+#define        XFS_TRANS_SB_FDBLOCKS           0x00000004
+#define        XFS_TRANS_SB_RES_FDBLOCKS       0x00000008
+#define        XFS_TRANS_SB_FREXTENTS          0x00000010
+#define        XFS_TRANS_SB_RES_FREXTENTS      0x00000020
+#define        XFS_TRANS_SB_DBLOCKS            0x00000040
+#define        XFS_TRANS_SB_AGCOUNT            0x00000080
+#define        XFS_TRANS_SB_IMAXPCT            0x00000100
+#define        XFS_TRANS_SB_REXTSIZE           0x00000200
+#define        XFS_TRANS_SB_RBMBLOCKS          0x00000400
+#define        XFS_TRANS_SB_RBLOCKS            0x00000800
+#define        XFS_TRANS_SB_REXTENTS           0x00001000
+#define        XFS_TRANS_SB_REXTSLOG           0x00002000
+
+/*
+ * Here we centralize the specification of XFS meta-data buffer
+ * reference count values.  This determine how hard the buffer
+ * cache tries to hold onto the buffer.
+ */
+#define        XFS_AGF_REF             4
+#define        XFS_AGI_REF             4
+#define        XFS_AGFL_REF            3
+#define        XFS_INO_BTREE_REF       3
+#define        XFS_ALLOC_BTREE_REF     2
+#define        XFS_BMAP_BTREE_REF      2
+#define        XFS_DIR_BTREE_REF       2
+#define        XFS_INO_REF             2
+#define        XFS_ATTR_BTREE_REF      1
+#define        XFS_DQUOT_REF           1
+
+/*
+ * Flags for xfs_trans_ichgtime().
+ */
+#define        XFS_ICHGTIME_MOD        0x1     /* data fork modification timestamp */
+#define        XFS_ICHGTIME_CHG        0x2     /* inode field change timestamp */
+#define        XFS_ICHGTIME_CREATE     0x4     /* inode create timestamp */
+
+
+/*
+ * Inode Log Item Format definitions.
+ *
+ * This is the structure used to lay out an inode log item in the
+ * log.  The size of the inline data/extents/b-tree root to be logged
+ * (if any) is indicated in the ilf_dsize field.  Changes to this structure
+ * must be added on to the end.
+ */
+typedef struct xfs_inode_log_format {
+       __uint16_t              ilf_type;       /* inode log item type */
+       __uint16_t              ilf_size;       /* size of this item */
+       __uint32_t              ilf_fields;     /* flags for fields logged */
+       __uint16_t              ilf_asize;      /* size of attr d/ext/root */
+       __uint16_t              ilf_dsize;      /* size of data/ext/root */
+       __uint64_t              ilf_ino;        /* inode number */
+       union {
+               __uint32_t      ilfu_rdev;      /* rdev value for dev inode*/
+               uuid_t          ilfu_uuid;      /* mount point value */
+       } ilf_u;
+       __int64_t               ilf_blkno;      /* blkno of inode buffer */
+       __int32_t               ilf_len;        /* len of inode buffer */
+       __int32_t               ilf_boffset;    /* off of inode in buffer */
+} xfs_inode_log_format_t;
+
+typedef struct xfs_inode_log_format_32 {
+       __uint16_t              ilf_type;       /* inode log item type */
+       __uint16_t              ilf_size;       /* size of this item */
+       __uint32_t              ilf_fields;     /* flags for fields logged */
+       __uint16_t              ilf_asize;      /* size of attr d/ext/root */
+       __uint16_t              ilf_dsize;      /* size of data/ext/root */
+       __uint64_t              ilf_ino;        /* inode number */
+       union {
+               __uint32_t      ilfu_rdev;      /* rdev value for dev inode*/
+               uuid_t          ilfu_uuid;      /* mount point value */
+       } ilf_u;
+       __int64_t               ilf_blkno;      /* blkno of inode buffer */
+       __int32_t               ilf_len;        /* len of inode buffer */
+       __int32_t               ilf_boffset;    /* off of inode in buffer */
+} __attribute__((packed)) xfs_inode_log_format_32_t;
+
+typedef struct xfs_inode_log_format_64 {
+       __uint16_t              ilf_type;       /* inode log item type */
+       __uint16_t              ilf_size;       /* size of this item */
+       __uint32_t              ilf_fields;     /* flags for fields logged */
+       __uint16_t              ilf_asize;      /* size of attr d/ext/root */
+       __uint16_t              ilf_dsize;      /* size of data/ext/root */
+       __uint32_t              ilf_pad;        /* pad for 64 bit boundary */
+       __uint64_t              ilf_ino;        /* inode number */
+       union {
+               __uint32_t      ilfu_rdev;      /* rdev value for dev inode*/
+               uuid_t          ilfu_uuid;      /* mount point value */
+       } ilf_u;
+       __int64_t               ilf_blkno;      /* blkno of inode buffer */
+       __int32_t               ilf_len;        /* len of inode buffer */
+       __int32_t               ilf_boffset;    /* off of inode in buffer */
+} xfs_inode_log_format_64_t;
+
+/*
+ * Flags for xfs_trans_log_inode flags field.
+ */
+#define        XFS_ILOG_CORE   0x001   /* log standard inode fields */
+#define        XFS_ILOG_DDATA  0x002   /* log i_df.if_data */
+#define        XFS_ILOG_DEXT   0x004   /* log i_df.if_extents */
+#define        XFS_ILOG_DBROOT 0x008   /* log i_df.i_broot */
+#define        XFS_ILOG_DEV    0x010   /* log the dev field */
+#define        XFS_ILOG_UUID   0x020   /* log the uuid field */
+#define        XFS_ILOG_ADATA  0x040   /* log i_af.if_data */
+#define        XFS_ILOG_AEXT   0x080   /* log i_af.if_extents */
+#define        XFS_ILOG_ABROOT 0x100   /* log i_af.i_broot */
+#define XFS_ILOG_DOWNER        0x200   /* change the data fork owner on replay */
+#define XFS_ILOG_AOWNER        0x400   /* change the attr fork owner on replay */
+
+
+/*
+ * The timestamps are dirty, but not necessarily anything else in the inode
+ * core.  Unlike the other fields above this one must never make it to disk
+ * in the ilf_fields of the inode_log_format, but is purely store in-memory in
+ * ili_fields in the inode_log_item.
+ */
+#define XFS_ILOG_TIMESTAMP     0x4000
+
+#define        XFS_ILOG_NONCORE        (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
+                                XFS_ILOG_DBROOT | XFS_ILOG_DEV | \
+                                XFS_ILOG_UUID | XFS_ILOG_ADATA | \
+                                XFS_ILOG_AEXT | XFS_ILOG_ABROOT | \
+                                XFS_ILOG_DOWNER | XFS_ILOG_AOWNER)
+
+#define        XFS_ILOG_DFORK          (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \
+                                XFS_ILOG_DBROOT)
+
+#define        XFS_ILOG_AFORK          (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
+                                XFS_ILOG_ABROOT)
+
+#define        XFS_ILOG_ALL            (XFS_ILOG_CORE | XFS_ILOG_DDATA | \
+                                XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \
+                                XFS_ILOG_DEV | XFS_ILOG_UUID | \
+                                XFS_ILOG_ADATA | XFS_ILOG_AEXT | \
+                                XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP | \
+                                XFS_ILOG_DOWNER | XFS_ILOG_AOWNER)
+
+static inline int xfs_ilog_fbroot(int w)
+{
+       return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT);
+}
+
+static inline int xfs_ilog_fext(int w)
+{
+       return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT);
+}
+
+static inline int xfs_ilog_fdata(int w)
+{
+       return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA);
+}
+
+/*
+ * Incore version of the on-disk inode core structures. We log this directly
+ * into the journal in host CPU format (for better or worse) and as such
+ * directly mirrors the xfs_dinode structure as it must contain all the same
+ * information.
+ */
+typedef struct xfs_ictimestamp {
+       __int32_t       t_sec;          /* timestamp seconds */
+       __int32_t       t_nsec;         /* timestamp nanoseconds */
+} xfs_ictimestamp_t;
+
+/*
+ * NOTE:  This structure must be kept identical to struct xfs_dinode
+ *       in xfs_dinode.h except for the endianness annotations.
+ */
+typedef struct xfs_icdinode {
+       __uint16_t      di_magic;       /* inode magic # = XFS_DINODE_MAGIC */
+       __uint16_t      di_mode;        /* mode and type of file */
+       __int8_t        di_version;     /* inode version */
+       __int8_t        di_format;      /* format of di_c data */
+       __uint16_t      di_onlink;      /* old number of links to file */
+       __uint32_t      di_uid;         /* owner's user id */
+       __uint32_t      di_gid;         /* owner's group id */
+       __uint32_t      di_nlink;       /* number of links to file */
+       __uint16_t      di_projid_lo;   /* lower part of owner's project id */
+       __uint16_t      di_projid_hi;   /* higher part of owner's project id */
+       __uint8_t       di_pad[6];      /* unused, zeroed space */
+       __uint16_t      di_flushiter;   /* incremented on flush */
+       xfs_ictimestamp_t di_atime;     /* time last accessed */
+       xfs_ictimestamp_t di_mtime;     /* time last modified */
+       xfs_ictimestamp_t di_ctime;     /* time created/inode modified */
+       xfs_fsize_t     di_size;        /* number of bytes in file */
+       xfs_drfsbno_t   di_nblocks;     /* # of direct & btree blocks used */
+       xfs_extlen_t    di_extsize;     /* basic/minimum extent size for file */
+       xfs_extnum_t    di_nextents;    /* number of extents in data fork */
+       xfs_aextnum_t   di_anextents;   /* number of extents in attribute fork*/
+       __uint8_t       di_forkoff;     /* attr fork offs, <<3 for 64b align */
+       __int8_t        di_aformat;     /* format of attr fork's data */
+       __uint32_t      di_dmevmask;    /* DMIG event mask */
+       __uint16_t      di_dmstate;     /* DMIG state info */
+       __uint16_t      di_flags;       /* random flags, XFS_DIFLAG_... */
+       __uint32_t      di_gen;         /* generation number */
+
+       /* di_next_unlinked is the only non-core field in the old dinode */
+       xfs_agino_t     di_next_unlinked;/* agi unlinked list ptr */
+
+       /* start of the extended dinode, writable fields */
+       __uint32_t      di_crc;         /* CRC of the inode */
+       __uint64_t      di_changecount; /* number of attribute changes */
+       xfs_lsn_t       di_lsn;         /* flush sequence */
+       __uint64_t      di_flags2;      /* more random flags */
+       __uint8_t       di_pad2[16];    /* more padding for future expansion */
+
+       /* fields only written to during inode creation */
+       xfs_ictimestamp_t di_crtime;    /* time created */
+       xfs_ino_t       di_ino;         /* inode number */
+       uuid_t          di_uuid;        /* UUID of the filesystem */
+
+       /* structure must be padded to 64 bit alignment */
+} xfs_icdinode_t;
+
+static inline uint xfs_icdinode_size(int version)
+{
+       if (version == 3)
+               return sizeof(struct xfs_icdinode);
+       return offsetof(struct xfs_icdinode, di_next_unlinked);
+}
+
+/*
+ * Buffer Log Format defintions
+ *
+ * These are the physical dirty bitmap defintions for the log format structure.
+ */
+#define        XFS_BLF_CHUNK           128
+#define        XFS_BLF_SHIFT           7
+#define        BIT_TO_WORD_SHIFT       5
+#define        NBWORD                  (NBBY * sizeof(unsigned int))
+
+/*
+ * This flag indicates that the buffer contains on disk inodes
+ * and requires special recovery handling.
+ */
+#define        XFS_BLF_INODE_BUF       (1<<0)
+
+/*
+ * This flag indicates that the buffer should not be replayed
+ * during recovery because its blocks are being freed.
+ */
+#define        XFS_BLF_CANCEL          (1<<1)
+
+/*
+ * This flag indicates that the buffer contains on disk
+ * user or group dquots and may require special recovery handling.
+ */
+#define        XFS_BLF_UDQUOT_BUF      (1<<2)
+#define XFS_BLF_PDQUOT_BUF     (1<<3)
+#define        XFS_BLF_GDQUOT_BUF      (1<<4)
+
+/*
+ * This is the structure used to lay out a buf log item in the
+ * log.  The data map describes which 128 byte chunks of the buffer
+ * have been logged.
+ */
+#define XFS_BLF_DATAMAP_SIZE   ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD)
+
+typedef struct xfs_buf_log_format {
+       unsigned short  blf_type;       /* buf log item type indicator */
+       unsigned short  blf_size;       /* size of this item */
+       ushort          blf_flags;      /* misc state */
+       ushort          blf_len;        /* number of blocks in this buf */
+       __int64_t       blf_blkno;      /* starting blkno of this buf */
+       unsigned int    blf_map_size;   /* used size of data bitmap in words */
+       unsigned int    blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */
+} xfs_buf_log_format_t;
+
+/*
+ * All buffers now need to tell recovery where the magic number
+ * is so that it can verify and calculate the CRCs on the buffer correctly
+ * once the changes have been replayed into the buffer.
+ *
+ * The type value is held in the upper 5 bits of the blf_flags field, which is
+ * an unsigned 16 bit field. Hence we need to shift it 11 bits up and down.
+ */
+#define XFS_BLFT_BITS  5
+#define XFS_BLFT_SHIFT 11
+#define XFS_BLFT_MASK  (((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT)
+
+enum xfs_blft {
+       XFS_BLFT_UNKNOWN_BUF = 0,
+       XFS_BLFT_UDQUOT_BUF,
+       XFS_BLFT_PDQUOT_BUF,
+       XFS_BLFT_GDQUOT_BUF,
+       XFS_BLFT_BTREE_BUF,
+       XFS_BLFT_AGF_BUF,
+       XFS_BLFT_AGFL_BUF,
+       XFS_BLFT_AGI_BUF,
+       XFS_BLFT_DINO_BUF,
+       XFS_BLFT_SYMLINK_BUF,
+       XFS_BLFT_DIR_BLOCK_BUF,
+       XFS_BLFT_DIR_DATA_BUF,
+       XFS_BLFT_DIR_FREE_BUF,
+       XFS_BLFT_DIR_LEAF1_BUF,
+       XFS_BLFT_DIR_LEAFN_BUF,
+       XFS_BLFT_DA_NODE_BUF,
+       XFS_BLFT_ATTR_LEAF_BUF,
+       XFS_BLFT_ATTR_RMT_BUF,
+       XFS_BLFT_SB_BUF,
+       XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS),
+};
+
+static inline void
+xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type)
+{
+       ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF);
+       blf->blf_flags &= ~XFS_BLFT_MASK;
+       blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK);
+}
+
+static inline __uint16_t
+xfs_blft_from_flags(struct xfs_buf_log_format *blf)
+{
+       return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT;
+}
+
+/*
+ * EFI/EFD log format definitions
+ */
+typedef struct xfs_extent {
+       xfs_dfsbno_t    ext_start;
+       xfs_extlen_t    ext_len;
+} xfs_extent_t;
+
+/*
+ * Since an xfs_extent_t has types (start:64, len: 32)
+ * there are different alignments on 32 bit and 64 bit kernels.
+ * So we provide the different variants for use by a
+ * conversion routine.
+ */
+typedef struct xfs_extent_32 {
+       __uint64_t      ext_start;
+       __uint32_t      ext_len;
+} __attribute__((packed)) xfs_extent_32_t;
+
+typedef struct xfs_extent_64 {
+       __uint64_t      ext_start;
+       __uint32_t      ext_len;
+       __uint32_t      ext_pad;
+} xfs_extent_64_t;
+
+/*
+ * This is the structure used to lay out an efi log item in the
+ * log.  The efi_extents field is a variable size array whose
+ * size is given by efi_nextents.
+ */
+typedef struct xfs_efi_log_format {
+       __uint16_t              efi_type;       /* efi log item type */
+       __uint16_t              efi_size;       /* size of this item */
+       __uint32_t              efi_nextents;   /* # extents to free */
+       __uint64_t              efi_id;         /* efi identifier */
+       xfs_extent_t            efi_extents[1]; /* array of extents to free */
+} xfs_efi_log_format_t;
+
+typedef struct xfs_efi_log_format_32 {
+       __uint16_t              efi_type;       /* efi log item type */
+       __uint16_t              efi_size;       /* size of this item */
+       __uint32_t              efi_nextents;   /* # extents to free */
+       __uint64_t              efi_id;         /* efi identifier */
+       xfs_extent_32_t         efi_extents[1]; /* array of extents to free */
+} __attribute__((packed)) xfs_efi_log_format_32_t;
+
+typedef struct xfs_efi_log_format_64 {
+       __uint16_t              efi_type;       /* efi log item type */
+       __uint16_t              efi_size;       /* size of this item */
+       __uint32_t              efi_nextents;   /* # extents to free */
+       __uint64_t              efi_id;         /* efi identifier */
+       xfs_extent_64_t         efi_extents[1]; /* array of extents to free */
+} xfs_efi_log_format_64_t;
+
+/*
+ * This is the structure used to lay out an efd log item in the
+ * log.  The efd_extents array is a variable size array whose
+ * size is given by efd_nextents;
+ */
+typedef struct xfs_efd_log_format {
+       __uint16_t              efd_type;       /* efd log item type */
+       __uint16_t              efd_size;       /* size of this item */
+       __uint32_t              efd_nextents;   /* # of extents freed */
+       __uint64_t              efd_efi_id;     /* id of corresponding efi */
+       xfs_extent_t            efd_extents[1]; /* array of extents freed */
+} xfs_efd_log_format_t;
+
+typedef struct xfs_efd_log_format_32 {
+       __uint16_t              efd_type;       /* efd log item type */
+       __uint16_t              efd_size;       /* size of this item */
+       __uint32_t              efd_nextents;   /* # of extents freed */
+       __uint64_t              efd_efi_id;     /* id of corresponding efi */
+       xfs_extent_32_t         efd_extents[1]; /* array of extents freed */
+} __attribute__((packed)) xfs_efd_log_format_32_t;
+
+typedef struct xfs_efd_log_format_64 {
+       __uint16_t              efd_type;       /* efd log item type */
+       __uint16_t              efd_size;       /* size of this item */
+       __uint32_t              efd_nextents;   /* # of extents freed */
+       __uint64_t              efd_efi_id;     /* id of corresponding efi */
+       xfs_extent_64_t         efd_extents[1]; /* array of extents freed */
+} xfs_efd_log_format_64_t;
+
+/*
+ * Dquot Log format definitions.
+ *
+ * The first two fields must be the type and size fitting into
+ * 32 bits : log_recovery code assumes that.
+ */
+typedef struct xfs_dq_logformat {
+       __uint16_t              qlf_type;      /* dquot log item type */
+       __uint16_t              qlf_size;      /* size of this item */
+       xfs_dqid_t              qlf_id;        /* usr/grp/proj id : 32 bits */
+       __int64_t               qlf_blkno;     /* blkno of dquot buffer */
+       __int32_t               qlf_len;       /* len of dquot buffer */
+       __uint32_t              qlf_boffset;   /* off of dquot in buffer */
+} xfs_dq_logformat_t;
+
+/*
+ * log format struct for QUOTAOFF records.
+ * The first two fields must be the type and size fitting into
+ * 32 bits : log_recovery code assumes that.
+ * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
+ * to the first and ensures that the first logitem is taken out of the AIL
+ * only when the last one is securely committed.
+ */
+typedef struct xfs_qoff_logformat {
+       unsigned short          qf_type;        /* quotaoff log item type */
+       unsigned short          qf_size;        /* size of this item */
+       unsigned int            qf_flags;       /* USR and/or GRP */
+       char                    qf_pad[12];     /* padding for future */
+} xfs_qoff_logformat_t;
+
+
+/*
+ * Disk quotas status in m_qflags, and also sb_qflags. 16 bits.
+ */
+#define XFS_UQUOTA_ACCT        0x0001  /* user quota accounting ON */
+#define XFS_UQUOTA_ENFD        0x0002  /* user quota limits enforced */
+#define XFS_UQUOTA_CHKD        0x0004  /* quotacheck run on usr quotas */
+#define XFS_PQUOTA_ACCT        0x0008  /* project quota accounting ON */
+#define XFS_OQUOTA_ENFD        0x0010  /* other (grp/prj) quota limits enforced */
+#define XFS_OQUOTA_CHKD        0x0020  /* quotacheck run on other (grp/prj) quotas */
+#define XFS_GQUOTA_ACCT        0x0040  /* group quota accounting ON */
+
+/*
+ * Conversion to and from the combined OQUOTA flag (if necessary)
+ * is done only in xfs_sb_qflags_to_disk() and xfs_sb_qflags_from_disk()
+ */
+#define XFS_GQUOTA_ENFD        0x0080  /* group quota limits enforced */
+#define XFS_GQUOTA_CHKD        0x0100  /* quotacheck run on group quotas */
+#define XFS_PQUOTA_ENFD        0x0200  /* project quota limits enforced */
+#define XFS_PQUOTA_CHKD        0x0400  /* quotacheck run on project quotas */
+
+#define XFS_ALL_QUOTA_ACCT     \
+               (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
+#define XFS_ALL_QUOTA_ENFD     \
+               (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD)
+#define XFS_ALL_QUOTA_CHKD     \
+               (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD)
+
+#define XFS_MOUNT_QUOTA_ALL    (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
+                                XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
+                                XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\
+                                XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD|\
+                                XFS_PQUOTA_CHKD)
+
+/*
+ * Inode create log item structure
+ *
+ * Log recovery assumes the first two entries are the type and size and they fit
+ * in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so
+ * decoding can be done correctly.
+ */
+struct xfs_icreate_log {
+       __uint16_t      icl_type;       /* type of log format structure */
+       __uint16_t      icl_size;       /* size of log format structure */
+       __be32          icl_ag;         /* ag being allocated in */
+       __be32          icl_agbno;      /* start block of inode range */
+       __be32          icl_count;      /* number of inodes to initialise */
+       __be32          icl_isize;      /* size of inodes */
+       __be32          icl_length;     /* length of extent to initialise */
+       __be32          icl_gen;        /* inode generation number to use */
+};
+
+int    xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes);
+int    xfs_log_calc_minimum_size(struct xfs_mount *);
+
+
+#endif /* __XFS_LOG_FORMAT_H__ */
index b9ea262dd1c2c7575fee738fba6e71575180924a..136654b9400df9b28a40415b1fbca3c9b7d6a958 100644 (file)
@@ -24,51 +24,13 @@ struct xlog_ticket;
 struct xfs_mount;
 
 /*
- * Macros, structures, prototypes for internal log manager use.
+ * Flags for log structure
  */
-
-#define XLOG_MIN_ICLOGS                2
-#define XLOG_MAX_ICLOGS                8
-#define XLOG_HEADER_MAGIC_NUM  0xFEEDbabe      /* Invalid cycle number */
-#define XLOG_VERSION_1         1
-#define XLOG_VERSION_2         2               /* Large IClogs, Log sunit */
-#define XLOG_VERSION_OKBITS    (XLOG_VERSION_1 | XLOG_VERSION_2)
-#define XLOG_MIN_RECORD_BSIZE  (16*1024)       /* eventually 32k */
-#define XLOG_BIG_RECORD_BSIZE  (32*1024)       /* 32k buffers */
-#define XLOG_MAX_RECORD_BSIZE  (256*1024)
-#define XLOG_HEADER_CYCLE_SIZE (32*1024)       /* cycle data in header */
-#define XLOG_MIN_RECORD_BSHIFT 14              /* 16384 == 1 << 14 */
-#define XLOG_BIG_RECORD_BSHIFT 15              /* 32k == 1 << 15 */
-#define XLOG_MAX_RECORD_BSHIFT 18              /* 256k == 1 << 18 */
-#define XLOG_BTOLSUNIT(log, b)  (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \
-                                 (log)->l_mp->m_sb.sb_logsunit)
-#define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit)
-
-#define XLOG_HEADER_SIZE       512
-
-#define XLOG_REC_SHIFT(log) \
-       BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \
-        XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
-#define XLOG_TOTAL_REC_SHIFT(log) \
-       BTOBB(XLOG_MAX_ICLOGS << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \
-        XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
-
-static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block)
-{
-       return ((xfs_lsn_t)cycle << 32) | block;
-}
-
-static inline uint xlog_get_cycle(char *ptr)
-{
-       if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM)
-               return be32_to_cpu(*((__be32 *)ptr + 1));
-       else
-               return be32_to_cpu(*(__be32 *)ptr);
-}
-
-#define BLK_AVG(blk1, blk2)    ((blk1+blk2) >> 1)
-
-#ifdef __KERNEL__
+#define XLOG_ACTIVE_RECOVERY   0x2     /* in the middle of recovery */
+#define        XLOG_RECOVERY_NEEDED    0x4     /* log was recovered */
+#define XLOG_IO_ERROR          0x8     /* log hit an I/O error, and being
+                                          shutdown */
+#define XLOG_TAIL_WARN         0x10    /* log tail verify warning issued */
 
 /*
  * get client id from packed copy.
@@ -101,27 +63,7 @@ static inline uint xlog_get_client_id(__be32 i)
 #define XLOG_STATE_IOERROR   0x0080 /* IO error happened in sync'ing log */
 #define XLOG_STATE_ALL      0x7FFF /* All possible valid flags */
 #define XLOG_STATE_NOTUSED   0x8000 /* This IC log not being used */
-#endif /* __KERNEL__ */
 
-/*
- * Flags to log operation header
- *
- * The first write of a new transaction will be preceded with a start
- * record, XLOG_START_TRANS.  Once a transaction is committed, a commit
- * record is written, XLOG_COMMIT_TRANS.  If a single region can not fit into
- * the remainder of the current active in-core log, it is split up into
- * multiple regions.  Each partial region will be marked with a
- * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS.
- *
- */
-#define XLOG_START_TRANS       0x01    /* Start a new transaction */
-#define XLOG_COMMIT_TRANS      0x02    /* Commit this transaction */
-#define XLOG_CONTINUE_TRANS    0x04    /* Cont this trans into new region */
-#define XLOG_WAS_CONT_TRANS    0x08    /* Cont this trans into new region */
-#define XLOG_END_TRANS         0x10    /* End a continued transaction */
-#define XLOG_UNMOUNT_TRANS     0x20    /* Unmount a filesystem transaction */
-
-#ifdef __KERNEL__
 /*
  * Flags to log ticket
  */
@@ -132,22 +74,6 @@ static inline uint xlog_get_client_id(__be32 i)
        { XLOG_TIC_INITED,      "XLOG_TIC_INITED" }, \
        { XLOG_TIC_PERM_RESERV, "XLOG_TIC_PERM_RESERV" }
 
-#endif /* __KERNEL__ */
-
-#define XLOG_UNMOUNT_TYPE      0x556e  /* Un for Unmount */
-
-/*
- * Flags for log structure
- */
-#define XLOG_ACTIVE_RECOVERY   0x2     /* in the middle of recovery */
-#define        XLOG_RECOVERY_NEEDED    0x4     /* log was recovered */
-#define XLOG_IO_ERROR          0x8     /* log hit an I/O error, and being
-                                          shutdown */
-#define XLOG_TAIL_WARN         0x10    /* log tail verify warning issued */
-
-typedef __uint32_t xlog_tid_t;
-
-#ifdef __KERNEL__
 /*
  * Below are states for covering allocation transactions.
  * By covering, we mean changing the h_tail_lsn in the last on-disk
@@ -223,7 +149,6 @@ typedef __uint32_t xlog_tid_t;
 
 #define XLOG_COVER_OPS         5
 
-
 /* Ticket reservation region accounting */ 
 #define XLOG_TIC_LEN_MAX       15
 
@@ -258,64 +183,6 @@ typedef struct xlog_ticket {
        xlog_res_t         t_res_arr[XLOG_TIC_LEN_MAX];  /* array of res : 8 * 15 */ 
 } xlog_ticket_t;
 
-#endif
-
-
-typedef struct xlog_op_header {
-       __be32     oh_tid;      /* transaction id of operation  :  4 b */
-       __be32     oh_len;      /* bytes in data region         :  4 b */
-       __u8       oh_clientid; /* who sent me this             :  1 b */
-       __u8       oh_flags;    /*                              :  1 b */
-       __u16      oh_res2;     /* 32 bit align                 :  2 b */
-} xlog_op_header_t;
-
-
-/* valid values for h_fmt */
-#define XLOG_FMT_UNKNOWN  0
-#define XLOG_FMT_LINUX_LE 1
-#define XLOG_FMT_LINUX_BE 2
-#define XLOG_FMT_IRIX_BE  3
-
-/* our fmt */
-#ifdef XFS_NATIVE_HOST
-#define XLOG_FMT XLOG_FMT_LINUX_BE
-#else
-#define XLOG_FMT XLOG_FMT_LINUX_LE
-#endif
-
-typedef struct xlog_rec_header {
-       __be32    h_magicno;    /* log record (LR) identifier           :  4 */
-       __be32    h_cycle;      /* write cycle of log                   :  4 */
-       __be32    h_version;    /* LR version                           :  4 */
-       __be32    h_len;        /* len in bytes; should be 64-bit aligned: 4 */
-       __be64    h_lsn;        /* lsn of this LR                       :  8 */
-       __be64    h_tail_lsn;   /* lsn of 1st LR w/ buffers not committed: 8 */
-       __le32    h_crc;        /* crc of log record                    :  4 */
-       __be32    h_prev_block; /* block number to previous LR          :  4 */
-       __be32    h_num_logops; /* number of log operations in this LR  :  4 */
-       __be32    h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE];
-       /* new fields */
-       __be32    h_fmt;        /* format of log record                 :  4 */
-       uuid_t    h_fs_uuid;    /* uuid of FS                           : 16 */
-       __be32    h_size;       /* iclog size                           :  4 */
-} xlog_rec_header_t;
-
-typedef struct xlog_rec_ext_header {
-       __be32    xh_cycle;     /* write cycle of log                   : 4 */
-       __be32    xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /*    : 256 */
-} xlog_rec_ext_header_t;
-
-#ifdef __KERNEL__
-
-/*
- * Quite misnamed, because this union lays out the actual on-disk log buffer.
- */
-typedef union xlog_in_core2 {
-       xlog_rec_header_t       hic_header;
-       xlog_rec_ext_header_t   hic_xheader;
-       char                    hic_sector[XLOG_HEADER_SIZE];
-} xlog_in_core_2_t;
-
 /*
  * - A log record header is 512 bytes.  There is plenty of room to grow the
  *     xlog_rec_header_t into the reserved space.
@@ -411,14 +278,17 @@ struct xfs_cil {
        struct xlog             *xc_log;
        struct list_head        xc_cil;
        spinlock_t              xc_cil_lock;
+
+       struct rw_semaphore     xc_ctx_lock ____cacheline_aligned_in_smp;
        struct xfs_cil_ctx      *xc_ctx;
-       struct rw_semaphore     xc_ctx_lock;
+
+       spinlock_t              xc_push_lock ____cacheline_aligned_in_smp;
+       xfs_lsn_t               xc_push_seq;
        struct list_head        xc_committing;
        wait_queue_head_t       xc_commit_wait;
        xfs_lsn_t               xc_current_sequence;
        struct work_struct      xc_push_work;
-       xfs_lsn_t               xc_push_seq;
-};
+} ____cacheline_aligned_in_smp;
 
 /*
  * The amount of log space we allow the CIL to aggregate is difficult to size.
@@ -686,6 +556,5 @@ static inline void xlog_wait(wait_queue_head_t *wq, spinlock_t *lock)
        schedule();
        remove_wait_queue(wq, &wait);
 }
-#endif /* __KERNEL__ */
 
 #endif /* __XFS_LOG_PRIV_H__ */
index 7681b19aa5dc565a9807005ff3f1d6428a22f016..dabda9521b4becc2ded846307aa062a093a7a3d3 100644 (file)
@@ -17,7 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
@@ -41,7 +41,6 @@
 #include "xfs_extfree_item.h"
 #include "xfs_trans_priv.h"
 #include "xfs_quota.h"
-#include "xfs_utils.h"
 #include "xfs_cksum.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_symlink.h"
 #include "xfs_da_btree.h"
 #include "xfs_dir2_format.h"
-#include "xfs_dir2_priv.h"
+#include "xfs_dir2.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_attr_remote.h"
 
+#define BLK_AVG(blk1, blk2)    ((blk1+blk2) >> 1)
+
 STATIC int
 xlog_find_zeroed(
        struct xlog     *,
@@ -607,7 +608,7 @@ out:
 
 /*
  * Head is defined to be the point of the log where the next log write
- * write could go.  This means that incomplete LR writes at the end are
+ * could go.  This means that incomplete LR writes at the end are
  * eliminated when calculating the head.  We aren't guaranteed that previous
  * LR have complete transactions.  We only know that a cycle number of
  * current cycle number -1 won't be present in the log if we start writing
@@ -963,6 +964,7 @@ xlog_find_tail(
        }
        if (!found) {
                xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__);
+               xlog_put_bp(bp);
                ASSERT(0);
                return XFS_ERROR(EIO);
        }
@@ -1144,7 +1146,8 @@ xlog_find_zeroed(
                 */
                xfs_warn(log->l_mp,
                        "Log inconsistent or not a log (last==0, first!=1)");
-               return XFS_ERROR(EINVAL);
+               error = XFS_ERROR(EINVAL);
+               goto bp_err;
        }
 
        /* we have a partially zeroed log */
@@ -1766,19 +1769,11 @@ xlog_recover_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_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.
- *
- * We remove the cancel record from the table when we encounter its
- * last occurrence in the log so that if the same buffer is re-used
- * again after its last cancellation we actually replay the changes
- * made at that point.
+ * entry in the buffer cancel record table. If it is, return the cancel
+ * buffer structure to the caller.
  */
-STATIC int
-xlog_check_buffer_cancelled(
+STATIC struct xfs_buf_cancel *
+xlog_peek_buffer_cancelled(
        struct xlog             *log,
        xfs_daddr_t             blkno,
        uint                    len,
@@ -1787,22 +1782,16 @@ xlog_check_buffer_cancelled(
        struct list_head        *bucket;
        struct xfs_buf_cancel   *bcp;
 
-       if (log->l_buf_cancel_table == NULL) {
-               /*
-                * There is nothing in the table built in pass one,
-                * so this buffer must not be cancelled.
-                */
+       if (!log->l_buf_cancel_table) {
+               /* empty table means no cancelled buffers in the log */
                ASSERT(!(flags & XFS_BLF_CANCEL));
-               return 0;
+               return NULL;
        }
 
-       /*
-        * Search for an entry in the  cancel table that matches our buffer.
-        */
        bucket = XLOG_BUF_CANCEL_BUCKET(log, blkno);
        list_for_each_entry(bcp, bucket, bc_list) {
                if (bcp->bc_blkno == blkno && bcp->bc_len == len)
-                       goto found;
+                       return bcp;
        }
 
        /*
@@ -1810,9 +1799,32 @@ xlog_check_buffer_cancelled(
         * that the buffer is NOT cancelled.
         */
        ASSERT(!(flags & XFS_BLF_CANCEL));
-       return 0;
+       return NULL;
+}
+
+/*
+ * If the buffer is being cancelled then return 1 so that it will be cancelled,
+ * otherwise return 0.  If the buffer is 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.
+ *
+ * We remove the cancel record from the table when we encounter its last
+ * occurrence in the log so that if the same buffer is re-used again after its
+ * last cancellation we actually replay the changes made at that point.
+ */
+STATIC int
+xlog_check_buffer_cancelled(
+       struct xlog             *log,
+       xfs_daddr_t             blkno,
+       uint                    len,
+       ushort                  flags)
+{
+       struct xfs_buf_cancel   *bcp;
+
+       bcp = xlog_peek_buffer_cancelled(log, blkno, len, flags);
+       if (!bcp)
+               return 0;
 
-found:
        /*
         * We've go a match, so return 1 so that the recovery of this buffer
         * is cancelled.  If this buffer is actually a buffer cancel log
@@ -1946,6 +1958,104 @@ xlog_recover_do_inode_buffer(
        return 0;
 }
 
+/*
+ * V5 filesystems know the age of the buffer on disk being recovered. We can
+ * have newer objects on disk than we are replaying, and so for these cases we
+ * don't want to replay the current change as that will make the buffer contents
+ * temporarily invalid on disk.
+ *
+ * The magic number might not match the buffer type we are going to recover
+ * (e.g. reallocated blocks), so we ignore the xfs_buf_log_format flags.  Hence
+ * extract the LSN of the existing object in the buffer based on it's current
+ * magic number.  If we don't recognise the magic number in the buffer, then
+ * return a LSN of -1 so that the caller knows it was an unrecognised block and
+ * so can recover the buffer.
+ */
+static xfs_lsn_t
+xlog_recover_get_buf_lsn(
+       struct xfs_mount        *mp,
+       struct xfs_buf          *bp)
+{
+       __uint32_t              magic32;
+       __uint16_t              magic16;
+       __uint16_t              magicda;
+       void                    *blk = bp->b_addr;
+
+       /* v4 filesystems always recover immediately */
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               goto recover_immediately;
+
+       magic32 = be32_to_cpu(*(__be32 *)blk);
+       switch (magic32) {
+       case XFS_ABTB_CRC_MAGIC:
+       case XFS_ABTC_CRC_MAGIC:
+       case XFS_ABTB_MAGIC:
+       case XFS_ABTC_MAGIC:
+       case XFS_IBT_CRC_MAGIC:
+       case XFS_IBT_MAGIC:
+               return be64_to_cpu(
+                               ((struct xfs_btree_block *)blk)->bb_u.s.bb_lsn);
+       case XFS_BMAP_CRC_MAGIC:
+       case XFS_BMAP_MAGIC:
+               return be64_to_cpu(
+                               ((struct xfs_btree_block *)blk)->bb_u.l.bb_lsn);
+       case XFS_AGF_MAGIC:
+               return be64_to_cpu(((struct xfs_agf *)blk)->agf_lsn);
+       case XFS_AGFL_MAGIC:
+               return be64_to_cpu(((struct xfs_agfl *)blk)->agfl_lsn);
+       case XFS_AGI_MAGIC:
+               return be64_to_cpu(((struct xfs_agi *)blk)->agi_lsn);
+       case XFS_SYMLINK_MAGIC:
+               return be64_to_cpu(((struct xfs_dsymlink_hdr *)blk)->sl_lsn);
+       case XFS_DIR3_BLOCK_MAGIC:
+       case XFS_DIR3_DATA_MAGIC:
+       case XFS_DIR3_FREE_MAGIC:
+               return be64_to_cpu(((struct xfs_dir3_blk_hdr *)blk)->lsn);
+       case XFS_ATTR3_RMT_MAGIC:
+               return be64_to_cpu(((struct xfs_attr3_rmt_hdr *)blk)->rm_lsn);
+       case XFS_SB_MAGIC:
+               return be64_to_cpu(((struct xfs_dsb *)blk)->sb_lsn);
+       default:
+               break;
+       }
+
+       magicda = be16_to_cpu(((struct xfs_da_blkinfo *)blk)->magic);
+       switch (magicda) {
+       case XFS_DIR3_LEAF1_MAGIC:
+       case XFS_DIR3_LEAFN_MAGIC:
+       case XFS_DA3_NODE_MAGIC:
+               return be64_to_cpu(((struct xfs_da3_blkinfo *)blk)->lsn);
+       default:
+               break;
+       }
+
+       /*
+        * We do individual object checks on dquot and inode buffers as they
+        * have their own individual LSN records. Also, we could have a stale
+        * buffer here, so we have to at least recognise these buffer types.
+        *
+        * A notd complexity here is inode unlinked list processing - it logs
+        * the inode directly in the buffer, but we don't know which inodes have
+        * been modified, and there is no global buffer LSN. Hence we need to
+        * recover all inode buffer types immediately. This problem will be
+        * fixed by logical logging of the unlinked list modifications.
+        */
+       magic16 = be16_to_cpu(*(__be16 *)blk);
+       switch (magic16) {
+       case XFS_DQUOT_MAGIC:
+       case XFS_DINODE_MAGIC:
+               goto recover_immediately;
+       default:
+               break;
+       }
+
+       /* unknown buffer contents, recover immediately */
+
+recover_immediately:
+       return (xfs_lsn_t)-1;
+
+}
+
 /*
  * Validate the recovered buffer is of the correct type and attach the
  * appropriate buffer operations to them for writeback. Magic numbers are in a
@@ -1955,7 +2065,7 @@ xlog_recover_do_inode_buffer(
  *     inside a struct xfs_da_blkinfo at the start of the buffer.
  */
 static void
-xlog_recovery_validate_buf_type(
+xlog_recover_validate_buf_type(
        struct xfs_mount        *mp,
        struct xfs_buf          *bp,
        xfs_buf_log_format_t    *buf_f)
@@ -2234,7 +2344,7 @@ xlog_recover_do_reg_buffer(
         * just avoid the verification stage for non-crc filesystems
         */
        if (xfs_sb_version_hascrc(&mp->m_sb))
-               xlog_recovery_validate_buf_type(mp, bp, buf_f);
+               xlog_recover_validate_buf_type(mp, bp, buf_f);
 }
 
 /*
@@ -2366,7 +2476,7 @@ xfs_qm_dqcheck(
 
 /*
  * Perform a dquot buffer recovery.
- * Simple algorithm: if we have found a QUOTAOFF logitem of the same type
+ * Simple algorithm: if we have found a QUOTAOFF log item of the same type
  * (ie. USR or GRP), then just toss this buffer away; don't recover it.
  * Else, treat it as a regular buffer and do recovery.
  */
@@ -2425,20 +2535,22 @@ xlog_recover_do_dquot_buffer(
  * over the log during recovery.  During the first we build a table of
  * those buffers which have been cancelled, and during the second we
  * only replay those buffers which do not have corresponding cancel
- * records in the table.  See xlog_recover_do_buffer_pass[1,2] above
+ * records in the table.  See xlog_recover_buffer_pass[1,2] above
  * for more details on the implementation of the table of cancel records.
  */
 STATIC int
 xlog_recover_buffer_pass2(
        struct xlog                     *log,
        struct list_head                *buffer_list,
-       struct xlog_recover_item        *item)
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       current_lsn)
 {
        xfs_buf_log_format_t    *buf_f = item->ri_buf[0].i_addr;
        xfs_mount_t             *mp = log->l_mp;
        xfs_buf_t               *bp;
        int                     error;
        uint                    buf_flags;
+       xfs_lsn_t               lsn;
 
        /*
         * In this pass we only want to recover all the buffers which have
@@ -2463,10 +2575,17 @@ xlog_recover_buffer_pass2(
        error = bp->b_error;
        if (error) {
                xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#1)");
-               xfs_buf_relse(bp);
-               return error;
+               goto out_release;
        }
 
+       /*
+        * recover the buffer only if we get an LSN from it and it's less than
+        * the lsn of the transaction we are replaying.
+        */
+       lsn = xlog_recover_get_buf_lsn(mp, bp);
+       if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0)
+               goto out_release;
+
        if (buf_f->blf_flags & XFS_BLF_INODE_BUF) {
                error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f);
        } else if (buf_f->blf_flags &
@@ -2476,7 +2595,7 @@ xlog_recover_buffer_pass2(
                xlog_recover_do_reg_buffer(mp, item, bp, buf_f);
        }
        if (error)
-               return XFS_ERROR(error);
+               goto out_release;
 
        /*
         * Perform delayed write on the buffer.  Asynchronous writes will be
@@ -2505,15 +2624,93 @@ xlog_recover_buffer_pass2(
                xfs_buf_delwri_queue(bp, buffer_list);
        }
 
+out_release:
        xfs_buf_relse(bp);
        return error;
 }
 
+/*
+ * Inode fork owner changes
+ *
+ * If we have been told that we have to reparent the inode fork, it's because an
+ * extent swap operation on a CRC enabled filesystem has been done and we are
+ * replaying it. We need to walk the BMBT of the appropriate fork and change the
+ * owners of it.
+ *
+ * The complexity here is that we don't have an inode context to work with, so
+ * after we've replayed the inode we need to instantiate one.  This is where the
+ * fun begins.
+ *
+ * We are in the middle of log recovery, so we can't run transactions. That
+ * means we cannot use cache coherent inode instantiation via xfs_iget(), as
+ * that will result in the corresponding iput() running the inode through
+ * xfs_inactive(). If we've just replayed an inode core that changes the link
+ * count to zero (i.e. it's been unlinked), then xfs_inactive() will run
+ * transactions (bad!).
+ *
+ * So, to avoid this, we instantiate an inode directly from the inode core we've
+ * just recovered. We have the buffer still locked, and all we really need to
+ * instantiate is the inode core and the forks being modified. We can do this
+ * manually, then run the inode btree owner change, and then tear down the
+ * xfs_inode without having to run any transactions at all.
+ *
+ * Also, because we don't have a transaction context available here but need to
+ * gather all the buffers we modify for writeback so we pass the buffer_list
+ * instead for the operation to use.
+ */
+
+STATIC int
+xfs_recover_inode_owner_change(
+       struct xfs_mount        *mp,
+       struct xfs_dinode       *dip,
+       struct xfs_inode_log_format *in_f,
+       struct list_head        *buffer_list)
+{
+       struct xfs_inode        *ip;
+       int                     error;
+
+       ASSERT(in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER));
+
+       ip = xfs_inode_alloc(mp, in_f->ilf_ino);
+       if (!ip)
+               return ENOMEM;
+
+       /* instantiate the inode */
+       xfs_dinode_from_disk(&ip->i_d, dip);
+       ASSERT(ip->i_d.di_version >= 3);
+
+       error = xfs_iformat_fork(ip, dip);
+       if (error)
+               goto out_free_ip;
+
+
+       if (in_f->ilf_fields & XFS_ILOG_DOWNER) {
+               ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT);
+               error = xfs_bmbt_change_owner(NULL, ip, XFS_DATA_FORK,
+                                             ip->i_ino, buffer_list);
+               if (error)
+                       goto out_free_ip;
+       }
+
+       if (in_f->ilf_fields & XFS_ILOG_AOWNER) {
+               ASSERT(in_f->ilf_fields & XFS_ILOG_ABROOT);
+               error = xfs_bmbt_change_owner(NULL, ip, XFS_ATTR_FORK,
+                                             ip->i_ino, buffer_list);
+               if (error)
+                       goto out_free_ip;
+       }
+
+out_free_ip:
+       xfs_inode_free(ip);
+       return error;
+}
+
 STATIC int
 xlog_recover_inode_pass2(
        struct xlog                     *log,
        struct list_head                *buffer_list,
-       struct xlog_recover_item        *item)
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       current_lsn)
 {
        xfs_inode_log_format_t  *in_f;
        xfs_mount_t             *mp = log->l_mp;
@@ -2560,8 +2757,7 @@ xlog_recover_inode_pass2(
        error = bp->b_error;
        if (error) {
                xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#2)");
-               xfs_buf_relse(bp);
-               goto error;
+               goto out_release;
        }
        ASSERT(in_f->ilf_fields & XFS_ILOG_CORE);
        dip = (xfs_dinode_t *)xfs_buf_offset(bp, in_f->ilf_boffset);
@@ -2571,25 +2767,40 @@ xlog_recover_inode_pass2(
         * like an inode!
         */
        if (unlikely(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))) {
-               xfs_buf_relse(bp);
                xfs_alert(mp,
        "%s: Bad inode magic number, dip = 0x%p, dino bp = 0x%p, ino = %Ld",
                        __func__, dip, bp, in_f->ilf_ino);
                XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)",
                                 XFS_ERRLEVEL_LOW, mp);
                error = EFSCORRUPTED;
-               goto error;
+               goto out_release;
        }
        dicp = item->ri_buf[1].i_addr;
        if (unlikely(dicp->di_magic != XFS_DINODE_MAGIC)) {
-               xfs_buf_relse(bp);
                xfs_alert(mp,
                        "%s: Bad inode log record, rec ptr 0x%p, ino %Ld",
                        __func__, item, in_f->ilf_ino);
                XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)",
                                 XFS_ERRLEVEL_LOW, mp);
                error = EFSCORRUPTED;
-               goto error;
+               goto out_release;
+       }
+
+       /*
+        * If the inode has an LSN in it, recover the inode only if it's less
+        * than the lsn of the transaction we are replaying. Note: we still
+        * need to replay an owner change even though the inode is more recent
+        * than the transaction as there is no guarantee that all the btree
+        * blocks are more recent than this transaction, too.
+        */
+       if (dip->di_version >= 3) {
+               xfs_lsn_t       lsn = be64_to_cpu(dip->di_lsn);
+
+               if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
+                       trace_xfs_log_recover_inode_skip(log, in_f);
+                       error = 0;
+                       goto out_owner_change;
+               }
        }
 
        /*
@@ -2610,10 +2821,9 @@ xlog_recover_inode_pass2(
                    dicp->di_flushiter < (DI_MAX_FLUSH >> 1)) {
                        /* do nothing */
                } else {
-                       xfs_buf_relse(bp);
                        trace_xfs_log_recover_inode_skip(log, in_f);
                        error = 0;
-                       goto error;
+                       goto out_release;
                }
        }
 
@@ -2625,13 +2835,12 @@ xlog_recover_inode_pass2(
                    (dicp->di_format != XFS_DINODE_FMT_BTREE)) {
                        XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)",
                                         XFS_ERRLEVEL_LOW, mp, dicp);
-                       xfs_buf_relse(bp);
                        xfs_alert(mp,
                "%s: Bad regular inode log record, rec ptr 0x%p, "
                "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                                __func__, item, dip, bp, in_f->ilf_ino);
                        error = EFSCORRUPTED;
-                       goto error;
+                       goto out_release;
                }
        } else if (unlikely(S_ISDIR(dicp->di_mode))) {
                if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) &&
@@ -2639,19 +2848,17 @@ xlog_recover_inode_pass2(
                    (dicp->di_format != XFS_DINODE_FMT_LOCAL)) {
                        XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)",
                                             XFS_ERRLEVEL_LOW, mp, dicp);
-                       xfs_buf_relse(bp);
                        xfs_alert(mp,
                "%s: Bad dir inode log record, rec ptr 0x%p, "
                "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld",
                                __func__, item, dip, bp, in_f->ilf_ino);
                        error = EFSCORRUPTED;
-                       goto error;
+                       goto out_release;
                }
        }
        if (unlikely(dicp->di_nextents + dicp->di_anextents > dicp->di_nblocks)){
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
                                     XFS_ERRLEVEL_LOW, mp, dicp);
-               xfs_buf_relse(bp);
                xfs_alert(mp,
        "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
        "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld",
@@ -2659,29 +2866,27 @@ xlog_recover_inode_pass2(
                        dicp->di_nextents + dicp->di_anextents,
                        dicp->di_nblocks);
                error = EFSCORRUPTED;
-               goto error;
+               goto out_release;
        }
        if (unlikely(dicp->di_forkoff > mp->m_sb.sb_inodesize)) {
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)",
                                     XFS_ERRLEVEL_LOW, mp, dicp);
-               xfs_buf_relse(bp);
                xfs_alert(mp,
        "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, "
        "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__,
                        item, dip, bp, in_f->ilf_ino, dicp->di_forkoff);
                error = EFSCORRUPTED;
-               goto error;
+               goto out_release;
        }
        isize = xfs_icdinode_size(dicp->di_version);
        if (unlikely(item->ri_buf[1].i_len > isize)) {
                XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)",
                                     XFS_ERRLEVEL_LOW, mp, dicp);
-               xfs_buf_relse(bp);
                xfs_alert(mp,
                        "%s: Bad inode log record length %d, rec ptr 0x%p",
                        __func__, item->ri_buf[1].i_len, item);
                error = EFSCORRUPTED;
-               goto error;
+               goto out_release;
        }
 
        /* The core is in in-core format */
@@ -2707,7 +2912,7 @@ xlog_recover_inode_pass2(
        }
 
        if (in_f->ilf_size == 2)
-               goto write_inode_buffer;
+               goto out_owner_change;
        len = item->ri_buf[2].i_len;
        src = item->ri_buf[2].i_addr;
        ASSERT(in_f->ilf_size <= 4);
@@ -2768,19 +2973,23 @@ xlog_recover_inode_pass2(
                default:
                        xfs_warn(log->l_mp, "%s: Invalid flag", __func__);
                        ASSERT(0);
-                       xfs_buf_relse(bp);
                        error = EIO;
-                       goto error;
+                       goto out_release;
                }
        }
 
-write_inode_buffer:
+out_owner_change:
+       if (in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER))
+               error = xfs_recover_inode_owner_change(mp, dip, in_f,
+                                                      buffer_list);
        /* re-generate the checksum. */
        xfs_dinode_calc_crc(log->l_mp, dip);
 
        ASSERT(bp->b_target->bt_mount == mp);
        bp->b_iodone = xlog_recover_iodone;
        xfs_buf_delwri_queue(bp, buffer_list);
+
+out_release:
        xfs_buf_relse(bp);
 error:
        if (need_free)
@@ -2822,7 +3031,8 @@ STATIC int
 xlog_recover_dquot_pass2(
        struct xlog                     *log,
        struct list_head                *buffer_list,
-       struct xlog_recover_item        *item)
+       struct xlog_recover_item        *item,
+       xfs_lsn_t                       current_lsn)
 {
        xfs_mount_t             *mp = log->l_mp;
        xfs_buf_t               *bp;
@@ -2896,6 +3106,19 @@ xlog_recover_dquot_pass2(
                return XFS_ERROR(EIO);
        }
 
+       /*
+        * If the dquot has an LSN in it, recover the dquot only if it's less
+        * than the lsn of the transaction we are replaying.
+        */
+       if (xfs_sb_version_hascrc(&mp->m_sb)) {
+               struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq;
+               xfs_lsn_t       lsn = be64_to_cpu(dqb->dd_lsn);
+
+               if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
+                       goto out_release;
+               }
+       }
+
        memcpy(ddq, recddq, item->ri_buf[1].i_len);
        if (xfs_sb_version_hascrc(&mp->m_sb)) {
                xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk),
@@ -2906,9 +3129,10 @@ xlog_recover_dquot_pass2(
        ASSERT(bp->b_target->bt_mount == mp);
        bp->b_iodone = xlog_recover_iodone;
        xfs_buf_delwri_queue(bp, buffer_list);
-       xfs_buf_relse(bp);
 
-       return (0);
+out_release:
+       xfs_buf_relse(bp);
+       return 0;
 }
 
 /*
@@ -3116,6 +3340,106 @@ xlog_recover_free_trans(
        kmem_free(trans);
 }
 
+STATIC void
+xlog_recover_buffer_ra_pass2(
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
+{
+       struct xfs_buf_log_format       *buf_f = item->ri_buf[0].i_addr;
+       struct xfs_mount                *mp = log->l_mp;
+
+       if (xlog_peek_buffer_cancelled(log, buf_f->blf_blkno,
+                       buf_f->blf_len, buf_f->blf_flags)) {
+               return;
+       }
+
+       xfs_buf_readahead(mp->m_ddev_targp, buf_f->blf_blkno,
+                               buf_f->blf_len, NULL);
+}
+
+STATIC void
+xlog_recover_inode_ra_pass2(
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
+{
+       struct xfs_inode_log_format     ilf_buf;
+       struct xfs_inode_log_format     *ilfp;
+       struct xfs_mount                *mp = log->l_mp;
+       int                     error;
+
+       if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) {
+               ilfp = item->ri_buf[0].i_addr;
+       } else {
+               ilfp = &ilf_buf;
+               memset(ilfp, 0, sizeof(*ilfp));
+               error = xfs_inode_item_format_convert(&item->ri_buf[0], ilfp);
+               if (error)
+                       return;
+       }
+
+       if (xlog_peek_buffer_cancelled(log, ilfp->ilf_blkno, ilfp->ilf_len, 0))
+               return;
+
+       xfs_buf_readahead(mp->m_ddev_targp, ilfp->ilf_blkno,
+                               ilfp->ilf_len, &xfs_inode_buf_ra_ops);
+}
+
+STATIC void
+xlog_recover_dquot_ra_pass2(
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
+{
+       struct xfs_mount        *mp = log->l_mp;
+       struct xfs_disk_dquot   *recddq;
+       struct xfs_dq_logformat *dq_f;
+       uint                    type;
+
+
+       if (mp->m_qflags == 0)
+               return;
+
+       recddq = item->ri_buf[1].i_addr;
+       if (recddq == NULL)
+               return;
+       if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
+               return;
+
+       type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP);
+       ASSERT(type);
+       if (log->l_quotaoffs_flag & type)
+               return;
+
+       dq_f = item->ri_buf[0].i_addr;
+       ASSERT(dq_f);
+       ASSERT(dq_f->qlf_len == 1);
+
+       xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno,
+                         XFS_FSB_TO_BB(mp, dq_f->qlf_len), NULL);
+}
+
+STATIC void
+xlog_recover_ra_pass2(
+       struct xlog                     *log,
+       struct xlog_recover_item        *item)
+{
+       switch (ITEM_TYPE(item)) {
+       case XFS_LI_BUF:
+               xlog_recover_buffer_ra_pass2(log, item);
+               break;
+       case XFS_LI_INODE:
+               xlog_recover_inode_ra_pass2(log, item);
+               break;
+       case XFS_LI_DQUOT:
+               xlog_recover_dquot_ra_pass2(log, item);
+               break;
+       case XFS_LI_EFI:
+       case XFS_LI_EFD:
+       case XFS_LI_QUOTAOFF:
+       default:
+               break;
+       }
+}
+
 STATIC int
 xlog_recover_commit_pass1(
        struct xlog                     *log,
@@ -3155,15 +3479,18 @@ xlog_recover_commit_pass2(
 
        switch (ITEM_TYPE(item)) {
        case XFS_LI_BUF:
-               return xlog_recover_buffer_pass2(log, buffer_list, item);
+               return xlog_recover_buffer_pass2(log, buffer_list, item,
+                                                trans->r_lsn);
        case XFS_LI_INODE:
-               return xlog_recover_inode_pass2(log, buffer_list, item);
+               return xlog_recover_inode_pass2(log, buffer_list, item,
+                                                trans->r_lsn);
        case XFS_LI_EFI:
                return xlog_recover_efi_pass2(log, item, trans->r_lsn);
        case XFS_LI_EFD:
                return xlog_recover_efd_pass2(log, item);
        case XFS_LI_DQUOT:
-               return xlog_recover_dquot_pass2(log, buffer_list, item);
+               return xlog_recover_dquot_pass2(log, buffer_list, item,
+                                               trans->r_lsn);
        case XFS_LI_ICREATE:
                return xlog_recover_do_icreate_pass2(log, buffer_list, item);
        case XFS_LI_QUOTAOFF:
@@ -3177,6 +3504,26 @@ xlog_recover_commit_pass2(
        }
 }
 
+STATIC int
+xlog_recover_items_pass2(
+       struct xlog                     *log,
+       struct xlog_recover             *trans,
+       struct list_head                *buffer_list,
+       struct list_head                *item_list)
+{
+       struct xlog_recover_item        *item;
+       int                             error = 0;
+
+       list_for_each_entry(item, item_list, ri_list) {
+               error = xlog_recover_commit_pass2(log, trans,
+                                         buffer_list, item);
+               if (error)
+                       return error;
+       }
+
+       return error;
+}
+
 /*
  * Perform the transaction.
  *
@@ -3189,9 +3536,16 @@ xlog_recover_commit_trans(
        struct xlog_recover     *trans,
        int                     pass)
 {
-       int                     error = 0, error2;
-       xlog_recover_item_t     *item;
-       LIST_HEAD               (buffer_list);
+       int                             error = 0;
+       int                             error2;
+       int                             items_queued = 0;
+       struct xlog_recover_item        *item;
+       struct xlog_recover_item        *next;
+       LIST_HEAD                       (buffer_list);
+       LIST_HEAD                       (ra_list);
+       LIST_HEAD                       (done_list);
+
+       #define XLOG_RECOVER_COMMIT_QUEUE_MAX 100
 
        hlist_del(&trans->r_list);
 
@@ -3199,14 +3553,22 @@ xlog_recover_commit_trans(
        if (error)
                return error;
 
-       list_for_each_entry(item, &trans->r_itemq, ri_list) {
+       list_for_each_entry_safe(item, next, &trans->r_itemq, ri_list) {
                switch (pass) {
                case XLOG_RECOVER_PASS1:
                        error = xlog_recover_commit_pass1(log, trans, item);
                        break;
                case XLOG_RECOVER_PASS2:
-                       error = xlog_recover_commit_pass2(log, trans,
-                                                         &buffer_list, item);
+                       xlog_recover_ra_pass2(log, item);
+                       list_move_tail(&item->ri_list, &ra_list);
+                       items_queued++;
+                       if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) {
+                               error = xlog_recover_items_pass2(log, trans,
+                                               &buffer_list, &ra_list);
+                               list_splice_tail_init(&ra_list, &done_list);
+                               items_queued = 0;
+                       }
+
                        break;
                default:
                        ASSERT(0);
@@ -3216,9 +3578,19 @@ xlog_recover_commit_trans(
                        goto out;
        }
 
+out:
+       if (!list_empty(&ra_list)) {
+               if (!error)
+                       error = xlog_recover_items_pass2(log, trans,
+                                       &buffer_list, &ra_list);
+               list_splice_tail_init(&ra_list, &done_list);
+       }
+
+       if (!list_empty(&done_list))
+               list_splice_init(&done_list, &trans->r_itemq);
+
        xlog_recover_free_trans(trans);
 
-out:
        error2 = xfs_buf_delwri_submit(&buffer_list);
        return error ? error : error2;
 }
@@ -3376,7 +3748,7 @@ xlog_recover_process_efi(
        }
 
        tp = xfs_trans_alloc(mp, 0);
-       error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, 0, 0);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
        if (error)
                goto abort_error;
        efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents);
@@ -3482,8 +3854,7 @@ xlog_recover_clear_agi_bucket(
        int             error;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_CLEAR_AGI_BUCKET);
-       error = xfs_trans_reserve(tp, 0, XFS_CLEAR_AGI_BUCKET_LOG_RES(mp),
-                                 0, 0, 0);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_clearagi, 0, 0);
        if (error)
                goto out_abort;
 
diff --git a/fs/xfs/xfs_log_rlimit.c b/fs/xfs/xfs_log_rlimit.c
new file mode 100644 (file)
index 0000000..bbcec0b
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2013 Jie Liu.
+ * 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_log.h"
+#include "xfs_trans.h"
+#include "xfs_ag.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_trans_space.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_da_btree.h"
+#include "xfs_attr_leaf.h"
+
+/*
+ * Calculate the maximum length in bytes that would be required for a local
+ * attribute value as large attributes out of line are not logged.
+ */
+STATIC int
+xfs_log_calc_max_attrsetm_res(
+       struct xfs_mount        *mp)
+{
+       int                     size;
+       int                     nblks;
+
+       size = xfs_attr_leaf_entsize_local_max(mp->m_sb.sb_blocksize) -
+              MAXNAMELEN - 1;
+       nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
+       nblks += XFS_B_TO_FSB(mp, size);
+       nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK);
+
+       return  M_RES(mp)->tr_attrsetm.tr_logres +
+               M_RES(mp)->tr_attrsetrt.tr_logres * nblks;
+}
+
+/*
+ * Iterate over the log space reservation table to figure out and return
+ * the maximum one in terms of the pre-calculated values which were done
+ * at mount time.
+ */
+STATIC void
+xfs_log_get_max_trans_res(
+       struct xfs_mount        *mp,
+       struct xfs_trans_res    *max_resp)
+{
+       struct xfs_trans_res    *resp;
+       struct xfs_trans_res    *end_resp;
+       int                     log_space = 0;
+       int                     attr_space;
+
+       attr_space = xfs_log_calc_max_attrsetm_res(mp);
+
+       resp = (struct xfs_trans_res *)M_RES(mp);
+       end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1);
+       for (; resp < end_resp; resp++) {
+               int             tmp = resp->tr_logcount > 1 ?
+                                     resp->tr_logres * resp->tr_logcount :
+                                     resp->tr_logres;
+               if (log_space < tmp) {
+                       log_space = tmp;
+                       *max_resp = *resp;              /* struct copy */
+               }
+       }
+
+       if (attr_space > log_space) {
+               *max_resp = M_RES(mp)->tr_attrsetm;     /* struct copy */
+               max_resp->tr_logres = attr_space;
+       }
+}
+
+/*
+ * Calculate the minimum valid log size for the given superblock configuration.
+ * Used to calculate the minimum log size at mkfs time, and to determine if
+ * the log is large enough or not at mount time. Returns the minimum size in
+ * filesystem block size units.
+ */
+int
+xfs_log_calc_minimum_size(
+       struct xfs_mount        *mp)
+{
+       struct xfs_trans_res    tres = {0};
+       int                     max_logres;
+       int                     min_logblks = 0;
+       int                     lsunit = 0;
+
+       xfs_log_get_max_trans_res(mp, &tres);
+
+       max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres);
+       if (tres.tr_logcount > 1)
+               max_logres *= tres.tr_logcount;
+
+       if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1)
+               lsunit = BTOBB(mp->m_sb.sb_logsunit);
+
+       /*
+        * Two factors should be taken into account for calculating the minimum
+        * log space.
+        * 1) The fundamental limitation is that no single transaction can be
+        *    larger than half size of the log.
+        *
+        *    From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR
+        *    define, which is set to 3. That means we can definitely fit
+        *    maximally sized 2 transactions in the log. We'll use this same
+        *    value here.
+        *
+        * 2) If the lsunit option is specified, a transaction requires 2 LSU
+        *    for the reservation because there are two log writes that can
+        *    require padding - the transaction data and the commit record which
+        *    are written separately and both can require padding to the LSU.
+        *    Consider that we can have an active CIL reservation holding 2*LSU,
+        *    but the CIL is not over a push threshold, in this case, if we
+        *    don't have enough log space for at one new transaction, which
+        *    includes another 2*LSU in the reservation, we will run into dead
+        *    loop situation in log space grant procedure. i.e.
+        *    xlog_grant_head_wait().
+        *
+        *    Hence the log size needs to be able to contain two maximally sized
+        *    and padded transactions, which is (2 * (2 * LSU + maxlres)).
+        *
+        * Also, the log size should be a multiple of the log stripe unit, round
+        * it up to lsunit boundary if lsunit is specified.
+        */
+       if (lsunit) {
+               min_logblks = roundup_64(BTOBB(max_logres), lsunit) +
+                             2 * lsunit;
+       } else
+               min_logblks = BTOBB(max_logres) + 2 * BBSIZE;
+       min_logblks *= XFS_MIN_LOG_FACTOR;
+
+       return XFS_BB_TO_FSB(mp, min_logblks);
+}
index 2b0ba358165619b87523315f1ca3940b4e2606c0..5dcc68019d1bc8c49a799695436045d69d49167f 100644 (file)
@@ -17,7 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
 #include "xfs_trans_priv.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_alloc_btree.h"
 #include "xfs_ialloc_btree.h"
@@ -40,7 +42,6 @@
 #include "xfs_error.h"
 #include "xfs_quota.h"
 #include "xfs_fsops.h"
-#include "xfs_utils.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
 #include "xfs_cksum.h"
@@ -59,69 +60,6 @@ STATIC void  xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
 #define xfs_icsb_balance_counter_locked(mp, a, b)      do { } while (0)
 #endif
 
-static const struct {
-       short offset;
-       short type;     /* 0 = integer
-                        * 1 = binary / string (no translation)
-                        */
-} xfs_sb_info[] = {
-    { offsetof(xfs_sb_t, sb_magicnum),   0 },
-    { offsetof(xfs_sb_t, sb_blocksize),  0 },
-    { offsetof(xfs_sb_t, sb_dblocks),    0 },
-    { offsetof(xfs_sb_t, sb_rblocks),    0 },
-    { offsetof(xfs_sb_t, sb_rextents),   0 },
-    { offsetof(xfs_sb_t, sb_uuid),       1 },
-    { offsetof(xfs_sb_t, sb_logstart),   0 },
-    { offsetof(xfs_sb_t, sb_rootino),    0 },
-    { offsetof(xfs_sb_t, sb_rbmino),     0 },
-    { offsetof(xfs_sb_t, sb_rsumino),    0 },
-    { offsetof(xfs_sb_t, sb_rextsize),   0 },
-    { offsetof(xfs_sb_t, sb_agblocks),   0 },
-    { offsetof(xfs_sb_t, sb_agcount),    0 },
-    { offsetof(xfs_sb_t, sb_rbmblocks),  0 },
-    { offsetof(xfs_sb_t, sb_logblocks),  0 },
-    { offsetof(xfs_sb_t, sb_versionnum), 0 },
-    { offsetof(xfs_sb_t, sb_sectsize),   0 },
-    { offsetof(xfs_sb_t, sb_inodesize),  0 },
-    { offsetof(xfs_sb_t, sb_inopblock),  0 },
-    { offsetof(xfs_sb_t, sb_fname[0]),   1 },
-    { offsetof(xfs_sb_t, sb_blocklog),   0 },
-    { offsetof(xfs_sb_t, sb_sectlog),    0 },
-    { offsetof(xfs_sb_t, sb_inodelog),   0 },
-    { offsetof(xfs_sb_t, sb_inopblog),   0 },
-    { offsetof(xfs_sb_t, sb_agblklog),   0 },
-    { offsetof(xfs_sb_t, sb_rextslog),   0 },
-    { offsetof(xfs_sb_t, sb_inprogress), 0 },
-    { offsetof(xfs_sb_t, sb_imax_pct),   0 },
-    { offsetof(xfs_sb_t, sb_icount),     0 },
-    { offsetof(xfs_sb_t, sb_ifree),      0 },
-    { offsetof(xfs_sb_t, sb_fdblocks),   0 },
-    { offsetof(xfs_sb_t, sb_frextents),  0 },
-    { offsetof(xfs_sb_t, sb_uquotino),   0 },
-    { offsetof(xfs_sb_t, sb_gquotino),   0 },
-    { offsetof(xfs_sb_t, sb_qflags),     0 },
-    { offsetof(xfs_sb_t, sb_flags),      0 },
-    { offsetof(xfs_sb_t, sb_shared_vn),  0 },
-    { offsetof(xfs_sb_t, sb_inoalignmt), 0 },
-    { offsetof(xfs_sb_t, sb_unit),      0 },
-    { offsetof(xfs_sb_t, sb_width),     0 },
-    { offsetof(xfs_sb_t, sb_dirblklog),         0 },
-    { offsetof(xfs_sb_t, sb_logsectlog), 0 },
-    { offsetof(xfs_sb_t, sb_logsectsize),0 },
-    { offsetof(xfs_sb_t, sb_logsunit),  0 },
-    { offsetof(xfs_sb_t, sb_features2),         0 },
-    { offsetof(xfs_sb_t, sb_bad_features2), 0 },
-    { offsetof(xfs_sb_t, sb_features_compat), 0 },
-    { offsetof(xfs_sb_t, sb_features_ro_compat), 0 },
-    { offsetof(xfs_sb_t, sb_features_incompat), 0 },
-    { offsetof(xfs_sb_t, sb_features_log_incompat), 0 },
-    { offsetof(xfs_sb_t, sb_crc),       0 },
-    { offsetof(xfs_sb_t, sb_pad),       0 },
-    { offsetof(xfs_sb_t, sb_pquotino),  0 },
-    { offsetof(xfs_sb_t, sb_lsn),       0 },
-    { sizeof(xfs_sb_t),                         0 }
-};
-
 static DEFINE_MUTEX(xfs_uuid_table_mutex);
 static int xfs_uuid_table_size;
 static uuid_t *xfs_uuid_table;
@@ -197,64 +135,6 @@ xfs_uuid_unmount(
 }
 
 
-/*
- * Reference counting access wrappers to the perag structures.
- * Because we never free per-ag structures, the only thing we
- * have to protect against changes is the tree structure itself.
- */
-struct xfs_perag *
-xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno)
-{
-       struct xfs_perag        *pag;
-       int                     ref = 0;
-
-       rcu_read_lock();
-       pag = radix_tree_lookup(&mp->m_perag_tree, agno);
-       if (pag) {
-               ASSERT(atomic_read(&pag->pag_ref) >= 0);
-               ref = atomic_inc_return(&pag->pag_ref);
-       }
-       rcu_read_unlock();
-       trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
-       return pag;
-}
-
-/*
- * search from @first to find the next perag with the given tag set.
- */
-struct xfs_perag *
-xfs_perag_get_tag(
-       struct xfs_mount        *mp,
-       xfs_agnumber_t          first,
-       int                     tag)
-{
-       struct xfs_perag        *pag;
-       int                     found;
-       int                     ref;
-
-       rcu_read_lock();
-       found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
-                                       (void **)&pag, first, 1, tag);
-       if (found <= 0) {
-               rcu_read_unlock();
-               return NULL;
-       }
-       ref = atomic_inc_return(&pag->pag_ref);
-       rcu_read_unlock();
-       trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
-       return pag;
-}
-
-void
-xfs_perag_put(struct xfs_perag *pag)
-{
-       int     ref;
-
-       ASSERT(atomic_read(&pag->pag_ref) > 0);
-       ref = atomic_dec_return(&pag->pag_ref);
-       trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
-}
-
 STATIC void
 __xfs_free_perag(
        struct rcu_head *head)
@@ -307,184 +187,6 @@ xfs_sb_validate_fsb_count(
        return 0;
 }
 
-/*
- * Check the validity of the SB found.
- */
-STATIC int
-xfs_mount_validate_sb(
-       xfs_mount_t     *mp,
-       xfs_sb_t        *sbp,
-       bool            check_inprogress,
-       bool            check_version)
-{
-
-       /*
-        * If the log device and data device have the
-        * same device number, the log is internal.
-        * Consequently, the sb_logstart should be non-zero.  If
-        * we have a zero sb_logstart in this case, we may be trying to mount
-        * a volume filesystem in a non-volume manner.
-        */
-       if (sbp->sb_magicnum != XFS_SB_MAGIC) {
-               xfs_warn(mp, "bad magic number");
-               return XFS_ERROR(EWRONGFS);
-       }
-
-
-       if (!xfs_sb_good_version(sbp)) {
-               xfs_warn(mp, "bad version");
-               return XFS_ERROR(EWRONGFS);
-       }
-
-       if ((sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) &&
-                       (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
-                               XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))) {
-               xfs_notice(mp,
-"Super block has XFS_OQUOTA bits along with XFS_PQUOTA and/or XFS_GQUOTA bits.\n");
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       /*
-        * Version 5 superblock feature mask validation. Reject combinations the
-        * kernel cannot support up front before checking anything else. For
-        * write validation, we don't need to check feature masks.
-        */
-       if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) {
-               xfs_alert(mp,
-"Version 5 superblock detected. This kernel has EXPERIMENTAL support enabled!\n"
-"Use of these features in this kernel is at your own risk!");
-
-               if (xfs_sb_has_compat_feature(sbp,
-                                       XFS_SB_FEAT_COMPAT_UNKNOWN)) {
-                       xfs_warn(mp,
-"Superblock has unknown compatible features (0x%x) enabled.\n"
-"Using a more recent kernel is recommended.",
-                               (sbp->sb_features_compat &
-                                               XFS_SB_FEAT_COMPAT_UNKNOWN));
-               }
-
-               if (xfs_sb_has_ro_compat_feature(sbp,
-                                       XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
-                       xfs_alert(mp,
-"Superblock has unknown read-only compatible features (0x%x) enabled.",
-                               (sbp->sb_features_ro_compat &
-                                               XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
-                       if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
-                               xfs_warn(mp,
-"Attempted to mount read-only compatible filesystem read-write.\n"
-"Filesystem can only be safely mounted read only.");
-                               return XFS_ERROR(EINVAL);
-                       }
-               }
-               if (xfs_sb_has_incompat_feature(sbp,
-                                       XFS_SB_FEAT_INCOMPAT_UNKNOWN)) {
-                       xfs_warn(mp,
-"Superblock has unknown incompatible features (0x%x) enabled.\n"
-"Filesystem can not be safely mounted by this kernel.",
-                               (sbp->sb_features_incompat &
-                                               XFS_SB_FEAT_INCOMPAT_UNKNOWN));
-                       return XFS_ERROR(EINVAL);
-               }
-       }
-
-       if (unlikely(
-           sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
-               xfs_warn(mp,
-               "filesystem is marked as having an external log; "
-               "specify logdev on the mount command line.");
-               return XFS_ERROR(EINVAL);
-       }
-
-       if (unlikely(
-           sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
-               xfs_warn(mp,
-               "filesystem is marked as having an internal log; "
-               "do not specify logdev on the mount command line.");
-               return XFS_ERROR(EINVAL);
-       }
-
-       /*
-        * More sanity checking.  Most of these were stolen directly from
-        * xfs_repair.
-        */
-       if (unlikely(
-           sbp->sb_agcount <= 0                                        ||
-           sbp->sb_sectsize < XFS_MIN_SECTORSIZE                       ||
-           sbp->sb_sectsize > XFS_MAX_SECTORSIZE                       ||
-           sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG                    ||
-           sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG                    ||
-           sbp->sb_sectsize != (1 << sbp->sb_sectlog)                  ||
-           sbp->sb_blocksize < XFS_MIN_BLOCKSIZE                       ||
-           sbp->sb_blocksize > XFS_MAX_BLOCKSIZE                       ||
-           sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG                    ||
-           sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG                    ||
-           sbp->sb_blocksize != (1 << sbp->sb_blocklog)                ||
-           sbp->sb_inodesize < XFS_DINODE_MIN_SIZE                     ||
-           sbp->sb_inodesize > XFS_DINODE_MAX_SIZE                     ||
-           sbp->sb_inodelog < XFS_DINODE_MIN_LOG                       ||
-           sbp->sb_inodelog > XFS_DINODE_MAX_LOG                       ||
-           sbp->sb_inodesize != (1 << sbp->sb_inodelog)                ||
-           (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)   ||
-           (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)  ||
-           (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)  ||
-           (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)    ||
-           sbp->sb_dblocks == 0                                        ||
-           sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)                      ||
-           sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
-               XFS_CORRUPTION_ERROR("SB sanity check failed",
-                               XFS_ERRLEVEL_LOW, mp, sbp);
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       /*
-        * Until this is fixed only page-sized or smaller data blocks work.
-        */
-       if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
-               xfs_warn(mp,
-               "File system with blocksize %d bytes. "
-               "Only pagesize (%ld) or less will currently work.",
-                               sbp->sb_blocksize, PAGE_SIZE);
-               return XFS_ERROR(ENOSYS);
-       }
-
-       /*
-        * Currently only very few inode sizes are supported.
-        */
-       switch (sbp->sb_inodesize) {
-       case 256:
-       case 512:
-       case 1024:
-       case 2048:
-               break;
-       default:
-               xfs_warn(mp, "inode size of %d bytes not supported",
-                               sbp->sb_inodesize);
-               return XFS_ERROR(ENOSYS);
-       }
-
-       if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
-           xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
-               xfs_warn(mp,
-               "file system too large to be mounted on this system.");
-               return XFS_ERROR(EFBIG);
-       }
-
-       if (check_inprogress && sbp->sb_inprogress) {
-               xfs_warn(mp, "Offline file system operation in progress!");
-               return XFS_ERROR(EFSCORRUPTED);
-       }
-
-       /*
-        * Version 1 directory format has never worked on Linux.
-        */
-       if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
-               xfs_warn(mp, "file system using version 1 directory format");
-               return XFS_ERROR(ENOSYS);
-       }
-
-       return 0;
-}
-
 int
 xfs_initialize_perag(
        xfs_mount_t     *mp,
@@ -569,283 +271,15 @@ out_unwind:
        return error;
 }
 
-static void
-xfs_sb_quota_from_disk(struct xfs_sb *sbp)
-{
-       if (sbp->sb_qflags & XFS_OQUOTA_ENFD)
-               sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ?
-                                       XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
-       if (sbp->sb_qflags & XFS_OQUOTA_CHKD)
-               sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ?
-                                       XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
-       sbp->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
-}
-
-void
-xfs_sb_from_disk(
-       struct xfs_sb   *to,
-       xfs_dsb_t       *from)
-{
-       to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
-       to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
-       to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
-       to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
-       to->sb_rextents = be64_to_cpu(from->sb_rextents);
-       memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid));
-       to->sb_logstart = be64_to_cpu(from->sb_logstart);
-       to->sb_rootino = be64_to_cpu(from->sb_rootino);
-       to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
-       to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
-       to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
-       to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
-       to->sb_agcount = be32_to_cpu(from->sb_agcount);
-       to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
-       to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
-       to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
-       to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
-       to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
-       to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
-       memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname));
-       to->sb_blocklog = from->sb_blocklog;
-       to->sb_sectlog = from->sb_sectlog;
-       to->sb_inodelog = from->sb_inodelog;
-       to->sb_inopblog = from->sb_inopblog;
-       to->sb_agblklog = from->sb_agblklog;
-       to->sb_rextslog = from->sb_rextslog;
-       to->sb_inprogress = from->sb_inprogress;
-       to->sb_imax_pct = from->sb_imax_pct;
-       to->sb_icount = be64_to_cpu(from->sb_icount);
-       to->sb_ifree = be64_to_cpu(from->sb_ifree);
-       to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
-       to->sb_frextents = be64_to_cpu(from->sb_frextents);
-       to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
-       to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
-       to->sb_qflags = be16_to_cpu(from->sb_qflags);
-       to->sb_flags = from->sb_flags;
-       to->sb_shared_vn = from->sb_shared_vn;
-       to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
-       to->sb_unit = be32_to_cpu(from->sb_unit);
-       to->sb_width = be32_to_cpu(from->sb_width);
-       to->sb_dirblklog = from->sb_dirblklog;
-       to->sb_logsectlog = from->sb_logsectlog;
-       to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize);
-       to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
-       to->sb_features2 = be32_to_cpu(from->sb_features2);
-       to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
-       to->sb_features_compat = be32_to_cpu(from->sb_features_compat);
-       to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat);
-       to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
-       to->sb_features_log_incompat =
-                               be32_to_cpu(from->sb_features_log_incompat);
-       to->sb_pad = 0;
-       to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
-       to->sb_lsn = be64_to_cpu(from->sb_lsn);
-}
-
-static inline void
-xfs_sb_quota_to_disk(
-       xfs_dsb_t       *to,
-       xfs_sb_t        *from,
-       __int64_t       *fields)
-{
-       __uint16_t      qflags = from->sb_qflags;
-
-       if (*fields & XFS_SB_QFLAGS) {
-               /*
-                * The in-core version of sb_qflags do not have
-                * XFS_OQUOTA_* flags, whereas the on-disk version
-                * does.  So, convert incore XFS_{PG}QUOTA_* flags
-                * to on-disk XFS_OQUOTA_* flags.
-                */
-               qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
-                               XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
-
-               if (from->sb_qflags &
-                               (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
-                       qflags |= XFS_OQUOTA_ENFD;
-               if (from->sb_qflags &
-                               (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
-                       qflags |= XFS_OQUOTA_CHKD;
-               to->sb_qflags = cpu_to_be16(qflags);
-               *fields &= ~XFS_SB_QFLAGS;
-       }
-}
-
-/*
- * Copy in core superblock to ondisk one.
- *
- * The fields argument is mask of superblock fields to copy.
- */
-void
-xfs_sb_to_disk(
-       xfs_dsb_t       *to,
-       xfs_sb_t        *from,
-       __int64_t       fields)
-{
-       xfs_caddr_t     to_ptr = (xfs_caddr_t)to;
-       xfs_caddr_t     from_ptr = (xfs_caddr_t)from;
-       xfs_sb_field_t  f;
-       int             first;
-       int             size;
-
-       ASSERT(fields);
-       if (!fields)
-               return;
-
-       xfs_sb_quota_to_disk(to, from, &fields);
-       while (fields) {
-               f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
-               first = xfs_sb_info[f].offset;
-               size = xfs_sb_info[f + 1].offset - first;
-
-               ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1);
-
-               if (size == 1 || xfs_sb_info[f].type == 1) {
-                       memcpy(to_ptr + first, from_ptr + first, size);
-               } else {
-                       switch (size) {
-                       case 2:
-                               *(__be16 *)(to_ptr + first) =
-                                       cpu_to_be16(*(__u16 *)(from_ptr + first));
-                               break;
-                       case 4:
-                               *(__be32 *)(to_ptr + first) =
-                                       cpu_to_be32(*(__u32 *)(from_ptr + first));
-                               break;
-                       case 8:
-                               *(__be64 *)(to_ptr + first) =
-                                       cpu_to_be64(*(__u64 *)(from_ptr + first));
-                               break;
-                       default:
-                               ASSERT(0);
-                       }
-               }
-
-               fields &= ~(1LL << f);
-       }
-}
-
-static int
-xfs_sb_verify(
-       struct xfs_buf  *bp,
-       bool            check_version)
-{
-       struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_sb   sb;
-
-       xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));
-
-       /*
-        * Only check the in progress field for the primary superblock as
-        * mkfs.xfs doesn't clear it from secondary superblocks.
-        */
-       return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR,
-                                    check_version);
-}
-
-/*
- * If the superblock has the CRC feature bit set or the CRC field is non-null,
- * check that the CRC is valid.  We check the CRC field is non-null because a
- * single bit error could clear the feature bit and unused parts of the
- * superblock are supposed to be zero. Hence a non-null crc field indicates that
- * we've potentially lost a feature bit and we should check it anyway.
- */
-static void
-xfs_sb_read_verify(
-       struct xfs_buf  *bp)
-{
-       struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
-       int             error;
-
-       /*
-        * open code the version check to avoid needing to convert the entire
-        * superblock from disk order just to check the version number
-        */
-       if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) &&
-           (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) ==
-                                               XFS_SB_VERSION_5) ||
-            dsb->sb_crc != 0)) {
-
-               if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
-                                     offsetof(struct xfs_sb, sb_crc))) {
-                       error = EFSCORRUPTED;
-                       goto out_error;
-               }
-       }
-       error = xfs_sb_verify(bp, true);
-
-out_error:
-       if (error) {
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
-               xfs_buf_ioerror(bp, error);
-       }
-}
-
-/*
- * We may be probed for a filesystem match, so we may not want to emit
- * messages when the superblock buffer is not actually an XFS superblock.
- * If we find an XFS superblock, the run a normal, noisy mount because we are
- * really going to mount it and want to know about errors.
- */
-static void
-xfs_sb_quiet_read_verify(
-       struct xfs_buf  *bp)
-{
-       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
-
-
-       if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
-               /* XFS filesystem, verify noisily! */
-               xfs_sb_read_verify(bp);
-               return;
-       }
-       /* quietly fail */
-       xfs_buf_ioerror(bp, EWRONGFS);
-}
-
-static void
-xfs_sb_write_verify(
-       struct xfs_buf          *bp)
-{
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
-       int                     error;
-
-       error = xfs_sb_verify(bp, false);
-       if (error) {
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
-               xfs_buf_ioerror(bp, error);
-               return;
-       }
-
-       if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return;
-
-       if (bip)
-               XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
-
-       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
-                        offsetof(struct xfs_sb, sb_crc));
-}
-
-const struct xfs_buf_ops xfs_sb_buf_ops = {
-       .verify_read = xfs_sb_read_verify,
-       .verify_write = xfs_sb_write_verify,
-};
-
-static const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
-       .verify_read = xfs_sb_quiet_read_verify,
-       .verify_write = xfs_sb_write_verify,
-};
-
 /*
  * xfs_readsb
  *
  * Does the initial read of the superblock.
  */
 int
-xfs_readsb(xfs_mount_t *mp, int flags)
+xfs_readsb(
+       struct xfs_mount *mp,
+       int             flags)
 {
        unsigned int    sector_size;
        struct xfs_buf  *bp;
@@ -884,8 +318,8 @@ reread:
         * Initialize the mount structure from the superblock.
         */
        xfs_sb_from_disk(&mp->m_sb, XFS_BUF_TO_SBP(bp));
-
        xfs_sb_quota_from_disk(&mp->m_sb);
+
        /*
         * We must be able to do sector-sized and sector-aligned IO.
         */
@@ -922,107 +356,6 @@ release_buf:
        return error;
 }
 
-
-/*
- * xfs_mount_common
- *
- * Mount initialization code establishing various mount
- * fields from the superblock associated with the given
- * mount structure
- */
-STATIC void
-xfs_mount_common(xfs_mount_t *mp, xfs_sb_t *sbp)
-{
-       mp->m_agfrotor = mp->m_agirotor = 0;
-       spin_lock_init(&mp->m_agirotor_lock);
-       mp->m_maxagi = mp->m_sb.sb_agcount;
-       mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG;
-       mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
-       mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
-       mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
-       mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
-       mp->m_blockmask = sbp->sb_blocksize - 1;
-       mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
-       mp->m_blockwmask = mp->m_blockwsize - 1;
-
-       mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
-       mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
-       mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
-       mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
-
-       mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
-       mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
-       mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2;
-       mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2;
-
-       mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
-       mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
-       mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
-       mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
-
-       mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
-       mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
-                                       sbp->sb_inopblock);
-       mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
-}
-
-/*
- * xfs_initialize_perag_data
- *
- * Read in each per-ag structure so we can count up the number of
- * allocated inodes, free inodes and used filesystem blocks as this
- * information is no longer persistent in the superblock. Once we have
- * this information, write it into the in-core superblock structure.
- */
-STATIC int
-xfs_initialize_perag_data(xfs_mount_t *mp, xfs_agnumber_t agcount)
-{
-       xfs_agnumber_t  index;
-       xfs_perag_t     *pag;
-       xfs_sb_t        *sbp = &mp->m_sb;
-       uint64_t        ifree = 0;
-       uint64_t        ialloc = 0;
-       uint64_t        bfree = 0;
-       uint64_t        bfreelst = 0;
-       uint64_t        btree = 0;
-       int             error;
-
-       for (index = 0; index < agcount; index++) {
-               /*
-                * read the agf, then the agi. This gets us
-                * all the information we need and populates the
-                * per-ag structures for us.
-                */
-               error = xfs_alloc_pagf_init(mp, NULL, index, 0);
-               if (error)
-                       return error;
-
-               error = xfs_ialloc_pagi_init(mp, NULL, index);
-               if (error)
-                       return error;
-               pag = xfs_perag_get(mp, index);
-               ifree += pag->pagi_freecount;
-               ialloc += pag->pagi_count;
-               bfree += pag->pagf_freeblks;
-               bfreelst += pag->pagf_flcount;
-               btree += pag->pagf_btreeblks;
-               xfs_perag_put(pag);
-       }
-       /*
-        * Overwrite incore superblock counters with just-read data
-        */
-       spin_lock(&mp->m_sb_lock);
-       sbp->sb_ifree = ifree;
-       sbp->sb_icount = ialloc;
-       sbp->sb_fdblocks = bfree + bfreelst + btree;
-       spin_unlock(&mp->m_sb_lock);
-
-       /* Fixup the per-cpu counters as well. */
-       xfs_icsb_reinit_counters(mp);
-
-       return 0;
-}
-
 /*
  * Update alignment values based on mount options and sb values
  */
@@ -1194,7 +527,7 @@ xfs_set_inoalignment(xfs_mount_t *mp)
 }
 
 /*
- * Check that the data (and log if separate) are an ok size.
+ * Check that the data (and log if separate) is an ok size.
  */
 STATIC int
 xfs_check_sizes(xfs_mount_t *mp)
@@ -1264,8 +597,7 @@ xfs_mount_reset_sbqflags(
                return 0;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       error = xfs_trans_reserve(tp, 0, XFS_QM_SBCHANGE_LOG_RES(mp),
-                                 0, 0, XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_sbchange, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                xfs_alert(mp, "%s: Superblock update failed!", __func__);
@@ -1315,7 +647,7 @@ xfs_mountfs(
        uint            quotaflags = 0;
        int             error = 0;
 
-       xfs_mount_common(mp, sbp);
+       xfs_sb_mount_common(mp, sbp);
 
        /*
         * Check for a mismatched features2 values.  Older kernels
@@ -1400,7 +732,7 @@ xfs_mountfs(
        xfs_set_inoalignment(mp);
 
        /*
-        * Check that the data (and log if separate) are an ok size.
+        * Check that the data (and log if separate) is an ok size.
         */
        error = xfs_check_sizes(mp);
        if (error)
@@ -1738,8 +1070,7 @@ xfs_log_sbcount(xfs_mount_t *mp)
                return 0;
 
        tp = _xfs_trans_alloc(mp, XFS_TRANS_SB_COUNT, KM_SLEEP);
-       error = xfs_trans_reserve(tp, 0, XFS_SB_LOG_RES(mp), 0, 0,
-                                 XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
@@ -1752,49 +1083,7 @@ xfs_log_sbcount(xfs_mount_t *mp)
 }
 
 /*
- * xfs_mod_sb() can be used to copy arbitrary changes to the
- * in-core superblock into the superblock buffer to be logged.
- * It does not provide the higher level of locking that is
- * needed to protect the in-core superblock from concurrent
- * access.
- */
-void
-xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
-{
-       xfs_buf_t       *bp;
-       int             first;
-       int             last;
-       xfs_mount_t     *mp;
-       xfs_sb_field_t  f;
-
-       ASSERT(fields);
-       if (!fields)
-               return;
-       mp = tp->t_mountp;
-       bp = xfs_trans_getsb(tp, mp, 0);
-       first = sizeof(xfs_sb_t);
-       last = 0;
-
-       /* translate/copy */
-
-       xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);
-
-       /* find modified range */
-       f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
-       ASSERT((1LL << f) & XFS_SB_MOD_BITS);
-       last = xfs_sb_info[f + 1].offset - 1;
-
-       f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
-       ASSERT((1LL << f) & XFS_SB_MOD_BITS);
-       first = xfs_sb_info[f].offset;
-
-       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF);
-       xfs_trans_log_buf(tp, bp, first, last);
-}
-
-
-/*
- * xfs_mod_incore_sb_unlocked() is a utility routine common used to apply
+ * xfs_mod_incore_sb_unlocked() is a utility routine commonly used to apply
  * a delta to a specified field in the in-core superblock.  Simply
  * switch on the field indicated and apply the delta to that field.
  * Fields are not allowed to dip below zero, so if the delta would
@@ -2101,8 +1390,7 @@ xfs_mount_log_sb(
                         XFS_SB_VERSIONNUM));
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_SB_UNIT);
-       error = xfs_trans_reserve(tp, 0, XFS_SB_LOG_RES(mp), 0, 0,
-                                 XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_sb, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
@@ -2260,12 +1548,6 @@ xfs_icsb_init_counters(
        if (mp->m_sb_cnts == NULL)
                return -ENOMEM;
 
-#ifdef CONFIG_HOTPLUG_CPU
-       mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
-       mp->m_icsb_notifier.priority = 0;
-       register_hotcpu_notifier(&mp->m_icsb_notifier);
-#endif /* CONFIG_HOTPLUG_CPU */
-
        for_each_online_cpu(i) {
                cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i);
                memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
@@ -2278,6 +1560,13 @@ xfs_icsb_init_counters(
         * initial balance kicks us off correctly
         */
        mp->m_icsb_counters = -1;
+
+#ifdef CONFIG_HOTPLUG_CPU
+       mp->m_icsb_notifier.notifier_call = xfs_icsb_cpu_notify;
+       mp->m_icsb_notifier.priority = 0;
+       register_hotcpu_notifier(&mp->m_icsb_notifier);
+#endif /* CONFIG_HOTPLUG_CPU */
+
        return 0;
 }
 
index 4e374d4a9189622bccb2b56aa331c7218567d1f2..1fa0584b5627830c77e4bf0fa02db9c55c066a2d 100644 (file)
 #ifndef __XFS_MOUNT_H__
 #define        __XFS_MOUNT_H__
 
-typedef struct xfs_trans_reservations {
-       uint    tr_write;       /* extent alloc trans */
-       uint    tr_itruncate;   /* truncate trans */
-       uint    tr_rename;      /* rename trans */
-       uint    tr_link;        /* link trans */
-       uint    tr_remove;      /* unlink trans */
-       uint    tr_symlink;     /* symlink trans */
-       uint    tr_create;      /* create trans */
-       uint    tr_mkdir;       /* mkdir trans */
-       uint    tr_ifree;       /* inode free trans */
-       uint    tr_ichange;     /* inode update trans */
-       uint    tr_growdata;    /* fs data section grow trans */
-       uint    tr_swrite;      /* sync write inode trans */
-       uint    tr_addafork;    /* cvt inode to attributed trans */
-       uint    tr_writeid;     /* write setuid/setgid file */
-       uint    tr_attrinval;   /* attr fork buffer invalidation */
-       uint    tr_attrsetm;    /* set/create an attribute at mount time */
-       uint    tr_attrsetrt;   /* set/create an attribute at runtime */
-       uint    tr_attrrm;      /* remove an attribute */
-       uint    tr_clearagi;    /* clear bad agi unlinked ino bucket */
-       uint    tr_growrtalloc; /* grow realtime allocations */
-       uint    tr_growrtzero;  /* grow realtime zeroing */
-       uint    tr_growrtfree;  /* grow realtime freeing */
-       uint    tr_qm_sbchange; /* change quota flags */
-       uint    tr_qm_setqlim;  /* adjust quota limits */
-       uint    tr_qm_dqalloc;  /* allocate quota on disk */
-       uint    tr_qm_quotaoff; /* turn quota off */
-       uint    tr_qm_equotaoff;/* end of turn quota off */
-       uint    tr_sb;          /* modify superblock */
-} xfs_trans_reservations_t;
-
-#ifndef __KERNEL__
-
-#define xfs_daddr_to_agno(mp,d) \
-       ((xfs_agnumber_t)(XFS_BB_TO_FSBT(mp, d) / (mp)->m_sb.sb_agblocks))
-#define xfs_daddr_to_agbno(mp,d) \
-       ((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks))
-
-#else /* __KERNEL__ */
+#ifdef __KERNEL__
 
 struct xlog;
 struct xfs_inode;
@@ -174,7 +136,7 @@ typedef struct xfs_mount {
        int                     m_ialloc_blks;  /* blocks in inode allocation */
        int                     m_inoalign_mask;/* mask sb_inoalignmt if used */
        uint                    m_qflags;       /* quota status flags */
-       xfs_trans_reservations_t m_reservations;/* precomputed res values */
+       struct xfs_trans_resv   m_resv;         /* precomputed res values */
        __uint64_t              m_maxicount;    /* maximum inode count */
        __uint64_t              m_resblks;      /* total reserved blocks */
        __uint64_t              m_resblks_avail;/* available reserved blocks */
@@ -329,14 +291,6 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d)
        return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks);
 }
 
-/*
- * perag get/put wrappers for ref counting
- */
-struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
-struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno,
-                                       int tag);
-void   xfs_perag_put(struct xfs_perag *pag);
-
 /*
  * Per-cpu superblock locking functions
  */
@@ -366,9 +320,63 @@ typedef struct xfs_mod_sb {
        int64_t         msb_delta;      /* Change to make to specified field */
 } xfs_mod_sb_t;
 
+/*
+ * Per-ag incore structure, copies of information in agf and agi, to improve the
+ * performance of allocation group selection. This is defined for the kernel
+ * only, and hence is defined here instead of in xfs_ag.h. You need the struct
+ * xfs_mount to be defined to look up a xfs_perag anyway (via mp->m_perag_tree),
+ * so this doesn't introduce any strange header file dependencies.
+ */
+typedef struct xfs_perag {
+       struct xfs_mount *pag_mount;    /* owner filesystem */
+       xfs_agnumber_t  pag_agno;       /* AG this structure belongs to */
+       atomic_t        pag_ref;        /* perag reference count */
+       char            pagf_init;      /* this agf's entry is initialized */
+       char            pagi_init;      /* this agi's entry is initialized */
+       char            pagf_metadata;  /* the agf is preferred to be metadata */
+       char            pagi_inodeok;   /* The agi is ok for inodes */
+       __uint8_t       pagf_levels[XFS_BTNUM_AGF];
+                                       /* # of levels in bno & cnt btree */
+       __uint32_t      pagf_flcount;   /* count of blocks in freelist */
+       xfs_extlen_t    pagf_freeblks;  /* total free blocks */
+       xfs_extlen_t    pagf_longest;   /* longest free space */
+       __uint32_t      pagf_btreeblks; /* # of blocks held in AGF btrees */
+       xfs_agino_t     pagi_freecount; /* number of free inodes */
+       xfs_agino_t     pagi_count;     /* number of allocated inodes */
+
+       /*
+        * Inode allocation search lookup optimisation.
+        * If the pagino matches, the search for new inodes
+        * doesn't need to search the near ones again straight away
+        */
+       xfs_agino_t     pagl_pagino;
+       xfs_agino_t     pagl_leftrec;
+       xfs_agino_t     pagl_rightrec;
+       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 */
+
+       spinlock_t      pag_ici_lock;   /* incore inode cache lock */
+       struct radix_tree_root pag_ici_root;    /* incore inode cache root */
+       int             pag_ici_reclaimable;    /* reclaimable inodes */
+       struct mutex    pag_ici_reclaim_lock;   /* serialisation point */
+       unsigned long   pag_ici_reclaim_cursor; /* reclaim restart point */
+
+       /* buffer cache index */
+       spinlock_t      pag_buf_lock;   /* lock for pag_buf_tree */
+       struct rb_root  pag_buf_tree;   /* ordered tree of active buffers */
+
+       /* for rcu-safe freeing */
+       struct rcu_head rcu_head;
+       int             pagb_count;     /* pagb slots in use */
+} xfs_perag_t;
+
 extern int     xfs_log_sbcount(xfs_mount_t *);
 extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);
 extern int     xfs_mountfs(xfs_mount_t *mp);
+extern int     xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount,
+                                    xfs_agnumber_t *maxagi);
 
 extern void    xfs_unmountfs(xfs_mount_t *);
 extern int     xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int);
@@ -387,13 +395,4 @@ extern void        xfs_set_low_space_thresholds(struct xfs_mount *);
 
 #endif /* __KERNEL__ */
 
-extern void    xfs_sb_calc_crc(struct xfs_buf  *);
-extern void    xfs_mod_sb(struct xfs_trans *, __int64_t);
-extern int     xfs_initialize_perag(struct xfs_mount *, xfs_agnumber_t,
-                                       xfs_agnumber_t *);
-extern void    xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
-extern void    xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
-
-extern const struct xfs_buf_ops xfs_sb_buf_ops;
-
 #endif /* __XFS_MOUNT_H__ */
index d320794d03ce233d93f7ccfcd0a6c2c3f186e9c2..3e6c2e6c9cd24d145514c95b7357ce91acc219f0 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
@@ -37,7 +38,6 @@
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
 #include "xfs_trans_space.h"
-#include "xfs_utils.h"
 #include "xfs_qm.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
@@ -51,8 +51,9 @@
  */
 STATIC int     xfs_qm_init_quotainos(xfs_mount_t *);
 STATIC int     xfs_qm_init_quotainfo(xfs_mount_t *);
-STATIC int     xfs_qm_shake(struct shrinker *, struct shrink_control *);
 
+
+STATIC void    xfs_qm_dqfree_one(struct xfs_dquot *dqp);
 /*
  * We use the batch lookup interface to iterate over the dquots as it
  * currently is the only interface into the radix tree code that allows
@@ -203,12 +204,9 @@ xfs_qm_dqpurge(
         * We move dquots to the freelist as soon as their reference count
         * hits zero, so it really should be on the freelist here.
         */
-       mutex_lock(&qi->qi_lru_lock);
        ASSERT(!list_empty(&dqp->q_lru));
-       list_del_init(&dqp->q_lru);
-       qi->qi_lru_count--;
+       list_lru_del(&qi->qi_lru, &dqp->q_lru);
        XFS_STATS_DEC(xs_qm_dquot_unused);
-       mutex_unlock(&qi->qi_lru_lock);
 
        xfs_qm_dqdestroy(dqp);
 
@@ -680,6 +678,143 @@ xfs_qm_calc_dquots_per_chunk(
        return ndquots;
 }
 
+struct xfs_qm_isolate {
+       struct list_head        buffers;
+       struct list_head        dispose;
+};
+
+static enum lru_status
+xfs_qm_dquot_isolate(
+       struct list_head        *item,
+       spinlock_t              *lru_lock,
+       void                    *arg)
+{
+       struct xfs_dquot        *dqp = container_of(item,
+                                               struct xfs_dquot, q_lru);
+       struct xfs_qm_isolate   *isol = arg;
+
+       if (!xfs_dqlock_nowait(dqp))
+               goto out_miss_busy;
+
+       /*
+        * This dquot has acquired a reference in the meantime remove it from
+        * the freelist and try again.
+        */
+       if (dqp->q_nrefs) {
+               xfs_dqunlock(dqp);
+               XFS_STATS_INC(xs_qm_dqwants);
+
+               trace_xfs_dqreclaim_want(dqp);
+               list_del_init(&dqp->q_lru);
+               XFS_STATS_DEC(xs_qm_dquot_unused);
+               return LRU_REMOVED;
+       }
+
+       /*
+        * If the dquot is dirty, flush it. If it's already being flushed, just
+        * skip it so there is time for the IO to complete before we try to
+        * reclaim it again on the next LRU pass.
+        */
+       if (!xfs_dqflock_nowait(dqp)) {
+               xfs_dqunlock(dqp);
+               goto out_miss_busy;
+       }
+
+       if (XFS_DQ_IS_DIRTY(dqp)) {
+               struct xfs_buf  *bp = NULL;
+               int             error;
+
+               trace_xfs_dqreclaim_dirty(dqp);
+
+               /* we have to drop the LRU lock to flush the dquot */
+               spin_unlock(lru_lock);
+
+               error = xfs_qm_dqflush(dqp, &bp);
+               if (error) {
+                       xfs_warn(dqp->q_mount, "%s: dquot %p flush failed",
+                                __func__, dqp);
+                       goto out_unlock_dirty;
+               }
+
+               xfs_buf_delwri_queue(bp, &isol->buffers);
+               xfs_buf_relse(bp);
+               goto out_unlock_dirty;
+       }
+       xfs_dqfunlock(dqp);
+
+       /*
+        * Prevent lookups now that we are past the point of no return.
+        */
+       dqp->dq_flags |= XFS_DQ_FREEING;
+       xfs_dqunlock(dqp);
+
+       ASSERT(dqp->q_nrefs == 0);
+       list_move_tail(&dqp->q_lru, &isol->dispose);
+       XFS_STATS_DEC(xs_qm_dquot_unused);
+       trace_xfs_dqreclaim_done(dqp);
+       XFS_STATS_INC(xs_qm_dqreclaims);
+       return LRU_REMOVED;
+
+out_miss_busy:
+       trace_xfs_dqreclaim_busy(dqp);
+       XFS_STATS_INC(xs_qm_dqreclaim_misses);
+       return LRU_SKIP;
+
+out_unlock_dirty:
+       trace_xfs_dqreclaim_busy(dqp);
+       XFS_STATS_INC(xs_qm_dqreclaim_misses);
+       xfs_dqunlock(dqp);
+       spin_lock(lru_lock);
+       return LRU_RETRY;
+}
+
+static unsigned long
+xfs_qm_shrink_scan(
+       struct shrinker         *shrink,
+       struct shrink_control   *sc)
+{
+       struct xfs_quotainfo    *qi = container_of(shrink,
+                                       struct xfs_quotainfo, qi_shrinker);
+       struct xfs_qm_isolate   isol;
+       unsigned long           freed;
+       int                     error;
+       unsigned long           nr_to_scan = sc->nr_to_scan;
+
+       if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT))
+               return 0;
+
+       INIT_LIST_HEAD(&isol.buffers);
+       INIT_LIST_HEAD(&isol.dispose);
+
+       freed = list_lru_walk_node(&qi->qi_lru, sc->nid, xfs_qm_dquot_isolate, &isol,
+                                       &nr_to_scan);
+
+       error = xfs_buf_delwri_submit(&isol.buffers);
+       if (error)
+               xfs_warn(NULL, "%s: dquot reclaim failed", __func__);
+
+       while (!list_empty(&isol.dispose)) {
+               struct xfs_dquot        *dqp;
+
+               dqp = list_first_entry(&isol.dispose, struct xfs_dquot, q_lru);
+               list_del_init(&dqp->q_lru);
+               xfs_qm_dqfree_one(dqp);
+       }
+
+       return freed;
+}
+
+static unsigned long
+xfs_qm_shrink_count(
+       struct shrinker         *shrink,
+       struct shrink_control   *sc)
+{
+       struct xfs_quotainfo    *qi = container_of(shrink,
+                                       struct xfs_quotainfo, qi_shrinker);
+
+       return list_lru_count_node(&qi->qi_lru, sc->nid);
+}
+
 /*
  * This initializes all the quota information that's kept in the
  * mount structure
@@ -696,11 +831,18 @@ xfs_qm_init_quotainfo(
 
        qinf = mp->m_quotainfo = kmem_zalloc(sizeof(xfs_quotainfo_t), KM_SLEEP);
 
+       if ((error = list_lru_init(&qinf->qi_lru))) {
+               kmem_free(qinf);
+               mp->m_quotainfo = NULL;
+               return error;
+       }
+
        /*
         * See if quotainodes are setup, and if not, allocate them,
         * and change the superblock accordingly.
         */
        if ((error = xfs_qm_init_quotainos(mp))) {
+               list_lru_destroy(&qinf->qi_lru);
                kmem_free(qinf);
                mp->m_quotainfo = NULL;
                return error;
@@ -711,10 +853,6 @@ xfs_qm_init_quotainfo(
        INIT_RADIX_TREE(&qinf->qi_pquota_tree, GFP_NOFS);
        mutex_init(&qinf->qi_tree_lock);
 
-       INIT_LIST_HEAD(&qinf->qi_lru_list);
-       qinf->qi_lru_count = 0;
-       mutex_init(&qinf->qi_lru_lock);
-
        /* mutex used to serialize quotaoffs */
        mutex_init(&qinf->qi_quotaofflock);
 
@@ -779,8 +917,10 @@ xfs_qm_init_quotainfo(
                qinf->qi_rtbwarnlimit = XFS_QM_RTBWARNLIMIT;
        }
 
-       qinf->qi_shrinker.shrink = xfs_qm_shake;
+       qinf->qi_shrinker.count_objects = xfs_qm_shrink_count;
+       qinf->qi_shrinker.scan_objects = xfs_qm_shrink_scan;
        qinf->qi_shrinker.seeks = DEFAULT_SEEKS;
+       qinf->qi_shrinker.flags = SHRINKER_NUMA_AWARE;
        register_shrinker(&qinf->qi_shrinker);
        return 0;
 }
@@ -801,6 +941,7 @@ xfs_qm_destroy_quotainfo(
        ASSERT(qi != NULL);
 
        unregister_shrinker(&qi->qi_shrinker);
+       list_lru_destroy(&qi->qi_lru);
 
        if (qi->qi_uquotaip) {
                IRELE(qi->qi_uquotaip);
@@ -834,21 +975,52 @@ xfs_qm_qino_alloc(
        int             error;
        int             committed;
 
+       *ip = NULL;
+       /*
+        * With superblock that doesn't have separate pquotino, we
+        * share an inode between gquota and pquota. If the on-disk
+        * superblock has GQUOTA and the filesystem is now mounted
+        * with PQUOTA, just use sb_gquotino for sb_pquotino and
+        * vice-versa.
+        */
+       if (!xfs_sb_version_has_pquotino(&mp->m_sb) &&
+                       (flags & (XFS_QMOPT_PQUOTA|XFS_QMOPT_GQUOTA))) {
+               xfs_ino_t ino = NULLFSINO;
+
+               if ((flags & XFS_QMOPT_PQUOTA) &&
+                            (mp->m_sb.sb_gquotino != NULLFSINO)) {
+                       ino = mp->m_sb.sb_gquotino;
+                       ASSERT(mp->m_sb.sb_pquotino == NULLFSINO);
+               } else if ((flags & XFS_QMOPT_GQUOTA) &&
+                            (mp->m_sb.sb_pquotino != NULLFSINO)) {
+                       ino = mp->m_sb.sb_pquotino;
+                       ASSERT(mp->m_sb.sb_gquotino == NULLFSINO);
+               }
+               if (ino != NULLFSINO) {
+                       error = xfs_iget(mp, NULL, ino, 0, 0, ip);
+                       if (error)
+                               return error;
+                       mp->m_sb.sb_gquotino = NULLFSINO;
+                       mp->m_sb.sb_pquotino = NULLFSINO;
+               }
+       }
+
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QINOCREATE);
-       if ((error = xfs_trans_reserve(tp,
-                                     XFS_QM_QINOCREATE_SPACE_RES(mp),
-                                     XFS_CREATE_LOG_RES(mp), 0,
-                                     XFS_TRANS_PERM_LOG_RES,
-                                     XFS_CREATE_LOG_COUNT))) {
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_create,
+                                 XFS_QM_QINOCREATE_SPACE_RES(mp), 0);
+       if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
        }
 
-       error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip, &committed);
-       if (error) {
-               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
-                                XFS_TRANS_ABORT);
-               return error;
+       if (!*ip) {
+               error = xfs_dir_ialloc(&tp, NULL, S_IFREG, 1, 0, 0, 1, ip,
+                                                               &committed);
+               if (error) {
+                       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES |
+                                        XFS_TRANS_ABORT);
+                       return error;
+               }
        }
 
        /*
@@ -860,21 +1032,25 @@ xfs_qm_qino_alloc(
        if (flags & XFS_QMOPT_SBVERSION) {
                ASSERT(!xfs_sb_version_hasquota(&mp->m_sb));
                ASSERT((sbfields & (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                                  XFS_SB_GQUOTINO | XFS_SB_QFLAGS)) ==
-                      (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                       XFS_SB_GQUOTINO | XFS_SB_QFLAGS));
+                       XFS_SB_GQUOTINO | XFS_SB_PQUOTINO | XFS_SB_QFLAGS)) ==
+                               (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
+                                XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
+                                XFS_SB_QFLAGS));
 
                xfs_sb_version_addquota(&mp->m_sb);
                mp->m_sb.sb_uquotino = NULLFSINO;
                mp->m_sb.sb_gquotino = NULLFSINO;
+               mp->m_sb.sb_pquotino = NULLFSINO;
 
-               /* qflags will get updated _after_ quotacheck */
-               mp->m_sb.sb_qflags = 0;
+               /* qflags will get updated fully _after_ quotacheck */
+               mp->m_sb.sb_qflags = mp->m_qflags & XFS_ALL_QUOTA_ACCT;
        }
        if (flags & XFS_QMOPT_UQUOTA)
                mp->m_sb.sb_uquotino = (*ip)->i_ino;
-       else
+       else if (flags & XFS_QMOPT_GQUOTA)
                mp->m_sb.sb_gquotino = (*ip)->i_ino;
+       else
+               mp->m_sb.sb_pquotino = (*ip)->i_ino;
        spin_unlock(&mp->m_sb_lock);
        xfs_mod_sb(tp, sbfields);
 
@@ -1484,11 +1660,10 @@ xfs_qm_init_quotainos(
                        if (error)
                                goto error_rele;
                }
-               /* XXX: Use gquotino for now */
                if (XFS_IS_PQUOTA_ON(mp) &&
-                   mp->m_sb.sb_gquotino != NULLFSINO) {
-                       ASSERT(mp->m_sb.sb_gquotino > 0);
-                       error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+                   mp->m_sb.sb_pquotino != NULLFSINO) {
+                       ASSERT(mp->m_sb.sb_pquotino > 0);
+                       error = xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
                                             0, 0, &pip);
                        if (error)
                                goto error_rele;
@@ -1496,7 +1671,8 @@ xfs_qm_init_quotainos(
        } else {
                flags |= XFS_QMOPT_SBVERSION;
                sbflags |= (XFS_SB_VERSIONNUM | XFS_SB_UQUOTINO |
-                           XFS_SB_GQUOTINO | XFS_SB_QFLAGS);
+                           XFS_SB_GQUOTINO | XFS_SB_PQUOTINO |
+                           XFS_SB_QFLAGS);
        }
 
        /*
@@ -1524,9 +1700,8 @@ xfs_qm_init_quotainos(
                flags &= ~XFS_QMOPT_SBVERSION;
        }
        if (XFS_IS_PQUOTA_ON(mp) && pip == NULL) {
-               /* XXX: Use XFS_SB_GQUOTINO for now */
                error = xfs_qm_qino_alloc(mp, &pip,
-                                         sbflags | XFS_SB_GQUOTINO,
+                                         sbflags | XFS_SB_PQUOTINO,
                                          flags | XFS_QMOPT_PQUOTA);
                if (error)
                        goto error_rele;
@@ -1565,132 +1740,6 @@ xfs_qm_dqfree_one(
        xfs_qm_dqdestroy(dqp);
 }
 
-STATIC void
-xfs_qm_dqreclaim_one(
-       struct xfs_dquot        *dqp,
-       struct list_head        *buffer_list,
-       struct list_head        *dispose_list)
-{
-       struct xfs_mount        *mp = dqp->q_mount;
-       struct xfs_quotainfo    *qi = mp->m_quotainfo;
-       int                     error;
-
-       if (!xfs_dqlock_nowait(dqp))
-               goto out_move_tail;
-
-       /*
-        * This dquot has acquired a reference in the meantime remove it from
-        * the freelist and try again.
-        */
-       if (dqp->q_nrefs) {
-               xfs_dqunlock(dqp);
-
-               trace_xfs_dqreclaim_want(dqp);
-               XFS_STATS_INC(xs_qm_dqwants);
-
-               list_del_init(&dqp->q_lru);
-               qi->qi_lru_count--;
-               XFS_STATS_DEC(xs_qm_dquot_unused);
-               return;
-       }
-
-       /*
-        * Try to grab the flush lock. If this dquot is in the process of
-        * getting flushed to disk, we don't want to reclaim it.
-        */
-       if (!xfs_dqflock_nowait(dqp))
-               goto out_unlock_move_tail;
-
-       if (XFS_DQ_IS_DIRTY(dqp)) {
-               struct xfs_buf  *bp = NULL;
-
-               trace_xfs_dqreclaim_dirty(dqp);
-
-               error = xfs_qm_dqflush(dqp, &bp);
-               if (error) {
-                       xfs_warn(mp, "%s: dquot %p flush failed",
-                                __func__, dqp);
-                       goto out_unlock_move_tail;
-               }
-
-               xfs_buf_delwri_queue(bp, buffer_list);
-               xfs_buf_relse(bp);
-               /*
-                * Give the dquot another try on the freelist, as the
-                * flushing will take some time.
-                */
-               goto out_unlock_move_tail;
-       }
-       xfs_dqfunlock(dqp);
-
-       /*
-        * Prevent lookups now that we are past the point of no return.
-        */
-       dqp->dq_flags |= XFS_DQ_FREEING;
-       xfs_dqunlock(dqp);
-
-       ASSERT(dqp->q_nrefs == 0);
-       list_move_tail(&dqp->q_lru, dispose_list);
-       qi->qi_lru_count--;
-       XFS_STATS_DEC(xs_qm_dquot_unused);
-
-       trace_xfs_dqreclaim_done(dqp);
-       XFS_STATS_INC(xs_qm_dqreclaims);
-       return;
-
-       /*
-        * Move the dquot to the tail of the list so that we don't spin on it.
-        */
-out_unlock_move_tail:
-       xfs_dqunlock(dqp);
-out_move_tail:
-       list_move_tail(&dqp->q_lru, &qi->qi_lru_list);
-       trace_xfs_dqreclaim_busy(dqp);
-       XFS_STATS_INC(xs_qm_dqreclaim_misses);
-}
-
-STATIC int
-xfs_qm_shake(
-       struct shrinker         *shrink,
-       struct shrink_control   *sc)
-{
-       struct xfs_quotainfo    *qi =
-               container_of(shrink, struct xfs_quotainfo, qi_shrinker);
-       int                     nr_to_scan = sc->nr_to_scan;
-       LIST_HEAD               (buffer_list);
-       LIST_HEAD               (dispose_list);
-       struct xfs_dquot        *dqp;
-       int                     error;
-
-       if ((sc->gfp_mask & (__GFP_FS|__GFP_WAIT)) != (__GFP_FS|__GFP_WAIT))
-               return 0;
-       if (!nr_to_scan)
-               goto out;
-
-       mutex_lock(&qi->qi_lru_lock);
-       while (!list_empty(&qi->qi_lru_list)) {
-               if (nr_to_scan-- <= 0)
-                       break;
-               dqp = list_first_entry(&qi->qi_lru_list, struct xfs_dquot,
-                                      q_lru);
-               xfs_qm_dqreclaim_one(dqp, &buffer_list, &dispose_list);
-       }
-       mutex_unlock(&qi->qi_lru_lock);
-
-       error = xfs_buf_delwri_submit(&buffer_list);
-       if (error)
-               xfs_warn(NULL, "%s: dquot reclaim failed", __func__);
-
-       while (!list_empty(&dispose_list)) {
-               dqp = list_first_entry(&dispose_list, struct xfs_dquot, q_lru);
-               list_del_init(&dqp->q_lru);
-               xfs_qm_dqfree_one(dqp);
-       }
-
-out:
-       return (qi->qi_lru_count / 100) * sysctl_vfs_cache_pressure;
-}
-
 /*
  * Start a transaction and write the incore superblock changes to
  * disk. flags parameter indicates which fields have changed.
@@ -1704,8 +1753,7 @@ xfs_qm_write_sb_changes(
        int             error;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SBCHANGE);
-       error = xfs_trans_reserve(tp, 0, XFS_QM_SBCHANGE_LOG_RES(mp),
-                                 0, 0, XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_sbchange, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return error;
@@ -1734,8 +1782,8 @@ xfs_qm_write_sb_changes(
 int
 xfs_qm_vop_dqalloc(
        struct xfs_inode        *ip,
-       uid_t                   uid,
-       gid_t                   gid,
+       xfs_dqid_t              uid,
+       xfs_dqid_t              gid,
        prid_t                  prid,
        uint                    flags,
        struct xfs_dquot        **O_udqpp,
@@ -1782,7 +1830,7 @@ xfs_qm_vop_dqalloc(
                         * holding ilock.
                         */
                        xfs_iunlock(ip, lockflags);
-                       error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t) uid,
+                       error = xfs_qm_dqget(mp, NULL, uid,
                                                 XFS_DQ_USER,
                                                 XFS_QMOPT_DQALLOC |
                                                 XFS_QMOPT_DOWARN,
@@ -1809,7 +1857,7 @@ xfs_qm_vop_dqalloc(
        if ((flags & XFS_QMOPT_GQUOTA) && XFS_IS_GQUOTA_ON(mp)) {
                if (ip->i_d.di_gid != gid) {
                        xfs_iunlock(ip, lockflags);
-                       error = xfs_qm_dqget(mp, NULL, (xfs_dqid_t)gid,
+                       error = xfs_qm_dqget(mp, NULL, gid,
                                                 XFS_DQ_GROUP,
                                                 XFS_QMOPT_DQALLOC |
                                                 XFS_QMOPT_DOWARN,
@@ -1943,7 +1991,7 @@ xfs_qm_vop_chown_reserve(
                        XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS;
 
        if (XFS_IS_UQUOTA_ON(mp) && udqp &&
-           ip->i_d.di_uid != (uid_t)be32_to_cpu(udqp->q_core.d_id)) {
+           ip->i_d.di_uid != be32_to_cpu(udqp->q_core.d_id)) {
                udq_delblks = udqp;
                /*
                 * If there are delayed allocation blocks, then we have to
index 579d6a02a5b6ec5fd2e21c503f4ada8b6dfa54d6..2b602df9c242d3c3efe7b6841abe5fdbee28d00e 100644 (file)
@@ -49,9 +49,7 @@ typedef struct xfs_quotainfo {
        struct xfs_inode        *qi_uquotaip;   /* user quota inode */
        struct xfs_inode        *qi_gquotaip;   /* group quota inode */
        struct xfs_inode        *qi_pquotaip;   /* project quota inode */
-       struct list_head qi_lru_list;
-       struct mutex     qi_lru_lock;
-       int              qi_lru_count;
+       struct list_lru  qi_lru;
        int              qi_dquots;
        time_t           qi_btimelimit;  /* limit for blks timer */
        time_t           qi_itimelimit;  /* limit for inodes timer */
@@ -160,6 +158,8 @@ extern int          xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint,
                                        struct fs_disk_quota *);
 extern int             xfs_qm_scall_getqstat(struct xfs_mount *,
                                        struct fs_quota_stat *);
+extern int             xfs_qm_scall_getqstatv(struct xfs_mount *,
+                                       struct fs_quota_statv *);
 extern int             xfs_qm_scall_quotaon(struct xfs_mount *, uint);
 extern int             xfs_qm_scall_quotaoff(struct xfs_mount *, uint);
 
index 437a52d91f6d91ce9f48acbfc5a9928a9ee366ed..3af50ccdfac1a10da858ef26e80b040ad4a474f1 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
index e4f8b2d6f38ba1960beefe35cbd15b0066f530cf..8174aad0b38813ec836ea044d9a1b7b4dc06f300 100644 (file)
@@ -20,6 +20,7 @@
 
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
@@ -37,7 +38,6 @@
 #include "xfs_error.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
-#include "xfs_utils.h"
 #include "xfs_qm.h"
 #include "xfs_trace.h"
 #include "xfs_icache.h"
@@ -247,9 +247,7 @@ xfs_qm_scall_trunc_qfile(
        xfs_ilock(ip, XFS_IOLOCK_EXCL);
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_TRUNCATE_FILE);
-       error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
-                                 XFS_TRANS_PERM_LOG_RES,
-                                 XFS_ITRUNCATE_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                xfs_iunlock(ip, XFS_IOLOCK_EXCL);
@@ -296,8 +294,10 @@ xfs_qm_scall_trunc_qfiles(
 
        if (flags & XFS_DQ_USER)
                error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
-       if (flags & (XFS_DQ_GROUP|XFS_DQ_PROJ))
+       if (flags & XFS_DQ_GROUP)
                error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
+       if (flags & XFS_DQ_PROJ)
+               error2 = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);
 
        return error ? error : error2;
 }
@@ -404,6 +404,7 @@ xfs_qm_scall_quotaon(
 
 /*
  * Return quota status information, such as uquota-off, enforcements, etc.
+ * for Q_XGETQSTAT command.
  */
 int
 xfs_qm_scall_getqstat(
@@ -413,8 +414,10 @@ xfs_qm_scall_getqstat(
        struct xfs_quotainfo    *q = mp->m_quotainfo;
        struct xfs_inode        *uip = NULL;
        struct xfs_inode        *gip = NULL;
+       struct xfs_inode        *pip = NULL;
        bool                    tempuqip = false;
        bool                    tempgqip = false;
+       bool                    temppqip = false;
 
        memset(out, 0, sizeof(fs_quota_stat_t));
 
@@ -424,16 +427,106 @@ xfs_qm_scall_getqstat(
                out->qs_gquota.qfs_ino = NULLFSINO;
                return (0);
        }
+
+       out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
+                                                       (XFS_ALL_QUOTA_ACCT|
+                                                        XFS_ALL_QUOTA_ENFD));
+       if (q) {
+               uip = q->qi_uquotaip;
+               gip = q->qi_gquotaip;
+               pip = q->qi_pquotaip;
+       }
+       if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
+                                       0, 0, &uip) == 0)
+                       tempuqip = true;
+       }
+       if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
+                                       0, 0, &gip) == 0)
+                       tempgqip = true;
+       }
+       /*
+        * Q_XGETQSTAT doesn't have room for both group and project quotas.
+        * So, allow the project quota values to be copied out only if
+        * there is no group quota information available.
+        */
+       if (!gip) {
+               if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
+                       if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
+                                               0, 0, &pip) == 0)
+                               temppqip = true;
+               }
+       } else
+               pip = NULL;
+       if (uip) {
+               out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
+               out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
+               out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
+               if (tempuqip)
+                       IRELE(uip);
+       }
+
+       if (gip) {
+               out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+               out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
+               out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
+               if (tempgqip)
+                       IRELE(gip);
+       }
+       if (pip) {
+               out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+               out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks;
+               out->qs_gquota.qfs_nextents = pip->i_d.di_nextents;
+               if (temppqip)
+                       IRELE(pip);
+       }
+       if (q) {
+               out->qs_incoredqs = q->qi_dquots;
+               out->qs_btimelimit = q->qi_btimelimit;
+               out->qs_itimelimit = q->qi_itimelimit;
+               out->qs_rtbtimelimit = q->qi_rtbtimelimit;
+               out->qs_bwarnlimit = q->qi_bwarnlimit;
+               out->qs_iwarnlimit = q->qi_iwarnlimit;
+       }
+       return 0;
+}
+
+/*
+ * Return quota status information, such as uquota-off, enforcements, etc.
+ * for Q_XGETQSTATV command, to support separate project quota field.
+ */
+int
+xfs_qm_scall_getqstatv(
+       struct xfs_mount        *mp,
+       struct fs_quota_statv   *out)
+{
+       struct xfs_quotainfo    *q = mp->m_quotainfo;
+       struct xfs_inode        *uip = NULL;
+       struct xfs_inode        *gip = NULL;
+       struct xfs_inode        *pip = NULL;
+       bool                    tempuqip = false;
+       bool                    tempgqip = false;
+       bool                    temppqip = false;
+
+       if (!xfs_sb_version_hasquota(&mp->m_sb)) {
+               out->qs_uquota.qfs_ino = NULLFSINO;
+               out->qs_gquota.qfs_ino = NULLFSINO;
+               out->qs_pquota.qfs_ino = NULLFSINO;
+               return (0);
+       }
+
        out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
                                                        (XFS_ALL_QUOTA_ACCT|
                                                         XFS_ALL_QUOTA_ENFD));
-       out->qs_pad = 0;
        out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
        out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
+       out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;
 
        if (q) {
                uip = q->qi_uquotaip;
                gip = q->qi_gquotaip;
+               pip = q->qi_pquotaip;
        }
        if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
                if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
@@ -445,18 +538,30 @@ xfs_qm_scall_getqstat(
                                        0, 0, &gip) == 0)
                        tempgqip = true;
        }
+       if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
+               if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
+                                       0, 0, &pip) == 0)
+                       temppqip = true;
+       }
        if (uip) {
                out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
                out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
                if (tempuqip)
                        IRELE(uip);
        }
+
        if (gip) {
                out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
                out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
                if (tempgqip)
                        IRELE(gip);
        }
+       if (pip) {
+               out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
+               out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
+               if (temppqip)
+                       IRELE(pip);
+       }
        if (q) {
                out->qs_incoredqs = q->qi_dquots;
                out->qs_btimelimit = q->qi_btimelimit;
@@ -515,8 +620,7 @@ xfs_qm_scall_setqlim(
        xfs_dqunlock(dqp);
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM);
-       error = xfs_trans_reserve(tp, 0, XFS_QM_SETQLIM_LOG_RES(mp),
-                                 0, 0, XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_setqlim, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                goto out_rele;
@@ -650,8 +754,7 @@ xfs_qm_log_quotaoff_end(
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END);
 
-       error = xfs_trans_reserve(tp, 0, XFS_QM_QUOTAOFF_END_LOG_RES(mp),
-                                 0, 0, XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_equotaoff, 0, 0);
        if (error) {
                xfs_trans_cancel(tp, 0);
                return (error);
@@ -684,8 +787,7 @@ xfs_qm_log_quotaoff(
        uint                    oldsbqflag=0;
 
        tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF);
-       error = xfs_trans_reserve(tp, 0, XFS_QM_QUOTAOFF_LOG_RES(mp),
-                                 0, 0, XFS_DEFAULT_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_qm_quotaoff, 0, 0);
        if (error)
                goto error0;
 
index b14f42c714b609b95eab2b993805a7e4e4e73c24..e7d84d2d86830a25a5cd9778521766d4a592c45b 100644 (file)
 #ifndef __XFS_QUOTA_H__
 #define __XFS_QUOTA_H__
 
-struct xfs_trans;
-
-/*
- * The ondisk form of a dquot structure.
- */
-#define XFS_DQUOT_MAGIC                0x4451          /* 'DQ' */
-#define XFS_DQUOT_VERSION      (u_int8_t)0x01  /* latest version number */
-
-/*
- * uid_t and gid_t are hard-coded to 32 bits in the inode.
- * Hence, an 'id' in a dquot is 32 bits..
- */
-typedef __uint32_t     xfs_dqid_t;
-
-/*
- * Even though users may not have quota limits occupying all 64-bits,
- * they may need 64-bit accounting. Hence, 64-bit quota-counters,
- * and quota-limits. This is a waste in the common case, but hey ...
- */
-typedef __uint64_t     xfs_qcnt_t;
-typedef __uint16_t     xfs_qwarncnt_t;
-
-/*
- * This is the main portion of the on-disk representation of quota
- * information for a user. This is the q_core of the xfs_dquot_t that
- * is kept in kernel memory. We pad this with some more expansion room
- * to construct the on disk structure.
- */
-typedef struct xfs_disk_dquot {
-       __be16          d_magic;        /* dquot magic = XFS_DQUOT_MAGIC */
-       __u8            d_version;      /* dquot version */
-       __u8            d_flags;        /* XFS_DQ_USER/PROJ/GROUP */
-       __be32          d_id;           /* user,project,group id */
-       __be64          d_blk_hardlimit;/* absolute limit on disk blks */
-       __be64          d_blk_softlimit;/* preferred limit on disk blks */
-       __be64          d_ino_hardlimit;/* maximum # allocated inodes */
-       __be64          d_ino_softlimit;/* preferred inode limit */
-       __be64          d_bcount;       /* disk blocks owned by the user */
-       __be64          d_icount;       /* inodes owned by the user */
-       __be32          d_itimer;       /* zero if within inode limits if not,
-                                          this is when we refuse service */
-       __be32          d_btimer;       /* similar to above; for disk blocks */
-       __be16          d_iwarns;       /* warnings issued wrt num inodes */
-       __be16          d_bwarns;       /* warnings issued wrt disk blocks */
-       __be32          d_pad0;         /* 64 bit align */
-       __be64          d_rtb_hardlimit;/* absolute limit on realtime blks */
-       __be64          d_rtb_softlimit;/* preferred limit on RT disk blks */
-       __be64          d_rtbcount;     /* realtime blocks owned */
-       __be32          d_rtbtimer;     /* similar to above; for RT disk blocks */
-       __be16          d_rtbwarns;     /* warnings issued wrt RT disk blocks */
-       __be16          d_pad;
-} xfs_disk_dquot_t;
-
-/*
- * This is what goes on disk. This is separated from the xfs_disk_dquot because
- * carrying the unnecessary padding would be a waste of memory.
- */
-typedef struct xfs_dqblk {
-       xfs_disk_dquot_t  dd_diskdq;    /* portion that lives incore as well */
-       char              dd_fill[4];   /* filling for posterity */
-
-       /*
-        * These two are only present on filesystems with the CRC bits set.
-        */
-       __be32            dd_crc;       /* checksum */
-       __be64            dd_lsn;       /* last modification in log */
-       uuid_t            dd_uuid;      /* location information */
-} xfs_dqblk_t;
-
-#define XFS_DQUOT_CRC_OFF      offsetof(struct xfs_dqblk, dd_crc)
-
-/*
- * flags for q_flags field in the dquot.
- */
-#define XFS_DQ_USER            0x0001          /* a user quota */
-#define XFS_DQ_PROJ            0x0002          /* project quota */
-#define XFS_DQ_GROUP           0x0004          /* a group quota */
-#define XFS_DQ_DIRTY           0x0008          /* dquot is dirty */
-#define XFS_DQ_FREEING         0x0010          /* dquot is beeing torn down */
-
-#define XFS_DQ_ALLTYPES                (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
-
-#define XFS_DQ_FLAGS \
-       { XFS_DQ_USER,          "USER" }, \
-       { XFS_DQ_PROJ,          "PROJ" }, \
-       { XFS_DQ_GROUP,         "GROUP" }, \
-       { XFS_DQ_DIRTY,         "DIRTY" }, \
-       { XFS_DQ_FREEING,       "FREEING" }
-
-/*
- * We have the possibility of all three quota types being active at once, and
- * hence free space modification requires modification of all three current
- * dquots in a single transaction. For this case we need to have a reservation
- * of at least 3 dquots.
- *
- * However, a chmod operation can change both UID and GID in a single
- * transaction, resulting in requiring {old, new} x {uid, gid} dquots to be
- * modified. Hence for this case we need to reserve space for at least 4 dquots.
- *
- * And in the worst case, there's a rename operation that can be modifying up to
- * 4 inodes with dquots attached to them. In reality, the only inodes that can
- * have their dquots modified are the source and destination directory inodes
- * due to directory name creation and removal. That can require space allocation
- * and/or freeing on both directory inodes, and hence all three dquots on each
- * inode can be modified. And if the directories are world writeable, all the
- * dquots can be unique and so 6 dquots can be modified....
- *
- * And, of course, we also need to take into account the dquot log format item
- * used to describe each dquot.
- */
-#define XFS_DQUOT_LOGRES(mp)   \
-       ((sizeof(struct xfs_dq_logformat) + sizeof(struct xfs_disk_dquot)) * 6)
-
-/*
- * These are the structures used to lay out dquots and quotaoff
- * records on the log. Quite similar to those of inodes.
- */
-
-/*
- * log format struct for dquots.
- * The first two fields must be the type and size fitting into
- * 32 bits : log_recovery code assumes that.
- */
-typedef struct xfs_dq_logformat {
-       __uint16_t              qlf_type;      /* dquot log item type */
-       __uint16_t              qlf_size;      /* size of this item */
-       xfs_dqid_t              qlf_id;        /* usr/grp/proj id : 32 bits */
-       __int64_t               qlf_blkno;     /* blkno of dquot buffer */
-       __int32_t               qlf_len;       /* len of dquot buffer */
-       __uint32_t              qlf_boffset;   /* off of dquot in buffer */
-} xfs_dq_logformat_t;
-
-/*
- * log format struct for QUOTAOFF records.
- * The first two fields must be the type and size fitting into
- * 32 bits : log_recovery code assumes that.
- * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer
- * to the first and ensures that the first logitem is taken out of the AIL
- * only when the last one is securely committed.
- */
-typedef struct xfs_qoff_logformat {
-       unsigned short          qf_type;        /* quotaoff log item type */
-       unsigned short          qf_size;        /* size of this item */
-       unsigned int            qf_flags;       /* USR and/or GRP */
-       char                    qf_pad[12];     /* padding for future */
-} xfs_qoff_logformat_t;
-
-
-/*
- * Disk quotas status in m_qflags, and also sb_qflags. 16 bits.
- */
-#define XFS_UQUOTA_ACCT        0x0001  /* user quota accounting ON */
-#define XFS_UQUOTA_ENFD        0x0002  /* user quota limits enforced */
-#define XFS_UQUOTA_CHKD        0x0004  /* quotacheck run on usr quotas */
-#define XFS_PQUOTA_ACCT        0x0008  /* project quota accounting ON */
-#define XFS_OQUOTA_ENFD        0x0010  /* other (grp/prj) quota limits enforced */
-#define XFS_OQUOTA_CHKD        0x0020  /* quotacheck run on other (grp/prj) quotas */
-#define XFS_GQUOTA_ACCT        0x0040  /* group quota accounting ON */
-
-/*
- * Conversion to and from the combined OQUOTA flag (if necessary)
- * is done only in xfs_sb_qflags_to_disk() and xfs_sb_qflags_from_disk()
- */
-#define XFS_GQUOTA_ENFD        0x0080  /* group quota limits enforced */
-#define XFS_GQUOTA_CHKD        0x0100  /* quotacheck run on group quotas */
-#define XFS_PQUOTA_ENFD        0x0200  /* project quota limits enforced */
-#define XFS_PQUOTA_CHKD        0x0400  /* quotacheck run on project quotas */
-
-/*
- * Quota Accounting/Enforcement flags
- */
-#define XFS_ALL_QUOTA_ACCT     \
-               (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT)
-#define XFS_ALL_QUOTA_ENFD     \
-               (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD)
-#define XFS_ALL_QUOTA_CHKD     \
-               (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD)
-
-#define XFS_IS_QUOTA_RUNNING(mp)       ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
-#define XFS_IS_UQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_UQUOTA_ACCT)
-#define XFS_IS_PQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_PQUOTA_ACCT)
-#define XFS_IS_GQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_GQUOTA_ACCT)
-#define XFS_IS_UQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_UQUOTA_ENFD)
-#define XFS_IS_GQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_GQUOTA_ENFD)
-#define XFS_IS_PQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_PQUOTA_ENFD)
-
-/*
- * Incore only flags for quotaoff - these bits get cleared when quota(s)
- * are in the process of getting turned off. These flags are in m_qflags but
- * never in sb_qflags.
- */
-#define XFS_UQUOTA_ACTIVE      0x1000  /* uquotas are being turned off */
-#define XFS_GQUOTA_ACTIVE      0x2000  /* gquotas are being turned off */
-#define XFS_PQUOTA_ACTIVE      0x4000  /* pquotas are being turned off */
-#define XFS_ALL_QUOTA_ACTIVE   \
-       (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE)
+#include "xfs_quota_defs.h"
 
 /*
- * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees
- * quota will be not be switched off as long as that inode lock is held.
+ * Kernel only quota definitions and functions
  */
-#define XFS_IS_QUOTA_ON(mp)    ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \
-                                                  XFS_GQUOTA_ACTIVE | \
-                                                  XFS_PQUOTA_ACTIVE))
-#define XFS_IS_OQUOTA_ON(mp)   ((mp)->m_qflags & (XFS_GQUOTA_ACTIVE | \
-                                                  XFS_PQUOTA_ACTIVE))
-#define XFS_IS_UQUOTA_ON(mp)   ((mp)->m_qflags & XFS_UQUOTA_ACTIVE)
-#define XFS_IS_GQUOTA_ON(mp)   ((mp)->m_qflags & XFS_GQUOTA_ACTIVE)
-#define XFS_IS_PQUOTA_ON(mp)   ((mp)->m_qflags & XFS_PQUOTA_ACTIVE)
 
-/*
- * Flags to tell various functions what to do. Not all of these are meaningful
- * to a single function. None of these XFS_QMOPT_* flags are meant to have
- * persistent values (ie. their values can and will change between versions)
- */
-#define XFS_QMOPT_DQALLOC      0x0000002 /* alloc dquot ondisk if needed */
-#define XFS_QMOPT_UQUOTA       0x0000004 /* user dquot requested */
-#define XFS_QMOPT_PQUOTA       0x0000008 /* project dquot requested */
-#define XFS_QMOPT_FORCE_RES    0x0000010 /* ignore quota limits */
-#define XFS_QMOPT_SBVERSION    0x0000040 /* change superblock version num */
-#define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if needed */
-#define XFS_QMOPT_DQREPAIR     0x0001000 /* repair dquot if damaged */
-#define XFS_QMOPT_GQUOTA       0x0002000 /* group dquot requested */
-#define XFS_QMOPT_ENOSPC       0x0004000 /* enospc instead of edquot (prj) */
-
-/*
- * flags to xfs_trans_mod_dquot to indicate which field needs to be
- * modified.
- */
-#define XFS_QMOPT_RES_REGBLKS  0x0010000
-#define XFS_QMOPT_RES_RTBLKS   0x0020000
-#define XFS_QMOPT_BCOUNT       0x0040000
-#define XFS_QMOPT_ICOUNT       0x0080000
-#define XFS_QMOPT_RTBCOUNT     0x0100000
-#define XFS_QMOPT_DELBCOUNT    0x0200000
-#define XFS_QMOPT_DELRTBCOUNT  0x0400000
-#define XFS_QMOPT_RES_INOS     0x0800000
-
-/*
- * flags for dqalloc.
- */
-#define XFS_QMOPT_INHERIT      0x1000000
-
-/*
- * flags to xfs_trans_mod_dquot.
- */
-#define XFS_TRANS_DQ_RES_BLKS  XFS_QMOPT_RES_REGBLKS
-#define XFS_TRANS_DQ_RES_RTBLKS        XFS_QMOPT_RES_RTBLKS
-#define XFS_TRANS_DQ_RES_INOS  XFS_QMOPT_RES_INOS
-#define XFS_TRANS_DQ_BCOUNT    XFS_QMOPT_BCOUNT
-#define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT
-#define XFS_TRANS_DQ_ICOUNT    XFS_QMOPT_ICOUNT
-#define XFS_TRANS_DQ_RTBCOUNT  XFS_QMOPT_RTBCOUNT
-#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT
-
-
-#define XFS_QMOPT_QUOTALL      \
-               (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA)
-#define XFS_QMOPT_RESBLK_MASK  (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
+struct xfs_trans;
 
-#ifdef __KERNEL__
 /*
  * This check is done typically without holding the inode lock;
  * that may seem racy, but it is harmless in the context that it is used.
@@ -301,13 +48,6 @@ typedef struct xfs_qoff_logformat {
         (XFS_IS_PQUOTA_ON(mp) && \
                (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0))
 
-#define XFS_MOUNT_QUOTA_ALL    (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\
-                                XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\
-                                XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\
-                                XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD|\
-                                XFS_PQUOTA_CHKD)
-
-
 /*
  * The structure kept inside the xfs_trans_t keep track of dquot changes
  * within a transaction and apply them later.
@@ -340,8 +80,9 @@ extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
                struct xfs_mount *, struct xfs_dquot *,
                struct xfs_dquot *, struct xfs_dquot *, long, long, uint);
 
-extern int xfs_qm_vop_dqalloc(struct xfs_inode *, uid_t, gid_t, prid_t, uint,
-               struct xfs_dquot **, struct xfs_dquot **, struct xfs_dquot **);
+extern int xfs_qm_vop_dqalloc(struct xfs_inode *, xfs_dqid_t, xfs_dqid_t,
+               prid_t, uint, struct xfs_dquot **, struct xfs_dquot **,
+               struct xfs_dquot **);
 extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *,
                struct xfs_dquot *, struct xfs_dquot *, struct xfs_dquot *);
 extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **);
@@ -362,9 +103,9 @@ extern void xfs_qm_unmount_quotas(struct xfs_mount *);
 
 #else
 static inline int
-xfs_qm_vop_dqalloc(struct xfs_inode *ip, uid_t uid, gid_t gid, prid_t prid,
-               uint flags, struct xfs_dquot **udqp, struct xfs_dquot **gdqp,
-               struct xfs_dquot **pdqp)
+xfs_qm_vop_dqalloc(struct xfs_inode *ip, xfs_dqid_t uid, xfs_dqid_t gid,
+               prid_t prid, uint flags, struct xfs_dquot **udqp,
+               struct xfs_dquot **gdqp, struct xfs_dquot **pdqp)
 {
        *udqp = NULL;
        *gdqp = NULL;
@@ -415,5 +156,4 @@ extern int xfs_mount_reset_sbqflags(struct xfs_mount *);
 
 extern const struct xfs_buf_ops xfs_dquot_buf_ops;
 
-#endif /* __KERNEL__ */
 #endif /* __XFS_QUOTA_H__ */
diff --git a/fs/xfs/xfs_quota_defs.h b/fs/xfs/xfs_quota_defs.h
new file mode 100644 (file)
index 0000000..e6b0d6e
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, 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
+ */
+#ifndef __XFS_QUOTA_DEFS_H__
+#define __XFS_QUOTA_DEFS_H__
+
+/*
+ * Quota definitions shared between user and kernel source trees.
+ */
+
+/*
+ * Even though users may not have quota limits occupying all 64-bits,
+ * they may need 64-bit accounting. Hence, 64-bit quota-counters,
+ * and quota-limits. This is a waste in the common case, but hey ...
+ */
+typedef __uint64_t     xfs_qcnt_t;
+typedef __uint16_t     xfs_qwarncnt_t;
+
+/*
+ * flags for q_flags field in the dquot.
+ */
+#define XFS_DQ_USER            0x0001          /* a user quota */
+#define XFS_DQ_PROJ            0x0002          /* project quota */
+#define XFS_DQ_GROUP           0x0004          /* a group quota */
+#define XFS_DQ_DIRTY           0x0008          /* dquot is dirty */
+#define XFS_DQ_FREEING         0x0010          /* dquot is beeing torn down */
+
+#define XFS_DQ_ALLTYPES                (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP)
+
+#define XFS_DQ_FLAGS \
+       { XFS_DQ_USER,          "USER" }, \
+       { XFS_DQ_PROJ,          "PROJ" }, \
+       { XFS_DQ_GROUP,         "GROUP" }, \
+       { XFS_DQ_DIRTY,         "DIRTY" }, \
+       { XFS_DQ_FREEING,       "FREEING" }
+
+/*
+ * We have the possibility of all three quota types being active at once, and
+ * hence free space modification requires modification of all three current
+ * dquots in a single transaction. For this case we need to have a reservation
+ * of at least 3 dquots.
+ *
+ * However, a chmod operation can change both UID and GID in a single
+ * transaction, resulting in requiring {old, new} x {uid, gid} dquots to be
+ * modified. Hence for this case we need to reserve space for at least 4 dquots.
+ *
+ * And in the worst case, there's a rename operation that can be modifying up to
+ * 4 inodes with dquots attached to them. In reality, the only inodes that can
+ * have their dquots modified are the source and destination directory inodes
+ * due to directory name creation and removal. That can require space allocation
+ * and/or freeing on both directory inodes, and hence all three dquots on each
+ * inode can be modified. And if the directories are world writeable, all the
+ * dquots can be unique and so 6 dquots can be modified....
+ *
+ * And, of course, we also need to take into account the dquot log format item
+ * used to describe each dquot.
+ */
+#define XFS_DQUOT_LOGRES(mp)   \
+       ((sizeof(struct xfs_dq_logformat) + sizeof(struct xfs_disk_dquot)) * 6)
+
+#define XFS_IS_QUOTA_RUNNING(mp)       ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT)
+#define XFS_IS_UQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_UQUOTA_ACCT)
+#define XFS_IS_PQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_PQUOTA_ACCT)
+#define XFS_IS_GQUOTA_RUNNING(mp)      ((mp)->m_qflags & XFS_GQUOTA_ACCT)
+#define XFS_IS_UQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_UQUOTA_ENFD)
+#define XFS_IS_GQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_GQUOTA_ENFD)
+#define XFS_IS_PQUOTA_ENFORCED(mp)     ((mp)->m_qflags & XFS_PQUOTA_ENFD)
+
+/*
+ * Incore only flags for quotaoff - these bits get cleared when quota(s)
+ * are in the process of getting turned off. These flags are in m_qflags but
+ * never in sb_qflags.
+ */
+#define XFS_UQUOTA_ACTIVE      0x1000  /* uquotas are being turned off */
+#define XFS_GQUOTA_ACTIVE      0x2000  /* gquotas are being turned off */
+#define XFS_PQUOTA_ACTIVE      0x4000  /* pquotas are being turned off */
+#define XFS_ALL_QUOTA_ACTIVE   \
+       (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE)
+
+/*
+ * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees
+ * quota will be not be switched off as long as that inode lock is held.
+ */
+#define XFS_IS_QUOTA_ON(mp)    ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \
+                                                  XFS_GQUOTA_ACTIVE | \
+                                                  XFS_PQUOTA_ACTIVE))
+#define XFS_IS_OQUOTA_ON(mp)   ((mp)->m_qflags & (XFS_GQUOTA_ACTIVE | \
+                                                  XFS_PQUOTA_ACTIVE))
+#define XFS_IS_UQUOTA_ON(mp)   ((mp)->m_qflags & XFS_UQUOTA_ACTIVE)
+#define XFS_IS_GQUOTA_ON(mp)   ((mp)->m_qflags & XFS_GQUOTA_ACTIVE)
+#define XFS_IS_PQUOTA_ON(mp)   ((mp)->m_qflags & XFS_PQUOTA_ACTIVE)
+
+/*
+ * Flags to tell various functions what to do. Not all of these are meaningful
+ * to a single function. None of these XFS_QMOPT_* flags are meant to have
+ * persistent values (ie. their values can and will change between versions)
+ */
+#define XFS_QMOPT_DQALLOC      0x0000002 /* alloc dquot ondisk if needed */
+#define XFS_QMOPT_UQUOTA       0x0000004 /* user dquot requested */
+#define XFS_QMOPT_PQUOTA       0x0000008 /* project dquot requested */
+#define XFS_QMOPT_FORCE_RES    0x0000010 /* ignore quota limits */
+#define XFS_QMOPT_SBVERSION    0x0000040 /* change superblock version num */
+#define XFS_QMOPT_DOWARN        0x0000400 /* increase warning cnt if needed */
+#define XFS_QMOPT_DQREPAIR     0x0001000 /* repair dquot if damaged */
+#define XFS_QMOPT_GQUOTA       0x0002000 /* group dquot requested */
+#define XFS_QMOPT_ENOSPC       0x0004000 /* enospc instead of edquot (prj) */
+
+/*
+ * flags to xfs_trans_mod_dquot to indicate which field needs to be
+ * modified.
+ */
+#define XFS_QMOPT_RES_REGBLKS  0x0010000
+#define XFS_QMOPT_RES_RTBLKS   0x0020000
+#define XFS_QMOPT_BCOUNT       0x0040000
+#define XFS_QMOPT_ICOUNT       0x0080000
+#define XFS_QMOPT_RTBCOUNT     0x0100000
+#define XFS_QMOPT_DELBCOUNT    0x0200000
+#define XFS_QMOPT_DELRTBCOUNT  0x0400000
+#define XFS_QMOPT_RES_INOS     0x0800000
+
+/*
+ * flags for dqalloc.
+ */
+#define XFS_QMOPT_INHERIT      0x1000000
+
+/*
+ * flags to xfs_trans_mod_dquot.
+ */
+#define XFS_TRANS_DQ_RES_BLKS  XFS_QMOPT_RES_REGBLKS
+#define XFS_TRANS_DQ_RES_RTBLKS        XFS_QMOPT_RES_RTBLKS
+#define XFS_TRANS_DQ_RES_INOS  XFS_QMOPT_RES_INOS
+#define XFS_TRANS_DQ_BCOUNT    XFS_QMOPT_BCOUNT
+#define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT
+#define XFS_TRANS_DQ_ICOUNT    XFS_QMOPT_ICOUNT
+#define XFS_TRANS_DQ_RTBCOUNT  XFS_QMOPT_RTBCOUNT
+#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT
+
+
+#define XFS_QMOPT_QUOTALL      \
+               (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA)
+#define XFS_QMOPT_RESBLK_MASK  (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS)
+
+#endif /* __XFS_QUOTA_H__ */
index 20e30f93b0c7dab8b548527c46634c49486e02cd..1326d81596c2920b27f45021b67b76979e5ef387 100644 (file)
  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 #include "xfs.h"
-#include "xfs_sb.h"
+#include "xfs_format.h"
+#include "xfs_trans_resv.h"
 #include "xfs_log.h"
+#include "xfs_sb.h"
 #include "xfs_ag.h"
 #include "xfs_mount.h"
 #include "xfs_quota.h"
@@ -53,6 +55,18 @@ xfs_fs_get_xstate(
        return -xfs_qm_scall_getqstat(mp, fqs);
 }
 
+STATIC int
+xfs_fs_get_xstatev(
+       struct super_block      *sb,
+       struct fs_quota_statv   *fqs)
+{
+       struct xfs_mount        *mp = XFS_M(sb);
+
+       if (!XFS_IS_QUOTA_RUNNING(mp))
+               return -ENOSYS;
+       return -xfs_qm_scall_getqstatv(mp, fqs);
+}
+
 STATIC int
 xfs_fs_set_xstate(
        struct super_block      *sb,
@@ -133,6 +147,7 @@ xfs_fs_set_dqblk(
 }
 
 const struct quotactl_ops xfs_quotactl_operations = {
+       .get_xstatev            = xfs_fs_get_xstatev,
        .get_xstate             = xfs_fs_get_xstate,
        .set_xstate             = xfs_fs_set_xstate,
        .get_dqblk              = xfs_fs_get_dqblk,
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
deleted file mode 100644 (file)
index 30ff5f4..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright (c) 2000-2003,2005 Silicon Graphics, 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_log.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_mount.h"
-#include "xfs_da_btree.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_bmap.h"
-#include "xfs_error.h"
-#include "xfs_quota.h"
-#include "xfs_utils.h"
-#include "xfs_trans_space.h"
-#include "xfs_vnodeops.h"
-#include "xfs_trace.h"
-
-
-/*
- * Enter all inodes for a rename transaction into a sorted array.
- */
-STATIC void
-xfs_sort_for_rename(
-       xfs_inode_t     *dp1,   /* in: old (source) directory inode */
-       xfs_inode_t     *dp2,   /* in: new (target) directory inode */
-       xfs_inode_t     *ip1,   /* in: inode of old entry */
-       xfs_inode_t     *ip2,   /* in: inode of new entry, if it
-                                  already exists, NULL otherwise. */
-       xfs_inode_t     **i_tab,/* out: array of inode returned, sorted */
-       int             *num_inodes)  /* out: number of inodes in array */
-{
-       xfs_inode_t             *temp;
-       int                     i, j;
-
-       /*
-        * i_tab contains a list of pointers to inodes.  We initialize
-        * the table here & we'll sort it.  We will then use it to
-        * order the acquisition of the inode locks.
-        *
-        * Note that the table may contain duplicates.  e.g., dp1 == dp2.
-        */
-       i_tab[0] = dp1;
-       i_tab[1] = dp2;
-       i_tab[2] = ip1;
-       if (ip2) {
-               *num_inodes = 4;
-               i_tab[3] = ip2;
-       } else {
-               *num_inodes = 3;
-               i_tab[3] = NULL;
-       }
-
-       /*
-        * Sort the elements via bubble sort.  (Remember, there are at
-        * most 4 elements to sort, so this is adequate.)
-        */
-       for (i = 0; i < *num_inodes; i++) {
-               for (j = 1; j < *num_inodes; j++) {
-                       if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) {
-                               temp = i_tab[j];
-                               i_tab[j] = i_tab[j-1];
-                               i_tab[j-1] = temp;
-                       }
-               }
-       }
-}
-
-/*
- * xfs_rename
- */
-int
-xfs_rename(
-       xfs_inode_t     *src_dp,
-       struct xfs_name *src_name,
-       xfs_inode_t     *src_ip,
-       xfs_inode_t     *target_dp,
-       struct xfs_name *target_name,
-       xfs_inode_t     *target_ip)
-{
-       xfs_trans_t     *tp = NULL;
-       xfs_mount_t     *mp = src_dp->i_mount;
-       int             new_parent;             /* moving to a new dir */
-       int             src_is_directory;       /* src_name is a directory */
-       int             error;
-       xfs_bmap_free_t free_list;
-       xfs_fsblock_t   first_block;
-       int             cancel_flags;
-       int             committed;
-       xfs_inode_t     *inodes[4];
-       int             spaceres;
-       int             num_inodes;
-
-       trace_xfs_rename(src_dp, target_dp, src_name, target_name);
-
-       new_parent = (src_dp != target_dp);
-       src_is_directory = S_ISDIR(src_ip->i_d.di_mode);
-
-       xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip,
-                               inodes, &num_inodes);
-
-       xfs_bmap_init(&free_list, &first_block);
-       tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-       spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len);
-       error = xfs_trans_reserve(tp, spaceres, XFS_RENAME_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
-       if (error == ENOSPC) {
-               spaceres = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_RENAME_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES, XFS_RENAME_LOG_COUNT);
-       }
-       if (error) {
-               xfs_trans_cancel(tp, 0);
-               goto std_return;
-       }
-
-       /*
-        * Attach the dquots to the inodes
-        */
-       error = xfs_qm_vop_rename_dqattach(inodes);
-       if (error) {
-               xfs_trans_cancel(tp, cancel_flags);
-               goto std_return;
-       }
-
-       /*
-        * Lock all the participating inodes. Depending upon whether
-        * the target_name exists in the target directory, and
-        * whether the target directory is the same as the source
-        * directory, we can lock from 2 to 4 inodes.
-        */
-       xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
-
-       /*
-        * Join all the inodes to the transaction. From this point on,
-        * we can rely on either trans_commit or trans_cancel to unlock
-        * them.
-        */
-       xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
-       if (new_parent)
-               xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
-       if (target_ip)
-               xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
-
-       /*
-        * If we are using project inheritance, we only allow renames
-        * into our tree when the project IDs are the same; else the
-        * tree quota mechanism would be circumvented.
-        */
-       if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) {
-               error = XFS_ERROR(EXDEV);
-               goto error_return;
-       }
-
-       /*
-        * Set up the target.
-        */
-       if (target_ip == NULL) {
-               /*
-                * If there's no space reservation, check the entry will
-                * fit before actually inserting it.
-                */
-               error = xfs_dir_canenter(tp, target_dp, target_name, spaceres);
-               if (error)
-                       goto error_return;
-               /*
-                * If target does not exist and the rename crosses
-                * directories, adjust the target directory link count
-                * to account for the ".." reference from the new entry.
-                */
-               error = xfs_dir_createname(tp, target_dp, target_name,
-                                               src_ip->i_ino, &first_block,
-                                               &free_list, spaceres);
-               if (error == ENOSPC)
-                       goto error_return;
-               if (error)
-                       goto abort_return;
-
-               xfs_trans_ichgtime(tp, target_dp,
-                                       XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
-               if (new_parent && src_is_directory) {
-                       error = xfs_bumplink(tp, target_dp);
-                       if (error)
-                               goto abort_return;
-               }
-       } else { /* target_ip != NULL */
-               /*
-                * If target exists and it's a directory, check that both
-                * target and source are directories and that target can be
-                * destroyed, or that neither is a directory.
-                */
-               if (S_ISDIR(target_ip->i_d.di_mode)) {
-                       /*
-                        * Make sure target dir is empty.
-                        */
-                       if (!(xfs_dir_isempty(target_ip)) ||
-                           (target_ip->i_d.di_nlink > 2)) {
-                               error = XFS_ERROR(EEXIST);
-                               goto error_return;
-                       }
-               }
-
-               /*
-                * Link the source inode under the target name.
-                * If the source inode is a directory and we are moving
-                * it across directories, its ".." entry will be
-                * inconsistent until we replace that down below.
-                *
-                * In case there is already an entry with the same
-                * name at the destination directory, remove it first.
-                */
-               error = xfs_dir_replace(tp, target_dp, target_name,
-                                       src_ip->i_ino,
-                                       &first_block, &free_list, spaceres);
-               if (error)
-                       goto abort_return;
-
-               xfs_trans_ichgtime(tp, target_dp,
-                                       XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
-               /*
-                * Decrement the link count on the target since the target
-                * dir no longer points to it.
-                */
-               error = xfs_droplink(tp, target_ip);
-               if (error)
-                       goto abort_return;
-
-               if (src_is_directory) {
-                       /*
-                        * Drop the link from the old "." entry.
-                        */
-                       error = xfs_droplink(tp, target_ip);
-                       if (error)
-                               goto abort_return;
-               }
-       } /* target_ip != NULL */
-
-       /*
-        * Remove the source.
-        */
-       if (new_parent && src_is_directory) {
-               /*
-                * Rewrite the ".." entry to point to the new
-                * directory.
-                */
-               error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot,
-                                       target_dp->i_ino,
-                                       &first_block, &free_list, spaceres);
-               ASSERT(error != EEXIST);
-               if (error)
-                       goto abort_return;
-       }
-
-       /*
-        * We always want to hit the ctime on the source inode.
-        *
-        * This isn't strictly required by the standards since the source
-        * inode isn't really being changed, but old unix file systems did
-        * it and some incremental backup programs won't work without it.
-        */
-       xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE);
-
-       /*
-        * Adjust the link count on src_dp.  This is necessary when
-        * renaming a directory, either within one parent when
-        * the target existed, or across two parent directories.
-        */
-       if (src_is_directory && (new_parent || target_ip != NULL)) {
-
-               /*
-                * Decrement link count on src_directory since the
-                * entry that's moved no longer points to it.
-                */
-               error = xfs_droplink(tp, src_dp);
-               if (error)
-                       goto abort_return;
-       }
-
-       error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino,
-                                       &first_block, &free_list, spaceres);
-       if (error)
-               goto abort_return;
-
-       xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE);
-       if (new_parent)
-               xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE);
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * rename transaction goes to disk before returning to
-        * the user.
-        */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
-               xfs_trans_set_sync(tp);
-       }
-
-       error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error) {
-               xfs_bmap_cancel(&free_list);
-               xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
-                                XFS_TRANS_ABORT));
-               goto std_return;
-       }
-
-       /*
-        * trans_commit will unlock src_ip, target_ip & decrement
-        * the vnode references.
-        */
-       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-
- abort_return:
-       cancel_flags |= XFS_TRANS_ABORT;
- error_return:
-       xfs_bmap_cancel(&free_list);
-       xfs_trans_cancel(tp, cancel_flags);
- std_return:
-       return error;
-}
index 98dc670d3ee04182da47b27e7db1695b71807434..6f9e63c9fc2617ab89966447083527f1d0c94257 100644 (file)
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_mount.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_rtalloc.h"
 #include "xfs_fsops.h"
 #include "xfs_error.h"
 #include "xfs_inode_item.h"
 #include "xfs_trans_space.h"
-#include "xfs_utils.h"
 #include "xfs_trace.h"
 #include "xfs_buf.h"
 #include "xfs_icache.h"
@@ -101,10 +100,9 @@ xfs_growfs_rt_alloc(
                /*
                 * Reserve space & log for one extent added to the file.
                 */
-               if ((error = xfs_trans_reserve(tp, resblks,
-                               XFS_GROWRTALLOC_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES,
-                               XFS_DEFAULT_PERM_LOG_COUNT)))
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growdata,
+                                         resblks, 0);
+               if (error)
                        goto error_cancel;
                cancelflags = XFS_TRANS_RELEASE_LOG_RES;
                /*
@@ -147,8 +145,9 @@ xfs_growfs_rt_alloc(
                        /*
                         * Reserve log for one block zeroing.
                         */
-                       if ((error = xfs_trans_reserve(tp, 0,
-                                       XFS_GROWRTZERO_LOG_RES(mp), 0, 0, 0)))
+                       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtzero,
+                                                 0, 0);
+                       if (error)
                                goto error_cancel;
                        /*
                         * Lock the bitmap inode.
@@ -736,8 +735,8 @@ xfs_rtallocate_range(
 {
        xfs_rtblock_t   end;            /* end of the allocated extent */
        int             error;          /* error value */
-       xfs_rtblock_t   postblock;      /* first block allocated > end */
-       xfs_rtblock_t   preblock;       /* first block allocated < start */
+       xfs_rtblock_t   postblock = 0;  /* first block allocated > end */
+       xfs_rtblock_t   preblock = 0;   /* first block allocated < start */
 
        end = start + len - 1;
        /*
@@ -1958,8 +1957,9 @@ xfs_growfs_rt(
                 * Start a transaction, get the log reservation.
                 */
                tp = xfs_trans_alloc(mp, XFS_TRANS_GROWFSRT_FREE);
-               if ((error = xfs_trans_reserve(tp, 0,
-                               XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0)))
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_growrtfree,
+                                         0, 0);
+               if (error)
                        goto error_cancel;
                /*
                 * Lock out other callers by grabbing the bitmap inode lock.
@@ -2148,7 +2148,7 @@ xfs_rtfree_extent(
        ASSERT(mp->m_rbmip->i_itemp != NULL);
        ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
 
-#if defined(__KERNEL__) && defined(DEBUG)
+#ifdef DEBUG
        /*
         * Check to see that this whole range is currently allocated.
         */
index f7f3a359c1c5a238afd4884b19f4a74363e36287..b2a1a24c0e2f3d8037cdd03f2b8deffc298d38c9 100644 (file)
 #ifndef __XFS_RTALLOC_H__
 #define        __XFS_RTALLOC_H__
 
+/* kernel only definitions and functions */
+
 struct xfs_mount;
 struct xfs_trans;
 
-/* Min and max rt extent sizes, specified in bytes */
-#define        XFS_MAX_RTEXTSIZE       (1024 * 1024 * 1024)    /* 1GB */
-#define        XFS_DFL_RTEXTSIZE       (64 * 1024)             /* 64kB */
-#define        XFS_MIN_RTEXTSIZE       (4 * 1024)              /* 4kB */
-
-/*
- * Constants for bit manipulations.
- */
-#define        XFS_NBBYLOG     3               /* log2(NBBY) */
-#define        XFS_WORDLOG     2               /* log2(sizeof(xfs_rtword_t)) */
-#define        XFS_NBWORDLOG   (XFS_NBBYLOG + XFS_WORDLOG)
-#define        XFS_NBWORD      (1 << XFS_NBWORDLOG)
-#define        XFS_WORDMASK    ((1 << XFS_WORDLOG) - 1)
-
-#define        XFS_BLOCKSIZE(mp)       ((mp)->m_sb.sb_blocksize)
-#define        XFS_BLOCKMASK(mp)       ((mp)->m_blockmask)
-#define        XFS_BLOCKWSIZE(mp)      ((mp)->m_blockwsize)
-#define        XFS_BLOCKWMASK(mp)      ((mp)->m_blockwmask)
-
-/*
- * Summary and bit manipulation macros.
- */
-#define        XFS_SUMOFFS(mp,ls,bb)   ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb)))
-#define        XFS_SUMOFFSTOBLOCK(mp,s)        \
-       (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog)
-#define        XFS_SUMPTR(mp,bp,so)    \
-       ((xfs_suminfo_t *)((bp)->b_addr + \
-               (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp))))
-
-#define        XFS_BITTOBLOCK(mp,bi)   ((bi) >> (mp)->m_blkbit_log)
-#define        XFS_BLOCKTOBIT(mp,bb)   ((bb) << (mp)->m_blkbit_log)
-#define        XFS_BITTOWORD(mp,bi)    \
-       ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp)))
-
-#define        XFS_RTMIN(a,b)  ((a) < (b) ? (a) : (b))
-#define        XFS_RTMAX(a,b)  ((a) > (b) ? (a) : (b))
-
-#define        XFS_RTLOBIT(w)  xfs_lowbit32(w)
-#define        XFS_RTHIBIT(w)  xfs_highbit32(w)
-
-#if XFS_BIG_BLKNOS
-#define        XFS_RTBLOCKLOG(b)       xfs_highbit64(b)
-#else
-#define        XFS_RTBLOCKLOG(b)       xfs_highbit32(b)
-#endif
-
-
-#ifdef __KERNEL__
-
 #ifdef CONFIG_XFS_RT
 /*
  * Function prototypes for exported functions.
@@ -161,6 +114,4 @@ xfs_rtmount_init(
 # define xfs_rtunmount_inodes(m)
 #endif /* CONFIG_XFS_RT */
 
-#endif /* __KERNEL__ */
-
 #endif /* __XFS_RTALLOC_H__ */
diff --git a/fs/xfs/xfs_sb.c b/fs/xfs/xfs_sb.c
new file mode 100644 (file)
index 0000000..a5b59d9
--- /dev/null
@@ -0,0 +1,834 @@
+/*
+ * Copyright (c) 2000-2005 Silicon Graphics, 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_format.h"
+#include "xfs_bit.h"
+#include "xfs_log.h"
+#include "xfs_inum.h"
+#include "xfs_trans.h"
+#include "xfs_trans_priv.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_alloc.h"
+#include "xfs_rtalloc.h"
+#include "xfs_bmap.h"
+#include "xfs_error.h"
+#include "xfs_quota.h"
+#include "xfs_fsops.h"
+#include "xfs_trace.h"
+#include "xfs_cksum.h"
+#include "xfs_buf_item.h"
+
+/*
+ * Physical superblock buffer manipulations. Shared with libxfs in userspace.
+ */
+
+static const struct {
+       short offset;
+       short type;     /* 0 = integer
+                        * 1 = binary / string (no translation)
+                        */
+} xfs_sb_info[] = {
+       { offsetof(xfs_sb_t, sb_magicnum),      0 },
+       { offsetof(xfs_sb_t, sb_blocksize),     0 },
+       { offsetof(xfs_sb_t, sb_dblocks),       0 },
+       { offsetof(xfs_sb_t, sb_rblocks),       0 },
+       { offsetof(xfs_sb_t, sb_rextents),      0 },
+       { offsetof(xfs_sb_t, sb_uuid),          1 },
+       { offsetof(xfs_sb_t, sb_logstart),      0 },
+       { offsetof(xfs_sb_t, sb_rootino),       0 },
+       { offsetof(xfs_sb_t, sb_rbmino),        0 },
+       { offsetof(xfs_sb_t, sb_rsumino),       0 },
+       { offsetof(xfs_sb_t, sb_rextsize),      0 },
+       { offsetof(xfs_sb_t, sb_agblocks),      0 },
+       { offsetof(xfs_sb_t, sb_agcount),       0 },
+       { offsetof(xfs_sb_t, sb_rbmblocks),     0 },
+       { offsetof(xfs_sb_t, sb_logblocks),     0 },
+       { offsetof(xfs_sb_t, sb_versionnum),    0 },
+       { offsetof(xfs_sb_t, sb_sectsize),      0 },
+       { offsetof(xfs_sb_t, sb_inodesize),     0 },
+       { offsetof(xfs_sb_t, sb_inopblock),     0 },
+       { offsetof(xfs_sb_t, sb_fname[0]),      1 },
+       { offsetof(xfs_sb_t, sb_blocklog),      0 },
+       { offsetof(xfs_sb_t, sb_sectlog),       0 },
+       { offsetof(xfs_sb_t, sb_inodelog),      0 },
+       { offsetof(xfs_sb_t, sb_inopblog),      0 },
+       { offsetof(xfs_sb_t, sb_agblklog),      0 },
+       { offsetof(xfs_sb_t, sb_rextslog),      0 },
+       { offsetof(xfs_sb_t, sb_inprogress),    0 },
+       { offsetof(xfs_sb_t, sb_imax_pct),      0 },
+       { offsetof(xfs_sb_t, sb_icount),        0 },
+       { offsetof(xfs_sb_t, sb_ifree),         0 },
+       { offsetof(xfs_sb_t, sb_fdblocks),      0 },
+       { offsetof(xfs_sb_t, sb_frextents),     0 },
+       { offsetof(xfs_sb_t, sb_uquotino),      0 },
+       { offsetof(xfs_sb_t, sb_gquotino),      0 },
+       { offsetof(xfs_sb_t, sb_qflags),        0 },
+       { offsetof(xfs_sb_t, sb_flags),         0 },
+       { offsetof(xfs_sb_t, sb_shared_vn),     0 },
+       { offsetof(xfs_sb_t, sb_inoalignmt),    0 },
+       { offsetof(xfs_sb_t, sb_unit),          0 },
+       { offsetof(xfs_sb_t, sb_width),         0 },
+       { offsetof(xfs_sb_t, sb_dirblklog),     0 },
+       { offsetof(xfs_sb_t, sb_logsectlog),    0 },
+       { offsetof(xfs_sb_t, sb_logsectsize),   0 },
+       { offsetof(xfs_sb_t, sb_logsunit),      0 },
+       { offsetof(xfs_sb_t, sb_features2),     0 },
+       { offsetof(xfs_sb_t, sb_bad_features2), 0 },
+       { offsetof(xfs_sb_t, sb_features_compat),       0 },
+       { offsetof(xfs_sb_t, sb_features_ro_compat),    0 },
+       { offsetof(xfs_sb_t, sb_features_incompat),     0 },
+       { offsetof(xfs_sb_t, sb_features_log_incompat), 0 },
+       { offsetof(xfs_sb_t, sb_crc),           0 },
+       { offsetof(xfs_sb_t, sb_pad),           0 },
+       { offsetof(xfs_sb_t, sb_pquotino),      0 },
+       { offsetof(xfs_sb_t, sb_lsn),           0 },
+       { sizeof(xfs_sb_t),                     0 }
+};
+
+/*
+ * Reference counting access wrappers to the perag structures.
+ * Because we never free per-ag structures, the only thing we
+ * have to protect against changes is the tree structure itself.
+ */
+struct xfs_perag *
+xfs_perag_get(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          agno)
+{
+       struct xfs_perag        *pag;
+       int                     ref = 0;
+
+       rcu_read_lock();
+       pag = radix_tree_lookup(&mp->m_perag_tree, agno);
+       if (pag) {
+               ASSERT(atomic_read(&pag->pag_ref) >= 0);
+               ref = atomic_inc_return(&pag->pag_ref);
+       }
+       rcu_read_unlock();
+       trace_xfs_perag_get(mp, agno, ref, _RET_IP_);
+       return pag;
+}
+
+/*
+ * search from @first to find the next perag with the given tag set.
+ */
+struct xfs_perag *
+xfs_perag_get_tag(
+       struct xfs_mount        *mp,
+       xfs_agnumber_t          first,
+       int                     tag)
+{
+       struct xfs_perag        *pag;
+       int                     found;
+       int                     ref;
+
+       rcu_read_lock();
+       found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
+                                       (void **)&pag, first, 1, tag);
+       if (found <= 0) {
+               rcu_read_unlock();
+               return NULL;
+       }
+       ref = atomic_inc_return(&pag->pag_ref);
+       rcu_read_unlock();
+       trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_);
+       return pag;
+}
+
+void
+xfs_perag_put(
+       struct xfs_perag        *pag)
+{
+       int     ref;
+
+       ASSERT(atomic_read(&pag->pag_ref) > 0);
+       ref = atomic_dec_return(&pag->pag_ref);
+       trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_);
+}
+
+/*
+ * Check the validity of the SB found.
+ */
+STATIC int
+xfs_mount_validate_sb(
+       xfs_mount_t     *mp,
+       xfs_sb_t        *sbp,
+       bool            check_inprogress,
+       bool            check_version)
+{
+
+       /*
+        * If the log device and data device have the
+        * same device number, the log is internal.
+        * Consequently, the sb_logstart should be non-zero.  If
+        * we have a zero sb_logstart in this case, we may be trying to mount
+        * a volume filesystem in a non-volume manner.
+        */
+       if (sbp->sb_magicnum != XFS_SB_MAGIC) {
+               xfs_warn(mp, "bad magic number");
+               return XFS_ERROR(EWRONGFS);
+       }
+
+
+       if (!xfs_sb_good_version(sbp)) {
+               xfs_warn(mp, "bad version");
+               return XFS_ERROR(EWRONGFS);
+       }
+
+       /*
+        * Version 5 superblock feature mask validation. Reject combinations the
+        * kernel cannot support up front before checking anything else. For
+        * write validation, we don't need to check feature masks.
+        */
+       if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) {
+               xfs_alert(mp,
+"Version 5 superblock detected. This kernel has EXPERIMENTAL support enabled!\n"
+"Use of these features in this kernel is at your own risk!");
+
+               if (xfs_sb_has_compat_feature(sbp,
+                                       XFS_SB_FEAT_COMPAT_UNKNOWN)) {
+                       xfs_warn(mp,
+"Superblock has unknown compatible features (0x%x) enabled.\n"
+"Using a more recent kernel is recommended.",
+                               (sbp->sb_features_compat &
+                                               XFS_SB_FEAT_COMPAT_UNKNOWN));
+               }
+
+               if (xfs_sb_has_ro_compat_feature(sbp,
+                                       XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) {
+                       xfs_alert(mp,
+"Superblock has unknown read-only compatible features (0x%x) enabled.",
+                               (sbp->sb_features_ro_compat &
+                                               XFS_SB_FEAT_RO_COMPAT_UNKNOWN));
+                       if (!(mp->m_flags & XFS_MOUNT_RDONLY)) {
+                               xfs_warn(mp,
+"Attempted to mount read-only compatible filesystem read-write.\n"
+"Filesystem can only be safely mounted read only.");
+                               return XFS_ERROR(EINVAL);
+                       }
+               }
+               if (xfs_sb_has_incompat_feature(sbp,
+                                       XFS_SB_FEAT_INCOMPAT_UNKNOWN)) {
+                       xfs_warn(mp,
+"Superblock has unknown incompatible features (0x%x) enabled.\n"
+"Filesystem can not be safely mounted by this kernel.",
+                               (sbp->sb_features_incompat &
+                                               XFS_SB_FEAT_INCOMPAT_UNKNOWN));
+                       return XFS_ERROR(EINVAL);
+               }
+       }
+
+       if (xfs_sb_version_has_pquotino(sbp)) {
+               if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) {
+                       xfs_notice(mp,
+                          "Version 5 of Super block has XFS_OQUOTA bits.\n");
+                       return XFS_ERROR(EFSCORRUPTED);
+               }
+       } else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD |
+                               XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) {
+                       xfs_notice(mp,
+"Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits.\n");
+                       return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       if (unlikely(
+           sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) {
+               xfs_warn(mp,
+               "filesystem is marked as having an external log; "
+               "specify logdev on the mount command line.");
+               return XFS_ERROR(EINVAL);
+       }
+
+       if (unlikely(
+           sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) {
+               xfs_warn(mp,
+               "filesystem is marked as having an internal log; "
+               "do not specify logdev on the mount command line.");
+               return XFS_ERROR(EINVAL);
+       }
+
+       /*
+        * More sanity checking.  Most of these were stolen directly from
+        * xfs_repair.
+        */
+       if (unlikely(
+           sbp->sb_agcount <= 0                                        ||
+           sbp->sb_sectsize < XFS_MIN_SECTORSIZE                       ||
+           sbp->sb_sectsize > XFS_MAX_SECTORSIZE                       ||
+           sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG                    ||
+           sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG                    ||
+           sbp->sb_sectsize != (1 << sbp->sb_sectlog)                  ||
+           sbp->sb_blocksize < XFS_MIN_BLOCKSIZE                       ||
+           sbp->sb_blocksize > XFS_MAX_BLOCKSIZE                       ||
+           sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG                    ||
+           sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG                    ||
+           sbp->sb_blocksize != (1 << sbp->sb_blocklog)                ||
+           sbp->sb_inodesize < XFS_DINODE_MIN_SIZE                     ||
+           sbp->sb_inodesize > XFS_DINODE_MAX_SIZE                     ||
+           sbp->sb_inodelog < XFS_DINODE_MIN_LOG                       ||
+           sbp->sb_inodelog > XFS_DINODE_MAX_LOG                       ||
+           sbp->sb_inodesize != (1 << sbp->sb_inodelog)                ||
+           (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog)   ||
+           (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE)  ||
+           (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)  ||
+           (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */)    ||
+           sbp->sb_dblocks == 0                                        ||
+           sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp)                      ||
+           sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) {
+               XFS_CORRUPTION_ERROR("SB sanity check failed",
+                               XFS_ERRLEVEL_LOW, mp, sbp);
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       /*
+        * Until this is fixed only page-sized or smaller data blocks work.
+        */
+       if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) {
+               xfs_warn(mp,
+               "File system with blocksize %d bytes. "
+               "Only pagesize (%ld) or less will currently work.",
+                               sbp->sb_blocksize, PAGE_SIZE);
+               return XFS_ERROR(ENOSYS);
+       }
+
+       /*
+        * Currently only very few inode sizes are supported.
+        */
+       switch (sbp->sb_inodesize) {
+       case 256:
+       case 512:
+       case 1024:
+       case 2048:
+               break;
+       default:
+               xfs_warn(mp, "inode size of %d bytes not supported",
+                               sbp->sb_inodesize);
+               return XFS_ERROR(ENOSYS);
+       }
+
+       if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) ||
+           xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) {
+               xfs_warn(mp,
+               "file system too large to be mounted on this system.");
+               return XFS_ERROR(EFBIG);
+       }
+
+       if (check_inprogress && sbp->sb_inprogress) {
+               xfs_warn(mp, "Offline file system operation in progress!");
+               return XFS_ERROR(EFSCORRUPTED);
+       }
+
+       /*
+        * Version 1 directory format has never worked on Linux.
+        */
+       if (unlikely(!xfs_sb_version_hasdirv2(sbp))) {
+               xfs_warn(mp, "file system using version 1 directory format");
+               return XFS_ERROR(ENOSYS);
+       }
+
+       return 0;
+}
+
+void
+xfs_sb_quota_from_disk(struct xfs_sb *sbp)
+{
+       /*
+        * older mkfs doesn't initialize quota inodes to NULLFSINO. This
+        * leads to in-core values having two different values for a quota
+        * inode to be invalid: 0 and NULLFSINO. Change it to a single value
+        * NULLFSINO.
+        *
+        * Note that this change affect only the in-core values. These
+        * values are not written back to disk unless any quota information
+        * is written to the disk. Even in that case, sb_pquotino field is
+        * not written to disk unless the superblock supports pquotino.
+        */
+       if (sbp->sb_uquotino == 0)
+               sbp->sb_uquotino = NULLFSINO;
+       if (sbp->sb_gquotino == 0)
+               sbp->sb_gquotino = NULLFSINO;
+       if (sbp->sb_pquotino == 0)
+               sbp->sb_pquotino = NULLFSINO;
+
+       /*
+        * We need to do these manipilations only if we are working
+        * with an older version of on-disk superblock.
+        */
+       if (xfs_sb_version_has_pquotino(sbp))
+               return;
+
+       if (sbp->sb_qflags & XFS_OQUOTA_ENFD)
+               sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ?
+                                       XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD;
+       if (sbp->sb_qflags & XFS_OQUOTA_CHKD)
+               sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ?
+                                       XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD;
+       sbp->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD);
+
+       if (sbp->sb_qflags & XFS_PQUOTA_ACCT)  {
+               /*
+                * In older version of superblock, on-disk superblock only
+                * has sb_gquotino, and in-core superblock has both sb_gquotino
+                * and sb_pquotino. But, only one of them is supported at any
+                * point of time. So, if PQUOTA is set in disk superblock,
+                * copy over sb_gquotino to sb_pquotino.
+                */
+               sbp->sb_pquotino = sbp->sb_gquotino;
+               sbp->sb_gquotino = NULLFSINO;
+       }
+}
+
+void
+xfs_sb_from_disk(
+       struct xfs_sb   *to,
+       xfs_dsb_t       *from)
+{
+       to->sb_magicnum = be32_to_cpu(from->sb_magicnum);
+       to->sb_blocksize = be32_to_cpu(from->sb_blocksize);
+       to->sb_dblocks = be64_to_cpu(from->sb_dblocks);
+       to->sb_rblocks = be64_to_cpu(from->sb_rblocks);
+       to->sb_rextents = be64_to_cpu(from->sb_rextents);
+       memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid));
+       to->sb_logstart = be64_to_cpu(from->sb_logstart);
+       to->sb_rootino = be64_to_cpu(from->sb_rootino);
+       to->sb_rbmino = be64_to_cpu(from->sb_rbmino);
+       to->sb_rsumino = be64_to_cpu(from->sb_rsumino);
+       to->sb_rextsize = be32_to_cpu(from->sb_rextsize);
+       to->sb_agblocks = be32_to_cpu(from->sb_agblocks);
+       to->sb_agcount = be32_to_cpu(from->sb_agcount);
+       to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks);
+       to->sb_logblocks = be32_to_cpu(from->sb_logblocks);
+       to->sb_versionnum = be16_to_cpu(from->sb_versionnum);
+       to->sb_sectsize = be16_to_cpu(from->sb_sectsize);
+       to->sb_inodesize = be16_to_cpu(from->sb_inodesize);
+       to->sb_inopblock = be16_to_cpu(from->sb_inopblock);
+       memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname));
+       to->sb_blocklog = from->sb_blocklog;
+       to->sb_sectlog = from->sb_sectlog;
+       to->sb_inodelog = from->sb_inodelog;
+       to->sb_inopblog = from->sb_inopblog;
+       to->sb_agblklog = from->sb_agblklog;
+       to->sb_rextslog = from->sb_rextslog;
+       to->sb_inprogress = from->sb_inprogress;
+       to->sb_imax_pct = from->sb_imax_pct;
+       to->sb_icount = be64_to_cpu(from->sb_icount);
+       to->sb_ifree = be64_to_cpu(from->sb_ifree);
+       to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks);
+       to->sb_frextents = be64_to_cpu(from->sb_frextents);
+       to->sb_uquotino = be64_to_cpu(from->sb_uquotino);
+       to->sb_gquotino = be64_to_cpu(from->sb_gquotino);
+       to->sb_qflags = be16_to_cpu(from->sb_qflags);
+       to->sb_flags = from->sb_flags;
+       to->sb_shared_vn = from->sb_shared_vn;
+       to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt);
+       to->sb_unit = be32_to_cpu(from->sb_unit);
+       to->sb_width = be32_to_cpu(from->sb_width);
+       to->sb_dirblklog = from->sb_dirblklog;
+       to->sb_logsectlog = from->sb_logsectlog;
+       to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize);
+       to->sb_logsunit = be32_to_cpu(from->sb_logsunit);
+       to->sb_features2 = be32_to_cpu(from->sb_features2);
+       to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2);
+       to->sb_features_compat = be32_to_cpu(from->sb_features_compat);
+       to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat);
+       to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat);
+       to->sb_features_log_incompat =
+                               be32_to_cpu(from->sb_features_log_incompat);
+       to->sb_pad = 0;
+       to->sb_pquotino = be64_to_cpu(from->sb_pquotino);
+       to->sb_lsn = be64_to_cpu(from->sb_lsn);
+}
+
+static inline void
+xfs_sb_quota_to_disk(
+       xfs_dsb_t       *to,
+       xfs_sb_t        *from,
+       __int64_t       *fields)
+{
+       __uint16_t      qflags = from->sb_qflags;
+
+       /*
+        * We need to do these manipilations only if we are working
+        * with an older version of on-disk superblock.
+        */
+       if (xfs_sb_version_has_pquotino(from))
+               return;
+
+       if (*fields & XFS_SB_QFLAGS) {
+               /*
+                * The in-core version of sb_qflags do not have
+                * XFS_OQUOTA_* flags, whereas the on-disk version
+                * does.  So, convert incore XFS_{PG}QUOTA_* flags
+                * to on-disk XFS_OQUOTA_* flags.
+                */
+               qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD |
+                               XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD);
+
+               if (from->sb_qflags &
+                               (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD))
+                       qflags |= XFS_OQUOTA_ENFD;
+               if (from->sb_qflags &
+                               (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD))
+                       qflags |= XFS_OQUOTA_CHKD;
+               to->sb_qflags = cpu_to_be16(qflags);
+               *fields &= ~XFS_SB_QFLAGS;
+       }
+
+       /*
+        * GQUOTINO and PQUOTINO cannot be used together in versions
+        * of superblock that do not have pquotino. from->sb_flags
+        * tells us which quota is active and should be copied to
+        * disk.
+        */
+       if ((*fields & XFS_SB_GQUOTINO) &&
+                               (from->sb_qflags & XFS_GQUOTA_ACCT))
+               to->sb_gquotino = cpu_to_be64(from->sb_gquotino);
+       else if ((*fields & XFS_SB_PQUOTINO) &&
+                               (from->sb_qflags & XFS_PQUOTA_ACCT))
+               to->sb_gquotino = cpu_to_be64(from->sb_pquotino);
+
+       *fields &= ~(XFS_SB_PQUOTINO | XFS_SB_GQUOTINO);
+}
+
+/*
+ * Copy in core superblock to ondisk one.
+ *
+ * The fields argument is mask of superblock fields to copy.
+ */
+void
+xfs_sb_to_disk(
+       xfs_dsb_t       *to,
+       xfs_sb_t        *from,
+       __int64_t       fields)
+{
+       xfs_caddr_t     to_ptr = (xfs_caddr_t)to;
+       xfs_caddr_t     from_ptr = (xfs_caddr_t)from;
+       xfs_sb_field_t  f;
+       int             first;
+       int             size;
+
+       ASSERT(fields);
+       if (!fields)
+               return;
+
+       xfs_sb_quota_to_disk(to, from, &fields);
+       while (fields) {
+               f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
+               first = xfs_sb_info[f].offset;
+               size = xfs_sb_info[f + 1].offset - first;
+
+               ASSERT(xfs_sb_info[f].type == 0 || xfs_sb_info[f].type == 1);
+
+               if (size == 1 || xfs_sb_info[f].type == 1) {
+                       memcpy(to_ptr + first, from_ptr + first, size);
+               } else {
+                       switch (size) {
+                       case 2:
+                               *(__be16 *)(to_ptr + first) =
+                                     cpu_to_be16(*(__u16 *)(from_ptr + first));
+                               break;
+                       case 4:
+                               *(__be32 *)(to_ptr + first) =
+                                     cpu_to_be32(*(__u32 *)(from_ptr + first));
+                               break;
+                       case 8:
+                               *(__be64 *)(to_ptr + first) =
+                                     cpu_to_be64(*(__u64 *)(from_ptr + first));
+                               break;
+                       default:
+                               ASSERT(0);
+                       }
+               }
+
+               fields &= ~(1LL << f);
+       }
+}
+
+static int
+xfs_sb_verify(
+       struct xfs_buf  *bp,
+       bool            check_version)
+{
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_sb   sb;
+
+       xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp));
+
+       /*
+        * Only check the in progress field for the primary superblock as
+        * mkfs.xfs doesn't clear it from secondary superblocks.
+        */
+       return xfs_mount_validate_sb(mp, &sb, bp->b_bn == XFS_SB_DADDR,
+                                    check_version);
+}
+
+/*
+ * If the superblock has the CRC feature bit set or the CRC field is non-null,
+ * check that the CRC is valid.  We check the CRC field is non-null because a
+ * single bit error could clear the feature bit and unused parts of the
+ * superblock are supposed to be zero. Hence a non-null crc field indicates that
+ * we've potentially lost a feature bit and we should check it anyway.
+ */
+static void
+xfs_sb_read_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
+       int             error;
+
+       /*
+        * open code the version check to avoid needing to convert the entire
+        * superblock from disk order just to check the version number
+        */
+       if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) &&
+           (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) ==
+                                               XFS_SB_VERSION_5) ||
+            dsb->sb_crc != 0)) {
+
+               if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize),
+                                     offsetof(struct xfs_sb, sb_crc))) {
+                       error = EFSCORRUPTED;
+                       goto out_error;
+               }
+       }
+       error = xfs_sb_verify(bp, true);
+
+out_error:
+       if (error) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    mp, bp->b_addr);
+               xfs_buf_ioerror(bp, error);
+       }
+}
+
+/*
+ * We may be probed for a filesystem match, so we may not want to emit
+ * messages when the superblock buffer is not actually an XFS superblock.
+ * If we find an XFS superblock, then run a normal, noisy mount because we are
+ * really going to mount it and want to know about errors.
+ */
+static void
+xfs_sb_quiet_read_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_dsb  *dsb = XFS_BUF_TO_SBP(bp);
+
+
+       if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) {
+               /* XFS filesystem, verify noisily! */
+               xfs_sb_read_verify(bp);
+               return;
+       }
+       /* quietly fail */
+       xfs_buf_ioerror(bp, EWRONGFS);
+}
+
+static void
+xfs_sb_write_verify(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+       int                     error;
+
+       error = xfs_sb_verify(bp, false);
+       if (error) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW,
+                                    mp, bp->b_addr);
+               xfs_buf_ioerror(bp, error);
+               return;
+       }
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (bip)
+               XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        offsetof(struct xfs_sb, sb_crc));
+}
+
+const struct xfs_buf_ops xfs_sb_buf_ops = {
+       .verify_read = xfs_sb_read_verify,
+       .verify_write = xfs_sb_write_verify,
+};
+
+const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
+       .verify_read = xfs_sb_quiet_read_verify,
+       .verify_write = xfs_sb_write_verify,
+};
+
+/*
+ * xfs_mount_common
+ *
+ * Mount initialization code establishing various mount
+ * fields from the superblock associated with the given
+ * mount structure
+ */
+void
+xfs_sb_mount_common(
+       struct xfs_mount *mp,
+       struct xfs_sb   *sbp)
+{
+       mp->m_agfrotor = mp->m_agirotor = 0;
+       spin_lock_init(&mp->m_agirotor_lock);
+       mp->m_maxagi = mp->m_sb.sb_agcount;
+       mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG;
+       mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT;
+       mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT;
+       mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1;
+       mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
+       mp->m_blockmask = sbp->sb_blocksize - 1;
+       mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
+       mp->m_blockwmask = mp->m_blockwsize - 1;
+
+       mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
+       mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
+       mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
+       mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
+
+       mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
+       mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
+       mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2;
+       mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2;
+
+       mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
+       mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
+       mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
+       mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
+
+       mp->m_bsize = XFS_FSB_TO_BB(mp, 1);
+       mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK,
+                                       sbp->sb_inopblock);
+       mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
+}
+
+/*
+ * xfs_initialize_perag_data
+ *
+ * Read in each per-ag structure so we can count up the number of
+ * allocated inodes, free inodes and used filesystem blocks as this
+ * information is no longer persistent in the superblock. Once we have
+ * this information, write it into the in-core superblock structure.
+ */
+int
+xfs_initialize_perag_data(
+       struct xfs_mount *mp,
+       xfs_agnumber_t  agcount)
+{
+       xfs_agnumber_t  index;
+       xfs_perag_t     *pag;
+       xfs_sb_t        *sbp = &mp->m_sb;
+       uint64_t        ifree = 0;
+       uint64_t        ialloc = 0;
+       uint64_t        bfree = 0;
+       uint64_t        bfreelst = 0;
+       uint64_t        btree = 0;
+       int             error;
+
+       for (index = 0; index < agcount; index++) {
+               /*
+                * read the agf, then the agi. This gets us
+                * all the information we need and populates the
+                * per-ag structures for us.
+                */
+               error = xfs_alloc_pagf_init(mp, NULL, index, 0);
+               if (error)
+                       return error;
+
+               error = xfs_ialloc_pagi_init(mp, NULL, index);
+               if (error)
+                       return error;
+               pag = xfs_perag_get(mp, index);
+               ifree += pag->pagi_freecount;
+               ialloc += pag->pagi_count;
+               bfree += pag->pagf_freeblks;
+               bfreelst += pag->pagf_flcount;
+               btree += pag->pagf_btreeblks;
+               xfs_perag_put(pag);
+       }
+       /*
+        * Overwrite incore superblock counters with just-read data
+        */
+       spin_lock(&mp->m_sb_lock);
+       sbp->sb_ifree = ifree;
+       sbp->sb_icount = ialloc;
+       sbp->sb_fdblocks = bfree + bfreelst + btree;
+       spin_unlock(&mp->m_sb_lock);
+
+       /* Fixup the per-cpu counters as well. */
+       xfs_icsb_reinit_counters(mp);
+
+       return 0;
+}
+
+/*
+ * xfs_mod_sb() can be used to copy arbitrary changes to the
+ * in-core superblock into the superblock buffer to be logged.
+ * It does not provide the higher level of locking that is
+ * needed to protect the in-core superblock from concurrent
+ * access.
+ */
+void
+xfs_mod_sb(xfs_trans_t *tp, __int64_t fields)
+{
+       xfs_buf_t       *bp;
+       int             first;
+       int             last;
+       xfs_mount_t     *mp;
+       xfs_sb_field_t  f;
+
+       ASSERT(fields);
+       if (!fields)
+               return;
+       mp = tp->t_mountp;
+       bp = xfs_trans_getsb(tp, mp, 0);
+       first = sizeof(xfs_sb_t);
+       last = 0;
+
+       /* translate/copy */
+
+       xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb, fields);
+
+       /* find modified range */
+       f = (xfs_sb_field_t)xfs_highbit64((__uint64_t)fields);
+       ASSERT((1LL << f) & XFS_SB_MOD_BITS);
+       last = xfs_sb_info[f + 1].offset - 1;
+
+       f = (xfs_sb_field_t)xfs_lowbit64((__uint64_t)fields);
+       ASSERT((1LL << f) & XFS_SB_MOD_BITS);
+       first = xfs_sb_info[f].offset;
+
+       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF);
+       xfs_trans_log_buf(tp, bp, first, last);
+}
index 78f9e70b80c7da8a64b92d528a9f7aa2ba49401e..6835b44f850e58e780c2712e24530dbb3e57f5f4 100644 (file)
@@ -26,6 +26,7 @@
 
 struct xfs_buf;
 struct xfs_mount;
+struct xfs_trans;
 
 #define        XFS_SB_MAGIC            0x58465342      /* 'XFSB' */
 #define        XFS_SB_VERSION_1        1               /* 5.3, 6.0.1, 6.1 */
@@ -83,11 +84,13 @@ struct xfs_mount;
 #define XFS_SB_VERSION2_PARENTBIT      0x00000010      /* parent pointers */
 #define XFS_SB_VERSION2_PROJID32BIT    0x00000080      /* 32 bit project id */
 #define XFS_SB_VERSION2_CRCBIT         0x00000100      /* metadata CRCs */
+#define XFS_SB_VERSION2_FTYPE          0x00000200      /* inode type in dir */
 
 #define        XFS_SB_VERSION2_OKREALFBITS     \
        (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \
         XFS_SB_VERSION2_ATTR2BIT       | \
-        XFS_SB_VERSION2_PROJID32BIT)
+        XFS_SB_VERSION2_PROJID32BIT    | \
+        XFS_SB_VERSION2_FTYPE)
 #define        XFS_SB_VERSION2_OKSASHFBITS     \
        (0)
 #define XFS_SB_VERSION2_OKREALBITS     \
@@ -354,15 +357,8 @@ static inline int xfs_sb_good_version(xfs_sb_t *sbp)
                     (sbp->sb_features2 & ~XFS_SB_VERSION2_OKREALBITS)))
                        return 0;
 
-#ifdef __KERNEL__
                if (sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
                        return 0;
-#else
-               if ((sbp->sb_versionnum & XFS_SB_VERSION_SHAREDBIT) &&
-                   sbp->sb_shared_vn > XFS_SB_MAX_SHARED_VN)
-                       return 0;
-#endif
-
                return 1;
        }
        if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5)
@@ -554,12 +550,13 @@ static inline int xfs_sb_version_hasprojid32bit(xfs_sb_t *sbp)
                (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT));
 }
 
-static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp)
+static inline void xfs_sb_version_addprojid32bit(xfs_sb_t *sbp)
 {
-       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
+       sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT;
+       sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT;
+       sbp->sb_bad_features2 |= XFS_SB_VERSION2_PROJID32BIT;
 }
 
-
 /*
  * Extended v5 superblock feature masks. These are to be used for new v5
  * superblock features only.
@@ -598,7 +595,10 @@ xfs_sb_has_ro_compat_feature(
        return (sbp->sb_features_ro_compat & feature) != 0;
 }
 
-#define XFS_SB_FEAT_INCOMPAT_ALL 0
+#define XFS_SB_FEAT_INCOMPAT_FTYPE     (1 << 0)        /* filetype in dirent */
+#define XFS_SB_FEAT_INCOMPAT_ALL \
+               (XFS_SB_FEAT_INCOMPAT_FTYPE)
+
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN   ~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
 xfs_sb_has_incompat_feature(
@@ -618,16 +618,39 @@ xfs_sb_has_incompat_log_feature(
        return (sbp->sb_features_log_incompat & feature) != 0;
 }
 
-static inline bool
-xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
+/*
+ * V5 superblock specific feature checks
+ */
+static inline int xfs_sb_version_hascrc(xfs_sb_t *sbp)
 {
-       return (ino == sbp->sb_uquotino || ino == sbp->sb_gquotino);
+       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
+}
+
+static inline int xfs_sb_version_has_pquotino(xfs_sb_t *sbp)
+{
+       return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5;
+}
+
+static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp)
+{
+       return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 &&
+               xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_FTYPE)) ||
+              (xfs_sb_version_hasmorebits(sbp) &&
+                (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE));
 }
 
 /*
  * end of superblock version macros
  */
 
+static inline bool
+xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
+{
+       return (ino == sbp->sb_uquotino ||
+               ino == sbp->sb_gquotino ||
+               ino == sbp->sb_pquotino);
+}
+
 #define XFS_SB_DADDR           ((xfs_daddr_t)0) /* daddr in filesystem/ag */
 #define        XFS_SB_BLOCK(mp)        XFS_HDR_BLOCK(mp, XFS_SB_DADDR)
 #define XFS_BUF_TO_SBP(bp)     ((xfs_dsb_t *)((bp)->b_addr))
@@ -660,4 +683,23 @@ xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino)
 #define XFS_B_TO_FSBT(mp,b)    (((__uint64_t)(b)) >> (mp)->m_sb.sb_blocklog)
 #define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask)
 
+/*
+ * perag get/put wrappers for ref counting
+ */
+extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t);
+extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t,
+                                          int tag);
+extern void    xfs_perag_put(struct xfs_perag *pag);
+extern int     xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t);
+
+extern void    xfs_sb_calc_crc(struct xfs_buf  *);
+extern void    xfs_mod_sb(struct xfs_trans *, __int64_t);
+extern void    xfs_sb_mount_common(struct xfs_mount *, struct xfs_sb *);
+extern void    xfs_sb_from_disk(struct xfs_sb *, struct xfs_dsb *);
+extern void    xfs_sb_to_disk(struct xfs_dsb *, struct xfs_sb *, __int64_t);
+extern void    xfs_sb_quota_from_disk(struct xfs_sb *sbp);
+
+extern const struct xfs_buf_ops xfs_sb_buf_ops;
+extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
+
 #endif /* __XFS_SB_H__ */
index 1d68ffcdeaa7f555ab77ee05f5c13571c6ee3b4d..15188cc9944919e275e43e4978056efa91801343 100644 (file)
  */
 
 #include "xfs.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_inum.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_alloc.h"
 #include "xfs_quota.h"
 #include "xfs_mount.h"
 #include "xfs_fsops.h"
 #include "xfs_attr.h"
 #include "xfs_buf_item.h"
-#include "xfs_utils.h"
-#include "xfs_vnodeops.h"
 #include "xfs_log_priv.h"
 #include "xfs_trans_priv.h"
 #include "xfs_filestream.h"
 #include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_extfree_item.h"
 #include "xfs_mru_cache.h"
 #include "xfs_inode_item.h"
@@ -421,12 +421,6 @@ xfs_parseargs(
        }
 #endif
 
-       if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
-           (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
-               xfs_warn(mp, "cannot mount with both project and group quota");
-               return EINVAL;
-       }
-
        if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
                xfs_warn(mp, "sunit and swidth must be specified together");
                return EINVAL;
@@ -556,14 +550,13 @@ xfs_showargs(
        else if (mp->m_qflags & XFS_UQUOTA_ACCT)
                seq_puts(m, "," MNTOPT_UQUOTANOENF);
 
-       /* Either project or group quotas can be active, not both */
-
        if (mp->m_qflags & XFS_PQUOTA_ACCT) {
                if (mp->m_qflags & XFS_PQUOTA_ENFD)
                        seq_puts(m, "," MNTOPT_PRJQUOTA);
                else
                        seq_puts(m, "," MNTOPT_PQUOTANOENF);
-       } else if (mp->m_qflags & XFS_GQUOTA_ACCT) {
+       }
+       if (mp->m_qflags & XFS_GQUOTA_ACCT) {
                if (mp->m_qflags & XFS_GQUOTA_ENFD)
                        seq_puts(m, "," MNTOPT_GRPQUOTA);
                else
@@ -870,17 +863,17 @@ xfs_init_mount_workqueues(
                goto out_destroy_unwritten;
 
        mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
-                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+                       0, 0, mp->m_fsname);
        if (!mp->m_reclaim_workqueue)
                goto out_destroy_cil;
 
        mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
-                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+                       0, 0, mp->m_fsname);
        if (!mp->m_log_workqueue)
                goto out_destroy_reclaim;
 
        mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
-                       WQ_NON_REENTRANT, 0, mp->m_fsname);
+                       0, 0, mp->m_fsname);
        if (!mp->m_eofblocks_workqueue)
                goto out_destroy_log;
 
@@ -1396,6 +1389,14 @@ xfs_finish_flags(
                return XFS_ERROR(EROFS);
        }
 
+       if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
+           (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) &&
+           !xfs_sb_version_has_pquotino(&mp->m_sb)) {
+               xfs_warn(mp,
+                 "Super block does not support project and group quota together");
+               return XFS_ERROR(EINVAL);
+       }
+
        return 0;
 }
 
@@ -1534,19 +1535,21 @@ xfs_fs_mount(
        return mount_bdev(fs_type, flags, dev_name, data, xfs_fs_fill_super);
 }
 
-static int
+static long
 xfs_fs_nr_cached_objects(
-       struct super_block      *sb)
+       struct super_block      *sb,
+       int                     nid)
 {
        return xfs_reclaim_inodes_count(XFS_M(sb));
 }
 
-static void
+static long
 xfs_fs_free_cached_objects(
        struct super_block      *sb,
-       int                     nr_to_scan)
+       long                    nr_to_scan,
+       int                     nid)
 {
-       xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan);
+       return xfs_reclaim_inodes_nr(XFS_M(sb), nr_to_scan);
 }
 
 static const struct super_operations xfs_super_operations = {
index f4895b662fcb549706881a4dd65a8b048d23d03e..f622a97a7e3383d287d85a3787c2feecc8a36b3f 100644 (file)
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_bit.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 #include "xfs_ag.h"
-#include "xfs_dir2.h"
 #include "xfs_mount.h"
 #include "xfs_da_btree.h"
+#include "xfs_dir2_format.h"
+#include "xfs_dir2.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_ialloc_btree.h"
 #include "xfs_dinode.h"
 #include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_itable.h"
 #include "xfs_ialloc.h"
 #include "xfs_alloc.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
 #include "xfs_error.h"
 #include "xfs_quota.h"
-#include "xfs_utils.h"
 #include "xfs_trans_space.h"
-#include "xfs_log_priv.h"
 #include "xfs_trace.h"
 #include "xfs_symlink.h"
-#include "xfs_cksum.h"
 #include "xfs_buf_item.h"
 
-
-/*
- * Each contiguous block has a header, so it is not just a simple pathlen
- * to FSB conversion.
- */
-int
-xfs_symlink_blocks(
-       struct xfs_mount *mp,
-       int             pathlen)
-{
-       int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
-
-       return (pathlen + buflen - 1) / buflen;
-}
-
-static int
-xfs_symlink_hdr_set(
-       struct xfs_mount        *mp,
-       xfs_ino_t               ino,
-       uint32_t                offset,
-       uint32_t                size,
-       struct xfs_buf          *bp)
-{
-       struct xfs_dsymlink_hdr *dsl = bp->b_addr;
-
-       if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return 0;
-
-       dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
-       dsl->sl_offset = cpu_to_be32(offset);
-       dsl->sl_bytes = cpu_to_be32(size);
-       uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
-       dsl->sl_owner = cpu_to_be64(ino);
-       dsl->sl_blkno = cpu_to_be64(bp->b_bn);
-       bp->b_ops = &xfs_symlink_buf_ops;
-
-       return sizeof(struct xfs_dsymlink_hdr);
-}
-
-/*
- * Checking of the symlink header is split into two parts. the verifier does
- * CRC, location and bounds checking, the unpacking function checks the path
- * parameters and owner.
- */
-bool
-xfs_symlink_hdr_ok(
-       struct xfs_mount        *mp,
-       xfs_ino_t               ino,
-       uint32_t                offset,
-       uint32_t                size,
-       struct xfs_buf          *bp)
-{
-       struct xfs_dsymlink_hdr *dsl = bp->b_addr;
-
-       if (offset != be32_to_cpu(dsl->sl_offset))
-               return false;
-       if (size != be32_to_cpu(dsl->sl_bytes))
-               return false;
-       if (ino != be64_to_cpu(dsl->sl_owner))
-               return false;
-
-       /* ok */
-       return true;
-}
-
-static bool
-xfs_symlink_verify(
-       struct xfs_buf          *bp)
-{
-       struct xfs_mount        *mp = bp->b_target->bt_mount;
-       struct xfs_dsymlink_hdr *dsl = bp->b_addr;
-
-       if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return false;
-       if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
-               return false;
-       if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
-               return false;
-       if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
-               return false;
-       if (be32_to_cpu(dsl->sl_offset) +
-                               be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
-               return false;
-       if (dsl->sl_owner == 0)
-               return false;
-
-       return true;
-}
-
-static void
-xfs_symlink_read_verify(
-       struct xfs_buf  *bp)
-{
-       struct xfs_mount *mp = bp->b_target->bt_mount;
-
-       /* no verification of non-crc buffers */
-       if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return;
-
-       if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
-                                 offsetof(struct xfs_dsymlink_hdr, sl_crc)) ||
-           !xfs_symlink_verify(bp)) {
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
-               xfs_buf_ioerror(bp, EFSCORRUPTED);
-       }
-}
-
-static void
-xfs_symlink_write_verify(
-       struct xfs_buf  *bp)
-{
-       struct xfs_mount *mp = bp->b_target->bt_mount;
-       struct xfs_buf_log_item *bip = bp->b_fspriv;
-
-       /* no verification of non-crc buffers */
-       if (!xfs_sb_version_hascrc(&mp->m_sb))
-               return;
-
-       if (!xfs_symlink_verify(bp)) {
-               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
-               xfs_buf_ioerror(bp, EFSCORRUPTED);
-               return;
-       }
-
-       if (bip) {
-               struct xfs_dsymlink_hdr *dsl = bp->b_addr;
-               dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
-       }
-       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
-                        offsetof(struct xfs_dsymlink_hdr, sl_crc));
-}
-
-const struct xfs_buf_ops xfs_symlink_buf_ops = {
-       .verify_read = xfs_symlink_read_verify,
-       .verify_write = xfs_symlink_write_verify,
-};
-
-void
-xfs_symlink_local_to_remote(
-       struct xfs_trans        *tp,
-       struct xfs_buf          *bp,
-       struct xfs_inode        *ip,
-       struct xfs_ifork        *ifp)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       char                    *buf;
-
-       if (!xfs_sb_version_hascrc(&mp->m_sb)) {
-               bp->b_ops = NULL;
-               memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
-               return;
-       }
-
-       /*
-        * As this symlink fits in an inode literal area, it must also fit in
-        * the smallest buffer the filesystem supports.
-        */
-       ASSERT(BBTOB(bp->b_length) >=
-                       ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
-
-       bp->b_ops = &xfs_symlink_buf_ops;
-
-       buf = bp->b_addr;
-       buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
-       memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
-}
-
 /* ----- Kernel only functions below ----- */
 STATIC int
 xfs_readlink_bmap(
@@ -386,8 +216,11 @@ xfs_symlink(
        /*
         * Make sure that we have allocated dquot(s) on disk.
         */
-       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-               XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, &udqp, &gdqp, &pdqp);
+       error = xfs_qm_vop_dqalloc(dp,
+                       xfs_kuid_to_uid(current_fsuid()),
+                       xfs_kgid_to_gid(current_fsgid()), prid,
+                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
+                       &udqp, &gdqp, &pdqp);
        if (error)
                goto std_return;
 
@@ -402,12 +235,10 @@ xfs_symlink(
        else
                fs_blocks = xfs_symlink_blocks(mp, pathlen);
        resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks);
-       error = xfs_trans_reserve(tp, resblks, XFS_SYMLINK_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_symlink, resblks, 0);
        if (error == ENOSPC && fs_blocks == 0) {
                resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_SYMLINK_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES, XFS_SYMLINK_LOG_COUNT);
+               error = xfs_trans_reserve(tp, &M_RES(mp)->tr_symlink, 0, 0);
        }
        if (error) {
                cancel_flags = 0;
@@ -533,6 +364,7 @@ xfs_symlink(
                        pathlen -= byte_cnt;
                        offset += byte_cnt;
 
+                       xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF);
                        xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) -
                                                        (char *)bp->b_addr);
                }
@@ -710,8 +542,8 @@ xfs_inactive_symlink_rmt(
         * Put an itruncate log reservation in the new transaction
         * for our caller.
         */
-       if ((error = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_ITRUNCATE_LOG_COUNT))) {
+       error = xfs_trans_reserve(tp, &M_RES(mp)->tr_itruncate, 0, 0);
+       if (error) {
                ASSERT(XFS_FORCED_SHUTDOWN(mp));
                goto error0;
        }
index 374394880c01e4d8db8dc36d6468e748295c6f29..99338ba666ac68c11350fb1b24906364c7a6de01 100644 (file)
 #ifndef __XFS_SYMLINK_H
 #define __XFS_SYMLINK_H 1
 
-struct xfs_mount;
-struct xfs_trans;
-struct xfs_inode;
-struct xfs_buf;
-struct xfs_ifork;
-struct xfs_name;
-
-#define XFS_SYMLINK_MAGIC      0x58534c4d      /* XSLM */
-
-struct xfs_dsymlink_hdr {
-       __be32  sl_magic;
-       __be32  sl_offset;
-       __be32  sl_bytes;
-       __be32  sl_crc;
-       uuid_t  sl_uuid;
-       __be64  sl_owner;
-       __be64  sl_blkno;
-       __be64  sl_lsn;
-};
-
-/*
- * The maximum pathlen is 1024 bytes. Since the minimum file system
- * blocksize is 512 bytes, we can get a max of 3 extents back from
- * bmapi when crc headers are taken into account.
- */
-#define XFS_SYMLINK_MAPS 3
-
-#define XFS_SYMLINK_BUF_SPACE(mp, bufsize)     \
-       ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \
-                       sizeof(struct xfs_dsymlink_hdr) : 0))
-
-int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen);
-
-void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp,
-                                struct xfs_inode *ip, struct xfs_ifork *ifp);
-
-extern const struct xfs_buf_ops xfs_symlink_buf_ops;
-
-#ifdef __KERNEL__
+/* Kernel only symlink defintions */
 
 int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
                const char *target_path, umode_t mode, struct xfs_inode **ipp);
 int xfs_readlink(struct xfs_inode *ip, char *link);
 int xfs_inactive_symlink(struct xfs_inode *ip, struct xfs_trans **tpp);
 
-#endif /* __KERNEL__ */
 #endif /* __XFS_SYMLINK_H */
diff --git a/fs/xfs/xfs_symlink_remote.c b/fs/xfs/xfs_symlink_remote.c
new file mode 100644 (file)
index 0000000..01c85e3
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
+ * Copyright (c) 2012-2013 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_format.h"
+#include "xfs_log.h"
+#include "xfs_trans.h"
+#include "xfs_ag.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_error.h"
+#include "xfs_trace.h"
+#include "xfs_symlink.h"
+#include "xfs_cksum.h"
+#include "xfs_buf_item.h"
+
+
+/*
+ * Each contiguous block has a header, so it is not just a simple pathlen
+ * to FSB conversion.
+ */
+int
+xfs_symlink_blocks(
+       struct xfs_mount *mp,
+       int             pathlen)
+{
+       int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize);
+
+       return (pathlen + buflen - 1) / buflen;
+}
+
+int
+xfs_symlink_hdr_set(
+       struct xfs_mount        *mp,
+       xfs_ino_t               ino,
+       uint32_t                offset,
+       uint32_t                size,
+       struct xfs_buf          *bp)
+{
+       struct xfs_dsymlink_hdr *dsl = bp->b_addr;
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return 0;
+
+       dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
+       dsl->sl_offset = cpu_to_be32(offset);
+       dsl->sl_bytes = cpu_to_be32(size);
+       uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_uuid);
+       dsl->sl_owner = cpu_to_be64(ino);
+       dsl->sl_blkno = cpu_to_be64(bp->b_bn);
+       bp->b_ops = &xfs_symlink_buf_ops;
+
+       return sizeof(struct xfs_dsymlink_hdr);
+}
+
+/*
+ * Checking of the symlink header is split into two parts. the verifier does
+ * CRC, location and bounds checking, the unpacking function checks the path
+ * parameters and owner.
+ */
+bool
+xfs_symlink_hdr_ok(
+       struct xfs_mount        *mp,
+       xfs_ino_t               ino,
+       uint32_t                offset,
+       uint32_t                size,
+       struct xfs_buf          *bp)
+{
+       struct xfs_dsymlink_hdr *dsl = bp->b_addr;
+
+       if (offset != be32_to_cpu(dsl->sl_offset))
+               return false;
+       if (size != be32_to_cpu(dsl->sl_bytes))
+               return false;
+       if (ino != be64_to_cpu(dsl->sl_owner))
+               return false;
+
+       /* ok */
+       return true;
+}
+
+static bool
+xfs_symlink_verify(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_dsymlink_hdr *dsl = bp->b_addr;
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return false;
+       if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC))
+               return false;
+       if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_uuid))
+               return false;
+       if (bp->b_bn != be64_to_cpu(dsl->sl_blkno))
+               return false;
+       if (be32_to_cpu(dsl->sl_offset) +
+                               be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN)
+               return false;
+       if (dsl->sl_owner == 0)
+               return false;
+
+       return true;
+}
+
+static void
+xfs_symlink_read_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+
+       /* no verification of non-crc buffers */
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length),
+                                 offsetof(struct xfs_dsymlink_hdr, sl_crc)) ||
+           !xfs_symlink_verify(bp)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+       }
+}
+
+static void
+xfs_symlink_write_verify(
+       struct xfs_buf  *bp)
+{
+       struct xfs_mount *mp = bp->b_target->bt_mount;
+       struct xfs_buf_log_item *bip = bp->b_fspriv;
+
+       /* no verification of non-crc buffers */
+       if (!xfs_sb_version_hascrc(&mp->m_sb))
+               return;
+
+       if (!xfs_symlink_verify(bp)) {
+               XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
+               xfs_buf_ioerror(bp, EFSCORRUPTED);
+               return;
+       }
+
+       if (bip) {
+               struct xfs_dsymlink_hdr *dsl = bp->b_addr;
+               dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn);
+       }
+       xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length),
+                        offsetof(struct xfs_dsymlink_hdr, sl_crc));
+}
+
+const struct xfs_buf_ops xfs_symlink_buf_ops = {
+       .verify_read = xfs_symlink_read_verify,
+       .verify_write = xfs_symlink_write_verify,
+};
+
+void
+xfs_symlink_local_to_remote(
+       struct xfs_trans        *tp,
+       struct xfs_buf          *bp,
+       struct xfs_inode        *ip,
+       struct xfs_ifork        *ifp)
+{
+       struct xfs_mount        *mp = ip->i_mount;
+       char                    *buf;
+
+       if (!xfs_sb_version_hascrc(&mp->m_sb)) {
+               bp->b_ops = NULL;
+               memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
+               return;
+       }
+
+       /*
+        * As this symlink fits in an inode literal area, it must also fit in
+        * the smallest buffer the filesystem supports.
+        */
+       ASSERT(BBTOB(bp->b_length) >=
+                       ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr));
+
+       bp->b_ops = &xfs_symlink_buf_ops;
+
+       buf = bp->b_addr;
+       buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
+       memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
+}
index b6e3897c1d9f0bbeb34f3b1e610e58217ee005f4..5d7b3e40705ffe4a96c75493d09ac74d9ae265cd 100644 (file)
@@ -18,6 +18,7 @@
 #include "xfs.h"
 #include "xfs_fs.h"
 #include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
index 35a229981354159add4b143aea86682c22966a7f..5411e01ab4527318b187846fa3e7a53ad6300eb3 100644 (file)
@@ -18,7 +18,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
-#include "xfs_types.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
 kmem_zone_t    *xfs_trans_zone;
 kmem_zone_t    *xfs_log_item_desc_zone;
 
-/*
- * A buffer has a format structure overhead in the log in addition
- * to the data, so we need to take this into account when reserving
- * space in a transaction for a buffer.  Round the space required up
- * to a multiple of 128 bytes so that we don't change the historical
- * reservation that has been used for this overhead.
- */
-STATIC uint
-xfs_buf_log_overhead(void)
-{
-       return round_up(sizeof(struct xlog_op_header) +
-                       sizeof(struct xfs_buf_log_format), 128);
-}
-
-/*
- * Calculate out transaction log reservation per item in bytes.
- *
- * The nbufs argument is used to indicate the number of items that
- * will be changed in a transaction.  size is used to tell how many
- * bytes should be reserved per item.
- */
-STATIC uint
-xfs_calc_buf_res(
-       uint            nbufs,
-       uint            size)
-{
-       return nbufs * (size + xfs_buf_log_overhead());
-}
-
-/*
- * Various log reservation values.
- *
- * These are based on the size of the file system block because that is what
- * most transactions manipulate.  Each adds in an additional 128 bytes per
- * item logged to try to account for the overhead of the transaction mechanism.
- *
- * Note:  Most of the reservations underestimate the number of allocation
- * groups into which they could free extents in the xfs_bmap_finish() call.
- * This is because the number in the worst case is quite high and quite
- * unusual.  In order to fix this we need to change xfs_bmap_finish() to free
- * extents in only a single AG at a time.  This will require changes to the
- * EFI code as well, however, so that the EFI for the extents not freed is
- * logged again in each transaction.  See SGI PV #261917.
- *
- * Reservation functions here avoid a huge stack in xfs_trans_init due to
- * register overflow from temporaries in the calculations.
- */
-
-
-/*
- * In a write transaction we can allocate a maximum of 2
- * extents.  This gives:
- *    the inode getting the new extents: inode size
- *    the inode's bmap btree: max depth * block size
- *    the agfs of the ags from which the extents are allocated: 2 * sector
- *    the superblock free block counter: sector size
- *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- * And the bmap_finish transaction can free bmap blocks in a join:
- *    the agfs of the ags containing the blocks: 2 * sector size
- *    the agfls of the ags containing the blocks: 2 * sector size
- *    the super block free block counter: sector size
- *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_write_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
-                                     XFS_FSB_TO_B(mp, 1)) +
-                    xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
-                                     XFS_FSB_TO_B(mp, 1))),
-                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
-                                     XFS_FSB_TO_B(mp, 1))));
-}
-
-/*
- * In truncating a file we free up to two extents at once.  We can modify:
- *    the inode being truncated: inode size
- *    the inode's bmap btree: (max depth + 1) * block size
- * And the bmap_finish transaction can free the blocks and bmap blocks:
- *    the agf for each of the ags: 4 * sector size
- *    the agfl for each of the ags: 4 * sector size
- *    the super block to reflect the freed blocks: sector size
- *    worst case split in allocation btrees per extent assuming 4 extents:
- *             4 exts * 2 trees * (2 * max depth - 1) * block size
- *    the inode btree: max depth * blocksize
- *    the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_itruncate_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1,
-                                     XFS_FSB_TO_B(mp, 1))),
-                   (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
-                                     XFS_FSB_TO_B(mp, 1)) +
-                   xfs_calc_buf_res(5, 0) +
-                   xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                    XFS_FSB_TO_B(mp, 1)) +
-                   xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
-                                    mp->m_in_maxlevels, 0)));
-}
-
-/*
- * In renaming a files we can modify:
- *    the four inodes involved: 4 * inode size
- *    the two directory btrees: 2 * (max depth + v2) * dir block size
- *    the two directory bmap btrees: 2 * max depth * block size
- * And the bmap_finish transaction can free dir and bmap blocks (two sets
- *     of bmap blocks) giving:
- *    the agf for the ags in which the blocks live: 3 * sector size
- *    the agfl for the ags in which the blocks live: 3 * sector size
- *    the superblock for the free block count: sector size
- *    the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_rename_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_buf_res(4, mp->m_sb.sb_inodesize) +
-                    xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
-                                     XFS_FSB_TO_B(mp, 1))),
-                   (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 3),
-                                     XFS_FSB_TO_B(mp, 1))));
-}
-
-/*
- * For creating a link to an inode:
- *    the parent directory inode: inode size
- *    the linked inode: inode size
- *    the directory btree could split: (max depth + v2) * dir block size
- *    the directory bmap btree could join or split: (max depth + v2) * blocksize
- * And the bmap_finish transaction can free some bmap blocks giving:
- *    the agf for the ag in which the blocks live: sector size
- *    the agfl for the ag in which the blocks live: sector size
- *    the superblock for the free block count: sector size
- *    the allocation btrees: 2 trees * (2 * max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_link_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_buf_res(2, mp->m_sb.sb_inodesize) +
-                    xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
-                                     XFS_FSB_TO_B(mp, 1))),
-                   (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                     XFS_FSB_TO_B(mp, 1))));
-}
-
-/*
- * For removing a directory entry we can modify:
- *    the parent directory inode: inode size
- *    the removed inode: inode size
- *    the directory btree could join: (max depth + v2) * dir block size
- *    the directory bmap btree could join or split: (max depth + v2) * blocksize
- * And the bmap_finish transaction can free the dir and bmap blocks giving:
- *    the agf for the ag in which the blocks live: 2 * sector size
- *    the agfl for the ag in which the blocks live: 2 * sector size
- *    the superblock for the free block count: sector size
- *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_remove_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_buf_res(2, mp->m_sb.sb_inodesize) +
-                    xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
-                                     XFS_FSB_TO_B(mp, 1))),
-                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
-                                     XFS_FSB_TO_B(mp, 1))));
-}
-
-/*
- * For create, break it in to the two cases that the transaction
- * covers. We start with the modify case - allocation done by modification
- * of the state of existing inodes - and the allocation case.
- */
-
-/*
- * For create we can modify:
- *    the parent directory inode: inode size
- *    the new inode: inode size
- *    the inode btree entry: block size
- *    the superblock for the nlink flag: sector size
- *    the directory btree: (max depth + v2) * dir block size
- *    the directory inode's bmap btree: (max depth + v2) * block size
- */
-STATIC uint
-xfs_calc_create_resv_modify(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(2, mp->m_sb.sb_inodesize) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-               (uint)XFS_FSB_TO_B(mp, 1) +
-               xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * For create we can allocate some inodes giving:
- *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
- *    the superblock for the nlink flag: sector size
- *    the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
- *    the inode btree: max depth * blocksize
- *    the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_create_resv_alloc(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
-               mp->m_sb.sb_sectsize +
-               xfs_calc_buf_res(XFS_IALLOC_BLOCKS(mp), XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-STATIC uint
-__xfs_calc_create_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX(xfs_calc_create_resv_alloc(mp),
-                   xfs_calc_create_resv_modify(mp));
-}
-
-/*
- * For icreate we can allocate some inodes giving:
- *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
- *    the superblock for the nlink flag: sector size
- *    the inode btree: max depth * blocksize
- *    the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_icreate_resv_alloc(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
-               mp->m_sb.sb_sectsize +
-               xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-STATIC uint
-xfs_calc_icreate_reservation(xfs_mount_t *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX(xfs_calc_icreate_resv_alloc(mp),
-                   xfs_calc_create_resv_modify(mp));
-}
-
-STATIC uint
-xfs_calc_create_reservation(
-       struct xfs_mount        *mp)
-{
-       if (xfs_sb_version_hascrc(&mp->m_sb))
-               return xfs_calc_icreate_reservation(mp);
-       return __xfs_calc_create_reservation(mp);
-
-}
-
-/*
- * Making a new directory is the same as creating a new file.
- */
-STATIC uint
-xfs_calc_mkdir_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_create_reservation(mp);
-}
-
-
-/*
- * Making a new symplink is the same as creating a new file, but
- * with the added blocks for remote symlink data which can be up to 1kB in
- * length (MAXPATHLEN).
- */
-STATIC uint
-xfs_calc_symlink_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_create_reservation(mp) +
-              xfs_calc_buf_res(1, MAXPATHLEN);
-}
-
-/*
- * In freeing an inode we can modify:
- *    the inode being freed: inode size
- *    the super block free inode counter: sector size
- *    the agi hash list and counters: sector size
- *    the inode btree entry: block size
- *    the on disk inode before ours in the agi hash list: inode cluster size
- *    the inode btree: max depth * blocksize
- *    the allocation btrees: 2 trees * (max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_ifree_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-               xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
-               MAX((__uint16_t)XFS_FSB_TO_B(mp, 1),
-                   XFS_INODE_CLUSTER_SIZE(mp)) +
-               xfs_calc_buf_res(1, 0) +
-               xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
-                                mp->m_in_maxlevels, 0) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * When only changing the inode we log the inode and possibly the superblock
- * We also add a bit of slop for the transaction stuff.
- */
-STATIC uint
-xfs_calc_ichange_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               mp->m_sb.sb_inodesize +
-               mp->m_sb.sb_sectsize +
-               512;
-
-}
-
-/*
- * Growing the data section of the filesystem.
- *     superblock
- *     agi and agf
- *     allocation btrees
- */
-STATIC uint
-xfs_calc_growdata_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * Growing the rt section of the filesystem.
- * In the first set of transactions (ALLOC) we allocate space to the
- * bitmap or summary files.
- *     superblock: sector size
- *     agf of the ag from which the extent is allocated: sector size
- *     bmap btree for bitmap/summary inode: max depth * blocksize
- *     bitmap/summary inode: inode size
- *     allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize
- */
-STATIC uint
-xfs_calc_growrtalloc_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
-                                XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * Growing the rt section of the filesystem.
- * In the second set of transactions (ZERO) we zero the new metadata blocks.
- *     one bitmap/summary block: blocksize
- */
-STATIC uint
-xfs_calc_growrtzero_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_blocksize);
-}
-
-/*
- * Growing the rt section of the filesystem.
- * In the third set of transactions (FREE) we update metadata without
- * allocating any new blocks.
- *     superblock: sector size
- *     bitmap inode: inode size
- *     summary inode: inode size
- *     one bitmap block: blocksize
- *     summary blocks: new summary size
- */
-STATIC uint
-xfs_calc_growrtfree_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(2, mp->m_sb.sb_inodesize) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) +
-               xfs_calc_buf_res(1, mp->m_rsumsize);
-}
-
-/*
- * Logging the inode modification timestamp on a synchronous write.
- *     inode
- */
-STATIC uint
-xfs_calc_swrite_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_inodesize);
-}
-
-/*
- * Logging the inode mode bits when writing a setuid/setgid file
- *     inode
- */
-STATIC uint
-xfs_calc_writeid_reservation(xfs_mount_t *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_inodesize);
-}
-
-/*
- * Converting the inode from non-attributed to attributed.
- *     the inode being converted: inode size
- *     agf block and superblock (for block allocation)
- *     the new block (directory sized)
- *     bmap blocks for the new directory block
- *     allocation btrees
- */
-STATIC uint
-xfs_calc_addafork_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-               xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(1, mp->m_dirblksize) +
-               xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1,
-                                XFS_FSB_TO_B(mp, 1)) +
-               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * Removing the attribute fork of a file
- *    the inode being truncated: inode size
- *    the inode's bmap btree: max depth * block size
- * And the bmap_finish transaction can free the blocks and bmap blocks:
- *    the agf for each of the ags: 4 * sector size
- *    the agfl for each of the ags: 4 * sector size
- *    the super block to reflect the freed blocks: sector size
- *    worst case split in allocation btrees per extent assuming 4 extents:
- *             4 exts * 2 trees * (2 * max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_attrinval_reservation(
-       struct xfs_mount        *mp)
-{
-       return MAX((xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-                   xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
-                                    XFS_FSB_TO_B(mp, 1))),
-                  (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
-                   xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
-                                    XFS_FSB_TO_B(mp, 1))));
-}
-
-/*
- * Setting an attribute at mount time.
- *     the inode getting the attribute
- *     the superblock for allocations
- *     the agfs extents are allocated from
- *     the attribute btree * max depth
- *     the inode allocation btree
- * Since attribute transaction space is dependent on the size of the attribute,
- * the calculation is done partially at mount time and partially at runtime(see
- * below).
- */
-STATIC uint
-xfs_calc_attrsetm_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * Setting an attribute at runtime, transaction space unit per block.
- *     the superblock for allocations: sector size
- *     the inode bmap btree could join or split: max depth * block size
- * Since the runtime attribute transaction space is dependent on the total
- * blocks needed for the 1st bmap, here we calculate out the space unit for
- * one block so that the caller could figure out the total space according
- * to the attibute extent length in blocks by: ext * XFS_ATTRSETRT_LOG_RES(mp).
- */
-STATIC uint
-xfs_calc_attrsetrt_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
-               xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
-                                XFS_FSB_TO_B(mp, 1));
-}
-
-/*
- * Removing an attribute.
- *    the inode: inode size
- *    the attribute btree could join: max depth * block size
- *    the inode bmap btree could join or split: max depth * block size
- * And the bmap_finish transaction can free the attr blocks freed giving:
- *    the agf for the ag in which the blocks live: 2 * sector size
- *    the agfl for the ag in which the blocks live: 2 * sector size
- *    the superblock for the free block count: sector size
- *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
- */
-STATIC uint
-xfs_calc_attrrm_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_DQUOT_LOGRES(mp) +
-               MAX((xfs_calc_buf_res(1, mp->m_sb.sb_inodesize) +
-                    xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH,
-                                     XFS_FSB_TO_B(mp, 1)) +
-                    (uint)XFS_FSB_TO_B(mp,
-                                       XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) +
-                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)),
-                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
-                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
-                                     XFS_FSB_TO_B(mp, 1))));
-}
-
-/*
- * Clearing a bad agino number in an agi hash bucket.
- */
-STATIC uint
-xfs_calc_clear_agi_bucket_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
-}
-
-/*
- * Clearing the quotaflags in the superblock.
- *     the super block for changing quota flags: sector size
- */
-STATIC uint
-xfs_calc_qm_sbchange_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
-}
-
-/*
- * Adjusting quota limits.
- *    the xfs_disk_dquot_t: sizeof(struct xfs_disk_dquot)
- */
-STATIC uint
-xfs_calc_qm_setqlim_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, sizeof(struct xfs_disk_dquot));
-}
-
-/*
- * Allocating quota on disk if needed.
- *     the write transaction log space: XFS_WRITE_LOG_RES(mp)
- *     the unit of quota allocation: one system block size
- */
-STATIC uint
-xfs_calc_qm_dqalloc_reservation(
-       struct xfs_mount        *mp)
-{
-       return XFS_WRITE_LOG_RES(mp) +
-               xfs_calc_buf_res(1,
-                       XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1);
-}
-
-/*
- * Turning off quotas.
- *    the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2
- *    the superblock for the quota flags: sector size
- */
-STATIC uint
-xfs_calc_qm_quotaoff_reservation(
-       struct xfs_mount        *mp)
-{
-       return sizeof(struct xfs_qoff_logitem) * 2 +
-               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
-}
-
-/*
- * End of turning off quotas.
- *    the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2
- */
-STATIC uint
-xfs_calc_qm_quotaoff_end_reservation(
-       struct xfs_mount        *mp)
-{
-       return sizeof(struct xfs_qoff_logitem) * 2;
-}
-
-/*
- * Syncing the incore super block changes to disk.
- *     the super block to reflect the changes: sector size
- */
-STATIC uint
-xfs_calc_sb_reservation(
-       struct xfs_mount        *mp)
-{
-       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
-}
-
 /*
  * Initialize the precomputed transaction reservation values
  * in the mount structure.
@@ -679,36 +56,7 @@ void
 xfs_trans_init(
        struct xfs_mount        *mp)
 {
-       struct xfs_trans_reservations *resp = &mp->m_reservations;
-
-       resp->tr_write = xfs_calc_write_reservation(mp);
-       resp->tr_itruncate = xfs_calc_itruncate_reservation(mp);
-       resp->tr_rename = xfs_calc_rename_reservation(mp);
-       resp->tr_link = xfs_calc_link_reservation(mp);
-       resp->tr_remove = xfs_calc_remove_reservation(mp);
-       resp->tr_symlink = xfs_calc_symlink_reservation(mp);
-       resp->tr_create = xfs_calc_create_reservation(mp);
-       resp->tr_mkdir = xfs_calc_mkdir_reservation(mp);
-       resp->tr_ifree = xfs_calc_ifree_reservation(mp);
-       resp->tr_ichange = xfs_calc_ichange_reservation(mp);
-       resp->tr_growdata = xfs_calc_growdata_reservation(mp);
-       resp->tr_swrite = xfs_calc_swrite_reservation(mp);
-       resp->tr_writeid = xfs_calc_writeid_reservation(mp);
-       resp->tr_addafork = xfs_calc_addafork_reservation(mp);
-       resp->tr_attrinval = xfs_calc_attrinval_reservation(mp);
-       resp->tr_attrsetm = xfs_calc_attrsetm_reservation(mp);
-       resp->tr_attrsetrt = xfs_calc_attrsetrt_reservation(mp);
-       resp->tr_attrrm = xfs_calc_attrrm_reservation(mp);
-       resp->tr_clearagi = xfs_calc_clear_agi_bucket_reservation(mp);
-       resp->tr_growrtalloc = xfs_calc_growrtalloc_reservation(mp);
-       resp->tr_growrtzero = xfs_calc_growrtzero_reservation(mp);
-       resp->tr_growrtfree = xfs_calc_growrtfree_reservation(mp);
-       resp->tr_qm_sbchange = xfs_calc_qm_sbchange_reservation(mp);
-       resp->tr_qm_setqlim = xfs_calc_qm_setqlim_reservation(mp);
-       resp->tr_qm_dqalloc = xfs_calc_qm_dqalloc_reservation(mp);
-       resp->tr_qm_quotaoff = xfs_calc_qm_quotaoff_reservation(mp);
-       resp->tr_qm_equotaoff = xfs_calc_qm_quotaoff_end_reservation(mp);
-       resp->tr_sb = xfs_calc_sb_reservation(mp);
+       xfs_trans_resv_calc(mp, M_RES(mp));
 }
 
 /*
@@ -744,7 +92,7 @@ _xfs_trans_alloc(
        atomic_inc(&mp->m_active_trans);
 
        tp = kmem_zone_zalloc(xfs_trans_zone, memflags);
-       tp->t_magic = XFS_TRANS_MAGIC;
+       tp->t_magic = XFS_TRANS_HEADER_MAGIC;
        tp->t_type = type;
        tp->t_mountp = mp;
        INIT_LIST_HEAD(&tp->t_items);
@@ -789,7 +137,7 @@ xfs_trans_dup(
        /*
         * Initialize the new transaction structure.
         */
-       ntp->t_magic = XFS_TRANS_MAGIC;
+       ntp->t_magic = XFS_TRANS_HEADER_MAGIC;
        ntp->t_type = tp->t_type;
        ntp->t_mountp = tp->t_mountp;
        INIT_LIST_HEAD(&ntp->t_items);
@@ -832,12 +180,10 @@ xfs_trans_dup(
  */
 int
 xfs_trans_reserve(
-       xfs_trans_t     *tp,
-       uint            blocks,
-       uint            logspace,
-       uint            rtextents,
-       uint            flags,
-       uint            logcount)
+       struct xfs_trans        *tp,
+       struct xfs_trans_res    *resp,
+       uint                    blocks,
+       uint                    rtextents)
 {
        int             error = 0;
        int             rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0;
@@ -863,13 +209,15 @@ xfs_trans_reserve(
        /*
         * Reserve the log space needed for this transaction.
         */
-       if (logspace > 0) {
+       if (resp->tr_logres > 0) {
                bool    permanent = false;
 
-               ASSERT(tp->t_log_res == 0 || tp->t_log_res == logspace);
-               ASSERT(tp->t_log_count == 0 || tp->t_log_count == logcount);
+               ASSERT(tp->t_log_res == 0 ||
+                      tp->t_log_res == resp->tr_logres);
+               ASSERT(tp->t_log_count == 0 ||
+                      tp->t_log_count == resp->tr_logcount);
 
-               if (flags & XFS_TRANS_PERM_LOG_RES) {
+               if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) {
                        tp->t_flags |= XFS_TRANS_PERM_LOG_RES;
                        permanent = true;
                } else {
@@ -878,20 +226,21 @@ xfs_trans_reserve(
                }
 
                if (tp->t_ticket != NULL) {
-                       ASSERT(flags & XFS_TRANS_PERM_LOG_RES);
+                       ASSERT(resp->tr_logflags & XFS_TRANS_PERM_LOG_RES);
                        error = xfs_log_regrant(tp->t_mountp, tp->t_ticket);
                } else {
-                       error = xfs_log_reserve(tp->t_mountp, logspace,
-                                               logcount, &tp->t_ticket,
-                                               XFS_TRANSACTION, permanent,
-                                               tp->t_type);
+                       error = xfs_log_reserve(tp->t_mountp,
+                                               resp->tr_logres,
+                                               resp->tr_logcount,
+                                               &tp->t_ticket, XFS_TRANSACTION,
+                                               permanent, tp->t_type);
                }
 
                if (error)
                        goto undo_blocks;
 
-               tp->t_log_res = logspace;
-               tp->t_log_count = logcount;
+               tp->t_log_res = resp->tr_logres;
+               tp->t_log_count = resp->tr_logcount;
        }
 
        /*
@@ -916,10 +265,10 @@ xfs_trans_reserve(
         * reservations which have already been performed.
         */
 undo_log:
-       if (logspace > 0) {
+       if (resp->tr_logres > 0) {
                int             log_flags;
 
-               if (flags & XFS_TRANS_PERM_LOG_RES) {
+               if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) {
                        log_flags = XFS_LOG_REL_PERM_RESERV;
                } else {
                        log_flags = 0;
@@ -1367,10 +716,10 @@ xfs_trans_free_items(
                lip->li_desc = NULL;
 
                if (commit_lsn != NULLCOMMITLSN)
-                       IOP_COMMITTING(lip, commit_lsn);
+                       lip->li_ops->iop_committing(lip, commit_lsn);
                if (flags & XFS_TRANS_ABORT)
                        lip->li_flags |= XFS_LI_ABORTED;
-               IOP_UNLOCK(lip);
+               lip->li_ops->iop_unlock(lip);
 
                xfs_trans_free_item_desc(lidp);
        }
@@ -1390,8 +739,11 @@ xfs_log_item_batch_insert(
        /* xfs_trans_ail_update_bulk drops ailp->xa_lock */
        xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn);
 
-       for (i = 0; i < nr_items; i++)
-               IOP_UNPIN(log_items[i], 0);
+       for (i = 0; i < nr_items; i++) {
+               struct xfs_log_item *lip = log_items[i];
+
+               lip->li_ops->iop_unpin(lip, 0);
+       }
 }
 
 /*
@@ -1401,11 +753,11 @@ xfs_log_item_batch_insert(
  *
  * If we are called with the aborted flag set, it is because a log write during
  * a CIL checkpoint commit has failed. In this case, all the items in the
- * checkpoint have already gone through IOP_COMMITED and IOP_UNLOCK, which
+ * checkpoint have already gone through iop_commited and iop_unlock, which
  * means that checkpoint commit abort handling is treated exactly the same
  * as an iclog write error even though we haven't started any IO yet. Hence in
- * this case all we need to do is IOP_COMMITTED processing, followed by an
- * IOP_UNPIN(aborted) call.
+ * this case all we need to do is iop_committed processing, followed by an
+ * iop_unpin(aborted) call.
  *
  * The AIL cursor is used to optimise the insert process. If commit_lsn is not
  * at the end of the AIL, the insert cursor avoids the need to walk
@@ -1438,7 +790,7 @@ xfs_trans_committed_bulk(
 
                if (aborted)
                        lip->li_flags |= XFS_LI_ABORTED;
-               item_lsn = IOP_COMMITTED(lip, commit_lsn);
+               item_lsn = lip->li_ops->iop_committed(lip, commit_lsn);
 
                /* item_lsn of -1 means the item needs no further processing */
                if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0)
@@ -1450,7 +802,7 @@ xfs_trans_committed_bulk(
                 */
                if (aborted) {
                        ASSERT(XFS_FORCED_SHUTDOWN(ailp->xa_mount));
-                       IOP_UNPIN(lip, 1);
+                       lip->li_ops->iop_unpin(lip, 1);
                        continue;
                }
 
@@ -1468,7 +820,7 @@ xfs_trans_committed_bulk(
                                xfs_trans_ail_update(ailp, lip, item_lsn);
                        else
                                spin_unlock(&ailp->xa_lock);
-                       IOP_UNPIN(lip, 0);
+                       lip->li_ops->iop_unpin(lip, 0);
                        continue;
                }
 
@@ -1666,7 +1018,7 @@ xfs_trans_roll(
        struct xfs_inode        *dp)
 {
        struct xfs_trans        *trans;
-       unsigned int            logres, count;
+       struct xfs_trans_res    tres;
        int                     error;
 
        /*
@@ -1678,8 +1030,8 @@ xfs_trans_roll(
        /*
         * Copy the critical parameters from one trans to the next.
         */
-       logres = trans->t_log_res;
-       count = trans->t_log_count;
+       tres.tr_logres = trans->t_log_res;
+       tres.tr_logcount = trans->t_log_count;
        *tpp = xfs_trans_dup(trans);
 
        /*
@@ -1710,8 +1062,8 @@ xfs_trans_roll(
         * across this call, or that anything that is locked be logged in
         * the prior and the next transactions.
         */
-       error = xfs_trans_reserve(trans, 0, logres, 0,
-                                 XFS_TRANS_PERM_LOG_RES, count);
+       tres.tr_logflags = XFS_TRANS_PERM_LOG_RES;
+       error = xfs_trans_reserve(trans, &tres, 0, 0);
        /*
         *  Ensure that the inode is in the new transaction and locked.
         */
index 2b4946393e30f56655e55c782813778760846f79..09cf40b89e8c1d85817cc649b22a12c3ba97aa78 100644 (file)
 
 struct xfs_log_item;
 
-/*
- * This is the structure written in the log at the head of
- * every transaction. It identifies the type and id of the
- * transaction, and contains the number of items logged by
- * the transaction so we know how many to expect during recovery.
- *
- * Do not change the below structure without redoing the code in
- * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans().
- */
-typedef struct xfs_trans_header {
-       uint            th_magic;               /* magic number */
-       uint            th_type;                /* transaction type */
-       __int32_t       th_tid;                 /* transaction id (unused) */
-       uint            th_num_items;           /* num items logged by trans */
-} xfs_trans_header_t;
-
-#define        XFS_TRANS_HEADER_MAGIC  0x5452414e      /* TRAN */
-
-/*
- * Log item types.
- */
-#define        XFS_LI_EFI              0x1236
-#define        XFS_LI_EFD              0x1237
-#define        XFS_LI_IUNLINK          0x1238
-#define        XFS_LI_INODE            0x123b  /* aligned ino chunks, var-size ibufs */
-#define        XFS_LI_BUF              0x123c  /* v2 bufs, variable sized inode bufs */
-#define        XFS_LI_DQUOT            0x123d
-#define        XFS_LI_QUOTAOFF         0x123e
-#define        XFS_LI_ICREATE          0x123f
-
-#define XFS_LI_TYPE_DESC \
-       { XFS_LI_EFI,           "XFS_LI_EFI" }, \
-       { XFS_LI_EFD,           "XFS_LI_EFD" }, \
-       { XFS_LI_IUNLINK,       "XFS_LI_IUNLINK" }, \
-       { XFS_LI_INODE,         "XFS_LI_INODE" }, \
-       { XFS_LI_BUF,           "XFS_LI_BUF" }, \
-       { XFS_LI_DQUOT,         "XFS_LI_DQUOT" }, \
-       { XFS_LI_QUOTAOFF,      "XFS_LI_QUOTAOFF" }
-
-/*
- * Transaction types.  Used to distinguish types of buffers.
- */
-#define XFS_TRANS_SETATTR_NOT_SIZE     1
-#define XFS_TRANS_SETATTR_SIZE         2
-#define XFS_TRANS_INACTIVE             3
-#define XFS_TRANS_CREATE               4
-#define XFS_TRANS_CREATE_TRUNC         5
-#define XFS_TRANS_TRUNCATE_FILE                6
-#define XFS_TRANS_REMOVE               7
-#define XFS_TRANS_LINK                 8
-#define XFS_TRANS_RENAME               9
-#define XFS_TRANS_MKDIR                        10
-#define XFS_TRANS_RMDIR                        11
-#define XFS_TRANS_SYMLINK              12
-#define XFS_TRANS_SET_DMATTRS          13
-#define XFS_TRANS_GROWFS               14
-#define XFS_TRANS_STRAT_WRITE          15
-#define XFS_TRANS_DIOSTRAT             16
-/* 17 was XFS_TRANS_WRITE_SYNC */
-#define        XFS_TRANS_WRITEID               18
-#define        XFS_TRANS_ADDAFORK              19
-#define        XFS_TRANS_ATTRINVAL             20
-#define        XFS_TRANS_ATRUNCATE             21
-#define        XFS_TRANS_ATTR_SET              22
-#define        XFS_TRANS_ATTR_RM               23
-#define        XFS_TRANS_ATTR_FLAG             24
-#define        XFS_TRANS_CLEAR_AGI_BUCKET      25
-#define XFS_TRANS_QM_SBCHANGE          26
-/*
- * Dummy entries since we use the transaction type to index into the
- * trans_type[] in xlog_recover_print_trans_head()
- */
-#define XFS_TRANS_DUMMY1               27
-#define XFS_TRANS_DUMMY2               28
-#define XFS_TRANS_QM_QUOTAOFF          29
-#define XFS_TRANS_QM_DQALLOC           30
-#define XFS_TRANS_QM_SETQLIM           31
-#define XFS_TRANS_QM_DQCLUSTER         32
-#define XFS_TRANS_QM_QINOCREATE                33
-#define XFS_TRANS_QM_QUOTAOFF_END      34
-#define XFS_TRANS_SB_UNIT              35
-#define XFS_TRANS_FSYNC_TS             36
-#define        XFS_TRANS_GROWFSRT_ALLOC        37
-#define        XFS_TRANS_GROWFSRT_ZERO         38
-#define        XFS_TRANS_GROWFSRT_FREE         39
-#define        XFS_TRANS_SWAPEXT               40
-#define        XFS_TRANS_SB_COUNT              41
-#define        XFS_TRANS_CHECKPOINT            42
-#define        XFS_TRANS_ICREATE               43
-#define        XFS_TRANS_TYPE_MAX              43
-/* new transaction types need to be reflected in xfs_logprint(8) */
-
-#define XFS_TRANS_TYPES \
-       { XFS_TRANS_SETATTR_NOT_SIZE,   "SETATTR_NOT_SIZE" }, \
-       { XFS_TRANS_SETATTR_SIZE,       "SETATTR_SIZE" }, \
-       { XFS_TRANS_INACTIVE,           "INACTIVE" }, \
-       { XFS_TRANS_CREATE,             "CREATE" }, \
-       { XFS_TRANS_CREATE_TRUNC,       "CREATE_TRUNC" }, \
-       { XFS_TRANS_TRUNCATE_FILE,      "TRUNCATE_FILE" }, \
-       { XFS_TRANS_REMOVE,             "REMOVE" }, \
-       { XFS_TRANS_LINK,               "LINK" }, \
-       { XFS_TRANS_RENAME,             "RENAME" }, \
-       { XFS_TRANS_MKDIR,              "MKDIR" }, \
-       { XFS_TRANS_RMDIR,              "RMDIR" }, \
-       { XFS_TRANS_SYMLINK,            "SYMLINK" }, \
-       { XFS_TRANS_SET_DMATTRS,        "SET_DMATTRS" }, \
-       { XFS_TRANS_GROWFS,             "GROWFS" }, \
-       { XFS_TRANS_STRAT_WRITE,        "STRAT_WRITE" }, \
-       { XFS_TRANS_DIOSTRAT,           "DIOSTRAT" }, \
-       { XFS_TRANS_WRITEID,            "WRITEID" }, \
-       { XFS_TRANS_ADDAFORK,           "ADDAFORK" }, \
-       { XFS_TRANS_ATTRINVAL,          "ATTRINVAL" }, \
-       { XFS_TRANS_ATRUNCATE,          "ATRUNCATE" }, \
-       { XFS_TRANS_ATTR_SET,           "ATTR_SET" }, \
-       { XFS_TRANS_ATTR_RM,            "ATTR_RM" }, \
-       { XFS_TRANS_ATTR_FLAG,          "ATTR_FLAG" }, \
-       { XFS_TRANS_CLEAR_AGI_BUCKET,   "CLEAR_AGI_BUCKET" }, \
-       { XFS_TRANS_QM_SBCHANGE,        "QM_SBCHANGE" }, \
-       { XFS_TRANS_QM_QUOTAOFF,        "QM_QUOTAOFF" }, \
-       { XFS_TRANS_QM_DQALLOC,         "QM_DQALLOC" }, \
-       { XFS_TRANS_QM_SETQLIM,         "QM_SETQLIM" }, \
-       { XFS_TRANS_QM_DQCLUSTER,       "QM_DQCLUSTER" }, \
-       { XFS_TRANS_QM_QINOCREATE,      "QM_QINOCREATE" }, \
-       { XFS_TRANS_QM_QUOTAOFF_END,    "QM_QOFF_END" }, \
-       { XFS_TRANS_SB_UNIT,            "SB_UNIT" }, \
-       { XFS_TRANS_FSYNC_TS,           "FSYNC_TS" }, \
-       { XFS_TRANS_GROWFSRT_ALLOC,     "GROWFSRT_ALLOC" }, \
-       { XFS_TRANS_GROWFSRT_ZERO,      "GROWFSRT_ZERO" }, \
-       { 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" }
-
-/*
- * This structure is used to track log items associated with
- * a transaction.  It points to the log item and keeps some
- * flags to track the state of the log item.  It also tracks
- * the amount of space needed to log the item it describes
- * once we get to commit processing (see xfs_trans_commit()).
- */
-struct xfs_log_item_desc {
-       struct xfs_log_item     *lid_item;
-       struct list_head        lid_trans;
-       unsigned char           lid_flags;
-};
-
-#define XFS_LID_DIRTY          0x1
-
-#define        XFS_TRANS_MAGIC         0x5452414E      /* 'TRAN' */
-/*
- * Values for t_flags.
- */
-#define        XFS_TRANS_DIRTY         0x01    /* something needs to be logged */
-#define        XFS_TRANS_SB_DIRTY      0x02    /* superblock is modified */
-#define        XFS_TRANS_PERM_LOG_RES  0x04    /* xact took a permanent log res */
-#define        XFS_TRANS_SYNC          0x08    /* make commit synchronous */
-#define XFS_TRANS_DQ_DIRTY     0x10    /* at least one dquot in trx dirty */
-#define XFS_TRANS_RESERVE      0x20    /* OK to use reserved data blocks */
-#define XFS_TRANS_FREEZE_PROT  0x40    /* Transaction has elevated writer
-                                          count in superblock */
-
-/*
- * Values for call flags parameter.
- */
-#define        XFS_TRANS_RELEASE_LOG_RES       0x4
-#define        XFS_TRANS_ABORT                 0x8
-
-/*
- * Field values for xfs_trans_mod_sb.
- */
-#define        XFS_TRANS_SB_ICOUNT             0x00000001
-#define        XFS_TRANS_SB_IFREE              0x00000002
-#define        XFS_TRANS_SB_FDBLOCKS           0x00000004
-#define        XFS_TRANS_SB_RES_FDBLOCKS       0x00000008
-#define        XFS_TRANS_SB_FREXTENTS          0x00000010
-#define        XFS_TRANS_SB_RES_FREXTENTS      0x00000020
-#define        XFS_TRANS_SB_DBLOCKS            0x00000040
-#define        XFS_TRANS_SB_AGCOUNT            0x00000080
-#define        XFS_TRANS_SB_IMAXPCT            0x00000100
-#define        XFS_TRANS_SB_REXTSIZE           0x00000200
-#define        XFS_TRANS_SB_RBMBLOCKS          0x00000400
-#define        XFS_TRANS_SB_RBLOCKS            0x00000800
-#define        XFS_TRANS_SB_REXTENTS           0x00001000
-#define        XFS_TRANS_SB_REXTSLOG           0x00002000
-
-
-/*
- * Per-extent log reservation for the allocation btree changes
- * involved in freeing or allocating an extent.
- * 2 trees * (2 blocks/level * max depth - 1)
- */
-#define        XFS_ALLOCFREE_LOG_COUNT(mp,nx) \
-       ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1)))
-
-/*
- * Per-directory log reservation for any directory change.
- * dir blocks: (1 btree block per level + data block + free block)
- * bmap btree: (levels + 2) * max depth
- * v2 directory blocks can be fragmented below the dirblksize down to the fsb
- * size, so account for that in the DAENTER macros.
- */
-#define        XFS_DIROP_LOG_COUNT(mp) \
-       (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \
-        XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1)
-
+#include "xfs_trans_resv.h"
 
-#define        XFS_WRITE_LOG_RES(mp)   ((mp)->m_reservations.tr_write)
-#define        XFS_ITRUNCATE_LOG_RES(mp)   ((mp)->m_reservations.tr_itruncate)
-#define        XFS_RENAME_LOG_RES(mp)  ((mp)->m_reservations.tr_rename)
-#define        XFS_LINK_LOG_RES(mp)    ((mp)->m_reservations.tr_link)
-#define        XFS_REMOVE_LOG_RES(mp)  ((mp)->m_reservations.tr_remove)
-#define        XFS_SYMLINK_LOG_RES(mp) ((mp)->m_reservations.tr_symlink)
-#define        XFS_CREATE_LOG_RES(mp)  ((mp)->m_reservations.tr_create)
-#define        XFS_MKDIR_LOG_RES(mp)   ((mp)->m_reservations.tr_mkdir)
-#define        XFS_IFREE_LOG_RES(mp)   ((mp)->m_reservations.tr_ifree)
-#define        XFS_ICHANGE_LOG_RES(mp) ((mp)->m_reservations.tr_ichange)
-#define        XFS_GROWDATA_LOG_RES(mp)    ((mp)->m_reservations.tr_growdata)
-#define        XFS_GROWRTALLOC_LOG_RES(mp)     ((mp)->m_reservations.tr_growrtalloc)
-#define        XFS_GROWRTZERO_LOG_RES(mp)      ((mp)->m_reservations.tr_growrtzero)
-#define        XFS_GROWRTFREE_LOG_RES(mp)      ((mp)->m_reservations.tr_growrtfree)
-#define        XFS_SWRITE_LOG_RES(mp)  ((mp)->m_reservations.tr_swrite)
-/*
- * Logging the inode timestamps on an fsync -- same as SWRITE
- * as long as SWRITE logs the entire inode core
- */
-#define XFS_FSYNC_TS_LOG_RES(mp)        ((mp)->m_reservations.tr_swrite)
-#define        XFS_WRITEID_LOG_RES(mp)         ((mp)->m_reservations.tr_swrite)
-#define        XFS_ADDAFORK_LOG_RES(mp)        ((mp)->m_reservations.tr_addafork)
-#define        XFS_ATTRINVAL_LOG_RES(mp)       ((mp)->m_reservations.tr_attrinval)
-#define        XFS_ATTRSETM_LOG_RES(mp)        ((mp)->m_reservations.tr_attrsetm)
-#define XFS_ATTRSETRT_LOG_RES(mp)      ((mp)->m_reservations.tr_attrsetrt)
-#define        XFS_ATTRRM_LOG_RES(mp)          ((mp)->m_reservations.tr_attrrm)
-#define        XFS_CLEAR_AGI_BUCKET_LOG_RES(mp)  ((mp)->m_reservations.tr_clearagi)
-#define XFS_QM_SBCHANGE_LOG_RES(mp)    ((mp)->m_reservations.tr_qm_sbchange)
-#define XFS_QM_SETQLIM_LOG_RES(mp)     ((mp)->m_reservations.tr_qm_setqlim)
-#define XFS_QM_DQALLOC_LOG_RES(mp)     ((mp)->m_reservations.tr_qm_dqalloc)
-#define XFS_QM_QUOTAOFF_LOG_RES(mp)    ((mp)->m_reservations.tr_qm_quotaoff)
-#define XFS_QM_QUOTAOFF_END_LOG_RES(mp)        ((mp)->m_reservations.tr_qm_equotaoff)
-#define XFS_SB_LOG_RES(mp)             ((mp)->m_reservations.tr_sb)
-
-/*
- * Various log count values.
- */
-#define        XFS_DEFAULT_LOG_COUNT           1
-#define        XFS_DEFAULT_PERM_LOG_COUNT      2
-#define        XFS_ITRUNCATE_LOG_COUNT         2
-#define XFS_INACTIVE_LOG_COUNT         2
-#define        XFS_CREATE_LOG_COUNT            2
-#define        XFS_MKDIR_LOG_COUNT             3
-#define        XFS_SYMLINK_LOG_COUNT           3
-#define        XFS_REMOVE_LOG_COUNT            2
-#define        XFS_LINK_LOG_COUNT              2
-#define        XFS_RENAME_LOG_COUNT            2
-#define        XFS_WRITE_LOG_COUNT             2
-#define        XFS_ADDAFORK_LOG_COUNT          2
-#define        XFS_ATTRINVAL_LOG_COUNT         1
-#define        XFS_ATTRSET_LOG_COUNT           3
-#define        XFS_ATTRRM_LOG_COUNT            3
-
-/*
- * Here we centralize the specification of XFS meta-data buffer
- * reference count values.  This determine how hard the buffer
- * cache tries to hold onto the buffer.
- */
-#define        XFS_AGF_REF             4
-#define        XFS_AGI_REF             4
-#define        XFS_AGFL_REF            3
-#define        XFS_INO_BTREE_REF       3
-#define        XFS_ALLOC_BTREE_REF     2
-#define        XFS_BMAP_BTREE_REF      2
-#define        XFS_DIR_BTREE_REF       2
-#define        XFS_INO_REF             2
-#define        XFS_ATTR_BTREE_REF      1
-#define        XFS_DQUOT_REF           1
-
-#ifdef __KERNEL__
+/* kernel only transaction subsystem defines */
 
 struct xfs_buf;
 struct xfs_buftarg;
@@ -310,6 +34,7 @@ struct xfs_log_iovec;
 struct xfs_log_item_desc;
 struct xfs_mount;
 struct xfs_trans;
+struct xfs_trans_res;
 struct xfs_dquot_acct;
 struct xfs_busy_extent;
 
@@ -342,7 +67,7 @@ typedef struct xfs_log_item {
        { XFS_LI_ABORTED,       "ABORTED" }
 
 struct xfs_item_ops {
-       uint (*iop_size)(xfs_log_item_t *);
+       void (*iop_size)(xfs_log_item_t *, int *, int *);
        void (*iop_format)(xfs_log_item_t *, struct xfs_log_iovec *);
        void (*iop_pin)(xfs_log_item_t *);
        void (*iop_unpin)(xfs_log_item_t *, int remove);
@@ -352,17 +77,8 @@ struct xfs_item_ops {
        void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
 };
 
-#define IOP_SIZE(ip)           (*(ip)->li_ops->iop_size)(ip)
-#define IOP_FORMAT(ip,vp)      (*(ip)->li_ops->iop_format)(ip, vp)
-#define IOP_PIN(ip)            (*(ip)->li_ops->iop_pin)(ip)
-#define IOP_UNPIN(ip, remove)  (*(ip)->li_ops->iop_unpin)(ip, remove)
-#define IOP_PUSH(ip, list)     (*(ip)->li_ops->iop_push)(ip, list)
-#define IOP_UNLOCK(ip)         (*(ip)->li_ops->iop_unlock)(ip)
-#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
-#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
-
 /*
- * Return values for the IOP_PUSH() routines.
+ * Return values for the iop_push() routines.
  */
 #define XFS_ITEM_SUCCESS       0
 #define XFS_ITEM_PINNED                1
@@ -446,7 +162,7 @@ typedef struct xfs_trans {
 xfs_trans_t    *xfs_trans_alloc(struct xfs_mount *, uint);
 xfs_trans_t    *_xfs_trans_alloc(struct xfs_mount *, uint, xfs_km_flags_t);
 xfs_trans_t    *xfs_trans_dup(xfs_trans_t *);
-int            xfs_trans_reserve(xfs_trans_t *, uint, uint, uint,
+int            xfs_trans_reserve(struct xfs_trans *, struct xfs_trans_res *,
                                  uint, uint);
 void           xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t);
 
@@ -528,9 +244,4 @@ void                xfs_trans_ail_destroy(struct xfs_mount *);
 extern kmem_zone_t     *xfs_trans_zone;
 extern kmem_zone_t     *xfs_log_item_desc_zone;
 
-#endif /* __KERNEL__ */
-
-void           xfs_trans_init(struct xfs_mount *);
-int            xfs_trans_roll(struct xfs_trans **, struct xfs_inode *);
-
 #endif /* __XFS_TRANS_H__ */
index 0eda7254305f3c5a6524a378596215c8cf861140..21c6d7ddbc06b474e102b30cb6a13c7690d1a2a5 100644 (file)
@@ -61,20 +61,6 @@ xfs_ail_check(
 #endif /* DEBUG */
 
 /*
- * Return a pointer to the first item in the AIL.  If the AIL is empty, then
- * return NULL.
- */
-xfs_log_item_t *
-xfs_ail_min(
-       struct xfs_ail  *ailp)
-{
-       if (list_empty(&ailp->xa_ail))
-               return NULL;
-
-       return list_first_entry(&ailp->xa_ail, xfs_log_item_t, li_ail);
-}
-
- /*
  * Return a pointer to the last item in the AIL.  If the AIL is empty, then
  * return NULL.
  */
@@ -393,11 +379,11 @@ xfsaild_push(
                int     lock_result;
 
                /*
-                * Note that IOP_PUSH may unlock and reacquire the AIL lock.  We
+                * Note that iop_push may unlock and reacquire the AIL lock.  We
                 * rely on the AIL cursor implementation to be able to deal with
                 * the dropped lock.
                 */
-               lock_result = IOP_PUSH(lip, &ailp->xa_buf_list);
+               lock_result = lip->li_ops->iop_push(lip, &ailp->xa_buf_list);
                switch (lock_result) {
                case XFS_ITEM_SUCCESS:
                        XFS_STATS_INC(xs_push_ail_success);
index aa5a04b844d6d530b12edd39b3f99240aff625bc..8c75b8f672702419beede8e54363ec259616039a 100644 (file)
@@ -505,7 +505,7 @@ xfs_trans_brelse(xfs_trans_t        *tp,
 
 /*
  * Mark the buffer as not needing to be unlocked when the buf item's
- * IOP_UNLOCK() routine is called.  The buffer must already be locked
+ * iop_unlock() routine is called.  The buffer must already be locked
  * and associated with the given transaction.
  */
 /* ARGSUSED */
index 61407a847b869a6bb0faec7bf2c3279d66aaeb83..54ee3c5dee76093b6a6136a5fde759a8be309ccd 100644 (file)
@@ -17,6 +17,7 @@
  */
 #include "xfs.h"
 #include "xfs_fs.h"
+#include "xfs_format.h"
 #include "xfs_log.h"
 #include "xfs_trans.h"
 #include "xfs_sb.h"
index 53b7c9b0f8f7a6fa3c96a3f73298c2862eb3d107..c52def0b441cd89f2cb207e1b7ba5a9f22cc915c 100644 (file)
@@ -25,6 +25,9 @@ struct xfs_trans;
 struct xfs_ail;
 struct xfs_log_vec;
 
+
+void   xfs_trans_init(struct xfs_mount *);
+int    xfs_trans_roll(struct xfs_trans **, struct xfs_inode *);
 void   xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *);
 void   xfs_trans_del_item(struct xfs_log_item *);
 void   xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn,
@@ -83,6 +86,18 @@ void xfs_trans_ail_update_bulk(struct xfs_ail *ailp,
                                struct xfs_ail_cursor *cur,
                                struct xfs_log_item **log_items, int nr_items,
                                xfs_lsn_t lsn) __releases(ailp->xa_lock);
+/*
+ * Return a pointer to the first item in the AIL.  If the AIL is empty, then
+ * return NULL.
+ */
+static inline struct xfs_log_item *
+xfs_ail_min(
+       struct xfs_ail  *ailp)
+{
+       return list_first_entry_or_null(&ailp->xa_ail, struct xfs_log_item,
+                                       li_ail);
+}
+
 static inline void
 xfs_trans_ail_update(
        struct xfs_ail          *ailp,
diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c
new file mode 100644 (file)
index 0000000..a65a3cc
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+ * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
+ * 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_format.h"
+#include "xfs_log.h"
+#include "xfs_trans_resv.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_ag.h"
+#include "xfs_mount.h"
+#include "xfs_error.h"
+#include "xfs_da_btree.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_alloc_btree.h"
+#include "xfs_ialloc_btree.h"
+#include "xfs_dinode.h"
+#include "xfs_inode.h"
+#include "xfs_btree.h"
+#include "xfs_ialloc.h"
+#include "xfs_alloc.h"
+#include "xfs_extent_busy.h"
+#include "xfs_bmap.h"
+#include "xfs_bmap_util.h"
+#include "xfs_quota.h"
+#include "xfs_qm.h"
+#include "xfs_trans_space.h"
+#include "xfs_trace.h"
+
+/*
+ * A buffer has a format structure overhead in the log in addition
+ * to the data, so we need to take this into account when reserving
+ * space in a transaction for a buffer.  Round the space required up
+ * to a multiple of 128 bytes so that we don't change the historical
+ * reservation that has been used for this overhead.
+ */
+STATIC uint
+xfs_buf_log_overhead(void)
+{
+       return round_up(sizeof(struct xlog_op_header) +
+                       sizeof(struct xfs_buf_log_format), 128);
+}
+
+/*
+ * Calculate out transaction log reservation per item in bytes.
+ *
+ * The nbufs argument is used to indicate the number of items that
+ * will be changed in a transaction.  size is used to tell how many
+ * bytes should be reserved per item.
+ */
+STATIC uint
+xfs_calc_buf_res(
+       uint            nbufs,
+       uint            size)
+{
+       return nbufs * (size + xfs_buf_log_overhead());
+}
+
+/*
+ * Logging inodes is really tricksy. They are logged in memory format,
+ * which means that what we write into the log doesn't directly translate into
+ * the amount of space they use on disk.
+ *
+ * Case in point - btree format forks in memory format use more space than the
+ * on-disk format. In memory, the buffer contains a normal btree block header so
+ * the btree code can treat it as though it is just another generic buffer.
+ * However, when we write it to the inode fork, we don't write all of this
+ * header as it isn't needed. e.g. the root is only ever in the inode, so
+ * there's no need for sibling pointers which would waste 16 bytes of space.
+ *
+ * Hence when we have an inode with a maximally sized btree format fork, then
+ * amount of information we actually log is greater than the size of the inode
+ * on disk. Hence we need an inode reservation function that calculates all this
+ * correctly. So, we log:
+ *
+ * - log op headers for object
+ * - inode log format object
+ * - the entire inode contents (core + 2 forks)
+ * - two bmap btree block headers
+ */
+STATIC uint
+xfs_calc_inode_res(
+       struct xfs_mount        *mp,
+       uint                    ninodes)
+{
+       return ninodes * (sizeof(struct xlog_op_header) +
+                         sizeof(struct xfs_inode_log_format) +
+                         mp->m_sb.sb_inodesize +
+                         2 * XFS_BMBT_BLOCK_LEN(mp));
+}
+
+/*
+ * Various log reservation values.
+ *
+ * These are based on the size of the file system block because that is what
+ * most transactions manipulate.  Each adds in an additional 128 bytes per
+ * item logged to try to account for the overhead of the transaction mechanism.
+ *
+ * Note:  Most of the reservations underestimate the number of allocation
+ * groups into which they could free extents in the xfs_bmap_finish() call.
+ * This is because the number in the worst case is quite high and quite
+ * unusual.  In order to fix this we need to change xfs_bmap_finish() to free
+ * extents in only a single AG at a time.  This will require changes to the
+ * EFI code as well, however, so that the EFI for the extents not freed is
+ * logged again in each transaction.  See SGI PV #261917.
+ *
+ * Reservation functions here avoid a huge stack in xfs_trans_init due to
+ * register overflow from temporaries in the calculations.
+ */
+
+
+/*
+ * In a write transaction we can allocate a maximum of 2
+ * extents.  This gives:
+ *    the inode getting the new extents: inode size
+ *    the inode's bmap btree: max depth * block size
+ *    the agfs of the ags from which the extents are allocated: 2 * sector
+ *    the superblock free block counter: sector size
+ *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ * And the bmap_finish transaction can free bmap blocks in a join:
+ *    the agfs of the ags containing the blocks: 2 * sector size
+ *    the agfls of the ags containing the blocks: 2 * sector size
+ *    the super block free block counter: sector size
+ *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_write_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX((xfs_calc_inode_res(mp, 1) +
+                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
+                                     XFS_FSB_TO_B(mp, 1)) +
+                    xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                                     XFS_FSB_TO_B(mp, 1))),
+                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                                     XFS_FSB_TO_B(mp, 1))));
+}
+
+/*
+ * In truncating a file we free up to two extents at once.  We can modify:
+ *    the inode being truncated: inode size
+ *    the inode's bmap btree: (max depth + 1) * block size
+ * And the bmap_finish transaction can free the blocks and bmap blocks:
+ *    the agf for each of the ags: 4 * sector size
+ *    the agfl for each of the ags: 4 * sector size
+ *    the super block to reflect the freed blocks: sector size
+ *    worst case split in allocation btrees per extent assuming 4 extents:
+ *             4 exts * 2 trees * (2 * max depth - 1) * block size
+ *    the inode btree: max depth * blocksize
+ *    the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_itruncate_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX((xfs_calc_inode_res(mp, 1) +
+                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1,
+                                     XFS_FSB_TO_B(mp, 1))),
+                   (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
+                                     XFS_FSB_TO_B(mp, 1)) +
+                   xfs_calc_buf_res(5, 0) +
+                   xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                    XFS_FSB_TO_B(mp, 1)) +
+                   xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
+                                    mp->m_in_maxlevels, 0)));
+}
+
+/*
+ * In renaming a files we can modify:
+ *    the four inodes involved: 4 * inode size
+ *    the two directory btrees: 2 * (max depth + v2) * dir block size
+ *    the two directory bmap btrees: 2 * max depth * block size
+ * And the bmap_finish transaction can free dir and bmap blocks (two sets
+ *     of bmap blocks) giving:
+ *    the agf for the ags in which the blocks live: 3 * sector size
+ *    the agfl for the ags in which the blocks live: 3 * sector size
+ *    the superblock for the free block count: sector size
+ *    the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_rename_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX((xfs_calc_inode_res(mp, 4) +
+                    xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
+                                     XFS_FSB_TO_B(mp, 1))),
+                   (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 3),
+                                     XFS_FSB_TO_B(mp, 1))));
+}
+
+/*
+ * For creating a link to an inode:
+ *    the parent directory inode: inode size
+ *    the linked inode: inode size
+ *    the directory btree could split: (max depth + v2) * dir block size
+ *    the directory bmap btree could join or split: (max depth + v2) * blocksize
+ * And the bmap_finish transaction can free some bmap blocks giving:
+ *    the agf for the ag in which the blocks live: sector size
+ *    the agfl for the ag in which the blocks live: sector size
+ *    the superblock for the free block count: sector size
+ *    the allocation btrees: 2 trees * (2 * max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_link_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX((xfs_calc_inode_res(mp, 2) +
+                    xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
+                                     XFS_FSB_TO_B(mp, 1))),
+                   (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                     XFS_FSB_TO_B(mp, 1))));
+}
+
+/*
+ * For removing a directory entry we can modify:
+ *    the parent directory inode: inode size
+ *    the removed inode: inode size
+ *    the directory btree could join: (max depth + v2) * dir block size
+ *    the directory bmap btree could join or split: (max depth + v2) * blocksize
+ * And the bmap_finish transaction can free the dir and bmap blocks giving:
+ *    the agf for the ag in which the blocks live: 2 * sector size
+ *    the agfl for the ag in which the blocks live: 2 * sector size
+ *    the superblock for the free block count: sector size
+ *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_remove_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX((xfs_calc_inode_res(mp, 2) +
+                    xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
+                                     XFS_FSB_TO_B(mp, 1))),
+                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                                     XFS_FSB_TO_B(mp, 1))));
+}
+
+/*
+ * For create, break it in to the two cases that the transaction
+ * covers. We start with the modify case - allocation done by modification
+ * of the state of existing inodes - and the allocation case.
+ */
+
+/*
+ * For create we can modify:
+ *    the parent directory inode: inode size
+ *    the new inode: inode size
+ *    the inode btree entry: block size
+ *    the superblock for the nlink flag: sector size
+ *    the directory btree: (max depth + v2) * dir block size
+ *    the directory inode's bmap btree: (max depth + v2) * block size
+ */
+STATIC uint
+xfs_calc_create_resv_modify(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_inode_res(mp, 2) +
+               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
+               (uint)XFS_FSB_TO_B(mp, 1) +
+               xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * For create we can allocate some inodes giving:
+ *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
+ *    the superblock for the nlink flag: sector size
+ *    the inode blocks allocated: XFS_IALLOC_BLOCKS * blocksize
+ *    the inode btree: max depth * blocksize
+ *    the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_create_resv_alloc(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
+               mp->m_sb.sb_sectsize +
+               xfs_calc_buf_res(XFS_IALLOC_BLOCKS(mp), XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+STATIC uint
+__xfs_calc_create_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX(xfs_calc_create_resv_alloc(mp),
+                   xfs_calc_create_resv_modify(mp));
+}
+
+/*
+ * For icreate we can allocate some inodes giving:
+ *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
+ *    the superblock for the nlink flag: sector size
+ *    the inode btree: max depth * blocksize
+ *    the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_icreate_resv_alloc(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
+               mp->m_sb.sb_sectsize +
+               xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+STATIC uint
+xfs_calc_icreate_reservation(xfs_mount_t *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX(xfs_calc_icreate_resv_alloc(mp),
+                   xfs_calc_create_resv_modify(mp));
+}
+
+STATIC uint
+xfs_calc_create_reservation(
+       struct xfs_mount        *mp)
+{
+       if (xfs_sb_version_hascrc(&mp->m_sb))
+               return xfs_calc_icreate_reservation(mp);
+       return __xfs_calc_create_reservation(mp);
+
+}
+
+/*
+ * Making a new directory is the same as creating a new file.
+ */
+STATIC uint
+xfs_calc_mkdir_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_create_reservation(mp);
+}
+
+
+/*
+ * Making a new symplink is the same as creating a new file, but
+ * with the added blocks for remote symlink data which can be up to 1kB in
+ * length (MAXPATHLEN).
+ */
+STATIC uint
+xfs_calc_symlink_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_create_reservation(mp) +
+              xfs_calc_buf_res(1, MAXPATHLEN);
+}
+
+/*
+ * In freeing an inode we can modify:
+ *    the inode being freed: inode size
+ *    the super block free inode counter: sector size
+ *    the agi hash list and counters: sector size
+ *    the inode btree entry: block size
+ *    the on disk inode before ours in the agi hash list: inode cluster size
+ *    the inode btree: max depth * blocksize
+ *    the allocation btrees: 2 trees * (max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_ifree_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               xfs_calc_inode_res(mp, 1) +
+               xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
+               MAX((__uint16_t)XFS_FSB_TO_B(mp, 1),
+                   XFS_INODE_CLUSTER_SIZE(mp)) +
+               xfs_calc_buf_res(1, 0) +
+               xfs_calc_buf_res(2 + XFS_IALLOC_BLOCKS(mp) +
+                                mp->m_in_maxlevels, 0) +
+               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * When only changing the inode we log the inode and possibly the superblock
+ * We also add a bit of slop for the transaction stuff.
+ */
+STATIC uint
+xfs_calc_ichange_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               xfs_calc_inode_res(mp, 1) +
+               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
+
+}
+
+/*
+ * Growing the data section of the filesystem.
+ *     superblock
+ *     agi and agf
+ *     allocation btrees
+ */
+STATIC uint
+xfs_calc_growdata_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * Growing the rt section of the filesystem.
+ * In the first set of transactions (ALLOC) we allocate space to the
+ * bitmap or summary files.
+ *     superblock: sector size
+ *     agf of the ag from which the extent is allocated: sector size
+ *     bmap btree for bitmap/summary inode: max depth * blocksize
+ *     bitmap/summary inode: inode size
+ *     allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize
+ */
+STATIC uint
+xfs_calc_growrtalloc_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
+                                XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_inode_res(mp, 1) +
+               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * Growing the rt section of the filesystem.
+ * In the second set of transactions (ZERO) we zero the new metadata blocks.
+ *     one bitmap/summary block: blocksize
+ */
+STATIC uint
+xfs_calc_growrtzero_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, mp->m_sb.sb_blocksize);
+}
+
+/*
+ * Growing the rt section of the filesystem.
+ * In the third set of transactions (FREE) we update metadata without
+ * allocating any new blocks.
+ *     superblock: sector size
+ *     bitmap inode: inode size
+ *     summary inode: inode size
+ *     one bitmap block: blocksize
+ *     summary blocks: new summary size
+ */
+STATIC uint
+xfs_calc_growrtfree_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
+               xfs_calc_inode_res(mp, 2) +
+               xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) +
+               xfs_calc_buf_res(1, mp->m_rsumsize);
+}
+
+/*
+ * Logging the inode modification timestamp on a synchronous write.
+ *     inode
+ */
+STATIC uint
+xfs_calc_swrite_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_inode_res(mp, 1);
+}
+
+/*
+ * Logging the inode mode bits when writing a setuid/setgid file
+ *     inode
+ */
+STATIC uint
+xfs_calc_writeid_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_inode_res(mp, 1);
+}
+
+/*
+ * Converting the inode from non-attributed to attributed.
+ *     the inode being converted: inode size
+ *     agf block and superblock (for block allocation)
+ *     the new block (directory sized)
+ *     bmap blocks for the new directory block
+ *     allocation btrees
+ */
+STATIC uint
+xfs_calc_addafork_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               xfs_calc_inode_res(mp, 1) +
+               xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(1, mp->m_dirblksize) +
+               xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1,
+                                XFS_FSB_TO_B(mp, 1)) +
+               xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * Removing the attribute fork of a file
+ *    the inode being truncated: inode size
+ *    the inode's bmap btree: max depth * block size
+ * And the bmap_finish transaction can free the blocks and bmap blocks:
+ *    the agf for each of the ags: 4 * sector size
+ *    the agfl for each of the ags: 4 * sector size
+ *    the super block to reflect the freed blocks: sector size
+ *    worst case split in allocation btrees per extent assuming 4 extents:
+ *             4 exts * 2 trees * (2 * max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_attrinval_reservation(
+       struct xfs_mount        *mp)
+{
+       return MAX((xfs_calc_inode_res(mp, 1) +
+                   xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
+                                    XFS_FSB_TO_B(mp, 1))),
+                  (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
+                   xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
+                                    XFS_FSB_TO_B(mp, 1))));
+}
+
+/*
+ * Setting an attribute at mount time.
+ *     the inode getting the attribute
+ *     the superblock for allocations
+ *     the agfs extents are allocated from
+ *     the attribute btree * max depth
+ *     the inode allocation btree
+ * Since attribute transaction space is dependent on the size of the attribute,
+ * the calculation is done partially at mount time and partially at runtime(see
+ * below).
+ */
+STATIC uint
+xfs_calc_attrsetm_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               xfs_calc_inode_res(mp, 1) +
+               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * Setting an attribute at runtime, transaction space unit per block.
+ *     the superblock for allocations: sector size
+ *     the inode bmap btree could join or split: max depth * block size
+ * Since the runtime attribute transaction space is dependent on the total
+ * blocks needed for the 1st bmap, here we calculate out the space unit for
+ * one block so that the caller could figure out the total space according
+ * to the attibute extent length in blocks by:
+ *     ext * M_RES(mp)->tr_attrsetrt.tr_logres
+ */
+STATIC uint
+xfs_calc_attrsetrt_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
+               xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
+                                XFS_FSB_TO_B(mp, 1));
+}
+
+/*
+ * Removing an attribute.
+ *    the inode: inode size
+ *    the attribute btree could join: max depth * block size
+ *    the inode bmap btree could join or split: max depth * block size
+ * And the bmap_finish transaction can free the attr blocks freed giving:
+ *    the agf for the ag in which the blocks live: 2 * sector size
+ *    the agfl for the ag in which the blocks live: 2 * sector size
+ *    the superblock for the free block count: sector size
+ *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
+ */
+STATIC uint
+xfs_calc_attrrm_reservation(
+       struct xfs_mount        *mp)
+{
+       return XFS_DQUOT_LOGRES(mp) +
+               MAX((xfs_calc_inode_res(mp, 1) +
+                    xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH,
+                                     XFS_FSB_TO_B(mp, 1)) +
+                    (uint)XFS_FSB_TO_B(mp,
+                                       XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) +
+                    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)),
+                   (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
+                    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
+                                     XFS_FSB_TO_B(mp, 1))));
+}
+
+/*
+ * Clearing a bad agino number in an agi hash bucket.
+ */
+STATIC uint
+xfs_calc_clear_agi_bucket_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
+}
+
+/*
+ * Clearing the quotaflags in the superblock.
+ *     the super block for changing quota flags: sector size
+ */
+STATIC uint
+xfs_calc_qm_sbchange_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
+}
+
+/*
+ * Adjusting quota limits.
+ *    the xfs_disk_dquot_t: sizeof(struct xfs_disk_dquot)
+ */
+STATIC uint
+xfs_calc_qm_setqlim_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, sizeof(struct xfs_disk_dquot));
+}
+
+/*
+ * Allocating quota on disk if needed.
+ *     the write transaction log space: M_RES(mp)->tr_write.tr_logres
+ *     the unit of quota allocation: one system block size
+ */
+STATIC uint
+xfs_calc_qm_dqalloc_reservation(
+       struct xfs_mount        *mp)
+{
+       ASSERT(M_RES(mp)->tr_write.tr_logres);
+       return M_RES(mp)->tr_write.tr_logres +
+               xfs_calc_buf_res(1,
+                       XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1);
+}
+
+/*
+ * Turning off quotas.
+ *    the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2
+ *    the superblock for the quota flags: sector size
+ */
+STATIC uint
+xfs_calc_qm_quotaoff_reservation(
+       struct xfs_mount        *mp)
+{
+       return sizeof(struct xfs_qoff_logitem) * 2 +
+               xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
+}
+
+/*
+ * End of turning off quotas.
+ *    the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2
+ */
+STATIC uint
+xfs_calc_qm_quotaoff_end_reservation(
+       struct xfs_mount        *mp)
+{
+       return sizeof(struct xfs_qoff_logitem) * 2;
+}
+
+/*
+ * Syncing the incore super block changes to disk.
+ *     the super block to reflect the changes: sector size
+ */
+STATIC uint
+xfs_calc_sb_reservation(
+       struct xfs_mount        *mp)
+{
+       return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize);
+}
+
+void
+xfs_trans_resv_calc(
+       struct xfs_mount        *mp,
+       struct xfs_trans_resv   *resp)
+{
+       /*
+        * The following transactions are logged in physical format and
+        * require a permanent reservation on space.
+        */
+       resp->tr_write.tr_logres = xfs_calc_write_reservation(mp);
+       resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
+       resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp);
+       resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
+       resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp);
+       resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT;
+       resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_link.tr_logres = xfs_calc_link_reservation(mp);
+       resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT;
+       resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp);
+       resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT;
+       resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp);
+       resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT;
+       resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_create.tr_logres = xfs_calc_create_reservation(mp);
+       resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT;
+       resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp);
+       resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT;
+       resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp);
+       resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT;
+       resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_addafork.tr_logres = xfs_calc_addafork_reservation(mp);
+       resp->tr_addafork.tr_logcount = XFS_ADDAFORK_LOG_COUNT;
+       resp->tr_addafork.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_attrinval.tr_logres = xfs_calc_attrinval_reservation(mp);
+       resp->tr_attrinval.tr_logcount = XFS_ATTRINVAL_LOG_COUNT;
+       resp->tr_attrinval.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_attrsetm.tr_logres = xfs_calc_attrsetm_reservation(mp);
+       resp->tr_attrsetm.tr_logcount = XFS_ATTRSET_LOG_COUNT;
+       resp->tr_attrsetm.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_attrrm.tr_logres = xfs_calc_attrrm_reservation(mp);
+       resp->tr_attrrm.tr_logcount = XFS_ATTRRM_LOG_COUNT;
+       resp->tr_attrrm.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_growrtalloc.tr_logres = xfs_calc_growrtalloc_reservation(mp);
+       resp->tr_growrtalloc.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT;
+       resp->tr_growrtalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       resp->tr_qm_dqalloc.tr_logres = xfs_calc_qm_dqalloc_reservation(mp);
+       resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
+       resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES;
+
+       /*
+        * The following transactions are logged in logical format with
+        * a default log count.
+        */
+       resp->tr_qm_sbchange.tr_logres = xfs_calc_qm_sbchange_reservation(mp);
+       resp->tr_qm_sbchange.tr_logcount = XFS_DEFAULT_LOG_COUNT;
+
+       resp->tr_qm_setqlim.tr_logres = xfs_calc_qm_setqlim_reservation(mp);
+       resp->tr_qm_setqlim.tr_logcount = XFS_DEFAULT_LOG_COUNT;
+
+       resp->tr_qm_quotaoff.tr_logres = xfs_calc_qm_quotaoff_reservation(mp);
+       resp->tr_qm_quotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT;
+
+       resp->tr_qm_equotaoff.tr_logres =
+               xfs_calc_qm_quotaoff_end_reservation(mp);
+       resp->tr_qm_equotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT;
+
+       resp->tr_sb.tr_logres = xfs_calc_sb_reservation(mp);
+       resp->tr_sb.tr_logcount = XFS_DEFAULT_LOG_COUNT;
+
+       /* The following transaction are logged in logical format */
+       resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp);
+       resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp);
+       resp->tr_swrite.tr_logres = xfs_calc_swrite_reservation(mp);
+       resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp);
+       resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp);
+       resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp);
+       resp->tr_clearagi.tr_logres = xfs_calc_clear_agi_bucket_reservation(mp);
+       resp->tr_growrtzero.tr_logres = xfs_calc_growrtzero_reservation(mp);
+       resp->tr_growrtfree.tr_logres = xfs_calc_growrtfree_reservation(mp);
+}
diff --git a/fs/xfs/xfs_trans_resv.h b/fs/xfs/xfs_trans_resv.h
new file mode 100644 (file)
index 0000000..de7de9a
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2000-2002,2005 Silicon Graphics, 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
+ */
+#ifndef        __XFS_TRANS_RESV_H__
+#define        __XFS_TRANS_RESV_H__
+
+struct xfs_mount;
+
+/*
+ * structure for maintaining pre-calculated transaction reservations.
+ */
+struct xfs_trans_res {
+       uint    tr_logres;      /* log space unit in bytes per log ticket */
+       int     tr_logcount;    /* number of log operations per log ticket */
+       int     tr_logflags;    /* log flags, currently only used for indicating
+                                * a reservation request is permanent or not */
+};
+
+struct xfs_trans_resv {
+       struct xfs_trans_res    tr_write;       /* extent alloc trans */
+       struct xfs_trans_res    tr_itruncate;   /* truncate trans */
+       struct xfs_trans_res    tr_rename;      /* rename trans */
+       struct xfs_trans_res    tr_link;        /* link trans */
+       struct xfs_trans_res    tr_remove;      /* unlink trans */
+       struct xfs_trans_res    tr_symlink;     /* symlink trans */
+       struct xfs_trans_res    tr_create;      /* create trans */
+       struct xfs_trans_res    tr_mkdir;       /* mkdir trans */
+       struct xfs_trans_res    tr_ifree;       /* inode free trans */
+       struct xfs_trans_res    tr_ichange;     /* inode update trans */
+       struct xfs_trans_res    tr_growdata;    /* fs data section grow trans */
+       struct xfs_trans_res    tr_swrite;      /* sync write inode trans */
+       struct xfs_trans_res    tr_addafork;    /* add inode attr fork trans */
+       struct xfs_trans_res    tr_writeid;     /* write setuid/setgid file */
+       struct xfs_trans_res    tr_attrinval;   /* attr fork buffer
+                                                * invalidation */
+       struct xfs_trans_res    tr_attrsetm;    /* set/create an attribute at
+                                                * mount time */
+       struct xfs_trans_res    tr_attrsetrt;   /* set/create an attribute at
+                                                * runtime */
+       struct xfs_trans_res    tr_attrrm;      /* remove an attribute */
+       struct xfs_trans_res    tr_clearagi;    /* clear agi unlinked bucket */
+       struct xfs_trans_res    tr_growrtalloc; /* grow realtime allocations */
+       struct xfs_trans_res    tr_growrtzero;  /* grow realtime zeroing */
+       struct xfs_trans_res    tr_growrtfree;  /* grow realtime freeing */
+       struct xfs_trans_res    tr_qm_sbchange; /* change quota flags */
+       struct xfs_trans_res    tr_qm_setqlim;  /* adjust quota limits */
+       struct xfs_trans_res    tr_qm_dqalloc;  /* allocate quota on disk */
+       struct xfs_trans_res    tr_qm_quotaoff; /* turn quota off */
+       struct xfs_trans_res    tr_qm_equotaoff;/* end of turn quota off */
+       struct xfs_trans_res    tr_sb;          /* modify superblock */
+       struct xfs_trans_res    tr_fsyncts;     /* update timestamps on fsync */
+};
+
+/* shorthand way of accessing reservation structure */
+#define M_RES(mp)      (&(mp)->m_resv)
+
+/*
+ * Per-extent log reservation for the allocation btree changes
+ * involved in freeing or allocating an extent.
+ * 2 trees * (2 blocks/level * max depth - 1) * block size
+ */
+#define        XFS_ALLOCFREE_LOG_RES(mp,nx) \
+       ((nx) * (2 * XFS_FSB_TO_B((mp), 2 * XFS_AG_MAXLEVELS(mp) - 1)))
+#define        XFS_ALLOCFREE_LOG_COUNT(mp,nx) \
+       ((nx) * (2 * (2 * XFS_AG_MAXLEVELS(mp) - 1)))
+
+/*
+ * Per-directory log reservation for any directory change.
+ * dir blocks: (1 btree block per level + data block + free block) * dblock size
+ * bmap btree: (levels + 2) * max depth * block size
+ * v2 directory blocks can be fragmented below the dirblksize down to the fsb
+ * size, so account for that in the DAENTER macros.
+ */
+#define        XFS_DIROP_LOG_RES(mp)   \
+       (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \
+        (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1)))
+#define        XFS_DIROP_LOG_COUNT(mp) \
+       (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \
+        XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1)
+
+/*
+ * Various log count values.
+ */
+#define        XFS_DEFAULT_LOG_COUNT           1
+#define        XFS_DEFAULT_PERM_LOG_COUNT      2
+#define        XFS_ITRUNCATE_LOG_COUNT         2
+#define XFS_INACTIVE_LOG_COUNT         2
+#define        XFS_CREATE_LOG_COUNT            2
+#define        XFS_MKDIR_LOG_COUNT             3
+#define        XFS_SYMLINK_LOG_COUNT           3
+#define        XFS_REMOVE_LOG_COUNT            2
+#define        XFS_LINK_LOG_COUNT              2
+#define        XFS_RENAME_LOG_COUNT            2
+#define        XFS_WRITE_LOG_COUNT             2
+#define        XFS_ADDAFORK_LOG_COUNT          2
+#define        XFS_ATTRINVAL_LOG_COUNT         1
+#define        XFS_ATTRSET_LOG_COUNT           3
+#define        XFS_ATTRRM_LOG_COUNT            3
+
+void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp);
+
+#endif /* __XFS_TRANS_RESV_H__ */
index 61ba1cfa974c7e3e32c493c1317236e2cb397730..82bbc34d54a3b344559379a665365bb2bab9b903 100644 (file)
 #ifndef __XFS_TYPES_H__
 #define        __XFS_TYPES_H__
 
-#ifdef __KERNEL__
-
-/*
- * Additional type declarations for XFS
- */
-typedef signed char            __int8_t;
-typedef unsigned char          __uint8_t;
-typedef signed short int       __int16_t;
-typedef unsigned short int     __uint16_t;
-typedef signed int             __int32_t;
-typedef unsigned int           __uint32_t;
-typedef signed long long int   __int64_t;
-typedef unsigned long long int __uint64_t;
-
-typedef __uint32_t             prid_t;         /* project ID */
-typedef __uint32_t             inst_t;         /* an instruction */
-
-typedef __s64                  xfs_off_t;      /* <file offset> type */
-typedef unsigned long long     xfs_ino_t;      /* <inode> type */
-typedef __s64                  xfs_daddr_t;    /* <disk address> type */
-typedef char *                 xfs_caddr_t;    /* <core address> type */
-typedef __u32                  xfs_dev_t;
-typedef __u32                  xfs_nlink_t;
-
-/* __psint_t is the same size as a pointer */
-#if (BITS_PER_LONG == 32)
-typedef __int32_t __psint_t;
-typedef __uint32_t __psunsigned_t;
-#elif (BITS_PER_LONG == 64)
-typedef __int64_t __psint_t;
-typedef __uint64_t __psunsigned_t;
-#else
-#error BITS_PER_LONG must be 32 or 64
-#endif
-
-#endif /* __KERNEL__ */
+typedef __uint32_t     prid_t;         /* project ID */
 
 typedef __uint32_t     xfs_agblock_t;  /* blockno in alloc. group */
 typedef        __uint32_t      xfs_agino_t;    /* inode # within allocation grp */
@@ -145,6 +110,12 @@ typedef __uint64_t xfs_filblks_t;  /* number of blocks in a file */
 #define XFS_MIN_SECTORSIZE     (1 << XFS_MIN_SECTORSIZE_LOG)
 #define XFS_MAX_SECTORSIZE     (1 << XFS_MAX_SECTORSIZE_LOG)
 
+/*
+ * Inode fork identifiers.
+ */
+#define        XFS_DATA_FORK   0
+#define        XFS_ATTR_FORK   1
+
 /*
  * Min numbers of data/attr fork btree root pointers.
  */
@@ -169,6 +140,23 @@ typedef enum {
 struct xfs_name {
        const unsigned char     *name;
        int                     len;
+       int                     type;
 };
 
+/*
+ * uid_t and gid_t are hard-coded to 32 bits in the inode.
+ * Hence, an 'id' in a dquot is 32 bits..
+ */
+typedef __uint32_t     xfs_dqid_t;
+
+/*
+ * Constants for bit manipulations.
+ */
+#define        XFS_NBBYLOG     3               /* log2(NBBY) */
+#define        XFS_WORDLOG     2               /* log2(sizeof(xfs_rtword_t)) */
+#define        XFS_NBWORDLOG   (XFS_NBBYLOG + XFS_WORDLOG)
+#define        XFS_NBWORD      (1 << XFS_NBWORDLOG)
+#define        XFS_WORDMASK    ((1 << XFS_WORDLOG) - 1)
+
+
 #endif /* __XFS_TYPES_H__ */
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
deleted file mode 100644 (file)
index 0025c78..0000000
+++ /dev/null
@@ -1,314 +0,0 @@
-/*
- * Copyright (c) 2000-2002,2005 Silicon Graphics, 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_log.h"
-#include "xfs_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_mount.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_bmap.h"
-#include "xfs_error.h"
-#include "xfs_quota.h"
-#include "xfs_itable.h"
-#include "xfs_utils.h"
-
-
-/*
- * Allocates a new inode from disk and return a pointer to the
- * incore copy. This routine will internally commit the current
- * transaction and allocate a new one if the Space Manager needed
- * to do an allocation to replenish the inode free-list.
- *
- * This routine is designed to be called from xfs_create and
- * xfs_create_dir.
- *
- */
-int
-xfs_dir_ialloc(
-       xfs_trans_t     **tpp,          /* input: current transaction;
-                                          output: may be a new transaction. */
-       xfs_inode_t     *dp,            /* directory within whose allocate
-                                          the inode. */
-       umode_t         mode,
-       xfs_nlink_t     nlink,
-       xfs_dev_t       rdev,
-       prid_t          prid,           /* project id */
-       int             okalloc,        /* ok to allocate new space */
-       xfs_inode_t     **ipp,          /* pointer to inode; it will be
-                                          locked. */
-       int             *committed)
-
-{
-       xfs_trans_t     *tp;
-       xfs_trans_t     *ntp;
-       xfs_inode_t     *ip;
-       xfs_buf_t       *ialloc_context = NULL;
-       int             code;
-       uint            log_res;
-       uint            log_count;
-       void            *dqinfo;
-       uint            tflags;
-
-       tp = *tpp;
-       ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
-
-       /*
-        * xfs_ialloc will return a pointer to an incore inode if
-        * the Space Manager has an available inode on the free
-        * list. Otherwise, it will do an allocation and replenish
-        * the freelist.  Since we can only do one allocation per
-        * transaction without deadlocks, we will need to commit the
-        * current transaction and start a new one.  We will then
-        * need to call xfs_ialloc again to get the inode.
-        *
-        * If xfs_ialloc did an allocation to replenish the freelist,
-        * it returns the bp containing the head of the freelist as
-        * ialloc_context. We will hold a lock on it across the
-        * transaction commit so that no other process can steal
-        * the inode(s) that we've just allocated.
-        */
-       code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc,
-                         &ialloc_context, &ip);
-
-       /*
-        * Return an error if we were unable to allocate a new inode.
-        * This should only happen if we run out of space on disk or
-        * encounter a disk error.
-        */
-       if (code) {
-               *ipp = NULL;
-               return code;
-       }
-       if (!ialloc_context && !ip) {
-               *ipp = NULL;
-               return XFS_ERROR(ENOSPC);
-       }
-
-       /*
-        * If the AGI buffer is non-NULL, then we were unable to get an
-        * inode in one operation.  We need to commit the current
-        * transaction and call xfs_ialloc() again.  It is guaranteed
-        * to succeed the second time.
-        */
-       if (ialloc_context) {
-               /*
-                * Normally, xfs_trans_commit releases all the locks.
-                * We call bhold to hang on to the ialloc_context across
-                * the commit.  Holding this buffer prevents any other
-                * processes from doing any allocations in this
-                * allocation group.
-                */
-               xfs_trans_bhold(tp, ialloc_context);
-               /*
-                * Save the log reservation so we can use
-                * them in the next transaction.
-                */
-               log_res = xfs_trans_get_log_res(tp);
-               log_count = xfs_trans_get_log_count(tp);
-
-               /*
-                * We want the quota changes to be associated with the next
-                * transaction, NOT this one. So, detach the dqinfo from this
-                * and attach it to the next transaction.
-                */
-               dqinfo = NULL;
-               tflags = 0;
-               if (tp->t_dqinfo) {
-                       dqinfo = (void *)tp->t_dqinfo;
-                       tp->t_dqinfo = NULL;
-                       tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY;
-                       tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY);
-               }
-
-               ntp = xfs_trans_dup(tp);
-               code = xfs_trans_commit(tp, 0);
-               tp = ntp;
-               if (committed != NULL) {
-                       *committed = 1;
-               }
-               /*
-                * If we get an error during the commit processing,
-                * release the buffer that is still held and return
-                * to the caller.
-                */
-               if (code) {
-                       xfs_buf_relse(ialloc_context);
-                       if (dqinfo) {
-                               tp->t_dqinfo = dqinfo;
-                               xfs_trans_free_dqinfo(tp);
-                       }
-                       *tpp = ntp;
-                       *ipp = NULL;
-                       return code;
-               }
-
-               /*
-                * transaction commit worked ok so we can drop the extra ticket
-                * reference that we gained in xfs_trans_dup()
-                */
-               xfs_log_ticket_put(tp->t_ticket);
-               code = xfs_trans_reserve(tp, 0, log_res, 0,
-                                        XFS_TRANS_PERM_LOG_RES, log_count);
-               /*
-                * Re-attach the quota info that we detached from prev trx.
-                */
-               if (dqinfo) {
-                       tp->t_dqinfo = dqinfo;
-                       tp->t_flags |= tflags;
-               }
-
-               if (code) {
-                       xfs_buf_relse(ialloc_context);
-                       *tpp = ntp;
-                       *ipp = NULL;
-                       return code;
-               }
-               xfs_trans_bjoin(tp, ialloc_context);
-
-               /*
-                * Call ialloc again. Since we've locked out all
-                * other allocations in this allocation group,
-                * this call should always succeed.
-                */
-               code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
-                                 okalloc, &ialloc_context, &ip);
-
-               /*
-                * If we get an error at this point, return to the caller
-                * so that the current transaction can be aborted.
-                */
-               if (code) {
-                       *tpp = tp;
-                       *ipp = NULL;
-                       return code;
-               }
-               ASSERT(!ialloc_context && ip);
-
-       } else {
-               if (committed != NULL)
-                       *committed = 0;
-       }
-
-       *ipp = ip;
-       *tpp = tp;
-
-       return 0;
-}
-
-/*
- * Decrement the link count on an inode & log the change.
- * If this causes the link count to go to zero, initiate the
- * logging activity required to truncate a file.
- */
-int                            /* error */
-xfs_droplink(
-       xfs_trans_t *tp,
-       xfs_inode_t *ip)
-{
-       int     error;
-
-       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
-
-       ASSERT (ip->i_d.di_nlink > 0);
-       ip->i_d.di_nlink--;
-       drop_nlink(VFS_I(ip));
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-
-       error = 0;
-       if (ip->i_d.di_nlink == 0) {
-               /*
-                * We're dropping the last link to this file.
-                * Move the on-disk inode to the AGI unlinked list.
-                * From xfs_inactive() we will pull the inode from
-                * the list and free it.
-                */
-               error = xfs_iunlink(tp, ip);
-       }
-       return error;
-}
-
-/*
- * This gets called when the inode's version needs to be changed from 1 to 2.
- * Currently this happens when the nlink field overflows the old 16-bit value
- * or when chproj is called to change the project for the first time.
- * As a side effect the superblock version will also get rev'd
- * to contain the NLINK bit.
- */
-void
-xfs_bump_ino_vers2(
-       xfs_trans_t     *tp,
-       xfs_inode_t     *ip)
-{
-       xfs_mount_t     *mp;
-
-       ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
-       ASSERT(ip->i_d.di_version == 1);
-
-       ip->i_d.di_version = 2;
-       ip->i_d.di_onlink = 0;
-       memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
-       mp = tp->t_mountp;
-       if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
-               spin_lock(&mp->m_sb_lock);
-               if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
-                       xfs_sb_version_addnlink(&mp->m_sb);
-                       spin_unlock(&mp->m_sb_lock);
-                       xfs_mod_sb(tp, XFS_SB_VERSIONNUM);
-               } else {
-                       spin_unlock(&mp->m_sb_lock);
-               }
-       }
-       /* Caller must log the inode */
-}
-
-/*
- * Increment the link count on an inode & log the change.
- */
-int
-xfs_bumplink(
-       xfs_trans_t *tp,
-       xfs_inode_t *ip)
-{
-       xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
-
-       ASSERT(ip->i_d.di_nlink > 0);
-       ip->i_d.di_nlink++;
-       inc_nlink(VFS_I(ip));
-       if ((ip->i_d.di_version == 1) &&
-           (ip->i_d.di_nlink > XFS_MAXLINK_1)) {
-               /*
-                * The inode has increased its number of links beyond
-                * what can fit in an old format inode.  It now needs
-                * to be converted to a version 2 inode with a 32 bit
-                * link count.  If this is the first inode in the file
-                * system to do this, then we need to bump the superblock
-                * version number as well.
-                */
-               xfs_bump_ino_vers2(tp, ip);
-       }
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       return 0;
-}
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h
deleted file mode 100644 (file)
index 5eeab46..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2000-2002,2005 Silicon Graphics, 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
- */
-#ifndef __XFS_UTILS_H__
-#define __XFS_UTILS_H__
-
-extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, umode_t, xfs_nlink_t,
-                               xfs_dev_t, prid_t, int, xfs_inode_t **, int *);
-extern int xfs_droplink(xfs_trans_t *, xfs_inode_t *);
-extern int xfs_bumplink(xfs_trans_t *, xfs_inode_t *);
-extern void xfs_bump_ino_vers2(xfs_trans_t *, xfs_inode_t *);
-
-#endif /* __XFS_UTILS_H__ */
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
deleted file mode 100644 (file)
index dc730ac..0000000
+++ /dev/null
@@ -1,1870 +0,0 @@
-/*
- * Copyright (c) 2000-2006 Silicon Graphics, Inc.
- * Copyright (c) 2012 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_trans.h"
-#include "xfs_sb.h"
-#include "xfs_ag.h"
-#include "xfs_dir2.h"
-#include "xfs_mount.h"
-#include "xfs_da_btree.h"
-#include "xfs_bmap_btree.h"
-#include "xfs_ialloc_btree.h"
-#include "xfs_dinode.h"
-#include "xfs_inode.h"
-#include "xfs_inode_item.h"
-#include "xfs_itable.h"
-#include "xfs_ialloc.h"
-#include "xfs_alloc.h"
-#include "xfs_bmap.h"
-#include "xfs_acl.h"
-#include "xfs_attr.h"
-#include "xfs_error.h"
-#include "xfs_quota.h"
-#include "xfs_utils.h"
-#include "xfs_rtalloc.h"
-#include "xfs_trans_space.h"
-#include "xfs_log_priv.h"
-#include "xfs_filestream.h"
-#include "xfs_vnodeops.h"
-#include "xfs_trace.h"
-#include "xfs_icache.h"
-#include "xfs_symlink.h"
-
-
-/*
- * This is called by xfs_inactive to free any blocks beyond eof
- * when the link count isn't zero and by xfs_dm_punch_hole() when
- * punching a hole to EOF.
- */
-int
-xfs_free_eofblocks(
-       xfs_mount_t     *mp,
-       xfs_inode_t     *ip,
-       bool            need_iolock)
-{
-       xfs_trans_t     *tp;
-       int             error;
-       xfs_fileoff_t   end_fsb;
-       xfs_fileoff_t   last_fsb;
-       xfs_filblks_t   map_len;
-       int             nimaps;
-       xfs_bmbt_irec_t imap;
-
-       /*
-        * Figure out if there are any blocks beyond the end
-        * of the file.  If not, then there is nothing to do.
-        */
-       end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip));
-       last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes);
-       if (last_fsb <= end_fsb)
-               return 0;
-       map_len = last_fsb - end_fsb;
-
-       nimaps = 1;
-       xfs_ilock(ip, XFS_ILOCK_SHARED);
-       error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
-       xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
-       if (!error && (nimaps != 0) &&
-           (imap.br_startblock != HOLESTARTBLOCK ||
-            ip->i_delayed_blks)) {
-               /*
-                * Attach the dquots to the inode up front.
-                */
-               error = xfs_qm_dqattach(ip, 0);
-               if (error)
-                       return error;
-
-               /*
-                * There are blocks after the end of file.
-                * Free them up now by truncating the file to
-                * its current size.
-                */
-               tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-
-               if (need_iolock) {
-                       if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
-                               xfs_trans_cancel(tp, 0);
-                               return EAGAIN;
-                       }
-               }
-
-               error = xfs_trans_reserve(tp, 0,
-                                         XFS_ITRUNCATE_LOG_RES(mp),
-                                         0, XFS_TRANS_PERM_LOG_RES,
-                                         XFS_ITRUNCATE_LOG_COUNT);
-               if (error) {
-                       ASSERT(XFS_FORCED_SHUTDOWN(mp));
-                       xfs_trans_cancel(tp, 0);
-                       if (need_iolock)
-                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                       return error;
-               }
-
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, 0);
-
-               /*
-                * Do not update the on-disk file size.  If we update the
-                * on-disk file size and then the system crashes before the
-                * contents of the file are flushed to disk then the files
-                * may be full of holes (ie NULL files bug).
-                */
-               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK,
-                                             XFS_ISIZE(ip));
-               if (error) {
-                       /*
-                        * If we get an error at this point we simply don't
-                        * bother truncating the file.
-                        */
-                       xfs_trans_cancel(tp,
-                                        (XFS_TRANS_RELEASE_LOG_RES |
-                                         XFS_TRANS_ABORT));
-               } else {
-                       error = xfs_trans_commit(tp,
-                                               XFS_TRANS_RELEASE_LOG_RES);
-                       if (!error)
-                               xfs_inode_clear_eofblocks_tag(ip);
-               }
-
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               if (need_iolock)
-                       xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-       }
-       return error;
-}
-
-int
-xfs_release(
-       xfs_inode_t     *ip)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       int             error;
-
-       if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0))
-               return 0;
-
-       /* If this is a read-only mount, don't do this (would generate I/O) */
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               return 0;
-
-       if (!XFS_FORCED_SHUTDOWN(mp)) {
-               int truncated;
-
-               /*
-                * If we are using filestreams, and we have an unlinked
-                * file that we are processing the last close on, then nothing
-                * will be able to reopen and write to this file. Purge this
-                * inode from the filestreams cache so that it doesn't delay
-                * teardown of the inode.
-                */
-               if ((ip->i_d.di_nlink == 0) && xfs_inode_is_filestream(ip))
-                       xfs_filestream_deassociate(ip);
-
-               /*
-                * If we previously truncated this file and removed old data
-                * in the process, we want to initiate "early" writeout on
-                * the last close.  This is an attempt to combat the notorious
-                * NULL files problem which is particularly noticeable from a
-                * truncate down, buffered (re-)write (delalloc), followed by
-                * a crash.  What we are effectively doing here is
-                * significantly reducing the time window where we'd otherwise
-                * be exposed to that problem.
-                */
-               truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
-               if (truncated) {
-                       xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
-                       if (VN_DIRTY(VFS_I(ip)) && ip->i_delayed_blks > 0) {
-                               error = -filemap_flush(VFS_I(ip)->i_mapping);
-                               if (error)
-                                       return error;
-                       }
-               }
-       }
-
-       if (ip->i_d.di_nlink == 0)
-               return 0;
-
-       if (xfs_can_free_eofblocks(ip, false)) {
-
-               /*
-                * If we can't get the iolock just skip truncating the blocks
-                * past EOF because we could deadlock with the mmap_sem
-                * otherwise.  We'll get another chance to drop them once the
-                * last reference to the inode is dropped, so we'll never leak
-                * blocks permanently.
-                *
-                * Further, check if the inode is being opened, written and
-                * closed frequently and we have delayed allocation blocks
-                * outstanding (e.g. streaming writes from the NFS server),
-                * truncating the blocks past EOF will cause fragmentation to
-                * occur.
-                *
-                * In this case don't do the truncation, either, but we have to
-                * be careful how we detect this case. Blocks beyond EOF show
-                * up as i_delayed_blks even when the inode is clean, so we
-                * need to truncate them away first before checking for a dirty
-                * release. Hence on the first dirty close we will still remove
-                * the speculative allocation, but after that we will leave it
-                * in place.
-                */
-               if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
-                       return 0;
-
-               error = xfs_free_eofblocks(mp, ip, true);
-               if (error && error != EAGAIN)
-                       return error;
-
-               /* delalloc blocks after truncation means it really is dirty */
-               if (ip->i_delayed_blks)
-                       xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
-       }
-       return 0;
-}
-
-/*
- * xfs_inactive
- *
- * This is called when the vnode reference count for the vnode
- * goes to zero.  If the file has been unlinked, then it must
- * now be truncated.  Also, we clear all of the read-ahead state
- * kept for the inode here since the file is now closed.
- */
-int
-xfs_inactive(
-       xfs_inode_t     *ip)
-{
-       xfs_bmap_free_t free_list;
-       xfs_fsblock_t   first_block;
-       int             committed;
-       xfs_trans_t     *tp;
-       xfs_mount_t     *mp;
-       int             error;
-       int             truncate = 0;
-
-       /*
-        * If the inode is already free, then there can be nothing
-        * to clean up here.
-        */
-       if (ip->i_d.di_mode == 0 || is_bad_inode(VFS_I(ip))) {
-               ASSERT(ip->i_df.if_real_bytes == 0);
-               ASSERT(ip->i_df.if_broot_bytes == 0);
-               return VN_INACTIVE_CACHE;
-       }
-
-       mp = ip->i_mount;
-
-       error = 0;
-
-       /* If this is a read-only mount, don't do this (would generate I/O) */
-       if (mp->m_flags & XFS_MOUNT_RDONLY)
-               goto out;
-
-       if (ip->i_d.di_nlink != 0) {
-               /*
-                * force is true because we are evicting an inode from the
-                * cache. Post-eof blocks must be freed, lest we end up with
-                * broken free space accounting.
-                */
-               if (xfs_can_free_eofblocks(ip, true)) {
-                       error = xfs_free_eofblocks(mp, ip, false);
-                       if (error)
-                               return VN_INACTIVE_CACHE;
-               }
-               goto out;
-       }
-
-       if (S_ISREG(ip->i_d.di_mode) &&
-           (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 ||
-            ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0))
-               truncate = 1;
-
-       error = xfs_qm_dqattach(ip, 0);
-       if (error)
-               return VN_INACTIVE_CACHE;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-       error = xfs_trans_reserve(tp, 0,
-                       (truncate || S_ISLNK(ip->i_d.di_mode)) ?
-                               XFS_ITRUNCATE_LOG_RES(mp) :
-                               XFS_IFREE_LOG_RES(mp),
-                       0,
-                       XFS_TRANS_PERM_LOG_RES,
-                       XFS_ITRUNCATE_LOG_COUNT);
-       if (error) {
-               ASSERT(XFS_FORCED_SHUTDOWN(mp));
-               xfs_trans_cancel(tp, 0);
-               return VN_INACTIVE_CACHE;
-       }
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, 0);
-
-       if (S_ISLNK(ip->i_d.di_mode)) {
-               error = xfs_inactive_symlink(ip, &tp);
-               if (error)
-                       goto out_cancel;
-       } else if (truncate) {
-               ip->i_d.di_size = 0;
-               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-
-               error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
-               if (error)
-                       goto out_cancel;
-
-               ASSERT(ip->i_d.di_nextents == 0);
-       }
-
-       /*
-        * If there are attributes associated with the file then blow them away
-        * now.  The code calls a routine that recursively deconstructs the
-        * attribute fork.  We need to just commit the current transaction
-        * because we can't use it for xfs_attr_inactive().
-        */
-       if (ip->i_d.di_anextents > 0) {
-               ASSERT(ip->i_d.di_forkoff != 0);
-
-               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-               if (error)
-                       goto out_unlock;
-
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-               error = xfs_attr_inactive(ip);
-               if (error)
-                       goto out;
-
-               tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
-               error = xfs_trans_reserve(tp, 0,
-                                         XFS_IFREE_LOG_RES(mp),
-                                         0, XFS_TRANS_PERM_LOG_RES,
-                                         XFS_INACTIVE_LOG_COUNT);
-               if (error) {
-                       xfs_trans_cancel(tp, 0);
-                       goto out;
-               }
-
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_trans_ijoin(tp, ip, 0);
-       }
-
-       if (ip->i_afp)
-               xfs_idestroy_fork(ip, XFS_ATTR_FORK);
-
-       ASSERT(ip->i_d.di_anextents == 0);
-
-       /*
-        * Free the inode.
-        */
-       xfs_bmap_init(&free_list, &first_block);
-       error = xfs_ifree(tp, ip, &free_list);
-       if (error) {
-               /*
-                * If we fail to free the inode, shut down.  The cancel
-                * might do that, we need to make sure.  Otherwise the
-                * inode might be lost for a long time or forever.
-                */
-               if (!XFS_FORCED_SHUTDOWN(mp)) {
-                       xfs_notice(mp, "%s: xfs_ifree returned error %d",
-                               __func__, error);
-                       xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR);
-               }
-               xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
-       } else {
-               /*
-                * Credit the quota account(s). The inode is gone.
-                */
-               xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1);
-
-               /*
-                * Just ignore errors at this point.  There is nothing we can
-                * do except to try to keep going. Make sure it's not a silent
-                * error.
-                */
-               error = xfs_bmap_finish(&tp,  &free_list, &committed);
-               if (error)
-                       xfs_notice(mp, "%s: xfs_bmap_finish returned error %d",
-                               __func__, error);
-               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-               if (error)
-                       xfs_notice(mp, "%s: xfs_trans_commit returned error %d",
-                               __func__, error);
-       }
-
-       /*
-        * Release the dquots held by inode, if any.
-        */
-       xfs_qm_dqdetach(ip);
-out_unlock:
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-out:
-       return VN_INACTIVE_CACHE;
-out_cancel:
-       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-       goto out_unlock;
-}
-
-/*
- * Lookups up an inode from "name". If ci_name is not NULL, then a CI match
- * is allowed, otherwise it has to be an exact match. If a CI match is found,
- * ci_name->name will point to a the actual name (caller must free) or
- * will be set to NULL if an exact match is found.
- */
-int
-xfs_lookup(
-       xfs_inode_t             *dp,
-       struct xfs_name         *name,
-       xfs_inode_t             **ipp,
-       struct xfs_name         *ci_name)
-{
-       xfs_ino_t               inum;
-       int                     error;
-       uint                    lock_mode;
-
-       trace_xfs_lookup(dp, name);
-
-       if (XFS_FORCED_SHUTDOWN(dp->i_mount))
-               return XFS_ERROR(EIO);
-
-       lock_mode = xfs_ilock_map_shared(dp);
-       error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name);
-       xfs_iunlock_map_shared(dp, lock_mode);
-
-       if (error)
-               goto out;
-
-       error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp);
-       if (error)
-               goto out_free_name;
-
-       return 0;
-
-out_free_name:
-       if (ci_name)
-               kmem_free(ci_name->name);
-out:
-       *ipp = NULL;
-       return error;
-}
-
-int
-xfs_create(
-       xfs_inode_t             *dp,
-       struct xfs_name         *name,
-       umode_t                 mode,
-       xfs_dev_t               rdev,
-       xfs_inode_t             **ipp)
-{
-       int                     is_dir = S_ISDIR(mode);
-       struct xfs_mount        *mp = dp->i_mount;
-       struct xfs_inode        *ip = NULL;
-       struct xfs_trans        *tp = NULL;
-       int                     error;
-       xfs_bmap_free_t         free_list;
-       xfs_fsblock_t           first_block;
-       bool                    unlock_dp_on_error = false;
-       uint                    cancel_flags;
-       int                     committed;
-       prid_t                  prid;
-       struct xfs_dquot        *udqp = NULL;
-       struct xfs_dquot        *gdqp = NULL;
-       struct xfs_dquot        *pdqp = NULL;
-       uint                    resblks;
-       uint                    log_res;
-       uint                    log_count;
-
-       trace_xfs_create(dp, name);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)
-               prid = xfs_get_projid(dp);
-       else
-               prid = XFS_PROJID_DEFAULT;
-
-       /*
-        * Make sure that we have allocated dquot(s) on disk.
-        */
-       error = xfs_qm_vop_dqalloc(dp, current_fsuid(), current_fsgid(), prid,
-                                       XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT,
-                                       &udqp, &gdqp, &pdqp);
-       if (error)
-               return error;
-
-       if (is_dir) {
-               rdev = 0;
-               resblks = XFS_MKDIR_SPACE_RES(mp, name->len);
-               log_res = XFS_MKDIR_LOG_RES(mp);
-               log_count = XFS_MKDIR_LOG_COUNT;
-               tp = xfs_trans_alloc(mp, XFS_TRANS_MKDIR);
-       } else {
-               resblks = XFS_CREATE_SPACE_RES(mp, name->len);
-               log_res = XFS_CREATE_LOG_RES(mp);
-               log_count = XFS_CREATE_LOG_COUNT;
-               tp = xfs_trans_alloc(mp, XFS_TRANS_CREATE);
-       }
-
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-
-       /*
-        * Initially assume that the file does not exist and
-        * reserve the resources for that case.  If that is not
-        * the case we'll drop the one we have and get a more
-        * appropriate transaction later.
-        */
-       error = xfs_trans_reserve(tp, resblks, log_res, 0,
-                       XFS_TRANS_PERM_LOG_RES, log_count);
-       if (error == ENOSPC) {
-               /* flush outstanding delalloc blocks and retry */
-               xfs_flush_inodes(mp);
-               error = xfs_trans_reserve(tp, resblks, log_res, 0,
-                               XFS_TRANS_PERM_LOG_RES, log_count);
-       }
-       if (error == ENOSPC) {
-               /* No space at all so try a "no-allocation" reservation */
-               resblks = 0;
-               error = xfs_trans_reserve(tp, 0, log_res, 0,
-                               XFS_TRANS_PERM_LOG_RES, log_count);
-       }
-       if (error) {
-               cancel_flags = 0;
-               goto out_trans_cancel;
-       }
-
-       xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
-       unlock_dp_on_error = true;
-
-       xfs_bmap_init(&free_list, &first_block);
-
-       /*
-        * Reserve disk quota and the inode.
-        */
-       error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp,
-                                               pdqp, resblks, 1, 0);
-       if (error)
-               goto out_trans_cancel;
-
-       error = xfs_dir_canenter(tp, dp, name, resblks);
-       if (error)
-               goto out_trans_cancel;
-
-       /*
-        * A newly created regular or special file just has one directory
-        * entry pointing to them, but a directory also the "." entry
-        * pointing to itself.
-        */
-       error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev,
-                              prid, resblks > 0, &ip, &committed);
-       if (error) {
-               if (error == ENOSPC)
-                       goto out_trans_cancel;
-               goto out_trans_abort;
-       }
-
-       /*
-        * Now we join the directory inode to the transaction.  We do not do it
-        * earlier because xfs_dir_ialloc might commit the previous transaction
-        * (and release all the locks).  An error from here on will result in
-        * the transaction cancel unlocking dp so don't do it explicitly in the
-        * error path.
-        */
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-       unlock_dp_on_error = false;
-
-       error = xfs_dir_createname(tp, dp, name, ip->i_ino,
-                                       &first_block, &free_list, resblks ?
-                                       resblks - XFS_IALLOC_SPACE_RES(mp) : 0);
-       if (error) {
-               ASSERT(error != ENOSPC);
-               goto out_trans_abort;
-       }
-       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-
-       if (is_dir) {
-               error = xfs_dir_init(tp, ip, dp);
-               if (error)
-                       goto out_bmap_cancel;
-
-               error = xfs_bumplink(tp, dp);
-               if (error)
-                       goto out_bmap_cancel;
-       }
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * create transaction goes to disk before returning to
-        * the user.
-        */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
-               xfs_trans_set_sync(tp);
-
-       /*
-        * Attach the dquot(s) to the inodes and modify them incore.
-        * These ids of the inode couldn't have changed since the new
-        * inode has been locked ever since it was created.
-        */
-       xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp);
-
-       error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error)
-               goto out_bmap_cancel;
-
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error)
-               goto out_release_inode;
-
-       xfs_qm_dqrele(udqp);
-       xfs_qm_dqrele(gdqp);
-       xfs_qm_dqrele(pdqp);
-
-       *ipp = ip;
-       return 0;
-
- out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
- out_trans_abort:
-       cancel_flags |= XFS_TRANS_ABORT;
- out_trans_cancel:
-       xfs_trans_cancel(tp, cancel_flags);
- out_release_inode:
-       /*
-        * Wait until after the current transaction is aborted to
-        * release the inode.  This prevents recursive transactions
-        * and deadlocks from xfs_inactive.
-        */
-       if (ip)
-               IRELE(ip);
-
-       xfs_qm_dqrele(udqp);
-       xfs_qm_dqrele(gdqp);
-       xfs_qm_dqrele(pdqp);
-
-       if (unlock_dp_on_error)
-               xfs_iunlock(dp, XFS_ILOCK_EXCL);
-       return error;
-}
-
-#ifdef DEBUG
-int xfs_locked_n;
-int xfs_small_retries;
-int xfs_middle_retries;
-int xfs_lots_retries;
-int xfs_lock_delays;
-#endif
-
-/*
- * Bump the subclass so xfs_lock_inodes() acquires each lock with
- * a different value
- */
-static inline int
-xfs_lock_inumorder(int lock_mode, int subclass)
-{
-       if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
-               lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_IOLOCK_SHIFT;
-       if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))
-               lock_mode |= (subclass + XFS_LOCK_INUMORDER) << XFS_ILOCK_SHIFT;
-
-       return lock_mode;
-}
-
-/*
- * The following routine will lock n inodes in exclusive mode.
- * We assume the caller calls us with the inodes in i_ino order.
- *
- * We need to detect deadlock where an inode that we lock
- * is in the AIL and we start waiting for another inode that is locked
- * by a thread in a long running transaction (such as truncate). This can
- * result in deadlock since the long running trans might need to wait
- * for the inode we just locked in order to push the tail and free space
- * in the log.
- */
-void
-xfs_lock_inodes(
-       xfs_inode_t     **ips,
-       int             inodes,
-       uint            lock_mode)
-{
-       int             attempts = 0, i, j, try_lock;
-       xfs_log_item_t  *lp;
-
-       ASSERT(ips && (inodes >= 2)); /* we need at least two */
-
-       try_lock = 0;
-       i = 0;
-
-again:
-       for (; i < inodes; i++) {
-               ASSERT(ips[i]);
-
-               if (i && (ips[i] == ips[i-1]))  /* Already locked */
-                       continue;
-
-               /*
-                * If try_lock is not set yet, make sure all locked inodes
-                * are not in the AIL.
-                * If any are, set try_lock to be used later.
-                */
-
-               if (!try_lock) {
-                       for (j = (i - 1); j >= 0 && !try_lock; j--) {
-                               lp = (xfs_log_item_t *)ips[j]->i_itemp;
-                               if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
-                                       try_lock++;
-                               }
-                       }
-               }
-
-               /*
-                * If any of the previous locks we have locked is in the AIL,
-                * we must TRY to get the second and subsequent locks. If
-                * we can't get any, we must release all we have
-                * and try again.
-                */
-
-               if (try_lock) {
-                       /* try_lock must be 0 if i is 0. */
-                       /*
-                        * try_lock means we have an inode locked
-                        * that is in the AIL.
-                        */
-                       ASSERT(i != 0);
-                       if (!xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) {
-                               attempts++;
-
-                               /*
-                                * Unlock all previous guys and try again.
-                                * xfs_iunlock will try to push the tail
-                                * if the inode is in the AIL.
-                                */
-
-                               for(j = i - 1; j >= 0; j--) {
-
-                                       /*
-                                        * Check to see if we've already
-                                        * unlocked this one.
-                                        * Not the first one going back,
-                                        * and the inode ptr is the same.
-                                        */
-                                       if ((j != (i - 1)) && ips[j] ==
-                                                               ips[j+1])
-                                               continue;
-
-                                       xfs_iunlock(ips[j], lock_mode);
-                               }
-
-                               if ((attempts % 5) == 0) {
-                                       delay(1); /* Don't just spin the CPU */
-#ifdef DEBUG
-                                       xfs_lock_delays++;
-#endif
-                               }
-                               i = 0;
-                               try_lock = 0;
-                               goto again;
-                       }
-               } else {
-                       xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i));
-               }
-       }
-
-#ifdef DEBUG
-       if (attempts) {
-               if (attempts < 5) xfs_small_retries++;
-               else if (attempts < 100) xfs_middle_retries++;
-               else xfs_lots_retries++;
-       } else {
-               xfs_locked_n++;
-       }
-#endif
-}
-
-/*
- * xfs_lock_two_inodes() can only be used to lock one type of lock
- * at a time - the iolock or the ilock, but not both at once. If
- * we lock both at once, lockdep will report false positives saying
- * we have violated locking orders.
- */
-void
-xfs_lock_two_inodes(
-       xfs_inode_t             *ip0,
-       xfs_inode_t             *ip1,
-       uint                    lock_mode)
-{
-       xfs_inode_t             *temp;
-       int                     attempts = 0;
-       xfs_log_item_t          *lp;
-
-       if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL))
-               ASSERT((lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) == 0);
-       ASSERT(ip0->i_ino != ip1->i_ino);
-
-       if (ip0->i_ino > ip1->i_ino) {
-               temp = ip0;
-               ip0 = ip1;
-               ip1 = temp;
-       }
-
- again:
-       xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0));
-
-       /*
-        * If the first lock we have locked is in the AIL, we must TRY to get
-        * the second lock. If we can't get it, we must release the first one
-        * and try again.
-        */
-       lp = (xfs_log_item_t *)ip0->i_itemp;
-       if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
-               if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) {
-                       xfs_iunlock(ip0, lock_mode);
-                       if ((++attempts % 5) == 0)
-                               delay(1); /* Don't just spin the CPU */
-                       goto again;
-               }
-       } else {
-               xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1));
-       }
-}
-
-int
-xfs_remove(
-       xfs_inode_t             *dp,
-       struct xfs_name         *name,
-       xfs_inode_t             *ip)
-{
-       xfs_mount_t             *mp = dp->i_mount;
-       xfs_trans_t             *tp = NULL;
-       int                     is_dir = S_ISDIR(ip->i_d.di_mode);
-       int                     error = 0;
-       xfs_bmap_free_t         free_list;
-       xfs_fsblock_t           first_block;
-       int                     cancel_flags;
-       int                     committed;
-       int                     link_zero;
-       uint                    resblks;
-       uint                    log_count;
-
-       trace_xfs_remove(dp, name);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       error = xfs_qm_dqattach(dp, 0);
-       if (error)
-               goto std_return;
-
-       error = xfs_qm_dqattach(ip, 0);
-       if (error)
-               goto std_return;
-
-       if (is_dir) {
-               tp = xfs_trans_alloc(mp, XFS_TRANS_RMDIR);
-               log_count = XFS_DEFAULT_LOG_COUNT;
-       } else {
-               tp = xfs_trans_alloc(mp, XFS_TRANS_REMOVE);
-               log_count = XFS_REMOVE_LOG_COUNT;
-       }
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-
-       /*
-        * We try to get the real space reservation first,
-        * allowing for directory btree deletion(s) implying
-        * possible bmap insert(s).  If we can't get the space
-        * reservation then we use 0 instead, and avoid the bmap
-        * btree insert(s) in the directory code by, if the bmap
-        * insert tries to happen, instead trimming the LAST
-        * block from the directory.
-        */
-       resblks = XFS_REMOVE_SPACE_RES(mp);
-       error = xfs_trans_reserve(tp, resblks, XFS_REMOVE_LOG_RES(mp), 0,
-                                 XFS_TRANS_PERM_LOG_RES, log_count);
-       if (error == ENOSPC) {
-               resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_REMOVE_LOG_RES(mp), 0,
-                                         XFS_TRANS_PERM_LOG_RES, log_count);
-       }
-       if (error) {
-               ASSERT(error != ENOSPC);
-               cancel_flags = 0;
-               goto out_trans_cancel;
-       }
-
-       xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
-
-       xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       /*
-        * If we're removing a directory perform some additional validation.
-        */
-       if (is_dir) {
-               ASSERT(ip->i_d.di_nlink >= 2);
-               if (ip->i_d.di_nlink != 2) {
-                       error = XFS_ERROR(ENOTEMPTY);
-                       goto out_trans_cancel;
-               }
-               if (!xfs_dir_isempty(ip)) {
-                       error = XFS_ERROR(ENOTEMPTY);
-                       goto out_trans_cancel;
-               }
-       }
-
-       xfs_bmap_init(&free_list, &first_block);
-       error = xfs_dir_removename(tp, dp, name, ip->i_ino,
-                                       &first_block, &free_list, resblks);
-       if (error) {
-               ASSERT(error != ENOENT);
-               goto out_bmap_cancel;
-       }
-       xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-
-       if (is_dir) {
-               /*
-                * Drop the link from ip's "..".
-                */
-               error = xfs_droplink(tp, dp);
-               if (error)
-                       goto out_bmap_cancel;
-
-               /*
-                * Drop the "." link from ip to self.
-                */
-               error = xfs_droplink(tp, ip);
-               if (error)
-                       goto out_bmap_cancel;
-       } else {
-               /*
-                * When removing a non-directory we need to log the parent
-                * inode here.  For a directory this is done implicitly
-                * by the xfs_droplink call for the ".." entry.
-                */
-               xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-       }
-
-       /*
-        * Drop the link from dp to ip.
-        */
-       error = xfs_droplink(tp, ip);
-       if (error)
-               goto out_bmap_cancel;
-
-       /*
-        * Determine if this is the last link while
-        * we are in the transaction.
-        */
-       link_zero = (ip->i_d.di_nlink == 0);
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * remove transaction goes to disk before returning to
-        * the user.
-        */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC))
-               xfs_trans_set_sync(tp);
-
-       error = xfs_bmap_finish(&tp, &free_list, &committed);
-       if (error)
-               goto out_bmap_cancel;
-
-       error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-       if (error)
-               goto std_return;
-
-       /*
-        * If we are using filestreams, kill the stream association.
-        * If the file is still open it may get a new one but that
-        * will get killed on last close in xfs_close() so we don't
-        * have to worry about that.
-        */
-       if (!is_dir && link_zero && xfs_inode_is_filestream(ip))
-               xfs_filestream_deassociate(ip);
-
-       return 0;
-
- out_bmap_cancel:
-       xfs_bmap_cancel(&free_list);
-       cancel_flags |= XFS_TRANS_ABORT;
- out_trans_cancel:
-       xfs_trans_cancel(tp, cancel_flags);
- std_return:
-       return error;
-}
-
-int
-xfs_link(
-       xfs_inode_t             *tdp,
-       xfs_inode_t             *sip,
-       struct xfs_name         *target_name)
-{
-       xfs_mount_t             *mp = tdp->i_mount;
-       xfs_trans_t             *tp;
-       int                     error;
-       xfs_bmap_free_t         free_list;
-       xfs_fsblock_t           first_block;
-       int                     cancel_flags;
-       int                     committed;
-       int                     resblks;
-
-       trace_xfs_link(tdp, target_name);
-
-       ASSERT(!S_ISDIR(sip->i_d.di_mode));
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       error = xfs_qm_dqattach(sip, 0);
-       if (error)
-               goto std_return;
-
-       error = xfs_qm_dqattach(tdp, 0);
-       if (error)
-               goto std_return;
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_LINK);
-       cancel_flags = XFS_TRANS_RELEASE_LOG_RES;
-       resblks = XFS_LINK_SPACE_RES(mp, target_name->len);
-       error = xfs_trans_reserve(tp, resblks, XFS_LINK_LOG_RES(mp), 0,
-                       XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
-       if (error == ENOSPC) {
-               resblks = 0;
-               error = xfs_trans_reserve(tp, 0, XFS_LINK_LOG_RES(mp), 0,
-                               XFS_TRANS_PERM_LOG_RES, XFS_LINK_LOG_COUNT);
-       }
-       if (error) {
-               cancel_flags = 0;
-               goto error_return;
-       }
-
-       xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
-
-       xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, tdp, XFS_ILOCK_EXCL);
-
-       /*
-        * If we are using project inheritance, we only allow hard link
-        * creation in our tree when the project IDs are the same; else
-        * the tree quota mechanism could be circumvented.
-        */
-       if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
-                    (xfs_get_projid(tdp) != xfs_get_projid(sip)))) {
-               error = XFS_ERROR(EXDEV);
-               goto error_return;
-       }
-
-       error = xfs_dir_canenter(tp, tdp, target_name, resblks);
-       if (error)
-               goto error_return;
-
-       xfs_bmap_init(&free_list, &first_block);
-
-       error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino,
-                                       &first_block, &free_list, resblks);
-       if (error)
-               goto abort_return;
-       xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
-
-       error = xfs_bumplink(tp, sip);
-       if (error)
-               goto abort_return;
-
-       /*
-        * If this is a synchronous mount, make sure that the
-        * link transaction goes to disk before returning to
-        * the user.
-        */
-       if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) {
-               xfs_trans_set_sync(tp);
-       }
-
-       error = xfs_bmap_finish (&tp, &free_list, &committed);
-       if (error) {
-               xfs_bmap_cancel(&free_list);
-               goto abort_return;
-       }
-
-       return xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-
- abort_return:
-       cancel_flags |= XFS_TRANS_ABORT;
- error_return:
-       xfs_trans_cancel(tp, cancel_flags);
- std_return:
-       return error;
-}
-
-int
-xfs_set_dmattrs(
-       xfs_inode_t     *ip,
-       u_int           evmask,
-       u_int16_t       state)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       xfs_trans_t     *tp;
-       int             error;
-
-       if (!capable(CAP_SYS_ADMIN))
-               return XFS_ERROR(EPERM);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       tp = xfs_trans_alloc(mp, XFS_TRANS_SET_DMATTRS);
-       error = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES (mp), 0, 0, 0);
-       if (error) {
-               xfs_trans_cancel(tp, 0);
-               return error;
-       }
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       ip->i_d.di_dmevmask = evmask;
-       ip->i_d.di_dmstate  = state;
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       error = xfs_trans_commit(tp, 0);
-
-       return error;
-}
-
-/*
- * xfs_alloc_file_space()
- *      This routine allocates disk space for the given file.
- *
- *     If alloc_type == 0, this request is for an ALLOCSP type
- *     request which will change the file size.  In this case, no
- *     DMAPI event will be generated by the call.  A TRUNCATE event
- *     will be generated later by xfs_setattr.
- *
- *     If alloc_type != 0, this request is for a RESVSP type
- *     request, and a DMAPI DM_EVENT_WRITE will be generated if the
- *     lower block boundary byte address is less than the file's
- *     length.
- *
- * RETURNS:
- *       0 on success
- *      errno on error
- *
- */
-STATIC int
-xfs_alloc_file_space(
-       xfs_inode_t             *ip,
-       xfs_off_t               offset,
-       xfs_off_t               len,
-       int                     alloc_type,
-       int                     attr_flags)
-{
-       xfs_mount_t             *mp = ip->i_mount;
-       xfs_off_t               count;
-       xfs_filblks_t           allocated_fsb;
-       xfs_filblks_t           allocatesize_fsb;
-       xfs_extlen_t            extsz, temp;
-       xfs_fileoff_t           startoffset_fsb;
-       xfs_fsblock_t           firstfsb;
-       int                     nimaps;
-       int                     quota_flag;
-       int                     rt;
-       xfs_trans_t             *tp;
-       xfs_bmbt_irec_t         imaps[1], *imapp;
-       xfs_bmap_free_t         free_list;
-       uint                    qblocks, resblks, resrtextents;
-       int                     committed;
-       int                     error;
-
-       trace_xfs_alloc_file_space(ip);
-
-       if (XFS_FORCED_SHUTDOWN(mp))
-               return XFS_ERROR(EIO);
-
-       error = xfs_qm_dqattach(ip, 0);
-       if (error)
-               return error;
-
-       if (len <= 0)
-               return XFS_ERROR(EINVAL);
-
-       rt = XFS_IS_REALTIME_INODE(ip);
-       extsz = xfs_get_extsz_hint(ip);
-
-       count = len;
-       imapp = &imaps[0];
-       nimaps = 1;
-       startoffset_fsb = XFS_B_TO_FSBT(mp, offset);
-       allocatesize_fsb = XFS_B_TO_FSB(mp, count);
-
-       /*
-        * Allocate file space until done or until there is an error
-        */
-       while (allocatesize_fsb && !error) {
-               xfs_fileoff_t   s, e;
-
-               /*
-                * Determine space reservations for data/realtime.
-                */
-               if (unlikely(extsz)) {
-                       s = startoffset_fsb;
-                       do_div(s, extsz);
-                       s *= extsz;
-                       e = startoffset_fsb + allocatesize_fsb;
-                       if ((temp = do_mod(startoffset_fsb, extsz)))
-                               e += temp;
-                       if ((temp = do_mod(e, extsz)))
-                               e += extsz - temp;
-               } else {
-                       s = 0;
-                       e = allocatesize_fsb;
-               }
-
-               /*
-                * The transaction reservation is limited to a 32-bit block
-                * count, hence we need to limit the number of blocks we are
-                * trying to reserve to avoid an overflow. We can't allocate
-                * more than @nimaps extents, and an extent is limited on disk
-                * to MAXEXTLEN (21 bits), so use that to enforce the limit.
-                */
-               resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps));
-               if (unlikely(rt)) {
-                       resrtextents = qblocks = resblks;
-                       resrtextents /= mp->m_sb.sb_rextsize;
-                       resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
-                       quota_flag = XFS_QMOPT_RES_RTBLKS;
-               } else {
-                       resrtextents = 0;
-                       resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks);
-                       quota_flag = XFS_QMOPT_RES_REGBLKS;
-               }
-
-               /*
-                * Allocate and setup the transaction.
-                */
-               tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
-               error = xfs_trans_reserve(tp, resblks,
-                                         XFS_WRITE_LOG_RES(mp), resrtextents,
-                                         XFS_TRANS_PERM_LOG_RES,
-                                         XFS_WRITE_LOG_COUNT);
-               /*
-                * Check for running out of space
-                */
-               if (error) {
-                       /*
-                        * Free the transaction structure.
-                        */
-                       ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
-                       xfs_trans_cancel(tp, 0);
-                       break;
-               }
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks,
-                                                     0, quota_flag);
-               if (error)
-                       goto error1;
-
-               xfs_trans_ijoin(tp, ip, 0);
-
-               xfs_bmap_init(&free_list, &firstfsb);
-               error = xfs_bmapi_write(tp, ip, startoffset_fsb,
-                                       allocatesize_fsb, alloc_type, &firstfsb,
-                                       0, imapp, &nimaps, &free_list);
-               if (error) {
-                       goto error0;
-               }
-
-               /*
-                * Complete the transaction
-                */
-               error = xfs_bmap_finish(&tp, &free_list, &committed);
-               if (error) {
-                       goto error0;
-               }
-
-               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               if (error) {
-                       break;
-               }
-
-               allocated_fsb = imapp->br_blockcount;
-
-               if (nimaps == 0) {
-                       error = XFS_ERROR(ENOSPC);
-                       break;
-               }
-
-               startoffset_fsb += allocated_fsb;
-               allocatesize_fsb -= allocated_fsb;
-       }
-
-       return error;
-
-error0:        /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
-       xfs_bmap_cancel(&free_list);
-       xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag);
-
-error1:        /* Just cancel transaction */
-       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       return error;
-}
-
-/*
- * Zero file bytes between startoff and endoff inclusive.
- * The iolock is held exclusive and no blocks are buffered.
- *
- * This function is used by xfs_free_file_space() to zero
- * partial blocks when the range to free is not block aligned.
- * When unreserving space with boundaries that are not block
- * aligned we round up the start and round down the end
- * boundaries and then use this function to zero the parts of
- * the blocks that got dropped during the rounding.
- */
-STATIC int
-xfs_zero_remaining_bytes(
-       xfs_inode_t             *ip,
-       xfs_off_t               startoff,
-       xfs_off_t               endoff)
-{
-       xfs_bmbt_irec_t         imap;
-       xfs_fileoff_t           offset_fsb;
-       xfs_off_t               lastoffset;
-       xfs_off_t               offset;
-       xfs_buf_t               *bp;
-       xfs_mount_t             *mp = ip->i_mount;
-       int                     nimap;
-       int                     error = 0;
-
-       /*
-        * Avoid doing I/O beyond eof - it's not necessary
-        * since nothing can read beyond eof.  The space will
-        * be zeroed when the file is extended anyway.
-        */
-       if (startoff >= XFS_ISIZE(ip))
-               return 0;
-
-       if (endoff > XFS_ISIZE(ip))
-               endoff = XFS_ISIZE(ip);
-
-       bp = xfs_buf_get_uncached(XFS_IS_REALTIME_INODE(ip) ?
-                                       mp->m_rtdev_targp : mp->m_ddev_targp,
-                                 BTOBB(mp->m_sb.sb_blocksize), 0);
-       if (!bp)
-               return XFS_ERROR(ENOMEM);
-
-       xfs_buf_unlock(bp);
-
-       for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
-               offset_fsb = XFS_B_TO_FSBT(mp, offset);
-               nimap = 1;
-               error = xfs_bmapi_read(ip, offset_fsb, 1, &imap, &nimap, 0);
-               if (error || nimap < 1)
-                       break;
-               ASSERT(imap.br_blockcount >= 1);
-               ASSERT(imap.br_startoff == offset_fsb);
-               lastoffset = XFS_FSB_TO_B(mp, imap.br_startoff + 1) - 1;
-               if (lastoffset > endoff)
-                       lastoffset = endoff;
-               if (imap.br_startblock == HOLESTARTBLOCK)
-                       continue;
-               ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
-               if (imap.br_state == XFS_EXT_UNWRITTEN)
-                       continue;
-               XFS_BUF_UNDONE(bp);
-               XFS_BUF_UNWRITE(bp);
-               XFS_BUF_READ(bp);
-               XFS_BUF_SET_ADDR(bp, xfs_fsb_to_db(ip, imap.br_startblock));
-               xfsbdstrat(mp, bp);
-               error = xfs_buf_iowait(bp);
-               if (error) {
-                       xfs_buf_ioerror_alert(bp,
-                                       "xfs_zero_remaining_bytes(read)");
-                       break;
-               }
-               memset(bp->b_addr +
-                       (offset - XFS_FSB_TO_B(mp, imap.br_startoff)),
-                     0, lastoffset - offset + 1);
-               XFS_BUF_UNDONE(bp);
-               XFS_BUF_UNREAD(bp);
-               XFS_BUF_WRITE(bp);
-               xfsbdstrat(mp, bp);
-               error = xfs_buf_iowait(bp);
-               if (error) {
-                       xfs_buf_ioerror_alert(bp,
-                                       "xfs_zero_remaining_bytes(write)");
-                       break;
-               }
-       }
-       xfs_buf_free(bp);
-       return error;
-}
-
-/*
- * xfs_free_file_space()
- *      This routine frees disk space for the given file.
- *
- *     This routine is only called by xfs_change_file_space
- *     for an UNRESVSP type call.
- *
- * RETURNS:
- *       0 on success
- *      errno on error
- *
- */
-STATIC int
-xfs_free_file_space(
-       xfs_inode_t             *ip,
-       xfs_off_t               offset,
-       xfs_off_t               len,
-       int                     attr_flags)
-{
-       int                     committed;
-       int                     done;
-       xfs_fileoff_t           endoffset_fsb;
-       int                     error;
-       xfs_fsblock_t           firstfsb;
-       xfs_bmap_free_t         free_list;
-       xfs_bmbt_irec_t         imap;
-       xfs_off_t               ioffset;
-       xfs_extlen_t            mod=0;
-       xfs_mount_t             *mp;
-       int                     nimap;
-       uint                    resblks;
-       xfs_off_t               rounding;
-       int                     rt;
-       xfs_fileoff_t           startoffset_fsb;
-       xfs_trans_t             *tp;
-       int                     need_iolock = 1;
-
-       mp = ip->i_mount;
-
-       trace_xfs_free_file_space(ip);
-
-       error = xfs_qm_dqattach(ip, 0);
-       if (error)
-               return error;
-
-       error = 0;
-       if (len <= 0)   /* if nothing being freed */
-               return error;
-       rt = XFS_IS_REALTIME_INODE(ip);
-       startoffset_fsb = XFS_B_TO_FSB(mp, offset);
-       endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len);
-
-       if (attr_flags & XFS_ATTR_NOLOCK)
-               need_iolock = 0;
-       if (need_iolock) {
-               xfs_ilock(ip, XFS_IOLOCK_EXCL);
-               /* wait for the completion of any pending DIOs */
-               inode_dio_wait(VFS_I(ip));
-       }
-
-       rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
-       ioffset = offset & ~(rounding - 1);
-       error = -filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
-                                             ioffset, -1);
-       if (error)
-               goto out_unlock_iolock;
-       truncate_pagecache_range(VFS_I(ip), ioffset, -1);
-
-       /*
-        * Need to zero the stuff we're not freeing, on disk.
-        * If it's a realtime file & can't use unwritten extents then we
-        * actually need to zero the extent edges.  Otherwise xfs_bunmapi
-        * will take care of it for us.
-        */
-       if (rt && !xfs_sb_version_hasextflgbit(&mp->m_sb)) {
-               nimap = 1;
-               error = xfs_bmapi_read(ip, startoffset_fsb, 1,
-                                       &imap, &nimap, 0);
-               if (error)
-                       goto out_unlock_iolock;
-               ASSERT(nimap == 0 || nimap == 1);
-               if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
-                       xfs_daddr_t     block;
-
-                       ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
-                       block = imap.br_startblock;
-                       mod = do_div(block, mp->m_sb.sb_rextsize);
-                       if (mod)
-                               startoffset_fsb += mp->m_sb.sb_rextsize - mod;
-               }
-               nimap = 1;
-               error = xfs_bmapi_read(ip, endoffset_fsb - 1, 1,
-                                       &imap, &nimap, 0);
-               if (error)
-                       goto out_unlock_iolock;
-               ASSERT(nimap == 0 || nimap == 1);
-               if (nimap && imap.br_startblock != HOLESTARTBLOCK) {
-                       ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
-                       mod++;
-                       if (mod && (mod != mp->m_sb.sb_rextsize))
-                               endoffset_fsb -= mod;
-               }
-       }
-       if ((done = (endoffset_fsb <= startoffset_fsb)))
-               /*
-                * One contiguous piece to clear
-                */
-               error = xfs_zero_remaining_bytes(ip, offset, offset + len - 1);
-       else {
-               /*
-                * Some full blocks, possibly two pieces to clear
-                */
-               if (offset < XFS_FSB_TO_B(mp, startoffset_fsb))
-                       error = xfs_zero_remaining_bytes(ip, offset,
-                               XFS_FSB_TO_B(mp, startoffset_fsb) - 1);
-               if (!error &&
-                   XFS_FSB_TO_B(mp, endoffset_fsb) < offset + len)
-                       error = xfs_zero_remaining_bytes(ip,
-                               XFS_FSB_TO_B(mp, endoffset_fsb),
-                               offset + len - 1);
-       }
-
-       /*
-        * free file space until done or until there is an error
-        */
-       resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0);
-       while (!error && !done) {
-
-               /*
-                * allocate and setup the transaction. Allow this
-                * transaction to dip into the reserve blocks to ensure
-                * the freeing of the space succeeds at ENOSPC.
-                */
-               tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
-               tp->t_flags |= XFS_TRANS_RESERVE;
-               error = xfs_trans_reserve(tp,
-                                         resblks,
-                                         XFS_WRITE_LOG_RES(mp),
-                                         0,
-                                         XFS_TRANS_PERM_LOG_RES,
-                                         XFS_WRITE_LOG_COUNT);
-
-               /*
-                * check for running out of space
-                */
-               if (error) {
-                       /*
-                        * Free the transaction structure.
-                        */
-                       ASSERT(error == ENOSPC || XFS_FORCED_SHUTDOWN(mp));
-                       xfs_trans_cancel(tp, 0);
-                       break;
-               }
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               error = xfs_trans_reserve_quota(tp, mp,
-                               ip->i_udquot, ip->i_gdquot, ip->i_pdquot,
-                               resblks, 0, XFS_QMOPT_RES_REGBLKS);
-               if (error)
-                       goto error1;
-
-               xfs_trans_ijoin(tp, ip, 0);
-
-               /*
-                * issue the bunmapi() call to free the blocks
-                */
-               xfs_bmap_init(&free_list, &firstfsb);
-               error = xfs_bunmapi(tp, ip, startoffset_fsb,
-                                 endoffset_fsb - startoffset_fsb,
-                                 0, 2, &firstfsb, &free_list, &done);
-               if (error) {
-                       goto error0;
-               }
-
-               /*
-                * complete the transaction
-                */
-               error = xfs_bmap_finish(&tp, &free_list, &committed);
-               if (error) {
-                       goto error0;
-               }
-
-               error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
-               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       }
-
- out_unlock_iolock:
-       if (need_iolock)
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-       return error;
-
- error0:
-       xfs_bmap_cancel(&free_list);
- error1:
-       xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-       xfs_iunlock(ip, need_iolock ? (XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL) :
-                   XFS_ILOCK_EXCL);
-       return error;
-}
-
-
-STATIC int
-xfs_zero_file_space(
-       struct xfs_inode        *ip,
-       xfs_off_t               offset,
-       xfs_off_t               len,
-       int                     attr_flags)
-{
-       struct xfs_mount        *mp = ip->i_mount;
-       uint                    granularity;
-       xfs_off_t               start_boundary;
-       xfs_off_t               end_boundary;
-       int                     error;
-
-       granularity = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
-
-       /*
-        * Round the range of extents we are going to convert inwards.  If the
-        * offset is aligned, then it doesn't get changed so we zero from the
-        * start of the block offset points to.
-        */
-       start_boundary = round_up(offset, granularity);
-       end_boundary = round_down(offset + len, granularity);
-
-       ASSERT(start_boundary >= offset);
-       ASSERT(end_boundary <= offset + len);
-
-       if (!(attr_flags & XFS_ATTR_NOLOCK))
-               xfs_ilock(ip, XFS_IOLOCK_EXCL);
-
-       if (start_boundary < end_boundary - 1) {
-               /* punch out the page cache over the conversion range */
-               truncate_pagecache_range(VFS_I(ip), start_boundary,
-                                        end_boundary - 1);
-               /* convert the blocks */
-               error = xfs_alloc_file_space(ip, start_boundary,
-                                       end_boundary - start_boundary - 1,
-                                       XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT,
-                                       attr_flags);
-               if (error)
-                       goto out_unlock;
-
-               /* We've handled the interior of the range, now for the edges */
-               if (start_boundary != offset)
-                       error = xfs_iozero(ip, offset, start_boundary - offset);
-               if (error)
-                       goto out_unlock;
-
-               if (end_boundary != offset + len)
-                       error = xfs_iozero(ip, end_boundary,
-                                          offset + len - end_boundary);
-
-       } else {
-               /*
-                * It's either a sub-granularity range or the range spanned lies
-                * partially across two adjacent blocks.
-                */
-               error = xfs_iozero(ip, offset, len);
-       }
-
-out_unlock:
-       if (!(attr_flags & XFS_ATTR_NOLOCK))
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-       return error;
-
-}
-
-/*
- * xfs_change_file_space()
- *      This routine allocates or frees disk space for the given file.
- *      The user specified parameters are checked for alignment and size
- *      limitations.
- *
- * RETURNS:
- *       0 on success
- *      errno on error
- *
- */
-int
-xfs_change_file_space(
-       xfs_inode_t     *ip,
-       int             cmd,
-       xfs_flock64_t   *bf,
-       xfs_off_t       offset,
-       int             attr_flags)
-{
-       xfs_mount_t     *mp = ip->i_mount;
-       int             clrprealloc;
-       int             error;
-       xfs_fsize_t     fsize;
-       int             setprealloc;
-       xfs_off_t       startoffset;
-       xfs_trans_t     *tp;
-       struct iattr    iattr;
-
-       if (!S_ISREG(ip->i_d.di_mode))
-               return XFS_ERROR(EINVAL);
-
-       switch (bf->l_whence) {
-       case 0: /*SEEK_SET*/
-               break;
-       case 1: /*SEEK_CUR*/
-               bf->l_start += offset;
-               break;
-       case 2: /*SEEK_END*/
-               bf->l_start += XFS_ISIZE(ip);
-               break;
-       default:
-               return XFS_ERROR(EINVAL);
-       }
-
-       /*
-        * length of <= 0 for resv/unresv/zero is invalid.  length for
-        * alloc/free is ignored completely and we have no idea what userspace
-        * might have set it to, so set it to zero to allow range
-        * checks to pass.
-        */
-       switch (cmd) {
-       case XFS_IOC_ZERO_RANGE:
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_RESVSP64:
-       case XFS_IOC_UNRESVSP:
-       case XFS_IOC_UNRESVSP64:
-               if (bf->l_len <= 0)
-                       return XFS_ERROR(EINVAL);
-               break;
-       default:
-               bf->l_len = 0;
-               break;
-       }
-
-       if (bf->l_start < 0 ||
-           bf->l_start > mp->m_super->s_maxbytes ||
-           bf->l_start + bf->l_len < 0 ||
-           bf->l_start + bf->l_len >= mp->m_super->s_maxbytes)
-               return XFS_ERROR(EINVAL);
-
-       bf->l_whence = 0;
-
-       startoffset = bf->l_start;
-       fsize = XFS_ISIZE(ip);
-
-       setprealloc = clrprealloc = 0;
-       switch (cmd) {
-       case XFS_IOC_ZERO_RANGE:
-               error = xfs_zero_file_space(ip, startoffset, bf->l_len,
-                                               attr_flags);
-               if (error)
-                       return error;
-               setprealloc = 1;
-               break;
-
-       case XFS_IOC_RESVSP:
-       case XFS_IOC_RESVSP64:
-               error = xfs_alloc_file_space(ip, startoffset, bf->l_len,
-                                               XFS_BMAPI_PREALLOC, attr_flags);
-               if (error)
-                       return error;
-               setprealloc = 1;
-               break;
-
-       case XFS_IOC_UNRESVSP:
-       case XFS_IOC_UNRESVSP64:
-               if ((error = xfs_free_file_space(ip, startoffset, bf->l_len,
-                                                               attr_flags)))
-                       return error;
-               break;
-
-       case XFS_IOC_ALLOCSP:
-       case XFS_IOC_ALLOCSP64:
-       case XFS_IOC_FREESP:
-       case XFS_IOC_FREESP64:
-               /*
-                * These operations actually do IO when extending the file, but
-                * the allocation is done seperately to the zeroing that is
-                * done. This set of operations need to be serialised against
-                * other IO operations, such as truncate and buffered IO. We
-                * need to take the IOLOCK here to serialise the allocation and
-                * zeroing IO to prevent other IOLOCK holders (e.g. getbmap,
-                * truncate, direct IO) from racing against the transient
-                * allocated but not written state we can have here.
-                */
-               xfs_ilock(ip, XFS_IOLOCK_EXCL);
-               if (startoffset > fsize) {
-                       error = xfs_alloc_file_space(ip, fsize,
-                                       startoffset - fsize, 0,
-                                       attr_flags | XFS_ATTR_NOLOCK);
-                       if (error) {
-                               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-                               break;
-                       }
-               }
-
-               iattr.ia_valid = ATTR_SIZE;
-               iattr.ia_size = startoffset;
-
-               error = xfs_setattr_size(ip, &iattr,
-                                        attr_flags | XFS_ATTR_NOLOCK);
-               xfs_iunlock(ip, XFS_IOLOCK_EXCL);
-
-               if (error)
-                       return error;
-
-               clrprealloc = 1;
-               break;
-
-       default:
-               ASSERT(0);
-               return XFS_ERROR(EINVAL);
-       }
-
-       /*
-        * update the inode timestamp, mode, and prealloc flag bits
-        */
-       tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
-
-       if ((error = xfs_trans_reserve(tp, 0, XFS_WRITEID_LOG_RES(mp),
-                                     0, 0, 0))) {
-               /* ASSERT(0); */
-               xfs_trans_cancel(tp, 0);
-               return error;
-       }
-
-       xfs_ilock(ip, XFS_ILOCK_EXCL);
-       xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-
-       if ((attr_flags & XFS_ATTR_DMI) == 0) {
-               ip->i_d.di_mode &= ~S_ISUID;
-
-               /*
-                * Note that we don't have to worry about mandatory
-                * file locking being disabled here because we only
-                * clear the S_ISGID bit if the Group execute bit is
-                * on, but if it was on then mandatory locking wouldn't
-                * have been enabled.
-                */
-               if (ip->i_d.di_mode & S_IXGRP)
-                       ip->i_d.di_mode &= ~S_ISGID;
-
-               xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       }
-       if (setprealloc)
-               ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
-       else if (clrprealloc)
-               ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
-
-       xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
-       if (attr_flags & XFS_ATTR_SYNC)
-               xfs_trans_set_sync(tp);
-       return xfs_trans_commit(tp, 0);
-}
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
deleted file mode 100644 (file)
index 38c67c3..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _XFS_VNODEOPS_H
-#define _XFS_VNODEOPS_H 1
-
-struct attrlist_cursor_kern;
-struct file;
-struct iattr;
-struct inode;
-struct iovec;
-struct kiocb;
-struct pipe_inode_info;
-struct uio;
-struct xfs_inode;
-
-
-int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, int flags);
-int xfs_setattr_size(struct xfs_inode *ip, struct iattr *vap, int flags);
-#define        XFS_ATTR_DMI            0x01    /* invocation from a DMI function */
-#define        XFS_ATTR_NONBLOCK       0x02    /* return EAGAIN if operation would block */
-#define XFS_ATTR_NOLOCK                0x04    /* Don't grab any conflicting locks */
-#define XFS_ATTR_NOACL         0x08    /* Don't call xfs_acl_chmod */
-#define XFS_ATTR_SYNC          0x10    /* synchronous operation required */
-
-int xfs_readlink(struct xfs_inode *ip, char *link);
-int xfs_release(struct xfs_inode *ip);
-int xfs_inactive(struct xfs_inode *ip);
-int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
-               struct xfs_inode **ipp, struct xfs_name *ci_name);
-int xfs_create(struct xfs_inode *dp, struct xfs_name *name, umode_t mode,
-               xfs_dev_t rdev, struct xfs_inode **ipp);
-int xfs_remove(struct xfs_inode *dp, struct xfs_name *name,
-               struct xfs_inode *ip);
-int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip,
-               struct xfs_name *target_name);
-int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx, size_t bufsize);
-int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name,
-               const char *target_path, umode_t mode, struct xfs_inode **ipp);
-int xfs_set_dmattrs(struct xfs_inode *ip, u_int evmask, u_int16_t state);
-int xfs_change_file_space(struct xfs_inode *ip, int cmd,
-               xfs_flock64_t *bf, xfs_off_t offset, int attr_flags);
-int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
-               struct xfs_inode *src_ip, struct xfs_inode *target_dp,
-               struct xfs_name *target_name, struct xfs_inode *target_ip);
-int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-               unsigned char *value, int *valuelenp, int flags);
-int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-               unsigned char *value, int valuelen, int flags);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
-int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
-               int flags, struct attrlist_cursor_kern *cursor);
-
-int xfs_iozero(struct xfs_inode *, loff_t, size_t);
-int xfs_zero_eof(struct xfs_inode *, xfs_off_t, xfs_fsize_t);
-int xfs_free_eofblocks(struct xfs_mount *, struct xfs_inode *, bool);
-
-#endif /* _XFS_VNODEOPS_H */
index 87d3e03878c8da30b762d19263ec3e1cbe02aa24..e01f35ea76ba436310f11d82b9fdf78322d8f6fe 100644 (file)
  */
 
 #include "xfs.h"
+#include "xfs_log_format.h"
 #include "xfs_da_btree.h"
 #include "xfs_bmap_btree.h"
 #include "xfs_inode.h"
 #include "xfs_attr.h"
 #include "xfs_attr_leaf.h"
 #include "xfs_acl.h"
-#include "xfs_vnodeops.h"
 
 #include <linux/posix_acl_xattr.h>
 #include <linux/xattr.h>
diff --git a/include/asm-generic/dma-contiguous.h b/include/asm-generic/dma-contiguous.h
deleted file mode 100644 (file)
index 294b1e7..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef ASM_DMA_CONTIGUOUS_H
-#define ASM_DMA_CONTIGUOUS_H
-
-#ifdef __KERNEL__
-#ifdef CONFIG_CMA
-
-#include <linux/device.h>
-#include <linux/dma-contiguous.h>
-
-static inline struct cma *dev_get_cma_area(struct device *dev)
-{
-       if (dev && dev->cma_area)
-               return dev->cma_area;
-       return dma_contiguous_default_area;
-}
-
-static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
-{
-       if (dev)
-               dev->cma_area = cma;
-       if (!dev && !dma_contiguous_default_area)
-               dma_contiguous_default_area = cma;
-}
-
-#endif
-#endif
-
-#endif
index fd54a14a7c2a23972f4074217265c3e767063feb..3d79e513c0b3663ef9cd08850801a2d038ee721d 100644 (file)
        {0x1002, 0x130F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1310, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1311, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x1312, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1313, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1315, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x1316, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x1317, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x131B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x131C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
+       {0x1002, 0x131D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_KAVERI|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \
        {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
        {0x1002, 0x3151, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
        {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
index 63d609d8a3f6940f930f3898956e3df0da5a5116..3abfa6ea226edda57aed2b9efaf970dcae1d3c35 100644 (file)
@@ -26,6 +26,7 @@
 #ifndef _I915_DRM_H_
 #define _I915_DRM_H_
 
+#include <drm/i915_pciids.h>
 #include <uapi/drm/i915_drm.h>
 
 /* For use by IPS driver */
@@ -34,4 +35,37 @@ extern bool i915_gpu_raise(void);
 extern bool i915_gpu_lower(void);
 extern bool i915_gpu_busy(void);
 extern bool i915_gpu_turbo_disable(void);
+
+/*
+ * The Bridge device's PCI config space has information about the
+ * fb aperture size and the amount of pre-reserved memory.
+ * This is all handled in the intel-gtt.ko module. i915.ko only
+ * cares about the vga bit for the vga rbiter.
+ */
+#define INTEL_GMCH_CTRL                0x52
+#define INTEL_GMCH_VGA_DISABLE  (1 << 1)
+#define SNB_GMCH_CTRL          0x50
+#define    SNB_GMCH_GGMS_SHIFT 8 /* GTT Graphics Memory Size */
+#define    SNB_GMCH_GGMS_MASK  0x3
+#define    SNB_GMCH_GMS_SHIFT   3 /* Graphics Mode Select */
+#define    SNB_GMCH_GMS_MASK    0x1f
+
+#define I830_GMCH_CTRL                 0x52
+
+#define I855_GMCH_GMS_MASK             0xF0
+#define I855_GMCH_GMS_STOLEN_0M                0x0
+#define I855_GMCH_GMS_STOLEN_1M                (0x1 << 4)
+#define I855_GMCH_GMS_STOLEN_4M                (0x2 << 4)
+#define I855_GMCH_GMS_STOLEN_8M                (0x3 << 4)
+#define I855_GMCH_GMS_STOLEN_16M       (0x4 << 4)
+#define I855_GMCH_GMS_STOLEN_32M       (0x5 << 4)
+#define I915_GMCH_GMS_STOLEN_48M       (0x6 << 4)
+#define I915_GMCH_GMS_STOLEN_64M       (0x7 << 4)
+#define G33_GMCH_GMS_STOLEN_128M       (0x8 << 4)
+#define G33_GMCH_GMS_STOLEN_256M       (0x9 << 4)
+#define INTEL_GMCH_GMS_STOLEN_96M      (0xa << 4)
+#define INTEL_GMCH_GMS_STOLEN_160M     (0xb << 4)
+#define INTEL_GMCH_GMS_STOLEN_224M     (0xc << 4)
+#define INTEL_GMCH_GMS_STOLEN_352M     (0xd << 4)
+
 #endif                         /* _I915_DRM_H_ */
diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h
new file mode 100644 (file)
index 0000000..8a10f5c
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2013 Intel Corporation
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND 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 _I915_PCIIDS_H
+#define _I915_PCIIDS_H
+
+/*
+ * A pci_device_id struct {
+ *     __u32 vendor, device;
+ *      __u32 subvendor, subdevice;
+ *     __u32 class, class_mask;
+ *     kernel_ulong_t driver_data;
+ * };
+ * Don't use C99 here because "class" is reserved and we want to
+ * give userspace flexibility.
+ */
+#define INTEL_VGA_DEVICE(id, info) {           \
+       0x8086, id,                             \
+       ~0, ~0,                                 \
+       0x030000, 0xff0000,                     \
+       (unsigned long) info }
+
+#define INTEL_QUANTA_VGA_DEVICE(info) {                \
+       0x8086, 0x16a,                          \
+       0x152d, 0x8990,                         \
+       0x030000, 0xff0000,                     \
+       (unsigned long) info }
+
+#define INTEL_I830_IDS(info)                           \
+       INTEL_VGA_DEVICE(0x3577, info)
+
+#define INTEL_I845G_IDS(info)                          \
+       INTEL_VGA_DEVICE(0x2562, info)
+
+#define INTEL_I85X_IDS(info)                           \
+       INTEL_VGA_DEVICE(0x3582, info), /* I855_GM */ \
+       INTEL_VGA_DEVICE(0x358e, info)
+
+#define INTEL_I865G_IDS(info)                          \
+       INTEL_VGA_DEVICE(0x2572, info) /* I865_G */
+
+#define INTEL_I915G_IDS(info)                          \
+       INTEL_VGA_DEVICE(0x2582, info), /* I915_G */ \
+       INTEL_VGA_DEVICE(0x258a, info)  /* E7221_G */
+
+#define INTEL_I915GM_IDS(info)                         \
+       INTEL_VGA_DEVICE(0x2592, info) /* I915_GM */
+
+#define INTEL_I945G_IDS(info)                          \
+       INTEL_VGA_DEVICE(0x2772, info) /* I945_G */
+
+#define INTEL_I945GM_IDS(info)                         \
+       INTEL_VGA_DEVICE(0x27a2, info), /* I945_GM */ \
+       INTEL_VGA_DEVICE(0x27ae, info)  /* I945_GME */
+
+#define INTEL_I965G_IDS(info)                          \
+       INTEL_VGA_DEVICE(0x2972, info), /* I946_GZ */   \
+       INTEL_VGA_DEVICE(0x2982, info), /* G35_G */     \
+       INTEL_VGA_DEVICE(0x2992, info), /* I965_Q */    \
+       INTEL_VGA_DEVICE(0x29a2, info)  /* I965_G */
+
+#define INTEL_G33_IDS(info)                            \
+       INTEL_VGA_DEVICE(0x29b2, info), /* Q35_G */ \
+       INTEL_VGA_DEVICE(0x29c2, info), /* G33_G */ \
+       INTEL_VGA_DEVICE(0x29d2, info)  /* Q33_G */
+
+#define INTEL_I965GM_IDS(info)                         \
+       INTEL_VGA_DEVICE(0x2a02, info), /* I965_GM */ \
+       INTEL_VGA_DEVICE(0x2a12, info)  /* I965_GME */
+
+#define INTEL_GM45_IDS(info)                           \
+       INTEL_VGA_DEVICE(0x2a42, info) /* GM45_G */
+
+#define INTEL_G45_IDS(info)                            \
+       INTEL_VGA_DEVICE(0x2e02, info), /* IGD_E_G */ \
+       INTEL_VGA_DEVICE(0x2e12, info), /* Q45_G */ \
+       INTEL_VGA_DEVICE(0x2e22, info), /* G45_G */ \
+       INTEL_VGA_DEVICE(0x2e32, info), /* G41_G */ \
+       INTEL_VGA_DEVICE(0x2e42, info), /* B43_G */ \
+       INTEL_VGA_DEVICE(0x2e92, info)  /* B43_G.1 */
+
+#define INTEL_PINEVIEW_IDS(info)                       \
+       INTEL_VGA_DEVICE(0xa001, info),                 \
+       INTEL_VGA_DEVICE(0xa011, info)
+
+#define INTEL_IRONLAKE_D_IDS(info) \
+       INTEL_VGA_DEVICE(0x0042, info)
+
+#define INTEL_IRONLAKE_M_IDS(info) \
+       INTEL_VGA_DEVICE(0x0046, info)
+
+#define INTEL_SNB_D_IDS(info) \
+       INTEL_VGA_DEVICE(0x0102, info), \
+       INTEL_VGA_DEVICE(0x0112, info), \
+       INTEL_VGA_DEVICE(0x0122, info), \
+       INTEL_VGA_DEVICE(0x010A, info)
+
+#define INTEL_SNB_M_IDS(info) \
+       INTEL_VGA_DEVICE(0x0106, info), \
+       INTEL_VGA_DEVICE(0x0116, info), \
+       INTEL_VGA_DEVICE(0x0126, info)
+
+#define INTEL_IVB_M_IDS(info) \
+       INTEL_VGA_DEVICE(0x0156, info), /* GT1 mobile */ \
+       INTEL_VGA_DEVICE(0x0166, info)  /* GT2 mobile */
+
+#define INTEL_IVB_D_IDS(info) \
+       INTEL_VGA_DEVICE(0x0152, info), /* GT1 desktop */ \
+       INTEL_VGA_DEVICE(0x0162, info), /* GT2 desktop */ \
+       INTEL_VGA_DEVICE(0x015a, info), /* GT1 server */ \
+       INTEL_VGA_DEVICE(0x016a, info)  /* GT2 server */
+
+#define INTEL_IVB_Q_IDS(info) \
+       INTEL_QUANTA_VGA_DEVICE(info) /* Quanta transcode */
+
+#define INTEL_HSW_D_IDS(info) \
+       INTEL_VGA_DEVICE(0x0402, info), /* GT1 desktop */ \
+       INTEL_VGA_DEVICE(0x0412, info), /* GT2 desktop */ \
+       INTEL_VGA_DEVICE(0x0422, info), /* GT3 desktop */ \
+       INTEL_VGA_DEVICE(0x040a, info), /* GT1 server */ \
+       INTEL_VGA_DEVICE(0x041a, info), /* GT2 server */ \
+       INTEL_VGA_DEVICE(0x042a, info), /* GT3 server */ \
+       INTEL_VGA_DEVICE(0x040B, info), /* GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x041B, info), /* GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x042B, info), /* GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x040E, info), /* GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x041E, info), /* GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x042E, info), /* GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x0C02, info), /* SDV GT1 desktop */ \
+       INTEL_VGA_DEVICE(0x0C12, info), /* SDV GT2 desktop */ \
+       INTEL_VGA_DEVICE(0x0C22, info), /* SDV GT3 desktop */ \
+       INTEL_VGA_DEVICE(0x0C0A, info), /* SDV GT1 server */ \
+       INTEL_VGA_DEVICE(0x0C1A, info), /* SDV GT2 server */ \
+       INTEL_VGA_DEVICE(0x0C2A, info), /* SDV GT3 server */ \
+       INTEL_VGA_DEVICE(0x0C0B, info), /* SDV GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x0C1B, info), /* SDV GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x0C2B, info), /* SDV GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x0C0E, info), /* SDV GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x0C1E, info), /* SDV GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x0C2E, info), /* SDV GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x0A02, info), /* ULT GT1 desktop */ \
+       INTEL_VGA_DEVICE(0x0A12, info), /* ULT GT2 desktop */ \
+       INTEL_VGA_DEVICE(0x0A22, info), /* ULT GT3 desktop */ \
+       INTEL_VGA_DEVICE(0x0A0A, info), /* ULT GT1 server */ \
+       INTEL_VGA_DEVICE(0x0A1A, info), /* ULT GT2 server */ \
+       INTEL_VGA_DEVICE(0x0A2A, info), /* ULT GT3 server */ \
+       INTEL_VGA_DEVICE(0x0A0B, info), /* ULT GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x0A1B, info), /* ULT GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x0A2B, info), /* ULT GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x0D02, info), /* CRW GT1 desktop */ \
+       INTEL_VGA_DEVICE(0x0D12, info), /* CRW GT2 desktop */ \
+       INTEL_VGA_DEVICE(0x0D22, info), /* CRW GT3 desktop */ \
+       INTEL_VGA_DEVICE(0x0D0A, info), /* CRW GT1 server */ \
+       INTEL_VGA_DEVICE(0x0D1A, info), /* CRW GT2 server */ \
+       INTEL_VGA_DEVICE(0x0D2A, info), /* CRW GT3 server */ \
+       INTEL_VGA_DEVICE(0x0D0B, info), /* CRW GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x0D1B, info), /* CRW GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x0D2B, info), /* CRW GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x0D0E, info), /* CRW GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x0D1E, info), /* CRW GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x0D2E, info)  /* CRW GT3 reserved */ \
+
+#define INTEL_HSW_M_IDS(info) \
+       INTEL_VGA_DEVICE(0x0406, info), /* GT1 mobile */ \
+       INTEL_VGA_DEVICE(0x0416, info), /* GT2 mobile */ \
+       INTEL_VGA_DEVICE(0x0426, info), /* GT2 mobile */ \
+       INTEL_VGA_DEVICE(0x0C06, info), /* SDV GT1 mobile */ \
+       INTEL_VGA_DEVICE(0x0C16, info), /* SDV GT2 mobile */ \
+       INTEL_VGA_DEVICE(0x0C26, info), /* SDV GT3 mobile */ \
+       INTEL_VGA_DEVICE(0x0A06, info), /* ULT GT1 mobile */ \
+       INTEL_VGA_DEVICE(0x0A16, info), /* ULT GT2 mobile */ \
+       INTEL_VGA_DEVICE(0x0A26, info), /* ULT GT3 mobile */ \
+       INTEL_VGA_DEVICE(0x0A0E, info), /* ULT GT1 reserved */ \
+       INTEL_VGA_DEVICE(0x0A1E, info), /* ULT GT2 reserved */ \
+       INTEL_VGA_DEVICE(0x0A2E, info), /* ULT GT3 reserved */ \
+       INTEL_VGA_DEVICE(0x0D06, info), /* CRW GT1 mobile */ \
+       INTEL_VGA_DEVICE(0x0D16, info), /* CRW GT2 mobile */ \
+       INTEL_VGA_DEVICE(0x0D26, info)  /* CRW GT3 mobile */
+
+#define INTEL_VLV_M_IDS(info) \
+       INTEL_VGA_DEVICE(0x0f30, info), \
+       INTEL_VGA_DEVICE(0x0f31, info), \
+       INTEL_VGA_DEVICE(0x0f32, info), \
+       INTEL_VGA_DEVICE(0x0f33, info), \
+       INTEL_VGA_DEVICE(0x0157, info)
+
+#define INTEL_VLV_D_IDS(info) \
+       INTEL_VGA_DEVICE(0x0155, info)
+
+#endif /* _I915_PCIIDS_H */
diff --git a/include/dt-bindings/clock/samsung,s3c64xx-clock.h b/include/dt-bindings/clock/samsung,s3c64xx-clock.h
new file mode 100644 (file)
index 0000000..ad95c7f
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2013 Tomasz Figa <tomasz.figa at 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.
+ *
+ * Device Tree binding constants for Samsung S3C64xx clock controller.
+*/
+
+#ifndef _DT_BINDINGS_CLOCK_SAMSUNG_S3C64XX_CLOCK_H
+#define _DT_BINDINGS_CLOCK_SAMSUNG_S3C64XX_CLOCK_H
+
+/*
+ * Let each exported clock get a unique index, which is used on DT-enabled
+ * platforms to lookup the clock from a clock specifier. These indices are
+ * therefore considered an ABI and so must not be changed. This implies
+ * that new clocks should be added either in free spaces between clock groups
+ * or at the end.
+ */
+
+/* Core clocks. */
+#define CLK27M                 1
+#define CLK48M                 2
+#define FOUT_APLL              3
+#define FOUT_MPLL              4
+#define FOUT_EPLL              5
+#define ARMCLK                 6
+#define HCLKX2                 7
+#define HCLK                   8
+#define PCLK                   9
+
+/* HCLK bus clocks. */
+#define HCLK_3DSE              16
+#define HCLK_UHOST             17
+#define HCLK_SECUR             18
+#define HCLK_SDMA1             19
+#define HCLK_SDMA0             20
+#define HCLK_IROM              21
+#define HCLK_DDR1              22
+#define HCLK_MEM1              23
+#define HCLK_MEM0              24
+#define HCLK_USB               25
+#define HCLK_HSMMC2            26
+#define HCLK_HSMMC1            27
+#define HCLK_HSMMC0            28
+#define HCLK_MDP               29
+#define HCLK_DHOST             30
+#define HCLK_IHOST             31
+#define HCLK_DMA1              32
+#define HCLK_DMA0              33
+#define HCLK_JPEG              34
+#define HCLK_CAMIF             35
+#define HCLK_SCALER            36
+#define HCLK_2D                        37
+#define HCLK_TV                        38
+#define HCLK_POST0             39
+#define HCLK_ROT               40
+#define HCLK_LCD               41
+#define HCLK_TZIC              42
+#define HCLK_INTC              43
+#define HCLK_MFC               44
+#define HCLK_DDR0              45
+
+/* PCLK bus clocks. */
+#define PCLK_IIC1              48
+#define PCLK_IIS2              49
+#define PCLK_SKEY              50
+#define PCLK_CHIPID            51
+#define PCLK_SPI1              52
+#define PCLK_SPI0              53
+#define PCLK_HSIRX             54
+#define PCLK_HSITX             55
+#define PCLK_GPIO              56
+#define PCLK_IIC0              57
+#define PCLK_IIS1              58
+#define PCLK_IIS0              59
+#define PCLK_AC97              60
+#define PCLK_TZPC              61
+#define PCLK_TSADC             62
+#define PCLK_KEYPAD            63
+#define PCLK_IRDA              64
+#define PCLK_PCM1              65
+#define PCLK_PCM0              66
+#define PCLK_PWM               67
+#define PCLK_RTC               68
+#define PCLK_WDT               69
+#define PCLK_UART3             70
+#define PCLK_UART2             71
+#define PCLK_UART1             72
+#define PCLK_UART0             73
+#define PCLK_MFC               74
+
+/* Special clocks. */
+#define SCLK_UHOST             80
+#define SCLK_MMC2_48           81
+#define SCLK_MMC1_48           82
+#define SCLK_MMC0_48           83
+#define SCLK_MMC2              84
+#define SCLK_MMC1              85
+#define SCLK_MMC0              86
+#define SCLK_SPI1_48           87
+#define SCLK_SPI0_48           88
+#define SCLK_SPI1              89
+#define SCLK_SPI0              90
+#define SCLK_DAC27             91
+#define SCLK_TV27              92
+#define SCLK_SCALER27          93
+#define SCLK_SCALER            94
+#define SCLK_LCD27             95
+#define SCLK_LCD               96
+#define SCLK_FIMC              97
+#define SCLK_POST0_27          98
+#define SCLK_AUDIO2            99
+#define SCLK_POST0             100
+#define SCLK_AUDIO1            101
+#define SCLK_AUDIO0            102
+#define SCLK_SECUR             103
+#define SCLK_IRDA              104
+#define SCLK_UART              105
+#define SCLK_MFC               106
+#define SCLK_CAM               107
+#define SCLK_JPEG              108
+#define SCLK_ONENAND           109
+
+/* MEM0 bus clocks - S3C6410-specific. */
+#define MEM0_CFCON             112
+#define MEM0_ONENAND1          113
+#define MEM0_ONENAND0          114
+#define MEM0_NFCON             115
+#define MEM0_SROM              116
+
+/* Muxes. */
+#define MOUT_APLL              128
+#define MOUT_MPLL              129
+#define MOUT_EPLL              130
+#define MOUT_MFC               131
+#define MOUT_AUDIO0            132
+#define MOUT_AUDIO1            133
+#define MOUT_UART              134
+#define MOUT_SPI0              135
+#define MOUT_SPI1              136
+#define MOUT_MMC0              137
+#define MOUT_MMC1              138
+#define MOUT_MMC2              139
+#define MOUT_UHOST             140
+#define MOUT_IRDA              141
+#define MOUT_LCD               142
+#define MOUT_SCALER            143
+#define MOUT_DAC27             144
+#define MOUT_TV27              145
+#define MOUT_AUDIO2            146
+
+/* Dividers. */
+#define DOUT_MPLL              160
+#define DOUT_SECUR             161
+#define DOUT_CAM               162
+#define DOUT_JPEG              163
+#define DOUT_MFC               164
+#define DOUT_MMC0              165
+#define DOUT_MMC1              166
+#define DOUT_MMC2              167
+#define DOUT_LCD               168
+#define DOUT_SCALER            169
+#define DOUT_UHOST             170
+#define DOUT_SPI0              171
+#define DOUT_SPI1              172
+#define DOUT_AUDIO0            173
+#define DOUT_AUDIO1            174
+#define DOUT_UART              175
+#define DOUT_IRDA              176
+#define DOUT_FIMC              177
+#define DOUT_AUDIO2            178
+
+/* Total number of clocks. */
+#define NR_CLKS                        (DOUT_AUDIO2 + 1)
+
+#endif /* _DT_BINDINGS_CLOCK_SAMSUNG_S3C64XX_CLOCK_H */
diff --git a/include/dt-bindings/input/input.h b/include/dt-bindings/input/input.h
new file mode 100644 (file)
index 0000000..042e7b3
--- /dev/null
@@ -0,0 +1,525 @@
+/*
+ * This header provides constants for most input bindings.
+ *
+ * Most input bindings include key code, matrix key code format.
+ * In most cases, key code and matrix key code format uses
+ * the standard values/macro defined in this header.
+ */
+
+#ifndef _DT_BINDINGS_INPUT_INPUT_H
+#define _DT_BINDINGS_INPUT_INPUT_H
+
+#define KEY_RESERVED           0
+#define KEY_ESC                        1
+#define KEY_1                  2
+#define KEY_2                  3
+#define KEY_3                  4
+#define KEY_4                  5
+#define KEY_5                  6
+#define KEY_6                  7
+#define KEY_7                  8
+#define KEY_8                  9
+#define KEY_9                  10
+#define KEY_0                  11
+#define KEY_MINUS              12
+#define KEY_EQUAL              13
+#define KEY_BACKSPACE          14
+#define KEY_TAB                        15
+#define KEY_Q                  16
+#define KEY_W                  17
+#define KEY_E                  18
+#define KEY_R                  19
+#define KEY_T                  20
+#define KEY_Y                  21
+#define KEY_U                  22
+#define KEY_I                  23
+#define KEY_O                  24
+#define KEY_P                  25
+#define KEY_LEFTBRACE          26
+#define KEY_RIGHTBRACE         27
+#define KEY_ENTER              28
+#define KEY_LEFTCTRL           29
+#define KEY_A                  30
+#define KEY_S                  31
+#define KEY_D                  32
+#define KEY_F                  33
+#define KEY_G                  34
+#define KEY_H                  35
+#define KEY_J                  36
+#define KEY_K                  37
+#define KEY_L                  38
+#define KEY_SEMICOLON          39
+#define KEY_APOSTROPHE         40
+#define KEY_GRAVE              41
+#define KEY_LEFTSHIFT          42
+#define KEY_BACKSLASH          43
+#define KEY_Z                  44
+#define KEY_X                  45
+#define KEY_C                  46
+#define KEY_V                  47
+#define KEY_B                  48
+#define KEY_N                  49
+#define KEY_M                  50
+#define KEY_COMMA              51
+#define KEY_DOT                        52
+#define KEY_SLASH              53
+#define KEY_RIGHTSHIFT         54
+#define KEY_KPASTERISK         55
+#define KEY_LEFTALT            56
+#define KEY_SPACE              57
+#define KEY_CAPSLOCK           58
+#define KEY_F1                 59
+#define KEY_F2                 60
+#define KEY_F3                 61
+#define KEY_F4                 62
+#define KEY_F5                 63
+#define KEY_F6                 64
+#define KEY_F7                 65
+#define KEY_F8                 66
+#define KEY_F9                 67
+#define KEY_F10                        68
+#define KEY_NUMLOCK            69
+#define KEY_SCROLLLOCK         70
+#define KEY_KP7                        71
+#define KEY_KP8                        72
+#define KEY_KP9                        73
+#define KEY_KPMINUS            74
+#define KEY_KP4                        75
+#define KEY_KP5                        76
+#define KEY_KP6                        77
+#define KEY_KPPLUS             78
+#define KEY_KP1                        79
+#define KEY_KP2                        80
+#define KEY_KP3                        81
+#define KEY_KP0                        82
+#define KEY_KPDOT              83
+
+#define KEY_ZENKAKUHANKAKU     85
+#define KEY_102ND              86
+#define KEY_F11                        87
+#define KEY_F12                        88
+#define KEY_RO                 89
+#define KEY_KATAKANA           90
+#define KEY_HIRAGANA           91
+#define KEY_HENKAN             92
+#define KEY_KATAKANAHIRAGANA   93
+#define KEY_MUHENKAN           94
+#define KEY_KPJPCOMMA          95
+#define KEY_KPENTER            96
+#define KEY_RIGHTCTRL          97
+#define KEY_KPSLASH            98
+#define KEY_SYSRQ              99
+#define KEY_RIGHTALT           100
+#define KEY_LINEFEED           101
+#define KEY_HOME               102
+#define KEY_UP                 103
+#define KEY_PAGEUP             104
+#define KEY_LEFT               105
+#define KEY_RIGHT              106
+#define KEY_END                        107
+#define KEY_DOWN               108
+#define KEY_PAGEDOWN           109
+#define KEY_INSERT             110
+#define KEY_DELETE             111
+#define KEY_MACRO              112
+#define KEY_MUTE               113
+#define KEY_VOLUMEDOWN         114
+#define KEY_VOLUMEUP           115
+#define KEY_POWER              116     /* SC System Power Down */
+#define KEY_KPEQUAL            117
+#define KEY_KPPLUSMINUS                118
+#define KEY_PAUSE              119
+#define KEY_SCALE              120     /* AL Compiz Scale (Expose) */
+
+#define KEY_KPCOMMA            121
+#define KEY_HANGEUL            122
+#define KEY_HANGUEL            KEY_HANGEUL
+#define KEY_HANJA              123
+#define KEY_YEN                        124
+#define KEY_LEFTMETA           125
+#define KEY_RIGHTMETA          126
+#define KEY_COMPOSE            127
+
+#define KEY_STOP               128     /* AC Stop */
+#define KEY_AGAIN              129
+#define KEY_PROPS              130     /* AC Properties */
+#define KEY_UNDO               131     /* AC Undo */
+#define KEY_FRONT              132
+#define KEY_COPY               133     /* AC Copy */
+#define KEY_OPEN               134     /* AC Open */
+#define KEY_PASTE              135     /* AC Paste */
+#define KEY_FIND               136     /* AC Search */
+#define KEY_CUT                        137     /* AC Cut */
+#define KEY_HELP               138     /* AL Integrated Help Center */
+#define KEY_MENU               139     /* Menu (show menu) */
+#define KEY_CALC               140     /* AL Calculator */
+#define KEY_SETUP              141
+#define KEY_SLEEP              142     /* SC System Sleep */
+#define KEY_WAKEUP             143     /* System Wake Up */
+#define KEY_FILE               144     /* AL Local Machine Browser */
+#define KEY_SENDFILE           145
+#define KEY_DELETEFILE         146
+#define KEY_XFER               147
+#define KEY_PROG1              148
+#define KEY_PROG2              149
+#define KEY_WWW                        150     /* AL Internet Browser */
+#define KEY_MSDOS              151
+#define KEY_COFFEE             152     /* AL Terminal Lock/Screensaver */
+#define KEY_SCREENLOCK         KEY_COFFEE
+#define KEY_DIRECTION          153
+#define KEY_CYCLEWINDOWS       154
+#define KEY_MAIL               155
+#define KEY_BOOKMARKS          156     /* AC Bookmarks */
+#define KEY_COMPUTER           157
+#define KEY_BACK               158     /* AC Back */
+#define KEY_FORWARD            159     /* AC Forward */
+#define KEY_CLOSECD            160
+#define KEY_EJECTCD            161
+#define KEY_EJECTCLOSECD       162
+#define KEY_NEXTSONG           163
+#define KEY_PLAYPAUSE          164
+#define KEY_PREVIOUSSONG       165
+#define KEY_STOPCD             166
+#define KEY_RECORD             167
+#define KEY_REWIND             168
+#define KEY_PHONE              169     /* Media Select Telephone */
+#define KEY_ISO                        170
+#define KEY_CONFIG             171     /* AL Consumer Control Configuration */
+#define KEY_HOMEPAGE           172     /* AC Home */
+#define KEY_REFRESH            173     /* AC Refresh */
+#define KEY_EXIT               174     /* AC Exit */
+#define KEY_MOVE               175
+#define KEY_EDIT               176
+#define KEY_SCROLLUP           177
+#define KEY_SCROLLDOWN         178
+#define KEY_KPLEFTPAREN                179
+#define KEY_KPRIGHTPAREN       180
+#define KEY_NEW                        181     /* AC New */
+#define KEY_REDO               182     /* AC Redo/Repeat */
+
+#define KEY_F13                        183
+#define KEY_F14                        184
+#define KEY_F15                        185
+#define KEY_F16                        186
+#define KEY_F17                        187
+#define KEY_F18                        188
+#define KEY_F19                        189
+#define KEY_F20                        190
+#define KEY_F21                        191
+#define KEY_F22                        192
+#define KEY_F23                        193
+#define KEY_F24                        194
+
+#define KEY_PLAYCD             200
+#define KEY_PAUSECD            201
+#define KEY_PROG3              202
+#define KEY_PROG4              203
+#define KEY_DASHBOARD          204     /* AL Dashboard */
+#define KEY_SUSPEND            205
+#define KEY_CLOSE              206     /* AC Close */
+#define KEY_PLAY               207
+#define KEY_FASTFORWARD                208
+#define KEY_BASSBOOST          209
+#define KEY_PRINT              210     /* AC Print */
+#define KEY_HP                 211
+#define KEY_CAMERA             212
+#define KEY_SOUND              213
+#define KEY_QUESTION           214
+#define KEY_EMAIL              215
+#define KEY_CHAT               216
+#define KEY_SEARCH             217
+#define KEY_CONNECT            218
+#define KEY_FINANCE            219     /* AL Checkbook/Finance */
+#define KEY_SPORT              220
+#define KEY_SHOP               221
+#define KEY_ALTERASE           222
+#define KEY_CANCEL             223     /* AC Cancel */
+#define KEY_BRIGHTNESSDOWN     224
+#define KEY_BRIGHTNESSUP       225
+#define KEY_MEDIA              226
+
+#define KEY_SWITCHVIDEOMODE    227     /* Cycle between available video
+                                          outputs (Monitor/LCD/TV-out/etc) */
+#define KEY_KBDILLUMTOGGLE     228
+#define KEY_KBDILLUMDOWN       229
+#define KEY_KBDILLUMUP         230
+
+#define KEY_SEND               231     /* AC Send */
+#define KEY_REPLY              232     /* AC Reply */
+#define KEY_FORWARDMAIL                233     /* AC Forward Msg */
+#define KEY_SAVE               234     /* AC Save */
+#define KEY_DOCUMENTS          235
+
+#define KEY_BATTERY            236
+
+#define KEY_BLUETOOTH          237
+#define KEY_WLAN               238
+#define KEY_UWB                        239
+
+#define KEY_UNKNOWN            240
+
+#define KEY_VIDEO_NEXT         241     /* drive next video source */
+#define KEY_VIDEO_PREV         242     /* drive previous video source */
+#define KEY_BRIGHTNESS_CYCLE   243     /* brightness up, after max is min */
+#define KEY_BRIGHTNESS_ZERO    244     /* brightness off, use ambient */
+#define KEY_DISPLAY_OFF                245     /* display device to off state */
+
+#define KEY_WIMAX              246
+#define KEY_RFKILL             247     /* Key that controls all radios */
+
+#define KEY_MICMUTE            248     /* Mute / unmute the microphone */
+
+/* Code 255 is reserved for special needs of AT keyboard driver */
+
+#define BTN_MISC               0x100
+#define BTN_0                  0x100
+#define BTN_1                  0x101
+#define BTN_2                  0x102
+#define BTN_3                  0x103
+#define BTN_4                  0x104
+#define BTN_5                  0x105
+#define BTN_6                  0x106
+#define BTN_7                  0x107
+#define BTN_8                  0x108
+#define BTN_9                  0x109
+
+#define BTN_MOUSE              0x110
+#define BTN_LEFT               0x110
+#define BTN_RIGHT              0x111
+#define BTN_MIDDLE             0x112
+#define BTN_SIDE               0x113
+#define BTN_EXTRA              0x114
+#define BTN_FORWARD            0x115
+#define BTN_BACK               0x116
+#define BTN_TASK               0x117
+
+#define BTN_JOYSTICK           0x120
+#define BTN_TRIGGER            0x120
+#define BTN_THUMB              0x121
+#define BTN_THUMB2             0x122
+#define BTN_TOP                        0x123
+#define BTN_TOP2               0x124
+#define BTN_PINKIE             0x125
+#define BTN_BASE               0x126
+#define BTN_BASE2              0x127
+#define BTN_BASE3              0x128
+#define BTN_BASE4              0x129
+#define BTN_BASE5              0x12a
+#define BTN_BASE6              0x12b
+#define BTN_DEAD               0x12f
+
+#define BTN_GAMEPAD            0x130
+#define BTN_SOUTH              0x130
+#define BTN_A                  BTN_SOUTH
+#define BTN_EAST               0x131
+#define BTN_B                  BTN_EAST
+#define BTN_C                  0x132
+#define BTN_NORTH              0x133
+#define BTN_X                  BTN_NORTH
+#define BTN_WEST               0x134
+#define BTN_Y                  BTN_WEST
+#define BTN_Z                  0x135
+#define BTN_TL                 0x136
+#define BTN_TR                 0x137
+#define BTN_TL2                        0x138
+#define BTN_TR2                        0x139
+#define BTN_SELECT             0x13a
+#define BTN_START              0x13b
+#define BTN_MODE               0x13c
+#define BTN_THUMBL             0x13d
+#define BTN_THUMBR             0x13e
+
+#define BTN_DIGI               0x140
+#define BTN_TOOL_PEN           0x140
+#define BTN_TOOL_RUBBER                0x141
+#define BTN_TOOL_BRUSH         0x142
+#define BTN_TOOL_PENCIL                0x143
+#define BTN_TOOL_AIRBRUSH      0x144
+#define BTN_TOOL_FINGER                0x145
+#define BTN_TOOL_MOUSE         0x146
+#define BTN_TOOL_LENS          0x147
+#define BTN_TOOL_QUINTTAP      0x148   /* Five fingers on trackpad */
+#define BTN_TOUCH              0x14a
+#define BTN_STYLUS             0x14b
+#define BTN_STYLUS2            0x14c
+#define BTN_TOOL_DOUBLETAP     0x14d
+#define BTN_TOOL_TRIPLETAP     0x14e
+#define BTN_TOOL_QUADTAP       0x14f   /* Four fingers on trackpad */
+
+#define BTN_WHEEL              0x150
+#define BTN_GEAR_DOWN          0x150
+#define BTN_GEAR_UP            0x151
+
+#define KEY_OK                 0x160
+#define KEY_SELECT             0x161
+#define KEY_GOTO               0x162
+#define KEY_CLEAR              0x163
+#define KEY_POWER2             0x164
+#define KEY_OPTION             0x165
+#define KEY_INFO               0x166   /* AL OEM Features/Tips/Tutorial */
+#define KEY_TIME               0x167
+#define KEY_VENDOR             0x168
+#define KEY_ARCHIVE            0x169
+#define KEY_PROGRAM            0x16a   /* Media Select Program Guide */
+#define KEY_CHANNEL            0x16b
+#define KEY_FAVORITES          0x16c
+#define KEY_EPG                        0x16d
+#define KEY_PVR                        0x16e   /* Media Select Home */
+#define KEY_MHP                        0x16f
+#define KEY_LANGUAGE           0x170
+#define KEY_TITLE              0x171
+#define KEY_SUBTITLE           0x172
+#define KEY_ANGLE              0x173
+#define KEY_ZOOM               0x174
+#define KEY_MODE               0x175
+#define KEY_KEYBOARD           0x176
+#define KEY_SCREEN             0x177
+#define KEY_PC                 0x178   /* Media Select Computer */
+#define KEY_TV                 0x179   /* Media Select TV */
+#define KEY_TV2                        0x17a   /* Media Select Cable */
+#define KEY_VCR                        0x17b   /* Media Select VCR */
+#define KEY_VCR2               0x17c   /* VCR Plus */
+#define KEY_SAT                        0x17d   /* Media Select Satellite */
+#define KEY_SAT2               0x17e
+#define KEY_CD                 0x17f   /* Media Select CD */
+#define KEY_TAPE               0x180   /* Media Select Tape */
+#define KEY_RADIO              0x181
+#define KEY_TUNER              0x182   /* Media Select Tuner */
+#define KEY_PLAYER             0x183
+#define KEY_TEXT               0x184
+#define KEY_DVD                        0x185   /* Media Select DVD */
+#define KEY_AUX                        0x186
+#define KEY_MP3                        0x187
+#define KEY_AUDIO              0x188   /* AL Audio Browser */
+#define KEY_VIDEO              0x189   /* AL Movie Browser */
+#define KEY_DIRECTORY          0x18a
+#define KEY_LIST               0x18b
+#define KEY_MEMO               0x18c   /* Media Select Messages */
+#define KEY_CALENDAR           0x18d
+#define KEY_RED                        0x18e
+#define KEY_GREEN              0x18f
+#define KEY_YELLOW             0x190
+#define KEY_BLUE               0x191
+#define KEY_CHANNELUP          0x192   /* Channel Increment */
+#define KEY_CHANNELDOWN                0x193   /* Channel Decrement */
+#define KEY_FIRST              0x194
+#define KEY_LAST               0x195   /* Recall Last */
+#define KEY_AB                 0x196
+#define KEY_NEXT               0x197
+#define KEY_RESTART            0x198
+#define KEY_SLOW               0x199
+#define KEY_SHUFFLE            0x19a
+#define KEY_BREAK              0x19b
+#define KEY_PREVIOUS           0x19c
+#define KEY_DIGITS             0x19d
+#define KEY_TEEN               0x19e
+#define KEY_TWEN               0x19f
+#define KEY_VIDEOPHONE         0x1a0   /* Media Select Video Phone */
+#define KEY_GAMES              0x1a1   /* Media Select Games */
+#define KEY_ZOOMIN             0x1a2   /* AC Zoom In */
+#define KEY_ZOOMOUT            0x1a3   /* AC Zoom Out */
+#define KEY_ZOOMRESET          0x1a4   /* AC Zoom */
+#define KEY_WORDPROCESSOR      0x1a5   /* AL Word Processor */
+#define KEY_EDITOR             0x1a6   /* AL Text Editor */
+#define KEY_SPREADSHEET                0x1a7   /* AL Spreadsheet */
+#define KEY_GRAPHICSEDITOR     0x1a8   /* AL Graphics Editor */
+#define KEY_PRESENTATION       0x1a9   /* AL Presentation App */
+#define KEY_DATABASE           0x1aa   /* AL Database App */
+#define KEY_NEWS               0x1ab   /* AL Newsreader */
+#define KEY_VOICEMAIL          0x1ac   /* AL Voicemail */
+#define KEY_ADDRESSBOOK                0x1ad   /* AL Contacts/Address Book */
+#define KEY_MESSENGER          0x1ae   /* AL Instant Messaging */
+#define KEY_DISPLAYTOGGLE      0x1af   /* Turn display (LCD) on and off */
+#define KEY_SPELLCHECK         0x1b0   /* AL Spell Check */
+#define KEY_LOGOFF             0x1b1   /* AL Logoff */
+
+#define KEY_DOLLAR             0x1b2
+#define KEY_EURO               0x1b3
+
+#define KEY_FRAMEBACK          0x1b4   /* Consumer - transport controls */
+#define KEY_FRAMEFORWARD       0x1b5
+#define KEY_CONTEXT_MENU       0x1b6   /* GenDesc - system context menu */
+#define KEY_MEDIA_REPEAT       0x1b7   /* Consumer - transport control */
+#define KEY_10CHANNELSUP       0x1b8   /* 10 channels up (10+) */
+#define KEY_10CHANNELSDOWN     0x1b9   /* 10 channels down (10-) */
+#define KEY_IMAGES             0x1ba   /* AL Image Browser */
+
+#define KEY_DEL_EOL            0x1c0
+#define KEY_DEL_EOS            0x1c1
+#define KEY_INS_LINE           0x1c2
+#define KEY_DEL_LINE           0x1c3
+
+#define KEY_FN                 0x1d0
+#define KEY_FN_ESC             0x1d1
+#define KEY_FN_F1              0x1d2
+#define KEY_FN_F2              0x1d3
+#define KEY_FN_F3              0x1d4
+#define KEY_FN_F4              0x1d5
+#define KEY_FN_F5              0x1d6
+#define KEY_FN_F6              0x1d7
+#define KEY_FN_F7              0x1d8
+#define KEY_FN_F8              0x1d9
+#define KEY_FN_F9              0x1da
+#define KEY_FN_F10             0x1db
+#define KEY_FN_F11             0x1dc
+#define KEY_FN_F12             0x1dd
+#define KEY_FN_1               0x1de
+#define KEY_FN_2               0x1df
+#define KEY_FN_D               0x1e0
+#define KEY_FN_E               0x1e1
+#define KEY_FN_F               0x1e2
+#define KEY_FN_S               0x1e3
+#define KEY_FN_B               0x1e4
+
+#define KEY_BRL_DOT1           0x1f1
+#define KEY_BRL_DOT2           0x1f2
+#define KEY_BRL_DOT3           0x1f3
+#define KEY_BRL_DOT4           0x1f4
+#define KEY_BRL_DOT5           0x1f5
+#define KEY_BRL_DOT6           0x1f6
+#define KEY_BRL_DOT7           0x1f7
+#define KEY_BRL_DOT8           0x1f8
+#define KEY_BRL_DOT9           0x1f9
+#define KEY_BRL_DOT10          0x1fa
+
+#define KEY_NUMERIC_0          0x200   /* used by phones, remote controls, */
+#define KEY_NUMERIC_1          0x201   /* and other keypads */
+#define KEY_NUMERIC_2          0x202
+#define KEY_NUMERIC_3          0x203
+#define KEY_NUMERIC_4          0x204
+#define KEY_NUMERIC_5          0x205
+#define KEY_NUMERIC_6          0x206
+#define KEY_NUMERIC_7          0x207
+#define KEY_NUMERIC_8          0x208
+#define KEY_NUMERIC_9          0x209
+#define KEY_NUMERIC_STAR       0x20a
+#define KEY_NUMERIC_POUND      0x20b
+
+#define KEY_CAMERA_FOCUS       0x210
+#define KEY_WPS_BUTTON         0x211   /* WiFi Protected Setup key */
+
+#define KEY_TOUCHPAD_TOGGLE    0x212   /* Request switch touchpad on or off */
+#define KEY_TOUCHPAD_ON                0x213
+#define KEY_TOUCHPAD_OFF       0x214
+
+#define KEY_CAMERA_ZOOMIN      0x215
+#define KEY_CAMERA_ZOOMOUT     0x216
+#define KEY_CAMERA_UP          0x217
+#define KEY_CAMERA_DOWN                0x218
+#define KEY_CAMERA_LEFT                0x219
+#define KEY_CAMERA_RIGHT       0x21a
+
+#define KEY_ATTENDANT_ON       0x21b
+#define KEY_ATTENDANT_OFF      0x21c
+#define KEY_ATTENDANT_TOGGLE   0x21d   /* Attendant call on or off */
+#define KEY_LIGHTS_TOGGLE      0x21e   /* Reading light on or off */
+
+#define BTN_DPAD_UP            0x220
+#define BTN_DPAD_DOWN          0x221
+#define BTN_DPAD_LEFT          0x222
+#define BTN_DPAD_RIGHT         0x223
+
+#define MATRIX_KEY(row, col, code)     \
+       ((((row) & 0xFF) << 24) | (((col) & 0xFF) << 16) | ((code) & 0xFFFF))
+
+#endif /* _DT_BINDINGS_INPUT_INPUT_H */
index 1bdf965339f9bef4222a5bc739efc0b23807e35e..d9c92daa3944e43a13f285a7baaa1443868cce3d 100644 (file)
@@ -27,15 +27,13 @@ struct kiocb;
  */
 #define KIOCB_CANCELLED                ((void *) (~0ULL))
 
-typedef int (kiocb_cancel_fn)(struct kiocb *, struct io_event *);
+typedef int (kiocb_cancel_fn)(struct kiocb *);
 
 struct kiocb {
-       atomic_t                ki_users;
-
        struct file             *ki_filp;
        struct kioctx           *ki_ctx;        /* NULL for sync ops */
        kiocb_cancel_fn         *ki_cancel;
-       void                    (*ki_dtor)(struct kiocb *);
+       void                    *private;
 
        union {
                void __user             *user;
@@ -44,17 +42,7 @@ struct kiocb {
 
        __u64                   ki_user_data;   /* user's data for completion */
        loff_t                  ki_pos;
-
-       void                    *private;
-       /* State that we remember to be able to restart/retry  */
-       unsigned short          ki_opcode;
-       size_t                  ki_nbytes;      /* copy of iocb->aio_nbytes */
-       char                    __user *ki_buf; /* remaining iocb->aio_buf */
-       size_t                  ki_left;        /* remaining bytes */
-       struct iovec            ki_inline_vec;  /* inline vector */
-       struct iovec            *ki_iovec;
-       unsigned long           ki_nr_segs;
-       unsigned long           ki_cur_seg;
+       size_t                  ki_nbytes;      /* copy of iocb->aio_nbytes */
 
        struct list_head        ki_list;        /* the aio core uses this
                                                 * for cancellation */
@@ -74,7 +62,6 @@ static inline bool is_sync_kiocb(struct kiocb *kiocb)
 static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
 {
        *kiocb = (struct kiocb) {
-                       .ki_users = ATOMIC_INIT(1),
                        .ki_ctx = NULL,
                        .ki_filp = filp,
                        .ki_obj.tsk = current,
@@ -84,7 +71,6 @@ static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp)
 /* prototypes */
 #ifdef CONFIG_AIO
 extern ssize_t wait_on_sync_kiocb(struct kiocb *iocb);
-extern void aio_put_req(struct kiocb *iocb);
 extern void aio_complete(struct kiocb *iocb, long res, long res2);
 struct mm_struct;
 extern void exit_aio(struct mm_struct *mm);
@@ -93,7 +79,6 @@ extern long do_io_submit(aio_context_t ctx_id, long nr,
 void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel);
 #else
 static inline ssize_t wait_on_sync_kiocb(struct kiocb *iocb) { return 0; }
-static inline void aio_put_req(struct kiocb *iocb) { }
 static inline void aio_complete(struct kiocb *iocb, long res, long res2) { }
 struct mm_struct;
 static inline void exit_aio(struct mm_struct *mm) { }
index 3e7b62fbefbd28cf7992089b0f6068a7b741e97d..91b84a7f053933089e63224aea1f616809b8af57 100644 (file)
@@ -87,6 +87,7 @@
 #define PL080_CONTROL_SB_SIZE_MASK             (0x7 << 12)
 #define PL080_CONTROL_SB_SIZE_SHIFT            (12)
 #define PL080_CONTROL_TRANSFER_SIZE_MASK       (0xfff << 0)
+#define PL080S_CONTROL_TRANSFER_SIZE_MASK      (0x1ffffff << 0)
 #define PL080_CONTROL_TRANSFER_SIZE_SHIFT      (0)
 
 #define PL080_BSIZE_1                          (0x0)
index 8013a45242fe37df8b07d8970e14f3ab05d570da..cf573c22b81ef4b1b1e602244119808f86f65871 100644 (file)
@@ -13,6 +13,9 @@ struct file_operations;
 struct file *anon_inode_getfile(const char *name,
                                const struct file_operations *fops,
                                void *priv, int flags);
+struct file *anon_inode_getfile_private(const char *name,
+                               const struct file_operations *fops,
+                               void *priv, int flags);
 int anon_inode_getfd(const char *name, const struct file_operations *fops,
                     void *priv, int flags);
 
index c3881553f7d15ef029323e49bcbc9e48365eb5db..5f66d519a72640b3c9b874625de9b79808724226 100644 (file)
@@ -243,6 +243,8 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
  * BDI_CAP_EXEC_MAP:       Can be mapped for execution
  *
  * BDI_CAP_SWAP_BACKED:    Count shmem/tmpfs objects as swap-backed.
+ *
+ * BDI_CAP_STRICTLIMIT:    Keep number of dirty pages below bdi threshold.
  */
 #define BDI_CAP_NO_ACCT_DIRTY  0x00000001
 #define BDI_CAP_NO_WRITEBACK   0x00000002
@@ -254,6 +256,7 @@ int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
 #define BDI_CAP_NO_ACCT_WB     0x00000080
 #define BDI_CAP_SWAP_BACKED    0x00000100
 #define BDI_CAP_STABLE_WRITES  0x00000200
+#define BDI_CAP_STRICTLIMIT    0x00000400
 
 #define BDI_CAP_VMFLAGS \
        (BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP)
index 70cf138690e9184678b1dea1aa9a23dd1a10a487..e8112ae5053131c47a1e472985fc1628ddd5e8eb 100644 (file)
@@ -31,7 +31,7 @@ struct linux_binprm {
 #ifdef __alpha__
        unsigned int taso:1;
 #endif
-       unsigned int recursion_depth;
+       unsigned int recursion_depth; /* only for search_binary_handler() */
        struct file * file;
        struct cred *cred;      /* new credentials */
        int unsafe;             /* how unsafe this exec is (mask of LSM_UNSAFE_*) */
index ce6df39f60ff6f966144855ca0e1bdb04c312903..8f47625a06615dbf5cbc79ef5df2e2fd5cee6041 100644 (file)
@@ -335,6 +335,8 @@ extern int ceph_osdc_wait_request(struct ceph_osd_client *osdc,
                                  struct ceph_osd_request *req);
 extern void ceph_osdc_sync(struct ceph_osd_client *osdc);
 
+extern void ceph_osdc_flush_notifies(struct ceph_osd_client *osdc);
+
 extern int ceph_osdc_readpages(struct ceph_osd_client *osdc,
                               struct ceph_vino vino,
                               struct ceph_file_layout *layout,
index dd7adff76e81fef6e2cc9fa8b2d18ac3c52bc174..8138c94409f3f3d1253c2b83e62c3f131ff70d84 100644 (file)
@@ -33,8 +33,11 @@ struct clk {
        const char              **parent_names;
        struct clk              **parents;
        u8                      num_parents;
+       u8                      new_parent_index;
        unsigned long           rate;
        unsigned long           new_rate;
+       struct clk              *new_parent;
+       struct clk              *new_child;
        unsigned long           flags;
        unsigned int            enable_count;
        unsigned int            prepare_count;
index 1ec14a73217654308fa20bd18e3ec913d668274f..73bdb69f0c08150a64ac2cd4cd5bf1cca3c3ac6a 100644 (file)
@@ -12,6 +12,7 @@
 #define __LINUX_CLK_PROVIDER_H
 
 #include <linux/clk.h>
+#include <linux/io.h>
 
 #ifdef CONFIG_COMMON_CLK
 
@@ -27,6 +28,7 @@
 #define CLK_IS_ROOT            BIT(4) /* root clk, has no parent */
 #define CLK_IS_BASIC           BIT(5) /* Basic clk, can't do a to_clk_foo() */
 #define CLK_GET_RATE_NOCACHE   BIT(6) /* do not use the cached clk rate */
+#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
 
 struct clk_hw;
 
@@ -79,6 +81,10 @@ struct clk_hw;
  * @round_rate:        Given a target rate as input, returns the closest rate actually
  *             supported by the clock.
  *
+ * @determine_rate: Given a target rate as input, returns the closest rate
+ *             actually supported by the clock, and optionally the parent clock
+ *             that should be used to provide the clock rate.
+ *
  * @get_parent:        Queries the hardware to determine the parent of a clock.  The
  *             return value is a u8 which specifies the index corresponding to
  *             the parent clock.  This index can be applied to either the
@@ -126,6 +132,9 @@ struct clk_ops {
                                        unsigned long parent_rate);
        long            (*round_rate)(struct clk_hw *hw, unsigned long,
                                        unsigned long *);
+       long            (*determine_rate)(struct clk_hw *hw, unsigned long rate,
+                                       unsigned long *best_parent_rate,
+                                       struct clk **best_parent_clk);
        int             (*set_parent)(struct clk_hw *hw, u8 index);
        u8              (*get_parent)(struct clk_hw *hw);
        int             (*set_rate)(struct clk_hw *hw, unsigned long,
@@ -327,8 +336,10 @@ struct clk_mux {
 #define CLK_MUX_INDEX_ONE              BIT(0)
 #define CLK_MUX_INDEX_BIT              BIT(1)
 #define CLK_MUX_HIWORD_MASK            BIT(2)
+#define CLK_MUX_READ_ONLY      BIT(3) /* mux setting cannot be changed */
 
 extern const struct clk_ops clk_mux_ops;
+extern const struct clk_ops clk_mux_ro_ops;
 
 struct clk *clk_register_mux(struct device *dev, const char *name,
                const char **parent_names, u8 num_parents, unsigned long flags,
@@ -418,6 +429,7 @@ const char *__clk_get_name(struct clk *clk);
 struct clk_hw *__clk_get_hw(struct clk *clk);
 u8 __clk_get_num_parents(struct clk *clk);
 struct clk *__clk_get_parent(struct clk *clk);
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index);
 unsigned int __clk_get_enable_count(struct clk *clk);
 unsigned int __clk_get_prepare_count(struct clk *clk);
 unsigned long __clk_get_rate(struct clk *clk);
@@ -425,6 +437,9 @@ unsigned long __clk_get_flags(struct clk *clk);
 bool __clk_is_prepared(struct clk *clk);
 bool __clk_is_enabled(struct clk *clk);
 struct clk *__clk_lookup(const char *name);
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+                             unsigned long *best_parent_rate,
+                             struct clk **best_parent_p);
 
 /*
  * FIXME clock api without lock protection
@@ -490,5 +505,21 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
 #define of_clk_init(matches) \
        { while (0); }
 #endif /* CONFIG_OF */
+
+/*
+ * wrap access to peripherals in accessor routines
+ * for improved portability across platforms
+ */
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return readl(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       writel(val, reg);
+}
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
diff --git a/include/linux/cmdline-parser.h b/include/linux/cmdline-parser.h
new file mode 100644 (file)
index 0000000..98e892e
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Parsing command line, get the partitions information.
+ *
+ * Written by Cai Zhiyong <caizhiyong@huawei.com>
+ *
+ */
+#ifndef CMDLINEPARSEH
+#define CMDLINEPARSEH
+
+#include <linux/blkdev.h>
+
+/* partition flags */
+#define PF_RDONLY                   0x01 /* Device is read only */
+#define PF_POWERUP_LOCK             0x02 /* Always locked after reset */
+
+struct cmdline_subpart {
+       char name[BDEVNAME_SIZE]; /* partition name, such as 'rootfs' */
+       sector_t from;
+       sector_t size;
+       int flags;
+       struct cmdline_subpart *next_subpart;
+};
+
+struct cmdline_parts {
+       char name[BDEVNAME_SIZE]; /* block device, such as 'mmcblk0' */
+       unsigned int nr_subparts;
+       struct cmdline_subpart *subpart;
+       struct cmdline_parts *next_parts;
+};
+
+void cmdline_parts_free(struct cmdline_parts **parts);
+
+int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline);
+
+struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
+                                        const char *bdev);
+
+void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
+                      int slot,
+                      int (*add_part)(int, struct cmdline_subpart *, void *),
+                      void *param);
+
+#endif /* CMDLINEPARSEH */
index ec1aee4aec9ca4b205c1d677623088d65e19f8f3..345da00a86e07c0c5cd5cf7de50c5155c5a758d5 100644 (file)
@@ -43,6 +43,7 @@
 #define COMPAT_SYSCALL_DEFINEx(x, name, ...)                           \
        asmlinkage long compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
        static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
+       asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));\
        asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))\
        {                                                               \
                return C_SYSC##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__)); \
index 1739510d89943df23f193d5fb04332f47cdaf958..bdd18caa6c9473f4e9600a6cc5753aaa20523628 100644 (file)
@@ -52,8 +52,6 @@ static inline void *cpu_rmap_lookup_obj(struct cpu_rmap *rmap, unsigned int cpu)
        return rmap->obj[rmap->near[cpu].index];
 }
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-
 /**
  * alloc_irq_cpu_rmap - allocate CPU affinity reverse-map for IRQs
  * @size: Number of objects to be mapped
@@ -68,5 +66,4 @@ extern void free_irq_cpu_rmap(struct cpu_rmap *rmap);
 
 extern int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq);
 
-#endif
 #endif /* __LINUX_CPU_RMAP_H */
index d568f3975eeb66125a28aa8a31ccbb712de56807..fcabc42d66ab413a38730cb78d8eedc9bda91084 100644 (file)
@@ -85,7 +85,6 @@ struct cpufreq_policy {
        struct list_head        policy_list;
        struct kobject          kobj;
        struct completion       kobj_unregister;
-       int                     transition_ongoing; /* Tracks transition status */
 };
 
 /* Only for ACPI */
index 37e4f8da7cdf81deefacf7d7b19175e98d2063a6..fe68a5a985831eca65d3880fb69094fbb91dbde0 100644 (file)
 extern unsigned long long elfcorehdr_addr;
 extern unsigned long long elfcorehdr_size;
 
+extern int __weak elfcorehdr_alloc(unsigned long long *addr,
+                                  unsigned long long *size);
+extern void __weak elfcorehdr_free(unsigned long long addr);
+extern ssize_t __weak elfcorehdr_read(char *buf, size_t count, u64 *ppos);
+extern ssize_t __weak elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos);
+extern int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma,
+                                        unsigned long from, unsigned long pfn,
+                                        unsigned long size, pgprot_t prot);
+
 extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
                                                unsigned long, int);
 
index fe50f3db3af9f125cc7c5aa25effa0f1eae06d3a..59066e0b4ff134fde5679d582246e942df9f86fc 100644 (file)
@@ -55,11 +55,11 @@ struct qstr {
 #define hashlen_len(hashlen)  ((u32)((hashlen) >> 32))
 
 struct dentry_stat_t {
-       int nr_dentry;
-       int nr_unused;
-       int age_limit;          /* age in seconds */
-       int want_pages;         /* pages requested by system */
-       int dummy[2];
+       long nr_dentry;
+       long nr_unused;
+       long age_limit;          /* age in seconds */
+       long want_pages;         /* pages requested by system */
+       long dummy[2];
 };
 extern struct dentry_stat_t dentry_stat;
 
@@ -208,6 +208,7 @@ struct dentry_operations {
 #define DCACHE_MANAGED_DENTRY \
        (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT)
 
+#define DCACHE_LRU_LIST                0x80000
 #define DCACHE_DENTRY_KILLED   0x100000
 
 extern seqlock_t rename_lock;
@@ -394,4 +395,8 @@ static inline bool d_mountpoint(const struct dentry *dentry)
 
 extern int sysctl_vfs_cache_pressure;
 
+static inline unsigned long vfs_pressure_ratio(unsigned long val)
+{
+       return mult_frac(val, sysctl_vfs_cache_pressure, 100);
+}
 #endif /* __LINUX_DCACHE_H */
index e151d4c9298d858eca5a3ccd5594da1aebe20596..653073de09e379ef1c8b04c1a96d0ef2c948f5a3 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/bio.h>
 #include <linux/blkdev.h>
+#include <linux/math64.h>
 #include <linux/ratelimit.h>
 
 struct dm_dev;
@@ -550,6 +551,14 @@ extern struct ratelimit_state dm_ratelimit_state;
 #define DM_MAPIO_REMAPPED      1
 #define DM_MAPIO_REQUEUE       DM_ENDIO_REQUEUE
 
+#define dm_sector_div64(x, y)( \
+{ \
+       u64 _res; \
+       (x) = div64_u64_rem(x, y, &_res); \
+       _res; \
+} \
+)
+
 /*
  * Ceiling(n / sz)
  */
index f46646e4923520cebd5a3335e2dd3724c283b1ec..2a9d6ed5957903009d9ea7eea1050b2463b66b64 100644 (file)
@@ -737,7 +737,7 @@ struct device {
 
        struct dma_coherent_mem *dma_mem; /* internal for coherent mem
                                             override */
-#ifdef CONFIG_CMA
+#ifdef CONFIG_DMA_CMA
        struct cma *cma_area;           /* contiguous memory area for dma
                                           allocations */
 #endif
index 00141d3325fe2dbe0f0c649f3580d9ec473b7f0c..3b28f937d959d4da8872c92ca1487724e05ee83b 100644 (file)
@@ -67,9 +67,53 @@ struct device;
 
 extern struct cma *dma_contiguous_default_area;
 
+static inline struct cma *dev_get_cma_area(struct device *dev)
+{
+       if (dev && dev->cma_area)
+               return dev->cma_area;
+       return dma_contiguous_default_area;
+}
+
+static inline void dev_set_cma_area(struct device *dev, struct cma *cma)
+{
+       if (dev)
+               dev->cma_area = cma;
+}
+
+static inline void dma_contiguous_set_default(struct cma *cma)
+{
+       dma_contiguous_default_area = cma;
+}
+
 void dma_contiguous_reserve(phys_addr_t addr_limit);
-int dma_declare_contiguous(struct device *dev, phys_addr_t size,
-                          phys_addr_t base, phys_addr_t limit);
+
+int __init dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+                                      phys_addr_t limit, struct cma **res_cma);
+
+/**
+ * dma_declare_contiguous() - reserve area for contiguous memory handling
+ *                           for particular device
+ * @dev:   Pointer to device structure.
+ * @size:  Size of the reserved memory.
+ * @base:  Start address of the reserved memory (optional, 0 for any).
+ * @limit: End address of the reserved memory (optional, 0 for any).
+ *
+ * This function reserves memory for specified device. It should be
+ * called by board specific code when early allocator (memblock or bootmem)
+ * is still activate.
+ */
+
+static inline int dma_declare_contiguous(struct device *dev, phys_addr_t size,
+                                        phys_addr_t base, phys_addr_t limit)
+{
+       struct cma *cma;
+       int ret;
+       ret = dma_contiguous_reserve_area(size, base, limit, &cma);
+       if (ret == 0)
+               dev_set_cma_area(dev, cma);
+
+       return ret;
+}
 
 struct page *dma_alloc_from_contiguous(struct device *dev, int count,
                                       unsigned int order);
@@ -80,8 +124,22 @@ bool dma_release_from_contiguous(struct device *dev, struct page *pages,
 
 #define MAX_CMA_AREAS  (0)
 
+static inline struct cma *dev_get_cma_area(struct device *dev)
+{
+       return NULL;
+}
+
+static inline void dev_set_cma_area(struct device *dev, struct cma *cma) { }
+
+static inline void dma_contiguous_set_default(struct cma *cma) { }
+
 static inline void dma_contiguous_reserve(phys_addr_t limit) { }
 
+static inline int dma_contiguous_reserve_area(phys_addr_t size, phys_addr_t base,
+                                      phys_addr_t limit, struct cma **res_cma) {
+       return -ENOSYS;
+}
+
 static inline
 int dma_declare_contiguous(struct device *dev, phys_addr_t size,
                           phys_addr_t base, phys_addr_t limit)
diff --git a/include/linux/dma/mmp-pdma.h b/include/linux/dma/mmp-pdma.h
new file mode 100644 (file)
index 0000000..2dc9b2b
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef _MMP_PDMA_H_
+#define _MMP_PDMA_H_
+
+struct dma_chan;
+
+#ifdef CONFIG_MMP_PDMA
+bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param);
+#else
+static inline bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param)
+{
+       return false;
+}
+#endif
+
+#endif /* _MMP_PDMA_H_ */
index cb286b1acdb64f06131a4de019d5d5603c864b50..0bc727534108d5a2d5d527e75eaa8020a3ccd239 100644 (file)
@@ -38,7 +38,10 @@ typedef s32 dma_cookie_t;
 #define DMA_MIN_COOKIE 1
 #define DMA_MAX_COOKIE INT_MAX
 
-#define dma_submit_error(cookie) ((cookie) < 0 ? 1 : 0)
+static inline int dma_submit_error(dma_cookie_t cookie)
+{
+       return cookie < 0 ? cookie : 0;
+}
 
 /**
  * enum dma_status - DMA transaction status
@@ -370,6 +373,25 @@ struct dma_slave_config {
        unsigned int slave_id;
 };
 
+/* struct dma_slave_caps - expose capabilities of a slave channel only
+ *
+ * @src_addr_widths: bit mask of src addr widths the channel supports
+ * @dstn_addr_widths: bit mask of dstn addr widths the channel supports
+ * @directions: bit mask of slave direction the channel supported
+ *     since the enum dma_transfer_direction is not defined as bits for each
+ *     type of direction, the dma controller should fill (1 << <TYPE>) and same
+ *     should be checked by controller as well
+ * @cmd_pause: true, if pause and thereby resume is supported
+ * @cmd_terminate: true, if terminate cmd is supported
+ */
+struct dma_slave_caps {
+       u32 src_addr_widths;
+       u32 dstn_addr_widths;
+       u32 directions;
+       bool cmd_pause;
+       bool cmd_terminate;
+};
+
 static inline const char *dma_chan_name(struct dma_chan *chan)
 {
        return dev_name(&chan->dev->device);
@@ -532,6 +554,7 @@ struct dma_tx_state {
  *     struct with auxiliary transfer status information, otherwise the call
  *     will just return a simple status code
  * @device_issue_pending: push pending transactions to hardware
+ * @device_slave_caps: return the slave channel capabilities
  */
 struct dma_device {
 
@@ -597,6 +620,7 @@ struct dma_device {
                                            dma_cookie_t cookie,
                                            struct dma_tx_state *txstate);
        void (*device_issue_pending)(struct dma_chan *chan);
+       int (*device_slave_caps)(struct dma_chan *chan, struct dma_slave_caps *caps);
 };
 
 static inline int dmaengine_device_control(struct dma_chan *chan,
@@ -670,6 +694,21 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
        return chan->device->device_prep_interleaved_dma(chan, xt, flags);
 }
 
+static inline int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
+{
+       if (!chan || !caps)
+               return -EINVAL;
+
+       /* check if the channel supports slave transactions */
+       if (!test_bit(DMA_SLAVE, chan->device->cap_mask.bits))
+               return -ENXIO;
+
+       if (chan->device->device_slave_caps)
+               return chan->device->device_slave_caps(chan, caps);
+
+       return -ENXIO;
+}
+
 static inline int dmaengine_terminate_all(struct dma_chan *chan)
 {
        return dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
@@ -958,8 +997,9 @@ dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used,
        }
 }
 
-enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
 #ifdef CONFIG_DMA_ENGINE
+struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
+enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie);
 enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx);
 void dma_issue_pending_all(void);
 struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
@@ -967,6 +1007,14 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask,
 struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name);
 void dma_release_channel(struct dma_chan *chan);
 #else
+static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type)
+{
+       return NULL;
+}
+static inline enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
+{
+       return DMA_SUCCESS;
+}
 static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx)
 {
        return DMA_SUCCESS;
@@ -994,7 +1042,7 @@ static inline void dma_release_channel(struct dma_chan *chan)
 int dma_async_device_register(struct dma_device *device);
 void dma_async_device_unregister(struct dma_device *device);
 void dma_run_dependencies(struct dma_async_tx_descriptor *tx);
-struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type);
+struct dma_chan *dma_get_slave_channel(struct dma_chan *chan);
 struct dma_chan *net_dma_find_channel(void);
 #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y)
 #define dma_request_slave_channel_compat(mask, x, y, dev, name) \
index cf5d2af61b8105ba34818d4f668fad10c6759c02..ff0b981f078e238122113da027d96698a5cbe91d 100644 (file)
@@ -9,7 +9,6 @@
 #define _LINUX_EVENTFD_H
 
 #include <linux/fcntl.h>
-#include <linux/file.h>
 #include <linux/wait.h>
 
 /*
@@ -26,6 +25,8 @@
 #define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK)
 #define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE)
 
+struct file;
+
 #ifdef CONFIG_EVENTFD
 
 struct file *eventfd_file_create(unsigned int count, int flags);
index 529d8711baba0e6ba07c57921694302332d762fd..3f40547ba1917cd038f085bcdb6c6e577a9d4538 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/stat.h>
 #include <linux/cache.h>
 #include <linux/list.h>
+#include <linux/list_lru.h>
 #include <linux/llist.h>
 #include <linux/radix-tree.h>
 #include <linux/rbtree.h>
@@ -1269,15 +1270,6 @@ struct super_block {
        struct list_head        s_files;
 #endif
        struct list_head        s_mounts;       /* list of mounts; _not_ for fs use */
-       /* s_dentry_lru, s_nr_dentry_unused protected by dcache.c lru locks */
-       struct list_head        s_dentry_lru;   /* unused dentry lru */
-       int                     s_nr_dentry_unused;     /* # of dentry on lru */
-
-       /* s_inode_lru_lock protects s_inode_lru and s_nr_inodes_unused */
-       spinlock_t              s_inode_lru_lock ____cacheline_aligned_in_smp;
-       struct list_head        s_inode_lru;            /* unused inode lru */
-       int                     s_nr_inodes_unused;     /* # of inodes on lru */
-
        struct block_device     *s_bdev;
        struct backing_dev_info *s_bdi;
        struct mtd_info         *s_mtd;
@@ -1331,11 +1323,14 @@ struct super_block {
 
        /* AIO completions deferred from interrupt context */
        struct workqueue_struct *s_dio_done_wq;
-};
 
-/* superblock cache pruning functions */
-extern void prune_icache_sb(struct super_block *sb, int nr_to_scan);
-extern void prune_dcache_sb(struct super_block *sb, int nr_to_scan);
+       /*
+        * Keep the lru lists last in the structure so they always sit on their
+        * own individual cachelines.
+        */
+       struct list_lru         s_dentry_lru ____cacheline_aligned_in_smp;
+       struct list_lru         s_inode_lru ____cacheline_aligned_in_smp;
+};
 
 extern struct timespec current_fs_time(struct super_block *sb);
 
@@ -1629,8 +1624,8 @@ struct super_operations {
        ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
 #endif
        int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
-       int (*nr_cached_objects)(struct super_block *);
-       void (*free_cached_objects)(struct super_block *, int);
+       long (*nr_cached_objects)(struct super_block *, int);
+       long (*free_cached_objects)(struct super_block *, long, int);
 };
 
 /*
@@ -2074,6 +2069,7 @@ extern struct super_block *freeze_bdev(struct block_device *);
 extern void emergency_thaw_all(void);
 extern int thaw_bdev(struct block_device *bdev, struct super_block *sb);
 extern int fsync_bdev(struct block_device *);
+extern int sb_is_blkdev_sb(struct super_block *sb);
 #else
 static inline void bd_forget(struct inode *inode) {}
 static inline int sync_blockdev(struct block_device *bdev) { return 0; }
@@ -2093,6 +2089,11 @@ static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb)
 static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void *arg)
 {
 }
+
+static inline int sb_is_blkdev_sb(struct super_block *sb)
+{
+       return 0;
+}
 #endif
 extern int sync_filesystem(struct super_block *);
 extern const struct file_operations def_blk_fops;
@@ -2494,7 +2495,6 @@ extern const struct file_operations generic_ro_fops;
 #define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m))
 
 extern int vfs_readlink(struct dentry *, char __user *, int, const char *);
-extern int vfs_follow_link(struct nameidata *, const char *);
 extern int page_readlink(struct dentry *, char __user *, int);
 extern void *page_follow_link_light(struct dentry *, struct nameidata *);
 extern void page_put_link(struct dentry *, struct nameidata *, void *);
index 2b93a9a5a1e6b8ef4a15a6aaf36ade3b48bd0d98..0efc3e62843ae74592128dc7e34bd11fbaca4a3c 100644 (file)
@@ -39,17 +39,6 @@ static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd)
        spin_unlock(&fs->lock);
 }
 
-static inline void get_fs_root_and_pwd(struct fs_struct *fs, struct path *root,
-                                      struct path *pwd)
-{
-       spin_lock(&fs->lock);
-       *root = fs->root;
-       path_get(root);
-       *pwd = fs->pwd;
-       path_get(pwd);
-       spin_unlock(&fs->lock);
-}
-
 extern bool current_chrooted(void);
 
 #endif /* _LINUX_FS_STRUCT_H */
index a9ff9a36b86dc45c0f324fc2bacfc036f49fd0e3..7823e9ef995e2beaaa2b8e7a26a3c9619ee2e370 100644 (file)
@@ -251,6 +251,10 @@ struct fscache_cache_ops {
        /* unpin an object in the cache */
        void (*unpin_object)(struct fscache_object *object);
 
+       /* check the consistency between the backing cache and the FS-Cache
+        * cookie */
+       bool (*check_consistency)(struct fscache_operation *op);
+
        /* store the updated auxiliary data on an object */
        void (*update_object)(struct fscache_object *object);
 
index 7a086235da4be1ab94a026e0a1be3728dc1304a7..19b46458e4e88e3e25e55692a00ace4987897441 100644 (file)
@@ -183,6 +183,7 @@ extern struct fscache_cookie *__fscache_acquire_cookie(
        const struct fscache_cookie_def *,
        void *);
 extern void __fscache_relinquish_cookie(struct fscache_cookie *, int);
+extern int __fscache_check_consistency(struct fscache_cookie *);
 extern void __fscache_update_cookie(struct fscache_cookie *);
 extern int __fscache_attr_changed(struct fscache_cookie *);
 extern void __fscache_invalidate(struct fscache_cookie *);
@@ -208,6 +209,8 @@ extern bool __fscache_maybe_release_page(struct fscache_cookie *, struct page *,
                                         gfp_t);
 extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *,
                                              struct inode *);
+extern void __fscache_readpages_cancel(struct fscache_cookie *cookie,
+                                      struct list_head *pages);
 
 /**
  * fscache_register_netfs - Register a filesystem as desiring caching services
@@ -325,6 +328,25 @@ void fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire)
                __fscache_relinquish_cookie(cookie, retire);
 }
 
+/**
+ * fscache_check_consistency - Request that if the cache is updated
+ * @cookie: The cookie representing the cache object
+ *
+ * Request an consistency check from fscache, which passes the request
+ * to the backing cache.
+ *
+ * Returns 0 if consistent and -ESTALE if inconsistent.  May also
+ * return -ENOMEM and -ERESTARTSYS.
+ */
+static inline
+int fscache_check_consistency(struct fscache_cookie *cookie)
+{
+       if (fscache_cookie_valid(cookie))
+               return __fscache_check_consistency(cookie);
+       else
+               return 0;
+}
+
 /**
  * fscache_update_cookie - Request that a cache object be updated
  * @cookie: The cookie representing the cache object
@@ -569,6 +591,26 @@ int fscache_alloc_page(struct fscache_cookie *cookie,
                return -ENOBUFS;
 }
 
+/**
+ * fscache_readpages_cancel - Cancel read/alloc on pages
+ * @cookie: The cookie representing the inode's cache object.
+ * @pages: The netfs pages that we canceled write on in readpages()
+ *
+ * Uncache/unreserve the pages reserved earlier in readpages() via
+ * fscache_readpages_or_alloc() and similar.  In most successful caches in
+ * readpages() this doesn't do anything.  In cases when the underlying netfs's
+ * readahead failed we need to clean up the pagelist (unmark and uncache).
+ *
+ * This function may sleep as it may have to clean up disk state.
+ */
+static inline
+void fscache_readpages_cancel(struct fscache_cookie *cookie,
+                             struct list_head *pages)
+{
+       if (fscache_cookie_valid(cookie))
+               __fscache_readpages_cancel(cookie, pages);
+}
+
 /**
  * fscache_write_page - Request storage of a page in the cache
  * @cookie: The cookie representing the cache object
diff --git a/include/linux/fsl/mxs-dma.h b/include/linux/fsl/mxs-dma.h
deleted file mode 100644 (file)
index 55d8702..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright 2011 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 version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef __MACH_MXS_DMA_H__
-#define __MACH_MXS_DMA_H__
-
-#include <linux/dmaengine.h>
-
-struct mxs_dma_data {
-       int chan_irq;
-};
-
-extern int mxs_dma_is_apbh(struct dma_chan *chan);
-extern int mxs_dma_is_apbx(struct dma_chan *chan);
-#endif /* __MACH_MXS_DMA_H__ */
index 661d374aeb2d5275b396207e31c021c8c5f7ebeb..f8d41cb1cbe0a4afb726779f4c0ca05ff9a2a926 100644 (file)
@@ -66,8 +66,8 @@ struct gen_pool_chunk {
        struct list_head next_chunk;    /* next chunk in pool */
        atomic_t avail;
        phys_addr_t phys_addr;          /* physical starting address of memory chunk */
-       unsigned long start_addr;       /* starting address of memory chunk */
-       unsigned long end_addr;         /* ending address of memory chunk */
+       unsigned long start_addr;       /* start address of memory chunk */
+       unsigned long end_addr;         /* end address of memory chunk (inclusive) */
        unsigned long bits[0];          /* bitmap for allocating memory chunk */
 };
 
index ccfe17c5c8da1d78f62d652da8bb845d00dfc1f9..1e041063b22654aa375630bf36282d10059d7bec 100644 (file)
@@ -7,11 +7,7 @@
 #include <linux/vtime.h>
 
 
-#if defined(CONFIG_SMP) || defined(CONFIG_GENERIC_HARDIRQS)
 extern void synchronize_irq(unsigned int irq);
-#else
-# define synchronize_irq(irq)  barrier()
-#endif
 
 #if defined(CONFIG_TINY_RCU)
 
index ee1ffc5e19c9fd3d8b2c9ab4c481953455417d4c..31b9d299ef6ca25bf3d5bfd753860d7d3294be68 100644 (file)
@@ -756,6 +756,10 @@ u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags);
 struct hid_device *hid_allocate_device(void);
 struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
 int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
+struct hid_report *hid_validate_values(struct hid_device *hid,
+                                      unsigned int type, unsigned int id,
+                                      unsigned int field_index,
+                                      unsigned int report_counts);
 int hid_open_report(struct hid_device *device);
 int hid_check_keys_pressed(struct hid_device *hid);
 int hid_connect(struct hid_device *hid, unsigned int connect_mask);
index b60de92e2edc4ecadc2681a77b8973c1087dd748..3935428c57cff80d01236428fdea979d7a9f911b 100644 (file)
@@ -96,9 +96,6 @@ extern int copy_pte_range(struct mm_struct *dst_mm, struct mm_struct *src_mm,
                          pmd_t *dst_pmd, pmd_t *src_pmd,
                          struct vm_area_struct *vma,
                          unsigned long addr, unsigned long end);
-extern int handle_pte_fault(struct mm_struct *mm,
-                           struct vm_area_struct *vma, unsigned long address,
-                           pte_t *pte, pmd_t *pmd, unsigned int flags);
 extern int split_huge_page_to_list(struct page *page, struct list_head *list);
 static inline int split_huge_page(struct page *page)
 {
index c2b1801a160bccafd6d52a3cd77ca1effc2dfd89..0393270466c3fd8a59d24781cf54ab5ffd0c5a57 100644 (file)
@@ -66,6 +66,9 @@ int hugetlb_reserve_pages(struct inode *inode, long from, long to,
                                                vm_flags_t vm_flags);
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed);
 int dequeue_hwpoisoned_huge_page(struct page *page);
+bool isolate_huge_page(struct page *page, struct list_head *list);
+void putback_active_hugepage(struct page *page);
+bool is_hugepage_active(struct page *page);
 void copy_huge_page(struct page *dst, struct page *src);
 
 #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
@@ -134,6 +137,9 @@ static inline int dequeue_hwpoisoned_huge_page(struct page *page)
        return 0;
 }
 
+#define isolate_huge_page(p, l) false
+#define putback_active_hugepage(p)     do {} while (0)
+#define is_hugepage_active(x)  false
 static inline void copy_huge_page(struct page *dst, struct page *src)
 {
 }
@@ -261,6 +267,8 @@ struct huge_bootmem_page {
 };
 
 struct page *alloc_huge_page_node(struct hstate *h, int nid);
+struct page *alloc_huge_page_noerr(struct vm_area_struct *vma,
+                               unsigned long addr, int avoid_reserve);
 
 /* arch callback */
 int __init alloc_bootmem_huge_page(struct hstate *h);
@@ -371,9 +379,23 @@ static inline pgoff_t basepage_index(struct page *page)
        return __basepage_index(page);
 }
 
+extern void dissolve_free_huge_pages(unsigned long start_pfn,
+                                    unsigned long end_pfn);
+int pmd_huge_support(void);
+/*
+ * Currently hugepage migration is enabled only for pmd-based hugepage.
+ * This function will be updated when hugepage migration is more widely
+ * supported.
+ */
+static inline int hugepage_migration_support(struct hstate *h)
+{
+       return pmd_huge_support() && (huge_page_shift(h) == PMD_SHIFT);
+}
+
 #else  /* CONFIG_HUGETLB_PAGE */
 struct hstate {};
 #define alloc_huge_page_node(h, nid) NULL
+#define alloc_huge_page_noerr(v, a, r) NULL
 #define alloc_bootmem_huge_page(h) NULL
 #define hstate_file(f) NULL
 #define hstate_sizelog(s) NULL
@@ -396,6 +418,9 @@ static inline pgoff_t basepage_index(struct page *page)
 {
        return page->index;
 }
+#define dissolve_free_huge_pages(s, e) do {} while (0)
+#define pmd_huge_support()     0
+#define hugepage_migration_support(h)  0
 #endif /* CONFIG_HUGETLB_PAGE */
 
 #endif /* _LINUX_HUGETLB_H */
index a5b598a79becb99eb3554886cbec7708ee426309..7c1e1ebc0e2396cc7697bccc31d18be5566dc944 100644 (file)
@@ -1391,8 +1391,8 @@ struct ieee80211_vht_operation {
 #define IEEE80211_VHT_CAP_RXSTBC_MASK                          0x00000700
 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE                        0x00000800
 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE                        0x00001000
-#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX              0x00006000
-#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX              0x00030000
+#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX                   0x0000e000
+#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX              0x00070000
 #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE                        0x00080000
 #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE                        0x00100000
 #define IEEE80211_VHT_CAP_VHT_TXOP_PS                          0x00200000
index e73f2b708525d06046811febe8ca490e93d6ab31..f1c27a71d03c9ee03754f882cd738d90d58ac25b 100644 (file)
@@ -153,6 +153,7 @@ extern unsigned int reset_devices;
 void setup_arch(char **);
 void prepare_namespace(void);
 void __init load_default_modules(void);
+int __init init_rootfs(void);
 
 extern void (*late_time_init)(void);
 
index 5fa5afeeb7599d6c0f05d7fb59796cf153a614a9..5e865b55494096898112234b1f2898cfc372d757 100644 (file)
@@ -120,7 +120,6 @@ struct irqaction {
 
 extern irqreturn_t no_action(int cpl, void *dev_id);
 
-#ifdef CONFIG_GENERIC_HARDIRQS
 extern int __must_check
 request_threaded_irq(unsigned int irq, irq_handler_t handler,
                     irq_handler_t thread_fn,
@@ -140,40 +139,6 @@ request_any_context_irq(unsigned int irq, irq_handler_t handler,
 extern int __must_check
 request_percpu_irq(unsigned int irq, irq_handler_t handler,
                   const char *devname, void __percpu *percpu_dev_id);
-#else
-
-extern int __must_check
-request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
-           const char *name, void *dev);
-
-/*
- * Special function to avoid ifdeffery in kernel/irq/devres.c which
- * gets magically built by GENERIC_HARDIRQS=n architectures (sparc,
- * m68k). I really love these $@%#!* obvious Makefile references:
- * ../../../kernel/irq/devres.o
- */
-static inline int __must_check
-request_threaded_irq(unsigned int irq, irq_handler_t handler,
-                    irq_handler_t thread_fn,
-                    unsigned long flags, const char *name, void *dev)
-{
-       return request_irq(irq, handler, flags, name, dev);
-}
-
-static inline int __must_check
-request_any_context_irq(unsigned int irq, irq_handler_t handler,
-                       unsigned long flags, const char *name, void *dev_id)
-{
-       return request_irq(irq, handler, flags, name, dev_id);
-}
-
-static inline int __must_check
-request_percpu_irq(unsigned int irq, irq_handler_t handler,
-                  const char *devname, void __percpu *percpu_dev_id)
-{
-       return request_irq(irq, handler, 0, devname, percpu_dev_id);
-}
-#endif
 
 extern void free_irq(unsigned int, void *);
 extern void free_percpu_irq(unsigned int, void __percpu *);
@@ -221,7 +186,6 @@ extern void enable_irq(unsigned int irq);
 extern void enable_percpu_irq(unsigned int irq, unsigned int type);
 
 /* The following three functions are for the core kernel use only. */
-#ifdef CONFIG_GENERIC_HARDIRQS
 extern void suspend_device_irqs(void);
 extern void resume_device_irqs(void);
 #ifdef CONFIG_PM_SLEEP
@@ -229,13 +193,8 @@ extern int check_wakeup_irqs(void);
 #else
 static inline int check_wakeup_irqs(void) { return 0; }
 #endif
-#else
-static inline void suspend_device_irqs(void) { };
-static inline void resume_device_irqs(void) { };
-static inline int check_wakeup_irqs(void) { return 0; }
-#endif
 
-#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_HARDIRQS)
+#if defined(CONFIG_SMP)
 
 extern cpumask_var_t irq_default_affinity;
 
@@ -287,9 +246,8 @@ static inline int irq_set_affinity_hint(unsigned int irq,
 {
        return -EINVAL;
 }
-#endif /* CONFIG_SMP && CONFIG_GENERIC_HARDIRQS */
+#endif /* CONFIG_SMP */
 
-#ifdef CONFIG_GENERIC_HARDIRQS
 /*
  * Special lockdep variants of irq disabling/enabling.
  * These should be used for locking constructs that
@@ -354,33 +312,6 @@ static inline int disable_irq_wake(unsigned int irq)
        return irq_set_irq_wake(irq, 0);
 }
 
-#else /* !CONFIG_GENERIC_HARDIRQS */
-/*
- * NOTE: non-genirq architectures, if they want to support the lock
- * validator need to define the methods below in their asm/irq.h
- * files, under an #ifdef CONFIG_LOCKDEP section.
- */
-#ifndef CONFIG_LOCKDEP
-#  define disable_irq_nosync_lockdep(irq)      disable_irq_nosync(irq)
-#  define disable_irq_nosync_lockdep_irqsave(irq, flags) \
-                                               disable_irq_nosync(irq)
-#  define disable_irq_lockdep(irq)             disable_irq(irq)
-#  define enable_irq_lockdep(irq)              enable_irq(irq)
-#  define enable_irq_lockdep_irqrestore(irq, flags) \
-                                               enable_irq(irq)
-# endif
-
-static inline int enable_irq_wake(unsigned int irq)
-{
-       return 0;
-}
-
-static inline int disable_irq_wake(unsigned int irq)
-{
-       return 0;
-}
-#endif /* CONFIG_GENERIC_HARDIRQS */
-
 
 #ifdef CONFIG_IRQ_FORCED_THREADING
 extern bool force_irqthreads;
@@ -655,7 +586,7 @@ void tasklet_hrtimer_cancel(struct tasklet_hrtimer *ttimer)
  * if more than one irq occurred.
  */
 
-#if defined(CONFIG_GENERIC_HARDIRQS) && !defined(CONFIG_GENERIC_IRQ_PROBE) 
+#if !defined(CONFIG_GENERIC_IRQ_PROBE) 
 static inline unsigned long probe_irq_on(void)
 {
        return 0;
index 3aeb7305e2f59d3eae986c1c36d0af22cfea057b..7ea319e95b4771ecb9dc4be7d04ad24a8e628d86 100644 (file)
@@ -58,10 +58,26 @@ struct iommu_domain {
 #define IOMMU_CAP_CACHE_COHERENCY      0x1
 #define IOMMU_CAP_INTR_REMAP           0x2     /* isolates device intrs */
 
+/*
+ * Following constraints are specifc to FSL_PAMUV1:
+ *  -aperture must be power of 2, and naturally aligned
+ *  -number of windows must be power of 2, and address space size
+ *   of each window is determined by aperture size / # of windows
+ *  -the actual size of the mapped region of a window must be power
+ *   of 2 starting with 4KB and physical address must be naturally
+ *   aligned.
+ * DOMAIN_ATTR_FSL_PAMUV1 corresponds to the above mentioned contraints.
+ * The caller can invoke iommu_domain_get_attr to check if the underlying
+ * iommu implementation supports these constraints.
+ */
+
 enum iommu_attr {
        DOMAIN_ATTR_GEOMETRY,
        DOMAIN_ATTR_PAGING,
        DOMAIN_ATTR_WINDOWS,
+       DOMAIN_ATTR_FSL_PAMU_STASH,
+       DOMAIN_ATTR_FSL_PAMU_ENABLE,
+       DOMAIN_ATTR_FSL_PAMUV1,
        DOMAIN_ATTR_MAX,
 };
 
index c4d870b0d5e6e26580bfd717d64489fce8d59aa6..19c19a5eee293396d0ddec9454e1ecb55adfed5b 100644 (file)
@@ -22,7 +22,7 @@ struct ipc_ids {
        int in_use;
        unsigned short seq;
        unsigned short seq_max;
-       struct rw_semaphore rw_mutex;
+       struct rw_semaphore rwsem;
        struct idr ipcs_idr;
        int next_id;
 };
index f04d3ba335cb3ec778bd9820dc13dad29c2a8e72..56bb0dc8b7d44cbab1a5a3cefb9efc04a7440995 100644 (file)
@@ -382,8 +382,6 @@ extern void irq_cpu_online(void);
 extern void irq_cpu_offline(void);
 extern int __irq_set_affinity_locked(struct irq_data *data,  const struct cpumask *cpumask);
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-
 #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ)
 void irq_move_irq(struct irq_data *data);
 void irq_move_masked_irq(struct irq_data *data);
@@ -802,11 +800,4 @@ static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
 static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
 #endif
 
-#else /* !CONFIG_GENERIC_HARDIRQS */
-
-extern struct msi_desc *irq_get_msi_desc(unsigned int irq);
-extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry);
-
-#endif /* CONFIG_GENERIC_HARDIRQS */
-
 #endif /* _LINUX_IRQ_H */
index 3e203eb23cc79231f96ae50e1fb56da9cf4125ad..0e5d9ecdb2b672d901b47f184a4b720e604317e2 100644 (file)
@@ -66,6 +66,7 @@ extern struct irq_chip gic_arch_extn;
 void gic_init_bases(unsigned int, int, void __iomem *, void __iomem *,
                    u32 offset, struct device_node *);
 void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
+void gic_cpu_if_down(void);
 
 static inline void gic_init(unsigned int nr, int start,
                            void __iomem *dist , void __iomem *cpu)
diff --git a/include/linux/irqchip/mmp.h b/include/linux/irqchip/mmp.h
new file mode 100644 (file)
index 0000000..c78a892
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef        __IRQCHIP_MMP_H
+#define        __IRQCHIP_MMP_H
+
+extern struct irq_chip icu_irq_chip;
+
+#endif /* __IRQCHIP_MMP_H */
index 623325e2ff97d4f0e3ead2d1eeeeddd35c1916fa..56fb646909dce8ddd749c207eb1cfe7a2481790c 100644 (file)
@@ -76,8 +76,6 @@ struct irq_desc {
 extern struct irq_desc irq_desc[NR_IRQS];
 #endif
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-
 static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc)
 {
        return &desc->irq_data;
@@ -173,6 +171,5 @@ __irq_set_preflow_handler(unsigned int irq, irq_preflow_handler_t handler)
        desc->preflow_handler = handler;
 }
 #endif
-#endif
 
 #endif
index 0a2dc46cdaf6e7070dc602fcde64a23c72553361..fdd5cc16c9c43bcf4bb72cbd7c18d2047af7dd7c 100644 (file)
@@ -4,23 +4,6 @@
 #include <uapi/linux/irqnr.h>
 
 
-#ifndef CONFIG_GENERIC_HARDIRQS
-#include <asm/irq.h>
-
-/*
- * Wrappers for non-genirq architectures:
- */
-#define nr_irqs                        NR_IRQS
-#define irq_to_desc(irq)       (&irq_desc[irq])
-
-# define for_each_irq_desc(irq, desc)          \
-       for (irq = 0; irq < nr_irqs; irq++)
-
-# define for_each_irq_desc_reverse(irq, desc)                          \
-       for (irq = nr_irqs - 1; irq >= 0; irq--)
-
-#else /* CONFIG_GENERIC_HARDIRQS */
-
 extern int nr_irqs;
 extern struct irq_desc *irq_to_desc(unsigned int irq);
 unsigned int irq_get_next_irq(unsigned int offset);
@@ -50,8 +33,6 @@ unsigned int irq_get_next_irq(unsigned int offset);
        for (irq = irq_get_next_irq(0); irq < nr_irqs;  \
             irq = irq_get_next_irq(irq + 1))
 
-#endif /* CONFIG_GENERIC_HARDIRQS */
-
 #define for_each_irq_nr(irq)                   \
        for (irq = 0; irq < nr_irqs; irq++)
 
index ed5f6ed6eb772797ea1c7eb0e98e46f55dbcf027..51c72be4a7c3f1782a5d5f21801b06bea1720f57 100644 (file)
@@ -36,9 +36,6 @@ struct kernel_cpustat {
 };
 
 struct kernel_stat {
-#ifndef CONFIG_GENERIC_HARDIRQS
-       unsigned int irqs[NR_IRQS];
-#endif
        unsigned long irqs_sum;
        unsigned int softirqs[NR_SOFTIRQS];
 };
@@ -54,22 +51,6 @@ DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat);
 
 extern unsigned long long nr_context_switches(void);
 
-#ifndef CONFIG_GENERIC_HARDIRQS
-
-struct irq_desc;
-
-static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
-                                           struct irq_desc *desc)
-{
-       __this_cpu_inc(kstat.irqs[irq]);
-       __this_cpu_inc(kstat.irqs_sum);
-}
-
-static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
-{
-       return kstat_cpu(cpu).irqs[irq];
-}
-#else
 #include <linux/irq.h>
 extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
 
@@ -79,8 +60,6 @@ do {                                                  \
        __this_cpu_inc(kstat.irqs_sum);                 \
 } while (0)
 
-#endif
-
 static inline void kstat_incr_softirqs_this_cpu(unsigned int irq)
 {
        __this_cpu_inc(kstat.softirqs[irq]);
@@ -94,20 +73,7 @@ static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu)
 /*
  * Number of interrupts per specific IRQ source, since bootup
  */
-#ifndef CONFIG_GENERIC_HARDIRQS
-static inline unsigned int kstat_irqs(unsigned int irq)
-{
-       unsigned int sum = 0;
-       int cpu;
-
-       for_each_possible_cpu(cpu)
-               sum += kstat_irqs_cpu(irq, cpu);
-
-       return sum;
-}
-#else
 extern unsigned int kstat_irqs(unsigned int irq);
-#endif
 
 /*
  * Number of interrupts per cpu, since bootup
index ca1d27a0d6a6679700a01fb141fa229026cb1b4b..925eaf28fca9ccf3a38e6360eca752eb2cab857d 100644 (file)
@@ -264,10 +264,36 @@ extern void arch_arm_kprobe(struct kprobe *p);
 extern void arch_disarm_kprobe(struct kprobe *p);
 extern int arch_init_kprobes(void);
 extern void show_registers(struct pt_regs *regs);
-extern kprobe_opcode_t *get_insn_slot(void);
-extern void free_insn_slot(kprobe_opcode_t *slot, int dirty);
 extern void kprobes_inc_nmissed_count(struct kprobe *p);
 
+struct kprobe_insn_cache {
+       struct mutex mutex;
+       void *(*alloc)(void);   /* allocate insn page */
+       void (*free)(void *);   /* free insn page */
+       struct list_head pages; /* list of kprobe_insn_page */
+       size_t insn_size;       /* size of instruction slot */
+       int nr_garbage;
+};
+
+extern kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c);
+extern void __free_insn_slot(struct kprobe_insn_cache *c,
+                            kprobe_opcode_t *slot, int dirty);
+
+#define DEFINE_INSN_CACHE_OPS(__name)                                  \
+extern struct kprobe_insn_cache kprobe_##__name##_slots;               \
+                                                                       \
+static inline kprobe_opcode_t *get_##__name##_slot(void)               \
+{                                                                      \
+       return __get_insn_slot(&kprobe_##__name##_slots);               \
+}                                                                      \
+                                                                       \
+static inline void free_##__name##_slot(kprobe_opcode_t *slot, int dirty)\
+{                                                                      \
+       __free_insn_slot(&kprobe_##__name##_slots, slot, dirty);        \
+}                                                                      \
+
+DEFINE_INSN_CACHE_OPS(insn);
+
 #ifdef CONFIG_OPTPROBES
 /*
  * Internal structure for direct jump optimized probe
@@ -287,13 +313,13 @@ extern void arch_optimize_kprobes(struct list_head *oplist);
 extern void arch_unoptimize_kprobes(struct list_head *oplist,
                                    struct list_head *done_list);
 extern void arch_unoptimize_kprobe(struct optimized_kprobe *op);
-extern kprobe_opcode_t *get_optinsn_slot(void);
-extern void free_optinsn_slot(kprobe_opcode_t *slot, int dirty);
 extern int arch_within_optimized_kprobe(struct optimized_kprobe *op,
                                        unsigned long addr);
 
 extern void opt_pre_handler(struct kprobe *p, struct pt_regs *regs);
 
+DEFINE_INSN_CACHE_OPS(optinsn);
+
 #ifdef CONFIG_SYSCTL
 extern int sysctl_kprobes_optimization;
 extern int proc_kprobes_optimization_handler(struct ctl_table *table,
index ca645a01d37a79767baccfd12a8871b79af7b624..0fbbc7aa02cb17c9c7d1cc5b5a17330d58858c10 100644 (file)
@@ -533,6 +533,7 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,
 
 struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
 unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
+unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable);
 unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn);
 void kvm_release_page_clean(struct page *page);
 void kvm_release_page_dirty(struct page *page);
diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h
new file mode 100644 (file)
index 0000000..3ce5417
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved.
+ * Authors: David Chinner and Glauber Costa
+ *
+ * Generic LRU infrastructure
+ */
+#ifndef _LRU_LIST_H
+#define _LRU_LIST_H
+
+#include <linux/list.h>
+#include <linux/nodemask.h>
+
+/* list_lru_walk_cb has to always return one of those */
+enum lru_status {
+       LRU_REMOVED,            /* item removed from list */
+       LRU_ROTATE,             /* item referenced, give another pass */
+       LRU_SKIP,               /* item cannot be locked, skip */
+       LRU_RETRY,              /* item not freeable. May drop the lock
+                                  internally, but has to return locked. */
+};
+
+struct list_lru_node {
+       spinlock_t              lock;
+       struct list_head        list;
+       /* kept as signed so we can catch imbalance bugs */
+       long                    nr_items;
+} ____cacheline_aligned_in_smp;
+
+struct list_lru {
+       struct list_lru_node    *node;
+       nodemask_t              active_nodes;
+};
+
+void list_lru_destroy(struct list_lru *lru);
+int list_lru_init(struct list_lru *lru);
+
+/**
+ * list_lru_add: add an element to the lru list's tail
+ * @list_lru: the lru pointer
+ * @item: the item to be added.
+ *
+ * If the element is already part of a list, this function returns doing
+ * nothing. Therefore the caller does not need to keep state about whether or
+ * not the element already belongs in the list and is allowed to lazy update
+ * it. Note however that this is valid for *a* list, not *this* list. If
+ * the caller organize itself in a way that elements can be in more than
+ * one type of list, it is up to the caller to fully remove the item from
+ * the previous list (with list_lru_del() for instance) before moving it
+ * to @list_lru
+ *
+ * Return value: true if the list was updated, false otherwise
+ */
+bool list_lru_add(struct list_lru *lru, struct list_head *item);
+
+/**
+ * list_lru_del: delete an element to the lru list
+ * @list_lru: the lru pointer
+ * @item: the item to be deleted.
+ *
+ * This function works analogously as list_lru_add in terms of list
+ * manipulation. The comments about an element already pertaining to
+ * a list are also valid for list_lru_del.
+ *
+ * Return value: true if the list was updated, false otherwise
+ */
+bool list_lru_del(struct list_lru *lru, struct list_head *item);
+
+/**
+ * list_lru_count_node: return the number of objects currently held by @lru
+ * @lru: the lru pointer.
+ * @nid: the node id to count from.
+ *
+ * Always return a non-negative number, 0 for empty lists. There is no
+ * guarantee that the list is not updated while the count is being computed.
+ * Callers that want such a guarantee need to provide an outer lock.
+ */
+unsigned long list_lru_count_node(struct list_lru *lru, int nid);
+static inline unsigned long list_lru_count(struct list_lru *lru)
+{
+       long count = 0;
+       int nid;
+
+       for_each_node_mask(nid, lru->active_nodes)
+               count += list_lru_count_node(lru, nid);
+
+       return count;
+}
+
+typedef enum lru_status
+(*list_lru_walk_cb)(struct list_head *item, spinlock_t *lock, void *cb_arg);
+/**
+ * list_lru_walk_node: walk a list_lru, isolating and disposing freeable items.
+ * @lru: the lru pointer.
+ * @nid: the node id to scan from.
+ * @isolate: callback function that is resposible for deciding what to do with
+ *  the item currently being scanned
+ * @cb_arg: opaque type that will be passed to @isolate
+ * @nr_to_walk: how many items to scan.
+ *
+ * This function will scan all elements in a particular list_lru, calling the
+ * @isolate callback for each of those items, along with the current list
+ * spinlock and a caller-provided opaque. The @isolate callback can choose to
+ * drop the lock internally, but *must* return with the lock held. The callback
+ * will return an enum lru_status telling the list_lru infrastructure what to
+ * do with the object being scanned.
+ *
+ * Please note that nr_to_walk does not mean how many objects will be freed,
+ * just how many objects will be scanned.
+ *
+ * Return value: the number of objects effectively removed from the LRU.
+ */
+unsigned long list_lru_walk_node(struct list_lru *lru, int nid,
+                                list_lru_walk_cb isolate, void *cb_arg,
+                                unsigned long *nr_to_walk);
+
+static inline unsigned long
+list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate,
+             void *cb_arg, unsigned long nr_to_walk)
+{
+       long isolated = 0;
+       int nid;
+
+       for_each_node_mask(nid, lru->active_nodes) {
+               isolated += list_lru_walk_node(lru, nid, isolate,
+                                              cb_arg, &nr_to_walk);
+               if (nr_to_walk <= 0)
+                       break;
+       }
+       return isolated;
+}
+#endif /* _LRU_LIST_H */
index d21c13f10a6471590f0a783a53eabfbba9571051..4356686b0a3914a2d47271ca87ff74943782be42 100644 (file)
@@ -67,8 +67,8 @@ int lz4hc_compress(const unsigned char *src, size_t src_len,
  *     note :  Destination buffer must be already allocated.
  *             slightly faster than lz4_decompress_unknownoutputsize()
  */
-int lz4_decompress(const char *src, size_t *src_len, char *dest,
-               size_t actual_dest_len);
+int lz4_decompress(const unsigned char *src, size_t *src_len,
+               unsigned char *dest, size_t actual_dest_len);
 
 /*
  * lz4_decompress_unknownoutputsize()
@@ -82,6 +82,6 @@ int lz4_decompress(const char *src, size_t *src_len, char *dest,
  *               Error if return (< 0)
  *     note :  Destination buffer must be already allocated.
  */
-int lz4_decompress_unknownoutputsize(const char *src, size_t src_len,
-               char *dest, size_t *dest_len);
+int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len,
+               unsigned char *dest, size_t *dest_len);
 #endif
index 2913b86eb12a7a1068991b9342e7ed43c8eec1fe..69ed5f5e9f6e4a83f8c9226cb92d6ba7eafa17bd 100644 (file)
@@ -30,6 +30,15 @@ static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
        return dividend / divisor;
 }
 
+/**
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
+ */
+static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
+{
+       *remainder = dividend % divisor;
+       return dividend / divisor;
+}
+
 /**
  * div64_u64 - unsigned 64bit divide with 64bit divisor
  */
@@ -63,6 +72,10 @@ static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
 extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
 #endif
 
+#ifndef div64_u64_rem
+extern u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder);
+#endif
+
 #ifndef div64_u64
 extern u64 div64_u64(u64 dividend, u64 divisor);
 #endif
index f388203db7e85b421bfb58d3963f2edbc315c70c..31e95acddb4dc3eb76020ea9f1ab09823330d55f 100644 (file)
@@ -60,6 +60,8 @@ int memblock_reserve(phys_addr_t base, phys_addr_t size);
 void memblock_trim_memory(phys_addr_t align);
 
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
+int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
+                           unsigned long  *end_pfn);
 void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn,
                          unsigned long *out_end_pfn, int *out_nid);
 
index 6c416092e3244d1e82b1f928ee0d31a6f6e46162..60e95872da2983365300f1abb193b6e81974b5de 100644 (file)
@@ -30,9 +30,21 @@ struct page;
 struct mm_struct;
 struct kmem_cache;
 
-/* Stats that can be updated by kernel. */
-enum mem_cgroup_page_stat_item {
-       MEMCG_NR_FILE_MAPPED, /* # of pages charged as file rss */
+/*
+ * The corresponding mem_cgroup_stat_names is defined in mm/memcontrol.c,
+ * These two lists should keep in accord with each other.
+ */
+enum mem_cgroup_stat_index {
+       /*
+        * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
+        */
+       MEM_CGROUP_STAT_CACHE,          /* # of pages charged as cache */
+       MEM_CGROUP_STAT_RSS,            /* # of pages charged as anon rss */
+       MEM_CGROUP_STAT_RSS_HUGE,       /* # of pages charged as anon huge */
+       MEM_CGROUP_STAT_FILE_MAPPED,    /* # of pages charged as file rss */
+       MEM_CGROUP_STAT_WRITEBACK,      /* # of pages under writeback */
+       MEM_CGROUP_STAT_SWAP,           /* # of pages, swapped out */
+       MEM_CGROUP_STAT_NSTATS,
 };
 
 struct mem_cgroup_reclaim_cookie {
@@ -41,6 +53,23 @@ struct mem_cgroup_reclaim_cookie {
        unsigned int generation;
 };
 
+enum mem_cgroup_filter_t {
+       VISIT,          /* visit current node */
+       SKIP,           /* skip the current node and continue traversal */
+       SKIP_TREE,      /* skip the whole subtree and continue traversal */
+};
+
+/*
+ * mem_cgroup_filter_t predicate might instruct mem_cgroup_iter_cond how to
+ * iterate through the hierarchy tree. Each tree element is checked by the
+ * predicate before it is returned by the iterator. If a filter returns
+ * SKIP or SKIP_TREE then the iterator code continues traversal (with the
+ * next node down the hierarchy or the next node that doesn't belong under the
+ * memcg's subtree).
+ */
+typedef enum mem_cgroup_filter_t
+(*mem_cgroup_iter_filter)(struct mem_cgroup *memcg, struct mem_cgroup *root);
+
 #ifdef CONFIG_MEMCG
 /*
  * All "charge" functions with gfp_mask should use GFP_KERNEL or
@@ -108,9 +137,18 @@ mem_cgroup_prepare_migration(struct page *page, struct page *newpage,
 extern void mem_cgroup_end_migration(struct mem_cgroup *memcg,
        struct page *oldpage, struct page *newpage, bool migration_ok);
 
-struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *,
-                                  struct mem_cgroup *,
-                                  struct mem_cgroup_reclaim_cookie *);
+struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root,
+                                  struct mem_cgroup *prev,
+                                  struct mem_cgroup_reclaim_cookie *reclaim,
+                                  mem_cgroup_iter_filter cond);
+
+static inline struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
+                                  struct mem_cgroup *prev,
+                                  struct mem_cgroup_reclaim_cookie *reclaim)
+{
+       return mem_cgroup_iter_cond(root, prev, reclaim, NULL);
+}
+
 void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *);
 
 /*
@@ -125,6 +163,48 @@ extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
 extern void mem_cgroup_replace_page_cache(struct page *oldpage,
                                        struct page *newpage);
 
+/**
+ * mem_cgroup_toggle_oom - toggle the memcg OOM killer for the current task
+ * @new: true to enable, false to disable
+ *
+ * Toggle whether a failed memcg charge should invoke the OOM killer
+ * or just return -ENOMEM.  Returns the previous toggle state.
+ *
+ * NOTE: Any path that enables the OOM killer before charging must
+ *       call mem_cgroup_oom_synchronize() afterward to finalize the
+ *       OOM handling and clean up.
+ */
+static inline bool mem_cgroup_toggle_oom(bool new)
+{
+       bool old;
+
+       old = current->memcg_oom.may_oom;
+       current->memcg_oom.may_oom = new;
+
+       return old;
+}
+
+static inline void mem_cgroup_enable_oom(void)
+{
+       bool old = mem_cgroup_toggle_oom(true);
+
+       WARN_ON(old == true);
+}
+
+static inline void mem_cgroup_disable_oom(void)
+{
+       bool old = mem_cgroup_toggle_oom(false);
+
+       WARN_ON(old == false);
+}
+
+static inline bool task_in_memcg_oom(struct task_struct *p)
+{
+       return p->memcg_oom.in_memcg_oom;
+}
+
+bool mem_cgroup_oom_synchronize(void);
+
 #ifdef CONFIG_MEMCG_SWAP
 extern int do_swap_account;
 #endif
@@ -165,24 +245,24 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page,
 }
 
 void mem_cgroup_update_page_stat(struct page *page,
-                                enum mem_cgroup_page_stat_item idx,
+                                enum mem_cgroup_stat_index idx,
                                 int val);
 
 static inline void mem_cgroup_inc_page_stat(struct page *page,
-                                           enum mem_cgroup_page_stat_item idx)
+                                           enum mem_cgroup_stat_index idx)
 {
        mem_cgroup_update_page_stat(page, idx, 1);
 }
 
 static inline void mem_cgroup_dec_page_stat(struct page *page,
-                                           enum mem_cgroup_page_stat_item idx)
+                                           enum mem_cgroup_stat_index idx)
 {
        mem_cgroup_update_page_stat(page, idx, -1);
 }
 
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
-                                               gfp_t gfp_mask,
-                                               unsigned long *total_scanned);
+enum mem_cgroup_filter_t
+mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
+               struct mem_cgroup *root);
 
 void __mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx);
 static inline void mem_cgroup_count_vm_event(struct mm_struct *mm,
@@ -296,6 +376,15 @@ static inline void mem_cgroup_end_migration(struct mem_cgroup *memcg,
                struct page *oldpage, struct page *newpage, bool migration_ok)
 {
 }
+static inline struct mem_cgroup *
+mem_cgroup_iter_cond(struct mem_cgroup *root,
+               struct mem_cgroup *prev,
+               struct mem_cgroup_reclaim_cookie *reclaim,
+               mem_cgroup_iter_filter cond)
+{
+       /* first call must return non-NULL, second return NULL */
+       return (struct mem_cgroup *)(unsigned long)!prev;
+}
 
 static inline struct mem_cgroup *
 mem_cgroup_iter(struct mem_cgroup *root,
@@ -348,22 +437,45 @@ static inline void mem_cgroup_end_update_page_stat(struct page *page,
 {
 }
 
+static inline bool mem_cgroup_toggle_oom(bool new)
+{
+       return false;
+}
+
+static inline void mem_cgroup_enable_oom(void)
+{
+}
+
+static inline void mem_cgroup_disable_oom(void)
+{
+}
+
+static inline bool task_in_memcg_oom(struct task_struct *p)
+{
+       return false;
+}
+
+static inline bool mem_cgroup_oom_synchronize(void)
+{
+       return false;
+}
+
 static inline void mem_cgroup_inc_page_stat(struct page *page,
-                                           enum mem_cgroup_page_stat_item idx)
+                                           enum mem_cgroup_stat_index idx)
 {
 }
 
 static inline void mem_cgroup_dec_page_stat(struct page *page,
-                                           enum mem_cgroup_page_stat_item idx)
+                                           enum mem_cgroup_stat_index idx)
 {
 }
 
 static inline
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
-                                           gfp_t gfp_mask,
-                                           unsigned long *total_scanned)
+enum mem_cgroup_filter_t
+mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
+               struct mem_cgroup *root)
 {
-       return 0;
+       return VISIT;
 }
 
 static inline void mem_cgroup_split_huge_fixup(struct page *head)
index 0d7df39a5885f84c33a843e59f77f44d3ec6824f..da6716b9e3fea8148f45f57ac556367b547f839f 100644 (file)
@@ -91,7 +91,6 @@ static inline struct mempolicy *mpol_dup(struct mempolicy *pol)
 }
 
 #define vma_policy(vma) ((vma)->vm_policy)
-#define vma_set_policy(vma, pol) ((vma)->vm_policy = (pol))
 
 static inline void mpol_get(struct mempolicy *pol)
 {
@@ -126,6 +125,7 @@ struct shared_policy {
        spinlock_t lock;
 };
 
+int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst);
 void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol);
 int mpol_set_shared_policy(struct shared_policy *info,
                                struct vm_area_struct *vma,
@@ -173,7 +173,7 @@ extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol);
 /* Check if a vma is migratable */
 static inline int vma_migratable(struct vm_area_struct *vma)
 {
-       if (vma->vm_flags & (VM_IO | VM_HUGETLB | VM_PFNMAP))
+       if (vma->vm_flags & (VM_IO | VM_PFNMAP))
                return 0;
        /*
         * Migration allocates pages in the highest zone. If we cannot
@@ -240,7 +240,12 @@ mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx)
 }
 
 #define vma_policy(vma) NULL
-#define vma_set_policy(vma, pol) do {} while(0)
+
+static inline int
+vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
+{
+       return 0;
+}
 
 static inline void numa_policy_init(void)
 {
diff --git a/include/linux/mfd/da9063/core.h b/include/linux/mfd/da9063/core.h
new file mode 100644 (file)
index 0000000..2d2a0af
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Definitions for DA9063 MFD driver
+ *
+ * Copyright 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Michal Hajduk <michal.hajduk@diasemi.com>
+ *        Krystian Garbaciak <krystian.garbaciak@diasemi.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 __MFD_DA9063_CORE_H__
+#define __MFD_DA9063_CORE_H__
+
+#include <linux/interrupt.h>
+#include <linux/mfd/da9063/registers.h>
+
+/* DA9063 modules */
+#define DA9063_DRVNAME_CORE            "da9063-core"
+#define DA9063_DRVNAME_REGULATORS      "da9063-regulators"
+#define DA9063_DRVNAME_LEDS            "da9063-leds"
+#define DA9063_DRVNAME_WATCHDOG                "da9063-watchdog"
+#define DA9063_DRVNAME_HWMON           "da9063-hwmon"
+#define DA9063_DRVNAME_ONKEY           "da9063-onkey"
+#define DA9063_DRVNAME_RTC             "da9063-rtc"
+#define DA9063_DRVNAME_VIBRATION       "da9063-vibration"
+
+enum da9063_models {
+       PMIC_DA9063 = 0x61,
+};
+
+/* Interrupts */
+enum da9063_irqs {
+       DA9063_IRQ_ONKEY = 0,
+       DA9063_IRQ_ALARM,
+       DA9063_IRQ_TICK,
+       DA9063_IRQ_ADC_RDY,
+       DA9063_IRQ_SEQ_RDY,
+       DA9063_IRQ_WAKE,
+       DA9063_IRQ_TEMP,
+       DA9063_IRQ_COMP_1V2,
+       DA9063_IRQ_LDO_LIM,
+       DA9063_IRQ_REG_UVOV,
+       DA9063_IRQ_VDD_MON,
+       DA9063_IRQ_WARN,
+       DA9063_IRQ_GPI0,
+       DA9063_IRQ_GPI1,
+       DA9063_IRQ_GPI2,
+       DA9063_IRQ_GPI3,
+       DA9063_IRQ_GPI4,
+       DA9063_IRQ_GPI5,
+       DA9063_IRQ_GPI6,
+       DA9063_IRQ_GPI7,
+       DA9063_IRQ_GPI8,
+       DA9063_IRQ_GPI9,
+       DA9063_IRQ_GPI10,
+       DA9063_IRQ_GPI11,
+       DA9063_IRQ_GPI12,
+       DA9063_IRQ_GPI13,
+       DA9063_IRQ_GPI14,
+       DA9063_IRQ_GPI15,
+};
+
+#define DA9063_IRQ_BASE_OFFSET 0
+#define DA9063_NUM_IRQ         (DA9063_IRQ_GPI15 + 1 - DA9063_IRQ_BASE_OFFSET)
+
+struct da9063 {
+       /* Device */
+       struct device   *dev;
+       unsigned short  model;
+       unsigned short  revision;
+       unsigned int    flags;
+
+       /* Control interface */
+       struct regmap   *regmap;
+
+       /* Interrupts */
+       int             chip_irq;
+       unsigned int    irq_base;
+       struct regmap_irq_chip_data *regmap_irq;
+};
+
+int da9063_device_init(struct da9063 *da9063, unsigned int irq);
+int da9063_irq_init(struct da9063 *da9063);
+
+void da9063_device_exit(struct da9063 *da9063);
+void da9063_irq_exit(struct da9063 *da9063);
+
+#endif /* __MFD_DA9063_CORE_H__ */
diff --git a/include/linux/mfd/da9063/pdata.h b/include/linux/mfd/da9063/pdata.h
new file mode 100644 (file)
index 0000000..95c8742
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Platform configuration options for DA9063
+ *
+ * Copyright 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Michal Hajduk <michal.hajduk@diasemi.com>
+ * Author: Krystian Garbaciak <krystian.garbaciak@diasemi.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 __MFD_DA9063_PDATA_H__
+#define __MFD_DA9063_PDATA_H__
+
+#include <linux/regulator/machine.h>
+
+/*
+ * Regulator configuration
+ */
+/* DA9063 regulator IDs */
+enum {
+       /* BUCKs */
+       DA9063_ID_BCORE1,
+       DA9063_ID_BCORE2,
+       DA9063_ID_BPRO,
+       DA9063_ID_BMEM,
+       DA9063_ID_BIO,
+       DA9063_ID_BPERI,
+
+       /* BCORE1 and BCORE2 in merged mode */
+       DA9063_ID_BCORES_MERGED,
+       /* BMEM and BIO in merged mode */
+       DA9063_ID_BMEM_BIO_MERGED,
+       /* When two BUCKs are merged, they cannot be reused separately */
+
+       /* LDOs */
+       DA9063_ID_LDO1,
+       DA9063_ID_LDO2,
+       DA9063_ID_LDO3,
+       DA9063_ID_LDO4,
+       DA9063_ID_LDO5,
+       DA9063_ID_LDO6,
+       DA9063_ID_LDO7,
+       DA9063_ID_LDO8,
+       DA9063_ID_LDO9,
+       DA9063_ID_LDO10,
+       DA9063_ID_LDO11,
+};
+
+/* Regulators platform data */
+struct da9063_regulator_data {
+       int                             id;
+       struct regulator_init_data      *initdata;
+};
+
+struct da9063_regulators_pdata {
+       unsigned                        n_regulators;
+       struct da9063_regulator_data    *regulator_data;
+};
+
+
+/*
+ * RGB LED configuration
+ */
+/* LED IDs for flags in struct led_info. */
+enum {
+       DA9063_GPIO11_LED,
+       DA9063_GPIO14_LED,
+       DA9063_GPIO15_LED,
+
+       DA9063_LED_NUM
+};
+#define DA9063_LED_ID_MASK             0x3
+
+/* LED polarity for flags in struct led_info. */
+#define DA9063_LED_HIGH_LEVEL_ACTIVE   0x0
+#define DA9063_LED_LOW_LEVEL_ACTIVE    0x4
+
+
+/*
+ * General PMIC configuration
+ */
+/* HWMON ADC channels configuration */
+#define DA9063_FLG_FORCE_IN0_MANUAL_MODE       0x0010
+#define DA9063_FLG_FORCE_IN0_AUTO_MODE         0x0020
+#define DA9063_FLG_FORCE_IN1_MANUAL_MODE       0x0040
+#define DA9063_FLG_FORCE_IN1_AUTO_MODE         0x0080
+#define DA9063_FLG_FORCE_IN2_MANUAL_MODE       0x0100
+#define DA9063_FLG_FORCE_IN2_AUTO_MODE         0x0200
+#define DA9063_FLG_FORCE_IN3_MANUAL_MODE       0x0400
+#define DA9063_FLG_FORCE_IN3_AUTO_MODE         0x0800
+
+/* Disable register caching. */
+#define DA9063_FLG_NO_CACHE                    0x0008
+
+struct da9063;
+
+/* DA9063 platform data */
+struct da9063_pdata {
+       int                             (*init)(struct da9063 *da9063);
+       int                             irq_base;
+       unsigned                        flags;
+       struct da9063_regulators_pdata  *regulators_pdata;
+       struct led_platform_data        *leds_pdata;
+};
+
+#endif /* __MFD_DA9063_PDATA_H__ */
diff --git a/include/linux/mfd/da9063/registers.h b/include/linux/mfd/da9063/registers.h
new file mode 100644 (file)
index 0000000..5834813
--- /dev/null
@@ -0,0 +1,1028 @@
+/*
+ * Registers definition for DA9063 modules
+ *
+ * Copyright 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Michal Hajduk <michal.hajduk@diasemi.com>
+ *        Krystian Garbaciak <krystian.garbaciak@diasemi.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 _DA9063_REG_H
+#define        _DA9063_REG_H
+
+#define DA9063_I2C_PAGE_SEL_SHIFT      1
+
+#define        DA9063_EVENT_REG_NUM            4
+#define        DA9210_EVENT_REG_NUM            2
+#define        DA9063_EXT_EVENT_REG_NUM        (DA9063_EVENT_REG_NUM + \
+                                               DA9210_EVENT_REG_NUM)
+
+/* Page selection I2C or SPI always in the begining of any page. */
+/* Page 0 : I2C access 0x000 - 0x0FF   SPI access 0x000 - 0x07F */
+/* Page 1 :                            SPI access 0x080 - 0x0FF */
+/* Page 2 : I2C access 0x100 - 0x1FF   SPI access 0x100 - 0x17F */
+/* Page 3 :                            SPI access 0x180 - 0x1FF */
+#define        DA9063_REG_PAGE_CON             0x00
+
+/* System Control and Event Registers */
+#define        DA9063_REG_STATUS_A             0x01
+#define        DA9063_REG_STATUS_B             0x02
+#define        DA9063_REG_STATUS_C             0x03
+#define        DA9063_REG_STATUS_D             0x04
+#define        DA9063_REG_FAULT_LOG            0x05
+#define        DA9063_REG_EVENT_A              0x06
+#define        DA9063_REG_EVENT_B              0x07
+#define        DA9063_REG_EVENT_C              0x08
+#define        DA9063_REG_EVENT_D              0x09
+#define        DA9063_REG_IRQ_MASK_A           0x0A
+#define        DA9063_REG_IRQ_MASK_B           0x0B
+#define        DA9063_REG_IRQ_MASK_C           0x0C
+#define        DA9063_REG_IRQ_MASK_D           0x0D
+#define        DA9063_REG_CONTROL_A            0x0E
+#define        DA9063_REG_CONTROL_B            0x0F
+#define        DA9063_REG_CONTROL_C            0x10
+#define        DA9063_REG_CONTROL_D            0x11
+#define        DA9063_REG_CONTROL_E            0x12
+#define        DA9063_REG_CONTROL_F            0x13
+#define        DA9063_REG_PD_DIS               0x14
+
+/* GPIO Control Registers */
+#define        DA9063_REG_GPIO_0_1             0x15
+#define        DA9063_REG_GPIO_2_3             0x16
+#define        DA9063_REG_GPIO_4_5             0x17
+#define        DA9063_REG_GPIO_6_7             0x18
+#define        DA9063_REG_GPIO_8_9             0x19
+#define        DA9063_REG_GPIO_10_11           0x1A
+#define        DA9063_REG_GPIO_12_13           0x1B
+#define        DA9063_REG_GPIO_14_15           0x1C
+#define        DA9063_REG_GPIO_MODE_0_7        0x1D
+#define        DA9063_REG_GPIO_MODE_8_15       0x1E
+#define        DA9063_REG_GPIO_SWITCH_CONT     0x1F
+
+/* Regulator Control Registers */
+#define        DA9063_REG_BCORE2_CONT          0x20
+#define        DA9063_REG_BCORE1_CONT          0x21
+#define        DA9063_REG_BPRO_CONT            0x22
+#define        DA9063_REG_BMEM_CONT            0x23
+#define        DA9063_REG_BIO_CONT             0x24
+#define        DA9063_REG_BPERI_CONT           0x25
+#define        DA9063_REG_LDO1_CONT            0x26
+#define        DA9063_REG_LDO2_CONT            0x27
+#define        DA9063_REG_LDO3_CONT            0x28
+#define        DA9063_REG_LDO4_CONT            0x29
+#define        DA9063_REG_LDO5_CONT            0x2A
+#define        DA9063_REG_LDO6_CONT            0x2B
+#define        DA9063_REG_LDO7_CONT            0x2C
+#define        DA9063_REG_LDO8_CONT            0x2D
+#define        DA9063_REG_LDO9_CONT            0x2E
+#define        DA9063_REG_LDO10_CONT           0x2F
+#define        DA9063_REG_LDO11_CONT           0x30
+#define        DA9063_REG_VIB                  0x31
+#define        DA9063_REG_DVC_1                0x32
+#define        DA9063_REG_DVC_2                0x33
+
+/* GP-ADC Control Registers */
+#define        DA9063_REG_ADC_MAN              0x34
+#define        DA9063_REG_ADC_CONT             0x35
+#define        DA9063_REG_VSYS_MON             0x36
+#define        DA9063_REG_ADC_RES_L            0x37
+#define        DA9063_REG_ADC_RES_H            0x38
+#define        DA9063_REG_VSYS_RES             0x39
+#define        DA9063_REG_ADCIN1_RES           0x3A
+#define        DA9063_REG_ADCIN2_RES           0x3B
+#define        DA9063_REG_ADCIN3_RES           0x3C
+#define        DA9063_REG_MON1_RES             0x3D
+#define        DA9063_REG_MON2_RES             0x3E
+#define        DA9063_REG_MON3_RES             0x3F
+
+/* RTC Calendar and Alarm Registers */
+#define        DA9063_REG_COUNT_S              0x40
+#define        DA9063_REG_COUNT_MI             0x41
+#define        DA9063_REG_COUNT_H              0x42
+#define        DA9063_REG_COUNT_D              0x43
+#define        DA9063_REG_COUNT_MO             0x44
+#define        DA9063_REG_COUNT_Y              0x45
+#define        DA9063_REG_ALARM_MI             0x46
+#define        DA9063_REG_ALARM_H              0x47
+#define        DA9063_REG_ALARM_D              0x48
+#define        DA9063_REG_ALARM_MO             0x49
+#define        DA9063_REG_ALARM_Y              0x4A
+#define        DA9063_REG_SECOND_A             0x4B
+#define        DA9063_REG_SECOND_B             0x4C
+#define        DA9063_REG_SECOND_C             0x4D
+#define        DA9063_REG_SECOND_D             0x4E
+
+/* Sequencer Control Registers */
+#define        DA9063_REG_SEQ                  0x81
+#define        DA9063_REG_SEQ_TIMER            0x82
+#define        DA9063_REG_ID_2_1               0x83
+#define        DA9063_REG_ID_4_3               0x84
+#define        DA9063_REG_ID_6_5               0x85
+#define        DA9063_REG_ID_8_7               0x86
+#define        DA9063_REG_ID_10_9              0x87
+#define        DA9063_REG_ID_12_11             0x88
+#define        DA9063_REG_ID_14_13             0x89
+#define        DA9063_REG_ID_16_15             0x8A
+#define        DA9063_REG_ID_18_17             0x8B
+#define        DA9063_REG_ID_20_19             0x8C
+#define        DA9063_REG_ID_22_21             0x8D
+#define        DA9063_REG_ID_24_23             0x8E
+#define        DA9063_REG_ID_26_25             0x8F
+#define        DA9063_REG_ID_28_27             0x90
+#define        DA9063_REG_ID_30_29             0x91
+#define        DA9063_REG_ID_32_31             0x92
+#define        DA9063_REG_SEQ_A                0x95
+#define        DA9063_REG_SEQ_B                0x96
+#define        DA9063_REG_WAIT                 0x97
+#define        DA9063_REG_EN_32K               0x98
+#define        DA9063_REG_RESET                0x99
+
+/* Regulator Setting Registers */
+#define        DA9063_REG_BUCK_ILIM_A          0x9A
+#define        DA9063_REG_BUCK_ILIM_B          0x9B
+#define        DA9063_REG_BUCK_ILIM_C          0x9C
+#define        DA9063_REG_BCORE2_CFG           0x9D
+#define        DA9063_REG_BCORE1_CFG           0x9E
+#define        DA9063_REG_BPRO_CFG             0x9F
+#define        DA9063_REG_BIO_CFG              0xA0
+#define        DA9063_REG_BMEM_CFG             0xA1
+#define        DA9063_REG_BPERI_CFG            0xA2
+#define        DA9063_REG_VBCORE2_A            0xA3
+#define        DA9063_REG_VBCORE1_A            0xA4
+#define        DA9063_REG_VBPRO_A              0xA5
+#define        DA9063_REG_VBMEM_A              0xA6
+#define        DA9063_REG_VBIO_A               0xA7
+#define        DA9063_REG_VBPERI_A             0xA8
+#define        DA9063_REG_VLDO1_A              0xA9
+#define        DA9063_REG_VLDO2_A              0xAA
+#define        DA9063_REG_VLDO3_A              0xAB
+#define        DA9063_REG_VLDO4_A              0xAC
+#define        DA9063_REG_VLDO5_A              0xAD
+#define        DA9063_REG_VLDO6_A              0xAE
+#define        DA9063_REG_VLDO7_A              0xAF
+#define        DA9063_REG_VLDO8_A              0xB0
+#define        DA9063_REG_VLDO9_A              0xB1
+#define        DA9063_REG_VLDO10_A             0xB2
+#define        DA9063_REG_VLDO11_A             0xB3
+#define        DA9063_REG_VBCORE2_B            0xB4
+#define        DA9063_REG_VBCORE1_B            0xB5
+#define        DA9063_REG_VBPRO_B              0xB6
+#define        DA9063_REG_VBMEM_B              0xB7
+#define        DA9063_REG_VBIO_B               0xB8
+#define        DA9063_REG_VBPERI_B             0xB9
+#define        DA9063_REG_VLDO1_B              0xBA
+#define        DA9063_REG_VLDO2_B              0xBB
+#define        DA9063_REG_VLDO3_B              0xBC
+#define        DA9063_REG_VLDO4_B              0xBD
+#define        DA9063_REG_VLDO5_B              0xBE
+#define        DA9063_REG_VLDO6_B              0xBF
+#define        DA9063_REG_VLDO7_B              0xC0
+#define        DA9063_REG_VLDO8_B              0xC1
+#define        DA9063_REG_VLDO9_B              0xC2
+#define        DA9063_REG_VLDO10_B             0xC3
+#define        DA9063_REG_VLDO11_B             0xC4
+
+/* Backup Battery Charger Control Register */
+#define        DA9063_REG_BBAT_CONT            0xC5
+
+/* GPIO PWM (LED) */
+#define        DA9063_REG_GPO11_LED            0xC6
+#define        DA9063_REG_GPO14_LED            0xC7
+#define        DA9063_REG_GPO15_LED            0xC8
+
+/* GP-ADC Threshold Registers */
+#define        DA9063_REG_ADC_CFG              0xC9
+#define        DA9063_REG_AUTO1_HIGH           0xCA
+#define        DA9063_REG_AUTO1_LOW            0xCB
+#define        DA9063_REG_AUTO2_HIGH           0xCC
+#define        DA9063_REG_AUTO2_LOW            0xCD
+#define        DA9063_REG_AUTO3_HIGH           0xCE
+#define        DA9063_REG_AUTO3_LOW            0xCF
+
+/* DA9063 Configuration registers */
+/* OTP */
+#define        DA9063_REG_OPT_COUNT            0x101
+#define        DA9063_REG_OPT_ADDR             0x102
+#define        DA9063_REG_OPT_DATA             0x103
+
+/* Customer Trim and Configuration */
+#define        DA9063_REG_T_OFFSET             0x104
+#define        DA9063_REG_INTERFACE            0x105
+#define        DA9063_REG_CONFIG_A             0x106
+#define        DA9063_REG_CONFIG_B             0x107
+#define        DA9063_REG_CONFIG_C             0x108
+#define        DA9063_REG_CONFIG_D             0x109
+#define        DA9063_REG_CONFIG_E             0x10A
+#define        DA9063_REG_CONFIG_F             0x10B
+#define        DA9063_REG_CONFIG_G             0x10C
+#define        DA9063_REG_CONFIG_H             0x10D
+#define        DA9063_REG_CONFIG_I             0x10E
+#define        DA9063_REG_CONFIG_J             0x10F
+#define        DA9063_REG_CONFIG_K             0x110
+#define        DA9063_REG_CONFIG_L             0x111
+#define        DA9063_REG_MON_REG_1            0x112
+#define        DA9063_REG_MON_REG_2            0x113
+#define        DA9063_REG_MON_REG_3            0x114
+#define        DA9063_REG_MON_REG_4            0x115
+#define        DA9063_REG_MON_REG_5            0x116
+#define        DA9063_REG_MON_REG_6            0x117
+#define        DA9063_REG_TRIM_CLDR            0x118
+
+/* General Purpose Registers */
+#define        DA9063_REG_GP_ID_0              0x119
+#define        DA9063_REG_GP_ID_1              0x11A
+#define        DA9063_REG_GP_ID_2              0x11B
+#define        DA9063_REG_GP_ID_3              0x11C
+#define        DA9063_REG_GP_ID_4              0x11D
+#define        DA9063_REG_GP_ID_5              0x11E
+#define        DA9063_REG_GP_ID_6              0x11F
+#define        DA9063_REG_GP_ID_7              0x120
+#define        DA9063_REG_GP_ID_8              0x121
+#define        DA9063_REG_GP_ID_9              0x122
+#define        DA9063_REG_GP_ID_10             0x123
+#define        DA9063_REG_GP_ID_11             0x124
+#define        DA9063_REG_GP_ID_12             0x125
+#define        DA9063_REG_GP_ID_13             0x126
+#define        DA9063_REG_GP_ID_14             0x127
+#define        DA9063_REG_GP_ID_15             0x128
+#define        DA9063_REG_GP_ID_16             0x129
+#define        DA9063_REG_GP_ID_17             0x12A
+#define        DA9063_REG_GP_ID_18             0x12B
+#define        DA9063_REG_GP_ID_19             0x12C
+
+/* Chip ID and variant */
+#define        DA9063_REG_CHIP_ID              0x181
+#define        DA9063_REG_CHIP_VARIANT         0x182
+
+/*
+ * PMIC registers bits
+ */
+/* DA9063_REG_PAGE_CON (addr=0x00) */
+#define        DA9063_PEG_PAGE_SHIFT                   0
+#define        DA9063_REG_PAGE_MASK                    0x07
+#define                DA9063_REG_PAGE0                0x00
+#define                DA9063_REG_PAGE2                0x02
+#define        DA9063_PAGE_WRITE_MODE                  0x00
+#define        DA9063_REPEAT_WRITE_MODE                0x40
+#define        DA9063_PAGE_REVERT                      0x80
+
+/* DA9063_REG_STATUS_A (addr=0x01) */
+#define        DA9063_NONKEY                           0x01
+#define        DA9063_WAKE                             0x02
+#define        DA9063_DVC_BUSY                         0x04
+#define        DA9063_COMP_1V2                         0x08
+
+/* DA9063_REG_STATUS_B (addr=0x02) */
+#define        DA9063_GPI0                             0x01
+#define        DA9063_GPI1                             0x02
+#define        DA9063_GPI2                             0x04
+#define        DA9063_GPI3                             0x08
+#define        DA9063_GPI4                             0x10
+#define        DA9063_GPI5                             0x20
+#define        DA9063_GPI6                             0x40
+#define        DA9063_GPI7                             0x80
+
+/* DA9063_REG_STATUS_C (addr=0x03) */
+#define        DA9063_GPI8                             0x01
+#define        DA9063_GPI9                             0x02
+#define        DA9063_GPI10                            0x04
+#define        DA9063_GPI11                            0x08
+#define        DA9063_GPI12                            0x10
+#define        DA9063_GPI13                            0x20
+#define        DA9063_GPI14                            0x40
+#define        DA9063_GPI15                            0x80
+
+/* DA9063_REG_STATUS_D (addr=0x04) */
+#define        DA9063_LDO3_LIM                         0x08
+#define        DA9063_LDO4_LIM                         0x10
+#define        DA9063_LDO7_LIM                         0x20
+#define        DA9063_LDO8_LIM                         0x40
+#define        DA9063_LDO11_LIM                        0x80
+
+/* DA9063_REG_FAULT_LOG (addr=0x05) */
+#define        DA9063_TWD_ERROR                        0x01
+#define        DA9063_POR                              0x02
+#define        DA9063_VDD_FAULT                        0x04
+#define        DA9063_VDD_START                        0x08
+#define        DA9063_TEMP_CRIT                        0x10
+#define        DA9063_KEY_RESET                        0x20
+#define        DA9063_NSHUTDOWN                        0x40
+#define        DA9063_WAIT_SHUT                        0x80
+
+/* DA9063_REG_EVENT_A (addr=0x06) */
+#define        DA9063_E_NONKEY                         0x01
+#define        DA9063_E_ALARM                          0x02
+#define        DA9063_E_TICK                           0x04
+#define        DA9063_E_ADC_RDY                        0x08
+#define        DA9063_E_SEQ_RDY                        0x10
+#define        DA9063_EVENTS_B                         0x20
+#define        DA9063_EVENTS_C                         0x40
+#define        DA9063_EVENTS_D                         0x80
+
+/* DA9063_REG_EVENT_B (addr=0x07) */
+#define        DA9063_E_WAKE                           0x01
+#define        DA9063_E_TEMP                           0x02
+#define        DA9063_E_COMP_1V2                       0x04
+#define        DA9063_E_LDO_LIM                        0x08
+#define        DA9063_E_REG_UVOV                       0x10
+#define        DA9063_E_DVC_RDY                        0x20
+#define        DA9063_E_VDD_MON                        0x40
+#define        DA9063_E_VDD_WARN                       0x80
+
+/* DA9063_REG_EVENT_C (addr=0x08) */
+#define        DA9063_E_GPI0                           0x01
+#define        DA9063_E_GPI1                           0x02
+#define        DA9063_E_GPI2                           0x04
+#define        DA9063_E_GPI3                           0x08
+#define        DA9063_E_GPI4                           0x10
+#define        DA9063_E_GPI5                           0x20
+#define        DA9063_E_GPI6                           0x40
+#define        DA9063_E_GPI7                           0x80
+
+/* DA9063_REG_EVENT_D (addr=0x09) */
+#define        DA9063_E_GPI8                           0x01
+#define        DA9063_E_GPI9                           0x02
+#define        DA9063_E_GPI10                          0x04
+#define        DA9063_E_GPI11                          0x08
+#define        DA9063_E_GPI12                          0x10
+#define        DA9063_E_GPI13                          0x20
+#define        DA9063_E_GPI14                          0x40
+#define        DA9063_E_GPI15                          0x80
+
+/* DA9063_REG_IRQ_MASK_A (addr=0x0A) */
+#define        DA9063_M_ONKEY                          0x01
+#define        DA9063_M_ALARM                          0x02
+#define        DA9063_M_TICK                           0x04
+#define        DA9063_M_ADC_RDY                        0x08
+#define        DA9063_M_SEQ_RDY                        0x10
+
+/* DA9063_REG_IRQ_MASK_B (addr=0x0B) */
+#define        DA9063_M_WAKE                           0x01
+#define        DA9063_M_TEMP                           0x02
+#define        DA9063_M_COMP_1V2                       0x04
+#define        DA9063_M_LDO_LIM                        0x08
+#define        DA9063_M_UVOV                           0x10
+#define        DA9063_M_DVC_RDY                        0x20
+#define        DA9063_M_VDD_MON                        0x40
+#define        DA9063_M_VDD_WARN                       0x80
+
+/* DA9063_REG_IRQ_MASK_C (addr=0x0C) */
+#define        DA9063_M_GPI0                           0x01
+#define        DA9063_M_GPI1                           0x02
+#define        DA9063_M_GPI2                           0x04
+#define        DA9063_M_GPI3                           0x08
+#define        DA9063_M_GPI4                           0x10
+#define        DA9063_M_GPI5                           0x20
+#define        DA9063_M_GPI6                           0x40
+#define        DA9063_M_GPI7                           0x80
+
+/* DA9063_REG_IRQ_MASK_D (addr=0x0D) */
+#define        DA9063_M_GPI8                           0x01
+#define        DA9063_M_GPI9                           0x02
+#define        DA9063_M_GPI10                          0x04
+#define        DA9063_M_GPI11                          0x08
+#define        DA9063_M_GPI12                          0x10
+#define        DA9063_M_GPI13                          0x20
+#define        DA9063_M_GPI14                          0x40
+#define        DA9063_M_GPI15                          0x80
+
+/* DA9063_REG_CONTROL_A (addr=0x0E) */
+#define        DA9063_SYSTEM_EN                        0x01
+#define        DA9063_POWER_EN                         0x02
+#define        DA9063_POWER1_EN                        0x04
+#define        DA9063_STANDBY                          0x08
+#define        DA9063_M_SYSTEM_EN                      0x10
+#define        DA9063_M_POWER_EN                       0x20
+#define        DA9063_M_POWER1_EN                      0x40
+#define        DA9063_CP_EN                            0x80
+
+/* DA9063_REG_CONTROL_B (addr=0x0F) */
+#define        DA9063_CHG_SEL                          0x01
+#define        DA9063_WATCHDOG_PD                      0x02
+#define        DA9063_NRES_MODE                        0x08
+#define        DA9063_NONKEY_LOCK                      0x10
+
+/* DA9063_REG_CONTROL_C (addr=0x10) */
+#define        DA9063_DEBOUNCING_MASK                  0x07
+#define                DA9063_DEBOUNCING_OFF           0x0
+#define                DA9063_DEBOUNCING_0MS1          0x1
+#define                DA9063_DEBOUNCING_1MS           0x2
+#define                DA9063_DEBOUNCING_10MS24        0x3
+#define                DA9063_DEBOUNCING_51MS2         0x4
+#define                DA9063_DEBOUNCING_256MS         0x5
+#define                DA9063_DEBOUNCING_512MS         0x6
+#define                DA9063_DEBOUNCING_1024MS        0x7
+
+#define        DA9063_AUTO_BOOT                        0x08
+#define        DA9063_OTPREAD_EN                       0x10
+#define        DA9063_SLEW_RATE_MASK                   0x60
+#define                DA9063_SLEW_RATE_4US            0x00
+#define                DA9063_SLEW_RATE_3US            0x20
+#define                DA9063_SLEW_RATE_1US            0x40
+#define                DA9063_SLEW_RATE_0US5           0x60
+#define        DA9063_DEF_SUPPLY                       0x80
+
+/* DA9063_REG_CONTROL_D (addr=0x11) */
+#define        DA9063_TWDSCALE_MASK                    0x07
+#define        DA9063_BLINK_FRQ_MASK                   0x38
+#define                DA9063_BLINK_FRQ_OFF            0x00
+#define                DA9063_BLINK_FRQ_1S0            0x08
+#define                DA9063_BLINK_FRQ_2S0            0x10
+#define                DA9063_BLINK_FRQ_4S0            0x18
+#define                DA9063_BLINK_FRQ_0S18           0x20
+#define                DA9063_BLINK_FRQ_2S0_VDD        0x28
+#define                DA9063_BLINK_FRQ_4S0_VDD        0x30
+#define                DA9063_BLINK_FRQ_0S18_VDD       0x38
+
+#define        DA9063_BLINK_DUR_MASK                   0xC0
+#define                DA9063_BLINK_DUR_10MS           0x00
+#define                DA9063_BLINK_DUR_20MS           0x40
+#define                DA9063_BLINK_DUR_40MS           0x80
+#define                DA9063_BLINK_DUR_20MSDBL        0xC0
+
+/* DA9063_REG_CONTROL_E (addr=0x12) */
+#define        DA9063_RTC_MODE_PD                      0x01
+#define        DA9063_RTC_MODE_SD                      0x02
+#define        DA9063_RTC_EN                           0x04
+#define        DA9063_ECO_MODE                         0x08
+#define        DA9063_PM_FB1_PIN                       0x10
+#define        DA9063_PM_FB2_PIN                       0x20
+#define        DA9063_PM_FB3_PIN                       0x40
+#define        DA9063_V_LOCK                           0x80
+
+/* DA9063_REG_CONTROL_F (addr=0x13) */
+#define        DA9063_WATCHDOG                         0x01
+#define        DA9063_SHUTDOWN                         0x02
+#define        DA9063_WAKE_UP                          0x04
+
+/* DA9063_REG_PD_DIS (addr=0x14) */
+#define        DA9063_GPI_DIS                          0x01
+#define        DA9063_GPADC_PAUSE                      0x02
+#define        DA9063_PMIF_DIS                         0x04
+#define        DA9063_HS2WIRE_DIS                      0x08
+#define        DA9063_BBAT_DIS                         0x20
+#define        DA9063_OUT_32K_PAUSE                    0x40
+#define        DA9063_PMCONT_DIS                       0x80
+
+/* DA9063_REG_GPIO_0_1 (addr=0x15) */
+#define        DA9063_GPIO0_PIN_MASK                   0x03
+#define                DA9063_GPIO0_PIN_ADCIN1         0x00
+#define                DA9063_GPIO0_PIN_GPI            0x01
+#define                DA9063_GPIO0_PIN_GPO_OD         0x02
+#define                DA9063_GPIO0_PIN_GPO            0x03
+#define        DA9063_GPIO0_TYPE                       0x04
+#define                DA9063_GPIO0_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO0_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO0_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO0_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO0_NO_WAKEUP                  0x08
+#define        DA9063_GPIO1_PIN_MASK                   0x30
+#define                DA9063_GPIO1_PIN_ADCIN2_COMP    0x00
+#define                DA9063_GPIO1_PIN_GPI            0x10
+#define                DA9063_GPIO1_PIN_GPO_OD         0x20
+#define                DA9063_GPIO1_PIN_GPO            0x30
+#define        DA9063_GPIO1_TYPE                       0x40
+#define                DA9063_GPIO1_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO1_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO1_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO1_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO1_NO_WAKEUP                  0x80
+
+/* DA9063_REG_GPIO_2_3 (addr=0x16) */
+#define        DA9063_GPIO2_PIN_MASK                   0x03
+#define                DA9063_GPIO2_PIN_ADCIN3         0x00
+#define                DA9063_GPIO2_PIN_GPI            0x01
+#define                DA9063_GPIO2_PIN_GPO_PSS        0x02
+#define                DA9063_GPIO2_PIN_GPO            0x03
+#define        DA9063_GPIO2_TYPE                       0x04
+#define                DA9063_GPIO2_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO2_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO2_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO2_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO2_NO_WAKEUP                  0x08
+#define        DA9063_GPIO3_PIN_MASK                   0x30
+#define                DA9063_GPIO3_PIN_CORE_SW_G      0x00
+#define                DA9063_GPIO3_PIN_GPI            0x10
+#define                DA9063_GPIO3_PIN_GPO_OD         0x20
+#define                DA9063_GPIO3_PIN_GPO            0x30
+#define        DA9063_GPIO3_TYPE                       0x40
+#define                DA9063_GPIO3_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO3_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO3_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO3_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO3_NO_WAKEUP                  0x80
+
+/* DA9063_REG_GPIO_4_5 (addr=0x17) */
+#define        DA9063_GPIO4_PIN_MASK                   0x03
+#define                DA9063_GPIO4_PIN_CORE_SW_S      0x00
+#define                DA9063_GPIO4_PIN_GPI            0x01
+#define                DA9063_GPIO4_PIN_GPO_OD         0x02
+#define                DA9063_GPIO4_PIN_GPO            0x03
+#define        DA9063_GPIO4_TYPE                       0x04
+#define                DA9063_GPIO4_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO4_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO4_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO4_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO4_NO_WAKEUP                  0x08
+#define        DA9063_GPIO5_PIN_MASK                   0x30
+#define                DA9063_GPIO5_PIN_PERI_SW_G      0x00
+#define                DA9063_GPIO5_PIN_GPI            0x10
+#define                DA9063_GPIO5_PIN_GPO_OD         0x20
+#define                DA9063_GPIO5_PIN_GPO            0x30
+#define        DA9063_GPIO5_TYPE                       0x40
+#define                DA9063_GPIO5_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO5_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO5_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO5_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO5_NO_WAKEUP                  0x80
+
+/* DA9063_REG_GPIO_6_7 (addr=0x18) */
+#define        DA9063_GPIO6_PIN_MASK                   0x03
+#define                DA9063_GPIO6_PIN_PERI_SW_S      0x00
+#define                DA9063_GPIO6_PIN_GPI            0x01
+#define                DA9063_GPIO6_PIN_GPO_OD         0x02
+#define                DA9063_GPIO6_PIN_GPO            0x03
+#define        DA9063_GPIO6_TYPE                       0x04
+#define                DA9063_GPIO6_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO6_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO6_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO6_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO6_NO_WAKEUP                  0x08
+#define        DA9063_GPIO7_PIN_MASK                   0x30
+#define                DA9063_GPIO7_PIN_GPI            0x10
+#define                DA9063_GPIO7_PIN_GPO_PSS        0x20
+#define                DA9063_GPIO7_PIN_GPO            0x30
+#define        DA9063_GPIO7_TYPE                       0x40
+#define                DA9063_GPIO7_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO7_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO7_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO7_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO7_NO_WAKEUP                  0x80
+
+/* DA9063_REG_GPIO_8_9 (addr=0x19) */
+#define        DA9063_GPIO8_PIN_MASK                   0x03
+#define                DA9063_GPIO8_PIN_GPI_SYS_EN     0x00
+#define                DA9063_GPIO8_PIN_GPI            0x01
+#define                DA9063_GPIO8_PIN_GPO_PSS        0x02
+#define                DA9063_GPIO8_PIN_GPO            0x03
+#define        DA9063_GPIO8_TYPE                       0x04
+#define                DA9063_GPIO8_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO8_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO8_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO8_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO8_NO_WAKEUP                  0x08
+#define        DA9063_GPIO9_PIN_MASK                   0x30
+#define                DA9063_GPIO9_PIN_GPI_PWR_EN     0x00
+#define                DA9063_GPIO9_PIN_GPI            0x10
+#define                DA9063_GPIO9_PIN_GPO_PSS        0x20
+#define                DA9063_GPIO9_PIN_GPO            0x30
+#define        DA9063_GPIO9_TYPE                       0x40
+#define                DA9063_GPIO9_TYPE_GPI_ACT_LOW   0x00
+#define                DA9063_GPIO9_TYPE_GPO_VDD_IO1   0x00
+#define                DA9063_GPIO9_TYPE_GPI_ACT_HIGH  0x04
+#define                DA9063_GPIO9_TYPE_GPO_VDD_IO2   0x04
+#define        DA9063_GPIO9_NO_WAKEUP                  0x80
+
+/* DA9063_REG_GPIO_10_11 (addr=0x1A) */
+#define        DA9063_GPIO10_PIN_MASK                  0x03
+#define                DA9063_GPIO10_PIN_GPI_PWR1_EN   0x00
+#define                DA9063_GPIO10_PIN_GPI           0x01
+#define                DA9063_GPIO10_PIN_GPO_OD        0x02
+#define                DA9063_GPIO10_PIN_GPO           0x03
+#define        DA9063_GPIO10_TYPE                      0x04
+#define                DA9063_GPIO10_TYPE_GPI_ACT_LOW  0x00
+#define                DA9063_GPIO10_TYPE_GPO_VDD_IO1  0x00
+#define                DA9063_GPIO10_TYPE_GPI_ACT_HIGH 0x04
+#define                DA9063_GPIO10_TYPE_GPO_VDD_IO2  0x04
+#define        DA9063_GPIO10_NO_WAKEUP                 0x08
+#define        DA9063_GPIO11_PIN_MASK                  0x30
+#define                DA9063_GPIO11_PIN_GPO_OD        0x00
+#define                DA9063_GPIO11_PIN_GPI           0x10
+#define                DA9063_GPIO11_PIN_GPO_PSS       0x20
+#define                DA9063_GPIO11_PIN_GPO           0x30
+#define        DA9063_GPIO11_TYPE                      0x40
+#define                DA9063_GPIO11_TYPE_GPI_ACT_LOW  0x00
+#define                DA9063_GPIO11_TYPE_GPO_VDD_IO1  0x00
+#define                DA9063_GPIO11_TYPE_GPI_ACT_HIGH 0x04
+#define                DA9063_GPIO11_TYPE_GPO_VDD_IO2  0x04
+#define        DA9063_GPIO11_NO_WAKEUP                 0x80
+
+/* DA9063_REG_GPIO_12_13 (addr=0x1B) */
+#define        DA9063_GPIO12_PIN_MASK                  0x03
+#define                DA9063_GPIO12_PIN_NVDDFLT_OUT   0x00
+#define                DA9063_GPIO12_PIN_GPI           0x01
+#define                DA9063_GPIO12_PIN_VSYSMON_OUT   0x02
+#define                DA9063_GPIO12_PIN_GPO           0x03
+#define        DA9063_GPIO12_TYPE                      0x04
+#define                DA9063_GPIO12_TYPE_GPI_ACT_LOW  0x00
+#define                DA9063_GPIO12_TYPE_GPO_VDD_IO1  0x00
+#define                DA9063_GPIO12_TYPE_GPI_ACT_HIGH 0x04
+#define                DA9063_GPIO12_TYPE_GPO_VDD_IO2  0x04
+#define        DA9063_GPIO12_NO_WAKEUP                 0x08
+#define        DA9063_GPIO13_PIN_MASK                  0x30
+#define                DA9063_GPIO13_PIN_GPFB1_OUT     0x00
+#define                DA9063_GPIO13_PIN_GPI           0x10
+#define                DA9063_GPIO13_PIN_GPFB1_OUTOD   0x20
+#define                DA9063_GPIO13_PIN_GPO           0x30
+#define        DA9063_GPIO13_TYPE                      0x40
+#define                DA9063_GPIO13_TYPE_GPFB1_OUT    0x00
+#define                DA9063_GPIO13_TYPE_GPI          0x00
+#define                DA9063_GPIO13_TYPE_GPFB1_OUTOD  0x04
+#define                DA9063_GPIO13_TYPE_GPO          0x04
+#define        DA9063_GPIO13_NO_WAKEUP                 0x80
+
+/* DA9063_REG_GPIO_14_15 (addr=0x1C) */
+#define        DA9063_GPIO14_PIN_MASK                  0x03
+#define                DA9063_GPIO14_PIN_GPO_OD        0x00
+#define                DA9063_GPIO14_PIN_GPI           0x01
+#define                DA9063_GPIO14_PIN_HS2DATA       0x02
+#define                DA9063_GPIO14_PIN_GPO           0x03
+#define        DA9063_GPIO14_TYPE                      0x04
+#define                DA9063_GPIO14_TYPE_GPI_ACT_LOW  0x00
+#define                DA9063_GPIO14_TYPE_GPO_VDD_IO1  0x00
+#define                DA9063_GPIO14_TYPE_GPI_ACT_HIGH 0x04
+#define                DA9063_GPIO14_TYPE_GPO_VDD_IO2  0x04
+#define        DA9063_GPIO14_NO_WAKEUP                 0x08
+#define        DA9063_GPIO15_PIN_MASK                  0x30
+#define                DA9063_GPIO15_PIN_GPO_OD        0x00
+#define                DA9063_GPIO15_PIN_GPI           0x10
+#define                DA9063_GPIO15_PIN_GPO           0x30
+#define        DA9063_GPIO15_TYPE                      0x40
+#define                DA9063_GPIO15_TYPE_GPFB1_OUT    0x00
+#define                DA9063_GPIO15_TYPE_GPI          0x00
+#define                DA9063_GPIO15_TYPE_GPFB1_OUTOD  0x04
+#define                DA9063_GPIO15_TYPE_GPO          0x04
+#define        DA9063_GPIO15_NO_WAKEUP                 0x80
+
+/* DA9063_REG_GPIO_MODE_0_7 (addr=0x1D) */
+#define        DA9063_GPIO0_MODE                       0x01
+#define        DA9063_GPIO1_MODE                       0x02
+#define        DA9063_GPIO2_MODE                       0x04
+#define        DA9063_GPIO3_MODE                       0x08
+#define        DA9063_GPIO4_MODE                       0x10
+#define        DA9063_GPIO5_MODE                       0x20
+#define        DA9063_GPIO6_MODE                       0x40
+#define        DA9063_GPIO7_MODE                       0x80
+
+/* DA9063_REG_GPIO_MODE_8_15 (addr=0x1E) */
+#define        DA9063_GPIO8_MODE                       0x01
+#define        DA9063_GPIO9_MODE                       0x02
+#define        DA9063_GPIO10_MODE                      0x04
+#define        DA9063_GPIO11_MODE                      0x08
+#define                DA9063_GPIO11_MODE_LED_ACT_HIGH 0x00
+#define                DA9063_GPIO11_MODE_LED_ACT_LOW  0x08
+#define        DA9063_GPIO12_MODE                      0x10
+#define        DA9063_GPIO13_MODE                      0x20
+#define        DA9063_GPIO14_MODE                      0x40
+#define                DA9063_GPIO14_MODE_LED_ACT_HIGH 0x00
+#define                DA9063_GPIO14_MODE_LED_ACT_LOW  0x40
+#define        DA9063_GPIO15_MODE                      0x80
+#define                DA9063_GPIO15_MODE_LED_ACT_HIGH 0x00
+#define                DA9063_GPIO15_MODE_LED_ACT_LOW  0x80
+
+/* DA9063_REG_SWITCH_CONT (addr=0x1F) */
+#define        DA9063_CORE_SW_GPI_MASK                 0x03
+#define                DA9063_CORE_SW_GPI_OFF          0x00
+#define                DA9063_CORE_SW_GPI_GPIO1        0x01
+#define                DA9063_CORE_SW_GPI_GPIO2        0x02
+#define                DA9063_CORE_SW_GPI_GPIO13       0x03
+#define        DA9063_PERI_SW_GPI_MASK                 0x0C
+#define                DA9063_PERI_SW_GPI_OFF          0x00
+#define                DA9063_PERI_SW_GPI_GPIO1        0x04
+#define                DA9063_PERI_SW_GPI_GPIO2        0x08
+#define                DA9063_PERI_SW_GPI_GPIO13       0x0C
+#define        DA9063_SWITCH_SR_MASK                   0x30
+#define                DA9063_SWITCH_SR_1MV            0x00
+#define                DA9063_SWITCH_SR_5MV            0x10
+#define                DA9063_SWITCH_SR_10MV           0x20
+#define                DA9063_SWITCH_SR_50MV           0x30
+#define        DA9063_SWITCH_SR_DIS                    0x40
+#define        DA9063_CP_EN_MODE                       0x80
+
+/* DA9063_REGL_Bxxxx_CONT common bits (addr=0x20-0x25) */
+#define        DA9063_BUCK_EN                          0x01
+#define DA9063_BUCK_GPI_MASK                   0x06
+#define                DA9063_BUCK_GPI_OFF             0x00
+#define                DA9063_BUCK_GPI_GPIO1           0x02
+#define                DA9063_BUCK_GPI_GPIO2           0x04
+#define                DA9063_BUCK_GPI_GPIO13          0x06
+#define        DA9063_BUCK_CONF                        0x08
+#define        DA9063_VBUCK_GPI_MASK                   0x60
+#define                DA9063_VBUCK_GPI_OFF            0x00
+#define                DA9063_VBUCK_GPI_GPIO1          0x20
+#define                DA9063_VBUCK_GPI_GPIO2          0x40
+#define                DA9063_VBUCK_GPI_GPIO13         0x60
+
+/* DA9063_REG_BCORE1_CONT specific bits (addr=0x21) */
+#define        DA9063_CORE_SW_EN                       0x10
+#define        DA9063_CORE_SW_CONF                     0x80
+
+/* DA9063_REG_BPERI_CONT specific bits (addr=0x25) */
+#define        DA9063_PERI_SW_EN                       0x10
+#define        DA9063_PERI_SW_CONF                     0x80
+
+/* DA9063_REG_LDOx_CONT common bits (addr=0x26-0x30) */
+#define        DA9063_LDO_EN                           0x01
+#define DA9063_LDO_GPI_MASK                    0x06
+#define                DA9063_LDO_GPI_OFF              0x00
+#define                DA9063_LDO_GPI_GPIO1            0x02
+#define                DA9063_LDO_GPI_GPIO2            0x04
+#define                DA9063_LDO_GPI_GPIO13           0x06
+#define        DA9063_LDO_PD_DIS                       0x08
+#define        DA9063_VLDO_GPI_MASK                    0x60
+#define                DA9063_VLDO_GPI_OFF             0x00
+#define                DA9063_VLDO_GPI_GPIO1           0x20
+#define                DA9063_VLDO_GPI_GPIO2           0x40
+#define                DA9063_VLDO_GPI_GPIO13          0x60
+#define        DA9063_LDO_CONF                         0x80
+
+/* DA9063_REG_LDO5_CONT specific bits (addr=0x2A) */
+#define        DA9063_VLDO5_SEL                        0x10
+
+/* DA9063_REG_LDO6_CONT specific bits (addr=0x2B) */
+#define        DA9063_VLDO6_SEL                        0x10
+
+/* DA9063_REG_LDO7_CONT specific bits (addr=0x2C) */
+#define        DA9063_VLDO7_SEL                        0x10
+
+/* DA9063_REG_LDO8_CONT specific bits (addr=0x2D) */
+#define        DA9063_VLDO8_SEL                        0x10
+
+/* DA9063_REG_LDO9_CONT specific bits (addr=0x2E) */
+#define        DA9063_VLDO9_SEL                        0x10
+
+/* DA9063_REG_LDO10_CONT specific bits (addr=0x2F) */
+#define        DA9063_VLDO10_SEL                       0x10
+
+/* DA9063_REG_LDO11_CONT specific bits (addr=0x30) */
+#define        DA9063_VLDO11_SEL                       0x10
+
+/* DA9063_REG_VIB (addr=0x31) */
+#define DA9063_VIB_SET_MASK                    0x3F
+#define                DA9063_VIB_SET_OFF              0
+#define                DA9063_VIB_SET_MAX              0x3F
+
+/* DA9063_REG_DVC_1 (addr=0x32) */
+#define        DA9063_VBCORE1_SEL                      0x01
+#define        DA9063_VBCORE2_SEL                      0x02
+#define        DA9063_VBPRO_SEL                        0x04
+#define        DA9063_VBMEM_SEL                        0x08
+#define        DA9063_VBPERI_SEL                       0x10
+#define        DA9063_VLDO1_SEL                        0x20
+#define        DA9063_VLDO2_SEL                        0x40
+#define        DA9063_VLDO3_SEL                        0x80
+
+/* DA9063_REG_DVC_2 (addr=0x33) */
+#define        DA9063_VBIO_SEL                         0x01
+#define        DA9063_VLDO4_SEL                        0x80
+
+/* DA9063_REG_ADC_MAN (addr=0x34) */
+#define        DA9063_ADC_MUX_MASK                     0x0F
+#define                DA9063_ADC_MUX_VSYS             0x00
+#define                DA9063_ADC_MUX_ADCIN1           0x01
+#define                DA9063_ADC_MUX_ADCIN2           0x02
+#define                DA9063_ADC_MUX_ADCIN3           0x03
+#define                DA9063_ADC_MUX_T_SENSE          0x04
+#define                DA9063_ADC_MUX_VBBAT            0x05
+#define                DA9063_ADC_MUX_LDO_G1           0x08
+#define                DA9063_ADC_MUX_LDO_G2           0x09
+#define                DA9063_ADC_MUX_LDO_G3           0x0A
+#define        DA9063_ADC_MAN                          0x10
+#define        DA9063_ADC_MODE                         0x20
+
+/* DA9063_REG_ADC_CONT (addr=0x35) */
+#define        DA9063_ADC_AUTO_VSYS_EN                 0x01
+#define        DA9063_ADC_AUTO_AD1_EN                  0x02
+#define        DA9063_ADC_AUTO_AD2_EN                  0x04
+#define        DA9063_ADC_AUTO_AD3_EN                  0x08
+#define        DA9063_ADC_AD1_ISRC_EN                  0x10
+#define        DA9063_ADC_AD2_ISRC_EN                  0x20
+#define        DA9063_ADC_AD3_ISRC_EN                  0x40
+#define        DA9063_COMP1V2_EN                       0x80
+
+/* DA9063_REG_VSYS_MON (addr=0x36) */
+#define        DA9063_VSYS_VAL_MASK                    0xFF
+#define        DA9063_VSYS_VAL_BASE                    0x00
+
+/* DA9063_REG_ADC_RES_L (addr=0x37) */
+#define        DA9063_ADC_RES_L_BITS                   2
+#define        DA9063_ADC_RES_L_MASK                   0xC0
+
+/* DA9063_REG_ADC_RES_H (addr=0x38) */
+#define        DA9063_ADC_RES_M_BITS                   8
+#define        DA9063_ADC_RES_M_MASK                   0xFF
+
+/* DA9063_REG_(xxx_RES/ADC_RES_H) (addr=0x39-0x3F) */
+#define        DA9063_ADC_VAL_MASK                     0xFF
+
+/* DA9063_REG_COUNT_S (addr=0x40) */
+#define DA9063_RTC_READ                                0x80
+#define DA9063_COUNT_SEC_MASK                  0x3F
+
+/* DA9063_REG_COUNT_MI (addr=0x41) */
+#define DA9063_COUNT_MIN_MASK                  0x3F
+
+/* DA9063_REG_COUNT_H (addr=0x42) */
+#define DA9063_COUNT_HOUR_MASK                 0x1F
+
+/* DA9063_REG_COUNT_D (addr=0x43) */
+#define DA9063_COUNT_DAY_MASK                  0x1F
+
+/* DA9063_REG_COUNT_MO (addr=0x44) */
+#define DA9063_COUNT_MONTH_MASK                        0x0F
+
+/* DA9063_REG_COUNT_Y (addr=0x45) */
+#define DA9063_COUNT_YEAR_MASK                 0x3F
+#define DA9063_MONITOR                         0x40
+
+/* DA9063_REG_ALARM_MI (addr=0x46) */
+#define DA9063_ALARM_STATUS_ALARM              0x80
+#define DA9063_ALARM_STATUS_TICK               0x40
+#define DA9063_ALARM_MIN_MASK                  0x3F
+
+/* DA9063_REG_ALARM_H (addr=0x47) */
+#define DA9063_ALARM_HOUR_MASK                 0x1F
+
+/* DA9063_REG_ALARM_D (addr=0x48) */
+#define DA9063_ALARM_DAY_MASK                  0x1F
+
+/* DA9063_REG_ALARM_MO (addr=0x49) */
+#define DA9063_TICK_WAKE                       0x20
+#define DA9063_TICK_TYPE                       0x10
+#define                DA9063_TICK_TYPE_SEC            0x00
+#define                DA9063_TICK_TYPE_MIN            0x10
+#define DA9063_ALARM_MONTH_MASK                        0x0F
+
+/* DA9063_REG_ALARM_Y (addr=0x4A) */
+#define DA9063_TICK_ON                         0x80
+#define DA9063_ALARM_ON                                0x40
+#define DA9063_ALARM_YEAR_MASK                 0x3F
+
+/* DA9063_REG_WAIT (addr=0x97)*/
+#define        DA9063_REG_WAIT_TIME_MASK               0xF
+#define        DA9063_WAIT_TIME_0_US                   0x0
+#define        DA9063_WAIT_TIME_512_US                 0x1
+#define        DA9063_WAIT_TIME_1_MS                   0x2
+#define        DA9063_WAIT_TIME_2_MS                   0x3
+#define        DA9063_WAIT_TIME_4_1_MS                 0x4
+#define        DA9063_WAIT_TIME_8_2_MS                 0x5
+#define        DA9063_WAIT_TIME_16_4_MS                0x6
+#define        DA9063_WAIT_TIME_32_8_MS                0x7
+#define        DA9063_WAIT_TIME_65_5_MS                0x8
+#define        DA9063_WAIT_TIME_128_MS                 0x9
+#define        DA9063_WAIT_TIME_256_MS                 0xA
+#define        DA9063_WAIT_TIME_512_MS                 0xB
+#define        DA9063_WAIT_TIME_1_S                    0xC
+#define        DA9063_WAIT_TIME_2_1_S                  0xD
+
+/* DA9063_REG_EN_32K  (addr=0x98)*/
+#define        DA9063_STABILIZ_TIME_MASK               0x7
+#define        DA9063_CRYSTAL                          0x08
+#define        DA9063_DELAY_MODE                       0x10
+#define        DA9063_OUT_CLOCK                        0x20
+#define        DA9063_RTC_CLOCK                        0x40
+#define        DA9063_OUT_32K_EN                       0x80
+
+/* DA9063_REG_CHIP_VARIANT */
+#define        DA9063_CHIP_VARIANT_SHIFT               4
+
+/* DA9063_REG_BUCK_ILIM_A (addr=0x9A) */
+#define DA9063_BIO_ILIM_MASK                   0x0F
+#define DA9063_BMEM_ILIM_MASK                  0xF0
+
+/* DA9063_REG_BUCK_ILIM_B (addr=0x9B) */
+#define DA9063_BPRO_ILIM_MASK                  0x0F
+#define DA9063_BPERI_ILIM_MASK                 0xF0
+
+/* DA9063_REG_BUCK_ILIM_C (addr=0x9C) */
+#define DA9063_BCORE1_ILIM_MASK                        0x0F
+#define DA9063_BCORE2_ILIM_MASK                        0xF0
+
+/* DA9063_REG_Bxxxx_CFG common bits (addr=0x9D-0xA2) */
+#define DA9063_BUCK_FB_MASK                    0x07
+#define DA9063_BUCK_PD_DIS_SHIFT               5
+#define DA9063_BUCK_MODE_MASK                  0xC0
+#define                DA9063_BUCK_MODE_MANUAL         0x00
+#define                DA9063_BUCK_MODE_SLEEP          0x40
+#define                DA9063_BUCK_MODE_SYNC           0x80
+#define                DA9063_BUCK_MODE_AUTO           0xC0
+
+/* DA9063_REG_BPRO_CFG (addr=0x9F) */
+#define        DA9063_BPRO_VTTR_EN                     0x08
+#define        DA9063_BPRO_VTT_EN                      0x10
+
+/* DA9063_REG_VBxxxx_A/B (addr=0xA3-0xA8, 0xB4-0xB9) */
+#define DA9063_VBUCK_MASK                      0x7F
+#define DA9063_VBUCK_BIAS                      0
+#define DA9063_BUCK_SL                         0x80
+
+/* DA9063_REG_VLDOx_A/B (addr=0xA9-0x3, 0xBA-0xC4) */
+#define DA9063_LDO_SL                          0x80
+
+/* DA9063_REG_VLDO1_A/B (addr=0xA9, 0xBA) */
+#define DA9063_VLDO1_MASK                      0x3F
+#define DA9063_VLDO1_BIAS                      0
+
+/* DA9063_REG_VLDO2_A/B (addr=0xAA, 0xBB) */
+#define DA9063_VLDO2_MASK                      0x3F
+#define DA9063_VLDO2_BIAS                      0
+
+/* DA9063_REG_VLDO3_A/B (addr=0xAB, 0xBC) */
+#define DA9063_VLDO3_MASK                      0x7F
+#define DA9063_VLDO3_BIAS                      0
+
+/* DA9063_REG_VLDO4_A/B (addr=0xAC, 0xBD) */
+#define DA9063_VLDO4_MASK                      0x7F
+#define DA9063_VLDO4_BIAS                      0
+
+/* DA9063_REG_VLDO5_A/B (addr=0xAD, 0xBE) */
+#define DA9063_VLDO5_MASK                      0x3F
+#define DA9063_VLDO5_BIAS                      2
+
+/* DA9063_REG_VLDO6_A/B (addr=0xAE, 0xBF) */
+#define DA9063_VLDO6_MASK                      0x3F
+#define DA9063_VLDO6_BIAS                      2
+
+/* DA9063_REG_VLDO7_A/B (addr=0xAF, 0xC0) */
+#define DA9063_VLDO7_MASK                      0x3F
+#define DA9063_VLDO7_BIAS                      2
+
+/* DA9063_REG_VLDO8_A/B (addr=0xB0, 0xC1) */
+#define DA9063_VLDO8_MASK                      0x3F
+#define DA9063_VLDO8_BIAS                      2
+
+/* DA9063_REG_VLDO9_A/B (addr=0xB1, 0xC2) */
+#define DA9063_VLDO9_MASK                      0x3F
+#define DA9063_VLDO9_BIAS                      3
+
+/* DA9063_REG_VLDO10_A/B (addr=0xB2, 0xC3) */
+#define DA9063_VLDO10_MASK                     0x3F
+#define DA9063_VLDO10_BIAS                     2
+
+/* DA9063_REG_VLDO11_A/B (addr=0xB3, 0xC4) */
+#define DA9063_VLDO11_MASK                     0x3F
+#define DA9063_VLDO11_BIAS                     2
+
+/* DA9063_REG_GPO11_LED (addr=0xC6) */
+/* DA9063_REG_GPO14_LED (addr=0xC7) */
+/* DA9063_REG_GPO15_LED (addr=0xC8) */
+#define DA9063_GPIO_DIM                                0x80
+#define DA9063_GPIO_PWM_MASK                   0x7F
+
+/* DA9063_REG_CONFIG_H (addr=0x10D) */
+#define DA9063_PWM_CLK_MASK                    0x01
+#define                DA9063_PWM_CLK_PWM2MHZ          0x00
+#define                DA9063_PWM_CLK_PWM1MHZ          0x01
+#define DA9063_LDO8_MODE_MASK                  0x02
+#define                DA9063_LDO8_MODE_LDO            0
+#define                DA9063_LDO8_MODE_VIBR           0x02
+#define DA9063_MERGE_SENSE_MASK                        0x04
+#define                DA9063_MERGE_SENSE_GP_FB2       0x00
+#define                DA9063_MERGE_SENSE_GPIO4        0x04
+#define DA9063_BCORE_MERGE                     0x08
+#define DA9063_BPRO_OD                         0x10
+#define DA9063_BCORE2_OD                       0x20
+#define DA9063_BCORE1_OD                       0x40
+#define DA9063_BUCK_MERGE                      0x80
+
+/* DA9063_REG_CONFIG_I (addr=0x10E) */
+#define DA9063_NONKEY_PIN_MASK                 0x03
+#define                DA9063_NONKEY_PIN_PORT          0x00
+#define                DA9063_NONKEY_PIN_SWDOWN        0x01
+#define                DA9063_NONKEY_PIN_AUTODOWN      0x02
+#define                DA9063_NONKEY_PIN_AUTOFLPRT     0x03
+
+/* DA9063_REG_MON_REG_5 (addr=0x116) */
+#define DA9063_MON_A8_IDX_MASK                 0x07
+#define                DA9063_MON_A8_IDX_NONE          0x00
+#define                DA9063_MON_A8_IDX_BCORE1        0x01
+#define                DA9063_MON_A8_IDX_BCORE2        0x02
+#define                DA9063_MON_A8_IDX_BPRO          0x03
+#define                DA9063_MON_A8_IDX_LDO3          0x04
+#define                DA9063_MON_A8_IDX_LDO4          0x05
+#define                DA9063_MON_A8_IDX_LDO11         0x06
+#define DA9063_MON_A9_IDX_MASK                 0x70
+#define                DA9063_MON_A9_IDX_NONE          0x00
+#define                DA9063_MON_A9_IDX_BIO           0x01
+#define                DA9063_MON_A9_IDX_BMEM          0x02
+#define                DA9063_MON_A9_IDX_BPERI         0x03
+#define                DA9063_MON_A9_IDX_LDO1          0x04
+#define                DA9063_MON_A9_IDX_LDO2          0x05
+#define                DA9063_MON_A9_IDX_LDO5          0x06
+
+/* DA9063_REG_MON_REG_6 (addr=0x117) */
+#define DA9063_MON_A10_IDX_MASK                        0x07
+#define                DA9063_MON_A10_IDX_NONE         0x00
+#define                DA9063_MON_A10_IDX_LDO6         0x01
+#define                DA9063_MON_A10_IDX_LDO7         0x02
+#define                DA9063_MON_A10_IDX_LDO8         0x03
+#define                DA9063_MON_A10_IDX_LDO9         0x04
+#define                DA9063_MON_A10_IDX_LDO10        0x05
+
+#endif /* _DA9063_REG_H */
index 13a1ee95a2334bdda6fed40c3e8dbf36a9784012..5166935ce66df46748e1b173ad8cfc2b6379b011 100644 (file)
@@ -30,6 +30,8 @@
 
 #include <mach/hardware.h>
 
+struct regmap;
+
 /*
  * Register values.
  */
@@ -113,6 +115,7 @@ struct davinci_vc {
 
        /* Memory resources */
        void __iomem *base;
+       struct regmap *regmap;
 
        /* MFD cells */
        struct mfd_cell cells[DAVINCI_VC_CELLS];
index a9e8bd157673a475ebfb5d78e81f0b8d6d621ed6..f682953043ba9c81686ef35293d0274d402b5326 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef MCP_H
 #define MCP_H
 
+#include <linux/device.h>
+
 struct mcp_ops;
 
 struct mcp {
index 37e48c9577914b6de786ce20b9009c5f2a998f46..9974e387e483001746e680e8a1129680f8af45f3 100644 (file)
@@ -184,6 +184,50 @@ enum palmas_regulators {
        PALMAS_NUM_REGS,
 };
 
+/* External controll signal name */
+enum {
+       PALMAS_EXT_CONTROL_ENABLE1      = 0x1,
+       PALMAS_EXT_CONTROL_ENABLE2      = 0x2,
+       PALMAS_EXT_CONTROL_NSLEEP       = 0x4,
+};
+
+/*
+ * Palmas device resources can be controlled externally for
+ * enabling/disabling it rather than register write through i2c.
+ * Add the external controlled requestor ID for different resources.
+ */
+enum palmas_external_requestor_id {
+       PALMAS_EXTERNAL_REQSTR_ID_REGEN1,
+       PALMAS_EXTERNAL_REQSTR_ID_REGEN2,
+       PALMAS_EXTERNAL_REQSTR_ID_SYSEN1,
+       PALMAS_EXTERNAL_REQSTR_ID_SYSEN2,
+       PALMAS_EXTERNAL_REQSTR_ID_CLK32KG,
+       PALMAS_EXTERNAL_REQSTR_ID_CLK32KGAUDIO,
+       PALMAS_EXTERNAL_REQSTR_ID_REGEN3,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS12,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS3,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS45,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS6,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS7,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS8,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS9,
+       PALMAS_EXTERNAL_REQSTR_ID_SMPS10,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO1,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO2,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO3,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO4,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO5,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO6,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO7,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO8,
+       PALMAS_EXTERNAL_REQSTR_ID_LDO9,
+       PALMAS_EXTERNAL_REQSTR_ID_LDOLN,
+       PALMAS_EXTERNAL_REQSTR_ID_LDOUSB,
+
+       /* Last entry */
+       PALMAS_EXTERNAL_REQSTR_ID_MAX,
+};
+
 struct palmas_pmic_platform_data {
        /* An array of pointers to regulator init data indexed by regulator
         * ID
@@ -259,6 +303,7 @@ struct palmas_platform_data {
         */
        int mux_from_pdata;
        u8 pad1, pad2;
+       bool pm_off;
 
        struct palmas_pmic_platform_data *pmic_pdata;
        struct palmas_gpadc_platform_data *gpadc_pdata;
@@ -2878,4 +2923,9 @@ static inline int palmas_irq_get_virq(struct palmas *palmas, int irq)
        return regmap_irq_get_virq(palmas->irq_data, irq);
 }
 
+
+int palmas_ext_control_req_config(struct palmas *palmas,
+       enum palmas_external_requestor_id ext_control_req_id,
+       int ext_ctrl, bool enable);
+
 #endif /*  __LINUX_MFD_PALMAS_H */
index 2b13970596f53732cda07a6fd3b270cc9e933e5b..443176ee1ab04e1f9d2788b51d700eb2a913610c 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek driver-based card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #ifndef __RTSX_COMMON_H
index 7a9f7089435dcb21d50c7ff902c14f6c76bd3317..d1382dfbeff022b5f91dfcf6789ece80874eea5b 100644 (file)
@@ -1,6 +1,6 @@
 /* Driver for Realtek PCI-Express card reader
  *
- * Copyright(c) 2009 Realtek Semiconductor Corp. All rights reserved.
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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
@@ -17,7 +17,6 @@
  *
  * Author:
  *   Wei WANG <wei_wang@realsil.com.cn>
- *   No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China
  */
 
 #ifndef __RTSX_PCI_H
@@ -25,8 +24,7 @@
 
 #include <linux/sched.h>
 #include <linux/pci.h>
-
-#include "rtsx_common.h"
+#include <linux/mfd/rtsx_common.h>
 
 #define MAX_RW_REG_CNT                 1024
 
 #define CARD_SHARE_BAROSSA_SD          0x01
 #define CARD_SHARE_BAROSSA_MS          0x02
 
+/* CARD_DRIVE_SEL */
+#define MS_DRIVE_8mA                   (0x01 << 6)
+#define MMC_DRIVE_8mA                  (0x01 << 4)
+#define XD_DRIVE_8mA                   (0x01 << 2)
+#define GPIO_DRIVE_8mA                 0x01
+#define RTS5209_CARD_DRIVE_DEFAULT     (MS_DRIVE_8mA | MMC_DRIVE_8mA |\
+                                               XD_DRIVE_8mA | GPIO_DRIVE_8mA)
+#define RTL8411_CARD_DRIVE_DEFAULT     (MS_DRIVE_8mA | MMC_DRIVE_8mA |\
+                                               XD_DRIVE_8mA)
+#define RTSX_CARD_DRIVE_DEFAULT                (MS_DRIVE_8mA | GPIO_DRIVE_8mA)
+
 /* SD30_DRIVE_SEL */
 #define DRIVER_TYPE_A                  0x05
 #define DRIVER_TYPE_B                  0x03
 #define DRIVER_TYPE_C                  0x02
 #define DRIVER_TYPE_D                  0x01
+#define CFG_DRIVER_TYPE_A              0x02
+#define CFG_DRIVER_TYPE_B              0x03
+#define CFG_DRIVER_TYPE_C              0x01
+#define CFG_DRIVER_TYPE_D              0x00
 
 /* FPDCTL */
 #define SSC_POWER_DOWN                 0x01
 #define SAMPLE_VAR_CLK0                        (0x01 << 4)
 #define SAMPLE_VAR_CLK1                        (0x02 << 4)
 
+/* HOST_SLEEP_STATE */
+#define HOST_ENTER_S1                  1
+#define HOST_ENTER_S3                  2
+
 #define MS_CFG                         0xFD40
 #define MS_TPC                         0xFD41
 #define MS_TRANS_CFG                   0xFD42
 #define PME_FORCE_CTL                  0xFE56
 #define ASPM_FORCE_CTL                 0xFE57
 #define PM_CLK_FORCE_CTL               0xFE58
+#define FUNC_FORCE_CTL                 0xFE59
 #define PERST_GLITCH_WIDTH             0xFE5C
 #define CHANGE_LINK_STATE              0xFE5B
 #define RESET_LOAD_REG                 0xFE5E
 
 #define DUMMY_REG_RESET_0              0xFE90
 
+#define AUTOLOAD_CFG_BASE              0xFF00
+
+#define PM_CTRL1                       0xFF44
+#define PM_CTRL2                       0xFF45
+#define PM_CTRL3                       0xFF46
+#define PM_CTRL4                       0xFF47
+
 /* Memory mapping */
 #define SRAM_BASE                      0xE600
 #define RBUF_BASE                      0xF400
 #define PHY_FLD4                       0x1E
 #define PHY_DUM_REG                    0x1F
 
+#define LCTLR                          0x80
+#define PCR_SETTING_REG1               0x724
+#define PCR_SETTING_REG2               0x814
+#define PCR_SETTING_REG3               0x747
+
 #define rtsx_pci_init_cmd(pcr)         ((pcr)->ci = 0)
 
 struct rtsx_pcr;
@@ -747,6 +777,8 @@ struct pcr_ops {
                                                u8 voltage);
        unsigned int    (*cd_deglitch)(struct rtsx_pcr *pcr);
        int             (*conv_clk_and_div_n)(int clk, int dir);
+       void            (*fetch_vendor_settings)(struct rtsx_pcr *pcr);
+       void            (*force_power_down)(struct rtsx_pcr *pcr, u8 pm_state);
 };
 
 enum PDEV_STAT  {PDEV_STAT_IDLE, PDEV_STAT_RUN};
@@ -788,7 +820,6 @@ struct rtsx_pcr {
        struct completion               *finish_me;
 
        unsigned int                    cur_clock;
-       bool                            ms_pmos;
        bool                            remove_pci;
        bool                            msi_en;
 
@@ -806,6 +837,19 @@ struct rtsx_pcr {
 #define IC_VER_D                       3
        u8                              ic_version;
 
+       u8                              sd30_drive_sel_1v8;
+       u8                              sd30_drive_sel_3v3;
+       u8                              card_drive_sel;
+#define ASPM_L1_EN                     0x02
+       u8                              aspm_en;
+
+#define PCR_MS_PMOS                    (1 << 0)
+#define PCR_REVERSE_SOCKET             (1 << 1)
+       u32                             flags;
+
+       u32                             tx_initial_phase;
+       u32                             rx_initial_phase;
+
        const u32                       *sd_pull_ctl_enable_tbl;
        const u32                       *sd_pull_ctl_disable_tbl;
        const u32                       *ms_pull_ctl_enable_tbl;
@@ -822,6 +866,18 @@ struct rtsx_pcr {
 #define PCI_VID(pcr)                   ((pcr)->pci->vendor)
 #define PCI_PID(pcr)                   ((pcr)->pci->device)
 
+#define SDR104_PHASE(val)              ((val) & 0xFF)
+#define SDR50_PHASE(val)               (((val) >> 8) & 0xFF)
+#define DDR50_PHASE(val)               (((val) >> 16) & 0xFF)
+#define SDR104_TX_PHASE(pcr)           SDR104_PHASE((pcr)->tx_initial_phase)
+#define SDR50_TX_PHASE(pcr)            SDR50_PHASE((pcr)->tx_initial_phase)
+#define DDR50_TX_PHASE(pcr)            DDR50_PHASE((pcr)->tx_initial_phase)
+#define SDR104_RX_PHASE(pcr)           SDR104_PHASE((pcr)->rx_initial_phase)
+#define SDR50_RX_PHASE(pcr)            SDR50_PHASE((pcr)->rx_initial_phase)
+#define DDR50_RX_PHASE(pcr)            DDR50_PHASE((pcr)->rx_initial_phase)
+#define SET_CLOCK_PHASE(sdr104, sdr50, ddr50)  \
+                               (((ddr50) << 16) | ((sdr50) << 8) | (sdr104))
+
 void rtsx_pci_start_run(struct rtsx_pcr *pcr);
 int rtsx_pci_write_register(struct rtsx_pcr *pcr, u16 addr, u8 mask, u8 data);
 int rtsx_pci_read_register(struct rtsx_pcr *pcr, u16 addr, u8 *data);
index d0d52ea6007439c18c3cf17bb71961187da72026..b3ddf98dec3734ea7c4fc483a2efacc8cd7dfcad 100644 (file)
@@ -167,11 +167,8 @@ enum s2mps11_regulators {
        S2MPS11_BUCK8,
        S2MPS11_BUCK9,
        S2MPS11_BUCK10,
-       S2MPS11_AP_EN32KHZ,
-       S2MPS11_CP_EN32KHZ,
-       S2MPS11_BT_EN32KHZ,
 
-       S2MPS11_REG_MAX,
+       S2MPS11_REGULATOR_MAX,
 };
 
 #define S2MPS11_BUCK_MIN1      600000
@@ -203,6 +200,5 @@ enum s2mps11_regulators {
 #define S2MPS11_BUCK4_RAMP_EN_SHIFT    1
 #define S2MPS11_BUCK6_RAMP_EN_SHIFT    0
 #define S2MPS11_PMIC_EN_SHIFT  6
-#define S2MPS11_REGULATOR_MAX (S2MPS11_REG_MAX - 3)
 
 #endif /*  __LINUX_MFD_S2MPS11_H */
index db1791bb997ae495d65637e506b6f13ab4945b6d..25f2c611ab013db8e3a4135a00c129b3d556e7d5 100644 (file)
 #define SEQ_STATUS BIT(5)
 
 #define ADC_CLK                        3000000
-#define        MAX_CLK_DIV             7
 #define TOTAL_STEPS            16
 #define TOTAL_CHANNELS         8
 
index ce3511326f801d90f630667569685cf8c63dafb0..b22883d60500ee540315f6bdd56e2e9f11be56aa 100644 (file)
@@ -108,7 +108,6 @@ struct tmio_mmc_data {
        unsigned int                    cd_gpio;
        void (*set_pwr)(struct platform_device *host, int state);
        void (*set_clk_div)(struct platform_device *host, int state);
-       int (*get_cd)(struct platform_device *host);
        int (*write16_hook)(struct tmio_mmc_host *host, int addr);
        /* clock management callbacks */
        int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
index 7e7fbce7a30874ddca4c06bc37359042902c983b..81f639bc1ae671c3e8d6671c4a16004977387704 100644 (file)
 
 #define TWL6040_GPO_MAX        3
 
+/* TODO: All platform data struct can be removed */
 struct twl6040_codec_data {
        u16 hs_left_step;
        u16 hs_right_step;
@@ -229,7 +230,6 @@ struct twl6040 {
        int audpwron;
        int power_count;
        int rev;
-       u8 vibra_ctrl_cache[2];
 
        /* PLL configuration */
        int pll;
index 28af417563609b50bbff851bea7e0fb4692c966d..88f90cbf8e6a0a2588aea4e023a5594cb19528a4 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef UCB1200_H
 #define UCB1200_H
 
+#include <linux/device.h>
 #include <linux/mfd/mcp.h>
 #include <linux/gpio.h>
 #include <linux/mutex.h>
index a405d3dc0f61f0bd9609a580e17c5bd14127e39a..8d3c57fdf2213cd21625ea2b5f871462093c0921 100644 (file)
@@ -41,8 +41,6 @@ extern int migrate_page(struct address_space *,
                        struct page *, struct page *, enum migrate_mode);
 extern int migrate_pages(struct list_head *l, new_page_t x,
                unsigned long private, enum migrate_mode mode, int reason);
-extern int migrate_huge_page(struct page *, new_page_t x,
-               unsigned long private, enum migrate_mode mode);
 
 extern int fail_migrate_page(struct address_space *,
                        struct page *, struct page *);
@@ -55,6 +53,9 @@ extern int migrate_vmas(struct mm_struct *mm,
 extern void migrate_page_copy(struct page *newpage, struct page *page);
 extern int migrate_huge_page_move_mapping(struct address_space *mapping,
                                  struct page *newpage, struct page *page);
+extern int migrate_page_move_mapping(struct address_space *mapping,
+               struct page *newpage, struct page *page,
+               struct buffer_head *head, enum migrate_mode mode);
 #else
 
 static inline void putback_lru_pages(struct list_head *l) {}
@@ -62,9 +63,6 @@ static inline void putback_movable_pages(struct list_head *l) {}
 static inline int migrate_pages(struct list_head *l, new_page_t x,
                unsigned long private, enum migrate_mode mode, int reason)
        { return -ENOSYS; }
-static inline int migrate_huge_page(struct page *page, new_page_t x,
-               unsigned long private, enum migrate_mode mode)
-       { return -ENOSYS; }
 
 static inline int migrate_prep(void) { return -ENOSYS; }
 static inline int migrate_prep_local(void) { return -ENOSYS; }
index d2d59b4149d06536d552d402cc872186f6f5ac74..8b6e55ee885576d3dc3613a23a990cd20da4bfed 100644 (file)
@@ -115,6 +115,12 @@ extern unsigned int kobjsize(const void *objp);
 #define VM_ARCH_1      0x01000000      /* Architecture-specific flag */
 #define VM_DONTDUMP    0x04000000      /* Do not include in the core dump */
 
+#ifdef CONFIG_MEM_SOFT_DIRTY
+# define VM_SOFTDIRTY  0x08000000      /* Not soft dirty clean area */
+#else
+# define VM_SOFTDIRTY  0
+#endif
+
 #define VM_MIXEDMAP    0x10000000      /* Can contain "struct page" and pure PFN pages */
 #define VM_HUGEPAGE    0x20000000      /* MADV_HUGEPAGE marked this vma */
 #define VM_NOHUGEPAGE  0x40000000      /* MADV_NOHUGEPAGE marked this vma */
@@ -170,6 +176,7 @@ extern pgprot_t protection_map[16];
 #define FAULT_FLAG_RETRY_NOWAIT        0x10    /* Don't drop mmap_sem and wait when retrying */
 #define FAULT_FLAG_KILLABLE    0x20    /* The fault task is in SIGKILL killable region */
 #define FAULT_FLAG_TRIED       0x40    /* second try */
+#define FAULT_FLAG_USER                0x80    /* The fault originated in userspace */
 
 /*
  * vm_fault is filled by the the pagefault handler and passed to the vma's
@@ -489,20 +496,6 @@ static inline int compound_order(struct page *page)
        return (unsigned long)page[1].lru.prev;
 }
 
-static inline int compound_trans_order(struct page *page)
-{
-       int order;
-       unsigned long flags;
-
-       if (!PageHead(page))
-               return 0;
-
-       flags = compound_lock_irqsave(page);
-       order = compound_order(page);
-       compound_unlock_irqrestore(page, flags);
-       return order;
-}
-
 static inline void set_compound_order(struct page *page, unsigned long order)
 {
        page[1].lru.prev = (void *)order;
@@ -637,12 +630,12 @@ static inline enum zone_type page_zonenum(const struct page *page)
 #endif
 
 /*
- * The identification function is only used by the buddy allocator for
- * determining if two pages could be buddies. We are not really
- * identifying a zone since we could be using a the section number
- * id if we have not node id available in page flags.
- * We guarantee only that it will return the same value for two
- * combinable pages in a zone.
+ * The identification function is mainly used by the buddy allocator for
+ * determining if two pages could be buddies. We are not really identifying
+ * the zone since we could be using the section number id if we do not have
+ * node id available in page flags.
+ * We only guarantee that it will return the same value for two combinable
+ * pages in a zone.
  */
 static inline int page_zone_id(struct page *page)
 {
@@ -884,11 +877,12 @@ static inline int page_mapped(struct page *page)
 #define VM_FAULT_NOPAGE        0x0100  /* ->fault installed the pte, not return page */
 #define VM_FAULT_LOCKED        0x0200  /* ->fault locked the returned page */
 #define VM_FAULT_RETRY 0x0400  /* ->fault blocked, must retry */
+#define VM_FAULT_FALLBACK 0x0800       /* huge page fault failed, fall back to small */
 
 #define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */
 
 #define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_HWPOISON | \
-                        VM_FAULT_HWPOISON_LARGE)
+                        VM_FAULT_FALLBACK | VM_FAULT_HWPOISON_LARGE)
 
 /* Encode hstate index for a hwpoisoned large page */
 #define VM_FAULT_SET_HINDEX(x) ((x) << 12)
@@ -992,7 +986,7 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping,
        unmap_mapping_range(mapping, holebegin, holelen, 0);
 }
 
-extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new);
+extern void truncate_pagecache(struct inode *inode, loff_t new);
 extern void truncate_setsize(struct inode *inode, loff_t newsize);
 void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end);
 int truncate_inode_page(struct address_space *mapping, struct page *page);
index 1397ccf81e91f16d937c3f0b2e7d361104dce5f1..cf55945c83fb91d18bdaef4f0d893d6a94fa9034 100644 (file)
@@ -2,6 +2,7 @@
 #define LINUX_MM_INLINE_H
 
 #include <linux/huge_mm.h>
+#include <linux/swap.h>
 
 /**
  * page_is_file_cache - should the page be on a file LRU or anon LRU?
index faf4b7c1ad12702db919bd03a448741b7e579789..d9851eeb6e1d183ca2c49e3dffcc4e1a1443510e 100644 (file)
@@ -322,6 +322,7 @@ struct mm_rss_stat {
        atomic_long_t count[NR_MM_COUNTERS];
 };
 
+struct kioctx_table;
 struct mm_struct {
        struct vm_area_struct * mmap;           /* list of VMAs */
        struct rb_root mm_rb;
@@ -383,8 +384,8 @@ struct mm_struct {
 
        struct core_state *core_state; /* coredumping support */
 #ifdef CONFIG_AIO
-       spinlock_t              ioctx_lock;
-       struct hlist_head       ioctx_list;
+       spinlock_t                      ioctx_lock;
+       struct kioctx_table __rcu       *ioctx_table;
 #endif
 #ifdef CONFIG_MM_OWNER
        /*
index 443243b241d5fcce816f4f269a95bed7c16a6878..da51bec578c33043c156d6661668e8957f5cb86f 100644 (file)
@@ -208,6 +208,8 @@ static inline void mmc_claim_host(struct mmc_host *host)
        __mmc_claim_host(host, NULL);
 }
 
+struct device_node;
 extern u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max);
+extern int mmc_of_parse_voltage(struct device_node *np, u32 *mask);
 
 #endif /* LINUX_MMC_CORE_H */
index e3c6a74d980adc43312c35184f1b581261177ed4..3e781b8c0be74dd76e658c4ba78ecbb72516e153 100644 (file)
@@ -171,6 +171,7 @@ struct sdhci_host {
        unsigned int            ocr_avail_sdio; /* OCR bit masks */
        unsigned int            ocr_avail_sd;
        unsigned int            ocr_avail_mmc;
+       u32 ocr_mask;           /* available voltages */
 
        wait_queue_head_t       buf_ready_int;  /* Waitqueue for Buffer Read Ready interrupt */
        unsigned int            tuning_done;    /* Condition flag set when CMD19 succeeds */
index e7d5dd67bb74fa42fbac10a67840667bc6c8e062..ccd8fb2cad522b6d967b05e760ce8634dcbf9106 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/io.h>
 #include <linux/platform_device.h>
-#include <linux/sh_dma.h>
 
 /*
  * MMCIF : CE_CLK_CTRL [19:16]
  */
 
 struct sh_mmcif_plat_data {
-       void (*set_pwr)(struct platform_device *pdev, int state);
-       void (*down_pwr)(struct platform_device *pdev);
        int (*get_cd)(struct platform_device *pdef);
        unsigned int            slave_id_tx;    /* embedded slave_id_[tr]x */
        unsigned int            slave_id_rx;
        bool                    use_cd_gpio : 1;
+       bool                    ccs_unsupported : 1;
+       bool                    clk_ctrl2_present : 1;
        unsigned int            cd_gpio;
        u8                      sup_pclk;       /* 1 :SH7757, 0: SH7724/SH7372 */
        unsigned long           caps;
@@ -62,6 +61,7 @@ struct sh_mmcif_plat_data {
 #define MMCIF_CE_INT_MASK      0x00000044
 #define MMCIF_CE_HOST_STS1     0x00000048
 #define MMCIF_CE_HOST_STS2     0x0000004C
+#define MMCIF_CE_CLK_CTRL2     0x00000070
 #define MMCIF_CE_VERSION       0x0000007C
 
 /* CE_BUF_ACC */
index b76bcf0621f69ddd6b16723744b95e4be6034b23..68927ae50845c73de623d14f87b00af368d3672a 100644 (file)
@@ -25,8 +25,6 @@ struct sh_mobile_sdhi_info {
        unsigned long tmio_caps2;
        u32 tmio_ocr_mask;      /* available MMC voltages */
        unsigned int cd_gpio;
-       void (*set_pwr)(struct platform_device *pdev, int state);
-       int (*get_cd)(struct platform_device *pdev);
 
        /* callbacks for board specific setup code */
        int (*init)(struct platform_device *pdev,
index 7d88d27bfafaf9a337dc201bc8b3296b59fdb6d1..b0c73e4cacea1484fe4790a49514cb004e0af024 100644 (file)
@@ -18,7 +18,8 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio);
 void mmc_gpio_free_ro(struct mmc_host *host);
 
 int mmc_gpio_get_cd(struct mmc_host *host);
-int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio);
+int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
+                       unsigned int debounce);
 void mmc_gpio_free_cd(struct mmc_host *host);
 
 #endif
index af4a3b77a8decfce07e5129f2e932d41fa7271c0..bd791e452ad7a96329d883afba92ffbdf7bbc9bc 100644 (file)
@@ -105,6 +105,7 @@ struct zone_padding {
 enum zone_stat_item {
        /* First 128 byte cacheline (assuming 64 bit words) */
        NR_FREE_PAGES,
+       NR_ALLOC_BATCH,
        NR_LRU_BASE,
        NR_INACTIVE_ANON = NR_LRU_BASE, /* must match order of LRU_[IN]ACTIVE */
        NR_ACTIVE_ANON,         /*  "     "     "   "       "         */
@@ -352,7 +353,6 @@ struct zone {
         * free areas of different sizes
         */
        spinlock_t              lock;
-       int                     all_unreclaimable; /* All pages pinned */
 #if defined CONFIG_COMPACTION || defined CONFIG_CMA
        /* Set to true when the PG_migrate_skip bits should be cleared */
        bool                    compact_blockskip_flush;
index 211ff67e8b0d0c3def3389ed474ab098112fa749..95fc482cef36cb12c78ba0eade0da4f8d717b3cb 100644 (file)
@@ -93,8 +93,6 @@ struct nand_bbt_descr {
 #define NAND_BBT_CREATE_EMPTY  0x00000400
 /* Search good / bad pattern through all pages of a block */
 #define NAND_BBT_SCANALLPAGES  0x00000800
-/* Scan block empty during good / bad block scan */
-#define NAND_BBT_SCANEMPTY     0x00001000
 /* Write bbt if neccecary */
 #define NAND_BBT_WRITE         0x00002000
 /* Read and write back block contents when writing bbt */
index d6ed61ef451df403377f77e010a52711dac8e5a9..c8be32e9fc49507702d187a33893f8f3870a38ef 100644 (file)
@@ -137,6 +137,7 @@ enum access_mode {
 
 /**
  * fsmc_nand_platform_data - platform specific NAND controller config
+ * @nand_timings: timing setup for the physical NAND interface
  * @partitions: partition table for the platform, use a default fallback
  * if this is NULL
  * @nr_partitions: the number of partitions in the previous entry
index a5cf4e8d68187e5bd5e7892effc0957dc5bfea0b..f9bfe526d3102175ab3d32149966f61aab35da62 100644 (file)
@@ -173,6 +173,9 @@ struct mtd_info {
        /* ECC layout structure pointer - read only! */
        struct nand_ecclayout *ecclayout;
 
+       /* the ecc step size. */
+       unsigned int ecc_step_size;
+
        /* max number of correctible bit errors per ecc step */
        unsigned int ecc_strength;
 
index ab6363443ce81f033b641b014102a2dfdf8921be..ac8e89d5a7929b6bdd40c424928a7d0d9872a73e 100644 (file)
@@ -56,7 +56,7 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
  * is supported now. If you add a chip with bigger oobsize/page
  * adjust this accordingly.
  */
-#define NAND_MAX_OOBSIZE       640
+#define NAND_MAX_OOBSIZE       744
 #define NAND_MAX_PAGESIZE      8192
 
 /*
@@ -202,6 +202,10 @@ typedef enum {
 /* Keep gcc happy */
 struct nand_chip;
 
+/* ONFI features */
+#define ONFI_FEATURE_16_BIT_BUS                (1 << 0)
+#define ONFI_FEATURE_EXT_PARAM_PAGE    (1 << 7)
+
 /* ONFI timing mode, used in both asynchronous and synchronous mode */
 #define ONFI_TIMING_MODE_0             (1 << 0)
 #define ONFI_TIMING_MODE_1             (1 << 1)
@@ -217,6 +221,9 @@ struct nand_chip;
 /* ONFI subfeature parameters length */
 #define ONFI_SUBFEATURE_PARAM_LEN      4
 
+/* ONFI optional commands SET/GET FEATURES supported? */
+#define ONFI_OPT_CMD_SET_GET_FEATURES  (1 << 2)
+
 struct nand_onfi_params {
        /* rev info and features block */
        /* 'O' 'N' 'F' 'I'  */
@@ -224,7 +231,10 @@ struct nand_onfi_params {
        __le16 revision;
        __le16 features;
        __le16 opt_cmd;
-       u8 reserved[22];
+       u8 reserved0[2];
+       __le16 ext_param_page_length; /* since ONFI 2.1 */
+       u8 num_of_param_pages;        /* since ONFI 2.1 */
+       u8 reserved1[17];
 
        /* manufacturer information block */
        char manufacturer[12];
@@ -281,6 +291,40 @@ struct nand_onfi_params {
 
 #define ONFI_CRC_BASE  0x4F4E
 
+/* Extended ECC information Block Definition (since ONFI 2.1) */
+struct onfi_ext_ecc_info {
+       u8 ecc_bits;
+       u8 codeword_size;
+       __le16 bb_per_lun;
+       __le16 block_endurance;
+       u8 reserved[2];
+} __packed;
+
+#define ONFI_SECTION_TYPE_0    0       /* Unused section. */
+#define ONFI_SECTION_TYPE_1    1       /* for additional sections. */
+#define ONFI_SECTION_TYPE_2    2       /* for ECC information. */
+struct onfi_ext_section {
+       u8 type;
+       u8 length;
+} __packed;
+
+#define ONFI_EXT_SECTION_MAX 8
+
+/* Extended Parameter Page Definition (since ONFI 2.1) */
+struct onfi_ext_param_page {
+       __le16 crc;
+       u8 sig[4];             /* 'E' 'P' 'P' 'S' */
+       u8 reserved0[10];
+       struct onfi_ext_section sections[ONFI_EXT_SECTION_MAX];
+
+       /*
+        * The actual size of the Extended Parameter Page is in
+        * @ext_param_page_length of nand_onfi_params{}.
+        * The following are the variable length sections.
+        * So we do not add any fields below. Please see the ONFI spec.
+        */
+} __packed;
+
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * @lock:               protection lock
@@ -390,8 +434,8 @@ struct nand_buffers {
  * @write_buf:         [REPLACEABLE] write data from the buffer to the chip
  * @read_buf:          [REPLACEABLE] read data from the chip into the buffer
  * @select_chip:       [REPLACEABLE] select chip nr
- * @block_bad:         [REPLACEABLE] check, if the block is bad
- * @block_markbad:     [REPLACEABLE] mark the block bad
+ * @block_bad:         [REPLACEABLE] check if a block is bad, using OOB markers
+ * @block_markbad:     [REPLACEABLE] mark a block bad
  * @cmd_ctrl:          [BOARDSPECIFIC] hardwarespecific function for controlling
  *                     ALE/CLE/nCE. Also used to write command and address
  * @init_size:         [BOARDSPECIFIC] hardwarespecific function for setting
@@ -434,6 +478,12 @@ struct nand_buffers {
  *                     bad block marker position; i.e., BBM == 11110111b is
  *                     not bad when badblockbits == 7
  * @cellinfo:          [INTERN] MLC/multichip data from chip ident
+ * @ecc_strength_ds:   [INTERN] ECC correctability from the datasheet.
+ *                     Minimum amount of bit errors per @ecc_step_ds guaranteed
+ *                     to be correctable. If unknown, set to zero.
+ * @ecc_step_ds:       [INTERN] ECC step required by the @ecc_strength_ds,
+ *                      also from the datasheet. It is the recommended ECC step
+ *                     size, if known; if unknown, set to zero.
  * @numchips:          [INTERN] number of physical chips
  * @chipsize:          [INTERN] the size of one chip for multichip arrays
  * @pagemask:          [INTERN] page number mask = number of (pages / chip) - 1
@@ -510,6 +560,8 @@ struct nand_chip {
        unsigned int pagebuf_bitflips;
        int subpagesize;
        uint8_t cellinfo;
+       uint16_t ecc_strength_ds;
+       uint16_t ecc_step_ds;
        int badblockpos;
        int badblockbits;
 
@@ -576,6 +628,11 @@ struct nand_chip {
        { .name = (nm), {{ .dev_id = (devid) }}, .chipsize = (chipsz), \
          .options = (opts) }
 
+#define NAND_ECC_INFO(_strength, _step)        \
+                       { .strength_ds = (_strength), .step_ds = (_step) }
+#define NAND_ECC_STRENGTH(type)                ((type)->ecc.strength_ds)
+#define NAND_ECC_STEP(type)            ((type)->ecc.step_ds)
+
 /**
  * struct nand_flash_dev - NAND Flash Device ID Structure
  * @name: a human-readable name of the NAND chip
@@ -593,6 +650,12 @@ struct nand_chip {
  * @options: stores various chip bit options
  * @id_len: The valid length of the @id.
  * @oobsize: OOB size
+ * @ecc.strength_ds: The ECC correctability from the datasheet, same as the
+ *                   @ecc_strength_ds in nand_chip{}.
+ * @ecc.step_ds: The ECC step required by the @ecc.strength_ds, same as the
+ *               @ecc_step_ds in nand_chip{}, also from the datasheet.
+ *               For example, the "4bit ECC for each 512Byte" can be set with
+ *               NAND_ECC_INFO(4, 512).
  */
 struct nand_flash_dev {
        char *name;
@@ -609,6 +672,10 @@ struct nand_flash_dev {
        unsigned int options;
        uint16_t id_len;
        uint16_t oobsize;
+       struct {
+               uint16_t strength_ds;
+               uint16_t step_ds;
+       } ecc;
 };
 
 /**
@@ -625,8 +692,8 @@ extern struct nand_flash_dev nand_flash_ids[];
 extern struct nand_manufacturers nand_manuf_ids[];
 
 extern int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd);
-extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
 extern int nand_default_bbt(struct mtd_info *mtd);
+extern int nand_markbad_bbt(struct mtd_info *mtd, loff_t offs);
 extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
 extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
                           int allowbbt);
@@ -708,6 +775,12 @@ struct platform_nand_chip *get_platform_nandchip(struct mtd_info *mtd)
        return chip->priv;
 }
 
+/* return the supported features. */
+static inline int onfi_feature(struct nand_chip *chip)
+{
+       return chip->onfi_version ? le16_to_cpu(chip->onfi_params.features) : 0;
+}
+
 /* return the supported asynchronous timing mode. */
 static inline int onfi_get_async_timing_mode(struct nand_chip *chip)
 {
index cd09751c71a0474cfddc0afc90cfdbfb48d5d4e0..8e47bc7a1665b8b7e6ca06392584328aab702d82 100644 (file)
@@ -58,7 +58,6 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 
 extern int user_path_at(int, const char __user *, unsigned, struct path *);
 extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
-extern int user_path_umountat(int, const char __user *, unsigned int, struct path *);
 
 #define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
 #define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
@@ -71,8 +70,7 @@ extern struct dentry *kern_path_create(int, const char *, struct path *, unsigne
 extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
 extern void done_path_create(struct path *, struct dentry *);
 extern struct dentry *kern_path_locked(const char *, struct path *);
-extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
-                          const char *, unsigned int, struct path *);
+extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
 
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 
index 041b42a305f6a1817df51bfd46aa746a454e1a50..3de49aca451970a738b5ae55cfd74656248ac9ea 100644 (file)
@@ -950,14 +950,14 @@ struct netdev_phys_port_id {
  *     multiple net devices on single physical port.
  *
  * void (*ndo_add_vxlan_port)(struct  net_device *dev,
- *                           sa_family_t sa_family, __u16 port);
+ *                           sa_family_t sa_family, __be16 port);
  *     Called by vxlan to notiy a driver about the UDP port and socket
  *     address family that vxlan is listnening to. It is called only when
  *     a new port starts listening. The operation is protected by the
  *     vxlan_net->sock_lock.
  *
  * void (*ndo_del_vxlan_port)(struct  net_device *dev,
- *                           sa_family_t sa_family, __u16 port);
+ *                           sa_family_t sa_family, __be16 port);
  *     Called by vxlan to notify the driver about a UDP port and socket
  *     address family that vxlan is not listening to anymore. The operation
  *     is protected by the vxlan_net->sock_lock.
@@ -1093,10 +1093,10 @@ struct net_device_ops {
                                                        struct netdev_phys_port_id *ppid);
        void                    (*ndo_add_vxlan_port)(struct  net_device *dev,
                                                      sa_family_t sa_family,
-                                                     __u16 port);
+                                                     __be16 port);
        void                    (*ndo_del_vxlan_port)(struct  net_device *dev,
                                                      sa_family_t sa_family,
-                                                     __u16 port);
+                                                     __be16 port);
 };
 
 /*
index d80e2753847ce40d23e174e0b9fa623249bb4f28..9ac9fbde7b61a38795d631ab545b9bd3140fe6f6 100644 (file)
@@ -296,10 +296,12 @@ ip_set_eexist(int ret, u32 flags)
 
 /* Match elements marked with nomatch */
 static inline bool
-ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt)
+ip_set_enomatch(int ret, u32 flags, enum ipset_adt adt, struct ip_set *set)
 {
        return adt == IPSET_TEST &&
-              ret == -ENOTEMPTY && ((flags >> 16) & IPSET_FLAG_NOMATCH);
+              (set->type->features & IPSET_TYPE_NOMATCH) &&
+              ((flags >> 16) & IPSET_FLAG_NOMATCH) &&
+              (ret > 0 || ret == -ENOTEMPTY);
 }
 
 /* Check the NLA_F_NET_BYTEORDER flag */
index 7125cef741642b77ca5c41758c26e500be3a2672..3ea4cde8701ce1e97d6a39a4a1264452468a5254 100644 (file)
@@ -524,6 +524,7 @@ static inline void nfs4_label_free(void *label) {}
  * linux/fs/nfs/unlink.c
  */
 extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
+extern void nfs_wait_on_sillyrename(struct dentry *dentry);
 extern void nfs_block_sillyrename(struct dentry *dentry);
 extern void nfs_unblock_sillyrename(struct dentry *dentry);
 extern int  nfs_sillyrename(struct inode *dir, struct dentry *dentry);
index d2212432c456a3fb2b1cbe33311d6e789d518173..b8cedced50c9c70dd00c680d42a424bcdb90a8a9 100644 (file)
@@ -56,6 +56,7 @@ struct nfs_client {
        struct rpc_cred         *cl_machine_cred;
 
 #if IS_ENABLED(CONFIG_NFS_V4)
+       struct list_head        cl_ds_clients; /* auth flavor data servers */
        u64                     cl_clientid;    /* constant */
        nfs4_verifier           cl_confirm;     /* Clientid verifier */
        unsigned long           cl_state;
@@ -78,6 +79,9 @@ struct nfs_client {
        u32                     cl_cb_ident;    /* v4.0 callback identifier */
        const struct nfs4_minor_version_ops *cl_mvops;
 
+       /* NFSv4.0 transport blocking */
+       struct nfs4_slot_table  *cl_slot_tbl;
+
        /* The sequence id to use for the next CREATE_SESSION */
        u32                     cl_seqid;
        /* The flags used for obtaining the clientid during EXCHANGE_ID */
@@ -87,6 +91,15 @@ struct nfs_client {
        struct nfs41_server_owner *cl_serverowner;
        struct nfs41_server_scope *cl_serverscope;
        struct nfs41_impl_id    *cl_implid;
+       /* nfs 4.1+ state protection modes: */
+       unsigned long           cl_sp4_flags;
+#define NFS_SP4_MACH_CRED_MINIMAL  1   /* Minimal sp4_mach_cred - state ops
+                                        * must use machine cred */
+#define NFS_SP4_MACH_CRED_CLEANUP  2   /* CLOSE and LOCKU */
+#define NFS_SP4_MACH_CRED_SECINFO  3   /* SECINFO and SECINFO_NO_NAME */
+#define NFS_SP4_MACH_CRED_STATEID  4   /* TEST_STATEID and FREE_STATEID */
+#define NFS_SP4_MACH_CRED_WRITE    5   /* WRITE */
+#define NFS_SP4_MACH_CRED_COMMIT   6   /* COMMIT */
 #endif /* CONFIG_NFS_V4 */
 
 #ifdef CONFIG_NFS_FSCACHE
index 8651574a305bb44815e0c5e19826a3fbcbf7a37e..01fd84b566f773505122f235ceb3f70ec158bb04 100644 (file)
@@ -1107,6 +1107,23 @@ struct pnfs_ds_commit_info {
        struct pnfs_commit_bucket *buckets;
 };
 
+#define NFS4_OP_MAP_NUM_LONGS \
+       DIV_ROUND_UP(LAST_NFS4_OP, 8 * sizeof(unsigned long))
+#define NFS4_OP_MAP_NUM_WORDS \
+       (NFS4_OP_MAP_NUM_LONGS * sizeof(unsigned long) / sizeof(u32))
+struct nfs4_op_map {
+       union {
+               unsigned long longs[NFS4_OP_MAP_NUM_LONGS];
+               u32 words[NFS4_OP_MAP_NUM_WORDS];
+       } u;
+};
+
+struct nfs41_state_protection {
+       u32 how;
+       struct nfs4_op_map enforce;
+       struct nfs4_op_map allow;
+};
+
 #define NFS4_EXCHANGE_ID_LEN   (48)
 struct nfs41_exchange_id_args {
        struct nfs_client               *client;
@@ -1114,6 +1131,7 @@ struct nfs41_exchange_id_args {
        unsigned int                    id_len;
        char                            id[NFS4_EXCHANGE_ID_LEN];
        u32                             flags;
+       struct nfs41_state_protection   state_protect;
 };
 
 struct nfs41_server_owner {
@@ -1146,6 +1164,7 @@ struct nfs41_exchange_id_res {
        struct nfs41_server_owner       *server_owner;
        struct nfs41_server_scope       *server_scope;
        struct nfs41_impl_id            *impl_id;
+       struct nfs41_state_protection   state_protect;
 };
 
 struct nfs41_create_session_args {
@@ -1419,12 +1438,12 @@ struct nfs_rpc_ops {
        void    (*read_setup)   (struct nfs_read_data *, struct rpc_message *);
        void    (*read_pageio_init)(struct nfs_pageio_descriptor *, struct inode *,
                                    const struct nfs_pgio_completion_ops *);
-       void    (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *);
+       int     (*read_rpc_prepare)(struct rpc_task *, struct nfs_read_data *);
        int     (*read_done)  (struct rpc_task *, struct nfs_read_data *);
        void    (*write_setup)  (struct nfs_write_data *, struct rpc_message *);
        void    (*write_pageio_init)(struct nfs_pageio_descriptor *, struct inode *, int,
                                     const struct nfs_pgio_completion_ops *);
-       void    (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
+       int     (*write_rpc_prepare)(struct rpc_task *, struct nfs_write_data *);
        int     (*write_done)  (struct rpc_task *, struct nfs_write_data *);
        void    (*commit_setup) (struct nfs_commit_data *, struct rpc_message *);
        void    (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *);
@@ -1442,7 +1461,7 @@ struct nfs_rpc_ops {
        struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *);
        struct nfs_client *
                (*init_client) (struct nfs_client *, const struct rpc_timeout *,
-                               const char *, rpc_authflavor_t);
+                               const char *);
        void    (*free_client) (struct nfs_client *);
        struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *);
        struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
index f451c8d6e231005b5a1ef702a89a2a4b8968ffc4..26ebcf41c2131d681aab56112b3390c773e70ab8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Definitions for the NVM Express interface
- * Copyright (c) 2011, Intel Corporation.
+ * Copyright (c) 2011-2013, Intel Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
 #ifndef _LINUX_NVME_H
 #define _LINUX_NVME_H
 
-#include <linux/types.h>
+#include <uapi/linux/nvme.h>
+#include <linux/pci.h>
+#include <linux/miscdevice.h>
+#include <linux/kref.h>
 
 struct nvme_bar {
        __u64                   cap;    /* Controller Capabilities */
@@ -50,6 +53,7 @@ enum {
        NVME_CC_SHN_NONE        = 0 << 14,
        NVME_CC_SHN_NORMAL      = 1 << 14,
        NVME_CC_SHN_ABRUPT      = 2 << 14,
+       NVME_CC_SHN_MASK        = 3 << 14,
        NVME_CC_IOSQES          = 6 << 16,
        NVME_CC_IOCQES          = 4 << 20,
        NVME_CSTS_RDY           = 1 << 0,
@@ -57,462 +61,11 @@ enum {
        NVME_CSTS_SHST_NORMAL   = 0 << 2,
        NVME_CSTS_SHST_OCCUR    = 1 << 2,
        NVME_CSTS_SHST_CMPLT    = 2 << 2,
-};
-
-struct nvme_id_power_state {
-       __le16                  max_power;      /* centiwatts */
-       __u16                   rsvd2;
-       __le32                  entry_lat;      /* microseconds */
-       __le32                  exit_lat;       /* microseconds */
-       __u8                    read_tput;
-       __u8                    read_lat;
-       __u8                    write_tput;
-       __u8                    write_lat;
-       __u8                    rsvd16[16];
+       NVME_CSTS_SHST_MASK     = 3 << 2,
 };
 
 #define NVME_VS(major, minor)  (major << 16 | minor)
 
-struct nvme_id_ctrl {
-       __le16                  vid;
-       __le16                  ssvid;
-       char                    sn[20];
-       char                    mn[40];
-       char                    fr[8];
-       __u8                    rab;
-       __u8                    ieee[3];
-       __u8                    mic;
-       __u8                    mdts;
-       __u8                    rsvd78[178];
-       __le16                  oacs;
-       __u8                    acl;
-       __u8                    aerl;
-       __u8                    frmw;
-       __u8                    lpa;
-       __u8                    elpe;
-       __u8                    npss;
-       __u8                    rsvd264[248];
-       __u8                    sqes;
-       __u8                    cqes;
-       __u8                    rsvd514[2];
-       __le32                  nn;
-       __le16                  oncs;
-       __le16                  fuses;
-       __u8                    fna;
-       __u8                    vwc;
-       __le16                  awun;
-       __le16                  awupf;
-       __u8                    rsvd530[1518];
-       struct nvme_id_power_state      psd[32];
-       __u8                    vs[1024];
-};
-
-enum {
-       NVME_CTRL_ONCS_COMPARE                  = 1 << 0,
-       NVME_CTRL_ONCS_WRITE_UNCORRECTABLE      = 1 << 1,
-       NVME_CTRL_ONCS_DSM                      = 1 << 2,
-};
-
-struct nvme_lbaf {
-       __le16                  ms;
-       __u8                    ds;
-       __u8                    rp;
-};
-
-struct nvme_id_ns {
-       __le64                  nsze;
-       __le64                  ncap;
-       __le64                  nuse;
-       __u8                    nsfeat;
-       __u8                    nlbaf;
-       __u8                    flbas;
-       __u8                    mc;
-       __u8                    dpc;
-       __u8                    dps;
-       __u8                    rsvd30[98];
-       struct nvme_lbaf        lbaf[16];
-       __u8                    rsvd192[192];
-       __u8                    vs[3712];
-};
-
-enum {
-       NVME_NS_FEAT_THIN       = 1 << 0,
-       NVME_LBAF_RP_BEST       = 0,
-       NVME_LBAF_RP_BETTER     = 1,
-       NVME_LBAF_RP_GOOD       = 2,
-       NVME_LBAF_RP_DEGRADED   = 3,
-};
-
-struct nvme_smart_log {
-       __u8                    critical_warning;
-       __u8                    temperature[2];
-       __u8                    avail_spare;
-       __u8                    spare_thresh;
-       __u8                    percent_used;
-       __u8                    rsvd6[26];
-       __u8                    data_units_read[16];
-       __u8                    data_units_written[16];
-       __u8                    host_reads[16];
-       __u8                    host_writes[16];
-       __u8                    ctrl_busy_time[16];
-       __u8                    power_cycles[16];
-       __u8                    power_on_hours[16];
-       __u8                    unsafe_shutdowns[16];
-       __u8                    media_errors[16];
-       __u8                    num_err_log_entries[16];
-       __u8                    rsvd192[320];
-};
-
-enum {
-       NVME_SMART_CRIT_SPARE           = 1 << 0,
-       NVME_SMART_CRIT_TEMPERATURE     = 1 << 1,
-       NVME_SMART_CRIT_RELIABILITY     = 1 << 2,
-       NVME_SMART_CRIT_MEDIA           = 1 << 3,
-       NVME_SMART_CRIT_VOLATILE_MEMORY = 1 << 4,
-};
-
-struct nvme_lba_range_type {
-       __u8                    type;
-       __u8                    attributes;
-       __u8                    rsvd2[14];
-       __u64                   slba;
-       __u64                   nlb;
-       __u8                    guid[16];
-       __u8                    rsvd48[16];
-};
-
-enum {
-       NVME_LBART_TYPE_FS      = 0x01,
-       NVME_LBART_TYPE_RAID    = 0x02,
-       NVME_LBART_TYPE_CACHE   = 0x03,
-       NVME_LBART_TYPE_SWAP    = 0x04,
-
-       NVME_LBART_ATTRIB_TEMP  = 1 << 0,
-       NVME_LBART_ATTRIB_HIDE  = 1 << 1,
-};
-
-/* I/O commands */
-
-enum nvme_opcode {
-       nvme_cmd_flush          = 0x00,
-       nvme_cmd_write          = 0x01,
-       nvme_cmd_read           = 0x02,
-       nvme_cmd_write_uncor    = 0x04,
-       nvme_cmd_compare        = 0x05,
-       nvme_cmd_dsm            = 0x09,
-};
-
-struct nvme_common_command {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __le32                  nsid;
-       __le32                  cdw2[2];
-       __le64                  metadata;
-       __le64                  prp1;
-       __le64                  prp2;
-       __le32                  cdw10[6];
-};
-
-struct nvme_rw_command {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __le32                  nsid;
-       __u64                   rsvd2;
-       __le64                  metadata;
-       __le64                  prp1;
-       __le64                  prp2;
-       __le64                  slba;
-       __le16                  length;
-       __le16                  control;
-       __le32                  dsmgmt;
-       __le32                  reftag;
-       __le16                  apptag;
-       __le16                  appmask;
-};
-
-enum {
-       NVME_RW_LR                      = 1 << 15,
-       NVME_RW_FUA                     = 1 << 14,
-       NVME_RW_DSM_FREQ_UNSPEC         = 0,
-       NVME_RW_DSM_FREQ_TYPICAL        = 1,
-       NVME_RW_DSM_FREQ_RARE           = 2,
-       NVME_RW_DSM_FREQ_READS          = 3,
-       NVME_RW_DSM_FREQ_WRITES         = 4,
-       NVME_RW_DSM_FREQ_RW             = 5,
-       NVME_RW_DSM_FREQ_ONCE           = 6,
-       NVME_RW_DSM_FREQ_PREFETCH       = 7,
-       NVME_RW_DSM_FREQ_TEMP           = 8,
-       NVME_RW_DSM_LATENCY_NONE        = 0 << 4,
-       NVME_RW_DSM_LATENCY_IDLE        = 1 << 4,
-       NVME_RW_DSM_LATENCY_NORM        = 2 << 4,
-       NVME_RW_DSM_LATENCY_LOW         = 3 << 4,
-       NVME_RW_DSM_SEQ_REQ             = 1 << 6,
-       NVME_RW_DSM_COMPRESSED          = 1 << 7,
-};
-
-struct nvme_dsm_cmd {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __le32                  nsid;
-       __u64                   rsvd2[2];
-       __le64                  prp1;
-       __le64                  prp2;
-       __le32                  nr;
-       __le32                  attributes;
-       __u32                   rsvd12[4];
-};
-
-enum {
-       NVME_DSMGMT_IDR         = 1 << 0,
-       NVME_DSMGMT_IDW         = 1 << 1,
-       NVME_DSMGMT_AD          = 1 << 2,
-};
-
-struct nvme_dsm_range {
-       __le32                  cattr;
-       __le32                  nlb;
-       __le64                  slba;
-};
-
-/* Admin commands */
-
-enum nvme_admin_opcode {
-       nvme_admin_delete_sq            = 0x00,
-       nvme_admin_create_sq            = 0x01,
-       nvme_admin_get_log_page         = 0x02,
-       nvme_admin_delete_cq            = 0x04,
-       nvme_admin_create_cq            = 0x05,
-       nvme_admin_identify             = 0x06,
-       nvme_admin_abort_cmd            = 0x08,
-       nvme_admin_set_features         = 0x09,
-       nvme_admin_get_features         = 0x0a,
-       nvme_admin_async_event          = 0x0c,
-       nvme_admin_activate_fw          = 0x10,
-       nvme_admin_download_fw          = 0x11,
-       nvme_admin_format_nvm           = 0x80,
-       nvme_admin_security_send        = 0x81,
-       nvme_admin_security_recv        = 0x82,
-};
-
-enum {
-       NVME_QUEUE_PHYS_CONTIG  = (1 << 0),
-       NVME_CQ_IRQ_ENABLED     = (1 << 1),
-       NVME_SQ_PRIO_URGENT     = (0 << 1),
-       NVME_SQ_PRIO_HIGH       = (1 << 1),
-       NVME_SQ_PRIO_MEDIUM     = (2 << 1),
-       NVME_SQ_PRIO_LOW        = (3 << 1),
-       NVME_FEAT_ARBITRATION   = 0x01,
-       NVME_FEAT_POWER_MGMT    = 0x02,
-       NVME_FEAT_LBA_RANGE     = 0x03,
-       NVME_FEAT_TEMP_THRESH   = 0x04,
-       NVME_FEAT_ERR_RECOVERY  = 0x05,
-       NVME_FEAT_VOLATILE_WC   = 0x06,
-       NVME_FEAT_NUM_QUEUES    = 0x07,
-       NVME_FEAT_IRQ_COALESCE  = 0x08,
-       NVME_FEAT_IRQ_CONFIG    = 0x09,
-       NVME_FEAT_WRITE_ATOMIC  = 0x0a,
-       NVME_FEAT_ASYNC_EVENT   = 0x0b,
-       NVME_FEAT_SW_PROGRESS   = 0x0c,
-       NVME_FWACT_REPL         = (0 << 3),
-       NVME_FWACT_REPL_ACTV    = (1 << 3),
-       NVME_FWACT_ACTV         = (2 << 3),
-};
-
-struct nvme_identify {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __le32                  nsid;
-       __u64                   rsvd2[2];
-       __le64                  prp1;
-       __le64                  prp2;
-       __le32                  cns;
-       __u32                   rsvd11[5];
-};
-
-struct nvme_features {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __le32                  nsid;
-       __u64                   rsvd2[2];
-       __le64                  prp1;
-       __le64                  prp2;
-       __le32                  fid;
-       __le32                  dword11;
-       __u32                   rsvd12[4];
-};
-
-struct nvme_create_cq {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __u32                   rsvd1[5];
-       __le64                  prp1;
-       __u64                   rsvd8;
-       __le16                  cqid;
-       __le16                  qsize;
-       __le16                  cq_flags;
-       __le16                  irq_vector;
-       __u32                   rsvd12[4];
-};
-
-struct nvme_create_sq {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __u32                   rsvd1[5];
-       __le64                  prp1;
-       __u64                   rsvd8;
-       __le16                  sqid;
-       __le16                  qsize;
-       __le16                  sq_flags;
-       __le16                  cqid;
-       __u32                   rsvd12[4];
-};
-
-struct nvme_delete_queue {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __u32                   rsvd1[9];
-       __le16                  qid;
-       __u16                   rsvd10;
-       __u32                   rsvd11[5];
-};
-
-struct nvme_download_firmware {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __u32                   rsvd1[5];
-       __le64                  prp1;
-       __le64                  prp2;
-       __le32                  numd;
-       __le32                  offset;
-       __u32                   rsvd12[4];
-};
-
-struct nvme_format_cmd {
-       __u8                    opcode;
-       __u8                    flags;
-       __u16                   command_id;
-       __le32                  nsid;
-       __u64                   rsvd2[4];
-       __le32                  cdw10;
-       __u32                   rsvd11[5];
-};
-
-struct nvme_command {
-       union {
-               struct nvme_common_command common;
-               struct nvme_rw_command rw;
-               struct nvme_identify identify;
-               struct nvme_features features;
-               struct nvme_create_cq create_cq;
-               struct nvme_create_sq create_sq;
-               struct nvme_delete_queue delete_queue;
-               struct nvme_download_firmware dlfw;
-               struct nvme_format_cmd format;
-               struct nvme_dsm_cmd dsm;
-       };
-};
-
-enum {
-       NVME_SC_SUCCESS                 = 0x0,
-       NVME_SC_INVALID_OPCODE          = 0x1,
-       NVME_SC_INVALID_FIELD           = 0x2,
-       NVME_SC_CMDID_CONFLICT          = 0x3,
-       NVME_SC_DATA_XFER_ERROR         = 0x4,
-       NVME_SC_POWER_LOSS              = 0x5,
-       NVME_SC_INTERNAL                = 0x6,
-       NVME_SC_ABORT_REQ               = 0x7,
-       NVME_SC_ABORT_QUEUE             = 0x8,
-       NVME_SC_FUSED_FAIL              = 0x9,
-       NVME_SC_FUSED_MISSING           = 0xa,
-       NVME_SC_INVALID_NS              = 0xb,
-       NVME_SC_CMD_SEQ_ERROR           = 0xc,
-       NVME_SC_LBA_RANGE               = 0x80,
-       NVME_SC_CAP_EXCEEDED            = 0x81,
-       NVME_SC_NS_NOT_READY            = 0x82,
-       NVME_SC_CQ_INVALID              = 0x100,
-       NVME_SC_QID_INVALID             = 0x101,
-       NVME_SC_QUEUE_SIZE              = 0x102,
-       NVME_SC_ABORT_LIMIT             = 0x103,
-       NVME_SC_ABORT_MISSING           = 0x104,
-       NVME_SC_ASYNC_LIMIT             = 0x105,
-       NVME_SC_FIRMWARE_SLOT           = 0x106,
-       NVME_SC_FIRMWARE_IMAGE          = 0x107,
-       NVME_SC_INVALID_VECTOR          = 0x108,
-       NVME_SC_INVALID_LOG_PAGE        = 0x109,
-       NVME_SC_INVALID_FORMAT          = 0x10a,
-       NVME_SC_BAD_ATTRIBUTES          = 0x180,
-       NVME_SC_WRITE_FAULT             = 0x280,
-       NVME_SC_READ_ERROR              = 0x281,
-       NVME_SC_GUARD_CHECK             = 0x282,
-       NVME_SC_APPTAG_CHECK            = 0x283,
-       NVME_SC_REFTAG_CHECK            = 0x284,
-       NVME_SC_COMPARE_FAILED          = 0x285,
-       NVME_SC_ACCESS_DENIED           = 0x286,
-};
-
-struct nvme_completion {
-       __le32  result;         /* Used by admin commands to return data */
-       __u32   rsvd;
-       __le16  sq_head;        /* how much of this queue may be reclaimed */
-       __le16  sq_id;          /* submission queue that generated this entry */
-       __u16   command_id;     /* of the command which completed */
-       __le16  status;         /* did the command fail, and if so, why? */
-};
-
-struct nvme_user_io {
-       __u8    opcode;
-       __u8    flags;
-       __u16   control;
-       __u16   nblocks;
-       __u16   rsvd;
-       __u64   metadata;
-       __u64   addr;
-       __u64   slba;
-       __u32   dsmgmt;
-       __u32   reftag;
-       __u16   apptag;
-       __u16   appmask;
-};
-
-struct nvme_admin_cmd {
-       __u8    opcode;
-       __u8    flags;
-       __u16   rsvd1;
-       __u32   nsid;
-       __u32   cdw2;
-       __u32   cdw3;
-       __u64   metadata;
-       __u64   addr;
-       __u32   metadata_len;
-       __u32   data_len;
-       __u32   cdw10;
-       __u32   cdw11;
-       __u32   cdw12;
-       __u32   cdw13;
-       __u32   cdw14;
-       __u32   cdw15;
-       __u32   timeout_ms;
-       __u32   result;
-};
-
-#define NVME_IOCTL_ID          _IO('N', 0x40)
-#define NVME_IOCTL_ADMIN_CMD   _IOWR('N', 0x41, struct nvme_admin_cmd)
-#define NVME_IOCTL_SUBMIT_IO   _IOW('N', 0x42, struct nvme_user_io)
-
-#ifdef __KERNEL__
-#include <linux/pci.h>
-#include <linux/miscdevice.h>
-#include <linux/kref.h>
-
 #define NVME_IO_TIMEOUT        (5 * HZ)
 
 /*
@@ -553,7 +106,7 @@ struct nvme_ns {
        struct request_queue *queue;
        struct gendisk *disk;
 
-       int ns_id;
+       unsigned ns_id;
        int lba_shift;
        int ms;
        u64 mode_select_num_blocks;
@@ -572,6 +125,7 @@ struct nvme_iod {
        int offset;             /* Of PRP list */
        int nents;              /* Used in scatterlist */
        int length;             /* Of data, in bytes */
+       unsigned long start_time;
        dma_addr_t first_dma;
        struct scatterlist sg[0];
 };
@@ -613,6 +167,4 @@ struct sg_io_hdr;
 int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
 int nvme_sg_get_version_num(int __user *ip);
 
-#endif
-
 #endif /* _LINUX_NVME_H */
index 3a45c4f593ad68258129f22a8a6c5e84b4611cda..f95aee391e30fcb98eeec0f6569c0b4bc9b8ba31 100644 (file)
@@ -281,6 +281,9 @@ extern struct device_node *of_parse_phandle(const struct device_node *np,
 extern int of_parse_phandle_with_args(const struct device_node *np,
        const char *list_name, const char *cells_name, int index,
        struct of_phandle_args *out_args);
+extern int of_parse_phandle_with_fixed_args(const struct device_node *np,
+       const char *list_name, int cells_count, int index,
+       struct of_phandle_args *out_args);
 extern int of_count_phandle_with_args(const struct device_node *np,
        const char *list_name, const char *cells_name);
 
@@ -324,12 +327,6 @@ extern int of_detach_node(struct device_node *);
  */
 const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
                               u32 *pu);
-#define of_property_for_each_u32(np, propname, prop, p, u)     \
-       for (prop = of_find_property(np, propname, NULL),       \
-               p = of_prop_next_u32(prop, NULL, &u);           \
-               p;                                              \
-               p = of_prop_next_u32(prop, p, &u))
-
 /*
  * struct property *prop;
  * const char *s;
@@ -338,11 +335,6 @@ const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur,
  *         printk("String value: %s\n", s);
  */
 const char *of_prop_next_string(struct property *prop, const char *cur);
-#define of_property_for_each_string(np, propname, prop, s)     \
-       for (prop = of_find_property(np, propname, NULL),       \
-               s = of_prop_next_string(prop, NULL);            \
-               s;                                              \
-               s = of_prop_next_string(prop, s))
 
 int of_device_is_stdout_path(struct device_node *dn);
 
@@ -497,6 +489,13 @@ static inline int of_parse_phandle_with_args(struct device_node *np,
        return -ENOSYS;
 }
 
+static inline int of_parse_phandle_with_fixed_args(const struct device_node *np,
+       const char *list_name, int cells_count, int index,
+       struct of_phandle_args *out_args)
+{
+       return -ENOSYS;
+}
+
 static inline int of_count_phandle_with_args(struct device_node *np,
                                             const char *list_name,
                                             const char *cells_name)
@@ -519,12 +518,20 @@ static inline int of_device_is_stdout_path(struct device_node *dn)
        return 0;
 }
 
+static inline const __be32 *of_prop_next_u32(struct property *prop,
+               const __be32 *cur, u32 *pu)
+{
+       return NULL;
+}
+
+static inline const char *of_prop_next_string(struct property *prop,
+               const char *cur)
+{
+       return NULL;
+}
+
 #define of_match_ptr(_ptr)     NULL
 #define of_match_node(_matches, _node) NULL
-#define of_property_for_each_u32(np, propname, prop, p, u) \
-       while (0)
-#define of_property_for_each_string(np, propname, prop, s) \
-       while (0)
 #endif /* CONFIG_OF */
 
 #ifndef of_node_to_nid
@@ -573,6 +580,18 @@ static inline int of_property_read_u32(const struct device_node *np,
        return of_property_read_u32_array(np, propname, out_value, 1);
 }
 
+#define of_property_for_each_u32(np, propname, prop, p, u)     \
+       for (prop = of_find_property(np, propname, NULL),       \
+               p = of_prop_next_u32(prop, NULL, &u);           \
+               p;                                              \
+               p = of_prop_next_u32(prop, p, &u))
+
+#define of_property_for_each_string(np, propname, prop, s)     \
+       for (prop = of_find_property(np, propname, NULL),       \
+               s = of_prop_next_string(prop, NULL);            \
+               s;                                              \
+               s = of_prop_next_string(prop, s))
+
 #if defined(CONFIG_PROC_FS) && defined(CONFIG_PROC_DEVICETREE)
 extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
 extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
index ed136ad698ce622e4d150d7fda337a99c78d5a4e..a478c62a2aabc4dc38f243e25b572bae62688fec 100644 (file)
@@ -90,6 +90,9 @@ extern void *of_get_flat_dt_prop(unsigned long node, const char *name,
 extern int of_flat_dt_is_compatible(unsigned long node, const char *name);
 extern int of_flat_dt_match(unsigned long node, const char *const *matches);
 extern unsigned long of_get_flat_dt_root(void);
+extern int of_scan_flat_dt_by_path(const char *path,
+       int (*it)(unsigned long node, const char *name, int depth, void *data),
+       void *data);
 
 extern int early_init_dt_scan_chosen(unsigned long node, const char *uname,
                                     int depth, void *data);
@@ -106,8 +109,7 @@ extern u64 dt_mem_next_cell(int s, __be32 **cellp);
  * physical addresses.
  */
 #ifdef CONFIG_BLK_DEV_INITRD
-extern void early_init_dt_setup_initrd_arch(unsigned long start,
-                                           unsigned long end);
+extern void early_init_dt_setup_initrd_arch(u64 start, u64 end);
 #endif
 
 /* Early flat tree scan hooks */
index 61bf53b02779200323e19c9c6671ec6b78cd1fde..34597c8c1a4cad4942c6c575cccc3190f01ad274 100644 (file)
@@ -9,10 +9,10 @@
 
 #ifdef CONFIG_OF_NET
 #include <linux/of.h>
-extern const int of_get_phy_mode(struct device_node *np);
+extern int of_get_phy_mode(struct device_node *np);
 extern const void *of_get_mac_address(struct device_node *np);
 #else
-static inline const int of_get_phy_mode(struct device_node *np)
+static inline int of_get_phy_mode(struct device_node *np)
 {
        return -ENODEV;
 }
diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
new file mode 100644 (file)
index 0000000..c841282
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef __OF_RESERVED_MEM_H
+#define __OF_RESERVED_MEM_H
+
+#ifdef CONFIG_OF_RESERVED_MEM
+void of_reserved_mem_device_init(struct device *dev);
+void of_reserved_mem_device_release(struct device *dev);
+void early_init_dt_scan_reserved_mem(void);
+#else
+static inline void of_reserved_mem_device_init(struct device *dev) { }
+static inline void of_reserved_mem_device_release(struct device *dev) { }
+static inline void early_init_dt_scan_reserved_mem(void) { }
+#endif
+
+#endif /* __OF_RESERVED_MEM_H */
index bc95b2b391bf2a9ec73a7b3c8bf1d08d89f8411a..97fbecdd7a401157cd290d6f4e981a8557ee4745 100644 (file)
 #define PCI_DEVICE_ID_HP_CISSE         0x323a
 #define PCI_DEVICE_ID_HP_CISSF         0x323b
 #define PCI_DEVICE_ID_HP_CISSH         0x323c
+#define PCI_DEVICE_ID_HP_CISSI         0x3239
 #define PCI_DEVICE_ID_HP_ZX2_IOC       0x4031
 
 #define PCI_VENDOR_ID_PCTECH           0x1042
diff --git a/include/linux/percpu_ida.h b/include/linux/percpu_ida.h
new file mode 100644 (file)
index 0000000..0b23edb
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef __PERCPU_IDA_H__
+#define __PERCPU_IDA_H__
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/spinlock_types.h>
+#include <linux/wait.h>
+#include <linux/cpumask.h>
+
+struct percpu_ida_cpu;
+
+struct percpu_ida {
+       /*
+        * number of tags available to be allocated, as passed to
+        * percpu_ida_init()
+        */
+       unsigned                        nr_tags;
+
+       struct percpu_ida_cpu __percpu  *tag_cpu;
+
+       /*
+        * Bitmap of cpus that (may) have tags on their percpu freelists:
+        * steal_tags() uses this to decide when to steal tags, and which cpus
+        * to try stealing from.
+        *
+        * It's ok for a freelist to be empty when its bit is set - steal_tags()
+        * will just keep looking - but the bitmap _must_ be set whenever a
+        * percpu freelist does have tags.
+        */
+       cpumask_t                       cpus_have_tags;
+
+       struct {
+               spinlock_t              lock;
+               /*
+                * When we go to steal tags from another cpu (see steal_tags()),
+                * we want to pick a cpu at random. Cycling through them every
+                * time we steal is a bit easier and more or less equivalent:
+                */
+               unsigned                cpu_last_stolen;
+
+               /* For sleeping on allocation failure */
+               wait_queue_head_t       wait;
+
+               /*
+                * Global freelist - it's a stack where nr_free points to the
+                * top
+                */
+               unsigned                nr_free;
+               unsigned                *freelist;
+       } ____cacheline_aligned_in_smp;
+};
+
+int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp);
+void percpu_ida_free(struct percpu_ida *pool, unsigned tag);
+
+void percpu_ida_destroy(struct percpu_ida *pool);
+int percpu_ida_init(struct percpu_ida *pool, unsigned long nr_tags);
+
+#endif /* __PERCPU_IDA_H__ */
index 6a293b7fff3bf9d4cb260d3d6c6d639427f38275..cea9f70133c521f1d5fb2a0d459f3e30ca3f9576 100644 (file)
@@ -71,6 +71,10 @@ struct atmel_nand_data {
        u8              on_flash_bbt;           /* bbt on flash */
        struct mtd_partition *parts;
        unsigned int    num_parts;
+       bool            has_dma;                /* support dma transfer */
+
+       /* default is false, only for at32ap7000 chip is true */
+       bool            need_reset_workaround;
 };
 
  /* Serial */
diff --git a/include/linux/platform_data/dma-rcar-hpbdma.h b/include/linux/platform_data/dma-rcar-hpbdma.h
new file mode 100644 (file)
index 0000000..648b8ea
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011-2013 Renesas Electronics Corporation
+ * Copyright (C) 2013 Cogent Embedded, Inc.
+ *
+ * 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 __DMA_RCAR_HPBDMA_H
+#define __DMA_RCAR_HPBDMA_H
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+
+/* Transmit sizes and respective register values */
+enum {
+       XMIT_SZ_8BIT    = 0,
+       XMIT_SZ_16BIT   = 1,
+       XMIT_SZ_32BIT   = 2,
+       XMIT_SZ_MAX
+};
+
+/* DMA control register (DCR) bits */
+#define HPB_DMAE_DCR_DTAMD             (1u << 26)
+#define HPB_DMAE_DCR_DTAC              (1u << 25)
+#define HPB_DMAE_DCR_DTAU              (1u << 24)
+#define HPB_DMAE_DCR_DTAU1             (1u << 23)
+#define HPB_DMAE_DCR_SWMD              (1u << 22)
+#define HPB_DMAE_DCR_BTMD              (1u << 21)
+#define HPB_DMAE_DCR_PKMD              (1u << 20)
+#define HPB_DMAE_DCR_CT                        (1u << 18)
+#define HPB_DMAE_DCR_ACMD              (1u << 17)
+#define HPB_DMAE_DCR_DIP               (1u << 16)
+#define HPB_DMAE_DCR_SMDL              (1u << 13)
+#define HPB_DMAE_DCR_SPDAM             (1u << 12)
+#define HPB_DMAE_DCR_SDRMD_MASK                (3u << 10)
+#define HPB_DMAE_DCR_SDRMD_MOD         (0u << 10)
+#define HPB_DMAE_DCR_SDRMD_AUTO                (1u << 10)
+#define HPB_DMAE_DCR_SDRMD_TIMER       (2u << 10)
+#define HPB_DMAE_DCR_SPDS_MASK         (3u << 8)
+#define HPB_DMAE_DCR_SPDS_8BIT         (0u << 8)
+#define HPB_DMAE_DCR_SPDS_16BIT                (1u << 8)
+#define HPB_DMAE_DCR_SPDS_32BIT                (2u << 8)
+#define HPB_DMAE_DCR_DMDL              (1u << 5)
+#define HPB_DMAE_DCR_DPDAM             (1u << 4)
+#define HPB_DMAE_DCR_DDRMD_MASK                (3u << 2)
+#define HPB_DMAE_DCR_DDRMD_MOD         (0u << 2)
+#define HPB_DMAE_DCR_DDRMD_AUTO                (1u << 2)
+#define HPB_DMAE_DCR_DDRMD_TIMER       (2u << 2)
+#define HPB_DMAE_DCR_DPDS_MASK         (3u << 0)
+#define HPB_DMAE_DCR_DPDS_8BIT         (0u << 0)
+#define HPB_DMAE_DCR_DPDS_16BIT                (1u << 0)
+#define HPB_DMAE_DCR_DPDS_32BIT                (2u << 0)
+
+/* Asynchronous reset register (ASYNCRSTR) bits */
+#define HPB_DMAE_ASYNCRSTR_ASRST41     BIT(10)
+#define HPB_DMAE_ASYNCRSTR_ASRST40     BIT(9)
+#define HPB_DMAE_ASYNCRSTR_ASRST39     BIT(8)
+#define HPB_DMAE_ASYNCRSTR_ASRST27     BIT(7)
+#define HPB_DMAE_ASYNCRSTR_ASRST26     BIT(6)
+#define HPB_DMAE_ASYNCRSTR_ASRST25     BIT(5)
+#define HPB_DMAE_ASYNCRSTR_ASRST24     BIT(4)
+#define HPB_DMAE_ASYNCRSTR_ASRST23     BIT(3)
+#define HPB_DMAE_ASYNCRSTR_ASRST22     BIT(2)
+#define HPB_DMAE_ASYNCRSTR_ASRST21     BIT(1)
+#define HPB_DMAE_ASYNCRSTR_ASRST20     BIT(0)
+
+struct hpb_dmae_slave_config {
+       unsigned int    id;
+       dma_addr_t      addr;
+       u32             dcr;
+       u32             port;
+       u32             rstr;
+       u32             mdr;
+       u32             mdm;
+       u32             flags;
+#define        HPB_DMAE_SET_ASYNC_RESET        BIT(0)
+#define        HPB_DMAE_SET_ASYNC_MODE         BIT(1)
+       u32             dma_ch;
+};
+
+#define HPB_DMAE_CHANNEL(_irq, _s_id)  \
+{                                      \
+       .ch_irq         = _irq,         \
+       .s_id           = _s_id,        \
+}
+
+struct hpb_dmae_channel {
+       unsigned int    ch_irq;
+       unsigned int    s_id;
+};
+
+struct hpb_dmae_pdata {
+       const struct hpb_dmae_slave_config *slaves;
+       int num_slaves;
+       const struct hpb_dmae_channel *channels;
+       int num_channels;
+       const unsigned int ts_shift[XMIT_SZ_MAX];
+       int num_hw_channels;
+};
+
+#endif
index 57300fd7cc03435a55c8824309c52594e926e66f..179fb91bb5f2eaef7354e37411628f90a6c02335 100644 (file)
@@ -180,4 +180,6 @@ struct edma_soc_info {
        const s16       (*xbar_chans)[2];
 };
 
+int edma_trigger_channel(unsigned);
+
 #endif
diff --git a/include/linux/platform_data/exynos_thermal.h b/include/linux/platform_data/exynos_thermal.h
deleted file mode 100644 (file)
index da7e627..0000000
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * exynos_thermal.h - Samsung EXYNOS TMU (Thermal Management Unit)
- *
- *  Copyright (C) 2011 Samsung Electronics
- *  Donggeun Kim <dg77.kim@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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef _LINUX_EXYNOS_THERMAL_H
-#define _LINUX_EXYNOS_THERMAL_H
-#include <linux/cpu_cooling.h>
-
-enum calibration_type {
-       TYPE_ONE_POINT_TRIMMING,
-       TYPE_TWO_POINT_TRIMMING,
-       TYPE_NONE,
-};
-
-enum soc_type {
-       SOC_ARCH_EXYNOS4210 = 1,
-       SOC_ARCH_EXYNOS,
-};
-/**
- * struct freq_clip_table
- * @freq_clip_max: maximum frequency allowed for this cooling state.
- * @temp_level: Temperature level at which the temperature clipping will
- *     happen.
- * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
- *
- * This structure is required to be filled and passed to the
- * cpufreq_cooling_unregister function.
- */
-struct freq_clip_table {
-       unsigned int freq_clip_max;
-       unsigned int temp_level;
-       const struct cpumask *mask_val;
-};
-
-/**
- * struct exynos_tmu_platform_data
- * @threshold: basic temperature for generating interrupt
- *            25 <= threshold <= 125 [unit: degree Celsius]
- * @threshold_falling: differntial value for setting threshold
- *                    of temperature falling interrupt.
- * @trigger_levels: array for each interrupt levels
- *     [unit: degree Celsius]
- *     0: temperature for trigger_level0 interrupt
- *        condition for trigger_level0 interrupt:
- *             current temperature > threshold + trigger_levels[0]
- *     1: temperature for trigger_level1 interrupt
- *        condition for trigger_level1 interrupt:
- *             current temperature > threshold + trigger_levels[1]
- *     2: temperature for trigger_level2 interrupt
- *        condition for trigger_level2 interrupt:
- *             current temperature > threshold + trigger_levels[2]
- *     3: temperature for trigger_level3 interrupt
- *        condition for trigger_level3 interrupt:
- *             current temperature > threshold + trigger_levels[3]
- * @trigger_level0_en:
- *     1 = enable trigger_level0 interrupt,
- *     0 = disable trigger_level0 interrupt
- * @trigger_level1_en:
- *     1 = enable trigger_level1 interrupt,
- *     0 = disable trigger_level1 interrupt
- * @trigger_level2_en:
- *     1 = enable trigger_level2 interrupt,
- *     0 = disable trigger_level2 interrupt
- * @trigger_level3_en:
- *     1 = enable trigger_level3 interrupt,
- *     0 = disable trigger_level3 interrupt
- * @gain: gain of amplifier in the positive-TC generator block
- *     0 <= gain <= 15
- * @reference_voltage: reference voltage of amplifier
- *     in the positive-TC generator block
- *     0 <= reference_voltage <= 31
- * @noise_cancel_mode: noise cancellation mode
- *     000, 100, 101, 110 and 111 can be different modes
- * @type: determines the type of SOC
- * @efuse_value: platform defined fuse value
- * @cal_type: calibration type for temperature
- * @freq_clip_table: Table representing frequency reduction percentage.
- * @freq_tab_count: Count of the above table as frequency reduction may
- *     applicable to only some of the trigger levels.
- *
- * This structure is required for configuration of exynos_tmu driver.
- */
-struct exynos_tmu_platform_data {
-       u8 threshold;
-       u8 threshold_falling;
-       u8 trigger_levels[4];
-       bool trigger_level0_en;
-       bool trigger_level1_en;
-       bool trigger_level2_en;
-       bool trigger_level3_en;
-
-       u8 gain;
-       u8 reference_voltage;
-       u8 noise_cancel_mode;
-       u32 efuse_value;
-
-       enum calibration_type cal_type;
-       enum soc_type type;
-       struct freq_clip_table freq_tab[4];
-       unsigned int freq_tab_count;
-};
-#endif /* _LINUX_EXYNOS_THERMAL_H */
index 202e290faea877effcc153f0a8bc21e35f2cb697..51a2ff579d60d1763ddd465ac5bf4457272bfb19 100644 (file)
@@ -36,6 +36,13 @@ struct lp55xx_predef_pattern {
        u8 size_b;
 };
 
+enum lp8501_pwr_sel {
+       LP8501_ALL_VDD,         /* D1~9 are connected to VDD */
+       LP8501_6VDD_3VOUT,      /* D1~6 with VDD, D7~9 with VOUT */
+       LP8501_3VDD_6VOUT,      /* D1~6 with VOUT, D7~9 with VDD */
+       LP8501_ALL_VOUT,        /* D1~9 are connected to VOUT */
+};
+
 /*
  * struct lp55xx_platform_data
  * @led_config        : Configurable led class device
@@ -67,6 +74,9 @@ struct lp55xx_platform_data {
        /* Predefined pattern data */
        struct lp55xx_predef_pattern *patterns;
        unsigned int num_patterns;
+
+       /* LP8501 specific */
+       enum lp8501_pwr_sel pwr_sel;
 };
 
 #endif /* _LEDS_LP55XX_H */
diff --git a/include/linux/platform_data/leds-pca9633.h b/include/linux/platform_data/leds-pca9633.h
deleted file mode 100644 (file)
index c5bf29b..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * PCA9633 LED chip driver.
- *
- * Copyright 2012 bct electronic GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef __LINUX_PCA9633_H
-#define __LINUX_PCA9633_H
-#include <linux/leds.h>
-
-enum pca9633_outdrv {
-       PCA9633_OPEN_DRAIN,
-       PCA9633_TOTEM_POLE, /* aka push-pull */
-};
-
-struct pca9633_platform_data {
-       struct led_platform_data leds;
-       enum pca9633_outdrv outdrv;
-};
-
-#endif /* __LINUX_PCA9633_H*/
diff --git a/include/linux/platform_data/leds-pca963x.h b/include/linux/platform_data/leds-pca963x.h
new file mode 100644 (file)
index 0000000..e731f00
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * PCA963X LED chip driver.
+ *
+ * Copyright 2012 bct electronic GmbH
+ * Copyright 2013 Qtechnology A/S
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef __LINUX_PCA963X_H
+#define __LINUX_PCA963X_H
+#include <linux/leds.h>
+
+enum pca963x_outdrv {
+       PCA963X_OPEN_DRAIN,
+       PCA963X_TOTEM_POLE, /* aka push-pull */
+};
+
+enum pca963x_blink_type {
+       PCA963X_SW_BLINK,
+       PCA963X_HW_BLINK,
+};
+
+struct pca963x_platform_data {
+       struct led_platform_data leds;
+       enum pca963x_outdrv outdrv;
+       enum pca963x_blink_type blink_type;
+};
+
+#endif /* __LINUX_PCA963X_H*/
index c42f39f20195374bf6f0f046b487bd8e8c4511a6..ffb801998e5dfa10c450f99b2dbb943e8f7a05d4 100644 (file)
@@ -16,19 +16,6 @@ struct pxa3xx_nand_timing {
        unsigned int    tAR;  /* ND_ALE low to ND_nRE low delay */
 };
 
-struct pxa3xx_nand_cmdset {
-       uint16_t        read1;
-       uint16_t        read2;
-       uint16_t        program;
-       uint16_t        read_status;
-       uint16_t        read_id;
-       uint16_t        erase;
-       uint16_t        reset;
-       uint16_t        lock;
-       uint16_t        unlock;
-       uint16_t        lock_status;
-};
-
 struct pxa3xx_nand_flash {
        char            *name;
        uint32_t        chip_id;
diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
new file mode 100644 (file)
index 0000000..9f02837
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Platform data for the TI bq24190 battery charger driver.
+ *
+ * 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 _BQ24190_CHARGER_H_
+#define _BQ24190_CHARGER_H_
+
+struct bq24190_platform_data {
+       unsigned int    gpio_int;       /* GPIO pin that's connected to INT# */
+};
+
+#endif
diff --git a/include/linux/power/twl4030_madc_battery.h b/include/linux/power/twl4030_madc_battery.h
new file mode 100644 (file)
index 0000000..23110dc
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Dumb driver for LiIon batteries using TWL4030 madc.
+ *
+ * Copyright 2013 Golden Delicious Computers
+ * Nikolaus Schaller <hns@goldelico.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.
+ *
+ *  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 __TWL4030_MADC_BATTERY_H
+#define __TWL4030_MADC_BATTERY_H
+
+/*
+ * Usually we can assume 100% @ 4.15V and 0% @ 3.3V but curves differ for
+ * charging and discharging!
+ */
+
+struct twl4030_madc_bat_calibration {
+       short voltage;  /* in mV - specify -1 for end of list */
+       short level;    /* in percent (0 .. 100%) */
+};
+
+struct twl4030_madc_bat_platform_data {
+       unsigned int capacity;  /* total capacity in uAh */
+       struct twl4030_madc_bat_calibration *charging;
+       int charging_size;
+       struct twl4030_madc_bat_calibration *discharging;
+       int discharging_size;
+};
+
+#endif
index 804b90643a85eae1b42f46f6870b5be3f23b36c2..5c2600630dc99ace79f3d001416db6d37f568806 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/leds.h>
+#include <linux/spinlock.h>
 
 struct device;
 
@@ -194,6 +195,8 @@ struct power_supply {
        /* private */
        struct device *dev;
        struct work_struct changed_work;
+       spinlock_t changed_lock;
+       bool changed;
 #ifdef CONFIG_THERMAL
        struct thermal_zone_device *tzd;
        struct thermal_cooling_device *tcd;
index d13371134c59fbec0be79992a692257d8021a959..cc7494a3542983bbd4e73b95920eb981bb196716 100644 (file)
@@ -328,6 +328,7 @@ struct quotactl_ops {
        int (*set_dqblk)(struct super_block *, struct kqid, struct fs_disk_quota *);
        int (*get_xstate)(struct super_block *, struct fs_quota_stat *);
        int (*set_xstate)(struct super_block *, unsigned int, int);
+       int (*get_xstatev)(struct super_block *, struct fs_quota_statv *);
 };
 
 struct quota_format_type {
index ffc444c38b0ab64ab999da3d670dde338e669265..403940787be18230a5201799d57020ed46177cab 100644 (file)
@@ -231,6 +231,7 @@ unsigned long radix_tree_next_hole(struct radix_tree_root *root,
 unsigned long radix_tree_prev_hole(struct radix_tree_root *root,
                                unsigned long index, unsigned long max_scan);
 int radix_tree_preload(gfp_t gfp_mask);
+int radix_tree_maybe_preload(gfp_t gfp_mask);
 void radix_tree_init(void);
 void *radix_tree_tag_set(struct radix_tree_root *root,
                        unsigned long index, unsigned int tag);
index 0f424698064f5ee2c0a0da036189843c2e8cead4..73069cb6c54a15ea01bacdd9af20170be6ba257a 100644 (file)
@@ -101,6 +101,7 @@ extern const struct raid6_calls raid6_altivec8;
 extern const struct raid6_calls raid6_avx2x1;
 extern const struct raid6_calls raid6_avx2x2;
 extern const struct raid6_calls raid6_avx2x4;
+extern const struct raid6_calls raid6_tilegx8;
 
 struct raid6_recov_calls {
        void (*data2)(int, size_t, int, int, void **);
index 69e37c2d1ea556fb990f5d1c8cebd9fee39f8ca7..753207c8ce204fe11eab92f43d6c04b25e5ee753 100644 (file)
@@ -25,7 +25,7 @@ extern int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma);
 
 extern const struct file_operations ramfs_file_operations;
 extern const struct vm_operations_struct generic_file_vm_ops;
-extern int __init init_rootfs(void);
+extern int __init init_ramfs_fs(void);
 
 int ramfs_fill_super(struct super_block *sb, void *data, int silent);
 
index 0022c1bb1e26398c9db767a8eebc4fa153bff559..aa870a4ddf5428bd120d464f0ffb304ec27b868f 100644 (file)
@@ -68,6 +68,10 @@ extern struct rb_node *rb_prev(const struct rb_node *);
 extern struct rb_node *rb_first(const struct rb_root *);
 extern struct rb_node *rb_last(const struct rb_root *);
 
+/* Postorder iteration - always visit the parent after its children */
+extern struct rb_node *rb_first_postorder(const struct rb_root *);
+extern struct rb_node *rb_next_postorder(const struct rb_node *);
+
 /* Fast replacement of a single node without remove/rebalance/add/rebalance */
 extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, 
                            struct rb_root *root);
@@ -81,4 +85,22 @@ static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
        *rb_link = node;
 }
 
+/**
+ * rbtree_postorder_for_each_entry_safe - iterate over rb_root in post order of
+ * given type safe against removal of rb_node entry
+ *
+ * @pos:       the 'type *' to use as a loop cursor.
+ * @n:         another 'type *' to use as temporary storage
+ * @root:      'rb_root *' of the rbtree.
+ * @field:     the name of the rb_node field within 'type'.
+ */
+#define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \
+       for (pos = rb_entry(rb_first_postorder(root), typeof(*pos), field),\
+               n = rb_entry(rb_next_postorder(&pos->field), \
+                       typeof(*pos), field); \
+            &pos->field; \
+            pos = n, \
+               n = rb_entry(rb_next_postorder(&pos->field), \
+                       typeof(*pos), field))
+
 #endif /* _LINUX_RBTREE_H */
index 96a509b6be04eeaceecad4b6cc03d8d5ea60e451..201a6974965925bf5f9424acf0b63f671efd3c60 100644 (file)
@@ -54,7 +54,7 @@ struct res_counter {
        struct res_counter *parent;
 };
 
-#define RESOURCE_MAX (unsigned long long)LLONG_MAX
+#define RES_COUNTER_MAX ULLONG_MAX
 
 /**
  * Helpers to interact with userspace
index ce1e1c0aaa337fab9dda6de7f8f6d7529ca8a270..6682da36b293cfad598a0c5803e9e32038f72aa3 100644 (file)
@@ -1393,6 +1393,13 @@ struct task_struct {
                unsigned long memsw_nr_pages; /* uncharged mem+swap usage */
        } memcg_batch;
        unsigned int memcg_kmem_skip_account;
+       struct memcg_oom_info {
+               unsigned int may_oom:1;
+               unsigned int in_memcg_oom:1;
+               unsigned int oom_locked:1;
+               int wakeups;
+               struct mem_cgroup *wait_on_memcg;
+       } memcg_oom;
 #endif
 #ifdef CONFIG_UPROBES
        struct uprobe_task *utask;
@@ -2169,15 +2176,15 @@ static inline bool thread_group_leader(struct task_struct *p)
  * all we care about is that we have a task with the appropriate
  * pid, we don't actually care if we have the right task.
  */
-static inline int has_group_leader_pid(struct task_struct *p)
+static inline bool has_group_leader_pid(struct task_struct *p)
 {
-       return p->pid == p->tgid;
+       return task_pid(p) == p->signal->leader_pid;
 }
 
 static inline
-int same_thread_group(struct task_struct *p1, struct task_struct *p2)
+bool same_thread_group(struct task_struct *p1, struct task_struct *p2)
 {
-       return p1->tgid == p2->tgid;
+       return p1->signal == p2->signal;
 }
 
 static inline struct task_struct *next_thread(const struct task_struct *p)
index 18299057402f1bf9015cff936f9f2a37c01a5896..21a209336e794fcf70be28f5a27b7e5f31a734ee 100644 (file)
@@ -3,15 +3,21 @@
 /*
  * Reader/writer consistent mechanism without starving writers. This type of
  * lock for data where the reader wants a consistent set of information
- * and is willing to retry if the information changes.  Readers never
- * block but they may have to retry if a writer is in
- * progress. Writers do not wait for readers. 
+ * and is willing to retry if the information changes. There are two types
+ * of readers:
+ * 1. Sequence readers which never block a writer but they may have to retry
+ *    if a writer is in progress by detecting change in sequence number.
+ *    Writers do not wait for a sequence reader.
+ * 2. Locking readers which will wait if a writer or another locking reader
+ *    is in progress. A locking reader in progress will also block a writer
+ *    from going forward. Unlike the regular rwlock, the read lock here is
+ *    exclusive so that only one locking reader can get it.
  *
- * This is not as cache friendly as brlock. Also, this will not work
+ * This is not as cache friendly as brlock. Also, this may not work well
  * for data that contains pointers, because any writer could
  * invalidate a pointer that a reader was following.
  *
- * Expected reader usage:
+ * Expected non-blocking reader usage:
  *     do {
  *         seq = read_seqbegin(&foo);
  *     ...
@@ -268,4 +274,56 @@ write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags)
        spin_unlock_irqrestore(&sl->lock, flags);
 }
 
+/*
+ * A locking reader exclusively locks out other writers and locking readers,
+ * but doesn't update the sequence number. Acts like a normal spin_lock/unlock.
+ * Don't need preempt_disable() because that is in the spin_lock already.
+ */
+static inline void read_seqlock_excl(seqlock_t *sl)
+{
+       spin_lock(&sl->lock);
+}
+
+static inline void read_sequnlock_excl(seqlock_t *sl)
+{
+       spin_unlock(&sl->lock);
+}
+
+static inline void read_seqlock_excl_bh(seqlock_t *sl)
+{
+       spin_lock_bh(&sl->lock);
+}
+
+static inline void read_sequnlock_excl_bh(seqlock_t *sl)
+{
+       spin_unlock_bh(&sl->lock);
+}
+
+static inline void read_seqlock_excl_irq(seqlock_t *sl)
+{
+       spin_lock_irq(&sl->lock);
+}
+
+static inline void read_sequnlock_excl_irq(seqlock_t *sl)
+{
+       spin_unlock_irq(&sl->lock);
+}
+
+static inline unsigned long __read_seqlock_excl_irqsave(seqlock_t *sl)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sl->lock, flags);
+       return flags;
+}
+
+#define read_seqlock_excl_irqsave(lock, flags)                         \
+       do { flags = __read_seqlock_excl_irqsave(lock); } while (0)
+
+static inline void
+read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigned long flags)
+{
+       spin_unlock_irqrestore(&sl->lock, flags);
+}
+
 #endif /* __LINUX_SEQLOCK_H */
index 4e83f3e034f3873d531580550a1940b4b49f6461..b7b43b82231e0ae7fed55cae10c302ba4a04c105 100644 (file)
@@ -33,13 +33,44 @@ struct sh_dmae_slave_config {
        char            mid_rid;
 };
 
+/**
+ * struct sh_dmae_channel - DMAC channel platform data
+ * @offset:            register offset within the main IOMEM resource
+ * @dmars:             channel DMARS register offset
+ * @chclr_offset:      channel CHCLR register offset
+ * @dmars_bit:         channel DMARS field offset within the register
+ * @chclr_bit:         bit position, to be set to reset the channel
+ */
 struct sh_dmae_channel {
        unsigned int    offset;
        unsigned int    dmars;
-       unsigned int    dmars_bit;
        unsigned int    chclr_offset;
+       unsigned char   dmars_bit;
+       unsigned char   chclr_bit;
 };
 
+/**
+ * struct sh_dmae_pdata - DMAC platform data
+ * @slave:             array of slaves
+ * @slave_num:         number of slaves in the above array
+ * @channel:           array of DMA channels
+ * @channel_num:       number of channels in the above array
+ * @ts_low_shift:      shift of the low part of the TS field
+ * @ts_low_mask:       low TS field mask
+ * @ts_high_shift:     additional shift of the high part of the TS field
+ * @ts_high_mask:      high TS field mask
+ * @ts_shift:          array of Transfer Size shifts, indexed by TS value
+ * @ts_shift_num:      number of shifts in the above array
+ * @dmaor_init:                DMAOR initialisation value
+ * @chcr_offset:       CHCR address offset
+ * @chcr_ie_bit:       CHCR Interrupt Enable bit
+ * @dmaor_is_32bit:    DMAOR is a 32-bit register
+ * @needs_tend_set:    the TEND register has to be set
+ * @no_dmars:          DMAC has no DMARS registers
+ * @chclr_present:     DMAC has one or several CHCLR registers
+ * @chclr_bitwise:     channel CHCLR registers are bitwise
+ * @slave_only:                DMAC cannot be used for MEMCPY
+ */
 struct sh_dmae_pdata {
        const struct sh_dmae_slave_config *slave;
        int slave_num;
@@ -59,42 +90,22 @@ struct sh_dmae_pdata {
        unsigned int needs_tend_set:1;
        unsigned int no_dmars:1;
        unsigned int chclr_present:1;
+       unsigned int chclr_bitwise:1;
        unsigned int slave_only:1;
 };
 
-/* DMA register */
-#define SAR    0x00
-#define DAR    0x04
-#define TCR    0x08
-#define CHCR   0x0C
-#define DMAOR  0x40
-
-#define TEND   0x18 /* USB-DMAC */
-
 /* DMAOR definitions */
 #define DMAOR_AE       0x00000004
 #define DMAOR_NMIF     0x00000002
 #define DMAOR_DME      0x00000001
 
 /* Definitions for the SuperH DMAC */
-#define REQ_L  0x00000000
-#define REQ_E  0x00080000
-#define RACK_H 0x00000000
-#define RACK_L 0x00040000
-#define ACK_R  0x00000000
-#define ACK_W  0x00020000
-#define ACK_H  0x00000000
-#define ACK_L  0x00010000
 #define DM_INC 0x00004000
 #define DM_DEC 0x00008000
 #define DM_FIX 0x0000c000
 #define SM_INC 0x00001000
 #define SM_DEC 0x00002000
 #define SM_FIX 0x00003000
-#define RS_IN  0x00000200
-#define RS_OUT 0x00000300
-#define TS_BLK 0x00000040
-#define TM_BUR 0x00000020
 #define CHCR_DE        0x00000001
 #define CHCR_TE        0x00000002
 #define CHCR_IE        0x00000004
index 5b1c9848124cb8c366f95a0dbfaa6d54d64d1927..f92c0a43c54cb9ee2465e8e4c726cc1a1e630096 100644 (file)
@@ -96,7 +96,7 @@ struct shdma_ops {
        dma_addr_t (*slave_addr)(struct shdma_chan *);
        int (*desc_setup)(struct shdma_chan *, struct shdma_desc *,
                          dma_addr_t, dma_addr_t, size_t *);
-       int (*set_slave)(struct shdma_chan *, int, bool);
+       int (*set_slave)(struct shdma_chan *, int, dma_addr_t, bool);
        void (*setup_xfer)(struct shdma_chan *, int);
        void (*start_xfer)(struct shdma_chan *, struct shdma_desc *);
        struct shdma_desc *(*embedded_desc)(void *, int);
@@ -116,7 +116,6 @@ struct shdma_dev {
 
 int shdma_request_irq(struct shdma_chan *, int,
                           unsigned long, const char *);
-void shdma_free_irq(struct shdma_chan *);
 bool shdma_reset(struct shdma_dev *sdev);
 void shdma_chan_probe(struct shdma_dev *sdev,
                           struct shdma_chan *schan, int id);
index ac6b8ee07825ee6ce99dff9faf9901a224a97b5e..68c097077ef04af4533dd3ccc0272db8564bf269 100644 (file)
@@ -4,39 +4,67 @@
 /*
  * This struct is used to pass information from page reclaim to the shrinkers.
  * We consolidate the values for easier extention later.
+ *
+ * The 'gfpmask' refers to the allocation we are currently trying to
+ * fulfil.
  */
 struct shrink_control {
        gfp_t gfp_mask;
 
-       /* How many slab objects shrinker() should scan and try to reclaim */
+       /*
+        * How many objects scan_objects should scan and try to reclaim.
+        * This is reset before every call, so it is safe for callees
+        * to modify.
+        */
        unsigned long nr_to_scan;
+
+       /* shrink from these nodes */
+       nodemask_t nodes_to_scan;
+       /* current node being shrunk (for NUMA aware shrinkers) */
+       int nid;
 };
 
+#define SHRINK_STOP (~0UL)
 /*
  * A callback you can register to apply pressure to ageable caches.
  *
- * 'sc' is passed shrink_control which includes a count 'nr_to_scan'
- * and a 'gfpmask'.  It should look through the least-recently-used
- * 'nr_to_scan' entries and attempt to free them up.  It should return
- * the number of objects which remain in the cache.  If it returns -1, it means
- * it cannot do any scanning at this time (eg. there is a risk of deadlock).
+ * @count_objects should return the number of freeable items in the cache. If
+ * there are no objects to free or the number of freeable items cannot be
+ * determined, it should return 0. No deadlock checks should be done during the
+ * count callback - the shrinker relies on aggregating scan counts that couldn't
+ * be executed due to potential deadlocks to be run at a later call when the
+ * deadlock condition is no longer pending.
  *
- * The 'gfpmask' refers to the allocation we are currently trying to
- * fulfil.
+ * @scan_objects will only be called if @count_objects returned a non-zero
+ * value for the number of freeable objects. The callout should scan the cache
+ * and attempt to free items from the cache. It should then return the number
+ * of objects freed during the scan, or SHRINK_STOP if progress cannot be made
+ * due to potential deadlocks. If SHRINK_STOP is returned, then no further
+ * attempts to call the @scan_objects will be made from the current reclaim
+ * context.
  *
- * Note that 'shrink' will be passed nr_to_scan == 0 when the VM is
- * querying the cache size, so a fastpath for that case is appropriate.
+ * @flags determine the shrinker abilities, like numa awareness
  */
 struct shrinker {
-       int (*shrink)(struct shrinker *, struct shrink_control *sc);
+       unsigned long (*count_objects)(struct shrinker *,
+                                      struct shrink_control *sc);
+       unsigned long (*scan_objects)(struct shrinker *,
+                                     struct shrink_control *sc);
+
        int seeks;      /* seeks to recreate an obj */
        long batch;     /* reclaim batch size, 0 = default */
+       unsigned long flags;
 
        /* These are for internal use */
        struct list_head list;
-       atomic_long_t nr_in_batch; /* objs pending delete */
+       /* objs pending delete, per node */
+       atomic_long_t *nr_deferred;
 };
 #define DEFAULT_SEEKS 2 /* A good number if you don't know better. */
-extern void register_shrinker(struct shrinker *);
+
+/* Flags */
+#define SHRINKER_NUMA_AWARE (1 << 0)
+
+extern int register_shrinker(struct shrinker *);
 extern void unregister_shrinker(struct shrinker *);
 #endif
index 6c5cc0ea871348673c2a45253e377c1136402250..74f105847d13ceae757c8aa6b83bdf8412816696 100644 (file)
@@ -4,6 +4,8 @@
  * (C) SGI 2006, Christoph Lameter
  *     Cleaned up and restructured to ease the addition of alternative
  *     implementations of SLAB allocators.
+ * (C) Linux Foundation 2008-2013
+ *      Unified interface for all slab allocators
  */
 
 #ifndef _LINUX_SLAB_H
@@ -94,6 +96,7 @@
 #define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \
                                (unsigned long)ZERO_SIZE_PTR)
 
+#include <linux/kmemleak.h>
 
 struct mem_cgroup;
 /*
@@ -289,6 +292,57 @@ static __always_inline int kmalloc_index(size_t size)
 }
 #endif /* !CONFIG_SLOB */
 
+void *__kmalloc(size_t size, gfp_t flags);
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags);
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t flags, int node);
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+#else
+static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
+{
+       return __kmalloc(size, flags);
+}
+
+static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node)
+{
+       return kmem_cache_alloc(s, flags);
+}
+#endif
+
+#ifdef CONFIG_TRACING
+extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t);
+
+#ifdef CONFIG_NUMA
+extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
+                                          gfp_t gfpflags,
+                                          int node, size_t size);
+#else
+static __always_inline void *
+kmem_cache_alloc_node_trace(struct kmem_cache *s,
+                             gfp_t gfpflags,
+                             int node, size_t size)
+{
+       return kmem_cache_alloc_trace(s, gfpflags, size);
+}
+#endif /* CONFIG_NUMA */
+
+#else /* CONFIG_TRACING */
+static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s,
+               gfp_t flags, size_t size)
+{
+       return kmem_cache_alloc(s, flags);
+}
+
+static __always_inline void *
+kmem_cache_alloc_node_trace(struct kmem_cache *s,
+                             gfp_t gfpflags,
+                             int node, size_t size)
+{
+       return kmem_cache_alloc_node(s, gfpflags, node);
+}
+#endif /* CONFIG_TRACING */
+
 #ifdef CONFIG_SLAB
 #include <linux/slab_def.h>
 #endif
@@ -297,9 +351,60 @@ static __always_inline int kmalloc_index(size_t size)
 #include <linux/slub_def.h>
 #endif
 
-#ifdef CONFIG_SLOB
-#include <linux/slob_def.h>
+static __always_inline void *
+kmalloc_order(size_t size, gfp_t flags, unsigned int order)
+{
+       void *ret;
+
+       flags |= (__GFP_COMP | __GFP_KMEMCG);
+       ret = (void *) __get_free_pages(flags, order);
+       kmemleak_alloc(ret, size, 1, flags);
+       return ret;
+}
+
+#ifdef CONFIG_TRACING
+extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
+#else
+static __always_inline void *
+kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
+{
+       return kmalloc_order(size, flags, order);
+}
+#endif
+
+static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
+{
+       unsigned int order = get_order(size);
+       return kmalloc_order_trace(size, flags, order);
+}
+
+/**
+ * kmalloc - allocate memory
+ * @size: how many bytes of memory are required.
+ * @flags: the type of memory to allocate (see kcalloc).
+ *
+ * kmalloc is the normal method of allocating memory
+ * for objects smaller than page size in the kernel.
+ */
+static __always_inline void *kmalloc(size_t size, gfp_t flags)
+{
+       if (__builtin_constant_p(size)) {
+               if (size > KMALLOC_MAX_CACHE_SIZE)
+                       return kmalloc_large(size, flags);
+#ifndef CONFIG_SLOB
+               if (!(flags & GFP_DMA)) {
+                       int index = kmalloc_index(size);
+
+                       if (!index)
+                               return ZERO_SIZE_PTR;
+
+                       return kmem_cache_alloc_trace(kmalloc_caches[index],
+                                       flags, size);
+               }
 #endif
+       }
+       return __kmalloc(size, flags);
+}
 
 /*
  * Determine size used for the nth kmalloc cache.
@@ -321,6 +426,23 @@ static __always_inline int kmalloc_size(int n)
        return 0;
 }
 
+static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
+{
+#ifndef CONFIG_SLOB
+       if (__builtin_constant_p(size) &&
+               size <= KMALLOC_MAX_CACHE_SIZE && !(flags & GFP_DMA)) {
+               int i = kmalloc_index(size);
+
+               if (!i)
+                       return ZERO_SIZE_PTR;
+
+               return kmem_cache_alloc_node_trace(kmalloc_caches[i],
+                                               flags, node, size);
+       }
+#endif
+       return __kmalloc_node(size, flags, node);
+}
+
 /*
  * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
  * Intended for arches that get misalignment faults even for 64 bit integer
@@ -451,36 +573,6 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
        return kmalloc_array(n, size, flags | __GFP_ZERO);
 }
 
-#if !defined(CONFIG_NUMA) && !defined(CONFIG_SLOB)
-/**
- * kmalloc_node - allocate memory from a specific node
- * @size: how many bytes of memory are required.
- * @flags: the type of memory to allocate (see kmalloc).
- * @node: node to allocate from.
- *
- * kmalloc() for non-local nodes, used to allocate from a specific node
- * if available. Equivalent to kmalloc() in the non-NUMA single-node
- * case.
- */
-static inline void *kmalloc_node(size_t size, gfp_t flags, int node)
-{
-       return kmalloc(size, flags);
-}
-
-static inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
-{
-       return __kmalloc(size, flags);
-}
-
-void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
-
-static inline void *kmem_cache_alloc_node(struct kmem_cache *cachep,
-                                       gfp_t flags, int node)
-{
-       return kmem_cache_alloc(cachep, flags);
-}
-#endif /* !CONFIG_NUMA && !CONFIG_SLOB */
-
 /*
  * kmalloc_track_caller is a special version of kmalloc that records the
  * calling function of the routine calling it for slab leak tracking instead
index cd401580bdd30f2f0c6fb586e8244f7e6756b1fa..e9346b4f1ef4b2ef6d302a5799e30e631fa10ce2 100644 (file)
@@ -3,20 +3,6 @@
 
 /*
  * Definitions unique to the original Linux SLAB allocator.
- *
- * What we provide here is a way to optimize the frequent kmalloc
- * calls in the kernel by selecting the appropriate general cache
- * if kmalloc was called with a size that can be established at
- * compile time.
- */
-
-#include <linux/init.h>
-#include <linux/compiler.h>
-
-/*
- * struct kmem_cache
- *
- * manages a cache.
  */
 
 struct kmem_cache {
@@ -102,96 +88,4 @@ struct kmem_cache {
         */
 };
 
-void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
-void *__kmalloc(size_t size, gfp_t flags);
-
-#ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t);
-#else
-static __always_inline void *
-kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size)
-{
-       return kmem_cache_alloc(cachep, flags);
-}
-#endif
-
-static __always_inline void *kmalloc(size_t size, gfp_t flags)
-{
-       struct kmem_cache *cachep;
-       void *ret;
-
-       if (__builtin_constant_p(size)) {
-               int i;
-
-               if (!size)
-                       return ZERO_SIZE_PTR;
-
-               if (WARN_ON_ONCE(size > KMALLOC_MAX_SIZE))
-                       return NULL;
-
-               i = kmalloc_index(size);
-
-#ifdef CONFIG_ZONE_DMA
-               if (flags & GFP_DMA)
-                       cachep = kmalloc_dma_caches[i];
-               else
-#endif
-                       cachep = kmalloc_caches[i];
-
-               ret = kmem_cache_alloc_trace(cachep, flags, size);
-
-               return ret;
-       }
-       return __kmalloc(size, flags);
-}
-
-#ifdef CONFIG_NUMA
-extern void *__kmalloc_node(size_t size, gfp_t flags, int node);
-extern void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
-
-#ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
-                                        gfp_t flags,
-                                        int nodeid,
-                                        size_t size);
-#else
-static __always_inline void *
-kmem_cache_alloc_node_trace(struct kmem_cache *cachep,
-                           gfp_t flags,
-                           int nodeid,
-                           size_t size)
-{
-       return kmem_cache_alloc_node(cachep, flags, nodeid);
-}
-#endif
-
-static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
-{
-       struct kmem_cache *cachep;
-
-       if (__builtin_constant_p(size)) {
-               int i;
-
-               if (!size)
-                       return ZERO_SIZE_PTR;
-
-               if (WARN_ON_ONCE(size > KMALLOC_MAX_SIZE))
-                       return NULL;
-
-               i = kmalloc_index(size);
-
-#ifdef CONFIG_ZONE_DMA
-               if (flags & GFP_DMA)
-                       cachep = kmalloc_dma_caches[i];
-               else
-#endif
-                       cachep = kmalloc_caches[i];
-
-               return kmem_cache_alloc_node_trace(cachep, flags, node, size);
-       }
-       return __kmalloc_node(size, flags, node);
-}
-
-#endif /* CONFIG_NUMA */
-
 #endif /* _LINUX_SLAB_DEF_H */
diff --git a/include/linux/slob_def.h b/include/linux/slob_def.h
deleted file mode 100644 (file)
index 095a5a4..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __LINUX_SLOB_DEF_H
-#define __LINUX_SLOB_DEF_H
-
-#include <linux/numa.h>
-
-void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
-
-static __always_inline void *kmem_cache_alloc(struct kmem_cache *cachep,
-                                             gfp_t flags)
-{
-       return kmem_cache_alloc_node(cachep, flags, NUMA_NO_NODE);
-}
-
-void *__kmalloc_node(size_t size, gfp_t flags, int node);
-
-static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
-{
-       return __kmalloc_node(size, flags, node);
-}
-
-static __always_inline void *kmalloc(size_t size, gfp_t flags)
-{
-       return __kmalloc_node(size, flags, NUMA_NO_NODE);
-}
-
-static __always_inline void *__kmalloc(size_t size, gfp_t flags)
-{
-       return kmalloc(size, flags);
-}
-
-#endif /* __LINUX_SLOB_DEF_H */
index 027276fa87132728d2c914ccc38fc09bc7602395..cc0b67eada4260331276e9ae145fa593c14ecee8 100644 (file)
@@ -6,14 +6,8 @@
  *
  * (C) 2007 SGI, Christoph Lameter
  */
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/bug.h>
-#include <linux/workqueue.h>
 #include <linux/kobject.h>
 
-#include <linux/kmemleak.h>
-
 enum stat_item {
        ALLOC_FASTPATH,         /* Allocation from cpu slab */
        ALLOC_SLOWPATH,         /* Allocation by getting a new cpu slab */
@@ -104,108 +98,4 @@ struct kmem_cache {
        struct kmem_cache_node *node[MAX_NUMNODES];
 };
 
-void *kmem_cache_alloc(struct kmem_cache *, gfp_t);
-void *__kmalloc(size_t size, gfp_t flags);
-
-static __always_inline void *
-kmalloc_order(size_t size, gfp_t flags, unsigned int order)
-{
-       void *ret;
-
-       flags |= (__GFP_COMP | __GFP_KMEMCG);
-       ret = (void *) __get_free_pages(flags, order);
-       kmemleak_alloc(ret, size, 1, flags);
-       return ret;
-}
-
-/**
- * Calling this on allocated memory will check that the memory
- * is expected to be in use, and print warnings if not.
- */
-#ifdef CONFIG_SLUB_DEBUG
-extern bool verify_mem_not_deleted(const void *x);
-#else
-static inline bool verify_mem_not_deleted(const void *x)
-{
-       return true;
-}
-#endif
-
-#ifdef CONFIG_TRACING
-extern void *
-kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size);
-extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
-#else
-static __always_inline void *
-kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
-{
-       return kmem_cache_alloc(s, gfpflags);
-}
-
-static __always_inline void *
-kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
-{
-       return kmalloc_order(size, flags, order);
-}
-#endif
-
-static __always_inline void *kmalloc_large(size_t size, gfp_t flags)
-{
-       unsigned int order = get_order(size);
-       return kmalloc_order_trace(size, flags, order);
-}
-
-static __always_inline void *kmalloc(size_t size, gfp_t flags)
-{
-       if (__builtin_constant_p(size)) {
-               if (size > KMALLOC_MAX_CACHE_SIZE)
-                       return kmalloc_large(size, flags);
-
-               if (!(flags & GFP_DMA)) {
-                       int index = kmalloc_index(size);
-
-                       if (!index)
-                               return ZERO_SIZE_PTR;
-
-                       return kmem_cache_alloc_trace(kmalloc_caches[index],
-                                       flags, size);
-               }
-       }
-       return __kmalloc(size, flags);
-}
-
-#ifdef CONFIG_NUMA
-void *__kmalloc_node(size_t size, gfp_t flags, int node);
-void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
-
-#ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
-                                          gfp_t gfpflags,
-                                          int node, size_t size);
-#else
-static __always_inline void *
-kmem_cache_alloc_node_trace(struct kmem_cache *s,
-                             gfp_t gfpflags,
-                             int node, size_t size)
-{
-       return kmem_cache_alloc_node(s, gfpflags, node);
-}
-#endif
-
-static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
-{
-       if (__builtin_constant_p(size) &&
-               size <= KMALLOC_MAX_CACHE_SIZE && !(flags & GFP_DMA)) {
-               int index = kmalloc_index(size);
-
-               if (!index)
-                       return ZERO_SIZE_PTR;
-
-               return kmem_cache_alloc_node_trace(kmalloc_caches[index],
-                              flags, node, size);
-       }
-       return __kmalloc_node(size, flags, node);
-}
-#endif
-
 #endif /* _LINUX_SLUB_DEF_H */
index c181399f2c20e3a7ffedd868c20803c87843e2bf..cfb7ca094b384522d2378c2a952bbe788812f1c6 100644 (file)
@@ -28,6 +28,27 @@ extern unsigned int total_cpus;
 int smp_call_function_single(int cpuid, smp_call_func_t func, void *info,
                             int wait);
 
+/*
+ * Call a function on all processors
+ */
+int on_each_cpu(smp_call_func_t func, void *info, int wait);
+
+/*
+ * Call a function on processors specified by mask, which might include
+ * the local one.
+ */
+void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
+               void *info, bool wait);
+
+/*
+ * Call a function on each processor for which the supplied function
+ * cond_func returns a positive value. This may include the local
+ * processor.
+ */
+void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
+               smp_call_func_t func, void *info, bool wait,
+               gfp_t gfp_flags);
+
 #ifdef CONFIG_SMP
 
 #include <linux/preempt.h>
@@ -94,27 +115,6 @@ void generic_smp_call_function_single_interrupt(void);
 static inline void call_function_init(void) { }
 #endif
 
-/*
- * Call a function on all processors
- */
-int on_each_cpu(smp_call_func_t func, void *info, int wait);
-
-/*
- * Call a function on processors specified by mask, which might include
- * the local one.
- */
-void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
-               void *info, bool wait);
-
-/*
- * Call a function on each processor for which the supplied function
- * cond_func returns a positive value. This may include the local
- * processor.
- */
-void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
-               smp_call_func_t func, void *info, bool wait,
-               gfp_t gfp_flags);
-
 /*
  * Mark the boot cpu "online" so that it can call console drivers in
  * printk() and can access its per-cpu storage.
@@ -139,43 +139,6 @@ static inline int up_smp_call_function(smp_call_func_t func, void *info)
 }
 #define smp_call_function(func, info, wait) \
                        (up_smp_call_function(func, info))
-#define on_each_cpu(func, info, wait)          \
-       ({                                      \
-               unsigned long __flags;          \
-               local_irq_save(__flags);        \
-               func(info);                     \
-               local_irq_restore(__flags);     \
-               0;                              \
-       })
-/*
- * Note we still need to test the mask even for UP
- * because we actually can get an empty mask from
- * code that on SMP might call us without the local
- * CPU in the mask.
- */
-#define on_each_cpu_mask(mask, func, info, wait) \
-       do {                                            \
-               if (cpumask_test_cpu(0, (mask))) {      \
-                       local_irq_disable();            \
-                       (func)(info);                   \
-                       local_irq_enable();             \
-               }                                       \
-       } while (0)
-/*
- * Preemption is disabled here to make sure the cond_func is called under the
- * same condtions in UP and SMP.
- */
-#define on_each_cpu_cond(cond_func, func, info, wait, gfp_flags)\
-       do {                                                    \
-               void *__info = (info);                          \
-               preempt_disable();                              \
-               if ((cond_func)(0, __info)) {                   \
-                       local_irq_disable();                    \
-                       (func)(__info);                         \
-                       local_irq_enable();                     \
-               }                                               \
-               preempt_enable();                               \
-       } while (0)
 
 static inline void smp_send_reschedule(int cpu) { }
 #define smp_prepare_boot_cpu()                 do {} while (0)
index 32be8dbdf1917b900b4a97ac19d02447915a098c..274bc0fa00af6e2662f47f7d14b5f25c7649dbd8 100644 (file)
@@ -7,6 +7,11 @@
 struct device;
 struct mmc_host;
 
+#define MMC_SPI_USE_CD_GPIO                    (1 << 0)
+#define MMC_SPI_USE_RO_GPIO                    (1 << 1)
+#define MMC_SPI_CD_GPIO_ACTIVE_LOW             (1 << 2)
+#define MMC_SPI_RO_GPIO_ACTIVE_LOW             (1 << 3)
+
 /* Put this in platform_data of a device being used to manage an MMC/SD
  * card slot.  (Modeled after PXA mmc glue; see that for usage examples.)
  *
@@ -21,17 +26,19 @@ struct mmc_spi_platform_data {
                void *);
        void (*exit)(struct device *, void *);
 
-       /* sense switch on sd cards */
-       int (*get_ro)(struct device *);
-
        /*
-        * If board does not use CD interrupts, driver can optimize polling
-        * using this function.
+        * Card Detect and Read Only GPIOs. To enable debouncing on the card
+        * detect GPIO, set the cd_debounce to the debounce time in
+        * microseconds.
         */
-       int (*get_cd)(struct device *);
+       unsigned int flags;
+       unsigned int cd_gpio;
+       unsigned int cd_debounce;
+       unsigned int ro_gpio;
 
        /* Capabilities to pass into mmc core (e.g. MMC_CAP_NEEDS_POLL). */
        unsigned long caps;
+       unsigned long caps2;
 
        /* how long to debounce card detect, in msecs */
        u16 detect_delay;
index 0dd00f4f681046018f25292cc288632dc2593caa..790be1472792a3fc49fcf81edd7d7e9c2ab08128 100644 (file)
 
 struct rpcsec_gss_info;
 
+/* auth_cred ac_flags bits */
+enum {
+       RPC_CRED_NO_CRKEY_TIMEOUT = 0, /* underlying cred has no key timeout */
+       RPC_CRED_KEY_EXPIRE_SOON = 1, /* underlying cred key will expire soon */
+       RPC_CRED_NOTIFY_TIMEOUT = 2,   /* nofity generic cred when underlying
+                                       key will expire soon */
+};
+
 /* Work around the lack of a VFS credential */
 struct auth_cred {
        kuid_t  uid;
        kgid_t  gid;
        struct group_info *group_info;
        const char *principal;
+       unsigned long ac_flags;
        unsigned char machine_cred : 1;
 };
 
@@ -87,6 +96,11 @@ struct rpc_auth {
        /* per-flavor data */
 };
 
+struct rpc_auth_create_args {
+       rpc_authflavor_t pseudoflavor;
+       const char *target_name;
+};
+
 /* Flags for rpcauth_lookupcred() */
 #define RPCAUTH_LOOKUP_NEW             0x01    /* Accept an uninitialised cred */
 
@@ -97,17 +111,17 @@ struct rpc_authops {
        struct module           *owner;
        rpc_authflavor_t        au_flavor;      /* flavor (RPC_AUTH_*) */
        char *                  au_name;
-       struct rpc_auth *       (*create)(struct rpc_clnt *, rpc_authflavor_t);
+       struct rpc_auth *       (*create)(struct rpc_auth_create_args *, struct rpc_clnt *);
        void                    (*destroy)(struct rpc_auth *);
 
        struct rpc_cred *       (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int);
        struct rpc_cred *       (*crcreate)(struct rpc_auth*, struct auth_cred *, int);
-       int                     (*pipes_create)(struct rpc_auth *);
-       void                    (*pipes_destroy)(struct rpc_auth *);
        int                     (*list_pseudoflavors)(rpc_authflavor_t *, int);
        rpc_authflavor_t        (*info2flavor)(struct rpcsec_gss_info *);
        int                     (*flavor2info)(rpc_authflavor_t,
                                                struct rpcsec_gss_info *);
+       int                     (*key_timeout)(struct rpc_auth *,
+                                               struct rpc_cred *);
 };
 
 struct rpc_credops {
@@ -124,6 +138,8 @@ struct rpc_credops {
                                                void *, __be32 *, void *);
        int                     (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t,
                                                void *, __be32 *, void *);
+       int                     (*crkey_timeout)(struct rpc_cred *);
+       bool                    (*crkey_to_expire)(struct rpc_cred *);
 };
 
 extern const struct rpc_authops        authunix_ops;
@@ -140,7 +156,8 @@ struct rpc_cred *   rpc_lookup_cred(void);
 struct rpc_cred *      rpc_lookup_machine_cred(const char *service_name);
 int                    rpcauth_register(const struct rpc_authops *);
 int                    rpcauth_unregister(const struct rpc_authops *);
-struct rpc_auth *      rpcauth_create(rpc_authflavor_t, struct rpc_clnt *);
+struct rpc_auth *      rpcauth_create(struct rpc_auth_create_args *,
+                               struct rpc_clnt *);
 void                   rpcauth_release(struct rpc_auth *);
 rpc_authflavor_t       rpcauth_get_pseudoflavor(rpc_authflavor_t,
                                struct rpcsec_gss_info *);
@@ -162,6 +179,9 @@ int                 rpcauth_uptodatecred(struct rpc_task *);
 int                    rpcauth_init_credcache(struct rpc_auth *);
 void                   rpcauth_destroy_credcache(struct rpc_auth *);
 void                   rpcauth_clear_credcache(struct rpc_cred_cache *);
+int                    rpcauth_key_timeout_notify(struct rpc_auth *,
+                                               struct rpc_cred *);
+bool                   rpcauth_cred_key_to_expire(struct rpc_cred *);
 
 static inline
 struct rpc_cred *      get_rpccred(struct rpc_cred *cred)
index 6ce690de447fe80f5967fbc7b459cce646b4706a..437ddb6c4aefbcf4d1b5abbacd6cfcd1ff5a9b3b 100644 (file)
@@ -264,12 +264,30 @@ static inline int get_uint(char **bpp, unsigned int *anint)
        return 0;
 }
 
+static inline int get_time(char **bpp, time_t *time)
+{
+       char buf[50];
+       long long ll;
+       int len = qword_get(bpp, buf, sizeof(buf));
+
+       if (len < 0)
+               return -EINVAL;
+       if (len == 0)
+               return -ENOENT;
+
+       if (kstrtoll(buf, 0, &ll))
+               return -EINVAL;
+
+       *time = (time_t)ll;
+       return 0;
+}
+
 static inline time_t get_expiry(char **bpp)
 {
-       int rv;
+       time_t rv;
        struct timespec boot;
 
-       if (get_int(bpp, &rv))
+       if (get_time(bpp, &rv))
                return 0;
        if (rv < 0)
                return 0;
index bfe11be81f6fd46dfa1a20de478ceadf4418ac10..6740801aa71ab519c59bd21a7e50ee5793cc242a 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/sunrpc/stats.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/timer.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 #include <asm/signal.h>
 #include <linux/path.h>
 #include <net/ipv6.h>
@@ -32,6 +33,7 @@ struct rpc_inode;
  */
 struct rpc_clnt {
        atomic_t                cl_count;       /* Number of references */
+       unsigned int            cl_clid;        /* client id */
        struct list_head        cl_clients;     /* Global list of clients */
        struct list_head        cl_tasks;       /* List of tasks */
        spinlock_t              cl_lock;        /* spinlock */
@@ -41,7 +43,6 @@ struct rpc_clnt {
                                cl_vers,        /* RPC version number */
                                cl_maxproc;     /* max procedure number */
 
-       const char *            cl_protname;    /* protocol name */
        struct rpc_auth *       cl_auth;        /* authenticator */
        struct rpc_stat *       cl_stats;       /* per-program statistics */
        struct rpc_iostats *    cl_metrics;     /* per-client statistics */
@@ -56,12 +57,11 @@ struct rpc_clnt {
 
        int                     cl_nodelen;     /* nodename length */
        char                    cl_nodename[UNX_MAXNODENAME];
-       struct dentry *         cl_dentry;
+       struct rpc_pipe_dir_head cl_pipedir_objects;
        struct rpc_clnt *       cl_parent;      /* Points to parent of clones */
        struct rpc_rtt          cl_rtt_default;
        struct rpc_timeout      cl_timeout_default;
        const struct rpc_program *cl_program;
-       char                    *cl_principal;  /* target to authenticate to */
 };
 
 /*
index aa5b582cc4711c9d929996e31e76fe4fa93ad31d..a353e0300b54b97a63cf4b87baf28cacf91428b8 100644 (file)
@@ -5,6 +5,26 @@
 
 #include <linux/workqueue.h>
 
+struct rpc_pipe_dir_head {
+       struct list_head pdh_entries;
+       struct dentry *pdh_dentry;
+};
+
+struct rpc_pipe_dir_object_ops;
+struct rpc_pipe_dir_object {
+       struct list_head pdo_head;
+       const struct rpc_pipe_dir_object_ops *pdo_ops;
+
+       void *pdo_data;
+};
+
+struct rpc_pipe_dir_object_ops {
+       int (*create)(struct dentry *dir,
+                       struct rpc_pipe_dir_object *pdo);
+       void (*destroy)(struct dentry *dir,
+                       struct rpc_pipe_dir_object *pdo);
+};
+
 struct rpc_pipe_msg {
        struct list_head list;
        void *data;
@@ -74,7 +94,24 @@ extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *);
 
 struct rpc_clnt;
 extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *);
-extern int rpc_remove_client_dir(struct dentry *);
+extern int rpc_remove_client_dir(struct rpc_clnt *);
+
+extern void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh);
+extern void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
+               const struct rpc_pipe_dir_object_ops *pdo_ops,
+               void *pdo_data);
+extern int rpc_add_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo);
+extern void rpc_remove_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo);
+extern struct rpc_pipe_dir_object *rpc_find_or_alloc_pipe_dir_object(
+               struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               int (*match)(struct rpc_pipe_dir_object *, void *),
+               struct rpc_pipe_dir_object *(*alloc)(void *),
+               void *data);
 
 struct cache_detail;
 extern struct dentry *rpc_create_cache_dir(struct dentry *,
index 1821445708d62d81bb1176ecb20f8480fa4799fa..096ee58be11a83f2fc05107639a2273cc0c677e6 100644 (file)
@@ -79,7 +79,7 @@ struct rpc_task {
        unsigned short          tk_flags;       /* misc flags */
        unsigned short          tk_timeouts;    /* maj timeouts */
 
-#ifdef RPC_DEBUG
+#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
        unsigned short          tk_pid;         /* debugging aid */
 #endif
        unsigned char           tk_priority : 2,/* Task priority */
index 1f0216b9a6c9d0cbd556cfa501ec7739997c2361..6eecfc2e4f989b8e9511719cee900f75e057850c 100644 (file)
@@ -243,7 +243,6 @@ struct svc_rqst {
        struct xdr_buf          rq_res;
        struct page *           rq_pages[RPCSVC_MAXPAGES];
        struct page *           *rq_respages;   /* points into rq_pages */
-       int                     rq_resused;     /* number of pages used for result */
        struct page *           *rq_next_page; /* next reply page to use */
 
        struct kvec             rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
index d95cde5e257d9d23c71190109ba97d373668ebf9..46ba0c6c219fbb64523741a316efcdd3d909a742 100644 (file)
@@ -181,6 +181,33 @@ enum {
 #define COUNT_CONTINUED        0x80    /* See swap_map continuation for full count */
 #define SWAP_MAP_SHMEM 0xbf    /* Owned by shmem/tmpfs, in first swap_map */
 
+/*
+ * We use this to track usage of a cluster. A cluster is a block of swap disk
+ * space with SWAPFILE_CLUSTER pages long and naturally aligns in disk. All
+ * free clusters are organized into a list. We fetch an entry from the list to
+ * get a free cluster.
+ *
+ * The data field stores next cluster if the cluster is free or cluster usage
+ * counter otherwise. The flags field determines if a cluster is free. This is
+ * protected by swap_info_struct.lock.
+ */
+struct swap_cluster_info {
+       unsigned int data:24;
+       unsigned int flags:8;
+};
+#define CLUSTER_FLAG_FREE 1 /* This cluster is free */
+#define CLUSTER_FLAG_NEXT_NULL 2 /* This cluster has no next cluster */
+
+/*
+ * We assign a cluster to each CPU, so each CPU can allocate swap entry from
+ * its own cluster and swapout sequentially. The purpose is to optimize swapout
+ * throughput.
+ */
+struct percpu_cluster {
+       struct swap_cluster_info index; /* Current cluster index */
+       unsigned int next; /* Likely next allocation offset */
+};
+
 /*
  * The in-memory structure used to track swap areas.
  */
@@ -191,14 +218,16 @@ struct swap_info_struct {
        signed char     next;           /* next type on the swap list */
        unsigned int    max;            /* extent of the swap_map */
        unsigned char *swap_map;        /* vmalloc'ed array of usage counts */
+       struct swap_cluster_info *cluster_info; /* cluster info. Only for SSD */
+       struct swap_cluster_info free_cluster_head; /* free cluster list head */
+       struct swap_cluster_info free_cluster_tail; /* free cluster list tail */
        unsigned int lowest_bit;        /* index of first free in swap_map */
        unsigned int highest_bit;       /* index of last free in swap_map */
        unsigned int pages;             /* total of usable pages of swap */
        unsigned int inuse_pages;       /* number of those currently in use */
        unsigned int cluster_next;      /* likely index for next allocation */
        unsigned int cluster_nr;        /* countdown to next cluster search */
-       unsigned int lowest_alloc;      /* while preparing discard cluster */
-       unsigned int highest_alloc;     /* while preparing discard cluster */
+       struct percpu_cluster __percpu *percpu_cluster; /* per cpu's swap location */
        struct swap_extent *curr_swap_extent;
        struct swap_extent first_swap_extent;
        struct block_device *bdev;      /* swap device or bdev of swap file */
@@ -212,14 +241,18 @@ struct swap_info_struct {
                                         * protect map scan related fields like
                                         * swap_map, lowest_bit, highest_bit,
                                         * inuse_pages, cluster_next,
-                                        * cluster_nr, lowest_alloc and
-                                        * highest_alloc. other fields are only
-                                        * changed at swapon/swapoff, so are
-                                        * protected by swap_lock. changing
-                                        * flags need hold this lock and
-                                        * swap_lock. If both locks need hold,
-                                        * hold swap_lock first.
+                                        * cluster_nr, lowest_alloc,
+                                        * highest_alloc, free/discard cluster
+                                        * list. other fields are only changed
+                                        * at swapon/swapoff, so are protected
+                                        * by swap_lock. changing flags need
+                                        * hold this lock and swap_lock. If
+                                        * both locks need hold, hold swap_lock
+                                        * first.
                                         */
+       struct work_struct discard_work; /* discard worker */
+       struct swap_cluster_info discard_cluster_head; /* list head of discard clusters */
+       struct swap_cluster_info discard_cluster_tail; /* list tail of discard clusters */
 };
 
 struct swap_list_t {
@@ -247,7 +280,7 @@ extern void activate_page(struct page *);
 extern void mark_page_accessed(struct page *);
 extern void lru_add_drain(void);
 extern void lru_add_drain_cpu(int cpu);
-extern int lru_add_drain_all(void);
+extern void lru_add_drain_all(void);
 extern void rotate_reclaimable_page(struct page *page);
 extern void deactivate_page(struct page *page);
 extern void swap_setup(void);
@@ -414,6 +447,7 @@ mem_cgroup_uncharge_swapcache(struct page *page, swp_entry_t ent, bool swapout)
 
 #else /* CONFIG_SWAP */
 
+#define swap_address_space(entry)              (NULL)
 #define get_nr_swap_pages()                    0L
 #define total_swap_pages                       0L
 #define total_swapcache_pages()                        0UL
index 84662ecc7b51468233175959ddd5c04bd0efac0d..7fac04e7ff6eac91f4d8a37d30486892e1dac141 100644 (file)
@@ -186,6 +186,7 @@ extern struct trace_event_functions exit_syscall_print_funcs;
 #define __SYSCALL_DEFINEx(x, name, ...)                                        \
        asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));      \
        static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));  \
+       asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));      \
        asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))       \
        {                                                               \
                long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));  \
index a386a1cbb6e1c912667ef7433ea608a003832940..b268d3cf7ae3b112f4ccb05dca85075ddd50facc 100644 (file)
@@ -207,6 +207,16 @@ struct thermal_bind_params {
         * See Documentation/thermal/sysfs-api.txt for more information.
         */
        int trip_mask;
+
+       /*
+        * This is an array of cooling state limits. Must have exactly
+        * 2 * thermal_zone.number_of_trip_points. It is an array consisting
+        * of tuples <lower-state upper-state> of state limits. Each trip
+        * will be associated with one state limit tuple when binding.
+        * A NULL pointer means <THERMAL_NO_LIMITS THERMAL_NO_LIMITS>
+        * on all trips.
+        */
+       unsigned long *binding_limits;
        int (*match) (struct thermal_zone_device *tz,
                        struct thermal_cooling_device *cdev);
 };
@@ -214,6 +224,14 @@ struct thermal_bind_params {
 /* Structure to define Thermal Zone parameters */
 struct thermal_zone_params {
        char governor_name[THERMAL_NAME_LENGTH];
+
+       /*
+        * a boolean to indicate if the thermal to hwmon sysfs interface
+        * is required. when no_hwmon == false, a hwmon sysfs interface
+        * will be created. when no_hwmon == true, nothing will be done
+        */
+       bool no_hwmon;
+
        int num_tbps;   /* Number of tbp entries */
        struct thermal_bind_params *tbp;
 };
diff --git a/include/linux/time-armada-370-xp.h b/include/linux/time-armada-370-xp.h
deleted file mode 100644 (file)
index 6fb0856..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Marvell Armada 370/XP SoC timer handling.
- *
- * Copyright (C) 2012 Marvell
- *
- * Lior Amsalem <alior@marvell.com>
- * Gregory CLEMENT <gregory.clement@free-electrons.com>
- * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
- *
- */
-#ifndef __TIME_ARMADA_370_XPPRCMU_H
-#define __TIME_ARMADA_370_XPPRCMU_H
-
-void armada_370_xp_timer_init(void);
-
-#endif
index b3726e61368e5c0e56bc161a41fdfce0200271b1..dd3edd7dfc94dc73de9389e55ed7f35bdcadfcbd 100644 (file)
@@ -141,6 +141,7 @@ extern int do_adjtimex(struct timex *);
 extern void hardpps(const struct timespec *, const struct timespec *);
 
 int read_current_timer(unsigned long *timer_val);
+void ntp_notify_cmos_timer(void);
 
 /* The clock frequency of the i8253/i8254 PIT */
 #define PIT_TICK_RATE 1193182ul
index ac8d488e4372d32e2136a3c673dc0e105d5320b9..24579a0312a0c45dca0216d137721e0381d8c11d 100644 (file)
@@ -90,4 +90,11 @@ extern void vfio_unregister_iommu_driver(
        TYPE tmp;                                               \
        offsetof(TYPE, MEMBER) + sizeof(tmp.MEMBER); })         \
 
+/*
+ * External user API
+ */
+extern struct vfio_group *vfio_group_get_external_user(struct file *filep);
+extern void vfio_group_put_external_user(struct vfio_group *group);
+extern int vfio_external_user_iommu_id(struct vfio_group *group);
+
 #endif /* VFIO_H */
index 2c02f3a8d2ba3f4ba079a51f537be25742b17162..80cf8173a65b1491bd7e1da05978024acd7889b1 100644 (file)
@@ -65,8 +65,15 @@ struct pci_dev;
  *     out of the arbitration process (and can be safe to take
  *     interrupts at any time.
  */
+#if defined(CONFIG_VGA_ARB)
 extern void vga_set_legacy_decoding(struct pci_dev *pdev,
                                    unsigned int decodes);
+#else
+static inline void vga_set_legacy_decoding(struct pci_dev *pdev,
+                                          unsigned int decodes)
+{
+}
+#endif
 
 /**
  *     vga_get         - acquire & locks VGA resources
index bd6cf61142beaf4eae68c8d88e10a51e6119b522..1855f0a22add848202b693a16d103072a8f3487a 100644 (file)
@@ -70,6 +70,12 @@ enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT,
                THP_ZERO_PAGE_ALLOC,
                THP_ZERO_PAGE_ALLOC_FAILED,
 #endif
+#ifdef CONFIG_SMP
+               NR_TLB_REMOTE_FLUSH,    /* cpu tried to flush others' tlbs */
+               NR_TLB_REMOTE_FLUSH_RECEIVED,/* cpu received ipi for flush */
+#endif
+               NR_TLB_LOCAL_FLUSH_ALL,
+               NR_TLB_LOCAL_FLUSH_ONE,
                NR_VM_EVENT_ITEMS
 };
 
index c586679b6fefd4f8f15fe68d123295fc4d7af39f..e4b948080d20e7a537c7a83da17b8b5b7fec0008 100644 (file)
@@ -143,7 +143,6 @@ static inline unsigned long zone_page_state_snapshot(struct zone *zone,
 }
 
 extern unsigned long global_reclaimable_pages(void);
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
 
 #ifdef CONFIG_NUMA
 /*
@@ -198,7 +197,7 @@ extern void __inc_zone_state(struct zone *, enum zone_stat_item);
 extern void dec_zone_state(struct zone *, enum zone_stat_item);
 extern void __dec_zone_state(struct zone *, enum zone_stat_item);
 
-void refresh_cpu_vm_stats(int);
+void cpu_vm_stats_fold(int cpu);
 void refresh_zone_stat_thresholds(void);
 
 void drain_zonestat(struct zone *zone, struct per_cpu_pageset *);
@@ -255,6 +254,7 @@ static inline void __dec_zone_page_state(struct page *page,
 
 static inline void refresh_cpu_vm_stats(int cpu) { }
 static inline void refresh_zone_stat_thresholds(void) { }
+static inline void cpu_vm_stats_fold(int cpu) { }
 
 static inline void drain_zonestat(struct zone *zone,
                        struct per_cpu_pageset *pset) { }
index 4e198ca1f685de549b38ced1644d2b2008d18624..021b8a319b9e2cf7f0f60a5f6fedcfe3367f8016 100644 (file)
@@ -98,8 +98,6 @@ int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason);
 int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr,
                                  enum wb_reason reason);
 void sync_inodes_sb(struct super_block *);
-long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages,
-                               enum wb_reason reason);
 void wakeup_flusher_threads(long nr_pages, enum wb_reason reason);
 void inode_wait_for_writeback(struct inode *inode);
 
index 4c7c01a73911d3a1ee06a6bed39d5fa90e503fa8..c38a005bd0cf9d84a09216cd6f47102e71bb2972 100644 (file)
@@ -26,6 +26,8 @@
 #ifndef NET_9P_CLIENT_H
 #define NET_9P_CLIENT_H
 
+#include <linux/utsname.h>
+
 /* Number of requests per row */
 #define P9_ROW_MAXTAG 255
 
@@ -134,6 +136,7 @@ struct p9_req_t {
  * @tagpool - transaction id accounting for session
  * @reqs - 2D array of requests
  * @max_tag - current maximum tag id allocated
+ * @name - node name used as client id
  *
  * The client structure is used to keep track of various per-client
  * state that has been instantiated.
@@ -164,6 +167,8 @@ struct p9_client {
        struct p9_idpool *tagpool;
        struct p9_req_t *reqs[P9_ROW_MAXTAG];
        int max_tag;
+
+       char name[__NEW_UTS_LEN + 1];
 };
 
 /**
index cb710913d5c8db68e20bd3cca10f72710d1ef1ae..45f6bf5911042885a999292adb4001f0c93da02a 100644 (file)
@@ -436,6 +436,15 @@ bool cfg80211_chandef_usable(struct wiphy *wiphy,
                             const struct cfg80211_chan_def *chandef,
                             u32 prohibited_flags);
 
+/**
+ * cfg80211_chandef_dfs_required - checks if radar detection is required
+ * @wiphy: the wiphy to validate against
+ * @chandef: the channel definition to check
+ * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
+ */
+int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
+                                 const struct cfg80211_chan_def *chandef);
+
 /**
  * ieee80211_chandef_rate_flags - returns rate flags for a channel
  *
index 48f55979d842c3e9d46eedb5c6d893374c0ef499..5e5268807a1ceb521f673ca05ec3233389a97f61 100644 (file)
@@ -264,9 +264,11 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
 
 extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
 
-static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, struct sock *sk)
+static inline void ip_select_ident(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk)
 {
-       if (iph->frag_off & htons(IP_DF)) {
+       struct iphdr *iph = ip_hdr(skb);
+
+       if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) {
                /* This is only to work around buggy Windows95/2000
                 * VJ compression implementations.  If the ID field
                 * does not change, they drop every other packet in
@@ -278,9 +280,11 @@ static inline void ip_select_ident(struct iphdr *iph, struct dst_entry *dst, str
                __ip_select_ident(iph, dst, 0);
 }
 
-static inline void ip_select_ident_more(struct iphdr *iph, struct dst_entry *dst, struct sock *sk, int more)
+static inline void ip_select_ident_more(struct sk_buff *skb, struct dst_entry *dst, struct sock *sk, int more)
 {
-       if (iph->frag_off & htons(IP_DF)) {
+       struct iphdr *iph = ip_hdr(skb);
+
+       if ((iph->frag_off & htons(IP_DF)) && !skb->local_df) {
                if (sk && inet_sk(sk)->inet_daddr) {
                        iph->id = htons(inet_sk(sk)->inet_id);
                        inet_sk(sk)->inet_id += 1 + more;
index cc6035f1a2f11c1b68f5a82235d4698441e8cddd..f386c480e1341dd70308d02300dc26f60af275f0 100644 (file)
@@ -829,6 +829,15 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  * @RX_FLAG_STBC_MASK: STBC 2 bit bitmask. 1 - Nss=1, 2 - Nss=2, 3 - Nss=3
  * @RX_FLAG_10MHZ: 10 MHz (half channel) was used
  * @RX_FLAG_5MHZ: 5 MHz (quarter channel) was used
+ * @RX_FLAG_AMSDU_MORE: Some drivers may prefer to report separate A-MSDU
+ *     subframes instead of a one huge frame for performance reasons.
+ *     All, but the last MSDU from an A-MSDU should have this flag set. E.g.
+ *     if an A-MSDU has 3 frames, the first 2 must have the flag set, while
+ *     the 3rd (last) one must not have this flag set. The flag is used to
+ *     deal with retransmission/duplication recovery properly since A-MSDU
+ *     subframes share the same sequence number. Reported subframes can be
+ *     either regular MSDU or singly A-MSDUs. Subframes must not be
+ *     interleaved with other frames.
  */
 enum mac80211_rx_flags {
        RX_FLAG_MMIC_ERROR              = BIT(0),
@@ -859,6 +868,7 @@ enum mac80211_rx_flags {
        RX_FLAG_STBC_MASK               = BIT(26) | BIT(27),
        RX_FLAG_10MHZ                   = BIT(28),
        RX_FLAG_5MHZ                    = BIT(29),
+       RX_FLAG_AMSDU_MORE              = BIT(30),
 };
 
 #define RX_FLAG_STBC_SHIFT             26
@@ -1492,6 +1502,11 @@ struct ieee80211_tx_control {
  *
  * @IEEE80211_HW_TIMING_BEACON_ONLY: Use sync timing from beacon frames
  *     only, to allow getting TBTT of a DTIM beacon.
+ *
+ * @IEEE80211_HW_CHANCTX_STA_CSA: Support 802.11h based channel-switch (CSA)
+ *     for a single active channel while using channel contexts. When support
+ *     is not enabled the default action is to disconnect when getting the
+ *     CSA frame.
  */
 enum ieee80211_hw_flags {
        IEEE80211_HW_HAS_RATE_CONTROL                   = 1<<0,
@@ -1522,6 +1537,7 @@ enum ieee80211_hw_flags {
        IEEE80211_HW_P2P_DEV_ADDR_FOR_INTF              = 1<<25,
        IEEE80211_HW_TIMING_BEACON_ONLY                 = 1<<26,
        IEEE80211_HW_SUPPORTS_HT_CCK_RATES              = 1<<27,
+       IEEE80211_HW_CHANCTX_STA_CSA                    = 1<<28,
 };
 
 /**
@@ -2666,6 +2682,10 @@ enum ieee80211_roc_type {
  *     zero using ieee80211_csa_is_complete() after the beacon has been
  *     transmitted and then call ieee80211_csa_finish().
  *
+ * @join_ibss: Join an IBSS (on an IBSS interface); this is called after all
+ *     information in bss_conf is set up and the beacon can be retrieved. A
+ *     channel context is bound before this is called.
+ * @leave_ibss: Leave the IBSS again.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -2857,6 +2877,9 @@ struct ieee80211_ops {
        void (*channel_switch_beacon)(struct ieee80211_hw *hw,
                                      struct ieee80211_vif *vif,
                                      struct cfg80211_chan_def *chandef);
+
+       int (*join_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+       void (*leave_ibss)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 };
 
 /**
@@ -3919,6 +3942,25 @@ void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
                                                    struct ieee80211_vif *vif),
                                                void *data);
 
+/**
+ * ieee80211_iterate_active_interfaces_rtnl - iterate active interfaces
+ *
+ * This function iterates over the interfaces associated with a given
+ * hardware that are currently active and calls the callback for them.
+ * This version can only be used while holding the RTNL.
+ *
+ * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
+ * @iterator: the iterator function to call, cannot sleep
+ * @data: first argument of the iterator function
+ */
+void ieee80211_iterate_active_interfaces_rtnl(struct ieee80211_hw *hw,
+                                             u32 iter_flags,
+                                             void (*iterator)(void *data,
+                                               u8 *mac,
+                                               struct ieee80211_vif *vif),
+                                             void *data);
+
 /**
  * ieee80211_queue_work - add work onto the mac80211 workqueue
  *
index 3c4211f0bed60fe9035c3fc12c7190c6c564918c..ea0cc26ab70e1b447a0e834992c746a9f33c9938 100644 (file)
@@ -190,7 +190,9 @@ static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, cons
 }
 
 extern int                     ndisc_init(void);
+extern int                     ndisc_late_init(void);
 
+extern void                    ndisc_late_cleanup(void);
 extern void                    ndisc_cleanup(void);
 
 extern int                     ndisc_rcv(struct sk_buff *skb);
index ff95434e50ca4273e7e795e55f37134457cca69f..88a1d4060d5260f7ac51e7b2d74f87ab409cd4de 100644 (file)
@@ -86,7 +86,7 @@ static inline void nf_ct_ext_destroy(struct nf_conn *ct)
 static inline void nf_ct_ext_free(struct nf_conn *ct)
 {
        if (ct->ext)
-               kfree(ct->ext);
+               kfree_rcu(ct->ext, rcu);
 }
 
 /* Add this type, returns pointer to data or NULL. */
index d477bfb73fb9261399d750f286ae92c8af8b27ef..66d42edfb3fc341d8a33a0a0f9e9666b53111ec3 100644 (file)
@@ -144,6 +144,7 @@ enum scsi_timeouts {
 #define ACCESS_CONTROL_IN     0x86
 #define ACCESS_CONTROL_OUT    0x87
 #define READ_16               0x88
+#define COMPARE_AND_WRITE     0x89
 #define WRITE_16              0x8a
 #define READ_ATTRIBUTE        0x8c
 #define WRITE_ATTRIBUTE              0x8d
index d35412ae03b3805294a11fbd86170005a31111d0..fe66533e9b7a51ef143acd33ff398bee47f71398 100644 (file)
@@ -55,7 +55,7 @@ struct rsnd_ssi_platform_info {
 /*
  * flags
  */
-#define RSND_SCU_USB_HPBIF             (1 << 31) /* it needs RSND_SSI_DEPENDENT */
+#define RSND_SCU_USE_HPBIF             (1 << 31) /* it needs RSND_SSI_DEPENDENT */
 
 struct rsnd_scu_platform_info {
        u32 flags;
index e5d09d242ba3be8e89df14b9e0611dda759c49be..a12589c4ee92b9a044b9fbc3df927164c5e1f813 100644 (file)
@@ -6,13 +6,13 @@ struct iscsit_transport {
 #define ISCSIT_TRANSPORT_NAME  16
        char name[ISCSIT_TRANSPORT_NAME];
        int transport_type;
+       int priv_size;
        struct module *owner;
        struct list_head t_node;
        int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *);
        int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *);
        void (*iscsit_free_np)(struct iscsi_np *);
        void (*iscsit_free_conn)(struct iscsi_conn *);
-       struct iscsi_cmd *(*iscsit_alloc_cmd)(struct iscsi_conn *, gfp_t);
        int (*iscsit_get_login_rx)(struct iscsi_conn *, struct iscsi_login *);
        int (*iscsit_put_login_tx)(struct iscsi_conn *, struct iscsi_login *, u32);
        int (*iscsit_immediate_queue)(struct iscsi_conn *, struct iscsi_cmd *, int);
@@ -22,6 +22,11 @@ struct iscsit_transport {
        int (*iscsit_queue_status)(struct iscsi_conn *, struct iscsi_cmd *);
 };
 
+static inline void *iscsit_priv_cmd(struct iscsi_cmd *cmd)
+{
+       return (void *)(cmd + 1);
+}
+
 /*
  * From iscsi_target_transport.c
  */
@@ -92,3 +97,4 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
 extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
 extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
                               unsigned char *, __be32);
+extern void iscsit_release_cmd(struct iscsi_cmd *);
index ffa2696d64dcfe9794ec87a83be887b0e2aab453..5ebe21cd5d1cda075c484f13fd818e289ff0932c 100644 (file)
@@ -39,7 +39,8 @@ struct se_subsystem_api {
 };
 
 struct sbc_ops {
-       sense_reason_t (*execute_rw)(struct se_cmd *cmd);
+       sense_reason_t (*execute_rw)(struct se_cmd *cmd, struct scatterlist *,
+                                    u32, enum dma_data_direction);
        sense_reason_t (*execute_sync_cache)(struct se_cmd *cmd);
        sense_reason_t (*execute_write_same)(struct se_cmd *cmd);
        sense_reason_t (*execute_write_same_unmap)(struct se_cmd *cmd);
@@ -73,6 +74,10 @@ int  transport_set_vpd_ident(struct t10_vpd *, unsigned char *);
 /* core helpers also used by command snooping in pscsi */
 void   *transport_kmap_data_sg(struct se_cmd *);
 void   transport_kunmap_data_sg(struct se_cmd *);
+/* core helpers also used by xcopy during internal command setup */
+int    target_alloc_sgl(struct scatterlist **, unsigned int *, u32, bool);
+sense_reason_t transport_generic_map_mem_to_cmd(struct se_cmd *,
+               struct scatterlist *, u32, struct scatterlist *, u32);
 
 void   array_free(void *array, int n);
 
index e34fc904f2e153f8bd6e1c3162fa914ca0bfb189..5bdb8b7d2a69e52b56a6fe98dcd8aeb632cbc018 100644 (file)
@@ -5,11 +5,12 @@
 #include <linux/configfs.h>
 #include <linux/dma-mapping.h>
 #include <linux/blkdev.h>
+#include <linux/percpu_ida.h>
 #include <scsi/scsi_cmnd.h>
 #include <net/sock.h>
 #include <net/tcp.h>
 
-#define TARGET_CORE_MOD_VERSION                "v4.1.0-rc2-ml"
+#define TARGET_CORE_MOD_VERSION                "v4.1.0"
 #define TARGET_CORE_VERSION            TARGET_CORE_MOD_VERSION
 
 /* Maximum Number of LUNs per Target Portal Group */
  * block/blk-lib.c:blkdev_issue_discard()
  */
 #define DA_EMULATE_TPWS                                0
+/* Emulation for CompareAndWrite (AtomicTestandSet) by default */
+#define DA_EMULATE_CAW                         1
+/* Emulation for 3rd Party Copy (ExtendedCopy) by default */
+#define DA_EMULATE_3PC                         1
 /* No Emulation for PSCSI by default */
 #define DA_EMULATE_ALUA                                0
 /* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */
@@ -158,6 +163,9 @@ enum se_cmd_flags_table {
        SCF_ALUA_NON_OPTIMIZED          = 0x00008000,
        SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00020000,
        SCF_ACK_KREF                    = 0x00040000,
+       SCF_COMPARE_AND_WRITE           = 0x00080000,
+       SCF_COMPARE_AND_WRITE_POST      = 0x00100000,
+       SCF_CMD_XCOPY_PASSTHROUGH       = 0x00200000,
 };
 
 /* struct se_dev_entry->lun_flags and struct se_lun->lun_access */
@@ -196,6 +204,7 @@ enum tcm_sense_reason_table {
        TCM_ADDRESS_OUT_OF_RANGE                = R(0x11),
        TCM_OUT_OF_RESOURCES                    = R(0x12),
        TCM_PARAMETER_LIST_LENGTH_ERROR         = R(0x13),
+       TCM_MISCOMPARE_VERIFY                   = R(0x14),
 #undef R
 };
 
@@ -415,6 +424,8 @@ struct se_cmd {
        enum dma_data_direction data_direction;
        /* For SAM Task Attribute */
        int                     sam_task_attr;
+       /* Used for se_sess->sess_tag_pool */
+       unsigned int            map_tag;
        /* Transport protocol dependent state, see transport_state_table */
        enum transport_state_table t_state;
        unsigned                cmd_wait_set:1;
@@ -444,11 +455,14 @@ struct se_cmd {
        struct kref             cmd_kref;
        struct target_core_fabric_ops *se_tfo;
        sense_reason_t          (*execute_cmd)(struct se_cmd *);
-       void (*transport_complete_callback)(struct se_cmd *);
+       sense_reason_t          (*execute_rw)(struct se_cmd *, struct scatterlist *,
+                                             u32, enum dma_data_direction);
+       sense_reason_t (*transport_complete_callback)(struct se_cmd *);
 
        unsigned char           *t_task_cdb;
        unsigned char           __t_task_cdb[TCM_MAX_COMMAND_SIZE];
        unsigned long long      t_task_lba;
+       unsigned int            t_task_nolb;
        unsigned int            transport_state;
 #define CMD_T_ABORTED          (1 << 0)
 #define CMD_T_ACTIVE           (1 << 1)
@@ -469,7 +483,9 @@ struct se_cmd {
        struct work_struct      work;
 
        struct scatterlist      *t_data_sg;
+       struct scatterlist      *t_data_sg_orig;
        unsigned int            t_data_nents;
+       unsigned int            t_data_nents_orig;
        void                    *t_data_vmap;
        struct scatterlist      *t_bidi_data_sg;
        unsigned int            t_bidi_data_nents;
@@ -536,6 +552,8 @@ struct se_session {
        struct list_head        sess_wait_list;
        spinlock_t              sess_cmd_lock;
        struct kref             sess_kref;
+       void                    *sess_cmd_map;
+       struct percpu_ida       sess_tag_pool;
 };
 
 struct se_device;
@@ -589,6 +607,8 @@ struct se_dev_attrib {
        int             emulate_tas;
        int             emulate_tpu;
        int             emulate_tpws;
+       int             emulate_caw;
+       int             emulate_3pc;
        int             enforce_pr_isids;
        int             is_nonrot;
        int             emulate_rest_reord;
@@ -656,6 +676,7 @@ struct se_device {
        spinlock_t              se_port_lock;
        spinlock_t              se_tmr_lock;
        spinlock_t              qf_cmd_lock;
+       struct semaphore        caw_sem;
        /* Used for legacy SPC-2 reservationsa */
        struct se_node_acl      *dev_reserved_node_acl;
        /* Used for ALUA Logical Unit Group membership */
@@ -669,6 +690,7 @@ struct se_device {
        struct list_head        delayed_cmd_list;
        struct list_head        state_list;
        struct list_head        qf_cmd_list;
+       struct list_head        g_dev_node;
        /* Pointer to associated SE HBA */
        struct se_hba           *se_hba;
        /* T10 Inquiry and VPD WWN Information */
index 7a16178424f9af3e9ac57eceb1629eda100fb0b9..882b650e32be1d51b9945f4c475e5adcc79b523a 100644 (file)
@@ -84,6 +84,9 @@ struct target_core_fabric_ops {
 };
 
 struct se_session *transport_init_session(void);
+int transport_alloc_session_tags(struct se_session *, unsigned int,
+               unsigned int);
+struct se_session *transport_init_session_tags(unsigned int, unsigned int);
 void   __transport_register_session(struct se_portal_group *,
                struct se_node_acl *, struct se_session *, void *);
 void   transport_register_session(struct se_portal_group *,
@@ -131,6 +134,7 @@ int core_tmr_alloc_req(struct se_cmd *, void *, u8, gfp_t);
 void   core_tmr_release_req(struct se_tmr_req *);
 int    transport_generic_handle_tmr(struct se_cmd *);
 void   transport_generic_request_failure(struct se_cmd *, sense_reason_t);
+void   __target_execute_cmd(struct se_cmd *);
 int    transport_lookup_tmr_lun(struct se_cmd *, u32);
 
 struct se_node_acl *core_tpg_check_initiator_node_acl(struct se_portal_group *,
@@ -175,4 +179,30 @@ u32        iscsi_get_pr_transport_id_len(struct se_portal_group *, struct se_node_acl *
 char   *iscsi_parse_pr_out_transport_id(struct se_portal_group *, const char *,
                u32 *, char **);
 
+/*
+ * The LIO target core uses DMA_TO_DEVICE to mean that data is going
+ * to the target (eg handling a WRITE) and DMA_FROM_DEVICE to mean
+ * that data is coming from the target (eg handling a READ).  However,
+ * this is just the opposite of what we have to tell the DMA mapping
+ * layer -- eg when handling a READ, the HBA will have to DMA the data
+ * out of memory so it can send it to the initiator, which means we
+ * need to use DMA_TO_DEVICE when we map the data.
+ */
+static inline enum dma_data_direction
+target_reverse_dma_direction(struct se_cmd *se_cmd)
+{
+       if (se_cmd->se_cmd_flags & SCF_BIDI)
+               return DMA_BIDIRECTIONAL;
+
+       switch (se_cmd->data_direction) {
+       case DMA_TO_DEVICE:
+               return DMA_FROM_DEVICE;
+       case DMA_FROM_DEVICE:
+               return DMA_TO_DEVICE;
+       case DMA_NONE:
+       default:
+               return DMA_NONE;
+       }
+}
+
 #endif /* TARGET_CORE_FABRICH */
index 2902657ba766bb7dc1a9949b1f0436816615484a..45702c3c3837f316709438a462d4a6517e0ba168 100644 (file)
@@ -439,7 +439,7 @@ TRACE_EVENT(btrfs_sync_fs,
                { BTRFS_UPDATE_DELAYED_HEAD, "UPDATE_DELAYED_HEAD" })
                        
 
-TRACE_EVENT(btrfs_delayed_tree_ref,
+DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref,
 
        TP_PROTO(struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_tree_ref *full_ref,
@@ -481,7 +481,25 @@ TRACE_EVENT(btrfs_delayed_tree_ref,
                  (unsigned long long)__entry->seq)
 );
 
-TRACE_EVENT(btrfs_delayed_data_ref,
+DEFINE_EVENT(btrfs_delayed_tree_ref,  add_delayed_tree_ref,
+
+       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+                struct btrfs_delayed_tree_ref *full_ref,
+                int action),
+
+       TP_ARGS(ref, full_ref, action)
+);
+
+DEFINE_EVENT(btrfs_delayed_tree_ref,  run_delayed_tree_ref,
+
+       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+                struct btrfs_delayed_tree_ref *full_ref,
+                int action),
+
+       TP_ARGS(ref, full_ref, action)
+);
+
+DECLARE_EVENT_CLASS(btrfs_delayed_data_ref,
 
        TP_PROTO(struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_data_ref *full_ref,
@@ -527,7 +545,25 @@ TRACE_EVENT(btrfs_delayed_data_ref,
                  (unsigned long long)__entry->seq)
 );
 
-TRACE_EVENT(btrfs_delayed_ref_head,
+DEFINE_EVENT(btrfs_delayed_data_ref,  add_delayed_data_ref,
+
+       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+                struct btrfs_delayed_data_ref *full_ref,
+                int action),
+
+       TP_ARGS(ref, full_ref, action)
+);
+
+DEFINE_EVENT(btrfs_delayed_data_ref,  run_delayed_data_ref,
+
+       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+                struct btrfs_delayed_data_ref *full_ref,
+                int action),
+
+       TP_ARGS(ref, full_ref, action)
+);
+
+DECLARE_EVENT_CLASS(btrfs_delayed_ref_head,
 
        TP_PROTO(struct btrfs_delayed_ref_node *ref,
                 struct btrfs_delayed_ref_head *head_ref,
@@ -556,6 +592,24 @@ TRACE_EVENT(btrfs_delayed_ref_head,
                  __entry->is_data)
 );
 
+DEFINE_EVENT(btrfs_delayed_ref_head,  add_delayed_ref_head,
+
+       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+                struct btrfs_delayed_ref_head *head_ref,
+                int action),
+
+       TP_ARGS(ref, head_ref, action)
+);
+
+DEFINE_EVENT(btrfs_delayed_ref_head,  run_delayed_ref_head,
+
+       TP_PROTO(struct btrfs_delayed_ref_node *ref,
+                struct btrfs_delayed_ref_head *head_ref,
+                int action),
+
+       TP_ARGS(ref, head_ref, action)
+);
+
 #define show_chunk_type(type)                                  \
        __print_flags(type, "|",                                \
                { BTRFS_BLOCK_GROUP_DATA,       "DATA"  },      \
index 6bc943ecb84135034ee968772726efb8383cb1c8..d0c613476620fa9da3f60220557dee19eb725c86 100644 (file)
@@ -268,11 +268,13 @@ TRACE_EVENT(mm_page_alloc_extfrag,
 
        TP_PROTO(struct page *page,
                        int alloc_order, int fallback_order,
-                       int alloc_migratetype, int fallback_migratetype),
+                       int alloc_migratetype, int fallback_migratetype,
+                       int change_ownership),
 
        TP_ARGS(page,
                alloc_order, fallback_order,
-               alloc_migratetype, fallback_migratetype),
+               alloc_migratetype, fallback_migratetype,
+               change_ownership),
 
        TP_STRUCT__entry(
                __field(        struct page *,  page                    )
@@ -280,6 +282,7 @@ TRACE_EVENT(mm_page_alloc_extfrag,
                __field(        int,            fallback_order          )
                __field(        int,            alloc_migratetype       )
                __field(        int,            fallback_migratetype    )
+               __field(        int,            change_ownership        )
        ),
 
        TP_fast_assign(
@@ -288,6 +291,7 @@ TRACE_EVENT(mm_page_alloc_extfrag,
                __entry->fallback_order         = fallback_order;
                __entry->alloc_migratetype      = alloc_migratetype;
                __entry->fallback_migratetype   = fallback_migratetype;
+               __entry->change_ownership       = change_ownership;
        ),
 
        TP_printk("page=%p pfn=%lu alloc_order=%d fallback_order=%d pageblock_order=%d alloc_migratetype=%d fallback_migratetype=%d fragmenting=%d change_ownership=%d",
@@ -299,7 +303,7 @@ TRACE_EVENT(mm_page_alloc_extfrag,
                __entry->alloc_migratetype,
                __entry->fallback_migratetype,
                __entry->fallback_order < pageblock_order,
-               __entry->alloc_migratetype == __entry->fallback_migratetype)
+               __entry->change_ownership)
 );
 
 #endif /* _TRACE_KMEM_H */
index 43be87d5dd58c4395e40bd19f476c145c4c088c2..d51d16c7afd86d64b02092f0a8e4969b4ab5eaa2 100644 (file)
@@ -6,6 +6,8 @@
 
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/clnt.h>
+#include <net/tcp_states.h>
+#include <linux/net.h>
 #include <linux/tracepoint.h>
 
 DECLARE_EVENT_CLASS(rpc_task_status,
@@ -15,18 +17,20 @@ DECLARE_EVENT_CLASS(rpc_task_status,
        TP_ARGS(task),
 
        TP_STRUCT__entry(
-               __field(const struct rpc_task *, task)
-               __field(const struct rpc_clnt *, clnt)
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
                __field(int, status)
        ),
 
        TP_fast_assign(
-               __entry->task = task;
-               __entry->clnt = task->tk_client;
+               __entry->task_id = task->tk_pid;
+               __entry->client_id = task->tk_client->cl_clid;
                __entry->status = task->tk_status;
        ),
 
-       TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
+       TP_printk("task:%u@%u, status %d",
+               __entry->task_id, __entry->client_id,
+               __entry->status)
 );
 
 DEFINE_EVENT(rpc_task_status, rpc_call_status,
@@ -47,18 +51,20 @@ TRACE_EVENT(rpc_connect_status,
        TP_ARGS(task, status),
 
        TP_STRUCT__entry(
-               __field(const struct rpc_task *, task)
-               __field(const struct rpc_clnt *, clnt)
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
                __field(int, status)
        ),
 
        TP_fast_assign(
-               __entry->task = task;
-               __entry->clnt = task->tk_client;
+               __entry->task_id = task->tk_pid;
+               __entry->client_id = task->tk_client->cl_clid;
                __entry->status = status;
        ),
 
-       TP_printk("task:%p@%p, status %d",__entry->task, __entry->clnt, __entry->status)
+       TP_printk("task:%u@%u, status %d",
+               __entry->task_id, __entry->client_id,
+               __entry->status)
 );
 
 DECLARE_EVENT_CLASS(rpc_task_running,
@@ -68,8 +74,8 @@ DECLARE_EVENT_CLASS(rpc_task_running,
        TP_ARGS(clnt, task, action),
 
        TP_STRUCT__entry(
-               __field(const struct rpc_clnt *, clnt)
-               __field(const struct rpc_task *, task)
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
                __field(const void *, action)
                __field(unsigned long, runstate)
                __field(int, status)
@@ -77,17 +83,16 @@ DECLARE_EVENT_CLASS(rpc_task_running,
                ),
 
        TP_fast_assign(
-               __entry->clnt = clnt;
-               __entry->task = task;
+               __entry->client_id = clnt->cl_clid;
+               __entry->task_id = task->tk_pid;
                __entry->action = action;
                __entry->runstate = task->tk_runstate;
                __entry->status = task->tk_status;
                __entry->flags = task->tk_flags;
                ),
 
-       TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d action=%pf",
-               __entry->task,
-               __entry->clnt,
+       TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d action=%pf",
+               __entry->task_id, __entry->client_id,
                __entry->flags,
                __entry->runstate,
                __entry->status,
@@ -126,8 +131,8 @@ DECLARE_EVENT_CLASS(rpc_task_queued,
        TP_ARGS(clnt, task, q),
 
        TP_STRUCT__entry(
-               __field(const struct rpc_clnt *, clnt)
-               __field(const struct rpc_task *, task)
+               __field(unsigned int, task_id)
+               __field(unsigned int, client_id)
                __field(unsigned long, timeout)
                __field(unsigned long, runstate)
                __field(int, status)
@@ -136,8 +141,8 @@ DECLARE_EVENT_CLASS(rpc_task_queued,
                ),
 
        TP_fast_assign(
-               __entry->clnt = clnt;
-               __entry->task = task;
+               __entry->client_id = clnt->cl_clid;
+               __entry->task_id = task->tk_pid;
                __entry->timeout = task->tk_timeout;
                __entry->runstate = task->tk_runstate;
                __entry->status = task->tk_status;
@@ -145,9 +150,8 @@ DECLARE_EVENT_CLASS(rpc_task_queued,
                __assign_str(q_name, rpc_qname(q));
                ),
 
-       TP_printk("task:%p@%p flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s",
-               __entry->task,
-               __entry->clnt,
+       TP_printk("task:%u@%u flags=%4.4x state=%4.4lx status=%d timeout=%lu queue=%s",
+               __entry->task_id, __entry->client_id,
                __entry->flags,
                __entry->runstate,
                __entry->status,
@@ -172,6 +176,135 @@ DEFINE_EVENT(rpc_task_queued, rpc_task_wakeup,
 
 );
 
+#define rpc_show_socket_state(state) \
+       __print_symbolic(state, \
+               { SS_FREE, "FREE" }, \
+               { SS_UNCONNECTED, "UNCONNECTED" }, \
+               { SS_CONNECTING, "CONNECTING," }, \
+               { SS_CONNECTED, "CONNECTED," }, \
+               { SS_DISCONNECTING, "DISCONNECTING" })
+
+#define rpc_show_sock_state(state) \
+       __print_symbolic(state, \
+               { TCP_ESTABLISHED, "ESTABLISHED" }, \
+               { TCP_SYN_SENT, "SYN_SENT" }, \
+               { TCP_SYN_RECV, "SYN_RECV" }, \
+               { TCP_FIN_WAIT1, "FIN_WAIT1" }, \
+               { TCP_FIN_WAIT2, "FIN_WAIT2" }, \
+               { TCP_TIME_WAIT, "TIME_WAIT" }, \
+               { TCP_CLOSE, "CLOSE" }, \
+               { TCP_CLOSE_WAIT, "CLOSE_WAIT" }, \
+               { TCP_LAST_ACK, "LAST_ACK" }, \
+               { TCP_LISTEN, "LISTEN" }, \
+               { TCP_CLOSING, "CLOSING" })
+
+DECLARE_EVENT_CLASS(xs_socket_event,
+
+               TP_PROTO(
+                       struct rpc_xprt *xprt,
+                       struct socket *socket
+               ),
+
+               TP_ARGS(xprt, socket),
+
+               TP_STRUCT__entry(
+                       __field(unsigned int, socket_state)
+                       __field(unsigned int, sock_state)
+                       __field(unsigned long long, ino)
+                       __string(dstaddr,
+                               xprt->address_strings[RPC_DISPLAY_ADDR])
+                       __string(dstport,
+                               xprt->address_strings[RPC_DISPLAY_PORT])
+               ),
+
+               TP_fast_assign(
+                       struct inode *inode = SOCK_INODE(socket);
+                       __entry->socket_state = socket->state;
+                       __entry->sock_state = socket->sk->sk_state;
+                       __entry->ino = (unsigned long long)inode->i_ino;
+                       __assign_str(dstaddr,
+                               xprt->address_strings[RPC_DISPLAY_ADDR]);
+                       __assign_str(dstport,
+                               xprt->address_strings[RPC_DISPLAY_PORT]);
+               ),
+
+               TP_printk(
+                       "socket:[%llu] dstaddr=%s/%s "
+                       "state=%u (%s) sk_state=%u (%s)",
+                       __entry->ino, __get_str(dstaddr), __get_str(dstport),
+                       __entry->socket_state,
+                       rpc_show_socket_state(__entry->socket_state),
+                       __entry->sock_state,
+                       rpc_show_sock_state(__entry->sock_state)
+               )
+);
+#define DEFINE_RPC_SOCKET_EVENT(name) \
+       DEFINE_EVENT(xs_socket_event, name, \
+                       TP_PROTO( \
+                               struct rpc_xprt *xprt, \
+                               struct socket *socket \
+                       ), \
+                       TP_ARGS(xprt, socket))
+
+DECLARE_EVENT_CLASS(xs_socket_event_done,
+
+               TP_PROTO(
+                       struct rpc_xprt *xprt,
+                       struct socket *socket,
+                       int error
+               ),
+
+               TP_ARGS(xprt, socket, error),
+
+               TP_STRUCT__entry(
+                       __field(int, error)
+                       __field(unsigned int, socket_state)
+                       __field(unsigned int, sock_state)
+                       __field(unsigned long long, ino)
+                       __string(dstaddr,
+                               xprt->address_strings[RPC_DISPLAY_ADDR])
+                       __string(dstport,
+                               xprt->address_strings[RPC_DISPLAY_PORT])
+               ),
+
+               TP_fast_assign(
+                       struct inode *inode = SOCK_INODE(socket);
+                       __entry->socket_state = socket->state;
+                       __entry->sock_state = socket->sk->sk_state;
+                       __entry->ino = (unsigned long long)inode->i_ino;
+                       __entry->error = error;
+                       __assign_str(dstaddr,
+                               xprt->address_strings[RPC_DISPLAY_ADDR]);
+                       __assign_str(dstport,
+                               xprt->address_strings[RPC_DISPLAY_PORT]);
+               ),
+
+               TP_printk(
+                       "error=%d socket:[%llu] dstaddr=%s/%s "
+                       "state=%u (%s) sk_state=%u (%s)",
+                       __entry->error,
+                       __entry->ino, __get_str(dstaddr), __get_str(dstport),
+                       __entry->socket_state,
+                       rpc_show_socket_state(__entry->socket_state),
+                       __entry->sock_state,
+                       rpc_show_sock_state(__entry->sock_state)
+               )
+);
+#define DEFINE_RPC_SOCKET_EVENT_DONE(name) \
+       DEFINE_EVENT(xs_socket_event_done, name, \
+                       TP_PROTO( \
+                               struct rpc_xprt *xprt, \
+                               struct socket *socket, \
+                               int error \
+                       ), \
+                       TP_ARGS(xprt, socket, error))
+
+DEFINE_RPC_SOCKET_EVENT(rpc_socket_state_change);
+DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_connect);
+DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_reset_connection);
+DEFINE_RPC_SOCKET_EVENT(rpc_socket_close);
+DEFINE_RPC_SOCKET_EVENT(rpc_socket_shutdown);
+
 #endif /* _TRACE_SUNRPC_H */
 
 #include <trace/define_trace.h>
index 63cfcccaebb3a79eea8d6be86f477ae26d3173f0..132a985aba8befe56323b41213d193f572b3b32c 100644 (file)
@@ -202,7 +202,7 @@ TRACE_EVENT(mm_shrink_slab_start,
 
        TP_fast_assign(
                __entry->shr = shr;
-               __entry->shrink = shr->shrink;
+               __entry->shrink = shr->scan_objects;
                __entry->nr_objects_to_shrink = nr_objects_to_shrink;
                __entry->gfp_flags = sc->gfp_mask;
                __entry->pgs_scanned = pgs_scanned;
@@ -241,7 +241,7 @@ TRACE_EVENT(mm_shrink_slab_end,
 
        TP_fast_assign(
                __entry->shr = shr;
-               __entry->shrink = shr->shrink;
+               __entry->shrink = shr->scan_objects;
                __entry->unused_scan = unused_scan_cnt;
                __entry->new_scan = new_scan_cnt;
                __entry->retval = shrinker_retval;
index e7c94eeb9475e4a9e9667704ce54b31b8dada428..115add2515aaad2bc5caebd1bf330060fee75ebc 100644 (file)
@@ -284,6 +284,7 @@ header-y += nfs_mount.h
 header-y += nfsacl.h
 header-y += nl80211.h
 header-y += nubus.h
+header-y += nvme.h
 header-y += nvram.h
 header-y += omap3isp.h
 header-y += omapfb.h
index 05aed70627e24392d87cb4bc350e16bf32ceca44..45e618921c612385c0c1b97f78fe0e19bac86056 100644 (file)
@@ -305,6 +305,31 @@ struct btrfs_ioctl_clone_range_args {
 #define BTRFS_DEFRAG_RANGE_COMPRESS 1
 #define BTRFS_DEFRAG_RANGE_START_IO 2
 
+#define BTRFS_SAME_DATA_DIFFERS        1
+/* For extent-same ioctl */
+struct btrfs_ioctl_same_extent_info {
+       __s64 fd;               /* in - destination file */
+       __u64 logical_offset;   /* in - start of extent in destination */
+       __u64 bytes_deduped;    /* out - total # of bytes we were able
+                                * to dedupe from this file */
+       /* status of this dedupe operation:
+        * 0 if dedup succeeds
+        * < 0 for error
+        * == BTRFS_SAME_DATA_DIFFERS if data differs
+        */
+       __s32 status;           /* out - see above description */
+       __u32 reserved;
+};
+
+struct btrfs_ioctl_same_args {
+       __u64 logical_offset;   /* in - start of extent in source */
+       __u64 length;           /* in - length of extent */
+       __u16 dest_count;       /* in - total elements in info array */
+       __u16 reserved1;
+       __u32 reserved2;
+       struct btrfs_ioctl_same_extent_info info[0];
+};
+
 struct btrfs_ioctl_space_info {
        __u64 flags;
        __u64 total_bytes;
@@ -524,7 +549,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
                                   struct btrfs_ioctl_search_args)
 #define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
                                   struct btrfs_ioctl_ino_lookup_args)
-#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
+#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64)
 #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
                                    struct btrfs_ioctl_space_args)
 #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
@@ -579,4 +604,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
                                      struct btrfs_ioctl_get_dev_stats)
 #define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \
                                    struct btrfs_ioctl_dev_replace_args)
+#define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \
+                                        struct btrfs_ioctl_same_args)
+
 #endif /* _UAPI_LINUX_BTRFS_H */
diff --git a/include/uapi/linux/cifs/cifs_mount.h b/include/uapi/linux/cifs/cifs_mount.h
new file mode 100644 (file)
index 0000000..d7e4c6c
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *   include/uapi/linux/cifs/cifs_mount.h
+ *
+ *   Author(s): Scott Lovenberg (scott.lovenberg@gmail.com)
+ *
+ *   This library is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU Lesser General Public License as published
+ *   by the Free Software Foundation; either version 2.1 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This library is distributed in 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 Lesser General Public License for more details.
+ */
+#ifndef _CIFS_MOUNT_H
+#define _CIFS_MOUNT_H
+
+/* Max string lengths for cifs mounting options. */
+#define CIFS_MAX_DOMAINNAME_LEN 256 /* max fully qualified domain name */
+#define CIFS_MAX_USERNAME_LEN   256 /* reasonable max for current servers */
+#define CIFS_MAX_PASSWORD_LEN   512 /* Windows max seems to be 256 wide chars */
+#define CIFS_MAX_SHARE_LEN      256 /* reasonable max share name length */
+#define CIFS_NI_MAXHOST        1024 /* max host name length (256 * 4 bytes) */
+
+
+#endif /* _CIFS_MOUNT_H */
index afd0cbd52edb62b501bbbe4225338af6b9dc95f0..f1e12bd40b3b42bc5f1ccc4695e6622a9522862e 100644 (file)
@@ -267,9 +267,9 @@ enum {
 #define DM_DEV_SET_GEOMETRY    _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
 
 #define DM_VERSION_MAJOR       4
-#define DM_VERSION_MINOR       25
+#define DM_VERSION_MINOR       26
 #define DM_VERSION_PATCHLEVEL  0
-#define DM_VERSION_EXTRA       "-ioctl (2013-06-26)"
+#define DM_VERSION_EXTRA       "-ioctl (2013-08-15)"
 
 /* Status bits */
 #define DM_READONLY_FLAG       (1 << 0) /* In/Out */
index 86552807aed949529fc34a3007658ede564f4e52..dcd75cc261962f65c909a6efa0defe3f1dcdc281 100644 (file)
@@ -38,6 +38,7 @@
 #define Q_XGETQSTAT    XQM_CMD(5)      /* get quota subsystem status */
 #define Q_XQUOTARM     XQM_CMD(6)      /* free disk space used by dquots */
 #define Q_XQUOTASYNC   XQM_CMD(7)      /* delalloc flush, updates dquots */
+#define Q_XGETQSTATV   XQM_CMD(8)      /* newer version of get quota */
 
 /*
  * fs_disk_quota structure:
@@ -163,4 +164,50 @@ typedef struct fs_quota_stat {
        __u16           qs_iwarnlimit;  /* limit for num warnings */
 } fs_quota_stat_t;
 
+/*
+ * fs_quota_statv is used by Q_XGETQSTATV for a given file system. It provides
+ * a centralized way to get meta information about the quota subsystem. eg.
+ * space taken up for user, group, and project quotas, number of dquots
+ * currently incore.
+ *
+ * This version has proper versioning support with appropriate padding for
+ * future expansions, and ability to expand for future without creating any
+ * backward compatibility issues.
+ *
+ * Q_XGETQSTATV uses the passed in value of the requested version via
+ * fs_quota_statv.qs_version to determine the return data layout of
+ * fs_quota_statv.  The kernel will fill the data fields relevant to that
+ * version.
+ *
+ * If kernel does not support user space caller specified version, EINVAL will
+ * be returned. User space caller can then reduce the version number and retry
+ * the same command.
+ */
+#define FS_QSTATV_VERSION1     1       /* fs_quota_statv.qs_version */
+/*
+ * Some basic information about 'quota files' for Q_XGETQSTATV command
+ */
+struct fs_qfilestatv {
+       __u64           qfs_ino;        /* inode number */
+       __u64           qfs_nblks;      /* number of BBs 512-byte-blks */
+       __u32           qfs_nextents;   /* number of extents */
+       __u32           qfs_pad;        /* pad for 8-byte alignment */
+};
+
+struct fs_quota_statv {
+       __s8                    qs_version;     /* version for future changes */
+       __u8                    qs_pad1;        /* pad for 16bit alignment */
+       __u16                   qs_flags;       /* FS_QUOTA_.* flags */
+       __u32                   qs_incoredqs;   /* number of dquots incore */
+       struct fs_qfilestatv    qs_uquota;      /* user quota information */
+       struct fs_qfilestatv    qs_gquota;      /* group quota information */
+       struct fs_qfilestatv    qs_pquota;      /* project quota information */
+       __s32                   qs_btimelimit;  /* limit for blks timer */
+       __s32                   qs_itimelimit;  /* limit for inodes timer */
+       __s32                   qs_rtbtimelimit;/* limit for rt blks timer */
+       __u16                   qs_bwarnlimit;  /* limit for num warnings */
+       __u16                   qs_iwarnlimit;  /* limit for num warnings */
+       __u64                   qs_pad2[8];     /* for future proofing */
+};
+
 #endif /* _LINUX_DQBLK_XFS_H */
index a4ed56cf0eac5f1e5c1b90edf2a1d3b6093d9e02..6c28b61bb69041b166b09698a05d8c0619122c1c 100644 (file)
@@ -49,9 +49,9 @@ struct files_stat_struct {
 };
 
 struct inodes_stat_t {
-       int nr_inodes;
-       int nr_unused;
-       int dummy[5];           /* padding for sysctl ABI compatibility */
+       long nr_inodes;
+       long nr_unused;
+       long dummy[5];          /* padding for sysctl ABI compatibility */
 };
 
 
index d08abf9101d2161df16557e97e86b67c969eaa10..a3726275876dc509bfa99a01b8113385c1fb2d2f 100644 (file)
@@ -152,6 +152,7 @@ struct input_keymap_entry {
 #define EVIOCGEFFECTS          _IOR('E', 0x84, int)                    /* Report number of effects playable at the same time */
 
 #define EVIOCGRAB              _IOW('E', 0x90, int)                    /* Grab/Release device */
+#define EVIOCREVOKE            _IOW('E', 0x91, int)                    /* Revoke device access */
 
 #define EVIOCSCLOCKID          _IOW('E', 0xa0, int)                    /* Set clockid to be used for timestamps */
 
diff --git a/include/uapi/linux/nvme.h b/include/uapi/linux/nvme.h
new file mode 100644 (file)
index 0000000..989c04e
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * Definitions for the NVM Express interface
+ * Copyright (c) 2011-2013, Intel Corporation.
+ *
+ * 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.
+ */
+
+#ifndef _UAPI_LINUX_NVME_H
+#define _UAPI_LINUX_NVME_H
+
+#include <linux/types.h>
+
+struct nvme_id_power_state {
+       __le16                  max_power;      /* centiwatts */
+       __u8                    rsvd2;
+       __u8                    flags;
+       __le32                  entry_lat;      /* microseconds */
+       __le32                  exit_lat;       /* microseconds */
+       __u8                    read_tput;
+       __u8                    read_lat;
+       __u8                    write_tput;
+       __u8                    write_lat;
+       __u8                    rsvd16[16];
+};
+
+enum {
+       NVME_PS_FLAGS_MAX_POWER_SCALE   = 1 << 0,
+       NVME_PS_FLAGS_NON_OP_STATE      = 1 << 1,
+};
+
+struct nvme_id_ctrl {
+       __le16                  vid;
+       __le16                  ssvid;
+       char                    sn[20];
+       char                    mn[40];
+       char                    fr[8];
+       __u8                    rab;
+       __u8                    ieee[3];
+       __u8                    mic;
+       __u8                    mdts;
+       __u8                    rsvd78[178];
+       __le16                  oacs;
+       __u8                    acl;
+       __u8                    aerl;
+       __u8                    frmw;
+       __u8                    lpa;
+       __u8                    elpe;
+       __u8                    npss;
+       __u8                    rsvd264[248];
+       __u8                    sqes;
+       __u8                    cqes;
+       __u8                    rsvd514[2];
+       __le32                  nn;
+       __le16                  oncs;
+       __le16                  fuses;
+       __u8                    fna;
+       __u8                    vwc;
+       __le16                  awun;
+       __le16                  awupf;
+       __u8                    rsvd530[1518];
+       struct nvme_id_power_state      psd[32];
+       __u8                    vs[1024];
+};
+
+enum {
+       NVME_CTRL_ONCS_COMPARE                  = 1 << 0,
+       NVME_CTRL_ONCS_WRITE_UNCORRECTABLE      = 1 << 1,
+       NVME_CTRL_ONCS_DSM                      = 1 << 2,
+};
+
+struct nvme_lbaf {
+       __le16                  ms;
+       __u8                    ds;
+       __u8                    rp;
+};
+
+struct nvme_id_ns {
+       __le64                  nsze;
+       __le64                  ncap;
+       __le64                  nuse;
+       __u8                    nsfeat;
+       __u8                    nlbaf;
+       __u8                    flbas;
+       __u8                    mc;
+       __u8                    dpc;
+       __u8                    dps;
+       __u8                    rsvd30[98];
+       struct nvme_lbaf        lbaf[16];
+       __u8                    rsvd192[192];
+       __u8                    vs[3712];
+};
+
+enum {
+       NVME_NS_FEAT_THIN       = 1 << 0,
+       NVME_LBAF_RP_BEST       = 0,
+       NVME_LBAF_RP_BETTER     = 1,
+       NVME_LBAF_RP_GOOD       = 2,
+       NVME_LBAF_RP_DEGRADED   = 3,
+};
+
+struct nvme_smart_log {
+       __u8                    critical_warning;
+       __u8                    temperature[2];
+       __u8                    avail_spare;
+       __u8                    spare_thresh;
+       __u8                    percent_used;
+       __u8                    rsvd6[26];
+       __u8                    data_units_read[16];
+       __u8                    data_units_written[16];
+       __u8                    host_reads[16];
+       __u8                    host_writes[16];
+       __u8                    ctrl_busy_time[16];
+       __u8                    power_cycles[16];
+       __u8                    power_on_hours[16];
+       __u8                    unsafe_shutdowns[16];
+       __u8                    media_errors[16];
+       __u8                    num_err_log_entries[16];
+       __u8                    rsvd192[320];
+};
+
+enum {
+       NVME_SMART_CRIT_SPARE           = 1 << 0,
+       NVME_SMART_CRIT_TEMPERATURE     = 1 << 1,
+       NVME_SMART_CRIT_RELIABILITY     = 1 << 2,
+       NVME_SMART_CRIT_MEDIA           = 1 << 3,
+       NVME_SMART_CRIT_VOLATILE_MEMORY = 1 << 4,
+};
+
+struct nvme_lba_range_type {
+       __u8                    type;
+       __u8                    attributes;
+       __u8                    rsvd2[14];
+       __u64                   slba;
+       __u64                   nlb;
+       __u8                    guid[16];
+       __u8                    rsvd48[16];
+};
+
+enum {
+       NVME_LBART_TYPE_FS      = 0x01,
+       NVME_LBART_TYPE_RAID    = 0x02,
+       NVME_LBART_TYPE_CACHE   = 0x03,
+       NVME_LBART_TYPE_SWAP    = 0x04,
+
+       NVME_LBART_ATTRIB_TEMP  = 1 << 0,
+       NVME_LBART_ATTRIB_HIDE  = 1 << 1,
+};
+
+/* I/O commands */
+
+enum nvme_opcode {
+       nvme_cmd_flush          = 0x00,
+       nvme_cmd_write          = 0x01,
+       nvme_cmd_read           = 0x02,
+       nvme_cmd_write_uncor    = 0x04,
+       nvme_cmd_compare        = 0x05,
+       nvme_cmd_dsm            = 0x09,
+};
+
+struct nvme_common_command {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __le32                  cdw2[2];
+       __le64                  metadata;
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  cdw10[6];
+};
+
+struct nvme_rw_command {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2;
+       __le64                  metadata;
+       __le64                  prp1;
+       __le64                  prp2;
+       __le64                  slba;
+       __le16                  length;
+       __le16                  control;
+       __le32                  dsmgmt;
+       __le32                  reftag;
+       __le16                  apptag;
+       __le16                  appmask;
+};
+
+enum {
+       NVME_RW_LR                      = 1 << 15,
+       NVME_RW_FUA                     = 1 << 14,
+       NVME_RW_DSM_FREQ_UNSPEC         = 0,
+       NVME_RW_DSM_FREQ_TYPICAL        = 1,
+       NVME_RW_DSM_FREQ_RARE           = 2,
+       NVME_RW_DSM_FREQ_READS          = 3,
+       NVME_RW_DSM_FREQ_WRITES         = 4,
+       NVME_RW_DSM_FREQ_RW             = 5,
+       NVME_RW_DSM_FREQ_ONCE           = 6,
+       NVME_RW_DSM_FREQ_PREFETCH       = 7,
+       NVME_RW_DSM_FREQ_TEMP           = 8,
+       NVME_RW_DSM_LATENCY_NONE        = 0 << 4,
+       NVME_RW_DSM_LATENCY_IDLE        = 1 << 4,
+       NVME_RW_DSM_LATENCY_NORM        = 2 << 4,
+       NVME_RW_DSM_LATENCY_LOW         = 3 << 4,
+       NVME_RW_DSM_SEQ_REQ             = 1 << 6,
+       NVME_RW_DSM_COMPRESSED          = 1 << 7,
+};
+
+struct nvme_dsm_cmd {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2[2];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  nr;
+       __le32                  attributes;
+       __u32                   rsvd12[4];
+};
+
+enum {
+       NVME_DSMGMT_IDR         = 1 << 0,
+       NVME_DSMGMT_IDW         = 1 << 1,
+       NVME_DSMGMT_AD          = 1 << 2,
+};
+
+struct nvme_dsm_range {
+       __le32                  cattr;
+       __le32                  nlb;
+       __le64                  slba;
+};
+
+/* Admin commands */
+
+enum nvme_admin_opcode {
+       nvme_admin_delete_sq            = 0x00,
+       nvme_admin_create_sq            = 0x01,
+       nvme_admin_get_log_page         = 0x02,
+       nvme_admin_delete_cq            = 0x04,
+       nvme_admin_create_cq            = 0x05,
+       nvme_admin_identify             = 0x06,
+       nvme_admin_abort_cmd            = 0x08,
+       nvme_admin_set_features         = 0x09,
+       nvme_admin_get_features         = 0x0a,
+       nvme_admin_async_event          = 0x0c,
+       nvme_admin_activate_fw          = 0x10,
+       nvme_admin_download_fw          = 0x11,
+       nvme_admin_format_nvm           = 0x80,
+       nvme_admin_security_send        = 0x81,
+       nvme_admin_security_recv        = 0x82,
+};
+
+enum {
+       NVME_QUEUE_PHYS_CONTIG  = (1 << 0),
+       NVME_CQ_IRQ_ENABLED     = (1 << 1),
+       NVME_SQ_PRIO_URGENT     = (0 << 1),
+       NVME_SQ_PRIO_HIGH       = (1 << 1),
+       NVME_SQ_PRIO_MEDIUM     = (2 << 1),
+       NVME_SQ_PRIO_LOW        = (3 << 1),
+       NVME_FEAT_ARBITRATION   = 0x01,
+       NVME_FEAT_POWER_MGMT    = 0x02,
+       NVME_FEAT_LBA_RANGE     = 0x03,
+       NVME_FEAT_TEMP_THRESH   = 0x04,
+       NVME_FEAT_ERR_RECOVERY  = 0x05,
+       NVME_FEAT_VOLATILE_WC   = 0x06,
+       NVME_FEAT_NUM_QUEUES    = 0x07,
+       NVME_FEAT_IRQ_COALESCE  = 0x08,
+       NVME_FEAT_IRQ_CONFIG    = 0x09,
+       NVME_FEAT_WRITE_ATOMIC  = 0x0a,
+       NVME_FEAT_ASYNC_EVENT   = 0x0b,
+       NVME_FEAT_SW_PROGRESS   = 0x0c,
+       NVME_FWACT_REPL         = (0 << 3),
+       NVME_FWACT_REPL_ACTV    = (1 << 3),
+       NVME_FWACT_ACTV         = (2 << 3),
+};
+
+struct nvme_identify {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2[2];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  cns;
+       __u32                   rsvd11[5];
+};
+
+struct nvme_features {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2[2];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  fid;
+       __le32                  dword11;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_create_cq {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[5];
+       __le64                  prp1;
+       __u64                   rsvd8;
+       __le16                  cqid;
+       __le16                  qsize;
+       __le16                  cq_flags;
+       __le16                  irq_vector;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_create_sq {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[5];
+       __le64                  prp1;
+       __u64                   rsvd8;
+       __le16                  sqid;
+       __le16                  qsize;
+       __le16                  sq_flags;
+       __le16                  cqid;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_delete_queue {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[9];
+       __le16                  qid;
+       __u16                   rsvd10;
+       __u32                   rsvd11[5];
+};
+
+struct nvme_download_firmware {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __u32                   rsvd1[5];
+       __le64                  prp1;
+       __le64                  prp2;
+       __le32                  numd;
+       __le32                  offset;
+       __u32                   rsvd12[4];
+};
+
+struct nvme_format_cmd {
+       __u8                    opcode;
+       __u8                    flags;
+       __u16                   command_id;
+       __le32                  nsid;
+       __u64                   rsvd2[4];
+       __le32                  cdw10;
+       __u32                   rsvd11[5];
+};
+
+struct nvme_command {
+       union {
+               struct nvme_common_command common;
+               struct nvme_rw_command rw;
+               struct nvme_identify identify;
+               struct nvme_features features;
+               struct nvme_create_cq create_cq;
+               struct nvme_create_sq create_sq;
+               struct nvme_delete_queue delete_queue;
+               struct nvme_download_firmware dlfw;
+               struct nvme_format_cmd format;
+               struct nvme_dsm_cmd dsm;
+       };
+};
+
+enum {
+       NVME_SC_SUCCESS                 = 0x0,
+       NVME_SC_INVALID_OPCODE          = 0x1,
+       NVME_SC_INVALID_FIELD           = 0x2,
+       NVME_SC_CMDID_CONFLICT          = 0x3,
+       NVME_SC_DATA_XFER_ERROR         = 0x4,
+       NVME_SC_POWER_LOSS              = 0x5,
+       NVME_SC_INTERNAL                = 0x6,
+       NVME_SC_ABORT_REQ               = 0x7,
+       NVME_SC_ABORT_QUEUE             = 0x8,
+       NVME_SC_FUSED_FAIL              = 0x9,
+       NVME_SC_FUSED_MISSING           = 0xa,
+       NVME_SC_INVALID_NS              = 0xb,
+       NVME_SC_CMD_SEQ_ERROR           = 0xc,
+       NVME_SC_LBA_RANGE               = 0x80,
+       NVME_SC_CAP_EXCEEDED            = 0x81,
+       NVME_SC_NS_NOT_READY            = 0x82,
+       NVME_SC_CQ_INVALID              = 0x100,
+       NVME_SC_QID_INVALID             = 0x101,
+       NVME_SC_QUEUE_SIZE              = 0x102,
+       NVME_SC_ABORT_LIMIT             = 0x103,
+       NVME_SC_ABORT_MISSING           = 0x104,
+       NVME_SC_ASYNC_LIMIT             = 0x105,
+       NVME_SC_FIRMWARE_SLOT           = 0x106,
+       NVME_SC_FIRMWARE_IMAGE          = 0x107,
+       NVME_SC_INVALID_VECTOR          = 0x108,
+       NVME_SC_INVALID_LOG_PAGE        = 0x109,
+       NVME_SC_INVALID_FORMAT          = 0x10a,
+       NVME_SC_BAD_ATTRIBUTES          = 0x180,
+       NVME_SC_WRITE_FAULT             = 0x280,
+       NVME_SC_READ_ERROR              = 0x281,
+       NVME_SC_GUARD_CHECK             = 0x282,
+       NVME_SC_APPTAG_CHECK            = 0x283,
+       NVME_SC_REFTAG_CHECK            = 0x284,
+       NVME_SC_COMPARE_FAILED          = 0x285,
+       NVME_SC_ACCESS_DENIED           = 0x286,
+};
+
+struct nvme_completion {
+       __le32  result;         /* Used by admin commands to return data */
+       __u32   rsvd;
+       __le16  sq_head;        /* how much of this queue may be reclaimed */
+       __le16  sq_id;          /* submission queue that generated this entry */
+       __u16   command_id;     /* of the command which completed */
+       __le16  status;         /* did the command fail, and if so, why? */
+};
+
+struct nvme_user_io {
+       __u8    opcode;
+       __u8    flags;
+       __u16   control;
+       __u16   nblocks;
+       __u16   rsvd;
+       __u64   metadata;
+       __u64   addr;
+       __u64   slba;
+       __u32   dsmgmt;
+       __u32   reftag;
+       __u16   apptag;
+       __u16   appmask;
+};
+
+struct nvme_admin_cmd {
+       __u8    opcode;
+       __u8    flags;
+       __u16   rsvd1;
+       __u32   nsid;
+       __u32   cdw2;
+       __u32   cdw3;
+       __u64   metadata;
+       __u64   addr;
+       __u32   metadata_len;
+       __u32   data_len;
+       __u32   cdw10;
+       __u32   cdw11;
+       __u32   cdw12;
+       __u32   cdw13;
+       __u32   cdw14;
+       __u32   cdw15;
+       __u32   timeout_ms;
+       __u32   result;
+};
+
+#define NVME_IOCTL_ID          _IO('N', 0x40)
+#define NVME_IOCTL_ADMIN_CMD   _IOWR('N', 0x41, struct nvme_admin_cmd)
+#define NVME_IOCTL_SUBMIT_IO   _IOW('N', 0x42, struct nvme_user_io)
+
+#endif /* _UAPI_LINUX_NVME_H */
index ca1d90bcb74d248ddb48323279bd0b3d4520d489..40a1fb8073961425249d50110a6de04f856feac9 100644 (file)
@@ -324,7 +324,7 @@ struct perf_event_attr {
 #define PERF_EVENT_IOC_PERIOD          _IOW('$', 4, __u64)
 #define PERF_EVENT_IOC_SET_OUTPUT      _IO ('$', 5)
 #define PERF_EVENT_IOC_SET_FILTER      _IOW('$', 6, char *)
-#define PERF_EVENT_IOC_ID              _IOR('$', 7, u64 *)
+#define PERF_EVENT_IOC_ID              _IOR('$', 7, __u64 *)
 
 enum perf_event_ioc_flags {
        PERF_IOC_FLAG_GROUP             = 1U << 0,
index 916e444e6f74f38745353ec96108dd63e6b91a7e..0fd47f5bc146d2765b3bd2026fb183ff54142be2 100644 (file)
@@ -324,6 +324,44 @@ enum {
        VFIO_PCI_NUM_IRQS
 };
 
+/**
+ * VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IORW(VFIO_TYPE, VFIO_BASE + 12,
+ *                                           struct vfio_pci_hot_reset_info)
+ *
+ * Return: 0 on success, -errno on failure:
+ *     -enospc = insufficient buffer, -enodev = unsupported for device.
+ */
+struct vfio_pci_dependent_device {
+       __u32   group_id;
+       __u16   segment;
+       __u8    bus;
+       __u8    devfn; /* Use PCI_SLOT/PCI_FUNC */
+};
+
+struct vfio_pci_hot_reset_info {
+       __u32   argsz;
+       __u32   flags;
+       __u32   count;
+       struct vfio_pci_dependent_device        devices[];
+};
+
+#define VFIO_DEVICE_GET_PCI_HOT_RESET_INFO     _IO(VFIO_TYPE, VFIO_BASE + 12)
+
+/**
+ * VFIO_DEVICE_PCI_HOT_RESET - _IOW(VFIO_TYPE, VFIO_BASE + 13,
+ *                                 struct vfio_pci_hot_reset)
+ *
+ * Return: 0 on success, -errno on failure.
+ */
+struct vfio_pci_hot_reset {
+       __u32   argsz;
+       __u32   flags;
+       __u32   count;
+       __s32   group_fds[];
+};
+
+#define VFIO_DEVICE_PCI_HOT_RESET      _IO(VFIO_TYPE, VFIO_BASE + 13)
+
 /* -------- API for Type1 VFIO IOMMU -------- */
 
 /**
index 0a2c4bcf179e21d321b25206718cb58aad722b54..3ecd8a1178f102d832cdf3b4af0a908997ea648b 100644 (file)
@@ -1123,7 +1123,6 @@ config IPC_NS
 
 config USER_NS
        bool "User namespace"
-       depends on UIDGID_CONVERTED
        select UIDGID_STRICT_TYPE_CHECKS
 
        default n
@@ -1157,20 +1156,8 @@ config NET_NS
 
 endif # NAMESPACES
 
-config UIDGID_CONVERTED
-       # True if all of the selected software conmponents are known
-       # to have uid_t and gid_t converted to kuid_t and kgid_t
-       # where appropriate and are otherwise safe to use with
-       # the user namespace.
-       bool
-       default y
-
-       # Filesystems
-       depends on XFS_FS = n
-
 config UIDGID_STRICT_TYPE_CHECKS
        bool "Require conversions between uid/gids and their internal representation"
-       depends on UIDGID_CONVERTED
        default n
        help
         While the nececessary conversions are being added to all subsystems this option allows
@@ -1615,7 +1602,7 @@ endchoice
 
 config SLUB_CPU_PARTIAL
        default y
-       depends on SLUB
+       depends on SLUB && SMP
        bool "SLUB per cpu partial cache"
        help
          Per cpu partial caches accellerate objects allocation and freeing
@@ -1683,6 +1670,7 @@ config BASE_SMALL
 
 menuconfig MODULES
        bool "Enable loadable module support"
+       option modules
        help
          Kernel modules are small pieces of compiled code which can
          be inserted in the running kernel, rather than being
index 816014c4627ee2f4adb7c8cf7ef53e6083de16fc..a51cddc2ff8c184e7a7034585190a9fad8ad270b 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/async.h>
 #include <linux/fs_struct.h>
 #include <linux/slab.h>
+#include <linux/ramfs.h>
+#include <linux/shmem_fs.h>
 
 #include <linux/nfs_fs.h>
 #include <linux/nfs_fs_sb.h>
@@ -588,3 +590,46 @@ out:
        sys_mount(".", "/", NULL, MS_MOVE, NULL);
        sys_chroot(".");
 }
+
+static bool is_tmpfs;
+static struct dentry *rootfs_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data)
+{
+       static unsigned long once;
+       void *fill = ramfs_fill_super;
+
+       if (test_and_set_bit(0, &once))
+               return ERR_PTR(-ENODEV);
+
+       if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs)
+               fill = shmem_fill_super;
+
+       return mount_nodev(fs_type, flags, data, fill);
+}
+
+static struct file_system_type rootfs_fs_type = {
+       .name           = "rootfs",
+       .mount          = rootfs_mount,
+       .kill_sb        = kill_litter_super,
+};
+
+int __init init_rootfs(void)
+{
+       int err = register_filesystem(&rootfs_fs_type);
+
+       if (err)
+               return err;
+
+       if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] &&
+               (!root_fs_names || strstr(root_fs_names, "tmpfs"))) {
+               err = shmem_init();
+               is_tmpfs = true;
+       } else {
+               err = init_ramfs_fs();
+       }
+
+       if (err)
+               unregister_filesystem(&rootfs_fs_type);
+
+       return err;
+}
index b65fdf1a09dd1f81b32731bfa2fcb455389ea63c..b0d541d426771caec217961b031e3de191135ced 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -70,8 +70,6 @@ struct msg_sender {
 
 #define msg_ids(ns)    ((ns)->ids[IPC_MSG_IDS])
 
-#define msg_unlock(msq)                ipc_unlock(&(msq)->q_perm)
-
 static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
 static int newque(struct ipc_namespace *, struct ipc_params *);
 #ifdef CONFIG_PROC_FS
@@ -172,7 +170,7 @@ static inline void msg_rmid(struct ipc_namespace *ns, struct msg_queue *s)
  * @ns: namespace
  * @params: ptr to the structure that contains the key and msgflg
  *
- * Called with msg_ids.rw_mutex held (writer)
+ * Called with msg_ids.rwsem held (writer)
  */
 static int newque(struct ipc_namespace *ns, struct ipc_params *params)
 {
@@ -259,8 +257,8 @@ static void expunge_all(struct msg_queue *msq, int res)
  * removes the message queue from message queue ID IDR, and cleans up all the
  * messages associated with this queue.
  *
- * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held
- * before freeque() is called. msg_ids.rw_mutex remains locked on exit.
+ * msg_ids.rwsem (writer) and the spinlock for this message queue are held
+ * before freeque() is called. msg_ids.rwsem remains locked on exit.
  */
 static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 {
@@ -270,7 +268,8 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        expunge_all(msq, -EIDRM);
        ss_wakeup(&msq->q_senders, 1);
        msg_rmid(ns, msq);
-       msg_unlock(msq);
+       ipc_unlock_object(&msq->q_perm);
+       rcu_read_unlock();
 
        list_for_each_entry_safe(msg, t, &msq->q_messages, m_list) {
                atomic_dec(&ns->msg_hdrs);
@@ -282,7 +281,7 @@ static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 }
 
 /*
- * Called with msg_ids.rw_mutex and ipcp locked.
+ * Called with msg_ids.rwsem and ipcp locked.
  */
 static inline int msg_security(struct kern_ipc_perm *ipcp, int msgflg)
 {
@@ -386,9 +385,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
 }
 
 /*
- * This function handles some msgctl commands which require the rw_mutex
+ * This function handles some msgctl commands which require the rwsem
  * to be held in write mode.
- * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ * NOTE: no locks must be held, the rwsem is taken inside this function.
  */
 static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
                       struct msqid_ds __user *buf, int version)
@@ -403,7 +402,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
                        return -EFAULT;
        }
 
-       down_write(&msg_ids(ns).rw_mutex);
+       down_write(&msg_ids(ns).rwsem);
        rcu_read_lock();
 
        ipcp = ipcctl_pre_down_nolock(ns, &msg_ids(ns), msqid, cmd,
@@ -459,7 +458,7 @@ out_unlock0:
 out_unlock1:
        rcu_read_unlock();
 out_up:
-       up_write(&msg_ids(ns).rw_mutex);
+       up_write(&msg_ids(ns).rwsem);
        return err;
 }
 
@@ -494,7 +493,7 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
                msginfo.msgmnb = ns->msg_ctlmnb;
                msginfo.msgssz = MSGSSZ;
                msginfo.msgseg = MSGSEG;
-               down_read(&msg_ids(ns).rw_mutex);
+               down_read(&msg_ids(ns).rwsem);
                if (cmd == MSG_INFO) {
                        msginfo.msgpool = msg_ids(ns).in_use;
                        msginfo.msgmap = atomic_read(&ns->msg_hdrs);
@@ -505,7 +504,7 @@ static int msgctl_nolock(struct ipc_namespace *ns, int msqid,
                        msginfo.msgtql = MSGTQL;
                }
                max_id = ipc_get_maxid(&msg_ids(ns));
-               up_read(&msg_ids(ns).rw_mutex);
+               up_read(&msg_ids(ns).rwsem);
                if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
                        return -EFAULT;
                return (max_id < 0) ? 0 : max_id;
index 4be6581d3b7fa075c3d899e889ce6d09e8fcca86..59451c1e214d71f1b771b764d309b20759e19eb6 100644 (file)
@@ -81,7 +81,7 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
        int next_id;
        int total, in_use;
 
-       down_write(&ids->rw_mutex);
+       down_write(&ids->rwsem);
 
        in_use = ids->in_use;
 
@@ -89,11 +89,12 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
                perm = idr_find(&ids->ipcs_idr, next_id);
                if (perm == NULL)
                        continue;
-               ipc_lock_by_ptr(perm);
+               rcu_read_lock();
+               ipc_lock_object(perm);
                free(ns, perm);
                total++;
        }
-       up_write(&ids->rw_mutex);
+       up_write(&ids->rwsem);
 }
 
 static void free_ipc_ns(struct ipc_namespace *ns)
index 41088899783d4106140333014a722da531494838..69b6a21f38441aa437a8f79cb53ae4c4a6a520a1 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -322,7 +322,7 @@ static inline void sem_unlock(struct sem_array *sma, int locknum)
 }
 
 /*
- * sem_lock_(check_) routines are called in the paths where the rw_mutex
+ * sem_lock_(check_) routines are called in the paths where the rwsem
  * is not held.
  *
  * The caller holds the RCU read lock.
@@ -426,7 +426,7 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  * @ns: namespace
  * @params: ptr to the structure that contains key, semflg and nsems
  *
- * Called with sem_ids.rw_mutex held (as a writer)
+ * Called with sem_ids.rwsem held (as a writer)
  */
 
 static int newary(struct ipc_namespace *ns, struct ipc_params *params)
@@ -492,7 +492,7 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
 
 
 /*
- * Called with sem_ids.rw_mutex and ipcp locked.
+ * Called with sem_ids.rwsem and ipcp locked.
  */
 static inline int sem_security(struct kern_ipc_perm *ipcp, int semflg)
 {
@@ -503,7 +503,7 @@ static inline int sem_security(struct kern_ipc_perm *ipcp, int semflg)
 }
 
 /*
- * Called with sem_ids.rw_mutex and ipcp locked.
+ * Called with sem_ids.rwsem and ipcp locked.
  */
 static inline int sem_more_checks(struct kern_ipc_perm *ipcp,
                                struct ipc_params *params)
@@ -994,8 +994,8 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
        return semzcnt;
 }
 
-/* Free a semaphore set. freeary() is called with sem_ids.rw_mutex locked
- * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex
+/* Free a semaphore set. freeary() is called with sem_ids.rwsem locked
+ * as a writer and the spinlock for this semaphore set hold. sem_ids.rwsem
  * remains locked on exit.
  */
 static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
@@ -1116,7 +1116,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                seminfo.semmnu = SEMMNU;
                seminfo.semmap = SEMMAP;
                seminfo.semume = SEMUME;
-               down_read(&sem_ids(ns).rw_mutex);
+               down_read(&sem_ids(ns).rwsem);
                if (cmd == SEM_INFO) {
                        seminfo.semusz = sem_ids(ns).in_use;
                        seminfo.semaem = ns->used_sems;
@@ -1125,7 +1125,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                        seminfo.semaem = SEMAEM;
                }
                max_id = ipc_get_maxid(&sem_ids(ns));
-               up_read(&sem_ids(ns).rw_mutex);
+               up_read(&sem_ids(ns).rwsem);
                if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) 
                        return -EFAULT;
                return (max_id < 0) ? 0: max_id;
@@ -1431,9 +1431,9 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
 }
 
 /*
- * This function handles some semctl commands which require the rw_mutex
+ * This function handles some semctl commands which require the rwsem
  * to be held in write mode.
- * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ * NOTE: no locks must be held, the rwsem is taken inside this function.
  */
 static int semctl_down(struct ipc_namespace *ns, int semid,
                       int cmd, int version, void __user *p)
@@ -1448,7 +1448,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
                        return -EFAULT;
        }
 
-       down_write(&sem_ids(ns).rw_mutex);
+       down_write(&sem_ids(ns).rwsem);
        rcu_read_lock();
 
        ipcp = ipcctl_pre_down_nolock(ns, &sem_ids(ns), semid, cmd,
@@ -1487,7 +1487,7 @@ out_unlock0:
 out_unlock1:
        rcu_read_unlock();
 out_up:
-       up_write(&sem_ids(ns).rw_mutex);
+       up_write(&sem_ids(ns).rwsem);
        return err;
 }
 
index c6b4ad5ce3b7b53df40b5934bb823fff4de9f9c8..2821cdf93adb39ac83f8a604e6f487590bfe01f7 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -19,6 +19,9 @@
  * namespaces support
  * OpenVZ, SWsoft Inc.
  * Pavel Emelianov <xemul@openvz.org>
+ *
+ * Better ipc lock (kern_ipc_perm.lock) handling
+ * Davidlohr Bueso <davidlohr.bueso@hp.com>, June 2013.
  */
 
 #include <linux/slab.h>
@@ -80,8 +83,8 @@ void shm_init_ns(struct ipc_namespace *ns)
 }
 
 /*
- * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
- * Only shm_ids.rw_mutex remains locked on exit.
+ * Called with shm_ids.rwsem (writer) and the shp structure locked.
+ * Only shm_ids.rwsem remains locked on exit.
  */
 static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 {
@@ -124,8 +127,28 @@ void __init shm_init (void)
                                IPC_SHM_IDS, sysvipc_shm_proc_show);
 }
 
+static inline struct shmid_kernel *shm_obtain_object(struct ipc_namespace *ns, int id)
+{
+       struct kern_ipc_perm *ipcp = ipc_obtain_object(&shm_ids(ns), id);
+
+       if (IS_ERR(ipcp))
+               return ERR_CAST(ipcp);
+
+       return container_of(ipcp, struct shmid_kernel, shm_perm);
+}
+
+static inline struct shmid_kernel *shm_obtain_object_check(struct ipc_namespace *ns, int id)
+{
+       struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&shm_ids(ns), id);
+
+       if (IS_ERR(ipcp))
+               return ERR_CAST(ipcp);
+
+       return container_of(ipcp, struct shmid_kernel, shm_perm);
+}
+
 /*
- * shm_lock_(check_) routines are called in the paths where the rw_mutex
+ * shm_lock_(check_) routines are called in the paths where the rwsem
  * is not necessarily held.
  */
 static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
@@ -144,17 +167,6 @@ static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
        ipc_lock_object(&ipcp->shm_perm);
 }
 
-static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
-                                               int id)
-{
-       struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
-
-       if (IS_ERR(ipcp))
-               return (struct shmid_kernel *)ipcp;
-
-       return container_of(ipcp, struct shmid_kernel, shm_perm);
-}
-
 static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
 {
        ipc_rmid(&shm_ids(ns), &s->shm_perm);
@@ -182,7 +194,7 @@ static void shm_open(struct vm_area_struct *vma)
  * @ns: namespace
  * @shp: struct to free
  *
- * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
+ * It has to be called with shp and shm_ids.rwsem (writer) locked,
  * but returns with shp unlocked and freed.
  */
 static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
@@ -230,7 +242,7 @@ static void shm_close(struct vm_area_struct *vma)
        struct shmid_kernel *shp;
        struct ipc_namespace *ns = sfd->ns;
 
-       down_write(&shm_ids(ns).rw_mutex);
+       down_write(&shm_ids(ns).rwsem);
        /* remove from the list of attaches of the shm segment */
        shp = shm_lock(ns, sfd->id);
        BUG_ON(IS_ERR(shp));
@@ -241,10 +253,10 @@ static void shm_close(struct vm_area_struct *vma)
                shm_destroy(ns, shp);
        else
                shm_unlock(shp);
-       up_write(&shm_ids(ns).rw_mutex);
+       up_write(&shm_ids(ns).rwsem);
 }
 
-/* Called with ns->shm_ids(ns).rw_mutex locked */
+/* Called with ns->shm_ids(ns).rwsem locked */
 static int shm_try_destroy_current(int id, void *p, void *data)
 {
        struct ipc_namespace *ns = data;
@@ -275,7 +287,7 @@ static int shm_try_destroy_current(int id, void *p, void *data)
        return 0;
 }
 
-/* Called with ns->shm_ids(ns).rw_mutex locked */
+/* Called with ns->shm_ids(ns).rwsem locked */
 static int shm_try_destroy_orphaned(int id, void *p, void *data)
 {
        struct ipc_namespace *ns = data;
@@ -286,7 +298,7 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data)
         * We want to destroy segments without users and with already
         * exit'ed originating process.
         *
-        * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
+        * As shp->* are changed under rwsem, it's safe to skip shp locking.
         */
        if (shp->shm_creator != NULL)
                return 0;
@@ -300,10 +312,10 @@ static int shm_try_destroy_orphaned(int id, void *p, void *data)
 
 void shm_destroy_orphaned(struct ipc_namespace *ns)
 {
-       down_write(&shm_ids(ns).rw_mutex);
+       down_write(&shm_ids(ns).rwsem);
        if (shm_ids(ns).in_use)
                idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
-       up_write(&shm_ids(ns).rw_mutex);
+       up_write(&shm_ids(ns).rwsem);
 }
 
 
@@ -315,10 +327,10 @@ void exit_shm(struct task_struct *task)
                return;
 
        /* Destroy all already created segments, but not mapped yet */
-       down_write(&shm_ids(ns).rw_mutex);
+       down_write(&shm_ids(ns).rwsem);
        if (shm_ids(ns).in_use)
                idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
-       up_write(&shm_ids(ns).rw_mutex);
+       up_write(&shm_ids(ns).rwsem);
 }
 
 static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
@@ -452,7 +464,7 @@ static const struct vm_operations_struct shm_vm_ops = {
  * @ns: namespace
  * @params: ptr to the structure that contains key, size and shmflg
  *
- * Called with shm_ids.rw_mutex held as a writer.
+ * Called with shm_ids.rwsem held as a writer.
  */
 
 static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
@@ -560,7 +572,7 @@ no_file:
 }
 
 /*
- * Called with shm_ids.rw_mutex and ipcp locked.
+ * Called with shm_ids.rwsem and ipcp locked.
  */
 static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
 {
@@ -571,7 +583,7 @@ static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
 }
 
 /*
- * Called with shm_ids.rw_mutex and ipcp locked.
+ * Called with shm_ids.rwsem and ipcp locked.
  */
 static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
                                struct ipc_params *params)
@@ -684,7 +696,7 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
 
 /*
  * Calculate and add used RSS and swap pages of a shm.
- * Called with shm_ids.rw_mutex held as a reader
+ * Called with shm_ids.rwsem held as a reader
  */
 static void shm_add_rss_swap(struct shmid_kernel *shp,
        unsigned long *rss_add, unsigned long *swp_add)
@@ -711,7 +723,7 @@ static void shm_add_rss_swap(struct shmid_kernel *shp,
 }
 
 /*
- * Called with shm_ids.rw_mutex held as a reader
+ * Called with shm_ids.rwsem held as a reader
  */
 static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
                unsigned long *swp)
@@ -740,9 +752,9 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
 }
 
 /*
- * This function handles some shmctl commands which require the rw_mutex
+ * This function handles some shmctl commands which require the rwsem
  * to be held in write mode.
- * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ * NOTE: no locks must be held, the rwsem is taken inside this function.
  */
 static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
                       struct shmid_ds __user *buf, int version)
@@ -757,14 +769,13 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
                        return -EFAULT;
        }
 
-       down_write(&shm_ids(ns).rw_mutex);
+       down_write(&shm_ids(ns).rwsem);
        rcu_read_lock();
 
-       ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
-                              &shmid64.shm_perm, 0);
+       ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
+                                     &shmid64.shm_perm, 0);
        if (IS_ERR(ipcp)) {
                err = PTR_ERR(ipcp);
-               /* the ipc lock is not held upon failure */
                goto out_unlock1;
        }
 
@@ -772,14 +783,16 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
 
        err = security_shm_shmctl(shp, cmd);
        if (err)
-               goto out_unlock0;
+               goto out_unlock1;
 
        switch (cmd) {
        case IPC_RMID:
+               ipc_lock_object(&shp->shm_perm);
                /* do_shm_rmid unlocks the ipc object and rcu */
                do_shm_rmid(ns, ipcp);
                goto out_up;
        case IPC_SET:
+               ipc_lock_object(&shp->shm_perm);
                err = ipc_update_perm(&shmid64.shm_perm, ipcp);
                if (err)
                        goto out_unlock0;
@@ -787,6 +800,7 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
                break;
        default:
                err = -EINVAL;
+               goto out_unlock1;
        }
 
 out_unlock0:
@@ -794,33 +808,28 @@ out_unlock0:
 out_unlock1:
        rcu_read_unlock();
 out_up:
-       up_write(&shm_ids(ns).rw_mutex);
+       up_write(&shm_ids(ns).rwsem);
        return err;
 }
 
-SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
+static int shmctl_nolock(struct ipc_namespace *ns, int shmid,
+                        int cmd, int version, void __user *buf)
 {
+       int err;
        struct shmid_kernel *shp;
-       int err, version;
-       struct ipc_namespace *ns;
 
-       if (cmd < 0 || shmid < 0) {
-               err = -EINVAL;
-               goto out;
+       /* preliminary security checks for *_INFO */
+       if (cmd == IPC_INFO || cmd == SHM_INFO) {
+               err = security_shm_shmctl(NULL, cmd);
+               if (err)
+                       return err;
        }
 
-       version = ipc_parse_version(&cmd);
-       ns = current->nsproxy->ipc_ns;
-
-       switch (cmd) { /* replace with proc interface ? */
+       switch (cmd) {
        case IPC_INFO:
        {
                struct shminfo64 shminfo;
 
-               err = security_shm_shmctl(NULL, cmd);
-               if (err)
-                       return err;
-
                memset(&shminfo, 0, sizeof(shminfo));
                shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
                shminfo.shmmax = ns->shm_ctlmax;
@@ -830,9 +839,9 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                if(copy_shminfo_to_user (buf, &shminfo, version))
                        return -EFAULT;
 
-               down_read(&shm_ids(ns).rw_mutex);
+               down_read(&shm_ids(ns).rwsem);
                err = ipc_get_maxid(&shm_ids(ns));
-               up_read(&shm_ids(ns).rw_mutex);
+               up_read(&shm_ids(ns).rwsem);
 
                if(err<0)
                        err = 0;
@@ -842,19 +851,15 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
        {
                struct shm_info shm_info;
 
-               err = security_shm_shmctl(NULL, cmd);
-               if (err)
-                       return err;
-
                memset(&shm_info, 0, sizeof(shm_info));
-               down_read(&shm_ids(ns).rw_mutex);
+               down_read(&shm_ids(ns).rwsem);
                shm_info.used_ids = shm_ids(ns).in_use;
                shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
                shm_info.shm_tot = ns->shm_tot;
                shm_info.swap_attempts = 0;
                shm_info.swap_successes = 0;
                err = ipc_get_maxid(&shm_ids(ns));
-               up_read(&shm_ids(ns).rw_mutex);
+               up_read(&shm_ids(ns).rwsem);
                if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
                        err = -EFAULT;
                        goto out;
@@ -869,27 +874,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                struct shmid64_ds tbuf;
                int result;
 
+               rcu_read_lock();
                if (cmd == SHM_STAT) {
-                       shp = shm_lock(ns, shmid);
+                       shp = shm_obtain_object(ns, shmid);
                        if (IS_ERR(shp)) {
                                err = PTR_ERR(shp);
-                               goto out;
+                               goto out_unlock;
                        }
                        result = shp->shm_perm.id;
                } else {
-                       shp = shm_lock_check(ns, shmid);
+                       shp = shm_obtain_object_check(ns, shmid);
                        if (IS_ERR(shp)) {
                                err = PTR_ERR(shp);
-                               goto out;
+                               goto out_unlock;
                        }
                        result = 0;
                }
+
                err = -EACCES;
                if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
                        goto out_unlock;
+
                err = security_shm_shmctl(shp, cmd);
                if (err)
                        goto out_unlock;
+
                memset(&tbuf, 0, sizeof(tbuf));
                kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
                tbuf.shm_segsz  = shp->shm_segsz;
@@ -899,43 +908,76 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                tbuf.shm_cpid   = shp->shm_cprid;
                tbuf.shm_lpid   = shp->shm_lprid;
                tbuf.shm_nattch = shp->shm_nattch;
-               shm_unlock(shp);
-               if(copy_shmid_to_user (buf, &tbuf, version))
+               rcu_read_unlock();
+
+               if (copy_shmid_to_user(buf, &tbuf, version))
                        err = -EFAULT;
                else
                        err = result;
                goto out;
        }
+       default:
+               return -EINVAL;
+       }
+
+out_unlock:
+       rcu_read_unlock();
+out:
+       return err;
+}
+
+SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
+{
+       struct shmid_kernel *shp;
+       int err, version;
+       struct ipc_namespace *ns;
+
+       if (cmd < 0 || shmid < 0)
+               return -EINVAL;
+
+       version = ipc_parse_version(&cmd);
+       ns = current->nsproxy->ipc_ns;
+
+       switch (cmd) {
+       case IPC_INFO:
+       case SHM_INFO:
+       case SHM_STAT:
+       case IPC_STAT:
+               return shmctl_nolock(ns, shmid, cmd, version, buf);
+       case IPC_RMID:
+       case IPC_SET:
+               return shmctl_down(ns, shmid, cmd, buf, version);
        case SHM_LOCK:
        case SHM_UNLOCK:
        {
                struct file *shm_file;
 
-               shp = shm_lock_check(ns, shmid);
+               rcu_read_lock();
+               shp = shm_obtain_object_check(ns, shmid);
                if (IS_ERR(shp)) {
                        err = PTR_ERR(shp);
-                       goto out;
+                       goto out_unlock1;
                }
 
                audit_ipc_obj(&(shp->shm_perm));
+               err = security_shm_shmctl(shp, cmd);
+               if (err)
+                       goto out_unlock1;
 
+               ipc_lock_object(&shp->shm_perm);
                if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
                        kuid_t euid = current_euid();
                        err = -EPERM;
                        if (!uid_eq(euid, shp->shm_perm.uid) &&
                            !uid_eq(euid, shp->shm_perm.cuid))
-                               goto out_unlock;
+                               goto out_unlock0;
                        if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
-                               goto out_unlock;
+                               goto out_unlock0;
                }
 
-               err = security_shm_shmctl(shp, cmd);
-               if (err)
-                       goto out_unlock;
-
                shm_file = shp->shm_file;
                if (is_file_hugepages(shm_file))
-                       goto out_unlock;
+                       goto out_unlock0;
 
                if (cmd == SHM_LOCK) {
                        struct user_struct *user = current_user();
@@ -944,32 +986,31 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                                shp->shm_perm.mode |= SHM_LOCKED;
                                shp->mlock_user = user;
                        }
-                       goto out_unlock;
+                       goto out_unlock0;
                }
 
                /* SHM_UNLOCK */
                if (!(shp->shm_perm.mode & SHM_LOCKED))
-                       goto out_unlock;
+                       goto out_unlock0;
                shmem_lock(shm_file, 0, shp->mlock_user);
                shp->shm_perm.mode &= ~SHM_LOCKED;
                shp->mlock_user = NULL;
                get_file(shm_file);
-               shm_unlock(shp);
+               ipc_unlock_object(&shp->shm_perm);
+               rcu_read_unlock();
                shmem_unlock_mapping(shm_file->f_mapping);
+
                fput(shm_file);
-               goto out;
-       }
-       case IPC_RMID:
-       case IPC_SET:
-               err = shmctl_down(ns, shmid, cmd, buf, version);
                return err;
+       }
        default:
                return -EINVAL;
        }
 
-out_unlock:
-       shm_unlock(shp);
-out:
+out_unlock0:
+       ipc_unlock_object(&shp->shm_perm);
+out_unlock1:
+       rcu_read_unlock();
        return err;
 }
 
@@ -1037,10 +1078,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
         * additional creator id...
         */
        ns = current->nsproxy->ipc_ns;
-       shp = shm_lock_check(ns, shmid);
+       rcu_read_lock();
+       shp = shm_obtain_object_check(ns, shmid);
        if (IS_ERR(shp)) {
                err = PTR_ERR(shp);
-               goto out;
+               goto out_unlock;
        }
 
        err = -EACCES;
@@ -1051,24 +1093,31 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
        if (err)
                goto out_unlock;
 
+       ipc_lock_object(&shp->shm_perm);
        path = shp->shm_file->f_path;
        path_get(&path);
        shp->shm_nattch++;
        size = i_size_read(path.dentry->d_inode);
-       shm_unlock(shp);
+       ipc_unlock_object(&shp->shm_perm);
+       rcu_read_unlock();
 
        err = -ENOMEM;
        sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
-       if (!sfd)
-               goto out_put_dentry;
+       if (!sfd) {
+               path_put(&path);
+               goto out_nattch;
+       }
 
        file = alloc_file(&path, f_mode,
                          is_file_hugepages(shp->shm_file) ?
                                &shm_file_operations_huge :
                                &shm_file_operations);
        err = PTR_ERR(file);
-       if (IS_ERR(file))
-               goto out_free;
+       if (IS_ERR(file)) {
+               kfree(sfd);
+               path_put(&path);
+               goto out_nattch;
+       }
 
        file->private_data = sfd;
        file->f_mapping = shp->shm_file->f_mapping;
@@ -1094,7 +1143,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
                    addr > current->mm->start_stack - size - PAGE_SIZE * 5)
                        goto invalid;
        }
-               
+
        addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate);
        *raddr = addr;
        err = 0;
@@ -1109,7 +1158,7 @@ out_fput:
        fput(file);
 
 out_nattch:
-       down_write(&shm_ids(ns).rw_mutex);
+       down_write(&shm_ids(ns).rwsem);
        shp = shm_lock(ns, shmid);
        BUG_ON(IS_ERR(shp));
        shp->shm_nattch--;
@@ -1117,20 +1166,13 @@ out_nattch:
                shm_destroy(ns, shp);
        else
                shm_unlock(shp);
-       up_write(&shm_ids(ns).rw_mutex);
-
-out:
+       up_write(&shm_ids(ns).rwsem);
        return err;
 
 out_unlock:
-       shm_unlock(shp);
-       goto out;
-
-out_free:
-       kfree(sfd);
-out_put_dentry:
-       path_put(&path);
-       goto out_nattch;
+       rcu_read_unlock();
+out:
+       return err;
 }
 
 SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
@@ -1235,8 +1277,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
 #else /* CONFIG_MMU */
        /* under NOMMU conditions, the exact address to be destroyed must be
         * given */
-       retval = -EINVAL;
-       if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
+       if (vma && vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
                do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
                retval = 0;
        }
index 4704223bfad48e41258e018266feb9f5ed4b860e..e829da9ed01f3dbe2973fd232a4f2b889f401c9c 100644 (file)
  * Jun 2006 - namespaces ssupport
  *            OpenVZ, SWsoft Inc.
  *            Pavel Emelianov <xemul@openvz.org>
+ *
+ * General sysv ipc locking scheme:
+ *  when doing ipc id lookups, take the ids->rwsem
+ *      rcu_read_lock()
+ *          obtain the ipc object (kern_ipc_perm)
+ *          perform security, capabilities, auditing and permission checks, etc.
+ *          acquire the ipc lock (kern_ipc_perm.lock) throught ipc_lock_object()
+ *             perform data updates (ie: SET, RMID, LOCK/UNLOCK commands)
  */
 
 #include <linux/mm.h>
@@ -119,7 +127,7 @@ __initcall(ipc_init);
  
 void ipc_init_ids(struct ipc_ids *ids)
 {
-       init_rwsem(&ids->rw_mutex);
+       init_rwsem(&ids->rwsem);
 
        ids->in_use = 0;
        ids->seq = 0;
@@ -174,7 +182,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
  *     @ids: Identifier set
  *     @key: The key to find
  *     
- *     Requires ipc_ids.rw_mutex locked.
+ *     Requires ipc_ids.rwsem locked.
  *     Returns the LOCKED pointer to the ipc structure if found or NULL
  *     if not.
  *     If key is found ipc points to the owning ipc structure
@@ -197,7 +205,8 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
                        continue;
                }
 
-               ipc_lock_by_ptr(ipc);
+               rcu_read_lock();
+               ipc_lock_object(ipc);
                return ipc;
        }
 
@@ -208,7 +217,7 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
  *     ipc_get_maxid   -       get the last assigned id
  *     @ids: IPC identifier set
  *
- *     Called with ipc_ids.rw_mutex held.
+ *     Called with ipc_ids.rwsem held.
  */
 
 int ipc_get_maxid(struct ipc_ids *ids)
@@ -246,7 +255,7 @@ int ipc_get_maxid(struct ipc_ids *ids)
  *     is returned. The 'new' entry is returned in a locked state on success.
  *     On failure the entry is not locked and a negative err-code is returned.
  *
- *     Called with writer ipc_ids.rw_mutex held.
+ *     Called with writer ipc_ids.rwsem held.
  */
 int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 {
@@ -312,9 +321,9 @@ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
 {
        int err;
 
-       down_write(&ids->rw_mutex);
+       down_write(&ids->rwsem);
        err = ops->getnew(ns, params);
-       up_write(&ids->rw_mutex);
+       up_write(&ids->rwsem);
        return err;
 }
 
@@ -331,7 +340,7 @@ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
  *
  *     On success, the IPC id is returned.
  *
- *     It is called with ipc_ids.rw_mutex and ipcp->lock held.
+ *     It is called with ipc_ids.rwsem and ipcp->lock held.
  */
 static int ipc_check_perms(struct ipc_namespace *ns,
                           struct kern_ipc_perm *ipcp,
@@ -376,7 +385,7 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
         * Take the lock as a writer since we are potentially going to add
         * a new entry + read locks are not "upgradable"
         */
-       down_write(&ids->rw_mutex);
+       down_write(&ids->rwsem);
        ipcp = ipc_findkey(ids, params->key);
        if (ipcp == NULL) {
                /* key not used */
@@ -402,7 +411,7 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
                }
                ipc_unlock(ipcp);
        }
-       up_write(&ids->rw_mutex);
+       up_write(&ids->rwsem);
 
        return err;
 }
@@ -413,7 +422,7 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
  *     @ids: IPC identifier set
  *     @ipcp: ipc perm structure containing the identifier to remove
  *
- *     ipc_ids.rw_mutex (as a writer) and the spinlock for this ID are held
+ *     ipc_ids.rwsem (as a writer) and the spinlock for this ID are held
  *     before this function is called, and remain locked on the exit.
  */
  
@@ -621,7 +630,7 @@ struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id)
 }
 
 /**
- * ipc_lock - Lock an ipc structure without rw_mutex held
+ * ipc_lock - Lock an ipc structure without rwsem held
  * @ids: IPC identifier set
  * @id: ipc id to look for
  *
@@ -677,22 +686,6 @@ out:
        return out;
 }
 
-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
-{
-       struct kern_ipc_perm *out;
-
-       out = ipc_lock(ids, id);
-       if (IS_ERR(out))
-               return out;
-
-       if (ipc_checkid(out, id)) {
-               ipc_unlock(out);
-               return ERR_PTR(-EIDRM);
-       }
-
-       return out;
-}
-
 /**
  * ipcget - Common sys_*get() code
  * @ns : namsepace
@@ -733,7 +726,7 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
 }
 
 /**
- * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
+ * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd
  * @ns:  the ipc namespace
  * @ids:  the table of ids where to look for the ipc
  * @id:   the id of the ipc to retrieve
@@ -746,29 +739,13 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
  * It must be called without any lock held and
  *  - retrieves the ipc with the given id in the given table.
  *  - performs some audit and permission check, depending on the given cmd
- *  - returns the ipc with the ipc lock held in case of success
- *    or an err-code without any lock held otherwise.
+ *  - returns a pointer to the ipc object or otherwise, the corresponding error.
  *
- * Call holding the both the rw_mutex and the rcu read lock.
+ * Call holding the both the rwsem and the rcu read lock.
  */
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
-                                     struct ipc_ids *ids, int id, int cmd,
-                                     struct ipc64_perm *perm, int extra_perm)
-{
-       struct kern_ipc_perm *ipcp;
-
-       ipcp = ipcctl_pre_down_nolock(ns, ids, id, cmd, perm, extra_perm);
-       if (IS_ERR(ipcp))
-               goto out;
-
-       spin_lock(&ipcp->lock);
-out:
-       return ipcp;
-}
-
 struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
-                                            struct ipc_ids *ids, int id, int cmd,
-                                            struct ipc64_perm *perm, int extra_perm)
+                                       struct ipc_ids *ids, int id, int cmd,
+                                       struct ipc64_perm *perm, int extra_perm)
 {
        kuid_t euid;
        int err = -EPERM;
@@ -846,7 +823,8 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
                ipc = idr_find(&ids->ipcs_idr, pos);
                if (ipc != NULL) {
                        *new_pos = pos + 1;
-                       ipc_lock_by_ptr(ipc);
+                       rcu_read_lock();
+                       ipc_lock_object(ipc);
                        return ipc;
                }
        }
@@ -884,7 +862,7 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
         * Take the lock - this will be released by the corresponding
         * call to stop().
         */
-       down_read(&ids->rw_mutex);
+       down_read(&ids->rwsem);
 
        /* pos < 0 is invalid */
        if (*pos < 0)
@@ -911,7 +889,7 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it)
 
        ids = &iter->ns->ids[iface->ids];
        /* Release the lock we took in start() */
-       up_read(&ids->rw_mutex);
+       up_read(&ids->rwsem);
 }
 
 static int sysvipc_proc_show(struct seq_file *s, void *it)
index b6a6a88f30024f17dff00e7257c622dca2af1912..c5f3338ba1fa7913967c1bc7e9845e0561eeb027 100644 (file)
@@ -94,10 +94,10 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
 #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
 #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER)
 
-/* must be called with ids->rw_mutex acquired for writing */
+/* must be called with ids->rwsem acquired for writing */
 int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
 
-/* must be called with ids->rw_mutex acquired for reading */
+/* must be called with ids->rwsem acquired for reading */
 int ipc_get_maxid(struct ipc_ids *);
 
 /* must be called with both locks acquired. */
@@ -131,9 +131,6 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
 struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
                                             struct ipc_ids *ids, int id, int cmd,
                                             struct ipc64_perm *perm, int extra_perm);
-struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
-                                     struct ipc_ids *ids, int id, int cmd,
-                                     struct ipc64_perm *perm, int extra_perm);
 
 #ifndef CONFIG_ARCH_WANT_IPC_PARSE_VERSION
   /* On IA-64, we always use the "64-bit version" of the IPC structures.  */ 
@@ -174,19 +171,12 @@ static inline void ipc_assert_locked_object(struct kern_ipc_perm *perm)
        assert_spin_locked(&perm->lock);
 }
 
-static inline void ipc_lock_by_ptr(struct kern_ipc_perm *perm)
-{
-       rcu_read_lock();
-       ipc_lock_object(perm);
-}
-
 static inline void ipc_unlock(struct kern_ipc_perm *perm)
 {
        ipc_unlock_object(perm);
        rcu_read_unlock();
 }
 
-struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
 struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
 int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
                        struct ipc_ops *ops, struct ipc_params *params);
index 35ef1185e359457323d5513b578185ad16435bc2..1ce47553fb020e97e2a930309242c2c1e5161437 100644 (file)
@@ -26,6 +26,7 @@ obj-y += sched/
 obj-y += power/
 obj-y += printk/
 obj-y += cpu/
+obj-y += irq/
 
 obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o
 obj-$(CONFIG_FREEZER) += freezer.o
@@ -79,7 +80,6 @@ obj-$(CONFIG_KPROBES) += kprobes.o
 obj-$(CONFIG_KGDB) += debug/
 obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o
 obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o
-obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
 obj-$(CONFIG_SECCOMP) += seccomp.o
 obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_TREE_RCU) += rcutree.o
index 6fc1c8af44df745bad512e02be04645984d1b5a1..4e66bf9275b03edf3c62e0e350afc5248f2b00b8 100644 (file)
@@ -452,3 +452,4 @@ bool inode_capable(const struct inode *inode, int cap)
 
        return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid);
 }
+EXPORT_SYMBOL(inode_capable);
index e0aeb32415fff53a032803edbcf96ea30398b61d..2418b6e71a854e187573ec12746481ce863e721a 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/poll.h>
 #include <linux/flex_array.h> /* used in cgroup_attach_task */
 #include <linux/kthread.h>
+#include <linux/file.h>
 
 #include <linux/atomic.h>
 
@@ -4034,8 +4035,8 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css,
        struct cgroup_event *event;
        struct cgroup_subsys_state *cfile_css;
        unsigned int efd, cfd;
-       struct file *efile;
-       struct file *cfile;
+       struct fefile;
+       struct fcfile;
        char *endp;
        int ret;
 
@@ -4058,31 +4059,31 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css,
        init_waitqueue_func_entry(&event->wait, cgroup_event_wake);
        INIT_WORK(&event->remove, cgroup_event_remove);
 
-       efile = eventfd_fget(efd);
-       if (IS_ERR(efile)) {
-               ret = PTR_ERR(efile);
+       efile = fdget(efd);
+       if (!efile.file) {
+               ret = -EBADF;
                goto out_kfree;
        }
 
-       event->eventfd = eventfd_ctx_fileget(efile);
+       event->eventfd = eventfd_ctx_fileget(efile.file);
        if (IS_ERR(event->eventfd)) {
                ret = PTR_ERR(event->eventfd);
                goto out_put_efile;
        }
 
-       cfile = fget(cfd);
-       if (!cfile) {
+       cfile = fdget(cfd);
+       if (!cfile.file) {
                ret = -EBADF;
                goto out_put_eventfd;
        }
 
        /* the process need read permission on control file */
        /* AV: shouldn't we check that it's been opened for read instead? */
-       ret = inode_permission(file_inode(cfile), MAY_READ);
+       ret = inode_permission(file_inode(cfile.file), MAY_READ);
        if (ret < 0)
                goto out_put_cfile;
 
-       event->cft = __file_cft(cfile);
+       event->cft = __file_cft(cfile.file);
        if (IS_ERR(event->cft)) {
                ret = PTR_ERR(event->cft);
                goto out_put_cfile;
@@ -4103,7 +4104,7 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css,
 
        ret = -EINVAL;
        event->css = cgroup_css(cgrp, event->cft->ss);
-       cfile_css = css_from_dir(cfile->f_dentry->d_parent, event->cft->ss);
+       cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, event->cft->ss);
        if (event->css && event->css == cfile_css && css_tryget(event->css))
                ret = 0;
 
@@ -4121,25 +4122,25 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css,
        if (ret)
                goto out_put_css;
 
-       efile->f_op->poll(efile, &event->pt);
+       efile.file->f_op->poll(efile.file, &event->pt);
 
        spin_lock(&cgrp->event_list_lock);
        list_add(&event->list, &cgrp->event_list);
        spin_unlock(&cgrp->event_list_lock);
 
-       fput(cfile);
-       fput(efile);
+       fdput(cfile);
+       fdput(efile);
 
        return 0;
 
 out_put_css:
        css_put(event->css);
 out_put_cfile:
-       fput(cfile);
+       fdput(cfile);
 out_put_eventfd:
        eventfd_ctx_put(event->eventfd);
 out_put_efile:
-       fput(efile);
+       fdput(efile);
 out_kfree:
        kfree(event);
 
index 2207efc941d1da66efe03d0db33f40e6b4670307..dd236b66ca3a8ef894386e7dcb8c7f02dbba34ae 100644 (file)
@@ -5039,6 +5039,7 @@ static void perf_event_mmap_output(struct perf_event *event,
                mmap_event->event_id.header.size += sizeof(mmap_event->maj);
                mmap_event->event_id.header.size += sizeof(mmap_event->min);
                mmap_event->event_id.header.size += sizeof(mmap_event->ino);
+               mmap_event->event_id.header.size += sizeof(mmap_event->ino_generation);
        }
 
        perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
index f3569747d6295043ca3c8a853361a48c2ecf2869..ad8e1bdca70e4c702ff5c6e86255dc74a8b98259 100644 (file)
@@ -1682,12 +1682,10 @@ static bool handle_trampoline(struct pt_regs *regs)
                tmp = ri;
                ri = ri->next;
                kfree(tmp);
+               utask->depth--;
 
                if (!chained)
                        break;
-
-               utask->depth--;
-
                BUG_ON(!ri);
        }
 
index 67460b93b1a1cb8d60294cd90c2972ab97fd80e8..832cb28105bbb7900a6c1342a095179303734215 100644 (file)
@@ -41,7 +41,7 @@ u32 __initdata main_extable_sort_needed = 1;
 /* Sort the kernel's built-in exception table */
 void __init sort_main_extable(void)
 {
-       if (main_extable_sort_needed) {
+       if (main_extable_sort_needed && __stop___ex_table > __start___ex_table) {
                pr_notice("Sorting __ex_table...\n");
                sort_extable(__start___ex_table, __stop___ex_table);
        }
index c9eaf20130021fbe3c8b24f4634ff7cd0ef02c3f..086fe73ad6bde5b1ac1703f29f3d9f154878968b 100644 (file)
@@ -351,7 +351,6 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
        struct rb_node **rb_link, *rb_parent;
        int retval;
        unsigned long charge;
-       struct mempolicy *pol;
 
        uprobe_start_dup_mmap();
        down_write(&oldmm->mmap_sem);
@@ -400,11 +399,9 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
                        goto fail_nomem;
                *tmp = *mpnt;
                INIT_LIST_HEAD(&tmp->anon_vma_chain);
-               pol = mpol_dup(vma_policy(mpnt));
-               retval = PTR_ERR(pol);
-               if (IS_ERR(pol))
+               retval = vma_dup_policy(mpnt, tmp);
+               if (retval)
                        goto fail_nomem_policy;
-               vma_set_policy(tmp, pol);
                tmp->vm_mm = mm;
                if (anon_vma_fork(tmp, mpnt))
                        goto fail_nomem_anon_vma_fork;
@@ -472,7 +469,7 @@ out:
        uprobe_end_dup_mmap();
        return retval;
 fail_nomem_anon_vma_fork:
-       mpol_put(pol);
+       mpol_put(vma_policy(tmp));
 fail_nomem_policy:
        kmem_cache_free(vm_area_cachep, tmp);
 fail_nomem:
@@ -522,7 +519,7 @@ static void mm_init_aio(struct mm_struct *mm)
 {
 #ifdef CONFIG_AIO
        spin_lock_init(&mm->ioctx_lock);
-       INIT_HLIST_HEAD(&mm->ioctx_list);
+       mm->ioctx_table = NULL;
 #endif
 }
 
@@ -1173,13 +1170,16 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                return ERR_PTR(-EINVAL);
 
        /*
-        * If the new process will be in a different pid namespace
-        * don't allow the creation of threads.
+        * If the new process will be in a different pid or user namespace
+        * do not allow it to share a thread group or signal handlers or
+        * parent with the forking task.
         */
-       if ((clone_flags & (CLONE_VM|CLONE_NEWPID)) &&
-           (task_active_pid_ns(current) !=
-            current->nsproxy->pid_ns_for_children))
-               return ERR_PTR(-EINVAL);
+       if (clone_flags & (CLONE_SIGHAND | CLONE_PARENT)) {
+               if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) ||
+                   (task_active_pid_ns(current) !=
+                               current->nsproxy->pid_ns_for_children))
+                       return ERR_PTR(-EINVAL);
+       }
 
        retval = security_task_create(clone_flags);
        if (retval)
@@ -1575,15 +1575,6 @@ long do_fork(unsigned long clone_flags,
        int trace = 0;
        long nr;
 
-       /*
-        * Do some preliminary argument and permissions checking before we
-        * actually start allocating stuff
-        */
-       if (clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) {
-               if (clone_flags & (CLONE_THREAD|CLONE_PARENT))
-                       return -EINVAL;
-       }
-
        /*
         * Determine whether and which event to report to ptracer.  When
         * called from kernel_thread or CLONE_UNTRACED is explicitly
index 9bd0934f6c33b31a3432b4d0e4adab9790ed0a6c..7a7d2ee96d42c477289c34c4de79647285958319 100644 (file)
@@ -74,7 +74,7 @@ static int __init gcov_persist_setup(char *str)
 {
        unsigned long val;
 
-       if (strict_strtoul(str, 0, &val)) {
+       if (kstrtoul(str, 0, &val)) {
                pr_warning("invalid gcov_persist parameter '%s'\n", str);
                return 0;
        }
index d1a758bc972afcb3f7c0103de781fa5720bea126..4a1fef09f658b894ea5eef6a55cff8f55b97dd0e 100644 (file)
@@ -1,15 +1,4 @@
-# Select this to activate the generic irq options below
-config HAVE_GENERIC_HARDIRQS
-       bool
-
-if HAVE_GENERIC_HARDIRQS
 menu "IRQ subsystem"
-#
-# Interrupt subsystem related configuration options
-#
-config GENERIC_HARDIRQS
-       def_bool y
-
 # Options selectable by the architecture code
 
 # Make sparse irq Kconfig switch below available
@@ -84,4 +73,3 @@ config SPARSE_IRQ
          If you don't know what to do here, say N.
 
 endmenu
-endif
index 59f7b55ba7453d4b406d0c066e5f6be5cea7037c..2a74f307c5ec57b050ceeb8a21341f8a394841ef 100644 (file)
@@ -1474,11 +1474,8 @@ static int __init __parse_crashkernel(char *cmdline,
        if (first_colon && (!first_space || first_colon < first_space))
                return parse_crashkernel_mem(ck_cmdline, system_ram,
                                crash_size, crash_base);
-       else
-               return parse_crashkernel_simple(ck_cmdline, crash_size,
-                               crash_base);
 
-       return 0;
+       return parse_crashkernel_simple(ck_cmdline, crash_size, crash_base);
 }
 
 /*
index 6e33498d665c3caa35ac764a46dd27c7cec80685..a0d367a49122ea39ddb060c7a2a2ecd60855e6f9 100644 (file)
@@ -112,6 +112,7 @@ static struct kprobe_blackpoint kprobe_blacklist[] = {
 struct kprobe_insn_page {
        struct list_head list;
        kprobe_opcode_t *insns;         /* Page of instruction slots */
+       struct kprobe_insn_cache *cache;
        int nused;
        int ngarbage;
        char slot_used[];
@@ -121,12 +122,6 @@ struct kprobe_insn_page {
        (offsetof(struct kprobe_insn_page, slot_used) + \
         (sizeof(char) * (slots)))
 
-struct kprobe_insn_cache {
-       struct list_head pages; /* list of kprobe_insn_page */
-       size_t insn_size;       /* size of instruction slot */
-       int nr_garbage;
-};
-
 static int slots_per_page(struct kprobe_insn_cache *c)
 {
        return PAGE_SIZE/(c->insn_size * sizeof(kprobe_opcode_t));
@@ -138,8 +133,20 @@ enum kprobe_slot_state {
        SLOT_USED = 2,
 };
 
-static DEFINE_MUTEX(kprobe_insn_mutex);        /* Protects kprobe_insn_slots */
-static struct kprobe_insn_cache kprobe_insn_slots = {
+static void *alloc_insn_page(void)
+{
+       return module_alloc(PAGE_SIZE);
+}
+
+static void free_insn_page(void *page)
+{
+       module_free(NULL, page);
+}
+
+struct kprobe_insn_cache kprobe_insn_slots = {
+       .mutex = __MUTEX_INITIALIZER(kprobe_insn_slots.mutex),
+       .alloc = alloc_insn_page,
+       .free = free_insn_page,
        .pages = LIST_HEAD_INIT(kprobe_insn_slots.pages),
        .insn_size = MAX_INSN_SIZE,
        .nr_garbage = 0,
@@ -150,10 +157,12 @@ static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c);
  * __get_insn_slot() - Find a slot on an executable page for an instruction.
  * We allocate an executable page if there's no room on existing ones.
  */
-static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
+kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
 {
        struct kprobe_insn_page *kip;
+       kprobe_opcode_t *slot = NULL;
 
+       mutex_lock(&c->mutex);
  retry:
        list_for_each_entry(kip, &c->pages, list) {
                if (kip->nused < slots_per_page(c)) {
@@ -162,7 +171,8 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
                                if (kip->slot_used[i] == SLOT_CLEAN) {
                                        kip->slot_used[i] = SLOT_USED;
                                        kip->nused++;
-                                       return kip->insns + (i * c->insn_size);
+                                       slot = kip->insns + (i * c->insn_size);
+                                       goto out;
                                }
                        }
                        /* kip->nused is broken. Fix it. */
@@ -178,37 +188,29 @@ static kprobe_opcode_t __kprobes *__get_insn_slot(struct kprobe_insn_cache *c)
        /* All out of space.  Need to allocate a new page. */
        kip = kmalloc(KPROBE_INSN_PAGE_SIZE(slots_per_page(c)), GFP_KERNEL);
        if (!kip)
-               return NULL;
+               goto out;
 
        /*
         * Use module_alloc so this page is within +/- 2GB of where the
         * kernel image and loaded module images reside. This is required
         * so x86_64 can correctly handle the %rip-relative fixups.
         */
-       kip->insns = module_alloc(PAGE_SIZE);
+       kip->insns = c->alloc();
        if (!kip->insns) {
                kfree(kip);
-               return NULL;
+               goto out;
        }
        INIT_LIST_HEAD(&kip->list);
        memset(kip->slot_used, SLOT_CLEAN, slots_per_page(c));
        kip->slot_used[0] = SLOT_USED;
        kip->nused = 1;
        kip->ngarbage = 0;
+       kip->cache = c;
        list_add(&kip->list, &c->pages);
-       return kip->insns;
-}
-
-
-kprobe_opcode_t __kprobes *get_insn_slot(void)
-{
-       kprobe_opcode_t *ret = NULL;
-
-       mutex_lock(&kprobe_insn_mutex);
-       ret = __get_insn_slot(&kprobe_insn_slots);
-       mutex_unlock(&kprobe_insn_mutex);
-
-       return ret;
+       slot = kip->insns;
+out:
+       mutex_unlock(&c->mutex);
+       return slot;
 }
 
 /* Return 1 if all garbages are collected, otherwise 0. */
@@ -225,7 +227,7 @@ static int __kprobes collect_one_slot(struct kprobe_insn_page *kip, int idx)
                 */
                if (!list_is_singular(&kip->list)) {
                        list_del(&kip->list);
-                       module_free(NULL, kip->insns);
+                       kip->cache->free(kip->insns);
                        kfree(kip);
                }
                return 1;
@@ -255,11 +257,12 @@ static int __kprobes collect_garbage_slots(struct kprobe_insn_cache *c)
        return 0;
 }
 
-static void __kprobes __free_insn_slot(struct kprobe_insn_cache *c,
-                                      kprobe_opcode_t *slot, int dirty)
+void __kprobes __free_insn_slot(struct kprobe_insn_cache *c,
+                               kprobe_opcode_t *slot, int dirty)
 {
        struct kprobe_insn_page *kip;
 
+       mutex_lock(&c->mutex);
        list_for_each_entry(kip, &c->pages, list) {
                long idx = ((long)slot - (long)kip->insns) /
                                (c->insn_size * sizeof(kprobe_opcode_t));
@@ -272,45 +275,25 @@ static void __kprobes __free_insn_slot(struct kprobe_insn_cache *c,
                                        collect_garbage_slots(c);
                        } else
                                collect_one_slot(kip, idx);
-                       return;
+                       goto out;
                }
        }
        /* Could not free this slot. */
        WARN_ON(1);
+out:
+       mutex_unlock(&c->mutex);
 }
 
-void __kprobes free_insn_slot(kprobe_opcode_t * slot, int dirty)
-{
-       mutex_lock(&kprobe_insn_mutex);
-       __free_insn_slot(&kprobe_insn_slots, slot, dirty);
-       mutex_unlock(&kprobe_insn_mutex);
-}
 #ifdef CONFIG_OPTPROBES
 /* For optimized_kprobe buffer */
-static DEFINE_MUTEX(kprobe_optinsn_mutex); /* Protects kprobe_optinsn_slots */
-static struct kprobe_insn_cache kprobe_optinsn_slots = {
+struct kprobe_insn_cache kprobe_optinsn_slots = {
+       .mutex = __MUTEX_INITIALIZER(kprobe_optinsn_slots.mutex),
+       .alloc = alloc_insn_page,
+       .free = free_insn_page,
        .pages = LIST_HEAD_INIT(kprobe_optinsn_slots.pages),
        /* .insn_size is initialized later */
        .nr_garbage = 0,
 };
-/* Get a slot for optimized_kprobe buffer */
-kprobe_opcode_t __kprobes *get_optinsn_slot(void)
-{
-       kprobe_opcode_t *ret = NULL;
-
-       mutex_lock(&kprobe_optinsn_mutex);
-       ret = __get_insn_slot(&kprobe_optinsn_slots);
-       mutex_unlock(&kprobe_optinsn_mutex);
-
-       return ret;
-}
-
-void __kprobes free_optinsn_slot(kprobe_opcode_t * slot, int dirty)
-{
-       mutex_lock(&kprobe_optinsn_mutex);
-       __free_insn_slot(&kprobe_optinsn_slots, slot, dirty);
-       mutex_unlock(&kprobe_optinsn_mutex);
-}
 #endif
 #endif
 
index 6ada93c23a9ac55e0c5aaebe9fcd98c05f2c84dd..9659d38e008f7f4e35ed4fcfb9a866f61f00c72f 100644 (file)
@@ -113,7 +113,7 @@ static ssize_t kexec_crash_size_store(struct kobject *kobj,
        unsigned long cnt;
        int ret;
 
-       if (strict_strtoul(buf, 0, &cnt))
+       if (kstrtoul(buf, 0, &cnt))
                return -EINVAL;
 
        ret = crash_shrink_memory(cnt);
index 2b6e69909c394440b015e771ff0f3f4eab1a1a28..7cbd4507a7e628bdd05d432e1fb72a90f5107bbd 100644 (file)
 
 struct key *modsign_keyring;
 
-extern __initdata const u8 modsign_certificate_list[];
-extern __initdata const u8 modsign_certificate_list_end[];
+extern __initconst const u8 modsign_certificate_list[];
+extern __initconst const u8 modsign_certificate_list_end[];
 
 /*
  * We need to make sure ccache doesn't cache the .o file as it doesn't notice
  * if modsign.pub changes.
  */
-static __initdata const char annoy_ccache[] = __TIME__ "foo";
+static __initconst const char annoy_ccache[] = __TIME__ "foo";
 
 /*
  * Load the compiled-in keys
index 8018646005144c4082da694b331a1f44964134d6..b6c482ccc5db77f4af0afbb0948ff0373bb094d5 100644 (file)
@@ -123,10 +123,14 @@ void panic(const char *fmt, ...)
         */
        smp_send_stop();
 
-       kmsg_dump(KMSG_DUMP_PANIC);
-
+       /*
+        * Run any panic handlers, including those that might need to
+        * add information to the kmsg dump output.
+        */
        atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
 
+       kmsg_dump(KMSG_DUMP_PANIC);
+
        bust_spinlocks(0);
 
        if (!panic_blink)
index 501bde4f3bee1476e1b0b293dda516dc815da680..81c4e78c8f4cc0b79b89086c3255934079082380 100644 (file)
@@ -253,13 +253,13 @@ int parse_args(const char *doing,
        EXPORT_SYMBOL(param_ops_##name)
 
 
-STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", unsigned long, strict_strtoul);
-STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
-STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul);
-STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol);
-STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
-STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
-STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
+STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", unsigned long, kstrtoul);
+STANDARD_PARAM_DEF(short, short, "%hi", long, kstrtoul);
+STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, kstrtoul);
+STANDARD_PARAM_DEF(int, int, "%i", long, kstrtoul);
+STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, kstrtoul);
+STANDARD_PARAM_DEF(long, long, "%li", long, kstrtoul);
+STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, kstrtoul);
 
 int param_set_charp(const char *val, const struct kernel_param *kp)
 {
index 3085e62a80a5cea43a857cb7b28c50237f71fe39..c9c759d5a15cbd53831bdf7552dc455a64a40b5b 100644 (file)
@@ -644,22 +644,23 @@ int hibernate(void)
        if (error)
                goto Exit;
 
-       /* Allocate memory management structures */
-       error = create_basic_memory_bitmaps();
-       if (error)
-               goto Exit;
-
        printk(KERN_INFO "PM: Syncing filesystems ... ");
        sys_sync();
        printk("done.\n");
 
        error = freeze_processes();
        if (error)
-               goto Free_bitmaps;
+               goto Exit;
+
+       lock_device_hotplug();
+       /* Allocate memory management structures */
+       error = create_basic_memory_bitmaps();
+       if (error)
+               goto Thaw;
 
        error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
        if (error || freezer_test_done)
-               goto Thaw;
+               goto Free_bitmaps;
 
        if (in_suspend) {
                unsigned int flags = 0;
@@ -682,14 +683,14 @@ int hibernate(void)
                pr_debug("PM: Image restored successfully.\n");
        }
 
+ Free_bitmaps:
+       free_basic_memory_bitmaps();
  Thaw:
+       unlock_device_hotplug();
        thaw_processes();
 
        /* Don't bother checking whether freezer_test_done is true */
        freezer_test_done = false;
-
- Free_bitmaps:
-       free_basic_memory_bitmaps();
  Exit:
        pm_notifier_call_chain(PM_POST_HIBERNATION);
        pm_restore_console();
@@ -806,21 +807,20 @@ static int software_resume(void)
        pm_prepare_console();
        error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
        if (error)
-               goto close_finish;
-
-       error = create_basic_memory_bitmaps();
-       if (error)
-               goto close_finish;
+               goto Close_Finish;
 
        pr_debug("PM: Preparing processes for restore.\n");
        error = freeze_processes();
-       if (error) {
-               swsusp_close(FMODE_READ);
-               goto Done;
-       }
+       if (error)
+               goto Close_Finish;
 
        pr_debug("PM: Loading hibernation image.\n");
 
+       lock_device_hotplug();
+       error = create_basic_memory_bitmaps();
+       if (error)
+               goto Thaw;
+
        error = swsusp_read(&flags);
        swsusp_close(FMODE_READ);
        if (!error)
@@ -828,9 +828,10 @@ static int software_resume(void)
 
        printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
        swsusp_free();
-       thaw_processes();
- Done:
        free_basic_memory_bitmaps();
+ Thaw:
+       unlock_device_hotplug();
+       thaw_processes();
  Finish:
        pm_notifier_call_chain(PM_POST_RESTORE);
        pm_restore_console();
@@ -840,7 +841,7 @@ static int software_resume(void)
        mutex_unlock(&pm_mutex);
        pr_debug("PM: Hibernation image not present or could not be loaded.\n");
        return error;
-close_finish:
+ Close_Finish:
        swsusp_close(FMODE_READ);
        goto Finish;
 }
index 349587bb03e1edb64dc5609eee61fdf90a517af0..358a146fd4dacda5462f5ef29a8f797c91868c71 100644 (file)
@@ -352,7 +352,7 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
                struct mem_extent *ext, *cur, *aux;
 
                zone_start = zone->zone_start_pfn;
-               zone_end = zone->zone_start_pfn + zone->spanned_pages;
+               zone_end = zone_end_pfn(zone);
 
                list_for_each_entry(ext, list, hook)
                        if (zone_start <= ext->end)
@@ -884,7 +884,7 @@ static unsigned int count_highmem_pages(void)
                        continue;
 
                mark_free_pages(zone);
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
+               max_zone_pfn = zone_end_pfn(zone);
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (saveable_highmem_page(zone, pfn))
                                n++;
@@ -948,7 +948,7 @@ static unsigned int count_data_pages(void)
                        continue;
 
                mark_free_pages(zone);
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
+               max_zone_pfn = zone_end_pfn(zone);
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (saveable_page(zone, pfn))
                                n++;
@@ -1041,7 +1041,7 @@ copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
                unsigned long max_zone_pfn;
 
                mark_free_pages(zone);
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
+               max_zone_pfn = zone_end_pfn(zone);
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (page_is_saveable(zone, pfn))
                                memory_bm_set_bit(orig_bm, pfn);
@@ -1093,7 +1093,7 @@ void swsusp_free(void)
        unsigned long pfn, max_zone_pfn;
 
        for_each_populated_zone(zone) {
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
+               max_zone_pfn = zone_end_pfn(zone);
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (pfn_valid(pfn)) {
                                struct page *page = pfn_to_page(pfn);
@@ -1755,7 +1755,7 @@ static int mark_unsafe_pages(struct memory_bitmap *bm)
 
        /* Clear page flags */
        for_each_populated_zone(zone) {
-               max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;
+               max_zone_pfn = zone_end_pfn(zone);
                for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
                        if (pfn_valid(pfn))
                                swsusp_unset_page_free(pfn_to_page(pfn));
index 4ed81e74f86fbb2a9d7b0ab8e7d105d0944763c0..72e8f4fd616dee0cec880d442e33127602601f6c 100644 (file)
@@ -60,11 +60,6 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                error = -ENOSYS;
                goto Unlock;
        }
-       if(create_basic_memory_bitmaps()) {
-               atomic_inc(&snapshot_device_available);
-               error = -ENOMEM;
-               goto Unlock;
-       }
        nonseekable_open(inode, filp);
        data = &snapshot_state;
        filp->private_data = data;
@@ -90,10 +85,9 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                if (error)
                        pm_notifier_call_chain(PM_POST_RESTORE);
        }
-       if (error) {
-               free_basic_memory_bitmaps();
+       if (error)
                atomic_inc(&snapshot_device_available);
-       }
+
        data->frozen = 0;
        data->ready = 0;
        data->platform_support = 0;
@@ -111,11 +105,11 @@ static int snapshot_release(struct inode *inode, struct file *filp)
        lock_system_sleep();
 
        swsusp_free();
-       free_basic_memory_bitmaps();
        data = filp->private_data;
        free_all_swap_pages(data->swap);
        if (data->frozen) {
                pm_restore_gfp_mask();
+               free_basic_memory_bitmaps();
                thaw_processes();
        }
        pm_notifier_call_chain(data->mode == O_RDONLY ?
@@ -207,6 +201,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
        if (!mutex_trylock(&pm_mutex))
                return -EBUSY;
 
+       lock_device_hotplug();
        data = filp->private_data;
 
        switch (cmd) {
@@ -220,14 +215,22 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
                printk("done.\n");
 
                error = freeze_processes();
-               if (!error)
+               if (error)
+                       break;
+
+               error = create_basic_memory_bitmaps();
+               if (error)
+                       thaw_processes();
+               else
                        data->frozen = 1;
+
                break;
 
        case SNAPSHOT_UNFREEZE:
                if (!data->frozen || data->ready)
                        break;
                pm_restore_gfp_mask();
+               free_basic_memory_bitmaps();
                thaw_processes();
                data->frozen = 0;
                break;
@@ -371,6 +374,7 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
 
        }
 
+       unlock_device_hotplug();
        mutex_unlock(&pm_mutex);
 
        return error;
index a146ee327f6ac15029b64424f0abd07e8d316f67..dd562e9aa2c8419b02067c4883c674989a694cd2 100644 (file)
@@ -236,7 +236,7 @@ static int __ptrace_may_access(struct task_struct *task, unsigned int mode)
         */
        int dumpable = 0;
        /* Don't let security modules deny introspection */
-       if (task == current)
+       if (same_thread_group(task, current))
                return 0;
        rcu_read_lock();
        tcred = __task_cred(task);
index 33eb4620aa1716c9010432ef0a63db53afbcf82e..b02a339836b43d59dbd273efdb77d423b84ea90b 100644 (file)
@@ -122,7 +122,7 @@ struct lockdep_map rcu_sched_lock_map =
        STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key);
 EXPORT_SYMBOL_GPL(rcu_sched_lock_map);
 
-int debug_lockdep_rcu_enabled(void)
+int notrace debug_lockdep_rcu_enabled(void)
 {
        return rcu_scheduler_active && debug_locks &&
               current->lockdep_recursion == 0;
index ff55247e7049aeaf08fcf2d058ef6e5d5d20d76b..4aa8a305aedeb23cf7ad15aa2750898057b3c0d4 100644 (file)
@@ -17,8 +17,8 @@
 void res_counter_init(struct res_counter *counter, struct res_counter *parent)
 {
        spin_lock_init(&counter->lock);
-       counter->limit = RESOURCE_MAX;
-       counter->soft_limit = RESOURCE_MAX;
+       counter->limit = RES_COUNTER_MAX;
+       counter->soft_limit = RES_COUNTER_MAX;
        counter->parent = parent;
 }
 
@@ -178,23 +178,30 @@ u64 res_counter_read_u64(struct res_counter *counter, int member)
 #endif
 
 int res_counter_memparse_write_strategy(const char *buf,
-                                       unsigned long long *res)
+                                       unsigned long long *resp)
 {
        char *end;
+       unsigned long long res;
 
-       /* return RESOURCE_MAX(unlimited) if "-1" is specified */
+       /* return RES_COUNTER_MAX(unlimited) if "-1" is specified */
        if (*buf == '-') {
-               *res = simple_strtoull(buf + 1, &end, 10);
-               if (*res != 1 || *end != '\0')
+               res = simple_strtoull(buf + 1, &end, 10);
+               if (res != 1 || *end != '\0')
                        return -EINVAL;
-               *res = RESOURCE_MAX;
+               *resp = RES_COUNTER_MAX;
                return 0;
        }
 
-       *res = memparse(buf, &end);
+       res = memparse(buf, &end);
        if (*end != '\0')
                return -EINVAL;
 
-       *res = PAGE_ALIGN(*res);
+       if (PAGE_ALIGN(res) >= res)
+               res = PAGE_ALIGN(res);
+       else
+               res = RES_COUNTER_MAX;
+
+       *resp = res;
+
        return 0;
 }
index e076bddd4c66f4a007db513954c3f41240525fe2..196559994f7ce33e210f3a290043ed5862950ec6 100644 (file)
@@ -124,7 +124,7 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
                SEQ_printf(m, " ");
 
        SEQ_printf(m, "%15s %5d %9Ld.%06ld %9Ld %5d ",
-               p->comm, p->pid,
+               p->comm, task_pid_nr(p),
                SPLIT_NS(p->se.vruntime),
                (long long)(p->nvcsw + p->nivcsw),
                p->prio);
@@ -289,7 +289,7 @@ do {                                                                        \
        P(nr_load_updates);
        P(nr_uninterruptible);
        PN(next_balance);
-       P(curr->pid);
+       SEQ_printf(m, "  .%-30s: %ld\n", "curr->pid", (long)(task_pid_nr(rq->curr)));
        PN(clock);
        P(cpu_load[0]);
        P(cpu_load[1]);
@@ -492,7 +492,7 @@ void proc_sched_show_task(struct task_struct *p, struct seq_file *m)
 {
        unsigned long nr_switches;
 
-       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, p->pid,
+       SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, task_pid_nr(p),
                                                get_nr_threads(p));
        SEQ_printf(m,
                "---------------------------------------------------------"
index 7f0a5e6cdae0e03db16a8c8fec5bd48ba1f893af..11cd13667359862c58872a9ce6091391a1d40b86 100644 (file)
@@ -5151,7 +5151,7 @@ static int should_we_balance(struct lb_env *env)
         * First idle cpu or the first cpu(busiest) in this sched group
         * is eligible for doing load balancing at this and above domains.
         */
-       return balance_cpu != env->dst_cpu;
+       return balance_cpu == env->dst_cpu;
 }
 
 /*
@@ -5928,11 +5928,15 @@ static void task_fork_fair(struct task_struct *p)
        cfs_rq = task_cfs_rq(current);
        curr = cfs_rq->curr;
 
-       if (unlikely(task_cpu(p) != this_cpu)) {
-               rcu_read_lock();
-               __set_task_cpu(p, this_cpu);
-               rcu_read_unlock();
-       }
+       /*
+        * Not only the cpu but also the task_group of the parent might have
+        * been changed after parent->se.parent,cfs_rq were copied to
+        * child->se.parent,cfs_rq. So call __set_task_cpu() to make those
+        * of child point to valid ones.
+        */
+       rcu_read_lock();
+       __set_task_cpu(p, this_cpu);
+       rcu_read_unlock();
 
        update_curr(cfs_rq);
 
index 5aef494fc8b42471006a48c516737b93aa086fb7..c7edee71bce8915f67a3b4427b7f305696834afb 100644 (file)
@@ -104,8 +104,9 @@ static inline void sched_info_queued(struct task_struct *t)
 }
 
 /*
- * Called when a process ceases being the active-running process, either
- * voluntarily or involuntarily.  Now we can calculate how long we ran.
+ * Called when a process ceases being the active-running process involuntarily
+ * due, typically, to expiring its time slice (this may also be called when
+ * switching to the idle task).  Now we can calculate how long we ran.
  * Also, if the process is still in the TASK_RUNNING state, call
  * sched_info_queued() to mark that it has now again started waiting on
  * the runqueue.
index 50e41075ac77105fd26d190b2068929af6c4becc..ded28b91fa539586901a047c12a416b28d18c223 100644 (file)
@@ -3394,7 +3394,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig,
                new_ka.sa.sa_restorer = compat_ptr(restorer);
 #endif
                ret |= copy_from_user(&mask, &act->sa_mask, sizeof(mask));
-               ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
+               ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags);
                if (ret)
                        return -EFAULT;
                sigset_from_compat(&new_ka.sa.sa_mask, &mask);
@@ -3406,7 +3406,7 @@ COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig,
                ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), 
                               &oact->sa_handler);
                ret |= copy_to_user(&oact->sa_mask, &mask, sizeof(mask));
-               ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
+               ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags);
 #ifdef __ARCH_HAS_SA_RESTORER
                ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer),
                                &oact->sa_restorer);
index 449b707fc20ddc3439a203546354564448aacfb7..0564571dcdf726fab6832bf91417dfe2eff372fb 100644 (file)
@@ -48,10 +48,13 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
                                cpu_to_node(cpu)))
                        return notifier_from_errno(-ENOMEM);
                if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL,
-                               cpu_to_node(cpu)))
+                               cpu_to_node(cpu))) {
+                       free_cpumask_var(cfd->cpumask);
                        return notifier_from_errno(-ENOMEM);
+               }
                cfd->csd = alloc_percpu(struct call_single_data);
                if (!cfd->csd) {
+                       free_cpumask_var(cfd->cpumask_ipi);
                        free_cpumask_var(cfd->cpumask);
                        return notifier_from_errno(-ENOMEM);
                }
@@ -572,8 +575,10 @@ EXPORT_SYMBOL(on_each_cpu);
  *
  * If @wait is true, then returns once @func has returned.
  *
- * You must not call this function with disabled interrupts or
- * from a hardware interrupt handler or from a bottom half handler.
+ * You must not call this function with disabled interrupts or from a
+ * hardware interrupt handler or from a bottom half handler.  The
+ * exception is that it may be used during early boot while
+ * early_boot_irqs_disabled is set.
  */
 void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
                        void *info, bool wait)
@@ -582,9 +587,10 @@ void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func,
 
        smp_call_function_many(mask, func, info, wait);
        if (cpumask_test_cpu(cpu, mask)) {
-               local_irq_disable();
+               unsigned long flags;
+               local_irq_save(flags);
                func(info);
-               local_irq_enable();
+               local_irq_restore(flags);
        }
        put_cpu();
 }
index be3d3514c325f8aad38d62f65d2aee0393a70585..53cc09ceb0b869cf407fdc9d8195f265cce4c011 100644 (file)
@@ -876,7 +876,6 @@ int __init __weak early_irq_init(void)
        return 0;
 }
 
-#ifdef CONFIG_GENERIC_HARDIRQS
 int __init __weak arch_probe_nr_irqs(void)
 {
        return NR_IRQS_LEGACY;
@@ -886,4 +885,3 @@ int __init __weak arch_early_irq_init(void)
 {
        return 0;
 }
-#endif
index 5cdd8065a3ce32f6cecadd5a99a59a8ebc937613..4b082b5cac9eedfd7c31daef7e8dd02974eedbed 100644 (file)
 #else
 #define raw_read_can_lock(l)   read_can_lock(l)
 #define raw_write_can_lock(l)  write_can_lock(l)
+
+/*
+ * Some architectures can relax in favour of the CPU owning the lock.
+ */
+#ifndef arch_read_relax
+# define arch_read_relax(l)    cpu_relax()
+#endif
+#ifndef arch_write_relax
+# define arch_write_relax(l)   cpu_relax()
+#endif
+#ifndef arch_spin_relax
+# define arch_spin_relax(l)    cpu_relax()
+#endif
+
 /*
  * We build the __lock_function inlines here. They are too large for
  * inlining all over the place, but here is only one user per function
index 07f6fc468e1732734e7fcf5f73982a93670e4194..b2f06f3c6a3ff32ec9f8f2b92bea0c4766ac6f7d 100644 (file)
@@ -1225,7 +1225,7 @@ static struct ctl_table vm_table[] = {
                .data           = &hugepages_treat_as_movable,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = hugetlb_treat_movable_handler,
+               .proc_handler   = proc_dointvec,
        },
        {
                .procname       = "nr_overcommit_hugepages",
@@ -1471,14 +1471,14 @@ static struct ctl_table fs_table[] = {
        {
                .procname       = "inode-nr",
                .data           = &inodes_stat,
-               .maxlen         = 2*sizeof(int),
+               .maxlen         = 2*sizeof(long),
                .mode           = 0444,
                .proc_handler   = proc_nr_inodes,
        },
        {
                .procname       = "inode-state",
                .data           = &inodes_stat,
-               .maxlen         = 7*sizeof(int),
+               .maxlen         = 7*sizeof(long),
                .mode           = 0444,
                .proc_handler   = proc_nr_inodes,
        },
@@ -1508,7 +1508,7 @@ static struct ctl_table fs_table[] = {
        {
                .procname       = "dentry-state",
                .data           = &dentry_stat,
-               .maxlen         = 6*sizeof(int),
+               .maxlen         = 6*sizeof(long),
                .mode           = 0444,
                .proc_handler   = proc_nr_dentry,
        },
index 65bd3c92d6f3a14cf9db95f9ab7e22c368457661..8727032e3a6fbd6038aa4283a58cf1ce782d37f2 100644 (file)
@@ -4,6 +4,23 @@
 
 static struct callback_head work_exited; /* all we need is ->next == NULL */
 
+/**
+ * task_work_add - ask the @task to execute @work->func()
+ * @task: the task which should run the callback
+ * @work: the callback to run
+ * @notify: send the notification if true
+ *
+ * Queue @work for task_work_run() below and notify the @task if @notify.
+ * Fails if the @task is exiting/exited and thus it can't process this @work.
+ * Otherwise @work->func() will be called when the @task returns from kernel
+ * mode or exits.
+ *
+ * This is like the signal handler which runs in kernel mode, but it doesn't
+ * try to wake up the @task.
+ *
+ * RETURNS:
+ * 0 if succeeds or -ESRCH.
+ */
 int
 task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
 {
@@ -21,11 +38,22 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify)
        return 0;
 }
 
+/**
+ * task_work_cancel - cancel a pending work added by task_work_add()
+ * @task: the task which should execute the work
+ * @func: identifies the work to remove
+ *
+ * Find the last queued pending work with ->func == @func and remove
+ * it from queue.
+ *
+ * RETURNS:
+ * The found work or NULL if not found.
+ */
 struct callback_head *
 task_work_cancel(struct task_struct *task, task_work_func_t func)
 {
        struct callback_head **pprev = &task->task_works;
-       struct callback_head *work = NULL;
+       struct callback_head *work;
        unsigned long flags;
        /*
         * If cmpxchg() fails we continue without updating pprev.
@@ -35,7 +63,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
         */
        raw_spin_lock_irqsave(&task->pi_lock, flags);
        while ((work = ACCESS_ONCE(*pprev))) {
-               read_barrier_depends();
+               smp_read_barrier_depends();
                if (work->func != func)
                        pprev = &work->next;
                else if (cmpxchg(pprev, work, work->next) == work)
@@ -46,6 +74,14 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
        return work;
 }
 
+/**
+ * task_work_run - execute the works added by task_work_add()
+ *
+ * Flush the pending works. Should be used by the core kernel code.
+ * Called before the task returns to the user-mode or stops, or when
+ * it exits. In the latter case task_work_add() can no longer add the
+ * new work after task_work_run() returns.
+ */
 void task_work_run(void)
 {
        struct task_struct *task = current;
index 8f5b3b98577b797663f8057762b6248d0fae1823..bb2215174f0577332cc8924eacb440703d1414d0 100644 (file)
@@ -516,13 +516,13 @@ static void sync_cmos_clock(struct work_struct *work)
        schedule_delayed_work(&sync_cmos_work, timespec_to_jiffies(&next));
 }
 
-static void notify_cmos_timer(void)
+void ntp_notify_cmos_timer(void)
 {
        schedule_delayed_work(&sync_cmos_work, 0);
 }
 
 #else
-static inline void notify_cmos_timer(void) { }
+void ntp_notify_cmos_timer(void) { }
 #endif
 
 
@@ -687,8 +687,6 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
        if (!(time_status & STA_NANO))
                txc->time.tv_usec /= NSEC_PER_USEC;
 
-       notify_cmos_timer();
-
        return result;
 }
 
index 48b9fffabdc294a4bea16b9b78083a161e8eec42..947ba25a95a0aeb51415591ab8e19fb1a846b989 100644 (file)
@@ -1703,6 +1703,8 @@ int do_adjtimex(struct timex *txc)
        write_seqcount_end(&timekeeper_seq);
        raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
+       ntp_notify_cmos_timer();
+
        return ret;
 }
 
index a6d098c6df3f47f960004019fb48468ecea64410..03cf44ac54d3666b434a26a30bc6f7a1e34cbf56 100644 (file)
@@ -1978,12 +1978,27 @@ int __weak ftrace_arch_code_modify_post_process(void)
 
 void ftrace_modify_all_code(int command)
 {
+       int update = command & FTRACE_UPDATE_TRACE_FUNC;
+
+       /*
+        * If the ftrace_caller calls a ftrace_ops func directly,
+        * we need to make sure that it only traces functions it
+        * expects to trace. When doing the switch of functions,
+        * we need to update to the ftrace_ops_list_func first
+        * before the transition between old and new calls are set,
+        * as the ftrace_ops_list_func will check the ops hashes
+        * to make sure the ops are having the right functions
+        * traced.
+        */
+       if (update)
+               ftrace_update_ftrace_func(ftrace_ops_list_func);
+
        if (command & FTRACE_UPDATE_CALLS)
                ftrace_replace_code(1);
        else if (command & FTRACE_DISABLE_CALLS)
                ftrace_replace_code(0);
 
-       if (command & FTRACE_UPDATE_TRACE_FUNC)
+       if (update && ftrace_trace_function != ftrace_ops_list_func)
                ftrace_update_ftrace_func(ftrace_trace_function);
 
        if (command & FTRACE_START_FUNC_RET)
index 496f94d57698294966d2c0c9bd10de34854b34a5..7974ba20557d8a945111bb3b9c7c7a294cadc4fa 100644 (file)
@@ -3165,11 +3165,6 @@ static const struct file_operations show_traces_fops = {
        .llseek         = seq_lseek,
 };
 
-/*
- * Only trace on a CPU if the bitmask is set:
- */
-static cpumask_var_t tracing_cpumask;
-
 /*
  * The tracer itself will not take this lock, but still we want
  * to provide a consistent cpumask to user-space:
@@ -3186,11 +3181,12 @@ static ssize_t
 tracing_cpumask_read(struct file *filp, char __user *ubuf,
                     size_t count, loff_t *ppos)
 {
+       struct trace_array *tr = file_inode(filp)->i_private;
        int len;
 
        mutex_lock(&tracing_cpumask_update_lock);
 
-       len = cpumask_scnprintf(mask_str, count, tracing_cpumask);
+       len = cpumask_scnprintf(mask_str, count, tr->tracing_cpumask);
        if (count - len < 2) {
                count = -EINVAL;
                goto out_err;
@@ -3208,7 +3204,7 @@ static ssize_t
 tracing_cpumask_write(struct file *filp, const char __user *ubuf,
                      size_t count, loff_t *ppos)
 {
-       struct trace_array *tr = filp->private_data;
+       struct trace_array *tr = file_inode(filp)->i_private;
        cpumask_var_t tracing_cpumask_new;
        int err, cpu;
 
@@ -3228,12 +3224,12 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
                 * Increase/decrease the disabled counter if we are
                 * about to flip a bit in the cpumask:
                 */
-               if (cpumask_test_cpu(cpu, tracing_cpumask) &&
+               if (cpumask_test_cpu(cpu, tr->tracing_cpumask) &&
                                !cpumask_test_cpu(cpu, tracing_cpumask_new)) {
                        atomic_inc(&per_cpu_ptr(tr->trace_buffer.data, cpu)->disabled);
                        ring_buffer_record_disable_cpu(tr->trace_buffer.buffer, cpu);
                }
-               if (!cpumask_test_cpu(cpu, tracing_cpumask) &&
+               if (!cpumask_test_cpu(cpu, tr->tracing_cpumask) &&
                                cpumask_test_cpu(cpu, tracing_cpumask_new)) {
                        atomic_dec(&per_cpu_ptr(tr->trace_buffer.data, cpu)->disabled);
                        ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu);
@@ -3242,7 +3238,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
        arch_spin_unlock(&ftrace_max_lock);
        local_irq_enable();
 
-       cpumask_copy(tracing_cpumask, tracing_cpumask_new);
+       cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new);
 
        mutex_unlock(&tracing_cpumask_update_lock);
        free_cpumask_var(tracing_cpumask_new);
@@ -3256,9 +3252,10 @@ err_unlock:
 }
 
 static const struct file_operations tracing_cpumask_fops = {
-       .open           = tracing_open_generic,
+       .open           = tracing_open_generic_tr,
        .read           = tracing_cpumask_read,
        .write          = tracing_cpumask_write,
+       .release        = tracing_release_generic_tr,
        .llseek         = generic_file_llseek,
 };
 
@@ -5938,6 +5935,11 @@ static int new_instance_create(const char *name)
        if (!tr->name)
                goto out_free_tr;
 
+       if (!alloc_cpumask_var(&tr->tracing_cpumask, GFP_KERNEL))
+               goto out_free_tr;
+
+       cpumask_copy(tr->tracing_cpumask, cpu_all_mask);
+
        raw_spin_lock_init(&tr->start_lock);
 
        tr->current_trace = &nop_trace;
@@ -5969,6 +5971,7 @@ static int new_instance_create(const char *name)
  out_free_tr:
        if (tr->trace_buffer.buffer)
                ring_buffer_free(tr->trace_buffer.buffer);
+       free_cpumask_var(tr->tracing_cpumask);
        kfree(tr->name);
        kfree(tr);
 
@@ -6098,6 +6101,9 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
 {
        int cpu;
 
+       trace_create_file("tracing_cpumask", 0644, d_tracer,
+                         tr, &tracing_cpumask_fops);
+
        trace_create_file("trace_options", 0644, d_tracer,
                          tr, &tracing_iter_fops);
 
@@ -6147,9 +6153,6 @@ static __init int tracer_init_debugfs(void)
 
        init_tracer_debugfs(&global_trace, d_tracer);
 
-       trace_create_file("tracing_cpumask", 0644, d_tracer,
-                       &global_trace, &tracing_cpumask_fops);
-
        trace_create_file("available_tracers", 0444, d_tracer,
                        &global_trace, &show_traces_fops);
 
@@ -6371,7 +6374,7 @@ __init static int tracer_alloc_buffers(void)
        if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))
                goto out;
 
-       if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL))
+       if (!alloc_cpumask_var(&global_trace.tracing_cpumask, GFP_KERNEL))
                goto out_free_buffer_mask;
 
        /* Only allocate trace_printk buffers if a trace_printk exists */
@@ -6386,7 +6389,7 @@ __init static int tracer_alloc_buffers(void)
                ring_buf_size = 1;
 
        cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
-       cpumask_copy(tracing_cpumask, cpu_all_mask);
+       cpumask_copy(global_trace.tracing_cpumask, cpu_all_mask);
 
        raw_spin_lock_init(&global_trace.start_lock);
 
@@ -6441,7 +6444,7 @@ out_free_cpumask:
 #ifdef CONFIG_TRACER_MAX_TRACE
        free_percpu(global_trace.max_buffer.data);
 #endif
-       free_cpumask_var(tracing_cpumask);
+       free_cpumask_var(global_trace.tracing_cpumask);
 out_free_buffer_mask:
        free_cpumask_var(tracing_buffer_mask);
 out:
index fe39acd4c1aafa8655c6d8656621dcafbeb3abbf..10c86fb7a2b4674c4433d30123562608ec72c59b 100644 (file)
@@ -206,6 +206,7 @@ struct trace_array {
        struct dentry           *event_dir;
        struct list_head        systems;
        struct list_head        events;
+       cpumask_var_t           tracing_cpumask; /* only trace on set CPUs */
        int                     ref;
 };
 
index 29a7ebcfb42621d05cb9a74a7bcf291515b38461..368a4d50cc308cbe9564d4b01925b7937b0c4aba 100644 (file)
@@ -1489,12 +1489,7 @@ event_subsystem_dir(struct trace_array *tr, const char *name,
 }
 
 static int
-event_create_dir(struct dentry *parent,
-                struct ftrace_event_file *file,
-                const struct file_operations *id,
-                const struct file_operations *enable,
-                const struct file_operations *filter,
-                const struct file_operations *format)
+event_create_dir(struct dentry *parent, struct ftrace_event_file *file)
 {
        struct ftrace_event_call *call = file->event_call;
        struct trace_array *tr = file->tr;
@@ -1522,12 +1517,13 @@ event_create_dir(struct dentry *parent,
 
        if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
                trace_create_file("enable", 0644, file->dir, file,
-                                 enable);
+                                 &ftrace_enable_fops);
 
 #ifdef CONFIG_PERF_EVENTS
        if (call->event.type && call->class->reg)
                trace_create_file("id", 0444, file->dir,
-                                 (void *)(long)call->event.type, id);
+                                 (void *)(long)call->event.type,
+                                 &ftrace_event_id_fops);
 #endif
 
        /*
@@ -1544,10 +1540,10 @@ event_create_dir(struct dentry *parent,
                }
        }
        trace_create_file("filter", 0644, file->dir, call,
-                         filter);
+                         &ftrace_event_filter_fops);
 
        trace_create_file("format", 0444, file->dir, call,
-                         format);
+                         &ftrace_event_format_fops);
 
        return 0;
 }
@@ -1648,12 +1644,7 @@ trace_create_new_event(struct ftrace_event_call *call,
 
 /* Add an event to a trace directory */
 static int
-__trace_add_new_event(struct ftrace_event_call *call,
-                     struct trace_array *tr,
-                     const struct file_operations *id,
-                     const struct file_operations *enable,
-                     const struct file_operations *filter,
-                     const struct file_operations *format)
+__trace_add_new_event(struct ftrace_event_call *call, struct trace_array *tr)
 {
        struct ftrace_event_file *file;
 
@@ -1661,7 +1652,7 @@ __trace_add_new_event(struct ftrace_event_call *call,
        if (!file)
                return -ENOMEM;
 
-       return event_create_dir(tr->event_dir, file, id, enable, filter, format);
+       return event_create_dir(tr->event_dir, file);
 }
 
 /*
@@ -1683,8 +1674,7 @@ __trace_early_add_new_event(struct ftrace_event_call *call,
 }
 
 struct ftrace_module_file_ops;
-static void __add_event_to_tracers(struct ftrace_event_call *call,
-                                  struct ftrace_module_file_ops *file_ops);
+static void __add_event_to_tracers(struct ftrace_event_call *call);
 
 /* Add an additional event_call dynamically */
 int trace_add_event_call(struct ftrace_event_call *call)
@@ -1695,7 +1685,7 @@ int trace_add_event_call(struct ftrace_event_call *call)
 
        ret = __register_event(call, NULL);
        if (ret >= 0)
-               __add_event_to_tracers(call, NULL);
+               __add_event_to_tracers(call);
 
        mutex_unlock(&event_mutex);
        mutex_unlock(&trace_types_lock);
@@ -1769,100 +1759,21 @@ int trace_remove_event_call(struct ftrace_event_call *call)
 
 #ifdef CONFIG_MODULES
 
-static LIST_HEAD(ftrace_module_file_list);
-
-/*
- * Modules must own their file_operations to keep up with
- * reference counting.
- */
-struct ftrace_module_file_ops {
-       struct list_head                list;
-       struct module                   *mod;
-       struct file_operations          id;
-       struct file_operations          enable;
-       struct file_operations          format;
-       struct file_operations          filter;
-};
-
-static struct ftrace_module_file_ops *
-find_ftrace_file_ops(struct ftrace_module_file_ops *file_ops, struct module *mod)
-{
-       /*
-        * As event_calls are added in groups by module,
-        * when we find one file_ops, we don't need to search for
-        * each call in that module, as the rest should be the
-        * same. Only search for a new one if the last one did
-        * not match.
-        */
-       if (file_ops && mod == file_ops->mod)
-               return file_ops;
-
-       list_for_each_entry(file_ops, &ftrace_module_file_list, list) {
-               if (file_ops->mod == mod)
-                       return file_ops;
-       }
-       return NULL;
-}
-
-static struct ftrace_module_file_ops *
-trace_create_file_ops(struct module *mod)
-{
-       struct ftrace_module_file_ops *file_ops;
-
-       /*
-        * This is a bit of a PITA. To allow for correct reference
-        * counting, modules must "own" their file_operations.
-        * To do this, we allocate the file operations that will be
-        * used in the event directory.
-        */
-
-       file_ops = kmalloc(sizeof(*file_ops), GFP_KERNEL);
-       if (!file_ops)
-               return NULL;
-
-       file_ops->mod = mod;
-
-       file_ops->id = ftrace_event_id_fops;
-       file_ops->id.owner = mod;
-
-       file_ops->enable = ftrace_enable_fops;
-       file_ops->enable.owner = mod;
-
-       file_ops->filter = ftrace_event_filter_fops;
-       file_ops->filter.owner = mod;
-
-       file_ops->format = ftrace_event_format_fops;
-       file_ops->format.owner = mod;
-
-       list_add(&file_ops->list, &ftrace_module_file_list);
-
-       return file_ops;
-}
-
 static void trace_module_add_events(struct module *mod)
 {
-       struct ftrace_module_file_ops *file_ops = NULL;
        struct ftrace_event_call **call, **start, **end;
 
        start = mod->trace_events;
        end = mod->trace_events + mod->num_trace_events;
 
-       if (start == end)
-               return;
-
-       file_ops = trace_create_file_ops(mod);
-       if (!file_ops)
-               return;
-
        for_each_event(call, start, end) {
                __register_event(*call, mod);
-               __add_event_to_tracers(*call, file_ops);
+               __add_event_to_tracers(*call);
        }
 }
 
 static void trace_module_remove_events(struct module *mod)
 {
-       struct ftrace_module_file_ops *file_ops;
        struct ftrace_event_call *call, *p;
        bool clear_trace = false;
 
@@ -1874,16 +1785,6 @@ static void trace_module_remove_events(struct module *mod)
                        __trace_remove_event_call(call);
                }
        }
-
-       /* Now free the file_operations */
-       list_for_each_entry(file_ops, &ftrace_module_file_list, list) {
-               if (file_ops->mod == mod)
-                       break;
-       }
-       if (&file_ops->list != &ftrace_module_file_list) {
-               list_del(&file_ops->list);
-               kfree(file_ops);
-       }
        up_write(&trace_event_sem);
 
        /*
@@ -1919,67 +1820,21 @@ static int trace_module_notify(struct notifier_block *self,
        return 0;
 }
 
-static int
-__trace_add_new_mod_event(struct ftrace_event_call *call,
-                         struct trace_array *tr,
-                         struct ftrace_module_file_ops *file_ops)
-{
-       return __trace_add_new_event(call, tr,
-                                    &file_ops->id, &file_ops->enable,
-                                    &file_ops->filter, &file_ops->format);
-}
-
-#else
-static inline struct ftrace_module_file_ops *
-find_ftrace_file_ops(struct ftrace_module_file_ops *file_ops, struct module *mod)
-{
-       return NULL;
-}
-static inline int trace_module_notify(struct notifier_block *self,
-                                     unsigned long val, void *data)
-{
-       return 0;
-}
-static inline int
-__trace_add_new_mod_event(struct ftrace_event_call *call,
-                         struct trace_array *tr,
-                         struct ftrace_module_file_ops *file_ops)
-{
-       return -ENODEV;
-}
+static struct notifier_block trace_module_nb = {
+       .notifier_call = trace_module_notify,
+       .priority = 0,
+};
 #endif /* CONFIG_MODULES */
 
 /* Create a new event directory structure for a trace directory. */
 static void
 __trace_add_event_dirs(struct trace_array *tr)
 {
-       struct ftrace_module_file_ops *file_ops = NULL;
        struct ftrace_event_call *call;
        int ret;
 
        list_for_each_entry(call, &ftrace_events, list) {
-               if (call->mod) {
-                       /*
-                        * Directories for events by modules need to
-                        * keep module ref counts when opened (as we don't
-                        * want the module to disappear when reading one
-                        * of these files). The file_ops keep account of
-                        * the module ref count.
-                        */
-                       file_ops = find_ftrace_file_ops(file_ops, call->mod);
-                       if (!file_ops)
-                               continue; /* Warn? */
-                       ret = __trace_add_new_mod_event(call, tr, file_ops);
-                       if (ret < 0)
-                               pr_warning("Could not create directory for event %s\n",
-                                          call->name);
-                       continue;
-               }
-               ret = __trace_add_new_event(call, tr,
-                                           &ftrace_event_id_fops,
-                                           &ftrace_enable_fops,
-                                           &ftrace_event_filter_fops,
-                                           &ftrace_event_format_fops);
+               ret = __trace_add_new_event(call, tr);
                if (ret < 0)
                        pr_warning("Could not create directory for event %s\n",
                                   call->name);
@@ -2287,11 +2142,7 @@ __trace_early_add_event_dirs(struct trace_array *tr)
 
 
        list_for_each_entry(file, &tr->events, list) {
-               ret = event_create_dir(tr->event_dir, file,
-                                      &ftrace_event_id_fops,
-                                      &ftrace_enable_fops,
-                                      &ftrace_event_filter_fops,
-                                      &ftrace_event_format_fops);
+               ret = event_create_dir(tr->event_dir, file);
                if (ret < 0)
                        pr_warning("Could not create directory for event %s\n",
                                   file->event_call->name);
@@ -2332,29 +2183,14 @@ __trace_remove_event_dirs(struct trace_array *tr)
                remove_event_file_dir(file);
 }
 
-static void
-__add_event_to_tracers(struct ftrace_event_call *call,
-                      struct ftrace_module_file_ops *file_ops)
+static void __add_event_to_tracers(struct ftrace_event_call *call)
 {
        struct trace_array *tr;
 
-       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
-               if (file_ops)
-                       __trace_add_new_mod_event(call, tr, file_ops);
-               else
-                       __trace_add_new_event(call, tr,
-                                             &ftrace_event_id_fops,
-                                             &ftrace_enable_fops,
-                                             &ftrace_event_filter_fops,
-                                             &ftrace_event_format_fops);
-       }
+       list_for_each_entry(tr, &ftrace_trace_arrays, list)
+               __trace_add_new_event(call, tr);
 }
 
-static struct notifier_block trace_module_nb = {
-       .notifier_call = trace_module_notify,
-       .priority = 0,
-};
-
 extern struct ftrace_event_call *__start_ftrace_events[];
 extern struct ftrace_event_call *__stop_ftrace_events[];
 
@@ -2559,10 +2395,11 @@ static __init int event_trace_init(void)
        if (ret)
                return ret;
 
+#ifdef CONFIG_MODULES
        ret = register_module_notifier(&trace_module_nb);
        if (ret)
                pr_warning("Failed to register trace events module notifier\n");
-
+#endif
        return 0;
 }
 early_initcall(event_trace_memsetup);
index 8fd03657bc7d1f684279c46681519e16a1812f87..559329d9bd2fa4d9dd22f2ce31b4dcba6b5f1119 100644 (file)
@@ -200,8 +200,8 @@ extern char *__bad_type_size(void);
                #type, #name, offsetof(typeof(trace), name),            \
                sizeof(trace.name), is_signed_type(type)
 
-static
-int  __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len)
+static int __init
+__set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len)
 {
        int i;
        int pos = 0;
@@ -228,7 +228,7 @@ int  __set_enter_print_fmt(struct syscall_metadata *entry, char *buf, int len)
        return pos;
 }
 
-static int set_syscall_print_fmt(struct ftrace_event_call *call)
+static int __init set_syscall_print_fmt(struct ftrace_event_call *call)
 {
        char *print_fmt;
        int len;
@@ -253,7 +253,7 @@ static int set_syscall_print_fmt(struct ftrace_event_call *call)
        return 0;
 }
 
-static void free_syscall_print_fmt(struct ftrace_event_call *call)
+static void __init free_syscall_print_fmt(struct ftrace_event_call *call)
 {
        struct syscall_metadata *entry = call->data;
 
@@ -459,7 +459,7 @@ static void unreg_event_syscall_exit(struct ftrace_event_file *file,
        mutex_unlock(&syscall_trace_lock);
 }
 
-static int init_syscall_trace(struct ftrace_event_call *call)
+static int __init init_syscall_trace(struct ftrace_event_call *call)
 {
        int id;
        int num;
index c54c75e9faf7a68446c1a5e80f3713af0cc64117..630d72bf7e4173d2c47272ea7ce63012007ab192 100644 (file)
 int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
                                int wait)
 {
+       unsigned long flags;
+
        WARN_ON(cpu != 0);
 
-       local_irq_disable();
-       (func)(info);
-       local_irq_enable();
+       local_irq_save(flags);
+       func(info);
+       local_irq_restore(flags);
 
        return 0;
 }
 EXPORT_SYMBOL(smp_call_function_single);
+
+int on_each_cpu(smp_call_func_t func, void *info, int wait)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       func(info);
+       local_irq_restore(flags);
+       return 0;
+}
+EXPORT_SYMBOL(on_each_cpu);
+
+/*
+ * Note we still need to test the mask even for UP
+ * because we actually can get an empty mask from
+ * code that on SMP might call us without the local
+ * CPU in the mask.
+ */
+void on_each_cpu_mask(const struct cpumask *mask,
+                     smp_call_func_t func, void *info, bool wait)
+{
+       unsigned long flags;
+
+       if (cpumask_test_cpu(0, mask)) {
+               local_irq_save(flags);
+               func(info);
+               local_irq_restore(flags);
+       }
+}
+EXPORT_SYMBOL(on_each_cpu_mask);
+
+/*
+ * Preemption is disabled here to make sure the cond_func is called under the
+ * same condtions in UP and SMP.
+ */
+void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info),
+                     smp_call_func_t func, void *info, bool wait,
+                     gfp_t gfp_flags)
+{
+       unsigned long flags;
+
+       preempt_disable();
+       if (cond_func(0, info)) {
+               local_irq_save(flags);
+               func(info);
+               local_irq_restore(flags);
+       }
+       preempt_enable();
+}
+EXPORT_SYMBOL(on_each_cpu_cond);
index 444e1c12fea9cbd422ab14e025a008db8ee877af..06344d986eb9dde61f341057f431d3183301f54e 100644 (file)
@@ -597,7 +597,7 @@ endmenu # "Memory Debugging"
 
 config DEBUG_SHIRQ
        bool "Debug shared IRQ handlers"
-       depends on DEBUG_KERNEL && GENERIC_HARDIRQS
+       depends on DEBUG_KERNEL
        help
          Enable this to generate a spurious interrupt as soon as a shared
          interrupt handler is registered, and just before one is deregistered.
@@ -908,7 +908,7 @@ config LOCKDEP
        bool
        depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT
        select STACKTRACE
-       select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE
+       select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE && !ARC
        select KALLSYMS
        select KALLSYMS_ALL
 
@@ -1366,7 +1366,7 @@ config FAULT_INJECTION_STACKTRACE_FILTER
        depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT
        depends on !X86_64
        select STACKTRACE
-       select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
+       select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC
        help
          Provide stacktrace filter for fault-injection capabilities
 
@@ -1376,7 +1376,7 @@ config LATENCYTOP
        depends on DEBUG_KERNEL
        depends on STACKTRACE_SUPPORT
        depends on PROC_FS
-       select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND
+       select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC
        select KALLSYMS
        select KALLSYMS_ALL
        select STACKTRACE
@@ -1461,7 +1461,7 @@ config BACKTRACE_SELF_TEST
 
 config RBTREE_TEST
        tristate "Red-Black tree test"
-       depends on m && DEBUG_KERNEL
+       depends on DEBUG_KERNEL
        help
          A benchmark measuring the performance of the rbtree library.
          Also includes rbtree invariant checks.
index f2cb3082697cbbeb7cb033b3b0840c8e4371b0cf..f3bb2cb98adfd2a631144ecbde775f6f224bea4e 100644 (file)
@@ -13,7 +13,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
         sha1.o md5.o irq_regs.o reciprocal_div.o argv_split.o \
         proportions.o flex_proportions.o prio_heap.o ratelimit.o show_mem.o \
         is_single_threaded.o plist.o decompress.o kobject_uevent.o \
-        earlycpio.o percpu-refcount.o
+        earlycpio.o percpu-refcount.o percpu_ida.o
 
 obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
 lib-$(CONFIG_MMU) += ioremap.o
@@ -25,7 +25,8 @@ obj-y += lockref.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 \
         gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \
-        bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o
+        bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \
+        percpu_ida.o
 obj-y += string_helpers.o
 obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
 obj-y += kstrtox.o
index 5fbed5caba6e833222a62952cb4ba6e3430c053e..4f134d8907a7d03760877bfa41a3a10e7747913f 100644 (file)
@@ -8,9 +8,7 @@
  */
 
 #include <linux/cpu_rmap.h>
-#ifdef CONFIG_GENERIC_HARDIRQS
 #include <linux/interrupt.h>
-#endif
 #include <linux/export.h>
 
 /*
@@ -213,8 +211,6 @@ int cpu_rmap_update(struct cpu_rmap *rmap, u16 index,
 }
 EXPORT_SYMBOL(cpu_rmap_update);
 
-#ifdef CONFIG_GENERIC_HARDIRQS
-
 /* Glue between IRQ affinity notifiers and CPU rmaps */
 
 struct irq_glue {
@@ -309,5 +305,3 @@ int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq)
        return rc;
 }
 EXPORT_SYMBOL(irq_cpu_rmap_add);
-
-#endif /* CONFIG_GENERIC_HARDIRQS */
index 43bc5b071f9698847e66353e867c7b4771628475..dfe6ec17c0a5fa774ec34d23de696be7b99a6182 100644 (file)
 #include <linux/err.h>
 #include <linux/init.h>
 #include <crypto/hash.h>
+#include <linux/static_key.h>
 
 static struct crypto_shash *crct10dif_tfm;
+static struct static_key crct10dif_fallback __read_mostly;
 
 __u16 crc_t10dif(const unsigned char *buffer, size_t len)
 {
@@ -25,6 +27,9 @@ __u16 crc_t10dif(const unsigned char *buffer, size_t len)
        } desc;
        int err;
 
+       if (static_key_false(&crct10dif_fallback))
+               return crc_t10dif_generic(0, buffer, len);
+
        desc.shash.tfm = crct10dif_tfm;
        desc.shash.flags = 0;
        *(__u16 *)desc.ctx = 0;
@@ -39,7 +44,11 @@ EXPORT_SYMBOL(crc_t10dif);
 static int __init crc_t10dif_mod_init(void)
 {
        crct10dif_tfm = crypto_alloc_shash("crct10dif", 0, 0);
-       return PTR_RET(crct10dif_tfm);
+       if (IS_ERR(crct10dif_tfm)) {
+               static_key_slow_inc(&crct10dif_fallback);
+               crct10dif_tfm = NULL;
+       }
+       return 0;
 }
 
 static void __exit crc_t10dif_mod_fini(void)
index 072fbd8234d56f531a25dbf4a6dcb53f6463eb7d..410093dbe51cba0e430301530eb4f567abc720ee 100644 (file)
@@ -131,11 +131,14 @@ crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256])
 #endif
 
 /**
- * crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
- * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
- *     other uses, or the previous crc32 value if computing incrementally.
- * @p: pointer to buffer over which CRC is run
+ * crc32_le_generic() - Calculate bitwise little-endian Ethernet AUTODIN II
+ *                     CRC32/CRC32C
+ * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for other
+ *      uses, or the previous crc32/crc32c value if computing incrementally.
+ * @p: pointer to buffer over which CRC32/CRC32C is run
  * @len: length of buffer @p
+ * @tab: little-endian Ethernet table
+ * @polynomial: CRC32/CRC32c LE polynomial
  */
 static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p,
                                          size_t len, const u32 (*tab)[256],
@@ -201,11 +204,13 @@ EXPORT_SYMBOL(crc32_le);
 EXPORT_SYMBOL(__crc32c_le);
 
 /**
- * crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
+ * crc32_be_generic() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
  * @crc: seed value for computation.  ~0 for Ethernet, sometimes 0 for
  *     other uses, or the previous crc32 value if computing incrementally.
- * @p: pointer to buffer over which CRC is run
+ * @p: pointer to buffer over which CRC32 is run
  * @len: length of buffer @p
+ * @tab: big-endian Ethernet table
+ * @polynomial: CRC32 BE polynomial
  */
 static inline u32 __pure crc32_be_generic(u32 crc, unsigned char const *p,
                                          size_t len, const u32 (*tab)[256],
index 19ff89e34eec6b7aaec3d47b4a13aac9d6d70c1f..d619b28c456fc282d7d4c0c24db0ada6922601f6 100644 (file)
@@ -48,7 +48,7 @@ STATIC int INIT gunzip(unsigned char *buf, int len,
                out_len = 0x8000; /* 32 K */
                out_buf = malloc(out_len);
        } else {
-               out_len = 0x7fffffff; /* no limit */
+               out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */
        }
        if (!out_buf) {
                error("Out of memory while allocating output buffer");
index a163b6caef73fdc26e19f8d18ef66604a03b1cf8..4382ad77777ebcb17bc4b25fe606f4371b563a5d 100644 (file)
@@ -78,6 +78,46 @@ s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
 EXPORT_SYMBOL(div_s64_rem);
 #endif
 
+/**
+ * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder
+ * @dividend:  64bit dividend
+ * @divisor:   64bit divisor
+ * @remainder:  64bit remainder
+ *
+ * This implementation is a comparable to algorithm used by div64_u64.
+ * But this operation, which includes math for calculating the remainder,
+ * is kept distinct to avoid slowing down the div64_u64 operation on 32bit
+ * systems.
+ */
+#ifndef div64_u64_rem
+u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder)
+{
+       u32 high = divisor >> 32;
+       u64 quot;
+
+       if (high == 0) {
+               u32 rem32;
+               quot = div_u64_rem(dividend, divisor, &rem32);
+               *remainder = rem32;
+       } else {
+               int n = 1 + fls(high);
+               quot = div_u64(dividend >> n, divisor >> n);
+
+               if (quot != 0)
+                       quot--;
+
+               *remainder = dividend - quot * divisor;
+               if (*remainder >= divisor) {
+                       quot++;
+                       *remainder -= divisor;
+               }
+       }
+
+       return quot;
+}
+EXPORT_SYMBOL(div64_u64_rem);
+#endif
+
 /**
  * div64_u64 - unsigned 64bit divide with 64bit divisor
  * @dividend:  64bit dividend
index b35cfa9bc3d42d9e0303d0ec07c2c473fd64618c..26cf20be72b74013dd874abc551c3f9a412bc1b6 100644 (file)
 #include <linux/of_address.h>
 #include <linux/of_device.h>
 
+static inline size_t chunk_size(const struct gen_pool_chunk *chunk)
+{
+       return chunk->end_addr - chunk->start_addr + 1;
+}
+
 static int set_bits_ll(unsigned long *addr, unsigned long mask_to_set)
 {
        unsigned long val, nval;
@@ -182,13 +187,13 @@ int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phy
        int nbytes = sizeof(struct gen_pool_chunk) +
                                BITS_TO_LONGS(nbits) * sizeof(long);
 
-       chunk = kmalloc_node(nbytes, GFP_KERNEL | __GFP_ZERO, nid);
+       chunk = kzalloc_node(nbytes, GFP_KERNEL, nid);
        if (unlikely(chunk == NULL))
                return -ENOMEM;
 
        chunk->phys_addr = phys;
        chunk->start_addr = virt;
-       chunk->end_addr = virt + size;
+       chunk->end_addr = virt + size - 1;
        atomic_set(&chunk->avail, size);
 
        spin_lock(&pool->lock);
@@ -213,7 +218,7 @@ phys_addr_t gen_pool_virt_to_phys(struct gen_pool *pool, unsigned long addr)
 
        rcu_read_lock();
        list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
-               if (addr >= chunk->start_addr && addr < chunk->end_addr) {
+               if (addr >= chunk->start_addr && addr <= chunk->end_addr) {
                        paddr = chunk->phys_addr + (addr - chunk->start_addr);
                        break;
                }
@@ -242,7 +247,7 @@ void gen_pool_destroy(struct gen_pool *pool)
                chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
                list_del(&chunk->next_chunk);
 
-               end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+               end_bit = chunk_size(chunk) >> order;
                bit = find_next_bit(chunk->bits, end_bit, 0);
                BUG_ON(bit < end_bit);
 
@@ -283,7 +288,7 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
                if (size > atomic_read(&chunk->avail))
                        continue;
 
-               end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+               end_bit = chunk_size(chunk) >> order;
 retry:
                start_bit = pool->algo(chunk->bits, end_bit, start_bit, nbits,
                                pool->data);
@@ -330,8 +335,8 @@ void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
        nbits = (size + (1UL << order) - 1) >> order;
        rcu_read_lock();
        list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
-               if (addr >= chunk->start_addr && addr < chunk->end_addr) {
-                       BUG_ON(addr + size > chunk->end_addr);
+               if (addr >= chunk->start_addr && addr <= chunk->end_addr) {
+                       BUG_ON(addr + size - 1 > chunk->end_addr);
                        start_bit = (addr - chunk->start_addr) >> order;
                        remain = bitmap_clear_ll(chunk->bits, start_bit, nbits);
                        BUG_ON(remain);
@@ -400,7 +405,7 @@ size_t gen_pool_size(struct gen_pool *pool)
 
        rcu_read_lock();
        list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk)
-               size += chunk->end_addr - chunk->start_addr;
+               size += chunk_size(chunk);
        rcu_read_unlock();
        return size;
 }
@@ -519,7 +524,6 @@ struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order,
 /**
  * dev_get_gen_pool - Obtain the gen_pool (if any) for a device
  * @dev: device to retrieve the gen_pool from
- * @name: Optional name for the gen_pool, usually NULL
  *
  * Returns the gen_pool for the device if one is present, or NULL.
  */
index 411be80ddb46942242fb11013844219f8a5bf39c..df6839e3ce0886a481e8565f8b19d5c71c9b299a 100644 (file)
@@ -283,8 +283,8 @@ _output_error:
        return (int) (-(((char *) ip) - source));
 }
 
-int lz4_decompress(const char *src, size_t *src_len, char *dest,
-               size_t actual_dest_len)
+int lz4_decompress(const unsigned char *src, size_t *src_len,
+               unsigned char *dest, size_t actual_dest_len)
 {
        int ret = -1;
        int input_len = 0;
@@ -302,8 +302,8 @@ exit_0:
 EXPORT_SYMBOL(lz4_decompress);
 #endif
 
-int lz4_decompress_unknownoutputsize(const char *src, size_t src_len,
-               char *dest, size_t *dest_len)
+int lz4_decompress_unknownoutputsize(const unsigned char *src, size_t src_len,
+               unsigned char *dest, size_t *dest_len)
 {
        int ret = -1;
        int out_len = 0;
diff --git a/lib/percpu_ida.c b/lib/percpu_ida.c
new file mode 100644 (file)
index 0000000..bab1ba2
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * Percpu IDA library
+ *
+ * Copyright (C) 2013 Datera, Inc. Kent Overstreet
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/hardirq.h>
+#include <linux/idr.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/percpu_ida.h>
+
+/*
+ * Number of tags we move between the percpu freelist and the global freelist at
+ * a time
+ */
+#define IDA_PCPU_BATCH_MOVE    32U
+
+/* Max size of percpu freelist, */
+#define IDA_PCPU_SIZE          ((IDA_PCPU_BATCH_MOVE * 3) / 2)
+
+struct percpu_ida_cpu {
+       /*
+        * Even though this is percpu, we need a lock for tag stealing by remote
+        * CPUs:
+        */
+       spinlock_t                      lock;
+
+       /* nr_free/freelist form a stack of free IDs */
+       unsigned                        nr_free;
+       unsigned                        freelist[];
+};
+
+static inline void move_tags(unsigned *dst, unsigned *dst_nr,
+                            unsigned *src, unsigned *src_nr,
+                            unsigned nr)
+{
+       *src_nr -= nr;
+       memcpy(dst + *dst_nr, src + *src_nr, sizeof(unsigned) * nr);
+       *dst_nr += nr;
+}
+
+/*
+ * Try to steal tags from a remote cpu's percpu freelist.
+ *
+ * We first check how many percpu freelists have tags - we don't steal tags
+ * unless enough percpu freelists have tags on them that it's possible more than
+ * half the total tags could be stuck on remote percpu freelists.
+ *
+ * Then we iterate through the cpus until we find some tags - we don't attempt
+ * to find the "best" cpu to steal from, to keep cacheline bouncing to a
+ * minimum.
+ */
+static inline void steal_tags(struct percpu_ida *pool,
+                             struct percpu_ida_cpu *tags)
+{
+       unsigned cpus_have_tags, cpu = pool->cpu_last_stolen;
+       struct percpu_ida_cpu *remote;
+
+       for (cpus_have_tags = cpumask_weight(&pool->cpus_have_tags);
+            cpus_have_tags * IDA_PCPU_SIZE > pool->nr_tags / 2;
+            cpus_have_tags--) {
+               cpu = cpumask_next(cpu, &pool->cpus_have_tags);
+
+               if (cpu >= nr_cpu_ids) {
+                       cpu = cpumask_first(&pool->cpus_have_tags);
+                       if (cpu >= nr_cpu_ids)
+                               BUG();
+               }
+
+               pool->cpu_last_stolen = cpu;
+               remote = per_cpu_ptr(pool->tag_cpu, cpu);
+
+               cpumask_clear_cpu(cpu, &pool->cpus_have_tags);
+
+               if (remote == tags)
+                       continue;
+
+               spin_lock(&remote->lock);
+
+               if (remote->nr_free) {
+                       memcpy(tags->freelist,
+                              remote->freelist,
+                              sizeof(unsigned) * remote->nr_free);
+
+                       tags->nr_free = remote->nr_free;
+                       remote->nr_free = 0;
+               }
+
+               spin_unlock(&remote->lock);
+
+               if (tags->nr_free)
+                       break;
+       }
+}
+
+/*
+ * Pop up to IDA_PCPU_BATCH_MOVE IDs off the global freelist, and push them onto
+ * our percpu freelist:
+ */
+static inline void alloc_global_tags(struct percpu_ida *pool,
+                                    struct percpu_ida_cpu *tags)
+{
+       move_tags(tags->freelist, &tags->nr_free,
+                 pool->freelist, &pool->nr_free,
+                 min(pool->nr_free, IDA_PCPU_BATCH_MOVE));
+}
+
+static inline unsigned alloc_local_tag(struct percpu_ida *pool,
+                                      struct percpu_ida_cpu *tags)
+{
+       int tag = -ENOSPC;
+
+       spin_lock(&tags->lock);
+       if (tags->nr_free)
+               tag = tags->freelist[--tags->nr_free];
+       spin_unlock(&tags->lock);
+
+       return tag;
+}
+
+/**
+ * percpu_ida_alloc - allocate a tag
+ * @pool: pool to allocate from
+ * @gfp: gfp flags
+ *
+ * Returns a tag - an integer in the range [0..nr_tags) (passed to
+ * tag_pool_init()), or otherwise -ENOSPC on allocation failure.
+ *
+ * Safe to be called from interrupt context (assuming it isn't passed
+ * __GFP_WAIT, of course).
+ *
+ * @gfp indicates whether or not to wait until a free id is available (it's not
+ * used for internal memory allocations); thus if passed __GFP_WAIT we may sleep
+ * however long it takes until another thread frees an id (same semantics as a
+ * mempool).
+ *
+ * Will not fail if passed __GFP_WAIT.
+ */
+int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
+{
+       DEFINE_WAIT(wait);
+       struct percpu_ida_cpu *tags;
+       unsigned long flags;
+       int tag;
+
+       local_irq_save(flags);
+       tags = this_cpu_ptr(pool->tag_cpu);
+
+       /* Fastpath */
+       tag = alloc_local_tag(pool, tags);
+       if (likely(tag >= 0)) {
+               local_irq_restore(flags);
+               return tag;
+       }
+
+       while (1) {
+               spin_lock(&pool->lock);
+
+               /*
+                * prepare_to_wait() must come before steal_tags(), in case
+                * percpu_ida_free() on another cpu flips a bit in
+                * cpus_have_tags
+                *
+                * global lock held and irqs disabled, don't need percpu lock
+                */
+               prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
+
+               if (!tags->nr_free)
+                       alloc_global_tags(pool, tags);
+               if (!tags->nr_free)
+                       steal_tags(pool, tags);
+
+               if (tags->nr_free) {
+                       tag = tags->freelist[--tags->nr_free];
+                       if (tags->nr_free)
+                               cpumask_set_cpu(smp_processor_id(),
+                                               &pool->cpus_have_tags);
+               }
+
+               spin_unlock(&pool->lock);
+               local_irq_restore(flags);
+
+               if (tag >= 0 || !(gfp & __GFP_WAIT))
+                       break;
+
+               schedule();
+
+               local_irq_save(flags);
+               tags = this_cpu_ptr(pool->tag_cpu);
+       }
+
+       finish_wait(&pool->wait, &wait);
+       return tag;
+}
+EXPORT_SYMBOL_GPL(percpu_ida_alloc);
+
+/**
+ * percpu_ida_free - free a tag
+ * @pool: pool @tag was allocated from
+ * @tag: a tag previously allocated with percpu_ida_alloc()
+ *
+ * Safe to be called from interrupt context.
+ */
+void percpu_ida_free(struct percpu_ida *pool, unsigned tag)
+{
+       struct percpu_ida_cpu *tags;
+       unsigned long flags;
+       unsigned nr_free;
+
+       BUG_ON(tag >= pool->nr_tags);
+
+       local_irq_save(flags);
+       tags = this_cpu_ptr(pool->tag_cpu);
+
+       spin_lock(&tags->lock);
+       tags->freelist[tags->nr_free++] = tag;
+
+       nr_free = tags->nr_free;
+       spin_unlock(&tags->lock);
+
+       if (nr_free == 1) {
+               cpumask_set_cpu(smp_processor_id(),
+                               &pool->cpus_have_tags);
+               wake_up(&pool->wait);
+       }
+
+       if (nr_free == IDA_PCPU_SIZE) {
+               spin_lock(&pool->lock);
+
+               /*
+                * Global lock held and irqs disabled, don't need percpu
+                * lock
+                */
+               if (tags->nr_free == IDA_PCPU_SIZE) {
+                       move_tags(pool->freelist, &pool->nr_free,
+                                 tags->freelist, &tags->nr_free,
+                                 IDA_PCPU_BATCH_MOVE);
+
+                       wake_up(&pool->wait);
+               }
+               spin_unlock(&pool->lock);
+       }
+
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(percpu_ida_free);
+
+/**
+ * percpu_ida_destroy - release a tag pool's resources
+ * @pool: pool to free
+ *
+ * Frees the resources allocated by percpu_ida_init().
+ */
+void percpu_ida_destroy(struct percpu_ida *pool)
+{
+       free_percpu(pool->tag_cpu);
+       free_pages((unsigned long) pool->freelist,
+                  get_order(pool->nr_tags * sizeof(unsigned)));
+}
+EXPORT_SYMBOL_GPL(percpu_ida_destroy);
+
+/**
+ * percpu_ida_init - initialize a percpu tag pool
+ * @pool: pool to initialize
+ * @nr_tags: number of tags that will be available for allocation
+ *
+ * Initializes @pool so that it can be used to allocate tags - integers in the
+ * range [0, nr_tags). Typically, they'll be used by driver code to refer to a
+ * preallocated array of tag structures.
+ *
+ * Allocation is percpu, but sharding is limited by nr_tags - for best
+ * performance, the workload should not span more cpus than nr_tags / 128.
+ */
+int percpu_ida_init(struct percpu_ida *pool, unsigned long nr_tags)
+{
+       unsigned i, cpu, order;
+
+       memset(pool, 0, sizeof(*pool));
+
+       init_waitqueue_head(&pool->wait);
+       spin_lock_init(&pool->lock);
+       pool->nr_tags = nr_tags;
+
+       /* Guard against overflow */
+       if (nr_tags > (unsigned) INT_MAX + 1) {
+               pr_err("percpu_ida_init(): nr_tags too large\n");
+               return -EINVAL;
+       }
+
+       order = get_order(nr_tags * sizeof(unsigned));
+       pool->freelist = (void *) __get_free_pages(GFP_KERNEL, order);
+       if (!pool->freelist)
+               return -ENOMEM;
+
+       for (i = 0; i < nr_tags; i++)
+               pool->freelist[i] = i;
+
+       pool->nr_free = nr_tags;
+
+       pool->tag_cpu = __alloc_percpu(sizeof(struct percpu_ida_cpu) +
+                                      IDA_PCPU_SIZE * sizeof(unsigned),
+                                      sizeof(unsigned));
+       if (!pool->tag_cpu)
+               goto err;
+
+       for_each_possible_cpu(cpu)
+               spin_lock_init(&per_cpu_ptr(pool->tag_cpu, cpu)->lock);
+
+       return 0;
+err:
+       percpu_ida_destroy(pool);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(percpu_ida_init);
index e7964296fd50551020872d430009e890d0e97b5d..7811ed3b4e701c2e0d82368a8bae457279ca3246 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/string.h>
 #include <linux/bitops.h>
 #include <linux/rcupdate.h>
+#include <linux/hardirq.h>             /* in_interrupt() */
 
 
 #ifdef __KERNEL__
@@ -207,7 +208,12 @@ radix_tree_node_alloc(struct radix_tree_root *root)
        struct radix_tree_node *ret = NULL;
        gfp_t gfp_mask = root_gfp_mask(root);
 
-       if (!(gfp_mask & __GFP_WAIT)) {
+       /*
+        * Preload code isn't irq safe and it doesn't make sence to use
+        * preloading in the interrupt anyway as all the allocations have to
+        * be atomic. So just do normal allocation when in interrupt.
+        */
+       if (!(gfp_mask & __GFP_WAIT) && !in_interrupt()) {
                struct radix_tree_preload *rtp;
 
                /*
@@ -264,7 +270,7 @@ radix_tree_node_free(struct radix_tree_node *node)
  * To make use of this facility, the radix tree must be initialised without
  * __GFP_WAIT being passed to INIT_RADIX_TREE().
  */
-int radix_tree_preload(gfp_t gfp_mask)
+static int __radix_tree_preload(gfp_t gfp_mask)
 {
        struct radix_tree_preload *rtp;
        struct radix_tree_node *node;
@@ -288,8 +294,39 @@ int radix_tree_preload(gfp_t gfp_mask)
 out:
        return ret;
 }
+
+/*
+ * Load up this CPU's radix_tree_node buffer with sufficient objects to
+ * ensure that the addition of a single element in the tree cannot fail.  On
+ * success, return zero, with preemption disabled.  On error, return -ENOMEM
+ * with preemption not disabled.
+ *
+ * To make use of this facility, the radix tree must be initialised without
+ * __GFP_WAIT being passed to INIT_RADIX_TREE().
+ */
+int radix_tree_preload(gfp_t gfp_mask)
+{
+       /* Warn on non-sensical use... */
+       WARN_ON_ONCE(!(gfp_mask & __GFP_WAIT));
+       return __radix_tree_preload(gfp_mask);
+}
 EXPORT_SYMBOL(radix_tree_preload);
 
+/*
+ * The same as above function, except we don't guarantee preloading happens.
+ * We do it, if we decide it helps. On success, return zero with preemption
+ * disabled. On error, return -ENOMEM with preemption not disabled.
+ */
+int radix_tree_maybe_preload(gfp_t gfp_mask)
+{
+       if (gfp_mask & __GFP_WAIT)
+               return __radix_tree_preload(gfp_mask);
+       /* Preloading doesn't help anything with this gfp mask, skip it */
+       preempt_disable();
+       return 0;
+}
+EXPORT_SYMBOL(radix_tree_maybe_preload);
+
 /*
  *     Return the maximum key which can be store into a
  *     radix tree with height HEIGHT.
index b4625787c7eeb462d2ba220a5bf497fb522cf32c..c7dab0645554ea341590bee0ecf5b0a0139a55bd 100644 (file)
@@ -6,6 +6,7 @@ raid6_pq-y      += algos.o recov.o tables.o int1.o int2.o int4.o \
 raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o
 raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o
 raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o
+raid6_pq-$(CONFIG_TILEGX) += tilegx8.o
 
 hostprogs-y    += mktables
 
@@ -110,6 +111,11 @@ $(obj)/neon8.c:   UNROLL := 8
 $(obj)/neon8.c:   $(src)/neon.uc $(src)/unroll.awk FORCE
        $(call if_changed,unroll)
 
+targets += tilegx8.c
+$(obj)/tilegx8.c:   UNROLL := 8
+$(obj)/tilegx8.c:   $(src)/tilegx.uc $(src)/unroll.awk FORCE
+       $(call if_changed,unroll)
+
 quiet_cmd_mktable = TABLE   $@
       cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 )
 
index 74e6f5629dbc793464f402087818df6fea11ee1a..f0b1aa3586d1bdc7dd9000cbf58fd46509337f97 100644 (file)
@@ -65,6 +65,9 @@ const struct raid6_calls * const raid6_algos[] = {
        &raid6_altivec2,
        &raid6_altivec4,
        &raid6_altivec8,
+#endif
+#if defined(CONFIG_TILEGX)
+       &raid6_tilegx8,
 #endif
        &raid6_intx1,
        &raid6_intx2,
index 28afa1a06e033f264d2a9228d654e7fc50b6fea4..29090f3db677b7c311a86da1120e1ceb805b2517 100644 (file)
@@ -40,13 +40,16 @@ else ifeq ($(HAS_NEON),yes)
         OBJS   += neon.o neon1.o neon2.o neon4.o neon8.o
         CFLAGS += -DCONFIG_KERNEL_MODE_NEON=1
 else
-        HAS_ALTIVEC := $(shell echo -e '\#include <altivec.h>\nvector int a;' |\
+        HAS_ALTIVEC := $(shell printf '\#include <altivec.h>\nvector int a;\n' |\
                          gcc -c -x c - >&/dev/null && \
                          rm ./-.o && echo yes)
         ifeq ($(HAS_ALTIVEC),yes)
                 OBJS += altivec1.o altivec2.o altivec4.o altivec8.o
         endif
 endif
+ifeq ($(ARCH),tilegx)
+OBJS += tilegx8.o
+endif
 
 .c.o:
        $(CC) $(CFLAGS) -c -o $@ $<
@@ -109,11 +112,15 @@ int16.c: int.uc ../unroll.awk
 int32.c: int.uc ../unroll.awk
        $(AWK) ../unroll.awk -vN=32 < int.uc > $@
 
+tilegx8.c: tilegx.uc ../unroll.awk
+       $(AWK) ../unroll.awk -vN=8 < tilegx.uc > $@
+
 tables.c: mktables
        ./mktables > tables.c
 
 clean:
        rm -f *.o *.a mktables mktables.c *.uc int*.c altivec*.c neon*.c tables.c raid6test
+       rm -f tilegx*.c
 
 spotless: clean
        rm -f *~
diff --git a/lib/raid6/tilegx.uc b/lib/raid6/tilegx.uc
new file mode 100644 (file)
index 0000000..e7c2945
--- /dev/null
@@ -0,0 +1,86 @@
+/* -*- linux-c -*- ------------------------------------------------------- *
+ *
+ *   Copyright 2002 H. Peter Anvin - All Rights Reserved
+ *   Copyright 2012 Tilera Corporation - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
+ *   Boston MA 02111-1307, USA; either version 2 of the License, or
+ *   (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * tilegx$#.c
+ *
+ * $#-way unrolled TILE-Gx SIMD for RAID-6 math.
+ *
+ * This file is postprocessed using unroll.awk.
+ *
+ */
+
+#include <linux/raid/pq.h>
+
+/* Create 8 byte copies of constant byte */
+# define NBYTES(x) (__insn_v1addi(0, x))
+# define NSIZE  8
+
+/*
+ * The SHLBYTE() operation shifts each byte left by 1, *not*
+ * rolling over into the next byte
+ */
+static inline __attribute_const__ u64 SHLBYTE(u64 v)
+{
+       /* Vector One Byte Shift Left Immediate. */
+       return __insn_v1shli(v, 1);
+}
+
+/*
+ * The MASK() operation returns 0xFF in any byte for which the high
+ * bit is 1, 0x00 for any byte for which the high bit is 0.
+ */
+static inline __attribute_const__ u64 MASK(u64 v)
+{
+       /* Vector One Byte Shift Right Signed Immediate. */
+       return __insn_v1shrsi(v, 7);
+}
+
+
+void raid6_tilegx$#_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+       u8 **dptr = (u8 **)ptrs;
+       u64 *p, *q;
+       int d, z, z0;
+
+       u64 wd$$, wq$$, wp$$, w1$$, w2$$;
+       u64 x1d = NBYTES(0x1d);
+       u64 * z0ptr;
+
+       z0 = disks - 3;                 /* Highest data disk */
+       p = (u64 *)dptr[z0+1];  /* XOR parity */
+       q = (u64 *)dptr[z0+2];  /* RS syndrome */
+
+       z0ptr = (u64 *)&dptr[z0][0];
+       for ( d = 0 ; d < bytes ; d += NSIZE*$# ) {
+               wq$$ = wp$$ = *z0ptr++;
+               for ( z = z0-1 ; z >= 0 ; z-- ) {
+                       wd$$ = *(u64 *)&dptr[z][d+$$*NSIZE];
+                       wp$$ = wp$$ ^ wd$$;
+                       w2$$ = MASK(wq$$);
+                       w1$$ = SHLBYTE(wq$$);
+                       w2$$ = w2$$ & x1d;
+                       w1$$ = w1$$ ^ w2$$;
+                       wq$$ = w1$$ ^ wd$$;
+               }
+               *p++ = wp$$;
+               *q++ = wq$$;
+       }
+}
+
+const struct raid6_calls raid6_tilegx$# = {
+       raid6_tilegx$#_gen_syndrome,
+       NULL,
+       "tilegx$#",
+       0
+};
index c0e31fe2fabf5b99c160fb01daf618cb7c0488b3..65f4effd117f4350bb5dde964eab219f67caf701 100644 (file)
@@ -518,3 +518,43 @@ void rb_replace_node(struct rb_node *victim, struct rb_node *new,
        *new = *victim;
 }
 EXPORT_SYMBOL(rb_replace_node);
+
+static struct rb_node *rb_left_deepest_node(const struct rb_node *node)
+{
+       for (;;) {
+               if (node->rb_left)
+                       node = node->rb_left;
+               else if (node->rb_right)
+                       node = node->rb_right;
+               else
+                       return (struct rb_node *)node;
+       }
+}
+
+struct rb_node *rb_next_postorder(const struct rb_node *node)
+{
+       const struct rb_node *parent;
+       if (!node)
+               return NULL;
+       parent = rb_parent(node);
+
+       /* If we're sitting on node, we've already seen our children */
+       if (parent && node == parent->rb_left && parent->rb_right) {
+               /* If we are the parent's left node, go to the parent's right
+                * node then all the way down to the left */
+               return rb_left_deepest_node(parent->rb_right);
+       } else
+               /* Otherwise we are the parent's right node, and the parent
+                * should be next */
+               return (struct rb_node *)parent;
+}
+EXPORT_SYMBOL(rb_next_postorder);
+
+struct rb_node *rb_first_postorder(const struct rb_root *root)
+{
+       if (!root->rb_node)
+               return NULL;
+
+       return rb_left_deepest_node(root->rb_node);
+}
+EXPORT_SYMBOL(rb_first_postorder);
index 122f02f9941b5680b6fd9f14793e8806476bb634..31dd4ccd3baae800a4459088cca01ca560c3a536 100644 (file)
@@ -114,6 +114,16 @@ static int black_path_count(struct rb_node *rb)
        return count;
 }
 
+static void check_postorder(int nr_nodes)
+{
+       struct rb_node *rb;
+       int count = 0;
+       for (rb = rb_first_postorder(&root); rb; rb = rb_next_postorder(rb))
+               count++;
+
+       WARN_ON_ONCE(count != nr_nodes);
+}
+
 static void check(int nr_nodes)
 {
        struct rb_node *rb;
@@ -136,6 +146,8 @@ static void check(int nr_nodes)
 
        WARN_ON_ONCE(count != nr_nodes);
        WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root))) - 1);
+
+       check_postorder(nr_nodes);
 }
 
 static void check_augmented(int nr_nodes)
index 6cdd27043303e7473925bbc04778a43481dc2205..026771a9b0976068f64935b60c9da8526dbe7b63 100644 (file)
@@ -245,7 +245,7 @@ config COMPACTION
 config MIGRATION
        bool "Page migration"
        def_bool y
-       depends on NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION || CMA
+       depends on (NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION || CMA) && MMU
        help
          Allows the migration of the physical location of pages of processes
          while the virtual addresses are not changed. This is useful in
@@ -480,7 +480,7 @@ config FRONTSWAP
 
 config CMA
        bool "Contiguous Memory Allocator"
-       depends on HAVE_MEMBLOCK
+       depends on HAVE_MEMBLOCK && MMU
        select MIGRATION
        select MEMORY_ISOLATION
        help
index f00803386a67e4d7c98ff3d162d61c137cecf0d6..305d10acd081842fd965550b299f5e5704b04b00 100644 (file)
@@ -17,7 +17,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o fadvise.o \
                           util.o mmzone.o vmstat.o backing-dev.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
                           compaction.o balloon_compaction.o \
-                          interval_tree.o $(mmu-y)
+                          interval_tree.o list_lru.o $(mmu-y)
 
 obj-y += init-mm.o
 
index 37d9edcd14cfbbff06510be795b4a6e125b95336..ce682f7a4f29d161189f47fd7e376d69bea2359d 100644 (file)
@@ -652,7 +652,7 @@ int pdflush_proc_obsolete(struct ctl_table *table, int write,
 {
        char kbuf[] = "0\n";
 
-       if (*ppos) {
+       if (*ppos || *lenp < sizeof(kbuf)) {
                *lenp = 0;
                return 0;
        }
index 05ccb4cc0bdb984dc2613461703587ec199804cd..c43789388cd8667536bfd9644a5bbe2cd0d35f3e 100644 (file)
@@ -1131,6 +1131,9 @@ void compact_pgdat(pg_data_t *pgdat, int order)
                .sync = false,
        };
 
+       if (!order)
+               return;
+
        __compact_pgdat(pgdat, &cc);
 }
 
index 731a2c24532df32ca532184e7c714911a338dd9c..1e6aec4a2d2ebae29c0fea0405a7e81f422beeb4 100644 (file)
@@ -467,32 +467,34 @@ int add_to_page_cache_locked(struct page *page, struct address_space *mapping,
        error = mem_cgroup_cache_charge(page, current->mm,
                                        gfp_mask & GFP_RECLAIM_MASK);
        if (error)
-               goto out;
-
-       error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM);
-       if (error == 0) {
-               page_cache_get(page);
-               page->mapping = mapping;
-               page->index = offset;
+               return error;
 
-               spin_lock_irq(&mapping->tree_lock);
-               error = radix_tree_insert(&mapping->page_tree, offset, page);
-               if (likely(!error)) {
-                       mapping->nrpages++;
-                       __inc_zone_page_state(page, NR_FILE_PAGES);
-                       spin_unlock_irq(&mapping->tree_lock);
-                       trace_mm_filemap_add_to_page_cache(page);
-               } else {
-                       page->mapping = NULL;
-                       /* Leave page->index set: truncation relies upon it */
-                       spin_unlock_irq(&mapping->tree_lock);
-                       mem_cgroup_uncharge_cache_page(page);
-                       page_cache_release(page);
-               }
-               radix_tree_preload_end();
-       } else
+       error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM);
+       if (error) {
                mem_cgroup_uncharge_cache_page(page);
-out:
+               return error;
+       }
+
+       page_cache_get(page);
+       page->mapping = mapping;
+       page->index = offset;
+
+       spin_lock_irq(&mapping->tree_lock);
+       error = radix_tree_insert(&mapping->page_tree, offset, page);
+       radix_tree_preload_end();
+       if (unlikely(error))
+               goto err_insert;
+       mapping->nrpages++;
+       __inc_zone_page_state(page, NR_FILE_PAGES);
+       spin_unlock_irq(&mapping->tree_lock);
+       trace_mm_filemap_add_to_page_cache(page);
+       return 0;
+err_insert:
+       page->mapping = NULL;
+       /* Leave page->index set: truncation relies upon it */
+       spin_unlock_irq(&mapping->tree_lock);
+       mem_cgroup_uncharge_cache_page(page);
+       page_cache_release(page);
        return error;
 }
 EXPORT_SYMBOL(add_to_page_cache_locked);
@@ -1614,6 +1616,7 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct inode *inode = mapping->host;
        pgoff_t offset = vmf->pgoff;
        struct page *page;
+       bool memcg_oom;
        pgoff_t size;
        int ret = 0;
 
@@ -1622,7 +1625,11 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                return VM_FAULT_SIGBUS;
 
        /*
-        * Do we have something in the page cache already?
+        * Do we have something in the page cache already?  Either
+        * way, try readahead, but disable the memcg OOM killer for it
+        * as readahead is optional and no errors are propagated up
+        * the fault stack.  The OOM killer is enabled while trying to
+        * instantiate the faulting page individually below.
         */
        page = find_get_page(mapping, offset);
        if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) {
@@ -1630,10 +1637,14 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                 * We found the page, so try async readahead before
                 * waiting for the lock.
                 */
+               memcg_oom = mem_cgroup_toggle_oom(false);
                do_async_mmap_readahead(vma, ra, file, page, offset);
+               mem_cgroup_toggle_oom(memcg_oom);
        } else if (!page) {
                /* No page in the page cache at all */
+               memcg_oom = mem_cgroup_toggle_oom(false);
                do_sync_mmap_readahead(vma, ra, file, offset);
+               mem_cgroup_toggle_oom(memcg_oom);
                count_vm_event(PGMAJFAULT);
                mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
                ret = VM_FAULT_MAJOR;
index a92012a71702e7156baba919e636bcfcce8971f2..7489884682d84a6b5840fef19e90234076fd374e 100644 (file)
@@ -211,24 +211,29 @@ static void put_huge_zero_page(void)
        BUG_ON(atomic_dec_and_test(&huge_zero_refcount));
 }
 
-static int shrink_huge_zero_page(struct shrinker *shrink,
-               struct shrink_control *sc)
+static unsigned long shrink_huge_zero_page_count(struct shrinker *shrink,
+                                       struct shrink_control *sc)
 {
-       if (!sc->nr_to_scan)
-               /* we can free zero page only if last reference remains */
-               return atomic_read(&huge_zero_refcount) == 1 ? HPAGE_PMD_NR : 0;
+       /* we can free zero page only if last reference remains */
+       return atomic_read(&huge_zero_refcount) == 1 ? HPAGE_PMD_NR : 0;
+}
 
+static unsigned long shrink_huge_zero_page_scan(struct shrinker *shrink,
+                                      struct shrink_control *sc)
+{
        if (atomic_cmpxchg(&huge_zero_refcount, 1, 0) == 1) {
                struct page *zero_page = xchg(&huge_zero_page, NULL);
                BUG_ON(zero_page == NULL);
                __free_page(zero_page);
+               return HPAGE_PMD_NR;
        }
 
        return 0;
 }
 
 static struct shrinker huge_zero_page_shrinker = {
-       .shrink = shrink_huge_zero_page,
+       .count_objects = shrink_huge_zero_page_count,
+       .scan_objects = shrink_huge_zero_page_scan,
        .seeks = DEFAULT_SEEKS,
 };
 
@@ -417,7 +422,7 @@ static ssize_t scan_sleep_millisecs_store(struct kobject *kobj,
        unsigned long msecs;
        int err;
 
-       err = strict_strtoul(buf, 10, &msecs);
+       err = kstrtoul(buf, 10, &msecs);
        if (err || msecs > UINT_MAX)
                return -EINVAL;
 
@@ -444,7 +449,7 @@ static ssize_t alloc_sleep_millisecs_store(struct kobject *kobj,
        unsigned long msecs;
        int err;
 
-       err = strict_strtoul(buf, 10, &msecs);
+       err = kstrtoul(buf, 10, &msecs);
        if (err || msecs > UINT_MAX)
                return -EINVAL;
 
@@ -470,7 +475,7 @@ static ssize_t pages_to_scan_store(struct kobject *kobj,
        int err;
        unsigned long pages;
 
-       err = strict_strtoul(buf, 10, &pages);
+       err = kstrtoul(buf, 10, &pages);
        if (err || !pages || pages > UINT_MAX)
                return -EINVAL;
 
@@ -538,7 +543,7 @@ static ssize_t khugepaged_max_ptes_none_store(struct kobject *kobj,
        int err;
        unsigned long max_ptes_none;
 
-       err = strict_strtoul(buf, 10, &max_ptes_none);
+       err = kstrtoul(buf, 10, &max_ptes_none);
        if (err || max_ptes_none > HPAGE_PMD_NR-1)
                return -EINVAL;
 
@@ -690,11 +695,10 @@ pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma)
        return pmd;
 }
 
-static inline pmd_t mk_huge_pmd(struct page *page, struct vm_area_struct *vma)
+static inline pmd_t mk_huge_pmd(struct page *page, pgprot_t prot)
 {
        pmd_t entry;
-       entry = mk_pmd(page, vma->vm_page_prot);
-       entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
+       entry = mk_pmd(page, prot);
        entry = pmd_mkhuge(entry);
        return entry;
 }
@@ -727,7 +731,8 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm,
                pte_free(mm, pgtable);
        } else {
                pmd_t entry;
-               entry = mk_huge_pmd(page, vma);
+               entry = mk_huge_pmd(page, vma->vm_page_prot);
+               entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
                page_add_new_anon_rmap(page, vma, haddr);
                pgtable_trans_huge_deposit(mm, pmd, pgtable);
                set_pmd_at(mm, haddr, pmd, entry);
@@ -783,77 +788,57 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
 {
        struct page *page;
        unsigned long haddr = address & HPAGE_PMD_MASK;
-       pte_t *pte;
 
-       if (haddr >= vma->vm_start && haddr + HPAGE_PMD_SIZE <= vma->vm_end) {
-               if (unlikely(anon_vma_prepare(vma)))
-                       return VM_FAULT_OOM;
-               if (unlikely(khugepaged_enter(vma)))
+       if (haddr < vma->vm_start || haddr + HPAGE_PMD_SIZE > vma->vm_end)
+               return VM_FAULT_FALLBACK;
+       if (unlikely(anon_vma_prepare(vma)))
+               return VM_FAULT_OOM;
+       if (unlikely(khugepaged_enter(vma)))
+               return VM_FAULT_OOM;
+       if (!(flags & FAULT_FLAG_WRITE) &&
+                       transparent_hugepage_use_zero_page()) {
+               pgtable_t pgtable;
+               struct page *zero_page;
+               bool set;
+               pgtable = pte_alloc_one(mm, haddr);
+               if (unlikely(!pgtable))
                        return VM_FAULT_OOM;
-               if (!(flags & FAULT_FLAG_WRITE) &&
-                               transparent_hugepage_use_zero_page()) {
-                       pgtable_t pgtable;
-                       struct page *zero_page;
-                       bool set;
-                       pgtable = pte_alloc_one(mm, haddr);
-                       if (unlikely(!pgtable))
-                               return VM_FAULT_OOM;
-                       zero_page = get_huge_zero_page();
-                       if (unlikely(!zero_page)) {
-                               pte_free(mm, pgtable);
-                               count_vm_event(THP_FAULT_FALLBACK);
-                               goto out;
-                       }
-                       spin_lock(&mm->page_table_lock);
-                       set = set_huge_zero_page(pgtable, mm, vma, haddr, pmd,
-                                       zero_page);
-                       spin_unlock(&mm->page_table_lock);
-                       if (!set) {
-                               pte_free(mm, pgtable);
-                               put_huge_zero_page();
-                       }
-                       return 0;
-               }
-               page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
-                                         vma, haddr, numa_node_id(), 0);
-               if (unlikely(!page)) {
+               zero_page = get_huge_zero_page();
+               if (unlikely(!zero_page)) {
+                       pte_free(mm, pgtable);
                        count_vm_event(THP_FAULT_FALLBACK);
-                       goto out;
+                       return VM_FAULT_FALLBACK;
                }
-               count_vm_event(THP_FAULT_ALLOC);
-               if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
-                       put_page(page);
-                       goto out;
-               }
-               if (unlikely(__do_huge_pmd_anonymous_page(mm, vma, haddr, pmd,
-                                                         page))) {
-                       mem_cgroup_uncharge_page(page);
-                       put_page(page);
-                       goto out;
+               spin_lock(&mm->page_table_lock);
+               set = set_huge_zero_page(pgtable, mm, vma, haddr, pmd,
+                               zero_page);
+               spin_unlock(&mm->page_table_lock);
+               if (!set) {
+                       pte_free(mm, pgtable);
+                       put_huge_zero_page();
                }
-
                return 0;
        }
-out:
-       /*
-        * Use __pte_alloc instead of pte_alloc_map, because we can't
-        * run pte_offset_map on the pmd, if an huge pmd could
-        * materialize from under us from a different thread.
-        */
-       if (unlikely(pmd_none(*pmd)) &&
-           unlikely(__pte_alloc(mm, vma, pmd, address)))
-               return VM_FAULT_OOM;
-       /* if an huge pmd materialized from under us just retry later */
-       if (unlikely(pmd_trans_huge(*pmd)))
-               return 0;
-       /*
-        * A regular pmd is established and it can't morph into a huge pmd
-        * from under us anymore at this point because we hold the mmap_sem
-        * read mode and khugepaged takes it in write mode. So now it's
-        * safe to run pte_offset_map().
-        */
-       pte = pte_offset_map(pmd, address);
-       return handle_pte_fault(mm, vma, address, pte, pmd, flags);
+       page = alloc_hugepage_vma(transparent_hugepage_defrag(vma),
+                       vma, haddr, numa_node_id(), 0);
+       if (unlikely(!page)) {
+               count_vm_event(THP_FAULT_FALLBACK);
+               return VM_FAULT_FALLBACK;
+       }
+       if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
+               put_page(page);
+               count_vm_event(THP_FAULT_FALLBACK);
+               return VM_FAULT_FALLBACK;
+       }
+       if (unlikely(__do_huge_pmd_anonymous_page(mm, vma, haddr, pmd, page))) {
+               mem_cgroup_uncharge_page(page);
+               put_page(page);
+               count_vm_event(THP_FAULT_FALLBACK);
+               return VM_FAULT_FALLBACK;
+       }
+
+       count_vm_event(THP_FAULT_ALLOC);
+       return 0;
 }
 
 int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm,
@@ -1165,7 +1150,6 @@ alloc:
                new_page = NULL;
 
        if (unlikely(!new_page)) {
-               count_vm_event(THP_FAULT_FALLBACK);
                if (is_huge_zero_pmd(orig_pmd)) {
                        ret = do_huge_pmd_wp_zero_page_fallback(mm, vma,
                                        address, pmd, orig_pmd, haddr);
@@ -1176,9 +1160,9 @@ alloc:
                                split_huge_page(page);
                        put_page(page);
                }
+               count_vm_event(THP_FAULT_FALLBACK);
                goto out;
        }
-       count_vm_event(THP_FAULT_ALLOC);
 
        if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
                put_page(new_page);
@@ -1186,10 +1170,13 @@ alloc:
                        split_huge_page(page);
                        put_page(page);
                }
+               count_vm_event(THP_FAULT_FALLBACK);
                ret |= VM_FAULT_OOM;
                goto out;
        }
 
+       count_vm_event(THP_FAULT_ALLOC);
+
        if (is_huge_zero_pmd(orig_pmd))
                clear_huge_page(new_page, haddr, HPAGE_PMD_NR);
        else
@@ -1210,7 +1197,8 @@ alloc:
                goto out_mn;
        } else {
                pmd_t entry;
-               entry = mk_huge_pmd(new_page, vma);
+               entry = mk_huge_pmd(new_page, vma->vm_page_prot);
+               entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
                pmdp_clear_flush(vma, haddr, pmd);
                page_add_new_anon_rmap(new_page, vma, haddr);
                set_pmd_at(mm, haddr, pmd, entry);
@@ -1661,7 +1649,6 @@ static void __split_huge_page_refcount(struct page *page,
        BUG_ON(atomic_read(&page->_count) <= 0);
 
        __mod_zone_page_state(zone, NR_ANON_TRANSPARENT_HUGEPAGES, -1);
-       __mod_zone_page_state(zone, NR_ANON_PAGES, HPAGE_PMD_NR);
 
        ClearPageCompound(page);
        compound_unlock(page);
@@ -2296,6 +2283,8 @@ static void collapse_huge_page(struct mm_struct *mm,
                goto out;
 
        vma = find_vma(mm, address);
+       if (!vma)
+               goto out;
        hstart = (vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK;
        hend = vma->vm_end & HPAGE_PMD_MASK;
        if (address < hstart || address + HPAGE_PMD_SIZE > hend)
@@ -2357,7 +2346,8 @@ static void collapse_huge_page(struct mm_struct *mm,
        __SetPageUptodate(new_page);
        pgtable = pmd_pgtable(_pmd);
 
-       _pmd = mk_huge_pmd(new_page, vma);
+       _pmd = mk_huge_pmd(new_page, vma->vm_page_prot);
+       _pmd = maybe_pmd_mkwrite(pmd_mkdirty(_pmd), vma);
 
        /*
         * spin_lock() below is not the equivalent of smp_wmb(), so
index b60f33080a28f0a078f8186e65ab8d878fced928..b49579c7f2a550462c334f97907f2fc131a65e00 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/rmap.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
+#include <linux/page-isolation.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -33,7 +34,6 @@
 #include "internal.h"
 
 const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL;
-static gfp_t htlb_alloc_mask = GFP_HIGHUSER;
 unsigned long hugepages_treat_as_movable;
 
 int hugetlb_max_hstate __read_mostly;
@@ -48,7 +48,8 @@ static unsigned long __initdata default_hstate_max_huge_pages;
 static unsigned long __initdata default_hstate_size;
 
 /*
- * Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
+ * Protects updates to hugepage_freelists, hugepage_activelist, nr_huge_pages,
+ * free_huge_pages, and surplus_huge_pages.
  */
 DEFINE_SPINLOCK(hugetlb_lock);
 
@@ -135,9 +136,9 @@ static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma)
  *                    across the pages in a mapping.
  *
  * The region data structures are protected by a combination of the mmap_sem
- * and the hugetlb_instantion_mutex.  To access or modify a region the caller
+ * and the hugetlb_instantiation_mutex.  To access or modify a region the caller
  * must either hold the mmap_sem for write, or the mmap_sem for read and
- * the hugetlb_instantiation mutex:
+ * the hugetlb_instantiation_mutex:
  *
  *     down_write(&mm->mmap_sem);
  * or
@@ -434,25 +435,6 @@ static int is_vma_resv_set(struct vm_area_struct *vma, unsigned long flag)
        return (get_vma_private_data(vma) & flag) != 0;
 }
 
-/* Decrement the reserved pages in the hugepage pool by one */
-static void decrement_hugepage_resv_vma(struct hstate *h,
-                       struct vm_area_struct *vma)
-{
-       if (vma->vm_flags & VM_NORESERVE)
-               return;
-
-       if (vma->vm_flags & VM_MAYSHARE) {
-               /* Shared mappings always use reserves */
-               h->resv_huge_pages--;
-       } else if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
-               /*
-                * Only the process that called mmap() has reserves for
-                * private mappings.
-                */
-               h->resv_huge_pages--;
-       }
-}
-
 /* Reset counters to 0 and clear all HPAGE_RESV_* flags */
 void reset_vma_resv_huge_pages(struct vm_area_struct *vma)
 {
@@ -462,12 +444,35 @@ void reset_vma_resv_huge_pages(struct vm_area_struct *vma)
 }
 
 /* Returns true if the VMA has associated reserve pages */
-static int vma_has_reserves(struct vm_area_struct *vma)
+static int vma_has_reserves(struct vm_area_struct *vma, long chg)
 {
+       if (vma->vm_flags & VM_NORESERVE) {
+               /*
+                * This address is already reserved by other process(chg == 0),
+                * so, we should decrement reserved count. Without decrementing,
+                * reserve count remains after releasing inode, because this
+                * allocated page will go into page cache and is regarded as
+                * coming from reserved pool in releasing step.  Currently, we
+                * don't have any other solution to deal with this situation
+                * properly, so add work-around here.
+                */
+               if (vma->vm_flags & VM_MAYSHARE && chg == 0)
+                       return 1;
+               else
+                       return 0;
+       }
+
+       /* Shared mappings always use reserves */
        if (vma->vm_flags & VM_MAYSHARE)
                return 1;
+
+       /*
+        * Only the process that called mmap() has reserves for
+        * private mappings.
+        */
        if (is_vma_resv_set(vma, HPAGE_RESV_OWNER))
                return 1;
+
        return 0;
 }
 
@@ -517,9 +522,15 @@ static struct page *dequeue_huge_page_node(struct hstate *h, int nid)
 {
        struct page *page;
 
-       if (list_empty(&h->hugepage_freelists[nid]))
+       list_for_each_entry(page, &h->hugepage_freelists[nid], lru)
+               if (!is_migrate_isolate_page(page))
+                       break;
+       /*
+        * if 'non-isolated free hugepage' not found on the list,
+        * the allocation fails.
+        */
+       if (&h->hugepage_freelists[nid] == &page->lru)
                return NULL;
-       page = list_entry(h->hugepage_freelists[nid].next, struct page, lru);
        list_move(&page->lru, &h->hugepage_activelist);
        set_page_refcounted(page);
        h->free_huge_pages--;
@@ -527,9 +538,19 @@ static struct page *dequeue_huge_page_node(struct hstate *h, int nid)
        return page;
 }
 
+/* Movability of hugepages depends on migration support. */
+static inline gfp_t htlb_alloc_mask(struct hstate *h)
+{
+       if (hugepages_treat_as_movable || hugepage_migration_support(h))
+               return GFP_HIGHUSER_MOVABLE;
+       else
+               return GFP_HIGHUSER;
+}
+
 static struct page *dequeue_huge_page_vma(struct hstate *h,
                                struct vm_area_struct *vma,
-                               unsigned long address, int avoid_reserve)
+                               unsigned long address, int avoid_reserve,
+                               long chg)
 {
        struct page *page = NULL;
        struct mempolicy *mpol;
@@ -539,16 +560,12 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
        struct zoneref *z;
        unsigned int cpuset_mems_cookie;
 
-retry_cpuset:
-       cpuset_mems_cookie = 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
         * not "stolen". The child may still get SIGKILLed
         */
-       if (!vma_has_reserves(vma) &&
+       if (!vma_has_reserves(vma, chg) &&
                        h->free_huge_pages - h->resv_huge_pages == 0)
                goto err;
 
@@ -556,13 +573,23 @@ retry_cpuset:
        if (avoid_reserve && h->free_huge_pages - h->resv_huge_pages == 0)
                goto err;
 
+retry_cpuset:
+       cpuset_mems_cookie = get_mems_allowed();
+       zonelist = huge_zonelist(vma, address,
+                                       htlb_alloc_mask(h), &mpol, &nodemask);
+
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                                MAX_NR_ZONES - 1, nodemask) {
-               if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask)) {
+               if (cpuset_zone_allowed_softwall(zone, htlb_alloc_mask(h))) {
                        page = dequeue_huge_page_node(h, zone_to_nid(zone));
                        if (page) {
-                               if (!avoid_reserve)
-                                       decrement_hugepage_resv_vma(h, vma);
+                               if (avoid_reserve)
+                                       break;
+                               if (!vma_has_reserves(vma, chg))
+                                       break;
+
+                               SetPagePrivate(page);
+                               h->resv_huge_pages--;
                                break;
                        }
                }
@@ -574,7 +601,6 @@ retry_cpuset:
        return page;
 
 err:
-       mpol_cond_put(mpol);
        return NULL;
 }
 
@@ -620,15 +646,20 @@ static void free_huge_page(struct page *page)
        int nid = page_to_nid(page);
        struct hugepage_subpool *spool =
                (struct hugepage_subpool *)page_private(page);
+       bool restore_reserve;
 
        set_page_private(page, 0);
        page->mapping = NULL;
        BUG_ON(page_count(page));
        BUG_ON(page_mapcount(page));
+       restore_reserve = PagePrivate(page);
 
        spin_lock(&hugetlb_lock);
        hugetlb_cgroup_uncharge_page(hstate_index(h),
                                     pages_per_huge_page(h), page);
+       if (restore_reserve)
+               h->resv_huge_pages++;
+
        if (h->surplus_huge_pages_node[nid] && huge_page_order(h) < MAX_ORDER) {
                /* remove the page from active list */
                list_del(&page->lru);
@@ -715,7 +746,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid)
                return NULL;
 
        page = alloc_pages_exact_node(nid,
-               htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
+               htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE|
                                                __GFP_REPEAT|__GFP_NOWARN,
                huge_page_order(h));
        if (page) {
@@ -772,33 +803,6 @@ static int hstate_next_node_to_alloc(struct hstate *h,
        return nid;
 }
 
-static int alloc_fresh_huge_page(struct hstate *h, nodemask_t *nodes_allowed)
-{
-       struct page *page;
-       int start_nid;
-       int next_nid;
-       int ret = 0;
-
-       start_nid = hstate_next_node_to_alloc(h, nodes_allowed);
-       next_nid = start_nid;
-
-       do {
-               page = alloc_fresh_huge_page_node(h, next_nid);
-               if (page) {
-                       ret = 1;
-                       break;
-               }
-               next_nid = hstate_next_node_to_alloc(h, nodes_allowed);
-       } while (next_nid != start_nid);
-
-       if (ret)
-               count_vm_event(HTLB_BUDDY_PGALLOC);
-       else
-               count_vm_event(HTLB_BUDDY_PGALLOC_FAIL);
-
-       return ret;
-}
-
 /*
  * helper for free_pool_huge_page() - return the previously saved
  * node ["this node"] from which to free a huge page.  Advance the
@@ -817,6 +821,40 @@ static int hstate_next_node_to_free(struct hstate *h, nodemask_t *nodes_allowed)
        return nid;
 }
 
+#define for_each_node_mask_to_alloc(hs, nr_nodes, node, mask)          \
+       for (nr_nodes = nodes_weight(*mask);                            \
+               nr_nodes > 0 &&                                         \
+               ((node = hstate_next_node_to_alloc(hs, mask)) || 1);    \
+               nr_nodes--)
+
+#define for_each_node_mask_to_free(hs, nr_nodes, node, mask)           \
+       for (nr_nodes = nodes_weight(*mask);                            \
+               nr_nodes > 0 &&                                         \
+               ((node = hstate_next_node_to_free(hs, mask)) || 1);     \
+               nr_nodes--)
+
+static int alloc_fresh_huge_page(struct hstate *h, nodemask_t *nodes_allowed)
+{
+       struct page *page;
+       int nr_nodes, node;
+       int ret = 0;
+
+       for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
+               page = alloc_fresh_huge_page_node(h, node);
+               if (page) {
+                       ret = 1;
+                       break;
+               }
+       }
+
+       if (ret)
+               count_vm_event(HTLB_BUDDY_PGALLOC);
+       else
+               count_vm_event(HTLB_BUDDY_PGALLOC_FAIL);
+
+       return ret;
+}
+
 /*
  * Free huge page from pool from next node to free.
  * Attempt to keep persistent huge pages more or less
@@ -826,40 +864,73 @@ static int hstate_next_node_to_free(struct hstate *h, nodemask_t *nodes_allowed)
 static int free_pool_huge_page(struct hstate *h, nodemask_t *nodes_allowed,
                                                         bool acct_surplus)
 {
-       int start_nid;
-       int next_nid;
+       int nr_nodes, node;
        int ret = 0;
 
-       start_nid = hstate_next_node_to_free(h, nodes_allowed);
-       next_nid = start_nid;
-
-       do {
+       for_each_node_mask_to_free(h, nr_nodes, node, nodes_allowed) {
                /*
                 * If we're returning unused surplus pages, only examine
                 * nodes with surplus pages.
                 */
-               if ((!acct_surplus || h->surplus_huge_pages_node[next_nid]) &&
-                   !list_empty(&h->hugepage_freelists[next_nid])) {
+               if ((!acct_surplus || h->surplus_huge_pages_node[node]) &&
+                   !list_empty(&h->hugepage_freelists[node])) {
                        struct page *page =
-                               list_entry(h->hugepage_freelists[next_nid].next,
+                               list_entry(h->hugepage_freelists[node].next,
                                          struct page, lru);
                        list_del(&page->lru);
                        h->free_huge_pages--;
-                       h->free_huge_pages_node[next_nid]--;
+                       h->free_huge_pages_node[node]--;
                        if (acct_surplus) {
                                h->surplus_huge_pages--;
-                               h->surplus_huge_pages_node[next_nid]--;
+                               h->surplus_huge_pages_node[node]--;
                        }
                        update_and_free_page(h, page);
                        ret = 1;
                        break;
                }
-               next_nid = hstate_next_node_to_free(h, nodes_allowed);
-       } while (next_nid != start_nid);
+       }
 
        return ret;
 }
 
+/*
+ * Dissolve a given free hugepage into free buddy pages. This function does
+ * nothing for in-use (including surplus) hugepages.
+ */
+static void dissolve_free_huge_page(struct page *page)
+{
+       spin_lock(&hugetlb_lock);
+       if (PageHuge(page) && !page_count(page)) {
+               struct hstate *h = page_hstate(page);
+               int nid = page_to_nid(page);
+               list_del(&page->lru);
+               h->free_huge_pages--;
+               h->free_huge_pages_node[nid]--;
+               update_and_free_page(h, page);
+       }
+       spin_unlock(&hugetlb_lock);
+}
+
+/*
+ * Dissolve free hugepages in a given pfn range. Used by memory hotplug to
+ * make specified memory blocks removable from the system.
+ * Note that start_pfn should aligned with (minimum) hugepage size.
+ */
+void dissolve_free_huge_pages(unsigned long start_pfn, unsigned long end_pfn)
+{
+       unsigned int order = 8 * sizeof(void *);
+       unsigned long pfn;
+       struct hstate *h;
+
+       /* Set scan step to minimum hugepage size */
+       for_each_hstate(h)
+               if (order > huge_page_order(h))
+                       order = huge_page_order(h);
+       VM_BUG_ON(!IS_ALIGNED(start_pfn, 1 << order));
+       for (pfn = start_pfn; pfn < end_pfn; pfn += 1 << order)
+               dissolve_free_huge_page(pfn_to_page(pfn));
+}
+
 static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
 {
        struct page *page;
@@ -902,12 +973,12 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
        spin_unlock(&hugetlb_lock);
 
        if (nid == NUMA_NO_NODE)
-               page = alloc_pages(htlb_alloc_mask|__GFP_COMP|
+               page = alloc_pages(htlb_alloc_mask(h)|__GFP_COMP|
                                   __GFP_REPEAT|__GFP_NOWARN,
                                   huge_page_order(h));
        else
                page = alloc_pages_exact_node(nid,
-                       htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
+                       htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE|
                        __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h));
 
        if (page && arch_prepare_hugepage(page)) {
@@ -944,10 +1015,11 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid)
  */
 struct page *alloc_huge_page_node(struct hstate *h, int nid)
 {
-       struct page *page;
+       struct page *page = NULL;
 
        spin_lock(&hugetlb_lock);
-       page = dequeue_huge_page_node(h, nid);
+       if (h->free_huge_pages - h->resv_huge_pages > 0)
+               page = dequeue_huge_page_node(h, nid);
        spin_unlock(&hugetlb_lock);
 
        if (!page)
@@ -1035,11 +1107,8 @@ free:
        spin_unlock(&hugetlb_lock);
 
        /* Free unnecessary surplus pages to the buddy allocator */
-       if (!list_empty(&surplus_list)) {
-               list_for_each_entry_safe(page, tmp, &surplus_list, lru) {
-                       put_page(page);
-               }
-       }
+       list_for_each_entry_safe(page, tmp, &surplus_list, lru)
+               put_page(page);
        spin_lock(&hugetlb_lock);
 
        return ret;
@@ -1106,9 +1175,9 @@ static long vma_needs_reservation(struct hstate *h,
        } else  {
                long err;
                pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               struct resv_map *reservations = vma_resv_map(vma);
+               struct resv_map *resv = vma_resv_map(vma);
 
-               err = region_chg(&reservations->regions, idx, idx + 1);
+               err = region_chg(&resv->regions, idx, idx + 1);
                if (err < 0)
                        return err;
                return 0;
@@ -1126,10 +1195,10 @@ static void vma_commit_reservation(struct hstate *h,
 
        } else if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
                pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               struct resv_map *reservations = vma_resv_map(vma);
+               struct resv_map *resv = vma_resv_map(vma);
 
                /* Mark this page used in the map. */
-               region_add(&reservations->regions, idx, idx + 1);
+               region_add(&resv->regions, idx, idx + 1);
        }
 }
 
@@ -1155,38 +1224,35 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
        chg = vma_needs_reservation(h, vma, addr);
        if (chg < 0)
                return ERR_PTR(-ENOMEM);
-       if (chg)
-               if (hugepage_subpool_get_pages(spool, chg))
+       if (chg || avoid_reserve)
+               if (hugepage_subpool_get_pages(spool, 1))
                        return ERR_PTR(-ENOSPC);
 
        ret = hugetlb_cgroup_charge_cgroup(idx, pages_per_huge_page(h), &h_cg);
        if (ret) {
-               hugepage_subpool_put_pages(spool, chg);
+               if (chg || avoid_reserve)
+                       hugepage_subpool_put_pages(spool, 1);
                return ERR_PTR(-ENOSPC);
        }
        spin_lock(&hugetlb_lock);
-       page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve);
-       if (page) {
-               /* update page cgroup details */
-               hugetlb_cgroup_commit_charge(idx, pages_per_huge_page(h),
-                                            h_cg, page);
-               spin_unlock(&hugetlb_lock);
-       } else {
+       page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve, chg);
+       if (!page) {
                spin_unlock(&hugetlb_lock);
                page = alloc_buddy_huge_page(h, NUMA_NO_NODE);
                if (!page) {
                        hugetlb_cgroup_uncharge_cgroup(idx,
                                                       pages_per_huge_page(h),
                                                       h_cg);
-                       hugepage_subpool_put_pages(spool, chg);
+                       if (chg || avoid_reserve)
+                               hugepage_subpool_put_pages(spool, 1);
                        return ERR_PTR(-ENOSPC);
                }
                spin_lock(&hugetlb_lock);
-               hugetlb_cgroup_commit_charge(idx, pages_per_huge_page(h),
-                                            h_cg, page);
                list_move(&page->lru, &h->hugepage_activelist);
-               spin_unlock(&hugetlb_lock);
+               /* Fall through */
        }
+       hugetlb_cgroup_commit_charge(idx, pages_per_huge_page(h), h_cg, page);
+       spin_unlock(&hugetlb_lock);
 
        set_page_private(page, (unsigned long)spool);
 
@@ -1194,17 +1260,29 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma,
        return page;
 }
 
+/*
+ * alloc_huge_page()'s wrapper which simply returns the page if allocation
+ * succeeds, otherwise NULL. This function is called from new_vma_page(),
+ * where no ERR_VALUE is expected to be returned.
+ */
+struct page *alloc_huge_page_noerr(struct vm_area_struct *vma,
+                               unsigned long addr, int avoid_reserve)
+{
+       struct page *page = alloc_huge_page(vma, addr, avoid_reserve);
+       if (IS_ERR(page))
+               page = NULL;
+       return page;
+}
+
 int __weak alloc_bootmem_huge_page(struct hstate *h)
 {
        struct huge_bootmem_page *m;
-       int nr_nodes = nodes_weight(node_states[N_MEMORY]);
+       int nr_nodes, node;
 
-       while (nr_nodes) {
+       for_each_node_mask_to_alloc(h, nr_nodes, node, &node_states[N_MEMORY]) {
                void *addr;
 
-               addr = __alloc_bootmem_node_nopanic(
-                               NODE_DATA(hstate_next_node_to_alloc(h,
-                                               &node_states[N_MEMORY])),
+               addr = __alloc_bootmem_node_nopanic(NODE_DATA(node),
                                huge_page_size(h), huge_page_size(h), 0);
 
                if (addr) {
@@ -1216,7 +1294,6 @@ int __weak alloc_bootmem_huge_page(struct hstate *h)
                        m = addr;
                        goto found;
                }
-               nr_nodes--;
        }
        return 0;
 
@@ -1355,48 +1432,28 @@ static inline void try_to_free_low(struct hstate *h, unsigned long count,
 static int adjust_pool_surplus(struct hstate *h, nodemask_t *nodes_allowed,
                                int delta)
 {
-       int start_nid, next_nid;
-       int ret = 0;
+       int nr_nodes, node;
 
        VM_BUG_ON(delta != -1 && delta != 1);
 
-       if (delta < 0)
-               start_nid = hstate_next_node_to_alloc(h, nodes_allowed);
-       else
-               start_nid = hstate_next_node_to_free(h, nodes_allowed);
-       next_nid = start_nid;
-
-       do {
-               int nid = next_nid;
-               if (delta < 0)  {
-                       /*
-                        * To shrink on this node, there must be a surplus page
-                        */
-                       if (!h->surplus_huge_pages_node[nid]) {
-                               next_nid = hstate_next_node_to_alloc(h,
-                                                               nodes_allowed);
-                               continue;
-                       }
+       if (delta < 0) {
+               for_each_node_mask_to_alloc(h, nr_nodes, node, nodes_allowed) {
+                       if (h->surplus_huge_pages_node[node])
+                               goto found;
                }
-               if (delta > 0) {
-                       /*
-                        * Surplus cannot exceed the total number of pages
-                        */
-                       if (h->surplus_huge_pages_node[nid] >=
-                                               h->nr_huge_pages_node[nid]) {
-                               next_nid = hstate_next_node_to_free(h,
-                                                               nodes_allowed);
-                               continue;
-                       }
+       } else {
+               for_each_node_mask_to_free(h, nr_nodes, node, nodes_allowed) {
+                       if (h->surplus_huge_pages_node[node] <
+                                       h->nr_huge_pages_node[node])
+                               goto found;
                }
+       }
+       return 0;
 
-               h->surplus_huge_pages += delta;
-               h->surplus_huge_pages_node[nid] += delta;
-               ret = 1;
-               break;
-       } while (next_nid != start_nid);
-
-       return ret;
+found:
+       h->surplus_huge_pages += delta;
+       h->surplus_huge_pages_node[node] += delta;
+       return 1;
 }
 
 #define persistent_huge_pages(h) (h->nr_huge_pages - h->surplus_huge_pages)
@@ -1526,7 +1583,7 @@ static ssize_t nr_hugepages_store_common(bool obey_mempolicy,
        struct hstate *h;
        NODEMASK_ALLOC(nodemask_t, nodes_allowed, GFP_KERNEL | __GFP_NORETRY);
 
-       err = strict_strtoul(buf, 10, &count);
+       err = kstrtoul(buf, 10, &count);
        if (err)
                goto out;
 
@@ -1617,7 +1674,7 @@ static ssize_t nr_overcommit_hugepages_store(struct kobject *kobj,
        if (h->order >= MAX_ORDER)
                return -EINVAL;
 
-       err = strict_strtoul(buf, 10, &input);
+       err = kstrtoul(buf, 10, &input);
        if (err)
                return err;
 
@@ -2068,18 +2125,6 @@ int hugetlb_mempolicy_sysctl_handler(struct ctl_table *table, int write,
 }
 #endif /* CONFIG_NUMA */
 
-int hugetlb_treat_movable_handler(struct ctl_table *table, int write,
-                       void __user *buffer,
-                       size_t *length, loff_t *ppos)
-{
-       proc_dointvec(table, write, buffer, length, ppos);
-       if (hugepages_treat_as_movable)
-               htlb_alloc_mask = GFP_HIGHUSER_MOVABLE;
-       else
-               htlb_alloc_mask = GFP_HIGHUSER;
-       return 0;
-}
-
 int hugetlb_overcommit_handler(struct ctl_table *table, int write,
                        void __user *buffer,
                        size_t *length, loff_t *ppos)
@@ -2207,7 +2252,7 @@ out:
 
 static void hugetlb_vm_op_open(struct vm_area_struct *vma)
 {
-       struct resv_map *reservations = vma_resv_map(vma);
+       struct resv_map *resv = vma_resv_map(vma);
 
        /*
         * This new VMA should share its siblings reservation map if present.
@@ -2217,34 +2262,34 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma)
         * after this open call completes.  It is therefore safe to take a
         * new reference here without additional locking.
         */
-       if (reservations)
-               kref_get(&reservations->refs);
+       if (resv)
+               kref_get(&resv->refs);
 }
 
 static void resv_map_put(struct vm_area_struct *vma)
 {
-       struct resv_map *reservations = vma_resv_map(vma);
+       struct resv_map *resv = vma_resv_map(vma);
 
-       if (!reservations)
+       if (!resv)
                return;
-       kref_put(&reservations->refs, resv_map_release);
+       kref_put(&resv->refs, resv_map_release);
 }
 
 static void hugetlb_vm_op_close(struct vm_area_struct *vma)
 {
        struct hstate *h = hstate_vma(vma);
-       struct resv_map *reservations = vma_resv_map(vma);
+       struct resv_map *resv = vma_resv_map(vma);
        struct hugepage_subpool *spool = subpool_vma(vma);
        unsigned long reserve;
        unsigned long start;
        unsigned long end;
 
-       if (reservations) {
+       if (resv) {
                start = vma_hugecache_offset(h, vma, vma->vm_start);
                end = vma_hugecache_offset(h, vma, vma->vm_end);
 
                reserve = (end - start) -
-                       region_count(&reservations->regions, start, end);
+                       region_count(&resv->regions, start, end);
 
                resv_map_put(vma);
 
@@ -2557,7 +2602,6 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
 {
        struct hstate *h = hstate_vma(vma);
        struct page *old_page, *new_page;
-       int avoidcopy;
        int outside_reserve = 0;
        unsigned long mmun_start;       /* For mmu_notifiers */
        unsigned long mmun_end;         /* For mmu_notifiers */
@@ -2567,10 +2611,8 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
 retry_avoidcopy:
        /* If no-one else is actually using this page, avoid the copy
         * and just make the page writable */
-       avoidcopy = (page_mapcount(old_page) == 1);
-       if (avoidcopy) {
-               if (PageAnon(old_page))
-                       page_move_anon_rmap(old_page, vma, address);
+       if (page_mapcount(old_page) == 1 && PageAnon(old_page)) {
+               page_move_anon_rmap(old_page, vma, address);
                set_huge_ptep_writable(vma, address, ptep);
                return 0;
        }
@@ -2584,8 +2626,7 @@ retry_avoidcopy:
         * at the time of fork() could consume its reserves on COW instead
         * of the full address range.
         */
-       if (!(vma->vm_flags & VM_MAYSHARE) &&
-                       is_vma_resv_set(vma, HPAGE_RESV_OWNER) &&
+       if (is_vma_resv_set(vma, HPAGE_RESV_OWNER) &&
                        old_page != pagecache_page)
                outside_reserve = 1;
 
@@ -2657,6 +2698,8 @@ retry_avoidcopy:
        spin_lock(&mm->page_table_lock);
        ptep = huge_pte_offset(mm, address & huge_page_mask(h));
        if (likely(pte_same(huge_ptep_get(ptep), pte))) {
+               ClearPagePrivate(new_page);
+
                /* Break COW */
                huge_ptep_clear_flush(vma, address, ptep);
                set_huge_pte_at(mm, address, ptep,
@@ -2668,10 +2711,11 @@ retry_avoidcopy:
        }
        spin_unlock(&mm->page_table_lock);
        mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
-       /* Caller expects lock to be held */
-       spin_lock(&mm->page_table_lock);
        page_cache_release(new_page);
        page_cache_release(old_page);
+
+       /* Caller expects lock to be held */
+       spin_lock(&mm->page_table_lock);
        return 0;
 }
 
@@ -2767,6 +2811,7 @@ retry:
                                        goto retry;
                                goto out;
                        }
+                       ClearPagePrivate(page);
 
                        spin_lock(&inode->i_lock);
                        inode->i_blocks += blocks_per_huge_page(h);
@@ -2813,8 +2858,10 @@ retry:
        if (!huge_pte_none(huge_ptep_get(ptep)))
                goto backout;
 
-       if (anon_rmap)
+       if (anon_rmap) {
+               ClearPagePrivate(page);
                hugepage_add_new_anon_rmap(page, vma, address);
+       }
        else
                page_dup_rmap(page);
        new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)
@@ -3431,3 +3478,45 @@ int dequeue_hwpoisoned_huge_page(struct page *hpage)
        return ret;
 }
 #endif
+
+bool isolate_huge_page(struct page *page, struct list_head *list)
+{
+       VM_BUG_ON(!PageHead(page));
+       if (!get_page_unless_zero(page))
+               return false;
+       spin_lock(&hugetlb_lock);
+       list_move_tail(&page->lru, list);
+       spin_unlock(&hugetlb_lock);
+       return true;
+}
+
+void putback_active_hugepage(struct page *page)
+{
+       VM_BUG_ON(!PageHead(page));
+       spin_lock(&hugetlb_lock);
+       list_move_tail(&page->lru, &(page_hstate(page))->hugepage_activelist);
+       spin_unlock(&hugetlb_lock);
+       put_page(page);
+}
+
+bool is_hugepage_active(struct page *page)
+{
+       VM_BUG_ON(!PageHuge(page));
+       /*
+        * This function can be called for a tail page because the caller,
+        * scan_movable_pages, scans through a given pfn-range which typically
+        * covers one memory block. In systems using gigantic hugepage (1GB
+        * for x86_64,) a hugepage is larger than a memory block, and we don't
+        * support migrating such large hugepages for now, so return false
+        * when called for tail pages.
+        */
+       if (PageTail(page))
+               return false;
+       /*
+        * Refcount of a hwpoisoned hugepages is 1, but they are not active,
+        * so we should return false for them.
+        */
+       if (unlikely(PageHWPoison(page)))
+               return false;
+       return page_count(page) > 0;
+}
index 3a61efc518d56964460af63ca31ba26bc375ad47..afc2daa91c609dd8aab70f50fb58fd9100ed8326 100644 (file)
@@ -88,12 +88,12 @@ static int pfn_inject_init(void)
         * hardware status change, hence do not require hardware support.
         * They are mainly for testing hwpoison in software level.
         */
-       dentry = debugfs_create_file("corrupt-pfn", 0600, hwpoison_dir,
+       dentry = debugfs_create_file("corrupt-pfn", 0200, hwpoison_dir,
                                          NULL, &hwpoison_fops);
        if (!dentry)
                goto fail;
 
-       dentry = debugfs_create_file("unpoison-pfn", 0600, hwpoison_dir,
+       dentry = debugfs_create_file("unpoison-pfn", 0200, hwpoison_dir,
                                     NULL, &unpoison_fops);
        if (!dentry)
                goto fail;
index 4390ac6c106e6124d653f18948ec296173527521..684f7aa9692aecc9e002a3095468a23c5c5c4ed4 100644 (file)
@@ -85,6 +85,8 @@ extern unsigned long highest_memmap_pfn;
  */
 extern int isolate_lru_page(struct page *page);
 extern void putback_lru_page(struct page *page);
+extern unsigned long zone_reclaimable_pages(struct zone *zone);
+extern bool zone_reclaimable(struct zone *zone);
 
 /*
  * in mm/rmap.c:
index c8d7f3110fd0002cc1c2b85061c163ba7183bfc4..e126b0ef9ad20023d6a8d3ff505ae71ad96fdaa0 100644 (file)
@@ -1639,7 +1639,7 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf,
        else if (strncmp(buf, "scan=", 5) == 0) {
                unsigned long secs;
 
-               ret = strict_strtoul(buf + 5, 0, &secs);
+               ret = kstrtoul(buf + 5, 0, &secs);
                if (ret < 0)
                        goto out;
                stop_scan_thread();
index b6afe0c440d8b3e500f4a09e2875491c7d70199a..0bea2b262a47837f1c0bd81492e9cfdd30daa041 100644 (file)
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -2194,7 +2194,7 @@ static ssize_t sleep_millisecs_store(struct kobject *kobj,
        unsigned long msecs;
        int err;
 
-       err = strict_strtoul(buf, 10, &msecs);
+       err = kstrtoul(buf, 10, &msecs);
        if (err || msecs > UINT_MAX)
                return -EINVAL;
 
@@ -2217,7 +2217,7 @@ static ssize_t pages_to_scan_store(struct kobject *kobj,
        int err;
        unsigned long nr_pages;
 
-       err = strict_strtoul(buf, 10, &nr_pages);
+       err = kstrtoul(buf, 10, &nr_pages);
        if (err || nr_pages > UINT_MAX)
                return -EINVAL;
 
@@ -2239,7 +2239,7 @@ static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr,
        int err;
        unsigned long flags;
 
-       err = strict_strtoul(buf, 10, &flags);
+       err = kstrtoul(buf, 10, &flags);
        if (err || flags > UINT_MAX)
                return -EINVAL;
        if (flags > KSM_RUN_UNMERGE)
diff --git a/mm/list_lru.c b/mm/list_lru.c
new file mode 100644 (file)
index 0000000..7246791
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved.
+ * Authors: David Chinner and Glauber Costa
+ *
+ * Generic LRU infrastructure
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/list_lru.h>
+#include <linux/slab.h>
+
+bool list_lru_add(struct list_lru *lru, struct list_head *item)
+{
+       int nid = page_to_nid(virt_to_page(item));
+       struct list_lru_node *nlru = &lru->node[nid];
+
+       spin_lock(&nlru->lock);
+       WARN_ON_ONCE(nlru->nr_items < 0);
+       if (list_empty(item)) {
+               list_add_tail(item, &nlru->list);
+               if (nlru->nr_items++ == 0)
+                       node_set(nid, lru->active_nodes);
+               spin_unlock(&nlru->lock);
+               return true;
+       }
+       spin_unlock(&nlru->lock);
+       return false;
+}
+EXPORT_SYMBOL_GPL(list_lru_add);
+
+bool list_lru_del(struct list_lru *lru, struct list_head *item)
+{
+       int nid = page_to_nid(virt_to_page(item));
+       struct list_lru_node *nlru = &lru->node[nid];
+
+       spin_lock(&nlru->lock);
+       if (!list_empty(item)) {
+               list_del_init(item);
+               if (--nlru->nr_items == 0)
+                       node_clear(nid, lru->active_nodes);
+               WARN_ON_ONCE(nlru->nr_items < 0);
+               spin_unlock(&nlru->lock);
+               return true;
+       }
+       spin_unlock(&nlru->lock);
+       return false;
+}
+EXPORT_SYMBOL_GPL(list_lru_del);
+
+unsigned long
+list_lru_count_node(struct list_lru *lru, int nid)
+{
+       unsigned long count = 0;
+       struct list_lru_node *nlru = &lru->node[nid];
+
+       spin_lock(&nlru->lock);
+       WARN_ON_ONCE(nlru->nr_items < 0);
+       count += nlru->nr_items;
+       spin_unlock(&nlru->lock);
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(list_lru_count_node);
+
+unsigned long
+list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate,
+                  void *cb_arg, unsigned long *nr_to_walk)
+{
+
+       struct list_lru_node    *nlru = &lru->node[nid];
+       struct list_head *item, *n;
+       unsigned long isolated = 0;
+
+       spin_lock(&nlru->lock);
+restart:
+       list_for_each_safe(item, n, &nlru->list) {
+               enum lru_status ret;
+
+               /*
+                * decrement nr_to_walk first so that we don't livelock if we
+                * get stuck on large numbesr of LRU_RETRY items
+                */
+               if (--(*nr_to_walk) == 0)
+                       break;
+
+               ret = isolate(item, &nlru->lock, cb_arg);
+               switch (ret) {
+               case LRU_REMOVED:
+                       if (--nlru->nr_items == 0)
+                               node_clear(nid, lru->active_nodes);
+                       WARN_ON_ONCE(nlru->nr_items < 0);
+                       isolated++;
+                       break;
+               case LRU_ROTATE:
+                       list_move_tail(item, &nlru->list);
+                       break;
+               case LRU_SKIP:
+                       break;
+               case LRU_RETRY:
+                       /*
+                        * The lru lock has been dropped, our list traversal is
+                        * now invalid and so we have to restart from scratch.
+                        */
+                       goto restart;
+               default:
+                       BUG();
+               }
+       }
+
+       spin_unlock(&nlru->lock);
+       return isolated;
+}
+EXPORT_SYMBOL_GPL(list_lru_walk_node);
+
+int list_lru_init(struct list_lru *lru)
+{
+       int i;
+       size_t size = sizeof(*lru->node) * nr_node_ids;
+
+       lru->node = kzalloc(size, GFP_KERNEL);
+       if (!lru->node)
+               return -ENOMEM;
+
+       nodes_clear(lru->active_nodes);
+       for (i = 0; i < nr_node_ids; i++) {
+               spin_lock_init(&lru->node[i].lock);
+               INIT_LIST_HEAD(&lru->node[i].list);
+               lru->node[i].nr_items = 0;
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(list_lru_init);
+
+void list_lru_destroy(struct list_lru *lru)
+{
+       kfree(lru->node);
+}
+EXPORT_SYMBOL_GPL(list_lru_destroy);
index 7055883e6e250f2914ed5c0a7814400e4945c9d1..6975bc812542d2c13642363d928005f355199c54 100644 (file)
@@ -42,11 +42,11 @@ static int madvise_need_mmap_write(int behavior)
  * We can potentially split a vm area into separate
  * areas, each area with its own behavior.
  */
-static long madvise_behavior(struct vm_area_struct * vma,
+static long madvise_behavior(struct vm_area_struct *vma,
                     struct vm_area_struct **prev,
                     unsigned long start, unsigned long end, int behavior)
 {
-       struct mm_struct * mm = vma->vm_mm;
+       struct mm_struct *mm = vma->vm_mm;
        int error = 0;
        pgoff_t pgoff;
        unsigned long new_flags = vma->vm_flags;
@@ -215,8 +215,8 @@ static void force_shm_swapin_readahead(struct vm_area_struct *vma,
 /*
  * Schedule all required I/O operations.  Do not wait for completion.
  */
-static long madvise_willneed(struct vm_area_struct * vma,
-                            struct vm_area_struct ** prev,
+static long madvise_willneed(struct vm_area_struct *vma,
+                            struct vm_area_struct **prev,
                             unsigned long start, unsigned long end)
 {
        struct file *file = vma->vm_file;
@@ -270,8 +270,8 @@ static long madvise_willneed(struct vm_area_struct * vma,
  * An interface that causes the system to free clean pages and flush
  * dirty pages is already available as msync(MS_INVALIDATE).
  */
-static long madvise_dontneed(struct vm_area_struct * vma,
-                            struct vm_area_struct ** prev,
+static long madvise_dontneed(struct vm_area_struct *vma,
+                            struct vm_area_struct **prev,
                             unsigned long start, unsigned long end)
 {
        *prev = vma;
@@ -343,29 +343,34 @@ static long madvise_remove(struct vm_area_struct *vma,
  */
 static int madvise_hwpoison(int bhv, unsigned long start, unsigned long end)
 {
-       int ret = 0;
-
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
        for (; start < end; start += PAGE_SIZE) {
                struct page *p;
-               int ret = get_user_pages_fast(start, 1, 0, &p);
+               int ret;
+
+               ret = get_user_pages_fast(start, 1, 0, &p);
                if (ret != 1)
                        return ret;
+
+               if (PageHWPoison(p)) {
+                       put_page(p);
+                       continue;
+               }
                if (bhv == MADV_SOFT_OFFLINE) {
-                       printk(KERN_INFO "Soft offlining page %lx at %lx\n",
+                       pr_info("Soft offlining page %#lx at %#lx\n",
                                page_to_pfn(p), start);
                        ret = soft_offline_page(p, MF_COUNT_INCREASED);
                        if (ret)
-                               break;
+                               return ret;
                        continue;
                }
-               printk(KERN_INFO "Injecting memory failure for page %lx at %lx\n",
+               pr_info("Injecting memory failure for page %#lx at %#lx\n",
                       page_to_pfn(p), start);
                /* Ignore return value for now */
                memory_failure(page_to_pfn(p), 0, MF_COUNT_INCREASED);
        }
-       return ret;
+       return 0;
 }
 #endif
 
@@ -459,7 +464,7 @@ madvise_behavior_valid(int behavior)
 SYSCALL_DEFINE3(madvise, unsigned long, start, size_t, len_in, int, behavior)
 {
        unsigned long end, tmp;
-       struct vm_area_struct * vma, *prev;
+       struct vm_area_struct *vma, *prev;
        int unmapped_error = 0;
        int error = -EINVAL;
        int write;
index a847bfe6f3bae3be1ff711c83d22fd9074bd7a23..0ac412a0a7ee0c68a919754e6b6ae0e40624b30c 100644 (file)
@@ -914,6 +914,24 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)
        return memblock_search(&memblock.memory, addr) != -1;
 }
 
+#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
+int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
+                        unsigned long *start_pfn, unsigned long *end_pfn)
+{
+       struct memblock_type *type = &memblock.memory;
+       int mid = memblock_search(type, (phys_addr_t)pfn << PAGE_SHIFT);
+
+       if (mid == -1)
+               return -1;
+
+       *start_pfn = type->regions[mid].base >> PAGE_SHIFT;
+       *end_pfn = (type->regions[mid].base + type->regions[mid].size)
+                       >> PAGE_SHIFT;
+
+       return type->regions[mid].nid;
+}
+#endif
+
 /**
  * memblock_is_region_memory - check if a region is a subset of memory
  * @base: base of region to check
index 3b83957b643985afa2659e27fc11bc01beb84a7b..d5ff3ce13029b2c99b4ed402898ae0c76a143fde 100644 (file)
@@ -39,7 +39,6 @@
 #include <linux/limits.h>
 #include <linux/export.h>
 #include <linux/mutex.h>
-#include <linux/rbtree.h>
 #include <linux/slab.h>
 #include <linux/swap.h>
 #include <linux/swapops.h>
@@ -85,26 +84,12 @@ static int really_do_swap_account __initdata = 0;
 #endif
 
 
-/*
- * Statistics for memory cgroup.
- */
-enum mem_cgroup_stat_index {
-       /*
-        * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss.
-        */
-       MEM_CGROUP_STAT_CACHE,          /* # of pages charged as cache */
-       MEM_CGROUP_STAT_RSS,            /* # of pages charged as anon rss */
-       MEM_CGROUP_STAT_RSS_HUGE,       /* # of pages charged as anon huge */
-       MEM_CGROUP_STAT_FILE_MAPPED,    /* # of pages charged as file rss */
-       MEM_CGROUP_STAT_SWAP,           /* # of pages, swapped out */
-       MEM_CGROUP_STAT_NSTATS,
-};
-
 static const char * const mem_cgroup_stat_names[] = {
        "cache",
        "rss",
        "rss_huge",
        "mapped_file",
+       "writeback",
        "swap",
 };
 
@@ -175,10 +160,6 @@ struct mem_cgroup_per_zone {
 
        struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1];
 
-       struct rb_node          tree_node;      /* RB tree node */
-       unsigned long long      usage_in_excess;/* Set to the value by which */
-                                               /* the soft limit is exceeded*/
-       bool                    on_tree;
        struct mem_cgroup       *memcg;         /* Back pointer, we cannot */
                                                /* use container_of        */
 };
@@ -187,26 +168,6 @@ struct mem_cgroup_per_node {
        struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES];
 };
 
-/*
- * Cgroups above their limits are maintained in a RB-Tree, independent of
- * their hierarchy representation
- */
-
-struct mem_cgroup_tree_per_zone {
-       struct rb_root rb_root;
-       spinlock_t lock;
-};
-
-struct mem_cgroup_tree_per_node {
-       struct mem_cgroup_tree_per_zone rb_tree_per_zone[MAX_NR_ZONES];
-};
-
-struct mem_cgroup_tree {
-       struct mem_cgroup_tree_per_node *rb_tree_per_node[MAX_NUMNODES];
-};
-
-static struct mem_cgroup_tree soft_limit_tree __read_mostly;
-
 struct mem_cgroup_threshold {
        struct eventfd_ctx *eventfd;
        u64 threshold;
@@ -280,6 +241,7 @@ struct mem_cgroup {
 
        bool            oom_lock;
        atomic_t        under_oom;
+       atomic_t        oom_wakeups;
 
        int     swappiness;
        /* OOM-Killer disable */
@@ -304,7 +266,7 @@ struct mem_cgroup {
         * 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;
+       unsigned long move_charge_at_immigrate;
        /*
         * set > 0 if pages under this cgroup are moving to other cgroup.
         */
@@ -341,6 +303,22 @@ struct mem_cgroup {
        atomic_t        numainfo_events;
        atomic_t        numainfo_updating;
 #endif
+       /*
+        * Protects soft_contributed transitions.
+        * See mem_cgroup_update_soft_limit
+        */
+       spinlock_t soft_lock;
+
+       /*
+        * If true then this group has increased parents' children_in_excess
+        * when it got over the soft limit.
+        * When a group falls bellow the soft limit, parents' children_in_excess
+        * is decreased and soft_contributed changed to false.
+        */
+       bool soft_contributed;
+
+       /* Number of children that are in soft limit excess */
+       atomic_t children_in_excess;
 
        struct mem_cgroup_per_node *nodeinfo[0];
        /* WARNING: nodeinfo must be the last member here */
@@ -444,7 +422,6 @@ static bool move_file(void)
  * limit reclaim to prevent infinite loops, if they ever occur.
  */
 #define        MEM_CGROUP_MAX_RECLAIM_LOOPS            100
-#define        MEM_CGROUP_MAX_SOFT_LIMIT_RECLAIM_LOOPS 2
 
 enum charge_type {
        MEM_CGROUP_CHARGE_TYPE_CACHE = 0,
@@ -671,164 +648,6 @@ page_cgroup_zoneinfo(struct mem_cgroup *memcg, struct page *page)
        return mem_cgroup_zoneinfo(memcg, nid, zid);
 }
 
-static struct mem_cgroup_tree_per_zone *
-soft_limit_tree_node_zone(int nid, int zid)
-{
-       return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid];
-}
-
-static struct mem_cgroup_tree_per_zone *
-soft_limit_tree_from_page(struct page *page)
-{
-       int nid = page_to_nid(page);
-       int zid = page_zonenum(page);
-
-       return &soft_limit_tree.rb_tree_per_node[nid]->rb_tree_per_zone[zid];
-}
-
-static void
-__mem_cgroup_insert_exceeded(struct mem_cgroup *memcg,
-                               struct mem_cgroup_per_zone *mz,
-                               struct mem_cgroup_tree_per_zone *mctz,
-                               unsigned long long new_usage_in_excess)
-{
-       struct rb_node **p = &mctz->rb_root.rb_node;
-       struct rb_node *parent = NULL;
-       struct mem_cgroup_per_zone *mz_node;
-
-       if (mz->on_tree)
-               return;
-
-       mz->usage_in_excess = new_usage_in_excess;
-       if (!mz->usage_in_excess)
-               return;
-       while (*p) {
-               parent = *p;
-               mz_node = rb_entry(parent, struct mem_cgroup_per_zone,
-                                       tree_node);
-               if (mz->usage_in_excess < mz_node->usage_in_excess)
-                       p = &(*p)->rb_left;
-               /*
-                * We can't avoid mem cgroups that are over their soft
-                * limit by the same amount
-                */
-               else if (mz->usage_in_excess >= mz_node->usage_in_excess)
-                       p = &(*p)->rb_right;
-       }
-       rb_link_node(&mz->tree_node, parent, p);
-       rb_insert_color(&mz->tree_node, &mctz->rb_root);
-       mz->on_tree = true;
-}
-
-static void
-__mem_cgroup_remove_exceeded(struct mem_cgroup *memcg,
-                               struct mem_cgroup_per_zone *mz,
-                               struct mem_cgroup_tree_per_zone *mctz)
-{
-       if (!mz->on_tree)
-               return;
-       rb_erase(&mz->tree_node, &mctz->rb_root);
-       mz->on_tree = false;
-}
-
-static void
-mem_cgroup_remove_exceeded(struct mem_cgroup *memcg,
-                               struct mem_cgroup_per_zone *mz,
-                               struct mem_cgroup_tree_per_zone *mctz)
-{
-       spin_lock(&mctz->lock);
-       __mem_cgroup_remove_exceeded(memcg, mz, mctz);
-       spin_unlock(&mctz->lock);
-}
-
-
-static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
-{
-       unsigned long long excess;
-       struct mem_cgroup_per_zone *mz;
-       struct mem_cgroup_tree_per_zone *mctz;
-       int nid = page_to_nid(page);
-       int zid = page_zonenum(page);
-       mctz = soft_limit_tree_from_page(page);
-
-       /*
-        * Necessary to update all ancestors when hierarchy is used.
-        * because their event counter is not touched.
-        */
-       for (; memcg; memcg = parent_mem_cgroup(memcg)) {
-               mz = mem_cgroup_zoneinfo(memcg, nid, zid);
-               excess = res_counter_soft_limit_excess(&memcg->res);
-               /*
-                * We have to update the tree if mz is on RB-tree or
-                * mem is over its softlimit.
-                */
-               if (excess || mz->on_tree) {
-                       spin_lock(&mctz->lock);
-                       /* if on-tree, remove it */
-                       if (mz->on_tree)
-                               __mem_cgroup_remove_exceeded(memcg, mz, mctz);
-                       /*
-                        * Insert again. mz->usage_in_excess will be updated.
-                        * If excess is 0, no tree ops.
-                        */
-                       __mem_cgroup_insert_exceeded(memcg, mz, mctz, excess);
-                       spin_unlock(&mctz->lock);
-               }
-       }
-}
-
-static void mem_cgroup_remove_from_trees(struct mem_cgroup *memcg)
-{
-       int node, zone;
-       struct mem_cgroup_per_zone *mz;
-       struct mem_cgroup_tree_per_zone *mctz;
-
-       for_each_node(node) {
-               for (zone = 0; zone < MAX_NR_ZONES; zone++) {
-                       mz = mem_cgroup_zoneinfo(memcg, node, zone);
-                       mctz = soft_limit_tree_node_zone(node, zone);
-                       mem_cgroup_remove_exceeded(memcg, mz, mctz);
-               }
-       }
-}
-
-static struct mem_cgroup_per_zone *
-__mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
-{
-       struct rb_node *rightmost = NULL;
-       struct mem_cgroup_per_zone *mz;
-
-retry:
-       mz = NULL;
-       rightmost = rb_last(&mctz->rb_root);
-       if (!rightmost)
-               goto done;              /* Nothing to reclaim from */
-
-       mz = rb_entry(rightmost, struct mem_cgroup_per_zone, tree_node);
-       /*
-        * Remove the node now but someone else can add it back,
-        * we will to add it back at the end of reclaim to its correct
-        * position in the tree.
-        */
-       __mem_cgroup_remove_exceeded(mz->memcg, mz, mctz);
-       if (!res_counter_soft_limit_excess(&mz->memcg->res) ||
-               !css_tryget(&mz->memcg->css))
-               goto retry;
-done:
-       return mz;
-}
-
-static struct mem_cgroup_per_zone *
-mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz)
-{
-       struct mem_cgroup_per_zone *mz;
-
-       spin_lock(&mctz->lock);
-       mz = __mem_cgroup_largest_soft_limit_node(mctz);
-       spin_unlock(&mctz->lock);
-       return mz;
-}
-
 /*
  * Implementation Note: reading percpu statistics for memcg.
  *
@@ -1002,6 +821,48 @@ static bool mem_cgroup_event_ratelimit(struct mem_cgroup *memcg,
        return false;
 }
 
+/*
+ * Called from rate-limited memcg_check_events when enough
+ * MEM_CGROUP_TARGET_SOFTLIMIT events are accumulated and it makes sure
+ * that all the parents up the hierarchy will be notified that this group
+ * is in excess or that it is not in excess anymore. mmecg->soft_contributed
+ * makes the transition a single action whenever the state flips from one to
+ * the other.
+ */
+static void mem_cgroup_update_soft_limit(struct mem_cgroup *memcg)
+{
+       unsigned long long excess = res_counter_soft_limit_excess(&memcg->res);
+       struct mem_cgroup *parent = memcg;
+       int delta = 0;
+
+       spin_lock(&memcg->soft_lock);
+       if (excess) {
+               if (!memcg->soft_contributed) {
+                       delta = 1;
+                       memcg->soft_contributed = true;
+               }
+       } else {
+               if (memcg->soft_contributed) {
+                       delta = -1;
+                       memcg->soft_contributed = false;
+               }
+       }
+
+       /*
+        * Necessary to update all ancestors when hierarchy is used
+        * because their event counter is not touched.
+        * We track children even outside the hierarchy for the root
+        * cgroup because tree walk starting at root should visit
+        * all cgroups and we want to prevent from pointless tree
+        * walk if no children is below the limit.
+        */
+       while (delta && (parent = parent_mem_cgroup(parent)))
+               atomic_add(delta, &parent->children_in_excess);
+       if (memcg != root_mem_cgroup && !root_mem_cgroup->use_hierarchy)
+               atomic_add(delta, &root_mem_cgroup->children_in_excess);
+       spin_unlock(&memcg->soft_lock);
+}
+
 /*
  * Check events in order.
  *
@@ -1025,7 +886,7 @@ static void memcg_check_events(struct mem_cgroup *memcg, struct page *page)
 
                mem_cgroup_threshold(memcg);
                if (unlikely(do_softlimit))
-                       mem_cgroup_update_tree(memcg, page);
+                       mem_cgroup_update_soft_limit(memcg);
 #if MAX_NUMNODES > 1
                if (unlikely(do_numainfo))
                        atomic_inc(&memcg->numainfo_events);
@@ -1068,6 +929,15 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
        return memcg;
 }
 
+static enum mem_cgroup_filter_t
+mem_cgroup_filter(struct mem_cgroup *memcg, struct mem_cgroup *root,
+               mem_cgroup_iter_filter cond)
+{
+       if (!cond)
+               return VISIT;
+       return cond(memcg, root);
+}
+
 /*
  * Returns a next (in a pre-order walk) alive memcg (with elevated css
  * ref. count) or NULL if the whole root's subtree has been visited.
@@ -1075,7 +945,7 @@ struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
  * helper function to be used by mem_cgroup_iter
  */
 static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root,
-               struct mem_cgroup *last_visited)
+               struct mem_cgroup *last_visited, mem_cgroup_iter_filter cond)
 {
        struct cgroup_subsys_state *prev_css, *next_css;
 
@@ -1093,11 +963,31 @@ skip_node:
        if (next_css) {
                struct mem_cgroup *mem = mem_cgroup_from_css(next_css);
 
-               if (css_tryget(&mem->css))
-                       return mem;
-               else {
+               switch (mem_cgroup_filter(mem, root, cond)) {
+               case SKIP:
                        prev_css = next_css;
                        goto skip_node;
+               case SKIP_TREE:
+                       if (mem == root)
+                               return NULL;
+                       /*
+                        * css_rightmost_descendant is not an optimal way to
+                        * skip through a subtree (especially for imbalanced
+                        * trees leaning to right) but that's what we have right
+                        * now. More effective solution would be traversing
+                        * right-up for first non-NULL without calling
+                        * css_next_descendant_pre afterwards.
+                        */
+                       prev_css = css_rightmost_descendant(next_css);
+                       goto skip_node;
+               case VISIT:
+                       if (css_tryget(&mem->css))
+                               return mem;
+                       else {
+                               prev_css = next_css;
+                               goto skip_node;
+                       }
+                       break;
                }
        }
 
@@ -1161,6 +1051,7 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
  * @root: hierarchy root
  * @prev: previously returned memcg, NULL on first invocation
  * @reclaim: cookie for shared reclaim walks, NULL for full walks
+ * @cond: filter for visited nodes, NULL for no filter
  *
  * Returns references to children of the hierarchy below @root, or
  * @root itself, or %NULL after a full round-trip.
@@ -1173,15 +1064,18 @@ static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
  * divide up the memcgs in the hierarchy among all concurrent
  * reclaimers operating on the same zone and priority.
  */
-struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
+struct mem_cgroup *mem_cgroup_iter_cond(struct mem_cgroup *root,
                                   struct mem_cgroup *prev,
-                                  struct mem_cgroup_reclaim_cookie *reclaim)
+                                  struct mem_cgroup_reclaim_cookie *reclaim,
+                                  mem_cgroup_iter_filter cond)
 {
        struct mem_cgroup *memcg = NULL;
        struct mem_cgroup *last_visited = NULL;
 
-       if (mem_cgroup_disabled())
-               return NULL;
+       if (mem_cgroup_disabled()) {
+               /* first call must return non-NULL, second return NULL */
+               return (struct mem_cgroup *)(unsigned long)!prev;
+       }
 
        if (!root)
                root = root_mem_cgroup;
@@ -1192,7 +1086,9 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
        if (!root->use_hierarchy && root != root_mem_cgroup) {
                if (prev)
                        goto out_css_put;
-               return root;
+               if (mem_cgroup_filter(root, root, cond) == VISIT)
+                       return root;
+               return NULL;
        }
 
        rcu_read_lock();
@@ -1215,7 +1111,7 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                        last_visited = mem_cgroup_iter_load(iter, root, &seq);
                }
 
-               memcg = __mem_cgroup_iter_next(root, last_visited);
+               memcg = __mem_cgroup_iter_next(root, last_visited, cond);
 
                if (reclaim) {
                        mem_cgroup_iter_update(iter, last_visited, memcg, seq);
@@ -1226,7 +1122,11 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
                                reclaim->generation = iter->generation;
                }
 
-               if (prev && !memcg)
+               /*
+                * We have finished the whole tree walk or no group has been
+                * visited because filter told us to skip the root node.
+                */
+               if (!memcg && (prev || (cond && !last_visited)))
                        goto out_unlock;
        }
 out_unlock:
@@ -1867,6 +1767,7 @@ static unsigned long mem_cgroup_reclaim(struct mem_cgroup *memcg,
        return total;
 }
 
+#if MAX_NUMNODES > 1
 /**
  * test_mem_cgroup_node_reclaimable
  * @memcg: the target memcg
@@ -1889,7 +1790,6 @@ static bool test_mem_cgroup_node_reclaimable(struct mem_cgroup *memcg,
        return false;
 
 }
-#if MAX_NUMNODES > 1
 
 /*
  * Always updating the nodemask is not very good - even if we have an empty
@@ -1957,115 +1857,64 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
        return node;
 }
 
-/*
- * Check all nodes whether it contains reclaimable pages or not.
- * For quick scan, we make use of scan_nodes. This will allow us to skip
- * unused nodes. But scan_nodes is lazily updated and may not cotain
- * enough new information. We need to do double check.
- */
-static bool mem_cgroup_reclaimable(struct mem_cgroup *memcg, bool noswap)
-{
-       int nid;
-
-       /*
-        * quick check...making use of scan_node.
-        * We can skip unused nodes.
-        */
-       if (!nodes_empty(memcg->scan_nodes)) {
-               for (nid = first_node(memcg->scan_nodes);
-                    nid < MAX_NUMNODES;
-                    nid = next_node(nid, memcg->scan_nodes)) {
-
-                       if (test_mem_cgroup_node_reclaimable(memcg, nid, noswap))
-                               return true;
-               }
-       }
-       /*
-        * Check rest of nodes.
-        */
-       for_each_node_state(nid, N_MEMORY) {
-               if (node_isset(nid, memcg->scan_nodes))
-                       continue;
-               if (test_mem_cgroup_node_reclaimable(memcg, nid, noswap))
-                       return true;
-       }
-       return false;
-}
-
 #else
 int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
 {
        return 0;
 }
 
-static bool mem_cgroup_reclaimable(struct mem_cgroup *memcg, bool noswap)
-{
-       return test_mem_cgroup_node_reclaimable(memcg, 0, noswap);
-}
 #endif
 
-static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
-                                  struct zone *zone,
-                                  gfp_t gfp_mask,
-                                  unsigned long *total_scanned)
-{
-       struct mem_cgroup *victim = NULL;
-       int total = 0;
-       int loop = 0;
-       unsigned long excess;
-       unsigned long nr_scanned;
-       struct mem_cgroup_reclaim_cookie reclaim = {
-               .zone = zone,
-               .priority = 0,
-       };
-
-       excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT;
-
-       while (1) {
-               victim = mem_cgroup_iter(root_memcg, victim, &reclaim);
-               if (!victim) {
-                       loop++;
-                       if (loop >= 2) {
-                               /*
-                                * If we have not been able to reclaim
-                                * anything, it might because there are
-                                * no reclaimable pages under this hierarchy
-                                */
-                               if (!total)
-                                       break;
-                               /*
-                                * We want to do more targeted reclaim.
-                                * excess >> 2 is not to excessive so as to
-                                * reclaim too much, nor too less that we keep
-                                * coming back to reclaim from this cgroup
-                                */
-                               if (total >= (excess >> 2) ||
-                                       (loop > MEM_CGROUP_MAX_RECLAIM_LOOPS))
-                                       break;
-                       }
-                       continue;
-               }
-               if (!mem_cgroup_reclaimable(victim, false))
-                       continue;
-               total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false,
-                                                    zone, &nr_scanned);
-               *total_scanned += nr_scanned;
-               if (!res_counter_soft_limit_excess(&root_memcg->res))
+/*
+ * A group is eligible for the soft limit reclaim under the given root
+ * hierarchy if
+ *     a) it is over its soft limit
+ *     b) any parent up the hierarchy is over its soft limit
+ *
+ * If the given group doesn't have any children over the limit then it
+ * doesn't make any sense to iterate its subtree.
+ */
+enum mem_cgroup_filter_t
+mem_cgroup_soft_reclaim_eligible(struct mem_cgroup *memcg,
+               struct mem_cgroup *root)
+{
+       struct mem_cgroup *parent;
+
+       if (!memcg)
+               memcg = root_mem_cgroup;
+       parent = memcg;
+
+       if (res_counter_soft_limit_excess(&memcg->res))
+               return VISIT;
+
+       /*
+        * If any parent up to the root in the hierarchy is over its soft limit
+        * then we have to obey and reclaim from this group as well.
+        */
+       while ((parent = parent_mem_cgroup(parent))) {
+               if (res_counter_soft_limit_excess(&parent->res))
+                       return VISIT;
+               if (parent == root)
                        break;
        }
-       mem_cgroup_iter_break(root_memcg, victim);
-       return total;
+
+       if (!atomic_read(&memcg->children_in_excess))
+               return SKIP_TREE;
+       return SKIP;
 }
 
+static DEFINE_SPINLOCK(memcg_oom_lock);
+
 /*
  * Check OOM-Killer is already running under our hierarchy.
  * If someone is running, return false.
- * Has to be called with memcg_oom_lock
  */
-static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg)
+static bool mem_cgroup_oom_trylock(struct mem_cgroup *memcg)
 {
        struct mem_cgroup *iter, *failed = NULL;
 
+       spin_lock(&memcg_oom_lock);
+
        for_each_mem_cgroup_tree(iter, memcg) {
                if (iter->oom_lock) {
                        /*
@@ -2079,33 +1928,33 @@ static bool mem_cgroup_oom_lock(struct mem_cgroup *memcg)
                        iter->oom_lock = true;
        }
 
-       if (!failed)
-               return true;
-
-       /*
-        * OK, we failed to lock the whole subtree so we have to clean up
-        * what we set up to the failing subtree
-        */
-       for_each_mem_cgroup_tree(iter, memcg) {
-               if (iter == failed) {
-                       mem_cgroup_iter_break(memcg, iter);
-                       break;
+       if (failed) {
+               /*
+                * OK, we failed to lock the whole subtree so we have
+                * to clean up what we set up to the failing subtree
+                */
+               for_each_mem_cgroup_tree(iter, memcg) {
+                       if (iter == failed) {
+                               mem_cgroup_iter_break(memcg, iter);
+                               break;
+                       }
+                       iter->oom_lock = false;
                }
-               iter->oom_lock = false;
        }
-       return false;
+
+       spin_unlock(&memcg_oom_lock);
+
+       return !failed;
 }
 
-/*
- * Has to be called with memcg_oom_lock
- */
-static int mem_cgroup_oom_unlock(struct mem_cgroup *memcg)
+static void mem_cgroup_oom_unlock(struct mem_cgroup *memcg)
 {
        struct mem_cgroup *iter;
 
+       spin_lock(&memcg_oom_lock);
        for_each_mem_cgroup_tree(iter, memcg)
                iter->oom_lock = false;
-       return 0;
+       spin_unlock(&memcg_oom_lock);
 }
 
 static void mem_cgroup_mark_under_oom(struct mem_cgroup *memcg)
@@ -2129,7 +1978,6 @@ static void mem_cgroup_unmark_under_oom(struct mem_cgroup *memcg)
                atomic_add_unless(&iter->under_oom, -1, 0);
 }
 
-static DEFINE_SPINLOCK(memcg_oom_lock);
 static DECLARE_WAIT_QUEUE_HEAD(memcg_oom_waitq);
 
 struct oom_wait_info {
@@ -2159,6 +2007,7 @@ static int memcg_oom_wake_function(wait_queue_t *wait,
 
 static void memcg_wakeup_oom(struct mem_cgroup *memcg)
 {
+       atomic_inc(&memcg->oom_wakeups);
        /* for filtering, pass "memcg" as argument. */
        __wake_up(&memcg_oom_waitq, TASK_NORMAL, 0, memcg);
 }
@@ -2170,56 +2019,136 @@ static void memcg_oom_recover(struct mem_cgroup *memcg)
 }
 
 /*
- * try to call OOM killer. returns false if we should exit memory-reclaim loop.
+ * try to call OOM killer
  */
-static bool mem_cgroup_handle_oom(struct mem_cgroup *memcg, gfp_t mask,
-                                 int order)
+static void mem_cgroup_oom(struct mem_cgroup *memcg, gfp_t mask, int order)
 {
-       struct oom_wait_info owait;
-       bool locked, need_to_kill;
+       bool locked;
+       int wakeups;
 
-       owait.memcg = memcg;
-       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;
-       mem_cgroup_mark_under_oom(memcg);
+       if (!current->memcg_oom.may_oom)
+               return;
+
+       current->memcg_oom.in_memcg_oom = 1;
 
-       /* At first, try to OOM lock hierarchy under memcg.*/
-       spin_lock(&memcg_oom_lock);
-       locked = mem_cgroup_oom_lock(memcg);
        /*
-        * Even if signal_pending(), we can't quit charge() loop without
-        * accounting. So, UNINTERRUPTIBLE is appropriate. But SIGKILL
-        * under OOM is always welcomed, use TASK_KILLABLE here.
+        * As with any blocking lock, a contender needs to start
+        * listening for wakeups before attempting the trylock,
+        * otherwise it can miss the wakeup from the unlock and sleep
+        * indefinitely.  This is just open-coded because our locking
+        * is so particular to memcg hierarchies.
         */
-       prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE);
-       if (!locked || memcg->oom_kill_disable)
-               need_to_kill = false;
+       wakeups = atomic_read(&memcg->oom_wakeups);
+       mem_cgroup_mark_under_oom(memcg);
+
+       locked = mem_cgroup_oom_trylock(memcg);
+
        if (locked)
                mem_cgroup_oom_notify(memcg);
-       spin_unlock(&memcg_oom_lock);
 
-       if (need_to_kill) {
-               finish_wait(&memcg_oom_waitq, &owait.wait);
+       if (locked && !memcg->oom_kill_disable) {
+               mem_cgroup_unmark_under_oom(memcg);
                mem_cgroup_out_of_memory(memcg, mask, order);
+               mem_cgroup_oom_unlock(memcg);
+               /*
+                * There is no guarantee that an OOM-lock contender
+                * sees the wakeups triggered by the OOM kill
+                * uncharges.  Wake any sleepers explicitely.
+                */
+               memcg_oom_recover(memcg);
        } else {
-               schedule();
-               finish_wait(&memcg_oom_waitq, &owait.wait);
+               /*
+                * A system call can just return -ENOMEM, but if this
+                * is a page fault and somebody else is handling the
+                * OOM already, we need to sleep on the OOM waitqueue
+                * for this memcg until the situation is resolved.
+                * Which can take some time because it might be
+                * handled by a userspace task.
+                *
+                * However, this is the charge context, which means
+                * that we may sit on a large call stack and hold
+                * various filesystem locks, the mmap_sem etc. and we
+                * don't want the OOM handler to deadlock on them
+                * while we sit here and wait.  Store the current OOM
+                * context in the task_struct, then return -ENOMEM.
+                * At the end of the page fault handler, with the
+                * stack unwound, pagefault_out_of_memory() will check
+                * back with us by calling
+                * mem_cgroup_oom_synchronize(), possibly putting the
+                * task to sleep.
+                */
+               current->memcg_oom.oom_locked = locked;
+               current->memcg_oom.wakeups = wakeups;
+               css_get(&memcg->css);
+               current->memcg_oom.wait_on_memcg = memcg;
        }
-       spin_lock(&memcg_oom_lock);
-       if (locked)
-               mem_cgroup_oom_unlock(memcg);
-       memcg_wakeup_oom(memcg);
-       spin_unlock(&memcg_oom_lock);
+}
 
-       mem_cgroup_unmark_under_oom(memcg);
+/**
+ * mem_cgroup_oom_synchronize - complete memcg OOM handling
+ *
+ * This has to be called at the end of a page fault if the the memcg
+ * OOM handler was enabled and the fault is returning %VM_FAULT_OOM.
+ *
+ * Memcg supports userspace OOM handling, so failed allocations must
+ * sleep on a waitqueue until the userspace task resolves the
+ * situation.  Sleeping directly in the charge context with all kinds
+ * of locks held is not a good idea, instead we remember an OOM state
+ * in the task and mem_cgroup_oom_synchronize() has to be called at
+ * the end of the page fault to put the task to sleep and clean up the
+ * OOM state.
+ *
+ * Returns %true if an ongoing memcg OOM situation was detected and
+ * finalized, %false otherwise.
+ */
+bool mem_cgroup_oom_synchronize(void)
+{
+       struct oom_wait_info owait;
+       struct mem_cgroup *memcg;
 
-       if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
+       /* OOM is global, do not handle */
+       if (!current->memcg_oom.in_memcg_oom)
                return false;
-       /* Give chance to dying process */
-       schedule_timeout_uninterruptible(1);
+
+       /*
+        * We invoked the OOM killer but there is a chance that a kill
+        * did not free up any charges.  Everybody else might already
+        * be sleeping, so restart the fault and keep the rampage
+        * going until some charges are released.
+        */
+       memcg = current->memcg_oom.wait_on_memcg;
+       if (!memcg)
+               goto out;
+
+       if (test_thread_flag(TIF_MEMDIE) || fatal_signal_pending(current))
+               goto out_memcg;
+
+       owait.memcg = memcg;
+       owait.wait.flags = 0;
+       owait.wait.func = memcg_oom_wake_function;
+       owait.wait.private = current;
+       INIT_LIST_HEAD(&owait.wait.task_list);
+
+       prepare_to_wait(&memcg_oom_waitq, &owait.wait, TASK_KILLABLE);
+       /* Only sleep if we didn't miss any wakeups since OOM */
+       if (atomic_read(&memcg->oom_wakeups) == current->memcg_oom.wakeups)
+               schedule();
+       finish_wait(&memcg_oom_waitq, &owait.wait);
+out_memcg:
+       mem_cgroup_unmark_under_oom(memcg);
+       if (current->memcg_oom.oom_locked) {
+               mem_cgroup_oom_unlock(memcg);
+               /*
+                * There is no guarantee that an OOM-lock contender
+                * sees the wakeups triggered by the OOM kill
+                * uncharges.  Wake any sleepers explicitely.
+                */
+               memcg_oom_recover(memcg);
+       }
+       css_put(&memcg->css);
+       current->memcg_oom.wait_on_memcg = NULL;
+out:
+       current->memcg_oom.in_memcg_oom = 0;
        return true;
 }
 
@@ -2288,7 +2217,7 @@ void __mem_cgroup_end_update_page_stat(struct page *page, unsigned long *flags)
 }
 
 void mem_cgroup_update_page_stat(struct page *page,
-                                enum mem_cgroup_page_stat_item idx, int val)
+                                enum mem_cgroup_stat_index idx, int val)
 {
        struct mem_cgroup *memcg;
        struct page_cgroup *pc = lookup_page_cgroup(page);
@@ -2297,18 +2226,11 @@ void mem_cgroup_update_page_stat(struct page *page,
        if (mem_cgroup_disabled())
                return;
 
+       VM_BUG_ON(!rcu_read_lock_held());
        memcg = pc->mem_cgroup;
        if (unlikely(!memcg || !PageCgroupUsed(pc)))
                return;
 
-       switch (idx) {
-       case MEMCG_NR_FILE_MAPPED:
-               idx = MEM_CGROUP_STAT_FILE_MAPPED;
-               break;
-       default:
-               BUG();
-       }
-
        this_cpu_add(memcg->stat->count[idx], val);
 }
 
@@ -2450,7 +2372,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg, bool sync)
                        flush_work(&stock->work);
        }
 out:
-       put_online_cpus();
+       put_online_cpus();
 }
 
 /*
@@ -2532,12 +2454,11 @@ enum {
        CHARGE_RETRY,           /* need to retry but retry is not bad */
        CHARGE_NOMEM,           /* we can't do more. return -ENOMEM */
        CHARGE_WOULDBLOCK,      /* GFP_WAIT wasn't set and no enough res. */
-       CHARGE_OOM_DIE,         /* the current is killed because of OOM */
 };
 
 static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
                                unsigned int nr_pages, unsigned int min_pages,
-                               bool oom_check)
+                               bool invoke_oom)
 {
        unsigned long csize = nr_pages * PAGE_SIZE;
        struct mem_cgroup *mem_over_limit;
@@ -2594,14 +2515,10 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        if (mem_cgroup_wait_acct_move(mem_over_limit))
                return CHARGE_RETRY;
 
-       /* If we don't need to call oom-killer at el, return immediately */
-       if (!oom_check)
-               return CHARGE_NOMEM;
-       /* check OOM */
-       if (!mem_cgroup_handle_oom(mem_over_limit, gfp_mask, get_order(csize)))
-               return CHARGE_OOM_DIE;
+       if (invoke_oom)
+               mem_cgroup_oom(mem_over_limit, gfp_mask, get_order(csize));
 
-       return CHARGE_RETRY;
+       return CHARGE_NOMEM;
 }
 
 /*
@@ -2704,7 +2621,7 @@ again:
        }
 
        do {
-               bool oom_check;
+               bool invoke_oom = oom && !nr_oom_retries;
 
                /* If killed, bypass charge */
                if (fatal_signal_pending(current)) {
@@ -2712,14 +2629,8 @@ again:
                        goto bypass;
                }
 
-               oom_check = false;
-               if (oom && !nr_oom_retries) {
-                       oom_check = true;
-                       nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES;
-               }
-
-               ret = mem_cgroup_do_charge(memcg, gfp_mask, batch, nr_pages,
-                   oom_check);
+               ret = mem_cgroup_do_charge(memcg, gfp_mask, batch,
+                                          nr_pages, invoke_oom);
                switch (ret) {
                case CHARGE_OK:
                        break;
@@ -2732,16 +2643,12 @@ again:
                        css_put(&memcg->css);
                        goto nomem;
                case CHARGE_NOMEM: /* OOM routine works */
-                       if (!oom) {
+                       if (!oom || invoke_oom) {
                                css_put(&memcg->css);
                                goto nomem;
                        }
-                       /* If oom, we never return -ENOMEM */
                        nr_oom_retries--;
                        break;
-               case CHARGE_OOM_DIE: /* Killed by OOM Killer */
-                       css_put(&memcg->css);
-                       goto bypass;
                }
        } while (ret != CHARGE_OK);
 
@@ -2882,7 +2789,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
         * is accessed after testing USED bit. To make pc->mem_cgroup visible
         * before USED bit, we need memory barrier here.
         * See mem_cgroup_add_lru_list(), etc.
-        */
+        */
        smp_wmb();
        SetPageCgroupUsed(pc);
 
@@ -2905,9 +2812,7 @@ static void __mem_cgroup_commit_charge(struct mem_cgroup *memcg,
        unlock_page_cgroup(pc);
 
        /*
-        * "charge_statistics" updated event counter. Then, check it.
-        * Insert ancestor (and ancestor's ancestors), to softlimit RB-tree.
-        * if they exceeds softlimit.
+        * "charge_statistics" updated event counter.
         */
        memcg_check_events(memcg, page);
 }
@@ -3121,7 +3026,7 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
                ssize_t size = memcg_caches_array_size(num_groups);
 
                size *= sizeof(void *);
-               size += sizeof(struct memcg_cache_params);
+               size += offsetof(struct memcg_cache_params, memcg_caches);
 
                s->memcg_params = kzalloc(size, GFP_KERNEL);
                if (!s->memcg_params) {
@@ -3164,13 +3069,16 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
 int memcg_register_cache(struct mem_cgroup *memcg, struct kmem_cache *s,
                         struct kmem_cache *root_cache)
 {
-       size_t size = sizeof(struct memcg_cache_params);
+       size_t size;
 
        if (!memcg_kmem_enabled())
                return 0;
 
-       if (!memcg)
+       if (!memcg) {
+               size = offsetof(struct memcg_cache_params, memcg_caches);
                size += memcg_limited_groups_array_size * sizeof(void *);
+       } else
+               size = sizeof(struct memcg_cache_params);
 
        s->memcg_params = kzalloc(size, GFP_KERNEL);
        if (!s->memcg_params)
@@ -3623,9 +3531,9 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order)
         * the page allocator. Therefore, the following sequence when backed by
         * the SLUB allocator:
         *
-        *      memcg_stop_kmem_account();
-        *      kmalloc(<large_number>)
-        *      memcg_resume_kmem_account();
+        *      memcg_stop_kmem_account();
+        *      kmalloc(<large_number>)
+        *      memcg_resume_kmem_account();
         *
         * would effectively ignore the fact that we should skip accounting,
         * since it will drive us directly to this function without passing
@@ -3747,6 +3655,20 @@ void mem_cgroup_split_huge_fixup(struct page *head)
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
+static inline
+void mem_cgroup_move_account_page_stat(struct mem_cgroup *from,
+                                       struct mem_cgroup *to,
+                                       unsigned int nr_pages,
+                                       enum mem_cgroup_stat_index idx)
+{
+       /* Update stat data for mem_cgroup */
+       preempt_disable();
+       WARN_ON_ONCE(from->stat->count[idx] < nr_pages);
+       __this_cpu_add(from->stat->count[idx], -nr_pages);
+       __this_cpu_add(to->stat->count[idx], nr_pages);
+       preempt_enable();
+}
+
 /**
  * mem_cgroup_move_account - move account of the page
  * @page: the page
@@ -3792,13 +3714,14 @@ static int mem_cgroup_move_account(struct page *page,
 
        move_lock_mem_cgroup(from, &flags);
 
-       if (!anon && page_mapped(page)) {
-               /* Update mapped_file data for mem_cgroup */
-               preempt_disable();
-               __this_cpu_dec(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
-               __this_cpu_inc(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED]);
-               preempt_enable();
-       }
+       if (!anon && page_mapped(page))
+               mem_cgroup_move_account_page_stat(from, to, nr_pages,
+                       MEM_CGROUP_STAT_FILE_MAPPED);
+
+       if (PageWriteback(page))
+               mem_cgroup_move_account_page_stat(from, to, nr_pages,
+                       MEM_CGROUP_STAT_WRITEBACK);
+
        mem_cgroup_charge_statistics(from, page, anon, -nr_pages);
 
        /* caller should have done css_get */
@@ -4654,7 +4577,7 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                                   MEM_CGROUP_RECLAIM_SHRINK);
                curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
                /* Usage is reduced ? */
-               if (curusage >= oldusage)
+               if (curusage >= oldusage)
                        retry_count--;
                else
                        oldusage = curusage;
@@ -4675,7 +4598,7 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
        int enlarge = 0;
 
        /* see mem_cgroup_resize_res_limit */
-       retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
+       retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
        oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
        while (retry_count) {
                if (signal_pending(current)) {
@@ -4724,98 +4647,6 @@ static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
        return ret;
 }
 
-unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
-                                           gfp_t gfp_mask,
-                                           unsigned long *total_scanned)
-{
-       unsigned long nr_reclaimed = 0;
-       struct mem_cgroup_per_zone *mz, *next_mz = NULL;
-       unsigned long reclaimed;
-       int loop = 0;
-       struct mem_cgroup_tree_per_zone *mctz;
-       unsigned long long excess;
-       unsigned long nr_scanned;
-
-       if (order > 0)
-               return 0;
-
-       mctz = soft_limit_tree_node_zone(zone_to_nid(zone), zone_idx(zone));
-       /*
-        * This loop can run a while, specially if mem_cgroup's continuously
-        * keep exceeding their soft limit and putting the system under
-        * pressure
-        */
-       do {
-               if (next_mz)
-                       mz = next_mz;
-               else
-                       mz = mem_cgroup_largest_soft_limit_node(mctz);
-               if (!mz)
-                       break;
-
-               nr_scanned = 0;
-               reclaimed = mem_cgroup_soft_reclaim(mz->memcg, zone,
-                                                   gfp_mask, &nr_scanned);
-               nr_reclaimed += reclaimed;
-               *total_scanned += nr_scanned;
-               spin_lock(&mctz->lock);
-
-               /*
-                * If we failed to reclaim anything from this memory cgroup
-                * it is time to move on to the next cgroup
-                */
-               next_mz = NULL;
-               if (!reclaimed) {
-                       do {
-                               /*
-                                * Loop until we find yet another one.
-                                *
-                                * By the time we get the soft_limit lock
-                                * again, someone might have aded the
-                                * group back on the RB tree. Iterate to
-                                * make sure we get a different mem.
-                                * mem_cgroup_largest_soft_limit_node returns
-                                * NULL if no other cgroup is present on
-                                * the tree
-                                */
-                               next_mz =
-                               __mem_cgroup_largest_soft_limit_node(mctz);
-                               if (next_mz == mz)
-                                       css_put(&next_mz->memcg->css);
-                               else /* next_mz == NULL or other memcg */
-                                       break;
-                       } while (1);
-               }
-               __mem_cgroup_remove_exceeded(mz->memcg, mz, mctz);
-               excess = res_counter_soft_limit_excess(&mz->memcg->res);
-               /*
-                * One school of thought says that we should not add
-                * back the node to the tree if reclaim returns 0.
-                * But our reclaim could return 0, simply because due
-                * to priority we are exposing a smaller subset of
-                * memory to reclaim from. Consider this as a longer
-                * term TODO.
-                */
-               /* If excess == 0, no tree ops */
-               __mem_cgroup_insert_exceeded(mz->memcg, mz, mctz, excess);
-               spin_unlock(&mctz->lock);
-               css_put(&mz->memcg->css);
-               loop++;
-               /*
-                * Could not reclaim anything and there are no more
-                * mem cgroups to try or we seem to be looping without
-                * reclaiming anything.
-                */
-               if (!nr_reclaimed &&
-                       (next_mz == NULL ||
-                       loop > MEM_CGROUP_MAX_SOFT_LIMIT_RECLAIM_LOOPS))
-                       break;
-       } while (!nr_reclaimed);
-       if (next_mz)
-               css_put(&next_mz->memcg->css);
-       return nr_reclaimed;
-}
-
 /**
  * mem_cgroup_force_empty_list - clears LRU of a group
  * @memcg: group to clear
@@ -4987,18 +4818,12 @@ static int mem_cgroup_force_empty_write(struct cgroup_subsys_state *css,
                                        unsigned int event)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
-       int ret;
 
        if (mem_cgroup_is_root(memcg))
                return -EINVAL;
-       css_get(&memcg->css);
-       ret = mem_cgroup_force_empty(memcg);
-       css_put(&memcg->css);
-
-       return ret;
+       return mem_cgroup_force_empty(memcg);
 }
 
-
 static u64 mem_cgroup_hierarchy_read(struct cgroup_subsys_state *css,
                                     struct cftype *cft)
 {
@@ -5136,7 +4961,7 @@ static int memcg_update_kmem_limit(struct cgroup_subsys_state *css, u64 val)
         */
        mutex_lock(&memcg_create_mutex);
        mutex_lock(&set_limit_mutex);
-       if (!memcg->kmem_account_flags && val != RESOURCE_MAX) {
+       if (!memcg->kmem_account_flags && val != RES_COUNTER_MAX) {
                if (cgroup_task_count(css->cgroup) || memcg_has_children(memcg)) {
                        ret = -EBUSY;
                        goto out;
@@ -5146,7 +4971,7 @@ static int memcg_update_kmem_limit(struct cgroup_subsys_state *css, u64 val)
 
                ret = memcg_update_cache_sizes(memcg);
                if (ret) {
-                       res_counter_set_limit(&memcg->kmem, RESOURCE_MAX);
+                       res_counter_set_limit(&memcg->kmem, RES_COUNTER_MAX);
                        goto out;
                }
                static_key_slow_inc(&memcg_kmem_enabled_key);
@@ -5588,7 +5413,13 @@ static int compare_thresholds(const void *a, const void *b)
        const struct mem_cgroup_threshold *_a = a;
        const struct mem_cgroup_threshold *_b = b;
 
-       return _a->threshold - _b->threshold;
+       if (_a->threshold > _b->threshold)
+               return 1;
+
+       if (_a->threshold < _b->threshold)
+               return -1;
+
+       return 0;
 }
 
 static int mem_cgroup_oom_notify_cb(struct mem_cgroup *memcg)
@@ -6080,8 +5911,6 @@ static int alloc_mem_cgroup_per_zone_info(struct mem_cgroup *memcg, int node)
        for (zone = 0; zone < MAX_NR_ZONES; zone++) {
                mz = &pn->zoneinfo[zone];
                lruvec_init(&mz->lruvec);
-               mz->usage_in_excess = 0;
-               mz->on_tree = false;
                mz->memcg = memcg;
        }
        memcg->nodeinfo[node] = pn;
@@ -6137,7 +5966,6 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
        int node;
        size_t size = memcg_size();
 
-       mem_cgroup_remove_from_trees(memcg);
        free_css_id(&mem_cgroup_subsys, &memcg->css);
 
        for_each_node(node)
@@ -6174,29 +6002,6 @@ struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
 }
 EXPORT_SYMBOL(parent_mem_cgroup);
 
-static void __init mem_cgroup_soft_limit_tree_init(void)
-{
-       struct mem_cgroup_tree_per_node *rtpn;
-       struct mem_cgroup_tree_per_zone *rtpz;
-       int tmp, node, zone;
-
-       for_each_node(node) {
-               tmp = node;
-               if (!node_state(node, N_NORMAL_MEMORY))
-                       tmp = -1;
-               rtpn = kzalloc_node(sizeof(*rtpn), GFP_KERNEL, tmp);
-               BUG_ON(!rtpn);
-
-               soft_limit_tree.rb_tree_per_node[node] = rtpn;
-
-               for (zone = 0; zone < MAX_NR_ZONES; zone++) {
-                       rtpz = &rtpn->rb_tree_per_zone[zone];
-                       rtpz->rb_root = RB_ROOT;
-                       spin_lock_init(&rtpz->lock);
-               }
-       }
-}
-
 static struct cgroup_subsys_state * __ref
 mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
 {
@@ -6226,6 +6031,7 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
        mutex_init(&memcg->thresholds_lock);
        spin_lock_init(&memcg->move_lock);
        vmpressure_init(&memcg->vmpressure);
+       spin_lock_init(&memcg->soft_lock);
 
        return &memcg->css;
 
@@ -6303,6 +6109,13 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
 
        mem_cgroup_invalidate_reclaim_iterators(memcg);
        mem_cgroup_reparent_charges(memcg);
+       if (memcg->soft_contributed) {
+               while ((memcg = parent_mem_cgroup(memcg)))
+                       atomic_dec(&memcg->children_in_excess);
+
+               if (memcg != root_mem_cgroup && !root_mem_cgroup->use_hierarchy)
+                       atomic_dec(&root_mem_cgroup->children_in_excess);
+       }
        mem_cgroup_destroy_all_caches(memcg);
        vmpressure_cleanup(&memcg->vmpressure);
 }
@@ -6977,7 +6790,6 @@ static int __init mem_cgroup_init(void)
 {
        hotcpu_notifier(memcg_cpu_hotplug_callback, 0);
        enable_swap_cgroup();
-       mem_cgroup_soft_limit_tree_init();
        memcg_stock_init();
        return 0;
 }
index d84c5e5331bb5199632f46fda6d3ca3fef9dbaf4..947ed5413279261a830eeaeb42d9392aea0f8fa8 100644 (file)
@@ -206,7 +206,7 @@ static int kill_proc(struct task_struct *t, unsigned long addr, int trapno,
 #ifdef __ARCH_SI_TRAPNO
        si.si_trapno = trapno;
 #endif
-       si.si_addr_lsb = compound_trans_order(compound_head(page)) + PAGE_SHIFT;
+       si.si_addr_lsb = compound_order(compound_head(page)) + PAGE_SHIFT;
 
        if ((flags & MF_ACTION_REQUIRED) && t == current) {
                si.si_code = BUS_MCEERR_AR;
@@ -248,10 +248,12 @@ void shake_page(struct page *p, int access)
         */
        if (access) {
                int nr;
+               int nid = page_to_nid(p);
                do {
                        struct shrink_control shrink = {
                                .gfp_mask = GFP_KERNEL,
                        };
+                       node_set(nid, shrink.nodes_to_scan);
 
                        nr = shrink_slab(&shrink, 1000, 1000);
                        if (page_count(p) == 1)
@@ -983,7 +985,7 @@ static int hwpoison_user_mappings(struct page *p, unsigned long pfn,
 static void set_page_hwpoison_huge_page(struct page *hpage)
 {
        int i;
-       int nr_pages = 1 << compound_trans_order(hpage);
+       int nr_pages = 1 << compound_order(hpage);
        for (i = 0; i < nr_pages; i++)
                SetPageHWPoison(hpage + i);
 }
@@ -991,7 +993,7 @@ static void set_page_hwpoison_huge_page(struct page *hpage)
 static void clear_page_hwpoison_huge_page(struct page *hpage)
 {
        int i;
-       int nr_pages = 1 << compound_trans_order(hpage);
+       int nr_pages = 1 << compound_order(hpage);
        for (i = 0; i < nr_pages; i++)
                ClearPageHWPoison(hpage + i);
 }
@@ -1204,6 +1206,9 @@ int memory_failure(unsigned long pfn, int trapno, int flags)
        for (ps = error_states;; ps++)
                if ((p->flags & ps->mask) == ps->res)
                        break;
+
+       page_flags |= (p->flags & (1UL << PG_dirty));
+
        if (!ps->mask)
                for (ps = error_states;; ps++)
                        if ((page_flags & ps->mask) == ps->res)
@@ -1339,7 +1344,17 @@ int unpoison_memory(unsigned long pfn)
                return 0;
        }
 
-       nr_pages = 1 << compound_trans_order(page);
+       /*
+        * unpoison_memory() can encounter thp only when the thp is being
+        * worked by memory_failure() and the page lock is not held yet.
+        * In such case, we yield to memory_failure() and make unpoison fail.
+        */
+       if (PageTransHuge(page)) {
+               pr_info("MCE: Memory failure is now running on %#lx\n", pfn);
+                       return 0;
+       }
+
+       nr_pages = 1 << compound_order(page);
 
        if (!get_page_unless_zero(page)) {
                /*
@@ -1353,7 +1368,7 @@ int unpoison_memory(unsigned long pfn)
                        return 0;
                }
                if (TestClearPageHWPoison(p))
-                       atomic_long_sub(nr_pages, &num_poisoned_pages);
+                       atomic_long_dec(&num_poisoned_pages);
                pr_info("MCE: Software-unpoisoned free page %#lx\n", pfn);
                return 0;
        }
@@ -1375,7 +1390,7 @@ int unpoison_memory(unsigned long pfn)
        unlock_page(page);
 
        put_page(page);
-       if (freeit)
+       if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1))
                put_page(page);
 
        return 0;
@@ -1416,7 +1431,8 @@ static int __get_any_page(struct page *p, unsigned long pfn, int flags)
         * was free. This flag should be kept set until the source page
         * is freed and PG_hwpoison on it is set.
         */
-       set_migratetype_isolate(p, true);
+       if (get_pageblock_migratetype(p) != MIGRATE_ISOLATE)
+               set_migratetype_isolate(p, true);
        /*
         * When the target page is a free hugepage, just remove it
         * from free hugepage list.
@@ -1470,6 +1486,7 @@ static int soft_offline_huge_page(struct page *page, int flags)
        int ret;
        unsigned long pfn = page_to_pfn(page);
        struct page *hpage = compound_head(page);
+       LIST_HEAD(pagelist);
 
        /*
         * This double-check of PageHWPoison is to avoid the race with
@@ -1485,86 +1502,29 @@ static int soft_offline_huge_page(struct page *page, int flags)
        unlock_page(hpage);
 
        /* Keep page count to indicate a given hugepage is isolated. */
-       ret = migrate_huge_page(hpage, new_page, MPOL_MF_MOVE_ALL,
-                               MIGRATE_SYNC);
-       put_page(hpage);
+       list_move(&hpage->lru, &pagelist);
+       ret = migrate_pages(&pagelist, new_page, MPOL_MF_MOVE_ALL,
+                               MIGRATE_SYNC, MR_MEMORY_FAILURE);
        if (ret) {
                pr_info("soft offline: %#lx: migration failed %d, type %lx\n",
                        pfn, ret, page->flags);
+               /*
+                * We know that soft_offline_huge_page() tries to migrate
+                * only one hugepage pointed to by hpage, so we need not
+                * run through the pagelist here.
+                */
+               putback_active_hugepage(hpage);
+               if (ret > 0)
+                       ret = -EIO;
        } else {
                set_page_hwpoison_huge_page(hpage);
                dequeue_hwpoisoned_huge_page(hpage);
-               atomic_long_add(1 << compound_trans_order(hpage),
+               atomic_long_add(1 << compound_order(hpage),
                                &num_poisoned_pages);
        }
        return ret;
 }
 
-static int __soft_offline_page(struct page *page, int flags);
-
-/**
- * soft_offline_page - Soft offline a page.
- * @page: page to offline
- * @flags: flags. Same as memory_failure().
- *
- * Returns 0 on success, otherwise negated errno.
- *
- * Soft offline a page, by migration or invalidation,
- * without killing anything. This is for the case when
- * a page is not corrupted yet (so it's still valid to access),
- * but has had a number of corrected errors and is better taken
- * out.
- *
- * The actual policy on when to do that is maintained by
- * user space.
- *
- * This should never impact any application or cause data loss,
- * however it might take some time.
- *
- * This is not a 100% solution for all memory, but tries to be
- * ``good enough'' for the majority of memory.
- */
-int soft_offline_page(struct page *page, int flags)
-{
-       int ret;
-       unsigned long pfn = page_to_pfn(page);
-       struct page *hpage = compound_trans_head(page);
-
-       if (PageHWPoison(page)) {
-               pr_info("soft offline: %#lx page already poisoned\n", pfn);
-               return -EBUSY;
-       }
-       if (!PageHuge(page) && PageTransHuge(hpage)) {
-               if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
-                       pr_info("soft offline: %#lx: failed to split THP\n",
-                               pfn);
-                       return -EBUSY;
-               }
-       }
-
-       ret = get_any_page(page, pfn, flags);
-       if (ret < 0)
-               return ret;
-       if (ret) { /* for in-use pages */
-               if (PageHuge(page))
-                       ret = soft_offline_huge_page(page, flags);
-               else
-                       ret = __soft_offline_page(page, flags);
-       } else { /* for free pages */
-               if (PageHuge(page)) {
-                       set_page_hwpoison_huge_page(hpage);
-                       dequeue_hwpoisoned_huge_page(hpage);
-                       atomic_long_add(1 << compound_trans_order(hpage),
-                                       &num_poisoned_pages);
-               } else {
-                       SetPageHWPoison(page);
-                       atomic_long_inc(&num_poisoned_pages);
-               }
-       }
-       unset_migratetype_isolate(page, MIGRATE_MOVABLE);
-       return ret;
-}
-
 static int __soft_offline_page(struct page *page, int flags)
 {
        int ret;
@@ -1651,3 +1611,67 @@ static int __soft_offline_page(struct page *page, int flags)
        }
        return ret;
 }
+
+/**
+ * soft_offline_page - Soft offline a page.
+ * @page: page to offline
+ * @flags: flags. Same as memory_failure().
+ *
+ * Returns 0 on success, otherwise negated errno.
+ *
+ * Soft offline a page, by migration or invalidation,
+ * without killing anything. This is for the case when
+ * a page is not corrupted yet (so it's still valid to access),
+ * but has had a number of corrected errors and is better taken
+ * out.
+ *
+ * The actual policy on when to do that is maintained by
+ * user space.
+ *
+ * This should never impact any application or cause data loss,
+ * however it might take some time.
+ *
+ * This is not a 100% solution for all memory, but tries to be
+ * ``good enough'' for the majority of memory.
+ */
+int soft_offline_page(struct page *page, int flags)
+{
+       int ret;
+       unsigned long pfn = page_to_pfn(page);
+       struct page *hpage = compound_trans_head(page);
+
+       if (PageHWPoison(page)) {
+               pr_info("soft offline: %#lx page already poisoned\n", pfn);
+               return -EBUSY;
+       }
+       if (!PageHuge(page) && PageTransHuge(hpage)) {
+               if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) {
+                       pr_info("soft offline: %#lx: failed to split THP\n",
+                               pfn);
+                       return -EBUSY;
+               }
+       }
+
+       ret = get_any_page(page, pfn, flags);
+       if (ret < 0)
+               goto unset;
+       if (ret) { /* for in-use pages */
+               if (PageHuge(page))
+                       ret = soft_offline_huge_page(page, flags);
+               else
+                       ret = __soft_offline_page(page, flags);
+       } else { /* for free pages */
+               if (PageHuge(page)) {
+                       set_page_hwpoison_huge_page(hpage);
+                       dequeue_hwpoisoned_huge_page(hpage);
+                       atomic_long_add(1 << compound_order(hpage),
+                                       &num_poisoned_pages);
+               } else {
+                       SetPageHWPoison(page);
+                       atomic_long_inc(&num_poisoned_pages);
+               }
+       }
+unset:
+       unset_migratetype_isolate(page, MIGRATE_MOVABLE);
+       return ret;
+}
index b3c6bf9a398e9b13f7c5bb1130a72e67034faf75..ca00039471152eae75bb8321a129a4edfc6f580e 100644 (file)
@@ -372,30 +372,6 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)
 
 #endif /* CONFIG_HAVE_RCU_TABLE_FREE */
 
-/*
- * If a p?d_bad entry is found while walking page tables, report
- * the error, before resetting entry to p?d_none.  Usually (but
- * very seldom) called out from the p?d_none_or_clear_bad macros.
- */
-
-void pgd_clear_bad(pgd_t *pgd)
-{
-       pgd_ERROR(*pgd);
-       pgd_clear(pgd);
-}
-
-void pud_clear_bad(pud_t *pud)
-{
-       pud_ERROR(*pud);
-       pud_clear(pud);
-}
-
-void pmd_clear_bad(pmd_t *pmd)
-{
-       pmd_ERROR(*pmd);
-       pmd_clear(pmd);
-}
-
 /*
  * Note: this doesn't free the actual pages themselves. That
  * has been handled earlier when unmapping all the memory regions.
@@ -1505,7 +1481,8 @@ struct page *follow_page_mask(struct vm_area_struct *vma,
        if (pud_none(*pud))
                goto no_page_table;
        if (pud_huge(*pud) && vma->vm_flags & VM_HUGETLB) {
-               BUG_ON(flags & FOLL_GET);
+               if (flags & FOLL_GET)
+                       goto out;
                page = follow_huge_pud(mm, address, pud, flags & FOLL_WRITE);
                goto out;
        }
@@ -1516,8 +1493,20 @@ struct page *follow_page_mask(struct vm_area_struct *vma,
        if (pmd_none(*pmd))
                goto no_page_table;
        if (pmd_huge(*pmd) && vma->vm_flags & VM_HUGETLB) {
-               BUG_ON(flags & FOLL_GET);
                page = follow_huge_pmd(mm, address, pmd, flags & FOLL_WRITE);
+               if (flags & FOLL_GET) {
+                       /*
+                        * Refcount on tail pages are not well-defined and
+                        * shouldn't be taken. The caller should handle a NULL
+                        * return when trying to follow tail pages.
+                        */
+                       if (PageHead(page))
+                               get_page(page);
+                       else {
+                               page = NULL;
+                               goto out;
+                       }
+               }
                goto out;
        }
        if ((flags & FOLL_NUMA) && pmd_numa(*pmd))
@@ -3706,7 +3695,7 @@ static int do_pmd_numa_page(struct mm_struct *mm, struct vm_area_struct *vma,
  * but allow concurrent faults), and pte mapped but not yet locked.
  * We return with mmap_sem still held, but pte unmapped and unlocked.
  */
-int handle_pte_fault(struct mm_struct *mm,
+static int handle_pte_fault(struct mm_struct *mm,
                     struct vm_area_struct *vma, unsigned long address,
                     pte_t *pte, pmd_t *pmd, unsigned int flags)
 {
@@ -3765,22 +3754,14 @@ unlock:
 /*
  * By the time we get here, we already hold the mm semaphore
  */
-int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
-               unsigned long address, unsigned int flags)
+static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+                            unsigned long address, unsigned int flags)
 {
        pgd_t *pgd;
        pud_t *pud;
        pmd_t *pmd;
        pte_t *pte;
 
-       __set_current_state(TASK_RUNNING);
-
-       count_vm_event(PGFAULT);
-       mem_cgroup_count_vm_event(mm, PGFAULT);
-
-       /* do counter updates before entering really critical section. */
-       check_sync_rss_stat(current);
-
        if (unlikely(is_vm_hugetlb_page(vma)))
                return hugetlb_fault(mm, vma, address, flags);
 
@@ -3793,9 +3774,12 @@ retry:
        if (!pmd)
                return VM_FAULT_OOM;
        if (pmd_none(*pmd) && transparent_hugepage_enabled(vma)) {
+               int ret = VM_FAULT_FALLBACK;
                if (!vma->vm_ops)
-                       return do_huge_pmd_anonymous_page(mm, vma, address,
-                                                         pmd, flags);
+                       ret = do_huge_pmd_anonymous_page(mm, vma, address,
+                                       pmd, flags);
+               if (!(ret & VM_FAULT_FALLBACK))
+                       return ret;
        } else {
                pmd_t orig_pmd = *pmd;
                int ret;
@@ -3861,6 +3845,37 @@ retry:
        return handle_pte_fault(mm, vma, address, pte, pmd, flags);
 }
 
+int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
+                   unsigned long address, unsigned int flags)
+{
+       int ret;
+
+       __set_current_state(TASK_RUNNING);
+
+       count_vm_event(PGFAULT);
+       mem_cgroup_count_vm_event(mm, PGFAULT);
+
+       /* do counter updates before entering really critical section. */
+       check_sync_rss_stat(current);
+
+       /*
+        * Enable the memcg OOM handling for faults triggered in user
+        * space.  Kernel faults are handled more gracefully.
+        */
+       if (flags & FAULT_FLAG_USER)
+               mem_cgroup_enable_oom();
+
+       ret = __handle_mm_fault(mm, vma, address, flags);
+
+       if (flags & FAULT_FLAG_USER)
+               mem_cgroup_disable_oom();
+
+       if (WARN_ON(task_in_memcg_oom(current) && !(ret & VM_FAULT_OOM)))
+               mem_cgroup_oom_synchronize();
+
+       return ret;
+}
+
 #ifndef __PAGETABLE_PUD_FOLDED
 /*
  * Allocate page upper directory.
index ca1dd3aa5eee89a924da879735d59b26cd96387f..ed85fe3870e2c5d0094d47c7aa1086084d98235e 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mm_inline.h>
 #include <linux/firmware-map.h>
 #include <linux/stop_machine.h>
+#include <linux/hugetlb.h>
 
 #include <asm/tlbflush.h>
 
@@ -51,14 +52,10 @@ DEFINE_MUTEX(mem_hotplug_mutex);
 void lock_memory_hotplug(void)
 {
        mutex_lock(&mem_hotplug_mutex);
-
-       /* for exclusive hibernation if CONFIG_HIBERNATION=y */
-       lock_system_sleep();
 }
 
 void unlock_memory_hotplug(void)
 {
-       unlock_system_sleep();
        mutex_unlock(&mem_hotplug_mutex);
 }
 
@@ -194,7 +191,7 @@ void register_page_bootmem_info_node(struct pglist_data *pgdat)
 
        zone = &pgdat->node_zones[0];
        for (; zone < pgdat->node_zones + MAX_NR_ZONES - 1; zone++) {
-               if (zone->wait_table) {
+               if (zone_is_initialized(zone)) {
                        nr_pages = zone->wait_table_hash_nr_entries
                                * sizeof(wait_queue_head_t);
                        nr_pages = PAGE_ALIGN(nr_pages) >> PAGE_SHIFT;
@@ -229,8 +226,8 @@ static void grow_zone_span(struct zone *zone, unsigned long start_pfn,
 
        zone_span_writelock(zone);
 
-       old_zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
-       if (!zone->spanned_pages || start_pfn < zone->zone_start_pfn)
+       old_zone_end_pfn = zone_end_pfn(zone);
+       if (zone_is_empty(zone) || start_pfn < zone->zone_start_pfn)
                zone->zone_start_pfn = start_pfn;
 
        zone->spanned_pages = max(old_zone_end_pfn, end_pfn) -
@@ -305,7 +302,7 @@ static int __meminit move_pfn_range_left(struct zone *z1, struct zone *z2,
                goto out_fail;
 
        /* use start_pfn for z1's start_pfn if z1 is empty */
-       if (z1->spanned_pages)
+       if (!zone_is_empty(z1))
                z1_start_pfn = z1->zone_start_pfn;
        else
                z1_start_pfn = start_pfn;
@@ -347,7 +344,7 @@ static int __meminit move_pfn_range_right(struct zone *z1, struct zone *z2,
                goto out_fail;
 
        /* use end_pfn for z2's end_pfn if z2 is empty */
-       if (z2->spanned_pages)
+       if (!zone_is_empty(z2))
                z2_end_pfn = zone_end_pfn(z2);
        else
                z2_end_pfn = end_pfn;
@@ -514,8 +511,9 @@ static int find_biggest_section_pfn(int nid, struct zone *zone,
 static void shrink_zone_span(struct zone *zone, unsigned long start_pfn,
                             unsigned long end_pfn)
 {
-       unsigned long zone_start_pfn =  zone->zone_start_pfn;
-       unsigned long zone_end_pfn = zone->zone_start_pfn + zone->spanned_pages;
+       unsigned long zone_start_pfn = zone->zone_start_pfn;
+       unsigned long z = zone_end_pfn(zone); /* zone_end_pfn namespace clash */
+       unsigned long zone_end_pfn = z;
        unsigned long pfn;
        struct mem_section *ms;
        int nid = zone_to_nid(zone);
@@ -1069,6 +1067,23 @@ out:
        return ret;
 }
 
+static int check_hotplug_memory_range(u64 start, u64 size)
+{
+       u64 start_pfn = start >> PAGE_SHIFT;
+       u64 nr_pages = size >> PAGE_SHIFT;
+
+       /* Memory range must be aligned with section */
+       if ((start_pfn & ~PAGE_SECTION_MASK) ||
+           (nr_pages % PAGES_PER_SECTION) || (!nr_pages)) {
+               pr_err("Section-unaligned hotplug range: start 0x%llx, size 0x%llx\n",
+                               (unsigned long long)start,
+                               (unsigned long long)size);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 /* we are OK calling __meminit stuff here - we have CONFIG_MEMORY_HOTPLUG */
 int __ref add_memory(int nid, u64 start, u64 size)
 {
@@ -1078,6 +1093,10 @@ int __ref add_memory(int nid, u64 start, u64 size)
        struct resource *res;
        int ret;
 
+       ret = check_hotplug_memory_range(start, size);
+       if (ret)
+               return ret;
+
        lock_memory_hotplug();
 
        res = register_memory_resource(start, size);
@@ -1208,10 +1227,12 @@ static int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
 }
 
 /*
- * Scanning pfn is much easier than scanning lru list.
- * Scan pfn from start to end and Find LRU page.
+ * Scan pfn range [start,end) to find movable/migratable pages (LRU pages
+ * and hugepages). We scan pfn because it's much easier than scanning over
+ * linked list. This function returns the pfn of the first found movable
+ * page if it's found, otherwise 0.
  */
-static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
+static unsigned long scan_movable_pages(unsigned long start, unsigned long end)
 {
        unsigned long pfn;
        struct page *page;
@@ -1220,6 +1241,13 @@ static unsigned long scan_lru_pages(unsigned long start, unsigned long end)
                        page = pfn_to_page(pfn);
                        if (PageLRU(page))
                                return pfn;
+                       if (PageHuge(page)) {
+                               if (is_hugepage_active(page))
+                                       return pfn;
+                               else
+                                       pfn = round_up(pfn + 1,
+                                               1 << compound_order(page)) - 1;
+                       }
                }
        }
        return 0;
@@ -1240,6 +1268,19 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                if (!pfn_valid(pfn))
                        continue;
                page = pfn_to_page(pfn);
+
+               if (PageHuge(page)) {
+                       struct page *head = compound_head(page);
+                       pfn = page_to_pfn(head) + (1<<compound_order(head)) - 1;
+                       if (compound_order(head) > PFN_SECTION_SHIFT) {
+                               ret = -EBUSY;
+                               break;
+                       }
+                       if (isolate_huge_page(page, &source))
+                               move_pages -= 1 << compound_order(head);
+                       continue;
+               }
+
                if (!get_page_unless_zero(page))
                        continue;
                /*
@@ -1272,7 +1313,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
        }
        if (!list_empty(&source)) {
                if (not_managed) {
-                       putback_lru_pages(&source);
+                       putback_movable_pages(&source);
                        goto out;
                }
 
@@ -1283,7 +1324,7 @@ do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
                ret = migrate_pages(&source, alloc_migrate_target, 0,
                                        MIGRATE_SYNC, MR_MEMORY_HOTPLUG);
                if (ret)
-                       putback_lru_pages(&source);
+                       putback_movable_pages(&source);
        }
 out:
        return ret;
@@ -1472,7 +1513,6 @@ static int __ref __offline_pages(unsigned long start_pfn,
        struct zone *zone;
        struct memory_notify arg;
 
-       BUG_ON(start_pfn >= end_pfn);
        /* at least, alignment against pageblock is necessary */
        if (!IS_ALIGNED(start_pfn, pageblock_nr_pages))
                return -EINVAL;
@@ -1527,8 +1567,8 @@ repeat:
                drain_all_pages();
        }
 
-       pfn = scan_lru_pages(start_pfn, end_pfn);
-       if (pfn) { /* We have page on LRU */
+       pfn = scan_movable_pages(start_pfn, end_pfn);
+       if (pfn) { /* We have movable pages */
                ret = do_migrate_range(pfn, end_pfn);
                if (!ret) {
                        drain = 1;
@@ -1547,6 +1587,11 @@ repeat:
        yield();
        /* drain pcp pages, this is synchronous. */
        drain_all_pages();
+       /*
+        * dissolve free hugepages in the memory block before doing offlining
+        * actually in order to make hugetlbfs's object counting consistent.
+        */
+       dissolve_free_huge_pages(start_pfn, end_pfn);
        /* check again */
        offlined_pages = check_pages_isolated(start_pfn, end_pfn);
        if (offlined_pages < 0) {
@@ -1674,9 +1719,8 @@ static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
        return ret;
 }
 
-static int check_cpu_on_node(void *data)
+static int check_cpu_on_node(pg_data_t *pgdat)
 {
-       struct pglist_data *pgdat = data;
        int cpu;
 
        for_each_present_cpu(cpu) {
@@ -1691,10 +1735,9 @@ static int check_cpu_on_node(void *data)
        return 0;
 }
 
-static void unmap_cpu_on_node(void *data)
+static void unmap_cpu_on_node(pg_data_t *pgdat)
 {
 #ifdef CONFIG_ACPI_NUMA
-       struct pglist_data *pgdat = data;
        int cpu;
 
        for_each_possible_cpu(cpu)
@@ -1703,10 +1746,11 @@ static void unmap_cpu_on_node(void *data)
 #endif
 }
 
-static int check_and_unmap_cpu_on_node(void *data)
+static int check_and_unmap_cpu_on_node(pg_data_t *pgdat)
 {
-       int ret = check_cpu_on_node(data);
+       int ret;
 
+       ret = check_cpu_on_node(pgdat);
        if (ret)
                return ret;
 
@@ -1715,11 +1759,18 @@ static int check_and_unmap_cpu_on_node(void *data)
         * the cpu_to_node() now.
         */
 
-       unmap_cpu_on_node(data);
+       unmap_cpu_on_node(pgdat);
        return 0;
 }
 
-/* offline the node if all memory sections of this node are removed */
+/**
+ * try_offline_node
+ *
+ * Offline a node if all memory sections and cpus of the node are removed.
+ *
+ * NOTE: The caller must call lock_device_hotplug() to serialize hotplug
+ * and online/offline operations before this call.
+ */
 void try_offline_node(int nid)
 {
        pg_data_t *pgdat = NODE_DATA(nid);
@@ -1745,7 +1796,7 @@ void try_offline_node(int nid)
                return;
        }
 
-       if (stop_machine(check_and_unmap_cpu_on_node, pgdat, NULL))
+       if (check_and_unmap_cpu_on_node(pgdat))
                return;
 
        /*
@@ -1782,10 +1833,19 @@ void try_offline_node(int nid)
 }
 EXPORT_SYMBOL(try_offline_node);
 
+/**
+ * remove_memory
+ *
+ * NOTE: The caller must call lock_device_hotplug() to serialize hotplug
+ * and online/offline operations before this call, as required by
+ * try_offline_node().
+ */
 void __ref remove_memory(int nid, u64 start, u64 size)
 {
        int ret;
 
+       BUG_ON(check_hotplug_memory_range(start, size));
+
        lock_memory_hotplug();
 
        /*
index 4baf12e534d19031d28ddc5eba5335f72de54099..04729647f359c7c1fa3a91058cc1044c0db2df8d 100644 (file)
@@ -123,16 +123,19 @@ static struct mempolicy preferred_node_policy[MAX_NUMNODES];
 static struct mempolicy *get_task_policy(struct task_struct *p)
 {
        struct mempolicy *pol = p->mempolicy;
-       int node;
 
        if (!pol) {
-               node = numa_node_id();
-               if (node != NUMA_NO_NODE)
-                       pol = &preferred_node_policy[node];
+               int node = numa_node_id();
 
-               /* preferred_node_policy is not initialised early in boot */
-               if (!pol->mode)
-                       pol = NULL;
+               if (node != NUMA_NO_NODE) {
+                       pol = &preferred_node_policy[node];
+                       /*
+                        * preferred_node_policy is not initialised early in
+                        * boot
+                        */
+                       if (!pol->mode)
+                               pol = NULL;
+               }
        }
 
        return pol;
@@ -473,8 +476,11 @@ static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
 static void migrate_page_add(struct page *page, struct list_head *pagelist,
                                unsigned long flags);
 
-/* Scan through pages checking if pages follow certain conditions. */
-static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
+/*
+ * Scan through pages checking if pages follow certain conditions,
+ * and move them to the pagelist if they do.
+ */
+static int queue_pages_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, unsigned long end,
                const nodemask_t *nodes, unsigned long flags,
                void *private)
@@ -512,7 +518,31 @@ static int check_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
        return addr != end;
 }
 
-static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud,
+static void queue_pages_hugetlb_pmd_range(struct vm_area_struct *vma,
+               pmd_t *pmd, const nodemask_t *nodes, unsigned long flags,
+                                   void *private)
+{
+#ifdef CONFIG_HUGETLB_PAGE
+       int nid;
+       struct page *page;
+
+       spin_lock(&vma->vm_mm->page_table_lock);
+       page = pte_page(huge_ptep_get((pte_t *)pmd));
+       nid = page_to_nid(page);
+       if (node_isset(nid, *nodes) == !!(flags & MPOL_MF_INVERT))
+               goto unlock;
+       /* With MPOL_MF_MOVE, we migrate only unshared hugepage. */
+       if (flags & (MPOL_MF_MOVE_ALL) ||
+           (flags & MPOL_MF_MOVE && page_mapcount(page) == 1))
+               isolate_huge_page(page, private);
+unlock:
+       spin_unlock(&vma->vm_mm->page_table_lock);
+#else
+       BUG();
+#endif
+}
+
+static inline int queue_pages_pmd_range(struct vm_area_struct *vma, pud_t *pud,
                unsigned long addr, unsigned long end,
                const nodemask_t *nodes, unsigned long flags,
                void *private)
@@ -523,17 +553,24 @@ static inline int check_pmd_range(struct vm_area_struct *vma, pud_t *pud,
        pmd = pmd_offset(pud, addr);
        do {
                next = pmd_addr_end(addr, end);
+               if (!pmd_present(*pmd))
+                       continue;
+               if (pmd_huge(*pmd) && is_vm_hugetlb_page(vma)) {
+                       queue_pages_hugetlb_pmd_range(vma, pmd, nodes,
+                                               flags, private);
+                       continue;
+               }
                split_huge_page_pmd(vma, addr, pmd);
                if (pmd_none_or_trans_huge_or_clear_bad(pmd))
                        continue;
-               if (check_pte_range(vma, pmd, addr, next, nodes,
+               if (queue_pages_pte_range(vma, pmd, addr, next, nodes,
                                    flags, private))
                        return -EIO;
        } while (pmd++, addr = next, addr != end);
        return 0;
 }
 
-static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
+static inline int queue_pages_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
                unsigned long addr, unsigned long end,
                const nodemask_t *nodes, unsigned long flags,
                void *private)
@@ -544,16 +581,18 @@ static inline int check_pud_range(struct vm_area_struct *vma, pgd_t *pgd,
        pud = pud_offset(pgd, addr);
        do {
                next = pud_addr_end(addr, end);
+               if (pud_huge(*pud) && is_vm_hugetlb_page(vma))
+                       continue;
                if (pud_none_or_clear_bad(pud))
                        continue;
-               if (check_pmd_range(vma, pud, addr, next, nodes,
+               if (queue_pages_pmd_range(vma, pud, addr, next, nodes,
                                    flags, private))
                        return -EIO;
        } while (pud++, addr = next, addr != end);
        return 0;
 }
 
-static inline int check_pgd_range(struct vm_area_struct *vma,
+static inline int queue_pages_pgd_range(struct vm_area_struct *vma,
                unsigned long addr, unsigned long end,
                const nodemask_t *nodes, unsigned long flags,
                void *private)
@@ -566,7 +605,7 @@ static inline int check_pgd_range(struct vm_area_struct *vma,
                next = pgd_addr_end(addr, end);
                if (pgd_none_or_clear_bad(pgd))
                        continue;
-               if (check_pud_range(vma, pgd, addr, next, nodes,
+               if (queue_pages_pud_range(vma, pgd, addr, next, nodes,
                                    flags, private))
                        return -EIO;
        } while (pgd++, addr = next, addr != end);
@@ -604,12 +643,14 @@ static unsigned long change_prot_numa(struct vm_area_struct *vma,
 #endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */
 
 /*
- * Check if all pages in a range are on a set of nodes.
- * If pagelist != NULL then isolate pages from the LRU and
- * put them on the pagelist.
+ * Walk through page tables and collect pages to be migrated.
+ *
+ * If pages found in a given range are on a set of nodes (determined by
+ * @nodes and @flags,) it's isolated and queued to the pagelist which is
+ * passed via @private.)
  */
 static struct vm_area_struct *
-check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
+queue_pages_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                const nodemask_t *nodes, unsigned long flags, void *private)
 {
        int err;
@@ -635,9 +676,6 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                                return ERR_PTR(-EFAULT);
                }
 
-               if (is_vm_hugetlb_page(vma))
-                       goto next;
-
                if (flags & MPOL_MF_LAZY) {
                        change_prot_numa(vma, start, endvma);
                        goto next;
@@ -647,7 +685,7 @@ check_range(struct mm_struct *mm, unsigned long start, unsigned long end,
                     ((flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)) &&
                      vma_migratable(vma))) {
 
-                       err = check_pgd_range(vma, start, endvma, nodes,
+                       err = queue_pages_pgd_range(vma, start, endvma, nodes,
                                                flags, private);
                        if (err) {
                                first = ERR_PTR(err);
@@ -990,7 +1028,11 @@ static void migrate_page_add(struct page *page, struct list_head *pagelist,
 
 static struct page *new_node_page(struct page *page, unsigned long node, int **x)
 {
-       return alloc_pages_exact_node(node, GFP_HIGHUSER_MOVABLE, 0);
+       if (PageHuge(page))
+               return alloc_huge_page_node(page_hstate(compound_head(page)),
+                                       node);
+       else
+               return alloc_pages_exact_node(node, GFP_HIGHUSER_MOVABLE, 0);
 }
 
 /*
@@ -1013,14 +1055,14 @@ static int migrate_to_node(struct mm_struct *mm, int source, int dest,
         * space range and MPOL_MF_DISCONTIG_OK, this call can not fail.
         */
        VM_BUG_ON(!(flags & (MPOL_MF_MOVE | MPOL_MF_MOVE_ALL)));
-       check_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
+       queue_pages_range(mm, mm->mmap->vm_start, mm->task_size, &nmask,
                        flags | MPOL_MF_DISCONTIG_OK, &pagelist);
 
        if (!list_empty(&pagelist)) {
                err = migrate_pages(&pagelist, new_node_page, dest,
                                        MIGRATE_SYNC, MR_SYSCALL);
                if (err)
-                       putback_lru_pages(&pagelist);
+                       putback_movable_pages(&pagelist);
        }
 
        return err;
@@ -1154,10 +1196,14 @@ static struct page *new_vma_page(struct page *page, unsigned long private, int *
                        break;
                vma = vma->vm_next;
        }
-
        /*
-        * if !vma, alloc_page_vma() will use task or system default policy
+        * queue_pages_range() confirms that @page belongs to some vma,
+        * so vma shouldn't be NULL.
         */
+       BUG_ON(!vma);
+
+       if (PageHuge(page))
+               return alloc_huge_page_noerr(vma, address, 1);
        return alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, address);
 }
 #else
@@ -1249,7 +1295,7 @@ static long do_mbind(unsigned long start, unsigned long len,
        if (err)
                goto mpol_out;
 
-       vma = check_range(mm, start, end, nmask,
+       vma = queue_pages_range(mm, start, end, nmask,
                          flags | MPOL_MF_INVERT, &pagelist);
 
        err = PTR_ERR(vma);     /* maybe ... */
@@ -1265,7 +1311,7 @@ static long do_mbind(unsigned long start, unsigned long len,
                                        (unsigned long)vma,
                                        MIGRATE_SYNC, MR_MEMPOLICY_MBIND);
                        if (nr_failed)
-                               putback_lru_pages(&pagelist);
+                               putback_movable_pages(&pagelist);
                }
 
                if (nr_failed && (flags & MPOL_MF_STRICT))
@@ -2065,6 +2111,16 @@ retry_cpuset:
 }
 EXPORT_SYMBOL(alloc_pages_current);
 
+int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
+{
+       struct mempolicy *pol = mpol_dup(vma_policy(src));
+
+       if (IS_ERR(pol))
+               return PTR_ERR(pol);
+       dst->vm_policy = pol;
+       return 0;
+}
+
 /*
  * If mpol_dup() sees current->cpuset == cpuset_being_rebound, then it
  * rebinds the mempolicy its copying by calling mpol_rebind_policy()
index 54990476c049b2fa60c5e740a0533ea70df1f856..659aa42bad1621756878dc41ce65e3cbd86ed0fb 100644 (file)
@@ -73,7 +73,7 @@ mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn,
                               gfp_t gfp_mask, int node_id)
 {
        mempool_t *pool;
-       pool = kmalloc_node(sizeof(*pool), gfp_mask | __GFP_ZERO, node_id);
+       pool = kzalloc_node(sizeof(*pool), gfp_mask, node_id);
        if (!pool)
                return NULL;
        pool->elements = kmalloc_node(min_nr * sizeof(void *),
index 6f0c24438bbaaf6ffdaa4f840ab8da37cf9e236a..9c8d5f59d30bb87e63c9990c085eb646e69b4ed7 100644 (file)
@@ -100,6 +100,10 @@ void putback_movable_pages(struct list_head *l)
        struct page *page2;
 
        list_for_each_entry_safe(page, page2, l, lru) {
+               if (unlikely(PageHuge(page))) {
+                       putback_active_hugepage(page);
+                       continue;
+               }
                list_del(&page->lru);
                dec_zone_page_state(page, NR_ISOLATED_ANON +
                                page_is_file_cache(page));
@@ -307,7 +311,7 @@ static inline bool buffer_migrate_lock_buffers(struct buffer_head *head,
  * 2 for pages with a mapping
  * 3 for pages with a mapping and PagePrivate/PagePrivate2 set.
  */
-static int migrate_page_move_mapping(struct address_space *mapping,
+int migrate_page_move_mapping(struct address_space *mapping,
                struct page *newpage, struct page *page,
                struct buffer_head *head, enum migrate_mode mode)
 {
@@ -945,6 +949,16 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
        struct page *new_hpage = get_new_page(hpage, private, &result);
        struct anon_vma *anon_vma = NULL;
 
+       /*
+        * Movability of hugepages depends on architectures and hugepage size.
+        * This check is necessary because some callers of hugepage migration
+        * like soft offline and memory hotremove don't walk through page
+        * tables or check whether the hugepage is pmd-based or not before
+        * kicking migration.
+        */
+       if (!hugepage_migration_support(page_hstate(hpage)))
+               return -ENOSYS;
+
        if (!new_hpage)
                return -ENOMEM;
 
@@ -975,6 +989,8 @@ static int unmap_and_move_huge_page(new_page_t get_new_page,
 
        unlock_page(hpage);
 out:
+       if (rc != -EAGAIN)
+               putback_active_hugepage(hpage);
        put_page(new_hpage);
        if (result) {
                if (rc)
@@ -1025,7 +1041,11 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
                list_for_each_entry_safe(page, page2, from, lru) {
                        cond_resched();
 
-                       rc = unmap_and_move(get_new_page, private,
+                       if (PageHuge(page))
+                               rc = unmap_and_move_huge_page(get_new_page,
+                                               private, page, pass > 2, mode);
+                       else
+                               rc = unmap_and_move(get_new_page, private,
                                                page, pass > 2, mode);
 
                        switch(rc) {
@@ -1058,32 +1078,6 @@ out:
        return rc;
 }
 
-int migrate_huge_page(struct page *hpage, new_page_t get_new_page,
-                     unsigned long private, enum migrate_mode mode)
-{
-       int pass, rc;
-
-       for (pass = 0; pass < 10; pass++) {
-               rc = unmap_and_move_huge_page(get_new_page, private,
-                                               hpage, pass > 2, mode);
-               switch (rc) {
-               case -ENOMEM:
-                       goto out;
-               case -EAGAIN:
-                       /* try again */
-                       cond_resched();
-                       break;
-               case MIGRATEPAGE_SUCCESS:
-                       goto out;
-               default:
-                       rc = -EIO;
-                       goto out;
-               }
-       }
-out:
-       return rc;
-}
-
 #ifdef CONFIG_NUMA
 /*
  * Move a list of individual pages
@@ -1108,7 +1102,11 @@ static struct page *new_page_node(struct page *p, unsigned long private,
 
        *result = &pm->status;
 
-       return alloc_pages_exact_node(pm->node,
+       if (PageHuge(p))
+               return alloc_huge_page_node(page_hstate(compound_head(p)),
+                                       pm->node);
+       else
+               return alloc_pages_exact_node(pm->node,
                                GFP_HIGHUSER_MOVABLE | GFP_THISNODE, 0);
 }
 
@@ -1168,6 +1166,11 @@ static int do_move_page_to_node_array(struct mm_struct *mm,
                                !migrate_all)
                        goto put_and_set;
 
+               if (PageHuge(page)) {
+                       isolate_huge_page(page, &pagelist);
+                       goto put_and_set;
+               }
+
                err = isolate_lru_page(page);
                if (!err) {
                        list_add_tail(&page->lru, &pagelist);
@@ -1190,7 +1193,7 @@ set_status:
                err = migrate_pages(&pagelist, new_page_node,
                                (unsigned long)pm, MIGRATE_SYNC, MR_SYSCALL);
                if (err)
-                       putback_lru_pages(&pagelist);
+                       putback_movable_pages(&pagelist);
        }
 
        up_read(&mm->mmap_sem);
@@ -1468,7 +1471,7 @@ static bool migrate_balanced_pgdat(struct pglist_data *pgdat,
                if (!populated_zone(zone))
                        continue;
 
-               if (zone->all_unreclaimable)
+               if (!zone_reclaimable(zone))
                        continue;
 
                /* Avoid waking kswapd by allocating pages_to_migrate pages. */
index 79b7cf7d1bca72cee9babfb60e21a38799c8eba1..d63802663242eb6ad13ca2ed065434f24fd7e5d1 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/swap.h>
 #include <linux/swapops.h>
 #include <linux/pagemap.h>
+#include <linux/pagevec.h>
 #include <linux/mempolicy.h>
 #include <linux/syscalls.h>
 #include <linux/sched.h>
@@ -18,6 +19,8 @@
 #include <linux/rmap.h>
 #include <linux/mmzone.h>
 #include <linux/hugetlb.h>
+#include <linux/memcontrol.h>
+#include <linux/mm_inline.h>
 
 #include "internal.h"
 
@@ -87,6 +90,47 @@ void mlock_vma_page(struct page *page)
        }
 }
 
+/*
+ * Finish munlock after successful page isolation
+ *
+ * Page must be locked. This is a wrapper for try_to_munlock()
+ * and putback_lru_page() with munlock accounting.
+ */
+static void __munlock_isolated_page(struct page *page)
+{
+       int ret = SWAP_AGAIN;
+
+       /*
+        * Optimization: if the page was mapped just once, that's our mapping
+        * and we don't need to check all the other vmas.
+        */
+       if (page_mapcount(page) > 1)
+               ret = try_to_munlock(page);
+
+       /* Did try_to_unlock() succeed or punt? */
+       if (ret != SWAP_MLOCK)
+               count_vm_event(UNEVICTABLE_PGMUNLOCKED);
+
+       putback_lru_page(page);
+}
+
+/*
+ * Accounting for page isolation fail during munlock
+ *
+ * Performs accounting when page isolation fails in munlock. There is nothing
+ * else to do because it means some other task has already removed the page
+ * from the LRU. putback_lru_page() will take care of removing the page from
+ * the unevictable list, if necessary. vmscan [page_referenced()] will move
+ * the page back to the unevictable list if some other vma has it mlocked.
+ */
+static void __munlock_isolation_failed(struct page *page)
+{
+       if (PageUnevictable(page))
+               count_vm_event(UNEVICTABLE_PGSTRANDED);
+       else
+               count_vm_event(UNEVICTABLE_PGMUNLOCKED);
+}
+
 /**
  * munlock_vma_page - munlock a vma page
  * @page - page to be unlocked
@@ -112,37 +156,10 @@ unsigned int munlock_vma_page(struct page *page)
                unsigned int nr_pages = hpage_nr_pages(page);
                mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages);
                page_mask = nr_pages - 1;
-               if (!isolate_lru_page(page)) {
-                       int ret = SWAP_AGAIN;
-
-                       /*
-                        * Optimization: if the page was mapped just once,
-                        * that's our mapping and we don't need to check all the
-                        * other vmas.
-                        */
-                       if (page_mapcount(page) > 1)
-                               ret = try_to_munlock(page);
-                       /*
-                        * did try_to_unlock() succeed or punt?
-                        */
-                       if (ret != SWAP_MLOCK)
-                               count_vm_event(UNEVICTABLE_PGMUNLOCKED);
-
-                       putback_lru_page(page);
-               } else {
-                       /*
-                        * Some other task has removed the page from the LRU.
-                        * putback_lru_page() will take care of removing the
-                        * page from the unevictable list, if necessary.
-                        * vmscan [page_referenced()] will move the page back
-                        * to the unevictable list if some other vma has it
-                        * mlocked.
-                        */
-                       if (PageUnevictable(page))
-                               count_vm_event(UNEVICTABLE_PGSTRANDED);
-                       else
-                               count_vm_event(UNEVICTABLE_PGMUNLOCKED);
-               }
+               if (!isolate_lru_page(page))
+                       __munlock_isolated_page(page);
+               else
+                       __munlock_isolation_failed(page);
        }
 
        return page_mask;
@@ -209,6 +226,191 @@ static int __mlock_posix_error_return(long retval)
        return retval;
 }
 
+/*
+ * Prepare page for fast batched LRU putback via putback_lru_evictable_pagevec()
+ *
+ * The fast path is available only for evictable pages with single mapping.
+ * Then we can bypass the per-cpu pvec and get better performance.
+ * when mapcount > 1 we need try_to_munlock() which can fail.
+ * when !page_evictable(), we need the full redo logic of putback_lru_page to
+ * avoid leaving evictable page in unevictable list.
+ *
+ * In case of success, @page is added to @pvec and @pgrescued is incremented
+ * in case that the page was previously unevictable. @page is also unlocked.
+ */
+static bool __putback_lru_fast_prepare(struct page *page, struct pagevec *pvec,
+               int *pgrescued)
+{
+       VM_BUG_ON(PageLRU(page));
+       VM_BUG_ON(!PageLocked(page));
+
+       if (page_mapcount(page) <= 1 && page_evictable(page)) {
+               pagevec_add(pvec, page);
+               if (TestClearPageUnevictable(page))
+                       (*pgrescued)++;
+               unlock_page(page);
+               return true;
+       }
+
+       return false;
+}
+
+/*
+ * Putback multiple evictable pages to the LRU
+ *
+ * Batched putback of evictable pages that bypasses the per-cpu pvec. Some of
+ * the pages might have meanwhile become unevictable but that is OK.
+ */
+static void __putback_lru_fast(struct pagevec *pvec, int pgrescued)
+{
+       count_vm_events(UNEVICTABLE_PGMUNLOCKED, pagevec_count(pvec));
+       /*
+        *__pagevec_lru_add() calls release_pages() so we don't call
+        * put_page() explicitly
+        */
+       __pagevec_lru_add(pvec);
+       count_vm_events(UNEVICTABLE_PGRESCUED, pgrescued);
+}
+
+/*
+ * Munlock a batch of pages from the same zone
+ *
+ * The work is split to two main phases. First phase clears the Mlocked flag
+ * and attempts to isolate the pages, all under a single zone lru lock.
+ * The second phase finishes the munlock only for pages where isolation
+ * succeeded.
+ *
+ * Note that the pagevec may be modified during the process.
+ */
+static void __munlock_pagevec(struct pagevec *pvec, struct zone *zone)
+{
+       int i;
+       int nr = pagevec_count(pvec);
+       int delta_munlocked = -nr;
+       struct pagevec pvec_putback;
+       int pgrescued = 0;
+
+       /* Phase 1: page isolation */
+       spin_lock_irq(&zone->lru_lock);
+       for (i = 0; i < nr; i++) {
+               struct page *page = pvec->pages[i];
+
+               if (TestClearPageMlocked(page)) {
+                       struct lruvec *lruvec;
+                       int lru;
+
+                       if (PageLRU(page)) {
+                               lruvec = mem_cgroup_page_lruvec(page, zone);
+                               lru = page_lru(page);
+                               /*
+                                * We already have pin from follow_page_mask()
+                                * so we can spare the get_page() here.
+                                */
+                               ClearPageLRU(page);
+                               del_page_from_lru_list(page, lruvec, lru);
+                       } else {
+                               __munlock_isolation_failed(page);
+                               goto skip_munlock;
+                       }
+
+               } else {
+skip_munlock:
+                       /*
+                        * We won't be munlocking this page in the next phase
+                        * but we still need to release the follow_page_mask()
+                        * pin.
+                        */
+                       pvec->pages[i] = NULL;
+                       put_page(page);
+                       delta_munlocked++;
+               }
+       }
+       __mod_zone_page_state(zone, NR_MLOCK, delta_munlocked);
+       spin_unlock_irq(&zone->lru_lock);
+
+       /* Phase 2: page munlock */
+       pagevec_init(&pvec_putback, 0);
+       for (i = 0; i < nr; i++) {
+               struct page *page = pvec->pages[i];
+
+               if (page) {
+                       lock_page(page);
+                       if (!__putback_lru_fast_prepare(page, &pvec_putback,
+                                       &pgrescued)) {
+                               /*
+                                * Slow path. We don't want to lose the last
+                                * pin before unlock_page()
+                                */
+                               get_page(page); /* for putback_lru_page() */
+                               __munlock_isolated_page(page);
+                               unlock_page(page);
+                               put_page(page); /* from follow_page_mask() */
+                       }
+               }
+       }
+
+       /*
+        * Phase 3: page putback for pages that qualified for the fast path
+        * This will also call put_page() to return pin from follow_page_mask()
+        */
+       if (pagevec_count(&pvec_putback))
+               __putback_lru_fast(&pvec_putback, pgrescued);
+}
+
+/*
+ * Fill up pagevec for __munlock_pagevec using pte walk
+ *
+ * The function expects that the struct page corresponding to @start address is
+ * a non-TPH page already pinned and in the @pvec, and that it belongs to @zone.
+ *
+ * The rest of @pvec is filled by subsequent pages within the same pmd and same
+ * zone, as long as the pte's are present and vm_normal_page() succeeds. These
+ * pages also get pinned.
+ *
+ * Returns the address of the next page that should be scanned. This equals
+ * @start + PAGE_SIZE when no page could be added by the pte walk.
+ */
+static unsigned long __munlock_pagevec_fill(struct pagevec *pvec,
+               struct vm_area_struct *vma, int zoneid, unsigned long start,
+               unsigned long end)
+{
+       pte_t *pte;
+       spinlock_t *ptl;
+
+       /*
+        * Initialize pte walk starting at the already pinned page where we
+        * are sure that there is a pte.
+        */
+       pte = get_locked_pte(vma->vm_mm, start, &ptl);
+       end = min(end, pmd_addr_end(start, end));
+
+       /* The page next to the pinned page is the first we will try to get */
+       start += PAGE_SIZE;
+       while (start < end) {
+               struct page *page = NULL;
+               pte++;
+               if (pte_present(*pte))
+                       page = vm_normal_page(vma, start, *pte);
+               /*
+                * Break if page could not be obtained or the page's node+zone does not
+                * match
+                */
+               if (!page || page_zone_id(page) != zoneid)
+                       break;
+
+               get_page(page);
+               /*
+                * Increase the address that will be returned *before* the
+                * eventual break due to pvec becoming full by adding the page
+                */
+               start += PAGE_SIZE;
+               if (pagevec_add(pvec, page) == 0)
+                       break;
+       }
+       pte_unmap_unlock(pte, ptl);
+       return start;
+}
+
 /*
  * munlock_vma_pages_range() - munlock all pages in the vma range.'
  * @vma - vma containing range to be munlock()ed.
@@ -233,9 +435,13 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
        vma->vm_flags &= ~VM_LOCKED;
 
        while (start < end) {
-               struct page *page;
+               struct page *page = NULL;
                unsigned int page_mask, page_increm;
+               struct pagevec pvec;
+               struct zone *zone;
+               int zoneid;
 
+               pagevec_init(&pvec, 0);
                /*
                 * Although FOLL_DUMP is intended for get_dump_page(),
                 * it just so happens that its special treatment of the
@@ -244,21 +450,45 @@ void munlock_vma_pages_range(struct vm_area_struct *vma,
                 * has sneaked into the range, we won't oops here: great).
                 */
                page = follow_page_mask(vma, start, FOLL_GET | FOLL_DUMP,
-                                       &page_mask);
+                               &page_mask);
+
                if (page && !IS_ERR(page)) {
-                       lock_page(page);
-                       lru_add_drain();
-                       /*
-                        * Any THP page found by follow_page_mask() may have
-                        * gotten split before reaching munlock_vma_page(),
-                        * so we need to recompute the page_mask here.
-                        */
-                       page_mask = munlock_vma_page(page);
-                       unlock_page(page);
-                       put_page(page);
+                       if (PageTransHuge(page)) {
+                               lock_page(page);
+                               /*
+                                * Any THP page found by follow_page_mask() may
+                                * have gotten split before reaching
+                                * munlock_vma_page(), so we need to recompute
+                                * the page_mask here.
+                                */
+                               page_mask = munlock_vma_page(page);
+                               unlock_page(page);
+                               put_page(page); /* follow_page_mask() */
+                       } else {
+                               /*
+                                * Non-huge pages are handled in batches via
+                                * pagevec. The pin from follow_page_mask()
+                                * prevents them from collapsing by THP.
+                                */
+                               pagevec_add(&pvec, page);
+                               zone = page_zone(page);
+                               zoneid = page_zone_id(page);
+
+                               /*
+                                * Try to fill the rest of pagevec using fast
+                                * pte walk. This will also update start to
+                                * the next page to process. Then munlock the
+                                * pagevec.
+                                */
+                               start = __munlock_pagevec_fill(&pvec, vma,
+                                               zoneid, start, end);
+                               __munlock_pagevec(&pvec, zone);
+                               goto next;
+                       }
                }
                page_increm = 1 + (~(start >> PAGE_SHIFT) & page_mask);
                start += page_increm * PAGE_SIZE;
+next:
                cond_resched();
        }
 }
index f9c97d10b873ae4a896c3a22266707653d941c90..9d548512ff8a30498ce07f2e536f765e8bd54cca 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -1202,7 +1202,6 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
                        unsigned long *populate)
 {
        struct mm_struct * mm = current->mm;
-       struct inode *inode;
        vm_flags_t vm_flags;
 
        *populate = 0;
@@ -1265,9 +1264,9 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
                        return -EAGAIN;
        }
 
-       inode = file ? file_inode(file) : NULL;
-
        if (file) {
+               struct inode *inode = file_inode(file);
+
                switch (flags & MAP_TYPE) {
                case MAP_SHARED:
                        if ((prot&PROT_WRITE) && !(file->f_mode&FMODE_WRITE))
@@ -1302,6 +1301,8 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
 
                        if (!file->f_op || !file->f_op->mmap)
                                return -ENODEV;
+                       if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
+                               return -EINVAL;
                        break;
 
                default:
@@ -1310,6 +1311,8 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
        } else {
                switch (flags & MAP_TYPE) {
                case MAP_SHARED:
+                       if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
+                               return -EINVAL;
                        /*
                         * Ignore pgoff.
                         */
@@ -1476,11 +1479,9 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma, *prev;
-       int correct_wcount = 0;
        int error;
        struct rb_node **rb_link, *rb_parent;
        unsigned long charged = 0;
-       struct inode *inode =  file ? file_inode(file) : NULL;
 
        /* Check against address space limit. */
        if (!may_expand_vm(mm, len >> PAGE_SHIFT)) {
@@ -1544,16 +1545,11 @@ munmap_back:
        vma->vm_pgoff = pgoff;
        INIT_LIST_HEAD(&vma->anon_vma_chain);
 
-       error = -EINVAL;        /* when rejecting VM_GROWSDOWN|VM_GROWSUP */
-
        if (file) {
-               if (vm_flags & (VM_GROWSDOWN|VM_GROWSUP))
-                       goto free_vma;
                if (vm_flags & VM_DENYWRITE) {
                        error = deny_write_access(file);
                        if (error)
                                goto free_vma;
-                       correct_wcount = 1;
                }
                vma->vm_file = get_file(file);
                error = file->f_op->mmap(file, vma);
@@ -1570,11 +1566,8 @@ munmap_back:
                WARN_ON_ONCE(addr != vma->vm_start);
 
                addr = vma->vm_start;
-               pgoff = vma->vm_pgoff;
                vm_flags = vma->vm_flags;
        } else if (vm_flags & VM_SHARED) {
-               if (unlikely(vm_flags & (VM_GROWSDOWN|VM_GROWSUP)))
-                       goto free_vma;
                error = shmem_zero_setup(vma);
                if (error)
                        goto free_vma;
@@ -1596,11 +1589,10 @@ munmap_back:
        }
 
        vma_link(mm, vma, prev, rb_link, rb_parent);
-       file = vma->vm_file;
-
        /* Once vma denies write, undo our temporary denial count */
-       if (correct_wcount)
-               atomic_inc(&inode->i_writecount);
+       if (vm_flags & VM_DENYWRITE)
+               allow_write_access(file);
+       file = vma->vm_file;
 out:
        perf_event_mmap(vma);
 
@@ -1616,11 +1608,20 @@ out:
        if (file)
                uprobe_mmap(vma);
 
+       /*
+        * New (or expanded) vma always get soft dirty status.
+        * Otherwise user-space soft-dirty page tracker won't
+        * be able to distinguish situation when vma area unmapped,
+        * then new mapped in-place (which must be aimed as
+        * a completely new data area).
+        */
+       vma->vm_flags |= VM_SOFTDIRTY;
+
        return addr;
 
 unmap_and_free_vma:
-       if (correct_wcount)
-               atomic_inc(&inode->i_writecount);
+       if (vm_flags & VM_DENYWRITE)
+               allow_write_access(file);
        vma->vm_file = NULL;
        fput(file);
 
@@ -2380,7 +2381,6 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
 static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
              unsigned long addr, int new_below)
 {
-       struct mempolicy *pol;
        struct vm_area_struct *new;
        int err = -ENOMEM;
 
@@ -2404,12 +2404,9 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
                new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT);
        }
 
-       pol = mpol_dup(vma_policy(vma));
-       if (IS_ERR(pol)) {
-               err = PTR_ERR(pol);
+       err = vma_dup_policy(vma, new);
+       if (err)
                goto out_free_vma;
-       }
-       vma_set_policy(new, pol);
 
        if (anon_vma_clone(new, vma))
                goto out_free_mpol;
@@ -2437,7 +2434,7 @@ static int __split_vma(struct mm_struct * mm, struct vm_area_struct * vma,
                fput(new->vm_file);
        unlink_anon_vmas(new);
  out_free_mpol:
-       mpol_put(pol);
+       mpol_put(vma_policy(new));
  out_free_vma:
        kmem_cache_free(vm_area_cachep, new);
  out_err:
@@ -2663,6 +2660,7 @@ out:
        mm->total_vm += len >> PAGE_SHIFT;
        if (flags & VM_LOCKED)
                mm->locked_vm += (len >> PAGE_SHIFT);
+       vma->vm_flags |= VM_SOFTDIRTY;
        return addr;
 }
 
@@ -2780,7 +2778,6 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
        struct mm_struct *mm = vma->vm_mm;
        struct vm_area_struct *new_vma, *prev;
        struct rb_node **rb_link, *rb_parent;
-       struct mempolicy *pol;
        bool faulted_in_anon_vma = true;
 
        /*
@@ -2825,10 +2822,8 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
                        new_vma->vm_start = addr;
                        new_vma->vm_end = addr + len;
                        new_vma->vm_pgoff = pgoff;
-                       pol = mpol_dup(vma_policy(vma));
-                       if (IS_ERR(pol))
+                       if (vma_dup_policy(vma, new_vma))
                                goto out_free_vma;
-                       vma_set_policy(new_vma, pol);
                        INIT_LIST_HEAD(&new_vma->anon_vma_chain);
                        if (anon_vma_clone(new_vma, vma))
                                goto out_free_mempol;
@@ -2843,7 +2838,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
        return new_vma;
 
  out_free_mempol:
-       mpol_put(pol);
+       mpol_put(vma_policy(new_vma));
  out_free_vma:
        kmem_cache_free(vm_area_cachep, new_vma);
        return NULL;
@@ -2930,7 +2925,7 @@ int install_special_mapping(struct mm_struct *mm,
        vma->vm_start = addr;
        vma->vm_end = addr + len;
 
-       vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
+       vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND | VM_SOFTDIRTY;
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
 
        vma->vm_ops = &special_mapping_vmops;
index 0843feb66f3d0236abd4386b5bfd0170c24ae0ef..91b13d6a16d453b50894e6028800b92399bf8f14 100644 (file)
@@ -25,6 +25,7 @@
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
 
 #include "internal.h"
 
@@ -62,8 +63,10 @@ static pmd_t *alloc_new_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
                return NULL;
 
        pmd = pmd_alloc(mm, pud, addr);
-       if (!pmd)
+       if (!pmd) {
+               pud_free(mm, pud);
                return NULL;
+       }
 
        VM_BUG_ON(pmd_trans_huge(*pmd));
 
index 98e75f2ac7bc3ad01f1287e9697948e6212610d4..314e9d2743813ea5e52c08929b8a4cbb4621dfa9 100644 (file)
@@ -678,9 +678,12 @@ out:
  */
 void pagefault_out_of_memory(void)
 {
-       struct zonelist *zonelist = node_zonelist(first_online_node,
-                                                 GFP_KERNEL);
+       struct zonelist *zonelist;
 
+       if (mem_cgroup_oom_synchronize())
+               return;
+
+       zonelist = node_zonelist(first_online_node, GFP_KERNEL);
        if (try_set_zonelist_oom(zonelist, GFP_KERNEL)) {
                out_of_memory(NULL, 0, 0, NULL, false);
                clear_zonelist_oom(zonelist, GFP_KERNEL);
index 3f0c895c71fee656619de3a6f1c8299cc1f95d6e..f5236f804aa6cdf9800f445c31950a52cdd6b88f 100644 (file)
 #include <linux/pagevec.h>
 #include <linux/timer.h>
 #include <linux/sched/rt.h>
+#include <linux/mm_inline.h>
 #include <trace/events/writeback.h>
 
+#include "internal.h"
+
 /*
  * Sleep at most 200ms at a time in balance_dirty_pages().
  */
@@ -241,9 +244,6 @@ static unsigned long global_dirtyable_memory(void)
        if (!vm_highmem_is_dirtyable)
                x -= highmem_dirtyable_memory(x);
 
-       /* Subtract min_free_kbytes */
-       x -= min_t(unsigned long, x, min_free_kbytes >> (PAGE_SHIFT - 10));
-
        return x + 1;   /* Ensure that we never return 0 */
 }
 
@@ -584,6 +584,37 @@ unsigned long bdi_dirty_limit(struct backing_dev_info *bdi, unsigned long dirty)
        return bdi_dirty;
 }
 
+/*
+ *                           setpoint - dirty 3
+ *        f(dirty) := 1.0 + (----------------)
+ *                           limit - setpoint
+ *
+ * it's a 3rd order polynomial that subjects to
+ *
+ * (1) f(freerun)  = 2.0 => rampup dirty_ratelimit reasonably fast
+ * (2) f(setpoint) = 1.0 => the balance point
+ * (3) f(limit)    = 0   => the hard limit
+ * (4) df/dx      <= 0  => negative feedback control
+ * (5) the closer to setpoint, the smaller |df/dx| (and the reverse)
+ *     => fast response on large errors; small oscillation near setpoint
+ */
+static inline long long pos_ratio_polynom(unsigned long setpoint,
+                                         unsigned long dirty,
+                                         unsigned long limit)
+{
+       long long pos_ratio;
+       long x;
+
+       x = div_s64(((s64)setpoint - (s64)dirty) << RATELIMIT_CALC_SHIFT,
+                   limit - setpoint + 1);
+       pos_ratio = x;
+       pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT;
+       pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT;
+       pos_ratio += 1 << RATELIMIT_CALC_SHIFT;
+
+       return clamp(pos_ratio, 0LL, 2LL << RATELIMIT_CALC_SHIFT);
+}
+
 /*
  * Dirty position control.
  *
@@ -682,26 +713,80 @@ static unsigned long bdi_position_ratio(struct backing_dev_info *bdi,
        /*
         * global setpoint
         *
-        *                           setpoint - dirty 3
-        *        f(dirty) := 1.0 + (----------------)
-        *                           limit - setpoint
+        * See comment for pos_ratio_polynom().
+        */
+       setpoint = (freerun + limit) / 2;
+       pos_ratio = pos_ratio_polynom(setpoint, dirty, limit);
+
+       /*
+        * The strictlimit feature is a tool preventing mistrusted filesystems
+        * from growing a large number of dirty pages before throttling. For
+        * such filesystems balance_dirty_pages always checks bdi counters
+        * against bdi limits. Even if global "nr_dirty" is under "freerun".
+        * This is especially important for fuse which sets bdi->max_ratio to
+        * 1% by default. Without strictlimit feature, fuse writeback may
+        * consume arbitrary amount of RAM because it is accounted in
+        * NR_WRITEBACK_TEMP which is not involved in calculating "nr_dirty".
         *
-        * it's a 3rd order polynomial that subjects to
+        * Here, in bdi_position_ratio(), we calculate pos_ratio based on
+        * two values: bdi_dirty and bdi_thresh. Let's consider an example:
+        * total amount of RAM is 16GB, bdi->max_ratio is equal to 1%, global
+        * limits are set by default to 10% and 20% (background and throttle).
+        * Then bdi_thresh is 1% of 20% of 16GB. This amounts to ~8K pages.
+        * bdi_dirty_limit(bdi, bg_thresh) is about ~4K pages. bdi_setpoint is
+        * about ~6K pages (as the average of background and throttle bdi
+        * limits). The 3rd order polynomial will provide positive feedback if
+        * bdi_dirty is under bdi_setpoint and vice versa.
         *
-        * (1) f(freerun)  = 2.0 => rampup dirty_ratelimit reasonably fast
-        * (2) f(setpoint) = 1.0 => the balance point
-        * (3) f(limit)    = 0   => the hard limit
-        * (4) df/dx      <= 0   => negative feedback control
-        * (5) the closer to setpoint, the smaller |df/dx| (and the reverse)
-        *     => fast response on large errors; small oscillation near setpoint
+        * Note, that we cannot use global counters in these calculations
+        * because we want to throttle process writing to a strictlimit BDI
+        * much earlier than global "freerun" is reached (~23MB vs. ~2.3GB
+        * in the example above).
         */
-       setpoint = (freerun + limit) / 2;
-       x = div_s64(((s64)setpoint - (s64)dirty) << RATELIMIT_CALC_SHIFT,
-                   limit - setpoint + 1);
-       pos_ratio = x;
-       pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT;
-       pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT;
-       pos_ratio += 1 << RATELIMIT_CALC_SHIFT;
+       if (unlikely(bdi->capabilities & BDI_CAP_STRICTLIMIT)) {
+               long long bdi_pos_ratio;
+               unsigned long bdi_bg_thresh;
+
+               if (bdi_dirty < 8)
+                       return min_t(long long, pos_ratio * 2,
+                                    2 << RATELIMIT_CALC_SHIFT);
+
+               if (bdi_dirty >= bdi_thresh)
+                       return 0;
+
+               bdi_bg_thresh = div_u64((u64)bdi_thresh * bg_thresh, thresh);
+               bdi_setpoint = dirty_freerun_ceiling(bdi_thresh,
+                                                    bdi_bg_thresh);
+
+               if (bdi_setpoint == 0 || bdi_setpoint == bdi_thresh)
+                       return 0;
+
+               bdi_pos_ratio = pos_ratio_polynom(bdi_setpoint, bdi_dirty,
+                                                 bdi_thresh);
+
+               /*
+                * Typically, for strictlimit case, bdi_setpoint << setpoint
+                * and pos_ratio >> bdi_pos_ratio. In the other words global
+                * state ("dirty") is not limiting factor and we have to
+                * make decision based on bdi counters. But there is an
+                * important case when global pos_ratio should get precedence:
+                * global limits are exceeded (e.g. due to activities on other
+                * BDIs) while given strictlimit BDI is below limit.
+                *
+                * "pos_ratio * bdi_pos_ratio" would work for the case above,
+                * but it would look too non-natural for the case of all
+                * activity in the system coming from a single strictlimit BDI
+                * with bdi->max_ratio == 100%.
+                *
+                * Note that min() below somewhat changes the dynamics of the
+                * control system. Normally, pos_ratio value can be well over 3
+                * (when globally we are at freerun and bdi is well below bdi
+                * setpoint). Now the maximum pos_ratio in the same situation
+                * is 2. We might want to tweak this if we observe the control
+                * system is too slow to adapt.
+                */
+               return min(pos_ratio, bdi_pos_ratio);
+       }
 
        /*
         * We have computed basic pos_ratio above based on global situation. If
@@ -994,6 +1079,27 @@ static void bdi_update_dirty_ratelimit(struct backing_dev_info *bdi,
         * keep that period small to reduce time lags).
         */
        step = 0;
+
+       /*
+        * For strictlimit case, calculations above were based on bdi counters
+        * and limits (starting from pos_ratio = bdi_position_ratio() and up to
+        * balanced_dirty_ratelimit = task_ratelimit * write_bw / dirty_rate).
+        * Hence, to calculate "step" properly, we have to use bdi_dirty as
+        * "dirty" and bdi_setpoint as "setpoint".
+        *
+        * We rampup dirty_ratelimit forcibly if bdi_dirty is low because
+        * it's possible that bdi_thresh is close to zero due to inactivity
+        * of backing device (see the implementation of bdi_dirty_limit()).
+        */
+       if (unlikely(bdi->capabilities & BDI_CAP_STRICTLIMIT)) {
+               dirty = bdi_dirty;
+               if (bdi_dirty < 8)
+                       setpoint = bdi_dirty + 1;
+               else
+                       setpoint = (bdi_thresh +
+                                   bdi_dirty_limit(bdi, bg_thresh)) / 2;
+       }
+
        if (dirty < setpoint) {
                x = min(bdi->balanced_dirty_ratelimit,
                         min(balanced_dirty_ratelimit, task_ratelimit));
@@ -1198,6 +1304,56 @@ static long bdi_min_pause(struct backing_dev_info *bdi,
        return pages >= DIRTY_POLL_THRESH ? 1 + t / 2 : t;
 }
 
+static inline void bdi_dirty_limits(struct backing_dev_info *bdi,
+                                   unsigned long dirty_thresh,
+                                   unsigned long background_thresh,
+                                   unsigned long *bdi_dirty,
+                                   unsigned long *bdi_thresh,
+                                   unsigned long *bdi_bg_thresh)
+{
+       unsigned long bdi_reclaimable;
+
+       /*
+        * bdi_thresh is not treated as some limiting factor as
+        * dirty_thresh, due to reasons
+        * - in JBOD setup, bdi_thresh can fluctuate a lot
+        * - in a system with HDD and USB key, the USB key may somehow
+        *   go into state (bdi_dirty >> bdi_thresh) either because
+        *   bdi_dirty starts high, or because bdi_thresh drops low.
+        *   In this case we don't want to hard throttle the USB key
+        *   dirtiers for 100 seconds until bdi_dirty drops under
+        *   bdi_thresh. Instead the auxiliary bdi control line in
+        *   bdi_position_ratio() will let the dirtier task progress
+        *   at some rate <= (write_bw / 2) for bringing down bdi_dirty.
+        */
+       *bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
+
+       if (bdi_bg_thresh)
+               *bdi_bg_thresh = div_u64((u64)*bdi_thresh *
+                                        background_thresh,
+                                        dirty_thresh);
+
+       /*
+        * In order to avoid the stacked BDI deadlock we need
+        * to ensure we accurately count the 'dirty' pages when
+        * the threshold is low.
+        *
+        * Otherwise it would be possible to get thresh+n pages
+        * reported dirty, even though there are thresh-m pages
+        * actually dirty; with m+n sitting in the percpu
+        * deltas.
+        */
+       if (*bdi_thresh < 2 * bdi_stat_error(bdi)) {
+               bdi_reclaimable = bdi_stat_sum(bdi, BDI_RECLAIMABLE);
+               *bdi_dirty = bdi_reclaimable +
+                       bdi_stat_sum(bdi, BDI_WRITEBACK);
+       } else {
+               bdi_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE);
+               *bdi_dirty = bdi_reclaimable +
+                       bdi_stat(bdi, BDI_WRITEBACK);
+       }
+}
+
 /*
  * balance_dirty_pages() must be called by processes which are generating dirty
  * data.  It looks at the number of dirty pages in the machine and will force
@@ -1209,13 +1365,9 @@ static void balance_dirty_pages(struct address_space *mapping,
                                unsigned long pages_dirtied)
 {
        unsigned long nr_reclaimable;   /* = file_dirty + unstable_nfs */
-       unsigned long bdi_reclaimable;
        unsigned long nr_dirty;  /* = file_dirty + writeback + unstable_nfs */
-       unsigned long bdi_dirty;
-       unsigned long freerun;
        unsigned long background_thresh;
        unsigned long dirty_thresh;
-       unsigned long bdi_thresh;
        long period;
        long pause;
        long max_pause;
@@ -1226,10 +1378,16 @@ static void balance_dirty_pages(struct address_space *mapping,
        unsigned long dirty_ratelimit;
        unsigned long pos_ratio;
        struct backing_dev_info *bdi = mapping->backing_dev_info;
+       bool strictlimit = bdi->capabilities & BDI_CAP_STRICTLIMIT;
        unsigned long start_time = jiffies;
 
        for (;;) {
                unsigned long now = jiffies;
+               unsigned long uninitialized_var(bdi_thresh);
+               unsigned long thresh;
+               unsigned long uninitialized_var(bdi_dirty);
+               unsigned long dirty;
+               unsigned long bg_thresh;
 
                /*
                 * Unstable writes are a feature of certain networked
@@ -1243,61 +1401,44 @@ static void balance_dirty_pages(struct address_space *mapping,
 
                global_dirty_limits(&background_thresh, &dirty_thresh);
 
+               if (unlikely(strictlimit)) {
+                       bdi_dirty_limits(bdi, dirty_thresh, background_thresh,
+                                        &bdi_dirty, &bdi_thresh, &bg_thresh);
+
+                       dirty = bdi_dirty;
+                       thresh = bdi_thresh;
+               } else {
+                       dirty = nr_dirty;
+                       thresh = dirty_thresh;
+                       bg_thresh = background_thresh;
+               }
+
                /*
                 * Throttle it only when the background writeback cannot
                 * catch-up. This avoids (excessively) small writeouts
-                * when the bdi limits are ramping up.
+                * when the bdi limits are ramping up in case of !strictlimit.
+                *
+                * In strictlimit case make decision based on the bdi counters
+                * and limits. Small writeouts when the bdi limits are ramping
+                * up are the price we consciously pay for strictlimit-ing.
                 */
-               freerun = dirty_freerun_ceiling(dirty_thresh,
-                                               background_thresh);
-               if (nr_dirty <= freerun) {
+               if (dirty <= dirty_freerun_ceiling(thresh, bg_thresh)) {
                        current->dirty_paused_when = now;
                        current->nr_dirtied = 0;
                        current->nr_dirtied_pause =
-                               dirty_poll_interval(nr_dirty, dirty_thresh);
+                               dirty_poll_interval(dirty, thresh);
                        break;
                }
 
                if (unlikely(!writeback_in_progress(bdi)))
                        bdi_start_background_writeback(bdi);
 
-               /*
-                * bdi_thresh is not treated as some limiting factor as
-                * dirty_thresh, due to reasons
-                * - in JBOD setup, bdi_thresh can fluctuate a lot
-                * - in a system with HDD and USB key, the USB key may somehow
-                *   go into state (bdi_dirty >> bdi_thresh) either because
-                *   bdi_dirty starts high, or because bdi_thresh drops low.
-                *   In this case we don't want to hard throttle the USB key
-                *   dirtiers for 100 seconds until bdi_dirty drops under
-                *   bdi_thresh. Instead the auxiliary bdi control line in
-                *   bdi_position_ratio() will let the dirtier task progress
-                *   at some rate <= (write_bw / 2) for bringing down bdi_dirty.
-                */
-               bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);
-
-               /*
-                * In order to avoid the stacked BDI deadlock we need
-                * to ensure we accurately count the 'dirty' pages when
-                * the threshold is low.
-                *
-                * Otherwise it would be possible to get thresh+n pages
-                * reported dirty, even though there are thresh-m pages
-                * actually dirty; with m+n sitting in the percpu
-                * deltas.
-                */
-               if (bdi_thresh < 2 * bdi_stat_error(bdi)) {
-                       bdi_reclaimable = bdi_stat_sum(bdi, BDI_RECLAIMABLE);
-                       bdi_dirty = bdi_reclaimable +
-                                   bdi_stat_sum(bdi, BDI_WRITEBACK);
-               } else {
-                       bdi_reclaimable = bdi_stat(bdi, BDI_RECLAIMABLE);
-                       bdi_dirty = bdi_reclaimable +
-                                   bdi_stat(bdi, BDI_WRITEBACK);
-               }
+               if (!strictlimit)
+                       bdi_dirty_limits(bdi, dirty_thresh, background_thresh,
+                                        &bdi_dirty, &bdi_thresh, NULL);
 
                dirty_exceeded = (bdi_dirty > bdi_thresh) &&
-                                 (nr_dirty > dirty_thresh);
+                                ((nr_dirty > dirty_thresh) || strictlimit);
                if (dirty_exceeded && !bdi->dirty_exceeded)
                        bdi->dirty_exceeded = 1;
 
@@ -2002,11 +2143,17 @@ EXPORT_SYMBOL(account_page_dirtied);
 
 /*
  * Helper function for set_page_writeback family.
+ *
+ * The caller must hold mem_cgroup_begin/end_update_page_stat() lock
+ * while calling this function.
+ * See test_set_page_writeback for example.
+ *
  * NOTE: Unlike account_page_dirtied this does not rely on being atomic
  * wrt interrupts.
  */
 void account_page_writeback(struct page *page)
 {
+       mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
        inc_zone_page_state(page, NR_WRITEBACK);
 }
 EXPORT_SYMBOL(account_page_writeback);
@@ -2223,7 +2370,10 @@ int test_clear_page_writeback(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
        int ret;
+       bool locked;
+       unsigned long memcg_flags;
 
+       mem_cgroup_begin_update_page_stat(page, &locked, &memcg_flags);
        if (mapping) {
                struct backing_dev_info *bdi = mapping->backing_dev_info;
                unsigned long flags;
@@ -2244,9 +2394,11 @@ int test_clear_page_writeback(struct page *page)
                ret = TestClearPageWriteback(page);
        }
        if (ret) {
+               mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK);
                dec_zone_page_state(page, NR_WRITEBACK);
                inc_zone_page_state(page, NR_WRITTEN);
        }
+       mem_cgroup_end_update_page_stat(page, &locked, &memcg_flags);
        return ret;
 }
 
@@ -2254,7 +2406,10 @@ int test_set_page_writeback(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
        int ret;
+       bool locked;
+       unsigned long memcg_flags;
 
+       mem_cgroup_begin_update_page_stat(page, &locked, &memcg_flags);
        if (mapping) {
                struct backing_dev_info *bdi = mapping->backing_dev_info;
                unsigned long flags;
@@ -2281,6 +2436,7 @@ int test_set_page_writeback(struct page *page)
        }
        if (!ret)
                account_page_writeback(page);
+       mem_cgroup_end_update_page_stat(page, &locked, &memcg_flags);
        return ret;
 
 }
index c2b59dbda196dcaaffcd44f367143e3e83a15c0f..0ee638f76ebe584cd40d7541bac886b96b03162e 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/ftrace_event.h>
 #include <linux/memcontrol.h>
 #include <linux/prefetch.h>
+#include <linux/mm_inline.h>
 #include <linux/migrate.h>
 #include <linux/page-debug-flags.h>
 #include <linux/hugetlb.h>
@@ -488,8 +489,10 @@ __find_buddy_index(unsigned long page_idx, unsigned int order)
  * (c) a page and its buddy have the same order &&
  * (d) a page and its buddy are in the same zone.
  *
- * For recording whether a page is in the buddy system, we set ->_mapcount -2.
- * Setting, clearing, and testing _mapcount -2 is serialized by zone->lock.
+ * For recording whether a page is in the buddy system, we set ->_mapcount
+ * PAGE_BUDDY_MAPCOUNT_VALUE.
+ * Setting, clearing, and testing _mapcount PAGE_BUDDY_MAPCOUNT_VALUE is
+ * serialized by zone->lock.
  *
  * For recording page's order, we use page_private(page).
  */
@@ -527,8 +530,9 @@ static inline int page_is_buddy(struct page *page, struct page *buddy,
  * as necessary, plus some accounting needed to play nicely with other
  * parts of the VM system.
  * At each level, we keep a list of pages, which are heads of continuous
- * free pages of length of (1 << order) and marked with _mapcount -2. Page's
- * order is recorded in page_private(page) field.
+ * free pages of length of (1 << order) and marked with _mapcount
+ * PAGE_BUDDY_MAPCOUNT_VALUE. Page's order is recorded in page_private(page)
+ * field.
  * So when we are allocating or freeing one, we can derive the state of the
  * other.  That is, if we allocate a small block, and both were
  * free, the remainder of the region must be split into blocks.
@@ -647,7 +651,6 @@ static void free_pcppages_bulk(struct zone *zone, int count,
        int to_free = count;
 
        spin_lock(&zone->lock);
-       zone->all_unreclaimable = 0;
        zone->pages_scanned = 0;
 
        while (to_free) {
@@ -696,7 +699,6 @@ static void free_one_page(struct zone *zone, struct page *page, int order,
                                int migratetype)
 {
        spin_lock(&zone->lock);
-       zone->all_unreclaimable = 0;
        zone->pages_scanned = 0;
 
        __free_one_page(page, zone, order, migratetype);
@@ -721,7 +723,8 @@ static bool free_pages_prepare(struct page *page, unsigned int order)
                return false;
 
        if (!PageHighMem(page)) {
-               debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
+               debug_check_no_locks_freed(page_address(page),
+                                          PAGE_SIZE << order);
                debug_check_no_obj_freed(page_address(page),
                                           PAGE_SIZE << order);
        }
@@ -750,19 +753,19 @@ static void __free_pages_ok(struct page *page, unsigned int order)
 void __init __free_pages_bootmem(struct page *page, unsigned int order)
 {
        unsigned int nr_pages = 1 << order;
+       struct page *p = page;
        unsigned int loop;
 
-       prefetchw(page);
-       for (loop = 0; loop < nr_pages; loop++) {
-               struct page *p = &page[loop];
-
-               if (loop + 1 < nr_pages)
-                       prefetchw(p + 1);
+       prefetchw(p);
+       for (loop = 0; loop < (nr_pages - 1); loop++, p++) {
+               prefetchw(p + 1);
                __ClearPageReserved(p);
                set_page_count(p, 0);
        }
+       __ClearPageReserved(p);
+       set_page_count(p, 0);
 
-       page_zone(page)->managed_pages += 1 << order;
+       page_zone(page)->managed_pages += nr_pages;
        set_page_refcounted(page);
        __free_pages(page, order);
 }
@@ -885,7 +888,7 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order,
                                                int migratetype)
 {
        unsigned int current_order;
-       struct free_area * area;
+       struct free_area *area;
        struct page *page;
 
        /* Find a page of the appropriate size in the preferred list */
@@ -1007,14 +1010,60 @@ static void change_pageblock_range(struct page *pageblock_page,
        }
 }
 
+/*
+ * If breaking a large block of pages, move all free pages to the preferred
+ * allocation list. If falling back for a reclaimable kernel allocation, be
+ * more aggressive about taking ownership of free pages.
+ *
+ * On the other hand, never change migration type of MIGRATE_CMA pageblocks
+ * nor move CMA pages to different free lists. We don't want unmovable pages
+ * to be allocated from MIGRATE_CMA areas.
+ *
+ * Returns the new migratetype of the pageblock (or the same old migratetype
+ * if it was unchanged).
+ */
+static int try_to_steal_freepages(struct zone *zone, struct page *page,
+                                 int start_type, int fallback_type)
+{
+       int current_order = page_order(page);
+
+       if (is_migrate_cma(fallback_type))
+               return fallback_type;
+
+       /* Take ownership for orders >= pageblock_order */
+       if (current_order >= pageblock_order) {
+               change_pageblock_range(page, current_order, start_type);
+               return start_type;
+       }
+
+       if (current_order >= pageblock_order / 2 ||
+           start_type == MIGRATE_RECLAIMABLE ||
+           page_group_by_mobility_disabled) {
+               int pages;
+
+               pages = move_freepages_block(zone, page, start_type);
+
+               /* Claim the whole block if over half of it is free */
+               if (pages >= (1 << (pageblock_order-1)) ||
+                               page_group_by_mobility_disabled) {
+
+                       set_pageblock_migratetype(page, start_type);
+                       return start_type;
+               }
+
+       }
+
+       return fallback_type;
+}
+
 /* Remove an element from the buddy allocator from the fallback list */
 static inline struct page *
 __rmqueue_fallback(struct zone *zone, int order, int start_migratetype)
 {
-       struct free_area * area;
+       struct free_area *area;
        int current_order;
        struct page *page;
-       int migratetype, i;
+       int migratetype, new_type, i;
 
        /* Find the largest possible block of pages in the other list */
        for (current_order = MAX_ORDER-1; current_order >= order;
@@ -1034,51 +1083,29 @@ __rmqueue_fallback(struct zone *zone, int order, int start_migratetype)
                                        struct page, lru);
                        area->nr_free--;
 
-                       /*
-                        * If breaking a large block of pages, move all free
-                        * pages to the preferred allocation list. If falling
-                        * back for a reclaimable kernel allocation, be more
-                        * aggressive about taking ownership of free pages
-                        *
-                        * On the other hand, never change migration
-                        * type of MIGRATE_CMA pageblocks nor move CMA
-                        * pages on different free lists. We don't
-                        * want unmovable pages to be allocated from
-                        * MIGRATE_CMA areas.
-                        */
-                       if (!is_migrate_cma(migratetype) &&
-                           (current_order >= pageblock_order / 2 ||
-                            start_migratetype == MIGRATE_RECLAIMABLE ||
-                            page_group_by_mobility_disabled)) {
-                               int pages;
-                               pages = move_freepages_block(zone, page,
-                                                               start_migratetype);
-
-                               /* Claim the whole block if over half of it is free */
-                               if (pages >= (1 << (pageblock_order-1)) ||
-                                               page_group_by_mobility_disabled)
-                                       set_pageblock_migratetype(page,
-                                                               start_migratetype);
-
-                               migratetype = start_migratetype;
-                       }
+                       new_type = try_to_steal_freepages(zone, page,
+                                                         start_migratetype,
+                                                         migratetype);
 
                        /* Remove the page from the freelists */
                        list_del(&page->lru);
                        rmv_page_order(page);
 
-                       /* Take ownership for orders >= pageblock_order */
-                       if (current_order >= pageblock_order &&
-                           !is_migrate_cma(migratetype))
-                               change_pageblock_range(page, current_order,
-                                                       start_migratetype);
-
+                       /*
+                        * Borrow the excess buddy pages as well, irrespective
+                        * of whether we stole freepages, or took ownership of
+                        * the pageblock or not.
+                        *
+                        * Exception: When borrowing from MIGRATE_CMA, release
+                        * the excess buddy pages to CMA itself.
+                        */
                        expand(zone, page, order, current_order, area,
                               is_migrate_cma(migratetype)
                             ? migratetype : start_migratetype);
 
-                       trace_mm_page_alloc_extfrag(page, order, current_order,
-                               start_migratetype, migratetype);
+                       trace_mm_page_alloc_extfrag(page, order,
+                               current_order, start_migratetype, migratetype,
+                               new_type == start_migratetype);
 
                        return page;
                }
@@ -1281,7 +1308,7 @@ void mark_free_pages(struct zone *zone)
        int order, t;
        struct list_head *curr;
 
-       if (!zone->spanned_pages)
+       if (zone_is_empty(zone))
                return;
 
        spin_lock_irqsave(&zone->lock, flags);
@@ -1526,6 +1553,7 @@ again:
                                          get_pageblock_migratetype(page));
        }
 
+       __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
        __count_zone_vm_events(PGALLOC, zone, 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
        local_irq_restore(flags);
@@ -1792,6 +1820,11 @@ static void zlc_clear_zones_full(struct zonelist *zonelist)
        bitmap_zero(zlc->fullzones, MAX_ZONES_PER_ZONELIST);
 }
 
+static bool zone_local(struct zone *local_zone, struct zone *zone)
+{
+       return node_distance(local_zone->node, zone->node) == LOCAL_DISTANCE;
+}
+
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
        return node_isset(local_zone->node, zone->zone_pgdat->reclaim_nodes);
@@ -1829,6 +1862,11 @@ static void zlc_clear_zones_full(struct zonelist *zonelist)
 {
 }
 
+static bool zone_local(struct zone *local_zone, struct zone *zone)
+{
+       return true;
+}
+
 static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone)
 {
        return true;
@@ -1860,16 +1898,41 @@ get_page_from_freelist(gfp_t gfp_mask, nodemask_t *nodemask, unsigned int order,
 zonelist_scan:
        /*
         * Scan zonelist, looking for a zone with enough free.
-        * See also cpuset_zone_allowed() comment in kernel/cpuset.c.
+        * See also __cpuset_node_allowed_softwall() comment in kernel/cpuset.c.
         */
        for_each_zone_zonelist_nodemask(zone, z, zonelist,
                                                high_zoneidx, nodemask) {
+               unsigned long mark;
+
                if (IS_ENABLED(CONFIG_NUMA) && zlc_active &&
                        !zlc_zone_worth_trying(zonelist, z, allowednodes))
                                continue;
                if ((alloc_flags & ALLOC_CPUSET) &&
                        !cpuset_zone_allowed_softwall(zone, gfp_mask))
                                continue;
+               BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
+               if (unlikely(alloc_flags & ALLOC_NO_WATERMARKS))
+                       goto try_this_zone;
+               /*
+                * Distribute pages in proportion to the individual
+                * zone size to ensure fair page aging.  The zone a
+                * page was allocated in should have no effect on the
+                * time the page has in memory before being reclaimed.
+                *
+                * When zone_reclaim_mode is enabled, try to stay in
+                * local zones in the fastpath.  If that fails, the
+                * slowpath is entered, which will do another pass
+                * starting with the local zones, but ultimately fall
+                * back to remote zones that do not partake in the
+                * fairness round-robin cycle of this zonelist.
+                */
+               if (alloc_flags & ALLOC_WMARK_LOW) {
+                       if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
+                               continue;
+                       if (zone_reclaim_mode &&
+                           !zone_local(preferred_zone, zone))
+                               continue;
+               }
                /*
                 * When allocating a page cache page for writing, we
                 * want to get it from a zone that is within its dirty
@@ -1900,16 +1963,11 @@ zonelist_scan:
                    (gfp_mask & __GFP_WRITE) && !zone_dirty_ok(zone))
                        goto this_zone_full;
 
-               BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK);
-               if (!(alloc_flags & ALLOC_NO_WATERMARKS)) {
-                       unsigned long mark;
+               mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
+               if (!zone_watermark_ok(zone, order, mark,
+                                      classzone_idx, alloc_flags)) {
                        int ret;
 
-                       mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK];
-                       if (zone_watermark_ok(zone, order, mark,
-                                   classzone_idx, alloc_flags))
-                               goto try_this_zone;
-
                        if (IS_ENABLED(CONFIG_NUMA) &&
                                        !did_zlc_setup && nr_online_nodes > 1) {
                                /*
@@ -2321,16 +2379,30 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
        return page;
 }
 
-static inline
-void wake_all_kswapd(unsigned int order, struct zonelist *zonelist,
-                                               enum zone_type high_zoneidx,
-                                               enum zone_type classzone_idx)
+static void prepare_slowpath(gfp_t gfp_mask, unsigned int order,
+                            struct zonelist *zonelist,
+                            enum zone_type high_zoneidx,
+                            struct zone *preferred_zone)
 {
        struct zoneref *z;
        struct zone *zone;
 
-       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
-               wakeup_kswapd(zone, order, classzone_idx);
+       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
+               if (!(gfp_mask & __GFP_NO_KSWAPD))
+                       wakeup_kswapd(zone, order, zone_idx(preferred_zone));
+               /*
+                * Only reset the batches of zones that were actually
+                * considered in the fast path, we don't want to
+                * thrash fairness information for zones that are not
+                * actually part of this zonelist's round-robin cycle.
+                */
+               if (zone_reclaim_mode && !zone_local(preferred_zone, zone))
+                       continue;
+               mod_zone_page_state(zone, NR_ALLOC_BATCH,
+                                   high_wmark_pages(zone) -
+                                   low_wmark_pages(zone) -
+                                   zone_page_state(zone, NR_ALLOC_BATCH));
+       }
 }
 
 static inline int
@@ -2426,9 +2498,8 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
                goto nopage;
 
 restart:
-       if (!(gfp_mask & __GFP_NO_KSWAPD))
-               wake_all_kswapd(order, zonelist, high_zoneidx,
-                                               zone_idx(preferred_zone));
+       prepare_slowpath(gfp_mask, order, zonelist,
+                        high_zoneidx, preferred_zone);
 
        /*
         * OK, we're below the kswapd watermark and have kicked background
@@ -3095,7 +3166,7 @@ void show_free_areas(unsigned int filter)
                        K(zone_page_state(zone, NR_FREE_CMA_PAGES)),
                        K(zone_page_state(zone, NR_WRITEBACK_TEMP)),
                        zone->pages_scanned,
-                       (zone->all_unreclaimable ? "yes" : "no")
+                       (!zone_reclaimable(zone) ? "yes" : "no")
                        );
                printk("lowmem_reserve[]:");
                for (i = 0; i < MAX_NR_ZONES; i++)
@@ -3104,7 +3175,7 @@ void show_free_areas(unsigned int filter)
        }
 
        for_each_populated_zone(zone) {
-               unsigned long nr[MAX_ORDER], flags, order, total = 0;
+               unsigned long nr[MAX_ORDER], flags, order, total = 0;
                unsigned char types[MAX_ORDER];
 
                if (skip_free_areas_node(filter, zone_to_nid(zone)))
@@ -3416,11 +3487,11 @@ static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes)
 static int default_zonelist_order(void)
 {
        int nid, zone_type;
-       unsigned long low_kmem_size,total_size;
+       unsigned long low_kmem_size, total_size;
        struct zone *z;
        int average_size;
        /*
-         * ZONE_DMA and ZONE_DMA32 can be very small area in the system.
+        * 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 configures zone order.
@@ -3452,9 +3523,9 @@ static int default_zonelist_order(void)
                return ZONELIST_ORDER_NODE;
        /*
         * look into each node's config.
-        * If there is a node whose DMA/DMA32 memory is very big area on
-        * local memory, NODE_ORDER may be suitable.
-         */
+        * If there is a node whose DMA/DMA32 memory is very big area on
+        * local memory, NODE_ORDER may be suitable.
+        */
        average_size = total_size /
                                (nodes_weight(node_states[N_MEMORY]) + 1);
        for_each_online_node(nid) {
@@ -4180,7 +4251,7 @@ int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
        if (!zone->wait_table)
                return -ENOMEM;
 
-       for(i = 0; i < zone->wait_table_hash_nr_entries; ++i)
+       for (i = 0; i < zone->wait_table_hash_nr_entries; ++i)
                init_waitqueue_head(zone->wait_table + i);
 
        return 0;
@@ -4237,7 +4308,7 @@ int __meminit init_currently_empty_zone(struct zone *zone,
 int __meminit __early_pfn_to_nid(unsigned long pfn)
 {
        unsigned long start_pfn, end_pfn;
-       int i, nid;
+       int nid;
        /*
         * NOTE: The following SMP-unsafe globals are only used early in boot
         * when the kernel is running single-threaded.
@@ -4248,15 +4319,14 @@ int __meminit __early_pfn_to_nid(unsigned long pfn)
        if (last_start_pfn <= pfn && pfn < last_end_pfn)
                return last_nid;
 
-       for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid)
-               if (start_pfn <= pfn && pfn < end_pfn) {
-                       last_start_pfn = start_pfn;
-                       last_end_pfn = end_pfn;
-                       last_nid = nid;
-                       return nid;
-               }
-       /* This is a memory hole */
-       return -1;
+       nid = memblock_search_pfn_nid(pfn, &start_pfn, &end_pfn);
+       if (nid != -1) {
+               last_start_pfn = start_pfn;
+               last_end_pfn = end_pfn;
+               last_nid = nid;
+       }
+
+       return nid;
 }
 #endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
 
@@ -4586,7 +4656,7 @@ static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone,
 #ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE
 
 /* Initialise the number of pages represented by NR_PAGEBLOCK_BITS */
-void __init set_pageblock_order(void)
+void __paginginit set_pageblock_order(void)
 {
        unsigned int order;
 
@@ -4614,7 +4684,7 @@ void __init set_pageblock_order(void)
  * include/linux/pageblock-flags.h for the values of pageblock_order based on
  * the kernel config
  */
-void __init set_pageblock_order(void)
+void __paginginit set_pageblock_order(void)
 {
 }
 
@@ -4728,8 +4798,11 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
                spin_lock_init(&zone->lru_lock);
                zone_seqlock_init(zone);
                zone->zone_pgdat = pgdat;
-
                zone_pcp_init(zone);
+
+               /* For bootup, initialized properly in watermark setup */
+               mod_zone_page_state(zone, NR_ALLOC_BATCH, zone->managed_pages);
+
                lruvec_init(&zone->lruvec);
                if (!size)
                        continue;
@@ -4930,7 +5003,7 @@ static unsigned long __init early_calculate_totalpages(void)
                if (pages)
                        node_set_state(nid, N_MEMORY);
        }
-       return totalpages;
+       return totalpages;
 }
 
 /*
@@ -5047,7 +5120,7 @@ restart:
                        /*
                         * Some kernelcore has been met, update counts and
                         * break if the kernelcore for this node has been
-                        * satisified
+                        * satisfied
                         */
                        required_kernelcore -= min(required_kernelcore,
                                                                size_pages);
@@ -5061,7 +5134,7 @@ restart:
         * If there is still required_kernelcore, we do another pass with one
         * less node in the count. This will push zone_movable_pfn[nid] further
         * along on the nodes that still have memory until kernelcore is
-        * satisified
+        * satisfied
         */
        usable_nodes--;
        if (usable_nodes && required_kernelcore > usable_nodes)
@@ -5286,8 +5359,10 @@ void __init mem_init_print_info(const char *str)
         * 3) .rodata.* may be embedded into .text or .data sections.
         */
 #define adj_init_size(start, end, size, pos, adj) \
-       if (start <= pos && pos < end && size > adj) \
-               size -= adj;
+       do { \
+               if (start <= pos && pos < end && size > adj) \
+                       size -= adj; \
+       } while (0)
 
        adj_init_size(__init_begin, __init_end, init_data_size,
                     _sinittext, init_code_size);
@@ -5361,7 +5436,7 @@ static int page_alloc_cpu_notify(struct notifier_block *self,
                 * This is only okay since the processor is dead and cannot
                 * race with what we are doing.
                 */
-               refresh_cpu_vm_stats(cpu);
+               cpu_vm_stats_fold(cpu);
        }
        return NOTIFY_OK;
 }
@@ -5498,6 +5573,11 @@ static void __setup_per_zone_wmarks(void)
                zone->watermark[WMARK_LOW]  = min_wmark_pages(zone) + (tmp >> 2);
                zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + (tmp >> 1);
 
+               __mod_zone_page_state(zone, NR_ALLOC_BATCH,
+                                     high_wmark_pages(zone) -
+                                     low_wmark_pages(zone) -
+                                     zone_page_state(zone, NR_ALLOC_BATCH));
+
                setup_zone_migrate_reserve(zone);
                spin_unlock_irqrestore(&zone->lock, flags);
        }
@@ -5570,7 +5650,7 @@ static void __meminit setup_per_zone_inactive_ratio(void)
  * we want it large (64MB max).  But it is not linear, because network
  * bandwidth does not increase linearly with machine size.  We use
  *
- *     min_free_kbytes = 4 * sqrt(lowmem_kbytes), for better accuracy:
+ *     min_free_kbytes = 4 * sqrt(lowmem_kbytes), for better accuracy:
  *     min_free_kbytes = sqrt(lowmem_kbytes * 16)
  *
  * which yields
@@ -5614,11 +5694,11 @@ int __meminit init_per_zone_wmark_min(void)
 module_init(init_per_zone_wmark_min)
 
 /*
- * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so 
+ * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so
  *     that we can call two helper functions whenever min_free_kbytes
  *     changes.
  */
-int min_free_kbytes_sysctl_handler(ctl_table *table, int write, 
+int min_free_kbytes_sysctl_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
 {
        proc_dointvec(table, write, buffer, length, ppos);
@@ -5682,8 +5762,8 @@ int lowmem_reserve_ratio_sysctl_handler(ctl_table *table, int write,
 
 /*
  * percpu_pagelist_fraction - changes the pcp->high for each zone on each
- * cpu.  It is the fraction of total pages in each zone that a hot per cpu pagelist
- * can have before it gets flushed back to buddy allocator.
+ * cpu.  It is the fraction of total pages in each zone that a hot per cpu
+ * pagelist can have before it gets flushed back to buddy allocator.
  */
 int percpu_pagelist_fraction_sysctl_handler(ctl_table *table, int write,
        void __user *buffer, size_t *length, loff_t *ppos)
@@ -5745,9 +5825,10 @@ void *__init alloc_large_system_hash(const char *tablename,
        if (!numentries) {
                /* round applicable memory size up to nearest megabyte */
                numentries = nr_kernel_pages;
-               numentries += (1UL << (20 - PAGE_SHIFT)) - 1;
-               numentries >>= 20 - PAGE_SHIFT;
-               numentries <<= 20 - PAGE_SHIFT;
+
+               /* It isn't necessary when PAGE_SIZE >= 1MB */
+               if (PAGE_SHIFT < 20)
+                       numentries = round_up(numentries, (1<<20)/PAGE_SIZE);
 
                /* limit to 1 bucket per 2^scale bytes of low memory */
                if (scale > PAGE_SHIFT)
@@ -5900,7 +5981,7 @@ void set_pageblock_flags_group(struct page *page, unsigned long flags,
  * This function checks whether pageblock includes unmovable pages or not.
  * If @count is not zero, it is okay to include less @count unmovable pages
  *
- * PageLRU check wihtout isolation or lru_lock could race so that
+ * PageLRU check without isolation or lru_lock could race so that
  * MIGRATE_MOVABLE block might include unmovable pages. It means you can't
  * expect this function should be exact.
  */
@@ -5928,6 +6009,17 @@ bool has_unmovable_pages(struct zone *zone, struct page *page, int count,
                        continue;
 
                page = pfn_to_page(check);
+
+               /*
+                * Hugepages are not in LRU lists, but they're movable.
+                * We need not scan over tail pages bacause we don't
+                * handle each tail page individually in migration.
+                */
+               if (PageHuge(page)) {
+                       iter = round_up(iter + 1, 1<<compound_order(page)) - 1;
+                       continue;
+               }
+
                /*
                 * We can't use page_count without pin a page
                 * because another CPU can free compound page.
index ba05b64e5d8ddfc19f31c046f7c0b735d099364b..8c79a4764be0c99a1d573d174e2d247e90079519 100644 (file)
@@ -266,7 +266,6 @@ int __swap_writepage(struct page *page, struct writeback_control *wbc,
 
                init_sync_kiocb(&kiocb, swap_file);
                kiocb.ki_pos = page_file_offset(page);
-               kiocb.ki_left = PAGE_SIZE;
                kiocb.ki_nbytes = PAGE_SIZE;
 
                set_page_writeback(page);
index 0cee10ffb98d4cf8e6ad930faa1f4de925bdf3a5..d1473b2e9481731988695755a618baa0991556a7 100644 (file)
@@ -6,6 +6,7 @@
 #include <linux/page-isolation.h>
 #include <linux/pageblock-flags.h>
 #include <linux/memory.h>
+#include <linux/hugetlb.h>
 #include "internal.h"
 
 int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages)
@@ -252,6 +253,19 @@ struct page *alloc_migrate_target(struct page *page, unsigned long private,
 {
        gfp_t gfp_mask = GFP_USER | __GFP_MOVABLE;
 
+       /*
+        * TODO: allocate a destination hugepage from a nearest neighbor node,
+        * accordance with memory policy of the user process if possible. For
+        * now as a simple work-around, we use the next node for destination.
+        */
+       if (PageHuge(page)) {
+               nodemask_t src = nodemask_of_node(page_to_nid(page));
+               nodemask_t dst;
+               nodes_complement(dst, src);
+               return alloc_huge_page_node(page_hstate(compound_head(page)),
+                                           next_node(page_to_nid(page), dst));
+       }
+
        if (PageHighMem(page))
                gfp_mask |= __GFP_HIGHMEM;
 
index e1a6e4fab016200e94ec2c9e96b1c7f88281ed22..3929a40bd6c0a6d618d0dc0136fe6aecaad08628 100644 (file)
 #include <asm/tlb.h>
 #include <asm-generic/pgtable.h>
 
+/*
+ * If a p?d_bad entry is found while walking page tables, report
+ * the error, before resetting entry to p?d_none.  Usually (but
+ * very seldom) called out from the p?d_none_or_clear_bad macros.
+ */
+
+void pgd_clear_bad(pgd_t *pgd)
+{
+       pgd_ERROR(*pgd);
+       pgd_clear(pgd);
+}
+
+void pud_clear_bad(pud_t *pud)
+{
+       pud_ERROR(*pud);
+       pud_clear(pud);
+}
+
+void pmd_clear_bad(pmd_t *pmd)
+{
+       pmd_ERROR(*pmd);
+       pmd_clear(pmd);
+}
+
 #ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
 /*
  * Only sets the access flags (dirty, accessed), as well as write 
index 829a77c628348a78b9efc130689d549368a57567..e4ed04149785f069b201cd2ffaa9caa90c4b0d22 100644 (file)
@@ -371,10 +371,10 @@ static int try_context_readahead(struct address_space *mapping,
        size = count_history_pages(mapping, ra, offset, max);
 
        /*
-        * no history pages:
+        * not enough history pages:
         * it could be a random read
         */
-       if (!size)
+       if (size <= req_size)
                return 0;
 
        /*
@@ -385,8 +385,8 @@ static int try_context_readahead(struct address_space *mapping,
                size *= 2;
 
        ra->start = offset;
-       ra->size = get_init_ra_size(size + req_size, max);
-       ra->async_size = ra->size;
+       ra->size = min(size + req_size, max);
+       ra->async_size = 1;
 
        return 1;
 }
index 07748e68b72948744d7610db07d4a2abd7349545..fd3ee7a54a13a52c7d8761ff8e20508f352d083b 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1052,11 +1052,11 @@ void do_page_add_anon_rmap(struct page *page,
 {
        int first = atomic_inc_and_test(&page->_mapcount);
        if (first) {
-               if (!PageTransHuge(page))
-                       __inc_zone_page_state(page, NR_ANON_PAGES);
-               else
+               if (PageTransHuge(page))
                        __inc_zone_page_state(page,
                                              NR_ANON_TRANSPARENT_HUGEPAGES);
+               __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
+                               hpage_nr_pages(page));
        }
        if (unlikely(PageKsm(page)))
                return;
@@ -1085,10 +1085,10 @@ void page_add_new_anon_rmap(struct page *page,
        VM_BUG_ON(address < vma->vm_start || address >= vma->vm_end);
        SetPageSwapBacked(page);
        atomic_set(&page->_mapcount, 0); /* increment count (starts at -1) */
-       if (!PageTransHuge(page))
-               __inc_zone_page_state(page, NR_ANON_PAGES);
-       else
+       if (PageTransHuge(page))
                __inc_zone_page_state(page, NR_ANON_TRANSPARENT_HUGEPAGES);
+       __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
+                       hpage_nr_pages(page));
        __page_set_anon_rmap(page, vma, address, 1);
        if (!mlocked_vma_newpage(vma, page)) {
                SetPageActive(page);
@@ -1111,7 +1111,7 @@ void page_add_file_rmap(struct page *page)
        mem_cgroup_begin_update_page_stat(page, &locked, &flags);
        if (atomic_inc_and_test(&page->_mapcount)) {
                __inc_zone_page_state(page, NR_FILE_MAPPED);
-               mem_cgroup_inc_page_stat(page, MEMCG_NR_FILE_MAPPED);
+               mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
        }
        mem_cgroup_end_update_page_stat(page, &locked, &flags);
 }
@@ -1148,14 +1148,14 @@ void page_remove_rmap(struct page *page)
                goto out;
        if (anon) {
                mem_cgroup_uncharge_page(page);
-               if (!PageTransHuge(page))
-                       __dec_zone_page_state(page, NR_ANON_PAGES);
-               else
+               if (PageTransHuge(page))
                        __dec_zone_page_state(page,
                                              NR_ANON_TRANSPARENT_HUGEPAGES);
+               __mod_zone_page_state(page_zone(page), NR_ANON_PAGES,
+                               -hpage_nr_pages(page));
        } else {
                __dec_zone_page_state(page, NR_FILE_MAPPED);
-               mem_cgroup_dec_page_stat(page, MEMCG_NR_FILE_MAPPED);
+               mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_FILE_MAPPED);
                mem_cgroup_end_update_page_stat(page, &locked, &flags);
        }
        if (unlikely(PageMlocked(page)))
index 526149846d0a82370eaf96c32489a45152fd4f66..8297623fcaedec21b37b5080d376967e673afe92 100644 (file)
@@ -1205,7 +1205,7 @@ repeat:
                                                gfp & GFP_RECLAIM_MASK);
                if (error)
                        goto decused;
-               error = radix_tree_preload(gfp & GFP_RECLAIM_MASK);
+               error = radix_tree_maybe_preload(gfp & GFP_RECLAIM_MASK);
                if (!error) {
                        error = shmem_add_to_page_cache(page, mapping, index,
                                                        gfp, NULL);
@@ -2819,6 +2819,10 @@ int __init shmem_init(void)
 {
        int error;
 
+       /* If rootfs called this, don't re-init */
+       if (shmem_inode_cachep)
+               return 0;
+
        error = bdi_init(&shmem_backing_dev_info);
        if (error)
                goto out4;
index 538bade6df7dc2a3f27c9ad5ac5f0efc8a6d08bc..a3443278ce3a693b4c2625df3752a59e975abca3 100644 (file)
@@ -19,6 +19,7 @@
 #include <asm/tlbflush.h>
 #include <asm/page.h>
 #include <linux/memcontrol.h>
+#include <trace/events/kmem.h>
 
 #include "slab.h"
 
@@ -373,7 +374,7 @@ struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags)
 {
        int index;
 
-       if (size > KMALLOC_MAX_SIZE) {
+       if (unlikely(size > KMALLOC_MAX_SIZE)) {
                WARN_ON_ONCE(!(flags & __GFP_NOWARN));
                return NULL;
        }
@@ -495,6 +496,15 @@ void __init create_kmalloc_caches(unsigned long flags)
 }
 #endif /* !CONFIG_SLOB */
 
+#ifdef CONFIG_TRACING
+void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
+{
+       void *ret = kmalloc_order(size, flags, order);
+       trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags);
+       return ret;
+}
+EXPORT_SYMBOL(kmalloc_order_trace);
+#endif
 
 #ifdef CONFIG_SLABINFO
 
index 91bd3f2dd2f02622d6aa32802d2bdcd70ee922bd..4bf8809dfcce78f900c9c52b1f0aa0d614ece1bb 100644 (file)
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -462,11 +462,11 @@ __do_kmalloc_node(size_t size, gfp_t gfp, int node, unsigned long caller)
        return ret;
 }
 
-void *__kmalloc_node(size_t size, gfp_t gfp, int node)
+void *__kmalloc(size_t size, gfp_t gfp)
 {
-       return __do_kmalloc_node(size, gfp, node, _RET_IP_);
+       return __do_kmalloc_node(size, gfp, NUMA_NO_NODE, _RET_IP_);
 }
-EXPORT_SYMBOL(__kmalloc_node);
+EXPORT_SYMBOL(__kmalloc);
 
 #ifdef CONFIG_TRACING
 void *__kmalloc_track_caller(size_t size, gfp_t gfp, unsigned long caller)
@@ -534,7 +534,7 @@ int __kmem_cache_create(struct kmem_cache *c, unsigned long flags)
        return 0;
 }
 
-void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
+void *slob_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
 {
        void *b;
 
@@ -560,7 +560,27 @@ void *kmem_cache_alloc_node(struct kmem_cache *c, gfp_t flags, int node)
        kmemleak_alloc_recursive(b, c->size, 1, c->flags, flags);
        return b;
 }
+EXPORT_SYMBOL(slob_alloc_node);
+
+void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags)
+{
+       return slob_alloc_node(cachep, flags, NUMA_NO_NODE);
+}
+EXPORT_SYMBOL(kmem_cache_alloc);
+
+#ifdef CONFIG_NUMA
+void *__kmalloc_node(size_t size, gfp_t gfp, int node)
+{
+       return __do_kmalloc_node(size, gfp, node, _RET_IP_);
+}
+EXPORT_SYMBOL(__kmalloc_node);
+
+void *kmem_cache_alloc_node(struct kmem_cache *cachep, gfp_t gfp, int node)
+{
+       return slob_alloc_node(cachep, gfp, node);
+}
 EXPORT_SYMBOL(kmem_cache_alloc_node);
+#endif
 
 static void __kmem_cache_free(void *b, int size)
 {
index e3ba1f2cf60cc0caa5dd7ed059dbe583b477e073..c3eb3d3ca83565b925e197f2ad44ac2c313345b8 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -373,7 +373,8 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
 #endif
        {
                slab_lock(page);
-               if (page->freelist == freelist_old && page->counters == counters_old) {
+               if (page->freelist == freelist_old &&
+                                       page->counters == counters_old) {
                        page->freelist = freelist_new;
                        page->counters = counters_new;
                        slab_unlock(page);
@@ -411,7 +412,8 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
 
                local_irq_save(flags);
                slab_lock(page);
-               if (page->freelist == freelist_old && page->counters == counters_old) {
+               if (page->freelist == freelist_old &&
+                                       page->counters == counters_old) {
                        page->freelist = freelist_new;
                        page->counters = counters_new;
                        slab_unlock(page);
@@ -553,8 +555,9 @@ static void print_tracking(struct kmem_cache *s, void *object)
 
 static void print_page_info(struct page *page)
 {
-       printk(KERN_ERR "INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n",
-               page, page->objects, page->inuse, page->freelist, page->flags);
+       printk(KERN_ERR
+              "INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n",
+              page, page->objects, page->inuse, page->freelist, page->flags);
 
 }
 
@@ -629,7 +632,8 @@ static void object_err(struct kmem_cache *s, struct page *page,
        print_trailer(s, page, object);
 }
 
-static void slab_err(struct kmem_cache *s, struct page *page, const char *fmt, ...)
+static void slab_err(struct kmem_cache *s, struct page *page,
+                       const char *fmt, ...)
 {
        va_list args;
        char buf[100];
@@ -788,7 +792,8 @@ static int check_object(struct kmem_cache *s, struct page *page,
        } else {
                if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) {
                        check_bytes_and_report(s, page, p, "Alignment padding",
-                               endobject, POISON_INUSE, s->inuse - s->object_size);
+                               endobject, POISON_INUSE,
+                               s->inuse - s->object_size);
                }
        }
 
@@ -873,7 +878,6 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
                                object_err(s, page, object,
                                        "Freechain corrupt");
                                set_freepointer(s, object, NULL);
-                               break;
                        } else {
                                slab_err(s, page, "Freepointer corrupt");
                                page->freelist = NULL;
@@ -918,7 +922,8 @@ static void trace(struct kmem_cache *s, struct page *page, void *object,
                        page->freelist);
 
                if (!alloc)
-                       print_section("Object ", (void *)object, s->object_size);
+                       print_section("Object ", (void *)object,
+                                       s->object_size);
 
                dump_stack();
        }
@@ -937,7 +942,8 @@ static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
        return should_failslab(s->object_size, flags, s->flags);
 }
 
-static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, void *object)
+static inline void slab_post_alloc_hook(struct kmem_cache *s,
+                                       gfp_t flags, void *object)
 {
        flags &= gfp_allowed_mask;
        kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
@@ -1039,7 +1045,8 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
        init_tracking(s, object);
 }
 
-static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *page,
+static noinline int alloc_debug_processing(struct kmem_cache *s,
+                                       struct page *page,
                                        void *object, unsigned long addr)
 {
        if (!check_slab(s, page))
@@ -1743,7 +1750,8 @@ static void init_kmem_cache_cpus(struct kmem_cache *s)
 /*
  * Remove the cpu slab
  */
-static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist)
+static void deactivate_slab(struct kmem_cache *s, struct page *page,
+                               void *freelist)
 {
        enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
@@ -1999,7 +2007,8 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
                page->pobjects = pobjects;
                page->next = oldpage;
 
-       } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) != oldpage);
+       } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page)
+                                                               != oldpage);
 #endif
 }
 
@@ -2169,8 +2178,8 @@ static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags)
 }
 
 /*
- * Check the page->freelist of a page and either transfer the freelist to the per cpu freelist
- * or deactivate the page.
+ * Check the page->freelist of a page and either transfer the freelist to the
+ * per cpu freelist or deactivate the page.
  *
  * The page is still frozen if the return value is not NULL.
  *
@@ -2314,7 +2323,8 @@ new_slab:
                goto load_freelist;
 
        /* Only entered in the debug case */
-       if (kmem_cache_debug(s) && !alloc_debug_processing(s, page, freelist, addr))
+       if (kmem_cache_debug(s) &&
+                       !alloc_debug_processing(s, page, freelist, addr))
                goto new_slab;  /* Slab failed checks. Next slab needed */
 
        deactivate_slab(s, page, get_freepointer(s, freelist));
@@ -2372,7 +2382,7 @@ redo:
 
        object = c->freelist;
        page = c->page;
-       if (unlikely(!object || !page || !node_match(page, node)))
+       if (unlikely(!object || !node_match(page, node)))
                object = __slab_alloc(s, gfpflags, node, addr, c);
 
        else {
@@ -2382,13 +2392,15 @@ redo:
                 * The cmpxchg will only match if there was no additional
                 * operation and if we are on the right processor.
                 *
-                * The cmpxchg does the following atomically (without lock semantics!)
+                * The cmpxchg does the following atomically (without lock
+                * semantics!)
                 * 1. Relocate first pointer to the current per cpu area.
                 * 2. Verify that tid and freelist have not been changed
                 * 3. If they were not changed replace tid and freelist
                 *
-                * Since this is without lock semantics the protection is only against
-                * code executing on this cpu *not* from access by other cpus.
+                * Since this is without lock semantics the protection is only
+                * against code executing on this cpu *not* from access by
+                * other cpus.
                 */
                if (unlikely(!this_cpu_cmpxchg_double(
                                s->cpu_slab->freelist, s->cpu_slab->tid,
@@ -2420,7 +2432,8 @@ void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
 {
        void *ret = slab_alloc(s, gfpflags, _RET_IP_);
 
-       trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, s->size, gfpflags);
+       trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size,
+                               s->size, gfpflags);
 
        return ret;
 }
@@ -2434,14 +2447,6 @@ void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size)
        return ret;
 }
 EXPORT_SYMBOL(kmem_cache_alloc_trace);
-
-void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
-{
-       void *ret = kmalloc_order(size, flags, order);
-       trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags);
-       return ret;
-}
-EXPORT_SYMBOL(kmalloc_order_trace);
 #endif
 
 #ifdef CONFIG_NUMA
@@ -2512,8 +2517,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
                        if (kmem_cache_has_cpu_partial(s) && !prior)
 
                                /*
-                                * Slab was on no list before and will be partially empty
-                                * We can defer the list move and instead freeze it.
+                                * Slab was on no list before and will be
+                                * partially empty
+                                * We can defer the list move and instead
+                                * freeze it.
                                 */
                                new.frozen = 1;
 
@@ -3071,8 +3078,8 @@ static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
         * A) The number of objects from per cpu partial slabs dumped to the
         *    per node list when we reach the limit.
         * B) The number of objects in cpu partial slabs to extract from the
-        *    per node list when we run out of per cpu objects. We only fetch 50%
-        *    to keep some capacity around for frees.
+        *    per node list when we run out of per cpu objects. We only fetch
+        *    50% to keep some capacity around for frees.
         */
        if (!kmem_cache_has_cpu_partial(s))
                s->cpu_partial = 0;
@@ -3099,8 +3106,8 @@ error:
        if (flags & SLAB_PANIC)
                panic("Cannot create slab %s size=%lu realsize=%u "
                        "order=%u offset=%u flags=%lx\n",
-                       s->name, (unsigned long)s->size, s->size, oo_order(s->oo),
-                       s->offset, flags);
+                       s->name, (unsigned long)s->size, s->size,
+                       oo_order(s->oo), s->offset, flags);
        return -EINVAL;
 }
 
@@ -3316,42 +3323,6 @@ size_t ksize(const void *object)
 }
 EXPORT_SYMBOL(ksize);
 
-#ifdef CONFIG_SLUB_DEBUG
-bool verify_mem_not_deleted(const void *x)
-{
-       struct page *page;
-       void *object = (void *)x;
-       unsigned long flags;
-       bool rv;
-
-       if (unlikely(ZERO_OR_NULL_PTR(x)))
-               return false;
-
-       local_irq_save(flags);
-
-       page = virt_to_head_page(x);
-       if (unlikely(!PageSlab(page))) {
-               /* maybe it was from stack? */
-               rv = true;
-               goto out_unlock;
-       }
-
-       slab_lock(page);
-       if (on_freelist(page->slab_cache, page, object)) {
-               object_err(page->slab_cache, page, object, "Object is on free-list");
-               rv = false;
-       } else {
-               rv = true;
-       }
-       slab_unlock(page);
-
-out_unlock:
-       local_irq_restore(flags);
-       return rv;
-}
-EXPORT_SYMBOL(verify_mem_not_deleted);
-#endif
-
 void kfree(const void *x)
 {
        struct page *page;
@@ -4162,15 +4133,17 @@ static int list_locations(struct kmem_cache *s, char *buf,
                                !cpumask_empty(to_cpumask(l->cpus)) &&
                                len < PAGE_SIZE - 60) {
                        len += sprintf(buf + len, " cpus=");
-                       len += cpulist_scnprintf(buf + len, PAGE_SIZE - len - 50,
+                       len += cpulist_scnprintf(buf + len,
+                                                PAGE_SIZE - len - 50,
                                                 to_cpumask(l->cpus));
                }
 
                if (nr_online_nodes > 1 && !nodes_empty(l->nodes) &&
                                len < PAGE_SIZE - 60) {
                        len += sprintf(buf + len, " nodes=");
-                       len += nodelist_scnprintf(buf + len, PAGE_SIZE - len - 50,
-                                       l->nodes);
+                       len += nodelist_scnprintf(buf + len,
+                                                 PAGE_SIZE - len - 50,
+                                                 l->nodes);
                }
 
                len += sprintf(buf + len, "\n");
@@ -4268,18 +4241,17 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
        int node;
        int x;
        unsigned long *nodes;
-       unsigned long *per_cpu;
 
-       nodes = kzalloc(2 * sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
+       nodes = kzalloc(sizeof(unsigned long) * nr_node_ids, GFP_KERNEL);
        if (!nodes)
                return -ENOMEM;
-       per_cpu = nodes + nr_node_ids;
 
        if (flags & SO_CPU) {
                int cpu;
 
                for_each_possible_cpu(cpu) {
-                       struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
+                       struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab,
+                                                              cpu);
                        int node;
                        struct page *page;
 
@@ -4304,8 +4276,6 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                                total += x;
                                nodes[node] += x;
                        }
-
-                       per_cpu[node]++;
                }
        }
 
@@ -4315,12 +4285,11 @@ static ssize_t show_slab_objects(struct kmem_cache *s,
                for_each_node_state(node, N_NORMAL_MEMORY) {
                        struct kmem_cache_node *n = get_node(s, node);
 
-               if (flags & SO_TOTAL)
-                       x = atomic_long_read(&n->total_objects);
-               else if (flags & SO_OBJECTS)
-                       x = atomic_long_read(&n->total_objects) -
-                               count_partial(n, count_free);
-
+                       if (flags & SO_TOTAL)
+                               x = atomic_long_read(&n->total_objects);
+                       else if (flags & SO_OBJECTS)
+                               x = atomic_long_read(&n->total_objects) -
+                                       count_partial(n, count_free);
                        else
                                x = atomic_long_read(&n->nr_slabs);
                        total += x;
@@ -4420,7 +4389,7 @@ static ssize_t order_store(struct kmem_cache *s,
        unsigned long order;
        int err;
 
-       err = strict_strtoul(buf, 10, &order);
+       err = kstrtoul(buf, 10, &order);
        if (err)
                return err;
 
@@ -4448,7 +4417,7 @@ static ssize_t min_partial_store(struct kmem_cache *s, const char *buf,
        unsigned long min;
        int err;
 
-       err = strict_strtoul(buf, 10, &min);
+       err = kstrtoul(buf, 10, &min);
        if (err)
                return err;
 
@@ -4468,7 +4437,7 @@ static ssize_t cpu_partial_store(struct kmem_cache *s, const char *buf,
        unsigned long objects;
        int err;
 
-       err = strict_strtoul(buf, 10, &objects);
+       err = kstrtoul(buf, 10, &objects);
        if (err)
                return err;
        if (objects && !kmem_cache_has_cpu_partial(s))
@@ -4784,7 +4753,7 @@ static ssize_t remote_node_defrag_ratio_store(struct kmem_cache *s,
        unsigned long ratio;
        int err;
 
-       err = strict_strtoul(buf, 10, &ratio);
+       err = kstrtoul(buf, 10, &ratio);
        if (err)
                return err;
 
@@ -5136,7 +5105,8 @@ static char *create_unique_id(struct kmem_cache *s)
 
 #ifdef CONFIG_MEMCG_KMEM
        if (!is_root_cache(s))
-               p += sprintf(p, "-%08d", memcg_cache_id(s->memcg_params->memcg));
+               p += sprintf(p, "-%08d",
+                               memcg_cache_id(s->memcg_params->memcg));
 #endif
 
        BUG_ON(p > name + ID_STR_LENGTH - 1);
index 308d50331bc353e69f00b8ef7ea78555b1426224..4ac1d7ef548f8ce75b65ae64057c300c8b0cc48c 100644 (file)
@@ -339,13 +339,14 @@ static void __init check_usemap_section_nr(int nid, unsigned long *usemap)
 }
 #endif /* CONFIG_MEMORY_HOTREMOVE */
 
-static void __init sparse_early_usemaps_alloc_node(unsigned long**usemap_map,
+static void __init sparse_early_usemaps_alloc_node(void *data,
                                 unsigned long pnum_begin,
                                 unsigned long pnum_end,
                                 unsigned long usemap_count, int nodeid)
 {
        void *usemap;
        unsigned long pnum;
+       unsigned long **usemap_map = (unsigned long **)data;
        int size = usemap_size();
 
        usemap = sparse_early_usemaps_alloc_pgdat_section(NODE_DATA(nodeid),
@@ -430,11 +431,12 @@ void __init sparse_mem_maps_populate_node(struct page **map_map,
 #endif /* !CONFIG_SPARSEMEM_VMEMMAP */
 
 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-static void __init sparse_early_mem_maps_alloc_node(struct page **map_map,
+static void __init sparse_early_mem_maps_alloc_node(void *data,
                                 unsigned long pnum_begin,
                                 unsigned long pnum_end,
                                 unsigned long map_count, int nodeid)
 {
+       struct page **map_map = (struct page **)data;
        sparse_mem_maps_populate_node(map_map, pnum_begin, pnum_end,
                                         map_count, nodeid);
 }
@@ -460,6 +462,55 @@ void __attribute__((weak)) __meminit vmemmap_populate_print_last(void)
 {
 }
 
+/**
+ *  alloc_usemap_and_memmap - memory alloction for pageblock flags and vmemmap
+ *  @map: usemap_map for pageblock flags or mmap_map for vmemmap
+ */
+static void __init alloc_usemap_and_memmap(void (*alloc_func)
+                                       (void *, unsigned long, unsigned long,
+                                       unsigned long, int), void *data)
+{
+       unsigned long pnum;
+       unsigned long map_count;
+       int nodeid_begin = 0;
+       unsigned long pnum_begin = 0;
+
+       for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
+               struct mem_section *ms;
+
+               if (!present_section_nr(pnum))
+                       continue;
+               ms = __nr_to_section(pnum);
+               nodeid_begin = sparse_early_nid(ms);
+               pnum_begin = pnum;
+               break;
+       }
+       map_count = 1;
+       for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) {
+               struct mem_section *ms;
+               int nodeid;
+
+               if (!present_section_nr(pnum))
+                       continue;
+               ms = __nr_to_section(pnum);
+               nodeid = sparse_early_nid(ms);
+               if (nodeid == nodeid_begin) {
+                       map_count++;
+                       continue;
+               }
+               /* ok, we need to take cake of from pnum_begin to pnum - 1*/
+               alloc_func(data, pnum_begin, pnum,
+                                               map_count, nodeid_begin);
+               /* new start, update count etc*/
+               nodeid_begin = nodeid;
+               pnum_begin = pnum;
+               map_count = 1;
+       }
+       /* ok, last chunk */
+       alloc_func(data, pnum_begin, NR_MEM_SECTIONS,
+                                               map_count, nodeid_begin);
+}
+
 /*
  * Allocate the accumulated non-linear sections, allocate a mem_map
  * for each and record the physical to section mapping.
@@ -471,11 +522,7 @@ void __init sparse_init(void)
        unsigned long *usemap;
        unsigned long **usemap_map;
        int size;
-       int nodeid_begin = 0;
-       unsigned long pnum_begin = 0;
-       unsigned long usemap_count;
 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
-       unsigned long map_count;
        int size2;
        struct page **map_map;
 #endif
@@ -501,82 +548,16 @@ void __init sparse_init(void)
        usemap_map = alloc_bootmem(size);
        if (!usemap_map)
                panic("can not allocate usemap_map\n");
-
-       for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
-               struct mem_section *ms;
-
-               if (!present_section_nr(pnum))
-                       continue;
-               ms = __nr_to_section(pnum);
-               nodeid_begin = sparse_early_nid(ms);
-               pnum_begin = pnum;
-               break;
-       }
-       usemap_count = 1;
-       for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) {
-               struct mem_section *ms;
-               int nodeid;
-
-               if (!present_section_nr(pnum))
-                       continue;
-               ms = __nr_to_section(pnum);
-               nodeid = sparse_early_nid(ms);
-               if (nodeid == nodeid_begin) {
-                       usemap_count++;
-                       continue;
-               }
-               /* ok, we need to take cake of from pnum_begin to pnum - 1*/
-               sparse_early_usemaps_alloc_node(usemap_map, pnum_begin, pnum,
-                                                usemap_count, nodeid_begin);
-               /* new start, update count etc*/
-               nodeid_begin = nodeid;
-               pnum_begin = pnum;
-               usemap_count = 1;
-       }
-       /* ok, last chunk */
-       sparse_early_usemaps_alloc_node(usemap_map, pnum_begin, NR_MEM_SECTIONS,
-                                        usemap_count, nodeid_begin);
+       alloc_usemap_and_memmap(sparse_early_usemaps_alloc_node,
+                                                       (void *)usemap_map);
 
 #ifdef CONFIG_SPARSEMEM_ALLOC_MEM_MAP_TOGETHER
        size2 = sizeof(struct page *) * NR_MEM_SECTIONS;
        map_map = alloc_bootmem(size2);
        if (!map_map)
                panic("can not allocate map_map\n");
-
-       for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
-               struct mem_section *ms;
-
-               if (!present_section_nr(pnum))
-                       continue;
-               ms = __nr_to_section(pnum);
-               nodeid_begin = sparse_early_nid(ms);
-               pnum_begin = pnum;
-               break;
-       }
-       map_count = 1;
-       for (pnum = pnum_begin + 1; pnum < NR_MEM_SECTIONS; pnum++) {
-               struct mem_section *ms;
-               int nodeid;
-
-               if (!present_section_nr(pnum))
-                       continue;
-               ms = __nr_to_section(pnum);
-               nodeid = sparse_early_nid(ms);
-               if (nodeid == nodeid_begin) {
-                       map_count++;
-                       continue;
-               }
-               /* ok, we need to take cake of from pnum_begin to pnum - 1*/
-               sparse_early_mem_maps_alloc_node(map_map, pnum_begin, pnum,
-                                                map_count, nodeid_begin);
-               /* new start, update count etc*/
-               nodeid_begin = nodeid;
-               pnum_begin = pnum;
-               map_count = 1;
-       }
-       /* ok, last chunk */
-       sparse_early_mem_maps_alloc_node(map_map, pnum_begin, NR_MEM_SECTIONS,
-                                        map_count, nodeid_begin);
+       alloc_usemap_and_memmap(sparse_early_mem_maps_alloc_node,
+                                                       (void *)map_map);
 #endif
 
        for (pnum = 0; pnum < NR_MEM_SECTIONS; pnum++) {
index 62b78a6e224f2f10682e9fa11f28b8d01da1c324..759c3caf44bd21bef216c6a011981f150615646b 100644 (file)
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -31,6 +31,7 @@
 #include <linux/memcontrol.h>
 #include <linux/gfp.h>
 #include <linux/uio.h>
+#include <linux/hugetlb.h>
 
 #include "internal.h"
 
@@ -81,6 +82,19 @@ static void __put_compound_page(struct page *page)
 
 static void put_compound_page(struct page *page)
 {
+       /*
+        * hugetlbfs pages cannot be split from under us.  If this is a
+        * hugetlbfs page, check refcount on head page and release the page if
+        * the refcount becomes zero.
+        */
+       if (PageHuge(page)) {
+               page = compound_head(page);
+               if (put_page_testzero(page))
+                       __put_compound_page(page);
+
+               return;
+       }
+
        if (unlikely(PageTail(page))) {
                /* __split_huge_page_refcount can run under us */
                struct page *page_head = compound_trans_head(page);
@@ -184,38 +198,51 @@ bool __get_page_tail(struct page *page)
         * proper PT lock that already serializes against
         * split_huge_page().
         */
-       unsigned long flags;
        bool got = false;
-       struct page *page_head = compound_trans_head(page);
+       struct page *page_head;
 
-       if (likely(page != page_head && get_page_unless_zero(page_head))) {
+       /*
+        * If this is a hugetlbfs page it cannot be split under us.  Simply
+        * increment refcount for the head page.
+        */
+       if (PageHuge(page)) {
+               page_head = compound_head(page);
+               atomic_inc(&page_head->_count);
+               got = true;
+       } else {
+               unsigned long flags;
 
-               /* Ref to put_compound_page() comment. */
-               if (PageSlab(page_head)) {
+               page_head = compound_trans_head(page);
+               if (likely(page != page_head &&
+                                       get_page_unless_zero(page_head))) {
+
+                       /* Ref to put_compound_page() comment. */
+                       if (PageSlab(page_head)) {
+                               if (likely(PageTail(page))) {
+                                       __get_page_tail_foll(page, false);
+                                       return true;
+                               } else {
+                                       put_page(page_head);
+                                       return false;
+                               }
+                       }
+
+                       /*
+                        * page_head wasn't a dangling pointer but it
+                        * may not be a head page anymore by the time
+                        * we obtain the lock. That is ok as long as it
+                        * can't be freed from under us.
+                        */
+                       flags = compound_lock_irqsave(page_head);
+                       /* here __split_huge_page_refcount won't run anymore */
                        if (likely(PageTail(page))) {
                                __get_page_tail_foll(page, false);
-                               return true;
-                       } else {
-                               put_page(page_head);
-                               return false;
+                               got = true;
                        }
+                       compound_unlock_irqrestore(page_head, flags);
+                       if (unlikely(!got))
+                               put_page(page_head);
                }
-
-               /*
-                * page_head wasn't a dangling pointer but it
-                * may not be a head page anymore by the time
-                * we obtain the lock. That is ok as long as it
-                * can't be freed from under us.
-                */
-               flags = compound_lock_irqsave(page_head);
-               /* here __split_huge_page_refcount won't run anymore */
-               if (likely(PageTail(page))) {
-                       __get_page_tail_foll(page, false);
-                       got = true;
-               }
-               compound_unlock_irqrestore(page_head, flags);
-               if (unlikely(!got))
-                       put_page(page_head);
        }
        return got;
 }
@@ -405,6 +432,11 @@ static void activate_page_drain(int cpu)
                pagevec_lru_move_fn(pvec, __activate_page, NULL);
 }
 
+static bool need_activate_page_drain(int cpu)
+{
+       return pagevec_count(&per_cpu(activate_page_pvecs, cpu)) != 0;
+}
+
 void activate_page(struct page *page)
 {
        if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) {
@@ -422,6 +454,11 @@ static inline void activate_page_drain(int cpu)
 {
 }
 
+static bool need_activate_page_drain(int cpu)
+{
+       return false;
+}
+
 void activate_page(struct page *page)
 {
        struct zone *zone = page_zone(page);
@@ -674,12 +711,36 @@ static void lru_add_drain_per_cpu(struct work_struct *dummy)
        lru_add_drain();
 }
 
-/*
- * Returns 0 for success
- */
-int lru_add_drain_all(void)
+static DEFINE_PER_CPU(struct work_struct, lru_add_drain_work);
+
+void lru_add_drain_all(void)
 {
-       return schedule_on_each_cpu(lru_add_drain_per_cpu);
+       static DEFINE_MUTEX(lock);
+       static struct cpumask has_work;
+       int cpu;
+
+       mutex_lock(&lock);
+       get_online_cpus();
+       cpumask_clear(&has_work);
+
+       for_each_online_cpu(cpu) {
+               struct work_struct *work = &per_cpu(lru_add_drain_work, cpu);
+
+               if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) ||
+                   pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) ||
+                   pagevec_count(&per_cpu(lru_deactivate_pvecs, cpu)) ||
+                   need_activate_page_drain(cpu)) {
+                       INIT_WORK(work, lru_add_drain_per_cpu);
+                       schedule_work_on(cpu, work);
+                       cpumask_set_cpu(cpu, &has_work);
+               }
+       }
+
+       for_each_cpu(cpu, &has_work)
+               flush_work(&per_cpu(lru_add_drain_work, cpu));
+
+       put_online_cpus();
+       mutex_unlock(&lock);
 }
 
 /*
index f24ab0dff554262e1da6866b866a4584871f8d9c..e6f15f8ca2af339ce9e90159bae0e6a800f06819 100644 (file)
@@ -122,7 +122,7 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
 {
        int error;
 
-       error = radix_tree_preload(gfp_mask);
+       error = radix_tree_maybe_preload(gfp_mask);
        if (!error) {
                error = __add_to_swap_cache(page, entry);
                radix_tree_preload_end();
@@ -328,7 +328,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                /*
                 * call radix_tree_preload() while we can wait.
                 */
-               err = radix_tree_preload(gfp_mask & GFP_KERNEL);
+               err = radix_tree_maybe_preload(gfp_mask & GFP_KERNEL);
                if (err)
                        break;
 
index 6cf2e60983b7c36c5dea0b745e6aadd907c01532..3963fc24fcc1b6f8c4d365de4d99bda8993311b7 100644 (file)
@@ -175,14 +175,296 @@ static void discard_swap_cluster(struct swap_info_struct *si,
        }
 }
 
-static int wait_for_discard(void *word)
+#define SWAPFILE_CLUSTER       256
+#define LATENCY_LIMIT          256
+
+static inline void cluster_set_flag(struct swap_cluster_info *info,
+       unsigned int flag)
 {
-       schedule();
-       return 0;
+       info->flags = flag;
 }
 
-#define SWAPFILE_CLUSTER       256
-#define LATENCY_LIMIT          256
+static inline unsigned int cluster_count(struct swap_cluster_info *info)
+{
+       return info->data;
+}
+
+static inline void cluster_set_count(struct swap_cluster_info *info,
+                                    unsigned int c)
+{
+       info->data = c;
+}
+
+static inline void cluster_set_count_flag(struct swap_cluster_info *info,
+                                        unsigned int c, unsigned int f)
+{
+       info->flags = f;
+       info->data = c;
+}
+
+static inline unsigned int cluster_next(struct swap_cluster_info *info)
+{
+       return info->data;
+}
+
+static inline void cluster_set_next(struct swap_cluster_info *info,
+                                   unsigned int n)
+{
+       info->data = n;
+}
+
+static inline void cluster_set_next_flag(struct swap_cluster_info *info,
+                                        unsigned int n, unsigned int f)
+{
+       info->flags = f;
+       info->data = n;
+}
+
+static inline bool cluster_is_free(struct swap_cluster_info *info)
+{
+       return info->flags & CLUSTER_FLAG_FREE;
+}
+
+static inline bool cluster_is_null(struct swap_cluster_info *info)
+{
+       return info->flags & CLUSTER_FLAG_NEXT_NULL;
+}
+
+static inline void cluster_set_null(struct swap_cluster_info *info)
+{
+       info->flags = CLUSTER_FLAG_NEXT_NULL;
+       info->data = 0;
+}
+
+/* Add a cluster to discard list and schedule it to do discard */
+static void swap_cluster_schedule_discard(struct swap_info_struct *si,
+               unsigned int idx)
+{
+       /*
+        * If scan_swap_map() can't find a free cluster, it will check
+        * si->swap_map directly. To make sure the discarding cluster isn't
+        * taken by scan_swap_map(), mark the swap entries bad (occupied). It
+        * will be cleared after discard
+        */
+       memset(si->swap_map + idx * SWAPFILE_CLUSTER,
+                       SWAP_MAP_BAD, SWAPFILE_CLUSTER);
+
+       if (cluster_is_null(&si->discard_cluster_head)) {
+               cluster_set_next_flag(&si->discard_cluster_head,
+                                               idx, 0);
+               cluster_set_next_flag(&si->discard_cluster_tail,
+                                               idx, 0);
+       } else {
+               unsigned int tail = cluster_next(&si->discard_cluster_tail);
+               cluster_set_next(&si->cluster_info[tail], idx);
+               cluster_set_next_flag(&si->discard_cluster_tail,
+                                               idx, 0);
+       }
+
+       schedule_work(&si->discard_work);
+}
+
+/*
+ * Doing discard actually. After a cluster discard is finished, the cluster
+ * will be added to free cluster list. caller should hold si->lock.
+*/
+static void swap_do_scheduled_discard(struct swap_info_struct *si)
+{
+       struct swap_cluster_info *info;
+       unsigned int idx;
+
+       info = si->cluster_info;
+
+       while (!cluster_is_null(&si->discard_cluster_head)) {
+               idx = cluster_next(&si->discard_cluster_head);
+
+               cluster_set_next_flag(&si->discard_cluster_head,
+                                               cluster_next(&info[idx]), 0);
+               if (cluster_next(&si->discard_cluster_tail) == idx) {
+                       cluster_set_null(&si->discard_cluster_head);
+                       cluster_set_null(&si->discard_cluster_tail);
+               }
+               spin_unlock(&si->lock);
+
+               discard_swap_cluster(si, idx * SWAPFILE_CLUSTER,
+                               SWAPFILE_CLUSTER);
+
+               spin_lock(&si->lock);
+               cluster_set_flag(&info[idx], CLUSTER_FLAG_FREE);
+               if (cluster_is_null(&si->free_cluster_head)) {
+                       cluster_set_next_flag(&si->free_cluster_head,
+                                               idx, 0);
+                       cluster_set_next_flag(&si->free_cluster_tail,
+                                               idx, 0);
+               } else {
+                       unsigned int tail;
+
+                       tail = cluster_next(&si->free_cluster_tail);
+                       cluster_set_next(&info[tail], idx);
+                       cluster_set_next_flag(&si->free_cluster_tail,
+                                               idx, 0);
+               }
+               memset(si->swap_map + idx * SWAPFILE_CLUSTER,
+                               0, SWAPFILE_CLUSTER);
+       }
+}
+
+static void swap_discard_work(struct work_struct *work)
+{
+       struct swap_info_struct *si;
+
+       si = container_of(work, struct swap_info_struct, discard_work);
+
+       spin_lock(&si->lock);
+       swap_do_scheduled_discard(si);
+       spin_unlock(&si->lock);
+}
+
+/*
+ * The cluster corresponding to page_nr will be used. The cluster will be
+ * removed from free cluster list and its usage counter will be increased.
+ */
+static void inc_cluster_info_page(struct swap_info_struct *p,
+       struct swap_cluster_info *cluster_info, unsigned long page_nr)
+{
+       unsigned long idx = page_nr / SWAPFILE_CLUSTER;
+
+       if (!cluster_info)
+               return;
+       if (cluster_is_free(&cluster_info[idx])) {
+               VM_BUG_ON(cluster_next(&p->free_cluster_head) != idx);
+               cluster_set_next_flag(&p->free_cluster_head,
+                       cluster_next(&cluster_info[idx]), 0);
+               if (cluster_next(&p->free_cluster_tail) == idx) {
+                       cluster_set_null(&p->free_cluster_tail);
+                       cluster_set_null(&p->free_cluster_head);
+               }
+               cluster_set_count_flag(&cluster_info[idx], 0, 0);
+       }
+
+       VM_BUG_ON(cluster_count(&cluster_info[idx]) >= SWAPFILE_CLUSTER);
+       cluster_set_count(&cluster_info[idx],
+               cluster_count(&cluster_info[idx]) + 1);
+}
+
+/*
+ * The cluster corresponding to page_nr decreases one usage. If the usage
+ * counter becomes 0, which means no page in the cluster is in using, we can
+ * optionally discard the cluster and add it to free cluster list.
+ */
+static void dec_cluster_info_page(struct swap_info_struct *p,
+       struct swap_cluster_info *cluster_info, unsigned long page_nr)
+{
+       unsigned long idx = page_nr / SWAPFILE_CLUSTER;
+
+       if (!cluster_info)
+               return;
+
+       VM_BUG_ON(cluster_count(&cluster_info[idx]) == 0);
+       cluster_set_count(&cluster_info[idx],
+               cluster_count(&cluster_info[idx]) - 1);
+
+       if (cluster_count(&cluster_info[idx]) == 0) {
+               /*
+                * If the swap is discardable, prepare discard the cluster
+                * instead of free it immediately. The cluster will be freed
+                * after discard.
+                */
+               if ((p->flags & (SWP_WRITEOK | SWP_PAGE_DISCARD)) ==
+                                (SWP_WRITEOK | SWP_PAGE_DISCARD)) {
+                       swap_cluster_schedule_discard(p, idx);
+                       return;
+               }
+
+               cluster_set_flag(&cluster_info[idx], CLUSTER_FLAG_FREE);
+               if (cluster_is_null(&p->free_cluster_head)) {
+                       cluster_set_next_flag(&p->free_cluster_head, idx, 0);
+                       cluster_set_next_flag(&p->free_cluster_tail, idx, 0);
+               } else {
+                       unsigned int tail = cluster_next(&p->free_cluster_tail);
+                       cluster_set_next(&cluster_info[tail], idx);
+                       cluster_set_next_flag(&p->free_cluster_tail, idx, 0);
+               }
+       }
+}
+
+/*
+ * It's possible scan_swap_map() uses a free cluster in the middle of free
+ * cluster list. Avoiding such abuse to avoid list corruption.
+ */
+static bool
+scan_swap_map_ssd_cluster_conflict(struct swap_info_struct *si,
+       unsigned long offset)
+{
+       struct percpu_cluster *percpu_cluster;
+       bool conflict;
+
+       offset /= SWAPFILE_CLUSTER;
+       conflict = !cluster_is_null(&si->free_cluster_head) &&
+               offset != cluster_next(&si->free_cluster_head) &&
+               cluster_is_free(&si->cluster_info[offset]);
+
+       if (!conflict)
+               return false;
+
+       percpu_cluster = this_cpu_ptr(si->percpu_cluster);
+       cluster_set_null(&percpu_cluster->index);
+       return true;
+}
+
+/*
+ * Try to get a swap entry from current cpu's swap entry pool (a cluster). This
+ * might involve allocating a new cluster for current CPU too.
+ */
+static void scan_swap_map_try_ssd_cluster(struct swap_info_struct *si,
+       unsigned long *offset, unsigned long *scan_base)
+{
+       struct percpu_cluster *cluster;
+       bool found_free;
+       unsigned long tmp;
+
+new_cluster:
+       cluster = this_cpu_ptr(si->percpu_cluster);
+       if (cluster_is_null(&cluster->index)) {
+               if (!cluster_is_null(&si->free_cluster_head)) {
+                       cluster->index = si->free_cluster_head;
+                       cluster->next = cluster_next(&cluster->index) *
+                                       SWAPFILE_CLUSTER;
+               } else if (!cluster_is_null(&si->discard_cluster_head)) {
+                       /*
+                        * we don't have free cluster but have some clusters in
+                        * discarding, do discard now and reclaim them
+                        */
+                       swap_do_scheduled_discard(si);
+                       *scan_base = *offset = si->cluster_next;
+                       goto new_cluster;
+               } else
+                       return;
+       }
+
+       found_free = false;
+
+       /*
+        * Other CPUs can use our cluster if they can't find a free cluster,
+        * check if there is still free entry in the cluster
+        */
+       tmp = cluster->next;
+       while (tmp < si->max && tmp < (cluster_next(&cluster->index) + 1) *
+              SWAPFILE_CLUSTER) {
+               if (!si->swap_map[tmp]) {
+                       found_free = true;
+                       break;
+               }
+               tmp++;
+       }
+       if (!found_free) {
+               cluster_set_null(&cluster->index);
+               goto new_cluster;
+       }
+       cluster->next = tmp + 1;
+       *offset = tmp;
+       *scan_base = tmp;
+}
 
 static unsigned long scan_swap_map(struct swap_info_struct *si,
                                   unsigned char usage)
@@ -191,7 +473,6 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
        unsigned long scan_base;
        unsigned long last_in_cluster = 0;
        int latency_ration = LATENCY_LIMIT;
-       int found_free_cluster = 0;
 
        /*
         * We try to cluster swap pages by allocating them sequentially
@@ -207,24 +488,18 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
        si->flags += SWP_SCANNING;
        scan_base = offset = si->cluster_next;
 
+       /* SSD algorithm */
+       if (si->cluster_info) {
+               scan_swap_map_try_ssd_cluster(si, &offset, &scan_base);
+               goto checks;
+       }
+
        if (unlikely(!si->cluster_nr--)) {
                if (si->pages - si->inuse_pages < SWAPFILE_CLUSTER) {
                        si->cluster_nr = SWAPFILE_CLUSTER - 1;
                        goto checks;
                }
-               if (si->flags & SWP_PAGE_DISCARD) {
-                       /*
-                        * Start range check on racing allocations, in case
-                        * they overlap the cluster we eventually decide on
-                        * (we scan without swap_lock to allow preemption).
-                        * It's hardly conceivable that cluster_nr could be
-                        * wrapped during our scan, but don't depend on it.
-                        */
-                       if (si->lowest_alloc)
-                               goto checks;
-                       si->lowest_alloc = si->max;
-                       si->highest_alloc = 0;
-               }
+
                spin_unlock(&si->lock);
 
                /*
@@ -248,7 +523,6 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
                                offset -= SWAPFILE_CLUSTER - 1;
                                si->cluster_next = offset;
                                si->cluster_nr = SWAPFILE_CLUSTER - 1;
-                               found_free_cluster = 1;
                                goto checks;
                        }
                        if (unlikely(--latency_ration < 0)) {
@@ -269,7 +543,6 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
                                offset -= SWAPFILE_CLUSTER - 1;
                                si->cluster_next = offset;
                                si->cluster_nr = SWAPFILE_CLUSTER - 1;
-                               found_free_cluster = 1;
                                goto checks;
                        }
                        if (unlikely(--latency_ration < 0)) {
@@ -281,10 +554,13 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
                offset = scan_base;
                spin_lock(&si->lock);
                si->cluster_nr = SWAPFILE_CLUSTER - 1;
-               si->lowest_alloc = 0;
        }
 
 checks:
+       if (si->cluster_info) {
+               while (scan_swap_map_ssd_cluster_conflict(si, offset))
+                       scan_swap_map_try_ssd_cluster(si, &offset, &scan_base);
+       }
        if (!(si->flags & SWP_WRITEOK))
                goto no_page;
        if (!si->highest_bit)
@@ -317,62 +593,10 @@ checks:
                si->highest_bit = 0;
        }
        si->swap_map[offset] = usage;
+       inc_cluster_info_page(si, si->cluster_info, offset);
        si->cluster_next = offset + 1;
        si->flags -= SWP_SCANNING;
 
-       if (si->lowest_alloc) {
-               /*
-                * Only set when SWP_PAGE_DISCARD, and there's a scan
-                * for a free cluster in progress or just completed.
-                */
-               if (found_free_cluster) {
-                       /*
-                        * To optimize wear-levelling, discard the
-                        * old data of the cluster, taking care not to
-                        * discard any of its pages that have already
-                        * been allocated by racing tasks (offset has
-                        * already stepped over any at the beginning).
-                        */
-                       if (offset < si->highest_alloc &&
-                           si->lowest_alloc <= last_in_cluster)
-                               last_in_cluster = si->lowest_alloc - 1;
-                       si->flags |= SWP_DISCARDING;
-                       spin_unlock(&si->lock);
-
-                       if (offset < last_in_cluster)
-                               discard_swap_cluster(si, offset,
-                                       last_in_cluster - offset + 1);
-
-                       spin_lock(&si->lock);
-                       si->lowest_alloc = 0;
-                       si->flags &= ~SWP_DISCARDING;
-
-                       smp_mb();       /* wake_up_bit advises this */
-                       wake_up_bit(&si->flags, ilog2(SWP_DISCARDING));
-
-               } else if (si->flags & SWP_DISCARDING) {
-                       /*
-                        * Delay using pages allocated by racing tasks
-                        * until the whole discard has been issued. We
-                        * could defer that delay until swap_writepage,
-                        * but it's easier to keep this self-contained.
-                        */
-                       spin_unlock(&si->lock);
-                       wait_on_bit(&si->flags, ilog2(SWP_DISCARDING),
-                               wait_for_discard, TASK_UNINTERRUPTIBLE);
-                       spin_lock(&si->lock);
-               } else {
-                       /*
-                        * Note pages allocated by racing tasks while
-                        * scan for a free cluster is in progress, so
-                        * that its final discard can exclude them.
-                        */
-                       if (offset < si->lowest_alloc)
-                               si->lowest_alloc = offset;
-                       if (offset > si->highest_alloc)
-                               si->highest_alloc = offset;
-               }
-       }
        return offset;
 
 scan:
@@ -527,16 +751,16 @@ static struct swap_info_struct *swap_info_get(swp_entry_t entry)
        return p;
 
 bad_free:
-       printk(KERN_ERR "swap_free: %s%08lx\n", Unused_offset, entry.val);
+       pr_err("swap_free: %s%08lx\n", Unused_offset, entry.val);
        goto out;
 bad_offset:
-       printk(KERN_ERR "swap_free: %s%08lx\n", Bad_offset, entry.val);
+       pr_err("swap_free: %s%08lx\n", Bad_offset, entry.val);
        goto out;
 bad_device:
-       printk(KERN_ERR "swap_free: %s%08lx\n", Unused_file, entry.val);
+       pr_err("swap_free: %s%08lx\n", Unused_file, entry.val);
        goto out;
 bad_nofile:
-       printk(KERN_ERR "swap_free: %s%08lx\n", Bad_file, entry.val);
+       pr_err("swap_free: %s%08lx\n", Bad_file, entry.val);
 out:
        return NULL;
 }
@@ -600,6 +824,7 @@ static unsigned char swap_entry_free(struct swap_info_struct *p,
 
        /* free if no reference */
        if (!usage) {
+               dec_cluster_info_page(p, p->cluster_info, offset);
                if (offset < p->lowest_bit)
                        p->lowest_bit = offset;
                if (offset > p->highest_bit)
@@ -1107,7 +1332,7 @@ static unsigned int find_next_to_unuse(struct swap_info_struct *si,
                        else
                                continue;
                }
-               count = si->swap_map[i];
+               count = ACCESS_ONCE(si->swap_map[i]);
                if (count && swap_count(count) != SWAP_MAP_BAD)
                        break;
        }
@@ -1127,7 +1352,11 @@ int try_to_unuse(unsigned int type, bool frontswap,
 {
        struct swap_info_struct *si = swap_info[type];
        struct mm_struct *start_mm;
-       unsigned char *swap_map;
+       volatile unsigned char *swap_map; /* swap_map is accessed without
+                                          * locking. Mark it as volatile
+                                          * to prevent compiler doing
+                                          * something odd.
+                                          */
        unsigned char swcount;
        struct page *page;
        swp_entry_t entry;
@@ -1178,7 +1407,15 @@ int try_to_unuse(unsigned int type, bool frontswap,
                         * reused since sys_swapoff() already disabled
                         * allocation from here, or alloc_page() failed.
                         */
-                       if (!*swap_map)
+                       swcount = *swap_map;
+                       /*
+                        * We don't hold lock here, so the swap entry could be
+                        * SWAP_MAP_BAD (when the cluster is discarding).
+                        * Instead of fail out, We can just skip the swap
+                        * entry because swapoff will wait for discarding
+                        * finish anyway.
+                        */
+                       if (!swcount || swcount == SWAP_MAP_BAD)
                                continue;
                        retval = -ENOMEM;
                        break;
@@ -1524,7 +1761,8 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
 }
 
 static void _enable_swap_info(struct swap_info_struct *p, int prio,
-                               unsigned char *swap_map)
+                               unsigned char *swap_map,
+                               struct swap_cluster_info *cluster_info)
 {
        int i, prev;
 
@@ -1533,6 +1771,7 @@ static void _enable_swap_info(struct swap_info_struct *p, int prio,
        else
                p->prio = --least_priority;
        p->swap_map = swap_map;
+       p->cluster_info = cluster_info;
        p->flags |= SWP_WRITEOK;
        atomic_long_add(p->pages, &nr_swap_pages);
        total_swap_pages += p->pages;
@@ -1553,12 +1792,13 @@ static void _enable_swap_info(struct swap_info_struct *p, int prio,
 
 static void enable_swap_info(struct swap_info_struct *p, int prio,
                                unsigned char *swap_map,
+                               struct swap_cluster_info *cluster_info,
                                unsigned long *frontswap_map)
 {
        frontswap_init(p->type, frontswap_map);
        spin_lock(&swap_lock);
        spin_lock(&p->lock);
-        _enable_swap_info(p, prio, swap_map);
+        _enable_swap_info(p, prio, swap_map, cluster_info);
        spin_unlock(&p->lock);
        spin_unlock(&swap_lock);
 }
@@ -1567,7 +1807,7 @@ static void reinsert_swap_info(struct swap_info_struct *p)
 {
        spin_lock(&swap_lock);
        spin_lock(&p->lock);
-       _enable_swap_info(p, p->prio, p->swap_map);
+       _enable_swap_info(p, p->prio, p->swap_map, p->cluster_info);
        spin_unlock(&p->lock);
        spin_unlock(&swap_lock);
 }
@@ -1576,6 +1816,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
 {
        struct swap_info_struct *p = NULL;
        unsigned char *swap_map;
+       struct swap_cluster_info *cluster_info;
        unsigned long *frontswap_map;
        struct file *swap_file, *victim;
        struct address_space *mapping;
@@ -1651,6 +1892,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
                goto out_dput;
        }
 
+       flush_work(&p->discard_work);
+
        destroy_swap_extents(p);
        if (p->flags & SWP_CONTINUED)
                free_swap_count_continuations(p);
@@ -1675,6 +1918,8 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        p->max = 0;
        swap_map = p->swap_map;
        p->swap_map = NULL;
+       cluster_info = p->cluster_info;
+       p->cluster_info = NULL;
        p->flags = 0;
        frontswap_map = frontswap_map_get(p);
        frontswap_map_set(p, NULL);
@@ -1682,7 +1927,10 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
        spin_unlock(&swap_lock);
        frontswap_invalidate_area(type);
        mutex_unlock(&swapon_mutex);
+       free_percpu(p->percpu_cluster);
+       p->percpu_cluster = NULL;
        vfree(swap_map);
+       vfree(cluster_info);
        vfree(frontswap_map);
        /* Destroy swap account informatin */
        swap_cgroup_swapoff(type);
@@ -1926,9 +2174,10 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
        int i;
        unsigned long maxpages;
        unsigned long swapfilepages;
+       unsigned long last_page;
 
        if (memcmp("SWAPSPACE2", swap_header->magic.magic, 10)) {
-               printk(KERN_ERR "Unable to find swap-space signature\n");
+               pr_err("Unable to find swap-space signature\n");
                return 0;
        }
 
@@ -1942,9 +2191,8 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
        }
        /* Check the swap header's sub-version */
        if (swap_header->info.version != 1) {
-               printk(KERN_WARNING
-                      "Unable to handle swap header version %d\n",
-                      swap_header->info.version);
+               pr_warn("Unable to handle swap header version %d\n",
+                       swap_header->info.version);
                return 0;
        }
 
@@ -1968,8 +2216,14 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
         */
        maxpages = swp_offset(pte_to_swp_entry(
                        swp_entry_to_pte(swp_entry(0, ~0UL)))) + 1;
-       if (maxpages > swap_header->info.last_page) {
-               maxpages = swap_header->info.last_page + 1;
+       last_page = swap_header->info.last_page;
+       if (last_page > maxpages) {
+               pr_warn("Truncating oversized swap area, only using %luk out of %luk\n",
+                       maxpages << (PAGE_SHIFT - 10),
+                       last_page << (PAGE_SHIFT - 10));
+       }
+       if (maxpages > last_page) {
+               maxpages = last_page + 1;
                /* p->max is an unsigned int: don't overflow it */
                if ((unsigned int)maxpages == 0)
                        maxpages = UINT_MAX;
@@ -1980,8 +2234,7 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
                return 0;
        swapfilepages = i_size_read(inode) >> PAGE_SHIFT;
        if (swapfilepages && maxpages > swapfilepages) {
-               printk(KERN_WARNING
-                      "Swap area shorter than signature indicates\n");
+               pr_warn("Swap area shorter than signature indicates\n");
                return 0;
        }
        if (swap_header->info.nr_badpages && S_ISREG(inode->i_mode))
@@ -1995,15 +2248,23 @@ static unsigned long read_swap_header(struct swap_info_struct *p,
 static int setup_swap_map_and_extents(struct swap_info_struct *p,
                                        union swap_header *swap_header,
                                        unsigned char *swap_map,
+                                       struct swap_cluster_info *cluster_info,
                                        unsigned long maxpages,
                                        sector_t *span)
 {
        int i;
        unsigned int nr_good_pages;
        int nr_extents;
+       unsigned long nr_clusters = DIV_ROUND_UP(maxpages, SWAPFILE_CLUSTER);
+       unsigned long idx = p->cluster_next / SWAPFILE_CLUSTER;
 
        nr_good_pages = maxpages - 1;   /* omit header page */
 
+       cluster_set_null(&p->free_cluster_head);
+       cluster_set_null(&p->free_cluster_tail);
+       cluster_set_null(&p->discard_cluster_head);
+       cluster_set_null(&p->discard_cluster_tail);
+
        for (i = 0; i < swap_header->info.nr_badpages; i++) {
                unsigned int page_nr = swap_header->info.badpages[i];
                if (page_nr == 0 || page_nr > swap_header->info.last_page)
@@ -2011,11 +2272,25 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
                if (page_nr < maxpages) {
                        swap_map[page_nr] = SWAP_MAP_BAD;
                        nr_good_pages--;
+                       /*
+                        * Haven't marked the cluster free yet, no list
+                        * operation involved
+                        */
+                       inc_cluster_info_page(p, cluster_info, page_nr);
                }
        }
 
+       /* Haven't marked the cluster free yet, no list operation involved */
+       for (i = maxpages; i < round_up(maxpages, SWAPFILE_CLUSTER); i++)
+               inc_cluster_info_page(p, cluster_info, i);
+
        if (nr_good_pages) {
                swap_map[0] = SWAP_MAP_BAD;
+               /*
+                * Not mark the cluster free yet, no list
+                * operation involved
+                */
+               inc_cluster_info_page(p, cluster_info, 0);
                p->max = maxpages;
                p->pages = nr_good_pages;
                nr_extents = setup_swap_extents(p, span);
@@ -2024,10 +2299,34 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
                nr_good_pages = p->pages;
        }
        if (!nr_good_pages) {
-               printk(KERN_WARNING "Empty swap-file\n");
+               pr_warn("Empty swap-file\n");
                return -EINVAL;
        }
 
+       if (!cluster_info)
+               return nr_extents;
+
+       for (i = 0; i < nr_clusters; i++) {
+               if (!cluster_count(&cluster_info[idx])) {
+                       cluster_set_flag(&cluster_info[idx], CLUSTER_FLAG_FREE);
+                       if (cluster_is_null(&p->free_cluster_head)) {
+                               cluster_set_next_flag(&p->free_cluster_head,
+                                                               idx, 0);
+                               cluster_set_next_flag(&p->free_cluster_tail,
+                                                               idx, 0);
+                       } else {
+                               unsigned int tail;
+
+                               tail = cluster_next(&p->free_cluster_tail);
+                               cluster_set_next(&cluster_info[tail], idx);
+                               cluster_set_next_flag(&p->free_cluster_tail,
+                                                               idx, 0);
+                       }
+               }
+               idx++;
+               if (idx == nr_clusters)
+                       idx = 0;
+       }
        return nr_extents;
 }
 
@@ -2059,6 +2358,7 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        sector_t span;
        unsigned long maxpages;
        unsigned char *swap_map = NULL;
+       struct swap_cluster_info *cluster_info = NULL;
        unsigned long *frontswap_map = NULL;
        struct page *page = NULL;
        struct inode *inode = NULL;
@@ -2073,6 +2373,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        if (IS_ERR(p))
                return PTR_ERR(p);
 
+       INIT_WORK(&p->discard_work, swap_discard_work);
+
        name = getname(specialfile);
        if (IS_ERR(name)) {
                error = PTR_ERR(name);
@@ -2132,13 +2434,38 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
                error = -ENOMEM;
                goto bad_swap;
        }
+       if (p->bdev && blk_queue_nonrot(bdev_get_queue(p->bdev))) {
+               p->flags |= SWP_SOLIDSTATE;
+               /*
+                * select a random position to start with to help wear leveling
+                * SSD
+                */
+               p->cluster_next = 1 + (prandom_u32() % p->highest_bit);
+
+               cluster_info = vzalloc(DIV_ROUND_UP(maxpages,
+                       SWAPFILE_CLUSTER) * sizeof(*cluster_info));
+               if (!cluster_info) {
+                       error = -ENOMEM;
+                       goto bad_swap;
+               }
+               p->percpu_cluster = alloc_percpu(struct percpu_cluster);
+               if (!p->percpu_cluster) {
+                       error = -ENOMEM;
+                       goto bad_swap;
+               }
+               for_each_possible_cpu(i) {
+                       struct percpu_cluster *cluster;
+                       cluster = per_cpu_ptr(p->percpu_cluster, i);
+                       cluster_set_null(&cluster->index);
+               }
+       }
 
        error = swap_cgroup_swapon(p->type, maxpages);
        if (error)
                goto bad_swap;
 
        nr_extents = setup_swap_map_and_extents(p, swap_header, swap_map,
-               maxpages, &span);
+               cluster_info, maxpages, &span);
        if (unlikely(nr_extents < 0)) {
                error = nr_extents;
                goto bad_swap;
@@ -2147,41 +2474,33 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        if (frontswap_enabled)
                frontswap_map = vzalloc(BITS_TO_LONGS(maxpages) * sizeof(long));
 
-       if (p->bdev) {
-               if (blk_queue_nonrot(bdev_get_queue(p->bdev))) {
-                       p->flags |= SWP_SOLIDSTATE;
-                       p->cluster_next = 1 + (prandom_u32() % p->highest_bit);
-               }
-
-               if ((swap_flags & SWAP_FLAG_DISCARD) && swap_discardable(p)) {
-                       /*
-                        * When discard is enabled for swap with no particular
-                        * policy flagged, we set all swap discard flags here in
-                        * order to sustain backward compatibility with older
-                        * swapon(8) releases.
-                        */
-                       p->flags |= (SWP_DISCARDABLE | SWP_AREA_DISCARD |
-                                    SWP_PAGE_DISCARD);
+       if (p->bdev &&(swap_flags & SWAP_FLAG_DISCARD) && swap_discardable(p)) {
+               /*
+                * When discard is enabled for swap with no particular
+                * policy flagged, we set all swap discard flags here in
+                * order to sustain backward compatibility with older
+                * swapon(8) releases.
+                */
+               p->flags |= (SWP_DISCARDABLE | SWP_AREA_DISCARD |
+                            SWP_PAGE_DISCARD);
 
-                       /*
-                        * By flagging sys_swapon, a sysadmin can tell us to
-                        * either do single-time area discards only, or to just
-                        * perform discards for released swap page-clusters.
-                        * Now it's time to adjust the p->flags accordingly.
-                        */
-                       if (swap_flags & SWAP_FLAG_DISCARD_ONCE)
-                               p->flags &= ~SWP_PAGE_DISCARD;
-                       else if (swap_flags & SWAP_FLAG_DISCARD_PAGES)
-                               p->flags &= ~SWP_AREA_DISCARD;
-
-                       /* issue a swapon-time discard if it's still required */
-                       if (p->flags & SWP_AREA_DISCARD) {
-                               int err = discard_swap(p);
-                               if (unlikely(err))
-                                       printk(KERN_ERR
-                                              "swapon: discard_swap(%p): %d\n",
-                                               p, err);
-                       }
+               /*
+                * By flagging sys_swapon, a sysadmin can tell us to
+                * either do single-time area discards only, or to just
+                * perform discards for released swap page-clusters.
+                * Now it's time to adjust the p->flags accordingly.
+                */
+               if (swap_flags & SWAP_FLAG_DISCARD_ONCE)
+                       p->flags &= ~SWP_PAGE_DISCARD;
+               else if (swap_flags & SWAP_FLAG_DISCARD_PAGES)
+                       p->flags &= ~SWP_AREA_DISCARD;
+
+               /* issue a swapon-time discard if it's still required */
+               if (p->flags & SWP_AREA_DISCARD) {
+                       int err = discard_swap(p);
+                       if (unlikely(err))
+                               pr_err("swapon: discard_swap(%p): %d\n",
+                                       p, err);
                }
        }
 
@@ -2190,9 +2509,9 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        if (swap_flags & SWAP_FLAG_PREFER)
                prio =
                  (swap_flags & SWAP_FLAG_PRIO_MASK) >> SWAP_FLAG_PRIO_SHIFT;
-       enable_swap_info(p, prio, swap_map, frontswap_map);
+       enable_swap_info(p, prio, swap_map, cluster_info, frontswap_map);
 
-       printk(KERN_INFO "Adding %uk swap on %s.  "
+       pr_info("Adding %uk swap on %s.  "
                        "Priority:%d extents:%d across:%lluk %s%s%s%s%s\n",
                p->pages<<(PAGE_SHIFT-10), name->name, p->prio,
                nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
@@ -2211,6 +2530,8 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
        error = 0;
        goto out;
 bad_swap:
+       free_percpu(p->percpu_cluster);
+       p->percpu_cluster = NULL;
        if (inode && S_ISBLK(inode->i_mode) && p->bdev) {
                set_blocksize(p->bdev, p->old_block_size);
                blkdev_put(p->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL);
@@ -2222,6 +2543,7 @@ bad_swap:
        p->flags = 0;
        spin_unlock(&swap_lock);
        vfree(swap_map);
+       vfree(cluster_info);
        if (swap_file) {
                if (inode && S_ISREG(inode->i_mode)) {
                        mutex_unlock(&inode->i_mutex);
@@ -2291,6 +2613,16 @@ static int __swap_duplicate(swp_entry_t entry, unsigned char usage)
                goto unlock_out;
 
        count = p->swap_map[offset];
+
+       /*
+        * swapin_readahead() doesn't check if a swap entry is valid, so the
+        * swap entry could be SWAP_MAP_BAD. Check here with lock held.
+        */
+       if (unlikely(swap_count(count) == SWAP_MAP_BAD)) {
+               err = -ENOENT;
+               goto unlock_out;
+       }
+
        has_cache = count & SWAP_HAS_CACHE;
        count &= ~SWAP_HAS_CACHE;
        err = 0;
@@ -2326,7 +2658,7 @@ out:
        return err;
 
 bad_file:
-       printk(KERN_ERR "swap_dup: %s%08lx\n", Bad_file, entry.val);
+       pr_err("swap_dup: %s%08lx\n", Bad_file, entry.val);
        goto out;
 }
 
index e2e8a8a7eb9d8facfd7581998641e72f81b4c02d..353b683afd6ef538ab3318f5c40ad6502789227e 100644 (file)
@@ -567,7 +567,6 @@ EXPORT_SYMBOL_GPL(invalidate_inode_pages2);
 /**
  * truncate_pagecache - unmap and remove pagecache that has been truncated
  * @inode: inode
- * @oldsize: old file size
  * @newsize: new file size
  *
  * inode's new i_size must already be written before truncate_pagecache
@@ -580,7 +579,7 @@ EXPORT_SYMBOL_GPL(invalidate_inode_pages2);
  * situations such as writepage being called for a page that has already
  * had its underlying blocks deallocated.
  */
-void truncate_pagecache(struct inode *inode, loff_t oldsize, loff_t newsize)
+void truncate_pagecache(struct inode *inode, loff_t newsize)
 {
        struct address_space *mapping = inode->i_mapping;
        loff_t holebegin = round_up(newsize, PAGE_SIZE);
@@ -614,12 +613,8 @@ EXPORT_SYMBOL(truncate_pagecache);
  */
 void truncate_setsize(struct inode *inode, loff_t newsize)
 {
-       loff_t oldsize;
-
-       oldsize = inode->i_size;
        i_size_write(inode, newsize);
-
-       truncate_pagecache(inode, oldsize, newsize);
+       truncate_pagecache(inode, newsize);
 }
 EXPORT_SYMBOL(truncate_setsize);
 
index 7441c41d00f64df8b2f2439d3bce661cc12c1966..eaf63fc2c92f05078f0c93694ea03b55d425eecb 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -388,15 +388,12 @@ struct address_space *page_mapping(struct page *page)
        struct address_space *mapping = page->mapping;
 
        VM_BUG_ON(PageSlab(page));
-#ifdef CONFIG_SWAP
        if (unlikely(PageSwapCache(page))) {
                swp_entry_t entry;
 
                entry.val = page_private(page);
                mapping = swap_address_space(entry);
-       } else
-#endif
-       if ((unsigned long)mapping & PAGE_MAPPING_ANON)
+       } else if ((unsigned long)mapping & PAGE_MAPPING_ANON)
                mapping = NULL;
        return mapping;
 }
index 13a54953a273a715f1f4466ff5eeb1ba119f179c..107454312d5ef859ec8dc55f3ba13831cc5cbc65 100644 (file)
@@ -752,7 +752,6 @@ struct vmap_block_queue {
 struct vmap_block {
        spinlock_t lock;
        struct vmap_area *va;
-       struct vmap_block_queue *vbq;
        unsigned long free, dirty;
        DECLARE_BITMAP(dirty_map, VMAP_BBMAP_BITS);
        struct list_head free_list;
@@ -830,7 +829,6 @@ static struct vmap_block *new_vmap_block(gfp_t gfp_mask)
        radix_tree_preload_end();
 
        vbq = &get_cpu_var(vmap_block_queue);
-       vb->vbq = vbq;
        spin_lock(&vbq->lock);
        list_add_rcu(&vb->free_list, &vbq->free);
        spin_unlock(&vbq->lock);
@@ -1018,15 +1016,16 @@ void vm_unmap_aliases(void)
 
                rcu_read_lock();
                list_for_each_entry_rcu(vb, &vbq->free, free_list) {
-                       int i;
+                       int i, j;
 
                        spin_lock(&vb->lock);
                        i = find_first_bit(vb->dirty_map, VMAP_BBMAP_BITS);
-                       while (i < VMAP_BBMAP_BITS) {
+                       if (i < VMAP_BBMAP_BITS) {
                                unsigned long s, e;
-                               int j;
-                               j = find_next_zero_bit(vb->dirty_map,
-                                       VMAP_BBMAP_BITS, i);
+
+                               j = find_last_bit(vb->dirty_map,
+                                                       VMAP_BBMAP_BITS);
+                               j = j + 1; /* need exclusive index */
 
                                s = vb->va->va_start + (i << PAGE_SHIFT);
                                e = vb->va->va_start + (j << PAGE_SHIFT);
@@ -1036,10 +1035,6 @@ void vm_unmap_aliases(void)
                                        start = s;
                                if (e > end)
                                        end = e;
-
-                               i = j;
-                               i = find_next_bit(vb->dirty_map,
-                                                       VMAP_BBMAP_BITS, i);
                        }
                        spin_unlock(&vb->lock);
                }
@@ -1263,7 +1258,7 @@ void unmap_kernel_range(unsigned long addr, unsigned long size)
 int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page ***pages)
 {
        unsigned long addr = (unsigned long)area->addr;
-       unsigned long end = addr + area->size - PAGE_SIZE;
+       unsigned long end = addr + get_vm_area_size(area);
        int err;
 
        err = vmap_page_range(addr, end, prot, *pages);
@@ -1558,7 +1553,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
        unsigned int nr_pages, array_size, i;
        gfp_t nested_gfp = (gfp_mask & GFP_RECLAIM_MASK) | __GFP_ZERO;
 
-       nr_pages = (area->size - PAGE_SIZE) >> PAGE_SHIFT;
+       nr_pages = get_vm_area_size(area) >> PAGE_SHIFT;
        array_size = (nr_pages * sizeof(struct page *));
 
        area->nr_pages = nr_pages;
@@ -1990,7 +1985,7 @@ long vread(char *buf, char *addr, unsigned long count)
 
                vm = va->vm;
                vaddr = (char *) vm->addr;
-               if (addr >= vaddr + vm->size - PAGE_SIZE)
+               if (addr >= vaddr + get_vm_area_size(vm))
                        continue;
                while (addr < vaddr) {
                        if (count == 0)
@@ -2000,7 +1995,7 @@ long vread(char *buf, char *addr, unsigned long count)
                        addr++;
                        count--;
                }
-               n = vaddr + vm->size - PAGE_SIZE - addr;
+               n = vaddr + get_vm_area_size(vm) - addr;
                if (n > count)
                        n = count;
                if (!(vm->flags & VM_IOREMAP))
@@ -2072,7 +2067,7 @@ long vwrite(char *buf, char *addr, unsigned long count)
 
                vm = va->vm;
                vaddr = (char *) vm->addr;
-               if (addr >= vaddr + vm->size - PAGE_SIZE)
+               if (addr >= vaddr + get_vm_area_size(vm))
                        continue;
                while (addr < vaddr) {
                        if (count == 0)
@@ -2081,7 +2076,7 @@ long vwrite(char *buf, char *addr, unsigned long count)
                        addr++;
                        count--;
                }
-               n = vaddr + vm->size - PAGE_SIZE - addr;
+               n = vaddr + get_vm_area_size(vm) - addr;
                if (n > count)
                        n = count;
                if (!(vm->flags & VM_IOREMAP)) {
index 2cff0d491c6dca84391edd100e1726696c1475d5..8ed1b775bdc9cafe9aaf2ab74e4acf842ffe1a9d 100644 (file)
@@ -139,13 +139,44 @@ static bool global_reclaim(struct scan_control *sc)
 {
        return !sc->target_mem_cgroup;
 }
+
+static bool mem_cgroup_should_soft_reclaim(struct scan_control *sc)
+{
+       struct mem_cgroup *root = sc->target_mem_cgroup;
+       return !mem_cgroup_disabled() &&
+               mem_cgroup_soft_reclaim_eligible(root, root) != SKIP_TREE;
+}
 #else
 static bool global_reclaim(struct scan_control *sc)
 {
        return true;
 }
+
+static bool mem_cgroup_should_soft_reclaim(struct scan_control *sc)
+{
+       return false;
+}
 #endif
 
+unsigned long zone_reclaimable_pages(struct zone *zone)
+{
+       int nr;
+
+       nr = zone_page_state(zone, NR_ACTIVE_FILE) +
+            zone_page_state(zone, NR_INACTIVE_FILE);
+
+       if (get_nr_swap_pages() > 0)
+               nr += zone_page_state(zone, NR_ACTIVE_ANON) +
+                     zone_page_state(zone, NR_INACTIVE_ANON);
+
+       return nr;
+}
+
+bool zone_reclaimable(struct zone *zone)
+{
+       return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
+}
+
 static unsigned long get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 {
        if (!mem_cgroup_disabled())
@@ -155,14 +186,31 @@ static unsigned long get_lru_size(struct lruvec *lruvec, enum lru_list lru)
 }
 
 /*
- * Add a shrinker callback to be called from the vm
+ * Add a shrinker callback to be called from the vm.
  */
-void register_shrinker(struct shrinker *shrinker)
+int register_shrinker(struct shrinker *shrinker)
 {
-       atomic_long_set(&shrinker->nr_in_batch, 0);
+       size_t size = sizeof(*shrinker->nr_deferred);
+
+       /*
+        * If we only have one possible node in the system anyway, save
+        * ourselves the trouble and disable NUMA aware behavior. This way we
+        * will save memory and some small loop time later.
+        */
+       if (nr_node_ids == 1)
+               shrinker->flags &= ~SHRINKER_NUMA_AWARE;
+
+       if (shrinker->flags & SHRINKER_NUMA_AWARE)
+               size *= nr_node_ids;
+
+       shrinker->nr_deferred = kzalloc(size, GFP_KERNEL);
+       if (!shrinker->nr_deferred)
+               return -ENOMEM;
+
        down_write(&shrinker_rwsem);
        list_add_tail(&shrinker->list, &shrinker_list);
        up_write(&shrinker_rwsem);
+       return 0;
 }
 EXPORT_SYMBOL(register_shrinker);
 
@@ -177,15 +225,102 @@ void unregister_shrinker(struct shrinker *shrinker)
 }
 EXPORT_SYMBOL(unregister_shrinker);
 
-static inline int do_shrinker_shrink(struct shrinker *shrinker,
-                                    struct shrink_control *sc,
-                                    unsigned long nr_to_scan)
-{
-       sc->nr_to_scan = nr_to_scan;
-       return (*shrinker->shrink)(shrinker, sc);
+#define SHRINK_BATCH 128
+
+static unsigned long
+shrink_slab_node(struct shrink_control *shrinkctl, struct shrinker *shrinker,
+                unsigned long nr_pages_scanned, unsigned long lru_pages)
+{
+       unsigned long freed = 0;
+       unsigned long long delta;
+       long total_scan;
+       long max_pass;
+       long nr;
+       long new_nr;
+       int nid = shrinkctl->nid;
+       long batch_size = shrinker->batch ? shrinker->batch
+                                         : SHRINK_BATCH;
+
+       max_pass = shrinker->count_objects(shrinker, shrinkctl);
+       if (max_pass == 0)
+               return 0;
+
+       /*
+        * copy the current shrinker scan count into a local variable
+        * and zero it so that other concurrent shrinker invocations
+        * don't also do this scanning work.
+        */
+       nr = atomic_long_xchg(&shrinker->nr_deferred[nid], 0);
+
+       total_scan = nr;
+       delta = (4 * nr_pages_scanned) / shrinker->seeks;
+       delta *= max_pass;
+       do_div(delta, lru_pages + 1);
+       total_scan += delta;
+       if (total_scan < 0) {
+               printk(KERN_ERR
+               "shrink_slab: %pF negative objects to delete nr=%ld\n",
+                      shrinker->scan_objects, total_scan);
+               total_scan = max_pass;
+       }
+
+       /*
+        * We need to avoid excessive windup on filesystem shrinkers
+        * due to large numbers of GFP_NOFS allocations causing the
+        * shrinkers to return -1 all the time. This results in a large
+        * nr being built up so when a shrink that can do some work
+        * comes along it empties the entire cache due to nr >>>
+        * max_pass.  This is bad for sustaining a working set in
+        * memory.
+        *
+        * Hence only allow the shrinker to scan the entire cache when
+        * a large delta change is calculated directly.
+        */
+       if (delta < max_pass / 4)
+               total_scan = min(total_scan, max_pass / 2);
+
+       /*
+        * Avoid risking looping forever due to too large nr value:
+        * never try to free more than twice the estimate number of
+        * freeable entries.
+        */
+       if (total_scan > max_pass * 2)
+               total_scan = max_pass * 2;
+
+       trace_mm_shrink_slab_start(shrinker, shrinkctl, nr,
+                               nr_pages_scanned, lru_pages,
+                               max_pass, delta, total_scan);
+
+       while (total_scan >= batch_size) {
+               unsigned long ret;
+
+               shrinkctl->nr_to_scan = batch_size;
+               ret = shrinker->scan_objects(shrinker, shrinkctl);
+               if (ret == SHRINK_STOP)
+                       break;
+               freed += ret;
+
+               count_vm_events(SLABS_SCANNED, batch_size);
+               total_scan -= batch_size;
+
+               cond_resched();
+       }
+
+       /*
+        * move the unused scan count back into the shrinker in a
+        * manner that handles concurrent updates. If we exhausted the
+        * scan, there is no need to do an update.
+        */
+       if (total_scan > 0)
+               new_nr = atomic_long_add_return(total_scan,
+                                               &shrinker->nr_deferred[nid]);
+       else
+               new_nr = atomic_long_read(&shrinker->nr_deferred[nid]);
+
+       trace_mm_shrink_slab_end(shrinker, freed, nr, new_nr);
+       return freed;
 }
 
-#define SHRINK_BATCH 128
 /*
  * Call the shrink functions to age shrinkable caches
  *
@@ -205,115 +340,45 @@ static inline int do_shrinker_shrink(struct shrinker *shrinker,
  *
  * Returns the number of slab objects which we shrunk.
  */
-unsigned long shrink_slab(struct shrink_control *shrink,
+unsigned long shrink_slab(struct shrink_control *shrinkctl,
                          unsigned long nr_pages_scanned,
                          unsigned long lru_pages)
 {
        struct shrinker *shrinker;
-       unsigned long ret = 0;
+       unsigned long freed = 0;
 
        if (nr_pages_scanned == 0)
                nr_pages_scanned = SWAP_CLUSTER_MAX;
 
        if (!down_read_trylock(&shrinker_rwsem)) {
-               /* Assume we'll be able to shrink next time */
-               ret = 1;
+               /*
+                * If we would return 0, our callers would understand that we
+                * have nothing else to shrink and give up trying. By returning
+                * 1 we keep it going and assume we'll be able to shrink next
+                * time.
+                */
+               freed = 1;
                goto out;
        }
 
        list_for_each_entry(shrinker, &shrinker_list, list) {
-               unsigned long long delta;
-               long total_scan;
-               long max_pass;
-               int shrink_ret = 0;
-               long nr;
-               long new_nr;
-               long batch_size = shrinker->batch ? shrinker->batch
-                                                 : SHRINK_BATCH;
-
-               max_pass = do_shrinker_shrink(shrinker, shrink, 0);
-               if (max_pass <= 0)
-                       continue;
-
-               /*
-                * copy the current shrinker scan count into a local variable
-                * and zero it so that other concurrent shrinker invocations
-                * don't also do this scanning work.
-                */
-               nr = atomic_long_xchg(&shrinker->nr_in_batch, 0);
-
-               total_scan = nr;
-               delta = (4 * nr_pages_scanned) / shrinker->seeks;
-               delta *= max_pass;
-               do_div(delta, lru_pages + 1);
-               total_scan += delta;
-               if (total_scan < 0) {
-                       printk(KERN_ERR "shrink_slab: %pF negative objects to "
-                              "delete nr=%ld\n",
-                              shrinker->shrink, total_scan);
-                       total_scan = max_pass;
-               }
-
-               /*
-                * We need to avoid excessive windup on filesystem shrinkers
-                * due to large numbers of GFP_NOFS allocations causing the
-                * shrinkers to return -1 all the time. This results in a large
-                * nr being built up so when a shrink that can do some work
-                * comes along it empties the entire cache due to nr >>>
-                * max_pass.  This is bad for sustaining a working set in
-                * memory.
-                *
-                * Hence only allow the shrinker to scan the entire cache when
-                * a large delta change is calculated directly.
-                */
-               if (delta < max_pass / 4)
-                       total_scan = min(total_scan, max_pass / 2);
-
-               /*
-                * Avoid risking looping forever due to too large nr value:
-                * never try to free more than twice the estimate number of
-                * freeable entries.
-                */
-               if (total_scan > max_pass * 2)
-                       total_scan = max_pass * 2;
-
-               trace_mm_shrink_slab_start(shrinker, shrink, nr,
-                                       nr_pages_scanned, lru_pages,
-                                       max_pass, delta, total_scan);
-
-               while (total_scan >= batch_size) {
-                       int nr_before;
+               for_each_node_mask(shrinkctl->nid, shrinkctl->nodes_to_scan) {
+                       if (!node_online(shrinkctl->nid))
+                               continue;
 
-                       nr_before = do_shrinker_shrink(shrinker, shrink, 0);
-                       shrink_ret = do_shrinker_shrink(shrinker, shrink,
-                                                       batch_size);
-                       if (shrink_ret == -1)
+                       if (!(shrinker->flags & SHRINKER_NUMA_AWARE) &&
+                           (shrinkctl->nid != 0))
                                break;
-                       if (shrink_ret < nr_before)
-                               ret += nr_before - shrink_ret;
-                       count_vm_events(SLABS_SCANNED, batch_size);
-                       total_scan -= batch_size;
-
-                       cond_resched();
-               }
 
-               /*
-                * move the unused scan count back into the shrinker in a
-                * manner that handles concurrent updates. If we exhausted the
-                * scan, there is no need to do an update.
-                */
-               if (total_scan > 0)
-                       new_nr = atomic_long_add_return(total_scan,
-                                       &shrinker->nr_in_batch);
-               else
-                       new_nr = atomic_long_read(&shrinker->nr_in_batch);
+                       freed += shrink_slab_node(shrinkctl, shrinker,
+                                nr_pages_scanned, lru_pages);
 
-               trace_mm_shrink_slab_end(shrinker, shrink_ret, nr, new_nr);
+               }
        }
        up_read(&shrinker_rwsem);
 out:
        cond_resched();
-       return ret;
+       return freed;
 }
 
 static inline int is_page_cache_freeable(struct page *page)
@@ -545,7 +610,7 @@ int remove_mapping(struct address_space *mapping, struct page *page)
  */
 void putback_lru_page(struct page *page)
 {
-       int lru;
+       bool is_unevictable;
        int was_unevictable = PageUnevictable(page);
 
        VM_BUG_ON(PageLRU(page));
@@ -560,14 +625,14 @@ redo:
                 * unevictable page on [in]active list.
                 * We know how to handle that.
                 */
-               lru = page_lru_base_type(page);
+               is_unevictable = false;
                lru_cache_add(page);
        } else {
                /*
                 * Put unevictable pages directly on zone's unevictable
                 * list.
                 */
-               lru = LRU_UNEVICTABLE;
+               is_unevictable = true;
                add_page_to_unevictable_list(page);
                /*
                 * When racing with an mlock or AS_UNEVICTABLE clearing
@@ -587,7 +652,7 @@ redo:
         * page is on unevictable list, it never be freed. To avoid that,
         * check after we added it to the list, again.
         */
-       if (lru == LRU_UNEVICTABLE && page_evictable(page)) {
+       if (is_unevictable && page_evictable(page)) {
                if (!isolate_lru_page(page)) {
                        put_page(page);
                        goto redo;
@@ -598,9 +663,9 @@ redo:
                 */
        }
 
-       if (was_unevictable && lru != LRU_UNEVICTABLE)
+       if (was_unevictable && !is_unevictable)
                count_vm_event(UNEVICTABLE_PGRESCUED);
-       else if (!was_unevictable && lru == LRU_UNEVICTABLE)
+       else if (!was_unevictable && is_unevictable)
                count_vm_event(UNEVICTABLE_PGCULLED);
 
        put_page(page);         /* drop ref from isolate */
@@ -1789,7 +1854,7 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc,
         * latencies, so it's better to scan a minimum amount there as
         * well.
         */
-       if (current_is_kswapd() && zone->all_unreclaimable)
+       if (current_is_kswapd() && !zone_reclaimable(zone))
                force_scan = true;
        if (!global_reclaim(sc))
                force_scan = true;
@@ -2111,9 +2176,11 @@ static inline bool should_continue_reclaim(struct zone *zone,
        }
 }
 
-static void shrink_zone(struct zone *zone, struct scan_control *sc)
+static int
+__shrink_zone(struct zone *zone, struct scan_control *sc, bool soft_reclaim)
 {
        unsigned long nr_reclaimed, nr_scanned;
+       int groups_scanned = 0;
 
        do {
                struct mem_cgroup *root = sc->target_mem_cgroup;
@@ -2121,15 +2188,17 @@ static void shrink_zone(struct zone *zone, struct scan_control *sc)
                        .zone = zone,
                        .priority = sc->priority,
                };
-               struct mem_cgroup *memcg;
+               struct mem_cgroup *memcg = NULL;
+               mem_cgroup_iter_filter filter = (soft_reclaim) ?
+                       mem_cgroup_soft_reclaim_eligible : NULL;
 
                nr_reclaimed = sc->nr_reclaimed;
                nr_scanned = sc->nr_scanned;
 
-               memcg = mem_cgroup_iter(root, NULL, &reclaim);
-               do {
+               while ((memcg = mem_cgroup_iter_cond(root, memcg, &reclaim, filter))) {
                        struct lruvec *lruvec;
 
+                       groups_scanned++;
                        lruvec = mem_cgroup_zone_lruvec(zone, memcg);
 
                        shrink_lruvec(lruvec, sc);
@@ -2149,8 +2218,7 @@ static void shrink_zone(struct zone *zone, struct scan_control *sc)
                                mem_cgroup_iter_break(root, memcg);
                                break;
                        }
-                       memcg = mem_cgroup_iter(root, memcg, &reclaim);
-               } while (memcg);
+               }
 
                vmpressure(sc->gfp_mask, sc->target_mem_cgroup,
                           sc->nr_scanned - nr_scanned,
@@ -2158,6 +2226,37 @@ static void shrink_zone(struct zone *zone, struct scan_control *sc)
 
        } while (should_continue_reclaim(zone, sc->nr_reclaimed - nr_reclaimed,
                                         sc->nr_scanned - nr_scanned, sc));
+
+       return groups_scanned;
+}
+
+
+static void shrink_zone(struct zone *zone, struct scan_control *sc)
+{
+       bool do_soft_reclaim = mem_cgroup_should_soft_reclaim(sc);
+       unsigned long nr_scanned = sc->nr_scanned;
+       int scanned_groups;
+
+       scanned_groups = __shrink_zone(zone, sc, do_soft_reclaim);
+       /*
+        * memcg iterator might race with other reclaimer or start from
+        * a incomplete tree walk so the tree walk in __shrink_zone
+        * might have missed groups that are above the soft limit. Try
+        * another loop to catch up with others. Do it just once to
+        * prevent from reclaim latencies when other reclaimers always
+        * preempt this one.
+        */
+       if (do_soft_reclaim && !scanned_groups)
+               __shrink_zone(zone, sc, do_soft_reclaim);
+
+       /*
+        * No group is over the soft limit or those that are do not have
+        * pages in the zone we are reclaiming so we have to reclaim everybody
+        */
+       if (do_soft_reclaim && (sc->nr_scanned == nr_scanned)) {
+               __shrink_zone(zone, sc, false);
+               return;
+       }
 }
 
 /* Returns true if compaction should go ahead for a high-order request */
@@ -2221,8 +2320,6 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
 {
        struct zoneref *z;
        struct zone *zone;
-       unsigned long nr_soft_reclaimed;
-       unsigned long nr_soft_scanned;
        bool aborted_reclaim = false;
 
        /*
@@ -2244,8 +2341,8 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                if (global_reclaim(sc)) {
                        if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                                continue;
-                       if (zone->all_unreclaimable &&
-                                       sc->priority != DEF_PRIORITY)
+                       if (sc->priority != DEF_PRIORITY &&
+                           !zone_reclaimable(zone))
                                continue;       /* Let kswapd poll it */
                        if (IS_ENABLED(CONFIG_COMPACTION)) {
                                /*
@@ -2262,18 +2359,6 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                                        continue;
                                }
                        }
-                       /*
-                        * This steals pages from memory cgroups over softlimit
-                        * and returns the number of reclaimed pages and
-                        * scanned pages. This works for global memory pressure
-                        * and balancing, not for a memcg's limit.
-                        */
-                       nr_soft_scanned = 0;
-                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
-                                               sc->order, sc->gfp_mask,
-                                               &nr_soft_scanned);
-                       sc->nr_reclaimed += nr_soft_reclaimed;
-                       sc->nr_scanned += nr_soft_scanned;
                        /* need some check for avoid more shrink_zone() */
                }
 
@@ -2283,11 +2368,6 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        return aborted_reclaim;
 }
 
-static bool zone_reclaimable(struct zone *zone)
-{
-       return zone->pages_scanned < zone_reclaimable_pages(zone) * 6;
-}
-
 /* All zones in zonelist are unreclaimable? */
 static bool all_unreclaimable(struct zonelist *zonelist,
                struct scan_control *sc)
@@ -2301,7 +2381,7 @@ static bool all_unreclaimable(struct zonelist *zonelist,
                        continue;
                if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                        continue;
-               if (!zone->all_unreclaimable)
+               if (zone_reclaimable(zone))
                        return false;
        }
 
@@ -2354,12 +2434,16 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
                 */
                if (global_reclaim(sc)) {
                        unsigned long lru_pages = 0;
+
+                       nodes_clear(shrink->nodes_to_scan);
                        for_each_zone_zonelist(zone, z, zonelist,
                                        gfp_zone(sc->gfp_mask)) {
                                if (!cpuset_zone_allowed_hardwall(zone, GFP_KERNEL))
                                        continue;
 
                                lru_pages += zone_reclaimable_pages(zone);
+                               node_set(zone_to_nid(zone),
+                                        shrink->nodes_to_scan);
                        }
 
                        shrink_slab(shrink, sc->nr_scanned, lru_pages);
@@ -2712,7 +2796,7 @@ static bool pgdat_balanced(pg_data_t *pgdat, int order, int classzone_idx)
                 * DEF_PRIORITY. Effectively, it considers them balanced so
                 * they must be considered balanced here as well!
                 */
-               if (zone->all_unreclaimable) {
+               if (!zone_reclaimable(zone)) {
                        balanced_pages += zone->managed_pages;
                        continue;
                }
@@ -2773,7 +2857,6 @@ static bool kswapd_shrink_zone(struct zone *zone,
                               unsigned long lru_pages,
                               unsigned long *nr_attempted)
 {
-       unsigned long nr_slab;
        int testorder = sc->order;
        unsigned long balance_gap;
        struct reclaim_state *reclaim_state = current->reclaim_state;
@@ -2816,17 +2899,16 @@ static bool kswapd_shrink_zone(struct zone *zone,
                return true;
 
        shrink_zone(zone, sc);
+       nodes_clear(shrink.nodes_to_scan);
+       node_set(zone_to_nid(zone), shrink.nodes_to_scan);
 
        reclaim_state->reclaimed_slab = 0;
-       nr_slab = shrink_slab(&shrink, sc->nr_scanned, lru_pages);
+       shrink_slab(&shrink, sc->nr_scanned, lru_pages);
        sc->nr_reclaimed += reclaim_state->reclaimed_slab;
 
        /* Account for the number of pages attempted to reclaim */
        *nr_attempted += sc->nr_to_reclaim;
 
-       if (nr_slab == 0 && !zone_reclaimable(zone))
-               zone->all_unreclaimable = 1;
-
        zone_clear_flag(zone, ZONE_WRITEBACK);
 
        /*
@@ -2835,7 +2917,7 @@ static bool kswapd_shrink_zone(struct zone *zone,
         * BDIs but as pressure is relieved, speculatively avoid congestion
         * waits.
         */
-       if (!zone->all_unreclaimable &&
+       if (zone_reclaimable(zone) &&
            zone_balanced(zone, testorder, 0, classzone_idx)) {
                zone_clear_flag(zone, ZONE_CONGESTED);
                zone_clear_flag(zone, ZONE_TAIL_LRU_DIRTY);
@@ -2870,8 +2952,6 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
 {
        int i;
        int end_zone = 0;       /* Inclusive.  0 = ZONE_DMA */
-       unsigned long nr_soft_reclaimed;
-       unsigned long nr_soft_scanned;
        struct scan_control sc = {
                .gfp_mask = GFP_KERNEL,
                .priority = DEF_PRIORITY,
@@ -2901,8 +2981,8 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                        if (!populated_zone(zone))
                                continue;
 
-                       if (zone->all_unreclaimable &&
-                           sc.priority != DEF_PRIORITY)
+                       if (sc.priority != DEF_PRIORITY &&
+                           !zone_reclaimable(zone))
                                continue;
 
                        /*
@@ -2980,21 +3060,12 @@ static unsigned long balance_pgdat(pg_data_t *pgdat, int order,
                        if (!populated_zone(zone))
                                continue;
 
-                       if (zone->all_unreclaimable &&
-                           sc.priority != DEF_PRIORITY)
+                       if (sc.priority != DEF_PRIORITY &&
+                           !zone_reclaimable(zone))
                                continue;
 
                        sc.nr_scanned = 0;
 
-                       nr_soft_scanned = 0;
-                       /*
-                        * Call soft limit reclaim before calling shrink_zone.
-                        */
-                       nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone,
-                                                       order, sc.gfp_mask,
-                                                       &nr_soft_scanned);
-                       sc.nr_reclaimed += nr_soft_reclaimed;
-
                        /*
                         * There should be no need to raise the scanning
                         * priority if enough pages are already being scanned
@@ -3237,7 +3308,7 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
        }
        if (!waitqueue_active(&pgdat->kswapd_wait))
                return;
-       if (zone_watermark_ok_safe(zone, order, low_wmark_pages(zone), 0, 0))
+       if (zone_balanced(zone, order, 0, 0))
                return;
 
        trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, zone_idx(zone), order);
@@ -3265,20 +3336,6 @@ unsigned long global_reclaimable_pages(void)
        return nr;
 }
 
-unsigned long zone_reclaimable_pages(struct zone *zone)
-{
-       int nr;
-
-       nr = zone_page_state(zone, NR_ACTIVE_FILE) +
-            zone_page_state(zone, NR_INACTIVE_FILE);
-
-       if (get_nr_swap_pages() > 0)
-               nr += zone_page_state(zone, NR_ACTIVE_ANON) +
-                     zone_page_state(zone, NR_INACTIVE_ANON);
-
-       return nr;
-}
-
 #ifdef CONFIG_HIBERNATION
 /*
  * Try to free `nr_to_reclaim' of memory, system-wide, and return the number of
@@ -3524,10 +3581,9 @@ static int __zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
                 * number of slab pages and shake the slab until it is reduced
                 * by the same nr_pages that we used for reclaiming unmapped
                 * pages.
-                *
-                * Note that shrink_slab will free memory on all zones and may
-                * take a long time.
                 */
+               nodes_clear(shrink.nodes_to_scan);
+               node_set(zone_to_nid(zone), shrink.nodes_to_scan);
                for (;;) {
                        unsigned long lru_pages = zone_reclaimable_pages(zone);
 
@@ -3576,7 +3632,7 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
            zone_page_state(zone, NR_SLAB_RECLAIMABLE) <= zone->min_slab_pages)
                return ZONE_RECLAIM_FULL;
 
-       if (zone->all_unreclaimable)
+       if (!zone_reclaimable(zone))
                return ZONE_RECLAIM_FULL;
 
        /*
index 20c2ef4458fac9ba3a5af98afd34b135ec86e5cb..9bb314577911f50c06848373d273b3b993373858 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/math64.h>
 #include <linux/writeback.h>
 #include <linux/compaction.h>
+#include <linux/mm_inline.h>
+
+#include "internal.h"
 
 #ifdef CONFIG_VM_EVENT_COUNTERS
 DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
@@ -414,12 +417,17 @@ void dec_zone_page_state(struct page *page, enum zone_stat_item item)
 EXPORT_SYMBOL(dec_zone_page_state);
 #endif
 
+static inline void fold_diff(int *diff)
+{
+       int i;
+
+       for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+               if (diff[i])
+                       atomic_long_add(diff[i], &vm_stat[i]);
+}
+
 /*
- * Update the zone counters for one cpu.
- *
- * The cpu specified must be either the current cpu or a processor that
- * is not online. If it is the current cpu then the execution thread must
- * be pinned to the current cpu.
+ * Update the zone counters for the current cpu.
  *
  * Note that refresh_cpu_vm_stats strives to only access
  * node local memory. The per cpu pagesets on remote zones are placed
@@ -432,33 +440,29 @@ EXPORT_SYMBOL(dec_zone_page_state);
  * with the global counters. These could cause remote node cache line
  * bouncing and will have to be only done when necessary.
  */
-void refresh_cpu_vm_stats(int cpu)
+static void refresh_cpu_vm_stats(void)
 {
        struct zone *zone;
        int i;
        int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
 
        for_each_populated_zone(zone) {
-               struct per_cpu_pageset *p;
+               struct per_cpu_pageset __percpu *p = zone->pageset;
 
-               p = per_cpu_ptr(zone->pageset, cpu);
+               for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) {
+                       int v;
 
-               for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-                       if (p->vm_stat_diff[i]) {
-                               unsigned long flags;
-                               int v;
+                       v = this_cpu_xchg(p->vm_stat_diff[i], 0);
+                       if (v) {
 
-                               local_irq_save(flags);
-                               v = p->vm_stat_diff[i];
-                               p->vm_stat_diff[i] = 0;
-                               local_irq_restore(flags);
                                atomic_long_add(v, &zone->vm_stat[i]);
                                global_diff[i] += v;
 #ifdef CONFIG_NUMA
                                /* 3 seconds idle till flush */
-                               p->expire = 3;
+                               __this_cpu_write(p->expire, 3);
 #endif
                        }
+               }
                cond_resched();
 #ifdef CONFIG_NUMA
                /*
@@ -468,29 +472,57 @@ void refresh_cpu_vm_stats(int cpu)
                 * Check if there are pages remaining in this pageset
                 * if not then there is nothing to expire.
                 */
-               if (!p->expire || !p->pcp.count)
+               if (!__this_cpu_read(p->expire) ||
+                              !__this_cpu_read(p->pcp.count))
                        continue;
 
                /*
                 * We never drain zones local to this processor.
                 */
                if (zone_to_nid(zone) == numa_node_id()) {
-                       p->expire = 0;
+                       __this_cpu_write(p->expire, 0);
                        continue;
                }
 
-               p->expire--;
-               if (p->expire)
+
+               if (__this_cpu_dec_return(p->expire))
                        continue;
 
-               if (p->pcp.count)
-                       drain_zone_pages(zone, &p->pcp);
+               if (__this_cpu_read(p->pcp.count))
+                       drain_zone_pages(zone, __this_cpu_ptr(&p->pcp));
 #endif
        }
+       fold_diff(global_diff);
+}
 
-       for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
-               if (global_diff[i])
-                       atomic_long_add(global_diff[i], &vm_stat[i]);
+/*
+ * Fold the data for an offline cpu into the global array.
+ * There cannot be any access by the offline cpu and therefore
+ * synchronization is simplified.
+ */
+void cpu_vm_stats_fold(int cpu)
+{
+       struct zone *zone;
+       int i;
+       int global_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, };
+
+       for_each_populated_zone(zone) {
+               struct per_cpu_pageset *p;
+
+               p = per_cpu_ptr(zone->pageset, cpu);
+
+               for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++)
+                       if (p->vm_stat_diff[i]) {
+                               int v;
+
+                               v = p->vm_stat_diff[i];
+                               p->vm_stat_diff[i] = 0;
+                               atomic_long_add(v, &zone->vm_stat[i]);
+                               global_diff[i] += v;
+                       }
+       }
+
+       fold_diff(global_diff);
 }
 
 /*
@@ -703,6 +735,7 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
 const char * const vmstat_text[] = {
        /* Zoned VM counters */
        "nr_free_pages",
+       "nr_alloc_batch",
        "nr_inactive_anon",
        "nr_active_anon",
        "nr_inactive_file",
@@ -817,6 +850,12 @@ const char * const vmstat_text[] = {
        "thp_zero_page_alloc",
        "thp_zero_page_alloc_failed",
 #endif
+#ifdef CONFIG_SMP
+       "nr_tlb_remote_flush",
+       "nr_tlb_remote_flush_received",
+#endif
+       "nr_tlb_local_flush_all",
+       "nr_tlb_local_flush_one",
 
 #endif /* CONFIG_VM_EVENTS_COUNTERS */
 };
@@ -1052,7 +1091,7 @@ static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat,
                   "\n  all_unreclaimable: %u"
                   "\n  start_pfn:         %lu"
                   "\n  inactive_ratio:    %u",
-                  zone->all_unreclaimable,
+                  !zone_reclaimable(zone),
                   zone->zone_start_pfn,
                   zone->inactive_ratio);
        seq_putc(m, '\n');
@@ -1177,7 +1216,7 @@ int sysctl_stat_interval __read_mostly = HZ;
 
 static void vmstat_update(struct work_struct *w)
 {
-       refresh_cpu_vm_stats(smp_processor_id());
+       refresh_cpu_vm_stats();
        schedule_delayed_work(&__get_cpu_var(vmstat_work),
                round_jiffies_relative(sysctl_stat_interval));
 }
index ad1e781284fdd48492e7bac46c245fae5d578f95..9451361e6aa701557e9d028e738e9d6e3024756f 100644 (file)
--- a/mm/zbud.c
+++ b/mm/zbud.c
@@ -16,7 +16,7 @@
  *
  * zbud works by storing compressed pages, or "zpages", together in pairs in a
  * single memory page called a "zbud page".  The first buddy is "left
- * justifed" at the beginning of the zbud page, and the last buddy is "right
+ * justified" at the beginning of the zbud page, and the last buddy is "right
  * justified" at the end of the zbud page.  The benefit is that if either
  * buddy is freed, the freed buddy space, coalesced with whatever slack space
  * that existed between the buddies, results in the largest possible free region
@@ -243,7 +243,7 @@ void zbud_destroy_pool(struct zbud_pool *pool)
  * gfp should not set __GFP_HIGHMEM as highmem pages cannot be used
  * as zbud pool pages.
  *
- * Return: 0 if success and handle is set, otherwise -EINVAL is the size or
+ * Return: 0 if success and handle is set, otherwise -EINVAL if the size or
  * gfp arguments are invalid or -ENOMEM if the pool was unable to allocate
  * a new page.
  */
index deda2b671e128600c817714754a6d58decb0c50a..841e35f1db22caff3afd03c104403f0c744776cb 100644 (file)
@@ -409,7 +409,7 @@ static int zswap_get_swap_cache_page(swp_entry_t entry,
                                struct page **retpage)
 {
        struct page *found_page, *new_page = NULL;
-       struct address_space *swapper_space = &swapper_spaces[swp_type(entry)];
+       struct address_space *swapper_space = swap_address_space(entry);
        int err;
 
        *retpage = NULL;
@@ -790,26 +790,14 @@ static void zswap_frontswap_invalidate_page(unsigned type, pgoff_t offset)
 static void zswap_frontswap_invalidate_area(unsigned type)
 {
        struct zswap_tree *tree = zswap_trees[type];
-       struct rb_node *node;
-       struct zswap_entry *entry;
+       struct zswap_entry *entry, *n;
 
        if (!tree)
                return;
 
        /* walk the tree and free everything */
        spin_lock(&tree->lock);
-       /*
-        * TODO: Even though this code should not be executed because
-        * the try_to_unuse() in swapoff should have emptied the tree,
-        * it is very wasteful to rebalance the tree after every
-        * removal when we are freeing the whole tree.
-        *
-        * If post-order traversal code is ever added to the rbtree
-        * implementation, it should be used here.
-        */
-       while ((node = rb_first(&tree->rbroot))) {
-               entry = rb_entry(node, struct zswap_entry, rbnode);
-               rb_erase(&entry->rbnode, &tree->rbroot);
+       rbtree_postorder_for_each_entry_safe(entry, n, &tree->rbroot, rbnode) {
                zbud_free(tree->pool, entry->handle);
                zswap_entry_cache_free(entry);
                atomic_dec(&zswap_stored_pages);
index ba93bdab2701939e2488b30c5c55be315acb0670..ee8fd6bd4035b28697db6dacaf3453a3d94a72a3 100644 (file)
@@ -987,6 +987,7 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 {
        int err;
        struct p9_client *clnt;
+       char *client_id;
 
        err = 0;
        clnt = kmalloc(sizeof(struct p9_client), GFP_KERNEL);
@@ -995,6 +996,10 @@ struct p9_client *p9_client_create(const char *dev_name, char *options)
 
        clnt->trans_mod = NULL;
        clnt->trans = NULL;
+
+       client_id = utsname()->nodename;
+       memcpy(clnt->name, client_id, strlen(client_id) + 1);
+
        spin_lock_init(&clnt->lock);
        INIT_LIST_HEAD(&clnt->fidlist);
 
index e1c26b10183067d02a66f56f8ffb3094fb13f2cc..990afab2be1bcc1732167def7eb0336e38509588 100644 (file)
@@ -577,6 +577,10 @@ static int p9_virtio_probe(struct virtio_device *vdev)
        mutex_lock(&virtio_9p_lock);
        list_add_tail(&chan->chan_list, &virtio_chan_list);
        mutex_unlock(&virtio_9p_lock);
+
+       /* Let udev rules use the new mount_tag attribute. */
+       kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
+
        return 0;
 
 out_free_tag:
@@ -654,6 +658,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
        list_del(&chan->chan_list);
        mutex_unlock(&virtio_9p_lock);
        sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
+       kobject_uevent(&(vdev->dev.kobj), KOBJ_CHANGE);
        kfree(chan->tag);
        kfree(chan->vc_wq);
        kfree(chan);
index ee0213667272cc8eb5425af16921c69bee385311..b50dacc072f0026416490e534f7f6c14fa624724 100644 (file)
@@ -228,7 +228,7 @@ config RPS
 
 config RFS_ACCEL
        boolean
-       depends on RPS && GENERIC_HARDIRQS
+       depends on RPS
        select CPU_RMAP
        default y
 
index 4493913f0d5c973446e0597b38f9dda2269d3c48..813db4e646021dea4c089d53ea65504a63ff0d2d 100644 (file)
@@ -168,6 +168,7 @@ static int batadv_interface_tx(struct sk_buff *skb,
        case ETH_P_8021Q:
                vhdr = (struct vlan_ethhdr *)skb->data;
                vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
+               vid |= BATADV_VLAN_HAS_TAG;
 
                if (vhdr->h_vlan_encapsulated_proto != ethertype)
                        break;
@@ -331,6 +332,7 @@ void batadv_interface_rx(struct net_device *soft_iface,
        case ETH_P_8021Q:
                vhdr = (struct vlan_ethhdr *)skb->data;
                vid = ntohs(vhdr->h_vlan_TCI) & VLAN_VID_MASK;
+               vid |= BATADV_VLAN_HAS_TAG;
 
                if (vhdr->h_vlan_encapsulated_proto != ethertype)
                        break;
index b9259efa636ef8fe2b79ec25de49a16efa9034db..e74ddc1c29a8be20f1a093fcc8e27b11bca6f03e 100644 (file)
@@ -207,7 +207,7 @@ int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
               struct net_device *dev, u32 filter_mask)
 {
        int err = 0;
-       struct net_bridge_port *port = br_port_get_rcu(dev);
+       struct net_bridge_port *port = br_port_get_rtnl(dev);
 
        /* not a bridge port and  */
        if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN))
@@ -451,7 +451,7 @@ static size_t br_get_link_af_size(const struct net_device *dev)
        struct net_port_vlans *pv;
 
        if (br_port_exists(dev))
-               pv = nbp_get_vlan_info(br_port_get_rcu(dev));
+               pv = nbp_get_vlan_info(br_port_get_rtnl(dev));
        else if (dev->priv_flags & IFF_EBRIDGE)
                pv = br_get_vlan_info((struct net_bridge *)netdev_priv(dev));
        else
index 598cb0b333c64b57c639dd7cda8df7aec229448d..efb57d91156975b3b43a2afdc588128a2f6e1f79 100644 (file)
@@ -202,13 +202,10 @@ struct net_bridge_port
 
 static inline struct net_bridge_port *br_port_get_rcu(const struct net_device *dev)
 {
-       struct net_bridge_port *port =
-                       rcu_dereference_rtnl(dev->rx_handler_data);
-
-       return br_port_exists(dev) ? port : NULL;
+       return rcu_dereference(dev->rx_handler_data);
 }
 
-static inline struct net_bridge_port *br_port_get_rtnl(struct net_device *dev)
+static inline struct net_bridge_port *br_port_get_rtnl(const struct net_device *dev)
 {
        return br_port_exists(dev) ?
                rtnl_dereference(dev->rx_handler_data) : NULL;
@@ -746,6 +743,7 @@ extern struct net_bridge_port *br_get_port(struct net_bridge *br,
 extern void br_init_port(struct net_bridge_port *p);
 extern void br_become_designated_port(struct net_bridge_port *p);
 
+extern void __br_set_forward_delay(struct net_bridge *br, unsigned long t);
 extern int br_set_forward_delay(struct net_bridge *br, unsigned long x);
 extern int br_set_hello_time(struct net_bridge *br, unsigned long x);
 extern int br_set_max_age(struct net_bridge *br, unsigned long x);
index 1c0a50f132293e0fb15e506620459047a8e1075b..3c86f0538cbb4a056bc274c971e254cb3d8da0f8 100644 (file)
@@ -209,7 +209,7 @@ static void br_record_config_information(struct net_bridge_port *p,
        p->designated_age = jiffies - bpdu->message_age;
 
        mod_timer(&p->message_age_timer, jiffies
-                 + (p->br->max_age - bpdu->message_age));
+                 + (bpdu->max_age - bpdu->message_age));
 }
 
 /* called under bridge lock */
@@ -544,18 +544,27 @@ int br_set_max_age(struct net_bridge *br, unsigned long val)
 
 }
 
+void __br_set_forward_delay(struct net_bridge *br, unsigned long t)
+{
+       br->bridge_forward_delay = t;
+       if (br_is_root_bridge(br))
+               br->forward_delay = br->bridge_forward_delay;
+}
+
 int br_set_forward_delay(struct net_bridge *br, unsigned long val)
 {
        unsigned long t = clock_t_to_jiffies(val);
+       int err = -ERANGE;
 
+       spin_lock_bh(&br->lock);
        if (br->stp_enabled != BR_NO_STP &&
            (t < BR_MIN_FORWARD_DELAY || t > BR_MAX_FORWARD_DELAY))
-               return -ERANGE;
+               goto unlock;
 
-       spin_lock_bh(&br->lock);
-       br->bridge_forward_delay = t;
-       if (br_is_root_bridge(br))
-               br->forward_delay = br->bridge_forward_delay;
+       __br_set_forward_delay(br, t);
+       err = 0;
+
+unlock:
        spin_unlock_bh(&br->lock);
-       return 0;
+       return err;
 }
index d45e760141bb81a34909b98724b2d8f3fc876136..108084a0467160e30eb001cd2dbb326fdc4dadd3 100644 (file)
@@ -129,6 +129,14 @@ static void br_stp_start(struct net_bridge *br)
        char *envp[] = { NULL };
 
        r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
+
+       spin_lock_bh(&br->lock);
+
+       if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY)
+               __br_set_forward_delay(br, BR_MIN_FORWARD_DELAY);
+       else if (br->bridge_forward_delay < BR_MAX_FORWARD_DELAY)
+               __br_set_forward_delay(br, BR_MAX_FORWARD_DELAY);
+
        if (r == 0) {
                br->stp_enabled = BR_USER_STP;
                br_debug(br, "userspace STP started\n");
@@ -137,10 +145,10 @@ static void br_stp_start(struct net_bridge *br)
                br_debug(br, "using kernel STP\n");
 
                /* To start timers on any ports left in blocking */
-               spin_lock_bh(&br->lock);
                br_port_state_selection(br);
-               spin_unlock_bh(&br->lock);
        }
+
+       spin_unlock_bh(&br->lock);
 }
 
 static void br_stp_stop(struct net_bridge *br)
index 3be308e143026ac3d831e4aefc13faa198400d21..4a5df7b1cc9ff5652185e0248cf5a4df4006effd 100644 (file)
@@ -290,7 +290,7 @@ int ceph_msgr_init(void)
        if (ceph_msgr_slab_init())
                return -ENOMEM;
 
-       ceph_msgr_wq = alloc_workqueue("ceph-msgr", WQ_NON_REENTRANT, 0);
+       ceph_msgr_wq = alloc_workqueue("ceph-msgr", 0, 0);
        if (ceph_msgr_wq)
                return 0;
 
index dd47889adc4aec94941d6f17105878ebe235db8f..2b4b32aaa893b3117043e6a218fcde6c58f0aff4 100644 (file)
@@ -503,7 +503,9 @@ void osd_req_op_extent_init(struct ceph_osd_request *osd_req,
        struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which, opcode);
        size_t payload_len = 0;
 
-       BUG_ON(opcode != CEPH_OSD_OP_READ && opcode != CEPH_OSD_OP_WRITE);
+       BUG_ON(opcode != CEPH_OSD_OP_READ && opcode != CEPH_OSD_OP_WRITE &&
+              opcode != CEPH_OSD_OP_DELETE && opcode != CEPH_OSD_OP_ZERO &&
+              opcode != CEPH_OSD_OP_TRUNCATE);
 
        op->extent.offset = offset;
        op->extent.length = length;
@@ -631,6 +633,9 @@ static u64 osd_req_encode_op(struct ceph_osd_request *req,
                break;
        case CEPH_OSD_OP_READ:
        case CEPH_OSD_OP_WRITE:
+       case CEPH_OSD_OP_ZERO:
+       case CEPH_OSD_OP_DELETE:
+       case CEPH_OSD_OP_TRUNCATE:
                if (src->op == CEPH_OSD_OP_WRITE)
                        request_data_len = src->extent.length;
                dst->extent.offset = cpu_to_le64(src->extent.offset);
@@ -715,7 +720,9 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        u64 object_base;
        int r;
 
-       BUG_ON(opcode != CEPH_OSD_OP_READ && opcode != CEPH_OSD_OP_WRITE);
+       BUG_ON(opcode != CEPH_OSD_OP_READ && opcode != CEPH_OSD_OP_WRITE &&
+              opcode != CEPH_OSD_OP_DELETE && opcode != CEPH_OSD_OP_ZERO &&
+              opcode != CEPH_OSD_OP_TRUNCATE);
 
        req = ceph_osdc_alloc_request(osdc, snapc, num_ops, use_mempool,
                                        GFP_NOFS);
@@ -1488,14 +1495,14 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
        dout("handle_reply %p tid %llu req %p result %d\n", msg, tid,
             req, result);
 
-       ceph_decode_need(&p, end, 4, bad);
+       ceph_decode_need(&p, end, 4, bad_put);
        numops = ceph_decode_32(&p);
        if (numops > CEPH_OSD_MAX_OP)
                goto bad_put;
        if (numops != req->r_num_ops)
                goto bad_put;
        payload_len = 0;
-       ceph_decode_need(&p, end, numops * sizeof(struct ceph_osd_op), bad);
+       ceph_decode_need(&p, end, numops * sizeof(struct ceph_osd_op), bad_put);
        for (i = 0; i < numops; i++) {
                struct ceph_osd_op *op = p;
                int len;
@@ -1513,7 +1520,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
                goto bad_put;
        }
 
-       ceph_decode_need(&p, end, 4 + numops * 4, bad);
+       ceph_decode_need(&p, end, 4 + numops * 4, bad_put);
        retry_attempt = ceph_decode_32(&p);
        for (i = 0; i < numops; i++)
                req->r_reply_op_result[i] = ceph_decode_32(&p);
@@ -1786,6 +1793,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                nr_maps--;
        }
 
+       if (!osdc->osdmap)
+               goto bad;
 done:
        downgrade_write(&osdc->map_sem);
        ceph_monc_got_osdmap(&osdc->client->monc, osdc->osdmap->epoch);
@@ -2129,6 +2138,8 @@ int ceph_osdc_start_request(struct ceph_osd_client *osdc,
                        dout("osdc_start_request failed map, "
                                " will retry %lld\n", req->r_tid);
                        rc = 0;
+               } else {
+                       __unregister_request(osdc, req);
                }
                goto out_unlock;
        }
@@ -2204,6 +2215,17 @@ void ceph_osdc_sync(struct ceph_osd_client *osdc)
 }
 EXPORT_SYMBOL(ceph_osdc_sync);
 
+/*
+ * Call all pending notify callbacks - for use after a watch is
+ * unregistered, to make sure no more callbacks for it will be invoked
+ */
+extern void ceph_osdc_flush_notifies(struct ceph_osd_client *osdc)
+{
+       flush_workqueue(osdc->notify_wq);
+}
+EXPORT_SYMBOL(ceph_osdc_flush_notifies);
+
+
 /*
  * init, shutdown
  */
@@ -2253,12 +2275,10 @@ int ceph_osdc_init(struct ceph_osd_client *osdc, struct ceph_client *client)
        if (err < 0)
                goto out_msgpool;
 
+       err = -ENOMEM;
        osdc->notify_wq = create_singlethread_workqueue("ceph-watch-notify");
-       if (IS_ERR(osdc->notify_wq)) {
-               err = PTR_ERR(osdc->notify_wq);
-               osdc->notify_wq = NULL;
+       if (!osdc->notify_wq)
                goto out_msgpool;
-       }
        return 0;
 
 out_msgpool:
index 603ddd92db1965e16fac61a420c4cdb5c8330bbb..dbd9a4792427455e0a2dfdd7d2249c4abcbbb798 100644 (file)
@@ -1129,7 +1129,7 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
 
        /* pg_temp? */
        pgid.seed = ceph_stable_mod(pgid.seed, pool->pg_num,
-                                   pool->pgp_num_mask);
+                                   pool->pg_num_mask);
        pg = __lookup_pg_mapping(&osdmap->pg_temp, pgid);
        if (pg) {
                *num = pg->len;
index 0ff42f029ace683610115f5251554dc3e87b9210..1929af87b2609650d0b484e7d01dc4a405ba8389 100644 (file)
@@ -352,7 +352,7 @@ u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb)
 
                if (queue_index != new_index && sk &&
                    rcu_access_pointer(sk->sk_dst_cache))
-                       sk_tx_queue_set(sk, queue_index);
+                       sk_tx_queue_set(sk, new_index);
 
                queue_index = new_index;
        }
index 2c637e9a0b277ff2a987edf139622d7580b43e02..fc75c9e461b8d366d5c29417735432dc573f08ae 100644 (file)
@@ -550,7 +550,7 @@ static void netpoll_neigh_reply(struct sk_buff *skb, struct netpoll_info *npinfo
                return;
 
        proto = ntohs(eth_hdr(skb)->h_proto);
-       if (proto == ETH_P_IP) {
+       if (proto == ETH_P_ARP) {
                struct arphdr *arp;
                unsigned char *arp_ptr;
                /* No arp on this interface */
@@ -1284,15 +1284,14 @@ EXPORT_SYMBOL_GPL(__netpoll_free_async);
 
 void netpoll_cleanup(struct netpoll *np)
 {
-       if (!np->dev)
-               return;
-
        rtnl_lock();
+       if (!np->dev)
+               goto out;
        __netpoll_cleanup(np);
-       rtnl_unlock();
-
        dev_put(np->dev);
        np->dev = NULL;
+out:
+       rtnl_unlock();
 }
 EXPORT_SYMBOL(netpoll_cleanup);
 
index 9c61f9c02fdb81df0f87f62994ac13330631c59a..6cf9f7782ad4238208173f390369b5fc4cc75e2b 100644 (file)
@@ -135,6 +135,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 
                if (dst)
                        dst->ops->redirect(dst, sk, skb);
+               goto out;
        }
 
        if (type == ICMPV6_PKT_TOOBIG) {
index d6c0e64ec97f2147124e84d4b634f263bac9eb95..dace87f06e5f9bf22ed99d078d058ea8f1339f4a 100644 (file)
@@ -369,7 +369,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, int size)
        pip->saddr    = fl4.saddr;
        pip->protocol = IPPROTO_IGMP;
        pip->tot_len  = 0;      /* filled in later */
-       ip_select_ident(pip, &rt->dst, NULL);
+       ip_select_ident(skb, &rt->dst, NULL);
        ((u8 *)&pip[1])[0] = IPOPT_RA;
        ((u8 *)&pip[1])[1] = 4;
        ((u8 *)&pip[1])[2] = 0;
@@ -714,7 +714,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
        iph->daddr    = dst;
        iph->saddr    = fl4.saddr;
        iph->protocol = IPPROTO_IGMP;
-       ip_select_ident(iph, &rt->dst, NULL);
+       ip_select_ident(skb, &rt->dst, NULL);
        ((u8 *)&iph[1])[0] = IPOPT_RA;
        ((u8 *)&iph[1])[1] = 4;
        ((u8 *)&iph[1])[2] = 0;
index 000e3d239d6481ed230e71c9c9033dba301694e9..33d5537881ed7b39e33199dfe978bbe5b912d706 100644 (file)
@@ -32,8 +32,8 @@
  *  At the moment of writing this notes identifier of IP packets is generated
  *  to be unpredictable using this code only for packets subjected
  *  (actually or potentially) to defragmentation.  I.e. DF packets less than
- *  PMTU in size uses a constant ID and do not use this code (see
- *  ip_select_ident() in include/net/ip.h).
+ *  PMTU in size when local fragmentation is disabled use a constant ID and do
+ *  not use this code (see ip_select_ident() in include/net/ip.h).
  *
  *  Route cache entries hold references to our nodes.
  *  New cache entries get references via lookup by destination IP address in
index 9ee17e3d11c30e4054558729df205b41a762e806..a04d872c54f919c7133e7830773301cdf070f3ed 100644 (file)
@@ -148,7 +148,7 @@ int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
        iph->daddr    = (opt && opt->opt.srr ? opt->opt.faddr : daddr);
        iph->saddr    = saddr;
        iph->protocol = sk->sk_protocol;
-       ip_select_ident(iph, &rt->dst, sk);
+       ip_select_ident(skb, &rt->dst, sk);
 
        if (opt && opt->opt.optlen) {
                iph->ihl += opt->opt.optlen>>2;
@@ -386,7 +386,7 @@ packet_routed:
                ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0);
        }
 
-       ip_select_ident_more(iph, &rt->dst, sk,
+       ip_select_ident_more(skb, &rt->dst, sk,
                             (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 
        skb->priority = sk->sk_priority;
@@ -1316,7 +1316,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
        else
                ttl = ip_select_ttl(inet, &rt->dst);
 
-       iph = (struct iphdr *)skb->data;
+       iph = ip_hdr(skb);
        iph->version = 4;
        iph->ihl = 5;
        iph->tos = inet->tos;
@@ -1324,7 +1324,7 @@ struct sk_buff *__ip_make_skb(struct sock *sk,
        iph->ttl = ttl;
        iph->protocol = sk->sk_protocol;
        ip_copy_addrs(iph, fl4);
-       ip_select_ident(iph, &rt->dst, sk);
+       ip_select_ident(skb, &rt->dst, sk);
 
        if (opt) {
                iph->ihl += opt->optlen>>2;
index 9ae54b09254f158d82d6b86adafe04776c830775..62212c772a4b95961dafe1efce3fd06f146ccbb6 100644 (file)
@@ -1658,7 +1658,7 @@ static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
        iph->protocol   =       IPPROTO_IPIP;
        iph->ihl        =       5;
        iph->tot_len    =       htons(skb->len);
-       ip_select_ident(iph, skb_dst(skb), NULL);
+       ip_select_ident(skb, skb_dst(skb), NULL);
        ip_send_check(iph);
 
        memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
index a86c7ae71881b1e65e998888c92749fe63fcf3c1..bfec521c717fd2320242c24e7a7f74a64c1c1a44 100644 (file)
@@ -387,7 +387,7 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
                iph->check   = 0;
                iph->tot_len = htons(length);
                if (!iph->id)
-                       ip_select_ident(iph, &rt->dst, NULL);
+                       ip_select_ident(skb, &rt->dst, NULL);
 
                iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
        }
index 8a57d79b0b16c9bffa9615295095525bc9b90f98..559d4ae6ebf4ed32ff80605e3d1b5c3792b1752c 100644 (file)
@@ -87,8 +87,8 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
        if (!cg_proto)
                return -EINVAL;
 
-       if (val > RESOURCE_MAX)
-               val = RESOURCE_MAX;
+       if (val > RES_COUNTER_MAX)
+               val = RES_COUNTER_MAX;
 
        tcp = tcp_from_cgproto(cg_proto);
 
@@ -101,9 +101,9 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
                tcp->tcp_prot_mem[i] = min_t(long, val >> PAGE_SHIFT,
                                             net->ipv4.sysctl_tcp_mem[i]);
 
-       if (val == RESOURCE_MAX)
+       if (val == RES_COUNTER_MAX)
                clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags);
-       else if (val != RESOURCE_MAX) {
+       else if (val != RES_COUNTER_MAX) {
                /*
                 * The active bit needs to be written after the static_key
                 * update. This is what guarantees that the socket activation
@@ -187,7 +187,7 @@ static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
 
        switch (cft->private) {
        case RES_LIMIT:
-               val = tcp_read_stat(memcg, RES_LIMIT, RESOURCE_MAX);
+               val = tcp_read_stat(memcg, RES_LIMIT, RES_COUNTER_MAX);
                break;
        case RES_USAGE:
                val = tcp_read_usage(memcg);
index 4a22f3e715df930b9853cda07c4ec0f379553a9a..52f3c6b971d2def6854cf7d489022ad499ee0d24 100644 (file)
@@ -502,7 +502,9 @@ reset:
         * ACKs, wait for troubles.
         */
        if (crtt > tp->srtt) {
-               inet_csk(sk)->icsk_rto = crtt + max(crtt >> 2, tcp_rto_min(sk));
+               /* Set RTO like tcp_rtt_estimator(), but from cached RTT. */
+               crtt >>= 3;
+               inet_csk(sk)->icsk_rto = crtt + max(2 * crtt, tcp_rto_min(sk));
        } else if (tp->srtt == 0) {
                /* RFC6298: 5.7 We've failed to get a valid RTT sample from
                 * 3WHS. This is most likely due to retransmission,
index eb1dd4d643f2f92d5a2385d0839d06a3424c545c..b5663c37f089ed0afe33115bcbfad2555b8d0f48 100644 (file)
@@ -117,7 +117,7 @@ static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
 
        top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ?
                0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF));
-       ip_select_ident(top_iph, dst->child, NULL);
+       ip_select_ident(skb, dst->child, NULL);
 
        top_iph->ttl = ip4_dst_hoplimit(dst->child);
 
index 136fe55c1a471c72a959fbb33add244416fc93f6..7c96100b021ef0558a739b6da719246548153b11 100644 (file)
@@ -915,6 +915,9 @@ static int __init inet6_init(void)
        err = ip6_route_init();
        if (err)
                goto ip6_route_fail;
+       err = ndisc_late_init();
+       if (err)
+               goto ndisc_late_fail;
        err = ip6_flowlabel_init();
        if (err)
                goto ip6_flowlabel_fail;
@@ -981,6 +984,8 @@ ipv6_exthdrs_fail:
 addrconf_fail:
        ip6_flowlabel_cleanup();
 ip6_flowlabel_fail:
+       ndisc_late_cleanup();
+ndisc_late_fail:
        ip6_route_cleanup();
 ip6_route_fail:
 #ifdef CONFIG_PROC_FS
@@ -1043,6 +1048,7 @@ static void __exit inet6_exit(void)
        ipv6_exthdrs_exit();
        addrconf_cleanup();
        ip6_flowlabel_cleanup();
+       ndisc_late_cleanup();
        ip6_route_cleanup();
 #ifdef CONFIG_PROC_FS
 
index 07a7d65a7cb6757bdac702b01e8284ad2402bf46..8d67900aa0036139e934354f98aefab13ba51c7a 100644 (file)
@@ -162,12 +162,6 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb)
                off += optlen;
                len -= optlen;
        }
-       /* This case will not be caught by above check since its padding
-        * length is smaller than 7:
-        * 1 byte NH + 1 byte Length + 6 bytes Padding
-        */
-       if ((padlen == 6) && ((off - skb_network_header_len(skb)) == 8))
-               goto bad;
 
        if (len == 0)
                return true;
index a6c58ce43d34aaa878c6ea239e0ff7c3616bd302..e27591635f92c45306a33cb9513628751e93dd16 100644 (file)
@@ -138,8 +138,8 @@ static bool fib6_rule_suppress(struct fib_rule *rule, struct fib_lookup_arg *arg
        return false;
 
 suppress_route:
-               ip6_rt_put(rt);
-               return true;
+       ip6_rt_put(rt);
+       return true;
 }
 
 static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
index 73db48eba1c48faa046c584912f09cda8f6ae2fa..5bec666aba61d464fab4e77684eedd4265143cf9 100644 (file)
@@ -825,9 +825,9 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info)
        fn = fib6_add_1(root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen,
                        offsetof(struct rt6_info, rt6i_dst), allow_create,
                        replace_required);
-
        if (IS_ERR(fn)) {
                err = PTR_ERR(fn);
+               fn = NULL;
                goto out;
        }
 
index 61355f7f4da5b4bb7bcc3c12030e09abe9fa9691..2d8f4829575b2d410ce74014287b97361e2abf38 100644 (file)
@@ -1656,9 +1656,9 @@ static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev)
 
        if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
            nla_put(skb, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr),
-                   &parm->raddr) ||
-           nla_put(skb, IFLA_IPTUN_REMOTE, sizeof(struct in6_addr),
                    &parm->laddr) ||
+           nla_put(skb, IFLA_IPTUN_REMOTE, sizeof(struct in6_addr),
+                   &parm->raddr) ||
            nla_put_u8(skb, IFLA_IPTUN_TTL, parm->hop_limit) ||
            nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
            nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
index 12179457b2cd8026dd867586078b6b900c0488b3..f8a55ff1971b36db95ae7c22dd8c65062fbdcb61 100644 (file)
@@ -1727,24 +1727,28 @@ int __init ndisc_init(void)
        if (err)
                goto out_unregister_pernet;
 #endif
-       err = register_netdevice_notifier(&ndisc_netdev_notifier);
-       if (err)
-               goto out_unregister_sysctl;
 out:
        return err;
 
-out_unregister_sysctl:
 #ifdef CONFIG_SYSCTL
-       neigh_sysctl_unregister(&nd_tbl.parms);
 out_unregister_pernet:
-#endif
        unregister_pernet_subsys(&ndisc_net_ops);
        goto out;
+#endif
 }
 
-void ndisc_cleanup(void)
+int __init ndisc_late_init(void)
+{
+       return register_netdevice_notifier(&ndisc_netdev_notifier);
+}
+
+void ndisc_late_cleanup(void)
 {
        unregister_netdevice_notifier(&ndisc_netdev_notifier);
+}
+
+void ndisc_cleanup(void)
+{
 #ifdef CONFIG_SYSCTL
        neigh_sysctl_unregister(&nd_tbl.parms);
 #endif
index 61aaf70f376e9eafee55cae3cb3b909916d0554e..2205e8eeeacfa2ff56980cbeb73b6d52c77089fe 100644 (file)
@@ -69,8 +69,8 @@ icmpv6_manip_pkt(struct sk_buff *skb,
        hdr = (struct icmp6hdr *)(skb->data + hdroff);
        l3proto->csum_update(skb, iphdroff, &hdr->icmp6_cksum,
                             tuple, maniptype);
-       if (hdr->icmp6_code == ICMPV6_ECHO_REQUEST ||
-           hdr->icmp6_code == ICMPV6_ECHO_REPLY) {
+       if (hdr->icmp6_type == ICMPV6_ECHO_REQUEST ||
+           hdr->icmp6_type == ICMPV6_ECHO_REPLY) {
                inet_proto_csum_replace2(&hdr->icmp6_cksum, skb,
                                         hdr->icmp6_identifier,
                                         tuple->src.u.icmp.id, 0);
index 2e7855a1b10d17198adcfec98d550838daef80bd..ac28af74a41410abceed9884a9388d9cb37784cb 100644 (file)
@@ -2865,30 +2865,43 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
        if (!ieee80211_sdata_running(sdata))
                return;
 
-       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_AP))
-               return;
-
        sdata->radar_required = sdata->csa_radar_required;
        err = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
                                           &changed);
        if (WARN_ON(err < 0))
                return;
 
-       err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
-       if (err < 0)
-               return;
+       if (!local->use_chanctx) {
+               local->_oper_chandef = local->csa_chandef;
+               ieee80211_hw_config(local, 0);
+       }
 
-       changed |= err;
-       kfree(sdata->u.ap.next_beacon);
-       sdata->u.ap.next_beacon = NULL;
+       ieee80211_bss_info_change_notify(sdata, changed);
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+               err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon);
+               if (err < 0)
+                       return;
+               changed |= err;
+               kfree(sdata->u.ap.next_beacon);
+               sdata->u.ap.next_beacon = NULL;
+
+               ieee80211_bss_info_change_notify(sdata, err);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               ieee80211_ibss_finish_csa(sdata);
+               break;
+       default:
+               WARN_ON(1);
+               return;
+       }
        sdata->vif.csa_active = false;
 
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       ieee80211_bss_info_change_notify(sdata, changed);
-
        cfg80211_ch_switch_notify(sdata->dev, &local->csa_chandef);
 }
 
@@ -2936,20 +2949,56 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
        if (sdata->vif.csa_active)
                return -EBUSY;
 
-       /* only handle AP for now. */
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_AP:
+               sdata->csa_counter_offset_beacon =
+                       params->counter_offset_beacon;
+               sdata->csa_counter_offset_presp = params->counter_offset_presp;
+               sdata->u.ap.next_beacon =
+                       cfg80211_beacon_dup(&params->beacon_after);
+               if (!sdata->u.ap.next_beacon)
+                       return -ENOMEM;
+
+               err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
+               if (err < 0) {
+                       kfree(sdata->u.ap.next_beacon);
+                       return err;
+               }
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               if (!sdata->vif.bss_conf.ibss_joined)
+                       return -EINVAL;
+
+               if (params->chandef.width != sdata->u.ibss.chandef.width)
+                       return -EINVAL;
+
+               switch (params->chandef.width) {
+               case NL80211_CHAN_WIDTH_40:
+                       if (cfg80211_get_chandef_type(&params->chandef) !=
+                           cfg80211_get_chandef_type(&sdata->u.ibss.chandef))
+                               return -EINVAL;
+               case NL80211_CHAN_WIDTH_5:
+               case NL80211_CHAN_WIDTH_10:
+               case NL80211_CHAN_WIDTH_20_NOHT:
+               case NL80211_CHAN_WIDTH_20:
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               /* changes into another band are not supported */
+               if (sdata->u.ibss.chandef.chan->band !=
+                   params->chandef.chan->band)
+                       return -EINVAL;
+
+               err = ieee80211_ibss_csa_beacon(sdata, params);
+               if (err < 0)
+                       return err;
                break;
        default:
                return -EOPNOTSUPP;
        }
 
-       sdata->u.ap.next_beacon = cfg80211_beacon_dup(&params->beacon_after);
-       if (!sdata->u.ap.next_beacon)
-               return -ENOMEM;
-
-       sdata->csa_counter_offset_beacon = params->counter_offset_beacon;
-       sdata->csa_counter_offset_presp = params->counter_offset_presp;
        sdata->csa_radar_required = params->radar_required;
 
        if (params->block_tx)
@@ -2957,10 +3006,6 @@ static int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
                                IEEE80211_MAX_QUEUE_MAP,
                                IEEE80211_QUEUE_STOP_REASON_CSA);
 
-       err = ieee80211_assign_beacon(sdata, &params->beacon_csa);
-       if (err < 0)
-               return err;
-
        local->csa_chandef = params->chandef;
        sdata->vif.csa_active = true;
 
@@ -3014,7 +3059,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                        need_offchan = true;
                if (!ieee80211_is_action(mgmt->frame_control) ||
                    mgmt->u.action.category == WLAN_CATEGORY_PUBLIC ||
-                   mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED)
+                   mgmt->u.action.category == WLAN_CATEGORY_SELF_PROTECTED ||
+                   mgmt->u.action.category == WLAN_CATEGORY_SPECTRUM_MGMT)
                        break;
                rcu_read_lock();
                sta = sta_info_get(sdata, mgmt->da);
index 3a4764b2869efffdbcc3f90a363cf3f8b095496c..03ba6b5c5373b373d47956518fafeaf1338b2ad0 100644 (file)
@@ -453,11 +453,6 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
        chanctx_changed |= IEEE80211_CHANCTX_CHANGE_CHANNEL;
        drv_change_chanctx(local, ctx, chanctx_changed);
 
-       if (!local->use_chanctx) {
-               local->_oper_chandef = *chandef;
-               ieee80211_hw_config(local, 0);
-       }
-
        ieee80211_recalc_chanctx_chantype(local, ctx);
        ieee80211_recalc_smps_chanctx(local, ctx);
        ieee80211_recalc_radar_chanctx(local, ctx);
index b0e32d6281146231061d34f63088db6b90106fc1..5c090e41d9bbf1ea379307c8ecd6a648cb33f0ac 100644 (file)
@@ -103,54 +103,57 @@ static ssize_t hwflags_read(struct file *file, char __user *user_buf,
        if (!buf)
                return 0;
 
-       sf += snprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
+       sf += scnprintf(buf, mxln - sf, "0x%x\n", local->hw.flags);
        if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
-               sf += snprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
+               sf += scnprintf(buf + sf, mxln - sf, "HAS_RATE_CONTROL\n");
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
-               sf += snprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
+               sf += scnprintf(buf + sf, mxln - sf, "RX_INCLUDES_FCS\n");
        if (local->hw.flags & IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING)
-               sf += snprintf(buf + sf, mxln - sf,
-                              "HOST_BCAST_PS_BUFFERING\n");
+               sf += scnprintf(buf + sf, mxln - sf,
+                               "HOST_BCAST_PS_BUFFERING\n");
        if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE)
-               sf += snprintf(buf + sf, mxln - sf,
-                              "2GHZ_SHORT_SLOT_INCAPABLE\n");
+               sf += scnprintf(buf + sf, mxln - sf,
+                               "2GHZ_SHORT_SLOT_INCAPABLE\n");
        if (local->hw.flags & IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE)
-               sf += snprintf(buf + sf, mxln - sf,
-                              "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
+               sf += scnprintf(buf + sf, mxln - sf,
+                               "2GHZ_SHORT_PREAMBLE_INCAPABLE\n");
        if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
-               sf += snprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_UNSPEC\n");
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
-               sf += snprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SIGNAL_DBM\n");
        if (local->hw.flags & IEEE80211_HW_NEED_DTIM_BEFORE_ASSOC)
-               sf += snprintf(buf + sf, mxln - sf, "NEED_DTIM_BEFORE_ASSOC\n");
+               sf += scnprintf(buf + sf, mxln - sf,
+                               "NEED_DTIM_BEFORE_ASSOC\n");
        if (local->hw.flags & IEEE80211_HW_SPECTRUM_MGMT)
-               sf += snprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SPECTRUM_MGMT\n");
        if (local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION)
-               sf += snprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
+               sf += scnprintf(buf + sf, mxln - sf, "AMPDU_AGGREGATION\n");
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_PS)
-               sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PS\n");
        if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
-               sf += snprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
+               sf += scnprintf(buf + sf, mxln - sf, "PS_NULLFUNC_STACK\n");
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
-               sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_PS\n");
        if (local->hw.flags & IEEE80211_HW_MFP_CAPABLE)
-               sf += snprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
+               sf += scnprintf(buf + sf, mxln - sf, "MFP_CAPABLE\n");
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_STATIC_SMPS)
-               sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_STATIC_SMPS\n");
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS)
-               sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_DYNAMIC_SMPS\n");
+               sf += scnprintf(buf + sf, mxln - sf,
+                               "SUPPORTS_DYNAMIC_SMPS\n");
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)
-               sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_UAPSD\n");
        if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
-               sf += snprintf(buf + sf, mxln - sf, "REPORTS_TX_ACK_STATUS\n");
+               sf += scnprintf(buf + sf, mxln - sf,
+                               "REPORTS_TX_ACK_STATUS\n");
        if (local->hw.flags & IEEE80211_HW_CONNECTION_MONITOR)
-               sf += snprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
+               sf += scnprintf(buf + sf, mxln - sf, "CONNECTION_MONITOR\n");
        if (local->hw.flags & IEEE80211_HW_SUPPORTS_PER_STA_GTK)
-               sf += snprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
+               sf += scnprintf(buf + sf, mxln - sf, "SUPPORTS_PER_STA_GTK\n");
        if (local->hw.flags & IEEE80211_HW_AP_LINK_PS)
-               sf += snprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
+               sf += scnprintf(buf + sf, mxln - sf, "AP_LINK_PS\n");
        if (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)
-               sf += snprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
+               sf += scnprintf(buf + sf, mxln - sf, "TX_AMPDU_SETUP_IN_HW\n");
 
        rv = simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
        kfree(buf);
index b3ea11f3d526962ddd8190587f82d8d84134067c..5d03c47c0a4cb4fa60e861750956c64bb8c90337 100644 (file)
@@ -1085,4 +1085,31 @@ drv_channel_switch_beacon(struct ieee80211_sub_if_data *sdata,
        }
 }
 
+static inline int drv_join_ibss(struct ieee80211_local *local,
+                               struct ieee80211_sub_if_data *sdata)
+{
+       int ret = 0;
+
+       might_sleep();
+       check_sdata_in_driver(sdata);
+
+       trace_drv_join_ibss(local, sdata, &sdata->vif.bss_conf);
+       if (local->ops->join_ibss)
+               ret = local->ops->join_ibss(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+static inline void drv_leave_ibss(struct ieee80211_local *local,
+                                 struct ieee80211_sub_if_data *sdata)
+{
+       might_sleep();
+       check_sdata_in_driver(sdata);
+
+       trace_drv_leave_ibss(local, sdata);
+       if (local->ops->leave_ibss)
+               local->ops->leave_ibss(&local->hw, &sdata->vif);
+       trace_drv_return_void(local);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index a12afe77bb26b5037fe58d6624bbc87939c30cde..21a0b8835cb31d4a27dda9b2243038c2280b8f6a 100644 (file)
@@ -39,7 +39,8 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
                           const int beacon_int, const u32 basic_rates,
                           const u16 capability, u64 tsf,
                           struct cfg80211_chan_def *chandef,
-                          bool *have_higher_than_11mbit)
+                          bool *have_higher_than_11mbit,
+                          struct cfg80211_csa_settings *csa_settings)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
        struct ieee80211_local *local = sdata->local;
@@ -59,6 +60,7 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
                    2 + 8 /* max Supported Rates */ +
                    3 /* max DS params */ +
                    4 /* IBSS params */ +
+                   5 /* Channel Switch Announcement */ +
                    2 + (IEEE80211_MAX_SUPP_RATES - 8) +
                    2 + sizeof(struct ieee80211_ht_cap) +
                    2 + sizeof(struct ieee80211_ht_operation) +
@@ -135,6 +137,16 @@ ieee80211_ibss_build_presp(struct ieee80211_sub_if_data *sdata,
        *pos++ = 0;
        *pos++ = 0;
 
+       if (csa_settings) {
+               *pos++ = WLAN_EID_CHANNEL_SWITCH;
+               *pos++ = 3;
+               *pos++ = csa_settings->block_tx ? 1 : 0;
+               *pos++ = ieee80211_frequency_to_channel(
+                               csa_settings->chandef.chan->center_freq);
+               sdata->csa_counter_offset_beacon = (pos - presp->head);
+               *pos++ = csa_settings->count;
+       }
+
        /* put the remaining rates in WLAN_EID_EXT_SUPP_RATES */
        if (rates_n > 8) {
                *pos++ = WLAN_EID_EXT_SUPP_RATES;
@@ -217,6 +229,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        struct beacon_data *presp;
        enum nl80211_bss_scan_width scan_width;
        bool have_higher_than_11mbit;
+       int err;
 
        sdata_assert_lock(sdata);
 
@@ -235,6 +248,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_IBSS |
                                                 BSS_CHANGED_BEACON_ENABLED);
+               drv_leave_ibss(local, sdata);
        }
 
        presp = rcu_dereference_protected(ifibss->presp,
@@ -276,7 +290,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        presp = ieee80211_ibss_build_presp(sdata, beacon_int, basic_rates,
                                           capability, tsf, &chandef,
-                                          &have_higher_than_11mbit);
+                                          &have_higher_than_11mbit, NULL);
        if (!presp)
                return;
 
@@ -317,11 +331,26 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
+       ieee80211_set_wmm_default(sdata, true);
+
        sdata->vif.bss_conf.ibss_joined = true;
        sdata->vif.bss_conf.ibss_creator = creator;
-       ieee80211_bss_info_change_notify(sdata, bss_change);
 
-       ieee80211_set_wmm_default(sdata, true);
+       err = drv_join_ibss(local, sdata);
+       if (err) {
+               sdata->vif.bss_conf.ibss_joined = false;
+               sdata->vif.bss_conf.ibss_creator = false;
+               sdata->vif.bss_conf.enable_beacon = false;
+               sdata->vif.bss_conf.ssid_len = 0;
+               RCU_INIT_POINTER(ifibss->presp, NULL);
+               kfree_rcu(presp, rcu_head);
+               ieee80211_vif_release_channel(sdata);
+               sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
+                          err);
+               return;
+       }
+
+       ieee80211_bss_info_change_notify(sdata, bss_change);
 
        ifibss->state = IEEE80211_IBSS_MLME_JOINED;
        mod_timer(&ifibss->timer,
@@ -416,6 +445,169 @@ static void ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                                  tsf, false);
 }
 
+static int ieee80211_send_action_csa(struct ieee80211_sub_if_data *sdata,
+                                    struct cfg80211_csa_settings *csa_settings)
+{
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+       int freq;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.chan_switch) +
+                     sizeof(mgmt->u.action.u.chan_switch);
+       u8 *pos;
+
+       skb = dev_alloc_skb(local->tx_headroom + hdr_len +
+                           5 + /* channel switch announcement element */
+                           3); /* secondary channel offset element */
+       if (!skb)
+               return -1;
+
+       skb_reserve(skb, local->tx_headroom);
+       mgmt = (struct ieee80211_mgmt *)skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_ACTION);
+
+       eth_broadcast_addr(mgmt->da);
+       memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
+       memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
+       mgmt->u.action.category = WLAN_CATEGORY_SPECTRUM_MGMT;
+       mgmt->u.action.u.chan_switch.action_code = WLAN_ACTION_SPCT_CHL_SWITCH;
+       pos = skb_put(skb, 5);
+       *pos++ = WLAN_EID_CHANNEL_SWITCH;                       /* EID */
+       *pos++ = 3;                                             /* IE length */
+       *pos++ = csa_settings->block_tx ? 1 : 0;                /* CSA mode */
+       freq = csa_settings->chandef.chan->center_freq;
+       *pos++ = ieee80211_frequency_to_channel(freq);          /* channel */
+       *pos++ = csa_settings->count;                           /* count */
+
+       if (csa_settings->chandef.width == NL80211_CHAN_WIDTH_40) {
+               enum nl80211_channel_type ch_type;
+
+               skb_put(skb, 3);
+               *pos++ = WLAN_EID_SECONDARY_CHANNEL_OFFSET;     /* EID */
+               *pos++ = 1;                                     /* IE length */
+               ch_type = cfg80211_get_chandef_type(&csa_settings->chandef);
+               if (ch_type == NL80211_CHAN_HT40PLUS)
+                       *pos++ = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               else
+                       *pos++ = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+       }
+
+       ieee80211_tx_skb(sdata, skb);
+       return 0;
+}
+
+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
+                             struct cfg80211_csa_settings *csa_settings)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct beacon_data *presp, *old_presp;
+       struct cfg80211_bss *cbss;
+       const struct cfg80211_bss_ies *ies;
+       u16 capability;
+       u64 tsf;
+       int ret = 0;
+
+       sdata_assert_lock(sdata);
+
+       capability = WLAN_CAPABILITY_IBSS;
+
+       if (ifibss->privacy)
+               capability |= WLAN_CAPABILITY_PRIVACY;
+
+       cbss = cfg80211_get_bss(sdata->local->hw.wiphy, ifibss->chandef.chan,
+                               ifibss->bssid, ifibss->ssid,
+                               ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+                               WLAN_CAPABILITY_PRIVACY,
+                               capability);
+
+       if (WARN_ON(!cbss)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       rcu_read_lock();
+       ies = rcu_dereference(cbss->ies);
+       tsf = ies->tsf;
+       rcu_read_unlock();
+       cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+
+       old_presp = rcu_dereference_protected(ifibss->presp,
+                                         lockdep_is_held(&sdata->wdev.mtx));
+
+       presp = ieee80211_ibss_build_presp(sdata,
+                                          sdata->vif.bss_conf.beacon_int,
+                                          sdata->vif.bss_conf.basic_rates,
+                                          capability, tsf, &ifibss->chandef,
+                                          NULL, csa_settings);
+       if (!presp) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rcu_assign_pointer(ifibss->presp, presp);
+       if (old_presp)
+               kfree_rcu(old_presp, rcu_head);
+
+       /* it might not send the beacon for a while. send an action frame
+        * immediately to announce the channel switch.
+        */
+       if (csa_settings)
+               ieee80211_send_action_csa(sdata, csa_settings);
+
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
+ out:
+       return ret;
+}
+
+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct cfg80211_bss *cbss;
+       int err;
+       u16 capability;
+
+       sdata_lock(sdata);
+       /* update cfg80211 bss information with the new channel */
+       if (!is_zero_ether_addr(ifibss->bssid)) {
+               capability = WLAN_CAPABILITY_IBSS;
+
+               if (ifibss->privacy)
+                       capability |= WLAN_CAPABILITY_PRIVACY;
+
+               cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
+                                       ifibss->chandef.chan,
+                                       ifibss->bssid, ifibss->ssid,
+                                       ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+                                       WLAN_CAPABILITY_PRIVACY,
+                                       capability);
+               /* XXX: should not really modify cfg80211 data */
+               if (cbss) {
+                       cbss->channel = sdata->local->csa_chandef.chan;
+                       cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+               }
+       }
+
+       ifibss->chandef = sdata->local->csa_chandef;
+
+       /* generate the beacon */
+       err = ieee80211_ibss_csa_beacon(sdata, NULL);
+       sdata_unlock(sdata);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       cancel_work_sync(&ifibss->csa_connection_drop_work);
+}
+
 static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta)
        __acquires(RCU)
 {
@@ -499,6 +691,295 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, const u8 *bssid,
        return ieee80211_ibss_finish_sta(sta);
 }
 
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       int active = 0;
+       struct sta_info *sta;
+
+       sdata_assert_lock(sdata);
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (sta->sdata == sdata &&
+                   time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
+                              jiffies)) {
+                       active++;
+                       break;
+               }
+       }
+
+       rcu_read_unlock();
+
+       return active;
+}
+
+static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+       struct cfg80211_bss *cbss;
+       struct beacon_data *presp;
+       struct sta_info *sta;
+       int active_ibss;
+       u16 capability;
+
+       active_ibss = ieee80211_sta_active_ibss(sdata);
+
+       if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
+               capability = WLAN_CAPABILITY_IBSS;
+
+               if (ifibss->privacy)
+                       capability |= WLAN_CAPABILITY_PRIVACY;
+
+               cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
+                                       ifibss->bssid, ifibss->ssid,
+                                       ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
+                                       WLAN_CAPABILITY_PRIVACY,
+                                       capability);
+
+               if (cbss) {
+                       cfg80211_unlink_bss(local->hw.wiphy, cbss);
+                       cfg80211_put_bss(sdata->local->hw.wiphy, cbss);
+               }
+       }
+
+       ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
+
+       sta_info_flush(sdata);
+
+       spin_lock_bh(&ifibss->incomplete_lock);
+       while (!list_empty(&ifibss->incomplete_stations)) {
+               sta = list_first_entry(&ifibss->incomplete_stations,
+                                      struct sta_info, list);
+               list_del(&sta->list);
+               spin_unlock_bh(&ifibss->incomplete_lock);
+
+               sta_info_free(local, sta);
+               spin_lock_bh(&ifibss->incomplete_lock);
+       }
+       spin_unlock_bh(&ifibss->incomplete_lock);
+
+       netif_carrier_off(sdata->dev);
+
+       sdata->vif.bss_conf.ibss_joined = false;
+       sdata->vif.bss_conf.ibss_creator = false;
+       sdata->vif.bss_conf.enable_beacon = false;
+       sdata->vif.bss_conf.ssid_len = 0;
+
+       /* remove beacon */
+       presp = rcu_dereference_protected(ifibss->presp,
+                                         lockdep_is_held(&sdata->wdev.mtx));
+       RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
+       if (presp)
+               kfree_rcu(presp, rcu_head);
+
+       clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
+       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
+                                               BSS_CHANGED_IBSS);
+       drv_leave_ibss(local, sdata);
+       ieee80211_vif_release_channel(sdata);
+}
+
+static void ieee80211_csa_connection_drop_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data,
+                            u.ibss.csa_connection_drop_work);
+
+       ieee80211_ibss_disconnect(sdata);
+       synchronize_rcu();
+       skb_queue_purge(&sdata->skb_queue);
+
+       /* trigger a scan to find another IBSS network to join */
+       ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+}
+
+static bool
+ieee80211_ibss_process_chanswitch(struct ieee80211_sub_if_data *sdata,
+                                 struct ieee802_11_elems *elems,
+                                 bool beacon)
+{
+       struct cfg80211_csa_settings params;
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_chanctx *chanctx;
+       enum nl80211_channel_type ch_type;
+       int err, num_chanctx;
+       u32 sta_flags;
+       u8 mode;
+
+       if (sdata->vif.csa_active)
+               return true;
+
+       if (!sdata->vif.bss_conf.ibss_joined)
+               return false;
+
+       sta_flags = IEEE80211_STA_DISABLE_VHT;
+       switch (ifibss->chandef.width) {
+       case NL80211_CHAN_WIDTH_5:
+       case NL80211_CHAN_WIDTH_10:
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               sta_flags |= IEEE80211_STA_DISABLE_HT;
+               /* fall through */
+       case NL80211_CHAN_WIDTH_20:
+               sta_flags |= IEEE80211_STA_DISABLE_40MHZ;
+               break;
+       default:
+               break;
+       }
+
+       memset(&params, 0, sizeof(params));
+       err = ieee80211_parse_ch_switch_ie(sdata, elems, beacon,
+                                          ifibss->chandef.chan->band,
+                                          sta_flags, ifibss->bssid,
+                                          &params.count, &mode,
+                                          &params.chandef);
+
+       /* can't switch to destination channel, fail */
+       if (err < 0)
+               goto disconnect;
+
+       /* did not contain a CSA */
+       if (err)
+               return false;
+
+       if (ifibss->chandef.chan->band != params.chandef.chan->band)
+               goto disconnect;
+
+       switch (ifibss->chandef.width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+       case NL80211_CHAN_WIDTH_20:
+       case NL80211_CHAN_WIDTH_40:
+               /* keep our current HT mode (HT20/HT40+/HT40-), even if
+                * another mode  has been announced. The mode is not adopted
+                * within the beacon while doing CSA and we should therefore
+                * keep the mode which we announce.
+                */
+               ch_type = cfg80211_get_chandef_type(&ifibss->chandef);
+               cfg80211_chandef_create(&params.chandef, params.chandef.chan,
+                                       ch_type);
+               break;
+       case NL80211_CHAN_WIDTH_5:
+       case NL80211_CHAN_WIDTH_10:
+               if (params.chandef.width != ifibss->chandef.width) {
+                       sdata_info(sdata,
+                                  "IBSS %pM received channel switch from incompatible channel width (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+                                  ifibss->bssid,
+                                  params.chandef.chan->center_freq,
+                                  params.chandef.width,
+                                  params.chandef.center_freq1,
+                                  params.chandef.center_freq2);
+                       goto disconnect;
+               }
+               break;
+       default:
+               /* should not happen, sta_flags should prevent VHT modes. */
+               WARN_ON(1);
+               goto disconnect;
+       }
+
+       if (!cfg80211_chandef_usable(sdata->local->hw.wiphy, &params.chandef,
+                                    IEEE80211_CHAN_DISABLED)) {
+               sdata_info(sdata,
+                          "IBSS %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
+                          ifibss->bssid,
+                          params.chandef.chan->center_freq,
+                          params.chandef.width,
+                          params.chandef.center_freq1,
+                          params.chandef.center_freq2);
+               goto disconnect;
+       }
+
+       err = cfg80211_chandef_dfs_required(sdata->local->hw.wiphy,
+                                           &params.chandef);
+       if (err < 0)
+               goto disconnect;
+       if (err) {
+               params.radar_required = true;
+
+               /* TODO: IBSS-DFS not (yet) supported, disconnect. */
+               goto disconnect;
+       }
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!chanctx_conf) {
+               rcu_read_unlock();
+               goto disconnect;
+       }
+
+       /* don't handle for multi-VIF cases */
+       chanctx = container_of(chanctx_conf, struct ieee80211_chanctx, conf);
+       if (chanctx->refcount > 1) {
+               rcu_read_unlock();
+               goto disconnect;
+       }
+       num_chanctx = 0;
+       list_for_each_entry_rcu(chanctx, &sdata->local->chanctx_list, list)
+               num_chanctx++;
+
+       if (num_chanctx > 1) {
+               rcu_read_unlock();
+               goto disconnect;
+       }
+       rcu_read_unlock();
+
+       /* all checks done, now perform the channel switch. */
+       ibss_dbg(sdata,
+                "received channel switch announcement to go to channel %d MHz\n",
+                params.chandef.chan->center_freq);
+
+       params.block_tx = !!mode;
+
+       ieee80211_ibss_csa_beacon(sdata, &params);
+       sdata->csa_radar_required = params.radar_required;
+
+       if (params.block_tx)
+               ieee80211_stop_queues_by_reason(&sdata->local->hw,
+                               IEEE80211_MAX_QUEUE_MAP,
+                               IEEE80211_QUEUE_STOP_REASON_CSA);
+
+       sdata->local->csa_chandef = params.chandef;
+       sdata->vif.csa_active = true;
+
+       ieee80211_bss_info_change_notify(sdata, err);
+       drv_channel_switch_beacon(sdata, &params.chandef);
+
+       return true;
+disconnect:
+       ibss_dbg(sdata, "Can't handle channel switch, disconnect\n");
+       ieee80211_queue_work(&sdata->local->hw,
+                            &ifibss->csa_connection_drop_work);
+
+       return true;
+}
+
+static void
+ieee80211_rx_mgmt_spectrum_mgmt(struct ieee80211_sub_if_data *sdata,
+                               struct ieee80211_mgmt *mgmt, size_t len,
+                               struct ieee80211_rx_status *rx_status,
+                               struct ieee802_11_elems *elems)
+{
+       int required_len;
+
+       if (len < IEEE80211_MIN_ACTION_SIZE + 1)
+               return;
+
+       /* CSA is the only action we handle for now */
+       if (mgmt->u.action.u.measurement.action_code !=
+           WLAN_ACTION_SPCT_CHL_SWITCH)
+               return;
+
+       required_len = IEEE80211_MIN_ACTION_SIZE +
+                      sizeof(mgmt->u.action.u.chan_switch);
+       if (len < required_len)
+               return;
+
+       ieee80211_ibss_process_chanswitch(sdata, elems, false);
+}
+
 static void ieee80211_rx_mgmt_deauth_ibss(struct ieee80211_sub_if_data *sdata,
                                          struct ieee80211_mgmt *mgmt,
                                          size_t len)
@@ -661,10 +1142,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
 
        /* check if we need to merge IBSS */
 
-       /* we use a fixed BSSID */
-       if (sdata->u.ibss.fixed_bssid)
-               goto put_bss;
-
        /* not an IBSS */
        if (!(cbss->capability & WLAN_CAPABILITY_IBSS))
                goto put_bss;
@@ -680,10 +1157,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                sdata->u.ibss.ssid_len))
                goto put_bss;
 
+       /* process channel switch */
+       if (ieee80211_ibss_process_chanswitch(sdata, elems, true))
+               goto put_bss;
+
        /* same BSSID */
        if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
                goto put_bss;
 
+       /* we use a fixed BSSID */
+       if (sdata->u.ibss.fixed_bssid)
+               goto put_bss;
+
        if (ieee80211_have_rx_timestamp(rx_status)) {
                /* time when timestamp field was received */
                rx_timestamp =
@@ -775,30 +1260,6 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
        ieee80211_queue_work(&local->hw, &sdata->work);
 }
 
-static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       int active = 0;
-       struct sta_info *sta;
-
-       sdata_assert_lock(sdata);
-
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(sta, &local->sta_list, list) {
-               if (sta->sdata == sdata &&
-                   time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
-                              jiffies)) {
-                       active++;
-                       break;
-               }
-       }
-
-       rcu_read_unlock();
-
-       return active;
-}
-
 static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
@@ -1076,6 +1537,8 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_rx_status *rx_status;
        struct ieee80211_mgmt *mgmt;
        u16 fc;
+       struct ieee802_11_elems elems;
+       int ies_len;
 
        rx_status = IEEE80211_SKB_RXCB(skb);
        mgmt = (struct ieee80211_mgmt *) skb->data;
@@ -1101,6 +1564,27 @@ void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
        case IEEE80211_STYPE_DEAUTH:
                ieee80211_rx_mgmt_deauth_ibss(sdata, mgmt, skb->len);
                break;
+       case IEEE80211_STYPE_ACTION:
+               switch (mgmt->u.action.category) {
+               case WLAN_CATEGORY_SPECTRUM_MGMT:
+                       ies_len = skb->len -
+                                 offsetof(struct ieee80211_mgmt,
+                                          u.action.u.chan_switch.variable);
+
+                       if (ies_len < 0)
+                               break;
+
+                       ieee802_11_parse_elems(
+                               mgmt->u.action.u.chan_switch.variable,
+                               ies_len, true, &elems);
+
+                       if (elems.parse_error)
+                               break;
+
+                       ieee80211_rx_mgmt_spectrum_mgmt(sdata, mgmt, skb->len,
+                                                       rx_status, &elems);
+                       break;
+               }
        }
 
  mgmt_out:
@@ -1167,6 +1651,8 @@ void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
                    (unsigned long) sdata);
        INIT_LIST_HEAD(&ifibss->incomplete_stations);
        spin_lock_init(&ifibss->incomplete_lock);
+       INIT_WORK(&ifibss->csa_connection_drop_work,
+                 ieee80211_csa_connection_drop_work);
 }
 
 /* scan finished notification */
@@ -1265,73 +1751,19 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
-       struct ieee80211_local *local = sdata->local;
-       struct cfg80211_bss *cbss;
-       u16 capability;
-       int active_ibss;
-       struct sta_info *sta;
-       struct beacon_data *presp;
-
-       active_ibss = ieee80211_sta_active_ibss(sdata);
-
-       if (!active_ibss && !is_zero_ether_addr(ifibss->bssid)) {
-               capability = WLAN_CAPABILITY_IBSS;
-
-               if (ifibss->privacy)
-                       capability |= WLAN_CAPABILITY_PRIVACY;
-
-               cbss = cfg80211_get_bss(local->hw.wiphy, ifibss->chandef.chan,
-                                       ifibss->bssid, ifibss->ssid,
-                                       ifibss->ssid_len, WLAN_CAPABILITY_IBSS |
-                                       WLAN_CAPABILITY_PRIVACY,
-                                       capability);
 
-               if (cbss) {
-                       cfg80211_unlink_bss(local->hw.wiphy, cbss);
-                       cfg80211_put_bss(local->hw.wiphy, cbss);
-               }
-       }
-
-       ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
-       memset(ifibss->bssid, 0, ETH_ALEN);
+       ieee80211_ibss_disconnect(sdata);
        ifibss->ssid_len = 0;
-
-       sta_info_flush(sdata);
-
-       spin_lock_bh(&ifibss->incomplete_lock);
-       while (!list_empty(&ifibss->incomplete_stations)) {
-               sta = list_first_entry(&ifibss->incomplete_stations,
-                                      struct sta_info, list);
-               list_del(&sta->list);
-               spin_unlock_bh(&ifibss->incomplete_lock);
-
-               sta_info_free(local, sta);
-               spin_lock_bh(&ifibss->incomplete_lock);
-       }
-       spin_unlock_bh(&ifibss->incomplete_lock);
-
-       netif_carrier_off(sdata->dev);
+       memset(ifibss->bssid, 0, ETH_ALEN);
 
        /* remove beacon */
        kfree(sdata->u.ibss.ie);
-       presp = rcu_dereference_protected(ifibss->presp,
-                                         lockdep_is_held(&sdata->wdev.mtx));
-       RCU_INIT_POINTER(sdata->u.ibss.presp, NULL);
 
        /* on the next join, re-program HT parameters */
        memset(&ifibss->ht_capa, 0, sizeof(ifibss->ht_capa));
        memset(&ifibss->ht_capa_mask, 0, sizeof(ifibss->ht_capa_mask));
 
-       sdata->vif.bss_conf.ibss_joined = false;
-       sdata->vif.bss_conf.ibss_creator = false;
-       sdata->vif.bss_conf.enable_beacon = false;
-       sdata->vif.bss_conf.ssid_len = 0;
-       clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state);
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
-                                               BSS_CHANGED_IBSS);
-       ieee80211_vif_release_channel(sdata);
        synchronize_rcu();
-       kfree(presp);
 
        skb_queue_purge(&sdata->skb_queue);
 
index b6186517ec567e85eb986d77dd6ff72c36a4379d..3a87c8976a320473a5155f5963109b4319954f7f 100644 (file)
@@ -322,7 +322,6 @@ struct ieee80211_roc_work {
 
 /* flags used in struct ieee80211_if_managed.flags */
 enum ieee80211_sta_flags {
-       IEEE80211_STA_BEACON_POLL       = BIT(0),
        IEEE80211_STA_CONNECTION_POLL   = BIT(1),
        IEEE80211_STA_CONTROL_PORT      = BIT(2),
        IEEE80211_STA_DISABLE_HT        = BIT(4),
@@ -487,6 +486,7 @@ struct ieee80211_if_managed {
 
 struct ieee80211_if_ibss {
        struct timer_list timer;
+       struct work_struct csa_connection_drop_work;
 
        unsigned long last_scan_completed;
 
@@ -1330,6 +1330,10 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_work(struct ieee80211_sub_if_data *sdata);
 void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                   struct sk_buff *skb);
+int ieee80211_ibss_csa_beacon(struct ieee80211_sub_if_data *sdata,
+                             struct cfg80211_csa_settings *csa_settings);
+int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata);
+void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata);
 
 /* mesh code */
 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
@@ -1481,6 +1485,29 @@ void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
 void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
                                       struct ieee80211_mgmt *mgmt,
                                       size_t len);
+/**
+ * ieee80211_parse_ch_switch_ie - parses channel switch IEs
+ * @sdata: the sdata of the interface which has received the frame
+ * @elems: parsed 802.11 elements received with the frame
+ * @beacon: indicates if the frame was a beacon or probe response
+ * @current_band: indicates the current band
+ * @sta_flags: contains information about own capabilities and restrictions
+ *     to decide which channel switch announcements can be accepted. Only the
+ *     following subset of &enum ieee80211_sta_flags are evaluated:
+ *     %IEEE80211_STA_DISABLE_HT, %IEEE80211_STA_DISABLE_VHT,
+ *     %IEEE80211_STA_DISABLE_40MHZ, %IEEE80211_STA_DISABLE_80P80MHZ,
+ *     %IEEE80211_STA_DISABLE_160MHZ.
+ * @count: to be filled with the counter until the switch (on success only)
+ * @bssid: the currently connected bssid (for reporting)
+ * @mode: to be filled with CSA mode (on success only)
+ * @new_chandef: to be filled with destination chandef (on success only)
+ * Return: 0 on success, <0 on error and >0 if there is nothing to parse.
+ */
+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
+                                struct ieee802_11_elems *elems, bool beacon,
+                                enum ieee80211_band current_band,
+                                u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
+                                struct cfg80211_chan_def *new_chandef);
 
 /* Suspend/resume and hw reconfiguration */
 int ieee80211_reconfig(struct ieee80211_local *local);
@@ -1654,6 +1681,7 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
 void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
                                  const struct ieee80211_ht_operation *ht_oper,
                                  struct cfg80211_chan_def *chandef);
+u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c);
 
 int __must_check
 ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
index fcecd633514e2185b0a31235cac345ab08df9433..e48f103b9adeb5fd773f68c6d12cb633cea33fa5 100644 (file)
@@ -766,6 +766,10 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.type == NL80211_IFTYPE_STATION)
                ieee80211_mgd_stop(sdata);
 
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+               ieee80211_ibss_stop(sdata);
+
+
        /*
         * Remove all stations associated with this interface.
         *
index 620677e897bd0fc82fd5f4e737156096c05a9eef..3e51dd7d98b34aad114e6b927beae8e4ecdde9fb 100644 (file)
@@ -879,7 +879,7 @@ ieee80211_gtk_rekey_add(struct ieee80211_vif *vif,
                                  keyconf->keylen, keyconf->key,
                                  0, NULL);
        if (IS_ERR(key))
-               return ERR_PTR(PTR_ERR(key));
+               return ERR_CAST(key);
 
        if (sdata->u.mgd.mfp != IEEE80211_MFP_DISABLED)
                key->conf.flags |= IEEE80211_KEY_FLAG_RX_MGMT;
index 86e4ad56b573df27779831e17dce835f67396836..91cc8281e266cbfb7c51ea23c36e046e5f3c008a 100644 (file)
@@ -145,66 +145,6 @@ static int ecw2cw(int ecw)
        return (1 << ecw) - 1;
 }
 
-static u32 chandef_downgrade(struct cfg80211_chan_def *c)
-{
-       u32 ret;
-       int tmp;
-
-       switch (c->width) {
-       case NL80211_CHAN_WIDTH_20:
-               c->width = NL80211_CHAN_WIDTH_20_NOHT;
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
-               break;
-       case NL80211_CHAN_WIDTH_40:
-               c->width = NL80211_CHAN_WIDTH_20;
-               c->center_freq1 = c->chan->center_freq;
-               ret = IEEE80211_STA_DISABLE_40MHZ |
-                     IEEE80211_STA_DISABLE_VHT;
-               break;
-       case NL80211_CHAN_WIDTH_80:
-               tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
-               /* n_P40 */
-               tmp /= 2;
-               /* freq_P40 */
-               c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
-               c->width = NL80211_CHAN_WIDTH_40;
-               ret = IEEE80211_STA_DISABLE_VHT;
-               break;
-       case NL80211_CHAN_WIDTH_80P80:
-               c->center_freq2 = 0;
-               c->width = NL80211_CHAN_WIDTH_80;
-               ret = IEEE80211_STA_DISABLE_80P80MHZ |
-                     IEEE80211_STA_DISABLE_160MHZ;
-               break;
-       case NL80211_CHAN_WIDTH_160:
-               /* n_P20 */
-               tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
-               /* n_P80 */
-               tmp /= 4;
-               c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
-               c->width = NL80211_CHAN_WIDTH_80;
-               ret = IEEE80211_STA_DISABLE_80P80MHZ |
-                     IEEE80211_STA_DISABLE_160MHZ;
-               break;
-       default:
-       case NL80211_CHAN_WIDTH_20_NOHT:
-               WARN_ON_ONCE(1);
-               c->width = NL80211_CHAN_WIDTH_20_NOHT;
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
-               break;
-       case NL80211_CHAN_WIDTH_5:
-       case NL80211_CHAN_WIDTH_10:
-               WARN_ON_ONCE(1);
-               /* keep c->width */
-               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
-               break;
-       }
-
-       WARN_ON_ONCE(!cfg80211_chandef_valid(c));
-
-       return ret;
-}
-
 static u32
 ieee80211_determine_chantype(struct ieee80211_sub_if_data *sdata,
                             struct ieee80211_supported_band *sband,
@@ -352,7 +292,7 @@ out:
                        break;
                }
 
-               ret |= chandef_downgrade(chandef);
+               ret |= ieee80211_chandef_downgrade(chandef);
        }
 
        if (chandef->width != vht_chandef.width && !tracking)
@@ -406,13 +346,13 @@ static int ieee80211_config_bw(struct ieee80211_sub_if_data *sdata,
         */
        if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
            chandef.width == NL80211_CHAN_WIDTH_80P80)
-               flags |= chandef_downgrade(&chandef);
+               flags |= ieee80211_chandef_downgrade(&chandef);
        if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
            chandef.width == NL80211_CHAN_WIDTH_160)
-               flags |= chandef_downgrade(&chandef);
+               flags |= ieee80211_chandef_downgrade(&chandef);
        if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
            chandef.width > NL80211_CHAN_WIDTH_20)
-               flags |= chandef_downgrade(&chandef);
+               flags |= ieee80211_chandef_downgrade(&chandef);
 
        if (cfg80211_chandef_identical(&chandef, &sdata->vif.bss_conf.chandef))
                return 0;
@@ -893,8 +833,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
        if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
 
-       if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
-                           IEEE80211_STA_CONNECTION_POLL))
+       if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
                IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_USE_MINRATE;
 
        ieee80211_tx_skb(sdata, skb);
@@ -937,6 +876,8 @@ static void ieee80211_chswitch_work(struct work_struct *work)
                container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       u32 changed = 0;
+       int ret;
 
        if (!ieee80211_sdata_running(sdata))
                return;
@@ -945,24 +886,39 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        if (!ifmgd->associated)
                goto out;
 
-       local->_oper_chandef = local->csa_chandef;
+       ret = ieee80211_vif_change_channel(sdata, &local->csa_chandef,
+                                          &changed);
+       if (ret) {
+               sdata_info(sdata,
+                          "vif channel switch failed, disconnecting\n");
+               ieee80211_queue_work(&sdata->local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               goto out;
+       }
 
-       if (!local->ops->channel_switch) {
-               /* call "hw_config" only if doing sw channel switch */
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       } else {
-               /* update the device channel directly */
-               local->hw.conf.chandef = local->_oper_chandef;
+       if (!local->use_chanctx) {
+               local->_oper_chandef = local->csa_chandef;
+               /* Call "hw_config" only if doing sw channel switch.
+                * Otherwise update the channel directly
+                */
+               if (!local->ops->channel_switch)
+                       ieee80211_hw_config(local, 0);
+               else
+                       local->hw.conf.chandef = local->_oper_chandef;
        }
 
        /* XXX: shouldn't really modify cfg80211-owned data! */
-       ifmgd->associated->channel = local->_oper_chandef.chan;
+       ifmgd->associated->channel = local->csa_chandef.chan;
 
        /* XXX: wait for a beacon first? */
        ieee80211_wake_queues_by_reason(&local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
+
+       ieee80211_bss_info_change_notify(sdata, changed);
+
  out:
+       sdata->vif.csa_active = false;
        ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
        sdata_unlock(sdata);
 }
@@ -1000,20 +956,12 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct cfg80211_bss *cbss = ifmgd->associated;
-       struct ieee80211_bss *bss;
        struct ieee80211_chanctx *chanctx;
-       enum ieee80211_band new_band;
-       int new_freq;
-       u8 new_chan_no;
+       enum ieee80211_band current_band;
        u8 count;
        u8 mode;
-       struct ieee80211_channel *new_chan;
        struct cfg80211_chan_def new_chandef = {};
-       struct cfg80211_chan_def new_vht_chandef = {};
-       const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
-       const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
-       const struct ieee80211_ht_operation *ht_oper;
-       int secondary_channel_offset = -1;
+       int res;
 
        sdata_assert_lock(sdata);
 
@@ -1027,162 +975,23 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
                return;
 
-       sec_chan_offs = elems->sec_chan_offs;
-       wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
-       ht_oper = elems->ht_operation;
-
-       if (ifmgd->flags & (IEEE80211_STA_DISABLE_HT |
-                           IEEE80211_STA_DISABLE_40MHZ)) {
-               sec_chan_offs = NULL;
-               wide_bw_chansw_ie = NULL;
-               /* only used for bandwidth here */
-               ht_oper = NULL;
-       }
-
-       if (ifmgd->flags & IEEE80211_STA_DISABLE_VHT)
-               wide_bw_chansw_ie = NULL;
-
-       if (elems->ext_chansw_ie) {
-               if (!ieee80211_operating_class_to_band(
-                               elems->ext_chansw_ie->new_operating_class,
-                               &new_band)) {
-                       sdata_info(sdata,
-                                  "cannot understand ECSA IE operating class %d, disconnecting\n",
-                                  elems->ext_chansw_ie->new_operating_class);
-                       ieee80211_queue_work(&local->hw,
-                                            &ifmgd->csa_connection_drop_work);
-               }
-               new_chan_no = elems->ext_chansw_ie->new_ch_num;
-               count = elems->ext_chansw_ie->count;
-               mode = elems->ext_chansw_ie->mode;
-       } else if (elems->ch_switch_ie) {
-               new_band = cbss->channel->band;
-               new_chan_no = elems->ch_switch_ie->new_ch_num;
-               count = elems->ch_switch_ie->count;
-               mode = elems->ch_switch_ie->mode;
-       } else {
-               /* nothing here we understand */
-               return;
-       }
-
-       bss = (void *)cbss->priv;
-
-       new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
-       new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
-       if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
-               sdata_info(sdata,
-                          "AP %pM switches to unsupported channel (%d MHz), disconnecting\n",
-                          ifmgd->associated->bssid, new_freq);
+       current_band = cbss->channel->band;
+       res = ieee80211_parse_ch_switch_ie(sdata, elems, beacon, current_band,
+                                          ifmgd->flags,
+                                          ifmgd->associated->bssid, &count,
+                                          &mode, &new_chandef);
+       if (res < 0)
                ieee80211_queue_work(&local->hw,
                                     &ifmgd->csa_connection_drop_work);
+       if (res)
                return;
-       }
-
-       if (!beacon && sec_chan_offs) {
-               secondary_channel_offset = sec_chan_offs->sec_chan_offs;
-       } else if (beacon && ht_oper) {
-               secondary_channel_offset =
-                       ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
-       } else if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) {
-               /*
-                * If it's not a beacon, HT is enabled and the IE not present,
-                * it's 20 MHz, 802.11-2012 8.5.2.6:
-                *      This element [the Secondary Channel Offset Element] is
-                *      present when switching to a 40 MHz channel. It may be
-                *      present when switching to a 20 MHz channel (in which
-                *      case the secondary channel offset is set to SCN).
-                */
-               secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
-       }
-
-       switch (secondary_channel_offset) {
-       default:
-               /* secondary_channel_offset was present but is invalid */
-       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
-               cfg80211_chandef_create(&new_chandef, new_chan,
-                                       NL80211_CHAN_HT20);
-               break;
-       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-               cfg80211_chandef_create(&new_chandef, new_chan,
-                                       NL80211_CHAN_HT40PLUS);
-               break;
-       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-               cfg80211_chandef_create(&new_chandef, new_chan,
-                                       NL80211_CHAN_HT40MINUS);
-               break;
-       case -1:
-               cfg80211_chandef_create(&new_chandef, new_chan,
-                                       NL80211_CHAN_NO_HT);
-               /* keep width for 5/10 MHz channels */
-               switch (sdata->vif.bss_conf.chandef.width) {
-               case NL80211_CHAN_WIDTH_5:
-               case NL80211_CHAN_WIDTH_10:
-                       new_chandef.width = sdata->vif.bss_conf.chandef.width;
-                       break;
-               default:
-                       break;
-               }
-               break;
-       }
-
-       if (wide_bw_chansw_ie) {
-               new_vht_chandef.chan = new_chan;
-               new_vht_chandef.center_freq1 =
-                       ieee80211_channel_to_frequency(
-                               wide_bw_chansw_ie->new_center_freq_seg0,
-                               new_band);
-
-               switch (wide_bw_chansw_ie->new_channel_width) {
-               default:
-                       /* hmmm, ignore VHT and use HT if present */
-               case IEEE80211_VHT_CHANWIDTH_USE_HT:
-                       new_vht_chandef.chan = NULL;
-                       break;
-               case IEEE80211_VHT_CHANWIDTH_80MHZ:
-                       new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
-                       break;
-               case IEEE80211_VHT_CHANWIDTH_160MHZ:
-                       new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
-                       break;
-               case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
-                       /* field is otherwise reserved */
-                       new_vht_chandef.center_freq2 =
-                               ieee80211_channel_to_frequency(
-                                       wide_bw_chansw_ie->new_center_freq_seg1,
-                                       new_band);
-                       new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
-                       break;
-               }
-               if (ifmgd->flags & IEEE80211_STA_DISABLE_80P80MHZ &&
-                   new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
-                       chandef_downgrade(&new_vht_chandef);
-               if (ifmgd->flags & IEEE80211_STA_DISABLE_160MHZ &&
-                   new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
-                       chandef_downgrade(&new_vht_chandef);
-               if (ifmgd->flags & IEEE80211_STA_DISABLE_40MHZ &&
-                   new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
-                       chandef_downgrade(&new_vht_chandef);
-       }
-
-       /* if VHT data is there validate & use it */
-       if (new_vht_chandef.chan) {
-               if (!cfg80211_chandef_compatible(&new_vht_chandef,
-                                                &new_chandef)) {
-                       sdata_info(sdata,
-                                  "AP %pM CSA has inconsistent channel data, disconnecting\n",
-                                  ifmgd->associated->bssid);
-                       ieee80211_queue_work(&local->hw,
-                                            &ifmgd->csa_connection_drop_work);
-                       return;
-               }
-               new_chandef = new_vht_chandef;
-       }
 
        if (!cfg80211_chandef_usable(local->hw.wiphy, &new_chandef,
                                     IEEE80211_CHAN_DISABLED)) {
                sdata_info(sdata,
                           "AP %pM switches to unsupported channel (%d MHz, width:%d, CF1/2: %d/%d MHz), disconnecting\n",
-                          ifmgd->associated->bssid, new_freq,
+                          ifmgd->associated->bssid,
+                          new_chandef.chan->center_freq,
                           new_chandef.width, new_chandef.center_freq1,
                           new_chandef.center_freq2);
                ieee80211_queue_work(&local->hw,
@@ -1191,17 +1000,28 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        }
 
        ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+       sdata->vif.csa_active = true;
 
+       mutex_lock(&local->chanctx_mtx);
        if (local->use_chanctx) {
-               sdata_info(sdata,
-                          "not handling channel switch with channel contexts\n");
-               ieee80211_queue_work(&local->hw,
-                                    &ifmgd->csa_connection_drop_work);
-               return;
+               u32 num_chanctx = 0;
+               list_for_each_entry(chanctx, &local->chanctx_list, list)
+                      num_chanctx++;
+
+               if (num_chanctx > 1 ||
+                   !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+                       sdata_info(sdata,
+                                  "not handling chan-switch with channel contexts\n");
+                       ieee80211_queue_work(&local->hw,
+                                            &ifmgd->csa_connection_drop_work);
+                       mutex_unlock(&local->chanctx_mtx);
+                       return;
+               }
        }
 
-       mutex_lock(&local->chanctx_mtx);
        if (WARN_ON(!rcu_access_pointer(sdata->vif.chanctx_conf))) {
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
                mutex_unlock(&local->chanctx_mtx);
                return;
        }
@@ -1374,8 +1194,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
        if (!mgd->associated)
                return false;
 
-       if (mgd->flags & (IEEE80211_STA_BEACON_POLL |
-                         IEEE80211_STA_CONNECTION_POLL))
+       if (mgd->flags & IEEE80211_STA_CONNECTION_POLL)
                return false;
 
        if (!mgd->have_beacon)
@@ -1691,8 +1510,7 @@ static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata)
 {
        lockdep_assert_held(&sdata->local->mtx);
 
-       sdata->u.mgd.flags &= ~(IEEE80211_STA_CONNECTION_POLL |
-                               IEEE80211_STA_BEACON_POLL);
+       sdata->u.mgd.flags &= ~IEEE80211_STA_CONNECTION_POLL;
        ieee80211_run_deferred_scan(sdata->local);
 }
 
@@ -1954,11 +1772,8 @@ static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
        struct ieee80211_local *local = sdata->local;
 
        mutex_lock(&local->mtx);
-       if (!(ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
-                             IEEE80211_STA_CONNECTION_POLL))) {
-               mutex_unlock(&local->mtx);
-               return;
-       }
+       if (!(ifmgd->flags & IEEE80211_STA_CONNECTION_POLL))
+               goto out;
 
        __ieee80211_stop_poll(sdata);
 
@@ -2094,15 +1909,9 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
         * because otherwise we would reset the timer every time and
         * never check whether we received a probe response!
         */
-       if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
-                           IEEE80211_STA_CONNECTION_POLL))
+       if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL)
                already = true;
 
-       if (beacon)
-               ifmgd->flags |= IEEE80211_STA_BEACON_POLL;
-       else
-               ifmgd->flags |= IEEE80211_STA_CONNECTION_POLL;
-
        mutex_unlock(&sdata->local->mtx);
 
        if (already)
@@ -2174,6 +1983,7 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata)
                               WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY,
                               true, frame_buf);
        ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+       sdata->vif.csa_active = false;
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_MAX_QUEUE_MAP,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
@@ -3061,17 +2871,10 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) {
+       if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL) {
                mlme_dbg_ratelimited(sdata,
                                     "cancelling AP probe due to a received beacon\n");
-               mutex_lock(&local->mtx);
-               ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL;
-               ieee80211_run_deferred_scan(local);
-               mutex_unlock(&local->mtx);
-
-               mutex_lock(&local->iflist_mtx);
-               ieee80211_recalc_ps(local, -1);
-               mutex_unlock(&local->iflist_mtx);
+               ieee80211_reset_ap_probe(sdata);
        }
 
        /*
@@ -3543,8 +3346,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
        } else if (ifmgd->assoc_data && ifmgd->assoc_data->timeout_started)
                run_again(sdata, ifmgd->assoc_data->timeout);
 
-       if (ifmgd->flags & (IEEE80211_STA_BEACON_POLL |
-                           IEEE80211_STA_CONNECTION_POLL) &&
+       if (ifmgd->flags & IEEE80211_STA_CONNECTION_POLL &&
            ifmgd->associated) {
                u8 bssid[ETH_ALEN];
                int max_tries;
@@ -3876,7 +3678,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                return ret;
 
        while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
-               ifmgd->flags |= chandef_downgrade(&chandef);
+               ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
                ret = ieee80211_vif_use_channel(sdata, &chandef,
                                                IEEE80211_CHANCTX_SHARED);
        }
index 8b5f7ef7c0c9f14db5dba3baf8ab82247500c1c3..7fa1b36e620247ed5c14e97d54b2d72d7a0b43cb 100644 (file)
@@ -203,6 +203,15 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
        memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate));
        mi->max_prob_rate = tmp_prob_rate;
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* use fixed index if set */
+       if (mp->fixed_rate_idx != -1) {
+               mi->max_tp_rate[0] = mp->fixed_rate_idx;
+               mi->max_tp_rate[1] = mp->fixed_rate_idx;
+               mi->max_prob_rate = mp->fixed_rate_idx;
+       }
+#endif
+
        /* Reset update timer */
        mi->stats_update = jiffies;
 
@@ -310,6 +319,11 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
        /* increase sum packet counter */
        mi->packet_count++;
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+       if (mp->fixed_rate_idx != -1)
+               return;
+#endif
+
        delta = (mi->packet_count * sampling_ratio / 100) -
                        (mi->sample_count + mi->sample_deferred / 2);
 
index 7c323f27ba230a91599f34a6877caa8c17ff8605..5d60779a0c1be89e987b2cd478af865ec806d4bb 100644 (file)
@@ -365,6 +365,14 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi)
                }
        }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* use fixed index if set */
+       if (mp->fixed_rate_idx != -1) {
+               mi->max_tp_rate = mp->fixed_rate_idx;
+               mi->max_tp_rate2 = mp->fixed_rate_idx;
+               mi->max_prob_rate = mp->fixed_rate_idx;
+       }
+#endif
 
        mi->stats_update = jiffies;
 }
@@ -774,6 +782,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        info->flags |= mi->tx_flags;
        minstrel_ht_check_cck_shortpreamble(mp, mi, txrc->short_preamble);
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+       if (mp->fixed_rate_idx != -1)
+               return;
+#endif
+
        /* Don't use EAPOL frames for sampling on non-mrr hw */
        if (mp->hw->max_rates == 1 &&
            (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO))
@@ -781,16 +794,6 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
        else
                sample_idx = minstrel_get_sample_rate(mp, mi);
 
-#ifdef CONFIG_MAC80211_DEBUGFS
-       /* use fixed index if set */
-       if (mp->fixed_rate_idx != -1) {
-               mi->max_tp_rate = mp->fixed_rate_idx;
-               mi->max_tp_rate2 = mp->fixed_rate_idx;
-               mi->max_prob_rate = mp->fixed_rate_idx;
-               sample_idx = -1;
-       }
-#endif
-
        mi->total_packets++;
 
        /* wraparound */
index c97a0657c0435bece74ce534e173df74b62a16ae..6ff134650a84c195e033c62c76e9c954ac7dc245 100644 (file)
@@ -167,29 +167,29 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
         * provide large enough buffers. */
        length = length < RC_PID_PRINT_BUF_SIZE ?
                 length : RC_PID_PRINT_BUF_SIZE;
-       p = snprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
+       p = scnprintf(pb, length, "%u %lu ", ev->id, ev->timestamp);
        switch (ev->type) {
        case RC_PID_EVENT_TYPE_TX_STATUS:
-               p += snprintf(pb + p, length - p, "tx_status %u %u",
-                             !(ev->data.flags & IEEE80211_TX_STAT_ACK),
-                             ev->data.tx_status.status.rates[0].idx);
+               p += scnprintf(pb + p, length - p, "tx_status %u %u",
+                              !(ev->data.flags & IEEE80211_TX_STAT_ACK),
+                              ev->data.tx_status.status.rates[0].idx);
                break;
        case RC_PID_EVENT_TYPE_RATE_CHANGE:
-               p += snprintf(pb + p, length - p, "rate_change %d %d",
-                             ev->data.index, ev->data.rate);
+               p += scnprintf(pb + p, length - p, "rate_change %d %d",
+                              ev->data.index, ev->data.rate);
                break;
        case RC_PID_EVENT_TYPE_TX_RATE:
-               p += snprintf(pb + p, length - p, "tx_rate %d %d",
-                             ev->data.index, ev->data.rate);
+               p += scnprintf(pb + p, length - p, "tx_rate %d %d",
+                              ev->data.index, ev->data.rate);
                break;
        case RC_PID_EVENT_TYPE_PF_SAMPLE:
-               p += snprintf(pb + p, length - p,
-                             "pf_sample %d %d %d %d",
-                             ev->data.pf_sample, ev->data.prop_err,
-                             ev->data.int_err, ev->data.der_err);
+               p += scnprintf(pb + p, length - p,
+                              "pf_sample %d %d %d %d",
+                              ev->data.pf_sample, ev->data.prop_err,
+                              ev->data.int_err, ev->data.der_err);
                break;
        }
-       p += snprintf(pb + p, length - p, "\n");
+       p += scnprintf(pb + p, length - p, "\n");
 
        spin_unlock_irqrestore(&events->lock, status);
 
index 54395d7583ba70e31111b08092c88d2901be7815..f0247a43a75c1d0825f2588cfbfbcd13fad9c28b 100644 (file)
@@ -995,8 +995,9 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                                rx->sta->num_duplicates++;
                        }
                        return RX_DROP_UNUSABLE;
-               } else
+               } else if (!(status->flag & RX_FLAG_AMSDU_MORE)) {
                        rx->sta->last_seq_ctrl[rx->seqno_idx] = hdr->seq_ctrl;
+               }
        }
 
        if (unlikely(rx->skb->len < 16)) {
@@ -2402,7 +2403,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                return RX_DROP_UNUSABLE;
 
        if (!rx->sta && mgmt->u.action.category != WLAN_CATEGORY_PUBLIC &&
-           mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED)
+           mgmt->u.action.category != WLAN_CATEGORY_SELF_PROTECTED &&
+           mgmt->u.action.category != WLAN_CATEGORY_SPECTRUM_MGMT)
                return RX_DROP_UNUSABLE;
 
        if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
@@ -2566,31 +2568,46 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
                goto queue;
        case WLAN_CATEGORY_SPECTRUM_MGMT:
-               if (status->band != IEEE80211_BAND_5GHZ)
-                       break;
-
-               if (sdata->vif.type != NL80211_IFTYPE_STATION)
-                       break;
-
                /* verify action_code is present */
                if (len < IEEE80211_MIN_ACTION_SIZE + 1)
                        break;
 
                switch (mgmt->u.action.u.measurement.action_code) {
                case WLAN_ACTION_SPCT_MSR_REQ:
+                       if (status->band != IEEE80211_BAND_5GHZ)
+                               break;
+
                        if (len < (IEEE80211_MIN_ACTION_SIZE +
                                   sizeof(mgmt->u.action.u.measurement)))
                                break;
+
+                       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                               break;
+
                        ieee80211_process_measurement_req(sdata, mgmt, len);
                        goto handled;
-               case WLAN_ACTION_SPCT_CHL_SWITCH:
-                       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+               case WLAN_ACTION_SPCT_CHL_SWITCH: {
+                       u8 *bssid;
+                       if (len < (IEEE80211_MIN_ACTION_SIZE +
+                                  sizeof(mgmt->u.action.u.chan_switch)))
+                               break;
+
+                       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                           sdata->vif.type != NL80211_IFTYPE_ADHOC)
                                break;
 
-                       if (!ether_addr_equal(mgmt->bssid, sdata->u.mgd.bssid))
+                       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+                               bssid = sdata->u.mgd.bssid;
+                       else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+                               bssid = sdata->u.ibss.bssid;
+                       else
+                               break;
+
+                       if (!ether_addr_equal(mgmt->bssid, bssid))
                                break;
 
                        goto queue;
+                       }
                }
                break;
        case WLAN_CATEGORY_SA_QUERY:
index 08afe74b98f4b6cbdda21ed3d8ff68b9a95fa64b..ecb57b0bf74a19153ab0ed196fe1ae4f7e272c64 100644 (file)
@@ -391,8 +391,7 @@ static bool ieee80211_can_scan(struct ieee80211_local *local,
                return false;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
-           sdata->u.mgd.flags & (IEEE80211_STA_BEACON_POLL |
-                                 IEEE80211_STA_CONNECTION_POLL))
+           sdata->u.mgd.flags & IEEE80211_STA_CONNECTION_POLL)
                return false;
 
        return true;
index 578eea3fc04d27a25eeddc84f244fe6de24dc6a8..921597e279a307857cad5974a434fdd9252ec225 100644 (file)
 #include "sta_info.h"
 #include "wme.h"
 
+int ieee80211_parse_ch_switch_ie(struct ieee80211_sub_if_data *sdata,
+                                struct ieee802_11_elems *elems, bool beacon,
+                                enum ieee80211_band current_band,
+                                u32 sta_flags, u8 *bssid, u8 *count, u8 *mode,
+                                struct cfg80211_chan_def *new_chandef)
+{
+       enum ieee80211_band new_band;
+       int new_freq;
+       u8 new_chan_no;
+       struct ieee80211_channel *new_chan;
+       struct cfg80211_chan_def new_vht_chandef = {};
+       const struct ieee80211_sec_chan_offs_ie *sec_chan_offs;
+       const struct ieee80211_wide_bw_chansw_ie *wide_bw_chansw_ie;
+       const struct ieee80211_ht_operation *ht_oper;
+       int secondary_channel_offset = -1;
+
+       sec_chan_offs = elems->sec_chan_offs;
+       wide_bw_chansw_ie = elems->wide_bw_chansw_ie;
+       ht_oper = elems->ht_operation;
+
+       if (sta_flags & (IEEE80211_STA_DISABLE_HT |
+                        IEEE80211_STA_DISABLE_40MHZ)) {
+               sec_chan_offs = NULL;
+               wide_bw_chansw_ie = NULL;
+               /* only used for bandwidth here */
+               ht_oper = NULL;
+       }
+
+       if (sta_flags & IEEE80211_STA_DISABLE_VHT)
+               wide_bw_chansw_ie = NULL;
+
+       if (elems->ext_chansw_ie) {
+               if (!ieee80211_operating_class_to_band(
+                               elems->ext_chansw_ie->new_operating_class,
+                               &new_band)) {
+                       sdata_info(sdata,
+                                  "cannot understand ECSA IE operating class %d, disconnecting\n",
+                                  elems->ext_chansw_ie->new_operating_class);
+                       return -EINVAL;
+               }
+               new_chan_no = elems->ext_chansw_ie->new_ch_num;
+               *count = elems->ext_chansw_ie->count;
+               *mode = elems->ext_chansw_ie->mode;
+       } else if (elems->ch_switch_ie) {
+               new_band = current_band;
+               new_chan_no = elems->ch_switch_ie->new_ch_num;
+               *count = elems->ch_switch_ie->count;
+               *mode = elems->ch_switch_ie->mode;
+       } else {
+               /* nothing here we understand */
+               return 1;
+       }
+
+       new_freq = ieee80211_channel_to_frequency(new_chan_no, new_band);
+       new_chan = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
+       if (!new_chan || new_chan->flags & IEEE80211_CHAN_DISABLED) {
+               sdata_info(sdata,
+                          "BSS %pM switches to unsupported channel (%d MHz), disconnecting\n",
+                          bssid, new_freq);
+               return -EINVAL;
+       }
+
+       if (!beacon && sec_chan_offs) {
+               secondary_channel_offset = sec_chan_offs->sec_chan_offs;
+       } else if (beacon && ht_oper) {
+               secondary_channel_offset =
+                       ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
+       } else if (!(sta_flags & IEEE80211_STA_DISABLE_HT)) {
+               /* If it's not a beacon, HT is enabled and the IE not present,
+                * it's 20 MHz, 802.11-2012 8.5.2.6:
+                *      This element [the Secondary Channel Offset Element] is
+                *      present when switching to a 40 MHz channel. It may be
+                *      present when switching to a 20 MHz channel (in which
+                *      case the secondary channel offset is set to SCN).
+                */
+               secondary_channel_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+       }
+
+       switch (secondary_channel_offset) {
+       default:
+               /* secondary_channel_offset was present but is invalid */
+       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+               cfg80211_chandef_create(new_chandef, new_chan,
+                                       NL80211_CHAN_HT20);
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+               cfg80211_chandef_create(new_chandef, new_chan,
+                                       NL80211_CHAN_HT40PLUS);
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+               cfg80211_chandef_create(new_chandef, new_chan,
+                                       NL80211_CHAN_HT40MINUS);
+               break;
+       case -1:
+               cfg80211_chandef_create(new_chandef, new_chan,
+                                       NL80211_CHAN_NO_HT);
+               /* keep width for 5/10 MHz channels */
+               switch (sdata->vif.bss_conf.chandef.width) {
+               case NL80211_CHAN_WIDTH_5:
+               case NL80211_CHAN_WIDTH_10:
+                       new_chandef->width = sdata->vif.bss_conf.chandef.width;
+                       break;
+               default:
+                       break;
+               }
+               break;
+       }
+
+       if (wide_bw_chansw_ie) {
+               new_vht_chandef.chan = new_chan;
+               new_vht_chandef.center_freq1 =
+                       ieee80211_channel_to_frequency(
+                               wide_bw_chansw_ie->new_center_freq_seg0,
+                               new_band);
+
+               switch (wide_bw_chansw_ie->new_channel_width) {
+               default:
+                       /* hmmm, ignore VHT and use HT if present */
+               case IEEE80211_VHT_CHANWIDTH_USE_HT:
+                       new_vht_chandef.chan = NULL;
+                       break;
+               case IEEE80211_VHT_CHANWIDTH_80MHZ:
+                       new_vht_chandef.width = NL80211_CHAN_WIDTH_80;
+                       break;
+               case IEEE80211_VHT_CHANWIDTH_160MHZ:
+                       new_vht_chandef.width = NL80211_CHAN_WIDTH_160;
+                       break;
+               case IEEE80211_VHT_CHANWIDTH_80P80MHZ:
+                       /* field is otherwise reserved */
+                       new_vht_chandef.center_freq2 =
+                               ieee80211_channel_to_frequency(
+                                       wide_bw_chansw_ie->new_center_freq_seg1,
+                                       new_band);
+                       new_vht_chandef.width = NL80211_CHAN_WIDTH_80P80;
+                       break;
+               }
+               if (sta_flags & IEEE80211_STA_DISABLE_80P80MHZ &&
+                   new_vht_chandef.width == NL80211_CHAN_WIDTH_80P80)
+                       ieee80211_chandef_downgrade(&new_vht_chandef);
+               if (sta_flags & IEEE80211_STA_DISABLE_160MHZ &&
+                   new_vht_chandef.width == NL80211_CHAN_WIDTH_160)
+                       ieee80211_chandef_downgrade(&new_vht_chandef);
+               if (sta_flags & IEEE80211_STA_DISABLE_40MHZ &&
+                   new_vht_chandef.width > NL80211_CHAN_WIDTH_20)
+                       ieee80211_chandef_downgrade(&new_vht_chandef);
+       }
+
+       /* if VHT data is there validate & use it */
+       if (new_vht_chandef.chan) {
+               if (!cfg80211_chandef_compatible(&new_vht_chandef,
+                                                new_chandef)) {
+                       sdata_info(sdata,
+                                  "BSS %pM: CSA has inconsistent channel data, disconnecting\n",
+                                  bssid);
+                       return -EINVAL;
+               }
+               *new_chandef = new_vht_chandef;
+       }
+
+       return 0;
+}
+
 static void ieee80211_send_refuse_measurement_request(struct ieee80211_sub_if_data *sdata,
                                        struct ieee80211_msrment_ie *request_ie,
                                        const u8 *da, const u8 *bssid,
index 1aba645882bd92abbf9e5a4cdd90f7544a173c4a..5d62c5804819e8e3faa3e696e16b166c5f431524 100644 (file)
@@ -1475,6 +1475,41 @@ DEFINE_EVENT(local_sdata_evt, drv_ipv6_addr_change,
 );
 #endif
 
+TRACE_EVENT(drv_join_ibss,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_bss_conf *info),
+
+       TP_ARGS(local, sdata, info),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u8, dtimper)
+               __field(u16, bcnint)
+               __dynamic_array(u8, ssid, info->ssid_len);
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->dtimper = info->dtim_period;
+               __entry->bcnint = info->beacon_int;
+               memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_leave_ibss,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
index 3456c0486b482bfb44a6f797ebaff5d70bde4940..4fcbf634b54863387f85b42d5f47f82de861e995 100644 (file)
@@ -1981,7 +1981,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         * EAPOL frames from the local station.
         */
        if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) &&
-                    !is_multicast_ether_addr(hdr.addr1) && !authorized &&
+                    !multicast && !authorized &&
                     (cpu_to_be16(ethertype) != sdata->control_port_protocol ||
                      !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -2357,15 +2357,31 @@ static void ieee80211_update_csa(struct ieee80211_sub_if_data *sdata,
        struct probe_resp *resp;
        int counter_offset_beacon = sdata->csa_counter_offset_beacon;
        int counter_offset_presp = sdata->csa_counter_offset_presp;
+       u8 *beacon_data;
+       size_t beacon_data_len;
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_AP:
+               beacon_data = beacon->tail;
+               beacon_data_len = beacon->tail_len;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               beacon_data = beacon->head;
+               beacon_data_len = beacon->head_len;
+               break;
+       default:
+               return;
+       }
+       if (WARN_ON(counter_offset_beacon >= beacon_data_len))
+               return;
 
        /* warn if the driver did not check for/react to csa completeness */
-       if (WARN_ON(((u8 *)beacon->tail)[counter_offset_beacon] == 0))
+       if (WARN_ON(beacon_data[counter_offset_beacon] == 0))
                return;
 
-       ((u8 *)beacon->tail)[counter_offset_beacon]--;
+       beacon_data[counter_offset_beacon]--;
 
-       if (sdata->vif.type == NL80211_IFTYPE_AP &&
-           counter_offset_presp) {
+       if (sdata->vif.type == NL80211_IFTYPE_AP && counter_offset_presp) {
                rcu_read_lock();
                resp = rcu_dereference(sdata->u.ap.probe_resp);
 
@@ -2400,6 +2416,15 @@ bool ieee80211_csa_is_complete(struct ieee80211_vif *vif)
                        goto out;
                beacon_data = beacon->tail;
                beacon_data_len = beacon->tail_len;
+       } else if (vif->type == NL80211_IFTYPE_ADHOC) {
+               struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+               beacon = rcu_dereference(ifibss->presp);
+               if (!beacon)
+                       goto out;
+
+               beacon_data = beacon->head;
+               beacon_data_len = beacon->head_len;
        } else {
                WARN_ON(1);
                goto out;
@@ -2484,6 +2509,10 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                if (!presp)
                        goto out;
 
+               if (sdata->vif.csa_active)
+                       ieee80211_update_csa(sdata, presp);
+
+
                skb = dev_alloc_skb(local->tx_headroom + presp->head_len);
                if (!skb)
                        goto out;
index e1b34a18b24344cb95a642c436fc5322054207ce..550a6880625dd79cfd9741017ddb6e63f4c50274 100644 (file)
@@ -567,18 +567,15 @@ void ieee80211_flush_queues(struct ieee80211_local *local,
                                        IEEE80211_QUEUE_STOP_REASON_FLUSH);
 }
 
-void ieee80211_iterate_active_interfaces(
-       struct ieee80211_hw *hw, u32 iter_flags,
-       void (*iterator)(void *data, u8 *mac,
-                        struct ieee80211_vif *vif),
-       void *data)
+static void __iterate_active_interfaces(struct ieee80211_local *local,
+                                       u32 iter_flags,
+                                       void (*iterator)(void *data, u8 *mac,
+                                               struct ieee80211_vif *vif),
+                                       void *data)
 {
-       struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
 
-       mutex_lock(&local->iflist_mtx);
-
-       list_for_each_entry(sdata, &local->interfaces, list) {
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_MONITOR:
                        if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
@@ -597,13 +594,25 @@ void ieee80211_iterate_active_interfaces(
                                 &sdata->vif);
        }
 
-       sdata = rcu_dereference_protected(local->monitor_sdata,
-                                         lockdep_is_held(&local->iflist_mtx));
+       sdata = rcu_dereference_check(local->monitor_sdata,
+                                     lockdep_is_held(&local->iflist_mtx) ||
+                                     lockdep_rtnl_is_held());
        if (sdata &&
            (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
             sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                iterator(data, sdata->vif.addr, &sdata->vif);
+}
+
+void ieee80211_iterate_active_interfaces(
+       struct ieee80211_hw *hw, u32 iter_flags,
+       void (*iterator)(void *data, u8 *mac,
+                        struct ieee80211_vif *vif),
+       void *data)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
 
+       mutex_lock(&local->iflist_mtx);
+       __iterate_active_interfaces(local, iter_flags, iterator, data);
        mutex_unlock(&local->iflist_mtx);
 }
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
@@ -615,38 +624,26 @@ void ieee80211_iterate_active_interfaces_atomic(
        void *data)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_sub_if_data *sdata;
 
        rcu_read_lock();
+       __iterate_active_interfaces(local, iter_flags, iterator, data);
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
 
-       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-               switch (sdata->vif.type) {
-               case NL80211_IFTYPE_MONITOR:
-                       if (!(sdata->u.mntr_flags & MONITOR_FLAG_ACTIVE))
-                               continue;
-                       break;
-               case NL80211_IFTYPE_AP_VLAN:
-                       continue;
-               default:
-                       break;
-               }
-               if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
-                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
-                       continue;
-               if (ieee80211_sdata_running(sdata))
-                       iterator(data, sdata->vif.addr,
-                                &sdata->vif);
-       }
+void ieee80211_iterate_active_interfaces_rtnl(
+       struct ieee80211_hw *hw, u32 iter_flags,
+       void (*iterator)(void *data, u8 *mac,
+                        struct ieee80211_vif *vif),
+       void *data)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
 
-       sdata = rcu_dereference(local->monitor_sdata);
-       if (sdata &&
-           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
-            sdata->flags & IEEE80211_SDATA_IN_DRIVER))
-               iterator(data, sdata->vif.addr, &sdata->vif);
+       ASSERT_RTNL();
 
-       rcu_read_unlock();
+       __iterate_active_interfaces(local, iter_flags, iterator, data);
 }
-EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic);
+EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_rtnl);
 
 /*
  * Nothing should have been stuffed into the workqueue during
@@ -1007,14 +1004,21 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
         */
        enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION);
 
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-               /* Set defaults according to 802.11-2007 Table 7-37 */
-               aCWmax = 1023;
-               if (use_11b)
-                       aCWmin = 31;
-               else
-                       aCWmin = 15;
+       /* Set defaults according to 802.11-2007 Table 7-37 */
+       aCWmax = 1023;
+       if (use_11b)
+               aCWmin = 31;
+       else
+               aCWmin = 15;
+
+       /* Confiure old 802.11b/g medium access rules. */
+       qparam.cw_max = aCWmax;
+       qparam.cw_min = aCWmin;
+       qparam.txop = 0;
+       qparam.aifs = 2;
 
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+               /* Update if QoS is enabled. */
                if (enable_qos) {
                        switch (ac) {
                        case IEEE80211_AC_BK:
@@ -1050,12 +1054,6 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
                                qparam.aifs = 2;
                                break;
                        }
-               } else {
-                       /* Confiure old 802.11b/g medium access rules. */
-                       qparam.cw_max = aCWmax;
-                       qparam.cw_min = aCWmin;
-                       qparam.txop = 0;
-                       qparam.aifs = 2;
                }
 
                qparam.uapsd = false;
@@ -1084,8 +1082,8 @@ void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_mgmt *mgmt;
        int err;
 
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           sizeof(*mgmt) + 6 + extra_len);
+       /* 24 + 6 = header + auth_algo + auth_transaction + status_code */
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 6 + extra_len);
        if (!skb)
                return;
 
@@ -2295,3 +2293,63 @@ void ieee80211_radar_detected(struct ieee80211_hw *hw)
        ieee80211_queue_work(hw, &local->radar_detected_work);
 }
 EXPORT_SYMBOL(ieee80211_radar_detected);
+
+u32 ieee80211_chandef_downgrade(struct cfg80211_chan_def *c)
+{
+       u32 ret;
+       int tmp;
+
+       switch (c->width) {
+       case NL80211_CHAN_WIDTH_20:
+               c->width = NL80211_CHAN_WIDTH_20_NOHT;
+               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               break;
+       case NL80211_CHAN_WIDTH_40:
+               c->width = NL80211_CHAN_WIDTH_20;
+               c->center_freq1 = c->chan->center_freq;
+               ret = IEEE80211_STA_DISABLE_40MHZ |
+                     IEEE80211_STA_DISABLE_VHT;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+               tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
+               /* n_P40 */
+               tmp /= 2;
+               /* freq_P40 */
+               c->center_freq1 = c->center_freq1 - 20 + 40 * tmp;
+               c->width = NL80211_CHAN_WIDTH_40;
+               ret = IEEE80211_STA_DISABLE_VHT;
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               c->center_freq2 = 0;
+               c->width = NL80211_CHAN_WIDTH_80;
+               ret = IEEE80211_STA_DISABLE_80P80MHZ |
+                     IEEE80211_STA_DISABLE_160MHZ;
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               /* n_P20 */
+               tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
+               /* n_P80 */
+               tmp /= 4;
+               c->center_freq1 = c->center_freq1 - 40 + 80 * tmp;
+               c->width = NL80211_CHAN_WIDTH_80;
+               ret = IEEE80211_STA_DISABLE_80P80MHZ |
+                     IEEE80211_STA_DISABLE_160MHZ;
+               break;
+       default:
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               WARN_ON_ONCE(1);
+               c->width = NL80211_CHAN_WIDTH_20_NOHT;
+               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               break;
+       case NL80211_CHAN_WIDTH_5:
+       case NL80211_CHAN_WIDTH_10:
+               WARN_ON_ONCE(1);
+               /* keep c->width */
+               ret = IEEE80211_STA_DISABLE_HT | IEEE80211_STA_DISABLE_VHT;
+               break;
+       }
+
+       WARN_ON_ONCE(!cfg80211_chandef_valid(c));
+
+       return ret;
+}
index 97c289414e32a5d989528dd9bba7c8b77ec982bf..de0112785aae19a8b23b2f8f84b364c80d27e8b3 100644 (file)
@@ -185,13 +185,13 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata,
        if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) {
                vht_cap->cap |= cap_info &
                                (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
-                                IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX |
                                 IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX);
        }
 
        if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
                vht_cap->cap |= cap_info &
-                               IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE;
+                               (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+                                IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX);
 
        if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
                vht_cap->cap |= cap_info &
index f7713900798308557c134b00e9db3975e3697ecb..f2e30fb31e78efa405156ca99ba9aeaded3ea49c 100644 (file)
@@ -1052,7 +1052,7 @@ ip_set_swap(struct sock *ctnl, struct sk_buff *skb,
         * Not an artificial restriction anymore, as we must prevent
         * possible loops created by swapping in setlist type of sets. */
        if (!(from->type->features == to->type->features &&
-             from->type->family == to->type->family))
+             from->family == to->family))
                return -IPSET_ERR_TYPE_MISMATCH;
 
        strncpy(from_name, from->name, IPSET_MAXNAMELEN);
@@ -1489,8 +1489,7 @@ ip_set_utest(struct sock *ctnl, struct sk_buff *skb,
        if (ret == -EAGAIN)
                ret = 1;
 
-       return (ret < 0 && ret != -ENOTEMPTY) ? ret :
-               ret > 0 ? 0 : -IPSET_ERR_EXIST;
+       return ret > 0 ? 0 : -IPSET_ERR_EXIST;
 }
 
 /* Get headed data of a set */
index 6fdf88ae2353b67be38c307fd8d4cb114594e624..dac156f819ac2f2fe25c876d800aadd2c47c0752 100644 (file)
@@ -116,12 +116,12 @@ ip_set_get_ip6_port(const struct sk_buff *skb, bool src,
 {
        int protoff;
        u8 nexthdr;
-       __be16 frag_off;
+       __be16 frag_off = 0;
 
        nexthdr = ipv6_hdr(skb)->nexthdr;
        protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr,
                                   &frag_off);
-       if (protoff < 0)
+       if (protoff < 0 || (frag_off & htons(~0x7)) != 0)
                return false;
 
        return get_port(skb, nexthdr, protoff, src, port, proto);
index 57beb1762b2de5f77031d79cd54f5903d246c3f7..707bc520d629f311dd9978d2e0bf222719f71c82 100644 (file)
@@ -325,18 +325,22 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length)
 static void
 mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length)
 {
-       u8 i, j;
-
-       for (i = 0; i < nets_length - 1 && h->nets[i].cidr != cidr; i++)
-               ;
-       h->nets[i].nets--;
-
-       if (h->nets[i].nets != 0)
-               return;
-
-       for (j = i; j < nets_length - 1 && h->nets[j].nets; j++) {
-               h->nets[j].cidr = h->nets[j + 1].cidr;
-               h->nets[j].nets = h->nets[j + 1].nets;
+       u8 i, j, net_end = nets_length - 1;
+
+       for (i = 0; i < nets_length; i++) {
+               if (h->nets[i].cidr != cidr)
+                       continue;
+                if (h->nets[i].nets > 1 || i == net_end ||
+                    h->nets[i + 1].nets == 0) {
+                        h->nets[i].nets--;
+                        return;
+                }
+                for (j = i; j < net_end && h->nets[j].nets; j++) {
+                       h->nets[j].cidr = h->nets[j + 1].cidr;
+                       h->nets[j].nets = h->nets[j + 1].nets;
+                }
+                h->nets[j].nets = 0;
+                return;
        }
 }
 #endif
index c6a525373be4e24bb4de1d056095c5edfe3919c2..f15f3e28b9c338c6e72d3aa949d9d241c0e7cabe 100644 (file)
@@ -260,7 +260,7 @@ hash_ipportnet4_uadt(struct ip_set *set, struct nlattr *tb[],
                e.ip = htonl(ip);
                e.ip2 = htonl(ip2_from & ip_set_hostmask(e.cidr + 1));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -544,7 +544,7 @@ hash_ipportnet6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
index da740ceb56aefc8db240d83d74daf68a631ec975..223e9f546d0fa3e414b7a53a839b56d6835093bb 100644 (file)
@@ -199,7 +199,7 @@ hash_net4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
                e.ip = htonl(ip & ip_set_hostmask(e.cidr));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret:
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -396,7 +396,7 @@ hash_net6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        ret = adtfn(set, &e, &ext, &ext, flags);
 
-       return ip_set_enomatch(ret, flags, adt) ? 1 :
+       return ip_set_enomatch(ret, flags, adt, set) ? -ret :
               ip_set_eexist(ret, flags) ? 0 : ret;
 }
 
index 84ae6f6ce624665f9d2cc27c07efe9033412f132..7d798d5d5cd30a66de3d6fade0b4110eeba583f7 100644 (file)
@@ -368,7 +368,7 @@ hash_netiface4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST || !tb[IPSET_ATTR_IP_TO]) {
                e.ip = htonl(ip & ip_set_hostmask(e.cidr));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -634,7 +634,7 @@ hash_netiface6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        ret = adtfn(set, &e, &ext, &ext, flags);
 
-       return ip_set_enomatch(ret, flags, adt) ? 1 :
+       return ip_set_enomatch(ret, flags, adt, set) ? -ret :
               ip_set_eexist(ret, flags) ? 0 : ret;
 }
 
index 9a0869853be565ca09a7e6c54c9cd205229dd3bf..09d6690bee6fd33891c4a00bbbb909f2bbf7731b 100644 (file)
@@ -244,7 +244,7 @@ hash_netport4_uadt(struct ip_set *set, struct nlattr *tb[],
        if (adt == IPSET_TEST || !(with_ports || tb[IPSET_ATTR_IP_TO])) {
                e.ip = htonl(ip & ip_set_hostmask(e.cidr + 1));
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
@@ -489,7 +489,7 @@ hash_netport6_uadt(struct ip_set *set, struct nlattr *tb[],
 
        if (adt == IPSET_TEST || !with_ports || !tb[IPSET_ATTR_PORT_TO]) {
                ret = adtfn(set, &e, &ext, &ext, flags);
-               return ip_set_enomatch(ret, flags, adt) ? 1 :
+               return ip_set_enomatch(ret, flags, adt, set) ? -ret :
                       ip_set_eexist(ret, flags) ? 0 : ret;
        }
 
index b75ff6429a04e25d4ba8e6368173ab84a342751c..c47444e4cf8ccc9977fa0622689b4fb55799ff4b 100644 (file)
@@ -883,7 +883,7 @@ ip_vs_tunnel_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
        iph->daddr              =       cp->daddr.ip;
        iph->saddr              =       saddr;
        iph->ttl                =       old_iph->ttl;
-       ip_select_ident(iph, &rt->dst, NULL);
+       ip_select_ident(skb, &rt->dst, NULL);
 
        /* Another hack: avoid icmp_send in ip_fragment */
        skb->local_df = 1;
index 95a98c8c1da65be10ea5499aba6291cdf8319fed..ae2e5c11d01ac9887c5158d0084f193c624373ef 100644 (file)
@@ -1009,7 +1009,7 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
                        verdict = NF_DROP;
 
                if (ct)
-                       nfqnl_ct_seq_adjust(skb, ct, ctinfo, diff);
+                       nfqnl_ct_seq_adjust(entry->skb, ct, ctinfo, diff);
        }
 
        if (nfqa[NFQA_MARK])
index fb36f856516112045c767f02a7f561da2a85d086..410db90db73d32493a525a530cd04ad57a92fadf 100644 (file)
@@ -1178,6 +1178,7 @@ static int __parse_flow_nlattrs(const struct nlattr *attr,
                if (type > OVS_KEY_ATTR_MAX) {
                        OVS_NLERR("Unknown key attribute (type=%d, max=%d).\n",
                                  type, OVS_KEY_ATTR_MAX);
+                       return -EINVAL;
                }
 
                if (attrs & (1 << type)) {
index c2178b15ca6e0bb0ed60eb885cc94177fd5b8e95..863846cc5513b5cd136264265d226a811bd868c6 100644 (file)
@@ -1495,7 +1495,7 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
        psched_ratecfg_precompute(&cl->ceil, &hopt->ceil);
 
        cl->buffer = PSCHED_TICKS2NS(hopt->buffer);
-       cl->cbuffer = PSCHED_TICKS2NS(hopt->buffer);
+       cl->cbuffer = PSCHED_TICKS2NS(hopt->cbuffer);
 
        sch_tree_unlock(sch);
 
index 5f2068679f8339b8a85b85cf2dc7b185a663dd9c..98b69bbecdd96eadcbaeb3bdecc210dcca2ab11d 100644 (file)
@@ -634,8 +634,7 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
                break;
        case ICMP_REDIRECT:
                sctp_icmp_redirect(sk, transport, skb);
-               err = 0;
-               break;
+               /* Fall through to out_unlock. */
        default:
                goto out_unlock;
        }
index da613ceae28cc95b38dc1a3d7366c2f38b348d9b..e7b2d4fe2b6a120c66b3e869d796eb6dba69c2d2 100644 (file)
@@ -183,7 +183,7 @@ static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
                break;
        case NDISC_REDIRECT:
                sctp_icmp_redirect(sk, transport, skb);
-               break;
+               goto out_unlock;
        default:
                break;
        }
@@ -204,44 +204,23 @@ out:
                in6_dev_put(idev);
 }
 
-/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
 static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
 {
        struct sock *sk = skb->sk;
        struct ipv6_pinfo *np = inet6_sk(sk);
-       struct flowi6 fl6;
-
-       memset(&fl6, 0, sizeof(fl6));
-
-       fl6.flowi6_proto = sk->sk_protocol;
-
-       /* Fill in the dest address from the route entry passed with the skb
-        * and the source address from the transport.
-        */
-       fl6.daddr = transport->ipaddr.v6.sin6_addr;
-       fl6.saddr = transport->saddr.v6.sin6_addr;
-
-       fl6.flowlabel = np->flow_label;
-       IP6_ECN_flow_xmit(sk, fl6.flowlabel);
-       if (ipv6_addr_type(&fl6.saddr) & IPV6_ADDR_LINKLOCAL)
-               fl6.flowi6_oif = transport->saddr.v6.sin6_scope_id;
-       else
-               fl6.flowi6_oif = sk->sk_bound_dev_if;
-
-       if (np->opt && np->opt->srcrt) {
-               struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-               fl6.daddr = *rt0->addr;
-       }
+       struct flowi6 *fl6 = &transport->fl.u.ip6;
 
        pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
-                skb->len, &fl6.saddr, &fl6.daddr);
+                skb->len, &fl6->saddr, &fl6->daddr);
 
-       SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
+       IP6_ECN_flow_xmit(sk, fl6->flowlabel);
 
        if (!(transport->param_flags & SPP_PMTUD_ENABLE))
                skb->local_df = 1;
 
-       return ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+       SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
+
+       return ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
 }
 
 /* Returns the dst cache entry for the given source and destination ip
@@ -254,10 +233,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
        struct dst_entry *dst = NULL;
        struct flowi6 *fl6 = &fl->u.ip6;
        struct sctp_bind_addr *bp;
+       struct ipv6_pinfo *np = inet6_sk(sk);
        struct sctp_sockaddr_entry *laddr;
        union sctp_addr *baddr = NULL;
        union sctp_addr *daddr = &t->ipaddr;
        union sctp_addr dst_saddr;
+       struct in6_addr *final_p, final;
        __u8 matchlen = 0;
        __u8 bmatchlen;
        sctp_scope_t scope;
@@ -281,7 +262,8 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                pr_debug("src=%pI6 - ", &fl6->saddr);
        }
 
-       dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+       final_p = fl6_update_dst(fl6, np->opt, &final);
+       dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
        if (!asoc || saddr)
                goto out;
 
@@ -333,10 +315,12 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                }
        }
        rcu_read_unlock();
+
        if (baddr) {
                fl6->saddr = baddr->v6.sin6_addr;
                fl6->fl6_sport = baddr->v6.sin6_port;
-               dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
+               final_p = fl6_update_dst(fl6, np->opt, &final);
+               dst = ip6_dst_lookup_flow(sk, fl6, final_p, false);
        }
 
 out:
index d5d5882a2891ac4c1047faa002375ba829598bb5..911b71b26b0e6670bfac1a7f8d450aea510f7333 100644 (file)
@@ -806,6 +806,9 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                        goto skip_mkasconf;
                }
 
+               if (laddr == NULL)
+                       return -EINVAL;
+
                /* We do not need RCU protection throughout this loop
                 * because this is done under a socket lock from the
                 * setsockopt call.
@@ -6176,7 +6179,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
        /* Is there any exceptional events?  */
        if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue))
                mask |= POLLERR |
-                       sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0;
+                       (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0);
        if (sk->sk_shutdown & RCV_SHUTDOWN)
                mask |= POLLRDHUP | POLLIN | POLLRDNORM;
        if (sk->sk_shutdown == SHUTDOWN_MASK)
index b2d7c629eeb9f2de785600ed189080af9be02a3e..ebed4b68f768a1afccea45ea7dc22ef555f3f679 100644 (file)
@@ -854,11 +854,6 @@ int kernel_recvmsg(struct socket *sock, struct msghdr *msg,
 }
 EXPORT_SYMBOL(kernel_recvmsg);
 
-static void sock_aio_dtor(struct kiocb *iocb)
-{
-       kfree(iocb->private);
-}
-
 static ssize_t sock_sendpage(struct file *file, struct page *page,
                             int offset, size_t size, loff_t *ppos, int more)
 {
@@ -889,12 +884,8 @@ static ssize_t sock_splice_read(struct file *file, loff_t *ppos,
 static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
                                         struct sock_iocb *siocb)
 {
-       if (!is_sync_kiocb(iocb)) {
-               siocb = kmalloc(sizeof(*siocb), GFP_KERNEL);
-               if (!siocb)
-                       return NULL;
-               iocb->ki_dtor = sock_aio_dtor;
-       }
+       if (!is_sync_kiocb(iocb))
+               BUG();
 
        siocb->kiocb = iocb;
        iocb->private = siocb;
@@ -931,7 +922,7 @@ static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
        if (pos != 0)
                return -ESPIPE;
 
-       if (iocb->ki_left == 0) /* Match SYS5 behaviour */
+       if (iocb->ki_nbytes == 0)       /* Match SYS5 behaviour */
                return 0;
 
 
@@ -3072,12 +3063,12 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
 
        uifmap32 = &uifr32->ifr_ifru.ifru_map;
        err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name));
-       err |= __get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
-       err |= __get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
-       err |= __get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
-       err |= __get_user(ifr.ifr_map.irq, &uifmap32->irq);
-       err |= __get_user(ifr.ifr_map.dma, &uifmap32->dma);
-       err |= __get_user(ifr.ifr_map.port, &uifmap32->port);
+       err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
+       err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
+       err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
+       err |= get_user(ifr.ifr_map.irq, &uifmap32->irq);
+       err |= get_user(ifr.ifr_map.dma, &uifmap32->dma);
+       err |= get_user(ifr.ifr_map.port, &uifmap32->port);
        if (err)
                return -EFAULT;
 
@@ -3088,12 +3079,12 @@ static int compat_sioc_ifmap(struct net *net, unsigned int cmd,
 
        if (cmd == SIOCGIFMAP && !err) {
                err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name));
-               err |= __put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
-               err |= __put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
-               err |= __put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
-               err |= __put_user(ifr.ifr_map.irq, &uifmap32->irq);
-               err |= __put_user(ifr.ifr_map.dma, &uifmap32->dma);
-               err |= __put_user(ifr.ifr_map.port, &uifmap32->port);
+               err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start);
+               err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end);
+               err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr);
+               err |= put_user(ifr.ifr_map.irq, &uifmap32->irq);
+               err |= put_user(ifr.ifr_map.dma, &uifmap32->dma);
+               err |= put_user(ifr.ifr_map.port, &uifmap32->port);
                if (err)
                        err = -EFAULT;
        }
@@ -3167,25 +3158,25 @@ static int routing_ioctl(struct net *net, struct socket *sock,
                struct in6_rtmsg32 __user *ur6 = argp;
                ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst),
                        3 * sizeof(struct in6_addr));
-               ret |= __get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
-               ret |= __get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
-               ret |= __get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
-               ret |= __get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
-               ret |= __get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
-               ret |= __get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
-               ret |= __get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
+               ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type));
+               ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len));
+               ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len));
+               ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric));
+               ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info));
+               ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags));
+               ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex));
 
                r = (void *) &r6;
        } else { /* ipv4 */
                struct rtentry32 __user *ur4 = argp;
                ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst),
                                        3 * sizeof(struct sockaddr));
-               ret |= __get_user(r4.rt_flags, &(ur4->rt_flags));
-               ret |= __get_user(r4.rt_metric, &(ur4->rt_metric));
-               ret |= __get_user(r4.rt_mtu, &(ur4->rt_mtu));
-               ret |= __get_user(r4.rt_window, &(ur4->rt_window));
-               ret |= __get_user(r4.rt_irtt, &(ur4->rt_irtt));
-               ret |= __get_user(rtdev, &(ur4->rt_dev));
+               ret |= get_user(r4.rt_flags, &(ur4->rt_flags));
+               ret |= get_user(r4.rt_metric, &(ur4->rt_metric));
+               ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu));
+               ret |= get_user(r4.rt_window, &(ur4->rt_window));
+               ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt));
+               ret |= get_user(rtdev, &(ur4->rt_dev));
                if (rtdev) {
                        ret |= copy_from_user(devname, compat_ptr(rtdev), 15);
                        r4.rt_dev = (char __user __force *)devname;
index ed2fdd210c0bac4f5569acbe5da9daa025012cdd..5285ead196c06de33ed55df22404f78c8302bf30 100644 (file)
@@ -250,11 +250,11 @@ rpcauth_list_flavors(rpc_authflavor_t *array, int size)
 EXPORT_SYMBOL_GPL(rpcauth_list_flavors);
 
 struct rpc_auth *
-rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
+rpcauth_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
 {
        struct rpc_auth         *auth;
        const struct rpc_authops *ops;
-       u32                     flavor = pseudoflavor_to_flavor(pseudoflavor);
+       u32                     flavor = pseudoflavor_to_flavor(args->pseudoflavor);
 
        auth = ERR_PTR(-EINVAL);
        if (flavor >= RPC_AUTH_MAXFLAVOR)
@@ -269,7 +269,7 @@ rpcauth_create(rpc_authflavor_t pseudoflavor, struct rpc_clnt *clnt)
                goto out;
        }
        spin_unlock(&rpc_authflavor_lock);
-       auth = ops->create(clnt, pseudoflavor);
+       auth = ops->create(args, clnt);
        module_put(ops->owner);
        if (IS_ERR(auth))
                return auth;
@@ -342,6 +342,27 @@ out_nocache:
 }
 EXPORT_SYMBOL_GPL(rpcauth_init_credcache);
 
+/*
+ * Setup a credential key lifetime timeout notification
+ */
+int
+rpcauth_key_timeout_notify(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+       if (!cred->cr_auth->au_ops->key_timeout)
+               return 0;
+       return cred->cr_auth->au_ops->key_timeout(auth, cred);
+}
+EXPORT_SYMBOL_GPL(rpcauth_key_timeout_notify);
+
+bool
+rpcauth_cred_key_to_expire(struct rpc_cred *cred)
+{
+       if (!cred->cr_ops->crkey_to_expire)
+               return false;
+       return cred->cr_ops->crkey_to_expire(cred);
+}
+EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire);
+
 /*
  * Destroy a list of credentials
  */
@@ -413,12 +434,13 @@ EXPORT_SYMBOL_GPL(rpcauth_destroy_credcache);
 /*
  * Remove stale credentials. Avoid sleeping inside the loop.
  */
-static int
+static long
 rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
 {
        spinlock_t *cache_lock;
        struct rpc_cred *cred, *next;
        unsigned long expired = jiffies - RPC_AUTH_EXPIRY_MORATORIUM;
+       long freed = 0;
 
        list_for_each_entry_safe(cred, next, &cred_unused, cr_lru) {
 
@@ -430,10 +452,11 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
                 */
                if (time_in_range(cred->cr_expire, expired, jiffies) &&
                    test_bit(RPCAUTH_CRED_HASHED, &cred->cr_flags) != 0)
-                       return 0;
+                       break;
 
                list_del_init(&cred->cr_lru);
                number_cred_unused--;
+               freed++;
                if (atomic_read(&cred->cr_count) != 0)
                        continue;
 
@@ -446,29 +469,39 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan)
                }
                spin_unlock(cache_lock);
        }
-       return (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
+       return freed;
 }
 
 /*
  * Run memory cache shrinker.
  */
-static int
-rpcauth_cache_shrinker(struct shrinker *shrink, struct shrink_control *sc)
+static unsigned long
+rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
+
 {
        LIST_HEAD(free);
-       int res;
-       int nr_to_scan = sc->nr_to_scan;
-       gfp_t gfp_mask = sc->gfp_mask;
+       unsigned long freed;
 
-       if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL)
-               return (nr_to_scan == 0) ? 0 : -1;
+       if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL)
+               return SHRINK_STOP;
+
+       /* nothing left, don't come back */
        if (list_empty(&cred_unused))
-               return 0;
+               return SHRINK_STOP;
+
        spin_lock(&rpc_credcache_lock);
-       res = rpcauth_prune_expired(&free, nr_to_scan);
+       freed = rpcauth_prune_expired(&free, sc->nr_to_scan);
        spin_unlock(&rpc_credcache_lock);
        rpcauth_destroy_credlist(&free);
-       return res;
+
+       return freed;
+}
+
+static unsigned long
+rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc)
+
+{
+       return (number_cred_unused / 100) * sysctl_vfs_cache_pressure;
 }
 
 /*
@@ -784,7 +817,8 @@ rpcauth_uptodatecred(struct rpc_task *task)
 }
 
 static struct shrinker rpc_cred_shrinker = {
-       .shrink = rpcauth_cache_shrinker,
+       .count_objects = rpcauth_cache_shrink_count,
+       .scan_objects = rpcauth_cache_shrink_scan,
        .seeks = DEFAULT_SEEKS,
 };
 
index b6badafc6494767c68ae6bf2a5a35ae287707ccf..ed04869b2d4f4f097ea85e8fe899c2ea262a0aca 100644 (file)
@@ -89,6 +89,7 @@ generic_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
        gcred->acred.uid = acred->uid;
        gcred->acred.gid = acred->gid;
        gcred->acred.group_info = acred->group_info;
+       gcred->acred.ac_flags = 0;
        if (gcred->acred.group_info != NULL)
                get_group_info(gcred->acred.group_info);
        gcred->acred.machine_cred = acred->machine_cred;
@@ -182,11 +183,78 @@ void rpc_destroy_generic_auth(void)
        rpcauth_destroy_credcache(&generic_auth);
 }
 
+/*
+ * Test the the current time (now) against the underlying credential key expiry
+ * minus a timeout and setup notification.
+ *
+ * The normal case:
+ * If 'now' is before the key expiry minus RPC_KEY_EXPIRE_TIMEO, set
+ * the RPC_CRED_NOTIFY_TIMEOUT flag to setup the underlying credential
+ * rpc_credops crmatch routine to notify this generic cred when it's key
+ * expiration is within RPC_KEY_EXPIRE_TIMEO, and return 0.
+ *
+ * The error case:
+ * If the underlying cred lookup fails, return -EACCES.
+ *
+ * The 'almost' error case:
+ * If 'now' is within key expiry minus RPC_KEY_EXPIRE_TIMEO, but not within
+ * key expiry minus RPC_KEY_EXPIRE_FAIL, set the RPC_CRED_EXPIRE_SOON bit
+ * on the acred ac_flags and return 0.
+ */
+static int
+generic_key_timeout(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+       struct auth_cred *acred = &container_of(cred, struct generic_cred,
+                                               gc_base)->acred;
+       struct rpc_cred *tcred;
+       int ret = 0;
+
+
+       /* Fast track for non crkey_timeout (no key) underlying credentials */
+       if (test_bit(RPC_CRED_NO_CRKEY_TIMEOUT, &acred->ac_flags))
+               return 0;
+
+       /* Fast track for the normal case */
+       if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags))
+               return 0;
+
+       /* lookup_cred either returns a valid referenced rpc_cred, or PTR_ERR */
+       tcred = auth->au_ops->lookup_cred(auth, acred, 0);
+       if (IS_ERR(tcred))
+               return -EACCES;
+
+       if (!tcred->cr_ops->crkey_timeout) {
+               set_bit(RPC_CRED_NO_CRKEY_TIMEOUT, &acred->ac_flags);
+               ret = 0;
+               goto out_put;
+       }
+
+       /* Test for the almost error case */
+       ret = tcred->cr_ops->crkey_timeout(tcred);
+       if (ret != 0) {
+               set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
+               ret = 0;
+       } else {
+               /* In case underlying cred key has been reset */
+               if (test_and_clear_bit(RPC_CRED_KEY_EXPIRE_SOON,
+                                       &acred->ac_flags))
+                       dprintk("RPC:        UID %d Credential key reset\n",
+                               from_kuid(&init_user_ns, tcred->cr_uid));
+               /* set up fasttrack for the normal case */
+               set_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags);
+       }
+
+out_put:
+       put_rpccred(tcred);
+       return ret;
+}
+
 static const struct rpc_authops generic_auth_ops = {
        .owner = THIS_MODULE,
        .au_name = "Generic",
        .lookup_cred = generic_lookup_cred,
        .crcreate = generic_create_cred,
+       .key_timeout = generic_key_timeout,
 };
 
 static struct rpc_auth generic_auth = {
@@ -194,9 +262,23 @@ static struct rpc_auth generic_auth = {
        .au_count = ATOMIC_INIT(0),
 };
 
+static bool generic_key_to_expire(struct rpc_cred *cred)
+{
+       struct auth_cred *acred = &container_of(cred, struct generic_cred,
+                                               gc_base)->acred;
+       bool ret;
+
+       get_rpccred(cred);
+       ret = test_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
+       put_rpccred(cred);
+
+       return ret;
+}
+
 static const struct rpc_credops generic_credops = {
        .cr_name = "Generic cred",
        .crdestroy = generic_destroy_cred,
        .crbind = generic_bind_cred,
        .crmatch = generic_match,
+       .crkey_to_expire = generic_key_to_expire,
 };
index fc2f78d6a9b46fae51a3ba366bc50c23e9238101..fcac5d14171779a32599e6b4111b75a8e94a15aa 100644 (file)
@@ -51,6 +51,7 @@
 #include <linux/sunrpc/rpc_pipe_fs.h>
 #include <linux/sunrpc/gss_api.h>
 #include <asm/uaccess.h>
+#include <linux/hashtable.h>
 
 #include "../netns.h"
 
@@ -62,6 +63,9 @@ static const struct rpc_credops gss_nullops;
 #define GSS_RETRY_EXPIRED 5
 static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
 
+#define GSS_KEY_EXPIRE_TIMEO 240
+static unsigned int gss_key_expire_timeo = GSS_KEY_EXPIRE_TIMEO;
+
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY       RPCDBG_AUTH
 #endif
@@ -71,19 +75,33 @@ static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
  * using integrity (two 4-byte integers): */
 #define GSS_VERF_SLACK         100
 
+static DEFINE_HASHTABLE(gss_auth_hash_table, 4);
+static DEFINE_SPINLOCK(gss_auth_hash_lock);
+
+struct gss_pipe {
+       struct rpc_pipe_dir_object pdo;
+       struct rpc_pipe *pipe;
+       struct rpc_clnt *clnt;
+       const char *name;
+       struct kref kref;
+};
+
 struct gss_auth {
        struct kref kref;
+       struct hlist_node hash;
        struct rpc_auth rpc_auth;
        struct gss_api_mech *mech;
        enum rpc_gss_svc service;
        struct rpc_clnt *client;
+       struct net *net;
        /*
         * There are two upcall pipes; dentry[1], named "gssd", is used
         * for the new text-based upcall; dentry[0] is named after the
         * mechanism (for example, "krb5") and exists for
         * backwards-compatibility with older gssd's.
         */
-       struct rpc_pipe *pipe[2];
+       struct gss_pipe *gss_pipe[2];
+       const char *target_name;
 };
 
 /* pipe_version >= 0 if and only if someone has a pipe open. */
@@ -294,7 +312,7 @@ static void put_pipe_version(struct net *net)
 static void
 gss_release_msg(struct gss_upcall_msg *gss_msg)
 {
-       struct net *net = rpc_net_ns(gss_msg->auth->client);
+       struct net *net = gss_msg->auth->net;
        if (!atomic_dec_and_test(&gss_msg->count))
                return;
        put_pipe_version(net);
@@ -406,8 +424,8 @@ static void gss_encode_v0_msg(struct gss_upcall_msg *gss_msg)
 }
 
 static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
-                               struct rpc_clnt *clnt,
-                               const char *service_name)
+                               const char *service_name,
+                               const char *target_name)
 {
        struct gss_api_mech *mech = gss_msg->auth->mech;
        char *p = gss_msg->databuf;
@@ -417,8 +435,8 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
                                   mech->gm_name,
                                   from_kuid(&init_user_ns, gss_msg->uid));
        p += gss_msg->msg.len;
-       if (clnt->cl_principal) {
-               len = sprintf(p, "target=%s ", clnt->cl_principal);
+       if (target_name) {
+               len = sprintf(p, "target=%s ", target_name);
                p += len;
                gss_msg->msg.len += len;
        }
@@ -439,21 +457,8 @@ static void gss_encode_v1_msg(struct gss_upcall_msg *gss_msg,
        BUG_ON(gss_msg->msg.len > UPCALL_BUF_LEN);
 }
 
-static void gss_encode_msg(struct gss_upcall_msg *gss_msg,
-                               struct rpc_clnt *clnt,
-                               const char *service_name)
-{
-       struct net *net = rpc_net_ns(clnt);
-       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
-
-       if (sn->pipe_version == 0)
-               gss_encode_v0_msg(gss_msg);
-       else /* pipe_version == 1 */
-               gss_encode_v1_msg(gss_msg, clnt, service_name);
-}
-
 static struct gss_upcall_msg *
-gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt,
+gss_alloc_msg(struct gss_auth *gss_auth,
                kuid_t uid, const char *service_name)
 {
        struct gss_upcall_msg *gss_msg;
@@ -462,31 +467,36 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt,
        gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS);
        if (gss_msg == NULL)
                return ERR_PTR(-ENOMEM);
-       vers = get_pipe_version(rpc_net_ns(clnt));
+       vers = get_pipe_version(gss_auth->net);
        if (vers < 0) {
                kfree(gss_msg);
                return ERR_PTR(vers);
        }
-       gss_msg->pipe = gss_auth->pipe[vers];
+       gss_msg->pipe = gss_auth->gss_pipe[vers]->pipe;
        INIT_LIST_HEAD(&gss_msg->list);
        rpc_init_wait_queue(&gss_msg->rpc_waitqueue, "RPCSEC_GSS upcall waitq");
        init_waitqueue_head(&gss_msg->waitqueue);
        atomic_set(&gss_msg->count, 1);
        gss_msg->uid = uid;
        gss_msg->auth = gss_auth;
-       gss_encode_msg(gss_msg, clnt, service_name);
+       switch (vers) {
+       case 0:
+               gss_encode_v0_msg(gss_msg);
+       default:
+               gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name);
+       };
        return gss_msg;
 }
 
 static struct gss_upcall_msg *
-gss_setup_upcall(struct rpc_clnt *clnt, struct gss_auth *gss_auth, struct rpc_cred *cred)
+gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
 {
        struct gss_cred *gss_cred = container_of(cred,
                        struct gss_cred, gc_base);
        struct gss_upcall_msg *gss_new, *gss_msg;
        kuid_t uid = cred->cr_uid;
 
-       gss_new = gss_alloc_msg(gss_auth, clnt, uid, gss_cred->gc_principal);
+       gss_new = gss_alloc_msg(gss_auth, uid, gss_cred->gc_principal);
        if (IS_ERR(gss_new))
                return gss_new;
        gss_msg = gss_add_msg(gss_new);
@@ -527,7 +537,7 @@ gss_refresh_upcall(struct rpc_task *task)
 
        dprintk("RPC: %5u %s for uid %u\n",
                task->tk_pid, __func__, from_kuid(&init_user_ns, cred->cr_uid));
-       gss_msg = gss_setup_upcall(task->tk_client, gss_auth, cred);
+       gss_msg = gss_setup_upcall(gss_auth, cred);
        if (PTR_ERR(gss_msg) == -EAGAIN) {
                /* XXX: warning on the first, under the assumption we
                 * shouldn't normally hit this case on a refresh. */
@@ -566,7 +576,7 @@ out:
 static inline int
 gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
 {
-       struct net *net = rpc_net_ns(gss_auth->client);
+       struct net *net = gss_auth->net;
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
        struct rpc_pipe *pipe;
        struct rpc_cred *cred = &gss_cred->gc_base;
@@ -583,7 +593,7 @@ retry:
        timeout = 15 * HZ;
        if (!sn->gssd_running)
                timeout = HZ >> 2;
-       gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred);
+       gss_msg = gss_setup_upcall(gss_auth, cred);
        if (PTR_ERR(gss_msg) == -EAGAIN) {
                err = wait_event_interruptible_timeout(pipe_version_waitqueue,
                                sn->pipe_version >= 0, timeout);
@@ -797,83 +807,153 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg *msg)
        }
 }
 
-static void gss_pipes_dentries_destroy(struct rpc_auth *auth)
+static void gss_pipe_dentry_destroy(struct dentry *dir,
+               struct rpc_pipe_dir_object *pdo)
 {
-       struct gss_auth *gss_auth;
+       struct gss_pipe *gss_pipe = pdo->pdo_data;
+       struct rpc_pipe *pipe = gss_pipe->pipe;
 
-       gss_auth = container_of(auth, struct gss_auth, rpc_auth);
-       if (gss_auth->pipe[0]->dentry)
-               rpc_unlink(gss_auth->pipe[0]->dentry);
-       if (gss_auth->pipe[1]->dentry)
-               rpc_unlink(gss_auth->pipe[1]->dentry);
+       if (pipe->dentry != NULL) {
+               rpc_unlink(pipe->dentry);
+               pipe->dentry = NULL;
+       }
 }
 
-static int gss_pipes_dentries_create(struct rpc_auth *auth)
+static int gss_pipe_dentry_create(struct dentry *dir,
+               struct rpc_pipe_dir_object *pdo)
 {
-       int err;
-       struct gss_auth *gss_auth;
-       struct rpc_clnt *clnt;
+       struct gss_pipe *p = pdo->pdo_data;
+       struct dentry *dentry;
 
-       gss_auth = container_of(auth, struct gss_auth, rpc_auth);
-       clnt = gss_auth->client;
-
-       gss_auth->pipe[1]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
-                                                     "gssd",
-                                                     clnt, gss_auth->pipe[1]);
-       if (IS_ERR(gss_auth->pipe[1]->dentry))
-               return PTR_ERR(gss_auth->pipe[1]->dentry);
-       gss_auth->pipe[0]->dentry = rpc_mkpipe_dentry(clnt->cl_dentry,
-                                                     gss_auth->mech->gm_name,
-                                                     clnt, gss_auth->pipe[0]);
-       if (IS_ERR(gss_auth->pipe[0]->dentry)) {
-               err = PTR_ERR(gss_auth->pipe[0]->dentry);
-               goto err_unlink_pipe_1;
-       }
+       dentry = rpc_mkpipe_dentry(dir, p->name, p->clnt, p->pipe);
+       if (IS_ERR(dentry))
+               return PTR_ERR(dentry);
+       p->pipe->dentry = dentry;
        return 0;
+}
 
-err_unlink_pipe_1:
-       rpc_unlink(gss_auth->pipe[1]->dentry);
-       return err;
+static const struct rpc_pipe_dir_object_ops gss_pipe_dir_object_ops = {
+       .create = gss_pipe_dentry_create,
+       .destroy = gss_pipe_dentry_destroy,
+};
+
+static struct gss_pipe *gss_pipe_alloc(struct rpc_clnt *clnt,
+               const char *name,
+               const struct rpc_pipe_ops *upcall_ops)
+{
+       struct gss_pipe *p;
+       int err = -ENOMEM;
+
+       p = kmalloc(sizeof(*p), GFP_KERNEL);
+       if (p == NULL)
+               goto err;
+       p->pipe = rpc_mkpipe_data(upcall_ops, RPC_PIPE_WAIT_FOR_OPEN);
+       if (IS_ERR(p->pipe)) {
+               err = PTR_ERR(p->pipe);
+               goto err_free_gss_pipe;
+       }
+       p->name = name;
+       p->clnt = clnt;
+       kref_init(&p->kref);
+       rpc_init_pipe_dir_object(&p->pdo,
+                       &gss_pipe_dir_object_ops,
+                       p);
+       return p;
+err_free_gss_pipe:
+       kfree(p);
+err:
+       return ERR_PTR(err);
+}
+
+struct gss_alloc_pdo {
+       struct rpc_clnt *clnt;
+       const char *name;
+       const struct rpc_pipe_ops *upcall_ops;
+};
+
+static int gss_pipe_match_pdo(struct rpc_pipe_dir_object *pdo, void *data)
+{
+       struct gss_pipe *gss_pipe;
+       struct gss_alloc_pdo *args = data;
+
+       if (pdo->pdo_ops != &gss_pipe_dir_object_ops)
+               return 0;
+       gss_pipe = container_of(pdo, struct gss_pipe, pdo);
+       if (strcmp(gss_pipe->name, args->name) != 0)
+               return 0;
+       if (!kref_get_unless_zero(&gss_pipe->kref))
+               return 0;
+       return 1;
 }
 
-static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt,
-                                          struct rpc_auth *auth)
+static struct rpc_pipe_dir_object *gss_pipe_alloc_pdo(void *data)
+{
+       struct gss_pipe *gss_pipe;
+       struct gss_alloc_pdo *args = data;
+
+       gss_pipe = gss_pipe_alloc(args->clnt, args->name, args->upcall_ops);
+       if (!IS_ERR(gss_pipe))
+               return &gss_pipe->pdo;
+       return NULL;
+}
+
+static struct gss_pipe *gss_pipe_get(struct rpc_clnt *clnt,
+               const char *name,
+               const struct rpc_pipe_ops *upcall_ops)
 {
        struct net *net = rpc_net_ns(clnt);
-       struct super_block *sb;
+       struct rpc_pipe_dir_object *pdo;
+       struct gss_alloc_pdo args = {
+               .clnt = clnt,
+               .name = name,
+               .upcall_ops = upcall_ops,
+       };
 
-       sb = rpc_get_sb_net(net);
-       if (sb) {
-               if (clnt->cl_dentry)
-                       gss_pipes_dentries_destroy(auth);
-               rpc_put_sb_net(net);
-       }
+       pdo = rpc_find_or_alloc_pipe_dir_object(net,
+                       &clnt->cl_pipedir_objects,
+                       gss_pipe_match_pdo,
+                       gss_pipe_alloc_pdo,
+                       &args);
+       if (pdo != NULL)
+               return container_of(pdo, struct gss_pipe, pdo);
+       return ERR_PTR(-ENOMEM);
 }
 
-static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt,
-                                        struct rpc_auth *auth)
+static void __gss_pipe_free(struct gss_pipe *p)
 {
+       struct rpc_clnt *clnt = p->clnt;
        struct net *net = rpc_net_ns(clnt);
-       struct super_block *sb;
-       int err = 0;
 
-       sb = rpc_get_sb_net(net);
-       if (sb) {
-               if (clnt->cl_dentry)
-                       err = gss_pipes_dentries_create(auth);
-               rpc_put_sb_net(net);
-       }
-       return err;
+       rpc_remove_pipe_dir_object(net,
+                       &clnt->cl_pipedir_objects,
+                       &p->pdo);
+       rpc_destroy_pipe_data(p->pipe);
+       kfree(p);
+}
+
+static void __gss_pipe_release(struct kref *kref)
+{
+       struct gss_pipe *p = container_of(kref, struct gss_pipe, kref);
+
+       __gss_pipe_free(p);
+}
+
+static void gss_pipe_free(struct gss_pipe *p)
+{
+       if (p != NULL)
+               kref_put(&p->kref, __gss_pipe_release);
 }
 
 /*
  * NOTE: we have the opportunity to use different
  * parameters based on the input flavor (which must be a pseudoflavor)
  */
-static struct rpc_auth *
-gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
+static struct gss_auth *
+gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
 {
+       rpc_authflavor_t flavor = args->pseudoflavor;
        struct gss_auth *gss_auth;
+       struct gss_pipe *gss_pipe;
        struct rpc_auth * auth;
        int err = -ENOMEM; /* XXX? */
 
@@ -883,12 +963,20 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
                return ERR_PTR(err);
        if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
                goto out_dec;
+       INIT_HLIST_NODE(&gss_auth->hash);
+       gss_auth->target_name = NULL;
+       if (args->target_name) {
+               gss_auth->target_name = kstrdup(args->target_name, GFP_KERNEL);
+               if (gss_auth->target_name == NULL)
+                       goto err_free;
+       }
        gss_auth->client = clnt;
+       gss_auth->net = get_net(rpc_net_ns(clnt));
        err = -EINVAL;
        gss_auth->mech = gss_mech_get_by_pseudoflavor(flavor);
        if (!gss_auth->mech) {
                dprintk("RPC:       Pseudoflavor %d not found!\n", flavor);
-               goto err_free;
+               goto err_put_net;
        }
        gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor);
        if (gss_auth->service == 0)
@@ -901,42 +989,41 @@ gss_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
        atomic_set(&auth->au_count, 1);
        kref_init(&gss_auth->kref);
 
+       err = rpcauth_init_credcache(auth);
+       if (err)
+               goto err_put_mech;
        /*
         * Note: if we created the old pipe first, then someone who
         * examined the directory at the right moment might conclude
         * that we supported only the old pipe.  So we instead create
         * the new pipe first.
         */
-       gss_auth->pipe[1] = rpc_mkpipe_data(&gss_upcall_ops_v1,
-                                           RPC_PIPE_WAIT_FOR_OPEN);
-       if (IS_ERR(gss_auth->pipe[1])) {
-               err = PTR_ERR(gss_auth->pipe[1]);
-               goto err_put_mech;
+       gss_pipe = gss_pipe_get(clnt, "gssd", &gss_upcall_ops_v1);
+       if (IS_ERR(gss_pipe)) {
+               err = PTR_ERR(gss_pipe);
+               goto err_destroy_credcache;
        }
+       gss_auth->gss_pipe[1] = gss_pipe;
 
-       gss_auth->pipe[0] = rpc_mkpipe_data(&gss_upcall_ops_v0,
-                                           RPC_PIPE_WAIT_FOR_OPEN);
-       if (IS_ERR(gss_auth->pipe[0])) {
-               err = PTR_ERR(gss_auth->pipe[0]);
+       gss_pipe = gss_pipe_get(clnt, gss_auth->mech->gm_name,
+                       &gss_upcall_ops_v0);
+       if (IS_ERR(gss_pipe)) {
+               err = PTR_ERR(gss_pipe);
                goto err_destroy_pipe_1;
        }
-       err = gss_pipes_dentries_create_net(clnt, auth);
-       if (err)
-               goto err_destroy_pipe_0;
-       err = rpcauth_init_credcache(auth);
-       if (err)
-               goto err_unlink_pipes;
+       gss_auth->gss_pipe[0] = gss_pipe;
 
-       return auth;
-err_unlink_pipes:
-       gss_pipes_dentries_destroy_net(clnt, auth);
-err_destroy_pipe_0:
-       rpc_destroy_pipe_data(gss_auth->pipe[0]);
+       return gss_auth;
 err_destroy_pipe_1:
-       rpc_destroy_pipe_data(gss_auth->pipe[1]);
+       gss_pipe_free(gss_auth->gss_pipe[1]);
+err_destroy_credcache:
+       rpcauth_destroy_credcache(auth);
 err_put_mech:
        gss_mech_put(gss_auth->mech);
+err_put_net:
+       put_net(gss_auth->net);
 err_free:
+       kfree(gss_auth->target_name);
        kfree(gss_auth);
 out_dec:
        module_put(THIS_MODULE);
@@ -946,10 +1033,11 @@ out_dec:
 static void
 gss_free(struct gss_auth *gss_auth)
 {
-       gss_pipes_dentries_destroy_net(gss_auth->client, &gss_auth->rpc_auth);
-       rpc_destroy_pipe_data(gss_auth->pipe[0]);
-       rpc_destroy_pipe_data(gss_auth->pipe[1]);
+       gss_pipe_free(gss_auth->gss_pipe[0]);
+       gss_pipe_free(gss_auth->gss_pipe[1]);
        gss_mech_put(gss_auth->mech);
+       put_net(gss_auth->net);
+       kfree(gss_auth->target_name);
 
        kfree(gss_auth);
        module_put(THIS_MODULE);
@@ -966,17 +1054,101 @@ gss_free_callback(struct kref *kref)
 static void
 gss_destroy(struct rpc_auth *auth)
 {
-       struct gss_auth *gss_auth;
+       struct gss_auth *gss_auth = container_of(auth,
+                       struct gss_auth, rpc_auth);
 
        dprintk("RPC:       destroying GSS authenticator %p flavor %d\n",
                        auth, auth->au_flavor);
 
+       if (hash_hashed(&gss_auth->hash)) {
+               spin_lock(&gss_auth_hash_lock);
+               hash_del(&gss_auth->hash);
+               spin_unlock(&gss_auth_hash_lock);
+       }
+
+       gss_pipe_free(gss_auth->gss_pipe[0]);
+       gss_auth->gss_pipe[0] = NULL;
+       gss_pipe_free(gss_auth->gss_pipe[1]);
+       gss_auth->gss_pipe[1] = NULL;
        rpcauth_destroy_credcache(auth);
 
-       gss_auth = container_of(auth, struct gss_auth, rpc_auth);
        kref_put(&gss_auth->kref, gss_free_callback);
 }
 
+static struct gss_auth *
+gss_auth_find_or_add_hashed(struct rpc_auth_create_args *args,
+               struct rpc_clnt *clnt,
+               struct gss_auth *new)
+{
+       struct gss_auth *gss_auth;
+       unsigned long hashval = (unsigned long)clnt;
+
+       spin_lock(&gss_auth_hash_lock);
+       hash_for_each_possible(gss_auth_hash_table,
+                       gss_auth,
+                       hash,
+                       hashval) {
+               if (gss_auth->rpc_auth.au_flavor != args->pseudoflavor)
+                       continue;
+               if (gss_auth->target_name != args->target_name) {
+                       if (gss_auth->target_name == NULL)
+                               continue;
+                       if (args->target_name == NULL)
+                               continue;
+                       if (strcmp(gss_auth->target_name, args->target_name))
+                               continue;
+               }
+               if (!atomic_inc_not_zero(&gss_auth->rpc_auth.au_count))
+                       continue;
+               goto out;
+       }
+       if (new)
+               hash_add(gss_auth_hash_table, &new->hash, hashval);
+       gss_auth = new;
+out:
+       spin_unlock(&gss_auth_hash_lock);
+       return gss_auth;
+}
+
+static struct gss_auth *
+gss_create_hashed(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+{
+       struct gss_auth *gss_auth;
+       struct gss_auth *new;
+
+       gss_auth = gss_auth_find_or_add_hashed(args, clnt, NULL);
+       if (gss_auth != NULL)
+               goto out;
+       new = gss_create_new(args, clnt);
+       if (IS_ERR(new))
+               return new;
+       gss_auth = gss_auth_find_or_add_hashed(args, clnt, new);
+       if (gss_auth != new)
+               gss_destroy(&new->rpc_auth);
+out:
+       return gss_auth;
+}
+
+static struct rpc_auth *
+gss_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
+{
+       struct gss_auth *gss_auth;
+       struct rpc_xprt *xprt = rcu_access_pointer(clnt->cl_xprt);
+
+       while (clnt != clnt->cl_parent) {
+               struct rpc_clnt *parent = clnt->cl_parent;
+               /* Find the original parent for this transport */
+               if (rcu_access_pointer(parent->cl_xprt) != xprt)
+                       break;
+               clnt = parent;
+       }
+
+       gss_auth = gss_create_hashed(args, clnt);
+       if (IS_ERR(gss_auth))
+               return ERR_CAST(gss_auth);
+       return &gss_auth->rpc_auth;
+}
+
 /*
  * gss_destroying_context will cause the RPCSEC_GSS to send a NULL RPC call
  * to the server with the GSS control procedure field set to
@@ -1126,10 +1298,32 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
        return err;
 }
 
+/*
+ * Returns -EACCES if GSS context is NULL or will expire within the
+ * timeout (miliseconds)
+ */
+static int
+gss_key_timeout(struct rpc_cred *rc)
+{
+       struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
+       unsigned long now = jiffies;
+       unsigned long expire;
+
+       if (gss_cred->gc_ctx == NULL)
+               return -EACCES;
+
+       expire = gss_cred->gc_ctx->gc_expiry - (gss_key_expire_timeo * HZ);
+
+       if (time_after(now, expire))
+               return -EACCES;
+       return 0;
+}
+
 static int
 gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
 {
        struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
+       int ret;
 
        if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags))
                goto out;
@@ -1142,11 +1336,26 @@ out:
        if (acred->principal != NULL) {
                if (gss_cred->gc_principal == NULL)
                        return 0;
-               return strcmp(acred->principal, gss_cred->gc_principal) == 0;
+               ret = strcmp(acred->principal, gss_cred->gc_principal) == 0;
+               goto check_expire;
        }
        if (gss_cred->gc_principal != NULL)
                return 0;
-       return uid_eq(rc->cr_uid, acred->uid);
+       ret = uid_eq(rc->cr_uid, acred->uid);
+
+check_expire:
+       if (ret == 0)
+               return ret;
+
+       /* Notify acred users of GSS context expiration timeout */
+       if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags) &&
+           (gss_key_timeout(rc) != 0)) {
+               /* test will now be done from generic cred */
+               test_and_clear_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags);
+               /* tell NFS layer that key will expire soon */
+               set_bit(RPC_CRED_KEY_EXPIRE_SOON, &acred->ac_flags);
+       }
+       return ret;
 }
 
 /*
@@ -1292,6 +1501,7 @@ gss_validate(struct rpc_task *task, __be32 *p)
        struct xdr_netobj mic;
        u32             flav,len;
        u32             maj_stat;
+       __be32          *ret = ERR_PTR(-EIO);
 
        dprintk("RPC: %5u %s\n", task->tk_pid, __func__);
 
@@ -1307,6 +1517,7 @@ gss_validate(struct rpc_task *task, __be32 *p)
        mic.data = (u8 *)p;
        mic.len = len;
 
+       ret = ERR_PTR(-EACCES);
        maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic);
        if (maj_stat == GSS_S_CONTEXT_EXPIRED)
                clear_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags);
@@ -1324,8 +1535,9 @@ gss_validate(struct rpc_task *task, __be32 *p)
        return p + XDR_QUADLEN(len);
 out_bad:
        gss_put_ctx(ctx);
-       dprintk("RPC: %5u %s failed.\n", task->tk_pid, __func__);
-       return NULL;
+       dprintk("RPC: %5u %s failed ret %ld.\n", task->tk_pid, __func__,
+               PTR_ERR(ret));
+       return ret;
 }
 
 static void gss_wrap_req_encode(kxdreproc_t encode, struct rpc_rqst *rqstp,
@@ -1657,8 +1869,6 @@ static const struct rpc_authops authgss_ops = {
        .destroy        = gss_destroy,
        .lookup_cred    = gss_lookup_cred,
        .crcreate       = gss_create_cred,
-       .pipes_create   = gss_pipes_dentries_create,
-       .pipes_destroy  = gss_pipes_dentries_destroy,
        .list_pseudoflavors = gss_mech_list_pseudoflavors,
        .info2flavor    = gss_mech_info2flavor,
        .flavor2info    = gss_mech_flavor2info,
@@ -1675,6 +1885,7 @@ static const struct rpc_credops gss_credops = {
        .crvalidate     = gss_validate,
        .crwrap_req     = gss_wrap_req,
        .crunwrap_resp  = gss_unwrap_resp,
+       .crkey_timeout  = gss_key_timeout,
 };
 
 static const struct rpc_credops gss_nullops = {
@@ -1762,5 +1973,12 @@ module_param_named(expired_cred_retry_delay,
 MODULE_PARM_DESC(expired_cred_retry_delay, "Timeout (in seconds) until "
                "the RPC engine retries an expired credential");
 
+module_param_named(key_expire_timeo,
+                  gss_key_expire_timeo,
+                  uint, 0644);
+MODULE_PARM_DESC(key_expire_timeo, "Time (in seconds) at the end of a "
+               "credential keys lifetime where the NFS layer cleans up "
+               "prior to key expiration");
+
 module_init(init_rpcsec_gss)
 module_exit(exit_rpcsec_gss)
index af7ffd447fee2af42a642c3e608536a8459ecbe5..f1eb0d16666c2750b0001d923fabbd572f2cbe7d 100644 (file)
@@ -213,6 +213,26 @@ static int gssp_call(struct net *net, struct rpc_message *msg)
        return status;
 }
 
+static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context *arg)
+{
+       int i;
+
+       for (i = 0; i < arg->npages && arg->pages[i]; i++)
+               __free_page(arg->pages[i]);
+}
+
+static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context *arg)
+{
+       arg->npages = DIV_ROUND_UP(NGROUPS_MAX * 4, PAGE_SIZE);
+       arg->pages = kzalloc(arg->npages * sizeof(struct page *), GFP_KERNEL);
+       /*
+        * XXX: actual pages are allocated by xdr layer in
+        * xdr_partial_copy_from_skb.
+        */
+       if (!arg->pages)
+               return -ENOMEM;
+       return 0;
+}
 
 /*
  * Public functions
@@ -261,10 +281,16 @@ int gssp_accept_sec_context_upcall(struct net *net,
                arg.context_handle = &ctxh;
        res.output_token->len = GSSX_max_output_token_sz;
 
+       ret = gssp_alloc_receive_pages(&arg);
+       if (ret)
+               return ret;
+
        /* use nfs/ for targ_name ? */
 
        ret = gssp_call(net, &msg);
 
+       gssp_free_receive_pages(&arg);
+
        /* we need to fetch all data even in case of error so
         * that we can free special strctures is they have been allocated */
        data->major_status = res.status.major_status;
index 3c85d1c8a0288db543fdb5cbec9d9ef5bd0f2f22..f0f78c5f1c7d9690bc017db01ddf697d3022a81a 100644 (file)
@@ -166,14 +166,15 @@ static int dummy_dec_opt_array(struct xdr_stream *xdr,
        return 0;
 }
 
-static int get_s32(void **p, void *max, s32 *res)
+static int get_host_u32(struct xdr_stream *xdr, u32 *res)
 {
-       void *base = *p;
-       void *next = (void *)((char *)base + sizeof(s32));
-       if (unlikely(next > max || next < base))
+       __be32 *p;
+
+       p = xdr_inline_decode(xdr, 4);
+       if (!p)
                return -EINVAL;
-       memcpy(res, base, sizeof(s32));
-       *p = next;
+       /* Contents of linux creds are all host-endian: */
+       memcpy(res, p, sizeof(u32));
        return 0;
 }
 
@@ -182,9 +183,9 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
 {
        u32 length;
        __be32 *p;
-       void *q, *end;
-       s32 tmp;
-       int N, i, err;
+       u32 tmp;
+       u32 N;
+       int i, err;
 
        p = xdr_inline_decode(xdr, 4);
        if (unlikely(p == NULL))
@@ -192,33 +193,28 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
 
        length = be32_to_cpup(p);
 
-       /* FIXME: we do not want to use the scratch buffer for this one
-        * may need to use functions that allows us to access an io vector
-        * directly */
-       p = xdr_inline_decode(xdr, length);
-       if (unlikely(p == NULL))
+       if (length > (3 + NGROUPS_MAX) * sizeof(u32))
                return -ENOSPC;
 
-       q = p;
-       end = q + length;
-
        /* uid */
-       err = get_s32(&q, end, &tmp);
+       err = get_host_u32(xdr, &tmp);
        if (err)
                return err;
        creds->cr_uid = make_kuid(&init_user_ns, tmp);
 
        /* gid */
-       err = get_s32(&q, end, &tmp);
+       err = get_host_u32(xdr, &tmp);
        if (err)
                return err;
        creds->cr_gid = make_kgid(&init_user_ns, tmp);
 
        /* number of additional gid's */
-       err = get_s32(&q, end, &tmp);
+       err = get_host_u32(xdr, &tmp);
        if (err)
                return err;
        N = tmp;
+       if ((3 + N) * sizeof(u32) != length)
+               return -EINVAL;
        creds->cr_group_info = groups_alloc(N);
        if (creds->cr_group_info == NULL)
                return -ENOMEM;
@@ -226,7 +222,7 @@ static int gssx_dec_linux_creds(struct xdr_stream *xdr,
        /* gid's */
        for (i = 0; i < N; i++) {
                kgid_t kgid;
-               err = get_s32(&q, end, &tmp);
+               err = get_host_u32(xdr, &tmp);
                if (err)
                        goto out_free_groups;
                err = -EINVAL;
@@ -784,6 +780,9 @@ void gssx_enc_accept_sec_context(struct rpc_rqst *req,
        /* arg->options */
        err = dummy_enc_opt_array(xdr, &arg->options);
 
+       xdr_inline_pages(&req->rq_rcv_buf,
+               PAGE_SIZE/2 /* pretty arbitrary */,
+               arg->pages, 0 /* page base */, arg->npages * PAGE_SIZE);
 done:
        if (err)
                dprintk("RPC:       gssx_enc_accept_sec_context: %d\n", err);
index 1c98b27d870cb7ffaef4ab9fabfea090b3fcd2dc..685a688f3d8aed9ae3eba23d413f3e58520a217f 100644 (file)
@@ -147,6 +147,8 @@ struct gssx_arg_accept_sec_context {
        struct gssx_cb *input_cb;
        u32 ret_deleg_cred;
        struct gssx_option_array options;
+       struct page **pages;
+       unsigned int npages;
 };
 
 struct gssx_res_accept_sec_context {
@@ -240,7 +242,8 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
                             2 * GSSX_max_princ_sz + \
                             8 + 8 + 4 + 4 + 4)
 #define GSSX_max_output_token_sz 1024
-#define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4)
+/* grouplist not included; we allocate separate pages for that: */
+#define GSSX_max_creds_sz (4 + 4 + 4 /* + NGROUPS_MAX*4 */)
 #define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \
                                        GSSX_default_ctx_sz + \
                                        GSSX_max_output_token_sz + \
index a5c36c01707baa3379bd32b29e23d0f5142887a3..f0ebe07978a236e66744bc2dfe332a92bfb85d05 100644 (file)
@@ -18,7 +18,7 @@ static struct rpc_auth null_auth;
 static struct rpc_cred null_cred;
 
 static struct rpc_auth *
-nul_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
+nul_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
 {
        atomic_inc(&null_auth.au_count);
        return &null_auth;
@@ -88,13 +88,13 @@ nul_validate(struct rpc_task *task, __be32 *p)
        flavor = ntohl(*p++);
        if (flavor != RPC_AUTH_NULL) {
                printk("RPC: bad verf flavor: %u\n", flavor);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
 
        size = ntohl(*p++);
        if (size != 0) {
                printk("RPC: bad verf size: %u\n", size);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
 
        return p;
index dc37021fc3e5c96c87a35e902a382562d47bfa02..d5d692366294bacf976ed53fbb83fb1ecbb5ef61 100644 (file)
@@ -33,7 +33,7 @@ static struct rpc_auth                unix_auth;
 static const struct rpc_credops        unix_credops;
 
 static struct rpc_auth *
-unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
+unx_create(struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
 {
        dprintk("RPC:       creating UNIX authenticator for client %p\n",
                        clnt);
@@ -192,13 +192,13 @@ unx_validate(struct rpc_task *task, __be32 *p)
            flavor != RPC_AUTH_UNIX &&
            flavor != RPC_AUTH_SHORT) {
                printk("RPC: bad verf flavor: %u\n", flavor);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
 
        size = ntohl(*p++);
        if (size > RPC_MAX_AUTH_SIZE) {
                printk("RPC: giant verf size: %u\n", size);
-               return NULL;
+               return ERR_PTR(-EIO);
        }
        task->tk_rqstp->rq_cred->cr_auth->au_rslack = (size >> 2) + 2;
        p += (size >> 2);
index ecbc4e3d83ad3f816caa51b6ec942461dac9f090..77479606a9716e9526019ba5e5a0dfa4b7d010a2 100644 (file)
@@ -102,12 +102,7 @@ static void rpc_unregister_client(struct rpc_clnt *clnt)
 
 static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
 {
-       if (clnt->cl_dentry) {
-               if (clnt->cl_auth && clnt->cl_auth->au_ops->pipes_destroy)
-                       clnt->cl_auth->au_ops->pipes_destroy(clnt->cl_auth);
-               rpc_remove_client_dir(clnt->cl_dentry);
-       }
-       clnt->cl_dentry = NULL;
+       rpc_remove_client_dir(clnt);
 }
 
 static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
@@ -123,10 +118,10 @@ static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
 }
 
 static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
-                                   struct rpc_clnt *clnt,
-                                   const char *dir_name)
+                                   struct rpc_clnt *clnt)
 {
        static uint32_t clntid;
+       const char *dir_name = clnt->cl_program->pipe_dir_name;
        char name[15];
        struct dentry *dir, *dentry;
 
@@ -153,28 +148,35 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
 }
 
 static int
-rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name,
-                 struct super_block *pipefs_sb)
+rpc_setup_pipedir(struct super_block *pipefs_sb, struct rpc_clnt *clnt)
 {
        struct dentry *dentry;
 
-       clnt->cl_dentry = NULL;
-       if (dir_name == NULL)
-               return 0;
-       dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-       clnt->cl_dentry = dentry;
+       if (clnt->cl_program->pipe_dir_name != NULL) {
+               dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt);
+               if (IS_ERR(dentry))
+                       return PTR_ERR(dentry);
+       }
        return 0;
 }
 
-static inline int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
+static int rpc_clnt_skip_event(struct rpc_clnt *clnt, unsigned long event)
 {
-       if (((event == RPC_PIPEFS_MOUNT) && clnt->cl_dentry) ||
-           ((event == RPC_PIPEFS_UMOUNT) && !clnt->cl_dentry))
-               return 1;
-       if ((event == RPC_PIPEFS_MOUNT) && atomic_read(&clnt->cl_count) == 0)
+       if (clnt->cl_program->pipe_dir_name == NULL)
                return 1;
+
+       switch (event) {
+       case RPC_PIPEFS_MOUNT:
+               if (clnt->cl_pipedir_objects.pdh_dentry != NULL)
+                       return 1;
+               if (atomic_read(&clnt->cl_count) == 0)
+                       return 1;
+               break;
+       case RPC_PIPEFS_UMOUNT:
+               if (clnt->cl_pipedir_objects.pdh_dentry == NULL)
+                       return 1;
+               break;
+       }
        return 0;
 }
 
@@ -186,18 +188,11 @@ static int __rpc_clnt_handle_event(struct rpc_clnt *clnt, unsigned long event,
 
        switch (event) {
        case RPC_PIPEFS_MOUNT:
-               dentry = rpc_setup_pipedir_sb(sb, clnt,
-                                             clnt->cl_program->pipe_dir_name);
+               dentry = rpc_setup_pipedir_sb(sb, clnt);
                if (!dentry)
                        return -ENOENT;
                if (IS_ERR(dentry))
                        return PTR_ERR(dentry);
-               clnt->cl_dentry = dentry;
-               if (clnt->cl_auth->au_ops->pipes_create) {
-                       err = clnt->cl_auth->au_ops->pipes_create(clnt->cl_auth);
-                       if (err)
-                               __rpc_clnt_remove_pipedir(clnt);
-               }
                break;
        case RPC_PIPEFS_UMOUNT:
                __rpc_clnt_remove_pipedir(clnt);
@@ -230,8 +225,6 @@ static struct rpc_clnt *rpc_get_client_for_event(struct net *net, int event)
 
        spin_lock(&sn->rpc_client_lock);
        list_for_each_entry(clnt, &sn->all_clients, cl_clients) {
-               if (clnt->cl_program->pipe_dir_name == NULL)
-                       continue;
                if (rpc_clnt_skip_event(clnt, event))
                        continue;
                spin_unlock(&sn->rpc_client_lock);
@@ -282,7 +275,10 @@ static void rpc_clnt_set_nodename(struct rpc_clnt *clnt, const char *nodename)
 static int rpc_client_register(const struct rpc_create_args *args,
                               struct rpc_clnt *clnt)
 {
-       const struct rpc_program *program = args->program;
+       struct rpc_auth_create_args auth_args = {
+               .pseudoflavor = args->authflavor,
+               .target_name = args->client_name,
+       };
        struct rpc_auth *auth;
        struct net *net = rpc_net_ns(clnt);
        struct super_block *pipefs_sb;
@@ -290,7 +286,7 @@ static int rpc_client_register(const struct rpc_create_args *args,
 
        pipefs_sb = rpc_get_sb_net(net);
        if (pipefs_sb) {
-               err = rpc_setup_pipedir(clnt, program->pipe_dir_name, pipefs_sb);
+               err = rpc_setup_pipedir(pipefs_sb, clnt);
                if (err)
                        goto out;
        }
@@ -299,7 +295,7 @@ static int rpc_client_register(const struct rpc_create_args *args,
        if (pipefs_sb)
                rpc_put_sb_net(net);
 
-       auth = rpcauth_create(args->authflavor, clnt);
+       auth = rpcauth_create(&auth_args, clnt);
        if (IS_ERR(auth)) {
                dprintk("RPC:       Couldn't create auth handle (flavor %u)\n",
                                args->authflavor);
@@ -317,7 +313,27 @@ out:
        return err;
 }
 
-static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, struct rpc_xprt *xprt)
+static DEFINE_IDA(rpc_clids);
+
+static int rpc_alloc_clid(struct rpc_clnt *clnt)
+{
+       int clid;
+
+       clid = ida_simple_get(&rpc_clids, 0, 0, GFP_KERNEL);
+       if (clid < 0)
+               return clid;
+       clnt->cl_clid = clid;
+       return 0;
+}
+
+static void rpc_free_clid(struct rpc_clnt *clnt)
+{
+       ida_simple_remove(&rpc_clids, clnt->cl_clid);
+}
+
+static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args,
+               struct rpc_xprt *xprt,
+               struct rpc_clnt *parent)
 {
        const struct rpc_program *program = args->program;
        const struct rpc_version *version;
@@ -343,16 +359,20 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        clnt = kzalloc(sizeof(*clnt), GFP_KERNEL);
        if (!clnt)
                goto out_err;
-       clnt->cl_parent = clnt;
+       clnt->cl_parent = parent ? : clnt;
+
+       err = rpc_alloc_clid(clnt);
+       if (err)
+               goto out_no_clid;
 
        rcu_assign_pointer(clnt->cl_xprt, xprt);
        clnt->cl_procinfo = version->procs;
        clnt->cl_maxproc  = version->nrprocs;
-       clnt->cl_protname = program->name;
        clnt->cl_prog     = args->prognumber ? : program->number;
        clnt->cl_vers     = version->number;
        clnt->cl_stats    = program->stats;
        clnt->cl_metrics  = rpc_alloc_iostats(clnt);
+       rpc_init_pipe_dir_head(&clnt->cl_pipedir_objects);
        err = -ENOMEM;
        if (clnt->cl_metrics == NULL)
                goto out_no_stats;
@@ -372,12 +392,6 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
 
        clnt->cl_rtt = &clnt->cl_rtt_default;
        rpc_init_rtt(&clnt->cl_rtt_default, clnt->cl_timeout->to_initval);
-       clnt->cl_principal = NULL;
-       if (args->client_name) {
-               clnt->cl_principal = kstrdup(args->client_name, GFP_KERNEL);
-               if (!clnt->cl_principal)
-                       goto out_no_principal;
-       }
 
        atomic_set(&clnt->cl_count, 1);
 
@@ -387,13 +401,15 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
        err = rpc_client_register(args, clnt);
        if (err)
                goto out_no_path;
+       if (parent)
+               atomic_inc(&parent->cl_count);
        return clnt;
 
 out_no_path:
-       kfree(clnt->cl_principal);
-out_no_principal:
        rpc_free_iostats(clnt->cl_metrics);
 out_no_stats:
+       rpc_free_clid(clnt);
+out_no_clid:
        kfree(clnt);
 out_err:
        rpciod_down();
@@ -479,7 +495,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
                xprt->resvport = 0;
 
-       clnt = rpc_new_client(args, xprt);
+       clnt = rpc_new_client(args, xprt, NULL);
        if (IS_ERR(clnt))
                return clnt;
 
@@ -526,15 +542,12 @@ static struct rpc_clnt *__rpc_clone_client(struct rpc_create_args *args,
                goto out_err;
        args->servername = xprt->servername;
 
-       new = rpc_new_client(args, xprt);
+       new = rpc_new_client(args, xprt, clnt);
        if (IS_ERR(new)) {
                err = PTR_ERR(new);
                goto out_err;
        }
 
-       atomic_inc(&clnt->cl_count);
-       new->cl_parent = clnt;
-
        /* Turn off autobind on clones */
        new->cl_autobind = 0;
        new->cl_softrtry = clnt->cl_softrtry;
@@ -561,7 +574,6 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *clnt)
                .prognumber     = clnt->cl_prog,
                .version        = clnt->cl_vers,
                .authflavor     = clnt->cl_auth->au_flavor,
-               .client_name    = clnt->cl_principal,
        };
        return __rpc_clone_client(&args, clnt);
 }
@@ -583,7 +595,6 @@ rpc_clone_client_set_auth(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
                .prognumber     = clnt->cl_prog,
                .version        = clnt->cl_vers,
                .authflavor     = flavor,
-               .client_name    = clnt->cl_principal,
        };
        return __rpc_clone_client(&args, clnt);
 }
@@ -629,7 +640,7 @@ void rpc_shutdown_client(struct rpc_clnt *clnt)
        might_sleep();
 
        dprintk_rcu("RPC:       shutting down %s client for %s\n",
-                       clnt->cl_protname,
+                       clnt->cl_program->name,
                        rcu_dereference(clnt->cl_xprt)->servername);
 
        while (!list_empty(&clnt->cl_tasks)) {
@@ -649,17 +660,17 @@ static void
 rpc_free_client(struct rpc_clnt *clnt)
 {
        dprintk_rcu("RPC:       destroying %s client for %s\n",
-                       clnt->cl_protname,
+                       clnt->cl_program->name,
                        rcu_dereference(clnt->cl_xprt)->servername);
        if (clnt->cl_parent != clnt)
                rpc_release_client(clnt->cl_parent);
        rpc_clnt_remove_pipedir(clnt);
        rpc_unregister_client(clnt);
        rpc_free_iostats(clnt->cl_metrics);
-       kfree(clnt->cl_principal);
        clnt->cl_metrics = NULL;
        xprt_put(rcu_dereference_raw(clnt->cl_xprt));
        rpciod_down();
+       rpc_free_clid(clnt);
        kfree(clnt);
 }
 
@@ -720,7 +731,6 @@ struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *old,
                .prognumber     = program->number,
                .version        = vers,
                .authflavor     = old->cl_auth->au_flavor,
-               .client_name    = old->cl_principal,
        };
        struct rpc_clnt *clnt;
        int err;
@@ -1299,7 +1309,7 @@ call_start(struct rpc_task *task)
        struct rpc_clnt *clnt = task->tk_client;
 
        dprintk("RPC: %5u call_start %s%d proc %s (%s)\n", task->tk_pid,
-                       clnt->cl_protname, clnt->cl_vers,
+                       clnt->cl_program->name, clnt->cl_vers,
                        rpc_proc_name(task),
                        (RPC_IS_ASYNC(task) ? "async" : "sync"));
 
@@ -1423,9 +1433,9 @@ call_refreshresult(struct rpc_task *task)
                return;
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
-       case -EKEYEXPIRED:
        case -EAGAIN:
                status = -EACCES;
+       case -EKEYEXPIRED:
                if (!task->tk_cred_retry)
                        break;
                task->tk_cred_retry--;
@@ -1912,7 +1922,7 @@ call_status(struct rpc_task *task)
        default:
                if (clnt->cl_chatty)
                        printk("%s: RPC call returned error %d\n",
-                              clnt->cl_protname, -status);
+                              clnt->cl_program->name, -status);
                rpc_exit(task, status);
        }
 }
@@ -1943,7 +1953,7 @@ call_timeout(struct rpc_task *task)
                if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
-                               clnt->cl_protname,
+                               clnt->cl_program->name,
                                rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
                }
@@ -1959,7 +1969,7 @@ call_timeout(struct rpc_task *task)
                if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
-                       clnt->cl_protname,
+                       clnt->cl_program->name,
                        rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
                }
@@ -1994,7 +2004,7 @@ call_decode(struct rpc_task *task)
                if (clnt->cl_chatty) {
                        rcu_read_lock();
                        printk(KERN_NOTICE "%s: server %s OK\n",
-                               clnt->cl_protname,
+                               clnt->cl_program->name,
                                rcu_dereference(clnt->cl_xprt)->servername);
                        rcu_read_unlock();
                }
@@ -2019,7 +2029,7 @@ call_decode(struct rpc_task *task)
                        goto out_retry;
                }
                dprintk("RPC:       %s: too small RPC reply size (%d bytes)\n",
-                               clnt->cl_protname, task->tk_status);
+                               clnt->cl_program->name, task->tk_status);
                task->tk_action = call_timeout;
                goto out_retry;
        }
@@ -2091,7 +2101,8 @@ rpc_verify_header(struct rpc_task *task)
                dprintk("RPC: %5u %s: XDR representation not a multiple of"
                       " 4 bytes: 0x%x\n", task->tk_pid, __func__,
                       task->tk_rqstp->rq_rcv_buf.len);
-               goto out_eio;
+               error = -EIO;
+               goto out_err;
        }
        if ((len -= 3) < 0)
                goto out_overflow;
@@ -2100,6 +2111,7 @@ rpc_verify_header(struct rpc_task *task)
        if ((n = ntohl(*p++)) != RPC_REPLY) {
                dprintk("RPC: %5u %s: not an RPC reply: %x\n",
                        task->tk_pid, __func__, n);
+               error = -EIO;
                goto out_garbage;
        }
 
@@ -2118,7 +2130,8 @@ rpc_verify_header(struct rpc_task *task)
                        dprintk("RPC: %5u %s: RPC call rejected, "
                                "unknown error: %x\n",
                                task->tk_pid, __func__, n);
-                       goto out_eio;
+                       error = -EIO;
+                       goto out_err;
                }
                if (--len < 0)
                        goto out_overflow;
@@ -2163,9 +2176,11 @@ rpc_verify_header(struct rpc_task *task)
                                task->tk_pid, __func__, n);
                goto out_err;
        }
-       if (!(p = rpcauth_checkverf(task, p))) {
-               dprintk("RPC: %5u %s: auth check failed\n",
-                               task->tk_pid, __func__);
+       p = rpcauth_checkverf(task, p);
+       if (IS_ERR(p)) {
+               error = PTR_ERR(p);
+               dprintk("RPC: %5u %s: auth check failed with %d\n",
+                               task->tk_pid, __func__, error);
                goto out_garbage;               /* bad verifier, retry */
        }
        len = p - (__be32 *)iov->iov_base - 1;
@@ -2218,8 +2233,6 @@ out_garbage:
 out_retry:
                return ERR_PTR(-EAGAIN);
        }
-out_eio:
-       error = -EIO;
 out_err:
        rpc_exit(task, error);
        dprintk("RPC: %5u %s: call failed with error %d\n", task->tk_pid,
@@ -2291,7 +2304,7 @@ static void rpc_show_task(const struct rpc_clnt *clnt,
        printk(KERN_INFO "%5u %04x %6d %8p %8p %8ld %8p %sv%u %s a:%ps q:%s\n",
                task->tk_pid, task->tk_flags, task->tk_status,
                clnt, task->tk_rqstp, task->tk_timeout, task->tk_ops,
-               clnt->cl_protname, clnt->cl_vers, rpc_proc_name(task),
+               clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
                task->tk_action, rpc_waitq);
 }
 
index 406859cc68aa90073ef237e91e0aa67116adcf33..f94567b45bb3eb9f4f8b0ec82db4ee08a304c48b 100644 (file)
@@ -409,7 +409,7 @@ rpc_show_info(struct seq_file *m, void *v)
        rcu_read_lock();
        seq_printf(m, "RPC server: %s\n",
                        rcu_dereference(clnt->cl_xprt)->servername);
-       seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
+       seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_program->name,
                        clnt->cl_prog, clnt->cl_vers);
        seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
        seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
@@ -480,23 +480,6 @@ static const struct dentry_operations rpc_dentry_operations = {
        .d_delete = rpc_delete_dentry,
 };
 
-/*
- * Lookup the data. This is trivial - if the dentry didn't already
- * exist, we know it is negative.
- */
-static struct dentry *
-rpc_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
-{
-       if (dentry->d_name.len > NAME_MAX)
-               return ERR_PTR(-ENAMETOOLONG);
-       d_add(dentry, NULL);
-       return NULL;
-}
-
-static const struct inode_operations rpc_dir_inode_operations = {
-       .lookup         = rpc_lookup,
-};
-
 static struct inode *
 rpc_get_inode(struct super_block *sb, umode_t mode)
 {
@@ -509,7 +492,7 @@ rpc_get_inode(struct super_block *sb, umode_t mode)
        switch (mode & S_IFMT) {
        case S_IFDIR:
                inode->i_fop = &simple_dir_operations;
-               inode->i_op = &rpc_dir_inode_operations;
+               inode->i_op = &simple_dir_inode_operations;
                inc_nlink(inode);
        default:
                break;
@@ -901,6 +884,159 @@ rpc_unlink(struct dentry *dentry)
 }
 EXPORT_SYMBOL_GPL(rpc_unlink);
 
+/**
+ * rpc_init_pipe_dir_head - initialise a struct rpc_pipe_dir_head
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ */
+void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh)
+{
+       INIT_LIST_HEAD(&pdh->pdh_entries);
+       pdh->pdh_dentry = NULL;
+}
+EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_head);
+
+/**
+ * rpc_init_pipe_dir_object - initialise a struct rpc_pipe_dir_object
+ * @pdo: pointer to struct rpc_pipe_dir_object
+ * @pdo_ops: pointer to const struct rpc_pipe_dir_object_ops
+ * @pdo_data: pointer to caller-defined data
+ */
+void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo,
+               const struct rpc_pipe_dir_object_ops *pdo_ops,
+               void *pdo_data)
+{
+       INIT_LIST_HEAD(&pdo->pdo_head);
+       pdo->pdo_ops = pdo_ops;
+       pdo->pdo_data = pdo_data;
+}
+EXPORT_SYMBOL_GPL(rpc_init_pipe_dir_object);
+
+static int
+rpc_add_pipe_dir_object_locked(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       int ret = 0;
+
+       if (pdh->pdh_dentry)
+               ret = pdo->pdo_ops->create(pdh->pdh_dentry, pdo);
+       if (ret == 0)
+               list_add_tail(&pdo->pdo_head, &pdh->pdh_entries);
+       return ret;
+}
+
+static void
+rpc_remove_pipe_dir_object_locked(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       if (pdh->pdh_dentry)
+               pdo->pdo_ops->destroy(pdh->pdh_dentry, pdo);
+       list_del_init(&pdo->pdo_head);
+}
+
+/**
+ * rpc_add_pipe_dir_object - associate a rpc_pipe_dir_object to a directory
+ * @net: pointer to struct net
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ * @pdo: pointer to struct rpc_pipe_dir_object
+ *
+ */
+int
+rpc_add_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       int ret = 0;
+
+       if (list_empty(&pdo->pdo_head)) {
+               struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+               mutex_lock(&sn->pipefs_sb_lock);
+               ret = rpc_add_pipe_dir_object_locked(net, pdh, pdo);
+               mutex_unlock(&sn->pipefs_sb_lock);
+       }
+       return ret;
+}
+EXPORT_SYMBOL_GPL(rpc_add_pipe_dir_object);
+
+/**
+ * rpc_remove_pipe_dir_object - remove a rpc_pipe_dir_object from a directory
+ * @net: pointer to struct net
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ * @pdo: pointer to struct rpc_pipe_dir_object
+ *
+ */
+void
+rpc_remove_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               struct rpc_pipe_dir_object *pdo)
+{
+       if (!list_empty(&pdo->pdo_head)) {
+               struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+               mutex_lock(&sn->pipefs_sb_lock);
+               rpc_remove_pipe_dir_object_locked(net, pdh, pdo);
+               mutex_unlock(&sn->pipefs_sb_lock);
+       }
+}
+EXPORT_SYMBOL_GPL(rpc_remove_pipe_dir_object);
+
+/**
+ * rpc_find_or_alloc_pipe_dir_object
+ * @net: pointer to struct net
+ * @pdh: pointer to struct rpc_pipe_dir_head
+ * @match: match struct rpc_pipe_dir_object to data
+ * @alloc: allocate a new struct rpc_pipe_dir_object
+ * @data: user defined data for match() and alloc()
+ *
+ */
+struct rpc_pipe_dir_object *
+rpc_find_or_alloc_pipe_dir_object(struct net *net,
+               struct rpc_pipe_dir_head *pdh,
+               int (*match)(struct rpc_pipe_dir_object *, void *),
+               struct rpc_pipe_dir_object *(*alloc)(void *),
+               void *data)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct rpc_pipe_dir_object *pdo;
+
+       mutex_lock(&sn->pipefs_sb_lock);
+       list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head) {
+               if (!match(pdo, data))
+                       continue;
+               goto out;
+       }
+       pdo = alloc(data);
+       if (!pdo)
+               goto out;
+       rpc_add_pipe_dir_object_locked(net, pdh, pdo);
+out:
+       mutex_unlock(&sn->pipefs_sb_lock);
+       return pdo;
+}
+EXPORT_SYMBOL_GPL(rpc_find_or_alloc_pipe_dir_object);
+
+static void
+rpc_create_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
+{
+       struct rpc_pipe_dir_object *pdo;
+       struct dentry *dir = pdh->pdh_dentry;
+
+       list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
+               pdo->pdo_ops->create(dir, pdo);
+}
+
+static void
+rpc_destroy_pipe_dir_objects(struct rpc_pipe_dir_head *pdh)
+{
+       struct rpc_pipe_dir_object *pdo;
+       struct dentry *dir = pdh->pdh_dentry;
+
+       list_for_each_entry(pdo, &pdh->pdh_entries, pdo_head)
+               pdo->pdo_ops->destroy(dir, pdo);
+}
+
 enum {
        RPCAUTH_info,
        RPCAUTH_EOF
@@ -941,16 +1077,29 @@ struct dentry *rpc_create_client_dir(struct dentry *dentry,
                                   const char *name,
                                   struct rpc_clnt *rpc_client)
 {
-       return rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
+       struct dentry *ret;
+
+       ret = rpc_mkdir_populate(dentry, name, S_IRUGO | S_IXUGO, NULL,
                        rpc_clntdir_populate, rpc_client);
+       if (!IS_ERR(ret)) {
+               rpc_client->cl_pipedir_objects.pdh_dentry = ret;
+               rpc_create_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
+       }
+       return ret;
 }
 
 /**
  * rpc_remove_client_dir - Remove a directory created with rpc_create_client_dir()
- * @dentry: dentry for the pipe
+ * @rpc_client: rpc_client for the pipe
  */
-int rpc_remove_client_dir(struct dentry *dentry)
+int rpc_remove_client_dir(struct rpc_clnt *rpc_client)
 {
+       struct dentry *dentry = rpc_client->cl_pipedir_objects.pdh_dentry;
+
+       if (dentry == NULL)
+               return 0;
+       rpc_destroy_pipe_dir_objects(&rpc_client->cl_pipedir_objects);
+       rpc_client->cl_pipedir_objects.pdh_dentry = NULL;
        return rpc_rmdir_depopulate(dentry, rpc_clntdir_depopulate);
 }
 
index 93a7a4e94d80abcd423215e2102d510af7331fe9..ff3cc4bf4b24bc868088a67dd9ad92d40e42f066 100644 (file)
@@ -258,7 +258,7 @@ static int rpc_wait_bit_killable(void *word)
        return 0;
 }
 
-#ifdef RPC_DEBUG
+#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
 static void rpc_task_set_debuginfo(struct rpc_task *task)
 {
        static atomic_t rpc_pid;
index 21b75cb08c039285100134281bbe8cbc7749b09a..54530490944e8a9bbb49e12e1d620f183b0e012d 100644 (file)
@@ -188,7 +188,7 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
 
        seq_printf(seq, "\tRPC iostats version: %s  ", RPC_IOSTATS_VERS);
        seq_printf(seq, "p/v: %u/%u (%s)\n",
-                       clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
+                       clnt->cl_prog, clnt->cl_vers, clnt->cl_program->name);
 
        rcu_read_lock();
        xprt = rcu_dereference(clnt->cl_xprt);
index d6656d7768f4e689e94aca67189a0634bd950fad..ee03d35677d962a3385d8d01a31968b70fa77b56 100644 (file)
@@ -47,6 +47,8 @@
 #include <net/udp.h>
 #include <net/tcp.h>
 
+#include <trace/events/sunrpc.h>
+
 #include "sunrpc.h"
 
 static void xs_close(struct rpc_xprt *xprt);
@@ -665,8 +667,10 @@ static void xs_tcp_shutdown(struct rpc_xprt *xprt)
        struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
        struct socket *sock = transport->sock;
 
-       if (sock != NULL)
+       if (sock != NULL) {
                kernel_sock_shutdown(sock, SHUT_WR);
+               trace_rpc_socket_shutdown(xprt, sock);
+       }
 }
 
 /**
@@ -811,6 +815,7 @@ static void xs_reset_transport(struct sock_xprt *transport)
 
        sk->sk_no_check = 0;
 
+       trace_rpc_socket_close(&transport->xprt, sock);
        sock_release(sock);
 }
 
@@ -1492,6 +1497,7 @@ static void xs_tcp_state_change(struct sock *sk)
                        sock_flag(sk, SOCK_ZAPPED),
                        sk->sk_shutdown);
 
+       trace_rpc_socket_state_change(xprt, sk->sk_socket);
        switch (sk->sk_state) {
        case TCP_ESTABLISHED:
                spin_lock(&xprt->transport_lock);
@@ -1896,6 +1902,7 @@ static int xs_local_setup_socket(struct sock_xprt *transport)
                        xprt, xprt->address_strings[RPC_DISPLAY_ADDR]);
 
        status = xs_local_finish_connecting(xprt, sock);
+       trace_rpc_socket_connect(xprt, sock, status);
        switch (status) {
        case 0:
                dprintk("RPC:       xprt %p connected to %s\n",
@@ -2039,6 +2046,7 @@ static void xs_udp_setup_socket(struct work_struct *work)
                        xprt->address_strings[RPC_DISPLAY_PORT]);
 
        xs_udp_finish_connecting(xprt, sock);
+       trace_rpc_socket_connect(xprt, sock, 0);
        status = 0;
 out:
        xprt_clear_connecting(xprt);
@@ -2064,6 +2072,8 @@ static void xs_abort_connection(struct sock_xprt *transport)
        memset(&any, 0, sizeof(any));
        any.sa_family = AF_UNSPEC;
        result = kernel_connect(transport->sock, &any, sizeof(any), 0);
+       trace_rpc_socket_reset_connection(&transport->xprt,
+                       transport->sock, result);
        if (!result)
                xs_sock_reset_connection_flags(&transport->xprt);
        dprintk("RPC:       AF_UNSPEC connect return code %d\n", result);
@@ -2194,6 +2204,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
                        xprt->address_strings[RPC_DISPLAY_PORT]);
 
        status = xs_tcp_finish_connecting(xprt, sock);
+       trace_rpc_socket_connect(xprt, sock, status);
        dprintk("RPC:       %p connect status %d connected %d sock state %d\n",
                        xprt, -status, xprt_connected(xprt),
                        sock->sk->sk_state);
index 50f6195c8b70b816ab35ade4075c5f71de105b35..16f3c3a7b2c17747230f62d1318ed152490eac34 100644 (file)
@@ -328,6 +328,7 @@ int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
        return cfg80211_get_chans_dfs_required(wiphy, chandef->center_freq2,
                                               width);
 }
+EXPORT_SYMBOL(cfg80211_chandef_dfs_required);
 
 static bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
                                        u32 center_freq, u32 bandwidth,
index 9ad43c619c54830f915193daa60eadef92b5bda5..b43efac4efca786d3078c45220747e88eea168e2 100644 (file)
@@ -382,15 +382,6 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev,
                                 enum cfg80211_chan_mode chanmode,
                                 u8 radar_detect);
 
-/**
- * cfg80211_chandef_dfs_required - checks if radar detection is required
- * @wiphy: the wiphy to validate against
- * @chandef: the channel definition to check
- * Return: 1 if radar detection is required, 0 if it is not, < 0 on error
- */
-int cfg80211_chandef_dfs_required(struct wiphy *wiphy,
-                                 const struct cfg80211_chan_def *c);
-
 void cfg80211_set_dfs_state(struct wiphy *wiphy,
                            const struct cfg80211_chan_def *chandef,
                            enum nl80211_dfs_state dfs_state);
index 90d0500366248900f2aebcac8d57f295d229d764..454157717efaf8654cae9cdee39e827381dd20c3 100644 (file)
@@ -47,17 +47,19 @@ static int ht_print_chan(struct ieee80211_channel *chan,
                return 0;
 
        if (chan->flags & IEEE80211_CHAN_DISABLED)
-               return snprintf(buf + offset,
-                               buf_size - offset,
-                               "%d Disabled\n",
-                               chan->center_freq);
-
-       return snprintf(buf + offset,
-                       buf_size - offset,
-                       "%d HT40 %c%c\n",
-                       chan->center_freq,
-                       (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ? ' ' : '-',
-                       (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)  ? ' ' : '+');
+               return scnprintf(buf + offset,
+                                buf_size - offset,
+                                "%d Disabled\n",
+                                chan->center_freq);
+
+       return scnprintf(buf + offset,
+                        buf_size - offset,
+                        "%d HT40 %c%c\n",
+                        chan->center_freq,
+                        (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) ?
+                               ' ' : '-',
+                        (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) ?
+                               ' ' : '+');
 }
 
 static ssize_t ht40allow_map_read(struct file *file,
index 9392f8cbb901d605769bbd6bb0fd048b3f884328..42ed274e81f4ca7debc59c4ae17137c35a0993d8 100644 (file)
@@ -46,6 +46,12 @@ BEGIN {
        sub(/:/, "", country)
        printf "static const struct ieee80211_regdomain regdom_%s = {\n", country
        printf "\t.alpha2 = \"%s\",\n", country
+       if ($NF ~ /DFS-ETSI/)
+               printf "\t.dfs_region = NL80211_DFS_ETSI,\n"
+       else if ($NF ~ /DFS-FCC/)
+               printf "\t.dfs_region = NL80211_DFS_FCC,\n"
+       else if ($NF ~ /DFS-JP/)
+               printf "\t.dfs_region = NL80211_DFS_JP,\n"
        printf "\t.reg_rules = {\n"
        active = 1
        regdb = regdb "\t&regdom_" country ",\n"
index af8d84a4a5b2a05fab2de732722e6535c8e699d0..2838206ddad3b5b05ea2eb2a6bfbc281593f9b41 100644 (file)
@@ -5591,6 +5591,9 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
        if (err)
                return err;
 
+       if (netif_carrier_ok(dev))
+               return -EBUSY;
+
        if (wdev->cac_started)
                return -EBUSY;
 
@@ -5634,15 +5637,26 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
        static struct nlattr *csa_attrs[NL80211_ATTR_MAX+1];
        u8 radar_detect_width = 0;
        int err;
+       bool need_new_beacon = false;
 
        if (!rdev->ops->channel_switch ||
            !(rdev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH))
                return -EOPNOTSUPP;
 
-       /* may add IBSS support later */
-       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
-           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+       switch (dev->ieee80211_ptr->iftype) {
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_P2P_GO:
+               need_new_beacon = true;
+
+               /* useless if AP is not running */
+               if (!wdev->beacon_interval)
+                       return -EINVAL;
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               break;
+       default:
                return -EOPNOTSUPP;
+       }
 
        memset(&params, 0, sizeof(params));
 
@@ -5651,15 +5665,16 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
                return -EINVAL;
 
        /* only important for AP, IBSS and mesh create IEs internally */
-       if (!info->attrs[NL80211_ATTR_CSA_IES])
-               return -EINVAL;
-
-       /* useless if AP is not running */
-       if (!wdev->beacon_interval)
+       if (need_new_beacon &&
+           (!info->attrs[NL80211_ATTR_CSA_IES] ||
+            !info->attrs[NL80211_ATTR_CSA_C_OFF_BEACON]))
                return -EINVAL;
 
        params.count = nla_get_u32(info->attrs[NL80211_ATTR_CH_SWITCH_COUNT]);
 
+       if (!need_new_beacon)
+               goto skip_beacons;
+
        err = nl80211_parse_beacon(info->attrs, &params.beacon_after);
        if (err)
                return err;
@@ -5699,6 +5714,7 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
                        return -EINVAL;
        }
 
+skip_beacons:
        err = nl80211_parse_chandef(rdev, info, &params.chandef);
        if (err)
                return err;
@@ -5706,12 +5722,17 @@ static int nl80211_channel_switch(struct sk_buff *skb, struct genl_info *info)
        if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
                return -EINVAL;
 
-       err = cfg80211_chandef_dfs_required(wdev->wiphy, &params.chandef);
-       if (err < 0) {
-               return err;
-       } else if (err) {
-               radar_detect_width = BIT(params.chandef.width);
-               params.radar_required = true;
+       /* DFS channels are only supported for AP/P2P GO ... for now. */
+       if (dev->ieee80211_ptr->iftype == NL80211_IFTYPE_AP ||
+           dev->ieee80211_ptr->iftype == NL80211_IFTYPE_P2P_GO) {
+               err = cfg80211_chandef_dfs_required(wdev->wiphy,
+                                                   &params.chandef);
+               if (err < 0) {
+                       return err;
+               } else if (err) {
+                       radar_detect_width = BIT(params.chandef.width);
+                       params.radar_required = true;
+               }
        }
 
        err = cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype,
@@ -10740,7 +10761,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
        wdev_lock(wdev);
 
        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
-                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype != NL80211_IFTYPE_ADHOC))
                goto out;
 
        wdev->channel = chandef->chan;
index de06d5d1287f97b6f6c8a1fd6b3e59371d80ae3e..d62cb1e91475e0adad49111cb615cc87af963e7c 100644 (file)
@@ -172,11 +172,21 @@ static const struct ieee80211_regdomain world_regdom = {
                        NL80211_RRF_NO_IBSS |
                        NL80211_RRF_NO_OFDM),
                /* IEEE 802.11a, channel 36..48 */
-               REG_RULE(5180-10, 5240+10, 80, 6, 20,
+               REG_RULE(5180-10, 5240+10, 160, 6, 20,
                         NL80211_RRF_PASSIVE_SCAN |
                         NL80211_RRF_NO_IBSS),
 
-               /* NB: 5260 MHz - 5700 MHz requires DFS */
+               /* IEEE 802.11a, channel 52..64 - DFS required */
+               REG_RULE(5260-10, 5320+10, 160, 6, 20,
+                       NL80211_RRF_PASSIVE_SCAN |
+                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_DFS),
+
+               /* IEEE 802.11a, channel 100..144 - DFS required */
+               REG_RULE(5500-10, 5720+10, 160, 6, 20,
+                       NL80211_RRF_PASSIVE_SCAN |
+                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_DFS),
 
                /* IEEE 802.11a, channel 149..165 */
                REG_RULE(5745-10, 5825+10, 80, 6, 20,
index ce090c1c5e4fdb36459c4f6fde6b5af241a75f0e..3c8be6104ba407a9d0b5d997d8c2fe4d659a63e4 100644 (file)
@@ -10,6 +10,7 @@
 #include <net/cfg80211.h>
 #include <net/ip.h>
 #include <net/dsfield.h>
+#include <linux/if_vlan.h>
 #include "core.h"
 #include "rdev-ops.h"
 
@@ -691,6 +692,7 @@ EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 {
        unsigned int dscp;
+       unsigned char vlan_priority;
 
        /* skb->priority values from 256->263 are magic values to
         * directly indicate a specific 802.1d priority.  This is used
@@ -700,6 +702,13 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
        if (skb->priority >= 256 && skb->priority <= 263)
                return skb->priority - 256;
 
+       if (vlan_tx_tag_present(skb)) {
+               vlan_priority = (vlan_tx_tag_get(skb) & VLAN_PRIO_MASK)
+                       >> VLAN_PRIO_SHIFT;
+               if (vlan_priority > 0)
+                       return vlan_priority;
+       }
+
        switch (skb->protocol) {
        case htons(ETH_P_IP):
                dscp = ipv4_get_dsfield(ip_hdr(skb)) & 0xfc;
index 2ca49bb31efc0b19995944260466d4601b403016..ccb3391882d1c7ef9bff825400c2c960dd977f20 100755 (executable)
@@ -9,7 +9,7 @@ paths="$@"
 # Doing this once at the beginning saves a lot of time, on a cache-hot tree.
 Kconfigs="`find . -name 'Kconfig' -o -name 'Kconfig*[^~]'`"
 
-/bin/echo -e "File list \tundefined symbol used"
+printf "File list \tundefined symbol used\n"
 find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while read i
 do
        # Output the bare Kconfig variable and the filename; the _MODULE part at
@@ -54,6 +54,6 @@ while read symb files; do
        # beyond the purpose of this script.
        symb_bare=`echo $symb | sed -e 's/_MODULE//'`
        if ! grep -q "\<$symb_bare\>" $Kconfigs; then
-               /bin/echo -e "$files: \t$symb"
+               printf "$files: \t$symb\n"
        fi
 done|sort
index 2ee9eb750560256187d4f236e328b5d7ad2656f8..47016c304c847efffb96da5358224a9b5a93cc5e 100755 (executable)
@@ -31,12 +31,16 @@ my $show_types = 0;
 my $fix = 0;
 my $root;
 my %debug;
-my %ignore_type = ();
 my %camelcase = ();
+my %use_type = ();
+my @use = ();
+my %ignore_type = ();
 my @ignore = ();
 my $help = 0;
 my $configuration_file = ".checkpatch.conf";
 my $max_line_length = 80;
+my $ignore_perl_version = 0;
+my $minimum_perl_version = 5.10.0;
 
 sub help {
        my ($exitcode) = @_;
@@ -54,6 +58,7 @@ Options:
   --terse                    one line per report
   -f, --file                 treat FILE as regular source file
   --subjective, --strict     enable more subjective tests
+  --types TYPE(,TYPE2...)    show only these comma separated message types
   --ignore TYPE(,TYPE2...)   ignore various comma separated message types
   --max-line-length=n        set the maximum line length, if exceeded, warn
   --show-types               show the message "types" in the output
@@ -71,6 +76,8 @@ Options:
                              "<inputfile>.EXPERIMENTAL-checkpatch-fixes"
                              with potential errors corrected to the preferred
                              checkpatch style
+  --ignore-perl-version      override checking of perl version.  expect
+                             runtime errors.
   -h, --help, --version      display this help and exit
 
 When FILE is - read standard input.
@@ -116,6 +123,7 @@ GetOptions(
        'subjective!'   => \$check,
        'strict!'       => \$check,
        'ignore=s'      => \@ignore,
+       'types=s'       => \@use,
        'show-types!'   => \$show_types,
        'max-line-length=i' => \$max_line_length,
        'root=s'        => \$root,
@@ -123,6 +131,7 @@ GetOptions(
        'mailback!'     => \$mailback,
        'summary-file!' => \$summary_file,
        'fix!'          => \$fix,
+       'ignore-perl-version!' => \$ignore_perl_version,
        'debug=s'       => \%debug,
        'test-only=s'   => \$tst_only,
        'h|help'        => \$help,
@@ -133,24 +142,50 @@ help(0) if ($help);
 
 my $exit = 0;
 
+if ($^V && $^V lt $minimum_perl_version) {
+       printf "$P: requires at least perl version %vd\n", $minimum_perl_version;
+       if (!$ignore_perl_version) {
+               exit(1);
+       }
+}
+
 if ($#ARGV < 0) {
        print "$P: no input files\n";
        exit(1);
 }
 
-@ignore = split(/,/, join(',',@ignore));
-foreach my $word (@ignore) {
-       $word =~ s/\s*\n?$//g;
-       $word =~ s/^\s*//g;
-       $word =~ s/\s+/ /g;
-       $word =~ tr/[a-z]/[A-Z]/;
+sub hash_save_array_words {
+       my ($hashRef, $arrayRef) = @_;
+
+       my @array = split(/,/, join(',', @$arrayRef));
+       foreach my $word (@array) {
+               $word =~ s/\s*\n?$//g;
+               $word =~ s/^\s*//g;
+               $word =~ s/\s+/ /g;
+               $word =~ tr/[a-z]/[A-Z]/;
+
+               next if ($word =~ m/^\s*#/);
+               next if ($word =~ m/^\s*$/);
 
-       next if ($word =~ m/^\s*#/);
-       next if ($word =~ m/^\s*$/);
+               $hashRef->{$word}++;
+       }
+}
 
-       $ignore_type{$word}++;
+sub hash_show_words {
+       my ($hashRef, $prefix) = @_;
+
+       if ($quiet == 0 && keys %$hashRef) {
+               print "NOTE: $prefix message types:";
+               foreach my $word (sort keys %$hashRef) {
+                       print " $word";
+               }
+               print "\n\n";
+       }
 }
 
+hash_save_array_words(\%ignore_type, \@ignore);
+hash_save_array_words(\%use_type, \@use);
+
 my $dbg_values = 0;
 my $dbg_possible = 0;
 my $dbg_type = 0;
@@ -207,6 +242,8 @@ our $Sparse = qr{
                        __rcu
                }x;
 
+our $InitAttribute = qr{__(?:mem|cpu|dev|net_|)(?:initdata|initconst|init\b)};
+
 # Notes to $Attribute:
 # We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
 our $Attribute = qr{
@@ -227,7 +264,7 @@ our $Attribute      = qr{
                        __deprecated|
                        __read_mostly|
                        __kprobes|
-                       __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+                       $InitAttribute|
                        ____cacheline_aligned|
                        ____cacheline_aligned_in_smp|
                        ____cacheline_internodealigned_in_smp|
@@ -257,6 +294,7 @@ our $Operators      = qr{
                  }x;
 
 our $NonptrType;
+our $NonptrTypeWithAttr;
 our $Type;
 our $Declare;
 
@@ -319,6 +357,12 @@ our @typeList = (
        qr{${Ident}_handler},
        qr{${Ident}_handler_fn},
 );
+our @typeListWithAttr = (
+       @typeList,
+       qr{struct\s+$InitAttribute\s+$Ident},
+       qr{union\s+$InitAttribute\s+$Ident},
+);
+
 our @modifierList = (
        qr{fastcall},
 );
@@ -332,6 +376,7 @@ our $allowed_asm_includes = qr{(?x:
 sub build_types {
        my $mods = "(?x:  \n" . join("|\n  ", @modifierList) . "\n)";
        my $all = "(?x:  \n" . join("|\n  ", @typeList) . "\n)";
+       my $allWithAttr = "(?x:  \n" . join("|\n  ", @typeListWithAttr) . "\n)";
        $Modifier       = qr{(?:$Attribute|$Sparse|$mods)};
        $NonptrType     = qr{
                        (?:$Modifier\s+|const\s+)*
@@ -342,6 +387,15 @@ sub build_types {
                        )
                        (?:\s+$Modifier|\s+const)*
                  }x;
+       $NonptrTypeWithAttr     = qr{
+                       (?:$Modifier\s+|const\s+)*
+                       (?:
+                               (?:typeof|__typeof__)\s*\([^\)]*\)|
+                               (?:$typeTypedefs\b)|
+                               (?:${allWithAttr}\b)
+                       )
+                       (?:\s+$Modifier|\s+const)*
+                 }x;
        $Type   = qr{
                        $NonptrType
                        (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
@@ -1355,7 +1409,9 @@ sub possible {
 my $prefix = '';
 
 sub show_type {
-       return !defined $ignore_type{$_[0]};
+       return defined $use_type{$_[0]} if (scalar keys %use_type > 0);
+
+       return !defined $ignore_type{$_[0]};
 }
 
 sub report {
@@ -1435,7 +1491,23 @@ sub check_absolute_file {
 sub trim {
        my ($string) = @_;
 
-       $string =~ s/(^\s+|\s+$)//g;
+       $string =~ s/^\s+|\s+$//g;
+
+       return $string;
+}
+
+sub ltrim {
+       my ($string) = @_;
+
+       $string =~ s/^\s+//;
+
+       return $string;
+}
+
+sub rtrim {
+       my ($string) = @_;
+
+       $string =~ s/\s+$//;
 
        return $string;
 }
@@ -1532,6 +1604,7 @@ sub process {
        my %suppress_export;
        my $suppress_statement = 0;
 
+       my %signatures = ();
 
        # Pre-scan the patch sanitizing the lines.
        # Pre-scan the patch looking for any __setup documentation.
@@ -1624,6 +1697,8 @@ sub process {
        $linenr = 0;
        foreach my $line (@lines) {
                $linenr++;
+               my $sline = $line;      #copy of $line
+               $sline =~ s/$;/ /g;     #with comments as spaces
 
                my $rawline = $rawlines[$linenr - 1];
 
@@ -1781,6 +1856,17 @@ sub process {
                                             "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr);
                                }
                        }
+
+# Check for duplicate signatures
+                       my $sig_nospace = $line;
+                       $sig_nospace =~ s/\s//g;
+                       $sig_nospace = lc($sig_nospace);
+                       if (defined $signatures{$sig_nospace}) {
+                               WARN("BAD_SIGN_OFF",
+                                    "Duplicate signature\n" . $herecurr);
+                       } else {
+                               $signatures{$sig_nospace} = 1;
+                       }
                }
 
 # Check for wrappage within a valid hunk of the file
@@ -1845,15 +1931,17 @@ sub process {
 #trailing whitespace
                if ($line =~ /^\+.*\015/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
-                       ERROR("DOS_LINE_ENDINGS",
-                             "DOS line endings\n" . $herevet);
-
+                       if (ERROR("DOS_LINE_ENDINGS",
+                                 "DOS line endings\n" . $herevet) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/[\s\015]+$//;
+                       }
                } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
                        my $herevet = "$here\n" . cat_vet($rawline) . "\n";
                        if (ERROR("TRAILING_WHITESPACE",
                                  "trailing whitespace\n" . $herevet) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~ s/^(\+.*?)\s+$/$1/;
+                               $fixed[$linenr - 1] =~ s/\s+$//;
                        }
 
                        $rpt_cleaners = 1;
@@ -2060,6 +2148,7 @@ sub process {
                if ($realfile =~ m@^(drivers/net/|net/)@ &&
                    $prevrawline =~ /^\+[ \t]*\/\*/ &&          #starting /*
                    $prevrawline !~ /\*\/[ \t]*$/ &&            #no trailing */
+                   $rawline =~ /^\+/ &&                        #line is new
                    $rawline !~ /^\+[ \t]*\*/) {                #no leading *
                        WARN("NETWORKING_BLOCK_COMMENT_STYLE",
                             "networking block comments start with * on subsequent lines\n" . $hereprev);
@@ -2126,7 +2215,7 @@ sub process {
                    $realline_next);
 #print "LINE<$line>\n";
                if ($linenr >= $suppress_statement &&
-                   $realcnt && $line =~ /.\s*\S/) {
+                   $realcnt && $sline =~ /.\s*\S/) {
                        ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
                                ctx_statement_block($linenr, $realcnt, 0);
                        $stat =~ s/\n./\n /g;
@@ -2486,16 +2575,22 @@ sub process {
                }
 
 # check for global initialisers.
-               if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
-                       ERROR("GLOBAL_INITIALISERS",
-                             "do not initialise globals to 0 or NULL\n" .
-                               $herecurr);
+               if ($line =~ /^\+(\s*$Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/) {
+                       if (ERROR("GLOBAL_INITIALISERS",
+                                 "do not initialise globals to 0 or NULL\n" .
+                                     $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/($Type\s*$Ident\s*(?:\s+$Modifier))*\s*=\s*(0|NULL|false)\s*;/$1;/;
+                       }
                }
 # check for static initialisers.
-               if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
-                       ERROR("INITIALISED_STATIC",
-                             "do not initialise statics to 0 or NULL\n" .
-                               $herecurr);
+               if ($line =~ /^\+.*\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+                       if (ERROR("INITIALISED_STATIC",
+                                 "do not initialise statics to 0 or NULL\n" .
+                                     $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/(\bstatic\s.*?)\s*=\s*(0|NULL|false)\s*;/$1;/;
+                       }
                }
 
 # check for static const char * arrays.
@@ -2638,8 +2733,12 @@ sub process {
                }
 
                if ($line =~ /\bpr_warning\s*\(/) {
-                       WARN("PREFER_PR_LEVEL",
-                            "Prefer pr_warn(... to pr_warning(...\n" . $herecurr);
+                       if (WARN("PREFER_PR_LEVEL",
+                                "Prefer pr_warn(... to pr_warning(...\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/\bpr_warning\b/pr_warn/;
+                       }
                }
 
                if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) {
@@ -2759,6 +2858,7 @@ sub process {
                        $off = 0;
 
                        my $blank = copy_spacing($opline);
+                       my $last_after = -1;
 
                        for (my $n = 0; $n < $#elements; $n += 2) {
 
@@ -2824,7 +2924,7 @@ sub process {
                                            $cc !~ /^\\/ && $cc !~ /^;/) {
                                                if (ERROR("SPACING",
                                                          "space required after that '$op' $at\n" . $hereptr)) {
-                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
                                                        $line_fixed = 1;
                                                }
                                        }
@@ -2839,11 +2939,11 @@ sub process {
                                        if ($ctx =~ /Wx.|.xW/) {
                                                if (ERROR("SPACING",
                                                          "spaces prohibited around that '$op' $at\n" . $hereptr)) {
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
-                                                       $line_fixed = 1;
+                                                       $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
                                                        if (defined $fix_elements[$n + 2]) {
                                                                $fix_elements[$n + 2] =~ s/^\s+//;
                                                        }
+                                                       $line_fixed = 1;
                                                }
                                        }
 
@@ -2852,8 +2952,9 @@ sub process {
                                        if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
                                                if (ERROR("SPACING",
                                                          "space required after that '$op' $at\n" . $hereptr)) {
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]) . " ";
+                                                       $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
                                                        $line_fixed = 1;
+                                                       $last_after = $n;
                                                }
                                        }
 
@@ -2870,8 +2971,10 @@ sub process {
                                        if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
                                                if (ERROR("SPACING",
                                                          "space required before that '$op' $at\n" . $hereptr)) {
-                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]);
-                                                       $line_fixed = 1;
+                                                       if ($n != $last_after + 2) {
+                                                               $good = $fix_elements[$n] . " " . ltrim($fix_elements[$n + 1]);
+                                                               $line_fixed = 1;
+                                                       }
                                                }
                                        }
                                        if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
@@ -2880,12 +2983,11 @@ sub process {
                                        } elsif ($ctx =~ /.xW/) {
                                                if (ERROR("SPACING",
                                                          "space prohibited after that '$op' $at\n" . $hereptr)) {
-                                                       $fixed_line =~ s/\s+$//;
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
-                                                       $line_fixed = 1;
+                                                       $good = $fix_elements[$n] . rtrim($fix_elements[$n + 1]);
                                                        if (defined $fix_elements[$n + 2]) {
                                                                $fix_elements[$n + 2] =~ s/^\s+//;
                                                        }
+                                                       $line_fixed = 1;
                                                }
                                        }
 
@@ -2894,8 +2996,7 @@ sub process {
                                        if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
                                                if (ERROR("SPACING",
                                                          "space required one side of that '$op' $at\n" . $hereptr)) {
-                                                       $fixed_line =~ s/\s+$//;
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]) . " ";
+                                                       $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
                                                        $line_fixed = 1;
                                                }
                                        }
@@ -2903,20 +3004,18 @@ sub process {
                                            ($ctx =~ /Wx./ && $cc =~ /^;/)) {
                                                if (ERROR("SPACING",
                                                          "space prohibited before that '$op' $at\n" . $hereptr)) {
-                                                       $fixed_line =~ s/\s+$//;
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
                                                        $line_fixed = 1;
                                                }
                                        }
                                        if ($ctx =~ /ExW/) {
                                                if (ERROR("SPACING",
                                                          "space prohibited after that '$op' $at\n" . $hereptr)) {
-                                                       $fixed_line =~ s/\s+$//;
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
-                                                       $line_fixed = 1;
+                                                       $good = $fix_elements[$n] . trim($fix_elements[$n + 1]);
                                                        if (defined $fix_elements[$n + 2]) {
                                                                $fix_elements[$n + 2] =~ s/^\s+//;
                                                        }
+                                                       $line_fixed = 1;
                                                }
                                        }
 
@@ -2930,8 +3029,10 @@ sub process {
                                        if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
                                                if (ERROR("SPACING",
                                                          "need consistent spacing around '$op' $at\n" . $hereptr)) {
-                                                       $fixed_line =~ s/\s+$//;
-                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       if (defined $fix_elements[$n + 2]) {
+                                                               $fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
                                                        $line_fixed = 1;
                                                }
                                        }
@@ -2942,7 +3043,7 @@ sub process {
                                        if ($ctx =~ /Wx./) {
                                                if (ERROR("SPACING",
                                                          "space prohibited before that '$op' $at\n" . $hereptr)) {
-                                                       $good = trim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+                                                       $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
                                                        $line_fixed = 1;
                                                }
                                        }
@@ -2969,8 +3070,10 @@ sub process {
                                        if ($ok == 0) {
                                                if (ERROR("SPACING",
                                                          "spaces required around that '$op' $at\n" . $hereptr)) {
-                                                       $good = trim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
-                                                       $good = $fix_elements[$n] . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       $good = rtrim($fix_elements[$n]) . " " . trim($fix_elements[$n + 1]) . " ";
+                                                       if (defined $fix_elements[$n + 2]) {
+                                                               $fix_elements[$n + 2] =~ s/^\s+//;
+                                                       }
                                                        $line_fixed = 1;
                                                }
                                        }
@@ -3031,8 +3134,7 @@ sub process {
                        if (ERROR("SPACING",
                                  "space required before the open brace '{'\n" . $herecurr) &&
                            $fix) {
-                               $fixed[$linenr - 1] =~
-                                   s/^(\+.*(?:do|\))){/$1 {/;
+                               $fixed[$linenr - 1] =~ s/^(\+.*(?:do|\))){/$1 {/;
                        }
                }
 
@@ -3047,8 +3149,12 @@ sub process {
 # closing brace should have a space following it when it has anything
 # on the line
                if ($line =~ /}(?!(?:,|;|\)))\S/) {
-                       ERROR("SPACING",
-                             "space required after that close brace '}'\n" . $herecurr);
+                       if (ERROR("SPACING",
+                                 "space required after that close brace '}'\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~
+                                   s/}((?!(?:,|;|\)))\S)/} $1/;
+                       }
                }
 
 # check spacing on square brackets
@@ -3271,8 +3377,13 @@ sub process {
 
 #gcc binary extension
                        if ($var =~ /^$Binary$/) {
-                               WARN("GCC_BINARY_CONSTANT",
-                                    "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr);
+                               if (WARN("GCC_BINARY_CONSTANT",
+                                        "Avoid gcc v4.3+ binary constant extension: <$var>\n" . $herecurr) &&
+                                   $fix) {
+                                       my $hexval = sprintf("0x%x", oct($var));
+                                       $fixed[$linenr - 1] =~
+                                           s/\b$var\b/$hexval/;
+                               }
                        }
 
 #CamelCase
@@ -3282,19 +3393,26 @@ sub process {
                            $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
 #Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show)
                            $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/) {
-                               seed_camelcase_includes() if ($check);
-                               if (!defined $camelcase{$var}) {
-                                       $camelcase{$var} = 1;
-                                       CHK("CAMELCASE",
-                                           "Avoid CamelCase: <$var>\n" . $herecurr);
+                               while ($var =~ m{($Ident)}g) {
+                                       my $word = $1;
+                                       next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/);
+                                       seed_camelcase_includes() if ($check);
+                                       if (!defined $camelcase{$word}) {
+                                               $camelcase{$word} = 1;
+                                               CHK("CAMELCASE",
+                                                   "Avoid CamelCase: <$word>\n" . $herecurr);
+                                       }
                                }
                        }
                }
 
 #no spaces allowed after \ in define
-               if ($line=~/\#\s*define.*\\\s$/) {
-                       WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
-                            "Whitepspace after \\ makes next lines useless\n" . $herecurr);
+               if ($line =~ /\#\s*define.*\\\s+$/) {
+                       if (WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
+                                "Whitespace after \\ makes next lines useless\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\s+$//;
+                       }
                }
 
 #warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
@@ -3374,7 +3492,8 @@ sub process {
                            $dstat !~ /^for\s*$Constant$/ &&                            # for (...)
                            $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ &&   # for (...) bar()
                            $dstat !~ /^do\s*{/ &&                                      # do {...
-                           $dstat !~ /^\({/)                                           # ({...
+                           $dstat !~ /^\({/ &&                                         # ({...
+                           $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/)
                        {
                                $ctx =~ s/\n*$//;
                                my $herectx = $here . "\n";
@@ -3606,6 +3725,32 @@ sub process {
                        }
                }
 
+sub string_find_replace {
+       my ($string, $find, $replace) = @_;
+
+       $string =~ s/$find/$replace/g;
+
+       return $string;
+}
+
+# check for bad placement of section $InitAttribute (e.g.: __initdata)
+               if ($line =~ /(\b$InitAttribute\b)/) {
+                       my $attr = $1;
+                       if ($line =~ /^\+\s*static\s+(?:const\s+)?(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*[=;]/) {
+                               my $ptr = $1;
+                               my $var = $2;
+                               if ((($ptr =~ /\b(union|struct)\s+$attr\b/ &&
+                                     ERROR("MISPLACED_INIT",
+                                           "$attr should be placed after $var\n" . $herecurr)) ||
+                                    ($ptr !~ /\b(union|struct)\s+$attr\b/ &&
+                                     WARN("MISPLACED_INIT",
+                                          "$attr should be placed after $var\n" . $herecurr))) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =~ s/(\bstatic\s+(?:const\s+)?)(?:$attr\s+)?($NonptrTypeWithAttr)\s+(?:$attr\s+)?($Ident(?:\[[^]]*\])?)\s*([=;])\s*/"$1" . trim(string_find_replace($2, "\\s*$attr\\s*", " ")) . " " . trim(string_find_replace($3, "\\s*$attr\\s*", "")) . " $attr" . ("$4" eq ";" ? ";" : " = ")/e;
+                               }
+                       }
+               }
+
 # prefer usleep_range over udelay
                if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
                        # ignore udelay's < 10, however
@@ -3691,8 +3836,12 @@ sub process {
 
 # Check for __inline__ and __inline, prefer inline
                if ($line =~ /\b(__inline__|__inline)\b/) {
-                       WARN("INLINE",
-                            "plain inline is preferred over $1\n" . $herecurr);
+                       if (WARN("INLINE",
+                                "plain inline is preferred over $1\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\b(__inline__|__inline)\b/inline/;
+
+                       }
                }
 
 # Check for __attribute__ packed, prefer __packed
@@ -3709,14 +3858,21 @@ sub process {
 
 # Check for __attribute__ format(printf, prefer __printf
                if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
-                       WARN("PREFER_PRINTF",
-                            "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr);
+                       if (WARN("PREFER_PRINTF",
+                                "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf\s*,\s*(.*)\)\s*\)\s*\)/"__printf(" . trim($1) . ")"/ex;
+
+                       }
                }
 
 # Check for __attribute__ format(scanf, prefer __scanf
                if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
-                       WARN("PREFER_SCANF",
-                            "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr);
+                       if (WARN("PREFER_SCANF",
+                                "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\s*,\s*(.*)\)\s*\)\s*\)/"__scanf(" . trim($1) . ")"/ex;
+                       }
                }
 
 # check for sizeof(&)
@@ -3727,8 +3883,11 @@ sub process {
 
 # check for sizeof without parenthesis
                if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) {
-                       WARN("SIZEOF_PARENTHESIS",
-                            "sizeof $1 should be sizeof($1)\n" . $herecurr);
+                       if (WARN("SIZEOF_PARENTHESIS",
+                                "sizeof $1 should be sizeof($1)\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/"sizeof(" . trim($1) . ")"/ex;
+                       }
                }
 
 # check for line continuations in quoted strings with odd counts of "
@@ -3747,8 +3906,11 @@ sub process {
                if ($line =~ /\bseq_printf\s*\(/) {
                        my $fmt = get_quoted_string($line, $rawline);
                        if ($fmt !~ /[^\\]\%/) {
-                               WARN("PREFER_SEQ_PUTS",
-                                    "Prefer seq_puts to seq_printf\n" . $herecurr);
+                               if (WARN("PREFER_SEQ_PUTS",
+                                        "Prefer seq_puts to seq_printf\n" . $herecurr) &&
+                                   $fix) {
+                                       $fixed[$linenr - 1] =~ s/\bseq_printf\b/seq_puts/;
+                               }
                        }
                }
 
@@ -3810,6 +3972,16 @@ sub process {
                        }
                }
 
+# check for new externs in .h files.
+               if ($realfile =~ /\.h$/ &&
+                   $line =~ /^\+\s*(extern\s+)$Type\s*$Ident\s*\(/s) {
+                       if (WARN("AVOID_EXTERNS",
+                                "extern prototypes should be avoided in .h files\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/(.*)\bextern\b\s*(.*)/$1$2/;
+                       }
+               }
+
 # check for new externs in .c files.
                if ($realfile =~ /\.c$/ && defined $stat &&
                    $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
@@ -3879,8 +4051,11 @@ sub process {
 
 # check for multiple semicolons
                if ($line =~ /;\s*;\s*$/) {
-                       WARN("ONE_SEMICOLON",
-                            "Statements terminations use 1 semicolon\n" . $herecurr);
+                       if (WARN("ONE_SEMICOLON",
+                                "Statements terminations use 1 semicolon\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/(\s*;\s*){2,}$/;/g;
+                       }
                }
 
 # check for switch/default statements without a break;
@@ -3898,9 +4073,12 @@ sub process {
                }
 
 # check for gcc specific __FUNCTION__
-               if ($line =~ /__FUNCTION__/) {
-                       WARN("USE_FUNC",
-                            "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr);
+               if ($line =~ /\b__FUNCTION__\b/) {
+                       if (WARN("USE_FUNC",
+                                "__func__ should be used instead of gcc specific __FUNCTION__\n"  . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/\b__FUNCTION__\b/__func__/g;
+                       }
                }
 
 # check for use of yield()
@@ -4105,13 +4283,8 @@ sub process {
                }
        }
 
-       if ($quiet == 0 && keys %ignore_type) {
-           print "NOTE: Ignored message types:";
-           foreach my $ignore (sort keys %ignore_type) {
-               print " $ignore";
-           }
-           print "\n\n";
-       }
+       hash_show_words(\%use_type, "Used");
+       hash_show_words(\%ignore_type, "Ignored");
 
        if ($clean == 0 && $fix && "@rawlines" ne "@fixed") {
                my $newfile = $filename . ".EXPERIMENTAL-checkpatch-fixes";
diff --git a/scripts/coccinelle/misc/boolreturn.cocci b/scripts/coccinelle/misc/boolreturn.cocci
new file mode 100644 (file)
index 0000000..a43c7b0
--- /dev/null
@@ -0,0 +1,58 @@
+/// Return statements in functions returning bool should use
+/// true/false instead of 1/0.
+//
+// Confidence: High
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual report
+virtual context
+
+@r1 depends on patch@
+identifier fn;
+typedef bool;
+symbol false;
+symbol true;
+@@
+
+bool fn ( ... )
+{
+<...
+return
+(
+- 0
++ false
+|
+- 1
++ true
+)
+  ;
+...>
+}
+
+@r2 depends on report || context@
+identifier fn;
+position p;
+@@
+
+bool fn ( ... )
+{
+<...
+return
+(
+* 0@p
+|
+* 1@p
+)
+  ;
+...>
+}
+
+
+@script:python depends on report@
+p << r2.p;
+fn << r2.fn;
+@@
+
+msg = "WARNING: return of 0/1 in function '%s' with return type bool" % fn
+coccilib.report.print_report(p[0], msg)
index 567120a87c39c0152643fba45f5487979b305afc..68041793698c5f22099782129b03c81b8b4bca54 100755 (executable)
@@ -62,15 +62,52 @@ checkarg() {
        fi
 }
 
+txt_append() {
+       local anchor="$1"
+       local insert="$2"
+       local infile="$3"
+       local tmpfile="$infile.swp"
+
+       # sed append cmd: 'a\' + newline + text + newline
+       cmd="$(printf "a\\%b$insert" "\n")"
+
+       sed -e "/$anchor/$cmd" "$infile" >"$tmpfile"
+       # replace original file with the edited one
+       mv "$tmpfile" "$infile"
+}
+
+txt_subst() {
+       local before="$1"
+       local after="$2"
+       local infile="$3"
+       local tmpfile="$infile.swp"
+
+       sed -e "s:$before:$after:" "$infile" >"$tmpfile"
+       # replace original file with the edited one
+       mv "$tmpfile" "$infile"
+}
+
+txt_delete() {
+       local text="$1"
+       local infile="$2"
+       local tmpfile="$infile.swp"
+
+       sed -e "/$text/d" "$infile" >"$tmpfile"
+       # replace original file with the edited one
+       mv "$tmpfile" "$infile"
+}
+
 set_var() {
        local name=$1 new=$2 before=$3
 
        name_re="^($name=|# $name is not set)"
        before_re="^($before=|# $before is not set)"
        if test -n "$before" && grep -Eq "$before_re" "$FN"; then
-               sed -ri "/$before_re/a $new" "$FN"
+               txt_append "^$before=" "$new" "$FN"
+               txt_append "^# $before is not set" "$new" "$FN"
        elif grep -Eq "$name_re" "$FN"; then
-               sed -ri "s:$name_re.*:$new:" "$FN"
+               txt_subst "^$name=.*" "$new" "$FN"
+               txt_subst "^# $name is not set" "$new" "$FN"
        else
                echo "$new" >>"$FN"
        fi
@@ -79,7 +116,8 @@ set_var() {
 undef_var() {
        local name=$1
 
-       sed -ri "/^($name=|# $name is not set)/d" "$FN"
+       txt_delete "^$name=" "$FN"
+       txt_delete "^# $name is not set" "$FN"
 }
 
 if [ "$1" = "--file" ]; then
index b91f3e34d44d5d39907b8bbef3de4fb6f37fbb69..6d672836e18722c38cce43149587db32882e6316 100755 (executable)
@@ -10,7 +10,7 @@
 import sys, os
 
 def usage():
-    print """Usage: diffconfig [-h] [-m] [<config1> <config2>]
+    print("""Usage: diffconfig [-h] [-m] [<config1> <config2>]
 
 Diffconfig is a simple utility for comparing two .config files.
 Using standard diff to compare .config files often includes extraneous and
@@ -33,7 +33,7 @@ Example usage:
  EXT2_FS  y -> n
  LOG_BUF_SHIFT  14 -> 16
  PRINTK_TIME  n -> y
-"""
+""")
     sys.exit(0)
 
 # returns a dictionary of name/value pairs for config items in the file
@@ -54,23 +54,23 @@ def print_config(op, config, value, new_value):
     if merge_style:
         if new_value:
             if new_value=="n":
-                print "# CONFIG_%s is not set" % config
+                print("# CONFIG_%s is not set" % config)
             else:
-                print "CONFIG_%s=%s" % (config, new_value)
+                print("CONFIG_%s=%s" % (config, new_value))
     else:
         if op=="-":
-            print "-%s %s" % (config, value)
+            print("-%s %s" % (config, value))
         elif op=="+":
-            print "+%s %s" % (config, new_value)
+            print("+%s %s" % (config, new_value))
         else:
-            print " %s %s -> %s" % (config, value, new_value)
+            print(" %s %s -> %s" % (config, value, new_value))
 
 def main():
     global merge_style
 
     # parse command line args
     if ("-h" in sys.argv or "--help" in sys.argv):
-       usage()
+        usage()
 
     merge_style = 0
     if "-m" in sys.argv:
@@ -79,23 +79,27 @@ def main():
 
     argc = len(sys.argv)
     if not (argc==1 or argc == 3):
-        print "Error: incorrect number of arguments or unrecognized option"
+        print("Error: incorrect number of arguments or unrecognized option")
         usage()
 
     if argc == 1:
         # if no filenames given, assume .config and .config.old
         build_dir=""
-        if os.environ.has_key("KBUILD_OUTPUT"):
+        if "KBUILD_OUTPUT" in os.environ:
             build_dir = os.environ["KBUILD_OUTPUT"]+"/"
-
         configa_filename = build_dir + ".config.old"
         configb_filename = build_dir + ".config"
     else:
         configa_filename = sys.argv[1]
         configb_filename = sys.argv[2]
 
-    a = readconfig(file(configa_filename))
-    b = readconfig(file(configb_filename))
+    try:
+        a = readconfig(open(configa_filename))
+        b = readconfig(open(configb_filename))
+    except (IOError):
+        e = sys.exc_info()[1]
+        print("I/O error[%s]: %s\n" % (e.args[0],e.args[1]))
+        usage()
 
     # print items in a but not b (accumulate, sort and print)
     old = []
@@ -121,8 +125,7 @@ def main():
 
     # now print items in b but not in a
     # (items from b that were in a were removed above)
-    new = b.keys()
-    new.sort()
+    new = sorted(b.keys())
     for config in new:
         print_config("+", config, None, b[config])
 
index c55c227af463008396bc32548337769f71cc0d15..87f723804079ed3b6c1fbb0d1470f717582c4a28 100644 (file)
@@ -140,7 +140,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->flags |= def_flags;
                        break;
                }
-               conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+               if (def != S_DEF_AUTO)
+                       conf_warning("symbol value '%s' invalid for %s",
+                                    p, sym->name);
                return 1;
        case S_OTHER:
                if (*p != '"') {
@@ -161,7 +163,8 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        memmove(p2, p2 + 1, strlen(p2));
                }
                if (!p2) {
-                       conf_warning("invalid string found");
+                       if (def != S_DEF_AUTO)
+                               conf_warning("invalid string found");
                        return 1;
                }
                /* fall through */
@@ -172,7 +175,9 @@ static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p)
                        sym->def[def].val = strdup(p);
                        sym->flags |= def_flags;
                } else {
-                       conf_warning("symbol value '%s' invalid for %s", p, sym->name);
+                       if (def != S_DEF_AUTO)
+                               conf_warning("symbol value '%s' invalid for %s",
+                                            p, sym->name);
                        return 1;
                }
                break;
index 6c9c45f9fbbac432a877112f4243f483ed01e9e3..2c3963165a0d83f45b2d180361e12e4542588302 100644 (file)
@@ -401,8 +401,8 @@ static void search_conf(void)
        struct subtitle_part stpart;
 
        title = str_new();
-       str_printf( &title, _("Enter %s (sub)string or regexp to search for "
-                             "(with or without \"%s\")"), CONFIG_, CONFIG_);
+       str_printf( &title, _("Enter (sub)string or regexp to search for "
+                             "(with or without \"%s\")"), CONFIG_);
 
 again:
        dialog_clear();
index 7e233a6ca64ef7faf1bc9390ec89cb90ccef2d98..c1d53200c306dc6202cbcc13555a05333c34411a 100644 (file)
@@ -197,12 +197,15 @@ void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep)
 
 void menu_add_option(int token, char *arg)
 {
-       struct property *prop;
-
        switch (token) {
        case T_OPT_MODULES:
-               prop = prop_alloc(P_DEFAULT, modules_sym);
-               prop->expr = expr_alloc_symbol(current_entry->sym);
+               if (modules_sym)
+                       zconf_error("symbol '%s' redefines option 'modules'"
+                                   " already defined by symbol '%s'",
+                                   current_entry->sym->name,
+                                   modules_sym->name
+                                   );
+               modules_sym = current_entry->sym;
                break;
        case T_OPT_DEFCONFIG_LIST:
                if (!sym_defconfig_list)
index 7975d8d258c3f6cb8848a137a3f263a4f16f1d20..4fbecd2473bc51904629056eaa8bacb7b42fb660 100644 (file)
@@ -695,8 +695,8 @@ static void search_conf(void)
        int dres;
 
        title = str_new();
-       str_printf( &title, _("Enter %s (sub)string or regexp to search for "
-                             "(with or without \"%s\")"), CONFIG_, CONFIG_);
+       str_printf( &title, _("Enter (sub)string or regexp to search for "
+                             "(with or without \"%s\")"), CONFIG_);
 
 again:
        dres = dialog_inputbox(main_window,
index d550300ec00c34e5b1748478c6381341e9412e0b..c9a6775565bfa13252138f81ef8a0312b11cfea8 100644 (file)
@@ -136,7 +136,7 @@ static struct property *sym_get_range_prop(struct symbol *sym)
        return NULL;
 }
 
-static long sym_get_range_val(struct symbol *sym, int base)
+static long long sym_get_range_val(struct symbol *sym, int base)
 {
        sym_calc_value(sym);
        switch (sym->type) {
@@ -149,13 +149,14 @@ static long sym_get_range_val(struct symbol *sym, int base)
        default:
                break;
        }
-       return strtol(sym->curr.val, NULL, base);
+       return strtoll(sym->curr.val, NULL, base);
 }
 
 static void sym_validate_range(struct symbol *sym)
 {
        struct property *prop;
-       long base, val, val2;
+       int base;
+       long long val, val2;
        char str[64];
 
        switch (sym->type) {
@@ -171,7 +172,7 @@ static void sym_validate_range(struct symbol *sym)
        prop = sym_get_range_prop(sym);
        if (!prop)
                return;
-       val = strtol(sym->curr.val, NULL, base);
+       val = strtoll(sym->curr.val, NULL, base);
        val2 = sym_get_range_val(prop->expr->left.sym, base);
        if (val >= val2) {
                val2 = sym_get_range_val(prop->expr->right.sym, base);
@@ -179,9 +180,9 @@ static void sym_validate_range(struct symbol *sym)
                        return;
        }
        if (sym->type == S_INT)
-               sprintf(str, "%ld", val2);
+               sprintf(str, "%lld", val2);
        else
-               sprintf(str, "0x%lx", val2);
+               sprintf(str, "0x%llx", val2);
        sym->curr.val = strdup(str);
 }
 
@@ -594,7 +595,7 @@ bool sym_string_valid(struct symbol *sym, const char *str)
 bool sym_string_within_range(struct symbol *sym, const char *str)
 {
        struct property *prop;
-       long val;
+       long long val;
 
        switch (sym->type) {
        case S_STRING:
@@ -605,7 +606,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
                prop = sym_get_range_prop(sym);
                if (!prop)
                        return true;
-               val = strtol(str, NULL, 10);
+               val = strtoll(str, NULL, 10);
                return val >= sym_get_range_val(prop->expr->left.sym, 10) &&
                       val <= sym_get_range_val(prop->expr->right.sym, 10);
        case S_HEX:
@@ -614,7 +615,7 @@ bool sym_string_within_range(struct symbol *sym, const char *str)
                prop = sym_get_range_prop(sym);
                if (!prop)
                        return true;
-               val = strtol(str, NULL, 16);
+               val = strtoll(str, NULL, 16);
                return val >= sym_get_range_val(prop->expr->left.sym, 16) &&
                       val <= sym_get_range_val(prop->expr->right.sym, 16);
        case S_BOOLEAN:
@@ -963,11 +964,11 @@ struct sym_match {
  * - first, symbols that match exactly
  * - then, alphabetical sort
  */
-static int sym_rel_comp( const void *sym1, const void *sym2 )
+static int sym_rel_comp(const void *sym1, const void *sym2)
 {
-       struct sym_match *s1 = *(struct sym_match **)sym1;
-       struct sym_match *s2 = *(struct sym_match **)sym2;
-       int l1, l2;
+       const struct sym_match *s1 = sym1;
+       const struct sym_match *s2 = sym2;
+       int exact1, exact2;
 
        /* Exact match:
         * - if matched length on symbol s1 is the length of that symbol,
@@ -978,11 +979,11 @@ static int sym_rel_comp( const void *sym1, const void *sym2 )
         * exactly; if this is the case, we can't decide which comes first,
         * and we fallback to sorting alphabetically.
         */
-       l1 = s1->eo - s1->so;
-       l2 = s2->eo - s2->so;
-       if (l1 == strlen(s1->sym->name) && l2 != strlen(s2->sym->name))
+       exact1 = (s1->eo - s1->so) == strlen(s1->sym->name);
+       exact2 = (s2->eo - s2->so) == strlen(s2->sym->name);
+       if (exact1 && !exact2)
                return -1;
-       if (l1 != strlen(s1->sym->name) && l2 == strlen(s2->sym->name))
+       if (!exact1 && exact2)
                return 1;
 
        /* As a fallback, sort symbols alphabetically */
@@ -992,7 +993,7 @@ static int sym_rel_comp( const void *sym1, const void *sym2 )
 struct symbol **sym_re_search(const char *pattern)
 {
        struct symbol *sym, **sym_arr = NULL;
-       struct sym_match **sym_match_arr = NULL;
+       struct sym_match *sym_match_arr = NULL;
        int i, cnt, size;
        regex_t re;
        regmatch_t match[1];
@@ -1005,47 +1006,38 @@ struct symbol **sym_re_search(const char *pattern)
                return NULL;
 
        for_all_symbols(i, sym) {
-               struct sym_match *tmp_sym_match;
                if (sym->flags & SYMBOL_CONST || !sym->name)
                        continue;
                if (regexec(&re, sym->name, 1, match, 0))
                        continue;
-               if (cnt + 1 >= size) {
+               if (cnt >= size) {
                        void *tmp;
                        size += 16;
-                       tmp = realloc(sym_match_arr, size * sizeof(struct sym_match *));
-                       if (!tmp) {
+                       tmp = realloc(sym_match_arr, size * sizeof(struct sym_match));
+                       if (!tmp)
                                goto sym_re_search_free;
-                       }
                        sym_match_arr = tmp;
                }
                sym_calc_value(sym);
-               tmp_sym_match = (struct sym_match*)malloc(sizeof(struct sym_match));
-               if (!tmp_sym_match)
-                       goto sym_re_search_free;
-               tmp_sym_match->sym = sym;
-               /* As regexec return 0, we know we have a match, so
+               /* As regexec returned 0, we know we have a match, so
                 * we can use match[0].rm_[se]o without further checks
                 */
-               tmp_sym_match->so = match[0].rm_so;
-               tmp_sym_match->eo = match[0].rm_eo;
-               sym_match_arr[cnt++] = tmp_sym_match;
+               sym_match_arr[cnt].so = match[0].rm_so;
+               sym_match_arr[cnt].eo = match[0].rm_eo;
+               sym_match_arr[cnt++].sym = sym;
        }
        if (sym_match_arr) {
-               qsort(sym_match_arr, cnt, sizeof(struct sym_match*), sym_rel_comp);
+               qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp);
                sym_arr = malloc((cnt+1) * sizeof(struct symbol));
                if (!sym_arr)
                        goto sym_re_search_free;
                for (i = 0; i < cnt; i++)
-                       sym_arr[i] = sym_match_arr[i]->sym;
+                       sym_arr[i] = sym_match_arr[i].sym;
                sym_arr[cnt] = NULL;
        }
 sym_re_search_free:
-       if (sym_match_arr) {
-               for (i = 0; i < cnt; i++)
-                       free(sym_match_arr[i]);
-               free(sym_match_arr);
-       }
+       /* sym_match_arr can be NULL if no match, but free(NULL) is OK */
+       free(sym_match_arr);
        regfree(&re);
 
        return sym_arr;
index f636141e7bfd73526569bb96d300faba322761fe..25ae16ac75c85853e24733eb754bc514ba6eb419 100644 (file)
@@ -1,9 +1,8 @@
-/* A Bison parser, made by GNU Bison 2.4.3.  */
+/* A Bison parser, made by GNU Bison 2.5.  */
 
-/* Skeleton implementation for Bison's Yacc-like parsers in C
+/* Bison implementation for Yacc-like parsers in C
    
-      Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-   2009, 2010 Free Software Foundation, Inc.
+      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, 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
@@ -45,7 +44,7 @@
 #define YYBISON 1
 
 /* Bison version.  */
-#define YYBISON_VERSION "2.4.3"
+#define YYBISON_VERSION "2.5"
 
 /* Skeleton name.  */
 #define YYSKELETON_NAME "yacc.c"
@@ -302,11 +301,11 @@ YYID (yyi)
 #    define alloca _alloca
 #   else
 #    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 #     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
+#     ifndef EXIT_SUCCESS
+#      define EXIT_SUCCESS 0
 #     endif
 #    endif
 #   endif
@@ -329,24 +328,24 @@ YYID (yyi)
 #  ifndef YYSTACK_ALLOC_MAXIMUM
 #   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
 #  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
        && ! ((defined YYMALLOC || defined malloc) \
             && (defined YYFREE || defined free)))
 #   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
 #   endif
 #  endif
 #  ifndef YYMALLOC
 #   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
 #   endif
 #  endif
 #  ifndef YYFREE
 #   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
      || defined __cplusplus || defined _MSC_VER)
 void free (void *); /* INFRINGES ON USER NAME SPACE */
 #   endif
@@ -375,23 +374,7 @@ union yyalloc
      ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
       + YYSTACK_GAP_MAXIMUM)
 
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)             \
-      do                                       \
-       {                                       \
-         YYSIZE_T yyi;                         \
-         for (yyi = 0; yyi < (Count); yyi++)   \
-           (To)[yyi] = (From)[yyi];            \
-       }                                       \
-      while (YYID (0))
-#  endif
-# endif
+# define YYCOPY_NEEDED 1
 
 /* Relocate STACK from its old location to the new one.  The
    local variables YYSIZE and YYSTACKSIZE give the old and new number of
@@ -411,6 +394,26 @@ union yyalloc
 
 #endif
 
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)             \
+      do                                       \
+       {                                       \
+         YYSIZE_T yyi;                         \
+         for (yyi = 0; yyi < (Count); yyi++)   \
+           (To)[yyi] = (From)[yyi];            \
+       }                                       \
+      while (YYID (0))
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
 /* YYFINAL -- State number of the termination state.  */
 #define YYFINAL  11
 /* YYLAST -- Last index in YYTABLE.  */
@@ -529,18 +532,18 @@ static const yytype_int8 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   104,   104,   104,   106,   106,   108,   110,   111,   112,
-     113,   114,   115,   119,   123,   123,   123,   123,   123,   123,
-     123,   123,   127,   128,   129,   130,   131,   132,   136,   137,
-     143,   151,   157,   165,   175,   177,   178,   179,   180,   181,
-     182,   185,   193,   199,   209,   215,   221,   224,   226,   237,
-     238,   243,   252,   257,   265,   268,   270,   271,   272,   273,
-     274,   277,   283,   294,   300,   310,   312,   317,   325,   333,
-     336,   338,   339,   340,   345,   352,   359,   364,   372,   375,
-     377,   378,   379,   382,   390,   397,   404,   410,   417,   419,
-     420,   421,   424,   432,   434,   435,   438,   445,   447,   452,
-     453,   456,   457,   458,   462,   463,   466,   467,   470,   471,
-     472,   473,   474,   475,   476,   479,   480,   483,   484
+       0,   103,   103,   103,   105,   105,   107,   109,   110,   111,
+     112,   113,   114,   118,   122,   122,   122,   122,   122,   122,
+     122,   122,   126,   127,   128,   129,   130,   131,   135,   136,
+     142,   150,   156,   164,   174,   176,   177,   178,   179,   180,
+     181,   184,   192,   198,   208,   214,   220,   223,   225,   236,
+     237,   242,   251,   256,   264,   267,   269,   270,   271,   272,
+     273,   276,   282,   293,   299,   309,   311,   316,   324,   332,
+     335,   337,   338,   339,   344,   351,   358,   363,   371,   374,
+     376,   377,   378,   381,   389,   396,   403,   409,   416,   418,
+     419,   420,   423,   431,   433,   434,   437,   444,   446,   451,
+     452,   455,   456,   457,   461,   462,   465,   466,   469,   470,
+     471,   472,   473,   474,   475,   478,   479,   482,   483
 };
 #endif
 
@@ -615,8 +618,8 @@ static const yytype_uint8 yyr2[] =
        3,     3,     2,     3,     3,     1,     1,     0,     1
 };
 
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+   Performed when YYTABLE doesn't specify something else to do.  Zero
    means the default is an error.  */
 static const yytype_uint8 yydefact[] =
 {
@@ -691,8 +694,7 @@ static const yytype_int16 yypgoto[] =
 
 /* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
    positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
+   number is the opposite.  If YYTABLE_NINF, syntax error.  */
 #define YYTABLE_NINF -86
 static const yytype_int16 yytable[] =
 {
@@ -728,6 +730,12 @@ static const yytype_int16 yytable[] =
      184
 };
 
+#define yypact_value_is_default(yystate) \
+  ((yystate) == (-90))
+
+#define yytable_value_is_error(yytable_value) \
+  YYID (0)
+
 static const yytype_int16 yycheck[] =
 {
        1,    67,    68,    10,    93,    94,    76,     3,    76,    14,
@@ -821,7 +829,6 @@ do                                                          \
     {                                                          \
       yychar = (Token);                                                \
       yylval = (Value);                                                \
-      yytoken = YYTRANSLATE (yychar);                          \
       YYPOPSTACK (1);                                          \
       goto yybackup;                                           \
     }                                                          \
@@ -863,19 +870,10 @@ while (YYID (0))
 #endif
 
 
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
+/* This macro is provided for backward compatibility. */
 
 #ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)                 \
-     fprintf (File, "%d.%d-%d.%d",                     \
-             (Loc).first_line, (Loc).first_column,     \
-             (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
 #endif
 
 
@@ -1067,7 +1065,6 @@ int yydebug;
 # define YYMAXDEPTH 10000
 #endif
 
-\f
 
 #if YYERROR_VERBOSE
 
@@ -1170,115 +1167,142 @@ yytnamerr (char *yyres, const char *yystr)
 }
 # endif
 
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+   about the unexpected token YYTOKEN for the state stack whose top is
+   YYSSP.
 
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
+   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
+   not large enough to hold the message.  In that case, also set
+   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
+   required number of bytes is too large to store.  */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+                yytype_int16 *yyssp, int yytoken)
+{
+  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  YYSIZE_T yysize1;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  const char *yyformat = 0;
+  /* Arguments of yyformat. */
+  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+  /* Number of reported tokens (one for the "unexpected", one per
+     "expected"). */
+  int yycount = 0;
+
+  /* There are many possibilities here to consider:
+     - Assume YYFAIL is not used.  It's too flawed to consider.  See
+       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+       for details.  YYERROR is fine as it does not invoke this
+       function.
+     - If this state is a consistent state with a default action, then
+       the only way this function was invoked is if the default action
+       is an error action.  In that case, don't check for expected
+       tokens because there are none.
+     - The only way there can be no lookahead present (in yychar) is if
+       this state is a consistent state with a default action.  Thus,
+       detecting the absence of a lookahead is sufficient to determine
+       that there is no unexpected or expected token to report.  In that
+       case, just report a simple "syntax error".
+     - Don't assume there isn't a lookahead just because this state is a
+       consistent state with a default action.  There might have been a
+       previous inconsistent state, consistent state with a non-default
+       action, or user semantic action that manipulated yychar.
+     - Of course, the expected token list depends on states to have
+       correct lookahead information, and it depends on the parser not
+       to perform extra reductions after fetching a lookahead from the
+       scanner and before detecting a syntax error.  Thus, state merging
+       (from LALR or IELR) and default reductions corrupt the expected
+       token list.  However, the list is correct for canonical LR with
+       one exception: it will still contain any token that will not be
+       accepted due to an error action in a later state.
+  */
+  if (yytoken != YYEMPTY)
     {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-        constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-                   + sizeof yyexpecting - 1
-                   + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-                      * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-        YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-       if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-         {
-           if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-             {
-               yycount = 1;
-               yysize = yysize0;
-               yyformat[sizeof yyunexpected - 1] = '\0';
-               break;
-             }
-           yyarg[yycount++] = yytname[yyx];
-           yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-           yysize_overflow |= (yysize1 < yysize);
-           yysize = yysize1;
-           yyfmt = yystpcpy (yyfmt, yyprefix);
-           yyprefix = yyor;
-         }
+      int yyn = yypact[*yyssp];
+      yyarg[yycount++] = yytname[yytoken];
+      if (!yypact_value_is_default (yyn))
+        {
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  In other words, skip the first -YYN actions for
+             this state because they are default actions.  */
+          int yyxbegin = yyn < 0 ? -yyn : 0;
+          /* Stay within bounds of both yycheck and yytname.  */
+          int yychecklim = YYLAST - yyn + 1;
+          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+          int yyx;
+
+          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+                && !yytable_value_is_error (yytable[yyx + yyn]))
+              {
+                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+                  {
+                    yycount = 1;
+                    yysize = yysize0;
+                    break;
+                  }
+                yyarg[yycount++] = yytname[yyx];
+                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
+                if (! (yysize <= yysize1
+                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                  return 2;
+                yysize = yysize1;
+              }
+        }
+    }
 
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
+  switch (yycount)
+    {
+# define YYCASE_(N, S)                      \
+      case N:                               \
+        yyformat = S;                       \
+      break
+      YYCASE_(0, YY_("syntax error"));
+      YYCASE_(1, YY_("syntax error, unexpected %s"));
+      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+    }
 
-      if (yysize_overflow)
-       return YYSIZE_MAXIMUM;
+  yysize1 = yysize + yystrlen (yyformat);
+  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+    return 2;
+  yysize = yysize1;
 
-      if (yyresult)
-       {
-         /* Avoid sprintf, as that infringes on the user's name space.
-            Don't have undefined behavior even if the translation
-            produced a string with the wrong number of "%s"s.  */
-         char *yyp = yyresult;
-         int yyi = 0;
-         while ((*yyp = *yyf) != '\0')
-           {
-             if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-               {
-                 yyp += yytnamerr (yyp, yyarg[yyi++]);
-                 yyf += 2;
-               }
-             else
-               {
-                 yyp++;
-                 yyf++;
-               }
-           }
-       }
-      return yysize;
+  if (*yymsg_alloc < yysize)
+    {
+      *yymsg_alloc = 2 * yysize;
+      if (! (yysize <= *yymsg_alloc
+             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+      return 1;
     }
+
+  /* Avoid sprintf, as that infringes on the user's name space.
+     Don't have undefined behavior even if the translation
+     produced a string with the wrong number of "%s"s.  */
+  {
+    char *yyp = *yymsg;
+    int yyi = 0;
+    while ((*yyp = *yyformat) != '\0')
+      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+        {
+          yyp += yytnamerr (yyp, yyarg[yyi++]);
+          yyformat += 2;
+        }
+      else
+        {
+          yyp++;
+          yyformat++;
+        }
+  }
+  return 0;
 }
 #endif /* YYERROR_VERBOSE */
-\f
 
 /*-----------------------------------------------.
 | Release the memory associated to this symbol.  |
@@ -1341,6 +1365,7 @@ yydestruct (yymsg, yytype, yyvaluep)
     }
 }
 
+
 /* Prevent warnings from -Wmissing-prototypes.  */
 #ifdef YYPARSE_PARAM
 #if defined __STDC__ || defined __cplusplus
@@ -1367,10 +1392,9 @@ YYSTYPE yylval;
 int yynerrs;
 
 
-
-/*-------------------------.
-| yyparse or yypush_parse.  |
-`-------------------------*/
+/*----------.
+| yyparse.  |
+`----------*/
 
 #ifdef YYPARSE_PARAM
 #if (defined __STDC__ || defined __C99__FUNC__ \
@@ -1394,8 +1418,6 @@ yyparse ()
 #endif
 #endif
 {
-
-
     int yystate;
     /* Number of tokens to shift before error messages enabled.  */
     int yyerrstatus;
@@ -1550,7 +1572,7 @@ yybackup:
 
   /* First try to decide what to do without reference to lookahead token.  */
   yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
+  if (yypact_value_is_default (yyn))
     goto yydefault;
 
   /* Not known => get a lookahead token if don't already have one.  */
@@ -1581,8 +1603,8 @@ yybackup:
   yyn = yytable[yyn];
   if (yyn <= 0)
     {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-       goto yyerrlab;
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
@@ -1637,34 +1659,34 @@ yyreduce:
     {
         case 10:
 
-    { zconf_error("unexpected end statement"); ;}
+    { zconf_error("unexpected end statement"); }
     break;
 
   case 11:
 
-    { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); ;}
+    { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); }
     break;
 
   case 12:
 
     {
        zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name);
-;}
+}
     break;
 
   case 13:
 
-    { zconf_error("invalid statement"); ;}
+    { zconf_error("invalid statement"); }
     break;
 
   case 28:
 
-    { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); ;}
+    { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); }
     break;
 
   case 29:
 
-    { zconf_error("invalid option"); ;}
+    { zconf_error("invalid option"); }
     break;
 
   case 30:
@@ -1674,7 +1696,7 @@ yyreduce:
        sym->flags |= SYMBOL_OPTIONAL;
        menu_add_entry(sym);
        printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
-;}
+}
     break;
 
   case 31:
@@ -1682,7 +1704,7 @@ yyreduce:
     {
        menu_end_entry();
        printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 32:
@@ -1692,7 +1714,7 @@ yyreduce:
        sym->flags |= SYMBOL_OPTIONAL;
        menu_add_entry(sym);
        printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
-;}
+}
     break;
 
   case 33:
@@ -1704,7 +1726,7 @@ yyreduce:
                zconfprint("warning: menuconfig statement without prompt");
        menu_end_entry();
        printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 41:
@@ -1714,7 +1736,7 @@ yyreduce:
        printd(DEBUG_PARSE, "%s:%d:type(%u)\n",
                zconf_curname(), zconf_lineno(),
                (yyvsp[(1) - (3)].id)->stype);
-;}
+}
     break;
 
   case 42:
@@ -1722,7 +1744,7 @@ yyreduce:
     {
        menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
        printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 43:
@@ -1734,7 +1756,7 @@ yyreduce:
        printd(DEBUG_PARSE, "%s:%d:default(%u)\n",
                zconf_curname(), zconf_lineno(),
                (yyvsp[(1) - (4)].id)->stype);
-;}
+}
     break;
 
   case 44:
@@ -1742,7 +1764,7 @@ yyreduce:
     {
        menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr));
        printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 45:
@@ -1750,7 +1772,7 @@ yyreduce:
     {
        menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr));
        printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 48:
@@ -1762,17 +1784,17 @@ yyreduce:
        else
                zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string));
        free((yyvsp[(2) - (3)].string));
-;}
+}
     break;
 
   case 49:
 
-    { (yyval.string) = NULL; ;}
+    { (yyval.string) = NULL; }
     break;
 
   case 50:
 
-    { (yyval.string) = (yyvsp[(2) - (2)].string); ;}
+    { (yyval.string) = (yyvsp[(2) - (2)].string); }
     break;
 
   case 51:
@@ -1783,14 +1805,14 @@ yyreduce:
        menu_add_entry(sym);
        menu_add_expr(P_CHOICE, NULL, NULL);
        printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 52:
 
     {
        (yyval.menu) = menu_add_menu();
-;}
+}
     break;
 
   case 53:
@@ -1800,7 +1822,7 @@ yyreduce:
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
        }
-;}
+}
     break;
 
   case 61:
@@ -1808,7 +1830,7 @@ yyreduce:
     {
        menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr));
        printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 62:
@@ -1821,7 +1843,7 @@ yyreduce:
                        (yyvsp[(1) - (3)].id)->stype);
        } else
                YYERROR;
-;}
+}
     break;
 
   case 63:
@@ -1829,7 +1851,7 @@ yyreduce:
     {
        current_entry->sym->flags |= SYMBOL_OPTIONAL;
        printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 64:
@@ -1841,7 +1863,7 @@ yyreduce:
                        zconf_curname(), zconf_lineno());
        } else
                YYERROR;
-;}
+}
     break;
 
   case 67:
@@ -1851,7 +1873,7 @@ yyreduce:
        menu_add_entry(NULL);
        menu_add_dep((yyvsp[(2) - (3)].expr));
        (yyval.menu) = menu_add_menu();
-;}
+}
     break;
 
   case 68:
@@ -1861,14 +1883,14 @@ yyreduce:
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
        }
-;}
+}
     break;
 
   case 74:
 
     {
        menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
-;}
+}
     break;
 
   case 75:
@@ -1877,14 +1899,14 @@ yyreduce:
        menu_add_entry(NULL);
        menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL);
        printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 76:
 
     {
        (yyval.menu) = menu_add_menu();
-;}
+}
     break;
 
   case 77:
@@ -1894,7 +1916,7 @@ yyreduce:
                menu_end_menu();
                printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
        }
-;}
+}
     break;
 
   case 83:
@@ -1902,7 +1924,7 @@ yyreduce:
     {
        printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string));
        zconf_nextfile((yyvsp[(2) - (3)].string));
-;}
+}
     break;
 
   case 84:
@@ -1911,14 +1933,14 @@ yyreduce:
        menu_add_entry(NULL);
        menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL);
        printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 85:
 
     {
        menu_end_entry();
-;}
+}
     break;
 
   case 86:
@@ -1926,14 +1948,14 @@ yyreduce:
     {
        printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
        zconf_starthelp();
-;}
+}
     break;
 
   case 87:
 
     {
        current_entry->help = (yyvsp[(2) - (2)].string);
-;}
+}
     break;
 
   case 92:
@@ -1941,102 +1963,113 @@ yyreduce:
     {
        menu_add_dep((yyvsp[(3) - (4)].expr));
        printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
-;}
+}
     break;
 
   case 96:
 
     {
        menu_add_visibility((yyvsp[(2) - (2)].expr));
-;}
+}
     break;
 
   case 98:
 
     {
        menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr));
-;}
+}
     break;
 
   case 101:
 
-    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    { (yyval.id) = (yyvsp[(1) - (2)].id); }
     break;
 
   case 102:
 
-    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    { (yyval.id) = (yyvsp[(1) - (2)].id); }
     break;
 
   case 103:
 
-    { (yyval.id) = (yyvsp[(1) - (2)].id); ;}
+    { (yyval.id) = (yyvsp[(1) - (2)].id); }
     break;
 
   case 106:
 
-    { (yyval.expr) = NULL; ;}
+    { (yyval.expr) = NULL; }
     break;
 
   case 107:
 
-    { (yyval.expr) = (yyvsp[(2) - (2)].expr); ;}
+    { (yyval.expr) = (yyvsp[(2) - (2)].expr); }
     break;
 
   case 108:
 
-    { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); ;}
+    { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); }
     break;
 
   case 109:
 
-    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
     break;
 
   case 110:
 
-    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); ;}
+    { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); }
     break;
 
   case 111:
 
-    { (yyval.expr) = (yyvsp[(2) - (3)].expr); ;}
+    { (yyval.expr) = (yyvsp[(2) - (3)].expr); }
     break;
 
   case 112:
 
-    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); ;}
+    { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); }
     break;
 
   case 113:
 
-    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); }
     break;
 
   case 114:
 
-    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); ;}
+    { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); }
     break;
 
   case 115:
 
-    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); ;}
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); }
     break;
 
   case 116:
 
-    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); ;}
+    { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); }
     break;
 
   case 117:
 
-    { (yyval.string) = NULL; ;}
+    { (yyval.string) = NULL; }
     break;
 
 
 
       default: break;
     }
+  /* User semantic actions sometimes alter yychar, and that requires
+     that yytoken be updated with the new translation.  We take the
+     approach of translating immediately before every use of yytoken.
+     One alternative is translating here after every semantic action,
+     but that translation would be missed if the semantic action invokes
+     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
+     incorrect destructor might then be invoked immediately.  In the
+     case of YYERROR or YYBACKUP, subsequent parser actions might lead
+     to an incorrect destructor call or verbose syntax error message
+     before the lookahead is translated.  */
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
 
   YYPOPSTACK (yylen);
@@ -2064,6 +2097,10 @@ yyreduce:
 | yyerrlab -- here on detecting error |
 `------------------------------------*/
 yyerrlab:
+  /* Make sure we have latest lookahead translation.  See comments at
+     user semantic actions for why this is necessary.  */
+  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
   /* If not already recovering from an error, report this error.  */
   if (!yyerrstatus)
     {
@@ -2071,37 +2108,36 @@ yyerrlab:
 #if ! YYERROR_VERBOSE
       yyerror (YY_("syntax error"));
 #else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+                                        yyssp, yytoken)
       {
-       YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-       if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-         {
-           YYSIZE_T yyalloc = 2 * yysize;
-           if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-             yyalloc = YYSTACK_ALLOC_MAXIMUM;
-           if (yymsg != yymsgbuf)
-             YYSTACK_FREE (yymsg);
-           yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-           if (yymsg)
-             yymsg_alloc = yyalloc;
-           else
-             {
-               yymsg = yymsgbuf;
-               yymsg_alloc = sizeof yymsgbuf;
-             }
-         }
-
-       if (0 < yysize && yysize <= yymsg_alloc)
-         {
-           (void) yysyntax_error (yymsg, yystate, yychar);
-           yyerror (yymsg);
-         }
-       else
-         {
-           yyerror (YY_("syntax error"));
-           if (yysize != 0)
-             goto yyexhaustedlab;
-         }
+        char const *yymsgp = YY_("syntax error");
+        int yysyntax_error_status;
+        yysyntax_error_status = YYSYNTAX_ERROR;
+        if (yysyntax_error_status == 0)
+          yymsgp = yymsg;
+        else if (yysyntax_error_status == 1)
+          {
+            if (yymsg != yymsgbuf)
+              YYSTACK_FREE (yymsg);
+            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+            if (!yymsg)
+              {
+                yymsg = yymsgbuf;
+                yymsg_alloc = sizeof yymsgbuf;
+                yysyntax_error_status = 2;
+              }
+            else
+              {
+                yysyntax_error_status = YYSYNTAX_ERROR;
+                yymsgp = yymsg;
+              }
+          }
+        yyerror (yymsgp);
+        if (yysyntax_error_status == 2)
+          goto yyexhaustedlab;
       }
+# undef YYSYNTAX_ERROR
 #endif
     }
 
@@ -2160,7 +2196,7 @@ yyerrlab1:
   for (;;)
     {
       yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
+      if (!yypact_value_is_default (yyn))
        {
          yyn += YYTERROR;
          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
@@ -2219,8 +2255,13 @@ yyexhaustedlab:
 
 yyreturn:
   if (yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-                yytoken, &yylval);
+    {
+      /* Make sure we have latest lookahead translation.  See comments at
+         user semantic actions for why this is necessary.  */
+      yytoken = YYTRANSLATE (yychar);
+      yydestruct ("Cleanup: discarding lookahead",
+                  yytoken, &yylval);
+    }
   /* Do not reclaim the symbols of the rule which action triggered
      this YYABORT or YYACCEPT.  */
   YYPOPSTACK (yylen);
@@ -2256,9 +2297,6 @@ void conf_parse(const char *name)
 
        sym_init();
        _menu_init();
-       modules_sym = sym_lookup(NULL, 0);
-       modules_sym->type = S_BOOLEAN;
-       modules_sym->flags |= SYMBOL_AUTO;
        rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
        if (getenv("ZCONF_DEBUG"))
@@ -2266,12 +2304,8 @@ void conf_parse(const char *name)
        zconfparse();
        if (zconfnerrs)
                exit(1);
-       if (!modules_sym->prop) {
-               struct property *prop;
-
-               prop = prop_alloc(P_DEFAULT, modules_sym);
-               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
-       }
+       if (!modules_sym)
+               modules_sym = sym_find( "n" );
 
        rootmenu.prompt->text = _(rootmenu.prompt->text);
        rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
index 864da07ba4aadc02a71a0e4b8414ef330f570674..0653886fac4810b0989af918708f4dbfd39f145b 100644 (file)
@@ -493,9 +493,6 @@ void conf_parse(const char *name)
 
        sym_init();
        _menu_init();
-       modules_sym = sym_lookup(NULL, 0);
-       modules_sym->type = S_BOOLEAN;
-       modules_sym->flags |= SYMBOL_AUTO;
        rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL);
 
        if (getenv("ZCONF_DEBUG"))
@@ -503,12 +500,8 @@ void conf_parse(const char *name)
        zconfparse();
        if (zconfnerrs)
                exit(1);
-       if (!modules_sym->prop) {
-               struct property *prop;
-
-               prop = prop_alloc(P_DEFAULT, modules_sym);
-               prop->expr = expr_alloc_symbol(sym_lookup("MODULES", 0));
-       }
+       if (!modules_sym)
+               modules_sym = sym_find( "n" );
 
        rootmenu.prompt->text = _(rootmenu.prompt->text);
        rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text);
index acb86507828aaba1304594588959fbfc2804c528..90e521fde35fa827cf5008838024ef1bf1d03a88 100644 (file)
@@ -41,9 +41,9 @@ create_package() {
        parisc*)
                debarch=hppa ;;
        mips*)
-               debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y .config && echo el) ;;
+               debarch=mips$(grep -q CPU_LITTLE_ENDIAN=y $KCONFIG_CONFIG && echo el) ;;
        arm*)
-               debarch=arm$(grep -q CONFIG_AEABI=y .config && echo el) ;;
+               debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el) ;;
        *)
                echo "" >&2
                echo "** ** **  WARNING  ** ** **" >&2
@@ -78,17 +78,35 @@ tmpdir="$objtree/debian/tmp"
 fwdir="$objtree/debian/fwtmp"
 kernel_headers_dir="$objtree/debian/hdrtmp"
 libc_headers_dir="$objtree/debian/headertmp"
+dbg_dir="$objtree/debian/dbgtmp"
 packagename=linux-image-$version
-fwpackagename=linux-firmware-image
+fwpackagename=linux-firmware-image-$version
 kernel_headers_packagename=linux-headers-$version
 libc_headers_packagename=linux-libc-dev
+dbg_packagename=$packagename-dbg
 
 if [ "$ARCH" = "um" ] ; then
        packagename=user-mode-linux-$version
 fi
 
+# Not all arches have the same installed path in debian
+# XXX: have each arch Makefile export a variable of the canonical image install
+# path instead
+case $ARCH in
+um)
+       installed_image_path="usr/bin/linux-$version"
+       ;;
+parisc|mips|powerpc)
+       installed_image_path="boot/vmlinux-$version"
+       ;;
+*)
+       installed_image_path="boot/vmlinuz-$version"
+esac
+
+BUILD_DEBUG="$(grep -s '^CONFIG_DEBUG_INFO=y' $KCONFIG_CONFIG || true)"
+
 # Setup the directory structure
-rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir"
+rm -rf "$tmpdir" "$fwdir" "$kernel_headers_dir" "$libc_headers_dir" "$dbg_dir"
 mkdir -m 755 -p "$tmpdir/DEBIAN"
 mkdir -p  "$tmpdir/lib" "$tmpdir/boot" "$tmpdir/usr/share/doc/$packagename"
 mkdir -m 755 -p "$fwdir/DEBIAN"
@@ -101,26 +119,29 @@ mkdir -p "$kernel_headers_dir/lib/modules/$version/"
 if [ "$ARCH" = "um" ] ; then
        mkdir -p "$tmpdir/usr/lib/uml/modules/$version" "$tmpdir/usr/bin"
 fi
+if [ -n "$BUILD_DEBUG" ] ; then
+       mkdir -p "$dbg_dir/usr/share/doc/$dbg_packagename"
+       mkdir -m 755 -p "$dbg_dir/DEBIAN"
+fi
 
 # Build and install the kernel
 if [ "$ARCH" = "um" ] ; then
        $MAKE linux
        cp System.map "$tmpdir/usr/lib/uml/modules/$version/System.map"
-       cp .config "$tmpdir/usr/share/doc/$packagename/config"
+       cp $KCONFIG_CONFIG "$tmpdir/usr/share/doc/$packagename/config"
        gzip "$tmpdir/usr/share/doc/$packagename/config"
-       cp $KBUILD_IMAGE "$tmpdir/usr/bin/linux-$version"
 else 
        cp System.map "$tmpdir/boot/System.map-$version"
-       cp .config "$tmpdir/boot/config-$version"
-       # Not all arches include the boot path in KBUILD_IMAGE
-       if [ -e $KBUILD_IMAGE ]; then
-               cp $KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
-       else
-               cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/boot/vmlinuz-$version"
-       fi
+       cp $KCONFIG_CONFIG "$tmpdir/boot/config-$version"
+fi
+# Not all arches include the boot path in KBUILD_IMAGE
+if [ -e $KBUILD_IMAGE ]; then
+       cp $KBUILD_IMAGE "$tmpdir/$installed_image_path"
+else
+       cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/$installed_image_path"
 fi
 
-if grep -q '^CONFIG_MODULES=y' .config ; then
+if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then
        INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install
        rm -f "$tmpdir/lib/modules/$version/build"
        rm -f "$tmpdir/lib/modules/$version/source"
@@ -128,6 +149,20 @@ if grep -q '^CONFIG_MODULES=y' .config ; then
                mv "$tmpdir/lib/modules/$version"/* "$tmpdir/usr/lib/uml/modules/$version/"
                rmdir "$tmpdir/lib/modules/$version"
        fi
+       if [ -n "$BUILD_DEBUG" ] ; then
+               (
+                       cd $tmpdir
+                       for module in $(find lib/modules/ -name *.ko); do
+                               mkdir -p $(dirname $dbg_dir/usr/lib/debug/$module)
+                               # only keep debug symbols in the debug file
+                               objcopy --only-keep-debug $module $dbg_dir/usr/lib/debug/$module
+                               # strip original module from debug symbols
+                               objcopy --strip-debug $module
+                               # then add a link to those
+                               objcopy --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $module
+                       done
+               )
+       fi
 fi
 
 if [ "$ARCH" != "um" ]; then
@@ -149,7 +184,7 @@ set -e
 # Pass maintainer script parameters to hook scripts
 export DEB_MAINT_PARAMS="\$*"
 
-test -d $debhookdir/$script.d && run-parts --arg="$version" $debhookdir/$script.d
+test -d $debhookdir/$script.d && run-parts --arg="$version" --arg="/$installed_image_path" $debhookdir/$script.d
 exit 0
 EOF
        chmod 755 "$tmpdir/DEBIAN/$script"
@@ -245,11 +280,12 @@ fi
 # Build header package
 (cd $srctree; find . -name Makefile\* -o -name Kconfig\* -o -name \*.pl > "$objtree/debian/hdrsrcfiles")
 (cd $srctree; find arch/$SRCARCH/include include scripts -type f >> "$objtree/debian/hdrsrcfiles")
-(cd $objtree; find arch/$SRCARCH/include .config Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles")
+(cd $objtree; find arch/$SRCARCH/include Module.symvers include scripts -type f >> "$objtree/debian/hdrobjfiles")
 destdir=$kernel_headers_dir/usr/src/linux-headers-$version
 mkdir -p "$destdir"
 (cd $srctree; tar -c -f - -T "$objtree/debian/hdrsrcfiles") | (cd $destdir; tar -xf -)
 (cd $objtree; tar -c -f - -T "$objtree/debian/hdrobjfiles") | (cd $destdir; tar -xf -)
+(cd $objtree; cp $KCONFIG_CONFIG $destdir/.config) # copy .config manually to be where it's expected to be
 ln -sf "/usr/src/linux-headers-$version" "$kernel_headers_dir/lib/modules/$version/build"
 rm -f "$objtree/debian/hdrsrcfiles" "$objtree/debian/hdrobjfiles"
 arch=$(dpkg --print-architecture)
@@ -299,4 +335,30 @@ fi
 
 create_package "$packagename" "$tmpdir"
 
+if [ -n "$BUILD_DEBUG" ] ; then
+       # Build debug package
+       # Different tools want the image in different locations
+       # perf
+       mkdir -p $dbg_dir/usr/lib/debug/lib/modules/$version/
+       cp vmlinux $dbg_dir/usr/lib/debug/lib/modules/$version/
+       # systemtap
+       mkdir -p $dbg_dir/usr/lib/debug/boot/
+       ln -s ../lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/boot/vmlinux-$version
+       # kdump-tools
+       ln -s lib/modules/$version/vmlinux $dbg_dir/usr/lib/debug/vmlinux-$version
+
+       cat <<EOF >> debian/control
+
+Package: $dbg_packagename
+Section: debug
+Provides: linux-debug, linux-debug-$version
+Architecture: any
+Description: Linux kernel debugging symbols for $version
+ This package will come in handy if you need to debug the kernel. It provides
+ all the necessary debug symbols for the kernel and its modules.
+EOF
+
+       create_package "$dbg_packagename" "$dbg_dir"
+fi
+
 exit 0
index cdd9bb909bcda05efd16ba21f6700316194f6116..aa22f9447ddc2492bfee4241a1380bc4fb91a735 100644 (file)
@@ -87,6 +87,27 @@ case "${ARCH}" in
                [ -f "${objtree}/vmlinux.SYS" ] && cp -v -- "${objtree}/vmlinux.SYS" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.SYS"
                [ -f "${objtree}/vmlinux.dsk" ] && cp -v -- "${objtree}/vmlinux.dsk" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}.dsk"
                ;;
+       mips)
+               if [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.bin" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.bin" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.ecoff" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/compressed/vmlinux.srec" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/compressed/vmlinux.srec" "${tmpdir}/boot/vmlinuz-${KERNELRELEASE}"
+               elif [ -f "${objtree}/vmlinux.32" ]; then
+                       cp -v -- "${objtree}/vmlinux.32" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/vmlinux.64" ]; then
+                       cp -v -- "${objtree}/vmlinux.64" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/vmlinux.bin" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/vmlinux.bin" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/vmlinux.ecoff" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/vmlinux.ecoff" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/arch/mips/boot/vmlinux.srec" ]; then
+                       cp -v -- "${objtree}/arch/mips/boot/vmlinux.srec" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               elif [ -f "${objtree}/vmlinux" ]; then
+                       cp -v -- "${objtree}/vmlinux" "${tmpdir}/boot/vmlinux-${KERNELRELEASE}"
+               fi
+               ;;
        *)
                [ -f "${KBUILD_IMAGE}" ] && cp -v -- "${KBUILD_IMAGE}" "${tmpdir}/boot/vmlinux-kbuild-${KERNELRELEASE}"
                echo "" >&2
index fdd3fbf4d4a41a0d8bab7b93d5fb6f4c7896f94d..13957602f7ca5eb190170450b79ff877cd0cb3af 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/sh
 #
-#      Output a simple RPM spec file that uses no fancy features requiring
-#      RPM v4. This is intended to work with any RPM distro.
+#      Output a simple RPM spec file.
+#      This version assumes a minimum of RPM 4.0.3.
 #
 #      The only gothic bit here is redefining install_post to avoid
 #      stripping the symbols from files in the kernel which we want
@@ -59,6 +59,14 @@ echo "header files define structures and constants that are needed for"
 echo "building most standard programs and are also needed for rebuilding the"
 echo "glibc package."
 echo ""
+echo "%package devel"
+echo "Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel"
+echo "Group: System Environment/Kernel"
+echo "AutoReqProv: no"
+echo "%description -n kernel-devel"
+echo "This package provides kernel headers and makefiles sufficient to build modules"
+echo "against the $__KERNELRELEASE kernel package."
+echo ""
 
 if ! $PREBUILT; then
 echo "%prep"
@@ -77,13 +85,14 @@ echo "%install"
 echo 'KBUILD_IMAGE=$(make image_name)'
 echo "%ifarch ia64"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
-echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
 echo "%else"
 echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
-echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
 echo "%endif"
+echo 'mkdir -p $RPM_BUILD_ROOT'"/lib/firmware/$KERNELRELEASE"
 
-echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= modules_install'
+echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= mod-fw= modules_install'
+echo 'INSTALL_FW_PATH=$RPM_BUILD_ROOT'"/lib/firmware/$KERNELRELEASE"
+echo 'make INSTALL_FW_PATH=$INSTALL_FW_PATH' firmware_install
 echo "%ifarch ia64"
 echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
 echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
@@ -108,18 +117,43 @@ echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2"
 echo 'mv vmlinux.orig vmlinux'
 echo "%endif"
 
+echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/{build,source}"
+echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE"
+echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude=firmware --exclude .config.old --exclude .missing-syscalls.d\""
+echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)"
+echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE"
+echo "ln -sf /usr/src/kernels/$KERNELRELEASE build"
+echo "ln -sf /usr/src/kernels/$KERNELRELEASE source"
+
 echo ""
 echo "%clean"
 echo 'rm -rf $RPM_BUILD_ROOT'
 echo ""
+echo "%post"
+echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then"
+echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm"
+echo "cp /boot/System.map-$KERNELRELEASE /boot/System.map-$KERNELRELEASE-rpm"
+echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE"
+echo "/sbin/installkernel $KERNELRELEASE /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
+echo "rm -f /boot/vmlinuz-$KERNELRELEASE-rpm /boot/System.map-$KERNELRELEASE-rpm"
+echo "fi"
+echo ""
 echo "%files"
 echo '%defattr (-, root, root)'
 echo "%dir /lib/modules"
 echo "/lib/modules/$KERNELRELEASE"
-echo "/lib/firmware"
+echo "%exclude /lib/modules/$KERNELRELEASE/build"
+echo "%exclude /lib/modules/$KERNELRELEASE/source"
+echo "/lib/firmware/$KERNELRELEASE"
 echo "/boot/*"
 echo ""
 echo "%files headers"
 echo '%defattr (-, root, root)'
 echo "/usr/include"
 echo ""
+echo "%files devel"
+echo '%defattr (-, root, root)'
+echo "/usr/src/kernels/$KERNELRELEASE"
+echo "/lib/modules/$KERNELRELEASE/build"
+echo "/lib/modules/$KERNELRELEASE/source"
+echo ""
index f9ce1160419be2a81b7dabf097fc453fdb1ce9c3..7c2310c5b996dee9d43df56574b30236342c3c81 100644 (file)
@@ -64,14 +64,6 @@ fail_file(void)
        longjmp(jmpenv, SJ_FAIL);
 }
 
-static void __attribute__((noreturn))
-succeed_file(void)
-{
-       cleanup();
-       longjmp(jmpenv, SJ_SUCCEED);
-}
-
-
 /*
  * Get the whole file as a programming convenience in order to avoid
  * malloc+lseek+read+free of many pieces.  If successful, then mmap
index e54ebd5308491a30ff3dd725c39b8b2f1a0169bb..6e61a019aa5e4040e9f29bc58fdc35e799207f24 100644 (file)
@@ -3428,6 +3428,7 @@ static struct snd_pci_quirk msi_black_list[] = {
        SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */
        SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */
        SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */
+       SND_PCI_QUIRK(0x1179, 0xfb44, "Toshiba Satellite C870", 0), /* AMD Hudson */
        SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
        SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */
        {}
index cccaf9c7a7bbd29b195b6ae475c2479e528bdd86..b524f89a1f13a7d74c51c8231684f971662ccc15 100644 (file)
@@ -169,7 +169,7 @@ static void cs_automute(struct hda_codec *codec)
 
        snd_hda_gen_update_outputs(codec);
 
-       if (spec->gpio_eapd_hp) {
+       if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
                spec->gpio_data = spec->gen.hp_jack_present ?
                        spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
                snd_hda_codec_write(codec, 0x01, 0,
@@ -291,10 +291,11 @@ static int cs_init(struct hda_codec *codec)
 {
        struct cs_spec *spec = codec->spec;
 
-       /* init_verb sequence for C0/C1/C2 errata*/
-       snd_hda_sequence_write(codec, cs_errata_init_verbs);
-
-       snd_hda_sequence_write(codec, cs_coef_init_verbs);
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
+               /* init_verb sequence for C0/C1/C2 errata*/
+               snd_hda_sequence_write(codec, cs_errata_init_verbs);
+               snd_hda_sequence_write(codec, cs_coef_init_verbs);
+       }
 
        snd_hda_gen_init(codec);
 
@@ -307,8 +308,10 @@ static int cs_init(struct hda_codec *codec)
                                    spec->gpio_data);
        }
 
-       init_input_coef(codec);
-       init_digital_coef(codec);
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
+               init_input_coef(codec);
+               init_digital_coef(codec);
+       }
 
        return 0;
 }
@@ -551,6 +554,76 @@ static int patch_cs420x(struct hda_codec *codec)
        return err;
 }
 
+/*
+ * CS4208 support:
+ * Its layout is no longer compatible with CS4206/CS4207, and the generic
+ * parser seems working fairly well, except for trivial fixups.
+ */
+enum {
+       CS4208_GPIO0,
+};
+
+static const struct hda_model_fixup cs4208_models[] = {
+       { .id = CS4208_GPIO0, .name = "gpio0" },
+       {}
+};
+
+static const struct snd_pci_quirk cs4208_fixup_tbl[] = {
+       /* codec SSID */
+       SND_PCI_QUIRK(0x106b, 0x7100, "MacBookPro 6,1", CS4208_GPIO0),
+       SND_PCI_QUIRK(0x106b, 0x7200, "MacBookPro 6,2", CS4208_GPIO0),
+       {} /* terminator */
+};
+
+static void cs4208_fixup_gpio0(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct cs_spec *spec = codec->spec;
+               spec->gpio_eapd_hp = 0;
+               spec->gpio_eapd_speaker = 1;
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+       }
+}
+
+static const struct hda_fixup cs4208_fixups[] = {
+       [CS4208_GPIO0] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_gpio0,
+       },
+};
+
+static int patch_cs4208(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = cs_alloc_spec(codec, 0); /* no specific w/a */
+       if (!spec)
+               return -ENOMEM;
+
+       spec->gen.automute_hook = cs_automute;
+
+       snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
+                          cs4208_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = cs_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       codec->patch_ops = cs_patch_ops;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       cs_free(codec);
+       return err;
+}
+
 /*
  * Cirrus Logic CS4210
  *
@@ -991,6 +1064,7 @@ static int patch_cs4213(struct hda_codec *codec)
 static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
        { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x },
        { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x },
+       { .id = 0x10134208, .name = "CS4208", .patch = patch_cs4208 },
        { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 },
        { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 },
        {} /* terminator */
@@ -998,6 +1072,7 @@ static const struct hda_codec_preset snd_hda_preset_cirrus[] = {
 
 MODULE_ALIAS("snd-hda-codec-id:10134206");
 MODULE_ALIAS("snd-hda-codec-id:10134207");
+MODULE_ALIAS("snd-hda-codec-id:10134208");
 MODULE_ALIAS("snd-hda-codec-id:10134210");
 MODULE_ALIAS("snd-hda-codec-id:10134213");
 
index 9a58893d52a7c6325a69837ccae7f049087747e1..3d8cd04455a623b888a9efccb7bdd31f92df8188 100644 (file)
@@ -44,6 +44,8 @@ static bool static_hdmi_pcm;
 module_param(static_hdmi_pcm, bool, 0644);
 MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
 
+#define is_haswell(codec)  ((codec)->vendor_id == 0x80862807)
+
 struct hdmi_spec_per_cvt {
        hda_nid_t cvt_nid;
        int assigned;
@@ -894,6 +896,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
        if (!channels)
                return;
 
+       if (is_haswell(codec))
+               snd_hda_codec_write(codec, pin_nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_UNMUTE);
+
        eld = &per_pin->sink_eld;
        if (!eld->monitor_present)
                return;
@@ -1033,10 +1040,10 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
                hdmi_non_intrinsic_event(codec, res);
 }
 
-static void haswell_verify_pin_D0(struct hda_codec *codec,
+static void haswell_verify_D0(struct hda_codec *codec,
                hda_nid_t cvt_nid, hda_nid_t nid)
 {
-       int pwr, lamp, ramp;
+       int pwr;
 
        /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
         * thus pins could only choose converter 0 for use. Make sure the
@@ -1052,25 +1059,6 @@ static void haswell_verify_pin_D0(struct hda_codec *codec,
                pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
                snd_printd("Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr);
        }
-
-       lamp = snd_hda_codec_read(codec, nid, 0,
-                                 AC_VERB_GET_AMP_GAIN_MUTE,
-                                 AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
-       ramp = snd_hda_codec_read(codec, nid, 0,
-                                 AC_VERB_GET_AMP_GAIN_MUTE,
-                                 AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
-       if (lamp != ramp) {
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT | lamp);
-
-               lamp = snd_hda_codec_read(codec, nid, 0,
-                                 AC_VERB_GET_AMP_GAIN_MUTE,
-                                 AC_AMP_GET_LEFT | AC_AMP_GET_OUTPUT);
-               ramp = snd_hda_codec_read(codec, nid, 0,
-                                 AC_VERB_GET_AMP_GAIN_MUTE,
-                                 AC_AMP_GET_RIGHT | AC_AMP_GET_OUTPUT);
-               snd_printd("Haswell HDMI audio: Mute after set on pin 0x%x: [0x%x 0x%x]\n", nid, lamp, ramp);
-       }
 }
 
 /*
@@ -1087,8 +1075,8 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
        int pinctl;
        int new_pinctl = 0;
 
-       if (codec->vendor_id == 0x80862807)
-               haswell_verify_pin_D0(codec, cvt_nid, pin_nid);
+       if (is_haswell(codec))
+               haswell_verify_D0(codec, cvt_nid, pin_nid);
 
        if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
                pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -1227,7 +1215,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
                            mux_idx);
 
        /* configure unused pins to choose other converters */
-       if (codec->vendor_id == 0x80862807)
+       if (is_haswell(codec))
                haswell_config_cvts(codec, pin_idx, mux_idx);
 
        snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
@@ -1358,14 +1346,10 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
                /* Haswell-specific workaround: re-setup when the transcoder is
                 * changed during the stream playback
                 */
-               if (codec->vendor_id == 0x80862807 &&
-                   eld->eld_valid && !old_eld_valid && per_pin->setup) {
-                       snd_hda_codec_write(codec, pin_nid, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE,
-                                           AMP_OUT_UNMUTE);
+               if (is_haswell(codec) &&
+                   eld->eld_valid && !old_eld_valid && per_pin->setup)
                        hdmi_setup_audio_infoframe(codec, per_pin,
                                                   per_pin->non_pcm);
-               }
        }
        mutex_unlock(&pin_eld->lock);
 
@@ -1405,7 +1389,7 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
        if (get_defcfg_connect(config) == AC_JACK_PORT_NONE)
                return 0;
 
-       if (codec->vendor_id == 0x80862807)
+       if (is_haswell(codec))
                intel_haswell_fixup_connect_list(codec, pin_nid);
 
        pin_idx = spec->num_pins;
@@ -2014,7 +1998,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
        codec->spec = spec;
        hdmi_array_init(spec, 4);
 
-       if (codec->vendor_id == 0x80862807) {
+       if (is_haswell(codec)) {
                intel_haswell_enable_all_pins(codec, true);
                intel_haswell_fixup_enable_dp12(codec);
        }
@@ -2025,7 +2009,7 @@ static int patch_generic_hdmi(struct hda_codec *codec)
                return -EINVAL;
        }
        codec->patch_ops = generic_hdmi_patch_ops;
-       if (codec->vendor_id == 0x80862807) {
+       if (is_haswell(codec)) {
                codec->patch_ops.set_power_state = haswell_set_power_state;
                codec->dp_mst = true;
        }
index 9e9378cde8fa7c05005b8432878b662be74c1263..bc07d369fac43a548db7f1e45273627cc4e7246c 100644 (file)
@@ -3443,6 +3443,56 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
        }
 }
 
+/* mute tablet speaker pin (0x14) via dock plugging in addition */
+static void asus_tx300_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       snd_hda_gen_update_outputs(codec);
+       if (snd_hda_jack_detect(codec, 0x1b))
+               spec->gen.mute_bits |= (1ULL << 0x14);
+}
+
+static void alc282_fixup_asus_tx300(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       /* TX300 needs to set up GPIO2 for the speaker amp */
+       static const struct hda_verb gpio2_verbs[] = {
+               { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+               { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+               { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 },
+               {}
+       };
+       static const struct hda_pintbl dock_pins[] = {
+               { 0x1b, 0x21114000 }, /* dock speaker pin */
+               {}
+       };
+       struct snd_kcontrol *kctl;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_add_verbs(codec, gpio2_verbs);
+               snd_hda_apply_pincfgs(codec, dock_pins);
+               spec->gen.auto_mute_via_amp = 1;
+               spec->gen.automute_hook = asus_tx300_automute;
+               snd_hda_jack_detect_enable_callback(codec, 0x1b,
+                                                   HDA_GEN_HP_EVENT,
+                                                   snd_hda_gen_hp_automute);
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               /* this is a bit tricky; give more sane names for the main
+                * (tablet) speaker and the dock speaker, respectively
+                */
+               kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch");
+               if (kctl)
+                       strcpy(kctl->id.name, "Dock Speaker Playback Switch");
+               kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch");
+               if (kctl)
+                       strcpy(kctl->id.name, "Speaker Playback Switch");
+               break;
+       }
+}
+
 enum {
        ALC269_FIXUP_SONY_VAIO,
        ALC275_FIXUP_SONY_VAIO_GPIO2,
@@ -3480,6 +3530,7 @@ enum {
        ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
        ALC269VB_FIXUP_ORDISSIMO_EVE2,
        ALC283_FIXUP_CHROME_BOOK,
+       ALC282_FIXUP_ASUS_TX300,
 };
 
 static const struct hda_fixup alc269_fixups[] = {
@@ -3735,6 +3786,10 @@ static const struct hda_fixup alc269_fixups[] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc283_fixup_chromebook,
        },
+       [ALC282_FIXUP_ASUS_TX300] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc282_fixup_asus_tx300,
+       },
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -3784,6 +3839,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1),
        SND_PCI_QUIRK(0x103c, 0x21ed, "HP Falco Chromebook", ALC283_FIXUP_CHROME_BOOK),
        SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC),
index 0ecf356027f6c1fcc91693e4c7063152fe3ac706..bb53dea85b17eefc55090dfb4190ee5863337a2d 100644 (file)
@@ -649,7 +649,7 @@ static int atmel_ssc_prepare(struct snd_pcm_substream *substream,
        dma_params = ssc_p->dma_params[dir];
 
        ssc_writel(ssc_p->ssc->regs, CR, dma_params->mask->ssc_enable);
-       ssc_writel(ssc_p->ssc->regs, IER, dma_params->mask->ssc_error);
+       ssc_writel(ssc_p->ssc->regs, IDR, dma_params->mask->ssc_error);
 
        pr_debug("%s enabled SSC_SR=0x%08x\n",
                        dir ? "receive" : "transmit",
index 15106c045478e644719a73e76edb6ea795909ff1..b33b45dfceec54b205c512ca01638d947df56f66 100644 (file)
@@ -107,7 +107,7 @@ config SND_SOC_ALL_CODECS
        select SND_SOC_WM8782
        select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
        select SND_SOC_WM8900 if I2C
-       select SND_SOC_WM8903 if I2C && GENERIC_HARDIRQS
+       select SND_SOC_WM8903 if I2C
        select SND_SOC_WM8904 if I2C
        select SND_SOC_WM8940 if I2C
        select SND_SOC_WM8955 if I2C
index 4d3c8fd8c5db5aeec4632e958d3737a0d59adc0f..ea141e1d6f280733fdc832f7b5e2d054f2e8fff4 100644 (file)
@@ -125,6 +125,10 @@ static int mc13783_write(struct snd_soc_codec *codec,
 
        ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
 
+       /* include errata fix for spi audio problems */
+       if (reg == MC13783_AUDIO_CODEC || reg == MC13783_AUDIO_DAC)
+               ret = mc13xxx_reg_write(priv->mc13xxx, reg, value);
+
        mc13xxx_unlock(priv->mc13xxx);
 
        return ret;
index 704e246f5b1ef23e74f1fbce7cffb422ca0a442e..b7ab71f2ccc1676ec690427ef712c3785ccf80dd 100644 (file)
@@ -198,6 +198,7 @@ config SND_SOC_IMX_SPDIF
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_FSL_SPDIF
        select SND_SOC_SPDIF
+       select REGMAP_MMIO
        help
          SoC Audio support for i.MX boards with S/PDIF
          Say Y if you want to add support for SoC audio on an i.MX board with
index ab17381cc9812a7e0538f30ea44496bfdd944c6d..d3bf71a0ec56aa6ff0ef604b36779eec79e3f23a 100644 (file)
@@ -335,7 +335,8 @@ static int imx_audmux_probe(struct platform_device *pdev)
        if (audmux_type == IMX31_AUDMUX)
                audmux_debugfs_init();
 
-       imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
+       if (of_id)
+               imx_audmux_parse_dt_defaults(pdev, pdev->dev.of_node);
 
        return 0;
 }
index 7fce340ab3ef9452bcb01fbe84a306685dd916c9..0f3d73d4ef48ea72d5d9b3c63d72f90e919ba7bc 100644 (file)
@@ -559,7 +559,8 @@ static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_OF
 static struct of_device_id mvebu_audio_of_match[] = {
-       { .compatible = "marvell,mvebu-audio" },
+       { .compatible = "marvell,kirkwood-audio" },
+       { .compatible = "marvell,dove-audio" },
        { }
 };
 MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
index 9855dfc3e3ec86f726526540d3bf0446cca22cd5..2eea1840315d3448248109215f216d2f607c0b89 100644 (file)
@@ -63,7 +63,7 @@ config SND_SOC_SAMSUNG_SMDK_WM8580
 config SND_SOC_SAMSUNG_SMDK_WM8994
        tristate "SoC I2S Audio support for WM8994 on SMDK"
        depends on SND_SOC_SAMSUNG
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_WM8994
        select SND_SOC_WM8994
        select SND_SAMSUNG_I2S
@@ -151,7 +151,7 @@ config SND_SOC_SMARTQ
 config SND_SOC_GONI_AQUILA_WM8994
        tristate "SoC I2S Audio support for AQUILA/GONI - WM8994"
        depends on SND_SOC_SAMSUNG && (MACH_GONI || MACH_AQUILA)
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select SND_SAMSUNG_I2S
        select MFD_WM8994
        select SND_SOC_WM8994
@@ -177,7 +177,7 @@ config SND_SOC_SMDK_WM8580_PCM
 config SND_SOC_SMDK_WM8994_PCM
        tristate "SoC PCM Audio support for WM8994 on SMDK"
        depends on SND_SOC_SAMSUNG
-       depends on I2C=y && GENERIC_HARDIRQS
+       depends on I2C=y
        select MFD_WM8994
        select SND_SOC_WM8994
        select SND_SAMSUNG_PCM
index 184d9008cecd2f1080c5f6491bdc14de9221c910..2df2e9150b893498ffbc15991b1a47e2f9dfd47a 100644 (file)
@@ -157,9 +157,9 @@ static int rsnd_scu_start(struct rsnd_mod *mod,
        int ret;
 
        /*
-        * SCU will be used if it has RSND_SCU_USB_HPBIF flags
+        * SCU will be used if it has RSND_SCU_USE_HPBIF flags
         */
-       if (!(flags & RSND_SCU_USB_HPBIF)) {
+       if (!(flags & RSND_SCU_USE_HPBIF)) {
                /* it use PIO transter */
                dev_dbg(dev, "%s%d is not used\n",
                        rsnd_mod_name(mod), rsnd_mod_id(mod));
index 68f67cf3d3182f5dcc696a50f3ef889c05ea10d2..32cf2ce15d69bcfca9c24da9ad318fc1a2e84eb2 100644 (file)
 #include <pwd.h>
 #include <grp.h>
 
+#ifndef VIRTIO_F_ANY_LAYOUT
+#define VIRTIO_F_ANY_LAYOUT            27
+#endif
+
 /*L:110
  * We can ignore the 43 include files we need for this program, but I do want
  * to draw attention to the use of kernel-style types.
@@ -1544,6 +1548,8 @@ static void setup_tun_net(char *arg)
        add_feature(dev, VIRTIO_NET_F_HOST_ECN);
        /* We handle indirect ring entries */
        add_feature(dev, VIRTIO_RING_F_INDIRECT_DESC);
+       /* We're compliant with the damn spec. */
+       add_feature(dev, VIRTIO_F_ANY_LAYOUT);
        set_config(dev, sizeof(conf), &conf);
 
        /* We don't need the socket any more; setup is done. */
index c5dc1ad1b8d73bc66ae92d78d522af7f15155126..3a0ff7fb71b633df77cfd1302ce35e2bf9506142 100644 (file)
@@ -394,6 +394,8 @@ ifeq ($(ARCH),x86)
 LIB_OBJS += $(OUTPUT)tests/perf-time-to-tsc.o
 endif
 LIB_OBJS += $(OUTPUT)tests/code-reading.o
+LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
+LIB_OBJS += $(OUTPUT)tests/parse-no-sample-id-all.o
 
 BUILTIN_OBJS += $(OUTPUT)builtin-annotate.o
 BUILTIN_OBJS += $(OUTPUT)builtin-bench.o
@@ -439,7 +441,6 @@ PERFLIBS = $(LIB_FILE) $(LIBLK) $(LIBTRACEEVENT)
 ifneq ($(OUTPUT),)
   CFLAGS += -I$(OUTPUT)
 endif
-LIB_OBJS += $(OUTPUT)tests/sample-parsing.o
 
 ifdef NO_LIBELF
 EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
index f988d380c52f4c87b7f30cf042608a85c025c845..5ebd0c3b71b6aa45d80aa63b47661996577cf6a4 100644 (file)
@@ -277,6 +277,7 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
                .tool = {
                        .sample = process_sample_event,
                        .mmap   = perf_event__process_mmap,
+                       .mmap2  = perf_event__process_mmap2,
                        .comm   = perf_event__process_comm,
                        .exit   = perf_event__process_exit,
                        .fork   = perf_event__process_fork,
index 9b336fdb6f71ac8bc751a6d4955078cb6ab5009a..423875c999b21208a5a6274d0fd47a2fb359ecd8 100644 (file)
@@ -123,6 +123,19 @@ static int perf_event__repipe_mmap(struct perf_tool *tool,
        return err;
 }
 
+static int perf_event__repipe_mmap2(struct perf_tool *tool,
+                                  union perf_event *event,
+                                  struct perf_sample *sample,
+                                  struct machine *machine)
+{
+       int err;
+
+       err = perf_event__process_mmap2(tool, event, sample, machine);
+       perf_event__repipe(tool, event, sample, machine);
+
+       return err;
+}
+
 static int perf_event__repipe_fork(struct perf_tool *tool,
                                   union perf_event *event,
                                   struct perf_sample *sample,
@@ -339,6 +352,7 @@ static int __cmd_inject(struct perf_inject *inject)
 
        if (inject->build_ids || inject->sched_stat) {
                inject->tool.mmap         = perf_event__repipe_mmap;
+               inject->tool.mmap2        = perf_event__repipe_mmap2;
                inject->tool.fork         = perf_event__repipe_fork;
                inject->tool.tracing_data = perf_event__repipe_tracing_data;
        }
@@ -390,6 +404,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
                .tool = {
                        .sample         = perf_event__repipe_sample,
                        .mmap           = perf_event__repipe,
+                       .mmap2          = perf_event__repipe,
                        .comm           = perf_event__repipe,
                        .fork           = perf_event__repipe,
                        .exit           = perf_event__repipe,
index 47b35407c2f21705e65be4c0eab75ae89dcd3811..935d52216c899eb42774ae9f6e63767ff77fc8ba 100644 (file)
@@ -1165,16 +1165,16 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm)
                struct perf_event_attr *attr = &pos->attr;
 
                /* make sure these *are* set */
-               attr->sample_type |= PERF_SAMPLE_TID;
-               attr->sample_type |= PERF_SAMPLE_TIME;
-               attr->sample_type |= PERF_SAMPLE_CPU;
-               attr->sample_type |= PERF_SAMPLE_RAW;
+               perf_evsel__set_sample_bit(pos, TID);
+               perf_evsel__set_sample_bit(pos, TIME);
+               perf_evsel__set_sample_bit(pos, CPU);
+               perf_evsel__set_sample_bit(pos, RAW);
                /* make sure these are *not*; want as small a sample as possible */
-               attr->sample_type &= ~PERF_SAMPLE_PERIOD;
-               attr->sample_type &= ~PERF_SAMPLE_IP;
-               attr->sample_type &= ~PERF_SAMPLE_CALLCHAIN;
-               attr->sample_type &= ~PERF_SAMPLE_ADDR;
-               attr->sample_type &= ~PERF_SAMPLE_READ;
+               perf_evsel__reset_sample_bit(pos, PERIOD);
+               perf_evsel__reset_sample_bit(pos, IP);
+               perf_evsel__reset_sample_bit(pos, CALLCHAIN);
+               perf_evsel__reset_sample_bit(pos, ADDR);
+               perf_evsel__reset_sample_bit(pos, READ);
                attr->mmap = 0;
                attr->comm = 0;
                attr->task = 0;
index 791b432df84731d8d9746a77760095710198614d..253133a6251d3c3d657671b7a8a603ef4cb03643 100644 (file)
@@ -190,6 +190,7 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
                .tool = {
                        .sample         = process_sample_event,
                        .mmap           = perf_event__process_mmap,
+                       .mmap2          = perf_event__process_mmap2,
                        .comm           = perf_event__process_comm,
                        .lost           = perf_event__process_lost,
                        .fork           = perf_event__process_fork,
index 9725aa3754141d6be634547f6c53755134a8f32c..8e50d8d77419c7ca3e8ce72209b113d72665c09e 100644 (file)
@@ -744,6 +744,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
                .tool = {
                        .sample          = process_sample_event,
                        .mmap            = perf_event__process_mmap,
+                       .mmap2           = perf_event__process_mmap2,
                        .comm            = perf_event__process_comm,
                        .exit            = perf_event__process_exit,
                        .fork            = perf_event__process_fork,
index 93a34cef9676993b4f53ea16ab1aa6b34a37165d..7f31a3ded1b6dc59730a0162d5af279e038d1afc 100644 (file)
@@ -542,6 +542,7 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
 static struct perf_tool perf_script = {
        .sample          = process_sample_event,
        .mmap            = perf_event__process_mmap,
+       .mmap2           = perf_event__process_mmap2,
        .comm            = perf_event__process_comm,
        .exit            = perf_event__process_exit,
        .fork            = perf_event__process_fork,
index b6f0725068bda07d46d43f52c8097003d7375bb7..f5aa6375e3e9add4eea3cdd81de685fa37d87c4d 100644 (file)
@@ -100,7 +100,9 @@ static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size,
 
        P_MMAP_FLAG(SHARED);
        P_MMAP_FLAG(PRIVATE);
+#ifdef MAP_32BIT
        P_MMAP_FLAG(32BIT);
+#endif
        P_MMAP_FLAG(ANONYMOUS);
        P_MMAP_FLAG(DENYWRITE);
        P_MMAP_FLAG(EXECUTABLE);
@@ -994,6 +996,9 @@ again:
 
                        handler = evsel->handler.func;
                        handler(trace, evsel, &sample);
+
+                       if (done)
+                               goto out_unmap_evlist;
                }
        }
 
index 8bbeba322df9ea760f4a527821a1905cd0415bdc..1e67437fb4cae5c770087432d248591b05baa033 100644 (file)
@@ -111,6 +111,10 @@ static struct test {
                .desc = "Test using a dummy software event to keep tracking",
                .func = test__keep_tracking,
        },
+       {
+               .desc = "Test parsing with no sample_id_all bit set",
+               .func = test__parse_no_sample_id_all,
+       },
        {
                .func = NULL,
        },
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
new file mode 100644 (file)
index 0000000..e117b6c
--- /dev/null
@@ -0,0 +1,108 @@
+#include <sys/types.h>
+#include <stddef.h>
+
+#include "tests.h"
+
+#include "event.h"
+#include "evlist.h"
+#include "header.h"
+#include "util.h"
+
+static int process_event(struct perf_evlist **pevlist, union perf_event *event)
+{
+       struct perf_sample sample;
+
+       if (event->header.type == PERF_RECORD_HEADER_ATTR) {
+               if (perf_event__process_attr(NULL, event, pevlist)) {
+                       pr_debug("perf_event__process_attr failed\n");
+                       return -1;
+               }
+               return 0;
+       }
+
+       if (event->header.type >= PERF_RECORD_USER_TYPE_START)
+               return -1;
+
+       if (!*pevlist)
+               return -1;
+
+       if (perf_evlist__parse_sample(*pevlist, event, &sample)) {
+               pr_debug("perf_evlist__parse_sample failed\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int process_events(union perf_event **events, size_t count)
+{
+       struct perf_evlist *evlist = NULL;
+       int err = 0;
+       size_t i;
+
+       for (i = 0; i < count && !err; i++)
+               err = process_event(&evlist, events[i]);
+
+       if (evlist)
+               perf_evlist__delete(evlist);
+
+       return err;
+}
+
+struct test_attr_event {
+       struct attr_event attr;
+       u64 id;
+};
+
+/**
+ * test__parse_no_sample_id_all - test parsing with no sample_id_all bit set.
+ *
+ * This function tests parsing data produced on kernel's that do not support the
+ * sample_id_all bit.  Without the sample_id_all bit, non-sample events (such as
+ * mmap events) do not have an id sample appended, and consequently logic
+ * designed to determine the id will not work.  That case happens when there is
+ * more than one selected event, so this test processes three events: 2
+ * attributes representing the selected events and one mmap event.
+ *
+ * Return: %0 on success, %-1 if the test fails.
+ */
+int test__parse_no_sample_id_all(void)
+{
+       int err;
+
+       struct test_attr_event event1 = {
+               .attr = {
+                       .header = {
+                               .type = PERF_RECORD_HEADER_ATTR,
+                               .size = sizeof(struct test_attr_event),
+                       },
+               },
+               .id = 1,
+       };
+       struct test_attr_event event2 = {
+               .attr = {
+                       .header = {
+                               .type = PERF_RECORD_HEADER_ATTR,
+                               .size = sizeof(struct test_attr_event),
+                       },
+               },
+               .id = 2,
+       };
+       struct mmap_event event3 = {
+               .header = {
+                       .type = PERF_RECORD_MMAP,
+                       .size = sizeof(struct mmap_event),
+               },
+       };
+       union perf_event *events[] = {
+               (union perf_event *)&event1,
+               (union perf_event *)&event2,
+               (union perf_event *)&event3,
+       };
+
+       err = process_events(events, ARRAY_SIZE(events));
+       if (err)
+               return -1;
+
+       return 0;
+}
index 72d8881873b0689c2975e84edd5f7379b5282777..b8a7056519ac7c29b430a87d73be85314b4d8082 100644 (file)
@@ -50,7 +50,7 @@ int test__PERF_RECORD(void)
        struct perf_sample sample;
        const char *cmd = "sleep";
        const char *argv[] = { cmd, "1", NULL, };
-       char *bname;
+       char *bname, *mmap_filename;
        u64 prev_time = 0;
        bool found_cmd_mmap = false,
             found_libc_mmap = false,
@@ -212,6 +212,7 @@ int test__PERF_RECORD(void)
 
                                if ((type == PERF_RECORD_COMM ||
                                     type == PERF_RECORD_MMAP ||
+                                    type == PERF_RECORD_MMAP2 ||
                                     type == PERF_RECORD_FORK ||
                                     type == PERF_RECORD_EXIT) &&
                                     (pid_t)event->comm.pid != evlist->workload.pid) {
@@ -220,7 +221,8 @@ int test__PERF_RECORD(void)
                                }
 
                                if ((type == PERF_RECORD_COMM ||
-                                    type == PERF_RECORD_MMAP) &&
+                                    type == PERF_RECORD_MMAP ||
+                                    type == PERF_RECORD_MMAP2) &&
                                     event->comm.pid != event->comm.tid) {
                                        pr_debug("%s with different pid/tid!\n", name);
                                        ++errs;
@@ -236,7 +238,12 @@ int test__PERF_RECORD(void)
                                case PERF_RECORD_EXIT:
                                        goto found_exit;
                                case PERF_RECORD_MMAP:
-                                       bname = strrchr(event->mmap.filename, '/');
+                                       mmap_filename = event->mmap.filename;
+                                       goto check_bname;
+                               case PERF_RECORD_MMAP2:
+                                       mmap_filename = event->mmap2.filename;
+                               check_bname:
+                                       bname = strrchr(mmap_filename, '/');
                                        if (bname != NULL) {
                                                if (!found_cmd_mmap)
                                                        found_cmd_mmap = !strcmp(bname + 1, cmd);
@@ -245,7 +252,7 @@ int test__PERF_RECORD(void)
                                                if (!found_ld_mmap)
                                                        found_ld_mmap = !strncmp(bname + 1, "ld", 2);
                                        } else if (!found_vdso_mmap)
-                                               found_vdso_mmap = !strcmp(event->mmap.filename, "[vdso]");
+                                               found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
                                        break;
 
                                case PERF_RECORD_SAMPLE:
index c048b589998a90b8f72be45087f25237ffe38af8..e0ac713857ba5708fee69a8b1000cd81d9ae0a76 100644 (file)
@@ -39,5 +39,6 @@ int test__perf_time_to_tsc(void);
 int test__code_reading(void);
 int test__sample_parsing(void);
 int test__keep_tracking(void);
+int test__parse_no_sample_id_all(void);
 
 #endif /* TESTS_H */
index 5b4fb330f656d71f929f197c06387389dbc2dfed..194e2f42ff5d1335eb1c2b5b53ea2ab6b1604932 100644 (file)
@@ -350,9 +350,9 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,
 }
 
 static int hist_entry__fprintf(struct hist_entry *he, size_t size,
-                              struct hists *hists, FILE *fp)
+                              struct hists *hists,
+                              char *bf, size_t bfsz, FILE *fp)
 {
-       char bf[512];
        int ret;
        struct perf_hpp hpp = {
                .buf            = bf,
@@ -360,8 +360,8 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
        };
        bool color = !symbol_conf.field_sep;
 
-       if (size == 0 || size > sizeof(bf))
-               size = hpp.size = sizeof(bf);
+       if (size == 0 || size > bfsz)
+               size = hpp.size = bfsz;
 
        ret = hist_entry__period_snprintf(&hpp, he, color);
        hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
@@ -392,6 +392,8 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                .ptr    = hists_to_evsel(hists),
        };
        bool first = true;
+       size_t linesz;
+       char *line = NULL;
 
        init_rem_hits();
 
@@ -479,6 +481,13 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
                goto out;
 
 print_entries:
+       linesz = hists__sort_list_width(hists) + 3 + 1;
+       line = malloc(linesz);
+       if (line == NULL) {
+               ret = -1;
+               goto out;
+       }
+
        for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
                struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
                float percent = h->stat.period * 100.0 /
@@ -490,10 +499,10 @@ print_entries:
                if (percent < min_pcnt)
                        continue;
 
-               ret += hist_entry__fprintf(h, max_cols, hists, fp);
+               ret += hist_entry__fprintf(h, max_cols, hists, line, linesz, fp);
 
                if (max_rows && ++nr_rows >= max_rows)
-                       goto out;
+                       break;
 
                if (h->ms.map == NULL && verbose > 1) {
                        __map_groups__fprintf_maps(&h->thread->mg,
@@ -501,6 +510,8 @@ print_entries:
                        fprintf(fp, "%.10s end\n", graph_dotted_line);
                }
        }
+
+       free(line);
 out:
        free(rem_sq_bracket);
 
index fb584092eb8839f004d16a673c9e42cf859ec0fe..7ded71d19d75323ab02184c460afde37fe17d831 100644 (file)
@@ -67,6 +67,7 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
 struct perf_tool build_id__mark_dso_hit_ops = {
        .sample = build_id__mark_dso_hit,
        .mmap   = perf_event__process_mmap,
+       .mmap2  = perf_event__process_mmap2,
        .fork   = perf_event__process_fork,
        .exit   = perf_event__exit_del_thread,
        .attr            = perf_event__process_attr,
index 8d51f21107aa47b0b0cb97e97ec09cefec6e1804..9b393e7dca6fe849037d5a1314a8cf6b22e1f596 100644 (file)
@@ -11,6 +11,7 @@
 static const char *perf_event__names[] = {
        [0]                                     = "TOTAL",
        [PERF_RECORD_MMAP]                      = "MMAP",
+       [PERF_RECORD_MMAP2]                     = "MMAP2",
        [PERF_RECORD_LOST]                      = "LOST",
        [PERF_RECORD_COMM]                      = "COMM",
        [PERF_RECORD_EXIT]                      = "EXIT",
@@ -186,7 +187,7 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                return -1;
        }
 
-       event->header.type = PERF_RECORD_MMAP;
+       event->header.type = PERF_RECORD_MMAP2;
        /*
         * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
         */
@@ -197,7 +198,9 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                char prot[5];
                char execname[PATH_MAX];
                char anonstr[] = "//anon";
+               unsigned int ino;
                size_t size;
+               ssize_t n;
 
                if (fgets(bf, sizeof(bf), fp) == NULL)
                        break;
@@ -206,9 +209,16 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                strcpy(execname, "");
 
                /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
-               sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
-                      &event->mmap.start, &event->mmap.len, prot,
-                      &event->mmap.pgoff, execname);
+               n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n",
+                      &event->mmap2.start, &event->mmap2.len, prot,
+                      &event->mmap2.pgoff, &event->mmap2.maj,
+                      &event->mmap2.min,
+                      &ino, execname);
+
+               event->mmap2.ino = (u64)ino;
+
+               if (n != 8)
+                       continue;
 
                if (prot[2] != 'x')
                        continue;
@@ -217,15 +227,15 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
                        strcpy(execname, anonstr);
 
                size = strlen(execname) + 1;
-               memcpy(event->mmap.filename, execname, size);
+               memcpy(event->mmap2.filename, execname, size);
                size = PERF_ALIGN(size, sizeof(u64));
-               event->mmap.len -= event->mmap.start;
-               event->mmap.header.size = (sizeof(event->mmap) -
-                                          (sizeof(event->mmap.filename) - size));
-               memset(event->mmap.filename + size, 0, machine->id_hdr_size);
-               event->mmap.header.size += machine->id_hdr_size;
-               event->mmap.pid = tgid;
-               event->mmap.tid = pid;
+               event->mmap2.len -= event->mmap.start;
+               event->mmap2.header.size = (sizeof(event->mmap2) -
+                                       (sizeof(event->mmap2.filename) - size));
+               memset(event->mmap2.filename + size, 0, machine->id_hdr_size);
+               event->mmap2.header.size += machine->id_hdr_size;
+               event->mmap2.pid = tgid;
+               event->mmap2.tid = pid;
 
                if (process(tool, event, &synth_sample, machine) != 0) {
                        rc = -1;
@@ -527,6 +537,17 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
                       event->mmap.len, event->mmap.pgoff, event->mmap.filename);
 }
 
+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
+{
+       return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64
+                          " %02x:%02x %"PRIu64" %"PRIu64"]: %s\n",
+                      event->mmap2.pid, event->mmap2.tid, event->mmap2.start,
+                      event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj,
+                      event->mmap2.min, event->mmap2.ino,
+                      event->mmap2.ino_generation,
+                      event->mmap2.filename);
+}
+
 int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
                             union perf_event *event,
                             struct perf_sample *sample __maybe_unused,
@@ -535,6 +556,14 @@ int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
        return machine__process_mmap_event(machine, event);
 }
 
+int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused,
+                            union perf_event *event,
+                            struct perf_sample *sample __maybe_unused,
+                            struct machine *machine)
+{
+       return machine__process_mmap2_event(machine, event);
+}
+
 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
 {
        return fprintf(fp, "(%d:%d):(%d:%d)\n",
@@ -574,6 +603,9 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
        case PERF_RECORD_MMAP:
                ret += perf_event__fprintf_mmap(event, fp);
                break;
+       case PERF_RECORD_MMAP2:
+               ret += perf_event__fprintf_mmap2(event, fp);
+               break;
        default:
                ret += fprintf(fp, "\n");
        }
index 93130d856bf0dd612e9e906bd4a93454ade0381b..c67ecc457d295d029a2307c1b0ad7e1531b944d1 100644 (file)
@@ -17,6 +17,19 @@ struct mmap_event {
        char filename[PATH_MAX];
 };
 
+struct mmap2_event {
+       struct perf_event_header header;
+       u32 pid, tid;
+       u64 start;
+       u64 len;
+       u64 pgoff;
+       u32 maj;
+       u32 min;
+       u64 ino;
+       u64 ino_generation;
+       char filename[PATH_MAX];
+};
+
 struct comm_event {
        struct perf_event_header header;
        u32 pid, tid;
@@ -159,6 +172,7 @@ struct tracing_data_event {
 union perf_event {
        struct perf_event_header        header;
        struct mmap_event               mmap;
+       struct mmap2_event              mmap2;
        struct comm_event               comm;
        struct fork_event               fork;
        struct lost_event               lost;
@@ -208,6 +222,10 @@ int perf_event__process_mmap(struct perf_tool *tool,
                             union perf_event *event,
                             struct perf_sample *sample,
                             struct machine *machine);
+int perf_event__process_mmap2(struct perf_tool *tool,
+                            union perf_event *event,
+                            struct perf_sample *sample,
+                            struct machine *machine);
 int perf_event__process_fork(struct perf_tool *tool,
                             union perf_event *event,
                             struct perf_sample *sample,
@@ -238,6 +256,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
 
 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
 size_t perf_event__fprintf(union perf_event *event, FILE *fp);
 
index b8727ae45e3b9dc959734f1cd4bc9fc888a6dc4b..f9f77bee0b1b416414fa3561fb2eee4785e502c4 100644 (file)
@@ -64,6 +64,16 @@ void perf_evlist__set_id_pos(struct perf_evlist *evlist)
        evlist->is_pos = first->is_pos;
 }
 
+static void perf_evlist__update_id_pos(struct perf_evlist *evlist)
+{
+       struct perf_evsel *evsel;
+
+       list_for_each_entry(evsel, &evlist->entries, node)
+               perf_evsel__calc_id_pos(evsel);
+
+       perf_evlist__set_id_pos(evlist);
+}
+
 static void perf_evlist__purge(struct perf_evlist *evlist)
 {
        struct perf_evsel *pos, *n;
@@ -446,20 +456,25 @@ static int perf_evlist__event2id(struct perf_evlist *evlist,
 static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist,
                                                   union perf_event *event)
 {
+       struct perf_evsel *first = perf_evlist__first(evlist);
        struct hlist_head *head;
        struct perf_sample_id *sid;
        int hash;
        u64 id;
 
        if (evlist->nr_entries == 1)
-               return perf_evlist__first(evlist);
+               return first;
+
+       if (!first->attr.sample_id_all &&
+           event->header.type != PERF_RECORD_SAMPLE)
+               return first;
 
        if (perf_evlist__event2id(evlist, event, &id))
                return NULL;
 
        /* Synthesized events have an id of zero */
        if (!id)
-               return perf_evlist__first(evlist);
+               return first;
 
        hash = hash_64(id, PERF_EVLIST__HLIST_BITS);
        head = &evlist->heads[hash];
@@ -915,6 +930,8 @@ int perf_evlist__open(struct perf_evlist *evlist)
        struct perf_evsel *evsel;
        int err;
 
+       perf_evlist__update_id_pos(evlist);
+
        list_for_each_entry(evsel, &evlist->entries, node) {
                err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
                if (err < 0)
index 3612183e2cc5831c08fffbb8fc23f880d4aed7b3..0ce9febf1ba0c8c1a691c74a0c55fa1c4a8dfd14 100644 (file)
@@ -27,6 +27,7 @@
 static struct {
        bool sample_id_all;
        bool exclude_guest;
+       bool mmap2;
 } perf_missing_features;
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
@@ -676,8 +677,9 @@ void perf_evsel__config(struct perf_evsel *evsel,
        if (opts->sample_weight)
                attr->sample_type       |= PERF_SAMPLE_WEIGHT;
 
-       attr->mmap = track;
-       attr->comm = track;
+       attr->mmap  = track;
+       attr->mmap2 = track && !perf_missing_features.mmap2;
+       attr->comm  = track;
 
        /*
         * XXX see the function comment above
@@ -1016,6 +1018,8 @@ static int __perf_evsel__open(struct perf_evsel *evsel, struct cpu_map *cpus,
        }
 
 fallback_missing_features:
+       if (perf_missing_features.mmap2)
+               evsel->attr.mmap2 = 0;
        if (perf_missing_features.exclude_guest)
                evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
 retry_sample_id:
@@ -1080,8 +1084,11 @@ try_fallback:
        if (err != -EINVAL || cpu > 0 || thread > 0)
                goto out_close;
 
-       if (!perf_missing_features.exclude_guest &&
-           (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
+       if (!perf_missing_features.mmap2 && evsel->attr.mmap2) {
+               perf_missing_features.mmap2 = true;
+               goto fallback_missing_features;
+       } else if (!perf_missing_features.exclude_guest &&
+                  (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
                perf_missing_features.exclude_guest = true;
                goto fallback_missing_features;
        } else if (!perf_missing_features.sample_id_all) {
@@ -1925,6 +1932,7 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
                if_print(exclude_hv);
                if_print(exclude_idle);
                if_print(mmap);
+               if_print(mmap2);
                if_print(comm);
                if_print(freq);
                if_print(inherit_stat);
index a33197a4fd21b4790191ca9f654498e0b660bced..26441d0e571bfce2bcd469dfdfe428175facb5ee 100644 (file)
@@ -1351,6 +1351,9 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp)
 
                fprintf(fp, ", precise_ip = %d", evsel->attr.precise_ip);
 
+               fprintf(fp, ", attr_mmap2 = %d", evsel->attr.mmap2);
+               fprintf(fp, ", attr_mmap  = %d", evsel->attr.mmap);
+               fprintf(fp, ", attr_mmap_data = %d", evsel->attr.mmap_data);
                if (evsel->ids) {
                        fprintf(fp, ", id = {");
                        for (j = 0, id = evsel->id; j < evsel->ids; j++, id++) {
index 1dca61f0512d672abb257cf093cf4539835c30eb..933d14f287ca92645152f7714651a10b818e87bc 100644 (file)
@@ -997,6 +997,54 @@ out_problem:
        return -1;
 }
 
+int machine__process_mmap2_event(struct machine *machine,
+                                union perf_event *event)
+{
+       u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
+       struct thread *thread;
+       struct map *map;
+       enum map_type type;
+       int ret = 0;
+
+       if (dump_trace)
+               perf_event__fprintf_mmap2(event, stdout);
+
+       if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
+           cpumode == PERF_RECORD_MISC_KERNEL) {
+               ret = machine__process_kernel_mmap_event(machine, event);
+               if (ret < 0)
+                       goto out_problem;
+               return 0;
+       }
+
+       thread = machine__findnew_thread(machine, event->mmap2.pid,
+                                       event->mmap2.pid);
+       if (thread == NULL)
+               goto out_problem;
+
+       if (event->header.misc & PERF_RECORD_MISC_MMAP_DATA)
+               type = MAP__VARIABLE;
+       else
+               type = MAP__FUNCTION;
+
+       map = map__new(&machine->user_dsos, event->mmap2.start,
+                       event->mmap2.len, event->mmap2.pgoff,
+                       event->mmap2.pid, event->mmap2.maj,
+                       event->mmap2.min, event->mmap2.ino,
+                       event->mmap2.ino_generation,
+                       event->mmap2.filename, type);
+
+       if (map == NULL)
+               goto out_problem;
+
+       thread__insert_map(thread, map);
+       return 0;
+
+out_problem:
+       dump_printf("problem processing PERF_RECORD_MMAP2, skipping event.\n");
+       return 0;
+}
+
 int machine__process_mmap_event(struct machine *machine, union perf_event *event)
 {
        u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
@@ -1028,7 +1076,8 @@ int machine__process_mmap_event(struct machine *machine, union perf_event *event
 
        map = map__new(&machine->user_dsos, event->mmap.start,
                        event->mmap.len, event->mmap.pgoff,
-                       event->mmap.pid, event->mmap.filename,
+                       event->mmap.pid, 0, 0, 0, 0,
+                       event->mmap.filename,
                        type);
 
        if (map == NULL)
@@ -1101,6 +1150,8 @@ int machine__process_event(struct machine *machine, union perf_event *event)
                ret = machine__process_comm_event(machine, event); break;
        case PERF_RECORD_MMAP:
                ret = machine__process_mmap_event(machine, event); break;
+       case PERF_RECORD_MMAP2:
+               ret = machine__process_mmap2_event(machine, event); break;
        case PERF_RECORD_FORK:
                ret = machine__process_fork_event(machine, event); break;
        case PERF_RECORD_EXIT:
index 0df925ba6a44e5ca97235b90cadd7a672429c49a..58a6be1fc739ba8e543ebd7d1bb6ea5185991703 100644 (file)
@@ -45,6 +45,7 @@ int machine__process_exit_event(struct machine *machine, union perf_event *event
 int machine__process_fork_event(struct machine *machine, union perf_event *event);
 int machine__process_lost_event(struct machine *machine, union perf_event *event);
 int machine__process_mmap_event(struct machine *machine, union perf_event *event);
+int machine__process_mmap2_event(struct machine *machine, union perf_event *event);
 int machine__process_event(struct machine *machine, union perf_event *event);
 
 typedef void (*machine__process_t)(struct machine *machine, void *data);
index 9e8304ca343e4ce6d6b2e80d3a1b76e4808fadda..4f6680d2043b1e68ef7b9dfbc63a37326fcc6f22 100644 (file)
@@ -48,7 +48,8 @@ void map__init(struct map *map, enum map_type type,
 }
 
 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
-                    u64 pgoff, u32 pid, char *filename,
+                    u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+                    u64 ino_gen, char *filename,
                     enum map_type type)
 {
        struct map *map = malloc(sizeof(*map));
@@ -62,6 +63,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
                vdso = is_vdso_map(filename);
                no_dso = is_no_dso_memory(filename);
 
+               map->maj = d_maj;
+               map->min = d_min;
+               map->ino = ino;
+               map->ino_generation = ino_gen;
+
                if (anon) {
                        snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
                        filename = newfilename;
index 2cc93cbf0e17a021574a69d3198da84608105eb6..4886ca2805361df87a57c9f4406ed5c38fe418b5 100644 (file)
@@ -36,6 +36,9 @@ struct map {
        bool                    erange_warned;
        u32                     priv;
        u64                     pgoff;
+       u32                     maj, min; /* only valid for MMAP2 record */
+       u64                     ino;      /* only valid for MMAP2 record */
+       u64                     ino_generation;/* only valid for MMAP2 record */
 
        /* ip -> dso rip */
        u64                     (*map_ip)(struct map *, u64);
@@ -88,8 +91,9 @@ typedef int (*symbol_filter_t)(struct map *map, struct symbol *sym);
 void map__init(struct map *map, enum map_type type,
               u64 start, u64 end, u64 pgoff, struct dso *dso);
 struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
-                    u64 pgoff, u32 pid, char *filename,
-                    enum map_type type);
+                    u64 pgoff, u32 pid, u32 d_maj, u32 d_min, u64 ino,
+                    u64 ino_gen,
+                    char *filename, enum map_type type);
 struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
 void map__delete(struct map *map);
 struct map *map__clone(struct map *map);
index 1fc0c628683eea5b90d4e14f7efb7026d40cf0a2..51f5edf2a6d0d140dd897c58f9d606c9fb25be9d 100644 (file)
@@ -351,6 +351,25 @@ static void perf_event__mmap_swap(union perf_event *event,
        }
 }
 
+static void perf_event__mmap2_swap(union perf_event *event,
+                                 bool sample_id_all)
+{
+       event->mmap2.pid   = bswap_32(event->mmap2.pid);
+       event->mmap2.tid   = bswap_32(event->mmap2.tid);
+       event->mmap2.start = bswap_64(event->mmap2.start);
+       event->mmap2.len   = bswap_64(event->mmap2.len);
+       event->mmap2.pgoff = bswap_64(event->mmap2.pgoff);
+       event->mmap2.maj   = bswap_32(event->mmap2.maj);
+       event->mmap2.min   = bswap_32(event->mmap2.min);
+       event->mmap2.ino   = bswap_64(event->mmap2.ino);
+
+       if (sample_id_all) {
+               void *data = &event->mmap2.filename;
+
+               data += PERF_ALIGN(strlen(data) + 1, sizeof(u64));
+               swap_sample_id_all(event, data);
+       }
+}
 static void perf_event__task_swap(union perf_event *event, bool sample_id_all)
 {
        event->fork.pid  = bswap_32(event->fork.pid);
@@ -455,6 +474,7 @@ typedef void (*perf_event__swap_op)(union perf_event *event,
 
 static perf_event__swap_op perf_event__swap_ops[] = {
        [PERF_RECORD_MMAP]                = perf_event__mmap_swap,
+       [PERF_RECORD_MMAP2]               = perf_event__mmap2_swap,
        [PERF_RECORD_COMM]                = perf_event__comm_swap,
        [PERF_RECORD_FORK]                = perf_event__task_swap,
        [PERF_RECORD_EXIT]                = perf_event__task_swap,
@@ -504,6 +524,7 @@ static int flush_sample_queue(struct perf_session *s,
        u64 limit = os->next_flush;
        u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL;
        unsigned idx = 0, progress_next = os->nr_samples / 16;
+       bool show_progress = limit == ULLONG_MAX;
        int ret;
 
        if (!tool->ordered_samples || !limit)
@@ -526,7 +547,7 @@ static int flush_sample_queue(struct perf_session *s,
                os->last_flush = iter->timestamp;
                list_del(&iter->list);
                list_add(&iter->list, &os->sample_cache);
-               if (++idx >= progress_next) {
+               if (show_progress && (++idx >= progress_next)) {
                        progress_next += os->nr_samples / 16;
                        ui_progress__update(idx, os->nr_samples,
                                            "Processing time ordered events...");
@@ -850,7 +871,8 @@ static struct machine *
             (cpumode == PERF_RECORD_MISC_GUEST_USER))) {
                u32 pid;
 
-               if (event->header.type == PERF_RECORD_MMAP)
+               if (event->header.type == PERF_RECORD_MMAP
+                   || event->header.type == PERF_RECORD_MMAP2)
                        pid = event->mmap.pid;
                else
                        pid = sample->pid;
@@ -977,6 +999,8 @@ static int perf_session_deliver_event(struct perf_session *session,
                                                    sample, evsel, machine);
        case PERF_RECORD_MMAP:
                return tool->mmap(tool, event, sample, machine);
+       case PERF_RECORD_MMAP2:
+               return tool->mmap2(tool, event, sample, machine);
        case PERF_RECORD_COMM:
                return tool->comm(tool, event, sample, machine);
        case PERF_RECORD_FORK:
@@ -1619,52 +1643,26 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
                                             const struct perf_evsel_str_handler *assocs,
                                             size_t nr_assocs)
 {
-       struct perf_evlist *evlist = session->evlist;
-       struct event_format *format;
        struct perf_evsel *evsel;
-       char *tracepoint, *name;
        size_t i;
        int err;
 
        for (i = 0; i < nr_assocs; i++) {
-               err = -ENOMEM;
-               tracepoint = strdup(assocs[i].name);
-               if (tracepoint == NULL)
-                       goto out;
-
-               err = -ENOENT;
-               name = strchr(tracepoint, ':');
-               if (name == NULL)
-                       goto out_free;
-
-               *name++ = '\0';
-               format = pevent_find_event_by_name(session->pevent,
-                                                  tracepoint, name);
-               if (format == NULL) {
-                       /*
-                        * Adding a handler for an event not in the session,
-                        * just ignore it.
-                        */
-                       goto next;
-               }
-
-               evsel = perf_evlist__find_tracepoint_by_id(evlist, format->id);
+               /*
+                * Adding a handler for an event not in the session,
+                * just ignore it.
+                */
+               evsel = perf_evlist__find_tracepoint_by_name(session->evlist, assocs[i].name);
                if (evsel == NULL)
-                       goto next;
+                       continue;
 
                err = -EEXIST;
                if (evsel->handler.func != NULL)
-                       goto out_free;
+                       goto out;
                evsel->handler.func = assocs[i].handler;
-next:
-               free(tracepoint);
        }
 
        err = 0;
 out:
        return err;
-
-out_free:
-       free(tracepoint);
-       goto out;
 }
index 62b16b6165bafae5fd80cb79d1670628f1d81847..4385816d3d49643c981f64a310eaaef6d9838738 100644 (file)
@@ -29,6 +29,7 @@ struct perf_tool {
        event_sample    sample,
                        read;
        event_op        mmap,
+                       mmap2,
                        comm,
                        fork,
                        exit,
diff --git a/tools/virtio/.gitignore b/tools/virtio/.gitignore
new file mode 100644 (file)
index 0000000..1cfbb01
--- /dev/null
@@ -0,0 +1,3 @@
+*.d
+virtio_test
+vringh_test
index ea475cd035112a9db93ffa028a552df9be0724af..8a39dda7a3254677df5996c07c965a2f9f5ef8a8 100644 (file)
@@ -101,8 +101,11 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
                                   typeof(*work), queue);
                cancel_work_sync(&work->work);
                list_del(&work->queue);
-               if (!work->done) /* work was canceled */
+               if (!work->done) { /* work was canceled */
+                       mmdrop(work->mm);
+                       kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
                        kmem_cache_free(async_pf_cache, work);
+               }
        }
 
        spin_lock(&vcpu->async_pf.lock);
index bf040c4e02b332b7dd2126ae6ed2013261ecfdb4..979bff485fb0b343cb5e1fd4328d7cf046dafef7 100644 (file)
@@ -1058,11 +1058,15 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
 EXPORT_SYMBOL_GPL(gfn_to_hva);
 
 /*
- * The hva returned by this function is only allowed to be read.
- * It should pair with kvm_read_hva() or kvm_read_hva_atomic().
+ * If writable is set to false, the hva returned by this function is only
+ * allowed to be read.
  */
-static unsigned long gfn_to_hva_read(struct kvm *kvm, gfn_t gfn)
+unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable)
 {
+       struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
+       if (writable)
+               *writable = !memslot_is_readonly(slot);
+
        return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false);
 }
 
@@ -1430,7 +1434,7 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
        int r;
        unsigned long addr;
 
-       addr = gfn_to_hva_read(kvm, gfn);
+       addr = gfn_to_hva_prot(kvm, gfn, NULL);
        if (kvm_is_error_hva(addr))
                return -EFAULT;
        r = kvm_read_hva(data, (void __user *)addr + offset, len);
@@ -1468,7 +1472,7 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
        gfn_t gfn = gpa >> PAGE_SHIFT;
        int offset = offset_in_page(gpa);
 
-       addr = gfn_to_hva_read(kvm, gfn);
+       addr = gfn_to_hva_prot(kvm, gfn, NULL);
        if (kvm_is_error_hva(addr))
                return -EFAULT;
        pagefault_disable();